1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 1997 David Mosberger-Tang
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   This file implements a SANE backend for the Artec/Ultima scanners.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   Copyright (C) 1998-2000 Chris Pinkham
42141cc406Sopenharmony_ci   Released under the terms of the GPL.
43141cc406Sopenharmony_ci   *NO WARRANTY*
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci   Portions contributed by:
46141cc406Sopenharmony_ci   David Leadbetter - A6000C (3-pass)
47141cc406Sopenharmony_ci   Dick Bruijn - AT12
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci   *********************************************************************
50141cc406Sopenharmony_ci   For feedback/information:
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci   cpinkham@corp.infi.net
53141cc406Sopenharmony_ci   http://www4.infi.net/~cpinkham/sane/sane-artec-doc.html
54141cc406Sopenharmony_ci   *********************************************************************
55141cc406Sopenharmony_ci */
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci#include "../include/sane/config.h"
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#include <ctype.h>
60141cc406Sopenharmony_ci#include <limits.h>
61141cc406Sopenharmony_ci#include <stdlib.h>
62141cc406Sopenharmony_ci#include <stdarg.h>
63141cc406Sopenharmony_ci#include <string.h>
64141cc406Sopenharmony_ci#include <unistd.h>
65141cc406Sopenharmony_ci#include <sys/types.h>
66141cc406Sopenharmony_ci#include <sys/stat.h>
67141cc406Sopenharmony_ci#include <fcntl.h>
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#include "../include/_stdint.h"
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "../include/sane/sane.h"
72141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
74141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
75141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
76141cc406Sopenharmony_ci
77141cc406Sopenharmony_ci#include <artec.h>
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci#define BACKEND_NAME    artec
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci#define ARTEC_MAJOR     0
82141cc406Sopenharmony_ci#define ARTEC_MINOR     5
83141cc406Sopenharmony_ci#define ARTEC_SUB       16
84141cc406Sopenharmony_ci#define ARTEC_LAST_MOD  "05/26/2001 17:28 EST"
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci#ifndef PATH_MAX
88141cc406Sopenharmony_ci#define PATH_MAX	1024
89141cc406Sopenharmony_ci#endif
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci#define ARTEC_CONFIG_FILE "artec.conf"
92141cc406Sopenharmony_ci#define ARTEC_MAX_READ_SIZE 32768
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic int num_devices;
95141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
96141cc406Sopenharmony_cistatic ARTEC_Device *first_dev;
97141cc406Sopenharmony_cistatic ARTEC_Scanner *first_handle;
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] =
100141cc406Sopenharmony_ci{
101141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
102141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_HALFTONE,
103141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
104141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
105141cc406Sopenharmony_ci  0
106141cc406Sopenharmony_ci};
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_cistatic const SANE_String_Const filter_type_list[] =
109141cc406Sopenharmony_ci{
110141cc406Sopenharmony_ci  "Mono", "Red", "Green", "Blue",
111141cc406Sopenharmony_ci  0
112141cc406Sopenharmony_ci};
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_cistatic const SANE_String_Const halftone_pattern_list[] =
115141cc406Sopenharmony_ci{
116141cc406Sopenharmony_ci  "User defined (unsupported)", "4x4 Spiral", "4x4 Bayer", "8x8 Spiral",
117141cc406Sopenharmony_ci  "8x8 Bayer",
118141cc406Sopenharmony_ci  0
119141cc406Sopenharmony_ci};
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_cistatic const SANE_Range u8_range =
122141cc406Sopenharmony_ci{
123141cc406Sopenharmony_ci  0,				/* minimum */
124141cc406Sopenharmony_ci  255,				/* maximum */
125141cc406Sopenharmony_ci  0				/* quantization */
126141cc406Sopenharmony_ci};
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_ci#define INQ_LEN	0x60
129141cc406Sopenharmony_cistatic const uint8_t inquiry[] =
130141cc406Sopenharmony_ci{
131141cc406Sopenharmony_ci  0x12, 0x00, 0x00, 0x00, INQ_LEN, 0x00
132141cc406Sopenharmony_ci};
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_cistatic const uint8_t test_unit_ready[] =
135141cc406Sopenharmony_ci{
136141cc406Sopenharmony_ci  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
137141cc406Sopenharmony_ci};
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_cistatic struct
140141cc406Sopenharmony_ci  {
141141cc406Sopenharmony_ci    SANE_String model;		/* product model */
142141cc406Sopenharmony_ci    SANE_String type;		/* type of scanner */
143141cc406Sopenharmony_ci    double width;		/* width in inches */
144141cc406Sopenharmony_ci    double height;		/* height in inches */
145141cc406Sopenharmony_ci    SANE_Word adc_bits;		/* Analog-to-Digital Converter Bits */
146141cc406Sopenharmony_ci    SANE_Word setwindow_cmd_size;	/* Set-Window command size */
147141cc406Sopenharmony_ci    SANE_Word max_read_size;	/* Max Read size in bytes */
148141cc406Sopenharmony_ci    long flags;			/* flags */
149141cc406Sopenharmony_ci    SANE_String horz_resolution_str;	/* Horizontal resolution list */
150141cc406Sopenharmony_ci    SANE_String vert_resolution_str;	/* Vertical resolution list */
151141cc406Sopenharmony_ci  }
152141cc406Sopenharmony_cicap_data[] =
153141cc406Sopenharmony_ci{
154141cc406Sopenharmony_ci  {
155141cc406Sopenharmony_ci    "AT3", "flatbed",
156141cc406Sopenharmony_ci      8.3, 11, 8, 55, 32768,
157141cc406Sopenharmony_ci      ARTEC_FLAG_CALIBRATE_RGB |
158141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_LINE_OFFSET |
159141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_CHAR_SHIFT |
160141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_CONTRAST |
161141cc406Sopenharmony_ci      ARTEC_FLAG_GAMMA_SINGLE |
162141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
163141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
164141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_BYTE_19 |
165141cc406Sopenharmony_ci      ARTEC_FLAG_ADF |
166141cc406Sopenharmony_ci      ARTEC_FLAG_HALFTONE_PATTERN |
167141cc406Sopenharmony_ci      ARTEC_FLAG_MBPP_NEGATIVE |
168141cc406Sopenharmony_ci      ARTEC_FLAG_ONE_PASS_SCANNER,
169141cc406Sopenharmony_ci      "50,100,200,300", "50,100,200,300,600"
170141cc406Sopenharmony_ci  }
171141cc406Sopenharmony_ci  ,
172141cc406Sopenharmony_ci  {
173141cc406Sopenharmony_ci    "A6000C", "flatbed",
174141cc406Sopenharmony_ci      8.3, 14, 8, 55, 8192,
175141cc406Sopenharmony_ci/* some have reported that Calibration does not work the same as AT3 & A6000C+
176141cc406Sopenharmony_ci   ARTEC_FLAG_CALIBRATE_RGB |
177141cc406Sopenharmony_ci */
178141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_CONTRAST |
179141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_BRIGHTNESS |
180141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
181141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
182141cc406Sopenharmony_ci      ARTEC_FLAG_ADF |
183141cc406Sopenharmony_ci      ARTEC_FLAG_HALFTONE_PATTERN,
184141cc406Sopenharmony_ci      "50,100,200,300", "50,100,200,300,600"
185141cc406Sopenharmony_ci  }
186141cc406Sopenharmony_ci  ,
187141cc406Sopenharmony_ci  {
188141cc406Sopenharmony_ci    "A6000C PLUS", "flatbed",
189141cc406Sopenharmony_ci      8.3, 14, 8, 55, 8192,
190141cc406Sopenharmony_ci      ARTEC_FLAG_CALIBRATE_RGB |
191141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_LINE_OFFSET |
192141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_CHAR_SHIFT |
193141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_CONTRAST |
194141cc406Sopenharmony_ci      ARTEC_FLAG_GAMMA_SINGLE |
195141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
196141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
197141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_BYTE_19 |
198141cc406Sopenharmony_ci      ARTEC_FLAG_ADF |
199141cc406Sopenharmony_ci      ARTEC_FLAG_HALFTONE_PATTERN |
200141cc406Sopenharmony_ci      ARTEC_FLAG_MBPP_NEGATIVE |
201141cc406Sopenharmony_ci      ARTEC_FLAG_ONE_PASS_SCANNER,
202141cc406Sopenharmony_ci      "50,100,200,300", "50,100,200,300,600"
203141cc406Sopenharmony_ci  }
204141cc406Sopenharmony_ci  ,
205141cc406Sopenharmony_ci  {
206141cc406Sopenharmony_ci    "AT6", "flatbed",
207141cc406Sopenharmony_ci      8.3, 11, 10, 55, 32768,
208141cc406Sopenharmony_ci      ARTEC_FLAG_CALIBRATE_RGB |
209141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_LINE_OFFSET |
210141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_CHAR_SHIFT |
211141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_CONTRAST |
212141cc406Sopenharmony_ci/* gamma not working totally correct yet.
213141cc406Sopenharmony_ci   ARTEC_FLAG_GAMMA_SINGLE |
214141cc406Sopenharmony_ci */
215141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
216141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
217141cc406Sopenharmony_ci      ARTEC_FLAG_ADF |
218141cc406Sopenharmony_ci      ARTEC_FLAG_HALFTONE_PATTERN |
219141cc406Sopenharmony_ci      ARTEC_FLAG_MBPP_NEGATIVE |
220141cc406Sopenharmony_ci      ARTEC_FLAG_ONE_PASS_SCANNER,
221141cc406Sopenharmony_ci      "50,100,200,300", "50,100,200,300,600"
222141cc406Sopenharmony_ci  }
223141cc406Sopenharmony_ci  ,
224141cc406Sopenharmony_ci  {
225141cc406Sopenharmony_ci    "AT12", "flatbed",
226141cc406Sopenharmony_ci      8.5, 11, 12, 67, 32768,
227141cc406Sopenharmony_ci/* calibration works slower so disabled
228141cc406Sopenharmony_ci   ARTEC_CALIBRATE_DARK_WHITE |
229141cc406Sopenharmony_ci */
230141cc406Sopenharmony_ci/* gamma not working totally correct yet.
231141cc406Sopenharmony_ci   ARTEC_FLAG_GAMMA |
232141cc406Sopenharmony_ci */
233141cc406Sopenharmony_ci      ARTEC_FLAG_OPT_CONTRAST |
234141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
235141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
236141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_ENH_18 |
237141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_BYTE_22 |
238141cc406Sopenharmony_ci      ARTEC_FLAG_SC_BUFFERS_LINES |
239141cc406Sopenharmony_ci      ARTEC_FLAG_SC_HANDLES_OFFSET |
240141cc406Sopenharmony_ci      ARTEC_FLAG_PIXEL_AVERAGING |
241141cc406Sopenharmony_ci      ARTEC_FLAG_ENHANCE_LINE_EDGE |
242141cc406Sopenharmony_ci      ARTEC_FLAG_ADF |
243141cc406Sopenharmony_ci      ARTEC_FLAG_HALFTONE_PATTERN |
244141cc406Sopenharmony_ci      ARTEC_FLAG_MBPP_NEGATIVE |
245141cc406Sopenharmony_ci      ARTEC_FLAG_ONE_PASS_SCANNER,
246141cc406Sopenharmony_ci      "25,50,100,200,300,400,500,600",
247141cc406Sopenharmony_ci      "25,50,100,200,300,400,500,600,700,800,900,1000,1100,1200"
248141cc406Sopenharmony_ci  }
249141cc406Sopenharmony_ci  ,
250141cc406Sopenharmony_ci  {
251141cc406Sopenharmony_ci    "AM12S", "flatbed",
252141cc406Sopenharmony_ci      8.26, 11.7, 12, 67, ARTEC_MAX_READ_SIZE,
253141cc406Sopenharmony_ci/* calibration works slower so disabled
254141cc406Sopenharmony_ci   ARTEC_CALIBRATE_DARK_WHITE |
255141cc406Sopenharmony_ci */
256141cc406Sopenharmony_ci/* gamma not working totally correct yet.
257141cc406Sopenharmony_ci   ARTEC_FLAG_GAMMA |
258141cc406Sopenharmony_ci */
259141cc406Sopenharmony_ci      ARTEC_FLAG_RGB_LINE_OFFSET |
260141cc406Sopenharmony_ci      ARTEC_FLAG_SEPARATE_RES |
261141cc406Sopenharmony_ci      ARTEC_FLAG_IMAGE_REV_LR |
262141cc406Sopenharmony_ci      ARTEC_FLAG_REVERSE_WINDOW |
263141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_HANDLER |
264141cc406Sopenharmony_ci      ARTEC_FLAG_SENSE_ENH_18 |
265141cc406Sopenharmony_ci      ARTEC_FLAG_MBPP_NEGATIVE |
266141cc406Sopenharmony_ci      ARTEC_FLAG_ONE_PASS_SCANNER,
267141cc406Sopenharmony_ci      "50,100,300,600",
268141cc406Sopenharmony_ci      "50,100,300,600,1200"
269141cc406Sopenharmony_ci  }
270141cc406Sopenharmony_ci  ,
271141cc406Sopenharmony_ci};
272141cc406Sopenharmony_ci
273141cc406Sopenharmony_ci/* store vendor and model if hardcoded in artec.conf */
274141cc406Sopenharmony_cistatic char artec_vendor[9] = "";
275141cc406Sopenharmony_cistatic char artec_model[17] = "";
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci/* file descriptor for debug data output */
278141cc406Sopenharmony_cistatic int debug_fd = -1;
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_cistatic char *artec_skip_whitespace (char *str)
281141cc406Sopenharmony_ci{
282141cc406Sopenharmony_ci  while (isspace (*str))
283141cc406Sopenharmony_ci    ++str;
284141cc406Sopenharmony_ci  return str;
285141cc406Sopenharmony_ci}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_cistatic SANE_Status
288141cc406Sopenharmony_ciartec_str_list_to_word_list (SANE_Word ** word_list_ptr, SANE_String str)
289141cc406Sopenharmony_ci{
290141cc406Sopenharmony_ci  SANE_Word *word_list;
291141cc406Sopenharmony_ci  char *start;
292141cc406Sopenharmony_ci  char *end;
293141cc406Sopenharmony_ci  char temp_str[1024];
294141cc406Sopenharmony_ci  int comma_count = 1;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci  if ((str == NULL) ||
297141cc406Sopenharmony_ci      (strlen (str) == 0))
298141cc406Sopenharmony_ci    {
299141cc406Sopenharmony_ci      /* alloc space for word which stores length (0 in this case) */
300141cc406Sopenharmony_ci      word_list = (SANE_Word *) malloc (sizeof (SANE_Word));
301141cc406Sopenharmony_ci      if (word_list == NULL)
302141cc406Sopenharmony_ci	return (SANE_STATUS_NO_MEM);
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci      word_list[0] = 0;
305141cc406Sopenharmony_ci      *word_list_ptr = word_list;
306141cc406Sopenharmony_ci      return (SANE_STATUS_GOOD);
307141cc406Sopenharmony_ci    }
308141cc406Sopenharmony_ci
309141cc406Sopenharmony_ci  /* make temp copy of input string (only hold 1024 for now) */
310141cc406Sopenharmony_ci  strncpy (temp_str, str, 1023);
311141cc406Sopenharmony_ci  temp_str[1023] = '\0';
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci  end = strchr (temp_str, ',');
314141cc406Sopenharmony_ci  while (end != NULL)
315141cc406Sopenharmony_ci    {
316141cc406Sopenharmony_ci      comma_count++;
317141cc406Sopenharmony_ci      start = end + 1;
318141cc406Sopenharmony_ci      end = strchr (start, ',');
319141cc406Sopenharmony_ci    }
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  word_list = (SANE_Word *) calloc (comma_count + 1,
322141cc406Sopenharmony_ci				    sizeof (SANE_Word));
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci  if (word_list == NULL)
325141cc406Sopenharmony_ci    return (SANE_STATUS_NO_MEM);
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci  word_list[0] = comma_count;
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci  comma_count = 1;
330141cc406Sopenharmony_ci  start = temp_str;
331141cc406Sopenharmony_ci  end = strchr (temp_str, ',');
332141cc406Sopenharmony_ci  while (end != NULL)
333141cc406Sopenharmony_ci    {
334141cc406Sopenharmony_ci      *end = '\0';
335141cc406Sopenharmony_ci      word_list[comma_count] = atol (start);
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci      start = end + 1;
338141cc406Sopenharmony_ci      comma_count++;
339141cc406Sopenharmony_ci      end = strchr (start, ',');
340141cc406Sopenharmony_ci    }
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci  word_list[comma_count] = atol (start);
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci  *word_list_ptr = word_list;
345141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
346141cc406Sopenharmony_ci}
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_cistatic size_t
349141cc406Sopenharmony_ciartec_get_str_index (const SANE_String_Const strings[], char *str)
350141cc406Sopenharmony_ci{
351141cc406Sopenharmony_ci  size_t index;
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci  index = 0;
354141cc406Sopenharmony_ci  while ((strings[index]) && strcmp (strings[index], str))
355141cc406Sopenharmony_ci    {
356141cc406Sopenharmony_ci      index++;
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci  if (!strings[index])
360141cc406Sopenharmony_ci    {
361141cc406Sopenharmony_ci      index = 0;
362141cc406Sopenharmony_ci    }
363141cc406Sopenharmony_ci
364141cc406Sopenharmony_ci  return (index);
365141cc406Sopenharmony_ci}
366141cc406Sopenharmony_ci
367141cc406Sopenharmony_cistatic size_t
368141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
369141cc406Sopenharmony_ci{
370141cc406Sopenharmony_ci  size_t size, max_size = 0;
371141cc406Sopenharmony_ci  int i;
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
374141cc406Sopenharmony_ci    {
375141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
376141cc406Sopenharmony_ci      if (size > max_size)
377141cc406Sopenharmony_ci	max_size = size;
378141cc406Sopenharmony_ci    }
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  return (max_size);
381141cc406Sopenharmony_ci}
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci/* DB added a sense handler */
384141cc406Sopenharmony_ci/* last argument is expected to be a pointer to a Artec_Scanner structure */
385141cc406Sopenharmony_cistatic SANE_Status
386141cc406Sopenharmony_cisense_handler (int fd, u_char * sense, void *arg)
387141cc406Sopenharmony_ci{
388141cc406Sopenharmony_ci  ARTEC_Scanner *s = (ARTEC_Scanner *)arg;
389141cc406Sopenharmony_ci  int err;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci  err = 0;
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci  DBG(2, "sense fd: %d, data: %02x %02x %02x %02x %02x %02x %02x %02x "
394141cc406Sopenharmony_ci    "%02x %02x %02x %02x %02x %02x %02x %02x\n", fd,
395141cc406Sopenharmony_ci    sense[0], sense[1], sense[2], sense[3],
396141cc406Sopenharmony_ci    sense[4], sense[5], sense[6], sense[7],
397141cc406Sopenharmony_ci    sense[8], sense[9], sense[10], sense[11],
398141cc406Sopenharmony_ci    sense[12], sense[13], sense[14], sense[15]);
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  /* byte 18 info pertaining to ADF */
401141cc406Sopenharmony_ci  if ((s) && (s->hw->flags & ARTEC_FLAG_ADF))
402141cc406Sopenharmony_ci    {
403141cc406Sopenharmony_ci      if (sense[18] & 0x01)
404141cc406Sopenharmony_ci	{
405141cc406Sopenharmony_ci	  DBG (2, "sense:  ADF PAPER JAM\n");
406141cc406Sopenharmony_ci	  err++;
407141cc406Sopenharmony_ci	}
408141cc406Sopenharmony_ci      if (sense[18] & 0x02)
409141cc406Sopenharmony_ci	{
410141cc406Sopenharmony_ci	  DBG (2, "sense:  ADF NO DOCUMENT IN BIN\n");
411141cc406Sopenharmony_ci	  err++;
412141cc406Sopenharmony_ci	}
413141cc406Sopenharmony_ci      if (sense[18] & 0x04)
414141cc406Sopenharmony_ci	{
415141cc406Sopenharmony_ci	  DBG (2, "sense:  ADF SWITCH COVER OPEN\n");
416141cc406Sopenharmony_ci	  err++;
417141cc406Sopenharmony_ci	}
418141cc406Sopenharmony_ci      /* DB : next is, i think no failure, so no incrementing s */
419141cc406Sopenharmony_ci      if (sense[18] & 0x08)
420141cc406Sopenharmony_ci	{
421141cc406Sopenharmony_ci	  DBG (2, "sense:  ADF SET CORRECTLY ON TARGET\n");
422141cc406Sopenharmony_ci	}
423141cc406Sopenharmony_ci      /* The following only for AT12, its reserved (zero?) on other models,  */
424141cc406Sopenharmony_ci      if (sense[18] & 0x10)
425141cc406Sopenharmony_ci	{
426141cc406Sopenharmony_ci	  DBG (2, "sense:  ADF LENGTH TOO SHORT\n");
427141cc406Sopenharmony_ci	  err++;
428141cc406Sopenharmony_ci	}
429141cc406Sopenharmony_ci    }
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci  /* enhanced byte 18 sense data */
432141cc406Sopenharmony_ci  if ((s) && (s->hw->flags & ARTEC_FLAG_SENSE_ENH_18))
433141cc406Sopenharmony_ci    {
434141cc406Sopenharmony_ci      if (sense[18] & 0x20)
435141cc406Sopenharmony_ci	{
436141cc406Sopenharmony_ci	  DBG (2, "sense:  LAMP FAIL : NOT WARM \n");
437141cc406Sopenharmony_ci	  err++;
438141cc406Sopenharmony_ci	}
439141cc406Sopenharmony_ci      if (sense[18] & 0x40)
440141cc406Sopenharmony_ci	{
441141cc406Sopenharmony_ci	  DBG (2, "sense:  NOT READY STATE\n");
442141cc406Sopenharmony_ci	  err++;
443141cc406Sopenharmony_ci	}
444141cc406Sopenharmony_ci    }
445141cc406Sopenharmony_ci
446141cc406Sopenharmony_ci  if ((s) && (s->hw->flags & ARTEC_FLAG_SENSE_BYTE_19))
447141cc406Sopenharmony_ci    {
448141cc406Sopenharmony_ci      if (sense[19] & 0x01)
449141cc406Sopenharmony_ci	{
450141cc406Sopenharmony_ci	  DBG (2, "sense:  8031 program ROM checksum Error\n");
451141cc406Sopenharmony_ci	  err++;
452141cc406Sopenharmony_ci	}
453141cc406Sopenharmony_ci      if (sense[19] & 0x02)
454141cc406Sopenharmony_ci	{
455141cc406Sopenharmony_ci	  DBG (2, "sense:  8031 data RAM R/W Error\n");
456141cc406Sopenharmony_ci	  err++;
457141cc406Sopenharmony_ci	}
458141cc406Sopenharmony_ci      if (sense[19] & 0x04)
459141cc406Sopenharmony_ci	{
460141cc406Sopenharmony_ci	  DBG (2, "sense:  Shadow Correction RAM R/W Error\n");
461141cc406Sopenharmony_ci	  err++;
462141cc406Sopenharmony_ci	}
463141cc406Sopenharmony_ci      if (sense[19] & 0x08)
464141cc406Sopenharmony_ci	{
465141cc406Sopenharmony_ci	  DBG (2, "sense:  Line RAM R/W Error\n");
466141cc406Sopenharmony_ci	  err++;
467141cc406Sopenharmony_ci	}
468141cc406Sopenharmony_ci      if (sense[19] & 0x10)
469141cc406Sopenharmony_ci	{
470141cc406Sopenharmony_ci	  /* docs say "reserved to '0'" */
471141cc406Sopenharmony_ci	  DBG (2, "sense:  CCD control circuit Error\n");
472141cc406Sopenharmony_ci	  err++;
473141cc406Sopenharmony_ci	}
474141cc406Sopenharmony_ci      if (sense[19] & 0x20)
475141cc406Sopenharmony_ci	{
476141cc406Sopenharmony_ci	  DBG (2, "sense:  Motor End Switch Error\n");
477141cc406Sopenharmony_ci	  err++;
478141cc406Sopenharmony_ci	}
479141cc406Sopenharmony_ci      if (sense[19] & 0x40)
480141cc406Sopenharmony_ci	{
481141cc406Sopenharmony_ci	  /* docs say "reserved to '0'" */
482141cc406Sopenharmony_ci	  DBG (2, "sense:  Lamp Error\n");
483141cc406Sopenharmony_ci	  err++;
484141cc406Sopenharmony_ci	}
485141cc406Sopenharmony_ci      if (sense[19] & 0x80)
486141cc406Sopenharmony_ci	{
487141cc406Sopenharmony_ci	  DBG (2, "sense:  Optical Calibration/Shading Error\n");
488141cc406Sopenharmony_ci	  err++;
489141cc406Sopenharmony_ci	}
490141cc406Sopenharmony_ci    }
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci  /* These are the self test results for tests 0-15 */
493141cc406Sopenharmony_ci  if ((s) && (s->hw->flags & ARTEC_FLAG_SENSE_BYTE_22))
494141cc406Sopenharmony_ci    {
495141cc406Sopenharmony_ci      if (sense[22] & 0x01)
496141cc406Sopenharmony_ci	{
497141cc406Sopenharmony_ci	  DBG (2, "sense:  8031 Internal Memory R/W Error\n");
498141cc406Sopenharmony_ci	  err++;
499141cc406Sopenharmony_ci	}
500141cc406Sopenharmony_ci      if (sense[22] & 0x02)
501141cc406Sopenharmony_ci	{
502141cc406Sopenharmony_ci	  DBG (2, "sense:  EEPROM test pattern R/W Error\n");
503141cc406Sopenharmony_ci	  err++;
504141cc406Sopenharmony_ci	}
505141cc406Sopenharmony_ci      if (sense[22] & 0x04)
506141cc406Sopenharmony_ci	{
507141cc406Sopenharmony_ci	  DBG (2, "sense:  ASIC Test Error\n");
508141cc406Sopenharmony_ci	  err++;
509141cc406Sopenharmony_ci	}
510141cc406Sopenharmony_ci      if (sense[22] & 0x08)
511141cc406Sopenharmony_ci	{
512141cc406Sopenharmony_ci	  DBG (2, "sense:  Line RAM R/W Error\n");
513141cc406Sopenharmony_ci	  err++;
514141cc406Sopenharmony_ci	}
515141cc406Sopenharmony_ci      if (sense[22] & 0x10)
516141cc406Sopenharmony_ci	{
517141cc406Sopenharmony_ci	  DBG (2, "sense:  PSRAM R/W Test Error\n");
518141cc406Sopenharmony_ci	  err++;
519141cc406Sopenharmony_ci	}
520141cc406Sopenharmony_ci      if (sense[22] & 0x20)
521141cc406Sopenharmony_ci	{
522141cc406Sopenharmony_ci	  DBG (2, "sense:  Positioning Error\n");
523141cc406Sopenharmony_ci	  err++;
524141cc406Sopenharmony_ci	}
525141cc406Sopenharmony_ci      if (sense[22] & 0x40)
526141cc406Sopenharmony_ci	{
527141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 6 Error\n");
528141cc406Sopenharmony_ci	  err++;
529141cc406Sopenharmony_ci	}
530141cc406Sopenharmony_ci      if (sense[22] & 0x80)
531141cc406Sopenharmony_ci	{
532141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 7 Error\n");
533141cc406Sopenharmony_ci	  err++;
534141cc406Sopenharmony_ci	}
535141cc406Sopenharmony_ci      if (sense[23] & 0x01)
536141cc406Sopenharmony_ci	{
537141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 8 Error\n");
538141cc406Sopenharmony_ci	  err++;
539141cc406Sopenharmony_ci	}
540141cc406Sopenharmony_ci      if (sense[23] & 0x02)
541141cc406Sopenharmony_ci	{
542141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 9 Error\n");
543141cc406Sopenharmony_ci	  err++;
544141cc406Sopenharmony_ci	}
545141cc406Sopenharmony_ci      if (sense[23] & 0x04)
546141cc406Sopenharmony_ci	{
547141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 10 Error\n");
548141cc406Sopenharmony_ci	  err++;
549141cc406Sopenharmony_ci	}
550141cc406Sopenharmony_ci      if (sense[23] & 0x08)
551141cc406Sopenharmony_ci	{
552141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 11 Error\n");
553141cc406Sopenharmony_ci	  err++;
554141cc406Sopenharmony_ci	}
555141cc406Sopenharmony_ci      if (sense[23] & 0x10)
556141cc406Sopenharmony_ci	{
557141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 12 Error\n");
558141cc406Sopenharmony_ci	  err++;
559141cc406Sopenharmony_ci	}
560141cc406Sopenharmony_ci      if (sense[23] & 0x20)
561141cc406Sopenharmony_ci	{
562141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 13 Error\n");
563141cc406Sopenharmony_ci	  err++;
564141cc406Sopenharmony_ci	}
565141cc406Sopenharmony_ci      if (sense[23] & 0x40)
566141cc406Sopenharmony_ci	{
567141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 14 Error\n");
568141cc406Sopenharmony_ci	  err++;
569141cc406Sopenharmony_ci	}
570141cc406Sopenharmony_ci      if (sense[23] & 0x80)
571141cc406Sopenharmony_ci	{
572141cc406Sopenharmony_ci	  DBG (2, "sense:  Test 15 Error\n");
573141cc406Sopenharmony_ci	  err++;
574141cc406Sopenharmony_ci	}
575141cc406Sopenharmony_ci    }
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci  if (err)
578141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci  switch (sense[0])
581141cc406Sopenharmony_ci    {
582141cc406Sopenharmony_ci    case 0x70:			/* ALWAYS */
583141cc406Sopenharmony_ci      switch (sense[2])
584141cc406Sopenharmony_ci	{
585141cc406Sopenharmony_ci	case 0x00:
586141cc406Sopenharmony_ci	  DBG (2, "sense:  Successful command\n");
587141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
588141cc406Sopenharmony_ci	case 0x02:
589141cc406Sopenharmony_ci	  DBG (2, "sense:  Not Ready, target can not be accessed\n");
590141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
591141cc406Sopenharmony_ci	case 0x03:
592141cc406Sopenharmony_ci	  DBG (2, "sense:  Medium Error, paper jam or misfeed during ADF\n");
593141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
594141cc406Sopenharmony_ci	case 0x04:
595141cc406Sopenharmony_ci	  DBG (2, "sense:  Hardware Error, non-recoverable\n");
596141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
597141cc406Sopenharmony_ci	case 0x05:
598141cc406Sopenharmony_ci	  DBG (2, "sense:  Illegal Request, bad parameter in command block\n");
599141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
600141cc406Sopenharmony_ci	case 0x06:
601141cc406Sopenharmony_ci	  DBG (2, "sense:  Unit Attention\n");
602141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
603141cc406Sopenharmony_ci	default:
604141cc406Sopenharmony_ci	  DBG (2, "sense:  SENSE KEY UNKNOWN (%02x)\n", sense[2]);
605141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
606141cc406Sopenharmony_ci	}
607141cc406Sopenharmony_ci    default:
608141cc406Sopenharmony_ci      DBG (2, "sense: Unknown Error Code Qualifier (%02x)\n", sense[0]);
609141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
610141cc406Sopenharmony_ci    }
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci  DBG (2, "sense: Should not come here!\n");
613141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
614141cc406Sopenharmony_ci}
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci/* DB added a wait routine for the scanner to come ready */
618141cc406Sopenharmony_cistatic SANE_Status
619141cc406Sopenharmony_ciwait_ready (int fd)
620141cc406Sopenharmony_ci{
621141cc406Sopenharmony_ci  SANE_Status status;
622141cc406Sopenharmony_ci  int retry = 30;		/* make this tuneable? */
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci  DBG (7, "wait_ready()\n");
625141cc406Sopenharmony_ci  while (retry-- > 0)
626141cc406Sopenharmony_ci    {
627141cc406Sopenharmony_ci      status = sanei_scsi_cmd (fd, test_unit_ready,
628141cc406Sopenharmony_ci			       sizeof (test_unit_ready), 0, 0);
629141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
630141cc406Sopenharmony_ci	return status;
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci      if (status == SANE_STATUS_DEVICE_BUSY)
633141cc406Sopenharmony_ci	{
634141cc406Sopenharmony_ci	  sleep (1);
635141cc406Sopenharmony_ci	  continue;
636141cc406Sopenharmony_ci	}
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci      /* status != GOOD && != BUSY */
639141cc406Sopenharmony_ci      DBG (9, "wait_ready: '%s'\n", sane_strstatus (status));
640141cc406Sopenharmony_ci      return status;
641141cc406Sopenharmony_ci    }
642141cc406Sopenharmony_ci
643141cc406Sopenharmony_ci  /* BUSY after n retries */
644141cc406Sopenharmony_ci  DBG (9, "wait_ready: '%s'\n", sane_strstatus (status));
645141cc406Sopenharmony_ci  return status;
646141cc406Sopenharmony_ci}
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci/* DB added a abort routine, executed via mode select */
649141cc406Sopenharmony_cistatic SANE_Status
650141cc406Sopenharmony_ciabort_scan (SANE_Handle handle)
651141cc406Sopenharmony_ci{
652141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
653141cc406Sopenharmony_ci  uint8_t *data, comm[22];
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci  DBG (7, "abort_scan()\n");
656141cc406Sopenharmony_ci  memset (comm, 0, sizeof (comm));
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_ci  comm[0] = 0x15;
659141cc406Sopenharmony_ci  comm[1] = 0x10;
660141cc406Sopenharmony_ci  comm[2] = 0x00;
661141cc406Sopenharmony_ci  comm[3] = 0x00;
662141cc406Sopenharmony_ci  comm[4] = 0x10;
663141cc406Sopenharmony_ci  comm[5] = 0x00;
664141cc406Sopenharmony_ci
665141cc406Sopenharmony_ci  data = comm + 6;
666141cc406Sopenharmony_ci  data[0] = 0x00;		/* mode data length */
667141cc406Sopenharmony_ci  data[1] = 0x00;		/* medium type */
668141cc406Sopenharmony_ci  data[2] = 0x00;		/* device specific parameter */
669141cc406Sopenharmony_ci  data[3] = 0x00;		/* block descriptor length */
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci  data = comm + 10;
672141cc406Sopenharmony_ci  data[0] = 0x00;		/* control page parameters */
673141cc406Sopenharmony_ci  data[1] = 0x0a;		/* parameter length */
674141cc406Sopenharmony_ci  data[2] = 0x02 | ((s->val[OPT_TRANSPARENCY].w == SANE_TRUE) ? 0x04 : 0x00) |
675141cc406Sopenharmony_ci    ((s->val[OPT_ADF].w == SANE_TRUE) ? 0x00 : 0x01);
676141cc406Sopenharmony_ci  data[3] = 0x00;		/* reserved */
677141cc406Sopenharmony_ci  data[4] = 0x00;		/* reserved */
678141cc406Sopenharmony_ci
679141cc406Sopenharmony_ci  DBG (9, "abort: sending abort command\n");
680141cc406Sopenharmony_ci  sanei_scsi_cmd (s->fd, comm, 6 + comm[4], 0, 0);
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  DBG (9, "abort: wait for scanner to come ready...\n");
683141cc406Sopenharmony_ci  wait_ready (s->fd);
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  DBG (9, "abort: resetting abort status\n");
686141cc406Sopenharmony_ci  data[2] = ((s->val[OPT_TRANSPARENCY].w == SANE_TRUE) ? 0x04 : 0x00) |
687141cc406Sopenharmony_ci    ((s->val[OPT_ADF].w == SANE_TRUE) ? 0x00 : 0x01);
688141cc406Sopenharmony_ci  sanei_scsi_cmd (s->fd, comm, 6 + comm[4], 0, 0);
689141cc406Sopenharmony_ci
690141cc406Sopenharmony_ci  DBG (9, "abort: wait for scanner to come ready...\n");
691141cc406Sopenharmony_ci  return wait_ready (s->fd);
692141cc406Sopenharmony_ci}
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_ci/* DAL - mode_select: used for transparency and ADF scanning */
695141cc406Sopenharmony_ci/* Based on abort_scan */
696141cc406Sopenharmony_cistatic SANE_Status
697141cc406Sopenharmony_ciartec_mode_select (SANE_Handle handle)
698141cc406Sopenharmony_ci{
699141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
700141cc406Sopenharmony_ci  uint8_t *data, comm[22];
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci  DBG (7, "artec_mode_select()\n");
703141cc406Sopenharmony_ci  memset (comm, 0, sizeof (comm));
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci  comm[0] = 0x15;
706141cc406Sopenharmony_ci  comm[1] = 0x10;
707141cc406Sopenharmony_ci  comm[2] = 0x00;
708141cc406Sopenharmony_ci  comm[3] = 0x00;
709141cc406Sopenharmony_ci  comm[4] = 0x10;
710141cc406Sopenharmony_ci  comm[5] = 0x00;
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  data = comm + 6;
713141cc406Sopenharmony_ci  data[0] = 0x00;		/* mode data length */
714141cc406Sopenharmony_ci  data[1] = 0x00;		/* medium type */
715141cc406Sopenharmony_ci  data[2] = 0x00;		/* device specific parameter */
716141cc406Sopenharmony_ci  data[3] = 0x00;		/* block descriptor length */
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci  data = comm + 10;
719141cc406Sopenharmony_ci  data[0] = 0x00;		/* control page parameters */
720141cc406Sopenharmony_ci  data[1] = 0x0a;		/* parameter length */
721141cc406Sopenharmony_ci  data[2] = ((s->val[OPT_TRANSPARENCY].w == SANE_TRUE) ? 0x04 : 0x00) |
722141cc406Sopenharmony_ci    ((s->val[OPT_ADF].w == SANE_TRUE) ? 0x00 : 0x01);
723141cc406Sopenharmony_ci  data[3] = 0x00;		/* reserved */
724141cc406Sopenharmony_ci  data[4] = 0x00;		/* reserved */
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci  DBG (9, "artec_mode_select: mode %d\n", data[2]);
727141cc406Sopenharmony_ci  DBG (9, "artec_mode_select: sending mode command\n");
728141cc406Sopenharmony_ci  sanei_scsi_cmd (s->fd, comm, 6 + comm[4], 0, 0);
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci  DBG (9, "artec_mode_select: wait for scanner to come ready...\n");
731141cc406Sopenharmony_ci  return wait_ready (s->fd);
732141cc406Sopenharmony_ci}
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_cistatic SANE_Status
736141cc406Sopenharmony_ciread_data (int fd, int data_type_code, u_char * dest, size_t * len)
737141cc406Sopenharmony_ci{
738141cc406Sopenharmony_ci  static u_char read_6[10];
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci  DBG (7, "read_data()\n");
741141cc406Sopenharmony_ci
742141cc406Sopenharmony_ci  memset (read_6, 0, sizeof (read_6));
743141cc406Sopenharmony_ci  read_6[0] = 0x28;
744141cc406Sopenharmony_ci  read_6[2] = data_type_code;
745141cc406Sopenharmony_ci  read_6[6] = *len >> 16;
746141cc406Sopenharmony_ci  read_6[7] = *len >> 8;
747141cc406Sopenharmony_ci  read_6[8] = *len;
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  return (sanei_scsi_cmd (fd, read_6, sizeof (read_6), dest, len));
750141cc406Sopenharmony_ci}
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_cistatic int
753141cc406Sopenharmony_ciartec_get_status (int fd)
754141cc406Sopenharmony_ci{
755141cc406Sopenharmony_ci  u_char write_10[10];
756141cc406Sopenharmony_ci  u_char read_12[12];
757141cc406Sopenharmony_ci  size_t nread;
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci  DBG (7, "artec_get_status()\n");
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci  nread = 12;
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci  memset (write_10, 0, 10);
764141cc406Sopenharmony_ci  write_10[0] = 0x34;
765141cc406Sopenharmony_ci  write_10[8] = 0x0c;
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci  sanei_scsi_cmd (fd, write_10, 10, read_12, &nread);
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci  nread = (read_12[9] << 16) + (read_12[10] << 8) + read_12[11];
770141cc406Sopenharmony_ci  DBG (9, "artec_status: %lu\n", (u_long) nread);
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci  return (nread);
773141cc406Sopenharmony_ci}
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_cistatic SANE_Status
776141cc406Sopenharmony_ciartec_reverse_line (SANE_Handle handle, SANE_Byte * data)
777141cc406Sopenharmony_ci{
778141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
779141cc406Sopenharmony_ci  SANE_Byte tmp_buf[32768];	/* max dpi 1200 * 8.5 inches * 3 = 30600 */
780141cc406Sopenharmony_ci  SANE_Byte *to, *from;
781141cc406Sopenharmony_ci  int len;
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ci  DBG (8, "artec_reverse_line()\n");
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci  len = s->params.bytes_per_line;
786141cc406Sopenharmony_ci  memcpy (tmp_buf, data, len);
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci  if (s->params.format == SANE_FRAME_RGB)	/* RGB format */
789141cc406Sopenharmony_ci    {
790141cc406Sopenharmony_ci      for (from = tmp_buf, to = data + len - 3;
791141cc406Sopenharmony_ci	   to >= data;
792141cc406Sopenharmony_ci	   to -= 3, from += 3)
793141cc406Sopenharmony_ci	{
794141cc406Sopenharmony_ci	  *(to + 0) = *(from + 0);	/* copy the R byte */
795141cc406Sopenharmony_ci	  *(to + 1) = *(from + 1);	/* copy the G byte */
796141cc406Sopenharmony_ci	  *(to + 2) = *(from + 2);	/* copy the B byte */
797141cc406Sopenharmony_ci	}
798141cc406Sopenharmony_ci    }
799141cc406Sopenharmony_ci  else if (s->params.format == SANE_FRAME_GRAY)
800141cc406Sopenharmony_ci    {
801141cc406Sopenharmony_ci      if (s->params.depth == 8)	/* 256 color gray-scale */
802141cc406Sopenharmony_ci	{
803141cc406Sopenharmony_ci	  for (from = tmp_buf, to = data + len; to >= data; to--, from++)
804141cc406Sopenharmony_ci	    {
805141cc406Sopenharmony_ci	      *to = *from;
806141cc406Sopenharmony_ci	    }
807141cc406Sopenharmony_ci	}
808141cc406Sopenharmony_ci      else if (s->params.depth == 1)	/* line art or halftone */
809141cc406Sopenharmony_ci	{
810141cc406Sopenharmony_ci	  for (from = tmp_buf, to = data + len; to >= data; to--, from++)
811141cc406Sopenharmony_ci	    {
812141cc406Sopenharmony_ci	      *to = (((*from & 0x01) << 7) |
813141cc406Sopenharmony_ci		     ((*from & 0x02) << 5) |
814141cc406Sopenharmony_ci		     ((*from & 0x04) << 3) |
815141cc406Sopenharmony_ci		     ((*from & 0x08) << 1) |
816141cc406Sopenharmony_ci		     ((*from & 0x10) >> 1) |
817141cc406Sopenharmony_ci		     ((*from & 0x20) >> 3) |
818141cc406Sopenharmony_ci		     ((*from & 0x40) >> 5) |
819141cc406Sopenharmony_ci		     ((*from & 0x80) >> 7));
820141cc406Sopenharmony_ci	    }
821141cc406Sopenharmony_ci	}
822141cc406Sopenharmony_ci    }
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
825141cc406Sopenharmony_ci}
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci
828141cc406Sopenharmony_ci#if 0
829141cc406Sopenharmony_cistatic SANE_Status
830141cc406Sopenharmony_ciartec_byte_rgb_to_line_rgb (SANE_Byte * data, SANE_Int len)
831141cc406Sopenharmony_ci{
832141cc406Sopenharmony_ci  SANE_Byte tmp_buf[32768];	/* max dpi 1200 * 8.5 inches * 3 = 30600 */
833141cc406Sopenharmony_ci  int count, from;
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_ci  DBG (8, "artec_byte_rgb_to_line_rgb()\n");
836141cc406Sopenharmony_ci
837141cc406Sopenharmony_ci  /* copy the RGBRGBRGBRGBRGB... formatted data to our temp buffer */
838141cc406Sopenharmony_ci  memcpy (tmp_buf, data, len * 3);
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci  /* now copy back to *data in RRRRRRRGGGGGGGBBBBBBB format */
841141cc406Sopenharmony_ci  for (count = 0, from = 0; count < len; count++, from += 3)
842141cc406Sopenharmony_ci    {
843141cc406Sopenharmony_ci      data[count] = tmp_buf[from];	/* R byte */
844141cc406Sopenharmony_ci      data[count + len] = tmp_buf[from + 1];	/* G byte */
845141cc406Sopenharmony_ci      data[count + (len * 2)] = tmp_buf[from + 2];	/* B byte */
846141cc406Sopenharmony_ci    }
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
849141cc406Sopenharmony_ci}
850141cc406Sopenharmony_ci#endif
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_cistatic SANE_Status
853141cc406Sopenharmony_ciartec_line_rgb_to_byte_rgb (SANE_Byte * data, SANE_Int len)
854141cc406Sopenharmony_ci{
855141cc406Sopenharmony_ci  SANE_Byte tmp_buf[32768];	/* max dpi 1200 * 8.5 inches * 3 = 30600 */
856141cc406Sopenharmony_ci  int count, to;
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci  DBG (8, "artec_line_rgb_to_byte_rgb()\n");
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci  /* copy the rgb data to our temp buffer */
861141cc406Sopenharmony_ci  memcpy (tmp_buf, data, len * 3);
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci  /* now copy back to *data in RGB format */
864141cc406Sopenharmony_ci  for (count = 0, to = 0; count < len; count++, to += 3)
865141cc406Sopenharmony_ci    {
866141cc406Sopenharmony_ci      data[to] = tmp_buf[count];	/* R byte */
867141cc406Sopenharmony_ci      data[to + 1] = tmp_buf[count + len];	/* G byte */
868141cc406Sopenharmony_ci      data[to + 2] = tmp_buf[count + (len * 2)];	/* B byte */
869141cc406Sopenharmony_ci    }
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
872141cc406Sopenharmony_ci}
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_cistatic SANE_Byte **line_buffer = NULL;
875141cc406Sopenharmony_cistatic SANE_Byte *tmp_line_buf = NULL;
876141cc406Sopenharmony_cistatic SANE_Int r_buf_lines;
877141cc406Sopenharmony_cistatic SANE_Int g_buf_lines;
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_cistatic SANE_Status
880141cc406Sopenharmony_ciartec_buffer_line_offset (SANE_Handle handle, SANE_Int line_offset,
881141cc406Sopenharmony_ci			  SANE_Byte * data, size_t * len)
882141cc406Sopenharmony_ci{
883141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
884141cc406Sopenharmony_ci  static SANE_Int width;
885141cc406Sopenharmony_ci  static SANE_Int cur_line;
886141cc406Sopenharmony_ci  SANE_Byte *tmp_buf_ptr;
887141cc406Sopenharmony_ci  SANE_Byte *grn_ptr;
888141cc406Sopenharmony_ci  SANE_Byte *blu_ptr;
889141cc406Sopenharmony_ci  SANE_Byte *out_ptr;
890141cc406Sopenharmony_ci  int count;
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci  DBG (8, "artec_buffer_line_offset()\n");
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_ci  if (*len == 0)
895141cc406Sopenharmony_ci    return (SANE_STATUS_GOOD);
896141cc406Sopenharmony_ci
897141cc406Sopenharmony_ci  if (tmp_line_buf == NULL)
898141cc406Sopenharmony_ci    {
899141cc406Sopenharmony_ci      width = *len / 3;
900141cc406Sopenharmony_ci      cur_line = 0;
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_ci      DBG (9, "buffer_line_offset: offset = %d, len = %lu\n",
903141cc406Sopenharmony_ci	   line_offset, (u_long) * len);
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci      tmp_line_buf = malloc (*len);
906141cc406Sopenharmony_ci      if (tmp_line_buf == NULL)
907141cc406Sopenharmony_ci	{
908141cc406Sopenharmony_ci	  DBG (1, "couldn't allocate memory for temp line buffer\n");
909141cc406Sopenharmony_ci	  return (SANE_STATUS_NO_MEM);
910141cc406Sopenharmony_ci	}
911141cc406Sopenharmony_ci
912141cc406Sopenharmony_ci      r_buf_lines = line_offset * 2;
913141cc406Sopenharmony_ci      g_buf_lines = line_offset;
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ci      line_buffer = malloc (r_buf_lines * sizeof (SANE_Byte *));
916141cc406Sopenharmony_ci      if (line_buffer == NULL)
917141cc406Sopenharmony_ci	{
918141cc406Sopenharmony_ci	  DBG (1, "couldn't allocate memory for line buffer pointers\n");
919141cc406Sopenharmony_ci	  return (SANE_STATUS_NO_MEM);
920141cc406Sopenharmony_ci	}
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci      for (count = 0; count < r_buf_lines; count++)
923141cc406Sopenharmony_ci	{
924141cc406Sopenharmony_ci	  line_buffer[count] = malloc ((*len) * sizeof (SANE_Byte));
925141cc406Sopenharmony_ci	  if (line_buffer[count] == NULL)
926141cc406Sopenharmony_ci	    {
927141cc406Sopenharmony_ci	      DBG (1, "couldn't allocate memory for line buffer %d\n",
928141cc406Sopenharmony_ci		   count);
929141cc406Sopenharmony_ci	      return (SANE_STATUS_NO_MEM);
930141cc406Sopenharmony_ci	    }
931141cc406Sopenharmony_ci	}
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci      DBG (9, "buffer_line_offset: r lines = %d, g lines = %d\n",
934141cc406Sopenharmony_ci	   r_buf_lines, g_buf_lines);
935141cc406Sopenharmony_ci    }
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci  cur_line++;
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  if (r_buf_lines > 0)
940141cc406Sopenharmony_ci    {
941141cc406Sopenharmony_ci      if (cur_line > r_buf_lines)
942141cc406Sopenharmony_ci	{
943141cc406Sopenharmony_ci	  /* copy the Red and Green portions out of the buffer */
944141cc406Sopenharmony_ci	  /* if scanner returns RRRRRRRRGGGGGGGGGBBBBBBBB format it's easier */
945141cc406Sopenharmony_ci	  if (s->hw->flags & ARTEC_FLAG_RGB_CHAR_SHIFT)
946141cc406Sopenharmony_ci	    {
947141cc406Sopenharmony_ci	      /* get the red line info from r_buf_lines ago */
948141cc406Sopenharmony_ci	      memcpy (tmp_line_buf, line_buffer[0], width);
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci	      /* get the green line info from g_buf_lines ago */
951141cc406Sopenharmony_ci	      memcpy (tmp_line_buf + width, &line_buffer[line_offset][width],
952141cc406Sopenharmony_ci		      width);
953141cc406Sopenharmony_ci	    }
954141cc406Sopenharmony_ci	  else
955141cc406Sopenharmony_ci	    {
956141cc406Sopenharmony_ci	      /* get the red line info from r_buf_lines ago as a whole line */
957141cc406Sopenharmony_ci	      memcpy (tmp_line_buf, line_buffer[0], *len);
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci	      /* scanner returns RGBRGBRGB format so we do a loop for green */
960141cc406Sopenharmony_ci	      grn_ptr = &line_buffer[line_offset][1];
961141cc406Sopenharmony_ci	      out_ptr = tmp_line_buf + 1;
962141cc406Sopenharmony_ci	      for (count = 0; count < width; count++)
963141cc406Sopenharmony_ci		{
964141cc406Sopenharmony_ci		  *out_ptr = *grn_ptr;	/* copy green pixel */
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci		  grn_ptr += 3;
967141cc406Sopenharmony_ci		  out_ptr += 3;
968141cc406Sopenharmony_ci		}
969141cc406Sopenharmony_ci	    }
970141cc406Sopenharmony_ci	}
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci      /* move all the buffered lines down (just move the ptrs for speed) */
973141cc406Sopenharmony_ci      tmp_buf_ptr = line_buffer[0];
974141cc406Sopenharmony_ci      for (count = 0; count < (r_buf_lines - 1); count++)
975141cc406Sopenharmony_ci	{
976141cc406Sopenharmony_ci	  line_buffer[count] = line_buffer[count + 1];
977141cc406Sopenharmony_ci	}
978141cc406Sopenharmony_ci      line_buffer[r_buf_lines - 1] = tmp_buf_ptr;
979141cc406Sopenharmony_ci
980141cc406Sopenharmony_ci      /* insert the new line data at the end of our FIFO */
981141cc406Sopenharmony_ci      memcpy (line_buffer[r_buf_lines - 1], data, *len);
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci      if (cur_line > r_buf_lines)
984141cc406Sopenharmony_ci	{
985141cc406Sopenharmony_ci	  /* copy the Red and Green portions out of the buffer */
986141cc406Sopenharmony_ci	  /* if scanner returns RRRRRRRRGGGGGGGGGBBBBBBBB format it's easier */
987141cc406Sopenharmony_ci	  if (s->hw->flags & ARTEC_FLAG_RGB_CHAR_SHIFT)
988141cc406Sopenharmony_ci	    {
989141cc406Sopenharmony_ci	      /* copy the red and green data in with the original blue */
990141cc406Sopenharmony_ci	      memcpy (data, tmp_line_buf, width * 2);
991141cc406Sopenharmony_ci	    }
992141cc406Sopenharmony_ci	  else
993141cc406Sopenharmony_ci	    {
994141cc406Sopenharmony_ci	      /* scanner returns RGBRGBRGB format so we have to do a loop */
995141cc406Sopenharmony_ci	      /* copy the blue data into our temp buffer then copy full */
996141cc406Sopenharmony_ci	      /* temp buffer overtop of input data */
997141cc406Sopenharmony_ci	      if (s->hw->flags & ARTEC_FLAG_IMAGE_REV_LR)
998141cc406Sopenharmony_ci		{
999141cc406Sopenharmony_ci		  blu_ptr = data;
1000141cc406Sopenharmony_ci		  out_ptr = tmp_line_buf;
1001141cc406Sopenharmony_ci		}
1002141cc406Sopenharmony_ci	      else
1003141cc406Sopenharmony_ci		{
1004141cc406Sopenharmony_ci		  blu_ptr = data + 2;
1005141cc406Sopenharmony_ci		  out_ptr = tmp_line_buf + 2;
1006141cc406Sopenharmony_ci		}
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci	      for (count = 0; count < width; count++)
1009141cc406Sopenharmony_ci		{
1010141cc406Sopenharmony_ci		  *out_ptr = *blu_ptr;	/* copy blue pixel */
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci		  blu_ptr += 3;
1013141cc406Sopenharmony_ci		  out_ptr += 3;
1014141cc406Sopenharmony_ci		}
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci	      /* now just copy tmp_line_buf back over original data */
1017141cc406Sopenharmony_ci	      memcpy (data, tmp_line_buf, *len);
1018141cc406Sopenharmony_ci	    }
1019141cc406Sopenharmony_ci	}
1020141cc406Sopenharmony_ci      else
1021141cc406Sopenharmony_ci	{
1022141cc406Sopenharmony_ci	  /* if in the first r_buf_lines, then don't return anything */
1023141cc406Sopenharmony_ci	  *len = 0;
1024141cc406Sopenharmony_ci	}
1025141cc406Sopenharmony_ci    }
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1028141cc406Sopenharmony_ci}
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_cistatic SANE_Status
1031141cc406Sopenharmony_ciartec_buffer_line_offset_free (void)
1032141cc406Sopenharmony_ci{
1033141cc406Sopenharmony_ci  int count;
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci  DBG (7, "artec_buffer_line_offset_free()\n");
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci  free (tmp_line_buf);
1038141cc406Sopenharmony_ci  tmp_line_buf = NULL;
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_ci  for (count = 0; count < r_buf_lines; count++)
1041141cc406Sopenharmony_ci    {
1042141cc406Sopenharmony_ci      free (line_buffer[count]);
1043141cc406Sopenharmony_ci    }
1044141cc406Sopenharmony_ci  free (line_buffer);
1045141cc406Sopenharmony_ci  line_buffer = NULL;
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1048141cc406Sopenharmony_ci}
1049141cc406Sopenharmony_ci
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci#if 0
1052141cc406Sopenharmony_cistatic SANE_Status
1053141cc406Sopenharmony_ciartec_read_gamma_table (SANE_Handle handle)
1054141cc406Sopenharmony_ci{
1055141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1056141cc406Sopenharmony_ci  char write_6[4096 + 20];	/* max gamma table is 4096 + 20 for command data */
1057141cc406Sopenharmony_ci  char *data;
1058141cc406Sopenharmony_ci  char prt_buf[128];
1059141cc406Sopenharmony_ci  char tmp_buf[128];
1060141cc406Sopenharmony_ci  int i;
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci  DBG (7, "artec_read_gamma_table()\n");
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci  memset (write_6, 0, sizeof (*write_6));
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci  write_6[0] = 0x28;		/* read data code */
1067141cc406Sopenharmony_ci
1068141cc406Sopenharmony_ci  /* FIXME: AT12 and AM12S use 0x0E for reading all channels of data */
1069141cc406Sopenharmony_ci  write_6[2] = 0x03;		/* data type code "gamma data" */
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  write_6[6] = (s->gamma_length + 9) >> 16;
1072141cc406Sopenharmony_ci  write_6[7] = (s->gamma_length + 9) >> 8;
1073141cc406Sopenharmony_ci  write_6[8] = (s->gamma_length + 9);
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci  /* FIXME: AT12 and AM12S have one less byte so use 18 */
1076141cc406Sopenharmony_ci  if ((!strcmp (s->hw->sane.model, "AT12")) ||
1077141cc406Sopenharmony_ci      (!strcmp (s->hw->sane.model, "AM12S")))
1078141cc406Sopenharmony_ci    {
1079141cc406Sopenharmony_ci      data = write_6 + 18;
1080141cc406Sopenharmony_ci    }
1081141cc406Sopenharmony_ci  else
1082141cc406Sopenharmony_ci    {
1083141cc406Sopenharmony_ci      data = write_6 + 19;
1084141cc406Sopenharmony_ci    }
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci  /* FIXME: AT12 & AM12S ignore this, it's a reserved field */
1087141cc406Sopenharmony_ci  write_6[10] = 0x08;		/* bitmask, bit 3 means mono type */
1088141cc406Sopenharmony_ci
1089141cc406Sopenharmony_ci  if (!s->val[OPT_CUSTOM_GAMMA].w)
1090141cc406Sopenharmony_ci    {
1091141cc406Sopenharmony_ci      write_6[11] = 1;		/* internal gamma table #1 (hope this is default) */
1092141cc406Sopenharmony_ci    }
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci  DBG( 9, "Gamma Table\n" );
1095141cc406Sopenharmony_ci  DBG( 9, "==================================\n" );
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci  prt_buf[0] = '\0';
1098141cc406Sopenharmony_ci  for (i = 0; i < s->gamma_length; i++)
1099141cc406Sopenharmony_ci    {
1100141cc406Sopenharmony_ci      if (DBG_LEVEL >= 9)
1101141cc406Sopenharmony_ci	{
1102141cc406Sopenharmony_ci	  if (!(i % 16))
1103141cc406Sopenharmony_ci	    {
1104141cc406Sopenharmony_ci	      if ( prt_buf[0] )
1105141cc406Sopenharmony_ci		{
1106141cc406Sopenharmony_ci		  strcat( prt_buf, "\n" );
1107141cc406Sopenharmony_ci		  DBG( 9, "%s", prt_buf );
1108141cc406Sopenharmony_ci		}
1109141cc406Sopenharmony_ci	      sprintf (prt_buf, "%02x: ", i);
1110141cc406Sopenharmony_ci	    }
1111141cc406Sopenharmony_ci	  sprintf (tmp_buf, "%02x ", (int) s->gamma_table[0][i]);
1112141cc406Sopenharmony_ci	  strcat (prt_buf, tmp_buf );
1113141cc406Sopenharmony_ci	}
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci      data[i] = s->gamma_table[0][i];
1116141cc406Sopenharmony_ci    }
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_ci  if ( prt_buf[0] )
1119141cc406Sopenharmony_ci    {
1120141cc406Sopenharmony_ci      strcat( prt_buf, "\n" );
1121141cc406Sopenharmony_ci      DBG( 9, "%s", prt_buf );
1122141cc406Sopenharmony_ci    }
1123141cc406Sopenharmony_ci
1124141cc406Sopenharmony_ci  if ((!strcmp (s->hw->sane.model, "AT12")) ||
1125141cc406Sopenharmony_ci      (!strcmp (s->hw->sane.model, "AM12S")))
1126141cc406Sopenharmony_ci    {
1127141cc406Sopenharmony_ci      return (sanei_scsi_cmd (s->fd, write_6, 10 + 8 + s->gamma_length, 0, 0));
1128141cc406Sopenharmony_ci    }
1129141cc406Sopenharmony_ci  else
1130141cc406Sopenharmony_ci    {
1131141cc406Sopenharmony_ci      return (sanei_scsi_cmd (s->fd, write_6, 10 + 9 + s->gamma_length, 0, 0));
1132141cc406Sopenharmony_ci    }
1133141cc406Sopenharmony_ci}
1134141cc406Sopenharmony_ci#endif
1135141cc406Sopenharmony_ci
1136141cc406Sopenharmony_cistatic SANE_Status
1137141cc406Sopenharmony_ciartec_send_gamma_table (SANE_Handle handle)
1138141cc406Sopenharmony_ci{
1139141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1140141cc406Sopenharmony_ci  char write_6[4096 + 20];	/* max gamma table is 4096 + 20 for command data */
1141141cc406Sopenharmony_ci  char *data;
1142141cc406Sopenharmony_ci  char prt_buf[128];
1143141cc406Sopenharmony_ci  char tmp_buf[128];
1144141cc406Sopenharmony_ci  int i;
1145141cc406Sopenharmony_ci
1146141cc406Sopenharmony_ci  DBG (7, "artec_send_gamma_table()\n");
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci  memset (write_6, 0, sizeof (*write_6));
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_ci  write_6[0] = 0x2a;		/* send data code */
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci  if (s->hw->setwindow_cmd_size > 55)
1153141cc406Sopenharmony_ci    {
1154141cc406Sopenharmony_ci      /* newer scanners support sending 3 channels of gamma, or populating all */
1155141cc406Sopenharmony_ci      /* 3 channels with same data by using code 0x0e */
1156141cc406Sopenharmony_ci      write_6[2] = 0x0e;
1157141cc406Sopenharmony_ci    }
1158141cc406Sopenharmony_ci  else
1159141cc406Sopenharmony_ci    {
1160141cc406Sopenharmony_ci      /* older scanners only support 1 channel of gamma data using code 0x3 */
1161141cc406Sopenharmony_ci      write_6[2] = 0x03;
1162141cc406Sopenharmony_ci    }
1163141cc406Sopenharmony_ci
1164141cc406Sopenharmony_ci  /* FIXME: AT12 & AM!2S ignore this, it's a reserved field */
1165141cc406Sopenharmony_ci  write_6[10] = 0x08;		/* bitmask, bit 3 means mono type */
1166141cc406Sopenharmony_ci
1167141cc406Sopenharmony_ci  if (!s->val[OPT_CUSTOM_GAMMA].w)
1168141cc406Sopenharmony_ci    {
1169141cc406Sopenharmony_ci      write_6[6] = 9 >> 16;
1170141cc406Sopenharmony_ci      write_6[7] = 9 >> 8;
1171141cc406Sopenharmony_ci      write_6[8] = 9;
1172141cc406Sopenharmony_ci      write_6[11] = 1;		/* internal gamma table #1 (hope this is default) */
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci      return (sanei_scsi_cmd (s->fd, write_6, 10 + 9, 0, 0));
1175141cc406Sopenharmony_ci    }
1176141cc406Sopenharmony_ci  else
1177141cc406Sopenharmony_ci    {
1178141cc406Sopenharmony_ci      write_6[6] = (s->gamma_length + 9) >> 16;
1179141cc406Sopenharmony_ci      write_6[7] = (s->gamma_length + 9) >> 8;
1180141cc406Sopenharmony_ci      write_6[8] = (s->gamma_length + 9);
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci      DBG( 9, "Gamma Table\n" );
1183141cc406Sopenharmony_ci      DBG( 9, "==================================\n" );
1184141cc406Sopenharmony_ci
1185141cc406Sopenharmony_ci      /* FIXME: AT12 and AM12S have one less byte so use 18 */
1186141cc406Sopenharmony_ci      if ((!strcmp (s->hw->sane.model, "AT12")) ||
1187141cc406Sopenharmony_ci	  (!strcmp (s->hw->sane.model, "AM12S")))
1188141cc406Sopenharmony_ci	{
1189141cc406Sopenharmony_ci	  data = write_6 + 18;
1190141cc406Sopenharmony_ci	}
1191141cc406Sopenharmony_ci      else
1192141cc406Sopenharmony_ci	{
1193141cc406Sopenharmony_ci	  data = write_6 + 19;
1194141cc406Sopenharmony_ci	}
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci      prt_buf[0] = '\0';
1197141cc406Sopenharmony_ci      for (i = 0; i < s->gamma_length; i++)
1198141cc406Sopenharmony_ci	{
1199141cc406Sopenharmony_ci	  if (DBG_LEVEL >= 9)
1200141cc406Sopenharmony_ci	    {
1201141cc406Sopenharmony_ci	      if (!(i % 16))
1202141cc406Sopenharmony_ci		{
1203141cc406Sopenharmony_ci		  if ( prt_buf[0] )
1204141cc406Sopenharmony_ci		    {
1205141cc406Sopenharmony_ci		      strcat( prt_buf, "\n" );
1206141cc406Sopenharmony_ci		      DBG( 9, "%s", prt_buf );
1207141cc406Sopenharmony_ci		    }
1208141cc406Sopenharmony_ci		  sprintf (prt_buf, "%02x: ", i);
1209141cc406Sopenharmony_ci		}
1210141cc406Sopenharmony_ci	      sprintf (tmp_buf, "%02x ", (int) s->gamma_table[0][i]);
1211141cc406Sopenharmony_ci	      strcat (prt_buf, tmp_buf );
1212141cc406Sopenharmony_ci	    }
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci	  data[i] = s->gamma_table[0][i];
1215141cc406Sopenharmony_ci	}
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci      data[s->gamma_length - 1] = 0;
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci      if ( prt_buf[0] )
1220141cc406Sopenharmony_ci	{
1221141cc406Sopenharmony_ci	  strcat( prt_buf, "\n" );
1222141cc406Sopenharmony_ci	  DBG( 9, "%s", prt_buf );
1223141cc406Sopenharmony_ci	}
1224141cc406Sopenharmony_ci
1225141cc406Sopenharmony_ci      /* FIXME: AT12 and AM12S have one less byte so use 18 */
1226141cc406Sopenharmony_ci      if ((!strcmp (s->hw->sane.model, "AT12")) ||
1227141cc406Sopenharmony_ci	  (!strcmp (s->hw->sane.model, "AM12S")))
1228141cc406Sopenharmony_ci	{
1229141cc406Sopenharmony_ci	  return (sanei_scsi_cmd (s->fd, write_6, 10 + 8 + s->gamma_length, 0, 0));
1230141cc406Sopenharmony_ci	}
1231141cc406Sopenharmony_ci      else
1232141cc406Sopenharmony_ci	{
1233141cc406Sopenharmony_ci	  return (sanei_scsi_cmd (s->fd, write_6, 10 + 9 + s->gamma_length, 0, 0));
1234141cc406Sopenharmony_ci	}
1235141cc406Sopenharmony_ci    }
1236141cc406Sopenharmony_ci}
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_cistatic SANE_Status
1239141cc406Sopenharmony_ciartec_set_scan_window (SANE_Handle handle)
1240141cc406Sopenharmony_ci{
1241141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1242141cc406Sopenharmony_ci  char write_6[4096];
1243141cc406Sopenharmony_ci  unsigned char *data;
1244141cc406Sopenharmony_ci  int counter;
1245141cc406Sopenharmony_ci  int reversed_x;
1246141cc406Sopenharmony_ci  int max_x;
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci  DBG (7, "artec_set_scan_window()\n");
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci  /*
1251141cc406Sopenharmony_ci   * if we can, start before the desired window since we have to throw away
1252141cc406Sopenharmony_ci   * s->line_offset number of rows because of the RGB fixup.
1253141cc406Sopenharmony_ci   */
1254141cc406Sopenharmony_ci  if ((s->line_offset) &&
1255141cc406Sopenharmony_ci      (s->tl_y) &&
1256141cc406Sopenharmony_ci      (s->tl_y >= (s->line_offset * 2)))
1257141cc406Sopenharmony_ci    {
1258141cc406Sopenharmony_ci      s->tl_y -= (s->line_offset * 2);
1259141cc406Sopenharmony_ci    }
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci  data = (unsigned char *)write_6 + 10;
1262141cc406Sopenharmony_ci
1263141cc406Sopenharmony_ci  DBG (5, "Scan window info:\n");
1264141cc406Sopenharmony_ci  DBG (5, "  X resolution: %5d (%d-%d)\n",
1265141cc406Sopenharmony_ci       s->x_resolution, ARTEC_MIN_X (s->hw), ARTEC_MAX_X (s->hw));
1266141cc406Sopenharmony_ci  DBG (5, "  Y resolution: %5d (%d-%d)\n",
1267141cc406Sopenharmony_ci       s->y_resolution, ARTEC_MIN_Y (s->hw), ARTEC_MAX_Y (s->hw));
1268141cc406Sopenharmony_ci  DBG (5, "  TL_X (pixel): %5d\n",
1269141cc406Sopenharmony_ci       s->tl_x);
1270141cc406Sopenharmony_ci  DBG (5, "  TL_Y (pixel): %5d\n",
1271141cc406Sopenharmony_ci       s->tl_y);
1272141cc406Sopenharmony_ci  DBG (5, "  Width       : %5d (%d-%d)\n",
1273141cc406Sopenharmony_ci       s->params.pixels_per_line,
1274141cc406Sopenharmony_ci       s->hw->x_range.min,
1275141cc406Sopenharmony_ci       (int) ((SANE_UNFIX (s->hw->x_range.max) / MM_PER_INCH) *
1276141cc406Sopenharmony_ci	      s->x_resolution));
1277141cc406Sopenharmony_ci  DBG (5, "  Height      : %5d (%d-%d)\n",
1278141cc406Sopenharmony_ci       s->params.lines,
1279141cc406Sopenharmony_ci       s->hw->y_range.min,
1280141cc406Sopenharmony_ci       (int) ((SANE_UNFIX (s->hw->y_range.max) / MM_PER_INCH) *
1281141cc406Sopenharmony_ci	      s->y_resolution));
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci  DBG (5, "  Image Comp. : %s\n", s->mode);
1284141cc406Sopenharmony_ci  DBG (5, "  Line Offset : %lu\n", (u_long) s->line_offset);
1285141cc406Sopenharmony_ci
1286141cc406Sopenharmony_ci  memset (write_6, 0, 4096);
1287141cc406Sopenharmony_ci  write_6[0] = 0x24;
1288141cc406Sopenharmony_ci  write_6[8] = s->hw->setwindow_cmd_size;	/* total size of command */
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  /* beginning of set window data header */
1291141cc406Sopenharmony_ci  /* actual SCSI command data byte count */
1292141cc406Sopenharmony_ci  data[7] = s->hw->setwindow_cmd_size - 8;
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci  /* x resolution */
1295141cc406Sopenharmony_ci  data[10] = s->x_resolution >> 8;
1296141cc406Sopenharmony_ci  data[11] = s->x_resolution;
1297141cc406Sopenharmony_ci
1298141cc406Sopenharmony_ci  /* y resolution */
1299141cc406Sopenharmony_ci  data[12] = s->y_resolution >> 8;
1300141cc406Sopenharmony_ci  data[13] = s->y_resolution;
1301141cc406Sopenharmony_ci
1302141cc406Sopenharmony_ci  if ( s->hw->flags & ARTEC_FLAG_REVERSE_WINDOW )
1303141cc406Sopenharmony_ci    {
1304141cc406Sopenharmony_ci      /* top left X value */
1305141cc406Sopenharmony_ci      /* the select area is flipped across the page, so we have to do some */
1306141cc406Sopenharmony_ci      /* calculation here to get the real starting X value */
1307141cc406Sopenharmony_ci      max_x = (int) ((SANE_UNFIX (s->hw->x_range.max) / MM_PER_INCH) *
1308141cc406Sopenharmony_ci	      s->x_resolution);
1309141cc406Sopenharmony_ci      reversed_x = max_x - s->tl_x - s->params.pixels_per_line;
1310141cc406Sopenharmony_ci
1311141cc406Sopenharmony_ci      data[14] = reversed_x >> 24;
1312141cc406Sopenharmony_ci      data[15] = reversed_x >> 16;
1313141cc406Sopenharmony_ci      data[16] = reversed_x >> 8;
1314141cc406Sopenharmony_ci      data[17] = reversed_x;
1315141cc406Sopenharmony_ci    }
1316141cc406Sopenharmony_ci  else
1317141cc406Sopenharmony_ci    {
1318141cc406Sopenharmony_ci      /* top left X value */
1319141cc406Sopenharmony_ci      data[14] = s->tl_x >> 24;
1320141cc406Sopenharmony_ci      data[15] = s->tl_x >> 16;
1321141cc406Sopenharmony_ci      data[16] = s->tl_x >> 8;
1322141cc406Sopenharmony_ci      data[17] = s->tl_x;
1323141cc406Sopenharmony_ci    }
1324141cc406Sopenharmony_ci
1325141cc406Sopenharmony_ci  /* top left Y value */
1326141cc406Sopenharmony_ci  data[18] = s->tl_y >> 24;
1327141cc406Sopenharmony_ci  data[19] = s->tl_y >> 16;
1328141cc406Sopenharmony_ci  data[20] = s->tl_y >> 8;
1329141cc406Sopenharmony_ci  data[21] = s->tl_y;
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci
1332141cc406Sopenharmony_ci  /* width */
1333141cc406Sopenharmony_ci  data[22] = s->params.pixels_per_line >> 24;
1334141cc406Sopenharmony_ci  data[23] = s->params.pixels_per_line >> 16;
1335141cc406Sopenharmony_ci  data[24] = s->params.pixels_per_line >> 8;
1336141cc406Sopenharmony_ci  data[25] = s->params.pixels_per_line;
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci  /* height */
1339141cc406Sopenharmony_ci  data[26] = (s->params.lines + (s->line_offset * 2)) >> 24;
1340141cc406Sopenharmony_ci  data[27] = (s->params.lines + (s->line_offset * 2)) >> 16;
1341141cc406Sopenharmony_ci  data[28] = (s->params.lines + (s->line_offset * 2)) >> 8;
1342141cc406Sopenharmony_ci  data[29] = (s->params.lines + (s->line_offset * 2));
1343141cc406Sopenharmony_ci
1344141cc406Sopenharmony_ci  /* misc. single-byte settings */
1345141cc406Sopenharmony_ci  /* brightness */
1346141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_OPT_BRIGHTNESS)
1347141cc406Sopenharmony_ci    data[30] = s->val[OPT_BRIGHTNESS].w;
1348141cc406Sopenharmony_ci
1349141cc406Sopenharmony_ci  data[31] = s->val[OPT_THRESHOLD].w;	/* threshold */
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci  /* contrast */
1352141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_OPT_CONTRAST)
1353141cc406Sopenharmony_ci    data[32] = s->val[OPT_CONTRAST].w;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci  /*
1356141cc406Sopenharmony_ci   * byte 33 is mode
1357141cc406Sopenharmony_ci   * byte 37 bit 7 is "negative" setting
1358141cc406Sopenharmony_ci   */
1359141cc406Sopenharmony_ci  if (strcmp (s->mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1360141cc406Sopenharmony_ci    {
1361141cc406Sopenharmony_ci      data[33] = ARTEC_COMP_LINEART;
1362141cc406Sopenharmony_ci      data[37] = (s->val[OPT_NEGATIVE].w == SANE_TRUE) ? 0x0 : 0x80;
1363141cc406Sopenharmony_ci    }
1364141cc406Sopenharmony_ci  else if (strcmp (s->mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
1365141cc406Sopenharmony_ci    {
1366141cc406Sopenharmony_ci      data[33] = ARTEC_COMP_HALFTONE;
1367141cc406Sopenharmony_ci      data[37] = (s->val[OPT_NEGATIVE].w == SANE_TRUE) ? 0x0 : 0x80;
1368141cc406Sopenharmony_ci    }
1369141cc406Sopenharmony_ci  else if (strcmp (s->mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1370141cc406Sopenharmony_ci    {
1371141cc406Sopenharmony_ci      data[33] = ARTEC_COMP_GRAY;
1372141cc406Sopenharmony_ci      data[37] = (s->val[OPT_NEGATIVE].w == SANE_TRUE) ? 0x80 : 0x0;
1373141cc406Sopenharmony_ci    }
1374141cc406Sopenharmony_ci  else if (strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1375141cc406Sopenharmony_ci    {
1376141cc406Sopenharmony_ci      data[33] = ARTEC_COMP_COLOR;
1377141cc406Sopenharmony_ci      data[37] = (s->val[OPT_NEGATIVE].w == SANE_TRUE) ? 0x80 : 0x0;
1378141cc406Sopenharmony_ci    }
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci  data[34] = s->params.depth;	/* bits per pixel */
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_HALFTONE_PATTERN)
1383141cc406Sopenharmony_ci    {
1384141cc406Sopenharmony_ci      data[35] = artec_get_str_index (halftone_pattern_list,
1385141cc406Sopenharmony_ci		      s->val[OPT_HALFTONE_PATTERN].s);	/* halftone pattern */
1386141cc406Sopenharmony_ci    }
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci  /* user supplied halftone pattern not supported for now so override with */
1389141cc406Sopenharmony_ci  /* 8x8 Bayer */
1390141cc406Sopenharmony_ci  if (data[35] == 0)
1391141cc406Sopenharmony_ci    {
1392141cc406Sopenharmony_ci      data[35] = 4;
1393141cc406Sopenharmony_ci    }
1394141cc406Sopenharmony_ci
1395141cc406Sopenharmony_ci  /* NOTE: AT12 doesn't support mono according to docs. */
1396141cc406Sopenharmony_ci  data[48] = artec_get_str_index (filter_type_list,
1397141cc406Sopenharmony_ci	  s->val[OPT_FILTER_TYPE].s);	/* filter mode */
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci  if (s->hw->setwindow_cmd_size > 55)
1400141cc406Sopenharmony_ci    {
1401141cc406Sopenharmony_ci      data[48] = 0x2;		/* DB filter type green for AT12,see above */
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci      if (s->hw->flags & ARTEC_FLAG_SC_BUFFERS_LINES)
1404141cc406Sopenharmony_ci	{
1405141cc406Sopenharmony_ci	  /* FIXME: guessing at this value, use formula instead */
1406141cc406Sopenharmony_ci	  data[55] = 0x00;	/* buffer full line count */
1407141cc406Sopenharmony_ci	  data[56] = 0x00;	/* buffer full line count */
1408141cc406Sopenharmony_ci	  data[57] = 0x00;	/* buffer full line count */
1409141cc406Sopenharmony_ci	  data[58] = 0x0a;	/* buffer full line count */
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci	  /* FIXME: guessing at this value, use formula instead */
1412141cc406Sopenharmony_ci	  data[59] = 0x00;	/* access line count */
1413141cc406Sopenharmony_ci	  data[60] = 0x00;	/* access line count */
1414141cc406Sopenharmony_ci	  data[61] = 0x00;	/* access line count */
1415141cc406Sopenharmony_ci	  data[62] = 0x0a;	/* access line count */
1416141cc406Sopenharmony_ci	}
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci      if (s->hw->flags & ARTEC_FLAG_SC_HANDLES_OFFSET)
1419141cc406Sopenharmony_ci	{
1420141cc406Sopenharmony_ci	  /* DB : following fields : high order bit (0x80) is enable */
1421141cc406Sopenharmony_ci	  /* scanner handles line offset fixup, 0 = driver handles */
1422141cc406Sopenharmony_ci	  data[63] = 0x80;
1423141cc406Sopenharmony_ci	}
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci      if ((s->hw->flags & ARTEC_FLAG_PIXEL_AVERAGING) &&
1426141cc406Sopenharmony_ci	  (s->val[OPT_PIXEL_AVG].w))
1427141cc406Sopenharmony_ci	{
1428141cc406Sopenharmony_ci	  /* enable pixel average function */
1429141cc406Sopenharmony_ci	  data[64] = 0x80;
1430141cc406Sopenharmony_ci	}
1431141cc406Sopenharmony_ci      else
1432141cc406Sopenharmony_ci	{
1433141cc406Sopenharmony_ci	  /* disable pixel average function */
1434141cc406Sopenharmony_ci	  data[64] = 0;
1435141cc406Sopenharmony_ci	}
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci      if ((s->hw->flags & ARTEC_FLAG_ENHANCE_LINE_EDGE) &&
1438141cc406Sopenharmony_ci	  (s->val[OPT_EDGE_ENH].w))
1439141cc406Sopenharmony_ci	{
1440141cc406Sopenharmony_ci	  /* enable lineart edge enhancement function */
1441141cc406Sopenharmony_ci	  data[65] = 0x80;
1442141cc406Sopenharmony_ci	}
1443141cc406Sopenharmony_ci      else
1444141cc406Sopenharmony_ci	{
1445141cc406Sopenharmony_ci	  /* disable lineart edge enhancement function */
1446141cc406Sopenharmony_ci	  data[65] = 0;
1447141cc406Sopenharmony_ci	}
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci      /* data is R-G-B format, 0x80 = G-B-R format (reversed) */
1450141cc406Sopenharmony_ci      data[66] = 0;
1451141cc406Sopenharmony_ci    }
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci  DBG (50, "Set Window data : \n");
1454141cc406Sopenharmony_ci  for (counter = 0; counter < s->hw->setwindow_cmd_size; counter++)
1455141cc406Sopenharmony_ci    {
1456141cc406Sopenharmony_ci      DBG (50, "  byte %2d = %02x \n", counter, data[counter] & 0xff);	/* DB */
1457141cc406Sopenharmony_ci    }
1458141cc406Sopenharmony_ci  DBG (50, "\n");
1459141cc406Sopenharmony_ci
1460141cc406Sopenharmony_ci  /* set the scan window */
1461141cc406Sopenharmony_ci  return (sanei_scsi_cmd (s->fd, write_6, 10 +
1462141cc406Sopenharmony_ci			  s->hw->setwindow_cmd_size, 0, 0));
1463141cc406Sopenharmony_ci}
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_cistatic SANE_Status
1466141cc406Sopenharmony_ciartec_start_scan (SANE_Handle handle)
1467141cc406Sopenharmony_ci{
1468141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1469141cc406Sopenharmony_ci  char write_7[7];
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_ci  DBG (7, "artec_start_scan()\n");
1472141cc406Sopenharmony_ci
1473141cc406Sopenharmony_ci  /* setup cmd to start scanning */
1474141cc406Sopenharmony_ci  memset (write_7, 0, 7);
1475141cc406Sopenharmony_ci  write_7[0] = 0x1b;		/* code to start scan */
1476141cc406Sopenharmony_ci
1477141cc406Sopenharmony_ci  /* FIXME: need to make this a flag */
1478141cc406Sopenharmony_ci  if (!strcmp (s->hw->sane.model, "AM12S"))
1479141cc406Sopenharmony_ci    {
1480141cc406Sopenharmony_ci      /* start the scan */
1481141cc406Sopenharmony_ci      return (sanei_scsi_cmd (s->fd, write_7, 6, 0, 0));
1482141cc406Sopenharmony_ci    }
1483141cc406Sopenharmony_ci  else
1484141cc406Sopenharmony_ci    {
1485141cc406Sopenharmony_ci      write_7[4] = 0x01;	/* need to send 1 data byte */
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci      /* start the scan */
1488141cc406Sopenharmony_ci      return (sanei_scsi_cmd (s->fd, write_7, 7, 0, 0));
1489141cc406Sopenharmony_ci    }
1490141cc406Sopenharmony_ci}
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_cistatic SANE_Status
1493141cc406Sopenharmony_ciartec_software_rgb_calibrate (SANE_Handle handle, SANE_Byte * buf, int lines)
1494141cc406Sopenharmony_ci{
1495141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1496141cc406Sopenharmony_ci  int line, i, loop, offset;
1497141cc406Sopenharmony_ci
1498141cc406Sopenharmony_ci  DBG (7, "artec_software_rgb_calibrate()\n");
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci  for (line = 0; line < lines; line++)
1501141cc406Sopenharmony_ci    {
1502141cc406Sopenharmony_ci      i = 0;
1503141cc406Sopenharmony_ci      offset = 0;
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci      if (s->x_resolution == 200)
1506141cc406Sopenharmony_ci	{
1507141cc406Sopenharmony_ci	  /* skip ever 3rd byte, -= causes us to go down in count */
1508141cc406Sopenharmony_ci	  if ((s->tl_x % 3) == 0)
1509141cc406Sopenharmony_ci	    offset -= 1;
1510141cc406Sopenharmony_ci	}
1511141cc406Sopenharmony_ci      else
1512141cc406Sopenharmony_ci	{
1513141cc406Sopenharmony_ci	  /* round down to the previous pixel */
1514141cc406Sopenharmony_ci	  offset += ((s->tl_x / (300 / s->x_resolution)) *
1515141cc406Sopenharmony_ci		     (300 / s->x_resolution));
1516141cc406Sopenharmony_ci	}
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_ci      for (loop = 0; loop < s->params.pixels_per_line; loop++)
1519141cc406Sopenharmony_ci	{
1520141cc406Sopenharmony_ci	  if ((DBG_LEVEL == 100) &&
1521141cc406Sopenharmony_ci	      (loop < 100))
1522141cc406Sopenharmony_ci	    {
1523141cc406Sopenharmony_ci	      DBG (100, "  %2d-%4d R (%4d,%4d): %d * %5.2f = %d\n",
1524141cc406Sopenharmony_ci		       line, loop, i, offset, buf[i],
1525141cc406Sopenharmony_ci		       s->soft_calibrate_data[ARTEC_SOFT_CALIB_RED][offset],
1526141cc406Sopenharmony_ci		       (int) (buf[i] *
1527141cc406Sopenharmony_ci		     s->soft_calibrate_data[ARTEC_SOFT_CALIB_RED][offset]));
1528141cc406Sopenharmony_ci	    }
1529141cc406Sopenharmony_ci	  buf[i] = buf[i] *
1530141cc406Sopenharmony_ci	    s->soft_calibrate_data[ARTEC_SOFT_CALIB_RED][offset];
1531141cc406Sopenharmony_ci	  i++;
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci	  if ((DBG_LEVEL == 100) &&
1534141cc406Sopenharmony_ci	      (loop < 100))
1535141cc406Sopenharmony_ci	    {
1536141cc406Sopenharmony_ci	      DBG (100, "          G (%4d,%4d): %d * %5.2f = %d\n",
1537141cc406Sopenharmony_ci		       i, offset, buf[i],
1538141cc406Sopenharmony_ci		     s->soft_calibrate_data[ARTEC_SOFT_CALIB_GREEN][offset],
1539141cc406Sopenharmony_ci		       (int) (buf[i] *
1540141cc406Sopenharmony_ci		   s->soft_calibrate_data[ARTEC_SOFT_CALIB_GREEN][offset]));
1541141cc406Sopenharmony_ci	    }
1542141cc406Sopenharmony_ci	  buf[i] = buf[i] *
1543141cc406Sopenharmony_ci	    s->soft_calibrate_data[ARTEC_SOFT_CALIB_GREEN][offset];
1544141cc406Sopenharmony_ci	  i++;
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci	  if ((DBG_LEVEL == 100) &&
1547141cc406Sopenharmony_ci	      (loop < 100))
1548141cc406Sopenharmony_ci	    {
1549141cc406Sopenharmony_ci	      DBG (100, "          B (%4d,%4d): %d * %5.2f = %d\n",
1550141cc406Sopenharmony_ci		       i, offset, buf[i],
1551141cc406Sopenharmony_ci		       s->soft_calibrate_data[ARTEC_SOFT_CALIB_BLUE][offset],
1552141cc406Sopenharmony_ci		       (int) (buf[i] *
1553141cc406Sopenharmony_ci		    s->soft_calibrate_data[ARTEC_SOFT_CALIB_BLUE][offset]));
1554141cc406Sopenharmony_ci	    }
1555141cc406Sopenharmony_ci	  buf[i] = buf[i] *
1556141cc406Sopenharmony_ci	    s->soft_calibrate_data[ARTEC_SOFT_CALIB_BLUE][offset];
1557141cc406Sopenharmony_ci	  i++;
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci	  if (s->x_resolution == 200)
1560141cc406Sopenharmony_ci	    {
1561141cc406Sopenharmony_ci	      offset += 1;
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci	      /* skip every 3rd byte */
1564141cc406Sopenharmony_ci	      if (((offset + 1) % 3) == 0)
1565141cc406Sopenharmony_ci		offset += 1;
1566141cc406Sopenharmony_ci	    }
1567141cc406Sopenharmony_ci	  else
1568141cc406Sopenharmony_ci	    {
1569141cc406Sopenharmony_ci	      offset += (300 / s->x_resolution);
1570141cc406Sopenharmony_ci	    }
1571141cc406Sopenharmony_ci	}
1572141cc406Sopenharmony_ci    }
1573141cc406Sopenharmony_ci
1574141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1575141cc406Sopenharmony_ci}
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_cistatic SANE_Status
1578141cc406Sopenharmony_ciartec_calibrate_shading (SANE_Handle handle)
1579141cc406Sopenharmony_ci{
1580141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1581141cc406Sopenharmony_ci  SANE_Status status;		/* DB added */
1582141cc406Sopenharmony_ci  u_char buf[76800];		/* should be big enough */
1583141cc406Sopenharmony_ci  size_t len;
1584141cc406Sopenharmony_ci  SANE_Word save_x_resolution;
1585141cc406Sopenharmony_ci  SANE_Word save_pixels_per_line;
1586141cc406Sopenharmony_ci  int i;
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci  DBG (7, "artec_calibrate_shading()\n");
1589141cc406Sopenharmony_ci
1590141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_CALIBRATE_RGB)
1591141cc406Sopenharmony_ci    {
1592141cc406Sopenharmony_ci      /* this method scans in 4 lines each of Red, Green, and Blue */
1593141cc406Sopenharmony_ci      /* after reading line of shading data, generate data for software */
1594141cc406Sopenharmony_ci      /* calibration so we have it if user requests */
1595141cc406Sopenharmony_ci      len = 4 * 2592;		/* 4 lines of data, 2592 pixels wide */
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci      if ( DBG_LEVEL == 100 )
1598141cc406Sopenharmony_ci	DBG (100, "RED Software Calibration data\n");
1599141cc406Sopenharmony_ci
1600141cc406Sopenharmony_ci      read_data (s->fd, ARTEC_DATA_RED_SHADING, buf, &len);
1601141cc406Sopenharmony_ci      for (i = 0; i < 2592; i++)
1602141cc406Sopenharmony_ci	{
1603141cc406Sopenharmony_ci	  s->soft_calibrate_data[ARTEC_SOFT_CALIB_RED][i] =
1604141cc406Sopenharmony_ci	    255.0 / ((buf[i] + buf[i + 2592] + buf[i + 5184] + buf[i + 7776]) / 4);
1605141cc406Sopenharmony_ci	  if (DBG_LEVEL == 100)
1606141cc406Sopenharmony_ci	    {
1607141cc406Sopenharmony_ci	      DBG (100,
1608141cc406Sopenharmony_ci	       "   %4d: 255.0 / (( %3d + %3d + %3d + %3d ) / 4 ) = %5.2f\n",
1609141cc406Sopenharmony_ci		     i, buf[i], buf[i + 2592], buf[i + 5184], buf[i + 7776],
1610141cc406Sopenharmony_ci		       s->soft_calibrate_data[ARTEC_SOFT_CALIB_RED][i]);
1611141cc406Sopenharmony_ci	    }
1612141cc406Sopenharmony_ci	}
1613141cc406Sopenharmony_ci
1614141cc406Sopenharmony_ci      if (DBG_LEVEL == 100)
1615141cc406Sopenharmony_ci	{
1616141cc406Sopenharmony_ci	  DBG (100, "GREEN Software Calibration data\n");
1617141cc406Sopenharmony_ci	}
1618141cc406Sopenharmony_ci
1619141cc406Sopenharmony_ci      read_data (s->fd, ARTEC_DATA_GREEN_SHADING, buf, &len);
1620141cc406Sopenharmony_ci      for (i = 0; i < 2592; i++)
1621141cc406Sopenharmony_ci	{
1622141cc406Sopenharmony_ci	  s->soft_calibrate_data[ARTEC_SOFT_CALIB_GREEN][i] =
1623141cc406Sopenharmony_ci	    255.0 / ((buf[i] + buf[i + 2592] + buf[i + 5184] + buf[i + 7776]) / 4);
1624141cc406Sopenharmony_ci	  if (DBG_LEVEL == 100)
1625141cc406Sopenharmony_ci	    {
1626141cc406Sopenharmony_ci	      DBG (100,
1627141cc406Sopenharmony_ci	       "   %4d: 255.0 / (( %3d + %3d + %3d + %3d ) / 4 ) = %5.2f\n",
1628141cc406Sopenharmony_ci		     i, buf[i], buf[i + 2592], buf[i + 5184], buf[i + 7776],
1629141cc406Sopenharmony_ci		       s->soft_calibrate_data[ARTEC_SOFT_CALIB_GREEN][i]);
1630141cc406Sopenharmony_ci	    }
1631141cc406Sopenharmony_ci	}
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci      if (DBG_LEVEL == 100)
1634141cc406Sopenharmony_ci	{
1635141cc406Sopenharmony_ci	  DBG (100, "BLUE Software Calibration data\n");
1636141cc406Sopenharmony_ci	}
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci      read_data (s->fd, ARTEC_DATA_BLUE_SHADING, buf, &len);
1639141cc406Sopenharmony_ci      for (i = 0; i < 2592; i++)
1640141cc406Sopenharmony_ci	{
1641141cc406Sopenharmony_ci	  s->soft_calibrate_data[ARTEC_SOFT_CALIB_BLUE][i] =
1642141cc406Sopenharmony_ci	    255.0 / ((buf[i] + buf[i + 2592] + buf[i + 5184] + buf[i + 7776]) / 4);
1643141cc406Sopenharmony_ci	  if (DBG_LEVEL == 100)
1644141cc406Sopenharmony_ci	    {
1645141cc406Sopenharmony_ci	      DBG (100,
1646141cc406Sopenharmony_ci	       "   %4d: 255.0 / (( %3d + %3d + %3d + %3d ) / 4 ) = %5.2f\n",
1647141cc406Sopenharmony_ci		     i, buf[i], buf[i + 2592], buf[i + 5184], buf[i + 7776],
1648141cc406Sopenharmony_ci		       s->soft_calibrate_data[ARTEC_SOFT_CALIB_BLUE][i]);
1649141cc406Sopenharmony_ci	    }
1650141cc406Sopenharmony_ci	}
1651141cc406Sopenharmony_ci    }
1652141cc406Sopenharmony_ci  else if (s->hw->flags & ARTEC_FLAG_CALIBRATE_DARK_WHITE)
1653141cc406Sopenharmony_ci    {
1654141cc406Sopenharmony_ci      /* this method scans black, then white data */
1655141cc406Sopenharmony_ci      len = 3 * 5100;		/* 1 line of data, 5100 pixels wide, RGB data */
1656141cc406Sopenharmony_ci      read_data (s->fd, ARTEC_DATA_DARK_SHADING, buf, &len);
1657141cc406Sopenharmony_ci      save_x_resolution = s->x_resolution;
1658141cc406Sopenharmony_ci      s->x_resolution = 600;
1659141cc406Sopenharmony_ci      save_pixels_per_line = s->params.pixels_per_line;
1660141cc406Sopenharmony_ci      s->params.pixels_per_line = ARTEC_MAX_X (s->hw);
1661141cc406Sopenharmony_ci      s->params.pixels_per_line = 600 * 8.5;	/* ?this? or ?above line? */
1662141cc406Sopenharmony_ci      /* DB added wait_ready */
1663141cc406Sopenharmony_ci      status = wait_ready (s->fd);
1664141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1665141cc406Sopenharmony_ci	{
1666141cc406Sopenharmony_ci	  DBG (1, "wait for scanner ready failed: %s\n", sane_strstatus (status));
1667141cc406Sopenharmony_ci	  return status;
1668141cc406Sopenharmony_ci	}
1669141cc406Sopenharmony_ci      /* next line should use ARTEC_DATA_WHITE_SHADING_TRANS if using ADF */
1670141cc406Sopenharmony_ci      read_data (s->fd, ARTEC_DATA_WHITE_SHADING_OPT, buf, &len);
1671141cc406Sopenharmony_ci      s->x_resolution = save_x_resolution;
1672141cc406Sopenharmony_ci      s->params.pixels_per_line = save_pixels_per_line;
1673141cc406Sopenharmony_ci    }
1674141cc406Sopenharmony_ci
1675141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1676141cc406Sopenharmony_ci}
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_cistatic SANE_Status
1680141cc406Sopenharmony_ciend_scan (SANE_Handle handle)
1681141cc406Sopenharmony_ci{
1682141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
1683141cc406Sopenharmony_ci  /* DB
1684141cc406Sopenharmony_ci     uint8_t write_6[6] =
1685141cc406Sopenharmony_ci     {0x1B, 0, 0, 0, 0, 0};
1686141cc406Sopenharmony_ci   */
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci  DBG (7, "end_scan()\n");
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
1691141cc406Sopenharmony_ci
1692141cc406Sopenharmony_ci/*  if (s->this_pass == 3) */
1693141cc406Sopenharmony_ci  s->this_pass = 0;
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci  if ((s->hw->flags & ARTEC_FLAG_RGB_LINE_OFFSET) &&
1696141cc406Sopenharmony_ci      (tmp_line_buf != NULL))
1697141cc406Sopenharmony_ci    {
1698141cc406Sopenharmony_ci      artec_buffer_line_offset_free ();
1699141cc406Sopenharmony_ci    }
1700141cc406Sopenharmony_ci
1701141cc406Sopenharmony_ci  /* DB
1702141cc406Sopenharmony_ci     return (sanei_scsi_cmd (s->fd, write_6, 6, 0, 0));
1703141cc406Sopenharmony_ci   */
1704141cc406Sopenharmony_ci  return abort_scan (s);
1705141cc406Sopenharmony_ci}
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci
1708141cc406Sopenharmony_cistatic SANE_Status
1709141cc406Sopenharmony_ciartec_get_cap_data (ARTEC_Device * dev, int fd)
1710141cc406Sopenharmony_ci{
1711141cc406Sopenharmony_ci  int cap_model, loop;
1712141cc406Sopenharmony_ci  u_char cap_buf[256];		/* buffer for cap data */
1713141cc406Sopenharmony_ci
1714141cc406Sopenharmony_ci  DBG (7, "artec_get_cap_data()\n");
1715141cc406Sopenharmony_ci
1716141cc406Sopenharmony_ci  /* DB always use the hard-coded capability info first
1717141cc406Sopenharmony_ci   * if we get cap data from the scanner, we override */
1718141cc406Sopenharmony_ci  cap_model = -1;
1719141cc406Sopenharmony_ci  for (loop = 0; loop < NELEMS (cap_data); loop++)
1720141cc406Sopenharmony_ci    {
1721141cc406Sopenharmony_ci      if (strcmp (cap_data[loop].model, dev->sane.model) == 0)
1722141cc406Sopenharmony_ci	{
1723141cc406Sopenharmony_ci	  cap_model = loop;
1724141cc406Sopenharmony_ci	}
1725141cc406Sopenharmony_ci    }
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci  if (cap_model == -1)
1728141cc406Sopenharmony_ci    {
1729141cc406Sopenharmony_ci      DBG (1, "unable to identify Artec model '%s', check artec.c\n",
1730141cc406Sopenharmony_ci	   dev->sane.model);
1731141cc406Sopenharmony_ci      return (SANE_STATUS_UNSUPPORTED);
1732141cc406Sopenharmony_ci    }
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci  dev->x_range.min = 0;
1735141cc406Sopenharmony_ci  dev->x_range.max = SANE_FIX (cap_data[cap_model].width) * MM_PER_INCH;
1736141cc406Sopenharmony_ci  dev->x_range.quant = 1;
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci  dev->width = cap_data[cap_model].width;
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci  dev->y_range.min = 0;
1741141cc406Sopenharmony_ci  dev->y_range.max = SANE_FIX (cap_data[cap_model].height) * MM_PER_INCH;
1742141cc406Sopenharmony_ci  dev->y_range.quant = 1;
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  dev->height = cap_data[cap_model].height;
1745141cc406Sopenharmony_ci
1746141cc406Sopenharmony_ci  artec_str_list_to_word_list (&dev->horz_resolution_list,
1747141cc406Sopenharmony_ci                               cap_data[cap_model].horz_resolution_str);
1748141cc406Sopenharmony_ci
1749141cc406Sopenharmony_ci  artec_str_list_to_word_list (&dev->vert_resolution_list,
1750141cc406Sopenharmony_ci                               cap_data[cap_model].vert_resolution_str);
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci  dev->contrast_range.min = 0;
1753141cc406Sopenharmony_ci  dev->contrast_range.max = 255;
1754141cc406Sopenharmony_ci  dev->contrast_range.quant = 1;
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci  dev->brightness_range.min = 0;
1757141cc406Sopenharmony_ci  dev->brightness_range.max = 255;
1758141cc406Sopenharmony_ci  dev->brightness_range.quant = 1;
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci  dev->threshold_range.min = 0;
1761141cc406Sopenharmony_ci  dev->threshold_range.max = 255;
1762141cc406Sopenharmony_ci  dev->threshold_range.quant = 1;
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_ci  dev->sane.type = cap_data[cap_model].type;
1765141cc406Sopenharmony_ci
1766141cc406Sopenharmony_ci  dev->max_read_size = cap_data[cap_model].max_read_size;
1767141cc406Sopenharmony_ci
1768141cc406Sopenharmony_ci  dev->flags = cap_data[cap_model].flags;
1769141cc406Sopenharmony_ci
1770141cc406Sopenharmony_ci  switch (cap_data[cap_model].adc_bits)
1771141cc406Sopenharmony_ci    {
1772141cc406Sopenharmony_ci    case 8:
1773141cc406Sopenharmony_ci      dev->gamma_length = 256;
1774141cc406Sopenharmony_ci      break;
1775141cc406Sopenharmony_ci
1776141cc406Sopenharmony_ci    case 10:
1777141cc406Sopenharmony_ci      dev->gamma_length = 1024;
1778141cc406Sopenharmony_ci      break;
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci    case 12:
1781141cc406Sopenharmony_ci      dev->gamma_length = 4096;
1782141cc406Sopenharmony_ci      break;
1783141cc406Sopenharmony_ci    }
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  dev->setwindow_cmd_size = cap_data[cap_model].setwindow_cmd_size;
1786141cc406Sopenharmony_ci
1787141cc406Sopenharmony_ci  if (dev->support_cap_data_retrieve)	/* DB */
1788141cc406Sopenharmony_ci    {
1789141cc406Sopenharmony_ci      /* DB added reading capability data from scanner */
1790141cc406Sopenharmony_ci      char info[80];		/* for printing debugging info */
1791141cc406Sopenharmony_ci      size_t len = sizeof (cap_buf);
1792141cc406Sopenharmony_ci
1793141cc406Sopenharmony_ci      /* read the capability data from the scanner */
1794141cc406Sopenharmony_ci      DBG (9, "reading capability data from scanner...\n");
1795141cc406Sopenharmony_ci
1796141cc406Sopenharmony_ci      wait_ready (fd);
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci      read_data (fd, ARTEC_DATA_CAPABILITY_DATA, cap_buf, &len);
1799141cc406Sopenharmony_ci
1800141cc406Sopenharmony_ci      DBG (50, "scanner capability data : \n");
1801141cc406Sopenharmony_ci      strncpy (info, (const char *) &cap_buf[0], 8);
1802141cc406Sopenharmony_ci      info[8] = '\0';
1803141cc406Sopenharmony_ci      DBG (50, "  Vendor                    : %s\n", info);
1804141cc406Sopenharmony_ci      strncpy (info, (const char *) &cap_buf[8], 16);
1805141cc406Sopenharmony_ci      info[16] = '\0';
1806141cc406Sopenharmony_ci      DBG (50, "  Device Name               : %s\n", info);
1807141cc406Sopenharmony_ci      strncpy (info, (const char *) &cap_buf[24], 4);
1808141cc406Sopenharmony_ci      info[4] = '\0';
1809141cc406Sopenharmony_ci      DBG (50, "  Version Number            : %s\n", info);
1810141cc406Sopenharmony_ci      sprintf (info, "%d ", cap_buf[29]);
1811141cc406Sopenharmony_ci      DBG (50, "  CCD Type                  : %s\n", info);
1812141cc406Sopenharmony_ci      sprintf (info, "%d ", cap_buf[30]);
1813141cc406Sopenharmony_ci      DBG (50, "  AD Converter Type         : %s\n", info);
1814141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[31] << 8) | cap_buf[32]);
1815141cc406Sopenharmony_ci      DBG (50, "  Buffer size               : %s\n", info);
1816141cc406Sopenharmony_ci      sprintf (info, "%d ", cap_buf[33]);
1817141cc406Sopenharmony_ci      DBG (50, "  Channels of RGB Gamma     : %s\n", info);
1818141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[34] << 8) | cap_buf[35]);
1819141cc406Sopenharmony_ci      DBG (50, "  Opt. res. of R channel    : %s\n", info);
1820141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[36] << 8) | cap_buf[37]);
1821141cc406Sopenharmony_ci      DBG (50, "  Opt. res. of G channel    : %s\n", info);
1822141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[38] << 8) | cap_buf[39]);
1823141cc406Sopenharmony_ci      DBG (50, "  Opt. res. of B channel    : %s\n", info);
1824141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[40] << 8) | cap_buf[41]);
1825141cc406Sopenharmony_ci      DBG (50, "  Min. Hor. Resolution      : %s\n", info);
1826141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[42] << 8) | cap_buf[43]);
1827141cc406Sopenharmony_ci      DBG (50, "  Max. Vert. Resolution     : %s\n", info);
1828141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[44] << 8) | cap_buf[45]);
1829141cc406Sopenharmony_ci      DBG (50, "  Min. Vert. Resolution     : %s\n", info);
1830141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[46] == 0x80 ? "yes" : "no");
1831141cc406Sopenharmony_ci      DBG (50, "  Chunky Data Format        : %s\n", info);
1832141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[47] == 0x80 ? "yes" : "no");
1833141cc406Sopenharmony_ci      DBG (50, "  RGB Data Format           : %s\n", info);
1834141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[48] == 0x80 ? "yes" : "no");
1835141cc406Sopenharmony_ci      DBG (50, "  BGR Data Format           : %s\n", info);
1836141cc406Sopenharmony_ci      sprintf (info, "%d ", cap_buf[49]);
1837141cc406Sopenharmony_ci      DBG (50, "  Line Offset               : %s\n", info);
1838141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[50] == 0x80 ? "yes" : "no");
1839141cc406Sopenharmony_ci      DBG (50, "  Channel Valid Sequence    : %s\n", info);
1840141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[51] == 0x80 ? "yes" : "no");
1841141cc406Sopenharmony_ci      DBG (50, "  True Gray                 : %s\n", info);
1842141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[52] == 0x80 ? "yes" : "no");
1843141cc406Sopenharmony_ci      DBG (50, "  Force Host Not Do Shading : %s\n", info);
1844141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[53] == 0x00 ? "AT006" : "AT010");
1845141cc406Sopenharmony_ci      DBG (50, "  ASIC                      : %s\n", info);
1846141cc406Sopenharmony_ci      sprintf (info, "%s ", cap_buf[54] == 0x82 ? "SCSI2" :
1847141cc406Sopenharmony_ci	       cap_buf[54] == 0x81 ? "SCSI1" : "Parallel");
1848141cc406Sopenharmony_ci      DBG (50, "  Interface                 : %s\n", info);
1849141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[55] << 8) | cap_buf[56]);
1850141cc406Sopenharmony_ci      DBG (50, "  Phys. Area Width          : %s\n", info);
1851141cc406Sopenharmony_ci      sprintf (info, "%d ", (cap_buf[57] << 8) | cap_buf[58]);
1852141cc406Sopenharmony_ci      DBG (50, "  Phys. Area Length         : %s\n", info);
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci      /* fill in the information we've got from the scanner */
1855141cc406Sopenharmony_ci
1856141cc406Sopenharmony_ci      dev->width = ((float) ((cap_buf[55] << 8) | cap_buf[56])) / 1000;
1857141cc406Sopenharmony_ci      dev->height = ((float) ((cap_buf[57] << 8) | cap_buf[58])) / 1000;
1858141cc406Sopenharmony_ci
1859141cc406Sopenharmony_ci      /* DB ----- */
1860141cc406Sopenharmony_ci    }
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_ci  DBG (9, "Scanner capability info.\n");
1863141cc406Sopenharmony_ci  DBG (9, "  Vendor      : %s\n", dev->sane.vendor);
1864141cc406Sopenharmony_ci  DBG (9, "  Model       : %s\n", dev->sane.model);
1865141cc406Sopenharmony_ci  DBG (9, "  Type        : %s\n", dev->sane.type);
1866141cc406Sopenharmony_ci  DBG (5, "  Width       : %.2f inches\n", dev->width);
1867141cc406Sopenharmony_ci  DBG (9, "  Height      : %.2f inches\n", dev->height);
1868141cc406Sopenharmony_ci  DBG (9, "  X Range(mm) : %d-%d\n",
1869141cc406Sopenharmony_ci       dev->x_range.min,
1870141cc406Sopenharmony_ci       (int) (SANE_UNFIX (dev->x_range.max)));
1871141cc406Sopenharmony_ci  DBG (9, "  Y Range(mm) : %d-%d\n",
1872141cc406Sopenharmony_ci       dev->y_range.min,
1873141cc406Sopenharmony_ci       (int) (SANE_UNFIX (dev->y_range.max)));
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci  DBG (9, "  Horz. DPI   : %d-%d\n", ARTEC_MIN_X (dev), ARTEC_MAX_X (dev));
1876141cc406Sopenharmony_ci  DBG (9, "  Vert. DPI   : %d-%d\n", ARTEC_MIN_Y (dev), ARTEC_MAX_Y (dev));
1877141cc406Sopenharmony_ci  DBG (9, "  Contrast    : %d-%d\n",
1878141cc406Sopenharmony_ci       dev->contrast_range.min, dev->contrast_range.max);
1879141cc406Sopenharmony_ci  DBG (9, "  REQ Sh. Cal.: %d\n",
1880141cc406Sopenharmony_ci       dev->flags & ARTEC_FLAG_CALIBRATE ? 1 : 0);
1881141cc406Sopenharmony_ci  DBG (9, "  REQ Ln. Offs: %d\n",
1882141cc406Sopenharmony_ci       dev->flags & ARTEC_FLAG_RGB_LINE_OFFSET ? 1 : 0);
1883141cc406Sopenharmony_ci  DBG (9, "  REQ Ch. Shft: %d\n",
1884141cc406Sopenharmony_ci       dev->flags & ARTEC_FLAG_RGB_CHAR_SHIFT ? 1 : 0);
1885141cc406Sopenharmony_ci  DBG (9, "  SetWind Size: %d\n",
1886141cc406Sopenharmony_ci       dev->setwindow_cmd_size);
1887141cc406Sopenharmony_ci  DBG (9, "  Calib Method: %s\n",
1888141cc406Sopenharmony_ci       dev->flags & ARTEC_FLAG_CALIBRATE_RGB ? "RGB" :
1889141cc406Sopenharmony_ci       dev->flags & ARTEC_FLAG_CALIBRATE_DARK_WHITE ? "white/black" : "N/A");
1890141cc406Sopenharmony_ci
1891141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1892141cc406Sopenharmony_ci}
1893141cc406Sopenharmony_ci
1894141cc406Sopenharmony_cistatic SANE_Status
1895141cc406Sopenharmony_cidump_inquiry (unsigned char *result)
1896141cc406Sopenharmony_ci{
1897141cc406Sopenharmony_ci  int i;
1898141cc406Sopenharmony_ci  int j;
1899141cc406Sopenharmony_ci  char prt_buf[129] = "";
1900141cc406Sopenharmony_ci  char tmp_buf[129];
1901141cc406Sopenharmony_ci
1902141cc406Sopenharmony_ci  DBG (4, "dump_inquiry()\n");
1903141cc406Sopenharmony_ci
1904141cc406Sopenharmony_ci  DBG (4, " === SANE/Artec backend v%d.%d.%d ===\n",
1905141cc406Sopenharmony_ci	   ARTEC_MAJOR, ARTEC_MINOR, ARTEC_SUB);
1906141cc406Sopenharmony_ci  DBG (4, " ===== Scanner Inquiry Block =====\n");
1907141cc406Sopenharmony_ci  for (i = 0; i < 96; i += 16)
1908141cc406Sopenharmony_ci    {
1909141cc406Sopenharmony_ci      sprintf (prt_buf, "0x%02x: ", i);
1910141cc406Sopenharmony_ci      for (j = 0; j < 16; j++)
1911141cc406Sopenharmony_ci	{
1912141cc406Sopenharmony_ci	  sprintf (tmp_buf, "%02x ", (int) result[i + j]);
1913141cc406Sopenharmony_ci	  strcat( prt_buf, tmp_buf );
1914141cc406Sopenharmony_ci	}
1915141cc406Sopenharmony_ci      strcat( prt_buf, "  ");
1916141cc406Sopenharmony_ci      for (j = 0; j < 16; j++)
1917141cc406Sopenharmony_ci	{
1918141cc406Sopenharmony_ci	  sprintf (tmp_buf, "%c",
1919141cc406Sopenharmony_ci		   isprint (result[i + j]) ? result[i + j] : '.');
1920141cc406Sopenharmony_ci	  strcat( prt_buf, tmp_buf );
1921141cc406Sopenharmony_ci	}
1922141cc406Sopenharmony_ci      strcat( prt_buf, "\n" );
1923141cc406Sopenharmony_ci      DBG(4, "%s", prt_buf );
1924141cc406Sopenharmony_ci    }
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1927141cc406Sopenharmony_ci}
1928141cc406Sopenharmony_ci
1929141cc406Sopenharmony_cistatic SANE_Status
1930141cc406Sopenharmony_ciattach (const char *devname, ARTEC_Device ** devp)
1931141cc406Sopenharmony_ci{
1932141cc406Sopenharmony_ci  char result[INQ_LEN];
1933141cc406Sopenharmony_ci  char product_revision[5];
1934141cc406Sopenharmony_ci  char temp_result[33];
1935141cc406Sopenharmony_ci  char *str, *t;
1936141cc406Sopenharmony_ci  int fd;
1937141cc406Sopenharmony_ci  SANE_Status status;
1938141cc406Sopenharmony_ci  ARTEC_Device *dev;
1939141cc406Sopenharmony_ci  size_t size;
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci  DBG (7, "attach()\n");
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
1944141cc406Sopenharmony_ci    {
1945141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devname) == 0)
1946141cc406Sopenharmony_ci	{
1947141cc406Sopenharmony_ci	  if (devp)
1948141cc406Sopenharmony_ci	    *devp = dev;
1949141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
1950141cc406Sopenharmony_ci	}
1951141cc406Sopenharmony_ci    }
1952141cc406Sopenharmony_ci
1953141cc406Sopenharmony_ci  DBG (6, "attach: opening %s\n", devname);
1954141cc406Sopenharmony_ci
1955141cc406Sopenharmony_ci  status = sanei_scsi_open (devname, &fd, sense_handler, NULL);
1956141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1957141cc406Sopenharmony_ci    {
1958141cc406Sopenharmony_ci      DBG (1, "attach: open failed (%s)\n", sane_strstatus (status));
1959141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
1960141cc406Sopenharmony_ci    }
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci  DBG (6, "attach: sending INQUIRY\n");
1963141cc406Sopenharmony_ci  size = sizeof (result);
1964141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size);
1965141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size < 16)
1966141cc406Sopenharmony_ci    {
1967141cc406Sopenharmony_ci      DBG (1, "attach: inquiry failed (%s)\n", sane_strstatus (status));
1968141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1969141cc406Sopenharmony_ci      return (status);
1970141cc406Sopenharmony_ci    }
1971141cc406Sopenharmony_ci
1972141cc406Sopenharmony_ci  /*
1973141cc406Sopenharmony_ci   * Check to see if this device is a scanner.
1974141cc406Sopenharmony_ci   */
1975141cc406Sopenharmony_ci  if (result[0] != 0x6)
1976141cc406Sopenharmony_ci    {
1977141cc406Sopenharmony_ci      DBG (1, "attach: device doesn't look like a scanner at all.\n");
1978141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1979141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
1980141cc406Sopenharmony_ci    }
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci  /*
1983141cc406Sopenharmony_ci   * The BlackWidow BW4800SP is actually a rebadged AT3, with the vendor
1984141cc406Sopenharmony_ci   * string set to 8 spaces and the product to "Flatbed Scanner ".  So,
1985141cc406Sopenharmony_ci   * if we have one of these, we'll make it look like an AT3.
1986141cc406Sopenharmony_ci   *
1987141cc406Sopenharmony_ci   * For now, to be on the safe side, we'll also check the version number
1988141cc406Sopenharmony_ci   * since BlackWidow seems to have left that intact as "1.90".
1989141cc406Sopenharmony_ci   *
1990141cc406Sopenharmony_ci   * Check that result[36] == 0x00 so we don't mistake a microtek scanner.
1991141cc406Sopenharmony_ci   */
1992141cc406Sopenharmony_ci  if ((result[36] == 0x00) &&
1993141cc406Sopenharmony_ci      (strncmp (result + 32, "1.90", 4) == 0) &&
1994141cc406Sopenharmony_ci      (strncmp (result + 8, "        ", 8) == 0) &&
1995141cc406Sopenharmony_ci      (strncmp (result + 16, "Flatbed Scanner ", 16) == 0))
1996141cc406Sopenharmony_ci    {
1997141cc406Sopenharmony_ci      DBG (6, "Found BlackWidow BW4800SP scanner, setting up like AT3\n");
1998141cc406Sopenharmony_ci
1999141cc406Sopenharmony_ci      /* setup the vendor and product to mimic the Artec/Ultima AT3 */
2000141cc406Sopenharmony_ci      memcpy (result + 8, "ULTIMA", 6);
2001141cc406Sopenharmony_ci      memcpy (result + 16, "AT3             ", 16);
2002141cc406Sopenharmony_ci    }
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_ci  /*
2005141cc406Sopenharmony_ci   * The Plustek 19200S is actually a rebadged AM12S, with the vendor string
2006141cc406Sopenharmony_ci   * set to 8 spaces.
2007141cc406Sopenharmony_ci   */
2008141cc406Sopenharmony_ci  if ((strncmp (result + 8, "        ", 8) == 0) &&
2009141cc406Sopenharmony_ci      (strncmp (result + 16, "SCAN19200       ", 16) == 0))
2010141cc406Sopenharmony_ci    {
2011141cc406Sopenharmony_ci      DBG (6, "Found Plustek 19200S scanner, setting up like AM12S\n");
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci      /* setup the vendor and product to mimic the Artec/Ultima AM12S */
2014141cc406Sopenharmony_ci      memcpy (result + 8, "ULTIMA", 6);
2015141cc406Sopenharmony_ci      memcpy (result + 16, "AM12S           ", 16);
2016141cc406Sopenharmony_ci    }
2017141cc406Sopenharmony_ci
2018141cc406Sopenharmony_ci  /*
2019141cc406Sopenharmony_ci   * Check to see if they have forced a vendor and/or model string and
2020141cc406Sopenharmony_ci   * if so, fudge the inquiry results with that info.  We do this right
2021141cc406Sopenharmony_ci   * before we check the inquiry results, otherwise we might not be forcing
2022141cc406Sopenharmony_ci   * anything.
2023141cc406Sopenharmony_ci   */
2024141cc406Sopenharmony_ci  if (artec_vendor[0] != 0x0)
2025141cc406Sopenharmony_ci    {
2026141cc406Sopenharmony_ci      /*
2027141cc406Sopenharmony_ci       * 1) copy the vendor string to our temp variable
2028141cc406Sopenharmony_ci       * 2) append 8 spaces to make sure we have at least 8 characters
2029141cc406Sopenharmony_ci       * 3) copy our fudged vendor string into the inquiry result.
2030141cc406Sopenharmony_ci       */
2031141cc406Sopenharmony_ci      strcpy (temp_result, artec_vendor);
2032141cc406Sopenharmony_ci      strcat (temp_result, "        ");
2033141cc406Sopenharmony_ci      strncpy (result + 8, temp_result, 8);
2034141cc406Sopenharmony_ci    }
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci  if (artec_model[0] != 0x0)
2037141cc406Sopenharmony_ci    {
2038141cc406Sopenharmony_ci      /*
2039141cc406Sopenharmony_ci       * 1) copy the model string to our temp variable
2040141cc406Sopenharmony_ci       * 2) append 16 spaces to make sure we have at least 16 characters
2041141cc406Sopenharmony_ci       * 3) copy our fudged model string into the inquiry result.
2042141cc406Sopenharmony_ci       */
2043141cc406Sopenharmony_ci      strcpy (temp_result, artec_model);
2044141cc406Sopenharmony_ci      strcat (temp_result, "                ");
2045141cc406Sopenharmony_ci      strncpy (result + 16, temp_result, 16);
2046141cc406Sopenharmony_ci    }
2047141cc406Sopenharmony_ci
2048141cc406Sopenharmony_ci  /* are we really dealing with a scanner by ULTIMA/ARTEC? */
2049141cc406Sopenharmony_ci  if ((strncmp (result + 8, "ULTIMA", 6) != 0) &&
2050141cc406Sopenharmony_ci      (strncmp (result + 8, "ARTEC", 5) != 0))
2051141cc406Sopenharmony_ci    {
2052141cc406Sopenharmony_ci      DBG (1, "attach: device doesn't look like a Artec/ULTIMA scanner\n");
2053141cc406Sopenharmony_ci
2054141cc406Sopenharmony_ci      strncpy (temp_result, result + 8, 8);
2055141cc406Sopenharmony_ci      temp_result[8] = 0x0;
2056141cc406Sopenharmony_ci      DBG (1, "attach: FOUND vendor = '%s'\n", temp_result);
2057141cc406Sopenharmony_ci      strncpy (temp_result, result + 16, 16);
2058141cc406Sopenharmony_ci      temp_result[16] = 0x0;
2059141cc406Sopenharmony_ci      DBG (1, "attach: FOUND model  = '%s'\n", temp_result);
2060141cc406Sopenharmony_ci
2061141cc406Sopenharmony_ci      sanei_scsi_close (fd);
2062141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
2063141cc406Sopenharmony_ci    }
2064141cc406Sopenharmony_ci
2065141cc406Sopenharmony_ci  /* turn this wait OFF for now since it appears to cause problems with */
2066141cc406Sopenharmony_ci  /* AT12 models */
2067141cc406Sopenharmony_ci  /* turned off by creating an "if" that can never be true */
2068141cc406Sopenharmony_ci  if ( 1 == 2 ) {
2069141cc406Sopenharmony_ci  DBG (6, "attach: wait for scanner to come ready\n");
2070141cc406Sopenharmony_ci  status = wait_ready (fd);
2071141cc406Sopenharmony_ci
2072141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2073141cc406Sopenharmony_ci    {
2074141cc406Sopenharmony_ci      DBG (1, "attach: test unit ready failed (%s)\n",
2075141cc406Sopenharmony_ci	   sane_strstatus (status));
2076141cc406Sopenharmony_ci      sanei_scsi_close (fd);
2077141cc406Sopenharmony_ci      return (status);
2078141cc406Sopenharmony_ci    }
2079141cc406Sopenharmony_ci  /* This is the end of the "if" that can never be true that in effect */
2080141cc406Sopenharmony_ci  /* comments out this wait_ready() call */
2081141cc406Sopenharmony_ci  }
2082141cc406Sopenharmony_ci  /* end of "if( 1 == 2 )" */
2083141cc406Sopenharmony_ci
2084141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
2085141cc406Sopenharmony_ci  if (!dev)
2086141cc406Sopenharmony_ci    return (SANE_STATUS_NO_MEM);
2087141cc406Sopenharmony_ci
2088141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ci  if (DBG_LEVEL >= 4)
2091141cc406Sopenharmony_ci    dump_inquiry ((unsigned char *) result);
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci  dev->sane.name = strdup (devname);
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci  /* get the model info */
2096141cc406Sopenharmony_ci  str = malloc (17);
2097141cc406Sopenharmony_ci  memcpy (str, result + 16, 16);
2098141cc406Sopenharmony_ci  str[16] = ' ';
2099141cc406Sopenharmony_ci  t = str + 16;
2100141cc406Sopenharmony_ci  while ((*t == ' ') && (t > str))
2101141cc406Sopenharmony_ci    {
2102141cc406Sopenharmony_ci      *t = '\0';
2103141cc406Sopenharmony_ci      t--;
2104141cc406Sopenharmony_ci    }
2105141cc406Sopenharmony_ci  dev->sane.model = str;
2106141cc406Sopenharmony_ci
2107141cc406Sopenharmony_ci  /* for some reason, the firmware revision is in the model info string on */
2108141cc406Sopenharmony_ci  /* the A6000C PLUS scanners instead of in it's proper place */
2109141cc406Sopenharmony_ci  if (strstr (str, "A6000C PLUS") == str)
2110141cc406Sopenharmony_ci    {
2111141cc406Sopenharmony_ci      str[11] = '\0';
2112141cc406Sopenharmony_ci      strncpy (product_revision, str + 12, 4);
2113141cc406Sopenharmony_ci    }
2114141cc406Sopenharmony_ci  else if (strstr (str, "AT3") == str)
2115141cc406Sopenharmony_ci    {
2116141cc406Sopenharmony_ci      str[3] = '\0';
2117141cc406Sopenharmony_ci      strncpy (product_revision, str + 8, 4);
2118141cc406Sopenharmony_ci    }
2119141cc406Sopenharmony_ci  else
2120141cc406Sopenharmony_ci    {
2121141cc406Sopenharmony_ci      /* get the product revision from it's normal place */
2122141cc406Sopenharmony_ci      strncpy (product_revision, result + 32, 4);
2123141cc406Sopenharmony_ci    }
2124141cc406Sopenharmony_ci  product_revision[4] = ' ';
2125141cc406Sopenharmony_ci  t = strchr (product_revision, ' ');
2126141cc406Sopenharmony_ci  if (t)
2127141cc406Sopenharmony_ci    *t = '\0';
2128141cc406Sopenharmony_ci  else
2129141cc406Sopenharmony_ci    t = "unknown revision";
2130141cc406Sopenharmony_ci
2131141cc406Sopenharmony_ci  /* get the vendor info */
2132141cc406Sopenharmony_ci  str = malloc (9);
2133141cc406Sopenharmony_ci  memcpy (str, result + 8, 8);
2134141cc406Sopenharmony_ci  str[8] = ' ';
2135141cc406Sopenharmony_ci  t = strchr (str, ' ');
2136141cc406Sopenharmony_ci  *t = '\0';
2137141cc406Sopenharmony_ci  dev->sane.vendor = str;
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_ci  DBG (5, "scanner vendor: '%s', model: '%s', revision: '%s'\n",
2140141cc406Sopenharmony_ci       dev->sane.vendor, dev->sane.model, product_revision);
2141141cc406Sopenharmony_ci
2142141cc406Sopenharmony_ci  /* Artec docs say if bytes 36-43 = "ULTIMA  ", then supports read cap. data */
2143141cc406Sopenharmony_ci  if (strncmp (result + 36, "ULTIMA  ", 8) == 0)
2144141cc406Sopenharmony_ci    {
2145141cc406Sopenharmony_ci      DBG (5, "scanner supports read capability data function\n");
2146141cc406Sopenharmony_ci      dev->support_cap_data_retrieve = SANE_TRUE;
2147141cc406Sopenharmony_ci    }
2148141cc406Sopenharmony_ci  else
2149141cc406Sopenharmony_ci    {
2150141cc406Sopenharmony_ci      DBG (5, "scanner does NOT support read capability data function\n");
2151141cc406Sopenharmony_ci      dev->support_cap_data_retrieve = SANE_FALSE;
2152141cc406Sopenharmony_ci    }
2153141cc406Sopenharmony_ci
2154141cc406Sopenharmony_ci  DBG (6, "attach: getting scanner capability data\n");
2155141cc406Sopenharmony_ci  status = artec_get_cap_data (dev, fd);
2156141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2157141cc406Sopenharmony_ci    {
2158141cc406Sopenharmony_ci      DBG (1, "attach: artec_get_cap_data failed (%s)\n",
2159141cc406Sopenharmony_ci	   sane_strstatus (status));
2160141cc406Sopenharmony_ci      sanei_scsi_close (fd);
2161141cc406Sopenharmony_ci      return (status);
2162141cc406Sopenharmony_ci    }
2163141cc406Sopenharmony_ci
2164141cc406Sopenharmony_ci  sanei_scsi_close (fd);
2165141cc406Sopenharmony_ci
2166141cc406Sopenharmony_ci  ++num_devices;
2167141cc406Sopenharmony_ci  dev->next = first_dev;
2168141cc406Sopenharmony_ci  first_dev = dev;
2169141cc406Sopenharmony_ci
2170141cc406Sopenharmony_ci  if (devp)
2171141cc406Sopenharmony_ci    *devp = dev;
2172141cc406Sopenharmony_ci
2173141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2174141cc406Sopenharmony_ci}
2175141cc406Sopenharmony_ci
2176141cc406Sopenharmony_cistatic SANE_Status
2177141cc406Sopenharmony_ciinit_options (ARTEC_Scanner * s)
2178141cc406Sopenharmony_ci{
2179141cc406Sopenharmony_ci  int i;
2180141cc406Sopenharmony_ci
2181141cc406Sopenharmony_ci  DBG (7, "init_options()\n");
2182141cc406Sopenharmony_ci
2183141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
2184141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
2187141cc406Sopenharmony_ci    {
2188141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
2189141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2190141cc406Sopenharmony_ci    }
2191141cc406Sopenharmony_ci
2192141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2193141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2194141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2195141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2196141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_ci  /* "Mode" group: */
2199141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = "Scan Mode";
2200141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
2201141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2202141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
2203141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci  /* scan mode */
2206141cc406Sopenharmony_ci  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2207141cc406Sopenharmony_ci  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2208141cc406Sopenharmony_ci  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2209141cc406Sopenharmony_ci  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
2210141cc406Sopenharmony_ci  s->opt[OPT_MODE].size = max_string_size (mode_list);
2211141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2212141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint.string_list = mode_list;
2213141cc406Sopenharmony_ci  s->val[OPT_MODE].s = strdup (mode_list[3]);
2214141cc406Sopenharmony_ci
2215141cc406Sopenharmony_ci  /* horizontal resolution */
2216141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2217141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
2218141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
2219141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT;
2220141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI;
2221141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2222141cc406Sopenharmony_ci  s->opt[OPT_X_RESOLUTION].constraint.word_list = s->hw->horz_resolution_list;
2223141cc406Sopenharmony_ci  s->val[OPT_X_RESOLUTION].w = 100;
2224141cc406Sopenharmony_ci
2225141cc406Sopenharmony_ci  /* vertical resolution */
2226141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
2227141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
2228141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
2229141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT;
2230141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
2231141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2232141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].constraint.word_list = s->hw->vert_resolution_list;
2233141cc406Sopenharmony_ci  s->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
2234141cc406Sopenharmony_ci  s->val[OPT_Y_RESOLUTION].w = 100;
2235141cc406Sopenharmony_ci
2236141cc406Sopenharmony_ci  /* bind resolution */
2237141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
2238141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
2239141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
2240141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
2241141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
2242141cc406Sopenharmony_ci
2243141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_SEPARATE_RES))
2244141cc406Sopenharmony_ci    s->opt[OPT_RESOLUTION_BIND].cap |= SANE_CAP_INACTIVE;
2245141cc406Sopenharmony_ci
2246141cc406Sopenharmony_ci  /* Preview Mode */
2247141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
2248141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
2249141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
2250141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
2251141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE;
2252141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].size = sizeof (SANE_Word);
2253141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w = SANE_FALSE;
2254141cc406Sopenharmony_ci
2255141cc406Sopenharmony_ci  /* Grayscale Preview Mode */
2256141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
2257141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
2258141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
2259141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
2260141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].unit = SANE_UNIT_NONE;
2261141cc406Sopenharmony_ci  s->opt[OPT_GRAY_PREVIEW].size = sizeof (SANE_Word);
2262141cc406Sopenharmony_ci  s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci  /* negative */
2265141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].name = SANE_NAME_NEGATIVE;
2266141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE;
2267141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].desc = "Negative Image";
2268141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].type = SANE_TYPE_BOOL;
2269141cc406Sopenharmony_ci  s->val[OPT_NEGATIVE].w = SANE_FALSE;
2270141cc406Sopenharmony_ci
2271141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_MBPP_NEGATIVE))
2272141cc406Sopenharmony_ci    {
2273141cc406Sopenharmony_ci      s->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE;
2274141cc406Sopenharmony_ci    }
2275141cc406Sopenharmony_ci
2276141cc406Sopenharmony_ci  /* "Geometry" group: */
2277141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
2278141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
2279141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2280141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
2281141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2282141cc406Sopenharmony_ci
2283141cc406Sopenharmony_ci  /* top-left x */
2284141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2285141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2286141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2287141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
2288141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
2289141cc406Sopenharmony_ci
2290141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
2291141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
2292141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = s->hw->x_range.min;
2293141cc406Sopenharmony_ci
2294141cc406Sopenharmony_ci  /* top-left y */
2295141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2296141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2297141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2298141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
2299141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
2300141cc406Sopenharmony_ci
2301141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2302141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
2303141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = s->hw->y_range.min;
2304141cc406Sopenharmony_ci
2305141cc406Sopenharmony_ci  /* bottom-right x */
2306141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2307141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2308141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2309141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
2310141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
2311141cc406Sopenharmony_ci
2312141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
2313141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
2314141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = s->hw->x_range.max;
2315141cc406Sopenharmony_ci
2316141cc406Sopenharmony_ci  /* bottom-right y */
2317141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2318141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2319141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2320141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
2321141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
2322141cc406Sopenharmony_ci
2323141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2324141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
2325141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = s->hw->y_range.max;
2326141cc406Sopenharmony_ci
2327141cc406Sopenharmony_ci  /* Enhancement group: */
2328141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
2329141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
2330141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2331141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
2332141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2333141cc406Sopenharmony_ci
2334141cc406Sopenharmony_ci  /* filter mode */
2335141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].name = "filter-type";
2336141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].title = "Filter Type";
2337141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].desc = "Filter Type for mono scans";
2338141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].type = SANE_TYPE_STRING;
2339141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].size = max_string_size (filter_type_list);
2340141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2341141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].constraint.string_list = filter_type_list;
2342141cc406Sopenharmony_ci  s->val[OPT_FILTER_TYPE].s = strdup (filter_type_list[0]);
2343141cc406Sopenharmony_ci  s->opt[OPT_FILTER_TYPE].cap |= SANE_CAP_INACTIVE;
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci  /* contrast */
2346141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
2347141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
2348141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
2349141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
2350141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
2351141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2352141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint.range = &s->hw->brightness_range;
2353141cc406Sopenharmony_ci  s->val[OPT_CONTRAST].w = 0x80;
2354141cc406Sopenharmony_ci
2355141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_OPT_CONTRAST))
2356141cc406Sopenharmony_ci    {
2357141cc406Sopenharmony_ci      s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2358141cc406Sopenharmony_ci    }
2359141cc406Sopenharmony_ci
2360141cc406Sopenharmony_ci  /* brightness */
2361141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2362141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2363141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2364141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
2365141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
2366141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2367141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->contrast_range;
2368141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS].w = 0x80;
2369141cc406Sopenharmony_ci
2370141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_OPT_BRIGHTNESS))
2371141cc406Sopenharmony_ci    {
2372141cc406Sopenharmony_ci      s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2373141cc406Sopenharmony_ci    }
2374141cc406Sopenharmony_ci
2375141cc406Sopenharmony_ci  /* threshold */
2376141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
2377141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
2378141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
2379141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
2380141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
2381141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
2382141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint.range = &s->hw->threshold_range;
2383141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD].w = 0x80;
2384141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2385141cc406Sopenharmony_ci
2386141cc406Sopenharmony_ci  /* halftone pattern */
2387141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
2388141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
2389141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
2390141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
2391141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].size = max_string_size (halftone_pattern_list);
2392141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2393141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_pattern_list;
2394141cc406Sopenharmony_ci  s->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_pattern_list[1]);
2395141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
2396141cc406Sopenharmony_ci
2397141cc406Sopenharmony_ci  /* pixel averaging */
2398141cc406Sopenharmony_ci  s->opt[OPT_PIXEL_AVG].name = "pixel-avg";
2399141cc406Sopenharmony_ci  s->opt[OPT_PIXEL_AVG].title = "Pixel Averaging";
2400141cc406Sopenharmony_ci  s->opt[OPT_PIXEL_AVG].desc = "Enable HardWare Pixel Averaging function";
2401141cc406Sopenharmony_ci  s->opt[OPT_PIXEL_AVG].type = SANE_TYPE_BOOL;
2402141cc406Sopenharmony_ci  s->val[OPT_PIXEL_AVG].w = SANE_FALSE;
2403141cc406Sopenharmony_ci
2404141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_PIXEL_AVERAGING))
2405141cc406Sopenharmony_ci    {
2406141cc406Sopenharmony_ci      s->opt[OPT_PIXEL_AVG].cap |= SANE_CAP_INACTIVE;
2407141cc406Sopenharmony_ci    }
2408141cc406Sopenharmony_ci
2409141cc406Sopenharmony_ci  /* lineart line edge enhancement */
2410141cc406Sopenharmony_ci  s->opt[OPT_EDGE_ENH].name = "edge-enh";
2411141cc406Sopenharmony_ci  s->opt[OPT_EDGE_ENH].title = "Line Edge Enhancement";
2412141cc406Sopenharmony_ci  s->opt[OPT_EDGE_ENH].desc = "Enable HardWare Lineart Line Edge Enhancement";
2413141cc406Sopenharmony_ci  s->opt[OPT_EDGE_ENH].type = SANE_TYPE_BOOL;
2414141cc406Sopenharmony_ci  s->val[OPT_EDGE_ENH].w = SANE_FALSE;
2415141cc406Sopenharmony_ci  s->opt[OPT_EDGE_ENH].cap |= SANE_CAP_INACTIVE;
2416141cc406Sopenharmony_ci
2417141cc406Sopenharmony_ci  /* custom-gamma table */
2418141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
2419141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
2420141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
2421141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
2422141cc406Sopenharmony_ci  s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
2423141cc406Sopenharmony_ci
2424141cc406Sopenharmony_ci  /* grayscale gamma vector */
2425141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
2426141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
2427141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
2428141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
2429141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
2430141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
2431141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR].wa = &(s->gamma_table[0][0]);
2432141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
2433141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].size = s->gamma_length * sizeof (SANE_Word);
2434141cc406Sopenharmony_ci
2435141cc406Sopenharmony_ci  /* red gamma vector */
2436141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
2437141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
2438141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
2439141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
2440141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
2441141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
2442141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_R].wa = &(s->gamma_table[1][0]);
2443141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(s->gamma_range);
2444141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].size = s->gamma_length * sizeof (SANE_Word);
2445141cc406Sopenharmony_ci
2446141cc406Sopenharmony_ci  /* green gamma vector */
2447141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
2448141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
2449141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
2450141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
2451141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
2452141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
2453141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_G].wa = &(s->gamma_table[2][0]);
2454141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(s->gamma_range);
2455141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].size = s->gamma_length * sizeof (SANE_Word);
2456141cc406Sopenharmony_ci
2457141cc406Sopenharmony_ci  /* blue gamma vector */
2458141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
2459141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
2460141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
2461141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
2462141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
2463141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
2464141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_B].wa = &(s->gamma_table[3][0]);
2465141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range);
2466141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof (SANE_Word);
2467141cc406Sopenharmony_ci
2468141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_GAMMA_SINGLE)
2469141cc406Sopenharmony_ci    {
2470141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
2471141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
2472141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
2473141cc406Sopenharmony_ci    }
2474141cc406Sopenharmony_ci
2475141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_GAMMA))
2476141cc406Sopenharmony_ci    {
2477141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
2478141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
2479141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
2480141cc406Sopenharmony_ci      s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
2481141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
2482141cc406Sopenharmony_ci    }
2483141cc406Sopenharmony_ci
2484141cc406Sopenharmony_ci  /* transparency */
2485141cc406Sopenharmony_ci  s->opt[OPT_TRANSPARENCY].name = "transparency";
2486141cc406Sopenharmony_ci  s->opt[OPT_TRANSPARENCY].title = "Transparency";
2487141cc406Sopenharmony_ci  s->opt[OPT_TRANSPARENCY].desc = "Use transparency adaptor";
2488141cc406Sopenharmony_ci  s->opt[OPT_TRANSPARENCY].type = SANE_TYPE_BOOL;
2489141cc406Sopenharmony_ci  s->val[OPT_TRANSPARENCY].w = SANE_FALSE;
2490141cc406Sopenharmony_ci
2491141cc406Sopenharmony_ci  /* ADF */
2492141cc406Sopenharmony_ci  s->opt[OPT_ADF].name = "adf";
2493141cc406Sopenharmony_ci  s->opt[OPT_ADF].title = "ADF";
2494141cc406Sopenharmony_ci  s->opt[OPT_ADF].desc = "Use ADF";
2495141cc406Sopenharmony_ci  s->opt[OPT_ADF].type = SANE_TYPE_BOOL;
2496141cc406Sopenharmony_ci  s->val[OPT_ADF].w = SANE_FALSE;
2497141cc406Sopenharmony_ci
2498141cc406Sopenharmony_ci  /* Calibration group: */
2499141cc406Sopenharmony_ci  s->opt[OPT_CALIBRATION_GROUP].title = "Calibration";
2500141cc406Sopenharmony_ci  s->opt[OPT_CALIBRATION_GROUP].desc = "";
2501141cc406Sopenharmony_ci  s->opt[OPT_CALIBRATION_GROUP].type = SANE_TYPE_GROUP;
2502141cc406Sopenharmony_ci  s->opt[OPT_CALIBRATION_GROUP].cap = SANE_CAP_ADVANCED;
2503141cc406Sopenharmony_ci  s->opt[OPT_CALIBRATION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2504141cc406Sopenharmony_ci
2505141cc406Sopenharmony_ci  /* Calibrate Every Scan? */
2506141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].name = SANE_NAME_QUALITY_CAL;
2507141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].title = "Hardware Calibrate Every Scan";
2508141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].desc = "Perform hardware calibration on every scan";
2509141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].type = SANE_TYPE_BOOL;
2510141cc406Sopenharmony_ci  s->val[OPT_QUALITY_CAL].w = SANE_FALSE;
2511141cc406Sopenharmony_ci
2512141cc406Sopenharmony_ci  if (!(s->hw->flags & ARTEC_FLAG_CALIBRATE))
2513141cc406Sopenharmony_ci    {
2514141cc406Sopenharmony_ci      s->opt[OPT_QUALITY_CAL].cap |= SANE_CAP_INACTIVE;
2515141cc406Sopenharmony_ci    }
2516141cc406Sopenharmony_ci
2517141cc406Sopenharmony_ci  /* Perform Software Quality Calibration */
2518141cc406Sopenharmony_ci  s->opt[OPT_SOFTWARE_CAL].name = "software-cal";
2519141cc406Sopenharmony_ci  s->opt[OPT_SOFTWARE_CAL].title = "Software Color Calibration";
2520141cc406Sopenharmony_ci  s->opt[OPT_SOFTWARE_CAL].desc = "Perform software quality calibration in "
2521141cc406Sopenharmony_ci    "addition to hardware calibration";
2522141cc406Sopenharmony_ci  s->opt[OPT_SOFTWARE_CAL].type = SANE_TYPE_BOOL;
2523141cc406Sopenharmony_ci  s->val[OPT_SOFTWARE_CAL].w = SANE_FALSE;
2524141cc406Sopenharmony_ci
2525141cc406Sopenharmony_ci  /* check for RGB calibration now because we have only implemented software */
2526141cc406Sopenharmony_ci  /* calibration in conjunction with hardware RGB calibration */
2527141cc406Sopenharmony_ci  if ((!(s->hw->flags & ARTEC_FLAG_CALIBRATE)) ||
2528141cc406Sopenharmony_ci      (!(s->hw->flags & ARTEC_FLAG_CALIBRATE_RGB)))
2529141cc406Sopenharmony_ci    {
2530141cc406Sopenharmony_ci      s->opt[OPT_SOFTWARE_CAL].cap |= SANE_CAP_INACTIVE;
2531141cc406Sopenharmony_ci    }
2532141cc406Sopenharmony_ci
2533141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2534141cc406Sopenharmony_ci}
2535141cc406Sopenharmony_ci
2536141cc406Sopenharmony_cistatic SANE_Status
2537141cc406Sopenharmony_cido_cancel (ARTEC_Scanner * s)
2538141cc406Sopenharmony_ci{
2539141cc406Sopenharmony_ci  DBG (7, "do_cancel()\n");
2540141cc406Sopenharmony_ci
2541141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
2542141cc406Sopenharmony_ci
2543141cc406Sopenharmony_ci  /* DAL: Terminate a three pass scan properly */
2544141cc406Sopenharmony_ci/*  if (s->this_pass == 3) */
2545141cc406Sopenharmony_ci  s->this_pass = 0;
2546141cc406Sopenharmony_ci
2547141cc406Sopenharmony_ci  if ((s->hw->flags & ARTEC_FLAG_RGB_LINE_OFFSET) &&
2548141cc406Sopenharmony_ci      (tmp_line_buf != NULL))
2549141cc406Sopenharmony_ci    {
2550141cc406Sopenharmony_ci      artec_buffer_line_offset_free ();
2551141cc406Sopenharmony_ci    }
2552141cc406Sopenharmony_ci
2553141cc406Sopenharmony_ci  if (s->fd >= 0)
2554141cc406Sopenharmony_ci    {
2555141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
2556141cc406Sopenharmony_ci      s->fd = -1;
2557141cc406Sopenharmony_ci    }
2558141cc406Sopenharmony_ci
2559141cc406Sopenharmony_ci  return (SANE_STATUS_CANCELLED);
2560141cc406Sopenharmony_ci}
2561141cc406Sopenharmony_ci
2562141cc406Sopenharmony_ci
2563141cc406Sopenharmony_cistatic SANE_Status
2564141cc406Sopenharmony_ciattach_one (const char *dev)
2565141cc406Sopenharmony_ci{
2566141cc406Sopenharmony_ci  DBG (7, "attach_one()\n");
2567141cc406Sopenharmony_ci
2568141cc406Sopenharmony_ci  attach (dev, 0);
2569141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2570141cc406Sopenharmony_ci}
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci
2573141cc406Sopenharmony_ciSANE_Status
2574141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
2575141cc406Sopenharmony_ci{
2576141cc406Sopenharmony_ci  char dev_name[PATH_MAX], *cp;
2577141cc406Sopenharmony_ci  size_t len;
2578141cc406Sopenharmony_ci  FILE *fp;
2579141cc406Sopenharmony_ci
2580141cc406Sopenharmony_ci  DBG_INIT ();
2581141cc406Sopenharmony_ci
2582141cc406Sopenharmony_ci  DBG (1, "Artec/Ultima backend version %d.%d.%d, last mod: %s\n",
2583141cc406Sopenharmony_ci       ARTEC_MAJOR, ARTEC_MINOR, ARTEC_SUB, ARTEC_LAST_MOD);
2584141cc406Sopenharmony_ci  DBG (1, "http://www4.infi.net/~cpinkham/sane-artec-doc.html\n");
2585141cc406Sopenharmony_ci
2586141cc406Sopenharmony_ci  DBG (7, "sane_init()\n" );
2587141cc406Sopenharmony_ci
2588141cc406Sopenharmony_ci  devlist = 0;
2589141cc406Sopenharmony_ci  /* make sure these 2 are empty */
2590141cc406Sopenharmony_ci  strcpy (artec_vendor, "");
2591141cc406Sopenharmony_ci  strcpy (artec_model, "");
2592141cc406Sopenharmony_ci
2593141cc406Sopenharmony_ci  if (version_code)
2594141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
2595141cc406Sopenharmony_ci
2596141cc406Sopenharmony_ci  if (authorize)
2597141cc406Sopenharmony_ci    DBG (7, "sane_init(), authorize %s null\n", (authorize) ? "!=" : "==");
2598141cc406Sopenharmony_ci
2599141cc406Sopenharmony_ci  fp = sanei_config_open (ARTEC_CONFIG_FILE);
2600141cc406Sopenharmony_ci  if (!fp)
2601141cc406Sopenharmony_ci    {
2602141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
2603141cc406Sopenharmony_ci      attach ("/dev/scanner", 0);
2604141cc406Sopenharmony_ci      return (SANE_STATUS_GOOD);
2605141cc406Sopenharmony_ci    }
2606141cc406Sopenharmony_ci
2607141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
2608141cc406Sopenharmony_ci    {
2609141cc406Sopenharmony_ci      cp = artec_skip_whitespace (dev_name);
2610141cc406Sopenharmony_ci
2611141cc406Sopenharmony_ci      /* ignore line comments and blank lines */
2612141cc406Sopenharmony_ci      if ((!*cp) || (*cp == '#'))
2613141cc406Sopenharmony_ci	continue;
2614141cc406Sopenharmony_ci
2615141cc406Sopenharmony_ci      len = strlen (cp);
2616141cc406Sopenharmony_ci
2617141cc406Sopenharmony_ci      /* ignore empty lines */
2618141cc406Sopenharmony_ci      if (!len)
2619141cc406Sopenharmony_ci	continue;
2620141cc406Sopenharmony_ci
2621141cc406Sopenharmony_ci      DBG (50, "%s line: '%s', len = %lu\n", ARTEC_CONFIG_FILE, cp,
2622141cc406Sopenharmony_ci	   (u_long) len);
2623141cc406Sopenharmony_ci
2624141cc406Sopenharmony_ci      /* check to see if they forced a vendor string in artec.conf */
2625141cc406Sopenharmony_ci      if ((strncmp (cp, "vendor", 6) == 0) && isspace (cp[6]))
2626141cc406Sopenharmony_ci	{
2627141cc406Sopenharmony_ci	  cp += 7;
2628141cc406Sopenharmony_ci	  cp = artec_skip_whitespace (cp);
2629141cc406Sopenharmony_ci
2630141cc406Sopenharmony_ci	  strcpy (artec_vendor, cp);
2631141cc406Sopenharmony_ci	  DBG (5, "sane_init: Forced vendor string '%s' in %s.\n",
2632141cc406Sopenharmony_ci	       cp, ARTEC_CONFIG_FILE);
2633141cc406Sopenharmony_ci	}
2634141cc406Sopenharmony_ci      /* OK, maybe they forced the model string in artec.conf */
2635141cc406Sopenharmony_ci      else if ((strncmp (cp, "model", 5) == 0) && isspace (cp[5]))
2636141cc406Sopenharmony_ci	{
2637141cc406Sopenharmony_ci	  cp += 6;
2638141cc406Sopenharmony_ci	  cp = artec_skip_whitespace (cp);
2639141cc406Sopenharmony_ci
2640141cc406Sopenharmony_ci	  strcpy (artec_model, cp);
2641141cc406Sopenharmony_ci	  DBG (5, "sane_init: Forced model string '%s' in %s.\n",
2642141cc406Sopenharmony_ci	       cp, ARTEC_CONFIG_FILE);
2643141cc406Sopenharmony_ci	}
2644141cc406Sopenharmony_ci      /* well, nothing else to do but attempt the attach */
2645141cc406Sopenharmony_ci      else
2646141cc406Sopenharmony_ci	{
2647141cc406Sopenharmony_ci	  sanei_config_attach_matching_devices (dev_name, attach_one);
2648141cc406Sopenharmony_ci	  strcpy (artec_vendor, "");
2649141cc406Sopenharmony_ci	  strcpy (artec_model, "");
2650141cc406Sopenharmony_ci	}
2651141cc406Sopenharmony_ci    }
2652141cc406Sopenharmony_ci  fclose (fp);
2653141cc406Sopenharmony_ci
2654141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2655141cc406Sopenharmony_ci}
2656141cc406Sopenharmony_ci
2657141cc406Sopenharmony_civoid
2658141cc406Sopenharmony_cisane_exit (void)
2659141cc406Sopenharmony_ci{
2660141cc406Sopenharmony_ci  ARTEC_Device *dev, *next;
2661141cc406Sopenharmony_ci
2662141cc406Sopenharmony_ci  DBG (7, "sane_exit()\n");
2663141cc406Sopenharmony_ci
2664141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
2665141cc406Sopenharmony_ci    {
2666141cc406Sopenharmony_ci      next = dev->next;
2667141cc406Sopenharmony_ci      free ((void *) dev->sane.name);
2668141cc406Sopenharmony_ci      free ((void *) dev->sane.model);
2669141cc406Sopenharmony_ci      free (dev);
2670141cc406Sopenharmony_ci    }
2671141cc406Sopenharmony_ci
2672141cc406Sopenharmony_ci  if (devlist)
2673141cc406Sopenharmony_ci    free (devlist);
2674141cc406Sopenharmony_ci}
2675141cc406Sopenharmony_ci
2676141cc406Sopenharmony_ciSANE_Status
2677141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
2678141cc406Sopenharmony_ci{
2679141cc406Sopenharmony_ci  ARTEC_Device *dev;
2680141cc406Sopenharmony_ci  int i;
2681141cc406Sopenharmony_ci
2682141cc406Sopenharmony_ci  DBG (7, "sane_get_devices( device_list, local_only = %d )\n", local_only );
2683141cc406Sopenharmony_ci
2684141cc406Sopenharmony_ci  if (devlist)
2685141cc406Sopenharmony_ci    free (devlist);
2686141cc406Sopenharmony_ci
2687141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
2688141cc406Sopenharmony_ci  if (!devlist)
2689141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2690141cc406Sopenharmony_ci
2691141cc406Sopenharmony_ci  i = 0;
2692141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
2693141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
2694141cc406Sopenharmony_ci  devlist[i++] = 0;
2695141cc406Sopenharmony_ci
2696141cc406Sopenharmony_ci  *device_list = devlist;
2697141cc406Sopenharmony_ci
2698141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2699141cc406Sopenharmony_ci}
2700141cc406Sopenharmony_ci
2701141cc406Sopenharmony_ciSANE_Status
2702141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
2703141cc406Sopenharmony_ci{
2704141cc406Sopenharmony_ci  SANE_Status status;
2705141cc406Sopenharmony_ci  ARTEC_Device *dev;
2706141cc406Sopenharmony_ci  ARTEC_Scanner *s;
2707141cc406Sopenharmony_ci  int i, j;
2708141cc406Sopenharmony_ci
2709141cc406Sopenharmony_ci  DBG (7, "sane_open()\n");
2710141cc406Sopenharmony_ci
2711141cc406Sopenharmony_ci  if (devicename[0])
2712141cc406Sopenharmony_ci    {
2713141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
2714141cc406Sopenharmony_ci	if (strcmp (dev->sane.name, devicename) == 0)
2715141cc406Sopenharmony_ci	  break;
2716141cc406Sopenharmony_ci
2717141cc406Sopenharmony_ci      if (!dev)
2718141cc406Sopenharmony_ci	{
2719141cc406Sopenharmony_ci	  status = attach (devicename, &dev);
2720141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2721141cc406Sopenharmony_ci	    return (status);
2722141cc406Sopenharmony_ci	}
2723141cc406Sopenharmony_ci    }
2724141cc406Sopenharmony_ci  else
2725141cc406Sopenharmony_ci    {
2726141cc406Sopenharmony_ci      /* empty devicname -> use first device */
2727141cc406Sopenharmony_ci      dev = first_dev;
2728141cc406Sopenharmony_ci    }
2729141cc406Sopenharmony_ci
2730141cc406Sopenharmony_ci  if (!dev)
2731141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2732141cc406Sopenharmony_ci
2733141cc406Sopenharmony_ci  s = malloc (sizeof (*s));
2734141cc406Sopenharmony_ci  if (!s)
2735141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2736141cc406Sopenharmony_ci  memset (s, 0, sizeof (*s));
2737141cc406Sopenharmony_ci  s->fd = -1;
2738141cc406Sopenharmony_ci  s->hw = dev;
2739141cc406Sopenharmony_ci  s->this_pass = 0;
2740141cc406Sopenharmony_ci
2741141cc406Sopenharmony_ci  s->gamma_length = s->hw->gamma_length;
2742141cc406Sopenharmony_ci  s->gamma_range.min = 0;
2743141cc406Sopenharmony_ci  s->gamma_range.max = s->gamma_length - 1;
2744141cc406Sopenharmony_ci  s->gamma_range.quant = 0;
2745141cc406Sopenharmony_ci
2746141cc406Sopenharmony_ci  /* not sure if I need this or not, it was in the umax backend though. :-) */
2747141cc406Sopenharmony_ci  for (j = 0; j < s->gamma_length; ++j)
2748141cc406Sopenharmony_ci    {
2749141cc406Sopenharmony_ci      s->gamma_table[0][j] = j * (s->gamma_length - 1) / s->gamma_length;
2750141cc406Sopenharmony_ci    }
2751141cc406Sopenharmony_ci
2752141cc406Sopenharmony_ci  for (i = 1; i < 4; i++)
2753141cc406Sopenharmony_ci    {
2754141cc406Sopenharmony_ci      for (j = 0; j < s->gamma_length; ++j)
2755141cc406Sopenharmony_ci	{
2756141cc406Sopenharmony_ci	  s->gamma_table[i][j] = j;
2757141cc406Sopenharmony_ci	}
2758141cc406Sopenharmony_ci    }
2759141cc406Sopenharmony_ci
2760141cc406Sopenharmony_ci  init_options (s);
2761141cc406Sopenharmony_ci
2762141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
2763141cc406Sopenharmony_ci  s->next = first_handle;
2764141cc406Sopenharmony_ci  first_handle = s;
2765141cc406Sopenharmony_ci
2766141cc406Sopenharmony_ci  *handle = s;
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  if (s->hw->flags & ARTEC_FLAG_CALIBRATE)
2769141cc406Sopenharmony_ci    {
2770141cc406Sopenharmony_ci      status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0);
2771141cc406Sopenharmony_ci
2772141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2773141cc406Sopenharmony_ci	{
2774141cc406Sopenharmony_ci	  DBG (1, "error opening scanner for initial calibration: %s\n",
2775141cc406Sopenharmony_ci	       sane_strstatus (status));
2776141cc406Sopenharmony_ci	  s->fd = -1;
2777141cc406Sopenharmony_ci	  return status;
2778141cc406Sopenharmony_ci	}
2779141cc406Sopenharmony_ci
2780141cc406Sopenharmony_ci      status = artec_calibrate_shading (s);
2781141cc406Sopenharmony_ci
2782141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2783141cc406Sopenharmony_ci	{
2784141cc406Sopenharmony_ci	  DBG (1, "initial shading calibration failed: %s\n",
2785141cc406Sopenharmony_ci	       sane_strstatus (status));
2786141cc406Sopenharmony_ci	  sanei_scsi_close (s->fd);
2787141cc406Sopenharmony_ci	  s->fd = -1;
2788141cc406Sopenharmony_ci	  return status;
2789141cc406Sopenharmony_ci	}
2790141cc406Sopenharmony_ci
2791141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
2792141cc406Sopenharmony_ci    }
2793141cc406Sopenharmony_ci
2794141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2795141cc406Sopenharmony_ci}
2796141cc406Sopenharmony_ci
2797141cc406Sopenharmony_civoid
2798141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2799141cc406Sopenharmony_ci{
2800141cc406Sopenharmony_ci  ARTEC_Scanner *prev, *s;
2801141cc406Sopenharmony_ci
2802141cc406Sopenharmony_ci  DBG (7, "sane_close()\n");
2803141cc406Sopenharmony_ci
2804141cc406Sopenharmony_ci  if ((DBG_LEVEL == 101) &&
2805141cc406Sopenharmony_ci      (debug_fd > -1))
2806141cc406Sopenharmony_ci    {
2807141cc406Sopenharmony_ci      close (debug_fd);
2808141cc406Sopenharmony_ci      DBG (101, "closed artec.data.raw output file\n");
2809141cc406Sopenharmony_ci    }
2810141cc406Sopenharmony_ci
2811141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
2812141cc406Sopenharmony_ci  prev = 0;
2813141cc406Sopenharmony_ci  for (s = first_handle; s; s = s->next)
2814141cc406Sopenharmony_ci    {
2815141cc406Sopenharmony_ci      if (s == handle)
2816141cc406Sopenharmony_ci	break;
2817141cc406Sopenharmony_ci      prev = s;
2818141cc406Sopenharmony_ci    }
2819141cc406Sopenharmony_ci  if (!s)
2820141cc406Sopenharmony_ci    {
2821141cc406Sopenharmony_ci      DBG (1, "close: invalid handle %p\n", handle);
2822141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
2823141cc406Sopenharmony_ci    }
2824141cc406Sopenharmony_ci
2825141cc406Sopenharmony_ci  if (s->scanning)
2826141cc406Sopenharmony_ci    do_cancel (handle);
2827141cc406Sopenharmony_ci
2828141cc406Sopenharmony_ci
2829141cc406Sopenharmony_ci  if (prev)
2830141cc406Sopenharmony_ci    prev->next = s->next;
2831141cc406Sopenharmony_ci  else
2832141cc406Sopenharmony_ci    first_handle = s->next;
2833141cc406Sopenharmony_ci
2834141cc406Sopenharmony_ci  free (handle);
2835141cc406Sopenharmony_ci}
2836141cc406Sopenharmony_ci
2837141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
2838141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
2839141cc406Sopenharmony_ci{
2840141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_ci  DBG (7, "sane_get_option_descriptor()\n");
2843141cc406Sopenharmony_ci
2844141cc406Sopenharmony_ci  if (((unsigned) option >= NUM_OPTIONS) ||
2845141cc406Sopenharmony_ci      (option < 0 ))
2846141cc406Sopenharmony_ci    return (0);
2847141cc406Sopenharmony_ci
2848141cc406Sopenharmony_ci  return (s->opt + option);
2849141cc406Sopenharmony_ci}
2850141cc406Sopenharmony_ci
2851141cc406Sopenharmony_ciSANE_Status
2852141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
2853141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
2854141cc406Sopenharmony_ci{
2855141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
2856141cc406Sopenharmony_ci  SANE_Status status;
2857141cc406Sopenharmony_ci  SANE_Word w, cap;
2858141cc406Sopenharmony_ci
2859141cc406Sopenharmony_ci  DBG (7, "sane_control_option()\n");
2860141cc406Sopenharmony_ci
2861141cc406Sopenharmony_ci  if (info)
2862141cc406Sopenharmony_ci    *info = 0;
2863141cc406Sopenharmony_ci
2864141cc406Sopenharmony_ci  if (s->scanning)
2865141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
2866141cc406Sopenharmony_ci
2867141cc406Sopenharmony_ci  if (s->this_pass)
2868141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
2869141cc406Sopenharmony_ci
2870141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
2871141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2872141cc406Sopenharmony_ci
2873141cc406Sopenharmony_ci  cap = s->opt[option].cap;
2874141cc406Sopenharmony_ci
2875141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
2876141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2877141cc406Sopenharmony_ci
2878141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
2879141cc406Sopenharmony_ci    {
2880141cc406Sopenharmony_ci      DBG (13, "sane_control_option %d, get value\n", option);
2881141cc406Sopenharmony_ci
2882141cc406Sopenharmony_ci      switch (option)
2883141cc406Sopenharmony_ci	{
2884141cc406Sopenharmony_ci	  /* word options: */
2885141cc406Sopenharmony_ci	case OPT_X_RESOLUTION:
2886141cc406Sopenharmony_ci	case OPT_Y_RESOLUTION:
2887141cc406Sopenharmony_ci	case OPT_PREVIEW:
2888141cc406Sopenharmony_ci	case OPT_GRAY_PREVIEW:
2889141cc406Sopenharmony_ci	case OPT_RESOLUTION_BIND:
2890141cc406Sopenharmony_ci	case OPT_NEGATIVE:
2891141cc406Sopenharmony_ci	case OPT_TRANSPARENCY:
2892141cc406Sopenharmony_ci	case OPT_ADF:
2893141cc406Sopenharmony_ci	case OPT_TL_X:
2894141cc406Sopenharmony_ci	case OPT_TL_Y:
2895141cc406Sopenharmony_ci	case OPT_BR_X:
2896141cc406Sopenharmony_ci	case OPT_BR_Y:
2897141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
2898141cc406Sopenharmony_ci	case OPT_QUALITY_CAL:
2899141cc406Sopenharmony_ci	case OPT_SOFTWARE_CAL:
2900141cc406Sopenharmony_ci	case OPT_CONTRAST:
2901141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
2902141cc406Sopenharmony_ci	case OPT_THRESHOLD:
2903141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
2904141cc406Sopenharmony_ci	case OPT_PIXEL_AVG:
2905141cc406Sopenharmony_ci	case OPT_EDGE_ENH:
2906141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
2907141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2908141cc406Sopenharmony_ci
2909141cc406Sopenharmony_ci	  /* string options: */
2910141cc406Sopenharmony_ci	case OPT_MODE:
2911141cc406Sopenharmony_ci	case OPT_FILTER_TYPE:
2912141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
2913141cc406Sopenharmony_ci	  strcpy (val, s->val[option].s);
2914141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci	  /* word array options: */
2917141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
2918141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
2919141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
2920141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
2921141cc406Sopenharmony_ci	  memcpy (val, s->val[option].wa, s->opt[option].size);
2922141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2923141cc406Sopenharmony_ci	}
2924141cc406Sopenharmony_ci    }
2925141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
2926141cc406Sopenharmony_ci    {
2927141cc406Sopenharmony_ci      DBG (13, "sane_control_option %d, set value\n", option);
2928141cc406Sopenharmony_ci
2929141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
2930141cc406Sopenharmony_ci	return (SANE_STATUS_INVAL);
2931141cc406Sopenharmony_ci
2932141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, info);
2933141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2934141cc406Sopenharmony_ci	return (status);
2935141cc406Sopenharmony_ci
2936141cc406Sopenharmony_ci      switch (option)
2937141cc406Sopenharmony_ci	{
2938141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
2939141cc406Sopenharmony_ci	case OPT_X_RESOLUTION:
2940141cc406Sopenharmony_ci	case OPT_Y_RESOLUTION:
2941141cc406Sopenharmony_ci	case OPT_BR_X:
2942141cc406Sopenharmony_ci	case OPT_BR_Y:
2943141cc406Sopenharmony_ci	case OPT_TL_X:
2944141cc406Sopenharmony_ci	case OPT_TL_Y:
2945141cc406Sopenharmony_ci	  if (info && s->val[option].w != *(SANE_Word *) val)
2946141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
2947141cc406Sopenharmony_ci
2948141cc406Sopenharmony_ci	  /* fall through */
2949141cc406Sopenharmony_ci	case OPT_PREVIEW:
2950141cc406Sopenharmony_ci	case OPT_GRAY_PREVIEW:
2951141cc406Sopenharmony_ci	case OPT_QUALITY_CAL:
2952141cc406Sopenharmony_ci	case OPT_SOFTWARE_CAL:
2953141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
2954141cc406Sopenharmony_ci	case OPT_NEGATIVE:
2955141cc406Sopenharmony_ci	case OPT_TRANSPARENCY:
2956141cc406Sopenharmony_ci	case OPT_ADF:
2957141cc406Sopenharmony_ci	case OPT_CONTRAST:
2958141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
2959141cc406Sopenharmony_ci	case OPT_THRESHOLD:
2960141cc406Sopenharmony_ci	case OPT_PIXEL_AVG:
2961141cc406Sopenharmony_ci	case OPT_EDGE_ENH:
2962141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
2963141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2964141cc406Sopenharmony_ci
2965141cc406Sopenharmony_ci	case OPT_MODE:
2966141cc406Sopenharmony_ci	  {
2967141cc406Sopenharmony_ci	    if (s->val[option].s)
2968141cc406Sopenharmony_ci	      free (s->val[option].s);
2969141cc406Sopenharmony_ci
2970141cc406Sopenharmony_ci	    s->val[option].s = (SANE_Char *) strdup (val);
2971141cc406Sopenharmony_ci
2972141cc406Sopenharmony_ci	    if (info)
2973141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2974141cc406Sopenharmony_ci
2975141cc406Sopenharmony_ci	    s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
2976141cc406Sopenharmony_ci
2977141cc406Sopenharmony_ci	    /* options INvisible by default */
2978141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
2979141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
2980141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
2981141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
2982141cc406Sopenharmony_ci	    s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2983141cc406Sopenharmony_ci	    s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
2984141cc406Sopenharmony_ci	    s->opt[OPT_SOFTWARE_CAL].cap |= SANE_CAP_INACTIVE;
2985141cc406Sopenharmony_ci	    s->opt[OPT_EDGE_ENH].cap |= SANE_CAP_INACTIVE;
2986141cc406Sopenharmony_ci
2987141cc406Sopenharmony_ci	    /* options VISIBLE by default */
2988141cc406Sopenharmony_ci	    s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
2989141cc406Sopenharmony_ci	    s->opt[OPT_FILTER_TYPE].cap &= ~SANE_CAP_INACTIVE;
2990141cc406Sopenharmony_ci            s->opt[OPT_NEGATIVE].cap &= ~SANE_CAP_INACTIVE;
2991141cc406Sopenharmony_ci
2992141cc406Sopenharmony_ci	    if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0)
2993141cc406Sopenharmony_ci	      {
2994141cc406Sopenharmony_ci		/* Lineart mode */
2995141cc406Sopenharmony_ci		s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; /* OFF */
2996141cc406Sopenharmony_ci		s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
2997141cc406Sopenharmony_ci
2998141cc406Sopenharmony_ci		if (s->hw->flags & ARTEC_FLAG_ENHANCE_LINE_EDGE)
2999141cc406Sopenharmony_ci		  s->opt[OPT_EDGE_ENH].cap &= ~SANE_CAP_INACTIVE;
3000141cc406Sopenharmony_ci	      }
3001141cc406Sopenharmony_ci	    else if (strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
3002141cc406Sopenharmony_ci	      {
3003141cc406Sopenharmony_ci		/* Halftone mode */
3004141cc406Sopenharmony_ci		if (s->hw->flags & ARTEC_FLAG_HALFTONE_PATTERN)
3005141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
3006141cc406Sopenharmony_ci	      }
3007141cc406Sopenharmony_ci	    else if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
3008141cc406Sopenharmony_ci	      {
3009141cc406Sopenharmony_ci		/* Grayscale mode */
3010141cc406Sopenharmony_ci                if (!(s->hw->flags & ARTEC_FLAG_MBPP_NEGATIVE))
3011141cc406Sopenharmony_ci                  {
3012141cc406Sopenharmony_ci                    s->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE;
3013141cc406Sopenharmony_ci                  }
3014141cc406Sopenharmony_ci	      }
3015141cc406Sopenharmony_ci	    else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
3016141cc406Sopenharmony_ci	      {
3017141cc406Sopenharmony_ci		/* Color mode */
3018141cc406Sopenharmony_ci		s->opt[OPT_FILTER_TYPE].cap |= SANE_CAP_INACTIVE;
3019141cc406Sopenharmony_ci		s->opt[OPT_SOFTWARE_CAL].cap &= ~SANE_CAP_INACTIVE;
3020141cc406Sopenharmony_ci                if (!(s->hw->flags & ARTEC_FLAG_MBPP_NEGATIVE))
3021141cc406Sopenharmony_ci                  {
3022141cc406Sopenharmony_ci                    s->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE;
3023141cc406Sopenharmony_ci                  }
3024141cc406Sopenharmony_ci	      }
3025141cc406Sopenharmony_ci	  }
3026141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3027141cc406Sopenharmony_ci
3028141cc406Sopenharmony_ci	case OPT_FILTER_TYPE:
3029141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
3030141cc406Sopenharmony_ci	  if (s->val[option].s)
3031141cc406Sopenharmony_ci	    free (s->val[option].s);
3032141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
3033141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3034141cc406Sopenharmony_ci
3035141cc406Sopenharmony_ci	case OPT_RESOLUTION_BIND:
3036141cc406Sopenharmony_ci	  if (s->val[option].w != *(SANE_Word *) val)
3037141cc406Sopenharmony_ci	    {
3038141cc406Sopenharmony_ci	      s->val[option].w = *(SANE_Word *) val;
3039141cc406Sopenharmony_ci
3040141cc406Sopenharmony_ci	      if (info)
3041141cc406Sopenharmony_ci		{
3042141cc406Sopenharmony_ci		  *info |= SANE_INFO_RELOAD_OPTIONS;
3043141cc406Sopenharmony_ci		}
3044141cc406Sopenharmony_ci
3045141cc406Sopenharmony_ci	      if (s->val[option].w == SANE_FALSE)
3046141cc406Sopenharmony_ci		{		/* don't bind */
3047141cc406Sopenharmony_ci		  s->opt[OPT_Y_RESOLUTION].cap &= ~SANE_CAP_INACTIVE;
3048141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].title =
3049141cc406Sopenharmony_ci		    SANE_TITLE_SCAN_X_RESOLUTION;
3050141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].name =
3051141cc406Sopenharmony_ci		    SANE_NAME_SCAN_RESOLUTION;
3052141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].desc =
3053141cc406Sopenharmony_ci		    SANE_DESC_SCAN_X_RESOLUTION;
3054141cc406Sopenharmony_ci		}
3055141cc406Sopenharmony_ci	      else
3056141cc406Sopenharmony_ci		{		/* bind */
3057141cc406Sopenharmony_ci		  s->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
3058141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].title =
3059141cc406Sopenharmony_ci		    SANE_TITLE_SCAN_RESOLUTION;
3060141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].name =
3061141cc406Sopenharmony_ci		    SANE_NAME_SCAN_RESOLUTION;
3062141cc406Sopenharmony_ci		  s->opt[OPT_X_RESOLUTION].desc =
3063141cc406Sopenharmony_ci		    SANE_DESC_SCAN_RESOLUTION;
3064141cc406Sopenharmony_ci		}
3065141cc406Sopenharmony_ci	    }
3066141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3067141cc406Sopenharmony_ci
3068141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
3069141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
3070141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
3071141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
3072141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
3073141cc406Sopenharmony_ci	  memcpy (s->val[option].wa, val, s->opt[option].size);
3074141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3075141cc406Sopenharmony_ci
3076141cc406Sopenharmony_ci	  /* options with side effects: */
3077141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
3078141cc406Sopenharmony_ci	  w = *(SANE_Word *) val;
3079141cc406Sopenharmony_ci	  if (w == s->val[OPT_CUSTOM_GAMMA].w)
3080141cc406Sopenharmony_ci	    return (SANE_STATUS_GOOD);
3081141cc406Sopenharmony_ci
3082141cc406Sopenharmony_ci	  s->val[OPT_CUSTOM_GAMMA].w = w;
3083141cc406Sopenharmony_ci	  if (w)		/* use custom_gamma_table */
3084141cc406Sopenharmony_ci	    {
3085141cc406Sopenharmony_ci	      const char *mode = s->val[OPT_MODE].s;
3086141cc406Sopenharmony_ci
3087141cc406Sopenharmony_ci	      if ((strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) ||
3088141cc406Sopenharmony_ci		  (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) ||
3089141cc406Sopenharmony_ci		  (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0))
3090141cc406Sopenharmony_ci		{
3091141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
3092141cc406Sopenharmony_ci		}
3093141cc406Sopenharmony_ci	      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
3094141cc406Sopenharmony_ci		{
3095141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
3096141cc406Sopenharmony_ci
3097141cc406Sopenharmony_ci		  if (!(s->hw->flags & ARTEC_FLAG_GAMMA_SINGLE))
3098141cc406Sopenharmony_ci		    {
3099141cc406Sopenharmony_ci		      s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
3100141cc406Sopenharmony_ci		      s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
3101141cc406Sopenharmony_ci		      s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
3102141cc406Sopenharmony_ci		    }
3103141cc406Sopenharmony_ci		}
3104141cc406Sopenharmony_ci	    }
3105141cc406Sopenharmony_ci	  else
3106141cc406Sopenharmony_ci	    /* don't use custom_gamma_table */
3107141cc406Sopenharmony_ci	    {
3108141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
3109141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3110141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3111141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3112141cc406Sopenharmony_ci	    }
3113141cc406Sopenharmony_ci
3114141cc406Sopenharmony_ci	  if (info)
3115141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
3116141cc406Sopenharmony_ci
3117141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3118141cc406Sopenharmony_ci	}
3119141cc406Sopenharmony_ci    }
3120141cc406Sopenharmony_ci
3121141cc406Sopenharmony_ci  return (SANE_STATUS_INVAL);
3122141cc406Sopenharmony_ci}
3123141cc406Sopenharmony_ci
3124141cc406Sopenharmony_cistatic void
3125141cc406Sopenharmony_ciset_pass_parameters (SANE_Handle handle)
3126141cc406Sopenharmony_ci{
3127141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3128141cc406Sopenharmony_ci
3129141cc406Sopenharmony_ci  DBG (7, "set_pass_parameters()\n");
3130141cc406Sopenharmony_ci
3131141cc406Sopenharmony_ci  if (s->threepasscolor)
3132141cc406Sopenharmony_ci    {
3133141cc406Sopenharmony_ci      s->this_pass += 1;
3134141cc406Sopenharmony_ci      DBG (9, "set_pass_parameters:  three-pass, on %d\n", s->this_pass);
3135141cc406Sopenharmony_ci      switch (s->this_pass)
3136141cc406Sopenharmony_ci	{
3137141cc406Sopenharmony_ci	case 1:
3138141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_RED;
3139141cc406Sopenharmony_ci	  s->params.last_frame = SANE_FALSE;
3140141cc406Sopenharmony_ci	  break;
3141141cc406Sopenharmony_ci	case 2:
3142141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_GREEN;
3143141cc406Sopenharmony_ci	  s->params.last_frame = SANE_FALSE;
3144141cc406Sopenharmony_ci	  break;
3145141cc406Sopenharmony_ci	case 3:
3146141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_BLUE;
3147141cc406Sopenharmony_ci	  s->params.last_frame = SANE_TRUE;
3148141cc406Sopenharmony_ci	  break;
3149141cc406Sopenharmony_ci	default:
3150141cc406Sopenharmony_ci	  DBG (9, "set_pass_parameters:  What?!? pass %d = filter?\n",
3151141cc406Sopenharmony_ci	       s->this_pass);
3152141cc406Sopenharmony_ci	  break;
3153141cc406Sopenharmony_ci	}
3154141cc406Sopenharmony_ci    }
3155141cc406Sopenharmony_ci  else
3156141cc406Sopenharmony_ci    s->this_pass = 0;
3157141cc406Sopenharmony_ci}
3158141cc406Sopenharmony_ci
3159141cc406Sopenharmony_ciSANE_Status
3160141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
3161141cc406Sopenharmony_ci{
3162141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3163141cc406Sopenharmony_ci
3164141cc406Sopenharmony_ci  DBG (7, "sane_get_parameters()\n");
3165141cc406Sopenharmony_ci
3166141cc406Sopenharmony_ci  if (!s->scanning)
3167141cc406Sopenharmony_ci    {
3168141cc406Sopenharmony_ci      double width, height;
3169141cc406Sopenharmony_ci
3170141cc406Sopenharmony_ci      memset (&s->params, 0, sizeof (s->params));
3171141cc406Sopenharmony_ci
3172141cc406Sopenharmony_ci      s->x_resolution = s->val[OPT_X_RESOLUTION].w;
3173141cc406Sopenharmony_ci      s->y_resolution = s->val[OPT_Y_RESOLUTION].w;
3174141cc406Sopenharmony_ci
3175141cc406Sopenharmony_ci      if ((s->val[OPT_RESOLUTION_BIND].w == SANE_TRUE) ||
3176141cc406Sopenharmony_ci	  (s->val[OPT_PREVIEW].w == SANE_TRUE))
3177141cc406Sopenharmony_ci	{
3178141cc406Sopenharmony_ci	  s->y_resolution = s->x_resolution;
3179141cc406Sopenharmony_ci	}
3180141cc406Sopenharmony_ci
3181141cc406Sopenharmony_ci      s->tl_x = SANE_UNFIX (s->val[OPT_TL_X].w) / MM_PER_INCH
3182141cc406Sopenharmony_ci	* s->x_resolution;
3183141cc406Sopenharmony_ci      s->tl_y = SANE_UNFIX (s->val[OPT_TL_Y].w) / MM_PER_INCH
3184141cc406Sopenharmony_ci	* s->y_resolution;
3185141cc406Sopenharmony_ci      width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w);
3186141cc406Sopenharmony_ci      height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w);
3187141cc406Sopenharmony_ci
3188141cc406Sopenharmony_ci      if ((s->x_resolution > 0.0) &&
3189141cc406Sopenharmony_ci	  (s->y_resolution > 0.0) &&
3190141cc406Sopenharmony_ci	  (width > 0.0) &&
3191141cc406Sopenharmony_ci	  (height > 0.0))
3192141cc406Sopenharmony_ci	{
3193141cc406Sopenharmony_ci	  s->params.pixels_per_line = width * s->x_resolution / MM_PER_INCH + 1;
3194141cc406Sopenharmony_ci	  s->params.lines = height * s->y_resolution / MM_PER_INCH + 1;
3195141cc406Sopenharmony_ci	}
3196141cc406Sopenharmony_ci
3197141cc406Sopenharmony_ci      s->onepasscolor = SANE_FALSE;
3198141cc406Sopenharmony_ci      s->threepasscolor = SANE_FALSE;
3199141cc406Sopenharmony_ci      s->params.last_frame = SANE_TRUE;
3200141cc406Sopenharmony_ci
3201141cc406Sopenharmony_ci      if ((s->val[OPT_PREVIEW].w == SANE_TRUE) &&
3202141cc406Sopenharmony_ci	  (s->val[OPT_GRAY_PREVIEW].w == SANE_TRUE))
3203141cc406Sopenharmony_ci	{
3204141cc406Sopenharmony_ci	  s->mode = SANE_VALUE_SCAN_MODE_GRAY;
3205141cc406Sopenharmony_ci	}
3206141cc406Sopenharmony_ci      else
3207141cc406Sopenharmony_ci	{
3208141cc406Sopenharmony_ci	  s->mode = s->val[OPT_MODE].s;
3209141cc406Sopenharmony_ci	}
3210141cc406Sopenharmony_ci
3211141cc406Sopenharmony_ci      if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) ||
3212141cc406Sopenharmony_ci	  (strcmp (s->mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0))
3213141cc406Sopenharmony_ci	{
3214141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_GRAY;
3215141cc406Sopenharmony_ci	  s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
3216141cc406Sopenharmony_ci	  s->params.depth = 1;
3217141cc406Sopenharmony_ci	  s->line_offset = 0;
3218141cc406Sopenharmony_ci
3219141cc406Sopenharmony_ci	  /* round pixels_per_line up to the next full byte of pixels */
3220141cc406Sopenharmony_ci	  /* this way we don't have to do bit buffering, pixels_per_line is */
3221141cc406Sopenharmony_ci	  /* what is used in the set window command. */
3222141cc406Sopenharmony_ci	  /* SANE expects the last byte in a line to be padded if it's not */
3223141cc406Sopenharmony_ci	  /* full, so this should not affect scans in a negative way */
3224141cc406Sopenharmony_ci	  s->params.pixels_per_line = s->params.bytes_per_line * 8;
3225141cc406Sopenharmony_ci	}
3226141cc406Sopenharmony_ci      else if (strcmp (s->mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
3227141cc406Sopenharmony_ci	{
3228141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_GRAY;
3229141cc406Sopenharmony_ci	  s->params.bytes_per_line = s->params.pixels_per_line;
3230141cc406Sopenharmony_ci	  s->params.depth = 8;
3231141cc406Sopenharmony_ci	  s->line_offset = 0;
3232141cc406Sopenharmony_ci	}
3233141cc406Sopenharmony_ci      else
3234141cc406Sopenharmony_ci	{
3235141cc406Sopenharmony_ci	  s->params.bytes_per_line = s->params.pixels_per_line;
3236141cc406Sopenharmony_ci	  s->params.depth = 8;
3237141cc406Sopenharmony_ci
3238141cc406Sopenharmony_ci	  if (s->hw->flags & ARTEC_FLAG_ONE_PASS_SCANNER)
3239141cc406Sopenharmony_ci	    {
3240141cc406Sopenharmony_ci	      s->onepasscolor = SANE_TRUE;
3241141cc406Sopenharmony_ci	      s->params.format = SANE_FRAME_RGB;
3242141cc406Sopenharmony_ci	      s->params.bytes_per_line *= 3;
3243141cc406Sopenharmony_ci
3244141cc406Sopenharmony_ci	      /*
3245141cc406Sopenharmony_ci	       * line offsets from documentation.
3246141cc406Sopenharmony_ci	       * (I don't yet see a common formula I can easily use)
3247141cc406Sopenharmony_ci	       */
3248141cc406Sopenharmony_ci	      /* FIXME: figure out a cleaner way to do this... */
3249141cc406Sopenharmony_ci	      s->line_offset = 0;	/* default */
3250141cc406Sopenharmony_ci	      if ((!strcmp (s->hw->sane.model, "AT3")) ||
3251141cc406Sopenharmony_ci		  (!strcmp (s->hw->sane.model, "A6000C")) ||
3252141cc406Sopenharmony_ci		  (!strcmp (s->hw->sane.model, "A6000C PLUS")) ||
3253141cc406Sopenharmony_ci		  (!strcmp (s->hw->sane.model, "AT6")))
3254141cc406Sopenharmony_ci		{
3255141cc406Sopenharmony_ci		  /* formula #1 */
3256141cc406Sopenharmony_ci		  /* ranges from 1 at 50dpi to 16 at 600dpi */
3257141cc406Sopenharmony_ci		  s->line_offset = 8 * (s->y_resolution / 300.0);
3258141cc406Sopenharmony_ci		}
3259141cc406Sopenharmony_ci	      else if (!strcmp (s->hw->sane.model, "AT12"))
3260141cc406Sopenharmony_ci		{
3261141cc406Sopenharmony_ci		  /* formula #2 */
3262141cc406Sopenharmony_ci		  /* ranges from 0 at 25dpi to 16 at 1200dpi */
3263141cc406Sopenharmony_ci                  /***********************************************************/
3264141cc406Sopenharmony_ci		  /* this should be handled in hardware for now, so leave it */
3265141cc406Sopenharmony_ci		  /* sitting at zero for now.                                */
3266141cc406Sopenharmony_ci                  /***********************************************************/
3267141cc406Sopenharmony_ci		  /*
3268141cc406Sopenharmony_ci		     s->line_offset = 16 * ( s->y_resolution / 1200.0 );
3269141cc406Sopenharmony_ci		   */
3270141cc406Sopenharmony_ci		}
3271141cc406Sopenharmony_ci	      else if (!strcmp (s->hw->sane.model, "AM12S"))
3272141cc406Sopenharmony_ci		{
3273141cc406Sopenharmony_ci		  /* formula #3 */
3274141cc406Sopenharmony_ci		  /* ranges from 0 at 50dpi to 8 at 1200dpi */
3275141cc406Sopenharmony_ci		  s->line_offset = 8 * (s->y_resolution / 1200.0);
3276141cc406Sopenharmony_ci		}
3277141cc406Sopenharmony_ci	    }
3278141cc406Sopenharmony_ci	  else
3279141cc406Sopenharmony_ci	    {
3280141cc406Sopenharmony_ci	      s->params.last_frame = SANE_FALSE;
3281141cc406Sopenharmony_ci	      s->threepasscolor = SANE_TRUE;
3282141cc406Sopenharmony_ci	      s->line_offset = 0;
3283141cc406Sopenharmony_ci	    }
3284141cc406Sopenharmony_ci	}
3285141cc406Sopenharmony_ci    }
3286141cc406Sopenharmony_ci
3287141cc406Sopenharmony_ci  if (params)
3288141cc406Sopenharmony_ci    *params = s->params;
3289141cc406Sopenharmony_ci
3290141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3291141cc406Sopenharmony_ci}
3292141cc406Sopenharmony_ci
3293141cc406Sopenharmony_ci
3294141cc406Sopenharmony_ciSANE_Status
3295141cc406Sopenharmony_cisane_start (SANE_Handle handle)
3296141cc406Sopenharmony_ci{
3297141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3298141cc406Sopenharmony_ci  SANE_Status status;
3299141cc406Sopenharmony_ci
3300141cc406Sopenharmony_ci  DBG (7, "sane_start()\n");
3301141cc406Sopenharmony_ci
3302141cc406Sopenharmony_ci  if (debug_fd != -1)
3303141cc406Sopenharmony_ci    {
3304141cc406Sopenharmony_ci      close (debug_fd);
3305141cc406Sopenharmony_ci      debug_fd = -1;
3306141cc406Sopenharmony_ci    }
3307141cc406Sopenharmony_ci
3308141cc406Sopenharmony_ci  if (DBG_LEVEL == 101)
3309141cc406Sopenharmony_ci    {
3310141cc406Sopenharmony_ci      debug_fd = open ("artec.data.raw",
3311141cc406Sopenharmony_ci		       O_WRONLY | O_CREAT | O_TRUNC, 0666);
3312141cc406Sopenharmony_ci      if (debug_fd > -1)
3313141cc406Sopenharmony_ci	DBG (101, "opened artec.data.raw output file\n");
3314141cc406Sopenharmony_ci    }
3315141cc406Sopenharmony_ci
3316141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the */
3317141cc406Sopenharmony_ci  /* parameters will be overwritten below, but that's OK.  */
3318141cc406Sopenharmony_ci  status = sane_get_parameters (s, 0);
3319141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3320141cc406Sopenharmony_ci    return status;
3321141cc406Sopenharmony_ci
3322141cc406Sopenharmony_ci  /* DAL: For 3 pass colour set the current pass parameters */
3323141cc406Sopenharmony_ci  if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) && s->threepasscolor)
3324141cc406Sopenharmony_ci    set_pass_parameters (s);
3325141cc406Sopenharmony_ci
3326141cc406Sopenharmony_ci  /* DAL: For single pass scans and the first pass of a 3 pass scan */
3327141cc406Sopenharmony_ci  if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) != 0) ||
3328141cc406Sopenharmony_ci      (!s->threepasscolor) ||
3329141cc406Sopenharmony_ci      ((s->threepasscolor) &&
3330141cc406Sopenharmony_ci       (s->this_pass == 1)))
3331141cc406Sopenharmony_ci    {
3332141cc406Sopenharmony_ci
3333141cc406Sopenharmony_ci      if (s->hw->flags & ARTEC_FLAG_SENSE_HANDLER)
3334141cc406Sopenharmony_ci	{
3335141cc406Sopenharmony_ci	  status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler,
3336141cc406Sopenharmony_ci	    (void *)s);
3337141cc406Sopenharmony_ci	}
3338141cc406Sopenharmony_ci      else
3339141cc406Sopenharmony_ci	{
3340141cc406Sopenharmony_ci	  status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0);
3341141cc406Sopenharmony_ci	}
3342141cc406Sopenharmony_ci
3343141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3344141cc406Sopenharmony_ci	{
3345141cc406Sopenharmony_ci	  DBG (1, "open of %s failed: %s\n",
3346141cc406Sopenharmony_ci	       s->hw->sane.name, sane_strstatus (status));
3347141cc406Sopenharmony_ci	  return status;
3348141cc406Sopenharmony_ci	}
3349141cc406Sopenharmony_ci
3350141cc406Sopenharmony_ci      /* DB added wait_ready */
3351141cc406Sopenharmony_ci      status = wait_ready (s->fd);
3352141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3353141cc406Sopenharmony_ci	{
3354141cc406Sopenharmony_ci	  DBG (1, "wait for scanner ready failed: %s\n",
3355141cc406Sopenharmony_ci	       sane_strstatus (status));
3356141cc406Sopenharmony_ci	  return status;
3357141cc406Sopenharmony_ci	}
3358141cc406Sopenharmony_ci    }
3359141cc406Sopenharmony_ci
3360141cc406Sopenharmony_ci  s->bytes_to_read = s->params.bytes_per_line * s->params.lines;
3361141cc406Sopenharmony_ci
3362141cc406Sopenharmony_ci  DBG (9, "%d pixels per line, %d bytes, %d lines high, xdpi = %d, "
3363141cc406Sopenharmony_ci       "ydpi = %d, btr = %lu\n",
3364141cc406Sopenharmony_ci       s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines,
3365141cc406Sopenharmony_ci       s->x_resolution, s->y_resolution, (u_long) s->bytes_to_read);
3366141cc406Sopenharmony_ci
3367141cc406Sopenharmony_ci  /* DAL: For single pass scans and the first pass of a 3 pass scan */
3368141cc406Sopenharmony_ci  if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) != 0) || !s->threepasscolor ||
3369141cc406Sopenharmony_ci      (s->threepasscolor && s->this_pass == 1))
3370141cc406Sopenharmony_ci    {
3371141cc406Sopenharmony_ci
3372141cc406Sopenharmony_ci      /* do a calibrate if scanner requires/recommends it */
3373141cc406Sopenharmony_ci      if ((s->hw->flags & ARTEC_FLAG_CALIBRATE) &&
3374141cc406Sopenharmony_ci	  (s->val[OPT_QUALITY_CAL].w == SANE_TRUE))
3375141cc406Sopenharmony_ci	{
3376141cc406Sopenharmony_ci	  status = artec_calibrate_shading (s);
3377141cc406Sopenharmony_ci
3378141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
3379141cc406Sopenharmony_ci	    {
3380141cc406Sopenharmony_ci	      DBG (1, "shading calibration failed: %s\n",
3381141cc406Sopenharmony_ci		   sane_strstatus (status));
3382141cc406Sopenharmony_ci	      return status;
3383141cc406Sopenharmony_ci	    }
3384141cc406Sopenharmony_ci	}
3385141cc406Sopenharmony_ci
3386141cc406Sopenharmony_ci      /* DB added wait_ready */
3387141cc406Sopenharmony_ci      status = wait_ready (s->fd);
3388141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3389141cc406Sopenharmony_ci	{
3390141cc406Sopenharmony_ci	  DBG (1, "wait for scanner ready failed: %s\n",
3391141cc406Sopenharmony_ci	       sane_strstatus (status));
3392141cc406Sopenharmony_ci	  return status;
3393141cc406Sopenharmony_ci	}
3394141cc406Sopenharmony_ci
3395141cc406Sopenharmony_ci      /* send the custom gamma table if we have one */
3396141cc406Sopenharmony_ci      if (s->hw->flags & ARTEC_FLAG_GAMMA)
3397141cc406Sopenharmony_ci	artec_send_gamma_table (s);
3398141cc406Sopenharmony_ci
3399141cc406Sopenharmony_ci      /* now set our scan window */
3400141cc406Sopenharmony_ci      status = artec_set_scan_window (s);
3401141cc406Sopenharmony_ci
3402141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3403141cc406Sopenharmony_ci	{
3404141cc406Sopenharmony_ci	  DBG (1, "set scan window failed: %s\n",
3405141cc406Sopenharmony_ci	       sane_strstatus (status));
3406141cc406Sopenharmony_ci	  return status;
3407141cc406Sopenharmony_ci	}
3408141cc406Sopenharmony_ci
3409141cc406Sopenharmony_ci      /* DB added wait_ready */
3410141cc406Sopenharmony_ci      status = wait_ready (s->fd);
3411141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3412141cc406Sopenharmony_ci	{
3413141cc406Sopenharmony_ci	  DBG (1, "wait for scanner ready failed: %s\n",
3414141cc406Sopenharmony_ci	       sane_strstatus (status));
3415141cc406Sopenharmony_ci	  return status;
3416141cc406Sopenharmony_ci	}
3417141cc406Sopenharmony_ci    }
3418141cc406Sopenharmony_ci
3419141cc406Sopenharmony_ci  /* now we can start the actual scan */
3420141cc406Sopenharmony_ci  /* DAL: For single pass scans and the first pass of a 3 pass scan */
3421141cc406Sopenharmony_ci  if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) != 0) ||
3422141cc406Sopenharmony_ci      (!s->threepasscolor) ||
3423141cc406Sopenharmony_ci      (s->this_pass == 1))
3424141cc406Sopenharmony_ci    {
3425141cc406Sopenharmony_ci      /* DAL - do mode select before each scan */
3426141cc406Sopenharmony_ci      /*       The mode is NOT turned off at the end of the scan */
3427141cc406Sopenharmony_ci      artec_mode_select (s);
3428141cc406Sopenharmony_ci
3429141cc406Sopenharmony_ci      status = artec_start_scan (s);
3430141cc406Sopenharmony_ci
3431141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3432141cc406Sopenharmony_ci	{
3433141cc406Sopenharmony_ci	  DBG (1, "start scan: %s\n", sane_strstatus (status));
3434141cc406Sopenharmony_ci	  return status;
3435141cc406Sopenharmony_ci	}
3436141cc406Sopenharmony_ci    }
3437141cc406Sopenharmony_ci
3438141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
3439141cc406Sopenharmony_ci
3440141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3441141cc406Sopenharmony_ci}
3442141cc406Sopenharmony_ci
3443141cc406Sopenharmony_ci
3444141cc406Sopenharmony_ci#if 0
3445141cc406Sopenharmony_cistatic void
3446141cc406Sopenharmony_cibinout (SANE_Byte byte)
3447141cc406Sopenharmony_ci{
3448141cc406Sopenharmony_ci  SANE_Byte b = byte;
3449141cc406Sopenharmony_ci  int bit;
3450141cc406Sopenharmony_ci
3451141cc406Sopenharmony_ci  for (bit = 0; bit < 8; bit++)
3452141cc406Sopenharmony_ci    {
3453141cc406Sopenharmony_ci      DBG (9, "%d", b & 128 ? 1 : 0);
3454141cc406Sopenharmony_ci      b = b << 1;
3455141cc406Sopenharmony_ci    }
3456141cc406Sopenharmony_ci}
3457141cc406Sopenharmony_ci#endif
3458141cc406Sopenharmony_ci
3459141cc406Sopenharmony_cistatic SANE_Status
3460141cc406Sopenharmony_ciartec_sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len)
3461141cc406Sopenharmony_ci{
3462141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3463141cc406Sopenharmony_ci  SANE_Status status;
3464141cc406Sopenharmony_ci  size_t nread;
3465141cc406Sopenharmony_ci  size_t lread;
3466141cc406Sopenharmony_ci  size_t bytes_read;
3467141cc406Sopenharmony_ci  size_t rows_read;
3468141cc406Sopenharmony_ci  size_t max_read_rows;
3469141cc406Sopenharmony_ci  size_t max_ret_rows;
3470141cc406Sopenharmony_ci  size_t remaining_rows;
3471141cc406Sopenharmony_ci  size_t rows_available;
3472141cc406Sopenharmony_ci  size_t line;
3473141cc406Sopenharmony_ci  SANE_Byte temp_buf[ARTEC_MAX_READ_SIZE];
3474141cc406Sopenharmony_ci  SANE_Byte line_buf[ARTEC_MAX_READ_SIZE];
3475141cc406Sopenharmony_ci
3476141cc406Sopenharmony_ci
3477141cc406Sopenharmony_ci  DBG (7, "artec_sane_read( %p, %p, %d, %d )\n", handle, (void *) buf, max_len, *len);
3478141cc406Sopenharmony_ci
3479141cc406Sopenharmony_ci  *len = 0;
3480141cc406Sopenharmony_ci
3481141cc406Sopenharmony_ci  if (s->bytes_to_read == 0)
3482141cc406Sopenharmony_ci    {
3483141cc406Sopenharmony_ci      if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) != 0) || !s->threepasscolor ||
3484141cc406Sopenharmony_ci	  (s->threepasscolor && s->this_pass == 3))
3485141cc406Sopenharmony_ci	{
3486141cc406Sopenharmony_ci	  do_cancel (s);
3487141cc406Sopenharmony_ci	  /* without this a 4th pass is attempted, yet do_cancel does this */
3488141cc406Sopenharmony_ci	  s->scanning = SANE_FALSE;
3489141cc406Sopenharmony_ci	}
3490141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
3491141cc406Sopenharmony_ci    }
3492141cc406Sopenharmony_ci
3493141cc406Sopenharmony_ci  if (!s->scanning)
3494141cc406Sopenharmony_ci    return do_cancel (s);
3495141cc406Sopenharmony_ci
3496141cc406Sopenharmony_ci  remaining_rows = (s->bytes_to_read + s->params.bytes_per_line - 1) / s->params.bytes_per_line;
3497141cc406Sopenharmony_ci  max_read_rows = s->hw->max_read_size / s->params.bytes_per_line;
3498141cc406Sopenharmony_ci  max_ret_rows = max_len / s->params.bytes_per_line;
3499141cc406Sopenharmony_ci
3500141cc406Sopenharmony_ci  while (artec_get_status (s->fd) == 0)
3501141cc406Sopenharmony_ci    {
3502141cc406Sopenharmony_ci      DBG (120, "hokey loop till data available\n");
3503141cc406Sopenharmony_ci      usleep (50000);		/* sleep for .05 second */
3504141cc406Sopenharmony_ci    }
3505141cc406Sopenharmony_ci
3506141cc406Sopenharmony_ci  rows_read = 0;
3507141cc406Sopenharmony_ci  bytes_read = 0;
3508141cc406Sopenharmony_ci  while ((rows_read < max_ret_rows) && (rows_read < remaining_rows))
3509141cc406Sopenharmony_ci    {
3510141cc406Sopenharmony_ci      DBG (50, "top of while loop, rr = %lu, mrr = %lu, rem = %lu\n",
3511141cc406Sopenharmony_ci	   (u_long) rows_read, (u_long) max_ret_rows, (u_long) remaining_rows);
3512141cc406Sopenharmony_ci
3513141cc406Sopenharmony_ci      if (s->bytes_to_read - bytes_read <= s->params.bytes_per_line * max_read_rows)
3514141cc406Sopenharmony_ci	{
3515141cc406Sopenharmony_ci	  nread = s->bytes_to_read - bytes_read;
3516141cc406Sopenharmony_ci	}
3517141cc406Sopenharmony_ci      else
3518141cc406Sopenharmony_ci	{
3519141cc406Sopenharmony_ci	  nread = s->params.bytes_per_line * max_read_rows;
3520141cc406Sopenharmony_ci	}
3521141cc406Sopenharmony_ci      lread = nread / s->params.bytes_per_line;
3522141cc406Sopenharmony_ci
3523141cc406Sopenharmony_ci      if ((max_read_rows - rows_read) < lread)
3524141cc406Sopenharmony_ci	{
3525141cc406Sopenharmony_ci	  lread = max_read_rows - rows_read;
3526141cc406Sopenharmony_ci	  nread = lread * s->params.bytes_per_line;
3527141cc406Sopenharmony_ci	}
3528141cc406Sopenharmony_ci
3529141cc406Sopenharmony_ci      if ((max_ret_rows - rows_read) < lread)
3530141cc406Sopenharmony_ci	{
3531141cc406Sopenharmony_ci	  lread = max_ret_rows - rows_read;
3532141cc406Sopenharmony_ci	  nread = lread * s->params.bytes_per_line;
3533141cc406Sopenharmony_ci	}
3534141cc406Sopenharmony_ci
3535141cc406Sopenharmony_ci      while ((rows_available = artec_get_status (s->fd)) == 0)
3536141cc406Sopenharmony_ci	{
3537141cc406Sopenharmony_ci	  DBG (120, "hokey loop till data available\n");
3538141cc406Sopenharmony_ci	  usleep (50000);	/* sleep for .05 second */
3539141cc406Sopenharmony_ci	}
3540141cc406Sopenharmony_ci
3541141cc406Sopenharmony_ci      if (rows_available < lread)
3542141cc406Sopenharmony_ci	{
3543141cc406Sopenharmony_ci	  lread = rows_available;
3544141cc406Sopenharmony_ci	  nread = lread * s->params.bytes_per_line;
3545141cc406Sopenharmony_ci	}
3546141cc406Sopenharmony_ci
3547141cc406Sopenharmony_ci      /* This should never happen, but just in case... */
3548141cc406Sopenharmony_ci      if (nread > (s->bytes_to_read - bytes_read))
3549141cc406Sopenharmony_ci	{
3550141cc406Sopenharmony_ci	  nread = s->bytes_to_read - bytes_read;
3551141cc406Sopenharmony_ci	  lread = 1;
3552141cc406Sopenharmony_ci	}
3553141cc406Sopenharmony_ci
3554141cc406Sopenharmony_ci      DBG (50, "rows_available = %lu, params.lines = %d, bytes_per_line = %d\n",
3555141cc406Sopenharmony_ci	   (u_long) rows_available, s->params.lines, s->params.bytes_per_line);
3556141cc406Sopenharmony_ci      DBG (50, "bytes_to_read = %lu, max_len = %d, max_rows = %lu\n",
3557141cc406Sopenharmony_ci	   (u_long) s->bytes_to_read, max_len, (u_long) max_ret_rows);
3558141cc406Sopenharmony_ci      DBG (50, "nread = %lu, lread = %lu, bytes_read = %lu, rows_read = %lu\n",
3559141cc406Sopenharmony_ci	   (u_long) nread, (u_long) lread, (u_long) bytes_read, (u_long) rows_read);
3560141cc406Sopenharmony_ci
3561141cc406Sopenharmony_ci      status = read_data (s->fd, ARTEC_DATA_IMAGE, temp_buf, &nread);
3562141cc406Sopenharmony_ci
3563141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3564141cc406Sopenharmony_ci	{
3565141cc406Sopenharmony_ci	  end_scan (s);
3566141cc406Sopenharmony_ci	  do_cancel (s);
3567141cc406Sopenharmony_ci	  return (SANE_STATUS_IO_ERROR);
3568141cc406Sopenharmony_ci	}
3569141cc406Sopenharmony_ci
3570141cc406Sopenharmony_ci      if ((DBG_LEVEL == 101) &&
3571141cc406Sopenharmony_ci	  (debug_fd > -1))
3572141cc406Sopenharmony_ci	{
3573141cc406Sopenharmony_ci	  write (debug_fd, temp_buf, nread);
3574141cc406Sopenharmony_ci	}
3575141cc406Sopenharmony_ci
3576141cc406Sopenharmony_ci      if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) &&
3577141cc406Sopenharmony_ci	  (s->hw->flags & ARTEC_FLAG_RGB_LINE_OFFSET))
3578141cc406Sopenharmony_ci	{
3579141cc406Sopenharmony_ci	  for (line = 0; line < lread; line++)
3580141cc406Sopenharmony_ci	    {
3581141cc406Sopenharmony_ci	      memcpy (line_buf,
3582141cc406Sopenharmony_ci		      temp_buf + (line * s->params.bytes_per_line),
3583141cc406Sopenharmony_ci		      s->params.bytes_per_line);
3584141cc406Sopenharmony_ci
3585141cc406Sopenharmony_ci	      nread = s->params.bytes_per_line;
3586141cc406Sopenharmony_ci
3587141cc406Sopenharmony_ci	      artec_buffer_line_offset (s, s->line_offset, line_buf, &nread);
3588141cc406Sopenharmony_ci
3589141cc406Sopenharmony_ci	      if (nread > 0)
3590141cc406Sopenharmony_ci		{
3591141cc406Sopenharmony_ci		  if (s->hw->flags & ARTEC_FLAG_RGB_CHAR_SHIFT)
3592141cc406Sopenharmony_ci		    {
3593141cc406Sopenharmony_ci		      artec_line_rgb_to_byte_rgb (line_buf,
3594141cc406Sopenharmony_ci						  s->params.pixels_per_line);
3595141cc406Sopenharmony_ci		    }
3596141cc406Sopenharmony_ci		  if (s->hw->flags & ARTEC_FLAG_IMAGE_REV_LR)
3597141cc406Sopenharmony_ci		    {
3598141cc406Sopenharmony_ci		      artec_reverse_line (s, line_buf);
3599141cc406Sopenharmony_ci		    }
3600141cc406Sopenharmony_ci
3601141cc406Sopenharmony_ci		  /* do software calibration if necessary */
3602141cc406Sopenharmony_ci		  if (s->val[OPT_SOFTWARE_CAL].w)
3603141cc406Sopenharmony_ci		    {
3604141cc406Sopenharmony_ci		      artec_software_rgb_calibrate (s, line_buf, 1);
3605141cc406Sopenharmony_ci		    }
3606141cc406Sopenharmony_ci
3607141cc406Sopenharmony_ci		  memcpy (buf + bytes_read, line_buf,
3608141cc406Sopenharmony_ci			  s->params.bytes_per_line);
3609141cc406Sopenharmony_ci		  bytes_read += nread;
3610141cc406Sopenharmony_ci		  rows_read++;
3611141cc406Sopenharmony_ci		}
3612141cc406Sopenharmony_ci	    }
3613141cc406Sopenharmony_ci	}
3614141cc406Sopenharmony_ci      else
3615141cc406Sopenharmony_ci	{
3616141cc406Sopenharmony_ci	  if ((s->hw->flags & ARTEC_FLAG_IMAGE_REV_LR) ||
3617141cc406Sopenharmony_ci	      ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) &&
3618141cc406Sopenharmony_ci	       (s->hw->flags & ARTEC_FLAG_RGB_CHAR_SHIFT)))
3619141cc406Sopenharmony_ci	    {
3620141cc406Sopenharmony_ci	      for (line = 0; line < lread; line++)
3621141cc406Sopenharmony_ci		{
3622141cc406Sopenharmony_ci		  if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) &&
3623141cc406Sopenharmony_ci		      (s->hw->flags & ARTEC_FLAG_RGB_CHAR_SHIFT))
3624141cc406Sopenharmony_ci		    {
3625141cc406Sopenharmony_ci		      artec_line_rgb_to_byte_rgb (temp_buf +
3626141cc406Sopenharmony_ci					  (line * s->params.bytes_per_line),
3627141cc406Sopenharmony_ci						  s->params.pixels_per_line);
3628141cc406Sopenharmony_ci		    }
3629141cc406Sopenharmony_ci		  if (s->hw->flags & ARTEC_FLAG_IMAGE_REV_LR)
3630141cc406Sopenharmony_ci		    {
3631141cc406Sopenharmony_ci		      artec_reverse_line (s, temp_buf +
3632141cc406Sopenharmony_ci					  (line * s->params.bytes_per_line));
3633141cc406Sopenharmony_ci		    }
3634141cc406Sopenharmony_ci		}
3635141cc406Sopenharmony_ci	    }
3636141cc406Sopenharmony_ci
3637141cc406Sopenharmony_ci	  /* do software calibration if necessary */
3638141cc406Sopenharmony_ci	  if ((s->val[OPT_SOFTWARE_CAL].w) &&
3639141cc406Sopenharmony_ci	      (strcmp (s->mode, SANE_VALUE_SCAN_MODE_COLOR) == 0))
3640141cc406Sopenharmony_ci	    {
3641141cc406Sopenharmony_ci	      artec_software_rgb_calibrate (s, temp_buf, lread);
3642141cc406Sopenharmony_ci	    }
3643141cc406Sopenharmony_ci
3644141cc406Sopenharmony_ci	  memcpy (buf + bytes_read, temp_buf, nread);
3645141cc406Sopenharmony_ci	  bytes_read += nread;
3646141cc406Sopenharmony_ci	  rows_read += lread;
3647141cc406Sopenharmony_ci	}
3648141cc406Sopenharmony_ci    }
3649141cc406Sopenharmony_ci
3650141cc406Sopenharmony_ci  *len = bytes_read;
3651141cc406Sopenharmony_ci  s->bytes_to_read -= bytes_read;
3652141cc406Sopenharmony_ci
3653141cc406Sopenharmony_ci  DBG (9, "artec_sane_read() returning, we read %lu bytes, %lu left\n",
3654141cc406Sopenharmony_ci       (u_long) * len, (u_long) s->bytes_to_read);
3655141cc406Sopenharmony_ci
3656141cc406Sopenharmony_ci  if ((s->bytes_to_read == 0) &&
3657141cc406Sopenharmony_ci      (s->hw->flags & ARTEC_FLAG_RGB_LINE_OFFSET) &&
3658141cc406Sopenharmony_ci      (tmp_line_buf != NULL))
3659141cc406Sopenharmony_ci    {
3660141cc406Sopenharmony_ci      artec_buffer_line_offset_free ();
3661141cc406Sopenharmony_ci    }
3662141cc406Sopenharmony_ci
3663141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3664141cc406Sopenharmony_ci}
3665141cc406Sopenharmony_ci
3666141cc406Sopenharmony_ciSANE_Status
3667141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len)
3668141cc406Sopenharmony_ci{
3669141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3670141cc406Sopenharmony_ci  SANE_Status status;
3671141cc406Sopenharmony_ci  int bytes_to_copy;
3672141cc406Sopenharmony_ci  int loop;
3673141cc406Sopenharmony_ci
3674141cc406Sopenharmony_ci  static SANE_Byte temp_buf[ARTEC_MAX_READ_SIZE];
3675141cc406Sopenharmony_ci  static int bytes_in_buf = 0;
3676141cc406Sopenharmony_ci
3677141cc406Sopenharmony_ci  DBG (7, "sane_read( %p, %p, %d, %d )\n", handle, (void *) buf, max_len, *len);
3678141cc406Sopenharmony_ci  DBG (9, "sane_read: bib = %d, ml = %d\n", bytes_in_buf, max_len);
3679141cc406Sopenharmony_ci
3680141cc406Sopenharmony_ci  if (bytes_in_buf != 0)
3681141cc406Sopenharmony_ci    {
3682141cc406Sopenharmony_ci      bytes_to_copy = max_len < bytes_in_buf ? max_len : bytes_in_buf;
3683141cc406Sopenharmony_ci    }
3684141cc406Sopenharmony_ci  else
3685141cc406Sopenharmony_ci    {
3686141cc406Sopenharmony_ci      status = artec_sane_read (s, temp_buf, s->hw->max_read_size, len);
3687141cc406Sopenharmony_ci
3688141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3689141cc406Sopenharmony_ci	{
3690141cc406Sopenharmony_ci	  return (status);
3691141cc406Sopenharmony_ci	}
3692141cc406Sopenharmony_ci
3693141cc406Sopenharmony_ci      bytes_in_buf = *len;
3694141cc406Sopenharmony_ci
3695141cc406Sopenharmony_ci      if (*len == 0)
3696141cc406Sopenharmony_ci	{
3697141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
3698141cc406Sopenharmony_ci	}
3699141cc406Sopenharmony_ci
3700141cc406Sopenharmony_ci      bytes_to_copy = max_len < s->hw->max_read_size ?
3701141cc406Sopenharmony_ci	max_len : s->hw->max_read_size;
3702141cc406Sopenharmony_ci      bytes_to_copy = *len < bytes_to_copy ? *len : bytes_to_copy;
3703141cc406Sopenharmony_ci    }
3704141cc406Sopenharmony_ci
3705141cc406Sopenharmony_ci  memcpy (buf, temp_buf, bytes_to_copy);
3706141cc406Sopenharmony_ci  bytes_in_buf -= bytes_to_copy;
3707141cc406Sopenharmony_ci  *len = bytes_to_copy;
3708141cc406Sopenharmony_ci
3709141cc406Sopenharmony_ci  DBG (9, "sane_read: btc = %d, bib now = %d\n",
3710141cc406Sopenharmony_ci       bytes_to_copy, bytes_in_buf);
3711141cc406Sopenharmony_ci
3712141cc406Sopenharmony_ci  for (loop = 0; loop < bytes_in_buf; loop++)
3713141cc406Sopenharmony_ci    {
3714141cc406Sopenharmony_ci      temp_buf[loop] = temp_buf[loop + bytes_to_copy];
3715141cc406Sopenharmony_ci    }
3716141cc406Sopenharmony_ci
3717141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3718141cc406Sopenharmony_ci}
3719141cc406Sopenharmony_ci
3720141cc406Sopenharmony_civoid
3721141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
3722141cc406Sopenharmony_ci{
3723141cc406Sopenharmony_ci  ARTEC_Scanner *s = handle;
3724141cc406Sopenharmony_ci
3725141cc406Sopenharmony_ci  DBG (7, "sane_cancel()\n");
3726141cc406Sopenharmony_ci
3727141cc406Sopenharmony_ci  if (s->scanning)
3728141cc406Sopenharmony_ci    {
3729141cc406Sopenharmony_ci      s->scanning = SANE_FALSE;
3730141cc406Sopenharmony_ci
3731141cc406Sopenharmony_ci      abort_scan (s);
3732141cc406Sopenharmony_ci
3733141cc406Sopenharmony_ci      do_cancel (s);
3734141cc406Sopenharmony_ci    }
3735141cc406Sopenharmony_ci}
3736141cc406Sopenharmony_ci
3737141cc406Sopenharmony_ciSANE_Status
3738141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
3739141cc406Sopenharmony_ci{
3740141cc406Sopenharmony_ci  DBG (7, "sane_set_io_mode( %p, %d )\n", handle, non_blocking);
3741141cc406Sopenharmony_ci
3742141cc406Sopenharmony_ci  return (SANE_STATUS_UNSUPPORTED);
3743141cc406Sopenharmony_ci}
3744141cc406Sopenharmony_ci
3745141cc406Sopenharmony_ciSANE_Status
3746141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
3747141cc406Sopenharmony_ci{
3748141cc406Sopenharmony_ci  DBG (7, "sane_get_select_fd( %p, %d )\n", handle, *fd );
3749141cc406Sopenharmony_ci
3750141cc406Sopenharmony_ci  return (SANE_STATUS_UNSUPPORTED);
3751141cc406Sopenharmony_ci}
3752