1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   BACKEND canon_lide70
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   Copyright (C) 2019 Juergen Ernst and pimvantend.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This file is part of the SANE package.
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
10141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
11141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
12141cc406Sopenharmony_ci   License, or (at your option) any later version.
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
15141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
16141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17141cc406Sopenharmony_ci   General Public License for more details.
18141cc406Sopenharmony_ci
19141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
20141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   This file implements a SANE backend for the Canon CanoScan LiDE 70 and 600 */
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci#define BUILD 0
25141cc406Sopenharmony_ci#define MM_IN_INCH 25.4
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci#include "../include/sane/config.h"
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci#include <stdlib.h>
30141cc406Sopenharmony_ci#include <string.h>
31141cc406Sopenharmony_ci#include <stdio.h>
32141cc406Sopenharmony_ci#include <unistd.h>
33141cc406Sopenharmony_ci#include <fcntl.h>
34141cc406Sopenharmony_ci#include <sys/ioctl.h>
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci#include "../include/sane/sane.h"
37141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
38141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
39141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
40141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
41141cc406Sopenharmony_ci#define BACKEND_NAME        canon_lide70
42141cc406Sopenharmony_ci#define CANONUSB_CONFIG_FILE "canon_lide70.conf"
43141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_citypedef enum
46141cc406Sopenharmony_ci{
47141cc406Sopenharmony_ci  opt_num_opts = 0,
48141cc406Sopenharmony_ci  opt_mode_group,
49141cc406Sopenharmony_ci  opt_threshold,
50141cc406Sopenharmony_ci  opt_mode,
51141cc406Sopenharmony_ci  opt_resolution,
52141cc406Sopenharmony_ci  opt_non_blocking,
53141cc406Sopenharmony_ci  opt_geometry_group,
54141cc406Sopenharmony_ci  opt_tl_x,
55141cc406Sopenharmony_ci  opt_tl_y,
56141cc406Sopenharmony_ci  opt_br_x,
57141cc406Sopenharmony_ci  opt_br_y,
58141cc406Sopenharmony_ci  /* must come last: */
59141cc406Sopenharmony_ci  num_options
60141cc406Sopenharmony_ci}
61141cc406Sopenharmony_cicanon_opts;
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci#include "canon_lide70-common.c"
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_cistatic size_t
66141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
67141cc406Sopenharmony_ci{
68141cc406Sopenharmony_ci  size_t size, max_size = 0;
69141cc406Sopenharmony_ci  SANE_Int i;
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
72141cc406Sopenharmony_ci    {
73141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
74141cc406Sopenharmony_ci      if (size > max_size)
75141cc406Sopenharmony_ci	max_size = size;
76141cc406Sopenharmony_ci    }
77141cc406Sopenharmony_ci  return max_size;
78141cc406Sopenharmony_ci}
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = {
81141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
82141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
83141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
84141cc406Sopenharmony_ci  0
85141cc406Sopenharmony_ci};
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_cistatic SANE_Fixed init_tl_x = SANE_FIX (0.0);
88141cc406Sopenharmony_cistatic SANE_Fixed init_tl_y = SANE_FIX (0.0);
89141cc406Sopenharmony_cistatic SANE_Fixed init_br_x = SANE_FIX (80.0);
90141cc406Sopenharmony_cistatic SANE_Fixed init_br_y = SANE_FIX (100.0);
91141cc406Sopenharmony_cistatic SANE_Int init_threshold = 75;
92141cc406Sopenharmony_cistatic SANE_Int init_resolution = 600;
93141cc406Sopenharmony_cistatic SANE_String init_mode = SANE_VALUE_SCAN_MODE_COLOR;
94141cc406Sopenharmony_cistatic SANE_Int init_graymode = 0;
95141cc406Sopenharmony_cistatic SANE_Bool init_non_blocking = SANE_FALSE;
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci/*-----------------------------------------------------------------*/
98141cc406Sopenharmony_ci/*
99141cc406Sopenharmony_ciScan range
100141cc406Sopenharmony_ci*/
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_cistatic const SANE_Range widthRange = {
103141cc406Sopenharmony_ci  0,				/* minimum */
104141cc406Sopenharmony_ci  SANE_FIX (CANON_MAX_WIDTH * MM_IN_INCH / 600),	/* maximum */
105141cc406Sopenharmony_ci  0				/* quantization */
106141cc406Sopenharmony_ci};
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_cistatic const SANE_Range heightRange = {
109141cc406Sopenharmony_ci  0,				/* minimum */
110141cc406Sopenharmony_ci/*  SANE_FIX (CANON_MAX_HEIGHT * MM_IN_INCH / 600 - TOP_EDGE ),	 maximum */
111141cc406Sopenharmony_ci  SANE_FIX (297.0),
112141cc406Sopenharmony_ci  0				/* quantization */
113141cc406Sopenharmony_ci};
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_cistatic const SANE_Range threshold_range = {
116141cc406Sopenharmony_ci  0,
117141cc406Sopenharmony_ci  100,
118141cc406Sopenharmony_ci  1
119141cc406Sopenharmony_ci};
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_cistatic SANE_Int resolution_list[] = { 5,
122141cc406Sopenharmony_ci  75,
123141cc406Sopenharmony_ci  150,
124141cc406Sopenharmony_ci  300,
125141cc406Sopenharmony_ci  600,
126141cc406Sopenharmony_ci  1200
127141cc406Sopenharmony_ci};
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_citypedef struct Canon_Device
130141cc406Sopenharmony_ci{
131141cc406Sopenharmony_ci  struct Canon_Device *next;
132141cc406Sopenharmony_ci  SANE_String name;
133141cc406Sopenharmony_ci  SANE_Device sane;
134141cc406Sopenharmony_ci}
135141cc406Sopenharmony_ciCanon_Device;
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci/* Canon_Scanner is the type used for the sane handle */
138141cc406Sopenharmony_citypedef struct Canon_Scanner
139141cc406Sopenharmony_ci{
140141cc406Sopenharmony_ci  struct Canon_Scanner *next;
141141cc406Sopenharmony_ci  Canon_Device *device;
142141cc406Sopenharmony_ci  CANON_Handle scan;
143141cc406Sopenharmony_ci}
144141cc406Sopenharmony_ciCanon_Scanner;
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_cistatic int num_devices = 0;
147141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
148141cc406Sopenharmony_cistatic Canon_Device *first_dev = NULL;
149141cc406Sopenharmony_cistatic Canon_Scanner *first_handle = NULL;
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci/*-----------------------------------------------------------------*/
152141cc406Sopenharmony_cistatic SANE_Status
153141cc406Sopenharmony_ciattach_scanner (const char *devicename, Canon_Device ** devp)
154141cc406Sopenharmony_ci{
155141cc406Sopenharmony_ci  CANON_Handle scan;
156141cc406Sopenharmony_ci  Canon_Device *dev;
157141cc406Sopenharmony_ci  SANE_Status status;
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci  DBG (3, "attach_scanner: %s\n", devicename);
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
162141cc406Sopenharmony_ci    {
163141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
164141cc406Sopenharmony_ci	{
165141cc406Sopenharmony_ci	  if (devp)
166141cc406Sopenharmony_ci	    *devp = dev;
167141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
168141cc406Sopenharmony_ci	}
169141cc406Sopenharmony_ci    }
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
172141cc406Sopenharmony_ci  if (!dev)
173141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
174141cc406Sopenharmony_ci  memset (dev, '\0', sizeof (Canon_Device));	/* clear structure */
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci  DBG (4, "attach_scanner: opening %s\n", devicename);
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci  status = CANON_open_device (&scan, devicename);
179141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
180141cc406Sopenharmony_ci    {
181141cc406Sopenharmony_ci      DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename);
182141cc406Sopenharmony_ci      free (dev);
183141cc406Sopenharmony_ci      return status;
184141cc406Sopenharmony_ci    }
185141cc406Sopenharmony_ci  dev->name = strdup (devicename);
186141cc406Sopenharmony_ci  dev->sane.name = dev->name;
187141cc406Sopenharmony_ci  dev->sane.vendor = "CANON";
188141cc406Sopenharmony_ci  dev->sane.model = CANON_get_device_name (&scan);
189141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
190141cc406Sopenharmony_ci  CANON_close_device (&scan);
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  ++num_devices;
193141cc406Sopenharmony_ci  dev->next = first_dev;
194141cc406Sopenharmony_ci  first_dev = dev;
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci  if (devp)
197141cc406Sopenharmony_ci    *devp = dev;
198141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
199141cc406Sopenharmony_ci}
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci
202141cc406Sopenharmony_ci/* callback function for sanei_usb_attach_matching_devices */
203141cc406Sopenharmony_cistatic SANE_Status
204141cc406Sopenharmony_ciattach_one (const char *name)
205141cc406Sopenharmony_ci{
206141cc406Sopenharmony_ci  attach_scanner (name, 0);
207141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
208141cc406Sopenharmony_ci}
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci/* Find our devices */
212141cc406Sopenharmony_ciSANE_Status
213141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
214141cc406Sopenharmony_ci{
215141cc406Sopenharmony_ci  char config_line[PATH_MAX];
216141cc406Sopenharmony_ci  size_t len;
217141cc406Sopenharmony_ci  FILE *fp;
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci  DBG_INIT ();
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci#if 0
222141cc406Sopenharmony_ci  DBG_LEVEL = 10;
223141cc406Sopenharmony_ci#endif
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci  DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
226141cc406Sopenharmony_ci       version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
227141cc406Sopenharmony_ci  DBG (1, "sane_init: SANE Canon LiDE70 backend version %d.%d.%d from %s\n",
228141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci  if (version_code)
231141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  sanei_usb_init ();
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci  fp = sanei_config_open (CANONUSB_CONFIG_FILE);
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci  if (!fp)
238141cc406Sopenharmony_ci    {
239141cc406Sopenharmony_ci      /* no config-file: try these */
240141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);
241141cc406Sopenharmony_ci      attach_scanner ("/dev/usbscanner", 0);
242141cc406Sopenharmony_ci      attach_scanner ("/dev/usb/scanner", 0);
243141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
244141cc406Sopenharmony_ci    }
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci  DBG (3, "reading configure file %s\n", CANONUSB_CONFIG_FILE);
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci  while (sanei_config_read (config_line, sizeof (config_line), fp))
249141cc406Sopenharmony_ci    {
250141cc406Sopenharmony_ci      if (config_line[0] == '#')
251141cc406Sopenharmony_ci	continue;		/* ignore line comments */
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci      len = strlen (config_line);
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci      if (!len)
256141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci      DBG (4, "attach_matching_devices(%s)\n", config_line);
259141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices (config_line, attach_one);
260141cc406Sopenharmony_ci    }
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci  DBG (4, "finished reading configure file\n");
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci  fclose (fp);
265141cc406Sopenharmony_ci
266141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
267141cc406Sopenharmony_ci}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_civoid
271141cc406Sopenharmony_cisane_exit (void)
272141cc406Sopenharmony_ci{
273141cc406Sopenharmony_ci  Canon_Device *dev, *next;
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci  DBG (3, "sane_exit\n");
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
278141cc406Sopenharmony_ci    {
279141cc406Sopenharmony_ci      next = dev->next;
280141cc406Sopenharmony_ci      free (dev->name);
281141cc406Sopenharmony_ci      free (dev);
282141cc406Sopenharmony_ci    }
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci  if (devlist)
285141cc406Sopenharmony_ci    free (devlist);
286141cc406Sopenharmony_ci  return;
287141cc406Sopenharmony_ci}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ciSANE_Status
291141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
292141cc406Sopenharmony_ci{
293141cc406Sopenharmony_ci  Canon_Device *dev;
294141cc406Sopenharmony_ci  int i;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci  DBG (3, "sane_get_devices(local_only = %d)\n", local_only);
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  if (devlist)
299141cc406Sopenharmony_ci    free (devlist);
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
302141cc406Sopenharmony_ci  if (!devlist)
303141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
304141cc406Sopenharmony_ci
305141cc406Sopenharmony_ci  i = 0;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
308141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  devlist[i++] = 0;
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  *device_list = devlist;
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
315141cc406Sopenharmony_ci}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_cistatic SANE_Status
318141cc406Sopenharmony_ciinit_options (CANON_Handle * chndl)
319141cc406Sopenharmony_ci{
320141cc406Sopenharmony_ci  SANE_Option_Descriptor *od;
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci  DBG (2, "begin init_options: chndl=%p\n", (void *) chndl);
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci  /* opt_num_opts */
325141cc406Sopenharmony_ci  od = &chndl->opt[opt_num_opts];
326141cc406Sopenharmony_ci  od->name = "";
327141cc406Sopenharmony_ci  od->title = SANE_TITLE_NUM_OPTIONS;
328141cc406Sopenharmony_ci  od->desc = SANE_DESC_NUM_OPTIONS;
329141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
330141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
331141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
332141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT;
333141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
334141cc406Sopenharmony_ci  od->constraint.range = 0;
335141cc406Sopenharmony_ci  chndl->val[opt_num_opts].w = num_options;
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci  DBG (2, "val[opt_num_opts]: %d\n", chndl->val[opt_num_opts].w);
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci  /* opt_mode_group */
340141cc406Sopenharmony_ci  od = &chndl->opt[opt_mode_group];
341141cc406Sopenharmony_ci  od->name = "";
342141cc406Sopenharmony_ci  od->title = SANE_I18N ("Scan Mode");
343141cc406Sopenharmony_ci  od->desc = "";
344141cc406Sopenharmony_ci  od->type = SANE_TYPE_GROUP;
345141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
346141cc406Sopenharmony_ci  od->size = 0;
347141cc406Sopenharmony_ci  od->cap = 0;
348141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
349141cc406Sopenharmony_ci  od->constraint.range = 0;
350141cc406Sopenharmony_ci  chndl->val[opt_mode_group].w = 0;
351141cc406Sopenharmony_ci
352141cc406Sopenharmony_ci  /* opt_mode */
353141cc406Sopenharmony_ci  od = &chndl->opt[opt_mode];
354141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_MODE;
355141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_MODE;
356141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_MODE;
357141cc406Sopenharmony_ci  od->type = SANE_TYPE_STRING;
358141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
359141cc406Sopenharmony_ci  od->size = max_string_size (mode_list);
360141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
361141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_STRING_LIST;
362141cc406Sopenharmony_ci  od->constraint.string_list = mode_list;
363141cc406Sopenharmony_ci  chndl->val[opt_mode].s = malloc (od->size);
364141cc406Sopenharmony_ci  if (!chndl->val[opt_mode].s)
365141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
366141cc406Sopenharmony_ci  strcpy (chndl->val[opt_mode].s, init_mode);
367141cc406Sopenharmony_ci  chndl->graymode = init_graymode;
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci  /* opt_threshold */
370141cc406Sopenharmony_ci  od = &chndl->opt[opt_threshold];
371141cc406Sopenharmony_ci  od->name = SANE_NAME_THRESHOLD;
372141cc406Sopenharmony_ci  od->title = SANE_TITLE_THRESHOLD;
373141cc406Sopenharmony_ci  od->desc = SANE_DESC_THRESHOLD;
374141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
375141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PERCENT;
376141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
377141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
378141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
379141cc406Sopenharmony_ci  od->constraint.range = &threshold_range;
380141cc406Sopenharmony_ci  chndl->val[opt_threshold].w = init_threshold;
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci  /* opt_resolution */
383141cc406Sopenharmony_ci  od = &chndl->opt[opt_resolution];
384141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_RESOLUTION;
385141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_RESOLUTION;
386141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_RESOLUTION;
387141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
388141cc406Sopenharmony_ci  od->unit = SANE_UNIT_DPI;
389141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
390141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
391141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_WORD_LIST;
392141cc406Sopenharmony_ci  if (chndl->productcode == 0x2224)
393141cc406Sopenharmony_ci    {
394141cc406Sopenharmony_ci      resolution_list[0] = 4;
395141cc406Sopenharmony_ci    }
396141cc406Sopenharmony_ci  od->constraint.word_list = resolution_list;
397141cc406Sopenharmony_ci  chndl->val[opt_resolution].w = init_resolution;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci  /* opt_non_blocking */
400141cc406Sopenharmony_ci  od = &chndl->opt[opt_non_blocking];
401141cc406Sopenharmony_ci  od->name = "non-blocking";
402141cc406Sopenharmony_ci  od->title = SANE_I18N ("Use non-blocking IO");
403141cc406Sopenharmony_ci  od->desc = SANE_I18N ("Use non-blocking IO for sane_read() if supported "
404141cc406Sopenharmony_ci			"by the frontend.");
405141cc406Sopenharmony_ci  od->type = SANE_TYPE_BOOL;
406141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
407141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
408141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
409141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
410141cc406Sopenharmony_ci  od->constraint.range = 0;
411141cc406Sopenharmony_ci  chndl->val[opt_non_blocking].w = init_non_blocking;
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci  /* opt_geometry_group */
414141cc406Sopenharmony_ci  od = &chndl->opt[opt_geometry_group];
415141cc406Sopenharmony_ci  od->name = "";
416141cc406Sopenharmony_ci  od->title = SANE_I18N ("Geometry");
417141cc406Sopenharmony_ci  od->desc = "";
418141cc406Sopenharmony_ci  od->type = SANE_TYPE_GROUP;
419141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
420141cc406Sopenharmony_ci  od->size = 0;
421141cc406Sopenharmony_ci  od->cap = 0;
422141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
423141cc406Sopenharmony_ci  od->constraint.range = 0;
424141cc406Sopenharmony_ci  chndl->val[opt_geometry_group].w = 0;
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci  /* opt_tl_x */
427141cc406Sopenharmony_ci  od = &chndl->opt[opt_tl_x];
428141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_TL_X;
429141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_TL_X;
430141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_TL_X;
431141cc406Sopenharmony_ci  od->type = SANE_TYPE_FIXED;
432141cc406Sopenharmony_ci  od->unit = SANE_UNIT_MM;
433141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
434141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
435141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
436141cc406Sopenharmony_ci  od->constraint.range = &widthRange;
437141cc406Sopenharmony_ci  chndl->val[opt_tl_x].w = init_tl_x;
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  /* opt_tl_y */
440141cc406Sopenharmony_ci  od = &chndl->opt[opt_tl_y];
441141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_TL_Y;
442141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_TL_Y;
443141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_TL_Y;
444141cc406Sopenharmony_ci  od->type = SANE_TYPE_FIXED;
445141cc406Sopenharmony_ci  od->unit = SANE_UNIT_MM;
446141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
447141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
448141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
449141cc406Sopenharmony_ci  od->constraint.range = &heightRange;
450141cc406Sopenharmony_ci  chndl->val[opt_tl_y].w = init_tl_y;
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  /* opt_br_x */
453141cc406Sopenharmony_ci  od = &chndl->opt[opt_br_x];
454141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_BR_X;
455141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_BR_X;
456141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_BR_X;
457141cc406Sopenharmony_ci  od->type = SANE_TYPE_FIXED;
458141cc406Sopenharmony_ci  od->unit = SANE_UNIT_MM;
459141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
460141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
461141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
462141cc406Sopenharmony_ci  od->constraint.range = &widthRange;
463141cc406Sopenharmony_ci  chndl->val[opt_br_x].w = init_br_x;
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci  /* opt_br_y */
466141cc406Sopenharmony_ci  od = &chndl->opt[opt_br_y];
467141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_BR_Y;
468141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_BR_Y;
469141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_BR_Y;
470141cc406Sopenharmony_ci  od->type = SANE_TYPE_FIXED;
471141cc406Sopenharmony_ci  od->unit = SANE_UNIT_MM;
472141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
473141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
474141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
475141cc406Sopenharmony_ci  od->constraint.range = &heightRange;
476141cc406Sopenharmony_ci  chndl->val[opt_br_y].w = init_br_y;
477141cc406Sopenharmony_ci
478141cc406Sopenharmony_ci  DBG (2, "end init_options: chndl=%p\n", (void *) chndl);
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
481141cc406Sopenharmony_ci}
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_ciSANE_Status
484141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
485141cc406Sopenharmony_ci{
486141cc406Sopenharmony_ci  Canon_Device *dev;
487141cc406Sopenharmony_ci  SANE_Status status;
488141cc406Sopenharmony_ci  Canon_Scanner *scanner;
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci  DBG (3, "sane_open\n");
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci  if (devicename[0])		/* search for devicename */
493141cc406Sopenharmony_ci    {
494141cc406Sopenharmony_ci      DBG (4, "sane_open: devicename=%s\n", devicename);
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
497141cc406Sopenharmony_ci	if (strcmp (dev->sane.name, devicename) == 0)
498141cc406Sopenharmony_ci	  break;
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci      if (!dev)
501141cc406Sopenharmony_ci	{
502141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
505141cc406Sopenharmony_ci	    return status;
506141cc406Sopenharmony_ci	}
507141cc406Sopenharmony_ci    }
508141cc406Sopenharmony_ci  else
509141cc406Sopenharmony_ci    {
510141cc406Sopenharmony_ci      DBG (2, "sane_open: no devicename, opening first device\n");
511141cc406Sopenharmony_ci      dev = first_dev;
512141cc406Sopenharmony_ci    }
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci  if (!dev)
515141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci  scanner = malloc (sizeof (*scanner));
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  if (!scanner)
520141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci  memset (scanner, 0, sizeof (*scanner));
523141cc406Sopenharmony_ci  scanner->device = dev;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  status = CANON_open_device (&scanner->scan, dev->sane.name);
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
528141cc406Sopenharmony_ci    {
529141cc406Sopenharmony_ci      free (scanner);
530141cc406Sopenharmony_ci      return status;
531141cc406Sopenharmony_ci    }
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  status = init_options (&scanner->scan);
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  *handle = scanner;
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
538141cc406Sopenharmony_ci  scanner->next = first_handle;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci  first_handle = scanner;
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci  return status;
543141cc406Sopenharmony_ci}
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_cistatic void
546141cc406Sopenharmony_ciprint_options (CANON_Handle * chndl)
547141cc406Sopenharmony_ci{
548141cc406Sopenharmony_ci  SANE_Option_Descriptor *od;
549141cc406Sopenharmony_ci  SANE_Word option_number;
550141cc406Sopenharmony_ci  SANE_Char caps[1024];
551141cc406Sopenharmony_ci
552141cc406Sopenharmony_ci  for (option_number = 0; option_number < num_options; option_number++)
553141cc406Sopenharmony_ci    {
554141cc406Sopenharmony_ci      od = &chndl->opt[option_number];
555141cc406Sopenharmony_ci      DBG (50, "-----> number: %d\n", option_number);
556141cc406Sopenharmony_ci      DBG (50, "         name: `%s'\n", od->name);
557141cc406Sopenharmony_ci      DBG (50, "        title: `%s'\n", od->title);
558141cc406Sopenharmony_ci      DBG (50, "  description: `%s'\n", od->desc);
559141cc406Sopenharmony_ci      DBG (50, "         type: %s\n",
560141cc406Sopenharmony_ci	   od->type == SANE_TYPE_BOOL ? "SANE_TYPE_BOOL" :
561141cc406Sopenharmony_ci	   od->type == SANE_TYPE_INT ? "SANE_TYPE_INT" :
562141cc406Sopenharmony_ci	   od->type == SANE_TYPE_FIXED ? "SANE_TYPE_FIXED" :
563141cc406Sopenharmony_ci	   od->type == SANE_TYPE_STRING ? "SANE_TYPE_STRING" :
564141cc406Sopenharmony_ci	   od->type == SANE_TYPE_BUTTON ? "SANE_TYPE_BUTTON" :
565141cc406Sopenharmony_ci	   od->type == SANE_TYPE_GROUP ? "SANE_TYPE_GROUP" : "unknown");
566141cc406Sopenharmony_ci      DBG (50, "         unit: %s\n",
567141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_NONE ? "SANE_UNIT_NONE" :
568141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_PIXEL ? "SANE_UNIT_PIXEL" :
569141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_BIT ? "SANE_UNIT_BIT" :
570141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_MM ? "SANE_UNIT_MM" :
571141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_DPI ? "SANE_UNIT_DPI" :
572141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_PERCENT ? "SANE_UNIT_PERCENT" :
573141cc406Sopenharmony_ci	   od->unit == SANE_UNIT_MICROSECOND ? "SANE_UNIT_MICROSECOND" :
574141cc406Sopenharmony_ci	   "unknown");
575141cc406Sopenharmony_ci      DBG (50, "         size: %d\n", od->size);
576141cc406Sopenharmony_ci      caps[0] = '\0';
577141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_SOFT_SELECT)
578141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_SOFT_SELECT ");
579141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_HARD_SELECT)
580141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_HARD_SELECT ");
581141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_SOFT_DETECT)
582141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_SOFT_DETECT ");
583141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_EMULATED)
584141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_EMULATED ");
585141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_AUTOMATIC)
586141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_AUTOMATIC ");
587141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_INACTIVE)
588141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_INACTIVE ");
589141cc406Sopenharmony_ci      if (od->cap & SANE_CAP_ADVANCED)
590141cc406Sopenharmony_ci	strcat (caps, "SANE_CAP_ADVANCED ");
591141cc406Sopenharmony_ci      DBG (50, " capabilities: %s\n", caps);
592141cc406Sopenharmony_ci      DBG (50, "constraint type: %s\n",
593141cc406Sopenharmony_ci	   od->constraint_type == SANE_CONSTRAINT_NONE ?
594141cc406Sopenharmony_ci	   "SANE_CONSTRAINT_NONE" :
595141cc406Sopenharmony_ci	   od->constraint_type == SANE_CONSTRAINT_RANGE ?
596141cc406Sopenharmony_ci	   "SANE_CONSTRAINT_RANGE" :
597141cc406Sopenharmony_ci	   od->constraint_type == SANE_CONSTRAINT_WORD_LIST ?
598141cc406Sopenharmony_ci	   "SANE_CONSTRAINT_WORD_LIST" :
599141cc406Sopenharmony_ci	   od->constraint_type == SANE_CONSTRAINT_STRING_LIST ?
600141cc406Sopenharmony_ci	   "SANE_CONSTRAINT_STRING_LIST" : "unknown");
601141cc406Sopenharmony_ci      if (od->type == SANE_TYPE_INT)
602141cc406Sopenharmony_ci	DBG (50, "        value: %d\n", chndl->val[option_number].w);
603141cc406Sopenharmony_ci      else if (od->type == SANE_TYPE_FIXED)
604141cc406Sopenharmony_ci	DBG (50, "        value: %f\n",
605141cc406Sopenharmony_ci	     SANE_UNFIX (chndl->val[option_number].w));
606141cc406Sopenharmony_ci      else if (od->type == SANE_TYPE_STRING)
607141cc406Sopenharmony_ci	DBG (50, "        value: %s\n", chndl->val[option_number].s);
608141cc406Sopenharmony_ci    }
609141cc406Sopenharmony_ci}
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_civoid
612141cc406Sopenharmony_cisane_close (SANE_Handle handle)
613141cc406Sopenharmony_ci{
614141cc406Sopenharmony_ci  Canon_Scanner *prev, *scanner;
615141cc406Sopenharmony_ci  SANE_Status res;
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci  DBG (3, "sane_close\n");
618141cc406Sopenharmony_ci
619141cc406Sopenharmony_ci  scanner = handle;
620141cc406Sopenharmony_ci  print_options (&scanner->scan);
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci  if (!first_handle)
623141cc406Sopenharmony_ci    {
624141cc406Sopenharmony_ci      DBG (1, "ERROR: sane_close: no handles opened\n");
625141cc406Sopenharmony_ci      return;
626141cc406Sopenharmony_ci    }
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci  prev = NULL;
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci  for (scanner = first_handle; scanner; scanner = scanner->next)
633141cc406Sopenharmony_ci    {
634141cc406Sopenharmony_ci      if (scanner == handle)
635141cc406Sopenharmony_ci	break;
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci      prev = scanner;
638141cc406Sopenharmony_ci    }
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci  if (!scanner)
641141cc406Sopenharmony_ci    {
642141cc406Sopenharmony_ci      DBG (1, "ERROR: sane_close: invalid handle %p\n", handle);
643141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
644141cc406Sopenharmony_ci    }
645141cc406Sopenharmony_ci
646141cc406Sopenharmony_ci  if (prev)
647141cc406Sopenharmony_ci    prev->next = scanner->next;
648141cc406Sopenharmony_ci  else
649141cc406Sopenharmony_ci    first_handle = scanner->next;
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci  res = CANON_close_device (&scanner->scan);
652141cc406Sopenharmony_ci  DBG (3, "CANON_close_device returned: %d\n", res);
653141cc406Sopenharmony_ci  free (scanner);
654141cc406Sopenharmony_ci}
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
657141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
658141cc406Sopenharmony_ci{
659141cc406Sopenharmony_ci  Canon_Scanner *scanner = handle;
660141cc406Sopenharmony_ci  CANON_Handle *chndl = &scanner->scan;
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  DBG (4, "sane_get_option_descriptor: handle=%p, option = %d\n",
664141cc406Sopenharmony_ci       (void *) handle, option);
665141cc406Sopenharmony_ci  if (option < 0 || option >= num_options)
666141cc406Sopenharmony_ci    {
667141cc406Sopenharmony_ci      DBG (3, "sane_get_option_descriptor: option < 0 || "
668141cc406Sopenharmony_ci	   "option > num_options\n");
669141cc406Sopenharmony_ci      return 0;
670141cc406Sopenharmony_ci    }
671141cc406Sopenharmony_ci
672141cc406Sopenharmony_ci  return &chndl->opt[option];
673141cc406Sopenharmony_ci}
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ciSANE_Status
676141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
677141cc406Sopenharmony_ci		     void *value, SANE_Int * info)
678141cc406Sopenharmony_ci{
679141cc406Sopenharmony_ci  Canon_Scanner *scanner = handle;
680141cc406Sopenharmony_ci  CANON_Handle *chndl = &scanner->scan;
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  SANE_Int myinfo = 0;
683141cc406Sopenharmony_ci  SANE_Status status;
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  DBG (4, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
686141cc406Sopenharmony_ci       (void *) handle, option, action, (void *) value, (void *) info);
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci  if (option < 0 || option >= num_options)
689141cc406Sopenharmony_ci    {
690141cc406Sopenharmony_ci      DBG (1, "sane_control_option: option < 0 || option > num_options\n");
691141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
692141cc406Sopenharmony_ci    }
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (chndl->opt[option].cap))
695141cc406Sopenharmony_ci    {
696141cc406Sopenharmony_ci      DBG (1, "sane_control_option: option is inactive\n");
697141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
698141cc406Sopenharmony_ci    }
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci  if (chndl->opt[option].type == SANE_TYPE_GROUP)
701141cc406Sopenharmony_ci    {
702141cc406Sopenharmony_ci      DBG (1, "sane_control_option: option is a group\n");
703141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
704141cc406Sopenharmony_ci    }
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci  switch (action)
707141cc406Sopenharmony_ci    {
708141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
709141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (chndl->opt[option].cap))
710141cc406Sopenharmony_ci	{
711141cc406Sopenharmony_ci	  DBG (1, "sane_control_option: option is not setable\n");
712141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
713141cc406Sopenharmony_ci	}
714141cc406Sopenharmony_ci      status = sanei_constrain_value (&chndl->opt[option], value, &myinfo);
715141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
716141cc406Sopenharmony_ci	{
717141cc406Sopenharmony_ci	  DBG (3, "sane_control_option: sanei_constrain_value returned %s\n",
718141cc406Sopenharmony_ci	       sane_strstatus (status));
719141cc406Sopenharmony_ci	  return status;
720141cc406Sopenharmony_ci	}
721141cc406Sopenharmony_ci      switch (option)
722141cc406Sopenharmony_ci	{
723141cc406Sopenharmony_ci	case opt_tl_x:		/* Fixed with parameter reloading */
724141cc406Sopenharmony_ci	case opt_tl_y:
725141cc406Sopenharmony_ci	case opt_br_x:
726141cc406Sopenharmony_ci	case opt_br_y:
727141cc406Sopenharmony_ci	  if (chndl->val[option].w == *(SANE_Fixed *) value)
728141cc406Sopenharmony_ci	    {
729141cc406Sopenharmony_ci	      DBG (4, "sane_control_option: option %d (%s) not changed\n",
730141cc406Sopenharmony_ci		   option, chndl->opt[option].name);
731141cc406Sopenharmony_ci	      break;
732141cc406Sopenharmony_ci	    }
733141cc406Sopenharmony_ci	  chndl->val[option].w = *(SANE_Fixed *) value;
734141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_PARAMS;
735141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: set option %d (%s) to %.0f %s\n",
736141cc406Sopenharmony_ci	       option, chndl->opt[option].name,
737141cc406Sopenharmony_ci	       SANE_UNFIX (*(SANE_Fixed *) value),
738141cc406Sopenharmony_ci	       chndl->opt[option].unit == SANE_UNIT_MM ? "mm" : "dpi");
739141cc406Sopenharmony_ci	  break;
740141cc406Sopenharmony_ci	case opt_non_blocking:
741141cc406Sopenharmony_ci	  if (chndl->val[option].w == *(SANE_Bool *) value)
742141cc406Sopenharmony_ci	    {
743141cc406Sopenharmony_ci	      DBG (4, "sane_control_option: option %d (%s) not changed\n",
744141cc406Sopenharmony_ci		   option, chndl->opt[option].name);
745141cc406Sopenharmony_ci	      break;
746141cc406Sopenharmony_ci	    }
747141cc406Sopenharmony_ci	  chndl->val[option].w = *(SANE_Bool *) value;
748141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: set option %d (%s) to %s\n",
749141cc406Sopenharmony_ci	       option, chndl->opt[option].name,
750141cc406Sopenharmony_ci	       *(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
751141cc406Sopenharmony_ci	  break;
752141cc406Sopenharmony_ci	case opt_resolution:
753141cc406Sopenharmony_ci	case opt_threshold:
754141cc406Sopenharmony_ci	  if (chndl->val[option].w == *(SANE_Int *) value)
755141cc406Sopenharmony_ci	    {
756141cc406Sopenharmony_ci	      DBG (4, "sane_control_option: option %d (%s) not changed\n",
757141cc406Sopenharmony_ci		   option, chndl->opt[option].name);
758141cc406Sopenharmony_ci	      break;
759141cc406Sopenharmony_ci	    }
760141cc406Sopenharmony_ci	  chndl->val[option].w = *(SANE_Int *) value;
761141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_PARAMS;
762141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
763141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: set option %d (%s) to %d\n",
764141cc406Sopenharmony_ci	       option, chndl->opt[option].name, *(SANE_Int *) value);
765141cc406Sopenharmony_ci	  break;
766141cc406Sopenharmony_ci	case opt_mode:
767141cc406Sopenharmony_ci	  if (strcmp (chndl->val[option].s, value) == 0)
768141cc406Sopenharmony_ci	    {
769141cc406Sopenharmony_ci	      DBG (4, "sane_control_option: option %d (%s) not changed\n",
770141cc406Sopenharmony_ci		   option, chndl->opt[option].name);
771141cc406Sopenharmony_ci	      break;
772141cc406Sopenharmony_ci	    }
773141cc406Sopenharmony_ci	  strcpy (chndl->val[option].s, (SANE_String) value);
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci	  if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) ==
776141cc406Sopenharmony_ci	      0)
777141cc406Sopenharmony_ci	    {
778141cc406Sopenharmony_ci	      chndl->opt[opt_threshold].cap &= ~SANE_CAP_INACTIVE;
779141cc406Sopenharmony_ci	      chndl->graymode = 2;
780141cc406Sopenharmony_ci	    }
781141cc406Sopenharmony_ci	  if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
782141cc406Sopenharmony_ci	    {
783141cc406Sopenharmony_ci	      chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
784141cc406Sopenharmony_ci	      chndl->graymode = 0;
785141cc406Sopenharmony_ci	    }
786141cc406Sopenharmony_ci	  if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
787141cc406Sopenharmony_ci	    {
788141cc406Sopenharmony_ci	      chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
789141cc406Sopenharmony_ci	      chndl->graymode = 1;
790141cc406Sopenharmony_ci	    }
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_PARAMS;
794141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
795141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: set option %d (%s) to %s\n",
796141cc406Sopenharmony_ci	       option, chndl->opt[option].name, (SANE_String) value);
797141cc406Sopenharmony_ci	  break;
798141cc406Sopenharmony_ci	default:
799141cc406Sopenharmony_ci	  DBG (1, "sane_control_option: trying to set unexpected option\n");
800141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
801141cc406Sopenharmony_ci	}
802141cc406Sopenharmony_ci      break;
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
805141cc406Sopenharmony_ci      switch (option)
806141cc406Sopenharmony_ci	{
807141cc406Sopenharmony_ci	case opt_num_opts:
808141cc406Sopenharmony_ci	  *(SANE_Word *) value = num_options;
809141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: get option 0, value = %d\n",
810141cc406Sopenharmony_ci	       num_options);
811141cc406Sopenharmony_ci	  break;
812141cc406Sopenharmony_ci	case opt_tl_x:		/* Fixed options */
813141cc406Sopenharmony_ci	case opt_tl_y:
814141cc406Sopenharmony_ci	case opt_br_x:
815141cc406Sopenharmony_ci	case opt_br_y:
816141cc406Sopenharmony_ci	  {
817141cc406Sopenharmony_ci	    *(SANE_Fixed *) value = chndl->val[option].w;
818141cc406Sopenharmony_ci	    DBG (4,
819141cc406Sopenharmony_ci		 "sane_control_option: get option %d (%s), value=%.1f %s\n",
820141cc406Sopenharmony_ci		 option, chndl->opt[option].name,
821141cc406Sopenharmony_ci		 SANE_UNFIX (*(SANE_Fixed *) value),
822141cc406Sopenharmony_ci		 chndl->opt[option].unit == SANE_UNIT_MM ? "mm" :
823141cc406Sopenharmony_ci                 (chndl->opt[option].unit == SANE_UNIT_DPI ? "dpi" : ""));
824141cc406Sopenharmony_ci	    break;
825141cc406Sopenharmony_ci	  }
826141cc406Sopenharmony_ci	case opt_non_blocking:
827141cc406Sopenharmony_ci	  *(SANE_Bool *) value = chndl->val[option].w;
828141cc406Sopenharmony_ci	  DBG (4,
829141cc406Sopenharmony_ci	       "sane_control_option: get option %d (%s), value=%s\n",
830141cc406Sopenharmony_ci	       option, chndl->opt[option].name,
831141cc406Sopenharmony_ci	       *(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
832141cc406Sopenharmony_ci	  break;
833141cc406Sopenharmony_ci	case opt_mode:		/* String (list) options */
834141cc406Sopenharmony_ci	  strcpy (value, chndl->val[option].s);
835141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: get option %d (%s), value=`%s'\n",
836141cc406Sopenharmony_ci	       option, chndl->opt[option].name, (SANE_String) value);
837141cc406Sopenharmony_ci	  break;
838141cc406Sopenharmony_ci	case opt_resolution:
839141cc406Sopenharmony_ci	case opt_threshold:
840141cc406Sopenharmony_ci	  *(SANE_Int *) value = chndl->val[option].w;
841141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: get option %d (%s), value=%d\n",
842141cc406Sopenharmony_ci	       option, chndl->opt[option].name, *(SANE_Int *) value);
843141cc406Sopenharmony_ci	  break;
844141cc406Sopenharmony_ci	default:
845141cc406Sopenharmony_ci	  DBG (1, "sane_control_option: trying to get unexpected option\n");
846141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
847141cc406Sopenharmony_ci	}
848141cc406Sopenharmony_ci      break;
849141cc406Sopenharmony_ci    default:
850141cc406Sopenharmony_ci      DBG (1, "sane_control_option: trying unexpected action %d\n", action);
851141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
852141cc406Sopenharmony_ci    }
853141cc406Sopenharmony_ci
854141cc406Sopenharmony_ci  if (info)
855141cc406Sopenharmony_ci    *info = myinfo;
856141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
857141cc406Sopenharmony_ci}
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ciSANE_Status
861141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
862141cc406Sopenharmony_ci{
863141cc406Sopenharmony_ci  Canon_Scanner *hndl = handle;	/* Eliminate compiler warning */
864141cc406Sopenharmony_ci  CANON_Handle *chndl = &hndl->scan;
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci  SANE_Status rc = SANE_STATUS_GOOD;
867141cc406Sopenharmony_ci  int w = SANE_UNFIX (chndl->val[opt_br_x].w -
868141cc406Sopenharmony_ci		      chndl->val[opt_tl_x].w) / MM_IN_INCH *
869141cc406Sopenharmony_ci    chndl->val[opt_resolution].w;
870141cc406Sopenharmony_ci  int h =
871141cc406Sopenharmony_ci    SANE_UNFIX (chndl->val[opt_br_y].w -
872141cc406Sopenharmony_ci		chndl->val[opt_tl_y].w) / MM_IN_INCH *
873141cc406Sopenharmony_ci    chndl->val[opt_resolution].w;
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci  DBG (3, "sane_get_parameters\n");
876141cc406Sopenharmony_ci  chndl->params.depth = 8;
877141cc406Sopenharmony_ci  chndl->params.last_frame = SANE_TRUE;
878141cc406Sopenharmony_ci  chndl->params.pixels_per_line = w;
879141cc406Sopenharmony_ci  chndl->params.lines = h;
880141cc406Sopenharmony_ci
881141cc406Sopenharmony_ci  if (chndl->graymode == 1)
882141cc406Sopenharmony_ci    {
883141cc406Sopenharmony_ci      chndl->params.format = SANE_FRAME_GRAY;
884141cc406Sopenharmony_ci      chndl->params.bytes_per_line = w;
885141cc406Sopenharmony_ci    }
886141cc406Sopenharmony_ci  else if (chndl->graymode == 2)
887141cc406Sopenharmony_ci    {
888141cc406Sopenharmony_ci      chndl->params.format = SANE_FRAME_GRAY;
889141cc406Sopenharmony_ci      w /= 8;
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci      if ((chndl->params.pixels_per_line % 8) != 0)
892141cc406Sopenharmony_ci	w++;
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_ci      chndl->params.bytes_per_line = w;
895141cc406Sopenharmony_ci      chndl->params.depth = 1;
896141cc406Sopenharmony_ci    }
897141cc406Sopenharmony_ci  else
898141cc406Sopenharmony_ci    {
899141cc406Sopenharmony_ci      chndl->params.format = SANE_FRAME_RGB;
900141cc406Sopenharmony_ci      chndl->params.bytes_per_line = w * 3;
901141cc406Sopenharmony_ci    }
902141cc406Sopenharmony_ci
903141cc406Sopenharmony_ci  *params = chndl->params;
904141cc406Sopenharmony_ci  DBG (1, "%d\n", chndl->params.format);
905141cc406Sopenharmony_ci  return rc;
906141cc406Sopenharmony_ci}
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ciSANE_Status
910141cc406Sopenharmony_cisane_start (SANE_Handle handle)
911141cc406Sopenharmony_ci{
912141cc406Sopenharmony_ci  Canon_Scanner *scanner = handle;
913141cc406Sopenharmony_ci  CANON_Handle *chndl = &scanner->scan;
914141cc406Sopenharmony_ci  SANE_Status res;
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci  DBG (3, "sane_start\n");
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci  res = sane_get_parameters (handle, &chndl->params);
919141cc406Sopenharmony_ci  res = CANON_set_scan_parameters (&scanner->scan);
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
922141cc406Sopenharmony_ci    return res;
923141cc406Sopenharmony_ci
924141cc406Sopenharmony_ci  return CANON_start_scan (&scanner->scan);
925141cc406Sopenharmony_ci}
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ciSANE_Status
929141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data,
930141cc406Sopenharmony_ci	   SANE_Int max_length, SANE_Int * length)
931141cc406Sopenharmony_ci{
932141cc406Sopenharmony_ci  Canon_Scanner *scanner = handle;
933141cc406Sopenharmony_ci  return CANON_read (&scanner->scan, data, max_length, length);
934141cc406Sopenharmony_ci}
935141cc406Sopenharmony_ci
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_civoid
938141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
939141cc406Sopenharmony_ci{
940141cc406Sopenharmony_ci  DBG (3, "sane_cancel: handle = %p\n", handle);
941141cc406Sopenharmony_ci  DBG (3, "sane_cancel: cancelling is unsupported in this backend\n");
942141cc406Sopenharmony_ci}
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ciSANE_Status
946141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
947141cc406Sopenharmony_ci{
948141cc406Sopenharmony_ci  DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
949141cc406Sopenharmony_ci       non_blocking);
950141cc406Sopenharmony_ci  if (non_blocking != SANE_FALSE)
951141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
952141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
953141cc406Sopenharmony_ci}
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ciSANE_Status
957141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
958141cc406Sopenharmony_ci{
959141cc406Sopenharmony_ci  (void) handle;		/* silence gcc */
960141cc406Sopenharmony_ci  (void) fd;			/* silence gcc */
961141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
962141cc406Sopenharmony_ci}
963