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 
137 static const SANE_Device **devlist = 0;
138 static int num_devices;
139 static Apple_Device *first_dev;
140 static Apple_Scanner *first_handle;
141 
142 
143 static SANE_String_Const mode_list[6];
144 
145 static 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",
151 NULL
152 };
153 
154 static const SANE_String_Const graymap_list[] =
155 {
156   "dark", "normal", "light",
157   0
158 };
159 
160 #if 0
161 static const SANE_Int resbit4_list[] =
162 {
163   5,
164   75, 100, 150, 200, 300
165 };
166 
167 static 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 
175 static const SANE_Int resbit_list[] =
176 {
177   5,
178   75, 100, 150, 200, 300
179 };
180 
181 static const SANE_String_Const speed_list[] =
182 {
183   "normal", "high", "high wo H/S",
184   0
185 };
186 
187 static SANE_String_Const halftone_pattern_list[6];
188 
189 static 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 */
197 static const SANE_Range byte_range =
198 {
199   1, 255, 1
200 };
201 
202 static 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 
216 static const uint8_t inquiry[] =
217 {
218   APPLE_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00
219 };
220 
221 static const uint8_t test_unit_ready[] =
222 {
223   APPLE_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00
224 };
225 
226 
227 #if 0
228 SANE_Int
229 xqstep (unsigned int Xres, unsigned int bpp)
230 {
231   return (SANE_Int) ((double) (8 * 1200)) / ((double) (Xres * bpp));
232 }
233 
234 
235 SANE_Int
236 yqstep (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 
247 static SANE_Int
xquant(double x,unsigned int Xres,unsigned int bpp,int dir)248 xquant (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 
265 static SANE_Int
yquant(double y,unsigned int Yres,int dir)266 yquant (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 
281 static SANE_Status
wait_ready(int fd)282 wait_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
289 return 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 
328 static SANE_Status
sense_handler(int scsi_fd,u_char * result,void * arg)329 sense_handler (int scsi_fd, u_char * result, void *arg)
330 {
331   scsi_fd = scsi_fd;			/* silence gcc */
332   arg = 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 
364 static SANE_Status
request_sense(Apple_Scanner * s)365 request_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
376 return 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 
473 static SANE_Status
attach(const char * devname,Apple_Device ** devp,int may_wait)474 attach (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
494 result[0]=0x06;
495 strcpy(result +  8, "APPLE   ");
496 
497 if (APPLE_MODEL_SELECT==APPLESCANNER)
498   strcpy(result + 16, "SCANNER A9M0337 ");
499 if (APPLE_MODEL_SELECT==ONESCANNER)
500   strcpy(result + 16, "SCANNER II      ");
501 if (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 
617 static size_t
max_string_size(const SANE_String_Const strings[])618 max_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 
633 static SANE_Status
scan_area_and_windows(Apple_Scanner * s)634 scan_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
642 return 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 */
701 if (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 
743 static SANE_Status
mode_select(Apple_Scanner * s)744 mode_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 
836 static SANE_Status
start_scan(Apple_Scanner * s)837 start_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 
872 static SANE_Status
calc_parameters(Apple_Scanner * s)873 calc_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 
1059 static SANE_Status
gamma_update(SANE_Handle handle)1060 gamma_update(SANE_Handle handle)
1061 {
1062 Apple_Scanner *s = handle;
1063 
1064 
1065 if (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 */
1124 else
1125   {
1126 disall:
1127   DISABLE (OPT_CUSTOM_GAMMA);
1128 discustom:
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 
1135 return SANE_STATUS_GOOD;
1136 }
1137 
1138 
1139 static SANE_Status
mode_update(SANE_Handle handle,char * val)1140 mode_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 
1276 static SANE_Status
init_options(Apple_Scanner * s)1277 init_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 
1855 static SANE_Status
attach_one(const char * dev)1856 attach_one (const char *dev)
1857 {
1858   attach (dev, 0, SANE_FALSE);
1859   return SANE_STATUS_GOOD;
1860 }
1861 
1862 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)1863 sane_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   authorize = authorize;	/* silence gcc */
1870 
1871   DBG_INIT ();
1872 
1873   if (version_code)
1874     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_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 
1911 void
sane_exit(void)1912 sane_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 
1927 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)1928 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1929 {
1930   Apple_Device *dev;
1931   int i;
1932 
1933   local_only = 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 
1951 SANE_Status
sane_open(SANE_String_Const devicename,SANE_Handle * handle)1952 sane_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 
1999 void
sane_close(SANE_Handle handle)2000 sane_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 
2026 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)2027 sane_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 
2036 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)2037 sane_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 /*
2138 TODO: This is to protect the mode string to be ruined from the dll?
2139 backend. I do not know why. It's definitely an overkill and should be
2140 eliminated.
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 
2344 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)2345 sane_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 
2358 SANE_Status
sane_start(SANE_Handle handle)2359 sane_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 
2423 stop_scanner_and_return:
2424   s->scanning = SANE_FALSE;
2425   s->AbortedByUser = SANE_FALSE;
2426   return status;
2427 }
2428 
2429 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * buf,SANE_Int max_len,SANE_Int * len)2430 sane_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 
2626 void
sane_cancel(SANE_Handle handle)2627 sane_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 
2665 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)2666 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2667 {
2668 DBG (FLOW_CONTROL,"sane_set_io_mode: Entering.\n");
2669 
2670  handle = handle;				/* silence gcc */
2671 
2672 if (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 
2679 return SANE_STATUS_GOOD;
2680 }
2681 
2682 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)2683 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
2684 {
2685   handle = handle;				/* silence gcc */
2686   fd = 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