1/* sane - Scanner Access Now Easy. 2 Copyright (C) 1996 David Mosberger-Tang 3 Copyright (C) 1997 R.E.Wolff@BitWizard.nl 4 This file is part of the SANE package. 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License as 8 published by the Free Software Foundation; either version 2 of the 9 License, or (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <https://www.gnu.org/licenses/>. 18 19 Note: The exception that is mentioned in the other source files is 20 not here. If a case arises where you need the rights that that 21 exception gives you, Please do contact me, and we'll work something 22 out. 23 24 R.E.Wolff@BitWizard.nl 25 tel: +31-152137555 26 fax: +31-152138217 27 28 This file implements a SANE backend for Tamarack flatbed scanners. */ 29 30/* 31 This driver was written initially by changing all occurrences of 32 "mustek" to "tamarack". This actually worked without modification 33 for the manufacturer detection code! :-) 34 35 */ 36 37 38#include "../include/sane/config.h" 39 40#include <errno.h> 41#include <fcntl.h> 42#include <limits.h> 43#include <signal.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <sys/types.h> 48#include <unistd.h> 49#include <sys/time.h> 50 51#include "../include/_stdint.h" 52 53#include "../include/sane/sane.h" 54#include "../include/sane/sanei.h" 55#include "../include/sane/saneopts.h" 56#include "../include/sane/sanei_scsi.h" 57#include "../include/sane/sanei_thread.h" 58#include "../include/sane/sanei_config.h" 59 60/* For timeval... */ 61#ifdef DEBUG 62#include <sys/time.h> 63#endif 64 65 66#define BACKEND_NAME tamarack 67#include "../include/sane/sanei_backend.h" 68 69#include "tamarack.h" 70 71#ifndef PATH_MAX 72# define PATH_MAX 1024 73#endif 74 75#define TAMARACK_CONFIG_FILE "tamarack.conf" 76 77 78static const SANE_Device **devlist = NULL; 79static int num_devices; 80static Tamarack_Device *first_dev; 81static Tamarack_Scanner *first_handle; 82 83static const SANE_String_Const mode_list[] = 84 { 85 SANE_VALUE_SCAN_MODE_LINEART, 86 SANE_VALUE_SCAN_MODE_HALFTONE, 87 SANE_VALUE_SCAN_MODE_GRAY, 88 SANE_VALUE_SCAN_MODE_COLOR, 89 0 90 }; 91 92 93#if 0 94static const SANE_Range u8_range = 95 { 96 0, /* minimum */ 97 255, /* maximum */ 98 0 /* quantization */ 99 }; 100#endif 101 102 103/* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that 104 * it is implemented that way. I want to hide the datatype. 105 */ 106static const SANE_Range percentage_range = 107 { 108 SANE_FIX(-100), /* minimum */ 109 SANE_FIX( 100), /* maximum */ 110 SANE_FIX( 1 ) /* quantization */ 111 }; 112 113/* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that 114 * it is implemented that way. I want to hide the datatype. 115 */ 116static const SANE_Range abs_percentage_range = 117 { 118 SANE_FIX( 0), /* minimum */ 119 SANE_FIX( 100), /* maximum */ 120 SANE_FIX( 1 ) /* quantization */ 121 }; 122 123 124#define INQ_LEN 0x60 125static const uint8_t inquiry[] = 126{ 127 TAMARACK_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00 128}; 129 130static const uint8_t test_unit_ready[] = 131{ 132 TAMARACK_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00 133}; 134 135static const uint8_t stop[] = 136{ 137 TAMARACK_SCSI_START_STOP, 0x00, 0x00, 0x00, 0x00, 0x00 138}; 139 140static const uint8_t get_status[] = 141{ 142 TAMARACK_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 143 0x00, 0x00, 0x0c, 0x00 144}; 145 146 147 148static SANE_Status 149wait_ready (int fd) 150{ 151 SANE_Status status; 152 int i; 153 154 for (i = 0; i < 1000; ++i) 155 { 156 DBG(3, "wait_ready: sending TEST_UNIT_READY\n"); 157 status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready), 158 0, 0); 159 switch (status) 160 { 161 default: 162 /* Ignore errors while waiting for scanner to become ready. 163 Some SCSI drivers return EIO while the scanner is 164 returning to the home position. */ 165 DBG(1, "wait_ready: test unit ready failed (%s)\n", 166 sane_strstatus (status)); 167 /* fall through */ 168 case SANE_STATUS_DEVICE_BUSY: 169 usleep (100000); /* retry after 100ms */ 170 break; 171 172 case SANE_STATUS_GOOD: 173 return status; 174 } 175 } 176 DBG(1, "wait_ready: timed out after %d attempts\n", i); 177 return SANE_STATUS_INVAL; 178} 179 180 181 182static SANE_Status 183sense_handler (int scsi_fd, u_char *result, void *arg) 184{ 185 (void) scsi_fd; 186 (void) arg; /* silence compilation warnings */ 187 188 switch (result[0]) 189 { 190 case 0x00: 191 break; 192 193 default: 194 DBG(1, "sense_handler: got unknown sense code %02x\n", result[0]); 195 return SANE_STATUS_IO_ERROR; 196 } 197 return SANE_STATUS_GOOD; 198} 199 200 201/* XXX This might leak the memory to a TAMARACK string */ 202 203static SANE_Status 204attach (const char *devname, Tamarack_Device **devp) 205{ 206 char result[INQ_LEN]; 207 int fd; 208 Tamarack_Device *dev; 209 SANE_Status status; 210 size_t size; 211 char *mfg, *model; 212 char *p; 213 214 for (dev = first_dev; dev; dev = dev->next) 215 if (strcmp (dev->sane.name, devname) == 0) { 216 if (devp) 217 *devp = dev; 218 return SANE_STATUS_GOOD; 219 } 220 221 DBG(3, "attach: opening %s\n", devname); 222 status = sanei_scsi_open (devname, &fd, sense_handler, 0); 223 if (status != SANE_STATUS_GOOD) { 224 DBG(1, "attach: open failed (%s)\n", sane_strstatus (status)); 225 return SANE_STATUS_INVAL; 226 } 227 228 DBG(3, "attach: sending INQUIRY\n"); 229 size = sizeof (result); 230 status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size); 231 if (status != SANE_STATUS_GOOD || size != INQ_LEN) { 232 DBG(1, "attach: inquiry failed (%s)\n", sane_strstatus (status)); 233 sanei_scsi_close (fd); 234 return status; 235 } 236 237 status = wait_ready (fd); 238 sanei_scsi_close (fd); 239 if (status != SANE_STATUS_GOOD) 240 return status; 241 242 result[33]= '\0'; 243 p = strchr(result+16,' '); 244 if (p) *p = '\0'; 245 model = strdup (result+16); 246 247 result[16]= '\0'; 248 p = strchr(result+8,' '); 249 if (p) *p = '\0'; 250 mfg = strdup (result+8); 251 252 DBG(1, "attach: Inquiry gives mfg=%s, model=%s.\n", mfg, model); 253 254 if (strcmp (mfg, "TAMARACK") != 0) { 255 DBG(1, "attach: device doesn't look like a Tamarack scanner " 256 "(result[0]=%#02x)\n", result[0]); 257 return SANE_STATUS_INVAL; 258 } 259 260 dev = malloc (sizeof (*dev)); 261 if (!dev) 262 return SANE_STATUS_NO_MEM; 263 264 memset (dev, 0, sizeof (*dev)); 265 266 dev->sane.name = strdup (devname); 267 dev->sane.vendor = "Tamarack"; 268 dev->sane.model = model; 269 dev->sane.type = "flatbed scanner"; 270 271 dev->x_range.min = 0; 272 dev->y_range.min = 0; 273 dev->x_range.quant = 0; 274 dev->y_range.quant = 0; 275 dev->dpi_range.min = SANE_FIX (1); 276 dev->dpi_range.quant = SANE_FIX (1); 277 278 dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 279 dev->y_range.max = SANE_FIX (11.0 * MM_PER_INCH); 280 dev->dpi_range.max = SANE_FIX (600); 281 282 DBG(3, "attach: found Tamarack scanner model %s (%s)\n", 283 dev->sane.model, dev->sane.type); 284 285 ++num_devices; 286 dev->next = first_dev; 287 first_dev = dev; 288 289 if (devp) 290 *devp = dev; 291 return SANE_STATUS_GOOD; 292} 293 294 295static size_t 296max_string_size (const SANE_String_Const strings[]) 297{ 298 size_t size, max_size = 0; 299 int i; 300 301 for (i = 0; strings[i]; ++i) 302 { 303 size = strlen (strings[i]) + 1; 304 if (size > max_size) 305 max_size = size; 306 } 307 return max_size; 308} 309 310 311static SANE_Status 312constrain_value (Tamarack_Scanner *s, SANE_Int option, void *value, 313 SANE_Int *info) 314{ 315 return sanei_constrain_value (s->opt + option, value, info); 316} 317 318 319static unsigned char sign_mag (double val) 320{ 321 if (val > 100) val = 100; 322 if (val < -100) val = -100; 323 if (val >= 0) return ( val); 324 else return ((unsigned char)(-val)) | 0x80; 325} 326 327 328 329static SANE_Status 330scan_area_and_windows (Tamarack_Scanner *s) 331{ 332 struct def_win_par dwp; 333 334 memset (&dwp,'\0',sizeof (dwp)); 335 dwp.dwph.opc = TAMARACK_SCSI_AREA_AND_WINDOWS; 336 set_triple (dwp.dwph.len,8 + sizeof (dwp.wdb)); 337 338 set_double (dwp.wdh.wpll, sizeof (dwp.wdb)); 339 340 dwp.wdb.winid = WINID; 341 set_double (dwp.wdb.xres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w)); 342 set_double (dwp.wdb.yres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w)); 343 344 set_quad (dwp.wdb.ulx, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_X].w))); 345 set_quad (dwp.wdb.uly, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_Y].w))); 346 set_quad (dwp.wdb.width, 347 (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w))); 348 set_quad (dwp.wdb.length, 349 (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w))); 350 351 dwp.wdb.brightness = sign_mag (SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)); 352 dwp.wdb.contrast = sign_mag (SANE_UNFIX (s->val[OPT_CONTRAST].w)); 353 dwp.wdb.thresh = 0x80; 354 355 356 switch (s->mode) { 357 case THRESHOLDED: 358 dwp.wdb.bpp = 1; 359 dwp.wdb.image_comp = 0; 360 dwp.wdb.thresh = 1 + 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); 361 break; 362 case DITHERED: 363 dwp.wdb.bpp = 1; 364 dwp.wdb.image_comp = 1; 365 break; 366 case GREYSCALE: 367 dwp.wdb.bpp = 8; 368 dwp.wdb.image_comp = 2; 369 break; 370 case TRUECOLOR: 371 dwp.wdb.bpp = 8; 372 dwp.wdb.image_comp = 2; 373 break; 374 default: 375 DBG(1, "Invalid mode. %d\n", s->mode); 376 return SANE_STATUS_INVAL; 377 } 378 DBG(1, "bright, thresh, contrast = %d(%5.1f), %d, %d(%5.1f)\n", 379 dwp.wdb.brightness, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w), 380 dwp.wdb.thresh , 381 dwp.wdb.contrast , SANE_UNFIX (s->val[OPT_CONTRAST].w)); 382 383 set_double (dwp.wdb.halftone, 1); /* XXX What does this do again ? */ 384 dwp.wdb.pad_type = 3; /* This is the only usable pad-type. */ 385 dwp.wdb.exposure = 0x6f; /* XXX Option? */ 386 dwp.wdb.compr_type = 0; 387 388 /* XXX Shouldn't this be sizeof (dwp) */ 389 return sanei_scsi_cmd (s->fd, &dwp, (10+8+38), 0, 0); 390} 391 392 393static SANE_Status 394mode_select (Tamarack_Scanner *s) 395{ 396 struct { 397 struct command_header cmd; 398 struct page_header hdr; 399 struct tamarack_page page; 400 } c; 401 402 memset (&c, '\0', sizeof (c)); 403 c.cmd.opc = TAMARACK_SCSI_MODE_SELECT; 404 c.cmd.pad0[0] = 0x10; /* Suddenly the pad bytes are no long pad... */ 405 c.cmd.pad0[1] = 0; 406 c.cmd.len = sizeof (struct page_header) + sizeof (struct tamarack_page); 407 c.hdr.code = 0; 408 c.hdr.length = 6; 409 c.page.gamma = 2; 410 c.page.thresh = 0x80; /* XXX Option? */ 411 switch (s->mode) { 412 case THRESHOLDED: 413 case DITHERED: 414 case GREYSCALE: 415 c.page.masks = 0x80; 416 break; 417 case TRUECOLOR: 418 c.page.masks = 0x40 >> s->pass; 419 break; 420 } 421 c.page.delay = 0x10; /* XXX Option? */ 422 c.page.features = (s->val[OPT_TRANS].w ? TAM_TRANS_ON:0) | 1; 423 return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0); 424} 425 426 427static SANE_Status 428start_scan (Tamarack_Scanner *s) 429{ 430 struct { 431 struct command_header cmd; 432 unsigned char winid[1]; 433 } c; 434 435 memset (&c,'\0',sizeof (c)); 436 c.cmd.opc = TAMARACK_SCSI_START_STOP; 437 c.cmd.len = sizeof (c.winid); 438 c.winid[0] = WINID; 439 return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0); 440} 441 442 443static SANE_Status 444stop_scan (Tamarack_Scanner *s) 445{ 446 /* XXX I don't think a TAMARACK can stop in mid-scan. Just stop 447 sending it requests for data.... 448 */ 449 return sanei_scsi_cmd (s->fd, stop, sizeof (stop), 0, 0); 450} 451 452 453static SANE_Status 454do_eof (Tamarack_Scanner *s) 455{ 456 if (s->pipe >= 0) 457 { 458 close (s->pipe); 459 s->pipe = -1; 460 } 461 return SANE_STATUS_EOF; 462} 463 464 465static SANE_Status 466do_cancel (Tamarack_Scanner *s) 467{ 468 s->scanning = SANE_FALSE; 469 s->pass = 0; 470 471 do_eof (s); 472 473 if (sanei_thread_is_valid (s->reader_pid)) 474 { 475 int exit_status; 476 477 /* ensure child knows it's time to stop: */ 478 sanei_thread_kill (s->reader_pid); 479 sanei_thread_waitpid (s->reader_pid, &exit_status); 480 sanei_thread_invalidate (s->reader_pid); 481 } 482 483 if (s->fd >= 0) 484 { 485 stop_scan (s); 486 sanei_scsi_close (s->fd); 487 s->fd = -1; 488 } 489 490 return SANE_STATUS_CANCELLED; 491} 492 493 494static SANE_Status 495get_image_status (Tamarack_Scanner *s) 496{ 497 uint8_t result[12]; 498 SANE_Status status; 499 size_t len; 500 int busy; 501 502#if 1 503 do 504 { 505 len = sizeof (result); 506 status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status), 507 result, &len); 508 if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY)) 509 return status; 510 511 busy = (result[2] != 8) || (status == SANE_STATUS_DEVICE_BUSY); 512 if (busy) 513 usleep (100000); 514 515 if (!s->scanning) 516 return do_cancel (s); 517 } 518 while (busy); 519#else 520 /* XXX Test if this works one day... */ 521 wait_ready (s); 522#endif 523 524 len = sizeof (result); 525 status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status), 526 result, &len); 527 if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY)) 528 return status; 529 530 s->params.bytes_per_line = 531 result[ 8] | (result[ 7] << 8) | (result[6] << 16); 532 s->params.lines = 533 result[11] | (result[10] << 8) | (result[9] << 16); 534 535 switch (s->mode) { 536 case DITHERED: 537 case THRESHOLDED: 538 s->params.pixels_per_line = 8 * s->params.bytes_per_line; 539 break; 540 case GREYSCALE: 541 case TRUECOLOR: 542 s->params.pixels_per_line = s->params.bytes_per_line; 543 break; 544 } 545 546 547 DBG(1, "get_image_status: bytes_per_line=%d, lines=%d\n", 548 s->params.bytes_per_line, s->params.lines); 549 return SANE_STATUS_GOOD; 550} 551 552 553static SANE_Status 554read_data (Tamarack_Scanner *s, SANE_Byte *buf, int lines, int bpl) 555{ 556 struct command_header_10 cmd; 557 size_t nbytes; 558 SANE_Status status; 559#ifdef DEBUG 560 int dt; 561 struct timeval tv_start,tv_end; 562#endif 563 564 nbytes = bpl * lines; 565 memset (&cmd,'\0',sizeof (cmd)); 566 cmd.opc = 0x28; 567 set_triple (cmd.len,nbytes); 568 569#ifdef DEBUG 570 if (verbose) DBG (1, "Doing read_data... \n"); 571 gettimeofday (&tv_start,NULL); 572#endif 573 574 status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, &nbytes); 575 576#ifdef DEBUG 577 gettimeofday (&tv_end,NULL); 578 dt = tv_end.tv_usec - tv_start.tv_usec + 579 (tv_end.tv_sec - tv_start.tv_sec) * 1000000; 580 if (verbose) DBG(1, "Read took %d.%06d seconds.", 581 dt/1000000,dt%1000000); 582 dt = 1000000 * nbytes / dt; 583 if (verbose) DBG(1, "which is %d.%03d bytes per second.\n",dt,0); 584#endif 585 return status; 586} 587 588 589 590static SANE_Status 591init_options (Tamarack_Scanner *s) 592{ 593 int i; 594 595 memset (s->opt, 0, sizeof (s->opt)); 596 memset (s->val, 0, sizeof (s->val)); 597 598 for (i = 0; i < NUM_OPTIONS; ++i) { 599 s->opt[i].size = sizeof (SANE_Word); 600 s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 601 } 602 603 s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 604 s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 605 s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 606 s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 607 s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 608 609 /* "Mode" group: */ 610 s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 611 s->opt[OPT_MODE_GROUP].desc = ""; 612 s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 613 s->opt[OPT_MODE_GROUP].cap = 0; 614 s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 615 616 /* scan mode */ 617 s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 618 s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 619 s->opt[OPT_MODE].desc = "Select the scan mode"; 620 s->opt[OPT_MODE].type = SANE_TYPE_STRING; 621 s->opt[OPT_MODE].size = max_string_size (mode_list); 622 s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 623 s->opt[OPT_MODE].constraint.string_list = mode_list; 624 s->val[OPT_MODE].s = strdup (mode_list[OPT_MODE_DEFAULT]); 625 626 /* resolution */ 627 s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 628 s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 629 s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 630 s->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED; 631 s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 632 s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 633 s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range; 634 s->val[OPT_RESOLUTION].w = SANE_FIX (OPT_RESOLUTION_DEFAULT); 635 636 /* preview */ 637 s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; 638 s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; 639 s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; 640 s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; 641 s->val[OPT_PREVIEW].w = 0; 642 643 /* gray preview */ 644 s->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW; 645 s->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW; 646 s->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW; 647 s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL; 648 s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE; 649 650 /* "Geometry" group: */ 651 s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 652 s->opt[OPT_GEOMETRY_GROUP].desc = ""; 653 s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 654 s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 655 s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 656 657 /* top-left x */ 658 s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 659 s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 660 s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 661 s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 662 s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 663 s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 664 s->opt[OPT_TL_X].constraint.range = &s->hw->x_range; 665 s->val[OPT_TL_X].w = 0; 666 667 /* top-left y */ 668 s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 669 s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 670 s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 671 s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 672 s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 673 s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 674 s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range; 675 s->val[OPT_TL_Y].w = 0; 676 677 /* bottom-right x */ 678 s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 679 s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 680 s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 681 s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 682 s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 683 s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 684 s->opt[OPT_BR_X].constraint.range = &s->hw->x_range; 685 s->val[OPT_BR_X].w = s->hw->x_range.max; 686 687 /* bottom-right y */ 688 s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 689 s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 690 s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 691 s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 692 s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 693 s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 694 s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range; 695 s->val[OPT_BR_Y].w = s->hw->y_range.max; 696 697 /* "Enhancement" group: */ 698 s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 699 s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 700 s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 701 s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 702 s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 703 704 /* transparency adapter. */ 705 s->opt[OPT_TRANS].name = "transparency"; 706 s->opt[OPT_TRANS].title = "transparency"; 707 s->opt[OPT_TRANS].desc = "Turn on the transparency adapter."; 708 s->opt[OPT_TRANS].type = SANE_TYPE_BOOL; 709 s->opt[OPT_TRANS].unit = SANE_UNIT_NONE; 710 s->val[OPT_TRANS].w = SANE_FALSE; 711 712 /* brightness */ 713 s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 714 s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 715 s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS 716 " This option is active for lineart/halftone modes only. " 717 "For multibit modes (grey/color) use the gamma-table(s)."; 718 s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED; 719 s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT; 720 s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 721 s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range; 722 s->val[OPT_BRIGHTNESS].w = SANE_FIX(0); 723 724 /* contrast */ 725 s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 726 s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 727 s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST 728 " This option is active for lineart/halftone modes only. " 729 "For multibit modes (grey/color) use the gamma-table(s)."; 730 s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED; 731 s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT; 732 s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 733 s->opt[OPT_CONTRAST].constraint.range = &percentage_range; 734 s->val[OPT_CONTRAST].w = SANE_FIX(0); 735 736 /* Threshold */ 737 s->opt[OPT_THRESHOLD].name = "Threshold"; 738 s->opt[OPT_THRESHOLD].title = "Threshold"; 739 s->opt[OPT_THRESHOLD].desc = "Threshold: below this level is black, above is white" 740 " This option is active for bitmap modes only. "; 741 s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; 742 s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; 743 s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; 744 s->opt[OPT_THRESHOLD].constraint.range = &abs_percentage_range; 745 s->val[OPT_THRESHOLD].w = SANE_FIX(50); 746 s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; 747 748#if 0 749 /* custom-gamma table */ 750 s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; 751 s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; 752 s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; 753 s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; 754 s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; 755 s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE; 756 757 /* grayscale gamma vector */ 758 s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; 759 s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; 760 s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; 761 s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT; 762 s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 763 s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE; 764 s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word); 765 s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE; 766 s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range; 767 s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0]; 768 769 /* red gamma vector */ 770 s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; 771 s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; 772 s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; 773 s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT; 774 s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 775 s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE; 776 s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word); 777 s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE; 778 s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range; 779 s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0]; 780 781 /* green gamma vector */ 782 s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; 783 s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; 784 s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; 785 s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT; 786 s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 787 s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE; 788 s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word); 789 s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE; 790 s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range; 791 s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0]; 792 793 /* blue gamma vector */ 794 s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; 795 s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; 796 s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; 797 s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT; 798 s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 799 s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE; 800 s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word); 801 s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE; 802 s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range; 803 s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0]; 804#endif 805 return SANE_STATUS_GOOD; 806} 807 808 809/* This function is executed as a child process. The reason this is 810 executed as a subprocess is because some (most?) generic SCSI 811 interfaces block a SCSI request until it has completed. With a 812 subprocess, we can let it block waiting for the request to finish 813 while the main process can go about to do more important things 814 (such as recognizing when the user presses a cancel button). 815 816 WARNING: Since this is executed as a subprocess, it's NOT possible 817 to update any of the variables in the main process (in particular 818 the scanner state cannot be updated). */ 819static int 820reader_process (void *scanner) 821{ 822 Tamarack_Scanner *s = (Tamarack_Scanner *) scanner; 823 int fd = s->reader_pipe; 824 825 SANE_Byte *data; 826 int lines_per_buffer, bpl; 827 SANE_Status status; 828 sigset_t sigterm_set; 829 sigset_t ignore_set; 830 struct SIGACTION act; 831 FILE *fp; 832 833 if (sanei_thread_is_forked()) close (s->pipe); 834 835 sigfillset (&ignore_set); 836 sigdelset (&ignore_set, SIGTERM); 837#if defined (__APPLE__) && defined (__MACH__) 838 sigdelset (&ignore_set, SIGUSR2); 839#endif 840 sigprocmask (SIG_SETMASK, &ignore_set, 0); 841 842 memset (&act, 0, sizeof (act)); 843 sigaction (SIGTERM, &act, 0); 844 845 sigemptyset (&sigterm_set); 846 sigaddset (&sigterm_set, SIGTERM); 847 848 fp = fdopen (fd, "w"); 849 if (!fp) 850 return 1; 851 852 bpl = s->params.bytes_per_line; 853 854 lines_per_buffer = sanei_scsi_max_request_size / bpl; 855 if (!lines_per_buffer) 856 return 2; /* resolution is too high */ 857 858 /* Limit the size of a single transfer to one inch. 859 XXX Add a stripsize option. */ 860 if (lines_per_buffer > SANE_UNFIX (s->val[OPT_RESOLUTION].w)) 861 lines_per_buffer = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 862 863 DBG(3, "lines_per_buffer=%d, bytes_per_line=%d\n", lines_per_buffer, bpl); 864 865 data = malloc (lines_per_buffer * bpl); 866 867 for (s->line = 0; s->line < s->params.lines; s->line += lines_per_buffer) { 868 if (s->line + lines_per_buffer > s->params.lines) 869 /* do the last few lines: */ 870 lines_per_buffer = s->params.lines - s->line; 871 872 sigprocmask (SIG_BLOCK, &sigterm_set, 0); 873 status = read_data (s, data, lines_per_buffer, bpl); 874 sigprocmask (SIG_UNBLOCK, &sigterm_set, 0); 875 if (status != SANE_STATUS_GOOD) { 876 DBG(1, "reader_process: read_data failed with status=%d\n", status); 877 return 3; 878 } 879 DBG(3, "reader_process: read %d lines\n", lines_per_buffer); 880 881 if ((s->mode == TRUECOLOR) || (s->mode == GREYSCALE)) { 882 fwrite (data, lines_per_buffer, bpl, fp); 883 } else { 884 /* in singlebit mode, the scanner returns 1 for black. ;-( --DM */ 885 /* Hah! Same for Tamarack... -- REW */ 886 int i; 887 888 for (i = 0; i < lines_per_buffer * bpl; ++i) 889 fputc (~data[i], fp); 890 } 891 } 892 fclose (fp); 893 return 0; 894} 895 896 897static SANE_Status 898attach_one (const char *dev) 899{ 900 attach (dev, 0); 901 return SANE_STATUS_GOOD; 902} 903 904 905SANE_Status 906sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) 907{ 908 char dev_name[PATH_MAX]; 909 size_t len; 910 FILE *fp; 911 912 (void) authorize; /* silence compilation warnings */ 913 914 DBG_INIT(); 915 916 sanei_thread_init(); 917 918 if (version_code) 919 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 920 921 fp = sanei_config_open (TAMARACK_CONFIG_FILE); 922 if (!fp) { 923 /* default to /dev/scanner instead of insisting on config file */ 924 attach ("/dev/scanner", 0); 925 return SANE_STATUS_GOOD; 926 } 927 928 while (sanei_config_read (dev_name, sizeof (dev_name), fp)) { 929 if (dev_name[0] == '#') /* ignore line comments */ 930 continue; 931 len = strlen (dev_name); 932 933 if (!len) 934 continue; /* ignore empty lines */ 935 936 sanei_config_attach_matching_devices (dev_name, attach_one); 937 } 938 fclose (fp); 939 return SANE_STATUS_GOOD; 940} 941 942 943void 944sane_exit (void) 945{ 946 Tamarack_Device *dev, *next; 947 948 for (dev = first_dev; dev; dev = next) { 949 next = dev->next; 950 free ((void *) dev->sane.name); 951 free ((void *) dev->sane.model); 952 free (dev); 953 } 954 955 if (devlist) 956 free (devlist); 957} 958 959SANE_Status 960sane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only) 961{ 962 Tamarack_Device *dev; 963 int i; 964 965 (void) local_only; /* silence compilation warnings */ 966 967 if (devlist) 968 free (devlist); 969 970 devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 971 if (!devlist) 972 return SANE_STATUS_NO_MEM; 973 974 i = 0; 975 for (dev = first_dev; i < num_devices; dev = dev->next) 976 devlist[i++] = &dev->sane; 977 devlist[i++] = 0; 978 979 *device_list = devlist; 980 return SANE_STATUS_GOOD; 981} 982 983 984SANE_Status 985sane_open (SANE_String_Const devicename, SANE_Handle *handle) 986{ 987 Tamarack_Device *dev; 988 SANE_Status status; 989 Tamarack_Scanner *s; 990 int i, j; 991 992 if (devicename[0]) { 993 for (dev = first_dev; dev; dev = dev->next) 994 if (strcmp (dev->sane.name, devicename) == 0) 995 break; 996 997 if (!dev) { 998 status = attach (devicename, &dev); 999 if (status != SANE_STATUS_GOOD) 1000 return status; 1001 } 1002 } else { 1003 /* empty devicname -> use first device */ 1004 dev = first_dev; 1005 } 1006 1007 if (!dev) 1008 return SANE_STATUS_INVAL; 1009 1010 s = malloc (sizeof (*s)); 1011 if (!s) 1012 return SANE_STATUS_NO_MEM; 1013 memset (s, 0, sizeof (*s)); 1014 s->fd = -1; 1015 s->pipe = -1; 1016 s->hw = dev; 1017 for (i = 0; i < 4; ++i) 1018 for (j = 0; j < 256; ++j) 1019 s->gamma_table[i][j] = j; 1020 1021 init_options (s); 1022 1023 /* insert newly opened handle into list of open handles: */ 1024 s->next = first_handle; 1025 first_handle = s; 1026 1027 *handle = s; 1028 return SANE_STATUS_GOOD; 1029} 1030 1031 1032void 1033sane_close (SANE_Handle handle) 1034{ 1035 Tamarack_Scanner *prev, *s; 1036 1037 /* remove handle from list of open handles: */ 1038 prev = 0; 1039 for (s = first_handle; s; s = s->next) { 1040 if (s == handle) 1041 break; 1042 prev = s; 1043 } 1044 1045 if (!s) { 1046 DBG(1, "close: invalid handle %p\n", handle); 1047 return; /* oops, not a handle we know about */ 1048 } 1049 1050 if (s->scanning) 1051 do_cancel (handle); 1052 1053 if (prev) 1054 prev->next = s->next; 1055 else 1056 first_handle = s->next; 1057 1058 free (handle); 1059} 1060 1061 1062const SANE_Option_Descriptor * 1063sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1064{ 1065 Tamarack_Scanner *s = handle; 1066 1067 if ((unsigned) option >= NUM_OPTIONS) 1068 return 0; 1069 return s->opt + option; 1070} 1071 1072 1073 1074static int make_mode (char *mode) 1075{ 1076 if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) 1077 return THRESHOLDED; 1078 if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) 1079 return DITHERED; 1080 else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) 1081 return GREYSCALE; 1082 else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) 1083 return TRUECOLOR; 1084 1085 return -1; 1086} 1087 1088 1089SANE_Status 1090sane_control_option (SANE_Handle handle, SANE_Int option, 1091 SANE_Action action, void *val, SANE_Int *info) 1092{ 1093 Tamarack_Scanner *s = handle; 1094 SANE_Status status; 1095 SANE_Word cap; 1096 1097 if (info) 1098 *info = 0; 1099 1100 if (s->scanning) 1101 return SANE_STATUS_DEVICE_BUSY; 1102 1103 if (option >= NUM_OPTIONS) 1104 return SANE_STATUS_INVAL; 1105 1106 cap = s->opt[option].cap; 1107 1108 if (!SANE_OPTION_IS_ACTIVE (cap)) 1109 return SANE_STATUS_INVAL; 1110 1111 if (action == SANE_ACTION_GET_VALUE) { 1112 switch (option) { 1113 /* word options: */ 1114 case OPT_PREVIEW: 1115 case OPT_GRAY_PREVIEW: 1116 case OPT_RESOLUTION: 1117 case OPT_TL_X: 1118 case OPT_TL_Y: 1119 case OPT_BR_X: 1120 case OPT_BR_Y: 1121 case OPT_NUM_OPTS: 1122 case OPT_TRANS: 1123 case OPT_BRIGHTNESS: 1124 case OPT_CONTRAST: 1125 case OPT_THRESHOLD: 1126#if 0 1127 case OPT_CUSTOM_GAMMA: 1128#endif 1129 *(SANE_Word *) val = s->val[option].w; 1130 return SANE_STATUS_GOOD; 1131 1132#if 0 1133 /* word-array options: */ 1134 case OPT_GAMMA_VECTOR: 1135 case OPT_GAMMA_VECTOR_R: 1136 case OPT_GAMMA_VECTOR_G: 1137 case OPT_GAMMA_VECTOR_B: 1138 memcpy (val, s->val[option].wa, s->opt[option].size); 1139 return SANE_STATUS_GOOD; 1140#endif 1141 1142 /* string options: */ 1143 case OPT_MODE: 1144 strcpy (val, s->val[option].s); 1145 return SANE_STATUS_GOOD; 1146 } 1147 } else if (action == SANE_ACTION_SET_VALUE) { 1148 if (!SANE_OPTION_IS_SETTABLE (cap)) 1149 return SANE_STATUS_INVAL; 1150 1151 status = constrain_value (s, option, val, info); 1152 if (status != SANE_STATUS_GOOD) 1153 return status; 1154 1155 switch (option) 1156 { 1157 /* (mostly) side-effect-free word options: */ 1158 case OPT_RESOLUTION: 1159 case OPT_TL_X: 1160 case OPT_TL_Y: 1161 case OPT_BR_X: 1162 case OPT_BR_Y: 1163 if (info) 1164 *info |= SANE_INFO_RELOAD_PARAMS; 1165 /* fall through */ 1166 case OPT_PREVIEW: 1167 case OPT_GRAY_PREVIEW: 1168 case OPT_BRIGHTNESS: 1169 case OPT_CONTRAST: 1170 case OPT_THRESHOLD: 1171 case OPT_TRANS: 1172 s->val[option].w = *(SANE_Word *) val; 1173 return SANE_STATUS_GOOD; 1174 1175#if 0 1176 /* side-effect-free word-array options: */ 1177 case OPT_GAMMA_VECTOR: 1178 case OPT_GAMMA_VECTOR_R: 1179 case OPT_GAMMA_VECTOR_G: 1180 case OPT_GAMMA_VECTOR_B: 1181 memcpy (s->val[option].wa, val, s->opt[option].size); 1182 return SANE_STATUS_GOOD; 1183 1184 /* options with side-effects: */ 1185 1186 case OPT_CUSTOM_GAMMA: 1187 w = *(SANE_Word *) val; 1188 if (w == s->val[OPT_CUSTOM_GAMMA].w) 1189 return SANE_STATUS_GOOD; /* no change */ 1190 1191 s->val[OPT_CUSTOM_GAMMA].w = w; 1192 if (w) { 1193 s->mode = make_mode (s->val[OPT_MODE].s); 1194 1195 if (s->mode == GREYSCALE) { 1196 s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 1197 } else if (s->mode == TRUECOLOR) { 1198 s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 1199 s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; 1200 s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; 1201 s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; 1202 } 1203 } else { 1204 s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 1205 s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 1206 s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 1207 s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 1208 } 1209 if (info) 1210 *info |= SANE_INFO_RELOAD_OPTIONS; 1211 return SANE_STATUS_GOOD; 1212#endif 1213 1214 case OPT_MODE: 1215 { 1216 1217 if (s->val[option].s) 1218 free (s->val[option].s); 1219 s->val[option].s = strdup (val); 1220 1221 s->mode = make_mode (s->val[OPT_MODE].s); 1222 1223 if (info) 1224 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; 1225 1226 s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE; 1227 s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; 1228 s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; 1229#if 0 1230 s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; 1231 s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 1232 s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 1233 s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 1234 s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 1235#endif 1236 1237 1238 if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0) 1239 s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; 1240 else { 1241 s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; 1242 s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; 1243 } 1244#if 0 1245 if (!binary) 1246 s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; 1247 1248 if (s->val[OPT_CUSTOM_GAMMA].w) { 1249 if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0) 1250 s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 1251 else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0) { 1252 s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 1253 s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; 1254 s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; 1255 s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; 1256 } 1257 } 1258#endif 1259 return SANE_STATUS_GOOD; 1260 } 1261 } 1262 } 1263 return SANE_STATUS_INVAL; 1264} 1265 1266 1267SANE_Status 1268sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) 1269{ 1270 Tamarack_Scanner *s = handle; 1271 1272 if (!s->scanning) { 1273 double width, height, dpi; 1274 1275 1276 memset (&s->params, 0, sizeof (s->params)); 1277 1278 width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w); 1279 height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w); 1280 dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 1281 s->mode = make_mode (s->val[OPT_MODE].s); 1282 DBG(1, "got mode '%s' -> %d.\n", s->val[OPT_MODE].s, s->mode); 1283 /* make best-effort guess at what parameters will look like once 1284 scanning starts. */ 1285 if (dpi > 0.0 && width > 0.0 && height > 0.0) { 1286 double dots_per_mm = dpi / MM_PER_INCH; 1287 1288 s->params.pixels_per_line = width * dots_per_mm; 1289 s->params.lines = height * dots_per_mm; 1290 } 1291 if ((s->mode == THRESHOLDED) || (s->mode == DITHERED)) { 1292 s->params.format = SANE_FRAME_GRAY; 1293 s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8; 1294 s->params.depth = 1; 1295 } else if (s->mode == GREYSCALE) { 1296 s->params.format = SANE_FRAME_GRAY; 1297 s->params.bytes_per_line = s->params.pixels_per_line; 1298 s->params.depth = 8; 1299 } else { 1300 s->params.format = SANE_FRAME_RED + s->pass; 1301 s->params.bytes_per_line = s->params.pixels_per_line; 1302 s->params.depth = 8; 1303 } 1304 s->pass = 0; 1305 } else { 1306 if (s->mode == TRUECOLOR) 1307 s->params.format = SANE_FRAME_RED + s->pass; 1308 } 1309 1310 s->params.last_frame = (s->mode != TRUECOLOR) || (s->pass == 2); 1311 1312 if (params) 1313 *params = s->params; 1314 1315 DBG(1, "Got parameters: format:%d, ppl: %d, bpl:%d, depth:%d, " 1316 "last %d pass %d\n", 1317 s->params.format, s->params.pixels_per_line, 1318 s->params.bytes_per_line, s->params.depth, 1319 s->params.last_frame, s->pass); 1320 return SANE_STATUS_GOOD; 1321} 1322 1323 1324SANE_Status 1325sane_start (SANE_Handle handle) 1326{ 1327 Tamarack_Scanner *s = handle; 1328 SANE_Status status; 1329 int fds[2]; 1330 1331 /* First make sure we have a current parameter set. Some of the 1332 parameters will be overwritten below, but that's OK. */ 1333 status = sane_get_parameters (s, 0); 1334 1335 if (status != SANE_STATUS_GOOD) 1336 return status; 1337 1338 if (s->fd < 0) { 1339 /* translate options into s->mode for convenient access: */ 1340 s->mode = make_mode (s->val[OPT_MODE].s); 1341 1342 if (s->mode == TRUECOLOR) 1343 { 1344 if (s->val[OPT_PREVIEW].w && s->val[OPT_GRAY_PREVIEW].w) { 1345 /* Force gray-scale mode when previewing. */ 1346 s->mode = GREYSCALE; 1347 s->params.format = SANE_FRAME_GRAY; 1348 s->params.bytes_per_line = s->params.pixels_per_line; 1349 s->params.last_frame = SANE_TRUE; 1350 } 1351 } 1352 1353 status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0); 1354 if (status != SANE_STATUS_GOOD) { 1355 DBG(1, "open: open of %s failed: %s\n", 1356 s->hw->sane.name, sane_strstatus (status)); 1357 return status; 1358 } 1359 } 1360 1361 status = wait_ready (s->fd); 1362 if (status != SANE_STATUS_GOOD) { 1363 DBG(1, "open: wait_ready() failed: %s\n", sane_strstatus (status)); 1364 goto stop_scanner_and_return; 1365 } 1366 1367 status = scan_area_and_windows (s); 1368 if (status != SANE_STATUS_GOOD) { 1369 DBG(1, "open: set scan area command failed: %s\n", 1370 sane_strstatus (status)); 1371 goto stop_scanner_and_return; 1372 } 1373 1374 status = mode_select (s); 1375 if (status != SANE_STATUS_GOOD) 1376 goto stop_scanner_and_return; 1377 1378 s->scanning = SANE_TRUE; 1379 1380 status = start_scan (s); 1381 if (status != SANE_STATUS_GOOD) 1382 goto stop_scanner_and_return; 1383 1384 status = get_image_status (s); 1385 if (status != SANE_STATUS_GOOD) 1386 goto stop_scanner_and_return; 1387 1388 s->line = 0; 1389 1390 if (pipe (fds) < 0) 1391 return SANE_STATUS_IO_ERROR; 1392 1393 s->pipe = fds[0]; 1394 s->reader_pipe = fds[1]; 1395 s->reader_pid = sanei_thread_begin (reader_process, (void *) s); 1396 1397 if (sanei_thread_is_forked()) close (s->reader_pipe); 1398 1399 return SANE_STATUS_GOOD; 1400 1401stop_scanner_and_return: 1402 do_cancel (s); 1403 return status; 1404} 1405 1406 1407SANE_Status 1408sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) 1409{ 1410 Tamarack_Scanner *s = handle; 1411 ssize_t nread; 1412 1413 *len = 0; 1414 1415 nread = read (s->pipe, buf, max_len); 1416 DBG(3, "read %ld bytes\n", (long) nread); 1417 1418 if (!s->scanning) 1419 return do_cancel (s); 1420 1421 if (nread < 0) { 1422 if (errno == EAGAIN) { 1423 return SANE_STATUS_GOOD; 1424 } else { 1425 do_cancel (s); 1426 return SANE_STATUS_IO_ERROR; 1427 } 1428 } 1429 1430 *len = nread; 1431 1432 if (nread == 0) { 1433 s->pass++; 1434 return do_eof (s); 1435 } 1436 return SANE_STATUS_GOOD; 1437} 1438 1439 1440void 1441sane_cancel (SANE_Handle handle) 1442{ 1443 Tamarack_Scanner *s = handle; 1444 1445 if (sanei_thread_is_valid (s->reader_pid)) 1446 sanei_thread_kill (s->reader_pid); 1447 s->scanning = SANE_FALSE; 1448} 1449 1450 1451SANE_Status 1452sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 1453{ 1454 Tamarack_Scanner *s = handle; 1455 1456 if (!s->scanning) 1457 return SANE_STATUS_INVAL; 1458 1459 if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) 1460 return SANE_STATUS_IO_ERROR; 1461 1462 return SANE_STATUS_GOOD; 1463} 1464 1465 1466SANE_Status 1467sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) 1468{ 1469 Tamarack_Scanner *s = handle; 1470 1471 if (!s->scanning) 1472 return SANE_STATUS_INVAL; 1473 1474 *fd = s->pipe; 1475 return SANE_STATUS_GOOD; 1476} 1477