1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1996, 1997 David Mosberger-Tang and Andreas Czechanowski, 3141cc406Sopenharmony_ci 1998 Andreas Bolsch for extension to ScanExpress models version 0.6, 4141cc406Sopenharmony_ci 2000-2005 Henning Meier-Geinitz, 5141cc406Sopenharmony_ci 2003 James Perry (600 EP). 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci This file implements a SANE backend for Mustek and some Trust flatbed 44141cc406Sopenharmony_ci scanners with SCSI, parallel port (600 EP) or proprietary interface. */ 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci/**************************************************************************/ 48141cc406Sopenharmony_ci/* Mustek backend version */ 49141cc406Sopenharmony_ci#define BUILD 138 50141cc406Sopenharmony_ci/**************************************************************************/ 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci#include "../include/sane/config.h" 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci#include <ctype.h> 55141cc406Sopenharmony_ci#include <errno.h> 56141cc406Sopenharmony_ci#include <fcntl.h> 57141cc406Sopenharmony_ci#include <limits.h> 58141cc406Sopenharmony_ci#include <signal.h> 59141cc406Sopenharmony_ci#include <stdio.h> 60141cc406Sopenharmony_ci#include <stdlib.h> 61141cc406Sopenharmony_ci#include <string.h> 62141cc406Sopenharmony_ci#include <unistd.h> 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci#include <sys/time.h> 65141cc406Sopenharmony_ci#include <sys/types.h> 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci#include "../include/_stdint.h" 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_ci#include "../include/sane/sane.h" 70141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 71141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 72141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 73141cc406Sopenharmony_ci#include "../include/sane/sanei_ab306.h" 74141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h" 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci#define BACKEND_NAME mustek 77141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 78141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci#include "mustek.h" 81141cc406Sopenharmony_ci#include "mustek_scsi_pp.h" 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci#ifndef SANE_I18N 84141cc406Sopenharmony_ci#define SANE_I18N(text) text 85141cc406Sopenharmony_ci#endif 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci/* Debug level from sanei_init_debug */ 88141cc406Sopenharmony_cistatic SANE_Int debug_level; 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_ci/* Maximum # of inches to scan in one swoop. 0 means "unlimited." 91141cc406Sopenharmony_ci This is here to be nice on the SCSI bus---Mustek scanners don't 92141cc406Sopenharmony_ci disconnect while scanning is in progress, which confuses some 93141cc406Sopenharmony_ci drivers that expect no reasonable SCSI request would take more than 94141cc406Sopenharmony_ci 10 seconds. That's not really true for Mustek scanners operating 95141cc406Sopenharmony_ci in certain modes, hence this limit. Usually you don't need to set it. */ 96141cc406Sopenharmony_cistatic double strip_height; 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci/* Should we wait for the scan slider to return after each scan? */ 99141cc406Sopenharmony_cistatic SANE_Bool force_wait; 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci/* Should we disable double buffering when reading data from the scanner? */ 102141cc406Sopenharmony_cistatic SANE_Bool disable_double_buffering; 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_cistatic SANE_Int num_devices; 105141cc406Sopenharmony_cistatic Mustek_Device *first_dev; 106141cc406Sopenharmony_cistatic Mustek_Scanner *first_handle; 107141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0; 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci/* Array of newly attached devices */ 110141cc406Sopenharmony_cistatic Mustek_Device **new_dev; 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci/* Length of new_dev array */ 113141cc406Sopenharmony_cistatic SANE_Int new_dev_len; 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci/* Number of entries allocated for new_dev */ 116141cc406Sopenharmony_cistatic SANE_Int new_dev_alloced; 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_cistatic SANE_Int lamp_off_time = 60; 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci/* Used for line-distance correction: */ 121141cc406Sopenharmony_cistatic const SANE_Int color_seq[] = { 122141cc406Sopenharmony_ci 1, 2, 0 /* green, blue, red */ 123141cc406Sopenharmony_ci}; 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_ci/* Which modes are supported? */ 126141cc406Sopenharmony_cistatic SANE_String_Const mode_list_paragon[] = { 127141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_LINEART, 128141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_HALFTONE, 129141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_GRAY, 130141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_COLOR, 131141cc406Sopenharmony_ci 0 132141cc406Sopenharmony_ci}; 133141cc406Sopenharmony_cistatic SANE_String_Const mode_list_se[] = { 134141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_LINEART, 135141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_GRAY, 136141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_COLOR, 137141cc406Sopenharmony_ci 0 138141cc406Sopenharmony_ci}; 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_cistatic SANE_String_Const bit_depth_list_pro[] = { 141141cc406Sopenharmony_ci "8", "12", 142141cc406Sopenharmony_ci 0 143141cc406Sopenharmony_ci}; 144141cc406Sopenharmony_ci 145141cc406Sopenharmony_ci/* Some scanners support setting speed manually */ 146141cc406Sopenharmony_cistatic SANE_String_Const speed_list[] = { 147141cc406Sopenharmony_ci SANE_I18N ("Slowest"), SANE_I18N ("Slower"), SANE_I18N ("Normal"), 148141cc406Sopenharmony_ci SANE_I18N ("Faster"), SANE_I18N ("Fastest"), 149141cc406Sopenharmony_ci 0 150141cc406Sopenharmony_ci}; 151141cc406Sopenharmony_ci 152141cc406Sopenharmony_ci/* Which scan-sources are supported? */ 153141cc406Sopenharmony_cistatic const SANE_String_Const source_list[] = { 154141cc406Sopenharmony_ci SANE_I18N ("Flatbed"), 155141cc406Sopenharmony_ci 0 156141cc406Sopenharmony_ci}; 157141cc406Sopenharmony_cistatic SANE_String_Const adf_source_list[] = { 158141cc406Sopenharmony_ci SANE_I18N ("Flatbed"), SANE_I18N ("Automatic Document Feeder"), 159141cc406Sopenharmony_ci 0 160141cc406Sopenharmony_ci}; 161141cc406Sopenharmony_cistatic SANE_String_Const ta_source_list[] = { 162141cc406Sopenharmony_ci SANE_I18N ("Flatbed"), SANE_I18N ("Transparency Adapter"), 163141cc406Sopenharmony_ci 0 164141cc406Sopenharmony_ci}; 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_ci/* Range used for gamma and halftone pattern */ 167141cc406Sopenharmony_cistatic const SANE_Range u8_range = { 168141cc406Sopenharmony_ci 0, /* minimum */ 169141cc406Sopenharmony_ci 255, /* maximum */ 170141cc406Sopenharmony_ci 0 /* quantization */ 171141cc406Sopenharmony_ci}; 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci/* Which kind of halftone patterns are available? */ 174141cc406Sopenharmony_cistatic SANE_String_Const halftone_list[] = { 175141cc406Sopenharmony_ci SANE_I18N ("8x8 coarse"), SANE_I18N ("8x8 normal"), SANE_I18N ("8x8 fine"), 176141cc406Sopenharmony_ci SANE_I18N ("8x8 very fine"), SANE_I18N ("6x6 normal"), 177141cc406Sopenharmony_ci SANE_I18N ("5x5 coarse"), SANE_I18N ("5x5 fine"), SANE_I18N ("4x4 coarse"), 178141cc406Sopenharmony_ci SANE_I18N ("4x4 normal"), SANE_I18N ("4x4 fine"), SANE_I18N ("3x3 normal"), 179141cc406Sopenharmony_ci SANE_I18N ("2x2 normal"), SANE_I18N ("8x8 custom"), 180141cc406Sopenharmony_ci SANE_I18N ("6x6 custom"), 181141cc406Sopenharmony_ci SANE_I18N ("5x5 custom"), SANE_I18N ("4x4 custom"), 182141cc406Sopenharmony_ci SANE_I18N ("3x3 custom"), 183141cc406Sopenharmony_ci SANE_I18N ("2x2 custom"), 184141cc406Sopenharmony_ci 0 185141cc406Sopenharmony_ci}; 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_ci/* Range used for brightness and contrast */ 188141cc406Sopenharmony_cistatic const SANE_Range percentage_range = { 189141cc406Sopenharmony_ci SANE_FIX(-100), /* minimum */ 190141cc406Sopenharmony_ci SANE_FIX(100), /* maximum */ 191141cc406Sopenharmony_ci SANE_FIX(1) /* quantization */ 192141cc406Sopenharmony_ci}; 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci/* SCSI command buffers used by the backend */ 195141cc406Sopenharmony_cistatic const SANE_Byte scsi_inquiry[] = { 196141cc406Sopenharmony_ci MUSTEK_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00 197141cc406Sopenharmony_ci}; 198141cc406Sopenharmony_cistatic const SANE_Byte scsi_test_unit_ready[] = { 199141cc406Sopenharmony_ci MUSTEK_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00 200141cc406Sopenharmony_ci}; 201141cc406Sopenharmony_cistatic const SANE_Byte scsi_request_sense[] = { 202141cc406Sopenharmony_ci MUSTEK_SCSI_REQUEST_SENSE, 0x00, 0x00, 0x00, 0x04, 0x00 203141cc406Sopenharmony_ci}; 204141cc406Sopenharmony_cistatic const SANE_Byte scsi_start_stop[] = { 205141cc406Sopenharmony_ci MUSTEK_SCSI_START_STOP, 0x00, 0x00, 0x00, 0x00, 0x00 206141cc406Sopenharmony_ci}; 207141cc406Sopenharmony_cistatic const SANE_Byte scsi_ccd_distance[] = { 208141cc406Sopenharmony_ci MUSTEK_SCSI_CCD_DISTANCE, 0x00, 0x00, 0x00, 0x05, 0x00 209141cc406Sopenharmony_ci}; 210141cc406Sopenharmony_cistatic const SANE_Byte scsi_get_image_status[] = { 211141cc406Sopenharmony_ci MUSTEK_SCSI_GET_IMAGE_STATUS, 0x00, 0x00, 0x00, 0x06, 0x00 212141cc406Sopenharmony_ci}; 213141cc406Sopenharmony_cistatic const SANE_Byte scsi_get_window[] = { 214141cc406Sopenharmony_ci MUSTEK_SCSI_GET_WINDOW, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00 215141cc406Sopenharmony_ci}; 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci/* Sizes for fixed-length, non-vendor-specific CDB formats (others are 0) */ 218141cc406Sopenharmony_ci#define CDB_SIZE(opcode) ((opcode) < 0x20 ? 6 : \ 219141cc406Sopenharmony_ci (opcode) < 0x60 ? 10 : \ 220141cc406Sopenharmony_ci (opcode) < 0x80 ? 0 : \ 221141cc406Sopenharmony_ci (opcode) < 0xa0 ? 16 : \ 222141cc406Sopenharmony_ci (opcode) < 0xc0 ? 12 : 0) 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_ci/* prototypes */ 225141cc406Sopenharmony_cistatic SANE_Status area_and_windows (Mustek_Scanner * s); 226141cc406Sopenharmony_cistatic SANE_Status inquiry (Mustek_Scanner * s); 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_ci/* Test if this machine is little endian (from coolscan.c) */ 229141cc406Sopenharmony_cistatic SANE_Bool 230141cc406Sopenharmony_cilittle_endian (void) 231141cc406Sopenharmony_ci{ 232141cc406Sopenharmony_ci SANE_Int testvalue = 255; 233141cc406Sopenharmony_ci uint8_t *firstbyte = (uint8_t *) & testvalue; 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci if (*firstbyte == 255) 236141cc406Sopenharmony_ci return SANE_TRUE; 237141cc406Sopenharmony_ci return SANE_FALSE; 238141cc406Sopenharmony_ci} 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci/* Used for Pro series. First value seems to be always 85, second one varies. 241141cc406Sopenharmony_ci First bit of second value clear == device ready (?) */ 242141cc406Sopenharmony_cistatic SANE_Status 243141cc406Sopenharmony_ciscsi_sense_wait_ready (Mustek_Scanner * s) 244141cc406Sopenharmony_ci{ 245141cc406Sopenharmony_ci struct timeval now, start; 246141cc406Sopenharmony_ci SANE_Status status; 247141cc406Sopenharmony_ci size_t len; 248141cc406Sopenharmony_ci SANE_Byte sense_buffer[4]; 249141cc406Sopenharmony_ci SANE_Byte bytetxt[300], dbgtxt[300], *pp; 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci gettimeofday (&start, 0); 252141cc406Sopenharmony_ci 253141cc406Sopenharmony_ci while (1) 254141cc406Sopenharmony_ci { 255141cc406Sopenharmony_ci len = sizeof (sense_buffer); 256141cc406Sopenharmony_ci 257141cc406Sopenharmony_ci DBG (5, "scsi_sense_wait_ready: command size = %ld, sense size = %ld\n", 258141cc406Sopenharmony_ci (long int) sizeof (scsi_request_sense), (long int) len); 259141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, scsi_request_sense, 260141cc406Sopenharmony_ci sizeof (scsi_request_sense), sense_buffer, 261141cc406Sopenharmony_ci &len); 262141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 263141cc406Sopenharmony_ci { 264141cc406Sopenharmony_ci DBG (1, "scsi_sense_wait_ready: failed: %s\n", 265141cc406Sopenharmony_ci sane_strstatus (status)); 266141cc406Sopenharmony_ci return status; 267141cc406Sopenharmony_ci } 268141cc406Sopenharmony_ci 269141cc406Sopenharmony_ci dbgtxt[0] = '\0'; 270141cc406Sopenharmony_ci for (pp = sense_buffer; pp < (sense_buffer + 4); pp++) 271141cc406Sopenharmony_ci { 272141cc406Sopenharmony_ci sprintf ((SANE_String) bytetxt, " %02x", *pp); 273141cc406Sopenharmony_ci strcat ((SANE_String) dbgtxt, (SANE_String) bytetxt); 274141cc406Sopenharmony_ci } 275141cc406Sopenharmony_ci DBG (5, "scsi_sense_wait_ready: sensebuffer: %s\n", dbgtxt); 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci if (!(sense_buffer[1] & 0x01)) 278141cc406Sopenharmony_ci { 279141cc406Sopenharmony_ci DBG (4, "scsi_sense_wait_ready: ok\n"); 280141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 281141cc406Sopenharmony_ci } 282141cc406Sopenharmony_ci else 283141cc406Sopenharmony_ci { 284141cc406Sopenharmony_ci gettimeofday (&now, 0); 285141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 286141cc406Sopenharmony_ci { 287141cc406Sopenharmony_ci DBG (1, "scsi_sense_wait_ready: timed out after %lu seconds\n", 288141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 289141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 290141cc406Sopenharmony_ci } 291141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 292141cc406Sopenharmony_ci } 293141cc406Sopenharmony_ci } 294141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 295141cc406Sopenharmony_ci} 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci/* Used for 3pass series */ 298141cc406Sopenharmony_cistatic SANE_Status 299141cc406Sopenharmony_ciscsi_area_wait_ready (Mustek_Scanner * s) 300141cc406Sopenharmony_ci{ 301141cc406Sopenharmony_ci struct timeval now, start; 302141cc406Sopenharmony_ci SANE_Status status; 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci gettimeofday (&start, 0); 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci DBG (5, "scsi_area_wait_ready\n"); 307141cc406Sopenharmony_ci while (1) 308141cc406Sopenharmony_ci { 309141cc406Sopenharmony_ci status = area_and_windows (s); 310141cc406Sopenharmony_ci switch (status) 311141cc406Sopenharmony_ci { 312141cc406Sopenharmony_ci default: 313141cc406Sopenharmony_ci /* Ignore errors while waiting for scanner to become ready. 314141cc406Sopenharmony_ci Some SCSI drivers return EIO while the scanner is 315141cc406Sopenharmony_ci returning to the home position. */ 316141cc406Sopenharmony_ci DBG (3, "scsi_area_wait_ready: failed (%s)\n", 317141cc406Sopenharmony_ci sane_strstatus (status)); 318141cc406Sopenharmony_ci /* fall through */ 319141cc406Sopenharmony_ci case SANE_STATUS_DEVICE_BUSY: 320141cc406Sopenharmony_ci gettimeofday (&now, 0); 321141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 322141cc406Sopenharmony_ci { 323141cc406Sopenharmony_ci DBG (1, "scsi_area_wait_ready: timed out after %lu seconds\n", 324141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 325141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 326141cc406Sopenharmony_ci } 327141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 328141cc406Sopenharmony_ci break; 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 331141cc406Sopenharmony_ci return status; 332141cc406Sopenharmony_ci } 333141cc406Sopenharmony_ci } 334141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 335141cc406Sopenharmony_ci} 336141cc406Sopenharmony_ci 337141cc406Sopenharmony_cistatic SANE_Status 338141cc406Sopenharmony_ciscsi_unit_wait_ready (Mustek_Scanner * s) 339141cc406Sopenharmony_ci{ 340141cc406Sopenharmony_ci struct timeval now, start; 341141cc406Sopenharmony_ci SANE_Status status; 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci gettimeofday (&start, 0); 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci while (1) 346141cc406Sopenharmony_ci { 347141cc406Sopenharmony_ci DBG (5, "scsi_unit_wait_ready: sending TEST_UNIT_READY\n"); 348141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, scsi_test_unit_ready, 349141cc406Sopenharmony_ci sizeof (scsi_test_unit_ready), 0, 0); 350141cc406Sopenharmony_ci DBG (5, "scsi_unit_wait_ready: TEST_UNIT_READY finished\n"); 351141cc406Sopenharmony_ci switch (status) 352141cc406Sopenharmony_ci { 353141cc406Sopenharmony_ci default: 354141cc406Sopenharmony_ci /* Ignore errors while waiting for scanner to become ready. 355141cc406Sopenharmony_ci Some SCSI drivers return EIO while the scanner is 356141cc406Sopenharmony_ci returning to the home position. */ 357141cc406Sopenharmony_ci DBG (3, "scsi_unit_wait_ready: test unit ready failed (%s)\n", 358141cc406Sopenharmony_ci sane_strstatus (status)); 359141cc406Sopenharmony_ci /* fall through */ 360141cc406Sopenharmony_ci case SANE_STATUS_DEVICE_BUSY: 361141cc406Sopenharmony_ci gettimeofday (&now, 0); 362141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 363141cc406Sopenharmony_ci { 364141cc406Sopenharmony_ci DBG (1, "scsi_unit_wait_ready: timed out after %lu seconds\n", 365141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 366141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 367141cc406Sopenharmony_ci } 368141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 369141cc406Sopenharmony_ci break; 370141cc406Sopenharmony_ci 371141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 372141cc406Sopenharmony_ci return status; 373141cc406Sopenharmony_ci } 374141cc406Sopenharmony_ci } 375141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 376141cc406Sopenharmony_ci} 377141cc406Sopenharmony_ci 378141cc406Sopenharmony_cistatic SANE_Status 379141cc406Sopenharmony_ciscsi_inquiry_wait_ready (Mustek_Scanner * s) 380141cc406Sopenharmony_ci{ 381141cc406Sopenharmony_ci struct timeval now, start; 382141cc406Sopenharmony_ci SANE_Status status; 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_ci gettimeofday (&start, 0); 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci while (1) 387141cc406Sopenharmony_ci { 388141cc406Sopenharmony_ci DBG (5, "scsi_inquiry_wait_ready: sending INQUIRY\n"); 389141cc406Sopenharmony_ci status = inquiry (s); 390141cc406Sopenharmony_ci DBG (5, "scsi_inquiry_wait_ready: INQUIRY finished\n"); 391141cc406Sopenharmony_ci switch (status) 392141cc406Sopenharmony_ci { 393141cc406Sopenharmony_ci default: 394141cc406Sopenharmony_ci /* Ignore errors while waiting for scanner to become ready. 395141cc406Sopenharmony_ci Some SCSI drivers return EIO while the scanner is 396141cc406Sopenharmony_ci returning to the home position. */ 397141cc406Sopenharmony_ci DBG (3, "scsi_unit_wait_ready: inquiry failed (%s)\n", 398141cc406Sopenharmony_ci sane_strstatus (status)); 399141cc406Sopenharmony_ci /* fall through */ 400141cc406Sopenharmony_ci case SANE_STATUS_DEVICE_BUSY: 401141cc406Sopenharmony_ci gettimeofday (&now, 0); 402141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 403141cc406Sopenharmony_ci { 404141cc406Sopenharmony_ci DBG (1, "scsi_unit_wait_ready: timed out after %lu seconds\n", 405141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 406141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 407141cc406Sopenharmony_ci } 408141cc406Sopenharmony_ci usleep (500000); /* retry after 500ms */ 409141cc406Sopenharmony_ci break; 410141cc406Sopenharmony_ci 411141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 412141cc406Sopenharmony_ci return status; 413141cc406Sopenharmony_ci } 414141cc406Sopenharmony_ci } 415141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 416141cc406Sopenharmony_ci} 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_cistatic SANE_Status 419141cc406Sopenharmony_cin_wait_ready (Mustek_Scanner * s) 420141cc406Sopenharmony_ci{ 421141cc406Sopenharmony_ci struct timeval now, start; 422141cc406Sopenharmony_ci SANE_Status status; 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci gettimeofday (&start, 0); 425141cc406Sopenharmony_ci 426141cc406Sopenharmony_ci DBG (5, "n_wait_ready\n"); 427141cc406Sopenharmony_ci while (1) 428141cc406Sopenharmony_ci { 429141cc406Sopenharmony_ci status = sanei_ab306_test_ready (s->fd); 430141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 431141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 432141cc406Sopenharmony_ci 433141cc406Sopenharmony_ci gettimeofday (&now, 0); 434141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 435141cc406Sopenharmony_ci { 436141cc406Sopenharmony_ci DBG (1, "n_wait_ready: timed out after %lu seconds\n", 437141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 438141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 439141cc406Sopenharmony_ci } 440141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 441141cc406Sopenharmony_ci } 442141cc406Sopenharmony_ci} 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_cistatic SANE_Status 445141cc406Sopenharmony_ciscsi_pp_wait_ready (Mustek_Scanner * s) 446141cc406Sopenharmony_ci{ 447141cc406Sopenharmony_ci struct timeval now, start; 448141cc406Sopenharmony_ci SANE_Status status; 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_ci gettimeofday (&start, 0); 451141cc406Sopenharmony_ci 452141cc406Sopenharmony_ci DBG (5, "scsi_pp_wait_ready\n"); 453141cc406Sopenharmony_ci while (1) 454141cc406Sopenharmony_ci { 455141cc406Sopenharmony_ci status = mustek_scsi_pp_test_ready (s->fd); 456141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 457141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_ci gettimeofday (&now, 0); 460141cc406Sopenharmony_ci if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) 461141cc406Sopenharmony_ci { 462141cc406Sopenharmony_ci DBG (1, "scsi_pp_wait_ready: timed out after %lu seconds\n", 463141cc406Sopenharmony_ci (u_long) (now.tv_sec - start.tv_sec)); 464141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 465141cc406Sopenharmony_ci } 466141cc406Sopenharmony_ci usleep (100000); /* retry after 100ms */ 467141cc406Sopenharmony_ci } 468141cc406Sopenharmony_ci} 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_cistatic SANE_Status 471141cc406Sopenharmony_cidev_wait_ready (Mustek_Scanner * s) 472141cc406Sopenharmony_ci{ 473141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 474141cc406Sopenharmony_ci return n_wait_ready (s); 475141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP) 476141cc406Sopenharmony_ci return scsi_pp_wait_ready (s); 477141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 478141cc406Sopenharmony_ci { 479141cc406Sopenharmony_ci SANE_Status status; 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci /* some 3-pass scanners seem to need the inquiry wait, too */ 482141cc406Sopenharmony_ci status = scsi_area_wait_ready (s); 483141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 484141cc406Sopenharmony_ci return status; 485141cc406Sopenharmony_ci return scsi_inquiry_wait_ready (s); 486141cc406Sopenharmony_ci } 487141cc406Sopenharmony_ci else if ((s->hw->flags & MUSTEK_FLAG_PARAGON_1) 488141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_PARAGON_2)) 489141cc406Sopenharmony_ci return scsi_inquiry_wait_ready (s); 490141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PRO) 491141cc406Sopenharmony_ci return scsi_sense_wait_ready (s); 492141cc406Sopenharmony_ci else 493141cc406Sopenharmony_ci return scsi_unit_wait_ready (s); 494141cc406Sopenharmony_ci} 495141cc406Sopenharmony_ci 496141cc406Sopenharmony_cistatic SANE_Status 497141cc406Sopenharmony_cidev_open (SANE_String_Const devname, Mustek_Scanner * s, 498141cc406Sopenharmony_ci SANEI_SCSI_Sense_Handler handler) 499141cc406Sopenharmony_ci{ 500141cc406Sopenharmony_ci SANE_Status status; 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci DBG (5, "dev_open %s\n", devname); 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED 505141cc406Sopenharmony_ci s->hw->buffer_size = s->hw->max_buffer_size; 506141cc406Sopenharmony_ci status = sanei_scsi_open_extended (devname, &s->fd, handler, 0, 507141cc406Sopenharmony_ci &s->hw->buffer_size); 508141cc406Sopenharmony_ci#else 509141cc406Sopenharmony_ci s->hw->buffer_size = MIN (sanei_scsi_max_request_size, 510141cc406Sopenharmony_ci s->hw->max_buffer_size); 511141cc406Sopenharmony_ci status = sanei_scsi_open (devname, &s->fd, handler, 0); 512141cc406Sopenharmony_ci#endif 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 515141cc406Sopenharmony_ci { 516141cc406Sopenharmony_ci DBG (3, "dev_open: %s is a SCSI device\n", devname); 517141cc406Sopenharmony_ci DBG (4, "dev_open: wanted %d kbytes, got %d kbytes buffer\n", 518141cc406Sopenharmony_ci s->hw->max_buffer_size / 1024, s->hw->buffer_size / 1024); 519141cc406Sopenharmony_ci if (s->hw->buffer_size < 4096) 520141cc406Sopenharmony_ci { 521141cc406Sopenharmony_ci DBG (1, "dev_open: sanei_scsi_open buffer too small\n"); 522141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 523141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 524141cc406Sopenharmony_ci } 525141cc406Sopenharmony_ci } 526141cc406Sopenharmony_ci else 527141cc406Sopenharmony_ci { 528141cc406Sopenharmony_ci DBG (3, "dev_open: %s: can't open %s as a SCSI device\n", 529141cc406Sopenharmony_ci sane_strstatus (status), devname); 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_ci status = sanei_ab306_open (devname, &s->fd); 532141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 533141cc406Sopenharmony_ci { 534141cc406Sopenharmony_ci s->hw->flags |= MUSTEK_FLAG_N; 535141cc406Sopenharmony_ci DBG (3, "dev_open: %s is an AB306N device\n", devname); 536141cc406Sopenharmony_ci } 537141cc406Sopenharmony_ci else 538141cc406Sopenharmony_ci { 539141cc406Sopenharmony_ci DBG (3, "dev_open: %s: can't open %s as an AB306N device\n", 540141cc406Sopenharmony_ci sane_strstatus (status), devname); 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci status = mustek_scsi_pp_open (devname, &s->fd); 543141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 544141cc406Sopenharmony_ci { 545141cc406Sopenharmony_ci s->hw->flags |= MUSTEK_FLAG_SCSI_PP; 546141cc406Sopenharmony_ci DBG (3, "dev_open: %s is a SCSI-over-parallel device\n", 547141cc406Sopenharmony_ci devname); 548141cc406Sopenharmony_ci } 549141cc406Sopenharmony_ci else 550141cc406Sopenharmony_ci { 551141cc406Sopenharmony_ci DBG (3, 552141cc406Sopenharmony_ci "dev_open: %s: can't open %s as a SCSI-over-parallel device\n", 553141cc406Sopenharmony_ci sane_strstatus (status), devname); 554141cc406Sopenharmony_ci DBG (1, "dev_open: can't open %s\n", devname); 555141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 556141cc406Sopenharmony_ci } 557141cc406Sopenharmony_ci } 558141cc406Sopenharmony_ci } 559141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 560141cc406Sopenharmony_ci} 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_cistatic SANE_Status 563141cc406Sopenharmony_cidev_cmd (Mustek_Scanner * s, const void *src, size_t src_size, 564141cc406Sopenharmony_ci void *dst, size_t * dst_size) 565141cc406Sopenharmony_ci{ 566141cc406Sopenharmony_ci SANE_Status status; 567141cc406Sopenharmony_ci SANE_Byte cmd_byte_list[50]; 568141cc406Sopenharmony_ci SANE_Byte cmd_byte[5]; 569141cc406Sopenharmony_ci const SANE_Byte *pp; 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci DBG (5, "dev_cmd: fd=%d, src=%p, src_size=%ld, dst=%p, dst_size=%ld\n", 572141cc406Sopenharmony_ci s->fd, src, (long int) src_size, dst, 573141cc406Sopenharmony_ci (long int) (dst_size ? *dst_size : 0)); 574141cc406Sopenharmony_ci 575141cc406Sopenharmony_ci if (src && (debug_level >= 5)) /* output data sent to SCSI device */ 576141cc406Sopenharmony_ci { 577141cc406Sopenharmony_ci cmd_byte_list[0] = '\0'; 578141cc406Sopenharmony_ci for (pp = (const SANE_Byte *) src; 579141cc406Sopenharmony_ci pp < (((const SANE_Byte *) src) + src_size); pp++) 580141cc406Sopenharmony_ci { 581141cc406Sopenharmony_ci sprintf ((SANE_String) cmd_byte, " %02x", *pp); 582141cc406Sopenharmony_ci strcat ((SANE_String) cmd_byte_list, (SANE_String) cmd_byte); 583141cc406Sopenharmony_ci if (((pp - (const SANE_Byte *) src) % 0x10 == 0x0f) 584141cc406Sopenharmony_ci || (pp >= (((const SANE_Byte *) src) + src_size - 1))) 585141cc406Sopenharmony_ci { 586141cc406Sopenharmony_ci DBG (5, "dev_cmd: sending: %s\n", cmd_byte_list); 587141cc406Sopenharmony_ci cmd_byte_list[0] = '\0'; 588141cc406Sopenharmony_ci } 589141cc406Sopenharmony_ci } 590141cc406Sopenharmony_ci } 591141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 592141cc406Sopenharmony_ci status = sanei_ab306_cmd (s->fd, src, src_size, dst, dst_size); 593141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP) 594141cc406Sopenharmony_ci status = mustek_scsi_pp_cmd (s->fd, src, src_size, dst, dst_size); 595141cc406Sopenharmony_ci else 596141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, src, src_size, dst, dst_size); 597141cc406Sopenharmony_ci 598141cc406Sopenharmony_ci if (dst && dst_size && (debug_level >= 5)) 599141cc406Sopenharmony_ci /* output data received from SCSI device */ 600141cc406Sopenharmony_ci { 601141cc406Sopenharmony_ci cmd_byte_list[0] = '\0'; 602141cc406Sopenharmony_ci for (pp = (const SANE_Byte *) dst; 603141cc406Sopenharmony_ci pp < (((const SANE_Byte *) dst) + *dst_size); pp++) 604141cc406Sopenharmony_ci { 605141cc406Sopenharmony_ci sprintf ((SANE_String) cmd_byte, " %02x", *pp); 606141cc406Sopenharmony_ci strcat ((SANE_String) cmd_byte_list, (SANE_String) cmd_byte); 607141cc406Sopenharmony_ci if (((pp - (const SANE_Byte *) dst) % 0x10 == 0x0f) 608141cc406Sopenharmony_ci || (pp >= (((const SANE_Byte *) dst) + *dst_size - 1))) 609141cc406Sopenharmony_ci { 610141cc406Sopenharmony_ci DBG (5, "dev_cmd: receiving: %s\n", cmd_byte_list); 611141cc406Sopenharmony_ci cmd_byte_list[0] = '\0'; 612141cc406Sopenharmony_ci } 613141cc406Sopenharmony_ci } 614141cc406Sopenharmony_ci } 615141cc406Sopenharmony_ci 616141cc406Sopenharmony_ci DBG (5, "dev_cmd: finished: dst_size=%ld, status=%s\n", 617141cc406Sopenharmony_ci (long int) (dst_size ? *dst_size : 0), sane_strstatus (status)); 618141cc406Sopenharmony_ci return status; 619141cc406Sopenharmony_ci} 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_cistatic SANE_Status 622141cc406Sopenharmony_cidev_req_wait (void *id) 623141cc406Sopenharmony_ci{ 624141cc406Sopenharmony_ci if (!id) 625141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 626141cc406Sopenharmony_ci else 627141cc406Sopenharmony_ci return sanei_scsi_req_wait (id); 628141cc406Sopenharmony_ci} 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_cistatic SANE_Status 631141cc406Sopenharmony_cidev_block_read_start (Mustek_Scanner * s, SANE_Int lines) 632141cc406Sopenharmony_ci{ 633141cc406Sopenharmony_ci DBG (4, "dev_block_read_start: entering block for %d lines\n", lines); 634141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 635141cc406Sopenharmony_ci { 636141cc406Sopenharmony_ci SANE_Byte readlines[6]; 637141cc406Sopenharmony_ci 638141cc406Sopenharmony_ci memset (readlines, 0, sizeof (readlines)); 639141cc406Sopenharmony_ci readlines[0] = MUSTEK_SCSI_READ_SCANNED_DATA; 640141cc406Sopenharmony_ci readlines[2] = (lines >> 16) & 0xff; 641141cc406Sopenharmony_ci readlines[3] = (lines >> 8) & 0xff; 642141cc406Sopenharmony_ci readlines[4] = (lines >> 0) & 0xff; 643141cc406Sopenharmony_ci return sanei_ab306_cmd (s->fd, readlines, sizeof (readlines), 0, 0); 644141cc406Sopenharmony_ci } 645141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP) 646141cc406Sopenharmony_ci { 647141cc406Sopenharmony_ci SANE_Byte readlines[6]; 648141cc406Sopenharmony_ci 649141cc406Sopenharmony_ci memset (readlines, 0, sizeof (readlines)); 650141cc406Sopenharmony_ci readlines[0] = MUSTEK_SCSI_READ_SCANNED_DATA; 651141cc406Sopenharmony_ci readlines[2] = (lines >> 16) & 0xff; 652141cc406Sopenharmony_ci readlines[3] = (lines >> 8) & 0xff; 653141cc406Sopenharmony_ci readlines[4] = (lines >> 0) & 0xff; 654141cc406Sopenharmony_ci return mustek_scsi_pp_cmd (s->fd, readlines, sizeof (readlines), 0, 0); 655141cc406Sopenharmony_ci } 656141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PARAGON_2) 657141cc406Sopenharmony_ci { 658141cc406Sopenharmony_ci SANE_Byte buffer[6]; 659141cc406Sopenharmony_ci size_t len; 660141cc406Sopenharmony_ci SANE_Int color; 661141cc406Sopenharmony_ci SANE_Status status; 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci /* reset line-distance values */ 664141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 665141cc406Sopenharmony_ci { 666141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 667141cc406Sopenharmony_ci { 668141cc406Sopenharmony_ci s->ld.index[color] = -s->ld.dist[color]; 669141cc406Sopenharmony_ci } 670141cc406Sopenharmony_ci s->ld.lmod3 = -1; 671141cc406Sopenharmony_ci s->ld.ld_line = 0; 672141cc406Sopenharmony_ci } 673141cc406Sopenharmony_ci 674141cc406Sopenharmony_ci /* Get image status (necessary to start new block) */ 675141cc406Sopenharmony_ci len = sizeof (buffer); 676141cc406Sopenharmony_ci status = dev_cmd (s, scsi_get_image_status, 677141cc406Sopenharmony_ci sizeof (scsi_get_image_status), buffer, &len); 678141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 679141cc406Sopenharmony_ci return status; 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_ci /* tell scanner how many lines to scan in one block */ 682141cc406Sopenharmony_ci memset (buffer, 0, sizeof (buffer)); 683141cc406Sopenharmony_ci buffer[0] = MUSTEK_SCSI_READ_SCANNED_DATA; 684141cc406Sopenharmony_ci buffer[2] = (lines >> 16) & 0xff; 685141cc406Sopenharmony_ci buffer[3] = (lines >> 8) & 0xff; 686141cc406Sopenharmony_ci buffer[4] = (lines >> 0) & 0xff; 687141cc406Sopenharmony_ci buffer[5] = 0x04; 688141cc406Sopenharmony_ci return sanei_scsi_cmd (s->fd, buffer, sizeof (buffer), 0, 0); 689141cc406Sopenharmony_ci } 690141cc406Sopenharmony_ci else 691141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 692141cc406Sopenharmony_ci} 693141cc406Sopenharmony_ci 694141cc406Sopenharmony_cistatic SANE_Status 695141cc406Sopenharmony_cidev_read_req_enter (Mustek_Scanner * s, SANE_Byte * buf, SANE_Int lines, 696141cc406Sopenharmony_ci SANE_Int bpl, size_t * lenp, void **idp, SANE_Int bank, 697141cc406Sopenharmony_ci SANE_Byte * command) 698141cc406Sopenharmony_ci{ 699141cc406Sopenharmony_ci *lenp = lines * bpl; 700141cc406Sopenharmony_ci 701141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 702141cc406Sopenharmony_ci { 703141cc406Sopenharmony_ci SANE_Int planes; 704141cc406Sopenharmony_ci 705141cc406Sopenharmony_ci *idp = 0; 706141cc406Sopenharmony_ci planes = (s->mode & MUSTEK_MODE_COLOR) ? 3 : 1; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci return sanei_ab306_rdata (s->fd, planes, buf, lines, bpl); 709141cc406Sopenharmony_ci } 710141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP) 711141cc406Sopenharmony_ci { 712141cc406Sopenharmony_ci SANE_Int planes; 713141cc406Sopenharmony_ci 714141cc406Sopenharmony_ci *idp = 0; 715141cc406Sopenharmony_ci planes = (s->mode & MUSTEK_MODE_COLOR) ? 3 : 1; 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci return mustek_scsi_pp_rdata (s->fd, planes, buf, lines, bpl); 718141cc406Sopenharmony_ci } 719141cc406Sopenharmony_ci else 720141cc406Sopenharmony_ci { 721141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_SE) 722141cc406Sopenharmony_ci { 723141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 724141cc406Sopenharmony_ci lines *= 3; 725141cc406Sopenharmony_ci 726141cc406Sopenharmony_ci memset (command, 0, 10); 727141cc406Sopenharmony_ci command[0] = MUSTEK_SCSI_READ_DATA; 728141cc406Sopenharmony_ci command[6] = bank; /* buffer bank not used ??? */ 729141cc406Sopenharmony_ci command[7] = (lines >> 8) & 0xff; 730141cc406Sopenharmony_ci command[8] = (lines >> 0) & 0xff; 731141cc406Sopenharmony_ci return sanei_scsi_req_enter (s->fd, command, 10, buf, lenp, idp); 732141cc406Sopenharmony_ci } 733141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PRO) 734141cc406Sopenharmony_ci { 735141cc406Sopenharmony_ci memset (command, 0, 6); 736141cc406Sopenharmony_ci command[0] = MUSTEK_SCSI_READ_SCANNED_DATA; 737141cc406Sopenharmony_ci command[2] = ((lines * bpl) >> 16) & 0xff; 738141cc406Sopenharmony_ci command[3] = ((lines * bpl) >> 8) & 0xff; 739141cc406Sopenharmony_ci command[4] = ((lines * bpl) >> 0) & 0xff; 740141cc406Sopenharmony_ci 741141cc406Sopenharmony_ci return sanei_scsi_req_enter (s->fd, command, 6, buf, lenp, idp); 742141cc406Sopenharmony_ci } 743141cc406Sopenharmony_ci else /* Paragon series */ 744141cc406Sopenharmony_ci { 745141cc406Sopenharmony_ci memset (command, 0, 6); 746141cc406Sopenharmony_ci command[0] = MUSTEK_SCSI_READ_SCANNED_DATA; 747141cc406Sopenharmony_ci command[2] = (lines >> 16) & 0xff; 748141cc406Sopenharmony_ci command[3] = (lines >> 8) & 0xff; 749141cc406Sopenharmony_ci command[4] = (lines >> 0) & 0xff; 750141cc406Sopenharmony_ci return sanei_scsi_req_enter (s->fd, command, 6, buf, lenp, idp); 751141cc406Sopenharmony_ci } 752141cc406Sopenharmony_ci } 753141cc406Sopenharmony_ci} 754141cc406Sopenharmony_ci 755141cc406Sopenharmony_cistatic void 756141cc406Sopenharmony_cidev_close (Mustek_Scanner * s) 757141cc406Sopenharmony_ci{ 758141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 759141cc406Sopenharmony_ci sanei_ab306_close (s->fd); 760141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP) 761141cc406Sopenharmony_ci mustek_scsi_pp_close (s->fd); 762141cc406Sopenharmony_ci else 763141cc406Sopenharmony_ci sanei_scsi_close (s->fd); 764141cc406Sopenharmony_ci} 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_cistatic SANE_Status 767141cc406Sopenharmony_cisense_handler (SANE_Int scsi_fd, SANE_Byte * result, void *arg) 768141cc406Sopenharmony_ci{ 769141cc406Sopenharmony_ci if (!result) 770141cc406Sopenharmony_ci { 771141cc406Sopenharmony_ci DBG (5, "sense_handler: no sense buffer\n"); 772141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci if (!arg) 775141cc406Sopenharmony_ci DBG (5, "sense_handler: got sense code %02x for fd %d (arg = null)\n", 776141cc406Sopenharmony_ci result[0], scsi_fd); 777141cc406Sopenharmony_ci else 778141cc406Sopenharmony_ci DBG (5, "sense_handler: got sense code %02x for fd %d (arg = %uc)\n", 779141cc406Sopenharmony_ci result[0], scsi_fd, *(SANE_Byte *) arg); 780141cc406Sopenharmony_ci switch (result[0]) 781141cc406Sopenharmony_ci { 782141cc406Sopenharmony_ci case 0x00: 783141cc406Sopenharmony_ci break; 784141cc406Sopenharmony_ci 785141cc406Sopenharmony_ci case 0x82: 786141cc406Sopenharmony_ci if (result[1] & 0x80) 787141cc406Sopenharmony_ci { 788141cc406Sopenharmony_ci DBG (3, "sense_handler: ADF is jammed\n"); 789141cc406Sopenharmony_ci return SANE_STATUS_JAMMED; /* ADF is jammed */ 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci break; 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci case 0x83: 794141cc406Sopenharmony_ci if (result[2] & 0x02) 795141cc406Sopenharmony_ci { 796141cc406Sopenharmony_ci DBG (3, "sense_handler: ADF is out of documents\n"); 797141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; /* ADF out of documents */ 798141cc406Sopenharmony_ci } 799141cc406Sopenharmony_ci break; 800141cc406Sopenharmony_ci 801141cc406Sopenharmony_ci case 0x84: 802141cc406Sopenharmony_ci if (result[1] & 0x10) 803141cc406Sopenharmony_ci { 804141cc406Sopenharmony_ci DBG (3, "sense_handler: transparency adapter cover open\n"); 805141cc406Sopenharmony_ci return SANE_STATUS_COVER_OPEN; /* open transparency adapter cover */ 806141cc406Sopenharmony_ci } 807141cc406Sopenharmony_ci break; 808141cc406Sopenharmony_ci 809141cc406Sopenharmony_ci default: 810141cc406Sopenharmony_ci DBG (1, "sense_handler: got unknown sense code %02x for fd %d\n", 811141cc406Sopenharmony_ci result[0], scsi_fd); 812141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 813141cc406Sopenharmony_ci } 814141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 815141cc406Sopenharmony_ci} 816141cc406Sopenharmony_ci 817141cc406Sopenharmony_cistatic SANE_Status 818141cc406Sopenharmony_ciinquiry (Mustek_Scanner * s) 819141cc406Sopenharmony_ci{ 820141cc406Sopenharmony_ci SANE_Byte result[INQ_LEN]; 821141cc406Sopenharmony_ci size_t size; 822141cc406Sopenharmony_ci SANE_Status status; 823141cc406Sopenharmony_ci 824141cc406Sopenharmony_ci DBG (5, "inquiry: sending INQUIRY\n"); 825141cc406Sopenharmony_ci size = sizeof (result); 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci memset (result, 0, size); 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci status = dev_cmd (s, scsi_inquiry, sizeof (scsi_inquiry), result, &size); 830141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 831141cc406Sopenharmony_ci return status; 832141cc406Sopenharmony_ci 833141cc406Sopenharmony_ci /* checking ADF status */ 834141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_ADF) 835141cc406Sopenharmony_ci { 836141cc406Sopenharmony_ci if (result[63] & (1 << 3)) 837141cc406Sopenharmony_ci { 838141cc406Sopenharmony_ci s->hw->flags |= MUSTEK_FLAG_ADF_READY; 839141cc406Sopenharmony_ci DBG (4, "inquiry: ADF ready\n"); 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci else 842141cc406Sopenharmony_ci { 843141cc406Sopenharmony_ci s->hw->flags &= ~MUSTEK_FLAG_ADF_READY; 844141cc406Sopenharmony_ci DBG (4, "inquiry: ADF not ready (out of paper)\n"); 845141cc406Sopenharmony_ci } 846141cc406Sopenharmony_ci } 847141cc406Sopenharmony_ci if (!result[0]) 848141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 849141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 850141cc406Sopenharmony_ci} 851141cc406Sopenharmony_ci 852141cc406Sopenharmony_cistatic SANE_Status 853141cc406Sopenharmony_ciparagon_2_get_adf_status (Mustek_Scanner * s) 854141cc406Sopenharmony_ci{ 855141cc406Sopenharmony_ci SANE_Status status; 856141cc406Sopenharmony_ci size_t len; 857141cc406Sopenharmony_ci SANE_Byte sense_buffer[4]; 858141cc406Sopenharmony_ci 859141cc406Sopenharmony_ci len = sizeof (sense_buffer); 860141cc406Sopenharmony_ci 861141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, scsi_request_sense, 862141cc406Sopenharmony_ci sizeof (scsi_request_sense), sense_buffer, &len); 863141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 864141cc406Sopenharmony_ci { 865141cc406Sopenharmony_ci DBG (1, "paragon_2_get_adf_status: %s\n", sane_strstatus (status)); 866141cc406Sopenharmony_ci return status; 867141cc406Sopenharmony_ci } 868141cc406Sopenharmony_ci DBG (5, "paragon_2_get_adf_status: sense_buffer: %x %x %x %x\n", 869141cc406Sopenharmony_ci sense_buffer[0], sense_buffer[1], sense_buffer[3], sense_buffer[3]); 870141cc406Sopenharmony_ci 871141cc406Sopenharmony_ci if (sense_buffer[0] == 0x00 && sense_buffer[1] == 0x00) 872141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 873141cc406Sopenharmony_ci 874141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 875141cc406Sopenharmony_ci} 876141cc406Sopenharmony_ci 877141cc406Sopenharmony_cistatic SANE_Bool 878141cc406Sopenharmony_cita_available_pro (Mustek_Scanner * s) 879141cc406Sopenharmony_ci{ 880141cc406Sopenharmony_ci SANE_Status status; 881141cc406Sopenharmony_ci size_t len; 882141cc406Sopenharmony_ci SANE_Byte sense_buffer[4]; 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci len = sizeof (sense_buffer); 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ci status = sanei_scsi_cmd (s->fd, scsi_request_sense, 887141cc406Sopenharmony_ci sizeof (scsi_request_sense), sense_buffer, &len); 888141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 889141cc406Sopenharmony_ci { 890141cc406Sopenharmony_ci DBG (1, "ta_available_pro: failed: %s\n", sane_strstatus (status)); 891141cc406Sopenharmony_ci return status; 892141cc406Sopenharmony_ci } 893141cc406Sopenharmony_ci DBG (5, "ta_available_pro: sense_buffer[2] = %x\n", sense_buffer[2]); 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_ci scsi_unit_wait_ready (s); 896141cc406Sopenharmony_ci if (sense_buffer[2] == 0x40) 897141cc406Sopenharmony_ci return SANE_TRUE; 898141cc406Sopenharmony_ci 899141cc406Sopenharmony_ci return SANE_FALSE; 900141cc406Sopenharmony_ci} 901141cc406Sopenharmony_ci 902141cc406Sopenharmony_cistatic SANE_Status 903141cc406Sopenharmony_ciattach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) 904141cc406Sopenharmony_ci{ 905141cc406Sopenharmony_ci SANE_Int mustek_scanner, fw_revision; 906141cc406Sopenharmony_ci SANE_Byte result[INQ_LEN]; 907141cc406Sopenharmony_ci SANE_Byte inquiry_byte_list[50], inquiry_text_list[17]; 908141cc406Sopenharmony_ci SANE_Byte inquiry_byte[5], inquiry_text[5]; 909141cc406Sopenharmony_ci SANE_Byte *model_name = result + 44; 910141cc406Sopenharmony_ci Mustek_Scanner s; 911141cc406Sopenharmony_ci Mustek_Device *dev, new_dev; 912141cc406Sopenharmony_ci SANE_Status status; 913141cc406Sopenharmony_ci size_t size; 914141cc406Sopenharmony_ci SANE_String scsi_device_type[] = { 915141cc406Sopenharmony_ci "Direct-Access", "Sequential-Access", "Printer", "Processor", 916141cc406Sopenharmony_ci "Write-Once", "CD-ROM", "Scanner", "Optical Memory", "Medium Changer", 917141cc406Sopenharmony_ci "Communications" 918141cc406Sopenharmony_ci }; 919141cc406Sopenharmony_ci SANE_Byte scsi_vendor[9]; 920141cc406Sopenharmony_ci SANE_Byte scsi_product[17]; 921141cc406Sopenharmony_ci SANE_Byte scsi_revision[5]; 922141cc406Sopenharmony_ci SANE_Byte *pp; 923141cc406Sopenharmony_ci SANE_Bool warning = SANE_FALSE; 924141cc406Sopenharmony_ci SANE_Int firmware_format = 0; 925141cc406Sopenharmony_ci SANE_Int firmware_revision_system = 0; 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci if (devp) 928141cc406Sopenharmony_ci *devp = 0; 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 931141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 932141cc406Sopenharmony_ci { 933141cc406Sopenharmony_ci if (devp) 934141cc406Sopenharmony_ci *devp = dev; 935141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 936141cc406Sopenharmony_ci } 937141cc406Sopenharmony_ci 938141cc406Sopenharmony_ci memset (&new_dev, 0, sizeof (new_dev)); 939141cc406Sopenharmony_ci memset (&s, 0, sizeof (s)); 940141cc406Sopenharmony_ci s.hw = &new_dev; 941141cc406Sopenharmony_ci s.hw->max_buffer_size = 8 * 1024; 942141cc406Sopenharmony_ci 943141cc406Sopenharmony_ci DBG (3, "attach: trying device %s\n", devname); 944141cc406Sopenharmony_ci 945141cc406Sopenharmony_ci status = dev_open (devname, &s, sense_handler); 946141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 947141cc406Sopenharmony_ci return status; 948141cc406Sopenharmony_ci 949141cc406Sopenharmony_ci if (may_wait || force_wait) 950141cc406Sopenharmony_ci dev_wait_ready (&s); 951141cc406Sopenharmony_ci 952141cc406Sopenharmony_ci DBG (5, "attach: sending INQUIRY\n"); 953141cc406Sopenharmony_ci size = sizeof (result); 954141cc406Sopenharmony_ci memset (result, 0, sizeof (result)); 955141cc406Sopenharmony_ci status = dev_cmd (&s, scsi_inquiry, sizeof (scsi_inquiry), result, &size); 956141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD || size != INQ_LEN) 957141cc406Sopenharmony_ci { 958141cc406Sopenharmony_ci DBG (1, "attach: inquiry for device %s failed (%s)\n", devname, 959141cc406Sopenharmony_ci sane_strstatus (status)); 960141cc406Sopenharmony_ci dev_close (&s); 961141cc406Sopenharmony_ci return status; 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci 964141cc406Sopenharmony_ci status = dev_wait_ready (&s); 965141cc406Sopenharmony_ci dev_close (&s); 966141cc406Sopenharmony_ci 967141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 968141cc406Sopenharmony_ci return status; 969141cc406Sopenharmony_ci 970141cc406Sopenharmony_ci if ((result[0] & 0x1f) != 0x06) 971141cc406Sopenharmony_ci { 972141cc406Sopenharmony_ci DBG (1, "attach: device %s doesn't look like a scanner at all (%d)\n", 973141cc406Sopenharmony_ci devname, result[0] & 0x1f); 974141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 975141cc406Sopenharmony_ci } 976141cc406Sopenharmony_ci 977141cc406Sopenharmony_ci if (debug_level >= 3) 978141cc406Sopenharmony_ci { 979141cc406Sopenharmony_ci /* clear spaces and special chars */ 980141cc406Sopenharmony_ci strncpy ((SANE_String) scsi_vendor, (SANE_String) result + 8, 8); 981141cc406Sopenharmony_ci scsi_vendor[8] = '\0'; 982141cc406Sopenharmony_ci pp = scsi_vendor + 7; 983141cc406Sopenharmony_ci while (pp >= scsi_vendor && (*pp == ' ' || *pp >= 127)) 984141cc406Sopenharmony_ci *pp-- = '\0'; 985141cc406Sopenharmony_ci strncpy ((SANE_String) scsi_product, (SANE_String) result + 16, 16); 986141cc406Sopenharmony_ci scsi_product[16] = '\0'; 987141cc406Sopenharmony_ci pp = scsi_product + 15; 988141cc406Sopenharmony_ci while (pp >= scsi_product && (*pp == ' ' || *pp >= 127)) 989141cc406Sopenharmony_ci *pp-- = '\0'; 990141cc406Sopenharmony_ci strncpy ((SANE_String) scsi_revision, (SANE_String) result + 32, 4); 991141cc406Sopenharmony_ci scsi_revision[4] = '\0'; 992141cc406Sopenharmony_ci pp = scsi_revision + 3; 993141cc406Sopenharmony_ci while (pp >= scsi_revision && (*pp == ' ' || *pp >= 127)) 994141cc406Sopenharmony_ci *pp-- = '\0'; 995141cc406Sopenharmony_ci DBG (3, "attach: SCSI Vendor: `%-8s' Model: `%-16s' Rev.: `%-4s'\n", 996141cc406Sopenharmony_ci scsi_vendor, scsi_product, scsi_revision); 997141cc406Sopenharmony_ci DBG (3, "attach: SCSI Type: %s; ANSI rev.: %d\n", 998141cc406Sopenharmony_ci ((result[0] & 0x1f) < 0x10) ? 999141cc406Sopenharmony_ci scsi_device_type[result[0] & 0x1f] : "Unknown", result[2] & 0x03); 1000141cc406Sopenharmony_ci DBG (3, "attach: SCSI flags: %s%s%s%s%s%s%s\n", 1001141cc406Sopenharmony_ci (result[7] & 0x80) ? "RelAdr " : "", 1002141cc406Sopenharmony_ci (result[7] & 0x40) ? "WBus32 " : "", 1003141cc406Sopenharmony_ci (result[7] & 0x20) ? "WBus16 " : "", 1004141cc406Sopenharmony_ci (result[7] & 0x10) ? "Sync " : "", 1005141cc406Sopenharmony_ci (result[7] & 0x08) ? "Linked " : "", 1006141cc406Sopenharmony_ci (result[7] & 0x02) ? "CmdQue " : "", 1007141cc406Sopenharmony_ci (result[7] & 0x01) ? "SftRe " : ""); 1008141cc406Sopenharmony_ci } 1009141cc406Sopenharmony_ci 1010141cc406Sopenharmony_ci if (debug_level >= 4) 1011141cc406Sopenharmony_ci { 1012141cc406Sopenharmony_ci /* print out inquiry */ 1013141cc406Sopenharmony_ci DBG (4, "attach: inquiry output:\n"); 1014141cc406Sopenharmony_ci inquiry_byte_list[0] = '\0'; 1015141cc406Sopenharmony_ci inquiry_text_list[0] = '\0'; 1016141cc406Sopenharmony_ci for (pp = result; pp < (result + INQ_LEN); pp++) 1017141cc406Sopenharmony_ci { 1018141cc406Sopenharmony_ci sprintf ((SANE_String) inquiry_text, "%c", 1019141cc406Sopenharmony_ci (*pp < 127) && (*pp > 31) ? *pp : '.'); 1020141cc406Sopenharmony_ci strcat ((SANE_String) inquiry_text_list, 1021141cc406Sopenharmony_ci (SANE_String) inquiry_text); 1022141cc406Sopenharmony_ci sprintf ((SANE_String) inquiry_byte, " %02x", *pp); 1023141cc406Sopenharmony_ci strcat ((SANE_String) inquiry_byte_list, 1024141cc406Sopenharmony_ci (SANE_String) inquiry_byte); 1025141cc406Sopenharmony_ci if ((pp - result) % 0x10 == 0x0f) 1026141cc406Sopenharmony_ci { 1027141cc406Sopenharmony_ci DBG (4, "%s %s\n", inquiry_byte_list, inquiry_text_list); 1028141cc406Sopenharmony_ci inquiry_byte_list[0] = '\0'; 1029141cc406Sopenharmony_ci inquiry_text_list[0] = '\0'; 1030141cc406Sopenharmony_ci } 1031141cc406Sopenharmony_ci } 1032141cc406Sopenharmony_ci } 1033141cc406Sopenharmony_ci 1034141cc406Sopenharmony_ci /* first check for new firmware format: */ 1035141cc406Sopenharmony_ci mustek_scanner = (strncmp ((SANE_String) result + 36, "MUSTEK", 6) == 0); 1036141cc406Sopenharmony_ci if (mustek_scanner) 1037141cc406Sopenharmony_ci { 1038141cc406Sopenharmony_ci if (result[43] == 'M') 1039141cc406Sopenharmony_ci { 1040141cc406Sopenharmony_ci DBG (3, "attach: found Mustek scanner (pro series firmware " 1041141cc406Sopenharmony_ci "format)\n"); 1042141cc406Sopenharmony_ci firmware_format = 2; 1043141cc406Sopenharmony_ci model_name = result + 43; 1044141cc406Sopenharmony_ci } 1045141cc406Sopenharmony_ci else 1046141cc406Sopenharmony_ci { 1047141cc406Sopenharmony_ci DBG (3, "attach: found Mustek scanner (new firmware format)\n"); 1048141cc406Sopenharmony_ci firmware_format = 1; 1049141cc406Sopenharmony_ci } 1050141cc406Sopenharmony_ci } 1051141cc406Sopenharmony_ci else 1052141cc406Sopenharmony_ci { 1053141cc406Sopenharmony_ci /* check for old format: */ 1054141cc406Sopenharmony_ci mustek_scanner = (strncmp ((SANE_String) result + 8, "MUSTEK", 6) == 0); 1055141cc406Sopenharmony_ci if (mustek_scanner) 1056141cc406Sopenharmony_ci { 1057141cc406Sopenharmony_ci model_name = result + 16; 1058141cc406Sopenharmony_ci DBG (3, "attach: found Mustek scanner (old firmware format)\n"); 1059141cc406Sopenharmony_ci firmware_format = 0; 1060141cc406Sopenharmony_ci } 1061141cc406Sopenharmony_ci else 1062141cc406Sopenharmony_ci { 1063141cc406Sopenharmony_ci /* Check for some non-Mustek scanners an print warning */ 1064141cc406Sopenharmony_ci if (strncmp ((SANE_String) result + 8, "Trust", 5) == 0) 1065141cc406Sopenharmony_ci DBG (1, "attach: this is a real Trust scanner. It is not " 1066141cc406Sopenharmony_ci " supported by this backend.\n"); 1067141cc406Sopenharmony_ci if (strncmp ((SANE_String) result + 8, "Aashima", 7) == 0) 1068141cc406Sopenharmony_ci DBG (1, "attach: this is an Aashima/Teco scanner. It is not " 1069141cc406Sopenharmony_ci " supported by this backend.\n"); 1070141cc406Sopenharmony_ci if (strncmp ((SANE_String) result + 16, "Flatbed Scanner", 15) == 0 1071141cc406Sopenharmony_ci && strncmp ((SANE_String) result + 42, "TECO", 4) == 0) 1072141cc406Sopenharmony_ci DBG (1, "attach: this is a Relysis/Teco scanner. It is not " 1073141cc406Sopenharmony_ci " supported by this backend.\n"); 1074141cc406Sopenharmony_ci DBG (1, "attach: device %s doesn't look like a Mustek scanner\n", 1075141cc406Sopenharmony_ci devname); 1076141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1077141cc406Sopenharmony_ci } 1078141cc406Sopenharmony_ci } 1079141cc406Sopenharmony_ci 1080141cc406Sopenharmony_ci /* get firmware revision as BCD number: */ 1081141cc406Sopenharmony_ci /* General format: x.yz */ 1082141cc406Sopenharmony_ci /* Newer ScanExpress scanners (ID XC06): Vxyz */ 1083141cc406Sopenharmony_ci if (result[33] == '.') 1084141cc406Sopenharmony_ci { 1085141cc406Sopenharmony_ci fw_revision = 1086141cc406Sopenharmony_ci (result[32] - '0') << 8 | (result[34] - '0') << 4 | (result[35] - 1087141cc406Sopenharmony_ci '0'); 1088141cc406Sopenharmony_ci firmware_revision_system = 0; 1089141cc406Sopenharmony_ci DBG (4, "attach: old firmware revision system\n"); 1090141cc406Sopenharmony_ci } 1091141cc406Sopenharmony_ci else 1092141cc406Sopenharmony_ci { 1093141cc406Sopenharmony_ci fw_revision = 1094141cc406Sopenharmony_ci (result[33] - '0') << 8 | (result[34] - '0') << 4 | (result[35] - 1095141cc406Sopenharmony_ci '0'); 1096141cc406Sopenharmony_ci firmware_revision_system = 1; 1097141cc406Sopenharmony_ci DBG (4, "attach: new firmware revision system\n"); 1098141cc406Sopenharmony_ci } 1099141cc406Sopenharmony_ci DBG (3, "attach: firmware revision %d.%02x\n", 1100141cc406Sopenharmony_ci fw_revision >> 8, fw_revision & 0xff); 1101141cc406Sopenharmony_ci 1102141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 1103141cc406Sopenharmony_ci if (!dev) 1104141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1105141cc406Sopenharmony_ci 1106141cc406Sopenharmony_ci memcpy (dev, &new_dev, sizeof (*dev)); 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_ci dev->name = strdup (devname); 1109141cc406Sopenharmony_ci if (!dev->name) 1110141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1111141cc406Sopenharmony_ci dev->sane.name = (SANE_String_Const) dev->name; 1112141cc406Sopenharmony_ci dev->sane.vendor = "Mustek"; 1113141cc406Sopenharmony_ci dev->sane.type = "flatbed scanner"; 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci dev->x_range.min = 0; 1116141cc406Sopenharmony_ci dev->y_range.min = 0; 1117141cc406Sopenharmony_ci dev->x_range.quant = 0; 1118141cc406Sopenharmony_ci dev->y_range.quant = 0; 1119141cc406Sopenharmony_ci dev->x_trans_range.min = 0; 1120141cc406Sopenharmony_ci dev->y_trans_range.min = 0; 1121141cc406Sopenharmony_ci /* default to something really small to be on the safe side: */ 1122141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (8.0 * MM_PER_INCH); 1123141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (5.0 * MM_PER_INCH); 1124141cc406Sopenharmony_ci dev->x_trans_range.quant = 0; 1125141cc406Sopenharmony_ci dev->y_trans_range.quant = 0; 1126141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (72); /* some scanners don't like low dpi */ 1127141cc406Sopenharmony_ci dev->dpi_range.quant = SANE_FIX (1); 1128141cc406Sopenharmony_ci /* default to 128 kB */ 1129141cc406Sopenharmony_ci dev->max_buffer_size = 128 * 1024; /* SCSI buffer -> use 64 k per buffer */ 1130141cc406Sopenharmony_ci dev->max_block_buffer_size = 1024 * 1024 * 1024; 1131141cc406Sopenharmony_ci dev->firmware_format = firmware_format; 1132141cc406Sopenharmony_ci dev->firmware_revision_system = firmware_revision_system; 1133141cc406Sopenharmony_ci 1134141cc406Sopenharmony_ci DBG (3, "attach: scanner id: %.11s\n", model_name); 1135141cc406Sopenharmony_ci if (strncmp ((SANE_String) model_name + 10, "PRO", 3) == 0) 1136141cc406Sopenharmony_ci DBG (3, "attach: this is probably a Paragon Pro series scanner\n"); 1137141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFC", 3) == 0) 1138141cc406Sopenharmony_ci DBG (3, "attach: this is probably a Paragon series II scanner\n"); 1139141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "M", 1) == 0) 1140141cc406Sopenharmony_ci DBG (3, 1141141cc406Sopenharmony_ci "attach: this is probably a Paragon series I or 3-pass scanner\n"); 1142141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, " C", 2) == 0) 1143141cc406Sopenharmony_ci DBG (3, "attach: this is probably a ScanExpress series A4 scanner\n"); 1144141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, " L", 2) == 0) 1145141cc406Sopenharmony_ci DBG (3, "attach: this is probably a ScanExpress series A3 scanner\n"); 1146141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "XC", 2) == 0) 1147141cc406Sopenharmony_ci DBG (3, 1148141cc406Sopenharmony_ci "attach: this is probably a ScanExpress Plus series A4 scanner\n"); 1149141cc406Sopenharmony_ci else 1150141cc406Sopenharmony_ci DBG (3, "attach: I am not sure what type of scanner this is\n"); 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci /* Paragon 3-pass series */ 1153141cc406Sopenharmony_ci if (strncmp ((SANE_String) model_name, "MFS-12000CX", 11) == 0) 1154141cc406Sopenharmony_ci { 1155141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1156141cc406Sopenharmony_ci driver. Tested with a Paragon MFS-12000CX v4.00 */ 1157141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1158141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1159141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1160141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (14.00 * MM_PER_INCH); 1161141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1162141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1163141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1164141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1165141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1166141cc406Sopenharmony_ci dev->sane.model = "MFS-12000CX"; 1167141cc406Sopenharmony_ci } 1168141cc406Sopenharmony_ci /* There are two different versions of the MFS-6000CX, one has the model 1169141cc406Sopenharmony_ci name "MFS-06000CX", the other one is "MSF-06000CZ" */ 1170141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-06000CX", 11) == 0) 1171141cc406Sopenharmony_ci { 1172141cc406Sopenharmony_ci /* These values were measured and tested with a Paragon MFS-6000CX 1173141cc406Sopenharmony_ci v4.06 */ 1174141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1175141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1176141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1177141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (13.86 * MM_PER_INCH); 1178141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1179141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (2.0); 1180141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (203.0); 1181141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1182141cc406Sopenharmony_ci 1183141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1184141cc406Sopenharmony_ci dev->sane.model = "MFS-6000CX"; 1185141cc406Sopenharmony_ci } 1186141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MSF-06000CZ", 11) == 0) 1187141cc406Sopenharmony_ci { 1188141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1189141cc406Sopenharmony_ci driver. Tested with a Paragon MFS-6000CX v4.00 */ 1190141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1191141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1192141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1193141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (13.85 * MM_PER_INCH); 1194141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1195141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (2.0); 1196141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1197141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1198141cc406Sopenharmony_ci 1199141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1200141cc406Sopenharmony_ci dev->sane.model = "MFS-6000CX"; 1201141cc406Sopenharmony_ci } 1202141cc406Sopenharmony_ci 1203141cc406Sopenharmony_ci /* Paragon 1-pass 14" series I */ 1204141cc406Sopenharmony_ci 1205141cc406Sopenharmony_ci /* I haven't seen a single report for this, but it is mentioned in 1206141cc406Sopenharmony_ci the old man page. All reported Paragon 1200SP had a model name 1207141cc406Sopenharmony_ci "MFS-12000SP" */ 1208141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MSF-12000SP", 11) == 0) 1209141cc406Sopenharmony_ci { 1210141cc406Sopenharmony_ci /* These values are not tested and mostly guessed. */ 1211141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1212141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (13.85 * MM_PER_INCH); 1213141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1214141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1215141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (200.0); 1216141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (250.0); 1217141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1218141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_NONE; 1219141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1220141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_USE_BLOCK; 1221141cc406Sopenharmony_ci dev->sane.model = "MFS-12000SP"; 1222141cc406Sopenharmony_ci warning = SANE_TRUE; 1223141cc406Sopenharmony_ci } 1224141cc406Sopenharmony_ci /* MFS-8000 SP v 1.x */ 1225141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MSF-08000SP", 11) == 0) 1226141cc406Sopenharmony_ci { 1227141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1228141cc406Sopenharmony_ci driver. Tested with a Paragon MFS-8000SP v1.20 */ 1229141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1230141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1231141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1232141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (355.6); 1233141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1234141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1235141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1236141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (800); 1239141cc406Sopenharmony_ci /* At least scanners with firmware 1.20 need a gamma table upload 1240141cc406Sopenharmony_ci in color mode, otherwise the image is red */ 1241141cc406Sopenharmony_ci if (fw_revision == 0x120) 1242141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_FORCE_GAMMA; 1243141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1244141cc406Sopenharmony_ci dev->sane.model = "MFS-8000SP"; 1245141cc406Sopenharmony_ci } 1246141cc406Sopenharmony_ci /* This model name exists */ 1247141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MSF-06000SP", 11) == 0) 1248141cc406Sopenharmony_ci { 1249141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1250141cc406Sopenharmony_ci driver. Tested with a Paragon MFS-6000SP v3.12 */ 1251141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1252141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1253141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1254141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (355.6); 1255141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1256141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1257141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1258141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1259141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1260141cc406Sopenharmony_ci /* Looks like at least some versions of this scanner produce black images 1261141cc406Sopenharmony_ci in gray and color mode if MUSTEK_FORCE_GAMMA is not set. At least 1262141cc406Sopenharmony_ci versions 2.01, 2.02 and 2.10 are reported as having this bug. 3.12 1263141cc406Sopenharmony_ci doesn't need this workaround but it doesn't harm either. */ 1264141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_FORCE_GAMMA; 1265141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1266141cc406Sopenharmony_ci dev->sane.model = "MFS-6000SP"; 1267141cc406Sopenharmony_ci } 1268141cc406Sopenharmony_ci 1269141cc406Sopenharmony_ci /* This one was reported multiple times */ 1270141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-12000SP", 11) == 0) 1271141cc406Sopenharmony_ci { 1272141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1273141cc406Sopenharmony_ci driver. Tested with a Paragon MFS-12000SP v1.02 and v1.00 */ 1274141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1275141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (217.0); 1276141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (2.0); 1277141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (352.0); 1278141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0.0); 1279141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0.0); 1280141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1281141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (250.0); 1282141cc406Sopenharmony_ci 1283141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1284141cc406Sopenharmony_ci /* Earlier versions of this source code used MUSTEK_FLAG_LD_MFS 1285141cc406Sopenharmony_ci for firmware versions < 1.02 and LD_NONE for the rest. This 1286141cc406Sopenharmony_ci didn't work for my scanners. 1.00 doesn't need any LD 1287141cc406Sopenharmony_ci correction, 1.02, 1.07 and 1.11 do need normal LD 1288141cc406Sopenharmony_ci corrections. Maybe all != 1.00 need normal LD */ 1289141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1290141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_BLOCK; 1291141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_USE_BLOCK; 1292141cc406Sopenharmony_ci dev->sane.model = "MFS-12000SP"; 1293141cc406Sopenharmony_ci } 1294141cc406Sopenharmony_ci /* MFS-8000 SP v2.x */ 1295141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-08000SP", 11) == 0) 1296141cc406Sopenharmony_ci { 1297141cc406Sopenharmony_ci /* These values are tested with a MFS-08000SP v 2.04 */ 1298141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1299141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1300141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1301141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (355.6); 1302141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1303141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1304141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1305141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1306141cc406Sopenharmony_ci 1307141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (800); 1308141cc406Sopenharmony_ci /* At least scanners with firmware 1.20 need a gamma table upload 1309141cc406Sopenharmony_ci in color mode, otherwise the image is red */ 1310141cc406Sopenharmony_ci if (fw_revision == 0x120) 1311141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_FORCE_GAMMA; 1312141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1313141cc406Sopenharmony_ci dev->sane.model = "MFS-8000SP"; 1314141cc406Sopenharmony_ci } 1315141cc406Sopenharmony_ci /* I have never seen one of those */ 1316141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-06000SP", 11) == 0) 1317141cc406Sopenharmony_ci { 1318141cc406Sopenharmony_ci /* These values are not tested. */ 1319141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); 1320141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (13.84 * MM_PER_INCH); 1321141cc406Sopenharmony_ci /* copied from MSF-06000SP */ 1322141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (1.0); 1323141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (1.0); 1324141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1325141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (255.0); 1326141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1327141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_1; 1328141cc406Sopenharmony_ci dev->sane.model = "MFS-6000SP"; 1329141cc406Sopenharmony_ci warning = SANE_TRUE; 1330141cc406Sopenharmony_ci } 1331141cc406Sopenharmony_ci 1332141cc406Sopenharmony_ci /* Paragon 1-pass A4 series II */ 1333141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFC-08000CZ", 11) == 0) 1334141cc406Sopenharmony_ci { 1335141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1336141cc406Sopenharmony_ci driver. Tested with a Paragon 800 II SP v1.06. */ 1337141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (1.5); 1338141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (218.0); 1339141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1340141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (293.0); 1341141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0.0); 1342141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0.0); 1343141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (205.0); 1344141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (254.0); 1345141cc406Sopenharmony_ci 1346141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (800); 1347141cc406Sopenharmony_ci dev->max_block_buffer_size = 2 * 1024 * 1024; 1348141cc406Sopenharmony_ci 1349141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_2; 1350141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_BLOCK; 1351141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_USE_BLOCK; 1352141cc406Sopenharmony_ci dev->sane.model = "800S/800 II SP"; 1353141cc406Sopenharmony_ci } 1354141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFC-06000CZ", 11) == 0) 1355141cc406Sopenharmony_ci { 1356141cc406Sopenharmony_ci /* These values were measured and compared to those from the 1357141cc406Sopenharmony_ci Windows driver. Tested with a Paragon 600 II CD, a Paragon 1358141cc406Sopenharmony_ci MFC-600S and a Paragon 600 II N. */ 1359141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0.0); 1360141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (218.0); 1361141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0.0); 1362141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (293.0); 1363141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0.0); 1364141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0.0); 1365141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (201.0); 1366141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (257.0); 1367141cc406Sopenharmony_ci 1368141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1369141cc406Sopenharmony_ci /* This model comes in a non-scsi version, too. It is supplied 1370141cc406Sopenharmony_ci with its own parallel-port like adapter, an AB306N. Two 1371141cc406Sopenharmony_ci firmware revisions are known: 1.01 and 2.00. Each needs its 1372141cc406Sopenharmony_ci own line-distance correction code. */ 1373141cc406Sopenharmony_ci if (dev->flags & MUSTEK_FLAG_N) 1374141cc406Sopenharmony_ci { 1375141cc406Sopenharmony_ci if (fw_revision < 0x200) 1376141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_N1; 1377141cc406Sopenharmony_ci else 1378141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_N2; 1379141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (33.0); 1380141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (62.0); 1381141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (183.0); 1382141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (238.0); 1383141cc406Sopenharmony_ci dev->max_block_buffer_size = 1024 * 1024 * 1024; 1384141cc406Sopenharmony_ci dev->sane.model = "600 II N"; 1385141cc406Sopenharmony_ci } 1386141cc406Sopenharmony_ci else if (dev->flags & MUSTEK_FLAG_SCSI_PP) 1387141cc406Sopenharmony_ci { 1388141cc406Sopenharmony_ci /* FIXME; experiment with different line distance codes later */ 1389141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (75.0); 1390141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_NONE; 1391141cc406Sopenharmony_ci dev->max_block_buffer_size = 2 * 1024 * 1024; 1392141cc406Sopenharmony_ci dev->sane.model = "600 II EP"; 1393141cc406Sopenharmony_ci } 1394141cc406Sopenharmony_ci else 1395141cc406Sopenharmony_ci { 1396141cc406Sopenharmony_ci dev->sane.model = "600S/600 II CD"; 1397141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PARAGON_2; 1398141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_BLOCK; 1399141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_USE_BLOCK; 1400141cc406Sopenharmony_ci dev->max_block_buffer_size = 2 * 1024 * 1024; 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci } 1403141cc406Sopenharmony_ci 1404141cc406Sopenharmony_ci /* ScanExpress and ScanMagic series */ 1405141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, " C03", 4) == 0) 1406141cc406Sopenharmony_ci { 1407141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1408141cc406Sopenharmony_ci driver. Tested with a ScannExpress 6000SP 1.00 */ 1409141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (215); 1410141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1411141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (293); 1412141cc406Sopenharmony_ci 1413141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0); 1414141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0); 1415141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (150.0); 1416141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (175.0); 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1419141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (60); 1420141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE; 1421141cc406Sopenharmony_ci /* At least the SE 6000SP with firmware 1.00 limits its 1422141cc406Sopenharmony_ci x-resolution to 300 dpi and does *no* interpolation at higher 1423141cc406Sopenharmony_ci resolutions. So this has to be done in software. */ 1424141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1425141cc406Sopenharmony_ci dev->sane.model = "ScanExpress 6000SP"; 1426141cc406Sopenharmony_ci } 1427141cc406Sopenharmony_ci /* There are two different versions of the ScanExpress 12000SP, one 1428141cc406Sopenharmony_ci has the model name " C06", the other one is "XC06". The latter 1429141cc406Sopenharmony_ci seems to be used in the newer "Plus" models. 1430141cc406Sopenharmony_ci Also there is the Mustek ScanExpress 1200 FS, which looks similar to the 1431141cc406Sopenharmony_ci ScanExpress 12000 SP but has an "F" instead of the "V" in the 1432141cc406Sopenharmony_ci firmware version. 1433141cc406Sopenharmony_ci */ 1434141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, " C06", 4) == 0) 1435141cc406Sopenharmony_ci { 1436141cc406Sopenharmony_ci if (result[32] == 'F') 1437141cc406Sopenharmony_ci { 1438141cc406Sopenharmony_ci /* Mustek ScanExpress 1200 FS. Completely untested. */ 1439141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0); 1440141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1441141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (215.9); 1442141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (291.2); 1443141cc406Sopenharmony_ci 1444141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0); 1445141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0); 1446141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (150.0); 1447141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (175.0); 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1450141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (60); 1451141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE; 1452141cc406Sopenharmony_ci /* The ScanExpress models limit their x-resolution to 600 dpi 1453141cc406Sopenharmony_ci and do *no* interpolation at higher resolutions. So this has 1454141cc406Sopenharmony_ci to be done in software. */ 1455141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1456141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_COVER_SENSOR; 1457141cc406Sopenharmony_ci dev->sane.model = "ScanExpress 12000 FS (untested)"; 1458141cc406Sopenharmony_ci } 1459141cc406Sopenharmony_ci else 1460141cc406Sopenharmony_ci { 1461141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1462141cc406Sopenharmony_ci driver. Tested with a ScaneExpress 12000SP 2.02 and a ScanMagic 1463141cc406Sopenharmony_ci 9636S v 1.01 */ 1464141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0); 1465141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1466141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (215.9); 1467141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (291.2); 1468141cc406Sopenharmony_ci 1469141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0); 1470141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0); 1471141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (150.0); 1472141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (175.0); 1473141cc406Sopenharmony_ci 1474141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1475141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (60); 1476141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE; 1477141cc406Sopenharmony_ci /* The ScanExpress models limit their x-resolution to 600 dpi 1478141cc406Sopenharmony_ci and do *no* interpolation at higher resolutions. So this has 1479141cc406Sopenharmony_ci to be done in software. */ 1480141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1481141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_COVER_SENSOR; 1482141cc406Sopenharmony_ci dev->sane.model = "ScanExpress 12000SP"; 1483141cc406Sopenharmony_ci } 1484141cc406Sopenharmony_ci } 1485141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "XC06", 4) == 0) 1486141cc406Sopenharmony_ci { 1487141cc406Sopenharmony_ci /* These values are tested with a SE 12000 SP Plus v 1.01 */ 1488141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (216); 1489141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1490141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (294.5); 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0); 1493141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0); 1494141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (152.0); 1495141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (177.0); 1496141cc406Sopenharmony_ci 1497141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1498141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (60); 1499141cc406Sopenharmony_ci 1500141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE; 1501141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE_PLUS; 1502141cc406Sopenharmony_ci /* The ScanExpress models limit their x-resolution to 600 dpi 1503141cc406Sopenharmony_ci and do *no* interpolation at higher resolutions. So this has 1504141cc406Sopenharmony_ci to be done in software. */ 1505141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1506141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_COVER_SENSOR; 1507141cc406Sopenharmony_ci dev->sane.model = "ScanExpress 12000SP Plus"; 1508141cc406Sopenharmony_ci } 1509141cc406Sopenharmony_ci /* ScanExpress A3 SP */ 1510141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, " L03", 4) == 0) 1511141cc406Sopenharmony_ci { 1512141cc406Sopenharmony_ci /* These values were measured with a ScannExpress A3 SP 2.00 */ 1513141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (297); 1514141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 1515141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (430); 1516141cc406Sopenharmony_ci 1517141cc406Sopenharmony_ci /* TA couldn't be tested due to lack of equipment. So At least 1518141cc406Sopenharmony_ci the TA IV (A4 size) is supported */ 1519141cc406Sopenharmony_ci dev->x_trans_range.min = SANE_FIX (0); 1520141cc406Sopenharmony_ci dev->y_trans_range.min = SANE_FIX (0); 1521141cc406Sopenharmony_ci dev->x_trans_range.max = SANE_FIX (150.0); 1522141cc406Sopenharmony_ci dev->y_trans_range.max = SANE_FIX (175.0); 1523141cc406Sopenharmony_ci 1524141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (600); 1525141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (60); 1526141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_SE; 1527141cc406Sopenharmony_ci /* The ScanExpress models limit their x-resolution to 300 dpi 1528141cc406Sopenharmony_ci and do *no* interpolation at higher resolutions. So this has 1529141cc406Sopenharmony_ci to be done in software. */ 1530141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1531141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_COVER_SENSOR; 1532141cc406Sopenharmony_ci dev->sane.model = "ScanExpress A3 SP"; 1533141cc406Sopenharmony_ci } 1534141cc406Sopenharmony_ci /* Paragon 1200 SP Pro */ 1535141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-1200SPPRO", 13) == 0) 1536141cc406Sopenharmony_ci { 1537141cc406Sopenharmony_ci /* These values were measured with a Paragon 1200 SP Pro v2.01 */ 1538141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (8.6 * MM_PER_INCH); 1539141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (13.70 * MM_PER_INCH); 1540141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1541141cc406Sopenharmony_ci dev->sane.model = "1200 SP PRO"; 1542141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_NONE; 1543141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1544141cc406Sopenharmony_ci } 1545141cc406Sopenharmony_ci /* No documentation, but it works: Paragon 1200 A3 PRO */ 1546141cc406Sopenharmony_ci else if (strncmp ((SANE_String) model_name, "MFS-1200A3PRO", 13) == 0) 1547141cc406Sopenharmony_ci { 1548141cc406Sopenharmony_ci /* These values were measured and compared to those from the Windows 1549141cc406Sopenharmony_ci driver. Tested with a Paragon 1200 A3 Pro v1.10 */ 1550141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (11.7 * MM_PER_INCH); 1551141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (424); 1552141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (1200); 1553141cc406Sopenharmony_ci dev->sane.model = "1200 A3 PRO"; 1554141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_LD_NONE; 1555141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ENLARGE_X; 1556141cc406Sopenharmony_ci } 1557141cc406Sopenharmony_ci else 1558141cc406Sopenharmony_ci { 1559141cc406Sopenharmony_ci DBG (0, "attach: this Mustek scanner (ID: %s) is not supported yet\n", 1560141cc406Sopenharmony_ci model_name); 1561141cc406Sopenharmony_ci DBG (0, "attach: please set the debug level to 5 and send a debug " 1562141cc406Sopenharmony_ci "report\n"); 1563141cc406Sopenharmony_ci DBG (0, "attach: to henning@meier-geinitz.de (export " 1564141cc406Sopenharmony_ci "SANE_DEBUG_MUSTEK=5\n"); 1565141cc406Sopenharmony_ci DBG (0, "attach: scanimage -L 2>debug.txt). Thank you.\n"); 1566141cc406Sopenharmony_ci free (dev); 1567141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1568141cc406Sopenharmony_ci } 1569141cc406Sopenharmony_ci 1570141cc406Sopenharmony_ci if (dev->flags & MUSTEK_FLAG_SE) 1571141cc406Sopenharmony_ci { 1572141cc406Sopenharmony_ci DBG (3, "attach: this is a single-pass scanner\n"); 1573141cc406Sopenharmony_ci if (result[63] & (1 << 6)) 1574141cc406Sopenharmony_ci { 1575141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_TA; 1576141cc406Sopenharmony_ci DBG (3, "attach: scanner supports transparency adapter (TA)\n"); 1577141cc406Sopenharmony_ci } 1578141cc406Sopenharmony_ci } 1579141cc406Sopenharmony_ci else 1580141cc406Sopenharmony_ci { 1581141cc406Sopenharmony_ci if (result[57] & (1 << 6)) 1582141cc406Sopenharmony_ci { 1583141cc406Sopenharmony_ci DBG (3, "attach: this is a single-pass scanner\n"); 1584141cc406Sopenharmony_ci if (dev->flags & MUSTEK_FLAG_LD_NONE) 1585141cc406Sopenharmony_ci DBG (4, 1586141cc406Sopenharmony_ci "attach: scanner doesn't need line-distance correction\n"); 1587141cc406Sopenharmony_ci else if (dev->flags & MUSTEK_FLAG_LD_N1) 1588141cc406Sopenharmony_ci DBG (4, "attach: scanner has N1 line-distance correction\n"); 1589141cc406Sopenharmony_ci else if (dev->flags & MUSTEK_FLAG_LD_N2) 1590141cc406Sopenharmony_ci DBG (4, "attach: scanner has N2 line-distance correction\n"); 1591141cc406Sopenharmony_ci else if (dev->flags & MUSTEK_FLAG_LD_BLOCK) 1592141cc406Sopenharmony_ci DBG (4, "attach: scanner has block line-distance correction\n"); 1593141cc406Sopenharmony_ci else 1594141cc406Sopenharmony_ci DBG (4, "attach: scanner has normal line-distance correction\n"); 1595141cc406Sopenharmony_ci } 1596141cc406Sopenharmony_ci else 1597141cc406Sopenharmony_ci { 1598141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_THREE_PASS; 1599141cc406Sopenharmony_ci /* three-pass scanners quantize to 0.5% of the maximum resolution: */ 1600141cc406Sopenharmony_ci dev->dpi_range.quant = dev->dpi_range.max / 200; 1601141cc406Sopenharmony_ci dev->dpi_range.min = dev->dpi_range.quant; 1602141cc406Sopenharmony_ci DBG (3, "attach: this is a three-pass scanner\n"); 1603141cc406Sopenharmony_ci } 1604141cc406Sopenharmony_ci if (result[57] & (1 << 5)) 1605141cc406Sopenharmony_ci { 1606141cc406Sopenharmony_ci DBG (3, "attach: this is a professional series scanner\n"); 1607141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_PRO; 1608141cc406Sopenharmony_ci status = dev_open (devname, &s, sense_handler); 1609141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 1610141cc406Sopenharmony_ci { 1611141cc406Sopenharmony_ci if (ta_available_pro (&s)) 1612141cc406Sopenharmony_ci { 1613141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_TA; 1614141cc406Sopenharmony_ci DBG (3, "attach: found transparency adapter (TA)\n"); 1615141cc406Sopenharmony_ci } 1616141cc406Sopenharmony_ci dev_close (&s); 1617141cc406Sopenharmony_ci } 1618141cc406Sopenharmony_ci else 1619141cc406Sopenharmony_ci { 1620141cc406Sopenharmony_ci DBG (1, "attach: couldn't open device: %s\n", 1621141cc406Sopenharmony_ci sane_strstatus (status)); 1622141cc406Sopenharmony_ci return status; 1623141cc406Sopenharmony_ci } 1624141cc406Sopenharmony_ci } 1625141cc406Sopenharmony_ci if (result[63] & (1 << 2)) 1626141cc406Sopenharmony_ci { 1627141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ADF; 1628141cc406Sopenharmony_ci DBG (3, "attach: found automatic document feeder (ADF)\n"); 1629141cc406Sopenharmony_ci if (result[63] & (1 << 3)) 1630141cc406Sopenharmony_ci { 1631141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_ADF_READY; 1632141cc406Sopenharmony_ci DBG (4, "attach: automatic document feeder is ready\n"); 1633141cc406Sopenharmony_ci } 1634141cc406Sopenharmony_ci else 1635141cc406Sopenharmony_ci { 1636141cc406Sopenharmony_ci DBG (4, "attach: automatic document feeder is out of " 1637141cc406Sopenharmony_ci "documents\n"); 1638141cc406Sopenharmony_ci } 1639141cc406Sopenharmony_ci } 1640141cc406Sopenharmony_ci 1641141cc406Sopenharmony_ci if (result[63] & (1 << 6)) 1642141cc406Sopenharmony_ci { 1643141cc406Sopenharmony_ci dev->flags |= MUSTEK_FLAG_TA; 1644141cc406Sopenharmony_ci DBG (3, "attach: found transparency adapter (TA)\n"); 1645141cc406Sopenharmony_ci } 1646141cc406Sopenharmony_ci } 1647141cc406Sopenharmony_ci 1648141cc406Sopenharmony_ci if (dev->flags & MUSTEK_FLAG_COVER_SENSOR) 1649141cc406Sopenharmony_ci { 1650141cc406Sopenharmony_ci if (result[62] & (1 << 0)) 1651141cc406Sopenharmony_ci DBG (4, "attach: scanner cover is closed\n"); 1652141cc406Sopenharmony_ci else 1653141cc406Sopenharmony_ci DBG (4, "attach: scanner cover is open\n"); 1654141cc406Sopenharmony_ci } 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci if (warning == SANE_TRUE) 1657141cc406Sopenharmony_ci { 1658141cc406Sopenharmony_ci DBG (0, 1659141cc406Sopenharmony_ci "WARNING: Your scanner was detected by the SANE Mustek backend, " 1660141cc406Sopenharmony_ci "but\n it is not fully tested. It may or may not work. Be " 1661141cc406Sopenharmony_ci "careful and read\n the PROBLEMS file in the sane directory. " 1662141cc406Sopenharmony_ci "Please set the debug level of this\n backend to maximum " 1663141cc406Sopenharmony_ci "(export SANE_DEBUG_MUSTEK=255) and send the output of\n " 1664141cc406Sopenharmony_ci "scanimage -L to the SANE mailing list sane-devel@alioth-lists.debian.net. " 1665141cc406Sopenharmony_ci "Please include\n the exact model name of your scanner and to " 1666141cc406Sopenharmony_ci "which extend it works.\n"); 1667141cc406Sopenharmony_ci } 1668141cc406Sopenharmony_ci 1669141cc406Sopenharmony_ci DBG (2, "attach: found Mustek %s %s, %s%s%s%s\n", 1670141cc406Sopenharmony_ci dev->sane.model, dev->sane.type, 1671141cc406Sopenharmony_ci (dev->flags & MUSTEK_FLAG_THREE_PASS) ? "3-pass" : "1-pass", 1672141cc406Sopenharmony_ci (dev->flags & MUSTEK_FLAG_ADF) ? ", ADF" : "", 1673141cc406Sopenharmony_ci (dev->flags & MUSTEK_FLAG_TA) ? ", TA" : "", 1674141cc406Sopenharmony_ci (dev->flags & MUSTEK_FLAG_SE) ? ", SE" : ""); 1675141cc406Sopenharmony_ci 1676141cc406Sopenharmony_ci ++num_devices; 1677141cc406Sopenharmony_ci dev->next = first_dev; 1678141cc406Sopenharmony_ci first_dev = dev; 1679141cc406Sopenharmony_ci 1680141cc406Sopenharmony_ci if (devp) 1681141cc406Sopenharmony_ci *devp = dev; 1682141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1683141cc406Sopenharmony_ci} 1684141cc406Sopenharmony_ci 1685141cc406Sopenharmony_cistatic size_t 1686141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[]) 1687141cc406Sopenharmony_ci{ 1688141cc406Sopenharmony_ci size_t size, max_size = 0; 1689141cc406Sopenharmony_ci SANE_Int i; 1690141cc406Sopenharmony_ci 1691141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) 1692141cc406Sopenharmony_ci { 1693141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 1694141cc406Sopenharmony_ci if (size > max_size) 1695141cc406Sopenharmony_ci max_size = size; 1696141cc406Sopenharmony_ci } 1697141cc406Sopenharmony_ci return max_size; 1698141cc406Sopenharmony_ci} 1699141cc406Sopenharmony_ci 1700141cc406Sopenharmony_cistatic SANE_Status 1701141cc406Sopenharmony_ciconstrain_value (Mustek_Scanner * s, SANE_Int option, void *value, 1702141cc406Sopenharmony_ci SANE_Int * info) 1703141cc406Sopenharmony_ci{ 1704141cc406Sopenharmony_ci SANE_Fixed w, dpi; 1705141cc406Sopenharmony_ci SANE_Status status; 1706141cc406Sopenharmony_ci 1707141cc406Sopenharmony_ci if (value) 1708141cc406Sopenharmony_ci w = *(SANE_Fixed *) value; 1709141cc406Sopenharmony_ci else 1710141cc406Sopenharmony_ci w = 0; 1711141cc406Sopenharmony_ci 1712141cc406Sopenharmony_ci if (option == OPT_RESOLUTION) 1713141cc406Sopenharmony_ci { 1714141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 1715141cc406Sopenharmony_ci { 1716141cc406Sopenharmony_ci /* The three pass scanners use a 0.5% of the maximum resolution 1717141cc406Sopenharmony_ci increment for resolutions less than or equal to half of the 1718141cc406Sopenharmony_ci maximum resolution. The MFS-06000CX uses a 5% of the maximum 1719141cc406Sopenharmony_ci resolution increment for larger resolutions. The models 1720141cc406Sopenharmony_ci MFS-12000CX and MSF-06000CZ use 1% of the maximum resolution. 1721141cc406Sopenharmony_ci We can't represent this easily in SANE, so the constraint is 1722141cc406Sopenharmony_ci simply for 0.5% and then we round to the 5% or 1% increments 1723141cc406Sopenharmony_ci if necessary. */ 1724141cc406Sopenharmony_ci SANE_Fixed max_dpi, quant, half_res; 1725141cc406Sopenharmony_ci 1726141cc406Sopenharmony_ci /*w = *(SANE_Word *) value; */ 1727141cc406Sopenharmony_ci max_dpi = s->hw->dpi_range.max; 1728141cc406Sopenharmony_ci half_res = max_dpi / 2; 1729141cc406Sopenharmony_ci 1730141cc406Sopenharmony_ci if (w > half_res) 1731141cc406Sopenharmony_ci { 1732141cc406Sopenharmony_ci /* quantizize to 1% step */ 1733141cc406Sopenharmony_ci quant = max_dpi / 100; 1734141cc406Sopenharmony_ci 1735141cc406Sopenharmony_ci dpi = (w + quant / 2) / quant; 1736141cc406Sopenharmony_ci dpi *= quant; 1737141cc406Sopenharmony_ci if (dpi != w) 1738141cc406Sopenharmony_ci { 1739141cc406Sopenharmony_ci *(SANE_Word *) value = dpi; 1740141cc406Sopenharmony_ci if (info) 1741141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 1742141cc406Sopenharmony_ci } 1743141cc406Sopenharmony_ci } 1744141cc406Sopenharmony_ci 1745141cc406Sopenharmony_ci } 1746141cc406Sopenharmony_ci } 1747141cc406Sopenharmony_ci 1748141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, value, info); 1749141cc406Sopenharmony_ci if (s->opt[option].type == SANE_TYPE_FIXED) 1750141cc406Sopenharmony_ci DBG (5, "constrain_value: %s = %.2f (was %.2f)\n", s->opt[option].name, 1751141cc406Sopenharmony_ci SANE_UNFIX (*(SANE_Word *) value), SANE_UNFIX (w)); 1752141cc406Sopenharmony_ci return status; 1753141cc406Sopenharmony_ci} 1754141cc406Sopenharmony_ci 1755141cc406Sopenharmony_ci/* Quantize s->val[OPT_RESOLUTION].w and return the resolution code for the 1756141cc406Sopenharmony_ci quantized resolution. Quantization depends on scanner type (single 1757141cc406Sopenharmony_ci pass vs. three-pass) and resolution */ 1758141cc406Sopenharmony_cistatic SANE_Int 1759141cc406Sopenharmony_ciencode_resolution (Mustek_Scanner * s) 1760141cc406Sopenharmony_ci{ 1761141cc406Sopenharmony_ci SANE_Fixed max_dpi, dpi; 1762141cc406Sopenharmony_ci SANE_Int code, mode = 0; 1763141cc406Sopenharmony_ci 1764141cc406Sopenharmony_ci dpi = s->val[OPT_RESOLUTION].w; 1765141cc406Sopenharmony_ci 1766141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 1767141cc406Sopenharmony_ci { 1768141cc406Sopenharmony_ci code = dpi >> SANE_FIXED_SCALE_SHIFT; 1769141cc406Sopenharmony_ci } 1770141cc406Sopenharmony_ci else 1771141cc406Sopenharmony_ci { 1772141cc406Sopenharmony_ci SANE_Fixed quant, half_res; 1773141cc406Sopenharmony_ci 1774141cc406Sopenharmony_ci max_dpi = s->hw->dpi_range.max; 1775141cc406Sopenharmony_ci half_res = max_dpi / 2; 1776141cc406Sopenharmony_ci 1777141cc406Sopenharmony_ci if (dpi <= half_res) 1778141cc406Sopenharmony_ci { 1779141cc406Sopenharmony_ci /* quantizize to 0.5% step */ 1780141cc406Sopenharmony_ci quant = max_dpi / 200; 1781141cc406Sopenharmony_ci } 1782141cc406Sopenharmony_ci else 1783141cc406Sopenharmony_ci { 1784141cc406Sopenharmony_ci /* quantizize to 1% step */ 1785141cc406Sopenharmony_ci quant = max_dpi / 100; 1786141cc406Sopenharmony_ci mode = 0x100; /* indicate 5% or 1% quantization */ 1787141cc406Sopenharmony_ci } 1788141cc406Sopenharmony_ci 1789141cc406Sopenharmony_ci code = (dpi + quant / 2) / quant; 1790141cc406Sopenharmony_ci if (code < 1) 1791141cc406Sopenharmony_ci code = 1; 1792141cc406Sopenharmony_ci 1793141cc406Sopenharmony_ci } 1794141cc406Sopenharmony_ci DBG (5, "encode_resolution: code = 0x%x (%d); mode = %x\n", code, code, 1795141cc406Sopenharmony_ci mode); 1796141cc406Sopenharmony_ci return code | mode; 1797141cc406Sopenharmony_ci} 1798141cc406Sopenharmony_ci 1799141cc406Sopenharmony_cistatic SANE_Int 1800141cc406Sopenharmony_ciencode_percentage (Mustek_Scanner * s, double value) 1801141cc406Sopenharmony_ci{ 1802141cc406Sopenharmony_ci SANE_Int max, code, sign = 0; 1803141cc406Sopenharmony_ci 1804141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 1805141cc406Sopenharmony_ci { 1806141cc406Sopenharmony_ci code = (int) ((value / 100.0 * 12) + 12.5); 1807141cc406Sopenharmony_ci max = 0x18; 1808141cc406Sopenharmony_ci } 1809141cc406Sopenharmony_ci else 1810141cc406Sopenharmony_ci { 1811141cc406Sopenharmony_ci if (value < 0.0) 1812141cc406Sopenharmony_ci { 1813141cc406Sopenharmony_ci value = -value; 1814141cc406Sopenharmony_ci sign = 0x80; 1815141cc406Sopenharmony_ci } 1816141cc406Sopenharmony_ci code = (int) (value / 100.0 * 127 + 0.5); 1817141cc406Sopenharmony_ci code |= sign; 1818141cc406Sopenharmony_ci max = 0xff; 1819141cc406Sopenharmony_ci } 1820141cc406Sopenharmony_ci if (code > max) 1821141cc406Sopenharmony_ci code = max; 1822141cc406Sopenharmony_ci if (code < 0) 1823141cc406Sopenharmony_ci code = 0x00; 1824141cc406Sopenharmony_ci return code; 1825141cc406Sopenharmony_ci} 1826141cc406Sopenharmony_ci 1827141cc406Sopenharmony_ci/* encode halftone pattern type and size */ 1828141cc406Sopenharmony_cistatic SANE_Status 1829141cc406Sopenharmony_ciencode_halftone (Mustek_Scanner * s) 1830141cc406Sopenharmony_ci{ 1831141cc406Sopenharmony_ci SANE_String selection = s->val[OPT_HALFTONE_DIMENSION].s; 1832141cc406Sopenharmony_ci SANE_Int i = 0; 1833141cc406Sopenharmony_ci 1834141cc406Sopenharmony_ci while ((halftone_list[i] != 0) && (strcmp (selection, halftone_list[i]) != 0)) 1835141cc406Sopenharmony_ci { 1836141cc406Sopenharmony_ci i++; 1837141cc406Sopenharmony_ci } 1838141cc406Sopenharmony_ci if (halftone_list[i] == 0) 1839141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1840141cc406Sopenharmony_ci 1841141cc406Sopenharmony_ci if (i < 0x0c) /* standard pattern */ 1842141cc406Sopenharmony_ci { 1843141cc406Sopenharmony_ci s->custom_halftone_pattern = SANE_FALSE; 1844141cc406Sopenharmony_ci s->halftone_pattern_type = i; 1845141cc406Sopenharmony_ci } 1846141cc406Sopenharmony_ci else /* custom pattern */ 1847141cc406Sopenharmony_ci { 1848141cc406Sopenharmony_ci s->custom_halftone_pattern = SANE_TRUE; 1849141cc406Sopenharmony_ci i -= 0x0c; 1850141cc406Sopenharmony_ci i = 8 - i; 1851141cc406Sopenharmony_ci if (i < 8) 1852141cc406Sopenharmony_ci i--; 1853141cc406Sopenharmony_ci i = i + (i << 4); 1854141cc406Sopenharmony_ci s->halftone_pattern_type = i; 1855141cc406Sopenharmony_ci } 1856141cc406Sopenharmony_ci 1857141cc406Sopenharmony_ci DBG (5, "encode_halftone: %s pattern type %x\n", 1858141cc406Sopenharmony_ci s->custom_halftone_pattern ? "custom" : "standard", 1859141cc406Sopenharmony_ci s->halftone_pattern_type); 1860141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1861141cc406Sopenharmony_ci} 1862141cc406Sopenharmony_ci 1863141cc406Sopenharmony_ci/* Paragon series */ 1864141cc406Sopenharmony_cistatic SANE_Status 1865141cc406Sopenharmony_ciarea_and_windows (Mustek_Scanner * s) 1866141cc406Sopenharmony_ci{ 1867141cc406Sopenharmony_ci SANE_Byte cmd[117], *cp; 1868141cc406Sopenharmony_ci SANE_Int i, offset; 1869141cc406Sopenharmony_ci 1870141cc406Sopenharmony_ci /* setup SCSI command (except length): */ 1871141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 1872141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_AREA_AND_WINDOWS; 1873141cc406Sopenharmony_ci 1874141cc406Sopenharmony_ci cp = cmd + 6; 1875141cc406Sopenharmony_ci 1876141cc406Sopenharmony_ci /* Some scanners need a larger scanarea for line-distance correction */ 1877141cc406Sopenharmony_ci offset = 0; 1878141cc406Sopenharmony_ci if (((s->hw->flags & MUSTEK_FLAG_LD_N1) 1879141cc406Sopenharmony_ci || ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK) 1880141cc406Sopenharmony_ci && (s->hw->flags & MUSTEK_FLAG_PARAGON_1))) 1881141cc406Sopenharmony_ci && (s->mode & MUSTEK_MODE_COLOR)) 1882141cc406Sopenharmony_ci offset = MAX_LINE_DIST; 1883141cc406Sopenharmony_ci 1884141cc406Sopenharmony_ci /* fill in frame header: */ 1885141cc406Sopenharmony_ci 1886141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_USE_EIGHTS) 1887141cc406Sopenharmony_ci { 1888141cc406Sopenharmony_ci double eights_per_mm = 8 / MM_PER_INCH; 1889141cc406Sopenharmony_ci SANE_Int tlx, tly, brx, bry; 1890141cc406Sopenharmony_ci /* 1891141cc406Sopenharmony_ci * The MSF-06000CZ seems to lock-up if the pixel-unit is used. 1892141cc406Sopenharmony_ci * Using 1/8" works. 1893141cc406Sopenharmony_ci * This doesn't seem to be true with the current scheme. 1894141cc406Sopenharmony_ci * This code isn't used at the moment. <henning@meier-geinitz.de> 1895141cc406Sopenharmony_ci */ 1896141cc406Sopenharmony_ci *cp++ = ((s->mode & MUSTEK_MODE_LINEART) ? 0x00 : 0x01); 1897141cc406Sopenharmony_ci 1898141cc406Sopenharmony_ci tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * eights_per_mm + 0.5; 1899141cc406Sopenharmony_ci tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * eights_per_mm + 0.5; 1900141cc406Sopenharmony_ci brx = SANE_UNFIX (s->val[OPT_BR_X].w) * eights_per_mm + 0.5; 1901141cc406Sopenharmony_ci bry = SANE_UNFIX (s->val[OPT_BR_Y].w) * eights_per_mm + 0.5; 1902141cc406Sopenharmony_ci STORE16L (cp, tlx); 1903141cc406Sopenharmony_ci STORE16L (cp, tly); 1904141cc406Sopenharmony_ci STORE16L (cp, brx); 1905141cc406Sopenharmony_ci STORE16L (cp, bry); 1906141cc406Sopenharmony_ci DBG (5, "area_and_windows: tlx=%d (%d mm); tly=%d (%d mm); " 1907141cc406Sopenharmony_ci "brx=%d (%d mm); bry=%d (%d mm)\n", tlx, 1908141cc406Sopenharmony_ci (int) (tlx / eights_per_mm), tly, (int) (tly / eights_per_mm), brx, 1909141cc406Sopenharmony_ci (int) (brx / eights_per_mm), bry, (int) (bry / eights_per_mm)); 1910141cc406Sopenharmony_ci } 1911141cc406Sopenharmony_ci else 1912141cc406Sopenharmony_ci { 1913141cc406Sopenharmony_ci double pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH; 1914141cc406Sopenharmony_ci SANE_Int tlx, tly, brx, bry; 1915141cc406Sopenharmony_ci 1916141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 1917141cc406Sopenharmony_ci /* 3pass scanners use 1/2 of the max resolution as base */ 1918141cc406Sopenharmony_ci pixels_per_mm /= 2; 1919141cc406Sopenharmony_ci 1920141cc406Sopenharmony_ci /* pixel unit and halftoning: */ 1921141cc406Sopenharmony_ci *cp++ = 0x8 | ((s->mode & MUSTEK_MODE_LINEART) ? 0x00 : 0x01); 1922141cc406Sopenharmony_ci 1923141cc406Sopenharmony_ci /* fill in scanning area: */ 1924141cc406Sopenharmony_ci if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) 1925141cc406Sopenharmony_ci { 1926141cc406Sopenharmony_ci /* must mirror the x coordinates */ 1927141cc406Sopenharmony_ci brx = SANE_UNFIX (s->hw->x_range.max - s->val[OPT_TL_X].w) 1928141cc406Sopenharmony_ci * pixels_per_mm + 0.5; 1929141cc406Sopenharmony_ci tlx = SANE_UNFIX (s->hw->x_range.max - s->val[OPT_BR_X].w) 1930141cc406Sopenharmony_ci * pixels_per_mm + 0.5; 1931141cc406Sopenharmony_ci } 1932141cc406Sopenharmony_ci else 1933141cc406Sopenharmony_ci { 1934141cc406Sopenharmony_ci tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5; 1935141cc406Sopenharmony_ci brx = SANE_UNFIX (s->val[OPT_BR_X].w) * pixels_per_mm + 0.5; 1936141cc406Sopenharmony_ci 1937141cc406Sopenharmony_ci } 1938141cc406Sopenharmony_ci tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5; 1939141cc406Sopenharmony_ci bry = SANE_UNFIX (s->val[OPT_BR_Y].w) * pixels_per_mm + 0.5 + offset; 1940141cc406Sopenharmony_ci STORE16L (cp, tlx); 1941141cc406Sopenharmony_ci STORE16L (cp, tly); 1942141cc406Sopenharmony_ci STORE16L (cp, brx); 1943141cc406Sopenharmony_ci STORE16L (cp, bry); 1944141cc406Sopenharmony_ci DBG (5, "area_and_windows: tlx=%d (%d mm); tly=%d (%d mm); " 1945141cc406Sopenharmony_ci "brx=%d (%d mm); bry=%d (%d mm)\n", tlx, 1946141cc406Sopenharmony_ci (int) (tlx / pixels_per_mm), tly, (int) (tly / pixels_per_mm), brx, 1947141cc406Sopenharmony_ci (int) (brx / pixels_per_mm), bry, (int) (bry / pixels_per_mm)); 1948141cc406Sopenharmony_ci } 1949141cc406Sopenharmony_ci 1950141cc406Sopenharmony_ci if (s->custom_halftone_pattern) 1951141cc406Sopenharmony_ci { 1952141cc406Sopenharmony_ci *cp++ = 0x40; /* mark presence of user pattern */ 1953141cc406Sopenharmony_ci *cp++ = s->halftone_pattern_type; /* set pattern length */ 1954141cc406Sopenharmony_ci for (i = 0; i < (s->halftone_pattern_type & 0x0f) * 1955141cc406Sopenharmony_ci ((s->halftone_pattern_type >> 4) & 0x0f); ++i) 1956141cc406Sopenharmony_ci *cp++ = s->val[OPT_HALFTONE_PATTERN].wa[i]; 1957141cc406Sopenharmony_ci } 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_ci cmd[4] = (cp - cmd) - 6; 1960141cc406Sopenharmony_ci 1961141cc406Sopenharmony_ci return dev_cmd (s, cmd, (cp - cmd), 0, 0); 1962141cc406Sopenharmony_ci} 1963141cc406Sopenharmony_ci 1964141cc406Sopenharmony_ci/* ScanExpress */ 1965141cc406Sopenharmony_cistatic SANE_Status 1966141cc406Sopenharmony_ciset_window_se (Mustek_Scanner * s, SANE_Int lamp) 1967141cc406Sopenharmony_ci{ 1968141cc406Sopenharmony_ci SANE_Byte cmd[58], *cp; 1969141cc406Sopenharmony_ci double pixels_per_mm; 1970141cc406Sopenharmony_ci SANE_Int offset; 1971141cc406Sopenharmony_ci SANE_Int tlx, tly, width, height; 1972141cc406Sopenharmony_ci 1973141cc406Sopenharmony_ci /* setup SCSI command (except length): */ 1974141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 1975141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_SET_WINDOW; 1976141cc406Sopenharmony_ci cp = cmd + CDB_SIZE (MUSTEK_SCSI_SET_WINDOW); /* skip command block */ 1977141cc406Sopenharmony_ci 1978141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 1979141cc406Sopenharmony_ci { 1980141cc406Sopenharmony_ci /* We have to increase the specified resolution to the next */ 1981141cc406Sopenharmony_ci /* "standard" resolution due to a firmware bug(?) in color mode */ 1982141cc406Sopenharmony_ci /* It's possible to scan in 36, 75, 100, 150, 200, 250, 300, */ 1983141cc406Sopenharmony_ci /* 400, 500, 600, 900, 1200 dpi but the speed is only different */ 1984141cc406Sopenharmony_ci /* with 36, 150, 300, 600, 1200 dpi. */ 1985141cc406Sopenharmony_ci /* Additionally we must increase the window length slightly to */ 1986141cc406Sopenharmony_ci /* compensate for different line counts for r/g/b */ 1987141cc406Sopenharmony_ci const SANE_Int resolution_list[] = { 36, 150, 300, 600, 1200, 0 }; 1988141cc406Sopenharmony_ci SANE_Int entry = 0; 1989141cc406Sopenharmony_ci 1990141cc406Sopenharmony_ci while (resolution_list[entry] < s->resolution_code) 1991141cc406Sopenharmony_ci entry++; 1992141cc406Sopenharmony_ci s->ld.peak_res = resolution_list[entry]; 1993141cc406Sopenharmony_ci 1994141cc406Sopenharmony_ci offset = MAX_LINE_DIST; /* distance r/b lines */ 1995141cc406Sopenharmony_ci } 1996141cc406Sopenharmony_ci else 1997141cc406Sopenharmony_ci { 1998141cc406Sopenharmony_ci /* In gray and lineart modes all resolutions are possible */ 1999141cc406Sopenharmony_ci s->ld.peak_res = s->resolution_code; 2000141cc406Sopenharmony_ci offset = 0; 2001141cc406Sopenharmony_ci } 2002141cc406Sopenharmony_ci DBG (5, "set_window_se: hardware resolution is %d dpi; offset is %d\n", 2003141cc406Sopenharmony_ci s->ld.peak_res, offset); 2004141cc406Sopenharmony_ci 2005141cc406Sopenharmony_ci STORE16B (cp, 0); /* window identifier */ 2006141cc406Sopenharmony_ci STORE16B (cp, s->ld.peak_res); 2007141cc406Sopenharmony_ci /* x and y resolution */ 2008141cc406Sopenharmony_ci STORE16B (cp, 0); /* not used acc. to specs */ 2009141cc406Sopenharmony_ci 2010141cc406Sopenharmony_ci pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH; 2011141cc406Sopenharmony_ci 2012141cc406Sopenharmony_ci /* fill in scanning area, begin and length(!) */ 2013141cc406Sopenharmony_ci if ((strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0) && 2014141cc406Sopenharmony_ci !(s->hw->flags & MUSTEK_FLAG_TA)) 2015141cc406Sopenharmony_ci { 2016141cc406Sopenharmony_ci /* need to add the start values of the transparency adapter */ 2017141cc406Sopenharmony_ci tlx = (SANE_UNFIX (s->val[OPT_TL_X].w) + 33.0) * pixels_per_mm + 0.5; 2018141cc406Sopenharmony_ci tly = (SANE_UNFIX (s->val[OPT_TL_Y].w) + 60.0) * pixels_per_mm + 0.5; 2019141cc406Sopenharmony_ci DBG (5, "set_window_se: added offset for transparency adapter\n"); 2020141cc406Sopenharmony_ci } 2021141cc406Sopenharmony_ci else 2022141cc406Sopenharmony_ci { 2023141cc406Sopenharmony_ci /* no transparency adapter selected or calculation done in firmware */ 2024141cc406Sopenharmony_ci tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5; 2025141cc406Sopenharmony_ci tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5; 2026141cc406Sopenharmony_ci } 2027141cc406Sopenharmony_ci width = (SANE_UNFIX (s->val[OPT_BR_X].w) - SANE_UNFIX (s->val[OPT_TL_X].w)) 2028141cc406Sopenharmony_ci * pixels_per_mm + 0.5; 2029141cc406Sopenharmony_ci height = (SANE_UNFIX (s->val[OPT_BR_Y].w) - SANE_UNFIX (s->val[OPT_TL_Y].w)) 2030141cc406Sopenharmony_ci * pixels_per_mm + 0.5 + offset; 2031141cc406Sopenharmony_ci 2032141cc406Sopenharmony_ci DBG (5, "set_window_se: tlx=%d (%d mm); tly=%d (%d mm); width=%d (%d mm); " 2033141cc406Sopenharmony_ci "height=%d (%d mm)\n", tlx, (int) (tlx / pixels_per_mm), tly, 2034141cc406Sopenharmony_ci (int) (tly / pixels_per_mm), width, (int) (width / pixels_per_mm), 2035141cc406Sopenharmony_ci height, (int) (height / pixels_per_mm)); 2036141cc406Sopenharmony_ci 2037141cc406Sopenharmony_ci 2038141cc406Sopenharmony_ci STORE32B (cp, tlx); 2039141cc406Sopenharmony_ci STORE32B (cp, tly); 2040141cc406Sopenharmony_ci STORE32B (cp, width); 2041141cc406Sopenharmony_ci STORE32B (cp, height); 2042141cc406Sopenharmony_ci 2043141cc406Sopenharmony_ci *cp++ = 0x00; /* brightness, not impl. */ 2044141cc406Sopenharmony_ci *cp++ = 0x80; /* threshold, not impl. */ 2045141cc406Sopenharmony_ci *cp++ = 0x00; /* contrast, not impl. */ 2046141cc406Sopenharmony_ci 2047141cc406Sopenharmony_ci /* Note that 'image composition' has no meaning for the SE series */ 2048141cc406Sopenharmony_ci /* Mode selection is accomplished solely by bits/pixel (1, 8, 24) */ 2049141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 2050141cc406Sopenharmony_ci { 2051141cc406Sopenharmony_ci *cp++ = 0x05; /* actually not used! */ 2052141cc406Sopenharmony_ci *cp++ = 24; /* 24 bits/pixel in color mode */ 2053141cc406Sopenharmony_ci } 2054141cc406Sopenharmony_ci else if (s->mode & MUSTEK_MODE_GRAY) 2055141cc406Sopenharmony_ci { 2056141cc406Sopenharmony_ci *cp++ = 0x02; /* actually not used! */ 2057141cc406Sopenharmony_ci *cp++ = 8; /* 8 bits/pixel in gray mode */ 2058141cc406Sopenharmony_ci } 2059141cc406Sopenharmony_ci else 2060141cc406Sopenharmony_ci { 2061141cc406Sopenharmony_ci *cp++ = 0x00; /* actually not used! */ 2062141cc406Sopenharmony_ci *cp++ = 1; /* 1 bit/pixel in lineart mode */ 2063141cc406Sopenharmony_ci } 2064141cc406Sopenharmony_ci 2065141cc406Sopenharmony_ci cp += 14; /* skip reserved bytes */ 2066141cc406Sopenharmony_ci *cp++ = lamp; /* 0 = normal, 1 = on, 2 = off */ 2067141cc406Sopenharmony_ci 2068141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_TA) 2069141cc406Sopenharmony_ci && (strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0)) 2070141cc406Sopenharmony_ci *cp++ = 1; 2071141cc406Sopenharmony_ci else 2072141cc406Sopenharmony_ci *cp++ = 0; 2073141cc406Sopenharmony_ci cp += 5; /* skip reserved bytes */ 2074141cc406Sopenharmony_ci 2075141cc406Sopenharmony_ci cmd[8] = cp - cmd - CDB_SIZE (MUSTEK_SCSI_SET_WINDOW); 2076141cc406Sopenharmony_ci return dev_cmd (s, cmd, (cp - cmd), 0, 0); 2077141cc406Sopenharmony_ci} 2078141cc406Sopenharmony_ci 2079141cc406Sopenharmony_ci/* Pro series */ 2080141cc406Sopenharmony_cistatic SANE_Status 2081141cc406Sopenharmony_ciset_window_pro (Mustek_Scanner * s) 2082141cc406Sopenharmony_ci{ 2083141cc406Sopenharmony_ci SANE_Byte cmd[20], *cp; 2084141cc406Sopenharmony_ci double pixels_per_mm; 2085141cc406Sopenharmony_ci 2086141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 2087141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_SET_WINDOW; 2088141cc406Sopenharmony_ci if (strcmp (s->hw->sane.model, "1200 SP PRO") == 0) 2089141cc406Sopenharmony_ci cmd[8] = 0x09; 2090141cc406Sopenharmony_ci else 2091141cc406Sopenharmony_ci cmd[8] = 0x0a; 2092141cc406Sopenharmony_ci 2093141cc406Sopenharmony_ci cp = cmd + CDB_SIZE (MUSTEK_SCSI_SET_WINDOW); /* skip command block */ 2094141cc406Sopenharmony_ci 2095141cc406Sopenharmony_ci *cp++ = 0; /* what's this? */ 2096141cc406Sopenharmony_ci pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH; 2097141cc406Sopenharmony_ci 2098141cc406Sopenharmony_ci /* The next for 16 bit values are x0, y0, x1, y1 in pixels at max res */ 2099141cc406Sopenharmony_ci STORE16L (cp, SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5); 2100141cc406Sopenharmony_ci STORE16L (cp, SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5); 2101141cc406Sopenharmony_ci STORE16L (cp, SANE_UNFIX (s->val[OPT_BR_X].w) * pixels_per_mm + 0.5); 2102141cc406Sopenharmony_ci STORE16L (cp, SANE_UNFIX (s->val[OPT_BR_Y].w) * pixels_per_mm + 0.5); 2103141cc406Sopenharmony_ci 2104141cc406Sopenharmony_ci if (strcmp (s->hw->sane.model, "1200 SP PRO") != 0) 2105141cc406Sopenharmony_ci *cp++ = lamp_off_time; /* Only needed for A3 Pro, default: 60 minutes until lamp-off */ 2106141cc406Sopenharmony_ci DBG (5, "set_window_pro\n"); 2107141cc406Sopenharmony_ci 2108141cc406Sopenharmony_ci return dev_cmd (s, cmd, (cp - cmd), 0, 0); 2109141cc406Sopenharmony_ci} 2110141cc406Sopenharmony_ci 2111141cc406Sopenharmony_ci/* Pro series calibration */ 2112141cc406Sopenharmony_cistatic SANE_Status 2113141cc406Sopenharmony_ciget_calibration_size_pro (Mustek_Scanner * s) 2114141cc406Sopenharmony_ci{ 2115141cc406Sopenharmony_ci SANE_Status status; 2116141cc406Sopenharmony_ci SANE_Byte cmd[6]; 2117141cc406Sopenharmony_ci SANE_Byte result[6]; 2118141cc406Sopenharmony_ci size_t len; 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 2121141cc406Sopenharmony_ci memset (result, 0, sizeof (result)); 2122141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_GET_IMAGE_STATUS; 2123141cc406Sopenharmony_ci cmd[4] = 0x06; /* size of result */ 2124141cc406Sopenharmony_ci cmd[5] = 0x80; /* get back buffer size and number of buffers */ 2125141cc406Sopenharmony_ci len = sizeof (result); 2126141cc406Sopenharmony_ci status = dev_cmd (s, cmd, sizeof (cmd), result, &len); 2127141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2128141cc406Sopenharmony_ci return status; 2129141cc406Sopenharmony_ci 2130141cc406Sopenharmony_ci s->hw->cal.bytes = result[1] | (result[2] << 8); 2131141cc406Sopenharmony_ci s->hw->cal.lines = result[3] | (result[4] << 8); 2132141cc406Sopenharmony_ci 2133141cc406Sopenharmony_ci DBG (4, "get_calibration_size_pro: bytes=%d, lines=%d\n", s->hw->cal.bytes, 2134141cc406Sopenharmony_ci s->hw->cal.lines); 2135141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2136141cc406Sopenharmony_ci} 2137141cc406Sopenharmony_ci 2138141cc406Sopenharmony_cistatic SANE_Status 2139141cc406Sopenharmony_ciget_calibration_lines_pro (Mustek_Scanner * s) 2140141cc406Sopenharmony_ci{ 2141141cc406Sopenharmony_ci SANE_Status status; 2142141cc406Sopenharmony_ci SANE_Byte cmd[10]; 2143141cc406Sopenharmony_ci size_t len; 2144141cc406Sopenharmony_ci SANE_Int line; 2145141cc406Sopenharmony_ci 2146141cc406Sopenharmony_ci DBG (2, "get_calibration_lines_pro: please wait for warmup\n"); 2147141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 2148141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_READ_DATA; 2149141cc406Sopenharmony_ci len = s->hw->cal.bytes; 2150141cc406Sopenharmony_ci cmd[6] = (len >> 16) & 0xff; 2151141cc406Sopenharmony_ci cmd[7] = (len >> 8) & 0xff; 2152141cc406Sopenharmony_ci cmd[8] = (len >> 0) & 0xff; 2153141cc406Sopenharmony_ci 2154141cc406Sopenharmony_ci for (line = 0; line < s->hw->cal.lines; line++) 2155141cc406Sopenharmony_ci { 2156141cc406Sopenharmony_ci status = dev_cmd (s, cmd, CDB_SIZE (MUSTEK_SCSI_READ_DATA), 2157141cc406Sopenharmony_ci s->hw->cal.buffer + line * len, &len); 2158141cc406Sopenharmony_ci 2159141cc406Sopenharmony_ci if ((status != SANE_STATUS_GOOD) 2160141cc406Sopenharmony_ci || (len != (unsigned int) s->hw->cal.bytes)) 2161141cc406Sopenharmony_ci { 2162141cc406Sopenharmony_ci DBG (1, "get_calibration_lines_pro: read failed\n"); 2163141cc406Sopenharmony_ci return status; 2164141cc406Sopenharmony_ci } 2165141cc406Sopenharmony_ci } 2166141cc406Sopenharmony_ci DBG (5, "get_calibration_lines_pro finished. Assuming 12 bits per color\n"); 2167141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2168141cc406Sopenharmony_ci} 2169141cc406Sopenharmony_ci 2170141cc406Sopenharmony_cistatic SANE_Status 2171141cc406Sopenharmony_cisend_calibration_lines_pro (Mustek_Scanner * s) 2172141cc406Sopenharmony_ci{ 2173141cc406Sopenharmony_ci SANE_Status status; 2174141cc406Sopenharmony_ci SANE_Byte *cmd1, *cmd2; 2175141cc406Sopenharmony_ci size_t buf_size; 2176141cc406Sopenharmony_ci SANE_Word column, line, color; 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci DBG (5, "send_calibration_lines_pro\n"); 2179141cc406Sopenharmony_ci 2180141cc406Sopenharmony_ci buf_size = s->hw->cal.bytes / 2; 2181141cc406Sopenharmony_ci cmd1 = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2182141cc406Sopenharmony_ci cmd2 = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2183141cc406Sopenharmony_ci if (!cmd1 || !cmd2) 2184141cc406Sopenharmony_ci { 2185141cc406Sopenharmony_ci DBG (1, "send_calibration_lines_pro: failed to malloc %zu bytes for " 2186141cc406Sopenharmony_ci "sending lines\n", 2187141cc406Sopenharmony_ci buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2188141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2189141cc406Sopenharmony_ci } 2190141cc406Sopenharmony_ci memset (cmd1, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2191141cc406Sopenharmony_ci memset (cmd2, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2192141cc406Sopenharmony_ci 2193141cc406Sopenharmony_ci cmd1[0] = cmd2[0] = MUSTEK_SCSI_SEND_DATA; 2194141cc406Sopenharmony_ci cmd1[6] = cmd2[6] = (buf_size >> 16) & 0xff; 2195141cc406Sopenharmony_ci cmd1[7] = cmd2[7] = (buf_size >> 8) & 0xff; 2196141cc406Sopenharmony_ci cmd1[8] = cmd2[8] = (buf_size >> 0) & 0xff; 2197141cc406Sopenharmony_ci cmd1[9] = 0; /* Least significant 8 bits */ 2198141cc406Sopenharmony_ci cmd2[9] = 0x80; /* Most significant 2 bits */ 2199141cc406Sopenharmony_ci 2200141cc406Sopenharmony_ci for (color = 0; color < 3; color++) 2201141cc406Sopenharmony_ci { 2202141cc406Sopenharmony_ci for (column = 0; column < s->hw->cal.bytes / 6; column++) 2203141cc406Sopenharmony_ci { 2204141cc406Sopenharmony_ci SANE_Word calibration_word = 0; 2205141cc406Sopenharmony_ci for (line = 0; line < s->hw->cal.lines; line++) 2206141cc406Sopenharmony_ci { 2207141cc406Sopenharmony_ci calibration_word += 2208141cc406Sopenharmony_ci *(s->hw->cal.buffer + column * 6 + color_seq[color] * 2 + 0) 2209141cc406Sopenharmony_ci + 2210141cc406Sopenharmony_ci (*(s->hw->cal.buffer + column * 6 + color_seq[color] * 2 + 1) 2211141cc406Sopenharmony_ci << 8); 2212141cc406Sopenharmony_ci } 2213141cc406Sopenharmony_ci if (!calibration_word) 2214141cc406Sopenharmony_ci calibration_word = 1; 2215141cc406Sopenharmony_ci calibration_word = (1024 * 65536 / calibration_word) - 1024; 2216141cc406Sopenharmony_ci if (calibration_word > 1023) 2217141cc406Sopenharmony_ci calibration_word = 1023; 2218141cc406Sopenharmony_ci *(cmd1 + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + (buf_size / 3) * color 2219141cc406Sopenharmony_ci + column) = calibration_word & 0xff; 2220141cc406Sopenharmony_ci *(cmd2 + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + (buf_size / 3) * color 2221141cc406Sopenharmony_ci + column) = (calibration_word >> 8) & 0xff; 2222141cc406Sopenharmony_ci } 2223141cc406Sopenharmony_ci } 2224141cc406Sopenharmony_ci 2225141cc406Sopenharmony_ci status = dev_cmd (s, cmd1, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0); 2226141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2227141cc406Sopenharmony_ci { 2228141cc406Sopenharmony_ci DBG (1, "send_calibration_lines_pro: send failed\n"); 2229141cc406Sopenharmony_ci return status; 2230141cc406Sopenharmony_ci } 2231141cc406Sopenharmony_ci 2232141cc406Sopenharmony_ci status = dev_cmd (s, cmd2, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0); 2233141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2234141cc406Sopenharmony_ci { 2235141cc406Sopenharmony_ci DBG (1, "send_calibration_lines_pro: send failed\n"); 2236141cc406Sopenharmony_ci return status; 2237141cc406Sopenharmony_ci } 2238141cc406Sopenharmony_ci free (cmd1); 2239141cc406Sopenharmony_ci free (cmd2); 2240141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2241141cc406Sopenharmony_ci} 2242141cc406Sopenharmony_ci 2243141cc406Sopenharmony_cistatic SANE_Status 2244141cc406Sopenharmony_cicalibration_pro (Mustek_Scanner * s) 2245141cc406Sopenharmony_ci{ 2246141cc406Sopenharmony_ci SANE_Status status; 2247141cc406Sopenharmony_ci 2248141cc406Sopenharmony_ci if (s->val[OPT_QUALITY_CAL].w) 2249141cc406Sopenharmony_ci DBG (4, "calibration_pro: doing calibration\n"); 2250141cc406Sopenharmony_ci else 2251141cc406Sopenharmony_ci { 2252141cc406Sopenharmony_ci DBG (4, "calibration_pro: calibration not necessary\n"); 2253141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2254141cc406Sopenharmony_ci } 2255141cc406Sopenharmony_ci 2256141cc406Sopenharmony_ci status = get_calibration_size_pro (s); 2257141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2258141cc406Sopenharmony_ci return status; 2259141cc406Sopenharmony_ci 2260141cc406Sopenharmony_ci s->hw->cal.buffer = (SANE_Byte *) malloc (s->hw->cal.bytes * 2261141cc406Sopenharmony_ci s->hw->cal.lines); 2262141cc406Sopenharmony_ci if (!s->hw->cal.buffer) 2263141cc406Sopenharmony_ci { 2264141cc406Sopenharmony_ci DBG (1, "calibration_pro: failed to malloc %d bytes for buffer\n", 2265141cc406Sopenharmony_ci s->hw->cal.bytes * s->hw->cal.lines); 2266141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2267141cc406Sopenharmony_ci } 2268141cc406Sopenharmony_ci 2269141cc406Sopenharmony_ci status = get_calibration_lines_pro (s); 2270141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2271141cc406Sopenharmony_ci return status; 2272141cc406Sopenharmony_ci 2273141cc406Sopenharmony_ci status = send_calibration_lines_pro (s); 2274141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2275141cc406Sopenharmony_ci return status; 2276141cc406Sopenharmony_ci 2277141cc406Sopenharmony_ci free (s->hw->cal.buffer); 2278141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2279141cc406Sopenharmony_ci} 2280141cc406Sopenharmony_ci 2281141cc406Sopenharmony_ci 2282141cc406Sopenharmony_ci/* ScanExpress series calibration */ 2283141cc406Sopenharmony_cistatic SANE_Status 2284141cc406Sopenharmony_ciget_calibration_lines_se (Mustek_Scanner * s) 2285141cc406Sopenharmony_ci{ 2286141cc406Sopenharmony_ci SANE_Status status; 2287141cc406Sopenharmony_ci SANE_Byte cmd[10]; 2288141cc406Sopenharmony_ci size_t len; 2289141cc406Sopenharmony_ci SANE_Word lines, bytes_per_color; 2290141cc406Sopenharmony_ci 2291141cc406Sopenharmony_ci if (s->mode == MUSTEK_MODE_COLOR) 2292141cc406Sopenharmony_ci { 2293141cc406Sopenharmony_ci lines = s->hw->cal.lines * 3; 2294141cc406Sopenharmony_ci bytes_per_color = s->hw->cal.bytes / 3; 2295141cc406Sopenharmony_ci } 2296141cc406Sopenharmony_ci else 2297141cc406Sopenharmony_ci { 2298141cc406Sopenharmony_ci lines = s->hw->cal.lines; 2299141cc406Sopenharmony_ci bytes_per_color = s->hw->cal.bytes; 2300141cc406Sopenharmony_ci } 2301141cc406Sopenharmony_ci 2302141cc406Sopenharmony_ci DBG (4, "get_calibration_lines_se: reading %d lines (%d bytes per color)\n", 2303141cc406Sopenharmony_ci lines, bytes_per_color); 2304141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 2305141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_READ_DATA; 2306141cc406Sopenharmony_ci cmd[2] = 1; 2307141cc406Sopenharmony_ci cmd[7] = (lines >> 8) & 0xff; 2308141cc406Sopenharmony_ci cmd[8] = (lines >> 0) & 0xff; 2309141cc406Sopenharmony_ci len = lines * bytes_per_color; 2310141cc406Sopenharmony_ci status = dev_cmd (s, cmd, CDB_SIZE (MUSTEK_SCSI_READ_DATA), 2311141cc406Sopenharmony_ci s->hw->cal.buffer, &len); 2312141cc406Sopenharmony_ci if ((status != SANE_STATUS_GOOD) 2313141cc406Sopenharmony_ci || (len != (unsigned int) (lines * bytes_per_color))) 2314141cc406Sopenharmony_ci { 2315141cc406Sopenharmony_ci DBG (1, "get_calibration_lines_se: read failed\n"); 2316141cc406Sopenharmony_ci return status; 2317141cc406Sopenharmony_ci } 2318141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2319141cc406Sopenharmony_ci} 2320141cc406Sopenharmony_ci 2321141cc406Sopenharmony_cistatic SANE_Status 2322141cc406Sopenharmony_cisend_calibration_lines_se (Mustek_Scanner * s, SANE_Word color) 2323141cc406Sopenharmony_ci{ 2324141cc406Sopenharmony_ci SANE_Status status; 2325141cc406Sopenharmony_ci SANE_Byte *cmd; 2326141cc406Sopenharmony_ci size_t buf_size; 2327141cc406Sopenharmony_ci SANE_Word column; 2328141cc406Sopenharmony_ci SANE_Word bytes_per_color; 2329141cc406Sopenharmony_ci 2330141cc406Sopenharmony_ci if (s->mode == MUSTEK_MODE_COLOR) 2331141cc406Sopenharmony_ci { 2332141cc406Sopenharmony_ci bytes_per_color = s->hw->cal.bytes / 3; 2333141cc406Sopenharmony_ci } 2334141cc406Sopenharmony_ci else 2335141cc406Sopenharmony_ci { 2336141cc406Sopenharmony_ci bytes_per_color = s->hw->cal.bytes; 2337141cc406Sopenharmony_ci } 2338141cc406Sopenharmony_ci 2339141cc406Sopenharmony_ci buf_size = bytes_per_color; 2340141cc406Sopenharmony_ci 2341141cc406Sopenharmony_ci DBG (5, "send_calibration_lines_se: %d bytes, color: %d\n", 2342141cc406Sopenharmony_ci bytes_per_color, color + 1); 2343141cc406Sopenharmony_ci 2344141cc406Sopenharmony_ci cmd = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2345141cc406Sopenharmony_ci if (!cmd) 2346141cc406Sopenharmony_ci { 2347141cc406Sopenharmony_ci DBG (1, "send_calibration_lines_se: failed to malloc %zu bytes for " 2348141cc406Sopenharmony_ci "sending lines\n", 2349141cc406Sopenharmony_ci buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2350141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2351141cc406Sopenharmony_ci } 2352141cc406Sopenharmony_ci memset (cmd, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2353141cc406Sopenharmony_ci 2354141cc406Sopenharmony_ci for (column = 0; column < bytes_per_color; column++) 2355141cc406Sopenharmony_ci { 2356141cc406Sopenharmony_ci SANE_Word line; 2357141cc406Sopenharmony_ci SANE_Word cali_word = 0; 2358141cc406Sopenharmony_ci SANE_Int color_seq[] = { 2, 0, 1 }; 2359141cc406Sopenharmony_ci 2360141cc406Sopenharmony_ci for (line = 0; line < s->hw->cal.lines; line++) 2361141cc406Sopenharmony_ci cali_word += *(s->hw->cal.buffer 2362141cc406Sopenharmony_ci + line * bytes_per_color 2363141cc406Sopenharmony_ci + bytes_per_color * color_seq[color] + column); 2364141cc406Sopenharmony_ci if (!cali_word) 2365141cc406Sopenharmony_ci cali_word = 1; 2366141cc406Sopenharmony_ci cali_word = 256 * s->hw->cal.lines * 255 / cali_word - 256; 2367141cc406Sopenharmony_ci if (cali_word > 255) 2368141cc406Sopenharmony_ci cali_word = 255; 2369141cc406Sopenharmony_ci *(cmd + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + column) = cali_word; 2370141cc406Sopenharmony_ci } 2371141cc406Sopenharmony_ci 2372141cc406Sopenharmony_ci cmd[0] = MUSTEK_SCSI_SEND_DATA; 2373141cc406Sopenharmony_ci cmd[2] = 1; 2374141cc406Sopenharmony_ci cmd[6] = color + 1; 2375141cc406Sopenharmony_ci cmd[7] = (buf_size >> 8) & 0xff; 2376141cc406Sopenharmony_ci cmd[8] = (buf_size >> 0) & 0xff; 2377141cc406Sopenharmony_ci 2378141cc406Sopenharmony_ci status = dev_cmd (s, cmd, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0); 2379141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2380141cc406Sopenharmony_ci { 2381141cc406Sopenharmony_ci DBG (1, "send_calibration_lines_se: send failed\n"); 2382141cc406Sopenharmony_ci return status; 2383141cc406Sopenharmony_ci } 2384141cc406Sopenharmony_ci free (cmd); 2385141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2386141cc406Sopenharmony_ci} 2387141cc406Sopenharmony_ci 2388141cc406Sopenharmony_cistatic SANE_Status 2389141cc406Sopenharmony_cicalibration_se (Mustek_Scanner * s) 2390141cc406Sopenharmony_ci{ 2391141cc406Sopenharmony_ci SANE_Status status; 2392141cc406Sopenharmony_ci 2393141cc406Sopenharmony_ci if (!s->val[OPT_QUALITY_CAL].w || s->val[OPT_PREVIEW].w 2394141cc406Sopenharmony_ci || s->mode == MUSTEK_MODE_LINEART) 2395141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2396141cc406Sopenharmony_ci 2397141cc406Sopenharmony_ci DBG (4, "calibration_se: doing calibration\n"); 2398141cc406Sopenharmony_ci 2399141cc406Sopenharmony_ci s->hw->cal.lines = MIN (s->hw->cal.lines, 2400141cc406Sopenharmony_ci s->hw->buffer_size / s->hw->cal.bytes); 2401141cc406Sopenharmony_ci 2402141cc406Sopenharmony_ci s->hw->cal.buffer = (SANE_Byte *) malloc (s->hw->cal.bytes 2403141cc406Sopenharmony_ci * s->hw->cal.lines); 2404141cc406Sopenharmony_ci if (!s->hw->cal.buffer) 2405141cc406Sopenharmony_ci { 2406141cc406Sopenharmony_ci DBG (1, "calibration_se: failed to malloc %d bytes for buffer\n", 2407141cc406Sopenharmony_ci s->hw->cal.bytes * s->hw->cal.lines); 2408141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2409141cc406Sopenharmony_ci } 2410141cc406Sopenharmony_ci 2411141cc406Sopenharmony_ci status = get_calibration_lines_se (s); 2412141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2413141cc406Sopenharmony_ci return status; 2414141cc406Sopenharmony_ci 2415141cc406Sopenharmony_ci if (s->mode == MUSTEK_MODE_GRAY) 2416141cc406Sopenharmony_ci status = send_calibration_lines_se (s, 0); 2417141cc406Sopenharmony_ci else 2418141cc406Sopenharmony_ci { 2419141cc406Sopenharmony_ci status = send_calibration_lines_se (s, 0); 2420141cc406Sopenharmony_ci status = send_calibration_lines_se (s, 1); 2421141cc406Sopenharmony_ci status = send_calibration_lines_se (s, 2); 2422141cc406Sopenharmony_ci } 2423141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2424141cc406Sopenharmony_ci return status; 2425141cc406Sopenharmony_ci 2426141cc406Sopenharmony_ci free (s->hw->cal.buffer); 2427141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2428141cc406Sopenharmony_ci} 2429141cc406Sopenharmony_ci 2430141cc406Sopenharmony_ci/* ScanExpress series */ 2431141cc406Sopenharmony_cistatic SANE_Status 2432141cc406Sopenharmony_cisend_gamma_table_se (Mustek_Scanner * s) 2433141cc406Sopenharmony_ci{ 2434141cc406Sopenharmony_ci SANE_Status status; 2435141cc406Sopenharmony_ci SANE_Byte gamma[10 + 4096], *cp; 2436141cc406Sopenharmony_ci SANE_Int color, factor, val_a, val_b; 2437141cc406Sopenharmony_ci SANE_Int i, j; 2438141cc406Sopenharmony_ci# define CLIP(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x))) 2439141cc406Sopenharmony_ci 2440141cc406Sopenharmony_ci memset (gamma, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA)); 2441141cc406Sopenharmony_ci 2442141cc406Sopenharmony_ci gamma[0] = MUSTEK_SCSI_SEND_DATA; 2443141cc406Sopenharmony_ci gamma[2] = 0x03; /* indicates gamma table */ 2444141cc406Sopenharmony_ci 2445141cc406Sopenharmony_ci if ((s->mode & MUSTEK_MODE_GRAY) || (s->mode & MUSTEK_MODE_COLOR)) 2446141cc406Sopenharmony_ci { 2447141cc406Sopenharmony_ci if ((size_t) s->hw->gamma_length + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) 2448141cc406Sopenharmony_ci > sizeof (gamma)) 2449141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2450141cc406Sopenharmony_ci gamma[7] = (s->hw->gamma_length >> 8) & 0xff; 2451141cc406Sopenharmony_ci gamma[8] = (s->hw->gamma_length >> 0) & 0xff; 2452141cc406Sopenharmony_ci 2453141cc406Sopenharmony_ci factor = s->hw->gamma_length / 256; 2454141cc406Sopenharmony_ci color = (s->mode & MUSTEK_MODE_COLOR) ? 1 : 0; 2455141cc406Sopenharmony_ci 2456141cc406Sopenharmony_ci do 2457141cc406Sopenharmony_ci { 2458141cc406Sopenharmony_ci gamma[6] = color; 2459141cc406Sopenharmony_ci 2460141cc406Sopenharmony_ci if (color == 0) 2461141cc406Sopenharmony_ci { 2462141cc406Sopenharmony_ci val_a = s->gamma_table[0][1]; 2463141cc406Sopenharmony_ci val_b = s->gamma_table[0][0]; 2464141cc406Sopenharmony_ci } 2465141cc406Sopenharmony_ci else 2466141cc406Sopenharmony_ci { 2467141cc406Sopenharmony_ci /* compose intensity gamma and color channel gamma: */ 2468141cc406Sopenharmony_ci val_a = s->gamma_table[0][s->gamma_table[color][1]]; 2469141cc406Sopenharmony_ci val_b = s->gamma_table[0][s->gamma_table[color][0]]; 2470141cc406Sopenharmony_ci } 2471141cc406Sopenharmony_ci /* Now val_a is extrapolated from [0] and [1] */ 2472141cc406Sopenharmony_ci val_a = MAX (2 * val_b - val_a, 0); 2473141cc406Sopenharmony_ci 2474141cc406Sopenharmony_ci /* Interpolate first entries from 256 entry table */ 2475141cc406Sopenharmony_ci cp = gamma + CDB_SIZE (MUSTEK_SCSI_SEND_DATA); 2476141cc406Sopenharmony_ci for (j = 0; j < factor; j++) 2477141cc406Sopenharmony_ci *cp++ = CLIP (((factor - j) * val_a + j * val_b 2478141cc406Sopenharmony_ci + factor / 2) / factor); 2479141cc406Sopenharmony_ci 2480141cc406Sopenharmony_ci for (i = 1; i < 256; i++) 2481141cc406Sopenharmony_ci { 2482141cc406Sopenharmony_ci if (color == 0) 2483141cc406Sopenharmony_ci { 2484141cc406Sopenharmony_ci val_a = s->gamma_table[0][i - 1]; 2485141cc406Sopenharmony_ci val_b = s->gamma_table[0][i]; 2486141cc406Sopenharmony_ci } 2487141cc406Sopenharmony_ci else 2488141cc406Sopenharmony_ci { 2489141cc406Sopenharmony_ci /* compose intensity gamma and color channel gamma: */ 2490141cc406Sopenharmony_ci val_a = s->gamma_table[0][s->gamma_table[color][i - 1]]; 2491141cc406Sopenharmony_ci val_b = s->gamma_table[0][s->gamma_table[color][i]]; 2492141cc406Sopenharmony_ci } 2493141cc406Sopenharmony_ci 2494141cc406Sopenharmony_ci /* Interpolate next entries from the 256 entry table */ 2495141cc406Sopenharmony_ci for (j = 0; j < factor; j++) 2496141cc406Sopenharmony_ci *cp++ = CLIP (((factor - j) * val_a + j * val_b 2497141cc406Sopenharmony_ci + factor / 2) / factor); 2498141cc406Sopenharmony_ci } 2499141cc406Sopenharmony_ci 2500141cc406Sopenharmony_ci DBG (5, "send_gamma_table_se: sending table for color %d\n", 2501141cc406Sopenharmony_ci gamma[6]); 2502141cc406Sopenharmony_ci status = dev_cmd (s, gamma, CDB_SIZE (MUSTEK_SCSI_SEND_DATA) 2503141cc406Sopenharmony_ci + s->hw->gamma_length, 0, 0); 2504141cc406Sopenharmony_ci ++color; 2505141cc406Sopenharmony_ci } 2506141cc406Sopenharmony_ci while ((color != 1) & (color < 4) & (status == SANE_STATUS_GOOD)); 2507141cc406Sopenharmony_ci 2508141cc406Sopenharmony_ci return status; 2509141cc406Sopenharmony_ci } 2510141cc406Sopenharmony_ci else 2511141cc406Sopenharmony_ci { 2512141cc406Sopenharmony_ci /* In lineart mode the threshold is encoded in byte 8 as follows */ 2513141cc406Sopenharmony_ci /* brightest -> 00 01 02 ... 7F 80 81 82 ... FF <- darkest image */ 2514141cc406Sopenharmony_ci gamma[6] = 0x04; 2515141cc406Sopenharmony_ci gamma[8] = 128 - 127 * SANE_UNFIX (s->val[OPT_BRIGHTNESS].w) / 100.0; 2516141cc406Sopenharmony_ci 2517141cc406Sopenharmony_ci DBG (5, "send_gamma_table_se: sending lineart threshold %2X\n", 2518141cc406Sopenharmony_ci gamma[8]); 2519141cc406Sopenharmony_ci return dev_cmd (s, gamma, CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0); 2520141cc406Sopenharmony_ci } 2521141cc406Sopenharmony_ci} 2522141cc406Sopenharmony_ci 2523141cc406Sopenharmony_ci/* Paragon series */ 2524141cc406Sopenharmony_cistatic SANE_Status 2525141cc406Sopenharmony_cimode_select_paragon (Mustek_Scanner * s, SANE_Int color_code) 2526141cc406Sopenharmony_ci{ 2527141cc406Sopenharmony_ci SANE_Int speed_code; 2528141cc406Sopenharmony_ci SANE_Byte mode[19], *cp; 2529141cc406Sopenharmony_ci 2530141cc406Sopenharmony_ci /* calculate funky speed code: */ 2531141cc406Sopenharmony_ci for (speed_code = 0; speed_list[speed_code]; ++speed_code) 2532141cc406Sopenharmony_ci { 2533141cc406Sopenharmony_ci if (strcmp (speed_list[speed_code], s->val[OPT_SPEED].s) == 0) 2534141cc406Sopenharmony_ci break; 2535141cc406Sopenharmony_ci } 2536141cc406Sopenharmony_ci if (speed_code > 4) 2537141cc406Sopenharmony_ci speed_code = 4; 2538141cc406Sopenharmony_ci else if (speed_code < 0) 2539141cc406Sopenharmony_ci speed_code = 0; 2540141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2541141cc406Sopenharmony_ci { 2542141cc406Sopenharmony_ci speed_code = 5 - speed_code; /* 1 is fast, 5 is slow */ 2543141cc406Sopenharmony_ci } 2544141cc406Sopenharmony_ci else 2545141cc406Sopenharmony_ci { 2546141cc406Sopenharmony_ci speed_code = 4 - speed_code; /* 0 is fast, 4 is slow */ 2547141cc406Sopenharmony_ci } 2548141cc406Sopenharmony_ci memset (mode, 0, sizeof (mode)); 2549141cc406Sopenharmony_ci mode[0] = MUSTEK_SCSI_MODE_SELECT; 2550141cc406Sopenharmony_ci 2551141cc406Sopenharmony_ci /* set command length and resolution code: */ 2552141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2553141cc406Sopenharmony_ci { 2554141cc406Sopenharmony_ci mode[4] = 0x0b; 2555141cc406Sopenharmony_ci mode[7] = s->resolution_code; 2556141cc406Sopenharmony_ci } 2557141cc406Sopenharmony_ci else 2558141cc406Sopenharmony_ci { 2559141cc406Sopenharmony_ci mode[4] = 0x0d; 2560141cc406Sopenharmony_ci cp = mode + 17; 2561141cc406Sopenharmony_ci STORE16L (cp, s->resolution_code); 2562141cc406Sopenharmony_ci } 2563141cc406Sopenharmony_ci /* set mode byte: */ 2564141cc406Sopenharmony_ci mode[6] = 0x83 | (color_code << 5); 2565141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_USE_EIGHTS)) 2566141cc406Sopenharmony_ci mode[6] |= 0x08; 2567141cc406Sopenharmony_ci if (s->custom_halftone_pattern) 2568141cc406Sopenharmony_ci mode[6] |= 0x10; 2569141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PARAGON_1) 2570141cc406Sopenharmony_ci { 2571141cc406Sopenharmony_ci if ((s->mode == MUSTEK_MODE_LINEART) 2572141cc406Sopenharmony_ci || (s->mode == MUSTEK_MODE_HALFTONE)) 2573141cc406Sopenharmony_ci { 2574141cc406Sopenharmony_ci mode[8] = 2575141cc406Sopenharmony_ci encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)); 2576141cc406Sopenharmony_ci mode[9] = 2577141cc406Sopenharmony_ci encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w)); 2578141cc406Sopenharmony_ci } 2579141cc406Sopenharmony_ci else 2580141cc406Sopenharmony_ci { 2581141cc406Sopenharmony_ci mode[8] = 0x0c; 2582141cc406Sopenharmony_ci mode[9] = 0x0c; 2583141cc406Sopenharmony_ci } 2584141cc406Sopenharmony_ci mode[10] = 2; /* grain */ 2585141cc406Sopenharmony_ci if (s->val[OPT_PREVIEW].w && s->val[OPT_FAST_PREVIEW].w) 2586141cc406Sopenharmony_ci mode[11] = 0x01; 2587141cc406Sopenharmony_ci else if ((s->mode == MUSTEK_MODE_COLOR) 2588141cc406Sopenharmony_ci || (s->mode == MUSTEK_MODE_HALFTONE)) 2589141cc406Sopenharmony_ci mode[11] = 0x00; /* speed */ 2590141cc406Sopenharmony_ci else 2591141cc406Sopenharmony_ci mode[11] = 0x02; /* speed */ 2592141cc406Sopenharmony_ci mode[12] = 0x00; /* shadow param not used by Mustek */ 2593141cc406Sopenharmony_ci mode[13] = 0xff; /* highlight only used by some scanners */ 2594141cc406Sopenharmony_ci mode[14] = 0x70; /* paper- */ 2595141cc406Sopenharmony_ci mode[15] = 0x00; /* length */ 2596141cc406Sopenharmony_ci mode[16] = 0x53; /* midtone param not used by Mustek */ 2597141cc406Sopenharmony_ci } 2598141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PARAGON_2) 2599141cc406Sopenharmony_ci { 2600141cc406Sopenharmony_ci mode[8] = encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)); 2601141cc406Sopenharmony_ci mode[9] = encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w)); 2602141cc406Sopenharmony_ci mode[10] = 2; /* grain */ 2603141cc406Sopenharmony_ci if ((s->mode == MUSTEK_MODE_COLOR) || (s->mode == MUSTEK_MODE_HALFTONE)) 2604141cc406Sopenharmony_ci mode[11] = 0x00; /* speed */ 2605141cc406Sopenharmony_ci else 2606141cc406Sopenharmony_ci mode[11] = 0x02; /* speed */ 2607141cc406Sopenharmony_ci mode[12] = 0x00; /* shadow param not used by Mustek */ 2608141cc406Sopenharmony_ci mode[13] = 0x00; /* highlight param not used by Mustek */ 2609141cc406Sopenharmony_ci mode[14] = 0x5c; /* paper- */ 2610141cc406Sopenharmony_ci mode[15] = 0x00; /* length */ 2611141cc406Sopenharmony_ci mode[16] = 0x41; /* midtone param not used by Mustek */ 2612141cc406Sopenharmony_ci } 2613141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2614141cc406Sopenharmony_ci { 2615141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 2616141cc406Sopenharmony_ci { 2617141cc406Sopenharmony_ci mode[8] = encode_percentage 2618141cc406Sopenharmony_ci (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS + s->pass + 1].w - 1)); 2619141cc406Sopenharmony_ci mode[9] = encode_percentage 2620141cc406Sopenharmony_ci (s, SANE_UNFIX (s->val[OPT_CONTRAST + s->pass + 1].w - 1)); 2621141cc406Sopenharmony_ci } 2622141cc406Sopenharmony_ci else 2623141cc406Sopenharmony_ci { 2624141cc406Sopenharmony_ci mode[8] = encode_percentage 2625141cc406Sopenharmony_ci (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w - 1)); 2626141cc406Sopenharmony_ci mode[9] = encode_percentage 2627141cc406Sopenharmony_ci (s, SANE_UNFIX (s->val[OPT_CONTRAST].w - 1)); 2628141cc406Sopenharmony_ci } 2629141cc406Sopenharmony_ci mode[10] = s->halftone_pattern_type; 2630141cc406Sopenharmony_ci mode[11] = speed_code; /* lamp setting not supported yet */ 2631141cc406Sopenharmony_ci mode[12] = 0; /* shadow param not used by Mustek */ 2632141cc406Sopenharmony_ci mode[13] = 0; /* highlight param not used by Mustek */ 2633141cc406Sopenharmony_ci mode[14] = mode[15] = 0; /* paperlength not used by Mustek */ 2634141cc406Sopenharmony_ci mode[16] = 0; /* midtone param not used by Mustek */ 2635141cc406Sopenharmony_ci } 2636141cc406Sopenharmony_ci else 2637141cc406Sopenharmony_ci { 2638141cc406Sopenharmony_ci mode[8] = encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)); 2639141cc406Sopenharmony_ci mode[9] = encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w)); 2640141cc406Sopenharmony_ci mode[10] = s->halftone_pattern_type; 2641141cc406Sopenharmony_ci mode[11] = speed_code; /* lamp setting not supported yet */ 2642141cc406Sopenharmony_ci mode[12] = 0; /* shadow param not used by Mustek */ 2643141cc406Sopenharmony_ci mode[13] = 0; /* highlight param not used by Mustek */ 2644141cc406Sopenharmony_ci mode[14] = mode[15] = 0; /* paperlength not used by Mustek */ 2645141cc406Sopenharmony_ci mode[16] = 0; /* midtone param not used by Mustek */ 2646141cc406Sopenharmony_ci } 2647141cc406Sopenharmony_ci 2648141cc406Sopenharmony_ci DBG (5, "mode_select: resolution_code=%d (0x%x)\n", s->resolution_code, 2649141cc406Sopenharmony_ci s->resolution_code); 2650141cc406Sopenharmony_ci return dev_cmd (s, mode, 6 + mode[4], 0, 0); 2651141cc406Sopenharmony_ci} 2652141cc406Sopenharmony_ci 2653141cc406Sopenharmony_ci/* Pro series */ 2654141cc406Sopenharmony_cistatic SANE_Status 2655141cc406Sopenharmony_cimode_select_pro (Mustek_Scanner * s) 2656141cc406Sopenharmony_ci{ 2657141cc406Sopenharmony_ci SANE_Byte mode[19], *cp; 2658141cc406Sopenharmony_ci 2659141cc406Sopenharmony_ci memset (mode, 0, sizeof (mode)); 2660141cc406Sopenharmony_ci 2661141cc406Sopenharmony_ci mode[0] = MUSTEK_SCSI_MODE_SELECT; 2662141cc406Sopenharmony_ci mode[4] = 0x0d; 2663141cc406Sopenharmony_ci 2664141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 2665141cc406Sopenharmony_ci { 2666141cc406Sopenharmony_ci if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0) 2667141cc406Sopenharmony_ci mode[6] = 0xE0; 2668141cc406Sopenharmony_ci else 2669141cc406Sopenharmony_ci mode[6] = 0x60; 2670141cc406Sopenharmony_ci } 2671141cc406Sopenharmony_ci else if (s->mode & MUSTEK_MODE_GRAY) 2672141cc406Sopenharmony_ci { 2673141cc406Sopenharmony_ci if (s->val[OPT_FAST_GRAY_MODE].w) 2674141cc406Sopenharmony_ci mode[6] = 0x20; 2675141cc406Sopenharmony_ci else 2676141cc406Sopenharmony_ci mode[6] = 0x40; 2677141cc406Sopenharmony_ci } 2678141cc406Sopenharmony_ci else 2679141cc406Sopenharmony_ci mode[6] = 0x00; /* lineart */ 2680141cc406Sopenharmony_ci 2681141cc406Sopenharmony_ci mode[7] = 0; 2682141cc406Sopenharmony_ci mode[8] = 0; 2683141cc406Sopenharmony_ci mode[9] = 0; 2684141cc406Sopenharmony_ci mode[10] = 0; 2685141cc406Sopenharmony_ci mode[11] = 0x00; 2686141cc406Sopenharmony_ci mode[12] = 0x27; 2687141cc406Sopenharmony_ci mode[13] = 0xb0; 2688141cc406Sopenharmony_ci mode[14] = 0x04; 2689141cc406Sopenharmony_ci mode[15] = 0x43; 2690141cc406Sopenharmony_ci mode[16] = 0x41; 2691141cc406Sopenharmony_ci 2692141cc406Sopenharmony_ci cp = mode + 17; 2693141cc406Sopenharmony_ci STORE16L (cp, s->resolution_code); 2694141cc406Sopenharmony_ci 2695141cc406Sopenharmony_ci DBG (5, "mode_select_pro: resolution_code=%d (0x%x), mode=0x%x\n", 2696141cc406Sopenharmony_ci s->resolution_code, s->resolution_code, mode[6]); 2697141cc406Sopenharmony_ci return dev_cmd (s, mode, 6 + mode[4], 0, 0); 2698141cc406Sopenharmony_ci} 2699141cc406Sopenharmony_ci 2700141cc406Sopenharmony_ci/* Paragon and Pro series. According to Mustek, the only builtin gamma 2701141cc406Sopenharmony_ci table is a linear table, so all we support here is user-defined 2702141cc406Sopenharmony_ci gamma tables. */ 2703141cc406Sopenharmony_cistatic SANE_Status 2704141cc406Sopenharmony_cigamma_correction (Mustek_Scanner * s, SANE_Int color_code) 2705141cc406Sopenharmony_ci{ 2706141cc406Sopenharmony_ci SANE_Int i, j, table = 0, len = 0, bytes_per_channel, num_channels = 1; 2707141cc406Sopenharmony_ci SANE_Byte gamma[4096 + 10], val, *cp; /* for Paragon models 3 x 256 is the 2708141cc406Sopenharmony_ci maximum. Pro needs 4096 bytes */ 2709141cc406Sopenharmony_ci 2710141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_N) 2711141cc406Sopenharmony_ci && ((s->mode & MUSTEK_MODE_LINEART) 2712141cc406Sopenharmony_ci || (s->mode & MUSTEK_MODE_HALFTONE))) 2713141cc406Sopenharmony_ci { 2714141cc406Sopenharmony_ci /* sigh! - the 600 II N needs a (dummy) table download even for 2715141cc406Sopenharmony_ci lineart and halftone mode, else it produces a completely 2716141cc406Sopenharmony_ci white image. Thank Mustek for their buggy firmware ! */ 2717141cc406Sopenharmony_ci memset (gamma, 0, sizeof (gamma)); 2718141cc406Sopenharmony_ci gamma[0] = MUSTEK_SCSI_LOOKUP_TABLE; 2719141cc406Sopenharmony_ci gamma[2] = 0x0; /* indicate any preloaded gamma table */ 2720141cc406Sopenharmony_ci DBG (5, "gamma_correction: sending dummy gamma table\n"); 2721141cc406Sopenharmony_ci return dev_cmd (s, gamma, 6, 0, 0); 2722141cc406Sopenharmony_ci } 2723141cc406Sopenharmony_ci 2724141cc406Sopenharmony_ci if (((s->mode & MUSTEK_MODE_LINEART) || (s->mode & MUSTEK_MODE_HALFTONE)) 2725141cc406Sopenharmony_ci && !(s->hw->flags & MUSTEK_FLAG_PRO)) 2726141cc406Sopenharmony_ci { 2727141cc406Sopenharmony_ci DBG (5, "gamma_correction: nothing to do in lineart mode -- exiting\n"); 2728141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2729141cc406Sopenharmony_ci } 2730141cc406Sopenharmony_ci 2731141cc406Sopenharmony_ci if ((!s->val[OPT_CUSTOM_GAMMA].w) && (!(s->hw->flags & MUSTEK_FLAG_PRO))) 2732141cc406Sopenharmony_ci { 2733141cc406Sopenharmony_ci /* Do we need to upload a gamma table even if the user didn't select 2734141cc406Sopenharmony_ci this option? Some scanners need this work around. */ 2735141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_FORCE_GAMMA) || 2736141cc406Sopenharmony_ci !((s->mode & MUSTEK_MODE_COLOR) || (s->mode & MUSTEK_MODE_GRAY))) 2737141cc406Sopenharmony_ci { 2738141cc406Sopenharmony_ci DBG (5, 2739141cc406Sopenharmony_ci "gamma_correction: no custom table selected -- exititing\n"); 2740141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2741141cc406Sopenharmony_ci } 2742141cc406Sopenharmony_ci } 2743141cc406Sopenharmony_ci 2744141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 2745141cc406Sopenharmony_ci { 2746141cc406Sopenharmony_ci table = 1; 2747141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2748141cc406Sopenharmony_ci table += s->pass; 2749141cc406Sopenharmony_ci else 2750141cc406Sopenharmony_ci { 2751141cc406Sopenharmony_ci if ((color_code == MUSTEK_CODE_GRAY) 2752141cc406Sopenharmony_ci && !(s->hw->flags & MUSTEK_FLAG_PRO)) 2753141cc406Sopenharmony_ci num_channels = 3; 2754141cc406Sopenharmony_ci else 2755141cc406Sopenharmony_ci table = color_code; 2756141cc406Sopenharmony_ci } 2757141cc406Sopenharmony_ci } 2758141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_N) 2759141cc406Sopenharmony_ci { 2760141cc406Sopenharmony_ci /* it seems 600 II N (firmware 1.x at least) wants 768 bytes in 2761141cc406Sopenharmony_ci * gray mode too */ 2762141cc406Sopenharmony_ci num_channels = 3; 2763141cc406Sopenharmony_ci } 2764141cc406Sopenharmony_ci 2765141cc406Sopenharmony_ci memset (gamma, 0, sizeof (gamma)); 2766141cc406Sopenharmony_ci gamma[0] = MUSTEK_SCSI_LOOKUP_TABLE; 2767141cc406Sopenharmony_ci 2768141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PRO) 2769141cc406Sopenharmony_ci { 2770141cc406Sopenharmony_ci bytes_per_channel = 4096; 2771141cc406Sopenharmony_ci len = bytes_per_channel; 2772141cc406Sopenharmony_ci if (s->mode == MUSTEK_MODE_COLOR) 2773141cc406Sopenharmony_ci { 2774141cc406Sopenharmony_ci gamma[9] = (color_code << 6); /* color */ 2775141cc406Sopenharmony_ci if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0) 2776141cc406Sopenharmony_ci gamma[2] = 0x7f; /* medium brightness */ 2777141cc406Sopenharmony_ci } 2778141cc406Sopenharmony_ci else if (s->mode == MUSTEK_MODE_GRAY) 2779141cc406Sopenharmony_ci { 2780141cc406Sopenharmony_ci gamma[9] = 0x80; /* grayscale */ 2781141cc406Sopenharmony_ci if (s->val[OPT_FAST_GRAY_MODE].w) 2782141cc406Sopenharmony_ci gamma[2] = 0x7f; /* medium brightness */ 2783141cc406Sopenharmony_ci } 2784141cc406Sopenharmony_ci else /* lineart */ 2785141cc406Sopenharmony_ci { 2786141cc406Sopenharmony_ci gamma[2] = 2787141cc406Sopenharmony_ci 128 - 127 * SANE_UNFIX (s->val[OPT_BRIGHTNESS].w) / 100.0; 2788141cc406Sopenharmony_ci gamma[9] = 0x80; /* grayscale/lineart */ 2789141cc406Sopenharmony_ci DBG (5, "gamma_correction: sending brightness information\n"); 2790141cc406Sopenharmony_ci } 2791141cc406Sopenharmony_ci gamma[7] = (len >> 8) & 0xff; /* big endian! */ 2792141cc406Sopenharmony_ci gamma[8] = (len >> 0) & 0xff; 2793141cc406Sopenharmony_ci } 2794141cc406Sopenharmony_ci else 2795141cc406Sopenharmony_ci { 2796141cc406Sopenharmony_ci bytes_per_channel = 256; 2797141cc406Sopenharmony_ci len = num_channels * bytes_per_channel; 2798141cc406Sopenharmony_ci gamma[2] = 0x27; /* indicate user-selected gamma table */ 2799141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 2800141cc406Sopenharmony_ci { 2801141cc406Sopenharmony_ci /* 600 II N always uses 6-byte cdb */ 2802141cc406Sopenharmony_ci gamma[3] = (len >> 8) & 0xff; /* big endian! */ 2803141cc406Sopenharmony_ci gamma[4] = (len >> 0) & 0xff; 2804141cc406Sopenharmony_ci /* no way to pass color_code (?) */ 2805141cc406Sopenharmony_ci } 2806141cc406Sopenharmony_ci else 2807141cc406Sopenharmony_ci { 2808141cc406Sopenharmony_ci gamma[7] = (len >> 8) & 0xff; /* big endian! */ 2809141cc406Sopenharmony_ci gamma[8] = (len >> 0) & 0xff; 2810141cc406Sopenharmony_ci gamma[9] = (color_code << 6); 2811141cc406Sopenharmony_ci } 2812141cc406Sopenharmony_ci } 2813141cc406Sopenharmony_ci 2814141cc406Sopenharmony_ci if (len > 0) 2815141cc406Sopenharmony_ci { 2816141cc406Sopenharmony_ci cp = gamma + 10; 2817141cc406Sopenharmony_ci for (j = 0; j < num_channels; ++j) 2818141cc406Sopenharmony_ci { 2819141cc406Sopenharmony_ci for (i = 0; i < bytes_per_channel; ++i) 2820141cc406Sopenharmony_ci { 2821141cc406Sopenharmony_ci if (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE) 2822141cc406Sopenharmony_ci val = s->gamma_table[table][i * 256 / bytes_per_channel]; 2823141cc406Sopenharmony_ci else 2824141cc406Sopenharmony_ci val = i * 256 / bytes_per_channel; 2825141cc406Sopenharmony_ci if ((s->mode & MUSTEK_MODE_COLOR) 2826141cc406Sopenharmony_ci && (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)) 2827141cc406Sopenharmony_ci /* compose intensity gamma and color channel gamma: */ 2828141cc406Sopenharmony_ci val = s->gamma_table[0][val]; 2829141cc406Sopenharmony_ci *cp++ = val; 2830141cc406Sopenharmony_ci } 2831141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_N) 2832141cc406Sopenharmony_ci || !(s->mode & MUSTEK_MODE_GRAY)) 2833141cc406Sopenharmony_ci table++; 2834141cc406Sopenharmony_ci } 2835141cc406Sopenharmony_ci } 2836141cc406Sopenharmony_ci DBG (5, "gamma_correction: sending gamma table of %d bytes\n", len); 2837141cc406Sopenharmony_ci return dev_cmd (s, gamma, 10 + len, 0, 0); 2838141cc406Sopenharmony_ci} 2839141cc406Sopenharmony_ci 2840141cc406Sopenharmony_cistatic SANE_Status 2841141cc406Sopenharmony_cisend_gamma_table (Mustek_Scanner * s) 2842141cc406Sopenharmony_ci{ 2843141cc406Sopenharmony_ci SANE_Status status; 2844141cc406Sopenharmony_ci 2845141cc406Sopenharmony_ci if (s->one_pass_color_scan) 2846141cc406Sopenharmony_ci { 2847141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 2848141cc406Sopenharmony_ci /* This _should_ work for all one-pass scanners (not just 2849141cc406Sopenharmony_ci AB306N scanners), but it doesn't work for my Paragon 2850141cc406Sopenharmony_ci 600 II SP with firmware rev 1.01. Too bad, since it would 2851141cc406Sopenharmony_ci simplify the gamma correction code quite a bit. */ 2852141cc406Sopenharmony_ci status = gamma_correction (s, MUSTEK_CODE_GRAY); 2853141cc406Sopenharmony_ci else 2854141cc406Sopenharmony_ci { 2855141cc406Sopenharmony_ci status = gamma_correction (s, MUSTEK_CODE_RED); 2856141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2857141cc406Sopenharmony_ci return status; 2858141cc406Sopenharmony_ci 2859141cc406Sopenharmony_ci status = gamma_correction (s, MUSTEK_CODE_GREEN); 2860141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2861141cc406Sopenharmony_ci return status; 2862141cc406Sopenharmony_ci 2863141cc406Sopenharmony_ci status = gamma_correction (s, MUSTEK_CODE_BLUE); 2864141cc406Sopenharmony_ci } 2865141cc406Sopenharmony_ci } 2866141cc406Sopenharmony_ci else 2867141cc406Sopenharmony_ci status = gamma_correction (s, MUSTEK_CODE_GRAY); 2868141cc406Sopenharmony_ci return status; 2869141cc406Sopenharmony_ci} 2870141cc406Sopenharmony_ci 2871141cc406Sopenharmony_ci 2872141cc406Sopenharmony_ci/* ScanExpress and Paragon series */ 2873141cc406Sopenharmony_cistatic SANE_Status 2874141cc406Sopenharmony_cistart_scan (Mustek_Scanner * s) 2875141cc406Sopenharmony_ci{ 2876141cc406Sopenharmony_ci SANE_Byte start[6]; 2877141cc406Sopenharmony_ci SANE_Status status; 2878141cc406Sopenharmony_ci 2879141cc406Sopenharmony_ci memset (start, 0, sizeof (start)); 2880141cc406Sopenharmony_ci start[0] = MUSTEK_SCSI_START_STOP; 2881141cc406Sopenharmony_ci start[4] = 0x01; 2882141cc406Sopenharmony_ci 2883141cc406Sopenharmony_ci DBG (4, "start_scan\n"); 2884141cc406Sopenharmony_ci /* ScanExpress and Pro models don't have any variants */ 2885141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_SE) && !(s->hw->flags & MUSTEK_FLAG_PRO)) 2886141cc406Sopenharmony_ci { 2887141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 2888141cc406Sopenharmony_ci { 2889141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2890141cc406Sopenharmony_ci start[4] |= ((s->pass + 1) << 3); 2891141cc406Sopenharmony_ci else 2892141cc406Sopenharmony_ci start[4] |= 0x20; 2893141cc406Sopenharmony_ci } 2894141cc406Sopenharmony_ci /* or in single/multi bit: */ 2895141cc406Sopenharmony_ci start[4] |= ((s->mode & MUSTEK_MODE_LINEART) 2896141cc406Sopenharmony_ci || (s->mode & MUSTEK_MODE_HALFTONE)) ? 0 : (1 << 6); 2897141cc406Sopenharmony_ci 2898141cc406Sopenharmony_ci /* or in expanded resolution bit: */ 2899141cc406Sopenharmony_ci if (s->val[OPT_RESOLUTION].w > (s->hw->dpi_range.max / 2) 2900141cc406Sopenharmony_ci && ((s->hw->flags & MUSTEK_FLAG_THREE_PASS) 2901141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_PARAGON_1) 2902141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_PARAGON_2))) 2903141cc406Sopenharmony_ci start[4] |= 1 << 7; 2904141cc406Sopenharmony_ci 2905141cc406Sopenharmony_ci /* block mode (or whatever) */ 2906141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_USE_BLOCK) 2907141cc406Sopenharmony_ci { 2908141cc406Sopenharmony_ci start[5] = 0x08; 2909141cc406Sopenharmony_ci DBG (4, "start_scan: using block mode\n"); 2910141cc406Sopenharmony_ci } 2911141cc406Sopenharmony_ci } 2912141cc406Sopenharmony_ci 2913141cc406Sopenharmony_ci status = dev_cmd (s, start, sizeof (start), 0, 0); 2914141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2915141cc406Sopenharmony_ci DBG (1, "start_scan returned status %s\n", sane_strstatus (status)); 2916141cc406Sopenharmony_ci return status; 2917141cc406Sopenharmony_ci} 2918141cc406Sopenharmony_ci 2919141cc406Sopenharmony_cistatic SANE_Status 2920141cc406Sopenharmony_cido_eof (Mustek_Scanner * s) 2921141cc406Sopenharmony_ci{ 2922141cc406Sopenharmony_ci if (s->pipe >= 0) 2923141cc406Sopenharmony_ci { 2924141cc406Sopenharmony_ci close (s->pipe); 2925141cc406Sopenharmony_ci s->pipe = -1; 2926141cc406Sopenharmony_ci DBG (5, "do_eof: closing pipe\n"); 2927141cc406Sopenharmony_ci } 2928141cc406Sopenharmony_ci return SANE_STATUS_EOF; 2929141cc406Sopenharmony_ci} 2930141cc406Sopenharmony_ci 2931141cc406Sopenharmony_cistatic SANE_Status 2932141cc406Sopenharmony_cido_stop (Mustek_Scanner * s) 2933141cc406Sopenharmony_ci{ 2934141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 2935141cc406Sopenharmony_ci 2936141cc406Sopenharmony_ci DBG (5, "do_stop\n"); 2937141cc406Sopenharmony_ci 2938141cc406Sopenharmony_ci if (s->cancelled) 2939141cc406Sopenharmony_ci status = SANE_STATUS_CANCELLED; 2940141cc406Sopenharmony_ci 2941141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 2942141cc406Sopenharmony_ci s->pass = 0; 2943141cc406Sopenharmony_ci 2944141cc406Sopenharmony_ci if (sanei_thread_is_valid (s->reader_pid)) 2945141cc406Sopenharmony_ci { 2946141cc406Sopenharmony_ci SANE_Int exit_status; 2947141cc406Sopenharmony_ci struct timeval now; 2948141cc406Sopenharmony_ci long int scan_time; 2949141cc406Sopenharmony_ci long int scan_size; 2950141cc406Sopenharmony_ci SANE_Pid pid; 2951141cc406Sopenharmony_ci 2952141cc406Sopenharmony_ci /* print scanning time */ 2953141cc406Sopenharmony_ci gettimeofday (&now, 0); 2954141cc406Sopenharmony_ci scan_time = now.tv_sec - s->start_time; 2955141cc406Sopenharmony_ci if (scan_time < 1) 2956141cc406Sopenharmony_ci scan_time = 1; 2957141cc406Sopenharmony_ci scan_size = s->hw->bpl * s->hw->lines / 1024; 2958141cc406Sopenharmony_ci DBG (2, "Scanning time was %ld seconds, %ld kB/s\n", scan_time, 2959141cc406Sopenharmony_ci scan_size / scan_time); 2960141cc406Sopenharmony_ci 2961141cc406Sopenharmony_ci if (s->total_bytes == s->params.lines * s->params.bytes_per_line) 2962141cc406Sopenharmony_ci DBG (3, "Scanned %d bytes as expected\n", s->total_bytes); 2963141cc406Sopenharmony_ci else if (s->total_bytes < s->params.lines * s->params.bytes_per_line) 2964141cc406Sopenharmony_ci DBG (3, "Scanned %d bytes, expected %d bytes\n", s->total_bytes, 2965141cc406Sopenharmony_ci s->params.lines * s->params.bytes_per_line); 2966141cc406Sopenharmony_ci else 2967141cc406Sopenharmony_ci DBG (1, "Warning: Scanned %d bytes, but expected only %d bytes\n", 2968141cc406Sopenharmony_ci s->total_bytes, s->params.lines * s->params.bytes_per_line); 2969141cc406Sopenharmony_ci 2970141cc406Sopenharmony_ci /* ensure child knows it's time to stop: */ 2971141cc406Sopenharmony_ci DBG (5, "do_stop: terminating reader process\n"); 2972141cc406Sopenharmony_ci sanei_thread_kill (s->reader_pid); 2973141cc406Sopenharmony_ci 2974141cc406Sopenharmony_ci pid = sanei_thread_waitpid (s->reader_pid, &exit_status); 2975141cc406Sopenharmony_ci if (!sanei_thread_is_valid (pid)) 2976141cc406Sopenharmony_ci { 2977141cc406Sopenharmony_ci DBG (1, 2978141cc406Sopenharmony_ci "do_stop: sanei_thread_waitpid failed, already terminated? (%s)\n", 2979141cc406Sopenharmony_ci strerror (errno)); 2980141cc406Sopenharmony_ci } 2981141cc406Sopenharmony_ci else 2982141cc406Sopenharmony_ci { 2983141cc406Sopenharmony_ci DBG (2, "do_stop: reader process terminated with status %s\n", 2984141cc406Sopenharmony_ci sane_strstatus (exit_status)); 2985141cc406Sopenharmony_ci if (status != SANE_STATUS_CANCELLED 2986141cc406Sopenharmony_ci && exit_status != SANE_STATUS_GOOD) 2987141cc406Sopenharmony_ci status = exit_status; 2988141cc406Sopenharmony_ci } 2989141cc406Sopenharmony_ci 2990141cc406Sopenharmony_ci sanei_thread_invalidate (s->reader_pid); 2991141cc406Sopenharmony_ci } 2992141cc406Sopenharmony_ci 2993141cc406Sopenharmony_ci if (s->fd >= 0) 2994141cc406Sopenharmony_ci { 2995141cc406Sopenharmony_ci if (!sanei_thread_is_forked ()) 2996141cc406Sopenharmony_ci sanei_scsi_req_flush_all (); /* flush SCSI queue */ 2997141cc406Sopenharmony_ci 2998141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PRO) 2999141cc406Sopenharmony_ci { 3000141cc406Sopenharmony_ci if (s->total_bytes < s->params.lines * s->params.bytes_per_line) 3001141cc406Sopenharmony_ci status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop), 3002141cc406Sopenharmony_ci 0, 0); 3003141cc406Sopenharmony_ci dev_wait_ready (s); 3004141cc406Sopenharmony_ci } 3005141cc406Sopenharmony_ci else if ((s->hw->flags & MUSTEK_FLAG_PARAGON_1) 3006141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_PARAGON_2) 3007141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 3008141cc406Sopenharmony_ci { 3009141cc406Sopenharmony_ci if (s->cancelled && 3010141cc406Sopenharmony_ci (s->total_bytes < s->params.lines * s->params.bytes_per_line)) 3011141cc406Sopenharmony_ci status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop), 3012141cc406Sopenharmony_ci 0, 0); 3013141cc406Sopenharmony_ci } 3014141cc406Sopenharmony_ci else 3015141cc406Sopenharmony_ci status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop), 0, 0); 3016141cc406Sopenharmony_ci 3017141cc406Sopenharmony_ci if (force_wait) 3018141cc406Sopenharmony_ci { 3019141cc406Sopenharmony_ci DBG (5, "do_stop: waiting for scanner to be ready\n"); 3020141cc406Sopenharmony_ci dev_wait_ready (s); 3021141cc406Sopenharmony_ci } 3022141cc406Sopenharmony_ci 3023141cc406Sopenharmony_ci do_eof (s); 3024141cc406Sopenharmony_ci DBG (5, "do_stop: closing scanner\n"); 3025141cc406Sopenharmony_ci dev_close (s); 3026141cc406Sopenharmony_ci s->fd = -1; 3027141cc406Sopenharmony_ci } 3028141cc406Sopenharmony_ci 3029141cc406Sopenharmony_ci DBG (5, "do_stop: finished\n"); 3030141cc406Sopenharmony_ci return status; 3031141cc406Sopenharmony_ci} 3032141cc406Sopenharmony_ci 3033141cc406Sopenharmony_ci/* Paragon I + II: Determine the CCD's distance between the primary color 3034141cc406Sopenharmony_ci lines. */ 3035141cc406Sopenharmony_cistatic SANE_Status 3036141cc406Sopenharmony_ciline_distance (Mustek_Scanner * s) 3037141cc406Sopenharmony_ci{ 3038141cc406Sopenharmony_ci SANE_Int factor, color, res, peak_res; 3039141cc406Sopenharmony_ci SANE_Status status; 3040141cc406Sopenharmony_ci SANE_Byte result[5]; 3041141cc406Sopenharmony_ci size_t len; 3042141cc406Sopenharmony_ci 3043141cc406Sopenharmony_ci memset (result, 0, 5); 3044141cc406Sopenharmony_ci 3045141cc406Sopenharmony_ci res = SANE_UNFIX (s->val[OPT_RESOLUTION].w) + 0.5; 3046141cc406Sopenharmony_ci peak_res = SANE_UNFIX (s->hw->dpi_range.max) + 0.5; 3047141cc406Sopenharmony_ci 3048141cc406Sopenharmony_ci s->ld.buf[0] = NULL; 3049141cc406Sopenharmony_ci 3050141cc406Sopenharmony_ci len = sizeof (result); 3051141cc406Sopenharmony_ci status = dev_cmd (s, scsi_ccd_distance, sizeof (scsi_ccd_distance), 3052141cc406Sopenharmony_ci result, &len); 3053141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3054141cc406Sopenharmony_ci return status; 3055141cc406Sopenharmony_ci 3056141cc406Sopenharmony_ci DBG (3, "line_distance: got factor=%d, (r/g/b)=(%d/%d/%d)\n", 3057141cc406Sopenharmony_ci result[0] | (result[1] << 8), result[2], result[3], result[4]); 3058141cc406Sopenharmony_ci 3059141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_LD_FIX) 3060141cc406Sopenharmony_ci { 3061141cc406Sopenharmony_ci result[0] = 0xff; 3062141cc406Sopenharmony_ci result[1] = 0xff; 3063141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 3064141cc406Sopenharmony_ci { 3065141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 3066141cc406Sopenharmony_ci { 3067141cc406Sopenharmony_ci /* According to Andreas Czechanowski, the line-distance values 3068141cc406Sopenharmony_ci returned for the AB306N scanners are garbage, so we have to 3069141cc406Sopenharmony_ci fix things up manually. Not good. 3070141cc406Sopenharmony_ci This seems to be true only for firmware 2.00 which is 3071141cc406Sopenharmony_ci extremely seldom.. AB306N scanners with firmware 1.01 don't 3072141cc406Sopenharmony_ci need this fix. <henning@meier-geinitz.de> */ 3073141cc406Sopenharmony_ci if (peak_res == 600) 3074141cc406Sopenharmony_ci { 3075141cc406Sopenharmony_ci if (res < 51) 3076141cc406Sopenharmony_ci { 3077141cc406Sopenharmony_ci result[0] = 8; 3078141cc406Sopenharmony_ci result[1] = 0; 3079141cc406Sopenharmony_ci result[2] = 0; 3080141cc406Sopenharmony_ci result[3] = 2; 3081141cc406Sopenharmony_ci result[4] = 3; 3082141cc406Sopenharmony_ci } 3083141cc406Sopenharmony_ci else if (res < 75 || (res > 90 && res < 150)) 3084141cc406Sopenharmony_ci { 3085141cc406Sopenharmony_ci /* 51-74 and 91-149 dpi: */ 3086141cc406Sopenharmony_ci result[0] = 4; 3087141cc406Sopenharmony_ci result[1] = 0; 3088141cc406Sopenharmony_ci result[2] = 0; 3089141cc406Sopenharmony_ci result[3] = 3; 3090141cc406Sopenharmony_ci result[4] = 5; 3091141cc406Sopenharmony_ci } 3092141cc406Sopenharmony_ci else if (res <= 90 || (res >= 150 && res <= 300)) 3093141cc406Sopenharmony_ci { 3094141cc406Sopenharmony_ci /* 75-90 and 150-300 dpi: */ 3095141cc406Sopenharmony_ci result[0] = 2; 3096141cc406Sopenharmony_ci result[1] = 0; 3097141cc406Sopenharmony_ci result[2] = 0; 3098141cc406Sopenharmony_ci result[3] = 5; 3099141cc406Sopenharmony_ci result[4] = 9; 3100141cc406Sopenharmony_ci } 3101141cc406Sopenharmony_ci else 3102141cc406Sopenharmony_ci { 3103141cc406Sopenharmony_ci /* 301-600 dpi: */ 3104141cc406Sopenharmony_ci result[0] = 1; 3105141cc406Sopenharmony_ci result[1] = 0; 3106141cc406Sopenharmony_ci result[2] = 0; 3107141cc406Sopenharmony_ci result[3] = 9; 3108141cc406Sopenharmony_ci result[4] = 23; 3109141cc406Sopenharmony_ci } 3110141cc406Sopenharmony_ci } 3111141cc406Sopenharmony_ci else 3112141cc406Sopenharmony_ci DBG (1, "don't know how to fix up line-distance for %d dpi\n", 3113141cc406Sopenharmony_ci peak_res); 3114141cc406Sopenharmony_ci } 3115141cc406Sopenharmony_ci else if (!(s->hw->flags & MUSTEK_FLAG_LD_NONE)) 3116141cc406Sopenharmony_ci { 3117141cc406Sopenharmony_ci if (peak_res == 600) 3118141cc406Sopenharmony_ci { 3119141cc406Sopenharmony_ci if (res < 51) 3120141cc406Sopenharmony_ci { 3121141cc406Sopenharmony_ci /* 1-50 dpi: */ 3122141cc406Sopenharmony_ci result[0] = 4; 3123141cc406Sopenharmony_ci result[1] = 0; 3124141cc406Sopenharmony_ci result[2] = 0; 3125141cc406Sopenharmony_ci result[3] = 3; 3126141cc406Sopenharmony_ci result[4] = 5; 3127141cc406Sopenharmony_ci } 3128141cc406Sopenharmony_ci else if (res <= 300) 3129141cc406Sopenharmony_ci { 3130141cc406Sopenharmony_ci /* 51-300 dpi: */ 3131141cc406Sopenharmony_ci result[0] = 2; 3132141cc406Sopenharmony_ci result[1] = 0; 3133141cc406Sopenharmony_ci result[2] = 0; 3134141cc406Sopenharmony_ci result[3] = 5; 3135141cc406Sopenharmony_ci result[4] = 9; 3136141cc406Sopenharmony_ci } 3137141cc406Sopenharmony_ci else 3138141cc406Sopenharmony_ci { 3139141cc406Sopenharmony_ci /*301-600 dpi: */ 3140141cc406Sopenharmony_ci result[0] = 1; 3141141cc406Sopenharmony_ci result[1] = 0; 3142141cc406Sopenharmony_ci result[2] = 0; 3143141cc406Sopenharmony_ci result[3] = 9; 3144141cc406Sopenharmony_ci result[4] = 17; 3145141cc406Sopenharmony_ci } 3146141cc406Sopenharmony_ci } 3147141cc406Sopenharmony_ci else if (peak_res == 800) 3148141cc406Sopenharmony_ci { 3149141cc406Sopenharmony_ci if (res < 72) 3150141cc406Sopenharmony_ci { 3151141cc406Sopenharmony_ci /* 1-71 dpi: */ 3152141cc406Sopenharmony_ci result[0] = 4; 3153141cc406Sopenharmony_ci result[1] = 0; 3154141cc406Sopenharmony_ci result[2] = 0; 3155141cc406Sopenharmony_ci result[3] = 3; 3156141cc406Sopenharmony_ci result[4] = 5; 3157141cc406Sopenharmony_ci } 3158141cc406Sopenharmony_ci else if (res <= 400) 3159141cc406Sopenharmony_ci { 3160141cc406Sopenharmony_ci /* 72-400 dpi: */ 3161141cc406Sopenharmony_ci result[0] = 2; 3162141cc406Sopenharmony_ci result[1] = 0; 3163141cc406Sopenharmony_ci result[2] = 0; 3164141cc406Sopenharmony_ci result[3] = 9; 3165141cc406Sopenharmony_ci result[4] = 17; 3166141cc406Sopenharmony_ci } 3167141cc406Sopenharmony_ci else 3168141cc406Sopenharmony_ci { 3169141cc406Sopenharmony_ci /*401-800 dpi: */ 3170141cc406Sopenharmony_ci result[0] = 1; 3171141cc406Sopenharmony_ci result[1] = 0; 3172141cc406Sopenharmony_ci result[2] = 0; 3173141cc406Sopenharmony_ci result[3] = 16; 3174141cc406Sopenharmony_ci result[4] = 32; 3175141cc406Sopenharmony_ci } 3176141cc406Sopenharmony_ci } 3177141cc406Sopenharmony_ci } 3178141cc406Sopenharmony_ci } 3179141cc406Sopenharmony_ci DBG (4, "line_distance: fixed up to factor=%d, (r/g/b)=(%d/%d/%d)\n", 3180141cc406Sopenharmony_ci result[0] | (result[1] << 8), result[2], result[3], result[4]); 3181141cc406Sopenharmony_ci } 3182141cc406Sopenharmony_ci 3183141cc406Sopenharmony_ci factor = result[0] | (result[1] << 8); 3184141cc406Sopenharmony_ci if (factor != 0xffff) 3185141cc406Sopenharmony_ci { 3186141cc406Sopenharmony_ci /* need to do line-distance adjustment ourselves... */ 3187141cc406Sopenharmony_ci 3188141cc406Sopenharmony_ci s->ld.max_value = peak_res; 3189141cc406Sopenharmony_ci 3190141cc406Sopenharmony_ci if (factor == 0) 3191141cc406Sopenharmony_ci { 3192141cc406Sopenharmony_ci if (res <= peak_res / 2) 3193141cc406Sopenharmony_ci res *= 2; 3194141cc406Sopenharmony_ci } 3195141cc406Sopenharmony_ci else 3196141cc406Sopenharmony_ci res *= factor; 3197141cc406Sopenharmony_ci s->ld.peak_res = res; 3198141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3199141cc406Sopenharmony_ci { 3200141cc406Sopenharmony_ci s->ld.dist[color] = result[2 + color]; 3201141cc406Sopenharmony_ci s->ld.quant[color] = s->ld.max_value; 3202141cc406Sopenharmony_ci s->ld.index[color] = -s->ld.dist[color]; 3203141cc406Sopenharmony_ci } 3204141cc406Sopenharmony_ci s->ld.lmod3 = -1; 3205141cc406Sopenharmony_ci 3206141cc406Sopenharmony_ci DBG (4, "line_distance: max_value = %d, peak_res = %d, ld.quant = " 3207141cc406Sopenharmony_ci "(%d, %d, %d)\n", s->ld.max_value, s->ld.peak_res, s->ld.quant[0], 3208141cc406Sopenharmony_ci s->ld.quant[1], s->ld.quant[2]); 3209141cc406Sopenharmony_ci } 3210141cc406Sopenharmony_ci else 3211141cc406Sopenharmony_ci s->ld.max_value = 0; 3212141cc406Sopenharmony_ci 3213141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3214141cc406Sopenharmony_ci} 3215141cc406Sopenharmony_ci 3216141cc406Sopenharmony_ci/* Paragon + Pro series */ 3217141cc406Sopenharmony_cistatic SANE_Status 3218141cc406Sopenharmony_ciget_image_status (Mustek_Scanner * s, SANE_Int * bpl, SANE_Int * lines) 3219141cc406Sopenharmony_ci{ 3220141cc406Sopenharmony_ci SANE_Byte result[6]; 3221141cc406Sopenharmony_ci SANE_Status status; 3222141cc406Sopenharmony_ci size_t len; 3223141cc406Sopenharmony_ci SANE_Int busy, offset; 3224141cc406Sopenharmony_ci long res, half_res; 3225141cc406Sopenharmony_ci 3226141cc406Sopenharmony_ci memset (result, 0, 6); 3227141cc406Sopenharmony_ci 3228141cc406Sopenharmony_ci /* The 600 II N v1.01 and Paragon 12000SP need a larger scan-area for 3229141cc406Sopenharmony_ci line-distance correction in color mode */ 3230141cc406Sopenharmony_ci offset = 0; 3231141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_LD_N1) && (s->mode & MUSTEK_MODE_COLOR)) 3232141cc406Sopenharmony_ci offset = s->ld.dist[1]; 3233141cc406Sopenharmony_ci else if ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK) 3234141cc406Sopenharmony_ci && (s->hw->flags & MUSTEK_FLAG_PARAGON_1) 3235141cc406Sopenharmony_ci && (s->mode & MUSTEK_MODE_COLOR)) 3236141cc406Sopenharmony_ci offset = MAX_LINE_DIST * SANE_UNFIX (s->val[OPT_RESOLUTION].w) 3237141cc406Sopenharmony_ci / SANE_UNFIX (s->hw->dpi_range.max); 3238141cc406Sopenharmony_ci 3239141cc406Sopenharmony_ci do 3240141cc406Sopenharmony_ci { 3241141cc406Sopenharmony_ci len = sizeof (result); 3242141cc406Sopenharmony_ci status = dev_cmd (s, scsi_get_image_status, 3243141cc406Sopenharmony_ci sizeof (scsi_get_image_status), result, &len); 3244141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3245141cc406Sopenharmony_ci return status; 3246141cc406Sopenharmony_ci 3247141cc406Sopenharmony_ci busy = result[0]; 3248141cc406Sopenharmony_ci if (busy) 3249141cc406Sopenharmony_ci usleep (100000); 3250141cc406Sopenharmony_ci 3251141cc406Sopenharmony_ci if (!s->scanning) /* ? */ 3252141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_PRO)) 3253141cc406Sopenharmony_ci return do_stop (s); 3254141cc406Sopenharmony_ci } 3255141cc406Sopenharmony_ci while (busy); 3256141cc406Sopenharmony_ci 3257141cc406Sopenharmony_ci s->hw->bpl = result[1] | (result[2] << 8); 3258141cc406Sopenharmony_ci s->hw->lines = result[3] | (result[4] << 8) | (result[5] << 16); 3259141cc406Sopenharmony_ci 3260141cc406Sopenharmony_ci res = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 3261141cc406Sopenharmony_ci half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2; 3262141cc406Sopenharmony_ci /* Need to interpolate resolutions > max x-resolution? */ 3263141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3264141cc406Sopenharmony_ci { 3265141cc406Sopenharmony_ci *bpl = (s->hw->bpl * res) / half_res / 3; 3266141cc406Sopenharmony_ci *bpl *= 3; 3267141cc406Sopenharmony_ci DBG (4, "get_image_status: resolution > x-max; enlarge %d bpl to " 3268141cc406Sopenharmony_ci "%d bpl\n", s->hw->bpl, *bpl); 3269141cc406Sopenharmony_ci } 3270141cc406Sopenharmony_ci else 3271141cc406Sopenharmony_ci *bpl = s->hw->bpl; 3272141cc406Sopenharmony_ci 3273141cc406Sopenharmony_ci *lines = s->hw->lines - offset; 3274141cc406Sopenharmony_ci 3275141cc406Sopenharmony_ci DBG (3, "get_image_status: bytes_per_line=%d, lines=%d (offset = %d)\n", 3276141cc406Sopenharmony_ci *bpl, *lines, offset); 3277141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3278141cc406Sopenharmony_ci} 3279141cc406Sopenharmony_ci 3280141cc406Sopenharmony_ci/* ScanExpress models */ 3281141cc406Sopenharmony_cistatic SANE_Status 3282141cc406Sopenharmony_ciget_window (Mustek_Scanner * s, SANE_Int * bpl, SANE_Int * lines, 3283141cc406Sopenharmony_ci SANE_Int * pixels) 3284141cc406Sopenharmony_ci{ 3285141cc406Sopenharmony_ci SANE_Byte result[48]; 3286141cc406Sopenharmony_ci SANE_Status status; 3287141cc406Sopenharmony_ci size_t len; 3288141cc406Sopenharmony_ci SANE_Int color; 3289141cc406Sopenharmony_ci long res, half_res; 3290141cc406Sopenharmony_ci 3291141cc406Sopenharmony_ci res = s->resolution_code; 3292141cc406Sopenharmony_ci half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2; 3293141cc406Sopenharmony_ci 3294141cc406Sopenharmony_ci DBG (5, "get_window: resolution: %ld dpi (hardware: %d dpi)\n", 3295141cc406Sopenharmony_ci res, s->ld.peak_res); 3296141cc406Sopenharmony_ci 3297141cc406Sopenharmony_ci len = sizeof (result); 3298141cc406Sopenharmony_ci status = dev_cmd (s, scsi_get_window, sizeof (scsi_get_window), result, 3299141cc406Sopenharmony_ci &len); 3300141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3301141cc406Sopenharmony_ci return status; 3302141cc406Sopenharmony_ci 3303141cc406Sopenharmony_ci if (!s->scanning) 3304141cc406Sopenharmony_ci return do_stop (s); 3305141cc406Sopenharmony_ci 3306141cc406Sopenharmony_ci s->hw->cal.bytes = (result[6] << 24) | (result[7] << 16) | 3307141cc406Sopenharmony_ci (result[8] << 8) | (result[9] << 0); 3308141cc406Sopenharmony_ci s->hw->cal.lines = (result[10] << 24) | (result[11] << 16) | 3309141cc406Sopenharmony_ci (result[12] << 8) | (result[13] << 0); 3310141cc406Sopenharmony_ci 3311141cc406Sopenharmony_ci DBG (4, "get_window: calibration bpl=%d, lines=%d\n", 3312141cc406Sopenharmony_ci s->hw->cal.bytes, s->hw->cal.lines); 3313141cc406Sopenharmony_ci 3314141cc406Sopenharmony_ci s->hw->bpl = (result[14] << 24) | (result[15] << 16) | 3315141cc406Sopenharmony_ci (result[16] << 8) | result[17]; 3316141cc406Sopenharmony_ci 3317141cc406Sopenharmony_ci s->hw->lines = (result[18] << 24) | (result[19] << 16) | 3318141cc406Sopenharmony_ci (result[20] << 8) | result[21]; 3319141cc406Sopenharmony_ci 3320141cc406Sopenharmony_ci DBG (4, "get_window: scan bpl=%d, lines=%d\n", s->hw->bpl, s->hw->lines); 3321141cc406Sopenharmony_ci 3322141cc406Sopenharmony_ci if ((s->hw->cal.bytes == 0) || (s->hw->cal.lines == 0) 3323141cc406Sopenharmony_ci || (s->hw->bpl == 0) || (s->hw->lines == 0)) 3324141cc406Sopenharmony_ci { 3325141cc406Sopenharmony_ci DBG (1, "get_window: oops, none of these values should be 0 " 3326141cc406Sopenharmony_ci "-- exiting\n"); 3327141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3328141cc406Sopenharmony_ci } 3329141cc406Sopenharmony_ci 3330141cc406Sopenharmony_ci s->hw->gamma_length = 1 << result[26]; 3331141cc406Sopenharmony_ci DBG (4, "get_window: gamma length=%d\n", s->hw->gamma_length); 3332141cc406Sopenharmony_ci 3333141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 3334141cc406Sopenharmony_ci { 3335141cc406Sopenharmony_ci s->ld.buf[0] = NULL; 3336141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3337141cc406Sopenharmony_ci { 3338141cc406Sopenharmony_ci s->ld.dist[color] = result[42 + color]; 3339141cc406Sopenharmony_ci } 3340141cc406Sopenharmony_ci 3341141cc406Sopenharmony_ci DBG (4, "get_window: LD res=%d, (r/g/b)=(%d/%d/%d)\n", 3342141cc406Sopenharmony_ci (result[40] << 8) | result[41], s->ld.dist[0], 3343141cc406Sopenharmony_ci s->ld.dist[1], s->ld.dist[2]); 3344141cc406Sopenharmony_ci s->ld.max_value = (result[40] << 8) | result[41]; 3345141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3346141cc406Sopenharmony_ci { 3347141cc406Sopenharmony_ci /* We must interpolate resolutions > max x-resolution */ 3348141cc406Sopenharmony_ci *bpl = *pixels = (((s->hw->bpl / 3) * res) / half_res) * 3; 3349141cc406Sopenharmony_ci } 3350141cc406Sopenharmony_ci else 3351141cc406Sopenharmony_ci { 3352141cc406Sopenharmony_ci /* Scale down the image according to desired resolution */ 3353141cc406Sopenharmony_ci *bpl = *pixels = (((s->hw->bpl / 3) * res) / s->ld.peak_res) * 3; 3354141cc406Sopenharmony_ci } 3355141cc406Sopenharmony_ci *lines = (s->hw->lines - s->ld.dist[2]) * res / s->ld.peak_res; 3356141cc406Sopenharmony_ci } 3357141cc406Sopenharmony_ci else 3358141cc406Sopenharmony_ci { 3359141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3360141cc406Sopenharmony_ci { 3361141cc406Sopenharmony_ci /* We must interpolate resolutions > max x-resolution */ 3362141cc406Sopenharmony_ci *bpl = s->hw->bpl * res / half_res; 3363141cc406Sopenharmony_ci } 3364141cc406Sopenharmony_ci else 3365141cc406Sopenharmony_ci { 3366141cc406Sopenharmony_ci *bpl = s->hw->bpl; 3367141cc406Sopenharmony_ci } 3368141cc406Sopenharmony_ci *lines = s->hw->lines; 3369141cc406Sopenharmony_ci } 3370141cc406Sopenharmony_ci DBG (4, "get_window: bpl = %d (hardware: %d), lines = %d (hardware: %d)\n", 3371141cc406Sopenharmony_ci *bpl, s->hw->bpl, *lines, s->hw->lines); 3372141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3373141cc406Sopenharmony_ci} 3374141cc406Sopenharmony_ci 3375141cc406Sopenharmony_cistatic SANE_Status 3376141cc406Sopenharmony_ciadf_and_backtrack (Mustek_Scanner * s) 3377141cc406Sopenharmony_ci{ 3378141cc406Sopenharmony_ci SANE_Byte backtrack[6]; 3379141cc406Sopenharmony_ci SANE_Int code = 0x80; 3380141cc406Sopenharmony_ci 3381141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_NO_BACKTRACK)) 3382141cc406Sopenharmony_ci code |= 0x02; /* enable backtracking */ 3383141cc406Sopenharmony_ci 3384141cc406Sopenharmony_ci if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) 3385141cc406Sopenharmony_ci code |= 0x01; 3386141cc406Sopenharmony_ci else if (strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0) 3387141cc406Sopenharmony_ci code |= 0x04; 3388141cc406Sopenharmony_ci memset (backtrack, 0, sizeof (backtrack)); 3389141cc406Sopenharmony_ci backtrack[0] = MUSTEK_SCSI_ADF_AND_BACKTRACK; 3390141cc406Sopenharmony_ci backtrack[4] = code; 3391141cc406Sopenharmony_ci 3392141cc406Sopenharmony_ci DBG (4, "adf_and_backtrack: backtrack: %s; ADF: %s; TA: %s\n", 3393141cc406Sopenharmony_ci code & 0x02 ? "yes" : "no", code & 0x01 ? "yes" : "no", 3394141cc406Sopenharmony_ci code & 0x04 ? "yes" : "no"); 3395141cc406Sopenharmony_ci return dev_cmd (s, backtrack, sizeof (backtrack), 0, 0); 3396141cc406Sopenharmony_ci} 3397141cc406Sopenharmony_ci 3398141cc406Sopenharmony_ci/* 600 II N firmware 2.x */ 3399141cc406Sopenharmony_cistatic SANE_Int 3400141cc406Sopenharmony_cifix_line_distance_n_2 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 3401141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out) 3402141cc406Sopenharmony_ci{ 3403141cc406Sopenharmony_ci SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl; 3404141cc406Sopenharmony_ci SANE_Int c, num_saved_lines, line; 3405141cc406Sopenharmony_ci 3406141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3407141cc406Sopenharmony_ci { 3408141cc406Sopenharmony_ci /* This buffer must be big enough to hold maximum line distance 3409141cc406Sopenharmony_ci times max_bpl bytes. The maximum line distance for the 3410141cc406Sopenharmony_ci Paragon 600 II N scanner is 23, so 40 should be safe. */ 3411141cc406Sopenharmony_ci DBG (5, 3412141cc406Sopenharmony_ci "fix_line_distance_n_2: allocating temp buffer of %d*%d bytes\n", 3413141cc406Sopenharmony_ci MAX_LINE_DIST, bpl); 3414141cc406Sopenharmony_ci s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl); 3415141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3416141cc406Sopenharmony_ci { 3417141cc406Sopenharmony_ci DBG (1, 3418141cc406Sopenharmony_ci "fix_line_distance_n_2: failed to malloc temporary buffer\n"); 3419141cc406Sopenharmony_ci return 0; 3420141cc406Sopenharmony_ci } 3421141cc406Sopenharmony_ci } 3422141cc406Sopenharmony_ci 3423141cc406Sopenharmony_ci num_saved_lines = s->ld.index[0] - s->ld.index[2]; 3424141cc406Sopenharmony_ci if (num_saved_lines > 0) 3425141cc406Sopenharmony_ci /* restore the previously saved lines: */ 3426141cc406Sopenharmony_ci memcpy (out, s->ld.buf[0], num_saved_lines * bpl); 3427141cc406Sopenharmony_ci 3428141cc406Sopenharmony_ci while (1) 3429141cc406Sopenharmony_ci { 3430141cc406Sopenharmony_ci if (++s->ld.lmod3 >= 3) 3431141cc406Sopenharmony_ci s->ld.lmod3 = 0; 3432141cc406Sopenharmony_ci 3433141cc406Sopenharmony_ci c = color_seq[s->ld.lmod3]; 3434141cc406Sopenharmony_ci if (s->ld.index[c] < 0) 3435141cc406Sopenharmony_ci ++s->ld.index[c]; 3436141cc406Sopenharmony_ci else if (s->ld.index[c] < s->params.lines) 3437141cc406Sopenharmony_ci { 3438141cc406Sopenharmony_ci s->ld.quant[c] += s->ld.peak_res; 3439141cc406Sopenharmony_ci if (s->ld.quant[c] > s->ld.max_value) 3440141cc406Sopenharmony_ci { 3441141cc406Sopenharmony_ci s->ld.quant[c] -= s->ld.max_value; 3442141cc406Sopenharmony_ci line = s->ld.index[c]++ - s->ld.ld_line; 3443141cc406Sopenharmony_ci out_ptr = out + line * bpl + c; 3444141cc406Sopenharmony_ci out_end = out_ptr + bpl; 3445141cc406Sopenharmony_ci while (out_ptr != out_end) 3446141cc406Sopenharmony_ci { 3447141cc406Sopenharmony_ci *out_ptr = *raw++; 3448141cc406Sopenharmony_ci out_ptr += 3; 3449141cc406Sopenharmony_ci } 3450141cc406Sopenharmony_ci 3451141cc406Sopenharmony_ci if (raw >= raw_end) 3452141cc406Sopenharmony_ci { 3453141cc406Sopenharmony_ci DBG (3, "fix_line_distance_n_2: lmod3=%d, " 3454141cc406Sopenharmony_ci "index=(%d,%d,%d)\n", s->ld.lmod3, 3455141cc406Sopenharmony_ci s->ld.index[0], s->ld.index[1], s->ld.index[2]); 3456141cc406Sopenharmony_ci num_lines = s->ld.index[2] - s->ld.ld_line; 3457141cc406Sopenharmony_ci 3458141cc406Sopenharmony_ci /* copy away the lines with at least one missing 3459141cc406Sopenharmony_ci color component, so that we can interleave them 3460141cc406Sopenharmony_ci with new scan data on the next call */ 3461141cc406Sopenharmony_ci num_saved_lines = s->ld.index[0] - s->ld.index[2]; 3462141cc406Sopenharmony_ci memcpy (s->ld.buf[0], out + num_lines * bpl, 3463141cc406Sopenharmony_ci num_saved_lines * bpl); 3464141cc406Sopenharmony_ci 3465141cc406Sopenharmony_ci /* notice the number of lines we processed */ 3466141cc406Sopenharmony_ci s->ld.ld_line = s->ld.index[2]; 3467141cc406Sopenharmony_ci /* return number of complete (r+g+b) lines */ 3468141cc406Sopenharmony_ci return num_lines; 3469141cc406Sopenharmony_ci } 3470141cc406Sopenharmony_ci } 3471141cc406Sopenharmony_ci } 3472141cc406Sopenharmony_ci } 3473141cc406Sopenharmony_ci} 3474141cc406Sopenharmony_ci 3475141cc406Sopenharmony_ci/* 600 II N firmware 1.x */ 3476141cc406Sopenharmony_cistatic SANE_Int 3477141cc406Sopenharmony_cifix_line_distance_n_1 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 3478141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out) 3479141cc406Sopenharmony_ci{ 3480141cc406Sopenharmony_ci SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl; 3481141cc406Sopenharmony_ci SANE_Int c, num_saved_lines, line; 3482141cc406Sopenharmony_ci 3483141cc406Sopenharmony_ci /* For firmware 1.x the scanarea must be soemwhat bigger than needed 3484141cc406Sopenharmony_ci because of the linedistance correction */ 3485141cc406Sopenharmony_ci 3486141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3487141cc406Sopenharmony_ci { 3488141cc406Sopenharmony_ci /* This buffer must be big enough to hold maximum line distance 3489141cc406Sopenharmony_ci times max_bpl bytes. The maximum line distance for the 600 II N 3490141cc406Sopenharmony_ci is 23, so 40 is safe. */ 3491141cc406Sopenharmony_ci DBG (5, 3492141cc406Sopenharmony_ci "fix_line_distance_n_1: allocating temp buffer of %d*%d bytes\n", 3493141cc406Sopenharmony_ci MAX_LINE_DIST, bpl); 3494141cc406Sopenharmony_ci s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl); 3495141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3496141cc406Sopenharmony_ci { 3497141cc406Sopenharmony_ci DBG (1, 3498141cc406Sopenharmony_ci "fix_line_distance_n_1: failed to malloc temporary buffer\n"); 3499141cc406Sopenharmony_ci return 0; 3500141cc406Sopenharmony_ci } 3501141cc406Sopenharmony_ci } 3502141cc406Sopenharmony_ci num_saved_lines = s->ld.index[0] - s->ld.index[1]; 3503141cc406Sopenharmony_ci DBG (5, "fix_line_distance_n_1: got %d lines, %d bpl\n", num_lines, bpl); 3504141cc406Sopenharmony_ci DBG (5, "fix_line_distance_n_1: num_saved_lines = %d; peak_res = %d; " 3505141cc406Sopenharmony_ci "max_value = %d\n", num_saved_lines, s->ld.peak_res, s->ld.max_value); 3506141cc406Sopenharmony_ci if (num_saved_lines > 0) 3507141cc406Sopenharmony_ci /* restore the previously saved lines: */ 3508141cc406Sopenharmony_ci memcpy (out, s->ld.buf[0], num_saved_lines * bpl); 3509141cc406Sopenharmony_ci 3510141cc406Sopenharmony_ci while (1) 3511141cc406Sopenharmony_ci { 3512141cc406Sopenharmony_ci if (++s->ld.lmod3 >= 3) 3513141cc406Sopenharmony_ci s->ld.lmod3 = 0; 3514141cc406Sopenharmony_ci c = s->ld.lmod3; 3515141cc406Sopenharmony_ci if (s->ld.index[c] < 0) 3516141cc406Sopenharmony_ci ++s->ld.index[c]; 3517141cc406Sopenharmony_ci else 3518141cc406Sopenharmony_ci { 3519141cc406Sopenharmony_ci s->ld.quant[c] += s->ld.peak_res; 3520141cc406Sopenharmony_ci if (s->ld.quant[c] > s->ld.max_value) 3521141cc406Sopenharmony_ci { 3522141cc406Sopenharmony_ci s->ld.quant[c] -= s->ld.max_value; 3523141cc406Sopenharmony_ci line = s->ld.index[c]++ - s->ld.ld_line; 3524141cc406Sopenharmony_ci out_ptr = out + line * bpl + c; 3525141cc406Sopenharmony_ci out_end = out_ptr + bpl; 3526141cc406Sopenharmony_ci while (out_ptr != out_end) 3527141cc406Sopenharmony_ci { 3528141cc406Sopenharmony_ci *out_ptr = *raw++; 3529141cc406Sopenharmony_ci out_ptr += 3; 3530141cc406Sopenharmony_ci } 3531141cc406Sopenharmony_ci DBG (5, "fix_line_distance_n_1: copied line %d (color %d)\n", 3532141cc406Sopenharmony_ci line, c); 3533141cc406Sopenharmony_ci } 3534141cc406Sopenharmony_ci } 3535141cc406Sopenharmony_ci if ((raw >= raw_end) || ((s->ld.index[0] >= s->params.lines) && 3536141cc406Sopenharmony_ci (s->ld.index[1] >= s->params.lines) && 3537141cc406Sopenharmony_ci (s->ld.index[2] >= s->params.lines))) 3538141cc406Sopenharmony_ci { 3539141cc406Sopenharmony_ci DBG (3, "fix_line_distance_n_1: lmod3=%d, index=(%d,%d,%d)%s\n", 3540141cc406Sopenharmony_ci s->ld.lmod3, 3541141cc406Sopenharmony_ci s->ld.index[0], s->ld.index[1], s->ld.index[2], 3542141cc406Sopenharmony_ci raw >= raw_end ? " raw >= raw_end" : ""); 3543141cc406Sopenharmony_ci num_lines = s->ld.index[1] - s->ld.ld_line; 3544141cc406Sopenharmony_ci if (num_lines < 0) 3545141cc406Sopenharmony_ci num_lines = 0; 3546141cc406Sopenharmony_ci DBG (4, "fix_line_distance_n_1: lines ready: %d\n", num_lines); 3547141cc406Sopenharmony_ci 3548141cc406Sopenharmony_ci /* copy away the lines with at least one missing 3549141cc406Sopenharmony_ci color component, so that we can interleave them 3550141cc406Sopenharmony_ci with new scan data on the next call */ 3551141cc406Sopenharmony_ci num_saved_lines = s->ld.index[0] - s->ld.index[1]; 3552141cc406Sopenharmony_ci DBG (4, "fix_line_distance_n_1: copied %d lines to " 3553141cc406Sopenharmony_ci "ld.buf\n", num_saved_lines); 3554141cc406Sopenharmony_ci memcpy (s->ld.buf[0], out + num_lines * bpl, num_saved_lines * bpl); 3555141cc406Sopenharmony_ci /* notice the number of lines we processed */ 3556141cc406Sopenharmony_ci s->ld.ld_line = s->ld.index[1]; 3557141cc406Sopenharmony_ci if (s->ld.ld_line < 0) 3558141cc406Sopenharmony_ci s->ld.ld_line = 0; 3559141cc406Sopenharmony_ci /* return number of complete (r+g+b) lines */ 3560141cc406Sopenharmony_ci return num_lines; 3561141cc406Sopenharmony_ci } 3562141cc406Sopenharmony_ci 3563141cc406Sopenharmony_ci } 3564141cc406Sopenharmony_ci} 3565141cc406Sopenharmony_ci 3566141cc406Sopenharmony_ci/* For ScanExpress models */ 3567141cc406Sopenharmony_cistatic SANE_Int 3568141cc406Sopenharmony_cifix_line_distance_se (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 3569141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out) 3570141cc406Sopenharmony_ci{ 3571141cc406Sopenharmony_ci SANE_Byte *raw_end = raw + num_lines * bpl; 3572141cc406Sopenharmony_ci SANE_Byte *out_ptr[3], *ptr; 3573141cc406Sopenharmony_ci SANE_Int index[3], lines[3], quant[3], dist[3]; 3574141cc406Sopenharmony_ci SANE_Int max_value; 3575141cc406Sopenharmony_ci SANE_Int color, pixel, res, half_res, scale; 3576141cc406Sopenharmony_ci SANE_Int bpc = bpl / 3; /* bytes per color (per line) */ 3577141cc406Sopenharmony_ci SANE_Bool preview = SANE_FALSE; 3578141cc406Sopenharmony_ci 3579141cc406Sopenharmony_ci res = s->resolution_code; 3580141cc406Sopenharmony_ci half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2; 3581141cc406Sopenharmony_ci max_value = s->ld.max_value; 3582141cc406Sopenharmony_ci if ((s->val[OPT_PREVIEW].w == SANE_TRUE) 3583141cc406Sopenharmony_ci && (s->val[OPT_FAST_PREVIEW].w == SANE_TRUE)) 3584141cc406Sopenharmony_ci { 3585141cc406Sopenharmony_ci preview = SANE_TRUE; 3586141cc406Sopenharmony_ci /*max_value = 75; */ 3587141cc406Sopenharmony_ci dist[0] = s->ld.dist[0]; 3588141cc406Sopenharmony_ci dist[1] = s->ld.dist[1]; 3589141cc406Sopenharmony_ci dist[2] = s->ld.dist[2]; 3590141cc406Sopenharmony_ci } 3591141cc406Sopenharmony_ci else 3592141cc406Sopenharmony_ci { 3593141cc406Sopenharmony_ci dist[0] = s->ld.dist[0]; 3594141cc406Sopenharmony_ci dist[1] = s->ld.dist[1]; 3595141cc406Sopenharmony_ci dist[2] = s->ld.dist[2]; 3596141cc406Sopenharmony_ci } 3597141cc406Sopenharmony_ci 3598141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3599141cc406Sopenharmony_ci { 3600141cc406Sopenharmony_ci /* This buffer must be big enough to hold maximum line distance times 3601141cc406Sopenharmony_ci 3*bpl bytes. The maximum line distance for 1200 dpi is 32 */ 3602141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: allocating temp buffer of %d*%d bytes\n", 3603141cc406Sopenharmony_ci 3 * MAX_LINE_DIST, bpc); 3604141cc406Sopenharmony_ci s->ld.buf[0] = malloc (3 * MAX_LINE_DIST * (long) bpc); 3605141cc406Sopenharmony_ci 3606141cc406Sopenharmony_ci if (!s->ld.buf[0]) 3607141cc406Sopenharmony_ci { 3608141cc406Sopenharmony_ci DBG (1, 3609141cc406Sopenharmony_ci "fix_line_distance_se: failed to malloc temporary buffer\n"); 3610141cc406Sopenharmony_ci return 0; 3611141cc406Sopenharmony_ci } 3612141cc406Sopenharmony_ci 3613141cc406Sopenharmony_ci /* Note that either s->ld.buf[1] or s->ld.buf[2] is never used. */ 3614141cc406Sopenharmony_ci s->ld.buf[1] = s->ld.buf[2] = 3615141cc406Sopenharmony_ci s->ld.buf[0] + 2 * MAX_LINE_DIST * (long) bpc; 3616141cc406Sopenharmony_ci 3617141cc406Sopenharmony_ci /* Since the blocks don't start necessarily with red note color. */ 3618141cc406Sopenharmony_ci s->ld.color = 0; 3619141cc406Sopenharmony_ci 3620141cc406Sopenharmony_ci /* The scan area must be longer than desired because of the line 3621141cc406Sopenharmony_ci distance. So me must count complete (r+g+b) lines already 3622141cc406Sopenharmony_ci submitted to the fronted. */ 3623141cc406Sopenharmony_ci s->ld.ld_line = s->params.lines; 3624141cc406Sopenharmony_ci 3625141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3626141cc406Sopenharmony_ci { 3627141cc406Sopenharmony_ci s->ld.index[color] = -dist[color]; 3628141cc406Sopenharmony_ci s->ld.quant[color] = 0; 3629141cc406Sopenharmony_ci s->ld.saved[color] = 0; 3630141cc406Sopenharmony_ci } 3631141cc406Sopenharmony_ci } 3632141cc406Sopenharmony_ci 3633141cc406Sopenharmony_ci num_lines *= 3; 3634141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: start color: %d; %d lines \n", 3635141cc406Sopenharmony_ci s->ld.color, num_lines); 3636141cc406Sopenharmony_ci 3637141cc406Sopenharmony_ci /* First scan the lines read and count red, green and blue ones. 3638141cc406Sopenharmony_ci Since we will step through the lines a second time we must not 3639141cc406Sopenharmony_ci alter any global variables here! */ 3640141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3641141cc406Sopenharmony_ci { 3642141cc406Sopenharmony_ci index[color] = s->ld.index[color]; 3643141cc406Sopenharmony_ci lines[color] = s->ld.saved[color]; 3644141cc406Sopenharmony_ci quant[color] = s->ld.quant[color]; 3645141cc406Sopenharmony_ci } 3646141cc406Sopenharmony_ci 3647141cc406Sopenharmony_ci color = s->ld.color; 3648141cc406Sopenharmony_ci while (num_lines > 0) 3649141cc406Sopenharmony_ci { 3650141cc406Sopenharmony_ci if (index[color] < 0) 3651141cc406Sopenharmony_ci ++index[color]; 3652141cc406Sopenharmony_ci else 3653141cc406Sopenharmony_ci { 3654141cc406Sopenharmony_ci quant[color] += res; 3655141cc406Sopenharmony_ci if (quant[color] >= max_value) 3656141cc406Sopenharmony_ci { 3657141cc406Sopenharmony_ci /* This line must be processed, not dropped. */ 3658141cc406Sopenharmony_ci quant[color] -= max_value; 3659141cc406Sopenharmony_ci ++lines[color]; 3660141cc406Sopenharmony_ci --num_lines; 3661141cc406Sopenharmony_ci } 3662141cc406Sopenharmony_ci else if (!preview) 3663141cc406Sopenharmony_ci --num_lines; 3664141cc406Sopenharmony_ci 3665141cc406Sopenharmony_ci } 3666141cc406Sopenharmony_ci if (++color > 2) 3667141cc406Sopenharmony_ci color = 0; 3668141cc406Sopenharmony_ci } 3669141cc406Sopenharmony_ci 3670141cc406Sopenharmony_ci /* Calculate how many triples of color lines we can output now. 3671141cc406Sopenharmony_ci Because the number of available red lines is always greater 3672141cc406Sopenharmony_ci than for the other colors we may ignore the red ones here. */ 3673141cc406Sopenharmony_ci num_lines = MIN (lines[1], lines[2]); 3674141cc406Sopenharmony_ci 3675141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: saved lines: %d/%d/%d\n", s->ld.saved[0], 3676141cc406Sopenharmony_ci s->ld.saved[1], s->ld.saved[2]); 3677141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: available: %d/%d/%d --> triples: %d\n", 3678141cc406Sopenharmony_ci lines[0], lines[1], lines[2], num_lines); 3679141cc406Sopenharmony_ci 3680141cc406Sopenharmony_ci lines[0] = lines[1] = lines[2] = num_lines; 3681141cc406Sopenharmony_ci 3682141cc406Sopenharmony_ci /* Output the color lines saved in previous call first. 3683141cc406Sopenharmony_ci Note that data is converted in r/g/b interleave on the fly. */ 3684141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3685141cc406Sopenharmony_ci { 3686141cc406Sopenharmony_ci out_ptr[color] = out + color; 3687141cc406Sopenharmony_ci ptr = s->ld.buf[color]; 3688141cc406Sopenharmony_ci while ((s->ld.saved[color] > 0) && (lines[color] > 0)) 3689141cc406Sopenharmony_ci { 3690141cc406Sopenharmony_ci scale = 0; 3691141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3692141cc406Sopenharmony_ci { 3693141cc406Sopenharmony_ci /* Need to enlarge x-resolution */ 3694141cc406Sopenharmony_ci SANE_Byte *ptr_start = ptr; 3695141cc406Sopenharmony_ci for (pixel = 0; pixel < s->params.pixels_per_line; ++pixel) 3696141cc406Sopenharmony_ci { 3697141cc406Sopenharmony_ci *out_ptr[color] = *ptr; 3698141cc406Sopenharmony_ci out_ptr[color] += 3; 3699141cc406Sopenharmony_ci scale += half_res; 3700141cc406Sopenharmony_ci if (scale >= half_res) 3701141cc406Sopenharmony_ci { 3702141cc406Sopenharmony_ci scale -= res; 3703141cc406Sopenharmony_ci ++ptr; 3704141cc406Sopenharmony_ci } 3705141cc406Sopenharmony_ci } 3706141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: got saved line: %d; line: %d; " 3707141cc406Sopenharmony_ci "color: %d; raw bytes: %lu; out bytes: %d\n", 3708141cc406Sopenharmony_ci s->ld.saved[color], lines[color], color, (u_long) (ptr - ptr_start), 3709141cc406Sopenharmony_ci s->params.pixels_per_line); 3710141cc406Sopenharmony_ci ptr = ptr_start + bpc; 3711141cc406Sopenharmony_ci } 3712141cc406Sopenharmony_ci else 3713141cc406Sopenharmony_ci { 3714141cc406Sopenharmony_ci if (preview) 3715141cc406Sopenharmony_ci { 3716141cc406Sopenharmony_ci for (pixel = 0; pixel < bpc; ++pixel) 3717141cc406Sopenharmony_ci { 3718141cc406Sopenharmony_ci *out_ptr[color] = *ptr++; 3719141cc406Sopenharmony_ci out_ptr[color] += 3; 3720141cc406Sopenharmony_ci } 3721141cc406Sopenharmony_ci } 3722141cc406Sopenharmony_ci else 3723141cc406Sopenharmony_ci { 3724141cc406Sopenharmony_ci for (pixel = 0; pixel < bpc; ++pixel) 3725141cc406Sopenharmony_ci { 3726141cc406Sopenharmony_ci scale += res; 3727141cc406Sopenharmony_ci if (scale >= max_value) 3728141cc406Sopenharmony_ci { 3729141cc406Sopenharmony_ci scale -= max_value; 3730141cc406Sopenharmony_ci *out_ptr[color] = *ptr; 3731141cc406Sopenharmony_ci out_ptr[color] += 3; 3732141cc406Sopenharmony_ci } 3733141cc406Sopenharmony_ci ++ptr; 3734141cc406Sopenharmony_ci } 3735141cc406Sopenharmony_ci } 3736141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: got saved line: %d; line: %d; " 3737141cc406Sopenharmony_ci "color: %d\n", s->ld.saved[color], lines[color], color); 3738141cc406Sopenharmony_ci } 3739141cc406Sopenharmony_ci --(s->ld.saved[color]); 3740141cc406Sopenharmony_ci --lines[color]; 3741141cc406Sopenharmony_ci } 3742141cc406Sopenharmony_ci if (s->ld.saved[color] > 0) 3743141cc406Sopenharmony_ci memmove (s->ld.buf[color], ptr, s->ld.saved[color] * bpc); 3744141cc406Sopenharmony_ci } 3745141cc406Sopenharmony_ci 3746141cc406Sopenharmony_ci while (1) 3747141cc406Sopenharmony_ci { 3748141cc406Sopenharmony_ci if (s->ld.index[s->ld.color] < 0) 3749141cc406Sopenharmony_ci ++(s->ld.index[s->ld.color]); 3750141cc406Sopenharmony_ci else 3751141cc406Sopenharmony_ci { 3752141cc406Sopenharmony_ci s->ld.quant[s->ld.color] += res; 3753141cc406Sopenharmony_ci if (s->ld.quant[s->ld.color] >= max_value) 3754141cc406Sopenharmony_ci { 3755141cc406Sopenharmony_ci /* This line must be processed, not dropped. */ 3756141cc406Sopenharmony_ci s->ld.quant[s->ld.color] -= max_value; 3757141cc406Sopenharmony_ci 3758141cc406Sopenharmony_ci if (lines[s->ld.color] > 0) 3759141cc406Sopenharmony_ci { 3760141cc406Sopenharmony_ci /* There's still a line to be output for current color. 3761141cc406Sopenharmony_ci Then shuffle current color line to output buffer. */ 3762141cc406Sopenharmony_ci scale = 0; 3763141cc406Sopenharmony_ci /* need to enlarge x-resolution? */ 3764141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) 3765141cc406Sopenharmony_ci && (res > half_res)) 3766141cc406Sopenharmony_ci { 3767141cc406Sopenharmony_ci SANE_Byte *raw_start = raw; 3768141cc406Sopenharmony_ci for (pixel = 0; pixel < s->params.pixels_per_line; 3769141cc406Sopenharmony_ci ++pixel) 3770141cc406Sopenharmony_ci { 3771141cc406Sopenharmony_ci *out_ptr[s->ld.color] = *raw; 3772141cc406Sopenharmony_ci out_ptr[s->ld.color] += 3; 3773141cc406Sopenharmony_ci scale += half_res; 3774141cc406Sopenharmony_ci if (scale >= half_res) 3775141cc406Sopenharmony_ci { 3776141cc406Sopenharmony_ci scale -= res; 3777141cc406Sopenharmony_ci ++raw; 3778141cc406Sopenharmony_ci } 3779141cc406Sopenharmony_ci 3780141cc406Sopenharmony_ci } 3781141cc406Sopenharmony_ci DBG (5, 3782141cc406Sopenharmony_ci "fix_line_distance_se: got line: %d; color: %d; " 3783141cc406Sopenharmony_ci "raw bytes: %lu; out bytes: %d\n", 3784141cc406Sopenharmony_ci lines[s->ld.color], s->ld.color, (u_long) (raw - raw_start), 3785141cc406Sopenharmony_ci s->params.pixels_per_line); 3786141cc406Sopenharmony_ci raw = raw_start + bpc; 3787141cc406Sopenharmony_ci } 3788141cc406Sopenharmony_ci else 3789141cc406Sopenharmony_ci { 3790141cc406Sopenharmony_ci if (preview) 3791141cc406Sopenharmony_ci { 3792141cc406Sopenharmony_ci for (pixel = 0; pixel < bpc; ++pixel) 3793141cc406Sopenharmony_ci { 3794141cc406Sopenharmony_ci *out_ptr[s->ld.color] = *raw++; 3795141cc406Sopenharmony_ci out_ptr[s->ld.color] += 3; 3796141cc406Sopenharmony_ci } 3797141cc406Sopenharmony_ci } 3798141cc406Sopenharmony_ci else 3799141cc406Sopenharmony_ci { 3800141cc406Sopenharmony_ci for (pixel = 0; pixel < bpc; ++pixel) 3801141cc406Sopenharmony_ci { 3802141cc406Sopenharmony_ci scale += res; 3803141cc406Sopenharmony_ci if (scale >= max_value) 3804141cc406Sopenharmony_ci { 3805141cc406Sopenharmony_ci scale -= max_value; 3806141cc406Sopenharmony_ci *out_ptr[s->ld.color] = *raw; 3807141cc406Sopenharmony_ci out_ptr[s->ld.color] += 3; 3808141cc406Sopenharmony_ci } 3809141cc406Sopenharmony_ci ++raw; 3810141cc406Sopenharmony_ci } 3811141cc406Sopenharmony_ci } 3812141cc406Sopenharmony_ci 3813141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: got line: %d; color: " 3814141cc406Sopenharmony_ci "%d\n", lines[s->ld.color], s->ld.color); 3815141cc406Sopenharmony_ci } 3816141cc406Sopenharmony_ci --lines[s->ld.color]; 3817141cc406Sopenharmony_ci } 3818141cc406Sopenharmony_ci else 3819141cc406Sopenharmony_ci { 3820141cc406Sopenharmony_ci /* At least one component missing, so save this line. */ 3821141cc406Sopenharmony_ci memcpy (s->ld.buf[s->ld.color] + s->ld.saved[s->ld.color] 3822141cc406Sopenharmony_ci * bpc, raw, bpc); 3823141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: saved line %d; color %d\n", 3824141cc406Sopenharmony_ci s->ld.saved[s->ld.color], s->ld.color); 3825141cc406Sopenharmony_ci ++(s->ld.saved[s->ld.color]); 3826141cc406Sopenharmony_ci raw += bpc; 3827141cc406Sopenharmony_ci } 3828141cc406Sopenharmony_ci } 3829141cc406Sopenharmony_ci else 3830141cc406Sopenharmony_ci { 3831141cc406Sopenharmony_ci if (!preview) 3832141cc406Sopenharmony_ci raw += bpc; 3833141cc406Sopenharmony_ci DBG (5, "fix_line_distance_se: ignored line; color: %d\n", 3834141cc406Sopenharmony_ci s->ld.color); 3835141cc406Sopenharmony_ci } 3836141cc406Sopenharmony_ci 3837141cc406Sopenharmony_ci if (raw >= raw_end) 3838141cc406Sopenharmony_ci { 3839141cc406Sopenharmony_ci /* Reduce num_lines if we encounter excess lines. */ 3840141cc406Sopenharmony_ci if (num_lines > s->ld.ld_line) 3841141cc406Sopenharmony_ci num_lines = s->ld.ld_line; 3842141cc406Sopenharmony_ci s->ld.ld_line -= num_lines; 3843141cc406Sopenharmony_ci 3844141cc406Sopenharmony_ci if (++s->ld.color > 2) 3845141cc406Sopenharmony_ci s->ld.color = 0; 3846141cc406Sopenharmony_ci return num_lines; 3847141cc406Sopenharmony_ci } 3848141cc406Sopenharmony_ci } 3849141cc406Sopenharmony_ci if (++s->ld.color > 2) 3850141cc406Sopenharmony_ci s->ld.color = 0; 3851141cc406Sopenharmony_ci } 3852141cc406Sopenharmony_ci} 3853141cc406Sopenharmony_ci 3854141cc406Sopenharmony_ci 3855141cc406Sopenharmony_ci/* For Pro models. Not really a linedistance correction (they don't need one) 3856141cc406Sopenharmony_ci only enlarging x-res here */ 3857141cc406Sopenharmony_cistatic void 3858141cc406Sopenharmony_cifix_line_distance_pro (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 3859141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out) 3860141cc406Sopenharmony_ci{ 3861141cc406Sopenharmony_ci SANE_Byte *out_addr, *in_addr; 3862141cc406Sopenharmony_ci SANE_Int res, half_res, y, x_out, x_in; 3863141cc406Sopenharmony_ci 3864141cc406Sopenharmony_ci 3865141cc406Sopenharmony_ci res = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 3866141cc406Sopenharmony_ci half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2; 3867141cc406Sopenharmony_ci 3868141cc406Sopenharmony_ci DBG (5, "fix_line_distance_pro: res=%d; halfres=%d; num_lines=%d; bpl=%d\n", 3869141cc406Sopenharmony_ci res, half_res, num_lines, bpl); 3870141cc406Sopenharmony_ci 3871141cc406Sopenharmony_ci if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0) 3872141cc406Sopenharmony_ci { 3873141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3874141cc406Sopenharmony_ci { 3875141cc406Sopenharmony_ci /*12 bit, need to enlarge x-resolution */ 3876141cc406Sopenharmony_ci DBG (5, "fix_line_distance_pro: res > half_res --> need to " 3877141cc406Sopenharmony_ci "enlarge x\n"); 3878141cc406Sopenharmony_ci if (little_endian ()) 3879141cc406Sopenharmony_ci for (y = 0; y < num_lines; y++) 3880141cc406Sopenharmony_ci { 3881141cc406Sopenharmony_ci for (x_out = 0; x_out < s->params.pixels_per_line; x_out++) 3882141cc406Sopenharmony_ci { 3883141cc406Sopenharmony_ci x_in = x_out * bpl / s->params.bytes_per_line / 2; 3884141cc406Sopenharmony_ci x_in *= 2; 3885141cc406Sopenharmony_ci out_addr = out + y * s->params.bytes_per_line + x_out * 6; 3886141cc406Sopenharmony_ci in_addr = raw + y * bpl + x_in * 6; 3887141cc406Sopenharmony_ci *(out_addr) = *(in_addr) << 4; 3888141cc406Sopenharmony_ci *(out_addr + 1) = (*(in_addr) >> 4) + 3889141cc406Sopenharmony_ci (*(in_addr + 1) << 4); 3890141cc406Sopenharmony_ci *(out_addr + 2) = *(in_addr + 2) << 4; 3891141cc406Sopenharmony_ci *(out_addr + 3) = (*(in_addr + 2) >> 4) + 3892141cc406Sopenharmony_ci (*(in_addr + 3) << 4); 3893141cc406Sopenharmony_ci *(out_addr + 4) = *(in_addr + 4) << 4; 3894141cc406Sopenharmony_ci *(out_addr + 5) = (*(in_addr + 4) >> 4) + 3895141cc406Sopenharmony_ci (*(in_addr + 5) << 4); 3896141cc406Sopenharmony_ci } 3897141cc406Sopenharmony_ci } 3898141cc406Sopenharmony_ci else /* big endian */ 3899141cc406Sopenharmony_ci for (y = 0; y < num_lines; y++) 3900141cc406Sopenharmony_ci { 3901141cc406Sopenharmony_ci for (x_out = 0; x_out < s->params.pixels_per_line; x_out++) 3902141cc406Sopenharmony_ci { 3903141cc406Sopenharmony_ci x_in = x_out * bpl / s->params.bytes_per_line / 2; 3904141cc406Sopenharmony_ci out_addr = out + y * s->params.bytes_per_line + x_out * 6; 3905141cc406Sopenharmony_ci in_addr = raw + y * bpl + x_in * 6; 3906141cc406Sopenharmony_ci *(out_addr) = (*(in_addr) >> 4) + (*(in_addr + 1) << 4); 3907141cc406Sopenharmony_ci *(out_addr + 1) = *(in_addr) << 4; 3908141cc406Sopenharmony_ci *(out_addr + 2) = (*(in_addr + 2) >> 4) + 3909141cc406Sopenharmony_ci (*(in_addr + 3) << 4); 3910141cc406Sopenharmony_ci *(out_addr + 3) = *(in_addr + 2) << 4; 3911141cc406Sopenharmony_ci *(out_addr + 4) = (*(in_addr + 4) >> 4) + 3912141cc406Sopenharmony_ci (*(in_addr + 5) << 4); 3913141cc406Sopenharmony_ci *(out_addr + 5) = *(in_addr + 4) << 4; 3914141cc406Sopenharmony_ci } 3915141cc406Sopenharmony_ci } 3916141cc406Sopenharmony_ci } 3917141cc406Sopenharmony_ci else /* 12 bit, no need to enlarge x */ 3918141cc406Sopenharmony_ci { 3919141cc406Sopenharmony_ci SANE_Word pixel; 3920141cc406Sopenharmony_ci 3921141cc406Sopenharmony_ci if (little_endian ()) 3922141cc406Sopenharmony_ci for (pixel = 0; pixel < (num_lines * bpl / 2); pixel++) 3923141cc406Sopenharmony_ci { 3924141cc406Sopenharmony_ci *(out + pixel * 2) = *(raw + pixel * 2) << 4; 3925141cc406Sopenharmony_ci *(out + pixel * 2 + 1) = (*(raw + pixel * 2) >> 4) + 3926141cc406Sopenharmony_ci (*(raw + pixel * 2 + 1) << 4); 3927141cc406Sopenharmony_ci } 3928141cc406Sopenharmony_ci else /* big endian */ 3929141cc406Sopenharmony_ci for (pixel = 0; pixel < (num_lines * bpl / 2); pixel++) 3930141cc406Sopenharmony_ci { 3931141cc406Sopenharmony_ci *(out + pixel * 2) = (*(raw + pixel * 2) >> 4) + 3932141cc406Sopenharmony_ci (*(raw + pixel * 2 + 1) << 4); 3933141cc406Sopenharmony_ci *(out + pixel * 2 + 1) = *(raw + pixel * 2) << 4; 3934141cc406Sopenharmony_ci } 3935141cc406Sopenharmony_ci 3936141cc406Sopenharmony_ci } 3937141cc406Sopenharmony_ci } 3938141cc406Sopenharmony_ci else /* 8 bit */ 3939141cc406Sopenharmony_ci { 3940141cc406Sopenharmony_ci /* need to enlarge x-resolution? */ 3941141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res)) 3942141cc406Sopenharmony_ci { 3943141cc406Sopenharmony_ci DBG (5, "fix_line_distance_pro: res > half_res --> need to " 3944141cc406Sopenharmony_ci "enlarge x\n"); 3945141cc406Sopenharmony_ci 3946141cc406Sopenharmony_ci for (y = 0; y < num_lines; y++) 3947141cc406Sopenharmony_ci { 3948141cc406Sopenharmony_ci for (x_out = 0; x_out < s->params.pixels_per_line; x_out++) 3949141cc406Sopenharmony_ci { 3950141cc406Sopenharmony_ci x_in = x_out * bpl / s->params.bytes_per_line; 3951141cc406Sopenharmony_ci out_addr = out + y * s->params.bytes_per_line + x_out * 3; 3952141cc406Sopenharmony_ci in_addr = raw + y * bpl + x_in * 3; 3953141cc406Sopenharmony_ci *(out_addr) = *(in_addr); 3954141cc406Sopenharmony_ci *(out_addr + 1) = *(in_addr + 1); 3955141cc406Sopenharmony_ci *(out_addr + 2) = *(in_addr + 2); 3956141cc406Sopenharmony_ci } 3957141cc406Sopenharmony_ci } 3958141cc406Sopenharmony_ci } 3959141cc406Sopenharmony_ci else 3960141cc406Sopenharmony_ci memcpy (out, raw, num_lines * bpl); 3961141cc406Sopenharmony_ci } 3962141cc406Sopenharmony_ci return; 3963141cc406Sopenharmony_ci} 3964141cc406Sopenharmony_ci 3965141cc406Sopenharmony_ci/* For MFS-08000SP, MFS-06000SP. MFC-08000CZ, MFC-06000CZ */ 3966141cc406Sopenharmony_cistatic void 3967141cc406Sopenharmony_cifix_line_distance_normal (Mustek_Scanner * s, SANE_Int num_lines, 3968141cc406Sopenharmony_ci SANE_Int bpl, SANE_Byte * raw, SANE_Byte * out) 3969141cc406Sopenharmony_ci{ 3970141cc406Sopenharmony_ci SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl; 3971141cc406Sopenharmony_ci SANE_Int index[3]; /* index of the next output line for color C */ 3972141cc406Sopenharmony_ci SANE_Int i, color; 3973141cc406Sopenharmony_ci 3974141cc406Sopenharmony_ci /* Initialize the indices with the line distances that were returned 3975141cc406Sopenharmony_ci by the CCD linedistance command or set manually (option 3976141cc406Sopenharmony_ci linedistance-fix). We want to skip data for the first OFFSET 3977141cc406Sopenharmony_ci rounds, so we initialize the indices to the negative of this 3978141cc406Sopenharmony_ci offset. */ 3979141cc406Sopenharmony_ci 3980141cc406Sopenharmony_ci DBG (5, "fix_line_distance_normal: %d lines, %d bpl\n", num_lines, bpl); 3981141cc406Sopenharmony_ci 3982141cc406Sopenharmony_ci for (color = 0; color < 3; ++color) 3983141cc406Sopenharmony_ci index[color] = -s->ld.dist[color]; 3984141cc406Sopenharmony_ci 3985141cc406Sopenharmony_ci while (1) 3986141cc406Sopenharmony_ci { 3987141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3988141cc406Sopenharmony_ci { 3989141cc406Sopenharmony_ci color = color_seq[i]; 3990141cc406Sopenharmony_ci if (index[color] < 0) 3991141cc406Sopenharmony_ci ++index[color]; 3992141cc406Sopenharmony_ci else if (index[color] < num_lines) 3993141cc406Sopenharmony_ci { 3994141cc406Sopenharmony_ci s->ld.quant[color] += s->ld.peak_res; 3995141cc406Sopenharmony_ci if (s->ld.quant[color] > s->ld.max_value) 3996141cc406Sopenharmony_ci { 3997141cc406Sopenharmony_ci s->ld.quant[color] -= s->ld.max_value; 3998141cc406Sopenharmony_ci out_ptr = out + index[color] * bpl + color; 3999141cc406Sopenharmony_ci out_end = out_ptr + bpl; 4000141cc406Sopenharmony_ci while (out_ptr != out_end) 4001141cc406Sopenharmony_ci { 4002141cc406Sopenharmony_ci *out_ptr = *raw++; 4003141cc406Sopenharmony_ci out_ptr += 3; 4004141cc406Sopenharmony_ci } 4005141cc406Sopenharmony_ci ++index[color]; 4006141cc406Sopenharmony_ci if (raw >= raw_end) 4007141cc406Sopenharmony_ci return; 4008141cc406Sopenharmony_ci } 4009141cc406Sopenharmony_ci } 4010141cc406Sopenharmony_ci } 4011141cc406Sopenharmony_ci } 4012141cc406Sopenharmony_ci} 4013141cc406Sopenharmony_ci 4014141cc406Sopenharmony_ci/* Paragon series I + II. */ 4015141cc406Sopenharmony_cistatic SANE_Int 4016141cc406Sopenharmony_cifix_line_distance_block (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 4017141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out, 4018141cc406Sopenharmony_ci SANE_Int num_lines_total) 4019141cc406Sopenharmony_ci{ 4020141cc406Sopenharmony_ci SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl; 4021141cc406Sopenharmony_ci SANE_Int c, num_saved_lines, line, max_index, min_index; 4022141cc406Sopenharmony_ci 4023141cc406Sopenharmony_ci if (!s->ld.buf[0]) 4024141cc406Sopenharmony_ci { 4025141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: allocating temp buffer of %d*%d " 4026141cc406Sopenharmony_ci "bytes\n", MAX_LINE_DIST, bpl); 4027141cc406Sopenharmony_ci s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl); 4028141cc406Sopenharmony_ci if (!s->ld.buf[0]) 4029141cc406Sopenharmony_ci { 4030141cc406Sopenharmony_ci DBG (1, "fix_line_distance_block: failed to malloc temporary " 4031141cc406Sopenharmony_ci "buffer\n"); 4032141cc406Sopenharmony_ci return 0; 4033141cc406Sopenharmony_ci } 4034141cc406Sopenharmony_ci } 4035141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: s->ld.index = {%d, %d, %d}, " 4036141cc406Sopenharmony_ci "s->ld.lmod3 = %d\n", s->ld.index[0], s->ld.index[1], s->ld.index[2], 4037141cc406Sopenharmony_ci s->ld.lmod3); 4038141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: s->ld.quant = {%d, %d, %d}, " 4039141cc406Sopenharmony_ci "s->ld.max_value = %d\n", s->ld.quant[0], s->ld.quant[1], 4040141cc406Sopenharmony_ci s->ld.quant[2], s->ld.max_value); 4041141cc406Sopenharmony_ci DBG (5, 4042141cc406Sopenharmony_ci "fix_line_distance_block: s->ld.peak_res = %d, s->ld.ld_line = %d\n", 4043141cc406Sopenharmony_ci s->ld.peak_res, s->ld.ld_line); 4044141cc406Sopenharmony_ci 4045141cc406Sopenharmony_ci /* search maximum and minimum index */ 4046141cc406Sopenharmony_ci max_index = MAX (s->ld.index[0], MAX (s->ld.index[1], s->ld.index[2])); 4047141cc406Sopenharmony_ci min_index = MIN (s->ld.index[0], MIN (s->ld.index[1], s->ld.index[2])); 4048141cc406Sopenharmony_ci num_saved_lines = max_index - min_index; 4049141cc406Sopenharmony_ci if (s->ld.index[0] == 0) 4050141cc406Sopenharmony_ci num_saved_lines = 0; 4051141cc406Sopenharmony_ci /* restore the previously saved lines: */ 4052141cc406Sopenharmony_ci memcpy (out, s->ld.buf[0], num_saved_lines * bpl); 4053141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: copied %d lines from " 4054141cc406Sopenharmony_ci "ld.buf to buffer (max=%d, min=%d)\n", num_saved_lines, max_index, 4055141cc406Sopenharmony_ci min_index); 4056141cc406Sopenharmony_ci while (1) 4057141cc406Sopenharmony_ci { 4058141cc406Sopenharmony_ci if (++s->ld.lmod3 >= 3) 4059141cc406Sopenharmony_ci s->ld.lmod3 = 0; 4060141cc406Sopenharmony_ci 4061141cc406Sopenharmony_ci c = color_seq[s->ld.lmod3]; 4062141cc406Sopenharmony_ci if (s->ld.index[c] < 0) 4063141cc406Sopenharmony_ci ++s->ld.index[c]; 4064141cc406Sopenharmony_ci else if (s->ld.index[c] < num_lines_total) 4065141cc406Sopenharmony_ci { 4066141cc406Sopenharmony_ci s->ld.quant[c] += s->ld.peak_res; 4067141cc406Sopenharmony_ci if (s->ld.quant[c] > s->ld.max_value) 4068141cc406Sopenharmony_ci { 4069141cc406Sopenharmony_ci s->ld.quant[c] -= s->ld.max_value; 4070141cc406Sopenharmony_ci line = s->ld.index[c]++ - s->ld.ld_line; 4071141cc406Sopenharmony_ci out_ptr = out + line * bpl + c; 4072141cc406Sopenharmony_ci out_end = out_ptr + bpl; 4073141cc406Sopenharmony_ci while (out_ptr != out_end) 4074141cc406Sopenharmony_ci { 4075141cc406Sopenharmony_ci *out_ptr = *raw++; 4076141cc406Sopenharmony_ci out_ptr += 3; 4077141cc406Sopenharmony_ci } 4078141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: copied line %d (color %d)\n", 4079141cc406Sopenharmony_ci line + s->ld.ld_line, c); 4080141cc406Sopenharmony_ci 4081141cc406Sopenharmony_ci max_index = MAX (s->ld.index[0], 4082141cc406Sopenharmony_ci MAX (s->ld.index[1], s->ld.index[2])); 4083141cc406Sopenharmony_ci min_index = MIN (s->ld.index[0], 4084141cc406Sopenharmony_ci MIN (s->ld.index[1], s->ld.index[2])); 4085141cc406Sopenharmony_ci if ((raw >= raw_end) || ((min_index >= num_lines_total))) 4086141cc406Sopenharmony_ci { 4087141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: got num_lines: %d\n", 4088141cc406Sopenharmony_ci num_lines); 4089141cc406Sopenharmony_ci num_lines = min_index - s->ld.ld_line; 4090141cc406Sopenharmony_ci if (num_lines < 0) 4091141cc406Sopenharmony_ci num_lines = 0; 4092141cc406Sopenharmony_ci if ((s->total_lines + num_lines) > s->params.lines) 4093141cc406Sopenharmony_ci num_lines = s->params.lines - s->total_lines; 4094141cc406Sopenharmony_ci s->total_lines += num_lines; 4095141cc406Sopenharmony_ci 4096141cc406Sopenharmony_ci /* copy away the lines with at least one missing 4097141cc406Sopenharmony_ci color component, so that we can interleave them 4098141cc406Sopenharmony_ci with new scan data on the next call */ 4099141cc406Sopenharmony_ci num_saved_lines = max_index - min_index; 4100141cc406Sopenharmony_ci 4101141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: num_saved_lines = %d; " 4102141cc406Sopenharmony_ci "num_lines = %d; bpl = %d\n", num_saved_lines, 4103141cc406Sopenharmony_ci num_lines, bpl); 4104141cc406Sopenharmony_ci 4105141cc406Sopenharmony_ci memcpy (s->ld.buf[0], out + num_lines * bpl, 4106141cc406Sopenharmony_ci num_saved_lines * bpl); 4107141cc406Sopenharmony_ci 4108141cc406Sopenharmony_ci DBG (5, "fix_line_distance_block: copied %d lines to " 4109141cc406Sopenharmony_ci "ld.buf\n", num_saved_lines); 4110141cc406Sopenharmony_ci 4111141cc406Sopenharmony_ci /* notice the number of lines we processed */ 4112141cc406Sopenharmony_ci s->ld.ld_line = min_index; 4113141cc406Sopenharmony_ci if (s->ld.ld_line < 0) 4114141cc406Sopenharmony_ci s->ld.ld_line = 0; 4115141cc406Sopenharmony_ci 4116141cc406Sopenharmony_ci DBG (4, "fix_line_distance_block: lmod3=%d, " 4117141cc406Sopenharmony_ci "index=(%d,%d,%d), line = %d, lines = %d\n", 4118141cc406Sopenharmony_ci s->ld.lmod3, 4119141cc406Sopenharmony_ci s->ld.index[0], s->ld.index[1], s->ld.index[2], 4120141cc406Sopenharmony_ci s->ld.ld_line, num_lines); 4121141cc406Sopenharmony_ci /* return number of complete (r+g+b) lines */ 4122141cc406Sopenharmony_ci return num_lines; 4123141cc406Sopenharmony_ci } 4124141cc406Sopenharmony_ci } 4125141cc406Sopenharmony_ci } 4126141cc406Sopenharmony_ci } 4127141cc406Sopenharmony_ci} 4128141cc406Sopenharmony_ci 4129141cc406Sopenharmony_ci/* For MFS-1200SP 1.00 and others */ 4130141cc406Sopenharmony_ci/* No LD correction necessary, just shuffle around data */ 4131141cc406Sopenharmony_cistatic SANE_Int 4132141cc406Sopenharmony_cifix_line_distance_none (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, 4133141cc406Sopenharmony_ci SANE_Byte * raw, SANE_Byte * out) 4134141cc406Sopenharmony_ci{ 4135141cc406Sopenharmony_ci SANE_Byte *red_ptr, *grn_ptr, *blu_ptr, *ptr, *ptr_end; 4136141cc406Sopenharmony_ci SANE_Word y; 4137141cc406Sopenharmony_ci 4138141cc406Sopenharmony_ci ptr = out; 4139141cc406Sopenharmony_ci red_ptr = raw; 4140141cc406Sopenharmony_ci 4141141cc406Sopenharmony_ci DBG (5, "fix_line_distance_none: no ld correction necessary (%d lines)\n", 4142141cc406Sopenharmony_ci num_lines); 4143141cc406Sopenharmony_ci 4144141cc406Sopenharmony_ci s->ld.ld_line += num_lines; 4145141cc406Sopenharmony_ci 4146141cc406Sopenharmony_ci if (s->ld.ld_line > s->params.lines) 4147141cc406Sopenharmony_ci num_lines -= (s->ld.ld_line - s->params.lines); 4148141cc406Sopenharmony_ci if (num_lines < 0) 4149141cc406Sopenharmony_ci num_lines = 0; 4150141cc406Sopenharmony_ci 4151141cc406Sopenharmony_ci DBG (5, "fix_line_distance_none: using %d lines (ld_line = %d, " 4152141cc406Sopenharmony_ci "s->params.lines = %d)\n", num_lines, s->ld.ld_line, s->params.lines); 4153141cc406Sopenharmony_ci 4154141cc406Sopenharmony_ci for (y = 0; y < num_lines; ++y) 4155141cc406Sopenharmony_ci { 4156141cc406Sopenharmony_ci grn_ptr = red_ptr + bpl / 3; 4157141cc406Sopenharmony_ci blu_ptr = grn_ptr + bpl / 3; 4158141cc406Sopenharmony_ci ptr_end = red_ptr + bpl; 4159141cc406Sopenharmony_ci 4160141cc406Sopenharmony_ci while (blu_ptr != ptr_end) 4161141cc406Sopenharmony_ci { 4162141cc406Sopenharmony_ci *ptr++ = *red_ptr++; 4163141cc406Sopenharmony_ci *ptr++ = *grn_ptr++; 4164141cc406Sopenharmony_ci *ptr++ = *blu_ptr++; 4165141cc406Sopenharmony_ci } 4166141cc406Sopenharmony_ci red_ptr = ptr_end; 4167141cc406Sopenharmony_ci } 4168141cc406Sopenharmony_ci return num_lines; 4169141cc406Sopenharmony_ci} 4170141cc406Sopenharmony_ci 4171141cc406Sopenharmony_ci 4172141cc406Sopenharmony_cistatic SANE_Status 4173141cc406Sopenharmony_ciinit_options (Mustek_Scanner * s) 4174141cc406Sopenharmony_ci{ 4175141cc406Sopenharmony_ci SANE_Int i, j, gammasize; 4176141cc406Sopenharmony_ci 4177141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 4178141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 4179141cc406Sopenharmony_ci 4180141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 4181141cc406Sopenharmony_ci { 4182141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 4183141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 4184141cc406Sopenharmony_ci } 4185141cc406Sopenharmony_ci 4186141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].name = ""; 4187141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 4188141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 4189141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 4190141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 4191141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 4192141cc406Sopenharmony_ci 4193141cc406Sopenharmony_ci /* "Mode" group: */ 4194141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); 4195141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 4196141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 4197141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 4198141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].size = 0; 4199141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 4200141cc406Sopenharmony_ci 4201141cc406Sopenharmony_ci /* scan mode */ 4202141cc406Sopenharmony_ci s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 4203141cc406Sopenharmony_ci s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 4204141cc406Sopenharmony_ci s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 4205141cc406Sopenharmony_ci s->opt[OPT_MODE].type = SANE_TYPE_STRING; 4206141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4207141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_SE) 4208141cc406Sopenharmony_ci { 4209141cc406Sopenharmony_ci s->opt[OPT_MODE].size = max_string_size (mode_list_se); 4210141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list_se; 4211141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list_se[1]); 4212141cc406Sopenharmony_ci if (!s->val[OPT_MODE].s) 4213141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4214141cc406Sopenharmony_ci } 4215141cc406Sopenharmony_ci else 4216141cc406Sopenharmony_ci { 4217141cc406Sopenharmony_ci s->opt[OPT_MODE].size = max_string_size (mode_list_paragon); 4218141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list_paragon; 4219141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list_paragon[2]); 4220141cc406Sopenharmony_ci if (!s->val[OPT_MODE].s) 4221141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4222141cc406Sopenharmony_ci } 4223141cc406Sopenharmony_ci 4224141cc406Sopenharmony_ci /* fast gray mode (pro models) */ 4225141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].name = "fast-gray-mode"; 4226141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].title = SANE_I18N ("Fast gray mode"); 4227141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].desc = SANE_I18N ("Scan in fast gray mode " 4228141cc406Sopenharmony_ci "(lower quality)."); 4229141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].type = SANE_TYPE_BOOL; 4230141cc406Sopenharmony_ci s->val[OPT_FAST_GRAY_MODE].w = SANE_FALSE; 4231141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].cap |= SANE_CAP_INACTIVE; 4232141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PRO) 4233141cc406Sopenharmony_ci { 4234141cc406Sopenharmony_ci /* Only Pro models support fast gray mode */ 4235141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].cap &= ~SANE_CAP_INACTIVE; 4236141cc406Sopenharmony_ci } 4237141cc406Sopenharmony_ci 4238141cc406Sopenharmony_ci /* resolution */ 4239141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 4240141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 4241141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 4242141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED; 4243141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 4244141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 4245141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range; 4246141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].w = MAX (SANE_FIX (72), s->hw->dpi_range.min); 4247141cc406Sopenharmony_ci 4248141cc406Sopenharmony_ci /* bit depth */ 4249141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; 4250141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; 4251141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; 4252141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_STRING; 4253141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4254141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 4255141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].size = max_string_size (bit_depth_list_pro); 4256141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].constraint.string_list = bit_depth_list_pro; 4257141cc406Sopenharmony_ci s->val[OPT_BIT_DEPTH].s = strdup (bit_depth_list_pro[0]); 4258141cc406Sopenharmony_ci if (!s->val[OPT_BIT_DEPTH].s) 4259141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4260141cc406Sopenharmony_ci 4261141cc406Sopenharmony_ci /* speed */ 4262141cc406Sopenharmony_ci s->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED; 4263141cc406Sopenharmony_ci s->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED; 4264141cc406Sopenharmony_ci s->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED; 4265141cc406Sopenharmony_ci s->opt[OPT_SPEED].type = SANE_TYPE_STRING; 4266141cc406Sopenharmony_ci s->opt[OPT_SPEED].size = max_string_size (speed_list); 4267141cc406Sopenharmony_ci s->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4268141cc406Sopenharmony_ci s->opt[OPT_SPEED].constraint.string_list = speed_list; 4269141cc406Sopenharmony_ci s->val[OPT_SPEED].s = strdup (speed_list[4]); 4270141cc406Sopenharmony_ci if (!s->val[OPT_SPEED].s) 4271141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4272141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 4273141cc406Sopenharmony_ci { 4274141cc406Sopenharmony_ci /* Speed only supported by 3-pass scanners */ 4275141cc406Sopenharmony_ci s->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE; 4276141cc406Sopenharmony_ci } 4277141cc406Sopenharmony_ci 4278141cc406Sopenharmony_ci /* source */ 4279141cc406Sopenharmony_ci s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; 4280141cc406Sopenharmony_ci s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; 4281141cc406Sopenharmony_ci s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; 4282141cc406Sopenharmony_ci s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; 4283141cc406Sopenharmony_ci 4284141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_SE) || (s->hw->flags & MUSTEK_FLAG_N) 4285141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_TA)) 4286141cc406Sopenharmony_ci { 4287141cc406Sopenharmony_ci s->opt[OPT_SOURCE].size = max_string_size (ta_source_list); 4288141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4289141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint.string_list = ta_source_list; 4290141cc406Sopenharmony_ci s->val[OPT_SOURCE].s = strdup (ta_source_list[0]); 4291141cc406Sopenharmony_ci if (!s->val[OPT_SOURCE].s) 4292141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4293141cc406Sopenharmony_ci } 4294141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_ADF) 4295141cc406Sopenharmony_ci { 4296141cc406Sopenharmony_ci s->opt[OPT_SOURCE].size = max_string_size (adf_source_list); 4297141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4298141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint.string_list = adf_source_list; 4299141cc406Sopenharmony_ci s->val[OPT_SOURCE].s = strdup (adf_source_list[0]); 4300141cc406Sopenharmony_ci if (!s->val[OPT_SOURCE].s) 4301141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4302141cc406Sopenharmony_ci } 4303141cc406Sopenharmony_ci else 4304141cc406Sopenharmony_ci { 4305141cc406Sopenharmony_ci s->opt[OPT_SOURCE].size = max_string_size (source_list); 4306141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 4307141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint.string_list = source_list; 4308141cc406Sopenharmony_ci s->val[OPT_SOURCE].s = strdup (source_list[0]); 4309141cc406Sopenharmony_ci s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; 4310141cc406Sopenharmony_ci if (!s->val[OPT_SOURCE].s) 4311141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4312141cc406Sopenharmony_ci } 4313141cc406Sopenharmony_ci 4314141cc406Sopenharmony_ci /* preview */ 4315141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; 4316141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; 4317141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; 4318141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; 4319141cc406Sopenharmony_ci s->val[OPT_PREVIEW].w = 0; 4320141cc406Sopenharmony_ci 4321141cc406Sopenharmony_ci /* fast preview */ 4322141cc406Sopenharmony_ci s->opt[OPT_FAST_PREVIEW].name = "fast-preview"; 4323141cc406Sopenharmony_ci s->opt[OPT_FAST_PREVIEW].title = SANE_I18N ("Fast preview"); 4324141cc406Sopenharmony_ci s->opt[OPT_FAST_PREVIEW].desc = SANE_I18N ("Request that all previews are " 4325141cc406Sopenharmony_ci "done in the fastest (low-quality) mode. This may be a non-color " 4326141cc406Sopenharmony_ci "mode or a low resolution mode."); 4327141cc406Sopenharmony_ci s->opt[OPT_FAST_PREVIEW].type = SANE_TYPE_BOOL; 4328141cc406Sopenharmony_ci s->val[OPT_FAST_PREVIEW].w = SANE_FALSE; 4329141cc406Sopenharmony_ci 4330141cc406Sopenharmony_ci /* lamp off time*/ 4331141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; 4332141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time (minutes)"); 4333141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].desc = SANE_I18N ("Set the time (in minutes) after " 4334141cc406Sopenharmony_ci "which the lamp is shut off."); 4335141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; 4336141cc406Sopenharmony_ci if (strcmp (s->hw->sane.model, "1200 A3 PRO") != 0) 4337141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].cap |= SANE_CAP_INACTIVE; 4338141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; 4339141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_TIME].constraint.range = &u8_range; 4340141cc406Sopenharmony_ci s->val[OPT_LAMP_OFF_TIME].w = 60; 4341141cc406Sopenharmony_ci 4342141cc406Sopenharmony_ci /* shut lamp off */ 4343141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].name = "lamp-off"; 4344141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].title = SANE_I18N ("Turn lamp off"); 4345141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].desc = SANE_I18N ("Turns the lamp off immediately."); 4346141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].type = SANE_TYPE_BUTTON; 4347141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].cap = SANE_CAP_SOFT_SELECT; 4348141cc406Sopenharmony_ci if (strcmp (s->hw->sane.model, "1200 A3 PRO") != 0) 4349141cc406Sopenharmony_ci s->opt[OPT_LAMP_OFF_BUTTON].cap |= SANE_CAP_INACTIVE; 4350141cc406Sopenharmony_ci 4351141cc406Sopenharmony_ci /* "Geometry" group: */ 4352141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); 4353141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 4354141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 4355141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 4356141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].size = 0; 4357141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 4358141cc406Sopenharmony_ci 4359141cc406Sopenharmony_ci /* top-left x */ 4360141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 4361141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 4362141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 4363141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 4364141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 4365141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 4366141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &s->hw->x_range; 4367141cc406Sopenharmony_ci s->val[OPT_TL_X].w = s->hw->x_range.min; 4368141cc406Sopenharmony_ci 4369141cc406Sopenharmony_ci /* top-left y */ 4370141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 4371141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 4372141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 4373141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 4374141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 4375141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 4376141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range; 4377141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = s->hw->y_range.min; 4378141cc406Sopenharmony_ci 4379141cc406Sopenharmony_ci /* bottom-right x */ 4380141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 4381141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 4382141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 4383141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 4384141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 4385141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 4386141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &s->hw->x_range; 4387141cc406Sopenharmony_ci s->val[OPT_BR_X].w = s->hw->x_range.max; 4388141cc406Sopenharmony_ci 4389141cc406Sopenharmony_ci /* bottom-right y */ 4390141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 4391141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 4392141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 4393141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 4394141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 4395141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 4396141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range; 4397141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = s->hw->y_range.max; 4398141cc406Sopenharmony_ci 4399141cc406Sopenharmony_ci /* "Enhancement" group: */ 4400141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); 4401141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 4402141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 4403141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 4404141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].size = 0; 4405141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 4406141cc406Sopenharmony_ci 4407141cc406Sopenharmony_ci /* brightness */ 4408141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 4409141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 4410141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 4411141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED; 4412141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT; 4413141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 4414141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range; 4415141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 4416141cc406Sopenharmony_ci /* 1-pass scanners don't support brightness in multibit mode */ 4417141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE; 4418141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = 0; 4419141cc406Sopenharmony_ci 4420141cc406Sopenharmony_ci /* brightness red */ 4421141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].name = "brightness-r"; 4422141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].title = SANE_I18N ("Red brightness"); 4423141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].desc = SANE_I18N ("Controls the brightness of " 4424141cc406Sopenharmony_ci "the red channel of the " 4425141cc406Sopenharmony_ci "acquired image."); 4426141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].type = SANE_TYPE_FIXED; 4427141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].unit = SANE_UNIT_PERCENT; 4428141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].constraint_type = SANE_CONSTRAINT_RANGE; 4429141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].constraint.range = &percentage_range; 4430141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].cap |= SANE_CAP_INACTIVE; 4431141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS_R].w = 0; 4432141cc406Sopenharmony_ci 4433141cc406Sopenharmony_ci /* brightness green */ 4434141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].name = "brightness-g"; 4435141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].title = SANE_I18N ("Green brightness"); 4436141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].desc = SANE_I18N ("Controls the brightness of " 4437141cc406Sopenharmony_ci "the green channel of the " 4438141cc406Sopenharmony_ci "acquired image."); 4439141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].type = SANE_TYPE_FIXED; 4440141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].unit = SANE_UNIT_PERCENT; 4441141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].constraint_type = SANE_CONSTRAINT_RANGE; 4442141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].constraint.range = &percentage_range; 4443141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].cap |= SANE_CAP_INACTIVE; 4444141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS_G].w = 0; 4445141cc406Sopenharmony_ci 4446141cc406Sopenharmony_ci /* brightness blue */ 4447141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].name = "brightness-b"; 4448141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].title = SANE_I18N ("Blue brightness"); 4449141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].desc = SANE_I18N ("Controls the brightness of " 4450141cc406Sopenharmony_ci "the blue channel of the " 4451141cc406Sopenharmony_ci "acquired image."); 4452141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].type = SANE_TYPE_FIXED; 4453141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].unit = SANE_UNIT_PERCENT; 4454141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].constraint_type = SANE_CONSTRAINT_RANGE; 4455141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].constraint.range = &percentage_range; 4456141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].cap |= SANE_CAP_INACTIVE; 4457141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS_B].w = 0; 4458141cc406Sopenharmony_ci 4459141cc406Sopenharmony_ci /* contrast */ 4460141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 4461141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 4462141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 4463141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED; 4464141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT; 4465141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 4466141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &percentage_range; 4467141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 4468141cc406Sopenharmony_ci /* 1-pass scanners don't support contrast in multibit mode */ 4469141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; 4470141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = 0; 4471141cc406Sopenharmony_ci 4472141cc406Sopenharmony_ci /* contrast red */ 4473141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].name = "contrast-r"; 4474141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].title = SANE_I18N ("Contrast red channel"); 4475141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].desc = SANE_I18N ("Controls the contrast of " 4476141cc406Sopenharmony_ci "the red channel of the " 4477141cc406Sopenharmony_ci "acquired image."); 4478141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].type = SANE_TYPE_FIXED; 4479141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].unit = SANE_UNIT_PERCENT; 4480141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].constraint_type = SANE_CONSTRAINT_RANGE; 4481141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].constraint.range = &percentage_range; 4482141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].cap |= SANE_CAP_INACTIVE; 4483141cc406Sopenharmony_ci s->val[OPT_CONTRAST_R].w = 0; 4484141cc406Sopenharmony_ci 4485141cc406Sopenharmony_ci /* contrast green */ 4486141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].name = "contrast-g"; 4487141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].title = SANE_I18N ("Contrast green channel"); 4488141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].desc = SANE_I18N ("Controls the contrast of " 4489141cc406Sopenharmony_ci "the green channel of the " 4490141cc406Sopenharmony_ci "acquired image."); 4491141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].type = SANE_TYPE_FIXED; 4492141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].unit = SANE_UNIT_PERCENT; 4493141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].constraint_type = SANE_CONSTRAINT_RANGE; 4494141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].constraint.range = &percentage_range; 4495141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].cap |= SANE_CAP_INACTIVE; 4496141cc406Sopenharmony_ci s->val[OPT_CONTRAST_G].w = 0; 4497141cc406Sopenharmony_ci 4498141cc406Sopenharmony_ci /* contrast blue */ 4499141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].name = "contrast-b"; 4500141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].title = SANE_I18N ("Contrast blue channel"); 4501141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].desc = SANE_I18N ("Controls the contrast of " 4502141cc406Sopenharmony_ci "the blue channel of the " 4503141cc406Sopenharmony_ci "acquired image."); 4504141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].type = SANE_TYPE_FIXED; 4505141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].unit = SANE_UNIT_PERCENT; 4506141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].constraint_type = SANE_CONSTRAINT_RANGE; 4507141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].constraint.range = &percentage_range; 4508141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].cap |= SANE_CAP_INACTIVE; 4509141cc406Sopenharmony_ci s->val[OPT_CONTRAST_B].w = 0; 4510141cc406Sopenharmony_ci 4511141cc406Sopenharmony_ci /* gamma */ 4512141cc406Sopenharmony_ci gammasize = 256; 4513141cc406Sopenharmony_ci for (i = 0; i < 4; ++i) 4514141cc406Sopenharmony_ci for (j = 0; j < gammasize; ++j) 4515141cc406Sopenharmony_ci s->gamma_table[i][j] = j; 4516141cc406Sopenharmony_ci 4517141cc406Sopenharmony_ci /* custom-gamma table */ 4518141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; 4519141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; 4520141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; 4521141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; 4522141cc406Sopenharmony_ci s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE; 4523141cc406Sopenharmony_ci 4524141cc406Sopenharmony_ci /* grayscale gamma vector */ 4525141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; 4526141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; 4527141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; 4528141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT; 4529141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 4530141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE; 4531141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word); 4532141cc406Sopenharmony_ci s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0]; 4533141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE; 4534141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range; 4535141cc406Sopenharmony_ci 4536141cc406Sopenharmony_ci /* red gamma vector */ 4537141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; 4538141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; 4539141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; 4540141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT; 4541141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 4542141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE; 4543141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word); 4544141cc406Sopenharmony_ci s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0]; 4545141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE; 4546141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range; 4547141cc406Sopenharmony_ci 4548141cc406Sopenharmony_ci /* green gamma vector */ 4549141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; 4550141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; 4551141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; 4552141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT; 4553141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 4554141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE; 4555141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word); 4556141cc406Sopenharmony_ci s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0]; 4557141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE; 4558141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range; 4559141cc406Sopenharmony_ci 4560141cc406Sopenharmony_ci /* blue gamma vector */ 4561141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; 4562141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; 4563141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; 4564141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT; 4565141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 4566141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE; 4567141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word); 4568141cc406Sopenharmony_ci s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0]; 4569141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE; 4570141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range; 4571141cc406Sopenharmony_ci 4572141cc406Sopenharmony_ci /* quality calibration */ 4573141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].name = SANE_NAME_QUALITY_CAL; 4574141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].title = SANE_TITLE_QUALITY_CAL; 4575141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].desc = SANE_DESC_QUALITY_CAL; 4576141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].type = SANE_TYPE_BOOL; 4577141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PRO) 4578141cc406Sopenharmony_ci s->val[OPT_QUALITY_CAL].w = SANE_TRUE; 4579141cc406Sopenharmony_ci else 4580141cc406Sopenharmony_ci s->val[OPT_QUALITY_CAL].w = SANE_FALSE; 4581141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].cap |= SANE_CAP_INACTIVE; 4582141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_PRO) 4583141cc406Sopenharmony_ci || (s->hw->flags & MUSTEK_FLAG_SE_PLUS)) 4584141cc406Sopenharmony_ci { 4585141cc406Sopenharmony_ci /* Only Pro and SE Plus models support calibration */ 4586141cc406Sopenharmony_ci s->opt[OPT_QUALITY_CAL].cap &= ~SANE_CAP_INACTIVE; 4587141cc406Sopenharmony_ci } 4588141cc406Sopenharmony_ci 4589141cc406Sopenharmony_ci /* halftone dimension */ 4590141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].name = SANE_NAME_HALFTONE_DIMENSION; 4591141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].title = SANE_TITLE_HALFTONE_DIMENSION; 4592141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].desc = SANE_DESC_HALFTONE_DIMENSION; 4593141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].type = SANE_TYPE_STRING; 4594141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].size = max_string_size (halftone_list); 4595141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].constraint_type = 4596141cc406Sopenharmony_ci SANE_CONSTRAINT_STRING_LIST; 4597141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].constraint.string_list = halftone_list; 4598141cc406Sopenharmony_ci s->val[OPT_HALFTONE_DIMENSION].s = strdup (halftone_list[0]); 4599141cc406Sopenharmony_ci if (!s->val[OPT_HALFTONE_DIMENSION].s) 4600141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4601141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].cap |= SANE_CAP_INACTIVE; 4602141cc406Sopenharmony_ci 4603141cc406Sopenharmony_ci /* halftone pattern */ 4604141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; 4605141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; 4606141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN; 4607141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_INT; 4608141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; 4609141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_RANGE; 4610141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].constraint.range = &u8_range; 4611141cc406Sopenharmony_ci s->val[OPT_HALFTONE_PATTERN].wa = s->halftone_pattern; 4612141cc406Sopenharmony_ci 4613141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4614141cc406Sopenharmony_ci} 4615141cc406Sopenharmony_ci 4616141cc406Sopenharmony_ci/* The following three functions execute as a child process. The 4617141cc406Sopenharmony_ci reason for using a subprocess is that some (most?) generic SCSI 4618141cc406Sopenharmony_ci interfaces block a SCSI request until it has completed. With a 4619141cc406Sopenharmony_ci subprocess, we can let it block waiting for the request to finish 4620141cc406Sopenharmony_ci while the main process can go about to do more important things 4621141cc406Sopenharmony_ci (such as recognizing when the user presses a cancel button). 4622141cc406Sopenharmony_ci 4623141cc406Sopenharmony_ci WARNING: Since this is executed as a subprocess, it's NOT possible 4624141cc406Sopenharmony_ci to update any of the variables in the main process (in particular 4625141cc406Sopenharmony_ci the scanner state cannot be updated). 4626141cc406Sopenharmony_ci 4627141cc406Sopenharmony_ci NOTE: At least for Linux, it seems that we could get rid of the 4628141cc406Sopenharmony_ci subprocess. Linux v2.0 does seem to allow select() on SCSI 4629141cc406Sopenharmony_ci descriptors. */ 4630141cc406Sopenharmony_ci 4631141cc406Sopenharmony_cistatic void 4632141cc406Sopenharmony_cioutput_data (Mustek_Scanner * s, FILE * fp, 4633141cc406Sopenharmony_ci SANE_Byte * data, SANE_Int lines_per_buffer, SANE_Int bpl, 4634141cc406Sopenharmony_ci SANE_Byte * extra) 4635141cc406Sopenharmony_ci{ 4636141cc406Sopenharmony_ci SANE_Byte *ptr, *ptr_end; 4637141cc406Sopenharmony_ci SANE_Int y, num_lines; 4638141cc406Sopenharmony_ci 4639141cc406Sopenharmony_ci DBG (5, "output_data: data=%p, lpb=%d, bpl=%d, extra=%p\n", 4640141cc406Sopenharmony_ci (void *) data, lines_per_buffer, bpl, (void *) extra); 4641141cc406Sopenharmony_ci 4642141cc406Sopenharmony_ci /* convert to pixel-interleaved format: */ 4643141cc406Sopenharmony_ci if ((s->mode & MUSTEK_MODE_COLOR) 4644141cc406Sopenharmony_ci && !(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 4645141cc406Sopenharmony_ci { 4646141cc406Sopenharmony_ci num_lines = lines_per_buffer; 4647141cc406Sopenharmony_ci 4648141cc406Sopenharmony_ci /* need to correct for distance between r/g/b sensors: */ 4649141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PRO) 4650141cc406Sopenharmony_ci fix_line_distance_pro (s, num_lines, bpl, data, extra); 4651141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SE) 4652141cc406Sopenharmony_ci { 4653141cc406Sopenharmony_ci num_lines = fix_line_distance_se (s, num_lines, bpl, data, extra); 4654141cc406Sopenharmony_ci } 4655141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_N) 4656141cc406Sopenharmony_ci { 4657141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_LD_N2) 4658141cc406Sopenharmony_ci num_lines = fix_line_distance_n_2 (s, num_lines, bpl, data, 4659141cc406Sopenharmony_ci extra); 4660141cc406Sopenharmony_ci else 4661141cc406Sopenharmony_ci num_lines = fix_line_distance_n_1 (s, num_lines, bpl, data, 4662141cc406Sopenharmony_ci extra); 4663141cc406Sopenharmony_ci } 4664141cc406Sopenharmony_ci else if ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK) 4665141cc406Sopenharmony_ci && (s->ld.max_value != 0)) 4666141cc406Sopenharmony_ci { 4667141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_PARAGON_1) 4668141cc406Sopenharmony_ci num_lines = fix_line_distance_block (s, num_lines, bpl, data, 4669141cc406Sopenharmony_ci extra, s->hw->lines); 4670141cc406Sopenharmony_ci else 4671141cc406Sopenharmony_ci num_lines = fix_line_distance_block (s, num_lines, bpl, data, 4672141cc406Sopenharmony_ci extra, 4673141cc406Sopenharmony_ci s->hw->lines_per_block); 4674141cc406Sopenharmony_ci } 4675141cc406Sopenharmony_ci else if (!(s->hw->flags & MUSTEK_FLAG_LD_NONE) 4676141cc406Sopenharmony_ci && (s->ld.max_value != 0)) 4677141cc406Sopenharmony_ci fix_line_distance_normal (s, num_lines, bpl, data, extra); 4678141cc406Sopenharmony_ci else 4679141cc406Sopenharmony_ci num_lines = fix_line_distance_none (s, num_lines, bpl, data, extra); 4680141cc406Sopenharmony_ci 4681141cc406Sopenharmony_ci if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) 4682141cc406Sopenharmony_ci { 4683141cc406Sopenharmony_ci /* need to revert line direction */ 4684141cc406Sopenharmony_ci SANE_Int line_number; 4685141cc406Sopenharmony_ci SANE_Int byte_number; 4686141cc406Sopenharmony_ci 4687141cc406Sopenharmony_ci DBG (5, "output_data: ADF found, mirroring lines\n"); 4688141cc406Sopenharmony_ci for (line_number = 0; line_number < num_lines; line_number++) 4689141cc406Sopenharmony_ci { 4690141cc406Sopenharmony_ci for (byte_number = bpl - 3; byte_number >= 0; byte_number -= 3) 4691141cc406Sopenharmony_ci { 4692141cc406Sopenharmony_ci fputc (*(extra + line_number * bpl + byte_number), fp); 4693141cc406Sopenharmony_ci fputc (*(extra + line_number * bpl + byte_number + 1), fp); 4694141cc406Sopenharmony_ci fputc (*(extra + line_number * bpl + byte_number + 2), fp); 4695141cc406Sopenharmony_ci } 4696141cc406Sopenharmony_ci } 4697141cc406Sopenharmony_ci } 4698141cc406Sopenharmony_ci else 4699141cc406Sopenharmony_ci fwrite (extra, num_lines, s->params.bytes_per_line, fp); 4700141cc406Sopenharmony_ci } 4701141cc406Sopenharmony_ci else 4702141cc406Sopenharmony_ci { 4703141cc406Sopenharmony_ci DBG (5, "output_data: write %d lpb; %d bpl\n", lines_per_buffer, bpl); 4704141cc406Sopenharmony_ci /* Scale x-resolution above 1/2 of the maximum resolution for 4705141cc406Sopenharmony_ci SE and Pro scanners */ 4706141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && 4707141cc406Sopenharmony_ci (s->val[OPT_RESOLUTION].w > (s->hw->dpi_range.max / 2))) 4708141cc406Sopenharmony_ci { 4709141cc406Sopenharmony_ci SANE_Int x; 4710141cc406Sopenharmony_ci SANE_Int half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2; 4711141cc406Sopenharmony_ci SANE_Int res = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 4712141cc406Sopenharmony_ci SANE_Int res_counter; 4713141cc406Sopenharmony_ci SANE_Int enlarged_x; 4714141cc406Sopenharmony_ci 4715141cc406Sopenharmony_ci DBG (5, "output_data: enlarge lines from %d bpl to %d bpl\n", 4716141cc406Sopenharmony_ci s->hw->bpl, s->params.bytes_per_line); 4717141cc406Sopenharmony_ci 4718141cc406Sopenharmony_ci for (y = 0; y < lines_per_buffer; y++) 4719141cc406Sopenharmony_ci { 4720141cc406Sopenharmony_ci SANE_Byte byte = 0; 4721141cc406Sopenharmony_ci 4722141cc406Sopenharmony_ci x = 0; 4723141cc406Sopenharmony_ci res_counter = 0; 4724141cc406Sopenharmony_ci enlarged_x = 0; 4725141cc406Sopenharmony_ci 4726141cc406Sopenharmony_ci while (enlarged_x < s->params.pixels_per_line) 4727141cc406Sopenharmony_ci { 4728141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_GRAY) 4729141cc406Sopenharmony_ci { 4730141cc406Sopenharmony_ci fputc (*(data + y * bpl + x), fp); 4731141cc406Sopenharmony_ci res_counter += half_res; 4732141cc406Sopenharmony_ci if (res_counter >= half_res) 4733141cc406Sopenharmony_ci { 4734141cc406Sopenharmony_ci res_counter -= res; 4735141cc406Sopenharmony_ci x++; 4736141cc406Sopenharmony_ci } 4737141cc406Sopenharmony_ci enlarged_x++; 4738141cc406Sopenharmony_ci } 4739141cc406Sopenharmony_ci else /* lineart */ 4740141cc406Sopenharmony_ci { 4741141cc406Sopenharmony_ci /* need to invert image because of funny SANE 1-bit image 4742141cc406Sopenharmony_ci polarity */ 4743141cc406Sopenharmony_ci if (*(data + x / 8 + y * bpl) & (1 << (7 - (x % 8)))) 4744141cc406Sopenharmony_ci byte |= 1 << (7 - (enlarged_x % 8)); 4745141cc406Sopenharmony_ci 4746141cc406Sopenharmony_ci if ((enlarged_x % 8) == 7) 4747141cc406Sopenharmony_ci { 4748141cc406Sopenharmony_ci fputc (~byte, fp); /* invert image */ 4749141cc406Sopenharmony_ci byte = 0; 4750141cc406Sopenharmony_ci } 4751141cc406Sopenharmony_ci res_counter += half_res; 4752141cc406Sopenharmony_ci if (res_counter >= half_res) 4753141cc406Sopenharmony_ci { 4754141cc406Sopenharmony_ci res_counter -= res; 4755141cc406Sopenharmony_ci x++; 4756141cc406Sopenharmony_ci } 4757141cc406Sopenharmony_ci enlarged_x++; 4758141cc406Sopenharmony_ci } 4759141cc406Sopenharmony_ci } 4760141cc406Sopenharmony_ci } 4761141cc406Sopenharmony_ci } 4762141cc406Sopenharmony_ci else /* lineart, gray or halftone (nothing to scale) */ 4763141cc406Sopenharmony_ci { 4764141cc406Sopenharmony_ci if ((s->mode & MUSTEK_MODE_LINEART) 4765141cc406Sopenharmony_ci || (s->mode & MUSTEK_MODE_HALFTONE)) 4766141cc406Sopenharmony_ci { 4767141cc406Sopenharmony_ci /* need to invert image because of funny SANE 1-bit image 4768141cc406Sopenharmony_ci polarity */ 4769141cc406Sopenharmony_ci ptr = data; 4770141cc406Sopenharmony_ci ptr_end = ptr + lines_per_buffer * bpl; 4771141cc406Sopenharmony_ci 4772141cc406Sopenharmony_ci if (strcmp (s->val[OPT_SOURCE].s, 4773141cc406Sopenharmony_ci "Automatic Document Feeder") == 0) 4774141cc406Sopenharmony_ci { 4775141cc406Sopenharmony_ci while (ptr != ptr_end) 4776141cc406Sopenharmony_ci { 4777141cc406Sopenharmony_ci (*ptr) = ~(*ptr); 4778141cc406Sopenharmony_ci ptr++; 4779141cc406Sopenharmony_ci /* need to revert bit direction */ 4780141cc406Sopenharmony_ci *ptr = ((*ptr & 0x80) >> 7) + ((*ptr & 0x40) >> 5) 4781141cc406Sopenharmony_ci + ((*ptr & 0x20) >> 3) + ((*ptr & 0x10) >> 1) 4782141cc406Sopenharmony_ci + ((*ptr & 0x08) << 1) + ((*ptr & 0x04) << 3) 4783141cc406Sopenharmony_ci + ((*ptr & 0x02) << 5) + ((*ptr & 0x01) << 7); 4784141cc406Sopenharmony_ci } 4785141cc406Sopenharmony_ci } 4786141cc406Sopenharmony_ci else 4787141cc406Sopenharmony_ci while (ptr != ptr_end) 4788141cc406Sopenharmony_ci { 4789141cc406Sopenharmony_ci (*ptr) = ~(*ptr); 4790141cc406Sopenharmony_ci ptr++; 4791141cc406Sopenharmony_ci } 4792141cc406Sopenharmony_ci } 4793141cc406Sopenharmony_ci if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) 4794141cc406Sopenharmony_ci { 4795141cc406Sopenharmony_ci /* need to revert line direction */ 4796141cc406Sopenharmony_ci SANE_Int line_number; 4797141cc406Sopenharmony_ci SANE_Int byte_number; 4798141cc406Sopenharmony_ci 4799141cc406Sopenharmony_ci DBG (5, "output_data: ADF found, mirroring lines\n"); 4800141cc406Sopenharmony_ci for (line_number = 0; line_number < lines_per_buffer; 4801141cc406Sopenharmony_ci line_number++) 4802141cc406Sopenharmony_ci { 4803141cc406Sopenharmony_ci for (byte_number = bpl - 1; byte_number >= 0; byte_number--) 4804141cc406Sopenharmony_ci { 4805141cc406Sopenharmony_ci fputc (*(data + line_number * bpl + byte_number), fp); 4806141cc406Sopenharmony_ci } 4807141cc406Sopenharmony_ci } 4808141cc406Sopenharmony_ci } 4809141cc406Sopenharmony_ci else 4810141cc406Sopenharmony_ci { 4811141cc406Sopenharmony_ci fwrite (data, lines_per_buffer, bpl, fp); 4812141cc406Sopenharmony_ci } 4813141cc406Sopenharmony_ci } 4814141cc406Sopenharmony_ci } 4815141cc406Sopenharmony_ci DBG (5, "output_data: end\n"); 4816141cc406Sopenharmony_ci} 4817141cc406Sopenharmony_ci 4818141cc406Sopenharmony_cistatic void 4819141cc406Sopenharmony_cisigterm_handler (int signal) 4820141cc406Sopenharmony_ci{ 4821141cc406Sopenharmony_ci DBG (4, 4822141cc406Sopenharmony_ci "sigterm_handler: started, signal is %d, starting sanei_scsi_req_flush_all()\n", 4823141cc406Sopenharmony_ci signal); 4824141cc406Sopenharmony_ci sanei_scsi_req_flush_all (); /* flush SCSI queue */ 4825141cc406Sopenharmony_ci DBG (4, 4826141cc406Sopenharmony_ci "sigterm_handler: sanei_scsi_req_flush_all() finisheshed, _exiting()\n"); 4827141cc406Sopenharmony_ci _exit (SANE_STATUS_GOOD); 4828141cc406Sopenharmony_ci} 4829141cc406Sopenharmony_ci 4830141cc406Sopenharmony_ci 4831141cc406Sopenharmony_cistatic SANE_Int 4832141cc406Sopenharmony_cireader_process (void *data) 4833141cc406Sopenharmony_ci{ 4834141cc406Sopenharmony_ci Mustek_Scanner *s = (Mustek_Scanner *) data; 4835141cc406Sopenharmony_ci SANE_Int lines_per_buffer, bpl; 4836141cc406Sopenharmony_ci SANE_Byte *extra = 0, *ptr; 4837141cc406Sopenharmony_ci sigset_t sigterm_set; 4838141cc406Sopenharmony_ci struct SIGACTION act; 4839141cc406Sopenharmony_ci SANE_Status status; 4840141cc406Sopenharmony_ci FILE *fp; 4841141cc406Sopenharmony_ci int fd = s->reader_fds; 4842141cc406Sopenharmony_ci SANE_Int buffernumber = 0; 4843141cc406Sopenharmony_ci SANE_Int buffer_count, max_buffers; 4844141cc406Sopenharmony_ci struct 4845141cc406Sopenharmony_ci { 4846141cc406Sopenharmony_ci void *id; /* scsi queue id */ 4847141cc406Sopenharmony_ci SANE_Byte *data; /* data buffer */ 4848141cc406Sopenharmony_ci SANE_Byte *command; /* command buffer */ 4849141cc406Sopenharmony_ci SANE_Int lines; /* # lines in buffer */ 4850141cc406Sopenharmony_ci size_t num_read; /* # of bytes read (return value) */ 4851141cc406Sopenharmony_ci SANE_Int bank; /* needed by SE models */ 4852141cc406Sopenharmony_ci SANE_Bool ready; /* ready to send to application? */ 4853141cc406Sopenharmony_ci SANE_Bool finished; /* block is finished */ 4854141cc406Sopenharmony_ci } 4855141cc406Sopenharmony_ci bstat[2]; 4856141cc406Sopenharmony_ci 4857141cc406Sopenharmony_ci DBG (3, "reader_process: started\n"); 4858141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 4859141cc406Sopenharmony_ci { 4860141cc406Sopenharmony_ci DBG (4, "reader_process: using fork ()\n"); 4861141cc406Sopenharmony_ci close (s->pipe); 4862141cc406Sopenharmony_ci s->pipe = -1; 4863141cc406Sopenharmony_ci } 4864141cc406Sopenharmony_ci else 4865141cc406Sopenharmony_ci { 4866141cc406Sopenharmony_ci DBG (4, "reader_process: using threads\n"); 4867141cc406Sopenharmony_ci } 4868141cc406Sopenharmony_ci 4869141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 4870141cc406Sopenharmony_ci { 4871141cc406Sopenharmony_ci /* ignore SIGTERM while writing SCSI commands */ 4872141cc406Sopenharmony_ci sigemptyset (&sigterm_set); 4873141cc406Sopenharmony_ci sigaddset (&sigterm_set, SIGTERM); 4874141cc406Sopenharmony_ci 4875141cc406Sopenharmony_ci /* call our sigterm handler to clean up ongoing SCSI requests */ 4876141cc406Sopenharmony_ci memset (&act, 0, sizeof (act)); 4877141cc406Sopenharmony_ci act.sa_handler = sigterm_handler; 4878141cc406Sopenharmony_ci sigaction (SIGTERM, &act, 0); 4879141cc406Sopenharmony_ci } 4880141cc406Sopenharmony_ci 4881141cc406Sopenharmony_ci if (disable_double_buffering) 4882141cc406Sopenharmony_ci DBG (3, "reader_process: disable_double_buffering is set, this may be " 4883141cc406Sopenharmony_ci "slow\n"); 4884141cc406Sopenharmony_ci 4885141cc406Sopenharmony_ci fp = fdopen (fd, "w"); 4886141cc406Sopenharmony_ci if (!fp) 4887141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4888141cc406Sopenharmony_ci 4889141cc406Sopenharmony_ci s->total_lines = 0; 4890141cc406Sopenharmony_ci bpl = s->hw->bpl; 4891141cc406Sopenharmony_ci 4892141cc406Sopenharmony_ci /* buffer size is scanner dependent */ 4893141cc406Sopenharmony_ci lines_per_buffer = s->hw->buffer_size / bpl / 2; 4894141cc406Sopenharmony_ci 4895141cc406Sopenharmony_ci if (strip_height > 0.0) 4896141cc406Sopenharmony_ci { 4897141cc406Sopenharmony_ci SANE_Int max_lines; 4898141cc406Sopenharmony_ci double dpi; 4899141cc406Sopenharmony_ci 4900141cc406Sopenharmony_ci dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 4901141cc406Sopenharmony_ci max_lines = (int) (strip_height * dpi + 0.5); 4902141cc406Sopenharmony_ci 4903141cc406Sopenharmony_ci if (lines_per_buffer > max_lines) 4904141cc406Sopenharmony_ci { 4905141cc406Sopenharmony_ci DBG (2, "reader_process: limiting strip height to %g inches " 4906141cc406Sopenharmony_ci "(%d lines)\n", strip_height, max_lines); 4907141cc406Sopenharmony_ci lines_per_buffer = max_lines; 4908141cc406Sopenharmony_ci } 4909141cc406Sopenharmony_ci } 4910141cc406Sopenharmony_ci 4911141cc406Sopenharmony_ci if (!lines_per_buffer) 4912141cc406Sopenharmony_ci { 4913141cc406Sopenharmony_ci DBG (1, "reader_process: bpl (%d) > SCSI buffer size / 2 (%d)\n", 4914141cc406Sopenharmony_ci bpl, s->hw->buffer_size / 2); 4915141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; /* resolution is too high */ 4916141cc406Sopenharmony_ci } 4917141cc406Sopenharmony_ci 4918141cc406Sopenharmony_ci DBG (4, "reader_process: %d lines per buffer, %d bytes per line, " 4919141cc406Sopenharmony_ci "%d bytes per buffer\n", lines_per_buffer, bpl, 4920141cc406Sopenharmony_ci lines_per_buffer * bpl); 4921141cc406Sopenharmony_ci 4922141cc406Sopenharmony_ci bstat[0].data = malloc (2 * lines_per_buffer * (long) bpl); 4923141cc406Sopenharmony_ci if (!bstat[0].data) 4924141cc406Sopenharmony_ci { 4925141cc406Sopenharmony_ci DBG (1, "reader_process: failed to malloc %ld bytes for data buffer\n", 4926141cc406Sopenharmony_ci lines_per_buffer * (long) bpl); 4927141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4928141cc406Sopenharmony_ci } 4929141cc406Sopenharmony_ci bstat[1].data = bstat[0].data + lines_per_buffer * (long) bpl; 4930141cc406Sopenharmony_ci 4931141cc406Sopenharmony_ci bstat[0].command = malloc (2 * 10); 4932141cc406Sopenharmony_ci if (!bstat[0].command) 4933141cc406Sopenharmony_ci { 4934141cc406Sopenharmony_ci DBG (1, 4935141cc406Sopenharmony_ci "reader_process: failed to malloc %d bytes for command buffer\n", 4936141cc406Sopenharmony_ci 2 * 10); 4937141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4938141cc406Sopenharmony_ci } 4939141cc406Sopenharmony_ci bstat[1].command = bstat[0].command + 10; 4940141cc406Sopenharmony_ci 4941141cc406Sopenharmony_ci /* Touch all pages of the buffer to fool the memory management. */ 4942141cc406Sopenharmony_ci ptr = bstat[0].data + 2 * lines_per_buffer * (long) bpl - 1; 4943141cc406Sopenharmony_ci while (ptr >= bstat[0].data) 4944141cc406Sopenharmony_ci { 4945141cc406Sopenharmony_ci *ptr = 0x00; 4946141cc406Sopenharmony_ci ptr -= 256; 4947141cc406Sopenharmony_ci } 4948141cc406Sopenharmony_ci 4949141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 4950141cc406Sopenharmony_ci { 4951141cc406Sopenharmony_ci /* get temporary buffer for line-distance correction and/or bit 4952141cc406Sopenharmony_ci expansion. For some scanners more space is needed because the 4953141cc406Sopenharmony_ci data must be read in as single big block (cut up into pieces 4954141cc406Sopenharmony_ci of lines_per_buffer). This requires that the line distance 4955141cc406Sopenharmony_ci correction continues on every call exactly where it stopped 4956141cc406Sopenharmony_ci if the image shall be reconstructed without any stripes. */ 4957141cc406Sopenharmony_ci 4958141cc406Sopenharmony_ci extra = malloc ((lines_per_buffer + MAX_LINE_DIST) 4959141cc406Sopenharmony_ci * (long) s->params.bytes_per_line); 4960141cc406Sopenharmony_ci if (!extra) 4961141cc406Sopenharmony_ci { 4962141cc406Sopenharmony_ci DBG (1, "reader_process: failed to malloc extra buffer\n"); 4963141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4964141cc406Sopenharmony_ci } 4965141cc406Sopenharmony_ci } 4966141cc406Sopenharmony_ci 4967141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_N) 4968141cc406Sopenharmony_ci { 4969141cc406Sopenharmony_ci /* reacquire port access rights (lost because of fork()): */ 4970141cc406Sopenharmony_ci sanei_ab306_get_io_privilege (s->fd); 4971141cc406Sopenharmony_ci } 4972141cc406Sopenharmony_ci 4973141cc406Sopenharmony_ci if ((s->hw->flags & MUSTEK_FLAG_N) || (s->hw->flags & MUSTEK_FLAG_LD_BLOCK)) 4974141cc406Sopenharmony_ci { 4975141cc406Sopenharmony_ci /* reset counter of line number for line-dictance correction */ 4976141cc406Sopenharmony_ci s->ld.ld_line = 0; 4977141cc406Sopenharmony_ci } 4978141cc406Sopenharmony_ci 4979141cc406Sopenharmony_ci max_buffers = s->hw->max_block_buffer_size / (lines_per_buffer * bpl); 4980141cc406Sopenharmony_ci if (max_buffers < 1) 4981141cc406Sopenharmony_ci { 4982141cc406Sopenharmony_ci DBG (1, "reader_process: buffersize > blocksize!\n"); 4983141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4984141cc406Sopenharmony_ci } 4985141cc406Sopenharmony_ci DBG (4, "reader_process: limiting block read to %d buffers (%d lines)\n", 4986141cc406Sopenharmony_ci max_buffers, MIN (s->hw->lines, (max_buffers * lines_per_buffer))); 4987141cc406Sopenharmony_ci 4988141cc406Sopenharmony_ci while (s->line < s->hw->lines) 4989141cc406Sopenharmony_ci { 4990141cc406Sopenharmony_ci s->hw->lines_per_block = 4991141cc406Sopenharmony_ci MIN (s->hw->lines - s->line, (max_buffers * lines_per_buffer)); 4992141cc406Sopenharmony_ci status = dev_block_read_start (s, s->hw->lines_per_block); 4993141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 4994141cc406Sopenharmony_ci return status; 4995141cc406Sopenharmony_ci 4996141cc406Sopenharmony_ci for (buffernumber = 0; buffernumber < 2; buffernumber++) 4997141cc406Sopenharmony_ci { 4998141cc406Sopenharmony_ci bstat[buffernumber].ready = SANE_FALSE; 4999141cc406Sopenharmony_ci bstat[buffernumber].finished = SANE_FALSE; 5000141cc406Sopenharmony_ci } 5001141cc406Sopenharmony_ci buffer_count = 0; 5002141cc406Sopenharmony_ci buffernumber = 0; 5003141cc406Sopenharmony_ci 5004141cc406Sopenharmony_ci while (1) 5005141cc406Sopenharmony_ci { 5006141cc406Sopenharmony_ci /* omit reading first two buffers (not yet ready) */ 5007141cc406Sopenharmony_ci if (bstat[buffernumber].ready == SANE_TRUE) 5008141cc406Sopenharmony_ci { 5009141cc406Sopenharmony_ci DBG (4, "reader_process: buffer %d: waiting for request to be " 5010141cc406Sopenharmony_ci "ready\n", buffernumber + 1); 5011141cc406Sopenharmony_ci status = dev_req_wait (bstat[buffernumber].id); 5012141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 5013141cc406Sopenharmony_ci { 5014141cc406Sopenharmony_ci DBG (4, "reader_process: buffer %d is ready, wanted %d, " 5015141cc406Sopenharmony_ci "got %ld bytes\n", buffernumber + 1, 5016141cc406Sopenharmony_ci bstat[buffernumber].lines * bpl, 5017141cc406Sopenharmony_ci (long int) bstat[buffernumber].num_read); 5018141cc406Sopenharmony_ci } 5019141cc406Sopenharmony_ci else 5020141cc406Sopenharmony_ci { 5021141cc406Sopenharmony_ci DBG (1, "reader_process: failed to read data, status: %s, " 5022141cc406Sopenharmony_ci "buffer: %d\n", sane_strstatus (status), 5023141cc406Sopenharmony_ci buffernumber + 1); 5024141cc406Sopenharmony_ci if (status == SANE_STATUS_NO_MEM) 5025141cc406Sopenharmony_ci { 5026141cc406Sopenharmony_ci DBG (1, 5027141cc406Sopenharmony_ci "Probably the size of the kernel SCSI buffer is " 5028141cc406Sopenharmony_ci "too small for the\n selected buffersize " 5029141cc406Sopenharmony_ci "in mustek.conf. Either decrease " 5030141cc406Sopenharmony_ci "buffersize in\n mustek.conf to e.g. 32, " 5031141cc406Sopenharmony_ci "increase SG_BIG_BUF in kernel to 130560, " 5032141cc406Sopenharmony_ci "or\n use SANE_SG_BUFFERSIZE variable. " 5033141cc406Sopenharmony_ci "See man sane-scsi and README for\n " 5034141cc406Sopenharmony_ci "details.\n"); 5035141cc406Sopenharmony_ci } 5036141cc406Sopenharmony_ci return status; 5037141cc406Sopenharmony_ci } 5038141cc406Sopenharmony_ci 5039141cc406Sopenharmony_ci DBG (4, "reader_process: buffer %d: sending %ld bytes to " 5040141cc406Sopenharmony_ci "output_data\n", buffernumber + 1, 5041141cc406Sopenharmony_ci (long int) bstat[buffernumber].num_read); 5042141cc406Sopenharmony_ci output_data (s, fp, bstat[buffernumber].data, 5043141cc406Sopenharmony_ci bstat[buffernumber].lines, bpl, extra); 5044141cc406Sopenharmony_ci if (bstat[buffernumber].finished) 5045141cc406Sopenharmony_ci break; /* everything written; exit loop */ 5046141cc406Sopenharmony_ci } 5047141cc406Sopenharmony_ci if (disable_double_buffering) 5048141cc406Sopenharmony_ci { 5049141cc406Sopenharmony_ci /* Enter only one buffer at once */ 5050141cc406Sopenharmony_ci if (buffernumber == 1) 5051141cc406Sopenharmony_ci buffernumber = 0; 5052141cc406Sopenharmony_ci else 5053141cc406Sopenharmony_ci buffernumber = 1; 5054141cc406Sopenharmony_ci } 5055141cc406Sopenharmony_ci 5056141cc406Sopenharmony_ci /* enter read requests only if data left */ 5057141cc406Sopenharmony_ci if ((s->line < s->hw->lines) && (buffer_count < max_buffers)) 5058141cc406Sopenharmony_ci { 5059141cc406Sopenharmony_ci if (s->line + lines_per_buffer >= s->hw->lines) 5060141cc406Sopenharmony_ci { 5061141cc406Sopenharmony_ci /* do the last few lines: */ 5062141cc406Sopenharmony_ci bstat[buffernumber].lines = s->hw->lines - s->line; 5063141cc406Sopenharmony_ci bstat[buffernumber].bank = 0x01; 5064141cc406Sopenharmony_ci bstat[buffernumber].finished = SANE_TRUE; 5065141cc406Sopenharmony_ci } 5066141cc406Sopenharmony_ci else 5067141cc406Sopenharmony_ci { 5068141cc406Sopenharmony_ci bstat[buffernumber].lines = lines_per_buffer; 5069141cc406Sopenharmony_ci bstat[buffernumber].bank = 0x00; 5070141cc406Sopenharmony_ci } 5071141cc406Sopenharmony_ci 5072141cc406Sopenharmony_ci if ((buffer_count + 1) >= max_buffers) 5073141cc406Sopenharmony_ci bstat[buffernumber].finished = SANE_TRUE; 5074141cc406Sopenharmony_ci 5075141cc406Sopenharmony_ci s->line += bstat[buffernumber].lines; 5076141cc406Sopenharmony_ci bstat[buffernumber].ready = SANE_TRUE; 5077141cc406Sopenharmony_ci 5078141cc406Sopenharmony_ci buffer_count++; 5079141cc406Sopenharmony_ci 5080141cc406Sopenharmony_ci DBG (4, 5081141cc406Sopenharmony_ci "reader_process: buffer %d: entering read request for %d " 5082141cc406Sopenharmony_ci "bytes (buffer %d)\n", buffernumber + 1, 5083141cc406Sopenharmony_ci bstat[buffernumber].lines * bpl, buffer_count); 5084141cc406Sopenharmony_ci sigprocmask (SIG_BLOCK, &sigterm_set, 0); 5085141cc406Sopenharmony_ci status = dev_read_req_enter (s, bstat[buffernumber].data, 5086141cc406Sopenharmony_ci bstat[buffernumber].lines, bpl, 5087141cc406Sopenharmony_ci &bstat[buffernumber].num_read, 5088141cc406Sopenharmony_ci &bstat[buffernumber].id, 5089141cc406Sopenharmony_ci bstat[buffernumber].bank, 5090141cc406Sopenharmony_ci bstat[buffernumber].command); 5091141cc406Sopenharmony_ci sigprocmask (SIG_UNBLOCK, &sigterm_set, 0); 5092141cc406Sopenharmony_ci 5093141cc406Sopenharmony_ci 5094141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 5095141cc406Sopenharmony_ci { 5096141cc406Sopenharmony_ci DBG (5, "reader_process: buffer %d: entered (line %d of %d," 5097141cc406Sopenharmony_ci " buffer %d)\n", buffernumber + 1, s->line, 5098141cc406Sopenharmony_ci s->hw->lines, buffer_count); 5099141cc406Sopenharmony_ci } 5100141cc406Sopenharmony_ci else 5101141cc406Sopenharmony_ci { 5102141cc406Sopenharmony_ci DBG (1, "reader_process: buffer %d: failed to enter read " 5103141cc406Sopenharmony_ci "request, status: %s\n", buffernumber + 1, 5104141cc406Sopenharmony_ci sane_strstatus (status)); 5105141cc406Sopenharmony_ci return status; 5106141cc406Sopenharmony_ci } 5107141cc406Sopenharmony_ci } 5108141cc406Sopenharmony_ci if (!disable_double_buffering) 5109141cc406Sopenharmony_ci { 5110141cc406Sopenharmony_ci if (buffernumber == 1) 5111141cc406Sopenharmony_ci buffernumber = 0; 5112141cc406Sopenharmony_ci else 5113141cc406Sopenharmony_ci buffernumber = 1; 5114141cc406Sopenharmony_ci } 5115141cc406Sopenharmony_ci /* This is said to fix the scanner hangs that reportedly show on 5116141cc406Sopenharmony_ci some MFS-12000SP scanners. */ 5117141cc406Sopenharmony_ci if (s->mode == 0 && (s->hw->flags & MUSTEK_FLAG_LINEART_FIX)) 5118141cc406Sopenharmony_ci usleep (200000); 5119141cc406Sopenharmony_ci } 5120141cc406Sopenharmony_ci } 5121141cc406Sopenharmony_ci 5122141cc406Sopenharmony_ci fclose (fp); 5123141cc406Sopenharmony_ci free (bstat[0].data); 5124141cc406Sopenharmony_ci if (s->ld.buf[0]) 5125141cc406Sopenharmony_ci free (s->ld.buf[0]); 5126141cc406Sopenharmony_ci s->ld.buf[0] = NULL; 5127141cc406Sopenharmony_ci if (extra) 5128141cc406Sopenharmony_ci free (extra); 5129141cc406Sopenharmony_ci close (fd); 5130141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5131141cc406Sopenharmony_ci} 5132141cc406Sopenharmony_ci 5133141cc406Sopenharmony_cistatic SANE_Status 5134141cc406Sopenharmony_ciattach_one_device (SANE_String_Const devname) 5135141cc406Sopenharmony_ci{ 5136141cc406Sopenharmony_ci Mustek_Device *dev; 5137141cc406Sopenharmony_ci 5138141cc406Sopenharmony_ci attach (devname, &dev, SANE_FALSE); 5139141cc406Sopenharmony_ci if (dev) 5140141cc406Sopenharmony_ci { 5141141cc406Sopenharmony_ci /* Keep track of newly attached devices so we can set options as 5142141cc406Sopenharmony_ci necessary. */ 5143141cc406Sopenharmony_ci if (new_dev_len >= new_dev_alloced) 5144141cc406Sopenharmony_ci { 5145141cc406Sopenharmony_ci new_dev_alloced += 4; 5146141cc406Sopenharmony_ci if (new_dev) 5147141cc406Sopenharmony_ci new_dev = 5148141cc406Sopenharmony_ci realloc (new_dev, new_dev_alloced * sizeof (new_dev[0])); 5149141cc406Sopenharmony_ci else 5150141cc406Sopenharmony_ci new_dev = malloc (new_dev_alloced * sizeof (new_dev[0])); 5151141cc406Sopenharmony_ci if (!new_dev) 5152141cc406Sopenharmony_ci { 5153141cc406Sopenharmony_ci DBG (1, "attach_one_device: out of memory\n"); 5154141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5155141cc406Sopenharmony_ci } 5156141cc406Sopenharmony_ci } 5157141cc406Sopenharmony_ci new_dev[new_dev_len++] = dev; 5158141cc406Sopenharmony_ci } 5159141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5160141cc406Sopenharmony_ci} 5161141cc406Sopenharmony_ci 5162141cc406Sopenharmony_ci/**************************************************************************/ 5163141cc406Sopenharmony_ci/* SANE API calls */ 5164141cc406Sopenharmony_ci/**************************************************************************/ 5165141cc406Sopenharmony_ci 5166141cc406Sopenharmony_ciSANE_Status 5167141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 5168141cc406Sopenharmony_ci{ 5169141cc406Sopenharmony_ci SANE_Char line[PATH_MAX], *word, *end; 5170141cc406Sopenharmony_ci SANE_String_Const cp; 5171141cc406Sopenharmony_ci SANE_Int linenumber; 5172141cc406Sopenharmony_ci FILE *fp; 5173141cc406Sopenharmony_ci 5174141cc406Sopenharmony_ci DBG_INIT (); 5175141cc406Sopenharmony_ci 5176141cc406Sopenharmony_ci sanei_thread_init (); 5177141cc406Sopenharmony_ci 5178141cc406Sopenharmony_ci#ifdef DBG_LEVEL 5179141cc406Sopenharmony_ci debug_level = DBG_LEVEL; 5180141cc406Sopenharmony_ci#else 5181141cc406Sopenharmony_ci debug_level = 0; 5182141cc406Sopenharmony_ci#endif 5183141cc406Sopenharmony_ci 5184141cc406Sopenharmony_ci DBG (2, "SANE mustek backend version %d.%d build %d from %s\n", SANE_CURRENT_MAJOR, 5185141cc406Sopenharmony_ci SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING); 5186141cc406Sopenharmony_ci 5187141cc406Sopenharmony_ci if (version_code) 5188141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 5189141cc406Sopenharmony_ci 5190141cc406Sopenharmony_ci DBG (5, "sane_init: authorize %s null\n", authorize ? "!=" : "=="); 5191141cc406Sopenharmony_ci 5192141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED 5193141cc406Sopenharmony_ci DBG (5, "sane_init: using sanei_scsi_open_extended\n"); 5194141cc406Sopenharmony_ci#else 5195141cc406Sopenharmony_ci DBG (5, "sane_init: using sanei_scsi_open with buffer size = %d bytes\n", 5196141cc406Sopenharmony_ci sanei_scsi_max_request_size); 5197141cc406Sopenharmony_ci#endif 5198141cc406Sopenharmony_ci 5199141cc406Sopenharmony_ci num_devices = 0; 5200141cc406Sopenharmony_ci force_wait = SANE_FALSE; 5201141cc406Sopenharmony_ci disable_double_buffering = SANE_FALSE; 5202141cc406Sopenharmony_ci first_dev = 0; 5203141cc406Sopenharmony_ci first_handle = 0; 5204141cc406Sopenharmony_ci devlist = 0; 5205141cc406Sopenharmony_ci new_dev = 0; 5206141cc406Sopenharmony_ci new_dev_len = 0; 5207141cc406Sopenharmony_ci new_dev_alloced = 0; 5208141cc406Sopenharmony_ci 5209141cc406Sopenharmony_ci fp = sanei_config_open (MUSTEK_CONFIG_FILE); 5210141cc406Sopenharmony_ci if (!fp) 5211141cc406Sopenharmony_ci { 5212141cc406Sopenharmony_ci /* default to /dev/scanner instead of insisting on config file */ 5213141cc406Sopenharmony_ci DBG (3, "sane_init: couldn't find config file (%s), trying " 5214141cc406Sopenharmony_ci "/dev/scanner directly\n", MUSTEK_CONFIG_FILE); 5215141cc406Sopenharmony_ci attach ("/dev/scanner", 0, SANE_FALSE); 5216141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5217141cc406Sopenharmony_ci } 5218141cc406Sopenharmony_ci linenumber = 0; 5219141cc406Sopenharmony_ci DBG (4, "sane_init: reading config file `%s'\n", MUSTEK_CONFIG_FILE); 5220141cc406Sopenharmony_ci while (sanei_config_read (line, sizeof (line), fp)) 5221141cc406Sopenharmony_ci { 5222141cc406Sopenharmony_ci word = 0; 5223141cc406Sopenharmony_ci linenumber++; 5224141cc406Sopenharmony_ci 5225141cc406Sopenharmony_ci cp = sanei_config_get_string (line, &word); 5226141cc406Sopenharmony_ci if (!word || cp == line) 5227141cc406Sopenharmony_ci { 5228141cc406Sopenharmony_ci DBG (5, "sane_init: config file line %d: ignoring empty line\n", 5229141cc406Sopenharmony_ci linenumber); 5230141cc406Sopenharmony_ci if (word) 5231141cc406Sopenharmony_ci free (word); 5232141cc406Sopenharmony_ci continue; 5233141cc406Sopenharmony_ci } 5234141cc406Sopenharmony_ci if (word[0] == '#') 5235141cc406Sopenharmony_ci { 5236141cc406Sopenharmony_ci DBG (5, "sane_init: config file line %d: ignoring comment line\n", 5237141cc406Sopenharmony_ci linenumber); 5238141cc406Sopenharmony_ci free (word); 5239141cc406Sopenharmony_ci continue; 5240141cc406Sopenharmony_ci } 5241141cc406Sopenharmony_ci 5242141cc406Sopenharmony_ci if (strcmp (word, "option") == 0) 5243141cc406Sopenharmony_ci { 5244141cc406Sopenharmony_ci free (word); 5245141cc406Sopenharmony_ci word = 0; 5246141cc406Sopenharmony_ci cp = sanei_config_get_string (cp, &word); 5247141cc406Sopenharmony_ci if (!word) 5248141cc406Sopenharmony_ci { 5249141cc406Sopenharmony_ci DBG (1, 5250141cc406Sopenharmony_ci "sane_init: config file line %d: missing quotation mark?\n", 5251141cc406Sopenharmony_ci linenumber); 5252141cc406Sopenharmony_ci continue; 5253141cc406Sopenharmony_ci } 5254141cc406Sopenharmony_ci 5255141cc406Sopenharmony_ci if (strcmp (word, "strip-height") == 0) 5256141cc406Sopenharmony_ci { 5257141cc406Sopenharmony_ci free (word); 5258141cc406Sopenharmony_ci word = 0; 5259141cc406Sopenharmony_ci cp = sanei_config_get_string (cp, &word); 5260141cc406Sopenharmony_ci if (!word) 5261141cc406Sopenharmony_ci { 5262141cc406Sopenharmony_ci DBG (1, 5263141cc406Sopenharmony_ci "sane_init: config file line %d: missing quotation mark?\n", 5264141cc406Sopenharmony_ci linenumber); 5265141cc406Sopenharmony_ci continue; 5266141cc406Sopenharmony_ci } 5267141cc406Sopenharmony_ci 5268141cc406Sopenharmony_ci errno = 0; 5269141cc406Sopenharmony_ci strip_height = strtod (word, &end); 5270141cc406Sopenharmony_ci if (end == word) 5271141cc406Sopenharmony_ci { 5272141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d: strip-height " 5273141cc406Sopenharmony_ci "must have a parameter; using 1 inch\n", linenumber); 5274141cc406Sopenharmony_ci strip_height = 1.0; 5275141cc406Sopenharmony_ci } 5276141cc406Sopenharmony_ci if (errno) 5277141cc406Sopenharmony_ci { 5278141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d: strip-height `%s' " 5279141cc406Sopenharmony_ci "is invalid (%s); using 1 inch\n", linenumber, 5280141cc406Sopenharmony_ci word, strerror (errno)); 5281141cc406Sopenharmony_ci strip_height = 1.0; 5282141cc406Sopenharmony_ci } 5283141cc406Sopenharmony_ci else 5284141cc406Sopenharmony_ci { 5285141cc406Sopenharmony_ci if (strip_height < 0.1) 5286141cc406Sopenharmony_ci strip_height = 0.1; 5287141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: strip-height set " 5288141cc406Sopenharmony_ci "to %g inches\n", linenumber, strip_height); 5289141cc406Sopenharmony_ci } 5290141cc406Sopenharmony_ci if (word) 5291141cc406Sopenharmony_ci free (word); 5292141cc406Sopenharmony_ci word = 0; 5293141cc406Sopenharmony_ci } 5294141cc406Sopenharmony_ci else if (strcmp (word, "force-wait") == 0) 5295141cc406Sopenharmony_ci { 5296141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: enabling force-wait\n", 5297141cc406Sopenharmony_ci linenumber); 5298141cc406Sopenharmony_ci force_wait = SANE_TRUE; 5299141cc406Sopenharmony_ci if (word) 5300141cc406Sopenharmony_ci free (word); 5301141cc406Sopenharmony_ci word = 0; 5302141cc406Sopenharmony_ci } 5303141cc406Sopenharmony_ci else if (strcmp (word, "disable-double-buffering") == 0) 5304141cc406Sopenharmony_ci { 5305141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: disabling " 5306141cc406Sopenharmony_ci "double-buffering\n", linenumber); 5307141cc406Sopenharmony_ci disable_double_buffering = SANE_TRUE; 5308141cc406Sopenharmony_ci if (word) 5309141cc406Sopenharmony_ci free (word); 5310141cc406Sopenharmony_ci word = 0; 5311141cc406Sopenharmony_ci } 5312141cc406Sopenharmony_ci else if (strcmp (word, "legal-size") == 0) 5313141cc406Sopenharmony_ci { 5314141cc406Sopenharmony_ci if (new_dev_len > 0) 5315141cc406Sopenharmony_ci { 5316141cc406Sopenharmony_ci /* Check for 12000 LS, no way to find out automatically */ 5317141cc406Sopenharmony_ci if (strcmp (new_dev[new_dev_len - 1]->sane.model, 5318141cc406Sopenharmony_ci "ScanExpress 12000SP") == 0) 5319141cc406Sopenharmony_ci { 5320141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->x_range.max = 5321141cc406Sopenharmony_ci SANE_FIX (220.0); 5322141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->y_range.max = 5323141cc406Sopenharmony_ci SANE_FIX (360.0); 5324141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.model = 5325141cc406Sopenharmony_ci "Paragon 1200 LS"; 5326141cc406Sopenharmony_ci DBG (3, 5327141cc406Sopenharmony_ci "sane_init: config file line %d: enabling " 5328141cc406Sopenharmony_ci "legal-size for %s\n", linenumber, 5329141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5330141cc406Sopenharmony_ci } 5331141cc406Sopenharmony_ci else 5332141cc406Sopenharmony_ci { 5333141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5334141cc406Sopenharmony_ci "legal-size ignored, device %s is not a " 5335141cc406Sopenharmony_ci "Paragon 1200 LS\n", linenumber, 5336141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5337141cc406Sopenharmony_ci } 5338141cc406Sopenharmony_ci 5339141cc406Sopenharmony_ci } 5340141cc406Sopenharmony_ci else 5341141cc406Sopenharmony_ci { 5342141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5343141cc406Sopenharmony_ci "legal-size ignored, was set before any device " 5344141cc406Sopenharmony_ci "name\n", linenumber); 5345141cc406Sopenharmony_ci } 5346141cc406Sopenharmony_ci if (word) 5347141cc406Sopenharmony_ci free (word); 5348141cc406Sopenharmony_ci word = 0; 5349141cc406Sopenharmony_ci } 5350141cc406Sopenharmony_ci else if (strcmp (word, "linedistance-fix") == 0) 5351141cc406Sopenharmony_ci { 5352141cc406Sopenharmony_ci if (new_dev_len > 0) 5353141cc406Sopenharmony_ci { 5354141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_LD_FIX; 5355141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: enabling " 5356141cc406Sopenharmony_ci "linedistance-fix for %s\n", linenumber, 5357141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5358141cc406Sopenharmony_ci } 5359141cc406Sopenharmony_ci else 5360141cc406Sopenharmony_ci { 5361141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5362141cc406Sopenharmony_ci "linedistance-fix ignored, was set before any device " 5363141cc406Sopenharmony_ci "name\n", linenumber); 5364141cc406Sopenharmony_ci } 5365141cc406Sopenharmony_ci if (word) 5366141cc406Sopenharmony_ci free (word); 5367141cc406Sopenharmony_ci word = 0; 5368141cc406Sopenharmony_ci } 5369141cc406Sopenharmony_ci else if (strcmp (word, "disable-backtracking") == 0) 5370141cc406Sopenharmony_ci { 5371141cc406Sopenharmony_ci if (new_dev_len > 0) 5372141cc406Sopenharmony_ci { 5373141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_NO_BACKTRACK; 5374141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: disabling " 5375141cc406Sopenharmony_ci "backtracking for %s\n", linenumber, 5376141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5377141cc406Sopenharmony_ci } 5378141cc406Sopenharmony_ci else 5379141cc406Sopenharmony_ci { 5380141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5381141cc406Sopenharmony_ci "disable-backtracking ignored, was set before any " 5382141cc406Sopenharmony_ci "device name\n", linenumber); 5383141cc406Sopenharmony_ci } 5384141cc406Sopenharmony_ci if (word) 5385141cc406Sopenharmony_ci free (word); 5386141cc406Sopenharmony_ci word = 0; 5387141cc406Sopenharmony_ci } 5388141cc406Sopenharmony_ci else if (strcmp (word, "lineart-fix") == 0) 5389141cc406Sopenharmony_ci { 5390141cc406Sopenharmony_ci if (new_dev_len > 0) 5391141cc406Sopenharmony_ci { 5392141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_LINEART_FIX; 5393141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: enabling " 5394141cc406Sopenharmony_ci "lineart-fix for %s\n", linenumber, 5395141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5396141cc406Sopenharmony_ci } 5397141cc406Sopenharmony_ci else 5398141cc406Sopenharmony_ci { 5399141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5400141cc406Sopenharmony_ci "lineart-fix ignored, was set before any device name\n", 5401141cc406Sopenharmony_ci linenumber); 5402141cc406Sopenharmony_ci } 5403141cc406Sopenharmony_ci if (word) 5404141cc406Sopenharmony_ci free (word); 5405141cc406Sopenharmony_ci word = 0; 5406141cc406Sopenharmony_ci } 5407141cc406Sopenharmony_ci else if (strcmp (word, "buffersize") == 0) 5408141cc406Sopenharmony_ci { 5409141cc406Sopenharmony_ci long buffer_size; 5410141cc406Sopenharmony_ci 5411141cc406Sopenharmony_ci free (word); 5412141cc406Sopenharmony_ci word = 0; 5413141cc406Sopenharmony_ci cp = sanei_config_get_string (cp, &word); 5414141cc406Sopenharmony_ci if (!word) 5415141cc406Sopenharmony_ci { 5416141cc406Sopenharmony_ci DBG (1, 5417141cc406Sopenharmony_ci "sane_init: config file line %d: missing quotation mark?\n", 5418141cc406Sopenharmony_ci linenumber); 5419141cc406Sopenharmony_ci continue; 5420141cc406Sopenharmony_ci } 5421141cc406Sopenharmony_ci 5422141cc406Sopenharmony_ci errno = 0; 5423141cc406Sopenharmony_ci buffer_size = strtol (word, &end, 0); 5424141cc406Sopenharmony_ci 5425141cc406Sopenharmony_ci if (end == word) 5426141cc406Sopenharmony_ci { 5427141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d: buffersize must " 5428141cc406Sopenharmony_ci "have a parameter; using default (%d kb)\n", 5429141cc406Sopenharmony_ci linenumber, new_dev[new_dev_len - 1]->max_buffer_size); 5430141cc406Sopenharmony_ci } 5431141cc406Sopenharmony_ci if (errno) 5432141cc406Sopenharmony_ci { 5433141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d: buffersize `%s' " 5434141cc406Sopenharmony_ci "is invalid (%s); using default (%d kb)\n", linenumber, 5435141cc406Sopenharmony_ci word, strerror (errno), 5436141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->max_buffer_size); 5437141cc406Sopenharmony_ci } 5438141cc406Sopenharmony_ci else 5439141cc406Sopenharmony_ci { 5440141cc406Sopenharmony_ci if (new_dev_len > 0) 5441141cc406Sopenharmony_ci { 5442141cc406Sopenharmony_ci if (buffer_size < 32.0) 5443141cc406Sopenharmony_ci buffer_size = 32.0; 5444141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->max_buffer_size = 5445141cc406Sopenharmony_ci buffer_size * 1024; 5446141cc406Sopenharmony_ci DBG (3, 5447141cc406Sopenharmony_ci "sane_init: config file line %d: buffersize set " 5448141cc406Sopenharmony_ci "to %ld kb for %s\n", linenumber, buffer_size, 5449141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5450141cc406Sopenharmony_ci } 5451141cc406Sopenharmony_ci else 5452141cc406Sopenharmony_ci { 5453141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5454141cc406Sopenharmony_ci "buffersize ignored, was set before any device " 5455141cc406Sopenharmony_ci "name\n", linenumber); 5456141cc406Sopenharmony_ci } 5457141cc406Sopenharmony_ci } 5458141cc406Sopenharmony_ci if (word) 5459141cc406Sopenharmony_ci free (word); 5460141cc406Sopenharmony_ci word = 0; 5461141cc406Sopenharmony_ci } 5462141cc406Sopenharmony_ci else if (strcmp (word, "blocksize") == 0) 5463141cc406Sopenharmony_ci { 5464141cc406Sopenharmony_ci long block_size; 5465141cc406Sopenharmony_ci 5466141cc406Sopenharmony_ci free (word); 5467141cc406Sopenharmony_ci word = 0; 5468141cc406Sopenharmony_ci cp = sanei_config_get_string (cp, &word); 5469141cc406Sopenharmony_ci if (!word) 5470141cc406Sopenharmony_ci { 5471141cc406Sopenharmony_ci DBG (1, 5472141cc406Sopenharmony_ci "sane_init: config file line %d: missing quotation mark?\n", 5473141cc406Sopenharmony_ci linenumber); 5474141cc406Sopenharmony_ci continue; 5475141cc406Sopenharmony_ci } 5476141cc406Sopenharmony_ci 5477141cc406Sopenharmony_ci errno = 0; 5478141cc406Sopenharmony_ci block_size = strtol (word, &end, 0); 5479141cc406Sopenharmony_ci 5480141cc406Sopenharmony_ci if (end == word) 5481141cc406Sopenharmony_ci { 5482141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d:: blocksize must " 5483141cc406Sopenharmony_ci "have a parameter; using default (1 GB)\n", 5484141cc406Sopenharmony_ci linenumber); 5485141cc406Sopenharmony_ci } 5486141cc406Sopenharmony_ci if (errno) 5487141cc406Sopenharmony_ci { 5488141cc406Sopenharmony_ci DBG (3, "sane-init: config file line %d: blocksize `%s' " 5489141cc406Sopenharmony_ci "is invalid (%s); using default (1 GB)\n", linenumber, 5490141cc406Sopenharmony_ci word, strerror (errno)); 5491141cc406Sopenharmony_ci } 5492141cc406Sopenharmony_ci else 5493141cc406Sopenharmony_ci { 5494141cc406Sopenharmony_ci if (new_dev_len > 0) 5495141cc406Sopenharmony_ci { 5496141cc406Sopenharmony_ci if (block_size < 256.0) 5497141cc406Sopenharmony_ci block_size = 256.0; 5498141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->max_block_buffer_size = 5499141cc406Sopenharmony_ci block_size * 1024; 5500141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: blocksize set " 5501141cc406Sopenharmony_ci "to %ld kb for %s\n", linenumber, block_size, 5502141cc406Sopenharmony_ci new_dev[new_dev_len - 1]->sane.name); 5503141cc406Sopenharmony_ci } 5504141cc406Sopenharmony_ci else 5505141cc406Sopenharmony_ci { 5506141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: option " 5507141cc406Sopenharmony_ci "blocksize ignored, was set before any device " 5508141cc406Sopenharmony_ci "name\n", linenumber); 5509141cc406Sopenharmony_ci } 5510141cc406Sopenharmony_ci } 5511141cc406Sopenharmony_ci if (word) 5512141cc406Sopenharmony_ci free (word); 5513141cc406Sopenharmony_ci word = 0; 5514141cc406Sopenharmony_ci } 5515141cc406Sopenharmony_ci else 5516141cc406Sopenharmony_ci { 5517141cc406Sopenharmony_ci DBG (3, "sane_init: config file line %d: ignoring unknown " 5518141cc406Sopenharmony_ci "option `%s'\n", linenumber, word); 5519141cc406Sopenharmony_ci if (word) 5520141cc406Sopenharmony_ci free (word); 5521141cc406Sopenharmony_ci word = 0; 5522141cc406Sopenharmony_ci } 5523141cc406Sopenharmony_ci } 5524141cc406Sopenharmony_ci else 5525141cc406Sopenharmony_ci { 5526141cc406Sopenharmony_ci new_dev_len = 0; 5527141cc406Sopenharmony_ci DBG (4, "sane_init: config file line %d: trying to attach `%s'\n", 5528141cc406Sopenharmony_ci linenumber, line); 5529141cc406Sopenharmony_ci sanei_config_attach_matching_devices (line, attach_one_device); 5530141cc406Sopenharmony_ci if (word) 5531141cc406Sopenharmony_ci free (word); 5532141cc406Sopenharmony_ci word = 0; 5533141cc406Sopenharmony_ci } 5534141cc406Sopenharmony_ci } 5535141cc406Sopenharmony_ci 5536141cc406Sopenharmony_ci if (new_dev_alloced > 0) 5537141cc406Sopenharmony_ci { 5538141cc406Sopenharmony_ci new_dev_len = new_dev_alloced = 0; 5539141cc406Sopenharmony_ci free (new_dev); 5540141cc406Sopenharmony_ci } 5541141cc406Sopenharmony_ci fclose (fp); 5542141cc406Sopenharmony_ci DBG (5, "sane_init: end\n"); 5543141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5544141cc406Sopenharmony_ci} 5545141cc406Sopenharmony_ci 5546141cc406Sopenharmony_civoid 5547141cc406Sopenharmony_cisane_exit (void) 5548141cc406Sopenharmony_ci{ 5549141cc406Sopenharmony_ci Mustek_Device *dev, *next; 5550141cc406Sopenharmony_ci 5551141cc406Sopenharmony_ci DBG (4, "sane_exit\n"); 5552141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 5553141cc406Sopenharmony_ci { 5554141cc406Sopenharmony_ci next = dev->next; 5555141cc406Sopenharmony_ci free (dev->name); 5556141cc406Sopenharmony_ci free (dev); 5557141cc406Sopenharmony_ci } 5558141cc406Sopenharmony_ci if (devlist) 5559141cc406Sopenharmony_ci free (devlist); 5560141cc406Sopenharmony_ci devlist = 0; 5561141cc406Sopenharmony_ci first_dev = 0; 5562141cc406Sopenharmony_ci sanei_ab306_exit (); /* may have to do some cleanup */ 5563141cc406Sopenharmony_ci mustek_scsi_pp_exit (); 5564141cc406Sopenharmony_ci DBG (5, "sane_exit: finished\n"); 5565141cc406Sopenharmony_ci} 5566141cc406Sopenharmony_ci 5567141cc406Sopenharmony_ciSANE_Status 5568141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 5569141cc406Sopenharmony_ci{ 5570141cc406Sopenharmony_ci Mustek_Device *dev; 5571141cc406Sopenharmony_ci SANE_Int i; 5572141cc406Sopenharmony_ci 5573141cc406Sopenharmony_ci DBG (4, "sane_get_devices: %d devices %s\n", num_devices, 5574141cc406Sopenharmony_ci local_only ? "(local only)" : ""); 5575141cc406Sopenharmony_ci if (devlist) 5576141cc406Sopenharmony_ci free (devlist); 5577141cc406Sopenharmony_ci 5578141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 5579141cc406Sopenharmony_ci if (!devlist) 5580141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5581141cc406Sopenharmony_ci 5582141cc406Sopenharmony_ci i = 0; 5583141cc406Sopenharmony_ci for (dev = first_dev; i < num_devices; dev = dev->next) 5584141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 5585141cc406Sopenharmony_ci devlist[i++] = 0; 5586141cc406Sopenharmony_ci 5587141cc406Sopenharmony_ci *device_list = devlist; 5588141cc406Sopenharmony_ci DBG (5, "sane_get_devices: end\n"); 5589141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5590141cc406Sopenharmony_ci} 5591141cc406Sopenharmony_ci 5592141cc406Sopenharmony_ciSANE_Status 5593141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle) 5594141cc406Sopenharmony_ci{ 5595141cc406Sopenharmony_ci Mustek_Device *dev; 5596141cc406Sopenharmony_ci SANE_Status status; 5597141cc406Sopenharmony_ci Mustek_Scanner *s; 5598141cc406Sopenharmony_ci 5599141cc406Sopenharmony_ci if (!devicename) 5600141cc406Sopenharmony_ci { 5601141cc406Sopenharmony_ci DBG (1, "sane_open: devicename is null!\n"); 5602141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5603141cc406Sopenharmony_ci } 5604141cc406Sopenharmony_ci if (!handle) 5605141cc406Sopenharmony_ci { 5606141cc406Sopenharmony_ci DBG (1, "sane_open: handle is null!\n"); 5607141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5608141cc406Sopenharmony_ci } 5609141cc406Sopenharmony_ci DBG (4, "sane_open: devicename=%s\n", devicename); 5610141cc406Sopenharmony_ci 5611141cc406Sopenharmony_ci if (devicename[0]) 5612141cc406Sopenharmony_ci { 5613141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 5614141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devicename) == 0) 5615141cc406Sopenharmony_ci break; 5616141cc406Sopenharmony_ci 5617141cc406Sopenharmony_ci if (!dev) 5618141cc406Sopenharmony_ci { 5619141cc406Sopenharmony_ci status = attach (devicename, &dev, SANE_TRUE); 5620141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 5621141cc406Sopenharmony_ci return status; 5622141cc406Sopenharmony_ci } 5623141cc406Sopenharmony_ci } 5624141cc406Sopenharmony_ci else 5625141cc406Sopenharmony_ci /* empty devicname -> use first device */ 5626141cc406Sopenharmony_ci dev = first_dev; 5627141cc406Sopenharmony_ci 5628141cc406Sopenharmony_ci if (!dev) 5629141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5630141cc406Sopenharmony_ci 5631141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 5632141cc406Sopenharmony_ci if (!s) 5633141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5634141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 5635141cc406Sopenharmony_ci s->fd = -1; 5636141cc406Sopenharmony_ci s->pipe = -1; 5637141cc406Sopenharmony_ci s->hw = dev; 5638141cc406Sopenharmony_ci s->ld.ld_line = 0; 5639141cc406Sopenharmony_ci s->halftone_pattern = malloc (8 * 8 * sizeof (SANE_Int)); 5640141cc406Sopenharmony_ci if (!s->halftone_pattern) 5641141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5642141cc406Sopenharmony_ci init_options (s); 5643141cc406Sopenharmony_ci 5644141cc406Sopenharmony_ci /* insert newly opened handle into list of open handles: */ 5645141cc406Sopenharmony_ci s->next = first_handle; 5646141cc406Sopenharmony_ci first_handle = s; 5647141cc406Sopenharmony_ci 5648141cc406Sopenharmony_ci *handle = s; 5649141cc406Sopenharmony_ci DBG (4, "sane_open: finished (handle=%p)\n", (void *) s); 5650141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5651141cc406Sopenharmony_ci} 5652141cc406Sopenharmony_ci 5653141cc406Sopenharmony_civoid 5654141cc406Sopenharmony_cisane_close (SANE_Handle handle) 5655141cc406Sopenharmony_ci{ 5656141cc406Sopenharmony_ci Mustek_Scanner *prev, *s; 5657141cc406Sopenharmony_ci 5658141cc406Sopenharmony_ci DBG (4, "sane_close: handle=%p\n", handle); 5659141cc406Sopenharmony_ci /* remove handle from list of open handles: */ 5660141cc406Sopenharmony_ci prev = 0; 5661141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 5662141cc406Sopenharmony_ci { 5663141cc406Sopenharmony_ci if (s == handle) 5664141cc406Sopenharmony_ci break; 5665141cc406Sopenharmony_ci prev = s; 5666141cc406Sopenharmony_ci } 5667141cc406Sopenharmony_ci if (!s) 5668141cc406Sopenharmony_ci { 5669141cc406Sopenharmony_ci DBG (1, "sane_close: invalid handle %p\n", handle); 5670141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 5671141cc406Sopenharmony_ci } 5672141cc406Sopenharmony_ci 5673141cc406Sopenharmony_ci if (s->scanning) 5674141cc406Sopenharmony_ci do_stop (handle); 5675141cc406Sopenharmony_ci 5676141cc406Sopenharmony_ci if (s->ld.buf[0]) 5677141cc406Sopenharmony_ci free (s->ld.buf[0]); 5678141cc406Sopenharmony_ci if (s->val[OPT_MODE].s) 5679141cc406Sopenharmony_ci free (s->val[OPT_MODE].s); 5680141cc406Sopenharmony_ci if (s->val[OPT_BIT_DEPTH].s) 5681141cc406Sopenharmony_ci free (s->val[OPT_BIT_DEPTH].s); 5682141cc406Sopenharmony_ci if (s->val[OPT_SPEED].s) 5683141cc406Sopenharmony_ci free (s->val[OPT_SPEED].s); 5684141cc406Sopenharmony_ci if (s->val[OPT_SOURCE].s) 5685141cc406Sopenharmony_ci free (s->val[OPT_SOURCE].s); 5686141cc406Sopenharmony_ci if (s->val[OPT_HALFTONE_DIMENSION].s) 5687141cc406Sopenharmony_ci free (s->val[OPT_HALFTONE_DIMENSION].s); 5688141cc406Sopenharmony_ci if (s->halftone_pattern) 5689141cc406Sopenharmony_ci free (s->halftone_pattern); 5690141cc406Sopenharmony_ci if (prev) 5691141cc406Sopenharmony_ci prev->next = s->next; 5692141cc406Sopenharmony_ci else 5693141cc406Sopenharmony_ci first_handle = s->next; 5694141cc406Sopenharmony_ci free (handle); 5695141cc406Sopenharmony_ci handle = 0; 5696141cc406Sopenharmony_ci DBG (5, "sane_close: finished\n"); 5697141cc406Sopenharmony_ci} 5698141cc406Sopenharmony_ci 5699141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 5700141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 5701141cc406Sopenharmony_ci{ 5702141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 5703141cc406Sopenharmony_ci 5704141cc406Sopenharmony_ci if (((unsigned) option >= NUM_OPTIONS) || (option < 0)) 5705141cc406Sopenharmony_ci { 5706141cc406Sopenharmony_ci DBG (4, "sane_get_option_descriptor: option %d >= NUM_OPTIONS or < 0\n", 5707141cc406Sopenharmony_ci option); 5708141cc406Sopenharmony_ci return 0; 5709141cc406Sopenharmony_ci } 5710141cc406Sopenharmony_ci if (!s) 5711141cc406Sopenharmony_ci { 5712141cc406Sopenharmony_ci DBG (1, "sane_get_option_descriptor: handle is null!\n"); 5713141cc406Sopenharmony_ci return 0; 5714141cc406Sopenharmony_ci } 5715141cc406Sopenharmony_ci if (s->opt[option].name && s->opt[option].name[0] != 0) 5716141cc406Sopenharmony_ci DBG (5, "sane_get_option_descriptor for option %s (%sactive%s)\n", 5717141cc406Sopenharmony_ci s->opt[option].name, 5718141cc406Sopenharmony_ci s->opt[option].cap & SANE_CAP_INACTIVE ? "in" : "", 5719141cc406Sopenharmony_ci s->opt[option].cap & SANE_CAP_ADVANCED ? ", advanced" : ""); 5720141cc406Sopenharmony_ci else 5721141cc406Sopenharmony_ci DBG (5, "sane_get_option_descriptor for option \"%s\" (%sactive%s)\n", 5722141cc406Sopenharmony_ci s->opt[option].title, 5723141cc406Sopenharmony_ci s->opt[option].cap & SANE_CAP_INACTIVE ? "in" : "", 5724141cc406Sopenharmony_ci s->opt[option].cap & SANE_CAP_ADVANCED ? ", advanced" : ""); 5725141cc406Sopenharmony_ci return s->opt + option; 5726141cc406Sopenharmony_ci} 5727141cc406Sopenharmony_ci 5728141cc406Sopenharmony_ciSANE_Status 5729141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 5730141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 5731141cc406Sopenharmony_ci{ 5732141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 5733141cc406Sopenharmony_ci SANE_Status status; 5734141cc406Sopenharmony_ci SANE_Word w, cap; 5735141cc406Sopenharmony_ci 5736141cc406Sopenharmony_ci if (((unsigned) option >= NUM_OPTIONS) || (option < 0)) 5737141cc406Sopenharmony_ci { 5738141cc406Sopenharmony_ci DBG (4, "sane_control_option: option %d < 0 or >= NUM_OPTIONS\n", 5739141cc406Sopenharmony_ci option); 5740141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5741141cc406Sopenharmony_ci } 5742141cc406Sopenharmony_ci if (!s) 5743141cc406Sopenharmony_ci { 5744141cc406Sopenharmony_ci DBG (1, "sane_control_option: handle is null!\n"); 5745141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5746141cc406Sopenharmony_ci } 5747141cc406Sopenharmony_ci 5748141cc406Sopenharmony_ci if (s->opt[option].type != SANE_TYPE_BUTTON && !val) 5749141cc406Sopenharmony_ci { 5750141cc406Sopenharmony_ci DBG (1, "sane_control_option: val is null!\n"); 5751141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5752141cc406Sopenharmony_ci } 5753141cc406Sopenharmony_ci 5754141cc406Sopenharmony_ci if (s->opt[option].name && s->opt[option].name[0] != 0) 5755141cc406Sopenharmony_ci DBG (5, "sane_control_option (%s option %s)\n", 5756141cc406Sopenharmony_ci action == SANE_ACTION_GET_VALUE ? "get" : 5757141cc406Sopenharmony_ci (action == SANE_ACTION_SET_VALUE ? "set" : "unknown action with"), 5758141cc406Sopenharmony_ci s->opt[option].name); 5759141cc406Sopenharmony_ci else 5760141cc406Sopenharmony_ci DBG (5, "sane_control_option (%s option \"%s\")\n", 5761141cc406Sopenharmony_ci action == SANE_ACTION_GET_VALUE ? "get" : 5762141cc406Sopenharmony_ci (action == SANE_ACTION_SET_VALUE ? "set" : "unknown action with"), 5763141cc406Sopenharmony_ci s->opt[option].title); 5764141cc406Sopenharmony_ci 5765141cc406Sopenharmony_ci if (info) 5766141cc406Sopenharmony_ci *info = 0; 5767141cc406Sopenharmony_ci 5768141cc406Sopenharmony_ci if (s->scanning) 5769141cc406Sopenharmony_ci { 5770141cc406Sopenharmony_ci DBG (4, "sane_control_option: don't use while scanning (option %s)\n", 5771141cc406Sopenharmony_ci s->opt[option].name); 5772141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 5773141cc406Sopenharmony_ci } 5774141cc406Sopenharmony_ci 5775141cc406Sopenharmony_ci cap = s->opt[option].cap; 5776141cc406Sopenharmony_ci 5777141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 5778141cc406Sopenharmony_ci { 5779141cc406Sopenharmony_ci DBG (4, "sane_control_option: option %s is inactive\n", 5780141cc406Sopenharmony_ci s->opt[option].name); 5781141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5782141cc406Sopenharmony_ci } 5783141cc406Sopenharmony_ci 5784141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 5785141cc406Sopenharmony_ci { 5786141cc406Sopenharmony_ci switch (option) 5787141cc406Sopenharmony_ci { 5788141cc406Sopenharmony_ci /* word options: */ 5789141cc406Sopenharmony_ci case OPT_PREVIEW: 5790141cc406Sopenharmony_ci case OPT_FAST_PREVIEW: 5791141cc406Sopenharmony_ci case OPT_RESOLUTION: 5792141cc406Sopenharmony_ci case OPT_FAST_GRAY_MODE: 5793141cc406Sopenharmony_ci case OPT_TL_X: 5794141cc406Sopenharmony_ci case OPT_TL_Y: 5795141cc406Sopenharmony_ci case OPT_BR_X: 5796141cc406Sopenharmony_ci case OPT_BR_Y: 5797141cc406Sopenharmony_ci case OPT_NUM_OPTS: 5798141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 5799141cc406Sopenharmony_ci case OPT_BRIGHTNESS_R: 5800141cc406Sopenharmony_ci case OPT_BRIGHTNESS_G: 5801141cc406Sopenharmony_ci case OPT_BRIGHTNESS_B: 5802141cc406Sopenharmony_ci case OPT_CONTRAST: 5803141cc406Sopenharmony_ci case OPT_CONTRAST_R: 5804141cc406Sopenharmony_ci case OPT_CONTRAST_G: 5805141cc406Sopenharmony_ci case OPT_CONTRAST_B: 5806141cc406Sopenharmony_ci case OPT_CUSTOM_GAMMA: 5807141cc406Sopenharmony_ci case OPT_QUALITY_CAL: 5808141cc406Sopenharmony_ci case OPT_LAMP_OFF_TIME: 5809141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option].w; 5810141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5811141cc406Sopenharmony_ci 5812141cc406Sopenharmony_ci /* word-array options: */ 5813141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR: 5814141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_R: 5815141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_G: 5816141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_B: 5817141cc406Sopenharmony_ci case OPT_HALFTONE_PATTERN: 5818141cc406Sopenharmony_ci memcpy (val, s->val[option].wa, s->opt[option].size); 5819141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5820141cc406Sopenharmony_ci 5821141cc406Sopenharmony_ci /* string options: */ 5822141cc406Sopenharmony_ci case OPT_SPEED: 5823141cc406Sopenharmony_ci case OPT_SOURCE: 5824141cc406Sopenharmony_ci case OPT_MODE: 5825141cc406Sopenharmony_ci case OPT_BIT_DEPTH: 5826141cc406Sopenharmony_ci case OPT_HALFTONE_DIMENSION: 5827141cc406Sopenharmony_ci strcpy (val, s->val[option].s); 5828141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5829141cc406Sopenharmony_ci } 5830141cc406Sopenharmony_ci } 5831141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 5832141cc406Sopenharmony_ci { 5833141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 5834141cc406Sopenharmony_ci { 5835141cc406Sopenharmony_ci DBG (4, "sane_control_option: option %s is not setable\n", 5836141cc406Sopenharmony_ci s->opt[option].name); 5837141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5838141cc406Sopenharmony_ci } 5839141cc406Sopenharmony_ci 5840141cc406Sopenharmony_ci status = constrain_value (s, option, val, info); 5841141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 5842141cc406Sopenharmony_ci { 5843141cc406Sopenharmony_ci DBG (4, "sane_control_option: constrain_value error (option %s)\n", 5844141cc406Sopenharmony_ci s->opt[option].name); 5845141cc406Sopenharmony_ci return status; 5846141cc406Sopenharmony_ci } 5847141cc406Sopenharmony_ci 5848141cc406Sopenharmony_ci switch (option) 5849141cc406Sopenharmony_ci { 5850141cc406Sopenharmony_ci case OPT_LAMP_OFF_BUTTON: 5851141cc406Sopenharmony_ci { 5852141cc406Sopenharmony_ci SANE_Int old_time = lamp_off_time; 5853141cc406Sopenharmony_ci SANE_Status status; 5854141cc406Sopenharmony_ci 5855141cc406Sopenharmony_ci status = dev_open (s->hw->sane.name, s, sense_handler); 5856141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 5857141cc406Sopenharmony_ci return status; 5858141cc406Sopenharmony_ci lamp_off_time = 0; 5859141cc406Sopenharmony_ci set_window_pro (s); 5860141cc406Sopenharmony_ci lamp_off_time = old_time; 5861141cc406Sopenharmony_ci dev_close (s); 5862141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5863141cc406Sopenharmony_ci } 5864141cc406Sopenharmony_ci /* (mostly) side-effect-free word options: */ 5865141cc406Sopenharmony_ci case OPT_RESOLUTION: 5866141cc406Sopenharmony_ci case OPT_TL_X: 5867141cc406Sopenharmony_ci case OPT_BR_X: 5868141cc406Sopenharmony_ci case OPT_TL_Y: 5869141cc406Sopenharmony_ci case OPT_BR_Y: 5870141cc406Sopenharmony_ci if (info) 5871141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 5872141cc406Sopenharmony_ci /* fall through */ 5873141cc406Sopenharmony_ci case OPT_PREVIEW: 5874141cc406Sopenharmony_ci case OPT_FAST_PREVIEW: 5875141cc406Sopenharmony_ci case OPT_FAST_GRAY_MODE: 5876141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 5877141cc406Sopenharmony_ci case OPT_BRIGHTNESS_R: 5878141cc406Sopenharmony_ci case OPT_BRIGHTNESS_G: 5879141cc406Sopenharmony_ci case OPT_BRIGHTNESS_B: 5880141cc406Sopenharmony_ci case OPT_CONTRAST: 5881141cc406Sopenharmony_ci case OPT_CONTRAST_R: 5882141cc406Sopenharmony_ci case OPT_CONTRAST_G: 5883141cc406Sopenharmony_ci case OPT_CONTRAST_B: 5884141cc406Sopenharmony_ci case OPT_QUALITY_CAL: 5885141cc406Sopenharmony_ci case OPT_LAMP_OFF_TIME: 5886141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 5887141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5888141cc406Sopenharmony_ci 5889141cc406Sopenharmony_ci /* side-effect-free word-array options: */ 5890141cc406Sopenharmony_ci case OPT_HALFTONE_PATTERN: 5891141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR: 5892141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_R: 5893141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_G: 5894141cc406Sopenharmony_ci case OPT_GAMMA_VECTOR_B: 5895141cc406Sopenharmony_ci memcpy (s->val[option].wa, val, s->opt[option].size); 5896141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5897141cc406Sopenharmony_ci 5898141cc406Sopenharmony_ci /* side-effect-free single-string options: */ 5899141cc406Sopenharmony_ci case OPT_SPEED: 5900141cc406Sopenharmony_ci if (s->val[option].s) 5901141cc406Sopenharmony_ci free (s->val[option].s); 5902141cc406Sopenharmony_ci s->val[option].s = strdup (val); 5903141cc406Sopenharmony_ci if (!s->val[option].s) 5904141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5905141cc406Sopenharmony_ci 5906141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5907141cc406Sopenharmony_ci 5908141cc406Sopenharmony_ci /* side-effect-free string list options: */ 5909141cc406Sopenharmony_ci case OPT_BIT_DEPTH: 5910141cc406Sopenharmony_ci { 5911141cc406Sopenharmony_ci SANE_Char *old_val = s->val[option].s; 5912141cc406Sopenharmony_ci 5913141cc406Sopenharmony_ci if (old_val) 5914141cc406Sopenharmony_ci { 5915141cc406Sopenharmony_ci if (strcmp (old_val, val) == 0) 5916141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no change */ 5917141cc406Sopenharmony_ci free (old_val); 5918141cc406Sopenharmony_ci } 5919141cc406Sopenharmony_ci s->val[option].s = strdup (val); 5920141cc406Sopenharmony_ci if (!s->val[option].s) 5921141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5922141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5923141cc406Sopenharmony_ci } 5924141cc406Sopenharmony_ci 5925141cc406Sopenharmony_ci /* options with side-effects: */ 5926141cc406Sopenharmony_ci case OPT_CUSTOM_GAMMA: 5927141cc406Sopenharmony_ci w = *(SANE_Word *) val; 5928141cc406Sopenharmony_ci 5929141cc406Sopenharmony_ci if (w == s->val[OPT_CUSTOM_GAMMA].w) 5930141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no change */ 5931141cc406Sopenharmony_ci 5932141cc406Sopenharmony_ci if (info) 5933141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 5934141cc406Sopenharmony_ci 5935141cc406Sopenharmony_ci s->val[OPT_CUSTOM_GAMMA].w = w; 5936141cc406Sopenharmony_ci if (w) 5937141cc406Sopenharmony_ci { 5938141cc406Sopenharmony_ci SANE_String_Const mode = s->val[OPT_MODE].s; 5939141cc406Sopenharmony_ci 5940141cc406Sopenharmony_ci if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) 5941141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 5942141cc406Sopenharmony_ci else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) 5943141cc406Sopenharmony_ci { 5944141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 5945141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; 5946141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; 5947141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; 5948141cc406Sopenharmony_ci } 5949141cc406Sopenharmony_ci else if ((strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) 5950141cc406Sopenharmony_ci && (s->hw->flags & MUSTEK_FLAG_PRO)) 5951141cc406Sopenharmony_ci { 5952141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 5953141cc406Sopenharmony_ci } 5954141cc406Sopenharmony_ci } 5955141cc406Sopenharmony_ci else 5956141cc406Sopenharmony_ci { 5957141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 5958141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 5959141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 5960141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 5961141cc406Sopenharmony_ci } 5962141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5963141cc406Sopenharmony_ci 5964141cc406Sopenharmony_ci case OPT_MODE: 5965141cc406Sopenharmony_ci { 5966141cc406Sopenharmony_ci SANE_Char *old_val = s->val[option].s; 5967141cc406Sopenharmony_ci SANE_Int halftoning, binary; 5968141cc406Sopenharmony_ci 5969141cc406Sopenharmony_ci if (old_val) 5970141cc406Sopenharmony_ci { 5971141cc406Sopenharmony_ci if (strcmp (old_val, val) == 0) 5972141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no change */ 5973141cc406Sopenharmony_ci free (old_val); 5974141cc406Sopenharmony_ci } 5975141cc406Sopenharmony_ci if (info) 5976141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; 5977141cc406Sopenharmony_ci 5978141cc406Sopenharmony_ci s->val[option].s = strdup (val); 5979141cc406Sopenharmony_ci if (!s->val[option].s) 5980141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 5981141cc406Sopenharmony_ci 5982141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE; 5983141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].cap |= SANE_CAP_INACTIVE; 5984141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].cap |= SANE_CAP_INACTIVE; 5985141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].cap |= SANE_CAP_INACTIVE; 5986141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; 5987141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].cap |= SANE_CAP_INACTIVE; 5988141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].cap |= SANE_CAP_INACTIVE; 5989141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].cap |= SANE_CAP_INACTIVE; 5990141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; 5991141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; 5992141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; 5993141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; 5994141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; 5995141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].cap |= SANE_CAP_INACTIVE; 5996141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; 5997141cc406Sopenharmony_ci 5998141cc406Sopenharmony_ci halftoning = strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE) == 0; 5999141cc406Sopenharmony_ci binary = (halftoning || strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0); 6000141cc406Sopenharmony_ci 6001141cc406Sopenharmony_ci if (binary) 6002141cc406Sopenharmony_ci { 6003141cc406Sopenharmony_ci /* enable brightness/contrast for when in a binary mode */ 6004141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; 6005141cc406Sopenharmony_ci /* The SE and paragon models support only threshold 6006141cc406Sopenharmony_ci in lineart */ 6007141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_SE) 6008141cc406Sopenharmony_ci && !(s->hw->flags & MUSTEK_FLAG_PRO)) 6009141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; 6010141cc406Sopenharmony_ci 6011141cc406Sopenharmony_ci if (halftoning) 6012141cc406Sopenharmony_ci { 6013141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_DIMENSION].cap &= ~SANE_CAP_INACTIVE; 6014141cc406Sopenharmony_ci encode_halftone (s); 6015141cc406Sopenharmony_ci if (s->custom_halftone_pattern) 6016141cc406Sopenharmony_ci { 6017141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap 6018141cc406Sopenharmony_ci &= ~SANE_CAP_INACTIVE; 6019141cc406Sopenharmony_ci } 6020141cc406Sopenharmony_ci else 6021141cc406Sopenharmony_ci { 6022141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; 6023141cc406Sopenharmony_ci } 6024141cc406Sopenharmony_ci } 6025141cc406Sopenharmony_ci } 6026141cc406Sopenharmony_ci else 6027141cc406Sopenharmony_ci { 6028141cc406Sopenharmony_ci s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; 6029141cc406Sopenharmony_ci } 6030141cc406Sopenharmony_ci 6031141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 6032141cc406Sopenharmony_ci { 6033141cc406Sopenharmony_ci if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) 6034141cc406Sopenharmony_ci { 6035141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_R].cap &= ~SANE_CAP_INACTIVE; 6036141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_G].cap &= ~SANE_CAP_INACTIVE; 6037141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS_B].cap &= ~SANE_CAP_INACTIVE; 6038141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_R].cap &= ~SANE_CAP_INACTIVE; 6039141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_G].cap &= ~SANE_CAP_INACTIVE; 6040141cc406Sopenharmony_ci s->opt[OPT_CONTRAST_B].cap &= ~SANE_CAP_INACTIVE; 6041141cc406Sopenharmony_ci } 6042141cc406Sopenharmony_ci else 6043141cc406Sopenharmony_ci { 6044141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; 6045141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; 6046141cc406Sopenharmony_ci } 6047141cc406Sopenharmony_ci } 6048141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PRO) 6049141cc406Sopenharmony_ci { 6050141cc406Sopenharmony_ci if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) 6051141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].cap &= ~SANE_CAP_INACTIVE; 6052141cc406Sopenharmony_ci else 6053141cc406Sopenharmony_ci s->opt[OPT_FAST_GRAY_MODE].cap |= SANE_CAP_INACTIVE; 6054141cc406Sopenharmony_ci if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) 6055141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE; 6056141cc406Sopenharmony_ci else 6057141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 6058141cc406Sopenharmony_ci } 6059141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SE_PLUS) 6060141cc406Sopenharmony_ci { 6061141cc406Sopenharmony_ci if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) 6062141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE; 6063141cc406Sopenharmony_ci else 6064141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 6065141cc406Sopenharmony_ci } 6066141cc406Sopenharmony_ci 6067141cc406Sopenharmony_ci if (s->val[OPT_CUSTOM_GAMMA].w) 6068141cc406Sopenharmony_ci { 6069141cc406Sopenharmony_ci if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0) 6070141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 6071141cc406Sopenharmony_ci else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0) 6072141cc406Sopenharmony_ci { 6073141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; 6074141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; 6075141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; 6076141cc406Sopenharmony_ci s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; 6077141cc406Sopenharmony_ci } 6078141cc406Sopenharmony_ci } 6079141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6080141cc406Sopenharmony_ci } 6081141cc406Sopenharmony_ci 6082141cc406Sopenharmony_ci case OPT_HALFTONE_DIMENSION: 6083141cc406Sopenharmony_ci /* halftone pattern dimension affects halftone pattern option: */ 6084141cc406Sopenharmony_ci { 6085141cc406Sopenharmony_ci if (strcmp (s->val[option].s, (SANE_String) val) == 0) 6086141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no change */ 6087141cc406Sopenharmony_ci 6088141cc406Sopenharmony_ci if (info) 6089141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 6090141cc406Sopenharmony_ci 6091141cc406Sopenharmony_ci s->val[option].s = strdup (val); 6092141cc406Sopenharmony_ci if (!s->val[option].s) 6093141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 6094141cc406Sopenharmony_ci encode_halftone (s); 6095141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; 6096141cc406Sopenharmony_ci if (s->custom_halftone_pattern) 6097141cc406Sopenharmony_ci { 6098141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE; 6099141cc406Sopenharmony_ci /* BUG: The SANE standard does nor allow to change the option 6100141cc406Sopenharmony_ci size at run time */ 6101141cc406Sopenharmony_ci s->opt[OPT_HALFTONE_PATTERN].size = 6102141cc406Sopenharmony_ci (s->halftone_pattern_type & 0x0f) * sizeof (SANE_Word); 6103141cc406Sopenharmony_ci } 6104141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6105141cc406Sopenharmony_ci } 6106141cc406Sopenharmony_ci 6107141cc406Sopenharmony_ci case OPT_SOURCE: 6108141cc406Sopenharmony_ci if (info) 6109141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 6110141cc406Sopenharmony_ci if (s->val[option].s) 6111141cc406Sopenharmony_ci free (s->val[option].s); 6112141cc406Sopenharmony_ci s->val[option].s = strdup (val); 6113141cc406Sopenharmony_ci if (!s->val[option].s) 6114141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 6115141cc406Sopenharmony_ci 6116141cc406Sopenharmony_ci if (strcmp (val, "Transparency Adapter") == 0) 6117141cc406Sopenharmony_ci { 6118141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &s->hw->x_trans_range; 6119141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &s->hw->y_trans_range; 6120141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &s->hw->x_trans_range; 6121141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &s->hw->y_trans_range; 6122141cc406Sopenharmony_ci } 6123141cc406Sopenharmony_ci else 6124141cc406Sopenharmony_ci { 6125141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &s->hw->x_range; 6126141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range; 6127141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &s->hw->x_range; 6128141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range; 6129141cc406Sopenharmony_ci } 6130141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6131141cc406Sopenharmony_ci } 6132141cc406Sopenharmony_ci } 6133141cc406Sopenharmony_ci DBG (4, "sane_control_option: unknown action for option %s\n", 6134141cc406Sopenharmony_ci s->opt[option].name); 6135141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6136141cc406Sopenharmony_ci} 6137141cc406Sopenharmony_ci 6138141cc406Sopenharmony_ciSANE_Status 6139141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 6140141cc406Sopenharmony_ci{ 6141141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6142141cc406Sopenharmony_ci SANE_String_Const mode; 6143141cc406Sopenharmony_ci 6144141cc406Sopenharmony_ci if (!s) 6145141cc406Sopenharmony_ci { 6146141cc406Sopenharmony_ci DBG (1, "sane_get_parameters: handle is null!\n"); 6147141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6148141cc406Sopenharmony_ci } 6149141cc406Sopenharmony_ci 6150141cc406Sopenharmony_ci if (!s->scanning) 6151141cc406Sopenharmony_ci { 6152141cc406Sopenharmony_ci double width, height, dpi; 6153141cc406Sopenharmony_ci 6154141cc406Sopenharmony_ci memset (&s->params, 0, sizeof (s->params)); 6155141cc406Sopenharmony_ci 6156141cc406Sopenharmony_ci width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w); 6157141cc406Sopenharmony_ci height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w); 6158141cc406Sopenharmony_ci dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w); 6159141cc406Sopenharmony_ci 6160141cc406Sopenharmony_ci /* make best-effort guess at what parameters will look like once 6161141cc406Sopenharmony_ci scanning starts. */ 6162141cc406Sopenharmony_ci if (dpi > 0.0 && width > 0.0 && height > 0.0) 6163141cc406Sopenharmony_ci { 6164141cc406Sopenharmony_ci double dots_per_mm = dpi / MM_PER_INCH; 6165141cc406Sopenharmony_ci 6166141cc406Sopenharmony_ci s->params.pixels_per_line = width * dots_per_mm; 6167141cc406Sopenharmony_ci s->params.lines = height * dots_per_mm; 6168141cc406Sopenharmony_ci } 6169141cc406Sopenharmony_ci encode_halftone (s); 6170141cc406Sopenharmony_ci mode = s->val[OPT_MODE].s; 6171141cc406Sopenharmony_ci if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0 || strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) 6172141cc406Sopenharmony_ci { 6173141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 6174141cc406Sopenharmony_ci s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8; 6175141cc406Sopenharmony_ci s->params.depth = 1; 6176141cc406Sopenharmony_ci } 6177141cc406Sopenharmony_ci else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) 6178141cc406Sopenharmony_ci { 6179141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 6180141cc406Sopenharmony_ci s->params.bytes_per_line = s->params.pixels_per_line; 6181141cc406Sopenharmony_ci s->params.depth = 8; 6182141cc406Sopenharmony_ci } 6183141cc406Sopenharmony_ci else 6184141cc406Sopenharmony_ci { 6185141cc406Sopenharmony_ci /* it's one of the color modes... */ 6186141cc406Sopenharmony_ci 6187141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 6188141cc406Sopenharmony_ci { 6189141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RED + s->pass; 6190141cc406Sopenharmony_ci s->params.bytes_per_line = s->params.pixels_per_line; 6191141cc406Sopenharmony_ci s->params.depth = 8; 6192141cc406Sopenharmony_ci } 6193141cc406Sopenharmony_ci else /* 1-pass */ 6194141cc406Sopenharmony_ci { 6195141cc406Sopenharmony_ci if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0) 6196141cc406Sopenharmony_ci { 6197141cc406Sopenharmony_ci s->params.bytes_per_line = 6 * s->params.pixels_per_line; 6198141cc406Sopenharmony_ci s->params.depth = 16; 6199141cc406Sopenharmony_ci } 6200141cc406Sopenharmony_ci else 6201141cc406Sopenharmony_ci { 6202141cc406Sopenharmony_ci s->params.bytes_per_line = 3 * s->params.pixels_per_line; 6203141cc406Sopenharmony_ci s->params.depth = 8; 6204141cc406Sopenharmony_ci } 6205141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 6206141cc406Sopenharmony_ci } 6207141cc406Sopenharmony_ci } 6208141cc406Sopenharmony_ci } 6209141cc406Sopenharmony_ci else if ((s->mode & MUSTEK_MODE_COLOR) 6210141cc406Sopenharmony_ci && (s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 6211141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RED + s->pass; 6212141cc406Sopenharmony_ci s->params.last_frame = (s->params.format != SANE_FRAME_RED 6213141cc406Sopenharmony_ci && s->params.format != SANE_FRAME_GREEN); 6214141cc406Sopenharmony_ci if (params) 6215141cc406Sopenharmony_ci *params = s->params; 6216141cc406Sopenharmony_ci DBG (4, "sane_get_parameters: frame = %d; last_frame = %s; depth = %d\n", 6217141cc406Sopenharmony_ci s->params.format, s->params.last_frame ? "true" : "false", 6218141cc406Sopenharmony_ci s->params.depth); 6219141cc406Sopenharmony_ci DBG (4, "sane_get_parameters: lines = %d; ppl = %d; bpl = %d\n", 6220141cc406Sopenharmony_ci s->params.lines, s->params.pixels_per_line, s->params.bytes_per_line); 6221141cc406Sopenharmony_ci 6222141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6223141cc406Sopenharmony_ci} 6224141cc406Sopenharmony_ci 6225141cc406Sopenharmony_ciSANE_Status 6226141cc406Sopenharmony_cisane_start (SANE_Handle handle) 6227141cc406Sopenharmony_ci{ 6228141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6229141cc406Sopenharmony_ci SANE_Status status; 6230141cc406Sopenharmony_ci int fds[2]; 6231141cc406Sopenharmony_ci struct SIGACTION act; 6232141cc406Sopenharmony_ci 6233141cc406Sopenharmony_ci if (!s) 6234141cc406Sopenharmony_ci { 6235141cc406Sopenharmony_ci DBG (1, "sane_start: handle is null!\n"); 6236141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6237141cc406Sopenharmony_ci } 6238141cc406Sopenharmony_ci 6239141cc406Sopenharmony_ci DBG (4, "sane_start\n"); 6240141cc406Sopenharmony_ci /* First make sure we have a current parameter set. Some of the 6241141cc406Sopenharmony_ci parameters will be overwritten below, but that's OK. */ 6242141cc406Sopenharmony_ci status = sane_get_parameters (s, 0); 6243141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6244141cc406Sopenharmony_ci return status; 6245141cc406Sopenharmony_ci 6246141cc406Sopenharmony_ci /* Check for inconsistencies */ 6247141cc406Sopenharmony_ci 6248141cc406Sopenharmony_ci if (s->val[OPT_TL_X].w > s->val[OPT_BR_X].w) 6249141cc406Sopenharmony_ci { 6250141cc406Sopenharmony_ci DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) " 6251141cc406Sopenharmony_ci "-- aborting\n", 6252141cc406Sopenharmony_ci s->opt[OPT_TL_X].title, SANE_UNFIX (s->val[OPT_TL_X].w), 6253141cc406Sopenharmony_ci s->opt[OPT_BR_X].title, SANE_UNFIX (s->val[OPT_BR_X].w)); 6254141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6255141cc406Sopenharmony_ci } 6256141cc406Sopenharmony_ci if (s->val[OPT_TL_Y].w > s->val[OPT_BR_Y].w) 6257141cc406Sopenharmony_ci { 6258141cc406Sopenharmony_ci DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) " 6259141cc406Sopenharmony_ci "-- aborting\n", 6260141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title, SANE_UNFIX (s->val[OPT_TL_Y].w), 6261141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title, SANE_UNFIX (s->val[OPT_BR_Y].w)); 6262141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6263141cc406Sopenharmony_ci } 6264141cc406Sopenharmony_ci 6265141cc406Sopenharmony_ci s->total_bytes = 0; 6266141cc406Sopenharmony_ci 6267141cc406Sopenharmony_ci if (s->fd < 0) 6268141cc406Sopenharmony_ci { 6269141cc406Sopenharmony_ci /* this is the first (and maybe only) pass... */ 6270141cc406Sopenharmony_ci SANE_String_Const mode; 6271141cc406Sopenharmony_ci struct timeval start; 6272141cc406Sopenharmony_ci 6273141cc406Sopenharmony_ci /* save start time */ 6274141cc406Sopenharmony_ci gettimeofday (&start, 0); 6275141cc406Sopenharmony_ci s->start_time = start.tv_sec; 6276141cc406Sopenharmony_ci /* translate options into s->mode for convenient access: */ 6277141cc406Sopenharmony_ci mode = s->val[OPT_MODE].s; 6278141cc406Sopenharmony_ci if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) 6279141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_LINEART; 6280141cc406Sopenharmony_ci else if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) 6281141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_HALFTONE; 6282141cc406Sopenharmony_ci else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) 6283141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_GRAY; 6284141cc406Sopenharmony_ci else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) 6285141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_COLOR; 6286141cc406Sopenharmony_ci 6287141cc406Sopenharmony_ci /* scanner dependent specials */ 6288141cc406Sopenharmony_ci s->one_pass_color_scan = SANE_FALSE; 6289141cc406Sopenharmony_ci if ((s->mode & MUSTEK_MODE_COLOR) 6290141cc406Sopenharmony_ci && !(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 6291141cc406Sopenharmony_ci { 6292141cc406Sopenharmony_ci s->one_pass_color_scan = SANE_TRUE; 6293141cc406Sopenharmony_ci } 6294141cc406Sopenharmony_ci 6295141cc406Sopenharmony_ci s->resolution_code = encode_resolution (s); 6296141cc406Sopenharmony_ci 6297141cc406Sopenharmony_ci if (s->val[OPT_PREVIEW].w && s->val[OPT_FAST_PREVIEW].w) 6298141cc406Sopenharmony_ci { 6299141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_THREE_PASS) 6300141cc406Sopenharmony_ci { 6301141cc406Sopenharmony_ci if (s->mode & MUSTEK_MODE_COLOR) 6302141cc406Sopenharmony_ci { 6303141cc406Sopenharmony_ci /* Force gray-scale mode when previewing. */ 6304141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_GRAY; 6305141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 6306141cc406Sopenharmony_ci s->params.bytes_per_line = s->params.pixels_per_line; 6307141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 6308141cc406Sopenharmony_ci } 6309141cc406Sopenharmony_ci } 6310141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_SE) 6311141cc406Sopenharmony_ci { 6312141cc406Sopenharmony_ci /* use 36 dpi color in any case */ 6313141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_COLOR; 6314141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 6315141cc406Sopenharmony_ci s->params.depth = 8; 6316141cc406Sopenharmony_ci s->one_pass_color_scan = SANE_TRUE; 6317141cc406Sopenharmony_ci s->resolution_code = 36; 6318141cc406Sopenharmony_ci } 6319141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PARAGON_1) 6320141cc406Sopenharmony_ci { 6321141cc406Sopenharmony_ci /* use 36 dpi */ 6322141cc406Sopenharmony_ci s->resolution_code = 36; 6323141cc406Sopenharmony_ci } 6324141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PRO) 6325141cc406Sopenharmony_ci { 6326141cc406Sopenharmony_ci /* use 30 dpi color mode */ 6327141cc406Sopenharmony_ci s->mode = MUSTEK_MODE_COLOR; 6328141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 6329141cc406Sopenharmony_ci s->params.depth = 8; 6330141cc406Sopenharmony_ci s->one_pass_color_scan = SANE_TRUE; 6331141cc406Sopenharmony_ci s->resolution_code = 30; 6332141cc406Sopenharmony_ci } 6333141cc406Sopenharmony_ci DBG (4, "sane_start: use fast preview (res=%d dpi)\n", 6334141cc406Sopenharmony_ci s->resolution_code); 6335141cc406Sopenharmony_ci } 6336141cc406Sopenharmony_ci 6337141cc406Sopenharmony_ci status = dev_open (s->hw->sane.name, s, sense_handler); 6338141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6339141cc406Sopenharmony_ci return status; 6340141cc406Sopenharmony_ci } 6341141cc406Sopenharmony_ci 6342141cc406Sopenharmony_ci status = dev_wait_ready (s); 6343141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6344141cc406Sopenharmony_ci { 6345141cc406Sopenharmony_ci DBG (1, "sane_start: wait_ready() failed: %s\n", 6346141cc406Sopenharmony_ci sane_strstatus (status)); 6347141cc406Sopenharmony_ci goto stop_scanner_and_return; 6348141cc406Sopenharmony_ci } 6349141cc406Sopenharmony_ci 6350141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_SCSI_PP)) 6351141cc406Sopenharmony_ci { 6352141cc406Sopenharmony_ci /* SCSI-over-parallel port doesn't seem to like being inquired here */ 6353141cc406Sopenharmony_ci status = inquiry (s); 6354141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6355141cc406Sopenharmony_ci { 6356141cc406Sopenharmony_ci DBG (1, "sane_start: inquiry command failed: %s\n", 6357141cc406Sopenharmony_ci sane_strstatus (status)); 6358141cc406Sopenharmony_ci goto stop_scanner_and_return; 6359141cc406Sopenharmony_ci } 6360141cc406Sopenharmony_ci } 6361141cc406Sopenharmony_ci 6362141cc406Sopenharmony_ci if ((strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) && 6363141cc406Sopenharmony_ci !(s->hw->flags & MUSTEK_FLAG_ADF_READY)) 6364141cc406Sopenharmony_ci { 6365141cc406Sopenharmony_ci DBG (2, "sane_start: automatic document feeder is out of documents\n"); 6366141cc406Sopenharmony_ci status = SANE_STATUS_NO_DOCS; 6367141cc406Sopenharmony_ci goto stop_scanner_and_return; 6368141cc406Sopenharmony_ci } 6369141cc406Sopenharmony_ci 6370141cc406Sopenharmony_ci if (s->hw->flags & MUSTEK_FLAG_SE) 6371141cc406Sopenharmony_ci { 6372141cc406Sopenharmony_ci status = set_window_se (s, 0); 6373141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6374141cc406Sopenharmony_ci { 6375141cc406Sopenharmony_ci DBG (1, "sane_start: set window command failed: %s\n", 6376141cc406Sopenharmony_ci sane_strstatus (status)); 6377141cc406Sopenharmony_ci goto stop_scanner_and_return; 6378141cc406Sopenharmony_ci } 6379141cc406Sopenharmony_ci 6380141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 6381141cc406Sopenharmony_ci s->cancelled = SANE_FALSE; 6382141cc406Sopenharmony_ci 6383141cc406Sopenharmony_ci dev_wait_ready (s); 6384141cc406Sopenharmony_ci 6385141cc406Sopenharmony_ci status = get_window (s, &s->params.bytes_per_line, 6386141cc406Sopenharmony_ci &s->params.lines, &s->params.pixels_per_line); 6387141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6388141cc406Sopenharmony_ci { 6389141cc406Sopenharmony_ci DBG (1, "sane_start: get window command failed: %s\n", 6390141cc406Sopenharmony_ci sane_strstatus (status)); 6391141cc406Sopenharmony_ci goto stop_scanner_and_return; 6392141cc406Sopenharmony_ci } 6393141cc406Sopenharmony_ci 6394141cc406Sopenharmony_ci status = calibration_se (s); 6395141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6396141cc406Sopenharmony_ci goto stop_scanner_and_return; 6397141cc406Sopenharmony_ci 6398141cc406Sopenharmony_ci status = start_scan (s); 6399141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6400141cc406Sopenharmony_ci goto stop_scanner_and_return; 6401141cc406Sopenharmony_ci 6402141cc406Sopenharmony_ci status = send_gamma_table_se (s); 6403141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6404141cc406Sopenharmony_ci goto stop_scanner_and_return; 6405141cc406Sopenharmony_ci } 6406141cc406Sopenharmony_ci 6407141cc406Sopenharmony_ci else if (s->hw->flags & MUSTEK_FLAG_PRO) 6408141cc406Sopenharmony_ci { 6409141cc406Sopenharmony_ci 6410141cc406Sopenharmony_ci status = dev_wait_ready (s); 6411141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6412141cc406Sopenharmony_ci goto stop_scanner_and_return; 6413141cc406Sopenharmony_ci 6414141cc406Sopenharmony_ci status = set_window_pro (s); 6415141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6416141cc406Sopenharmony_ci goto stop_scanner_and_return; 6417141cc406Sopenharmony_ci 6418141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 6419141cc406Sopenharmony_ci s->cancelled = SANE_FALSE; 6420141cc406Sopenharmony_ci 6421141cc406Sopenharmony_ci status = adf_and_backtrack (s); 6422141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6423141cc406Sopenharmony_ci goto stop_scanner_and_return; 6424141cc406Sopenharmony_ci 6425141cc406Sopenharmony_ci status = mode_select_pro (s); 6426141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6427141cc406Sopenharmony_ci goto stop_scanner_and_return; 6428141cc406Sopenharmony_ci 6429141cc406Sopenharmony_ci status = scsi_sense_wait_ready (s); 6430141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6431141cc406Sopenharmony_ci goto stop_scanner_and_return; 6432141cc406Sopenharmony_ci 6433141cc406Sopenharmony_ci status = calibration_pro (s); 6434141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6435141cc406Sopenharmony_ci goto stop_scanner_and_return; 6436141cc406Sopenharmony_ci 6437141cc406Sopenharmony_ci status = send_gamma_table (s); 6438141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6439141cc406Sopenharmony_ci goto stop_scanner_and_return; 6440141cc406Sopenharmony_ci 6441141cc406Sopenharmony_ci status = start_scan (s); 6442141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6443141cc406Sopenharmony_ci goto stop_scanner_and_return; 6444141cc406Sopenharmony_ci 6445141cc406Sopenharmony_ci status = get_image_status (s, &s->params.bytes_per_line, 6446141cc406Sopenharmony_ci &s->params.lines); 6447141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6448141cc406Sopenharmony_ci goto stop_scanner_and_return; 6449141cc406Sopenharmony_ci 6450141cc406Sopenharmony_ci status = scsi_sense_wait_ready (s); 6451141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6452141cc406Sopenharmony_ci goto stop_scanner_and_return; 6453141cc406Sopenharmony_ci } 6454141cc406Sopenharmony_ci 6455141cc406Sopenharmony_ci else /* Paragon series */ 6456141cc406Sopenharmony_ci { 6457141cc406Sopenharmony_ci status = area_and_windows (s); 6458141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6459141cc406Sopenharmony_ci { 6460141cc406Sopenharmony_ci DBG (1, "sane_start: set scan area command failed: %s\n", 6461141cc406Sopenharmony_ci sane_strstatus (status)); 6462141cc406Sopenharmony_ci goto stop_scanner_and_return; 6463141cc406Sopenharmony_ci } 6464141cc406Sopenharmony_ci 6465141cc406Sopenharmony_ci status = adf_and_backtrack (s); 6466141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6467141cc406Sopenharmony_ci goto stop_scanner_and_return; 6468141cc406Sopenharmony_ci 6469141cc406Sopenharmony_ci if (s->one_pass_color_scan) 6470141cc406Sopenharmony_ci { 6471141cc406Sopenharmony_ci status = mode_select_paragon (s, MUSTEK_CODE_RED); 6472141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6473141cc406Sopenharmony_ci goto stop_scanner_and_return; 6474141cc406Sopenharmony_ci 6475141cc406Sopenharmony_ci status = mode_select_paragon (s, MUSTEK_CODE_GREEN); 6476141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6477141cc406Sopenharmony_ci goto stop_scanner_and_return; 6478141cc406Sopenharmony_ci 6479141cc406Sopenharmony_ci status = mode_select_paragon (s, MUSTEK_CODE_BLUE); 6480141cc406Sopenharmony_ci } 6481141cc406Sopenharmony_ci else 6482141cc406Sopenharmony_ci status = mode_select_paragon (s, MUSTEK_CODE_GRAY); 6483141cc406Sopenharmony_ci 6484141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6485141cc406Sopenharmony_ci goto stop_scanner_and_return; 6486141cc406Sopenharmony_ci 6487141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 6488141cc406Sopenharmony_ci s->cancelled = SANE_FALSE; 6489141cc406Sopenharmony_ci 6490141cc406Sopenharmony_ci status = send_gamma_table (s); 6491141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6492141cc406Sopenharmony_ci goto stop_scanner_and_return; 6493141cc406Sopenharmony_ci 6494141cc406Sopenharmony_ci status = start_scan (s); 6495141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6496141cc406Sopenharmony_ci goto stop_scanner_and_return; 6497141cc406Sopenharmony_ci 6498141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_SCSI_PP)) 6499141cc406Sopenharmony_ci { 6500141cc406Sopenharmony_ci /* This second gamma table download upsets the SCSI-over-parallel models */ 6501141cc406Sopenharmony_ci status = send_gamma_table (s); 6502141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6503141cc406Sopenharmony_ci goto stop_scanner_and_return; 6504141cc406Sopenharmony_ci } 6505141cc406Sopenharmony_ci 6506141cc406Sopenharmony_ci s->ld.max_value = 0; 6507141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)) 6508141cc406Sopenharmony_ci { 6509141cc406Sopenharmony_ci status = line_distance (s); 6510141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6511141cc406Sopenharmony_ci goto stop_scanner_and_return; 6512141cc406Sopenharmony_ci } 6513141cc406Sopenharmony_ci 6514141cc406Sopenharmony_ci status = get_image_status (s, &s->params.bytes_per_line, 6515141cc406Sopenharmony_ci &s->params.lines); 6516141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6517141cc406Sopenharmony_ci goto stop_scanner_and_return; 6518141cc406Sopenharmony_ci 6519141cc406Sopenharmony_ci if ((strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) 6520141cc406Sopenharmony_ci && (s->hw->flags & MUSTEK_FLAG_PARAGON_2)) 6521141cc406Sopenharmony_ci { 6522141cc406Sopenharmony_ci status = paragon_2_get_adf_status (s); 6523141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 6524141cc406Sopenharmony_ci goto stop_scanner_and_return; 6525141cc406Sopenharmony_ci } 6526141cc406Sopenharmony_ci } 6527141cc406Sopenharmony_ci 6528141cc406Sopenharmony_ci s->params.pixels_per_line = s->params.bytes_per_line; 6529141cc406Sopenharmony_ci if (s->one_pass_color_scan) 6530141cc406Sopenharmony_ci { 6531141cc406Sopenharmony_ci if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0) 6532141cc406Sopenharmony_ci s->params.pixels_per_line /= 6; 6533141cc406Sopenharmony_ci else 6534141cc406Sopenharmony_ci s->params.pixels_per_line /= 3; 6535141cc406Sopenharmony_ci } 6536141cc406Sopenharmony_ci else if ((s->mode & MUSTEK_MODE_LINEART) 6537141cc406Sopenharmony_ci || (s->mode & MUSTEK_MODE_HALFTONE)) 6538141cc406Sopenharmony_ci s->params.pixels_per_line *= 8; 6539141cc406Sopenharmony_ci 6540141cc406Sopenharmony_ci s->line = 0; 6541141cc406Sopenharmony_ci 6542141cc406Sopenharmony_ci /* don't call any SIGTERM or SIGCHLD handlers 6543141cc406Sopenharmony_ci this is to stop xsane and other frontends from calling 6544141cc406Sopenharmony_ci its quit handlers */ 6545141cc406Sopenharmony_ci memset (&act, 0, sizeof (act)); 6546141cc406Sopenharmony_ci sigaction (SIGTERM, &act, 0); 6547141cc406Sopenharmony_ci sigaction (SIGCHLD, &act, 0); 6548141cc406Sopenharmony_ci 6549141cc406Sopenharmony_ci if (pipe (fds) < 0) 6550141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 6551141cc406Sopenharmony_ci 6552141cc406Sopenharmony_ci s->reader_fds = fds[1]; 6553141cc406Sopenharmony_ci 6554141cc406Sopenharmony_ci /* create reader routine as new process or thread */ 6555141cc406Sopenharmony_ci s->reader_pid = sanei_thread_begin (reader_process, (void *) s); 6556141cc406Sopenharmony_ci 6557141cc406Sopenharmony_ci if (!sanei_thread_is_valid (s->reader_pid)) 6558141cc406Sopenharmony_ci { 6559141cc406Sopenharmony_ci DBG (1, "sane_start: sanei_thread_begin failed (%s)\n", 6560141cc406Sopenharmony_ci strerror (errno)); 6561141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 6562141cc406Sopenharmony_ci } 6563141cc406Sopenharmony_ci 6564141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 6565141cc406Sopenharmony_ci { 6566141cc406Sopenharmony_ci close (s->reader_fds); 6567141cc406Sopenharmony_ci s->reader_fds = -1; 6568141cc406Sopenharmony_ci } 6569141cc406Sopenharmony_ci 6570141cc406Sopenharmony_ci s->pipe = fds[0]; 6571141cc406Sopenharmony_ci 6572141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6573141cc406Sopenharmony_ci 6574141cc406Sopenharmony_cistop_scanner_and_return: 6575141cc406Sopenharmony_ci do_stop (s); 6576141cc406Sopenharmony_ci return status; 6577141cc406Sopenharmony_ci} 6578141cc406Sopenharmony_ci 6579141cc406Sopenharmony_ciSANE_Status 6580141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, 6581141cc406Sopenharmony_ci SANE_Int * len) 6582141cc406Sopenharmony_ci{ 6583141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6584141cc406Sopenharmony_ci SANE_Status status; 6585141cc406Sopenharmony_ci ssize_t nread; 6586141cc406Sopenharmony_ci 6587141cc406Sopenharmony_ci 6588141cc406Sopenharmony_ci if (!s) 6589141cc406Sopenharmony_ci { 6590141cc406Sopenharmony_ci DBG (1, "sane_read: handle is null!\n"); 6591141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6592141cc406Sopenharmony_ci } 6593141cc406Sopenharmony_ci 6594141cc406Sopenharmony_ci if (!buf) 6595141cc406Sopenharmony_ci { 6596141cc406Sopenharmony_ci DBG (1, "sane_read: buf is null!\n"); 6597141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6598141cc406Sopenharmony_ci } 6599141cc406Sopenharmony_ci 6600141cc406Sopenharmony_ci if (!len) 6601141cc406Sopenharmony_ci { 6602141cc406Sopenharmony_ci DBG (1, "sane_read: len is null!\n"); 6603141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6604141cc406Sopenharmony_ci } 6605141cc406Sopenharmony_ci 6606141cc406Sopenharmony_ci DBG (5, "sane_read\n"); 6607141cc406Sopenharmony_ci *len = 0; 6608141cc406Sopenharmony_ci 6609141cc406Sopenharmony_ci if (s->cancelled) 6610141cc406Sopenharmony_ci { 6611141cc406Sopenharmony_ci DBG (4, "sane_read: scan was cancelled\n"); 6612141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 6613141cc406Sopenharmony_ci } 6614141cc406Sopenharmony_ci 6615141cc406Sopenharmony_ci if (!s->scanning) 6616141cc406Sopenharmony_ci { 6617141cc406Sopenharmony_ci DBG (3, "sane_read: must call sane_start before sane_read\n"); 6618141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6619141cc406Sopenharmony_ci } 6620141cc406Sopenharmony_ci 6621141cc406Sopenharmony_ci while (*len < max_len) 6622141cc406Sopenharmony_ci { 6623141cc406Sopenharmony_ci nread = read (s->pipe, buf + *len, max_len - *len); 6624141cc406Sopenharmony_ci 6625141cc406Sopenharmony_ci if (s->cancelled) 6626141cc406Sopenharmony_ci { 6627141cc406Sopenharmony_ci DBG (4, "sane_read: scan was cancelled\n"); 6628141cc406Sopenharmony_ci *len = 0; 6629141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 6630141cc406Sopenharmony_ci } 6631141cc406Sopenharmony_ci 6632141cc406Sopenharmony_ci if (nread < 0) 6633141cc406Sopenharmony_ci { 6634141cc406Sopenharmony_ci if (errno == EAGAIN) 6635141cc406Sopenharmony_ci { 6636141cc406Sopenharmony_ci if (*len == 0) 6637141cc406Sopenharmony_ci DBG (5, "sane_read: no more data at the moment--try again\n"); 6638141cc406Sopenharmony_ci else 6639141cc406Sopenharmony_ci DBG (5, "sane_read: read buffer of %d bytes " 6640141cc406Sopenharmony_ci "(%d bytes total)\n", *len, s->total_bytes); 6641141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6642141cc406Sopenharmony_ci } 6643141cc406Sopenharmony_ci else 6644141cc406Sopenharmony_ci { 6645141cc406Sopenharmony_ci DBG (1, "sane_read: IO error\n"); 6646141cc406Sopenharmony_ci do_stop (s); 6647141cc406Sopenharmony_ci *len = 0; 6648141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 6649141cc406Sopenharmony_ci } 6650141cc406Sopenharmony_ci } 6651141cc406Sopenharmony_ci 6652141cc406Sopenharmony_ci *len += nread; 6653141cc406Sopenharmony_ci s->total_bytes += nread; 6654141cc406Sopenharmony_ci 6655141cc406Sopenharmony_ci if (nread == 0) 6656141cc406Sopenharmony_ci { 6657141cc406Sopenharmony_ci if (*len == 0) 6658141cc406Sopenharmony_ci { 6659141cc406Sopenharmony_ci if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS) 6660141cc406Sopenharmony_ci || !(s->mode & MUSTEK_MODE_COLOR) || ++s->pass >= 3) 6661141cc406Sopenharmony_ci { 6662141cc406Sopenharmony_ci DBG (5, "sane_read: pipe was closed ... calling do_stop\n"); 6663141cc406Sopenharmony_ci status = do_stop (s); 6664141cc406Sopenharmony_ci if (status != SANE_STATUS_CANCELLED 6665141cc406Sopenharmony_ci && status != SANE_STATUS_GOOD) 6666141cc406Sopenharmony_ci return status; /* something went wrong */ 6667141cc406Sopenharmony_ci } 6668141cc406Sopenharmony_ci else /* 3pass color first or second pass */ 6669141cc406Sopenharmony_ci { 6670141cc406Sopenharmony_ci DBG (5, 6671141cc406Sopenharmony_ci "sane_read: pipe was closed ... finishing pass %d\n", 6672141cc406Sopenharmony_ci s->pass); 6673141cc406Sopenharmony_ci } 6674141cc406Sopenharmony_ci 6675141cc406Sopenharmony_ci return do_eof (s); 6676141cc406Sopenharmony_ci } 6677141cc406Sopenharmony_ci else 6678141cc406Sopenharmony_ci { 6679141cc406Sopenharmony_ci DBG (5, "sane_read: read last buffer of %d bytes " 6680141cc406Sopenharmony_ci "(%d bytes total)\n", *len, s->total_bytes); 6681141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6682141cc406Sopenharmony_ci } 6683141cc406Sopenharmony_ci } 6684141cc406Sopenharmony_ci } 6685141cc406Sopenharmony_ci DBG (5, "sane_read: read full buffer of %d bytes (%d total bytes)\n", 6686141cc406Sopenharmony_ci *len, s->total_bytes); 6687141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6688141cc406Sopenharmony_ci} 6689141cc406Sopenharmony_ci 6690141cc406Sopenharmony_civoid 6691141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 6692141cc406Sopenharmony_ci{ 6693141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6694141cc406Sopenharmony_ci 6695141cc406Sopenharmony_ci if (!s) 6696141cc406Sopenharmony_ci { 6697141cc406Sopenharmony_ci DBG (1, "sane_cancel: handle is null!\n"); 6698141cc406Sopenharmony_ci return; 6699141cc406Sopenharmony_ci } 6700141cc406Sopenharmony_ci 6701141cc406Sopenharmony_ci DBG (4, "sane_cancel\n"); 6702141cc406Sopenharmony_ci if (s->scanning) 6703141cc406Sopenharmony_ci { 6704141cc406Sopenharmony_ci s->cancelled = SANE_TRUE; 6705141cc406Sopenharmony_ci do_stop (handle); 6706141cc406Sopenharmony_ci } 6707141cc406Sopenharmony_ci DBG (5, "sane_cancel: finished\n"); 6708141cc406Sopenharmony_ci} 6709141cc406Sopenharmony_ci 6710141cc406Sopenharmony_ciSANE_Status 6711141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 6712141cc406Sopenharmony_ci{ 6713141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6714141cc406Sopenharmony_ci 6715141cc406Sopenharmony_ci if (!s) 6716141cc406Sopenharmony_ci { 6717141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode: handle is null!\n"); 6718141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6719141cc406Sopenharmony_ci } 6720141cc406Sopenharmony_ci 6721141cc406Sopenharmony_ci DBG (4, "sane_set_io_mode: %s\n", 6722141cc406Sopenharmony_ci non_blocking ? "non-blocking" : "blocking"); 6723141cc406Sopenharmony_ci 6724141cc406Sopenharmony_ci if (!s->scanning) 6725141cc406Sopenharmony_ci { 6726141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode: call sane_start before sane_set_io_mode"); 6727141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6728141cc406Sopenharmony_ci } 6729141cc406Sopenharmony_ci 6730141cc406Sopenharmony_ci if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) 6731141cc406Sopenharmony_ci { 6732141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode: can't set io mode"); 6733141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 6734141cc406Sopenharmony_ci } 6735141cc406Sopenharmony_ci 6736141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6737141cc406Sopenharmony_ci} 6738141cc406Sopenharmony_ci 6739141cc406Sopenharmony_ciSANE_Status 6740141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 6741141cc406Sopenharmony_ci{ 6742141cc406Sopenharmony_ci Mustek_Scanner *s = handle; 6743141cc406Sopenharmony_ci 6744141cc406Sopenharmony_ci if (!s) 6745141cc406Sopenharmony_ci { 6746141cc406Sopenharmony_ci DBG (1, "sane_get_select_fd: handle is null!\n"); 6747141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6748141cc406Sopenharmony_ci } 6749141cc406Sopenharmony_ci if (!fd) 6750141cc406Sopenharmony_ci { 6751141cc406Sopenharmony_ci DBG (1, "sane_get_select_fd: fd is null!\n"); 6752141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6753141cc406Sopenharmony_ci } 6754141cc406Sopenharmony_ci 6755141cc406Sopenharmony_ci DBG (4, "sane_get_select_fd\n"); 6756141cc406Sopenharmony_ci if (!s->scanning) 6757141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 6758141cc406Sopenharmony_ci 6759141cc406Sopenharmony_ci *fd = s->pipe; 6760141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 6761141cc406Sopenharmony_ci} 6762141cc406Sopenharmony_ci 6763141cc406Sopenharmony_ci#include "mustek_scsi_pp.c" 6764