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