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