1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci This file implements a SANE backend for the Fujitsu fi-60F, the 4141cc406Sopenharmony_ci ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci Copyright 2007-2022 by m. allan noah <kitno455 at gmail dot com> 7141cc406Sopenharmony_ci Copyright 2009 by Richard Goedeken <richard at fascinationsoftware dot com> 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci Development funded by Microdea, Inc., TrueCheck, Inc. and Archivista, GmbH 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci -------------------------------------------------------------------------- 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 14141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 15141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 16141cc406Sopenharmony_ci License, or (at your option) any later version. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 19141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 20141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21141cc406Sopenharmony_ci General Public License for more details. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 24141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 25141cc406Sopenharmony_ci 26141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 27141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 30141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 31141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 32141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 33141cc406Sopenharmony_ci account of linking the SANE library code into it. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 36141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 37141cc406Sopenharmony_ci License. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 40141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 41141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 44141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 45141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci -------------------------------------------------------------------------- 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci The source code is divided in sections which you can easily find by 50141cc406Sopenharmony_ci searching for the tag "@@". 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci Section 1 - Init & static stuff 53141cc406Sopenharmony_ci Section 2 - sane_init, _get_devices, _open & friends 54141cc406Sopenharmony_ci Section 3 - sane_*_option functions 55141cc406Sopenharmony_ci Section 4 - sane_start, _get_param, _read & friends 56141cc406Sopenharmony_ci Section 5 - sane_close functions 57141cc406Sopenharmony_ci Section 6 - misc functions 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci Changes: 60141cc406Sopenharmony_ci v0, 2007-08-08, MAN 61141cc406Sopenharmony_ci - initial alpha release, S300 raw data only 62141cc406Sopenharmony_ci v1, 2007-09-03, MAN 63141cc406Sopenharmony_ci - only supports 300dpi duplex binary for S300 64141cc406Sopenharmony_ci v2, 2007-09-05, MAN 65141cc406Sopenharmony_ci - add resolution option (only one choice) 66141cc406Sopenharmony_ci - add simplex option 67141cc406Sopenharmony_ci v3, 2007-09-12, MAN 68141cc406Sopenharmony_ci - add support for 150 dpi resolution 69141cc406Sopenharmony_ci v4, 2007-10-03, MAN 70141cc406Sopenharmony_ci - change binarization algo to use average of all channels 71141cc406Sopenharmony_ci v5, 2007-10-10, MAN 72141cc406Sopenharmony_ci - move data blocks to separate file 73141cc406Sopenharmony_ci - add basic fi-60F support (600dpi color) 74141cc406Sopenharmony_ci v6, 2007-11-12, MAN 75141cc406Sopenharmony_ci - move various data vars into transfer structs 76141cc406Sopenharmony_ci - move most of read_from_scanner to sane_read 77141cc406Sopenharmony_ci - add single line reads to calibration code 78141cc406Sopenharmony_ci - generate calibration buffer from above reads 79141cc406Sopenharmony_ci v7, 2007-12-05, MAN 80141cc406Sopenharmony_ci - split calibration into fine and coarse functions 81141cc406Sopenharmony_ci - add S300 fine calibration code 82141cc406Sopenharmony_ci - add S300 color and grayscale support 83141cc406Sopenharmony_ci v8, 2007-12-06, MAN 84141cc406Sopenharmony_ci - change sane_start to call ingest earlier 85141cc406Sopenharmony_ci - enable SOURCE_ADF_BACK 86141cc406Sopenharmony_ci - add if() around memcopy and better debugs in sane_read 87141cc406Sopenharmony_ci - shorten default scan sizes from 15.4 to 11.75 inches 88141cc406Sopenharmony_ci v9, 2007-12-17, MAN 89141cc406Sopenharmony_ci - fi-60F 300 & 600 dpi support (150 is non-square?) 90141cc406Sopenharmony_ci - fi-60F gray & binary support 91141cc406Sopenharmony_ci - fi-60F improved calibration 92141cc406Sopenharmony_ci v10, 2007-12-19, MAN (SANE v1.0.19) 93141cc406Sopenharmony_ci - fix missing function (and memory leak) 94141cc406Sopenharmony_ci v11 2008-02-14, MAN 95141cc406Sopenharmony_ci - sanei_config_read has already cleaned string (#310597) 96141cc406Sopenharmony_ci v12 2008-02-28, MAN 97141cc406Sopenharmony_ci - cleanup double free bug with new destroy() 98141cc406Sopenharmony_ci v13 2008-09-18, MAN 99141cc406Sopenharmony_ci - add working page-height control 100141cc406Sopenharmony_ci - add working brightness, contrast and threshold controls 101141cc406Sopenharmony_ci - add disabled threshold curve and geometry controls 102141cc406Sopenharmony_ci - move initialization code to sane_get_devices, for hotplugging 103141cc406Sopenharmony_ci v14 2008-09-24, MAN 104141cc406Sopenharmony_ci - support S300 on USB power 105141cc406Sopenharmony_ci - support S300 225x200 and 600x600 scans 106141cc406Sopenharmony_ci - support for automatic paper length detection (parm.lines = -1) 107141cc406Sopenharmony_ci v15 2008-09-24, MAN 108141cc406Sopenharmony_ci - expose hardware buttons/sensors as options for S300 109141cc406Sopenharmony_ci v16 2008-10-01, MAN 110141cc406Sopenharmony_ci - split fill_frontback_buffers_S300 into 3 functions 111141cc406Sopenharmony_ci - enable threshold_curve option 112141cc406Sopenharmony_ci - add 1-D dynamic binary thresholding code 113141cc406Sopenharmony_ci - remove y-resolution option 114141cc406Sopenharmony_ci - pad 225x200 data to 225x225 115141cc406Sopenharmony_ci v17 2008-10-03, MAN 116141cc406Sopenharmony_ci - increase scan height ~1/2 inch due to head offset 117141cc406Sopenharmony_ci - change page length autodetection condition 118141cc406Sopenharmony_ci v18 2009-01-21, MAN 119141cc406Sopenharmony_ci - don't export private symbols 120141cc406Sopenharmony_ci v19 2009-08-31, RG 121141cc406Sopenharmony_ci - rewritten calibration routines 122141cc406Sopenharmony_ci v20 2010-02-09, MAN (SANE 1.0.21 to 1.0.24) 123141cc406Sopenharmony_ci - cleanup #include lines & copyright 124141cc406Sopenharmony_ci - add S1300 125141cc406Sopenharmony_ci v21 2011-04-15, MAN 126141cc406Sopenharmony_ci - unreleased attempt at S1100 support 127141cc406Sopenharmony_ci v22 2014-05-15, MAN/Hiroshi Miura 128141cc406Sopenharmony_ci - port some S1100 changes from v21 129141cc406Sopenharmony_ci - add paper size support 130141cc406Sopenharmony_ci v23 2014-05-20, MAN 131141cc406Sopenharmony_ci - add S1300i support 132141cc406Sopenharmony_ci - fix buffer overruns in read_from_scanner 133141cc406Sopenharmony_ci - set default page width 134141cc406Sopenharmony_ci - simplified the 225x200 resolution code 135141cc406Sopenharmony_ci v24 2014-06-01, MAN 136141cc406Sopenharmony_ci - enable fine calibration for S1300i 225 & 300 dpi, and S300 150 dpi 137141cc406Sopenharmony_ci v25 2014-06-04, MAN 138141cc406Sopenharmony_ci - initial support for fi-65F 139141cc406Sopenharmony_ci - initial support for S1100 140141cc406Sopenharmony_ci v26 2014-06-28, MAN 141141cc406Sopenharmony_ci - add resolution scaling 142141cc406Sopenharmony_ci - fix 150 dpi settings for fi-60F and fi-65F 143141cc406Sopenharmony_ci - make adf_height_padding variable 144141cc406Sopenharmony_ci - make white_factor variable 145141cc406Sopenharmony_ci v27 2015-01-24, MAN 146141cc406Sopenharmony_ci - don't override br_x and br_y 147141cc406Sopenharmony_ci - call change_params after changing page_width 148141cc406Sopenharmony_ci v28 2015-03-23, MAN 149141cc406Sopenharmony_ci - call get_hardware_status before starting scan 150141cc406Sopenharmony_ci v29 2017-03-18, MAN 151141cc406Sopenharmony_ci - fix infinite loop when scaling in Y direction 152141cc406Sopenharmony_ci v30 2017-03-21, MAN 153141cc406Sopenharmony_ci - fix image truncation when using 150 DPI in Y direction 154141cc406Sopenharmony_ci - add 200 and 400 DPI Y direction support for fi-60F/65F 155141cc406Sopenharmony_ci v31 2017-04-09, MAN 156141cc406Sopenharmony_ci - hardware gray support for fi-60F/65F (disabled pending calibration) 157141cc406Sopenharmony_ci - merge fi-60F/65F settings 158141cc406Sopenharmony_ci v32 2022-11-15, MAN 159141cc406Sopenharmony_ci - fix hanging scan when using source = ADF Back (fixes #601) 160141cc406Sopenharmony_ci v33 2022-11-17, MAN 161141cc406Sopenharmony_ci - S1300i: fix color plane offset at 225 and 330 dpi (fixes #538) 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_ci SANE FLOW DIAGRAM 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci - sane_init() : initialize backend 166141cc406Sopenharmony_ci . - sane_get_devices() : query list of scanner devices 167141cc406Sopenharmony_ci . - sane_open() : open a particular scanner device 168141cc406Sopenharmony_ci . . - sane_set_io_mode : set blocking mode 169141cc406Sopenharmony_ci . . - sane_get_select_fd : get scanner fd 170141cc406Sopenharmony_ci . . 171141cc406Sopenharmony_ci . . - sane_get_option_descriptor() : get option information 172141cc406Sopenharmony_ci . . - sane_control_option() : change option values 173141cc406Sopenharmony_ci . . - sane_get_parameters() : returns estimated scan parameters 174141cc406Sopenharmony_ci . . - (repeat previous 3 functions) 175141cc406Sopenharmony_ci . . 176141cc406Sopenharmony_ci . . - sane_start() : start image acquisition 177141cc406Sopenharmony_ci . . - sane_get_parameters() : returns actual scan parameters 178141cc406Sopenharmony_ci . . - sane_read() : read image data (from pipe) 179141cc406Sopenharmony_ci . . (sane_read called multiple times; after sane_read returns EOF, 180141cc406Sopenharmony_ci . . loop may continue with sane_start which may return a 2nd page 181141cc406Sopenharmony_ci . . when doing duplex scans, or load the next page from the ADF) 182141cc406Sopenharmony_ci . . 183141cc406Sopenharmony_ci . . - sane_cancel() : cancel operation 184141cc406Sopenharmony_ci . - sane_close() : close opened scanner device 185141cc406Sopenharmony_ci - sane_exit() : terminate use of backend 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_ci*/ 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_ci/* 190141cc406Sopenharmony_ci * @@ Section 1 - Init 191141cc406Sopenharmony_ci */ 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_ci#include "../include/sane/config.h" 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci#include <string.h> /*memcpy...*/ 196141cc406Sopenharmony_ci#include <ctype.h> /*isspace*/ 197141cc406Sopenharmony_ci#include <math.h> /*tan*/ 198141cc406Sopenharmony_ci#include <unistd.h> /*usleep*/ 199141cc406Sopenharmony_ci#include <time.h> /*time*/ 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 202141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 203141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 204141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci#include "epjitsu.h" 207141cc406Sopenharmony_ci#include "epjitsu-cmd.h" 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci#define DEBUG 1 210141cc406Sopenharmony_ci#define BUILD 33 211141cc406Sopenharmony_ci 212141cc406Sopenharmony_ci#ifndef MIN 213141cc406Sopenharmony_ci #define MIN(a,b) ((a) < (b) ? (a) : (b)) 214141cc406Sopenharmony_ci#endif 215141cc406Sopenharmony_ci#ifndef MAX 216141cc406Sopenharmony_ci #define MAX(a,b) ((a) > (b) ? (a) : (b)) 217141cc406Sopenharmony_ci#endif 218141cc406Sopenharmony_ci#ifndef MAX3 219141cc406Sopenharmony_ci #define MAX3(a,b,c) ((a) > (b) ? ((a) > (c) ? a : c) : ((b) > (c) ? b : c)) 220141cc406Sopenharmony_ci#endif 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ciunsigned char global_firmware_filename[PATH_MAX]; 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_ci/* values for SANE_DEBUG_EPJITSU env var: 225141cc406Sopenharmony_ci - errors 5 226141cc406Sopenharmony_ci - function trace 10 227141cc406Sopenharmony_ci - function detail 15 228141cc406Sopenharmony_ci - get/setopt cmds 20 229141cc406Sopenharmony_ci - usb cmd trace 25 230141cc406Sopenharmony_ci - usb cmd detail 30 231141cc406Sopenharmony_ci - useless noise 35 232141cc406Sopenharmony_ci*/ 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci/* Calibration settings */ 235141cc406Sopenharmony_ci#define COARSE_OFFSET_TARGET 15 236141cc406Sopenharmony_cistatic int coarse_gain_min[3] = { 88, 88, 88 }; /* front, back, FI-60F 3rd plane */ 237141cc406Sopenharmony_cistatic int coarse_gain_max[3] = { 92, 92, 92 }; 238141cc406Sopenharmony_cistatic int fine_gain_target[3] = {185, 150, 170}; /* front, back, FI-60F is this ok? */ 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */ 241141cc406Sopenharmony_ci#define STRING_FLATBED SANE_I18N("Flatbed") 242141cc406Sopenharmony_ci#define STRING_ADFFRONT SANE_I18N("ADF Front") 243141cc406Sopenharmony_ci#define STRING_ADFBACK SANE_I18N("ADF Back") 244141cc406Sopenharmony_ci#define STRING_ADFDUPLEX SANE_I18N("ADF Duplex") 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_ci#define STRING_LINEART SANE_VALUE_SCAN_MODE_LINEART 247141cc406Sopenharmony_ci#define STRING_GRAYSCALE SANE_VALUE_SCAN_MODE_GRAY 248141cc406Sopenharmony_ci#define STRING_COLOR SANE_VALUE_SCAN_MODE_COLOR 249141cc406Sopenharmony_ci 250141cc406Sopenharmony_ci/* 251141cc406Sopenharmony_ci * used by attach* and sane_get_devices 252141cc406Sopenharmony_ci * a ptr to a null term array of ptrs to SANE_Device structs 253141cc406Sopenharmony_ci * a ptr to a single-linked list of scanner structs 254141cc406Sopenharmony_ci */ 255141cc406Sopenharmony_cistatic const SANE_Device **sane_devArray = NULL; 256141cc406Sopenharmony_cistatic struct scanner *scanner_devList = NULL; 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci/* 259141cc406Sopenharmony_ci * @@ Section 2 - SANE & scanner init code 260141cc406Sopenharmony_ci */ 261141cc406Sopenharmony_ci 262141cc406Sopenharmony_ci/* 263141cc406Sopenharmony_ci * Called by SANE initially. 264141cc406Sopenharmony_ci * 265141cc406Sopenharmony_ci * From the SANE spec: 266141cc406Sopenharmony_ci * This function must be called before any other SANE function can be 267141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this 268141cc406Sopenharmony_ci * function is not called first. The version code of the backend is 269141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer 270141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either 271141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires 272141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does 273141cc406Sopenharmony_ci * not support authentication. 274141cc406Sopenharmony_ci */ 275141cc406Sopenharmony_ciSANE_Status 276141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 277141cc406Sopenharmony_ci{ 278141cc406Sopenharmony_ci (void) authorize; /* get rid of compiler warning */ 279141cc406Sopenharmony_ci 280141cc406Sopenharmony_ci DBG_INIT (); 281141cc406Sopenharmony_ci DBG (10, "sane_init: start\n"); 282141cc406Sopenharmony_ci 283141cc406Sopenharmony_ci if (version_code) 284141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci DBG (5, "sane_init: epjitsu backend %d.%d.%d, from %s\n", 287141cc406Sopenharmony_ci SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING); 288141cc406Sopenharmony_ci 289141cc406Sopenharmony_ci DBG (10, "sane_init: finish\n"); 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 292141cc406Sopenharmony_ci} 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ci/* 295141cc406Sopenharmony_ci * Called by SANE to find out about supported devices. 296141cc406Sopenharmony_ci * 297141cc406Sopenharmony_ci * From the SANE spec: 298141cc406Sopenharmony_ci * This function can be used to query the list of devices that are 299141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a 300141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device 301141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to 302141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function 303141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This 304141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become 305141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are 306141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is 307141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote 308141cc406Sopenharmony_ci * devices that are accessible to the SANE library. 309141cc406Sopenharmony_ci * 310141cc406Sopenharmony_ci * SANE does not require that this function is called before a 311141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified 312141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and 313141cc406Sopenharmony_ci * undesirable to call this function first. 314141cc406Sopenharmony_ci * 315141cc406Sopenharmony_ci * Read the config file, find scanners with help from sanei_* 316141cc406Sopenharmony_ci * store in global device structs 317141cc406Sopenharmony_ci */ 318141cc406Sopenharmony_ciSANE_Status 319141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 320141cc406Sopenharmony_ci{ 321141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 322141cc406Sopenharmony_ci struct scanner * s; 323141cc406Sopenharmony_ci struct scanner * prev = NULL; 324141cc406Sopenharmony_ci char line[PATH_MAX]; 325141cc406Sopenharmony_ci const char *lp; 326141cc406Sopenharmony_ci FILE *fp; 327141cc406Sopenharmony_ci int num_devices=0; 328141cc406Sopenharmony_ci int i=0; 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci (void) local_only; /* get rid of compiler warning */ 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci DBG (10, "sane_get_devices: start\n"); 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci /* mark all existing scanners as missing, attach_one will remove mark */ 335141cc406Sopenharmony_ci for (s = scanner_devList; s; s = s->next) { 336141cc406Sopenharmony_ci s->missing = 1; 337141cc406Sopenharmony_ci } 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci sanei_usb_init(); 340141cc406Sopenharmony_ci 341141cc406Sopenharmony_ci fp = sanei_config_open (CONFIG_FILE); 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci if (fp) { 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci DBG (15, "sane_get_devices: reading config file %s\n", CONFIG_FILE); 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci while (sanei_config_read (line, PATH_MAX, fp)) { 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci lp = line; 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci /* ignore comments */ 352141cc406Sopenharmony_ci if (*lp == '#') 353141cc406Sopenharmony_ci continue; 354141cc406Sopenharmony_ci 355141cc406Sopenharmony_ci /* skip empty lines */ 356141cc406Sopenharmony_ci if (*lp == 0) 357141cc406Sopenharmony_ci continue; 358141cc406Sopenharmony_ci 359141cc406Sopenharmony_ci if ((strncmp ("firmware", lp, 8) == 0) && isspace (lp[8])) { 360141cc406Sopenharmony_ci size_t firmware_len; 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci lp += 8; 363141cc406Sopenharmony_ci lp = sanei_config_skip_whitespace (lp); 364141cc406Sopenharmony_ci DBG (15, "sane_get_devices: firmware '%s'\n", lp); 365141cc406Sopenharmony_ci 366141cc406Sopenharmony_ci firmware_len = strlen(lp); 367141cc406Sopenharmony_ci if (firmware_len > sizeof(global_firmware_filename) - 1) 368141cc406Sopenharmony_ci { 369141cc406Sopenharmony_ci DBG (5, "sane_get_devices: firmware file too long. ignoring '%s'\n", lp); 370141cc406Sopenharmony_ci } 371141cc406Sopenharmony_ci else 372141cc406Sopenharmony_ci { 373141cc406Sopenharmony_ci strcpy((char *)global_firmware_filename, lp); 374141cc406Sopenharmony_ci } 375141cc406Sopenharmony_ci } 376141cc406Sopenharmony_ci else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { 377141cc406Sopenharmony_ci DBG (15, "sane_get_devices: looking for '%s'\n", lp); 378141cc406Sopenharmony_ci sanei_usb_attach_matching_devices(lp, attach_one); 379141cc406Sopenharmony_ci } 380141cc406Sopenharmony_ci else{ 381141cc406Sopenharmony_ci DBG (5, "sane_get_devices: config line \"%s\" ignored.\n", lp); 382141cc406Sopenharmony_ci } 383141cc406Sopenharmony_ci } 384141cc406Sopenharmony_ci fclose (fp); 385141cc406Sopenharmony_ci } 386141cc406Sopenharmony_ci 387141cc406Sopenharmony_ci else { 388141cc406Sopenharmony_ci DBG (5, "sane_get_devices: no config file '%s'!\n", 389141cc406Sopenharmony_ci CONFIG_FILE); 390141cc406Sopenharmony_ci } 391141cc406Sopenharmony_ci 392141cc406Sopenharmony_ci /*delete missing scanners from list*/ 393141cc406Sopenharmony_ci for (s = scanner_devList; s;) { 394141cc406Sopenharmony_ci if(s->missing){ 395141cc406Sopenharmony_ci DBG (5, "sane_get_devices: missing scanner %s\n",s->sane.name); 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci /*splice s out of list by changing pointer in prev to next*/ 398141cc406Sopenharmony_ci if(prev){ 399141cc406Sopenharmony_ci prev->next = s->next; 400141cc406Sopenharmony_ci free(s); 401141cc406Sopenharmony_ci s=prev->next; 402141cc406Sopenharmony_ci } 403141cc406Sopenharmony_ci /*remove s from head of list, using prev to cache it*/ 404141cc406Sopenharmony_ci else{ 405141cc406Sopenharmony_ci prev = s; 406141cc406Sopenharmony_ci s = s->next; 407141cc406Sopenharmony_ci free(prev); 408141cc406Sopenharmony_ci prev=NULL; 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci /*reset head to next s*/ 411141cc406Sopenharmony_ci scanner_devList = s; 412141cc406Sopenharmony_ci } 413141cc406Sopenharmony_ci } 414141cc406Sopenharmony_ci else{ 415141cc406Sopenharmony_ci prev = s; 416141cc406Sopenharmony_ci s=prev->next; 417141cc406Sopenharmony_ci } 418141cc406Sopenharmony_ci } 419141cc406Sopenharmony_ci 420141cc406Sopenharmony_ci for (s = scanner_devList; s; s=s->next) { 421141cc406Sopenharmony_ci DBG (15, "sane_get_devices: found scanner %s\n",s->sane.name); 422141cc406Sopenharmony_ci num_devices++; 423141cc406Sopenharmony_ci } 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci DBG (15, "sane_get_devices: found %d scanner(s)\n",num_devices); 426141cc406Sopenharmony_ci 427141cc406Sopenharmony_ci if (sane_devArray) 428141cc406Sopenharmony_ci free (sane_devArray); 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci sane_devArray = calloc (num_devices + 1, sizeof (SANE_Device*)); 431141cc406Sopenharmony_ci if (!sane_devArray) 432141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci for (s = scanner_devList; s; s=s->next) { 435141cc406Sopenharmony_ci sane_devArray[i++] = (SANE_Device *)&s->sane; 436141cc406Sopenharmony_ci } 437141cc406Sopenharmony_ci sane_devArray[i] = 0; 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci if(device_list){ 440141cc406Sopenharmony_ci *device_list = sane_devArray; 441141cc406Sopenharmony_ci } 442141cc406Sopenharmony_ci 443141cc406Sopenharmony_ci DBG (10, "sane_get_devices: finish\n"); 444141cc406Sopenharmony_ci 445141cc406Sopenharmony_ci return ret; 446141cc406Sopenharmony_ci} 447141cc406Sopenharmony_ci 448141cc406Sopenharmony_ci/* callback used by sane_init 449141cc406Sopenharmony_ci * build the scanner struct and link to global list 450141cc406Sopenharmony_ci * unless struct is already loaded, then pretend 451141cc406Sopenharmony_ci */ 452141cc406Sopenharmony_cistatic SANE_Status 453141cc406Sopenharmony_ciattach_one (const char *name) 454141cc406Sopenharmony_ci{ 455141cc406Sopenharmony_ci struct scanner *s; 456141cc406Sopenharmony_ci int ret, i; 457141cc406Sopenharmony_ci 458141cc406Sopenharmony_ci DBG (10, "attach_one: start '%s'\n", name); 459141cc406Sopenharmony_ci 460141cc406Sopenharmony_ci for (s = scanner_devList; s; s = s->next) { 461141cc406Sopenharmony_ci if (strcmp (s->sane.name, name) == 0) { 462141cc406Sopenharmony_ci DBG (10, "attach_one: already attached!\n"); 463141cc406Sopenharmony_ci s->missing = 0; 464141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 465141cc406Sopenharmony_ci } 466141cc406Sopenharmony_ci } 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_ci /* build a scanner struct to hold it */ 469141cc406Sopenharmony_ci DBG (15, "attach_one: init struct\n"); 470141cc406Sopenharmony_ci 471141cc406Sopenharmony_ci if ((s = calloc (sizeof (*s), 1)) == NULL) 472141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 473141cc406Sopenharmony_ci 474141cc406Sopenharmony_ci /* copy the device name */ 475141cc406Sopenharmony_ci s->sane.name = strdup (name); 476141cc406Sopenharmony_ci if (!s->sane.name){ 477141cc406Sopenharmony_ci destroy(s); 478141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 479141cc406Sopenharmony_ci } 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci /* connect the fd */ 482141cc406Sopenharmony_ci DBG (15, "attach_one: connect fd\n"); 483141cc406Sopenharmony_ci 484141cc406Sopenharmony_ci s->fd = -1; 485141cc406Sopenharmony_ci ret = connect_fd(s); 486141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 487141cc406Sopenharmony_ci destroy(s); 488141cc406Sopenharmony_ci return ret; 489141cc406Sopenharmony_ci } 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ci /* load the firmware file into scanner */ 492141cc406Sopenharmony_ci ret = load_fw(s); 493141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 494141cc406Sopenharmony_ci destroy(s); 495141cc406Sopenharmony_ci DBG (5, "attach_one: firmware load failed\n"); 496141cc406Sopenharmony_ci return ret; 497141cc406Sopenharmony_ci } 498141cc406Sopenharmony_ci 499141cc406Sopenharmony_ci /* Now query the device to load its vendor/model/version */ 500141cc406Sopenharmony_ci ret = get_ident(s); 501141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 502141cc406Sopenharmony_ci destroy(s); 503141cc406Sopenharmony_ci DBG (5, "attach_one: identify failed\n"); 504141cc406Sopenharmony_ci return ret; 505141cc406Sopenharmony_ci } 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci DBG (15, "attach_one: Found %s scanner %s at %s\n", 508141cc406Sopenharmony_ci s->sane.vendor, s->sane.model, s->sane.name); 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci if (strstr (s->sane.model, "S1300i")){ 511141cc406Sopenharmony_ci unsigned char stat; 512141cc406Sopenharmony_ci 513141cc406Sopenharmony_ci DBG (15, "attach_one: Found S1300i\n"); 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci stat = get_stat(s); 516141cc406Sopenharmony_ci if(stat & 0x01){ 517141cc406Sopenharmony_ci DBG (5, "attach_one: on USB power?\n"); 518141cc406Sopenharmony_ci s->usb_power=1; 519141cc406Sopenharmony_ci } 520141cc406Sopenharmony_ci 521141cc406Sopenharmony_ci s->model = MODEL_S1300i; 522141cc406Sopenharmony_ci 523141cc406Sopenharmony_ci s->has_adf = 1; 524141cc406Sopenharmony_ci s->has_adf_duplex = 1; 525141cc406Sopenharmony_ci s->min_res = 50; 526141cc406Sopenharmony_ci s->max_res = 600; 527141cc406Sopenharmony_ci s->adf_height_padding = 600; 528141cc406Sopenharmony_ci /* Blue, Red, Green */ 529141cc406Sopenharmony_ci s->white_factor[0] = 1.0; 530141cc406Sopenharmony_ci s->white_factor[1] = 0.93; 531141cc406Sopenharmony_ci s->white_factor[2] = 0.98; 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci s->source = SOURCE_ADF_FRONT; 534141cc406Sopenharmony_ci s->mode = MODE_LINEART; 535141cc406Sopenharmony_ci s->resolution = 300; 536141cc406Sopenharmony_ci s->page_height = 11.5 * 1200; 537141cc406Sopenharmony_ci s->page_width = 8.5 * 1200; 538141cc406Sopenharmony_ci 539141cc406Sopenharmony_ci s->threshold = 120; 540141cc406Sopenharmony_ci s->threshold_curve = 55; 541141cc406Sopenharmony_ci } 542141cc406Sopenharmony_ci else if (strstr (s->sane.model, "S300") || strstr (s->sane.model, "S1300")){ 543141cc406Sopenharmony_ci unsigned char stat; 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci DBG (15, "attach_one: Found S300/S1300\n"); 546141cc406Sopenharmony_ci 547141cc406Sopenharmony_ci stat = get_stat(s); 548141cc406Sopenharmony_ci if(stat & 0x01){ 549141cc406Sopenharmony_ci DBG (5, "attach_one: on USB power?\n"); 550141cc406Sopenharmony_ci s->usb_power=1; 551141cc406Sopenharmony_ci } 552141cc406Sopenharmony_ci 553141cc406Sopenharmony_ci s->model = MODEL_S300; 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci s->has_adf = 1; 556141cc406Sopenharmony_ci s->has_adf_duplex = 1; 557141cc406Sopenharmony_ci s->min_res = 50; 558141cc406Sopenharmony_ci s->max_res = 600; 559141cc406Sopenharmony_ci s->adf_height_padding = 600; 560141cc406Sopenharmony_ci /* Blue, Red, Green */ 561141cc406Sopenharmony_ci s->white_factor[0] = 1.0; 562141cc406Sopenharmony_ci s->white_factor[1] = 0.93; 563141cc406Sopenharmony_ci s->white_factor[2] = 0.98; 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci s->source = SOURCE_ADF_FRONT; 566141cc406Sopenharmony_ci s->mode = MODE_LINEART; 567141cc406Sopenharmony_ci s->resolution = 300; 568141cc406Sopenharmony_ci s->page_height = 11.5 * 1200; 569141cc406Sopenharmony_ci s->page_width = 8.5 * 1200; 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci s->threshold = 120; 572141cc406Sopenharmony_ci s->threshold_curve = 55; 573141cc406Sopenharmony_ci } 574141cc406Sopenharmony_ci else if (strstr (s->sane.model, "S1100")){ 575141cc406Sopenharmony_ci DBG (15, "attach_one: Found S1100\n"); 576141cc406Sopenharmony_ci s->model = MODEL_S1100; 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci s->usb_power = 1; 579141cc406Sopenharmony_ci s->has_adf = 1; 580141cc406Sopenharmony_ci s->has_adf_duplex = 0; 581141cc406Sopenharmony_ci s->min_res = 50; 582141cc406Sopenharmony_ci s->max_res = 600; 583141cc406Sopenharmony_ci s->adf_height_padding = 450; 584141cc406Sopenharmony_ci /* Blue, Red, Green */ 585141cc406Sopenharmony_ci s->white_factor[0] = 0.95; 586141cc406Sopenharmony_ci s->white_factor[1] = 1.0; 587141cc406Sopenharmony_ci s->white_factor[2] = 1.0; 588141cc406Sopenharmony_ci 589141cc406Sopenharmony_ci s->source = SOURCE_ADF_FRONT; 590141cc406Sopenharmony_ci s->mode = MODE_LINEART; 591141cc406Sopenharmony_ci s->resolution = 300; 592141cc406Sopenharmony_ci s->page_height = 11.5 * 1200; 593141cc406Sopenharmony_ci s->page_width = 8.5 * 1200; 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_ci s->threshold = 120; 596141cc406Sopenharmony_ci s->threshold_curve = 55; 597141cc406Sopenharmony_ci } 598141cc406Sopenharmony_ci else if (strstr (s->sane.model, "fi-60F")){ 599141cc406Sopenharmony_ci DBG (15, "attach_one: Found fi-60F\n"); 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_ci s->model = MODEL_FI60F; 602141cc406Sopenharmony_ci 603141cc406Sopenharmony_ci s->has_fb = 1; 604141cc406Sopenharmony_ci s->min_res = 50; 605141cc406Sopenharmony_ci s->max_res = 600; 606141cc406Sopenharmony_ci /* Blue, Red, Green */ 607141cc406Sopenharmony_ci s->white_factor[0] = 1.0; 608141cc406Sopenharmony_ci s->white_factor[1] = 0.93; 609141cc406Sopenharmony_ci s->white_factor[2] = 0.98; 610141cc406Sopenharmony_ci 611141cc406Sopenharmony_ci s->source = SOURCE_FLATBED; 612141cc406Sopenharmony_ci s->mode = MODE_COLOR; 613141cc406Sopenharmony_ci s->resolution = 300; 614141cc406Sopenharmony_ci s->page_height = 5.83 * 1200; 615141cc406Sopenharmony_ci s->page_width = 4.1 * 1200; 616141cc406Sopenharmony_ci 617141cc406Sopenharmony_ci s->threshold = 120; 618141cc406Sopenharmony_ci s->threshold_curve = 55; 619141cc406Sopenharmony_ci } 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci else if (strstr (s->sane.model, "fi-65F")){ 622141cc406Sopenharmony_ci DBG (15, "attach_one: Found fi-65F\n"); 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci s->model = MODEL_FI65F; 625141cc406Sopenharmony_ci 626141cc406Sopenharmony_ci s->has_fb = 1; 627141cc406Sopenharmony_ci s->min_res = 50; 628141cc406Sopenharmony_ci s->max_res = 600; 629141cc406Sopenharmony_ci /* Blue, Red, Green */ 630141cc406Sopenharmony_ci s->white_factor[0] = 1.0; 631141cc406Sopenharmony_ci s->white_factor[1] = 0.93; 632141cc406Sopenharmony_ci s->white_factor[2] = 0.98; 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_ci s->source = SOURCE_FLATBED; 635141cc406Sopenharmony_ci s->mode = MODE_COLOR; 636141cc406Sopenharmony_ci s->resolution = 300; 637141cc406Sopenharmony_ci s->page_height = 5.83 * 1200; 638141cc406Sopenharmony_ci s->page_width = 4.1 * 1200; 639141cc406Sopenharmony_ci 640141cc406Sopenharmony_ci s->threshold = 120; 641141cc406Sopenharmony_ci s->threshold_curve = 55; 642141cc406Sopenharmony_ci } 643141cc406Sopenharmony_ci else{ 644141cc406Sopenharmony_ci DBG (15, "attach_one: Found other\n"); 645141cc406Sopenharmony_ci } 646141cc406Sopenharmony_ci 647141cc406Sopenharmony_ci /* set SANE option 'values' to good defaults */ 648141cc406Sopenharmony_ci DBG (15, "attach_one: init options\n"); 649141cc406Sopenharmony_ci 650141cc406Sopenharmony_ci /* go ahead and setup the first opt, because 651141cc406Sopenharmony_ci * frontend may call control_option on it 652141cc406Sopenharmony_ci * before calling get_option_descriptor 653141cc406Sopenharmony_ci */ 654141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 655141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) { 656141cc406Sopenharmony_ci s->opt[i].name = "filler"; 657141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 658141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_INACTIVE; 659141cc406Sopenharmony_ci } 660141cc406Sopenharmony_ci 661141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; 662141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 663141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 664141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 665141cc406Sopenharmony_ci 666141cc406Sopenharmony_ci DBG (15, "attach_one: init settings\n"); 667141cc406Sopenharmony_ci ret = change_params(s); 668141cc406Sopenharmony_ci 669141cc406Sopenharmony_ci /* we close the connection, so that another backend can talk to scanner */ 670141cc406Sopenharmony_ci disconnect_fd(s); 671141cc406Sopenharmony_ci 672141cc406Sopenharmony_ci s->next = scanner_devList; 673141cc406Sopenharmony_ci scanner_devList = s; 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ci DBG (10, "attach_one: finish\n"); 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 678141cc406Sopenharmony_ci} 679141cc406Sopenharmony_ci 680141cc406Sopenharmony_ci/* 681141cc406Sopenharmony_ci * connect the fd in the scanner struct 682141cc406Sopenharmony_ci */ 683141cc406Sopenharmony_cistatic SANE_Status 684141cc406Sopenharmony_ciconnect_fd (struct scanner *s) 685141cc406Sopenharmony_ci{ 686141cc406Sopenharmony_ci SANE_Status ret; 687141cc406Sopenharmony_ci 688141cc406Sopenharmony_ci DBG (10, "connect_fd: start\n"); 689141cc406Sopenharmony_ci 690141cc406Sopenharmony_ci if(s->fd > -1){ 691141cc406Sopenharmony_ci DBG (5, "connect_fd: already open\n"); 692141cc406Sopenharmony_ci ret = SANE_STATUS_GOOD; 693141cc406Sopenharmony_ci } 694141cc406Sopenharmony_ci else { 695141cc406Sopenharmony_ci DBG (15, "connect_fd: opening USB device\n"); 696141cc406Sopenharmony_ci ret = sanei_usb_open (s->sane.name, &(s->fd)); 697141cc406Sopenharmony_ci } 698141cc406Sopenharmony_ci 699141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 700141cc406Sopenharmony_ci DBG (5, "connect_fd: could not open device: %d\n", ret); 701141cc406Sopenharmony_ci } 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci DBG (10, "connect_fd: finish\n"); 704141cc406Sopenharmony_ci 705141cc406Sopenharmony_ci return ret; 706141cc406Sopenharmony_ci} 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci/* 709141cc406Sopenharmony_ci * try to load fw into scanner 710141cc406Sopenharmony_ci */ 711141cc406Sopenharmony_cistatic SANE_Status 712141cc406Sopenharmony_ciload_fw (struct scanner *s) 713141cc406Sopenharmony_ci{ 714141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 715141cc406Sopenharmony_ci int file, i; 716141cc406Sopenharmony_ci int len = 0; 717141cc406Sopenharmony_ci unsigned char * buf; 718141cc406Sopenharmony_ci 719141cc406Sopenharmony_ci unsigned char cmd[4]; 720141cc406Sopenharmony_ci size_t cmdLen; 721141cc406Sopenharmony_ci unsigned char stat[2]; 722141cc406Sopenharmony_ci size_t statLen; 723141cc406Sopenharmony_ci 724141cc406Sopenharmony_ci DBG (10, "load_fw: start\n"); 725141cc406Sopenharmony_ci 726141cc406Sopenharmony_ci /*check status*/ 727141cc406Sopenharmony_ci /*reuse stat buffer*/ 728141cc406Sopenharmony_ci stat[0] = get_stat(s); 729141cc406Sopenharmony_ci 730141cc406Sopenharmony_ci if(stat[0] & 0x10){ 731141cc406Sopenharmony_ci DBG (5, "load_fw: firmware already loaded?\n"); 732141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 733141cc406Sopenharmony_ci } 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci if(!global_firmware_filename[0]){ 736141cc406Sopenharmony_ci DBG (5, "load_fw: missing filename\n"); 737141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 738141cc406Sopenharmony_ci } 739141cc406Sopenharmony_ci 740141cc406Sopenharmony_ci file = open((char *)global_firmware_filename,O_RDONLY); 741141cc406Sopenharmony_ci if(!file){ 742141cc406Sopenharmony_ci DBG (5, "load_fw: failed to open file %s\n",global_firmware_filename); 743141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 744141cc406Sopenharmony_ci } 745141cc406Sopenharmony_ci 746141cc406Sopenharmony_ci /* skip first 256 (=0x100) bytes */ 747141cc406Sopenharmony_ci if(lseek(file,0x100,SEEK_SET) != 0x100){ 748141cc406Sopenharmony_ci DBG (5, "load_fw: failed to lseek file %s\n",global_firmware_filename); 749141cc406Sopenharmony_ci close(file); 750141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 751141cc406Sopenharmony_ci } 752141cc406Sopenharmony_ci 753141cc406Sopenharmony_ci buf = malloc(FIRMWARE_LENGTH); 754141cc406Sopenharmony_ci if(!buf){ 755141cc406Sopenharmony_ci DBG (5, "load_fw: failed to alloc mem\n"); 756141cc406Sopenharmony_ci close(file); 757141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 758141cc406Sopenharmony_ci } 759141cc406Sopenharmony_ci 760141cc406Sopenharmony_ci len = read(file,buf,FIRMWARE_LENGTH); 761141cc406Sopenharmony_ci close(file); 762141cc406Sopenharmony_ci 763141cc406Sopenharmony_ci if(len != FIRMWARE_LENGTH){ 764141cc406Sopenharmony_ci DBG (5, "load_fw: firmware file %s wrong length\n", 765141cc406Sopenharmony_ci global_firmware_filename); 766141cc406Sopenharmony_ci free(buf); 767141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 768141cc406Sopenharmony_ci } 769141cc406Sopenharmony_ci 770141cc406Sopenharmony_ci DBG (15, "load_fw: read firmware file %s ok\n", global_firmware_filename); 771141cc406Sopenharmony_ci 772141cc406Sopenharmony_ci /* firmware upload is in three commands */ 773141cc406Sopenharmony_ci 774141cc406Sopenharmony_ci /*start/status*/ 775141cc406Sopenharmony_ci cmd[0] = 0x1b; 776141cc406Sopenharmony_ci cmd[1] = 0x06; 777141cc406Sopenharmony_ci cmdLen = 2; 778141cc406Sopenharmony_ci statLen = 1; 779141cc406Sopenharmony_ci 780141cc406Sopenharmony_ci ret = do_cmd( 781141cc406Sopenharmony_ci s, 0, 782141cc406Sopenharmony_ci cmd, cmdLen, 783141cc406Sopenharmony_ci NULL, 0, 784141cc406Sopenharmony_ci stat, &statLen 785141cc406Sopenharmony_ci ); 786141cc406Sopenharmony_ci if(ret){ 787141cc406Sopenharmony_ci DBG (5, "load_fw: error on cmd 1\n"); 788141cc406Sopenharmony_ci free(buf); 789141cc406Sopenharmony_ci return ret; 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci if(stat[0] != 6){ 792141cc406Sopenharmony_ci DBG (5, "load_fw: bad stat on cmd 1\n"); 793141cc406Sopenharmony_ci free(buf); 794141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 795141cc406Sopenharmony_ci } 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci /*length/data*/ 798141cc406Sopenharmony_ci cmd[0] = 0x01; 799141cc406Sopenharmony_ci cmd[1] = 0x00; 800141cc406Sopenharmony_ci cmd[2] = 0x01; 801141cc406Sopenharmony_ci cmd[3] = 0x00; 802141cc406Sopenharmony_ci cmdLen = 4; 803141cc406Sopenharmony_ci 804141cc406Sopenharmony_ci ret = do_cmd( 805141cc406Sopenharmony_ci s, 0, 806141cc406Sopenharmony_ci cmd, cmdLen, 807141cc406Sopenharmony_ci buf, FIRMWARE_LENGTH, 808141cc406Sopenharmony_ci NULL, 0 809141cc406Sopenharmony_ci ); 810141cc406Sopenharmony_ci if(ret){ 811141cc406Sopenharmony_ci DBG (5, "load_fw: error on cmd 2\n"); 812141cc406Sopenharmony_ci free(buf); 813141cc406Sopenharmony_ci return ret; 814141cc406Sopenharmony_ci } 815141cc406Sopenharmony_ci 816141cc406Sopenharmony_ci /*checksum/status*/ 817141cc406Sopenharmony_ci cmd[0] = 0; 818141cc406Sopenharmony_ci for(i=0;i<FIRMWARE_LENGTH;i++){ 819141cc406Sopenharmony_ci cmd[0] += buf[i]; 820141cc406Sopenharmony_ci } 821141cc406Sopenharmony_ci free(buf); 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci cmdLen = 1; 824141cc406Sopenharmony_ci statLen = 1; 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci ret = do_cmd( 827141cc406Sopenharmony_ci s, 0, 828141cc406Sopenharmony_ci cmd, cmdLen, 829141cc406Sopenharmony_ci NULL, 0, 830141cc406Sopenharmony_ci stat, &statLen 831141cc406Sopenharmony_ci ); 832141cc406Sopenharmony_ci if(ret){ 833141cc406Sopenharmony_ci DBG (5, "load_fw: error on cmd 3\n"); 834141cc406Sopenharmony_ci return ret; 835141cc406Sopenharmony_ci } 836141cc406Sopenharmony_ci if(stat[0] != 6){ 837141cc406Sopenharmony_ci DBG (5, "load_fw: bad stat on cmd 3\n"); 838141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 839141cc406Sopenharmony_ci } 840141cc406Sopenharmony_ci 841141cc406Sopenharmony_ci /*reinit*/ 842141cc406Sopenharmony_ci cmd[0] = 0x1b; 843141cc406Sopenharmony_ci cmd[1] = 0x16; 844141cc406Sopenharmony_ci cmdLen = 2; 845141cc406Sopenharmony_ci statLen = 1; 846141cc406Sopenharmony_ci 847141cc406Sopenharmony_ci ret = do_cmd( 848141cc406Sopenharmony_ci s, 0, 849141cc406Sopenharmony_ci cmd, cmdLen, 850141cc406Sopenharmony_ci NULL, 0, 851141cc406Sopenharmony_ci stat, &statLen 852141cc406Sopenharmony_ci ); 853141cc406Sopenharmony_ci if(ret){ 854141cc406Sopenharmony_ci DBG (5, "load_fw: error reinit cmd\n"); 855141cc406Sopenharmony_ci return ret; 856141cc406Sopenharmony_ci } 857141cc406Sopenharmony_ci if(stat[0] != 6){ 858141cc406Sopenharmony_ci DBG (5, "load_fw: reinit cmd bad status?\n"); 859141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 860141cc406Sopenharmony_ci } 861141cc406Sopenharmony_ci 862141cc406Sopenharmony_ci cmd[0] = 0x80; 863141cc406Sopenharmony_ci cmdLen = 1; 864141cc406Sopenharmony_ci statLen = 1; 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci ret = do_cmd( 867141cc406Sopenharmony_ci s, 0, 868141cc406Sopenharmony_ci cmd, cmdLen, 869141cc406Sopenharmony_ci NULL, 0, 870141cc406Sopenharmony_ci stat, &statLen 871141cc406Sopenharmony_ci ); 872141cc406Sopenharmony_ci if(ret){ 873141cc406Sopenharmony_ci DBG (5, "load_fw: error reinit payload\n"); 874141cc406Sopenharmony_ci return ret; 875141cc406Sopenharmony_ci } 876141cc406Sopenharmony_ci if(stat[0] != 6){ 877141cc406Sopenharmony_ci DBG (5, "load_fw: reinit payload bad status?\n"); 878141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 879141cc406Sopenharmony_ci } 880141cc406Sopenharmony_ci 881141cc406Sopenharmony_ci /*reuse stat buffer*/ 882141cc406Sopenharmony_ci stat[0] = get_stat(s); 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci if(!(stat[0] & 0x10)){ 885141cc406Sopenharmony_ci DBG (5, "load_fw: firmware not loaded? %#x\n",stat[0]); 886141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci 889141cc406Sopenharmony_ci return ret; 890141cc406Sopenharmony_ci} 891141cc406Sopenharmony_ci 892141cc406Sopenharmony_ci/* 893141cc406Sopenharmony_ci * get status from scanner 894141cc406Sopenharmony_ci */ 895141cc406Sopenharmony_cistatic unsigned char 896141cc406Sopenharmony_ciget_stat(struct scanner *s) 897141cc406Sopenharmony_ci{ 898141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 899141cc406Sopenharmony_ci 900141cc406Sopenharmony_ci unsigned char cmd[2]; 901141cc406Sopenharmony_ci size_t cmdLen; 902141cc406Sopenharmony_ci unsigned char stat[2]; 903141cc406Sopenharmony_ci size_t statLen; 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci DBG (10, "get_stat: start\n"); 906141cc406Sopenharmony_ci 907141cc406Sopenharmony_ci /*check status*/ 908141cc406Sopenharmony_ci cmd[0] = 0x1b; 909141cc406Sopenharmony_ci cmd[1] = 0x03; 910141cc406Sopenharmony_ci cmdLen = 2; 911141cc406Sopenharmony_ci statLen = 2; 912141cc406Sopenharmony_ci 913141cc406Sopenharmony_ci ret = do_cmd( 914141cc406Sopenharmony_ci s, 0, 915141cc406Sopenharmony_ci cmd, cmdLen, 916141cc406Sopenharmony_ci NULL, 0, 917141cc406Sopenharmony_ci stat, &statLen 918141cc406Sopenharmony_ci ); 919141cc406Sopenharmony_ci if(ret){ 920141cc406Sopenharmony_ci DBG (5, "get_stat: error checking status\n"); 921141cc406Sopenharmony_ci return 0; 922141cc406Sopenharmony_ci } 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ci return stat[0]; 925141cc406Sopenharmony_ci} 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci/* 928141cc406Sopenharmony_ci * get scanner identification 929141cc406Sopenharmony_ci */ 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_cistatic SANE_Status 932141cc406Sopenharmony_ciget_ident(struct scanner *s) 933141cc406Sopenharmony_ci{ 934141cc406Sopenharmony_ci int i; 935141cc406Sopenharmony_ci SANE_Status ret; 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b,0x13}; 938141cc406Sopenharmony_ci size_t cmdLen = 2; 939141cc406Sopenharmony_ci unsigned char in[0x20]; 940141cc406Sopenharmony_ci size_t inLen = sizeof(in); 941141cc406Sopenharmony_ci 942141cc406Sopenharmony_ci DBG (10, "get_ident: start\n"); 943141cc406Sopenharmony_ci 944141cc406Sopenharmony_ci ret = do_cmd ( 945141cc406Sopenharmony_ci s, 0, 946141cc406Sopenharmony_ci cmd, cmdLen, 947141cc406Sopenharmony_ci NULL, 0, 948141cc406Sopenharmony_ci in, &inLen 949141cc406Sopenharmony_ci ); 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD){ 952141cc406Sopenharmony_ci return ret; 953141cc406Sopenharmony_ci } 954141cc406Sopenharmony_ci 955141cc406Sopenharmony_ci /*hmm, similar to scsi?*/ 956141cc406Sopenharmony_ci for (i = 7; (in[i] == ' ' || in[i] == 0xff) && i >= 0; i--){ 957141cc406Sopenharmony_ci in[i] = 0; 958141cc406Sopenharmony_ci } 959141cc406Sopenharmony_ci s->sane.vendor = strndup((char *)in, 8); 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci for (i = 23; (in[i] == ' ' || in[i] == 0xff) && i >= 8; i--){ 962141cc406Sopenharmony_ci in[i] = 0; 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci s->sane.model= strndup((char *)in+8, 24); 965141cc406Sopenharmony_ci 966141cc406Sopenharmony_ci s->sane.type = "scanner"; 967141cc406Sopenharmony_ci 968141cc406Sopenharmony_ci DBG (10, "get_ident: finish\n"); 969141cc406Sopenharmony_ci return ret; 970141cc406Sopenharmony_ci} 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci/* 973141cc406Sopenharmony_ci * From the SANE spec: 974141cc406Sopenharmony_ci * This function is used to establish a connection to a particular 975141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument 976141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device 977141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length 978141cc406Sopenharmony_ci * string as the device requests opening the first available device 979141cc406Sopenharmony_ci * (if there is such a device). 980141cc406Sopenharmony_ci */ 981141cc406Sopenharmony_ciSANE_Status 982141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle) 983141cc406Sopenharmony_ci{ 984141cc406Sopenharmony_ci struct scanner *dev = NULL; 985141cc406Sopenharmony_ci struct scanner *s = NULL; 986141cc406Sopenharmony_ci SANE_Status ret; 987141cc406Sopenharmony_ci 988141cc406Sopenharmony_ci DBG (10, "sane_open: start\n"); 989141cc406Sopenharmony_ci 990141cc406Sopenharmony_ci if(scanner_devList){ 991141cc406Sopenharmony_ci DBG (15, "sane_open: searching currently attached scanners\n"); 992141cc406Sopenharmony_ci } 993141cc406Sopenharmony_ci else{ 994141cc406Sopenharmony_ci DBG (15, "sane_open: no scanners currently attached, attaching\n"); 995141cc406Sopenharmony_ci 996141cc406Sopenharmony_ci ret = sane_get_devices(NULL,0); 997141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 998141cc406Sopenharmony_ci return ret; 999141cc406Sopenharmony_ci } 1000141cc406Sopenharmony_ci } 1001141cc406Sopenharmony_ci 1002141cc406Sopenharmony_ci if(name[0] == 0){ 1003141cc406Sopenharmony_ci DBG (15, "sane_open: no device requested, using default\n"); 1004141cc406Sopenharmony_ci s = scanner_devList; 1005141cc406Sopenharmony_ci } 1006141cc406Sopenharmony_ci else{ 1007141cc406Sopenharmony_ci DBG (15, "sane_open: device %s requested, attaching\n", name); 1008141cc406Sopenharmony_ci 1009141cc406Sopenharmony_ci for (dev = scanner_devList; dev; dev = dev->next) { 1010141cc406Sopenharmony_ci if (strcmp (dev->sane.name, name) == 0) { 1011141cc406Sopenharmony_ci s = dev; 1012141cc406Sopenharmony_ci break; 1013141cc406Sopenharmony_ci } 1014141cc406Sopenharmony_ci } 1015141cc406Sopenharmony_ci } 1016141cc406Sopenharmony_ci 1017141cc406Sopenharmony_ci if (!s) { 1018141cc406Sopenharmony_ci DBG (5, "sane_open: no device found\n"); 1019141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1020141cc406Sopenharmony_ci } 1021141cc406Sopenharmony_ci 1022141cc406Sopenharmony_ci DBG (15, "sane_open: device %s found\n", s->sane.name); 1023141cc406Sopenharmony_ci 1024141cc406Sopenharmony_ci *handle = s; 1025141cc406Sopenharmony_ci 1026141cc406Sopenharmony_ci /* connect the fd so we can talk to scanner */ 1027141cc406Sopenharmony_ci ret = connect_fd(s); 1028141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 1029141cc406Sopenharmony_ci return ret; 1030141cc406Sopenharmony_ci } 1031141cc406Sopenharmony_ci 1032141cc406Sopenharmony_ci DBG (10, "sane_open: finish\n"); 1033141cc406Sopenharmony_ci 1034141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1035141cc406Sopenharmony_ci} 1036141cc406Sopenharmony_ci 1037141cc406Sopenharmony_ci/* 1038141cc406Sopenharmony_ci * @@ Section 3 - SANE Options functions 1039141cc406Sopenharmony_ci */ 1040141cc406Sopenharmony_ci 1041141cc406Sopenharmony_ci/* 1042141cc406Sopenharmony_ci * Returns the options we know. 1043141cc406Sopenharmony_ci * 1044141cc406Sopenharmony_ci * From the SANE spec: 1045141cc406Sopenharmony_ci * This function is used to access option descriptors. The function 1046141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device 1047141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a 1048141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of 1049141cc406Sopenharmony_ci * options that are available for device handle h (the count includes 1050141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns 1051141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid 1052141cc406Sopenharmony_ci * (and at the returned address) until the device is closed. 1053141cc406Sopenharmony_ci */ 1054141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1055141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1056141cc406Sopenharmony_ci{ 1057141cc406Sopenharmony_ci struct scanner *s = handle; 1058141cc406Sopenharmony_ci int i; 1059141cc406Sopenharmony_ci SANE_Option_Descriptor *opt = &s->opt[option]; 1060141cc406Sopenharmony_ci 1061141cc406Sopenharmony_ci DBG (20, "sane_get_option_descriptor: %d\n", option); 1062141cc406Sopenharmony_ci 1063141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 1064141cc406Sopenharmony_ci return NULL; 1065141cc406Sopenharmony_ci 1066141cc406Sopenharmony_ci /* "Mode" group -------------------------------------------------------- */ 1067141cc406Sopenharmony_ci if(option==OPT_MODE_GROUP){ 1068141cc406Sopenharmony_ci opt->title = "Scan Mode"; 1069141cc406Sopenharmony_ci opt->desc = ""; 1070141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1071141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1072141cc406Sopenharmony_ci } 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci /* source */ 1075141cc406Sopenharmony_ci else if(option==OPT_SOURCE){ 1076141cc406Sopenharmony_ci i=0; 1077141cc406Sopenharmony_ci if(s->has_fb){ 1078141cc406Sopenharmony_ci s->source_list[i++]=STRING_FLATBED; 1079141cc406Sopenharmony_ci } 1080141cc406Sopenharmony_ci if(s->has_adf){ 1081141cc406Sopenharmony_ci s->source_list[i++]=STRING_ADFFRONT; 1082141cc406Sopenharmony_ci if(s->has_adf_duplex){ 1083141cc406Sopenharmony_ci s->source_list[i++]=STRING_ADFBACK; 1084141cc406Sopenharmony_ci s->source_list[i++]=STRING_ADFDUPLEX; 1085141cc406Sopenharmony_ci } 1086141cc406Sopenharmony_ci } 1087141cc406Sopenharmony_ci s->source_list[i]=NULL; 1088141cc406Sopenharmony_ci 1089141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_SOURCE; 1090141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_SOURCE; 1091141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_SOURCE; 1092141cc406Sopenharmony_ci opt->type = SANE_TYPE_STRING; 1093141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; 1094141cc406Sopenharmony_ci opt->constraint.string_list = s->source_list; 1095141cc406Sopenharmony_ci opt->size = maxStringSize (opt->constraint.string_list); 1096141cc406Sopenharmony_ci if(i > 1){ 1097141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1098141cc406Sopenharmony_ci } 1099141cc406Sopenharmony_ci } 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci /* scan mode */ 1102141cc406Sopenharmony_ci else if(option==OPT_MODE){ 1103141cc406Sopenharmony_ci i=0; 1104141cc406Sopenharmony_ci s->mode_list[i++]=STRING_LINEART; 1105141cc406Sopenharmony_ci s->mode_list[i++]=STRING_GRAYSCALE; 1106141cc406Sopenharmony_ci s->mode_list[i++]=STRING_COLOR; 1107141cc406Sopenharmony_ci s->mode_list[i]=NULL; 1108141cc406Sopenharmony_ci 1109141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_MODE; 1110141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_MODE; 1111141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_MODE; 1112141cc406Sopenharmony_ci opt->type = SANE_TYPE_STRING; 1113141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; 1114141cc406Sopenharmony_ci opt->constraint.string_list = s->mode_list; 1115141cc406Sopenharmony_ci opt->size = maxStringSize (opt->constraint.string_list); 1116141cc406Sopenharmony_ci if(i > 1){ 1117141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1118141cc406Sopenharmony_ci } 1119141cc406Sopenharmony_ci } 1120141cc406Sopenharmony_ci 1121141cc406Sopenharmony_ci else if(option==OPT_RES){ 1122141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_RESOLUTION; 1123141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_RESOLUTION; 1124141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_RESOLUTION; 1125141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1126141cc406Sopenharmony_ci opt->unit = SANE_UNIT_DPI; 1127141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1128141cc406Sopenharmony_ci 1129141cc406Sopenharmony_ci s->res_range.min = s->min_res; 1130141cc406Sopenharmony_ci s->res_range.max = s->max_res; 1131141cc406Sopenharmony_ci s->res_range.quant = 1; 1132141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1133141cc406Sopenharmony_ci opt->constraint.range = &s->res_range; 1134141cc406Sopenharmony_ci } 1135141cc406Sopenharmony_ci 1136141cc406Sopenharmony_ci /* "Geometry" group ---------------------------------------------------- */ 1137141cc406Sopenharmony_ci if(option==OPT_GEOMETRY_GROUP){ 1138141cc406Sopenharmony_ci opt->name = SANE_NAME_GEOMETRY; 1139141cc406Sopenharmony_ci opt->title = SANE_TITLE_GEOMETRY; 1140141cc406Sopenharmony_ci opt->desc = SANE_DESC_GEOMETRY; 1141141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1142141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1143141cc406Sopenharmony_ci } 1144141cc406Sopenharmony_ci 1145141cc406Sopenharmony_ci /* top-left x */ 1146141cc406Sopenharmony_ci if(option==OPT_TL_X){ 1147141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1148141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1149141cc406Sopenharmony_ci s->tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(0); 1150141cc406Sopenharmony_ci s->tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(MAX(0, get_page_width(s)-s->min_x)); 1151141cc406Sopenharmony_ci s->tl_x_range.quant = MM_PER_UNIT_FIX; 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_TL_X; 1154141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_TL_X; 1155141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_TL_X; 1156141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1157141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1158141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1159141cc406Sopenharmony_ci opt->constraint.range = &(s->tl_x_range); 1160141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1161141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1162141cc406Sopenharmony_ci } 1163141cc406Sopenharmony_ci 1164141cc406Sopenharmony_ci /* top-left y */ 1165141cc406Sopenharmony_ci if(option==OPT_TL_Y){ 1166141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1167141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1168141cc406Sopenharmony_ci s->tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(0); 1169141cc406Sopenharmony_ci s->tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(MAX(0, get_page_height(s)-s->min_y)); 1170141cc406Sopenharmony_ci s->tl_y_range.quant = MM_PER_UNIT_FIX; 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_TL_Y; 1173141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_TL_Y; 1174141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_TL_Y; 1175141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1176141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1177141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1178141cc406Sopenharmony_ci opt->constraint.range = &(s->tl_y_range); 1179141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1180141cc406Sopenharmony_ci } 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci /* bottom-right x */ 1183141cc406Sopenharmony_ci if(option==OPT_BR_X){ 1184141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1185141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1186141cc406Sopenharmony_ci s->br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); 1187141cc406Sopenharmony_ci s->br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(MAX(s->min_x, get_page_width(s))); 1188141cc406Sopenharmony_ci s->br_x_range.quant = MM_PER_UNIT_FIX; 1189141cc406Sopenharmony_ci 1190141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_BR_X; 1191141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_BR_X; 1192141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_BR_X; 1193141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1194141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1195141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1196141cc406Sopenharmony_ci opt->constraint.range = &(s->br_x_range); 1197141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1198141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1199141cc406Sopenharmony_ci } 1200141cc406Sopenharmony_ci 1201141cc406Sopenharmony_ci /* bottom-right y */ 1202141cc406Sopenharmony_ci if(option==OPT_BR_Y){ 1203141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1204141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1205141cc406Sopenharmony_ci s->br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); 1206141cc406Sopenharmony_ci s->br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(MAX(s->min_y, get_page_height(s))); 1207141cc406Sopenharmony_ci s->br_y_range.quant = MM_PER_UNIT_FIX; 1208141cc406Sopenharmony_ci 1209141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_BR_Y; 1210141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_BR_Y; 1211141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_BR_Y; 1212141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1213141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1214141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1215141cc406Sopenharmony_ci opt->constraint.range = &(s->br_y_range); 1216141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1217141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1218141cc406Sopenharmony_ci } 1219141cc406Sopenharmony_ci 1220141cc406Sopenharmony_ci /* page width */ 1221141cc406Sopenharmony_ci if(option==OPT_PAGE_WIDTH){ 1222141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1223141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1224141cc406Sopenharmony_ci s->paper_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); 1225141cc406Sopenharmony_ci s->paper_x_range.max = SCANNER_UNIT_TO_FIXED_MM(s->max_x); 1226141cc406Sopenharmony_ci s->paper_x_range.quant = MM_PER_UNIT_FIX; 1227141cc406Sopenharmony_ci 1228141cc406Sopenharmony_ci opt->name = SANE_NAME_PAGE_WIDTH; 1229141cc406Sopenharmony_ci opt->title = SANE_TITLE_PAGE_WIDTH; 1230141cc406Sopenharmony_ci opt->desc = SANE_DESC_PAGE_WIDTH; 1231141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1232141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1233141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1234141cc406Sopenharmony_ci opt->constraint.range = &s->paper_x_range; 1235141cc406Sopenharmony_ci 1236141cc406Sopenharmony_ci if(s->has_adf){ 1237141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1238141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED){ 1239141cc406Sopenharmony_ci opt->cap |= SANE_CAP_INACTIVE; 1240141cc406Sopenharmony_ci } 1241141cc406Sopenharmony_ci } 1242141cc406Sopenharmony_ci else{ 1243141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1244141cc406Sopenharmony_ci } 1245141cc406Sopenharmony_ci } 1246141cc406Sopenharmony_ci 1247141cc406Sopenharmony_ci /* page height */ 1248141cc406Sopenharmony_ci if(option==OPT_PAGE_HEIGHT){ 1249141cc406Sopenharmony_ci /* values stored in 1200 dpi units */ 1250141cc406Sopenharmony_ci /* must be converted to MM for sane */ 1251141cc406Sopenharmony_ci s->paper_y_range.min = SCANNER_UNIT_TO_FIXED_MM(0); 1252141cc406Sopenharmony_ci s->paper_y_range.max = SCANNER_UNIT_TO_FIXED_MM(s->max_y); 1253141cc406Sopenharmony_ci s->paper_y_range.quant = MM_PER_UNIT_FIX; 1254141cc406Sopenharmony_ci 1255141cc406Sopenharmony_ci opt->name = SANE_NAME_PAGE_HEIGHT; 1256141cc406Sopenharmony_ci opt->title = SANE_TITLE_PAGE_HEIGHT; 1257141cc406Sopenharmony_ci opt->desc = "Specifies the height of the media, 0 will auto-detect."; 1258141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1259141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1260141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1261141cc406Sopenharmony_ci opt->constraint.range = &s->paper_y_range; 1262141cc406Sopenharmony_ci 1263141cc406Sopenharmony_ci if(s->has_adf){ 1264141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1265141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED){ 1266141cc406Sopenharmony_ci opt->cap |= SANE_CAP_INACTIVE; 1267141cc406Sopenharmony_ci } 1268141cc406Sopenharmony_ci } 1269141cc406Sopenharmony_ci else{ 1270141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1271141cc406Sopenharmony_ci } 1272141cc406Sopenharmony_ci } 1273141cc406Sopenharmony_ci 1274141cc406Sopenharmony_ci /* "Enhancement" group ------------------------------------------------- */ 1275141cc406Sopenharmony_ci if(option==OPT_ENHANCEMENT_GROUP){ 1276141cc406Sopenharmony_ci opt->name = SANE_NAME_ENHANCEMENT; 1277141cc406Sopenharmony_ci opt->title = SANE_TITLE_ENHANCEMENT; 1278141cc406Sopenharmony_ci opt->desc = SANE_DESC_ENHANCEMENT; 1279141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1280141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1281141cc406Sopenharmony_ci } 1282141cc406Sopenharmony_ci 1283141cc406Sopenharmony_ci /* brightness */ 1284141cc406Sopenharmony_ci if(option==OPT_BRIGHTNESS){ 1285141cc406Sopenharmony_ci opt->name = SANE_NAME_BRIGHTNESS; 1286141cc406Sopenharmony_ci opt->title = SANE_TITLE_BRIGHTNESS; 1287141cc406Sopenharmony_ci opt->desc = SANE_DESC_BRIGHTNESS; 1288141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1289141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1292141cc406Sopenharmony_ci opt->constraint.range = &s->brightness_range; 1293141cc406Sopenharmony_ci s->brightness_range.quant=1; 1294141cc406Sopenharmony_ci s->brightness_range.min=-127; 1295141cc406Sopenharmony_ci s->brightness_range.max=127; 1296141cc406Sopenharmony_ci 1297141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1298141cc406Sopenharmony_ci } 1299141cc406Sopenharmony_ci 1300141cc406Sopenharmony_ci /* contrast */ 1301141cc406Sopenharmony_ci if(option==OPT_CONTRAST){ 1302141cc406Sopenharmony_ci opt->name = SANE_NAME_CONTRAST; 1303141cc406Sopenharmony_ci opt->title = SANE_TITLE_CONTRAST; 1304141cc406Sopenharmony_ci opt->desc = SANE_DESC_CONTRAST; 1305141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1306141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1307141cc406Sopenharmony_ci 1308141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1309141cc406Sopenharmony_ci opt->constraint.range = &s->contrast_range; 1310141cc406Sopenharmony_ci s->contrast_range.quant=1; 1311141cc406Sopenharmony_ci s->contrast_range.min=-127; 1312141cc406Sopenharmony_ci s->contrast_range.max=127; 1313141cc406Sopenharmony_ci 1314141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1315141cc406Sopenharmony_ci } 1316141cc406Sopenharmony_ci 1317141cc406Sopenharmony_ci /* gamma */ 1318141cc406Sopenharmony_ci if(option==OPT_GAMMA){ 1319141cc406Sopenharmony_ci opt->name = "gamma"; 1320141cc406Sopenharmony_ci opt->title = "Gamma function exponent"; 1321141cc406Sopenharmony_ci opt->desc = "Changes intensity of midtones"; 1322141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1323141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1324141cc406Sopenharmony_ci 1325141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1326141cc406Sopenharmony_ci opt->constraint.range = &s->gamma_range; 1327141cc406Sopenharmony_ci 1328141cc406Sopenharmony_ci /* value ranges from .3 to 5, should be log scale? */ 1329141cc406Sopenharmony_ci s->gamma_range.quant=SANE_FIX(0.01); 1330141cc406Sopenharmony_ci s->gamma_range.min=SANE_FIX(0.3); 1331141cc406Sopenharmony_ci s->gamma_range.max=SANE_FIX(5); 1332141cc406Sopenharmony_ci 1333141cc406Sopenharmony_ci /*if (s->num_download_gamma){ 1334141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1335141cc406Sopenharmony_ci }*/ 1336141cc406Sopenharmony_ci 1337141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1338141cc406Sopenharmony_ci } 1339141cc406Sopenharmony_ci 1340141cc406Sopenharmony_ci /*threshold*/ 1341141cc406Sopenharmony_ci if(option==OPT_THRESHOLD){ 1342141cc406Sopenharmony_ci opt->name = SANE_NAME_THRESHOLD; 1343141cc406Sopenharmony_ci opt->title = SANE_TITLE_THRESHOLD; 1344141cc406Sopenharmony_ci opt->desc = SANE_DESC_THRESHOLD; 1345141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1346141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1347141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1348141cc406Sopenharmony_ci opt->constraint.range = &s->threshold_range; 1349141cc406Sopenharmony_ci s->threshold_range.min=0; 1350141cc406Sopenharmony_ci s->threshold_range.max=255; 1351141cc406Sopenharmony_ci s->threshold_range.quant=1; 1352141cc406Sopenharmony_ci 1353141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1354141cc406Sopenharmony_ci if(s->mode != MODE_LINEART){ 1355141cc406Sopenharmony_ci opt->cap |= SANE_CAP_INACTIVE; 1356141cc406Sopenharmony_ci } 1357141cc406Sopenharmony_ci } 1358141cc406Sopenharmony_ci 1359141cc406Sopenharmony_ci if(option==OPT_THRESHOLD_CURVE){ 1360141cc406Sopenharmony_ci opt->name = "threshold-curve"; 1361141cc406Sopenharmony_ci opt->title = "Threshold curve"; 1362141cc406Sopenharmony_ci opt->desc = "Dynamic threshold curve, from light to dark, normally 50-65"; 1363141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1364141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1365141cc406Sopenharmony_ci 1366141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1367141cc406Sopenharmony_ci opt->constraint.range = &s->threshold_curve_range; 1368141cc406Sopenharmony_ci s->threshold_curve_range.min=0; 1369141cc406Sopenharmony_ci s->threshold_curve_range.max=127; 1370141cc406Sopenharmony_ci s->threshold_curve_range.quant=1; 1371141cc406Sopenharmony_ci 1372141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1373141cc406Sopenharmony_ci if(s->mode != MODE_LINEART){ 1374141cc406Sopenharmony_ci opt->cap |= SANE_CAP_INACTIVE; 1375141cc406Sopenharmony_ci } 1376141cc406Sopenharmony_ci } 1377141cc406Sopenharmony_ci 1378141cc406Sopenharmony_ci /* "Sensor" group ------------------------------------------------------ */ 1379141cc406Sopenharmony_ci if(option==OPT_SENSOR_GROUP){ 1380141cc406Sopenharmony_ci opt->name = SANE_NAME_SENSORS; 1381141cc406Sopenharmony_ci opt->title = SANE_TITLE_SENSORS; 1382141cc406Sopenharmony_ci opt->desc = SANE_DESC_SENSORS; 1383141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1384141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci /*flaming hack to get scanimage to hide group*/ 1387141cc406Sopenharmony_ci if (!s->has_adf) 1388141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1389141cc406Sopenharmony_ci } 1390141cc406Sopenharmony_ci 1391141cc406Sopenharmony_ci if(option==OPT_SCAN_SW){ 1392141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN; 1393141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN; 1394141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN; 1395141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1396141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1397141cc406Sopenharmony_ci if (s->has_adf) 1398141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; 1399141cc406Sopenharmony_ci else 1400141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci if(option==OPT_HOPPER){ 1404141cc406Sopenharmony_ci opt->name = SANE_NAME_PAGE_LOADED; 1405141cc406Sopenharmony_ci opt->title = SANE_TITLE_PAGE_LOADED; 1406141cc406Sopenharmony_ci opt->desc = SANE_DESC_PAGE_LOADED; 1407141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1408141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1409141cc406Sopenharmony_ci if (s->has_adf) 1410141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; 1411141cc406Sopenharmony_ci else 1412141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1413141cc406Sopenharmony_ci } 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_ci if(option==OPT_TOP){ 1416141cc406Sopenharmony_ci opt->name = "top-edge"; 1417141cc406Sopenharmony_ci opt->title = "Top edge"; 1418141cc406Sopenharmony_ci opt->desc = "Paper is pulled partly into adf"; 1419141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1420141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1421141cc406Sopenharmony_ci if (s->has_adf) 1422141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; 1423141cc406Sopenharmony_ci else 1424141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1425141cc406Sopenharmony_ci } 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci if(option==OPT_ADF_OPEN){ 1428141cc406Sopenharmony_ci opt->name = SANE_NAME_COVER_OPEN; 1429141cc406Sopenharmony_ci opt->title = SANE_TITLE_COVER_OPEN; 1430141cc406Sopenharmony_ci opt->desc = SANE_DESC_COVER_OPEN; 1431141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1432141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1433141cc406Sopenharmony_ci if (s->has_adf) 1434141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; 1435141cc406Sopenharmony_ci else 1436141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1437141cc406Sopenharmony_ci } 1438141cc406Sopenharmony_ci 1439141cc406Sopenharmony_ci if(option==OPT_SLEEP){ 1440141cc406Sopenharmony_ci opt->name = "power-save"; 1441141cc406Sopenharmony_ci opt->title = "Power saving"; 1442141cc406Sopenharmony_ci opt->desc = "Scanner in power saving mode"; 1443141cc406Sopenharmony_ci opt->type = SANE_TYPE_BOOL; 1444141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1445141cc406Sopenharmony_ci if (s->has_adf) 1446141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; 1447141cc406Sopenharmony_ci else 1448141cc406Sopenharmony_ci opt->cap = SANE_CAP_INACTIVE; 1449141cc406Sopenharmony_ci } 1450141cc406Sopenharmony_ci 1451141cc406Sopenharmony_ci return opt; 1452141cc406Sopenharmony_ci} 1453141cc406Sopenharmony_ci 1454141cc406Sopenharmony_ci/** 1455141cc406Sopenharmony_ci * Gets or sets an option value. 1456141cc406Sopenharmony_ci * 1457141cc406Sopenharmony_ci * From the SANE spec: 1458141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option 1459141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which 1460141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The 1461141cc406Sopenharmony_ci * possible values of this parameter are described in more detail 1462141cc406Sopenharmony_ci * below. The value of the option is passed through argument val. It 1463141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory 1464141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option 1465141cc406Sopenharmony_ci * value (determined by member size in the corresponding option 1466141cc406Sopenharmony_ci * descriptor). 1467141cc406Sopenharmony_ci * 1468141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a 1469141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter 1470141cc406Sopenharmony_ci * since the backend will stop reading the option value upon 1471141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i 1472141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how 1473141cc406Sopenharmony_ci * well the request has been met. 1474141cc406Sopenharmony_ci */ 1475141cc406Sopenharmony_ciSANE_Status 1476141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 1477141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 1478141cc406Sopenharmony_ci{ 1479141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 1480141cc406Sopenharmony_ci SANE_Int dummy = 0; 1481141cc406Sopenharmony_ci 1482141cc406Sopenharmony_ci /* Make sure that all those statements involving *info cannot break (better 1483141cc406Sopenharmony_ci * than having to do "if (info) ..." everywhere!) 1484141cc406Sopenharmony_ci */ 1485141cc406Sopenharmony_ci if (info == 0) 1486141cc406Sopenharmony_ci info = &dummy; 1487141cc406Sopenharmony_ci 1488141cc406Sopenharmony_ci if (option >= NUM_OPTIONS) { 1489141cc406Sopenharmony_ci DBG (5, "sane_control_option: %d too big\n", option); 1490141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1491141cc406Sopenharmony_ci } 1492141cc406Sopenharmony_ci 1493141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (s->opt[option].cap)) { 1494141cc406Sopenharmony_ci DBG (5, "sane_control_option: %d inactive\n", option); 1495141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1496141cc406Sopenharmony_ci } 1497141cc406Sopenharmony_ci 1498141cc406Sopenharmony_ci /* 1499141cc406Sopenharmony_ci * SANE_ACTION_GET_VALUE: We have to find out the current setting and 1500141cc406Sopenharmony_ci * return it in a human-readable form (often, text). 1501141cc406Sopenharmony_ci */ 1502141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) { 1503141cc406Sopenharmony_ci SANE_Word * val_p = (SANE_Word *) val; 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ci DBG (20, "sane_control_option: get value for '%s' (%d)\n", s->opt[option].name,option); 1506141cc406Sopenharmony_ci 1507141cc406Sopenharmony_ci switch (option) { 1508141cc406Sopenharmony_ci 1509141cc406Sopenharmony_ci case OPT_NUM_OPTS: 1510141cc406Sopenharmony_ci *val_p = NUM_OPTIONS; 1511141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1512141cc406Sopenharmony_ci 1513141cc406Sopenharmony_ci case OPT_SOURCE: 1514141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED){ 1515141cc406Sopenharmony_ci strcpy (val, STRING_FLATBED); 1516141cc406Sopenharmony_ci } 1517141cc406Sopenharmony_ci else if(s->source == SOURCE_ADF_FRONT){ 1518141cc406Sopenharmony_ci strcpy (val, STRING_ADFFRONT); 1519141cc406Sopenharmony_ci } 1520141cc406Sopenharmony_ci else if(s->source == SOURCE_ADF_BACK){ 1521141cc406Sopenharmony_ci strcpy (val, STRING_ADFBACK); 1522141cc406Sopenharmony_ci } 1523141cc406Sopenharmony_ci else if(s->source == SOURCE_ADF_DUPLEX){ 1524141cc406Sopenharmony_ci strcpy (val, STRING_ADFDUPLEX); 1525141cc406Sopenharmony_ci } 1526141cc406Sopenharmony_ci else{ 1527141cc406Sopenharmony_ci DBG(5,"missing option val for source\n"); 1528141cc406Sopenharmony_ci } 1529141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1530141cc406Sopenharmony_ci 1531141cc406Sopenharmony_ci case OPT_MODE: 1532141cc406Sopenharmony_ci if(s->mode == MODE_LINEART){ 1533141cc406Sopenharmony_ci strcpy (val, STRING_LINEART); 1534141cc406Sopenharmony_ci } 1535141cc406Sopenharmony_ci else if(s->mode == MODE_GRAYSCALE){ 1536141cc406Sopenharmony_ci strcpy (val, STRING_GRAYSCALE); 1537141cc406Sopenharmony_ci } 1538141cc406Sopenharmony_ci else if(s->mode == MODE_COLOR){ 1539141cc406Sopenharmony_ci strcpy (val, STRING_COLOR); 1540141cc406Sopenharmony_ci } 1541141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci case OPT_RES: 1544141cc406Sopenharmony_ci *val_p = s->resolution; 1545141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1546141cc406Sopenharmony_ci 1547141cc406Sopenharmony_ci case OPT_TL_X: 1548141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->tl_x); 1549141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1550141cc406Sopenharmony_ci 1551141cc406Sopenharmony_ci case OPT_TL_Y: 1552141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->tl_y); 1553141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1554141cc406Sopenharmony_ci 1555141cc406Sopenharmony_ci case OPT_BR_X: 1556141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->br_x); 1557141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1558141cc406Sopenharmony_ci 1559141cc406Sopenharmony_ci case OPT_BR_Y: 1560141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->br_y); 1561141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1562141cc406Sopenharmony_ci 1563141cc406Sopenharmony_ci case OPT_PAGE_WIDTH: 1564141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->page_width); 1565141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1566141cc406Sopenharmony_ci 1567141cc406Sopenharmony_ci case OPT_PAGE_HEIGHT: 1568141cc406Sopenharmony_ci *val_p = SCANNER_UNIT_TO_FIXED_MM(s->page_height); 1569141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1572141cc406Sopenharmony_ci *val_p = s->brightness; 1573141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1574141cc406Sopenharmony_ci 1575141cc406Sopenharmony_ci case OPT_CONTRAST: 1576141cc406Sopenharmony_ci *val_p = s->contrast; 1577141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1578141cc406Sopenharmony_ci 1579141cc406Sopenharmony_ci case OPT_GAMMA: 1580141cc406Sopenharmony_ci *val_p = SANE_FIX(s->gamma); 1581141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1582141cc406Sopenharmony_ci 1583141cc406Sopenharmony_ci case OPT_THRESHOLD: 1584141cc406Sopenharmony_ci *val_p = s->threshold; 1585141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1586141cc406Sopenharmony_ci 1587141cc406Sopenharmony_ci case OPT_THRESHOLD_CURVE: 1588141cc406Sopenharmony_ci *val_p = s->threshold_curve; 1589141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1590141cc406Sopenharmony_ci 1591141cc406Sopenharmony_ci /* Sensor Group */ 1592141cc406Sopenharmony_ci case OPT_SCAN_SW: 1593141cc406Sopenharmony_ci get_hardware_status(s); 1594141cc406Sopenharmony_ci *val_p = s->hw_scan_sw; 1595141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1596141cc406Sopenharmony_ci 1597141cc406Sopenharmony_ci case OPT_HOPPER: 1598141cc406Sopenharmony_ci get_hardware_status(s); 1599141cc406Sopenharmony_ci *val_p = s->hw_hopper; 1600141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1601141cc406Sopenharmony_ci 1602141cc406Sopenharmony_ci case OPT_TOP: 1603141cc406Sopenharmony_ci get_hardware_status(s); 1604141cc406Sopenharmony_ci *val_p = s->hw_top; 1605141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1606141cc406Sopenharmony_ci 1607141cc406Sopenharmony_ci case OPT_ADF_OPEN: 1608141cc406Sopenharmony_ci get_hardware_status(s); 1609141cc406Sopenharmony_ci *val_p = s->hw_adf_open; 1610141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1611141cc406Sopenharmony_ci 1612141cc406Sopenharmony_ci case OPT_SLEEP: 1613141cc406Sopenharmony_ci get_hardware_status(s); 1614141cc406Sopenharmony_ci *val_p = s->hw_sleep; 1615141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1616141cc406Sopenharmony_ci } 1617141cc406Sopenharmony_ci } 1618141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) { 1619141cc406Sopenharmony_ci int tmp; 1620141cc406Sopenharmony_ci SANE_Word val_c; 1621141cc406Sopenharmony_ci SANE_Status status; 1622141cc406Sopenharmony_ci 1623141cc406Sopenharmony_ci DBG (20, "sane_control_option: set value for '%s' (%d)\n", s->opt[option].name,option); 1624141cc406Sopenharmony_ci 1625141cc406Sopenharmony_ci if ( s->started ) { 1626141cc406Sopenharmony_ci DBG (5, "sane_control_option: can't set, device busy\n"); 1627141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 1628141cc406Sopenharmony_ci } 1629141cc406Sopenharmony_ci 1630141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap)) { 1631141cc406Sopenharmony_ci DBG (5, "sane_control_option: not settable\n"); 1632141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1633141cc406Sopenharmony_ci } 1634141cc406Sopenharmony_ci 1635141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 1636141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1637141cc406Sopenharmony_ci DBG (5, "sane_control_option: bad value\n"); 1638141cc406Sopenharmony_ci return status; 1639141cc406Sopenharmony_ci } 1640141cc406Sopenharmony_ci 1641141cc406Sopenharmony_ci /* may have been changed by constraints, so don't copy until now */ 1642141cc406Sopenharmony_ci val_c = *(SANE_Word *)val; 1643141cc406Sopenharmony_ci 1644141cc406Sopenharmony_ci /* 1645141cc406Sopenharmony_ci * Note - for those options which can assume one of a list of 1646141cc406Sopenharmony_ci * valid values, we can safely assume that they will have 1647141cc406Sopenharmony_ci * exactly one of those values because that's what 1648141cc406Sopenharmony_ci * sanei_constrain_value does. Hence no "else: invalid" branches 1649141cc406Sopenharmony_ci * below. 1650141cc406Sopenharmony_ci */ 1651141cc406Sopenharmony_ci switch (option) { 1652141cc406Sopenharmony_ci 1653141cc406Sopenharmony_ci /* Mode Group */ 1654141cc406Sopenharmony_ci case OPT_SOURCE: 1655141cc406Sopenharmony_ci if (!strcmp (val, STRING_ADFFRONT)) { 1656141cc406Sopenharmony_ci tmp = SOURCE_ADF_FRONT; 1657141cc406Sopenharmony_ci } 1658141cc406Sopenharmony_ci else if (!strcmp (val, STRING_ADFBACK)) { 1659141cc406Sopenharmony_ci tmp = SOURCE_ADF_BACK; 1660141cc406Sopenharmony_ci } 1661141cc406Sopenharmony_ci else if (!strcmp (val, STRING_ADFDUPLEX)) { 1662141cc406Sopenharmony_ci tmp = SOURCE_ADF_DUPLEX; 1663141cc406Sopenharmony_ci } 1664141cc406Sopenharmony_ci else{ 1665141cc406Sopenharmony_ci tmp = SOURCE_FLATBED; 1666141cc406Sopenharmony_ci } 1667141cc406Sopenharmony_ci 1668141cc406Sopenharmony_ci if (s->source == tmp) 1669141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1670141cc406Sopenharmony_ci 1671141cc406Sopenharmony_ci s->source = tmp; 1672141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1673141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1674141cc406Sopenharmony_ci 1675141cc406Sopenharmony_ci case OPT_MODE: 1676141cc406Sopenharmony_ci if (!strcmp (val, STRING_LINEART)) { 1677141cc406Sopenharmony_ci tmp = MODE_LINEART; 1678141cc406Sopenharmony_ci } 1679141cc406Sopenharmony_ci else if (!strcmp (val, STRING_GRAYSCALE)) { 1680141cc406Sopenharmony_ci tmp = MODE_GRAYSCALE; 1681141cc406Sopenharmony_ci } 1682141cc406Sopenharmony_ci else{ 1683141cc406Sopenharmony_ci tmp = MODE_COLOR; 1684141cc406Sopenharmony_ci } 1685141cc406Sopenharmony_ci 1686141cc406Sopenharmony_ci if (tmp == s->mode) 1687141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1688141cc406Sopenharmony_ci 1689141cc406Sopenharmony_ci s->mode = tmp; 1690141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1691141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1692141cc406Sopenharmony_ci 1693141cc406Sopenharmony_ci case OPT_RES: 1694141cc406Sopenharmony_ci 1695141cc406Sopenharmony_ci if (s->resolution == val_c) 1696141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1697141cc406Sopenharmony_ci 1698141cc406Sopenharmony_ci s->resolution = val_c; 1699141cc406Sopenharmony_ci 1700141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1701141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1702141cc406Sopenharmony_ci 1703141cc406Sopenharmony_ci /* Geometry Group */ 1704141cc406Sopenharmony_ci case OPT_TL_X: 1705141cc406Sopenharmony_ci if (s->tl_x == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1706141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1707141cc406Sopenharmony_ci 1708141cc406Sopenharmony_ci s->tl_x = FIXED_MM_TO_SCANNER_UNIT(val_c); 1709141cc406Sopenharmony_ci 1710141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1711141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1712141cc406Sopenharmony_ci 1713141cc406Sopenharmony_ci case OPT_TL_Y: 1714141cc406Sopenharmony_ci if (s->tl_y == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1715141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1716141cc406Sopenharmony_ci 1717141cc406Sopenharmony_ci s->tl_y = FIXED_MM_TO_SCANNER_UNIT(val_c); 1718141cc406Sopenharmony_ci 1719141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1720141cc406Sopenharmony_ci return change_params(s); 1721141cc406Sopenharmony_ci 1722141cc406Sopenharmony_ci case OPT_BR_X: 1723141cc406Sopenharmony_ci if (s->br_x == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1724141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1725141cc406Sopenharmony_ci 1726141cc406Sopenharmony_ci s->br_x = FIXED_MM_TO_SCANNER_UNIT(val_c); 1727141cc406Sopenharmony_ci 1728141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1729141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1730141cc406Sopenharmony_ci 1731141cc406Sopenharmony_ci case OPT_BR_Y: 1732141cc406Sopenharmony_ci if (s->br_y == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1733141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1734141cc406Sopenharmony_ci 1735141cc406Sopenharmony_ci s->br_y = FIXED_MM_TO_SCANNER_UNIT(val_c); 1736141cc406Sopenharmony_ci 1737141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1738141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1739141cc406Sopenharmony_ci 1740141cc406Sopenharmony_ci case OPT_PAGE_WIDTH: 1741141cc406Sopenharmony_ci if (s->page_width == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1742141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1743141cc406Sopenharmony_ci 1744141cc406Sopenharmony_ci s->page_width = FIXED_MM_TO_SCANNER_UNIT(val_c); 1745141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1746141cc406Sopenharmony_ci return change_params(s); 1747141cc406Sopenharmony_ci 1748141cc406Sopenharmony_ci case OPT_PAGE_HEIGHT: 1749141cc406Sopenharmony_ci if (s->page_height == FIXED_MM_TO_SCANNER_UNIT(val_c)) 1750141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1751141cc406Sopenharmony_ci 1752141cc406Sopenharmony_ci s->page_height = FIXED_MM_TO_SCANNER_UNIT(val_c); 1753141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 1754141cc406Sopenharmony_ci return change_params(s); 1755141cc406Sopenharmony_ci 1756141cc406Sopenharmony_ci /* Enhancement Group */ 1757141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1758141cc406Sopenharmony_ci s->brightness = val_c; 1759141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1760141cc406Sopenharmony_ci 1761141cc406Sopenharmony_ci case OPT_CONTRAST: 1762141cc406Sopenharmony_ci s->contrast = val_c; 1763141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1764141cc406Sopenharmony_ci 1765141cc406Sopenharmony_ci case OPT_GAMMA: 1766141cc406Sopenharmony_ci s->gamma = SANE_UNFIX(val_c); 1767141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1768141cc406Sopenharmony_ci 1769141cc406Sopenharmony_ci case OPT_THRESHOLD: 1770141cc406Sopenharmony_ci s->threshold = val_c; 1771141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1772141cc406Sopenharmony_ci 1773141cc406Sopenharmony_ci case OPT_THRESHOLD_CURVE: 1774141cc406Sopenharmony_ci s->threshold_curve = val_c; 1775141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1776141cc406Sopenharmony_ci 1777141cc406Sopenharmony_ci } /* switch */ 1778141cc406Sopenharmony_ci } /* else */ 1779141cc406Sopenharmony_ci 1780141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1781141cc406Sopenharmony_ci} 1782141cc406Sopenharmony_ci 1783141cc406Sopenharmony_ci/* use height and width to initialize rest of transfer vals */ 1784141cc406Sopenharmony_cistatic void 1785141cc406Sopenharmony_ciupdate_transfer_totals(struct transfer * t) 1786141cc406Sopenharmony_ci{ 1787141cc406Sopenharmony_ci if (t->image == NULL) return; 1788141cc406Sopenharmony_ci 1789141cc406Sopenharmony_ci t->total_bytes = t->line_stride * t->image->height; 1790141cc406Sopenharmony_ci t->rx_bytes = 0; 1791141cc406Sopenharmony_ci t->done = 0; 1792141cc406Sopenharmony_ci} 1793141cc406Sopenharmony_ci 1794141cc406Sopenharmony_ci/* each model has various settings that differ based on X resolution */ 1795141cc406Sopenharmony_ci/* we hard-code the list (determined from usb snoops) here */ 1796141cc406Sopenharmony_cistruct model_res { 1797141cc406Sopenharmony_ci int model; 1798141cc406Sopenharmony_ci int mode; 1799141cc406Sopenharmony_ci int x_res; 1800141cc406Sopenharmony_ci int y_res; 1801141cc406Sopenharmony_ci int usb_power; 1802141cc406Sopenharmony_ci 1803141cc406Sopenharmony_ci int max_x; 1804141cc406Sopenharmony_ci int min_x; 1805141cc406Sopenharmony_ci int max_y; 1806141cc406Sopenharmony_ci int min_y; 1807141cc406Sopenharmony_ci 1808141cc406Sopenharmony_ci int line_stride; /* byte width of 1 raw side, with padding */ 1809141cc406Sopenharmony_ci int plane_stride; /* byte width of 1 raw color plane, with padding */ 1810141cc406Sopenharmony_ci int plane_width; /* byte width of 1 raw color plane, without padding */ 1811141cc406Sopenharmony_ci 1812141cc406Sopenharmony_ci int block_height; 1813141cc406Sopenharmony_ci 1814141cc406Sopenharmony_ci int cal_line_stride; 1815141cc406Sopenharmony_ci int cal_plane_stride; 1816141cc406Sopenharmony_ci int cal_plane_width; 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci unsigned char * sw_coarsecal; 1819141cc406Sopenharmony_ci unsigned char * sw_finecal; 1820141cc406Sopenharmony_ci unsigned char * sw_sendcal; 1821141cc406Sopenharmony_ci 1822141cc406Sopenharmony_ci unsigned char * head_cal1; 1823141cc406Sopenharmony_ci unsigned char * head_cal2; 1824141cc406Sopenharmony_ci unsigned char * sw_scan; 1825141cc406Sopenharmony_ci 1826141cc406Sopenharmony_ci}; 1827141cc406Sopenharmony_ci 1828141cc406Sopenharmony_cistatic struct model_res settings[] = { 1829141cc406Sopenharmony_ci 1830141cc406Sopenharmony_ci /*S300 AC*/ 1831141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1832141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592, 1833141cc406Sopenharmony_ci setWindowCoarseCal_S300_150, setWindowFineCal_S300_150, 1834141cc406Sopenharmony_ci setWindowSendCal_S300_150, sendCal1Header_S300_150, 1835141cc406Sopenharmony_ci sendCal2Header_S300_150, setWindowScan_S300_150 }, 1836141cc406Sopenharmony_ci 1837141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 225, 200, 0, 1944, 32, 3993, 32, 6144*3, 2100*3, 1944, 28, 8192*3, 2800*3, 2592, 1838141cc406Sopenharmony_ci setWindowCoarseCal_S300_225, setWindowFineCal_S300_225, 1839141cc406Sopenharmony_ci setWindowSendCal_S300_225, sendCal1Header_S300_225, 1840141cc406Sopenharmony_ci sendCal2Header_S300_225, setWindowScan_S300_225 }, 1841141cc406Sopenharmony_ci 1842141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 300, 300, 0, 2592, 32, 5324, 32, 8192*3, 2800*3, 2592, 21, 8192*3, 2800*3, 2592, 1843141cc406Sopenharmony_ci setWindowCoarseCal_S300_300, setWindowFineCal_S300_300, 1844141cc406Sopenharmony_ci setWindowSendCal_S300_300, sendCal1Header_S300_300, 1845141cc406Sopenharmony_ci sendCal2Header_S300_300, setWindowScan_S300_300 }, 1846141cc406Sopenharmony_ci 1847141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, 1848141cc406Sopenharmony_ci setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, 1849141cc406Sopenharmony_ci setWindowSendCal_S300_600, sendCal1Header_S300_600, 1850141cc406Sopenharmony_ci sendCal2Header_S300_600, setWindowScan_S300_600 }, 1851141cc406Sopenharmony_ci 1852141cc406Sopenharmony_ci /*S300 USB*/ 1853141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1854141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, 1855141cc406Sopenharmony_ci setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U, 1856141cc406Sopenharmony_ci setWindowSendCal_S300_150_U, sendCal1Header_S300_150_U, 1857141cc406Sopenharmony_ci sendCal2Header_S300_150_U, setWindowScan_S300_150_U }, 1858141cc406Sopenharmony_ci 1859141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, 1860141cc406Sopenharmony_ci setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U, 1861141cc406Sopenharmony_ci setWindowSendCal_S300_225_U, sendCal1Header_S300_225_U, 1862141cc406Sopenharmony_ci sendCal2Header_S300_225_U, setWindowScan_S300_225_U }, 1863141cc406Sopenharmony_ci 1864141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, 1865141cc406Sopenharmony_ci setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U, 1866141cc406Sopenharmony_ci setWindowSendCal_S300_300_U, sendCal1Header_S300_300_U, 1867141cc406Sopenharmony_ci sendCal2Header_S300_300_U, setWindowScan_S300_300_U }, 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci { MODEL_S300, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, 1870141cc406Sopenharmony_ci setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, 1871141cc406Sopenharmony_ci setWindowSendCal_S300_600, sendCal1Header_S300_600, 1872141cc406Sopenharmony_ci sendCal2Header_S300_600, setWindowScan_S300_600 }, 1873141cc406Sopenharmony_ci 1874141cc406Sopenharmony_ci /*S1300i AC*/ 1875141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1876141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4016*3, 1360*3, 1296, 43, 8032*3, 2720*3, 2592, 1877141cc406Sopenharmony_ci setWindowCoarseCal_S1300i_150, setWindowFineCal_S1300i_150, 1878141cc406Sopenharmony_ci setWindowSendCal_S1300i_150, sendCal1Header_S1300i_150, 1879141cc406Sopenharmony_ci sendCal2Header_S1300i_150, setWindowScan_S1300i_150 }, 1880141cc406Sopenharmony_ci 1881141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 225, 200, 0, 1944, 32, 3993, 32, 6072*3, 2063*3, 1944, 28, 8096*3, 2752*3, 2592, 1882141cc406Sopenharmony_ci setWindowCoarseCal_S1300i_225, setWindowFineCal_S1300i_225, 1883141cc406Sopenharmony_ci setWindowSendCal_S1300i_225, sendCal1Header_S1300i_225, 1884141cc406Sopenharmony_ci sendCal2Header_S1300i_225, setWindowScan_S1300i_225 }, 1885141cc406Sopenharmony_ci 1886141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 300, 300, 0, 2592, 32, 5324, 32, 8096*3, 2751*3, 2592, 21, 8096*3, 2752*3, 2592, 1887141cc406Sopenharmony_ci setWindowCoarseCal_S1300i_300, setWindowFineCal_S1300i_300, 1888141cc406Sopenharmony_ci setWindowSendCal_S1300i_300, sendCal1Header_S1300i_300, 1889141cc406Sopenharmony_ci sendCal2Header_S1300i_300, setWindowScan_S1300i_300 }, 1890141cc406Sopenharmony_ci 1891141cc406Sopenharmony_ci /*NOTE: S1300i uses S300 data blocks for remainder*/ 1892141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, 1893141cc406Sopenharmony_ci setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, 1894141cc406Sopenharmony_ci setWindowSendCal_S300_600, sendCal1Header_S300_600, 1895141cc406Sopenharmony_ci sendCal2Header_S300_600, setWindowScan_S300_600 }, 1896141cc406Sopenharmony_ci 1897141cc406Sopenharmony_ci /*S1300i USB*/ 1898141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1899141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, 1900141cc406Sopenharmony_ci setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U, 1901141cc406Sopenharmony_ci setWindowSendCal_S300_150_U, sendCal1Header_S1300i_USB, 1902141cc406Sopenharmony_ci sendCal2Header_S1300i_USB, setWindowScan_S300_150_U }, 1903141cc406Sopenharmony_ci 1904141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, 1905141cc406Sopenharmony_ci setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U, 1906141cc406Sopenharmony_ci setWindowSendCal_S300_225_U, sendCal1Header_S1300i_USB, 1907141cc406Sopenharmony_ci sendCal2Header_S1300i_USB, setWindowScan_S300_225_U }, 1908141cc406Sopenharmony_ci 1909141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, 1910141cc406Sopenharmony_ci setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U, 1911141cc406Sopenharmony_ci setWindowSendCal_S300_300_U, sendCal1Header_S1300i_USB, 1912141cc406Sopenharmony_ci sendCal2Header_S1300i_USB, setWindowScan_S300_300_U }, 1913141cc406Sopenharmony_ci 1914141cc406Sopenharmony_ci { MODEL_S1300i, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, 1915141cc406Sopenharmony_ci setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, 1916141cc406Sopenharmony_ci setWindowSendCal_S300_600, sendCal1Header_S1300i_USB, 1917141cc406Sopenharmony_ci sendCal2Header_S1300i_USB, setWindowScan_S300_600 }, 1918141cc406Sopenharmony_ci 1919141cc406Sopenharmony_ci /*fi-60F/65F GRAY */ 1920141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1921141cc406Sopenharmony_ci/* disabled until calibration code supports grayscale 1922141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 300, 300, 0, 1296, 32, 1749, 32, 1440, 480, 432, 364, 2400*3, 958*3, 432, 1923141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, 1924141cc406Sopenharmony_ci setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, 1925141cc406Sopenharmony_ci sendCal2Header_FI60F_300, setWindowScan_FI60F_300_g }, 1926141cc406Sopenharmony_ci 1927141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 600, 400, 0, 2592, 32, 2332, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, 1928141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, 1929141cc406Sopenharmony_ci setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, 1930141cc406Sopenharmony_ci sendCal2Header_FI60F_600, setWindowScan_FI60F_400_g }, 1931141cc406Sopenharmony_ci 1932141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 600, 600, 0, 2592, 32, 3498, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, 1933141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, 1934141cc406Sopenharmony_ci setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, 1935141cc406Sopenharmony_ci sendCal2Header_FI60F_600, setWindowScan_FI60F_600_g }, 1936141cc406Sopenharmony_ci*/ 1937141cc406Sopenharmony_ci 1938141cc406Sopenharmony_ci /*fi-60F/65F*/ 1939141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1940141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, 1941141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, 1942141cc406Sopenharmony_ci setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, 1943141cc406Sopenharmony_ci sendCal2Header_FI60F_300, setWindowScan_FI60F_150 }, 1944141cc406Sopenharmony_ci 1945141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 200, 0, 1296, 32, 1166, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, 1946141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, 1947141cc406Sopenharmony_ci setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, 1948141cc406Sopenharmony_ci sendCal2Header_FI60F_300, setWindowScan_FI60F_200 }, 1949141cc406Sopenharmony_ci 1950141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, 1951141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, 1952141cc406Sopenharmony_ci setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, 1953141cc406Sopenharmony_ci sendCal2Header_FI60F_300, setWindowScan_FI60F_300 }, 1954141cc406Sopenharmony_ci 1955141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 600, 400, 0, 2592, 32, 2332, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, 1956141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, 1957141cc406Sopenharmony_ci setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, 1958141cc406Sopenharmony_ci sendCal2Header_FI60F_600, setWindowScan_FI60F_400 }, 1959141cc406Sopenharmony_ci 1960141cc406Sopenharmony_ci { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, 1961141cc406Sopenharmony_ci setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, 1962141cc406Sopenharmony_ci setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, 1963141cc406Sopenharmony_ci sendCal2Header_FI60F_600, setWindowScan_FI60F_600 }, 1964141cc406Sopenharmony_ci 1965141cc406Sopenharmony_ci /*S1100 USB*/ 1966141cc406Sopenharmony_ci/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ 1967141cc406Sopenharmony_ci { MODEL_S1100, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 8912, 3160, 2592, 58, 8912, 3160, 2592, 1968141cc406Sopenharmony_ci setWindowCoarseCal_S1100_300_U, setWindowFineCal_S1100_300_U, 1969141cc406Sopenharmony_ci setWindowSendCal_S1100_300_U, sendCal1Header_S1100_300_U, 1970141cc406Sopenharmony_ci sendCal2Header_S1100_300_U, setWindowScan_S1100_300_U }, 1971141cc406Sopenharmony_ci 1972141cc406Sopenharmony_ci { MODEL_S1100, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 15904, 5360, 5184, 32, 15904, 5360, 5184, 1973141cc406Sopenharmony_ci setWindowCoarseCal_S1100_600_U, setWindowFineCal_S1100_600_U, 1974141cc406Sopenharmony_ci setWindowSendCal_S1100_600_U, sendCal1Header_S1100_600_U, 1975141cc406Sopenharmony_ci sendCal2Header_S1100_600_U, setWindowScan_S1100_600_U }, 1976141cc406Sopenharmony_ci 1977141cc406Sopenharmony_ci { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1978141cc406Sopenharmony_ci NULL, NULL, NULL, NULL, NULL, NULL }, 1979141cc406Sopenharmony_ci 1980141cc406Sopenharmony_ci}; 1981141cc406Sopenharmony_ci 1982141cc406Sopenharmony_ci/* 1983141cc406Sopenharmony_ci * clean up scanner struct vals when user changes mode, res, etc 1984141cc406Sopenharmony_ci */ 1985141cc406Sopenharmony_cistatic SANE_Status 1986141cc406Sopenharmony_cichange_params(struct scanner *s) 1987141cc406Sopenharmony_ci{ 1988141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 1989141cc406Sopenharmony_ci 1990141cc406Sopenharmony_ci int img_heads, img_pages, width; 1991141cc406Sopenharmony_ci int i=0; 1992141cc406Sopenharmony_ci 1993141cc406Sopenharmony_ci DBG (10, "change_params: start\n"); 1994141cc406Sopenharmony_ci 1995141cc406Sopenharmony_ci do { 1996141cc406Sopenharmony_ci if(settings[i].model & s->model 1997141cc406Sopenharmony_ci && settings[i].mode <= s->mode 1998141cc406Sopenharmony_ci && settings[i].x_res >= s->resolution 1999141cc406Sopenharmony_ci && settings[i].y_res >= s->resolution 2000141cc406Sopenharmony_ci && settings[i].usb_power == s->usb_power 2001141cc406Sopenharmony_ci ){ 2002141cc406Sopenharmony_ci break; 2003141cc406Sopenharmony_ci } 2004141cc406Sopenharmony_ci i++; 2005141cc406Sopenharmony_ci } while (settings[i].model); 2006141cc406Sopenharmony_ci 2007141cc406Sopenharmony_ci if (!settings[i].model){ 2008141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2009141cc406Sopenharmony_ci } 2010141cc406Sopenharmony_ci 2011141cc406Sopenharmony_ci /*1200 dpi*/ 2012141cc406Sopenharmony_ci s->max_x = PIX_TO_SCANNER_UNIT( settings[i].max_x, settings[i].x_res ); 2013141cc406Sopenharmony_ci s->min_x = PIX_TO_SCANNER_UNIT( settings[i].min_x, settings[i].x_res ); 2014141cc406Sopenharmony_ci s->max_y = PIX_TO_SCANNER_UNIT( settings[i].max_y, settings[i].y_res ); 2015141cc406Sopenharmony_ci s->min_y = PIX_TO_SCANNER_UNIT( settings[i].min_y, settings[i].y_res ); 2016141cc406Sopenharmony_ci 2017141cc406Sopenharmony_ci /*current dpi*/ 2018141cc406Sopenharmony_ci s->setWindowCoarseCal = settings[i].sw_coarsecal; 2019141cc406Sopenharmony_ci s->setWindowCoarseCalLen = SET_WINDOW_LEN; 2020141cc406Sopenharmony_ci 2021141cc406Sopenharmony_ci s->setWindowFineCal = settings[i].sw_finecal; 2022141cc406Sopenharmony_ci s->setWindowFineCalLen = SET_WINDOW_LEN; 2023141cc406Sopenharmony_ci 2024141cc406Sopenharmony_ci s->setWindowSendCal = settings[i].sw_sendcal; 2025141cc406Sopenharmony_ci s->setWindowSendCalLen = SET_WINDOW_LEN; 2026141cc406Sopenharmony_ci 2027141cc406Sopenharmony_ci s->sendCal1Header = settings[i].head_cal1; 2028141cc406Sopenharmony_ci s->sendCal1HeaderLen = 14; 2029141cc406Sopenharmony_ci 2030141cc406Sopenharmony_ci s->sendCal2Header = settings[i].head_cal2; 2031141cc406Sopenharmony_ci s->sendCal2HeaderLen = 7; 2032141cc406Sopenharmony_ci 2033141cc406Sopenharmony_ci s->setWindowScan = settings[i].sw_scan; 2034141cc406Sopenharmony_ci s->setWindowScanLen = SET_WINDOW_LEN; 2035141cc406Sopenharmony_ci 2036141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) 2037141cc406Sopenharmony_ci { 2038141cc406Sopenharmony_ci img_heads = 1; /* image width is the same as the plane width on the S300 */ 2039141cc406Sopenharmony_ci img_pages = 2; 2040141cc406Sopenharmony_ci } 2041141cc406Sopenharmony_ci else if (s->model == MODEL_S1100) 2042141cc406Sopenharmony_ci { 2043141cc406Sopenharmony_ci img_heads = 1; /* image width is the same as the plane width on the S1000 */ 2044141cc406Sopenharmony_ci img_pages = 1; 2045141cc406Sopenharmony_ci } 2046141cc406Sopenharmony_ci else /* MODEL_FI60F or MODEL_FI65F */ 2047141cc406Sopenharmony_ci { 2048141cc406Sopenharmony_ci img_heads = 3; /* image width is 3* the plane width on the FI-60F */ 2049141cc406Sopenharmony_ci img_pages = 1; 2050141cc406Sopenharmony_ci } 2051141cc406Sopenharmony_ci 2052141cc406Sopenharmony_ci /* height */ 2053141cc406Sopenharmony_ci if (s->tl_y > s->max_y - s->min_y) 2054141cc406Sopenharmony_ci s->tl_y = s->max_y - s->min_y - s->adf_height_padding; 2055141cc406Sopenharmony_ci s->page_height = MIN(s->page_height, s->max_y - s->adf_height_padding - s->tl_y); 2056141cc406Sopenharmony_ci if (s->page_height > 0) 2057141cc406Sopenharmony_ci s->page_height = MAX(s->page_height, s->min_y); 2058141cc406Sopenharmony_ci if (s->tl_y + s->page_height > s->max_y) 2059141cc406Sopenharmony_ci s->tl_y = s->max_y - s->adf_height_padding - s->page_height; 2060141cc406Sopenharmony_ci s->tl_y = MAX(s->tl_y, 0); 2061141cc406Sopenharmony_ci 2062141cc406Sopenharmony_ci if (s->page_height > 0) { 2063141cc406Sopenharmony_ci s->br_y = s->tl_y + s->page_height; 2064141cc406Sopenharmony_ci } 2065141cc406Sopenharmony_ci else { 2066141cc406Sopenharmony_ci s->br_y = s->max_y; 2067141cc406Sopenharmony_ci } 2068141cc406Sopenharmony_ci 2069141cc406Sopenharmony_ci /*width*/ 2070141cc406Sopenharmony_ci s->page_width = MIN(s->page_width, s->max_x); 2071141cc406Sopenharmony_ci s->page_width = MAX(s->page_width, s->min_x); 2072141cc406Sopenharmony_ci 2073141cc406Sopenharmony_ci s->tl_x = (s->max_x - s->page_width)/2; 2074141cc406Sopenharmony_ci s->br_x = (s->max_x + s->page_width)/2; 2075141cc406Sopenharmony_ci 2076141cc406Sopenharmony_ci /*=============================================================*/ 2077141cc406Sopenharmony_ci /* set up the calibration scan structs */ 2078141cc406Sopenharmony_ci /* generally full width, short height, full resolution */ 2079141cc406Sopenharmony_ci s->cal_image.line_stride = settings[i].cal_line_stride; 2080141cc406Sopenharmony_ci s->cal_image.plane_stride = settings[i].cal_plane_stride; 2081141cc406Sopenharmony_ci s->cal_image.plane_width = settings[i].cal_plane_width; 2082141cc406Sopenharmony_ci s->cal_image.mode = MODE_COLOR; 2083141cc406Sopenharmony_ci s->cal_image.x_res = settings[i].x_res; 2084141cc406Sopenharmony_ci s->cal_image.y_res = settings[i].y_res; 2085141cc406Sopenharmony_ci s->cal_image.raw_data = NULL; 2086141cc406Sopenharmony_ci s->cal_image.image = NULL; 2087141cc406Sopenharmony_ci 2088141cc406Sopenharmony_ci /* width is the same, but there are 2 bytes per pixel component */ 2089141cc406Sopenharmony_ci s->cal_data.line_stride = settings[i].cal_line_stride * 2; 2090141cc406Sopenharmony_ci s->cal_data.plane_stride = settings[i].cal_plane_stride * 2; 2091141cc406Sopenharmony_ci s->cal_data.plane_width = settings[i].cal_plane_width; 2092141cc406Sopenharmony_ci s->cal_data.mode = MODE_COLOR; 2093141cc406Sopenharmony_ci s->cal_data.x_res = settings[i].x_res; 2094141cc406Sopenharmony_ci s->cal_data.y_res = settings[i].y_res; 2095141cc406Sopenharmony_ci s->cal_data.raw_data = NULL; 2096141cc406Sopenharmony_ci s->cal_data.image = &s->sendcal; 2097141cc406Sopenharmony_ci 2098141cc406Sopenharmony_ci /*=============================================================*/ 2099141cc406Sopenharmony_ci /* set up the calibration image blocks */ 2100141cc406Sopenharmony_ci width = s->cal_image.plane_width * img_heads; 2101141cc406Sopenharmony_ci s->coarsecal.width_pix = s->darkcal.width_pix = s->lightcal.width_pix = width; 2102141cc406Sopenharmony_ci s->coarsecal.width_bytes = s->darkcal.width_bytes = s->lightcal.width_bytes = width * 3; 2103141cc406Sopenharmony_ci s->coarsecal.height = 1; 2104141cc406Sopenharmony_ci s->coarsecal.mode = MODE_COLOR; 2105141cc406Sopenharmony_ci s->coarsecal.x_res = s->darkcal.x_res = s->lightcal.x_res = settings[i].x_res; 2106141cc406Sopenharmony_ci s->coarsecal.y_res = s->darkcal.y_res = s->lightcal.y_res = settings[i].y_res; 2107141cc406Sopenharmony_ci s->darkcal.height = s->lightcal.height = 16; 2108141cc406Sopenharmony_ci s->coarsecal.pages = s->darkcal.pages = s->lightcal.pages = img_pages; 2109141cc406Sopenharmony_ci s->coarsecal.buffer = s->darkcal.buffer = s->lightcal.buffer = NULL; 2110141cc406Sopenharmony_ci 2111141cc406Sopenharmony_ci /* set up the calibration data block */ 2112141cc406Sopenharmony_ci width = s->cal_data.plane_width * img_heads; 2113141cc406Sopenharmony_ci s->sendcal.width_pix = width; 2114141cc406Sopenharmony_ci s->sendcal.width_bytes = width * 6; /* 2 bytes of cal data per pixel component */ 2115141cc406Sopenharmony_ci s->sendcal.height = 1; 2116141cc406Sopenharmony_ci s->sendcal.mode = MODE_COLOR; 2117141cc406Sopenharmony_ci s->sendcal.x_res = settings[i].x_res; 2118141cc406Sopenharmony_ci s->sendcal.y_res = settings[i].y_res; 2119141cc406Sopenharmony_ci s->sendcal.pages = img_pages; 2120141cc406Sopenharmony_ci s->sendcal.buffer = NULL; 2121141cc406Sopenharmony_ci 2122141cc406Sopenharmony_ci /*=============================================================*/ 2123141cc406Sopenharmony_ci /* set up the fullscan parameters */ 2124141cc406Sopenharmony_ci /* this is bookkeeping for what we actually pull from the scanner */ 2125141cc406Sopenharmony_ci /* note that this has no image, just dimensions and counters */ 2126141cc406Sopenharmony_ci s->fullscan.width_bytes = settings[i].line_stride; 2127141cc406Sopenharmony_ci s->fullscan.mode = settings[i].mode; 2128141cc406Sopenharmony_ci s->fullscan.x_res = settings[i].x_res; 2129141cc406Sopenharmony_ci s->fullscan.y_res = settings[i].y_res; 2130141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED || !s->page_height) 2131141cc406Sopenharmony_ci { 2132141cc406Sopenharmony_ci /* flatbed and adf in autodetect always ask for all*/ 2133141cc406Sopenharmony_ci s->fullscan.height = SCANNER_UNIT_TO_PIX(s->max_y, s->fullscan.y_res); 2134141cc406Sopenharmony_ci } 2135141cc406Sopenharmony_ci else 2136141cc406Sopenharmony_ci { 2137141cc406Sopenharmony_ci /* adf with specified paper size requires padding on top of page_height (~1/2in) */ 2138141cc406Sopenharmony_ci s->fullscan.height = SCANNER_UNIT_TO_PIX((s->page_height + s->tl_y + s->adf_height_padding), s->fullscan.y_res); 2139141cc406Sopenharmony_ci } 2140141cc406Sopenharmony_ci 2141141cc406Sopenharmony_ci /*=============================================================*/ 2142141cc406Sopenharmony_ci /* set up the input block raw struct */ 2143141cc406Sopenharmony_ci /* this holds up to 512k of raw scan data */ 2144141cc406Sopenharmony_ci s->block_xfr.line_stride = settings[i].line_stride; 2145141cc406Sopenharmony_ci s->block_xfr.plane_stride = settings[i].plane_stride; 2146141cc406Sopenharmony_ci s->block_xfr.plane_width = settings[i].plane_width; 2147141cc406Sopenharmony_ci s->block_xfr.mode = settings[i].mode; 2148141cc406Sopenharmony_ci s->block_xfr.x_res = settings[i].x_res; 2149141cc406Sopenharmony_ci s->block_xfr.y_res = settings[i].y_res; 2150141cc406Sopenharmony_ci s->block_xfr.raw_data = NULL; 2151141cc406Sopenharmony_ci s->block_xfr.image = &s->block_img; 2152141cc406Sopenharmony_ci 2153141cc406Sopenharmony_ci /* set up the input block image struct */ 2154141cc406Sopenharmony_ci /* note that this is the same width/x_res as the final output image */ 2155141cc406Sopenharmony_ci /* but the mode, height and y_res are the same as block_xfr */ 2156141cc406Sopenharmony_ci width = (settings[i].max_x * s->resolution / settings[i].x_res); 2157141cc406Sopenharmony_ci s->block_img.width_pix = width; 2158141cc406Sopenharmony_ci s->block_img.width_bytes = width * (settings[i].mode == MODE_COLOR ? 3 : 1); 2159141cc406Sopenharmony_ci s->block_img.height = settings[i].block_height; 2160141cc406Sopenharmony_ci s->block_img.mode = settings[i].mode; 2161141cc406Sopenharmony_ci s->block_img.x_res = s->resolution; 2162141cc406Sopenharmony_ci s->block_img.y_res = settings[i].y_res; 2163141cc406Sopenharmony_ci s->block_img.pages = img_pages; 2164141cc406Sopenharmony_ci s->block_img.buffer = NULL; 2165141cc406Sopenharmony_ci 2166141cc406Sopenharmony_ci /*=============================================================*/ 2167141cc406Sopenharmony_ci /* set up the output image structs */ 2168141cc406Sopenharmony_ci /* output image might be different from scan due to interpolation */ 2169141cc406Sopenharmony_ci s->front.mode = s->mode; 2170141cc406Sopenharmony_ci s->front.x_res = s->resolution; 2171141cc406Sopenharmony_ci s->front.y_res = s->resolution; 2172141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED) 2173141cc406Sopenharmony_ci { 2174141cc406Sopenharmony_ci /* flatbed ignores the tly */ 2175141cc406Sopenharmony_ci s->front.height = SCANNER_UNIT_TO_PIX(s->max_y - s->tl_y, s->front.y_res); 2176141cc406Sopenharmony_ci } 2177141cc406Sopenharmony_ci else if(!s->page_height) 2178141cc406Sopenharmony_ci { 2179141cc406Sopenharmony_ci /* adf in autodetect always asks for all */ 2180141cc406Sopenharmony_ci s->front.height = SCANNER_UNIT_TO_PIX(s->max_y, s->front.y_res); 2181141cc406Sopenharmony_ci } 2182141cc406Sopenharmony_ci else 2183141cc406Sopenharmony_ci { 2184141cc406Sopenharmony_ci /* adf with specified paper size */ 2185141cc406Sopenharmony_ci s->front.height = SCANNER_UNIT_TO_PIX(s->page_height, s->front.y_res); 2186141cc406Sopenharmony_ci } 2187141cc406Sopenharmony_ci s->front.width_pix = SCANNER_UNIT_TO_PIX(s->page_width, s->resolution * img_heads); 2188141cc406Sopenharmony_ci s->front.x_start_offset = (s->block_xfr.image->width_pix - s->front.width_pix)/2; 2189141cc406Sopenharmony_ci switch (s->mode) { 2190141cc406Sopenharmony_ci case MODE_COLOR: 2191141cc406Sopenharmony_ci s->front.width_bytes = s->front.width_pix*3; 2192141cc406Sopenharmony_ci s->front.x_offset_bytes = s->front.x_start_offset *3; 2193141cc406Sopenharmony_ci break; 2194141cc406Sopenharmony_ci case MODE_GRAYSCALE: 2195141cc406Sopenharmony_ci s->front.width_bytes = s->front.width_pix; 2196141cc406Sopenharmony_ci s->front.x_offset_bytes = s->front.x_start_offset; 2197141cc406Sopenharmony_ci break; 2198141cc406Sopenharmony_ci default: /*binary*/ 2199141cc406Sopenharmony_ci s->front.width_bytes = s->front.width_pix/8; 2200141cc406Sopenharmony_ci s->front.width_pix = s->front.width_bytes * 8; 2201141cc406Sopenharmony_ci /*s->page_width = PIX_TO_SCANNER_UNIT(s->front.width_pix, (img_heads * s->resolution_x));*/ 2202141cc406Sopenharmony_ci s->front.x_offset_bytes = s->front.x_start_offset/8; 2203141cc406Sopenharmony_ci break; 2204141cc406Sopenharmony_ci } 2205141cc406Sopenharmony_ci 2206141cc406Sopenharmony_ci /* ADF front need to remove padding header */ 2207141cc406Sopenharmony_ci if (s->source != SOURCE_FLATBED) 2208141cc406Sopenharmony_ci { 2209141cc406Sopenharmony_ci s->front.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y+s->adf_height_padding, s->fullscan.y_res); 2210141cc406Sopenharmony_ci } 2211141cc406Sopenharmony_ci else 2212141cc406Sopenharmony_ci { 2213141cc406Sopenharmony_ci s->front.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y, s->fullscan.y_res); 2214141cc406Sopenharmony_ci } 2215141cc406Sopenharmony_ci 2216141cc406Sopenharmony_ci s->front.pages = 1; 2217141cc406Sopenharmony_ci s->front.buffer = NULL; 2218141cc406Sopenharmony_ci 2219141cc406Sopenharmony_ci /* back settings always same as front settings */ 2220141cc406Sopenharmony_ci s->back.width_pix = s->front.width_pix; 2221141cc406Sopenharmony_ci s->back.width_bytes = s->front.width_bytes; 2222141cc406Sopenharmony_ci s->back.mode = s->front.mode; 2223141cc406Sopenharmony_ci s->back.x_res = s->front.x_res; 2224141cc406Sopenharmony_ci s->back.y_res = s->front.y_res; 2225141cc406Sopenharmony_ci s->back.height = s->front.height; 2226141cc406Sopenharmony_ci s->back.x_start_offset = s->front.x_start_offset; 2227141cc406Sopenharmony_ci s->back.x_offset_bytes = s->front.x_offset_bytes; 2228141cc406Sopenharmony_ci s->back.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y, s->fullscan.y_res); 2229141cc406Sopenharmony_ci s->back.pages = 1; 2230141cc406Sopenharmony_ci s->back.buffer = NULL; 2231141cc406Sopenharmony_ci 2232141cc406Sopenharmony_ci /* dynamic threshold temp buffer, in gray */ 2233141cc406Sopenharmony_ci s->dt.width_pix = s->front.width_pix; 2234141cc406Sopenharmony_ci s->dt.width_bytes = s->front.width_pix; 2235141cc406Sopenharmony_ci s->dt.mode = MODE_GRAYSCALE; 2236141cc406Sopenharmony_ci s->dt.x_res = s->front.x_res; 2237141cc406Sopenharmony_ci s->dt.y_res = s->front.y_res; 2238141cc406Sopenharmony_ci s->dt.height = 1; 2239141cc406Sopenharmony_ci s->dt.pages = 1; 2240141cc406Sopenharmony_ci s->dt.buffer = NULL; 2241141cc406Sopenharmony_ci 2242141cc406Sopenharmony_ci /* set up the pointers to the page images in the page structs */ 2243141cc406Sopenharmony_ci s->pages[SIDE_FRONT].image = &s->front; 2244141cc406Sopenharmony_ci s->pages[SIDE_BACK].image = &s->back; 2245141cc406Sopenharmony_ci s->pages[SIDE_FRONT].done = 0; 2246141cc406Sopenharmony_ci s->pages[SIDE_BACK].done = 0; 2247141cc406Sopenharmony_ci 2248141cc406Sopenharmony_ci DBG (10, "change_params: finish\n"); 2249141cc406Sopenharmony_ci 2250141cc406Sopenharmony_ci return ret; 2251141cc406Sopenharmony_ci} 2252141cc406Sopenharmony_ci 2253141cc406Sopenharmony_ci/* Function to build a lookup table (LUT), often 2254141cc406Sopenharmony_ci used by scanners to implement brightness/contrast/gamma 2255141cc406Sopenharmony_ci or by backends to speed binarization/thresholding 2256141cc406Sopenharmony_ci 2257141cc406Sopenharmony_ci offset and slope inputs are -127 to +127 2258141cc406Sopenharmony_ci 2259141cc406Sopenharmony_ci slope rotates line around central input/output val, 2260141cc406Sopenharmony_ci 0 makes horizontal line 2261141cc406Sopenharmony_ci 2262141cc406Sopenharmony_ci pos zero neg 2263141cc406Sopenharmony_ci . x . . x 2264141cc406Sopenharmony_ci . x . . x 2265141cc406Sopenharmony_ci out . x .xxxxxxxxxxx . x 2266141cc406Sopenharmony_ci . x . . x 2267141cc406Sopenharmony_ci ....x....... ............ .......x.... 2268141cc406Sopenharmony_ci in in in 2269141cc406Sopenharmony_ci 2270141cc406Sopenharmony_ci offset moves line vertically, and clamps to output range 2271141cc406Sopenharmony_ci 0 keeps the line crossing the center of the table 2272141cc406Sopenharmony_ci 2273141cc406Sopenharmony_ci high low 2274141cc406Sopenharmony_ci . xxxxxxxx . 2275141cc406Sopenharmony_ci . x . 2276141cc406Sopenharmony_ci out x . x 2277141cc406Sopenharmony_ci . . x 2278141cc406Sopenharmony_ci ............ xxxxxxxx.... 2279141cc406Sopenharmony_ci in in 2280141cc406Sopenharmony_ci 2281141cc406Sopenharmony_ci out_min/max provide bounds on output values, 2282141cc406Sopenharmony_ci useful when building thresholding lut. 2283141cc406Sopenharmony_ci 0 and 255 are good defaults otherwise. 2284141cc406Sopenharmony_ci */ 2285141cc406Sopenharmony_cistatic SANE_Status 2286141cc406Sopenharmony_ciload_lut (unsigned char * lut, 2287141cc406Sopenharmony_ci int in_bits, int out_bits, 2288141cc406Sopenharmony_ci int out_min, int out_max, 2289141cc406Sopenharmony_ci int slope, int offset) 2290141cc406Sopenharmony_ci{ 2291141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2292141cc406Sopenharmony_ci int i, j; 2293141cc406Sopenharmony_ci double shift, rise; 2294141cc406Sopenharmony_ci int max_in_val = (1 << in_bits) - 1; 2295141cc406Sopenharmony_ci int max_out_val = (1 << out_bits) - 1; 2296141cc406Sopenharmony_ci unsigned char * lut_p = lut; 2297141cc406Sopenharmony_ci 2298141cc406Sopenharmony_ci DBG (10, "load_lut: start\n"); 2299141cc406Sopenharmony_ci 2300141cc406Sopenharmony_ci /* slope is converted to rise per unit run: 2301141cc406Sopenharmony_ci * first [-127,127] to [-1,1] 2302141cc406Sopenharmony_ci * then multiply by PI/2 to convert to radians 2303141cc406Sopenharmony_ci * then take the tangent (T.O.A) 2304141cc406Sopenharmony_ci * then multiply by the normal linear slope 2305141cc406Sopenharmony_ci * because the table may not be square, i.e. 1024x256*/ 2306141cc406Sopenharmony_ci rise = tan((double)slope/127 * M_PI/2) * max_out_val / max_in_val; 2307141cc406Sopenharmony_ci 2308141cc406Sopenharmony_ci /* line must stay vertically centered, so figure 2309141cc406Sopenharmony_ci * out vertical offset at central input value */ 2310141cc406Sopenharmony_ci shift = (double)max_out_val/2 - (rise*max_in_val/2); 2311141cc406Sopenharmony_ci 2312141cc406Sopenharmony_ci /* convert the user offset setting to scale of output 2313141cc406Sopenharmony_ci * first [-127,127] to [-1,1] 2314141cc406Sopenharmony_ci * then to [-max_out_val/2,max_out_val/2]*/ 2315141cc406Sopenharmony_ci shift += (double)offset / 127 * max_out_val / 2; 2316141cc406Sopenharmony_ci 2317141cc406Sopenharmony_ci for(i=0;i<=max_in_val;i++){ 2318141cc406Sopenharmony_ci j = rise*i + shift; 2319141cc406Sopenharmony_ci 2320141cc406Sopenharmony_ci j = MAX(j, out_min); 2321141cc406Sopenharmony_ci j = MIN(j, out_max); 2322141cc406Sopenharmony_ci 2323141cc406Sopenharmony_ci *lut_p=j; 2324141cc406Sopenharmony_ci lut_p++; 2325141cc406Sopenharmony_ci } 2326141cc406Sopenharmony_ci 2327141cc406Sopenharmony_ci hexdump(5, "load_lut: ", lut, max_in_val+1); 2328141cc406Sopenharmony_ci 2329141cc406Sopenharmony_ci DBG (10, "load_lut: finish\n"); 2330141cc406Sopenharmony_ci return ret; 2331141cc406Sopenharmony_ci} 2332141cc406Sopenharmony_ci 2333141cc406Sopenharmony_ci/* 2334141cc406Sopenharmony_ci * @@ Section 4 - SANE scanning functions 2335141cc406Sopenharmony_ci */ 2336141cc406Sopenharmony_ci/* 2337141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data 2338141cc406Sopenharmony_ci * that the current scan will return. 2339141cc406Sopenharmony_ci * 2340141cc406Sopenharmony_ci * From the SANE spec: 2341141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The 2342141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time 2343141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the 2344141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned 2345141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be 2346141cc406Sopenharmony_ci * when sane_start() gets invoked. 2347141cc406Sopenharmony_ci * 2348141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows, 2349141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will 2350141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle h of the 2351141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer p 2352141cc406Sopenharmony_ci * to a parameter structure. 2353141cc406Sopenharmony_ci */ 2354141cc406Sopenharmony_ciSANE_Status 2355141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 2356141cc406Sopenharmony_ci{ 2357141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 2358141cc406Sopenharmony_ci 2359141cc406Sopenharmony_ci DBG (10, "sane_get_parameters: start\n"); 2360141cc406Sopenharmony_ci 2361141cc406Sopenharmony_ci params->pixels_per_line = s->front.width_pix; 2362141cc406Sopenharmony_ci params->bytes_per_line = s->front.width_bytes; 2363141cc406Sopenharmony_ci if(!s->page_height){ 2364141cc406Sopenharmony_ci params->lines = -1; 2365141cc406Sopenharmony_ci } 2366141cc406Sopenharmony_ci else{ 2367141cc406Sopenharmony_ci params->lines = s->front.height; 2368141cc406Sopenharmony_ci } 2369141cc406Sopenharmony_ci params->last_frame = 1; 2370141cc406Sopenharmony_ci 2371141cc406Sopenharmony_ci if (s->mode == MODE_COLOR) { 2372141cc406Sopenharmony_ci params->format = SANE_FRAME_RGB; 2373141cc406Sopenharmony_ci params->depth = 8; 2374141cc406Sopenharmony_ci } 2375141cc406Sopenharmony_ci else if (s->mode == MODE_GRAYSCALE) { 2376141cc406Sopenharmony_ci params->format = SANE_FRAME_GRAY; 2377141cc406Sopenharmony_ci params->depth = 8; 2378141cc406Sopenharmony_ci } 2379141cc406Sopenharmony_ci else if (s->mode == MODE_LINEART) { 2380141cc406Sopenharmony_ci params->format = SANE_FRAME_GRAY; 2381141cc406Sopenharmony_ci params->depth = 1; 2382141cc406Sopenharmony_ci } 2383141cc406Sopenharmony_ci 2384141cc406Sopenharmony_ci DBG (15, "\tdepth %d\n", params->depth); 2385141cc406Sopenharmony_ci DBG (15, "\tlines %d\n", params->lines); 2386141cc406Sopenharmony_ci DBG (15, "\tpixels_per_line %d\n", params->pixels_per_line); 2387141cc406Sopenharmony_ci DBG (15, "\tbytes_per_line %d\n", params->bytes_per_line); 2388141cc406Sopenharmony_ci 2389141cc406Sopenharmony_ci DBG (10, "sane_get_parameters: finish\n"); 2390141cc406Sopenharmony_ci 2391141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2392141cc406Sopenharmony_ci} 2393141cc406Sopenharmony_ci 2394141cc406Sopenharmony_ci/* 2395141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started. 2396141cc406Sopenharmony_ci * FIXME: won't handle SOURCE_ADF_BACK 2397141cc406Sopenharmony_ci */ 2398141cc406Sopenharmony_ciSANE_Status 2399141cc406Sopenharmony_cisane_start (SANE_Handle handle) 2400141cc406Sopenharmony_ci{ 2401141cc406Sopenharmony_ci struct scanner *s = handle; 2402141cc406Sopenharmony_ci SANE_Status ret; 2403141cc406Sopenharmony_ci int i; 2404141cc406Sopenharmony_ci 2405141cc406Sopenharmony_ci DBG (10, "sane_start: start\n"); 2406141cc406Sopenharmony_ci 2407141cc406Sopenharmony_ci /* set side marker on first page */ 2408141cc406Sopenharmony_ci if(!s->started){ 2409141cc406Sopenharmony_ci if(s->source == SOURCE_ADF_BACK){ 2410141cc406Sopenharmony_ci s->side = SIDE_BACK; 2411141cc406Sopenharmony_ci } 2412141cc406Sopenharmony_ci else{ 2413141cc406Sopenharmony_ci s->side = SIDE_FRONT; 2414141cc406Sopenharmony_ci } 2415141cc406Sopenharmony_ci } 2416141cc406Sopenharmony_ci /* if already running, duplex needs to switch sides */ 2417141cc406Sopenharmony_ci else if(s->source == SOURCE_ADF_DUPLEX){ 2418141cc406Sopenharmony_ci s->side = !s->side; 2419141cc406Sopenharmony_ci } 2420141cc406Sopenharmony_ci 2421141cc406Sopenharmony_ci /* recent scanners need ghs called before scanning */ 2422141cc406Sopenharmony_ci ret = get_hardware_status(s); 2423141cc406Sopenharmony_ci 2424141cc406Sopenharmony_ci /* ingest paper with adf */ 2425141cc406Sopenharmony_ci if( s->source == SOURCE_ADF_BACK || s->source == SOURCE_ADF_FRONT 2426141cc406Sopenharmony_ci || (s->source == SOURCE_ADF_DUPLEX && s->side == SIDE_FRONT) ){ 2427141cc406Sopenharmony_ci ret = object_position(s,EPJITSU_PAPER_INGEST); 2428141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2429141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to ingest\n"); 2430141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2431141cc406Sopenharmony_ci return ret; 2432141cc406Sopenharmony_ci } 2433141cc406Sopenharmony_ci } 2434141cc406Sopenharmony_ci 2435141cc406Sopenharmony_ci /* first page requires buffers, etc */ 2436141cc406Sopenharmony_ci if(!s->started){ 2437141cc406Sopenharmony_ci 2438141cc406Sopenharmony_ci DBG(15,"sane_start: first page\n"); 2439141cc406Sopenharmony_ci 2440141cc406Sopenharmony_ci s->started=1; 2441141cc406Sopenharmony_ci 2442141cc406Sopenharmony_ci ret = teardown_buffers(s); 2443141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2444141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to teardown buffers\n"); 2445141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2446141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2447141cc406Sopenharmony_ci } 2448141cc406Sopenharmony_ci 2449141cc406Sopenharmony_ci ret = change_params(s); 2450141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2451141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to change_params\n"); 2452141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2453141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2454141cc406Sopenharmony_ci } 2455141cc406Sopenharmony_ci 2456141cc406Sopenharmony_ci ret = setup_buffers(s); 2457141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2458141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to setup buffers\n"); 2459141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2460141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2461141cc406Sopenharmony_ci } 2462141cc406Sopenharmony_ci 2463141cc406Sopenharmony_ci ret = load_lut(s->dt_lut, 8, 8, 50, 205, 2464141cc406Sopenharmony_ci s->threshold_curve, s->threshold-127); 2465141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2466141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to load_lut for dt\n"); 2467141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2468141cc406Sopenharmony_ci return ret; 2469141cc406Sopenharmony_ci } 2470141cc406Sopenharmony_ci 2471141cc406Sopenharmony_ci ret = coarsecal(s); 2472141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2473141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to coarsecal\n"); 2474141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2475141cc406Sopenharmony_ci return ret; 2476141cc406Sopenharmony_ci } 2477141cc406Sopenharmony_ci 2478141cc406Sopenharmony_ci ret = finecal(s); 2479141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2480141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to finecal\n"); 2481141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2482141cc406Sopenharmony_ci return ret; 2483141cc406Sopenharmony_ci } 2484141cc406Sopenharmony_ci 2485141cc406Sopenharmony_ci ret = send_lut(s); 2486141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2487141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to send lut\n"); 2488141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2489141cc406Sopenharmony_ci return ret; 2490141cc406Sopenharmony_ci } 2491141cc406Sopenharmony_ci 2492141cc406Sopenharmony_ci ret = lamp(s,1); 2493141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2494141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to heat lamp\n"); 2495141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2496141cc406Sopenharmony_ci return ret; 2497141cc406Sopenharmony_ci } 2498141cc406Sopenharmony_ci 2499141cc406Sopenharmony_ci /*should this be between each page*/ 2500141cc406Sopenharmony_ci ret = set_window(s,WINDOW_SCAN); 2501141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2502141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to set window\n"); 2503141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2504141cc406Sopenharmony_ci return ret; 2505141cc406Sopenharmony_ci } 2506141cc406Sopenharmony_ci 2507141cc406Sopenharmony_ci } 2508141cc406Sopenharmony_ci 2509141cc406Sopenharmony_ci /* reset everything when starting any front, or just back */ 2510141cc406Sopenharmony_ci if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK){ 2511141cc406Sopenharmony_ci 2512141cc406Sopenharmony_ci DBG(15,"sane_start: reset counters\n"); 2513141cc406Sopenharmony_ci 2514141cc406Sopenharmony_ci /* reset scan */ 2515141cc406Sopenharmony_ci s->fullscan.done = 0; 2516141cc406Sopenharmony_ci s->fullscan.rx_bytes = 0; 2517141cc406Sopenharmony_ci s->fullscan.total_bytes = s->fullscan.width_bytes * s->fullscan.height; 2518141cc406Sopenharmony_ci 2519141cc406Sopenharmony_ci /* reset block */ 2520141cc406Sopenharmony_ci update_transfer_totals(&s->block_xfr); 2521141cc406Sopenharmony_ci 2522141cc406Sopenharmony_ci /* reset front and back page counters */ 2523141cc406Sopenharmony_ci for (i = 0; i < 2; i++) 2524141cc406Sopenharmony_ci { 2525141cc406Sopenharmony_ci struct image *page_img = s->pages[i].image; 2526141cc406Sopenharmony_ci s->pages[i].bytes_total = page_img->width_bytes * page_img->height; 2527141cc406Sopenharmony_ci s->pages[i].bytes_scanned = 0; 2528141cc406Sopenharmony_ci s->pages[i].bytes_read = 0; 2529141cc406Sopenharmony_ci s->pages[i].lines_rx = 0; 2530141cc406Sopenharmony_ci s->pages[i].lines_pass = 0; 2531141cc406Sopenharmony_ci s->pages[i].lines_tx = 0; 2532141cc406Sopenharmony_ci s->pages[i].done = 0; 2533141cc406Sopenharmony_ci } 2534141cc406Sopenharmony_ci 2535141cc406Sopenharmony_ci ret = scan(s); 2536141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 2537141cc406Sopenharmony_ci DBG (5, "sane_start: ERROR: failed to start scan\n"); 2538141cc406Sopenharmony_ci sane_cancel((SANE_Handle)s); 2539141cc406Sopenharmony_ci return ret; 2540141cc406Sopenharmony_ci } 2541141cc406Sopenharmony_ci } 2542141cc406Sopenharmony_ci else{ 2543141cc406Sopenharmony_ci DBG(15,"sane_start: back side\n"); 2544141cc406Sopenharmony_ci } 2545141cc406Sopenharmony_ci 2546141cc406Sopenharmony_ci DBG (10, "sane_start: finish\n"); 2547141cc406Sopenharmony_ci 2548141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2549141cc406Sopenharmony_ci} 2550141cc406Sopenharmony_ci 2551141cc406Sopenharmony_ci/* the +8 on all the lengths is to makeup for potential block trailers */ 2552141cc406Sopenharmony_cistatic SANE_Status 2553141cc406Sopenharmony_cisetup_buffers(struct scanner *s) 2554141cc406Sopenharmony_ci{ 2555141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2556141cc406Sopenharmony_ci 2557141cc406Sopenharmony_ci DBG (10, "setup_buffers: start\n"); 2558141cc406Sopenharmony_ci 2559141cc406Sopenharmony_ci /* temporary cal data */ 2560141cc406Sopenharmony_ci s->coarsecal.buffer = calloc (1,s->coarsecal.width_bytes * s->coarsecal.height * s->coarsecal.pages); 2561141cc406Sopenharmony_ci if(!s->coarsecal.buffer){ 2562141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup coarse cal buffer\n"); 2563141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2564141cc406Sopenharmony_ci } 2565141cc406Sopenharmony_ci 2566141cc406Sopenharmony_ci s->darkcal.buffer = calloc (1,s->darkcal.width_bytes * s->darkcal.height * s->darkcal.pages); 2567141cc406Sopenharmony_ci if(!s->darkcal.buffer){ 2568141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup fine cal buffer\n"); 2569141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2570141cc406Sopenharmony_ci } 2571141cc406Sopenharmony_ci 2572141cc406Sopenharmony_ci s->lightcal.buffer = calloc (1,s->lightcal.width_bytes * s->lightcal.height * s->lightcal.pages); 2573141cc406Sopenharmony_ci if(!s->lightcal.buffer){ 2574141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup fine cal buffer\n"); 2575141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2576141cc406Sopenharmony_ci } 2577141cc406Sopenharmony_ci 2578141cc406Sopenharmony_ci s->sendcal.buffer = calloc (1,s->sendcal.width_bytes * s->sendcal.height * s->sendcal.pages); 2579141cc406Sopenharmony_ci if(!s->sendcal.buffer){ 2580141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup send cal buffer\n"); 2581141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2582141cc406Sopenharmony_ci } 2583141cc406Sopenharmony_ci 2584141cc406Sopenharmony_ci s->cal_image.raw_data = calloc(1, s->cal_image.line_stride * 16 + 8); /* maximum 16 lines input for fine calibration */ 2585141cc406Sopenharmony_ci if(!s->cal_image.raw_data){ 2586141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup calibration input raw data buffer\n"); 2587141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2588141cc406Sopenharmony_ci } 2589141cc406Sopenharmony_ci 2590141cc406Sopenharmony_ci s->cal_data.raw_data = calloc(1, s->cal_data.line_stride); /* only 1 line of data is sent */ 2591141cc406Sopenharmony_ci if(!s->cal_data.raw_data){ 2592141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup calibration output raw data buffer\n"); 2593141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2594141cc406Sopenharmony_ci } 2595141cc406Sopenharmony_ci 2596141cc406Sopenharmony_ci /* grab up to 512K at a time */ 2597141cc406Sopenharmony_ci s->block_img.buffer = calloc (1,s->block_img.width_bytes * s->block_img.height * s->block_img.pages); 2598141cc406Sopenharmony_ci if(!s->block_img.buffer){ 2599141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup block image buffer\n"); 2600141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2601141cc406Sopenharmony_ci } 2602141cc406Sopenharmony_ci s->block_xfr.raw_data = calloc(1, s->block_xfr.line_stride * s->block_img.height + 8); 2603141cc406Sopenharmony_ci if(!s->block_xfr.raw_data){ 2604141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup block raw data buffer\n"); 2605141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2606141cc406Sopenharmony_ci } 2607141cc406Sopenharmony_ci 2608141cc406Sopenharmony_ci /* one grayscale line for dynamic threshold */ 2609141cc406Sopenharmony_ci s->dt.buffer = calloc (1,s->dt.width_bytes * s->dt.height * s->dt.pages); 2610141cc406Sopenharmony_ci if(!s->dt.buffer){ 2611141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup dt buffer\n"); 2612141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2613141cc406Sopenharmony_ci } 2614141cc406Sopenharmony_ci 2615141cc406Sopenharmony_ci /* make image buffer to hold frontside data */ 2616141cc406Sopenharmony_ci if(s->source != SOURCE_ADF_BACK){ 2617141cc406Sopenharmony_ci 2618141cc406Sopenharmony_ci s->front.buffer = calloc (1,s->front.width_bytes * s->front.height * s->front.pages); 2619141cc406Sopenharmony_ci if(!s->front.buffer){ 2620141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup front buffer\n"); 2621141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2622141cc406Sopenharmony_ci } 2623141cc406Sopenharmony_ci } 2624141cc406Sopenharmony_ci 2625141cc406Sopenharmony_ci /* make image buffer to hold backside data */ 2626141cc406Sopenharmony_ci if(s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK){ 2627141cc406Sopenharmony_ci 2628141cc406Sopenharmony_ci s->back.buffer = calloc (1,s->back.width_bytes * s->back.height * s->back.pages); 2629141cc406Sopenharmony_ci if(!s->back.buffer){ 2630141cc406Sopenharmony_ci DBG (5, "setup_buffers: ERROR: failed to setup back buffer\n"); 2631141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2632141cc406Sopenharmony_ci } 2633141cc406Sopenharmony_ci } 2634141cc406Sopenharmony_ci 2635141cc406Sopenharmony_ci DBG (10, "setup_buffers: finish\n"); 2636141cc406Sopenharmony_ci return ret; 2637141cc406Sopenharmony_ci} 2638141cc406Sopenharmony_ci 2639141cc406Sopenharmony_ci/* 2640141cc406Sopenharmony_ci coarse calibration consists of: 2641141cc406Sopenharmony_ci 1. turn lamp off (d0) 2642141cc406Sopenharmony_ci 2. set window for single line of data (d1) 2643141cc406Sopenharmony_ci 3. get line (d2) 2644141cc406Sopenharmony_ci 4. update dark coarse cal (c6) 2645141cc406Sopenharmony_ci 5. return to #3 if not dark enough 2646141cc406Sopenharmony_ci 6. turn lamp on (d0) 2647141cc406Sopenharmony_ci 7. get line (d2) 2648141cc406Sopenharmony_ci 8. update light coarse cal (c6) 2649141cc406Sopenharmony_ci 9. return to #7 if not light enough 2650141cc406Sopenharmony_ci*/ 2651141cc406Sopenharmony_ci 2652141cc406Sopenharmony_cistatic SANE_Status 2653141cc406Sopenharmony_cicoarsecal_send_cal(struct scanner *s, unsigned char *pay) 2654141cc406Sopenharmony_ci{ 2655141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2656141cc406Sopenharmony_ci unsigned char cmd[2]; 2657141cc406Sopenharmony_ci unsigned char stat[1]; 2658141cc406Sopenharmony_ci size_t cmdLen,statLen,payLen; 2659141cc406Sopenharmony_ci 2660141cc406Sopenharmony_ci DBG (10, "coarsecal_send_cal: start\n"); 2661141cc406Sopenharmony_ci /* send coarse cal (c6) */ 2662141cc406Sopenharmony_ci cmd[0] = 0x1b; 2663141cc406Sopenharmony_ci cmd[1] = 0xc6; 2664141cc406Sopenharmony_ci cmdLen = 2; 2665141cc406Sopenharmony_ci stat[0] = 0; 2666141cc406Sopenharmony_ci statLen = 1; 2667141cc406Sopenharmony_ci 2668141cc406Sopenharmony_ci ret = do_cmd( 2669141cc406Sopenharmony_ci s, 0, 2670141cc406Sopenharmony_ci cmd, cmdLen, 2671141cc406Sopenharmony_ci NULL, 0, 2672141cc406Sopenharmony_ci stat, &statLen 2673141cc406Sopenharmony_ci ); 2674141cc406Sopenharmony_ci if(ret){ 2675141cc406Sopenharmony_ci DBG (5, "coarsecal_send_cal: error sending c6 cmd\n"); 2676141cc406Sopenharmony_ci return ret; 2677141cc406Sopenharmony_ci } 2678141cc406Sopenharmony_ci if(stat[0] != 6){ 2679141cc406Sopenharmony_ci DBG (5, "coarsecal_send_cal: cmd bad c6 status?\n"); 2680141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2681141cc406Sopenharmony_ci } 2682141cc406Sopenharmony_ci 2683141cc406Sopenharmony_ci /*send coarse cal payload*/ 2684141cc406Sopenharmony_ci stat[0] = 0; 2685141cc406Sopenharmony_ci statLen = 1; 2686141cc406Sopenharmony_ci payLen = 28; 2687141cc406Sopenharmony_ci 2688141cc406Sopenharmony_ci ret = do_cmd( 2689141cc406Sopenharmony_ci s, 0, 2690141cc406Sopenharmony_ci pay, payLen, 2691141cc406Sopenharmony_ci NULL, 0, 2692141cc406Sopenharmony_ci stat, &statLen 2693141cc406Sopenharmony_ci ); 2694141cc406Sopenharmony_ci if(ret){ 2695141cc406Sopenharmony_ci DBG (5, "coarsecal_send_cal: error sending c6 payload\n"); 2696141cc406Sopenharmony_ci return ret; 2697141cc406Sopenharmony_ci } 2698141cc406Sopenharmony_ci if(stat[0] != 6){ 2699141cc406Sopenharmony_ci DBG (5, "coarsecal_send_cal: c6 payload bad status?\n"); 2700141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2701141cc406Sopenharmony_ci } 2702141cc406Sopenharmony_ci 2703141cc406Sopenharmony_ci DBG (10, "coarsecal_send_cal: finish\n"); 2704141cc406Sopenharmony_ci return ret; 2705141cc406Sopenharmony_ci} 2706141cc406Sopenharmony_ci 2707141cc406Sopenharmony_cistatic SANE_Status 2708141cc406Sopenharmony_cicoarsecal_get_line(struct scanner *s, struct image *img) 2709141cc406Sopenharmony_ci{ 2710141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2711141cc406Sopenharmony_ci unsigned char cmd[2]; 2712141cc406Sopenharmony_ci unsigned char stat[1]; 2713141cc406Sopenharmony_ci size_t cmdLen,statLen; 2714141cc406Sopenharmony_ci 2715141cc406Sopenharmony_ci DBG (10, "coarsecal_get_line: start\n"); 2716141cc406Sopenharmony_ci 2717141cc406Sopenharmony_ci /* send scan d2 command */ 2718141cc406Sopenharmony_ci cmd[0] = 0x1b; 2719141cc406Sopenharmony_ci cmd[1] = 0xd2; 2720141cc406Sopenharmony_ci cmdLen = 2; 2721141cc406Sopenharmony_ci stat[0] = 0; 2722141cc406Sopenharmony_ci statLen = 1; 2723141cc406Sopenharmony_ci 2724141cc406Sopenharmony_ci ret = do_cmd( 2725141cc406Sopenharmony_ci s, 0, 2726141cc406Sopenharmony_ci cmd, cmdLen, 2727141cc406Sopenharmony_ci NULL, 0, 2728141cc406Sopenharmony_ci stat, &statLen 2729141cc406Sopenharmony_ci ); 2730141cc406Sopenharmony_ci if(ret){ 2731141cc406Sopenharmony_ci DBG (5, "coarsecal_get_line: error sending d2 cmd\n"); 2732141cc406Sopenharmony_ci return ret; 2733141cc406Sopenharmony_ci } 2734141cc406Sopenharmony_ci if(stat[0] != 6){ 2735141cc406Sopenharmony_ci DBG (5, "coarsecal_get_line: cmd bad d2 status?\n"); 2736141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2737141cc406Sopenharmony_ci } 2738141cc406Sopenharmony_ci 2739141cc406Sopenharmony_ci s->cal_image.image = img; 2740141cc406Sopenharmony_ci update_transfer_totals(&s->cal_image); 2741141cc406Sopenharmony_ci 2742141cc406Sopenharmony_ci while(!s->cal_image.done){ 2743141cc406Sopenharmony_ci ret = read_from_scanner(s,&s->cal_image); 2744141cc406Sopenharmony_ci if(ret){ 2745141cc406Sopenharmony_ci DBG (5, "coarsecal_get_line: can't read from scanner\n"); 2746141cc406Sopenharmony_ci return ret; 2747141cc406Sopenharmony_ci } 2748141cc406Sopenharmony_ci } 2749141cc406Sopenharmony_ci /* convert the raw data into normal packed pixel data */ 2750141cc406Sopenharmony_ci descramble_raw(s, &s->cal_image); 2751141cc406Sopenharmony_ci 2752141cc406Sopenharmony_ci DBG (10, "coarsecal_get_line: finish\n"); 2753141cc406Sopenharmony_ci return ret; 2754141cc406Sopenharmony_ci} 2755141cc406Sopenharmony_ci 2756141cc406Sopenharmony_cistatic SANE_Status 2757141cc406Sopenharmony_cicoarsecal_dark(struct scanner *s, unsigned char *pay) 2758141cc406Sopenharmony_ci{ 2759141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2760141cc406Sopenharmony_ci 2761141cc406Sopenharmony_ci int try_count, cal_good[2], x, j; 2762141cc406Sopenharmony_ci int param[2], zcount[2], high_param[2], low_param[2], avg[2], maxval[2]; 2763141cc406Sopenharmony_ci 2764141cc406Sopenharmony_ci DBG (10, "coarsecal_dark: start\n"); 2765141cc406Sopenharmony_ci 2766141cc406Sopenharmony_ci /* dark cal, lamp off */ 2767141cc406Sopenharmony_ci ret = lamp(s,0); 2768141cc406Sopenharmony_ci if(ret){ 2769141cc406Sopenharmony_ci DBG (5, "coarsecal_dark: error lamp off\n"); 2770141cc406Sopenharmony_ci return ret; 2771141cc406Sopenharmony_ci } 2772141cc406Sopenharmony_ci 2773141cc406Sopenharmony_ci try_count = 8; 2774141cc406Sopenharmony_ci param[0] = 63; 2775141cc406Sopenharmony_ci param[1] = 63; 2776141cc406Sopenharmony_ci low_param[0] = low_param[1] = -64; /* The S300 will accept coarse offsets from -128 to 127 */ 2777141cc406Sopenharmony_ci high_param[0] = high_param[1] = 63; /* By our range is limited to converge faster */ 2778141cc406Sopenharmony_ci cal_good[0] = cal_good[1] = 0; 2779141cc406Sopenharmony_ci 2780141cc406Sopenharmony_ci while (try_count > 0){ 2781141cc406Sopenharmony_ci try_count--; 2782141cc406Sopenharmony_ci 2783141cc406Sopenharmony_ci /* update the coarsecal payload to use our new dark offset parameters */ 2784141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) 2785141cc406Sopenharmony_ci { 2786141cc406Sopenharmony_ci pay[5] = param[0]; 2787141cc406Sopenharmony_ci pay[7] = param[1]; 2788141cc406Sopenharmony_ci } 2789141cc406Sopenharmony_ci else /* MODEL_S1100 or MODEL_FI60F or MODEL_FI65F */ 2790141cc406Sopenharmony_ci { 2791141cc406Sopenharmony_ci pay[5] = param[0]; 2792141cc406Sopenharmony_ci pay[7] = param[0]; 2793141cc406Sopenharmony_ci pay[9] = param[0]; 2794141cc406Sopenharmony_ci } 2795141cc406Sopenharmony_ci 2796141cc406Sopenharmony_ci ret = coarsecal_send_cal(s, pay); 2797141cc406Sopenharmony_ci 2798141cc406Sopenharmony_ci DBG(15, "coarsecal_dark offset: parameter front: %i back: %i\n", param[0], param[1]); 2799141cc406Sopenharmony_ci 2800141cc406Sopenharmony_ci ret = coarsecal_get_line(s, &s->coarsecal); 2801141cc406Sopenharmony_ci 2802141cc406Sopenharmony_ci /* gather statistics: count the proportion of 0-valued pixels */ 2803141cc406Sopenharmony_ci /* since the lamp is off, there's no point in looking at the green or blue data - they're all from the same sensor anyway */ 2804141cc406Sopenharmony_ci zcount[0] = zcount[1] = 0; 2805141cc406Sopenharmony_ci avg[0] = avg[1] = 0; 2806141cc406Sopenharmony_ci maxval[0] = maxval[1] = 0; 2807141cc406Sopenharmony_ci for (j = 0; j < s->coarsecal.pages; j++) 2808141cc406Sopenharmony_ci { 2809141cc406Sopenharmony_ci int page_offset = j * s->coarsecal.width_bytes * s->coarsecal.height; 2810141cc406Sopenharmony_ci for (x = 0; x < s->coarsecal.width_bytes; x++) 2811141cc406Sopenharmony_ci { 2812141cc406Sopenharmony_ci int val = s->coarsecal.buffer[page_offset + x]; 2813141cc406Sopenharmony_ci avg[j] += val; 2814141cc406Sopenharmony_ci if (val == 0) zcount[j]++; 2815141cc406Sopenharmony_ci if (val > maxval[j]) maxval[j] = val; 2816141cc406Sopenharmony_ci } 2817141cc406Sopenharmony_ci } 2818141cc406Sopenharmony_ci /* convert the zero counts from a pixel count to a proportion in tenths of a percent */ 2819141cc406Sopenharmony_ci for (j = 0; j < s->coarsecal.pages; j++) 2820141cc406Sopenharmony_ci { 2821141cc406Sopenharmony_ci avg[j] /= s->coarsecal.width_bytes; 2822141cc406Sopenharmony_ci zcount[j] = zcount[j] * 1000 / s->coarsecal.width_bytes; 2823141cc406Sopenharmony_ci } 2824141cc406Sopenharmony_ci DBG(15, "coarsecal_dark offset: average pixel values front: %i back: %i\n", avg[0], avg[1]); 2825141cc406Sopenharmony_ci DBG(15, "coarsecal_dark offset: maximum pixel values front: %i back: %i\n", maxval[0], maxval[1]); 2826141cc406Sopenharmony_ci DBG(15, "coarsecal_dark offset: 0-valued pixel count front: %f%% back: %f%%\n", zcount[0] / 10.0f, zcount[1] / 10.0f); 2827141cc406Sopenharmony_ci 2828141cc406Sopenharmony_ci /* check the values, adjust parameters if they are not within the target range */ 2829141cc406Sopenharmony_ci for (j = 0; j < s->coarsecal.pages; j++) 2830141cc406Sopenharmony_ci { 2831141cc406Sopenharmony_ci if (!cal_good[j]) 2832141cc406Sopenharmony_ci { 2833141cc406Sopenharmony_ci if (avg[j] > COARSE_OFFSET_TARGET) 2834141cc406Sopenharmony_ci { 2835141cc406Sopenharmony_ci high_param[j] = param[j]; 2836141cc406Sopenharmony_ci param[j] = (low_param[j] + high_param[j]) / 2; 2837141cc406Sopenharmony_ci } 2838141cc406Sopenharmony_ci else if (avg[j] < COARSE_OFFSET_TARGET) 2839141cc406Sopenharmony_ci { 2840141cc406Sopenharmony_ci low_param[j] = param[j]; 2841141cc406Sopenharmony_ci param[j] = (low_param[j] + high_param[j]) / 2; 2842141cc406Sopenharmony_ci } 2843141cc406Sopenharmony_ci else cal_good[j] = 1; 2844141cc406Sopenharmony_ci } 2845141cc406Sopenharmony_ci } 2846141cc406Sopenharmony_ci if (cal_good[0] + cal_good[1] == s->coarsecal.pages) break; 2847141cc406Sopenharmony_ci 2848141cc406Sopenharmony_ci } /* continue looping for up to 8 tries */ 2849141cc406Sopenharmony_ci 2850141cc406Sopenharmony_ci DBG (10, "coarsecal_dark: finish\n"); 2851141cc406Sopenharmony_ci return ret; 2852141cc406Sopenharmony_ci} 2853141cc406Sopenharmony_ci 2854141cc406Sopenharmony_cistatic SANE_Status 2855141cc406Sopenharmony_cicoarsecal_light(struct scanner *s, unsigned char *pay) 2856141cc406Sopenharmony_ci{ 2857141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2858141cc406Sopenharmony_ci 2859141cc406Sopenharmony_ci int try_count, cal_good[2], x, i, j; 2860141cc406Sopenharmony_ci int param[2], zcount[2], high_param[2], low_param[2], avg[2]; 2861141cc406Sopenharmony_ci int rgb_avg[2][3], rgb_hicount[2][3]; 2862141cc406Sopenharmony_ci 2863141cc406Sopenharmony_ci DBG (10, "coarsecal_light: start\n"); 2864141cc406Sopenharmony_ci 2865141cc406Sopenharmony_ci /* light cal, lamp on */ 2866141cc406Sopenharmony_ci ret = lamp(s,1); 2867141cc406Sopenharmony_ci if(ret){ 2868141cc406Sopenharmony_ci DBG (5, "coarsecal_light: error lamp on\n"); 2869141cc406Sopenharmony_ci return ret; 2870141cc406Sopenharmony_ci } 2871141cc406Sopenharmony_ci 2872141cc406Sopenharmony_ci try_count = 8; 2873141cc406Sopenharmony_ci param[0] = pay[11]; 2874141cc406Sopenharmony_ci param[1] = pay[13]; 2875141cc406Sopenharmony_ci low_param[0] = low_param[1] = 0; 2876141cc406Sopenharmony_ci high_param[0] = high_param[1] = 63; 2877141cc406Sopenharmony_ci cal_good[0] = cal_good[1] = 0; 2878141cc406Sopenharmony_ci 2879141cc406Sopenharmony_ci while (try_count > 0){ 2880141cc406Sopenharmony_ci try_count--; 2881141cc406Sopenharmony_ci 2882141cc406Sopenharmony_ci ret = coarsecal_send_cal(s, pay); 2883141cc406Sopenharmony_ci 2884141cc406Sopenharmony_ci DBG(15, "coarsecal_light gain: parameter front: %i back: %i\n", param[0], param[1]); 2885141cc406Sopenharmony_ci 2886141cc406Sopenharmony_ci ret = coarsecal_get_line(s, &s->coarsecal); 2887141cc406Sopenharmony_ci 2888141cc406Sopenharmony_ci /* gather statistics: count the proportion of 255-valued pixels in each color channel */ 2889141cc406Sopenharmony_ci /* count the average pixel value in each color channel */ 2890141cc406Sopenharmony_ci for (i = 0; i < s->coarsecal.pages; i++) 2891141cc406Sopenharmony_ci for (j = 0; j < 3; j++) 2892141cc406Sopenharmony_ci rgb_avg[i][j] = rgb_hicount[i][j] = 0; 2893141cc406Sopenharmony_ci for (i = 0; i < s->coarsecal.pages; i++) 2894141cc406Sopenharmony_ci { 2895141cc406Sopenharmony_ci for (x = 0; x < s->coarsecal.width_pix; x++) 2896141cc406Sopenharmony_ci { 2897141cc406Sopenharmony_ci /* get color channel values and count of pixels pegged at 255 */ 2898141cc406Sopenharmony_ci unsigned char *rgbpix = s->coarsecal.buffer + (i * s->coarsecal.width_bytes * s->coarsecal.height) + x * 3; 2899141cc406Sopenharmony_ci for (j = 0; j < 3; j++) 2900141cc406Sopenharmony_ci { 2901141cc406Sopenharmony_ci rgb_avg[i][j] += rgbpix[j]; 2902141cc406Sopenharmony_ci if (rgbpix[j] == 255) 2903141cc406Sopenharmony_ci rgb_hicount[i][j]++; 2904141cc406Sopenharmony_ci } 2905141cc406Sopenharmony_ci } 2906141cc406Sopenharmony_ci } 2907141cc406Sopenharmony_ci /* apply the color correction factors to the averages */ 2908141cc406Sopenharmony_ci for (i = 0; i < s->coarsecal.pages; i++) 2909141cc406Sopenharmony_ci for (j = 0; j < 3; j++) 2910141cc406Sopenharmony_ci rgb_avg[i][j] *= s->white_factor[j]; 2911141cc406Sopenharmony_ci /* set the gain so that none of the color channels are clipping, ie take the highest channel values */ 2912141cc406Sopenharmony_ci for (i = 0; i < s->coarsecal.pages; i++) 2913141cc406Sopenharmony_ci { 2914141cc406Sopenharmony_ci avg[i] = MAX3(rgb_avg[i][0], rgb_avg[i][1], rgb_avg[i][2]) / s->coarsecal.width_pix; 2915141cc406Sopenharmony_ci for (j = 0; j < 3; j++) 2916141cc406Sopenharmony_ci rgb_avg[i][j] /= s->coarsecal.width_pix; 2917141cc406Sopenharmony_ci } 2918141cc406Sopenharmony_ci /* convert the 255-counts from a pixel count to a proportion in tenths of a percent */ 2919141cc406Sopenharmony_ci for (i = 0; i < s->coarsecal.pages; i++) 2920141cc406Sopenharmony_ci { 2921141cc406Sopenharmony_ci for (j = 0; j < 3; j++) 2922141cc406Sopenharmony_ci { 2923141cc406Sopenharmony_ci rgb_hicount[i][j] = rgb_hicount[i][j] * 1000 / s->coarsecal.width_pix; 2924141cc406Sopenharmony_ci } 2925141cc406Sopenharmony_ci zcount[i] = MAX3(rgb_hicount[i][0], rgb_hicount[i][1], rgb_hicount[i][2]); 2926141cc406Sopenharmony_ci } 2927141cc406Sopenharmony_ci DBG(15, "coarsecal_light gain: average RGB values front: (%i,%i,%i) back: (%i,%i,%i)\n", 2928141cc406Sopenharmony_ci rgb_avg[0][0], rgb_avg[0][1], rgb_avg[0][2], rgb_avg[1][0], rgb_avg[1][1], rgb_avg[1][2]); 2929141cc406Sopenharmony_ci DBG(15, "coarsecal_light gain: 255-valued pixel count front: (%g,%g,%g) back: (%g,%g,%g)\n", 2930141cc406Sopenharmony_ci rgb_hicount[0][0]/10.0f, rgb_hicount[0][1]/10.0f, rgb_hicount[0][2]/10.0f, 2931141cc406Sopenharmony_ci rgb_hicount[1][0]/10.0f, rgb_hicount[1][1]/10.0f, rgb_hicount[1][2]/10.0f); 2932141cc406Sopenharmony_ci 2933141cc406Sopenharmony_ci /* check the values, adjust parameters if they are not within the target range */ 2934141cc406Sopenharmony_ci for (x = 0; x < s->coarsecal.pages; x++) 2935141cc406Sopenharmony_ci { 2936141cc406Sopenharmony_ci if (!cal_good[x]) 2937141cc406Sopenharmony_ci { 2938141cc406Sopenharmony_ci if (zcount[x] > 9 || avg[x] > coarse_gain_max[x]) 2939141cc406Sopenharmony_ci { 2940141cc406Sopenharmony_ci high_param[x] = param[x]; 2941141cc406Sopenharmony_ci param[x] = (low_param[x] + high_param[x]) / 2; 2942141cc406Sopenharmony_ci } 2943141cc406Sopenharmony_ci else if (avg[x] < coarse_gain_min[x]) 2944141cc406Sopenharmony_ci { 2945141cc406Sopenharmony_ci low_param[x] = param[x]; 2946141cc406Sopenharmony_ci param[x] = (low_param[x] + high_param[x]) / 2; 2947141cc406Sopenharmony_ci } 2948141cc406Sopenharmony_ci else cal_good[x] = 1; 2949141cc406Sopenharmony_ci } 2950141cc406Sopenharmony_ci } 2951141cc406Sopenharmony_ci if (cal_good[0] + cal_good[1] == s->coarsecal.pages) break; 2952141cc406Sopenharmony_ci 2953141cc406Sopenharmony_ci /* update the coarsecal payload to use the new gain parameters */ 2954141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) 2955141cc406Sopenharmony_ci { 2956141cc406Sopenharmony_ci pay[11] = param[0]; 2957141cc406Sopenharmony_ci pay[13] = param[1]; 2958141cc406Sopenharmony_ci } 2959141cc406Sopenharmony_ci else /* MODEL_S1100 or MODEL_FI60F or MODEL_FI65F */ 2960141cc406Sopenharmony_ci { 2961141cc406Sopenharmony_ci pay[11] = param[0]; 2962141cc406Sopenharmony_ci pay[13] = param[0]; 2963141cc406Sopenharmony_ci pay[15] = param[0]; 2964141cc406Sopenharmony_ci } 2965141cc406Sopenharmony_ci } 2966141cc406Sopenharmony_ci 2967141cc406Sopenharmony_ci DBG (10, "coarsecal_light: finish\n"); 2968141cc406Sopenharmony_ci return ret; 2969141cc406Sopenharmony_ci} 2970141cc406Sopenharmony_ci 2971141cc406Sopenharmony_cistatic SANE_Status 2972141cc406Sopenharmony_cicoarsecal(struct scanner *s) 2973141cc406Sopenharmony_ci{ 2974141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 2975141cc406Sopenharmony_ci unsigned char pay[28]; 2976141cc406Sopenharmony_ci size_t payLen; 2977141cc406Sopenharmony_ci 2978141cc406Sopenharmony_ci DBG (10, "coarsecal: start\n"); 2979141cc406Sopenharmony_ci 2980141cc406Sopenharmony_ci payLen = sizeof(pay); 2981141cc406Sopenharmony_ci 2982141cc406Sopenharmony_ci if(s->model == MODEL_S300){ 2983141cc406Sopenharmony_ci memcpy(pay,coarseCalData_S300,payLen); 2984141cc406Sopenharmony_ci } 2985141cc406Sopenharmony_ci else if(s->model == MODEL_S1300i){ 2986141cc406Sopenharmony_ci memcpy(pay,coarseCalData_S1300i,payLen); 2987141cc406Sopenharmony_ci } 2988141cc406Sopenharmony_ci else if(s->model == MODEL_S1100){ 2989141cc406Sopenharmony_ci memcpy(pay,coarseCalData_S1100,payLen); 2990141cc406Sopenharmony_ci } 2991141cc406Sopenharmony_ci else{ 2992141cc406Sopenharmony_ci memcpy(pay,coarseCalData_FI60F,payLen); 2993141cc406Sopenharmony_ci } 2994141cc406Sopenharmony_ci 2995141cc406Sopenharmony_ci /* ask for 1 line */ 2996141cc406Sopenharmony_ci ret = set_window(s, WINDOW_COARSECAL); 2997141cc406Sopenharmony_ci if(ret){ 2998141cc406Sopenharmony_ci DBG (5, "coarsecal: error sending setwindow\n"); 2999141cc406Sopenharmony_ci return ret; 3000141cc406Sopenharmony_ci } 3001141cc406Sopenharmony_ci 3002141cc406Sopenharmony_ci if(s->model == MODEL_S1100){ 3003141cc406Sopenharmony_ci ret = coarsecal_send_cal(s, pay); 3004141cc406Sopenharmony_ci } 3005141cc406Sopenharmony_ci else{ 3006141cc406Sopenharmony_ci ret = coarsecal_dark(s, pay); 3007141cc406Sopenharmony_ci ret = coarsecal_light(s, pay); 3008141cc406Sopenharmony_ci } 3009141cc406Sopenharmony_ci 3010141cc406Sopenharmony_ci DBG (10, "coarsecal: finish\n"); 3011141cc406Sopenharmony_ci return ret; 3012141cc406Sopenharmony_ci} 3013141cc406Sopenharmony_ci 3014141cc406Sopenharmony_cistatic SANE_Status 3015141cc406Sopenharmony_cifinecal_send_cal(struct scanner *s) 3016141cc406Sopenharmony_ci{ 3017141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3018141cc406Sopenharmony_ci 3019141cc406Sopenharmony_ci size_t cmdLen = 2; 3020141cc406Sopenharmony_ci unsigned char cmd[2]; 3021141cc406Sopenharmony_ci 3022141cc406Sopenharmony_ci size_t statLen = 1; 3023141cc406Sopenharmony_ci unsigned char stat[2]; 3024141cc406Sopenharmony_ci 3025141cc406Sopenharmony_ci int i, j, k; 3026141cc406Sopenharmony_ci unsigned char *p_out, *p_in = s->sendcal.buffer; 3027141cc406Sopenharmony_ci int planes; 3028141cc406Sopenharmony_ci 3029141cc406Sopenharmony_ci DBG (10, "finecal_send_cal: start\n"); 3030141cc406Sopenharmony_ci 3031141cc406Sopenharmony_ci if(s->model == MODEL_FI60F || s->model == MODEL_FI65F) 3032141cc406Sopenharmony_ci planes = 3; 3033141cc406Sopenharmony_ci if(s->model == MODEL_S300 || s->model == MODEL_S1300i) 3034141cc406Sopenharmony_ci planes = 2; 3035141cc406Sopenharmony_ci 3036141cc406Sopenharmony_ci /* scramble the raster buffer data into scanner raw format */ 3037141cc406Sopenharmony_ci /* this is reverse of descramble_raw */ 3038141cc406Sopenharmony_ci memset(s->cal_data.raw_data, 0, s->cal_data.line_stride); 3039141cc406Sopenharmony_ci 3040141cc406Sopenharmony_ci if(s->model == MODEL_S1100){ 3041141cc406Sopenharmony_ci planes = 1; 3042141cc406Sopenharmony_ci 3043141cc406Sopenharmony_ci for (k = 0; k < s->sendcal.width_pix; k++){ /* column (x) */ 3044141cc406Sopenharmony_ci 3045141cc406Sopenharmony_ci /* input is RrGgBb (capital is offset, small is gain) */ 3046141cc406Sopenharmony_ci /* output is Bb...BbRr...RrGg...Gg*/ 3047141cc406Sopenharmony_ci 3048141cc406Sopenharmony_ci /*red*/ 3049141cc406Sopenharmony_ci p_out = s->cal_data.raw_data + s->cal_data.plane_stride + k*2; 3050141cc406Sopenharmony_ci *p_out = *p_in; 3051141cc406Sopenharmony_ci p_out++; 3052141cc406Sopenharmony_ci p_in++; 3053141cc406Sopenharmony_ci *p_out = *p_in; 3054141cc406Sopenharmony_ci p_in++; 3055141cc406Sopenharmony_ci 3056141cc406Sopenharmony_ci /*green*/ 3057141cc406Sopenharmony_ci p_out = s->cal_data.raw_data + 2*s->cal_data.plane_stride + k*2; 3058141cc406Sopenharmony_ci *p_out = *p_in; 3059141cc406Sopenharmony_ci p_out++; 3060141cc406Sopenharmony_ci p_in++; 3061141cc406Sopenharmony_ci *p_out = *p_in; 3062141cc406Sopenharmony_ci p_in++; 3063141cc406Sopenharmony_ci 3064141cc406Sopenharmony_ci /*blue*/ 3065141cc406Sopenharmony_ci p_out = s->cal_data.raw_data + k*2; 3066141cc406Sopenharmony_ci *p_out = *p_in; 3067141cc406Sopenharmony_ci p_out++; 3068141cc406Sopenharmony_ci p_in++; 3069141cc406Sopenharmony_ci *p_out = *p_in; 3070141cc406Sopenharmony_ci p_in++; 3071141cc406Sopenharmony_ci } 3072141cc406Sopenharmony_ci } 3073141cc406Sopenharmony_ci 3074141cc406Sopenharmony_ci else{ 3075141cc406Sopenharmony_ci for (i = 0; i < planes; i++) 3076141cc406Sopenharmony_ci for (j = 0; j < s->cal_data.plane_width; j++) 3077141cc406Sopenharmony_ci for (k = 0; k < 3; k++) 3078141cc406Sopenharmony_ci { 3079141cc406Sopenharmony_ci p_out = (s->cal_data.raw_data + k * s->cal_data.plane_stride + j * 6 + i * 2); 3080141cc406Sopenharmony_ci *p_out = *p_in++; /* dark offset */ 3081141cc406Sopenharmony_ci p_out++; 3082141cc406Sopenharmony_ci *p_out = *p_in++; /* gain */ 3083141cc406Sopenharmony_ci } 3084141cc406Sopenharmony_ci } 3085141cc406Sopenharmony_ci 3086141cc406Sopenharmony_ci ret = set_window(s, WINDOW_SENDCAL); 3087141cc406Sopenharmony_ci if(ret){ 3088141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: error sending setwindow\n"); 3089141cc406Sopenharmony_ci return ret; 3090141cc406Sopenharmony_ci } 3091141cc406Sopenharmony_ci 3092141cc406Sopenharmony_ci /*first unknown cal block*/ 3093141cc406Sopenharmony_ci cmd[0] = 0x1b; 3094141cc406Sopenharmony_ci cmd[1] = 0xc3; 3095141cc406Sopenharmony_ci stat[0] = 0; 3096141cc406Sopenharmony_ci statLen = 1; 3097141cc406Sopenharmony_ci 3098141cc406Sopenharmony_ci ret = do_cmd( 3099141cc406Sopenharmony_ci s, 0, 3100141cc406Sopenharmony_ci cmd, cmdLen, 3101141cc406Sopenharmony_ci NULL, 0, 3102141cc406Sopenharmony_ci stat, &statLen 3103141cc406Sopenharmony_ci ); 3104141cc406Sopenharmony_ci if(ret){ 3105141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: error sending c3 cmd\n"); 3106141cc406Sopenharmony_ci return ret; 3107141cc406Sopenharmony_ci } 3108141cc406Sopenharmony_ci if(stat[0] != 6){ 3109141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: cmd bad c3 status?\n"); 3110141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3111141cc406Sopenharmony_ci } 3112141cc406Sopenharmony_ci 3113141cc406Sopenharmony_ci /*send header*/ 3114141cc406Sopenharmony_ci /*send payload*/ 3115141cc406Sopenharmony_ci statLen = 1; 3116141cc406Sopenharmony_ci 3117141cc406Sopenharmony_ci ret = do_cmd( 3118141cc406Sopenharmony_ci s, 0, 3119141cc406Sopenharmony_ci s->sendCal1Header, s->sendCal1HeaderLen, 3120141cc406Sopenharmony_ci s->cal_data.raw_data, s->cal_data.line_stride, 3121141cc406Sopenharmony_ci stat, &statLen 3122141cc406Sopenharmony_ci ); 3123141cc406Sopenharmony_ci 3124141cc406Sopenharmony_ci if(ret){ 3125141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: error sending c3 payload\n"); 3126141cc406Sopenharmony_ci return ret; 3127141cc406Sopenharmony_ci } 3128141cc406Sopenharmony_ci if(stat[0] != 6){ 3129141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: payload bad c3 status?\n"); 3130141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3131141cc406Sopenharmony_ci } 3132141cc406Sopenharmony_ci 3133141cc406Sopenharmony_ci /*second unknown cal block*/ 3134141cc406Sopenharmony_ci cmd[1] = 0xc4; 3135141cc406Sopenharmony_ci statLen = 1; 3136141cc406Sopenharmony_ci 3137141cc406Sopenharmony_ci ret = do_cmd( 3138141cc406Sopenharmony_ci s, 0, 3139141cc406Sopenharmony_ci cmd, cmdLen, 3140141cc406Sopenharmony_ci NULL, 0, 3141141cc406Sopenharmony_ci stat, &statLen 3142141cc406Sopenharmony_ci ); 3143141cc406Sopenharmony_ci 3144141cc406Sopenharmony_ci if(ret){ 3145141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: error sending c4 cmd\n"); 3146141cc406Sopenharmony_ci return ret; 3147141cc406Sopenharmony_ci } 3148141cc406Sopenharmony_ci if(stat[0] != 6){ 3149141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: cmd bad c4 status?\n"); 3150141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3151141cc406Sopenharmony_ci } 3152141cc406Sopenharmony_ci 3153141cc406Sopenharmony_ci /*send header*/ 3154141cc406Sopenharmony_ci /*send payload*/ 3155141cc406Sopenharmony_ci statLen = 1; 3156141cc406Sopenharmony_ci 3157141cc406Sopenharmony_ci ret = do_cmd( 3158141cc406Sopenharmony_ci s, 0, 3159141cc406Sopenharmony_ci s->sendCal2Header, s->sendCal2HeaderLen, 3160141cc406Sopenharmony_ci s->cal_data.raw_data, s->cal_data.line_stride, 3161141cc406Sopenharmony_ci stat, &statLen 3162141cc406Sopenharmony_ci ); 3163141cc406Sopenharmony_ci 3164141cc406Sopenharmony_ci if(ret){ 3165141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: error sending c4 payload\n"); 3166141cc406Sopenharmony_ci return ret; 3167141cc406Sopenharmony_ci } 3168141cc406Sopenharmony_ci if(stat[0] != 6){ 3169141cc406Sopenharmony_ci DBG (5, "finecal_send_cal: payload bad c4 status?\n"); 3170141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3171141cc406Sopenharmony_ci } 3172141cc406Sopenharmony_ci 3173141cc406Sopenharmony_ci DBG (10, "finecal_send_cal: finish\n"); 3174141cc406Sopenharmony_ci return ret; 3175141cc406Sopenharmony_ci} 3176141cc406Sopenharmony_ci 3177141cc406Sopenharmony_cistatic SANE_Status 3178141cc406Sopenharmony_cifinecal_get_line(struct scanner *s, struct image *img) 3179141cc406Sopenharmony_ci{ 3180141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3181141cc406Sopenharmony_ci 3182141cc406Sopenharmony_ci size_t cmdLen = 2; 3183141cc406Sopenharmony_ci unsigned char cmd[2]; 3184141cc406Sopenharmony_ci 3185141cc406Sopenharmony_ci size_t statLen = 1; 3186141cc406Sopenharmony_ci unsigned char stat[2]; 3187141cc406Sopenharmony_ci 3188141cc406Sopenharmony_ci int round_offset = img->height / 2; 3189141cc406Sopenharmony_ci int i, j, k; 3190141cc406Sopenharmony_ci 3191141cc406Sopenharmony_ci DBG (10, "finecal_get_line: start\n"); 3192141cc406Sopenharmony_ci 3193141cc406Sopenharmony_ci /* ask for 16 lines */ 3194141cc406Sopenharmony_ci ret = set_window(s, WINDOW_FINECAL); 3195141cc406Sopenharmony_ci if(ret){ 3196141cc406Sopenharmony_ci DBG (5, "finecal_get_line: error sending setwindowcal\n"); 3197141cc406Sopenharmony_ci return ret; 3198141cc406Sopenharmony_ci } 3199141cc406Sopenharmony_ci 3200141cc406Sopenharmony_ci /* send scan d2 command */ 3201141cc406Sopenharmony_ci cmd[0] = 0x1b; 3202141cc406Sopenharmony_ci cmd[1] = 0xd2; 3203141cc406Sopenharmony_ci stat[0] = 0; 3204141cc406Sopenharmony_ci statLen = 1; 3205141cc406Sopenharmony_ci 3206141cc406Sopenharmony_ci ret = do_cmd( 3207141cc406Sopenharmony_ci s, 0, 3208141cc406Sopenharmony_ci cmd, cmdLen, 3209141cc406Sopenharmony_ci NULL, 0, 3210141cc406Sopenharmony_ci stat, &statLen 3211141cc406Sopenharmony_ci ); 3212141cc406Sopenharmony_ci if(ret){ 3213141cc406Sopenharmony_ci DBG (5, "finecal_get_line: error sending d2 cmd\n"); 3214141cc406Sopenharmony_ci return ret; 3215141cc406Sopenharmony_ci } 3216141cc406Sopenharmony_ci if(stat[0] != 6){ 3217141cc406Sopenharmony_ci DBG (5, "finecal_get_line: cmd bad d2 status?\n"); 3218141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3219141cc406Sopenharmony_ci } 3220141cc406Sopenharmony_ci 3221141cc406Sopenharmony_ci s->cal_image.image = img; 3222141cc406Sopenharmony_ci update_transfer_totals(&s->cal_image); 3223141cc406Sopenharmony_ci 3224141cc406Sopenharmony_ci while(!s->cal_image.done){ 3225141cc406Sopenharmony_ci ret = read_from_scanner(s,&s->cal_image); 3226141cc406Sopenharmony_ci if(ret){ 3227141cc406Sopenharmony_ci DBG (5, "finecal_get_line: can't read from scanner\n"); 3228141cc406Sopenharmony_ci return ret; 3229141cc406Sopenharmony_ci } 3230141cc406Sopenharmony_ci } 3231141cc406Sopenharmony_ci /* convert the raw data into normal packed pixel data */ 3232141cc406Sopenharmony_ci descramble_raw(s, &s->cal_image); 3233141cc406Sopenharmony_ci 3234141cc406Sopenharmony_ci /* average the columns of pixels together and put the results in the top line(s) */ 3235141cc406Sopenharmony_ci for (i = 0; i < img->pages; i++) 3236141cc406Sopenharmony_ci { 3237141cc406Sopenharmony_ci unsigned char *linepix = img->buffer + i * img->width_bytes * img->height; 3238141cc406Sopenharmony_ci unsigned char *avgpix = img->buffer + i * img->width_bytes; 3239141cc406Sopenharmony_ci for (j = 0; j < img->width_bytes; j++) 3240141cc406Sopenharmony_ci { 3241141cc406Sopenharmony_ci int total = 0; 3242141cc406Sopenharmony_ci 3243141cc406Sopenharmony_ci for (k = 0; k < img->height; k++) 3244141cc406Sopenharmony_ci total += linepix[j + k * img->width_bytes]; 3245141cc406Sopenharmony_ci 3246141cc406Sopenharmony_ci avgpix[j] = (total + round_offset) / img->height; 3247141cc406Sopenharmony_ci } 3248141cc406Sopenharmony_ci } 3249141cc406Sopenharmony_ci 3250141cc406Sopenharmony_ci DBG (10, "finecal_get_line: finish\n"); 3251141cc406Sopenharmony_ci return ret; 3252141cc406Sopenharmony_ci} 3253141cc406Sopenharmony_ci 3254141cc406Sopenharmony_ci/* roundf() is c99, so we provide our own, though this version won't return -0 */ 3255141cc406Sopenharmony_cistatic float 3256141cc406Sopenharmony_ciround2(float x) 3257141cc406Sopenharmony_ci{ 3258141cc406Sopenharmony_ci return (float)(x >= 0.0) ? (int)(x+0.5) : (int)(x-0.5); 3259141cc406Sopenharmony_ci} 3260141cc406Sopenharmony_ci 3261141cc406Sopenharmony_cistatic SANE_Status 3262141cc406Sopenharmony_cifinecal(struct scanner *s) 3263141cc406Sopenharmony_ci{ 3264141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3265141cc406Sopenharmony_ci 3266141cc406Sopenharmony_ci int max_pages; 3267141cc406Sopenharmony_ci int gain_delta = 0xff - 0xbf; 3268141cc406Sopenharmony_ci float *gain_slope, *last_error; 3269141cc406Sopenharmony_ci int i, j, k, idx, try_count, cal_good; 3270141cc406Sopenharmony_ci 3271141cc406Sopenharmony_ci DBG (10, "finecal: start\n"); 3272141cc406Sopenharmony_ci 3273141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { /* S300, S1300 */ 3274141cc406Sopenharmony_ci max_pages = 2; 3275141cc406Sopenharmony_ci } 3276141cc406Sopenharmony_ci else /* fi-60f, S1100 */ 3277141cc406Sopenharmony_ci { 3278141cc406Sopenharmony_ci max_pages = 1; 3279141cc406Sopenharmony_ci } 3280141cc406Sopenharmony_ci 3281141cc406Sopenharmony_ci /* set fine dark offset to 0 and fix all fine gains to lowest parameter (0xFF) */ 3282141cc406Sopenharmony_ci for (i = 0; i < s->sendcal.width_bytes * s->sendcal.pages / 2; i++) 3283141cc406Sopenharmony_ci { 3284141cc406Sopenharmony_ci s->sendcal.buffer[i*2] = 0; 3285141cc406Sopenharmony_ci s->sendcal.buffer[i*2+1] = 0xff; 3286141cc406Sopenharmony_ci } 3287141cc406Sopenharmony_ci ret = finecal_send_cal(s); 3288141cc406Sopenharmony_ci if(ret) return ret; 3289141cc406Sopenharmony_ci 3290141cc406Sopenharmony_ci /* grab rows with lamp on */ 3291141cc406Sopenharmony_ci ret = lamp(s,1); 3292141cc406Sopenharmony_ci if(ret){ 3293141cc406Sopenharmony_ci DBG (5, "finecal: error lamp on\n"); 3294141cc406Sopenharmony_ci return ret; 3295141cc406Sopenharmony_ci } 3296141cc406Sopenharmony_ci 3297141cc406Sopenharmony_ci /* read the low-gain average of 16 lines */ 3298141cc406Sopenharmony_ci ret = finecal_get_line(s, &s->darkcal); 3299141cc406Sopenharmony_ci if(ret) return ret; 3300141cc406Sopenharmony_ci 3301141cc406Sopenharmony_ci /* set fine dark offset to 0 and fine gain to a fixed higher-gain parameter (0xBF) */ 3302141cc406Sopenharmony_ci for (i = 0; i < s->sendcal.width_bytes * s->sendcal.pages / 2; i++) 3303141cc406Sopenharmony_ci { 3304141cc406Sopenharmony_ci s->sendcal.buffer[i*2] = 0; 3305141cc406Sopenharmony_ci s->sendcal.buffer[i*2+1] = 0xbf; 3306141cc406Sopenharmony_ci } 3307141cc406Sopenharmony_ci ret = finecal_send_cal(s); 3308141cc406Sopenharmony_ci if(ret) return ret; 3309141cc406Sopenharmony_ci 3310141cc406Sopenharmony_ci /* read the high-gain average of 16 lines */ 3311141cc406Sopenharmony_ci ret = finecal_get_line(s, &s->lightcal); 3312141cc406Sopenharmony_ci if(ret) return ret; 3313141cc406Sopenharmony_ci 3314141cc406Sopenharmony_ci /* calculate the per pixel slope of pixel value delta over gain delta */ 3315141cc406Sopenharmony_ci gain_slope = malloc(s->lightcal.width_bytes * s->lightcal.pages * sizeof(float)); 3316141cc406Sopenharmony_ci if (!gain_slope) 3317141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 3318141cc406Sopenharmony_ci idx = 0; 3319141cc406Sopenharmony_ci for (i = 0; i < s->lightcal.pages; i++) 3320141cc406Sopenharmony_ci { 3321141cc406Sopenharmony_ci for (j = 0; j < s->lightcal.width_pix; j++) 3322141cc406Sopenharmony_ci { 3323141cc406Sopenharmony_ci for (k = 0; k < 3; k++) 3324141cc406Sopenharmony_ci { 3325141cc406Sopenharmony_ci int value_delta = s->lightcal.buffer[idx] - s->darkcal.buffer[idx]; 3326141cc406Sopenharmony_ci /* limit this slope to 1 or less, to avoid overshoot if the lightcal ref input is clipped at 255 */ 3327141cc406Sopenharmony_ci if (value_delta < gain_delta) 3328141cc406Sopenharmony_ci gain_slope[idx] = -1.0; 3329141cc406Sopenharmony_ci else 3330141cc406Sopenharmony_ci gain_slope[idx] = (float) -gain_delta / value_delta; 3331141cc406Sopenharmony_ci idx++; 3332141cc406Sopenharmony_ci } 3333141cc406Sopenharmony_ci } 3334141cc406Sopenharmony_ci } 3335141cc406Sopenharmony_ci 3336141cc406Sopenharmony_ci /* keep track of the last iteration's pixel error. If we overshoot, we can reduce the value of the gain slope */ 3337141cc406Sopenharmony_ci last_error = malloc(s->lightcal.width_bytes * s->lightcal.pages * sizeof(float)); 3338141cc406Sopenharmony_ci if (!last_error) 3339141cc406Sopenharmony_ci { 3340141cc406Sopenharmony_ci free(gain_slope); 3341141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 3342141cc406Sopenharmony_ci } 3343141cc406Sopenharmony_ci for (i = 0; i < s->lightcal.width_bytes * s->lightcal.pages; i++) 3344141cc406Sopenharmony_ci last_error[i] = 0.0; 3345141cc406Sopenharmony_ci 3346141cc406Sopenharmony_ci /* fine calibration feedback loop */ 3347141cc406Sopenharmony_ci try_count = 8; 3348141cc406Sopenharmony_ci while (try_count > 0) 3349141cc406Sopenharmony_ci { 3350141cc406Sopenharmony_ci int min_value[2][3], max_value[2][3]; 3351141cc406Sopenharmony_ci float avg_value[2][3], variance[2][3]; 3352141cc406Sopenharmony_ci int high_pegs = 0, low_pegs = 0; 3353141cc406Sopenharmony_ci try_count--; 3354141cc406Sopenharmony_ci 3355141cc406Sopenharmony_ci /* clear statistics arrays */ 3356141cc406Sopenharmony_ci for (i = 0; i < max_pages; i++) 3357141cc406Sopenharmony_ci { 3358141cc406Sopenharmony_ci for (k = 0; k < 3; k++) 3359141cc406Sopenharmony_ci { 3360141cc406Sopenharmony_ci min_value[i][k] = 0xff; 3361141cc406Sopenharmony_ci max_value[i][k] = 0; 3362141cc406Sopenharmony_ci avg_value[i][k] = 0; 3363141cc406Sopenharmony_ci variance[i][k] = 0; 3364141cc406Sopenharmony_ci } 3365141cc406Sopenharmony_ci } 3366141cc406Sopenharmony_ci 3367141cc406Sopenharmony_ci /* gather statistics and calculate new fine gain parameters based on observed error and the value/gain slope */ 3368141cc406Sopenharmony_ci idx = 0; 3369141cc406Sopenharmony_ci for (i = 0; i < max_pages; i++) 3370141cc406Sopenharmony_ci { 3371141cc406Sopenharmony_ci for (j = 0; j < s->lightcal.width_pix; j++) 3372141cc406Sopenharmony_ci { 3373141cc406Sopenharmony_ci for (k = 0; k < 3; k++) 3374141cc406Sopenharmony_ci { 3375141cc406Sopenharmony_ci int pixvalue = s->lightcal.buffer[idx]; 3376141cc406Sopenharmony_ci float pixerror = (fine_gain_target[i] * s->white_factor[k] - pixvalue); 3377141cc406Sopenharmony_ci int oldgain = s->sendcal.buffer[idx * 2 + 1]; 3378141cc406Sopenharmony_ci int newgain; 3379141cc406Sopenharmony_ci /* if we overshot the last correction, reduce the gain_slope */ 3380141cc406Sopenharmony_ci if (pixerror * last_error[idx] < 0.0) 3381141cc406Sopenharmony_ci gain_slope[idx] *= 0.75; 3382141cc406Sopenharmony_ci last_error[idx] = pixerror; 3383141cc406Sopenharmony_ci /* set the new gain */ 3384141cc406Sopenharmony_ci newgain = oldgain + (int) round2(pixerror * gain_slope[idx]); 3385141cc406Sopenharmony_ci if (newgain < 0) 3386141cc406Sopenharmony_ci { 3387141cc406Sopenharmony_ci low_pegs++; 3388141cc406Sopenharmony_ci s->sendcal.buffer[idx * 2 + 1] = 0; 3389141cc406Sopenharmony_ci } 3390141cc406Sopenharmony_ci else if (newgain > 0xff) 3391141cc406Sopenharmony_ci { 3392141cc406Sopenharmony_ci high_pegs++; 3393141cc406Sopenharmony_ci s->sendcal.buffer[idx * 2 + 1] = 0xff; 3394141cc406Sopenharmony_ci } 3395141cc406Sopenharmony_ci else 3396141cc406Sopenharmony_ci s->sendcal.buffer[idx * 2 + 1] = newgain; 3397141cc406Sopenharmony_ci /* update statistics */ 3398141cc406Sopenharmony_ci min_value[i][k] = MIN(min_value[i][k], pixvalue); 3399141cc406Sopenharmony_ci max_value[i][k] = MAX(max_value[i][k], pixvalue); 3400141cc406Sopenharmony_ci avg_value[i][k] += pixerror; 3401141cc406Sopenharmony_ci variance[i][k] += (pixerror * pixerror); 3402141cc406Sopenharmony_ci idx++; 3403141cc406Sopenharmony_ci } 3404141cc406Sopenharmony_ci } 3405141cc406Sopenharmony_ci } 3406141cc406Sopenharmony_ci /* finish the statistics calculations */ 3407141cc406Sopenharmony_ci cal_good = 1; 3408141cc406Sopenharmony_ci for (i = 0; i < max_pages; i++) 3409141cc406Sopenharmony_ci { 3410141cc406Sopenharmony_ci for (k = 0; k < 3; k++) 3411141cc406Sopenharmony_ci { 3412141cc406Sopenharmony_ci float sum = avg_value[i][k]; 3413141cc406Sopenharmony_ci float sum2 = variance[i][k]; 3414141cc406Sopenharmony_ci avg_value[i][k] = sum / s->lightcal.width_pix; 3415141cc406Sopenharmony_ci variance[i][k] = ((sum2 - (sum * sum / s->lightcal.width_pix)) / s->lightcal.width_pix); 3416141cc406Sopenharmony_ci /* if any color channel is too far out of whack, set cal_good to 0 so we'll iterate again */ 3417141cc406Sopenharmony_ci if (fabs(avg_value[i][k]) > 1.0 || variance[i][k] > 3.0) 3418141cc406Sopenharmony_ci cal_good = 0; 3419141cc406Sopenharmony_ci } 3420141cc406Sopenharmony_ci } 3421141cc406Sopenharmony_ci 3422141cc406Sopenharmony_ci /* print debug info */ 3423141cc406Sopenharmony_ci DBG (15, "finecal: -------------------- Gain\n"); 3424141cc406Sopenharmony_ci DBG (15, "finecal: RGB Average Error - Front: (%.1f,%.1f,%.1f) - Back: (%.1f,%.1f,%.1f)\n", 3425141cc406Sopenharmony_ci avg_value[0][0], avg_value[0][1], avg_value[0][2], avg_value[1][0], avg_value[1][1], avg_value[1][2]); 3426141cc406Sopenharmony_ci DBG (15, "finecal: RGB Maximum - Front: (%i,%i,%i) - Back: (%i,%i,%i)\n", 3427141cc406Sopenharmony_ci max_value[0][0], max_value[0][1], max_value[0][2], max_value[1][0], max_value[1][1], max_value[1][2]); 3428141cc406Sopenharmony_ci DBG (15, "finecal: RGB Minimum - Front: (%i,%i,%i) - Back: (%i,%i,%i)\n", 3429141cc406Sopenharmony_ci min_value[0][0], min_value[0][1], min_value[0][2], min_value[1][0], min_value[1][1], min_value[1][2]); 3430141cc406Sopenharmony_ci DBG (15, "finecal: Variance - Front: (%.1f,%.1f,%.1f) - Back: (%.1f,%.1f,%.1f)\n", 3431141cc406Sopenharmony_ci variance[0][0], variance[0][1], variance[0][2], variance[1][0], variance[1][1], variance[1][2]); 3432141cc406Sopenharmony_ci DBG (15, "finecal: Pegged gain parameters - High (0xff): %i - Low (0): %i\n", high_pegs, low_pegs); 3433141cc406Sopenharmony_ci 3434141cc406Sopenharmony_ci /* break out of the loop if our calibration is done */ 3435141cc406Sopenharmony_ci if (cal_good) break; 3436141cc406Sopenharmony_ci 3437141cc406Sopenharmony_ci /* send the new calibration and read a new line */ 3438141cc406Sopenharmony_ci ret = finecal_send_cal(s); 3439141cc406Sopenharmony_ci if(ret) { free(gain_slope); free(last_error); return ret; } 3440141cc406Sopenharmony_ci ret = finecal_get_line(s, &s->lightcal); 3441141cc406Sopenharmony_ci if(ret) { free(gain_slope); free(last_error); return ret; } 3442141cc406Sopenharmony_ci } 3443141cc406Sopenharmony_ci 3444141cc406Sopenharmony_ci /* release the memory for the reference slope data */ 3445141cc406Sopenharmony_ci free(gain_slope); 3446141cc406Sopenharmony_ci free(last_error); 3447141cc406Sopenharmony_ci 3448141cc406Sopenharmony_ci DBG (10, "finecal: finish\n"); 3449141cc406Sopenharmony_ci return ret; 3450141cc406Sopenharmony_ci} 3451141cc406Sopenharmony_ci 3452141cc406Sopenharmony_ci/* 3453141cc406Sopenharmony_ci * set scanner lamp brightness 3454141cc406Sopenharmony_ci */ 3455141cc406Sopenharmony_cistatic SANE_Status 3456141cc406Sopenharmony_cilamp(struct scanner *s, unsigned char set) 3457141cc406Sopenharmony_ci{ 3458141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3459141cc406Sopenharmony_ci unsigned char cmd[2]; 3460141cc406Sopenharmony_ci size_t cmdLen = 2; 3461141cc406Sopenharmony_ci unsigned char stat[1]; 3462141cc406Sopenharmony_ci size_t statLen = 1; 3463141cc406Sopenharmony_ci 3464141cc406Sopenharmony_ci DBG (10, "lamp: start (%d)\n", set); 3465141cc406Sopenharmony_ci 3466141cc406Sopenharmony_ci /*send cmd*/ 3467141cc406Sopenharmony_ci cmd[0] = 0x1b; 3468141cc406Sopenharmony_ci cmd[1] = 0xd0; 3469141cc406Sopenharmony_ci 3470141cc406Sopenharmony_ci ret = do_cmd( 3471141cc406Sopenharmony_ci s, 0, 3472141cc406Sopenharmony_ci cmd, cmdLen, 3473141cc406Sopenharmony_ci NULL, 0, 3474141cc406Sopenharmony_ci stat, &statLen 3475141cc406Sopenharmony_ci ); 3476141cc406Sopenharmony_ci if(ret){ 3477141cc406Sopenharmony_ci DBG (5, "lamp: error sending cmd\n"); 3478141cc406Sopenharmony_ci return ret; 3479141cc406Sopenharmony_ci } 3480141cc406Sopenharmony_ci if(stat[0] != 6){ 3481141cc406Sopenharmony_ci DBG (5, "lamp: cmd bad status?\n"); 3482141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3483141cc406Sopenharmony_ci } 3484141cc406Sopenharmony_ci 3485141cc406Sopenharmony_ci /*send payload*/ 3486141cc406Sopenharmony_ci cmd[0] = set; 3487141cc406Sopenharmony_ci cmdLen = 1; 3488141cc406Sopenharmony_ci statLen = 1; 3489141cc406Sopenharmony_ci 3490141cc406Sopenharmony_ci ret = do_cmd( 3491141cc406Sopenharmony_ci s, 0, 3492141cc406Sopenharmony_ci cmd, cmdLen, 3493141cc406Sopenharmony_ci NULL, 0, 3494141cc406Sopenharmony_ci stat, &statLen 3495141cc406Sopenharmony_ci ); 3496141cc406Sopenharmony_ci if(ret){ 3497141cc406Sopenharmony_ci DBG (5, "lamp: error sending payload\n"); 3498141cc406Sopenharmony_ci return ret; 3499141cc406Sopenharmony_ci } 3500141cc406Sopenharmony_ci if(stat[0] != 6){ 3501141cc406Sopenharmony_ci DBG (5, "lamp: payload bad status?\n"); 3502141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3503141cc406Sopenharmony_ci } 3504141cc406Sopenharmony_ci 3505141cc406Sopenharmony_ci DBG (10, "lamp: finish\n"); 3506141cc406Sopenharmony_ci return ret; 3507141cc406Sopenharmony_ci} 3508141cc406Sopenharmony_ci 3509141cc406Sopenharmony_cistatic SANE_Status 3510141cc406Sopenharmony_ciset_window(struct scanner *s, int window) 3511141cc406Sopenharmony_ci{ 3512141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3513141cc406Sopenharmony_ci 3514141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b, 0xd1}; 3515141cc406Sopenharmony_ci size_t cmdLen = sizeof(cmd); 3516141cc406Sopenharmony_ci unsigned char stat[] = {0}; 3517141cc406Sopenharmony_ci size_t statLen = sizeof(stat); 3518141cc406Sopenharmony_ci unsigned char * payload; 3519141cc406Sopenharmony_ci size_t paylen = SET_WINDOW_LEN; 3520141cc406Sopenharmony_ci 3521141cc406Sopenharmony_ci DBG (10, "set_window: start, window %d\n",window); 3522141cc406Sopenharmony_ci 3523141cc406Sopenharmony_ci switch (window) { 3524141cc406Sopenharmony_ci case WINDOW_COARSECAL: 3525141cc406Sopenharmony_ci payload = s->setWindowCoarseCal; 3526141cc406Sopenharmony_ci paylen = s->setWindowCoarseCalLen; 3527141cc406Sopenharmony_ci break; 3528141cc406Sopenharmony_ci case WINDOW_FINECAL: 3529141cc406Sopenharmony_ci payload = s->setWindowFineCal; 3530141cc406Sopenharmony_ci paylen = s->setWindowFineCalLen; 3531141cc406Sopenharmony_ci break; 3532141cc406Sopenharmony_ci case WINDOW_SENDCAL: 3533141cc406Sopenharmony_ci payload = s->setWindowSendCal; 3534141cc406Sopenharmony_ci paylen = s->setWindowSendCalLen; 3535141cc406Sopenharmony_ci break; 3536141cc406Sopenharmony_ci case WINDOW_SCAN: 3537141cc406Sopenharmony_ci payload = s->setWindowScan; 3538141cc406Sopenharmony_ci paylen = s->setWindowScanLen; 3539141cc406Sopenharmony_ci set_SW_ypix(payload,s->fullscan.height); 3540141cc406Sopenharmony_ci break; 3541141cc406Sopenharmony_ci default: 3542141cc406Sopenharmony_ci DBG (5, "set_window: unknown window\n"); 3543141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3544141cc406Sopenharmony_ci } 3545141cc406Sopenharmony_ci 3546141cc406Sopenharmony_ci /*send cmd*/ 3547141cc406Sopenharmony_ci ret = do_cmd( 3548141cc406Sopenharmony_ci s, 0, 3549141cc406Sopenharmony_ci cmd, cmdLen, 3550141cc406Sopenharmony_ci NULL, 0, 3551141cc406Sopenharmony_ci stat, &statLen 3552141cc406Sopenharmony_ci ); 3553141cc406Sopenharmony_ci if(ret){ 3554141cc406Sopenharmony_ci DBG (5, "set_window: error sending cmd\n"); 3555141cc406Sopenharmony_ci return ret; 3556141cc406Sopenharmony_ci } 3557141cc406Sopenharmony_ci if(stat[0] != 6){ 3558141cc406Sopenharmony_ci DBG (5, "set_window: cmd bad status?\n"); 3559141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3560141cc406Sopenharmony_ci } 3561141cc406Sopenharmony_ci 3562141cc406Sopenharmony_ci /*send payload*/ 3563141cc406Sopenharmony_ci statLen = 1; 3564141cc406Sopenharmony_ci 3565141cc406Sopenharmony_ci ret = do_cmd( 3566141cc406Sopenharmony_ci s, 0, 3567141cc406Sopenharmony_ci payload, paylen, 3568141cc406Sopenharmony_ci NULL, 0, 3569141cc406Sopenharmony_ci stat, &statLen 3570141cc406Sopenharmony_ci ); 3571141cc406Sopenharmony_ci if(ret){ 3572141cc406Sopenharmony_ci DBG (5, "set_window: error sending payload\n"); 3573141cc406Sopenharmony_ci return ret; 3574141cc406Sopenharmony_ci } 3575141cc406Sopenharmony_ci if(stat[0] != 6){ 3576141cc406Sopenharmony_ci DBG (5, "set_window: payload bad status?\n"); 3577141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3578141cc406Sopenharmony_ci } 3579141cc406Sopenharmony_ci 3580141cc406Sopenharmony_ci DBG (10, "set_window: finish\n"); 3581141cc406Sopenharmony_ci return ret; 3582141cc406Sopenharmony_ci} 3583141cc406Sopenharmony_ci 3584141cc406Sopenharmony_ci/* instead of internal brightness/contrast/gamma 3585141cc406Sopenharmony_ci scanners uses 12bit x 12bit LUT 3586141cc406Sopenharmony_ci default is linear table of slope 1 3587141cc406Sopenharmony_ci brightness and contrast inputs are -127 to +127 3588141cc406Sopenharmony_ci 3589141cc406Sopenharmony_ci contrast rotates slope of line around central input val 3590141cc406Sopenharmony_ci 3591141cc406Sopenharmony_ci high low 3592141cc406Sopenharmony_ci . x . 3593141cc406Sopenharmony_ci . x . xx 3594141cc406Sopenharmony_ci out . x . xxxxxxxx 3595141cc406Sopenharmony_ci . x xx 3596141cc406Sopenharmony_ci ....x....... ............ 3597141cc406Sopenharmony_ci in in 3598141cc406Sopenharmony_ci 3599141cc406Sopenharmony_ci then brightness moves line vertically, and clamps to 8bit 3600141cc406Sopenharmony_ci 3601141cc406Sopenharmony_ci bright dark 3602141cc406Sopenharmony_ci . xxxxxxxx . 3603141cc406Sopenharmony_ci . x . 3604141cc406Sopenharmony_ci out x . x 3605141cc406Sopenharmony_ci . . x 3606141cc406Sopenharmony_ci ............ xxxxxxxx.... 3607141cc406Sopenharmony_ci in in 3608141cc406Sopenharmony_ci */ 3609141cc406Sopenharmony_cistatic SANE_Status 3610141cc406Sopenharmony_cisend_lut (struct scanner *s) 3611141cc406Sopenharmony_ci{ 3612141cc406Sopenharmony_ci SANE_Status ret=SANE_STATUS_GOOD; 3613141cc406Sopenharmony_ci 3614141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b, 0xc5}; 3615141cc406Sopenharmony_ci size_t cmdLen = 2; 3616141cc406Sopenharmony_ci unsigned char stat[1]; 3617141cc406Sopenharmony_ci size_t statLen = 1; 3618141cc406Sopenharmony_ci unsigned char *out; 3619141cc406Sopenharmony_ci size_t outLen; 3620141cc406Sopenharmony_ci 3621141cc406Sopenharmony_ci int i, j; 3622141cc406Sopenharmony_ci double b, slope, offset; 3623141cc406Sopenharmony_ci int width; 3624141cc406Sopenharmony_ci int height; 3625141cc406Sopenharmony_ci 3626141cc406Sopenharmony_ci DBG (10, "send_lut: start\n"); 3627141cc406Sopenharmony_ci 3628141cc406Sopenharmony_ci if (s->model == MODEL_S1100){ 3629141cc406Sopenharmony_ci outLen = 0x200; 3630141cc406Sopenharmony_ci width = outLen / 2; /* 1 color, 2 bytes */ 3631141cc406Sopenharmony_ci height = width; /* square table */ 3632141cc406Sopenharmony_ci } 3633141cc406Sopenharmony_ci else if (s->model == MODEL_FI65F){ 3634141cc406Sopenharmony_ci outLen = 0x600; 3635141cc406Sopenharmony_ci width = outLen / 6; /* 3 color, 2 bytes */ 3636141cc406Sopenharmony_ci height = width; /* square table */ 3637141cc406Sopenharmony_ci } 3638141cc406Sopenharmony_ci else { 3639141cc406Sopenharmony_ci outLen = 0x6000; 3640141cc406Sopenharmony_ci width = outLen / 6; /* 3 colors, 2 bytes */ 3641141cc406Sopenharmony_ci height = width; /* square table */ 3642141cc406Sopenharmony_ci } 3643141cc406Sopenharmony_ci out = ( unsigned char *)malloc(outLen*sizeof(unsigned char)); 3644141cc406Sopenharmony_ci if (out == NULL){ 3645141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 3646141cc406Sopenharmony_ci } 3647141cc406Sopenharmony_ci 3648141cc406Sopenharmony_ci /* contrast is converted to a slope [0,90] degrees: 3649141cc406Sopenharmony_ci * first [-127,127] to [0,254] then to [0,1] 3650141cc406Sopenharmony_ci * then multiply by PI/2 to convert to radians 3651141cc406Sopenharmony_ci * then take the tangent to get slope (T.O.A) 3652141cc406Sopenharmony_ci * then multiply by the normal linear slope 3653141cc406Sopenharmony_ci * because the table may not be square, i.e. 1024x256*/ 3654141cc406Sopenharmony_ci slope = tan(((double)s->contrast+127)/254 * M_PI/2); 3655141cc406Sopenharmony_ci 3656141cc406Sopenharmony_ci /* contrast slope must stay centered, so figure 3657141cc406Sopenharmony_ci * out vertical offset at central input value */ 3658141cc406Sopenharmony_ci offset = height/2 - slope*width/2; 3659141cc406Sopenharmony_ci 3660141cc406Sopenharmony_ci /* convert the user brightness setting (-127 to +127) 3661141cc406Sopenharmony_ci * into a scale that covers the range required 3662141cc406Sopenharmony_ci * to slide the contrast curve entirely off the table */ 3663141cc406Sopenharmony_ci b = ((double)s->brightness/127) * (slope*(width-1) + offset); 3664141cc406Sopenharmony_ci 3665141cc406Sopenharmony_ci DBG (15, "send_lut: %d %f %d %f %f\n", s->brightness, b, 3666141cc406Sopenharmony_ci s->contrast, slope, offset); 3667141cc406Sopenharmony_ci 3668141cc406Sopenharmony_ci for(i=0;i<width;i++){ 3669141cc406Sopenharmony_ci j=slope*i + offset + b; 3670141cc406Sopenharmony_ci 3671141cc406Sopenharmony_ci j = MAX(j, 0); 3672141cc406Sopenharmony_ci j = MIN(j, height-1); 3673141cc406Sopenharmony_ci 3674141cc406Sopenharmony_ci if (s->model == MODEL_S1100){ 3675141cc406Sopenharmony_ci /*only one table, be order*/ 3676141cc406Sopenharmony_ci out[i*2] = (j >> 8) & 0xff; 3677141cc406Sopenharmony_ci out[i*2+1] = j & 0xff; 3678141cc406Sopenharmony_ci } 3679141cc406Sopenharmony_ci else if (s->model == MODEL_FI65F){ 3680141cc406Sopenharmony_ci /*first table, be order*/ 3681141cc406Sopenharmony_ci out[i*2] = (j >> 8) & 0xff; 3682141cc406Sopenharmony_ci out[i*2+1] = j & 0xff; 3683141cc406Sopenharmony_ci 3684141cc406Sopenharmony_ci /*second table, be order*/ 3685141cc406Sopenharmony_ci out[width*2 + i*2] = (j >> 8) & 0xff; 3686141cc406Sopenharmony_ci out[width*2 + i*2+1] = j & 0xff; 3687141cc406Sopenharmony_ci 3688141cc406Sopenharmony_ci /*third table, be order*/ 3689141cc406Sopenharmony_ci out[width*4 + i*2] = (j >> 8) & 0xff; 3690141cc406Sopenharmony_ci out[width*4 + i*2+1] = j & 0xff; 3691141cc406Sopenharmony_ci } 3692141cc406Sopenharmony_ci else { 3693141cc406Sopenharmony_ci /*first table, le order*/ 3694141cc406Sopenharmony_ci out[i*2] = j & 0xff; 3695141cc406Sopenharmony_ci out[i*2+1] = (j >> 8) & 0x0f; 3696141cc406Sopenharmony_ci 3697141cc406Sopenharmony_ci /*second table, le order*/ 3698141cc406Sopenharmony_ci out[width*2 + i*2] = j & 0xff; 3699141cc406Sopenharmony_ci out[width*2 + i*2+1] = (j >> 8) & 0x0f; 3700141cc406Sopenharmony_ci 3701141cc406Sopenharmony_ci /*third table, le order*/ 3702141cc406Sopenharmony_ci out[width*4 + i*2] = j & 0xff; 3703141cc406Sopenharmony_ci out[width*4 + i*2+1] = (j >> 8) & 0x0f; 3704141cc406Sopenharmony_ci } 3705141cc406Sopenharmony_ci } 3706141cc406Sopenharmony_ci 3707141cc406Sopenharmony_ci ret = do_cmd( 3708141cc406Sopenharmony_ci s, 0, 3709141cc406Sopenharmony_ci cmd, cmdLen, 3710141cc406Sopenharmony_ci NULL, 0, 3711141cc406Sopenharmony_ci stat, &statLen 3712141cc406Sopenharmony_ci ); 3713141cc406Sopenharmony_ci if(ret){ 3714141cc406Sopenharmony_ci DBG (5, "send_lut: error sending cmd\n"); 3715141cc406Sopenharmony_ci return ret; 3716141cc406Sopenharmony_ci } 3717141cc406Sopenharmony_ci if(stat[0] != 6){ 3718141cc406Sopenharmony_ci DBG (5, "send_lut: cmd bad status?\n"); 3719141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3720141cc406Sopenharmony_ci } 3721141cc406Sopenharmony_ci 3722141cc406Sopenharmony_ci statLen = 1; 3723141cc406Sopenharmony_ci ret = do_cmd( 3724141cc406Sopenharmony_ci s, 0, 3725141cc406Sopenharmony_ci out, outLen, 3726141cc406Sopenharmony_ci NULL, 0, 3727141cc406Sopenharmony_ci stat, &statLen 3728141cc406Sopenharmony_ci ); 3729141cc406Sopenharmony_ci if(ret){ 3730141cc406Sopenharmony_ci DBG (5, "send_lut: error sending out\n"); 3731141cc406Sopenharmony_ci return ret; 3732141cc406Sopenharmony_ci } 3733141cc406Sopenharmony_ci if(stat[0] != 6){ 3734141cc406Sopenharmony_ci DBG (5, "send_lut: out bad status?\n"); 3735141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3736141cc406Sopenharmony_ci } 3737141cc406Sopenharmony_ci 3738141cc406Sopenharmony_ci DBG (10, "send_lut: finish\n"); 3739141cc406Sopenharmony_ci 3740141cc406Sopenharmony_ci return ret; 3741141cc406Sopenharmony_ci} 3742141cc406Sopenharmony_ci 3743141cc406Sopenharmony_cistatic SANE_Status 3744141cc406Sopenharmony_ciget_hardware_status (struct scanner *s) 3745141cc406Sopenharmony_ci{ 3746141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3747141cc406Sopenharmony_ci 3748141cc406Sopenharmony_ci DBG (10, "get_hardware_status: start\n"); 3749141cc406Sopenharmony_ci 3750141cc406Sopenharmony_ci /* only run this once every second */ 3751141cc406Sopenharmony_ci if (s->last_ghs < time(NULL)) { 3752141cc406Sopenharmony_ci 3753141cc406Sopenharmony_ci unsigned char cmd[2]; 3754141cc406Sopenharmony_ci size_t cmdLen = sizeof(cmd); 3755141cc406Sopenharmony_ci unsigned char pay[4]; 3756141cc406Sopenharmony_ci size_t payLen = sizeof(pay); 3757141cc406Sopenharmony_ci 3758141cc406Sopenharmony_ci DBG (15, "get_hardware_status: running\n"); 3759141cc406Sopenharmony_ci 3760141cc406Sopenharmony_ci cmd[0] = 0x1b; 3761141cc406Sopenharmony_ci cmd[1] = 0x33; 3762141cc406Sopenharmony_ci 3763141cc406Sopenharmony_ci ret = do_cmd( 3764141cc406Sopenharmony_ci s, 0, 3765141cc406Sopenharmony_ci cmd, cmdLen, 3766141cc406Sopenharmony_ci NULL, 0, 3767141cc406Sopenharmony_ci pay, &payLen 3768141cc406Sopenharmony_ci ); 3769141cc406Sopenharmony_ci if(ret){ 3770141cc406Sopenharmony_ci DBG (5, "get_hardware_status: error sending cmd\n"); 3771141cc406Sopenharmony_ci return ret; 3772141cc406Sopenharmony_ci } 3773141cc406Sopenharmony_ci 3774141cc406Sopenharmony_ci hexdump(5,"ghspayload: ", pay, payLen); 3775141cc406Sopenharmony_ci 3776141cc406Sopenharmony_ci s->last_ghs = time(NULL); 3777141cc406Sopenharmony_ci 3778141cc406Sopenharmony_ci s->hw_top = ((pay[0] >> 7) & 0x01); 3779141cc406Sopenharmony_ci s->hw_hopper = !((pay[0] >> 6) & 0x01); 3780141cc406Sopenharmony_ci s->hw_adf_open = ((pay[0] >> 5) & 0x01); 3781141cc406Sopenharmony_ci 3782141cc406Sopenharmony_ci s->hw_sleep = ((pay[1] >> 7) & 0x01); 3783141cc406Sopenharmony_ci s->hw_scan_sw = ((pay[1] >> 0) & 0x01); 3784141cc406Sopenharmony_ci } 3785141cc406Sopenharmony_ci 3786141cc406Sopenharmony_ci DBG (10, "get_hardware_status: finish\n"); 3787141cc406Sopenharmony_ci 3788141cc406Sopenharmony_ci return ret; 3789141cc406Sopenharmony_ci} 3790141cc406Sopenharmony_ci 3791141cc406Sopenharmony_cistatic SANE_Status 3792141cc406Sopenharmony_ciobject_position(struct scanner *s, int ingest) 3793141cc406Sopenharmony_ci{ 3794141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 3795141cc406Sopenharmony_ci int i; 3796141cc406Sopenharmony_ci unsigned char cmd[2]; 3797141cc406Sopenharmony_ci size_t cmdLen = sizeof(cmd); 3798141cc406Sopenharmony_ci unsigned char stat[1]; 3799141cc406Sopenharmony_ci size_t statLen = sizeof(stat); 3800141cc406Sopenharmony_ci unsigned char pay[2]; 3801141cc406Sopenharmony_ci size_t payLen = sizeof(pay); 3802141cc406Sopenharmony_ci 3803141cc406Sopenharmony_ci DBG (10, "object_position: start\n"); 3804141cc406Sopenharmony_ci 3805141cc406Sopenharmony_ci i = (ingest)?5:1; 3806141cc406Sopenharmony_ci 3807141cc406Sopenharmony_ci while(i--){ 3808141cc406Sopenharmony_ci /*send paper load cmd*/ 3809141cc406Sopenharmony_ci cmd[0] = 0x1b; 3810141cc406Sopenharmony_ci cmd[1] = 0xd4; 3811141cc406Sopenharmony_ci statLen = 1; 3812141cc406Sopenharmony_ci 3813141cc406Sopenharmony_ci ret = do_cmd( 3814141cc406Sopenharmony_ci s, 0, 3815141cc406Sopenharmony_ci cmd, cmdLen, 3816141cc406Sopenharmony_ci NULL, 0, 3817141cc406Sopenharmony_ci stat, &statLen 3818141cc406Sopenharmony_ci ); 3819141cc406Sopenharmony_ci if(ret){ 3820141cc406Sopenharmony_ci DBG (5, "object_position: error sending cmd\n"); 3821141cc406Sopenharmony_ci return ret; 3822141cc406Sopenharmony_ci } 3823141cc406Sopenharmony_ci if(stat[0] != 6){ 3824141cc406Sopenharmony_ci DBG (5, "object_position: cmd bad status? %d\n",stat[0]); 3825141cc406Sopenharmony_ci continue; 3826141cc406Sopenharmony_ci } 3827141cc406Sopenharmony_ci 3828141cc406Sopenharmony_ci /*send payload*/ 3829141cc406Sopenharmony_ci statLen = 1; 3830141cc406Sopenharmony_ci payLen = 1; 3831141cc406Sopenharmony_ci pay[0] = ingest; 3832141cc406Sopenharmony_ci 3833141cc406Sopenharmony_ci ret = do_cmd( 3834141cc406Sopenharmony_ci s, 0, 3835141cc406Sopenharmony_ci pay, payLen, 3836141cc406Sopenharmony_ci NULL, 0, 3837141cc406Sopenharmony_ci stat, &statLen 3838141cc406Sopenharmony_ci ); 3839141cc406Sopenharmony_ci if(ret){ 3840141cc406Sopenharmony_ci DBG (5, "object_position: error sending payload\n"); 3841141cc406Sopenharmony_ci return ret; 3842141cc406Sopenharmony_ci } 3843141cc406Sopenharmony_ci if(stat[0] == 6){ 3844141cc406Sopenharmony_ci DBG (5, "object_position: found paper?\n"); 3845141cc406Sopenharmony_ci break; 3846141cc406Sopenharmony_ci } 3847141cc406Sopenharmony_ci else if(stat[0] == 0x15 || stat[0] == 0){ 3848141cc406Sopenharmony_ci DBG (5, "object_position: no paper?\n"); 3849141cc406Sopenharmony_ci ret=SANE_STATUS_NO_DOCS; 3850141cc406Sopenharmony_ci continue; 3851141cc406Sopenharmony_ci } 3852141cc406Sopenharmony_ci else{ 3853141cc406Sopenharmony_ci DBG (5, "object_position: payload bad status?\n"); 3854141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3855141cc406Sopenharmony_ci } 3856141cc406Sopenharmony_ci } 3857141cc406Sopenharmony_ci 3858141cc406Sopenharmony_ci DBG (10, "object_position: finish\n"); 3859141cc406Sopenharmony_ci return ret; 3860141cc406Sopenharmony_ci} 3861141cc406Sopenharmony_ci 3862141cc406Sopenharmony_cistatic SANE_Status 3863141cc406Sopenharmony_ciscan(struct scanner *s) 3864141cc406Sopenharmony_ci{ 3865141cc406Sopenharmony_ci SANE_Status ret=SANE_STATUS_GOOD; 3866141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b, 0xd2}; 3867141cc406Sopenharmony_ci size_t cmdLen = 2; 3868141cc406Sopenharmony_ci unsigned char stat[1]; 3869141cc406Sopenharmony_ci size_t statLen = 1; 3870141cc406Sopenharmony_ci 3871141cc406Sopenharmony_ci DBG (10, "scan: start\n"); 3872141cc406Sopenharmony_ci 3873141cc406Sopenharmony_ci if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i){ 3874141cc406Sopenharmony_ci cmd[1] = 0xd6; 3875141cc406Sopenharmony_ci } 3876141cc406Sopenharmony_ci 3877141cc406Sopenharmony_ci ret = do_cmd( 3878141cc406Sopenharmony_ci s, 0, 3879141cc406Sopenharmony_ci cmd, cmdLen, 3880141cc406Sopenharmony_ci NULL, 0, 3881141cc406Sopenharmony_ci stat, &statLen 3882141cc406Sopenharmony_ci ); 3883141cc406Sopenharmony_ci if(ret){ 3884141cc406Sopenharmony_ci DBG (5, "scan: error sending cmd\n"); 3885141cc406Sopenharmony_ci return ret; 3886141cc406Sopenharmony_ci } 3887141cc406Sopenharmony_ci if(stat[0] != 6){ 3888141cc406Sopenharmony_ci DBG (5, "scan: cmd bad status?\n"); 3889141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3890141cc406Sopenharmony_ci } 3891141cc406Sopenharmony_ci 3892141cc406Sopenharmony_ci DBG (10, "scan: finish\n"); 3893141cc406Sopenharmony_ci 3894141cc406Sopenharmony_ci return ret; 3895141cc406Sopenharmony_ci} 3896141cc406Sopenharmony_ci 3897141cc406Sopenharmony_ci/* 3898141cc406Sopenharmony_ci * Called by SANE to read data. 3899141cc406Sopenharmony_ci * 3900141cc406Sopenharmony_ci * From the SANE spec: 3901141cc406Sopenharmony_ci * This function is used to read image data from the device 3902141cc406Sopenharmony_ci * represented by handle h. Argument buf is a pointer to a memory 3903141cc406Sopenharmony_ci * area that is at least maxlen bytes long. The number of bytes 3904141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when 3905141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is 3906141cc406Sopenharmony_ci * returned). 3907141cc406Sopenharmony_ci * 3908141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be 3909141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes. 3910141cc406Sopenharmony_ci */ 3911141cc406Sopenharmony_ciSANE_Status 3912141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len) 3913141cc406Sopenharmony_ci{ 3914141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 3915141cc406Sopenharmony_ci SANE_Status ret=SANE_STATUS_GOOD; 3916141cc406Sopenharmony_ci struct page * page; 3917141cc406Sopenharmony_ci 3918141cc406Sopenharmony_ci DBG (10, "sane_read: start si:%d len:%d max:%d\n",s->side,*len,max_len); 3919141cc406Sopenharmony_ci 3920141cc406Sopenharmony_ci *len = 0; 3921141cc406Sopenharmony_ci 3922141cc406Sopenharmony_ci /* cancelled? */ 3923141cc406Sopenharmony_ci if(!s->started){ 3924141cc406Sopenharmony_ci DBG (5, "sane_read: call sane_start first\n"); 3925141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 3926141cc406Sopenharmony_ci } 3927141cc406Sopenharmony_ci 3928141cc406Sopenharmony_ci page = &s->pages[s->side]; 3929141cc406Sopenharmony_ci 3930141cc406Sopenharmony_ci /* have sent all of current buffer */ 3931141cc406Sopenharmony_ci if(s->fullscan.done && page->done){ 3932141cc406Sopenharmony_ci DBG (10, "sane_read: returning eof\n"); 3933141cc406Sopenharmony_ci 3934141cc406Sopenharmony_ci /*S1100 needs help to turn off button*/ 3935141cc406Sopenharmony_ci if(s->model == MODEL_S1100){ 3936141cc406Sopenharmony_ci usleep(15000); 3937141cc406Sopenharmony_ci 3938141cc406Sopenharmony_ci /* eject paper */ 3939141cc406Sopenharmony_ci ret = object_position(s,EPJITSU_PAPER_EJECT); 3940141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_NO_DOCS) { 3941141cc406Sopenharmony_ci DBG (5, "sane_read: ERROR: failed to eject\n"); 3942141cc406Sopenharmony_ci return ret; 3943141cc406Sopenharmony_ci } 3944141cc406Sopenharmony_ci 3945141cc406Sopenharmony_ci /* reset flashing button? */ 3946141cc406Sopenharmony_ci ret = six5(s); 3947141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 3948141cc406Sopenharmony_ci DBG (5, "sane_read: ERROR: failed to six5\n"); 3949141cc406Sopenharmony_ci return ret; 3950141cc406Sopenharmony_ci } 3951141cc406Sopenharmony_ci } 3952141cc406Sopenharmony_ci 3953141cc406Sopenharmony_ci return SANE_STATUS_EOF; 3954141cc406Sopenharmony_ci } 3955141cc406Sopenharmony_ci 3956141cc406Sopenharmony_ci /* scan not finished, get more into block buffer */ 3957141cc406Sopenharmony_ci if(!s->fullscan.done) 3958141cc406Sopenharmony_ci { 3959141cc406Sopenharmony_ci /* block buffer currently empty, clean up */ 3960141cc406Sopenharmony_ci if(!s->block_xfr.rx_bytes) 3961141cc406Sopenharmony_ci { 3962141cc406Sopenharmony_ci /* block buffer bigger than remainder of scan, shrink block */ 3963141cc406Sopenharmony_ci int remainTotal = s->fullscan.total_bytes - s->fullscan.rx_bytes; 3964141cc406Sopenharmony_ci if(remainTotal < s->block_xfr.total_bytes) 3965141cc406Sopenharmony_ci { 3966141cc406Sopenharmony_ci DBG (15, "sane_read: shrinking block to %lu\n", (unsigned long)remainTotal); 3967141cc406Sopenharmony_ci s->block_xfr.total_bytes = remainTotal; 3968141cc406Sopenharmony_ci } 3969141cc406Sopenharmony_ci /* send d3 cmd for S300, S1100, S1300 */ 3970141cc406Sopenharmony_ci if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i) 3971141cc406Sopenharmony_ci { 3972141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b, 0xd3}; 3973141cc406Sopenharmony_ci size_t cmdLen = 2; 3974141cc406Sopenharmony_ci unsigned char stat[1]; 3975141cc406Sopenharmony_ci size_t statLen = 1; 3976141cc406Sopenharmony_ci 3977141cc406Sopenharmony_ci DBG (15, "sane_read: d3\n"); 3978141cc406Sopenharmony_ci 3979141cc406Sopenharmony_ci ret = do_cmd( 3980141cc406Sopenharmony_ci s, 0, 3981141cc406Sopenharmony_ci cmd, cmdLen, 3982141cc406Sopenharmony_ci NULL, 0, 3983141cc406Sopenharmony_ci stat, &statLen 3984141cc406Sopenharmony_ci ); 3985141cc406Sopenharmony_ci if(ret){ 3986141cc406Sopenharmony_ci DBG (5, "sane_read: error sending d3 cmd\n"); 3987141cc406Sopenharmony_ci return ret; 3988141cc406Sopenharmony_ci } 3989141cc406Sopenharmony_ci if(stat[0] != 6){ 3990141cc406Sopenharmony_ci DBG (5, "sane_read: cmd bad status?\n"); 3991141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 3992141cc406Sopenharmony_ci } 3993141cc406Sopenharmony_ci } 3994141cc406Sopenharmony_ci } 3995141cc406Sopenharmony_ci 3996141cc406Sopenharmony_ci ret = read_from_scanner(s, &s->block_xfr); 3997141cc406Sopenharmony_ci if(ret){ 3998141cc406Sopenharmony_ci DBG (5, "sane_read: can't read from scanner\n"); 3999141cc406Sopenharmony_ci return ret; 4000141cc406Sopenharmony_ci } 4001141cc406Sopenharmony_ci 4002141cc406Sopenharmony_ci /* block filled, copy to front/back */ 4003141cc406Sopenharmony_ci if(s->block_xfr.done) 4004141cc406Sopenharmony_ci { 4005141cc406Sopenharmony_ci DBG (15, "sane_read: block buffer full\n"); 4006141cc406Sopenharmony_ci 4007141cc406Sopenharmony_ci /* convert the raw color data into normal packed pixel data */ 4008141cc406Sopenharmony_ci descramble_raw(s, &s->block_xfr); 4009141cc406Sopenharmony_ci 4010141cc406Sopenharmony_ci s->block_xfr.done = 0; 4011141cc406Sopenharmony_ci 4012141cc406Sopenharmony_ci /* get the 0x43 cmd for the S300, S1100, S1300 */ 4013141cc406Sopenharmony_ci if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i){ 4014141cc406Sopenharmony_ci 4015141cc406Sopenharmony_ci unsigned char cmd[] = {0x1b, 0x43}; 4016141cc406Sopenharmony_ci size_t cmdLen = 2; 4017141cc406Sopenharmony_ci unsigned char in[10]; 4018141cc406Sopenharmony_ci size_t inLen = 10; 4019141cc406Sopenharmony_ci 4020141cc406Sopenharmony_ci ret = do_cmd( 4021141cc406Sopenharmony_ci s, 0, 4022141cc406Sopenharmony_ci cmd, cmdLen, 4023141cc406Sopenharmony_ci NULL, 0, 4024141cc406Sopenharmony_ci in, &inLen 4025141cc406Sopenharmony_ci ); 4026141cc406Sopenharmony_ci hexdump(15, "cmd 43: ", in, inLen); 4027141cc406Sopenharmony_ci 4028141cc406Sopenharmony_ci if(ret){ 4029141cc406Sopenharmony_ci DBG (5, "sane_read: error sending 43 cmd\n"); 4030141cc406Sopenharmony_ci return ret; 4031141cc406Sopenharmony_ci } 4032141cc406Sopenharmony_ci 4033141cc406Sopenharmony_ci /*copy backside data into buffer*/ 4034141cc406Sopenharmony_ci if( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK ) 4035141cc406Sopenharmony_ci ret = copy_block_to_page(s, SIDE_BACK); 4036141cc406Sopenharmony_ci 4037141cc406Sopenharmony_ci /*copy frontside data into buffer*/ 4038141cc406Sopenharmony_ci if( s->source != SOURCE_ADF_BACK ) 4039141cc406Sopenharmony_ci ret = copy_block_to_page(s, SIDE_FRONT); 4040141cc406Sopenharmony_ci 4041141cc406Sopenharmony_ci if(ret){ 4042141cc406Sopenharmony_ci DBG (5, "sane_read: can't copy to front/back\n"); 4043141cc406Sopenharmony_ci return ret; 4044141cc406Sopenharmony_ci } 4045141cc406Sopenharmony_ci 4046141cc406Sopenharmony_ci s->fullscan.rx_bytes += s->block_xfr.rx_bytes; 4047141cc406Sopenharmony_ci 4048141cc406Sopenharmony_ci /* autodetect mode, check for change length */ 4049141cc406Sopenharmony_ci if( s->source != SOURCE_FLATBED && !s->page_height ){ 4050141cc406Sopenharmony_ci int get = (in[6] << 8) | in[7]; 4051141cc406Sopenharmony_ci 4052141cc406Sopenharmony_ci /*always have to get full blocks*/ 4053141cc406Sopenharmony_ci if(get % s->block_img.height){ 4054141cc406Sopenharmony_ci get += s->block_img.height - (get % s->block_img.height); 4055141cc406Sopenharmony_ci } 4056141cc406Sopenharmony_ci 4057141cc406Sopenharmony_ci if(get < s->fullscan.height){ 4058141cc406Sopenharmony_ci DBG (15, "sane_read: paper out? %d\n",get); 4059141cc406Sopenharmony_ci s->fullscan.total_bytes = s->fullscan.width_bytes * get; 4060141cc406Sopenharmony_ci } 4061141cc406Sopenharmony_ci } 4062141cc406Sopenharmony_ci } 4063141cc406Sopenharmony_ci 4064141cc406Sopenharmony_ci else { /*fi-60f*/ 4065141cc406Sopenharmony_ci ret = copy_block_to_page(s, SIDE_FRONT); 4066141cc406Sopenharmony_ci if(ret){ 4067141cc406Sopenharmony_ci DBG (5, "sane_read: can't copy to front/back\n"); 4068141cc406Sopenharmony_ci return ret; 4069141cc406Sopenharmony_ci } 4070141cc406Sopenharmony_ci 4071141cc406Sopenharmony_ci s->fullscan.rx_bytes += s->block_xfr.rx_bytes; 4072141cc406Sopenharmony_ci } 4073141cc406Sopenharmony_ci 4074141cc406Sopenharmony_ci /* reset for next pass */ 4075141cc406Sopenharmony_ci update_transfer_totals(&s->block_xfr); 4076141cc406Sopenharmony_ci 4077141cc406Sopenharmony_ci /* scan now finished */ 4078141cc406Sopenharmony_ci if(s->fullscan.rx_bytes == s->fullscan.total_bytes){ 4079141cc406Sopenharmony_ci DBG (15, "sane_read: last block\n"); 4080141cc406Sopenharmony_ci s->fullscan.done = 1; 4081141cc406Sopenharmony_ci } 4082141cc406Sopenharmony_ci } 4083141cc406Sopenharmony_ci } 4084141cc406Sopenharmony_ci 4085141cc406Sopenharmony_ci *len = page->bytes_scanned - page->bytes_read; 4086141cc406Sopenharmony_ci *len = MIN(*len, max_len); 4087141cc406Sopenharmony_ci 4088141cc406Sopenharmony_ci if(*len){ 4089141cc406Sopenharmony_ci DBG (10, "sane_read: copy rx:%d tx:%d tot:%d len:%d\n", 4090141cc406Sopenharmony_ci page->bytes_scanned, page->bytes_read, page->bytes_total,*len); 4091141cc406Sopenharmony_ci 4092141cc406Sopenharmony_ci memcpy(buf, page->image->buffer + page->bytes_read, *len); 4093141cc406Sopenharmony_ci page->bytes_read += *len; 4094141cc406Sopenharmony_ci } 4095141cc406Sopenharmony_ci 4096141cc406Sopenharmony_ci /* sent it all, return eof on next read */ 4097141cc406Sopenharmony_ci if(page->bytes_read == page->bytes_scanned && s->fullscan.done){ 4098141cc406Sopenharmony_ci DBG (10, "sane_read: side done\n"); 4099141cc406Sopenharmony_ci page->done = 1; 4100141cc406Sopenharmony_ci } 4101141cc406Sopenharmony_ci 4102141cc406Sopenharmony_ci DBG (10, "sane_read: finish si:%d len:%d max:%d\n",s->side,*len,max_len); 4103141cc406Sopenharmony_ci 4104141cc406Sopenharmony_ci return ret; 4105141cc406Sopenharmony_ci} 4106141cc406Sopenharmony_ci 4107141cc406Sopenharmony_cistatic SANE_Status 4108141cc406Sopenharmony_cisix5 (struct scanner *s) 4109141cc406Sopenharmony_ci{ 4110141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4111141cc406Sopenharmony_ci 4112141cc406Sopenharmony_ci unsigned char cmd[2]; 4113141cc406Sopenharmony_ci size_t cmdLen = sizeof(cmd); 4114141cc406Sopenharmony_ci unsigned char stat[1]; 4115141cc406Sopenharmony_ci size_t statLen = sizeof(stat); 4116141cc406Sopenharmony_ci 4117141cc406Sopenharmony_ci DBG (10, "six5: start\n"); 4118141cc406Sopenharmony_ci 4119141cc406Sopenharmony_ci cmd[0] = 0x1b; 4120141cc406Sopenharmony_ci cmd[1] = 0x65; 4121141cc406Sopenharmony_ci statLen = 1; 4122141cc406Sopenharmony_ci 4123141cc406Sopenharmony_ci ret = do_cmd( 4124141cc406Sopenharmony_ci s, 0, 4125141cc406Sopenharmony_ci cmd, cmdLen, 4126141cc406Sopenharmony_ci NULL, 0, 4127141cc406Sopenharmony_ci stat, &statLen 4128141cc406Sopenharmony_ci ); 4129141cc406Sopenharmony_ci if(ret){ 4130141cc406Sopenharmony_ci DBG (5, "six5: error sending cmd\n"); 4131141cc406Sopenharmony_ci return ret; 4132141cc406Sopenharmony_ci } 4133141cc406Sopenharmony_ci if(stat[0] != 6){ 4134141cc406Sopenharmony_ci DBG (5, "six5: cmd bad status? %d\n",stat[0]); 4135141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4136141cc406Sopenharmony_ci } 4137141cc406Sopenharmony_ci 4138141cc406Sopenharmony_ci DBG (10, "six5: finish\n"); 4139141cc406Sopenharmony_ci 4140141cc406Sopenharmony_ci return ret; 4141141cc406Sopenharmony_ci} 4142141cc406Sopenharmony_ci 4143141cc406Sopenharmony_ci/* de-scrambles the raw data from the scanner into the image buffer */ 4144141cc406Sopenharmony_ci/* the output image might be lower dpi than input image, so we scale horizontally */ 4145141cc406Sopenharmony_ci/* if the input image is mirrored left to right, we do not correct it here */ 4146141cc406Sopenharmony_ci/* if the input image has padding (at the end or between heads), it is removed here */ 4147141cc406Sopenharmony_cistatic SANE_Status 4148141cc406Sopenharmony_cidescramble_raw(struct scanner *s, struct transfer * tp) 4149141cc406Sopenharmony_ci{ 4150141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4151141cc406Sopenharmony_ci unsigned char *p_out = tp->image->buffer; 4152141cc406Sopenharmony_ci int height = tp->total_bytes / tp->line_stride; 4153141cc406Sopenharmony_ci int i, j, k; 4154141cc406Sopenharmony_ci 4155141cc406Sopenharmony_ci /* raw gray data handled in another function */ 4156141cc406Sopenharmony_ci if(tp->mode == MODE_GRAYSCALE){ 4157141cc406Sopenharmony_ci return descramble_raw_gray(s, tp); 4158141cc406Sopenharmony_ci } 4159141cc406Sopenharmony_ci 4160141cc406Sopenharmony_ci DBG(15, "descramble_raw: start\n"); 4161141cc406Sopenharmony_ci 4162141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { 4163141cc406Sopenharmony_ci for (i = 0; i < 2; i++){ /* page, front/back */ 4164141cc406Sopenharmony_ci for (j = 0; j < height; j++){ /* row (y)*/ 4165141cc406Sopenharmony_ci int curr_col = 0; 4166141cc406Sopenharmony_ci int r=0, g=0, b=0, ppc=0; 4167141cc406Sopenharmony_ci int g_offset=0, b_offset=0; 4168141cc406Sopenharmony_ci 4169141cc406Sopenharmony_ci for (k = 0; k <= tp->plane_width; k++){ /* column (x) */ 4170141cc406Sopenharmony_ci int this_col = k*tp->image->x_res/tp->x_res; 4171141cc406Sopenharmony_ci 4172141cc406Sopenharmony_ci /* going to change output pixel, dump rgb and reset */ 4173141cc406Sopenharmony_ci if(ppc && curr_col != this_col){ 4174141cc406Sopenharmony_ci *p_out = r/ppc; 4175141cc406Sopenharmony_ci p_out++; 4176141cc406Sopenharmony_ci 4177141cc406Sopenharmony_ci *p_out = g/ppc; 4178141cc406Sopenharmony_ci p_out++; 4179141cc406Sopenharmony_ci 4180141cc406Sopenharmony_ci *p_out = b/ppc; 4181141cc406Sopenharmony_ci p_out++; 4182141cc406Sopenharmony_ci 4183141cc406Sopenharmony_ci r = g = b = ppc = 0; 4184141cc406Sopenharmony_ci 4185141cc406Sopenharmony_ci curr_col = this_col; 4186141cc406Sopenharmony_ci } 4187141cc406Sopenharmony_ci 4188141cc406Sopenharmony_ci if(k == tp->plane_width || this_col >= tp->image->width_pix){ 4189141cc406Sopenharmony_ci break; 4190141cc406Sopenharmony_ci } 4191141cc406Sopenharmony_ci 4192141cc406Sopenharmony_ci /* if we're using an S1300i with scan resolution 225 or 300, on AC power, the color planes are shifted */ 4193141cc406Sopenharmony_ci if(s->model == MODEL_S1300i && !s->usb_power && (tp->x_res == 225 || tp->x_res == 300) && tp != &s->cal_image && k + 2 <= tp->plane_width){ 4194141cc406Sopenharmony_ci g_offset = 3; 4195141cc406Sopenharmony_ci b_offset = 6; 4196141cc406Sopenharmony_ci } 4197141cc406Sopenharmony_ci 4198141cc406Sopenharmony_ci /*red is first*/ 4199141cc406Sopenharmony_ci r += tp->raw_data[j*tp->line_stride + k*3 + i]; 4200141cc406Sopenharmony_ci 4201141cc406Sopenharmony_ci /*green is second*/ 4202141cc406Sopenharmony_ci g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i + g_offset]; 4203141cc406Sopenharmony_ci 4204141cc406Sopenharmony_ci /*blue is third*/ 4205141cc406Sopenharmony_ci b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i + b_offset]; 4206141cc406Sopenharmony_ci 4207141cc406Sopenharmony_ci ppc++; 4208141cc406Sopenharmony_ci } 4209141cc406Sopenharmony_ci } 4210141cc406Sopenharmony_ci } 4211141cc406Sopenharmony_ci } 4212141cc406Sopenharmony_ci else if (s->model == MODEL_S1100){ 4213141cc406Sopenharmony_ci for (j = 0; j < height; j++){ /* row (y)*/ 4214141cc406Sopenharmony_ci int curr_col = 0; 4215141cc406Sopenharmony_ci int r=0, g=0, b=0, ppc=0; 4216141cc406Sopenharmony_ci 4217141cc406Sopenharmony_ci for (k = 0; k <= tp->plane_width; k++){ /* column (x) */ 4218141cc406Sopenharmony_ci int this_col = k*tp->image->x_res/tp->x_res; 4219141cc406Sopenharmony_ci 4220141cc406Sopenharmony_ci /* going to change output pixel, dump rgb and reset */ 4221141cc406Sopenharmony_ci if(ppc && curr_col != this_col){ 4222141cc406Sopenharmony_ci *p_out = r/ppc; 4223141cc406Sopenharmony_ci p_out++; 4224141cc406Sopenharmony_ci 4225141cc406Sopenharmony_ci *p_out = g/ppc; 4226141cc406Sopenharmony_ci p_out++; 4227141cc406Sopenharmony_ci 4228141cc406Sopenharmony_ci *p_out = b/ppc; 4229141cc406Sopenharmony_ci p_out++; 4230141cc406Sopenharmony_ci 4231141cc406Sopenharmony_ci r = g = b = ppc = 0; 4232141cc406Sopenharmony_ci 4233141cc406Sopenharmony_ci curr_col = this_col; 4234141cc406Sopenharmony_ci } 4235141cc406Sopenharmony_ci 4236141cc406Sopenharmony_ci if(k == tp->plane_width || this_col >= tp->image->width_pix){ 4237141cc406Sopenharmony_ci break; 4238141cc406Sopenharmony_ci } 4239141cc406Sopenharmony_ci 4240141cc406Sopenharmony_ci /*red is second*/ 4241141cc406Sopenharmony_ci r += tp->raw_data[j*tp->line_stride + tp->plane_stride + k]; 4242141cc406Sopenharmony_ci 4243141cc406Sopenharmony_ci /*green is third*/ 4244141cc406Sopenharmony_ci g += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k]; 4245141cc406Sopenharmony_ci 4246141cc406Sopenharmony_ci /*blue is first*/ 4247141cc406Sopenharmony_ci b += tp->raw_data[j*tp->line_stride + k]; 4248141cc406Sopenharmony_ci 4249141cc406Sopenharmony_ci ppc++; 4250141cc406Sopenharmony_ci } 4251141cc406Sopenharmony_ci } 4252141cc406Sopenharmony_ci } 4253141cc406Sopenharmony_ci else { /* MODEL_FI60F or MODEL_FI65F */ 4254141cc406Sopenharmony_ci 4255141cc406Sopenharmony_ci for (j = 0; j < height; j++){ /* row (y)*/ 4256141cc406Sopenharmony_ci int curr_col = 0; 4257141cc406Sopenharmony_ci 4258141cc406Sopenharmony_ci for (i = 0; i < 3; i++){ /* read head */ 4259141cc406Sopenharmony_ci int r=0, g=0, b=0, ppc=0; 4260141cc406Sopenharmony_ci 4261141cc406Sopenharmony_ci for (k = 0; k <= tp->plane_width; k++){ /* column (x) within the read head */ 4262141cc406Sopenharmony_ci int this_col = (k+i*tp->plane_width)*tp->image->x_res/tp->x_res; 4263141cc406Sopenharmony_ci 4264141cc406Sopenharmony_ci /* going to change output pixel, dump rgb and reset */ 4265141cc406Sopenharmony_ci if(ppc && curr_col != this_col){ 4266141cc406Sopenharmony_ci *p_out = r/ppc; 4267141cc406Sopenharmony_ci p_out++; 4268141cc406Sopenharmony_ci 4269141cc406Sopenharmony_ci *p_out = g/ppc; 4270141cc406Sopenharmony_ci p_out++; 4271141cc406Sopenharmony_ci 4272141cc406Sopenharmony_ci *p_out = b/ppc; 4273141cc406Sopenharmony_ci p_out++; 4274141cc406Sopenharmony_ci 4275141cc406Sopenharmony_ci r = g = b = ppc = 0; 4276141cc406Sopenharmony_ci 4277141cc406Sopenharmony_ci curr_col = this_col; 4278141cc406Sopenharmony_ci } 4279141cc406Sopenharmony_ci 4280141cc406Sopenharmony_ci if(k == tp->plane_width || this_col >= tp->image->width_pix){ 4281141cc406Sopenharmony_ci break; 4282141cc406Sopenharmony_ci } 4283141cc406Sopenharmony_ci 4284141cc406Sopenharmony_ci /*red is first*/ 4285141cc406Sopenharmony_ci r += tp->raw_data[j*tp->line_stride + k*3 + i]; 4286141cc406Sopenharmony_ci 4287141cc406Sopenharmony_ci /*green is second*/ 4288141cc406Sopenharmony_ci g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i]; 4289141cc406Sopenharmony_ci 4290141cc406Sopenharmony_ci /*blue is third*/ 4291141cc406Sopenharmony_ci b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i]; 4292141cc406Sopenharmony_ci 4293141cc406Sopenharmony_ci ppc++; 4294141cc406Sopenharmony_ci } 4295141cc406Sopenharmony_ci } 4296141cc406Sopenharmony_ci } 4297141cc406Sopenharmony_ci } 4298141cc406Sopenharmony_ci 4299141cc406Sopenharmony_ci DBG(15, "descramble_raw: finish %d\n", ret); 4300141cc406Sopenharmony_ci 4301141cc406Sopenharmony_ci return ret; 4302141cc406Sopenharmony_ci} 4303141cc406Sopenharmony_ci 4304141cc406Sopenharmony_ci/* de-scrambles the raw gray data from the scanner into the image buffer */ 4305141cc406Sopenharmony_ci/* the output image might be lower dpi than input image, so we scale horizontally */ 4306141cc406Sopenharmony_ci/* if the input image is mirrored left to right, we do not correct it here */ 4307141cc406Sopenharmony_ci/* if the input image has padding (at the end or between heads), it is removed here */ 4308141cc406Sopenharmony_cistatic SANE_Status 4309141cc406Sopenharmony_cidescramble_raw_gray(struct scanner *s, struct transfer * tp) 4310141cc406Sopenharmony_ci{ 4311141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4312141cc406Sopenharmony_ci int height = tp->total_bytes / tp->line_stride; 4313141cc406Sopenharmony_ci int row, col_out; 4314141cc406Sopenharmony_ci 4315141cc406Sopenharmony_ci DBG(15, "descramble_raw_gray: start\n"); 4316141cc406Sopenharmony_ci 4317141cc406Sopenharmony_ci if (s->model == MODEL_FI60F || s->model == MODEL_FI65F) { 4318141cc406Sopenharmony_ci for (row = 0; row < height; row++){ 4319141cc406Sopenharmony_ci 4320141cc406Sopenharmony_ci unsigned char *p_in = tp->raw_data + row * tp->line_stride; 4321141cc406Sopenharmony_ci unsigned char *p_out = tp->image->buffer + row * tp->image->width_pix; 4322141cc406Sopenharmony_ci 4323141cc406Sopenharmony_ci for (col_out = 0; col_out < tp->image->width_pix; col_out++){ 4324141cc406Sopenharmony_ci int col_in = col_out * tp->x_res/tp->image->x_res; 4325141cc406Sopenharmony_ci int offset = col_in%tp->plane_width; 4326141cc406Sopenharmony_ci int step = col_in/tp->plane_width; 4327141cc406Sopenharmony_ci 4328141cc406Sopenharmony_ci *p_out = *(p_in + offset*3 + step); 4329141cc406Sopenharmony_ci p_out++; 4330141cc406Sopenharmony_ci } 4331141cc406Sopenharmony_ci } 4332141cc406Sopenharmony_ci } 4333141cc406Sopenharmony_ci 4334141cc406Sopenharmony_ci else{ 4335141cc406Sopenharmony_ci DBG(5, "internal error: descramble_raw_gray not supported\n"); 4336141cc406Sopenharmony_ci ret = SANE_STATUS_INVAL; 4337141cc406Sopenharmony_ci } 4338141cc406Sopenharmony_ci 4339141cc406Sopenharmony_ci DBG(15, "descramble_raw_gray: finish %d\n", ret); 4340141cc406Sopenharmony_ci return ret; 4341141cc406Sopenharmony_ci} 4342141cc406Sopenharmony_ci 4343141cc406Sopenharmony_ci/* fills block buffer a little per pass */ 4344141cc406Sopenharmony_cistatic SANE_Status 4345141cc406Sopenharmony_ciread_from_scanner(struct scanner *s, struct transfer * tp) 4346141cc406Sopenharmony_ci{ 4347141cc406Sopenharmony_ci SANE_Status ret=SANE_STATUS_GOOD; 4348141cc406Sopenharmony_ci size_t bytes = MAX_IMG_PASS; 4349141cc406Sopenharmony_ci size_t remainBlock = tp->total_bytes - tp->rx_bytes + 8; 4350141cc406Sopenharmony_ci unsigned char * buf; 4351141cc406Sopenharmony_ci size_t bufLen; 4352141cc406Sopenharmony_ci 4353141cc406Sopenharmony_ci /* determine amount to ask for, S1300i wants big requests */ 4354141cc406Sopenharmony_ci if(s->model != MODEL_S1300i){ 4355141cc406Sopenharmony_ci bytes = MIN(bytes, remainBlock); 4356141cc406Sopenharmony_ci } 4357141cc406Sopenharmony_ci 4358141cc406Sopenharmony_ci if (tp->image == NULL) 4359141cc406Sopenharmony_ci { 4360141cc406Sopenharmony_ci DBG(5, "internal error: read_from_scanner called with no destination image.\n"); 4361141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4362141cc406Sopenharmony_ci } 4363141cc406Sopenharmony_ci 4364141cc406Sopenharmony_ci DBG (10, "read_from_scanner: start rB:%lu len:%lu\n", 4365141cc406Sopenharmony_ci (unsigned long)remainBlock, (unsigned long)bytes); 4366141cc406Sopenharmony_ci 4367141cc406Sopenharmony_ci if(!bytes){ 4368141cc406Sopenharmony_ci DBG(10, "read_from_scanner: no bytes!\n"); 4369141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4370141cc406Sopenharmony_ci } 4371141cc406Sopenharmony_ci 4372141cc406Sopenharmony_ci bufLen = bytes; 4373141cc406Sopenharmony_ci buf = malloc(bufLen); 4374141cc406Sopenharmony_ci if(!buf){ 4375141cc406Sopenharmony_ci DBG (5, "read_from_scanner: failed to alloc mem\n"); 4376141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 4377141cc406Sopenharmony_ci } 4378141cc406Sopenharmony_ci 4379141cc406Sopenharmony_ci ret = do_cmd( 4380141cc406Sopenharmony_ci s, 0, 4381141cc406Sopenharmony_ci NULL, 0, 4382141cc406Sopenharmony_ci NULL, 0, 4383141cc406Sopenharmony_ci buf, &bytes 4384141cc406Sopenharmony_ci ); 4385141cc406Sopenharmony_ci 4386141cc406Sopenharmony_ci /* full read or short read */ 4387141cc406Sopenharmony_ci if (ret == SANE_STATUS_GOOD || (ret == SANE_STATUS_EOF && bytes) ) { 4388141cc406Sopenharmony_ci 4389141cc406Sopenharmony_ci DBG(15,"read_from_scanner: got GOOD/EOF (%lu)\n",(unsigned long)bytes); 4390141cc406Sopenharmony_ci 4391141cc406Sopenharmony_ci if(bytes > remainBlock){ 4392141cc406Sopenharmony_ci DBG(15,"read_from_scanner: block too big?\n"); 4393141cc406Sopenharmony_ci bytes = remainBlock; 4394141cc406Sopenharmony_ci } 4395141cc406Sopenharmony_ci 4396141cc406Sopenharmony_ci if(bytes == remainBlock){ 4397141cc406Sopenharmony_ci DBG(15,"read_from_scanner: block done, ignoring trailer\n"); 4398141cc406Sopenharmony_ci bytes -= 8; 4399141cc406Sopenharmony_ci tp->done = 1; 4400141cc406Sopenharmony_ci } 4401141cc406Sopenharmony_ci 4402141cc406Sopenharmony_ci memcpy(tp->raw_data + tp->rx_bytes, buf, bytes); 4403141cc406Sopenharmony_ci tp->rx_bytes += bytes; 4404141cc406Sopenharmony_ci 4405141cc406Sopenharmony_ci ret = SANE_STATUS_GOOD; 4406141cc406Sopenharmony_ci } 4407141cc406Sopenharmony_ci else { 4408141cc406Sopenharmony_ci DBG(5, "read_from_scanner: error reading status = %d\n", ret); 4409141cc406Sopenharmony_ci } 4410141cc406Sopenharmony_ci 4411141cc406Sopenharmony_ci free(buf); 4412141cc406Sopenharmony_ci 4413141cc406Sopenharmony_ci DBG (10, "read_from_scanner: finish rB:%lu len:%lu\n", 4414141cc406Sopenharmony_ci (unsigned long)(tp->total_bytes - tp->rx_bytes + 8), (unsigned long)bytes); 4415141cc406Sopenharmony_ci 4416141cc406Sopenharmony_ci return ret; 4417141cc406Sopenharmony_ci} 4418141cc406Sopenharmony_ci 4419141cc406Sopenharmony_ci/* copies block buffer into front or back image buffer */ 4420141cc406Sopenharmony_ci/* converts pixel data from input mode (color/gray) to output mode (color/gray/binary) */ 4421141cc406Sopenharmony_ci/* the output image might be lower dpi than input image, so we scale vertically */ 4422141cc406Sopenharmony_ci/* the input is already scaled horizontally and padding skipped if required */ 4423141cc406Sopenharmony_ci/* if the input is mirrored left to right, we fix it here */ 4424141cc406Sopenharmony_cistatic SANE_Status 4425141cc406Sopenharmony_cicopy_block_to_page(struct scanner *s,int side) 4426141cc406Sopenharmony_ci{ 4427141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4428141cc406Sopenharmony_ci struct transfer * block = &s->block_xfr; 4429141cc406Sopenharmony_ci struct page * page = &s->pages[side]; 4430141cc406Sopenharmony_ci int image_height = block->total_bytes / block->line_stride; 4431141cc406Sopenharmony_ci int page_width = page->image->width_pix; 4432141cc406Sopenharmony_ci int block_page_stride = block->image->width_bytes * block->image->height; 4433141cc406Sopenharmony_ci int line_reverse = (side == SIDE_BACK) || (s->model == MODEL_FI60F) || (s->model == MODEL_FI65F); 4434141cc406Sopenharmony_ci int i,j,k=0; 4435141cc406Sopenharmony_ci 4436141cc406Sopenharmony_ci int curr_in_row = s->fullscan.rx_bytes/s->fullscan.width_bytes; 4437141cc406Sopenharmony_ci int last_out_row = (page->bytes_scanned / page->image->width_bytes) - 1; 4438141cc406Sopenharmony_ci 4439141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: start\n"); 4440141cc406Sopenharmony_ci 4441141cc406Sopenharmony_ci /* skip padding and tl_y */ 4442141cc406Sopenharmony_ci if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes <= block->line_stride * page->image->y_skip_offset) 4443141cc406Sopenharmony_ci { 4444141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: before the start? %d\n", side); 4445141cc406Sopenharmony_ci return ret; 4446141cc406Sopenharmony_ci } 4447141cc406Sopenharmony_ci else if (s->fullscan.rx_bytes < block->line_stride * page->image->y_skip_offset) 4448141cc406Sopenharmony_ci { 4449141cc406Sopenharmony_ci k = page->image->y_skip_offset - s->fullscan.rx_bytes / block->line_stride; 4450141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: k start? %d\n", k); 4451141cc406Sopenharmony_ci } 4452141cc406Sopenharmony_ci 4453141cc406Sopenharmony_ci /* loop over all the lines in the block */ 4454141cc406Sopenharmony_ci for (i = k; i < image_height; i++) 4455141cc406Sopenharmony_ci { 4456141cc406Sopenharmony_ci /* determine source and dest rows (dpi scaling) */ 4457141cc406Sopenharmony_ci int this_in_row = curr_in_row + i; 4458141cc406Sopenharmony_ci int this_out_row = (this_in_row - page->image->y_skip_offset) * page->image->y_res / s->fullscan.y_res; 4459141cc406Sopenharmony_ci DBG (15, "copy_block_to_page: in %d out %d lastout %d\n", this_in_row, this_out_row, last_out_row); 4460141cc406Sopenharmony_ci DBG (15, "copy_block_to_page: bs %d wb %d\n", page->bytes_scanned, page->image->width_bytes); 4461141cc406Sopenharmony_ci 4462141cc406Sopenharmony_ci /* don't walk off the end of the output buffer */ 4463141cc406Sopenharmony_ci if(this_out_row >= page->image->height || this_out_row < 0){ 4464141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: out of space? %d\n", side); 4465141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: rx:%d tx:%d tot:%d line:%d\n", 4466141cc406Sopenharmony_ci page->bytes_scanned, page->bytes_read, page->bytes_total,page->image->width_bytes); 4467141cc406Sopenharmony_ci return ret; 4468141cc406Sopenharmony_ci } 4469141cc406Sopenharmony_ci 4470141cc406Sopenharmony_ci /* ok, different output row, so we do the math */ 4471141cc406Sopenharmony_ci if(this_out_row > last_out_row){ 4472141cc406Sopenharmony_ci 4473141cc406Sopenharmony_ci unsigned char * p_in = block->image->buffer + (side * block_page_stride) 4474141cc406Sopenharmony_ci + (i * block->image->width_bytes) + page->image->x_start_offset * 3; 4475141cc406Sopenharmony_ci unsigned char * p_out = page->image->buffer + this_out_row * page->image->width_bytes; 4476141cc406Sopenharmony_ci unsigned char * lineStart = p_out; 4477141cc406Sopenharmony_ci 4478141cc406Sopenharmony_ci last_out_row = this_out_row; 4479141cc406Sopenharmony_ci 4480141cc406Sopenharmony_ci if (block->mode == MODE_COLOR){ 4481141cc406Sopenharmony_ci 4482141cc406Sopenharmony_ci /* reverse order for back side or FI-60F scanner */ 4483141cc406Sopenharmony_ci if (line_reverse) 4484141cc406Sopenharmony_ci p_in += (page_width - 1) * 3; 4485141cc406Sopenharmony_ci 4486141cc406Sopenharmony_ci /* convert all of the pixels in this row */ 4487141cc406Sopenharmony_ci for (j = 0; j < page_width; j++) 4488141cc406Sopenharmony_ci { 4489141cc406Sopenharmony_ci unsigned char r, g, b; 4490141cc406Sopenharmony_ci if (s->model == MODEL_S300 || s->model == MODEL_S1300i) 4491141cc406Sopenharmony_ci { r = p_in[1]; g = p_in[2]; b = p_in[0]; } 4492141cc406Sopenharmony_ci else /* MODEL_FI60F or MODEL_FI65F or MODEL_S1100 */ 4493141cc406Sopenharmony_ci { r = p_in[0]; g = p_in[1]; b = p_in[2]; } 4494141cc406Sopenharmony_ci if (s->mode == MODE_COLOR) 4495141cc406Sopenharmony_ci { 4496141cc406Sopenharmony_ci *p_out++ = r; 4497141cc406Sopenharmony_ci *p_out++ = g; 4498141cc406Sopenharmony_ci *p_out++ = b; 4499141cc406Sopenharmony_ci } 4500141cc406Sopenharmony_ci else if (s->mode == MODE_GRAYSCALE) 4501141cc406Sopenharmony_ci { 4502141cc406Sopenharmony_ci *p_out++ = (r + g + b) / 3; 4503141cc406Sopenharmony_ci } 4504141cc406Sopenharmony_ci else if (s->mode == MODE_LINEART) 4505141cc406Sopenharmony_ci { 4506141cc406Sopenharmony_ci s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterward */ 4507141cc406Sopenharmony_ci } 4508141cc406Sopenharmony_ci if (line_reverse) 4509141cc406Sopenharmony_ci p_in -= 3; 4510141cc406Sopenharmony_ci else 4511141cc406Sopenharmony_ci p_in += 3; 4512141cc406Sopenharmony_ci } 4513141cc406Sopenharmony_ci } 4514141cc406Sopenharmony_ci 4515141cc406Sopenharmony_ci /* grayscale input */ 4516141cc406Sopenharmony_ci else{ 4517141cc406Sopenharmony_ci unsigned char * p_in = block->image->buffer + (side * block_page_stride) 4518141cc406Sopenharmony_ci + (i * block->image->width_bytes) + page->image->x_start_offset; 4519141cc406Sopenharmony_ci 4520141cc406Sopenharmony_ci /* reverse order for back side or FI-60F scanner */ 4521141cc406Sopenharmony_ci if (line_reverse) 4522141cc406Sopenharmony_ci p_in += (page_width - 1); 4523141cc406Sopenharmony_ci 4524141cc406Sopenharmony_ci //memcpy(p_out,p_in,page->image->width_bytes); 4525141cc406Sopenharmony_ci 4526141cc406Sopenharmony_ci for (j = 0; j < page_width; j++) 4527141cc406Sopenharmony_ci { 4528141cc406Sopenharmony_ci if (s->mode == MODE_GRAYSCALE) 4529141cc406Sopenharmony_ci { 4530141cc406Sopenharmony_ci *p_out++ = *p_in; 4531141cc406Sopenharmony_ci } 4532141cc406Sopenharmony_ci else if (s->mode == MODE_LINEART) 4533141cc406Sopenharmony_ci { 4534141cc406Sopenharmony_ci s->dt.buffer[j] = *p_in; /* stores dt temp image buffer and binarize afterward */ 4535141cc406Sopenharmony_ci } 4536141cc406Sopenharmony_ci if (line_reverse) 4537141cc406Sopenharmony_ci p_in--; 4538141cc406Sopenharmony_ci else 4539141cc406Sopenharmony_ci p_in++; 4540141cc406Sopenharmony_ci } 4541141cc406Sopenharmony_ci } 4542141cc406Sopenharmony_ci 4543141cc406Sopenharmony_ci /* skip non-transfer pixels in block image buffer */ 4544141cc406Sopenharmony_ci if (line_reverse) 4545141cc406Sopenharmony_ci p_in -= page->image->x_offset_bytes; 4546141cc406Sopenharmony_ci else 4547141cc406Sopenharmony_ci p_in += page->image->x_offset_bytes; 4548141cc406Sopenharmony_ci 4549141cc406Sopenharmony_ci /* for MODE_LINEART, binarize the gray line stored in the temp image buffer(dt) */ 4550141cc406Sopenharmony_ci /* because dt.width = page_width, we pass page_width */ 4551141cc406Sopenharmony_ci if (s->mode == MODE_LINEART) 4552141cc406Sopenharmony_ci binarize_line(s, lineStart, page_width); 4553141cc406Sopenharmony_ci 4554141cc406Sopenharmony_ci page->bytes_scanned += page->image->width_bytes; 4555141cc406Sopenharmony_ci } 4556141cc406Sopenharmony_ci } 4557141cc406Sopenharmony_ci 4558141cc406Sopenharmony_ci DBG (10, "copy_block_to_page: finish\n"); 4559141cc406Sopenharmony_ci 4560141cc406Sopenharmony_ci return ret; 4561141cc406Sopenharmony_ci} 4562141cc406Sopenharmony_ci 4563141cc406Sopenharmony_ci/*uses the threshold/threshold_curve to control binarization*/ 4564141cc406Sopenharmony_cistatic SANE_Status 4565141cc406Sopenharmony_cibinarize_line(struct scanner *s, unsigned char *lineOut, int width) 4566141cc406Sopenharmony_ci{ 4567141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4568141cc406Sopenharmony_ci int j, windowX, sum = 0; 4569141cc406Sopenharmony_ci 4570141cc406Sopenharmony_ci /* ~1mm works best, but the window needs to have odd # of pixels */ 4571141cc406Sopenharmony_ci windowX = 6 * s->resolution / 150; 4572141cc406Sopenharmony_ci if (!(windowX % 2)) windowX++; 4573141cc406Sopenharmony_ci 4574141cc406Sopenharmony_ci /*second, prefill the sliding sum*/ 4575141cc406Sopenharmony_ci for (j = 0; j < windowX; j++) 4576141cc406Sopenharmony_ci sum += s->dt.buffer[j]; 4577141cc406Sopenharmony_ci 4578141cc406Sopenharmony_ci /* third, walk the dt buffer, update the sliding sum, */ 4579141cc406Sopenharmony_ci /* determine threshold, output bits */ 4580141cc406Sopenharmony_ci for (j = 0; j < width; j++) 4581141cc406Sopenharmony_ci { 4582141cc406Sopenharmony_ci /*output image location*/ 4583141cc406Sopenharmony_ci int offset = j % 8; 4584141cc406Sopenharmony_ci unsigned char mask = 0x80 >> offset; 4585141cc406Sopenharmony_ci int thresh = s->threshold; 4586141cc406Sopenharmony_ci 4587141cc406Sopenharmony_ci /* move sum/update threshold only if there is a curve*/ 4588141cc406Sopenharmony_ci if (s->threshold_curve) 4589141cc406Sopenharmony_ci { 4590141cc406Sopenharmony_ci int addCol = j + windowX/2; 4591141cc406Sopenharmony_ci int dropCol = addCol - windowX; 4592141cc406Sopenharmony_ci 4593141cc406Sopenharmony_ci if (dropCol >= 0 && addCol < width) 4594141cc406Sopenharmony_ci { 4595141cc406Sopenharmony_ci sum -= s->dt.buffer[dropCol]; 4596141cc406Sopenharmony_ci sum += s->dt.buffer[addCol]; 4597141cc406Sopenharmony_ci } 4598141cc406Sopenharmony_ci thresh = s->dt_lut[sum/windowX]; 4599141cc406Sopenharmony_ci } 4600141cc406Sopenharmony_ci 4601141cc406Sopenharmony_ci /*use average to lookup threshold*/ 4602141cc406Sopenharmony_ci if (s->dt.buffer[j] > thresh) 4603141cc406Sopenharmony_ci *lineOut &= ~mask; /* white */ 4604141cc406Sopenharmony_ci else 4605141cc406Sopenharmony_ci *lineOut |= mask; /* black */ 4606141cc406Sopenharmony_ci 4607141cc406Sopenharmony_ci if (offset == 7) 4608141cc406Sopenharmony_ci lineOut++; 4609141cc406Sopenharmony_ci } 4610141cc406Sopenharmony_ci 4611141cc406Sopenharmony_ci return ret; 4612141cc406Sopenharmony_ci} 4613141cc406Sopenharmony_ci 4614141cc406Sopenharmony_ci/* 4615141cc406Sopenharmony_ci * @@ Section 4 - SANE cleanup functions 4616141cc406Sopenharmony_ci */ 4617141cc406Sopenharmony_ci/* 4618141cc406Sopenharmony_ci * Cancels a scan. 4619141cc406Sopenharmony_ci * 4620141cc406Sopenharmony_ci * From the SANE spec: 4621141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible 4622141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by 4623141cc406Sopenharmony_ci * handle h. This function can be called at any time (as long as 4624141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running 4625141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call 4626141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler). 4627141cc406Sopenharmony_ci * It is important to note that completion of this operation does not 4628141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It 4629141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation 4630141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a 4631141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED). Since the SANE API does 4632141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies 4633141cc406Sopenharmony_ci * that a frontend must not call any other operation until the 4634141cc406Sopenharmony_ci * cancelled operation has returned. 4635141cc406Sopenharmony_ci */ 4636141cc406Sopenharmony_civoid 4637141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 4638141cc406Sopenharmony_ci{ 4639141cc406Sopenharmony_ci /*FIXME: actually ask the scanner to stop?*/ 4640141cc406Sopenharmony_ci struct scanner * s = (struct scanner *) handle; 4641141cc406Sopenharmony_ci DBG (10, "sane_cancel: start\n"); 4642141cc406Sopenharmony_ci s->started = 0; 4643141cc406Sopenharmony_ci DBG (10, "sane_cancel: finish\n"); 4644141cc406Sopenharmony_ci} 4645141cc406Sopenharmony_ci 4646141cc406Sopenharmony_ci/* 4647141cc406Sopenharmony_ci * Ends use of the scanner. 4648141cc406Sopenharmony_ci * 4649141cc406Sopenharmony_ci * From the SANE spec: 4650141cc406Sopenharmony_ci * This function terminates the association between the device handle 4651141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is 4652141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After 4653141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore. 4654141cc406Sopenharmony_ci */ 4655141cc406Sopenharmony_civoid 4656141cc406Sopenharmony_cisane_close (SANE_Handle handle) 4657141cc406Sopenharmony_ci{ 4658141cc406Sopenharmony_ci struct scanner * s = (struct scanner *) handle; 4659141cc406Sopenharmony_ci 4660141cc406Sopenharmony_ci DBG (10, "sane_close: start\n"); 4661141cc406Sopenharmony_ci 4662141cc406Sopenharmony_ci /* still connected- drop it */ 4663141cc406Sopenharmony_ci if(s->fd >= 0){ 4664141cc406Sopenharmony_ci sane_cancel(handle); 4665141cc406Sopenharmony_ci lamp(s, 0); 4666141cc406Sopenharmony_ci disconnect_fd(s); 4667141cc406Sopenharmony_ci } 4668141cc406Sopenharmony_ci 4669141cc406Sopenharmony_ci DBG (10, "sane_close: finish\n"); 4670141cc406Sopenharmony_ci} 4671141cc406Sopenharmony_ci 4672141cc406Sopenharmony_cistatic SANE_Status 4673141cc406Sopenharmony_cidisconnect_fd (struct scanner *s) 4674141cc406Sopenharmony_ci{ 4675141cc406Sopenharmony_ci DBG (10, "disconnect_fd: start\n"); 4676141cc406Sopenharmony_ci 4677141cc406Sopenharmony_ci if(s->fd > -1){ 4678141cc406Sopenharmony_ci DBG (15, "disconnecting usb device\n"); 4679141cc406Sopenharmony_ci sanei_usb_close (s->fd); 4680141cc406Sopenharmony_ci s->fd = -1; 4681141cc406Sopenharmony_ci } 4682141cc406Sopenharmony_ci 4683141cc406Sopenharmony_ci DBG (10, "disconnect_fd: finish\n"); 4684141cc406Sopenharmony_ci 4685141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4686141cc406Sopenharmony_ci} 4687141cc406Sopenharmony_ci 4688141cc406Sopenharmony_cistatic SANE_Status 4689141cc406Sopenharmony_cidestroy(struct scanner *s) 4690141cc406Sopenharmony_ci{ 4691141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4692141cc406Sopenharmony_ci 4693141cc406Sopenharmony_ci DBG (10, "destroy: start\n"); 4694141cc406Sopenharmony_ci 4695141cc406Sopenharmony_ci teardown_buffers(s); 4696141cc406Sopenharmony_ci 4697141cc406Sopenharmony_ci if(s->sane.name){ 4698141cc406Sopenharmony_ci free((void *) s->sane.name); 4699141cc406Sopenharmony_ci } 4700141cc406Sopenharmony_ci if(s->sane.vendor){ 4701141cc406Sopenharmony_ci free((void *) s->sane.vendor); 4702141cc406Sopenharmony_ci } 4703141cc406Sopenharmony_ci if(s->sane.model){ 4704141cc406Sopenharmony_ci free((void *) s->sane.model); 4705141cc406Sopenharmony_ci } 4706141cc406Sopenharmony_ci 4707141cc406Sopenharmony_ci free(s); 4708141cc406Sopenharmony_ci 4709141cc406Sopenharmony_ci DBG (10, "destroy: finish\n"); 4710141cc406Sopenharmony_ci return ret; 4711141cc406Sopenharmony_ci} 4712141cc406Sopenharmony_ci 4713141cc406Sopenharmony_cistatic SANE_Status 4714141cc406Sopenharmony_citeardown_buffers(struct scanner *s) 4715141cc406Sopenharmony_ci{ 4716141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4717141cc406Sopenharmony_ci 4718141cc406Sopenharmony_ci DBG (10, "teardown_buffers: start\n"); 4719141cc406Sopenharmony_ci 4720141cc406Sopenharmony_ci /* temporary cal data */ 4721141cc406Sopenharmony_ci if(s->coarsecal.buffer){ 4722141cc406Sopenharmony_ci free(s->coarsecal.buffer); 4723141cc406Sopenharmony_ci s->coarsecal.buffer = NULL; 4724141cc406Sopenharmony_ci } 4725141cc406Sopenharmony_ci 4726141cc406Sopenharmony_ci if(s->darkcal.buffer){ 4727141cc406Sopenharmony_ci free(s->darkcal.buffer); 4728141cc406Sopenharmony_ci s->darkcal.buffer = NULL; 4729141cc406Sopenharmony_ci } 4730141cc406Sopenharmony_ci 4731141cc406Sopenharmony_ci if(s->sendcal.buffer){ 4732141cc406Sopenharmony_ci free(s->sendcal.buffer); 4733141cc406Sopenharmony_ci s->sendcal.buffer = NULL; 4734141cc406Sopenharmony_ci } 4735141cc406Sopenharmony_ci 4736141cc406Sopenharmony_ci if(s->cal_image.raw_data){ 4737141cc406Sopenharmony_ci free(s->cal_image.raw_data); 4738141cc406Sopenharmony_ci s->cal_image.raw_data = NULL; 4739141cc406Sopenharmony_ci } 4740141cc406Sopenharmony_ci 4741141cc406Sopenharmony_ci if(s->cal_data.raw_data){ 4742141cc406Sopenharmony_ci free(s->cal_data.raw_data); 4743141cc406Sopenharmony_ci s->cal_data.raw_data = NULL; 4744141cc406Sopenharmony_ci } 4745141cc406Sopenharmony_ci 4746141cc406Sopenharmony_ci /* image slice */ 4747141cc406Sopenharmony_ci if(s->block_img.buffer){ 4748141cc406Sopenharmony_ci free(s->block_img.buffer); 4749141cc406Sopenharmony_ci s->block_img.buffer = NULL; 4750141cc406Sopenharmony_ci } 4751141cc406Sopenharmony_ci if(s->block_xfr.raw_data){ 4752141cc406Sopenharmony_ci free(s->block_xfr.raw_data); 4753141cc406Sopenharmony_ci s->block_xfr.raw_data = NULL; 4754141cc406Sopenharmony_ci } 4755141cc406Sopenharmony_ci 4756141cc406Sopenharmony_ci /* dynamic thresh slice */ 4757141cc406Sopenharmony_ci if(s->dt.buffer){ 4758141cc406Sopenharmony_ci free(s->dt.buffer); 4759141cc406Sopenharmony_ci s->dt.buffer = NULL; 4760141cc406Sopenharmony_ci } 4761141cc406Sopenharmony_ci 4762141cc406Sopenharmony_ci /* image buffer to hold frontside data */ 4763141cc406Sopenharmony_ci if(s->front.buffer){ 4764141cc406Sopenharmony_ci free(s->front.buffer); 4765141cc406Sopenharmony_ci s->front.buffer = NULL; 4766141cc406Sopenharmony_ci } 4767141cc406Sopenharmony_ci 4768141cc406Sopenharmony_ci /* image buffer to hold backside data */ 4769141cc406Sopenharmony_ci if(s->back.buffer){ 4770141cc406Sopenharmony_ci free(s->back.buffer); 4771141cc406Sopenharmony_ci s->back.buffer = NULL; 4772141cc406Sopenharmony_ci } 4773141cc406Sopenharmony_ci 4774141cc406Sopenharmony_ci DBG (10, "teardown_buffers: finish\n"); 4775141cc406Sopenharmony_ci return ret; 4776141cc406Sopenharmony_ci} 4777141cc406Sopenharmony_ci 4778141cc406Sopenharmony_ci/* 4779141cc406Sopenharmony_ci * Terminates the backend. 4780141cc406Sopenharmony_ci * 4781141cc406Sopenharmony_ci * From the SANE spec: 4782141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The 4783141cc406Sopenharmony_ci * function will first close all device handles that still might be 4784141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through 4785141cc406Sopenharmony_ci * a call to sane_close(), but backends are required to release all 4786141cc406Sopenharmony_ci * resources upon a call to this function). After this function 4787141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called 4788141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting 4789141cc406Sopenharmony_ci * to call this function may result in some resources not being 4790141cc406Sopenharmony_ci * released properly. 4791141cc406Sopenharmony_ci */ 4792141cc406Sopenharmony_civoid 4793141cc406Sopenharmony_cisane_exit (void) 4794141cc406Sopenharmony_ci{ 4795141cc406Sopenharmony_ci struct scanner *dev, *next; 4796141cc406Sopenharmony_ci 4797141cc406Sopenharmony_ci DBG (10, "sane_exit: start\n"); 4798141cc406Sopenharmony_ci 4799141cc406Sopenharmony_ci for (dev = scanner_devList; dev; dev = next) { 4800141cc406Sopenharmony_ci next = dev->next; 4801141cc406Sopenharmony_ci destroy(dev); 4802141cc406Sopenharmony_ci } 4803141cc406Sopenharmony_ci 4804141cc406Sopenharmony_ci if (sane_devArray) 4805141cc406Sopenharmony_ci free (sane_devArray); 4806141cc406Sopenharmony_ci 4807141cc406Sopenharmony_ci scanner_devList = NULL; 4808141cc406Sopenharmony_ci sane_devArray = NULL; 4809141cc406Sopenharmony_ci 4810141cc406Sopenharmony_ci DBG (10, "sane_exit: finish\n"); 4811141cc406Sopenharmony_ci} 4812141cc406Sopenharmony_ci 4813141cc406Sopenharmony_ci/* 4814141cc406Sopenharmony_ci * @@ Section 5 - misc helper functions 4815141cc406Sopenharmony_ci */ 4816141cc406Sopenharmony_ci/* 4817141cc406Sopenharmony_ci * take a bunch of pointers, send commands to scanner 4818141cc406Sopenharmony_ci */ 4819141cc406Sopenharmony_cistatic SANE_Status 4820141cc406Sopenharmony_cido_cmd(struct scanner *s, int shortTime, 4821141cc406Sopenharmony_ci unsigned char * cmdBuff, size_t cmdLen, 4822141cc406Sopenharmony_ci unsigned char * outBuff, size_t outLen, 4823141cc406Sopenharmony_ci unsigned char * inBuff, size_t * inLen 4824141cc406Sopenharmony_ci) 4825141cc406Sopenharmony_ci{ 4826141cc406Sopenharmony_ci /* sanei_usb overwrites the transfer size, so make some local copies */ 4827141cc406Sopenharmony_ci size_t loc_cmdLen = cmdLen; 4828141cc406Sopenharmony_ci size_t loc_outLen = outLen; 4829141cc406Sopenharmony_ci size_t loc_inLen = 0; 4830141cc406Sopenharmony_ci 4831141cc406Sopenharmony_ci int cmdTime = USB_COMMAND_TIME; 4832141cc406Sopenharmony_ci int outTime = USB_DATA_TIME; 4833141cc406Sopenharmony_ci int inTime = USB_DATA_TIME; 4834141cc406Sopenharmony_ci 4835141cc406Sopenharmony_ci int ret = 0; 4836141cc406Sopenharmony_ci 4837141cc406Sopenharmony_ci DBG (10, "do_cmd: start\n"); 4838141cc406Sopenharmony_ci 4839141cc406Sopenharmony_ci if(shortTime){ 4840141cc406Sopenharmony_ci cmdTime /= 20; 4841141cc406Sopenharmony_ci outTime /= 20; 4842141cc406Sopenharmony_ci inTime /= 20; 4843141cc406Sopenharmony_ci } 4844141cc406Sopenharmony_ci 4845141cc406Sopenharmony_ci /* this command has a cmd component, and a place to get it */ 4846141cc406Sopenharmony_ci if(cmdBuff && cmdLen && cmdTime){ 4847141cc406Sopenharmony_ci 4848141cc406Sopenharmony_ci /* change timeout */ 4849141cc406Sopenharmony_ci sanei_usb_set_timeout(cmdTime); 4850141cc406Sopenharmony_ci 4851141cc406Sopenharmony_ci /* write the command out */ 4852141cc406Sopenharmony_ci DBG(25, "cmd: writing %ld bytes, timeout %d\n", (long)cmdLen, cmdTime); 4853141cc406Sopenharmony_ci hexdump(30, "cmd: >>", cmdBuff, cmdLen); 4854141cc406Sopenharmony_ci ret = sanei_usb_write_bulk(s->fd, cmdBuff, &cmdLen); 4855141cc406Sopenharmony_ci DBG(25, "cmd: wrote %ld bytes, retVal %d\n", (long)cmdLen, ret); 4856141cc406Sopenharmony_ci 4857141cc406Sopenharmony_ci if(ret == SANE_STATUS_EOF){ 4858141cc406Sopenharmony_ci DBG(5,"cmd: got EOF, returning IO_ERROR\n"); 4859141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4860141cc406Sopenharmony_ci } 4861141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 4862141cc406Sopenharmony_ci DBG(5,"cmd: return error '%s'\n",sane_strstatus(ret)); 4863141cc406Sopenharmony_ci return ret; 4864141cc406Sopenharmony_ci } 4865141cc406Sopenharmony_ci if(loc_cmdLen != cmdLen){ 4866141cc406Sopenharmony_ci DBG(5,"cmd: wrong size %ld/%ld\n", (long)loc_cmdLen, (long)cmdLen); 4867141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4868141cc406Sopenharmony_ci } 4869141cc406Sopenharmony_ci } 4870141cc406Sopenharmony_ci 4871141cc406Sopenharmony_ci /* this command has a write component, and a place to get it */ 4872141cc406Sopenharmony_ci if(outBuff && outLen && outTime){ 4873141cc406Sopenharmony_ci 4874141cc406Sopenharmony_ci /* change timeout */ 4875141cc406Sopenharmony_ci sanei_usb_set_timeout(outTime); 4876141cc406Sopenharmony_ci 4877141cc406Sopenharmony_ci DBG(25, "out: writing %ld bytes, timeout %d\n", (long)outLen, outTime); 4878141cc406Sopenharmony_ci hexdump(30, "out: >>", outBuff, outLen); 4879141cc406Sopenharmony_ci ret = sanei_usb_write_bulk(s->fd, outBuff, &outLen); 4880141cc406Sopenharmony_ci DBG(25, "out: wrote %ld bytes, retVal %d\n", (long)outLen, ret); 4881141cc406Sopenharmony_ci 4882141cc406Sopenharmony_ci if(ret == SANE_STATUS_EOF){ 4883141cc406Sopenharmony_ci DBG(5,"out: got EOF, returning IO_ERROR\n"); 4884141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4885141cc406Sopenharmony_ci } 4886141cc406Sopenharmony_ci if(ret != SANE_STATUS_GOOD){ 4887141cc406Sopenharmony_ci DBG(5,"out: return error '%s'\n",sane_strstatus(ret)); 4888141cc406Sopenharmony_ci return ret; 4889141cc406Sopenharmony_ci } 4890141cc406Sopenharmony_ci if(loc_outLen != outLen){ 4891141cc406Sopenharmony_ci DBG(5,"out: wrong size %ld/%ld\n", (long)loc_outLen, (long)outLen); 4892141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4893141cc406Sopenharmony_ci } 4894141cc406Sopenharmony_ci } 4895141cc406Sopenharmony_ci 4896141cc406Sopenharmony_ci /* this command has a read component, and a place to put it */ 4897141cc406Sopenharmony_ci if(inBuff && inLen && inTime){ 4898141cc406Sopenharmony_ci 4899141cc406Sopenharmony_ci loc_inLen = *inLen; 4900141cc406Sopenharmony_ci DBG(25, "in: memset %ld bytes\n", (long)*inLen); 4901141cc406Sopenharmony_ci memset(inBuff,0,*inLen); 4902141cc406Sopenharmony_ci 4903141cc406Sopenharmony_ci /* change timeout */ 4904141cc406Sopenharmony_ci sanei_usb_set_timeout(inTime); 4905141cc406Sopenharmony_ci 4906141cc406Sopenharmony_ci DBG(25, "in: reading %ld bytes, timeout %d\n", (long)*inLen, inTime); 4907141cc406Sopenharmony_ci ret = sanei_usb_read_bulk(s->fd, inBuff, inLen); 4908141cc406Sopenharmony_ci DBG(25, "in: retVal %d\n", ret); 4909141cc406Sopenharmony_ci 4910141cc406Sopenharmony_ci if(ret == SANE_STATUS_EOF){ 4911141cc406Sopenharmony_ci DBG(5,"in: got EOF, continuing\n"); 4912141cc406Sopenharmony_ci } 4913141cc406Sopenharmony_ci else if(ret != SANE_STATUS_GOOD){ 4914141cc406Sopenharmony_ci DBG(5,"in: return error '%s'\n",sane_strstatus(ret)); 4915141cc406Sopenharmony_ci return ret; 4916141cc406Sopenharmony_ci } 4917141cc406Sopenharmony_ci 4918141cc406Sopenharmony_ci DBG(25, "in: read %ld bytes\n", (long)*inLen); 4919141cc406Sopenharmony_ci if(*inLen){ 4920141cc406Sopenharmony_ci hexdump(30, "in: <<", inBuff, *inLen); 4921141cc406Sopenharmony_ci } 4922141cc406Sopenharmony_ci 4923141cc406Sopenharmony_ci if(loc_inLen != *inLen){ 4924141cc406Sopenharmony_ci ret = SANE_STATUS_EOF; 4925141cc406Sopenharmony_ci DBG(5,"in: short read %ld/%ld\n", (long)loc_inLen, (long)*inLen); 4926141cc406Sopenharmony_ci } 4927141cc406Sopenharmony_ci } 4928141cc406Sopenharmony_ci 4929141cc406Sopenharmony_ci DBG (10, "do_cmd: finish\n"); 4930141cc406Sopenharmony_ci 4931141cc406Sopenharmony_ci return ret; 4932141cc406Sopenharmony_ci} 4933141cc406Sopenharmony_ci 4934141cc406Sopenharmony_ci/** 4935141cc406Sopenharmony_ci * Convenience method to determine longest string size in a list. 4936141cc406Sopenharmony_ci */ 4937141cc406Sopenharmony_cistatic size_t 4938141cc406Sopenharmony_cimaxStringSize (const SANE_String_Const strings[]) 4939141cc406Sopenharmony_ci{ 4940141cc406Sopenharmony_ci size_t size, max_size = 0; 4941141cc406Sopenharmony_ci int i; 4942141cc406Sopenharmony_ci 4943141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) { 4944141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 4945141cc406Sopenharmony_ci max_size = MAX(max_size, size); 4946141cc406Sopenharmony_ci } 4947141cc406Sopenharmony_ci 4948141cc406Sopenharmony_ci return max_size; 4949141cc406Sopenharmony_ci} 4950141cc406Sopenharmony_ci 4951141cc406Sopenharmony_ci/** 4952141cc406Sopenharmony_ci * Prints a hex dump of the given buffer onto the debug output stream. 4953141cc406Sopenharmony_ci */ 4954141cc406Sopenharmony_cistatic void 4955141cc406Sopenharmony_cihexdump (int level, char *comment, unsigned char *p, int l) 4956141cc406Sopenharmony_ci{ 4957141cc406Sopenharmony_ci int i; 4958141cc406Sopenharmony_ci char line[128]; 4959141cc406Sopenharmony_ci char *ptr; 4960141cc406Sopenharmony_ci 4961141cc406Sopenharmony_ci if(DBG_LEVEL < level) 4962141cc406Sopenharmony_ci return; 4963141cc406Sopenharmony_ci 4964141cc406Sopenharmony_ci DBG (level, "%s\n", comment); 4965141cc406Sopenharmony_ci ptr = line; 4966141cc406Sopenharmony_ci for (i = 0; i < l; i++, p++) 4967141cc406Sopenharmony_ci { 4968141cc406Sopenharmony_ci if ((i % 16) == 0) 4969141cc406Sopenharmony_ci { 4970141cc406Sopenharmony_ci if (ptr != line) 4971141cc406Sopenharmony_ci { 4972141cc406Sopenharmony_ci *ptr = '\0'; 4973141cc406Sopenharmony_ci DBG (level, "%s\n", line); 4974141cc406Sopenharmony_ci ptr = line; 4975141cc406Sopenharmony_ci } 4976141cc406Sopenharmony_ci sprintf (ptr, "%3.3x:", i); 4977141cc406Sopenharmony_ci ptr += 4; 4978141cc406Sopenharmony_ci } 4979141cc406Sopenharmony_ci sprintf (ptr, " %2.2x", *p); 4980141cc406Sopenharmony_ci ptr += 3; 4981141cc406Sopenharmony_ci } 4982141cc406Sopenharmony_ci *ptr = '\0'; 4983141cc406Sopenharmony_ci DBG (level, "%s\n", line); 4984141cc406Sopenharmony_ci} 4985141cc406Sopenharmony_ci 4986141cc406Sopenharmony_ci/** 4987141cc406Sopenharmony_ci * An advanced method we don't support but have to define. 4988141cc406Sopenharmony_ci */ 4989141cc406Sopenharmony_ciSANE_Status 4990141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking) 4991141cc406Sopenharmony_ci{ 4992141cc406Sopenharmony_ci DBG (10, "sane_set_io_mode\n"); 4993141cc406Sopenharmony_ci DBG (15, "%d %p\n", non_blocking, h); 4994141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4995141cc406Sopenharmony_ci} 4996141cc406Sopenharmony_ci 4997141cc406Sopenharmony_ci/** 4998141cc406Sopenharmony_ci * An advanced method we don't support but have to define. 4999141cc406Sopenharmony_ci */ 5000141cc406Sopenharmony_ciSANE_Status 5001141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int *fdp) 5002141cc406Sopenharmony_ci{ 5003141cc406Sopenharmony_ci DBG (10, "sane_get_select_fd\n"); 5004141cc406Sopenharmony_ci DBG (15, "%p %d\n", h, *fdp); 5005141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5006141cc406Sopenharmony_ci} 5007141cc406Sopenharmony_ci 5008141cc406Sopenharmony_ci/* s->page_width stores the user setting 5009141cc406Sopenharmony_ci * for the paper width in adf. sometimes, 5010141cc406Sopenharmony_ci * we need a value that differs from this 5011141cc406Sopenharmony_ci * due to using FB 5012141cc406Sopenharmony_ci */ 5013141cc406Sopenharmony_cistatic int 5014141cc406Sopenharmony_ciget_page_width(struct scanner *s) 5015141cc406Sopenharmony_ci{ 5016141cc406Sopenharmony_ci /* scanner max for fb */ 5017141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED){ 5018141cc406Sopenharmony_ci return s->max_x; 5019141cc406Sopenharmony_ci } 5020141cc406Sopenharmony_ci 5021141cc406Sopenharmony_ci return s->page_width; 5022141cc406Sopenharmony_ci} 5023141cc406Sopenharmony_ci 5024141cc406Sopenharmony_ci/* s->page_height stores the user setting 5025141cc406Sopenharmony_ci * for the paper height in adf. sometimes, 5026141cc406Sopenharmony_ci * we need a value that differs from this 5027141cc406Sopenharmony_ci * due to using FB. 5028141cc406Sopenharmony_ci */ 5029141cc406Sopenharmony_cistatic int 5030141cc406Sopenharmony_ciget_page_height(struct scanner *s) 5031141cc406Sopenharmony_ci{ 5032141cc406Sopenharmony_ci /* scanner max for fb */ 5033141cc406Sopenharmony_ci if(s->source == SOURCE_FLATBED){ 5034141cc406Sopenharmony_ci return s->max_y; 5035141cc406Sopenharmony_ci } 5036141cc406Sopenharmony_ci 5037141cc406Sopenharmony_ci return s->page_height; 5038141cc406Sopenharmony_ci} 5039