1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 1999,2000 Tom Martone
3141cc406Sopenharmony_ci   This file is part of a SANE backend for Bell and Howell Copiscan II
4141cc406Sopenharmony_ci   Scanners using the Remote SCSI Controller(RSC).
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*/
43141cc406Sopenharmony_ci#include "../include/sane/config.h"
44141cc406Sopenharmony_ci#include <limits.h>
45141cc406Sopenharmony_ci#include <errno.h>
46141cc406Sopenharmony_ci#include <fcntl.h>
47141cc406Sopenharmony_ci#include <ctype.h>
48141cc406Sopenharmony_ci#include <stdlib.h>
49141cc406Sopenharmony_ci#include <string.h>
50141cc406Sopenharmony_ci#include <stdio.h>
51141cc406Sopenharmony_ci#include <unistd.h>
52141cc406Sopenharmony_ci#include <sys/types.h>
53141cc406Sopenharmony_ci#include "../include/sane/sane.h"
54141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
55141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
56141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#define BACKEND_NAME bh
59141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
60141cc406Sopenharmony_ci#define BUILD 4
61141cc406Sopenharmony_ci
62141cc406Sopenharmony_ci#include "bh.h"
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci#define MIN(x,y) ((x)<(y) ? (x) : (y))
65141cc406Sopenharmony_ci#define MAX(x,y) ((x)>(y) ? (x) : (y))
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
68141cc406Sopenharmony_cistatic int num_devices = 0;
69141cc406Sopenharmony_cistatic BH_Device *first_dev = NULL;
70141cc406Sopenharmony_cistatic BH_Scanner *first_handle = NULL;
71141cc406Sopenharmony_cistatic SANE_Char inquiry_data[255] = "Bell+Howell scanner";
72141cc406Sopenharmony_cistatic SANE_Int disable_optional_frames = 0;
73141cc406Sopenharmony_cistatic SANE_Int fake_inquiry = 0;
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_cistatic int allblank(const char *s)
76141cc406Sopenharmony_ci{
77141cc406Sopenharmony_ci  while (s && *s)
78141cc406Sopenharmony_ci    if (!isspace(*s++))
79141cc406Sopenharmony_ci      return 0;
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci  return 1;
82141cc406Sopenharmony_ci}
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_cistatic size_t
85141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
86141cc406Sopenharmony_ci{
87141cc406Sopenharmony_ci  size_t size, max_size = 0;
88141cc406Sopenharmony_ci  int i;
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
91141cc406Sopenharmony_ci    {
92141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
93141cc406Sopenharmony_ci      if (size > max_size)
94141cc406Sopenharmony_ci        max_size = size;
95141cc406Sopenharmony_ci    }
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci  return max_size;
98141cc406Sopenharmony_ci}
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_cistatic void
101141cc406Sopenharmony_citrim_spaces(char *s, size_t n)
102141cc406Sopenharmony_ci{
103141cc406Sopenharmony_ci  for (s += (n-1); n > 0; n--, s--)
104141cc406Sopenharmony_ci    {
105141cc406Sopenharmony_ci      if (*s && !isspace(*s))
106141cc406Sopenharmony_ci	break;
107141cc406Sopenharmony_ci      *s = '\0';
108141cc406Sopenharmony_ci    }
109141cc406Sopenharmony_ci}
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_cistatic SANE_String_Const
112141cc406Sopenharmony_ciprint_devtype (SANE_Byte devtype)
113141cc406Sopenharmony_ci{
114141cc406Sopenharmony_ci  static SANE_String devtypes[] =
115141cc406Sopenharmony_ci  {
116141cc406Sopenharmony_ci    "disk",
117141cc406Sopenharmony_ci    "tape",
118141cc406Sopenharmony_ci    "printer",
119141cc406Sopenharmony_ci    "processor",
120141cc406Sopenharmony_ci    "CD-writer",
121141cc406Sopenharmony_ci    "CD-drive",
122141cc406Sopenharmony_ci    "scanner",
123141cc406Sopenharmony_ci    "optical-drive",
124141cc406Sopenharmony_ci    "jukebox",
125141cc406Sopenharmony_ci    "communicator"
126141cc406Sopenharmony_ci  };
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_ci  return (devtype > 0 && devtype < NELEMS(devtypes)) ?
129141cc406Sopenharmony_ci    devtypes[devtype] :
130141cc406Sopenharmony_ci    "unknown-device";
131141cc406Sopenharmony_ci}
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_cistatic SANE_String_Const
134141cc406Sopenharmony_ciprint_barcodetype (SANE_Int i)
135141cc406Sopenharmony_ci{
136141cc406Sopenharmony_ci  return (i > 0 && i < NELEMS(barcode_search_bar_list)) ?
137141cc406Sopenharmony_ci    barcode_search_bar_list[i] :
138141cc406Sopenharmony_ci    (SANE_String_Const) "unknown";
139141cc406Sopenharmony_ci}
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_cistatic SANE_String_Const
142141cc406Sopenharmony_ciprint_orientation (SANE_Int i)
143141cc406Sopenharmony_ci{
144141cc406Sopenharmony_ci  switch(i)
145141cc406Sopenharmony_ci    {
146141cc406Sopenharmony_ci    case 0:
147141cc406Sopenharmony_ci    case 7:
148141cc406Sopenharmony_ci      return "vertical upwards";
149141cc406Sopenharmony_ci    case 1:
150141cc406Sopenharmony_ci    case 2:
151141cc406Sopenharmony_ci      return "horizontal right";
152141cc406Sopenharmony_ci    case 3:
153141cc406Sopenharmony_ci    case 4:
154141cc406Sopenharmony_ci      return "vertical downwards";
155141cc406Sopenharmony_ci    case 5:
156141cc406Sopenharmony_ci    case 6:
157141cc406Sopenharmony_ci      return "horizontal left";
158141cc406Sopenharmony_ci    default:
159141cc406Sopenharmony_ci      return "unknown";
160141cc406Sopenharmony_ci    }
161141cc406Sopenharmony_ci}
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_cistatic SANE_String_Const
164141cc406Sopenharmony_ciprint_read_type (SANE_Int i)
165141cc406Sopenharmony_ci{
166141cc406Sopenharmony_ci  static char buf[32];
167141cc406Sopenharmony_ci  SANE_Int n;
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci  /* translate BH_SCSI_READ_TYPE_ codes to a human-readable string */
170141cc406Sopenharmony_ci  if (i == BH_SCSI_READ_TYPE_FRONT)
171141cc406Sopenharmony_ci    {
172141cc406Sopenharmony_ci      strcpy(buf, "front page");
173141cc406Sopenharmony_ci    }
174141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_BACK)
175141cc406Sopenharmony_ci    {
176141cc406Sopenharmony_ci      strcpy(buf, "back page");
177141cc406Sopenharmony_ci    }
178141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_FRONT &&
179141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_FRONT + NUM_SECTIONS)
180141cc406Sopenharmony_ci    {
181141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_FRONT;
182141cc406Sopenharmony_ci      sprintf(buf, "front section %d", n);
183141cc406Sopenharmony_ci    }
184141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_BACK &&
185141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_BACK + NUM_SECTIONS)
186141cc406Sopenharmony_ci    {
187141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_BACK;
188141cc406Sopenharmony_ci      sprintf(buf, "back section %d", n);
189141cc406Sopenharmony_ci    }
190141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_FRONT_BARCODE)
191141cc406Sopenharmony_ci    {
192141cc406Sopenharmony_ci      strcpy(buf, "front page barcode");
193141cc406Sopenharmony_ci    }
194141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_BACK_BARCODE)
195141cc406Sopenharmony_ci    {
196141cc406Sopenharmony_ci      strcpy(buf, "back page barcode");
197141cc406Sopenharmony_ci    }
198141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_FRONT_BARCODE &&
199141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_FRONT_BARCODE + NUM_SECTIONS)
200141cc406Sopenharmony_ci    {
201141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_FRONT_BARCODE;
202141cc406Sopenharmony_ci      sprintf(buf, "front barcode section %d", n);
203141cc406Sopenharmony_ci    }
204141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_BACK_BARCODE &&
205141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_BACK_BARCODE + NUM_SECTIONS)
206141cc406Sopenharmony_ci    {
207141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_BACK_BARCODE;
208141cc406Sopenharmony_ci      sprintf(buf, "back barcode section %d", n);
209141cc406Sopenharmony_ci    }
210141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_FRONT_PATCHCODE)
211141cc406Sopenharmony_ci    {
212141cc406Sopenharmony_ci      strcpy(buf, "front page patchcode");
213141cc406Sopenharmony_ci    }
214141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_BACK_PATCHCODE)
215141cc406Sopenharmony_ci    {
216141cc406Sopenharmony_ci      strcpy(buf, "back page patchcode");
217141cc406Sopenharmony_ci    }
218141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_FRONT_PATCHCODE &&
219141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_FRONT_PATCHCODE + NUM_SECTIONS)
220141cc406Sopenharmony_ci    {
221141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_FRONT_PATCHCODE;
222141cc406Sopenharmony_ci      sprintf(buf, "front patchcode section %d", n);
223141cc406Sopenharmony_ci    }
224141cc406Sopenharmony_ci  else if (i > BH_SCSI_READ_TYPE_BACK_PATCHCODE &&
225141cc406Sopenharmony_ci	   i <= BH_SCSI_READ_TYPE_BACK_PATCHCODE + NUM_SECTIONS)
226141cc406Sopenharmony_ci    {
227141cc406Sopenharmony_ci      n = i - BH_SCSI_READ_TYPE_BACK_PATCHCODE;
228141cc406Sopenharmony_ci      sprintf(buf, "back patchcode section %d", n);
229141cc406Sopenharmony_ci    }
230141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_FRONT_ICON)
231141cc406Sopenharmony_ci    {
232141cc406Sopenharmony_ci      strcpy(buf, "front page icon");
233141cc406Sopenharmony_ci    }
234141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_BACK_ICON)
235141cc406Sopenharmony_ci    {
236141cc406Sopenharmony_ci      strcpy(buf, "back page icon");
237141cc406Sopenharmony_ci    }
238141cc406Sopenharmony_ci  else if (i == BH_SCSI_READ_TYPE_SENDBARFILE)
239141cc406Sopenharmony_ci    {
240141cc406Sopenharmony_ci      strcpy(buf, "transmit bar/patch codes");
241141cc406Sopenharmony_ci    }
242141cc406Sopenharmony_ci  else
243141cc406Sopenharmony_ci    {
244141cc406Sopenharmony_ci      strcpy(buf, "unknown");
245141cc406Sopenharmony_ci    }
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci  return buf;
248141cc406Sopenharmony_ci}
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_cistatic SANE_Int
251141cc406Sopenharmony_ciget_rotation_id(char *s)
252141cc406Sopenharmony_ci{
253141cc406Sopenharmony_ci  SANE_Int i;
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci  for (i = 0; rotation_list[i]; i++)
256141cc406Sopenharmony_ci    if (strcmp(s, rotation_list[i]) == 0)
257141cc406Sopenharmony_ci      break;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci  /* unknown strings are treated as '0' */
260141cc406Sopenharmony_ci  return rotation_list[i] ? i : 0;
261141cc406Sopenharmony_ci}
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_cistatic SANE_Int
264141cc406Sopenharmony_ciget_compression_id(char *s)
265141cc406Sopenharmony_ci{
266141cc406Sopenharmony_ci  SANE_Int i;
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci  for (i = 0; compression_list[i]; i++)
269141cc406Sopenharmony_ci    if (strcmp(s, compression_list[i]) == 0)
270141cc406Sopenharmony_ci      break;
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci  /* unknown strings are treated as 'none' */
273141cc406Sopenharmony_ci  return compression_list[i] ?  i : 0;
274141cc406Sopenharmony_ci}
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_cistatic SANE_Int
277141cc406Sopenharmony_ciget_barcode_id(char *s)
278141cc406Sopenharmony_ci{
279141cc406Sopenharmony_ci  SANE_Int i;
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci  for (i = 0; barcode_search_bar_list[i]; i++)
282141cc406Sopenharmony_ci    if (strcmp(s, barcode_search_bar_list[i]) == 0)
283141cc406Sopenharmony_ci      break;
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci  /* unknown strings are treated as 'none' */
286141cc406Sopenharmony_ci  return barcode_search_bar_list[i] ?  i : 0;
287141cc406Sopenharmony_ci}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_cistatic SANE_Int
290141cc406Sopenharmony_ciget_scan_mode_id(char *s)
291141cc406Sopenharmony_ci{
292141cc406Sopenharmony_ci  SANE_Int i;
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci  for (i = 0; scan_mode_list[i]; i++)
295141cc406Sopenharmony_ci    if (strcmp(s, scan_mode_list[i]) == 0)
296141cc406Sopenharmony_ci      break;
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  /* unknown strings are treated as 'lineart' */
299141cc406Sopenharmony_ci  return scan_mode_list[i] ?  i : 0;
300141cc406Sopenharmony_ci}
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_cistatic SANE_Int
303141cc406Sopenharmony_ciget_paper_id(char *s)
304141cc406Sopenharmony_ci{
305141cc406Sopenharmony_ci  SANE_Int i;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  for (i = 0; paper_list[i]; i++)
308141cc406Sopenharmony_ci    if (strcmp(s, paper_list[i]) == 0)
309141cc406Sopenharmony_ci      break;
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci  /* unknown strings are treated as 'custom' */
312141cc406Sopenharmony_ci  return paper_list[i] ?  i : 0;
313141cc406Sopenharmony_ci}
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_cistatic SANE_Int
316141cc406Sopenharmony_ciget_barcode_search_mode(char *s)
317141cc406Sopenharmony_ci{
318141cc406Sopenharmony_ci  SANE_Int i;
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci  if (strcmp(s, "horizontal") == 0)
321141cc406Sopenharmony_ci    {
322141cc406Sopenharmony_ci      i = 1;
323141cc406Sopenharmony_ci    }
324141cc406Sopenharmony_ci  else if (strcmp(s, "vertical") == 0)
325141cc406Sopenharmony_ci    {
326141cc406Sopenharmony_ci      i = 2;
327141cc406Sopenharmony_ci    }
328141cc406Sopenharmony_ci  else if (strcmp(s, "vert-horiz") == 0)
329141cc406Sopenharmony_ci    {
330141cc406Sopenharmony_ci      i = 6;
331141cc406Sopenharmony_ci    }
332141cc406Sopenharmony_ci  else if (strcmp(s, "horiz-vert") == 0)
333141cc406Sopenharmony_ci    {
334141cc406Sopenharmony_ci      i = 9;
335141cc406Sopenharmony_ci    }
336141cc406Sopenharmony_ci  else
337141cc406Sopenharmony_ci    {
338141cc406Sopenharmony_ci      /* unknown strings are treated as 'horiz-vert' */
339141cc406Sopenharmony_ci      DBG(1, "get_barcode_search_mode: unrecognized string `%s'\n", s);
340141cc406Sopenharmony_ci      i = 9;
341141cc406Sopenharmony_ci    }
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci  return i;
344141cc406Sopenharmony_ci}
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_cistatic void
347141cc406Sopenharmony_ciappendStdList(BH_Info *sc, SANE_Int res)
348141cc406Sopenharmony_ci{
349141cc406Sopenharmony_ci  /*  append entry to resolution list - a SANE_WORD_LIST */
350141cc406Sopenharmony_ci  sc->resStdList[sc->resStdList[0]+1] = res;
351141cc406Sopenharmony_ci  sc->resStdList[0]++;
352141cc406Sopenharmony_ci}
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_cistatic void
355141cc406Sopenharmony_ciScannerDump(BH_Scanner *s)
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci  int i;
358141cc406Sopenharmony_ci  BH_Info *info;
359141cc406Sopenharmony_ci  SANE_Device *sdev;
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci  info = &s->hw->info;
362141cc406Sopenharmony_ci  sdev = &s->hw->sane;
363141cc406Sopenharmony_ci
364141cc406Sopenharmony_ci  DBG (1, "SANE Device: '%s' Vendor: '%s' Model: '%s' Type: '%s'\n",
365141cc406Sopenharmony_ci	 sdev->name,
366141cc406Sopenharmony_ci	 sdev->vendor,
367141cc406Sopenharmony_ci	 sdev->model,
368141cc406Sopenharmony_ci	 sdev->type);
369141cc406Sopenharmony_ci
370141cc406Sopenharmony_ci  DBG (1, "Type: '%s' Vendor: '%s' Product: '%s' Revision: '%s'\n",
371141cc406Sopenharmony_ci	 print_devtype(info->devtype),
372141cc406Sopenharmony_ci	 info->vendor,
373141cc406Sopenharmony_ci	 info->product,
374141cc406Sopenharmony_ci	 info->revision);
375141cc406Sopenharmony_ci
376141cc406Sopenharmony_ci  DBG (1, "Automatic Document Feeder:%s\n",
377141cc406Sopenharmony_ci	 info->canADF ? " <Installed>" : " <Not Installed>");
378141cc406Sopenharmony_ci
379141cc406Sopenharmony_ci  DBG (1, "Colors:%s%s\n", info->colorBandW ? " <Black and White>" : "",
380141cc406Sopenharmony_ci	 info->colorHalftone ? " <Halftone>" : "");
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci  DBG (1, "Data processing:%s%s%s%s%s%s\n",
383141cc406Sopenharmony_ci	 info->canWhiteFrame ? " <White Frame>" : "",
384141cc406Sopenharmony_ci	 info->canBlackFrame ? " <Black Frame>" : "",
385141cc406Sopenharmony_ci	 info->canEdgeExtract ? " <Edge Extraction>" : "",
386141cc406Sopenharmony_ci	 info->canNoiseFilter ? " <Noise Filter>" : "",
387141cc406Sopenharmony_ci	 info->canSmooth ? " <Smooth>" : "",
388141cc406Sopenharmony_ci	 info->canLineBold ? " <Line Bolding>" : "");
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci  DBG (1, "Compression:%s%s%s\n",
391141cc406Sopenharmony_ci	 info->comprG3_1D ? " <Group 3, 1D>" : "",
392141cc406Sopenharmony_ci	 info->comprG3_2D ? " <Group 3, 2D>" : "",
393141cc406Sopenharmony_ci	 info->comprG4 ? " <Group 4>" : "");
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci  DBG (1, "Optional Features:%s%s%s%s\n",
396141cc406Sopenharmony_ci	 info->canBorderRecog ? " <Border Recognition>" : "",
397141cc406Sopenharmony_ci	 info->canBarCode ? " <BarCode Decoding>" : "",
398141cc406Sopenharmony_ci	 info->canIcon ? " <Icon Generation>" : "",
399141cc406Sopenharmony_ci	 info->canSection ? " <Section Support>" : "");
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  DBG (1, "Max bytes per scan-line: %d (%d pixels)\n",
402141cc406Sopenharmony_ci	 info->lineMaxBytes,
403141cc406Sopenharmony_ci	 info->lineMaxBytes * 8);
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci  DBG (1, "Basic resolution (X/Y): %d/%d\n",
406141cc406Sopenharmony_ci	 info->resBasicX,
407141cc406Sopenharmony_ci	 info->resBasicY);
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci  DBG (1, "Maximum resolution (X/Y): %d/%d\n",
410141cc406Sopenharmony_ci	 info->resMaxX,
411141cc406Sopenharmony_ci	 info->resMaxY);
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci  DBG (1, "Minimum resolution (X/Y): %d/%d\n",
414141cc406Sopenharmony_ci	 info->resMinX,
415141cc406Sopenharmony_ci	 info->resMinY);
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci  DBG (1, "Standard Resolutions:\n");
418141cc406Sopenharmony_ci  for (i = 0; i < info->resStdList[0]; i++)
419141cc406Sopenharmony_ci    DBG (1, " %d\n", info->resStdList[i+1]);
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci  DBG (1, "Window Width/Height (in basic res) %d/%d (%.2f/%.2f inches)\n",
422141cc406Sopenharmony_ci	 info->winWidth,
423141cc406Sopenharmony_ci	 info->winHeight,
424141cc406Sopenharmony_ci	 (info->resBasicX != 0) ? ((float) info->winWidth) / info->resBasicX : 0.0,
425141cc406Sopenharmony_ci	 (info->resBasicY) ? ((float) info->winHeight) / info->resBasicY : 0.0);
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci  DBG (1, "Summary:%s%s%s\n",
428141cc406Sopenharmony_ci	 info->canDuplex ? "Duplex Scanner" : "Simplex Scanner",
429141cc406Sopenharmony_ci	 info->canACE ? " (ACE capable)" : "",
430141cc406Sopenharmony_ci	 info->canCheckADF ? " (ADF Paper Sensor capable)" : "");
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci  sprintf(inquiry_data, "Vendor: %s Product: %s Rev: %s %s%s%s\n",
433141cc406Sopenharmony_ci	 info->vendor,
434141cc406Sopenharmony_ci	 info->product,
435141cc406Sopenharmony_ci	 info->revision,
436141cc406Sopenharmony_ci	 info->canDuplex ? "Duplex Scanner" : "Simplex Scanner",
437141cc406Sopenharmony_ci	 info->canACE ? " (ACE capable)" : "",
438141cc406Sopenharmony_ci	 info->canCheckADF ? " (ADF Paper Sensor capable)" : "");
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci  DBG (5, "autoborder_default=%d\n", info->autoborder_default);
441141cc406Sopenharmony_ci  DBG (5, "batch_default=%d\n", info->batch_default);
442141cc406Sopenharmony_ci  DBG (5, "deskew_default=%d\n", info->deskew_default);
443141cc406Sopenharmony_ci  DBG (5, "check_adf_default=%d\n", info->check_adf_default);
444141cc406Sopenharmony_ci  DBG (5, "duplex_default=%d\n", info->duplex_default);
445141cc406Sopenharmony_ci  DBG (5, "timeout_adf_default=%d\n", info->timeout_adf_default);
446141cc406Sopenharmony_ci  DBG (5, "timeout_manual_default=%d\n", info->timeout_manual_default);
447141cc406Sopenharmony_ci  DBG (5, "control_panel_default=%d\n", info->control_panel_default);
448141cc406Sopenharmony_ci
449141cc406Sopenharmony_ci}
450141cc406Sopenharmony_ci
451141cc406Sopenharmony_cistatic SANE_Status
452141cc406Sopenharmony_citest_unit_ready (int fd)
453141cc406Sopenharmony_ci{
454141cc406Sopenharmony_ci  static SANE_Byte cmd[6];
455141cc406Sopenharmony_ci  SANE_Status status;
456141cc406Sopenharmony_ci  DBG (3, "test_unit_ready called\n");
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_TEST_UNIT_READY;
459141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
460141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0);
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci  return status;
463141cc406Sopenharmony_ci}
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_cistatic SANE_Status
466141cc406Sopenharmony_ciobject_position (BH_Scanner *s)
467141cc406Sopenharmony_ci{
468141cc406Sopenharmony_ci  static SANE_Byte cmd[10];
469141cc406Sopenharmony_ci  SANE_Status status;
470141cc406Sopenharmony_ci  DBG (3, "object_position called\n");
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
473141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_OBJECT_POSITION;
474141cc406Sopenharmony_ci  cmd[1] = 0x01;
475141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0);
476141cc406Sopenharmony_ci
477141cc406Sopenharmony_ci  return status;
478141cc406Sopenharmony_ci}
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_cistatic SANE_Status
481141cc406Sopenharmony_ciread_barcode_data (BH_Scanner *s, FILE *fp)
482141cc406Sopenharmony_ci{
483141cc406Sopenharmony_ci  static SANE_Byte cmd[10];
484141cc406Sopenharmony_ci  SANE_Status status;
485141cc406Sopenharmony_ci  SANE_Int num_found = 0;
486141cc406Sopenharmony_ci  double w, l, x, y, res;
487141cc406Sopenharmony_ci  struct barcode_data buf;
488141cc406Sopenharmony_ci  size_t buf_size = sizeof(buf);
489141cc406Sopenharmony_ci  DBG (3, "read_barcode_data called\n");
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
492141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_READ_SCANNED_DATA;
493141cc406Sopenharmony_ci  cmd[2] = s->readlist[s->readptr];
494141cc406Sopenharmony_ci  _lto3b(buf_size, &cmd[6]); /* transfer length */
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci  s->barcode_not_found = SANE_FALSE;
497141cc406Sopenharmony_ci  do {
498141cc406Sopenharmony_ci    memset (&buf, 0, sizeof(buf));
499141cc406Sopenharmony_ci    status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), &buf, &buf_size);
500141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
501141cc406Sopenharmony_ci      break;
502141cc406Sopenharmony_ci    if (s->barcode_not_found == SANE_TRUE)
503141cc406Sopenharmony_ci      break;
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci    num_found++;
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci    buf.barcodedata[sizeof(buf.barcodedata)-1] = '\0';
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_ci    /* calculate the bounding rectangle */
510141cc406Sopenharmony_ci    x = MIN((int) _2btol(buf.posxb), (int) _2btol(buf.posxa));
511141cc406Sopenharmony_ci    y = MIN((int) _2btol(buf.posyb), (int) _2btol(buf.posyd));
512141cc406Sopenharmony_ci    w = MAX((int) _2btol(buf.posxd), (int) _2btol(buf.posxd)) - x;
513141cc406Sopenharmony_ci    l = MAX((int) _2btol(buf.posya), (int) _2btol(buf.posyc)) - y;
514141cc406Sopenharmony_ci    /* convert from pixels to mm */
515141cc406Sopenharmony_ci    res = _OPT_VAL_WORD(s, OPT_RESOLUTION);
516141cc406Sopenharmony_ci    if (res <= 0.0)
517141cc406Sopenharmony_ci      {
518141cc406Sopenharmony_ci	/* avoid divide by zero */
519141cc406Sopenharmony_ci	DBG(1, "read_barcode_data: warning: "
520141cc406Sopenharmony_ci	    "encountered bad resolution value '%f', replacing with '%f'\n",
521141cc406Sopenharmony_ci	    res, 200.0);
522141cc406Sopenharmony_ci	res = 200.0;
523141cc406Sopenharmony_ci      }
524141cc406Sopenharmony_ci    x = x * MM_PER_INCH / res;
525141cc406Sopenharmony_ci    y = y * MM_PER_INCH / res;
526141cc406Sopenharmony_ci    w = w * MM_PER_INCH / res;
527141cc406Sopenharmony_ci    l = l * MM_PER_INCH / res;
528141cc406Sopenharmony_ci    /* add a bit of a border around the edges */
529141cc406Sopenharmony_ci    x = MAX(0.0, x - BH_DECODE_FUDGE);
530141cc406Sopenharmony_ci    y = MAX(0.0, y - BH_DECODE_FUDGE);
531141cc406Sopenharmony_ci    w += (BH_DECODE_FUDGE * 4);
532141cc406Sopenharmony_ci    l += (BH_DECODE_FUDGE * 4);
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci    /* write the decoded barcode data into the file */
535141cc406Sopenharmony_ci    fprintf(fp, "<barcode>\n <section>%s</section>\n",
536141cc406Sopenharmony_ci	    print_read_type((int) s->readlist[s->readptr]));
537141cc406Sopenharmony_ci    fprintf(fp, " <type>%s</type>\n <status-flag>%d</status-flag>\n",
538141cc406Sopenharmony_ci	    print_barcodetype((int) _2btol(buf.barcodetype)),
539141cc406Sopenharmony_ci	    (int) _2btol(buf.statusflag));
540141cc406Sopenharmony_ci    fprintf(fp, " <orientation>%s</orientation>\n",
541141cc406Sopenharmony_ci	    print_orientation((int) _2btol(buf.barcodeorientation)));
542141cc406Sopenharmony_ci    fprintf(fp, " <location>\n  <tl><x>%d</x><y>%d</y></tl>\n",
543141cc406Sopenharmony_ci	    (int) _2btol(buf.posxb), (int) _2btol(buf.posyb));
544141cc406Sopenharmony_ci    fprintf(fp, "  <tr><x>%d</x><y>%d</y></tr>\n",
545141cc406Sopenharmony_ci	    (int) _2btol(buf.posxd), (int) _2btol(buf.posyd));
546141cc406Sopenharmony_ci    fprintf(fp, "  <bl><x>%d</x><y>%d</y></bl>\n",
547141cc406Sopenharmony_ci	    (int) _2btol(buf.posxa), (int) _2btol(buf.posya));
548141cc406Sopenharmony_ci    fprintf(fp, "  <br><x>%d</x><y>%d</y></br>\n </location>\n",
549141cc406Sopenharmony_ci	    (int) _2btol(buf.posxc), (int) _2btol(buf.posyc));
550141cc406Sopenharmony_ci    fprintf(fp, " <rectangle>%.2fx%.2f+%.2f+%.2f</rectangle>\n",
551141cc406Sopenharmony_ci	    w, l, x, y);
552141cc406Sopenharmony_ci    fprintf(fp, " <search-time>%d</search-time>\n <length>%d</length>\n",
553141cc406Sopenharmony_ci	    (int) _2btol(buf.barcodesearchtime),
554141cc406Sopenharmony_ci	    (int) buf.barcodelen);
555141cc406Sopenharmony_ci    fprintf(fp, " <data>%s</data>\n</barcode>\n",
556141cc406Sopenharmony_ci	    buf.barcodedata);
557141cc406Sopenharmony_ci  } while (num_found <= BH_DECODE_TRIES);
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci  DBG (3, "read_barcode_data: found %d barcodes, returning %s\n",
560141cc406Sopenharmony_ci       num_found, sane_strstatus(status));
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci  return status;
563141cc406Sopenharmony_ci}
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_cistatic SANE_Status
566141cc406Sopenharmony_ciread_icon_data (BH_Scanner *s)
567141cc406Sopenharmony_ci{
568141cc406Sopenharmony_ci  static SANE_Byte cmd[10];
569141cc406Sopenharmony_ci  SANE_Status status;
570141cc406Sopenharmony_ci  struct icon_data buf;
571141cc406Sopenharmony_ci  size_t buf_size = sizeof(buf);
572141cc406Sopenharmony_ci  DBG (3, "read_icon_data called\n");
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
575141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_READ_SCANNED_DATA;
576141cc406Sopenharmony_ci  cmd[2] = s->readlist[s->readptr];
577141cc406Sopenharmony_ci  _lto3b(buf_size, &cmd[6]); /* transfer length */
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci  memset (&buf, 0, sizeof(buf));
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), &buf, &buf_size);
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  /* set the fields in the scanner handle for later reference */
584141cc406Sopenharmony_ci  s->iconwidth = _4btol(buf.iconwidth);
585141cc406Sopenharmony_ci  s->iconlength = _4btol(buf.iconlength);
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci  DBG(3, "read_icon_data: windowwidth:%lu, windowlength:%lu\n",
588141cc406Sopenharmony_ci      _4btol(buf.windowwidth),
589141cc406Sopenharmony_ci      _4btol(buf.windowlength));
590141cc406Sopenharmony_ci  DBG(3, "read_icon_data: iconwidth:%lu, iconlength:%lu, iconwidth(bytes):%lu\n",
591141cc406Sopenharmony_ci      _4btol(buf.iconwidth),
592141cc406Sopenharmony_ci      _4btol(buf.iconlength),
593141cc406Sopenharmony_ci      _4btol(buf.iconwidthbytes));
594141cc406Sopenharmony_ci  DBG(3, "read_icon_data: bitordering:%02x, icondatalen:%lu\n",
595141cc406Sopenharmony_ci      buf.bitordering,
596141cc406Sopenharmony_ci      _4btol(buf.icondatalen));
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci  DBG (3, "read_icon_data returning %d\n", status);
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci  return status;
601141cc406Sopenharmony_ci}
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_cistatic SANE_Status
604141cc406Sopenharmony_ciread_barfile (BH_Scanner *s, void *buf, size_t *buf_size)
605141cc406Sopenharmony_ci{
606141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
607141cc406Sopenharmony_ci  size_t nread;
608141cc406Sopenharmony_ci  DBG (3, "read_barfile called (%lu bytes)\n", (u_long) *buf_size);
609141cc406Sopenharmony_ci
610141cc406Sopenharmony_ci  if (s->barf != NULL)
611141cc406Sopenharmony_ci    {
612141cc406Sopenharmony_ci      /* this function needs to set InvalidBytes so it looks
613141cc406Sopenharmony_ci       * like a B&H scsi EOF
614141cc406Sopenharmony_ci       */
615141cc406Sopenharmony_ci      if ((nread = fread(buf, 1, *buf_size, s->barf)) < *buf_size)
616141cc406Sopenharmony_ci	{
617141cc406Sopenharmony_ci	  /* set InvalidBytes */
618141cc406Sopenharmony_ci	  s->InvalidBytes = *buf_size - nread;
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci	  if (ferror(s->barf))
621141cc406Sopenharmony_ci	    {
622141cc406Sopenharmony_ci	      status = SANE_STATUS_IO_ERROR;
623141cc406Sopenharmony_ci	      fclose(s->barf);
624141cc406Sopenharmony_ci	      s->barf = NULL;
625141cc406Sopenharmony_ci	      unlink(s->barfname);
626141cc406Sopenharmony_ci	    }
627141cc406Sopenharmony_ci	  else if (feof(s->barf))
628141cc406Sopenharmony_ci	    {
629141cc406Sopenharmony_ci	      /* it also needs to close the file and delete it when EOF is
630141cc406Sopenharmony_ci	       * reached.
631141cc406Sopenharmony_ci	       */
632141cc406Sopenharmony_ci	      fclose(s->barf);
633141cc406Sopenharmony_ci	      s->barf = NULL;
634141cc406Sopenharmony_ci	      unlink(s->barfname);
635141cc406Sopenharmony_ci	    }
636141cc406Sopenharmony_ci	}
637141cc406Sopenharmony_ci    }
638141cc406Sopenharmony_ci  else
639141cc406Sopenharmony_ci    {
640141cc406Sopenharmony_ci      /* set InvalidBytes */
641141cc406Sopenharmony_ci      s->InvalidBytes = *buf_size;
642141cc406Sopenharmony_ci    }
643141cc406Sopenharmony_ci
644141cc406Sopenharmony_ci  return status;
645141cc406Sopenharmony_ci}
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_cistatic SANE_Status
648141cc406Sopenharmony_ciread_data (BH_Scanner *s, void *buf, size_t *buf_size)
649141cc406Sopenharmony_ci{
650141cc406Sopenharmony_ci  static SANE_Byte cmd[10];
651141cc406Sopenharmony_ci  SANE_Status status;
652141cc406Sopenharmony_ci  DBG (3, "read_data called (%lu bytes)\n", (u_long) *buf_size);
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  if (s->readlist[s->readptr] == BH_SCSI_READ_TYPE_SENDBARFILE)
655141cc406Sopenharmony_ci    {
656141cc406Sopenharmony_ci      /* call special barcode data read function. */
657141cc406Sopenharmony_ci      status = read_barfile(s, buf, buf_size);
658141cc406Sopenharmony_ci    }
659141cc406Sopenharmony_ci  else
660141cc406Sopenharmony_ci    {
661141cc406Sopenharmony_ci      memset (&cmd, 0, sizeof (cmd));
662141cc406Sopenharmony_ci      cmd[0] = BH_SCSI_READ_SCANNED_DATA;
663141cc406Sopenharmony_ci      cmd[2] = s->readlist[s->readptr];
664141cc406Sopenharmony_ci      _lto3b(*buf_size, &cmd[6]); /* transfer length */
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, buf_size);
667141cc406Sopenharmony_ci    }
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci  return status;
670141cc406Sopenharmony_ci}
671141cc406Sopenharmony_ci
672141cc406Sopenharmony_cistatic SANE_Status
673141cc406Sopenharmony_cimode_select_measurement (BH_Scanner *s)
674141cc406Sopenharmony_ci{
675141cc406Sopenharmony_ci  static struct {
676141cc406Sopenharmony_ci    SANE_Byte cmd[6];
677141cc406Sopenharmony_ci    struct mode_page_03 mp;
678141cc406Sopenharmony_ci  } select_cmd;
679141cc406Sopenharmony_ci  SANE_Status status;
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ci  DBG (3, "mode_select_measurement called (bmu:%d mud:%d)\n",
682141cc406Sopenharmony_ci       s->bmu, s->mud);
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
685141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
686141cc406Sopenharmony_ci  select_cmd.cmd[1] = 0x10;
687141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  select_cmd.mp.pagecode = BH_MODE_MEASUREMENT_PAGE_CODE;
690141cc406Sopenharmony_ci  select_cmd.mp.paramlen = 0x06;
691141cc406Sopenharmony_ci  select_cmd.mp.bmu = s->bmu;
692141cc406Sopenharmony_ci  _lto2b(s->mud, select_cmd.mp.mud);
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci  return status;
697141cc406Sopenharmony_ci}
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_cistatic SANE_Status
700141cc406Sopenharmony_cimode_select_timeout (BH_Scanner *s)
701141cc406Sopenharmony_ci{
702141cc406Sopenharmony_ci  static struct {
703141cc406Sopenharmony_ci    SANE_Byte cmd[6];
704141cc406Sopenharmony_ci    struct mode_page_20 mp;
705141cc406Sopenharmony_ci  } select_cmd;
706141cc406Sopenharmony_ci  SANE_Status status;
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci  DBG (3, "mode_select_timeout called\n");
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
711141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
712141cc406Sopenharmony_ci  select_cmd.cmd[1] = 0x10;
713141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  select_cmd.mp.pagecode = BH_MODE_TIMEOUT_PAGE_CODE;
716141cc406Sopenharmony_ci  select_cmd.mp.paramlen = 0x06;
717141cc406Sopenharmony_ci  select_cmd.mp.timeoutmanual = _OPT_VAL_WORD(s, OPT_TIMEOUT_MANUAL);
718141cc406Sopenharmony_ci  select_cmd.mp.timeoutadf = _OPT_VAL_WORD(s, OPT_TIMEOUT_ADF);
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci  return status;
723141cc406Sopenharmony_ci}
724141cc406Sopenharmony_ci
725141cc406Sopenharmony_cistatic SANE_Status
726141cc406Sopenharmony_cimode_select_icon (BH_Scanner *s)
727141cc406Sopenharmony_ci{
728141cc406Sopenharmony_ci  static struct {
729141cc406Sopenharmony_ci    SANE_Byte cmd[6];
730141cc406Sopenharmony_ci    struct mode_page_21 mp;
731141cc406Sopenharmony_ci  } select_cmd;
732141cc406Sopenharmony_ci  SANE_Status status;
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci  DBG (3, "mode_select_icon called\n");
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
737141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
738141cc406Sopenharmony_ci  select_cmd.cmd[1] = 0x10;
739141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci  select_cmd.mp.pagecode = BH_MODE_ICON_PAGE_CODE;
742141cc406Sopenharmony_ci  select_cmd.mp.paramlen = 0x06;
743141cc406Sopenharmony_ci  _lto2b(_OPT_VAL_WORD(s, OPT_ICON_WIDTH), select_cmd.mp.iconwidth);
744141cc406Sopenharmony_ci  _lto2b(_OPT_VAL_WORD(s, OPT_ICON_LENGTH), select_cmd.mp.iconlength);
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci  return status;
749141cc406Sopenharmony_ci}
750141cc406Sopenharmony_ci
751141cc406Sopenharmony_cistatic SANE_Status
752141cc406Sopenharmony_cimode_select_barcode_priority (BH_Scanner *s)
753141cc406Sopenharmony_ci{
754141cc406Sopenharmony_ci  static struct {
755141cc406Sopenharmony_ci    SANE_Byte cmd[6];
756141cc406Sopenharmony_ci    struct mode_page_30 mp;
757141cc406Sopenharmony_ci  } select_cmd;
758141cc406Sopenharmony_ci  SANE_Status status;
759141cc406Sopenharmony_ci  int i;
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci  DBG (3, "mode_select_barcode_priority called\n");
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
764141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
765141cc406Sopenharmony_ci  select_cmd.cmd[1] = 0x10;
766141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
767141cc406Sopenharmony_ci
768141cc406Sopenharmony_ci  select_cmd.mp.pagecode = BH_MODE_BARCODE_PRIORITY_PAGE_CODE;
769141cc406Sopenharmony_ci  select_cmd.mp.paramlen = 0x06;
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci  for (i = 0; i < NUM_SEARCH_BARS; i++)
772141cc406Sopenharmony_ci    {
773141cc406Sopenharmony_ci      /* anything after a 'none' is ignored */
774141cc406Sopenharmony_ci      if ((select_cmd.mp.priority[i] = s->search_bars[i]) == 0) break;
775141cc406Sopenharmony_ci    }
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
778141cc406Sopenharmony_ci
779141cc406Sopenharmony_ci  return status;
780141cc406Sopenharmony_ci}
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_cistatic SANE_Status
783141cc406Sopenharmony_cimode_select_barcode_param1 (BH_Scanner *s)
784141cc406Sopenharmony_ci{
785141cc406Sopenharmony_ci  static struct {
786141cc406Sopenharmony_ci    SANE_Byte cmd[6];
787141cc406Sopenharmony_ci    struct mode_page_31 mp;
788141cc406Sopenharmony_ci  } select_cmd;
789141cc406Sopenharmony_ci  SANE_Status status;
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ci  DBG (3, "mode_select_barcode_param1 called\n");
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
794141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
795141cc406Sopenharmony_ci  select_cmd.cmd[1] = 0x10;
796141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci  select_cmd.mp.pagecode = BH_MODE_BARCODE_PARAM1_PAGE_CODE;
799141cc406Sopenharmony_ci  select_cmd.mp.paramlen = 0x06;
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ci  _lto2b((SANE_Int)_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BARCODE_HMIN), select_cmd.mp.minbarheight);
802141cc406Sopenharmony_ci  select_cmd.mp.searchcount = _OPT_VAL_WORD(s, OPT_BARCODE_SEARCH_COUNT);
803141cc406Sopenharmony_ci  select_cmd.mp.searchmode =
804141cc406Sopenharmony_ci    get_barcode_search_mode(_OPT_VAL_STRING(s, OPT_BARCODE_SEARCH_MODE));
805141cc406Sopenharmony_ci  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_SEARCH_TIMEOUT), select_cmd.mp.searchtimeout);
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci  return status;
810141cc406Sopenharmony_ci}
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_cistatic SANE_Status
813141cc406Sopenharmony_cimode_select_barcode_param2 (BH_Scanner *s)
814141cc406Sopenharmony_ci{
815141cc406Sopenharmony_ci  static struct {
816141cc406Sopenharmony_ci    SANE_Byte cmd[6];
817141cc406Sopenharmony_ci    struct mode_page_32 mp;
818141cc406Sopenharmony_ci  } select_cmd;
819141cc406Sopenharmony_ci  SANE_Status status;
820141cc406Sopenharmony_ci  size_t len;
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci  DBG (3, "mode_select_barcode_param2 called\n");
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci  /* first we'll do a mode sense, then we'll overwrite with
825141cc406Sopenharmony_ci   * our new values, and then do a mode select
826141cc406Sopenharmony_ci   */
827141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
828141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SENSE;
829141cc406Sopenharmony_ci  select_cmd.cmd[2] = BH_MODE_BARCODE_PARAM2_PAGE_CODE;
830141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci  len = sizeof(select_cmd.mp);
833141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd),
834141cc406Sopenharmony_ci			   &select_cmd.mp, &len);
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD)
837141cc406Sopenharmony_ci    {
838141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param2: sensed values: relmax:%d barmin:%d barmax:%d\n",
839141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.relmax),
840141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barmin),
841141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barmax));
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci      memset (&select_cmd.cmd, 0, sizeof (select_cmd.cmd));
844141cc406Sopenharmony_ci      select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
845141cc406Sopenharmony_ci      select_cmd.cmd[1] = 0x10;
846141cc406Sopenharmony_ci      select_cmd.cmd[4] = sizeof(select_cmd.mp);
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci      select_cmd.mp.modedatalen = 0x00;
849141cc406Sopenharmony_ci      select_cmd.mp.mediumtype = 0x00;
850141cc406Sopenharmony_ci      select_cmd.mp.devicespecificparam = 0x00;
851141cc406Sopenharmony_ci      select_cmd.mp.blockdescriptorlen = 0x00;
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci      select_cmd.mp.pagecode = BH_MODE_BARCODE_PARAM2_PAGE_CODE;
854141cc406Sopenharmony_ci      select_cmd.mp.paramlen = 0x06;
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci      /* only overwrite the default values if the option is non-zero */
857141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BARCODE_RELMAX) != 0)
858141cc406Sopenharmony_ci	{
859141cc406Sopenharmony_ci	  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_RELMAX), select_cmd.mp.relmax);
860141cc406Sopenharmony_ci	}
861141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BARCODE_BARMIN) != 0)
862141cc406Sopenharmony_ci	{
863141cc406Sopenharmony_ci	  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_BARMIN), select_cmd.mp.barmin);
864141cc406Sopenharmony_ci	}
865141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BARCODE_BARMAX) != 0)
866141cc406Sopenharmony_ci	{
867141cc406Sopenharmony_ci	  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_BARMAX), select_cmd.mp.barmax);
868141cc406Sopenharmony_ci	}
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param2: param values: relmax:%d barmin:%d barmax:%d\n",
871141cc406Sopenharmony_ci	  (int) _OPT_VAL_WORD(s, OPT_BARCODE_RELMAX),
872141cc406Sopenharmony_ci	  (int) _OPT_VAL_WORD(s, OPT_BARCODE_BARMIN),
873141cc406Sopenharmony_ci	  (int) _OPT_VAL_WORD(s, OPT_BARCODE_BARMAX));
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param2: select values: relmax:%d barmin:%d barmax:%d\n",
876141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.relmax),
877141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barmin),
878141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barmax));
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
881141cc406Sopenharmony_ci    }
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci  return status;
884141cc406Sopenharmony_ci}
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_cistatic SANE_Status
887141cc406Sopenharmony_cimode_select_barcode_param3 (BH_Scanner *s)
888141cc406Sopenharmony_ci{
889141cc406Sopenharmony_ci  static struct {
890141cc406Sopenharmony_ci    SANE_Byte cmd[6];
891141cc406Sopenharmony_ci    struct mode_page_33 mp;
892141cc406Sopenharmony_ci  } select_cmd;
893141cc406Sopenharmony_ci  SANE_Status status;
894141cc406Sopenharmony_ci  size_t len;
895141cc406Sopenharmony_ci
896141cc406Sopenharmony_ci  DBG (3, "mode_select_barcode_param3 called\n");
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci  /* first we'll do a mode sense, then we'll overwrite with
899141cc406Sopenharmony_ci   * our new values, and then do a mode select
900141cc406Sopenharmony_ci   */
901141cc406Sopenharmony_ci  memset (&select_cmd, 0, sizeof (select_cmd));
902141cc406Sopenharmony_ci  select_cmd.cmd[0] = BH_SCSI_MODE_SENSE;
903141cc406Sopenharmony_ci  select_cmd.cmd[2] = BH_MODE_BARCODE_PARAM3_PAGE_CODE;
904141cc406Sopenharmony_ci  select_cmd.cmd[4] = sizeof(select_cmd.mp);
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci  len = sizeof(select_cmd.mp);
907141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd),
908141cc406Sopenharmony_ci			   &select_cmd.mp, &len);
909141cc406Sopenharmony_ci
910141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD)
911141cc406Sopenharmony_ci    {
912141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param3: sensed values: contrast:%d patchmode:%d\n",
913141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barcodecontrast),
914141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.patchmode));
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci      memset (&select_cmd.cmd, 0, sizeof (select_cmd.cmd));
917141cc406Sopenharmony_ci      select_cmd.cmd[0] = BH_SCSI_MODE_SELECT;
918141cc406Sopenharmony_ci      select_cmd.cmd[1] = 0x10;
919141cc406Sopenharmony_ci      select_cmd.cmd[4] = sizeof(select_cmd.mp);
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci      select_cmd.mp.modedatalen = 0x00;
922141cc406Sopenharmony_ci      select_cmd.mp.mediumtype = 0x00;
923141cc406Sopenharmony_ci      select_cmd.mp.devicespecificparam = 0x00;
924141cc406Sopenharmony_ci      select_cmd.mp.blockdescriptorlen = 0x00;
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci      select_cmd.mp.pagecode = BH_MODE_BARCODE_PARAM3_PAGE_CODE;
927141cc406Sopenharmony_ci      select_cmd.mp.paramlen = 0x06;
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci      /* only overwrite the default values if the option is non-zero */
930141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BARCODE_CONTRAST) != 0)
931141cc406Sopenharmony_ci	{
932141cc406Sopenharmony_ci	  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_CONTRAST), select_cmd.mp.barcodecontrast);
933141cc406Sopenharmony_ci	}
934141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BARCODE_PATCHMODE) != 0)
935141cc406Sopenharmony_ci	{
936141cc406Sopenharmony_ci	  _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_PATCHMODE), select_cmd.mp.patchmode);
937141cc406Sopenharmony_ci	}
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param3: param values: contrast:%d patchmode:%d\n",
940141cc406Sopenharmony_ci	  (int) _OPT_VAL_WORD(s, OPT_BARCODE_CONTRAST),
941141cc406Sopenharmony_ci	  (int) _OPT_VAL_WORD(s, OPT_BARCODE_PATCHMODE));
942141cc406Sopenharmony_ci
943141cc406Sopenharmony_ci      DBG(8, "mode_select_barcode_param3: select values: contrast:%d patchmode:%d\n",
944141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.barcodecontrast),
945141cc406Sopenharmony_ci	  (int) _2btol(select_cmd.mp.patchmode));
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, &select_cmd, sizeof (select_cmd), 0, 0);
948141cc406Sopenharmony_ci    }
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci  return status;
951141cc406Sopenharmony_ci}
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_cistatic SANE_Status
954141cc406Sopenharmony_ciinquiry (int fd, void *buf, size_t *buf_size, SANE_Byte evpd, SANE_Byte page_code)
955141cc406Sopenharmony_ci{
956141cc406Sopenharmony_ci  static SANE_Byte cmd[6];
957141cc406Sopenharmony_ci  SANE_Status status;
958141cc406Sopenharmony_ci  DBG (3, "inquiry called\n");
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
961141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_INQUIRY;
962141cc406Sopenharmony_ci  cmd[1] = evpd;
963141cc406Sopenharmony_ci  cmd[2] = page_code;
964141cc406Sopenharmony_ci  cmd[4] = *buf_size;
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size);
967141cc406Sopenharmony_ci
968141cc406Sopenharmony_ci  return status;
969141cc406Sopenharmony_ci}
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_cistatic SANE_Status
972141cc406Sopenharmony_ciset_window (BH_Scanner *s, SANE_Byte batchmode)
973141cc406Sopenharmony_ci{
974141cc406Sopenharmony_ci  static struct {
975141cc406Sopenharmony_ci    SANE_Byte cmd[10];
976141cc406Sopenharmony_ci    SANE_Byte hdr[8];
977141cc406Sopenharmony_ci    struct window_data window;
978141cc406Sopenharmony_ci  } set_window_cmd;
979141cc406Sopenharmony_ci  SANE_Status status;
980141cc406Sopenharmony_ci  SANE_Int width, length, i, format, rotation, deskew ;
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci  DBG (3, "set_window called\n");
983141cc406Sopenharmony_ci
984141cc406Sopenharmony_ci  /* set to thousandths for set_window */
985141cc406Sopenharmony_ci  s->bmu = BH_UNIT_INCH;
986141cc406Sopenharmony_ci  s->mud = 1000;
987141cc406Sopenharmony_ci  status = mode_select_measurement(s);
988141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
989141cc406Sopenharmony_ci    return status;
990141cc406Sopenharmony_ci
991141cc406Sopenharmony_ci  memset (&set_window_cmd, 0, sizeof (set_window_cmd));
992141cc406Sopenharmony_ci  set_window_cmd.cmd[0] = BH_SCSI_SET_WINDOW;
993141cc406Sopenharmony_ci  DBG(3, "set_window: sizeof(hdr) %d, sizeof(window): %d\n",
994141cc406Sopenharmony_ci      (int)sizeof(set_window_cmd.hdr), (int)sizeof(set_window_cmd.window));
995141cc406Sopenharmony_ci
996141cc406Sopenharmony_ci  _lto3b(sizeof(set_window_cmd.hdr) + sizeof(set_window_cmd.window),
997141cc406Sopenharmony_ci	 &set_window_cmd.cmd[6]);
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci  _lto2b(256, &set_window_cmd.hdr[6]);
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci  set_window_cmd.window.windowid = 0;
1002141cc406Sopenharmony_ci  set_window_cmd.window.autoborder = _OPT_VAL_WORD(s, OPT_AUTOBORDER);
1003141cc406Sopenharmony_ci  DBG (5, "autoborder set to=%d\n", set_window_cmd.window.autoborder);
1004141cc406Sopenharmony_ci  _lto2b(_OPT_VAL_WORD(s, OPT_RESOLUTION), set_window_cmd.window.xres);
1005141cc406Sopenharmony_ci  _lto2b(_OPT_VAL_WORD(s, OPT_RESOLUTION), set_window_cmd.window.yres);
1006141cc406Sopenharmony_ci  _lto4b((int) _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_X), set_window_cmd.window.ulx);
1007141cc406Sopenharmony_ci  _lto4b((int) _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_Y), set_window_cmd.window.uly);
1008141cc406Sopenharmony_ci
1009141cc406Sopenharmony_ci  width = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_X) -
1010141cc406Sopenharmony_ci	 _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_X));
1011141cc406Sopenharmony_ci  length = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_Y) -
1012141cc406Sopenharmony_ci	 _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_Y));
1013141cc406Sopenharmony_ci
1014141cc406Sopenharmony_ci  _lto4b(width, set_window_cmd.window.windowwidth);
1015141cc406Sopenharmony_ci  _lto4b(length, set_window_cmd.window.windowlength);
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ci  /* brightness (1-255) 0 is default, aka 128.  Ignored with ACE scanners */
1018141cc406Sopenharmony_ci  set_window_cmd.window.brightness = _OPT_VAL_WORD(s, OPT_BRIGHTNESS);
1019141cc406Sopenharmony_ci  /* threshold (1-255) 0 is default, aka 128.  Ignored with ACE scanners */
1020141cc406Sopenharmony_ci  set_window_cmd.window.threshold = _OPT_VAL_WORD(s, OPT_THRESHOLD);
1021141cc406Sopenharmony_ci  /*!!! contrast (not used) */
1022141cc406Sopenharmony_ci  /*!!! set_window_cmd.window.contrast = _OPT_VAL_WORD(s, OPT_CONTRAST); */
1023141cc406Sopenharmony_ci  /* imagecomposition 0x00 lineart, 0x01 dithered/halftone, 0x02 grayscale*/
1024141cc406Sopenharmony_ci  set_window_cmd.window.imagecomposition =
1025141cc406Sopenharmony_ci    get_scan_mode_id(_OPT_VAL_STRING(s, OPT_SCAN_MODE));
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  set_window_cmd.window.bitsperpixel = 0x01;
1028141cc406Sopenharmony_ci  /*!!! halftone code (not used) */
1029141cc406Sopenharmony_ci  /*!!! halftone id (not used) */
1030141cc406Sopenharmony_ci
1031141cc406Sopenharmony_ci  set_window_cmd.window.paddingtype = 0x03; /* truncate byte */
1032141cc406Sopenharmony_ci  if (_OPT_VAL_WORD(s, OPT_NEGATIVE) == SANE_TRUE) {
1033141cc406Sopenharmony_ci    /* reverse image format (valid when bitsperpixel=1)
1034141cc406Sopenharmony_ci     * 0x00 normal, 0x01 reversed.  This is bit 7 of paddingtype.
1035141cc406Sopenharmony_ci     */
1036141cc406Sopenharmony_ci    set_window_cmd.window.paddingtype |= 0x80;
1037141cc406Sopenharmony_ci  }
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci  set_window_cmd.window.bitordering[0] = 0x00;
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci  /* we must always sent plain gray data in preview mode */
1042141cc406Sopenharmony_ci  format = (_OPT_VAL_WORD(s, OPT_PREVIEW)) ?
1043141cc406Sopenharmony_ci    BH_COMP_NONE :
1044141cc406Sopenharmony_ci    get_compression_id(_OPT_VAL_STRING(s, OPT_COMPRESSION));
1045141cc406Sopenharmony_ci
1046141cc406Sopenharmony_ci  switch (format)
1047141cc406Sopenharmony_ci    {
1048141cc406Sopenharmony_ci    case BH_COMP_G31D:
1049141cc406Sopenharmony_ci      set_window_cmd.window.compressiontype = 0x01;
1050141cc406Sopenharmony_ci      set_window_cmd.window.compressionarg = 0x00;
1051141cc406Sopenharmony_ci      set_window_cmd.window.bitordering[1] = 0x01; /* Bit ordering LSB */
1052141cc406Sopenharmony_ci      break;
1053141cc406Sopenharmony_ci    case BH_COMP_G32D:
1054141cc406Sopenharmony_ci      set_window_cmd.window.compressiontype = 0x02;
1055141cc406Sopenharmony_ci      set_window_cmd.window.compressionarg = 0x04;
1056141cc406Sopenharmony_ci      set_window_cmd.window.bitordering[1] = 0x01; /* Bit ordering LSB */
1057141cc406Sopenharmony_ci      break;
1058141cc406Sopenharmony_ci    case BH_COMP_G42D:
1059141cc406Sopenharmony_ci      set_window_cmd.window.compressiontype = 0x03;
1060141cc406Sopenharmony_ci      set_window_cmd.window.compressionarg = 0x00;
1061141cc406Sopenharmony_ci      set_window_cmd.window.bitordering[1] = 0x01; /* Bit ordering LSB */
1062141cc406Sopenharmony_ci      break;
1063141cc406Sopenharmony_ci    case BH_COMP_NONE:
1064141cc406Sopenharmony_ci    default:
1065141cc406Sopenharmony_ci      set_window_cmd.window.compressiontype = 0x00;
1066141cc406Sopenharmony_ci      set_window_cmd.window.compressionarg = 0x00;
1067141cc406Sopenharmony_ci      set_window_cmd.window.bitordering[1] = 0x00; /* n/a */
1068141cc406Sopenharmony_ci      break;
1069141cc406Sopenharmony_ci    }
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  /* rotation and deskew settings, if autoborder is turned on */
1072141cc406Sopenharmony_ci  if(set_window_cmd.window.autoborder){ /*--- setting byte 46 of the window descriptor block only works with autoborder */
1073141cc406Sopenharmony_ci    rotation = get_rotation_id(_OPT_VAL_STRING(s, OPT_ROTATION));
1074141cc406Sopenharmony_ci    if (_OPT_VAL_WORD(s, OPT_DESKEW) == SANE_TRUE) deskew = BH_DESKEW_ENABLE;
1075141cc406Sopenharmony_ci    else deskew = BH_DESKEW_DISABLE;
1076141cc406Sopenharmony_ci    set_window_cmd.window.border_rotation = ( rotation | deskew );  /*--- deskew assumes autoborder */
1077141cc406Sopenharmony_ci  }
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci  /* remote - 0x00 ACE set in window; 0x01 ACE set by control panel */
1080141cc406Sopenharmony_ci  set_window_cmd.window.remote = _OPT_VAL_WORD(s, OPT_CONTROL_PANEL);
1081141cc406Sopenharmony_ci  if (set_window_cmd.window.remote == 0x00) {
1082141cc406Sopenharmony_ci    /* acefunction (ignored on non-ACE scanners) */
1083141cc406Sopenharmony_ci    set_window_cmd.window.acefunction = _OPT_VAL_WORD(s, OPT_ACE_FUNCTION);
1084141cc406Sopenharmony_ci    /* acesensitivity (ignored on non-ACE scanners) */
1085141cc406Sopenharmony_ci    set_window_cmd.window.acesensitivity = _OPT_VAL_WORD(s, OPT_ACE_SENSITIVITY);
1086141cc406Sopenharmony_ci  }
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  set_window_cmd.window.batchmode = batchmode;
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci  /* fill in the section descriptor blocks */
1091141cc406Sopenharmony_ci  for (i = 0; i < s->num_sections; i++)
1092141cc406Sopenharmony_ci    {
1093141cc406Sopenharmony_ci      BH_SectionBlock *b;
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci      b = &set_window_cmd.window.sectionblock[i];
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci      _lto4b(s->sections[i].left, b->ul_x);
1098141cc406Sopenharmony_ci      _lto4b(s->sections[i].top, b->ul_y);
1099141cc406Sopenharmony_ci      _lto4b(s->sections[i].width, b->width);
1100141cc406Sopenharmony_ci      _lto4b(s->sections[i].length, b->length);
1101141cc406Sopenharmony_ci      b->compressiontype = s->sections[i].compressiontype;
1102141cc406Sopenharmony_ci      b->compressionarg = s->sections[i].compressionarg;
1103141cc406Sopenharmony_ci    }
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &set_window_cmd, sizeof (set_window_cmd), 0, 0);
1106141cc406Sopenharmony_ci  DBG (5, "sanei_scsi_cmd executed, status=%d\n", status );
1107141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1108141cc406Sopenharmony_ci    return status;
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci  /* set to points for reading */
1111141cc406Sopenharmony_ci  s->bmu = BH_UNIT_POINT;
1112141cc406Sopenharmony_ci  s->mud = 1;
1113141cc406Sopenharmony_ci  status = mode_select_measurement(s);
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  return status;
1116141cc406Sopenharmony_ci}
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_cistatic SANE_Status
1119141cc406Sopenharmony_ciget_window (BH_Scanner *s, SANE_Int *w, SANE_Int *h, SANE_Bool backpage)
1120141cc406Sopenharmony_ci{
1121141cc406Sopenharmony_ci  SANE_Byte cmd[10];
1122141cc406Sopenharmony_ci  static struct {
1123141cc406Sopenharmony_ci    SANE_Byte hdr[8];
1124141cc406Sopenharmony_ci    struct window_data window;
1125141cc406Sopenharmony_ci  } get_window_data;
1126141cc406Sopenharmony_ci  SANE_Status status;
1127141cc406Sopenharmony_ci  SANE_Int x, y, i = 0, get_window_delay = 1;
1128141cc406Sopenharmony_ci  SANE_Bool autoborder;
1129141cc406Sopenharmony_ci  size_t len;
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_ci  DBG (3, "get_window called\n");
1132141cc406Sopenharmony_ci
1133141cc406Sopenharmony_ci  autoborder = _OPT_VAL_WORD(s, OPT_AUTOBORDER) == 1;
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci  while (1)
1136141cc406Sopenharmony_ci    {
1137141cc406Sopenharmony_ci      i++;
1138141cc406Sopenharmony_ci      memset (&cmd, 0, sizeof (cmd));
1139141cc406Sopenharmony_ci      memset (&get_window_data, 0, sizeof (get_window_data));
1140141cc406Sopenharmony_ci
1141141cc406Sopenharmony_ci      cmd[0] = BH_SCSI_GET_WINDOW;
1142141cc406Sopenharmony_ci      _lto3b(sizeof(get_window_data), &cmd[6]);
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_ci      _lto2b(256, &get_window_data.hdr[6]);
1145141cc406Sopenharmony_ci
1146141cc406Sopenharmony_ci      get_window_data.window.windowid = (backpage == SANE_TRUE) ? 1 : 0;
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci      len = sizeof(get_window_data);
1149141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd),
1150141cc406Sopenharmony_ci			       &get_window_data, &len);
1151141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
1152141cc406Sopenharmony_ci	{
1153141cc406Sopenharmony_ci	  x =_4btol(get_window_data.window.ulx);
1154141cc406Sopenharmony_ci	  y =_4btol(get_window_data.window.uly);
1155141cc406Sopenharmony_ci	  *w =_4btol(get_window_data.window.windowwidth);
1156141cc406Sopenharmony_ci	  *h =_4btol(get_window_data.window.windowlength);
1157141cc406Sopenharmony_ci
1158141cc406Sopenharmony_ci	  if (autoborder)
1159141cc406Sopenharmony_ci	    {
1160141cc406Sopenharmony_ci	      /* we try repeatedly until we get the autoborder bit set */
1161141cc406Sopenharmony_ci	      if (get_window_data.window.autoborder != 1 &&
1162141cc406Sopenharmony_ci		  i < BH_AUTOBORDER_TRIES)
1163141cc406Sopenharmony_ci		{
1164141cc406Sopenharmony_ci	          DBG (5, "waiting %d second[s], try: %d\n",get_window_delay,i);
1165141cc406Sopenharmony_ci		  sleep(get_window_delay);  /*--- page 4-5 of B&H Copiscan 8000 ESC OEM Tech Manual */
1166141cc406Sopenharmony_ci                                            /*--- requires at least 50ms wait between each GET WINDOW command */
1167141cc406Sopenharmony_ci                                            /*--- experience shows that this can take 3 to 4 seconds */
1168141cc406Sopenharmony_ci		  continue;
1169141cc406Sopenharmony_ci		}
1170141cc406Sopenharmony_ci	      if (get_window_data.window.autoborder != 1)
1171141cc406Sopenharmony_ci		{
1172141cc406Sopenharmony_ci		  DBG(1, "Automatic Border Detection not done within %d tries\n",
1173141cc406Sopenharmony_ci		      BH_AUTOBORDER_TRIES);
1174141cc406Sopenharmony_ci		  status = SANE_STATUS_IO_ERROR;
1175141cc406Sopenharmony_ci		}
1176141cc406Sopenharmony_ci             DBG (0, "page dimension: wide:%d high:%d \n",*w,*h);
1177141cc406Sopenharmony_ci	    }
1178141cc406Sopenharmony_ci	  DBG (3, "*** Window size: %dx%d+%d+%d\n", *w, *h, x, y);
1179141cc406Sopenharmony_ci	  DBG (5, "*** get_window found autoborder=%02xh\n", get_window_data.window.autoborder);
1180141cc406Sopenharmony_ci	  DBG (5, "*** get_window found border_rotation=%02xh\n", get_window_data.window.border_rotation);
1181141cc406Sopenharmony_ci	}
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci      /* we are 'outta here' */
1184141cc406Sopenharmony_ci      break;
1185141cc406Sopenharmony_ci    }
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci  return status;
1188141cc406Sopenharmony_ci}
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_cistatic SANE_Status
1191141cc406Sopenharmony_ciget_parameters (SANE_Handle handle, SANE_Parameters *params)
1192141cc406Sopenharmony_ci{
1193141cc406Sopenharmony_ci  BH_Scanner *s = handle;
1194141cc406Sopenharmony_ci  SANE_Int width, length, res, comp;
1195141cc406Sopenharmony_ci  double br_x, tl_x, br_y, tl_y;
1196141cc406Sopenharmony_ci  SANE_Frame format;
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci  DBG(3, "get_parameters called\n");
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci  memset (&s->params, 0, sizeof (s->params));
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci  res = _OPT_VAL_WORD(s, OPT_RESOLUTION);
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci  /* make best-effort guess at what parameters will look like once
1205141cc406Sopenharmony_ci     the scan starts.  */
1206141cc406Sopenharmony_ci
1207141cc406Sopenharmony_ci  br_x = _OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_X);
1208141cc406Sopenharmony_ci  br_y = _OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_Y);
1209141cc406Sopenharmony_ci  tl_x = _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_X);
1210141cc406Sopenharmony_ci  tl_y = _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_Y);
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci  width = (br_x - tl_x + 1) * res / 1000.0;
1213141cc406Sopenharmony_ci  length = (br_y - tl_y + 1) * res / 1000.0;
1214141cc406Sopenharmony_ci
1215141cc406Sopenharmony_ci  /* figure out the default image format for front/back pages */
1216141cc406Sopenharmony_ci  comp = get_compression_id(_OPT_VAL_STRING(s, OPT_COMPRESSION));
1217141cc406Sopenharmony_ci  switch (comp)
1218141cc406Sopenharmony_ci    {
1219141cc406Sopenharmony_ci    case BH_COMP_G31D:
1220141cc406Sopenharmony_ci      format = SANE_FRAME_G31D;
1221141cc406Sopenharmony_ci      break;
1222141cc406Sopenharmony_ci    case BH_COMP_G32D:
1223141cc406Sopenharmony_ci      format = SANE_FRAME_G32D;
1224141cc406Sopenharmony_ci      break;
1225141cc406Sopenharmony_ci    case BH_COMP_G42D:
1226141cc406Sopenharmony_ci      format = SANE_FRAME_G42D;
1227141cc406Sopenharmony_ci      break;
1228141cc406Sopenharmony_ci    case BH_COMP_NONE:
1229141cc406Sopenharmony_ci    default:
1230141cc406Sopenharmony_ci      format = SANE_FRAME_GRAY;
1231141cc406Sopenharmony_ci      break;
1232141cc406Sopenharmony_ci    }
1233141cc406Sopenharmony_ci
1234141cc406Sopenharmony_ci  if (s->scanning)
1235141cc406Sopenharmony_ci    {
1236141cc406Sopenharmony_ci      SANE_Int w, l, status;
1237141cc406Sopenharmony_ci      SANE_Byte itemtype;
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci      itemtype = s->readlist[s->readptr];
1240141cc406Sopenharmony_ci      /* update parameters based on the current item */
1241141cc406Sopenharmony_ci
1242141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
1243141cc406Sopenharmony_ci      if (itemtype == BH_SCSI_READ_TYPE_FRONT)
1244141cc406Sopenharmony_ci	{
1245141cc406Sopenharmony_ci	  DBG (3, "get_parameters: sending GET WINDOW (front)\n");
1246141cc406Sopenharmony_ci	  status = get_window (s, &w, &l, SANE_FALSE);
1247141cc406Sopenharmony_ci	  if (status == SANE_STATUS_GOOD)
1248141cc406Sopenharmony_ci	    {
1249141cc406Sopenharmony_ci	      width = w;
1250141cc406Sopenharmony_ci	      length = l;
1251141cc406Sopenharmony_ci	    }
1252141cc406Sopenharmony_ci	}
1253141cc406Sopenharmony_ci      else if (itemtype == BH_SCSI_READ_TYPE_BACK)
1254141cc406Sopenharmony_ci	{
1255141cc406Sopenharmony_ci	  DBG (3, "get_parameters: sending GET WINDOW (back)\n");
1256141cc406Sopenharmony_ci	  status = get_window (s, &w, &l, SANE_TRUE);
1257141cc406Sopenharmony_ci	  if (status == SANE_STATUS_GOOD)
1258141cc406Sopenharmony_ci	    {
1259141cc406Sopenharmony_ci	      width = w;
1260141cc406Sopenharmony_ci	      length = l;
1261141cc406Sopenharmony_ci	    }
1262141cc406Sopenharmony_ci	}
1263141cc406Sopenharmony_ci      else if (itemtype == BH_SCSI_READ_TYPE_FRONT_ICON ||
1264141cc406Sopenharmony_ci	       itemtype == BH_SCSI_READ_TYPE_BACK_ICON)
1265141cc406Sopenharmony_ci	{
1266141cc406Sopenharmony_ci	  /* the icon is never compressed */
1267141cc406Sopenharmony_ci	  format = SANE_FRAME_GRAY;
1268141cc406Sopenharmony_ci	  width = s->iconwidth;
1269141cc406Sopenharmony_ci	  length = s->iconlength;
1270141cc406Sopenharmony_ci	}
1271141cc406Sopenharmony_ci      else if (itemtype > BH_SCSI_READ_TYPE_FRONT &&
1272141cc406Sopenharmony_ci	       itemtype <= (BH_SCSI_READ_TYPE_FRONT + NUM_SECTIONS))
1273141cc406Sopenharmony_ci	{
1274141cc406Sopenharmony_ci	  /* a front section */
1275141cc406Sopenharmony_ci	  SANE_Int sectnum = itemtype - BH_SCSI_READ_TYPE_FRONT;
1276141cc406Sopenharmony_ci
1277141cc406Sopenharmony_ci	  format = s->sections[sectnum - 1].format;
1278141cc406Sopenharmony_ci	  /* convert from thousandths to pixels */
1279141cc406Sopenharmony_ci	  width = s->sections[sectnum - 1].width * res / 1000.0;
1280141cc406Sopenharmony_ci	  length = s->sections[sectnum - 1].length * res / 1000.0;
1281141cc406Sopenharmony_ci	}
1282141cc406Sopenharmony_ci      else if (itemtype > BH_SCSI_READ_TYPE_BACK &&
1283141cc406Sopenharmony_ci	       itemtype <= (BH_SCSI_READ_TYPE_BACK + NUM_SECTIONS))
1284141cc406Sopenharmony_ci	{
1285141cc406Sopenharmony_ci	  /* a back section */
1286141cc406Sopenharmony_ci	  SANE_Int sectnum = itemtype - BH_SCSI_READ_TYPE_BACK;
1287141cc406Sopenharmony_ci
1288141cc406Sopenharmony_ci	  format = s->sections[sectnum - 1].format;
1289141cc406Sopenharmony_ci	  /* convert from thousandths to pixels */
1290141cc406Sopenharmony_ci	  width = s->sections[sectnum - 1].width * res / 1000.0;
1291141cc406Sopenharmony_ci	  length = s->sections[sectnum - 1].length * res / 1000.0;
1292141cc406Sopenharmony_ci	}
1293141cc406Sopenharmony_ci      else if ( (itemtype >= BH_SCSI_READ_TYPE_BACK_BARCODE &&
1294141cc406Sopenharmony_ci		 itemtype <= (BH_SCSI_READ_TYPE_BACK_BARCODE + NUM_SECTIONS)) ||
1295141cc406Sopenharmony_ci		(itemtype >= BH_SCSI_READ_TYPE_FRONT_BARCODE &&
1296141cc406Sopenharmony_ci		 itemtype <= (BH_SCSI_READ_TYPE_FRONT_BARCODE + NUM_SECTIONS)) )
1297141cc406Sopenharmony_ci	{
1298141cc406Sopenharmony_ci	  /* decoded barcode data */
1299141cc406Sopenharmony_ci	  format = SANE_FRAME_TEXT;
1300141cc406Sopenharmony_ci	  width = 8;
1301141cc406Sopenharmony_ci	  length = -1;
1302141cc406Sopenharmony_ci	}
1303141cc406Sopenharmony_ci      else if (itemtype == BH_SCSI_READ_TYPE_SENDBARFILE)
1304141cc406Sopenharmony_ci	{
1305141cc406Sopenharmony_ci	  /* decoded barcode data file */
1306141cc406Sopenharmony_ci	  format = SANE_FRAME_TEXT;
1307141cc406Sopenharmony_ci	  width = 8;
1308141cc406Sopenharmony_ci	  length = -1;
1309141cc406Sopenharmony_ci	}
1310141cc406Sopenharmony_ci      else
1311141cc406Sopenharmony_ci	{
1312141cc406Sopenharmony_ci	  format = SANE_FRAME_GRAY;
1313141cc406Sopenharmony_ci	  width = 8;
1314141cc406Sopenharmony_ci	  length = -1;
1315141cc406Sopenharmony_ci	  DBG(1, "get_parameters: unrecognized read itemtype: %d\n",
1316141cc406Sopenharmony_ci	      itemtype);
1317141cc406Sopenharmony_ci	}
1318141cc406Sopenharmony_ci
1319141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1320141cc406Sopenharmony_ci	{
1321141cc406Sopenharmony_ci	  DBG(1, "get_parameters: failed\n");
1322141cc406Sopenharmony_ci	  return status;
1323141cc406Sopenharmony_ci	}
1324141cc406Sopenharmony_ci    }
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  if (res <= 0 || width <= 0)
1327141cc406Sopenharmony_ci    {
1328141cc406Sopenharmony_ci      DBG(1, "get_parameters:illegal parameters res=%d, width=%d, length=%d\n",
1329141cc406Sopenharmony_ci	  res, width, length);
1330141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1331141cc406Sopenharmony_ci    }
1332141cc406Sopenharmony_ci
1333141cc406Sopenharmony_ci  /* we disable our compression/barcode formats in preview as well
1334141cc406Sopenharmony_ci   * as with the disable_optional_frames configuration option.  NOTE:
1335141cc406Sopenharmony_ci   * we may still be delivering 'wierd' data and lying about it being _GRAY!
1336141cc406Sopenharmony_ci   */
1337141cc406Sopenharmony_ci  if (format != SANE_FRAME_GRAY &&
1338141cc406Sopenharmony_ci      (_OPT_VAL_WORD(s, OPT_PREVIEW) || disable_optional_frames))
1339141cc406Sopenharmony_ci    {
1340141cc406Sopenharmony_ci      DBG(1, "get_parameters: warning: delivering %s data as gray",
1341141cc406Sopenharmony_ci	  sane_strframe(format));
1342141cc406Sopenharmony_ci      format = SANE_FRAME_GRAY;
1343141cc406Sopenharmony_ci    }
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci  s->params.format = format;
1346141cc406Sopenharmony_ci  s->params.depth = 1;
1347141cc406Sopenharmony_ci  s->params.last_frame = SANE_TRUE;
1348141cc406Sopenharmony_ci  s->params.pixels_per_line = width;
1349141cc406Sopenharmony_ci  s->params.lines = length;
1350141cc406Sopenharmony_ci  s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
1351141cc406Sopenharmony_ci  /* The Bell and Howell truncates to the byte */
1352141cc406Sopenharmony_ci  s->params.pixels_per_line = s->params.bytes_per_line * 8;
1353141cc406Sopenharmony_ci
1354141cc406Sopenharmony_ci  if (params)
1355141cc406Sopenharmony_ci    *params = s->params;
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci  DBG (1, "get_parameters: format=%d, pixels/line=%d, bytes/line=%d, "
1358141cc406Sopenharmony_ci       "lines=%d, dpi=%d\n",
1359141cc406Sopenharmony_ci       (int) s->params.format,
1360141cc406Sopenharmony_ci       s->params.pixels_per_line,
1361141cc406Sopenharmony_ci       s->params.bytes_per_line,
1362141cc406Sopenharmony_ci       s->params.lines,
1363141cc406Sopenharmony_ci       res);
1364141cc406Sopenharmony_ci
1365141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1366141cc406Sopenharmony_ci}
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_cistatic SANE_Status
1369141cc406Sopenharmony_cisection_parse(const char *val, BH_Section *sect, SANE_Int res, SANE_Int comp)
1370141cc406Sopenharmony_ci{
1371141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_INVAL;
1372141cc406Sopenharmony_ci  char buf[255+1], *x, *y, *w, *l, *f, *ep;
1373141cc406Sopenharmony_ci  const char *seps = "x+:";
1374141cc406Sopenharmony_ci  double mm, fpixels;
1375141cc406Sopenharmony_ci  u_long pixels;
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci  DBG(3, "section_parse called\n");
1378141cc406Sopenharmony_ci
1379141cc406Sopenharmony_ci  /* a section option looks something like this:
1380141cc406Sopenharmony_ci   * <width>x<length>+<tl-x>+<tl-y>:<functioncodes>
1381141cc406Sopenharmony_ci   * Example:
1382141cc406Sopenharmony_ci   * 76.2x25.4+50.8+0:frontbar:back:front
1383141cc406Sopenharmony_ci   * the width, length, tl-x, and tl-y are in mm.
1384141cc406Sopenharmony_ci   * the function codes are one or more of:
1385141cc406Sopenharmony_ci   * front, back, frontbar, backbar, frontpatch, backpatch
1386141cc406Sopenharmony_ci   */
1387141cc406Sopenharmony_ci  if (strlen(val) > sizeof(buf) - 1)
1388141cc406Sopenharmony_ci    {
1389141cc406Sopenharmony_ci      DBG(1, "section_parse: option string too long\n");
1390141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
1391141cc406Sopenharmony_ci    }
1392141cc406Sopenharmony_ci  else
1393141cc406Sopenharmony_ci    {
1394141cc406Sopenharmony_ci      do {
1395141cc406Sopenharmony_ci	strcpy(buf, val);
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_ci	x = y = w = l = f = NULL;
1398141cc406Sopenharmony_ci	w = strtok(buf, seps);
1399141cc406Sopenharmony_ci	if (w) l = strtok(NULL, seps);
1400141cc406Sopenharmony_ci	if (l) x = strtok(NULL, seps);
1401141cc406Sopenharmony_ci	if (x) y = strtok(NULL, seps);
1402141cc406Sopenharmony_ci	if (y) f = strtok(NULL, seps);
1403141cc406Sopenharmony_ci	if (!x || !y || !w || !l) break;
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci	mm = strtod(x, &ep);
1406141cc406Sopenharmony_ci	if (*ep != '\0' || errno == ERANGE || mm < 0.0) break;
1407141cc406Sopenharmony_ci	sect->left = mm * 1000.0 / MM_PER_INCH;
1408141cc406Sopenharmony_ci
1409141cc406Sopenharmony_ci	mm = strtod(y, &ep);
1410141cc406Sopenharmony_ci	if (*ep != '\0' || errno == ERANGE || mm < 0.0) break;
1411141cc406Sopenharmony_ci	sect->top = mm * 1000.0 / MM_PER_INCH;
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci	mm = strtod(w, &ep);
1414141cc406Sopenharmony_ci	if (*ep != '\0' || errno == ERANGE || mm < 0.0) break;
1415141cc406Sopenharmony_ci	sect->width = mm * 1000.0 / MM_PER_INCH;
1416141cc406Sopenharmony_ci	/* the window width must be truncated to 16 bit points */
1417141cc406Sopenharmony_ci	fpixels = sect->width * res / 1000.0;
1418141cc406Sopenharmony_ci	pixels = fpixels / 16;
1419141cc406Sopenharmony_ci	sect->width = pixels * 16 * 1000 / res;
1420141cc406Sopenharmony_ci
1421141cc406Sopenharmony_ci	mm = strtod(l, &ep);
1422141cc406Sopenharmony_ci	if (*ep != '\0' || errno == ERANGE || mm < 0.0) break;
1423141cc406Sopenharmony_ci	sect->length = mm * 1000.0 / MM_PER_INCH;
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci	status = SANE_STATUS_GOOD;
1426141cc406Sopenharmony_ci	while (f)
1427141cc406Sopenharmony_ci	  {
1428141cc406Sopenharmony_ci	    /* parse the function modifiers and set flags */
1429141cc406Sopenharmony_ci	    if (strcmp(f, "front") == 0)
1430141cc406Sopenharmony_ci	      sect->flags |= BH_SECTION_FRONT_IMAGE;
1431141cc406Sopenharmony_ci	    else if (strcmp(f, "frontbar") == 0)
1432141cc406Sopenharmony_ci	      sect->flags |= BH_SECTION_FRONT_BAR;
1433141cc406Sopenharmony_ci	    else if (strcmp(f, "frontpatch") == 0)
1434141cc406Sopenharmony_ci	      sect->flags |= BH_SECTION_FRONT_PATCH;
1435141cc406Sopenharmony_ci	    else if (strcmp(f, "back") == 0)
1436141cc406Sopenharmony_ci		sect->flags |= BH_SECTION_BACK_IMAGE;
1437141cc406Sopenharmony_ci	    else if (strcmp(f, "backbar") == 0)
1438141cc406Sopenharmony_ci		sect->flags |= BH_SECTION_BACK_BAR;
1439141cc406Sopenharmony_ci	    else if (strcmp(f, "backpatch") == 0)
1440141cc406Sopenharmony_ci		sect->flags |= BH_SECTION_BACK_PATCH;
1441141cc406Sopenharmony_ci	    else if (strcmp(f, "g42d") == 0)
1442141cc406Sopenharmony_ci		comp = BH_COMP_G42D;
1443141cc406Sopenharmony_ci	    else if (strcmp(f, "g32d") == 0)
1444141cc406Sopenharmony_ci		comp = BH_COMP_G32D;
1445141cc406Sopenharmony_ci	    else if (strcmp(f, "g31d") == 0)
1446141cc406Sopenharmony_ci		comp = BH_COMP_G31D;
1447141cc406Sopenharmony_ci	    else if (strcmp(f, "none") == 0)
1448141cc406Sopenharmony_ci		comp = BH_COMP_NONE;
1449141cc406Sopenharmony_ci	    else
1450141cc406Sopenharmony_ci	      DBG(1, "section_parse: ignoring unrecognized function "
1451141cc406Sopenharmony_ci		  "code '%s'\n", f);
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci	    f = strtok(NULL, seps);
1454141cc406Sopenharmony_ci	  }
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci	switch (comp)
1457141cc406Sopenharmony_ci	  {
1458141cc406Sopenharmony_ci	  case BH_COMP_G31D:
1459141cc406Sopenharmony_ci	    sect->compressiontype = 0x01;
1460141cc406Sopenharmony_ci	    sect->compressionarg = 0x00;
1461141cc406Sopenharmony_ci	    sect->format = SANE_FRAME_G31D;
1462141cc406Sopenharmony_ci	    break;
1463141cc406Sopenharmony_ci	  case BH_COMP_G32D:
1464141cc406Sopenharmony_ci	    sect->compressiontype = 0x02;
1465141cc406Sopenharmony_ci	    sect->compressionarg = 0x04;
1466141cc406Sopenharmony_ci	    sect->format = SANE_FRAME_G32D;
1467141cc406Sopenharmony_ci	    break;
1468141cc406Sopenharmony_ci	  case BH_COMP_G42D:
1469141cc406Sopenharmony_ci	    sect->compressiontype = 0x03;
1470141cc406Sopenharmony_ci	    sect->compressionarg = 0x00;
1471141cc406Sopenharmony_ci	    sect->format = SANE_FRAME_G42D;
1472141cc406Sopenharmony_ci	    break;
1473141cc406Sopenharmony_ci	  case BH_COMP_NONE:
1474141cc406Sopenharmony_ci	  default:
1475141cc406Sopenharmony_ci	    sect->compressiontype = 0x00;
1476141cc406Sopenharmony_ci	    sect->compressionarg = 0x00;
1477141cc406Sopenharmony_ci	    sect->format = SANE_FRAME_GRAY;
1478141cc406Sopenharmony_ci	    break;
1479141cc406Sopenharmony_ci	  }
1480141cc406Sopenharmony_ci
1481141cc406Sopenharmony_ci	DBG(3, "section_parse: converted '%s' (mm) to "
1482141cc406Sopenharmony_ci	    "%ldx%ld+%ld+%ld (thousandths) "
1483141cc406Sopenharmony_ci	    "flags=%02x compression=[%d,%d] frame=%s\n",
1484141cc406Sopenharmony_ci	    val,
1485141cc406Sopenharmony_ci	    sect->width, sect->length, sect->left, sect->top,
1486141cc406Sopenharmony_ci	    sect->flags,
1487141cc406Sopenharmony_ci	    sect->compressiontype, sect->compressionarg,
1488141cc406Sopenharmony_ci	    sane_strframe(sect->format));
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci      } while (0); /* perform 'loop' once */
1491141cc406Sopenharmony_ci    }
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci  return status;
1494141cc406Sopenharmony_ci}
1495141cc406Sopenharmony_ci
1496141cc406Sopenharmony_cistatic SANE_Status
1497141cc406Sopenharmony_cisetup_sections (BH_Scanner *s, const char *val)
1498141cc406Sopenharmony_ci{
1499141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
1500141cc406Sopenharmony_ci  SANE_Int sectnum = 0;
1501141cc406Sopenharmony_ci  char buf[255+1], *section;
1502141cc406Sopenharmony_ci
1503141cc406Sopenharmony_ci  DBG(3, "setup_sections called\n");
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci  memset(s->sections, '\0', sizeof(s->sections));
1506141cc406Sopenharmony_ci  if (strlen(val) > sizeof(buf) - 1)
1507141cc406Sopenharmony_ci    {
1508141cc406Sopenharmony_ci      DBG(1, "setup_sections: option string too long\n");
1509141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
1510141cc406Sopenharmony_ci    }
1511141cc406Sopenharmony_ci  else
1512141cc406Sopenharmony_ci    {
1513141cc406Sopenharmony_ci      strcpy(buf, val);
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci      section = strtok(buf, ",");
1516141cc406Sopenharmony_ci      while (section != NULL && sectnum < NUM_SECTIONS)
1517141cc406Sopenharmony_ci	{
1518141cc406Sopenharmony_ci	  if (!allblank(section))
1519141cc406Sopenharmony_ci	    {
1520141cc406Sopenharmony_ci	      SANE_Int res = _OPT_VAL_WORD(s, OPT_RESOLUTION);
1521141cc406Sopenharmony_ci	      SANE_Int format =
1522141cc406Sopenharmony_ci		get_compression_id(_OPT_VAL_STRING(s, OPT_COMPRESSION));
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci	      status = section_parse(section, &s->sections[sectnum],
1525141cc406Sopenharmony_ci				     res, format);
1526141cc406Sopenharmony_ci	      if (status != SANE_STATUS_GOOD)
1527141cc406Sopenharmony_ci		{
1528141cc406Sopenharmony_ci		  DBG(1,
1529141cc406Sopenharmony_ci		      "setup_sections: error parsing section `%s'\n",
1530141cc406Sopenharmony_ci		      section);
1531141cc406Sopenharmony_ci		  break;
1532141cc406Sopenharmony_ci		}
1533141cc406Sopenharmony_ci
1534141cc406Sopenharmony_ci	      sectnum++;
1535141cc406Sopenharmony_ci	    }
1536141cc406Sopenharmony_ci	  section += strlen(section) + 1;
1537141cc406Sopenharmony_ci	  if (section > buf + strlen(val)) break;
1538141cc406Sopenharmony_ci
1539141cc406Sopenharmony_ci	  section = strtok(section, ",");
1540141cc406Sopenharmony_ci	}
1541141cc406Sopenharmony_ci    }
1542141cc406Sopenharmony_ci  s->num_sections = sectnum;
1543141cc406Sopenharmony_ci
1544141cc406Sopenharmony_ci  return status;
1545141cc406Sopenharmony_ci}
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_cistatic SANE_Status
1548141cc406Sopenharmony_cistart_setup (BH_Scanner *s)
1549141cc406Sopenharmony_ci{
1550141cc406Sopenharmony_ci  SANE_Status status;
1551141cc406Sopenharmony_ci  SANE_Bool duplex;
1552141cc406Sopenharmony_ci  SANE_Int i, imagecnt;
1553141cc406Sopenharmony_ci  SANE_Byte batchmode;
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  DBG(3, "start_setup called\n");
1556141cc406Sopenharmony_ci
1557141cc406Sopenharmony_ci  duplex = _OPT_VAL_WORD(s, OPT_DUPLEX);
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci  /* get the _SECTION option, parse it and fill in the sections */
1560141cc406Sopenharmony_ci  status = setup_sections(s, _OPT_VAL_STRING(s, OPT_SECTION));
1561141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1562141cc406Sopenharmony_ci    {
1563141cc406Sopenharmony_ci      DBG(1, "start_setup: setup_sections failed: %s\n",
1564141cc406Sopenharmony_ci	  sane_strstatus(status));
1565141cc406Sopenharmony_ci      return status;
1566141cc406Sopenharmony_ci    }
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci  /* see whether we'll be decoding barcodes and
1569141cc406Sopenharmony_ci   * set the barcodes flag appropriately
1570141cc406Sopenharmony_ci   */
1571141cc406Sopenharmony_ci  if (s->search_bars[0] == 0)
1572141cc406Sopenharmony_ci    {
1573141cc406Sopenharmony_ci      s->barcodes = SANE_FALSE;
1574141cc406Sopenharmony_ci    }
1575141cc406Sopenharmony_ci  else
1576141cc406Sopenharmony_ci    {
1577141cc406Sopenharmony_ci      s->barcodes = SANE_TRUE;
1578141cc406Sopenharmony_ci    }
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_ci  /* see whether we'll be handling icons (thumbnails)
1581141cc406Sopenharmony_ci   * set the icons flag appropriately
1582141cc406Sopenharmony_ci   */
1583141cc406Sopenharmony_ci  if (_OPT_VAL_WORD(s, OPT_ICON_WIDTH) >= 8 &&
1584141cc406Sopenharmony_ci      _OPT_VAL_WORD(s, OPT_ICON_LENGTH) >= 8)
1585141cc406Sopenharmony_ci    {
1586141cc406Sopenharmony_ci      s->icons = SANE_TRUE;
1587141cc406Sopenharmony_ci    }
1588141cc406Sopenharmony_ci  else
1589141cc406Sopenharmony_ci    {
1590141cc406Sopenharmony_ci      s->icons = SANE_FALSE;
1591141cc406Sopenharmony_ci    }
1592141cc406Sopenharmony_ci
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci  /* calculate a new readlist for this 'batch' */
1595141cc406Sopenharmony_ci  s->readptr = s->readcnt = 0;
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  /* always read the front image */
1598141cc406Sopenharmony_ci  s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT;
1599141cc406Sopenharmony_ci
1600141cc406Sopenharmony_ci  /* read back page only if duplex is true */
1601141cc406Sopenharmony_ci  if (duplex == SANE_TRUE)
1602141cc406Sopenharmony_ci    {
1603141cc406Sopenharmony_ci      s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK;
1604141cc406Sopenharmony_ci    }
1605141cc406Sopenharmony_ci
1606141cc406Sopenharmony_ci  /* add image section reads to the readlist */
1607141cc406Sopenharmony_ci  for (i = 0; i < s->num_sections; i++)
1608141cc406Sopenharmony_ci    {
1609141cc406Sopenharmony_ci      SANE_Word flags = s->sections[i].flags;
1610141cc406Sopenharmony_ci
1611141cc406Sopenharmony_ci      if (flags & BH_SECTION_FRONT_IMAGE)
1612141cc406Sopenharmony_ci	s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT + i + 1;
1613141cc406Sopenharmony_ci      if (flags & BH_SECTION_BACK_IMAGE)
1614141cc406Sopenharmony_ci	s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK + i + 1;
1615141cc406Sopenharmony_ci    }
1616141cc406Sopenharmony_ci
1617141cc406Sopenharmony_ci
1618141cc406Sopenharmony_ci  /* icons (thumbnails) */
1619141cc406Sopenharmony_ci  if (s->icons)
1620141cc406Sopenharmony_ci    {
1621141cc406Sopenharmony_ci      s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT_ICON;
1622141cc406Sopenharmony_ci      /* read back icon only if duplex is true */
1623141cc406Sopenharmony_ci      if (duplex == SANE_TRUE)
1624141cc406Sopenharmony_ci	{
1625141cc406Sopenharmony_ci	  s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK_ICON;
1626141cc406Sopenharmony_ci	}
1627141cc406Sopenharmony_ci    }
1628141cc406Sopenharmony_ci
1629141cc406Sopenharmony_ci  /* NOTE: It is important that all of the image data comes before
1630141cc406Sopenharmony_ci   * the barcode/patchcode data.
1631141cc406Sopenharmony_ci   */
1632141cc406Sopenharmony_ci  /* barcodes */
1633141cc406Sopenharmony_ci  imagecnt = s->readcnt;
1634141cc406Sopenharmony_ci  if (s->barcodes)
1635141cc406Sopenharmony_ci    {
1636141cc406Sopenharmony_ci      if (s->num_sections == 0)
1637141cc406Sopenharmony_ci	{
1638141cc406Sopenharmony_ci	  /* we only decode the entire page(s) if there are no
1639141cc406Sopenharmony_ci	   * sections defined
1640141cc406Sopenharmony_ci	   */
1641141cc406Sopenharmony_ci	  s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT_BARCODE;
1642141cc406Sopenharmony_ci	  /* read back barcode only if duplex is true */
1643141cc406Sopenharmony_ci	  if (duplex == SANE_TRUE)
1644141cc406Sopenharmony_ci	    {
1645141cc406Sopenharmony_ci	      s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK_BARCODE;
1646141cc406Sopenharmony_ci	    }
1647141cc406Sopenharmony_ci	}
1648141cc406Sopenharmony_ci      else
1649141cc406Sopenharmony_ci	{
1650141cc406Sopenharmony_ci	  /* add barcode section reads to the readlist */
1651141cc406Sopenharmony_ci	  for (i = 0; i < s->num_sections; i++)
1652141cc406Sopenharmony_ci	    {
1653141cc406Sopenharmony_ci	      SANE_Word flags = s->sections[i].flags;
1654141cc406Sopenharmony_ci
1655141cc406Sopenharmony_ci	      if (flags & BH_SECTION_FRONT_BAR)
1656141cc406Sopenharmony_ci		s->readlist[s->readcnt++] =
1657141cc406Sopenharmony_ci		  BH_SCSI_READ_TYPE_FRONT_BARCODE + i + 1;
1658141cc406Sopenharmony_ci	      if (flags & BH_SECTION_BACK_BAR)
1659141cc406Sopenharmony_ci		s->readlist[s->readcnt++] =
1660141cc406Sopenharmony_ci		  BH_SCSI_READ_TYPE_BACK_BARCODE + i + 1;
1661141cc406Sopenharmony_ci	    }
1662141cc406Sopenharmony_ci	}
1663141cc406Sopenharmony_ci    }
1664141cc406Sopenharmony_ci
1665141cc406Sopenharmony_ci  /* patchcodes */
1666141cc406Sopenharmony_ci  if (s->patchcodes)
1667141cc406Sopenharmony_ci    {
1668141cc406Sopenharmony_ci      if (s->num_sections == 0)
1669141cc406Sopenharmony_ci	{
1670141cc406Sopenharmony_ci	  /* we only decode the entire page(s) if there are no
1671141cc406Sopenharmony_ci	   * sections defined
1672141cc406Sopenharmony_ci	   */
1673141cc406Sopenharmony_ci	  s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT_PATCHCODE;
1674141cc406Sopenharmony_ci	  /* read back patchcode only if duplex is true */
1675141cc406Sopenharmony_ci	  if (duplex == SANE_TRUE)
1676141cc406Sopenharmony_ci	    {
1677141cc406Sopenharmony_ci	      s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK_PATCHCODE;
1678141cc406Sopenharmony_ci	    }
1679141cc406Sopenharmony_ci	}
1680141cc406Sopenharmony_ci      else
1681141cc406Sopenharmony_ci	{
1682141cc406Sopenharmony_ci	  /* add patchcode section reads to the readlist */
1683141cc406Sopenharmony_ci	  for (i = 0; i < s->num_sections; i++)
1684141cc406Sopenharmony_ci	    {
1685141cc406Sopenharmony_ci	      SANE_Word flags = s->sections[i].flags;
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci	      if (flags & BH_SECTION_FRONT_PATCH)
1688141cc406Sopenharmony_ci		s->readlist[s->readcnt++] =
1689141cc406Sopenharmony_ci		  BH_SCSI_READ_TYPE_FRONT_PATCHCODE + i + 1;
1690141cc406Sopenharmony_ci	      if (flags & BH_SECTION_BACK_PATCH)
1691141cc406Sopenharmony_ci		s->readlist[s->readcnt++] =
1692141cc406Sopenharmony_ci		  BH_SCSI_READ_TYPE_BACK_PATCHCODE + i + 1;
1693141cc406Sopenharmony_ci	    }
1694141cc406Sopenharmony_ci	}
1695141cc406Sopenharmony_ci    }
1696141cc406Sopenharmony_ci
1697141cc406Sopenharmony_ci  /* add the special item to the read list which transfers the barcode
1698141cc406Sopenharmony_ci   * file that's built as a result of processing barcode and patchcode
1699141cc406Sopenharmony_ci   * readitems.  NOTE: this one must be last!
1700141cc406Sopenharmony_ci   */
1701141cc406Sopenharmony_ci  if (s->readcnt > imagecnt)
1702141cc406Sopenharmony_ci    {
1703141cc406Sopenharmony_ci      s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_SENDBARFILE;
1704141cc406Sopenharmony_ci    }
1705141cc406Sopenharmony_ci
1706141cc406Sopenharmony_ci  if (_OPT_VAL_WORD(s, OPT_BATCH) == SANE_TRUE)
1707141cc406Sopenharmony_ci    {
1708141cc406Sopenharmony_ci      /* if batchmode is enabled, then call set_window to
1709141cc406Sopenharmony_ci       * abort the batch (even though there might not (and probably
1710141cc406Sopenharmony_ci       * isn't) a batch in progress).  This avoids a batch start error
1711141cc406Sopenharmony_ci       * in the case where a previous batch was not aborted.
1712141cc406Sopenharmony_ci       */
1713141cc406Sopenharmony_ci      DBG(5, "start_setup: calling set_window to abort batch\n");
1714141cc406Sopenharmony_ci      set_window(s, BH_BATCH_ABORT);
1715141cc406Sopenharmony_ci
1716141cc406Sopenharmony_ci      batchmode = BH_BATCH_ENABLE;
1717141cc406Sopenharmony_ci    }
1718141cc406Sopenharmony_ci  else
1719141cc406Sopenharmony_ci    {
1720141cc406Sopenharmony_ci      batchmode = BH_BATCH_DISABLE;
1721141cc406Sopenharmony_ci    }
1722141cc406Sopenharmony_ci
1723141cc406Sopenharmony_ci  DBG(5, "start_setup: duplex=%s, barcodes=%s, patchcodes=%s, "
1724141cc406Sopenharmony_ci      "icons=%s, batch=%s\n",
1725141cc406Sopenharmony_ci      (duplex == SANE_TRUE) ? "yes" : "no",
1726141cc406Sopenharmony_ci      (s->barcodes == SANE_TRUE) ? "yes" : "no",
1727141cc406Sopenharmony_ci      (s->patchcodes == SANE_TRUE) ? "yes" : "no",
1728141cc406Sopenharmony_ci      (s->icons == SANE_TRUE) ? "yes" : "no",
1729141cc406Sopenharmony_ci      (batchmode == BH_BATCH_ENABLE) ? "yes" : "no");
1730141cc406Sopenharmony_ci  DBG(5, "start_setup: sections=%d\n", s->num_sections);
1731141cc406Sopenharmony_ci  for (i = 0; i < s->num_sections; i++)
1732141cc406Sopenharmony_ci    {
1733141cc406Sopenharmony_ci      DBG(5, "start_setup:  "
1734141cc406Sopenharmony_ci	  "[%d] %lux%lu+%lu+%lu flags=%02x compression=[%d,%d]\n",
1735141cc406Sopenharmony_ci	  i+1,
1736141cc406Sopenharmony_ci	  s->sections[i].width, s->sections[i].length,
1737141cc406Sopenharmony_ci	  s->sections[i].left, s->sections[i].top,
1738141cc406Sopenharmony_ci	  s->sections[i].flags,
1739141cc406Sopenharmony_ci	  s->sections[i].compressiontype, s->sections[i].compressionarg);
1740141cc406Sopenharmony_ci    }
1741141cc406Sopenharmony_ci  DBG(5, "start_setup: read list length=%d\n", s->readcnt);
1742141cc406Sopenharmony_ci  for (i = 0; i < s->readcnt; i++)
1743141cc406Sopenharmony_ci    {
1744141cc406Sopenharmony_ci      DBG(5, "start_setup:  [%d] %s\n", i+1, print_read_type(s->readlist[i]));
1745141cc406Sopenharmony_ci    }
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci  DBG(5, "start_setup: sending SET WINDOW\n");
1748141cc406Sopenharmony_ci  status = set_window(s, batchmode);
1749141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1750141cc406Sopenharmony_ci    {
1751141cc406Sopenharmony_ci      DBG(1, "start_setup: SET WINDOW failed: %s\n",
1752141cc406Sopenharmony_ci	   sane_strstatus(status));
1753141cc406Sopenharmony_ci      return status;
1754141cc406Sopenharmony_ci    }
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci  DBG(5, "start_setup: sending mode_select_timeout\n");
1757141cc406Sopenharmony_ci  status = mode_select_timeout(s);
1758141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1759141cc406Sopenharmony_ci    {
1760141cc406Sopenharmony_ci      DBG(1, "start_setup: mode_select_timeout failed: %s\n",
1761141cc406Sopenharmony_ci	   sane_strstatus(status));
1762141cc406Sopenharmony_ci      return status;
1763141cc406Sopenharmony_ci    }
1764141cc406Sopenharmony_ci
1765141cc406Sopenharmony_ci  if (s->icons == SANE_TRUE)
1766141cc406Sopenharmony_ci    {
1767141cc406Sopenharmony_ci      DBG(5, "start_setup: sending mode_select_icon\n");
1768141cc406Sopenharmony_ci      status = mode_select_icon(s);
1769141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1770141cc406Sopenharmony_ci	{
1771141cc406Sopenharmony_ci	  DBG(1, "start_setup: mode_select_icon failed: %s\n",
1772141cc406Sopenharmony_ci	       sane_strstatus(status));
1773141cc406Sopenharmony_ci	  return status;
1774141cc406Sopenharmony_ci	}
1775141cc406Sopenharmony_ci    }
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci  if (s->barcodes == SANE_TRUE)
1778141cc406Sopenharmony_ci    {
1779141cc406Sopenharmony_ci      DBG(5, "start_setup: sending mode_select_barcode_priority\n");
1780141cc406Sopenharmony_ci      status = mode_select_barcode_priority(s);
1781141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1782141cc406Sopenharmony_ci	{
1783141cc406Sopenharmony_ci	  DBG(1, "start_setup: mode_select_barcode_priority failed: %s\n",
1784141cc406Sopenharmony_ci	       sane_strstatus(status));
1785141cc406Sopenharmony_ci	  return status;
1786141cc406Sopenharmony_ci	}
1787141cc406Sopenharmony_ci
1788141cc406Sopenharmony_ci      DBG(5, "start_setup: sending mode_select_barcode_param1\n");
1789141cc406Sopenharmony_ci      status = mode_select_barcode_param1(s);
1790141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1791141cc406Sopenharmony_ci	{
1792141cc406Sopenharmony_ci	  DBG(1, "start_setup: mode_select_barcode_param1 failed: %s\n",
1793141cc406Sopenharmony_ci	       sane_strstatus(status));
1794141cc406Sopenharmony_ci	  return status;
1795141cc406Sopenharmony_ci	}
1796141cc406Sopenharmony_ci
1797141cc406Sopenharmony_ci      DBG(5, "start_setup: sending mode_select_barcode_param2\n");
1798141cc406Sopenharmony_ci      status = mode_select_barcode_param2(s);
1799141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1800141cc406Sopenharmony_ci	{
1801141cc406Sopenharmony_ci	  DBG(1, "start_setup: mode_select_barcode_param2 failed: %s\n",
1802141cc406Sopenharmony_ci	       sane_strstatus(status));
1803141cc406Sopenharmony_ci	  return status;
1804141cc406Sopenharmony_ci	}
1805141cc406Sopenharmony_ci
1806141cc406Sopenharmony_ci      DBG(5, "start_setup: sending mode_select_barcode_param3\n");
1807141cc406Sopenharmony_ci      status = mode_select_barcode_param3(s);
1808141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1809141cc406Sopenharmony_ci	{
1810141cc406Sopenharmony_ci	  DBG(1, "start_setup: mode_select_barcode_param3 failed: %s\n",
1811141cc406Sopenharmony_ci	       sane_strstatus(status));
1812141cc406Sopenharmony_ci	  return status;
1813141cc406Sopenharmony_ci	}
1814141cc406Sopenharmony_ci    }
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci  return status;
1817141cc406Sopenharmony_ci}
1818141cc406Sopenharmony_ci
1819141cc406Sopenharmony_cistatic SANE_Status
1820141cc406Sopenharmony_cistart_scan (BH_Scanner *s)
1821141cc406Sopenharmony_ci{
1822141cc406Sopenharmony_ci  static SANE_Byte cmd[8];
1823141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
1824141cc406Sopenharmony_ci  SANE_Bool check_adf, duplex;
1825141cc406Sopenharmony_ci  DBG (3, "start_scan called\n");
1826141cc406Sopenharmony_ci
1827141cc406Sopenharmony_ci  /* SANE front ends will call this function between 'FRAMES'.
1828141cc406Sopenharmony_ci   * A single scan on the B&H may result in up to 56 different
1829141cc406Sopenharmony_ci   * things to read (20 are SANE image frames, 36 are non-SANE
1830141cc406Sopenharmony_ci   * data - decoded bar/patch codes).
1831141cc406Sopenharmony_ci   */
1832141cc406Sopenharmony_ci
1833141cc406Sopenharmony_ci  if (s->readcnt > 1 && s->scanning == SANE_TRUE)
1834141cc406Sopenharmony_ci    {
1835141cc406Sopenharmony_ci      DBG(3, "start_scan: any more items in the readlist?\n");
1836141cc406Sopenharmony_ci      /* we've been reading data from this scan, so we just
1837141cc406Sopenharmony_ci       * move on to the next item in the readlist without
1838141cc406Sopenharmony_ci       * starting a new scan.
1839141cc406Sopenharmony_ci       */
1840141cc406Sopenharmony_ci      s->readptr++;
1841141cc406Sopenharmony_ci      if (s->readptr < s->readcnt)
1842141cc406Sopenharmony_ci	{
1843141cc406Sopenharmony_ci	  SANE_Byte itemtype;
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_ci	  for (; s->readptr < s->readcnt; s->readptr++)
1846141cc406Sopenharmony_ci	    {
1847141cc406Sopenharmony_ci
1848141cc406Sopenharmony_ci	      itemtype = s->readlist[s->readptr];
1849141cc406Sopenharmony_ci
1850141cc406Sopenharmony_ci	      DBG(3, "start_scan: advance readlist(%d, %d)\n",
1851141cc406Sopenharmony_ci		  s->readptr,
1852141cc406Sopenharmony_ci		  (int) itemtype);
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci	      /* 'dance' by the non-SANE data streams
1855141cc406Sopenharmony_ci	       * like bar/patch code data
1856141cc406Sopenharmony_ci	       */
1857141cc406Sopenharmony_ci	      if (!BH_HAS_IMAGE_DATA(itemtype))
1858141cc406Sopenharmony_ci		{
1859141cc406Sopenharmony_ci		  int fd;
1860141cc406Sopenharmony_ci		  FILE *fp;
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_ci		  strncpy(s->barfname, "/tmp/bhXXXXXX", sizeof(s->barfname));
1863141cc406Sopenharmony_ci		  s->barfname[sizeof(s->barfname)-1] = '\0';
1864141cc406Sopenharmony_ci		  fd = mkstemp(s->barfname);
1865141cc406Sopenharmony_ci
1866141cc406Sopenharmony_ci		  if (fd !=-1 && (fp = fdopen(fd, "w")) != NULL)
1867141cc406Sopenharmony_ci		    {
1868141cc406Sopenharmony_ci		      fprintf(fp, "<xml-stream>\n");
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci		      for (;
1871141cc406Sopenharmony_ci			   s->readptr < s->readcnt &&
1872141cc406Sopenharmony_ci			     status == SANE_STATUS_GOOD;
1873141cc406Sopenharmony_ci			   s->readptr++)
1874141cc406Sopenharmony_ci			{
1875141cc406Sopenharmony_ci			  if (s->readlist[s->readptr] ==
1876141cc406Sopenharmony_ci			      BH_SCSI_READ_TYPE_SENDBARFILE) {
1877141cc406Sopenharmony_ci			    break;
1878141cc406Sopenharmony_ci			  }
1879141cc406Sopenharmony_ci			  status = read_barcode_data(s, fp);
1880141cc406Sopenharmony_ci			  if (status != SANE_STATUS_GOOD) break;
1881141cc406Sopenharmony_ci			}
1882141cc406Sopenharmony_ci
1883141cc406Sopenharmony_ci		      fprintf(fp, "</xml-stream>\n");
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci		      /* close file; re-open for read(setting s->barfd) */
1886141cc406Sopenharmony_ci		      fclose(fp);
1887141cc406Sopenharmony_ci		      if ((s->barf = fopen(s->barfname, "r")) == NULL)
1888141cc406Sopenharmony_ci			{
1889141cc406Sopenharmony_ci			  DBG(1, "sane_start: error opening barfile `%s'\n",
1890141cc406Sopenharmony_ci			      s->barfname);
1891141cc406Sopenharmony_ci			  status = SANE_STATUS_IO_ERROR;
1892141cc406Sopenharmony_ci			}
1893141cc406Sopenharmony_ci		    }
1894141cc406Sopenharmony_ci		  else
1895141cc406Sopenharmony_ci		    {
1896141cc406Sopenharmony_ci		      DBG(1, "sane_start: error opening barfile `%s'\n",
1897141cc406Sopenharmony_ci			  s->barfname);
1898141cc406Sopenharmony_ci		      if (fd !=-1)
1899141cc406Sopenharmony_ci		        {
1900141cc406Sopenharmony_ci		          close(fd);
1901141cc406Sopenharmony_ci		          unlink(s->barfname);
1902141cc406Sopenharmony_ci		        }
1903141cc406Sopenharmony_ci		      status = SANE_STATUS_IO_ERROR;
1904141cc406Sopenharmony_ci		    }
1905141cc406Sopenharmony_ci		}
1906141cc406Sopenharmony_ci	      else if (itemtype == BH_SCSI_READ_TYPE_FRONT_ICON ||
1907141cc406Sopenharmony_ci		       itemtype == BH_SCSI_READ_TYPE_BACK_ICON)
1908141cc406Sopenharmony_ci		{
1909141cc406Sopenharmony_ci		  /* read the icon header setting the iconwidth and iconlength
1910141cc406Sopenharmony_ci		   * to the actual values so get_parameters will have them.
1911141cc406Sopenharmony_ci		   * Subsequent calls to sane_read will get pure image data
1912141cc406Sopenharmony_ci		   * since the icon header has been consumed.
1913141cc406Sopenharmony_ci		   */
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci		  status = read_icon_data(s);
1916141cc406Sopenharmony_ci		}
1917141cc406Sopenharmony_ci
1918141cc406Sopenharmony_ci	      if (status == SANE_STATUS_GOOD)
1919141cc406Sopenharmony_ci		{
1920141cc406Sopenharmony_ci		  /* update our parameters to reflect the new item */
1921141cc406Sopenharmony_ci		  status = get_parameters (s, 0);
1922141cc406Sopenharmony_ci		}
1923141cc406Sopenharmony_ci
1924141cc406Sopenharmony_ci	      if (status != SANE_STATUS_GOOD) s->scanning = SANE_FALSE;
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci	      return status;
1927141cc406Sopenharmony_ci	    }
1928141cc406Sopenharmony_ci	  /* if we reach here, we're finished with the readlist and
1929141cc406Sopenharmony_ci	   * will drop through to start a new scan
1930141cc406Sopenharmony_ci	   */
1931141cc406Sopenharmony_ci	}
1932141cc406Sopenharmony_ci    }
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci  s->readptr = 0;
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci  check_adf = _OPT_VAL_WORD(s, OPT_CHECK_ADF);
1937141cc406Sopenharmony_ci  duplex = _OPT_VAL_WORD(s, OPT_DUPLEX);
1938141cc406Sopenharmony_ci
1939141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
1940141cc406Sopenharmony_ci  cmd[0] = BH_SCSI_START_SCAN;
1941141cc406Sopenharmony_ci  cmd[4] = (duplex == SANE_TRUE) ? 2 : 1;
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_ci  cmd[6] = 0;
1944141cc406Sopenharmony_ci  cmd[7] = 1;
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ci  if (check_adf)
1947141cc406Sopenharmony_ci    {
1948141cc406Sopenharmony_ci      status = object_position(s);
1949141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1950141cc406Sopenharmony_ci	{
1951141cc406Sopenharmony_ci	  DBG(3, "object_position: returned %d\n", status);
1952141cc406Sopenharmony_ci	  return status;
1953141cc406Sopenharmony_ci	}
1954141cc406Sopenharmony_ci    }
1955141cc406Sopenharmony_ci
1956141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0);
1957141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD)
1958141cc406Sopenharmony_ci    {
1959141cc406Sopenharmony_ci      s->scanning = SANE_TRUE;
1960141cc406Sopenharmony_ci
1961141cc406Sopenharmony_ci      /* update our parameters,
1962141cc406Sopenharmony_ci       * now that we're scanning we'll do a GET_WINDOW
1963141cc406Sopenharmony_ci       */
1964141cc406Sopenharmony_ci      status = get_parameters (s, 0);
1965141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1966141cc406Sopenharmony_ci	{
1967141cc406Sopenharmony_ci	  s->scanning = SANE_FALSE;
1968141cc406Sopenharmony_ci	}
1969141cc406Sopenharmony_ci    }
1970141cc406Sopenharmony_ci
1971141cc406Sopenharmony_ci  return status;
1972141cc406Sopenharmony_ci}
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci/* a sensible sense handler, courtesy of Franck;
1975141cc406Sopenharmony_ci   arg is a pointer to the associated BH_Scanner structure */
1976141cc406Sopenharmony_cistatic SANE_Status
1977141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char *result, void *arg)
1978141cc406Sopenharmony_ci{
1979141cc406Sopenharmony_ci  BH_Scanner *s = (BH_Scanner *) arg;
1980141cc406Sopenharmony_ci  u_char sense, asc, ascq, EOM, ILI, ErrorCode, ValidData;
1981141cc406Sopenharmony_ci  u_long InvalidBytes;
1982141cc406Sopenharmony_ci  char *sense_str = "", *as_str = "";
1983141cc406Sopenharmony_ci  SANE_Int i;
1984141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_INVAL;
1985141cc406Sopenharmony_ci  SANE_Char print_sense[(16 * 3) + 1];
1986141cc406Sopenharmony_ci
1987141cc406Sopenharmony_ci  (void) scsi_fd; /* get rid of compiler warning */
1988141cc406Sopenharmony_ci  ErrorCode = result[0] & 0x7F;
1989141cc406Sopenharmony_ci  ValidData = (result[0] & 0x80) != 0;
1990141cc406Sopenharmony_ci  sense = result[2] & 0x0f; /* Key */
1991141cc406Sopenharmony_ci  asc = result[12]; /* Code */
1992141cc406Sopenharmony_ci  ascq = result[13]; /* Qual */
1993141cc406Sopenharmony_ci  EOM = (result[2] & 0x40) != 0; /* End Of Media */
1994141cc406Sopenharmony_ci  ILI = (result[2] & 0x20) != 0; /* Invalid Length Indicator */
1995141cc406Sopenharmony_ci  InvalidBytes = ValidData ? _4btol(&result[3]) : 0;
1996141cc406Sopenharmony_ci
1997141cc406Sopenharmony_ci  DBG(3, "sense_handler: result=%x, sense=%x, asc=%x, ascq=%x\n",
1998141cc406Sopenharmony_ci      result[0], sense, asc, ascq);
1999141cc406Sopenharmony_ci  DBG(3, "sense_handler: ErrorCode %02x ValidData: %d "
2000141cc406Sopenharmony_ci      "EOM: %d ILI: %d InvalidBytes: %lu\n",
2001141cc406Sopenharmony_ci      ErrorCode, ValidData, EOM, ILI, InvalidBytes);
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci  memset(print_sense, '\0', sizeof(print_sense));
2004141cc406Sopenharmony_ci  for (i = 0; i < 16; i++)
2005141cc406Sopenharmony_ci    {
2006141cc406Sopenharmony_ci      sprintf(print_sense + strlen(print_sense), "%02x ", result[i]);
2007141cc406Sopenharmony_ci    }
2008141cc406Sopenharmony_ci  DBG(5, "sense_handler: sense=%s\n", print_sense);
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci  if (ErrorCode != 0x70 && ErrorCode != 0x71)
2011141cc406Sopenharmony_ci    {
2012141cc406Sopenharmony_ci      DBG (3, "sense_handler: error code is invalid.\n");
2013141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;	/* error code is invalid */
2014141cc406Sopenharmony_ci    }
2015141cc406Sopenharmony_ci
2016141cc406Sopenharmony_ci  /* handle each sense key;
2017141cc406Sopenharmony_ci   * RSC supports 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B
2018141cc406Sopenharmony_ci   */
2019141cc406Sopenharmony_ci  switch (sense)
2020141cc406Sopenharmony_ci    {
2021141cc406Sopenharmony_ci    case 0x00:
2022141cc406Sopenharmony_ci      /* no sense */
2023141cc406Sopenharmony_ci      sense_str = "No sense.";
2024141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2025141cc406Sopenharmony_ci      if (ILI && asc == 0x00 && ascq == 0x05)
2026141cc406Sopenharmony_ci	{
2027141cc406Sopenharmony_ci	  /* from read_data function */
2028141cc406Sopenharmony_ci	  as_str = "ILI bit is set.";
2029141cc406Sopenharmony_ci	  if (s != NULL)
2030141cc406Sopenharmony_ci	    {
2031141cc406Sopenharmony_ci	      s->InvalidBytes = InvalidBytes;
2032141cc406Sopenharmony_ci	    }
2033141cc406Sopenharmony_ci	  status = SANE_STATUS_GOOD;
2034141cc406Sopenharmony_ci	}
2035141cc406Sopenharmony_ci      else if (EOM && asc == 0x00 && ascq == 0x02)
2036141cc406Sopenharmony_ci	{
2037141cc406Sopenharmony_ci	  /* from adfStatus or startScan function */
2038141cc406Sopenharmony_ci	  as_str = "Out of paper in the hopper.";
2039141cc406Sopenharmony_ci	  status = SANE_STATUS_NO_DOCS;
2040141cc406Sopenharmony_ci	}
2041141cc406Sopenharmony_ci      else if (EOM)
2042141cc406Sopenharmony_ci	{
2043141cc406Sopenharmony_ci	  /* from adfStatus or startScan function */
2044141cc406Sopenharmony_ci	  as_str = "Out of paper in the hopper.";
2045141cc406Sopenharmony_ci	  status = SANE_STATUS_NO_DOCS;
2046141cc406Sopenharmony_ci	}
2047141cc406Sopenharmony_ci      break;
2048141cc406Sopenharmony_ci    case 0x01:
2049141cc406Sopenharmony_ci      /* recovered error */
2050141cc406Sopenharmony_ci      sense_str = "Recovered error.";
2051141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2052141cc406Sopenharmony_ci      break;
2053141cc406Sopenharmony_ci    case 0x02:
2054141cc406Sopenharmony_ci      /* not ready */
2055141cc406Sopenharmony_ci      sense_str = "Not ready.";
2056141cc406Sopenharmony_ci      status = SANE_STATUS_DEVICE_BUSY;
2057141cc406Sopenharmony_ci      if (asc == 0x40 && ascq == 0x01)
2058141cc406Sopenharmony_ci	{
2059141cc406Sopenharmony_ci	  as_str = "P.O.D. error: Scanner not found.";
2060141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2061141cc406Sopenharmony_ci	}
2062141cc406Sopenharmony_ci      else if (asc == 0x40 && ascq == 0x02)
2063141cc406Sopenharmony_ci	{
2064141cc406Sopenharmony_ci	  as_str = "P.O.D. error: Scanner not ready(paper in transport).";
2065141cc406Sopenharmony_ci	  status = SANE_STATUS_DEVICE_BUSY;
2066141cc406Sopenharmony_ci	}
2067141cc406Sopenharmony_ci      else if (asc == 0x40 && ascq == 0x03)
2068141cc406Sopenharmony_ci	{
2069141cc406Sopenharmony_ci	  as_str = "P.O.D. error: Unknown scanner.";
2070141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2071141cc406Sopenharmony_ci	}
2072141cc406Sopenharmony_ci      break;
2073141cc406Sopenharmony_ci    case 0x03:
2074141cc406Sopenharmony_ci      /* medium error */
2075141cc406Sopenharmony_ci      sense_str = "Medium error.";
2076141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2077141cc406Sopenharmony_ci      if (asc == 0x00 && ascq == 0x00)
2078141cc406Sopenharmony_ci	{
2079141cc406Sopenharmony_ci	  as_str = "Scanner error: paper jam detected.";
2080141cc406Sopenharmony_ci	  status = SANE_STATUS_JAMMED;
2081141cc406Sopenharmony_ci	}
2082141cc406Sopenharmony_ci      break;
2083141cc406Sopenharmony_ci    case 0x04:
2084141cc406Sopenharmony_ci      /* hardware error */
2085141cc406Sopenharmony_ci      sense_str = "Hardware error.";
2086141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2087141cc406Sopenharmony_ci      if (asc == 0x60 && ascq == 0x00)
2088141cc406Sopenharmony_ci	{
2089141cc406Sopenharmony_ci	  as_str = "Scanner error: illumination lamps failure.";
2090141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2091141cc406Sopenharmony_ci	}
2092141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x03)
2093141cc406Sopenharmony_ci	{
2094141cc406Sopenharmony_ci	  as_str = "Communication error between RSC and scanner.";
2095141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2096141cc406Sopenharmony_ci	}
2097141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x06)
2098141cc406Sopenharmony_ci	{
2099141cc406Sopenharmony_ci	  as_str = "Scanner error: page detected but lamps are off.";
2100141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2101141cc406Sopenharmony_ci	}
2102141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x07)
2103141cc406Sopenharmony_ci	{
2104141cc406Sopenharmony_ci	  as_str = "Scanner error: camera white level problem.";
2105141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2106141cc406Sopenharmony_ci	}
2107141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x08)
2108141cc406Sopenharmony_ci	{
2109141cc406Sopenharmony_ci	  /* could be caught from start_scan or read_data */
2110141cc406Sopenharmony_ci	  /* stop button pressed */
2111141cc406Sopenharmony_ci	  as_str = "Scanner error: operator pressed the Stop key.";
2112141cc406Sopenharmony_ci	  status = SANE_STATUS_NO_DOCS;
2113141cc406Sopenharmony_ci	}
2114141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x12)
2115141cc406Sopenharmony_ci	{
2116141cc406Sopenharmony_ci	  as_str = "Scanner error: transport motor failure.";
2117141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2118141cc406Sopenharmony_ci	}
2119141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x15)
2120141cc406Sopenharmony_ci	{
2121141cc406Sopenharmony_ci	  as_str = "Scanner error: device / page sensor(s) bouncing.";
2122141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2123141cc406Sopenharmony_ci	}
2124141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x16)
2125141cc406Sopenharmony_ci	{
2126141cc406Sopenharmony_ci	  as_str = "Scanner error: feeder is not attached.";
2127141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2128141cc406Sopenharmony_ci	}
2129141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x18)
2130141cc406Sopenharmony_ci	{
2131141cc406Sopenharmony_ci	  as_str = "Scanner error: logic system general failure.";
2132141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2133141cc406Sopenharmony_ci	}
2134141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x34)
2135141cc406Sopenharmony_ci	{
2136141cc406Sopenharmony_ci	  as_str = "Scanner error: no dual logic communication.";
2137141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2138141cc406Sopenharmony_ci	}
2139141cc406Sopenharmony_ci      break;
2140141cc406Sopenharmony_ci    case 0x05:
2141141cc406Sopenharmony_ci      /* illegal request */
2142141cc406Sopenharmony_ci      sense_str = "Illegal request.";
2143141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
2144141cc406Sopenharmony_ci      if (asc == 0x1a && ascq == 0x00)
2145141cc406Sopenharmony_ci	{
2146141cc406Sopenharmony_ci	  as_str = "Parameter list length error.";
2147141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2148141cc406Sopenharmony_ci	}
2149141cc406Sopenharmony_ci      else if (asc == 0x20 && ascq == 0x00)
2150141cc406Sopenharmony_ci	{
2151141cc406Sopenharmony_ci	  as_str = "Invalid command operation code.";
2152141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2153141cc406Sopenharmony_ci	}
2154141cc406Sopenharmony_ci      else if (asc == 0x24 && ascq == 0x00)
2155141cc406Sopenharmony_ci	{
2156141cc406Sopenharmony_ci	  /* caught from object_position (via reverse engineering) */
2157141cc406Sopenharmony_ci	  /* Not supported? */
2158141cc406Sopenharmony_ci	  as_str = "Invalid field in CDB.";
2159141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2160141cc406Sopenharmony_ci	}
2161141cc406Sopenharmony_ci      else if (asc == 0x25 && ascq == 0x00)
2162141cc406Sopenharmony_ci	{
2163141cc406Sopenharmony_ci	  as_str = "Unsupported LUN.";
2164141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2165141cc406Sopenharmony_ci	}
2166141cc406Sopenharmony_ci      else if (asc == 0x26 && ascq == 0x00)
2167141cc406Sopenharmony_ci	{
2168141cc406Sopenharmony_ci	  /* caught from mode_select (as well as others) */
2169141cc406Sopenharmony_ci	  /* Bar/Patch code detection support not installed */
2170141cc406Sopenharmony_ci	  /* See Appendix A, Section A.5 */
2171141cc406Sopenharmony_ci	  as_str = "Invalid field in parameter list.";
2172141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2173141cc406Sopenharmony_ci	}
2174141cc406Sopenharmony_ci      else if (asc == 0x2c && ascq == 0x00)
2175141cc406Sopenharmony_ci	{
2176141cc406Sopenharmony_ci	  /* we were getting this in read_data during the time
2177141cc406Sopenharmony_ci	     that the ADF was misbehaving.  Hopefully we will
2178141cc406Sopenharmony_ci	     not see it anymore.
2179141cc406Sopenharmony_ci	  */
2180141cc406Sopenharmony_ci	  as_str = "Command out of sequence.";
2181141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2182141cc406Sopenharmony_ci	}
2183141cc406Sopenharmony_ci      else if (asc == 0x2c && ascq == 0x01)
2184141cc406Sopenharmony_ci	{
2185141cc406Sopenharmony_ci	  as_str = "Too many windows defined.";
2186141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2187141cc406Sopenharmony_ci	}
2188141cc406Sopenharmony_ci      else if (asc == 0x2c && ascq == 0x02)
2189141cc406Sopenharmony_ci	{
2190141cc406Sopenharmony_ci	  as_str = "Batch start error.";
2191141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2192141cc406Sopenharmony_ci	}
2193141cc406Sopenharmony_ci      else if (asc == 0x2c && ascq == 0x03)
2194141cc406Sopenharmony_ci	{
2195141cc406Sopenharmony_ci	  as_str = "Batch abort error.";
2196141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2197141cc406Sopenharmony_ci	}
2198141cc406Sopenharmony_ci      else if (asc == 0x3d && ascq == 0x00)
2199141cc406Sopenharmony_ci	{
2200141cc406Sopenharmony_ci	  as_str = "Invalid bits in IDENTIFY message.";
2201141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2202141cc406Sopenharmony_ci	}
2203141cc406Sopenharmony_ci      break;
2204141cc406Sopenharmony_ci    case 0x06:
2205141cc406Sopenharmony_ci      /* unit attention */
2206141cc406Sopenharmony_ci      sense_str = "Unit attention.";
2207141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2208141cc406Sopenharmony_ci      if (asc == 0x04 && ascq == 0x01)
2209141cc406Sopenharmony_ci	{
2210141cc406Sopenharmony_ci	  as_str = "Reset detected, LUN is becoming ready.";
2211141cc406Sopenharmony_ci	  status = SANE_STATUS_DEVICE_BUSY;
2212141cc406Sopenharmony_ci	}
2213141cc406Sopenharmony_ci      break;
2214141cc406Sopenharmony_ci    case 0x07:
2215141cc406Sopenharmony_ci      /* data protect */
2216141cc406Sopenharmony_ci      sense_str = "Data protect.";
2217141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2218141cc406Sopenharmony_ci      break;
2219141cc406Sopenharmony_ci    case 0x08:
2220141cc406Sopenharmony_ci      /* blank check */
2221141cc406Sopenharmony_ci      sense_str = "Blank check.";
2222141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2223141cc406Sopenharmony_ci      break;
2224141cc406Sopenharmony_ci    case 0x09:
2225141cc406Sopenharmony_ci      /* vendor specific */
2226141cc406Sopenharmony_ci      sense_str = "Vendor specific.";
2227141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2228141cc406Sopenharmony_ci      break;
2229141cc406Sopenharmony_ci    case 0x0A:
2230141cc406Sopenharmony_ci      /* copy aborted */
2231141cc406Sopenharmony_ci      sense_str = "Copy aborted.";
2232141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2233141cc406Sopenharmony_ci      break;
2234141cc406Sopenharmony_ci    case 0x0B:
2235141cc406Sopenharmony_ci      /* aborted command */
2236141cc406Sopenharmony_ci      sense_str = "Aborted command.";
2237141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2238141cc406Sopenharmony_ci      if (asc == 0x00 && ascq == 0x00)
2239141cc406Sopenharmony_ci	{
2240141cc406Sopenharmony_ci	  as_str = "Aborted command (unspecified error).";
2241141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2242141cc406Sopenharmony_ci	}
2243141cc406Sopenharmony_ci      else if (asc == 0x08 && ascq == 0x01)
2244141cc406Sopenharmony_ci	{
2245141cc406Sopenharmony_ci	  /* caught from start_scan */
2246141cc406Sopenharmony_ci	  /* manual feed timeout */
2247141cc406Sopenharmony_ci	  as_str = "SCSI Time-out, paper Time-out (SCAN command).";
2248141cc406Sopenharmony_ci	  status = SANE_STATUS_NO_DOCS;
2249141cc406Sopenharmony_ci	}
2250141cc406Sopenharmony_ci      else if (asc == 0x47 && ascq == 0x00)
2251141cc406Sopenharmony_ci	{
2252141cc406Sopenharmony_ci	  as_str = "SCSI parity error.";
2253141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2254141cc406Sopenharmony_ci	}
2255141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x00)
2256141cc406Sopenharmony_ci	{
2257141cc406Sopenharmony_ci	  as_str = "Aborted command due to memory error.";
2258141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2259141cc406Sopenharmony_ci	}
2260141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x01)
2261141cc406Sopenharmony_ci	{
2262141cc406Sopenharmony_ci	  /* caught from read_data */
2263141cc406Sopenharmony_ci	  /* section border error; border is outside the main window */
2264141cc406Sopenharmony_ci	  /* See Appendix A, Section A.4 */
2265141cc406Sopenharmony_ci	  as_str = "Section Read error (out of border).";
2266141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2267141cc406Sopenharmony_ci	}
2268141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x02)
2269141cc406Sopenharmony_ci	{
2270141cc406Sopenharmony_ci	  /* caught from read_data */
2271141cc406Sopenharmony_ci	  /* No code found; no barcode data is found */
2272141cc406Sopenharmony_ci	  /* See Appendix A, Section A.5 */
2273141cc406Sopenharmony_ci	  s->barcode_not_found = SANE_TRUE;
2274141cc406Sopenharmony_ci	  as_str = "No Bar/Patch Code found.";
2275141cc406Sopenharmony_ci	  status = SANE_STATUS_GOOD;
2276141cc406Sopenharmony_ci	}
2277141cc406Sopenharmony_ci      else if (asc == 0x80 && ascq == 0x03)
2278141cc406Sopenharmony_ci	{
2279141cc406Sopenharmony_ci	  as_str = "Icon Read error (out of border).";
2280141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
2281141cc406Sopenharmony_ci	}
2282141cc406Sopenharmony_ci      break;
2283141cc406Sopenharmony_ci    case 0x0C:
2284141cc406Sopenharmony_ci      /* equal */
2285141cc406Sopenharmony_ci      sense_str = "Equal.";
2286141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2287141cc406Sopenharmony_ci      break;
2288141cc406Sopenharmony_ci    case 0x0D:
2289141cc406Sopenharmony_ci      /* volume overflow */
2290141cc406Sopenharmony_ci      sense_str = "Volume overflow.";
2291141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2292141cc406Sopenharmony_ci      break;
2293141cc406Sopenharmony_ci    case 0x0E:
2294141cc406Sopenharmony_ci      /* miscompare */
2295141cc406Sopenharmony_ci      sense_str = "Miscompare.";
2296141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2297141cc406Sopenharmony_ci      break;
2298141cc406Sopenharmony_ci    case 0x0F:
2299141cc406Sopenharmony_ci      /* reserved */
2300141cc406Sopenharmony_ci      sense_str = "Reserved.";
2301141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2302141cc406Sopenharmony_ci      break;
2303141cc406Sopenharmony_ci    default:
2304141cc406Sopenharmony_ci      sense_str = "Unhandled case.";
2305141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2306141cc406Sopenharmony_ci      break;
2307141cc406Sopenharmony_ci    }
2308141cc406Sopenharmony_ci
2309141cc406Sopenharmony_ci  DBG(3, "sense_handler: '%s' '%s' return:%d\n",
2310141cc406Sopenharmony_ci      sense_str, as_str, status);
2311141cc406Sopenharmony_ci
2312141cc406Sopenharmony_ci  return status;
2313141cc406Sopenharmony_ci}
2314141cc406Sopenharmony_ci
2315141cc406Sopenharmony_cistatic SANE_Status
2316141cc406Sopenharmony_ciinit_options (BH_Scanner * s)
2317141cc406Sopenharmony_ci{
2318141cc406Sopenharmony_ci  int i;
2319141cc406Sopenharmony_ci  DBG (3, "init_options called\n");
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
2322141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
2323141cc406Sopenharmony_ci
2324141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
2325141cc406Sopenharmony_ci    {
2326141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
2327141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2328141cc406Sopenharmony_ci    }
2329141cc406Sopenharmony_ci
2330141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2331141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2332141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2333141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2334141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
2335141cc406Sopenharmony_ci
2336141cc406Sopenharmony_ci  /* "Scan Mode" group: */
2337141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].name = "";
2338141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE_GROUP;
2339141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
2340141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2341141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
2342141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2343141cc406Sopenharmony_ci
2344141cc406Sopenharmony_ci  /* Preview: */
2345141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
2346141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
2347141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
2348141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
2349141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
2350141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w = 0;
2351141cc406Sopenharmony_ci
2352141cc406Sopenharmony_ci  /* Inquiry */
2353141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].name = SANE_NAME_INQUIRY;
2354141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].title = SANE_TITLE_INQUIRY;
2355141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].desc = SANE_DESC_INQUIRY;
2356141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].type = SANE_TYPE_STRING;
2357141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].size = sizeof(inquiry_data);
2358141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].constraint_type = SANE_CONSTRAINT_NONE;
2359141cc406Sopenharmony_ci  s->val[OPT_INQUIRY].s = strdup(inquiry_data);
2360141cc406Sopenharmony_ci  s->opt[OPT_INQUIRY].cap = SANE_CAP_SOFT_DETECT;
2361141cc406Sopenharmony_ci
2362141cc406Sopenharmony_ci  /* scan mode */
2363141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
2364141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
2365141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
2366141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].type = SANE_TYPE_STRING;
2367141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].size = max_string_size (scan_mode_list);
2368141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2369141cc406Sopenharmony_ci  s->opt[OPT_SCAN_MODE].constraint.string_list = scan_mode_list;
2370141cc406Sopenharmony_ci  s->val[OPT_SCAN_MODE].s = strdup (scan_mode_list[0]);
2371141cc406Sopenharmony_ci
2372141cc406Sopenharmony_ci  /* Standard resolutions */
2373141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2374141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
2375141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
2376141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
2377141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
2378141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2379141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.word_list = s->hw->info.resStdList;
2380141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = s->hw->info.res_default;
2381141cc406Sopenharmony_ci
2382141cc406Sopenharmony_ci  /* compression */
2383141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].name = SANE_NAME_COMPRESSION;
2384141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].title = SANE_TITLE_COMPRESSION;
2385141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].desc = SANE_DESC_COMPRESSION;
2386141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].type = SANE_TYPE_STRING;
2387141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].size = max_string_size (compression_list);
2388141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2389141cc406Sopenharmony_ci  s->opt[OPT_COMPRESSION].constraint.string_list = compression_list;
2390141cc406Sopenharmony_ci  s->val[OPT_COMPRESSION].s = strdup (compression_list[0]);
2391141cc406Sopenharmony_ci
2392141cc406Sopenharmony_ci  if (s->hw->info.colorHalftone == SANE_FALSE)
2393141cc406Sopenharmony_ci    {
2394141cc406Sopenharmony_ci      s->opt[OPT_SCAN_MODE].size = max_string_size (scan_mode_min_list);
2395141cc406Sopenharmony_ci      s->opt[OPT_SCAN_MODE].constraint.string_list = scan_mode_min_list;
2396141cc406Sopenharmony_ci    }
2397141cc406Sopenharmony_ci
2398141cc406Sopenharmony_ci  if (s->hw->info.comprG3_1D == SANE_FALSE ||
2399141cc406Sopenharmony_ci      s->hw->info.comprG3_2D == SANE_FALSE ||
2400141cc406Sopenharmony_ci      s->hw->info.comprG4 == SANE_FALSE)
2401141cc406Sopenharmony_ci    {
2402141cc406Sopenharmony_ci      s->opt[OPT_COMPRESSION].cap |= SANE_CAP_INACTIVE;
2403141cc406Sopenharmony_ci    }
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci  /* "Geometry" group: */
2406141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].name = "";
2407141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY_GROUP;
2408141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
2409141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2410141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = 0;
2411141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2412141cc406Sopenharmony_ci
2413141cc406Sopenharmony_ci  /* Autoborder: */
2414141cc406Sopenharmony_ci  s->opt[OPT_AUTOBORDER].name = SANE_NAME_AUTOBORDER;
2415141cc406Sopenharmony_ci  s->opt[OPT_AUTOBORDER].title = SANE_TITLE_AUTOBORDER;
2416141cc406Sopenharmony_ci  s->opt[OPT_AUTOBORDER].desc = SANE_DESC_AUTOBORDER;
2417141cc406Sopenharmony_ci  s->opt[OPT_AUTOBORDER].type = SANE_TYPE_BOOL;
2418141cc406Sopenharmony_ci  s->opt[OPT_AUTOBORDER].constraint_type = SANE_CONSTRAINT_NONE;
2419141cc406Sopenharmony_ci  s->val[OPT_AUTOBORDER].w = s->hw->info.autoborder_default;
2420141cc406Sopenharmony_ci
2421141cc406Sopenharmony_ci  /* Paper Size */
2422141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].name = SANE_NAME_PAPER_SIZE;
2423141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].title = SANE_TITLE_PAPER_SIZE;
2424141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].desc = SANE_DESC_PAPER_SIZE;
2425141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].type = SANE_TYPE_STRING;
2426141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].size = max_string_size (paper_list);
2427141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2428141cc406Sopenharmony_ci  s->opt[OPT_PAPER_SIZE].constraint.string_list = paper_list;
2429141cc406Sopenharmony_ci  s->val[OPT_PAPER_SIZE].s = strdup (paper_list[0]);
2430141cc406Sopenharmony_ci
2431141cc406Sopenharmony_ci  /* rotation */
2432141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].name = SANE_NAME_ROTATION;
2433141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].title = SANE_TITLE_ROTATION;
2434141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].desc = SANE_DESC_ROTATION;
2435141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].type = SANE_TYPE_STRING;
2436141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].size = max_string_size (rotation_list);
2437141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2438141cc406Sopenharmony_ci  s->opt[OPT_ROTATION].constraint.string_list = rotation_list;
2439141cc406Sopenharmony_ci  s->val[OPT_ROTATION].s = strdup (rotation_list[0]);
2440141cc406Sopenharmony_ci
2441141cc406Sopenharmony_ci  /* Deskew: */
2442141cc406Sopenharmony_ci  s->opt[OPT_DESKEW].name = SANE_NAME_DESKEW;
2443141cc406Sopenharmony_ci  s->opt[OPT_DESKEW].title = SANE_TITLE_DESKEW;
2444141cc406Sopenharmony_ci  s->opt[OPT_DESKEW].desc = SANE_DESC_DESKEW;
2445141cc406Sopenharmony_ci  s->opt[OPT_DESKEW].type = SANE_TYPE_BOOL;
2446141cc406Sopenharmony_ci  s->opt[OPT_DESKEW].constraint_type = SANE_CONSTRAINT_NONE;
2447141cc406Sopenharmony_ci  s->val[OPT_DESKEW].w =  s->hw->info.deskew_default;
2448141cc406Sopenharmony_ci
2449141cc406Sopenharmony_ci  /* top-left x */
2450141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2451141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2452141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2453141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
2454141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
2455141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
2456141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &(s->hw->info.x_range);
2457141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = SANE_FIX(0.0);
2458141cc406Sopenharmony_ci
2459141cc406Sopenharmony_ci  /* top-left y */
2460141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2461141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2462141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2463141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
2464141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
2465141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2466141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &(s->hw->info.y_range);
2467141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = SANE_FIX(0.0);
2468141cc406Sopenharmony_ci
2469141cc406Sopenharmony_ci  /* bottom-right x */
2470141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2471141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2472141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2473141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
2474141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
2475141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
2476141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &(s->hw->info.x_range);
2477141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = s->hw->info.x_range.max;
2478141cc406Sopenharmony_ci
2479141cc406Sopenharmony_ci  /* bottom-right y */
2480141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2481141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2482141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2483141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
2484141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
2485141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2486141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &(s->hw->info.y_range);
2487141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = s->hw->info.y_range.max;
2488141cc406Sopenharmony_ci
2489141cc406Sopenharmony_ci  if (s->hw->info.canBorderRecog == SANE_FALSE)
2490141cc406Sopenharmony_ci    {
2491141cc406Sopenharmony_ci      s->opt[OPT_AUTOBORDER].cap |= SANE_CAP_INACTIVE;
2492141cc406Sopenharmony_ci    }
2493141cc406Sopenharmony_ci
2494141cc406Sopenharmony_ci  /* "Feeder" group: */
2495141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].name = "";
2496141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].title = SANE_TITLE_FEEDER_GROUP;
2497141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].desc = "";
2498141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].type = SANE_TYPE_GROUP;
2499141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].cap = SANE_CAP_ADVANCED;
2500141cc406Sopenharmony_ci  s->opt[OPT_FEEDER_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2501141cc406Sopenharmony_ci
2502141cc406Sopenharmony_ci  /* scan source */
2503141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE;
2504141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
2505141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
2506141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING;
2507141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].size = max_string_size (scan_source_list);
2508141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2509141cc406Sopenharmony_ci  s->opt[OPT_SCAN_SOURCE].constraint.string_list = scan_source_list;
2510141cc406Sopenharmony_ci  s->val[OPT_SCAN_SOURCE].s = strdup (scan_source_list[0]);
2511141cc406Sopenharmony_ci
2512141cc406Sopenharmony_ci  /* Batch: */
2513141cc406Sopenharmony_ci  s->opt[OPT_BATCH].name = SANE_NAME_BATCH;
2514141cc406Sopenharmony_ci  s->opt[OPT_BATCH].title = SANE_TITLE_BATCH;
2515141cc406Sopenharmony_ci  s->opt[OPT_BATCH].desc = SANE_DESC_BATCH;
2516141cc406Sopenharmony_ci  s->opt[OPT_BATCH].type = SANE_TYPE_BOOL;
2517141cc406Sopenharmony_ci  s->opt[OPT_BATCH].constraint_type = SANE_CONSTRAINT_NONE;
2518141cc406Sopenharmony_ci  s->val[OPT_BATCH].w =  s->hw->info.batch_default;
2519141cc406Sopenharmony_ci
2520141cc406Sopenharmony_ci  /* Check ADF: */
2521141cc406Sopenharmony_ci  s->opt[OPT_CHECK_ADF].name = SANE_NAME_CHECK_ADF;
2522141cc406Sopenharmony_ci  s->opt[OPT_CHECK_ADF].title = SANE_TITLE_CHECK_ADF;
2523141cc406Sopenharmony_ci  s->opt[OPT_CHECK_ADF].desc = SANE_DESC_CHECK_ADF;
2524141cc406Sopenharmony_ci  s->opt[OPT_CHECK_ADF].type = SANE_TYPE_BOOL;
2525141cc406Sopenharmony_ci  s->opt[OPT_CHECK_ADF].constraint_type = SANE_CONSTRAINT_NONE;
2526141cc406Sopenharmony_ci  s->val[OPT_CHECK_ADF].w =  s->hw->info.check_adf_default;
2527141cc406Sopenharmony_ci
2528141cc406Sopenharmony_ci  /* Duplex: */
2529141cc406Sopenharmony_ci  s->opt[OPT_DUPLEX].name = SANE_NAME_DUPLEX;
2530141cc406Sopenharmony_ci  s->opt[OPT_DUPLEX].title = SANE_TITLE_DUPLEX;
2531141cc406Sopenharmony_ci  s->opt[OPT_DUPLEX].desc = SANE_DESC_DUPLEX;
2532141cc406Sopenharmony_ci  s->opt[OPT_DUPLEX].type = SANE_TYPE_BOOL;
2533141cc406Sopenharmony_ci  s->opt[OPT_DUPLEX].constraint_type = SANE_CONSTRAINT_NONE;
2534141cc406Sopenharmony_ci  s->val[OPT_DUPLEX].w = s->hw->info.duplex_default;
2535141cc406Sopenharmony_ci
2536141cc406Sopenharmony_ci  /* timeout adf */
2537141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].name = SANE_NAME_TIMEOUT_ADF;
2538141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].title = SANE_TITLE_TIMEOUT_ADF;
2539141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].desc = SANE_DESC_TIMEOUT_ADF;
2540141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].type = SANE_TYPE_INT;
2541141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].unit = SANE_UNIT_NONE;
2542141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].constraint_type = SANE_CONSTRAINT_RANGE;
2543141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_ADF].constraint.range = &u8_range;
2544141cc406Sopenharmony_ci  s->val[OPT_TIMEOUT_ADF].w =  s->hw->info.timeout_adf_default;
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci  /* timeout manual */
2547141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].name = SANE_NAME_TIMEOUT_MANUAL;
2548141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].title = SANE_TITLE_TIMEOUT_MANUAL;
2549141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].desc = SANE_DESC_TIMEOUT_MANUAL;
2550141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].type = SANE_TYPE_INT;
2551141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].unit = SANE_UNIT_NONE;
2552141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].constraint_type = SANE_CONSTRAINT_RANGE;
2553141cc406Sopenharmony_ci  s->opt[OPT_TIMEOUT_MANUAL].constraint.range = &u8_range;
2554141cc406Sopenharmony_ci  s->val[OPT_TIMEOUT_MANUAL].w =  s->hw->info.timeout_manual_default;
2555141cc406Sopenharmony_ci
2556141cc406Sopenharmony_ci  if (s->hw->info.canCheckADF == SANE_FALSE)
2557141cc406Sopenharmony_ci    {
2558141cc406Sopenharmony_ci      s->opt[OPT_CHECK_ADF].cap |= SANE_CAP_INACTIVE;
2559141cc406Sopenharmony_ci    }
2560141cc406Sopenharmony_ci
2561141cc406Sopenharmony_ci  if (s->hw->info.canDuplex == SANE_FALSE)
2562141cc406Sopenharmony_ci    {
2563141cc406Sopenharmony_ci      s->opt[OPT_DUPLEX].cap |= SANE_CAP_INACTIVE;
2564141cc406Sopenharmony_ci    }
2565141cc406Sopenharmony_ci
2566141cc406Sopenharmony_ci  if (s->hw->info.canADF == SANE_FALSE)
2567141cc406Sopenharmony_ci    {
2568141cc406Sopenharmony_ci      s->opt[OPT_TIMEOUT_ADF].cap |= SANE_CAP_INACTIVE;
2569141cc406Sopenharmony_ci    }
2570141cc406Sopenharmony_ci
2571141cc406Sopenharmony_ci  /* "Enhancement" group: */
2572141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].name = "";
2573141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_TITLE_ENHANCEMENT_GROUP;
2574141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
2575141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2576141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
2577141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2578141cc406Sopenharmony_ci
2579141cc406Sopenharmony_ci  /* Control Panel: */
2580141cc406Sopenharmony_ci  s->opt[OPT_CONTROL_PANEL].name = SANE_NAME_CONTROL_PANEL;
2581141cc406Sopenharmony_ci  s->opt[OPT_CONTROL_PANEL].title = SANE_TITLE_CONTROL_PANEL;
2582141cc406Sopenharmony_ci  s->opt[OPT_CONTROL_PANEL].desc = SANE_DESC_CONTROL_PANEL;
2583141cc406Sopenharmony_ci  s->opt[OPT_CONTROL_PANEL].type = SANE_TYPE_BOOL;
2584141cc406Sopenharmony_ci  s->opt[OPT_CONTROL_PANEL].constraint_type = SANE_CONSTRAINT_NONE;
2585141cc406Sopenharmony_ci  s->val[OPT_CONTROL_PANEL].w =  s->hw->info.control_panel_default;
2586141cc406Sopenharmony_ci
2587141cc406Sopenharmony_ci  /* Ace_Function */
2588141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].name = SANE_NAME_ACE_FUNCTION;
2589141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].title = SANE_TITLE_ACE_FUNCTION;
2590141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].desc = SANE_DESC_ACE_FUNCTION;
2591141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].type = SANE_TYPE_INT;
2592141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].unit = SANE_UNIT_NONE;
2593141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].constraint_type = SANE_CONSTRAINT_RANGE;
2594141cc406Sopenharmony_ci  s->opt[OPT_ACE_FUNCTION].constraint.range = &ace_function_range;
2595141cc406Sopenharmony_ci  s->val[OPT_ACE_FUNCTION].w = 0;
2596141cc406Sopenharmony_ci
2597141cc406Sopenharmony_ci  /* Ace_Sensitivity */
2598141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].name = SANE_NAME_ACE_SENSITIVITY;
2599141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].title = SANE_TITLE_ACE_SENSITIVITY;
2600141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].desc = SANE_DESC_ACE_SENSITIVITY;
2601141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].type = SANE_TYPE_INT;
2602141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].unit = SANE_UNIT_NONE;
2603141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].constraint_type = SANE_CONSTRAINT_RANGE;
2604141cc406Sopenharmony_ci  s->opt[OPT_ACE_SENSITIVITY].constraint.range = &ace_sensitivity_range;
2605141cc406Sopenharmony_ci  s->val[OPT_ACE_SENSITIVITY].w = 4;
2606141cc406Sopenharmony_ci
2607141cc406Sopenharmony_ci  /* Brightness */
2608141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2609141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2610141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2611141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
2612141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
2613141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2614141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint.range = &u8_range;
2615141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS].w = 0;
2616141cc406Sopenharmony_ci
2617141cc406Sopenharmony_ci  /* Threshold */
2618141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
2619141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
2620141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
2621141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
2622141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
2623141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
2624141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint.range = &u8_range;
2625141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD].w = 0;
2626141cc406Sopenharmony_ci
2627141cc406Sopenharmony_ci  /* Contrast */
2628141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
2629141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
2630141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
2631141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
2632141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
2633141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2634141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint.range = &u8_range;
2635141cc406Sopenharmony_ci  s->val[OPT_CONTRAST].w = 0;
2636141cc406Sopenharmony_ci
2637141cc406Sopenharmony_ci  /* Negative: */
2638141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].name = SANE_NAME_NEGATIVE;
2639141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE;
2640141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].desc = SANE_DESC_NEGATIVE;
2641141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].type = SANE_TYPE_BOOL;
2642141cc406Sopenharmony_ci  s->opt[OPT_NEGATIVE].constraint_type = SANE_CONSTRAINT_NONE;
2643141cc406Sopenharmony_ci  s->val[OPT_NEGATIVE].w = SANE_FALSE;
2644141cc406Sopenharmony_ci
2645141cc406Sopenharmony_ci  /* Contrast is not used in any case; why did we add it? */
2646141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2647141cc406Sopenharmony_ci  if (s->hw->info.control_panel_default == SANE_TRUE)
2648141cc406Sopenharmony_ci    {
2649141cc406Sopenharmony_ci      s->opt[OPT_ACE_FUNCTION].cap |= SANE_CAP_INACTIVE;
2650141cc406Sopenharmony_ci      s->opt[OPT_ACE_SENSITIVITY].cap |= SANE_CAP_INACTIVE;
2651141cc406Sopenharmony_ci      s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2652141cc406Sopenharmony_ci      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2653141cc406Sopenharmony_ci    }
2654141cc406Sopenharmony_ci  else if (s->hw->info.canACE == SANE_FALSE)
2655141cc406Sopenharmony_ci    {
2656141cc406Sopenharmony_ci      s->opt[OPT_ACE_FUNCTION].cap |= SANE_CAP_INACTIVE;
2657141cc406Sopenharmony_ci      s->opt[OPT_ACE_SENSITIVITY].cap |= SANE_CAP_INACTIVE;
2658141cc406Sopenharmony_ci    }
2659141cc406Sopenharmony_ci  else
2660141cc406Sopenharmony_ci    {
2661141cc406Sopenharmony_ci      s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2662141cc406Sopenharmony_ci      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2663141cc406Sopenharmony_ci    }
2664141cc406Sopenharmony_ci
2665141cc406Sopenharmony_ci  /* "ICON" group: */
2666141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].name = "";
2667141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].title = SANE_TITLE_ICON_GROUP;
2668141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].desc = "";
2669141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].type = SANE_TYPE_GROUP;
2670141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].cap = SANE_CAP_ADVANCED;
2671141cc406Sopenharmony_ci  s->opt[OPT_ICON_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2672141cc406Sopenharmony_ci
2673141cc406Sopenharmony_ci  /* Icon_Width */
2674141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].name = SANE_NAME_ICON_WIDTH;
2675141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].title = SANE_TITLE_ICON_WIDTH;
2676141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].desc = SANE_DESC_ICON_WIDTH;
2677141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].type = SANE_TYPE_INT;
2678141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].unit = SANE_UNIT_PIXEL;
2679141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].constraint_type = SANE_CONSTRAINT_RANGE;
2680141cc406Sopenharmony_ci  s->opt[OPT_ICON_WIDTH].constraint.range = &icon_range;
2681141cc406Sopenharmony_ci  s->val[OPT_ICON_WIDTH].w = 0;
2682141cc406Sopenharmony_ci
2683141cc406Sopenharmony_ci  /* Icon_Length */
2684141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].name = SANE_NAME_ICON_LENGTH;
2685141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].title = SANE_TITLE_ICON_LENGTH;
2686141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].desc = SANE_DESC_ICON_LENGTH;
2687141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].type = SANE_TYPE_INT;
2688141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].unit = SANE_UNIT_PIXEL;
2689141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].constraint_type = SANE_CONSTRAINT_RANGE;
2690141cc406Sopenharmony_ci  s->opt[OPT_ICON_LENGTH].constraint.range = &icon_range;
2691141cc406Sopenharmony_ci  s->val[OPT_ICON_LENGTH].w = 0;
2692141cc406Sopenharmony_ci
2693141cc406Sopenharmony_ci  if (s->hw->info.canIcon == SANE_FALSE)
2694141cc406Sopenharmony_ci    {
2695141cc406Sopenharmony_ci      s->opt[OPT_ICON_GROUP].cap |= SANE_CAP_INACTIVE;
2696141cc406Sopenharmony_ci      s->opt[OPT_ICON_WIDTH].cap |= SANE_CAP_INACTIVE;
2697141cc406Sopenharmony_ci      s->opt[OPT_ICON_LENGTH].cap |= SANE_CAP_INACTIVE;
2698141cc406Sopenharmony_ci    }
2699141cc406Sopenharmony_ci
2700141cc406Sopenharmony_ci  /* "Barcode" group: */
2701141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].name = "";
2702141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].title = SANE_TITLE_BARCODE_GROUP;
2703141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].desc = "";
2704141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].type = SANE_TYPE_GROUP;
2705141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].cap = SANE_CAP_ADVANCED;
2706141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2707141cc406Sopenharmony_ci
2708141cc406Sopenharmony_ci  /* Add <name> to barcode search priority. */
2709141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].name = SANE_NAME_BARCODE_SEARCH_BAR;
2710141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].title = SANE_TITLE_BARCODE_SEARCH_BAR;
2711141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].desc = SANE_DESC_BARCODE_SEARCH_BAR;
2712141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].type = SANE_TYPE_STRING;
2713141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].unit = SANE_UNIT_NONE;
2714141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2715141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].constraint.string_list = barcode_search_bar_list;
2716141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_BAR].size = max_string_size (barcode_search_bar_list);
2717141cc406Sopenharmony_ci  s->val[OPT_BARCODE_SEARCH_BAR].s = strdup (barcode_search_bar_list[0]);
2718141cc406Sopenharmony_ci
2719141cc406Sopenharmony_ci  /* Barcode search count (1-7, default 1). */
2720141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].name = SANE_NAME_BARCODE_SEARCH_COUNT;
2721141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].title = SANE_TITLE_BARCODE_SEARCH_COUNT;
2722141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].desc = SANE_DESC_BARCODE_SEARCH_COUNT;
2723141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].type = SANE_TYPE_INT;
2724141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].unit = SANE_UNIT_NONE;
2725141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].constraint_type = SANE_CONSTRAINT_RANGE;
2726141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_COUNT].constraint.range = &barcode_search_count_range;
2727141cc406Sopenharmony_ci  s->val[OPT_BARCODE_SEARCH_COUNT].w =  3;
2728141cc406Sopenharmony_ci
2729141cc406Sopenharmony_ci  /* Barcode search mode. horiz-vert, horizontal, vertical, vert-horiz */
2730141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].name = SANE_NAME_BARCODE_SEARCH_MODE;
2731141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].title = SANE_TITLE_BARCODE_SEARCH_MODE;
2732141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].desc = SANE_DESC_BARCODE_SEARCH_MODE;
2733141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].type = SANE_TYPE_STRING;
2734141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].size = max_string_size (barcode_search_mode_list);
2735141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2736141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_MODE].constraint.string_list = barcode_search_mode_list;
2737141cc406Sopenharmony_ci  s->val[OPT_BARCODE_SEARCH_MODE].s = strdup(barcode_search_mode_list[0]);
2738141cc406Sopenharmony_ci
2739141cc406Sopenharmony_ci  /* Patch code min height (def=5mm) */
2740141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].name = SANE_NAME_BARCODE_HMIN;
2741141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].title = SANE_TITLE_BARCODE_HMIN;
2742141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].desc = SANE_DESC_BARCODE_HMIN;
2743141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].type = SANE_TYPE_INT;
2744141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].unit = SANE_UNIT_MM;
2745141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].constraint_type = SANE_CONSTRAINT_RANGE;
2746141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_HMIN].constraint.range = &barcode_hmin_range;
2747141cc406Sopenharmony_ci  s->val[OPT_BARCODE_HMIN].w =  5;
2748141cc406Sopenharmony_ci
2749141cc406Sopenharmony_ci  /* Barcode search timeout in ms (20-65535,default is 10000). */
2750141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].name = SANE_NAME_BARCODE_SEARCH_TIMEOUT;
2751141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].title = SANE_TITLE_BARCODE_SEARCH_TIMEOUT;
2752141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].desc = SANE_DESC_BARCODE_SEARCH_TIMEOUT;
2753141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].type = SANE_TYPE_INT;
2754141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].unit = SANE_UNIT_MICROSECOND;
2755141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE;
2756141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_SEARCH_TIMEOUT].constraint.range = &barcode_search_timeout_range;
2757141cc406Sopenharmony_ci  s->val[OPT_BARCODE_SEARCH_TIMEOUT].w =  10000;
2758141cc406Sopenharmony_ci
2759141cc406Sopenharmony_ci  /* Specify image sections and functions */
2760141cc406Sopenharmony_ci  s->opt[OPT_SECTION].name = SANE_NAME_SECTION;
2761141cc406Sopenharmony_ci  s->opt[OPT_SECTION].title = SANE_TITLE_SECTION;
2762141cc406Sopenharmony_ci  s->opt[OPT_SECTION].desc = SANE_DESC_SECTION;
2763141cc406Sopenharmony_ci  s->opt[OPT_SECTION].type = SANE_TYPE_STRING;
2764141cc406Sopenharmony_ci  s->opt[OPT_SECTION].unit = SANE_UNIT_NONE;
2765141cc406Sopenharmony_ci  s->opt[OPT_SECTION].constraint_type = SANE_CONSTRAINT_NONE;
2766141cc406Sopenharmony_ci  s->opt[OPT_SECTION].size = 255;
2767141cc406Sopenharmony_ci  s->val[OPT_SECTION].s = strdup ("");
2768141cc406Sopenharmony_ci
2769141cc406Sopenharmony_ci  /* Barcode_Relmax */
2770141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].name = SANE_NAME_BARCODE_RELMAX;
2771141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].title = SANE_TITLE_BARCODE_RELMAX;
2772141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].desc = SANE_DESC_BARCODE_RELMAX;
2773141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].type = SANE_TYPE_INT;
2774141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].unit = SANE_UNIT_NONE;
2775141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].constraint_type = SANE_CONSTRAINT_RANGE;
2776141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_RELMAX].constraint.range = &u8_range;
2777141cc406Sopenharmony_ci  s->val[OPT_BARCODE_RELMAX].w = 0;
2778141cc406Sopenharmony_ci
2779141cc406Sopenharmony_ci  /* Barcode_Barmin */
2780141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].name = SANE_NAME_BARCODE_BARMIN;
2781141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].title = SANE_TITLE_BARCODE_BARMIN;
2782141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].desc = SANE_DESC_BARCODE_BARMIN;
2783141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].type = SANE_TYPE_INT;
2784141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].unit = SANE_UNIT_NONE;
2785141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].constraint_type = SANE_CONSTRAINT_RANGE;
2786141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMIN].constraint.range = &u8_range;
2787141cc406Sopenharmony_ci  s->val[OPT_BARCODE_BARMIN].w = 0;
2788141cc406Sopenharmony_ci
2789141cc406Sopenharmony_ci  /* Barcode_Barmax */
2790141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].name = SANE_NAME_BARCODE_BARMAX;
2791141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].title = SANE_TITLE_BARCODE_BARMAX;
2792141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].desc = SANE_DESC_BARCODE_BARMAX;
2793141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].type = SANE_TYPE_INT;
2794141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].unit = SANE_UNIT_NONE;
2795141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].constraint_type = SANE_CONSTRAINT_RANGE;
2796141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_BARMAX].constraint.range = &u8_range;
2797141cc406Sopenharmony_ci  s->val[OPT_BARCODE_BARMAX].w = 0;
2798141cc406Sopenharmony_ci
2799141cc406Sopenharmony_ci  /* Barcode_Contrast */
2800141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].name = SANE_NAME_BARCODE_CONTRAST;
2801141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].title = SANE_TITLE_BARCODE_CONTRAST;
2802141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].desc = SANE_DESC_BARCODE_CONTRAST;
2803141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].type = SANE_TYPE_INT;
2804141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].unit = SANE_UNIT_NONE;
2805141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2806141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_CONTRAST].constraint.range = &barcode_contrast_range;
2807141cc406Sopenharmony_ci  s->val[OPT_BARCODE_CONTRAST].w = 3;
2808141cc406Sopenharmony_ci
2809141cc406Sopenharmony_ci  /* Barcode_Patchmode */
2810141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].name = SANE_NAME_BARCODE_PATCHMODE;
2811141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].title = SANE_TITLE_BARCODE_PATCHMODE;
2812141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].desc = SANE_DESC_BARCODE_PATCHMODE;
2813141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].type = SANE_TYPE_INT;
2814141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].unit = SANE_UNIT_NONE;
2815141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].constraint_type = SANE_CONSTRAINT_RANGE;
2816141cc406Sopenharmony_ci  s->opt[OPT_BARCODE_PATCHMODE].constraint.range = &barcode_patchmode_range;
2817141cc406Sopenharmony_ci  s->val[OPT_BARCODE_PATCHMODE].w = 0;
2818141cc406Sopenharmony_ci
2819141cc406Sopenharmony_ci  if (s->hw->info.canSection == SANE_FALSE)
2820141cc406Sopenharmony_ci    {
2821141cc406Sopenharmony_ci      s->opt[OPT_SECTION].cap |= SANE_CAP_INACTIVE;
2822141cc406Sopenharmony_ci    }
2823141cc406Sopenharmony_ci
2824141cc406Sopenharmony_ci  if (s->hw->info.canBarCode == SANE_FALSE)
2825141cc406Sopenharmony_ci    {
2826141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_GROUP].cap |= SANE_CAP_INACTIVE;
2827141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_SEARCH_BAR].cap |= SANE_CAP_INACTIVE;
2828141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_SEARCH_COUNT].cap |= SANE_CAP_INACTIVE;
2829141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_SEARCH_MODE].cap |= SANE_CAP_INACTIVE;
2830141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_HMIN].cap |= SANE_CAP_INACTIVE;
2831141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_SEARCH_TIMEOUT].cap |= SANE_CAP_INACTIVE;
2832141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_RELMAX].cap |= SANE_CAP_INACTIVE;
2833141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_BARMIN].cap |= SANE_CAP_INACTIVE;
2834141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_BARMAX].cap |= SANE_CAP_INACTIVE;
2835141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_CONTRAST].cap |= SANE_CAP_INACTIVE;
2836141cc406Sopenharmony_ci      s->opt[OPT_BARCODE_PATCHMODE].cap |= SANE_CAP_INACTIVE;
2837141cc406Sopenharmony_ci    }
2838141cc406Sopenharmony_ci
2839141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2840141cc406Sopenharmony_ci}
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_cistatic SANE_Status
2843141cc406Sopenharmony_ciattach (const char *devnam, BH_Device ** devp)
2844141cc406Sopenharmony_ci{
2845141cc406Sopenharmony_ci  SANE_Status status;
2846141cc406Sopenharmony_ci  BH_Device *dev;
2847141cc406Sopenharmony_ci  struct inquiry_standard_data ibuf;
2848141cc406Sopenharmony_ci  struct inquiry_vpd_data vbuf;
2849141cc406Sopenharmony_ci  struct inquiry_jis_data jbuf;
2850141cc406Sopenharmony_ci  size_t buf_size;
2851141cc406Sopenharmony_ci  int fd = -1;
2852141cc406Sopenharmony_ci  double mm;
2853141cc406Sopenharmony_ci
2854141cc406Sopenharmony_ci  DBG (3, "attach called\n");
2855141cc406Sopenharmony_ci
2856141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
2857141cc406Sopenharmony_ci    {
2858141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devnam) == 0)
2859141cc406Sopenharmony_ci        {
2860141cc406Sopenharmony_ci          if (devp)
2861141cc406Sopenharmony_ci            *devp = dev;
2862141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
2863141cc406Sopenharmony_ci        }
2864141cc406Sopenharmony_ci    }
2865141cc406Sopenharmony_ci
2866141cc406Sopenharmony_ci#ifdef FAKE_INQUIRY
2867141cc406Sopenharmony_ci  if (fake_inquiry)
2868141cc406Sopenharmony_ci    {
2869141cc406Sopenharmony_ci      DBG (3, "attach: faking inquiry of %s\n", devnam);
2870141cc406Sopenharmony_ci
2871141cc406Sopenharmony_ci      memset (&ibuf, 0, sizeof (ibuf));
2872141cc406Sopenharmony_ci      ibuf.devtype = 6;
2873141cc406Sopenharmony_ci      memcpy(ibuf.vendor, "**FAKE**", 8);
2874141cc406Sopenharmony_ci      memcpy(ibuf.product, "COPISCAN II 6338", 16);
2875141cc406Sopenharmony_ci      memcpy(ibuf.revision, "0016", 4);
2876141cc406Sopenharmony_ci
2877141cc406Sopenharmony_ci      DBG (1, "attach: reported devtype='%d', vendor='%.8s', "
2878141cc406Sopenharmony_ci	   "product='%.16s', revision='%.4s'\n",
2879141cc406Sopenharmony_ci	   ibuf.devtype, ibuf.vendor,
2880141cc406Sopenharmony_ci	   ibuf.product, ibuf.revision);
2881141cc406Sopenharmony_ci
2882141cc406Sopenharmony_ci      memset (&vbuf, 0, sizeof (vbuf));
2883141cc406Sopenharmony_ci      memset (&jbuf, 0, sizeof (jbuf));
2884141cc406Sopenharmony_ci    }
2885141cc406Sopenharmony_ci  else
2886141cc406Sopenharmony_ci#endif
2887141cc406Sopenharmony_ci    {
2888141cc406Sopenharmony_ci      DBG (3, "attach: opening %s\n", devnam);
2889141cc406Sopenharmony_ci      status = sanei_scsi_open (devnam, &fd, sense_handler, NULL);
2890141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2891141cc406Sopenharmony_ci	{
2892141cc406Sopenharmony_ci	  DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
2893141cc406Sopenharmony_ci	  return status;
2894141cc406Sopenharmony_ci	}
2895141cc406Sopenharmony_ci
2896141cc406Sopenharmony_ci      DBG (3, "attach: sending TEST_UNIT_READY\n");
2897141cc406Sopenharmony_ci      status = test_unit_ready (fd);
2898141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2899141cc406Sopenharmony_ci	{
2900141cc406Sopenharmony_ci	  DBG (1, "attach: test unit ready failed (%s)\n",
2901141cc406Sopenharmony_ci	       sane_strstatus (status));
2902141cc406Sopenharmony_ci	  sanei_scsi_close (fd);
2903141cc406Sopenharmony_ci	  return status;
2904141cc406Sopenharmony_ci	}
2905141cc406Sopenharmony_ci
2906141cc406Sopenharmony_ci      DBG (3, "attach: sending INQUIRY (standard data)\n");
2907141cc406Sopenharmony_ci      memset (&ibuf, 0, sizeof (ibuf));
2908141cc406Sopenharmony_ci      buf_size = sizeof(ibuf);
2909141cc406Sopenharmony_ci      status = inquiry (fd, &ibuf, &buf_size, 0,
2910141cc406Sopenharmony_ci			BH_INQUIRY_STANDARD_PAGE_CODE);
2911141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2912141cc406Sopenharmony_ci	{
2913141cc406Sopenharmony_ci	  DBG (1, "attach: inquiry (standard data) failed: %s\n",
2914141cc406Sopenharmony_ci	       sane_strstatus (status));
2915141cc406Sopenharmony_ci	  sanei_scsi_close (fd);
2916141cc406Sopenharmony_ci	  return status;
2917141cc406Sopenharmony_ci	}
2918141cc406Sopenharmony_ci
2919141cc406Sopenharmony_ci      DBG (1, "attach: reported devtype='%d', vendor='%.8s', "
2920141cc406Sopenharmony_ci	   "product='%.16s', revision='%.4s'\n",
2921141cc406Sopenharmony_ci	   ibuf.devtype, ibuf.vendor,
2922141cc406Sopenharmony_ci	   ibuf.product, ibuf.revision);
2923141cc406Sopenharmony_ci
2924141cc406Sopenharmony_ci      if (ibuf.devtype != 6
2925141cc406Sopenharmony_ci	  || strncmp ((char *)ibuf.vendor, "B&H SCSI", 8) != 0
2926141cc406Sopenharmony_ci	  || strncmp ((char *)ibuf.product, "COPISCAN ", 9) != 0)
2927141cc406Sopenharmony_ci	{
2928141cc406Sopenharmony_ci	  DBG (1,
2929141cc406Sopenharmony_ci	       "attach: device is not a recognized Bell and Howell scanner\n");
2930141cc406Sopenharmony_ci	  sanei_scsi_close (fd);
2931141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
2932141cc406Sopenharmony_ci	}
2933141cc406Sopenharmony_ci
2934141cc406Sopenharmony_ci      DBG (3, "attach: sending INQUIRY (vpd data)\n");
2935141cc406Sopenharmony_ci      memset (&vbuf, 0, sizeof (vbuf));
2936141cc406Sopenharmony_ci      buf_size = sizeof(vbuf);
2937141cc406Sopenharmony_ci      status = inquiry (fd, &vbuf, &buf_size, 1,
2938141cc406Sopenharmony_ci			BH_INQUIRY_VPD_PAGE_CODE);
2939141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2940141cc406Sopenharmony_ci	{
2941141cc406Sopenharmony_ci	  DBG (1, "attach: inquiry (vpd data) failed: %s\n",
2942141cc406Sopenharmony_ci	       sane_strstatus (status));
2943141cc406Sopenharmony_ci	  sanei_scsi_close (fd);
2944141cc406Sopenharmony_ci	  return status;
2945141cc406Sopenharmony_ci	}
2946141cc406Sopenharmony_ci
2947141cc406Sopenharmony_ci      DBG (3, "attach: sending INQUIRY (jis data)\n");
2948141cc406Sopenharmony_ci      memset (&jbuf, 0, sizeof (jbuf));
2949141cc406Sopenharmony_ci      buf_size = sizeof(jbuf);
2950141cc406Sopenharmony_ci      status = inquiry (fd, &jbuf, &buf_size, 1,
2951141cc406Sopenharmony_ci			BH_INQUIRY_JIS_PAGE_CODE);
2952141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2953141cc406Sopenharmony_ci	{
2954141cc406Sopenharmony_ci	  DBG (1, "attach: inquiry (jis data) failed: %s\n",
2955141cc406Sopenharmony_ci	       sane_strstatus (status));
2956141cc406Sopenharmony_ci	  sanei_scsi_close (fd);
2957141cc406Sopenharmony_ci	  return status;
2958141cc406Sopenharmony_ci	}
2959141cc406Sopenharmony_ci
2960141cc406Sopenharmony_ci      sanei_scsi_close (fd);
2961141cc406Sopenharmony_ci    }
2962141cc406Sopenharmony_ci
2963141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
2964141cc406Sopenharmony_ci  if (!dev)
2965141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2966141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
2967141cc406Sopenharmony_ci
2968141cc406Sopenharmony_ci
2969141cc406Sopenharmony_ci  dev->info.devtype = ibuf.devtype;
2970141cc406Sopenharmony_ci  sprintf(dev->info.vendor, "%.8s", ibuf.vendor);
2971141cc406Sopenharmony_ci  trim_spaces(dev->info.vendor, sizeof(dev->info.vendor));
2972141cc406Sopenharmony_ci  sprintf(dev->info.product, "%.16s", ibuf.product);
2973141cc406Sopenharmony_ci  trim_spaces(dev->info.product, sizeof(dev->info.product));
2974141cc406Sopenharmony_ci  sprintf(dev->info.revision, "%.4s", ibuf.revision);
2975141cc406Sopenharmony_ci  trim_spaces(dev->info.revision, sizeof(dev->info.revision));
2976141cc406Sopenharmony_ci
2977141cc406Sopenharmony_ci  dev->sane.name = strdup (devnam);
2978141cc406Sopenharmony_ci  dev->sane.vendor = strdup(dev->info.vendor);
2979141cc406Sopenharmony_ci  dev->sane.model = strdup(dev->info.product);;
2980141cc406Sopenharmony_ci  dev->sane.type = strdup(print_devtype(dev->info.devtype));
2981141cc406Sopenharmony_ci
2982141cc406Sopenharmony_ci  /* set capabilities from vpd */
2983141cc406Sopenharmony_ci  dev->info.canADF = vbuf.adf & 0x01;
2984141cc406Sopenharmony_ci  dev->info.colorBandW = vbuf.imagecomposition & 0x01;
2985141cc406Sopenharmony_ci  dev->info.colorHalftone = vbuf.imagecomposition & 0x02;
2986141cc406Sopenharmony_ci  dev->info.canWhiteFrame = vbuf.imagedataprocessing[1] & 0x01;
2987141cc406Sopenharmony_ci  dev->info.canBlackFrame = vbuf.imagedataprocessing[1] & 0x02;
2988141cc406Sopenharmony_ci  dev->info.canEdgeExtract = vbuf.imagedataprocessing[1] & 0x04;
2989141cc406Sopenharmony_ci  dev->info.canNoiseFilter = vbuf.imagedataprocessing[1] & 0x08;
2990141cc406Sopenharmony_ci  dev->info.canSmooth = vbuf.imagedataprocessing[1] & 0x10;
2991141cc406Sopenharmony_ci  dev->info.canLineBold = vbuf.imagedataprocessing[1] & 0x20;
2992141cc406Sopenharmony_ci  dev->info.comprG3_1D = vbuf.compression & 0x01;
2993141cc406Sopenharmony_ci  dev->info.comprG3_2D = vbuf.compression & 0x02;
2994141cc406Sopenharmony_ci  dev->info.comprG4 = vbuf.compression & 0x04;
2995141cc406Sopenharmony_ci  dev->info.canBorderRecog = vbuf.sizerecognition & 0x01;
2996141cc406Sopenharmony_ci  dev->info.canBarCode = vbuf.optionalfeatures & 0x01;
2997141cc406Sopenharmony_ci  dev->info.canIcon = vbuf.optionalfeatures & 0x02;
2998141cc406Sopenharmony_ci  dev->info.canSection = vbuf.optionalfeatures & 0x04;
2999141cc406Sopenharmony_ci  dev->info.lineMaxBytes = _2btol(vbuf.xmaxoutputbytes);
3000141cc406Sopenharmony_ci
3001141cc406Sopenharmony_ci#ifdef FAKE_INQUIRY
3002141cc406Sopenharmony_ci  if (fake_inquiry)
3003141cc406Sopenharmony_ci    {
3004141cc406Sopenharmony_ci      dev->info.canADF = SANE_FALSE;
3005141cc406Sopenharmony_ci      dev->info.colorBandW = SANE_TRUE;
3006141cc406Sopenharmony_ci      dev->info.colorHalftone = SANE_TRUE;
3007141cc406Sopenharmony_ci      dev->info.canWhiteFrame = SANE_TRUE;
3008141cc406Sopenharmony_ci      dev->info.canBlackFrame = SANE_TRUE;
3009141cc406Sopenharmony_ci      dev->info.canEdgeExtract = SANE_TRUE;
3010141cc406Sopenharmony_ci      dev->info.canNoiseFilter = SANE_TRUE;
3011141cc406Sopenharmony_ci      dev->info.canSmooth = SANE_TRUE;
3012141cc406Sopenharmony_ci      dev->info.canLineBold = SANE_TRUE;
3013141cc406Sopenharmony_ci      dev->info.comprG3_1D = SANE_TRUE;
3014141cc406Sopenharmony_ci      dev->info.comprG3_2D = SANE_TRUE;
3015141cc406Sopenharmony_ci      dev->info.comprG4 = SANE_TRUE;
3016141cc406Sopenharmony_ci      dev->info.canBorderRecog = SANE_TRUE;
3017141cc406Sopenharmony_ci      dev->info.canBarCode = SANE_TRUE;
3018141cc406Sopenharmony_ci      dev->info.canIcon = SANE_TRUE;
3019141cc406Sopenharmony_ci      dev->info.canSection = SANE_TRUE;
3020141cc406Sopenharmony_ci      dev->info.lineMaxBytes = 450;
3021141cc406Sopenharmony_ci    }
3022141cc406Sopenharmony_ci#endif
3023141cc406Sopenharmony_ci
3024141cc406Sopenharmony_ci  /* set capabilities from jis */
3025141cc406Sopenharmony_ci  dev->info.resBasicX = _2btol(jbuf.basicxres);
3026141cc406Sopenharmony_ci  dev->info.resBasicY = _2btol(jbuf.basicyres);
3027141cc406Sopenharmony_ci  dev->info.resMaxX = _2btol(jbuf.maxxres);
3028141cc406Sopenharmony_ci  dev->info.resMaxY = _2btol(jbuf.maxyres);
3029141cc406Sopenharmony_ci  dev->info.resMinX = _2btol(jbuf.minxres);
3030141cc406Sopenharmony_ci  dev->info.resMinY = _2btol(jbuf.minyres);
3031141cc406Sopenharmony_ci
3032141cc406Sopenharmony_ci  /* set the length of the list to zero first, then append standard resolutions */
3033141cc406Sopenharmony_ci  dev->info.resStdList[0] = 0;
3034141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x80) appendStdList(&dev->info, 60);
3035141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x40) appendStdList(&dev->info, 75);
3036141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x20) appendStdList(&dev->info, 100);
3037141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x10) appendStdList(&dev->info, 120);
3038141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x08) appendStdList(&dev->info, 150);
3039141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x04) appendStdList(&dev->info, 160);
3040141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x02) appendStdList(&dev->info, 180);
3041141cc406Sopenharmony_ci  if (jbuf.standardres[0] & 0x01) appendStdList(&dev->info, 200);
3042141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x80) appendStdList(&dev->info, 240);
3043141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x40) appendStdList(&dev->info, 300);
3044141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x20) appendStdList(&dev->info, 320);
3045141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x10) appendStdList(&dev->info, 400);
3046141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x08) appendStdList(&dev->info, 480);
3047141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x04) appendStdList(&dev->info, 600);
3048141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x02) appendStdList(&dev->info, 800);
3049141cc406Sopenharmony_ci  if (jbuf.standardres[1] & 0x01) appendStdList(&dev->info, 1200);
3050141cc406Sopenharmony_ci  if (dev->info.resStdList[0] == 0)
3051141cc406Sopenharmony_ci    {
3052141cc406Sopenharmony_ci      /* make a default standard resolutions for 200 and 300dpi */
3053141cc406Sopenharmony_ci      DBG(1, "attach: no standard resolutions reported\n");
3054141cc406Sopenharmony_ci      dev->info.resStdList[0] = 2;
3055141cc406Sopenharmony_ci      dev->info.resStdList[1] = 200;
3056141cc406Sopenharmony_ci      dev->info.resStdList[2] = 300;
3057141cc406Sopenharmony_ci      dev->info.resBasicX = dev->info.resBasicY = 300;
3058141cc406Sopenharmony_ci    }
3059141cc406Sopenharmony_ci
3060141cc406Sopenharmony_ci  dev->info.winWidth = _4btol(jbuf.windowwidth);
3061141cc406Sopenharmony_ci  dev->info.winHeight = _4btol(jbuf.windowlength);
3062141cc406Sopenharmony_ci
3063141cc406Sopenharmony_ci  if (dev->info.winWidth <= 0)
3064141cc406Sopenharmony_ci    {
3065141cc406Sopenharmony_ci      dev->info.winWidth = (SANE_Int) (dev->info.resBasicX * 8.5);
3066141cc406Sopenharmony_ci      DBG(1, "attach: invalid window width reported, using %d\n", dev->info.winWidth);
3067141cc406Sopenharmony_ci    }
3068141cc406Sopenharmony_ci  if (dev->info.winHeight <= 0)
3069141cc406Sopenharmony_ci    {
3070141cc406Sopenharmony_ci      dev->info.winHeight = dev->info.resBasicY * 14;
3071141cc406Sopenharmony_ci      DBG(1, "attach: invalid window height reported, using %d\n", dev->info.winHeight);
3072141cc406Sopenharmony_ci    }
3073141cc406Sopenharmony_ci
3074141cc406Sopenharmony_ci  mm = (dev->info.resBasicX > 0) ?
3075141cc406Sopenharmony_ci    ((double) dev->info.winWidth / (double) dev->info.resBasicX * MM_PER_INCH) :
3076141cc406Sopenharmony_ci    0.0;
3077141cc406Sopenharmony_ci  dev->info.x_range.min = SANE_FIX(0.0);
3078141cc406Sopenharmony_ci  dev->info.x_range.max = SANE_FIX(mm);
3079141cc406Sopenharmony_ci  dev->info.x_range.quant = SANE_FIX(0.0);
3080141cc406Sopenharmony_ci
3081141cc406Sopenharmony_ci  mm = (dev->info.resBasicY > 0) ?
3082141cc406Sopenharmony_ci    ((double) dev->info.winHeight / (double) dev->info.resBasicY * MM_PER_INCH) :
3083141cc406Sopenharmony_ci    0.0;
3084141cc406Sopenharmony_ci  dev->info.y_range.min = SANE_FIX(0.0);
3085141cc406Sopenharmony_ci  dev->info.y_range.max = SANE_FIX(mm);
3086141cc406Sopenharmony_ci  dev->info.y_range.quant = SANE_FIX(0.0);
3087141cc406Sopenharmony_ci
3088141cc406Sopenharmony_ci  /* set additional discovered/guessed capabilities */
3089141cc406Sopenharmony_ci
3090141cc406Sopenharmony_ci  /* if all of the ACE capabilities are present, declare it ACE capable */
3091141cc406Sopenharmony_ci  dev->info.canACE = dev->info.canEdgeExtract &&
3092141cc406Sopenharmony_ci    dev->info.canNoiseFilter &&
3093141cc406Sopenharmony_ci    dev->info.canSmooth &&
3094141cc406Sopenharmony_ci    dev->info.canLineBold;
3095141cc406Sopenharmony_ci
3096141cc406Sopenharmony_ci  /* if the model is known to be a duplex, declare it duplex capable */
3097141cc406Sopenharmony_ci  if (strcmp(dev->info.product, "COPISCAN II 6338") == 0)
3098141cc406Sopenharmony_ci    {
3099141cc406Sopenharmony_ci      dev->info.canDuplex = SANE_TRUE;
3100141cc406Sopenharmony_ci    }
3101141cc406Sopenharmony_ci  else
3102141cc406Sopenharmony_ci    {
3103141cc406Sopenharmony_ci      dev->info.canDuplex = SANE_FALSE;
3104141cc406Sopenharmony_ci    }
3105141cc406Sopenharmony_ci
3106141cc406Sopenharmony_ci  /* the paper sensor requires RSC revision 1.4 or higher and an
3107141cc406Sopenharmony_ci   * installed feeder.  NOTE: It also requires SW-4 on and the
3108141cc406Sopenharmony_ci   * AccufeedPlus feeder, but we cannot discover that.
3109141cc406Sopenharmony_ci   */
3110141cc406Sopenharmony_ci  if (strcmp(dev->info.revision, "0014") >= 0)
3111141cc406Sopenharmony_ci    {
3112141cc406Sopenharmony_ci      dev->info.canCheckADF = dev->info.canADF;
3113141cc406Sopenharmony_ci    }
3114141cc406Sopenharmony_ci  else
3115141cc406Sopenharmony_ci    {
3116141cc406Sopenharmony_ci      dev->info.canCheckADF = SANE_FALSE;
3117141cc406Sopenharmony_ci    }
3118141cc406Sopenharmony_ci
3119141cc406Sopenharmony_ci  /* set option defaults based on inquiry information */
3120141cc406Sopenharmony_ci  dev->info.res_default = dev->info.resBasicX;
3121141cc406Sopenharmony_ci  dev->info.autoborder_default = dev->info.canBorderRecog;
3122141cc406Sopenharmony_ci  dev->info.batch_default = SANE_FALSE;
3123141cc406Sopenharmony_ci  dev->info.deskew_default = SANE_FALSE;
3124141cc406Sopenharmony_ci  dev->info.check_adf_default = SANE_FALSE;
3125141cc406Sopenharmony_ci  dev->info.duplex_default = SANE_FALSE;
3126141cc406Sopenharmony_ci  dev->info.timeout_adf_default = 0;
3127141cc406Sopenharmony_ci  dev->info.timeout_manual_default = 0;
3128141cc406Sopenharmony_ci  dev->info.control_panel_default = dev->info.canACE;
3129141cc406Sopenharmony_ci
3130141cc406Sopenharmony_ci  ++num_devices;
3131141cc406Sopenharmony_ci  dev->next = first_dev;
3132141cc406Sopenharmony_ci  first_dev = dev;
3133141cc406Sopenharmony_ci
3134141cc406Sopenharmony_ci  if (devp)
3135141cc406Sopenharmony_ci    *devp = dev;
3136141cc406Sopenharmony_ci
3137141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3138141cc406Sopenharmony_ci}
3139141cc406Sopenharmony_ci
3140141cc406Sopenharmony_cistatic SANE_Status
3141141cc406Sopenharmony_ciattach_one(const char *devnam)
3142141cc406Sopenharmony_ci{
3143141cc406Sopenharmony_ci  attach (devnam, NULL);
3144141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3145141cc406Sopenharmony_ci}
3146141cc406Sopenharmony_ci
3147141cc406Sopenharmony_ciSANE_Status
3148141cc406Sopenharmony_cisane_init (SANE_Int *version_code, SANE_Auth_Callback authorize)
3149141cc406Sopenharmony_ci{
3150141cc406Sopenharmony_ci    char devnam[PATH_MAX] = "/dev/scanner";
3151141cc406Sopenharmony_ci    FILE *fp;
3152141cc406Sopenharmony_ci
3153141cc406Sopenharmony_ci    (void) authorize; /* get rid of compiler warning */
3154141cc406Sopenharmony_ci
3155141cc406Sopenharmony_ci    DBG_INIT();
3156141cc406Sopenharmony_ci    DBG(3, "sane_init called\n");
3157141cc406Sopenharmony_ci    DBG(1, "Bell+Howell SANE backend %d.%d build %d %s endian\n",
3158141cc406Sopenharmony_ci	SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD,
3159141cc406Sopenharmony_ci	_is_host_little_endian() ? "little" : "big");
3160141cc406Sopenharmony_ci
3161141cc406Sopenharmony_ci    if (version_code)
3162141cc406Sopenharmony_ci	*version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
3163141cc406Sopenharmony_ci
3164141cc406Sopenharmony_ci    fp = sanei_config_open(BH_CONFIG_FILE);
3165141cc406Sopenharmony_ci    if (fp)
3166141cc406Sopenharmony_ci	{
3167141cc406Sopenharmony_ci	    char line[PATH_MAX];
3168141cc406Sopenharmony_ci	    const char *lp;
3169141cc406Sopenharmony_ci	    size_t len;
3170141cc406Sopenharmony_ci
3171141cc406Sopenharmony_ci	    /* read config file */
3172141cc406Sopenharmony_ci	    while (sanei_config_read (line, sizeof (line), fp))
3173141cc406Sopenharmony_ci		{
3174141cc406Sopenharmony_ci		  if (line[0] == '#')           /* ignore line comments */
3175141cc406Sopenharmony_ci		    continue;
3176141cc406Sopenharmony_ci		  len = strlen (line);
3177141cc406Sopenharmony_ci
3178141cc406Sopenharmony_ci		  if (!len)
3179141cc406Sopenharmony_ci		    continue;                   /* ignore empty lines */
3180141cc406Sopenharmony_ci
3181141cc406Sopenharmony_ci		  lp = sanei_config_skip_whitespace (line);
3182141cc406Sopenharmony_ci
3183141cc406Sopenharmony_ci		  DBG(16,
3184141cc406Sopenharmony_ci		      "sane_init: processing config file line '%s'\n",
3185141cc406Sopenharmony_ci		      line);
3186141cc406Sopenharmony_ci		  if (strncmp(lp, "option", 6) == 0 &&
3187141cc406Sopenharmony_ci		      (isspace (lp[6]) || lp[6] == '\0'))
3188141cc406Sopenharmony_ci		    {
3189141cc406Sopenharmony_ci		      lp += 6;
3190141cc406Sopenharmony_ci		      lp = sanei_config_skip_whitespace (lp);
3191141cc406Sopenharmony_ci
3192141cc406Sopenharmony_ci		      if (strncmp(lp, "disable-optional-frames", 23) == 0)
3193141cc406Sopenharmony_ci			{
3194141cc406Sopenharmony_ci			  DBG(1, "sane_init: configuration option "
3195141cc406Sopenharmony_ci			      "'disable-optional-frames' set\n");
3196141cc406Sopenharmony_ci			  disable_optional_frames = 1;
3197141cc406Sopenharmony_ci			}
3198141cc406Sopenharmony_ci		      else if (strncmp(lp, "fake-inquiry", 12) == 0)
3199141cc406Sopenharmony_ci			{
3200141cc406Sopenharmony_ci			  DBG(1, "sane_init: configuration option "
3201141cc406Sopenharmony_ci			      "'fake-inquiry' set\n");
3202141cc406Sopenharmony_ci			  fake_inquiry = 1;
3203141cc406Sopenharmony_ci			}
3204141cc406Sopenharmony_ci		      else
3205141cc406Sopenharmony_ci			{
3206141cc406Sopenharmony_ci			  DBG(1, "sane_init: ignoring unknown "
3207141cc406Sopenharmony_ci			      "configuration option '%s'\n",
3208141cc406Sopenharmony_ci			      lp);
3209141cc406Sopenharmony_ci			}
3210141cc406Sopenharmony_ci		    }
3211141cc406Sopenharmony_ci		  else
3212141cc406Sopenharmony_ci		    {
3213141cc406Sopenharmony_ci		      DBG(16,
3214141cc406Sopenharmony_ci			  "sane_init: found a device: line '%s'\n",
3215141cc406Sopenharmony_ci			  lp);
3216141cc406Sopenharmony_ci		      strncpy (devnam, lp, sizeof(devnam));
3217141cc406Sopenharmony_ci		      devnam[sizeof(devnam)-1] = '\0';
3218141cc406Sopenharmony_ci
3219141cc406Sopenharmony_ci		      sanei_config_attach_matching_devices(devnam,
3220141cc406Sopenharmony_ci							   attach_one);
3221141cc406Sopenharmony_ci		    }
3222141cc406Sopenharmony_ci		}
3223141cc406Sopenharmony_ci	    fclose (fp);
3224141cc406Sopenharmony_ci	}
3225141cc406Sopenharmony_ci    else
3226141cc406Sopenharmony_ci	{
3227141cc406Sopenharmony_ci	    /* configure the /dev/scanner device in the absence of config file */
3228141cc406Sopenharmony_ci	    sanei_config_attach_matching_devices ("/dev/scanner", attach_one);
3229141cc406Sopenharmony_ci	}
3230141cc406Sopenharmony_ci
3231141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3232141cc406Sopenharmony_ci}
3233141cc406Sopenharmony_ci
3234141cc406Sopenharmony_ciSANE_Status
3235141cc406Sopenharmony_cisane_get_devices (const SANE_Device ***device_list, SANE_Bool local)
3236141cc406Sopenharmony_ci{
3237141cc406Sopenharmony_ci    BH_Device *dev;
3238141cc406Sopenharmony_ci    int i;
3239141cc406Sopenharmony_ci    DBG(3, "sane_get_devices called\n");
3240141cc406Sopenharmony_ci
3241141cc406Sopenharmony_ci    (void) local; /* get rid of compiler warning */
3242141cc406Sopenharmony_ci    if (devlist)
3243141cc406Sopenharmony_ci	free (devlist);
3244141cc406Sopenharmony_ci    devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
3245141cc406Sopenharmony_ci    if (!devlist)
3246141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
3247141cc406Sopenharmony_ci
3248141cc406Sopenharmony_ci    i = 0;
3249141cc406Sopenharmony_ci    for (dev = first_dev; dev; dev = dev->next)
3250141cc406Sopenharmony_ci	devlist[i++] = &dev->sane;
3251141cc406Sopenharmony_ci    devlist[i++] = 0;
3252141cc406Sopenharmony_ci
3253141cc406Sopenharmony_ci    *device_list = devlist;
3254141cc406Sopenharmony_ci
3255141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3256141cc406Sopenharmony_ci}
3257141cc406Sopenharmony_ci
3258141cc406Sopenharmony_ciSANE_Status
3259141cc406Sopenharmony_cisane_open (SANE_String_Const devnam, SANE_Handle *handle)
3260141cc406Sopenharmony_ci{
3261141cc406Sopenharmony_ci    SANE_Status status;
3262141cc406Sopenharmony_ci    BH_Device *dev;
3263141cc406Sopenharmony_ci    BH_Scanner *s;
3264141cc406Sopenharmony_ci    DBG(3, "sane_open called\n");
3265141cc406Sopenharmony_ci
3266141cc406Sopenharmony_ci    if (devnam[0] != '\0')
3267141cc406Sopenharmony_ci	{
3268141cc406Sopenharmony_ci	    for (dev = first_dev; dev; dev = dev->next)
3269141cc406Sopenharmony_ci		{
3270141cc406Sopenharmony_ci		    if (strcmp (dev->sane.name, devnam) == 0)
3271141cc406Sopenharmony_ci		      break;
3272141cc406Sopenharmony_ci		}
3273141cc406Sopenharmony_ci
3274141cc406Sopenharmony_ci	    if (!dev)
3275141cc406Sopenharmony_ci		{
3276141cc406Sopenharmony_ci		    status = attach (devnam, &dev);
3277141cc406Sopenharmony_ci		    if (status != SANE_STATUS_GOOD)
3278141cc406Sopenharmony_ci			return status;
3279141cc406Sopenharmony_ci		}
3280141cc406Sopenharmony_ci	}
3281141cc406Sopenharmony_ci    else
3282141cc406Sopenharmony_ci	{
3283141cc406Sopenharmony_ci	    dev = first_dev;
3284141cc406Sopenharmony_ci	}
3285141cc406Sopenharmony_ci
3286141cc406Sopenharmony_ci    if (!dev)
3287141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
3288141cc406Sopenharmony_ci
3289141cc406Sopenharmony_ci    s = malloc (sizeof (*s));
3290141cc406Sopenharmony_ci    if (!s)
3291141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
3292141cc406Sopenharmony_ci    memset (s, 0, sizeof (*s));
3293141cc406Sopenharmony_ci
3294141cc406Sopenharmony_ci    s->fd = -1;
3295141cc406Sopenharmony_ci    s->hw = dev;
3296141cc406Sopenharmony_ci
3297141cc406Sopenharmony_ci    s->bmu = BH_UNIT_POINT;
3298141cc406Sopenharmony_ci    s->mud = 1;
3299141cc406Sopenharmony_ci
3300141cc406Sopenharmony_ci    ScannerDump(s);
3301141cc406Sopenharmony_ci
3302141cc406Sopenharmony_ci    init_options (s);
3303141cc406Sopenharmony_ci
3304141cc406Sopenharmony_ci    s->next = first_handle;
3305141cc406Sopenharmony_ci    first_handle = s;
3306141cc406Sopenharmony_ci
3307141cc406Sopenharmony_ci    /* initialize our parameters */
3308141cc406Sopenharmony_ci    get_parameters(s, 0);
3309141cc406Sopenharmony_ci
3310141cc406Sopenharmony_ci    *handle = s;
3311141cc406Sopenharmony_ci
3312141cc406Sopenharmony_ci#ifdef FAKE_INQUIRY
3313141cc406Sopenharmony_ci    if (fake_inquiry)
3314141cc406Sopenharmony_ci      {
3315141cc406Sopenharmony_ci	DBG (1, "sane_open: faking open of %s\n",
3316141cc406Sopenharmony_ci	     s->hw->sane.name);
3317141cc406Sopenharmony_ci      }
3318141cc406Sopenharmony_ci    else
3319141cc406Sopenharmony_ci#endif
3320141cc406Sopenharmony_ci      {
3321141cc406Sopenharmony_ci	status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s);
3322141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
3323141cc406Sopenharmony_ci	  {
3324141cc406Sopenharmony_ci	    DBG (1, "sane_open: open of %s failed: %s\n",
3325141cc406Sopenharmony_ci		 s->hw->sane.name, sane_strstatus (status));
3326141cc406Sopenharmony_ci	    return status;
3327141cc406Sopenharmony_ci	  }
3328141cc406Sopenharmony_ci      }
3329141cc406Sopenharmony_ci
3330141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3331141cc406Sopenharmony_ci}
3332141cc406Sopenharmony_ci
3333141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3334141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
3335141cc406Sopenharmony_ci{
3336141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3337141cc406Sopenharmony_ci  DBG(3, "sane_get_option_descriptor called (option:%d)\n", option);
3338141cc406Sopenharmony_ci
3339141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
3340141cc406Sopenharmony_ci      return 0;
3341141cc406Sopenharmony_ci
3342141cc406Sopenharmony_ci  return (s->opt + option);
3343141cc406Sopenharmony_ci}
3344141cc406Sopenharmony_ci
3345141cc406Sopenharmony_ciSANE_Status
3346141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
3347141cc406Sopenharmony_ci		     void *val, SANE_Word *info)
3348141cc406Sopenharmony_ci{
3349141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3350141cc406Sopenharmony_ci  SANE_Status status;
3351141cc406Sopenharmony_ci  SANE_Word cap;
3352141cc406Sopenharmony_ci  SANE_String_Const name;
3353141cc406Sopenharmony_ci
3354141cc406Sopenharmony_ci  DBG(3, "sane_control_option called\n");
3355141cc406Sopenharmony_ci
3356141cc406Sopenharmony_ci  name = s->opt[option].name ? s->opt[option].name : "(nil)";
3357141cc406Sopenharmony_ci
3358141cc406Sopenharmony_ci  if (info)
3359141cc406Sopenharmony_ci    *info = 0;
3360141cc406Sopenharmony_ci
3361141cc406Sopenharmony_ci  if (s->scanning && action == SANE_ACTION_SET_VALUE)
3362141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
3363141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
3364141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3365141cc406Sopenharmony_ci
3366141cc406Sopenharmony_ci  cap = s->opt[option].cap;
3367141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
3368141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3369141cc406Sopenharmony_ci
3370141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
3371141cc406Sopenharmony_ci    {
3372141cc406Sopenharmony_ci      DBG(16, "sane_control_option: get_value %s [#%d]\n", name, option);
3373141cc406Sopenharmony_ci      switch (option)
3374141cc406Sopenharmony_ci	{
3375141cc406Sopenharmony_ci	  /* word options: */
3376141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3377141cc406Sopenharmony_ci	case OPT_TL_X:
3378141cc406Sopenharmony_ci	case OPT_TL_Y:
3379141cc406Sopenharmony_ci	case OPT_BR_X:
3380141cc406Sopenharmony_ci	case OPT_BR_Y:
3381141cc406Sopenharmony_ci	case OPT_TIMEOUT_ADF:
3382141cc406Sopenharmony_ci	case OPT_TIMEOUT_MANUAL:
3383141cc406Sopenharmony_ci	case OPT_ACE_FUNCTION:
3384141cc406Sopenharmony_ci	case OPT_ACE_SENSITIVITY:
3385141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
3386141cc406Sopenharmony_ci	case OPT_THRESHOLD:
3387141cc406Sopenharmony_ci	case OPT_CONTRAST:
3388141cc406Sopenharmony_ci	case OPT_ICON_WIDTH:
3389141cc406Sopenharmony_ci	case OPT_ICON_LENGTH:
3390141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_COUNT:
3391141cc406Sopenharmony_ci	case OPT_BARCODE_HMIN:
3392141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_TIMEOUT:
3393141cc406Sopenharmony_ci	case OPT_BARCODE_RELMAX:
3394141cc406Sopenharmony_ci	case OPT_BARCODE_BARMIN:
3395141cc406Sopenharmony_ci	case OPT_BARCODE_BARMAX:
3396141cc406Sopenharmony_ci	case OPT_BARCODE_CONTRAST:
3397141cc406Sopenharmony_ci	case OPT_BARCODE_PATCHMODE:
3398141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3399141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
3400141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3401141cc406Sopenharmony_ci
3402141cc406Sopenharmony_ci	  /* string options: */
3403141cc406Sopenharmony_ci	case OPT_INQUIRY:
3404141cc406Sopenharmony_ci	case OPT_SCAN_SOURCE:
3405141cc406Sopenharmony_ci	case OPT_SCAN_MODE:
3406141cc406Sopenharmony_ci	case OPT_COMPRESSION:
3407141cc406Sopenharmony_ci	case OPT_PAPER_SIZE:
3408141cc406Sopenharmony_ci	case OPT_ROTATION:
3409141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_BAR:
3410141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_MODE:
3411141cc406Sopenharmony_ci	case OPT_SECTION:
3412141cc406Sopenharmony_ci	  strcpy (val, s->val[option].s);
3413141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3414141cc406Sopenharmony_ci
3415141cc406Sopenharmony_ci	  /* boolean options: */
3416141cc406Sopenharmony_ci	case OPT_PREVIEW:
3417141cc406Sopenharmony_ci	case OPT_AUTOBORDER:
3418141cc406Sopenharmony_ci	case OPT_DESKEW:
3419141cc406Sopenharmony_ci	case OPT_BATCH:
3420141cc406Sopenharmony_ci	case OPT_CHECK_ADF:
3421141cc406Sopenharmony_ci	case OPT_DUPLEX:
3422141cc406Sopenharmony_ci	case OPT_CONTROL_PANEL:
3423141cc406Sopenharmony_ci	case OPT_NEGATIVE:
3424141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
3425141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3426141cc406Sopenharmony_ci
3427141cc406Sopenharmony_ci	default:
3428141cc406Sopenharmony_ci	  DBG(1, "sane_control_option:invalid option number %d\n", option);
3429141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3430141cc406Sopenharmony_ci	}
3431141cc406Sopenharmony_ci    }
3432141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
3433141cc406Sopenharmony_ci    {
3434141cc406Sopenharmony_ci      switch (s->opt[option].type)
3435141cc406Sopenharmony_ci	{
3436141cc406Sopenharmony_ci	case SANE_TYPE_BOOL:
3437141cc406Sopenharmony_ci	case SANE_TYPE_INT:
3438141cc406Sopenharmony_ci	  DBG(16, "sane_control_option: set_value %s [#%d] to %d\n",
3439141cc406Sopenharmony_ci	      name, option, *(SANE_Word *) val);
3440141cc406Sopenharmony_ci	  break;
3441141cc406Sopenharmony_ci
3442141cc406Sopenharmony_ci	case SANE_TYPE_FIXED:
3443141cc406Sopenharmony_ci	  DBG(16, "sane_control_option: set_value %s [#%d] to %f\n",
3444141cc406Sopenharmony_ci	      name, option, SANE_UNFIX(*(SANE_Word *) val));
3445141cc406Sopenharmony_ci	  break;
3446141cc406Sopenharmony_ci
3447141cc406Sopenharmony_ci	case SANE_TYPE_STRING:
3448141cc406Sopenharmony_ci	  DBG(16, "sane_control_option: set_value %s [#%d] to %s\n",
3449141cc406Sopenharmony_ci	      name, option, (char *) val);
3450141cc406Sopenharmony_ci	  break;
3451141cc406Sopenharmony_ci
3452141cc406Sopenharmony_ci	default:
3453141cc406Sopenharmony_ci	  DBG(16, "sane_control_option: set_value %s [#%d]\n",
3454141cc406Sopenharmony_ci	      name, option);
3455141cc406Sopenharmony_ci	}
3456141cc406Sopenharmony_ci
3457141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
3458141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
3459141cc406Sopenharmony_ci
3460141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, info);
3461141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3462141cc406Sopenharmony_ci	return status;
3463141cc406Sopenharmony_ci
3464141cc406Sopenharmony_ci      switch (option)
3465141cc406Sopenharmony_ci	{
3466141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
3467141cc406Sopenharmony_ci	case OPT_TL_X:
3468141cc406Sopenharmony_ci	case OPT_TL_Y:
3469141cc406Sopenharmony_ci	case OPT_BR_X:
3470141cc406Sopenharmony_ci	case OPT_BR_Y:
3471141cc406Sopenharmony_ci	  /* make sure that paper-size is set to custom */
3472141cc406Sopenharmony_ci	  if (s->val[option].w != *(SANE_Word *) val)
3473141cc406Sopenharmony_ci	    {
3474141cc406Sopenharmony_ci	      if (info) *info |= SANE_INFO_RELOAD_PARAMS;
3475141cc406Sopenharmony_ci
3476141cc406Sopenharmony_ci	      if (get_paper_id(_OPT_VAL_STRING(s, OPT_PAPER_SIZE)) != 0)
3477141cc406Sopenharmony_ci		{
3478141cc406Sopenharmony_ci		  if (info) *info |= SANE_INFO_RELOAD_OPTIONS;
3479141cc406Sopenharmony_ci
3480141cc406Sopenharmony_ci		  /* set paper size to 'custom' */
3481141cc406Sopenharmony_ci		  free (s->val[OPT_PAPER_SIZE].s);
3482141cc406Sopenharmony_ci		  s->val[OPT_PAPER_SIZE].s = strdup(paper_list[0]);
3483141cc406Sopenharmony_ci		}
3484141cc406Sopenharmony_ci	    }
3485141cc406Sopenharmony_ci	  /* fall through */
3486141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3487141cc406Sopenharmony_ci	  if (info && s->val[option].w != *(SANE_Word *) val)
3488141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3489141cc406Sopenharmony_ci	  /* fall through */
3490141cc406Sopenharmony_ci	case OPT_TIMEOUT_ADF:
3491141cc406Sopenharmony_ci	case OPT_TIMEOUT_MANUAL:
3492141cc406Sopenharmony_ci	case OPT_ACE_FUNCTION:
3493141cc406Sopenharmony_ci	case OPT_ACE_SENSITIVITY:
3494141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
3495141cc406Sopenharmony_ci	case OPT_THRESHOLD:
3496141cc406Sopenharmony_ci	case OPT_CONTRAST:
3497141cc406Sopenharmony_ci	case OPT_ICON_WIDTH:
3498141cc406Sopenharmony_ci	case OPT_ICON_LENGTH:
3499141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_COUNT:
3500141cc406Sopenharmony_ci	case OPT_BARCODE_HMIN:
3501141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_TIMEOUT:
3502141cc406Sopenharmony_ci	case OPT_BARCODE_RELMAX:
3503141cc406Sopenharmony_ci	case OPT_BARCODE_BARMIN:
3504141cc406Sopenharmony_ci	case OPT_BARCODE_BARMAX:
3505141cc406Sopenharmony_ci	case OPT_BARCODE_CONTRAST:
3506141cc406Sopenharmony_ci	case OPT_BARCODE_PATCHMODE:
3507141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3508141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
3509141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3510141cc406Sopenharmony_ci
3511141cc406Sopenharmony_ci	  /* string options */
3512141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_BAR:
3513141cc406Sopenharmony_ci	  /*!!! we're supporting only a single barcode type via the option */
3514141cc406Sopenharmony_ci	  s->search_bars[0] = get_barcode_id(val);
3515141cc406Sopenharmony_ci	  /* fall through */
3516141cc406Sopenharmony_ci	case OPT_SCAN_SOURCE:
3517141cc406Sopenharmony_ci	case OPT_COMPRESSION:
3518141cc406Sopenharmony_ci	case OPT_ROTATION:
3519141cc406Sopenharmony_ci	case OPT_BARCODE_SEARCH_MODE:
3520141cc406Sopenharmony_ci	case OPT_SECTION:
3521141cc406Sopenharmony_ci	  if (s->val[option].s)
3522141cc406Sopenharmony_ci	    free (s->val[option].s);
3523141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
3524141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3525141cc406Sopenharmony_ci
3526141cc406Sopenharmony_ci	  /* boolean options: */
3527141cc406Sopenharmony_ci	case OPT_AUTOBORDER:
3528141cc406Sopenharmony_ci	  /*!!! autoborder true disables geometry controls
3529141cc406Sopenharmony_ci	   * and sets them to defaults?
3530141cc406Sopenharmony_ci	   */
3531141cc406Sopenharmony_ci	  /* fall through */
3532141cc406Sopenharmony_ci	case OPT_PREVIEW:
3533141cc406Sopenharmony_ci	case OPT_BATCH:
3534141cc406Sopenharmony_ci	case OPT_DESKEW:
3535141cc406Sopenharmony_ci	case OPT_CHECK_ADF:
3536141cc406Sopenharmony_ci	case OPT_DUPLEX:
3537141cc406Sopenharmony_ci	case OPT_NEGATIVE:
3538141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
3539141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3540141cc406Sopenharmony_ci
3541141cc406Sopenharmony_ci	  /* options with side effects */
3542141cc406Sopenharmony_ci	case OPT_CONTROL_PANEL:
3543141cc406Sopenharmony_ci	  /* a boolean option */
3544141cc406Sopenharmony_ci	  /* control-panel true enables/disables some enhancement controls */
3545141cc406Sopenharmony_ci	  if (s->val[option].w != *(SANE_Word *) val)
3546141cc406Sopenharmony_ci	    {
3547141cc406Sopenharmony_ci	      if (info) *info |= SANE_INFO_RELOAD_OPTIONS;
3548141cc406Sopenharmony_ci
3549141cc406Sopenharmony_ci	      s->val[option].w = *(SANE_Word *) val;
3550141cc406Sopenharmony_ci
3551141cc406Sopenharmony_ci	      if (*(SANE_Word *) val == SANE_TRUE)
3552141cc406Sopenharmony_ci		{
3553141cc406Sopenharmony_ci		  if (s->hw->info.canACE == SANE_TRUE)
3554141cc406Sopenharmony_ci		    {
3555141cc406Sopenharmony_ci		      s->opt[OPT_ACE_FUNCTION].cap |= SANE_CAP_INACTIVE;
3556141cc406Sopenharmony_ci		      s->opt[OPT_ACE_SENSITIVITY].cap |= SANE_CAP_INACTIVE;
3557141cc406Sopenharmony_ci		    }
3558141cc406Sopenharmony_ci		  else
3559141cc406Sopenharmony_ci		    {
3560141cc406Sopenharmony_ci		      s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
3561141cc406Sopenharmony_ci		      s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
3562141cc406Sopenharmony_ci		    }
3563141cc406Sopenharmony_ci		}
3564141cc406Sopenharmony_ci	      else
3565141cc406Sopenharmony_ci		{
3566141cc406Sopenharmony_ci		  if (s->hw->info.canACE == SANE_TRUE)
3567141cc406Sopenharmony_ci		    {
3568141cc406Sopenharmony_ci		      s->opt[OPT_ACE_FUNCTION].cap &= ~SANE_CAP_INACTIVE;
3569141cc406Sopenharmony_ci		      s->opt[OPT_ACE_SENSITIVITY].cap &= ~SANE_CAP_INACTIVE;
3570141cc406Sopenharmony_ci		    }
3571141cc406Sopenharmony_ci		  else
3572141cc406Sopenharmony_ci		    {
3573141cc406Sopenharmony_ci		      s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
3574141cc406Sopenharmony_ci		      s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
3575141cc406Sopenharmony_ci		    }
3576141cc406Sopenharmony_ci		}
3577141cc406Sopenharmony_ci	    }
3578141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3579141cc406Sopenharmony_ci
3580141cc406Sopenharmony_ci	case OPT_SCAN_MODE:
3581141cc406Sopenharmony_ci	  /* a string option */
3582141cc406Sopenharmony_ci	  /* scan mode != lineart disables compression, setting it to
3583141cc406Sopenharmony_ci	   * 'none'
3584141cc406Sopenharmony_ci	   */
3585141cc406Sopenharmony_ci	  if (strcmp (s->val[option].s, (SANE_String) val))
3586141cc406Sopenharmony_ci	    {
3587141cc406Sopenharmony_ci	      if (info) *info |= SANE_INFO_RELOAD_OPTIONS;
3588141cc406Sopenharmony_ci	      if (get_scan_mode_id((SANE_String) val) != 0)
3589141cc406Sopenharmony_ci		{
3590141cc406Sopenharmony_ci		  /* scan mode is not lineart, disable compression
3591141cc406Sopenharmony_ci		   * and set compression to 'none'
3592141cc406Sopenharmony_ci		   */
3593141cc406Sopenharmony_ci		  s->opt[OPT_COMPRESSION].cap |= SANE_CAP_INACTIVE;
3594141cc406Sopenharmony_ci		  if (s->val[OPT_COMPRESSION].s &&
3595141cc406Sopenharmony_ci		      get_compression_id(s->val[OPT_COMPRESSION].s) != 0)
3596141cc406Sopenharmony_ci		    {
3597141cc406Sopenharmony_ci		      free (s->val[OPT_COMPRESSION].s);
3598141cc406Sopenharmony_ci		      s->val[OPT_COMPRESSION].s = strdup(compression_list[0]);
3599141cc406Sopenharmony_ci		    }
3600141cc406Sopenharmony_ci		}
3601141cc406Sopenharmony_ci	      else
3602141cc406Sopenharmony_ci		{
3603141cc406Sopenharmony_ci		  /* scan mode is lineart, enable compression */
3604141cc406Sopenharmony_ci		  s->opt[OPT_COMPRESSION].cap &= ~SANE_CAP_INACTIVE;
3605141cc406Sopenharmony_ci		}
3606141cc406Sopenharmony_ci	      free (s->val[option].s);
3607141cc406Sopenharmony_ci	      s->val[option].s = strdup (val);
3608141cc406Sopenharmony_ci	    }
3609141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3610141cc406Sopenharmony_ci
3611141cc406Sopenharmony_ci	case OPT_PAPER_SIZE:
3612141cc406Sopenharmony_ci	  /* a string option */
3613141cc406Sopenharmony_ci	  /* changes geometry options, therefore _RELOAD_PARAMS and _RELOAD_OPTIONS */
3614141cc406Sopenharmony_ci	  if (strcmp (s->val[option].s, (SANE_String) val))
3615141cc406Sopenharmony_ci	    {
3616141cc406Sopenharmony_ci	      SANE_Int paper_id = get_paper_id((SANE_String) val);
3617141cc406Sopenharmony_ci
3618141cc406Sopenharmony_ci	      /* paper_id 0 is a special case (custom) that
3619141cc406Sopenharmony_ci	       * disables the paper size control of geometry
3620141cc406Sopenharmony_ci	       */
3621141cc406Sopenharmony_ci	      if (paper_id != 0)
3622141cc406Sopenharmony_ci		{
3623141cc406Sopenharmony_ci		  double left, x_max, y_max, x, y;
3624141cc406Sopenharmony_ci
3625141cc406Sopenharmony_ci		  x_max = SANE_UNFIX(s->hw->info.x_range.max);
3626141cc406Sopenharmony_ci		  y_max = SANE_UNFIX(s->hw->info.y_range.max);
3627141cc406Sopenharmony_ci		  /* a dimension of 0.0 (or less) is replaced with the max value */
3628141cc406Sopenharmony_ci		  x = (paper_sizes[paper_id].width <= 0.0) ? x_max :
3629141cc406Sopenharmony_ci		    paper_sizes[paper_id].width;
3630141cc406Sopenharmony_ci		  y = (paper_sizes[paper_id].length <= 0.0) ? y_max :
3631141cc406Sopenharmony_ci		    paper_sizes[paper_id].length;
3632141cc406Sopenharmony_ci
3633141cc406Sopenharmony_ci		  if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
3634141cc406Sopenharmony_ci
3635141cc406Sopenharmony_ci		  /* set geometry options based on paper size */
3636141cc406Sopenharmony_ci		  /* set geometry options based on paper size */
3637141cc406Sopenharmony_ci		  if (s->hw->info.canADF)
3638141cc406Sopenharmony_ci		    {
3639141cc406Sopenharmony_ci		      /* when the feeder is used the paper is centered in the
3640141cc406Sopenharmony_ci		       * hopper; with the manual feed it is aligned left.
3641141cc406Sopenharmony_ci		       */
3642141cc406Sopenharmony_ci		      left = (x_max - x) / 2.0;
3643141cc406Sopenharmony_ci		      if (left < 0.0) left = 0.0;
3644141cc406Sopenharmony_ci		    }
3645141cc406Sopenharmony_ci		  else
3646141cc406Sopenharmony_ci		    {
3647141cc406Sopenharmony_ci		      left = 0.0;
3648141cc406Sopenharmony_ci		    }
3649141cc406Sopenharmony_ci
3650141cc406Sopenharmony_ci		  s->val[OPT_TL_X].w = SANE_FIX(left);
3651141cc406Sopenharmony_ci		  s->val[OPT_TL_Y].w = SANE_FIX(0.0);
3652141cc406Sopenharmony_ci		  s->val[OPT_BR_X].w = SANE_FIX(MIN(x + left, x_max));
3653141cc406Sopenharmony_ci		  s->val[OPT_BR_Y].w = SANE_FIX(MIN(y, y_max));
3654141cc406Sopenharmony_ci		}
3655141cc406Sopenharmony_ci	      free (s->val[option].s);
3656141cc406Sopenharmony_ci	      s->val[option].s = strdup (val);
3657141cc406Sopenharmony_ci	    }
3658141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3659141cc406Sopenharmony_ci
3660141cc406Sopenharmony_ci	default:
3661141cc406Sopenharmony_ci	  DBG(1, "sane_control_option:invalid option number %d\n", option);
3662141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3663141cc406Sopenharmony_ci	}
3664141cc406Sopenharmony_ci    }
3665141cc406Sopenharmony_ci
3666141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
3667141cc406Sopenharmony_ci}
3668141cc406Sopenharmony_ci
3669141cc406Sopenharmony_ciSANE_Status
3670141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
3671141cc406Sopenharmony_ci{
3672141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3673141cc406Sopenharmony_ci  SANE_Int status = SANE_STATUS_GOOD;
3674141cc406Sopenharmony_ci
3675141cc406Sopenharmony_ci  DBG(3, "sane_get_parameters called\n");
3676141cc406Sopenharmony_ci
3677141cc406Sopenharmony_ci  if (params)
3678141cc406Sopenharmony_ci    {
3679141cc406Sopenharmony_ci      SANE_Int res;
3680141cc406Sopenharmony_ci
3681141cc406Sopenharmony_ci      if (!s->scanning)
3682141cc406Sopenharmony_ci	{
3683141cc406Sopenharmony_ci	  /* update our parameters ONLY if we're not scanning */
3684141cc406Sopenharmony_ci	  status = get_parameters(s, 0);
3685141cc406Sopenharmony_ci	}
3686141cc406Sopenharmony_ci
3687141cc406Sopenharmony_ci      *params = s->params;
3688141cc406Sopenharmony_ci
3689141cc406Sopenharmony_ci      res = _OPT_VAL_WORD(s, OPT_RESOLUTION);
3690141cc406Sopenharmony_ci
3691141cc406Sopenharmony_ci      DBG (1, "get_parameters: format=%d, pixels/line=%d, bytes/line=%d, "
3692141cc406Sopenharmony_ci	   "lines=%d, dpi=%d\n",
3693141cc406Sopenharmony_ci	   (int) s->params.format,
3694141cc406Sopenharmony_ci	   s->params.pixels_per_line,
3695141cc406Sopenharmony_ci	   s->params.bytes_per_line,
3696141cc406Sopenharmony_ci	   s->params.lines,
3697141cc406Sopenharmony_ci	   res);
3698141cc406Sopenharmony_ci    }
3699141cc406Sopenharmony_ci
3700141cc406Sopenharmony_ci  return status;
3701141cc406Sopenharmony_ci}
3702141cc406Sopenharmony_ci
3703141cc406Sopenharmony_ciSANE_Status
3704141cc406Sopenharmony_cisane_start (SANE_Handle handle)
3705141cc406Sopenharmony_ci{
3706141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3707141cc406Sopenharmony_ci  SANE_Status status;
3708141cc406Sopenharmony_ci
3709141cc406Sopenharmony_ci  DBG(3, "sane_start called\n");
3710141cc406Sopenharmony_ci  s->cancelled = SANE_FALSE;
3711141cc406Sopenharmony_ci
3712141cc406Sopenharmony_ci  if (s->scanning == SANE_FALSE)
3713141cc406Sopenharmony_ci    {
3714141cc406Sopenharmony_ci      /* get preliminary parameters */
3715141cc406Sopenharmony_ci      status = get_parameters (s, 0);
3716141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3717141cc406Sopenharmony_ci	{
3718141cc406Sopenharmony_ci	  DBG (1, "sane_start: get_parameters failed: %s\n",
3719141cc406Sopenharmony_ci	       sane_strstatus (status));
3720141cc406Sopenharmony_ci	  return status;
3721141cc406Sopenharmony_ci	}
3722141cc406Sopenharmony_ci
3723141cc406Sopenharmony_ci      /* Do the setup once per 'batch'.  The SANE standard requires the
3724141cc406Sopenharmony_ci       * frontend to call sane_cancel once all desired frames have been
3725141cc406Sopenharmony_ci       * acquired.  That is when scanning is set back to SANE_FALSE and
3726141cc406Sopenharmony_ci       * the 'batch' is considered done.
3727141cc406Sopenharmony_ci       */
3728141cc406Sopenharmony_ci      status = start_setup (s);
3729141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3730141cc406Sopenharmony_ci	{
3731141cc406Sopenharmony_ci	  DBG (1, "sane_start: start_setup failed: %s\n",
3732141cc406Sopenharmony_ci	       sane_strstatus (status));
3733141cc406Sopenharmony_ci	  return status;
3734141cc406Sopenharmony_ci	}
3735141cc406Sopenharmony_ci    }
3736141cc406Sopenharmony_ci
3737141cc406Sopenharmony_ci  status = start_scan (s);
3738141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3739141cc406Sopenharmony_ci    {
3740141cc406Sopenharmony_ci      DBG (1, "sane_start: start_scan failed: %s\n",
3741141cc406Sopenharmony_ci	   sane_strstatus (status));
3742141cc406Sopenharmony_ci      return status;
3743141cc406Sopenharmony_ci    }
3744141cc406Sopenharmony_ci
3745141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3746141cc406Sopenharmony_ci}
3747141cc406Sopenharmony_ci
3748141cc406Sopenharmony_ciSANE_Status
3749141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
3750141cc406Sopenharmony_ci{
3751141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3752141cc406Sopenharmony_ci  SANE_Status status;
3753141cc406Sopenharmony_ci  size_t nread;
3754141cc406Sopenharmony_ci
3755141cc406Sopenharmony_ci  DBG(3, "sane_read called\n");
3756141cc406Sopenharmony_ci
3757141cc406Sopenharmony_ci  *len = 0;
3758141cc406Sopenharmony_ci
3759141cc406Sopenharmony_ci  if (s->cancelled) {
3760141cc406Sopenharmony_ci    DBG (3, "sane_read: cancelled!\n");
3761141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
3762141cc406Sopenharmony_ci  }
3763141cc406Sopenharmony_ci
3764141cc406Sopenharmony_ci  if (!s->scanning) {
3765141cc406Sopenharmony_ci    DBG (3, "sane_read: scanning is false!\n");
3766141cc406Sopenharmony_ci    sane_cancel(s);
3767141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
3768141cc406Sopenharmony_ci  }
3769141cc406Sopenharmony_ci
3770141cc406Sopenharmony_ci  nread = maxlen;
3771141cc406Sopenharmony_ci
3772141cc406Sopenharmony_ci  DBG (3, "sane_read: request %lu bytes\n", (u_long) nread);
3773141cc406Sopenharmony_ci  /* set InvalidBytes to 0 before read; sense_handler will set it
3774141cc406Sopenharmony_ci   * to non-zero if we do the last partial read.
3775141cc406Sopenharmony_ci   */
3776141cc406Sopenharmony_ci  s->InvalidBytes = 0;
3777141cc406Sopenharmony_ci  status = read_data (s, buf, &nread);
3778141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3779141cc406Sopenharmony_ci    {
3780141cc406Sopenharmony_ci      DBG (1, "sane_read: read_data failed %s\n",
3781141cc406Sopenharmony_ci	   sane_strstatus(status));
3782141cc406Sopenharmony_ci      sane_cancel (s);
3783141cc406Sopenharmony_ci      return status;
3784141cc406Sopenharmony_ci    }
3785141cc406Sopenharmony_ci  nread = maxlen - s->InvalidBytes;
3786141cc406Sopenharmony_ci  DBG (3, "sane_read: got %lu bytes\n", (u_long) nread);
3787141cc406Sopenharmony_ci  *len = nread;
3788141cc406Sopenharmony_ci
3789141cc406Sopenharmony_ci  return (maxlen != 0 && nread == 0) ? SANE_STATUS_EOF : SANE_STATUS_GOOD;
3790141cc406Sopenharmony_ci}
3791141cc406Sopenharmony_ci
3792141cc406Sopenharmony_ciSANE_Status
3793141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
3794141cc406Sopenharmony_ci{
3795141cc406Sopenharmony_ci#ifdef NONBLOCKSUPPORTED
3796141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3797141cc406Sopenharmony_ci#endif
3798141cc406Sopenharmony_ci  DBG(3, "sane_set_io_mode called: non_blocking=%d\n", non_blocking);
3799141cc406Sopenharmony_ci
3800141cc406Sopenharmony_ci#ifdef NONBLOCKSUPPORTED
3801141cc406Sopenharmony_ci  if (s->fd < 0)
3802141cc406Sopenharmony_ci    {
3803141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3804141cc406Sopenharmony_ci    }
3805141cc406Sopenharmony_ci
3806141cc406Sopenharmony_ci  if (fcntl (s->fd, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
3807141cc406Sopenharmony_ci    {
3808141cc406Sopenharmony_ci      DBG(1, "sane_set_io_mode: error setting io mode\n");
3809141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
3810141cc406Sopenharmony_ci    }
3811141cc406Sopenharmony_ci
3812141cc406Sopenharmony_ci return SANE_STATUS_GOOD;
3813141cc406Sopenharmony_ci#else
3814141cc406Sopenharmony_ci (void) handle; /* get rid of compiler warning */
3815141cc406Sopenharmony_ci return (non_blocking == 1) ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD;
3816141cc406Sopenharmony_ci#endif
3817141cc406Sopenharmony_ci}
3818141cc406Sopenharmony_ci
3819141cc406Sopenharmony_ciSANE_Status
3820141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
3821141cc406Sopenharmony_ci{
3822141cc406Sopenharmony_ci#ifdef NONBLOCKSUPPORTED
3823141cc406Sopenharmony_ci  BH_Scanner *s = handle;
3824141cc406Sopenharmony_ci#endif
3825141cc406Sopenharmony_ci  DBG(3, "sane_get_select_fd called\n");
3826141cc406Sopenharmony_ci
3827141cc406Sopenharmony_ci#ifdef NONBLOCKSUPPORTED
3828141cc406Sopenharmony_ci  if (s->fd < 0)
3829141cc406Sopenharmony_ci    {
3830141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3831141cc406Sopenharmony_ci    }
3832141cc406Sopenharmony_ci  *fd = s->fd;
3833141cc406Sopenharmony_ci
3834141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3835141cc406Sopenharmony_ci#else
3836141cc406Sopenharmony_ci  (void) handle; (void) fd; /* get rid of compiler warning */
3837141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
3838141cc406Sopenharmony_ci#endif
3839141cc406Sopenharmony_ci}
3840141cc406Sopenharmony_ci
3841141cc406Sopenharmony_civoid
3842141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
3843141cc406Sopenharmony_ci{
3844141cc406Sopenharmony_ci  BH_Scanner *s = (BH_Scanner *) handle;
3845141cc406Sopenharmony_ci  DBG(3, "sane_cancel called\n");
3846141cc406Sopenharmony_ci  if (s->scanning)
3847141cc406Sopenharmony_ci    {
3848141cc406Sopenharmony_ci      /* if batchmode is enabled, then call set_window to
3849141cc406Sopenharmony_ci       * abort the batch
3850141cc406Sopenharmony_ci       */
3851141cc406Sopenharmony_ci      if (_OPT_VAL_WORD(s, OPT_BATCH) == SANE_TRUE)
3852141cc406Sopenharmony_ci	{
3853141cc406Sopenharmony_ci	  DBG(5, "sane_cancel: calling set_window to abort batch\n");
3854141cc406Sopenharmony_ci	  set_window(s, BH_BATCH_ABORT);
3855141cc406Sopenharmony_ci	}
3856141cc406Sopenharmony_ci    }
3857141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
3858141cc406Sopenharmony_ci  s->cancelled = SANE_TRUE;
3859141cc406Sopenharmony_ci}
3860141cc406Sopenharmony_ci
3861141cc406Sopenharmony_civoid
3862141cc406Sopenharmony_cisane_close (SANE_Handle handle)
3863141cc406Sopenharmony_ci{
3864141cc406Sopenharmony_ci  BH_Scanner *s = (BH_Scanner *) handle;
3865141cc406Sopenharmony_ci  DBG(3, "sane_close called\n");
3866141cc406Sopenharmony_ci
3867141cc406Sopenharmony_ci  if (s->fd != -1)
3868141cc406Sopenharmony_ci    sanei_scsi_close (s->fd);
3869141cc406Sopenharmony_ci  s->fd = -1;
3870141cc406Sopenharmony_ci  free (s);
3871141cc406Sopenharmony_ci}
3872141cc406Sopenharmony_ci
3873141cc406Sopenharmony_civoid
3874141cc406Sopenharmony_cisane_exit (void)
3875141cc406Sopenharmony_ci{
3876141cc406Sopenharmony_ci  BH_Device *dev, *next;
3877141cc406Sopenharmony_ci  DBG(3, "sane_exit called\n");
3878141cc406Sopenharmony_ci
3879141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
3880141cc406Sopenharmony_ci    {
3881141cc406Sopenharmony_ci      next = dev->next;
3882141cc406Sopenharmony_ci      free (dev);
3883141cc406Sopenharmony_ci    }
3884141cc406Sopenharmony_ci
3885141cc406Sopenharmony_ci  if (devlist)
3886141cc406Sopenharmony_ci    free (devlist);
3887141cc406Sopenharmony_ci}
3888