1141cc406Sopenharmony_ci/* SANE - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
4141cc406Sopenharmony_ci   Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
5141cc406Sopenharmony_ci   Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
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   As a special exception, the authors of SANE give permission for
23141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
24141cc406Sopenharmony_ci
25141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
26141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
27141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
28141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
29141cc406Sopenharmony_ci   account of linking the SANE library code into it.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
32141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
33141cc406Sopenharmony_ci   License.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
36141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
37141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
40141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
41141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
42141cc406Sopenharmony_ci */
43141cc406Sopenharmony_ci#include "../include/sane/config.h"
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci#include <errno.h>
46141cc406Sopenharmony_ci#include <string.h>
47141cc406Sopenharmony_ci#include <stdlib.h>
48141cc406Sopenharmony_ci#ifdef USE_PTHREAD
49141cc406Sopenharmony_ci# include <pthread.h>
50141cc406Sopenharmony_ci#endif
51141cc406Sopenharmony_ci#include <signal.h>		/* sigaction(POSIX) */
52141cc406Sopenharmony_ci#include <unistd.h>		/* POSIX: write read close pipe */
53141cc406Sopenharmony_ci#ifdef HAVE_FCNTL_H
54141cc406Sopenharmony_ci# include <fcntl.h>
55141cc406Sopenharmony_ci#endif
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci#include "pixma_rename.h"
58141cc406Sopenharmony_ci#include "pixma.h"
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci# define DEBUG_NOT_STATIC
61141cc406Sopenharmony_ci# include "../include/sane/sane.h"
62141cc406Sopenharmony_ci# include "../include/sane/sanei.h"
63141cc406Sopenharmony_ci# include "../include/sane/saneopts.h"
64141cc406Sopenharmony_ci# include "../include/sane/sanei_thread.h"
65141cc406Sopenharmony_ci# include "../include/sane/sanei_backend.h"
66141cc406Sopenharmony_ci# include "../include/sane/sanei_config.h"
67141cc406Sopenharmony_ci# include "../include/sane/sanei_jpeg.h"
68141cc406Sopenharmony_ci# include "../include/sane/sanei_usb.h"
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#ifdef NDEBUG
71141cc406Sopenharmony_ci# define PDBG(x)
72141cc406Sopenharmony_ci#else
73141cc406Sopenharmony_ci#  define PDBG(x) IF_DBG(x)
74141cc406Sopenharmony_ci#endif /* NDEBUG */
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#ifdef __GNUC__
77141cc406Sopenharmony_ci# define UNUSED(v) (void) v
78141cc406Sopenharmony_ci#else
79141cc406Sopenharmony_ci# define UNUSED(v)
80141cc406Sopenharmony_ci#endif
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci#define DECL_CTX pixma_sane_t *ss = check_handle(h)
83141cc406Sopenharmony_ci#define OPT_IN_CTX ss->opt
84141cc406Sopenharmony_ci#define SOD(opt)  OPT_IN_CTX[opt].sod
85141cc406Sopenharmony_ci#define OVAL(opt) OPT_IN_CTX[opt].val
86141cc406Sopenharmony_ci#define AUTO_GAMMA 2.2
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci/* pixma_sane_options.h generated by
89141cc406Sopenharmony_ci * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h
90141cc406Sopenharmony_ci */
91141cc406Sopenharmony_ci#include "pixma_sane_options.h"
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci#define BUTTON_GROUP_SIZE ( opt_adf_orientation - opt_button_1 + 1 )
94141cc406Sopenharmony_ci#define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 )
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_citypedef struct pixma_sane_t
97141cc406Sopenharmony_ci{
98141cc406Sopenharmony_ci  struct pixma_sane_t *next;
99141cc406Sopenharmony_ci  pixma_t *s;
100141cc406Sopenharmony_ci  pixma_scan_param_t sp;
101141cc406Sopenharmony_ci  SANE_Bool cancel;
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci  /* valid states: idle, !idle && scanning, !idle && !scanning */
104141cc406Sopenharmony_ci  SANE_Bool idle;
105141cc406Sopenharmony_ci  SANE_Bool scanning;
106141cc406Sopenharmony_ci  SANE_Status last_read_status;	/* valid if !idle && !scanning */
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_ci  option_descriptor_t opt[opt_last];
109141cc406Sopenharmony_ci  char button_option_is_cached[BUTTON_GROUP_SIZE];
110141cc406Sopenharmony_ci  SANE_Range xrange, yrange;
111141cc406Sopenharmony_ci  SANE_Word dpi_list[9];	/* up to 9600 dpi */
112141cc406Sopenharmony_ci  SANE_String_Const mode_list[6];
113141cc406Sopenharmony_ci  pixma_scan_mode_t mode_map[6];
114141cc406Sopenharmony_ci  uint8_t gamma_table[4096];
115141cc406Sopenharmony_ci  SANE_String_Const source_list[4];
116141cc406Sopenharmony_ci  pixma_paper_source_t source_map[4];
117141cc406Sopenharmony_ci  SANE_String_Const calibrate_list[PIXMA_CALIBRATE_NUM_OPTS + 1];
118141cc406Sopenharmony_ci  pixma_calibrate_option_t calibrate_map[PIXMA_CALIBRATE_NUM_OPTS + 1];
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci  unsigned byte_pos_in_line, output_line_size;
121141cc406Sopenharmony_ci  uint64_t image_bytes_read;
122141cc406Sopenharmony_ci  unsigned page_count;		/* valid for ADF */
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_ci  SANE_Pid reader_taskid;
125141cc406Sopenharmony_ci  int wpipe, rpipe;
126141cc406Sopenharmony_ci  SANE_Bool reader_stop;
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_ci  /* Valid for JPEG source */
129141cc406Sopenharmony_ci  djpeg_dest_ptr jdst;
130141cc406Sopenharmony_ci  struct jpeg_decompress_struct jpeg_cinfo;
131141cc406Sopenharmony_ci  struct jpeg_error_mgr jpeg_err;
132141cc406Sopenharmony_ci  SANE_Bool jpeg_header_seen;
133141cc406Sopenharmony_ci} pixma_sane_t;
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_citypedef struct
136141cc406Sopenharmony_ci{
137141cc406Sopenharmony_ci  struct jpeg_source_mgr jpeg;
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci  pixma_sane_t *s;
140141cc406Sopenharmony_ci  JOCTET *buffer;
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci  SANE_Byte *linebuffer;
143141cc406Sopenharmony_ci  SANE_Int linebuffer_size;
144141cc406Sopenharmony_ci  SANE_Int linebuffer_index;
145141cc406Sopenharmony_ci} pixma_jpeg_src_mgr;
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_cistatic const char vendor_str[] = "CANON";
149141cc406Sopenharmony_cistatic const char type_str[] = "multi-function peripheral";
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_cistatic pixma_sane_t *first_scanner = NULL;
152141cc406Sopenharmony_cistatic const SANE_Device **dev_list = NULL;
153141cc406Sopenharmony_cistatic const char* conf_devices[MAX_CONF_DEVICES];
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_cistatic void mark_all_button_options_cached ( struct pixma_sane_t * ss )
156141cc406Sopenharmony_ci{
157141cc406Sopenharmony_ci  int i;
158141cc406Sopenharmony_ci  for (i = 0; i < (opt__group_5 - opt_button_1); i++ )
159141cc406Sopenharmony_ci      ss -> button_option_is_cached[i] = 1;
160141cc406Sopenharmony_ci}
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_cistatic SANE_Status config_attach_pixma(SANEI_Config __sane_unused__ * config,
163141cc406Sopenharmony_ci				       const char *devname,
164141cc406Sopenharmony_ci				       void __sane_unused__ *data)
165141cc406Sopenharmony_ci{
166141cc406Sopenharmony_ci  int i;
167141cc406Sopenharmony_ci  for (i=0; i < (MAX_CONF_DEVICES -1); i++)
168141cc406Sopenharmony_ci    {
169141cc406Sopenharmony_ci      if(conf_devices[i] == NULL)
170141cc406Sopenharmony_ci        {
171141cc406Sopenharmony_ci          conf_devices[i] = strdup(devname);
172141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
173141cc406Sopenharmony_ci        }
174141cc406Sopenharmony_ci    }
175141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
176141cc406Sopenharmony_ci}
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_cistatic SANE_Status
179141cc406Sopenharmony_cimap_error (int error)
180141cc406Sopenharmony_ci{
181141cc406Sopenharmony_ci  if (error >= 0)
182141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci  switch (error)
185141cc406Sopenharmony_ci    {
186141cc406Sopenharmony_ci    case PIXMA_ENOMEM:
187141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
188141cc406Sopenharmony_ci    case PIXMA_ECANCELED:
189141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
190141cc406Sopenharmony_ci    case PIXMA_EBUSY:
191141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
192141cc406Sopenharmony_ci    case PIXMA_EINVAL:
193141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
194141cc406Sopenharmony_ci    case PIXMA_EACCES:
195141cc406Sopenharmony_ci      return SANE_STATUS_ACCESS_DENIED;
196141cc406Sopenharmony_ci    case PIXMA_EPAPER_JAMMED:
197141cc406Sopenharmony_ci      return SANE_STATUS_JAMMED;
198141cc406Sopenharmony_ci    case PIXMA_ENO_PAPER:
199141cc406Sopenharmony_ci      return SANE_STATUS_NO_DOCS;
200141cc406Sopenharmony_ci    case PIXMA_ECOVER_OPEN:
201141cc406Sopenharmony_ci      return SANE_STATUS_COVER_OPEN;
202141cc406Sopenharmony_ci    case PIXMA_ENOTSUP:
203141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
204141cc406Sopenharmony_ci    case PIXMA_EPROTO:
205141cc406Sopenharmony_ci    case PIXMA_ENODEV:
206141cc406Sopenharmony_ci    case PIXMA_EIO:
207141cc406Sopenharmony_ci    case PIXMA_ETIMEDOUT:
208141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
209141cc406Sopenharmony_ci    }
210141cc406Sopenharmony_ci  PDBG (pixma_dbg (1, "BUG: unmapped error %d\n", error));
211141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
212141cc406Sopenharmony_ci}
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_cistatic int
215141cc406Sopenharmony_cigetenv_atoi (const char *name, int def)
216141cc406Sopenharmony_ci{
217141cc406Sopenharmony_ci  const char *str = getenv (name);
218141cc406Sopenharmony_ci  return (str) ? atoi (str) : def;
219141cc406Sopenharmony_ci}
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci#define CONST_CAST(t,x) (t)(x)
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_cistatic void
224141cc406Sopenharmony_cifree_block (const void * ptr)
225141cc406Sopenharmony_ci{
226141cc406Sopenharmony_ci  free (CONST_CAST (void *, ptr));
227141cc406Sopenharmony_ci}
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_cistatic void
230141cc406Sopenharmony_cicleanup_device_list (void)
231141cc406Sopenharmony_ci{
232141cc406Sopenharmony_ci  if (dev_list)
233141cc406Sopenharmony_ci    {
234141cc406Sopenharmony_ci      int i;
235141cc406Sopenharmony_ci      for (i = 0; dev_list[i]; i++)
236141cc406Sopenharmony_ci        {
237141cc406Sopenharmony_ci          free_block ((const void *) dev_list[i]->name);
238141cc406Sopenharmony_ci          free_block ((const void *) dev_list[i]->model);
239141cc406Sopenharmony_ci          free_block ((const void *) dev_list[i]);
240141cc406Sopenharmony_ci        }
241141cc406Sopenharmony_ci    }
242141cc406Sopenharmony_ci  free (dev_list);
243141cc406Sopenharmony_ci  dev_list = NULL;
244141cc406Sopenharmony_ci}
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_cistatic void
247141cc406Sopenharmony_cifind_scanners (SANE_Bool local_only)
248141cc406Sopenharmony_ci{
249141cc406Sopenharmony_ci  unsigned i, nscanners;
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci  cleanup_device_list ();
252141cc406Sopenharmony_ci  nscanners = pixma_find_scanners (conf_devices, local_only);
253141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "pixma_find_scanners() found %u devices\n", nscanners));
254141cc406Sopenharmony_ci  dev_list =
255141cc406Sopenharmony_ci    (const SANE_Device **) calloc (nscanners + 1, sizeof (*dev_list));
256141cc406Sopenharmony_ci  if (!dev_list)
257141cc406Sopenharmony_ci    return;
258141cc406Sopenharmony_ci  for (i = 0; i != nscanners; i++)
259141cc406Sopenharmony_ci    {
260141cc406Sopenharmony_ci      SANE_Device *sdev = (SANE_Device *) calloc (1, sizeof (*sdev));
261141cc406Sopenharmony_ci      char *name, *model;
262141cc406Sopenharmony_ci      if (!sdev)
263141cc406Sopenharmony_ci        goto nomem;
264141cc406Sopenharmony_ci      name = strdup (pixma_get_device_id (i));
265141cc406Sopenharmony_ci      model = strdup (pixma_get_device_model (i));
266141cc406Sopenharmony_ci      if (!name || !model)
267141cc406Sopenharmony_ci        {
268141cc406Sopenharmony_ci          free (name);
269141cc406Sopenharmony_ci          free (model);
270141cc406Sopenharmony_ci          free (sdev);
271141cc406Sopenharmony_ci          goto nomem;
272141cc406Sopenharmony_ci        }
273141cc406Sopenharmony_ci      sdev->name = name;
274141cc406Sopenharmony_ci      sdev->model = model;
275141cc406Sopenharmony_ci      sdev->vendor = vendor_str;
276141cc406Sopenharmony_ci      sdev->type = type_str;
277141cc406Sopenharmony_ci      dev_list[i] = sdev;
278141cc406Sopenharmony_ci    }
279141cc406Sopenharmony_ci  /* dev_list is already NULL terminated by calloc(). */
280141cc406Sopenharmony_ci  return;
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_cinomem:
283141cc406Sopenharmony_ci  PDBG (pixma_dbg (1, "WARNING:not enough memory for device list\n"));
284141cc406Sopenharmony_ci  return;
285141cc406Sopenharmony_ci}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_cistatic pixma_sane_t *
288141cc406Sopenharmony_cicheck_handle (SANE_Handle h)
289141cc406Sopenharmony_ci{
290141cc406Sopenharmony_ci  pixma_sane_t *p;
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci  for (p = first_scanner; p && (SANE_Handle) p != h; p = p->next)
293141cc406Sopenharmony_ci    {
294141cc406Sopenharmony_ci    }
295141cc406Sopenharmony_ci  return p;
296141cc406Sopenharmony_ci}
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_cistatic void
299141cc406Sopenharmony_ciupdate_button_state (pixma_sane_t * ss, SANE_Int * info)
300141cc406Sopenharmony_ci{
301141cc406Sopenharmony_ci  SANE_Int b1 = OVAL (opt_button_1).w;
302141cc406Sopenharmony_ci  SANE_Int b2 = OVAL (opt_button_2).w;
303141cc406Sopenharmony_ci  uint32_t ev = pixma_wait_event (ss->s, 300);
304141cc406Sopenharmony_ci  switch (ev & ~PIXMA_EV_ACTION_MASK)
305141cc406Sopenharmony_ci    {
306141cc406Sopenharmony_ci    case PIXMA_EV_BUTTON1:
307141cc406Sopenharmony_ci      b1 = 1;
308141cc406Sopenharmony_ci      break;
309141cc406Sopenharmony_ci    case PIXMA_EV_BUTTON2:
310141cc406Sopenharmony_ci      b2 = 1;
311141cc406Sopenharmony_ci      break;
312141cc406Sopenharmony_ci    }
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci  if (b1 != OVAL (opt_button_1).w || b2 != OVAL (opt_button_2).w)
315141cc406Sopenharmony_ci    {
316141cc406Sopenharmony_ci    *info |= SANE_INFO_RELOAD_OPTIONS;
317141cc406Sopenharmony_ci    OVAL (opt_button_1).w = b1;
318141cc406Sopenharmony_ci    OVAL (opt_button_2).w = b2;
319141cc406Sopenharmony_ci    OVAL (opt_original).w = GET_EV_ORIGINAL(ev);
320141cc406Sopenharmony_ci    OVAL (opt_target).w = GET_EV_TARGET(ev);
321141cc406Sopenharmony_ci    OVAL (opt_scan_resolution).w = GET_EV_DPI(ev);
322141cc406Sopenharmony_ci    OVAL (opt_document_type).w = GET_EV_DOC(ev);
323141cc406Sopenharmony_ci    OVAL (opt_adf_status).w = GET_EV_STAT(ev);
324141cc406Sopenharmony_ci    OVAL (opt_adf_orientation).w = GET_EV_ORIENT(ev);
325141cc406Sopenharmony_ci    }
326141cc406Sopenharmony_ci  mark_all_button_options_cached(ss);
327141cc406Sopenharmony_ci}
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_cistatic SANE_Bool
330141cc406Sopenharmony_cienable_option (pixma_sane_t * ss, SANE_Int o, SANE_Bool enable)
331141cc406Sopenharmony_ci{
332141cc406Sopenharmony_ci  SANE_Word save = SOD (o).cap;
333141cc406Sopenharmony_ci  if (enable)
334141cc406Sopenharmony_ci    SOD (o).cap &= ~SANE_CAP_INACTIVE;
335141cc406Sopenharmony_ci  else
336141cc406Sopenharmony_ci    SOD (o).cap |= SANE_CAP_INACTIVE;
337141cc406Sopenharmony_ci  return (save != SOD (o).cap);
338141cc406Sopenharmony_ci}
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_cistatic void
341141cc406Sopenharmony_ciclamp_value (pixma_sane_t * ss, SANE_Int n, void *v, SANE_Int * info)
342141cc406Sopenharmony_ci{
343141cc406Sopenharmony_ci  SANE_Option_Descriptor *sod = &SOD (n);
344141cc406Sopenharmony_ci  SANE_Word *va = (SANE_Word *) v;
345141cc406Sopenharmony_ci  const SANE_Range *range = sod->constraint.range;
346141cc406Sopenharmony_ci  int i, nmemb;
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  nmemb = sod->size / sizeof (SANE_Word);
349141cc406Sopenharmony_ci  for (i = 0; i < nmemb; i++)
350141cc406Sopenharmony_ci    {
351141cc406Sopenharmony_ci      SANE_Word value = va[i];
352141cc406Sopenharmony_ci      if (value < range->min)
353141cc406Sopenharmony_ci        {
354141cc406Sopenharmony_ci          value = range->min;
355141cc406Sopenharmony_ci        }
356141cc406Sopenharmony_ci      else if (value > range->max)
357141cc406Sopenharmony_ci        {
358141cc406Sopenharmony_ci          value = range->max;
359141cc406Sopenharmony_ci        }
360141cc406Sopenharmony_ci      if (range->quant != 0)
361141cc406Sopenharmony_ci        {
362141cc406Sopenharmony_ci          value = (value - range->min + range->quant / 2) /
363141cc406Sopenharmony_ci            range->quant * range->quant;
364141cc406Sopenharmony_ci        }
365141cc406Sopenharmony_ci      if (value != va[i])
366141cc406Sopenharmony_ci        {
367141cc406Sopenharmony_ci          va[i] = value;
368141cc406Sopenharmony_ci          *info |= SANE_INFO_INEXACT;
369141cc406Sopenharmony_ci        }
370141cc406Sopenharmony_ci    }
371141cc406Sopenharmony_ci}
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci/* create dynamic mode_list
374141cc406Sopenharmony_ci * ss:      scanner device
375141cc406Sopenharmony_ci * tpu = 0: flatbed or ADF mode
376141cc406Sopenharmony_ci *          1 bit lineart, 8 bit grayscale and 24 bit color scans
377141cc406Sopenharmony_ci * tpu = 1: TPU mode
378141cc406Sopenharmony_ci *          16 bit grayscale and 48 bit color scans */
379141cc406Sopenharmony_cistatic void
380141cc406Sopenharmony_cicreate_mode_list (pixma_sane_t * ss)
381141cc406Sopenharmony_ci{
382141cc406Sopenharmony_ci  SANE_Bool tpu;
383141cc406Sopenharmony_ci  const pixma_config_t *cfg;
384141cc406Sopenharmony_ci  int i;
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  cfg = pixma_get_config (ss->s);
387141cc406Sopenharmony_ci  tpu = (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU);
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci  /* setup available mode */
390141cc406Sopenharmony_ci  i = 0;
391141cc406Sopenharmony_ci  ss->mode_list[i] = SANE_VALUE_SCAN_MODE_COLOR;
392141cc406Sopenharmony_ci  ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR;
393141cc406Sopenharmony_ci  i++;
394141cc406Sopenharmony_ci  if (cfg->cap & PIXMA_CAP_GRAY)
395141cc406Sopenharmony_ci    {
396141cc406Sopenharmony_ci      ss->mode_list[i] = SANE_VALUE_SCAN_MODE_GRAY;
397141cc406Sopenharmony_ci      ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY;
398141cc406Sopenharmony_ci      i++;
399141cc406Sopenharmony_ci    }
400141cc406Sopenharmony_ci  if (tpu && (cfg->cap & PIXMA_CAP_NEGATIVE))
401141cc406Sopenharmony_ci    {
402141cc406Sopenharmony_ci      ss->mode_list[i] = SANE_I18N ("Negative color");
403141cc406Sopenharmony_ci      ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_COLOR;
404141cc406Sopenharmony_ci      i++;
405141cc406Sopenharmony_ci      if (cfg->cap & PIXMA_CAP_GRAY)
406141cc406Sopenharmony_ci        {
407141cc406Sopenharmony_ci          ss->mode_list[i] = SANE_I18N ("Negative gray");
408141cc406Sopenharmony_ci          ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_GRAY;
409141cc406Sopenharmony_ci          i++;
410141cc406Sopenharmony_ci        }
411141cc406Sopenharmony_ci    }
412141cc406Sopenharmony_ci  if (tpu && (cfg->cap & PIXMA_CAP_TPUIR) == PIXMA_CAP_TPUIR)
413141cc406Sopenharmony_ci    {
414141cc406Sopenharmony_ci      ss->mode_list[i] = SANE_I18N ("Infrared");
415141cc406Sopenharmony_ci      ss->mode_map[i] = PIXMA_SCAN_MODE_TPUIR;
416141cc406Sopenharmony_ci      i++;
417141cc406Sopenharmony_ci    }
418141cc406Sopenharmony_ci  if (!tpu && (cfg->cap & PIXMA_CAP_48BIT))
419141cc406Sopenharmony_ci    {
420141cc406Sopenharmony_ci      ss->mode_list[i] = SANE_I18N ("48 bits color");
421141cc406Sopenharmony_ci      ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR_48;
422141cc406Sopenharmony_ci      i++;
423141cc406Sopenharmony_ci      if (cfg->cap & PIXMA_CAP_GRAY)
424141cc406Sopenharmony_ci        {
425141cc406Sopenharmony_ci          ss->mode_list[i] = SANE_I18N ("16 bits gray");
426141cc406Sopenharmony_ci          ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY_16;
427141cc406Sopenharmony_ci          i++;
428141cc406Sopenharmony_ci        }
429141cc406Sopenharmony_ci    }
430141cc406Sopenharmony_ci  if (!tpu && (cfg->cap & PIXMA_CAP_LINEART))
431141cc406Sopenharmony_ci    {
432141cc406Sopenharmony_ci      ss->mode_list[i] = SANE_VALUE_SCAN_MODE_LINEART;
433141cc406Sopenharmony_ci      ss->mode_map[i] = PIXMA_SCAN_MODE_LINEART;
434141cc406Sopenharmony_ci      i++;
435141cc406Sopenharmony_ci    }
436141cc406Sopenharmony_ci  /* terminate mode_list and mode_map */
437141cc406Sopenharmony_ci  ss->mode_list[i] = 0;
438141cc406Sopenharmony_ci  ss->mode_map[i] = 0;
439141cc406Sopenharmony_ci}
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci/* create dynamic dpi_list
442141cc406Sopenharmony_ci * ss: scanner device */
443141cc406Sopenharmony_cistatic void
444141cc406Sopenharmony_cicreate_dpi_list (pixma_sane_t * ss)
445141cc406Sopenharmony_ci{
446141cc406Sopenharmony_ci  const pixma_config_t *cfg;
447141cc406Sopenharmony_ci  int i, j;
448141cc406Sopenharmony_ci  int min;
449141cc406Sopenharmony_ci  unsigned min_dpi;
450141cc406Sopenharmony_ci  unsigned max_dpi;
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  cfg = pixma_get_config (ss->s);
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci  /* get min/max dpi */
455141cc406Sopenharmony_ci  max_dpi = cfg->xdpi;
456141cc406Sopenharmony_ci  min_dpi = 75;
457141cc406Sopenharmony_ci  if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU
458141cc406Sopenharmony_ci      && ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_TPUIR)
459141cc406Sopenharmony_ci  { /* IR mode */
460141cc406Sopenharmony_ci    /*PDBG (pixma_dbg (4, "*create_dpi_list***** TPUIR mode\n"));*/
461141cc406Sopenharmony_ci    min_dpi = (cfg->tpuir_min_dpi) ? cfg->tpuir_min_dpi : 75;
462141cc406Sopenharmony_ci    max_dpi = (cfg->tpuir_max_dpi) ? cfg->tpuir_max_dpi : cfg->xdpi;
463141cc406Sopenharmony_ci  }
464141cc406Sopenharmony_ci  else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU
465141cc406Sopenharmony_ci            || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADF
466141cc406Sopenharmony_ci            || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADFDUP)
467141cc406Sopenharmony_ci  { /* ADF / TPU mode */
468141cc406Sopenharmony_ci    /*PDBG (pixma_dbg (4, "*create_dpi_list***** ADF/TPU mode\n"));*/
469141cc406Sopenharmony_ci    min_dpi = (cfg->adftpu_min_dpi) ? cfg->adftpu_min_dpi : 75;
470141cc406Sopenharmony_ci    max_dpi = (cfg->adftpu_max_dpi) ? cfg->adftpu_max_dpi : cfg->xdpi;
471141cc406Sopenharmony_ci  }
472141cc406Sopenharmony_ci  else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED
473141cc406Sopenharmony_ci            && (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_COLOR_48
474141cc406Sopenharmony_ci                || ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_GRAY_16))
475141cc406Sopenharmony_ci  { /* 48 bits flatbed */
476141cc406Sopenharmony_ci    /*PDBG (pixma_dbg (4, "*create_dpi_list***** 48 bits flatbed mode\n"));*/
477141cc406Sopenharmony_ci    min_dpi = (cfg->min_xdpi_16) ? cfg->min_xdpi_16 : 75;
478141cc406Sopenharmony_ci  }
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci  /* set j for min. dpi
481141cc406Sopenharmony_ci   *  75 dpi: j = 0
482141cc406Sopenharmony_ci   * 150 dpi: j = 1 \
483141cc406Sopenharmony_ci   * 300 dpi: j = 2 |--> from cfg->adftpu_min_dpi or cfg->tpuir_min_dpi
484141cc406Sopenharmony_ci   * 600 dpi: j = 3 /
485141cc406Sopenharmony_ci   * */
486141cc406Sopenharmony_ci  j = -1;
487141cc406Sopenharmony_ci  min = min_dpi / 75;
488141cc406Sopenharmony_ci  do
489141cc406Sopenharmony_ci  {
490141cc406Sopenharmony_ci    j++;
491141cc406Sopenharmony_ci    min >>= 1;
492141cc406Sopenharmony_ci  }
493141cc406Sopenharmony_ci  while (min > 0);
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci  /* create dpi_list
496141cc406Sopenharmony_ci   * use j for min. dpi */
497141cc406Sopenharmony_ci  i = 0;
498141cc406Sopenharmony_ci  do
499141cc406Sopenharmony_ci    {
500141cc406Sopenharmony_ci      i++; j++;
501141cc406Sopenharmony_ci      ss->dpi_list[i] = 75 * (1 << (j - 1));    /* 75 x 2^(j-1) */
502141cc406Sopenharmony_ci    }
503141cc406Sopenharmony_ci  while ((unsigned) ss->dpi_list[i] < max_dpi);
504141cc406Sopenharmony_ci  ss->dpi_list[0] = i;
505141cc406Sopenharmony_ci  /*PDBG (pixma_dbg (4, "*create_dpi_list***** min_dpi = %d, max_dpi = %d\n", min_dpi, max_dpi));*/
506141cc406Sopenharmony_ci}
507141cc406Sopenharmony_ci
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_cistatic void
510141cc406Sopenharmony_cicreate_calibrate_list (pixma_sane_t * ss)
511141cc406Sopenharmony_ci{
512141cc406Sopenharmony_ci  int i = 0;
513141cc406Sopenharmony_ci  ss->calibrate_list[i] = SANE_I18N ("Once");
514141cc406Sopenharmony_ci  ss->calibrate_map[i] = PIXMA_CALIBRATE_ONCE;
515141cc406Sopenharmony_ci  i++;
516141cc406Sopenharmony_ci  ss->calibrate_list[i] = SANE_I18N ("Always");
517141cc406Sopenharmony_ci  ss->calibrate_map[i] = PIXMA_CALIBRATE_ALWAYS;
518141cc406Sopenharmony_ci  i++;
519141cc406Sopenharmony_ci  ss->calibrate_list[i] = SANE_I18N ("Never");
520141cc406Sopenharmony_ci  ss->calibrate_map[i] = PIXMA_CALIBRATE_NEVER;
521141cc406Sopenharmony_ci  i++;
522141cc406Sopenharmony_ci}
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_cistatic void
525141cc406Sopenharmony_ciselect_value_from_list (pixma_sane_t * ss, SANE_Int n, void *v,
526141cc406Sopenharmony_ci			SANE_Int * info)
527141cc406Sopenharmony_ci{
528141cc406Sopenharmony_ci  SANE_Option_Descriptor *sod = &SOD (n);
529141cc406Sopenharmony_ci  SANE_Word *va = (SANE_Word *) v;
530141cc406Sopenharmony_ci  const SANE_Word *list = sod->constraint.word_list;
531141cc406Sopenharmony_ci  int i, j, nmemb;
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  nmemb = sod->size / sizeof (SANE_Word);
534141cc406Sopenharmony_ci  for (i = 0; i < nmemb; i++)
535141cc406Sopenharmony_ci    {
536141cc406Sopenharmony_ci      SANE_Word value = va[i];
537141cc406Sopenharmony_ci      SANE_Word mindelta = abs (value - list[1]);
538141cc406Sopenharmony_ci      SANE_Word nearest = list[1];
539141cc406Sopenharmony_ci      for (j = 2; j <= list[0]; j++)
540141cc406Sopenharmony_ci        {
541141cc406Sopenharmony_ci          SANE_Word delta = abs (value - list[j]);
542141cc406Sopenharmony_ci          if (delta < mindelta)
543141cc406Sopenharmony_ci            {
544141cc406Sopenharmony_ci              mindelta = delta;
545141cc406Sopenharmony_ci              nearest = list[j];
546141cc406Sopenharmony_ci            }
547141cc406Sopenharmony_ci          if (mindelta == 0)
548141cc406Sopenharmony_ci            break;
549141cc406Sopenharmony_ci        }
550141cc406Sopenharmony_ci      if (va[i] != nearest)
551141cc406Sopenharmony_ci        {
552141cc406Sopenharmony_ci          va[i] = nearest;
553141cc406Sopenharmony_ci          *info |= SANE_INFO_INEXACT;
554141cc406Sopenharmony_ci        }
555141cc406Sopenharmony_ci    }
556141cc406Sopenharmony_ci}
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_cistatic SANE_Status
559141cc406Sopenharmony_cicontrol_scalar_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
560141cc406Sopenharmony_ci		       SANE_Int * info)
561141cc406Sopenharmony_ci{
562141cc406Sopenharmony_ci  option_descriptor_t *opt = &(OPT_IN_CTX[n]);
563141cc406Sopenharmony_ci  SANE_Word val;
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci  /* PDBG (pixma_dbg (4, "*control_scalar_option***** n = %u, a = %u\n", n, a)); */
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci  switch (a)
568141cc406Sopenharmony_ci    {
569141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
570141cc406Sopenharmony_ci      switch (opt->sod.type)
571141cc406Sopenharmony_ci        {
572141cc406Sopenharmony_ci        case SANE_TYPE_BOOL:
573141cc406Sopenharmony_ci        case SANE_TYPE_INT:
574141cc406Sopenharmony_ci        case SANE_TYPE_FIXED:
575141cc406Sopenharmony_ci          *(SANE_Word *) v = opt->val.w;
576141cc406Sopenharmony_ci          break;
577141cc406Sopenharmony_ci        default:
578141cc406Sopenharmony_ci          return SANE_STATUS_UNSUPPORTED;
579141cc406Sopenharmony_ci        }
580141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
583141cc406Sopenharmony_ci      switch (opt->sod.type)
584141cc406Sopenharmony_ci        {
585141cc406Sopenharmony_ci        case SANE_TYPE_BOOL:
586141cc406Sopenharmony_ci          val = *(SANE_Word *) v;
587141cc406Sopenharmony_ci          if (val != SANE_TRUE && val != SANE_FALSE)
588141cc406Sopenharmony_ci            return SANE_STATUS_INVAL;
589141cc406Sopenharmony_ci          opt->val.w = val;
590141cc406Sopenharmony_ci          break;
591141cc406Sopenharmony_ci        case SANE_TYPE_INT:
592141cc406Sopenharmony_ci        case SANE_TYPE_FIXED:
593141cc406Sopenharmony_ci          if (opt->sod.constraint_type == SANE_CONSTRAINT_RANGE)
594141cc406Sopenharmony_ci            clamp_value (ss, n, v, info);
595141cc406Sopenharmony_ci          else if (opt->sod.constraint_type == SANE_CONSTRAINT_WORD_LIST)
596141cc406Sopenharmony_ci            select_value_from_list (ss, n, v, info);
597141cc406Sopenharmony_ci          opt->val.w = *(SANE_Word *) v;
598141cc406Sopenharmony_ci          break;
599141cc406Sopenharmony_ci        default:
600141cc406Sopenharmony_ci          return SANE_STATUS_UNSUPPORTED;
601141cc406Sopenharmony_ci        }
602141cc406Sopenharmony_ci      *info |= opt->info;
603141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
606141cc406Sopenharmony_ci      switch (opt->sod.type)
607141cc406Sopenharmony_ci        {
608141cc406Sopenharmony_ci        case SANE_TYPE_BOOL:
609141cc406Sopenharmony_ci        case SANE_TYPE_INT:
610141cc406Sopenharmony_ci        case SANE_TYPE_FIXED:
611141cc406Sopenharmony_ci          opt->val.w = opt->def.w;
612141cc406Sopenharmony_ci          break;
613141cc406Sopenharmony_ci        default:
614141cc406Sopenharmony_ci          return SANE_STATUS_UNSUPPORTED;
615141cc406Sopenharmony_ci        }
616141cc406Sopenharmony_ci      *info |= opt->info;
617141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
618141cc406Sopenharmony_ci    }
619141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
620141cc406Sopenharmony_ci}
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_cistatic SANE_Status
623141cc406Sopenharmony_cicontrol_string_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
624141cc406Sopenharmony_ci		       SANE_Int * info)
625141cc406Sopenharmony_ci{
626141cc406Sopenharmony_ci  option_descriptor_t *opt = &(OPT_IN_CTX[n]);
627141cc406Sopenharmony_ci  const SANE_String_Const *slist = opt->sod.constraint.string_list;
628141cc406Sopenharmony_ci  SANE_String str = (SANE_String) v;
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci  /* PDBG (pixma_dbg (4, "*control_string_option***** n = %u, a = %u\n", n, a)); */
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci  if (opt->sod.constraint_type == SANE_CONSTRAINT_NONE)
633141cc406Sopenharmony_ci    {
634141cc406Sopenharmony_ci      switch (a)
635141cc406Sopenharmony_ci        {
636141cc406Sopenharmony_ci        case SANE_ACTION_GET_VALUE:
637141cc406Sopenharmony_ci          strcpy (str, opt->val.s);
638141cc406Sopenharmony_ci          break;
639141cc406Sopenharmony_ci        case SANE_ACTION_SET_AUTO:
640141cc406Sopenharmony_ci          str = opt->def.s;
641141cc406Sopenharmony_ci          /* fall through */
642141cc406Sopenharmony_ci        case SANE_ACTION_SET_VALUE:
643141cc406Sopenharmony_ci          strncpy (opt->val.s, str, opt->sod.size - 1);
644141cc406Sopenharmony_ci          *info |= opt->info;
645141cc406Sopenharmony_ci          break;
646141cc406Sopenharmony_ci        }
647141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
648141cc406Sopenharmony_ci    }
649141cc406Sopenharmony_ci  else
650141cc406Sopenharmony_ci    {
651141cc406Sopenharmony_ci      int i;
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci      switch (a)
654141cc406Sopenharmony_ci        {
655141cc406Sopenharmony_ci        case SANE_ACTION_GET_VALUE:
656141cc406Sopenharmony_ci          strcpy (str, slist[opt->val.w]);
657141cc406Sopenharmony_ci          break;
658141cc406Sopenharmony_ci        case SANE_ACTION_SET_AUTO:
659141cc406Sopenharmony_ci          str = opt->def.ptr;
660141cc406Sopenharmony_ci          /* fall through */
661141cc406Sopenharmony_ci        case SANE_ACTION_SET_VALUE:
662141cc406Sopenharmony_ci          i = 0;
663141cc406Sopenharmony_ci          while (slist[i] && strcasecmp (str, slist[i]) != 0)
664141cc406Sopenharmony_ci            i++;
665141cc406Sopenharmony_ci          if (!slist[i])
666141cc406Sopenharmony_ci            return SANE_STATUS_INVAL;
667141cc406Sopenharmony_ci          if (strcmp (slist[i], str) != 0)
668141cc406Sopenharmony_ci            {
669141cc406Sopenharmony_ci              strcpy (str, slist[i]);
670141cc406Sopenharmony_ci              *info |= SANE_INFO_INEXACT;
671141cc406Sopenharmony_ci            }
672141cc406Sopenharmony_ci          opt->val.w = i;
673141cc406Sopenharmony_ci          *info |= opt->info;
674141cc406Sopenharmony_ci          break;
675141cc406Sopenharmony_ci        }
676141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
677141cc406Sopenharmony_ci    }
678141cc406Sopenharmony_ci}
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_cistatic SANE_Status
681141cc406Sopenharmony_cicontrol_option (pixma_sane_t * ss, SANE_Int n,
682141cc406Sopenharmony_ci		SANE_Action a, void *v, SANE_Int * info)
683141cc406Sopenharmony_ci{
684141cc406Sopenharmony_ci  SANE_Option_Descriptor *sod = &SOD (n);
685141cc406Sopenharmony_ci  int result, i;
686141cc406Sopenharmony_ci  const pixma_config_t *cfg;
687141cc406Sopenharmony_ci  SANE_Int dummy;
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  /* info may be null, better to set a dummy here then test everywhere */
690141cc406Sopenharmony_ci  if (info == NULL)
691141cc406Sopenharmony_ci    info = &dummy;
692141cc406Sopenharmony_ci
693141cc406Sopenharmony_ci  cfg = pixma_get_config (ss->s);
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci  /* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci  /* first deal with options that require special treatment */
698141cc406Sopenharmony_ci  result = SANE_STATUS_UNSUPPORTED;
699141cc406Sopenharmony_ci  switch (n)
700141cc406Sopenharmony_ci    {
701141cc406Sopenharmony_ci      case opt_gamma_table:
702141cc406Sopenharmony_ci        {
703141cc406Sopenharmony_ci          int table_size = sod->size / sizeof (SANE_Word);
704141cc406Sopenharmony_ci          int byte_cnt = table_size == 1024 ? 2 : 1;
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci          switch (a)
707141cc406Sopenharmony_ci            {
708141cc406Sopenharmony_ci            case SANE_ACTION_SET_VALUE:
709141cc406Sopenharmony_ci              PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_VALUE with %d values ***** \n", table_size));
710141cc406Sopenharmony_ci              clamp_value (ss, n, v, info);
711141cc406Sopenharmony_ci              if (byte_cnt == 1)
712141cc406Sopenharmony_ci                {
713141cc406Sopenharmony_ci                  for (i = 0; i < table_size; i++)
714141cc406Sopenharmony_ci                    ss->gamma_table[i] = *((SANE_Int *) v + i);
715141cc406Sopenharmony_ci                }
716141cc406Sopenharmony_ci              else
717141cc406Sopenharmony_ci                {
718141cc406Sopenharmony_ci                  for (i = 0; i < table_size; i++)
719141cc406Sopenharmony_ci                    {
720141cc406Sopenharmony_ci                      ss->gamma_table[i * 2] = *((SANE_Int *) v + i);
721141cc406Sopenharmony_ci                      ss->gamma_table[i * 2 + 1] = *((uint8_t *)((SANE_Int *) v + i) + 1);
722141cc406Sopenharmony_ci                    }
723141cc406Sopenharmony_ci                }
724141cc406Sopenharmony_ci              /* PDBG (pixma_hexdump (4, (uint8_t *)v, table_size * 4)); */
725141cc406Sopenharmony_ci              /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */
726141cc406Sopenharmony_ci              break;
727141cc406Sopenharmony_ci            case SANE_ACTION_GET_VALUE:
728141cc406Sopenharmony_ci              PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_GET_VALUE ***** \n"));
729141cc406Sopenharmony_ci              if (byte_cnt == 1)
730141cc406Sopenharmony_ci                {
731141cc406Sopenharmony_ci                  for (i = 0; i < table_size; i++)
732141cc406Sopenharmony_ci                    *((SANE_Int *) v + i) = ss->gamma_table[i];
733141cc406Sopenharmony_ci                }
734141cc406Sopenharmony_ci              else
735141cc406Sopenharmony_ci                {
736141cc406Sopenharmony_ci                  for (i = 0; i < table_size; i++)
737141cc406Sopenharmony_ci                    {
738141cc406Sopenharmony_ci                      *((SANE_Int *) v + i) = ss->gamma_table[i * 2];
739141cc406Sopenharmony_ci                      *((uint8_t *)((SANE_Int *) v + i) + 1) = ss->gamma_table[i * 2 + 1];
740141cc406Sopenharmony_ci                    }
741141cc406Sopenharmony_ci                }
742141cc406Sopenharmony_ci              break;
743141cc406Sopenharmony_ci            case SANE_ACTION_SET_AUTO:
744141cc406Sopenharmony_ci              PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_AUTO with gamma=%f ***** \n",
745141cc406Sopenharmony_ci                               SANE_UNFIX (OVAL (opt_gamma).w)));
746141cc406Sopenharmony_ci              pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w),
747141cc406Sopenharmony_ci                                      ss->gamma_table, table_size);
748141cc406Sopenharmony_ci              /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */
749141cc406Sopenharmony_ci              break;
750141cc406Sopenharmony_ci            default:
751141cc406Sopenharmony_ci              return SANE_STATUS_UNSUPPORTED;
752141cc406Sopenharmony_ci            }
753141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
754141cc406Sopenharmony_ci        }
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci      case opt_button_update:
757141cc406Sopenharmony_ci        if (a == SANE_ACTION_SET_VALUE)
758141cc406Sopenharmony_ci          {
759141cc406Sopenharmony_ci            update_button_state (ss, info);
760141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
761141cc406Sopenharmony_ci          }
762141cc406Sopenharmony_ci        else
763141cc406Sopenharmony_ci          {
764141cc406Sopenharmony_ci            return SANE_STATUS_INVAL;
765141cc406Sopenharmony_ci          }
766141cc406Sopenharmony_ci        break;
767141cc406Sopenharmony_ci      case opt_button_1:
768141cc406Sopenharmony_ci      case opt_button_2:
769141cc406Sopenharmony_ci      case opt_original:
770141cc406Sopenharmony_ci      case opt_target:
771141cc406Sopenharmony_ci      case opt_scan_resolution:
772141cc406Sopenharmony_ci      case opt_document_type:
773141cc406Sopenharmony_ci      case opt_adf_status:
774141cc406Sopenharmony_ci      case opt_adf_orientation:
775141cc406Sopenharmony_ci        /* poll scanner if option is not cached */
776141cc406Sopenharmony_ci        if (! ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] )
777141cc406Sopenharmony_ci          update_button_state (ss, info);
778141cc406Sopenharmony_ci        /* mark this option as read */
779141cc406Sopenharmony_ci        ss->button_option_is_cached[  BUTTON_GROUP_INDEX(n) ] = 0;
780141cc406Sopenharmony_ci    }
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci  /* now deal with getting and setting of options */
783141cc406Sopenharmony_ci  switch (SOD (n).type)
784141cc406Sopenharmony_ci    {
785141cc406Sopenharmony_ci    case SANE_TYPE_BOOL:
786141cc406Sopenharmony_ci    case SANE_TYPE_INT:
787141cc406Sopenharmony_ci    case SANE_TYPE_FIXED:
788141cc406Sopenharmony_ci      result = control_scalar_option (ss, n, a, v, info);
789141cc406Sopenharmony_ci      break;
790141cc406Sopenharmony_ci    case SANE_TYPE_STRING:
791141cc406Sopenharmony_ci      result = control_string_option (ss, n, a, v, info);
792141cc406Sopenharmony_ci      break;
793141cc406Sopenharmony_ci    case SANE_TYPE_BUTTON:
794141cc406Sopenharmony_ci    case SANE_TYPE_GROUP:
795141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "BUG:control_option():Unhandled option\n"));
796141cc406Sopenharmony_ci      result = SANE_STATUS_INVAL;
797141cc406Sopenharmony_ci      break;
798141cc406Sopenharmony_ci    }
799141cc406Sopenharmony_ci  if (result != SANE_STATUS_GOOD)
800141cc406Sopenharmony_ci    return result;
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci  /* deal with dependencies between options */
803141cc406Sopenharmony_ci  switch (n)
804141cc406Sopenharmony_ci    {
805141cc406Sopenharmony_ci    case opt_custom_gamma:
806141cc406Sopenharmony_ci      if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)
807141cc406Sopenharmony_ci        {
808141cc406Sopenharmony_ci          if (enable_option (ss, opt_gamma_table, OVAL (opt_custom_gamma).b))
809141cc406Sopenharmony_ci            *info |= SANE_INFO_RELOAD_OPTIONS;
810141cc406Sopenharmony_ci          if (OVAL (opt_custom_gamma).b)
811141cc406Sopenharmony_ci            sane_control_option (ss, opt_gamma_table, SANE_ACTION_SET_AUTO,
812141cc406Sopenharmony_ci                                 NULL, NULL);
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci        }
815141cc406Sopenharmony_ci      break;
816141cc406Sopenharmony_ci    case opt_gamma:
817141cc406Sopenharmony_ci      if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)
818141cc406Sopenharmony_ci        {
819141cc406Sopenharmony_ci          int table_size = SOD (opt_gamma_table).size / sizeof(SANE_Word);
820141cc406Sopenharmony_ci          PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n",
821141cc406Sopenharmony_ci                           SANE_UNFIX (OVAL (opt_gamma).w)));
822141cc406Sopenharmony_ci          PDBG (pixma_dbg (4, "*control_option***** table size = %d *\n",
823141cc406Sopenharmony_ci                           (int)(SOD (opt_gamma_table).size / sizeof (SANE_Word))));
824141cc406Sopenharmony_ci          pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w),
825141cc406Sopenharmony_ci                                  ss->gamma_table, table_size);
826141cc406Sopenharmony_ci          /* PDBG (pixma_hexdump (4, ss->gamma_table,
827141cc406Sopenharmony_ci                               table_size == 1024 ? 2048 : table_size)); */
828141cc406Sopenharmony_ci        }
829141cc406Sopenharmony_ci      break;
830141cc406Sopenharmony_ci    case opt_mode:
831141cc406Sopenharmony_ci      if (cfg->cap & (PIXMA_CAP_48BIT|PIXMA_CAP_LINEART|PIXMA_CAP_TPUIR)
832141cc406Sopenharmony_ci          && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO))
833141cc406Sopenharmony_ci        { /* new mode selected: Color, Gray, ... */
834141cc406Sopenharmony_ci          /* PDBG (pixma_dbg (4, "*control_option***** mode = %u *\n",
835141cc406Sopenharmony_ci                           ss->mode_map[OVAL (opt_mode).w])); */
836141cc406Sopenharmony_ci          /* recreate dynamic lists */
837141cc406Sopenharmony_ci          create_dpi_list (ss);
838141cc406Sopenharmony_ci          if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART)
839141cc406Sopenharmony_ci            { /* lineart */
840141cc406Sopenharmony_ci              enable_option (ss, opt_threshold, SANE_TRUE);
841141cc406Sopenharmony_ci              enable_option (ss, opt_threshold_curve, SANE_TRUE);
842141cc406Sopenharmony_ci            }
843141cc406Sopenharmony_ci          else
844141cc406Sopenharmony_ci            { /* all other modes */
845141cc406Sopenharmony_ci              enable_option (ss, opt_threshold, SANE_FALSE);
846141cc406Sopenharmony_ci              enable_option (ss, opt_threshold_curve, SANE_FALSE);
847141cc406Sopenharmony_ci            }
848141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
849141cc406Sopenharmony_ci        }
850141cc406Sopenharmony_ci      break;
851141cc406Sopenharmony_ci    case opt_source:
852141cc406Sopenharmony_ci      if ((cfg->cap & (PIXMA_CAP_ADF|PIXMA_CAP_ADFDUP|PIXMA_CAP_TPU))
853141cc406Sopenharmony_ci          && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO))
854141cc406Sopenharmony_ci        { /* new source selected: flatbed, ADF, TPU, ... */
855141cc406Sopenharmony_ci          /* to avoid fatal errors,
856141cc406Sopenharmony_ci           * select first entry of dynamic mode_list
857141cc406Sopenharmony_ci           * identifiers are unknown here */
858141cc406Sopenharmony_ci          OVAL (opt_mode).w = ss->mode_map[0];
859141cc406Sopenharmony_ci          /* recreate dynamic lists */
860141cc406Sopenharmony_ci          create_mode_list (ss);
861141cc406Sopenharmony_ci          create_dpi_list (ss);
862141cc406Sopenharmony_ci          /* to avoid fatal errors,
863141cc406Sopenharmony_ci           * select first entry of dynamic dpi_list
864141cc406Sopenharmony_ci           * identifiers are unknown here */
865141cc406Sopenharmony_ci          OVAL (opt_resolution).w = ss->dpi_list[1];
866141cc406Sopenharmony_ci          if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART)
867141cc406Sopenharmony_ci            { /* lineart */
868141cc406Sopenharmony_ci              enable_option (ss, opt_threshold, SANE_TRUE);
869141cc406Sopenharmony_ci              enable_option (ss, opt_threshold_curve, SANE_TRUE);
870141cc406Sopenharmony_ci            }
871141cc406Sopenharmony_ci          else
872141cc406Sopenharmony_ci            { /* all other modes */
873141cc406Sopenharmony_ci              enable_option (ss, opt_threshold, SANE_FALSE);
874141cc406Sopenharmony_ci              enable_option (ss, opt_threshold_curve, SANE_FALSE);
875141cc406Sopenharmony_ci            }
876141cc406Sopenharmony_ci          if (cfg->cap & (PIXMA_CAP_ADF_WAIT))
877141cc406Sopenharmony_ci            { /* adf-wait */
878141cc406Sopenharmony_ci              enable_option (ss, opt_adf_wait, SANE_TRUE);
879141cc406Sopenharmony_ci            }
880141cc406Sopenharmony_ci          else
881141cc406Sopenharmony_ci            { /* disable adf-wait */
882141cc406Sopenharmony_ci              enable_option (ss, opt_adf_wait, SANE_FALSE);
883141cc406Sopenharmony_ci            }
884141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
885141cc406Sopenharmony_ci        }
886141cc406Sopenharmony_ci      break;
887141cc406Sopenharmony_ci    }
888141cc406Sopenharmony_ci
889141cc406Sopenharmony_ci  return result;
890141cc406Sopenharmony_ci}
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci#ifndef NDEBUG
893141cc406Sopenharmony_cistatic void
894141cc406Sopenharmony_ciprint_scan_param (int level, const pixma_scan_param_t * sp)
895141cc406Sopenharmony_ci{
896141cc406Sopenharmony_ci  pixma_dbg (level, "Scan parameters\n");
897141cc406Sopenharmony_ci  pixma_dbg (level, "  line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n",
898141cc406Sopenharmony_ci	     sp->line_size, sp->image_size, sp->channels, sp->depth);
899141cc406Sopenharmony_ci  pixma_dbg (level, "  dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n",
900141cc406Sopenharmony_ci	     sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h);
901141cc406Sopenharmony_ci  pixma_dbg (level, "  gamma=%f gamma_table=%p source=%d\n", sp->gamma,
902141cc406Sopenharmony_ci             (void *) sp->gamma_table, sp->source);
903141cc406Sopenharmony_ci  pixma_dbg (level, "  adf-wait=%d\n", sp->adf_wait);
904141cc406Sopenharmony_ci}
905141cc406Sopenharmony_ci#endif
906141cc406Sopenharmony_ci
907141cc406Sopenharmony_cistatic int
908141cc406Sopenharmony_cicalc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp)
909141cc406Sopenharmony_ci{
910141cc406Sopenharmony_ci  int x1, y1, x2, y2;
911141cc406Sopenharmony_ci  int error;
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  memset (sp, 0, sizeof (*sp));
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ci  sp->channels = (OVAL (opt_mode).w == 0) ? 3 : 1;
916141cc406Sopenharmony_ci  sp->depth = (OVAL (opt_mode).w == 2) ? 1 : 8;
917141cc406Sopenharmony_ci  sp->xdpi = sp->ydpi = OVAL (opt_resolution).w;
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci#define PIXEL(x,dpi) (int)((SANE_UNFIX(x) / 25.4 * (dpi)) + 0.5)
920141cc406Sopenharmony_ci  x1 = PIXEL (OVAL (opt_tl_x).w, sp->xdpi);
921141cc406Sopenharmony_ci  x2 = PIXEL (OVAL (opt_br_x).w, sp->xdpi);
922141cc406Sopenharmony_ci  if (x2 < x1)
923141cc406Sopenharmony_ci    {
924141cc406Sopenharmony_ci      int temp = x1;
925141cc406Sopenharmony_ci      x1 = x2;
926141cc406Sopenharmony_ci      x2 = temp;
927141cc406Sopenharmony_ci    }
928141cc406Sopenharmony_ci  y1 = PIXEL (OVAL (opt_tl_y).w, sp->ydpi);
929141cc406Sopenharmony_ci  y2 = PIXEL (OVAL (opt_br_y).w, sp->ydpi);
930141cc406Sopenharmony_ci  if (y2 < y1)
931141cc406Sopenharmony_ci    {
932141cc406Sopenharmony_ci      int temp = y1;
933141cc406Sopenharmony_ci      y1 = y2;
934141cc406Sopenharmony_ci      y2 = temp;
935141cc406Sopenharmony_ci    }
936141cc406Sopenharmony_ci#undef PIXEL
937141cc406Sopenharmony_ci  sp->x = x1;
938141cc406Sopenharmony_ci  sp->y = y1;
939141cc406Sopenharmony_ci  sp->w = x2 - x1;
940141cc406Sopenharmony_ci  sp->h = y2 - y1;
941141cc406Sopenharmony_ci  if (sp->w == 0)
942141cc406Sopenharmony_ci    sp->w = 1;
943141cc406Sopenharmony_ci  if (sp->h == 0)
944141cc406Sopenharmony_ci    sp->h = 1;
945141cc406Sopenharmony_ci  sp->tpu_offset_added = 0;
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci  sp->gamma = SANE_UNFIX (OVAL (opt_gamma).w);
948141cc406Sopenharmony_ci  sp->gamma_table = ss->gamma_table;
949141cc406Sopenharmony_ci  sp->source = ss->source_map[OVAL (opt_source).w];
950141cc406Sopenharmony_ci  sp->mode = ss->mode_map[OVAL (opt_mode).w];
951141cc406Sopenharmony_ci  sp->adf_pageid = ss->page_count;
952141cc406Sopenharmony_ci  sp->threshold = 2.55 * OVAL (opt_threshold).w;
953141cc406Sopenharmony_ci  sp->threshold_curve = OVAL (opt_threshold_curve).w;
954141cc406Sopenharmony_ci  sp->adf_wait = OVAL (opt_adf_wait).w;
955141cc406Sopenharmony_ci  sp->calibrate = ss->calibrate_map[OVAL (opt_calibrate).w];
956141cc406Sopenharmony_ci
957141cc406Sopenharmony_ci  error = pixma_check_scan_param (ss->s, sp);
958141cc406Sopenharmony_ci  if (error < 0)
959141cc406Sopenharmony_ci    {
960141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "BUG:calc_scan_param() failed %d\n", error));
961141cc406Sopenharmony_ci      PDBG (print_scan_param (1, sp));
962141cc406Sopenharmony_ci    }
963141cc406Sopenharmony_ci  return error;
964141cc406Sopenharmony_ci}
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_cistatic void
967141cc406Sopenharmony_ciinit_option_descriptors (pixma_sane_t * ss)
968141cc406Sopenharmony_ci{
969141cc406Sopenharmony_ci  const pixma_config_t *cfg;
970141cc406Sopenharmony_ci  int i;
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci  cfg = pixma_get_config (ss->s);
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci  /* PDBG (pixma_dbg (4, "*init_option_descriptors*****\n")); */
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci  /* setup range for the scan area. */
977141cc406Sopenharmony_ci  ss->xrange.min = SANE_FIX (0);
978141cc406Sopenharmony_ci  ss->xrange.max = SANE_FIX (cfg->width / 75.0 * 25.4);
979141cc406Sopenharmony_ci  ss->xrange.quant = SANE_FIX (0);
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  ss->yrange.min = SANE_FIX (0);
982141cc406Sopenharmony_ci  ss->yrange.max = SANE_FIX (cfg->height / 75.0 * 25.4);
983141cc406Sopenharmony_ci  ss->yrange.quant = SANE_FIX (0);
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  /* mode_list and source_list were already NULL-terminated,
986141cc406Sopenharmony_ci   * because the whole pixma_sane_t was cleared during allocation. */
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci  /* setup available mode. */
989141cc406Sopenharmony_ci  create_mode_list (ss);
990141cc406Sopenharmony_ci
991141cc406Sopenharmony_ci  /* setup dpi up to the value supported by the scanner. */
992141cc406Sopenharmony_ci  create_dpi_list (ss);
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci  /* setup paper source */
995141cc406Sopenharmony_ci  i = 0;
996141cc406Sopenharmony_ci  ss->source_list[i] = SANE_I18N ("Flatbed");
997141cc406Sopenharmony_ci  ss->source_map[i] = PIXMA_SOURCE_FLATBED;
998141cc406Sopenharmony_ci  i++;
999141cc406Sopenharmony_ci  if (cfg->cap & PIXMA_CAP_ADF)
1000141cc406Sopenharmony_ci    {
1001141cc406Sopenharmony_ci      ss->source_list[i] = SANE_I18N ("Automatic Document Feeder");
1002141cc406Sopenharmony_ci      ss->source_map[i] = PIXMA_SOURCE_ADF;
1003141cc406Sopenharmony_ci      i++;
1004141cc406Sopenharmony_ci    }
1005141cc406Sopenharmony_ci  if ((cfg->cap & PIXMA_CAP_ADFDUP) == PIXMA_CAP_ADFDUP)
1006141cc406Sopenharmony_ci    {
1007141cc406Sopenharmony_ci      ss->source_list[i] = SANE_I18N ("ADF Duplex");
1008141cc406Sopenharmony_ci      ss->source_map[i] = PIXMA_SOURCE_ADFDUP;
1009141cc406Sopenharmony_ci      i++;
1010141cc406Sopenharmony_ci    }
1011141cc406Sopenharmony_ci  if (cfg->cap & PIXMA_CAP_TPU)
1012141cc406Sopenharmony_ci    {
1013141cc406Sopenharmony_ci      ss->source_list[i] = SANE_I18N ("Transparency Unit");
1014141cc406Sopenharmony_ci      ss->source_map[i] = PIXMA_SOURCE_TPU;
1015141cc406Sopenharmony_ci      i++;
1016141cc406Sopenharmony_ci    }
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci  create_calibrate_list (ss);
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci  build_option_descriptors (ss);
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci  /* Enable options that are available only in some scanners. */
1023141cc406Sopenharmony_ci  if (cfg->cap & PIXMA_CAP_GAMMA_TABLE)
1024141cc406Sopenharmony_ci    {
1025141cc406Sopenharmony_ci      SANE_Option_Descriptor *sod = &SOD (opt_gamma_table);
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci      /* some scanners have a large gamma table with 4096 entries */
1028141cc406Sopenharmony_ci      if (cfg->cap & PIXMA_CAP_GT_4096)
1029141cc406Sopenharmony_ci        {
1030141cc406Sopenharmony_ci          static const SANE_Range constraint_gamma_table_4096 = { 0,0xff,0 };
1031141cc406Sopenharmony_ci          sod->desc = SANE_I18N("Gamma-correction table with 4096 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table).");
1032141cc406Sopenharmony_ci          sod->size = 4096 * sizeof(SANE_Word);
1033141cc406Sopenharmony_ci          sod->constraint.range = &constraint_gamma_table_4096;
1034141cc406Sopenharmony_ci        }
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci      /* PDBG (pixma_dbg (4, "*%s***** PIXMA_CAP_GAMMA_TABLE ***** \n",
1037141cc406Sopenharmony_ci                       __func__)); */
1038141cc406Sopenharmony_ci      /* PDBG (pixma_dbg (4, "%s: gamma_table_contraint.max = %d\n",
1039141cc406Sopenharmony_ci                       __func__,  sod->constraint.range->max)); */
1040141cc406Sopenharmony_ci      /* PDBG (pixma_dbg (4, "%s: gamma_table_size = %d\n",
1041141cc406Sopenharmony_ci                       __func__,  sod->size / sizeof(SANE_Word))); */
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci      /* activate option gamma */
1044141cc406Sopenharmony_ci      enable_option (ss, opt_gamma, SANE_TRUE);
1045141cc406Sopenharmony_ci      sane_control_option (ss, opt_gamma, SANE_ACTION_SET_AUTO,
1046141cc406Sopenharmony_ci                           NULL, NULL);
1047141cc406Sopenharmony_ci      /* activate option custom gamma table */
1048141cc406Sopenharmony_ci      enable_option (ss, opt_custom_gamma, SANE_TRUE);
1049141cc406Sopenharmony_ci      sane_control_option (ss, opt_custom_gamma, SANE_ACTION_SET_AUTO,
1050141cc406Sopenharmony_ci                           NULL, NULL);
1051141cc406Sopenharmony_ci    }
1052141cc406Sopenharmony_ci  enable_option (ss, opt_button_controlled,
1053141cc406Sopenharmony_ci		 ((cfg->cap & PIXMA_CAP_EVENTS) != 0));
1054141cc406Sopenharmony_ci}
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci/* Writing to reader_ss outside reader_process() is a BUG! */
1057141cc406Sopenharmony_cistatic pixma_sane_t *reader_ss = NULL;
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_cistatic void
1060141cc406Sopenharmony_cireader_signal_handler (int sig)
1061141cc406Sopenharmony_ci{
1062141cc406Sopenharmony_ci  if (reader_ss)
1063141cc406Sopenharmony_ci    {
1064141cc406Sopenharmony_ci      reader_ss->reader_stop = SANE_TRUE;
1065141cc406Sopenharmony_ci      /* reader process is ended by SIGTERM, so no cancel in this case */
1066141cc406Sopenharmony_ci      if (sig != SIGTERM)
1067141cc406Sopenharmony_ci        pixma_cancel (reader_ss->s);
1068141cc406Sopenharmony_ci    }
1069141cc406Sopenharmony_ci}
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_cistatic int
1072141cc406Sopenharmony_ciwrite_all (pixma_sane_t * ss, void *buf_, size_t size)
1073141cc406Sopenharmony_ci{
1074141cc406Sopenharmony_ci  uint8_t *buf = (uint8_t *) buf_;
1075141cc406Sopenharmony_ci  int count;
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci  while (size != 0 && !ss->reader_stop)
1078141cc406Sopenharmony_ci    {
1079141cc406Sopenharmony_ci      count = write (ss->wpipe, buf, size);
1080141cc406Sopenharmony_ci      if (count == -1 && errno != EINTR)
1081141cc406Sopenharmony_ci	break;
1082141cc406Sopenharmony_ci      if (count == -1 && errno == EINTR)
1083141cc406Sopenharmony_ci	continue;
1084141cc406Sopenharmony_ci      buf += count;
1085141cc406Sopenharmony_ci      size -= count;
1086141cc406Sopenharmony_ci    }
1087141cc406Sopenharmony_ci  return buf - (uint8_t *) buf_;
1088141cc406Sopenharmony_ci}
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci/* NOTE: reader_loop() runs either in a separate thread or process. */
1091141cc406Sopenharmony_cistatic SANE_Status
1092141cc406Sopenharmony_cireader_loop (pixma_sane_t * ss)
1093141cc406Sopenharmony_ci{
1094141cc406Sopenharmony_ci  void *buf;
1095141cc406Sopenharmony_ci  unsigned bufsize;
1096141cc406Sopenharmony_ci  int count = 0;
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "Reader task started\n"));
1099141cc406Sopenharmony_ci  /*bufsize = ss->sp.line_size + 1;*/	/* XXX: "odd" bufsize for testing pixma_read_image() */
1100141cc406Sopenharmony_ci  bufsize = ss->sp.line_size;   /* bufsize EVEN needed by Xsane for 48 bits depth */
1101141cc406Sopenharmony_ci  buf = malloc (bufsize);
1102141cc406Sopenharmony_ci  if (!buf)
1103141cc406Sopenharmony_ci    {
1104141cc406Sopenharmony_ci      count = PIXMA_ENOMEM;
1105141cc406Sopenharmony_ci      goto done;
1106141cc406Sopenharmony_ci    }
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci  count = pixma_activate_connection (ss->s);
1109141cc406Sopenharmony_ci  if (count < 0)
1110141cc406Sopenharmony_ci    goto done;
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci  pixma_enable_background (ss->s, 1);
1113141cc406Sopenharmony_ci  if (OVAL (opt_button_controlled).b && ss->page_count == 0)
1114141cc406Sopenharmony_ci    {
1115141cc406Sopenharmony_ci      int start = 0;
1116141cc406Sopenharmony_ci#ifndef NDEBUG
1117141cc406Sopenharmony_ci      pixma_dbg (1, "==== Button-controlled scan mode is enabled.\n");
1118141cc406Sopenharmony_ci      pixma_dbg (1, "==== To proceed, press 'SCAN' or 'COLOR' button. "
1119141cc406Sopenharmony_ci		 "To cancel, press 'GRAY' or 'END' button.\n");
1120141cc406Sopenharmony_ci#endif
1121141cc406Sopenharmony_ci      while (pixma_wait_event (ss->s, 10) != 0)
1122141cc406Sopenharmony_ci        {
1123141cc406Sopenharmony_ci        }
1124141cc406Sopenharmony_ci      while (!start)
1125141cc406Sopenharmony_ci        {
1126141cc406Sopenharmony_ci          uint32_t events;
1127141cc406Sopenharmony_ci          if (ss->reader_stop)
1128141cc406Sopenharmony_ci            {
1129141cc406Sopenharmony_ci              count = PIXMA_ECANCELED;
1130141cc406Sopenharmony_ci              goto done;
1131141cc406Sopenharmony_ci            }
1132141cc406Sopenharmony_ci          events = pixma_wait_event (ss->s, 1000);
1133141cc406Sopenharmony_ci          switch (events & ~PIXMA_EV_ACTION_MASK)
1134141cc406Sopenharmony_ci            {
1135141cc406Sopenharmony_ci            case PIXMA_EV_BUTTON1:
1136141cc406Sopenharmony_ci              start = 1;
1137141cc406Sopenharmony_ci              break;
1138141cc406Sopenharmony_ci            case PIXMA_EV_BUTTON2:
1139141cc406Sopenharmony_ci              count = PIXMA_ECANCELED;
1140141cc406Sopenharmony_ci              goto done;
1141141cc406Sopenharmony_ci            }
1142141cc406Sopenharmony_ci        }
1143141cc406Sopenharmony_ci    }
1144141cc406Sopenharmony_ci  count = pixma_scan (ss->s, &ss->sp);
1145141cc406Sopenharmony_ci  if (count >= 0)
1146141cc406Sopenharmony_ci    {
1147141cc406Sopenharmony_ci      while ((count = pixma_read_image (ss->s, buf, bufsize)) > 0)
1148141cc406Sopenharmony_ci        {
1149141cc406Sopenharmony_ci          if (write_all (ss, buf, count) != count)
1150141cc406Sopenharmony_ci            pixma_cancel (ss->s);
1151141cc406Sopenharmony_ci        }
1152141cc406Sopenharmony_ci    }
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_cidone:
1155141cc406Sopenharmony_ci  pixma_enable_background (ss->s, 0);
1156141cc406Sopenharmony_ci  pixma_deactivate_connection (ss->s);
1157141cc406Sopenharmony_ci  free (buf);
1158141cc406Sopenharmony_ci  close (ss->wpipe);
1159141cc406Sopenharmony_ci  ss->wpipe = -1;
1160141cc406Sopenharmony_ci  if (count >= 0)
1161141cc406Sopenharmony_ci    {
1162141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "Reader task terminated\n"));
1163141cc406Sopenharmony_ci    }
1164141cc406Sopenharmony_ci  else
1165141cc406Sopenharmony_ci    {
1166141cc406Sopenharmony_ci      PDBG (pixma_dbg
1167141cc406Sopenharmony_ci	    (2, "Reader task terminated: %s\n", pixma_strerror (count)));
1168141cc406Sopenharmony_ci    }
1169141cc406Sopenharmony_ci  return map_error (count);
1170141cc406Sopenharmony_ci}
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_cistatic int
1173141cc406Sopenharmony_cireader_process (void *arg)
1174141cc406Sopenharmony_ci{
1175141cc406Sopenharmony_ci  pixma_sane_t *ss = (pixma_sane_t *) arg;
1176141cc406Sopenharmony_ci  struct SIGACTION sa;
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  reader_ss = ss;
1179141cc406Sopenharmony_ci  memset (&sa, 0, sizeof (sa));
1180141cc406Sopenharmony_ci  sigemptyset (&sa.sa_mask);
1181141cc406Sopenharmony_ci  sa.sa_handler = reader_signal_handler;
1182141cc406Sopenharmony_ci  /* FIXME: which signal else? */
1183141cc406Sopenharmony_ci  sigaction (SIGHUP, &sa, NULL);
1184141cc406Sopenharmony_ci  sigaction (SIGINT, &sa, NULL);
1185141cc406Sopenharmony_ci  sigaction (SIGPIPE, &sa, NULL);
1186141cc406Sopenharmony_ci  sigaction (SIGTERM, &sa, NULL);
1187141cc406Sopenharmony_ci  close (ss->rpipe);
1188141cc406Sopenharmony_ci  ss->rpipe = -1;
1189141cc406Sopenharmony_ci  return reader_loop (ss);
1190141cc406Sopenharmony_ci}
1191141cc406Sopenharmony_ci
1192141cc406Sopenharmony_cistatic int
1193141cc406Sopenharmony_cireader_thread (void *arg)
1194141cc406Sopenharmony_ci{
1195141cc406Sopenharmony_ci  pixma_sane_t *ss = (pixma_sane_t *) arg;
1196141cc406Sopenharmony_ci#ifdef USE_PTHREAD
1197141cc406Sopenharmony_ci  /* Block SIGPIPE. We will handle this in reader_loop() by checking
1198141cc406Sopenharmony_ci     ss->reader_stop and the return value from write(). */
1199141cc406Sopenharmony_ci  sigset_t sigs;
1200141cc406Sopenharmony_ci  sigemptyset (&sigs);
1201141cc406Sopenharmony_ci  sigaddset (&sigs, SIGPIPE);
1202141cc406Sopenharmony_ci  pthread_sigmask (SIG_BLOCK, &sigs, NULL);
1203141cc406Sopenharmony_ci#endif /* USE_PTHREAD */
1204141cc406Sopenharmony_ci  return reader_loop (ss);
1205141cc406Sopenharmony_ci}
1206141cc406Sopenharmony_ci
1207141cc406Sopenharmony_cistatic SANE_Pid
1208141cc406Sopenharmony_citerminate_reader_task (pixma_sane_t * ss, int *exit_code)
1209141cc406Sopenharmony_ci{
1210141cc406Sopenharmony_ci  SANE_Pid result, pid;
1211141cc406Sopenharmony_ci  int status = 0;
1212141cc406Sopenharmony_ci
1213141cc406Sopenharmony_ci  pid = ss->reader_taskid;
1214141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (pid))
1215141cc406Sopenharmony_ci    return pid;
1216141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
1217141cc406Sopenharmony_ci    {
1218141cc406Sopenharmony_ci      sanei_thread_kill (pid);
1219141cc406Sopenharmony_ci    }
1220141cc406Sopenharmony_ci  else
1221141cc406Sopenharmony_ci    {
1222141cc406Sopenharmony_ci      ss->reader_stop = SANE_TRUE;
1223141cc406Sopenharmony_ci/*      pixma_cancel (ss->s);   What is this for ? Makes end-of-scan buggy => removing */
1224141cc406Sopenharmony_ci    }
1225141cc406Sopenharmony_ci  result = sanei_thread_waitpid (pid, &status);
1226141cc406Sopenharmony_ci  sanei_thread_invalidate (ss->reader_taskid);
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci  if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
1229141cc406Sopenharmony_ci    ss->idle = SANE_TRUE;
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci  if (result == pid)
1232141cc406Sopenharmony_ci    {
1233141cc406Sopenharmony_ci      if (exit_code)
1234141cc406Sopenharmony_ci	      *exit_code = status;
1235141cc406Sopenharmony_ci      return pid;
1236141cc406Sopenharmony_ci    }
1237141cc406Sopenharmony_ci  else
1238141cc406Sopenharmony_ci    {
1239141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "WARNING:waitpid() failed %s\n", strerror (errno)));
1240141cc406Sopenharmony_ci      sanei_thread_invalidate (pid);
1241141cc406Sopenharmony_ci      return pid;
1242141cc406Sopenharmony_ci    }
1243141cc406Sopenharmony_ci}
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_cistatic int
1246141cc406Sopenharmony_cistart_reader_task (pixma_sane_t * ss)
1247141cc406Sopenharmony_ci{
1248141cc406Sopenharmony_ci  int fds[2];
1249141cc406Sopenharmony_ci  SANE_Pid pid;
1250141cc406Sopenharmony_ci  int is_forked;
1251141cc406Sopenharmony_ci
1252141cc406Sopenharmony_ci  if (ss->rpipe != -1 || ss->wpipe != -1)
1253141cc406Sopenharmony_ci    {
1254141cc406Sopenharmony_ci      PDBG (pixma_dbg
1255141cc406Sopenharmony_ci	    (1, "BUG:rpipe = %d, wpipe = %d\n", ss->rpipe, ss->wpipe));
1256141cc406Sopenharmony_ci      close (ss->rpipe);
1257141cc406Sopenharmony_ci      close (ss->wpipe);
1258141cc406Sopenharmony_ci      ss->rpipe = -1;
1259141cc406Sopenharmony_ci      ss->wpipe = -1;
1260141cc406Sopenharmony_ci    }
1261141cc406Sopenharmony_ci  if (sanei_thread_is_valid (ss->reader_taskid))
1262141cc406Sopenharmony_ci    {
1263141cc406Sopenharmony_ci      PDBG (pixma_dbg
1264141cc406Sopenharmony_ci	    (1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid));
1265141cc406Sopenharmony_ci      terminate_reader_task (ss, NULL);
1266141cc406Sopenharmony_ci    }
1267141cc406Sopenharmony_ci  if (pipe (fds) == -1)
1268141cc406Sopenharmony_ci    {
1269141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "ERROR:start_reader_task():pipe() failed %s\n",
1270141cc406Sopenharmony_ci		       strerror (errno)));
1271141cc406Sopenharmony_ci      return PIXMA_ENOMEM;
1272141cc406Sopenharmony_ci    }
1273141cc406Sopenharmony_ci  ss->rpipe = fds[0];
1274141cc406Sopenharmony_ci  ss->wpipe = fds[1];
1275141cc406Sopenharmony_ci  ss->reader_stop = SANE_FALSE;
1276141cc406Sopenharmony_ci
1277141cc406Sopenharmony_ci  is_forked = sanei_thread_is_forked ();
1278141cc406Sopenharmony_ci  if (is_forked)
1279141cc406Sopenharmony_ci    {
1280141cc406Sopenharmony_ci      pid = sanei_thread_begin (reader_process, ss);
1281141cc406Sopenharmony_ci      if (sanei_thread_is_valid (pid))
1282141cc406Sopenharmony_ci        {
1283141cc406Sopenharmony_ci          close (ss->wpipe);
1284141cc406Sopenharmony_ci          ss->wpipe = -1;
1285141cc406Sopenharmony_ci        }
1286141cc406Sopenharmony_ci    }
1287141cc406Sopenharmony_ci  else
1288141cc406Sopenharmony_ci    {
1289141cc406Sopenharmony_ci      pid = sanei_thread_begin (reader_thread, ss);
1290141cc406Sopenharmony_ci    }
1291141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (pid))
1292141cc406Sopenharmony_ci    {
1293141cc406Sopenharmony_ci      close (ss->wpipe);
1294141cc406Sopenharmony_ci      close (ss->rpipe);
1295141cc406Sopenharmony_ci      ss->wpipe = -1;
1296141cc406Sopenharmony_ci      ss->rpipe = -1;
1297141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n"));
1298141cc406Sopenharmony_ci      return PIXMA_ENOMEM;
1299141cc406Sopenharmony_ci    }
1300141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n", (long) pid,
1301141cc406Sopenharmony_ci		   (is_forked) ? "forked" : "threaded"));
1302141cc406Sopenharmony_ci  ss->reader_taskid = pid;
1303141cc406Sopenharmony_ci  return 0;
1304141cc406Sopenharmony_ci}
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci/* libJPEG API callbacks */
1307141cc406Sopenharmony_cistatic void
1308141cc406Sopenharmony_cijpeg_init_source(j_decompress_ptr __sane_unused__ cinfo)
1309141cc406Sopenharmony_ci{
1310141cc406Sopenharmony_ci  /* No-op */
1311141cc406Sopenharmony_ci}
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_cistatic void
1314141cc406Sopenharmony_cijpeg_term_source(j_decompress_ptr __sane_unused__ cinfo)
1315141cc406Sopenharmony_ci{
1316141cc406Sopenharmony_ci  /* No-op */
1317141cc406Sopenharmony_ci}
1318141cc406Sopenharmony_ci
1319141cc406Sopenharmony_cistatic boolean
1320141cc406Sopenharmony_cijpeg_fill_input_buffer(j_decompress_ptr cinfo)
1321141cc406Sopenharmony_ci{
1322141cc406Sopenharmony_ci  pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src;
1323141cc406Sopenharmony_ci  int size;
1324141cc406Sopenharmony_ci  int retry;
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  for (retry = 0; retry < 30; retry ++ )
1327141cc406Sopenharmony_ci    {
1328141cc406Sopenharmony_ci      size = read (mgr->s->rpipe, mgr->buffer, 1024);
1329141cc406Sopenharmony_ci      if (size == 0)
1330141cc406Sopenharmony_ci        {
1331141cc406Sopenharmony_ci          return FALSE;
1332141cc406Sopenharmony_ci        }
1333141cc406Sopenharmony_ci      else if (size < 0)
1334141cc406Sopenharmony_ci        {
1335141cc406Sopenharmony_ci          sleep (1);
1336141cc406Sopenharmony_ci        }
1337141cc406Sopenharmony_ci      else
1338141cc406Sopenharmony_ci        {
1339141cc406Sopenharmony_ci          mgr->jpeg.next_input_byte = mgr->buffer;
1340141cc406Sopenharmony_ci          mgr->jpeg.bytes_in_buffer = size;
1341141cc406Sopenharmony_ci          return TRUE;
1342141cc406Sopenharmony_ci        }
1343141cc406Sopenharmony_ci    }
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci  return FALSE;
1346141cc406Sopenharmony_ci}
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_cistatic void
1349141cc406Sopenharmony_cijpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
1350141cc406Sopenharmony_ci{
1351141cc406Sopenharmony_ci  pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src;
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci  if (num_bytes > 0)
1354141cc406Sopenharmony_ci    {
1355141cc406Sopenharmony_ci      /* Read and throw away extra */
1356141cc406Sopenharmony_ci      while (num_bytes > (long)mgr->jpeg.bytes_in_buffer)
1357141cc406Sopenharmony_ci        {
1358141cc406Sopenharmony_ci           num_bytes -= (long)mgr->jpeg.bytes_in_buffer;
1359141cc406Sopenharmony_ci           jpeg_fill_input_buffer(cinfo);
1360141cc406Sopenharmony_ci        }
1361141cc406Sopenharmony_ci
1362141cc406Sopenharmony_ci      /* Update jpeg info structure with leftover */
1363141cc406Sopenharmony_ci      mgr->jpeg.next_input_byte += (size_t) num_bytes;
1364141cc406Sopenharmony_ci      mgr->jpeg.bytes_in_buffer -= (size_t) num_bytes;
1365141cc406Sopenharmony_ci    }
1366141cc406Sopenharmony_ci}
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci/* Pixma JPEG reader helpers */
1369141cc406Sopenharmony_cistatic SANE_Status
1370141cc406Sopenharmony_cipixma_jpeg_start(pixma_sane_t *s)
1371141cc406Sopenharmony_ci{
1372141cc406Sopenharmony_ci  pixma_jpeg_src_mgr *mgr;
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci  s->jpeg_cinfo.err = jpeg_std_error(&s->jpeg_err);
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_ci  jpeg_create_decompress(&s->jpeg_cinfo);
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci  s->jpeg_cinfo.src = (struct jpeg_source_mgr *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo,
1379141cc406Sopenharmony_ci                              JPOOL_PERMANENT, sizeof(pixma_jpeg_src_mgr));
1380141cc406Sopenharmony_ci
1381141cc406Sopenharmony_ci  memset(s->jpeg_cinfo.src, 0, sizeof(pixma_jpeg_src_mgr));
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci  mgr = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src;
1384141cc406Sopenharmony_ci  mgr->s = s;
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci  mgr->buffer = (JOCTET *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo,
1387141cc406Sopenharmony_ci                                                  JPOOL_PERMANENT,
1388141cc406Sopenharmony_ci                                                  1024 * sizeof(JOCTET));
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  mgr->jpeg.init_source = jpeg_init_source;
1391141cc406Sopenharmony_ci  mgr->jpeg.fill_input_buffer = jpeg_fill_input_buffer;
1392141cc406Sopenharmony_ci  mgr->jpeg.skip_input_data = jpeg_skip_input_data;
1393141cc406Sopenharmony_ci  mgr->jpeg.resync_to_restart = jpeg_resync_to_restart;
1394141cc406Sopenharmony_ci  mgr->jpeg.term_source = jpeg_term_source;
1395141cc406Sopenharmony_ci  mgr->jpeg.bytes_in_buffer = 0;
1396141cc406Sopenharmony_ci  mgr->jpeg.next_input_byte = NULL;
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci  s->jpeg_header_seen = 0;
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1401141cc406Sopenharmony_ci}
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_cistatic SANE_Status
1404141cc406Sopenharmony_cipixma_jpeg_read_header(pixma_sane_t *s)
1405141cc406Sopenharmony_ci{
1406141cc406Sopenharmony_ci  pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src;
1407141cc406Sopenharmony_ci
1408141cc406Sopenharmony_ci  if (jpeg_read_header(&s->jpeg_cinfo, TRUE))
1409141cc406Sopenharmony_ci    {
1410141cc406Sopenharmony_ci      s->jdst = sanei_jpeg_jinit_write_ppm(&s->jpeg_cinfo);
1411141cc406Sopenharmony_ci
1412141cc406Sopenharmony_ci      if (jpeg_start_decompress(&s->jpeg_cinfo))
1413141cc406Sopenharmony_ci        {
1414141cc406Sopenharmony_ci          int size;
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci          DBG(3, "%s: w: %d, h: %d, components: %d\n",
1417141cc406Sopenharmony_ci                  __func__,
1418141cc406Sopenharmony_ci                  s->jpeg_cinfo.output_width, s->jpeg_cinfo.output_height,
1419141cc406Sopenharmony_ci                  s->jpeg_cinfo.output_components);
1420141cc406Sopenharmony_ci
1421141cc406Sopenharmony_ci          size = s->jpeg_cinfo.output_width * s->jpeg_cinfo.output_components * 1;
1422141cc406Sopenharmony_ci
1423141cc406Sopenharmony_ci          src->linebuffer = (*s->jpeg_cinfo.mem->alloc_large)((j_common_ptr)&s->jpeg_cinfo,
1424141cc406Sopenharmony_ci                  JPOOL_PERMANENT, size);
1425141cc406Sopenharmony_ci
1426141cc406Sopenharmony_ci          src->linebuffer_size = 0;
1427141cc406Sopenharmony_ci          src->linebuffer_index = 0;
1428141cc406Sopenharmony_ci
1429141cc406Sopenharmony_ci          s->jpeg_header_seen = 1;
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
1432141cc406Sopenharmony_ci        }
1433141cc406Sopenharmony_ci      else
1434141cc406Sopenharmony_ci        {
1435141cc406Sopenharmony_ci          DBG(0, "%s: decompression failed\n", __func__);
1436141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
1437141cc406Sopenharmony_ci        }
1438141cc406Sopenharmony_ci    }
1439141cc406Sopenharmony_ci  else
1440141cc406Sopenharmony_ci    {
1441141cc406Sopenharmony_ci      DBG(0, "%s: cannot read JPEG header\n", __func__);
1442141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1443141cc406Sopenharmony_ci    }
1444141cc406Sopenharmony_ci}
1445141cc406Sopenharmony_ci
1446141cc406Sopenharmony_cistatic void
1447141cc406Sopenharmony_cipixma_jpeg_finish(pixma_sane_t *ss)
1448141cc406Sopenharmony_ci{
1449141cc406Sopenharmony_ci  jpeg_destroy_decompress(&ss->jpeg_cinfo);
1450141cc406Sopenharmony_ci}
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_cistatic void
1453141cc406Sopenharmony_cipixma_jpeg_read(pixma_sane_t *ss, SANE_Byte *data,
1454141cc406Sopenharmony_ci           SANE_Int max_length, SANE_Int *length)
1455141cc406Sopenharmony_ci{
1456141cc406Sopenharmony_ci  struct jpeg_decompress_struct *cinfo = &ss->jpeg_cinfo;
1457141cc406Sopenharmony_ci  pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)cinfo->src;
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci  int l;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  *length = 0;
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci  /* copy from line buffer if available */
1464141cc406Sopenharmony_ci  if (src->linebuffer_size && src->linebuffer_index < src->linebuffer_size)
1465141cc406Sopenharmony_ci    {
1466141cc406Sopenharmony_ci      *length = src->linebuffer_size - src->linebuffer_index;
1467141cc406Sopenharmony_ci
1468141cc406Sopenharmony_ci      if (*length > max_length)
1469141cc406Sopenharmony_ci        *length = max_length;
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_ci      memcpy(data, src->linebuffer + src->linebuffer_index, *length);
1472141cc406Sopenharmony_ci             src->linebuffer_index += *length;
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci      return;
1475141cc406Sopenharmony_ci    }
1476141cc406Sopenharmony_ci
1477141cc406Sopenharmony_ci  if (cinfo->output_scanline >= cinfo->output_height)
1478141cc406Sopenharmony_ci    {
1479141cc406Sopenharmony_ci      *length = 0;
1480141cc406Sopenharmony_ci      return;
1481141cc406Sopenharmony_ci    }
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  /* scanlines of decompressed data will be in ss->jdst->buffer
1484141cc406Sopenharmony_ci   * only one line at time is supported
1485141cc406Sopenharmony_ci   */
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  l = jpeg_read_scanlines(cinfo, ss->jdst->buffer, 1);
1488141cc406Sopenharmony_ci  if (l == 0)
1489141cc406Sopenharmony_ci    return;
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_ci  /* from ss->jdst->buffer to linebuffer
1492141cc406Sopenharmony_ci   * linebuffer holds width * bytesperpixel
1493141cc406Sopenharmony_ci   */
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  (*ss->jdst->put_pixel_rows)(cinfo, ss->jdst, 1, (char *)src->linebuffer);
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_ci  *length = ss->sp.w * ss->sp.channels;
1498141cc406Sopenharmony_ci  /* Convert RGB into grayscale */
1499141cc406Sopenharmony_ci  if (ss->sp.channels == 1)
1500141cc406Sopenharmony_ci    {
1501141cc406Sopenharmony_ci      unsigned int i;
1502141cc406Sopenharmony_ci      unsigned char *d = (unsigned char *)src->linebuffer;
1503141cc406Sopenharmony_ci      unsigned char *s = (unsigned char *)src->linebuffer;
1504141cc406Sopenharmony_ci      for (i = 0; i < ss->sp.w; i++)
1505141cc406Sopenharmony_ci        {
1506141cc406Sopenharmony_ci          /* Using BT.709 luma formula, fixed-point */
1507141cc406Sopenharmony_ci          int sum = ( s[0]*2126 + s[1]*7152 + s[2]*722 );
1508141cc406Sopenharmony_ci          *d = sum / 10000;
1509141cc406Sopenharmony_ci          d ++;
1510141cc406Sopenharmony_ci          s += 3;
1511141cc406Sopenharmony_ci        }
1512141cc406Sopenharmony_ci    }
1513141cc406Sopenharmony_ci
1514141cc406Sopenharmony_ci  /* Maybe pack into lineary binary image */
1515141cc406Sopenharmony_ci  if (ss->sp.depth == 1)
1516141cc406Sopenharmony_ci    {
1517141cc406Sopenharmony_ci      *length /= 8;
1518141cc406Sopenharmony_ci      unsigned int i;
1519141cc406Sopenharmony_ci      unsigned char *d = (unsigned char *)src->linebuffer;
1520141cc406Sopenharmony_ci      unsigned char *s = (unsigned char *)src->linebuffer;
1521141cc406Sopenharmony_ci      unsigned char b = 0;
1522141cc406Sopenharmony_ci      for (i = 1; i < ss->sp.w + 1; i++)
1523141cc406Sopenharmony_ci        {
1524141cc406Sopenharmony_ci          if (*(s++) > 127)
1525141cc406Sopenharmony_ci            b = (b << 1) | 0;
1526141cc406Sopenharmony_ci         else
1527141cc406Sopenharmony_ci            b = (b << 1) | 1;
1528141cc406Sopenharmony_ci          if ((i % 8) == 0)
1529141cc406Sopenharmony_ci            *(d++) = b;
1530141cc406Sopenharmony_ci        }
1531141cc406Sopenharmony_ci    }
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci  src->linebuffer_size = *length;
1534141cc406Sopenharmony_ci  src->linebuffer_index = 0;
1535141cc406Sopenharmony_ci
1536141cc406Sopenharmony_ci  if (*length > max_length)
1537141cc406Sopenharmony_ci    *length = max_length;
1538141cc406Sopenharmony_ci
1539141cc406Sopenharmony_ci  memcpy(data, src->linebuffer + src->linebuffer_index, *length);
1540141cc406Sopenharmony_ci        src->linebuffer_index += *length;
1541141cc406Sopenharmony_ci}
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci
1544141cc406Sopenharmony_ci
1545141cc406Sopenharmony_cistatic SANE_Status
1546141cc406Sopenharmony_ciread_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen)
1547141cc406Sopenharmony_ci{
1548141cc406Sopenharmony_ci  int count, status;
1549141cc406Sopenharmony_ci
1550141cc406Sopenharmony_ci  if (readlen)
1551141cc406Sopenharmony_ci    *readlen = 0;
1552141cc406Sopenharmony_ci  if (ss->image_bytes_read >= ss->sp.image_size)
1553141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  do
1556141cc406Sopenharmony_ci    {
1557141cc406Sopenharmony_ci      if (ss->cancel)
1558141cc406Sopenharmony_ci        /* ss->rpipe has already been closed by sane_cancel(). */
1559141cc406Sopenharmony_ci        return SANE_STATUS_CANCELLED;
1560141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg && !ss->jpeg_header_seen)
1561141cc406Sopenharmony_ci        {
1562141cc406Sopenharmony_ci          status = pixma_jpeg_read_header(ss);
1563141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
1564141cc406Sopenharmony_ci            {
1565141cc406Sopenharmony_ci              close (ss->rpipe);
1566141cc406Sopenharmony_ci              pixma_jpeg_finish(ss);
1567141cc406Sopenharmony_ci              ss->rpipe = -1;
1568141cc406Sopenharmony_ci              if (sanei_thread_is_valid (terminate_reader_task (ss, &status))
1569141cc406Sopenharmony_ci                && status != SANE_STATUS_GOOD)
1570141cc406Sopenharmony_ci                {
1571141cc406Sopenharmony_ci                  return status;
1572141cc406Sopenharmony_ci                }
1573141cc406Sopenharmony_ci              else
1574141cc406Sopenharmony_ci                {
1575141cc406Sopenharmony_ci                  /* either terminate_reader_task failed or
1576141cc406Sopenharmony_ci                     rpipe was closed but we expect more data */
1577141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
1578141cc406Sopenharmony_ci                }
1579141cc406Sopenharmony_ci            }
1580141cc406Sopenharmony_ci        }
1581141cc406Sopenharmony_ci
1582141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg)
1583141cc406Sopenharmony_ci        {
1584141cc406Sopenharmony_ci          count = -1;
1585141cc406Sopenharmony_ci          pixma_jpeg_read(ss, buf, size, &count);
1586141cc406Sopenharmony_ci        }
1587141cc406Sopenharmony_ci      else
1588141cc406Sopenharmony_ci        count = read (ss->rpipe, buf, size);
1589141cc406Sopenharmony_ci    }
1590141cc406Sopenharmony_ci  while (count == -1 && errno == EINTR);
1591141cc406Sopenharmony_ci
1592141cc406Sopenharmony_ci  if (count == -1)
1593141cc406Sopenharmony_ci    {
1594141cc406Sopenharmony_ci      if (errno == EAGAIN)
1595141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
1596141cc406Sopenharmony_ci      if (!ss->cancel)
1597141cc406Sopenharmony_ci        {
1598141cc406Sopenharmony_ci          PDBG (pixma_dbg (1, "WARNING:read_image():read() failed %s\n",
1599141cc406Sopenharmony_ci               strerror (errno)));
1600141cc406Sopenharmony_ci        }
1601141cc406Sopenharmony_ci      close (ss->rpipe);
1602141cc406Sopenharmony_ci      ss->rpipe = -1;
1603141cc406Sopenharmony_ci      terminate_reader_task (ss, NULL);
1604141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg)
1605141cc406Sopenharmony_ci        pixma_jpeg_finish(ss);
1606141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1607141cc406Sopenharmony_ci    }
1608141cc406Sopenharmony_ci
1609141cc406Sopenharmony_ci  /* here count >= 0 */
1610141cc406Sopenharmony_ci  ss->image_bytes_read += count;
1611141cc406Sopenharmony_ci  if (ss->image_bytes_read > ss->sp.image_size)
1612141cc406Sopenharmony_ci    {
1613141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "BUG:ss->image_bytes_read > ss->sp.image_size\n"));
1614141cc406Sopenharmony_ci    }
1615141cc406Sopenharmony_ci  if (ss->image_bytes_read >= ss->sp.image_size)
1616141cc406Sopenharmony_ci    {
1617141cc406Sopenharmony_ci      close (ss->rpipe);
1618141cc406Sopenharmony_ci      ss->rpipe = -1;
1619141cc406Sopenharmony_ci      terminate_reader_task (ss, NULL);
1620141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg)
1621141cc406Sopenharmony_ci        pixma_jpeg_finish(ss);
1622141cc406Sopenharmony_ci    }
1623141cc406Sopenharmony_ci  else if (count == 0)
1624141cc406Sopenharmony_ci    {
1625141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "read_image():reader task closed the pipe:%"
1626141cc406Sopenharmony_ci		       PRIu64" bytes received, %"PRIu64" bytes expected\n",
1627141cc406Sopenharmony_ci		       ss->image_bytes_read, ss->sp.image_size));
1628141cc406Sopenharmony_ci      close (ss->rpipe);
1629141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg)
1630141cc406Sopenharmony_ci        pixma_jpeg_finish(ss);
1631141cc406Sopenharmony_ci      ss->rpipe = -1;
1632141cc406Sopenharmony_ci      if (sanei_thread_is_valid (terminate_reader_task (ss, &status))
1633141cc406Sopenharmony_ci      	  && status != SANE_STATUS_GOOD)
1634141cc406Sopenharmony_ci        {
1635141cc406Sopenharmony_ci          return status;
1636141cc406Sopenharmony_ci        }
1637141cc406Sopenharmony_ci      else
1638141cc406Sopenharmony_ci        {
1639141cc406Sopenharmony_ci          /* either terminate_reader_task failed or
1640141cc406Sopenharmony_ci             rpipe was closed but we expect more data */
1641141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
1642141cc406Sopenharmony_ci        }
1643141cc406Sopenharmony_ci    }
1644141cc406Sopenharmony_ci  if (readlen)
1645141cc406Sopenharmony_ci    *readlen = count;
1646141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1647141cc406Sopenharmony_ci}
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci
1650141cc406Sopenharmony_ci/*******************************************************************
1651141cc406Sopenharmony_ci ** SANE API
1652141cc406Sopenharmony_ci *******************************************************************/
1653141cc406Sopenharmony_ciSANE_Status
1654141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
1655141cc406Sopenharmony_ci{
1656141cc406Sopenharmony_ci  int status, myversion, i;
1657141cc406Sopenharmony_ci  SANEI_Config config;
1658141cc406Sopenharmony_ci
1659141cc406Sopenharmony_ci  UNUSED (authorize);
1660141cc406Sopenharmony_ci
1661141cc406Sopenharmony_ci  if (!version_code)
1662141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1663141cc406Sopenharmony_ci  myversion = 100 * PIXMA_VERSION_MAJOR + PIXMA_VERSION_MINOR;
1664141cc406Sopenharmony_ci  *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, myversion);
1665141cc406Sopenharmony_ci  DBG_INIT ();
1666141cc406Sopenharmony_ci  sanei_thread_init ();
1667141cc406Sopenharmony_ci  pixma_set_debug_level (DBG_LEVEL);
1668141cc406Sopenharmony_ci
1669141cc406Sopenharmony_ci  PDBG(pixma_dbg(2, "pixma is compiled %s pthread support.\n",
1670141cc406Sopenharmony_ci                   (sanei_thread_is_forked () ? "without" : "with")));
1671141cc406Sopenharmony_ci
1672141cc406Sopenharmony_ci  for (i = 0; i < MAX_CONF_DEVICES; i++)
1673141cc406Sopenharmony_ci    conf_devices[i] = NULL;
1674141cc406Sopenharmony_ci
1675141cc406Sopenharmony_ci  config.count = 0;
1676141cc406Sopenharmony_ci  config.descriptors = NULL;
1677141cc406Sopenharmony_ci  config.values = NULL;
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci  if (sanei_configure_attach(PIXMA_CONFIG_FILE, &config,
1680141cc406Sopenharmony_ci                             config_attach_pixma, NULL) != SANE_STATUS_GOOD)
1681141cc406Sopenharmony_ci    PDBG(pixma_dbg(2, "Could not read pixma configuration file: %s\n",
1682141cc406Sopenharmony_ci                   PIXMA_CONFIG_FILE));
1683141cc406Sopenharmony_ci
1684141cc406Sopenharmony_ci  status = pixma_init ();
1685141cc406Sopenharmony_ci  if (status < 0)
1686141cc406Sopenharmony_ci    {
1687141cc406Sopenharmony_ci      PDBG (pixma_dbg (2, "pixma_init() failed %s\n", pixma_strerror (status)));
1688141cc406Sopenharmony_ci    }
1689141cc406Sopenharmony_ci  return map_error (status);
1690141cc406Sopenharmony_ci}
1691141cc406Sopenharmony_ci
1692141cc406Sopenharmony_civoid
1693141cc406Sopenharmony_cisane_exit (void)
1694141cc406Sopenharmony_ci{
1695141cc406Sopenharmony_ci  while (first_scanner)
1696141cc406Sopenharmony_ci    sane_close (first_scanner);
1697141cc406Sopenharmony_ci  cleanup_device_list ();
1698141cc406Sopenharmony_ci  pixma_cleanup ();
1699141cc406Sopenharmony_ci  sanei_usb_exit ();
1700141cc406Sopenharmony_ci}
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_ciSANE_Status
1703141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1704141cc406Sopenharmony_ci{
1705141cc406Sopenharmony_ci  if (!device_list)
1706141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1707141cc406Sopenharmony_ci  find_scanners (local_only);
1708141cc406Sopenharmony_ci  *device_list = dev_list;
1709141cc406Sopenharmony_ci  return (dev_list) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM;
1710141cc406Sopenharmony_ci}
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ciSANE_Status
1713141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * h)
1714141cc406Sopenharmony_ci{
1715141cc406Sopenharmony_ci  unsigned i, j, nscanners;
1716141cc406Sopenharmony_ci  int error = 0;
1717141cc406Sopenharmony_ci  pixma_sane_t *ss = NULL;
1718141cc406Sopenharmony_ci  const pixma_config_t *cfg;
1719141cc406Sopenharmony_ci
1720141cc406Sopenharmony_ci  if (!name || !h)
1721141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1722141cc406Sopenharmony_ci
1723141cc406Sopenharmony_ci  *h = NULL;
1724141cc406Sopenharmony_ci  nscanners = pixma_find_scanners (conf_devices, SANE_FALSE);
1725141cc406Sopenharmony_ci  if (nscanners == 0)
1726141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1727141cc406Sopenharmony_ci
1728141cc406Sopenharmony_ci  /* also get device id if we replay a xml file
1729141cc406Sopenharmony_ci   * otherwise name contains the xml filename
1730141cc406Sopenharmony_ci   * and further replay will fail  */
1731141cc406Sopenharmony_ci  if (name[0] == '\0' || strstr (name, ".xml"))
1732141cc406Sopenharmony_ci    name = pixma_get_device_id (0);
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci  /* Have we already opened the scanner? */
1735141cc406Sopenharmony_ci  for (ss = first_scanner; ss; ss = ss->next)
1736141cc406Sopenharmony_ci    {
1737141cc406Sopenharmony_ci      if (strcmp (pixma_get_string (ss->s, PIXMA_STRING_ID), name) == 0)
1738141cc406Sopenharmony_ci        {
1739141cc406Sopenharmony_ci          /* We have already opened it! */
1740141cc406Sopenharmony_ci          return SANE_STATUS_DEVICE_BUSY;
1741141cc406Sopenharmony_ci        }
1742141cc406Sopenharmony_ci    }
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  i = 0;
1745141cc406Sopenharmony_ci  while (strcmp (pixma_get_device_id (i), name) != 0)
1746141cc406Sopenharmony_ci    {
1747141cc406Sopenharmony_ci      if (++i >= nscanners)
1748141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
1749141cc406Sopenharmony_ci    }
1750141cc406Sopenharmony_ci  cfg = pixma_get_device_config (i);
1751141cc406Sopenharmony_ci  if ((cfg->cap & PIXMA_CAP_EXPERIMENT) != 0)
1752141cc406Sopenharmony_ci    {
1753141cc406Sopenharmony_ci#ifndef NDEBUG
1754141cc406Sopenharmony_ci      pixma_dbg (1, "WARNING:"
1755141cc406Sopenharmony_ci		 "Experimental backend CAN DAMAGE your hardware!\n");
1756141cc406Sopenharmony_ci      if (getenv_atoi ("PIXMA_EXPERIMENT", 0) == 0)
1757141cc406Sopenharmony_ci        {
1758141cc406Sopenharmony_ci          pixma_dbg (1, "Experimental SANE backend for %s is disabled "
1759141cc406Sopenharmony_ci               "by default.\n", pixma_get_device_model (i));
1760141cc406Sopenharmony_ci          pixma_dbg (1, "To enable it, set the environment variable "
1761141cc406Sopenharmony_ci               "PIXMA_EXPERIMENT to non-zero.\n");
1762141cc406Sopenharmony_ci          return SANE_STATUS_UNSUPPORTED;
1763141cc406Sopenharmony_ci        }
1764141cc406Sopenharmony_ci#else
1765141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1766141cc406Sopenharmony_ci#endif
1767141cc406Sopenharmony_ci    }
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci  ss = (pixma_sane_t *) calloc (1, sizeof (*ss));
1770141cc406Sopenharmony_ci  if (!ss)
1771141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1772141cc406Sopenharmony_ci  ss->next = first_scanner;
1773141cc406Sopenharmony_ci  first_scanner = ss;
1774141cc406Sopenharmony_ci  sanei_thread_initialize (ss->reader_taskid);
1775141cc406Sopenharmony_ci  ss->wpipe = -1;
1776141cc406Sopenharmony_ci  ss->rpipe = -1;
1777141cc406Sopenharmony_ci  ss->idle = SANE_TRUE;
1778141cc406Sopenharmony_ci  ss->scanning = SANE_FALSE;
1779141cc406Sopenharmony_ci  ss->sp.frontend_cancel = SANE_FALSE;
1780141cc406Sopenharmony_ci  for (j=0; j < BUTTON_GROUP_SIZE; j++)
1781141cc406Sopenharmony_ci    ss->button_option_is_cached[j] = 0;
1782141cc406Sopenharmony_ci  error = pixma_open (i, &ss->s);
1783141cc406Sopenharmony_ci  if (error < 0)
1784141cc406Sopenharmony_ci    {
1785141cc406Sopenharmony_ci      sane_close (ss);
1786141cc406Sopenharmony_ci      return map_error (error);
1787141cc406Sopenharmony_ci    }
1788141cc406Sopenharmony_ci  pixma_enable_background (ss->s, 0);
1789141cc406Sopenharmony_ci  init_option_descriptors (ss);
1790141cc406Sopenharmony_ci  *h = ss;
1791141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1792141cc406Sopenharmony_ci}
1793141cc406Sopenharmony_ci
1794141cc406Sopenharmony_civoid
1795141cc406Sopenharmony_cisane_close (SANE_Handle h)
1796141cc406Sopenharmony_ci{
1797141cc406Sopenharmony_ci  pixma_sane_t **p, *ss;
1798141cc406Sopenharmony_ci
1799141cc406Sopenharmony_ci  for (p = &first_scanner; *p && *p != (pixma_sane_t *) h; p = &((*p)->next))
1800141cc406Sopenharmony_ci    {
1801141cc406Sopenharmony_ci    }
1802141cc406Sopenharmony_ci  if (!(*p))
1803141cc406Sopenharmony_ci    return;
1804141cc406Sopenharmony_ci  ss = *p;
1805141cc406Sopenharmony_ci  sane_cancel (ss);
1806141cc406Sopenharmony_ci  pixma_close (ss->s);
1807141cc406Sopenharmony_ci  *p = ss->next;
1808141cc406Sopenharmony_ci  free (ss);
1809141cc406Sopenharmony_ci}
1810141cc406Sopenharmony_ci
1811141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1812141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int n)
1813141cc406Sopenharmony_ci{
1814141cc406Sopenharmony_ci  DECL_CTX;
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci  if (ss && 0 <= n && n < opt_last)
1817141cc406Sopenharmony_ci    return &SOD (n);
1818141cc406Sopenharmony_ci  return NULL;
1819141cc406Sopenharmony_ci}
1820141cc406Sopenharmony_ci
1821141cc406Sopenharmony_ciSANE_Status
1822141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int n,
1823141cc406Sopenharmony_ci		     SANE_Action a, void *v, SANE_Int * i)
1824141cc406Sopenharmony_ci{
1825141cc406Sopenharmony_ci  DECL_CTX;
1826141cc406Sopenharmony_ci  SANE_Int info = 0;
1827141cc406Sopenharmony_ci  int error;
1828141cc406Sopenharmony_ci  option_descriptor_t *opt;
1829141cc406Sopenharmony_ci
1830141cc406Sopenharmony_ci  if (i)
1831141cc406Sopenharmony_ci    *i = 0;
1832141cc406Sopenharmony_ci  if (!ss)
1833141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1834141cc406Sopenharmony_ci  if (n < 0 || n >= opt_last)
1835141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1836141cc406Sopenharmony_ci  if (!ss->idle && a != SANE_ACTION_GET_VALUE)
1837141cc406Sopenharmony_ci    {
1838141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "Warning: !idle && !SANE_ACTION_GET_VALUE\n"));
1839141cc406Sopenharmony_ci      if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
1840141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
1841141cc406Sopenharmony_ci    }
1842141cc406Sopenharmony_ci
1843141cc406Sopenharmony_ci  opt = &(OPT_IN_CTX[n]);
1844141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (opt->sod.cap))
1845141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1846141cc406Sopenharmony_ci  switch (a)
1847141cc406Sopenharmony_ci    {
1848141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
1849141cc406Sopenharmony_ci      if ((opt->sod.type != SANE_TYPE_BUTTON && !v) ||
1850141cc406Sopenharmony_ci          !SANE_OPTION_IS_SETTABLE (opt->sod.cap))
1851141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
1852141cc406Sopenharmony_ci      break;
1853141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
1854141cc406Sopenharmony_ci      if (!(opt->sod.cap & SANE_CAP_AUTOMATIC) ||
1855141cc406Sopenharmony_ci          !SANE_OPTION_IS_SETTABLE (opt->sod.cap))
1856141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
1857141cc406Sopenharmony_ci      break;
1858141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
1859141cc406Sopenharmony_ci      if (!v || !(opt->sod.cap & SANE_CAP_SOFT_DETECT))
1860141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
1861141cc406Sopenharmony_ci      break;
1862141cc406Sopenharmony_ci    default:
1863141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1864141cc406Sopenharmony_ci    }
1865141cc406Sopenharmony_ci
1866141cc406Sopenharmony_ci  error = control_option (ss, n, a, v, &info);
1867141cc406Sopenharmony_ci  if (error == SANE_STATUS_GOOD && i)
1868141cc406Sopenharmony_ci    *i = info;
1869141cc406Sopenharmony_ci  return error;
1870141cc406Sopenharmony_ci}
1871141cc406Sopenharmony_ci
1872141cc406Sopenharmony_ciSANE_Status
1873141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters * p)
1874141cc406Sopenharmony_ci{
1875141cc406Sopenharmony_ci  DECL_CTX;
1876141cc406Sopenharmony_ci  pixma_scan_param_t temp, *sp;
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci  if (!ss || !p)
1879141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1880141cc406Sopenharmony_ci
1881141cc406Sopenharmony_ci  if (!ss->idle)
1882141cc406Sopenharmony_ci    {
1883141cc406Sopenharmony_ci      sp = &ss->sp;		/* sp is calculated in sane_start() */
1884141cc406Sopenharmony_ci    }
1885141cc406Sopenharmony_ci  else
1886141cc406Sopenharmony_ci    {
1887141cc406Sopenharmony_ci      calc_scan_param (ss, &temp);
1888141cc406Sopenharmony_ci      sp = &temp;
1889141cc406Sopenharmony_ci    }
1890141cc406Sopenharmony_ci  p->format = (sp->channels == 3) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
1891141cc406Sopenharmony_ci  p->last_frame = SANE_TRUE;
1892141cc406Sopenharmony_ci  p->lines = sp->h;
1893141cc406Sopenharmony_ci  p->depth = sp->depth;
1894141cc406Sopenharmony_ci  p->pixels_per_line = sp->w;
1895141cc406Sopenharmony_ci  /* p->bytes_per_line = sp->line_size; NOTE: It should work this way, but it doesn't. No SANE frontend can cope with this. */
1896141cc406Sopenharmony_ci  p->bytes_per_line = (sp->w * sp->channels * sp->depth) / 8;
1897141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1898141cc406Sopenharmony_ci}
1899141cc406Sopenharmony_ci
1900141cc406Sopenharmony_ciSANE_Status
1901141cc406Sopenharmony_cisane_start (SANE_Handle h)
1902141cc406Sopenharmony_ci{
1903141cc406Sopenharmony_ci  DECL_CTX;
1904141cc406Sopenharmony_ci  int error = 0;
1905141cc406Sopenharmony_ci
1906141cc406Sopenharmony_ci  if (!ss)
1907141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1908141cc406Sopenharmony_ci  if (!ss->idle && ss->scanning)
1909141cc406Sopenharmony_ci    {
1910141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "Warning in Sane_start: !idle && scanning. idle=%d, ss->scanning=%d\n",
1911141cc406Sopenharmony_ci                       ss->idle, ss->scanning));
1912141cc406Sopenharmony_ci      if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
1913141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
1914141cc406Sopenharmony_ci    }
1915141cc406Sopenharmony_ci
1916141cc406Sopenharmony_ci  ss->cancel = SANE_FALSE;
1917141cc406Sopenharmony_ci  if (ss->idle ||
1918141cc406Sopenharmony_ci      ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED ||
1919141cc406Sopenharmony_ci      ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU)
1920141cc406Sopenharmony_ci    ss->page_count = 0;	/* start from idle state or scan from flatbed or TPU */
1921141cc406Sopenharmony_ci  else
1922141cc406Sopenharmony_ci    ss->page_count++;
1923141cc406Sopenharmony_ci  if (calc_scan_param (ss, &ss->sp) < 0)
1924141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci  /* Prepare the JPEG decompressor, if needed */
1927141cc406Sopenharmony_ci  if (ss->sp.mode_jpeg)
1928141cc406Sopenharmony_ci    {
1929141cc406Sopenharmony_ci      SANE_Status status;
1930141cc406Sopenharmony_ci      status = pixma_jpeg_start(ss);
1931141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1932141cc406Sopenharmony_ci        {
1933141cc406Sopenharmony_ci          PDBG (pixma_dbg(1, "%s: pixma_jpeg_start: %s\n", __func__, sane_strstatus(status)) );
1934141cc406Sopenharmony_ci          return status;
1935141cc406Sopenharmony_ci        }
1936141cc406Sopenharmony_ci    }
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_ci  ss->image_bytes_read = 0;
1939141cc406Sopenharmony_ci  /* TODO: Check paper here in sane_start(). A function like
1940141cc406Sopenharmony_ci     pixma_get_status() is needed. */
1941141cc406Sopenharmony_ci  error = start_reader_task (ss);
1942141cc406Sopenharmony_ci  if (error >= 0)
1943141cc406Sopenharmony_ci    {
1944141cc406Sopenharmony_ci      ss->output_line_size = (ss->sp.w * ss->sp.channels * ss->sp.depth) / 8;
1945141cc406Sopenharmony_ci      ss->byte_pos_in_line = 0;
1946141cc406Sopenharmony_ci      ss->last_read_status = SANE_STATUS_GOOD;
1947141cc406Sopenharmony_ci      ss->scanning = SANE_TRUE;
1948141cc406Sopenharmony_ci      ss->idle = SANE_FALSE;
1949141cc406Sopenharmony_ci      if (ss->sp.mode_jpeg && !ss->jpeg_header_seen)
1950141cc406Sopenharmony_ci        {
1951141cc406Sopenharmony_ci          SANE_Status status;
1952141cc406Sopenharmony_ci          status = pixma_jpeg_read_header(ss);
1953141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
1954141cc406Sopenharmony_ci            {
1955141cc406Sopenharmony_ci              close (ss->rpipe);
1956141cc406Sopenharmony_ci              pixma_jpeg_finish(ss);
1957141cc406Sopenharmony_ci              ss->rpipe = -1;
1958141cc406Sopenharmony_ci              if (sanei_thread_is_valid (terminate_reader_task (ss, &error))
1959141cc406Sopenharmony_ci                && error != SANE_STATUS_GOOD)
1960141cc406Sopenharmony_ci                {
1961141cc406Sopenharmony_ci                  return error;
1962141cc406Sopenharmony_ci                }
1963141cc406Sopenharmony_ci            }
1964141cc406Sopenharmony_ci        }
1965141cc406Sopenharmony_ci    }
1966141cc406Sopenharmony_ci  return map_error (error);
1967141cc406Sopenharmony_ci}
1968141cc406Sopenharmony_ci
1969141cc406Sopenharmony_ciSANE_Status
1970141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
1971141cc406Sopenharmony_ci{
1972141cc406Sopenharmony_ci  DECL_CTX;
1973141cc406Sopenharmony_ci  int sum, n;
1974141cc406Sopenharmony_ci  /* Due to 32 pixels alignment, sizeof(temp) is to be greater than:
1975141cc406Sopenharmony_ci   * max(nchannels) * max (sp.line_size - output_line_size)
1976141cc406Sopenharmony_ci   * so currently: 3 * 32 = 96  for better end line cropping efficiency */
1977141cc406Sopenharmony_ci  SANE_Byte temp[100];
1978141cc406Sopenharmony_ci  SANE_Status status;
1979141cc406Sopenharmony_ci
1980141cc406Sopenharmony_ci  if (len)
1981141cc406Sopenharmony_ci    *len = 0;
1982141cc406Sopenharmony_ci  if (!ss || !buf || !len)
1983141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1984141cc406Sopenharmony_ci  if (ss->cancel)
1985141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
1986141cc406Sopenharmony_ci  if ((ss->idle)
1987141cc406Sopenharmony_ci      && (ss->sp.source == PIXMA_SOURCE_ADF || ss->sp.source == PIXMA_SOURCE_ADFDUP))
1988141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1989141cc406Sopenharmony_ci  if (!ss->scanning)
1990141cc406Sopenharmony_ci    return ss->last_read_status;
1991141cc406Sopenharmony_ci
1992141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
1993141cc406Sopenharmony_ci  /* CCD scanners use software lineart
1994141cc406Sopenharmony_ci   * the scanner must scan 24 bit color or 8 bit grayscale for one bit lineart */
1995141cc406Sopenharmony_ci  if ((ss->sp.line_size - ((ss->sp.software_lineart == 1) ? (ss->output_line_size * 8) : ss->output_line_size)) == 0)
1996141cc406Sopenharmony_ci    {
1997141cc406Sopenharmony_ci      status = read_image (ss, buf, maxlen, &sum);
1998141cc406Sopenharmony_ci    }
1999141cc406Sopenharmony_ci  else
2000141cc406Sopenharmony_ci    {
2001141cc406Sopenharmony_ci      /* FIXME: Because there is no frontend that can cope with padding at
2002141cc406Sopenharmony_ci         the end of line, we've to remove it here in the backend! */
2003141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "*sane_read***** Warning: padding may cause incomplete scan results\n"));
2004141cc406Sopenharmony_ci      sum = 0;
2005141cc406Sopenharmony_ci      while (sum < maxlen)
2006141cc406Sopenharmony_ci        {
2007141cc406Sopenharmony_ci          if (ss->byte_pos_in_line < ss->output_line_size)
2008141cc406Sopenharmony_ci            {
2009141cc406Sopenharmony_ci              n = ss->output_line_size - ss->byte_pos_in_line;
2010141cc406Sopenharmony_ci              if ((maxlen - sum) < n)
2011141cc406Sopenharmony_ci                n = maxlen - sum;
2012141cc406Sopenharmony_ci              status = read_image (ss, buf, n, &n);
2013141cc406Sopenharmony_ci              if (n == 0)
2014141cc406Sopenharmony_ci                break;
2015141cc406Sopenharmony_ci              sum += n;
2016141cc406Sopenharmony_ci              buf += n;
2017141cc406Sopenharmony_ci              ss->byte_pos_in_line += n;
2018141cc406Sopenharmony_ci            }
2019141cc406Sopenharmony_ci          else
2020141cc406Sopenharmony_ci            {
2021141cc406Sopenharmony_ci              /* skip padding */
2022141cc406Sopenharmony_ci              n = ss->sp.line_size - ss->byte_pos_in_line;
2023141cc406Sopenharmony_ci              if (n > (int) sizeof (temp))
2024141cc406Sopenharmony_ci                {
2025141cc406Sopenharmony_ci                  PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n));
2026141cc406Sopenharmony_ci                  n = sizeof (temp);
2027141cc406Sopenharmony_ci                }
2028141cc406Sopenharmony_ci              status = read_image (ss, temp, n, &n);
2029141cc406Sopenharmony_ci              if (n == 0)
2030141cc406Sopenharmony_ci                break;
2031141cc406Sopenharmony_ci              ss->byte_pos_in_line += n;
2032141cc406Sopenharmony_ci              if (ss->byte_pos_in_line == ss->sp.line_size)
2033141cc406Sopenharmony_ci                ss->byte_pos_in_line = 0;
2034141cc406Sopenharmony_ci             }
2035141cc406Sopenharmony_ci        }
2036141cc406Sopenharmony_ci    }
2037141cc406Sopenharmony_ci  if (ss->cancel)
2038141cc406Sopenharmony_ci    status = SANE_STATUS_CANCELLED;
2039141cc406Sopenharmony_ci  else if ((status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF) &&
2040141cc406Sopenharmony_ci	   sum > 0)
2041141cc406Sopenharmony_ci    {
2042141cc406Sopenharmony_ci      *len = sum;
2043141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2044141cc406Sopenharmony_ci    }
2045141cc406Sopenharmony_ci  ss->scanning = (status == SANE_STATUS_GOOD);
2046141cc406Sopenharmony_ci  ss->last_read_status = status;
2047141cc406Sopenharmony_ci  return status;
2048141cc406Sopenharmony_ci}
2049141cc406Sopenharmony_ci
2050141cc406Sopenharmony_civoid
2051141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
2052141cc406Sopenharmony_ci{
2053141cc406Sopenharmony_ci  DECL_CTX;
2054141cc406Sopenharmony_ci
2055141cc406Sopenharmony_ci  if (!ss)
2056141cc406Sopenharmony_ci    return;
2057141cc406Sopenharmony_ci  ss->cancel = SANE_TRUE;
2058141cc406Sopenharmony_ci  ss->sp.frontend_cancel = SANE_TRUE;
2059141cc406Sopenharmony_ci  if (ss->idle)
2060141cc406Sopenharmony_ci    return;
2061141cc406Sopenharmony_ci  close (ss->rpipe);
2062141cc406Sopenharmony_ci  if (ss->sp.mode_jpeg)
2063141cc406Sopenharmony_ci    pixma_jpeg_finish(ss);
2064141cc406Sopenharmony_ci  ss->rpipe = -1;
2065141cc406Sopenharmony_ci  terminate_reader_task (ss, NULL);
2066141cc406Sopenharmony_ci  ss->idle = SANE_TRUE;
2067141cc406Sopenharmony_ci}
2068141cc406Sopenharmony_ci
2069141cc406Sopenharmony_ciSANE_Status
2070141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool m)
2071141cc406Sopenharmony_ci{
2072141cc406Sopenharmony_ci  DECL_CTX;
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_ci  if (!ss || ss->idle || ss->rpipe == -1)
2075141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2076141cc406Sopenharmony_ci#ifdef HAVE_FCNTL_H
2077141cc406Sopenharmony_ci  PDBG (pixma_dbg (2, "Setting %sblocking mode\n", (m) ? "non-" : ""));
2078141cc406Sopenharmony_ci  if (fcntl (ss->rpipe, F_SETFL, (m) ? O_NONBLOCK : 0) == -1)
2079141cc406Sopenharmony_ci    {
2080141cc406Sopenharmony_ci      PDBG (pixma_dbg
2081141cc406Sopenharmony_ci	    (1, "WARNING:fcntl(F_SETFL) failed %s\n", strerror (errno)));
2082141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2083141cc406Sopenharmony_ci    }
2084141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2085141cc406Sopenharmony_ci#else
2086141cc406Sopenharmony_ci  return (m) ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD;
2087141cc406Sopenharmony_ci#endif
2088141cc406Sopenharmony_ci}
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ciSANE_Status
2091141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fd)
2092141cc406Sopenharmony_ci{
2093141cc406Sopenharmony_ci  DECL_CTX;
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci  *fd = -1;
2096141cc406Sopenharmony_ci  if (!ss || !fd || ss->idle || ss->rpipe == -1)
2097141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2098141cc406Sopenharmony_ci  *fd = ss->rpipe;
2099141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2100141cc406Sopenharmony_ci}
2101141cc406Sopenharmony_ci
2102141cc406Sopenharmony_ci/* CAUTION!
2103141cc406Sopenharmony_ci * Remove generated files pixma_sane_options.[ch] after editing SANE option
2104141cc406Sopenharmony_ci * descriptors below OR do a 'make clean' OR manually generate them as described
2105141cc406Sopenharmony_ci * below.
2106141cc406Sopenharmony_ci * However, make drops the circular dependency and the files won't be generated
2107141cc406Sopenharmony_ci * again (see merge request sane-project/backends!491).
2108141cc406Sopenharmony_ci
2109141cc406Sopenharmony_ciBEGIN SANE_Option_Descriptor
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_cirem -------------------------------------------
2112141cc406Sopenharmony_citype group
2113141cc406Sopenharmony_ci  title Scan mode
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_citype int resolution
2116141cc406Sopenharmony_ci  unit dpi
2117141cc406Sopenharmony_ci  constraint @word_list = ss->dpi_list
2118141cc406Sopenharmony_ci  default 75
2119141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_RESOLUTION
2120141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_RESOLUTION
2121141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2122141cc406Sopenharmony_ci  info reload_params
2123141cc406Sopenharmony_ci
2124141cc406Sopenharmony_citype string mode[30]
2125141cc406Sopenharmony_ci  constraint @string_list = ss->mode_list
2126141cc406Sopenharmony_ci  default @s = SANE_VALUE_SCAN_MODE_COLOR
2127141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_MODE
2128141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_MODE
2129141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2130141cc406Sopenharmony_ci  info reload_params
2131141cc406Sopenharmony_ci
2132141cc406Sopenharmony_citype string source[30]
2133141cc406Sopenharmony_ci  constraint @string_list = ss->source_list
2134141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_SOURCE
2135141cc406Sopenharmony_ci  desc  Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values.
2136141cc406Sopenharmony_ci  default Flatbed
2137141cc406Sopenharmony_ci  cap soft_select soft_detect
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_citype bool button-controlled
2140141cc406Sopenharmony_ci  title Button-controlled scan
2141141cc406Sopenharmony_ci  desc When enabled, scan process will not start immediately. To proceed, press \"SCAN\" button (for MP150) or \"COLOR\" button (for other models). To cancel, press \"GRAY\" button.
2142141cc406Sopenharmony_ci  default SANE_FALSE
2143141cc406Sopenharmony_ci  cap soft_select soft_detect inactive
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_cirem -------------------------------------------
2146141cc406Sopenharmony_citype group
2147141cc406Sopenharmony_ci  title Gamma
2148141cc406Sopenharmony_ci
2149141cc406Sopenharmony_citype bool custom-gamma
2150141cc406Sopenharmony_ci  default SANE_FALSE
2151141cc406Sopenharmony_ci  title @SANE_TITLE_CUSTOM_GAMMA
2152141cc406Sopenharmony_ci  desc  @SANE_DESC_CUSTOM_GAMMA
2153141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2154141cc406Sopenharmony_ci
2155141cc406Sopenharmony_citype int gamma-table[1024]
2156141cc406Sopenharmony_ci  constraint (0,0xffff,0)
2157141cc406Sopenharmony_ci  title @SANE_TITLE_GAMMA_VECTOR
2158141cc406Sopenharmony_ci  desc  Gamma-correction table with 1024 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table).
2159141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2160141cc406Sopenharmony_ci
2161141cc406Sopenharmony_citype fixed gamma
2162141cc406Sopenharmony_ci  default AUTO_GAMMA
2163141cc406Sopenharmony_ci  constraint (0.3,5,0)
2164141cc406Sopenharmony_ci  title Gamma function exponent
2165141cc406Sopenharmony_ci  desc  Changes intensity of midtones
2166141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2167141cc406Sopenharmony_ci
2168141cc406Sopenharmony_cirem -------------------------------------------
2169141cc406Sopenharmony_citype group
2170141cc406Sopenharmony_ci  title Geometry
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_citype fixed tl-x
2173141cc406Sopenharmony_ci  unit mm
2174141cc406Sopenharmony_ci  default 0
2175141cc406Sopenharmony_ci  constraint @range = &ss->xrange
2176141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_TL_X
2177141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_TL_X
2178141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2179141cc406Sopenharmony_ci  info reload_params
2180141cc406Sopenharmony_ci
2181141cc406Sopenharmony_citype fixed tl-y
2182141cc406Sopenharmony_ci  unit mm
2183141cc406Sopenharmony_ci  default 0
2184141cc406Sopenharmony_ci  constraint @range = &ss->yrange
2185141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_TL_Y
2186141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_TL_Y
2187141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2188141cc406Sopenharmony_ci  info reload_params
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_citype fixed br-x
2191141cc406Sopenharmony_ci  unit mm
2192141cc406Sopenharmony_ci  default _MAX
2193141cc406Sopenharmony_ci  constraint @range = &ss->xrange
2194141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_BR_X
2195141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_BR_X
2196141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2197141cc406Sopenharmony_ci  info reload_params
2198141cc406Sopenharmony_ci
2199141cc406Sopenharmony_citype fixed br-y
2200141cc406Sopenharmony_ci  unit mm
2201141cc406Sopenharmony_ci  default _MAX
2202141cc406Sopenharmony_ci  constraint @range = &ss->yrange
2203141cc406Sopenharmony_ci  title @SANE_TITLE_SCAN_BR_Y
2204141cc406Sopenharmony_ci  desc  @SANE_DESC_SCAN_BR_Y
2205141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2206141cc406Sopenharmony_ci  info reload_params
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_cirem -------------------------------------------
2209141cc406Sopenharmony_citype group
2210141cc406Sopenharmony_ci  title Buttons
2211141cc406Sopenharmony_ci
2212141cc406Sopenharmony_citype button button-update
2213141cc406Sopenharmony_ci  title Update button state
2214141cc406Sopenharmony_ci  cap soft_select soft_detect advanced
2215141cc406Sopenharmony_ci
2216141cc406Sopenharmony_citype int button-1
2217141cc406Sopenharmony_ci  default 0
2218141cc406Sopenharmony_ci  title Button 1
2219141cc406Sopenharmony_ci  cap soft_detect advanced
2220141cc406Sopenharmony_ci
2221141cc406Sopenharmony_citype int button-2
2222141cc406Sopenharmony_ci  default 0
2223141cc406Sopenharmony_ci  title Button 2
2224141cc406Sopenharmony_ci  cap soft_detect advanced
2225141cc406Sopenharmony_ci
2226141cc406Sopenharmony_citype int original
2227141cc406Sopenharmony_ci  default 0
2228141cc406Sopenharmony_ci  title Type of original to scan
2229141cc406Sopenharmony_ci  cap soft_detect advanced
2230141cc406Sopenharmony_ci
2231141cc406Sopenharmony_citype int target
2232141cc406Sopenharmony_ci  default 0
2233141cc406Sopenharmony_ci  title Target operation type
2234141cc406Sopenharmony_ci  cap soft_detect advanced
2235141cc406Sopenharmony_ci
2236141cc406Sopenharmony_citype int scan-resolution
2237141cc406Sopenharmony_ci  default 0
2238141cc406Sopenharmony_ci  title Scan resolution
2239141cc406Sopenharmony_ci  cap soft_detect advanced
2240141cc406Sopenharmony_ci
2241141cc406Sopenharmony_citype int document-type
2242141cc406Sopenharmony_ci  default 0
2243141cc406Sopenharmony_ci  title Document type
2244141cc406Sopenharmony_ci  cap soft_detect advanced
2245141cc406Sopenharmony_ci
2246141cc406Sopenharmony_citype int adf-status
2247141cc406Sopenharmony_ci  default 0
2248141cc406Sopenharmony_ci  title ADF status
2249141cc406Sopenharmony_ci  cap soft_detect advanced
2250141cc406Sopenharmony_ci
2251141cc406Sopenharmony_citype int adf-orientation
2252141cc406Sopenharmony_ci  default 0
2253141cc406Sopenharmony_ci  title ADF orientation
2254141cc406Sopenharmony_ci  cap soft_detect advanced
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_cirem -------------------------------------------
2257141cc406Sopenharmony_citype group
2258141cc406Sopenharmony_ci  title Extras
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_citype int threshold
2261141cc406Sopenharmony_ci  unit PERCENT
2262141cc406Sopenharmony_ci  default 50
2263141cc406Sopenharmony_ci  constraint (0,100,1)
2264141cc406Sopenharmony_ci  title @SANE_TITLE_THRESHOLD
2265141cc406Sopenharmony_ci  desc  @SANE_DESC_THRESHOLD
2266141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2267141cc406Sopenharmony_ci
2268141cc406Sopenharmony_citype int threshold-curve
2269141cc406Sopenharmony_ci  constraint (0,127,1)
2270141cc406Sopenharmony_ci  title Threshold curve
2271141cc406Sopenharmony_ci  desc  Dynamic threshold curve, from light to dark, normally 50-65
2272141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2273141cc406Sopenharmony_ci
2274141cc406Sopenharmony_citype int adf-wait
2275141cc406Sopenharmony_ci  default 0
2276141cc406Sopenharmony_ci  constraint (0,3600,1)
2277141cc406Sopenharmony_ci  title ADF Waiting Time
2278141cc406Sopenharmony_ci  desc  When set, the scanner waits up to the specified time in seconds for a new document inserted into the automatic document feeder.
2279141cc406Sopenharmony_ci  cap soft_select soft_detect automatic inactive
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_citype string calibrate[30]
2282141cc406Sopenharmony_ci  constraint @string_list = ss->calibrate_list
2283141cc406Sopenharmony_ci  title Calibration
2284141cc406Sopenharmony_ci  desc When to perform scanner calibration. If you choose \"Once\" it will be performed a single time per driver init for single page scans, and for the first page for each ADF scan.
2285141cc406Sopenharmony_ci  default Once
2286141cc406Sopenharmony_ci  cap soft_select soft_detect automatic
2287141cc406Sopenharmony_ci
2288141cc406Sopenharmony_cirem -------------------------------------------
2289141cc406Sopenharmony_ciEND SANE_Option_Descriptor
2290141cc406Sopenharmony_ci*/
2291141cc406Sopenharmony_ci
2292141cc406Sopenharmony_ci/* pixma_sane_options.c generated by
2293141cc406Sopenharmony_ci * scripts/pixma_gen_options.py < pixma.c > pixma_sane_options.c
2294141cc406Sopenharmony_ci *
2295141cc406Sopenharmony_ci * pixma_sane_options.h generated by
2296141cc406Sopenharmony_ci * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h
2297141cc406Sopenharmony_ci */
2298141cc406Sopenharmony_ci#include "pixma_sane_options.c"
2299