1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 1998 David Huggins-Daines, heavily based on the Apple 4141cc406Sopenharmony_ci scanner driver (since Abaton scanners are very similar to old Apple 5141cc406Sopenharmony_ci scanners), which is (C) 1998 Milon Firikis, which is, in turn, based 6141cc406Sopenharmony_ci on the Mustek driver, (C) 1996-7 David Mosberger-Tang. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci This file is part of the SANE package. 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 11141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 12141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 13141cc406Sopenharmony_ci License, or (at your option) any later version. 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 16141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 17141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18141cc406Sopenharmony_ci General Public License for more details. 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 21141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 24141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 25141cc406Sopenharmony_ci 26141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 27141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 28141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 29141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 30141cc406Sopenharmony_ci account of linking the SANE library code into it. 31141cc406Sopenharmony_ci 32141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 33141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 34141cc406Sopenharmony_ci License. 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 37141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 38141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 39141cc406Sopenharmony_ci 40141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 41141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 42141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci This file implements a SANE backend for Abaton flatbed scanners. */ 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci#include "../include/sane/config.h" 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include <ctype.h> 49141cc406Sopenharmony_ci#include <errno.h> 50141cc406Sopenharmony_ci#include <fcntl.h> 51141cc406Sopenharmony_ci#include <limits.h> 52141cc406Sopenharmony_ci#include <signal.h> 53141cc406Sopenharmony_ci#include <stdio.h> 54141cc406Sopenharmony_ci#include <stdlib.h> 55141cc406Sopenharmony_ci#include <string.h> 56141cc406Sopenharmony_ci#include <unistd.h> 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci#include <sys/time.h> 59141cc406Sopenharmony_ci#include <sys/types.h> 60141cc406Sopenharmony_ci#include <sys/wait.h> 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci#include "../include/_stdint.h" 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci#include "../include/sane/sane.h" 65141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 66141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 67141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_ci#define BACKEND_NAME abaton 70141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci#ifndef PATH_MAX 73141cc406Sopenharmony_ci# define PATH_MAX 1024 74141cc406Sopenharmony_ci#endif 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 77141cc406Sopenharmony_ci#define ABATON_CONFIG_FILE "abaton.conf" 78141cc406Sopenharmony_ci 79141cc406Sopenharmony_ci#include "abaton.h" 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0; 84141cc406Sopenharmony_cistatic int num_devices; 85141cc406Sopenharmony_cistatic Abaton_Device *first_dev; 86141cc406Sopenharmony_cistatic Abaton_Scanner *first_handle; 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_cistatic SANE_String_Const mode_list[5]; 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_cistatic const SANE_String_Const halftone_pattern_list[] = 91141cc406Sopenharmony_ci{ 92141cc406Sopenharmony_ci "spiral", "bayer", 93141cc406Sopenharmony_ci 0 94141cc406Sopenharmony_ci}; 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_cistatic const SANE_Range dpi_range = 97141cc406Sopenharmony_ci{ 98141cc406Sopenharmony_ci /* min, max, quant */ 99141cc406Sopenharmony_ci 72, 100141cc406Sopenharmony_ci 300, 101141cc406Sopenharmony_ci 1 102141cc406Sopenharmony_ci}; 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_cistatic const SANE_Range enhance_range = 105141cc406Sopenharmony_ci{ 106141cc406Sopenharmony_ci 1, 107141cc406Sopenharmony_ci 255, 108141cc406Sopenharmony_ci 1 109141cc406Sopenharmony_ci}; 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_cistatic const SANE_Range x_range = 112141cc406Sopenharmony_ci{ 113141cc406Sopenharmony_ci 0, 114141cc406Sopenharmony_ci 8.5 * MM_PER_INCH, 115141cc406Sopenharmony_ci 1 116141cc406Sopenharmony_ci}; 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_cistatic const SANE_Range y_range = 119141cc406Sopenharmony_ci{ 120141cc406Sopenharmony_ci 0, 121141cc406Sopenharmony_ci 14.0 * MM_PER_INCH, 122141cc406Sopenharmony_ci 1 123141cc406Sopenharmony_ci}; 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_ci#define ERROR_MESSAGE 1 126141cc406Sopenharmony_ci#define USER_MESSAGE 5 127141cc406Sopenharmony_ci#define FLOW_CONTROL 50 128141cc406Sopenharmony_ci#define VARIABLE_CONTROL 70 129141cc406Sopenharmony_ci#define DEBUG_SPECIAL 100 130141cc406Sopenharmony_ci#define IO_MESSAGE 110 131141cc406Sopenharmony_ci#define INNER_LOOP 120 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci/* SCSI commands that the Abaton scanners understand: */ 135141cc406Sopenharmony_ci#define TEST_UNIT_READY 0x00 136141cc406Sopenharmony_ci#define REQUEST_SENSE 0x03 137141cc406Sopenharmony_ci#define INQUIRY 0x12 138141cc406Sopenharmony_ci#define START_STOP 0x1b 139141cc406Sopenharmony_ci#define SET_WINDOW 0x24 140141cc406Sopenharmony_ci#define READ_10 0x28 141141cc406Sopenharmony_ci#define WRITE_10 0x2b /* not used, AFAIK */ 142141cc406Sopenharmony_ci#define GET_DATA_STATUS 0x34 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ci 145141cc406Sopenharmony_ci#define INQ_LEN 0x60 146141cc406Sopenharmony_cistatic const uint8_t inquiry[] = 147141cc406Sopenharmony_ci{ 148141cc406Sopenharmony_ci INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00 149141cc406Sopenharmony_ci}; 150141cc406Sopenharmony_ci 151141cc406Sopenharmony_cistatic const uint8_t test_unit_ready[] = 152141cc406Sopenharmony_ci{ 153141cc406Sopenharmony_ci TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00 154141cc406Sopenharmony_ci}; 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci/* convenience macros */ 157141cc406Sopenharmony_ci#define ENABLE(OPTION) s->opt[OPTION].cap &= ~SANE_CAP_INACTIVE 158141cc406Sopenharmony_ci#define DISABLE(OPTION) s->opt[OPTION].cap |= SANE_CAP_INACTIVE 159141cc406Sopenharmony_ci#define IS_ACTIVE(OPTION) (((s->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0) 160141cc406Sopenharmony_ci 161141cc406Sopenharmony_ci/* store an 8-bit-wide value at the location specified by ptr */ 162141cc406Sopenharmony_ci#define STORE8(ptr, val) (*((uint8_t *) ptr) = val) 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci/* store a 16-bit-wide value in network (big-endian) byte order */ 165141cc406Sopenharmony_ci#define STORE16(ptr, val) \ 166141cc406Sopenharmony_ci { \ 167141cc406Sopenharmony_ci *((uint8_t *) ptr) = (val >> 8) & 0xff; \ 168141cc406Sopenharmony_ci *((uint8_t *) ptr+1) = val & 0xff; \ 169141cc406Sopenharmony_ci } 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_ci/* store a 24-bit-wide value in network (big-endian) byte order */ 172141cc406Sopenharmony_ci#define STORE24(ptr, val) \ 173141cc406Sopenharmony_ci { \ 174141cc406Sopenharmony_ci *((uint8_t *) ptr) = (val >> 16) & 0xff; \ 175141cc406Sopenharmony_ci *((uint8_t *) ptr+1) = (val >> 8) & 0xff; \ 176141cc406Sopenharmony_ci *((uint8_t *) ptr+2) = val & 0xff; \ 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci/* store a 32-bit-wide value in network (big-endian) byte order */ 180141cc406Sopenharmony_ci#define STORE32(ptr, val) \ 181141cc406Sopenharmony_ci { \ 182141cc406Sopenharmony_ci *((uint8_t *) ptr) = (val >> 24) & 0xff; \ 183141cc406Sopenharmony_ci *((uint8_t *) ptr+1) = (val >> 16) & 0xff; \ 184141cc406Sopenharmony_ci *((uint8_t *) ptr+2) = (val >> 8) & 0xff; \ 185141cc406Sopenharmony_ci *((uint8_t *) ptr+3) = val & 0xff; \ 186141cc406Sopenharmony_ci } 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci/* retrieve a 24-bit-wide big-endian value at ptr */ 189141cc406Sopenharmony_ci#define GET24(ptr) \ 190141cc406Sopenharmony_ci (*((uint8_t *) ptr) << 16) + \ 191141cc406Sopenharmony_ci (*((uint8_t *) ptr+1) << 8) + \ 192141cc406Sopenharmony_ci (*((uint8_t *) ptr+2)) 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_cistatic SANE_Status 195141cc406Sopenharmony_ciwait_ready (int fd) 196141cc406Sopenharmony_ci{ 197141cc406Sopenharmony_ci#define MAX_WAITING_TIME 60 /* one minute, at most */ 198141cc406Sopenharmony_ci struct timeval now, start; 199141cc406Sopenharmony_ci SANE_Status status; 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci gettimeofday (&start, 0); 202141cc406Sopenharmony_ci 203141cc406Sopenharmony_ci while (1) 204141cc406Sopenharmony_ci { 205141cc406Sopenharmony_ci DBG (USER_MESSAGE, "wait_ready: sending TEST_UNIT_READY\n"); 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready), 208141cc406Sopenharmony_ci 0, 0); 209141cc406Sopenharmony_ci switch (status) 210141cc406Sopenharmony_ci { 211141cc406Sopenharmony_ci default: 212141cc406Sopenharmony_ci /* Ignore errors while waiting for scanner to become ready. 213141cc406Sopenharmony_ci Some SCSI drivers return EIO while the scanner is 214141cc406Sopenharmony_ci returning to the home position. */ 215141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "wait_ready: test unit ready failed (%s)\n", 216141cc406Sopenharmony_ci sane_strstatus (status)); 217141cc406Sopenharmony_ci /* fall through */ 218141cc406Sopenharmony_ci case SANE_STATUS_DEVICE_BUSY: 219141cc406Sopenharmony_ci gettimeofday (&now, 0); 220141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 221141cc406Sopenharmony_ci { 222141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "wait_ready: timed out after %ld seconds\n", 223141cc406Sopenharmony_ci (long) (now.tv_sec - start.tv_sec)); 224141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 225141cc406Sopenharmony_ci } 226141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 227141cc406Sopenharmony_ci break; 228141cc406Sopenharmony_ci 229141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 230141cc406Sopenharmony_ci return status; 231141cc406Sopenharmony_ci } 232141cc406Sopenharmony_ci } 233141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 234141cc406Sopenharmony_ci} 235141cc406Sopenharmony_ci 236141cc406Sopenharmony_cistatic SANE_Status 237141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char * result, void *arg) 238141cc406Sopenharmony_ci{ 239141cc406Sopenharmony_ci (void) scsi_fd; /* silence gcc */ 240141cc406Sopenharmony_ci (void) arg; /* silence gcc */ 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci switch (result[2] & 0x0F) 243141cc406Sopenharmony_ci { 244141cc406Sopenharmony_ci case 0: 245141cc406Sopenharmony_ci DBG (USER_MESSAGE, "Sense: No sense Error\n"); 246141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 247141cc406Sopenharmony_ci case 2: 248141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Scanner not ready\n"); 249141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 250141cc406Sopenharmony_ci case 4: 251141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Hardware Error. Read more...\n"); 252141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 253141cc406Sopenharmony_ci case 5: 254141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Illegal request\n"); 255141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 256141cc406Sopenharmony_ci case 6: 257141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Unit Attention (Wait until scanner " 258141cc406Sopenharmony_ci "boots)\n"); 259141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 260141cc406Sopenharmony_ci case 9: 261141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Vendor Unique. Read more...\n"); 262141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 263141cc406Sopenharmony_ci default: 264141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Unknown Sense Key. Read more...\n"); 265141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 266141cc406Sopenharmony_ci } 267141cc406Sopenharmony_ci 268141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 269141cc406Sopenharmony_ci} 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_cistatic SANE_Status 272141cc406Sopenharmony_cirequest_sense (Abaton_Scanner * s) 273141cc406Sopenharmony_ci{ 274141cc406Sopenharmony_ci uint8_t cmd[6]; 275141cc406Sopenharmony_ci uint8_t result[22]; 276141cc406Sopenharmony_ci size_t size = sizeof (result); 277141cc406Sopenharmony_ci SANE_Status status; 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 280141cc406Sopenharmony_ci memset (result, 0, sizeof (result)); 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_ci cmd[0] = REQUEST_SENSE; 283141cc406Sopenharmony_ci STORE8 (cmd + 4, sizeof (result)); 284141cc406Sopenharmony_ci sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), result, &size); 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci if (result[7] != 14) 287141cc406Sopenharmony_ci { 288141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Additional Length %u\n", (unsigned int) result[7]); 289141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 290141cc406Sopenharmony_ci } 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci status = sense_handler (s->fd, result, NULL); 294141cc406Sopenharmony_ci if (status == SANE_STATUS_IO_ERROR) 295141cc406Sopenharmony_ci { 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci /* Since I haven't figured out the vendor unique error codes on 298141cc406Sopenharmony_ci this thing, I'll just handle the normal ones for now */ 299141cc406Sopenharmony_ci 300141cc406Sopenharmony_ci if (result[18] & 0x80) 301141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: Dim Light (output of lamp below 70%%).\n"); 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_ci if (result[18] & 0x40) 304141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: No Light at all.\n"); 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci if (result[18] & 0x20) 307141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: No Home.\n"); 308141cc406Sopenharmony_ci 309141cc406Sopenharmony_ci if (result[18] & 0x10) 310141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Sense: No Limit. Tried to scan out of range.\n"); 311141cc406Sopenharmony_ci } 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci DBG (USER_MESSAGE, "Sense: Optical gain %u.\n", (unsigned int) result[20]); 314141cc406Sopenharmony_ci return status; 315141cc406Sopenharmony_ci} 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_cistatic SANE_Status 318141cc406Sopenharmony_ciset_window (Abaton_Scanner * s) 319141cc406Sopenharmony_ci{ 320141cc406Sopenharmony_ci uint8_t cmd[10 + 40]; 321141cc406Sopenharmony_ci uint8_t *window = cmd + 10 + 8; 322141cc406Sopenharmony_ci int invert; 323141cc406Sopenharmony_ci 324141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 325141cc406Sopenharmony_ci cmd[0] = SET_WINDOW; 326141cc406Sopenharmony_ci cmd[8] = 40; 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci /* Just like the Apple scanners, we put the resolution here */ 329141cc406Sopenharmony_ci STORE16 (window + 2, s->val[OPT_X_RESOLUTION].w); 330141cc406Sopenharmony_ci STORE16 (window + 4, s->val[OPT_Y_RESOLUTION].w); 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci /* Unlike Apple scanners, these are pixel values */ 333141cc406Sopenharmony_ci STORE16 (window + 6, s->ULx); 334141cc406Sopenharmony_ci STORE16 (window + 8, s->ULy); 335141cc406Sopenharmony_ci STORE16 (window + 10, s->Width); 336141cc406Sopenharmony_ci STORE16 (window + 12, s->Height); 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci STORE8 (window + 14, s->val[OPT_BRIGHTNESS].w); 339141cc406Sopenharmony_ci STORE8 (window + 15, s->val[OPT_THRESHOLD].w); 340141cc406Sopenharmony_ci STORE8 (window + 16, s->val[OPT_CONTRAST].w); 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci invert = s->val[OPT_NEGATIVE].w; 343141cc406Sopenharmony_ci 344141cc406Sopenharmony_ci if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) 345141cc406Sopenharmony_ci { 346141cc406Sopenharmony_ci STORE8 (window + 17, 0); 347141cc406Sopenharmony_ci } 348141cc406Sopenharmony_ci else if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE)) 349141cc406Sopenharmony_ci { 350141cc406Sopenharmony_ci STORE8 (window + 17, 1); 351141cc406Sopenharmony_ci } 352141cc406Sopenharmony_ci else if (!strcmp (s->val[OPT_MODE].s, "Gray256") 353141cc406Sopenharmony_ci || !strcmp (s->val[OPT_MODE].s, "Gray16")) 354141cc406Sopenharmony_ci { 355141cc406Sopenharmony_ci STORE8 (window + 17, 2); 356141cc406Sopenharmony_ci invert = !s->val[OPT_NEGATIVE].w; 357141cc406Sopenharmony_ci } 358141cc406Sopenharmony_ci else 359141cc406Sopenharmony_ci { 360141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Can't match mode %s\n", s->val[OPT_MODE].s); 361141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 362141cc406Sopenharmony_ci } 363141cc406Sopenharmony_ci 364141cc406Sopenharmony_ci STORE8 (window + 18, s->bpp); 365141cc406Sopenharmony_ci 366141cc406Sopenharmony_ci if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "spiral")) 367141cc406Sopenharmony_ci { 368141cc406Sopenharmony_ci STORE8 (window + 20, 0); 369141cc406Sopenharmony_ci } 370141cc406Sopenharmony_ci else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "bayer")) 371141cc406Sopenharmony_ci { 372141cc406Sopenharmony_ci STORE8 (window + 20, 1); 373141cc406Sopenharmony_ci } 374141cc406Sopenharmony_ci else 375141cc406Sopenharmony_ci { 376141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Can't match haftone pattern %s\n", 377141cc406Sopenharmony_ci s->val[OPT_HALFTONE_PATTERN].s); 378141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 379141cc406Sopenharmony_ci } 380141cc406Sopenharmony_ci 381141cc406Sopenharmony_ci /* We have to invert these ones for some reason, so why not 382141cc406Sopenharmony_ci let the scanner do it for us... */ 383141cc406Sopenharmony_ci STORE8 (window + 21, invert ? 0x80 : 0); 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci STORE16 (window + 22, (s->val[OPT_MIRROR].w != 0)); 386141cc406Sopenharmony_ci 387141cc406Sopenharmony_ci return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0); 388141cc406Sopenharmony_ci} 389141cc406Sopenharmony_ci 390141cc406Sopenharmony_cistatic SANE_Status 391141cc406Sopenharmony_cistart_scan (Abaton_Scanner * s) 392141cc406Sopenharmony_ci{ 393141cc406Sopenharmony_ci SANE_Status status; 394141cc406Sopenharmony_ci uint8_t start[7]; 395141cc406Sopenharmony_ci 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci memset (start, 0, sizeof (start)); 398141cc406Sopenharmony_ci start[0] = START_STOP; 399141cc406Sopenharmony_ci start[4] = 1; 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, start, sizeof (start), 0, 0); 402141cc406Sopenharmony_ci return status; 403141cc406Sopenharmony_ci} 404141cc406Sopenharmony_ci 405141cc406Sopenharmony_cistatic SANE_Status 406141cc406Sopenharmony_ciattach (const char *devname, Abaton_Device ** devp, int may_wait) 407141cc406Sopenharmony_ci{ 408141cc406Sopenharmony_ci char result[INQ_LEN]; 409141cc406Sopenharmony_ci const char *model_name = result + 44; 410141cc406Sopenharmony_ci int fd, abaton_scanner; 411141cc406Sopenharmony_ci Abaton_Device *dev; 412141cc406Sopenharmony_ci SANE_Status status; 413141cc406Sopenharmony_ci size_t size; 414141cc406Sopenharmony_ci 415141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 416141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 417141cc406Sopenharmony_ci { 418141cc406Sopenharmony_ci if (devp) 419141cc406Sopenharmony_ci *devp = dev; 420141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 421141cc406Sopenharmony_ci } 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci DBG (USER_MESSAGE, "attach: opening %s\n", devname); 424141cc406Sopenharmony_ci status = sanei_scsi_open (devname, &fd, sense_handler, 0); 425141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 426141cc406Sopenharmony_ci { 427141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "attach: open failed (%s)\n", 428141cc406Sopenharmony_ci sane_strstatus (status)); 429141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 430141cc406Sopenharmony_ci } 431141cc406Sopenharmony_ci 432141cc406Sopenharmony_ci if (may_wait) 433141cc406Sopenharmony_ci wait_ready (fd); 434141cc406Sopenharmony_ci 435141cc406Sopenharmony_ci DBG (USER_MESSAGE, "attach: sending INQUIRY\n"); 436141cc406Sopenharmony_ci size = sizeof (result); 437141cc406Sopenharmony_ci status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size); 438141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 439141cc406Sopenharmony_ci { 440141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "attach: inquiry failed (%s)\n", 441141cc406Sopenharmony_ci sane_strstatus (status)); 442141cc406Sopenharmony_ci sanei_scsi_close (fd); 443141cc406Sopenharmony_ci return status; 444141cc406Sopenharmony_ci } 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci status = wait_ready (fd); 447141cc406Sopenharmony_ci sanei_scsi_close (fd); 448141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 449141cc406Sopenharmony_ci return status; 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci /* check that we've got an Abaton */ 452141cc406Sopenharmony_ci abaton_scanner = (strncmp (result + 8, "ABATON ", 8) == 0); 453141cc406Sopenharmony_ci model_name = result + 16; 454141cc406Sopenharmony_ci 455141cc406Sopenharmony_ci /* make sure it's a scanner ;-) */ 456141cc406Sopenharmony_ci abaton_scanner = abaton_scanner && (result[0] == 0x06); 457141cc406Sopenharmony_ci 458141cc406Sopenharmony_ci if (!abaton_scanner) 459141cc406Sopenharmony_ci { 460141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "attach: device doesn't look like an Abaton scanner " 461141cc406Sopenharmony_ci "(result[0]=%#02x)\n", result[0]); 462141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 463141cc406Sopenharmony_ci } 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 466141cc406Sopenharmony_ci if (!dev) 467141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 468141cc406Sopenharmony_ci 469141cc406Sopenharmony_ci memset (dev, 0, sizeof (*dev)); 470141cc406Sopenharmony_ci 471141cc406Sopenharmony_ci dev->sane.name = strdup (devname); 472141cc406Sopenharmony_ci dev->sane.vendor = "Abaton"; 473141cc406Sopenharmony_ci dev->sane.model = strndup (model_name, 16); 474141cc406Sopenharmony_ci dev->sane.type = "flatbed scanner"; 475141cc406Sopenharmony_ci 476141cc406Sopenharmony_ci if (!strncmp (model_name, "SCAN 300/GS", 11)) 477141cc406Sopenharmony_ci { 478141cc406Sopenharmony_ci dev->ScannerModel = ABATON_300GS; 479141cc406Sopenharmony_ci } 480141cc406Sopenharmony_ci else if (!strncmp (model_name, "SCAN 300/S", 10)) 481141cc406Sopenharmony_ci { 482141cc406Sopenharmony_ci dev->ScannerModel = ABATON_300S; 483141cc406Sopenharmony_ci } 484141cc406Sopenharmony_ci 485141cc406Sopenharmony_ci DBG (USER_MESSAGE, "attach: found Abaton scanner model %s (%s)\n", 486141cc406Sopenharmony_ci dev->sane.model, dev->sane.type); 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci ++num_devices; 489141cc406Sopenharmony_ci dev->next = first_dev; 490141cc406Sopenharmony_ci first_dev = dev; 491141cc406Sopenharmony_ci 492141cc406Sopenharmony_ci if (devp) 493141cc406Sopenharmony_ci *devp = dev; 494141cc406Sopenharmony_ci 495141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 496141cc406Sopenharmony_ci} 497141cc406Sopenharmony_ci 498141cc406Sopenharmony_cistatic SANE_Status 499141cc406Sopenharmony_ciattach_one (const char *devname) 500141cc406Sopenharmony_ci{ 501141cc406Sopenharmony_ci return attach (devname, 0, SANE_FALSE); 502141cc406Sopenharmony_ci} 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_cistatic SANE_Status 505141cc406Sopenharmony_cicalc_parameters (Abaton_Scanner * s) 506141cc406Sopenharmony_ci{ 507141cc406Sopenharmony_ci SANE_String val = s->val[OPT_MODE].s; 508141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 509141cc406Sopenharmony_ci SANE_Int dpix = s->val[OPT_X_RESOLUTION].w; 510141cc406Sopenharmony_ci SANE_Int dpiy = s->val[OPT_Y_RESOLUTION].w; 511141cc406Sopenharmony_ci double ulx, uly, width, height; 512141cc406Sopenharmony_ci 513141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "Entering calc_parameters\n"); 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) || !strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE)) 516141cc406Sopenharmony_ci { 517141cc406Sopenharmony_ci s->params.depth = 1; 518141cc406Sopenharmony_ci s->bpp = 1; 519141cc406Sopenharmony_ci } 520141cc406Sopenharmony_ci else if (!strcmp (val, "Gray16")) 521141cc406Sopenharmony_ci { 522141cc406Sopenharmony_ci s->params.depth = 8; 523141cc406Sopenharmony_ci s->bpp = 4; 524141cc406Sopenharmony_ci } 525141cc406Sopenharmony_ci else if (!strcmp (val, "Gray256")) 526141cc406Sopenharmony_ci { 527141cc406Sopenharmony_ci s->params.depth = 8; 528141cc406Sopenharmony_ci s->bpp = 8; 529141cc406Sopenharmony_ci } 530141cc406Sopenharmony_ci else 531141cc406Sopenharmony_ci { 532141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "calc_parameters: Invalid mode %s\n", (char *) val); 533141cc406Sopenharmony_ci status = SANE_STATUS_INVAL; 534141cc406Sopenharmony_ci } 535141cc406Sopenharmony_ci 536141cc406Sopenharmony_ci /* in inches */ 537141cc406Sopenharmony_ci ulx = (double) s->val[OPT_TL_X].w / MM_PER_INCH; 538141cc406Sopenharmony_ci uly = (double) s->val[OPT_TL_Y].w / MM_PER_INCH; 539141cc406Sopenharmony_ci width = (double) s->val[OPT_BR_X].w / MM_PER_INCH - ulx; 540141cc406Sopenharmony_ci height = (double) s->val[OPT_BR_Y].w / MM_PER_INCH - uly; 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "(inches) ulx: %f, uly: %f, width: %f, height: %f\n", 543141cc406Sopenharmony_ci ulx, uly, width, height); 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci /* turn 'em into pixel quantities */ 546141cc406Sopenharmony_ci s->ULx = ulx * dpix; 547141cc406Sopenharmony_ci s->ULy = uly * dpiy; 548141cc406Sopenharmony_ci s->Width = width * dpix; 549141cc406Sopenharmony_ci s->Height = height * dpiy; 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "(pixels) ulx: %d, uly: %d, width: %d, height: %d\n", 552141cc406Sopenharmony_ci s->ULx, s->ULy, s->Width, s->Height); 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci /* floor width to a byte multiple */ 555141cc406Sopenharmony_ci if ((s->Width * s->bpp) % 8) 556141cc406Sopenharmony_ci { 557141cc406Sopenharmony_ci s->Width /= 8; 558141cc406Sopenharmony_ci s->Width *= 8; 559141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "Adapting to width %d\n", s->Width); 560141cc406Sopenharmony_ci } 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci s->params.pixels_per_line = s->Width; 563141cc406Sopenharmony_ci s->params.lines = s->Height; 564141cc406Sopenharmony_ci s->params.bytes_per_line = s->params.pixels_per_line * s->params.depth / 8; 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "format=%d\n", s->params.format); 568141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "last_frame=%d\n", s->params.last_frame); 569141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "lines=%d\n", s->params.lines); 570141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "depth=%d (%d)\n", s->params.depth, s->bpp); 571141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "pixels_per_line=%d\n", s->params.pixels_per_line); 572141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "bytes_per_line=%d\n", s->params.bytes_per_line); 573141cc406Sopenharmony_ci DBG (VARIABLE_CONTROL, "Pixels %dx%dx%d\n", 574141cc406Sopenharmony_ci s->params.pixels_per_line, s->params.lines, 1 << s->params.depth); 575141cc406Sopenharmony_ci 576141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "Leaving calc_parameters\n"); 577141cc406Sopenharmony_ci return status; 578141cc406Sopenharmony_ci} 579141cc406Sopenharmony_ci 580141cc406Sopenharmony_cistatic SANE_Status 581141cc406Sopenharmony_cimode_update (SANE_Handle handle, char *val) 582141cc406Sopenharmony_ci{ 583141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_ci if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART)) 586141cc406Sopenharmony_ci { 587141cc406Sopenharmony_ci DISABLE (OPT_BRIGHTNESS); 588141cc406Sopenharmony_ci DISABLE (OPT_CONTRAST); 589141cc406Sopenharmony_ci ENABLE (OPT_THRESHOLD); 590141cc406Sopenharmony_ci DISABLE (OPT_HALFTONE_PATTERN); 591141cc406Sopenharmony_ci } 592141cc406Sopenharmony_ci else if (!strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE)) 593141cc406Sopenharmony_ci { 594141cc406Sopenharmony_ci ENABLE (OPT_BRIGHTNESS); 595141cc406Sopenharmony_ci ENABLE (OPT_CONTRAST); 596141cc406Sopenharmony_ci DISABLE (OPT_THRESHOLD); 597141cc406Sopenharmony_ci ENABLE (OPT_HALFTONE_PATTERN); 598141cc406Sopenharmony_ci } 599141cc406Sopenharmony_ci else if (!strcmp (val, "Gray16") || !strcmp (val, "Gray256")) 600141cc406Sopenharmony_ci { 601141cc406Sopenharmony_ci ENABLE (OPT_BRIGHTNESS); 602141cc406Sopenharmony_ci ENABLE (OPT_CONTRAST); 603141cc406Sopenharmony_ci DISABLE (OPT_THRESHOLD); 604141cc406Sopenharmony_ci DISABLE (OPT_HALFTONE_PATTERN); 605141cc406Sopenharmony_ci } /* End of Gray */ 606141cc406Sopenharmony_ci else 607141cc406Sopenharmony_ci { 608141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "Invalid mode %s\n", (char *) val); 609141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 610141cc406Sopenharmony_ci } 611141cc406Sopenharmony_ci 612141cc406Sopenharmony_ci calc_parameters (s); 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 615141cc406Sopenharmony_ci} 616141cc406Sopenharmony_ci 617141cc406Sopenharmony_ci/* find the longest of a list of strings */ 618141cc406Sopenharmony_cistatic size_t 619141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[]) 620141cc406Sopenharmony_ci{ 621141cc406Sopenharmony_ci size_t size, max_size = 0; 622141cc406Sopenharmony_ci int i; 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) 625141cc406Sopenharmony_ci { 626141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 627141cc406Sopenharmony_ci if (size > max_size) 628141cc406Sopenharmony_ci max_size = size; 629141cc406Sopenharmony_ci } 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_ci return max_size; 632141cc406Sopenharmony_ci} 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_cistatic SANE_Status 635141cc406Sopenharmony_ciinit_options (Abaton_Scanner * s) 636141cc406Sopenharmony_ci{ 637141cc406Sopenharmony_ci int i; 638141cc406Sopenharmony_ci 639141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 640141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 641141cc406Sopenharmony_ci 642141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 643141cc406Sopenharmony_ci { 644141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 645141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 646141cc406Sopenharmony_ci } 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 649141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 650141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 651141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 652141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 653141cc406Sopenharmony_ci 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci /* "Mode" group: */ 656141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 657141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 658141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 659141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 660141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci mode_list[0]=SANE_VALUE_SCAN_MODE_LINEART; 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci switch (s->hw->ScannerModel) 665141cc406Sopenharmony_ci { 666141cc406Sopenharmony_ci case ABATON_300GS: 667141cc406Sopenharmony_ci mode_list[1]=SANE_VALUE_SCAN_MODE_HALFTONE; 668141cc406Sopenharmony_ci mode_list[2]="Gray16"; 669141cc406Sopenharmony_ci mode_list[3]="Gray256"; 670141cc406Sopenharmony_ci mode_list[4]=NULL; 671141cc406Sopenharmony_ci break; 672141cc406Sopenharmony_ci case ABATON_300S: 673141cc406Sopenharmony_ci default: 674141cc406Sopenharmony_ci mode_list[1]=NULL; 675141cc406Sopenharmony_ci break; 676141cc406Sopenharmony_ci } 677141cc406Sopenharmony_ci 678141cc406Sopenharmony_ci /* scan mode */ 679141cc406Sopenharmony_ci s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 680141cc406Sopenharmony_ci s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 681141cc406Sopenharmony_ci s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 682141cc406Sopenharmony_ci s->opt[OPT_MODE].type = SANE_TYPE_STRING; 683141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 684141cc406Sopenharmony_ci s->opt[OPT_MODE].size = max_string_size (mode_list); 685141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list; 686141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[0]); 687141cc406Sopenharmony_ci 688141cc406Sopenharmony_ci /* resolution - horizontal */ 689141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 690141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_X_RESOLUTION; 691141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_X_RESOLUTION; 692141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT; 693141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI; 694141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 695141cc406Sopenharmony_ci s->opt[OPT_X_RESOLUTION].constraint.range = &dpi_range; 696141cc406Sopenharmony_ci s->val[OPT_X_RESOLUTION].w = 150; 697141cc406Sopenharmony_ci 698141cc406Sopenharmony_ci /* resolution - vertical */ 699141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION; 700141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION; 701141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION; 702141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT; 703141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI; 704141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 705141cc406Sopenharmony_ci s->opt[OPT_Y_RESOLUTION].constraint.range = &dpi_range; 706141cc406Sopenharmony_ci s->val[OPT_Y_RESOLUTION].w = 150; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci /* constrain resolutions */ 709141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND; 710141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND; 711141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND; 712141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL; 713141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].unit = SANE_UNIT_NONE; 714141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION_BIND].constraint_type = SANE_CONSTRAINT_NONE; 715141cc406Sopenharmony_ci /* until I fix it */ 716141cc406Sopenharmony_ci s->val[OPT_RESOLUTION_BIND].w = SANE_FALSE; 717141cc406Sopenharmony_ci 718141cc406Sopenharmony_ci /* preview mode */ 719141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; 720141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; 721141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; 722141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; 723141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; 724141cc406Sopenharmony_ci s->val[OPT_PREVIEW].w = SANE_FALSE; 725141cc406Sopenharmony_ci 726141cc406Sopenharmony_ci /* halftone pattern */ 727141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; 728141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; 729141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN; 730141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].size = max_string_size (halftone_pattern_list); 731141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING; 732141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; 733141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST; 734141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_pattern_list; 735141cc406Sopenharmony_ci s->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_pattern_list[0]); 736141cc406Sopenharmony_ci 737141cc406Sopenharmony_ci 738141cc406Sopenharmony_ci /* "Geometry" group: */ 739141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 740141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 741141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 742141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 743141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_ci /* top-left x */ 746141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 747141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 748141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 749141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_INT; 750141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 751141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 752141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &x_range; 753141cc406Sopenharmony_ci s->val[OPT_TL_X].w = 0; 754141cc406Sopenharmony_ci 755141cc406Sopenharmony_ci /* top-left y */ 756141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 757141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 758141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 759141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_INT; 760141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 761141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 762141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &y_range; 763141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = 0; 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci /* bottom-right x */ 766141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 767141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 768141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 769141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_INT; 770141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 771141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 772141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &x_range; 773141cc406Sopenharmony_ci s->val[OPT_BR_X].w = x_range.max; 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci /* bottom-right y */ 776141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 777141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 778141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 779141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_INT; 780141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 781141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 782141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &y_range; 783141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = y_range.max; 784141cc406Sopenharmony_ci 785141cc406Sopenharmony_ci 786141cc406Sopenharmony_ci /* "Enhancement" group: */ 787141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 788141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 789141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 790141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 791141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci /* brightness */ 794141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 795141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 796141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 797141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; 798141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; 799141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE; 800141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 801141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &enhance_range; 802141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = 150; 803141cc406Sopenharmony_ci 804141cc406Sopenharmony_ci /* contrast */ 805141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 806141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 807141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 808141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; 809141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; 810141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; 811141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 812141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &enhance_range; 813141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = 150; 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci /* threshold */ 816141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; 817141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; 818141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; 819141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT; 820141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE; 821141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; 822141cc406Sopenharmony_ci s->opt[OPT_THRESHOLD].constraint.range = &enhance_range; 823141cc406Sopenharmony_ci s->val[OPT_THRESHOLD].w = 150; 824141cc406Sopenharmony_ci 825141cc406Sopenharmony_ci /* negative */ 826141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].name = SANE_NAME_NEGATIVE; 827141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE; 828141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].desc = SANE_DESC_NEGATIVE; 829141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].type = SANE_TYPE_BOOL; 830141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].unit = SANE_UNIT_NONE; 831141cc406Sopenharmony_ci s->opt[OPT_NEGATIVE].constraint_type = SANE_CONSTRAINT_NONE; 832141cc406Sopenharmony_ci s->val[OPT_NEGATIVE].w = SANE_FALSE; 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci /* mirror-image */ 835141cc406Sopenharmony_ci s->opt[OPT_MIRROR].name = "mirror"; 836141cc406Sopenharmony_ci s->opt[OPT_MIRROR].title = "Mirror Image"; 837141cc406Sopenharmony_ci s->opt[OPT_MIRROR].desc = "Scan in mirror-image"; 838141cc406Sopenharmony_ci s->opt[OPT_MIRROR].type = SANE_TYPE_BOOL; 839141cc406Sopenharmony_ci s->opt[OPT_MIRROR].unit = SANE_UNIT_NONE; 840141cc406Sopenharmony_ci s->opt[OPT_MIRROR].constraint_type = SANE_CONSTRAINT_NONE; 841141cc406Sopenharmony_ci s->val[OPT_MIRROR].w = SANE_FALSE; 842141cc406Sopenharmony_ci 843141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 844141cc406Sopenharmony_ci} 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ciSANE_Status 847141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 848141cc406Sopenharmony_ci{ 849141cc406Sopenharmony_ci char dev_name[PATH_MAX]; 850141cc406Sopenharmony_ci size_t len; 851141cc406Sopenharmony_ci FILE *fp; 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_ci (void) authorize; /* silence gcc */ 854141cc406Sopenharmony_ci 855141cc406Sopenharmony_ci DBG_INIT (); 856141cc406Sopenharmony_ci 857141cc406Sopenharmony_ci if (version_code) 858141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 859141cc406Sopenharmony_ci 860141cc406Sopenharmony_ci fp = sanei_config_open (ABATON_CONFIG_FILE); 861141cc406Sopenharmony_ci if (!fp) 862141cc406Sopenharmony_ci { 863141cc406Sopenharmony_ci /* default to /dev/scanner instead of insisting on config file */ 864141cc406Sopenharmony_ci attach ("/dev/scanner", 0, SANE_FALSE); 865141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 866141cc406Sopenharmony_ci } 867141cc406Sopenharmony_ci 868141cc406Sopenharmony_ci while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 869141cc406Sopenharmony_ci { 870141cc406Sopenharmony_ci if (dev_name[0] == '#') /* ignore line comments */ 871141cc406Sopenharmony_ci continue; 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci len = strlen (dev_name); 874141cc406Sopenharmony_ci 875141cc406Sopenharmony_ci if (!len) 876141cc406Sopenharmony_ci continue; /* ignore empty lines */ 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci if (strncmp (dev_name, "option", 6) == 0 879141cc406Sopenharmony_ci && isspace (dev_name[6])) 880141cc406Sopenharmony_ci { 881141cc406Sopenharmony_ci const char *str = dev_name + 7; 882141cc406Sopenharmony_ci 883141cc406Sopenharmony_ci while (isspace (*str)) 884141cc406Sopenharmony_ci ++str; 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ci continue; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci 889141cc406Sopenharmony_ci sanei_config_attach_matching_devices (dev_name, attach_one); 890141cc406Sopenharmony_ci } 891141cc406Sopenharmony_ci fclose (fp); 892141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 893141cc406Sopenharmony_ci} 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_civoid 896141cc406Sopenharmony_cisane_exit (void) 897141cc406Sopenharmony_ci{ 898141cc406Sopenharmony_ci Abaton_Device *dev, *next; 899141cc406Sopenharmony_ci 900141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 901141cc406Sopenharmony_ci { 902141cc406Sopenharmony_ci next = dev->next; 903141cc406Sopenharmony_ci free ((void *) dev->sane.name); 904141cc406Sopenharmony_ci free ((void *) dev->sane.model); 905141cc406Sopenharmony_ci free (dev); 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci if (devlist) 909141cc406Sopenharmony_ci free (devlist); 910141cc406Sopenharmony_ci} 911141cc406Sopenharmony_ci 912141cc406Sopenharmony_ciSANE_Status 913141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 914141cc406Sopenharmony_ci{ 915141cc406Sopenharmony_ci Abaton_Device *dev; 916141cc406Sopenharmony_ci int i; 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_ci (void) local_only; /* silence gcc */ 919141cc406Sopenharmony_ci 920141cc406Sopenharmony_ci if (devlist) 921141cc406Sopenharmony_ci free (devlist); 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 924141cc406Sopenharmony_ci if (!devlist) 925141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci i = 0; 928141cc406Sopenharmony_ci for (dev = first_dev; i < num_devices; dev = dev->next) 929141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 930141cc406Sopenharmony_ci devlist[i++] = 0; 931141cc406Sopenharmony_ci 932141cc406Sopenharmony_ci *device_list = devlist; 933141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 934141cc406Sopenharmony_ci} 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ciSANE_Status 937141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle) 938141cc406Sopenharmony_ci{ 939141cc406Sopenharmony_ci Abaton_Device *dev; 940141cc406Sopenharmony_ci SANE_Status status; 941141cc406Sopenharmony_ci Abaton_Scanner *s; 942141cc406Sopenharmony_ci 943141cc406Sopenharmony_ci if (devicename[0]) 944141cc406Sopenharmony_ci { 945141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 946141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devicename) == 0) 947141cc406Sopenharmony_ci break; 948141cc406Sopenharmony_ci 949141cc406Sopenharmony_ci if (!dev) 950141cc406Sopenharmony_ci { 951141cc406Sopenharmony_ci status = attach (devicename, &dev, SANE_TRUE); 952141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 953141cc406Sopenharmony_ci return status; 954141cc406Sopenharmony_ci } 955141cc406Sopenharmony_ci } 956141cc406Sopenharmony_ci else 957141cc406Sopenharmony_ci /* empty devicname -> use first device */ 958141cc406Sopenharmony_ci dev = first_dev; 959141cc406Sopenharmony_ci 960141cc406Sopenharmony_ci if (!dev) 961141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 962141cc406Sopenharmony_ci 963141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 964141cc406Sopenharmony_ci if (!s) 965141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 966141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 967141cc406Sopenharmony_ci s->fd = -1; 968141cc406Sopenharmony_ci s->hw = dev; 969141cc406Sopenharmony_ci 970141cc406Sopenharmony_ci init_options (s); 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci /* set up some universal parameters */ 973141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 974141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 975141cc406Sopenharmony_ci 976141cc406Sopenharmony_ci /* insert newly opened handle into list of open handles: */ 977141cc406Sopenharmony_ci s->next = first_handle; 978141cc406Sopenharmony_ci first_handle = s; 979141cc406Sopenharmony_ci 980141cc406Sopenharmony_ci *handle = s; 981141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 982141cc406Sopenharmony_ci} 983141cc406Sopenharmony_ci 984141cc406Sopenharmony_civoid 985141cc406Sopenharmony_cisane_close (SANE_Handle handle) 986141cc406Sopenharmony_ci{ 987141cc406Sopenharmony_ci Abaton_Scanner *prev, *s; 988141cc406Sopenharmony_ci 989141cc406Sopenharmony_ci /* remove handle from list of open handles: */ 990141cc406Sopenharmony_ci prev = 0; 991141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 992141cc406Sopenharmony_ci { 993141cc406Sopenharmony_ci if (s == (Abaton_Scanner *) handle) 994141cc406Sopenharmony_ci break; 995141cc406Sopenharmony_ci prev = s; 996141cc406Sopenharmony_ci } 997141cc406Sopenharmony_ci if (!s) 998141cc406Sopenharmony_ci { 999141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "close: invalid handle %p\n", handle); 1000141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 1001141cc406Sopenharmony_ci } 1002141cc406Sopenharmony_ci 1003141cc406Sopenharmony_ci if (prev) 1004141cc406Sopenharmony_ci prev->next = s->next; 1005141cc406Sopenharmony_ci else 1006141cc406Sopenharmony_ci first_handle = s->next; 1007141cc406Sopenharmony_ci 1008141cc406Sopenharmony_ci free (handle); 1009141cc406Sopenharmony_ci} 1010141cc406Sopenharmony_ci 1011141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1012141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1013141cc406Sopenharmony_ci{ 1014141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1015141cc406Sopenharmony_ci 1016141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 1017141cc406Sopenharmony_ci return NULL; 1018141cc406Sopenharmony_ci 1019141cc406Sopenharmony_ci return s->opt + option; 1020141cc406Sopenharmony_ci} 1021141cc406Sopenharmony_ci 1022141cc406Sopenharmony_ciSANE_Status 1023141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 1024141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 1025141cc406Sopenharmony_ci{ 1026141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1027141cc406Sopenharmony_ci SANE_Status status; 1028141cc406Sopenharmony_ci SANE_Word cap; 1029141cc406Sopenharmony_ci 1030141cc406Sopenharmony_ci 1031141cc406Sopenharmony_ci if (option < 0 || option >= NUM_OPTIONS) 1032141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1033141cc406Sopenharmony_ci 1034141cc406Sopenharmony_ci if (info != NULL) 1035141cc406Sopenharmony_ci *info = 0; 1036141cc406Sopenharmony_ci 1037141cc406Sopenharmony_ci if (s->scanning) 1038141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 1039141cc406Sopenharmony_ci 1040141cc406Sopenharmony_ci cap = s->opt[option].cap; 1041141cc406Sopenharmony_ci 1042141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 1043141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1044141cc406Sopenharmony_ci 1045141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 1046141cc406Sopenharmony_ci { 1047141cc406Sopenharmony_ci switch (option) 1048141cc406Sopenharmony_ci { 1049141cc406Sopenharmony_ci /* word options: */ 1050141cc406Sopenharmony_ci case OPT_NUM_OPTS: 1051141cc406Sopenharmony_ci case OPT_X_RESOLUTION: 1052141cc406Sopenharmony_ci case OPT_Y_RESOLUTION: 1053141cc406Sopenharmony_ci case OPT_RESOLUTION_BIND: 1054141cc406Sopenharmony_ci case OPT_PREVIEW: 1055141cc406Sopenharmony_ci case OPT_TL_X: 1056141cc406Sopenharmony_ci case OPT_TL_Y: 1057141cc406Sopenharmony_ci case OPT_BR_X: 1058141cc406Sopenharmony_ci case OPT_BR_Y: 1059141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1060141cc406Sopenharmony_ci case OPT_CONTRAST: 1061141cc406Sopenharmony_ci case OPT_THRESHOLD: 1062141cc406Sopenharmony_ci case OPT_NEGATIVE: 1063141cc406Sopenharmony_ci case OPT_MIRROR: 1064141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option].w; 1065141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1066141cc406Sopenharmony_ci 1067141cc406Sopenharmony_ci /* string options */ 1068141cc406Sopenharmony_ci 1069141cc406Sopenharmony_ci case OPT_MODE: 1070141cc406Sopenharmony_ci case OPT_HALFTONE_PATTERN: 1071141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, s->val[option].s, 1072141cc406Sopenharmony_ci info); 1073141cc406Sopenharmony_ci strcpy (val, s->val[option].s); 1074141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1075141cc406Sopenharmony_ci } 1076141cc406Sopenharmony_ci } 1077141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 1078141cc406Sopenharmony_ci { 1079141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 1080141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1081141cc406Sopenharmony_ci 1082141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 1083141cc406Sopenharmony_ci 1084141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1085141cc406Sopenharmony_ci return status; 1086141cc406Sopenharmony_ci 1087141cc406Sopenharmony_ci 1088141cc406Sopenharmony_ci switch (option) 1089141cc406Sopenharmony_ci { 1090141cc406Sopenharmony_ci /* resolution should be uniform for previews, or when the 1091141cc406Sopenharmony_ci user says so. */ 1092141cc406Sopenharmony_ci case OPT_PREVIEW: 1093141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1094141cc406Sopenharmony_ci if (*(SANE_Word *) val) { 1095141cc406Sopenharmony_ci s->val[OPT_Y_RESOLUTION].w = s->val[OPT_X_RESOLUTION].w; 1096141cc406Sopenharmony_ci if (info) 1097141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1098141cc406Sopenharmony_ci } 1099141cc406Sopenharmony_ci /* always recalculate! */ 1100141cc406Sopenharmony_ci calc_parameters (s); 1101141cc406Sopenharmony_ci if (info) 1102141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1103141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1104141cc406Sopenharmony_ci 1105141cc406Sopenharmony_ci case OPT_RESOLUTION_BIND: 1106141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1107141cc406Sopenharmony_ci if (*(SANE_Word *) val) { 1108141cc406Sopenharmony_ci s->val[OPT_Y_RESOLUTION].w = s->val[OPT_X_RESOLUTION].w; 1109141cc406Sopenharmony_ci calc_parameters (s); 1110141cc406Sopenharmony_ci if (info) 1111141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | 1112141cc406Sopenharmony_ci SANE_INFO_RELOAD_OPTIONS; 1113141cc406Sopenharmony_ci } 1114141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1115141cc406Sopenharmony_ci 1116141cc406Sopenharmony_ci case OPT_X_RESOLUTION: 1117141cc406Sopenharmony_ci if (s->val[OPT_PREVIEW].w || s->val[OPT_RESOLUTION_BIND].w) { 1118141cc406Sopenharmony_ci s->val[OPT_Y_RESOLUTION].w = *(SANE_Word *)val; 1119141cc406Sopenharmony_ci if (info) 1120141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1121141cc406Sopenharmony_ci } 1122141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1123141cc406Sopenharmony_ci calc_parameters (s); 1124141cc406Sopenharmony_ci if (info) 1125141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1126141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1127141cc406Sopenharmony_ci 1128141cc406Sopenharmony_ci case OPT_Y_RESOLUTION: 1129141cc406Sopenharmony_ci if (s->val[OPT_PREVIEW].w || s->val[OPT_RESOLUTION_BIND].w) { 1130141cc406Sopenharmony_ci s->val[OPT_X_RESOLUTION].w = *(SANE_Word *)val; 1131141cc406Sopenharmony_ci if (info) 1132141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1133141cc406Sopenharmony_ci } 1134141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1135141cc406Sopenharmony_ci calc_parameters (s); 1136141cc406Sopenharmony_ci if (info) 1137141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1138141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci /* these ones don't have crazy side effects */ 1141141cc406Sopenharmony_ci case OPT_TL_X: 1142141cc406Sopenharmony_ci case OPT_TL_Y: 1143141cc406Sopenharmony_ci case OPT_BR_Y: 1144141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1145141cc406Sopenharmony_ci calc_parameters (s); 1146141cc406Sopenharmony_ci if (info) 1147141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1148141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci /* this one is somewhat imprecise */ 1151141cc406Sopenharmony_ci case OPT_BR_X: 1152141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1153141cc406Sopenharmony_ci calc_parameters (s); 1154141cc406Sopenharmony_ci if (info) 1155141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS 1156141cc406Sopenharmony_ci | SANE_INFO_INEXACT; 1157141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_ci /* no side-effects whatsoever */ 1160141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1161141cc406Sopenharmony_ci case OPT_CONTRAST: 1162141cc406Sopenharmony_ci case OPT_THRESHOLD: 1163141cc406Sopenharmony_ci case OPT_NEGATIVE: 1164141cc406Sopenharmony_ci case OPT_MIRROR: 1165141cc406Sopenharmony_ci 1166141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1167141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1168141cc406Sopenharmony_ci 1169141cc406Sopenharmony_ci /* string options */ 1170141cc406Sopenharmony_ci case OPT_HALFTONE_PATTERN: 1171141cc406Sopenharmony_ci if (info) 1172141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1173141cc406Sopenharmony_ci if (s->val[option].s) 1174141cc406Sopenharmony_ci free (s->val[option].s); 1175141cc406Sopenharmony_ci s->val[option].s = strdup (val); 1176141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1177141cc406Sopenharmony_ci 1178141cc406Sopenharmony_ci case OPT_MODE: 1179141cc406Sopenharmony_ci status = mode_update (s, val); 1180141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1181141cc406Sopenharmony_ci return status; 1182141cc406Sopenharmony_ci if (s->val[option].s) 1183141cc406Sopenharmony_ci free (s->val[option].s); 1184141cc406Sopenharmony_ci s->val[option].s = strdup (val); 1185141cc406Sopenharmony_ci 1186141cc406Sopenharmony_ci if (info) 1187141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; 1188141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1189141cc406Sopenharmony_ci } /* End of switch */ 1190141cc406Sopenharmony_ci } /* End of SET_VALUE */ 1191141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1192141cc406Sopenharmony_ci} 1193141cc406Sopenharmony_ci 1194141cc406Sopenharmony_ciSANE_Status 1195141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 1196141cc406Sopenharmony_ci{ 1197141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1198141cc406Sopenharmony_ci 1199141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "Entering sane_get_parameters\n"); 1200141cc406Sopenharmony_ci calc_parameters (s); 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci 1203141cc406Sopenharmony_ci if (params) 1204141cc406Sopenharmony_ci *params = s->params; 1205141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1206141cc406Sopenharmony_ci} 1207141cc406Sopenharmony_ci 1208141cc406Sopenharmony_ciSANE_Status 1209141cc406Sopenharmony_cisane_start (SANE_Handle handle) 1210141cc406Sopenharmony_ci{ 1211141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1212141cc406Sopenharmony_ci SANE_Status status; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci /* First make sure we have a current parameter set. Some of the 1215141cc406Sopenharmony_ci parameters will be overwritten below, but that's OK. */ 1216141cc406Sopenharmony_ci 1217141cc406Sopenharmony_ci calc_parameters (s); 1218141cc406Sopenharmony_ci 1219141cc406Sopenharmony_ci if (s->fd < 0) 1220141cc406Sopenharmony_ci { 1221141cc406Sopenharmony_ci /* this is the first (and maybe only) pass... */ 1222141cc406Sopenharmony_ci 1223141cc406Sopenharmony_ci status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0); 1224141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1225141cc406Sopenharmony_ci { 1226141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "open: open of %s failed: %s\n", 1227141cc406Sopenharmony_ci s->hw->sane.name, sane_strstatus (status)); 1228141cc406Sopenharmony_ci return status; 1229141cc406Sopenharmony_ci } 1230141cc406Sopenharmony_ci } 1231141cc406Sopenharmony_ci 1232141cc406Sopenharmony_ci status = wait_ready (s->fd); 1233141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1234141cc406Sopenharmony_ci { 1235141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "open: wait_ready() failed: %s\n", 1236141cc406Sopenharmony_ci sane_strstatus (status)); 1237141cc406Sopenharmony_ci goto stop_scanner_and_return; 1238141cc406Sopenharmony_ci } 1239141cc406Sopenharmony_ci 1240141cc406Sopenharmony_ci status = request_sense (s); 1241141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1242141cc406Sopenharmony_ci { 1243141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "sane_start: request_sense revealed error: %s\n", 1244141cc406Sopenharmony_ci sane_strstatus (status)); 1245141cc406Sopenharmony_ci goto stop_scanner_and_return; 1246141cc406Sopenharmony_ci } 1247141cc406Sopenharmony_ci 1248141cc406Sopenharmony_ci status = set_window (s); 1249141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1250141cc406Sopenharmony_ci { 1251141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "open: set scan area command failed: %s\n", 1252141cc406Sopenharmony_ci sane_strstatus (status)); 1253141cc406Sopenharmony_ci goto stop_scanner_and_return; 1254141cc406Sopenharmony_ci } 1255141cc406Sopenharmony_ci 1256141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 1257141cc406Sopenharmony_ci s->AbortedByUser = SANE_FALSE; 1258141cc406Sopenharmony_ci 1259141cc406Sopenharmony_ci status = start_scan (s); 1260141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1261141cc406Sopenharmony_ci goto stop_scanner_and_return; 1262141cc406Sopenharmony_ci 1263141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1264141cc406Sopenharmony_ci 1265141cc406Sopenharmony_cistop_scanner_and_return: 1266141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1267141cc406Sopenharmony_ci s->AbortedByUser = SANE_FALSE; 1268141cc406Sopenharmony_ci return status; 1269141cc406Sopenharmony_ci} 1270141cc406Sopenharmony_ci 1271141cc406Sopenharmony_ciSANE_Status 1272141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, 1273141cc406Sopenharmony_ci SANE_Int * len) 1274141cc406Sopenharmony_ci{ 1275141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1276141cc406Sopenharmony_ci SANE_Status status; 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci uint8_t get_data_status[10]; 1279141cc406Sopenharmony_ci uint8_t read[10]; 1280141cc406Sopenharmony_ci 1281141cc406Sopenharmony_ci uint8_t result[12]; 1282141cc406Sopenharmony_ci size_t size; 1283141cc406Sopenharmony_ci SANE_Int data_av = 0; 1284141cc406Sopenharmony_ci SANE_Int data_length = 0; 1285141cc406Sopenharmony_ci SANE_Int offset = 0; 1286141cc406Sopenharmony_ci SANE_Int rread = 0; 1287141cc406Sopenharmony_ci SANE_Bool Pseudo8bit = SANE_FALSE; 1288141cc406Sopenharmony_ci 1289141cc406Sopenharmony_ci 1290141cc406Sopenharmony_ci *len = 0; 1291141cc406Sopenharmony_ci 1292141cc406Sopenharmony_ci /* don't let bogus read requests reach the scanner */ 1293141cc406Sopenharmony_ci /* this is a sub-optimal way of doing this, I'm sure */ 1294141cc406Sopenharmony_ci if (!s->scanning) 1295141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1296141cc406Sopenharmony_ci 1297141cc406Sopenharmony_ci if (!strcmp (s->val[OPT_MODE].s, "Gray16")) 1298141cc406Sopenharmony_ci Pseudo8bit = SANE_TRUE; 1299141cc406Sopenharmony_ci 1300141cc406Sopenharmony_ci memset (get_data_status, 0, sizeof (get_data_status)); 1301141cc406Sopenharmony_ci get_data_status[0] = GET_DATA_STATUS; 1302141cc406Sopenharmony_ci /* This means "block" for Apple scanners, it seems to be the same 1303141cc406Sopenharmony_ci for Abaton. The scanner will do non-blocking I/O, but I don't 1304141cc406Sopenharmony_ci want to go there right now. */ 1305141cc406Sopenharmony_ci get_data_status[1] = 1; 1306141cc406Sopenharmony_ci STORE8 (get_data_status + 8, sizeof (result)); 1307141cc406Sopenharmony_ci 1308141cc406Sopenharmony_ci memset (read, 0, sizeof (read)); 1309141cc406Sopenharmony_ci read[0] = READ_10; 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_ci do 1312141cc406Sopenharmony_ci { 1313141cc406Sopenharmony_ci size = sizeof (result); 1314141cc406Sopenharmony_ci /* this isn't necessary */ 1315141cc406Sopenharmony_ci /* memset (result, 0, size); */ 1316141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, get_data_status, 1317141cc406Sopenharmony_ci sizeof (get_data_status), result, &size); 1318141cc406Sopenharmony_ci 1319141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1320141cc406Sopenharmony_ci return status; 1321141cc406Sopenharmony_ci if (!size) 1322141cc406Sopenharmony_ci { 1323141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "sane_read: cannot get_data_status.\n"); 1324141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1325141cc406Sopenharmony_ci } 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci /* this is not an accurate name, but oh well... */ 1328141cc406Sopenharmony_ci data_length = GET24 (result); 1329141cc406Sopenharmony_ci data_av = GET24 (result + 9); 1330141cc406Sopenharmony_ci 1331141cc406Sopenharmony_ci /* don't check result[3] here, because that screws things up 1332141cc406Sopenharmony_ci somewhat */ 1333141cc406Sopenharmony_ci if (data_length) { 1334141cc406Sopenharmony_ci DBG (IO_MESSAGE, 1335141cc406Sopenharmony_ci "sane_read: (status) Available in scanner buffer %u.\n", 1336141cc406Sopenharmony_ci data_av); 1337141cc406Sopenharmony_ci 1338141cc406Sopenharmony_ci if (Pseudo8bit) 1339141cc406Sopenharmony_ci { 1340141cc406Sopenharmony_ci if ((data_av * 2) + offset > max_len) 1341141cc406Sopenharmony_ci rread = (max_len - offset) / 2; 1342141cc406Sopenharmony_ci else 1343141cc406Sopenharmony_ci rread = data_av; 1344141cc406Sopenharmony_ci } 1345141cc406Sopenharmony_ci else if (data_av + offset > max_len) 1346141cc406Sopenharmony_ci { 1347141cc406Sopenharmony_ci rread = max_len - offset; 1348141cc406Sopenharmony_ci } 1349141cc406Sopenharmony_ci else 1350141cc406Sopenharmony_ci { 1351141cc406Sopenharmony_ci rread = data_av; 1352141cc406Sopenharmony_ci } 1353141cc406Sopenharmony_ci 1354141cc406Sopenharmony_ci DBG (IO_MESSAGE, 1355141cc406Sopenharmony_ci "sane_read: (action) Actual read request for %u bytes.\n", 1356141cc406Sopenharmony_ci rread); 1357141cc406Sopenharmony_ci 1358141cc406Sopenharmony_ci size = rread; 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci STORE24 (read + 6, rread); 1361141cc406Sopenharmony_ci 1362141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, read, sizeof (read), 1363141cc406Sopenharmony_ci buf + offset, &size); 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ci if (Pseudo8bit) 1366141cc406Sopenharmony_ci { 1367141cc406Sopenharmony_ci SANE_Int byte; 1368141cc406Sopenharmony_ci SANE_Int pos = offset + (rread << 1) - 1; 1369141cc406Sopenharmony_ci SANE_Byte B; 1370141cc406Sopenharmony_ci for (byte = offset + rread - 1; byte >= offset; byte--) 1371141cc406Sopenharmony_ci { 1372141cc406Sopenharmony_ci B = buf[byte]; 1373141cc406Sopenharmony_ci /* don't invert these! */ 1374141cc406Sopenharmony_ci buf[pos--] = B << 4; /* low (right) nibble */ 1375141cc406Sopenharmony_ci buf[pos--] = B & 0xF0; /* high (left) nibble */ 1376141cc406Sopenharmony_ci } 1377141cc406Sopenharmony_ci /* putting an end to bitop abuse here */ 1378141cc406Sopenharmony_ci offset += size * 2; 1379141cc406Sopenharmony_ci } 1380141cc406Sopenharmony_ci else 1381141cc406Sopenharmony_ci offset += size; 1382141cc406Sopenharmony_ci 1383141cc406Sopenharmony_ci DBG (IO_MESSAGE, "sane_read: Buffer %u of %u full %g%%\n", 1384141cc406Sopenharmony_ci offset, max_len, (double) (offset * 100. / max_len)); 1385141cc406Sopenharmony_ci } 1386141cc406Sopenharmony_ci } 1387141cc406Sopenharmony_ci while (offset < max_len && data_length != 0 && !s->AbortedByUser); 1388141cc406Sopenharmony_ci 1389141cc406Sopenharmony_ci if (s->AbortedByUser) 1390141cc406Sopenharmony_ci { 1391141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1392141cc406Sopenharmony_ci 1393141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1394141cc406Sopenharmony_ci { 1395141cc406Sopenharmony_ci DBG (ERROR_MESSAGE, "sane_read: request_sense revealed error: %s\n", 1396141cc406Sopenharmony_ci sane_strstatus (status)); 1397141cc406Sopenharmony_ci return status; 1398141cc406Sopenharmony_ci } 1399141cc406Sopenharmony_ci 1400141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, test_unit_ready, 1401141cc406Sopenharmony_ci sizeof (test_unit_ready), 0, 0); 1402141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD && status != SANE_STATUS_INVAL) 1403141cc406Sopenharmony_ci return status; 1404141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1405141cc406Sopenharmony_ci } 1406141cc406Sopenharmony_ci 1407141cc406Sopenharmony_ci if (!data_length) 1408141cc406Sopenharmony_ci { 1409141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1410141cc406Sopenharmony_ci DBG (IO_MESSAGE, "sane_read: (status) No more data..."); 1411141cc406Sopenharmony_ci if (!offset) 1412141cc406Sopenharmony_ci { 1413141cc406Sopenharmony_ci /* this shouldn't happen */ 1414141cc406Sopenharmony_ci *len = 0; 1415141cc406Sopenharmony_ci DBG (IO_MESSAGE, "EOF\n"); 1416141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1417141cc406Sopenharmony_ci } 1418141cc406Sopenharmony_ci else 1419141cc406Sopenharmony_ci { 1420141cc406Sopenharmony_ci *len = offset; 1421141cc406Sopenharmony_ci DBG (IO_MESSAGE, "GOOD\n"); 1422141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1423141cc406Sopenharmony_ci } 1424141cc406Sopenharmony_ci } 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci DBG (FLOW_CONTROL, 1428141cc406Sopenharmony_ci "sane_read: Normal Exiting, Aborted=%u, data_length=%u\n", 1429141cc406Sopenharmony_ci s->AbortedByUser, data_av); 1430141cc406Sopenharmony_ci *len = offset; 1431141cc406Sopenharmony_ci 1432141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1433141cc406Sopenharmony_ci} 1434141cc406Sopenharmony_ci 1435141cc406Sopenharmony_civoid 1436141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 1437141cc406Sopenharmony_ci{ 1438141cc406Sopenharmony_ci Abaton_Scanner *s = handle; 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci if (s->scanning) 1441141cc406Sopenharmony_ci { 1442141cc406Sopenharmony_ci if (s->AbortedByUser) 1443141cc406Sopenharmony_ci { 1444141cc406Sopenharmony_ci DBG (FLOW_CONTROL, 1445141cc406Sopenharmony_ci "sane_cancel: Already Aborted. Please Wait...\n"); 1446141cc406Sopenharmony_ci } 1447141cc406Sopenharmony_ci else 1448141cc406Sopenharmony_ci { 1449141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1450141cc406Sopenharmony_ci s->AbortedByUser = SANE_TRUE; 1451141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "sane_cancel: Signal Caught! Aborting...\n"); 1452141cc406Sopenharmony_ci } 1453141cc406Sopenharmony_ci } 1454141cc406Sopenharmony_ci else 1455141cc406Sopenharmony_ci { 1456141cc406Sopenharmony_ci if (s->AbortedByUser) 1457141cc406Sopenharmony_ci { 1458141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "sane_cancel: Scan has not been initiated yet." 1459141cc406Sopenharmony_ci "we probably received a signal while writing data.\n"); 1460141cc406Sopenharmony_ci s->AbortedByUser = SANE_FALSE; 1461141cc406Sopenharmony_ci } 1462141cc406Sopenharmony_ci else 1463141cc406Sopenharmony_ci { 1464141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "sane_cancel: Scan has not been initiated " 1465141cc406Sopenharmony_ci "yet (or it's over).\n"); 1466141cc406Sopenharmony_ci } 1467141cc406Sopenharmony_ci } 1468141cc406Sopenharmony_ci 1469141cc406Sopenharmony_ci return; 1470141cc406Sopenharmony_ci} 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ciSANE_Status 1473141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 1474141cc406Sopenharmony_ci{ 1475141cc406Sopenharmony_ci (void) handle; /* silence gcc */ 1476141cc406Sopenharmony_ci (void) non_blocking; /* silence gcc */ 1477141cc406Sopenharmony_ci 1478141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "sane_set_io_mode: Don't call me please. " 1479141cc406Sopenharmony_ci "Unimplemented function\n"); 1480141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1481141cc406Sopenharmony_ci} 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ciSANE_Status 1484141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 1485141cc406Sopenharmony_ci{ 1486141cc406Sopenharmony_ci (void) handle; /* silence gcc */ 1487141cc406Sopenharmony_ci (void) fd; /* silence gcc */ 1488141cc406Sopenharmony_ci 1489141cc406Sopenharmony_ci DBG (FLOW_CONTROL, "sane_get_select_fd: Don't call me please. " 1490141cc406Sopenharmony_ci "Unimplemented function\n"); 1491141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1492141cc406Sopenharmony_ci} 1493