1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci * SANE - Scanner Access Now Easy. 3141cc406Sopenharmony_ci * coolscan3.c 4141cc406Sopenharmony_ci * 5141cc406Sopenharmony_ci * This file implements a SANE backend for Nikon Coolscan film scanners. 6141cc406Sopenharmony_ci * 7141cc406Sopenharmony_ci * coolscan3.c is based on coolscan2.c, a work of András Major, Ariel Garcia 8141cc406Sopenharmony_ci * and Giuseppe Sacco. 9141cc406Sopenharmony_ci * 10141cc406Sopenharmony_ci * Copyright (C) 2007-08 Tower Technologies 11141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it> 12141cc406Sopenharmony_ci * 13141cc406Sopenharmony_ci * This file is part of the SANE package. 14141cc406Sopenharmony_ci * 15141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or 16141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as 17141cc406Sopenharmony_ci * published by the Free Software Foundation, version 2. 18141cc406Sopenharmony_ci * 19141cc406Sopenharmony_ci */ 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci/* ========================================================================= */ 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "../include/sane/config.h" 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci#include <math.h> 26141cc406Sopenharmony_ci#include <stdio.h> 27141cc406Sopenharmony_ci#include <stdlib.h> 28141cc406Sopenharmony_ci#include <string.h> 29141cc406Sopenharmony_ci#include <ctype.h> 30141cc406Sopenharmony_ci#include <unistd.h> 31141cc406Sopenharmony_ci#include <time.h> 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci#include "../include/_stdint.h" 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci#include "../include/sane/sane.h" 36141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 37141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 38141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 39141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 40141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h" 41141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci#define BACKEND_NAME coolscan3 44141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" /* must be last */ 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci#define CS3_VERSION_MAJOR 1 47141cc406Sopenharmony_ci#define CS3_VERSION_MINOR 0 48141cc406Sopenharmony_ci#define CS3_REVISION 0 49141cc406Sopenharmony_ci#define CS3_CONFIG_FILE "coolscan3.conf" 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci#define WSIZE (sizeof (SANE_Word)) 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci/* ========================================================================= */ 55141cc406Sopenharmony_ci/* typedefs */ 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_citypedef enum 58141cc406Sopenharmony_ci{ 59141cc406Sopenharmony_ci CS3_TYPE_UNKOWN, 60141cc406Sopenharmony_ci CS3_TYPE_LS30, 61141cc406Sopenharmony_ci CS3_TYPE_LS40, 62141cc406Sopenharmony_ci CS3_TYPE_LS50, 63141cc406Sopenharmony_ci CS3_TYPE_LS2000, 64141cc406Sopenharmony_ci CS3_TYPE_LS4000, 65141cc406Sopenharmony_ci CS3_TYPE_LS5000, 66141cc406Sopenharmony_ci CS3_TYPE_LS8000 67141cc406Sopenharmony_ci} 68141cc406Sopenharmony_cics3_type_t; 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_citypedef enum 71141cc406Sopenharmony_ci{ 72141cc406Sopenharmony_ci CS3_INTERFACE_UNKNOWN, 73141cc406Sopenharmony_ci CS3_INTERFACE_SCSI, /* includes IEEE1394 via SBP2 */ 74141cc406Sopenharmony_ci CS3_INTERFACE_USB 75141cc406Sopenharmony_ci} 76141cc406Sopenharmony_cics3_interface_t; 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_citypedef enum 79141cc406Sopenharmony_ci{ 80141cc406Sopenharmony_ci CS3_PHASE_NONE = 0x00, 81141cc406Sopenharmony_ci CS3_PHASE_STATUS = 0x01, 82141cc406Sopenharmony_ci CS3_PHASE_OUT = 0x02, 83141cc406Sopenharmony_ci CS3_PHASE_IN = 0x03, 84141cc406Sopenharmony_ci CS3_PHASE_BUSY = 0x04 85141cc406Sopenharmony_ci} 86141cc406Sopenharmony_cics3_phase_t; 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_citypedef enum 89141cc406Sopenharmony_ci{ 90141cc406Sopenharmony_ci CS3_SCAN_NORMAL, 91141cc406Sopenharmony_ci CS3_SCAN_AE, 92141cc406Sopenharmony_ci CS3_SCAN_AE_WB 93141cc406Sopenharmony_ci} 94141cc406Sopenharmony_cics3_scan_t; 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_citypedef enum 97141cc406Sopenharmony_ci{ 98141cc406Sopenharmony_ci CS3_STATUS_READY = 0, 99141cc406Sopenharmony_ci CS3_STATUS_BUSY = 1, 100141cc406Sopenharmony_ci CS3_STATUS_NO_DOCS = 2, 101141cc406Sopenharmony_ci CS3_STATUS_PROCESSING = 4, 102141cc406Sopenharmony_ci CS3_STATUS_ERROR = 8, 103141cc406Sopenharmony_ci CS3_STATUS_REISSUE = 16, 104141cc406Sopenharmony_ci CS3_STATUS_ALL = 31 /* sum of all others */ 105141cc406Sopenharmony_ci} 106141cc406Sopenharmony_cics3_status_t; 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_citypedef enum 109141cc406Sopenharmony_ci{ 110141cc406Sopenharmony_ci CS3_OPTION_NUM = 0, 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci CS3_OPTION_PREVIEW, 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci CS3_OPTION_NEGATIVE, 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_ci CS3_OPTION_INFRARED, 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci CS3_OPTION_SAMPLES_PER_SCAN, 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci CS3_OPTION_DEPTH, 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci CS3_OPTION_EXPOSURE, 123141cc406Sopenharmony_ci CS3_OPTION_EXPOSURE_R, 124141cc406Sopenharmony_ci CS3_OPTION_EXPOSURE_G, 125141cc406Sopenharmony_ci CS3_OPTION_EXPOSURE_B, 126141cc406Sopenharmony_ci CS3_OPTION_SCAN_AE, 127141cc406Sopenharmony_ci CS3_OPTION_SCAN_AE_WB, 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci CS3_OPTION_LUT_R, 130141cc406Sopenharmony_ci CS3_OPTION_LUT_G, 131141cc406Sopenharmony_ci CS3_OPTION_LUT_B, 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci CS3_OPTION_RES, 134141cc406Sopenharmony_ci CS3_OPTION_RESX, 135141cc406Sopenharmony_ci CS3_OPTION_RESY, 136141cc406Sopenharmony_ci CS3_OPTION_RES_INDEPENDENT, 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci CS3_OPTION_PREVIEW_RESOLUTION, 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci CS3_OPTION_FRAME, 141141cc406Sopenharmony_ci CS3_OPTION_FRAME_COUNT, 142141cc406Sopenharmony_ci CS3_OPTION_SUBFRAME, 143141cc406Sopenharmony_ci CS3_OPTION_XMIN, 144141cc406Sopenharmony_ci CS3_OPTION_XMAX, 145141cc406Sopenharmony_ci CS3_OPTION_YMIN, 146141cc406Sopenharmony_ci CS3_OPTION_YMAX, 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci CS3_OPTION_LOAD, 149141cc406Sopenharmony_ci CS3_OPTION_AUTOLOAD, 150141cc406Sopenharmony_ci CS3_OPTION_EJECT, 151141cc406Sopenharmony_ci CS3_OPTION_RESET, 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci CS3_OPTION_FOCUS_ON_CENTRE, 154141cc406Sopenharmony_ci CS3_OPTION_FOCUS, 155141cc406Sopenharmony_ci CS3_OPTION_AUTOFOCUS, 156141cc406Sopenharmony_ci CS3_OPTION_FOCUSX, 157141cc406Sopenharmony_ci CS3_OPTION_FOCUSY, 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci CS3_N_OPTIONS /* must be last -- counts number of enum items */ 160141cc406Sopenharmony_ci} 161141cc406Sopenharmony_cics3_option_t; 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_citypedef unsigned int cs3_pixel_t; 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci#define CS3_COLOR_MAX 10 /* 9 + 1, see cs3_colors */ 166141cc406Sopenharmony_ci 167141cc406Sopenharmony_ci/* Given that there is no way to give scanner vendor 168141cc406Sopenharmony_ci * and model to the calling software, I have to use 169141cc406Sopenharmony_ci * an ugly hack here. :( That's very sad. Suggestions 170141cc406Sopenharmony_ci * that can provide the same features are appreciated. 171141cc406Sopenharmony_ci */ 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci#ifndef SANE_COOKIE 174141cc406Sopenharmony_ci#define SANE_COOKIE 0x0BADCAFE 175141cc406Sopenharmony_ci 176141cc406Sopenharmony_cistruct SANE_Cookie 177141cc406Sopenharmony_ci{ 178141cc406Sopenharmony_ci uint16_t version; 179141cc406Sopenharmony_ci const char *vendor; 180141cc406Sopenharmony_ci const char *model; 181141cc406Sopenharmony_ci const char *revision; 182141cc406Sopenharmony_ci}; 183141cc406Sopenharmony_ci#endif 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_citypedef struct 186141cc406Sopenharmony_ci{ 187141cc406Sopenharmony_ci /* magic bits :( */ 188141cc406Sopenharmony_ci uint32_t magic; 189141cc406Sopenharmony_ci struct SANE_Cookie *cookie_ptr; 190141cc406Sopenharmony_ci struct SANE_Cookie cookie; 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci /* interface */ 193141cc406Sopenharmony_ci cs3_interface_t interface; 194141cc406Sopenharmony_ci int fd; 195141cc406Sopenharmony_ci SANE_Byte *send_buf, *recv_buf; 196141cc406Sopenharmony_ci size_t send_buf_size, recv_buf_size; 197141cc406Sopenharmony_ci size_t n_cmd, n_send, n_recv; 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci /* device characteristics */ 200141cc406Sopenharmony_ci char vendor_string[9], product_string[17], revision_string[5]; 201141cc406Sopenharmony_ci cs3_type_t type; 202141cc406Sopenharmony_ci int maxbits; 203141cc406Sopenharmony_ci unsigned int resx_optical, resx_min, resx_max, *resx_list, 204141cc406Sopenharmony_ci resx_n_list; 205141cc406Sopenharmony_ci unsigned int resy_optical, resy_min, resy_max, *resy_list, 206141cc406Sopenharmony_ci resy_n_list; 207141cc406Sopenharmony_ci unsigned long boundaryx, boundaryy; 208141cc406Sopenharmony_ci unsigned long frame_offset; 209141cc406Sopenharmony_ci unsigned int unit_dpi; 210141cc406Sopenharmony_ci double unit_mm; 211141cc406Sopenharmony_ci int n_frames; 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_ci int focus_min, focus_max; 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci /* settings */ 216141cc406Sopenharmony_ci SANE_Bool preview, negative, infrared, autoload, autofocus, ae, aewb; 217141cc406Sopenharmony_ci int samples_per_scan, depth, real_depth, bytes_per_pixel, shift_bits, 218141cc406Sopenharmony_ci n_colors; 219141cc406Sopenharmony_ci cs3_pixel_t n_lut; 220141cc406Sopenharmony_ci cs3_pixel_t *lut_r, *lut_g, *lut_b, *lut_neutral; 221141cc406Sopenharmony_ci unsigned long resx, resy, res, res_independent, res_preview; 222141cc406Sopenharmony_ci unsigned long xmin, xmax, ymin, ymax; 223141cc406Sopenharmony_ci int i_frame, frame_count; 224141cc406Sopenharmony_ci double subframe; 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci unsigned int real_resx, real_resy, real_pitchx, real_pitchy; 227141cc406Sopenharmony_ci unsigned long real_xoffset, real_yoffset, real_width, real_height, 228141cc406Sopenharmony_ci logical_width, logical_height; 229141cc406Sopenharmony_ci int odd_padding; 230141cc406Sopenharmony_ci int block_padding; 231141cc406Sopenharmony_ci 232141cc406Sopenharmony_ci double exposure, exposure_r, exposure_g, exposure_b; 233141cc406Sopenharmony_ci unsigned long real_exposure[CS3_COLOR_MAX]; 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci 236141cc406Sopenharmony_ci SANE_Bool focus_on_centre; 237141cc406Sopenharmony_ci unsigned long focusx, focusy, real_focusx, real_focusy; 238141cc406Sopenharmony_ci int focus; 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci /* status */ 241141cc406Sopenharmony_ci SANE_Bool scanning; 242141cc406Sopenharmony_ci SANE_Byte *line_buf; 243141cc406Sopenharmony_ci ssize_t n_line_buf, i_line_buf; 244141cc406Sopenharmony_ci unsigned long sense_key, sense_asc, sense_ascq, sense_info; 245141cc406Sopenharmony_ci unsigned long sense_code; 246141cc406Sopenharmony_ci cs3_status_t status; 247141cc406Sopenharmony_ci size_t xfer_position, xfer_bytes_total; 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci /* SANE stuff */ 250141cc406Sopenharmony_ci SANE_Option_Descriptor option_list[CS3_N_OPTIONS]; 251141cc406Sopenharmony_ci} 252141cc406Sopenharmony_cics3_t; 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_ci 255141cc406Sopenharmony_ci/* ========================================================================= */ 256141cc406Sopenharmony_ci/* prototypes */ 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_cistatic SANE_Status cs3_open(const char *device, cs3_interface_t interface, 259141cc406Sopenharmony_ci cs3_t ** sp); 260141cc406Sopenharmony_cistatic void cs3_close(cs3_t * s); 261141cc406Sopenharmony_cistatic SANE_Status cs3_attach(const char *dev); 262141cc406Sopenharmony_cistatic SANE_Status cs3_scsi_sense_handler(int fd, u_char * sense_buffer, 263141cc406Sopenharmony_ci void *arg); 264141cc406Sopenharmony_cistatic SANE_Status cs3_parse_sense_data(cs3_t * s); 265141cc406Sopenharmony_cistatic void cs3_init_buffer(cs3_t * s); 266141cc406Sopenharmony_cistatic SANE_Status cs3_pack_byte(cs3_t * s, SANE_Byte byte); 267141cc406Sopenharmony_cistatic void cs3_pack_long(cs3_t * s, unsigned long val); 268141cc406Sopenharmony_cistatic void cs3_pack_word(cs3_t * s, unsigned long val); 269141cc406Sopenharmony_cistatic SANE_Status cs3_parse_cmd(cs3_t * s, char *text); 270141cc406Sopenharmony_cistatic SANE_Status cs3_grow_send_buffer(cs3_t * s); 271141cc406Sopenharmony_cistatic SANE_Status cs3_issue_cmd(cs3_t * s); 272141cc406Sopenharmony_cistatic cs3_phase_t cs3_phase_check(cs3_t * s); 273141cc406Sopenharmony_cistatic SANE_Status cs3_set_boundary(cs3_t * s); 274141cc406Sopenharmony_cistatic SANE_Status cs3_scanner_ready(cs3_t * s, int flags); 275141cc406Sopenharmony_cistatic SANE_Status cs3_page_inquiry(cs3_t * s, int page); 276141cc406Sopenharmony_cistatic SANE_Status cs3_full_inquiry(cs3_t * s); 277141cc406Sopenharmony_cistatic SANE_Status cs3_mode_select(cs3_t * s); 278141cc406Sopenharmony_cistatic SANE_Status cs3_reserve_unit(cs3_t * s); 279141cc406Sopenharmony_cistatic SANE_Status cs3_release_unit(cs3_t * s); 280141cc406Sopenharmony_cistatic SANE_Status cs3_execute(cs3_t * s); 281141cc406Sopenharmony_cistatic SANE_Status cs3_load(cs3_t * s); 282141cc406Sopenharmony_cistatic SANE_Status cs3_eject(cs3_t * s); 283141cc406Sopenharmony_cistatic SANE_Status cs3_reset(cs3_t * s); 284141cc406Sopenharmony_cistatic SANE_Status cs3_set_focus(cs3_t * s); 285141cc406Sopenharmony_cistatic SANE_Status cs3_autofocus(cs3_t * s); 286141cc406Sopenharmony_cistatic SANE_Status cs3_autoexposure(cs3_t * s, int wb); 287141cc406Sopenharmony_cistatic SANE_Status cs3_get_exposure(cs3_t * s); 288141cc406Sopenharmony_cistatic SANE_Status cs3_set_window(cs3_t * s, cs3_scan_t type); 289141cc406Sopenharmony_cistatic SANE_Status cs3_convert_options(cs3_t * s); 290141cc406Sopenharmony_cistatic SANE_Status cs3_scan(cs3_t * s, cs3_scan_t type); 291141cc406Sopenharmony_cistatic void *cs3_xmalloc(size_t size); 292141cc406Sopenharmony_cistatic void *cs3_xrealloc(void *p, size_t size); 293141cc406Sopenharmony_cistatic void cs3_xfree(void *p); 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_ci 296141cc406Sopenharmony_ci/* ========================================================================= */ 297141cc406Sopenharmony_ci/* global variables */ 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_cistatic int cs3_colors[] = { 1, 2, 3, 9 }; 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_cistatic SANE_Device **device_list = NULL; 302141cc406Sopenharmony_cistatic int n_device_list = 0; 303141cc406Sopenharmony_cistatic cs3_interface_t try_interface = CS3_INTERFACE_UNKNOWN; 304141cc406Sopenharmony_cistatic int open_devices = 0; 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci 307141cc406Sopenharmony_ci/* ========================================================================= */ 308141cc406Sopenharmony_ci/* SANE entry points */ 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ciSANE_Status 311141cc406Sopenharmony_cisane_init(SANE_Int * version_code, SANE_Auth_Callback authorize) 312141cc406Sopenharmony_ci{ 313141cc406Sopenharmony_ci DBG_INIT(); 314141cc406Sopenharmony_ci DBG(1, "coolscan3 backend, version %i.%i.%i initializing.\n", 315141cc406Sopenharmony_ci CS3_VERSION_MAJOR, CS3_VERSION_MINOR, CS3_REVISION); 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_ci (void) authorize; /* to shut up compiler */ 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci if (version_code) 320141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci sanei_usb_init(); 323141cc406Sopenharmony_ci 324141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 325141cc406Sopenharmony_ci} 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_civoid 328141cc406Sopenharmony_cisane_exit(void) 329141cc406Sopenharmony_ci{ 330141cc406Sopenharmony_ci int i; 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci for (i = 0; i < n_device_list; i++) { 335141cc406Sopenharmony_ci cs3_xfree((void *)device_list[i]->name); 336141cc406Sopenharmony_ci cs3_xfree((void *)device_list[i]->vendor); 337141cc406Sopenharmony_ci cs3_xfree((void *)device_list[i]->model); 338141cc406Sopenharmony_ci cs3_xfree(device_list[i]); 339141cc406Sopenharmony_ci } 340141cc406Sopenharmony_ci cs3_xfree(device_list); 341141cc406Sopenharmony_ci} 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ciSANE_Status 344141cc406Sopenharmony_cisane_get_devices(const SANE_Device *** list, SANE_Bool local_only) 345141cc406Sopenharmony_ci{ 346141cc406Sopenharmony_ci char line[PATH_MAX], *p; 347141cc406Sopenharmony_ci FILE *config; 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci (void) local_only; /* to shut up compiler */ 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci if (device_list) 354141cc406Sopenharmony_ci DBG(6, 355141cc406Sopenharmony_ci "sane_get_devices(): Device list already populated, not probing again.\n"); 356141cc406Sopenharmony_ci else { 357141cc406Sopenharmony_ci if (open_devices) { 358141cc406Sopenharmony_ci DBG(4, 359141cc406Sopenharmony_ci "sane_get_devices(): Devices open, not scanning for scanners.\n"); 360141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 361141cc406Sopenharmony_ci } 362141cc406Sopenharmony_ci 363141cc406Sopenharmony_ci config = sanei_config_open(CS3_CONFIG_FILE); 364141cc406Sopenharmony_ci if (config) { 365141cc406Sopenharmony_ci DBG(4, "sane_get_devices(): Reading config file.\n"); 366141cc406Sopenharmony_ci while (sanei_config_read(line, sizeof(line), config)) { 367141cc406Sopenharmony_ci p = line; 368141cc406Sopenharmony_ci p += strspn(line, " \t"); 369141cc406Sopenharmony_ci if (strlen(p) && (p[0] != '\n') 370141cc406Sopenharmony_ci && (p[0] != '#')) 371141cc406Sopenharmony_ci cs3_open(line, CS3_INTERFACE_UNKNOWN, 372141cc406Sopenharmony_ci NULL); 373141cc406Sopenharmony_ci } 374141cc406Sopenharmony_ci fclose(config); 375141cc406Sopenharmony_ci } else { 376141cc406Sopenharmony_ci DBG(4, "sane_get_devices(): No config file found.\n"); 377141cc406Sopenharmony_ci cs3_open("auto", CS3_INTERFACE_UNKNOWN, NULL); 378141cc406Sopenharmony_ci } 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci DBG(6, "%s: %i device(s) detected.\n", 381141cc406Sopenharmony_ci __func__, n_device_list); 382141cc406Sopenharmony_ci } 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_ci *list = (const SANE_Device **) device_list; 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 387141cc406Sopenharmony_ci} 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_ciSANE_Status 390141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle * h) 391141cc406Sopenharmony_ci{ 392141cc406Sopenharmony_ci SANE_Status status; 393141cc406Sopenharmony_ci cs3_t *s; 394141cc406Sopenharmony_ci int i_option; 395141cc406Sopenharmony_ci unsigned int i_list; 396141cc406Sopenharmony_ci SANE_Option_Descriptor o; 397141cc406Sopenharmony_ci SANE_Word *word_list; 398141cc406Sopenharmony_ci SANE_Range *range = NULL; 399141cc406Sopenharmony_ci int alloc_failed = 0; 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci status = cs3_open(name, CS3_INTERFACE_UNKNOWN, &s); 404141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 405141cc406Sopenharmony_ci return status; 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_ci *h = (SANE_Handle) s; 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci /* get device properties */ 410141cc406Sopenharmony_ci 411141cc406Sopenharmony_ci s->lut_r = s->lut_g = s->lut_b = s->lut_neutral = NULL; 412141cc406Sopenharmony_ci s->resx_list = s->resy_list = NULL; 413141cc406Sopenharmony_ci s->resx_n_list = s->resy_n_list = 0; 414141cc406Sopenharmony_ci 415141cc406Sopenharmony_ci status = cs3_full_inquiry(s); 416141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 417141cc406Sopenharmony_ci return status; 418141cc406Sopenharmony_ci 419141cc406Sopenharmony_ci status = cs3_mode_select(s); 420141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 421141cc406Sopenharmony_ci return status; 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci /* option descriptors */ 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci for (i_option = 0; i_option < CS3_N_OPTIONS; i_option++) { 426141cc406Sopenharmony_ci o.name = o.title = o.desc = NULL; 427141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 428141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 429141cc406Sopenharmony_ci o.size = o.cap = 0; 430141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_NONE; 431141cc406Sopenharmony_ci o.constraint.range = NULL; /* only one union member needs to be NULLed */ 432141cc406Sopenharmony_ci switch (i_option) { 433141cc406Sopenharmony_ci case CS3_OPTION_NUM: 434141cc406Sopenharmony_ci o.name = ""; 435141cc406Sopenharmony_ci o.title = SANE_TITLE_NUM_OPTIONS; 436141cc406Sopenharmony_ci o.desc = SANE_DESC_NUM_OPTIONS; 437141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 438141cc406Sopenharmony_ci o.size = WSIZE; 439141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_DETECT; 440141cc406Sopenharmony_ci break; 441141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW: 442141cc406Sopenharmony_ci o.name = "preview"; 443141cc406Sopenharmony_ci o.title = "Preview mode"; 444141cc406Sopenharmony_ci o.desc = "Preview mode"; 445141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 446141cc406Sopenharmony_ci o.size = WSIZE; 447141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | 448141cc406Sopenharmony_ci SANE_CAP_ADVANCED; 449141cc406Sopenharmony_ci break; 450141cc406Sopenharmony_ci case CS3_OPTION_NEGATIVE: 451141cc406Sopenharmony_ci o.name = "negative"; 452141cc406Sopenharmony_ci o.title = "Negative"; 453141cc406Sopenharmony_ci o.desc = "Negative film: make scanner invert colors"; 454141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 455141cc406Sopenharmony_ci o.size = WSIZE; 456141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 457141cc406Sopenharmony_ci /*o.cap |= SANE_CAP_INACTIVE; */ 458141cc406Sopenharmony_ci break; 459141cc406Sopenharmony_ci 460141cc406Sopenharmony_ci case CS3_OPTION_INFRARED: 461141cc406Sopenharmony_ci o.name = "infrared"; 462141cc406Sopenharmony_ci o.title = "Read infrared channel"; 463141cc406Sopenharmony_ci o.desc = "Read infrared channel in addition to scan colors"; 464141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 465141cc406Sopenharmony_ci o.size = WSIZE; 466141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 467141cc406Sopenharmony_ci#ifndef SANE_FRAME_RGBI 468141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 469141cc406Sopenharmony_ci#endif 470141cc406Sopenharmony_ci break; 471141cc406Sopenharmony_ci 472141cc406Sopenharmony_ci case CS3_OPTION_SAMPLES_PER_SCAN: 473141cc406Sopenharmony_ci o.name = "samples-per-scan"; 474141cc406Sopenharmony_ci o.title = "Samples per Scan"; 475141cc406Sopenharmony_ci o.desc = "Number of samples per scan"; 476141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 477141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 478141cc406Sopenharmony_ci o.size = WSIZE; 479141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 480141cc406Sopenharmony_ci if (s->type != CS3_TYPE_LS2000 && s->type != CS3_TYPE_LS4000 481141cc406Sopenharmony_ci && s->type != CS3_TYPE_LS5000 && s->type != CS3_TYPE_LS8000) 482141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 483141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 484141cc406Sopenharmony_ci range = (SANE_Range *) cs3_xmalloc (sizeof (SANE_Range)); 485141cc406Sopenharmony_ci if (! range) 486141cc406Sopenharmony_ci alloc_failed = 1; 487141cc406Sopenharmony_ci else 488141cc406Sopenharmony_ci { 489141cc406Sopenharmony_ci range->min = 1; 490141cc406Sopenharmony_ci range->max = 16; 491141cc406Sopenharmony_ci range->quant = 1; 492141cc406Sopenharmony_ci o.constraint.range = range; 493141cc406Sopenharmony_ci } 494141cc406Sopenharmony_ci break; 495141cc406Sopenharmony_ci 496141cc406Sopenharmony_ci case CS3_OPTION_DEPTH: 497141cc406Sopenharmony_ci o.name = "depth"; 498141cc406Sopenharmony_ci o.title = "Bit depth per channel"; 499141cc406Sopenharmony_ci o.desc = "Number of bits output by scanner for each channel"; 500141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 501141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 502141cc406Sopenharmony_ci o.size = WSIZE; 503141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 504141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_WORD_LIST; 505141cc406Sopenharmony_ci word_list = 506141cc406Sopenharmony_ci (SANE_Word *) cs3_xmalloc(2 * 507141cc406Sopenharmony_ci sizeof(SANE_Word)); 508141cc406Sopenharmony_ci if (!word_list) 509141cc406Sopenharmony_ci alloc_failed = 1; 510141cc406Sopenharmony_ci else { 511141cc406Sopenharmony_ci word_list[1] = 8; 512141cc406Sopenharmony_ci word_list[2] = s->maxbits; 513141cc406Sopenharmony_ci word_list[0] = 2; 514141cc406Sopenharmony_ci o.constraint.word_list = word_list; 515141cc406Sopenharmony_ci } 516141cc406Sopenharmony_ci break; 517141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE: 518141cc406Sopenharmony_ci o.name = "exposure"; 519141cc406Sopenharmony_ci o.title = "Exposure multiplier"; 520141cc406Sopenharmony_ci o.desc = "Exposure multiplier for all channels"; 521141cc406Sopenharmony_ci o.type = SANE_TYPE_FIXED; 522141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 523141cc406Sopenharmony_ci o.size = WSIZE; 524141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 525141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 526141cc406Sopenharmony_ci range = (SANE_Range *) 527141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 528141cc406Sopenharmony_ci if (!range) 529141cc406Sopenharmony_ci alloc_failed = 1; 530141cc406Sopenharmony_ci else { 531141cc406Sopenharmony_ci range->min = SANE_FIX(0.); 532141cc406Sopenharmony_ci range->max = SANE_FIX(10.); 533141cc406Sopenharmony_ci range->quant = SANE_FIX(0.1); 534141cc406Sopenharmony_ci o.constraint.range = range; 535141cc406Sopenharmony_ci } 536141cc406Sopenharmony_ci break; 537141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_R: 538141cc406Sopenharmony_ci o.name = "red-exposure"; 539141cc406Sopenharmony_ci o.title = "Red exposure time"; 540141cc406Sopenharmony_ci o.desc = "Exposure time for red channel"; 541141cc406Sopenharmony_ci o.type = SANE_TYPE_FIXED; 542141cc406Sopenharmony_ci o.unit = SANE_UNIT_MICROSECOND; 543141cc406Sopenharmony_ci o.size = WSIZE; 544141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 545141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 546141cc406Sopenharmony_ci range = (SANE_Range *) 547141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 548141cc406Sopenharmony_ci if (!range) 549141cc406Sopenharmony_ci alloc_failed = 1; 550141cc406Sopenharmony_ci else { 551141cc406Sopenharmony_ci range->min = SANE_FIX(50.); 552141cc406Sopenharmony_ci range->max = SANE_FIX(20000.); 553141cc406Sopenharmony_ci range->quant = SANE_FIX(10.); 554141cc406Sopenharmony_ci o.constraint.range = range; 555141cc406Sopenharmony_ci } 556141cc406Sopenharmony_ci break; 557141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_G: 558141cc406Sopenharmony_ci o.name = "green-exposure"; 559141cc406Sopenharmony_ci o.title = "Green exposure time"; 560141cc406Sopenharmony_ci o.desc = "Exposure time for green channel"; 561141cc406Sopenharmony_ci o.type = SANE_TYPE_FIXED; 562141cc406Sopenharmony_ci o.unit = SANE_UNIT_MICROSECOND; 563141cc406Sopenharmony_ci o.size = WSIZE; 564141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 565141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 566141cc406Sopenharmony_ci range = (SANE_Range *) 567141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 568141cc406Sopenharmony_ci if (!range) 569141cc406Sopenharmony_ci alloc_failed = 1; 570141cc406Sopenharmony_ci else { 571141cc406Sopenharmony_ci range->min = SANE_FIX(50.); 572141cc406Sopenharmony_ci range->max = SANE_FIX(20000.); 573141cc406Sopenharmony_ci range->quant = SANE_FIX(10.); 574141cc406Sopenharmony_ci o.constraint.range = range; 575141cc406Sopenharmony_ci } 576141cc406Sopenharmony_ci break; 577141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_B: 578141cc406Sopenharmony_ci o.name = "blue-exposure"; 579141cc406Sopenharmony_ci o.title = "Blue exposure time"; 580141cc406Sopenharmony_ci o.desc = "Exposure time for blue channel"; 581141cc406Sopenharmony_ci o.type = SANE_TYPE_FIXED; 582141cc406Sopenharmony_ci o.unit = SANE_UNIT_MICROSECOND; 583141cc406Sopenharmony_ci o.size = WSIZE; 584141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 585141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 586141cc406Sopenharmony_ci range = (SANE_Range *) 587141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 588141cc406Sopenharmony_ci if (!range) 589141cc406Sopenharmony_ci alloc_failed = 1; 590141cc406Sopenharmony_ci else { 591141cc406Sopenharmony_ci range->min = SANE_FIX(50.); 592141cc406Sopenharmony_ci range->max = SANE_FIX(20000.); 593141cc406Sopenharmony_ci range->quant = SANE_FIX(10.); 594141cc406Sopenharmony_ci o.constraint.range = range; 595141cc406Sopenharmony_ci } 596141cc406Sopenharmony_ci break; 597141cc406Sopenharmony_ci case CS3_OPTION_LUT_R: 598141cc406Sopenharmony_ci o.name = "red-gamma-table"; 599141cc406Sopenharmony_ci o.title = "LUT for red channel"; 600141cc406Sopenharmony_ci o.desc = "LUT for red channel"; 601141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 602141cc406Sopenharmony_ci o.size = s->n_lut * WSIZE; 603141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 604141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 605141cc406Sopenharmony_ci range = (SANE_Range *) 606141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 607141cc406Sopenharmony_ci if (!range) 608141cc406Sopenharmony_ci alloc_failed = 1; 609141cc406Sopenharmony_ci else { 610141cc406Sopenharmony_ci range->min = 0; 611141cc406Sopenharmony_ci range->max = s->n_lut - 1; 612141cc406Sopenharmony_ci range->quant = 1; 613141cc406Sopenharmony_ci o.constraint.range = range; 614141cc406Sopenharmony_ci } 615141cc406Sopenharmony_ci break; 616141cc406Sopenharmony_ci case CS3_OPTION_LUT_G: 617141cc406Sopenharmony_ci o.name = "green-gamma-table"; 618141cc406Sopenharmony_ci o.title = "LUT for green channel"; 619141cc406Sopenharmony_ci o.desc = "LUT for green channel"; 620141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 621141cc406Sopenharmony_ci o.size = s->n_lut * WSIZE; 622141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 623141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 624141cc406Sopenharmony_ci range = (SANE_Range *) 625141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 626141cc406Sopenharmony_ci if (!range) 627141cc406Sopenharmony_ci alloc_failed = 1; 628141cc406Sopenharmony_ci else { 629141cc406Sopenharmony_ci range->min = 0; 630141cc406Sopenharmony_ci range->max = s->n_lut - 1; 631141cc406Sopenharmony_ci range->quant = 1; 632141cc406Sopenharmony_ci o.constraint.range = range; 633141cc406Sopenharmony_ci } 634141cc406Sopenharmony_ci break; 635141cc406Sopenharmony_ci case CS3_OPTION_LUT_B: 636141cc406Sopenharmony_ci o.name = "blue-gamma-table"; 637141cc406Sopenharmony_ci o.title = "LUT for blue channel"; 638141cc406Sopenharmony_ci o.desc = "LUT for blue channel"; 639141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 640141cc406Sopenharmony_ci o.size = s->n_lut * WSIZE; 641141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 642141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 643141cc406Sopenharmony_ci range = (SANE_Range *) 644141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 645141cc406Sopenharmony_ci if (!range) 646141cc406Sopenharmony_ci alloc_failed = 1; 647141cc406Sopenharmony_ci else { 648141cc406Sopenharmony_ci range->min = 0; 649141cc406Sopenharmony_ci range->max = s->n_lut - 1; 650141cc406Sopenharmony_ci range->quant = 1; 651141cc406Sopenharmony_ci o.constraint.range = range; 652141cc406Sopenharmony_ci } 653141cc406Sopenharmony_ci break; 654141cc406Sopenharmony_ci case CS3_OPTION_LOAD: 655141cc406Sopenharmony_ci o.name = "load"; 656141cc406Sopenharmony_ci o.title = "Load"; 657141cc406Sopenharmony_ci o.desc = "Load next slide"; 658141cc406Sopenharmony_ci o.type = SANE_TYPE_BUTTON; 659141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 660141cc406Sopenharmony_ci if (s->n_frames > 1) 661141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 662141cc406Sopenharmony_ci break; 663141cc406Sopenharmony_ci case CS3_OPTION_AUTOLOAD: 664141cc406Sopenharmony_ci o.name = "autoload"; 665141cc406Sopenharmony_ci o.title = "Autoload"; 666141cc406Sopenharmony_ci o.desc = "Autoload slide before each scan"; 667141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 668141cc406Sopenharmony_ci o.size = WSIZE; 669141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 670141cc406Sopenharmony_ci if (s->n_frames > 1) 671141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 672141cc406Sopenharmony_ci break; 673141cc406Sopenharmony_ci case CS3_OPTION_EJECT: 674141cc406Sopenharmony_ci o.name = "eject"; 675141cc406Sopenharmony_ci o.title = "Eject"; 676141cc406Sopenharmony_ci o.desc = "Eject loaded medium"; 677141cc406Sopenharmony_ci o.type = SANE_TYPE_BUTTON; 678141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 679141cc406Sopenharmony_ci break; 680141cc406Sopenharmony_ci case CS3_OPTION_RESET: 681141cc406Sopenharmony_ci o.name = "reset"; 682141cc406Sopenharmony_ci o.title = "Reset scanner"; 683141cc406Sopenharmony_ci o.desc = "Initialize scanner"; 684141cc406Sopenharmony_ci o.type = SANE_TYPE_BUTTON; 685141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 686141cc406Sopenharmony_ci break; 687141cc406Sopenharmony_ci case CS3_OPTION_RESX: 688141cc406Sopenharmony_ci case CS3_OPTION_RES: 689141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW_RESOLUTION: 690141cc406Sopenharmony_ci if (i_option == CS3_OPTION_PREVIEW_RESOLUTION) { 691141cc406Sopenharmony_ci o.name = "preview-resolution"; 692141cc406Sopenharmony_ci o.title = "Preview resolution"; 693141cc406Sopenharmony_ci o.desc = "Scanning resolution for preview mode in dpi, affecting both x and y directions"; 694141cc406Sopenharmony_ci } else if (i_option == CS3_OPTION_RES) { 695141cc406Sopenharmony_ci o.name = "resolution"; 696141cc406Sopenharmony_ci o.title = "Resolution"; 697141cc406Sopenharmony_ci o.desc = "Scanning resolution in dpi, affecting both x and y directions"; 698141cc406Sopenharmony_ci } else { 699141cc406Sopenharmony_ci o.name = "x-resolution"; 700141cc406Sopenharmony_ci o.title = "X resolution"; 701141cc406Sopenharmony_ci o.desc = "Scanning resolution in dpi, affecting x direction only"; 702141cc406Sopenharmony_ci } 703141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 704141cc406Sopenharmony_ci o.unit = SANE_UNIT_DPI; 705141cc406Sopenharmony_ci o.size = WSIZE; 706141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 707141cc406Sopenharmony_ci if (i_option == CS3_OPTION_RESX) 708141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE | 709141cc406Sopenharmony_ci SANE_CAP_ADVANCED; 710141cc406Sopenharmony_ci if (i_option == CS3_OPTION_PREVIEW_RESOLUTION) 711141cc406Sopenharmony_ci o.cap |= SANE_CAP_ADVANCED; 712141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_WORD_LIST; 713141cc406Sopenharmony_ci word_list = 714141cc406Sopenharmony_ci (SANE_Word *) cs3_xmalloc((s->resx_n_list + 1) 715141cc406Sopenharmony_ci * 716141cc406Sopenharmony_ci sizeof(SANE_Word)); 717141cc406Sopenharmony_ci if (!word_list) 718141cc406Sopenharmony_ci alloc_failed = 1; 719141cc406Sopenharmony_ci else { 720141cc406Sopenharmony_ci for (i_list = 0; i_list < s->resx_n_list; 721141cc406Sopenharmony_ci i_list++) 722141cc406Sopenharmony_ci word_list[i_list + 1] = 723141cc406Sopenharmony_ci s->resx_list[i_list]; 724141cc406Sopenharmony_ci word_list[0] = s->resx_n_list; 725141cc406Sopenharmony_ci o.constraint.word_list = word_list; 726141cc406Sopenharmony_ci } 727141cc406Sopenharmony_ci break; 728141cc406Sopenharmony_ci case CS3_OPTION_RESY: 729141cc406Sopenharmony_ci o.name = "y-resolution"; 730141cc406Sopenharmony_ci o.title = "Y resolution"; 731141cc406Sopenharmony_ci o.desc = "Scanning resolution in dpi, affecting y direction only"; 732141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 733141cc406Sopenharmony_ci o.unit = SANE_UNIT_DPI; 734141cc406Sopenharmony_ci o.size = WSIZE; 735141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | 736141cc406Sopenharmony_ci SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; 737141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_WORD_LIST; 738141cc406Sopenharmony_ci word_list = 739141cc406Sopenharmony_ci (SANE_Word *) cs3_xmalloc((s->resy_n_list + 1) 740141cc406Sopenharmony_ci * 741141cc406Sopenharmony_ci sizeof(SANE_Word)); 742141cc406Sopenharmony_ci if (!word_list) 743141cc406Sopenharmony_ci alloc_failed = 1; 744141cc406Sopenharmony_ci else { 745141cc406Sopenharmony_ci for (i_list = 0; i_list < s->resy_n_list; 746141cc406Sopenharmony_ci i_list++) 747141cc406Sopenharmony_ci word_list[i_list + 1] = 748141cc406Sopenharmony_ci s->resy_list[i_list]; 749141cc406Sopenharmony_ci word_list[0] = s->resy_n_list; 750141cc406Sopenharmony_ci o.constraint.word_list = word_list; 751141cc406Sopenharmony_ci } 752141cc406Sopenharmony_ci break; 753141cc406Sopenharmony_ci case CS3_OPTION_RES_INDEPENDENT: 754141cc406Sopenharmony_ci o.name = "independent-res"; 755141cc406Sopenharmony_ci o.title = "Independent x/y resolutions"; 756141cc406Sopenharmony_ci o.desc = "Enable independent controls for scanning resolution in x and y direction"; 757141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 758141cc406Sopenharmony_ci o.size = WSIZE; 759141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | 760141cc406Sopenharmony_ci SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; 761141cc406Sopenharmony_ci break; 762141cc406Sopenharmony_ci case CS3_OPTION_FRAME: 763141cc406Sopenharmony_ci o.name = "frame"; 764141cc406Sopenharmony_ci o.title = "Frame number"; 765141cc406Sopenharmony_ci o.desc = "Number of frame to be scanned, starting with 1"; 766141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 767141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 768141cc406Sopenharmony_ci o.size = WSIZE; 769141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 770141cc406Sopenharmony_ci if (s->n_frames <= 1) 771141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 772141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 773141cc406Sopenharmony_ci range = (SANE_Range *) 774141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 775141cc406Sopenharmony_ci if (!range) 776141cc406Sopenharmony_ci alloc_failed = 1; 777141cc406Sopenharmony_ci else { 778141cc406Sopenharmony_ci range->min = 1; 779141cc406Sopenharmony_ci range->max = s->n_frames; 780141cc406Sopenharmony_ci range->quant = 1; 781141cc406Sopenharmony_ci o.constraint.range = range; 782141cc406Sopenharmony_ci } 783141cc406Sopenharmony_ci break; 784141cc406Sopenharmony_ci case CS3_OPTION_FRAME_COUNT: 785141cc406Sopenharmony_ci o.name = "frame-count"; 786141cc406Sopenharmony_ci o.title = "Frame count"; 787141cc406Sopenharmony_ci o.desc = "Amount of frames to scan"; 788141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 789141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 790141cc406Sopenharmony_ci o.size = WSIZE; 791141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 792141cc406Sopenharmony_ci if (s->n_frames <= 1) 793141cc406Sopenharmony_ci o.cap |= SANE_CAP_INACTIVE; 794141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 795141cc406Sopenharmony_ci range = (SANE_Range *) 796141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 797141cc406Sopenharmony_ci if (!range) 798141cc406Sopenharmony_ci alloc_failed = 1; 799141cc406Sopenharmony_ci else { 800141cc406Sopenharmony_ci range->min = 1; 801141cc406Sopenharmony_ci range->max = s->n_frames - s->i_frame + 1; 802141cc406Sopenharmony_ci range->quant = 1; 803141cc406Sopenharmony_ci o.constraint.range = range; 804141cc406Sopenharmony_ci } 805141cc406Sopenharmony_ci break; 806141cc406Sopenharmony_ci case CS3_OPTION_SUBFRAME: 807141cc406Sopenharmony_ci o.name = "subframe"; 808141cc406Sopenharmony_ci o.title = "Frame shift"; 809141cc406Sopenharmony_ci o.desc = "Fine position within the selected frame"; 810141cc406Sopenharmony_ci o.type = SANE_TYPE_FIXED; 811141cc406Sopenharmony_ci o.unit = SANE_UNIT_MM; 812141cc406Sopenharmony_ci o.size = WSIZE; 813141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 814141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 815141cc406Sopenharmony_ci range = (SANE_Range *) 816141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 817141cc406Sopenharmony_ci if (!range) 818141cc406Sopenharmony_ci alloc_failed = 1; 819141cc406Sopenharmony_ci else { 820141cc406Sopenharmony_ci range->min = SANE_FIX(0.); 821141cc406Sopenharmony_ci range->max = 822141cc406Sopenharmony_ci SANE_FIX((s->boundaryy - 823141cc406Sopenharmony_ci 1) * s->unit_mm); 824141cc406Sopenharmony_ci range->quant = SANE_FIX(0.); 825141cc406Sopenharmony_ci o.constraint.range = range; 826141cc406Sopenharmony_ci } 827141cc406Sopenharmony_ci break; 828141cc406Sopenharmony_ci case CS3_OPTION_XMIN: 829141cc406Sopenharmony_ci o.name = "tl-x"; 830141cc406Sopenharmony_ci o.title = "Left x value of scan area"; 831141cc406Sopenharmony_ci o.desc = "Left x value of scan area"; 832141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 833141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 834141cc406Sopenharmony_ci o.size = WSIZE; 835141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 836141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 837141cc406Sopenharmony_ci if (!range) 838141cc406Sopenharmony_ci alloc_failed = 1; 839141cc406Sopenharmony_ci else { 840141cc406Sopenharmony_ci range = (SANE_Range *) 841141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 842141cc406Sopenharmony_ci range->min = 0; 843141cc406Sopenharmony_ci range->max = s->boundaryx - 1; 844141cc406Sopenharmony_ci range->quant = 1; 845141cc406Sopenharmony_ci o.constraint.range = range; 846141cc406Sopenharmony_ci } 847141cc406Sopenharmony_ci break; 848141cc406Sopenharmony_ci case CS3_OPTION_XMAX: 849141cc406Sopenharmony_ci o.name = "br-x"; 850141cc406Sopenharmony_ci o.title = "Right x value of scan area"; 851141cc406Sopenharmony_ci o.desc = "Right x value of scan area"; 852141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 853141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 854141cc406Sopenharmony_ci o.size = WSIZE; 855141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 856141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 857141cc406Sopenharmony_ci range = (SANE_Range *) 858141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 859141cc406Sopenharmony_ci if (!range) 860141cc406Sopenharmony_ci alloc_failed = 1; 861141cc406Sopenharmony_ci else { 862141cc406Sopenharmony_ci range->min = 0; 863141cc406Sopenharmony_ci range->max = s->boundaryx - 1; 864141cc406Sopenharmony_ci range->quant = 1; 865141cc406Sopenharmony_ci o.constraint.range = range; 866141cc406Sopenharmony_ci } 867141cc406Sopenharmony_ci break; 868141cc406Sopenharmony_ci case CS3_OPTION_YMIN: 869141cc406Sopenharmony_ci o.name = "tl-y"; 870141cc406Sopenharmony_ci o.title = "Top y value of scan area"; 871141cc406Sopenharmony_ci o.desc = "Top y value of scan area"; 872141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 873141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 874141cc406Sopenharmony_ci o.size = WSIZE; 875141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 876141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 877141cc406Sopenharmony_ci range = (SANE_Range *) 878141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 879141cc406Sopenharmony_ci if (!range) 880141cc406Sopenharmony_ci alloc_failed = 1; 881141cc406Sopenharmony_ci else { 882141cc406Sopenharmony_ci range->min = 0; 883141cc406Sopenharmony_ci range->max = s->boundaryy - 1; 884141cc406Sopenharmony_ci range->quant = 1; 885141cc406Sopenharmony_ci o.constraint.range = range; 886141cc406Sopenharmony_ci } 887141cc406Sopenharmony_ci break; 888141cc406Sopenharmony_ci case CS3_OPTION_YMAX: 889141cc406Sopenharmony_ci o.name = "br-y"; 890141cc406Sopenharmony_ci o.title = "Bottom y value of scan area"; 891141cc406Sopenharmony_ci o.desc = "Bottom y value of scan area"; 892141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 893141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 894141cc406Sopenharmony_ci o.size = WSIZE; 895141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 896141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 897141cc406Sopenharmony_ci range = (SANE_Range *) 898141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 899141cc406Sopenharmony_ci if (!range) 900141cc406Sopenharmony_ci alloc_failed = 1; 901141cc406Sopenharmony_ci else { 902141cc406Sopenharmony_ci range->min = 0; 903141cc406Sopenharmony_ci range->max = s->boundaryy - 1; 904141cc406Sopenharmony_ci range->quant = 1; 905141cc406Sopenharmony_ci o.constraint.range = range; 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci break; 908141cc406Sopenharmony_ci case CS3_OPTION_FOCUS_ON_CENTRE: 909141cc406Sopenharmony_ci o.name = "focus-on-centre"; 910141cc406Sopenharmony_ci o.title = "Use centre of scan area as AF point"; 911141cc406Sopenharmony_ci o.desc = "Use centre of scan area as AF point instead of manual AF point selection"; 912141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 913141cc406Sopenharmony_ci o.size = WSIZE; 914141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 915141cc406Sopenharmony_ci break; 916141cc406Sopenharmony_ci case CS3_OPTION_FOCUS: 917141cc406Sopenharmony_ci o.name = SANE_NAME_FOCUS; 918141cc406Sopenharmony_ci o.title = SANE_TITLE_FOCUS; 919141cc406Sopenharmony_ci o.desc = SANE_DESC_FOCUS; 920141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 921141cc406Sopenharmony_ci o.unit = SANE_UNIT_NONE; 922141cc406Sopenharmony_ci o.size = WSIZE; 923141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 924141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 925141cc406Sopenharmony_ci range = (SANE_Range *) 926141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 927141cc406Sopenharmony_ci if (!range) 928141cc406Sopenharmony_ci alloc_failed = 1; 929141cc406Sopenharmony_ci else { 930141cc406Sopenharmony_ci range->min = s->focus_min; 931141cc406Sopenharmony_ci range->max = s->focus_max; 932141cc406Sopenharmony_ci range->quant = 1; 933141cc406Sopenharmony_ci o.constraint.range = range; 934141cc406Sopenharmony_ci } 935141cc406Sopenharmony_ci break; 936141cc406Sopenharmony_ci case CS3_OPTION_AUTOFOCUS: 937141cc406Sopenharmony_ci o.name = SANE_NAME_AUTOFOCUS; 938141cc406Sopenharmony_ci o.title = SANE_TITLE_AUTOFOCUS; 939141cc406Sopenharmony_ci o.desc = SANE_DESC_AUTOFOCUS; 940141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 941141cc406Sopenharmony_ci o.size = WSIZE; 942141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 943141cc406Sopenharmony_ci break; 944141cc406Sopenharmony_ci case CS3_OPTION_FOCUSX: 945141cc406Sopenharmony_ci o.name = "focusx"; 946141cc406Sopenharmony_ci o.title = "X coordinate of AF point"; 947141cc406Sopenharmony_ci o.desc = "X coordinate of AF point"; 948141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 949141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 950141cc406Sopenharmony_ci o.size = WSIZE; 951141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | 952141cc406Sopenharmony_ci SANE_CAP_INACTIVE; 953141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 954141cc406Sopenharmony_ci range = (SANE_Range *) 955141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 956141cc406Sopenharmony_ci if (!range) 957141cc406Sopenharmony_ci alloc_failed = 1; 958141cc406Sopenharmony_ci else { 959141cc406Sopenharmony_ci range->min = 0; 960141cc406Sopenharmony_ci range->max = s->boundaryx - 1; 961141cc406Sopenharmony_ci range->quant = 1; 962141cc406Sopenharmony_ci o.constraint.range = range; 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci break; 965141cc406Sopenharmony_ci case CS3_OPTION_FOCUSY: 966141cc406Sopenharmony_ci o.name = "focusy"; 967141cc406Sopenharmony_ci o.title = "Y coordinate of AF point"; 968141cc406Sopenharmony_ci o.desc = "Y coordinate of AF point"; 969141cc406Sopenharmony_ci o.type = SANE_TYPE_INT; 970141cc406Sopenharmony_ci o.unit = SANE_UNIT_PIXEL; 971141cc406Sopenharmony_ci o.size = WSIZE; 972141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | 973141cc406Sopenharmony_ci SANE_CAP_INACTIVE; 974141cc406Sopenharmony_ci o.constraint_type = SANE_CONSTRAINT_RANGE; 975141cc406Sopenharmony_ci range = (SANE_Range *) 976141cc406Sopenharmony_ci cs3_xmalloc(sizeof(SANE_Range)); 977141cc406Sopenharmony_ci if (!range) 978141cc406Sopenharmony_ci alloc_failed = 1; 979141cc406Sopenharmony_ci else { 980141cc406Sopenharmony_ci range->min = 0; 981141cc406Sopenharmony_ci range->max = s->boundaryy - 1; 982141cc406Sopenharmony_ci range->quant = 1; 983141cc406Sopenharmony_ci o.constraint.range = range; 984141cc406Sopenharmony_ci } 985141cc406Sopenharmony_ci break; 986141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE: 987141cc406Sopenharmony_ci o.name = "ae"; 988141cc406Sopenharmony_ci o.title = "Auto-exposure"; 989141cc406Sopenharmony_ci o.desc = "Perform auto-exposure before scan"; 990141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 991141cc406Sopenharmony_ci o.size = WSIZE; 992141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 993141cc406Sopenharmony_ci break; 994141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE_WB: 995141cc406Sopenharmony_ci o.name = "ae-wb"; 996141cc406Sopenharmony_ci o.title = "Auto-exposure with white balance"; 997141cc406Sopenharmony_ci o.desc = "Perform auto-exposure with white balance before scan"; 998141cc406Sopenharmony_ci o.type = SANE_TYPE_BOOL; 999141cc406Sopenharmony_ci o.size = WSIZE; 1000141cc406Sopenharmony_ci o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1001141cc406Sopenharmony_ci break; 1002141cc406Sopenharmony_ci default: 1003141cc406Sopenharmony_ci DBG(1, "BUG: sane_open(): Unknown option number: %d\n", i_option); 1004141cc406Sopenharmony_ci break; 1005141cc406Sopenharmony_ci } 1006141cc406Sopenharmony_ci s->option_list[i_option] = o; 1007141cc406Sopenharmony_ci } 1008141cc406Sopenharmony_ci 1009141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1010141cc406Sopenharmony_ci s->preview = SANE_FALSE; 1011141cc406Sopenharmony_ci s->negative = SANE_FALSE; 1012141cc406Sopenharmony_ci s->autoload = SANE_FALSE; 1013141cc406Sopenharmony_ci s->infrared = SANE_FALSE; 1014141cc406Sopenharmony_ci s->ae = SANE_FALSE; 1015141cc406Sopenharmony_ci s->aewb = SANE_FALSE; 1016141cc406Sopenharmony_ci s->samples_per_scan = 1; 1017141cc406Sopenharmony_ci s->depth = 8; 1018141cc406Sopenharmony_ci s->i_frame = 1; 1019141cc406Sopenharmony_ci s->frame_count = 1; 1020141cc406Sopenharmony_ci s->subframe = 0.; 1021141cc406Sopenharmony_ci s->res = s->resx = s->resx_max; 1022141cc406Sopenharmony_ci s->resy = s->resy_max; 1023141cc406Sopenharmony_ci s->res_independent = SANE_FALSE; 1024141cc406Sopenharmony_ci s->res_preview = s->resx_max / 10; 1025141cc406Sopenharmony_ci if (s->res_preview < s->resx_min) 1026141cc406Sopenharmony_ci s->res_preview = s->resx_min; 1027141cc406Sopenharmony_ci s->xmin = 0; 1028141cc406Sopenharmony_ci s->xmax = s->boundaryx - 1; 1029141cc406Sopenharmony_ci s->ymin = 0; 1030141cc406Sopenharmony_ci s->ymax = s->boundaryy - 1; 1031141cc406Sopenharmony_ci s->focus_on_centre = SANE_TRUE; 1032141cc406Sopenharmony_ci s->focus = 0; 1033141cc406Sopenharmony_ci s->focusx = 0; 1034141cc406Sopenharmony_ci s->focusy = 0; 1035141cc406Sopenharmony_ci s->exposure = 1.; 1036141cc406Sopenharmony_ci s->exposure_r = 1200.; 1037141cc406Sopenharmony_ci s->exposure_g = 1200.; 1038141cc406Sopenharmony_ci s->exposure_b = 1000.; 1039141cc406Sopenharmony_ci s->line_buf = NULL; 1040141cc406Sopenharmony_ci s->n_line_buf = 0; 1041141cc406Sopenharmony_ci 1042141cc406Sopenharmony_ci if (alloc_failed) { 1043141cc406Sopenharmony_ci cs3_close(s); 1044141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1045141cc406Sopenharmony_ci } 1046141cc406Sopenharmony_ci 1047141cc406Sopenharmony_ci return cs3_reserve_unit(s); 1048141cc406Sopenharmony_ci} 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_civoid 1051141cc406Sopenharmony_cisane_close(SANE_Handle h) 1052141cc406Sopenharmony_ci{ 1053141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 1056141cc406Sopenharmony_ci 1057141cc406Sopenharmony_ci cs3_release_unit(s); 1058141cc406Sopenharmony_ci cs3_close(s); 1059141cc406Sopenharmony_ci} 1060141cc406Sopenharmony_ci 1061141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1062141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle h, SANE_Int n) 1063141cc406Sopenharmony_ci{ 1064141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1065141cc406Sopenharmony_ci 1066141cc406Sopenharmony_ci DBG(24, "%s, option %i\n", __func__, n); 1067141cc406Sopenharmony_ci 1068141cc406Sopenharmony_ci if ((n >= 0) && (n < CS3_N_OPTIONS)) 1069141cc406Sopenharmony_ci return &s->option_list[n]; 1070141cc406Sopenharmony_ci else 1071141cc406Sopenharmony_ci return NULL; 1072141cc406Sopenharmony_ci} 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ciSANE_Status 1075141cc406Sopenharmony_cisane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, 1076141cc406Sopenharmony_ci SANE_Int * i) 1077141cc406Sopenharmony_ci{ 1078141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1079141cc406Sopenharmony_ci SANE_Int flags = 0; 1080141cc406Sopenharmony_ci cs3_pixel_t pixel; 1081141cc406Sopenharmony_ci SANE_Option_Descriptor o = s->option_list[n]; 1082141cc406Sopenharmony_ci 1083141cc406Sopenharmony_ci DBG(24, "%s, option %i, action %i.\n", __func__, n, a); 1084141cc406Sopenharmony_ci 1085141cc406Sopenharmony_ci switch (a) { 1086141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 1087141cc406Sopenharmony_ci 1088141cc406Sopenharmony_ci switch (n) { 1089141cc406Sopenharmony_ci case CS3_OPTION_NUM: 1090141cc406Sopenharmony_ci *(SANE_Word *) v = CS3_N_OPTIONS; 1091141cc406Sopenharmony_ci break; 1092141cc406Sopenharmony_ci case CS3_OPTION_NEGATIVE: 1093141cc406Sopenharmony_ci *(SANE_Word *) v = s->negative; 1094141cc406Sopenharmony_ci break; 1095141cc406Sopenharmony_ci case CS3_OPTION_INFRARED: 1096141cc406Sopenharmony_ci *(SANE_Word *) v = s->infrared; 1097141cc406Sopenharmony_ci break; 1098141cc406Sopenharmony_ci case CS3_OPTION_SAMPLES_PER_SCAN: 1099141cc406Sopenharmony_ci *(SANE_Word *) v = s->samples_per_scan; 1100141cc406Sopenharmony_ci break; 1101141cc406Sopenharmony_ci case CS3_OPTION_DEPTH: 1102141cc406Sopenharmony_ci *(SANE_Word *) v = s->depth; 1103141cc406Sopenharmony_ci break; 1104141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW: 1105141cc406Sopenharmony_ci *(SANE_Word *) v = s->preview; 1106141cc406Sopenharmony_ci break; 1107141cc406Sopenharmony_ci case CS3_OPTION_AUTOLOAD: 1108141cc406Sopenharmony_ci *(SANE_Word *) v = s->autoload; 1109141cc406Sopenharmony_ci break; 1110141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE: 1111141cc406Sopenharmony_ci *(SANE_Word *) v = SANE_FIX(s->exposure); 1112141cc406Sopenharmony_ci break; 1113141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_R: 1114141cc406Sopenharmony_ci *(SANE_Word *) v = SANE_FIX(s->exposure_r); 1115141cc406Sopenharmony_ci break; 1116141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_G: 1117141cc406Sopenharmony_ci *(SANE_Word *) v = SANE_FIX(s->exposure_g); 1118141cc406Sopenharmony_ci break; 1119141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_B: 1120141cc406Sopenharmony_ci *(SANE_Word *) v = SANE_FIX(s->exposure_b); 1121141cc406Sopenharmony_ci break; 1122141cc406Sopenharmony_ci case CS3_OPTION_LUT_R: 1123141cc406Sopenharmony_ci if (!(s->lut_r)) 1124141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1125141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1126141cc406Sopenharmony_ci ((SANE_Word *) v)[pixel] = s->lut_r[pixel]; 1127141cc406Sopenharmony_ci break; 1128141cc406Sopenharmony_ci case CS3_OPTION_LUT_G: 1129141cc406Sopenharmony_ci if (!(s->lut_g)) 1130141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1131141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1132141cc406Sopenharmony_ci ((SANE_Word *) v)[pixel] = s->lut_g[pixel]; 1133141cc406Sopenharmony_ci break; 1134141cc406Sopenharmony_ci case CS3_OPTION_LUT_B: 1135141cc406Sopenharmony_ci if (!(s->lut_b)) 1136141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1137141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1138141cc406Sopenharmony_ci ((SANE_Word *) v)[pixel] = s->lut_b[pixel]; 1139141cc406Sopenharmony_ci break; 1140141cc406Sopenharmony_ci case CS3_OPTION_EJECT: 1141141cc406Sopenharmony_ci break; 1142141cc406Sopenharmony_ci case CS3_OPTION_LOAD: 1143141cc406Sopenharmony_ci break; 1144141cc406Sopenharmony_ci case CS3_OPTION_RESET: 1145141cc406Sopenharmony_ci break; 1146141cc406Sopenharmony_ci case CS3_OPTION_FRAME: 1147141cc406Sopenharmony_ci *(SANE_Word *) v = s->i_frame; 1148141cc406Sopenharmony_ci break; 1149141cc406Sopenharmony_ci case CS3_OPTION_FRAME_COUNT: 1150141cc406Sopenharmony_ci *(SANE_Word *) v = s->frame_count; 1151141cc406Sopenharmony_ci break; 1152141cc406Sopenharmony_ci case CS3_OPTION_SUBFRAME: 1153141cc406Sopenharmony_ci *(SANE_Word *) v = SANE_FIX(s->subframe); 1154141cc406Sopenharmony_ci break; 1155141cc406Sopenharmony_ci case CS3_OPTION_RES: 1156141cc406Sopenharmony_ci *(SANE_Word *) v = s->res; 1157141cc406Sopenharmony_ci break; 1158141cc406Sopenharmony_ci case CS3_OPTION_RESX: 1159141cc406Sopenharmony_ci *(SANE_Word *) v = s->resx; 1160141cc406Sopenharmony_ci break; 1161141cc406Sopenharmony_ci case CS3_OPTION_RESY: 1162141cc406Sopenharmony_ci *(SANE_Word *) v = s->resy; 1163141cc406Sopenharmony_ci break; 1164141cc406Sopenharmony_ci case CS3_OPTION_RES_INDEPENDENT: 1165141cc406Sopenharmony_ci *(SANE_Word *) v = s->res_independent; 1166141cc406Sopenharmony_ci break; 1167141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW_RESOLUTION: 1168141cc406Sopenharmony_ci *(SANE_Word *) v = s->res_preview; 1169141cc406Sopenharmony_ci break; 1170141cc406Sopenharmony_ci case CS3_OPTION_XMIN: 1171141cc406Sopenharmony_ci *(SANE_Word *) v = s->xmin; 1172141cc406Sopenharmony_ci break; 1173141cc406Sopenharmony_ci case CS3_OPTION_XMAX: 1174141cc406Sopenharmony_ci *(SANE_Word *) v = s->xmax; 1175141cc406Sopenharmony_ci break; 1176141cc406Sopenharmony_ci case CS3_OPTION_YMIN: 1177141cc406Sopenharmony_ci *(SANE_Word *) v = s->ymin; 1178141cc406Sopenharmony_ci break; 1179141cc406Sopenharmony_ci case CS3_OPTION_YMAX: 1180141cc406Sopenharmony_ci *(SANE_Word *) v = s->ymax; 1181141cc406Sopenharmony_ci break; 1182141cc406Sopenharmony_ci case CS3_OPTION_FOCUS_ON_CENTRE: 1183141cc406Sopenharmony_ci *(SANE_Word *) v = s->focus_on_centre; 1184141cc406Sopenharmony_ci break; 1185141cc406Sopenharmony_ci case CS3_OPTION_FOCUS: 1186141cc406Sopenharmony_ci *(SANE_Word *) v = s->focus; 1187141cc406Sopenharmony_ci break; 1188141cc406Sopenharmony_ci case CS3_OPTION_AUTOFOCUS: 1189141cc406Sopenharmony_ci *(SANE_Word *) v = s->autofocus; 1190141cc406Sopenharmony_ci break; 1191141cc406Sopenharmony_ci case CS3_OPTION_FOCUSX: 1192141cc406Sopenharmony_ci *(SANE_Word *) v = s->focusx; 1193141cc406Sopenharmony_ci break; 1194141cc406Sopenharmony_ci case CS3_OPTION_FOCUSY: 1195141cc406Sopenharmony_ci *(SANE_Word *) v = s->focusy; 1196141cc406Sopenharmony_ci break; 1197141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE: 1198141cc406Sopenharmony_ci *(SANE_Word *) v = s->ae; 1199141cc406Sopenharmony_ci break; 1200141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE_WB: 1201141cc406Sopenharmony_ci *(SANE_Word *) v = s->aewb; 1202141cc406Sopenharmony_ci break; 1203141cc406Sopenharmony_ci default: 1204141cc406Sopenharmony_ci DBG(4, "%s: Unknown option (bug?).\n", __func__); 1205141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1206141cc406Sopenharmony_ci } 1207141cc406Sopenharmony_ci break; 1208141cc406Sopenharmony_ci 1209141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 1210141cc406Sopenharmony_ci if (s->scanning) 1211141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1212141cc406Sopenharmony_ci /* XXX do this for all elements of arrays */ 1213141cc406Sopenharmony_ci switch (o.type) { 1214141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 1215141cc406Sopenharmony_ci if ((*(SANE_Word *) v != SANE_TRUE) 1216141cc406Sopenharmony_ci && (*(SANE_Word *) v != SANE_FALSE)) 1217141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1218141cc406Sopenharmony_ci break; 1219141cc406Sopenharmony_ci case SANE_TYPE_INT: 1220141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 1221141cc406Sopenharmony_ci switch (o.constraint_type) { 1222141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 1223141cc406Sopenharmony_ci if (*(SANE_Word *) v < 1224141cc406Sopenharmony_ci o.constraint.range->min) { 1225141cc406Sopenharmony_ci *(SANE_Word *) v = 1226141cc406Sopenharmony_ci o.constraint.range->min; 1227141cc406Sopenharmony_ci flags |= SANE_INFO_INEXACT; 1228141cc406Sopenharmony_ci } else if (*(SANE_Word *) v > 1229141cc406Sopenharmony_ci o.constraint.range->max) { 1230141cc406Sopenharmony_ci *(SANE_Word *) v = 1231141cc406Sopenharmony_ci o.constraint.range->max; 1232141cc406Sopenharmony_ci flags |= SANE_INFO_INEXACT; 1233141cc406Sopenharmony_ci } 1234141cc406Sopenharmony_ci break; 1235141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 1236141cc406Sopenharmony_ci break; 1237141cc406Sopenharmony_ci default: 1238141cc406Sopenharmony_ci break; 1239141cc406Sopenharmony_ci } 1240141cc406Sopenharmony_ci break; 1241141cc406Sopenharmony_ci case SANE_TYPE_STRING: 1242141cc406Sopenharmony_ci break; 1243141cc406Sopenharmony_ci case SANE_TYPE_BUTTON: 1244141cc406Sopenharmony_ci break; 1245141cc406Sopenharmony_ci case SANE_TYPE_GROUP: 1246141cc406Sopenharmony_ci break; 1247141cc406Sopenharmony_ci } 1248141cc406Sopenharmony_ci switch (n) { 1249141cc406Sopenharmony_ci case CS3_OPTION_NUM: 1250141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1251141cc406Sopenharmony_ci break; 1252141cc406Sopenharmony_ci case CS3_OPTION_NEGATIVE: 1253141cc406Sopenharmony_ci s->negative = *(SANE_Word *) v; 1254141cc406Sopenharmony_ci break; 1255141cc406Sopenharmony_ci case CS3_OPTION_INFRARED: 1256141cc406Sopenharmony_ci s->infrared = *(SANE_Word *) v; 1257141cc406Sopenharmony_ci /* flags |= SANE_INFO_RELOAD_PARAMS; XXX */ 1258141cc406Sopenharmony_ci break; 1259141cc406Sopenharmony_ci case CS3_OPTION_SAMPLES_PER_SCAN: 1260141cc406Sopenharmony_ci s->samples_per_scan = *(SANE_Word *) v; 1261141cc406Sopenharmony_ci break; 1262141cc406Sopenharmony_ci case CS3_OPTION_DEPTH: 1263141cc406Sopenharmony_ci if (*(SANE_Word *) v > s->maxbits) 1264141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1265141cc406Sopenharmony_ci 1266141cc406Sopenharmony_ci s->depth = *(SANE_Word *) v; 1267141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1268141cc406Sopenharmony_ci break; 1269141cc406Sopenharmony_ci 1270141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW: 1271141cc406Sopenharmony_ci s->preview = *(SANE_Word *) v; 1272141cc406Sopenharmony_ci break; 1273141cc406Sopenharmony_ci 1274141cc406Sopenharmony_ci case CS3_OPTION_AUTOLOAD: 1275141cc406Sopenharmony_ci s->autoload = *(SANE_Word *) v; 1276141cc406Sopenharmony_ci break; 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE: 1279141cc406Sopenharmony_ci s->exposure = SANE_UNFIX(*(SANE_Word *) v); 1280141cc406Sopenharmony_ci break; 1281141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_R: 1282141cc406Sopenharmony_ci s->exposure_r = SANE_UNFIX(*(SANE_Word *) v); 1283141cc406Sopenharmony_ci break; 1284141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_G: 1285141cc406Sopenharmony_ci s->exposure_g = SANE_UNFIX(*(SANE_Word *) v); 1286141cc406Sopenharmony_ci break; 1287141cc406Sopenharmony_ci case CS3_OPTION_EXPOSURE_B: 1288141cc406Sopenharmony_ci s->exposure_b = SANE_UNFIX(*(SANE_Word *) v); 1289141cc406Sopenharmony_ci break; 1290141cc406Sopenharmony_ci case CS3_OPTION_LUT_R: 1291141cc406Sopenharmony_ci if (!(s->lut_r)) 1292141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1293141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1294141cc406Sopenharmony_ci s->lut_r[pixel] = ((SANE_Word *) v)[pixel]; 1295141cc406Sopenharmony_ci break; 1296141cc406Sopenharmony_ci case CS3_OPTION_LUT_G: 1297141cc406Sopenharmony_ci if (!(s->lut_g)) 1298141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1299141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1300141cc406Sopenharmony_ci s->lut_g[pixel] = ((SANE_Word *) v)[pixel]; 1301141cc406Sopenharmony_ci break; 1302141cc406Sopenharmony_ci case CS3_OPTION_LUT_B: 1303141cc406Sopenharmony_ci if (!(s->lut_b)) 1304141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1305141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) 1306141cc406Sopenharmony_ci s->lut_b[pixel] = ((SANE_Word *) v)[pixel]; 1307141cc406Sopenharmony_ci break; 1308141cc406Sopenharmony_ci case CS3_OPTION_LOAD: 1309141cc406Sopenharmony_ci cs3_load(s); 1310141cc406Sopenharmony_ci break; 1311141cc406Sopenharmony_ci case CS3_OPTION_EJECT: 1312141cc406Sopenharmony_ci cs3_eject(s); 1313141cc406Sopenharmony_ci break; 1314141cc406Sopenharmony_ci case CS3_OPTION_RESET: 1315141cc406Sopenharmony_ci cs3_reset(s); 1316141cc406Sopenharmony_ci break; 1317141cc406Sopenharmony_ci case CS3_OPTION_FRAME: 1318141cc406Sopenharmony_ci s->i_frame = *(SANE_Word *) v; 1319141cc406Sopenharmony_ci break; 1320141cc406Sopenharmony_ci 1321141cc406Sopenharmony_ci case CS3_OPTION_FRAME_COUNT: 1322141cc406Sopenharmony_ci if (*(SANE_Word *) v > (s->n_frames - s->i_frame + 1)) 1323141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1324141cc406Sopenharmony_ci s->frame_count = *(SANE_Word *) v; 1325141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1326141cc406Sopenharmony_ci break; 1327141cc406Sopenharmony_ci 1328141cc406Sopenharmony_ci case CS3_OPTION_SUBFRAME: 1329141cc406Sopenharmony_ci s->subframe = SANE_UNFIX(*(SANE_Word *) v); 1330141cc406Sopenharmony_ci break; 1331141cc406Sopenharmony_ci case CS3_OPTION_RES: 1332141cc406Sopenharmony_ci s->res = *(SANE_Word *) v; 1333141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1334141cc406Sopenharmony_ci break; 1335141cc406Sopenharmony_ci case CS3_OPTION_RESX: 1336141cc406Sopenharmony_ci s->resx = *(SANE_Word *) v; 1337141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1338141cc406Sopenharmony_ci break; 1339141cc406Sopenharmony_ci case CS3_OPTION_RESY: 1340141cc406Sopenharmony_ci s->resy = *(SANE_Word *) v; 1341141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1342141cc406Sopenharmony_ci break; 1343141cc406Sopenharmony_ci case CS3_OPTION_RES_INDEPENDENT: 1344141cc406Sopenharmony_ci s->res_independent = *(SANE_Word *) v; 1345141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1346141cc406Sopenharmony_ci break; 1347141cc406Sopenharmony_ci case CS3_OPTION_PREVIEW_RESOLUTION: 1348141cc406Sopenharmony_ci s->res_preview = *(SANE_Word *) v; 1349141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1350141cc406Sopenharmony_ci break; 1351141cc406Sopenharmony_ci case CS3_OPTION_XMIN: 1352141cc406Sopenharmony_ci s->xmin = *(SANE_Word *) v; 1353141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1354141cc406Sopenharmony_ci break; 1355141cc406Sopenharmony_ci case CS3_OPTION_XMAX: 1356141cc406Sopenharmony_ci s->xmax = *(SANE_Word *) v; 1357141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1358141cc406Sopenharmony_ci break; 1359141cc406Sopenharmony_ci case CS3_OPTION_YMIN: 1360141cc406Sopenharmony_ci s->ymin = *(SANE_Word *) v; 1361141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1362141cc406Sopenharmony_ci break; 1363141cc406Sopenharmony_ci case CS3_OPTION_YMAX: 1364141cc406Sopenharmony_ci s->ymax = *(SANE_Word *) v; 1365141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_PARAMS; 1366141cc406Sopenharmony_ci break; 1367141cc406Sopenharmony_ci case CS3_OPTION_FOCUS_ON_CENTRE: 1368141cc406Sopenharmony_ci s->focus_on_centre = *(SANE_Word *) v; 1369141cc406Sopenharmony_ci if (s->focus_on_centre) { 1370141cc406Sopenharmony_ci s->option_list[CS3_OPTION_FOCUSX].cap |= 1371141cc406Sopenharmony_ci SANE_CAP_INACTIVE; 1372141cc406Sopenharmony_ci s->option_list[CS3_OPTION_FOCUSY].cap |= 1373141cc406Sopenharmony_ci SANE_CAP_INACTIVE; 1374141cc406Sopenharmony_ci } else { 1375141cc406Sopenharmony_ci s->option_list[CS3_OPTION_FOCUSX].cap &= 1376141cc406Sopenharmony_ci ~SANE_CAP_INACTIVE; 1377141cc406Sopenharmony_ci s->option_list[CS3_OPTION_FOCUSY].cap &= 1378141cc406Sopenharmony_ci ~SANE_CAP_INACTIVE; 1379141cc406Sopenharmony_ci } 1380141cc406Sopenharmony_ci flags |= SANE_INFO_RELOAD_OPTIONS; 1381141cc406Sopenharmony_ci break; 1382141cc406Sopenharmony_ci case CS3_OPTION_FOCUS: 1383141cc406Sopenharmony_ci s->focus = *(SANE_Word *) v; 1384141cc406Sopenharmony_ci break; 1385141cc406Sopenharmony_ci case CS3_OPTION_AUTOFOCUS: 1386141cc406Sopenharmony_ci s->autofocus = *(SANE_Word *) v; 1387141cc406Sopenharmony_ci break; 1388141cc406Sopenharmony_ci case CS3_OPTION_FOCUSX: 1389141cc406Sopenharmony_ci s->focusx = *(SANE_Word *) v; 1390141cc406Sopenharmony_ci break; 1391141cc406Sopenharmony_ci case CS3_OPTION_FOCUSY: 1392141cc406Sopenharmony_ci s->focusy = *(SANE_Word *) v; 1393141cc406Sopenharmony_ci break; 1394141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE: 1395141cc406Sopenharmony_ci s->ae = *(SANE_Word *) v; 1396141cc406Sopenharmony_ci break; 1397141cc406Sopenharmony_ci case CS3_OPTION_SCAN_AE_WB: 1398141cc406Sopenharmony_ci s->aewb = *(SANE_Word *) v; 1399141cc406Sopenharmony_ci break; 1400141cc406Sopenharmony_ci default: 1401141cc406Sopenharmony_ci DBG(4, 1402141cc406Sopenharmony_ci "Error: sane_control_option(): Unknown option number (bug?).\n"); 1403141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1404141cc406Sopenharmony_ci break; 1405141cc406Sopenharmony_ci } 1406141cc406Sopenharmony_ci break; 1407141cc406Sopenharmony_ci 1408141cc406Sopenharmony_ci default: 1409141cc406Sopenharmony_ci DBG(1, 1410141cc406Sopenharmony_ci "BUG: sane_control_option(): Unknown action number.\n"); 1411141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1412141cc406Sopenharmony_ci break; 1413141cc406Sopenharmony_ci } 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_ci if (i) 1416141cc406Sopenharmony_ci *i = flags; 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1419141cc406Sopenharmony_ci} 1420141cc406Sopenharmony_ci 1421141cc406Sopenharmony_ciSANE_Status 1422141cc406Sopenharmony_cisane_get_parameters(SANE_Handle h, SANE_Parameters * p) 1423141cc406Sopenharmony_ci{ 1424141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1425141cc406Sopenharmony_ci SANE_Status status; 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 1428141cc406Sopenharmony_ci 1429141cc406Sopenharmony_ci if (!s->scanning) { /* only recalculate when not scanning */ 1430141cc406Sopenharmony_ci status = cs3_convert_options(s); 1431141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1432141cc406Sopenharmony_ci return status; 1433141cc406Sopenharmony_ci } 1434141cc406Sopenharmony_ci 1435141cc406Sopenharmony_ci p->bytes_per_line = 1436141cc406Sopenharmony_ci s->n_colors * s->logical_width * s->bytes_per_pixel; 1437141cc406Sopenharmony_ci 1438141cc406Sopenharmony_ci#ifdef SANE_FRAME_RGBI 1439141cc406Sopenharmony_ci if (s->infrared) { 1440141cc406Sopenharmony_ci p->format = SANE_FRAME_RGBI; 1441141cc406Sopenharmony_ci 1442141cc406Sopenharmony_ci } else { 1443141cc406Sopenharmony_ci#endif 1444141cc406Sopenharmony_ci p->format = SANE_FRAME_RGB; /* XXXXXXXX CCCCCCCCCC */ 1445141cc406Sopenharmony_ci#ifdef SANE_FRAME_RGBI 1446141cc406Sopenharmony_ci } 1447141cc406Sopenharmony_ci#endif 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci p->last_frame = SANE_TRUE; 1450141cc406Sopenharmony_ci p->lines = s->logical_height; 1451141cc406Sopenharmony_ci p->depth = 8 * s->bytes_per_pixel; 1452141cc406Sopenharmony_ci p->pixels_per_line = s->logical_width; 1453141cc406Sopenharmony_ci 1454141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1455141cc406Sopenharmony_ci} 1456141cc406Sopenharmony_ci 1457141cc406Sopenharmony_ciSANE_Status 1458141cc406Sopenharmony_cisane_start(SANE_Handle h) 1459141cc406Sopenharmony_ci{ 1460141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1461141cc406Sopenharmony_ci SANE_Status status; 1462141cc406Sopenharmony_ci 1463141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 1464141cc406Sopenharmony_ci 1465141cc406Sopenharmony_ci if (s->scanning) 1466141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1467141cc406Sopenharmony_ci 1468141cc406Sopenharmony_ci if (s->n_frames > 1 && s->frame_count == 0) { 1469141cc406Sopenharmony_ci DBG(4, "%s: no more frames\n", __func__); 1470141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 1471141cc406Sopenharmony_ci } 1472141cc406Sopenharmony_ci 1473141cc406Sopenharmony_ci if (s->n_frames > 1) { 1474141cc406Sopenharmony_ci DBG(4, "%s: scanning frame at position %d, %d to go\n", 1475141cc406Sopenharmony_ci __func__, s->i_frame, s->frame_count); 1476141cc406Sopenharmony_ci } 1477141cc406Sopenharmony_ci 1478141cc406Sopenharmony_ci status = cs3_convert_options(s); 1479141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1480141cc406Sopenharmony_ci return status; 1481141cc406Sopenharmony_ci 1482141cc406Sopenharmony_ci s->i_line_buf = 0; 1483141cc406Sopenharmony_ci s->xfer_position = 0; 1484141cc406Sopenharmony_ci 1485141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 1486141cc406Sopenharmony_ci 1487141cc406Sopenharmony_ci /* load if appropriate */ 1488141cc406Sopenharmony_ci if (s->autoload) { 1489141cc406Sopenharmony_ci status = cs3_load(s); 1490141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1491141cc406Sopenharmony_ci return status; 1492141cc406Sopenharmony_ci } 1493141cc406Sopenharmony_ci 1494141cc406Sopenharmony_ci /* check for documents */ 1495141cc406Sopenharmony_ci status = cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 1496141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1497141cc406Sopenharmony_ci return status; 1498141cc406Sopenharmony_ci if (s->status & CS3_STATUS_NO_DOCS) 1499141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 1500141cc406Sopenharmony_ci 1501141cc406Sopenharmony_ci if (s->autofocus) { 1502141cc406Sopenharmony_ci status = cs3_autofocus(s); 1503141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1504141cc406Sopenharmony_ci return status; 1505141cc406Sopenharmony_ci } 1506141cc406Sopenharmony_ci 1507141cc406Sopenharmony_ci if (s->aewb) { 1508141cc406Sopenharmony_ci status = cs3_autoexposure(s, 1); 1509141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1510141cc406Sopenharmony_ci return status; 1511141cc406Sopenharmony_ci } else if (s->ae) { 1512141cc406Sopenharmony_ci status = cs3_autoexposure(s, 0); 1513141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1514141cc406Sopenharmony_ci return status; 1515141cc406Sopenharmony_ci } 1516141cc406Sopenharmony_ci 1517141cc406Sopenharmony_ci return cs3_scan(s, CS3_SCAN_NORMAL); 1518141cc406Sopenharmony_ci} 1519141cc406Sopenharmony_ci 1520141cc406Sopenharmony_ciSANE_Status 1521141cc406Sopenharmony_cisane_read(SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) 1522141cc406Sopenharmony_ci{ 1523141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1524141cc406Sopenharmony_ci SANE_Status status; 1525141cc406Sopenharmony_ci ssize_t xfer_len_in, xfer_len_line, xfer_len_out; 1526141cc406Sopenharmony_ci unsigned long index; 1527141cc406Sopenharmony_ci int color, sample_pass; 1528141cc406Sopenharmony_ci uint8_t *s8 = NULL; 1529141cc406Sopenharmony_ci uint16_t *s16 = NULL; 1530141cc406Sopenharmony_ci double m_avg_sum; 1531141cc406Sopenharmony_ci SANE_Byte *line_buf_new; 1532141cc406Sopenharmony_ci 1533141cc406Sopenharmony_ci DBG(32, "%s, maxlen = %i.\n", __func__, maxlen); 1534141cc406Sopenharmony_ci 1535141cc406Sopenharmony_ci if (!s->scanning) { 1536141cc406Sopenharmony_ci *len = 0; 1537141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1538141cc406Sopenharmony_ci } 1539141cc406Sopenharmony_ci 1540141cc406Sopenharmony_ci /* transfer from buffer */ 1541141cc406Sopenharmony_ci if (s->i_line_buf > 0) { 1542141cc406Sopenharmony_ci xfer_len_out = s->n_line_buf - s->i_line_buf; 1543141cc406Sopenharmony_ci if (xfer_len_out > maxlen) 1544141cc406Sopenharmony_ci xfer_len_out = maxlen; 1545141cc406Sopenharmony_ci 1546141cc406Sopenharmony_ci memcpy(buf, &(s->line_buf[s->i_line_buf]), xfer_len_out); 1547141cc406Sopenharmony_ci 1548141cc406Sopenharmony_ci s->i_line_buf += xfer_len_out; 1549141cc406Sopenharmony_ci if (s->i_line_buf >= s->n_line_buf) 1550141cc406Sopenharmony_ci s->i_line_buf = 0; 1551141cc406Sopenharmony_ci 1552141cc406Sopenharmony_ci *len = xfer_len_out; 1553141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1554141cc406Sopenharmony_ci } 1555141cc406Sopenharmony_ci 1556141cc406Sopenharmony_ci xfer_len_line = s->n_colors * s->logical_width * s->bytes_per_pixel; 1557141cc406Sopenharmony_ci xfer_len_in = xfer_len_line + (s->n_colors * s->odd_padding); 1558141cc406Sopenharmony_ci 1559141cc406Sopenharmony_ci if ((xfer_len_in & 0x3f)) { 1560141cc406Sopenharmony_ci int d = ((xfer_len_in / 512) * 512) + 512; 1561141cc406Sopenharmony_ci s->block_padding = d - xfer_len_in; 1562141cc406Sopenharmony_ci } 1563141cc406Sopenharmony_ci 1564141cc406Sopenharmony_ci DBG(22, "%s: block_padding = %d, odd_padding = %d\n", 1565141cc406Sopenharmony_ci __func__, s->block_padding, s->odd_padding); 1566141cc406Sopenharmony_ci 1567141cc406Sopenharmony_ci DBG(22, 1568141cc406Sopenharmony_ci "%s: colors = %d, logical_width = %ld, bytes_per_pixel = %d\n", 1569141cc406Sopenharmony_ci __func__, s->n_colors, s->logical_width, s->bytes_per_pixel); 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci 1572141cc406Sopenharmony_ci /* Do not change the behaviour of older models, pad to 512 */ 1573141cc406Sopenharmony_ci if ((s->type == CS3_TYPE_LS50) || (s->type == CS3_TYPE_LS5000)) { 1574141cc406Sopenharmony_ci xfer_len_in += s->block_padding; 1575141cc406Sopenharmony_ci if (xfer_len_in & 0x3f) 1576141cc406Sopenharmony_ci DBG(1, "BUG: %s, not a multiple of 64. (0x%06lx)\n", 1577141cc406Sopenharmony_ci __func__, (long) xfer_len_in); 1578141cc406Sopenharmony_ci } 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_ci if (s->xfer_position + xfer_len_line > s->xfer_bytes_total) 1581141cc406Sopenharmony_ci xfer_len_line = s->xfer_bytes_total - s->xfer_position; /* just in case */ 1582141cc406Sopenharmony_ci 1583141cc406Sopenharmony_ci if (xfer_len_line == 0) { /* no more data */ 1584141cc406Sopenharmony_ci *len = 0; 1585141cc406Sopenharmony_ci 1586141cc406Sopenharmony_ci /* increment frame number if appropriate */ 1587141cc406Sopenharmony_ci if (s->n_frames > 1 && --s->frame_count) { 1588141cc406Sopenharmony_ci s->i_frame++; 1589141cc406Sopenharmony_ci } 1590141cc406Sopenharmony_ci 1591141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1592141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1593141cc406Sopenharmony_ci } 1594141cc406Sopenharmony_ci 1595141cc406Sopenharmony_ci if (xfer_len_line != s->n_line_buf) { 1596141cc406Sopenharmony_ci line_buf_new = 1597141cc406Sopenharmony_ci (SANE_Byte *) cs3_xrealloc(s->line_buf, 1598141cc406Sopenharmony_ci xfer_len_line * 1599141cc406Sopenharmony_ci sizeof(SANE_Byte)); 1600141cc406Sopenharmony_ci if (!line_buf_new) { 1601141cc406Sopenharmony_ci *len = 0; 1602141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1603141cc406Sopenharmony_ci } 1604141cc406Sopenharmony_ci s->line_buf = line_buf_new; 1605141cc406Sopenharmony_ci s->n_line_buf = xfer_len_line; 1606141cc406Sopenharmony_ci } 1607141cc406Sopenharmony_ci 1608141cc406Sopenharmony_ci /* adapt for multi-sampling */ 1609141cc406Sopenharmony_ci xfer_len_in *= s->samples_per_scan; 1610141cc406Sopenharmony_ci 1611141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 1612141cc406Sopenharmony_ci cs3_init_buffer(s); 1613141cc406Sopenharmony_ci cs3_parse_cmd(s, "28 00 00 00 00 00"); 1614141cc406Sopenharmony_ci cs3_pack_byte(s, (xfer_len_in >> 16) & 0xff); 1615141cc406Sopenharmony_ci cs3_pack_byte(s, (xfer_len_in >> 8) & 0xff); 1616141cc406Sopenharmony_ci cs3_pack_byte(s, xfer_len_in & 0xff); 1617141cc406Sopenharmony_ci cs3_parse_cmd(s, "00"); 1618141cc406Sopenharmony_ci s->n_recv = xfer_len_in; 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 1621141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1622141cc406Sopenharmony_ci *len = 0; 1623141cc406Sopenharmony_ci return status; 1624141cc406Sopenharmony_ci } 1625141cc406Sopenharmony_ci 1626141cc406Sopenharmony_ci for (index = 0; index < s->logical_width; index++) { 1627141cc406Sopenharmony_ci for (color = 0; color < s->n_colors; color++) { 1628141cc406Sopenharmony_ci int where = s->bytes_per_pixel 1629141cc406Sopenharmony_ci * (s->n_colors * index + color); 1630141cc406Sopenharmony_ci 1631141cc406Sopenharmony_ci m_avg_sum = 0.0; 1632141cc406Sopenharmony_ci 1633141cc406Sopenharmony_ci switch (s->bytes_per_pixel) { 1634141cc406Sopenharmony_ci case 1: 1635141cc406Sopenharmony_ci { 1636141cc406Sopenharmony_ci /* target address */ 1637141cc406Sopenharmony_ci s8 = (uint8_t *) & (s->line_buf[where]); 1638141cc406Sopenharmony_ci 1639141cc406Sopenharmony_ci if (s->samples_per_scan > 1) { 1640141cc406Sopenharmony_ci /* calculate average of multi samples */ 1641141cc406Sopenharmony_ci for (sample_pass = 0; 1642141cc406Sopenharmony_ci sample_pass < s->samples_per_scan; 1643141cc406Sopenharmony_ci sample_pass++) { 1644141cc406Sopenharmony_ci /* source index */ 1645141cc406Sopenharmony_ci int p8 = (sample_pass * s->n_colors + color) 1646141cc406Sopenharmony_ci * s->logical_width 1647141cc406Sopenharmony_ci + (color + 1) * s->odd_padding 1648141cc406Sopenharmony_ci + index; 1649141cc406Sopenharmony_ci m_avg_sum += (double) s->recv_buf[p8]; 1650141cc406Sopenharmony_ci } 1651141cc406Sopenharmony_ci *s8 = (uint8_t) (m_avg_sum / s->samples_per_scan + 0.5); 1652141cc406Sopenharmony_ci } else { 1653141cc406Sopenharmony_ci /* shortcut for single sample */ 1654141cc406Sopenharmony_ci int p8 = s->logical_width * color 1655141cc406Sopenharmony_ci + (color + 1) * s->odd_padding 1656141cc406Sopenharmony_ci + index; 1657141cc406Sopenharmony_ci *s8 = s->recv_buf[p8]; 1658141cc406Sopenharmony_ci } 1659141cc406Sopenharmony_ci } 1660141cc406Sopenharmony_ci break; 1661141cc406Sopenharmony_ci case 2: 1662141cc406Sopenharmony_ci { 1663141cc406Sopenharmony_ci /* target address */ 1664141cc406Sopenharmony_ci s16 = (uint16_t *) & (s->line_buf[where]); 1665141cc406Sopenharmony_ci 1666141cc406Sopenharmony_ci if (s->samples_per_scan > 1) { 1667141cc406Sopenharmony_ci /* calculate average of multi samples */ 1668141cc406Sopenharmony_ci for (sample_pass = 0; 1669141cc406Sopenharmony_ci sample_pass < s->samples_per_scan; 1670141cc406Sopenharmony_ci sample_pass++) { 1671141cc406Sopenharmony_ci /* source index */ 1672141cc406Sopenharmony_ci int p16 = 2 * ((sample_pass * s->n_colors + color) 1673141cc406Sopenharmony_ci * s->logical_width + index); 1674141cc406Sopenharmony_ci m_avg_sum += (double) ((s->recv_buf[p16] << 8) 1675141cc406Sopenharmony_ci + s->recv_buf[p16 + 1]); 1676141cc406Sopenharmony_ci } 1677141cc406Sopenharmony_ci *s16 = (uint16_t) (m_avg_sum / s->samples_per_scan + 0.5); 1678141cc406Sopenharmony_ci } else { 1679141cc406Sopenharmony_ci /* shortcut for single sample */ 1680141cc406Sopenharmony_ci int p16 = 2 * (color * s->logical_width + index); 1681141cc406Sopenharmony_ci 1682141cc406Sopenharmony_ci *s16 = (s->recv_buf[p16] << 8) 1683141cc406Sopenharmony_ci + s->recv_buf[p16 + 1]; 1684141cc406Sopenharmony_ci } 1685141cc406Sopenharmony_ci 1686141cc406Sopenharmony_ci *s16 <<= s->shift_bits; 1687141cc406Sopenharmony_ci } 1688141cc406Sopenharmony_ci break; 1689141cc406Sopenharmony_ci 1690141cc406Sopenharmony_ci default: 1691141cc406Sopenharmony_ci DBG(1, 1692141cc406Sopenharmony_ci "BUG: sane_read(): Unknown number of bytes per pixel.\n"); 1693141cc406Sopenharmony_ci *len = 0; 1694141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1695141cc406Sopenharmony_ci break; 1696141cc406Sopenharmony_ci } 1697141cc406Sopenharmony_ci } 1698141cc406Sopenharmony_ci } 1699141cc406Sopenharmony_ci 1700141cc406Sopenharmony_ci s->xfer_position += xfer_len_line; 1701141cc406Sopenharmony_ci 1702141cc406Sopenharmony_ci xfer_len_out = xfer_len_line; 1703141cc406Sopenharmony_ci if (xfer_len_out > maxlen) 1704141cc406Sopenharmony_ci xfer_len_out = maxlen; 1705141cc406Sopenharmony_ci 1706141cc406Sopenharmony_ci memcpy(buf, s->line_buf, xfer_len_out); 1707141cc406Sopenharmony_ci if (xfer_len_out < xfer_len_line) 1708141cc406Sopenharmony_ci s->i_line_buf = xfer_len_out; /* data left in the line buffer, read out next time */ 1709141cc406Sopenharmony_ci 1710141cc406Sopenharmony_ci *len = xfer_len_out; 1711141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1712141cc406Sopenharmony_ci} 1713141cc406Sopenharmony_ci 1714141cc406Sopenharmony_civoid 1715141cc406Sopenharmony_cisane_cancel(SANE_Handle h) 1716141cc406Sopenharmony_ci{ 1717141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1718141cc406Sopenharmony_ci 1719141cc406Sopenharmony_ci DBG(10, "%s, scanning = %d.\n", __func__, s->scanning); 1720141cc406Sopenharmony_ci 1721141cc406Sopenharmony_ci if (s->scanning) { 1722141cc406Sopenharmony_ci cs3_init_buffer(s); 1723141cc406Sopenharmony_ci cs3_parse_cmd(s, "c0 00 00 00 00 00"); 1724141cc406Sopenharmony_ci cs3_issue_cmd(s); 1725141cc406Sopenharmony_ci } 1726141cc406Sopenharmony_ci 1727141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 1728141cc406Sopenharmony_ci} 1729141cc406Sopenharmony_ci 1730141cc406Sopenharmony_ciSANE_Status 1731141cc406Sopenharmony_cisane_set_io_mode(SANE_Handle h, SANE_Bool m) 1732141cc406Sopenharmony_ci{ 1733141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1734141cc406Sopenharmony_ci 1735141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 1736141cc406Sopenharmony_ci 1737141cc406Sopenharmony_ci if (!s->scanning) 1738141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1739141cc406Sopenharmony_ci if (m == SANE_FALSE) 1740141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1741141cc406Sopenharmony_ci else 1742141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1743141cc406Sopenharmony_ci} 1744141cc406Sopenharmony_ci 1745141cc406Sopenharmony_ciSANE_Status 1746141cc406Sopenharmony_cisane_get_select_fd(SANE_Handle h, SANE_Int * fd) 1747141cc406Sopenharmony_ci{ 1748141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) h; 1749141cc406Sopenharmony_ci 1750141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 1751141cc406Sopenharmony_ci 1752141cc406Sopenharmony_ci (void) fd; /* to shut up compiler */ 1753141cc406Sopenharmony_ci (void) s; /* to shut up compiler */ 1754141cc406Sopenharmony_ci 1755141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1756141cc406Sopenharmony_ci} 1757141cc406Sopenharmony_ci 1758141cc406Sopenharmony_ci 1759141cc406Sopenharmony_ci/* ========================================================================= */ 1760141cc406Sopenharmony_ci/* private functions */ 1761141cc406Sopenharmony_ci 1762141cc406Sopenharmony_cistatic void 1763141cc406Sopenharmony_cics3_trim(char *s) 1764141cc406Sopenharmony_ci{ 1765141cc406Sopenharmony_ci int i, l = strlen(s); 1766141cc406Sopenharmony_ci 1767141cc406Sopenharmony_ci for (i = l - 1; i > 0; i--) { 1768141cc406Sopenharmony_ci if (s[i] == ' ') 1769141cc406Sopenharmony_ci s[i] = '\0'; 1770141cc406Sopenharmony_ci else 1771141cc406Sopenharmony_ci break; 1772141cc406Sopenharmony_ci } 1773141cc406Sopenharmony_ci} 1774141cc406Sopenharmony_ci 1775141cc406Sopenharmony_cistatic SANE_Status 1776141cc406Sopenharmony_cics3_open(const char *device, cs3_interface_t interface, cs3_t ** sp) 1777141cc406Sopenharmony_ci{ 1778141cc406Sopenharmony_ci SANE_Status status; 1779141cc406Sopenharmony_ci cs3_t *s; 1780141cc406Sopenharmony_ci char *prefix = NULL, *line; 1781141cc406Sopenharmony_ci int i; 1782141cc406Sopenharmony_ci int alloc_failed = 0; 1783141cc406Sopenharmony_ci SANE_Device **device_list_new; 1784141cc406Sopenharmony_ci 1785141cc406Sopenharmony_ci DBG(6, "%s, device = %s, interface = %i\n", 1786141cc406Sopenharmony_ci __func__, device, interface); 1787141cc406Sopenharmony_ci 1788141cc406Sopenharmony_ci if (!strncmp(device, "auto", 5)) { 1789141cc406Sopenharmony_ci try_interface = CS3_INTERFACE_SCSI; 1790141cc406Sopenharmony_ci sanei_config_attach_matching_devices("scsi Nikon *", 1791141cc406Sopenharmony_ci cs3_attach); 1792141cc406Sopenharmony_ci try_interface = CS3_INTERFACE_USB; 1793141cc406Sopenharmony_ci sanei_usb_attach_matching_devices("usb 0x04b0 0x4000", 1794141cc406Sopenharmony_ci cs3_attach); 1795141cc406Sopenharmony_ci sanei_usb_attach_matching_devices("usb 0x04b0 0x4001", 1796141cc406Sopenharmony_ci cs3_attach); 1797141cc406Sopenharmony_ci sanei_usb_attach_matching_devices("usb 0x04b0 0x4002", 1798141cc406Sopenharmony_ci cs3_attach); 1799141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1800141cc406Sopenharmony_ci } 1801141cc406Sopenharmony_ci 1802141cc406Sopenharmony_ci if ((s = (cs3_t *) cs3_xmalloc(sizeof(cs3_t))) == NULL) 1803141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1804141cc406Sopenharmony_ci memset(s, 0, sizeof(cs3_t)); 1805141cc406Sopenharmony_ci 1806141cc406Sopenharmony_ci /* fill magic bits */ 1807141cc406Sopenharmony_ci s->magic = SANE_COOKIE; 1808141cc406Sopenharmony_ci s->cookie_ptr = &s->cookie; 1809141cc406Sopenharmony_ci 1810141cc406Sopenharmony_ci s->cookie.version = 0x01; 1811141cc406Sopenharmony_ci s->cookie.vendor = s->vendor_string; 1812141cc406Sopenharmony_ci s->cookie.model = s->product_string; 1813141cc406Sopenharmony_ci s->cookie.revision = s->revision_string; 1814141cc406Sopenharmony_ci 1815141cc406Sopenharmony_ci s->send_buf = s->recv_buf = NULL; 1816141cc406Sopenharmony_ci s->send_buf_size = s->recv_buf_size = 0; 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci switch (interface) { 1819141cc406Sopenharmony_ci case CS3_INTERFACE_UNKNOWN: 1820141cc406Sopenharmony_ci for (i = 0; i < 2; i++) { 1821141cc406Sopenharmony_ci switch (i) { 1822141cc406Sopenharmony_ci case 1: 1823141cc406Sopenharmony_ci prefix = "usb:"; 1824141cc406Sopenharmony_ci try_interface = CS3_INTERFACE_USB; 1825141cc406Sopenharmony_ci break; 1826141cc406Sopenharmony_ci default: 1827141cc406Sopenharmony_ci prefix = "scsi:"; 1828141cc406Sopenharmony_ci try_interface = CS3_INTERFACE_SCSI; 1829141cc406Sopenharmony_ci break; 1830141cc406Sopenharmony_ci } 1831141cc406Sopenharmony_ci if (!strncmp(device, prefix, strlen(prefix))) { 1832141cc406Sopenharmony_ci const void *p = device + strlen(prefix); 1833141cc406Sopenharmony_ci cs3_xfree(s); 1834141cc406Sopenharmony_ci return cs3_open(p, try_interface, sp); 1835141cc406Sopenharmony_ci } 1836141cc406Sopenharmony_ci } 1837141cc406Sopenharmony_ci cs3_xfree(s); 1838141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1839141cc406Sopenharmony_ci break; 1840141cc406Sopenharmony_ci case CS3_INTERFACE_SCSI: 1841141cc406Sopenharmony_ci s->interface = CS3_INTERFACE_SCSI; 1842141cc406Sopenharmony_ci DBG(6, 1843141cc406Sopenharmony_ci "%s, trying to open %s, assuming SCSI or SBP2 interface\n", 1844141cc406Sopenharmony_ci __func__, device); 1845141cc406Sopenharmony_ci status = sanei_scsi_open(device, &s->fd, 1846141cc406Sopenharmony_ci cs3_scsi_sense_handler, s); 1847141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1848141cc406Sopenharmony_ci DBG(6, " ...failed: %s.\n", sane_strstatus(status)); 1849141cc406Sopenharmony_ci cs3_xfree(s); 1850141cc406Sopenharmony_ci return status; 1851141cc406Sopenharmony_ci } 1852141cc406Sopenharmony_ci break; 1853141cc406Sopenharmony_ci case CS3_INTERFACE_USB: 1854141cc406Sopenharmony_ci s->interface = CS3_INTERFACE_USB; 1855141cc406Sopenharmony_ci DBG(6, "%s, trying to open %s, assuming USB interface\n", 1856141cc406Sopenharmony_ci __func__, device); 1857141cc406Sopenharmony_ci status = sanei_usb_open(device, &s->fd); 1858141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1859141cc406Sopenharmony_ci DBG(6, " ...failed: %s.\n", sane_strstatus(status)); 1860141cc406Sopenharmony_ci cs3_xfree(s); 1861141cc406Sopenharmony_ci return status; 1862141cc406Sopenharmony_ci } 1863141cc406Sopenharmony_ci break; 1864141cc406Sopenharmony_ci } 1865141cc406Sopenharmony_ci 1866141cc406Sopenharmony_ci open_devices++; 1867141cc406Sopenharmony_ci DBG(6, "%s, trying to identify device.\n", __func__); 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci /* identify scanner */ 1870141cc406Sopenharmony_ci status = cs3_page_inquiry(s, -1); 1871141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1872141cc406Sopenharmony_ci cs3_close(s); 1873141cc406Sopenharmony_ci return status; 1874141cc406Sopenharmony_ci } 1875141cc406Sopenharmony_ci 1876141cc406Sopenharmony_ci strncpy(s->vendor_string, (char *) s->recv_buf + 8, 8); 1877141cc406Sopenharmony_ci s->vendor_string[8] = '\0'; 1878141cc406Sopenharmony_ci strncpy(s->product_string, (char *) s->recv_buf + 16, 16); 1879141cc406Sopenharmony_ci s->product_string[16] = '\0'; 1880141cc406Sopenharmony_ci strncpy(s->revision_string, (char *) s->recv_buf + 32, 4); 1881141cc406Sopenharmony_ci s->revision_string[4] = '\0'; 1882141cc406Sopenharmony_ci 1883141cc406Sopenharmony_ci DBG(10, 1884141cc406Sopenharmony_ci "%s, vendor = '%s', product = '%s', revision = '%s'.\n", 1885141cc406Sopenharmony_ci __func__, s->vendor_string, s->product_string, 1886141cc406Sopenharmony_ci s->revision_string); 1887141cc406Sopenharmony_ci 1888141cc406Sopenharmony_ci if (!strncmp(s->product_string, "COOLSCANIII ", 16)) 1889141cc406Sopenharmony_ci s->type = CS3_TYPE_LS30; 1890141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-40 ED ", 16)) 1891141cc406Sopenharmony_ci s->type = CS3_TYPE_LS40; 1892141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-50 ED ", 16)) 1893141cc406Sopenharmony_ci s->type = CS3_TYPE_LS50; 1894141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-2000 ", 16)) 1895141cc406Sopenharmony_ci s->type = CS3_TYPE_LS2000; 1896141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-4000 ED ", 16)) 1897141cc406Sopenharmony_ci s->type = CS3_TYPE_LS4000; 1898141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-5000 ED ", 16)) 1899141cc406Sopenharmony_ci s->type = CS3_TYPE_LS5000; 1900141cc406Sopenharmony_ci else if (!strncmp(s->product_string, "LS-8000 ED ", 16)) 1901141cc406Sopenharmony_ci s->type = CS3_TYPE_LS8000; 1902141cc406Sopenharmony_ci 1903141cc406Sopenharmony_ci if (s->type != CS3_TYPE_UNKOWN) 1904141cc406Sopenharmony_ci DBG(10, 1905141cc406Sopenharmony_ci "%s, device identified as coolscan3 type #%i.\n", 1906141cc406Sopenharmony_ci __func__, s->type); 1907141cc406Sopenharmony_ci else { 1908141cc406Sopenharmony_ci DBG(10, "%s, device not identified.\n", __func__); 1909141cc406Sopenharmony_ci cs3_close(s); 1910141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1911141cc406Sopenharmony_ci } 1912141cc406Sopenharmony_ci 1913141cc406Sopenharmony_ci cs3_trim(s->vendor_string); 1914141cc406Sopenharmony_ci cs3_trim(s->product_string); 1915141cc406Sopenharmony_ci cs3_trim(s->revision_string); 1916141cc406Sopenharmony_ci 1917141cc406Sopenharmony_ci if (sp) 1918141cc406Sopenharmony_ci *sp = s; 1919141cc406Sopenharmony_ci else { 1920141cc406Sopenharmony_ci device_list_new = 1921141cc406Sopenharmony_ci (SANE_Device **) cs3_xrealloc(device_list, 1922141cc406Sopenharmony_ci (n_device_list + 1923141cc406Sopenharmony_ci 2) * 1924141cc406Sopenharmony_ci sizeof(SANE_Device *)); 1925141cc406Sopenharmony_ci if (!device_list_new) 1926141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1927141cc406Sopenharmony_ci device_list = device_list_new; 1928141cc406Sopenharmony_ci device_list[n_device_list] = 1929141cc406Sopenharmony_ci (SANE_Device *) cs3_xmalloc(sizeof(SANE_Device)); 1930141cc406Sopenharmony_ci if (!device_list[n_device_list]) 1931141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1932141cc406Sopenharmony_ci switch (interface) { 1933141cc406Sopenharmony_ci case CS3_INTERFACE_UNKNOWN: 1934141cc406Sopenharmony_ci DBG(1, "BUG: cs3_open(): unknown interface.\n"); 1935141cc406Sopenharmony_ci cs3_close(s); 1936141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1937141cc406Sopenharmony_ci break; 1938141cc406Sopenharmony_ci case CS3_INTERFACE_SCSI: 1939141cc406Sopenharmony_ci prefix = "scsi:"; 1940141cc406Sopenharmony_ci break; 1941141cc406Sopenharmony_ci case CS3_INTERFACE_USB: 1942141cc406Sopenharmony_ci prefix = "usb:"; 1943141cc406Sopenharmony_ci break; 1944141cc406Sopenharmony_ci } 1945141cc406Sopenharmony_ci 1946141cc406Sopenharmony_ci line = (char *) cs3_xmalloc(strlen(device) + strlen(prefix) + 1947141cc406Sopenharmony_ci 1); 1948141cc406Sopenharmony_ci if (!line) 1949141cc406Sopenharmony_ci alloc_failed = 1; 1950141cc406Sopenharmony_ci else { 1951141cc406Sopenharmony_ci strcpy(line, prefix); 1952141cc406Sopenharmony_ci strcat(line, device); 1953141cc406Sopenharmony_ci device_list[n_device_list]->name = line; 1954141cc406Sopenharmony_ci } 1955141cc406Sopenharmony_ci 1956141cc406Sopenharmony_ci line = (char *) cs3_xmalloc(strlen(s->vendor_string) + 1); 1957141cc406Sopenharmony_ci if (!line) 1958141cc406Sopenharmony_ci alloc_failed = 1; 1959141cc406Sopenharmony_ci else { 1960141cc406Sopenharmony_ci strcpy(line, s->vendor_string); 1961141cc406Sopenharmony_ci device_list[n_device_list]->vendor = line; 1962141cc406Sopenharmony_ci } 1963141cc406Sopenharmony_ci 1964141cc406Sopenharmony_ci line = (char *) cs3_xmalloc(strlen(s->product_string) + 1); 1965141cc406Sopenharmony_ci if (!line) 1966141cc406Sopenharmony_ci alloc_failed = 1; 1967141cc406Sopenharmony_ci else { 1968141cc406Sopenharmony_ci strcpy(line, s->product_string); 1969141cc406Sopenharmony_ci device_list[n_device_list]->model = line; 1970141cc406Sopenharmony_ci } 1971141cc406Sopenharmony_ci 1972141cc406Sopenharmony_ci device_list[n_device_list]->type = "film scanner"; 1973141cc406Sopenharmony_ci 1974141cc406Sopenharmony_ci if (alloc_failed) { 1975141cc406Sopenharmony_ci cs3_xfree((void *)device_list[n_device_list]->name); 1976141cc406Sopenharmony_ci cs3_xfree((void *)device_list[n_device_list]->vendor); 1977141cc406Sopenharmony_ci cs3_xfree((void *)device_list[n_device_list]->model); 1978141cc406Sopenharmony_ci cs3_xfree(device_list[n_device_list]); 1979141cc406Sopenharmony_ci } else 1980141cc406Sopenharmony_ci n_device_list++; 1981141cc406Sopenharmony_ci device_list[n_device_list] = NULL; 1982141cc406Sopenharmony_ci 1983141cc406Sopenharmony_ci cs3_close(s); 1984141cc406Sopenharmony_ci } 1985141cc406Sopenharmony_ci 1986141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1987141cc406Sopenharmony_ci} 1988141cc406Sopenharmony_ci 1989141cc406Sopenharmony_civoid 1990141cc406Sopenharmony_cics3_close(cs3_t * s) 1991141cc406Sopenharmony_ci{ 1992141cc406Sopenharmony_ci cs3_xfree(s->lut_r); 1993141cc406Sopenharmony_ci cs3_xfree(s->lut_g); 1994141cc406Sopenharmony_ci cs3_xfree(s->lut_b); 1995141cc406Sopenharmony_ci cs3_xfree(s->lut_neutral); 1996141cc406Sopenharmony_ci cs3_xfree(s->line_buf); 1997141cc406Sopenharmony_ci 1998141cc406Sopenharmony_ci switch (s->interface) { 1999141cc406Sopenharmony_ci case CS3_INTERFACE_UNKNOWN: 2000141cc406Sopenharmony_ci DBG(0, "BUG: %s: Unknown interface number.\n", __func__); 2001141cc406Sopenharmony_ci break; 2002141cc406Sopenharmony_ci case CS3_INTERFACE_SCSI: 2003141cc406Sopenharmony_ci sanei_scsi_close(s->fd); 2004141cc406Sopenharmony_ci open_devices--; 2005141cc406Sopenharmony_ci break; 2006141cc406Sopenharmony_ci case CS3_INTERFACE_USB: 2007141cc406Sopenharmony_ci sanei_usb_close(s->fd); 2008141cc406Sopenharmony_ci open_devices--; 2009141cc406Sopenharmony_ci break; 2010141cc406Sopenharmony_ci } 2011141cc406Sopenharmony_ci 2012141cc406Sopenharmony_ci cs3_xfree(s); 2013141cc406Sopenharmony_ci} 2014141cc406Sopenharmony_ci 2015141cc406Sopenharmony_cistatic SANE_Status 2016141cc406Sopenharmony_cics3_attach(const char *dev) 2017141cc406Sopenharmony_ci{ 2018141cc406Sopenharmony_ci SANE_Status status; 2019141cc406Sopenharmony_ci 2020141cc406Sopenharmony_ci if (try_interface == CS3_INTERFACE_UNKNOWN) 2021141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 2022141cc406Sopenharmony_ci 2023141cc406Sopenharmony_ci status = cs3_open(dev, try_interface, NULL); 2024141cc406Sopenharmony_ci return status; 2025141cc406Sopenharmony_ci} 2026141cc406Sopenharmony_ci 2027141cc406Sopenharmony_cistatic SANE_Status 2028141cc406Sopenharmony_cics3_scsi_sense_handler(int fd, u_char * sense_buffer, void *arg) 2029141cc406Sopenharmony_ci{ 2030141cc406Sopenharmony_ci cs3_t *s = (cs3_t *) arg; 2031141cc406Sopenharmony_ci 2032141cc406Sopenharmony_ci (void) fd; /* to shut up compiler */ 2033141cc406Sopenharmony_ci 2034141cc406Sopenharmony_ci /* sort this out ! XXX */ 2035141cc406Sopenharmony_ci 2036141cc406Sopenharmony_ci s->sense_key = sense_buffer[2] & 0x0f; 2037141cc406Sopenharmony_ci s->sense_asc = sense_buffer[12]; 2038141cc406Sopenharmony_ci s->sense_ascq = sense_buffer[13]; 2039141cc406Sopenharmony_ci s->sense_info = sense_buffer[3]; 2040141cc406Sopenharmony_ci 2041141cc406Sopenharmony_ci return cs3_parse_sense_data(s); 2042141cc406Sopenharmony_ci} 2043141cc406Sopenharmony_ci 2044141cc406Sopenharmony_cistatic SANE_Status 2045141cc406Sopenharmony_cics3_parse_sense_data(cs3_t * s) 2046141cc406Sopenharmony_ci{ 2047141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 2048141cc406Sopenharmony_ci 2049141cc406Sopenharmony_ci s->sense_code = 2050141cc406Sopenharmony_ci (s->sense_key << 24) + (s->sense_asc << 16) + 2051141cc406Sopenharmony_ci (s->sense_ascq << 8) + s->sense_info; 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_ci if (s->sense_key) 2054141cc406Sopenharmony_ci DBG(14, "sense code: %02lx-%02lx-%02lx-%02lx\n", s->sense_key, 2055141cc406Sopenharmony_ci s->sense_asc, s->sense_ascq, s->sense_info); 2056141cc406Sopenharmony_ci 2057141cc406Sopenharmony_ci switch (s->sense_key) { 2058141cc406Sopenharmony_ci case 0x00: 2059141cc406Sopenharmony_ci s->status = CS3_STATUS_READY; 2060141cc406Sopenharmony_ci break; 2061141cc406Sopenharmony_ci 2062141cc406Sopenharmony_ci case 0x02: 2063141cc406Sopenharmony_ci switch (s->sense_asc) { 2064141cc406Sopenharmony_ci case 0x04: 2065141cc406Sopenharmony_ci DBG(15, " processing\n"); 2066141cc406Sopenharmony_ci s->status = CS3_STATUS_PROCESSING; 2067141cc406Sopenharmony_ci break; 2068141cc406Sopenharmony_ci case 0x3a: 2069141cc406Sopenharmony_ci DBG(15, " no docs\n"); 2070141cc406Sopenharmony_ci s->status = CS3_STATUS_NO_DOCS; 2071141cc406Sopenharmony_ci break; 2072141cc406Sopenharmony_ci default: 2073141cc406Sopenharmony_ci DBG(15, " default\n"); 2074141cc406Sopenharmony_ci s->status = CS3_STATUS_ERROR; 2075141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 2076141cc406Sopenharmony_ci break; 2077141cc406Sopenharmony_ci } 2078141cc406Sopenharmony_ci break; 2079141cc406Sopenharmony_ci 2080141cc406Sopenharmony_ci case 0x09: 2081141cc406Sopenharmony_ci if ((s->sense_code == 0x09800600) 2082141cc406Sopenharmony_ci || (s->sense_code == 0x09800601)) 2083141cc406Sopenharmony_ci s->status = CS3_STATUS_REISSUE; 2084141cc406Sopenharmony_ci break; 2085141cc406Sopenharmony_ci 2086141cc406Sopenharmony_ci default: 2087141cc406Sopenharmony_ci s->status = CS3_STATUS_ERROR; 2088141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 2089141cc406Sopenharmony_ci break; 2090141cc406Sopenharmony_ci } 2091141cc406Sopenharmony_ci 2092141cc406Sopenharmony_ci return status; 2093141cc406Sopenharmony_ci} 2094141cc406Sopenharmony_ci 2095141cc406Sopenharmony_cistatic void 2096141cc406Sopenharmony_cics3_init_buffer(cs3_t * s) 2097141cc406Sopenharmony_ci{ 2098141cc406Sopenharmony_ci s->n_cmd = 0; 2099141cc406Sopenharmony_ci s->n_send = 0; 2100141cc406Sopenharmony_ci s->n_recv = 0; 2101141cc406Sopenharmony_ci} 2102141cc406Sopenharmony_ci 2103141cc406Sopenharmony_cistatic SANE_Status 2104141cc406Sopenharmony_cics3_pack_byte(cs3_t * s, SANE_Byte byte) 2105141cc406Sopenharmony_ci{ 2106141cc406Sopenharmony_ci while (s->send_buf_size <= s->n_send) { 2107141cc406Sopenharmony_ci s->send_buf_size += 16; 2108141cc406Sopenharmony_ci s->send_buf = 2109141cc406Sopenharmony_ci (SANE_Byte *) cs3_xrealloc(s->send_buf, 2110141cc406Sopenharmony_ci s->send_buf_size); 2111141cc406Sopenharmony_ci if (!s->send_buf) 2112141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2113141cc406Sopenharmony_ci } 2114141cc406Sopenharmony_ci 2115141cc406Sopenharmony_ci s->send_buf[s->n_send++] = byte; 2116141cc406Sopenharmony_ci 2117141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2118141cc406Sopenharmony_ci} 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_cistatic void 2121141cc406Sopenharmony_cics3_pack_long(cs3_t * s, unsigned long val) 2122141cc406Sopenharmony_ci{ 2123141cc406Sopenharmony_ci cs3_pack_byte(s, (val >> 24) & 0xff); 2124141cc406Sopenharmony_ci cs3_pack_byte(s, (val >> 16) & 0xff); 2125141cc406Sopenharmony_ci cs3_pack_byte(s, (val >> 8) & 0xff); 2126141cc406Sopenharmony_ci cs3_pack_byte(s, val & 0xff); 2127141cc406Sopenharmony_ci} 2128141cc406Sopenharmony_ci 2129141cc406Sopenharmony_cistatic void 2130141cc406Sopenharmony_cics3_pack_word(cs3_t * s, unsigned long val) 2131141cc406Sopenharmony_ci{ 2132141cc406Sopenharmony_ci cs3_pack_byte(s, (val >> 8) & 0xff); 2133141cc406Sopenharmony_ci cs3_pack_byte(s, val & 0xff); 2134141cc406Sopenharmony_ci} 2135141cc406Sopenharmony_ci 2136141cc406Sopenharmony_cistatic SANE_Status 2137141cc406Sopenharmony_cics3_parse_cmd(cs3_t * s, char *text) 2138141cc406Sopenharmony_ci{ 2139141cc406Sopenharmony_ci size_t i, j; 2140141cc406Sopenharmony_ci char c, h; 2141141cc406Sopenharmony_ci SANE_Status status; 2142141cc406Sopenharmony_ci 2143141cc406Sopenharmony_ci for (i = 0; i < strlen(text); i += 2) 2144141cc406Sopenharmony_ci if (text[i] == ' ') 2145141cc406Sopenharmony_ci i--; /* a bit dirty... advance by -1+2=1 */ 2146141cc406Sopenharmony_ci else { 2147141cc406Sopenharmony_ci if ((!isxdigit(text[i])) || (!isxdigit(text[i + 1]))) 2148141cc406Sopenharmony_ci DBG(1, 2149141cc406Sopenharmony_ci "BUG: cs3_parse_cmd(): Parser got invalid character.\n"); 2150141cc406Sopenharmony_ci c = 0; 2151141cc406Sopenharmony_ci for (j = 0; j < 2; j++) { 2152141cc406Sopenharmony_ci h = tolower(text[i + j]); 2153141cc406Sopenharmony_ci if ((h >= 'a') && (h <= 'f')) 2154141cc406Sopenharmony_ci c += 10 + h - 'a'; 2155141cc406Sopenharmony_ci else 2156141cc406Sopenharmony_ci c += h - '0'; 2157141cc406Sopenharmony_ci if (j == 0) 2158141cc406Sopenharmony_ci c <<= 4; 2159141cc406Sopenharmony_ci } 2160141cc406Sopenharmony_ci status = cs3_pack_byte(s, c); 2161141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2162141cc406Sopenharmony_ci return status; 2163141cc406Sopenharmony_ci } 2164141cc406Sopenharmony_ci 2165141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2166141cc406Sopenharmony_ci} 2167141cc406Sopenharmony_ci 2168141cc406Sopenharmony_cistatic SANE_Status 2169141cc406Sopenharmony_cics3_grow_send_buffer(cs3_t * s) 2170141cc406Sopenharmony_ci{ 2171141cc406Sopenharmony_ci if (s->n_send > s->send_buf_size) { 2172141cc406Sopenharmony_ci s->send_buf_size = s->n_send; 2173141cc406Sopenharmony_ci s->send_buf = 2174141cc406Sopenharmony_ci (SANE_Byte *) cs3_xrealloc(s->send_buf, 2175141cc406Sopenharmony_ci s->send_buf_size); 2176141cc406Sopenharmony_ci if (!s->send_buf) 2177141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2178141cc406Sopenharmony_ci } 2179141cc406Sopenharmony_ci 2180141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2181141cc406Sopenharmony_ci} 2182141cc406Sopenharmony_ci 2183141cc406Sopenharmony_cistatic SANE_Status 2184141cc406Sopenharmony_cics3_issue_cmd(cs3_t * s) 2185141cc406Sopenharmony_ci{ 2186141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2187141cc406Sopenharmony_ci size_t n_data, n_status; 2188141cc406Sopenharmony_ci static SANE_Byte status_buf[8]; 2189141cc406Sopenharmony_ci int status_only = 0; 2190141cc406Sopenharmony_ci 2191141cc406Sopenharmony_ci DBG(20, 2192141cc406Sopenharmony_ci "cs3_issue_cmd(): opcode = 0x%02x, n_send = %lu, n_recv = %lu.\n", 2193141cc406Sopenharmony_ci s->send_buf[0], (unsigned long) s->n_send, 2194141cc406Sopenharmony_ci (unsigned long) s->n_recv); 2195141cc406Sopenharmony_ci 2196141cc406Sopenharmony_ci s->status = CS3_STATUS_READY; 2197141cc406Sopenharmony_ci 2198141cc406Sopenharmony_ci if (!s->n_cmd) 2199141cc406Sopenharmony_ci switch (s->send_buf[0]) { 2200141cc406Sopenharmony_ci case 0x00: 2201141cc406Sopenharmony_ci case 0x12: 2202141cc406Sopenharmony_ci case 0x15: 2203141cc406Sopenharmony_ci case 0x16: 2204141cc406Sopenharmony_ci case 0x17: 2205141cc406Sopenharmony_ci case 0x1a: 2206141cc406Sopenharmony_ci case 0x1b: 2207141cc406Sopenharmony_ci case 0x1c: 2208141cc406Sopenharmony_ci case 0x1d: 2209141cc406Sopenharmony_ci case 0xc0: 2210141cc406Sopenharmony_ci case 0xc1: 2211141cc406Sopenharmony_ci s->n_cmd = 6; 2212141cc406Sopenharmony_ci break; 2213141cc406Sopenharmony_ci case 0x24: 2214141cc406Sopenharmony_ci case 0x25: 2215141cc406Sopenharmony_ci case 0x28: 2216141cc406Sopenharmony_ci case 0x2a: 2217141cc406Sopenharmony_ci case 0xe0: 2218141cc406Sopenharmony_ci case 0xe1: 2219141cc406Sopenharmony_ci s->n_cmd = 10; 2220141cc406Sopenharmony_ci break; 2221141cc406Sopenharmony_ci default: 2222141cc406Sopenharmony_ci DBG(1, 2223141cc406Sopenharmony_ci "BUG: cs3_issue_cmd(): Unknown command opcode 0x%02x.\n", 2224141cc406Sopenharmony_ci s->send_buf[0]); 2225141cc406Sopenharmony_ci break; 2226141cc406Sopenharmony_ci } 2227141cc406Sopenharmony_ci 2228141cc406Sopenharmony_ci if (s->n_send < s->n_cmd) { 2229141cc406Sopenharmony_ci DBG(1, 2230141cc406Sopenharmony_ci "BUG: cs3_issue_cmd(): Negative number of data out bytes requested.\n"); 2231141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2232141cc406Sopenharmony_ci } 2233141cc406Sopenharmony_ci 2234141cc406Sopenharmony_ci n_data = s->n_send - s->n_cmd; 2235141cc406Sopenharmony_ci if (s->n_recv > 0) { 2236141cc406Sopenharmony_ci if (n_data > 0) { 2237141cc406Sopenharmony_ci DBG(1, 2238141cc406Sopenharmony_ci "BUG: cs3_issue_cmd(): Both data in and data out requested.\n"); 2239141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2240141cc406Sopenharmony_ci } else { 2241141cc406Sopenharmony_ci n_data = s->n_recv; 2242141cc406Sopenharmony_ci } 2243141cc406Sopenharmony_ci } 2244141cc406Sopenharmony_ci 2245141cc406Sopenharmony_ci s->recv_buf = (SANE_Byte *) cs3_xrealloc(s->recv_buf, s->n_recv); 2246141cc406Sopenharmony_ci if (!s->recv_buf) 2247141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2248141cc406Sopenharmony_ci 2249141cc406Sopenharmony_ci switch (s->interface) { 2250141cc406Sopenharmony_ci case CS3_INTERFACE_UNKNOWN: 2251141cc406Sopenharmony_ci DBG(1, 2252141cc406Sopenharmony_ci "BUG: cs3_issue_cmd(): Unknown or uninitialized interface number.\n"); 2253141cc406Sopenharmony_ci break; 2254141cc406Sopenharmony_ci 2255141cc406Sopenharmony_ci case CS3_INTERFACE_SCSI: 2256141cc406Sopenharmony_ci sanei_scsi_cmd2(s->fd, s->send_buf, s->n_cmd, 2257141cc406Sopenharmony_ci s->send_buf + s->n_cmd, s->n_send - s->n_cmd, 2258141cc406Sopenharmony_ci s->recv_buf, &s->n_recv); 2259141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2260141cc406Sopenharmony_ci break; 2261141cc406Sopenharmony_ci 2262141cc406Sopenharmony_ci case CS3_INTERFACE_USB: 2263141cc406Sopenharmony_ci status = sanei_usb_write_bulk(s->fd, s->send_buf, &s->n_cmd); 2264141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2265141cc406Sopenharmony_ci DBG(1, 2266141cc406Sopenharmony_ci "Error: cs3_issue_cmd(): Could not write command.\n"); 2267141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2268141cc406Sopenharmony_ci } 2269141cc406Sopenharmony_ci 2270141cc406Sopenharmony_ci switch (cs3_phase_check(s)) { 2271141cc406Sopenharmony_ci case CS3_PHASE_OUT: 2272141cc406Sopenharmony_ci if (s->n_send - s->n_cmd < n_data || !n_data) { 2273141cc406Sopenharmony_ci DBG(4, 2274141cc406Sopenharmony_ci "Error: cs3_issue_cmd(): Unexpected data out phase.\n"); 2275141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2276141cc406Sopenharmony_ci } 2277141cc406Sopenharmony_ci status = sanei_usb_write_bulk(s->fd, 2278141cc406Sopenharmony_ci s->send_buf + s->n_cmd, 2279141cc406Sopenharmony_ci &n_data); 2280141cc406Sopenharmony_ci break; 2281141cc406Sopenharmony_ci 2282141cc406Sopenharmony_ci case CS3_PHASE_IN: 2283141cc406Sopenharmony_ci if (s->n_recv < n_data || !n_data) { 2284141cc406Sopenharmony_ci DBG(4, 2285141cc406Sopenharmony_ci "Error: cs3_issue_cmd(): Unexpected data in phase.\n"); 2286141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2287141cc406Sopenharmony_ci } 2288141cc406Sopenharmony_ci status = sanei_usb_read_bulk(s->fd, s->recv_buf, 2289141cc406Sopenharmony_ci &n_data); 2290141cc406Sopenharmony_ci s->n_recv = n_data; 2291141cc406Sopenharmony_ci break; 2292141cc406Sopenharmony_ci 2293141cc406Sopenharmony_ci case CS3_PHASE_NONE: 2294141cc406Sopenharmony_ci DBG(4, "%s: No command received!\n", __func__); 2295141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2296141cc406Sopenharmony_ci 2297141cc406Sopenharmony_ci default: 2298141cc406Sopenharmony_ci if (n_data) { 2299141cc406Sopenharmony_ci DBG(4, 2300141cc406Sopenharmony_ci "%s: Unexpected non-data phase, but n_data != 0 (%lu).\n", 2301141cc406Sopenharmony_ci __func__, (u_long) n_data); 2302141cc406Sopenharmony_ci status_only = 1; 2303141cc406Sopenharmony_ci } 2304141cc406Sopenharmony_ci break; 2305141cc406Sopenharmony_ci } 2306141cc406Sopenharmony_ci 2307141cc406Sopenharmony_ci n_status = 8; 2308141cc406Sopenharmony_ci status = sanei_usb_read_bulk(s->fd, status_buf, &n_status); 2309141cc406Sopenharmony_ci if (n_status != 8) { 2310141cc406Sopenharmony_ci DBG(4, 2311141cc406Sopenharmony_ci "Error: cs3_issue_cmd(): Failed to read 8 status bytes from USB.\n"); 2312141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2313141cc406Sopenharmony_ci } 2314141cc406Sopenharmony_ci 2315141cc406Sopenharmony_ci s->sense_key = status_buf[1] & 0x0f; 2316141cc406Sopenharmony_ci s->sense_asc = status_buf[2] & 0xff; 2317141cc406Sopenharmony_ci s->sense_ascq = status_buf[3] & 0xff; 2318141cc406Sopenharmony_ci s->sense_info = status_buf[4] & 0xff; 2319141cc406Sopenharmony_ci status = cs3_parse_sense_data(s); 2320141cc406Sopenharmony_ci break; 2321141cc406Sopenharmony_ci } 2322141cc406Sopenharmony_ci 2323141cc406Sopenharmony_ci if (status_only) 2324141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2325141cc406Sopenharmony_ci else 2326141cc406Sopenharmony_ci return status; 2327141cc406Sopenharmony_ci} 2328141cc406Sopenharmony_ci 2329141cc406Sopenharmony_cistatic cs3_phase_t 2330141cc406Sopenharmony_cics3_phase_check(cs3_t * s) 2331141cc406Sopenharmony_ci{ 2332141cc406Sopenharmony_ci static SANE_Byte phase_send_buf[1] = { 0xd0 }, phase_recv_buf[1]; 2333141cc406Sopenharmony_ci SANE_Status status = 0; 2334141cc406Sopenharmony_ci size_t n = 1; 2335141cc406Sopenharmony_ci 2336141cc406Sopenharmony_ci status = sanei_usb_write_bulk(s->fd, phase_send_buf, &n); 2337141cc406Sopenharmony_ci status |= sanei_usb_read_bulk(s->fd, phase_recv_buf, &n); 2338141cc406Sopenharmony_ci 2339141cc406Sopenharmony_ci DBG(40, "%s: returned phase = 0x%02x.\n", __func__, 2340141cc406Sopenharmony_ci phase_recv_buf[0]); 2341141cc406Sopenharmony_ci 2342141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2343141cc406Sopenharmony_ci return -1; 2344141cc406Sopenharmony_ci else 2345141cc406Sopenharmony_ci return phase_recv_buf[0]; 2346141cc406Sopenharmony_ci} 2347141cc406Sopenharmony_ci 2348141cc406Sopenharmony_cistatic SANE_Status 2349141cc406Sopenharmony_cics3_scanner_ready(cs3_t * s, int flags) 2350141cc406Sopenharmony_ci{ 2351141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 2352141cc406Sopenharmony_ci int i = -1; 2353141cc406Sopenharmony_ci unsigned long count = 0; 2354141cc406Sopenharmony_ci int retry = 3; 2355141cc406Sopenharmony_ci 2356141cc406Sopenharmony_ci do { 2357141cc406Sopenharmony_ci if (i >= 0) /* dirty !!! */ 2358141cc406Sopenharmony_ci usleep(1000000); 2359141cc406Sopenharmony_ci /* test unit ready */ 2360141cc406Sopenharmony_ci cs3_init_buffer(s); 2361141cc406Sopenharmony_ci for (i = 0; i < 6; i++) 2362141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); 2363141cc406Sopenharmony_ci 2364141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2365141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2366141cc406Sopenharmony_ci if (--retry < 0) 2367141cc406Sopenharmony_ci return status; 2368141cc406Sopenharmony_ci 2369141cc406Sopenharmony_ci if (++count > 120) { /* 120s timeout */ 2370141cc406Sopenharmony_ci DBG(4, "Error: %s: Timeout expired.\n", __func__); 2371141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 2372141cc406Sopenharmony_ci break; 2373141cc406Sopenharmony_ci } 2374141cc406Sopenharmony_ci } 2375141cc406Sopenharmony_ci while (s->status & ~flags); /* until all relevant bits are 0 */ 2376141cc406Sopenharmony_ci 2377141cc406Sopenharmony_ci return status; 2378141cc406Sopenharmony_ci} 2379141cc406Sopenharmony_ci 2380141cc406Sopenharmony_cistatic SANE_Status 2381141cc406Sopenharmony_cics3_page_inquiry(cs3_t * s, int page) 2382141cc406Sopenharmony_ci{ 2383141cc406Sopenharmony_ci SANE_Status status; 2384141cc406Sopenharmony_ci 2385141cc406Sopenharmony_ci size_t n; 2386141cc406Sopenharmony_ci 2387141cc406Sopenharmony_ci if (page >= 0) { 2388141cc406Sopenharmony_ci 2389141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2390141cc406Sopenharmony_ci cs3_init_buffer(s); 2391141cc406Sopenharmony_ci cs3_parse_cmd(s, "12 01"); 2392141cc406Sopenharmony_ci cs3_pack_byte(s, page); 2393141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 04 00"); 2394141cc406Sopenharmony_ci s->n_recv = 4; 2395141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2396141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2397141cc406Sopenharmony_ci DBG(4, 2398141cc406Sopenharmony_ci "Error: cs3_page_inquiry(): Inquiry of page size failed: %s.\n", 2399141cc406Sopenharmony_ci sane_strstatus(status)); 2400141cc406Sopenharmony_ci return status; 2401141cc406Sopenharmony_ci } 2402141cc406Sopenharmony_ci 2403141cc406Sopenharmony_ci n = s->recv_buf[3] + 4; 2404141cc406Sopenharmony_ci 2405141cc406Sopenharmony_ci } else 2406141cc406Sopenharmony_ci n = 36; 2407141cc406Sopenharmony_ci 2408141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2409141cc406Sopenharmony_ci cs3_init_buffer(s); 2410141cc406Sopenharmony_ci if (page >= 0) { 2411141cc406Sopenharmony_ci cs3_parse_cmd(s, "12 01"); 2412141cc406Sopenharmony_ci cs3_pack_byte(s, page); 2413141cc406Sopenharmony_ci cs3_parse_cmd(s, "00"); 2414141cc406Sopenharmony_ci } else 2415141cc406Sopenharmony_ci cs3_parse_cmd(s, "12 00 00 00"); 2416141cc406Sopenharmony_ci cs3_pack_byte(s, n); 2417141cc406Sopenharmony_ci cs3_parse_cmd(s, "00"); 2418141cc406Sopenharmony_ci s->n_recv = n; 2419141cc406Sopenharmony_ci 2420141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2421141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2422141cc406Sopenharmony_ci DBG(4, "Error: %s: inquiry of page failed: %s.\n", 2423141cc406Sopenharmony_ci __func__, sane_strstatus(status)); 2424141cc406Sopenharmony_ci return status; 2425141cc406Sopenharmony_ci } 2426141cc406Sopenharmony_ci 2427141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2428141cc406Sopenharmony_ci} 2429141cc406Sopenharmony_ci 2430141cc406Sopenharmony_cistatic SANE_Status 2431141cc406Sopenharmony_cics3_full_inquiry(cs3_t * s) 2432141cc406Sopenharmony_ci{ 2433141cc406Sopenharmony_ci SANE_Status status; 2434141cc406Sopenharmony_ci int pitch, pitch_max; 2435141cc406Sopenharmony_ci cs3_pixel_t pixel; 2436141cc406Sopenharmony_ci 2437141cc406Sopenharmony_ci DBG(4, "%s\n", __func__); 2438141cc406Sopenharmony_ci 2439141cc406Sopenharmony_ci status = cs3_page_inquiry(s, 0xc1); 2440141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2441141cc406Sopenharmony_ci return status; 2442141cc406Sopenharmony_ci 2443141cc406Sopenharmony_ci s->maxbits = s->recv_buf[82]; 2444141cc406Sopenharmony_ci if (s->type == CS3_TYPE_LS30) /* must be overridden, LS-30 claims to have 12 bits */ 2445141cc406Sopenharmony_ci s->maxbits = 10; 2446141cc406Sopenharmony_ci 2447141cc406Sopenharmony_ci s->n_lut = 1; 2448141cc406Sopenharmony_ci s->n_lut <<= s->maxbits; 2449141cc406Sopenharmony_ci s->lut_r = 2450141cc406Sopenharmony_ci (cs3_pixel_t *) cs3_xrealloc(s->lut_r, 2451141cc406Sopenharmony_ci s->n_lut * sizeof(cs3_pixel_t)); 2452141cc406Sopenharmony_ci s->lut_g = 2453141cc406Sopenharmony_ci (cs3_pixel_t *) cs3_xrealloc(s->lut_g, 2454141cc406Sopenharmony_ci s->n_lut * sizeof(cs3_pixel_t)); 2455141cc406Sopenharmony_ci s->lut_b = 2456141cc406Sopenharmony_ci (cs3_pixel_t *) cs3_xrealloc(s->lut_b, 2457141cc406Sopenharmony_ci s->n_lut * sizeof(cs3_pixel_t)); 2458141cc406Sopenharmony_ci s->lut_neutral = 2459141cc406Sopenharmony_ci (cs3_pixel_t *) cs3_xrealloc(s->lut_neutral, 2460141cc406Sopenharmony_ci s->n_lut * sizeof(cs3_pixel_t)); 2461141cc406Sopenharmony_ci 2462141cc406Sopenharmony_ci if (!s->lut_r || !s->lut_g || !s->lut_b || !s->lut_neutral) { 2463141cc406Sopenharmony_ci cs3_xfree(s->lut_r); 2464141cc406Sopenharmony_ci cs3_xfree(s->lut_g); 2465141cc406Sopenharmony_ci cs3_xfree(s->lut_b); 2466141cc406Sopenharmony_ci cs3_xfree(s->lut_neutral); 2467141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2468141cc406Sopenharmony_ci } 2469141cc406Sopenharmony_ci 2470141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) { 2471141cc406Sopenharmony_ci s->lut_r[pixel] = s->lut_g[pixel] = s->lut_b[pixel] = 2472141cc406Sopenharmony_ci s->lut_neutral[pixel] = pixel; 2473141cc406Sopenharmony_ci } 2474141cc406Sopenharmony_ci 2475141cc406Sopenharmony_ci s->resx_optical = 256 * s->recv_buf[18] + s->recv_buf[19]; 2476141cc406Sopenharmony_ci s->resx_max = 256 * s->recv_buf[20] + s->recv_buf[21]; 2477141cc406Sopenharmony_ci s->resx_min = 256 * s->recv_buf[22] + s->recv_buf[23]; 2478141cc406Sopenharmony_ci s->boundaryx = 2479141cc406Sopenharmony_ci 65536 * (256 * s->recv_buf[36] + s->recv_buf[37]) + 2480141cc406Sopenharmony_ci 256 * s->recv_buf[38] + s->recv_buf[39]; 2481141cc406Sopenharmony_ci 2482141cc406Sopenharmony_ci s->resy_optical = 256 * s->recv_buf[40] + s->recv_buf[41]; 2483141cc406Sopenharmony_ci s->resy_max = 256 * s->recv_buf[42] + s->recv_buf[43]; 2484141cc406Sopenharmony_ci s->resy_min = 256 * s->recv_buf[44] + s->recv_buf[45]; 2485141cc406Sopenharmony_ci s->boundaryy = 2486141cc406Sopenharmony_ci 65536 * (256 * s->recv_buf[58] + s->recv_buf[59]) + 2487141cc406Sopenharmony_ci 256 * s->recv_buf[60] + s->recv_buf[61]; 2488141cc406Sopenharmony_ci 2489141cc406Sopenharmony_ci s->focus_min = 256 * s->recv_buf[76] + s->recv_buf[77]; 2490141cc406Sopenharmony_ci s->focus_max = 256 * s->recv_buf[78] + s->recv_buf[79]; 2491141cc406Sopenharmony_ci 2492141cc406Sopenharmony_ci s->n_frames = s->recv_buf[75]; 2493141cc406Sopenharmony_ci 2494141cc406Sopenharmony_ci s->frame_offset = s->resy_max * 1.5 + 1; /* works for LS-30, maybe not for others */ 2495141cc406Sopenharmony_ci 2496141cc406Sopenharmony_ci /* generate resolution list for x */ 2497141cc406Sopenharmony_ci s->resx_n_list = pitch_max = 2498141cc406Sopenharmony_ci floor(s->resx_max / (double) s->resx_min); 2499141cc406Sopenharmony_ci s->resx_list = 2500141cc406Sopenharmony_ci (unsigned int *) cs3_xrealloc(s->resx_list, 2501141cc406Sopenharmony_ci pitch_max * 2502141cc406Sopenharmony_ci sizeof(unsigned int)); 2503141cc406Sopenharmony_ci for (pitch = 1; pitch <= pitch_max; pitch++) 2504141cc406Sopenharmony_ci s->resx_list[pitch - 1] = s->resx_max / pitch; 2505141cc406Sopenharmony_ci 2506141cc406Sopenharmony_ci /* generate resolution list for y */ 2507141cc406Sopenharmony_ci s->resy_n_list = pitch_max = 2508141cc406Sopenharmony_ci floor(s->resy_max / (double) s->resy_min); 2509141cc406Sopenharmony_ci s->resy_list = 2510141cc406Sopenharmony_ci (unsigned int *) cs3_xrealloc(s->resy_list, 2511141cc406Sopenharmony_ci pitch_max * 2512141cc406Sopenharmony_ci sizeof(unsigned int)); 2513141cc406Sopenharmony_ci 2514141cc406Sopenharmony_ci for (pitch = 1; pitch <= pitch_max; pitch++) 2515141cc406Sopenharmony_ci s->resy_list[pitch - 1] = s->resy_max / pitch; 2516141cc406Sopenharmony_ci 2517141cc406Sopenharmony_ci s->unit_dpi = s->resx_max; 2518141cc406Sopenharmony_ci s->unit_mm = 25.4 / s->unit_dpi; 2519141cc406Sopenharmony_ci 2520141cc406Sopenharmony_ci DBG(4, " maximum depth: %d\n", s->maxbits); 2521141cc406Sopenharmony_ci DBG(4, " focus: %d/%d\n", s->focus_min, s->focus_max); 2522141cc406Sopenharmony_ci DBG(4, " resolution (x): %d (%d-%d)\n", s->resx_optical, 2523141cc406Sopenharmony_ci s->resx_min, s->resx_max); 2524141cc406Sopenharmony_ci DBG(4, " resolution (y): %d (%d-%d)\n", s->resy_optical, 2525141cc406Sopenharmony_ci s->resy_min, s->resy_max); 2526141cc406Sopenharmony_ci DBG(4, " frames: %d\n", s->n_frames); 2527141cc406Sopenharmony_ci DBG(4, " frame offset: %ld\n", s->frame_offset); 2528141cc406Sopenharmony_ci 2529141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2530141cc406Sopenharmony_ci} 2531141cc406Sopenharmony_ci 2532141cc406Sopenharmony_cistatic SANE_Status 2533141cc406Sopenharmony_cics3_execute(cs3_t * s) 2534141cc406Sopenharmony_ci{ 2535141cc406Sopenharmony_ci DBG(16, "%s\n", __func__); 2536141cc406Sopenharmony_ci 2537141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2538141cc406Sopenharmony_ci cs3_init_buffer(s); 2539141cc406Sopenharmony_ci cs3_parse_cmd(s, "c1 00 00 00 00 00"); 2540141cc406Sopenharmony_ci return cs3_issue_cmd(s); 2541141cc406Sopenharmony_ci} 2542141cc406Sopenharmony_ci 2543141cc406Sopenharmony_cistatic SANE_Status 2544141cc406Sopenharmony_cics3_issue_and_execute(cs3_t * s) 2545141cc406Sopenharmony_ci{ 2546141cc406Sopenharmony_ci SANE_Status status; 2547141cc406Sopenharmony_ci 2548141cc406Sopenharmony_ci DBG(10, "%s, opcode = %02x\n", __func__, s->send_buf[0]); 2549141cc406Sopenharmony_ci 2550141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2551141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2552141cc406Sopenharmony_ci return status; 2553141cc406Sopenharmony_ci 2554141cc406Sopenharmony_ci return cs3_execute(s); 2555141cc406Sopenharmony_ci} 2556141cc406Sopenharmony_ci 2557141cc406Sopenharmony_cistatic SANE_Status 2558141cc406Sopenharmony_cics3_mode_select(cs3_t * s) 2559141cc406Sopenharmony_ci{ 2560141cc406Sopenharmony_ci DBG(4, "%s\n", __func__); 2561141cc406Sopenharmony_ci 2562141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2563141cc406Sopenharmony_ci cs3_init_buffer(s); 2564141cc406Sopenharmony_ci 2565141cc406Sopenharmony_ci cs3_parse_cmd(s, 2566141cc406Sopenharmony_ci "15 10 00 00 14 00 00 00 00 08 00 00 00 00 00 00 00 01 03 06 00 00"); 2567141cc406Sopenharmony_ci cs3_pack_word(s, s->unit_dpi); 2568141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00"); 2569141cc406Sopenharmony_ci 2570141cc406Sopenharmony_ci return cs3_issue_cmd(s); 2571141cc406Sopenharmony_ci} 2572141cc406Sopenharmony_ci 2573141cc406Sopenharmony_cistatic SANE_Status 2574141cc406Sopenharmony_cics3_load(cs3_t * s) 2575141cc406Sopenharmony_ci{ 2576141cc406Sopenharmony_ci SANE_Status status; 2577141cc406Sopenharmony_ci 2578141cc406Sopenharmony_ci DBG(6, "%s\n", __func__); 2579141cc406Sopenharmony_ci 2580141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2581141cc406Sopenharmony_ci cs3_init_buffer(s); 2582141cc406Sopenharmony_ci cs3_parse_cmd(s, "e0 00 d1 00 00 00 00 00 0d 00"); 2583141cc406Sopenharmony_ci s->n_send += 13; 2584141cc406Sopenharmony_ci 2585141cc406Sopenharmony_ci status = cs3_grow_send_buffer(s); 2586141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2587141cc406Sopenharmony_ci return status; 2588141cc406Sopenharmony_ci 2589141cc406Sopenharmony_ci return cs3_issue_and_execute(s); 2590141cc406Sopenharmony_ci} 2591141cc406Sopenharmony_ci 2592141cc406Sopenharmony_cistatic SANE_Status 2593141cc406Sopenharmony_cics3_eject(cs3_t * s) 2594141cc406Sopenharmony_ci{ 2595141cc406Sopenharmony_ci SANE_Status status; 2596141cc406Sopenharmony_ci 2597141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2598141cc406Sopenharmony_ci cs3_init_buffer(s); 2599141cc406Sopenharmony_ci cs3_parse_cmd(s, "e0 00 d0 00 00 00 00 00 0d 00"); 2600141cc406Sopenharmony_ci s->n_send += 13; 2601141cc406Sopenharmony_ci 2602141cc406Sopenharmony_ci status = cs3_grow_send_buffer(s); 2603141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2604141cc406Sopenharmony_ci return status; 2605141cc406Sopenharmony_ci 2606141cc406Sopenharmony_ci return cs3_issue_and_execute(s); 2607141cc406Sopenharmony_ci} 2608141cc406Sopenharmony_ci 2609141cc406Sopenharmony_cistatic SANE_Status 2610141cc406Sopenharmony_cics3_reset(cs3_t * s) 2611141cc406Sopenharmony_ci{ 2612141cc406Sopenharmony_ci SANE_Status status; 2613141cc406Sopenharmony_ci 2614141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2615141cc406Sopenharmony_ci cs3_init_buffer(s); 2616141cc406Sopenharmony_ci cs3_parse_cmd(s, "e0 00 80 00 00 00 00 00 0d 00"); 2617141cc406Sopenharmony_ci s->n_send += 13; 2618141cc406Sopenharmony_ci 2619141cc406Sopenharmony_ci status = cs3_grow_send_buffer(s); 2620141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2621141cc406Sopenharmony_ci return status; 2622141cc406Sopenharmony_ci 2623141cc406Sopenharmony_ci return cs3_issue_and_execute(s); 2624141cc406Sopenharmony_ci} 2625141cc406Sopenharmony_ci 2626141cc406Sopenharmony_ci 2627141cc406Sopenharmony_cistatic SANE_Status 2628141cc406Sopenharmony_cics3_reserve_unit(cs3_t * s) 2629141cc406Sopenharmony_ci{ 2630141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 2631141cc406Sopenharmony_ci 2632141cc406Sopenharmony_ci cs3_init_buffer(s); 2633141cc406Sopenharmony_ci cs3_parse_cmd(s, "16 00 00 00 00 00"); 2634141cc406Sopenharmony_ci return cs3_issue_cmd(s); 2635141cc406Sopenharmony_ci} 2636141cc406Sopenharmony_ci 2637141cc406Sopenharmony_cistatic SANE_Status 2638141cc406Sopenharmony_cics3_release_unit(cs3_t * s) 2639141cc406Sopenharmony_ci{ 2640141cc406Sopenharmony_ci DBG(10, "%s\n", __func__); 2641141cc406Sopenharmony_ci 2642141cc406Sopenharmony_ci cs3_init_buffer(s); 2643141cc406Sopenharmony_ci cs3_parse_cmd(s, "17 00 00 00 00 00"); 2644141cc406Sopenharmony_ci return cs3_issue_cmd(s); 2645141cc406Sopenharmony_ci} 2646141cc406Sopenharmony_ci 2647141cc406Sopenharmony_ci 2648141cc406Sopenharmony_cistatic SANE_Status 2649141cc406Sopenharmony_cics3_set_focus(cs3_t * s) 2650141cc406Sopenharmony_ci{ 2651141cc406Sopenharmony_ci DBG(6, "%s: setting focus to %d\n", __func__, s->focus); 2652141cc406Sopenharmony_ci 2653141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 2654141cc406Sopenharmony_ci cs3_init_buffer(s); 2655141cc406Sopenharmony_ci cs3_parse_cmd(s, "e0 00 c1 00 00 00 00 00 09 00 00"); 2656141cc406Sopenharmony_ci cs3_pack_long(s, s->focus); 2657141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00 00 00"); 2658141cc406Sopenharmony_ci 2659141cc406Sopenharmony_ci return cs3_issue_and_execute(s); 2660141cc406Sopenharmony_ci} 2661141cc406Sopenharmony_ci 2662141cc406Sopenharmony_cistatic SANE_Status 2663141cc406Sopenharmony_cics3_read_focus(cs3_t * s) 2664141cc406Sopenharmony_ci{ 2665141cc406Sopenharmony_ci SANE_Status status; 2666141cc406Sopenharmony_ci 2667141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 2668141cc406Sopenharmony_ci cs3_init_buffer(s); 2669141cc406Sopenharmony_ci cs3_parse_cmd(s, "e1 00 c1 00 00 00 00 00 0d 00"); 2670141cc406Sopenharmony_ci s->n_recv = 13; 2671141cc406Sopenharmony_ci 2672141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2673141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2674141cc406Sopenharmony_ci return status; 2675141cc406Sopenharmony_ci 2676141cc406Sopenharmony_ci s->focus = 2677141cc406Sopenharmony_ci 65536 * (256 * s->recv_buf[1] + s->recv_buf[2]) + 2678141cc406Sopenharmony_ci 256 * s->recv_buf[3] + s->recv_buf[4]; 2679141cc406Sopenharmony_ci 2680141cc406Sopenharmony_ci DBG(4, "%s: focus at %d\n", __func__, s->focus); 2681141cc406Sopenharmony_ci 2682141cc406Sopenharmony_ci return status; 2683141cc406Sopenharmony_ci} 2684141cc406Sopenharmony_ci 2685141cc406Sopenharmony_cistatic SANE_Status 2686141cc406Sopenharmony_cics3_autofocus(cs3_t * s) 2687141cc406Sopenharmony_ci{ 2688141cc406Sopenharmony_ci SANE_Status status; 2689141cc406Sopenharmony_ci 2690141cc406Sopenharmony_ci DBG(6, "%s: focusing at %ld,%ld\n", __func__, 2691141cc406Sopenharmony_ci s->real_focusx, s->real_focusy); 2692141cc406Sopenharmony_ci 2693141cc406Sopenharmony_ci cs3_convert_options(s); 2694141cc406Sopenharmony_ci 2695141cc406Sopenharmony_ci status = cs3_read_focus(s); 2696141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2697141cc406Sopenharmony_ci return status; 2698141cc406Sopenharmony_ci 2699141cc406Sopenharmony_ci /* set parameter, autofocus */ 2700141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 2701141cc406Sopenharmony_ci cs3_init_buffer(s); 2702141cc406Sopenharmony_ci cs3_parse_cmd(s, "e0 00 a0 00 00 00 00 00 09 00 00"); 2703141cc406Sopenharmony_ci cs3_pack_long(s, s->real_focusx); 2704141cc406Sopenharmony_ci cs3_pack_long(s, s->real_focusy); 2705141cc406Sopenharmony_ci /*cs3_parse_cmd(s, "00 00 00 00"); */ 2706141cc406Sopenharmony_ci 2707141cc406Sopenharmony_ci status = cs3_issue_and_execute(s); 2708141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2709141cc406Sopenharmony_ci return status; 2710141cc406Sopenharmony_ci 2711141cc406Sopenharmony_ci return cs3_read_focus(s); 2712141cc406Sopenharmony_ci} 2713141cc406Sopenharmony_ci 2714141cc406Sopenharmony_cistatic SANE_Status 2715141cc406Sopenharmony_cics3_autoexposure(cs3_t * s, int wb) 2716141cc406Sopenharmony_ci{ 2717141cc406Sopenharmony_ci SANE_Status status; 2718141cc406Sopenharmony_ci 2719141cc406Sopenharmony_ci DBG(6, "%s, wb = %d\n", __func__, wb); 2720141cc406Sopenharmony_ci 2721141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2722141cc406Sopenharmony_ci status = cs3_scan(s, wb ? CS3_SCAN_AE_WB : CS3_SCAN_AE); 2723141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2724141cc406Sopenharmony_ci return status; 2725141cc406Sopenharmony_ci 2726141cc406Sopenharmony_ci status = cs3_get_exposure(s); 2727141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2728141cc406Sopenharmony_ci return status; 2729141cc406Sopenharmony_ci 2730141cc406Sopenharmony_ci s->exposure = 1.; 2731141cc406Sopenharmony_ci s->exposure_r = s->real_exposure[1] / 100.; 2732141cc406Sopenharmony_ci s->exposure_g = s->real_exposure[2] / 100.; 2733141cc406Sopenharmony_ci s->exposure_b = s->real_exposure[3] / 100.; 2734141cc406Sopenharmony_ci 2735141cc406Sopenharmony_ci return status; 2736141cc406Sopenharmony_ci} 2737141cc406Sopenharmony_ci 2738141cc406Sopenharmony_cistatic SANE_Status 2739141cc406Sopenharmony_cics3_get_exposure(cs3_t * s) 2740141cc406Sopenharmony_ci{ 2741141cc406Sopenharmony_ci SANE_Status status; 2742141cc406Sopenharmony_ci int i_color, colors = s->n_colors; 2743141cc406Sopenharmony_ci 2744141cc406Sopenharmony_ci DBG(6, "%s\n", __func__); 2745141cc406Sopenharmony_ci 2746141cc406Sopenharmony_ci if ((s->type == CS3_TYPE_LS50) || (s->type == CS3_TYPE_LS5000)) 2747141cc406Sopenharmony_ci colors = 3; 2748141cc406Sopenharmony_ci 2749141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 2750141cc406Sopenharmony_ci 2751141cc406Sopenharmony_ci /* GET WINDOW */ 2752141cc406Sopenharmony_ci for (i_color = 0; i_color < colors; i_color++) { /* XXXXXXXXXXXXX CCCCCCCCCCCCC */ 2753141cc406Sopenharmony_ci 2754141cc406Sopenharmony_ci cs3_init_buffer(s); 2755141cc406Sopenharmony_ci cs3_parse_cmd(s, "25 01 00 00 00"); 2756141cc406Sopenharmony_ci cs3_pack_byte(s, cs3_colors[i_color]); 2757141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00 3a 00"); 2758141cc406Sopenharmony_ci s->n_recv = 58; 2759141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2760141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2761141cc406Sopenharmony_ci return status; 2762141cc406Sopenharmony_ci 2763141cc406Sopenharmony_ci s->real_exposure[cs3_colors[i_color]] = 2764141cc406Sopenharmony_ci 65536 * (256 * s->recv_buf[54] + s->recv_buf[55]) + 2765141cc406Sopenharmony_ci 256 * s->recv_buf[56] + s->recv_buf[57]; 2766141cc406Sopenharmony_ci 2767141cc406Sopenharmony_ci DBG(6, 2768141cc406Sopenharmony_ci "%s, exposure for color %i: %li * 10ns\n", 2769141cc406Sopenharmony_ci __func__, 2770141cc406Sopenharmony_ci cs3_colors[i_color], 2771141cc406Sopenharmony_ci s->real_exposure[cs3_colors[i_color]]); 2772141cc406Sopenharmony_ci 2773141cc406Sopenharmony_ci DBG(6, "%02x %02x %02x %02x\n", s->recv_buf[48], 2774141cc406Sopenharmony_ci s->recv_buf[49], s->recv_buf[50], s->recv_buf[51]); 2775141cc406Sopenharmony_ci } 2776141cc406Sopenharmony_ci 2777141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2778141cc406Sopenharmony_ci} 2779141cc406Sopenharmony_ci 2780141cc406Sopenharmony_cistatic SANE_Status 2781141cc406Sopenharmony_cics3_convert_options(cs3_t * s) 2782141cc406Sopenharmony_ci{ 2783141cc406Sopenharmony_ci int i_color; 2784141cc406Sopenharmony_ci unsigned long xmin, xmax, ymin, ymax; 2785141cc406Sopenharmony_ci 2786141cc406Sopenharmony_ci DBG(4, "%s\n", __func__); 2787141cc406Sopenharmony_ci 2788141cc406Sopenharmony_ci s->real_depth = (s->preview ? 8 : s->depth); 2789141cc406Sopenharmony_ci s->bytes_per_pixel = (s->real_depth > 8 ? 2 : 1); 2790141cc406Sopenharmony_ci s->shift_bits = 8 * s->bytes_per_pixel - s->real_depth; 2791141cc406Sopenharmony_ci 2792141cc406Sopenharmony_ci DBG(12, " depth = %d, bpp = %d, shift = %d\n", 2793141cc406Sopenharmony_ci s->real_depth, s->bytes_per_pixel, s->shift_bits); 2794141cc406Sopenharmony_ci 2795141cc406Sopenharmony_ci if (s->preview) { 2796141cc406Sopenharmony_ci s->real_resx = s->res_preview; 2797141cc406Sopenharmony_ci s->real_resy = s->res_preview; 2798141cc406Sopenharmony_ci } else if (s->res_independent) { 2799141cc406Sopenharmony_ci s->real_resx = s->resx; 2800141cc406Sopenharmony_ci s->real_resy = s->resy; 2801141cc406Sopenharmony_ci } else { 2802141cc406Sopenharmony_ci s->real_resx = s->res; 2803141cc406Sopenharmony_ci s->real_resy = s->res; 2804141cc406Sopenharmony_ci } 2805141cc406Sopenharmony_ci 2806141cc406Sopenharmony_ci s->real_pitchx = s->resx_max / s->real_resx; 2807141cc406Sopenharmony_ci s->real_pitchy = s->resy_max / s->real_resy; 2808141cc406Sopenharmony_ci 2809141cc406Sopenharmony_ci s->real_resx = s->resx_max / s->real_pitchx; 2810141cc406Sopenharmony_ci s->real_resy = s->resy_max / s->real_pitchy; 2811141cc406Sopenharmony_ci 2812141cc406Sopenharmony_ci DBG(12, " resx = %d, resy = %d, pitchx = %d, pitchy = %d\n", 2813141cc406Sopenharmony_ci s->real_resx, s->real_resy, s->real_pitchx, s->real_pitchy); 2814141cc406Sopenharmony_ci 2815141cc406Sopenharmony_ci /* The prefix "real_" refers to data in device units (1/maxdpi), 2816141cc406Sopenharmony_ci * "logical_" refers to resolution-dependent data. 2817141cc406Sopenharmony_ci */ 2818141cc406Sopenharmony_ci 2819141cc406Sopenharmony_ci if (s->xmin < s->xmax) { 2820141cc406Sopenharmony_ci xmin = s->xmin; 2821141cc406Sopenharmony_ci xmax = s->xmax; 2822141cc406Sopenharmony_ci } else { 2823141cc406Sopenharmony_ci xmin = s->xmax; 2824141cc406Sopenharmony_ci xmax = s->xmin; 2825141cc406Sopenharmony_ci } 2826141cc406Sopenharmony_ci 2827141cc406Sopenharmony_ci if (s->ymin < s->ymax) { 2828141cc406Sopenharmony_ci ymin = s->ymin; 2829141cc406Sopenharmony_ci ymax = s->ymax; 2830141cc406Sopenharmony_ci } else { 2831141cc406Sopenharmony_ci ymin = s->ymax; 2832141cc406Sopenharmony_ci ymax = s->ymin; 2833141cc406Sopenharmony_ci } 2834141cc406Sopenharmony_ci 2835141cc406Sopenharmony_ci DBG(12, " xmin = %ld, xmax = %ld\n", xmin, xmax); 2836141cc406Sopenharmony_ci DBG(12, " ymin = %ld, ymax = %ld\n", ymin, ymax); 2837141cc406Sopenharmony_ci 2838141cc406Sopenharmony_ci s->real_xoffset = xmin; 2839141cc406Sopenharmony_ci s->real_yoffset = 2840141cc406Sopenharmony_ci ymin + (s->i_frame - 1) * s->frame_offset + 2841141cc406Sopenharmony_ci s->subframe / s->unit_mm; 2842141cc406Sopenharmony_ci 2843141cc406Sopenharmony_ci DBG(12, " xoffset = %ld, yoffset = %ld\n", 2844141cc406Sopenharmony_ci s->real_xoffset, s->real_yoffset); 2845141cc406Sopenharmony_ci 2846141cc406Sopenharmony_ci 2847141cc406Sopenharmony_ci s->logical_width = (xmax - xmin + 1) / s->real_pitchx; /* XXX use mm units */ 2848141cc406Sopenharmony_ci s->logical_height = (ymax - ymin + 1) / s->real_pitchy; 2849141cc406Sopenharmony_ci s->real_width = s->logical_width * s->real_pitchx; 2850141cc406Sopenharmony_ci s->real_height = s->logical_height * s->real_pitchy; 2851141cc406Sopenharmony_ci 2852141cc406Sopenharmony_ci DBG(12, " lw = %ld, lh = %ld, rw = %ld, rh = %ld\n", 2853141cc406Sopenharmony_ci s->logical_width, s->logical_height, 2854141cc406Sopenharmony_ci s->real_width, s->real_height); 2855141cc406Sopenharmony_ci 2856141cc406Sopenharmony_ci s->odd_padding = 0; 2857141cc406Sopenharmony_ci if ((s->bytes_per_pixel == 1) && (s->logical_width & 0x01) 2858141cc406Sopenharmony_ci && (s->type != CS3_TYPE_LS30) && (s->type != CS3_TYPE_LS2000)) 2859141cc406Sopenharmony_ci s->odd_padding = 1; 2860141cc406Sopenharmony_ci 2861141cc406Sopenharmony_ci if (s->focus_on_centre) { 2862141cc406Sopenharmony_ci s->real_focusx = s->real_xoffset + s->real_width / 2; 2863141cc406Sopenharmony_ci s->real_focusy = s->real_yoffset + s->real_height / 2; 2864141cc406Sopenharmony_ci } else { 2865141cc406Sopenharmony_ci s->real_focusx = s->focusx; 2866141cc406Sopenharmony_ci s->real_focusy = 2867141cc406Sopenharmony_ci s->focusy + (s->i_frame - 1) * s->frame_offset + 2868141cc406Sopenharmony_ci s->subframe / s->unit_mm; 2869141cc406Sopenharmony_ci } 2870141cc406Sopenharmony_ci 2871141cc406Sopenharmony_ci DBG(12, " focusx = %ld, focusy = %ld\n", 2872141cc406Sopenharmony_ci s->real_focusx, s->real_focusy); 2873141cc406Sopenharmony_ci 2874141cc406Sopenharmony_ci s->real_exposure[1] = s->exposure * s->exposure_r * 100.; 2875141cc406Sopenharmony_ci s->real_exposure[2] = s->exposure * s->exposure_g * 100.; 2876141cc406Sopenharmony_ci s->real_exposure[3] = s->exposure * s->exposure_b * 100.; 2877141cc406Sopenharmony_ci 2878141cc406Sopenharmony_ci /* XXX IR? */ 2879141cc406Sopenharmony_ci for (i_color = 0; i_color < 3; i_color++) 2880141cc406Sopenharmony_ci if (s->real_exposure[cs3_colors[i_color]] < 1) 2881141cc406Sopenharmony_ci s->real_exposure[cs3_colors[i_color]] = 1; 2882141cc406Sopenharmony_ci 2883141cc406Sopenharmony_ci s->n_colors = 3; /* XXXXXXXXXXXXXX CCCCCCCCCCCCCC */ 2884141cc406Sopenharmony_ci if (s->infrared) 2885141cc406Sopenharmony_ci s->n_colors = 4; 2886141cc406Sopenharmony_ci 2887141cc406Sopenharmony_ci s->xfer_bytes_total = 2888141cc406Sopenharmony_ci s->bytes_per_pixel * s->n_colors * s->logical_width * 2889141cc406Sopenharmony_ci s->logical_height; 2890141cc406Sopenharmony_ci 2891141cc406Sopenharmony_ci if (s->preview) 2892141cc406Sopenharmony_ci s->infrared = SANE_FALSE; 2893141cc406Sopenharmony_ci 2894141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2895141cc406Sopenharmony_ci} 2896141cc406Sopenharmony_ci 2897141cc406Sopenharmony_cistatic SANE_Status 2898141cc406Sopenharmony_cics3_set_boundary(cs3_t * s) 2899141cc406Sopenharmony_ci{ 2900141cc406Sopenharmony_ci SANE_Status status; 2901141cc406Sopenharmony_ci int i_boundary; 2902141cc406Sopenharmony_ci 2903141cc406Sopenharmony_ci /* Ariel - Check this function */ 2904141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 2905141cc406Sopenharmony_ci cs3_init_buffer(s); 2906141cc406Sopenharmony_ci cs3_parse_cmd(s, "2a 00 88 00 00 03"); 2907141cc406Sopenharmony_ci cs3_pack_byte(s, ((4 + s->n_frames * 16) >> 16) & 0xff); 2908141cc406Sopenharmony_ci cs3_pack_byte(s, ((4 + s->n_frames * 16) >> 8) & 0xff); 2909141cc406Sopenharmony_ci cs3_pack_byte(s, (4 + s->n_frames * 16) & 0xff); 2910141cc406Sopenharmony_ci cs3_parse_cmd(s, "00"); 2911141cc406Sopenharmony_ci 2912141cc406Sopenharmony_ci cs3_pack_byte(s, ((4 + s->n_frames * 16) >> 8) & 0xff); 2913141cc406Sopenharmony_ci cs3_pack_byte(s, (4 + s->n_frames * 16) & 0xff); 2914141cc406Sopenharmony_ci cs3_pack_byte(s, s->n_frames); 2915141cc406Sopenharmony_ci cs3_pack_byte(s, s->n_frames); 2916141cc406Sopenharmony_ci for (i_boundary = 0; i_boundary < s->n_frames; i_boundary++) { 2917141cc406Sopenharmony_ci unsigned long lvalue = s->frame_offset * i_boundary + 2918141cc406Sopenharmony_ci s->subframe / s->unit_mm; 2919141cc406Sopenharmony_ci 2920141cc406Sopenharmony_ci cs3_pack_long(s, lvalue); 2921141cc406Sopenharmony_ci 2922141cc406Sopenharmony_ci cs3_pack_long(s, 0); 2923141cc406Sopenharmony_ci 2924141cc406Sopenharmony_ci lvalue = s->frame_offset * i_boundary + 2925141cc406Sopenharmony_ci s->subframe / s->unit_mm + s->frame_offset - 1; 2926141cc406Sopenharmony_ci cs3_pack_long(s, lvalue); 2927141cc406Sopenharmony_ci 2928141cc406Sopenharmony_ci cs3_pack_long(s, s->boundaryx - 1); 2929141cc406Sopenharmony_ci 2930141cc406Sopenharmony_ci } 2931141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2932141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2933141cc406Sopenharmony_ci return status; 2934141cc406Sopenharmony_ci 2935141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2936141cc406Sopenharmony_ci} 2937141cc406Sopenharmony_ci 2938141cc406Sopenharmony_cistatic SANE_Status 2939141cc406Sopenharmony_cics3_send_lut(cs3_t * s) 2940141cc406Sopenharmony_ci{ 2941141cc406Sopenharmony_ci int color; 2942141cc406Sopenharmony_ci SANE_Status status; 2943141cc406Sopenharmony_ci cs3_pixel_t *lut, pixel; 2944141cc406Sopenharmony_ci 2945141cc406Sopenharmony_ci DBG(6, "%s\n", __func__); 2946141cc406Sopenharmony_ci 2947141cc406Sopenharmony_ci for (color = 0; color < s->n_colors; color++) { 2948141cc406Sopenharmony_ci /*cs3_scanner_ready(s, CS3_STATUS_READY); */ 2949141cc406Sopenharmony_ci 2950141cc406Sopenharmony_ci switch (color) { 2951141cc406Sopenharmony_ci case 0: 2952141cc406Sopenharmony_ci lut = s->lut_r; 2953141cc406Sopenharmony_ci break; 2954141cc406Sopenharmony_ci case 1: 2955141cc406Sopenharmony_ci lut = s->lut_g; 2956141cc406Sopenharmony_ci break; 2957141cc406Sopenharmony_ci case 2: 2958141cc406Sopenharmony_ci lut = s->lut_b; 2959141cc406Sopenharmony_ci break; 2960141cc406Sopenharmony_ci case 3: 2961141cc406Sopenharmony_ci lut = s->lut_neutral; 2962141cc406Sopenharmony_ci break; 2963141cc406Sopenharmony_ci default: 2964141cc406Sopenharmony_ci DBG(1, 2965141cc406Sopenharmony_ci "BUG: %s: Unknown color number for LUT download.\n", 2966141cc406Sopenharmony_ci __func__); 2967141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2968141cc406Sopenharmony_ci break; 2969141cc406Sopenharmony_ci } 2970141cc406Sopenharmony_ci 2971141cc406Sopenharmony_ci cs3_init_buffer(s); 2972141cc406Sopenharmony_ci cs3_parse_cmd(s, "2a 00 03 00"); 2973141cc406Sopenharmony_ci cs3_pack_byte(s, cs3_colors[color]); 2974141cc406Sopenharmony_ci cs3_pack_byte(s, 2 - 1); /* XXX number of bytes per data point - 1 */ 2975141cc406Sopenharmony_ci cs3_pack_byte(s, ((2 * s->n_lut) >> 16) & 0xff); /* XXX 2 bytes per point */ 2976141cc406Sopenharmony_ci cs3_pack_byte(s, ((2 * s->n_lut) >> 8) & 0xff); /* XXX 2 bytes per point */ 2977141cc406Sopenharmony_ci cs3_pack_byte(s, (2 * s->n_lut) & 0xff); /* XXX 2 bytes per point */ 2978141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); 2979141cc406Sopenharmony_ci 2980141cc406Sopenharmony_ci for (pixel = 0; pixel < s->n_lut; pixel++) { /* XXX 2 bytes per point */ 2981141cc406Sopenharmony_ci cs3_pack_word(s, lut[pixel]); 2982141cc406Sopenharmony_ci } 2983141cc406Sopenharmony_ci 2984141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 2985141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2986141cc406Sopenharmony_ci return status; 2987141cc406Sopenharmony_ci } 2988141cc406Sopenharmony_ci 2989141cc406Sopenharmony_ci return status; 2990141cc406Sopenharmony_ci} 2991141cc406Sopenharmony_ci 2992141cc406Sopenharmony_cistatic SANE_Status 2993141cc406Sopenharmony_cics3_set_window(cs3_t * s, cs3_scan_t type) 2994141cc406Sopenharmony_ci{ 2995141cc406Sopenharmony_ci int color; 2996141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2997141cc406Sopenharmony_ci 2998141cc406Sopenharmony_ci /* SET WINDOW */ 2999141cc406Sopenharmony_ci for (color = 0; color < s->n_colors; color++) { 3000141cc406Sopenharmony_ci 3001141cc406Sopenharmony_ci DBG(8, "%s: color %d\n", __func__, cs3_colors[color]); 3002141cc406Sopenharmony_ci 3003141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 3004141cc406Sopenharmony_ci 3005141cc406Sopenharmony_ci cs3_init_buffer(s); 3006141cc406Sopenharmony_ci if ((s->type == CS3_TYPE_LS40) 3007141cc406Sopenharmony_ci || (s->type == CS3_TYPE_LS4000) 3008141cc406Sopenharmony_ci || (s->type == CS3_TYPE_LS50) 3009141cc406Sopenharmony_ci || (s->type == CS3_TYPE_LS5000)) 3010141cc406Sopenharmony_ci cs3_parse_cmd(s, "24 00 00 00 00 00 00 00 3a 80"); 3011141cc406Sopenharmony_ci else 3012141cc406Sopenharmony_ci cs3_parse_cmd(s, "24 00 00 00 00 00 00 00 3a 00"); 3013141cc406Sopenharmony_ci 3014141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00 00 00 00 00 00 32"); 3015141cc406Sopenharmony_ci 3016141cc406Sopenharmony_ci cs3_pack_byte(s, cs3_colors[color]); 3017141cc406Sopenharmony_ci 3018141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); 3019141cc406Sopenharmony_ci 3020141cc406Sopenharmony_ci cs3_pack_word(s, s->real_resx); 3021141cc406Sopenharmony_ci cs3_pack_word(s, s->real_resy); 3022141cc406Sopenharmony_ci cs3_pack_long(s, s->real_xoffset); 3023141cc406Sopenharmony_ci cs3_pack_long(s, s->real_yoffset); 3024141cc406Sopenharmony_ci cs3_pack_long(s, s->real_width); 3025141cc406Sopenharmony_ci cs3_pack_long(s, s->real_height); 3026141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); /* brightness, etc. */ 3027141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); 3028141cc406Sopenharmony_ci cs3_pack_byte(s, 0x00); 3029141cc406Sopenharmony_ci cs3_pack_byte(s, 0x05); /* image composition CCCCCCC */ 3030141cc406Sopenharmony_ci cs3_pack_byte(s, s->real_depth); /* pixel composition */ 3031141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00 00 00 00 00 00 00 00 00 00 00 00"); 3032141cc406Sopenharmony_ci cs3_pack_byte(s, ((s->samples_per_scan - 1) << 4) | 0x00); /* multiread, ordering */ 3033141cc406Sopenharmony_ci 3034141cc406Sopenharmony_ci cs3_pack_byte(s, 0x80 | (s->negative ? 0 : 1)); /* averaging, pos/neg */ 3035141cc406Sopenharmony_ci 3036141cc406Sopenharmony_ci switch (type) { /* scanning kind */ 3037141cc406Sopenharmony_ci case CS3_SCAN_NORMAL: 3038141cc406Sopenharmony_ci cs3_pack_byte(s, 0x01); 3039141cc406Sopenharmony_ci break; 3040141cc406Sopenharmony_ci case CS3_SCAN_AE: 3041141cc406Sopenharmony_ci cs3_pack_byte(s, 0x20); 3042141cc406Sopenharmony_ci break; 3043141cc406Sopenharmony_ci case CS3_SCAN_AE_WB: 3044141cc406Sopenharmony_ci cs3_pack_byte(s, 0x40); 3045141cc406Sopenharmony_ci break; 3046141cc406Sopenharmony_ci default: 3047141cc406Sopenharmony_ci DBG(1, "BUG: cs3_scan(): Unknown scanning type.\n"); 3048141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3049141cc406Sopenharmony_ci } 3050141cc406Sopenharmony_ci if (s->samples_per_scan == 1) 3051141cc406Sopenharmony_ci cs3_pack_byte(s, 0x02); /* scanning mode single */ 3052141cc406Sopenharmony_ci else 3053141cc406Sopenharmony_ci cs3_pack_byte(s, 0x10); /* scanning mode multi */ 3054141cc406Sopenharmony_ci cs3_pack_byte(s, 0x02); /* color interleaving */ 3055141cc406Sopenharmony_ci cs3_pack_byte(s, 0xff); /* (ae) */ 3056141cc406Sopenharmony_ci if (color == 3) /* infrared */ 3057141cc406Sopenharmony_ci cs3_parse_cmd(s, "00 00 00 00"); /* automatic */ 3058141cc406Sopenharmony_ci else { 3059141cc406Sopenharmony_ci DBG(4, "%s: exposure = %ld * 10ns\n", __func__, 3060141cc406Sopenharmony_ci s->real_exposure[cs3_colors[color]]); 3061141cc406Sopenharmony_ci cs3_pack_long(s, s->real_exposure[cs3_colors[color]]); 3062141cc406Sopenharmony_ci } 3063141cc406Sopenharmony_ci 3064141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 3065141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3066141cc406Sopenharmony_ci return status; 3067141cc406Sopenharmony_ci } 3068141cc406Sopenharmony_ci 3069141cc406Sopenharmony_ci return status; 3070141cc406Sopenharmony_ci} 3071141cc406Sopenharmony_ci 3072141cc406Sopenharmony_ci 3073141cc406Sopenharmony_cistatic SANE_Status 3074141cc406Sopenharmony_cics3_scan(cs3_t * s, cs3_scan_t type) 3075141cc406Sopenharmony_ci{ 3076141cc406Sopenharmony_ci SANE_Status status; 3077141cc406Sopenharmony_ci 3078141cc406Sopenharmony_ci s->block_padding = 0; 3079141cc406Sopenharmony_ci 3080141cc406Sopenharmony_ci DBG(6, "%s, type = %d, colors = %d\n", __func__, type, s->n_colors); 3081141cc406Sopenharmony_ci 3082141cc406Sopenharmony_ci switch (type) { 3083141cc406Sopenharmony_ci case CS3_SCAN_NORMAL: 3084141cc406Sopenharmony_ci DBG(16, "%s: normal scan\n", __func__); 3085141cc406Sopenharmony_ci break; 3086141cc406Sopenharmony_ci case CS3_SCAN_AE: 3087141cc406Sopenharmony_ci DBG(16, "%s: ae scan\n", __func__); 3088141cc406Sopenharmony_ci break; 3089141cc406Sopenharmony_ci case CS3_SCAN_AE_WB: 3090141cc406Sopenharmony_ci DBG(16, "%s: ae wb scan\n", __func__); 3091141cc406Sopenharmony_ci break; 3092141cc406Sopenharmony_ci } 3093141cc406Sopenharmony_ci 3094141cc406Sopenharmony_ci /* wait for device to be ready with document, and set device unit */ 3095141cc406Sopenharmony_ci status = cs3_scanner_ready(s, CS3_STATUS_NO_DOCS); 3096141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3097141cc406Sopenharmony_ci return status; 3098141cc406Sopenharmony_ci 3099141cc406Sopenharmony_ci if (s->status & CS3_STATUS_NO_DOCS) 3100141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 3101141cc406Sopenharmony_ci 3102141cc406Sopenharmony_ci status = cs3_convert_options(s); 3103141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3104141cc406Sopenharmony_ci return status; 3105141cc406Sopenharmony_ci 3106141cc406Sopenharmony_ci status = cs3_set_boundary(s); 3107141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3108141cc406Sopenharmony_ci return status; 3109141cc406Sopenharmony_ci 3110141cc406Sopenharmony_ci cs3_set_focus(s); 3111141cc406Sopenharmony_ci 3112141cc406Sopenharmony_ci cs3_scanner_ready(s, CS3_STATUS_READY); 3113141cc406Sopenharmony_ci 3114141cc406Sopenharmony_ci if (type == CS3_SCAN_NORMAL) 3115141cc406Sopenharmony_ci cs3_send_lut(s); 3116141cc406Sopenharmony_ci 3117141cc406Sopenharmony_ci status = cs3_set_window(s, type); 3118141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3119141cc406Sopenharmony_ci return status; 3120141cc406Sopenharmony_ci 3121141cc406Sopenharmony_ci status = cs3_get_exposure(s); 3122141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3123141cc406Sopenharmony_ci return status; 3124141cc406Sopenharmony_ci 3125141cc406Sopenharmony_ci/* cs3_scanner_ready(s, CS3_STATUS_READY); */ 3126141cc406Sopenharmony_ci 3127141cc406Sopenharmony_ci cs3_init_buffer(s); 3128141cc406Sopenharmony_ci switch (s->n_colors) { 3129141cc406Sopenharmony_ci case 3: 3130141cc406Sopenharmony_ci cs3_parse_cmd(s, "1b 00 00 00 03 00 01 02 03"); 3131141cc406Sopenharmony_ci break; 3132141cc406Sopenharmony_ci case 4: 3133141cc406Sopenharmony_ci cs3_parse_cmd(s, "1b 00 00 00 04 00 01 02 03 09"); 3134141cc406Sopenharmony_ci break; 3135141cc406Sopenharmony_ci default: 3136141cc406Sopenharmony_ci DBG(0, "BUG: %s: Unknown number of input colors.\n", 3137141cc406Sopenharmony_ci __func__); 3138141cc406Sopenharmony_ci break; 3139141cc406Sopenharmony_ci } 3140141cc406Sopenharmony_ci 3141141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 3142141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 3143141cc406Sopenharmony_ci DBG(6, "scan setup failed\n"); 3144141cc406Sopenharmony_ci return status; 3145141cc406Sopenharmony_ci } 3146141cc406Sopenharmony_ci 3147141cc406Sopenharmony_ci if (s->status == CS3_STATUS_REISSUE) { 3148141cc406Sopenharmony_ci status = cs3_issue_cmd(s); 3149141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3150141cc406Sopenharmony_ci return status; 3151141cc406Sopenharmony_ci } 3152141cc406Sopenharmony_ci 3153141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3154141cc406Sopenharmony_ci} 3155141cc406Sopenharmony_ci 3156141cc406Sopenharmony_cistatic void * 3157141cc406Sopenharmony_cics3_xmalloc(size_t size) 3158141cc406Sopenharmony_ci{ 3159141cc406Sopenharmony_ci register void *value = malloc(size); 3160141cc406Sopenharmony_ci 3161141cc406Sopenharmony_ci if (value == NULL) { 3162141cc406Sopenharmony_ci DBG(0, "error: %s: failed to malloc() %lu bytes.\n", 3163141cc406Sopenharmony_ci __func__, (unsigned long) size); 3164141cc406Sopenharmony_ci } 3165141cc406Sopenharmony_ci return value; 3166141cc406Sopenharmony_ci} 3167141cc406Sopenharmony_ci 3168141cc406Sopenharmony_cistatic void * 3169141cc406Sopenharmony_cics3_xrealloc(void *p, size_t size) 3170141cc406Sopenharmony_ci{ 3171141cc406Sopenharmony_ci register void *value; 3172141cc406Sopenharmony_ci 3173141cc406Sopenharmony_ci if (!size) 3174141cc406Sopenharmony_ci return p; 3175141cc406Sopenharmony_ci 3176141cc406Sopenharmony_ci value = realloc(p, size); 3177141cc406Sopenharmony_ci 3178141cc406Sopenharmony_ci if (value == NULL) { 3179141cc406Sopenharmony_ci DBG(0, "error: %s: failed to realloc() %lu bytes.\n", 3180141cc406Sopenharmony_ci __func__, (unsigned long) size); 3181141cc406Sopenharmony_ci } 3182141cc406Sopenharmony_ci 3183141cc406Sopenharmony_ci return value; 3184141cc406Sopenharmony_ci} 3185141cc406Sopenharmony_ci 3186141cc406Sopenharmony_cistatic void 3187141cc406Sopenharmony_cics3_xfree(void *p) 3188141cc406Sopenharmony_ci{ 3189141cc406Sopenharmony_ci if (p) 3190141cc406Sopenharmony_ci free(p); 3191141cc406Sopenharmony_ci} 3192