xref: /third_party/backends/backend/apple.c (revision 141cc406)
1/* sane - Scanner Access Now Easy.
2
3   Copyright (C) 1998 Milon Firikis based on David Mosberger-Tang previous
4   Work on mustek.c file from the SANE package.
5
6   This file is part of the SANE package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
21   As a special exception, the authors of SANE give permission for
22   additional uses of the libraries contained in this release of SANE.
23
24   The exception is that, if you link a SANE library with other files
25   to produce an executable, this does not by itself cause the
26   resulting executable to be covered by the GNU General Public
27   License.  Your use of that executable is in no way restricted on
28   account of linking the SANE library code into it.
29
30   This exception does not, however, invalidate any other reasons why
31   the executable file might be covered by the GNU General Public
32   License.
33
34   If you submit changes to SANE to the maintainers to be included in
35   a subsequent release, you agree by submitting the changes that
36   those changes may be distributed with this exception intact.
37
38   If you write modifications of your own for SANE, it is your choice
39   whether to permit this exception to apply to your modifications.
40   If you do not wish that, delete this exception notice.
41
42   This file implements a SANE backend for Apple flatbed scanners.  */
43
44#include "../include/sane/config.h"
45
46#include <ctype.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <limits.h>
50#include <signal.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <unistd.h>
55
56#include <sys/time.h>
57#include <sys/types.h>
58#include <sys/wait.h>
59
60#include "../include/_stdint.h"
61
62#include "../include/sane/sane.h"
63#include "../include/sane/sanei.h"
64#include "../include/sane/saneopts.h"
65#include "../include/sane/sanei_scsi.h"
66
67
68/* SCSI commands that the Apple scanners understand: */
69#define APPLE_SCSI_TEST_UNIT_READY	0x00
70#define APPLE_SCSI_REQUEST_SENSE	0x03
71#define APPLE_SCSI_INQUIRY		0x12
72#define APPLE_SCSI_MODE_SELECT		0x15
73#define APPLE_SCSI_RESERVE		0x16
74#define APPLE_SCSI_RELEASE		0x17
75#define APPLE_SCSI_START		0x1b
76#define APPLE_SCSI_AREA_AND_WINDOWS	0x24
77#define APPLE_SCSI_READ_SCANNED_DATA	0x28
78#define APPLE_SCSI_GET_DATA_STATUS	0x34
79
80
81#define INQ_LEN	0x60
82
83#define ENABLE(OPTION)  s->opt[OPTION].cap &= ~SANE_CAP_INACTIVE
84#define DISABLE(OPTION) s->opt[OPTION].cap |=  SANE_CAP_INACTIVE
85#define IS_ACTIVE(OPTION) (((s->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0)
86
87#define XQSTEP(XRES,BPP) (SANE_Int) (((double) (8*1200)) / ((double) (XRES*BPP)))
88#define YQSTEP(YRES) (SANE_Int) (((double) (1200)) / ((double) (YRES)))
89
90
91/* Very low info, Apple Scanners only */
92
93/* TODO: Ok I admit it. I am not so clever to do this operations with bitwised
94   operators. Sorry. */
95
96#define STORE8(p,v)				\
97  {						\
98  *(p)=(v);					\
99  }
100
101#define STORE16(p,v)				\
102  {						\
103  *(p)=(v)/256;					\
104  *(p+1)=(v-*(p)*256);				\
105  }
106
107#define STORE24(p,v)				\
108  {						\
109  *(p)=(v)/65536;				\
110  *(p+1)=(v-*(p)*65536)/256;			\
111  *(p+2)=(v-*(p)*65536-*(p+1)*256);		\
112  }
113
114
115#define STORE32(p,v)				\
116  {						\
117  *(p)=(v)/16777216;				\
118  *(p+1)=(v-*(p)*16777216)/65536;		\
119  *(p+2)=(v-*(p)*16777216-*(p+1)*65536)/256;	\
120  *(p+3)=(v-*(p)*16777216-*(p+1)*65536-*(p+2)*256);\
121  }
122
123#define READ24(p) *(p)*65536 + *(p+1)*256 + *(p+2)
124
125#include "../include/sane/sanei_backend.h"
126
127#ifndef PATH_MAX
128# define PATH_MAX	1024
129#endif
130
131#include "../include/sane/sanei_config.h"
132#define APPLE_CONFIG_FILE "apple.conf"
133
134#include "apple.h"
135
136
137static const SANE_Device **devlist = 0;
138static int num_devices;
139static Apple_Device *first_dev;
140static Apple_Scanner *first_handle;
141
142
143static SANE_String_Const mode_list[6];
144
145static SANE_String_Const SupportedModel[] =
146{
147"3",
148"AppleScanner 4bit, 16 Shades of Gray",
149"OneScanner 8bit, 256 Shades of Gray",
150"ColorOneScanner, RGB color 8bit per band",
151NULL
152};
153
154static const SANE_String_Const graymap_list[] =
155{
156  "dark", "normal", "light",
157  0
158};
159
160#if 0
161static const SANE_Int resbit4_list[] =
162{
163  5,
164  75, 100, 150, 200, 300
165};
166
167static const SANE_Int resbit1_list[] =
168{
169  17,
170  75, 90, 100, 120, 135, 150, 165, 180, 195,
171  200, 210, 225, 240, 255, 270, 285, 300
172};
173#endif
174
175static const SANE_Int resbit_list[] =
176{
177  5,
178  75, 100, 150, 200, 300
179};
180
181static const SANE_String_Const speed_list[] =
182{
183  "normal", "high", "high wo H/S",
184  0
185};
186
187static SANE_String_Const halftone_pattern_list[6];
188
189static const SANE_String_Const color_sensor_list[] =
190{
191  "All", "Red", "Green", "Blue",
192  0
193};
194
195/* NOTE: This is used for Brightness, Contrast, Threshold, AutoBackAdj
196   and 0 is the default value */
197static const SANE_Range byte_range =
198{
199  1, 255, 1
200};
201
202static const SANE_Range u8_range =
203{
204  0,				/* minimum */
205  255,				/* maximum */
206  0				/* quantization */
207};
208
209
210/* NOTE: However I can select from different lists during the hardware
211   probing time. */
212
213
214
215
216static const uint8_t inquiry[] =
217{
218  APPLE_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00
219};
220
221static const uint8_t test_unit_ready[] =
222{
223  APPLE_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00
224};
225
226
227#if 0
228SANE_Int
229xqstep (unsigned int Xres, unsigned int bpp)
230{
231  return (SANE_Int) ((double) (8 * 1200)) / ((double) (Xres * bpp));
232}
233
234
235SANE_Int
236yqstep (unsigned int Yres, unsigned int bpp)
237{
238  return (SANE_Int) ((double) (1200)) / ((double) (Yres));
239}
240#endif
241
242
243
244/* The functions below return the quantized value of x,y in scanners dots
245   aka 1/1200 of an inch */
246
247static SANE_Int
248xquant (double x, unsigned int Xres, unsigned int bpp, int dir)
249{
250  double tmp;
251  unsigned int t;
252
253  tmp = (double) x *Xres * bpp / (double) 8;
254  t = (unsigned int) tmp;
255
256  if (tmp - ((double) t) >= 0.1)
257    if (dir)
258      t++;;
259
260  return t * 8 * 1200 / (Xres * bpp);
261}
262
263
264
265static SANE_Int
266yquant (double y, unsigned int Yres, int dir)
267{
268  double tmp;
269  unsigned int t;
270
271  tmp = (double) y *Yres;
272  t = (unsigned int) tmp;
273
274  if (tmp - ((double) t) >= 0.1)
275    if (dir)
276      t++;;
277
278  return t * 1200 / Yres;
279}
280
281static SANE_Status
282wait_ready (int fd)
283{
284#define MAX_WAITING_TIME	60	/* one minute, at most */
285  struct timeval now, start;
286  SANE_Status status;
287
288#ifdef NEUTRALIZE_BACKEND
289return SANE_STATUS_GOOD;
290#else
291
292  gettimeofday (&start, 0);
293
294  while (1)
295    {
296      DBG (USER_MESSAGE, "wait_ready: sending TEST_UNIT_READY\n");
297
298      status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready),
299			       0, 0);
300      switch (status)
301	{
302	default:
303	  /* Ignore errors while waiting for scanner to become ready.
304	     Some SCSI drivers return EIO while the scanner is
305	     returning to the home position.  */
306	  DBG (ERROR_MESSAGE, "wait_ready: test unit ready failed (%s)\n",
307	       sane_strstatus (status));
308	  /* fall through */
309	case SANE_STATUS_DEVICE_BUSY:
310	  gettimeofday (&now, 0);
311	  if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
312	    {
313	      DBG (ERROR_MESSAGE, "wait_ready: timed out after %lu seconds\n",
314		   (u_long) now.tv_sec - start.tv_sec);
315	      return SANE_STATUS_INVAL;
316	    }
317	  usleep (100000);	/* retry after 100ms */
318	  break;
319
320	case SANE_STATUS_GOOD:
321	  return status;
322	}
323    }
324  return SANE_STATUS_INVAL;
325#endif /* NEUTRALIZE_BACKEND */
326}
327
328static SANE_Status
329sense_handler (int scsi_fd, u_char * result, void *arg)
330{
331  (void) scsi_fd;			/* silence gcc */
332  (void) arg;				/* silence gcc */
333
334  switch (result[2] & 0x0F)
335    {
336    case 0:
337      DBG (USER_MESSAGE, "Sense: No sense Error\n");
338      return SANE_STATUS_GOOD;
339    case 2:
340      DBG (ERROR_MESSAGE, "Sense: Scanner not ready\n");
341      return SANE_STATUS_DEVICE_BUSY;
342    case 4:
343      DBG (ERROR_MESSAGE, "Sense: Hardware Error. Read more...\n");
344      return SANE_STATUS_IO_ERROR;
345    case 5:
346      DBG (ERROR_MESSAGE, "Sense: Illegall request\n");
347      return SANE_STATUS_UNSUPPORTED;
348    case 6:
349      DBG (ERROR_MESSAGE, "Sense: Unit Attention (Wait until scanner "
350	   "boots)\n");
351      return SANE_STATUS_DEVICE_BUSY;
352    case 9:
353      DBG (ERROR_MESSAGE, "Sense: Vendor Unique. Read more...\n");
354      return SANE_STATUS_IO_ERROR;
355    default:
356      DBG (ERROR_MESSAGE, "Sense: Unknown Sense Key. Read more...\n");
357      return SANE_STATUS_IO_ERROR;
358    }
359
360  return SANE_STATUS_GOOD;
361}
362
363
364static SANE_Status
365request_sense (Apple_Scanner * s)
366{
367  uint8_t cmd[6];
368  uint8_t result[22];
369  size_t size = sizeof (result);
370  SANE_Status status;
371
372  memset (cmd, 0, sizeof (cmd));
373  memset (result, 0, sizeof (result));
374
375#ifdef NEUTRALIZE_BACKEND
376return SANE_STATUS_GOOD;
377#else
378
379  cmd[0] = APPLE_SCSI_REQUEST_SENSE;
380  STORE8 (cmd + 4, sizeof (result));
381  sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), result, &size);
382
383  if (result[7] != 14)
384    {
385      DBG (ERROR_MESSAGE, "Additional Length %u\n", (unsigned int) result[7]);
386      status = SANE_STATUS_IO_ERROR;
387    }
388
389
390  status = sense_handler (s->fd, result, NULL);
391  if (status == SANE_STATUS_IO_ERROR)
392    {
393
394/* Now we are checking for Hardware and Vendor Unique Errors for all models */
395/* First check the common Error conditions */
396
397      if (result[18] & 0x80)
398	DBG (ERROR_MESSAGE, "Sense: Dim Light (output of lamp below 70%%).\n");
399
400      if (result[18] & 0x40)
401	DBG (ERROR_MESSAGE, "Sense: No Light at all.\n");
402
403      if (result[18] & 0x20)
404	DBG (ERROR_MESSAGE, "Sense: No Home.\n");
405
406      if (result[18] & 0x10)
407	DBG (ERROR_MESSAGE, "Sense: No Limit. Tried to scan out of range.\n");
408
409
410      switch (s->hw->ScannerModel)
411	{
412	case APPLESCANNER:
413	  if (result[18] & 0x08)
414	    DBG (ERROR_MESSAGE, "Sense: Shade Error. Failed Calibration.\n");
415	  if (result[18] & 0x04)
416	    DBG (ERROR_MESSAGE, "Sense: ROM Error.\n");
417	  if (result[18] & 0x02)
418	    DBG (ERROR_MESSAGE, "Sense: RAM Error.\n");
419	  if (result[18] & 0x01)
420	    DBG (ERROR_MESSAGE, "Sense: CPU Error.\n");
421	  if (result[19] & 0x80)
422	    DBG (ERROR_MESSAGE, "Sense: DIPP Error.\n");
423	  if (result[19] & 0x40)
424	    DBG (ERROR_MESSAGE, "Sense: DMA Error.\n");
425	  if (result[19] & 0x20)
426	    DBG (ERROR_MESSAGE, "Sense: GA1 Error.\n");
427	  break;
428	case ONESCANNER:
429	  if (result[18] & 0x08)
430	    DBG (ERROR_MESSAGE, "Sense: CCD clock generator failed.\n");
431	  if (result[18] & 0x04)
432	    DBG (ERROR_MESSAGE, "Sense: LRAM (Line RAM) Error.\n");
433	  if (result[18] & 0x02)
434	    DBG (ERROR_MESSAGE, "Sense: CRAM (Correction RAM) Error.\n");
435	  if (result[18] & 0x01)
436	    DBG (ERROR_MESSAGE, "Sense: ROM Error.\n");
437	  if (result[19] & 0x08)
438	    DBG (ERROR_MESSAGE, "Sense: SRAM Error.\n");
439	  if (result[19] & 0x04)
440	    DBG (ERROR_MESSAGE, "Sense: CPU Error.\n");
441	  break;
442	case COLORONESCANNER:
443	  if (result[18] & 0x08)
444	    DBG (ERROR_MESSAGE, "Sense: Calibration cirquit cannot "
445		 "support normal shading.\n");
446	  if (result[18] & 0x04)
447	    DBG (ERROR_MESSAGE, "Sense: PSRAM (Correction RAM) Error.\n");
448	  if (result[18] & 0x02)
449	    DBG (ERROR_MESSAGE, "Sense: SRAM Error.\n");
450	  if (result[18] & 0x01)
451	    DBG (ERROR_MESSAGE, "Sense: ROM Error.\n");
452	  if (result[19] & 0x10)
453	    DBG (ERROR_MESSAGE, "Sense: ICP (CPU) Error.\n");
454	  if (result[19] & 0x02)
455	    DBG (ERROR_MESSAGE, "Sense: Over light. (Too bright lamp ?).\n");
456	  break;
457	default:
458	  DBG (ERROR_MESSAGE,
459	       "Sense: Unselected Scanner model. Please report this.\n");
460	  break;
461	}
462    }
463
464  DBG (USER_MESSAGE, "Sense: Optical gain %u.\n", (unsigned int) result[20]);
465  return status;
466#endif /* NEUTRALIZE_BACKEND */
467}
468
469
470
471
472
473static SANE_Status
474attach (const char *devname, Apple_Device ** devp, int may_wait)
475{
476  char result[INQ_LEN];
477  const char *model_name = result + 44;
478  int fd, apple_scanner, fw_revision;
479  Apple_Device *dev;
480  SANE_Status status;
481  size_t size;
482
483  for (dev = first_dev; dev; dev = dev->next)
484    if (strcmp (dev->sane.name, devname) == 0)
485      {
486	if (devp)
487	  *devp = dev;
488	return SANE_STATUS_GOOD;
489      }
490
491  DBG (USER_MESSAGE, "attach: opening %s\n", devname);
492
493#ifdef NEUTRALIZE_BACKEND
494result[0]=0x06;
495strcpy(result +  8, "APPLE   ");
496
497if (APPLE_MODEL_SELECT==APPLESCANNER)
498  strcpy(result + 16, "SCANNER A9M0337 ");
499if (APPLE_MODEL_SELECT==ONESCANNER)
500  strcpy(result + 16, "SCANNER II      ");
501if (APPLE_MODEL_SELECT==COLORONESCANNER)
502  strcpy(result + 16, "SCANNER III     ");
503
504#else
505  status = sanei_scsi_open (devname, &fd, sense_handler, 0);
506  if (status != SANE_STATUS_GOOD)
507    {
508      DBG (ERROR_MESSAGE, "attach: open failed (%s)\n",
509	   sane_strstatus (status));
510      return SANE_STATUS_INVAL;
511    }
512
513  if (may_wait)
514    wait_ready (fd);
515
516  DBG (USER_MESSAGE, "attach: sending INQUIRY\n");
517  size = sizeof (result);
518  status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size);
519  if (status != SANE_STATUS_GOOD)
520    {
521      DBG (ERROR_MESSAGE, "attach: inquiry failed (%s)\n",
522	   sane_strstatus (status));
523      sanei_scsi_close (fd);
524      return status;
525    }
526
527  status = wait_ready (fd);
528  sanei_scsi_close (fd);
529  if (status != SANE_STATUS_GOOD)
530    return status;
531#endif /* NEUTRALIZE_BACKEND */
532
533  /* check for old format: */
534  apple_scanner = (strncmp (result + 8, "APPLE   ", 8) == 0);
535  model_name = result + 16;
536
537  apple_scanner = apple_scanner && (result[0] == 0x06);
538
539  if (!apple_scanner)
540    {
541      DBG (ERROR_MESSAGE, "attach: device doesn't look like an Apple scanner"
542	   "(result[0]=%#02x)\n", result[0]);
543      return SANE_STATUS_INVAL;
544    }
545
546  /* get firmware revision as BCD number: */
547  fw_revision =
548    (result[32] - '0') << 8 | (result[34] - '0') << 4 | (result[35] - '0');
549  DBG (USER_MESSAGE, "attach: firmware revision %d.%02x\n",
550       fw_revision >> 8, fw_revision & 0xff);
551
552  dev = malloc (sizeof (*dev));
553  if (!dev)
554    return SANE_STATUS_NO_MEM;
555
556  memset (dev, 0, sizeof (*dev));
557
558  dev->sane.name = strdup (devname);
559  dev->sane.vendor = "Apple";
560  dev->sane.model = strndup (model_name, 16);
561  dev->sane.type = "flatbed scanner";
562
563  dev->x_range.min = 0;
564  dev->x_range.max = SANE_FIX (8.51 * MM_PER_INCH);
565  dev->x_range.quant = 0;
566
567  dev->y_range.min = 0;
568  dev->y_range.max = SANE_FIX (14.0 * MM_PER_INCH);
569  dev->y_range.quant = 0;
570
571  dev->MaxHeight = 16800;
572
573  if (strncmp (model_name, "SCANNER A9M0337 ", 16) == 0)
574    {
575      dev->ScannerModel = APPLESCANNER;
576      dev->dpi_range.min = SANE_FIX (75);
577      dev->dpi_range.max = SANE_FIX (300);
578      dev->dpi_range.quant = SANE_FIX (1);
579      dev->MaxWidth = 10208;
580    }
581  else if (strncmp (model_name, "SCANNER II      ", 16) == 0)
582    {
583      dev->ScannerModel = ONESCANNER;
584      dev->dpi_range.min = SANE_FIX (72);
585      dev->dpi_range.max = SANE_FIX (300);
586      dev->dpi_range.quant = SANE_FIX (1);
587      dev->MaxWidth = 10200;
588    }
589  else if (strncmp (model_name, "SCANNER III     ", 16) == 0)
590    {
591      dev->ScannerModel = COLORONESCANNER;
592      dev->dpi_range.min = SANE_FIX (72);
593      dev->dpi_range.max = SANE_FIX (300);
594      dev->dpi_range.quant = SANE_FIX (1);
595      dev->MaxWidth = 10200;
596    }
597  else
598    {
599      DBG (ERROR_MESSAGE,
600	   "attach: Cannot found Apple scanner in the neighborhood\n");
601      free (dev);
602      return SANE_STATUS_INVAL;
603    }
604
605  DBG (USER_MESSAGE, "attach: found Apple scanner model %s (%s)\n",
606       dev->sane.model, dev->sane.type);
607
608  ++num_devices;
609  dev->next = first_dev;
610  first_dev = dev;
611
612  if (devp)
613    *devp = dev;
614  return SANE_STATUS_GOOD;
615}
616
617static size_t
618max_string_size (const SANE_String_Const strings[])
619{
620  size_t size, max_size = 0;
621  int i;
622
623  for (i = 0; strings[i]; ++i)
624    {
625      size = strlen (strings[i]) + 1;
626      if (size > max_size)
627	max_size = size;
628    }
629  return max_size;
630}
631
632
633static SANE_Status
634scan_area_and_windows (Apple_Scanner * s)
635{
636  uint8_t cmd[10 + 8 + 42];
637#define CMD cmd + 0
638#define WH  cmd + 10
639#define WP  WH + 8
640
641#ifdef NEUTRALIZE_BACKEND
642return SANE_STATUS_GOOD;
643#else
644
645  /* setup SCSI command (except length): */
646  memset (cmd, 0, sizeof (cmd));
647  cmd[0] = APPLE_SCSI_AREA_AND_WINDOWS;
648
649
650  if (s->hw->ScannerModel == COLORONESCANNER)
651    {
652      STORE24 (CMD + 6, 50);
653      STORE16 (WH + 6, 42);
654    }
655  else
656    {
657      STORE24 (CMD + 6, 48);
658      STORE16 (WH + 6, 40);
659    }
660
661/* Store resolution. First X, the Y */
662
663  STORE16 (WP + 2, s->val[OPT_RESOLUTION].w);
664  STORE16 (WP + 4, s->val[OPT_RESOLUTION].w);
665
666/* Now the Scanner Window in Scanner Parameters */
667
668  STORE32 (WP + 6, s->ULx);
669  STORE32 (WP + 10, s->ULy);
670  STORE32 (WP + 14, s->Width);
671  STORE32 (WP + 18, s->Height);
672
673/* Now The Enhansment Group */
674
675  STORE8 (WP + 22, s->val[OPT_BRIGHTNESS].w);
676  STORE8 (WP + 23, s->val[OPT_THRESHOLD].w);
677  STORE8 (WP + 24, s->val[OPT_CONTRAST].w);
678
679/* The Mode */
680
681  if      (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
682    STORE8 (WP + 25, 0)
683  else if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE))
684    STORE8 (WP + 25, 1)
685  else if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) ||
686	   !strcmp (s->val[OPT_MODE].s, "Gray16"))
687    STORE8 (WP + 25, 2)
688  else if (!strcmp (s->val[OPT_MODE].s, "BiColor"))
689    STORE8 (WP + 25, 3)
690  else if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR))
691    STORE8 (WP + 25, 5)
692  else
693    {
694      DBG (ERROR_MESSAGE, "Cannot much mode %s\n", s->val[OPT_MODE].s);
695      return SANE_STATUS_INVAL;
696    }
697
698  STORE8 (WP + 26, s->bpp)
699
700/* HalfTone */
701if (s->hw->ScannerModel != COLORONESCANNER)
702  {
703  if	  (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "spiral4x4"))
704    STORE16 (WP + 27, 0)
705  else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "bayer4x4"))
706    STORE16 (WP + 27, 1)
707  else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "download"))
708    STORE16 (WP + 27, 1)
709  else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "spiral8x8"))
710    STORE16 (WP + 27, 3)
711  else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "bayer8x8"))
712    STORE16 (WP + 27, 4)
713  else
714    {
715      DBG (ERROR_MESSAGE, "Cannot much haftone pattern %s\n",
716					s->val[OPT_HALFTONE_PATTERN].s);
717      return SANE_STATUS_INVAL;
718    }
719  }
720/* Padding Type */
721  STORE8 (WP + 29, 3);
722
723  if (s->hw->ScannerModel == COLORONESCANNER)
724    {
725    if (s->val[OPT_VOLT_REF].w)
726      {
727      STORE8(WP+40,s->val[OPT_VOLT_REF_TOP].w);
728      STORE8(WP+41,s->val[OPT_VOLT_REF_BOTTOM].w);
729      }
730    else
731      {
732      STORE8(WP+40,0);
733      STORE8(WP+41,0);
734      }
735    return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0);
736    }
737  else
738    return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd) - 2, 0, 0);
739
740#endif /* NEUTRALIZE_BACKEND */
741}
742
743static SANE_Status
744mode_select (Apple_Scanner * s)
745{
746  uint8_t cmd[6 + 12];
747#define CMD cmd + 0
748#define PP  cmd + 6
749
750  /* setup SCSI command (except length): */
751  memset (cmd, 0, sizeof (cmd));
752  cmd[0] = APPLE_SCSI_MODE_SELECT;
753
754/* Apple Hardware Magic */
755  STORE8 (CMD + 1, 0x10);
756
757/* Parameter list length */
758  STORE8 (CMD + 4, 12);
759
760  STORE8 (PP + 5, 6);
761
762  if (s->val[OPT_LAMP].w) *(PP+8) |= 1;
763
764  switch (s->hw->ScannerModel)
765    {
766    case APPLESCANNER:
767      if      (!strcmp (s->val[OPT_GRAYMAP].s, "dark"))
768	STORE8 (PP + 6, 0)
769      else if (!strcmp (s->val[OPT_GRAYMAP].s, "normal"))
770	STORE8 (PP + 6, 1)
771      else if (!strcmp (s->val[OPT_GRAYMAP].s, "light"))
772	STORE8 (PP + 6, 2)
773      else
774	{
775	DBG (ERROR_MESSAGE, "Cannot mach GrayMap Function %s\n",
776						s->val[OPT_GRAYMAP].s);
777	return SANE_STATUS_INVAL;
778	}
779				/* And the auto background threshold */
780      STORE8 (PP + 7, s->val[OPT_AUTOBACKGROUND_THRESHOLD].w)
781      break;
782    case ONESCANNER:
783      if (s->val[OPT_LED].w) *(PP+7) |= 4;
784      if (s->val[OPT_CCD].w) *(PP+8) |= 2;
785      if      (!strcmp (s->val[OPT_SPEED].s, "high"))
786	*(PP+8) |= 4;
787      else if (!strcmp (s->val[OPT_SPEED].s, "high wo H/S"))
788	*(PP+8) |= 8;
789      else if (!strcmp (s->val[OPT_SPEED].s, "normal"))
790	{ /* Do nothing. Zeros are great */}
791      else
792	{
793	DBG (ERROR_MESSAGE, "Cannot mach speed selection %s\n",
794						s->val[OPT_SPEED].s);
795	return SANE_STATUS_INVAL;
796	}
797      break;
798    case COLORONESCANNER:
799      if (s->val[OPT_LED].w)		*(PP+7) |= 4;
800      if (!s->val[OPT_CUSTOM_GAMMA].w)	*(PP+7) |= 2;
801      if (!s->val[OPT_CUSTOM_CCT].w)	*(PP+7) |= 1;
802      if (s->val[OPT_MTF_CIRCUIT].w)	*(PP+8) |= 16;
803      if (s->val[OPT_ICP].w)		*(PP+8) |= 8;
804      if (s->val[OPT_POLARITY].w)	*(PP+8) |= 4;
805      if (s->val[OPT_CCD].w)		*(PP+8) |= 2;
806
807      if      (!strcmp (s->val[OPT_COLOR_SENSOR].s, "All"))
808	STORE8 (PP + 9, 0)
809      else if (!strcmp (s->val[OPT_COLOR_SENSOR].s, "Red"))
810	STORE8 (PP + 9, 1)
811      else if (!strcmp (s->val[OPT_COLOR_SENSOR].s, "Green"))
812	STORE8 (PP + 9, 2)
813      else if (!strcmp (s->val[OPT_COLOR_SENSOR].s, "Blue"))
814	STORE8 (PP + 9, 3)
815      else
816	{
817	DBG (ERROR_MESSAGE, "Cannot mach Color Sensor for gray scans %s\n",
818						s->val[OPT_COLOR_SENSOR].s);
819	return SANE_STATUS_INVAL;
820	}
821
822      break;
823    default:
824      DBG(ERROR_MESSAGE,"Bad Scanner.\n");
825      break;
826    }
827
828#ifdef NEUTRALIZE_BACKEND
829  return SANE_STATUS_GOOD;
830#else
831  return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0);
832#endif /* NEUTRALIZE_BACKEND */
833
834}
835
836static SANE_Status
837start_scan (Apple_Scanner * s)
838{
839  SANE_Status status;
840  uint8_t start[7];
841
842
843  memset (start, 0, sizeof (start));
844  start[0] = APPLE_SCSI_START;
845  start[4] = 1;
846
847  switch (s->hw->ScannerModel)
848    {
849    case APPLESCANNER:
850      if (s->val[OPT_WAIT].w)  start[5]=0x80;
851      /* NOT TODO  NoHome */
852      break;
853    case ONESCANNER:
854      if (!s->val[OPT_CALIBRATE].w)  start[5]=0x20;
855      break;
856    case COLORONESCANNER:
857      break;
858    default:
859      DBG(ERROR_MESSAGE,"Bad Scanner.\n");
860      break;
861    }
862
863
864#ifdef NEUTRALIZE_BACKEND
865  return SANE_STATUS_GOOD;
866#else
867  status = sanei_scsi_cmd (s->fd, start, sizeof (start), 0, 0);
868  return status;
869#endif /* NEUTRALIZE_BACKEND */
870}
871
872static SANE_Status
873calc_parameters (Apple_Scanner * s)
874{
875  SANE_String val = s->val[OPT_MODE].s;
876  SANE_Status status = SANE_STATUS_GOOD;
877  SANE_Bool OutOfRangeX, OutOfRangeY, Protect = SANE_TRUE;
878  SANE_Int xqstep, yqstep;
879
880  DBG (FLOW_CONTROL, "Entering calc_parameters\n");
881
882  if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART))
883    {
884      s->params.last_frame = SANE_TRUE;
885      s->params.format = SANE_FRAME_GRAY;
886      s->params.depth = 1;
887      s->bpp = 1;
888    }
889  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE))
890    {
891      s->params.last_frame = SANE_TRUE;
892      s->params.format = SANE_FRAME_GRAY;
893      s->params.depth = 1;
894      s->bpp = 1;
895    }
896  else if (!strcmp (val, "Gray16"))
897    {
898      s->params.last_frame = SANE_TRUE;
899      s->params.format = SANE_FRAME_GRAY;
900      s->params.depth = 8;
901      s->bpp = 4;
902    }
903  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_GRAY))
904    {
905      s->params.last_frame = SANE_TRUE;
906      s->params.format = SANE_FRAME_GRAY;
907      s->params.depth = 8;
908      s->bpp = 8;
909    }
910  else if (!strcmp (val, "BiColor"))
911    {
912      s->params.last_frame = SANE_TRUE;
913      s->params.format = SANE_FRAME_RGB;
914      s->params.depth = 24;
915      s->bpp = 3;
916    }
917  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_COLOR))
918    {
919      s->params.last_frame = SANE_FALSE;
920      s->params.format = SANE_FRAME_RED;
921      s->params.depth = 24;
922      s->bpp = 24;
923    }
924  else
925    {
926      DBG (ERROR_MESSAGE, "calc_parameters: Invalid mode %s\n", (char *) val);
927      status = SANE_STATUS_INVAL;
928    }
929
930  s->ulx = SANE_UNFIX (s->val[OPT_TL_X].w) / MM_PER_INCH;
931  s->uly = SANE_UNFIX (s->val[OPT_TL_Y].w) / MM_PER_INCH;
932  s->wx = SANE_UNFIX (s->val[OPT_BR_X].w) / MM_PER_INCH - s->ulx;
933  s->wy = SANE_UNFIX (s->val[OPT_BR_Y].w) / MM_PER_INCH - s->uly;
934
935  DBG (VARIABLE_CONTROL, "Desired [%g,%g] to +[%g,%g]\n",
936       s->ulx, s->uly, s->wx, s->wy);
937
938  xqstep = XQSTEP (s->val[OPT_RESOLUTION].w, s->bpp);
939  yqstep = YQSTEP (s->val[OPT_RESOLUTION].w);
940
941  DBG (VARIABLE_CONTROL, "Quantization steps of [%u,%u].\n", xqstep, yqstep);
942
943  s->ULx = xquant (s->ulx, s->val[OPT_RESOLUTION].w, s->bpp, 0);
944  s->Width = xquant (s->wx, s->val[OPT_RESOLUTION].w, s->bpp, 1);
945  s->ULy = yquant (s->uly, s->val[OPT_RESOLUTION].w, 0);
946  s->Height = yquant (s->wy, s->val[OPT_RESOLUTION].w, 1);
947
948  DBG (VARIABLE_CONTROL, "Scanner [%u,%u] to +[%u,%u]\n",
949       s->ULx, s->ULy, s->Width, s->Height);
950
951  do
952    {
953
954      OutOfRangeX = SANE_FALSE;
955      OutOfRangeY = SANE_FALSE;
956
957      if (s->ULx + s->Width > s->hw->MaxWidth)
958	{
959	  OutOfRangeX = SANE_TRUE;
960	  Protect = SANE_FALSE;
961	  s->Width -= xqstep;
962	}
963
964      if (s->ULy + s->Height > s->hw->MaxHeight)
965	{
966	  OutOfRangeY = SANE_TRUE;
967	  Protect = SANE_FALSE;
968	  s->Height -= yqstep;
969	}
970
971      DBG (VARIABLE_CONTROL, "Adapting to [%u,%u] to +[%u,%u]\n",
972	   s->ULx, s->ULy, s->Width, s->Height);
973
974    }
975  while (OutOfRangeX || OutOfRangeY);
976
977  s->ulx = (double) s->ULx / 1200;
978  s->uly = (double) s->ULy / 1200;
979  s->wx = (double) s->Width / 1200;
980  s->wy = (double) s->Height / 1200;
981
982
983  DBG (VARIABLE_CONTROL, "Real [%g,%g] to +[%g,%g]\n",
984       s->ulx, s->uly, s->wx, s->wy);
985
986
987/*
988
989   TODO: Remove this ugly hack (Protect). Read to learn why!
990
991   NOTE: I hate the Fixed Sane type. This type gave me a terrible
992   headache and a difficult bug to find out. The xscanimage frontend
993   was looping and segfaulting all the time with random order. The
994   problem was the following:
995
996   * You select new let's say BR_X
997   * sane_control_option returns info inexact (always for BR_X) but
998     does not modify val because it fits under the constrained
999     quantization.
1000
1001   Hm... Well sane_control doesn't change the (double) value of val
1002   but the Fixed interpatation may have been change (by 1 or something
1003   small).
1004
1005   So now we should protect the val if the change is smaller than the
1006   quantization step or better under the SANE_[UN]FIX accuracy.
1007
1008   Looks like for two distinct val (Fixed) values we get the same
1009   double. How come ?
1010
1011   This hack fixed the looping situation. Unfortunately SIGSEGV
1012   remains when you touch the slice bars (thouhg not all the
1013   time). But it's OK if you select scan_area from the preview window
1014   (cool).
1015
1016 */
1017
1018  if (!Protect)
1019    {
1020      s->val[OPT_TL_X].w = SANE_FIX (s->ulx * MM_PER_INCH);
1021      s->val[OPT_TL_Y].w = SANE_FIX (s->uly * MM_PER_INCH);
1022      s->val[OPT_BR_X].w = SANE_FIX ((s->ulx + s->wx) * MM_PER_INCH);
1023      s->val[OPT_BR_Y].w = SANE_FIX ((s->uly + s->wy) * MM_PER_INCH);
1024    }
1025  else
1026    DBG (VARIABLE_CONTROL, "Not adapted. Protecting\n");
1027
1028
1029  DBG (VARIABLE_CONTROL, "GUI [%g,%g] to [%g,%g]\n",
1030       SANE_UNFIX (s->val[OPT_TL_X].w),
1031       SANE_UNFIX (s->val[OPT_TL_Y].w),
1032       SANE_UNFIX (s->val[OPT_BR_X].w),
1033       SANE_UNFIX (s->val[OPT_BR_Y].w));
1034
1035  /* NOTE: remember that AppleScanners quantize the scan area to be a
1036     byte multiple */
1037
1038
1039  s->params.pixels_per_line = s->Width * s->val[OPT_RESOLUTION].w / 1200;
1040  s->params.lines = s->Height * s->val[OPT_RESOLUTION].w / 1200;
1041  s->params.bytes_per_line = s->params.pixels_per_line * s->params.depth / 8;
1042
1043
1044  DBG (VARIABLE_CONTROL, "format=%d\n", s->params.format);
1045  DBG (VARIABLE_CONTROL, "last_frame=%d\n", s->params.last_frame);
1046  DBG (VARIABLE_CONTROL, "lines=%d\n", s->params.lines);
1047  DBG (VARIABLE_CONTROL, "depth=%d (%d)\n", s->params.depth, s->bpp);
1048  DBG (VARIABLE_CONTROL, "pixels_per_line=%d\n", s->params.pixels_per_line);
1049  DBG (VARIABLE_CONTROL, "bytes_per_line=%d\n", s->params.bytes_per_line);
1050  DBG (VARIABLE_CONTROL, "Pixels %dx%dx%d\n",
1051       s->params.pixels_per_line, s->params.lines, 1 << s->params.depth);
1052
1053  DBG (FLOW_CONTROL, "Leaving calc_parameters\n");
1054  return status;
1055}
1056
1057
1058
1059static SANE_Status
1060gamma_update(SANE_Handle handle)
1061{
1062Apple_Scanner *s = handle;
1063
1064
1065if (s->hw->ScannerModel == COLORONESCANNER)
1066  {
1067  if (	!strcmp(s->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_GRAY)	||
1068	!strcmp(s->val[OPT_MODE].s,"Gray16")	 )
1069    {
1070    ENABLE (OPT_CUSTOM_GAMMA);
1071    if (s->val[OPT_CUSTOM_GAMMA].w)
1072      {
1073      ENABLE (OPT_DOWNLOAD_GAMMA);
1074      if (! strcmp(s->val[OPT_COLOR_SENSOR].s,"All"))
1075	{
1076	ENABLE (OPT_GAMMA_VECTOR_R);
1077	ENABLE (OPT_GAMMA_VECTOR_G);
1078	ENABLE (OPT_GAMMA_VECTOR_B);
1079	}
1080      if (! strcmp(s->val[OPT_COLOR_SENSOR].s,"Red"))
1081	{
1082	ENABLE (OPT_GAMMA_VECTOR_R);
1083	DISABLE(OPT_GAMMA_VECTOR_G);
1084	DISABLE (OPT_GAMMA_VECTOR_B);
1085	}
1086      if (! strcmp(s->val[OPT_COLOR_SENSOR].s,"Green"))
1087	{
1088	DISABLE (OPT_GAMMA_VECTOR_R);
1089	ENABLE (OPT_GAMMA_VECTOR_G);
1090	DISABLE (OPT_GAMMA_VECTOR_B);
1091	}
1092      if (! strcmp(s->val[OPT_COLOR_SENSOR].s,"Blue"))
1093	{
1094	DISABLE (OPT_GAMMA_VECTOR_R);
1095	DISABLE (OPT_GAMMA_VECTOR_G);
1096	ENABLE (OPT_GAMMA_VECTOR_B);
1097	}
1098      }
1099    else /* Not custom gamma */
1100      {
1101      goto discustom;
1102      }
1103    }
1104  else if (!strcmp(s->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_COLOR))
1105    {
1106    ENABLE (OPT_CUSTOM_GAMMA);
1107    if (s->val[OPT_CUSTOM_GAMMA].w)
1108      {
1109      ENABLE (OPT_DOWNLOAD_GAMMA);
1110      ENABLE (OPT_GAMMA_VECTOR_R);
1111      ENABLE (OPT_GAMMA_VECTOR_G);
1112      ENABLE (OPT_GAMMA_VECTOR_B);
1113      }
1114    else /* Not custom gamma */
1115      {
1116      goto discustom;
1117      }
1118    }
1119  else /* Not Gamma capable mode */
1120    {
1121    goto disall;
1122    }
1123  }	/* Not Gamma capable Scanner */
1124else
1125  {
1126disall:
1127  DISABLE (OPT_CUSTOM_GAMMA);
1128discustom:
1129  DISABLE (OPT_GAMMA_VECTOR_R);
1130  DISABLE (OPT_GAMMA_VECTOR_G);
1131  DISABLE (OPT_GAMMA_VECTOR_B);
1132  DISABLE (OPT_DOWNLOAD_GAMMA);
1133  }
1134
1135return SANE_STATUS_GOOD;
1136}
1137
1138
1139static SANE_Status
1140mode_update (SANE_Handle handle, char *val)
1141{
1142  Apple_Scanner *s = handle;
1143  SANE_Bool cct=SANE_FALSE;
1144  SANE_Bool UseThreshold=SANE_FALSE;
1145
1146  DISABLE(OPT_COLOR_SENSOR);
1147
1148  if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART))
1149    {
1150      if (s->hw->ScannerModel == APPLESCANNER)
1151	ENABLE (OPT_AUTOBACKGROUND);
1152      else
1153	DISABLE (OPT_AUTOBACKGROUND);
1154      DISABLE (OPT_HALFTONE_PATTERN);
1155
1156      UseThreshold=SANE_TRUE;
1157    }
1158  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE))
1159    {
1160      DISABLE (OPT_AUTOBACKGROUND);
1161      ENABLE (OPT_HALFTONE_PATTERN);
1162    }
1163  else if (!strcmp (val, "Gray16") || !strcmp (val, SANE_VALUE_SCAN_MODE_GRAY))
1164    {
1165      DISABLE (OPT_AUTOBACKGROUND);
1166      DISABLE (OPT_HALFTONE_PATTERN);
1167      if (s->hw->ScannerModel == COLORONESCANNER)
1168	ENABLE(OPT_COLOR_SENSOR);
1169
1170    }				/* End of Gray */
1171  else if (!strcmp (val, "BiColor"))
1172    {
1173      DISABLE (OPT_AUTOBACKGROUND);
1174      DISABLE (OPT_HALFTONE_PATTERN);
1175      UseThreshold=SANE_TRUE;
1176    }
1177  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_COLOR))
1178    {
1179      DISABLE (OPT_AUTOBACKGROUND);
1180      DISABLE (OPT_HALFTONE_PATTERN);
1181      cct=SANE_TRUE;
1182    }
1183  else
1184    {
1185      DBG (ERROR_MESSAGE, "Invalid mode %s\n", (char *) val);
1186      return SANE_STATUS_INVAL;
1187    }
1188
1189/* Second hand dependencies of mode option */
1190/* Looks like code doubling */
1191
1192
1193  if (UseThreshold)
1194    {
1195      DISABLE (OPT_BRIGHTNESS);
1196      DISABLE (OPT_CONTRAST);
1197      DISABLE (OPT_VOLT_REF);
1198      DISABLE (OPT_VOLT_REF_TOP);
1199      DISABLE (OPT_VOLT_REF_BOTTOM);
1200
1201     if (IS_ACTIVE (OPT_AUTOBACKGROUND) && s->val[OPT_AUTOBACKGROUND].w)
1202      {
1203      DISABLE (OPT_THRESHOLD);
1204      ENABLE (OPT_AUTOBACKGROUND_THRESHOLD);
1205      }
1206    else
1207      {
1208      ENABLE (OPT_THRESHOLD);
1209      DISABLE (OPT_AUTOBACKGROUND_THRESHOLD);
1210      }
1211    }
1212  else
1213    {
1214      DISABLE (OPT_THRESHOLD);
1215      DISABLE (OPT_AUTOBACKGROUND_THRESHOLD);
1216
1217      if (s->hw->ScannerModel == COLORONESCANNER)
1218	{
1219	ENABLE (OPT_VOLT_REF);
1220	if (s->val[OPT_VOLT_REF].w)
1221	  {
1222	  ENABLE (OPT_VOLT_REF_TOP);
1223	  ENABLE (OPT_VOLT_REF_BOTTOM);
1224	  DISABLE (OPT_BRIGHTNESS);
1225	  DISABLE (OPT_CONTRAST);
1226	  }
1227	else
1228	  {
1229	  DISABLE (OPT_VOLT_REF_TOP);
1230	  DISABLE (OPT_VOLT_REF_BOTTOM);
1231	  ENABLE (OPT_BRIGHTNESS);
1232	  ENABLE (OPT_CONTRAST);
1233	  }
1234	}
1235      else
1236        {
1237	ENABLE (OPT_BRIGHTNESS);
1238	ENABLE (OPT_CONTRAST);
1239        }
1240    }
1241
1242
1243  if (IS_ACTIVE (OPT_HALFTONE_PATTERN) &&
1244      !strcmp (s->val[OPT_HALFTONE_PATTERN].s, "download"))
1245    ENABLE (OPT_HALFTONE_FILE);
1246  else
1247    DISABLE (OPT_HALFTONE_FILE);
1248
1249  if (cct)
1250    ENABLE (OPT_CUSTOM_CCT);
1251  else
1252    DISABLE (OPT_CUSTOM_CCT);
1253
1254  if (cct && s->val[OPT_CUSTOM_CCT].w)
1255    {
1256    ENABLE(OPT_CCT);
1257    ENABLE(OPT_DOWNLOAD_CCT);
1258    }
1259  else
1260    {
1261    DISABLE(OPT_CCT);
1262    DISABLE(OPT_DOWNLOAD_CCT);
1263    }
1264
1265
1266  gamma_update (s);
1267  calc_parameters (s);
1268
1269  return SANE_STATUS_GOOD;
1270
1271}
1272
1273
1274
1275
1276static SANE_Status
1277init_options (Apple_Scanner * s)
1278{
1279  int i;
1280
1281  memset (s->opt, 0, sizeof (s->opt));
1282  memset (s->val, 0, sizeof (s->val));
1283
1284  for (i = 0; i < NUM_OPTIONS; ++i)
1285    {
1286      s->opt[i].size = sizeof (SANE_Word);
1287      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1288    }
1289
1290  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1291  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1292  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1293  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1294  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
1295
1296  /* Hardware detect Information  group: */
1297
1298  s->opt[OPT_HWDETECT_GROUP].title = "Hardware";
1299  s->opt[OPT_HWDETECT_GROUP].desc = "Detected during hardware probing";
1300  s->opt[OPT_HWDETECT_GROUP].type = SANE_TYPE_GROUP;
1301  s->opt[OPT_HWDETECT_GROUP].cap = 0;
1302  s->opt[OPT_HWDETECT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1303
1304  s->opt[OPT_MODEL].name = "model";
1305  s->opt[OPT_MODEL].title = "Model";
1306  s->opt[OPT_MODEL].desc = "Model and capabilities";
1307  s->opt[OPT_MODEL].type = SANE_TYPE_STRING;
1308  s->opt[OPT_MODEL].cap = SANE_CAP_SOFT_DETECT;
1309  s->opt[OPT_MODEL].constraint_type = SANE_CONSTRAINT_NONE;
1310  s->opt[OPT_MODEL].size = max_string_size (SupportedModel);
1311  s->val[OPT_MODEL].s = strdup (SupportedModel[s->hw->ScannerModel]);
1312
1313
1314  /* "Mode" group: */
1315
1316  s->opt[OPT_MODE_GROUP].title = "Scan Mode";
1317  s->opt[OPT_MODE_GROUP].desc = "";
1318  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1319  s->opt[OPT_MODE_GROUP].cap = 0;
1320  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1321
1322  halftone_pattern_list[0]="spiral4x4";
1323  halftone_pattern_list[1]="bayer4x4";
1324  halftone_pattern_list[2]="download";
1325  halftone_pattern_list[3]=NULL;
1326
1327
1328  switch (s->hw->ScannerModel)
1329    {
1330    case APPLESCANNER:
1331      mode_list[0]=SANE_VALUE_SCAN_MODE_LINEART;
1332      mode_list[1]=SANE_VALUE_SCAN_MODE_HALFTONE;
1333      mode_list[2]="Gray16";
1334      mode_list[3]=NULL;
1335      break;
1336    case ONESCANNER:
1337      mode_list[0]=SANE_VALUE_SCAN_MODE_LINEART;
1338      mode_list[1]=SANE_VALUE_SCAN_MODE_HALFTONE;
1339      mode_list[2]="Gray16";
1340      mode_list[3]=SANE_VALUE_SCAN_MODE_GRAY;
1341      mode_list[4]=NULL;
1342      halftone_pattern_list[3]="spiral8x8";
1343      halftone_pattern_list[4]="bayer8x8";
1344      halftone_pattern_list[5]=NULL;
1345      break;
1346    case COLORONESCANNER:
1347      mode_list[0]=SANE_VALUE_SCAN_MODE_LINEART;
1348      mode_list[1]="Gray16";
1349      mode_list[2]=SANE_VALUE_SCAN_MODE_GRAY;
1350      mode_list[3]="BiColor";
1351      mode_list[4]=SANE_VALUE_SCAN_MODE_COLOR;
1352      mode_list[5]=NULL;
1353      break;
1354    default:
1355      break;
1356    }
1357
1358
1359  /* scan mode */
1360  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1361  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1362  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1363  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
1364  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1365  s->opt[OPT_MODE].size = max_string_size (mode_list);
1366  s->opt[OPT_MODE].constraint.string_list = mode_list;
1367  s->val[OPT_MODE].s = strdup (mode_list[0]);
1368
1369
1370  /* resolution */
1371  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1372  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1373  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1374  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1375  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1376/* TODO: Build the constraints on resolution in a smart way */
1377  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1378  s->opt[OPT_RESOLUTION].constraint.word_list = resbit_list;
1379  s->val[OPT_RESOLUTION].w = resbit_list[1];
1380
1381  /* preview */
1382  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
1383  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1384  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
1385  s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
1386  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
1387  s->val[OPT_PREVIEW].w = SANE_FALSE;
1388
1389  /* "Geometry" group: */
1390  s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
1391  s->opt[OPT_GEOMETRY_GROUP].desc = "";
1392  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1393  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
1394  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1395
1396  /* top-left x */
1397  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1398  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1399  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1400  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1401  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1402  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1403  s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
1404  s->val[OPT_TL_X].w = 0;
1405
1406  /* top-left y */
1407  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1408  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1409  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1410  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1411  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1412  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1413  s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
1414  s->val[OPT_TL_Y].w = 0;
1415
1416  /* bottom-right x */
1417  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1418  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1419  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1420  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1421  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1422  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1423  s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
1424  s->val[OPT_BR_X].w = s->hw->x_range.max;
1425
1426  /* bottom-right y */
1427  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1428  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1429  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1430  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1431  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1432  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1433  s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
1434  s->val[OPT_BR_Y].w = s->hw->y_range.max;
1435
1436
1437  /* "Enhancement" group: */
1438
1439  s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1440  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
1441  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1442  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
1443  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1444
1445  /* brightness */
1446  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1447  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1448  s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
1449  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
1450  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
1451  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1452  s->opt[OPT_BRIGHTNESS].constraint.range = &byte_range;
1453  s->val[OPT_BRIGHTNESS].w = 128;
1454
1455  /* contrast */
1456  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
1457  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
1458  s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST
1459    " This option is active for halftone/Grayscale modes only.";
1460  s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
1461  s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
1462  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
1463  s->opt[OPT_CONTRAST].constraint.range = &byte_range;
1464  s->val[OPT_CONTRAST].w = 1;
1465
1466  /* threshold */
1467  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1468  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1469  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1470  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1471  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1472  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1473  s->opt[OPT_THRESHOLD].constraint.range = &byte_range;
1474  s->val[OPT_THRESHOLD].w = 128;
1475
1476  /* AppleScanner Only options */
1477
1478  /* GrayMap Enhance */
1479  s->opt[OPT_GRAYMAP].name = "graymap";
1480  s->opt[OPT_GRAYMAP].title = "GrayMap";
1481  s->opt[OPT_GRAYMAP].desc = "Fixed Gamma Enhancing";
1482  s->opt[OPT_GRAYMAP].type = SANE_TYPE_STRING;
1483  s->opt[OPT_GRAYMAP].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1484  if (s->hw->ScannerModel != APPLESCANNER)
1485    s->opt[OPT_GRAYMAP].cap |= SANE_CAP_INACTIVE;
1486  s->opt[OPT_GRAYMAP].constraint.string_list = graymap_list;
1487  s->opt[OPT_GRAYMAP].size = max_string_size (graymap_list);
1488  s->val[OPT_GRAYMAP].s = strdup (graymap_list[1]);
1489
1490  /* Enable auto background adjustment */
1491  s->opt[OPT_AUTOBACKGROUND].name = "abj";
1492  s->opt[OPT_AUTOBACKGROUND].title = "Use Auto Background Adjustment";
1493  s->opt[OPT_AUTOBACKGROUND].desc =
1494      "Enables/Disables the Auto Background Adjustment feature";
1495  if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)
1496      || (s->hw->ScannerModel != APPLESCANNER))
1497    DISABLE (OPT_AUTOBACKGROUND);
1498  s->opt[OPT_AUTOBACKGROUND].type = SANE_TYPE_BOOL;
1499  s->val[OPT_AUTOBACKGROUND].w = SANE_FALSE;
1500
1501  /* auto background adjustment threshold */
1502  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].name = "abjthreshold";
1503  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].title = "Auto Background Adjustment Threshold";
1504  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].desc = "Selects the automatically adjustable threshold";
1505  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].type = SANE_TYPE_INT;
1506  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].unit = SANE_UNIT_NONE;
1507  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1508
1509  if (!IS_ACTIVE (OPT_AUTOBACKGROUND) ||
1510      s->val[OPT_AUTOBACKGROUND].w == SANE_FALSE)
1511    s->opt[OPT_AUTOBACKGROUND_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1512
1513  s->opt[OPT_AUTOBACKGROUND_THRESHOLD].constraint.range = &byte_range;
1514  s->val[OPT_AUTOBACKGROUND_THRESHOLD].w = 64;
1515
1516
1517  /* AppleScanner & OneScanner options  */
1518
1519  /* Select HalfTone Pattern  */
1520  s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
1521  s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
1522  s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
1523  s->opt[OPT_HALFTONE_PATTERN].size = max_string_size (halftone_pattern_list);
1524  s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
1525  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_AUTOMATIC;
1526  s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1527  s->opt[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_pattern_list;
1528  s->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_pattern_list[0]);
1529
1530  if (s->hw->ScannerModel!=APPLESCANNER && s->hw->ScannerModel!=ONESCANNER)
1531    s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1532
1533
1534  /* halftone pattern file */
1535  s->opt[OPT_HALFTONE_FILE].name = "halftone-pattern-file";
1536  s->opt[OPT_HALFTONE_FILE].title = "Halftone Pattern File";
1537  s->opt[OPT_HALFTONE_FILE].desc =
1538    "Download and use the specified file as halftone pattern";
1539  s->opt[OPT_HALFTONE_FILE].type = SANE_TYPE_STRING;
1540  s->opt[OPT_HALFTONE_FILE].cap |= SANE_CAP_INACTIVE;
1541  s->opt[OPT_HALFTONE_FILE].size = 256;
1542  s->val[OPT_HALFTONE_FILE].s = "halftone.pgm";
1543
1544  /* Use volt_ref */
1545  s->opt[OPT_VOLT_REF].name = "volt-ref";
1546  s->opt[OPT_VOLT_REF].title = "Volt Reference";
1547  s->opt[OPT_VOLT_REF].desc ="It's brightness equivalent.";
1548  s->opt[OPT_VOLT_REF].type = SANE_TYPE_BOOL;
1549  if (s->hw->ScannerModel!=COLORONESCANNER)
1550    s->opt[OPT_VOLT_REF].cap |= SANE_CAP_INACTIVE;
1551  s->val[OPT_VOLT_REF].w = SANE_FALSE;
1552
1553  s->opt[OPT_VOLT_REF_TOP].name = "volt-ref-top";
1554  s->opt[OPT_VOLT_REF_TOP].title = "Top Voltage Reference";
1555  s->opt[OPT_VOLT_REF_TOP].desc = "I really do not know.";
1556  s->opt[OPT_VOLT_REF_TOP].type = SANE_TYPE_INT;
1557  s->opt[OPT_VOLT_REF_TOP].unit = SANE_UNIT_NONE;
1558  if (s->hw->ScannerModel!=COLORONESCANNER || s->val[OPT_VOLT_REF].w==SANE_FALSE)
1559    s->opt[OPT_VOLT_REF_TOP].cap |= SANE_CAP_INACTIVE;
1560  s->opt[OPT_VOLT_REF_TOP].constraint_type = SANE_CONSTRAINT_RANGE;
1561  s->opt[OPT_VOLT_REF_TOP].constraint.range = &byte_range;
1562  s->val[OPT_VOLT_REF_TOP].w = 255;
1563
1564  s->opt[OPT_VOLT_REF_BOTTOM].name = "volt-ref-bottom";
1565  s->opt[OPT_VOLT_REF_BOTTOM].title = "Bottom Voltage Reference";
1566  s->opt[OPT_VOLT_REF_BOTTOM].desc = "I really do not know.";
1567  s->opt[OPT_VOLT_REF_BOTTOM].type = SANE_TYPE_INT;
1568  s->opt[OPT_VOLT_REF_BOTTOM].unit = SANE_UNIT_NONE;
1569  if (s->hw->ScannerModel!=COLORONESCANNER || s->val[OPT_VOLT_REF].w==SANE_FALSE)
1570    s->opt[OPT_VOLT_REF_BOTTOM].cap |= SANE_CAP_INACTIVE;
1571  s->opt[OPT_VOLT_REF_BOTTOM].constraint_type = SANE_CONSTRAINT_RANGE;
1572  s->opt[OPT_VOLT_REF_BOTTOM].constraint.range = &byte_range;
1573  s->val[OPT_VOLT_REF_BOTTOM].w = 1;
1574
1575/* Misc Functions: Advanced */
1576
1577  s->opt[OPT_MISC_GROUP].title = "Miscallaneous";
1578  s->opt[OPT_MISC_GROUP].desc = "";
1579  s->opt[OPT_MISC_GROUP].type = SANE_TYPE_GROUP;
1580  s->opt[OPT_MISC_GROUP].cap = SANE_CAP_ADVANCED;
1581  s->opt[OPT_MISC_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1582
1583
1584  /* Turn On lamp  during scan: All scanners */
1585  s->opt[OPT_LAMP].name = "lamp";
1586  s->opt[OPT_LAMP].title = "Lamp";
1587  s->opt[OPT_LAMP].desc = "Hold the lamp on during scans.";
1588  s->opt[OPT_LAMP].type = SANE_TYPE_BOOL;
1589  s->val[OPT_LAMP].w = SANE_FALSE;
1590
1591  /* AppleScanner Only options */
1592
1593  /* Wait for button to be pressed before scanning */
1594  s->opt[OPT_WAIT].name = "wait";
1595  s->opt[OPT_WAIT].title = "Wait";
1596  s->opt[OPT_WAIT].desc = "You may issue the scan command but the actual "
1597  "scan will not start unless you press the button in the front of the "
1598  "scanner. It is a useful feature when you want to make a network scan (?) "
1599  "In the mean time you may halt your computer waiting for the SCSI bus "
1600  "to be free. If this happens just press the scanner button.";
1601  s->opt[OPT_WAIT].type = SANE_TYPE_BOOL;
1602  if (s->hw->ScannerModel != APPLESCANNER)
1603    s->opt[OPT_WAIT].cap |= SANE_CAP_INACTIVE;
1604  s->val[OPT_WAIT].w = SANE_FALSE;
1605
1606
1607  /* OneScanner Only options */
1608
1609  /* Calibrate before scanning ? */
1610  s->opt[OPT_CALIBRATE].name = "calibrate";
1611  s->opt[OPT_CALIBRATE].title = "Calibrate";
1612  s->opt[OPT_CALIBRATE].desc = "You may avoid the calibration before "
1613      "scanning but this will lead you to lower image quality.";
1614  s->opt[OPT_CALIBRATE].type = SANE_TYPE_BOOL;
1615  if (s->hw->ScannerModel != ONESCANNER)
1616    s->opt[OPT_CALIBRATE].cap |= SANE_CAP_INACTIVE;
1617  s->val[OPT_CALIBRATE].w = SANE_TRUE;
1618
1619  /* speed */
1620  s->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED;
1621  s->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
1622  s->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED;
1623  s->opt[OPT_SPEED].type = SANE_TYPE_STRING;
1624  if (s->hw->ScannerModel != ONESCANNER)
1625    s->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE;
1626  s->opt[OPT_SPEED].size = max_string_size (speed_list);
1627  s->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1628  s->opt[OPT_SPEED].constraint.string_list = speed_list;
1629  s->val[OPT_SPEED].s = strdup (speed_list[0]);
1630
1631  /* OneScanner & ColorOneScanner (LED && CCD) */
1632
1633  /* LED ? */
1634  s->opt[OPT_LED].name = "led";
1635  s->opt[OPT_LED].title = "LED";
1636  s->opt[OPT_LED].desc ="This option controls the setting of the ambler LED.";
1637  s->opt[OPT_LED].type = SANE_TYPE_BOOL;
1638  if (s->hw->ScannerModel!=ONESCANNER && s->hw->ScannerModel!=COLORONESCANNER)
1639    s->opt[OPT_LED].cap |= SANE_CAP_INACTIVE;
1640  s->val[OPT_LED].w = SANE_TRUE;
1641
1642  /* CCD Power ? */
1643  s->opt[OPT_CCD].name = "ccd";
1644  s->opt[OPT_CCD].title = "CCD Power";
1645  s->opt[OPT_CCD].desc ="This option controls the power to the CCD array.";
1646  s->opt[OPT_CCD].type = SANE_TYPE_BOOL;
1647  if (s->hw->ScannerModel!=ONESCANNER && s->hw->ScannerModel!=COLORONESCANNER)
1648    s->opt[OPT_CCD].cap |= SANE_CAP_INACTIVE;
1649  s->val[OPT_CCD].w = SANE_TRUE;
1650
1651  /*  Use MTF Circuit */
1652  s->opt[OPT_MTF_CIRCUIT].name = "mtf";
1653  s->opt[OPT_MTF_CIRCUIT].title = "MTF Circuit";
1654  s->opt[OPT_MTF_CIRCUIT].desc ="Turns the MTF (Modulation Transfer Function) "
1655						"peaking circuit on or off.";
1656  s->opt[OPT_MTF_CIRCUIT].type = SANE_TYPE_BOOL;
1657  if (s->hw->ScannerModel!=COLORONESCANNER)
1658    s->opt[OPT_MTF_CIRCUIT].cap |= SANE_CAP_INACTIVE;
1659  s->val[OPT_MTF_CIRCUIT].w = SANE_TRUE;
1660
1661
1662  /* Use ICP */
1663  s->opt[OPT_ICP].name = "icp";
1664  s->opt[OPT_ICP].title = "ICP";
1665  s->opt[OPT_ICP].desc ="What is an ICP anyway?";
1666  s->opt[OPT_ICP].type = SANE_TYPE_BOOL;
1667  if (s->hw->ScannerModel!=COLORONESCANNER)
1668    s->opt[OPT_ICP].cap |= SANE_CAP_INACTIVE;
1669  s->val[OPT_ICP].w = SANE_TRUE;
1670
1671
1672  /* Data Polarity */
1673  s->opt[OPT_POLARITY].name = "polarity";
1674  s->opt[OPT_POLARITY].title = "Data Polarity";
1675  s->opt[OPT_POLARITY].desc = "Reverse black and white.";
1676  s->opt[OPT_POLARITY].type = SANE_TYPE_BOOL;
1677  if (s->hw->ScannerModel!=COLORONESCANNER)
1678    s->opt[OPT_POLARITY].cap |= SANE_CAP_INACTIVE;
1679  s->val[OPT_POLARITY].w = SANE_FALSE;
1680
1681
1682/* Color Functions: Advanced */
1683
1684  s->opt[OPT_COLOR_GROUP].title = SANE_VALUE_SCAN_MODE_COLOR;
1685  s->opt[OPT_COLOR_GROUP].desc = "";
1686  s->opt[OPT_COLOR_GROUP].type = SANE_TYPE_GROUP;
1687  s->opt[OPT_COLOR_GROUP].cap = SANE_CAP_ADVANCED;
1688  s->opt[OPT_COLOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1689
1690#ifdef CALIBRATION_FUNCTIONALITY
1691  /* OneScanner calibration vector */
1692  s->opt[OPT_CALIBRATION_VECTOR].name = "calibration-vector";
1693  s->opt[OPT_CALIBRATION_VECTOR].title = "Calibration Vector";
1694  s->opt[OPT_CALIBRATION_VECTOR].desc = "Calibration vector for the CCD array.";
1695  s->opt[OPT_CALIBRATION_VECTOR].type = SANE_TYPE_INT;
1696  if (s->hw->ScannerModel!=ONESCANNER)
1697    s->opt[OPT_CALIBRATION_VECTOR].cap |= SANE_CAP_INACTIVE;
1698  s->opt[OPT_CALIBRATION_VECTOR].unit = SANE_UNIT_NONE;
1699  s->opt[OPT_CALIBRATION_VECTOR].size = 2550 * sizeof (SANE_Word);
1700  s->opt[OPT_CALIBRATION_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
1701  s->opt[OPT_CALIBRATION_VECTOR].constraint.range = &u8_range;
1702  s->val[OPT_CALIBRATION_VECTOR].wa = s->calibration_vector;
1703
1704  /* ColorOneScanner calibration vector per band */
1705  s->opt[OPT_CALIBRATION_VECTOR_RED].name = "calibration-vector-red";
1706  s->opt[OPT_CALIBRATION_VECTOR_RED].title = "Calibration Vector for Red";
1707  s->opt[OPT_CALIBRATION_VECTOR_RED].desc = "Calibration vector for the CCD array.";
1708  s->opt[OPT_CALIBRATION_VECTOR_RED].type = SANE_TYPE_INT;
1709  if (s->hw->ScannerModel!=COLORONESCANNER)
1710    s->opt[OPT_CALIBRATION_VECTOR_RED].cap |= SANE_CAP_INACTIVE;
1711  s->opt[OPT_CALIBRATION_VECTOR_RED].unit = SANE_UNIT_NONE;
1712  s->opt[OPT_CALIBRATION_VECTOR_RED].size = 2700 * sizeof (SANE_Word);
1713  s->opt[OPT_CALIBRATION_VECTOR_RED].constraint_type = SANE_CONSTRAINT_RANGE;
1714  s->opt[OPT_CALIBRATION_VECTOR_RED].constraint.range = &u8_range;
1715  s->val[OPT_CALIBRATION_VECTOR_RED].wa = s->calibration_vector_red;
1716
1717  /* ColorOneScanner calibration vector per band */
1718  s->opt[OPT_CALIBRATION_VECTOR_GREEN].name = "calibration-vector-green";
1719  s->opt[OPT_CALIBRATION_VECTOR_GREEN].title = "Calibration Vector for Green";
1720  s->opt[OPT_CALIBRATION_VECTOR_GREEN].desc = "Calibration vector for the CCD array.";
1721  s->opt[OPT_CALIBRATION_VECTOR_GREEN].type = SANE_TYPE_INT;
1722  if (s->hw->ScannerModel!=COLORONESCANNER)
1723    s->opt[OPT_CALIBRATION_VECTOR].cap |= SANE_CAP_INACTIVE;
1724  s->opt[OPT_CALIBRATION_VECTOR_GREEN].unit = SANE_UNIT_NONE;
1725  s->opt[OPT_CALIBRATION_VECTOR_GREEN].size = 2700 * sizeof (SANE_Word);
1726  s->opt[OPT_CALIBRATION_VECTOR_GREEN].constraint_type = SANE_CONSTRAINT_RANGE;
1727  s->opt[OPT_CALIBRATION_VECTOR_GREEN].constraint.range = &u8_range;
1728  s->val[OPT_CALIBRATION_VECTOR_GREEN].wa = s->calibration_vector_green;
1729
1730  /* ColorOneScanner calibration vector per band */
1731  s->opt[OPT_CALIBRATION_VECTOR_BLUE].name = "calibration-vector-blue";
1732  s->opt[OPT_CALIBRATION_VECTOR_BLUE].title = "Calibration Vector for Blue";
1733  s->opt[OPT_CALIBRATION_VECTOR_BLUE].desc = "Calibration vector for the CCD array.";
1734  s->opt[OPT_CALIBRATION_VECTOR_BLUE].type = SANE_TYPE_INT;
1735  if (s->hw->ScannerModel!=COLORONESCANNER)
1736    s->opt[OPT_CALIBRATION_VECTOR_BLUE].cap |= SANE_CAP_INACTIVE;
1737  s->opt[OPT_CALIBRATION_VECTOR_BLUE].unit = SANE_UNIT_NONE;
1738  s->opt[OPT_CALIBRATION_VECTOR_BLUE].size = 2700 * sizeof (SANE_Word);
1739  s->opt[OPT_CALIBRATION_VECTOR_BLUE].constraint_type = SANE_CONSTRAINT_RANGE;
1740  s->opt[OPT_CALIBRATION_VECTOR_BLUE].constraint.range = &u8_range;
1741  s->val[OPT_CALIBRATION_VECTOR_BLUE].wa = s->calibration_vector_blue;
1742#endif /* CALIBRATION_FUNCTIONALITY */
1743
1744  /* Action: Download calibration vector */
1745  s->opt[OPT_DOWNLOAD_CALIBRATION_VECTOR].name = "download-calibration";
1746  s->opt[OPT_DOWNLOAD_CALIBRATION_VECTOR].title = "Download Calibration Vector";
1747  s->opt[OPT_DOWNLOAD_CALIBRATION_VECTOR].desc = "Download calibration vector to scanner";
1748  s->opt[OPT_DOWNLOAD_CALIBRATION_VECTOR].type = SANE_TYPE_BUTTON;
1749  if (s->hw->ScannerModel!=ONESCANNER && s->hw->ScannerModel!=COLORONESCANNER)
1750    s->opt[OPT_DOWNLOAD_CALIBRATION_VECTOR].cap |= SANE_CAP_INACTIVE;
1751
1752  /* custom-cct table */
1753  s->opt[OPT_CUSTOM_CCT].name = "custom-cct";
1754  s->opt[OPT_CUSTOM_CCT].title = "Use Custom CCT";
1755  s->opt[OPT_CUSTOM_CCT].desc ="Determines whether a builtin "
1756	"or a custom 3x3 Color Correction Table (CCT) should be used.";
1757  s->opt[OPT_CUSTOM_CCT].type = SANE_TYPE_BOOL;
1758  s->opt[OPT_CUSTOM_CCT].cap |= SANE_CAP_INACTIVE;
1759  if (s->hw->ScannerModel!=COLORONESCANNER)
1760    s->opt[OPT_CUSTOM_CCT].cap |= SANE_CAP_INACTIVE;
1761  s->val[OPT_CUSTOM_CCT].w = SANE_FALSE;
1762
1763
1764  /* CCT */
1765  s->opt[OPT_CCT].name = "cct";
1766  s->opt[OPT_CCT].title = "3x3 Color Correction Table";
1767  s->opt[OPT_CCT].desc = "TODO: Color Correction is currently unsupported";
1768  s->opt[OPT_CCT].type = SANE_TYPE_FIXED;
1769  s->opt[OPT_CCT].cap |= SANE_CAP_INACTIVE;
1770  s->opt[OPT_CCT].unit = SANE_UNIT_NONE;
1771  s->opt[OPT_CCT].size = 9 * sizeof (SANE_Word);
1772  s->opt[OPT_CCT].constraint_type = SANE_CONSTRAINT_RANGE;
1773  s->opt[OPT_CCT].constraint.range = &u8_range;
1774  s->val[OPT_CCT].wa = s->cct3x3;
1775
1776
1777  /* Action: custom 3x3 color correction table */
1778  s->opt[OPT_DOWNLOAD_CCT].name = "download-3x3";
1779  s->opt[OPT_DOWNLOAD_CCT].title = "Download 3x3 CCT";
1780  s->opt[OPT_DOWNLOAD_CCT].desc = "Download 3x3 color correction table";
1781  s->opt[OPT_DOWNLOAD_CCT].type = SANE_TYPE_BUTTON;
1782  if (s->hw->ScannerModel!=COLORONESCANNER)
1783    s->opt[OPT_DOWNLOAD_CCT].cap |= SANE_CAP_INACTIVE;
1784
1785
1786  /* custom-gamma table */
1787  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
1788  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
1789  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
1790  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
1791  s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1792  s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
1793
1794  /* red gamma vector */
1795  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
1796  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1797  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
1798  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
1799  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1800  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
1801  s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
1802  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1803  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
1804  s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[0][0];
1805
1806  /* green gamma vector */
1807  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
1808  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1809  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
1810  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
1811  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1812  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
1813  s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
1814  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1815  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
1816  s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[1][0];
1817
1818  /* blue gamma vector */
1819  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
1820  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1821  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
1822  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
1823  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1824  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
1825  s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
1826  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1827  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
1828  s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[2][0];
1829
1830  /* Action: download gamma vectors table */
1831  s->opt[OPT_DOWNLOAD_GAMMA].name = "download-gamma";
1832  s->opt[OPT_DOWNLOAD_GAMMA].title = "Download Gamma Vector(s)";
1833  s->opt[OPT_DOWNLOAD_GAMMA].desc = "Download Gamma Vector(s).";
1834  s->opt[OPT_DOWNLOAD_GAMMA].type = SANE_TYPE_BUTTON;
1835  s->opt[OPT_DOWNLOAD_GAMMA].cap |= SANE_CAP_INACTIVE;
1836
1837  s->opt[OPT_COLOR_SENSOR].name = "color-sensor";
1838  s->opt[OPT_COLOR_SENSOR].title = "Gray scan with";
1839  s->opt[OPT_COLOR_SENSOR].desc = "Select the color sensor to scan in gray mode.";
1840  s->opt[OPT_COLOR_SENSOR].type = SANE_TYPE_STRING;
1841  s->opt[OPT_COLOR_SENSOR].unit = SANE_UNIT_NONE;
1842  s->opt[OPT_COLOR_SENSOR].size = max_string_size (color_sensor_list);
1843  if (s->hw->ScannerModel!=COLORONESCANNER)
1844    s->opt[OPT_COLOR_SENSOR].cap |= SANE_CAP_INACTIVE;
1845  s->opt[OPT_COLOR_SENSOR].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1846  s->opt[OPT_COLOR_SENSOR].constraint.string_list = color_sensor_list;
1847  s->val[OPT_COLOR_SENSOR].s = strdup(color_sensor_list[2]);
1848
1849
1850  mode_update (s, s->val[OPT_MODE].s);
1851
1852  return SANE_STATUS_GOOD;
1853}
1854
1855static SANE_Status
1856attach_one (const char *dev)
1857{
1858  attach (dev, 0, SANE_FALSE);
1859  return SANE_STATUS_GOOD;
1860}
1861
1862SANE_Status
1863sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
1864{
1865  char dev_name[PATH_MAX];
1866  size_t len;
1867  FILE *fp;
1868
1869  (void) authorize;			/* silence gcc */
1870
1871  DBG_INIT ();
1872
1873  if (version_code)
1874    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
1875
1876  fp = sanei_config_open (APPLE_CONFIG_FILE);
1877  if (!fp)
1878    {
1879      /* default to /dev/scanner instead of insisting on config file */
1880      attach ("/dev/scanner", 0, SANE_FALSE);
1881      return SANE_STATUS_GOOD;
1882    }
1883
1884  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
1885    {
1886      if (dev_name[0] == '#')	/* ignore line comments */
1887	continue;
1888
1889      len = strlen (dev_name);
1890
1891      if (!len)
1892	continue;		/* ignore empty lines */
1893
1894      if (strncmp (dev_name, "option", 6) == 0
1895	  && isspace (dev_name[6]))
1896	{
1897	  const char *str = dev_name + 7;
1898
1899	  while (isspace (*str))
1900	    ++str;
1901
1902	  continue;
1903	}
1904
1905      sanei_config_attach_matching_devices (dev_name, attach_one);
1906    }
1907  fclose (fp);
1908  return SANE_STATUS_GOOD;
1909}
1910
1911void
1912sane_exit (void)
1913{
1914  Apple_Device *dev, *next;
1915
1916  for (dev = first_dev; dev; dev = next)
1917    {
1918      next = dev->next;
1919      free ((void *) dev->sane.name);
1920      free ((void *) dev->sane.model);
1921      free (dev);
1922    }
1923  if (devlist)
1924    free (devlist);
1925}
1926
1927SANE_Status
1928sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1929{
1930  Apple_Device *dev;
1931  int i;
1932
1933  (void) local_only;			/* silence gcc */
1934
1935  if (devlist)
1936    free (devlist);
1937
1938  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
1939  if (!devlist)
1940    return SANE_STATUS_NO_MEM;
1941
1942  i = 0;
1943  for (dev = first_dev; i < num_devices; dev = dev->next)
1944    devlist[i++] = &dev->sane;
1945  devlist[i++] = 0;
1946
1947  *device_list = devlist;
1948  return SANE_STATUS_GOOD;
1949}
1950
1951SANE_Status
1952sane_open (SANE_String_Const devicename, SANE_Handle * handle)
1953{
1954  Apple_Device *dev;
1955  SANE_Status status;
1956  Apple_Scanner *s;
1957  int i, j;
1958
1959  if (devicename[0])
1960    {
1961      for (dev = first_dev; dev; dev = dev->next)
1962	if (strcmp (dev->sane.name, devicename) == 0)
1963	  break;
1964
1965      if (!dev)
1966	{
1967	  status = attach (devicename, &dev, SANE_TRUE);
1968	  if (status != SANE_STATUS_GOOD)
1969	    return status;
1970	}
1971    }
1972  else
1973    /* empty devicname -> use first device */
1974    dev = first_dev;
1975
1976  if (!dev)
1977    return SANE_STATUS_INVAL;
1978
1979  s = malloc (sizeof (*s));
1980  if (!s)
1981    return SANE_STATUS_NO_MEM;
1982  memset (s, 0, sizeof (*s));
1983  s->fd = -1;
1984  s->hw = dev;
1985  for (i = 0; i < 3; ++i)
1986    for (j = 0; j < 256; ++j)
1987      s->gamma_table[i][j] = j;
1988
1989  init_options (s);
1990
1991  /* insert newly opened handle into list of open handles: */
1992  s->next = first_handle;
1993  first_handle = s;
1994
1995  *handle = s;
1996  return SANE_STATUS_GOOD;
1997}
1998
1999void
2000sane_close (SANE_Handle handle)
2001{
2002  Apple_Scanner *prev, *s;
2003
2004  /* remove handle from list of open handles: */
2005  prev = 0;
2006  for (s = first_handle; s; s = s->next)
2007    {
2008      if (s == handle)
2009	break;
2010      prev = s;
2011    }
2012  if (!s)
2013    {
2014      DBG (ERROR_MESSAGE, "close: invalid handle %p\n", handle);
2015      return;			/* oops, not a handle we know about */
2016    }
2017
2018  if (prev)
2019    prev->next = s->next;
2020  else
2021    first_handle = s->next;
2022
2023  free (handle);
2024}
2025
2026const SANE_Option_Descriptor *
2027sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
2028{
2029  Apple_Scanner *s = handle;
2030
2031  if ((unsigned) option >= NUM_OPTIONS)
2032    return 0;
2033  return s->opt + option;
2034}
2035
2036SANE_Status
2037sane_control_option (SANE_Handle handle, SANE_Int option,
2038		     SANE_Action action, void *val, SANE_Int * info)
2039{
2040  Apple_Scanner *s = handle;
2041  SANE_Status status;
2042  SANE_Word cap;
2043
2044
2045  DBG (FLOW_CONTROL, "(%s): Entering on control_option for option %s (%d).\n",
2046       (action == SANE_ACTION_GET_VALUE) ? "get" : "set",
2047       s->opt[option].name, option);
2048
2049  if (val || action == SANE_ACTION_GET_VALUE)
2050    switch (s->opt[option].type)
2051      {
2052      case SANE_TYPE_STRING:
2053	DBG (FLOW_CONTROL, "Value %s\n", (action == SANE_ACTION_GET_VALUE) ?
2054	  s->val[option].s : (char *) val);
2055	break;
2056      case SANE_TYPE_FIXED:
2057	{
2058	double v1, v2;
2059	SANE_Fixed f;
2060	v1 = SANE_UNFIX (s->val[option].w);
2061	f = *(SANE_Fixed *) val;
2062	v2 = SANE_UNFIX (f);
2063	DBG (FLOW_CONTROL, "Value %g (Fixed)\n",
2064	     (action == SANE_ACTION_GET_VALUE) ? v1 : v2);
2065	break;
2066	}
2067      default:
2068	DBG (FLOW_CONTROL, "Value %u (Int).\n",
2069		(action == SANE_ACTION_GET_VALUE)
2070			? s->val[option].w : *(SANE_Int *) val);
2071	break;
2072      }
2073
2074
2075  if (info)
2076    *info = 0;
2077
2078  if (s->scanning)
2079    return SANE_STATUS_DEVICE_BUSY;
2080
2081  if (option >= NUM_OPTIONS)
2082    return SANE_STATUS_INVAL;
2083
2084  cap = s->opt[option].cap;
2085
2086  if (!SANE_OPTION_IS_ACTIVE (cap))
2087    return SANE_STATUS_INVAL;
2088
2089
2090  if (action == SANE_ACTION_GET_VALUE)
2091    {
2092      switch (option)
2093	{
2094	  /* word options: */
2095	case OPT_NUM_OPTS:
2096	case OPT_RESOLUTION:
2097	case OPT_PREVIEW:
2098	case OPT_TL_X:
2099	case OPT_TL_Y:
2100	case OPT_BR_X:
2101	case OPT_BR_Y:
2102	case OPT_BRIGHTNESS:
2103	case OPT_CONTRAST:
2104	case OPT_THRESHOLD:
2105	case OPT_AUTOBACKGROUND:
2106	case OPT_AUTOBACKGROUND_THRESHOLD:
2107	case OPT_VOLT_REF:
2108	case OPT_VOLT_REF_TOP:
2109	case OPT_VOLT_REF_BOTTOM:
2110
2111	case OPT_LAMP:
2112	case OPT_WAIT:
2113	case OPT_CALIBRATE:
2114	case OPT_LED:
2115	case OPT_CCD:
2116	case OPT_MTF_CIRCUIT:
2117	case OPT_ICP:
2118	case OPT_POLARITY:
2119
2120	case OPT_CUSTOM_CCT:
2121	case OPT_CUSTOM_GAMMA:
2122	  *(SANE_Word *) val = s->val[option].w;
2123	  return SANE_STATUS_GOOD;
2124
2125	  /* word-array options: */
2126
2127	case OPT_CCT:
2128	case OPT_GAMMA_VECTOR_R:
2129	case OPT_GAMMA_VECTOR_G:
2130	case OPT_GAMMA_VECTOR_B:
2131	  memcpy (val, s->val[option].wa, s->opt[option].size);
2132	  return SANE_STATUS_GOOD;
2133
2134	  /* string options: */
2135
2136	case OPT_MODE:
2137/*
2138TODO: This is to protect the mode string to be ruined from the dll?
2139backend. I do not know why. It's definitely an overkill and should be
2140eliminated.
2141	  status = sanei_constrain_value (s->opt + option, s->val[option].s,
2142					  info);
2143*/
2144	case OPT_MODEL:
2145	case OPT_GRAYMAP:
2146	case OPT_HALFTONE_PATTERN:
2147	case OPT_HALFTONE_FILE:
2148	case OPT_SPEED:
2149	case OPT_COLOR_SENSOR:
2150	  strcpy (val, s->val[option].s);
2151	  return SANE_STATUS_GOOD;
2152
2153/* Some Buttons */
2154	case OPT_DOWNLOAD_CALIBRATION_VECTOR:
2155	case OPT_DOWNLOAD_CCT:
2156	case OPT_DOWNLOAD_GAMMA:
2157	  return SANE_STATUS_INVAL;
2158
2159	}
2160    }
2161  else if (action == SANE_ACTION_SET_VALUE)
2162    {
2163      if (!SANE_OPTION_IS_SETTABLE (cap))
2164	return SANE_STATUS_INVAL;
2165
2166      status = sanei_constrain_value (s->opt + option, val, info);
2167
2168      if (status != SANE_STATUS_GOOD)
2169	return status;
2170
2171
2172      switch (option)
2173	{
2174	  /* (mostly) side-effect-free word options: */
2175	case OPT_RESOLUTION:
2176	case OPT_TL_X:
2177	case OPT_TL_Y:
2178	case OPT_BR_X:
2179	case OPT_BR_Y:
2180
2181	  s->val[option].w = *(SANE_Word *) val;
2182	  calc_parameters (s);
2183
2184	  if (info)
2185	    *info |= SANE_INFO_RELOAD_PARAMS
2186	      | SANE_INFO_RELOAD_OPTIONS
2187	      | SANE_INFO_INEXACT;
2188
2189	  return SANE_STATUS_GOOD;
2190
2191	  /* fall through */
2192	case OPT_BRIGHTNESS:
2193	case OPT_CONTRAST:
2194	case OPT_THRESHOLD:
2195	case OPT_AUTOBACKGROUND_THRESHOLD:
2196	case OPT_VOLT_REF_TOP:
2197	case OPT_VOLT_REF_BOTTOM:
2198	case OPT_LAMP:
2199	case OPT_WAIT:
2200	case OPT_CALIBRATE:
2201	case OPT_LED:
2202	case OPT_CCD:
2203	case OPT_MTF_CIRCUIT:
2204	case OPT_ICP:
2205	case OPT_POLARITY:
2206	  s->val[option].w = *(SANE_Word *) val;
2207	  return SANE_STATUS_GOOD;
2208
2209	  /* Simple Strings */
2210	case OPT_GRAYMAP:
2211	case OPT_HALFTONE_FILE:
2212	case OPT_SPEED:
2213	  if (s->val[option].s)
2214	    free (s->val[option].s);
2215	  s->val[option].s = strdup (val);
2216	  return SANE_STATUS_GOOD;
2217
2218	  /* Boolean */
2219	case OPT_PREVIEW:
2220	  s->val[option].w = *(SANE_Bool *) val;
2221	  return SANE_STATUS_GOOD;
2222
2223
2224	  /* side-effect-free word-array options: */
2225	case OPT_CCT:
2226	case OPT_GAMMA_VECTOR_R:
2227	case OPT_GAMMA_VECTOR_G:
2228	case OPT_GAMMA_VECTOR_B:
2229	  memcpy (s->val[option].wa, val, s->opt[option].size);
2230	  return SANE_STATUS_GOOD;
2231
2232
2233	  /* options with light side-effects: */
2234
2235	case OPT_HALFTONE_PATTERN:
2236	  if (info)
2237	    *info |= SANE_INFO_RELOAD_OPTIONS;
2238	  if (s->val[option].s)
2239	    free (s->val[option].s);
2240	  s->val[option].s = strdup (val);
2241	  if (!strcmp (val, "download"))
2242	    {
2243	      return SANE_STATUS_UNSUPPORTED;
2244	      /* TODO: ENABLE(OPT_HALFTONE_FILE); */
2245	    }
2246	  else
2247	    DISABLE (OPT_HALFTONE_FILE);
2248	  return SANE_STATUS_GOOD;
2249
2250	case OPT_AUTOBACKGROUND:
2251	  if (info)
2252	    *info |= SANE_INFO_RELOAD_OPTIONS;
2253	  s->val[option].w = *(SANE_Bool *) val;
2254	  if (*(SANE_Bool *) val)
2255	    {
2256	      DISABLE (OPT_THRESHOLD);
2257	      ENABLE (OPT_AUTOBACKGROUND_THRESHOLD);
2258	    }
2259	  else
2260	    {
2261	      ENABLE (OPT_THRESHOLD);
2262	      DISABLE (OPT_AUTOBACKGROUND_THRESHOLD);
2263	    }
2264	  return SANE_STATUS_GOOD;
2265	case OPT_VOLT_REF:
2266	  if (info)
2267	    *info |= SANE_INFO_RELOAD_OPTIONS;
2268	  s->val[option].w = *(SANE_Bool *) val;
2269	  if (*(SANE_Bool *) val)
2270	    {
2271	    DISABLE(OPT_BRIGHTNESS);
2272	    DISABLE(OPT_CONTRAST);
2273	    ENABLE(OPT_VOLT_REF_TOP);
2274	    ENABLE(OPT_VOLT_REF_BOTTOM);
2275	    }
2276	  else
2277	    {
2278	    ENABLE(OPT_BRIGHTNESS);
2279	    ENABLE(OPT_CONTRAST);
2280	    DISABLE(OPT_VOLT_REF_TOP);
2281	    DISABLE(OPT_VOLT_REF_BOTTOM);
2282	    }
2283	  return SANE_STATUS_GOOD;
2284
2285/* Actions: Buttons */
2286
2287	case OPT_DOWNLOAD_CALIBRATION_VECTOR:
2288	case OPT_DOWNLOAD_CCT:
2289	case OPT_DOWNLOAD_GAMMA:
2290	  /* TODO: fix {down/up}loads */
2291	  return SANE_STATUS_UNSUPPORTED;
2292
2293	case OPT_CUSTOM_CCT:
2294	  s->val[OPT_CUSTOM_CCT].w=*(SANE_Word *) val;
2295	  if (s->val[OPT_CUSTOM_CCT].w)
2296	    {
2297		ENABLE(OPT_CCT);
2298		ENABLE(OPT_DOWNLOAD_CCT);
2299	    }
2300	  else
2301	    {
2302		DISABLE(OPT_CCT);
2303		DISABLE(OPT_DOWNLOAD_CCT);
2304	    }
2305	  if (info)
2306	    *info |= SANE_INFO_RELOAD_OPTIONS;
2307	  return SANE_STATUS_GOOD;
2308
2309	case OPT_CUSTOM_GAMMA:
2310	  s->val[OPT_CUSTOM_GAMMA].w = *(SANE_Word *) val;
2311	  gamma_update(s);
2312	  if (info)
2313	    *info |= SANE_INFO_RELOAD_OPTIONS;
2314	  return SANE_STATUS_GOOD;
2315
2316	case OPT_COLOR_SENSOR:
2317	  if (s->val[option].s)
2318	    free (s->val[option].s);
2319	  s->val[option].s = strdup (val);
2320	  gamma_update(s);
2321	  if (info)
2322	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2323	  return SANE_STATUS_GOOD;
2324
2325	  /* HEAVY (RADIOACTIVE) SIDE EFFECTS: CHECKME */
2326	case OPT_MODE:
2327	  if (s->val[option].s)
2328	    free (s->val[option].s);
2329	  s->val[option].s = strdup (val);
2330
2331	  status = mode_update (s, val);
2332	  if (status != SANE_STATUS_GOOD)
2333	    return status;
2334
2335	  if (info)
2336	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2337	  return SANE_STATUS_GOOD;
2338
2339	}			/* End of switch */
2340    }				/* End of SET_VALUE */
2341  return SANE_STATUS_INVAL;
2342}
2343
2344SANE_Status
2345sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
2346{
2347  Apple_Scanner *s = handle;
2348
2349  DBG (FLOW_CONTROL, "Entering sane_get_parameters\n");
2350  calc_parameters (s);
2351
2352
2353  if (params)
2354    *params = s->params;
2355  return SANE_STATUS_GOOD;
2356}
2357
2358SANE_Status
2359sane_start (SANE_Handle handle)
2360{
2361  Apple_Scanner *s = handle;
2362  SANE_Status status;
2363
2364  /* First make sure we have a current parameter set.  Some of the
2365     parameters will be overwritten below, but that's OK.  */
2366
2367  calc_parameters (s);
2368
2369  if (s->fd < 0)
2370    {
2371      /* this is the first (and maybe only) pass... */
2372
2373      status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0);
2374      if (status != SANE_STATUS_GOOD)
2375	{
2376	  DBG (ERROR_MESSAGE, "open: open of %s failed: %s\n",
2377	       s->hw->sane.name, sane_strstatus (status));
2378	  return status;
2379	}
2380    }
2381
2382  status = wait_ready (s->fd);
2383  if (status != SANE_STATUS_GOOD)
2384    {
2385      DBG (ERROR_MESSAGE, "open: wait_ready() failed: %s\n",
2386	   sane_strstatus (status));
2387      goto stop_scanner_and_return;
2388    }
2389
2390  status = mode_select (s);
2391  if (status != SANE_STATUS_GOOD)
2392    {
2393      DBG (ERROR_MESSAGE, "sane_start: mode_select command failed: %s\n",
2394	   sane_strstatus (status));
2395      goto stop_scanner_and_return;
2396    }
2397
2398  status = scan_area_and_windows (s);
2399  if (status != SANE_STATUS_GOOD)
2400    {
2401      DBG (ERROR_MESSAGE, "open: set scan area command failed: %s\n",
2402	   sane_strstatus (status));
2403      goto stop_scanner_and_return;
2404    }
2405
2406  status = request_sense (s);
2407  if (status != SANE_STATUS_GOOD)
2408    {
2409      DBG (ERROR_MESSAGE, "sane_start: request_sense revealed error: %s\n",
2410	   sane_strstatus (status));
2411      goto stop_scanner_and_return;
2412    }
2413
2414  s->scanning = SANE_TRUE;
2415  s->AbortedByUser = SANE_FALSE;
2416
2417  status = start_scan (s);
2418  if (status != SANE_STATUS_GOOD)
2419    goto stop_scanner_and_return;
2420
2421  return SANE_STATUS_GOOD;
2422
2423stop_scanner_and_return:
2424  s->scanning = SANE_FALSE;
2425  s->AbortedByUser = SANE_FALSE;
2426  return status;
2427}
2428
2429SANE_Status
2430sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
2431	   SANE_Int * len)
2432{
2433  Apple_Scanner *s = handle;
2434  SANE_Status status;
2435
2436  uint8_t get_data_status[10];
2437  uint8_t read[10];
2438
2439#ifdef RESERVE_RELEASE_HACK
2440  uint8_t reserve[6];
2441  uint8_t release[6];
2442#endif
2443
2444  uint8_t result[12];
2445  size_t size;
2446  SANE_Int data_length = 0;
2447  SANE_Int data_av = 0;
2448  SANE_Int offset = 0;
2449  SANE_Int rread = 0;
2450  SANE_Bool Pseudo8bit = SANE_FALSE;
2451
2452#ifdef NEUTRALIZE_BACKEND
2453  *len=max_len;
2454  return SANE_STATUS_GOOD;
2455
2456#else
2457  *len = 0;
2458  if (!s->scanning) return SANE_STATUS_EOF;
2459
2460
2461  if (!strcmp (s->val[OPT_MODE].s, "Gray16"))
2462    Pseudo8bit = SANE_TRUE;
2463
2464  /* TODO: The current function only implements for APPLESCANNER In
2465     order to use the COLORONESCANNER you have to study the docs to
2466     see how it the parameters get modified before scan. From this
2467     starting point it should be trivial to use a ONESCANNER int the
2468     gray256 mode but I don't have one from these pets in home.  MF */
2469
2470
2471  memset (get_data_status, 0, sizeof (get_data_status));
2472  get_data_status[0] = APPLE_SCSI_GET_DATA_STATUS;
2473  get_data_status[1] = 1;	/* Wait */
2474  STORE24 (get_data_status + 6, sizeof (result));
2475
2476  memset (read, 0, sizeof (read));
2477  read[0] = APPLE_SCSI_READ_SCANNED_DATA;
2478
2479
2480#ifdef RESERVE_RELEASE_HACK
2481  memset (reserve, 0, sizeof (reserve));
2482  reserve[0] = APPLE_SCSI_RESERVE;
2483
2484  reserve[1]=CONTROLLER_SCSI_ID;
2485  reserve[1]=reserve[1] << 1;
2486  reserve[1]|=SETTHIRDPARTY;
2487
2488  memset (release, 0, sizeof (release));
2489  release[0] = APPLE_SCSI_RELEASE;
2490  release[1]=CONTROLLER_SCSI_ID;
2491  release[1]=reserve[1] << 1;
2492  release[1]|=SETTHIRDPARTY;
2493
2494#endif
2495
2496  do
2497    {
2498      size = sizeof (result);
2499      status = sanei_scsi_cmd (s->fd, get_data_status,
2500			       sizeof (get_data_status), result, &size);
2501
2502      if (status != SANE_STATUS_GOOD)
2503	return status;
2504      if (!size)
2505	{
2506	  DBG (ERROR_MESSAGE, "sane_read: cannot get_data_status.\n");
2507	  return SANE_STATUS_IO_ERROR;
2508	}
2509
2510      data_length = READ24 (result);
2511      data_av = READ24 (result + 9);
2512
2513      if (data_length)
2514	{
2515	  /* if (result[3] & 1)	Scanner Blocked: Retrieve data */
2516	  if ((result[3] & 1) || data_av)
2517	    {
2518	      DBG (IO_MESSAGE,
2519		   "sane_read: (status) Available in scanner buffer %u.\n",
2520		   data_av);
2521
2522	      if (Pseudo8bit)
2523		if ((data_av << 1) + offset > max_len)
2524		  rread = (max_len - offset) >> 1;
2525		else
2526		  rread = data_av;
2527	      else if (data_av + offset > max_len)
2528		rread = max_len - offset;
2529	      else
2530		rread = data_av;
2531
2532	      DBG (IO_MESSAGE,
2533		   "sane_read: (action) Actual read request for %u bytes.\n",
2534		   rread);
2535
2536	      size = rread;
2537
2538	      STORE24 (read + 6, rread);
2539
2540#ifdef RESERVE_RELEASE_HACK
2541	      {
2542	      SANE_Status status;
2543	      DBG(IO_MESSAGE,"Reserving the SCSI bus.\n");
2544	      status=sanei_scsi_cmd (s->fd,reserve,sizeof(reserve),0,0);
2545	      DBG(IO_MESSAGE,"Reserving... status:= %d\n",status);
2546	      }
2547#endif /* RESERVE_RELEASE_HACK */
2548
2549	      status = sanei_scsi_cmd (s->fd, read, sizeof (read),
2550				       buf + offset, &size);
2551
2552#ifdef RESERVE_RELEASE_HACK
2553	      {
2554	      SANE_Status status;
2555	      DBG(IO_MESSAGE,"Releasing the SCSI bus.\n");
2556	      status=sanei_scsi_cmd (s->fd,release,sizeof(release),0,0);
2557	      DBG(IO_MESSAGE,"Releasing... status:= %d\n",status);
2558	      }
2559#endif /* RESERVE_RELEASE_HACK */
2560
2561
2562	      if (Pseudo8bit)
2563		{
2564		  SANE_Int byte;
2565		  SANE_Int pos = offset + (rread << 1) - 1;
2566		  SANE_Byte B;
2567		  for (byte = offset + rread - 1; byte >= offset; byte--)
2568		    {
2569		      B = buf[byte];
2570		      buf[pos--] = 255 - (B << 4);   /* low (right) nibble */
2571		      buf[pos--] = 255 - (B & 0xF0); /* high (left) nibble */
2572		    }
2573		  offset += size << 1;
2574		}
2575	      else
2576		offset += size;
2577
2578	      DBG (IO_MESSAGE, "sane_read: Buffer %u of %u full %g%%\n",
2579		   offset, max_len, (double) (offset * 100. / max_len));
2580	    }
2581	}
2582    }
2583  while (offset < max_len && data_length != 0 && !s->AbortedByUser);
2584
2585
2586  if (s->AbortedByUser)
2587    {
2588      s->scanning = SANE_FALSE;
2589      status = sanei_scsi_cmd (s->fd, test_unit_ready,
2590			       sizeof (test_unit_ready), 0, 0);
2591      if (status != SANE_STATUS_GOOD)
2592	return status;
2593      return SANE_STATUS_CANCELLED;
2594    }
2595
2596  if (!data_length)		/* If not blocked */
2597    {
2598      s->scanning = SANE_FALSE;
2599
2600      DBG (IO_MESSAGE, "sane_read: (status) Oups! No more data...");
2601      if (!offset)
2602	{
2603	  *len = 0;
2604	  DBG (IO_MESSAGE, "EOF\n");
2605	  return SANE_STATUS_EOF;
2606	}
2607      else
2608	{
2609	  *len = offset;
2610	  DBG (IO_MESSAGE, "GOOD\n");
2611	  return SANE_STATUS_GOOD;
2612	}
2613    }
2614
2615
2616  DBG (FLOW_CONTROL,
2617       "sane_read: Normal Exiting (?), Aborted=%u, data_length=%u\n",
2618       s->AbortedByUser, data_length);
2619  *len = offset;
2620
2621  return SANE_STATUS_GOOD;
2622
2623#endif /* NEUTRALIZE_BACKEND */
2624}
2625
2626void
2627sane_cancel (SANE_Handle handle)
2628{
2629  Apple_Scanner *s = handle;
2630
2631  if (s->scanning)
2632    {
2633      if (s->AbortedByUser)
2634	{
2635	  DBG (FLOW_CONTROL,
2636	       "sane_cancel: Already Aborted. Please Wait...\n");
2637	}
2638      else
2639	{
2640	  s->scanning=SANE_FALSE;
2641	  s->AbortedByUser = SANE_TRUE;
2642	  DBG (FLOW_CONTROL, "sane_cancel: Signal Caught! Aborting...\n");
2643	}
2644    }
2645  else
2646    {
2647      if (s->AbortedByUser)
2648	{
2649	  DBG (FLOW_CONTROL, "sane_cancel: Scan has not been Initiated yet, "
2650	       "or it is already aborted.\n");
2651	  s->AbortedByUser = SANE_FALSE;
2652	  sanei_scsi_cmd (s->fd, test_unit_ready,
2653				sizeof (test_unit_ready), 0, 0);
2654	}
2655      else
2656	{
2657	  DBG (FLOW_CONTROL, "sane_cancel: Scan has not been Initiated "
2658	       "yet (or it's over).\n");
2659	}
2660    }
2661
2662  return;
2663}
2664
2665SANE_Status
2666sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2667{
2668DBG (FLOW_CONTROL,"sane_set_io_mode: Entering.\n");
2669
2670 (void) handle;				/* silence gcc */
2671
2672if (non_blocking)
2673  {
2674  DBG (FLOW_CONTROL, "sane_set_io_mode: Don't call me please. "
2675       "Unimplemented function\n");
2676  return SANE_STATUS_UNSUPPORTED;
2677  }
2678
2679return SANE_STATUS_GOOD;
2680}
2681
2682SANE_Status
2683sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
2684{
2685  (void) handle;			/* silence gcc */
2686  (void) fd;				/* silence gcc */
2687
2688  DBG (FLOW_CONTROL, "sane_get_select_fd: Don't call me please. "
2689       "Unimplemented function\n");
2690  return SANE_STATUS_UNSUPPORTED;
2691}
2692