1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2000-2001 Kazuya Fukuda, based on sharp.c, which is
4141cc406Sopenharmony_ci   based on canon.c.
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   This file implements a SANE backend for NEC flatbed scanners.  */
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci/*
45141cc406Sopenharmony_ci   Version 0.12
46141cc406Sopenharmony_ci   - Remove references to sharp backend (grep for "JX").
47141cc406Sopenharmony_ci   - Check for HAVE_SYS_SHM_H before including sys/shm.h and
48141cc406Sopenharmony_ci     disable shared memory support if necessary.
49141cc406Sopenharmony_ci   - free devlist allocated in sane_get_devices() in sane_exit()
50141cc406Sopenharmony_ci   - resolution setting bug fixed(PC-IN500/4C 10dpi step)
51141cc406Sopenharmony_ci   - remove resolution list
52141cc406Sopenharmony_ci   Version 0.11
53141cc406Sopenharmony_ci   - get_data_buffer_status is not called in sane_get_parameter and
54141cc406Sopenharmony_ci     sane_read_direct, sane_read_shuffled.
55141cc406Sopenharmony_ci   - change some #include <> to ""
56141cc406Sopenharmony_ci   Version 0.10
57141cc406Sopenharmony_ci   - First release!
58141cc406Sopenharmony_ci   - supported scanner
59141cc406Sopenharmony_ci     PC-IN500/4C                    available
60141cc406Sopenharmony_ci     MultiReder 300U/300S series    not available
61141cc406Sopenharmony_ci     MultiReder 600U/600S series    not available
62141cc406Sopenharmony_ci     MultiReader PetiScan series    not available
63141cc406Sopenharmony_ci*/
64141cc406Sopenharmony_ci#include "../include/sane/config.h"
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci#include <limits.h>
67141cc406Sopenharmony_ci#include <stdlib.h>
68141cc406Sopenharmony_ci#include <stdarg.h>
69141cc406Sopenharmony_ci#include <string.h>
70141cc406Sopenharmony_ci#include <unistd.h>
71141cc406Sopenharmony_ci#include <errno.h>
72141cc406Sopenharmony_ci#include <math.h>
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci#include "../include/sane/sane.h"
75141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
76141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci/* QUEUEDEBUG should be undefined unless you want to play
79141cc406Sopenharmony_ci   with the sanei_scsi.c under Linux and/or with the Linux's SG driver,
80141cc406Sopenharmony_ci   or your suspect problems with command queueing
81141cc406Sopenharmony_ci*/
82141cc406Sopenharmony_ci#define QUEUEDEBUG
83141cc406Sopenharmony_ci/*#define DEBUG*/
84141cc406Sopenharmony_ci#ifdef DEBUG
85141cc406Sopenharmony_ci#include <unistd.h>
86141cc406Sopenharmony_ci#include <sys/time.h>
87141cc406Sopenharmony_ci#endif
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci/* USE_FORK: fork a special reader process
90141cc406Sopenharmony_ci   disable shared memory support.
91141cc406Sopenharmony_ci*/
92141cc406Sopenharmony_ci#if 0
93141cc406Sopenharmony_ci#ifdef HAVE_SYS_SHM_H
94141cc406Sopenharmony_ci#define USE_FORK
95141cc406Sopenharmony_ci#endif
96141cc406Sopenharmony_ci#endif
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci#ifdef USE_FORK
99141cc406Sopenharmony_ci#include <signal.h>
100141cc406Sopenharmony_ci#include <fcntl.h>
101141cc406Sopenharmony_ci#include <sys/types.h>
102141cc406Sopenharmony_ci#include <sys/wait.h>
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci#include <sys/ipc.h>
105141cc406Sopenharmony_ci#include <sys/shm.h>
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci#endif /* USE_FORK */
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci#ifndef USE_CUSTOM_GAMMA
110141cc406Sopenharmony_ci#define USE_CUSTOM_GAMMA
111141cc406Sopenharmony_ci#endif
112141cc406Sopenharmony_ci#ifndef USE_COLOR_THRESHOLD
113141cc406Sopenharmony_ci#define USE_COLOR_THRESHOLD
114141cc406Sopenharmony_ci#endif
115141cc406Sopenharmony_ci/* enable a short list of some standard resolutions. XSane provides
116141cc406Sopenharmony_ci   its own resolution list; therefore its is generally not reasonable
117141cc406Sopenharmony_ci   to enable this list, if you mainly using XSane. But it might be handy
118141cc406Sopenharmony_ci   if you are working with xscanimage
119141cc406Sopenharmony_ci*/
120141cc406Sopenharmony_ci/* #define USE_RESOLUTION_LIST */
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci#define BACKEND_NAME nec
123141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci#ifndef PATH_MAX
126141cc406Sopenharmony_ci#define PATH_MAX	1024
127141cc406Sopenharmony_ci#endif
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci#define DEFAULT_MUD_1200 1200
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci#define PIX_TO_MM(x, mud) ((x) * 25.4 / mud)
132141cc406Sopenharmony_ci#define MM_TO_PIX(x, mud) ((x) * mud / 25.4)
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
135141cc406Sopenharmony_ci#define NEC_CONFIG_FILE "nec.conf"
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci#include "nec.h"
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_cistatic int num_devices = 0;
140141cc406Sopenharmony_cistatic NEC_Device *first_dev = NULL;
141141cc406Sopenharmony_cistatic NEC_Scanner *first_handle = NULL;
142141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_citypedef enum
145141cc406Sopenharmony_ci  {
146141cc406Sopenharmony_ci    MODES_LINEART  = 0,
147141cc406Sopenharmony_ci    MODES_GRAY,
148141cc406Sopenharmony_ci    MODES_COLOR,
149141cc406Sopenharmony_ci    MODES_LINEART_COLOR
150141cc406Sopenharmony_ci  }
151141cc406Sopenharmony_ciModes;
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci#define M_LINEART            SANE_VALUE_SCAN_MODE_LINEART
154141cc406Sopenharmony_ci#define M_GRAY               SANE_VALUE_SCAN_MODE_GRAY
155141cc406Sopenharmony_ci#define M_LINEART_COLOR      "Lineart Color"
156141cc406Sopenharmony_ci#define M_COLOR              SANE_VALUE_SCAN_MODE_COLOR
157141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] =
158141cc406Sopenharmony_ci{
159141cc406Sopenharmony_ci#if 0
160141cc406Sopenharmony_ci  M_LINEART, M_GRAY, M_LINEART_COLOR, M_COLOR,
161141cc406Sopenharmony_ci#endif
162141cc406Sopenharmony_ci  M_LINEART, M_GRAY, M_COLOR,
163141cc406Sopenharmony_ci  0
164141cc406Sopenharmony_ci};
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci#define M_BILEVEL        "none"
167141cc406Sopenharmony_ci#define M_BAYER          "Dither Bayer"
168141cc406Sopenharmony_ci#define M_SPIRAL         "Dither Spiral"
169141cc406Sopenharmony_ci#define M_DISPERSED      "Dither Dispersed"
170141cc406Sopenharmony_ci#define M_ERRDIFFUSION   "Error Diffusion"
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci#define M_DITHER1        "Dither 1"
173141cc406Sopenharmony_ci#define M_DITHER2        "Dither 2"
174141cc406Sopenharmony_ci#define M_DITHER3        "Dither 3"
175141cc406Sopenharmony_ci#define M_DITHERUSER     "User defined"
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list[] =
178141cc406Sopenharmony_ci{
179141cc406Sopenharmony_ci  M_BILEVEL, M_DITHER1, M_DITHER2, M_DITHER3,
180141cc406Sopenharmony_ci  0
181141cc406Sopenharmony_ci};
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci#define LIGHT_GREEN "green"
184141cc406Sopenharmony_ci#define LIGHT_RED   "red"
185141cc406Sopenharmony_ci#define LIGHT_BLUE  "blue"
186141cc406Sopenharmony_ci#define LIGHT_NONE  "none"
187141cc406Sopenharmony_ci#define LIGHT_WHITE "white"
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_cistatic const SANE_String_Const light_color_list[] =
190141cc406Sopenharmony_ci{
191141cc406Sopenharmony_ci  LIGHT_GREEN, LIGHT_RED, LIGHT_BLUE, LIGHT_NONE,
192141cc406Sopenharmony_ci  0
193141cc406Sopenharmony_ci};
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci/* possible values for ADF/FSU selection */
196141cc406Sopenharmony_cistatic SANE_String use_adf = "Automatic Document Feeder";
197141cc406Sopenharmony_cistatic SANE_String use_fsu = "Transparency Adapter";
198141cc406Sopenharmony_cistatic SANE_String use_simple = "Flatbed";
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci#define HAVE_FSU 1
201141cc406Sopenharmony_ci#define HAVE_ADF 2
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci/* The follow #defines are used in NEC_Scanner.adf_fsu_mode
204141cc406Sopenharmony_ci   and as indexes for the arrays x_ranges, y_ranges in NEC_Device
205141cc406Sopenharmony_ci*/
206141cc406Sopenharmony_ci#define SCAN_SIMPLE 0
207141cc406Sopenharmony_ci#define SCAN_WITH_FSU 1
208141cc406Sopenharmony_ci#define SCAN_WITH_ADF 2
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci#define LOAD_PAPER 1
211141cc406Sopenharmony_ci#define UNLOAD_PAPER 0
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci#define PAPER_MAX  10
214141cc406Sopenharmony_ci#define W_LETTER "11\"x17\""
215141cc406Sopenharmony_ci#define INVOICE  "8.5\"x5.5\""
216141cc406Sopenharmony_cistatic const SANE_String_Const paper_list_pcinxxx[] =
217141cc406Sopenharmony_ci{
218141cc406Sopenharmony_ci  "A3", "A4", "A5", "A6", "B4", "B5",
219141cc406Sopenharmony_ci  W_LETTER, "Legal", "Letter", INVOICE,
220141cc406Sopenharmony_ci  0
221141cc406Sopenharmony_ci};
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_cistatic const SANE_String_Const paper_list_pcin500[] =
224141cc406Sopenharmony_ci{
225141cc406Sopenharmony_ci  "A4", "A5", "A6", "B5",
226141cc406Sopenharmony_ci  0
227141cc406Sopenharmony_ci};
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci#define CRT1    "CRT1"
231141cc406Sopenharmony_ci#define CRT2    "CRT2"
232141cc406Sopenharmony_ci#define PRINTER1 "PRINTER1"
233141cc406Sopenharmony_ci#define PRINTER2 "PRINTER2"
234141cc406Sopenharmony_ci#define NONE    "NONE"
235141cc406Sopenharmony_ci/* #define CUSTOM  "CUSTOM" */
236141cc406Sopenharmony_cistatic const SANE_String_Const gamma_list[] =
237141cc406Sopenharmony_ci{
238141cc406Sopenharmony_ci  CRT1, CRT2, PRINTER1, PRINTER2, NONE,
239141cc406Sopenharmony_ci  0
240141cc406Sopenharmony_ci};
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci#if 0
243141cc406Sopenharmony_ci#define SPEED_NORMAL    "Normal"
244141cc406Sopenharmony_ci#define SPEED_FAST      "Fast"
245141cc406Sopenharmony_cistatic const SANE_String_Const speed_list[] =
246141cc406Sopenharmony_ci{
247141cc406Sopenharmony_ci  SPEED_NORMAL, SPEED_FAST,
248141cc406Sopenharmony_ci  0
249141cc406Sopenharmony_ci};
250141cc406Sopenharmony_ci#endif
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci#ifdef USE_RESOLUTION_LIST
253141cc406Sopenharmony_ci#define RESOLUTION_MAX_PCINXXX 8
254141cc406Sopenharmony_cistatic const SANE_String_Const resolution_list_pcinxxx[] =
255141cc406Sopenharmony_ci{
256141cc406Sopenharmony_ci  "50", "75", "100", "150", "200", "300", "400", "600", "Select",
257141cc406Sopenharmony_ci  0
258141cc406Sopenharmony_ci};
259141cc406Sopenharmony_ci
260141cc406Sopenharmony_ci#define RESOLUTION_MAX_PCIN500 8
261141cc406Sopenharmony_cistatic const SANE_String_Const resolution_list_pcin500[] =
262141cc406Sopenharmony_ci{
263141cc406Sopenharmony_ci  "50", "75", "100", "150", "200", "300", "400", "480", "Select",
264141cc406Sopenharmony_ci  0
265141cc406Sopenharmony_ci};
266141cc406Sopenharmony_ci#endif
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci#define EDGE_NONE    "None"
269141cc406Sopenharmony_ci#define EDGE_MIDDLE  "Middle"
270141cc406Sopenharmony_ci#define EDGE_STRONG  "Strong"
271141cc406Sopenharmony_ci#define EDGE_BLUR    "Blur"
272141cc406Sopenharmony_cistatic const SANE_String_Const edge_emphasis_list[] =
273141cc406Sopenharmony_ci{
274141cc406Sopenharmony_ci  EDGE_NONE, EDGE_MIDDLE, EDGE_STRONG, EDGE_BLUR,
275141cc406Sopenharmony_ci  0
276141cc406Sopenharmony_ci};
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
279141cc406Sopenharmony_cistatic const SANE_Range u8_range =
280141cc406Sopenharmony_ci  {
281141cc406Sopenharmony_ci      0,				/* minimum */
282141cc406Sopenharmony_ci    255,				/* maximum */
283141cc406Sopenharmony_ci      0				/* quantization */
284141cc406Sopenharmony_ci  };
285141cc406Sopenharmony_ci#endif
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_cistatic SANE_Status
288141cc406Sopenharmony_cisense_handler(int fd, u_char *sense_buffer, void *ss)
289141cc406Sopenharmony_ci{
290141cc406Sopenharmony_ci  int sense_key;
291141cc406Sopenharmony_ci  NEC_Sense_Data *sdat = (NEC_Sense_Data *) ss;
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci  (void) fd; /* silence compilation warnings */
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_ci  #define add_sense_code sense_buffer[12]
296141cc406Sopenharmony_ci  #define add_sense_qual sense_buffer[13]
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  memcpy(sdat->sb, sense_buffer, 16);
299141cc406Sopenharmony_ci
300141cc406Sopenharmony_ci  DBG(10, "sense code: %02x %02x %02x %02x %02x %02x %02x %02x "
301141cc406Sopenharmony_ci          "%02x %02x %02x %02x %02x %02x %02x %02x\n",
302141cc406Sopenharmony_ci          sense_buffer[0], sense_buffer[1], sense_buffer[2], sense_buffer[3],
303141cc406Sopenharmony_ci          sense_buffer[4], sense_buffer[5], sense_buffer[6], sense_buffer[7],
304141cc406Sopenharmony_ci          sense_buffer[8], sense_buffer[9], sense_buffer[10], sense_buffer[11],
305141cc406Sopenharmony_ci          sense_buffer[12], sense_buffer[13], sense_buffer[14], sense_buffer[15]);
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  sense_key = sense_buffer[1] & 0x0F;
308141cc406Sopenharmony_ci  /* do we have additional information ? */
309141cc406Sopenharmony_ci  if (sense_buffer[7] >= 5)
310141cc406Sopenharmony_ci    {
311141cc406Sopenharmony_ci      if (sdat->model == PCIN500)
312141cc406Sopenharmony_ci        {
313141cc406Sopenharmony_ci          switch (sense_key)
314141cc406Sopenharmony_ci            {
315141cc406Sopenharmony_ci              case 0x02: /* not ready */
316141cc406Sopenharmony_ci                switch (add_sense_code)
317141cc406Sopenharmony_ci                  {
318141cc406Sopenharmony_ci                    case 0x80:
319141cc406Sopenharmony_ci                      switch (add_sense_qual & 0xf0)
320141cc406Sopenharmony_ci                        {
321141cc406Sopenharmony_ci                          case 0x10:
322141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: memory error\n");
323141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
324141cc406Sopenharmony_ci                          case 0x20:
325141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: hardware error\n");
326141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
327141cc406Sopenharmony_ci                          case 0x30:
328141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: optical error\n");
329141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
330141cc406Sopenharmony_ci                          case 0x40:
331141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: optical error\n");
332141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
333141cc406Sopenharmony_ci                          case 0x50:
334141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: marker error\n");
335141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
336141cc406Sopenharmony_ci                          case 0x60:
337141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: mechanical error\n");
338141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
339141cc406Sopenharmony_ci                          case 0x70:
340141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: hardware error\n");
341141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
342141cc406Sopenharmony_ci                          case 0x80:
343141cc406Sopenharmony_ci                            DBG(1, "Scanner not ready: hardware error\n");
344141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
345141cc406Sopenharmony_ci                          case 0x90:
346141cc406Sopenharmony_ci                          default:
347141cc406Sopenharmony_ci                            DBG(5, "Scanner not ready: undocumented reason\n");
348141cc406Sopenharmony_ci                            return SANE_STATUS_IO_ERROR;
349141cc406Sopenharmony_ci                        }
350141cc406Sopenharmony_ci                    default:
351141cc406Sopenharmony_ci                      DBG(5, "Scanner not ready: unknown sense code\n");
352141cc406Sopenharmony_ci                      return SANE_STATUS_IO_ERROR;
353141cc406Sopenharmony_ci                  }
354141cc406Sopenharmony_ci              case 0x03: /* medium error */
355141cc406Sopenharmony_ci		DBG(5, "medium error: undocumented reason\n");
356141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
357141cc406Sopenharmony_ci              case 0x04: /* hardware error */
358141cc406Sopenharmony_ci		DBG(1, "general hardware error\n");
359141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
360141cc406Sopenharmony_ci              case 0x05: /* illegal request */
361141cc406Sopenharmony_ci                DBG(10, "error: illegal request\n");
362141cc406Sopenharmony_ci                return SANE_STATUS_IO_ERROR;
363141cc406Sopenharmony_ci              case 0x06: /* unit attention */
364141cc406Sopenharmony_ci		DBG(5, "unit attention: exact reason not documented\n");
365141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
366141cc406Sopenharmony_ci              case 0x0B: /* data remains */
367141cc406Sopenharmony_ci                DBG(5, "error: aborted command\n");
368141cc406Sopenharmony_ci                return SANE_STATUS_IO_ERROR;
369141cc406Sopenharmony_ci              default:
370141cc406Sopenharmony_ci                DBG(5, "error: sense code not documented\n");
371141cc406Sopenharmony_ci                return SANE_STATUS_IO_ERROR;
372141cc406Sopenharmony_ci            }
373141cc406Sopenharmony_ci        }
374141cc406Sopenharmony_ci    }
375141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
376141cc406Sopenharmony_ci}
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_cistatic SANE_Status
379141cc406Sopenharmony_citest_unit_ready (int fd)
380141cc406Sopenharmony_ci{
381141cc406Sopenharmony_ci  static u_char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
382141cc406Sopenharmony_ci  SANE_Status status;
383141cc406Sopenharmony_ci  DBG (11, "<< test_unit_ready ");
384141cc406Sopenharmony_ci
385141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci  DBG (11, ">>\n");
388141cc406Sopenharmony_ci  return (status);
389141cc406Sopenharmony_ci}
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci#if 0
392141cc406Sopenharmony_cistatic SANE_Status
393141cc406Sopenharmony_cirequest_sense (int fd, void *sense_buf, size_t *sense_size)
394141cc406Sopenharmony_ci{
395141cc406Sopenharmony_ci  static u_char cmd[] = {REQUEST_SENSE, 0, 0, 0, SENSE_LEN, 0};
396141cc406Sopenharmony_ci  SANE_Status status;
397141cc406Sopenharmony_ci  DBG (11, "<< request_sense ");
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), sense_buf, sense_size);
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  DBG (11, ">>\n");
402141cc406Sopenharmony_ci  return (status);
403141cc406Sopenharmony_ci}
404141cc406Sopenharmony_ci#endif
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_cistatic SANE_Status
407141cc406Sopenharmony_ciinquiry (int fd, void *inq_buf, size_t *inq_size)
408141cc406Sopenharmony_ci{
409141cc406Sopenharmony_ci  static u_char cmd[] = {INQUIRY, 0, 0, 0, INQUIRY_LEN, 0};
410141cc406Sopenharmony_ci  SANE_Status status;
411141cc406Sopenharmony_ci  DBG (11, "<< inquiry ");
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), inq_buf, inq_size);
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  DBG (11, ">>\n");
416141cc406Sopenharmony_ci  return (status);
417141cc406Sopenharmony_ci}
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_cistatic SANE_Status
420141cc406Sopenharmony_cimode_select_mud (int fd, int mud)
421141cc406Sopenharmony_ci{
422141cc406Sopenharmony_ci  static u_char cmd[6 + MODEPARAM_LEN] =
423141cc406Sopenharmony_ci  {MODE_SELECT6, 0x10, 0, 0, MODEPARAM_LEN, 0};
424141cc406Sopenharmony_ci  mode_select_param *mp;
425141cc406Sopenharmony_ci  SANE_Status status;
426141cc406Sopenharmony_ci  DBG (11, "<< mode_select_mud ");
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci  mp = (mode_select_param *)(cmd + 6);
429141cc406Sopenharmony_ci  memset (mp, 0, MODEPARAM_LEN);
430141cc406Sopenharmony_ci  mp->mode_param_header1 = 11;
431141cc406Sopenharmony_ci  mp->page_code = 3;
432141cc406Sopenharmony_ci  mp->page_length = 6;
433141cc406Sopenharmony_ci  mp->mud[0] = mud >> 8;
434141cc406Sopenharmony_ci  mp->mud[1] = mud & 0xFF;
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
437141cc406Sopenharmony_ci
438141cc406Sopenharmony_ci  DBG (11, ">>\n");
439141cc406Sopenharmony_ci  return (status);
440141cc406Sopenharmony_ci}
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci#if 0
443141cc406Sopenharmony_cistatic SANE_Status
444141cc406Sopenharmony_cimode_select_adf_fsu (int fd, int mode)
445141cc406Sopenharmony_ci{
446141cc406Sopenharmony_ci  static u_char cmd[6 + MODE_SUBDEV_LEN] =
447141cc406Sopenharmony_ci                        {MODE_SELECT6, 0x10, 0, 0, MODE_SUBDEV_LEN, 0};
448141cc406Sopenharmony_ci  mode_select_subdevice *mp;
449141cc406Sopenharmony_ci  SANE_Status status;
450141cc406Sopenharmony_ci  DBG (11, "<< mode_select_adf_fsu ");
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  mp = (mode_select_subdevice *)(cmd + 6);
453141cc406Sopenharmony_ci  memset (mp, 0, MODE_SUBDEV_LEN);
454141cc406Sopenharmony_ci  mp->page_code = 0x20;
455141cc406Sopenharmony_ci  mp->page_length = 26;
456141cc406Sopenharmony_ci  switch (mode)
457141cc406Sopenharmony_ci    {
458141cc406Sopenharmony_ci      case SCAN_SIMPLE:
459141cc406Sopenharmony_ci        mp->a_mode = 0x40;
460141cc406Sopenharmony_ci        mp->f_mode = 0x40;
461141cc406Sopenharmony_ci        break;
462141cc406Sopenharmony_ci      case SCAN_WITH_FSU:
463141cc406Sopenharmony_ci        mp->a_mode = 0;
464141cc406Sopenharmony_ci        mp->f_mode = 0x40;
465141cc406Sopenharmony_ci        break;
466141cc406Sopenharmony_ci      case SCAN_WITH_ADF:
467141cc406Sopenharmony_ci        mp->a_mode = 0x40;
468141cc406Sopenharmony_ci        mp->f_mode = 0;
469141cc406Sopenharmony_ci        break;
470141cc406Sopenharmony_ci    }
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci  DBG (11, ">>\n");
475141cc406Sopenharmony_ci  return (status);
476141cc406Sopenharmony_ci}
477141cc406Sopenharmony_ci#endif
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_cistatic SANE_Status wait_ready(int fd);
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_cistatic SANE_Status
482141cc406Sopenharmony_cimode_sense (int fd, void *modeparam_buf, size_t * modeparam_size,
483141cc406Sopenharmony_ci            int page)
484141cc406Sopenharmony_ci{
485141cc406Sopenharmony_ci  static u_char cmd[6] = {MODE_SENSE6, 0, 0, 0, 0, 0};
486141cc406Sopenharmony_ci  SANE_Status status;
487141cc406Sopenharmony_ci  DBG (11, "<< mode_sense ");
488141cc406Sopenharmony_ci  cmd[0] = 0x1a;
489141cc406Sopenharmony_ci  cmd[2] = page;
490141cc406Sopenharmony_ci  cmd[4] = *modeparam_size;
491141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), modeparam_buf,
492141cc406Sopenharmony_ci			   modeparam_size);
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci  DBG (11, ">>\n");
495141cc406Sopenharmony_ci  return (status);
496141cc406Sopenharmony_ci}
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_cistatic SANE_Status
499141cc406Sopenharmony_ciscan (int fd)
500141cc406Sopenharmony_ci{
501141cc406Sopenharmony_ci  static u_char cmd[] = {SCAN, 0, 0, 0, 0, 0};
502141cc406Sopenharmony_ci  SANE_Status status;
503141cc406Sopenharmony_ci  DBG (11, "<< scan ");
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  DBG (11, ">>\n");
508141cc406Sopenharmony_ci  return (status);
509141cc406Sopenharmony_ci}
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci#if 0
512141cc406Sopenharmony_cistatic SANE_Status
513141cc406Sopenharmony_cisend_diagnostics (int fd)
514141cc406Sopenharmony_ci{
515141cc406Sopenharmony_ci  static u_char cmd[] = {SEND_DIAGNOSTIC, 0x04, 0, 0, 0, 0};
516141cc406Sopenharmony_ci  SANE_Status status;
517141cc406Sopenharmony_ci  DBG (11, "<< send_diagnostics ");
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci  DBG (11, ">>\n");
522141cc406Sopenharmony_ci  return (status);
523141cc406Sopenharmony_ci}
524141cc406Sopenharmony_ci#endif
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_cistatic SANE_Status
527141cc406Sopenharmony_ciset_window (int fd, window_param *wp, int len)
528141cc406Sopenharmony_ci{
529141cc406Sopenharmony_ci  static u_char cmd[10 + WINDOW_LEN] =
530141cc406Sopenharmony_ci                        {SET_WINDOW, 0, 0, 0, 0, 0, 0, 0, 0, 0};
531141cc406Sopenharmony_ci  window_param *winp;
532141cc406Sopenharmony_ci  SANE_Status status;
533141cc406Sopenharmony_ci  DBG (11, "<< set_window ");
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  cmd[8] = len;
536141cc406Sopenharmony_ci  winp = (window_param *)(cmd + 10);
537141cc406Sopenharmony_ci  memset (winp, 0, WINDOW_LEN);
538141cc406Sopenharmony_ci  memcpy (winp, wp, len);
539141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci  DBG (11, ">>\n");
542141cc406Sopenharmony_ci  return (status);
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci}
545141cc406Sopenharmony_ci
546141cc406Sopenharmony_cistatic SANE_Status
547141cc406Sopenharmony_ciget_window (int fd, void *buf, size_t * buf_size)
548141cc406Sopenharmony_ci{
549141cc406Sopenharmony_ci  static u_char cmd[10] = {GET_WINDOW, 0, 0, 0, 0, 0, 0, 0, WINDOW_LEN, 0};
550141cc406Sopenharmony_ci  SANE_Status status;
551141cc406Sopenharmony_ci  DBG (11, "<< get_window ");
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_ci  cmd[8] = *buf_size;
554141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size);
555141cc406Sopenharmony_ci
556141cc406Sopenharmony_ci  DBG (11, ">>\n");
557141cc406Sopenharmony_ci  return (status);
558141cc406Sopenharmony_ci}
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci#if 0
561141cc406Sopenharmony_cistatic SANE_Status
562141cc406Sopenharmony_ciget_data_buffer_status (int fd, void *buf, size_t *buf_size)
563141cc406Sopenharmony_ci{
564141cc406Sopenharmony_ci  static u_char cmd[10] =
565141cc406Sopenharmony_ci                        {GET_DATA_BUFFER_STATUS, 0, 0, 0, 0, 0, 0, 0, 0, 0};
566141cc406Sopenharmony_ci  SANE_Status status;
567141cc406Sopenharmony_ci  DBG (11, "<< get_data_buffer_status ");
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci  cmd[8] = *buf_size;
570141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size);
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci  DBG (11, ">>\n");
573141cc406Sopenharmony_ci  return (status);
574141cc406Sopenharmony_ci}
575141cc406Sopenharmony_ci#endif
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci#ifdef USE_FORK
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci/* the following four functions serve simply the purpose
580141cc406Sopenharmony_ci   to avoid "over-optimised" code when reader_process and
581141cc406Sopenharmony_ci   read_data wait for the buffer to become ready. The simple
582141cc406Sopenharmony_ci   while-loops in these functions which check the buffer
583141cc406Sopenharmony_ci   status may be optimised so that the machine code only
584141cc406Sopenharmony_ci   operates with registers instead of using the variable
585141cc406Sopenharmony_ci   values stored in memory. (This is only a workaround -
586141cc406Sopenharmony_ci   it would be better to set a compiler pragma, which ensures
587141cc406Sopenharmony_ci   that the program looks into the RAM in these while loops --
588141cc406Sopenharmony_ci   but unfortunately I could not find appropriate information
589141cc406Sopenharmony_ci   about this at least for gcc, not to speak about other
590141cc406Sopenharmony_ci   compilers...
591141cc406Sopenharmony_ci   Abel)
592141cc406Sopenharmony_ci*/
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_cistatic int
595141cc406Sopenharmony_cicancel_requested(NEC_Scanner *s)
596141cc406Sopenharmony_ci{
597141cc406Sopenharmony_ci  return s->rdr_ctl->cancel;
598141cc406Sopenharmony_ci}
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_cistatic SANE_Status
601141cc406Sopenharmony_cirdr_status(NEC_Scanner *s)
602141cc406Sopenharmony_ci{
603141cc406Sopenharmony_ci  return s->rdr_ctl->status;
604141cc406Sopenharmony_ci}
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_cistatic int
607141cc406Sopenharmony_cibuf_status(NEC_shmem_ctl *s)
608141cc406Sopenharmony_ci{
609141cc406Sopenharmony_ci  return s->shm_status;
610141cc406Sopenharmony_ci}
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_cistatic int
613141cc406Sopenharmony_cireader_running(NEC_Scanner *s)
614141cc406Sopenharmony_ci{
615141cc406Sopenharmony_ci  return s->rdr_ctl->running;
616141cc406Sopenharmony_ci}
617141cc406Sopenharmony_ci
618141cc406Sopenharmony_cistatic int
619141cc406Sopenharmony_cireader_process(NEC_Scanner *s)
620141cc406Sopenharmony_ci{
621141cc406Sopenharmony_ci  SANE_Status status;
622141cc406Sopenharmony_ci  sigset_t sigterm_set;
623141cc406Sopenharmony_ci  static u_char cmd[] = {READ, 0, 0, 0, 0, 0, 0, 0, 0, 0};
624141cc406Sopenharmony_ci  int full_count = 0, counted;
625141cc406Sopenharmony_ci  size_t waitindex, cmdindex;
626141cc406Sopenharmony_ci  size_t bytes_to_queue;
627141cc406Sopenharmony_ci  size_t nread;
628141cc406Sopenharmony_ci  size_t max_bytes_per_read;
629141cc406Sopenharmony_ci  int max_queue;
630141cc406Sopenharmony_ci  int i;
631141cc406Sopenharmony_ci  NEC_shmem_ctl *bc;
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_ci  s->rdr_ctl->running = 1;
634141cc406Sopenharmony_ci  DBG(11, "<< reader_process\n");
635141cc406Sopenharmony_ci
636141cc406Sopenharmony_ci  sigemptyset (&sigterm_set);
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci  bytes_to_queue = s->bytes_to_read;
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci  max_bytes_per_read = s->dev->info.bufsize / s->params.bytes_per_line;
641141cc406Sopenharmony_ci  if (max_bytes_per_read)
642141cc406Sopenharmony_ci    max_bytes_per_read *= s->params.bytes_per_line;
643141cc406Sopenharmony_ci  else
644141cc406Sopenharmony_ci    /* this is a really tiny buffer..*/
645141cc406Sopenharmony_ci    max_bytes_per_read = s->dev->info.bufsize;
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci  /*  wait_ready(s->fd); */
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci  if (s->dev->info.queued_reads <= s->dev->info.buffers)
650141cc406Sopenharmony_ci    max_queue = s->dev->info.queued_reads;
651141cc406Sopenharmony_ci  else
652141cc406Sopenharmony_ci    max_queue = s->dev->info.buffers;
653141cc406Sopenharmony_ci  for (i = 0; i < max_queue; i++)
654141cc406Sopenharmony_ci    {
655141cc406Sopenharmony_ci      bc = &s->rdr_ctl->buf_ctl[i];
656141cc406Sopenharmony_ci      if (bytes_to_queue)
657141cc406Sopenharmony_ci        {
658141cc406Sopenharmony_ci          nread = bytes_to_queue;
659141cc406Sopenharmony_ci          if (nread > max_bytes_per_read)
660141cc406Sopenharmony_ci            nread = max_bytes_per_read;
661141cc406Sopenharmony_ci          bc->used = nread;
662141cc406Sopenharmony_ci          cmd[6] = nread >> 16;
663141cc406Sopenharmony_ci          cmd[7] = nread >> 8;
664141cc406Sopenharmony_ci          cmd[8] = nread;
665141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
666141cc406Sopenharmony_ci          DBG(2, "reader: req_enter...\n");
667141cc406Sopenharmony_ci#endif
668141cc406Sopenharmony_ci          status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd),
669141cc406Sopenharmony_ci                     bc->buffer,
670141cc406Sopenharmony_ci                    &bc->used,
671141cc406Sopenharmony_ci                    &bc->qid);
672141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
673141cc406Sopenharmony_ci          DBG(2, "reader: req_enter ok\n");
674141cc406Sopenharmony_ci#endif
675141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
676141cc406Sopenharmony_ci            {
677141cc406Sopenharmony_ci              DBG(1, "reader_process: read command failed: %s",
678141cc406Sopenharmony_ci                  sane_strstatus(status));
679141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
680141cc406Sopenharmony_ci              sanei_scsi_req_flush_all_extended(s->fd);
681141cc406Sopenharmony_ci#else
682141cc406Sopenharmony_ci               sanei_scsi_req_flush_all();
683141cc406Sopenharmony_ci#endif
684141cc406Sopenharmony_ci              s->rdr_ctl->status = status;
685141cc406Sopenharmony_ci              s->rdr_ctl->running = 0;
686141cc406Sopenharmony_ci              return 2;
687141cc406Sopenharmony_ci            }
688141cc406Sopenharmony_ci          bc->shm_status = SHM_BUSY;
689141cc406Sopenharmony_ci          bc->nreq = bc->used;
690141cc406Sopenharmony_ci          bytes_to_queue -= bc->nreq;
691141cc406Sopenharmony_ci        }
692141cc406Sopenharmony_ci      else
693141cc406Sopenharmony_ci        {
694141cc406Sopenharmony_ci          bc->used = 0;
695141cc406Sopenharmony_ci          bc->shm_status = SHM_EMPTY;
696141cc406Sopenharmony_ci        }
697141cc406Sopenharmony_ci    }
698141cc406Sopenharmony_ci  waitindex = 0;
699141cc406Sopenharmony_ci  cmdindex = i % s->dev->info.buffers;
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci  while(s->bytes_to_read > 0)
702141cc406Sopenharmony_ci    {
703141cc406Sopenharmony_ci      if (cancel_requested(s))
704141cc406Sopenharmony_ci        {
705141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
706141cc406Sopenharmony_ci          DBG(2, "reader: flushing requests...\n");
707141cc406Sopenharmony_ci#endif
708141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
709141cc406Sopenharmony_ci          sanei_scsi_req_flush_all_extended(s->fd);
710141cc406Sopenharmony_ci#else
711141cc406Sopenharmony_ci          sanei_scsi_req_flush_all();
712141cc406Sopenharmony_ci#endif
713141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
714141cc406Sopenharmony_ci          DBG(2, "reader: flushing requests ok\n");
715141cc406Sopenharmony_ci#endif
716141cc406Sopenharmony_ci          s->rdr_ctl->cancel = 0;
717141cc406Sopenharmony_ci          s->rdr_ctl->status = SANE_STATUS_CANCELLED;
718141cc406Sopenharmony_ci          s->rdr_ctl->running = 0;
719141cc406Sopenharmony_ci          DBG(11, " reader_process (cancelled) >>\n");
720141cc406Sopenharmony_ci          return 1;
721141cc406Sopenharmony_ci        }
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci      bc = &s->rdr_ctl->buf_ctl[waitindex];
724141cc406Sopenharmony_ci      if (bc->shm_status == SHM_BUSY)
725141cc406Sopenharmony_ci        {
726141cc406Sopenharmony_ci#ifdef DEBUG
727141cc406Sopenharmony_ci          {
728141cc406Sopenharmony_ci            struct timeval t;
729141cc406Sopenharmony_ci            gettimeofday(&t, 0);
730141cc406Sopenharmony_ci            DBG(2, "rd: waiting for data %li.%06li\n", t.tv_sec, t.tv_usec);
731141cc406Sopenharmony_ci          }
732141cc406Sopenharmony_ci#endif
733141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
734141cc406Sopenharmony_ci          DBG(2, "reader: req_wait...\n");
735141cc406Sopenharmony_ci#endif
736141cc406Sopenharmony_ci          status = sanei_scsi_req_wait(bc->qid);
737141cc406Sopenharmony_ci#ifdef QUEUEDEBUG
738141cc406Sopenharmony_ci          DBG(2, "reader: req_wait ok\n");
739141cc406Sopenharmony_ci#endif
740141cc406Sopenharmony_ci#ifdef DEBUG
741141cc406Sopenharmony_ci          {
742141cc406Sopenharmony_ci            struct timeval t;
743141cc406Sopenharmony_ci            gettimeofday(&t, 0);
744141cc406Sopenharmony_ci            DBG(2, "rd: data received    %li.%06li\n", t.tv_sec, t.tv_usec);
745141cc406Sopenharmony_ci          }
746141cc406Sopenharmony_ci#endif
747141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
748141cc406Sopenharmony_ci            {
749141cc406Sopenharmony_ci              DBG(1, "reader_process: read command failed: %s",
750141cc406Sopenharmony_ci                  sane_strstatus(status));
751141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
752141cc406Sopenharmony_ci              sanei_scsi_req_flush_all_extended(s->fd);
753141cc406Sopenharmony_ci#else
754141cc406Sopenharmony_ci              sanei_scsi_req_flush_all();
755141cc406Sopenharmony_ci#endif
756141cc406Sopenharmony_ci              s->rdr_ctl->status = status;
757141cc406Sopenharmony_ci              s->rdr_ctl->running = 0;
758141cc406Sopenharmony_ci              return 2;
759141cc406Sopenharmony_ci            }
760141cc406Sopenharmony_ci          s->bytes_to_read -= bc->used;
761141cc406Sopenharmony_ci          bytes_to_queue += bc->nreq - bc->used;
762141cc406Sopenharmony_ci          bc->start = 0;
763141cc406Sopenharmony_ci          bc->shm_status = SHM_FULL;
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci          waitindex++;
766141cc406Sopenharmony_ci          if (waitindex == s->dev->info.buffers)
767141cc406Sopenharmony_ci            waitindex = 0;
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci        }
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci      if (bytes_to_queue)
772141cc406Sopenharmony_ci        {
773141cc406Sopenharmony_ci          /* wait until the next buffer is completely read via read_data */
774141cc406Sopenharmony_ci          bc = &s->rdr_ctl->buf_ctl[cmdindex];
775141cc406Sopenharmony_ci          counted = 0;
776141cc406Sopenharmony_ci          while (buf_status(bc) != SHM_EMPTY)
777141cc406Sopenharmony_ci            {
778141cc406Sopenharmony_ci              if (!counted)
779141cc406Sopenharmony_ci                {
780141cc406Sopenharmony_ci                  counted = 1;
781141cc406Sopenharmony_ci                  full_count++;
782141cc406Sopenharmony_ci                }
783141cc406Sopenharmony_ci              if (cancel_requested(s))
784141cc406Sopenharmony_ci                {
785141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
786141cc406Sopenharmony_ci                  sanei_scsi_req_flush_all_extended(s->fd);
787141cc406Sopenharmony_ci#else
788141cc406Sopenharmony_ci                  sanei_scsi_req_flush_all();
789141cc406Sopenharmony_ci#endif
790141cc406Sopenharmony_ci                  s->rdr_ctl->cancel = 0;
791141cc406Sopenharmony_ci                  s->rdr_ctl->status = SANE_STATUS_CANCELLED;
792141cc406Sopenharmony_ci                  s->rdr_ctl->running = 0;
793141cc406Sopenharmony_ci                  DBG(11, " reader_process (cancelled) >>\n");
794141cc406Sopenharmony_ci                  return 1;
795141cc406Sopenharmony_ci                }
796141cc406Sopenharmony_ci            }
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci          nread = bytes_to_queue;
799141cc406Sopenharmony_ci          if (nread > max_bytes_per_read)
800141cc406Sopenharmony_ci            nread = max_bytes_per_read;
801141cc406Sopenharmony_ci          bc->used = nread;
802141cc406Sopenharmony_ci          cmd[6] = nread >> 16;
803141cc406Sopenharmony_ci          cmd[7] = nread >> 8;
804141cc406Sopenharmony_ci          cmd[8] = nread;
805141cc406Sopenharmony_ci          status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd),
806141cc406Sopenharmony_ci                    bc->buffer, &bc->used, &bc->qid);
807141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
808141cc406Sopenharmony_ci            {
809141cc406Sopenharmony_ci              DBG(1, "reader_process: read command failed: %s",
810141cc406Sopenharmony_ci                  sane_strstatus(status));
811141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
812141cc406Sopenharmony_ci              sanei_scsi_req_flush_all_extended(s->fd);
813141cc406Sopenharmony_ci#else
814141cc406Sopenharmony_ci              sanei_scsi_req_flush_all();
815141cc406Sopenharmony_ci#endif
816141cc406Sopenharmony_ci              s->rdr_ctl->status = status;
817141cc406Sopenharmony_ci              s->rdr_ctl->running = 0;
818141cc406Sopenharmony_ci              return 2;
819141cc406Sopenharmony_ci            }
820141cc406Sopenharmony_ci          bc->shm_status = SHM_BUSY;
821141cc406Sopenharmony_ci          bc->nreq = nread;
822141cc406Sopenharmony_ci          bytes_to_queue -= nread;
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci          cmdindex++;
825141cc406Sopenharmony_ci          if (cmdindex == s->dev->info.buffers)
826141cc406Sopenharmony_ci            cmdindex = 0;
827141cc406Sopenharmony_ci        }
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci      if (cancel_requested(s))
830141cc406Sopenharmony_ci        {
831141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
832141cc406Sopenharmony_ci          sanei_scsi_req_flush_all_extended(s->fd);
833141cc406Sopenharmony_ci#else
834141cc406Sopenharmony_ci          sanei_scsi_req_flush_all();
835141cc406Sopenharmony_ci#endif
836141cc406Sopenharmony_ci          s->rdr_ctl->cancel = 0;
837141cc406Sopenharmony_ci          s->rdr_ctl->status = SANE_STATUS_CANCELLED;
838141cc406Sopenharmony_ci          s->rdr_ctl->running = 0;
839141cc406Sopenharmony_ci          DBG(11, " reader_process (cancelled) >>\n");
840141cc406Sopenharmony_ci          return 1;
841141cc406Sopenharmony_ci        }
842141cc406Sopenharmony_ci    }
843141cc406Sopenharmony_ci
844141cc406Sopenharmony_ci  DBG(1, "buffer full conditions: %i\n", full_count);
845141cc406Sopenharmony_ci  DBG(11, " reader_process>>\n");
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci  s->rdr_ctl->running = 0;
848141cc406Sopenharmony_ci  return 0;
849141cc406Sopenharmony_ci}
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_cistatic SANE_Status
852141cc406Sopenharmony_ciread_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size)
853141cc406Sopenharmony_ci{
854141cc406Sopenharmony_ci  size_t copysize, copied = 0;
855141cc406Sopenharmony_ci  NEC_shmem_ctl *bc;
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci  DBG(11, "<< read_data ");
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci  bc = &s->rdr_ctl->buf_ctl[s->read_buff];
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci  while (copied < *buf_size)
862141cc406Sopenharmony_ci    {
863141cc406Sopenharmony_ci      /* wait until the reader process delivers data or a scanner error occurs: */
864141cc406Sopenharmony_ci      while (   buf_status(bc) != SHM_FULL
865141cc406Sopenharmony_ci             && rdr_status(s) == SANE_STATUS_GOOD)
866141cc406Sopenharmony_ci        {
867141cc406Sopenharmony_ci          usleep(10); /* could perhaps be longer. make this user configurable?? */
868141cc406Sopenharmony_ci        }
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci      if (rdr_status(s) != SANE_STATUS_GOOD)
871141cc406Sopenharmony_ci        {
872141cc406Sopenharmony_ci          return rdr_status(s);
873141cc406Sopenharmony_ci          DBG(11, ">>\n");
874141cc406Sopenharmony_ci        }
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci      copysize = bc->used - bc->start;
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci      if (copysize > *buf_size - copied )
879141cc406Sopenharmony_ci        copysize = *buf_size - copied;
880141cc406Sopenharmony_ci
881141cc406Sopenharmony_ci      memcpy(buf, &(bc->buffer[bc->start]), copysize);
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci      copied += copysize;
884141cc406Sopenharmony_ci      buf = &buf[copysize];
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ci      bc->start += copysize;
887141cc406Sopenharmony_ci      if (bc->start >= bc->used)
888141cc406Sopenharmony_ci        {
889141cc406Sopenharmony_ci          bc->start = 0;
890141cc406Sopenharmony_ci          bc->shm_status = SHM_EMPTY;
891141cc406Sopenharmony_ci          s->read_buff++;
892141cc406Sopenharmony_ci          if (s->read_buff == s->dev->info.buffers)
893141cc406Sopenharmony_ci            s->read_buff = 0;
894141cc406Sopenharmony_ci          bc = &s->rdr_ctl->buf_ctl[s->read_buff];
895141cc406Sopenharmony_ci        }
896141cc406Sopenharmony_ci    }
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci  DBG(11, ">>\n");
899141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
900141cc406Sopenharmony_ci}
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_ci#else /* don't USE_FORK: */
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_cistatic SANE_Status
905141cc406Sopenharmony_ciread_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size)
906141cc406Sopenharmony_ci{
907141cc406Sopenharmony_ci  static u_char cmd[] = {READ, 0, 0, 0, 0, 0, 0, 0, 0, 0};
908141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
909141cc406Sopenharmony_ci  size_t remain = *buf_size;
910141cc406Sopenharmony_ci  size_t nread;
911141cc406Sopenharmony_ci  DBG (11, "<< read_data ");
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  /* sane_read_shuffled requires that read_data returns
914141cc406Sopenharmony_ci     exactly *buf_size bytes, so it must be guaranteed here.
915141cc406Sopenharmony_ci     Further make sure that not more bytes are read in than
916141cc406Sopenharmony_ci     sanei_scsi_max_request_size allows, to avoid a failure
917141cc406Sopenharmony_ci     of the read command
918141cc406Sopenharmony_ci  */
919141cc406Sopenharmony_ci  while (remain > 0)
920141cc406Sopenharmony_ci    {
921141cc406Sopenharmony_ci      nread = remain;
922141cc406Sopenharmony_ci      if (nread > s->dev->info.bufsize)
923141cc406Sopenharmony_ci        nread = s->dev->info.bufsize;
924141cc406Sopenharmony_ci      cmd[6] = nread >> 16;
925141cc406Sopenharmony_ci      cmd[7] = nread >> 8;
926141cc406Sopenharmony_ci      cmd[8] = nread;
927141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd),
928141cc406Sopenharmony_ci                 &buf[*buf_size - remain], &nread);
929141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
930141cc406Sopenharmony_ci        {
931141cc406Sopenharmony_ci          DBG(11, ">>\n");
932141cc406Sopenharmony_ci          return(status);
933141cc406Sopenharmony_ci        }
934141cc406Sopenharmony_ci      remain -= nread;
935141cc406Sopenharmony_ci    }
936141cc406Sopenharmony_ci  DBG (11, ">>\n");
937141cc406Sopenharmony_ci  return (status);
938141cc406Sopenharmony_ci}
939141cc406Sopenharmony_ci#endif
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_cistatic size_t
942141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
943141cc406Sopenharmony_ci{
944141cc406Sopenharmony_ci  size_t size, max_size = 0;
945141cc406Sopenharmony_ci  int i;
946141cc406Sopenharmony_ci  DBG (10, "<< max_string_size ");
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
949141cc406Sopenharmony_ci    {
950141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
951141cc406Sopenharmony_ci      if (size > max_size)
952141cc406Sopenharmony_ci	max_size = size;
953141cc406Sopenharmony_ci    }
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci  DBG (10, ">>\n");
956141cc406Sopenharmony_ci  return max_size;
957141cc406Sopenharmony_ci}
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_cistatic SANE_Status
960141cc406Sopenharmony_ciwait_ready(int fd)
961141cc406Sopenharmony_ci{
962141cc406Sopenharmony_ci  SANE_Status status;
963141cc406Sopenharmony_ci  int retry = 0;
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci  while ((status = test_unit_ready (fd)) != SANE_STATUS_GOOD)
966141cc406Sopenharmony_ci  {
967141cc406Sopenharmony_ci    DBG (5, "wait_ready failed (%d)\n", retry);
968141cc406Sopenharmony_ci    DBG (5, "wait_ready status = (%d)\n", status);
969141cc406Sopenharmony_ci    if (retry++ > 15){
970141cc406Sopenharmony_ci	return SANE_STATUS_IO_ERROR;
971141cc406Sopenharmony_ci    }
972141cc406Sopenharmony_ci    sleep(3);
973141cc406Sopenharmony_ci  }
974141cc406Sopenharmony_ci  return (status);
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci}
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_cistatic SANE_Status
979141cc406Sopenharmony_ciattach (const char *devnam, NEC_Device ** devp)
980141cc406Sopenharmony_ci{
981141cc406Sopenharmony_ci  SANE_Status status;
982141cc406Sopenharmony_ci  NEC_Device *dev;
983141cc406Sopenharmony_ci  NEC_Sense_Data sensedat;
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  int fd;
986141cc406Sopenharmony_ci  unsigned char inquiry_data[INQUIRY_LEN];
987141cc406Sopenharmony_ci  const unsigned char *model_name;
988141cc406Sopenharmony_ci  mode_sense_param msp;
989141cc406Sopenharmony_ci  size_t buf_size;
990141cc406Sopenharmony_ci  DBG (10, "<< attach ");
991141cc406Sopenharmony_ci
992141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
993141cc406Sopenharmony_ci    {
994141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devnam) == 0)
995141cc406Sopenharmony_ci	{
996141cc406Sopenharmony_ci	  if (devp)
997141cc406Sopenharmony_ci	    *devp = dev;
998141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
999141cc406Sopenharmony_ci	}
1000141cc406Sopenharmony_ci    }
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci  sensedat.model = unknown;
1003141cc406Sopenharmony_ci  sensedat.complain_on_adf_error = 0;
1004141cc406Sopenharmony_ci  DBG (3, "attach: opening %s\n", devnam);
1005141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
1006141cc406Sopenharmony_ci  {
1007141cc406Sopenharmony_ci    int bufsize = 4096;
1008141cc406Sopenharmony_ci    status = sanei_scsi_open_extended (devnam, &fd, &sense_handler, &sensedat, &bufsize);
1009141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
1010141cc406Sopenharmony_ci      {
1011141cc406Sopenharmony_ci        DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
1012141cc406Sopenharmony_ci        return (status);
1013141cc406Sopenharmony_ci      }
1014141cc406Sopenharmony_ci    if (bufsize < 4096)
1015141cc406Sopenharmony_ci      {
1016141cc406Sopenharmony_ci        DBG(1, "attach: open failed. no memory\n");
1017141cc406Sopenharmony_ci        sanei_scsi_close(fd);
1018141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
1019141cc406Sopenharmony_ci      }
1020141cc406Sopenharmony_ci  }
1021141cc406Sopenharmony_ci#else
1022141cc406Sopenharmony_ci  status = sanei_scsi_open (devnam, &fd, &sense_handler, &sensedat);
1023141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1024141cc406Sopenharmony_ci    {
1025141cc406Sopenharmony_ci      DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
1026141cc406Sopenharmony_ci      return (status);
1027141cc406Sopenharmony_ci    }
1028141cc406Sopenharmony_ci#endif
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  DBG (3, "attach: sending INQUIRY\n");
1031141cc406Sopenharmony_ci  memset (inquiry_data, 0, sizeof (inquiry_data));
1032141cc406Sopenharmony_ci  buf_size = sizeof (inquiry_data);
1033141cc406Sopenharmony_ci  status = inquiry (fd, inquiry_data, &buf_size);
1034141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1035141cc406Sopenharmony_ci    {
1036141cc406Sopenharmony_ci      DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
1037141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1038141cc406Sopenharmony_ci      return (status);
1039141cc406Sopenharmony_ci    }
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci  if (inquiry_data[0] == 6 && strncmp ((char *)inquiry_data + 8, "NEC", 3) == 0)
1042141cc406Sopenharmony_ci    {
1043141cc406Sopenharmony_ci      if (strncmp ((char *)inquiry_data + 16, "PC-IN500/4C", 11) == 0)
1044141cc406Sopenharmony_ci        sensedat.model = PCIN500;
1045141cc406Sopenharmony_ci      else
1046141cc406Sopenharmony_ci        sensedat.model = unknown;
1047141cc406Sopenharmony_ci    }
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_ci  if (sensedat.model == unknown)
1050141cc406Sopenharmony_ci    {
1051141cc406Sopenharmony_ci      DBG (1, "attach: device doesn't look like a NEC scanner\n");
1052141cc406Sopenharmony_ci      DBG (1, "      : Only PC-IN500/4C is supported.\n");
1053141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1054141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
1055141cc406Sopenharmony_ci    }
1056141cc406Sopenharmony_ci
1057141cc406Sopenharmony_ci  DBG (3, "attach: sending TEST_UNIT_READY\n");
1058141cc406Sopenharmony_ci  status = test_unit_ready (fd);
1059141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1060141cc406Sopenharmony_ci    {
1061141cc406Sopenharmony_ci      DBG (1, "attach: test unit ready failed (%s)\n",
1062141cc406Sopenharmony_ci	   sane_strstatus (status));
1063141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1064141cc406Sopenharmony_ci      return (status);
1065141cc406Sopenharmony_ci    }
1066141cc406Sopenharmony_ci  DBG (3, "attach: sending MODE SELECT\n");
1067141cc406Sopenharmony_ci
1068141cc406Sopenharmony_ci  if (sensedat.model == PCIN500)
1069141cc406Sopenharmony_ci    status = mode_select_mud (fd, DEFAULT_MUD_1200);
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1072141cc406Sopenharmony_ci    {
1073141cc406Sopenharmony_ci      DBG (1, "attach: MODE_SELECT_MUD failed\n");
1074141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1075141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
1076141cc406Sopenharmony_ci    }
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci  DBG (3, "attach: sending MODE SENSE/MUP page\n");
1079141cc406Sopenharmony_ci  memset (&msp, 0, sizeof (msp));
1080141cc406Sopenharmony_ci  buf_size = sizeof (msp);
1081141cc406Sopenharmony_ci  status = mode_sense (fd, &msp, &buf_size, 3);
1082141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1083141cc406Sopenharmony_ci    {
1084141cc406Sopenharmony_ci      DBG (1, "attach: MODE_SENSE/MUP page failed\n");
1085141cc406Sopenharmony_ci      sanei_scsi_close (fd);
1086141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
1087141cc406Sopenharmony_ci    }
1088141cc406Sopenharmony_ci#ifdef DEBUG_NEC
1089141cc406Sopenharmony_ci  DBG (3,"attach: MODE SENSE parameter\n");
1090141cc406Sopenharmony_ci      DBG(11, "%02x %02x %02x %02x "
1091141cc406Sopenharmony_ci              "%02x %02x %02x %02x %02x %02x %02x %02x\n",
1092141cc406Sopenharmony_ci              msp.mode_data_length,
1093141cc406Sopenharmony_ci	      msp.mode_param_header2,
1094141cc406Sopenharmony_ci	      msp.mode_param_header3,
1095141cc406Sopenharmony_ci	      msp.mode_desciptor_length,
1096141cc406Sopenharmony_ci	      msp.page_code,
1097141cc406Sopenharmony_ci	      msp.page_length,
1098141cc406Sopenharmony_ci	      msp.bmu,
1099141cc406Sopenharmony_ci	      msp.res2,
1100141cc406Sopenharmony_ci	      msp.mud[0],
1101141cc406Sopenharmony_ci	      msp.mud[1],
1102141cc406Sopenharmony_ci	      msp.res3,
1103141cc406Sopenharmony_ci	      msp.res4);
1104141cc406Sopenharmony_ci#endif
1105141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
1106141cc406Sopenharmony_ci  if (!dev)
1107141cc406Sopenharmony_ci    return (SANE_STATUS_NO_MEM);
1108141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci  dev->sane.name = (SANE_String) strdup (devnam);
1111141cc406Sopenharmony_ci  dev->sane.vendor = "NEC";
1112141cc406Sopenharmony_ci  model_name = inquiry_data + 16;
1113141cc406Sopenharmony_ci  dev->sane.model  = strndup ((const char *)model_name, 10);
1114141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci  dev->sensedat.model = sensedat.model;
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_ci  DBG (5, "dev->sane.name = %s\n", dev->sane.name);
1119141cc406Sopenharmony_ci  DBG (5, "dev->sane.vendor = %s\n", dev->sane.vendor);
1120141cc406Sopenharmony_ci  DBG (5, "dev->sane.model = %s\n", dev->sane.model);
1121141cc406Sopenharmony_ci  DBG (5, "dev->sane.type = %s\n", dev->sane.type);
1122141cc406Sopenharmony_ci
1123141cc406Sopenharmony_ci  if (sensedat.model == PCIN500)
1124141cc406Sopenharmony_ci    dev->info.res_range.quant = 10;
1125141cc406Sopenharmony_ci  else
1126141cc406Sopenharmony_ci    dev->info.res_range.quant = 0;
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci  dev->info.tl_x_ranges[SCAN_SIMPLE].min = SANE_FIX(0);
1129141cc406Sopenharmony_ci  dev->info.br_x_ranges[SCAN_SIMPLE].min = SANE_FIX(1);
1130141cc406Sopenharmony_ci  dev->info.tl_y_ranges[SCAN_SIMPLE].min = SANE_FIX(0);
1131141cc406Sopenharmony_ci  dev->info.br_y_ranges[SCAN_SIMPLE].min = SANE_FIX(1);
1132141cc406Sopenharmony_ci  dev->info.tl_x_ranges[SCAN_SIMPLE].quant = SANE_FIX(0);
1133141cc406Sopenharmony_ci  dev->info.br_x_ranges[SCAN_SIMPLE].quant = SANE_FIX(0);
1134141cc406Sopenharmony_ci  dev->info.tl_y_ranges[SCAN_SIMPLE].quant = SANE_FIX(0);
1135141cc406Sopenharmony_ci  dev->info.br_y_ranges[SCAN_SIMPLE].quant = SANE_FIX(0);
1136141cc406Sopenharmony_ci
1137141cc406Sopenharmony_ci  if (sensedat.model == PCIN500)
1138141cc406Sopenharmony_ci    dev->info.res_default = 15;
1139141cc406Sopenharmony_ci  else
1140141cc406Sopenharmony_ci    dev->info.res_default = 150;
1141141cc406Sopenharmony_ci  dev->info.tl_x_ranges[SCAN_SIMPLE].max = SANE_FIX(209);
1142141cc406Sopenharmony_ci  dev->info.br_x_ranges[SCAN_SIMPLE].max = SANE_FIX(210);
1143141cc406Sopenharmony_ci  dev->info.tl_y_ranges[SCAN_SIMPLE].max = SANE_FIX(296);
1144141cc406Sopenharmony_ci  dev->info.br_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297);
1145141cc406Sopenharmony_ci
1146141cc406Sopenharmony_ci  dev->info.bmu = msp.bmu;
1147141cc406Sopenharmony_ci  dev->info.mud = (msp.mud[0] << 8) + msp.mud[1];
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci  dev->info.adf_fsu_installed = 0;
1150141cc406Sopenharmony_ci  if (dev->sensedat.model == PCIN500)
1151141cc406Sopenharmony_ci    {
1152141cc406Sopenharmony_ci      dev->info.res_range.max = 48;
1153141cc406Sopenharmony_ci      dev->info.res_range.min = 5;
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci      dev->info.x_default = SANE_FIX(210);
1156141cc406Sopenharmony_ci      dev->info.tl_x_ranges[SCAN_SIMPLE].max = SANE_FIX(210); /* 304.8mm is the real max */
1157141cc406Sopenharmony_ci      dev->info.br_x_ranges[SCAN_SIMPLE].max = SANE_FIX(210); /* 304.8mm is the real max */
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_ci      dev->info.y_default = SANE_FIX(297);
1160141cc406Sopenharmony_ci      dev->info.tl_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297); /* 431.8 is the real max */
1161141cc406Sopenharmony_ci      dev->info.br_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297); /* 431.8 is the real max */
1162141cc406Sopenharmony_ci    }
1163141cc406Sopenharmony_ci  else
1164141cc406Sopenharmony_ci    {
1165141cc406Sopenharmony_ci      dev->info.res_range.max = 400;
1166141cc406Sopenharmony_ci      dev->info.res_range.min = 50;
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci      dev->info.x_default = SANE_FIX(210);
1169141cc406Sopenharmony_ci      dev->info.tl_x_ranges[SCAN_SIMPLE].max = SANE_FIX(210); /* 304.8mm is the real max */
1170141cc406Sopenharmony_ci      dev->info.br_x_ranges[SCAN_SIMPLE].max = SANE_FIX(210); /* 304.8mm is the real max */
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_ci      dev->info.y_default = SANE_FIX(297);
1173141cc406Sopenharmony_ci      dev->info.tl_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297); /* 431.8 is the real max */
1174141cc406Sopenharmony_ci      dev->info.br_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297); /* 431.8 is the real max */
1175141cc406Sopenharmony_ci    }
1176141cc406Sopenharmony_ci  sanei_scsi_close (fd);
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  dev->info.threshold_range.min = 1;
1179141cc406Sopenharmony_ci  dev->info.threshold_range.max = 255;
1180141cc406Sopenharmony_ci  dev->info.threshold_range.quant = 0;
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci  dev->info.tint_range.min = 1;
1183141cc406Sopenharmony_ci  dev->info.tint_range.max = 255;
1184141cc406Sopenharmony_ci  dev->info.tint_range.quant = 0;
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci  dev->info.color_range.min = 1;
1187141cc406Sopenharmony_ci  dev->info.color_range.max = 255;
1188141cc406Sopenharmony_ci  dev->info.color_range.quant = 0;
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci  DBG (5, "res_default=%d\n", dev->info.res_default);
1191141cc406Sopenharmony_ci  DBG (5, "res_range.max=%d\n", dev->info.res_range.max);
1192141cc406Sopenharmony_ci  DBG (5, "res_range.min=%d\n", dev->info.res_range.min);
1193141cc406Sopenharmony_ci  DBG (5, "res_range.quant=%d\n", dev->info.res_range.quant);
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci  DBG (5, "x_default=%f\n", SANE_UNFIX(dev->info.x_default));
1196141cc406Sopenharmony_ci  DBG (5, "tl_x_range[0].max=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_SIMPLE].max));
1197141cc406Sopenharmony_ci  DBG (5, "tl_x_range[0].min=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_SIMPLE].min));
1198141cc406Sopenharmony_ci  DBG (5, "tl_x_range[0].quant=%d\n", dev->info.tl_x_ranges[SCAN_SIMPLE].quant);
1199141cc406Sopenharmony_ci  DBG (5, "br_x_range[0].max=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_SIMPLE].max));
1200141cc406Sopenharmony_ci  DBG (5, "br_x_range[0].min=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_SIMPLE].min));
1201141cc406Sopenharmony_ci  DBG (5, "br_x_range[0].quant=%d\n", dev->info.br_x_ranges[SCAN_SIMPLE].quant);
1202141cc406Sopenharmony_ci  DBG (5, "y_default=%f\n", SANE_UNFIX(dev->info.y_default));
1203141cc406Sopenharmony_ci  DBG (5, "tl_y_range[0].max=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_SIMPLE].max));
1204141cc406Sopenharmony_ci  DBG (5, "tl_y_range[0].min=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_SIMPLE].min));
1205141cc406Sopenharmony_ci  DBG (5, "tl_y_range[0].quant=%d\n", dev->info.tl_y_ranges[SCAN_SIMPLE].quant);
1206141cc406Sopenharmony_ci  DBG (5, "br_y_range[0].max=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_SIMPLE].max));
1207141cc406Sopenharmony_ci  DBG (5, "br_y_range[0].min=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_SIMPLE].min));
1208141cc406Sopenharmony_ci  DBG (5, "br_y_range[0].quant=%d\n", dev->info.br_y_ranges[SCAN_SIMPLE].quant);
1209141cc406Sopenharmony_ci
1210141cc406Sopenharmony_ci  if (dev->info.adf_fsu_installed & HAVE_FSU)
1211141cc406Sopenharmony_ci    {
1212141cc406Sopenharmony_ci      DBG (5, "tl_x_range[1].max=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_WITH_FSU].max));
1213141cc406Sopenharmony_ci      DBG (5, "tl_x_range[1].min=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_WITH_FSU].min));
1214141cc406Sopenharmony_ci      DBG (5, "tl_x_range[1].quant=%d\n", dev->info.tl_x_ranges[SCAN_WITH_FSU].quant);
1215141cc406Sopenharmony_ci      DBG (5, "br_x_range[1].max=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_WITH_FSU].max));
1216141cc406Sopenharmony_ci      DBG (5, "br_x_range[1].min=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_WITH_FSU].min));
1217141cc406Sopenharmony_ci      DBG (5, "br_x_range[1].quant=%d\n", dev->info.br_x_ranges[SCAN_WITH_FSU].quant);
1218141cc406Sopenharmony_ci      DBG (5, "tl_y_range[1].max=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_WITH_FSU].max));
1219141cc406Sopenharmony_ci      DBG (5, "tl_y_range[1].min=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_WITH_FSU].min));
1220141cc406Sopenharmony_ci      DBG (5, "tl_y_range[1].quant=%d\n", dev->info.tl_y_ranges[SCAN_WITH_FSU].quant);
1221141cc406Sopenharmony_ci      DBG (5, "br_y_range[1].max=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_WITH_FSU].max));
1222141cc406Sopenharmony_ci      DBG (5, "br_y_range[1].min=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_WITH_FSU].min));
1223141cc406Sopenharmony_ci      DBG (5, "br_y_range[1].quant=%d\n", dev->info.br_y_ranges[SCAN_WITH_FSU].quant);
1224141cc406Sopenharmony_ci    }
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci  if (dev->info.adf_fsu_installed & HAVE_ADF)
1227141cc406Sopenharmony_ci    {
1228141cc406Sopenharmony_ci      DBG (5, "tl_x_range[2].max=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_WITH_ADF].max));
1229141cc406Sopenharmony_ci      DBG (5, "tl_x_range[2].min=%f\n", SANE_UNFIX(dev->info.tl_x_ranges[SCAN_WITH_ADF].min));
1230141cc406Sopenharmony_ci      DBG (5, "tl_x_range[2].quant=%d\n", dev->info.tl_x_ranges[SCAN_WITH_ADF].quant);
1231141cc406Sopenharmony_ci      DBG (5, "br_x_range[2].max=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_WITH_ADF].max));
1232141cc406Sopenharmony_ci      DBG (5, "br_x_range[2].min=%f\n", SANE_UNFIX(dev->info.br_x_ranges[SCAN_WITH_ADF].min));
1233141cc406Sopenharmony_ci      DBG (5, "br_x_range[2].quant=%d\n", dev->info.br_x_ranges[SCAN_WITH_ADF].quant);
1234141cc406Sopenharmony_ci      DBG (5, "tl_y_range[2].max=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_WITH_ADF].max));
1235141cc406Sopenharmony_ci      DBG (5, "tl_y_range[2].min=%f\n", SANE_UNFIX(dev->info.tl_y_ranges[SCAN_WITH_ADF].min));
1236141cc406Sopenharmony_ci      DBG (5, "tl_y_range[2].quant=%d\n", dev->info.tl_y_ranges[SCAN_WITH_ADF].quant);
1237141cc406Sopenharmony_ci      DBG (5, "br_y_range[2].max=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_WITH_ADF].max));
1238141cc406Sopenharmony_ci      DBG (5, "br_y_range[2].min=%f\n", SANE_UNFIX(dev->info.br_y_ranges[SCAN_WITH_ADF].min));
1239141cc406Sopenharmony_ci      DBG (5, "br_y_range[2].quant=%d\n", dev->info.br_y_ranges[SCAN_WITH_ADF].quant);
1240141cc406Sopenharmony_ci    }
1241141cc406Sopenharmony_ci
1242141cc406Sopenharmony_ci  DBG (5, "bmu=%d\n", dev->info.bmu);
1243141cc406Sopenharmony_ci  DBG (5, "mud=%d\n", dev->info.mud);
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci  ++num_devices;
1246141cc406Sopenharmony_ci  dev->next = first_dev;
1247141cc406Sopenharmony_ci  first_dev = dev;
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci  if (devp)
1250141cc406Sopenharmony_ci    *devp = dev;
1251141cc406Sopenharmony_ci
1252141cc406Sopenharmony_ci  DBG (10, ">>\n");
1253141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
1254141cc406Sopenharmony_ci}
1255141cc406Sopenharmony_ci
1256141cc406Sopenharmony_ci/* Enabling / disabling of gamma options.
1257141cc406Sopenharmony_ci   Depends on many user settable options, so lets put it into
1258141cc406Sopenharmony_ci   one function to be called by init_options and by sane_control_option
1259141cc406Sopenharmony_ci
1260141cc406Sopenharmony_ci*/
1261141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
1262141cc406Sopenharmony_cistatic void
1263141cc406Sopenharmony_ciset_gamma_caps(NEC_Scanner *s)
1264141cc406Sopenharmony_ci{
1265141cc406Sopenharmony_ci  /* neither fixed nor custom gamma for line art modes */
1266141cc406Sopenharmony_ci  if (   strcmp(s->val[OPT_MODE].s, M_LINEART) == 0
1267141cc406Sopenharmony_ci      || strcmp(s->val[OPT_MODE].s, M_LINEART_COLOR) == 0)
1268141cc406Sopenharmony_ci    {
1269141cc406Sopenharmony_ci      s->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
1270141cc406Sopenharmony_ci      s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1271141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1272141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1273141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1274141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1275141cc406Sopenharmony_ci    }
1276141cc406Sopenharmony_ci  else if (strcmp(s->val[OPT_MODE].s, M_GRAY) == 0)
1277141cc406Sopenharmony_ci    {
1278141cc406Sopenharmony_ci      s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1279141cc406Sopenharmony_ci      if (s->val[OPT_CUSTOM_GAMMA].w == SANE_FALSE)
1280141cc406Sopenharmony_ci        {
1281141cc406Sopenharmony_ci          s->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1282141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1283141cc406Sopenharmony_ci        }
1284141cc406Sopenharmony_ci      else
1285141cc406Sopenharmony_ci        {
1286141cc406Sopenharmony_ci          s->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
1287141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1288141cc406Sopenharmony_ci        }
1289141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1290141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1291141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1292141cc406Sopenharmony_ci    }
1293141cc406Sopenharmony_ci  else
1294141cc406Sopenharmony_ci    {
1295141cc406Sopenharmony_ci      /* color mode */
1296141cc406Sopenharmony_ci      s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1297141cc406Sopenharmony_ci      if (s->val[OPT_CUSTOM_GAMMA].w == SANE_FALSE)
1298141cc406Sopenharmony_ci        {
1299141cc406Sopenharmony_ci          s->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1300141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1301141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1302141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1303141cc406Sopenharmony_ci        }
1304141cc406Sopenharmony_ci      else
1305141cc406Sopenharmony_ci        {
1306141cc406Sopenharmony_ci          s->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
1307141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1308141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1309141cc406Sopenharmony_ci          s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1310141cc406Sopenharmony_ci        }
1311141cc406Sopenharmony_ci      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1312141cc406Sopenharmony_ci    }
1313141cc406Sopenharmony_ci}
1314141cc406Sopenharmony_ci#endif /* USE_CUSTOM_GAMMA */
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci/* The next function is a slightly modified version of sanei_constrain_value
1317141cc406Sopenharmony_ci   Instead of returning status information like STATUS_INVAL, it adjusts
1318141cc406Sopenharmony_ci   an invalid value to the nearest allowed one.
1319141cc406Sopenharmony_ci*/
1320141cc406Sopenharmony_cistatic void
1321141cc406Sopenharmony_ciclip_value (const SANE_Option_Descriptor * opt, void * value)
1322141cc406Sopenharmony_ci{
1323141cc406Sopenharmony_ci  const SANE_String_Const * string_list;
1324141cc406Sopenharmony_ci  const SANE_Word * word_list;
1325141cc406Sopenharmony_ci  int i, num_matches, match;
1326141cc406Sopenharmony_ci  const SANE_Range * range;
1327141cc406Sopenharmony_ci  SANE_Word w, v;
1328141cc406Sopenharmony_ci  size_t len;
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci  switch (opt->constraint_type)
1331141cc406Sopenharmony_ci    {
1332141cc406Sopenharmony_ci    case SANE_CONSTRAINT_RANGE:
1333141cc406Sopenharmony_ci      w = *(SANE_Word *) value;
1334141cc406Sopenharmony_ci      range = opt->constraint.range;
1335141cc406Sopenharmony_ci
1336141cc406Sopenharmony_ci      if (w < range->min)
1337141cc406Sopenharmony_ci        w = range->min;
1338141cc406Sopenharmony_ci      else if (w > range->max)
1339141cc406Sopenharmony_ci	w = range->max;
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci      if (range->quant)
1342141cc406Sopenharmony_ci	{
1343141cc406Sopenharmony_ci	  v = (w - range->min + range->quant/2) / range->quant;
1344141cc406Sopenharmony_ci	  w = v * range->quant + range->min;
1345141cc406Sopenharmony_ci	  *(SANE_Word*) value = w;
1346141cc406Sopenharmony_ci	}
1347141cc406Sopenharmony_ci      break;
1348141cc406Sopenharmony_ci
1349141cc406Sopenharmony_ci    case SANE_CONSTRAINT_WORD_LIST:
1350141cc406Sopenharmony_ci      w = *(SANE_Word *) value;
1351141cc406Sopenharmony_ci      word_list = opt->constraint.word_list;
1352141cc406Sopenharmony_ci      for (i = 1; w != word_list[i]; ++i)
1353141cc406Sopenharmony_ci	if (i >= word_list[0])
1354141cc406Sopenharmony_ci	  /* somewhat arbitrary... Would be better to have a default value
1355141cc406Sopenharmony_ci	     explicitly defined.
1356141cc406Sopenharmony_ci	  */
1357141cc406Sopenharmony_ci	  *(SANE_Word*) value = word_list[1];
1358141cc406Sopenharmony_ci      break;
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci    case SANE_CONSTRAINT_STRING_LIST:
1361141cc406Sopenharmony_ci      /* Matching algorithm: take the longest unique match ignoring
1362141cc406Sopenharmony_ci	 case.  If there is an exact match, it is admissible even if
1363141cc406Sopenharmony_ci	 the same string is a prefix of a longer option name. */
1364141cc406Sopenharmony_ci      string_list = opt->constraint.string_list;
1365141cc406Sopenharmony_ci      len = strlen (value);
1366141cc406Sopenharmony_ci
1367141cc406Sopenharmony_ci      /* count how many matches of length LEN characters we have: */
1368141cc406Sopenharmony_ci      num_matches = 0;
1369141cc406Sopenharmony_ci      match = -1;
1370141cc406Sopenharmony_ci      for (i = 0; string_list[i]; ++i)
1371141cc406Sopenharmony_ci	if (strncasecmp (value, string_list[i], len) == 0
1372141cc406Sopenharmony_ci	    && len <= strlen (string_list[i]))
1373141cc406Sopenharmony_ci	  {
1374141cc406Sopenharmony_ci	    match = i;
1375141cc406Sopenharmony_ci	    if (len == strlen (string_list[i]))
1376141cc406Sopenharmony_ci	      {
1377141cc406Sopenharmony_ci		/* exact match... */
1378141cc406Sopenharmony_ci		if (strcmp (value, string_list[i]) != 0)
1379141cc406Sopenharmony_ci		  /* ...but case differs */
1380141cc406Sopenharmony_ci		  strcpy (value, string_list[match]);
1381141cc406Sopenharmony_ci	      }
1382141cc406Sopenharmony_ci	    ++num_matches;
1383141cc406Sopenharmony_ci	  }
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci      if (num_matches > 1)
1386141cc406Sopenharmony_ci        /* xxx quite arbitrary... We could also choose the first match
1387141cc406Sopenharmony_ci        */
1388141cc406Sopenharmony_ci        strcpy(value, string_list[match]);
1389141cc406Sopenharmony_ci      else if (num_matches == 1)
1390141cc406Sopenharmony_ci        strcpy (value, string_list[match]);
1391141cc406Sopenharmony_ci      else
1392141cc406Sopenharmony_ci        strcpy (value, string_list[0]);
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci    default:
1395141cc406Sopenharmony_ci      break;
1396141cc406Sopenharmony_ci    }
1397141cc406Sopenharmony_ci}
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci/* make sure that enough memory is allocated for each string,
1400141cc406Sopenharmony_ci   so that the strcpy in sane_control_option / set value cannot
1401141cc406Sopenharmony_ci   write behind the end of the allocated memory.
1402141cc406Sopenharmony_ci*/
1403141cc406Sopenharmony_cistatic SANE_Status
1404141cc406Sopenharmony_ciinit_string_option(NEC_Scanner *s, SANE_String_Const name,
1405141cc406Sopenharmony_ci   SANE_String_Const title, SANE_String_Const desc,
1406141cc406Sopenharmony_ci   const SANE_String_Const *string_list, int option, int default_index)
1407141cc406Sopenharmony_ci{
1408141cc406Sopenharmony_ci  int i;
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci  s->opt[option].name = name;
1411141cc406Sopenharmony_ci  s->opt[option].title = title;
1412141cc406Sopenharmony_ci  s->opt[option].desc = desc;
1413141cc406Sopenharmony_ci  s->opt[option].type = SANE_TYPE_STRING;
1414141cc406Sopenharmony_ci  s->opt[option].size = max_string_size (string_list);
1415141cc406Sopenharmony_ci  s->opt[option].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1416141cc406Sopenharmony_ci  s->opt[option].constraint.string_list = string_list;
1417141cc406Sopenharmony_ci  s->val[option].s = malloc(s->opt[option].size);
1418141cc406Sopenharmony_ci  if (s->val[option].s == 0)
1419141cc406Sopenharmony_ci    {
1420141cc406Sopenharmony_ci      for (i = 1; i < NUM_OPTIONS; i++)
1421141cc406Sopenharmony_ci        {
1422141cc406Sopenharmony_ci          if (s->val[i].s && s->opt[i].type == SANE_TYPE_STRING)
1423141cc406Sopenharmony_ci            free(s->val[i].s);
1424141cc406Sopenharmony_ci        }
1425141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1426141cc406Sopenharmony_ci    }
1427141cc406Sopenharmony_ci  strcpy(s->val[option].s, string_list[default_index]);
1428141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1429141cc406Sopenharmony_ci}
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_cistatic SANE_Status
1432141cc406Sopenharmony_ciinit_options (NEC_Scanner * s)
1433141cc406Sopenharmony_ci{
1434141cc406Sopenharmony_ci  int i, default_source;
1435141cc406Sopenharmony_ci  SANE_Word scalar;
1436141cc406Sopenharmony_ci  DBG (10, "<< init_options ");
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
1439141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
1440141cc406Sopenharmony_ci
1441141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
1442141cc406Sopenharmony_ci    {
1443141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
1444141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1445141cc406Sopenharmony_ci      s->val[i].s = 0;
1446141cc406Sopenharmony_ci    }
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1449141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1450141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1451141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1452141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ci  /* Mode group: */
1455141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = "Scan Mode";
1456141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
1457141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1458141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
1459141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  /* scan mode */
1462141cc406Sopenharmony_ci  init_string_option(s, SANE_NAME_SCAN_MODE, SANE_TITLE_SCAN_MODE,
1463141cc406Sopenharmony_ci    SANE_DESC_SCAN_MODE, mode_list, OPT_MODE, MODES_COLOR);
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  /* half tone */
1466141cc406Sopenharmony_ci  init_string_option(s, SANE_NAME_HALFTONE_PATTERN, SANE_TITLE_HALFTONE_PATTERN,
1467141cc406Sopenharmony_ci    SANE_DESC_HALFTONE " (not support)", halftone_list, OPT_HALFTONE, 0);
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
1470141cc406Sopenharmony_ci    s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci  i = 0;
1473141cc406Sopenharmony_ci  default_source = -1;
1474141cc406Sopenharmony_ci
1475141cc406Sopenharmony_ci  if (s->dev->info.adf_fsu_installed & HAVE_ADF)
1476141cc406Sopenharmony_ci    {
1477141cc406Sopenharmony_ci      s->dev->info.scansources[i++] = use_adf;
1478141cc406Sopenharmony_ci      default_source = SCAN_WITH_ADF;
1479141cc406Sopenharmony_ci    }
1480141cc406Sopenharmony_ci  if (s->dev->info.adf_fsu_installed & HAVE_FSU)
1481141cc406Sopenharmony_ci    {
1482141cc406Sopenharmony_ci      s->dev->info.scansources[i++] = use_fsu;
1483141cc406Sopenharmony_ci      if (default_source < 0)
1484141cc406Sopenharmony_ci        default_source = SCAN_WITH_FSU;
1485141cc406Sopenharmony_ci    }
1486141cc406Sopenharmony_ci  s->dev->info.scansources[i++] = use_simple;
1487141cc406Sopenharmony_ci    if (default_source < 0)
1488141cc406Sopenharmony_ci      default_source = SCAN_SIMPLE;
1489141cc406Sopenharmony_ci  s->dev->info.scansources[i] = 0;
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_ci  init_string_option(s, SANE_NAME_SCAN_SOURCE, SANE_TITLE_SCAN_SOURCE,
1492141cc406Sopenharmony_ci    SANE_DESC_SCAN_SOURCE, (SANE_String_Const*)s->dev->info.scansources,
1493141cc406Sopenharmony_ci    OPT_SCANSOURCE, 0);
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  if (i < 2)
1496141cc406Sopenharmony_ci    s->opt[OPT_SCANSOURCE].cap |= SANE_CAP_INACTIVE;
1497141cc406Sopenharmony_ci
1498141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
1499141cc406Sopenharmony_ci    init_string_option(s, "Paper size", "Paper size",
1500141cc406Sopenharmony_ci      "Paper size", paper_list_pcin500, OPT_PAPER, 0);
1501141cc406Sopenharmony_ci  else
1502141cc406Sopenharmony_ci    init_string_option(s, "Paper size", "Paper size",
1503141cc406Sopenharmony_ci      "Paper size", paper_list_pcinxxx, OPT_PAPER, 1);
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci  /* gamma */
1506141cc406Sopenharmony_ci  init_string_option(s, "Gamma", "Gamma", "Gamma", gamma_list, OPT_GAMMA, 0);
1507141cc406Sopenharmony_ci
1508141cc406Sopenharmony_ci  /* Resolution Group */
1509141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_GROUP].title = "Resolution";
1510141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_GROUP].desc = "";
1511141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_GROUP].type = SANE_TYPE_GROUP;
1512141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_GROUP].cap = 0;
1513141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci#ifdef USE_RESOLUTION_LIST
1516141cc406Sopenharmony_ci  /* select resolution */
1517141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
1518141cc406Sopenharmony_ci    init_string_option(s, "Resolution", "Resolution", "Resolution",
1519141cc406Sopenharmony_ci      resolution_list_pcin500, OPT_RESOLUTION_LIST, RESOLUTION_MAX_PCIN500);
1520141cc406Sopenharmony_ci  else
1521141cc406Sopenharmony_ci    init_string_option(s, "Resolution", "Resolution", "Resolution",
1522141cc406Sopenharmony_ci      resolution_list_pcinxxx, OPT_RESOLUTION_LIST, RESOLUTION_MAX_PCINXXX);
1523141cc406Sopenharmony_ci#endif
1524141cc406Sopenharmony_ci
1525141cc406Sopenharmony_ci  /* x & y resolution */
1526141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1527141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
1528141cc406Sopenharmony_ci      s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION"(x 10)";
1529141cc406Sopenharmony_ci  else
1530141cc406Sopenharmony_ci      s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1531141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1532141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1533141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1534141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
1535141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.range = &s->dev->info.res_range;
1536141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = s->dev->info.res_default;
1537141cc406Sopenharmony_ci
1538141cc406Sopenharmony_ci  /* "Geometry" group: */
1539141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
1540141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
1541141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1542141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
1543141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1544141cc406Sopenharmony_ci
1545141cc406Sopenharmony_ci  /* top-left x */
1546141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1547141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1548141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1549141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1550141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1551141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1552141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &s->dev->info.tl_x_ranges[default_source];
1553141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = s->dev->info.tl_x_ranges[default_source].min;
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  /* top-left y */
1556141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1557141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1558141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1559141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1560141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1561141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1562141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &s->dev->info.tl_y_ranges[default_source];
1563141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = s->dev->info.tl_y_ranges[default_source].min;
1564141cc406Sopenharmony_ci
1565141cc406Sopenharmony_ci  /* bottom-right x */
1566141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1567141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1568141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1569141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1570141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1571141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1572141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &s->dev->info.br_x_ranges[default_source];
1573141cc406Sopenharmony_ci  scalar = s->dev->info.x_default;
1574141cc406Sopenharmony_ci  clip_value (&s->opt[OPT_BR_X], &scalar);
1575141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = scalar;
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci  /* bottom-right y */
1578141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1579141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1580141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1581141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1582141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1583141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1584141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &s->dev->info.br_y_ranges[default_source];
1585141cc406Sopenharmony_ci  scalar = s->dev->info.y_default;
1586141cc406Sopenharmony_ci  clip_value (&s->opt[OPT_BR_X], &scalar);
1587141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = scalar;
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci  /* "Enhancement" group: */
1590141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1591141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
1592141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1593141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
1594141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1595141cc406Sopenharmony_ci
1596141cc406Sopenharmony_ci  /* edge emphasis */
1597141cc406Sopenharmony_ci  init_string_option(s, "Edge emphasis", "Edge emphasis",
1598141cc406Sopenharmony_ci    "Edge emphasis", edge_emphasis_list,
1599141cc406Sopenharmony_ci    OPT_EDGE_EMPHASIS, 0);
1600141cc406Sopenharmony_ci
1601141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
1602141cc406Sopenharmony_ci    s->opt[OPT_EDGE_EMPHASIS].cap |= SANE_CAP_INACTIVE;
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci  /* OR */
1605141cc406Sopenharmony_ci  s->opt[OPT_OR].name = "OR";
1606141cc406Sopenharmony_ci  s->opt[OPT_OR].title = "OR";
1607141cc406Sopenharmony_ci  s->opt[OPT_OR].desc = "Select OR emphancement";
1608141cc406Sopenharmony_ci  s->opt[OPT_OR].type = SANE_TYPE_BOOL;
1609141cc406Sopenharmony_ci  s->val[OPT_OR].w = SANE_FALSE;
1610141cc406Sopenharmony_ci
1611141cc406Sopenharmony_ci  /* EDGE */
1612141cc406Sopenharmony_ci  s->opt[OPT_EDGE].name = "edge";
1613141cc406Sopenharmony_ci  s->opt[OPT_EDGE].title = "Edge";
1614141cc406Sopenharmony_ci  s->opt[OPT_EDGE].desc = "Select Edge emphancement";
1615141cc406Sopenharmony_ci  s->opt[OPT_EDGE].type = SANE_TYPE_BOOL;
1616141cc406Sopenharmony_ci  s->val[OPT_EDGE].w = SANE_FALSE;
1617141cc406Sopenharmony_ci
1618141cc406Sopenharmony_ci  /* NR */
1619141cc406Sopenharmony_ci  s->opt[OPT_NR].name = "NR";
1620141cc406Sopenharmony_ci  s->opt[OPT_NR].title = "NR";
1621141cc406Sopenharmony_ci  s->opt[OPT_NR].desc = "Select noise reduction";
1622141cc406Sopenharmony_ci  s->opt[OPT_NR].type = SANE_TYPE_BOOL;
1623141cc406Sopenharmony_ci  s->val[OPT_NR].w = SANE_FALSE;
1624141cc406Sopenharmony_ci
1625141cc406Sopenharmony_ci  if (s->dev->sensedat.model != PCIN500)
1626141cc406Sopenharmony_ci    {
1627141cc406Sopenharmony_ci      s->opt[OPT_EDGE].cap |= SANE_CAP_INACTIVE;
1628141cc406Sopenharmony_ci      s->opt[OPT_NR].cap |= SANE_CAP_INACTIVE;
1629141cc406Sopenharmony_ci      s->opt[OPT_OR].cap |= SANE_CAP_INACTIVE;
1630141cc406Sopenharmony_ci    }
1631141cc406Sopenharmony_ci  /* tint */
1632141cc406Sopenharmony_ci  s->opt[OPT_TINT].name = "tint";
1633141cc406Sopenharmony_ci  s->opt[OPT_TINT].title = "Tint";
1634141cc406Sopenharmony_ci  s->opt[OPT_TINT].desc = "Select tint";
1635141cc406Sopenharmony_ci  s->opt[OPT_TINT].type = SANE_TYPE_INT;
1636141cc406Sopenharmony_ci  s->opt[OPT_TINT].unit = SANE_UNIT_NONE;
1637141cc406Sopenharmony_ci  s->opt[OPT_TINT].constraint_type = SANE_CONSTRAINT_RANGE;
1638141cc406Sopenharmony_ci  s->opt[OPT_TINT].constraint.range = &s->dev->info.tint_range;
1639141cc406Sopenharmony_ci  s->val[OPT_TINT].w = 128;
1640141cc406Sopenharmony_ci  if (s->dev->sensedat.model != PCIN500)
1641141cc406Sopenharmony_ci    s->opt[OPT_TINT].cap |= SANE_CAP_INACTIVE;
1642141cc406Sopenharmony_ci
1643141cc406Sopenharmony_ci  /* color */
1644141cc406Sopenharmony_ci  s->opt[OPT_COLOR].name = "color";
1645141cc406Sopenharmony_ci  s->opt[OPT_COLOR].title = "Color";
1646141cc406Sopenharmony_ci  s->opt[OPT_COLOR].desc = "Select color";
1647141cc406Sopenharmony_ci  s->opt[OPT_COLOR].type = SANE_TYPE_INT;
1648141cc406Sopenharmony_ci  s->opt[OPT_COLOR].unit = SANE_UNIT_NONE;
1649141cc406Sopenharmony_ci  s->opt[OPT_COLOR].constraint_type = SANE_CONSTRAINT_RANGE;
1650141cc406Sopenharmony_ci  s->opt[OPT_COLOR].constraint.range = &s->dev->info.color_range;
1651141cc406Sopenharmony_ci  s->val[OPT_COLOR].w = 128;
1652141cc406Sopenharmony_ci  if (s->dev->sensedat.model != PCIN500)
1653141cc406Sopenharmony_ci    s->opt[OPT_COLOR].cap |= SANE_CAP_INACTIVE;
1654141cc406Sopenharmony_ci
1655141cc406Sopenharmony_ci  /* threshold */
1656141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1657141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1658141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1659141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1660141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1661141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1662141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint.range = &s->dev->info.threshold_range;
1663141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD].w = 128;
1664141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
1667141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].name = SANE_NAME_THRESHOLD "-red";
1668141cc406Sopenharmony_ci  /* xxx the titles and descriptions are confusing:
1669141cc406Sopenharmony_ci     "set white point (red)"
1670141cc406Sopenharmony_ci     Any idea? maybe "threshold to get the red component on"
1671141cc406Sopenharmony_ci  */
1672141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].title = SANE_TITLE_THRESHOLD " (red)";
1673141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].desc = SANE_DESC_THRESHOLD " (red)";
1674141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].type = SANE_TYPE_INT;
1675141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].unit = SANE_UNIT_NONE;
1676141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].constraint_type = SANE_CONSTRAINT_RANGE;
1677141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].constraint.range = &s->dev->info.threshold_range;
1678141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD_R].w = 128;
1679141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_R].cap |= SANE_CAP_INACTIVE;
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].name = SANE_NAME_THRESHOLD "-green";
1682141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].title = SANE_TITLE_THRESHOLD " (green)";
1683141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].desc = SANE_DESC_THRESHOLD " (green)";
1684141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].type = SANE_TYPE_INT;
1685141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].unit = SANE_UNIT_NONE;
1686141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].constraint_type = SANE_CONSTRAINT_RANGE;
1687141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].constraint.range = &s->dev->info.threshold_range;
1688141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD_G].w = 128;
1689141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_G].cap |= SANE_CAP_INACTIVE;
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].name = SANE_NAME_THRESHOLD "-blue";
1692141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].title = SANE_TITLE_THRESHOLD " (blue)";
1693141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].desc = SANE_DESC_THRESHOLD " (blue)";
1694141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].type = SANE_TYPE_INT;
1695141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].unit = SANE_UNIT_NONE;
1696141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].constraint_type = SANE_CONSTRAINT_RANGE;
1697141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].constraint.range = &s->dev->info.threshold_range;
1698141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD_B].w = 128;
1699141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD_B].cap |= SANE_CAP_INACTIVE;
1700141cc406Sopenharmony_ci
1701141cc406Sopenharmony_ci#endif
1702141cc406Sopenharmony_ci
1703141cc406Sopenharmony_ci  /* light color (for gray scale and line art scans) */
1704141cc406Sopenharmony_ci  init_string_option(s, "LightColor", "LightColor", "LightColor",
1705141cc406Sopenharmony_ci    light_color_list, OPT_LIGHTCOLOR, 3);
1706141cc406Sopenharmony_ci  s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE;
1707141cc406Sopenharmony_ci
1708141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name  = SANE_NAME_PREVIEW;
1709141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1710141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc  = SANE_DESC_PREVIEW;
1711141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].type  = SANE_TYPE_BOOL;
1712141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
1713141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w     = SANE_FALSE;
1714141cc406Sopenharmony_ci
1715141cc406Sopenharmony_ci
1716141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
1717141cc406Sopenharmony_ci  /* custom-gamma table */
1718141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
1719141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
1720141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
1721141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
1722141cc406Sopenharmony_ci  s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_ci  /* grayscale gamma vector */
1725141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
1726141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
1727141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
1728141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
1729141cc406Sopenharmony_ci#if 0
1730141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1731141cc406Sopenharmony_ci#endif
1732141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
1733141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
1734141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
1735141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
1736141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0];
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci  /* red gamma vector */
1739141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
1740141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1741141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
1742141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
1743141cc406Sopenharmony_ci#if 0
1744141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1745141cc406Sopenharmony_ci#endif
1746141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
1747141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
1748141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1749141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
1750141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0];
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci  /* green gamma vector */
1753141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
1754141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1755141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
1756141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
1757141cc406Sopenharmony_ci#if 0
1758141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1759141cc406Sopenharmony_ci#endif
1760141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
1761141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
1762141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1763141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
1764141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0];
1765141cc406Sopenharmony_ci
1766141cc406Sopenharmony_ci  /* blue gamma vector */
1767141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
1768141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1769141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
1770141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
1771141cc406Sopenharmony_ci#if 0
1772141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1773141cc406Sopenharmony_ci#endif
1774141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
1775141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
1776141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1777141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
1778141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0];
1779141cc406Sopenharmony_ci  set_gamma_caps(s);
1780141cc406Sopenharmony_ci#endif
1781141cc406Sopenharmony_ci
1782141cc406Sopenharmony_ci  DBG (10, ">>\n");
1783141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1784141cc406Sopenharmony_ci}
1785141cc406Sopenharmony_ci
1786141cc406Sopenharmony_cistatic SANE_Status
1787141cc406Sopenharmony_cido_cancel (NEC_Scanner * s)
1788141cc406Sopenharmony_ci{
1789141cc406Sopenharmony_ci  DBG (10, "<< do_cancel ");
1790141cc406Sopenharmony_ci
1791141cc406Sopenharmony_ci#ifdef USE_FORK
1792141cc406Sopenharmony_ci  if (s->reader_pid > 0)
1793141cc406Sopenharmony_ci    {
1794141cc406Sopenharmony_ci      int exit_status;
1795141cc406Sopenharmony_ci      int count = 0;
1796141cc406Sopenharmony_ci      /* ensure child knows it's time to stop: */
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci      DBG(11, "stopping reader process\n");
1799141cc406Sopenharmony_ci      s->rdr_ctl->cancel = 1;
1800141cc406Sopenharmony_ci      while(reader_running(s) && count < 100)
1801141cc406Sopenharmony_ci        {
1802141cc406Sopenharmony_ci          usleep(100000);
1803141cc406Sopenharmony_ci          count++;
1804141cc406Sopenharmony_ci        };
1805141cc406Sopenharmony_ci      if (reader_running(s))
1806141cc406Sopenharmony_ci        {
1807141cc406Sopenharmony_ci          kill(s->reader_pid, SIGKILL);
1808141cc406Sopenharmony_ci        }
1809141cc406Sopenharmony_ci      wait(&exit_status);
1810141cc406Sopenharmony_ci      DBG(11, "reader process stopped\n");
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci      s->reader_pid = 0;
1813141cc406Sopenharmony_ci    }
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci#endif
1816141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci  if (s->fd >= 0)
1819141cc406Sopenharmony_ci    {
1820141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
1821141cc406Sopenharmony_ci      s->fd = -1;
1822141cc406Sopenharmony_ci    }
1823141cc406Sopenharmony_ci#ifdef USE_FORK
1824141cc406Sopenharmony_ci  {
1825141cc406Sopenharmony_ci    struct shmid_ds ds;
1826141cc406Sopenharmony_ci    if (s->shmid != -1)
1827141cc406Sopenharmony_ci      shmctl(s->shmid, IPC_RMID, &ds);
1828141cc406Sopenharmony_ci    s->shmid = -1;
1829141cc406Sopenharmony_ci  }
1830141cc406Sopenharmony_ci#endif
1831141cc406Sopenharmony_ci  if (s->buffer)
1832141cc406Sopenharmony_ci    free(s->buffer);
1833141cc406Sopenharmony_ci  s->buffer = 0;
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_ci  DBG (10, ">>\n");
1836141cc406Sopenharmony_ci  return (SANE_STATUS_CANCELLED);
1837141cc406Sopenharmony_ci}
1838141cc406Sopenharmony_ci
1839141cc406Sopenharmony_cistatic NEC_New_Device *new_devs = 0;
1840141cc406Sopenharmony_cistatic NEC_New_Device *new_dev_pool = 0;
1841141cc406Sopenharmony_ci
1842141cc406Sopenharmony_cistatic SANE_Status
1843141cc406Sopenharmony_ciattach_and_list(const char *devnam)
1844141cc406Sopenharmony_ci{
1845141cc406Sopenharmony_ci  SANE_Status res;
1846141cc406Sopenharmony_ci  NEC_Device *devp;
1847141cc406Sopenharmony_ci  NEC_New_Device *np;
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_ci  res = attach(devnam, &devp);
1850141cc406Sopenharmony_ci  if (res == SANE_STATUS_GOOD)
1851141cc406Sopenharmony_ci    {
1852141cc406Sopenharmony_ci      if (new_dev_pool)
1853141cc406Sopenharmony_ci        {
1854141cc406Sopenharmony_ci          np = new_dev_pool;
1855141cc406Sopenharmony_ci          new_dev_pool = np->next;
1856141cc406Sopenharmony_ci        }
1857141cc406Sopenharmony_ci      else
1858141cc406Sopenharmony_ci        {
1859141cc406Sopenharmony_ci          np = malloc(sizeof(NEC_New_Device));
1860141cc406Sopenharmony_ci          if (np == 0)
1861141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
1862141cc406Sopenharmony_ci        }
1863141cc406Sopenharmony_ci      np->next =new_devs;
1864141cc406Sopenharmony_ci      np->dev = devp;
1865141cc406Sopenharmony_ci      new_devs = np;
1866141cc406Sopenharmony_ci    }
1867141cc406Sopenharmony_ci  return res;
1868141cc406Sopenharmony_ci}
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ciSANE_Status
1871141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
1872141cc406Sopenharmony_ci{
1873141cc406Sopenharmony_ci  char devnam[PATH_MAX] = "/dev/scanner";
1874141cc406Sopenharmony_ci  char line[PATH_MAX];
1875141cc406Sopenharmony_ci  const char *lp;
1876141cc406Sopenharmony_ci  char *word;
1877141cc406Sopenharmony_ci  char *end;
1878141cc406Sopenharmony_ci  FILE *fp;
1879141cc406Sopenharmony_ci  int opt_index = 0;
1880141cc406Sopenharmony_ci  int buffers[2] = {DEFAULT_BUFFERS, DEFAULT_BUFFERS};
1881141cc406Sopenharmony_ci  int bufsize[2] = {DEFAULT_BUFSIZE, DEFAULT_BUFSIZE};
1882141cc406Sopenharmony_ci  int queued_reads[2] = {DEFAULT_QUEUED_READS, DEFAULT_QUEUED_READS};
1883141cc406Sopenharmony_ci  int linecount = 0;
1884141cc406Sopenharmony_ci#if 1
1885141cc406Sopenharmony_ci  NEC_Device nd;
1886141cc406Sopenharmony_ci  NEC_Device *dp = &nd;
1887141cc406Sopenharmony_ci#else
1888141cc406Sopenharmony_ci  NEC_Device *dp;
1889141cc406Sopenharmony_ci#endif
1890141cc406Sopenharmony_ci  NEC_New_Device *np;
1891141cc406Sopenharmony_ci  int i;
1892141cc406Sopenharmony_ci
1893141cc406Sopenharmony_ci  (void) authorize; /* silence compilation warnings */
1894141cc406Sopenharmony_ci
1895141cc406Sopenharmony_ci  DBG_INIT ();
1896141cc406Sopenharmony_ci  DBG (10, "<< sane_init ");
1897141cc406Sopenharmony_ci
1898141cc406Sopenharmony_ci  DBG (1, "sane_init: NEC (Ver %d.%d)\n", NEC_MAJOR, NEC_MINOR);
1899141cc406Sopenharmony_ci
1900141cc406Sopenharmony_ci  if (version_code)
1901141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
1902141cc406Sopenharmony_ci
1903141cc406Sopenharmony_ci  fp = sanei_config_open (NEC_CONFIG_FILE);
1904141cc406Sopenharmony_ci  if (!fp)
1905141cc406Sopenharmony_ci    {
1906141cc406Sopenharmony_ci      /* use "/dev/scanner" as the default device name if no
1907141cc406Sopenharmony_ci         config file is available
1908141cc406Sopenharmony_ci      */
1909141cc406Sopenharmony_ci      attach (devnam, &dp);
1910141cc406Sopenharmony_ci      /* make sure that there are at least two buffers */
1911141cc406Sopenharmony_ci      if (DEFAULT_BUFFERS < 2)
1912141cc406Sopenharmony_ci        dp->info.buffers = DEFAULT_BUFFERS;
1913141cc406Sopenharmony_ci      else
1914141cc406Sopenharmony_ci        dp->info.buffers = 2;
1915141cc406Sopenharmony_ci      dp->info.wanted_bufsize = DEFAULT_BUFSIZE;
1916141cc406Sopenharmony_ci      dp->info.queued_reads = DEFAULT_QUEUED_READS;
1917141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1918141cc406Sopenharmony_ci    }
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci  while (fgets(line, PATH_MAX, fp))
1921141cc406Sopenharmony_ci    {
1922141cc406Sopenharmony_ci      linecount++;
1923141cc406Sopenharmony_ci      word = 0;
1924141cc406Sopenharmony_ci      lp = sanei_config_get_string(line, &word);
1925141cc406Sopenharmony_ci      if (word)
1926141cc406Sopenharmony_ci        {
1927141cc406Sopenharmony_ci          if (word[0] != '#')
1928141cc406Sopenharmony_ci            {
1929141cc406Sopenharmony_ci              if (strcmp(word, "option") == 0)
1930141cc406Sopenharmony_ci                {
1931141cc406Sopenharmony_ci                  free(word);
1932141cc406Sopenharmony_ci                  word = 0;
1933141cc406Sopenharmony_ci                  lp = sanei_config_get_string(lp, &word);
1934141cc406Sopenharmony_ci                  if (strcmp(word, "buffers") == 0)
1935141cc406Sopenharmony_ci                    {
1936141cc406Sopenharmony_ci                      free(word);
1937141cc406Sopenharmony_ci                      word = 0;
1938141cc406Sopenharmony_ci                      sanei_config_get_string(lp, &word);
1939141cc406Sopenharmony_ci                      i = strtol(word, &end, 0);
1940141cc406Sopenharmony_ci                      if (end == word)
1941141cc406Sopenharmony_ci                        {
1942141cc406Sopenharmony_ci                          DBG(1, "error in config file, line %i: number expected:\n",
1943141cc406Sopenharmony_ci                              linecount);
1944141cc406Sopenharmony_ci                          DBG(1, "%s\n", line);
1945141cc406Sopenharmony_ci                        }
1946141cc406Sopenharmony_ci                      else
1947141cc406Sopenharmony_ci                        if (i > 2)
1948141cc406Sopenharmony_ci                          buffers[opt_index] = i;
1949141cc406Sopenharmony_ci                        else
1950141cc406Sopenharmony_ci                          buffers[opt_index] = 2;
1951141cc406Sopenharmony_ci                    }
1952141cc406Sopenharmony_ci                  else if (strcmp(word, "buffersize") == 0)
1953141cc406Sopenharmony_ci                    {
1954141cc406Sopenharmony_ci                      free(word);
1955141cc406Sopenharmony_ci                      word = 0;
1956141cc406Sopenharmony_ci                      sanei_config_get_string(lp, &word);
1957141cc406Sopenharmony_ci                      i = strtol(word, &end, 0);
1958141cc406Sopenharmony_ci                      if (word == end)
1959141cc406Sopenharmony_ci                        {
1960141cc406Sopenharmony_ci                          DBG(1, "error in config file, line %i: number expected:\n",
1961141cc406Sopenharmony_ci                              linecount);
1962141cc406Sopenharmony_ci                          DBG(1, "%s\n", line);
1963141cc406Sopenharmony_ci                        }
1964141cc406Sopenharmony_ci                      else
1965141cc406Sopenharmony_ci                        bufsize[opt_index] = i;
1966141cc406Sopenharmony_ci                    }
1967141cc406Sopenharmony_ci                  else if (strcmp(word, "readqueue") == 0)
1968141cc406Sopenharmony_ci                    {
1969141cc406Sopenharmony_ci                      free(word);
1970141cc406Sopenharmony_ci                      word = 0;
1971141cc406Sopenharmony_ci                      sanei_config_get_string(lp, &word);
1972141cc406Sopenharmony_ci                      i = strtol(word, &end, 0);
1973141cc406Sopenharmony_ci                      if (word == end)
1974141cc406Sopenharmony_ci                        {
1975141cc406Sopenharmony_ci                          DBG(1, "error in config file, line %i: number expected:\n",
1976141cc406Sopenharmony_ci                              linecount);
1977141cc406Sopenharmony_ci                          DBG(1, "%s\n", line);
1978141cc406Sopenharmony_ci                        }
1979141cc406Sopenharmony_ci                      else
1980141cc406Sopenharmony_ci                        queued_reads[opt_index] = i;
1981141cc406Sopenharmony_ci                    }
1982141cc406Sopenharmony_ci                  else
1983141cc406Sopenharmony_ci                    {
1984141cc406Sopenharmony_ci                      DBG(1, "error in config file, line %i: unknown option\n",
1985141cc406Sopenharmony_ci                          linecount);
1986141cc406Sopenharmony_ci                      DBG(1, "%s\n", line);
1987141cc406Sopenharmony_ci                    }
1988141cc406Sopenharmony_ci                }
1989141cc406Sopenharmony_ci              else
1990141cc406Sopenharmony_ci                {
1991141cc406Sopenharmony_ci                  while (new_devs)
1992141cc406Sopenharmony_ci                    {
1993141cc406Sopenharmony_ci                      if (buffers[1] >= 2)
1994141cc406Sopenharmony_ci                        new_devs->dev->info.buffers = buffers[1];
1995141cc406Sopenharmony_ci                      else
1996141cc406Sopenharmony_ci                        new_devs->dev->info.buffers = 2;
1997141cc406Sopenharmony_ci                      if (bufsize[1] > 0)
1998141cc406Sopenharmony_ci                        new_devs->dev->info.wanted_bufsize = bufsize[1];
1999141cc406Sopenharmony_ci                      else
2000141cc406Sopenharmony_ci                        new_devs->dev->info.wanted_bufsize = DEFAULT_BUFSIZE;
2001141cc406Sopenharmony_ci                      if (queued_reads[1] >= 0)
2002141cc406Sopenharmony_ci                        new_devs->dev->info.queued_reads = queued_reads[1];
2003141cc406Sopenharmony_ci                      else
2004141cc406Sopenharmony_ci                        new_devs->dev->info.queued_reads = 0;
2005141cc406Sopenharmony_ci                      np = new_devs->next;
2006141cc406Sopenharmony_ci                      new_devs->next = new_dev_pool;
2007141cc406Sopenharmony_ci                      new_dev_pool = new_devs;
2008141cc406Sopenharmony_ci                      new_devs = np;
2009141cc406Sopenharmony_ci                    }
2010141cc406Sopenharmony_ci                  if (line[strlen(line)-1] == '\n')
2011141cc406Sopenharmony_ci                    line[strlen(line)-1] = 0;
2012141cc406Sopenharmony_ci                  sanei_config_attach_matching_devices(line, &attach_and_list);
2013141cc406Sopenharmony_ci                  buffers[1] = buffers[0];
2014141cc406Sopenharmony_ci                  bufsize[1] = bufsize[0];
2015141cc406Sopenharmony_ci                  queued_reads[1] = queued_reads[0];
2016141cc406Sopenharmony_ci                  opt_index = 1;
2017141cc406Sopenharmony_ci                }
2018141cc406Sopenharmony_ci            }
2019141cc406Sopenharmony_ci          if (word) free(word);
2020141cc406Sopenharmony_ci        }
2021141cc406Sopenharmony_ci    }
2022141cc406Sopenharmony_ci
2023141cc406Sopenharmony_ci  while (new_devs)
2024141cc406Sopenharmony_ci    {
2025141cc406Sopenharmony_ci      if (buffers[1] >= 2)
2026141cc406Sopenharmony_ci        new_devs->dev->info.buffers = buffers[1];
2027141cc406Sopenharmony_ci      else
2028141cc406Sopenharmony_ci        new_devs->dev->info.buffers = 2;
2029141cc406Sopenharmony_ci      if (bufsize[1] > 0)
2030141cc406Sopenharmony_ci        new_devs->dev->info.wanted_bufsize = bufsize[1];
2031141cc406Sopenharmony_ci      else
2032141cc406Sopenharmony_ci        new_devs->dev->info.wanted_bufsize = DEFAULT_BUFSIZE;
2033141cc406Sopenharmony_ci      if (queued_reads[1] >= 0)
2034141cc406Sopenharmony_ci        new_devs->dev->info.queued_reads = queued_reads[1];
2035141cc406Sopenharmony_ci      else
2036141cc406Sopenharmony_ci        new_devs->dev->info.queued_reads = 0;
2037141cc406Sopenharmony_ci      if (line[strlen(line)-1] == '\n')
2038141cc406Sopenharmony_ci        line[strlen(line)-1] = 0;
2039141cc406Sopenharmony_ci      np = new_devs->next;
2040141cc406Sopenharmony_ci      free(new_devs);
2041141cc406Sopenharmony_ci      new_devs = np;
2042141cc406Sopenharmony_ci    }
2043141cc406Sopenharmony_ci  while (new_dev_pool)
2044141cc406Sopenharmony_ci    {
2045141cc406Sopenharmony_ci      np = new_dev_pool->next;
2046141cc406Sopenharmony_ci      free(new_dev_pool);
2047141cc406Sopenharmony_ci      new_dev_pool = np;
2048141cc406Sopenharmony_ci    }
2049141cc406Sopenharmony_ci  fclose(fp);
2050141cc406Sopenharmony_ci  DBG (10, ">>\n");
2051141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2052141cc406Sopenharmony_ci}
2053141cc406Sopenharmony_ci
2054141cc406Sopenharmony_civoid
2055141cc406Sopenharmony_cisane_exit (void)
2056141cc406Sopenharmony_ci{
2057141cc406Sopenharmony_ci  NEC_Device *dev, *next;
2058141cc406Sopenharmony_ci  DBG (10, "<< sane_exit ");
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
2061141cc406Sopenharmony_ci    {
2062141cc406Sopenharmony_ci      next = dev->next;
2063141cc406Sopenharmony_ci      free ((void *) dev->sane.name);
2064141cc406Sopenharmony_ci      free ((void *) dev->sane.model);
2065141cc406Sopenharmony_ci      free (dev);
2066141cc406Sopenharmony_ci    }
2067141cc406Sopenharmony_ci  first_dev = 0;
2068141cc406Sopenharmony_ci
2069141cc406Sopenharmony_ci  if (devlist)
2070141cc406Sopenharmony_ci    free(devlist);
2071141cc406Sopenharmony_ci
2072141cc406Sopenharmony_ci  DBG (10, ">>\n");
2073141cc406Sopenharmony_ci}
2074141cc406Sopenharmony_ci
2075141cc406Sopenharmony_ciSANE_Status
2076141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
2077141cc406Sopenharmony_ci{
2078141cc406Sopenharmony_ci  NEC_Device *dev;
2079141cc406Sopenharmony_ci  int i;
2080141cc406Sopenharmony_ci  DBG (10, "<< sane_get_devices ");
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci  (void) local_only; /* silence compilation warnings */
2083141cc406Sopenharmony_ci
2084141cc406Sopenharmony_ci  if (devlist)
2085141cc406Sopenharmony_ci    free (devlist);
2086141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
2087141cc406Sopenharmony_ci  if (!devlist)
2088141cc406Sopenharmony_ci    return (SANE_STATUS_NO_MEM);
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ci  i = 0;
2091141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
2092141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
2093141cc406Sopenharmony_ci  devlist[i++] = 0;
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci  *device_list = devlist;
2096141cc406Sopenharmony_ci
2097141cc406Sopenharmony_ci  DBG (10, ">>\n");
2098141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2099141cc406Sopenharmony_ci}
2100141cc406Sopenharmony_ci
2101141cc406Sopenharmony_ciSANE_Status
2102141cc406Sopenharmony_cisane_open (SANE_String_Const devnam, SANE_Handle * handle)
2103141cc406Sopenharmony_ci{
2104141cc406Sopenharmony_ci  SANE_Status status;
2105141cc406Sopenharmony_ci  NEC_Device *dev;
2106141cc406Sopenharmony_ci  NEC_Scanner *s;
2107141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2108141cc406Sopenharmony_ci  int i, j;
2109141cc406Sopenharmony_ci#endif
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci  DBG (10, "<< sane_open ");
2112141cc406Sopenharmony_ci
2113141cc406Sopenharmony_ci  if (devnam[0])
2114141cc406Sopenharmony_ci    {
2115141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
2116141cc406Sopenharmony_ci	{
2117141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devnam) == 0)
2118141cc406Sopenharmony_ci	    break;
2119141cc406Sopenharmony_ci	}
2120141cc406Sopenharmony_ci
2121141cc406Sopenharmony_ci      if (!dev)
2122141cc406Sopenharmony_ci	{
2123141cc406Sopenharmony_ci	  status = attach (devnam, &dev);
2124141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2125141cc406Sopenharmony_ci	    return (status);
2126141cc406Sopenharmony_ci	}
2127141cc406Sopenharmony_ci    }
2128141cc406Sopenharmony_ci  else
2129141cc406Sopenharmony_ci    {
2130141cc406Sopenharmony_ci      dev = first_dev;
2131141cc406Sopenharmony_ci    }
2132141cc406Sopenharmony_ci
2133141cc406Sopenharmony_ci  if (!dev)
2134141cc406Sopenharmony_ci    return (SANE_STATUS_INVAL);
2135141cc406Sopenharmony_ci
2136141cc406Sopenharmony_ci  s = malloc (sizeof (*s));
2137141cc406Sopenharmony_ci  if (!s)
2138141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2139141cc406Sopenharmony_ci  memset (s, 0, sizeof (*s));
2140141cc406Sopenharmony_ci
2141141cc406Sopenharmony_ci  s->fd = -1;
2142141cc406Sopenharmony_ci  s->dev = dev;
2143141cc406Sopenharmony_ci
2144141cc406Sopenharmony_ci  s->buffer = 0;
2145141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2146141cc406Sopenharmony_ci  for (i = 0; i < 4; ++i)
2147141cc406Sopenharmony_ci    for (j = 0; j < 256; ++j)
2148141cc406Sopenharmony_ci      s->gamma_table[i][j] = j;
2149141cc406Sopenharmony_ci#endif
2150141cc406Sopenharmony_ci  status = init_options (s);
2151141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2152141cc406Sopenharmony_ci    {
2153141cc406Sopenharmony_ci      /* xxx clean up mallocs */
2154141cc406Sopenharmony_ci      return status;
2155141cc406Sopenharmony_ci    }
2156141cc406Sopenharmony_ci
2157141cc406Sopenharmony_ci  s->next = first_handle;
2158141cc406Sopenharmony_ci  first_handle = s;
2159141cc406Sopenharmony_ci
2160141cc406Sopenharmony_ci  *handle = s;
2161141cc406Sopenharmony_ci
2162141cc406Sopenharmony_ci  DBG (10, ">>\n");
2163141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2164141cc406Sopenharmony_ci}
2165141cc406Sopenharmony_ci
2166141cc406Sopenharmony_civoid
2167141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2168141cc406Sopenharmony_ci{
2169141cc406Sopenharmony_ci  NEC_Scanner *s = (NEC_Scanner *) handle;
2170141cc406Sopenharmony_ci  DBG (10, "<< sane_close ");
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_ci  if (s->fd != -1)
2173141cc406Sopenharmony_ci    sanei_scsi_close (s->fd);
2174141cc406Sopenharmony_ci#ifdef USE_FORK
2175141cc406Sopenharmony_ci  {
2176141cc406Sopenharmony_ci    struct shmid_ds ds;
2177141cc406Sopenharmony_ci    if (s->shmid != -1)
2178141cc406Sopenharmony_ci      shmctl(s->shmid, IPC_RMID, &ds);
2179141cc406Sopenharmony_ci  }
2180141cc406Sopenharmony_ci#endif
2181141cc406Sopenharmony_ci  if (s->buffer)
2182141cc406Sopenharmony_ci    free(s->buffer);
2183141cc406Sopenharmony_ci  free (s);
2184141cc406Sopenharmony_ci
2185141cc406Sopenharmony_ci  DBG (10, ">>\n");
2186141cc406Sopenharmony_ci}
2187141cc406Sopenharmony_ci
2188141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
2189141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
2190141cc406Sopenharmony_ci{
2191141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
2192141cc406Sopenharmony_ci  DBG (10, "<< sane_get_option_descriptor ");
2193141cc406Sopenharmony_ci
2194141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
2195141cc406Sopenharmony_ci    return (0);
2196141cc406Sopenharmony_ci
2197141cc406Sopenharmony_ci  DBG (10, ">>\n");
2198141cc406Sopenharmony_ci  return (s->opt + option);
2199141cc406Sopenharmony_ci}
2200141cc406Sopenharmony_ci
2201141cc406Sopenharmony_ciSANE_Status
2202141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
2203141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
2204141cc406Sopenharmony_ci{
2205141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
2206141cc406Sopenharmony_ci  SANE_Status status;
2207141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2208141cc406Sopenharmony_ci  SANE_Word w, cap;
2209141cc406Sopenharmony_ci#else
2210141cc406Sopenharmony_ci  SANE_Word cap;
2211141cc406Sopenharmony_ci#endif
2212141cc406Sopenharmony_ci  int range_index;
2213141cc406Sopenharmony_ci  DBG (10, "<< sane_control_option %i", option);
2214141cc406Sopenharmony_ci
2215141cc406Sopenharmony_ci  if (info)
2216141cc406Sopenharmony_ci    *info = 0;
2217141cc406Sopenharmony_ci
2218141cc406Sopenharmony_ci  if (s->scanning)
2219141cc406Sopenharmony_ci    return (SANE_STATUS_DEVICE_BUSY);
2220141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
2221141cc406Sopenharmony_ci    return (SANE_STATUS_INVAL);
2222141cc406Sopenharmony_ci
2223141cc406Sopenharmony_ci  cap = s->opt[option].cap;
2224141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
2225141cc406Sopenharmony_ci    return (SANE_STATUS_INVAL);
2226141cc406Sopenharmony_ci
2227141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
2228141cc406Sopenharmony_ci    {
2229141cc406Sopenharmony_ci      switch (option)
2230141cc406Sopenharmony_ci	{
2231141cc406Sopenharmony_ci	  /* word options: */
2232141cc406Sopenharmony_ci	case OPT_RESOLUTION:
2233141cc406Sopenharmony_ci	case OPT_TL_X:
2234141cc406Sopenharmony_ci	case OPT_TL_Y:
2235141cc406Sopenharmony_ci	case OPT_BR_X:
2236141cc406Sopenharmony_ci	case OPT_BR_Y:
2237141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
2238141cc406Sopenharmony_ci	case OPT_THRESHOLD:
2239141cc406Sopenharmony_ci	case OPT_TINT:
2240141cc406Sopenharmony_ci	case OPT_COLOR:
2241141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2242141cc406Sopenharmony_ci	case OPT_THRESHOLD_R:
2243141cc406Sopenharmony_ci	case OPT_THRESHOLD_G:
2244141cc406Sopenharmony_ci	case OPT_THRESHOLD_B:
2245141cc406Sopenharmony_ci#endif
2246141cc406Sopenharmony_ci	case OPT_OR:
2247141cc406Sopenharmony_ci	case OPT_NR:
2248141cc406Sopenharmony_ci	case OPT_EDGE:
2249141cc406Sopenharmony_ci	case OPT_PREVIEW:
2250141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2251141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
2252141cc406Sopenharmony_ci#endif
2253141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
2254141cc406Sopenharmony_ci#if 0 /* here, values are read; reload should not be necessary */
2255141cc406Sopenharmony_ci	  if (info)
2256141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
2257141cc406Sopenharmony_ci#endif
2258141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2261141cc406Sopenharmony_ci	  /* word-array options: */
2262141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
2263141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
2264141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
2265141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
2266141cc406Sopenharmony_ci	  memcpy (val, s->val[option].wa, s->opt[option].size);
2267141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2268141cc406Sopenharmony_ci#endif
2269141cc406Sopenharmony_ci
2270141cc406Sopenharmony_ci	  /* string options: */
2271141cc406Sopenharmony_ci	case OPT_MODE:
2272141cc406Sopenharmony_ci	case OPT_HALFTONE:
2273141cc406Sopenharmony_ci	case OPT_PAPER:
2274141cc406Sopenharmony_ci	case OPT_GAMMA:
2275141cc406Sopenharmony_ci#ifdef USE_RESOLUTION_LIST
2276141cc406Sopenharmony_ci	case OPT_RESOLUTION_LIST:
2277141cc406Sopenharmony_ci#endif
2278141cc406Sopenharmony_ci	case OPT_EDGE_EMPHASIS:
2279141cc406Sopenharmony_ci	case OPT_LIGHTCOLOR:
2280141cc406Sopenharmony_ci	case OPT_SCANSOURCE:
2281141cc406Sopenharmony_ci	  strcpy (val, s->val[option].s);
2282141cc406Sopenharmony_ci#if 0
2283141cc406Sopenharmony_ci	  if (info)
2284141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
2285141cc406Sopenharmony_ci#endif
2286141cc406Sopenharmony_ci
2287141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2288141cc406Sopenharmony_ci
2289141cc406Sopenharmony_ci	}
2290141cc406Sopenharmony_ci    }
2291141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
2292141cc406Sopenharmony_ci    {
2293141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
2294141cc406Sopenharmony_ci	return (SANE_STATUS_INVAL);
2295141cc406Sopenharmony_ci
2296141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, info);
2297141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2298141cc406Sopenharmony_ci	return status;
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci      switch (option)
2301141cc406Sopenharmony_ci	{
2302141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
2303141cc406Sopenharmony_ci	case OPT_RESOLUTION:
2304141cc406Sopenharmony_ci	case OPT_TL_X:
2305141cc406Sopenharmony_ci	case OPT_TL_Y:
2306141cc406Sopenharmony_ci	case OPT_BR_X:
2307141cc406Sopenharmony_ci	case OPT_BR_Y:
2308141cc406Sopenharmony_ci	  if (info && s->val[option].w != *(SANE_Word *) val)
2309141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
2310141cc406Sopenharmony_ci          // fall through
2311141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
2312141cc406Sopenharmony_ci	case OPT_THRESHOLD:
2313141cc406Sopenharmony_ci	  /* xxx theoretically, we could use OPT_THRESHOLD in
2314141cc406Sopenharmony_ci	     bi-level color mode to adjust all three other
2315141cc406Sopenharmony_ci	     threshold together. But this would require to set
2316141cc406Sopenharmony_ci	     the bit SANE_INFO_RELOAD_OPTIONS in *info, and that
2317141cc406Sopenharmony_ci	     would unfortunately cause a crash in both xscanimage
2318141cc406Sopenharmony_ci	     and xsane... Therefore, OPT_THRESHOLD is disabled
2319141cc406Sopenharmony_ci	     for bi-level color scan right now.
2320141cc406Sopenharmony_ci	  */
2321141cc406Sopenharmony_ci	case OPT_TINT:
2322141cc406Sopenharmony_ci	case OPT_COLOR:
2323141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2324141cc406Sopenharmony_ci	case OPT_THRESHOLD_R:
2325141cc406Sopenharmony_ci	case OPT_THRESHOLD_G:
2326141cc406Sopenharmony_ci	case OPT_THRESHOLD_B:
2327141cc406Sopenharmony_ci#endif
2328141cc406Sopenharmony_ci	case OPT_OR:
2329141cc406Sopenharmony_ci	case OPT_NR:
2330141cc406Sopenharmony_ci	case OPT_EDGE:
2331141cc406Sopenharmony_ci	case OPT_PREVIEW:
2332141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
2333141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2334141cc406Sopenharmony_ci
2335141cc406Sopenharmony_ci	case OPT_MODE:
2336141cc406Sopenharmony_ci	  if (strcmp (val, M_LINEART) == 0)
2337141cc406Sopenharmony_ci	    {
2338141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap &= ~SANE_CAP_INACTIVE;
2339141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
2340141cc406Sopenharmony_ci	      s->opt[OPT_TINT].cap |= SANE_CAP_INACTIVE;
2341141cc406Sopenharmony_ci	      s->opt[OPT_COLOR].cap |= SANE_CAP_INACTIVE;
2342141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2343141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_R].cap |= SANE_CAP_INACTIVE;
2344141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_G].cap |= SANE_CAP_INACTIVE;
2345141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_B].cap |= SANE_CAP_INACTIVE;
2346141cc406Sopenharmony_ci#endif
2347141cc406Sopenharmony_ci	      if (s->dev->sensedat.model == PCIN500)
2348141cc406Sopenharmony_ci                s->opt[OPT_HALFTONE].cap &= ~SANE_CAP_INACTIVE;
2349141cc406Sopenharmony_ci	    }
2350141cc406Sopenharmony_ci	  else if (strcmp (val, M_LINEART_COLOR) == 0)
2351141cc406Sopenharmony_ci	    {
2352141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE;
2353141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2354141cc406Sopenharmony_ci	      s->opt[OPT_TINT].cap |= SANE_CAP_INACTIVE;
2355141cc406Sopenharmony_ci	      s->opt[OPT_COLOR].cap |= SANE_CAP_INACTIVE;
2356141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2357141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_R].cap &= ~SANE_CAP_INACTIVE;
2358141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_G].cap &= ~SANE_CAP_INACTIVE;
2359141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_B].cap &= ~SANE_CAP_INACTIVE;
2360141cc406Sopenharmony_ci#endif
2361141cc406Sopenharmony_ci	      if (s->dev->sensedat.model == PCIN500)
2362141cc406Sopenharmony_ci                s->opt[OPT_HALFTONE].cap &= ~SANE_CAP_INACTIVE;
2363141cc406Sopenharmony_ci	    }
2364141cc406Sopenharmony_ci	  else if (strcmp (val, M_GRAY) == 0)
2365141cc406Sopenharmony_ci	    {
2366141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap &= ~SANE_CAP_INACTIVE;
2367141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2368141cc406Sopenharmony_ci	      s->opt[OPT_TINT].cap |= SANE_CAP_INACTIVE;
2369141cc406Sopenharmony_ci	      s->opt[OPT_COLOR].cap |= SANE_CAP_INACTIVE;
2370141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2371141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_R].cap |= SANE_CAP_INACTIVE;
2372141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_G].cap |= SANE_CAP_INACTIVE;
2373141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_B].cap |= SANE_CAP_INACTIVE;
2374141cc406Sopenharmony_ci#endif
2375141cc406Sopenharmony_ci              s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2376141cc406Sopenharmony_ci	    }
2377141cc406Sopenharmony_ci	  else
2378141cc406Sopenharmony_ci	    {
2379141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE;
2380141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2381141cc406Sopenharmony_ci	      s->opt[OPT_TINT].cap &= ~SANE_CAP_INACTIVE;
2382141cc406Sopenharmony_ci	      s->opt[OPT_COLOR].cap &= ~SANE_CAP_INACTIVE;
2383141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2384141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_R].cap |= SANE_CAP_INACTIVE;
2385141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_G].cap |= SANE_CAP_INACTIVE;
2386141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD_B].cap |= SANE_CAP_INACTIVE;
2387141cc406Sopenharmony_ci#endif
2388141cc406Sopenharmony_ci              s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2389141cc406Sopenharmony_ci            }
2390141cc406Sopenharmony_ci#if 0
2391141cc406Sopenharmony_ci	  if (   strcmp (val, M_LINEART) == 0
2392141cc406Sopenharmony_ci	      || strcmp (val, M_GRAY) == 0)
2393141cc406Sopenharmony_ci            {
2394141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap &= ~SANE_CAP_INACTIVE;
2395141cc406Sopenharmony_ci            }
2396141cc406Sopenharmony_ci          else
2397141cc406Sopenharmony_ci            {
2398141cc406Sopenharmony_ci	      s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE;
2399141cc406Sopenharmony_ci            }
2400141cc406Sopenharmony_ci#endif
2401141cc406Sopenharmony_ci          strcpy(s->val[option].s, val);
2402141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2403141cc406Sopenharmony_ci          set_gamma_caps(s);
2404141cc406Sopenharmony_ci#endif
2405141cc406Sopenharmony_ci          if (info)
2406141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2407141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2408141cc406Sopenharmony_ci
2409141cc406Sopenharmony_ci	case OPT_GAMMA:
2410141cc406Sopenharmony_ci	case OPT_HALFTONE:
2411141cc406Sopenharmony_ci	case OPT_EDGE_EMPHASIS:
2412141cc406Sopenharmony_ci	case OPT_LIGHTCOLOR:
2413141cc406Sopenharmony_ci#if 0
2414141cc406Sopenharmony_ci	  if (s->val[option].s)
2415141cc406Sopenharmony_ci	    free (s->val[option].s);
2416141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
2417141cc406Sopenharmony_ci#endif
2418141cc406Sopenharmony_ci          strcpy(s->val[option].s, val);
2419141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2420141cc406Sopenharmony_ci
2421141cc406Sopenharmony_ci	case OPT_SCANSOURCE:
2422141cc406Sopenharmony_ci	  if (info && strcmp (s->val[option].s, (SANE_String) val))
2423141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2424141cc406Sopenharmony_ci#if 0
2425141cc406Sopenharmony_ci	  if (s->val[option].s)
2426141cc406Sopenharmony_ci	    free (s->val[option].s);
2427141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
2428141cc406Sopenharmony_ci#endif
2429141cc406Sopenharmony_ci          strcpy(s->val[option].s, val);
2430141cc406Sopenharmony_ci	  if (strcmp(val, use_fsu) == 0)
2431141cc406Sopenharmony_ci	    range_index = SCAN_WITH_FSU;
2432141cc406Sopenharmony_ci	  else if (strcmp(val, use_adf) == 0)
2433141cc406Sopenharmony_ci	    range_index = SCAN_WITH_ADF;
2434141cc406Sopenharmony_ci	  else
2435141cc406Sopenharmony_ci	    range_index = SCAN_SIMPLE;
2436141cc406Sopenharmony_ci
2437141cc406Sopenharmony_ci          s->opt[OPT_TL_X].constraint.range
2438141cc406Sopenharmony_ci            = &s->dev->info.tl_x_ranges[range_index];
2439141cc406Sopenharmony_ci          clip_value (&s->opt[OPT_TL_X], &s->val[OPT_TL_X].w);
2440141cc406Sopenharmony_ci
2441141cc406Sopenharmony_ci          s->opt[OPT_TL_Y].constraint.range
2442141cc406Sopenharmony_ci            = &s->dev->info.tl_y_ranges[range_index];
2443141cc406Sopenharmony_ci          clip_value (&s->opt[OPT_TL_Y], &s->val[OPT_TL_Y].w);
2444141cc406Sopenharmony_ci
2445141cc406Sopenharmony_ci          s->opt[OPT_BR_X].constraint.range
2446141cc406Sopenharmony_ci            = &s->dev->info.br_x_ranges[range_index];
2447141cc406Sopenharmony_ci          clip_value (&s->opt[OPT_BR_X], &s->val[OPT_BR_X].w);
2448141cc406Sopenharmony_ci
2449141cc406Sopenharmony_ci          s->opt[OPT_BR_Y].constraint.range
2450141cc406Sopenharmony_ci            = &s->dev->info.br_y_ranges[range_index];
2451141cc406Sopenharmony_ci          clip_value (&s->opt[OPT_BR_Y], &s->val[OPT_BR_Y].w);
2452141cc406Sopenharmony_ci
2453141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2454141cc406Sopenharmony_ci
2455141cc406Sopenharmony_ci	case OPT_PAPER:
2456141cc406Sopenharmony_ci          if (info)
2457141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2458141cc406Sopenharmony_ci#if 0
2459141cc406Sopenharmony_ci	  if (s->val[option].s)
2460141cc406Sopenharmony_ci	    free (s->val[option].s);
2461141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
2462141cc406Sopenharmony_ci#endif
2463141cc406Sopenharmony_ci          strcpy(s->val[option].s, val);
2464141cc406Sopenharmony_ci	  s->val[OPT_TL_X].w = SANE_FIX(0);
2465141cc406Sopenharmony_ci	  s->val[OPT_TL_Y].w = SANE_FIX(0);
2466141cc406Sopenharmony_ci	  if (strcmp (s->val[option].s, "A3") == 0){
2467141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(297);
2468141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(420);
2469141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "A4") == 0){
2470141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(210);
2471141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(297);
2472141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "A5") == 0){
2473141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(148.5);
2474141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(210);
2475141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "A6") == 0){
2476141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(105);
2477141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(148.5);
2478141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "B4") == 0){
2479141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(250);
2480141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(353);
2481141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "B5") == 0){
2482141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(182);
2483141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(257);
2484141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, W_LETTER) == 0){
2485141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(279.4);
2486141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(431.8);
2487141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "Legal") == 0){
2488141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(215.9);
2489141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(355.6);
2490141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, "Letter") == 0){
2491141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(215.9);
2492141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(279.4);
2493141cc406Sopenharmony_ci	  }else if (strcmp (s->val[option].s, INVOICE) == 0){
2494141cc406Sopenharmony_ci	      s->val[OPT_BR_X].w = SANE_FIX(215.9);
2495141cc406Sopenharmony_ci	      s->val[OPT_BR_Y].w = SANE_FIX(139.7);
2496141cc406Sopenharmony_ci	  }else{
2497141cc406Sopenharmony_ci	  }
2498141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2499141cc406Sopenharmony_ci
2500141cc406Sopenharmony_ci#ifdef USE_RESOLUTION_LIST
2501141cc406Sopenharmony_ci	case OPT_RESOLUTION_LIST:
2502141cc406Sopenharmony_ci	  if (info)
2503141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2504141cc406Sopenharmony_ci#if 0
2505141cc406Sopenharmony_ci	  if (s->val[option].s)
2506141cc406Sopenharmony_ci	    free (s->val[option].s);
2507141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
2508141cc406Sopenharmony_ci#endif
2509141cc406Sopenharmony_ci	  for (i = 0; s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]; i++) {
2510141cc406Sopenharmony_ci	    if (strcmp (val,
2511141cc406Sopenharmony_ci	          s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]) == 0){
2512141cc406Sopenharmony_ci	      s->val[OPT_RESOLUTION].w
2513141cc406Sopenharmony_ci	        = atoi(s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]);
2514141cc406Sopenharmony_ci	      if (info)
2515141cc406Sopenharmony_ci	        *info |= SANE_INFO_RELOAD_PARAMS;
2516141cc406Sopenharmony_ci	      break;
2517141cc406Sopenharmony_ci	    }
2518141cc406Sopenharmony_ci	  }
2519141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
2520141cc406Sopenharmony_ci#endif
2521141cc406Sopenharmony_ci
2522141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2523141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
2524141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
2525141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
2526141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
2527141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
2528141cc406Sopenharmony_ci	  memcpy (s->val[option].wa, val, s->opt[option].size);
2529141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2530141cc406Sopenharmony_ci
2531141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
2532141cc406Sopenharmony_ci	  w = *(SANE_Word *) val;
2533141cc406Sopenharmony_ci
2534141cc406Sopenharmony_ci	  if (w == s->val[OPT_CUSTOM_GAMMA].w)
2535141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;		/* no change */
2536141cc406Sopenharmony_ci
2537141cc406Sopenharmony_ci	  if (info)
2538141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
2539141cc406Sopenharmony_ci	  s->val[OPT_CUSTOM_GAMMA].w = w;
2540141cc406Sopenharmony_ci          set_gamma_caps(s);
2541141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2542141cc406Sopenharmony_ci#endif
2543141cc406Sopenharmony_ci	}
2544141cc406Sopenharmony_ci    }
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci  DBG (10, ">>\n");
2547141cc406Sopenharmony_ci  return (SANE_STATUS_INVAL);
2548141cc406Sopenharmony_ci}
2549141cc406Sopenharmony_ci
2550141cc406Sopenharmony_ciSANE_Status
2551141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
2552141cc406Sopenharmony_ci{
2553141cc406Sopenharmony_ci  int width, length, res;
2554141cc406Sopenharmony_ci  const char *mode;
2555141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
2556141cc406Sopenharmony_ci  DBG (10, "<< sane_get_parameters ");
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_ci  res = s->val[OPT_RESOLUTION].w * s->dev->info.res_range.quant;
2559141cc406Sopenharmony_ci  if (!s->scanning)
2560141cc406Sopenharmony_ci    {
2561141cc406Sopenharmony_ci      /* make best-effort guess at what parameters will look like once
2562141cc406Sopenharmony_ci         scanning starts.  */
2563141cc406Sopenharmony_ci      memset (&s->params, 0, sizeof (s->params));
2564141cc406Sopenharmony_ci
2565141cc406Sopenharmony_ci      width = MM_TO_PIX(  SANE_UNFIX(s->val[OPT_BR_X].w)
2566141cc406Sopenharmony_ci                        - SANE_UNFIX(s->val[OPT_TL_X].w),
2567141cc406Sopenharmony_ci			s->dev->info.mud);
2568141cc406Sopenharmony_ci      length = MM_TO_PIX(  SANE_UNFIX(s->val[OPT_BR_Y].w)
2569141cc406Sopenharmony_ci                          - SANE_UNFIX(s->val[OPT_TL_Y].w),
2570141cc406Sopenharmony_ci			 s->dev->info.mud);
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci      s->width = width;
2573141cc406Sopenharmony_ci      s->length = length;
2574141cc406Sopenharmony_ci      s->params.pixels_per_line = width * res / s->dev->info.mud;
2575141cc406Sopenharmony_ci      s->params.lines = length * res / s->dev->info.mud;
2576141cc406Sopenharmony_ci
2577141cc406Sopenharmony_ci      if (s->dev->sensedat.model == PCIN500)
2578141cc406Sopenharmony_ci	{
2579141cc406Sopenharmony_ci	  s->params.pixels_per_line += 1;
2580141cc406Sopenharmony_ci	  s->params.lines += 1;
2581141cc406Sopenharmony_ci	}
2582141cc406Sopenharmony_ci      s->unscanned_lines = s->params.lines;
2583141cc406Sopenharmony_ci    }
2584141cc406Sopenharmony_ci#if 0
2585141cc406Sopenharmony_ci  else
2586141cc406Sopenharmony_ci    {
2587141cc406Sopenharmony_ci      buffer_status bs;
2588141cc406Sopenharmony_ci      SANE_Status status;
2589141cc406Sopenharmony_ci      size_t len = sizeof (buffer_status);
2590141cc406Sopenharmony_ci      status = get_data_buffer_status (s->fd, &bs, &len);
2591141cc406Sopenharmony_ci      DBG (11, "<< get_data_buffer_status ");
2592141cc406Sopenharmony_ci
2593141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2594141cc406Sopenharmony_ci	{
2595141cc406Sopenharmony_ci	  do_cancel(s);
2596141cc406Sopenharmony_ci	  return (status);
2597141cc406Sopenharmony_ci	}
2598141cc406Sopenharmony_ci      DBG (11, ">>\n ");
2599141cc406Sopenharmony_ci      {
2600141cc406Sopenharmony_ci#ifdef DEBUG_NEC
2601141cc406Sopenharmony_ci	int i;
2602141cc406Sopenharmony_ci	u_char *buf = &bs;
2603141cc406Sopenharmony_ci	DBG(11, "get data buffer status(debug):\n");
2604141cc406Sopenharmony_ci	for (i = 0; i < len; i += 16)
2605141cc406Sopenharmony_ci	  {
2606141cc406Sopenharmony_ci	    DBG(1, "%2x %2x %2x %2x %2x %2x %2x %2x - %2x %2x %2x %2x \n",
2607141cc406Sopenharmony_ci		buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7], buf[i+8],
2608141cc406Sopenharmony_ci		buf[i+9], buf[i+10], buf[i+11]);
2609141cc406Sopenharmony_ci	  }
2610141cc406Sopenharmony_ci#endif
2611141cc406Sopenharmony_ci      }
2612141cc406Sopenharmony_ci    }
2613141cc406Sopenharmony_ci#endif
2614141cc406Sopenharmony_ci  res = s->val[OPT_RESOLUTION].w * s->dev->info.res_range.quant;
2615141cc406Sopenharmony_ci
2616141cc406Sopenharmony_ci  mode = s->val[OPT_MODE].s;
2617141cc406Sopenharmony_ci
2618141cc406Sopenharmony_ci  if (strcmp (mode, M_LINEART) == 0)
2619141cc406Sopenharmony_ci     {
2620141cc406Sopenharmony_ci       s->params.format = SANE_FRAME_GRAY;
2621141cc406Sopenharmony_ci       s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
2622141cc406Sopenharmony_ci       s->params.depth = 1;
2623141cc406Sopenharmony_ci       s->modes = MODES_LINEART;
2624141cc406Sopenharmony_ci     }
2625141cc406Sopenharmony_ci  else if (strcmp (mode, M_GRAY) == 0)
2626141cc406Sopenharmony_ci     {
2627141cc406Sopenharmony_ci       s->params.format = SANE_FRAME_GRAY;
2628141cc406Sopenharmony_ci       s->params.bytes_per_line = s->params.pixels_per_line;
2629141cc406Sopenharmony_ci       s->params.depth = 8;
2630141cc406Sopenharmony_ci       s->modes = MODES_GRAY;
2631141cc406Sopenharmony_ci     }
2632141cc406Sopenharmony_ci  else if (strcmp (mode, M_LINEART_COLOR) == 0)
2633141cc406Sopenharmony_ci    {
2634141cc406Sopenharmony_ci       s->params.format = SANE_FRAME_RGB;
2635141cc406Sopenharmony_ci       s->params.bytes_per_line = 3 * (s->params.pixels_per_line + 7) / 8;
2636141cc406Sopenharmony_ci       s->params.depth = 8;
2637141cc406Sopenharmony_ci       s->modes = MODES_LINEART_COLOR;
2638141cc406Sopenharmony_ci    }
2639141cc406Sopenharmony_ci  else
2640141cc406Sopenharmony_ci     {
2641141cc406Sopenharmony_ci       s->params.format = SANE_FRAME_RGB;
2642141cc406Sopenharmony_ci       s->params.bytes_per_line = 3 * s->params.pixels_per_line;
2643141cc406Sopenharmony_ci       s->params.depth = 8;
2644141cc406Sopenharmony_ci       s->modes = MODES_COLOR;
2645141cc406Sopenharmony_ci     }
2646141cc406Sopenharmony_ci  s->params.last_frame = SANE_TRUE;
2647141cc406Sopenharmony_ci
2648141cc406Sopenharmony_ci  if (params)
2649141cc406Sopenharmony_ci    *params = s->params;
2650141cc406Sopenharmony_ci
2651141cc406Sopenharmony_ci  DBG (10, ">>\n");
2652141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
2653141cc406Sopenharmony_ci}
2654141cc406Sopenharmony_ci
2655141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2656141cc406Sopenharmony_ci
2657141cc406Sopenharmony_cistatic int
2658141cc406Sopenharmony_cisprint_gamma(Option_Value val, SANE_Byte *dst)
2659141cc406Sopenharmony_ci{
2660141cc406Sopenharmony_ci  int i;
2661141cc406Sopenharmony_ci  SANE_Byte *p = dst;
2662141cc406Sopenharmony_ci
2663141cc406Sopenharmony_ci  p += sprintf((char *) p, "%i", val.wa[0]);
2664141cc406Sopenharmony_ci  for (i = 1; i < 256; i++)
2665141cc406Sopenharmony_ci    p += sprintf((char *) p, ",%i", val.wa[i] > 255 ? 255 : val.wa[i]);
2666141cc406Sopenharmony_ci  return p - dst;
2667141cc406Sopenharmony_ci}
2668141cc406Sopenharmony_ci
2669141cc406Sopenharmony_cistatic SANE_Status
2670141cc406Sopenharmony_cisend_ascii_gamma_tables (NEC_Scanner *s)
2671141cc406Sopenharmony_ci{
2672141cc406Sopenharmony_ci  SANE_Status status;
2673141cc406Sopenharmony_ci  int i;
2674141cc406Sopenharmony_ci
2675141cc406Sopenharmony_ci  DBG(11, "<< send_ascii_gamma_tables ");
2676141cc406Sopenharmony_ci
2677141cc406Sopenharmony_ci  /* we need: 4 bytes for each gamma value (3 digits + delimiter)
2678141cc406Sopenharmony_ci             + 10 bytes for the command header
2679141cc406Sopenharmony_ci     i.e. 4 * 4 * 256 + 10 = 4106 bytes
2680141cc406Sopenharmony_ci  */
2681141cc406Sopenharmony_ci
2682141cc406Sopenharmony_ci  if (s->dev->info.bufsize < 4106)
2683141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2684141cc406Sopenharmony_ci
2685141cc406Sopenharmony_ci  memset(s->buffer, 0, 4106);
2686141cc406Sopenharmony_ci
2687141cc406Sopenharmony_ci  i = sprint_gamma(s->val[OPT_GAMMA_VECTOR_R], &s->buffer[10]);
2688141cc406Sopenharmony_ci  s->buffer[10+i++] = '/';
2689141cc406Sopenharmony_ci  i += sprint_gamma(s->val[OPT_GAMMA_VECTOR_G], &s->buffer[10+i]);
2690141cc406Sopenharmony_ci  s->buffer[10+i++] = '/';
2691141cc406Sopenharmony_ci  i += sprint_gamma(s->val[OPT_GAMMA_VECTOR_B], &s->buffer[10+i]);
2692141cc406Sopenharmony_ci  s->buffer[10+i++] = '/';
2693141cc406Sopenharmony_ci  i += sprint_gamma(s->val[OPT_GAMMA_VECTOR], &s->buffer[10+i]);
2694141cc406Sopenharmony_ci
2695141cc406Sopenharmony_ci  DBG(12, "%s\n", &s->buffer[10]);
2696141cc406Sopenharmony_ci
2697141cc406Sopenharmony_ci  s->buffer[0] = SEND;
2698141cc406Sopenharmony_ci  s->buffer[2] = 0x03;
2699141cc406Sopenharmony_ci  s->buffer[7] = i >> 8;
2700141cc406Sopenharmony_ci  s->buffer[8] = i & 0xff;
2701141cc406Sopenharmony_ci
2702141cc406Sopenharmony_ci  wait_ready(s->fd);
2703141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, s->buffer, i+10, 0, 0);
2704141cc406Sopenharmony_ci
2705141cc406Sopenharmony_ci  DBG(11, ">>\n");
2706141cc406Sopenharmony_ci
2707141cc406Sopenharmony_ci  return status;
2708141cc406Sopenharmony_ci}
2709141cc406Sopenharmony_ci#endif
2710141cc406Sopenharmony_ci
2711141cc406Sopenharmony_cistatic SANE_Status
2712141cc406Sopenharmony_cisend_binary_g_table(NEC_Scanner *s, SANE_Word *a, int dtq)
2713141cc406Sopenharmony_ci{
2714141cc406Sopenharmony_ci  SANE_Status status;
2715141cc406Sopenharmony_ci  unsigned int i, j;
2716141cc406Sopenharmony_ci
2717141cc406Sopenharmony_ci  (void) dtq; /* silence compilation warnings */
2718141cc406Sopenharmony_ci
2719141cc406Sopenharmony_ci  DBG(11, "<< send_binary_g_table\n");
2720141cc406Sopenharmony_ci
2721141cc406Sopenharmony_ci  i = 256;
2722141cc406Sopenharmony_ci  if (s->dev->info.bufsize < i)
2723141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2724141cc406Sopenharmony_ci  memset(s->buffer, 0, i+10);
2725141cc406Sopenharmony_ci
2726141cc406Sopenharmony_ci  s->buffer[0] = SEND;
2727141cc406Sopenharmony_ci  s->buffer[2] = 0x03;
2728141cc406Sopenharmony_ci  s->buffer[7] = i >> 8;
2729141cc406Sopenharmony_ci  s->buffer[8] = i & 0xff;
2730141cc406Sopenharmony_ci
2731141cc406Sopenharmony_ci  for (i = 0; i < 256; i++)
2732141cc406Sopenharmony_ci    {
2733141cc406Sopenharmony_ci      s->buffer[i+11] = a[i&0xff] & 0xff;
2734141cc406Sopenharmony_ci    }
2735141cc406Sopenharmony_ci
2736141cc406Sopenharmony_ci  for (j = 0; j < 256; j += 16)
2737141cc406Sopenharmony_ci    {
2738141cc406Sopenharmony_ci      DBG(11, "%02x %02x %02x %02x %02x %02x %02x %02x "
2739141cc406Sopenharmony_ci              "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2740141cc406Sopenharmony_ci              a[j  ], a[j+1], a[j+2], a[j+3],
2741141cc406Sopenharmony_ci              a[j+4], a[j+5], a[j+6], a[j+7],
2742141cc406Sopenharmony_ci              a[j+8], a[j+9], a[j+10], a[j+11],
2743141cc406Sopenharmony_ci              a[j+12], a[j+13], a[j+14], a[j+15]);
2744141cc406Sopenharmony_ci    }
2745141cc406Sopenharmony_ci  DBG(12, "transfer length = %d\n", i);
2746141cc406Sopenharmony_ci  DBG(12, "buffer[7] = %d\n", s->buffer[7]);
2747141cc406Sopenharmony_ci  DBG(12, "buffer[8] = %d\n", s->buffer[8]);
2748141cc406Sopenharmony_ci
2749141cc406Sopenharmony_ci  /*  wait_ready(s->fd); */
2750141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, s->buffer, i+10, 0, 0);
2751141cc406Sopenharmony_ci
2752141cc406Sopenharmony_ci  DBG(11, ">>\n");
2753141cc406Sopenharmony_ci
2754141cc406Sopenharmony_ci  return status;
2755141cc406Sopenharmony_ci}
2756141cc406Sopenharmony_ci
2757141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
2758141cc406Sopenharmony_cistatic SANE_Status
2759141cc406Sopenharmony_cisend_binary_gamma_tables (NEC_Scanner *s)
2760141cc406Sopenharmony_ci{
2761141cc406Sopenharmony_ci  SANE_Status status;
2762141cc406Sopenharmony_ci
2763141cc406Sopenharmony_ci  status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR].wa, 0x10);
2764141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2765141cc406Sopenharmony_ci    return status;
2766141cc406Sopenharmony_ci  DBG(11, "send_binary_gamma_tables\n");
2767141cc406Sopenharmony_ci#if 0
2768141cc406Sopenharmony_ci  status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_R].wa, 0x11);
2769141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2770141cc406Sopenharmony_ci    return status;
2771141cc406Sopenharmony_ci
2772141cc406Sopenharmony_ci  status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_G].wa, 0x12);
2773141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2774141cc406Sopenharmony_ci    return status;
2775141cc406Sopenharmony_ci
2776141cc406Sopenharmony_ci  status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_B].wa, 0x13);
2777141cc406Sopenharmony_ci#endif
2778141cc406Sopenharmony_ci  return status;
2779141cc406Sopenharmony_ci}
2780141cc406Sopenharmony_ci
2781141cc406Sopenharmony_cistatic SANE_Status
2782141cc406Sopenharmony_cisend_gamma_tables (NEC_Scanner *s)
2783141cc406Sopenharmony_ci{
2784141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
2785141cc406Sopenharmony_ci    {
2786141cc406Sopenharmony_ci      return send_binary_gamma_tables(s);
2787141cc406Sopenharmony_ci    }
2788141cc406Sopenharmony_ci  else
2789141cc406Sopenharmony_ci    {
2790141cc406Sopenharmony_ci      return send_ascii_gamma_tables(s);
2791141cc406Sopenharmony_ci    }
2792141cc406Sopenharmony_ci
2793141cc406Sopenharmony_ci}
2794141cc406Sopenharmony_ci#endif
2795141cc406Sopenharmony_ci
2796141cc406Sopenharmony_ci#ifdef USE_COLOR_THRESHOLD
2797141cc406Sopenharmony_ci/* not used? */
2798141cc406Sopenharmony_ci#if 0
2799141cc406Sopenharmony_cistatic SANE_Status
2800141cc406Sopenharmony_cisend_threshold_data(NEC_Scanner *s)
2801141cc406Sopenharmony_ci{
2802141cc406Sopenharmony_ci  SANE_Status status;
2803141cc406Sopenharmony_ci  SANE_Byte cmd[26] = {SEND, 0, 0x82, 0, 0, 0, 0, 0, 0, 0};
2804141cc406Sopenharmony_ci  int len;
2805141cc406Sopenharmony_ci
2806141cc406Sopenharmony_ci  memset(cmd, 0, sizeof(cmd));
2807141cc406Sopenharmony_ci  /* maximum string length: 3 bytes for each number (they are
2808141cc406Sopenharmony_ci     restricted to the range 0..255), 3 '/' and the null-byte,
2809141cc406Sopenharmony_ci     total: 16 bytes.
2810141cc406Sopenharmony_ci  */
2811141cc406Sopenharmony_ci  len = sprintf((char *) &cmd[10], "%i/%i/%i/%i",
2812141cc406Sopenharmony_ci                s->val[OPT_THRESHOLD_R].w,
2813141cc406Sopenharmony_ci                s->val[OPT_THRESHOLD_G].w,
2814141cc406Sopenharmony_ci                s->val[OPT_THRESHOLD_B].w,
2815141cc406Sopenharmony_ci                s->val[OPT_THRESHOLD].w);
2816141cc406Sopenharmony_ci  cmd[8] = len;
2817141cc406Sopenharmony_ci
2818141cc406Sopenharmony_ci  wait_ready(s->fd);
2819141cc406Sopenharmony_ci  status = sanei_scsi_cmd(s->fd, cmd, len + 10, 0, 0);
2820141cc406Sopenharmony_ci  return status;
2821141cc406Sopenharmony_ci}
2822141cc406Sopenharmony_ci#endif
2823141cc406Sopenharmony_ci#endif
2824141cc406Sopenharmony_ci
2825141cc406Sopenharmony_ciSANE_Status
2826141cc406Sopenharmony_cisane_start (SANE_Handle handle)
2827141cc406Sopenharmony_ci{
2828141cc406Sopenharmony_ci  char *mode, *halftone, *gamma, *edge, *lightcolor, *adf_fsu;
2829141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
2830141cc406Sopenharmony_ci  SANE_Status status;
2831141cc406Sopenharmony_ci  size_t buf_size;
2832141cc406Sopenharmony_ci  window_param wp;
2833141cc406Sopenharmony_ci
2834141cc406Sopenharmony_ci  DBG (10, "<< sane_start ");
2835141cc406Sopenharmony_ci
2836141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the
2837141cc406Sopenharmony_ci     parameters will be overwritten below, but that's OK.  */
2838141cc406Sopenharmony_ci  status = sane_get_parameters (s, 0);
2839141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2840141cc406Sopenharmony_ci    return status;
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_ci  s->dev->sensedat.complain_on_adf_error = 1;
2843141cc406Sopenharmony_ci
2844141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
2845141cc406Sopenharmony_ci  s->dev->info.bufsize = s->dev->info.wanted_bufsize;
2846141cc406Sopenharmony_ci  if (s->dev->info.bufsize < 32 * 1024)
2847141cc406Sopenharmony_ci    s->dev->info.bufsize = 32 * 1024;
2848141cc406Sopenharmony_ci  {
2849141cc406Sopenharmony_ci    int bsize = s->dev->info.bufsize;
2850141cc406Sopenharmony_ci    status = sanei_scsi_open_extended (s->dev->sane.name, &s->fd,
2851141cc406Sopenharmony_ci              &sense_handler, &s->dev->sensedat, &bsize);
2852141cc406Sopenharmony_ci    s->dev->info.bufsize = bsize;
2853141cc406Sopenharmony_ci  }
2854141cc406Sopenharmony_ci
2855141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2856141cc406Sopenharmony_ci    {
2857141cc406Sopenharmony_ci      DBG (1, "open of %s failed: %s\n",
2858141cc406Sopenharmony_ci         s->dev->sane.name, sane_strstatus (status));
2859141cc406Sopenharmony_ci      return (status);
2860141cc406Sopenharmony_ci    }
2861141cc406Sopenharmony_ci
2862141cc406Sopenharmony_ci  /* make sure that we got at least 32 kB. Even then, the scan will be
2863141cc406Sopenharmony_ci     awfully slow.
2864141cc406Sopenharmony_ci
2865141cc406Sopenharmony_ci  */
2866141cc406Sopenharmony_ci  if (s->dev->info.bufsize < 32 * 1024)
2867141cc406Sopenharmony_ci    {
2868141cc406Sopenharmony_ci      sanei_scsi_close(s->fd);
2869141cc406Sopenharmony_ci      s->fd = -1;
2870141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2871141cc406Sopenharmony_ci    }
2872141cc406Sopenharmony_ci#else
2873141cc406Sopenharmony_ci  status = sanei_scsi_open(s->dev->sane.name, &s->fd, &sense_handler,
2874141cc406Sopenharmony_ci              &s->dev->sensedat);
2875141cc406Sopenharmony_ci  if (s->dev->info.wanted_bufsize < sanei_scsi_max_request_size)
2876141cc406Sopenharmony_ci    s->dev->info.bufsize = s->dev->info.wanted_bufsize;
2877141cc406Sopenharmony_ci  else
2878141cc406Sopenharmony_ci    s->dev->info.bufsize = sanei_scsi_max_request_size;
2879141cc406Sopenharmony_ci
2880141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2881141cc406Sopenharmony_ci    {
2882141cc406Sopenharmony_ci      DBG (1, "open of %s failed: %s\n",
2883141cc406Sopenharmony_ci         s->dev->sane.name, sane_strstatus (status));
2884141cc406Sopenharmony_ci      return (status);
2885141cc406Sopenharmony_ci    }
2886141cc406Sopenharmony_ci#endif
2887141cc406Sopenharmony_ci
2888141cc406Sopenharmony_ci  s->buffer = malloc(s->dev->info.bufsize);
2889141cc406Sopenharmony_ci  if (!s->buffer) {
2890141cc406Sopenharmony_ci    sanei_scsi_close(s->fd);
2891141cc406Sopenharmony_ci    s->fd = -1;
2892141cc406Sopenharmony_ci    free(s);
2893141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2894141cc406Sopenharmony_ci  }
2895141cc406Sopenharmony_ci
2896141cc406Sopenharmony_ci#ifdef USE_FORK
2897141cc406Sopenharmony_ci  {
2898141cc406Sopenharmony_ci    struct shmid_ds ds;
2899141cc406Sopenharmony_ci    size_t n;
2900141cc406Sopenharmony_ci
2901141cc406Sopenharmony_ci    s->shmid = shmget(IPC_PRIVATE,
2902141cc406Sopenharmony_ci       sizeof(NEC_rdr_ctl)
2903141cc406Sopenharmony_ci       + s->dev->info.buffers *
2904141cc406Sopenharmony_ci         (sizeof(NEC_shmem_ctl) + s->dev->info.bufsize),
2905141cc406Sopenharmony_ci       IPC_CREAT | 0600);
2906141cc406Sopenharmony_ci    if (s->shmid == -1)
2907141cc406Sopenharmony_ci      {
2908141cc406Sopenharmony_ci        free(s->buffer);
2909141cc406Sopenharmony_ci        s->buffer = 0;
2910141cc406Sopenharmony_ci        sanei_scsi_close(s->fd);
2911141cc406Sopenharmony_ci        s->fd = -1;
2912141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
2913141cc406Sopenharmony_ci      }
2914141cc406Sopenharmony_ci    s->rdr_ctl = (NEC_rdr_ctl*) shmat(s->shmid, 0, 0);
2915141cc406Sopenharmony_ci    if ((int)s->rdr_ctl == -1)
2916141cc406Sopenharmony_ci     {
2917141cc406Sopenharmony_ci       shmctl(s->shmid, IPC_RMID, &ds);
2918141cc406Sopenharmony_ci       free(s->buffer);
2919141cc406Sopenharmony_ci       s->buffer = 0;
2920141cc406Sopenharmony_ci       sanei_scsi_close(s->fd);
2921141cc406Sopenharmony_ci       s->fd = -1;
2922141cc406Sopenharmony_ci       return SANE_STATUS_NO_MEM;
2923141cc406Sopenharmony_ci     }
2924141cc406Sopenharmony_ci
2925141cc406Sopenharmony_ci    s->rdr_ctl->buf_ctl = (NEC_shmem_ctl*) &s->rdr_ctl[1];
2926141cc406Sopenharmony_ci    for (n = 0; n < s->dev->info.buffers; n++)
2927141cc406Sopenharmony_ci      {
2928141cc406Sopenharmony_ci        s->rdr_ctl->buf_ctl[n].buffer =
2929141cc406Sopenharmony_ci          (SANE_Byte*) &s->rdr_ctl->buf_ctl[s->dev->info.buffers]
2930141cc406Sopenharmony_ci            + n * s->dev->info.bufsize;
2931141cc406Sopenharmony_ci      }
2932141cc406Sopenharmony_ci  }
2933141cc406Sopenharmony_ci#endif /* USE_FORK */
2934141cc406Sopenharmony_ci
2935141cc406Sopenharmony_ci  DBG (5, "start: TEST_UNIT_READY\n");
2936141cc406Sopenharmony_ci  status = test_unit_ready (s->fd);
2937141cc406Sopenharmony_ci
2938141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2939141cc406Sopenharmony_ci    {
2940141cc406Sopenharmony_ci      DBG (1, "TEST UNIT READY failed: %s\n", sane_strstatus (status));
2941141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
2942141cc406Sopenharmony_ci      s->fd = -1;
2943141cc406Sopenharmony_ci      return (status);
2944141cc406Sopenharmony_ci    }
2945141cc406Sopenharmony_ci
2946141cc406Sopenharmony_ci  DBG (3, "start: sending MODE SELECT\n");
2947141cc406Sopenharmony_ci  status = mode_select_mud (s->fd, s->dev->info.mud);
2948141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2949141cc406Sopenharmony_ci    {
2950141cc406Sopenharmony_ci      DBG (1, "start: MODE_SELECT6 failed\n");
2951141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
2952141cc406Sopenharmony_ci      s->fd = -1;
2953141cc406Sopenharmony_ci      return (status);
2954141cc406Sopenharmony_ci    }
2955141cc406Sopenharmony_ci
2956141cc406Sopenharmony_ci  mode = s->val[OPT_MODE].s;
2957141cc406Sopenharmony_ci  halftone = s->val[OPT_HALFTONE].s;
2958141cc406Sopenharmony_ci  gamma = s->val[OPT_GAMMA].s;
2959141cc406Sopenharmony_ci  edge = s->val[OPT_EDGE_EMPHASIS].s;
2960141cc406Sopenharmony_ci  lightcolor = s->val[OPT_LIGHTCOLOR].s;
2961141cc406Sopenharmony_ci  adf_fsu = s->val[OPT_SCANSOURCE].s;
2962141cc406Sopenharmony_ci
2963141cc406Sopenharmony_ci  if (s->val[OPT_PREVIEW].w == SANE_FALSE)
2964141cc406Sopenharmony_ci    {
2965141cc406Sopenharmony_ci      s->res = s->val[OPT_RESOLUTION].w * s->dev->info.res_range.quant;
2966141cc406Sopenharmony_ci    }
2967141cc406Sopenharmony_ci  else
2968141cc406Sopenharmony_ci    {
2969141cc406Sopenharmony_ci      s->res = 75;
2970141cc406Sopenharmony_ci    }
2971141cc406Sopenharmony_ci  s->ulx = MM_TO_PIX(SANE_UNFIX(s->val[OPT_TL_X].w), s->dev->info.mud);
2972141cc406Sopenharmony_ci  s->uly = MM_TO_PIX(SANE_UNFIX(s->val[OPT_TL_Y].w), s->dev->info.mud);
2973141cc406Sopenharmony_ci  s->threshold = s->val[OPT_THRESHOLD].w;
2974141cc406Sopenharmony_ci
2975141cc406Sopenharmony_ci  if (strcmp (mode, M_LINEART_COLOR) == 0)
2976141cc406Sopenharmony_ci    s->bpp = 1;
2977141cc406Sopenharmony_ci  else
2978141cc406Sopenharmony_ci    s->bpp = s->params.depth;
2979141cc406Sopenharmony_ci
2980141cc406Sopenharmony_ci  s->adf_fsu_mode = SCAN_SIMPLE; /* default: scan without ADF and FSU */
2981141cc406Sopenharmony_ci
2982141cc406Sopenharmony_ci  if (strcmp(adf_fsu, use_fsu) == 0)
2983141cc406Sopenharmony_ci    s->adf_fsu_mode = SCAN_WITH_FSU;
2984141cc406Sopenharmony_ci  else if (strcmp(adf_fsu, use_adf) == 0)
2985141cc406Sopenharmony_ci    s->adf_fsu_mode = SCAN_WITH_ADF;
2986141cc406Sopenharmony_ci  else if (strcmp(adf_fsu, use_adf) == 0)
2987141cc406Sopenharmony_ci    s->adf_fsu_mode = SCAN_SIMPLE;
2988141cc406Sopenharmony_ci
2989141cc406Sopenharmony_ci  /* halftone must not set to be zero PC-IN500 */
2990141cc406Sopenharmony_ci  s->halftone = 0x01;
2991141cc406Sopenharmony_ci  if (strcmp (mode, M_LINEART) == 0)
2992141cc406Sopenharmony_ci    {
2993141cc406Sopenharmony_ci      s->reverse = 0;
2994141cc406Sopenharmony_ci      s->image_composition = 1;
2995141cc406Sopenharmony_ci      if (strcmp(halftone, M_BILEVEL) == 0)
2996141cc406Sopenharmony_ci	{
2997141cc406Sopenharmony_ci	  s->image_composition = 0;
2998141cc406Sopenharmony_ci	  s->halftone = 0x01;
2999141cc406Sopenharmony_ci	}
3000141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER1) == 0)
3001141cc406Sopenharmony_ci	s->halftone = 0x01;
3002141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER2) == 0)
3003141cc406Sopenharmony_ci	s->halftone = 0x10;
3004141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER3) == 0)
3005141cc406Sopenharmony_ci	s->halftone = 0x20;
3006141cc406Sopenharmony_ci    }
3007141cc406Sopenharmony_ci  else if (strcmp (mode, M_GRAY) == 0)
3008141cc406Sopenharmony_ci    {
3009141cc406Sopenharmony_ci      s->image_composition = 2;
3010141cc406Sopenharmony_ci      s->reverse = 1;
3011141cc406Sopenharmony_ci    }
3012141cc406Sopenharmony_ci  else if (strcmp (mode, M_LINEART_COLOR) == 0)
3013141cc406Sopenharmony_ci    {
3014141cc406Sopenharmony_ci      s->reverse = 1;
3015141cc406Sopenharmony_ci      s->image_composition = 4;
3016141cc406Sopenharmony_ci      if (strcmp(halftone, M_BILEVEL) == 0)
3017141cc406Sopenharmony_ci	{
3018141cc406Sopenharmony_ci	  s->image_composition = 3;
3019141cc406Sopenharmony_ci	  s->halftone = 0x01;
3020141cc406Sopenharmony_ci	}
3021141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER1) == 0)
3022141cc406Sopenharmony_ci	s->halftone = 0x01;
3023141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER2) == 0)
3024141cc406Sopenharmony_ci	s->halftone = 0x10;
3025141cc406Sopenharmony_ci      else if (strcmp(halftone, M_DITHER3) == 0)
3026141cc406Sopenharmony_ci	s->halftone = 0x20;
3027141cc406Sopenharmony_ci    }
3028141cc406Sopenharmony_ci  else if (strcmp (mode, M_COLOR) == 0)
3029141cc406Sopenharmony_ci    {
3030141cc406Sopenharmony_ci      s->image_composition = 5;
3031141cc406Sopenharmony_ci      s->reverse = 1;
3032141cc406Sopenharmony_ci    }
3033141cc406Sopenharmony_ci
3034141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
3035141cc406Sopenharmony_ci    {
3036141cc406Sopenharmony_ci      s->or = s->val[OPT_OR].w;
3037141cc406Sopenharmony_ci      s->nr = s->val[OPT_NR].w;
3038141cc406Sopenharmony_ci      s->edge = s->val[OPT_EDGE].w;
3039141cc406Sopenharmony_ci    }
3040141cc406Sopenharmony_ci  else
3041141cc406Sopenharmony_ci    {
3042141cc406Sopenharmony_ci      if (strcmp (edge, EDGE_NONE) == 0)
3043141cc406Sopenharmony_ci	s->edge = 0;
3044141cc406Sopenharmony_ci      else if (strcmp (edge, EDGE_MIDDLE) == 0)
3045141cc406Sopenharmony_ci	s->edge = 1;
3046141cc406Sopenharmony_ci      else if (strcmp (edge, EDGE_STRONG) == 0)
3047141cc406Sopenharmony_ci	s->edge = 2;
3048141cc406Sopenharmony_ci      else if (strcmp (edge, EDGE_BLUR) == 0)
3049141cc406Sopenharmony_ci	s->edge = 3;
3050141cc406Sopenharmony_ci    }
3051141cc406Sopenharmony_ci
3052141cc406Sopenharmony_ci  s->lightcolor = 3;
3053141cc406Sopenharmony_ci  if (strcmp(lightcolor, LIGHT_GREEN) == 0)
3054141cc406Sopenharmony_ci    s->lightcolor = 0;
3055141cc406Sopenharmony_ci  else if (strcmp(lightcolor, LIGHT_RED) == 0)
3056141cc406Sopenharmony_ci    s->lightcolor = 1;
3057141cc406Sopenharmony_ci  else if (strcmp(lightcolor, LIGHT_BLUE) == 0)
3058141cc406Sopenharmony_ci    s->lightcolor = 2;
3059141cc406Sopenharmony_ci  else if (strcmp(lightcolor, LIGHT_NONE) == 0)
3060141cc406Sopenharmony_ci    s->lightcolor = 3;
3061141cc406Sopenharmony_ci
3062141cc406Sopenharmony_ci  s->adf_scan = 0;
3063141cc406Sopenharmony_ci
3064141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
3065141cc406Sopenharmony_ci  if (s->val[OPT_CUSTOM_GAMMA].w == SANE_FALSE)
3066141cc406Sopenharmony_ci    {
3067141cc406Sopenharmony_ci#endif
3068141cc406Sopenharmony_ci      if (s->dev->sensedat.model == PCIN500)
3069141cc406Sopenharmony_ci	{
3070141cc406Sopenharmony_ci	  if (strcmp (gamma, CRT1))
3071141cc406Sopenharmony_ci	    s->gamma = 1;
3072141cc406Sopenharmony_ci	  else if (strcmp (gamma, CRT2))
3073141cc406Sopenharmony_ci	    s->gamma = 2;
3074141cc406Sopenharmony_ci	  else if (strcmp (gamma, PRINTER1))
3075141cc406Sopenharmony_ci	    s->gamma = 3;
3076141cc406Sopenharmony_ci	  else if (strcmp (gamma, PRINTER2))
3077141cc406Sopenharmony_ci	    s->gamma = 4;
3078141cc406Sopenharmony_ci	  else if (strcmp (gamma, NONE))
3079141cc406Sopenharmony_ci	    s->gamma = 5;
3080141cc406Sopenharmony_ci	}
3081141cc406Sopenharmony_ci#if 0
3082141cc406Sopenharmony_ci      if (s->dev->sensedat.model != PCIN500)
3083141cc406Sopenharmony_ci        {
3084141cc406Sopenharmony_ci          ss.dtc = 0x03;
3085141cc406Sopenharmony_ci          if (strcmp (gamma, GAMMA10) == 0)
3086141cc406Sopenharmony_ci	    ss.dtq = 0x01;
3087141cc406Sopenharmony_ci          else
3088141cc406Sopenharmony_ci	    ss.dtq = 0x02;
3089141cc406Sopenharmony_ci          ss.length = 0;
3090141cc406Sopenharmony_ci          DBG (5, "start: SEND\n");
3091141cc406Sopenharmony_ci          status = send (s->fd,  &ss);
3092141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
3093141cc406Sopenharmony_ci            {
3094141cc406Sopenharmony_ci              DBG (1, "send failed: %s\n", sane_strstatus (status));
3095141cc406Sopenharmony_ci              sanei_scsi_close (s->fd);
3096141cc406Sopenharmony_ci              s->fd = -1;
3097141cc406Sopenharmony_ci              return (status);
3098141cc406Sopenharmony_ci            }
3099141cc406Sopenharmony_ci       }
3100141cc406Sopenharmony_ci     else
3101141cc406Sopenharmony_ci#else
3102141cc406Sopenharmony_ci       {
3103141cc406Sopenharmony_ci         int i;
3104141cc406Sopenharmony_ci         SANE_Word gtbl[256];
3105141cc406Sopenharmony_ci#if 0
3106141cc406Sopenharmony_ci         if (strcmp (gamma, GAMMA10) == 0)
3107141cc406Sopenharmony_ci           for (i = 0; i < 256; i++)
3108141cc406Sopenharmony_ci             gtbl[i] = i;
3109141cc406Sopenharmony_ci         else
3110141cc406Sopenharmony_ci#endif
3111141cc406Sopenharmony_ci           {
3112141cc406Sopenharmony_ci             gtbl[0] = 0;
3113141cc406Sopenharmony_ci             for (i = 1; i < 256; i++)
3114141cc406Sopenharmony_ci               gtbl[i] = 255 * exp(0.45 * log(i/255.0));
3115141cc406Sopenharmony_ci           }
3116141cc406Sopenharmony_ci         send_binary_g_table(s, gtbl, 0x10);
3117141cc406Sopenharmony_ci         send_binary_g_table(s, gtbl, 0x11);
3118141cc406Sopenharmony_ci         send_binary_g_table(s, gtbl, 0x12);
3119141cc406Sopenharmony_ci         send_binary_g_table(s, gtbl, 0x13);
3120141cc406Sopenharmony_ci       }
3121141cc406Sopenharmony_ci#endif /* DEBUG_NEC */
3122141cc406Sopenharmony_ci#ifdef USE_CUSTOM_GAMMA
3123141cc406Sopenharmony_ci    }
3124141cc406Sopenharmony_ci  else
3125141cc406Sopenharmony_ci    {
3126141cc406Sopenharmony_ci      s->gamma = 9;
3127141cc406Sopenharmony_ci      status = send_gamma_tables(s);
3128141cc406Sopenharmony_ci    }
3129141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3130141cc406Sopenharmony_ci    {
3131141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3132141cc406Sopenharmony_ci      s->fd = -1;
3133141cc406Sopenharmony_ci      return (status);
3134141cc406Sopenharmony_ci    }
3135141cc406Sopenharmony_ci#endif
3136141cc406Sopenharmony_ci
3137141cc406Sopenharmony_ci  s->tint = s->val[OPT_TINT].w;
3138141cc406Sopenharmony_ci  s->color = s->val[OPT_COLOR].w;
3139141cc406Sopenharmony_ci
3140141cc406Sopenharmony_ci  memset (&wp, 0, sizeof (wp));
3141141cc406Sopenharmony_ci  /* every NEC scanner seems to have a different
3142141cc406Sopenharmony_ci     window descriptor block...
3143141cc406Sopenharmony_ci  */
3144141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
3145141cc406Sopenharmony_ci    buf_size = sizeof(WDB) + sizeof(WDBX500);
3146141cc406Sopenharmony_ci  else
3147141cc406Sopenharmony_ci    buf_size = sizeof(WDB);
3148141cc406Sopenharmony_ci
3149141cc406Sopenharmony_ci  wp.wpdh.wdl[0] = buf_size >> 8;
3150141cc406Sopenharmony_ci  wp.wpdh.wdl[1] = buf_size;
3151141cc406Sopenharmony_ci  wp.wdb.x_res[0] = s->res >> 8;
3152141cc406Sopenharmony_ci  wp.wdb.x_res[1] = s->res;
3153141cc406Sopenharmony_ci  wp.wdb.y_res[0] = s->res >> 8;
3154141cc406Sopenharmony_ci  wp.wdb.y_res[1] = s->res;
3155141cc406Sopenharmony_ci  wp.wdb.x_ul[0] = s->ulx >> 24;
3156141cc406Sopenharmony_ci  wp.wdb.x_ul[1] = s->ulx >> 16;
3157141cc406Sopenharmony_ci  wp.wdb.x_ul[2] = s->ulx >> 8;
3158141cc406Sopenharmony_ci  wp.wdb.x_ul[3] = s->ulx;
3159141cc406Sopenharmony_ci  wp.wdb.y_ul[0] = s->uly >> 24;
3160141cc406Sopenharmony_ci  wp.wdb.y_ul[1] = s->uly >> 16;
3161141cc406Sopenharmony_ci  wp.wdb.y_ul[2] = s->uly >> 8;
3162141cc406Sopenharmony_ci  wp.wdb.y_ul[3] = s->uly;
3163141cc406Sopenharmony_ci  wp.wdb.width[0] = s->width >> 24;
3164141cc406Sopenharmony_ci  wp.wdb.width[1] = s->width >> 16;
3165141cc406Sopenharmony_ci  wp.wdb.width[2] = s->width >> 8;
3166141cc406Sopenharmony_ci  wp.wdb.width[3] = s->width;
3167141cc406Sopenharmony_ci  wp.wdb.length[0] = s->length >> 24;
3168141cc406Sopenharmony_ci  wp.wdb.length[1] = s->length >> 16;
3169141cc406Sopenharmony_ci  wp.wdb.length[2] = s->length >> 8;
3170141cc406Sopenharmony_ci  wp.wdb.length[3] = s->length;
3171141cc406Sopenharmony_ci  wp.wdb.brightness = 0;
3172141cc406Sopenharmony_ci  wp.wdb.threshold = s->threshold;
3173141cc406Sopenharmony_ci  wp.wdb.brightness = 128;
3174141cc406Sopenharmony_ci  wp.wdb.contrast = 128;
3175141cc406Sopenharmony_ci  wp.wdb.image_composition = s->image_composition;
3176141cc406Sopenharmony_ci  if (s->image_composition <= 2 || s->image_composition >= 5)
3177141cc406Sopenharmony_ci    wp.wdb.bpp = s->bpp;
3178141cc406Sopenharmony_ci  else
3179141cc406Sopenharmony_ci    wp.wdb.bpp = 1;
3180141cc406Sopenharmony_ci  wp.wdb.ht_pattern[0] = 0;
3181141cc406Sopenharmony_ci  wp.wdb.ht_pattern[1] = 0;
3182141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
3183141cc406Sopenharmony_ci    wp.wdb.ht_pattern[1] = s->halftone;
3184141cc406Sopenharmony_ci  wp.wdb.rif_padding = (s->reverse * 128) + 0;
3185141cc406Sopenharmony_ci
3186141cc406Sopenharmony_ci  if (s->dev->sensedat.model == PCIN500)
3187141cc406Sopenharmony_ci    {
3188141cc406Sopenharmony_ci      wp.wdbx500.data_length = 0x07;
3189141cc406Sopenharmony_ci      wp.wdbx500.control = 0 | (s->or << 7) | (s->edge << 6) | (s->nr << 5) |
3190141cc406Sopenharmony_ci	                   (s->lightcolor << 2);
3191141cc406Sopenharmony_ci      wp.wdbx500.format = 0;
3192141cc406Sopenharmony_ci      wp.wdbx500.gamma = s->gamma;
3193141cc406Sopenharmony_ci      wp.wdbx500.tint = s->tint;
3194141cc406Sopenharmony_ci      wp.wdbx500.color = s->color;
3195141cc406Sopenharmony_ci      wp.wdbx500.reserved1 = 0;
3196141cc406Sopenharmony_ci      wp.wdbx500.reserved2 = 0;
3197141cc406Sopenharmony_ci    }
3198141cc406Sopenharmony_ci
3199141cc406Sopenharmony_ci  DBG (5, "wdl=%d\n", (wp.wpdh.wdl[0] << 8) + wp.wpdh.wdl[1]);
3200141cc406Sopenharmony_ci  DBG (5, "xres=%d\n", (wp.wdb.x_res[0] << 8) + wp.wdb.x_res[1]);
3201141cc406Sopenharmony_ci  DBG (5, "yres=%d\n", (wp.wdb.y_res[0] << 8) + wp.wdb.y_res[1]);
3202141cc406Sopenharmony_ci  DBG (5, "ulx=%d\n", (wp.wdb.x_ul[0] << 24) + (wp.wdb.x_ul[1] << 16) +
3203141cc406Sopenharmony_ci                      (wp.wdb.x_ul[2] << 8) + wp.wdb.x_ul[3]);
3204141cc406Sopenharmony_ci  DBG (5, "uly=%d\n", (wp.wdb.y_ul[0] << 24) + (wp.wdb.y_ul[1] << 16) +
3205141cc406Sopenharmony_ci                      (wp.wdb.y_ul[2] << 8) + wp.wdb.y_ul[3]);
3206141cc406Sopenharmony_ci  DBG (5, "width=%d\n", (wp.wdb.width[0] << 8) + (wp.wdb.width[1] << 16) +
3207141cc406Sopenharmony_ci                        (wp.wdb.width[2] << 8) + wp.wdb.width[3]);
3208141cc406Sopenharmony_ci  DBG (5, "length=%d\n", (wp.wdb.length[0] << 16) + (wp.wdb.length[1] << 16) +
3209141cc406Sopenharmony_ci                         (wp.wdb.length[2] << 8) + wp.wdb.length[3]);
3210141cc406Sopenharmony_ci
3211141cc406Sopenharmony_ci  DBG (5, "threshold=%d\n", wp.wdb.threshold);
3212141cc406Sopenharmony_ci  DBG (5, "image_composition=%d\n", wp.wdb.image_composition);
3213141cc406Sopenharmony_ci  DBG (5, "bpp=%d\n", wp.wdb.bpp);
3214141cc406Sopenharmony_ci  DBG (5, "rif_padding=%d\n", wp.wdb.rif_padding);
3215141cc406Sopenharmony_ci
3216141cc406Sopenharmony_ci#ifdef DEBUG_NEC
3217141cc406Sopenharmony_ci  {
3218141cc406Sopenharmony_ci    window_param foo;
3219141cc406Sopenharmony_ci    size_t len = buf_size;
3220141cc406Sopenharmony_ci    len += sizeof(WPDH);
3221141cc406Sopenharmony_ci  DBG (5, "start: GET WINDOW\n");
3222141cc406Sopenharmony_ci  status = get_window (s->fd, &foo, &len);
3223141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3224141cc406Sopenharmony_ci    {
3225141cc406Sopenharmony_ci      DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status));
3226141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3227141cc406Sopenharmony_ci      s->fd = -1;
3228141cc406Sopenharmony_ci      return (status);
3229141cc406Sopenharmony_ci    }
3230141cc406Sopenharmony_ci#if 1
3231141cc406Sopenharmony_ci  {
3232141cc406Sopenharmony_ci    unsigned char *p = (unsigned char*) &foo;
3233141cc406Sopenharmony_ci    int i;
3234141cc406Sopenharmony_ci    DBG(11, "get window(debug):\n");
3235141cc406Sopenharmony_ci    for (i = 0; i < len; i += 16)
3236141cc406Sopenharmony_ci     {
3237141cc406Sopenharmony_ci      DBG(1, "%2x %2x %2x %2x %2x %2x %2x %2x - %2x %2x %2x %2x %2x %2x %2x %2x\n",
3238141cc406Sopenharmony_ci      p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5], p[i+6], p[i+7], p[i+8],
3239141cc406Sopenharmony_ci      p[i+9], p[i+10], p[i+11], p[i+12], p[i+13], p[i+14], p[i+15]);
3240141cc406Sopenharmony_ci     }
3241141cc406Sopenharmony_ci  }
3242141cc406Sopenharmony_ci#endif
3243141cc406Sopenharmony_ci  foo.wpdh.wpdh[1] = 0;
3244141cc406Sopenharmony_ci  status = set_window (s->fd, &foo, len);
3245141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3246141cc406Sopenharmony_ci    {
3247141cc406Sopenharmony_ci      DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status));
3248141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3249141cc406Sopenharmony_ci      s->fd = -1;
3250141cc406Sopenharmony_ci      return (status);
3251141cc406Sopenharmony_ci    }
3252141cc406Sopenharmony_ci#if 1
3253141cc406Sopenharmony_ci  {
3254141cc406Sopenharmony_ci    unsigned char *p = (unsigned char*) &foo;
3255141cc406Sopenharmony_ci    int i;
3256141cc406Sopenharmony_ci    DBG(11, "set window(debug):\n");
3257141cc406Sopenharmony_ci    for (i = 0; i < len; i += 16)
3258141cc406Sopenharmony_ci     {
3259141cc406Sopenharmony_ci      DBG(1, "%2x %2x %2x %2x %2x %2x %2x %2x - %2x %2x %2x %2x %2x %2x %2x %2x\n",
3260141cc406Sopenharmony_ci      p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5], p[i+6], p[i+7], p[i+8],
3261141cc406Sopenharmony_ci      p[i+9], p[i+10], p[i+11], p[i+12], p[i+13], p[i+14], p[i+15]);
3262141cc406Sopenharmony_ci     }
3263141cc406Sopenharmony_ci  }
3264141cc406Sopenharmony_ci#endif
3265141cc406Sopenharmony_ci  }
3266141cc406Sopenharmony_ci#endif /* debug_nec */
3267141cc406Sopenharmony_ci
3268141cc406Sopenharmony_ci#ifdef DEBUG_NEC
3269141cc406Sopenharmony_ci  {
3270141cc406Sopenharmony_ci    unsigned char *p = (unsigned char*) &wp;
3271141cc406Sopenharmony_ci    int i;
3272141cc406Sopenharmony_ci    DBG(11, "set window(debug):\n");
3273141cc406Sopenharmony_ci    for (i = 0; i < sizeof(wp.wdb) + sizeof(wp.wdbx500); i += 16)
3274141cc406Sopenharmony_ci     {
3275141cc406Sopenharmony_ci      DBG(1, "%2x %2x %2x %2x %2x %2x %2x %2x - %2x %2x %2x %2x %2x %2x %2x %2x\n",
3276141cc406Sopenharmony_ci      p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5], p[i+6], p[i+7], p[i+8],
3277141cc406Sopenharmony_ci      p[i+9], p[i+10], p[i+11], p[i+12], p[i+13], p[i+14], p[i+15]);
3278141cc406Sopenharmony_ci     }
3279141cc406Sopenharmony_ci  }
3280141cc406Sopenharmony_ci#endif /* debug_nec */
3281141cc406Sopenharmony_ci
3282141cc406Sopenharmony_ci  buf_size += sizeof(WPDH);
3283141cc406Sopenharmony_ci  DBG (5, "start: SET WINDOW\n");
3284141cc406Sopenharmony_ci  status = set_window (s->fd, &wp, buf_size);
3285141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3286141cc406Sopenharmony_ci    {
3287141cc406Sopenharmony_ci      DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status));
3288141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3289141cc406Sopenharmony_ci      s->fd = -1;
3290141cc406Sopenharmony_ci      return (status);
3291141cc406Sopenharmony_ci    }
3292141cc406Sopenharmony_ci
3293141cc406Sopenharmony_ci  memset (&wp, 0, buf_size);
3294141cc406Sopenharmony_ci  DBG (5, "start: GET WINDOW\n");
3295141cc406Sopenharmony_ci  status = get_window (s->fd, &wp, &buf_size);
3296141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3297141cc406Sopenharmony_ci    {
3298141cc406Sopenharmony_ci      DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status));
3299141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3300141cc406Sopenharmony_ci      s->fd = -1;
3301141cc406Sopenharmony_ci      return (status);
3302141cc406Sopenharmony_ci    }
3303141cc406Sopenharmony_ci#ifdef DEBUG_NEC
3304141cc406Sopenharmony_ci  {
3305141cc406Sopenharmony_ci    unsigned char *p = (unsigned char*) &wp;
3306141cc406Sopenharmony_ci    int i;
3307141cc406Sopenharmony_ci    DBG(11, "get window(debug):\n");
3308141cc406Sopenharmony_ci    for (i = 0; i < buf_size; i += 16)
3309141cc406Sopenharmony_ci     {
3310141cc406Sopenharmony_ci      DBG(1, "%2x %2x %2x %2x %2x %2x %2x %2x - %2x %2x %2x %2x %2x %2x %2x %2x\n",
3311141cc406Sopenharmony_ci      p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5], p[i+6], p[i+7], p[i+8],
3312141cc406Sopenharmony_ci      p[i+9], p[i+10], p[i+11], p[i+12], p[i+13], p[i+14], p[i+15]);
3313141cc406Sopenharmony_ci     }
3314141cc406Sopenharmony_ci  }
3315141cc406Sopenharmony_ci#endif
3316141cc406Sopenharmony_ci  DBG (5, "xres=%d\n", (wp.wdb.x_res[0] << 8) + wp.wdb.x_res[1]);
3317141cc406Sopenharmony_ci  DBG (5, "yres=%d\n", (wp.wdb.y_res[0] << 8) + wp.wdb.y_res[1]);
3318141cc406Sopenharmony_ci  DBG (5, "ulx=%d\n", (wp.wdb.x_ul[0] << 24) + (wp.wdb.x_ul[1] << 16) +
3319141cc406Sopenharmony_ci                      (wp.wdb.x_ul[2] << 8) + wp.wdb.x_ul[3]);
3320141cc406Sopenharmony_ci  DBG (5, "uly=%d\n", (wp.wdb.y_ul[0] << 24) + (wp.wdb.y_ul[1] << 16) +
3321141cc406Sopenharmony_ci       (wp.wdb.y_ul[2] << 8) + wp.wdb.y_ul[3]);
3322141cc406Sopenharmony_ci  DBG (5, "width=%d\n", (wp.wdb.width[0] << 24) + (wp.wdb.width[1] << 16) +
3323141cc406Sopenharmony_ci                        (wp.wdb.width[2] << 8) + wp.wdb.width[3]);
3324141cc406Sopenharmony_ci  DBG (5, "length=%d\n", (wp.wdb.length[0] << 24) + (wp.wdb.length[1] << 16) +
3325141cc406Sopenharmony_ci                         (wp.wdb.length[2] << 8) + wp.wdb.length[3]);
3326141cc406Sopenharmony_ci  DBG (5, "start: SCAN\n");
3327141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
3328141cc406Sopenharmony_ci  s->busy = SANE_TRUE;
3329141cc406Sopenharmony_ci  s->cancel = SANE_FALSE;
3330141cc406Sopenharmony_ci  s->get_params_called = 0;
3331141cc406Sopenharmony_ci
3332141cc406Sopenharmony_ci  status = scan (s->fd);
3333141cc406Sopenharmony_ci#ifdef DEBUG
3334141cc406Sopenharmony_ci          {
3335141cc406Sopenharmony_ci            struct timeval t;
3336141cc406Sopenharmony_ci            gettimeofday(&t, 0);
3337141cc406Sopenharmony_ci            DBG(2, "rd: scan started        %li.%06li\n", t.tv_sec, t.tv_usec);
3338141cc406Sopenharmony_ci          }
3339141cc406Sopenharmony_ci#endif
3340141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3341141cc406Sopenharmony_ci    {
3342141cc406Sopenharmony_ci      DBG (1, "start of scan failed: %s\n", sane_strstatus (status));
3343141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
3344141cc406Sopenharmony_ci      s->fd = -1;
3345141cc406Sopenharmony_ci      s->busy = SANE_FALSE;
3346141cc406Sopenharmony_ci      s->cancel = SANE_FALSE;
3347141cc406Sopenharmony_ci      return (status);
3348141cc406Sopenharmony_ci    }
3349141cc406Sopenharmony_ci
3350141cc406Sopenharmony_ci  /* ask the scanner for the scan size */
3351141cc406Sopenharmony_ci  /* wait_ready(s->fd); */
3352141cc406Sopenharmony_ci#ifdef DEBUG
3353141cc406Sopenharmony_ci          {
3354141cc406Sopenharmony_ci            struct timeval t;
3355141cc406Sopenharmony_ci            gettimeofday(&t, 0);
3356141cc406Sopenharmony_ci            DBG(2, "rd: wait_ready ok       %li.%06li\n", t.tv_sec, t.tv_usec);
3357141cc406Sopenharmony_ci          }
3358141cc406Sopenharmony_ci#endif
3359141cc406Sopenharmony_ci  sane_get_parameters(s, 0);
3360141cc406Sopenharmony_ci#ifdef DEBUG
3361141cc406Sopenharmony_ci          {
3362141cc406Sopenharmony_ci            struct timeval t;
3363141cc406Sopenharmony_ci            gettimeofday(&t, 0);
3364141cc406Sopenharmony_ci            DBG(2, "rd: get_params ok       %li.%06li\n", t.tv_sec, t.tv_usec);
3365141cc406Sopenharmony_ci          }
3366141cc406Sopenharmony_ci#endif
3367141cc406Sopenharmony_ci  if (strcmp (mode, M_LINEART_COLOR) != 0)
3368141cc406Sopenharmony_ci    s->bytes_to_read = s->params.bytes_per_line * s->params.lines;
3369141cc406Sopenharmony_ci  else
3370141cc406Sopenharmony_ci    {
3371141cc406Sopenharmony_ci      s->bytes_to_read = s->params.bytes_per_line * s->params.lines;
3372141cc406Sopenharmony_ci    }
3373141cc406Sopenharmony_ci
3374141cc406Sopenharmony_ci#ifdef USE_FORK
3375141cc406Sopenharmony_ci  {
3376141cc406Sopenharmony_ci    size_t i;
3377141cc406Sopenharmony_ci    for (i = 0; i < s->dev->info.buffers; i++)
3378141cc406Sopenharmony_ci      s->rdr_ctl->buf_ctl[i].shm_status = SHM_EMPTY;
3379141cc406Sopenharmony_ci    s->read_buff = 0;
3380141cc406Sopenharmony_ci    s->rdr_ctl->cancel = 0;
3381141cc406Sopenharmony_ci    s->rdr_ctl->running = 0;
3382141cc406Sopenharmony_ci    s->rdr_ctl->status  = SANE_STATUS_GOOD;
3383141cc406Sopenharmony_ci  }
3384141cc406Sopenharmony_ci  s->reader_pid = fork();
3385141cc406Sopenharmony_ci#ifdef DEBUG
3386141cc406Sopenharmony_ci          {
3387141cc406Sopenharmony_ci            struct timeval t;
3388141cc406Sopenharmony_ci            gettimeofday(&t, 0);
3389141cc406Sopenharmony_ci            DBG(2, "rd: forked              %li.%06li %i\n", t.tv_sec, t.tv_usec,
3390141cc406Sopenharmony_ci              s->reader_pid);
3391141cc406Sopenharmony_ci          }
3392141cc406Sopenharmony_ci#endif
3393141cc406Sopenharmony_ci  if (s->reader_pid == 0)
3394141cc406Sopenharmony_ci    {
3395141cc406Sopenharmony_ci      sigset_t ignore_set;
3396141cc406Sopenharmony_ci      struct SIGACTION act;
3397141cc406Sopenharmony_ci
3398141cc406Sopenharmony_ci      sigfillset (&ignore_set);
3399141cc406Sopenharmony_ci      sigdelset (&ignore_set, SIGTERM);
3400141cc406Sopenharmony_ci      sigprocmask (SIG_SETMASK, &ignore_set, 0);
3401141cc406Sopenharmony_ci
3402141cc406Sopenharmony_ci      memset (&act, 0, sizeof (act));
3403141cc406Sopenharmony_ci      sigaction (SIGTERM, &act, 0);
3404141cc406Sopenharmony_ci
3405141cc406Sopenharmony_ci      /* don't use exit() since that would run the atexit() handlers... */
3406141cc406Sopenharmony_ci      _exit (reader_process (s));
3407141cc406Sopenharmony_ci    }
3408141cc406Sopenharmony_ci  else if (s->reader_pid == -1)
3409141cc406Sopenharmony_ci    {
3410141cc406Sopenharmony_ci      s->busy = SANE_FALSE;
3411141cc406Sopenharmony_ci      do_cancel(s);
3412141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3413141cc406Sopenharmony_ci    }
3414141cc406Sopenharmony_ci
3415141cc406Sopenharmony_ci#endif /* USE_FORK */
3416141cc406Sopenharmony_ci
3417141cc406Sopenharmony_ci
3418141cc406Sopenharmony_ci  DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, "
3419141cc406Sopenharmony_ci       "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line,
3420141cc406Sopenharmony_ci       s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_RESOLUTION].w);
3421141cc406Sopenharmony_ci
3422141cc406Sopenharmony_ci  s->busy = SANE_FALSE;
3423141cc406Sopenharmony_ci  s->buf_used = 0;
3424141cc406Sopenharmony_ci  s->buf_pos = 0;
3425141cc406Sopenharmony_ci
3426141cc406Sopenharmony_ci  if (s->cancel == SANE_TRUE)
3427141cc406Sopenharmony_ci    {
3428141cc406Sopenharmony_ci      do_cancel(s);
3429141cc406Sopenharmony_ci      DBG (10, ">>\n");
3430141cc406Sopenharmony_ci      return(SANE_STATUS_CANCELLED);
3431141cc406Sopenharmony_ci    }
3432141cc406Sopenharmony_ci
3433141cc406Sopenharmony_ci  DBG (10, ">>\n");
3434141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3435141cc406Sopenharmony_ci
3436141cc406Sopenharmony_ci}
3437141cc406Sopenharmony_ci
3438141cc406Sopenharmony_cistatic SANE_Status
3439141cc406Sopenharmony_cisane_read_direct (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len,
3440141cc406Sopenharmony_ci	   SANE_Int * len)
3441141cc406Sopenharmony_ci{
3442141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
3443141cc406Sopenharmony_ci  SANE_Status status;
3444141cc406Sopenharmony_ci  size_t nread;
3445141cc406Sopenharmony_ci  DBG (10, "<< sane_read_direct ");
3446141cc406Sopenharmony_ci
3447141cc406Sopenharmony_ci#if 0
3448141cc406Sopenharmony_ci  {
3449141cc406Sopenharmony_ci    buffer_status bs;
3450141cc406Sopenharmony_ci    size_t len = sizeof (buffer_status);
3451141cc406Sopenharmony_ci    get_data_buffer_status (s->fd, &bs, &len);
3452141cc406Sopenharmony_ci    DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]);
3453141cc406Sopenharmony_ci  }
3454141cc406Sopenharmony_ci#endif
3455141cc406Sopenharmony_ci  DBG (20, "remaining: %lu ", (u_long)  s->bytes_to_read);
3456141cc406Sopenharmony_ci  *len = 0;
3457141cc406Sopenharmony_ci
3458141cc406Sopenharmony_ci  if (s->bytes_to_read == 0)
3459141cc406Sopenharmony_ci    {
3460141cc406Sopenharmony_ci      do_cancel (s);
3461141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
3462141cc406Sopenharmony_ci    }
3463141cc406Sopenharmony_ci
3464141cc406Sopenharmony_ci  if (!s->scanning)
3465141cc406Sopenharmony_ci    return (do_cancel (s));
3466141cc406Sopenharmony_ci  nread = max_len;
3467141cc406Sopenharmony_ci  if (nread > s->bytes_to_read)
3468141cc406Sopenharmony_ci    nread = s->bytes_to_read;
3469141cc406Sopenharmony_ci  if (nread > s->dev->info.bufsize)
3470141cc406Sopenharmony_ci    nread = s->dev->info.bufsize;
3471141cc406Sopenharmony_ci
3472141cc406Sopenharmony_ci#ifdef USE_FORK
3473141cc406Sopenharmony_ci  status = read_data(s, dst_buf, &nread);
3474141cc406Sopenharmony_ci#else
3475141cc406Sopenharmony_ci#ifdef NOTUSE_PCIN500
3476141cc406Sopenharmony_ci  wait_ready(s->fd);
3477141cc406Sopenharmony_ci#endif
3478141cc406Sopenharmony_ci  status = read_data (s, dst_buf, &nread);
3479141cc406Sopenharmony_ci#endif
3480141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3481141cc406Sopenharmony_ci    {
3482141cc406Sopenharmony_ci      do_cancel (s);
3483141cc406Sopenharmony_ci      return (SANE_STATUS_IO_ERROR);
3484141cc406Sopenharmony_ci    }
3485141cc406Sopenharmony_ci  *len = nread;
3486141cc406Sopenharmony_ci  s->bytes_to_read -= nread;
3487141cc406Sopenharmony_ci  DBG (20, "remaining: %lu ", (u_long) s->bytes_to_read);
3488141cc406Sopenharmony_ci
3489141cc406Sopenharmony_ci  DBG (10, ">>\n");
3490141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3491141cc406Sopenharmony_ci}
3492141cc406Sopenharmony_ci
3493141cc406Sopenharmony_cistatic SANE_Status
3494141cc406Sopenharmony_cisane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len,
3495141cc406Sopenharmony_ci	   SANE_Int * len, int eight_bit_data)
3496141cc406Sopenharmony_ci{
3497141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
3498141cc406Sopenharmony_ci  SANE_Status status;
3499141cc406Sopenharmony_ci  SANE_Byte *dest, *red, *green, *blue, mask;
3500141cc406Sopenharmony_ci  SANE_Int transfer;
3501141cc406Sopenharmony_ci  size_t nread, ntest, pixel, max_pixel, line, max_line;
3502141cc406Sopenharmony_ci  size_t start_input, bytes_per_line_in;
3503141cc406Sopenharmony_ci  DBG (10, "<< sane_read_shuffled ");
3504141cc406Sopenharmony_ci
3505141cc406Sopenharmony_ci#if 0
3506141cc406Sopenharmony_ci  {
3507141cc406Sopenharmony_ci    buffer_status bs;
3508141cc406Sopenharmony_ci    size_t len = sizeof (buffer_status);
3509141cc406Sopenharmony_ci    get_data_buffer_status (s->fd, &bs, &len);
3510141cc406Sopenharmony_ci    DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]);
3511141cc406Sopenharmony_ci  }
3512141cc406Sopenharmony_ci#endif
3513141cc406Sopenharmony_ci  *len = 0;
3514141cc406Sopenharmony_ci  if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used)
3515141cc406Sopenharmony_ci    {
3516141cc406Sopenharmony_ci      do_cancel (s);
3517141cc406Sopenharmony_ci      DBG (10, ">>\n");
3518141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
3519141cc406Sopenharmony_ci    }
3520141cc406Sopenharmony_ci
3521141cc406Sopenharmony_ci  if (!s->scanning)
3522141cc406Sopenharmony_ci    {
3523141cc406Sopenharmony_ci      DBG (10, ">>\n");
3524141cc406Sopenharmony_ci      return(do_cancel(s));
3525141cc406Sopenharmony_ci    }
3526141cc406Sopenharmony_ci
3527141cc406Sopenharmony_ci  if (s->buf_pos < s->buf_used)
3528141cc406Sopenharmony_ci    {
3529141cc406Sopenharmony_ci      transfer = s->buf_used - s->buf_pos;
3530141cc406Sopenharmony_ci      if (transfer > max_len)
3531141cc406Sopenharmony_ci        transfer = max_len;
3532141cc406Sopenharmony_ci
3533141cc406Sopenharmony_ci      memcpy(dst_buf, &(s->buffer[s->buf_pos]), transfer);
3534141cc406Sopenharmony_ci      s->buf_pos += transfer;
3535141cc406Sopenharmony_ci      max_len -= transfer;
3536141cc406Sopenharmony_ci      *len = transfer;
3537141cc406Sopenharmony_ci    }
3538141cc406Sopenharmony_ci
3539141cc406Sopenharmony_ci  while (max_len > 0 && s->bytes_to_read > 0)
3540141cc406Sopenharmony_ci    {
3541141cc406Sopenharmony_ci      if (eight_bit_data)
3542141cc406Sopenharmony_ci        {
3543141cc406Sopenharmony_ci          nread = s->dev->info.bufsize / s->params.bytes_per_line - 1;
3544141cc406Sopenharmony_ci          nread *= s->params.bytes_per_line;
3545141cc406Sopenharmony_ci          if (nread > s->bytes_to_read)
3546141cc406Sopenharmony_ci            nread = s->bytes_to_read;
3547141cc406Sopenharmony_ci          max_line = nread / s->params.bytes_per_line;
3548141cc406Sopenharmony_ci          start_input = s->params.bytes_per_line;
3549141cc406Sopenharmony_ci          bytes_per_line_in = s->params.bytes_per_line;
3550141cc406Sopenharmony_ci        }
3551141cc406Sopenharmony_ci      else
3552141cc406Sopenharmony_ci        {
3553141cc406Sopenharmony_ci          bytes_per_line_in = (s->params.pixels_per_line + 7) / 8;
3554141cc406Sopenharmony_ci          bytes_per_line_in *= 3;
3555141cc406Sopenharmony_ci          max_line = s->params.bytes_per_line + bytes_per_line_in;
3556141cc406Sopenharmony_ci          max_line = s->dev->info.bufsize / max_line;
3557141cc406Sopenharmony_ci          nread = max_line * bytes_per_line_in;
3558141cc406Sopenharmony_ci          if (nread > s->bytes_to_read)
3559141cc406Sopenharmony_ci            {
3560141cc406Sopenharmony_ci              nread = s->bytes_to_read;
3561141cc406Sopenharmony_ci              max_line = nread / bytes_per_line_in;
3562141cc406Sopenharmony_ci            }
3563141cc406Sopenharmony_ci          start_input = s->dev->info.bufsize - nread;
3564141cc406Sopenharmony_ci        }
3565141cc406Sopenharmony_ci      ntest = nread;
3566141cc406Sopenharmony_ci
3567141cc406Sopenharmony_ci#ifdef USE_FORK
3568141cc406Sopenharmony_ci      status = read_data (s, &(s->buffer[start_input]), &nread);
3569141cc406Sopenharmony_ci#else
3570141cc406Sopenharmony_ci      status = read_data (s, &(s->buffer[start_input]), &nread);
3571141cc406Sopenharmony_ci#endif
3572141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3573141cc406Sopenharmony_ci        {
3574141cc406Sopenharmony_ci          do_cancel (s);
3575141cc406Sopenharmony_ci          DBG (10, ">>\n");
3576141cc406Sopenharmony_ci          return (SANE_STATUS_IO_ERROR);
3577141cc406Sopenharmony_ci        }
3578141cc406Sopenharmony_ci
3579141cc406Sopenharmony_ci      if (nread != ntest)
3580141cc406Sopenharmony_ci        {
3581141cc406Sopenharmony_ci          /* if this happens, something is wrong in the input buffer
3582141cc406Sopenharmony_ci             management...
3583141cc406Sopenharmony_ci          */
3584141cc406Sopenharmony_ci          DBG(1, "Warning: could not read an integral number of scan lines\n");
3585141cc406Sopenharmony_ci          DBG(1, "         image will be scrambled\n");
3586141cc406Sopenharmony_ci        }
3587141cc406Sopenharmony_ci
3588141cc406Sopenharmony_ci
3589141cc406Sopenharmony_ci      s->buf_used = max_line * s->params.bytes_per_line;
3590141cc406Sopenharmony_ci      s->buf_pos = 0;
3591141cc406Sopenharmony_ci      s->bytes_to_read -= nread;
3592141cc406Sopenharmony_ci      dest = s->buffer;
3593141cc406Sopenharmony_ci      max_pixel = s->params.pixels_per_line;
3594141cc406Sopenharmony_ci
3595141cc406Sopenharmony_ci      if (eight_bit_data)
3596141cc406Sopenharmony_ci        for (line = 1; line <= max_line; line++)
3597141cc406Sopenharmony_ci          {
3598141cc406Sopenharmony_ci            red = &(s->buffer[line * s->params.bytes_per_line]);
3599141cc406Sopenharmony_ci            green = &(red[max_pixel]);
3600141cc406Sopenharmony_ci            blue = &(green[max_pixel]);
3601141cc406Sopenharmony_ci            for (pixel = 0; pixel < max_pixel; pixel++)
3602141cc406Sopenharmony_ci              {
3603141cc406Sopenharmony_ci                *dest++ = *red++;
3604141cc406Sopenharmony_ci                *dest++ = *green++;
3605141cc406Sopenharmony_ci                *dest++ = *blue++;
3606141cc406Sopenharmony_ci              }
3607141cc406Sopenharmony_ci          }
3608141cc406Sopenharmony_ci      else
3609141cc406Sopenharmony_ci        for (line = 0; line < max_line; line++)
3610141cc406Sopenharmony_ci          {
3611141cc406Sopenharmony_ci            red = &(s->buffer[start_input + line * bytes_per_line_in]);
3612141cc406Sopenharmony_ci            green = &(red[(max_pixel+7)/8]);
3613141cc406Sopenharmony_ci            blue = &(green[(max_pixel+7)/8]);
3614141cc406Sopenharmony_ci            mask = 0x80;
3615141cc406Sopenharmony_ci            for (pixel = 0; pixel < max_pixel; pixel++)
3616141cc406Sopenharmony_ci              {
3617141cc406Sopenharmony_ci                *dest++ = (*red & mask)   ? 0xff : 0;
3618141cc406Sopenharmony_ci                *dest++ = (*green & mask) ? 0xff : 0;
3619141cc406Sopenharmony_ci                *dest++ = (*blue & mask)  ? 0xff : 0;
3620141cc406Sopenharmony_ci                mask = mask >> 1;
3621141cc406Sopenharmony_ci                if (mask == 0)
3622141cc406Sopenharmony_ci                  {
3623141cc406Sopenharmony_ci                    mask = 0x80;
3624141cc406Sopenharmony_ci                    red++;
3625141cc406Sopenharmony_ci                    green++;
3626141cc406Sopenharmony_ci                    blue++;
3627141cc406Sopenharmony_ci                  }
3628141cc406Sopenharmony_ci              }
3629141cc406Sopenharmony_ci          }
3630141cc406Sopenharmony_ci
3631141cc406Sopenharmony_ci      transfer = max_len;
3632141cc406Sopenharmony_ci      if (transfer > s->buf_used)
3633141cc406Sopenharmony_ci        transfer = s->buf_used;
3634141cc406Sopenharmony_ci      memcpy(&(dst_buf[*len]), s->buffer, transfer);
3635141cc406Sopenharmony_ci
3636141cc406Sopenharmony_ci      max_len -= transfer;
3637141cc406Sopenharmony_ci      s->buf_pos += transfer;
3638141cc406Sopenharmony_ci      *len += transfer;
3639141cc406Sopenharmony_ci    }
3640141cc406Sopenharmony_ci
3641141cc406Sopenharmony_ci  if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used)
3642141cc406Sopenharmony_ci    do_cancel (s);
3643141cc406Sopenharmony_ci  DBG (10, ">>\n");
3644141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
3645141cc406Sopenharmony_ci}
3646141cc406Sopenharmony_ci
3647141cc406Sopenharmony_ciSANE_Status
3648141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len,
3649141cc406Sopenharmony_ci	   SANE_Int * len)
3650141cc406Sopenharmony_ci{
3651141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
3652141cc406Sopenharmony_ci  SANE_Status status;
3653141cc406Sopenharmony_ci
3654141cc406Sopenharmony_ci  DBG (10, "<< sane_read ");
3655141cc406Sopenharmony_ci  s->busy = SANE_TRUE;
3656141cc406Sopenharmony_ci  if (s->cancel == SANE_TRUE)
3657141cc406Sopenharmony_ci    {
3658141cc406Sopenharmony_ci      do_cancel(s);
3659141cc406Sopenharmony_ci      *len = 0;
3660141cc406Sopenharmony_ci      return (SANE_STATUS_CANCELLED);
3661141cc406Sopenharmony_ci    }
3662141cc406Sopenharmony_ci
3663141cc406Sopenharmony_ci  if (s->image_composition <= 2)
3664141cc406Sopenharmony_ci    status = sane_read_direct(handle, dst_buf, max_len, len);
3665141cc406Sopenharmony_ci  else if (s->image_composition <= 4)
3666141cc406Sopenharmony_ci    status = sane_read_shuffled(handle, dst_buf, max_len, len, 0);
3667141cc406Sopenharmony_ci  else if (s->dev->sensedat.model == PCIN500)
3668141cc406Sopenharmony_ci    status = sane_read_direct(handle, dst_buf, max_len, len);
3669141cc406Sopenharmony_ci  else
3670141cc406Sopenharmony_ci    status = sane_read_shuffled(handle, dst_buf, max_len, len, 1);
3671141cc406Sopenharmony_ci
3672141cc406Sopenharmony_ci  s->busy = SANE_FALSE;
3673141cc406Sopenharmony_ci  if (s->cancel == SANE_TRUE)
3674141cc406Sopenharmony_ci    {
3675141cc406Sopenharmony_ci      do_cancel(s);
3676141cc406Sopenharmony_ci      return (SANE_STATUS_CANCELLED);
3677141cc406Sopenharmony_ci    }
3678141cc406Sopenharmony_ci
3679141cc406Sopenharmony_ci  DBG (10, ">> \n");
3680141cc406Sopenharmony_ci  return (status);
3681141cc406Sopenharmony_ci}
3682141cc406Sopenharmony_ci
3683141cc406Sopenharmony_civoid
3684141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
3685141cc406Sopenharmony_ci{
3686141cc406Sopenharmony_ci  NEC_Scanner *s = handle;
3687141cc406Sopenharmony_ci  DBG (10, "<< sane_cancel ");
3688141cc406Sopenharmony_ci
3689141cc406Sopenharmony_ci  s->cancel = SANE_TRUE;
3690141cc406Sopenharmony_ci  if (s->busy == SANE_FALSE)
3691141cc406Sopenharmony_ci      do_cancel(s);
3692141cc406Sopenharmony_ci
3693141cc406Sopenharmony_ci  DBG (10, ">>\n");
3694141cc406Sopenharmony_ci}
3695141cc406Sopenharmony_ci
3696141cc406Sopenharmony_ciSANE_Status
3697141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
3698141cc406Sopenharmony_ci{
3699141cc406Sopenharmony_ci  (void) handle;
3700141cc406Sopenharmony_ci  (void) non_blocking; /* silence compilation warnings */
3701141cc406Sopenharmony_ci
3702141cc406Sopenharmony_ci  DBG (10, "<< sane_set_io_mode");
3703141cc406Sopenharmony_ci  DBG (10, ">>\n");
3704141cc406Sopenharmony_ci
3705141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
3706141cc406Sopenharmony_ci}
3707141cc406Sopenharmony_ci
3708141cc406Sopenharmony_ciSANE_Status
3709141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
3710141cc406Sopenharmony_ci{
3711141cc406Sopenharmony_ci  (void) handle;
3712141cc406Sopenharmony_ci  (void) fd; /* silence compilation warnings */
3713141cc406Sopenharmony_ci
3714141cc406Sopenharmony_ci  DBG (10, "<< sane_get_select_fd");
3715141cc406Sopenharmony_ci  DBG (10, ">>\n");
3716141cc406Sopenharmony_ci
3717141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
3718141cc406Sopenharmony_ci}
3719