1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci This file (C) 1997 Ingo Schneider 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci SANE is free software; you can redistribute it and/or modify it under 8141cc406Sopenharmony_ci the terms of the GNU General Public License as published by the Free 9141cc406Sopenharmony_ci Software Foundation; either version 2 of the License, or (at your 10141cc406Sopenharmony_ci option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci SANE is distributed in the hope that it will be useful, but WITHOUT 13141cc406Sopenharmony_ci ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14141cc406Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15141cc406Sopenharmony_ci for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with sane; see the file COPYING. 19141cc406Sopenharmony_ci If not, see <https://www.gnu.org/licenses/>. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci This file implements a SANE backend for Siemens 9036 flatbed scanners. */ 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "../include/sane/config.h" 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci#include <stdlib.h> 26141cc406Sopenharmony_ci#include <unistd.h> 27141cc406Sopenharmony_ci#include <string.h> 28141cc406Sopenharmony_ci#include <sys/types.h> 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci#ifndef PATH_MAX 31141cc406Sopenharmony_ci# define PATH_MAX 1024 32141cc406Sopenharmony_ci#endif 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_ci#include "../include/sane/sane.h" 35141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 36141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 37141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 38141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 39141cc406Sopenharmony_ci#include "s9036.h" 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci#define BACKEND_NAME s9036 42141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci#undef Byte 46141cc406Sopenharmony_ci#define Byte SANE_Byte 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL; 49141cc406Sopenharmony_cistatic int num_devices; 50141cc406Sopenharmony_cistatic S9036_Device *s9036_devices; 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci/* sets loc_s bytes long value at offset loc in scsi command to value size */ 54141cc406Sopenharmony_cistatic void 55141cc406Sopenharmony_ciset_size (Byte * loc, int loc_s, size_t size) 56141cc406Sopenharmony_ci{ 57141cc406Sopenharmony_ci int i; 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci for (i = 0; i < loc_s; i++) 60141cc406Sopenharmony_ci { 61141cc406Sopenharmony_ci loc[loc_s - i - 1] = (size >> (i * 8)) & 0xff; 62141cc406Sopenharmony_ci } 63141cc406Sopenharmony_ci} 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_cistatic long 66141cc406Sopenharmony_cireserve_unit (int fd) 67141cc406Sopenharmony_ci{ 68141cc406Sopenharmony_ci const Byte scsi_reserve[] = 69141cc406Sopenharmony_ci { 70141cc406Sopenharmony_ci 0x16, 0x00, 0x00, 0x00, 0x00, 0x00 71141cc406Sopenharmony_ci }; 72141cc406Sopenharmony_ci DBG (3, "reserve_unit()\n"); 73141cc406Sopenharmony_ci return sanei_scsi_cmd (fd, scsi_reserve, sizeof (scsi_reserve), 0, 0); 74141cc406Sopenharmony_ci} 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_cistatic long 77141cc406Sopenharmony_cirelease_unit (int fd) 78141cc406Sopenharmony_ci{ 79141cc406Sopenharmony_ci const Byte scsi_release[] = 80141cc406Sopenharmony_ci { 81141cc406Sopenharmony_ci 0x17, 0x00, 0x00, 0x00, 0x00, 0x00 82141cc406Sopenharmony_ci }; 83141cc406Sopenharmony_ci DBG (3, "release_unit()\n"); 84141cc406Sopenharmony_ci return sanei_scsi_cmd (fd, scsi_release, sizeof (scsi_release), 0, 0); 85141cc406Sopenharmony_ci} 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_cistatic SANE_Status 88141cc406Sopenharmony_citest_ready (int fd) 89141cc406Sopenharmony_ci{ 90141cc406Sopenharmony_ci static const Byte scsi_test_ready[] = 91141cc406Sopenharmony_ci { 92141cc406Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 93141cc406Sopenharmony_ci }; 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_ci SANE_Status status; 96141cc406Sopenharmony_ci int try; 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci for (try = 0; try < 1000; ++try) 99141cc406Sopenharmony_ci { 100141cc406Sopenharmony_ci DBG (3, "test_ready: sending TEST_UNIT_READY\n"); 101141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, scsi_test_ready, sizeof (scsi_test_ready), 102141cc406Sopenharmony_ci 0, 0); 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci switch (status) 105141cc406Sopenharmony_ci { 106141cc406Sopenharmony_ci case SANE_STATUS_DEVICE_BUSY: 107141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 108141cc406Sopenharmony_ci break; 109141cc406Sopenharmony_ci 110141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 111141cc406Sopenharmony_ci return status; 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_ci default: 114141cc406Sopenharmony_ci DBG (1, "test_ready: test unit ready failed (%s)\n", 115141cc406Sopenharmony_ci sane_strstatus (status)); 116141cc406Sopenharmony_ci return status; 117141cc406Sopenharmony_ci } 118141cc406Sopenharmony_ci } 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci DBG (1, "test_ready: timed out after %d attempts\n", try); 121141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 122141cc406Sopenharmony_ci} 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_cistatic SANE_Status 125141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char *result, void *arg) 126141cc406Sopenharmony_ci{ 127141cc406Sopenharmony_ci (void) scsi_fd; 128141cc406Sopenharmony_ci (void) arg; /* silence compilation warnings */ 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci if (result[0]) 131141cc406Sopenharmony_ci { 132141cc406Sopenharmony_ci DBG (0, "sense_handler() : sense code = %02x\n", result[0]); 133141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 134141cc406Sopenharmony_ci } 135141cc406Sopenharmony_ci else 136141cc406Sopenharmony_ci { 137141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 138141cc406Sopenharmony_ci } 139141cc406Sopenharmony_ci} 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_cistatic SANE_Status 142141cc406Sopenharmony_cistop_scan (int fd) 143141cc406Sopenharmony_ci{ 144141cc406Sopenharmony_ci (void) fd; /* silence compilation warnings */ 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci /* XXX don't know how to stop the scanner. To be tested ! */ 147141cc406Sopenharmony_ci#if 0 148141cc406Sopenharmony_ci const Byte scsi_rewind[] = 149141cc406Sopenharmony_ci { 150141cc406Sopenharmony_ci 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 151141cc406Sopenharmony_ci }; 152141cc406Sopenharmony_ci DBG (1, "Trying to stop scanner...\n"); 153141cc406Sopenharmony_ci return sanei_scsi_cmd (fd, scsi_rewind, sizeof (scsi_rewind), 0, 0); 154141cc406Sopenharmony_ci#else 155141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 156141cc406Sopenharmony_ci#endif 157141cc406Sopenharmony_ci} 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cistatic SANE_Status 161141cc406Sopenharmony_cistart_scan (int fd, SANE_Bool cont) 162141cc406Sopenharmony_ci{ 163141cc406Sopenharmony_ci struct 164141cc406Sopenharmony_ci { 165141cc406Sopenharmony_ci /* Command */ 166141cc406Sopenharmony_ci Byte cmd; 167141cc406Sopenharmony_ci Byte lun; 168141cc406Sopenharmony_ci Byte res[2]; 169141cc406Sopenharmony_ci Byte tr_len; 170141cc406Sopenharmony_ci Byte ctrl; 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci /* Data */ 173141cc406Sopenharmony_ci Byte wid; 174141cc406Sopenharmony_ci } 175141cc406Sopenharmony_ci scsi_start_scan; 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci memset (&scsi_start_scan, 0, sizeof (scsi_start_scan)); 178141cc406Sopenharmony_ci scsi_start_scan.cmd = 0x1b; 179141cc406Sopenharmony_ci scsi_start_scan.tr_len = 1; 180141cc406Sopenharmony_ci scsi_start_scan.wid = 0; 181141cc406Sopenharmony_ci scsi_start_scan.ctrl = (cont == SANE_TRUE) ? 0x80 : 0x00; 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci DBG (1, "Starting scanner ...\n"); 184141cc406Sopenharmony_ci return sanei_scsi_cmd (fd, &scsi_start_scan, sizeof (scsi_start_scan), 0, 0); 185141cc406Sopenharmony_ci} 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_cistatic void 188141cc406Sopenharmony_ciwait_ready (int fd) 189141cc406Sopenharmony_ci{ 190141cc406Sopenharmony_ci# define WAIT_READY_READ_SIZE 4 191141cc406Sopenharmony_ci const Byte scsi_read[] = 192141cc406Sopenharmony_ci { 193141cc406Sopenharmony_ci 0x28, 0x00, /* opcode, lun */ 194141cc406Sopenharmony_ci 0x80, /* data type 80 == read time left */ 195141cc406Sopenharmony_ci 0x00, 0x00, 0x00, /* reserved */ 196141cc406Sopenharmony_ci 0x00, 0x00, WAIT_READY_READ_SIZE, /* transfer length */ 197141cc406Sopenharmony_ci 0x00, /* control byte */ 198141cc406Sopenharmony_ci }; 199141cc406Sopenharmony_ci 200141cc406Sopenharmony_ci Byte result[WAIT_READY_READ_SIZE]; 201141cc406Sopenharmony_ci size_t size = WAIT_READY_READ_SIZE; 202141cc406Sopenharmony_ci SANE_Status status; 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_ci while (1) 205141cc406Sopenharmony_ci { 206141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, scsi_read, sizeof (scsi_read), 207141cc406Sopenharmony_ci result, &size); 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD || size != WAIT_READY_READ_SIZE) 210141cc406Sopenharmony_ci { 211141cc406Sopenharmony_ci /* 212141cc406Sopenharmony_ci Command failed, the assembler code of the windows scan library 213141cc406Sopenharmony_ci ignores this condition, and so do I 214141cc406Sopenharmony_ci */ 215141cc406Sopenharmony_ci break; 216141cc406Sopenharmony_ci } 217141cc406Sopenharmony_ci else 218141cc406Sopenharmony_ci { 219141cc406Sopenharmony_ci /* left is the amount of seconds left till the scanner is 220141cc406Sopenharmony_ci ready * 100 */ 221141cc406Sopenharmony_ci int left = result[2] * 256 + result[3]; 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci DBG (1, "wait_ready() : %d left...\n", left); 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci if (!left) 226141cc406Sopenharmony_ci break; 227141cc406Sopenharmony_ci /* We delay only for half the given time */ 228141cc406Sopenharmony_ci else if (left < 200) 229141cc406Sopenharmony_ci usleep (left * 5000); 230141cc406Sopenharmony_ci else 231141cc406Sopenharmony_ci sleep (left / 200); 232141cc406Sopenharmony_ci } 233141cc406Sopenharmony_ci } 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci return; 236141cc406Sopenharmony_ci} 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_cistatic SANE_Status 239141cc406Sopenharmony_ciget_read_sizes (int fd, int *lines_available, int *bpl, int *total_lines) 240141cc406Sopenharmony_ci{ 241141cc406Sopenharmony_ci# define GET_READ_SIZES_READ_SIZE 24 242141cc406Sopenharmony_ci 243141cc406Sopenharmony_ci const Byte scsi_read[] = 244141cc406Sopenharmony_ci { 245141cc406Sopenharmony_ci 0x28, 0x00, /* opcode, lun */ 246141cc406Sopenharmony_ci 0x81, /* data type 81 == read time left */ 247141cc406Sopenharmony_ci 0x00, 0x00, 0x00, /* reserved */ 248141cc406Sopenharmony_ci 0x00, 0x00, GET_READ_SIZES_READ_SIZE, /* transfer length */ 249141cc406Sopenharmony_ci 0x00, /* control byte */ 250141cc406Sopenharmony_ci }; 251141cc406Sopenharmony_ci 252141cc406Sopenharmony_ci Byte result[GET_READ_SIZES_READ_SIZE]; 253141cc406Sopenharmony_ci size_t size = GET_READ_SIZES_READ_SIZE; 254141cc406Sopenharmony_ci SANE_Status status; 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, scsi_read, sizeof (scsi_read), result, &size); 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD || size != GET_READ_SIZES_READ_SIZE) 259141cc406Sopenharmony_ci { 260141cc406Sopenharmony_ci /* Command failed */ 261141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 262141cc406Sopenharmony_ci } 263141cc406Sopenharmony_ci else 264141cc406Sopenharmony_ci { 265141cc406Sopenharmony_ci *lines_available = result[14] * 256 + result[15]; 266141cc406Sopenharmony_ci *bpl = result[12] * 256 + result[13]; 267141cc406Sopenharmony_ci if (total_lines) 268141cc406Sopenharmony_ci *total_lines = result[10] * 256 + result[11]; 269141cc406Sopenharmony_ci } 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci DBG (1, "get_read_sizes() : %d of %d, %d\n", 272141cc406Sopenharmony_ci *lines_available, total_lines ? *total_lines : -1, *bpl); 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 275141cc406Sopenharmony_ci} 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_cistatic SANE_Status 278141cc406Sopenharmony_ciset_window (S9036_Scanner * s) 279141cc406Sopenharmony_ci/* This function sets and sends the window for scanning */ 280141cc406Sopenharmony_ci{ 281141cc406Sopenharmony_ci double pixels_per_mm = (double) s->val[OPT_RESOLUTION] / MM_PER_INCH; 282141cc406Sopenharmony_ci 283141cc406Sopenharmony_ci SANE_Bool auto_bright = !(s->opt[OPT_BRIGHT_ADJUST].cap & SANE_CAP_INACTIVE); 284141cc406Sopenharmony_ci SANE_Bool auto_contr = !(s->opt[OPT_CONTR_ADJUST].cap & SANE_CAP_INACTIVE); 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci /* ranges down 255 (dark) down to 1(bright) */ 287141cc406Sopenharmony_ci int brightness = auto_bright ? 0 : (SANE_UNFIX (s->val[OPT_BRIGHTNESS]) 288141cc406Sopenharmony_ci * -1.27 + 128.5); 289141cc406Sopenharmony_ci /* ranges from 1 (little contrast) up to 255 (much contrast) */ 290141cc406Sopenharmony_ci int contrast = auto_contr ? 0 : (SANE_UNFIX (s->val[OPT_CONTRAST]) 291141cc406Sopenharmony_ci * 1.27 + 128.5); 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci /* ranges from 40 (dark) down to 0 (bright) */ 294141cc406Sopenharmony_ci int bright_adjust = auto_bright ? 20 - s->val[OPT_BRIGHT_ADJUST] : 0; 295141cc406Sopenharmony_ci /* ranges from 20 (little contrast) down to -20 = 235 (much contrast) */ 296141cc406Sopenharmony_ci int contr_adjust = auto_contr ? (256 - s->val[OPT_CONTR_ADJUST]) % 256 : 0; 297141cc406Sopenharmony_ci 298141cc406Sopenharmony_ci /* Warning ! The following structure SEEMS to be an valid SCSI-2 299141cc406Sopenharmony_ci SET_WINDOW command. But e.g. the limits for the window are only 300141cc406Sopenharmony_ci 2 Bytes instead of 4. The scanner was built at about 1990, so 301141cc406Sopenharmony_ci SCSI-2 wasn't available for development... 302141cc406Sopenharmony_ci */ 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci struct 305141cc406Sopenharmony_ci { 306141cc406Sopenharmony_ci Byte cmd; 307141cc406Sopenharmony_ci Byte lun; 308141cc406Sopenharmony_ci Byte re1[4]; 309141cc406Sopenharmony_ci Byte tr_len[3]; 310141cc406Sopenharmony_ci Byte ctrl; 311141cc406Sopenharmony_ci 312141cc406Sopenharmony_ci Byte re2[6]; 313141cc406Sopenharmony_ci Byte wd_len[2]; 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci struct 316141cc406Sopenharmony_ci { 317141cc406Sopenharmony_ci Byte wid; 318141cc406Sopenharmony_ci Byte autobit; 319141cc406Sopenharmony_ci Byte x_axis_res[2]; 320141cc406Sopenharmony_ci Byte y_axis_res[2]; 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci Byte x_axis_ul[2]; 323141cc406Sopenharmony_ci Byte y_axis_ul[2]; 324141cc406Sopenharmony_ci 325141cc406Sopenharmony_ci Byte wwidth[2]; 326141cc406Sopenharmony_ci Byte wlength[2]; 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci Byte contrast; 329141cc406Sopenharmony_ci Byte threshold; 330141cc406Sopenharmony_ci Byte brightness; 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci Byte image_comp; 333141cc406Sopenharmony_ci Byte bpp; 334141cc406Sopenharmony_ci 335141cc406Sopenharmony_ci Byte ht_pattern; 336141cc406Sopenharmony_ci Byte rif_padding; 337141cc406Sopenharmony_ci Byte three; 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci Byte null1[2]; 340141cc406Sopenharmony_ci Byte null2[8]; 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci Byte null_eins; 343141cc406Sopenharmony_ci Byte eins_null; 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci Byte contr_adjust; 346141cc406Sopenharmony_ci Byte bright_adjust; 347141cc406Sopenharmony_ci 348141cc406Sopenharmony_ci Byte null3; 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_ci } 351141cc406Sopenharmony_ci wd; 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci } 354141cc406Sopenharmony_ci cmd; 355141cc406Sopenharmony_ci 356141cc406Sopenharmony_ci DBG (3, 357141cc406Sopenharmony_ci "Setting parameters: bpp %d, res %d, bri %d, con %d, bad %d, cad %d\n", 358141cc406Sopenharmony_ci s->val[OPT_DEPTH], s->val[OPT_RESOLUTION], 359141cc406Sopenharmony_ci brightness, contrast, bright_adjust, contr_adjust); 360141cc406Sopenharmony_ci 361141cc406Sopenharmony_ci memset (&cmd, 0, sizeof (cmd)); 362141cc406Sopenharmony_ci 363141cc406Sopenharmony_ci /* Commands and sizes. Original comment in German: Kommando und Groessen. */ 364141cc406Sopenharmony_ci cmd.cmd = 0x24; 365141cc406Sopenharmony_ci set_size (cmd.tr_len, 3, 37 + 8); 366141cc406Sopenharmony_ci set_size (cmd.wd_len, 2, 37); 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_ci /* Resolution. Original comment in German: Aufloesung */ 369141cc406Sopenharmony_ci set_size (cmd.wd.x_axis_res, 2, s->val[OPT_RESOLUTION]); 370141cc406Sopenharmony_ci set_size (cmd.wd.y_axis_res, 2, s->val[OPT_RESOLUTION]); 371141cc406Sopenharmony_ci 372141cc406Sopenharmony_ci /* Scan window position/size. Original comment in German: 373141cc406Sopenharmony_ci Fensterposition / Groesse */ 374141cc406Sopenharmony_ci set_size (cmd.wd.x_axis_ul, 2, 375141cc406Sopenharmony_ci SANE_UNFIX (s->val[OPT_TL_X]) * pixels_per_mm + 0.5); 376141cc406Sopenharmony_ci set_size (cmd.wd.y_axis_ul, 2, 377141cc406Sopenharmony_ci SANE_UNFIX (s->val[OPT_TL_Y]) * pixels_per_mm + 0.5); 378141cc406Sopenharmony_ci set_size (cmd.wd.wwidth, 2, SANE_UNFIX (s->val[OPT_BR_X] - s->val[OPT_TL_X]) 379141cc406Sopenharmony_ci * pixels_per_mm + 0.5); 380141cc406Sopenharmony_ci set_size (cmd.wd.wlength, 2, SANE_UNFIX (s->val[OPT_BR_Y] - s->val[OPT_TL_Y]) 381141cc406Sopenharmony_ci * pixels_per_mm + 0.5); 382141cc406Sopenharmony_ci 383141cc406Sopenharmony_ci cmd.wd.contrast = contrast; 384141cc406Sopenharmony_ci cmd.wd.threshold = 0x00; 385141cc406Sopenharmony_ci cmd.wd.brightness = brightness; 386141cc406Sopenharmony_ci 387141cc406Sopenharmony_ci cmd.wd.image_comp = (s->val[OPT_DEPTH] == 1) ? 0 : 2; 388141cc406Sopenharmony_ci cmd.wd.bpp = s->val[OPT_DEPTH]; 389141cc406Sopenharmony_ci 390141cc406Sopenharmony_ci cmd.wd.ht_pattern = 0; 391141cc406Sopenharmony_ci cmd.wd.rif_padding = 0x00; 392141cc406Sopenharmony_ci cmd.wd.three = 3; 393141cc406Sopenharmony_ci 394141cc406Sopenharmony_ci cmd.wd.null_eins = (s->val[OPT_DEPTH] == 1) ? 0 : 1; 395141cc406Sopenharmony_ci cmd.wd.eins_null = (s->val[OPT_DEPTH] == 1) ? 1 : 0; 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci cmd.wd.contr_adjust = contr_adjust; 398141cc406Sopenharmony_ci cmd.wd.bright_adjust = bright_adjust; 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci return sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0); 401141cc406Sopenharmony_ci} 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci/* Tell scanner to scan more data. Original comment in German: 404141cc406Sopenharmony_ci Fordert Scanner auf, weiter zu scannen... */ 405141cc406Sopenharmony_cistatic SANE_Status 406141cc406Sopenharmony_cirequest_more_data (S9036_Scanner * s) 407141cc406Sopenharmony_ci{ 408141cc406Sopenharmony_ci SANE_Status status; 409141cc406Sopenharmony_ci int lines_available; 410141cc406Sopenharmony_ci int bytes_per_line; 411141cc406Sopenharmony_ci 412141cc406Sopenharmony_ci status = start_scan (s->fd, SANE_TRUE); 413141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 414141cc406Sopenharmony_ci return status; 415141cc406Sopenharmony_ci 416141cc406Sopenharmony_ci wait_ready (s->fd); 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci status = get_read_sizes (s->fd, &lines_available, &bytes_per_line, 0); 419141cc406Sopenharmony_ci 420141cc406Sopenharmony_ci if (!lines_available || bytes_per_line != s->params.bytes_per_line) 421141cc406Sopenharmony_ci { 422141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 423141cc406Sopenharmony_ci } 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci if (s->lines_read + lines_available > s->params.lines) 426141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 427141cc406Sopenharmony_ci 428141cc406Sopenharmony_ci s->lines_in_scanner = lines_available; 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 431141cc406Sopenharmony_ci} 432141cc406Sopenharmony_ci 433141cc406Sopenharmony_ci/* May only be called when there is at least one row of data to 434141cc406Sopenharmony_ci be read. 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_ci Original comment in German: Darf nur aufgerufen werden, wenn 437141cc406Sopenharmony_ci wirklich noch Zeilen zu scannen/lesen sind ! */ 438141cc406Sopenharmony_cistatic SANE_Status 439141cc406Sopenharmony_ciread_more_data (S9036_Scanner * s) 440141cc406Sopenharmony_ci{ 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci static Byte cmd[] = 443141cc406Sopenharmony_ci { 444141cc406Sopenharmony_ci 0x28, 0x00, /* opcode, lun */ 445141cc406Sopenharmony_ci 0x00, /* data type 80 == read time left */ 446141cc406Sopenharmony_ci 0x00, 0x00, 0x00, /* reserved */ 447141cc406Sopenharmony_ci 0x00, 0x00, 0x00, /* transfer length */ 448141cc406Sopenharmony_ci 0x00, /* control byte */ 449141cc406Sopenharmony_ci }; 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci SANE_Status status; 452141cc406Sopenharmony_ci size_t size; 453141cc406Sopenharmony_ci int lines_read; 454141cc406Sopenharmony_ci int bpl = s->params.bytes_per_line; 455141cc406Sopenharmony_ci unsigned int i; 456141cc406Sopenharmony_ci 457141cc406Sopenharmony_ci if (s->lines_in_scanner == 0) 458141cc406Sopenharmony_ci { 459141cc406Sopenharmony_ci /* No lines in scanner ? scan some more */ 460141cc406Sopenharmony_ci status = request_more_data (s); 461141cc406Sopenharmony_ci 462141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 463141cc406Sopenharmony_ci return status; 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci } 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci /* We try this 3 times */ 468141cc406Sopenharmony_ci while (1) 469141cc406Sopenharmony_ci { 470141cc406Sopenharmony_ci 471141cc406Sopenharmony_ci /* Request as much lines as would fit into the buffer ... */ 472141cc406Sopenharmony_ci lines_read = s->bufsize / bpl; 473141cc406Sopenharmony_ci 474141cc406Sopenharmony_ci /* buffer is too small for one line: we can't handle this */ 475141cc406Sopenharmony_ci if (!lines_read) 476141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 477141cc406Sopenharmony_ci 478141cc406Sopenharmony_ci /* We only request as many lines as there are already scanned */ 479141cc406Sopenharmony_ci if (lines_read > s->lines_in_scanner) 480141cc406Sopenharmony_ci lines_read = s->lines_in_scanner; 481141cc406Sopenharmony_ci 482141cc406Sopenharmony_ci set_size (&cmd[6], 3, lines_read); 483141cc406Sopenharmony_ci size = lines_read * s->params.bytes_per_line; 484141cc406Sopenharmony_ci 485141cc406Sopenharmony_ci DBG (1, "Requesting %d lines, in scanner: %d, total: %d\n", lines_read, 486141cc406Sopenharmony_ci s->lines_in_scanner, s->params.lines); 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), s->buffer, &size); 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 491141cc406Sopenharmony_ci { 492141cc406Sopenharmony_ci if (s->bufsize > 4096) 493141cc406Sopenharmony_ci { 494141cc406Sopenharmony_ci DBG (1, "sanei_scsi_cmd(): using 4k buffer\n"); 495141cc406Sopenharmony_ci s->bufsize = 4096; 496141cc406Sopenharmony_ci continue; 497141cc406Sopenharmony_ci } 498141cc406Sopenharmony_ci 499141cc406Sopenharmony_ci DBG (1, "sanei_scsi_cmd() = %d\n", status); 500141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 501141cc406Sopenharmony_ci } 502141cc406Sopenharmony_ci 503141cc406Sopenharmony_ci if (size != (unsigned int) lines_read * s->params.bytes_per_line) 504141cc406Sopenharmony_ci { 505141cc406Sopenharmony_ci DBG (1, "sanei_scsi_cmd(): got %lu bytes, expected %d\n", 506141cc406Sopenharmony_ci (u_long) size, lines_read * s->params.bytes_per_line); 507141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 508141cc406Sopenharmony_ci } 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci DBG (1, "Got %lu bytes\n", (u_long) size); 511141cc406Sopenharmony_ci break; 512141cc406Sopenharmony_ci } 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci /* Reverse: */ 516141cc406Sopenharmony_ci if (s->params.depth != 1) 517141cc406Sopenharmony_ci for (i = 0; i < size; i++) 518141cc406Sopenharmony_ci s->buffer[i] = (255 - s->buffer[i]); 519141cc406Sopenharmony_ci 520141cc406Sopenharmony_ci s->in_buffer += size; 521141cc406Sopenharmony_ci s->lines_in_scanner -= lines_read; 522141cc406Sopenharmony_ci s->lines_read += lines_read; 523141cc406Sopenharmony_ci 524141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 525141cc406Sopenharmony_ci} 526141cc406Sopenharmony_ci 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_cistatic SANE_Status 529141cc406Sopenharmony_ciattach (const char *devname, S9036_Device ** devp) 530141cc406Sopenharmony_ci{ 531141cc406Sopenharmony_ci#define ATTACH_SCSI_INQ_LEN 55 532141cc406Sopenharmony_ci const Byte scsi_inquiry[] = 533141cc406Sopenharmony_ci { 534141cc406Sopenharmony_ci 0x12, 0x00, 0x00, 0x00, ATTACH_SCSI_INQ_LEN, 0x00 535141cc406Sopenharmony_ci }; 536141cc406Sopenharmony_ci Byte result[ATTACH_SCSI_INQ_LEN]; 537141cc406Sopenharmony_ci 538141cc406Sopenharmony_ci int fd; 539141cc406Sopenharmony_ci S9036_Device *dev; 540141cc406Sopenharmony_ci SANE_Status status; 541141cc406Sopenharmony_ci size_t size; 542141cc406Sopenharmony_ci int i; 543141cc406Sopenharmony_ci 544141cc406Sopenharmony_ci for (dev = s9036_devices; dev; dev = dev->next) 545141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 546141cc406Sopenharmony_ci { 547141cc406Sopenharmony_ci if (devp) 548141cc406Sopenharmony_ci *devp = dev; 549141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 550141cc406Sopenharmony_ci } 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_ci DBG (3, "attach: opening %s\n", devname); 553141cc406Sopenharmony_ci status = sanei_scsi_open (devname, &fd, sense_handler, 0); 554141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 555141cc406Sopenharmony_ci { 556141cc406Sopenharmony_ci DBG (1, "attach: open failed (%s)\n", sane_strstatus (status)); 557141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 558141cc406Sopenharmony_ci } 559141cc406Sopenharmony_ci 560141cc406Sopenharmony_ci DBG (3, "attach: sending INQUIRY\n"); 561141cc406Sopenharmony_ci size = sizeof (result); 562141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, scsi_inquiry, sizeof (scsi_inquiry), 563141cc406Sopenharmony_ci result, &size); 564141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD || size != ATTACH_SCSI_INQ_LEN) 565141cc406Sopenharmony_ci { 566141cc406Sopenharmony_ci DBG (1, "attach: inquiry failed (%s)\n", sane_strstatus (status)); 567141cc406Sopenharmony_ci sanei_scsi_close (fd); 568141cc406Sopenharmony_ci return status; 569141cc406Sopenharmony_ci } 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci status = test_ready (fd); 572141cc406Sopenharmony_ci sanei_scsi_close (fd); 573141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 574141cc406Sopenharmony_ci return status; 575141cc406Sopenharmony_ci 576141cc406Sopenharmony_ci /* The structure send by the scanner after inquiry is not SCSI-2 577141cc406Sopenharmony_ci compatible. The standard manufacturer/model fields are no ASCII 578141cc406Sopenharmony_ci strings, but ? At offset 36 my SIEMENS scanner identifies as an 579141cc406Sopenharmony_ci AGFA one ?! */ 580141cc406Sopenharmony_ci 581141cc406Sopenharmony_ci if (result[0] != 6 || strncmp ((char *)result + 36, "AGFA03", 6)) 582141cc406Sopenharmony_ci { 583141cc406Sopenharmony_ci DBG (1, "attach: device doesn't look like a Siemens 9036 scanner\n"); 584141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 585141cc406Sopenharmony_ci } 586141cc406Sopenharmony_ci 587141cc406Sopenharmony_ci DBG (3, "Inquiry data:\n"); 588141cc406Sopenharmony_ci for (i = 5; i < 55; i += 10) 589141cc406Sopenharmony_ci DBG (3, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 590141cc406Sopenharmony_ci result[i], result[i + 1], result[i + 2], result[i + 3], result[i + 4], 591141cc406Sopenharmony_ci result[i + 5], result[i + 6], result[i + 7], result[i + 8], 592141cc406Sopenharmony_ci result[i + 9]); 593141cc406Sopenharmony_ci 594141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci if (!dev) 597141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 598141cc406Sopenharmony_ci 599141cc406Sopenharmony_ci memset (dev, 0, sizeof (*dev)); 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_ci dev->sane.name = strdup (devname); 602141cc406Sopenharmony_ci dev->sane.vendor = "Siemens"; 603141cc406Sopenharmony_ci dev->sane.model = "9036"; 604141cc406Sopenharmony_ci dev->sane.type = "flatbed scanner"; 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci dev->handle = 0; 607141cc406Sopenharmony_ci 608141cc406Sopenharmony_ci DBG (3, "attach: found S9036 scanner model\n"); 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_ci ++num_devices; 611141cc406Sopenharmony_ci dev->next = s9036_devices; 612141cc406Sopenharmony_ci s9036_devices = dev; 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci if (devp) 615141cc406Sopenharmony_ci *devp = dev; 616141cc406Sopenharmony_ci 617141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 618141cc406Sopenharmony_ci} 619141cc406Sopenharmony_ci 620141cc406Sopenharmony_cistatic SANE_Status 621141cc406Sopenharmony_cido_cancel (S9036_Scanner * s) 622141cc406Sopenharmony_ci{ 623141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci if (s->fd >= 0) 626141cc406Sopenharmony_ci { 627141cc406Sopenharmony_ci stop_scan (s->fd); 628141cc406Sopenharmony_ci release_unit (s->fd); 629141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 630141cc406Sopenharmony_ci s->fd = -1; 631141cc406Sopenharmony_ci } 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci if (s->buffer) 634141cc406Sopenharmony_ci { 635141cc406Sopenharmony_ci free (s->buffer); 636141cc406Sopenharmony_ci s->buffer = 0; 637141cc406Sopenharmony_ci } 638141cc406Sopenharmony_ci 639141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 640141cc406Sopenharmony_ci} 641141cc406Sopenharmony_ci 642141cc406Sopenharmony_ci 643141cc406Sopenharmony_cistatic SANE_Status 644141cc406Sopenharmony_ciinit_options (S9036_Scanner * s) 645141cc406Sopenharmony_ci{ 646141cc406Sopenharmony_ci int i; 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci /* Hardware Limitations: must be static ! */ 649141cc406Sopenharmony_ci static const SANE_Int depth_list[] = 650141cc406Sopenharmony_ci {2, 1, 8}; 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci static const SANE_Int dpi_list[] = 653141cc406Sopenharmony_ci {8, 100, 200, 300, 400, 500, 600, 700, 800}; 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci static const SANE_Range percentage_range = 656141cc406Sopenharmony_ci { 657141cc406Sopenharmony_ci SANE_FIX(-100), /* minimum */ 658141cc406Sopenharmony_ci SANE_FIX(100), /* maximum */ 659141cc406Sopenharmony_ci SANE_FIX(1) /* quantization */ 660141cc406Sopenharmony_ci }; 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci static const SANE_Range automatic_adjust_range = 663141cc406Sopenharmony_ci {-20, 20, 1}; 664141cc406Sopenharmony_ci 665141cc406Sopenharmony_ci static const SANE_Range x_range = 666141cc406Sopenharmony_ci {0, SANE_FIX (8.27 * MM_PER_INCH), 0}; 667141cc406Sopenharmony_ci static const SANE_Range y_range = 668141cc406Sopenharmony_ci {0, SANE_FIX (12.72 * MM_PER_INCH), 0}; 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_ci /* ------ */ 671141cc406Sopenharmony_ci 672141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 673141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 676141cc406Sopenharmony_ci { 677141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 678141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 679141cc406Sopenharmony_ci } 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 682141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 683141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 684141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 685141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS] = NUM_OPTIONS; 686141cc406Sopenharmony_ci 687141cc406Sopenharmony_ci /* "Mode" group: */ 688141cc406Sopenharmony_ci 689141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 690141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 691141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 692141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 693141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 694141cc406Sopenharmony_ci 695141cc406Sopenharmony_ci /* depth */ 696141cc406Sopenharmony_ci s->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH; 697141cc406Sopenharmony_ci s->opt[OPT_DEPTH].title = SANE_TITLE_BIT_DEPTH; 698141cc406Sopenharmony_ci s->opt[OPT_DEPTH].desc = SANE_DESC_BIT_DEPTH; 699141cc406Sopenharmony_ci s->opt[OPT_DEPTH].type = SANE_TYPE_INT; 700141cc406Sopenharmony_ci s->opt[OPT_DEPTH].unit = SANE_UNIT_BIT; 701141cc406Sopenharmony_ci s->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; 702141cc406Sopenharmony_ci s->opt[OPT_DEPTH].constraint.word_list = depth_list; 703141cc406Sopenharmony_ci s->val[OPT_DEPTH] = 1; 704141cc406Sopenharmony_ci 705141cc406Sopenharmony_ci /* resolution */ 706141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 707141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 708141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 709141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; 710141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 711141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; 712141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; 713141cc406Sopenharmony_ci s->val[OPT_RESOLUTION] = 100; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci /* "Geometry" group: */ 716141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 717141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 718141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 719141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 720141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci /* top-left x */ 723141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 724141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 725141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 726141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 727141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 728141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 729141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &x_range; 730141cc406Sopenharmony_ci s->val[OPT_TL_X] = 0; 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci /* top-left y */ 733141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 734141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 735141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 736141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 737141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 738141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 739141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &y_range; 740141cc406Sopenharmony_ci s->val[OPT_TL_Y] = 0; 741141cc406Sopenharmony_ci 742141cc406Sopenharmony_ci /* bottom-right x */ 743141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 744141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 745141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 746141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 747141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 748141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 749141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &x_range; 750141cc406Sopenharmony_ci s->val[OPT_BR_X] = x_range.max; 751141cc406Sopenharmony_ci 752141cc406Sopenharmony_ci /* bottom-right y */ 753141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 754141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 755141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 756141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 757141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 758141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 759141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &y_range; 760141cc406Sopenharmony_ci s->val[OPT_BR_Y] = y_range.max; 761141cc406Sopenharmony_ci 762141cc406Sopenharmony_ci /* "Enhancement" group: */ 763141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 764141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 765141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 766141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 767141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 768141cc406Sopenharmony_ci 769141cc406Sopenharmony_ci /* brightness */ 770141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 771141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 772141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 773141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED; 774141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_AUTOMATIC; 775141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT; 776141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 777141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range; 778141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS] = 0; 779141cc406Sopenharmony_ci 780141cc406Sopenharmony_ci /* contrast */ 781141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 782141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 783141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 784141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED; 785141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap |= SANE_CAP_AUTOMATIC; 786141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT; 787141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 788141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &percentage_range; 789141cc406Sopenharmony_ci s->val[OPT_CONTRAST] = 0; 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci /* brightness automatic correct */ 792141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].name = "adjust-bright"; 793141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].title = "Automatic brightness adjust"; 794141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].desc = "Controls the automatic brightness of the " 795141cc406Sopenharmony_ci "acquired image. This option is active for automatic brightness only."; 796141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].type = SANE_TYPE_INT; 797141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].cap |= SANE_CAP_INACTIVE; 798141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].unit = SANE_UNIT_NONE; 799141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].constraint_type = SANE_CONSTRAINT_RANGE; 800141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].constraint.range = &automatic_adjust_range; 801141cc406Sopenharmony_ci s->val[OPT_BRIGHT_ADJUST] = 0; 802141cc406Sopenharmony_ci 803141cc406Sopenharmony_ci /* contrast automatic correct */ 804141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].name = "adjust-contr"; 805141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].title = "Automatic contrast adjust"; 806141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].desc = "Controls the automatic contrast of the " 807141cc406Sopenharmony_ci " acquired image. This option is active for automatic contrast only."; 808141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].type = SANE_TYPE_INT; 809141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].cap |= SANE_CAP_INACTIVE; 810141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].unit = SANE_UNIT_NONE; 811141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].constraint_type = SANE_CONSTRAINT_RANGE; 812141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].constraint.range = &automatic_adjust_range; 813141cc406Sopenharmony_ci s->val[OPT_CONTR_ADJUST] = 0; 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 816141cc406Sopenharmony_ci} 817141cc406Sopenharmony_ci 818141cc406Sopenharmony_cistatic SANE_Status 819141cc406Sopenharmony_ciattach_one (const char *dev) 820141cc406Sopenharmony_ci{ 821141cc406Sopenharmony_ci attach (dev, 0); 822141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 823141cc406Sopenharmony_ci} 824141cc406Sopenharmony_ci 825141cc406Sopenharmony_ciSANE_Status 826141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 827141cc406Sopenharmony_ci{ 828141cc406Sopenharmony_ci char dev_name[PATH_MAX]; 829141cc406Sopenharmony_ci size_t len; 830141cc406Sopenharmony_ci FILE *fp; 831141cc406Sopenharmony_ci 832141cc406Sopenharmony_ci (void) authorize; /* silence compilation warnings */ 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci DBG_INIT (); 835141cc406Sopenharmony_ci 836141cc406Sopenharmony_ci if (version_code) 837141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 838141cc406Sopenharmony_ci 839141cc406Sopenharmony_ci fp = sanei_config_open ("s9036.conf"); 840141cc406Sopenharmony_ci if (!fp) 841141cc406Sopenharmony_ci { 842141cc406Sopenharmony_ci /* default to /dev/scanner instead of insisting on config file */ 843141cc406Sopenharmony_ci attach ("/dev/scanner", 0); 844141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 845141cc406Sopenharmony_ci } 846141cc406Sopenharmony_ci 847141cc406Sopenharmony_ci while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 848141cc406Sopenharmony_ci { 849141cc406Sopenharmony_ci if (dev_name[0] == '#') /* ignore line comments */ 850141cc406Sopenharmony_ci continue; 851141cc406Sopenharmony_ci len = strlen (dev_name); 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_ci if (!len) 854141cc406Sopenharmony_ci continue; /* ignore empty lines */ 855141cc406Sopenharmony_ci 856141cc406Sopenharmony_ci sanei_config_attach_matching_devices (dev_name, attach_one); 857141cc406Sopenharmony_ci } 858141cc406Sopenharmony_ci fclose (fp); 859141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 860141cc406Sopenharmony_ci} 861141cc406Sopenharmony_ci 862141cc406Sopenharmony_civoid 863141cc406Sopenharmony_cisane_exit (void) 864141cc406Sopenharmony_ci{ 865141cc406Sopenharmony_ci S9036_Device *dev, *next; 866141cc406Sopenharmony_ci 867141cc406Sopenharmony_ci for (dev = s9036_devices; dev; dev = next) 868141cc406Sopenharmony_ci { 869141cc406Sopenharmony_ci next = dev->next; 870141cc406Sopenharmony_ci if (dev->handle) 871141cc406Sopenharmony_ci sane_close (dev->handle); 872141cc406Sopenharmony_ci free (dev); 873141cc406Sopenharmony_ci } 874141cc406Sopenharmony_ci 875141cc406Sopenharmony_ci if (devlist) 876141cc406Sopenharmony_ci free (devlist); 877141cc406Sopenharmony_ci} 878141cc406Sopenharmony_ci 879141cc406Sopenharmony_ciSANE_Status 880141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 881141cc406Sopenharmony_ci{ 882141cc406Sopenharmony_ci S9036_Device *dev; 883141cc406Sopenharmony_ci int i; 884141cc406Sopenharmony_ci 885141cc406Sopenharmony_ci (void) local_only; /* silence compilation warnings */ 886141cc406Sopenharmony_ci 887141cc406Sopenharmony_ci if (devlist) 888141cc406Sopenharmony_ci free (devlist); 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 891141cc406Sopenharmony_ci if (!devlist) 892141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 893141cc406Sopenharmony_ci 894141cc406Sopenharmony_ci for (dev = s9036_devices, i = 0; i < num_devices; dev = dev->next) 895141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 896141cc406Sopenharmony_ci devlist[i++] = 0; 897141cc406Sopenharmony_ci 898141cc406Sopenharmony_ci *device_list = devlist; 899141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 900141cc406Sopenharmony_ci} 901141cc406Sopenharmony_ci 902141cc406Sopenharmony_ciSANE_Status 903141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle) 904141cc406Sopenharmony_ci{ 905141cc406Sopenharmony_ci S9036_Device *dev; 906141cc406Sopenharmony_ci SANE_Status status; 907141cc406Sopenharmony_ci S9036_Scanner *s; 908141cc406Sopenharmony_ci 909141cc406Sopenharmony_ci if (devicename[0]) 910141cc406Sopenharmony_ci { 911141cc406Sopenharmony_ci status = attach (devicename, &dev); 912141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 913141cc406Sopenharmony_ci return status; 914141cc406Sopenharmony_ci } 915141cc406Sopenharmony_ci else 916141cc406Sopenharmony_ci { 917141cc406Sopenharmony_ci /* empty devicname -> use first device */ 918141cc406Sopenharmony_ci dev = s9036_devices; 919141cc406Sopenharmony_ci } 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci if (!dev) 922141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ci if (dev->handle) 925141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 928141cc406Sopenharmony_ci if (!s) 929141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 932141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 933141cc406Sopenharmony_ci s->fd = -1; 934141cc406Sopenharmony_ci s->hw = dev; 935141cc406Sopenharmony_ci s->hw->handle = s; 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci init_options (s); 938141cc406Sopenharmony_ci 939141cc406Sopenharmony_ci *handle = s; 940141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 941141cc406Sopenharmony_ci} 942141cc406Sopenharmony_ci 943141cc406Sopenharmony_civoid 944141cc406Sopenharmony_cisane_close (SANE_Handle handle) 945141cc406Sopenharmony_ci{ 946141cc406Sopenharmony_ci S9036_Scanner *s = handle; 947141cc406Sopenharmony_ci 948141cc406Sopenharmony_ci if (s->scanning) 949141cc406Sopenharmony_ci do_cancel (handle); 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci s->hw->handle = 0; 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci free (handle); 954141cc406Sopenharmony_ci} 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 957141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 958141cc406Sopenharmony_ci{ 959141cc406Sopenharmony_ci S9036_Scanner *s = handle; 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 962141cc406Sopenharmony_ci return 0; 963141cc406Sopenharmony_ci return s->opt + option; 964141cc406Sopenharmony_ci} 965141cc406Sopenharmony_ci 966141cc406Sopenharmony_ciSANE_Status 967141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 968141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 969141cc406Sopenharmony_ci{ 970141cc406Sopenharmony_ci S9036_Scanner *s = handle; 971141cc406Sopenharmony_ci SANE_Status status; 972141cc406Sopenharmony_ci 973141cc406Sopenharmony_ci if (info) 974141cc406Sopenharmony_ci *info = 0; 975141cc406Sopenharmony_ci 976141cc406Sopenharmony_ci if (s->scanning) 977141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 978141cc406Sopenharmony_ci 979141cc406Sopenharmony_ci if (option >= NUM_OPTIONS || !SANE_OPTION_IS_ACTIVE (s->opt[option].cap)) 980141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 981141cc406Sopenharmony_ci 982141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 983141cc406Sopenharmony_ci { 984141cc406Sopenharmony_ci 985141cc406Sopenharmony_ci switch (option) 986141cc406Sopenharmony_ci { 987141cc406Sopenharmony_ci case OPT_DEPTH: 988141cc406Sopenharmony_ci case OPT_RESOLUTION: 989141cc406Sopenharmony_ci case OPT_TL_X: 990141cc406Sopenharmony_ci case OPT_TL_Y: 991141cc406Sopenharmony_ci case OPT_BR_X: 992141cc406Sopenharmony_ci case OPT_BR_Y: 993141cc406Sopenharmony_ci case OPT_NUM_OPTS: 994141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 995141cc406Sopenharmony_ci case OPT_CONTRAST: 996141cc406Sopenharmony_ci case OPT_BRIGHT_ADJUST: 997141cc406Sopenharmony_ci case OPT_CONTR_ADJUST: 998141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option]; 999141cc406Sopenharmony_ci break; 1000141cc406Sopenharmony_ci default: 1001141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1002141cc406Sopenharmony_ci } 1003141cc406Sopenharmony_ci 1004141cc406Sopenharmony_ci } 1005141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 1006141cc406Sopenharmony_ci { 1007141cc406Sopenharmony_ci 1008141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap)) 1009141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1010141cc406Sopenharmony_ci 1011141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 1012141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1013141cc406Sopenharmony_ci return status; 1014141cc406Sopenharmony_ci 1015141cc406Sopenharmony_ci switch (option) 1016141cc406Sopenharmony_ci { 1017141cc406Sopenharmony_ci case OPT_DEPTH: 1018141cc406Sopenharmony_ci case OPT_RESOLUTION: 1019141cc406Sopenharmony_ci case OPT_TL_X: 1020141cc406Sopenharmony_ci case OPT_TL_Y: 1021141cc406Sopenharmony_ci case OPT_BR_X: 1022141cc406Sopenharmony_ci case OPT_BR_Y: 1023141cc406Sopenharmony_ci if (info) 1024141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1025141cc406Sopenharmony_ci // fall through 1026141cc406Sopenharmony_ci case OPT_BRIGHT_ADJUST: 1027141cc406Sopenharmony_ci case OPT_CONTR_ADJUST: 1028141cc406Sopenharmony_ci s->val[option] = *(SANE_Word *) val; 1029141cc406Sopenharmony_ci break; 1030141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1031141cc406Sopenharmony_ci if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_BRIGHT_ADJUST].cap)) 1032141cc406Sopenharmony_ci { 1033141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].cap |= SANE_CAP_INACTIVE; 1034141cc406Sopenharmony_ci if (info) 1035141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1036141cc406Sopenharmony_ci } 1037141cc406Sopenharmony_ci s->val[option] = *(SANE_Word *) val; 1038141cc406Sopenharmony_ci break; 1039141cc406Sopenharmony_ci case OPT_CONTRAST: 1040141cc406Sopenharmony_ci if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_CONTR_ADJUST].cap)) 1041141cc406Sopenharmony_ci { 1042141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].cap |= SANE_CAP_INACTIVE; 1043141cc406Sopenharmony_ci if (info) 1044141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1045141cc406Sopenharmony_ci } 1046141cc406Sopenharmony_ci s->val[option] = *(SANE_Word *) val; 1047141cc406Sopenharmony_ci break; 1048141cc406Sopenharmony_ci default: 1049141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1050141cc406Sopenharmony_ci } 1051141cc406Sopenharmony_ci 1052141cc406Sopenharmony_ci } 1053141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_AUTO) 1054141cc406Sopenharmony_ci { 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap)) 1057141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1058141cc406Sopenharmony_ci 1059141cc406Sopenharmony_ci switch (option) 1060141cc406Sopenharmony_ci { 1061141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1062141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (s->opt[OPT_BRIGHT_ADJUST].cap)) 1063141cc406Sopenharmony_ci { 1064141cc406Sopenharmony_ci s->opt[OPT_BRIGHT_ADJUST].cap &= ~SANE_CAP_INACTIVE; 1065141cc406Sopenharmony_ci if (info) 1066141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1067141cc406Sopenharmony_ci } 1068141cc406Sopenharmony_ci break; 1069141cc406Sopenharmony_ci case OPT_CONTRAST: 1070141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (s->opt[OPT_CONTR_ADJUST].cap)) 1071141cc406Sopenharmony_ci { 1072141cc406Sopenharmony_ci s->opt[OPT_CONTR_ADJUST].cap &= ~SANE_CAP_INACTIVE; 1073141cc406Sopenharmony_ci if (info) 1074141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1075141cc406Sopenharmony_ci } 1076141cc406Sopenharmony_ci break; 1077141cc406Sopenharmony_ci default: 1078141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1079141cc406Sopenharmony_ci } 1080141cc406Sopenharmony_ci 1081141cc406Sopenharmony_ci } 1082141cc406Sopenharmony_ci else 1083141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1084141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1085141cc406Sopenharmony_ci} 1086141cc406Sopenharmony_ci 1087141cc406Sopenharmony_ciSANE_Status 1088141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 1089141cc406Sopenharmony_ci{ 1090141cc406Sopenharmony_ci S9036_Scanner *s = handle; 1091141cc406Sopenharmony_ci 1092141cc406Sopenharmony_ci if (!s->scanning) 1093141cc406Sopenharmony_ci { 1094141cc406Sopenharmony_ci double width, height, dpi; 1095141cc406Sopenharmony_ci 1096141cc406Sopenharmony_ci memset (&s->params, 0, sizeof (s->params)); 1097141cc406Sopenharmony_ci 1098141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 1099141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci s->params.depth = s->val[OPT_DEPTH]; 1102141cc406Sopenharmony_ci 1103141cc406Sopenharmony_ci width = SANE_UNFIX (s->val[OPT_BR_X] - s->val[OPT_TL_X]); 1104141cc406Sopenharmony_ci height = SANE_UNFIX (s->val[OPT_BR_Y] - s->val[OPT_TL_Y]); 1105141cc406Sopenharmony_ci dpi = s->val[OPT_RESOLUTION]; 1106141cc406Sopenharmony_ci 1107141cc406Sopenharmony_ci /* make best-effort guess at what parameters will look like once 1108141cc406Sopenharmony_ci scanning starts. */ 1109141cc406Sopenharmony_ci if (dpi > 0.0 && width > 0.0 && height > 0.0) 1110141cc406Sopenharmony_ci { 1111141cc406Sopenharmony_ci double dots_per_mm = dpi / MM_PER_INCH; 1112141cc406Sopenharmony_ci 1113141cc406Sopenharmony_ci s->params.pixels_per_line = width * dots_per_mm + 0.5; 1114141cc406Sopenharmony_ci s->params.lines = height * dots_per_mm + 0.5; 1115141cc406Sopenharmony_ci } 1116141cc406Sopenharmony_ci 1117141cc406Sopenharmony_ci s->params.bytes_per_line = 1118141cc406Sopenharmony_ci (s->params.pixels_per_line + (8 - s->params.depth)) 1119141cc406Sopenharmony_ci / (8 / s->params.depth); 1120141cc406Sopenharmony_ci } 1121141cc406Sopenharmony_ci 1122141cc406Sopenharmony_ci if (params) 1123141cc406Sopenharmony_ci *params = s->params; 1124141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1125141cc406Sopenharmony_ci} 1126141cc406Sopenharmony_ci 1127141cc406Sopenharmony_ciSANE_Status 1128141cc406Sopenharmony_cisane_start (SANE_Handle handle) 1129141cc406Sopenharmony_ci{ 1130141cc406Sopenharmony_ci S9036_Scanner *s = handle; 1131141cc406Sopenharmony_ci SANE_Status status; 1132141cc406Sopenharmony_ci 1133141cc406Sopenharmony_ci if (s->scanning) 1134141cc406Sopenharmony_ci do_cancel (s); 1135141cc406Sopenharmony_ci 1136141cc406Sopenharmony_ci /* First make sure we have a current parameter set. Some of the 1137141cc406Sopenharmony_ci parameters will be overwritten below, but that's OK. */ 1138141cc406Sopenharmony_ci status = sane_get_parameters (s, 0); 1139141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1140141cc406Sopenharmony_ci return status; 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_ci if (s->fd < 0) 1143141cc406Sopenharmony_ci { 1144141cc406Sopenharmony_ci status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0); 1145141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1146141cc406Sopenharmony_ci { 1147141cc406Sopenharmony_ci DBG (1, "open: open of %s failed: %s\n", 1148141cc406Sopenharmony_ci s->hw->sane.name, sane_strstatus (status)); 1149141cc406Sopenharmony_ci s->fd = -1; 1150141cc406Sopenharmony_ci return status; 1151141cc406Sopenharmony_ci } 1152141cc406Sopenharmony_ci } 1153141cc406Sopenharmony_ci 1154141cc406Sopenharmony_ci status = test_ready (s->fd); 1155141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1156141cc406Sopenharmony_ci { 1157141cc406Sopenharmony_ci DBG (1, "open: test_ready() failed: %s\n", sane_strstatus (status)); 1158141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 1159141cc406Sopenharmony_ci s->fd = -1; 1160141cc406Sopenharmony_ci return status; 1161141cc406Sopenharmony_ci } 1162141cc406Sopenharmony_ci 1163141cc406Sopenharmony_ci status = reserve_unit (s->fd); 1164141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1165141cc406Sopenharmony_ci { 1166141cc406Sopenharmony_ci DBG (1, "open: reserve_unit() failed: %s\n", sane_strstatus (status)); 1167141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 1168141cc406Sopenharmony_ci s->fd = -1; 1169141cc406Sopenharmony_ci return status; 1170141cc406Sopenharmony_ci } 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ci status = set_window (s); 1173141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1174141cc406Sopenharmony_ci { 1175141cc406Sopenharmony_ci DBG (1, "open: set_window() failed: %s\n", sane_strstatus (status)); 1176141cc406Sopenharmony_ci release_unit (s->fd); 1177141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 1178141cc406Sopenharmony_ci s->fd = -1; 1179141cc406Sopenharmony_ci return status; 1180141cc406Sopenharmony_ci } 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 1183141cc406Sopenharmony_ci 1184141cc406Sopenharmony_ci status = start_scan (s->fd, SANE_FALSE); 1185141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1186141cc406Sopenharmony_ci { 1187141cc406Sopenharmony_ci DBG (1, "open: start_scan() failed: %s\n", sane_strstatus (status)); 1188141cc406Sopenharmony_ci do_cancel (s); 1189141cc406Sopenharmony_ci return status; 1190141cc406Sopenharmony_ci } 1191141cc406Sopenharmony_ci 1192141cc406Sopenharmony_ci wait_ready (s->fd); 1193141cc406Sopenharmony_ci 1194141cc406Sopenharmony_ci { 1195141cc406Sopenharmony_ci int lines_available = 0, bytes_per_line = 0, total_lines = 0; 1196141cc406Sopenharmony_ci 1197141cc406Sopenharmony_ci status = get_read_sizes (s->fd, &lines_available, &bytes_per_line, 1198141cc406Sopenharmony_ci &total_lines); 1199141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1200141cc406Sopenharmony_ci { 1201141cc406Sopenharmony_ci DBG (1, "open: get_read_sizes() failed: %s\n", 1202141cc406Sopenharmony_ci sane_strstatus (status)); 1203141cc406Sopenharmony_ci do_cancel (s); 1204141cc406Sopenharmony_ci return status; 1205141cc406Sopenharmony_ci } 1206141cc406Sopenharmony_ci 1207141cc406Sopenharmony_ci if (!lines_available || !bytes_per_line || !total_lines) 1208141cc406Sopenharmony_ci { 1209141cc406Sopenharmony_ci DBG (1, "open: invalid_sizes(): %d, %d, %d\n", 1210141cc406Sopenharmony_ci lines_available, bytes_per_line, total_lines); 1211141cc406Sopenharmony_ci do_cancel (s); 1212141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1213141cc406Sopenharmony_ci } 1214141cc406Sopenharmony_ci 1215141cc406Sopenharmony_ci s->params.lines = total_lines; 1216141cc406Sopenharmony_ci s->params.bytes_per_line = bytes_per_line; 1217141cc406Sopenharmony_ci s->params.pixels_per_line = bytes_per_line * (8 / s->params.depth); 1218141cc406Sopenharmony_ci 1219141cc406Sopenharmony_ci s->lines_in_scanner = lines_available; 1220141cc406Sopenharmony_ci s->lines_read = 0; 1221141cc406Sopenharmony_ci 1222141cc406Sopenharmony_ci /* Buffer must be at least 4k */ 1223141cc406Sopenharmony_ci s->bufsize = (sanei_scsi_max_request_size < 4096) ? 1224141cc406Sopenharmony_ci 4096 : sanei_scsi_max_request_size; 1225141cc406Sopenharmony_ci 1226141cc406Sopenharmony_ci s->buffer = (Byte *) malloc (s->bufsize * sizeof (Byte)); 1227141cc406Sopenharmony_ci 1228141cc406Sopenharmony_ci if (!s->buffer) 1229141cc406Sopenharmony_ci { 1230141cc406Sopenharmony_ci DBG (1, "open malloc(%lu) failed.\n", (u_long) s->bufsize); 1231141cc406Sopenharmony_ci do_cancel (s); 1232141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1233141cc406Sopenharmony_ci } 1234141cc406Sopenharmony_ci s->bufstart = s->buffer; 1235141cc406Sopenharmony_ci s->in_buffer = 0; 1236141cc406Sopenharmony_ci } 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1239141cc406Sopenharmony_ci} 1240141cc406Sopenharmony_ci 1241141cc406Sopenharmony_cistatic void 1242141cc406Sopenharmony_cicopy_buffer (S9036_Scanner * s, SANE_Byte ** buf, SANE_Int * max_len, 1243141cc406Sopenharmony_ci SANE_Int * len) 1244141cc406Sopenharmony_ci{ 1245141cc406Sopenharmony_ci if (*max_len > (SANE_Int) s->in_buffer) 1246141cc406Sopenharmony_ci { 1247141cc406Sopenharmony_ci memcpy (*buf, s->bufstart, s->in_buffer); 1248141cc406Sopenharmony_ci *buf += s->in_buffer; 1249141cc406Sopenharmony_ci *len += s->in_buffer; 1250141cc406Sopenharmony_ci *max_len -= s->in_buffer; 1251141cc406Sopenharmony_ci 1252141cc406Sopenharmony_ci s->bufstart = s->buffer; 1253141cc406Sopenharmony_ci s->in_buffer = 0; 1254141cc406Sopenharmony_ci } 1255141cc406Sopenharmony_ci else 1256141cc406Sopenharmony_ci { 1257141cc406Sopenharmony_ci memcpy (*buf, s->bufstart, *max_len); 1258141cc406Sopenharmony_ci s->bufstart += *max_len; 1259141cc406Sopenharmony_ci s->in_buffer -= *max_len; 1260141cc406Sopenharmony_ci 1261141cc406Sopenharmony_ci *buf += *max_len; 1262141cc406Sopenharmony_ci *len += *max_len; 1263141cc406Sopenharmony_ci *max_len = 0; 1264141cc406Sopenharmony_ci } 1265141cc406Sopenharmony_ci} 1266141cc406Sopenharmony_ci 1267141cc406Sopenharmony_ci 1268141cc406Sopenharmony_ciSANE_Status 1269141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, 1270141cc406Sopenharmony_ci SANE_Int * len) 1271141cc406Sopenharmony_ci{ 1272141cc406Sopenharmony_ci S9036_Scanner *s = handle; 1273141cc406Sopenharmony_ci SANE_Status status; 1274141cc406Sopenharmony_ci 1275141cc406Sopenharmony_ci if (s->scanning != SANE_TRUE || max_len == 0) 1276141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci *len = 0; 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci DBG (3, "sane_read(%d) : lines_read %d\n", max_len, s->lines_read); 1281141cc406Sopenharmony_ci 1282141cc406Sopenharmony_ci while (max_len > (SANE_Int) s->in_buffer && s->lines_read < s->params.lines) 1283141cc406Sopenharmony_ci { 1284141cc406Sopenharmony_ci 1285141cc406Sopenharmony_ci if (s->in_buffer == 0) 1286141cc406Sopenharmony_ci { 1287141cc406Sopenharmony_ci status = read_more_data (s); 1288141cc406Sopenharmony_ci 1289141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1290141cc406Sopenharmony_ci { 1291141cc406Sopenharmony_ci DBG (1, "sane_read: read_more_data() failed (%s)\n", 1292141cc406Sopenharmony_ci sane_strstatus (status)); 1293141cc406Sopenharmony_ci do_cancel (s); 1294141cc406Sopenharmony_ci return status; 1295141cc406Sopenharmony_ci } 1296141cc406Sopenharmony_ci } 1297141cc406Sopenharmony_ci 1298141cc406Sopenharmony_ci copy_buffer (s, &buf, &max_len, len); 1299141cc406Sopenharmony_ci 1300141cc406Sopenharmony_ci if (!max_len || s->lines_read >= s->params.lines) 1301141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1302141cc406Sopenharmony_ci } 1303141cc406Sopenharmony_ci 1304141cc406Sopenharmony_ci /* If we reached this point, there are either enough bytes in the buffer, 1305141cc406Sopenharmony_ci or, if the buffer is empty, we already reached the end of the page */ 1306141cc406Sopenharmony_ci 1307141cc406Sopenharmony_ci if (s->in_buffer > 0) 1308141cc406Sopenharmony_ci { 1309141cc406Sopenharmony_ci copy_buffer (s, &buf, &max_len, len); 1310141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1311141cc406Sopenharmony_ci } 1312141cc406Sopenharmony_ci else 1313141cc406Sopenharmony_ci { 1314141cc406Sopenharmony_ci do_cancel (s); 1315141cc406Sopenharmony_ci DBG (1, "EOF\n"); 1316141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1317141cc406Sopenharmony_ci } 1318141cc406Sopenharmony_ci} 1319141cc406Sopenharmony_ci 1320141cc406Sopenharmony_civoid 1321141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 1322141cc406Sopenharmony_ci{ 1323141cc406Sopenharmony_ci S9036_Scanner *s = handle; 1324141cc406Sopenharmony_ci do_cancel (s); 1325141cc406Sopenharmony_ci} 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ciSANE_Status 1328141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 1329141cc406Sopenharmony_ci{ 1330141cc406Sopenharmony_ci (void) handle; /* silence compilation warnings */ 1331141cc406Sopenharmony_ci 1332141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode(%d)\n", non_blocking); 1333141cc406Sopenharmony_ci 1334141cc406Sopenharmony_ci return (non_blocking == SANE_TRUE) ? 1335141cc406Sopenharmony_ci SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD; 1336141cc406Sopenharmony_ci} 1337141cc406Sopenharmony_ci 1338141cc406Sopenharmony_ciSANE_Status 1339141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 1340141cc406Sopenharmony_ci{ 1341141cc406Sopenharmony_ci (void) handle; 1342141cc406Sopenharmony_ci (void) fd; /* silence compilation warnings */ 1343141cc406Sopenharmony_ci 1344141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1345141cc406Sopenharmony_ci} 1346