1141cc406Sopenharmony_ci/* SANE - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de> 4141cc406Sopenharmony_ci Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org> 5141cc406Sopenharmony_ci Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 42141cc406Sopenharmony_ci */ 43141cc406Sopenharmony_ci#include "../include/sane/config.h" 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci#include <errno.h> 46141cc406Sopenharmony_ci#include <string.h> 47141cc406Sopenharmony_ci#include <stdlib.h> 48141cc406Sopenharmony_ci#ifdef USE_PTHREAD 49141cc406Sopenharmony_ci# include <pthread.h> 50141cc406Sopenharmony_ci#endif 51141cc406Sopenharmony_ci#include <signal.h> /* sigaction(POSIX) */ 52141cc406Sopenharmony_ci#include <unistd.h> /* POSIX: write read close pipe */ 53141cc406Sopenharmony_ci#ifdef HAVE_FCNTL_H 54141cc406Sopenharmony_ci# include <fcntl.h> 55141cc406Sopenharmony_ci#endif 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_ci#include "pixma_rename.h" 58141cc406Sopenharmony_ci#include "pixma.h" 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci# define DEBUG_NOT_STATIC 61141cc406Sopenharmony_ci# include "../include/sane/sane.h" 62141cc406Sopenharmony_ci# include "../include/sane/sanei.h" 63141cc406Sopenharmony_ci# include "../include/sane/saneopts.h" 64141cc406Sopenharmony_ci# include "../include/sane/sanei_thread.h" 65141cc406Sopenharmony_ci# include "../include/sane/sanei_backend.h" 66141cc406Sopenharmony_ci# include "../include/sane/sanei_config.h" 67141cc406Sopenharmony_ci# include "../include/sane/sanei_jpeg.h" 68141cc406Sopenharmony_ci# include "../include/sane/sanei_usb.h" 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci#ifdef NDEBUG 71141cc406Sopenharmony_ci# define PDBG(x) 72141cc406Sopenharmony_ci#else 73141cc406Sopenharmony_ci# define PDBG(x) IF_DBG(x) 74141cc406Sopenharmony_ci#endif /* NDEBUG */ 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci#ifdef __GNUC__ 77141cc406Sopenharmony_ci# define UNUSED(v) (void) v 78141cc406Sopenharmony_ci#else 79141cc406Sopenharmony_ci# define UNUSED(v) 80141cc406Sopenharmony_ci#endif 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci#define DECL_CTX pixma_sane_t *ss = check_handle(h) 83141cc406Sopenharmony_ci#define OPT_IN_CTX ss->opt 84141cc406Sopenharmony_ci#define SOD(opt) OPT_IN_CTX[opt].sod 85141cc406Sopenharmony_ci#define OVAL(opt) OPT_IN_CTX[opt].val 86141cc406Sopenharmony_ci#define AUTO_GAMMA 2.2 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci/* pixma_sane_options.h generated by 89141cc406Sopenharmony_ci * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h 90141cc406Sopenharmony_ci */ 91141cc406Sopenharmony_ci#include "pixma_sane_options.h" 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_ci#define BUTTON_GROUP_SIZE ( opt_adf_orientation - opt_button_1 + 1 ) 94141cc406Sopenharmony_ci#define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 ) 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_citypedef struct pixma_sane_t 97141cc406Sopenharmony_ci{ 98141cc406Sopenharmony_ci struct pixma_sane_t *next; 99141cc406Sopenharmony_ci pixma_t *s; 100141cc406Sopenharmony_ci pixma_scan_param_t sp; 101141cc406Sopenharmony_ci SANE_Bool cancel; 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_ci /* valid states: idle, !idle && scanning, !idle && !scanning */ 104141cc406Sopenharmony_ci SANE_Bool idle; 105141cc406Sopenharmony_ci SANE_Bool scanning; 106141cc406Sopenharmony_ci SANE_Status last_read_status; /* valid if !idle && !scanning */ 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci option_descriptor_t opt[opt_last]; 109141cc406Sopenharmony_ci char button_option_is_cached[BUTTON_GROUP_SIZE]; 110141cc406Sopenharmony_ci SANE_Range xrange, yrange; 111141cc406Sopenharmony_ci SANE_Word dpi_list[9]; /* up to 9600 dpi */ 112141cc406Sopenharmony_ci SANE_String_Const mode_list[6]; 113141cc406Sopenharmony_ci pixma_scan_mode_t mode_map[6]; 114141cc406Sopenharmony_ci uint8_t gamma_table[4096]; 115141cc406Sopenharmony_ci SANE_String_Const source_list[4]; 116141cc406Sopenharmony_ci pixma_paper_source_t source_map[4]; 117141cc406Sopenharmony_ci SANE_String_Const calibrate_list[PIXMA_CALIBRATE_NUM_OPTS + 1]; 118141cc406Sopenharmony_ci pixma_calibrate_option_t calibrate_map[PIXMA_CALIBRATE_NUM_OPTS + 1]; 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci unsigned byte_pos_in_line, output_line_size; 121141cc406Sopenharmony_ci uint64_t image_bytes_read; 122141cc406Sopenharmony_ci unsigned page_count; /* valid for ADF */ 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci SANE_Pid reader_taskid; 125141cc406Sopenharmony_ci int wpipe, rpipe; 126141cc406Sopenharmony_ci SANE_Bool reader_stop; 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_ci /* Valid for JPEG source */ 129141cc406Sopenharmony_ci djpeg_dest_ptr jdst; 130141cc406Sopenharmony_ci struct jpeg_decompress_struct jpeg_cinfo; 131141cc406Sopenharmony_ci struct jpeg_error_mgr jpeg_err; 132141cc406Sopenharmony_ci SANE_Bool jpeg_header_seen; 133141cc406Sopenharmony_ci} pixma_sane_t; 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_citypedef struct 136141cc406Sopenharmony_ci{ 137141cc406Sopenharmony_ci struct jpeg_source_mgr jpeg; 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci pixma_sane_t *s; 140141cc406Sopenharmony_ci JOCTET *buffer; 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci SANE_Byte *linebuffer; 143141cc406Sopenharmony_ci SANE_Int linebuffer_size; 144141cc406Sopenharmony_ci SANE_Int linebuffer_index; 145141cc406Sopenharmony_ci} pixma_jpeg_src_mgr; 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_cistatic const char vendor_str[] = "CANON"; 149141cc406Sopenharmony_cistatic const char type_str[] = "multi-function peripheral"; 150141cc406Sopenharmony_ci 151141cc406Sopenharmony_cistatic pixma_sane_t *first_scanner = NULL; 152141cc406Sopenharmony_cistatic const SANE_Device **dev_list = NULL; 153141cc406Sopenharmony_cistatic const char* conf_devices[MAX_CONF_DEVICES]; 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_cistatic void mark_all_button_options_cached ( struct pixma_sane_t * ss ) 156141cc406Sopenharmony_ci{ 157141cc406Sopenharmony_ci int i; 158141cc406Sopenharmony_ci for (i = 0; i < (opt__group_5 - opt_button_1); i++ ) 159141cc406Sopenharmony_ci ss -> button_option_is_cached[i] = 1; 160141cc406Sopenharmony_ci} 161141cc406Sopenharmony_ci 162141cc406Sopenharmony_cistatic SANE_Status config_attach_pixma(SANEI_Config __sane_unused__ * config, 163141cc406Sopenharmony_ci const char *devname, 164141cc406Sopenharmony_ci void __sane_unused__ *data) 165141cc406Sopenharmony_ci{ 166141cc406Sopenharmony_ci int i; 167141cc406Sopenharmony_ci for (i=0; i < (MAX_CONF_DEVICES -1); i++) 168141cc406Sopenharmony_ci { 169141cc406Sopenharmony_ci if(conf_devices[i] == NULL) 170141cc406Sopenharmony_ci { 171141cc406Sopenharmony_ci conf_devices[i] = strdup(devname); 172141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 173141cc406Sopenharmony_ci } 174141cc406Sopenharmony_ci } 175141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 176141cc406Sopenharmony_ci} 177141cc406Sopenharmony_ci 178141cc406Sopenharmony_cistatic SANE_Status 179141cc406Sopenharmony_cimap_error (int error) 180141cc406Sopenharmony_ci{ 181141cc406Sopenharmony_ci if (error >= 0) 182141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci switch (error) 185141cc406Sopenharmony_ci { 186141cc406Sopenharmony_ci case PIXMA_ENOMEM: 187141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 188141cc406Sopenharmony_ci case PIXMA_ECANCELED: 189141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 190141cc406Sopenharmony_ci case PIXMA_EBUSY: 191141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 192141cc406Sopenharmony_ci case PIXMA_EINVAL: 193141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 194141cc406Sopenharmony_ci case PIXMA_EACCES: 195141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 196141cc406Sopenharmony_ci case PIXMA_EPAPER_JAMMED: 197141cc406Sopenharmony_ci return SANE_STATUS_JAMMED; 198141cc406Sopenharmony_ci case PIXMA_ENO_PAPER: 199141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 200141cc406Sopenharmony_ci case PIXMA_ECOVER_OPEN: 201141cc406Sopenharmony_ci return SANE_STATUS_COVER_OPEN; 202141cc406Sopenharmony_ci case PIXMA_ENOTSUP: 203141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 204141cc406Sopenharmony_ci case PIXMA_EPROTO: 205141cc406Sopenharmony_ci case PIXMA_ENODEV: 206141cc406Sopenharmony_ci case PIXMA_EIO: 207141cc406Sopenharmony_ci case PIXMA_ETIMEDOUT: 208141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 209141cc406Sopenharmony_ci } 210141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "BUG: unmapped error %d\n", error)); 211141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 212141cc406Sopenharmony_ci} 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_cistatic int 215141cc406Sopenharmony_cigetenv_atoi (const char *name, int def) 216141cc406Sopenharmony_ci{ 217141cc406Sopenharmony_ci const char *str = getenv (name); 218141cc406Sopenharmony_ci return (str) ? atoi (str) : def; 219141cc406Sopenharmony_ci} 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci#define CONST_CAST(t,x) (t)(x) 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_cistatic void 224141cc406Sopenharmony_cifree_block (const void * ptr) 225141cc406Sopenharmony_ci{ 226141cc406Sopenharmony_ci free (CONST_CAST (void *, ptr)); 227141cc406Sopenharmony_ci} 228141cc406Sopenharmony_ci 229141cc406Sopenharmony_cistatic void 230141cc406Sopenharmony_cicleanup_device_list (void) 231141cc406Sopenharmony_ci{ 232141cc406Sopenharmony_ci if (dev_list) 233141cc406Sopenharmony_ci { 234141cc406Sopenharmony_ci int i; 235141cc406Sopenharmony_ci for (i = 0; dev_list[i]; i++) 236141cc406Sopenharmony_ci { 237141cc406Sopenharmony_ci free_block ((const void *) dev_list[i]->name); 238141cc406Sopenharmony_ci free_block ((const void *) dev_list[i]->model); 239141cc406Sopenharmony_ci free_block ((const void *) dev_list[i]); 240141cc406Sopenharmony_ci } 241141cc406Sopenharmony_ci } 242141cc406Sopenharmony_ci free (dev_list); 243141cc406Sopenharmony_ci dev_list = NULL; 244141cc406Sopenharmony_ci} 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_cistatic void 247141cc406Sopenharmony_cifind_scanners (SANE_Bool local_only) 248141cc406Sopenharmony_ci{ 249141cc406Sopenharmony_ci unsigned i, nscanners; 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci cleanup_device_list (); 252141cc406Sopenharmony_ci nscanners = pixma_find_scanners (conf_devices, local_only); 253141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "pixma_find_scanners() found %u devices\n", nscanners)); 254141cc406Sopenharmony_ci dev_list = 255141cc406Sopenharmony_ci (const SANE_Device **) calloc (nscanners + 1, sizeof (*dev_list)); 256141cc406Sopenharmony_ci if (!dev_list) 257141cc406Sopenharmony_ci return; 258141cc406Sopenharmony_ci for (i = 0; i != nscanners; i++) 259141cc406Sopenharmony_ci { 260141cc406Sopenharmony_ci SANE_Device *sdev = (SANE_Device *) calloc (1, sizeof (*sdev)); 261141cc406Sopenharmony_ci char *name, *model; 262141cc406Sopenharmony_ci if (!sdev) 263141cc406Sopenharmony_ci goto nomem; 264141cc406Sopenharmony_ci name = strdup (pixma_get_device_id (i)); 265141cc406Sopenharmony_ci model = strdup (pixma_get_device_model (i)); 266141cc406Sopenharmony_ci if (!name || !model) 267141cc406Sopenharmony_ci { 268141cc406Sopenharmony_ci free (name); 269141cc406Sopenharmony_ci free (model); 270141cc406Sopenharmony_ci free (sdev); 271141cc406Sopenharmony_ci goto nomem; 272141cc406Sopenharmony_ci } 273141cc406Sopenharmony_ci sdev->name = name; 274141cc406Sopenharmony_ci sdev->model = model; 275141cc406Sopenharmony_ci sdev->vendor = vendor_str; 276141cc406Sopenharmony_ci sdev->type = type_str; 277141cc406Sopenharmony_ci dev_list[i] = sdev; 278141cc406Sopenharmony_ci } 279141cc406Sopenharmony_ci /* dev_list is already NULL terminated by calloc(). */ 280141cc406Sopenharmony_ci return; 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_cinomem: 283141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING:not enough memory for device list\n")); 284141cc406Sopenharmony_ci return; 285141cc406Sopenharmony_ci} 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_cistatic pixma_sane_t * 288141cc406Sopenharmony_cicheck_handle (SANE_Handle h) 289141cc406Sopenharmony_ci{ 290141cc406Sopenharmony_ci pixma_sane_t *p; 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci for (p = first_scanner; p && (SANE_Handle) p != h; p = p->next) 293141cc406Sopenharmony_ci { 294141cc406Sopenharmony_ci } 295141cc406Sopenharmony_ci return p; 296141cc406Sopenharmony_ci} 297141cc406Sopenharmony_ci 298141cc406Sopenharmony_cistatic void 299141cc406Sopenharmony_ciupdate_button_state (pixma_sane_t * ss, SANE_Int * info) 300141cc406Sopenharmony_ci{ 301141cc406Sopenharmony_ci SANE_Int b1 = OVAL (opt_button_1).w; 302141cc406Sopenharmony_ci SANE_Int b2 = OVAL (opt_button_2).w; 303141cc406Sopenharmony_ci uint32_t ev = pixma_wait_event (ss->s, 300); 304141cc406Sopenharmony_ci switch (ev & ~PIXMA_EV_ACTION_MASK) 305141cc406Sopenharmony_ci { 306141cc406Sopenharmony_ci case PIXMA_EV_BUTTON1: 307141cc406Sopenharmony_ci b1 = 1; 308141cc406Sopenharmony_ci break; 309141cc406Sopenharmony_ci case PIXMA_EV_BUTTON2: 310141cc406Sopenharmony_ci b2 = 1; 311141cc406Sopenharmony_ci break; 312141cc406Sopenharmony_ci } 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_ci if (b1 != OVAL (opt_button_1).w || b2 != OVAL (opt_button_2).w) 315141cc406Sopenharmony_ci { 316141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 317141cc406Sopenharmony_ci OVAL (opt_button_1).w = b1; 318141cc406Sopenharmony_ci OVAL (opt_button_2).w = b2; 319141cc406Sopenharmony_ci OVAL (opt_original).w = GET_EV_ORIGINAL(ev); 320141cc406Sopenharmony_ci OVAL (opt_target).w = GET_EV_TARGET(ev); 321141cc406Sopenharmony_ci OVAL (opt_scan_resolution).w = GET_EV_DPI(ev); 322141cc406Sopenharmony_ci OVAL (opt_document_type).w = GET_EV_DOC(ev); 323141cc406Sopenharmony_ci OVAL (opt_adf_status).w = GET_EV_STAT(ev); 324141cc406Sopenharmony_ci OVAL (opt_adf_orientation).w = GET_EV_ORIENT(ev); 325141cc406Sopenharmony_ci } 326141cc406Sopenharmony_ci mark_all_button_options_cached(ss); 327141cc406Sopenharmony_ci} 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_cistatic SANE_Bool 330141cc406Sopenharmony_cienable_option (pixma_sane_t * ss, SANE_Int o, SANE_Bool enable) 331141cc406Sopenharmony_ci{ 332141cc406Sopenharmony_ci SANE_Word save = SOD (o).cap; 333141cc406Sopenharmony_ci if (enable) 334141cc406Sopenharmony_ci SOD (o).cap &= ~SANE_CAP_INACTIVE; 335141cc406Sopenharmony_ci else 336141cc406Sopenharmony_ci SOD (o).cap |= SANE_CAP_INACTIVE; 337141cc406Sopenharmony_ci return (save != SOD (o).cap); 338141cc406Sopenharmony_ci} 339141cc406Sopenharmony_ci 340141cc406Sopenharmony_cistatic void 341141cc406Sopenharmony_ciclamp_value (pixma_sane_t * ss, SANE_Int n, void *v, SANE_Int * info) 342141cc406Sopenharmony_ci{ 343141cc406Sopenharmony_ci SANE_Option_Descriptor *sod = &SOD (n); 344141cc406Sopenharmony_ci SANE_Word *va = (SANE_Word *) v; 345141cc406Sopenharmony_ci const SANE_Range *range = sod->constraint.range; 346141cc406Sopenharmony_ci int i, nmemb; 347141cc406Sopenharmony_ci 348141cc406Sopenharmony_ci nmemb = sod->size / sizeof (SANE_Word); 349141cc406Sopenharmony_ci for (i = 0; i < nmemb; i++) 350141cc406Sopenharmony_ci { 351141cc406Sopenharmony_ci SANE_Word value = va[i]; 352141cc406Sopenharmony_ci if (value < range->min) 353141cc406Sopenharmony_ci { 354141cc406Sopenharmony_ci value = range->min; 355141cc406Sopenharmony_ci } 356141cc406Sopenharmony_ci else if (value > range->max) 357141cc406Sopenharmony_ci { 358141cc406Sopenharmony_ci value = range->max; 359141cc406Sopenharmony_ci } 360141cc406Sopenharmony_ci if (range->quant != 0) 361141cc406Sopenharmony_ci { 362141cc406Sopenharmony_ci value = (value - range->min + range->quant / 2) / 363141cc406Sopenharmony_ci range->quant * range->quant; 364141cc406Sopenharmony_ci } 365141cc406Sopenharmony_ci if (value != va[i]) 366141cc406Sopenharmony_ci { 367141cc406Sopenharmony_ci va[i] = value; 368141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 369141cc406Sopenharmony_ci } 370141cc406Sopenharmony_ci } 371141cc406Sopenharmony_ci} 372141cc406Sopenharmony_ci 373141cc406Sopenharmony_ci/* create dynamic mode_list 374141cc406Sopenharmony_ci * ss: scanner device 375141cc406Sopenharmony_ci * tpu = 0: flatbed or ADF mode 376141cc406Sopenharmony_ci * 1 bit lineart, 8 bit grayscale and 24 bit color scans 377141cc406Sopenharmony_ci * tpu = 1: TPU mode 378141cc406Sopenharmony_ci * 16 bit grayscale and 48 bit color scans */ 379141cc406Sopenharmony_cistatic void 380141cc406Sopenharmony_cicreate_mode_list (pixma_sane_t * ss) 381141cc406Sopenharmony_ci{ 382141cc406Sopenharmony_ci SANE_Bool tpu; 383141cc406Sopenharmony_ci const pixma_config_t *cfg; 384141cc406Sopenharmony_ci int i; 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci cfg = pixma_get_config (ss->s); 387141cc406Sopenharmony_ci tpu = (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU); 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_ci /* setup available mode */ 390141cc406Sopenharmony_ci i = 0; 391141cc406Sopenharmony_ci ss->mode_list[i] = SANE_VALUE_SCAN_MODE_COLOR; 392141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR; 393141cc406Sopenharmony_ci i++; 394141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_GRAY) 395141cc406Sopenharmony_ci { 396141cc406Sopenharmony_ci ss->mode_list[i] = SANE_VALUE_SCAN_MODE_GRAY; 397141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY; 398141cc406Sopenharmony_ci i++; 399141cc406Sopenharmony_ci } 400141cc406Sopenharmony_ci if (tpu && (cfg->cap & PIXMA_CAP_NEGATIVE)) 401141cc406Sopenharmony_ci { 402141cc406Sopenharmony_ci ss->mode_list[i] = SANE_I18N ("Negative color"); 403141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_COLOR; 404141cc406Sopenharmony_ci i++; 405141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_GRAY) 406141cc406Sopenharmony_ci { 407141cc406Sopenharmony_ci ss->mode_list[i] = SANE_I18N ("Negative gray"); 408141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_GRAY; 409141cc406Sopenharmony_ci i++; 410141cc406Sopenharmony_ci } 411141cc406Sopenharmony_ci } 412141cc406Sopenharmony_ci if (tpu && (cfg->cap & PIXMA_CAP_TPUIR) == PIXMA_CAP_TPUIR) 413141cc406Sopenharmony_ci { 414141cc406Sopenharmony_ci ss->mode_list[i] = SANE_I18N ("Infrared"); 415141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_TPUIR; 416141cc406Sopenharmony_ci i++; 417141cc406Sopenharmony_ci } 418141cc406Sopenharmony_ci if (!tpu && (cfg->cap & PIXMA_CAP_48BIT)) 419141cc406Sopenharmony_ci { 420141cc406Sopenharmony_ci ss->mode_list[i] = SANE_I18N ("48 bits color"); 421141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR_48; 422141cc406Sopenharmony_ci i++; 423141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_GRAY) 424141cc406Sopenharmony_ci { 425141cc406Sopenharmony_ci ss->mode_list[i] = SANE_I18N ("16 bits gray"); 426141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY_16; 427141cc406Sopenharmony_ci i++; 428141cc406Sopenharmony_ci } 429141cc406Sopenharmony_ci } 430141cc406Sopenharmony_ci if (!tpu && (cfg->cap & PIXMA_CAP_LINEART)) 431141cc406Sopenharmony_ci { 432141cc406Sopenharmony_ci ss->mode_list[i] = SANE_VALUE_SCAN_MODE_LINEART; 433141cc406Sopenharmony_ci ss->mode_map[i] = PIXMA_SCAN_MODE_LINEART; 434141cc406Sopenharmony_ci i++; 435141cc406Sopenharmony_ci } 436141cc406Sopenharmony_ci /* terminate mode_list and mode_map */ 437141cc406Sopenharmony_ci ss->mode_list[i] = 0; 438141cc406Sopenharmony_ci ss->mode_map[i] = 0; 439141cc406Sopenharmony_ci} 440141cc406Sopenharmony_ci 441141cc406Sopenharmony_ci/* create dynamic dpi_list 442141cc406Sopenharmony_ci * ss: scanner device */ 443141cc406Sopenharmony_cistatic void 444141cc406Sopenharmony_cicreate_dpi_list (pixma_sane_t * ss) 445141cc406Sopenharmony_ci{ 446141cc406Sopenharmony_ci const pixma_config_t *cfg; 447141cc406Sopenharmony_ci int i, j; 448141cc406Sopenharmony_ci int min; 449141cc406Sopenharmony_ci unsigned min_dpi; 450141cc406Sopenharmony_ci unsigned max_dpi; 451141cc406Sopenharmony_ci 452141cc406Sopenharmony_ci cfg = pixma_get_config (ss->s); 453141cc406Sopenharmony_ci 454141cc406Sopenharmony_ci /* get min/max dpi */ 455141cc406Sopenharmony_ci max_dpi = cfg->xdpi; 456141cc406Sopenharmony_ci min_dpi = 75; 457141cc406Sopenharmony_ci if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU 458141cc406Sopenharmony_ci && ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_TPUIR) 459141cc406Sopenharmony_ci { /* IR mode */ 460141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*create_dpi_list***** TPUIR mode\n"));*/ 461141cc406Sopenharmony_ci min_dpi = (cfg->tpuir_min_dpi) ? cfg->tpuir_min_dpi : 75; 462141cc406Sopenharmony_ci max_dpi = (cfg->tpuir_max_dpi) ? cfg->tpuir_max_dpi : cfg->xdpi; 463141cc406Sopenharmony_ci } 464141cc406Sopenharmony_ci else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU 465141cc406Sopenharmony_ci || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADF 466141cc406Sopenharmony_ci || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADFDUP) 467141cc406Sopenharmony_ci { /* ADF / TPU mode */ 468141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*create_dpi_list***** ADF/TPU mode\n"));*/ 469141cc406Sopenharmony_ci min_dpi = (cfg->adftpu_min_dpi) ? cfg->adftpu_min_dpi : 75; 470141cc406Sopenharmony_ci max_dpi = (cfg->adftpu_max_dpi) ? cfg->adftpu_max_dpi : cfg->xdpi; 471141cc406Sopenharmony_ci } 472141cc406Sopenharmony_ci else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED 473141cc406Sopenharmony_ci && (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_COLOR_48 474141cc406Sopenharmony_ci || ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_GRAY_16)) 475141cc406Sopenharmony_ci { /* 48 bits flatbed */ 476141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*create_dpi_list***** 48 bits flatbed mode\n"));*/ 477141cc406Sopenharmony_ci min_dpi = (cfg->min_xdpi_16) ? cfg->min_xdpi_16 : 75; 478141cc406Sopenharmony_ci } 479141cc406Sopenharmony_ci 480141cc406Sopenharmony_ci /* set j for min. dpi 481141cc406Sopenharmony_ci * 75 dpi: j = 0 482141cc406Sopenharmony_ci * 150 dpi: j = 1 \ 483141cc406Sopenharmony_ci * 300 dpi: j = 2 |--> from cfg->adftpu_min_dpi or cfg->tpuir_min_dpi 484141cc406Sopenharmony_ci * 600 dpi: j = 3 / 485141cc406Sopenharmony_ci * */ 486141cc406Sopenharmony_ci j = -1; 487141cc406Sopenharmony_ci min = min_dpi / 75; 488141cc406Sopenharmony_ci do 489141cc406Sopenharmony_ci { 490141cc406Sopenharmony_ci j++; 491141cc406Sopenharmony_ci min >>= 1; 492141cc406Sopenharmony_ci } 493141cc406Sopenharmony_ci while (min > 0); 494141cc406Sopenharmony_ci 495141cc406Sopenharmony_ci /* create dpi_list 496141cc406Sopenharmony_ci * use j for min. dpi */ 497141cc406Sopenharmony_ci i = 0; 498141cc406Sopenharmony_ci do 499141cc406Sopenharmony_ci { 500141cc406Sopenharmony_ci i++; j++; 501141cc406Sopenharmony_ci ss->dpi_list[i] = 75 * (1 << (j - 1)); /* 75 x 2^(j-1) */ 502141cc406Sopenharmony_ci } 503141cc406Sopenharmony_ci while ((unsigned) ss->dpi_list[i] < max_dpi); 504141cc406Sopenharmony_ci ss->dpi_list[0] = i; 505141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*create_dpi_list***** min_dpi = %d, max_dpi = %d\n", min_dpi, max_dpi));*/ 506141cc406Sopenharmony_ci} 507141cc406Sopenharmony_ci 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_cistatic void 510141cc406Sopenharmony_cicreate_calibrate_list (pixma_sane_t * ss) 511141cc406Sopenharmony_ci{ 512141cc406Sopenharmony_ci int i = 0; 513141cc406Sopenharmony_ci ss->calibrate_list[i] = SANE_I18N ("Once"); 514141cc406Sopenharmony_ci ss->calibrate_map[i] = PIXMA_CALIBRATE_ONCE; 515141cc406Sopenharmony_ci i++; 516141cc406Sopenharmony_ci ss->calibrate_list[i] = SANE_I18N ("Always"); 517141cc406Sopenharmony_ci ss->calibrate_map[i] = PIXMA_CALIBRATE_ALWAYS; 518141cc406Sopenharmony_ci i++; 519141cc406Sopenharmony_ci ss->calibrate_list[i] = SANE_I18N ("Never"); 520141cc406Sopenharmony_ci ss->calibrate_map[i] = PIXMA_CALIBRATE_NEVER; 521141cc406Sopenharmony_ci i++; 522141cc406Sopenharmony_ci} 523141cc406Sopenharmony_ci 524141cc406Sopenharmony_cistatic void 525141cc406Sopenharmony_ciselect_value_from_list (pixma_sane_t * ss, SANE_Int n, void *v, 526141cc406Sopenharmony_ci SANE_Int * info) 527141cc406Sopenharmony_ci{ 528141cc406Sopenharmony_ci SANE_Option_Descriptor *sod = &SOD (n); 529141cc406Sopenharmony_ci SANE_Word *va = (SANE_Word *) v; 530141cc406Sopenharmony_ci const SANE_Word *list = sod->constraint.word_list; 531141cc406Sopenharmony_ci int i, j, nmemb; 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci nmemb = sod->size / sizeof (SANE_Word); 534141cc406Sopenharmony_ci for (i = 0; i < nmemb; i++) 535141cc406Sopenharmony_ci { 536141cc406Sopenharmony_ci SANE_Word value = va[i]; 537141cc406Sopenharmony_ci SANE_Word mindelta = abs (value - list[1]); 538141cc406Sopenharmony_ci SANE_Word nearest = list[1]; 539141cc406Sopenharmony_ci for (j = 2; j <= list[0]; j++) 540141cc406Sopenharmony_ci { 541141cc406Sopenharmony_ci SANE_Word delta = abs (value - list[j]); 542141cc406Sopenharmony_ci if (delta < mindelta) 543141cc406Sopenharmony_ci { 544141cc406Sopenharmony_ci mindelta = delta; 545141cc406Sopenharmony_ci nearest = list[j]; 546141cc406Sopenharmony_ci } 547141cc406Sopenharmony_ci if (mindelta == 0) 548141cc406Sopenharmony_ci break; 549141cc406Sopenharmony_ci } 550141cc406Sopenharmony_ci if (va[i] != nearest) 551141cc406Sopenharmony_ci { 552141cc406Sopenharmony_ci va[i] = nearest; 553141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 554141cc406Sopenharmony_ci } 555141cc406Sopenharmony_ci } 556141cc406Sopenharmony_ci} 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_cistatic SANE_Status 559141cc406Sopenharmony_cicontrol_scalar_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v, 560141cc406Sopenharmony_ci SANE_Int * info) 561141cc406Sopenharmony_ci{ 562141cc406Sopenharmony_ci option_descriptor_t *opt = &(OPT_IN_CTX[n]); 563141cc406Sopenharmony_ci SANE_Word val; 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*control_scalar_option***** n = %u, a = %u\n", n, a)); */ 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_ci switch (a) 568141cc406Sopenharmony_ci { 569141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 570141cc406Sopenharmony_ci switch (opt->sod.type) 571141cc406Sopenharmony_ci { 572141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 573141cc406Sopenharmony_ci case SANE_TYPE_INT: 574141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 575141cc406Sopenharmony_ci *(SANE_Word *) v = opt->val.w; 576141cc406Sopenharmony_ci break; 577141cc406Sopenharmony_ci default: 578141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 579141cc406Sopenharmony_ci } 580141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 581141cc406Sopenharmony_ci 582141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 583141cc406Sopenharmony_ci switch (opt->sod.type) 584141cc406Sopenharmony_ci { 585141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 586141cc406Sopenharmony_ci val = *(SANE_Word *) v; 587141cc406Sopenharmony_ci if (val != SANE_TRUE && val != SANE_FALSE) 588141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 589141cc406Sopenharmony_ci opt->val.w = val; 590141cc406Sopenharmony_ci break; 591141cc406Sopenharmony_ci case SANE_TYPE_INT: 592141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 593141cc406Sopenharmony_ci if (opt->sod.constraint_type == SANE_CONSTRAINT_RANGE) 594141cc406Sopenharmony_ci clamp_value (ss, n, v, info); 595141cc406Sopenharmony_ci else if (opt->sod.constraint_type == SANE_CONSTRAINT_WORD_LIST) 596141cc406Sopenharmony_ci select_value_from_list (ss, n, v, info); 597141cc406Sopenharmony_ci opt->val.w = *(SANE_Word *) v; 598141cc406Sopenharmony_ci break; 599141cc406Sopenharmony_ci default: 600141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 601141cc406Sopenharmony_ci } 602141cc406Sopenharmony_ci *info |= opt->info; 603141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 604141cc406Sopenharmony_ci 605141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 606141cc406Sopenharmony_ci switch (opt->sod.type) 607141cc406Sopenharmony_ci { 608141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 609141cc406Sopenharmony_ci case SANE_TYPE_INT: 610141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 611141cc406Sopenharmony_ci opt->val.w = opt->def.w; 612141cc406Sopenharmony_ci break; 613141cc406Sopenharmony_ci default: 614141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 615141cc406Sopenharmony_ci } 616141cc406Sopenharmony_ci *info |= opt->info; 617141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 618141cc406Sopenharmony_ci } 619141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 620141cc406Sopenharmony_ci} 621141cc406Sopenharmony_ci 622141cc406Sopenharmony_cistatic SANE_Status 623141cc406Sopenharmony_cicontrol_string_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v, 624141cc406Sopenharmony_ci SANE_Int * info) 625141cc406Sopenharmony_ci{ 626141cc406Sopenharmony_ci option_descriptor_t *opt = &(OPT_IN_CTX[n]); 627141cc406Sopenharmony_ci const SANE_String_Const *slist = opt->sod.constraint.string_list; 628141cc406Sopenharmony_ci SANE_String str = (SANE_String) v; 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*control_string_option***** n = %u, a = %u\n", n, a)); */ 631141cc406Sopenharmony_ci 632141cc406Sopenharmony_ci if (opt->sod.constraint_type == SANE_CONSTRAINT_NONE) 633141cc406Sopenharmony_ci { 634141cc406Sopenharmony_ci switch (a) 635141cc406Sopenharmony_ci { 636141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 637141cc406Sopenharmony_ci strcpy (str, opt->val.s); 638141cc406Sopenharmony_ci break; 639141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 640141cc406Sopenharmony_ci str = opt->def.s; 641141cc406Sopenharmony_ci /* fall through */ 642141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 643141cc406Sopenharmony_ci strncpy (opt->val.s, str, opt->sod.size - 1); 644141cc406Sopenharmony_ci *info |= opt->info; 645141cc406Sopenharmony_ci break; 646141cc406Sopenharmony_ci } 647141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 648141cc406Sopenharmony_ci } 649141cc406Sopenharmony_ci else 650141cc406Sopenharmony_ci { 651141cc406Sopenharmony_ci int i; 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci switch (a) 654141cc406Sopenharmony_ci { 655141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 656141cc406Sopenharmony_ci strcpy (str, slist[opt->val.w]); 657141cc406Sopenharmony_ci break; 658141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 659141cc406Sopenharmony_ci str = opt->def.ptr; 660141cc406Sopenharmony_ci /* fall through */ 661141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 662141cc406Sopenharmony_ci i = 0; 663141cc406Sopenharmony_ci while (slist[i] && strcasecmp (str, slist[i]) != 0) 664141cc406Sopenharmony_ci i++; 665141cc406Sopenharmony_ci if (!slist[i]) 666141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 667141cc406Sopenharmony_ci if (strcmp (slist[i], str) != 0) 668141cc406Sopenharmony_ci { 669141cc406Sopenharmony_ci strcpy (str, slist[i]); 670141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 671141cc406Sopenharmony_ci } 672141cc406Sopenharmony_ci opt->val.w = i; 673141cc406Sopenharmony_ci *info |= opt->info; 674141cc406Sopenharmony_ci break; 675141cc406Sopenharmony_ci } 676141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 677141cc406Sopenharmony_ci } 678141cc406Sopenharmony_ci} 679141cc406Sopenharmony_ci 680141cc406Sopenharmony_cistatic SANE_Status 681141cc406Sopenharmony_cicontrol_option (pixma_sane_t * ss, SANE_Int n, 682141cc406Sopenharmony_ci SANE_Action a, void *v, SANE_Int * info) 683141cc406Sopenharmony_ci{ 684141cc406Sopenharmony_ci SANE_Option_Descriptor *sod = &SOD (n); 685141cc406Sopenharmony_ci int result, i; 686141cc406Sopenharmony_ci const pixma_config_t *cfg; 687141cc406Sopenharmony_ci SANE_Int dummy; 688141cc406Sopenharmony_ci 689141cc406Sopenharmony_ci /* info may be null, better to set a dummy here then test everywhere */ 690141cc406Sopenharmony_ci if (info == NULL) 691141cc406Sopenharmony_ci info = &dummy; 692141cc406Sopenharmony_ci 693141cc406Sopenharmony_ci cfg = pixma_get_config (ss->s); 694141cc406Sopenharmony_ci 695141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */ 696141cc406Sopenharmony_ci 697141cc406Sopenharmony_ci /* first deal with options that require special treatment */ 698141cc406Sopenharmony_ci result = SANE_STATUS_UNSUPPORTED; 699141cc406Sopenharmony_ci switch (n) 700141cc406Sopenharmony_ci { 701141cc406Sopenharmony_ci case opt_gamma_table: 702141cc406Sopenharmony_ci { 703141cc406Sopenharmony_ci int table_size = sod->size / sizeof (SANE_Word); 704141cc406Sopenharmony_ci int byte_cnt = table_size == 1024 ? 2 : 1; 705141cc406Sopenharmony_ci 706141cc406Sopenharmony_ci switch (a) 707141cc406Sopenharmony_ci { 708141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 709141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_VALUE with %d values ***** \n", table_size)); 710141cc406Sopenharmony_ci clamp_value (ss, n, v, info); 711141cc406Sopenharmony_ci if (byte_cnt == 1) 712141cc406Sopenharmony_ci { 713141cc406Sopenharmony_ci for (i = 0; i < table_size; i++) 714141cc406Sopenharmony_ci ss->gamma_table[i] = *((SANE_Int *) v + i); 715141cc406Sopenharmony_ci } 716141cc406Sopenharmony_ci else 717141cc406Sopenharmony_ci { 718141cc406Sopenharmony_ci for (i = 0; i < table_size; i++) 719141cc406Sopenharmony_ci { 720141cc406Sopenharmony_ci ss->gamma_table[i * 2] = *((SANE_Int *) v + i); 721141cc406Sopenharmony_ci ss->gamma_table[i * 2 + 1] = *((uint8_t *)((SANE_Int *) v + i) + 1); 722141cc406Sopenharmony_ci } 723141cc406Sopenharmony_ci } 724141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, (uint8_t *)v, table_size * 4)); */ 725141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */ 726141cc406Sopenharmony_ci break; 727141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 728141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_GET_VALUE ***** \n")); 729141cc406Sopenharmony_ci if (byte_cnt == 1) 730141cc406Sopenharmony_ci { 731141cc406Sopenharmony_ci for (i = 0; i < table_size; i++) 732141cc406Sopenharmony_ci *((SANE_Int *) v + i) = ss->gamma_table[i]; 733141cc406Sopenharmony_ci } 734141cc406Sopenharmony_ci else 735141cc406Sopenharmony_ci { 736141cc406Sopenharmony_ci for (i = 0; i < table_size; i++) 737141cc406Sopenharmony_ci { 738141cc406Sopenharmony_ci *((SANE_Int *) v + i) = ss->gamma_table[i * 2]; 739141cc406Sopenharmony_ci *((uint8_t *)((SANE_Int *) v + i) + 1) = ss->gamma_table[i * 2 + 1]; 740141cc406Sopenharmony_ci } 741141cc406Sopenharmony_ci } 742141cc406Sopenharmony_ci break; 743141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 744141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_AUTO with gamma=%f ***** \n", 745141cc406Sopenharmony_ci SANE_UNFIX (OVAL (opt_gamma).w))); 746141cc406Sopenharmony_ci pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w), 747141cc406Sopenharmony_ci ss->gamma_table, table_size); 748141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */ 749141cc406Sopenharmony_ci break; 750141cc406Sopenharmony_ci default: 751141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 752141cc406Sopenharmony_ci } 753141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 754141cc406Sopenharmony_ci } 755141cc406Sopenharmony_ci 756141cc406Sopenharmony_ci case opt_button_update: 757141cc406Sopenharmony_ci if (a == SANE_ACTION_SET_VALUE) 758141cc406Sopenharmony_ci { 759141cc406Sopenharmony_ci update_button_state (ss, info); 760141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 761141cc406Sopenharmony_ci } 762141cc406Sopenharmony_ci else 763141cc406Sopenharmony_ci { 764141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 765141cc406Sopenharmony_ci } 766141cc406Sopenharmony_ci break; 767141cc406Sopenharmony_ci case opt_button_1: 768141cc406Sopenharmony_ci case opt_button_2: 769141cc406Sopenharmony_ci case opt_original: 770141cc406Sopenharmony_ci case opt_target: 771141cc406Sopenharmony_ci case opt_scan_resolution: 772141cc406Sopenharmony_ci case opt_document_type: 773141cc406Sopenharmony_ci case opt_adf_status: 774141cc406Sopenharmony_ci case opt_adf_orientation: 775141cc406Sopenharmony_ci /* poll scanner if option is not cached */ 776141cc406Sopenharmony_ci if (! ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] ) 777141cc406Sopenharmony_ci update_button_state (ss, info); 778141cc406Sopenharmony_ci /* mark this option as read */ 779141cc406Sopenharmony_ci ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] = 0; 780141cc406Sopenharmony_ci } 781141cc406Sopenharmony_ci 782141cc406Sopenharmony_ci /* now deal with getting and setting of options */ 783141cc406Sopenharmony_ci switch (SOD (n).type) 784141cc406Sopenharmony_ci { 785141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 786141cc406Sopenharmony_ci case SANE_TYPE_INT: 787141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 788141cc406Sopenharmony_ci result = control_scalar_option (ss, n, a, v, info); 789141cc406Sopenharmony_ci break; 790141cc406Sopenharmony_ci case SANE_TYPE_STRING: 791141cc406Sopenharmony_ci result = control_string_option (ss, n, a, v, info); 792141cc406Sopenharmony_ci break; 793141cc406Sopenharmony_ci case SANE_TYPE_BUTTON: 794141cc406Sopenharmony_ci case SANE_TYPE_GROUP: 795141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "BUG:control_option():Unhandled option\n")); 796141cc406Sopenharmony_ci result = SANE_STATUS_INVAL; 797141cc406Sopenharmony_ci break; 798141cc406Sopenharmony_ci } 799141cc406Sopenharmony_ci if (result != SANE_STATUS_GOOD) 800141cc406Sopenharmony_ci return result; 801141cc406Sopenharmony_ci 802141cc406Sopenharmony_ci /* deal with dependencies between options */ 803141cc406Sopenharmony_ci switch (n) 804141cc406Sopenharmony_ci { 805141cc406Sopenharmony_ci case opt_custom_gamma: 806141cc406Sopenharmony_ci if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO) 807141cc406Sopenharmony_ci { 808141cc406Sopenharmony_ci if (enable_option (ss, opt_gamma_table, OVAL (opt_custom_gamma).b)) 809141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 810141cc406Sopenharmony_ci if (OVAL (opt_custom_gamma).b) 811141cc406Sopenharmony_ci sane_control_option (ss, opt_gamma_table, SANE_ACTION_SET_AUTO, 812141cc406Sopenharmony_ci NULL, NULL); 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci } 815141cc406Sopenharmony_ci break; 816141cc406Sopenharmony_ci case opt_gamma: 817141cc406Sopenharmony_ci if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO) 818141cc406Sopenharmony_ci { 819141cc406Sopenharmony_ci int table_size = SOD (opt_gamma_table).size / sizeof(SANE_Word); 820141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n", 821141cc406Sopenharmony_ci SANE_UNFIX (OVAL (opt_gamma).w))); 822141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*control_option***** table size = %d *\n", 823141cc406Sopenharmony_ci (int)(SOD (opt_gamma_table).size / sizeof (SANE_Word)))); 824141cc406Sopenharmony_ci pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w), 825141cc406Sopenharmony_ci ss->gamma_table, table_size); 826141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, ss->gamma_table, 827141cc406Sopenharmony_ci table_size == 1024 ? 2048 : table_size)); */ 828141cc406Sopenharmony_ci } 829141cc406Sopenharmony_ci break; 830141cc406Sopenharmony_ci case opt_mode: 831141cc406Sopenharmony_ci if (cfg->cap & (PIXMA_CAP_48BIT|PIXMA_CAP_LINEART|PIXMA_CAP_TPUIR) 832141cc406Sopenharmony_ci && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)) 833141cc406Sopenharmony_ci { /* new mode selected: Color, Gray, ... */ 834141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*control_option***** mode = %u *\n", 835141cc406Sopenharmony_ci ss->mode_map[OVAL (opt_mode).w])); */ 836141cc406Sopenharmony_ci /* recreate dynamic lists */ 837141cc406Sopenharmony_ci create_dpi_list (ss); 838141cc406Sopenharmony_ci if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART) 839141cc406Sopenharmony_ci { /* lineart */ 840141cc406Sopenharmony_ci enable_option (ss, opt_threshold, SANE_TRUE); 841141cc406Sopenharmony_ci enable_option (ss, opt_threshold_curve, SANE_TRUE); 842141cc406Sopenharmony_ci } 843141cc406Sopenharmony_ci else 844141cc406Sopenharmony_ci { /* all other modes */ 845141cc406Sopenharmony_ci enable_option (ss, opt_threshold, SANE_FALSE); 846141cc406Sopenharmony_ci enable_option (ss, opt_threshold_curve, SANE_FALSE); 847141cc406Sopenharmony_ci } 848141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 849141cc406Sopenharmony_ci } 850141cc406Sopenharmony_ci break; 851141cc406Sopenharmony_ci case opt_source: 852141cc406Sopenharmony_ci if ((cfg->cap & (PIXMA_CAP_ADF|PIXMA_CAP_ADFDUP|PIXMA_CAP_TPU)) 853141cc406Sopenharmony_ci && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)) 854141cc406Sopenharmony_ci { /* new source selected: flatbed, ADF, TPU, ... */ 855141cc406Sopenharmony_ci /* to avoid fatal errors, 856141cc406Sopenharmony_ci * select first entry of dynamic mode_list 857141cc406Sopenharmony_ci * identifiers are unknown here */ 858141cc406Sopenharmony_ci OVAL (opt_mode).w = ss->mode_map[0]; 859141cc406Sopenharmony_ci /* recreate dynamic lists */ 860141cc406Sopenharmony_ci create_mode_list (ss); 861141cc406Sopenharmony_ci create_dpi_list (ss); 862141cc406Sopenharmony_ci /* to avoid fatal errors, 863141cc406Sopenharmony_ci * select first entry of dynamic dpi_list 864141cc406Sopenharmony_ci * identifiers are unknown here */ 865141cc406Sopenharmony_ci OVAL (opt_resolution).w = ss->dpi_list[1]; 866141cc406Sopenharmony_ci if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART) 867141cc406Sopenharmony_ci { /* lineart */ 868141cc406Sopenharmony_ci enable_option (ss, opt_threshold, SANE_TRUE); 869141cc406Sopenharmony_ci enable_option (ss, opt_threshold_curve, SANE_TRUE); 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci else 872141cc406Sopenharmony_ci { /* all other modes */ 873141cc406Sopenharmony_ci enable_option (ss, opt_threshold, SANE_FALSE); 874141cc406Sopenharmony_ci enable_option (ss, opt_threshold_curve, SANE_FALSE); 875141cc406Sopenharmony_ci } 876141cc406Sopenharmony_ci if (cfg->cap & (PIXMA_CAP_ADF_WAIT)) 877141cc406Sopenharmony_ci { /* adf-wait */ 878141cc406Sopenharmony_ci enable_option (ss, opt_adf_wait, SANE_TRUE); 879141cc406Sopenharmony_ci } 880141cc406Sopenharmony_ci else 881141cc406Sopenharmony_ci { /* disable adf-wait */ 882141cc406Sopenharmony_ci enable_option (ss, opt_adf_wait, SANE_FALSE); 883141cc406Sopenharmony_ci } 884141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 885141cc406Sopenharmony_ci } 886141cc406Sopenharmony_ci break; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci 889141cc406Sopenharmony_ci return result; 890141cc406Sopenharmony_ci} 891141cc406Sopenharmony_ci 892141cc406Sopenharmony_ci#ifndef NDEBUG 893141cc406Sopenharmony_cistatic void 894141cc406Sopenharmony_ciprint_scan_param (int level, const pixma_scan_param_t * sp) 895141cc406Sopenharmony_ci{ 896141cc406Sopenharmony_ci pixma_dbg (level, "Scan parameters\n"); 897141cc406Sopenharmony_ci pixma_dbg (level, " line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n", 898141cc406Sopenharmony_ci sp->line_size, sp->image_size, sp->channels, sp->depth); 899141cc406Sopenharmony_ci pixma_dbg (level, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n", 900141cc406Sopenharmony_ci sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h); 901141cc406Sopenharmony_ci pixma_dbg (level, " gamma=%f gamma_table=%p source=%d\n", sp->gamma, 902141cc406Sopenharmony_ci (void *) sp->gamma_table, sp->source); 903141cc406Sopenharmony_ci pixma_dbg (level, " adf-wait=%d\n", sp->adf_wait); 904141cc406Sopenharmony_ci} 905141cc406Sopenharmony_ci#endif 906141cc406Sopenharmony_ci 907141cc406Sopenharmony_cistatic int 908141cc406Sopenharmony_cicalc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp) 909141cc406Sopenharmony_ci{ 910141cc406Sopenharmony_ci int x1, y1, x2, y2; 911141cc406Sopenharmony_ci int error; 912141cc406Sopenharmony_ci 913141cc406Sopenharmony_ci memset (sp, 0, sizeof (*sp)); 914141cc406Sopenharmony_ci 915141cc406Sopenharmony_ci sp->channels = (OVAL (opt_mode).w == 0) ? 3 : 1; 916141cc406Sopenharmony_ci sp->depth = (OVAL (opt_mode).w == 2) ? 1 : 8; 917141cc406Sopenharmony_ci sp->xdpi = sp->ydpi = OVAL (opt_resolution).w; 918141cc406Sopenharmony_ci 919141cc406Sopenharmony_ci#define PIXEL(x,dpi) (int)((SANE_UNFIX(x) / 25.4 * (dpi)) + 0.5) 920141cc406Sopenharmony_ci x1 = PIXEL (OVAL (opt_tl_x).w, sp->xdpi); 921141cc406Sopenharmony_ci x2 = PIXEL (OVAL (opt_br_x).w, sp->xdpi); 922141cc406Sopenharmony_ci if (x2 < x1) 923141cc406Sopenharmony_ci { 924141cc406Sopenharmony_ci int temp = x1; 925141cc406Sopenharmony_ci x1 = x2; 926141cc406Sopenharmony_ci x2 = temp; 927141cc406Sopenharmony_ci } 928141cc406Sopenharmony_ci y1 = PIXEL (OVAL (opt_tl_y).w, sp->ydpi); 929141cc406Sopenharmony_ci y2 = PIXEL (OVAL (opt_br_y).w, sp->ydpi); 930141cc406Sopenharmony_ci if (y2 < y1) 931141cc406Sopenharmony_ci { 932141cc406Sopenharmony_ci int temp = y1; 933141cc406Sopenharmony_ci y1 = y2; 934141cc406Sopenharmony_ci y2 = temp; 935141cc406Sopenharmony_ci } 936141cc406Sopenharmony_ci#undef PIXEL 937141cc406Sopenharmony_ci sp->x = x1; 938141cc406Sopenharmony_ci sp->y = y1; 939141cc406Sopenharmony_ci sp->w = x2 - x1; 940141cc406Sopenharmony_ci sp->h = y2 - y1; 941141cc406Sopenharmony_ci if (sp->w == 0) 942141cc406Sopenharmony_ci sp->w = 1; 943141cc406Sopenharmony_ci if (sp->h == 0) 944141cc406Sopenharmony_ci sp->h = 1; 945141cc406Sopenharmony_ci sp->tpu_offset_added = 0; 946141cc406Sopenharmony_ci 947141cc406Sopenharmony_ci sp->gamma = SANE_UNFIX (OVAL (opt_gamma).w); 948141cc406Sopenharmony_ci sp->gamma_table = ss->gamma_table; 949141cc406Sopenharmony_ci sp->source = ss->source_map[OVAL (opt_source).w]; 950141cc406Sopenharmony_ci sp->mode = ss->mode_map[OVAL (opt_mode).w]; 951141cc406Sopenharmony_ci sp->adf_pageid = ss->page_count; 952141cc406Sopenharmony_ci sp->threshold = 2.55 * OVAL (opt_threshold).w; 953141cc406Sopenharmony_ci sp->threshold_curve = OVAL (opt_threshold_curve).w; 954141cc406Sopenharmony_ci sp->adf_wait = OVAL (opt_adf_wait).w; 955141cc406Sopenharmony_ci sp->calibrate = ss->calibrate_map[OVAL (opt_calibrate).w]; 956141cc406Sopenharmony_ci 957141cc406Sopenharmony_ci error = pixma_check_scan_param (ss->s, sp); 958141cc406Sopenharmony_ci if (error < 0) 959141cc406Sopenharmony_ci { 960141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "BUG:calc_scan_param() failed %d\n", error)); 961141cc406Sopenharmony_ci PDBG (print_scan_param (1, sp)); 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci return error; 964141cc406Sopenharmony_ci} 965141cc406Sopenharmony_ci 966141cc406Sopenharmony_cistatic void 967141cc406Sopenharmony_ciinit_option_descriptors (pixma_sane_t * ss) 968141cc406Sopenharmony_ci{ 969141cc406Sopenharmony_ci const pixma_config_t *cfg; 970141cc406Sopenharmony_ci int i; 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci cfg = pixma_get_config (ss->s); 973141cc406Sopenharmony_ci 974141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*init_option_descriptors*****\n")); */ 975141cc406Sopenharmony_ci 976141cc406Sopenharmony_ci /* setup range for the scan area. */ 977141cc406Sopenharmony_ci ss->xrange.min = SANE_FIX (0); 978141cc406Sopenharmony_ci ss->xrange.max = SANE_FIX (cfg->width / 75.0 * 25.4); 979141cc406Sopenharmony_ci ss->xrange.quant = SANE_FIX (0); 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci ss->yrange.min = SANE_FIX (0); 982141cc406Sopenharmony_ci ss->yrange.max = SANE_FIX (cfg->height / 75.0 * 25.4); 983141cc406Sopenharmony_ci ss->yrange.quant = SANE_FIX (0); 984141cc406Sopenharmony_ci 985141cc406Sopenharmony_ci /* mode_list and source_list were already NULL-terminated, 986141cc406Sopenharmony_ci * because the whole pixma_sane_t was cleared during allocation. */ 987141cc406Sopenharmony_ci 988141cc406Sopenharmony_ci /* setup available mode. */ 989141cc406Sopenharmony_ci create_mode_list (ss); 990141cc406Sopenharmony_ci 991141cc406Sopenharmony_ci /* setup dpi up to the value supported by the scanner. */ 992141cc406Sopenharmony_ci create_dpi_list (ss); 993141cc406Sopenharmony_ci 994141cc406Sopenharmony_ci /* setup paper source */ 995141cc406Sopenharmony_ci i = 0; 996141cc406Sopenharmony_ci ss->source_list[i] = SANE_I18N ("Flatbed"); 997141cc406Sopenharmony_ci ss->source_map[i] = PIXMA_SOURCE_FLATBED; 998141cc406Sopenharmony_ci i++; 999141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_ADF) 1000141cc406Sopenharmony_ci { 1001141cc406Sopenharmony_ci ss->source_list[i] = SANE_I18N ("Automatic Document Feeder"); 1002141cc406Sopenharmony_ci ss->source_map[i] = PIXMA_SOURCE_ADF; 1003141cc406Sopenharmony_ci i++; 1004141cc406Sopenharmony_ci } 1005141cc406Sopenharmony_ci if ((cfg->cap & PIXMA_CAP_ADFDUP) == PIXMA_CAP_ADFDUP) 1006141cc406Sopenharmony_ci { 1007141cc406Sopenharmony_ci ss->source_list[i] = SANE_I18N ("ADF Duplex"); 1008141cc406Sopenharmony_ci ss->source_map[i] = PIXMA_SOURCE_ADFDUP; 1009141cc406Sopenharmony_ci i++; 1010141cc406Sopenharmony_ci } 1011141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_TPU) 1012141cc406Sopenharmony_ci { 1013141cc406Sopenharmony_ci ss->source_list[i] = SANE_I18N ("Transparency Unit"); 1014141cc406Sopenharmony_ci ss->source_map[i] = PIXMA_SOURCE_TPU; 1015141cc406Sopenharmony_ci i++; 1016141cc406Sopenharmony_ci } 1017141cc406Sopenharmony_ci 1018141cc406Sopenharmony_ci create_calibrate_list (ss); 1019141cc406Sopenharmony_ci 1020141cc406Sopenharmony_ci build_option_descriptors (ss); 1021141cc406Sopenharmony_ci 1022141cc406Sopenharmony_ci /* Enable options that are available only in some scanners. */ 1023141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_GAMMA_TABLE) 1024141cc406Sopenharmony_ci { 1025141cc406Sopenharmony_ci SANE_Option_Descriptor *sod = &SOD (opt_gamma_table); 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci /* some scanners have a large gamma table with 4096 entries */ 1028141cc406Sopenharmony_ci if (cfg->cap & PIXMA_CAP_GT_4096) 1029141cc406Sopenharmony_ci { 1030141cc406Sopenharmony_ci static const SANE_Range constraint_gamma_table_4096 = { 0,0xff,0 }; 1031141cc406Sopenharmony_ci sod->desc = SANE_I18N("Gamma-correction table with 4096 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table)."); 1032141cc406Sopenharmony_ci sod->size = 4096 * sizeof(SANE_Word); 1033141cc406Sopenharmony_ci sod->constraint.range = &constraint_gamma_table_4096; 1034141cc406Sopenharmony_ci } 1035141cc406Sopenharmony_ci 1036141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*%s***** PIXMA_CAP_GAMMA_TABLE ***** \n", 1037141cc406Sopenharmony_ci __func__)); */ 1038141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "%s: gamma_table_contraint.max = %d\n", 1039141cc406Sopenharmony_ci __func__, sod->constraint.range->max)); */ 1040141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "%s: gamma_table_size = %d\n", 1041141cc406Sopenharmony_ci __func__, sod->size / sizeof(SANE_Word))); */ 1042141cc406Sopenharmony_ci 1043141cc406Sopenharmony_ci /* activate option gamma */ 1044141cc406Sopenharmony_ci enable_option (ss, opt_gamma, SANE_TRUE); 1045141cc406Sopenharmony_ci sane_control_option (ss, opt_gamma, SANE_ACTION_SET_AUTO, 1046141cc406Sopenharmony_ci NULL, NULL); 1047141cc406Sopenharmony_ci /* activate option custom gamma table */ 1048141cc406Sopenharmony_ci enable_option (ss, opt_custom_gamma, SANE_TRUE); 1049141cc406Sopenharmony_ci sane_control_option (ss, opt_custom_gamma, SANE_ACTION_SET_AUTO, 1050141cc406Sopenharmony_ci NULL, NULL); 1051141cc406Sopenharmony_ci } 1052141cc406Sopenharmony_ci enable_option (ss, opt_button_controlled, 1053141cc406Sopenharmony_ci ((cfg->cap & PIXMA_CAP_EVENTS) != 0)); 1054141cc406Sopenharmony_ci} 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci/* Writing to reader_ss outside reader_process() is a BUG! */ 1057141cc406Sopenharmony_cistatic pixma_sane_t *reader_ss = NULL; 1058141cc406Sopenharmony_ci 1059141cc406Sopenharmony_cistatic void 1060141cc406Sopenharmony_cireader_signal_handler (int sig) 1061141cc406Sopenharmony_ci{ 1062141cc406Sopenharmony_ci if (reader_ss) 1063141cc406Sopenharmony_ci { 1064141cc406Sopenharmony_ci reader_ss->reader_stop = SANE_TRUE; 1065141cc406Sopenharmony_ci /* reader process is ended by SIGTERM, so no cancel in this case */ 1066141cc406Sopenharmony_ci if (sig != SIGTERM) 1067141cc406Sopenharmony_ci pixma_cancel (reader_ss->s); 1068141cc406Sopenharmony_ci } 1069141cc406Sopenharmony_ci} 1070141cc406Sopenharmony_ci 1071141cc406Sopenharmony_cistatic int 1072141cc406Sopenharmony_ciwrite_all (pixma_sane_t * ss, void *buf_, size_t size) 1073141cc406Sopenharmony_ci{ 1074141cc406Sopenharmony_ci uint8_t *buf = (uint8_t *) buf_; 1075141cc406Sopenharmony_ci int count; 1076141cc406Sopenharmony_ci 1077141cc406Sopenharmony_ci while (size != 0 && !ss->reader_stop) 1078141cc406Sopenharmony_ci { 1079141cc406Sopenharmony_ci count = write (ss->wpipe, buf, size); 1080141cc406Sopenharmony_ci if (count == -1 && errno != EINTR) 1081141cc406Sopenharmony_ci break; 1082141cc406Sopenharmony_ci if (count == -1 && errno == EINTR) 1083141cc406Sopenharmony_ci continue; 1084141cc406Sopenharmony_ci buf += count; 1085141cc406Sopenharmony_ci size -= count; 1086141cc406Sopenharmony_ci } 1087141cc406Sopenharmony_ci return buf - (uint8_t *) buf_; 1088141cc406Sopenharmony_ci} 1089141cc406Sopenharmony_ci 1090141cc406Sopenharmony_ci/* NOTE: reader_loop() runs either in a separate thread or process. */ 1091141cc406Sopenharmony_cistatic SANE_Status 1092141cc406Sopenharmony_cireader_loop (pixma_sane_t * ss) 1093141cc406Sopenharmony_ci{ 1094141cc406Sopenharmony_ci void *buf; 1095141cc406Sopenharmony_ci unsigned bufsize; 1096141cc406Sopenharmony_ci int count = 0; 1097141cc406Sopenharmony_ci 1098141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Reader task started\n")); 1099141cc406Sopenharmony_ci /*bufsize = ss->sp.line_size + 1;*/ /* XXX: "odd" bufsize for testing pixma_read_image() */ 1100141cc406Sopenharmony_ci bufsize = ss->sp.line_size; /* bufsize EVEN needed by Xsane for 48 bits depth */ 1101141cc406Sopenharmony_ci buf = malloc (bufsize); 1102141cc406Sopenharmony_ci if (!buf) 1103141cc406Sopenharmony_ci { 1104141cc406Sopenharmony_ci count = PIXMA_ENOMEM; 1105141cc406Sopenharmony_ci goto done; 1106141cc406Sopenharmony_ci } 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_ci count = pixma_activate_connection (ss->s); 1109141cc406Sopenharmony_ci if (count < 0) 1110141cc406Sopenharmony_ci goto done; 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci pixma_enable_background (ss->s, 1); 1113141cc406Sopenharmony_ci if (OVAL (opt_button_controlled).b && ss->page_count == 0) 1114141cc406Sopenharmony_ci { 1115141cc406Sopenharmony_ci int start = 0; 1116141cc406Sopenharmony_ci#ifndef NDEBUG 1117141cc406Sopenharmony_ci pixma_dbg (1, "==== Button-controlled scan mode is enabled.\n"); 1118141cc406Sopenharmony_ci pixma_dbg (1, "==== To proceed, press 'SCAN' or 'COLOR' button. " 1119141cc406Sopenharmony_ci "To cancel, press 'GRAY' or 'END' button.\n"); 1120141cc406Sopenharmony_ci#endif 1121141cc406Sopenharmony_ci while (pixma_wait_event (ss->s, 10) != 0) 1122141cc406Sopenharmony_ci { 1123141cc406Sopenharmony_ci } 1124141cc406Sopenharmony_ci while (!start) 1125141cc406Sopenharmony_ci { 1126141cc406Sopenharmony_ci uint32_t events; 1127141cc406Sopenharmony_ci if (ss->reader_stop) 1128141cc406Sopenharmony_ci { 1129141cc406Sopenharmony_ci count = PIXMA_ECANCELED; 1130141cc406Sopenharmony_ci goto done; 1131141cc406Sopenharmony_ci } 1132141cc406Sopenharmony_ci events = pixma_wait_event (ss->s, 1000); 1133141cc406Sopenharmony_ci switch (events & ~PIXMA_EV_ACTION_MASK) 1134141cc406Sopenharmony_ci { 1135141cc406Sopenharmony_ci case PIXMA_EV_BUTTON1: 1136141cc406Sopenharmony_ci start = 1; 1137141cc406Sopenharmony_ci break; 1138141cc406Sopenharmony_ci case PIXMA_EV_BUTTON2: 1139141cc406Sopenharmony_ci count = PIXMA_ECANCELED; 1140141cc406Sopenharmony_ci goto done; 1141141cc406Sopenharmony_ci } 1142141cc406Sopenharmony_ci } 1143141cc406Sopenharmony_ci } 1144141cc406Sopenharmony_ci count = pixma_scan (ss->s, &ss->sp); 1145141cc406Sopenharmony_ci if (count >= 0) 1146141cc406Sopenharmony_ci { 1147141cc406Sopenharmony_ci while ((count = pixma_read_image (ss->s, buf, bufsize)) > 0) 1148141cc406Sopenharmony_ci { 1149141cc406Sopenharmony_ci if (write_all (ss, buf, count) != count) 1150141cc406Sopenharmony_ci pixma_cancel (ss->s); 1151141cc406Sopenharmony_ci } 1152141cc406Sopenharmony_ci } 1153141cc406Sopenharmony_ci 1154141cc406Sopenharmony_cidone: 1155141cc406Sopenharmony_ci pixma_enable_background (ss->s, 0); 1156141cc406Sopenharmony_ci pixma_deactivate_connection (ss->s); 1157141cc406Sopenharmony_ci free (buf); 1158141cc406Sopenharmony_ci close (ss->wpipe); 1159141cc406Sopenharmony_ci ss->wpipe = -1; 1160141cc406Sopenharmony_ci if (count >= 0) 1161141cc406Sopenharmony_ci { 1162141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Reader task terminated\n")); 1163141cc406Sopenharmony_ci } 1164141cc406Sopenharmony_ci else 1165141cc406Sopenharmony_ci { 1166141cc406Sopenharmony_ci PDBG (pixma_dbg 1167141cc406Sopenharmony_ci (2, "Reader task terminated: %s\n", pixma_strerror (count))); 1168141cc406Sopenharmony_ci } 1169141cc406Sopenharmony_ci return map_error (count); 1170141cc406Sopenharmony_ci} 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_cistatic int 1173141cc406Sopenharmony_cireader_process (void *arg) 1174141cc406Sopenharmony_ci{ 1175141cc406Sopenharmony_ci pixma_sane_t *ss = (pixma_sane_t *) arg; 1176141cc406Sopenharmony_ci struct SIGACTION sa; 1177141cc406Sopenharmony_ci 1178141cc406Sopenharmony_ci reader_ss = ss; 1179141cc406Sopenharmony_ci memset (&sa, 0, sizeof (sa)); 1180141cc406Sopenharmony_ci sigemptyset (&sa.sa_mask); 1181141cc406Sopenharmony_ci sa.sa_handler = reader_signal_handler; 1182141cc406Sopenharmony_ci /* FIXME: which signal else? */ 1183141cc406Sopenharmony_ci sigaction (SIGHUP, &sa, NULL); 1184141cc406Sopenharmony_ci sigaction (SIGINT, &sa, NULL); 1185141cc406Sopenharmony_ci sigaction (SIGPIPE, &sa, NULL); 1186141cc406Sopenharmony_ci sigaction (SIGTERM, &sa, NULL); 1187141cc406Sopenharmony_ci close (ss->rpipe); 1188141cc406Sopenharmony_ci ss->rpipe = -1; 1189141cc406Sopenharmony_ci return reader_loop (ss); 1190141cc406Sopenharmony_ci} 1191141cc406Sopenharmony_ci 1192141cc406Sopenharmony_cistatic int 1193141cc406Sopenharmony_cireader_thread (void *arg) 1194141cc406Sopenharmony_ci{ 1195141cc406Sopenharmony_ci pixma_sane_t *ss = (pixma_sane_t *) arg; 1196141cc406Sopenharmony_ci#ifdef USE_PTHREAD 1197141cc406Sopenharmony_ci /* Block SIGPIPE. We will handle this in reader_loop() by checking 1198141cc406Sopenharmony_ci ss->reader_stop and the return value from write(). */ 1199141cc406Sopenharmony_ci sigset_t sigs; 1200141cc406Sopenharmony_ci sigemptyset (&sigs); 1201141cc406Sopenharmony_ci sigaddset (&sigs, SIGPIPE); 1202141cc406Sopenharmony_ci pthread_sigmask (SIG_BLOCK, &sigs, NULL); 1203141cc406Sopenharmony_ci#endif /* USE_PTHREAD */ 1204141cc406Sopenharmony_ci return reader_loop (ss); 1205141cc406Sopenharmony_ci} 1206141cc406Sopenharmony_ci 1207141cc406Sopenharmony_cistatic SANE_Pid 1208141cc406Sopenharmony_citerminate_reader_task (pixma_sane_t * ss, int *exit_code) 1209141cc406Sopenharmony_ci{ 1210141cc406Sopenharmony_ci SANE_Pid result, pid; 1211141cc406Sopenharmony_ci int status = 0; 1212141cc406Sopenharmony_ci 1213141cc406Sopenharmony_ci pid = ss->reader_taskid; 1214141cc406Sopenharmony_ci if (!sanei_thread_is_valid (pid)) 1215141cc406Sopenharmony_ci return pid; 1216141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 1217141cc406Sopenharmony_ci { 1218141cc406Sopenharmony_ci sanei_thread_kill (pid); 1219141cc406Sopenharmony_ci } 1220141cc406Sopenharmony_ci else 1221141cc406Sopenharmony_ci { 1222141cc406Sopenharmony_ci ss->reader_stop = SANE_TRUE; 1223141cc406Sopenharmony_ci/* pixma_cancel (ss->s); What is this for ? Makes end-of-scan buggy => removing */ 1224141cc406Sopenharmony_ci } 1225141cc406Sopenharmony_ci result = sanei_thread_waitpid (pid, &status); 1226141cc406Sopenharmony_ci sanei_thread_invalidate (ss->reader_taskid); 1227141cc406Sopenharmony_ci 1228141cc406Sopenharmony_ci if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) 1229141cc406Sopenharmony_ci ss->idle = SANE_TRUE; 1230141cc406Sopenharmony_ci 1231141cc406Sopenharmony_ci if (result == pid) 1232141cc406Sopenharmony_ci { 1233141cc406Sopenharmony_ci if (exit_code) 1234141cc406Sopenharmony_ci *exit_code = status; 1235141cc406Sopenharmony_ci return pid; 1236141cc406Sopenharmony_ci } 1237141cc406Sopenharmony_ci else 1238141cc406Sopenharmony_ci { 1239141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING:waitpid() failed %s\n", strerror (errno))); 1240141cc406Sopenharmony_ci sanei_thread_invalidate (pid); 1241141cc406Sopenharmony_ci return pid; 1242141cc406Sopenharmony_ci } 1243141cc406Sopenharmony_ci} 1244141cc406Sopenharmony_ci 1245141cc406Sopenharmony_cistatic int 1246141cc406Sopenharmony_cistart_reader_task (pixma_sane_t * ss) 1247141cc406Sopenharmony_ci{ 1248141cc406Sopenharmony_ci int fds[2]; 1249141cc406Sopenharmony_ci SANE_Pid pid; 1250141cc406Sopenharmony_ci int is_forked; 1251141cc406Sopenharmony_ci 1252141cc406Sopenharmony_ci if (ss->rpipe != -1 || ss->wpipe != -1) 1253141cc406Sopenharmony_ci { 1254141cc406Sopenharmony_ci PDBG (pixma_dbg 1255141cc406Sopenharmony_ci (1, "BUG:rpipe = %d, wpipe = %d\n", ss->rpipe, ss->wpipe)); 1256141cc406Sopenharmony_ci close (ss->rpipe); 1257141cc406Sopenharmony_ci close (ss->wpipe); 1258141cc406Sopenharmony_ci ss->rpipe = -1; 1259141cc406Sopenharmony_ci ss->wpipe = -1; 1260141cc406Sopenharmony_ci } 1261141cc406Sopenharmony_ci if (sanei_thread_is_valid (ss->reader_taskid)) 1262141cc406Sopenharmony_ci { 1263141cc406Sopenharmony_ci PDBG (pixma_dbg 1264141cc406Sopenharmony_ci (1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid)); 1265141cc406Sopenharmony_ci terminate_reader_task (ss, NULL); 1266141cc406Sopenharmony_ci } 1267141cc406Sopenharmony_ci if (pipe (fds) == -1) 1268141cc406Sopenharmony_ci { 1269141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "ERROR:start_reader_task():pipe() failed %s\n", 1270141cc406Sopenharmony_ci strerror (errno))); 1271141cc406Sopenharmony_ci return PIXMA_ENOMEM; 1272141cc406Sopenharmony_ci } 1273141cc406Sopenharmony_ci ss->rpipe = fds[0]; 1274141cc406Sopenharmony_ci ss->wpipe = fds[1]; 1275141cc406Sopenharmony_ci ss->reader_stop = SANE_FALSE; 1276141cc406Sopenharmony_ci 1277141cc406Sopenharmony_ci is_forked = sanei_thread_is_forked (); 1278141cc406Sopenharmony_ci if (is_forked) 1279141cc406Sopenharmony_ci { 1280141cc406Sopenharmony_ci pid = sanei_thread_begin (reader_process, ss); 1281141cc406Sopenharmony_ci if (sanei_thread_is_valid (pid)) 1282141cc406Sopenharmony_ci { 1283141cc406Sopenharmony_ci close (ss->wpipe); 1284141cc406Sopenharmony_ci ss->wpipe = -1; 1285141cc406Sopenharmony_ci } 1286141cc406Sopenharmony_ci } 1287141cc406Sopenharmony_ci else 1288141cc406Sopenharmony_ci { 1289141cc406Sopenharmony_ci pid = sanei_thread_begin (reader_thread, ss); 1290141cc406Sopenharmony_ci } 1291141cc406Sopenharmony_ci if (!sanei_thread_is_valid (pid)) 1292141cc406Sopenharmony_ci { 1293141cc406Sopenharmony_ci close (ss->wpipe); 1294141cc406Sopenharmony_ci close (ss->rpipe); 1295141cc406Sopenharmony_ci ss->wpipe = -1; 1296141cc406Sopenharmony_ci ss->rpipe = -1; 1297141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n")); 1298141cc406Sopenharmony_ci return PIXMA_ENOMEM; 1299141cc406Sopenharmony_ci } 1300141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n", (long) pid, 1301141cc406Sopenharmony_ci (is_forked) ? "forked" : "threaded")); 1302141cc406Sopenharmony_ci ss->reader_taskid = pid; 1303141cc406Sopenharmony_ci return 0; 1304141cc406Sopenharmony_ci} 1305141cc406Sopenharmony_ci 1306141cc406Sopenharmony_ci/* libJPEG API callbacks */ 1307141cc406Sopenharmony_cistatic void 1308141cc406Sopenharmony_cijpeg_init_source(j_decompress_ptr __sane_unused__ cinfo) 1309141cc406Sopenharmony_ci{ 1310141cc406Sopenharmony_ci /* No-op */ 1311141cc406Sopenharmony_ci} 1312141cc406Sopenharmony_ci 1313141cc406Sopenharmony_cistatic void 1314141cc406Sopenharmony_cijpeg_term_source(j_decompress_ptr __sane_unused__ cinfo) 1315141cc406Sopenharmony_ci{ 1316141cc406Sopenharmony_ci /* No-op */ 1317141cc406Sopenharmony_ci} 1318141cc406Sopenharmony_ci 1319141cc406Sopenharmony_cistatic boolean 1320141cc406Sopenharmony_cijpeg_fill_input_buffer(j_decompress_ptr cinfo) 1321141cc406Sopenharmony_ci{ 1322141cc406Sopenharmony_ci pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src; 1323141cc406Sopenharmony_ci int size; 1324141cc406Sopenharmony_ci int retry; 1325141cc406Sopenharmony_ci 1326141cc406Sopenharmony_ci for (retry = 0; retry < 30; retry ++ ) 1327141cc406Sopenharmony_ci { 1328141cc406Sopenharmony_ci size = read (mgr->s->rpipe, mgr->buffer, 1024); 1329141cc406Sopenharmony_ci if (size == 0) 1330141cc406Sopenharmony_ci { 1331141cc406Sopenharmony_ci return FALSE; 1332141cc406Sopenharmony_ci } 1333141cc406Sopenharmony_ci else if (size < 0) 1334141cc406Sopenharmony_ci { 1335141cc406Sopenharmony_ci sleep (1); 1336141cc406Sopenharmony_ci } 1337141cc406Sopenharmony_ci else 1338141cc406Sopenharmony_ci { 1339141cc406Sopenharmony_ci mgr->jpeg.next_input_byte = mgr->buffer; 1340141cc406Sopenharmony_ci mgr->jpeg.bytes_in_buffer = size; 1341141cc406Sopenharmony_ci return TRUE; 1342141cc406Sopenharmony_ci } 1343141cc406Sopenharmony_ci } 1344141cc406Sopenharmony_ci 1345141cc406Sopenharmony_ci return FALSE; 1346141cc406Sopenharmony_ci} 1347141cc406Sopenharmony_ci 1348141cc406Sopenharmony_cistatic void 1349141cc406Sopenharmony_cijpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 1350141cc406Sopenharmony_ci{ 1351141cc406Sopenharmony_ci pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src; 1352141cc406Sopenharmony_ci 1353141cc406Sopenharmony_ci if (num_bytes > 0) 1354141cc406Sopenharmony_ci { 1355141cc406Sopenharmony_ci /* Read and throw away extra */ 1356141cc406Sopenharmony_ci while (num_bytes > (long)mgr->jpeg.bytes_in_buffer) 1357141cc406Sopenharmony_ci { 1358141cc406Sopenharmony_ci num_bytes -= (long)mgr->jpeg.bytes_in_buffer; 1359141cc406Sopenharmony_ci jpeg_fill_input_buffer(cinfo); 1360141cc406Sopenharmony_ci } 1361141cc406Sopenharmony_ci 1362141cc406Sopenharmony_ci /* Update jpeg info structure with leftover */ 1363141cc406Sopenharmony_ci mgr->jpeg.next_input_byte += (size_t) num_bytes; 1364141cc406Sopenharmony_ci mgr->jpeg.bytes_in_buffer -= (size_t) num_bytes; 1365141cc406Sopenharmony_ci } 1366141cc406Sopenharmony_ci} 1367141cc406Sopenharmony_ci 1368141cc406Sopenharmony_ci/* Pixma JPEG reader helpers */ 1369141cc406Sopenharmony_cistatic SANE_Status 1370141cc406Sopenharmony_cipixma_jpeg_start(pixma_sane_t *s) 1371141cc406Sopenharmony_ci{ 1372141cc406Sopenharmony_ci pixma_jpeg_src_mgr *mgr; 1373141cc406Sopenharmony_ci 1374141cc406Sopenharmony_ci s->jpeg_cinfo.err = jpeg_std_error(&s->jpeg_err); 1375141cc406Sopenharmony_ci 1376141cc406Sopenharmony_ci jpeg_create_decompress(&s->jpeg_cinfo); 1377141cc406Sopenharmony_ci 1378141cc406Sopenharmony_ci s->jpeg_cinfo.src = (struct jpeg_source_mgr *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo, 1379141cc406Sopenharmony_ci JPOOL_PERMANENT, sizeof(pixma_jpeg_src_mgr)); 1380141cc406Sopenharmony_ci 1381141cc406Sopenharmony_ci memset(s->jpeg_cinfo.src, 0, sizeof(pixma_jpeg_src_mgr)); 1382141cc406Sopenharmony_ci 1383141cc406Sopenharmony_ci mgr = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src; 1384141cc406Sopenharmony_ci mgr->s = s; 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci mgr->buffer = (JOCTET *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo, 1387141cc406Sopenharmony_ci JPOOL_PERMANENT, 1388141cc406Sopenharmony_ci 1024 * sizeof(JOCTET)); 1389141cc406Sopenharmony_ci 1390141cc406Sopenharmony_ci mgr->jpeg.init_source = jpeg_init_source; 1391141cc406Sopenharmony_ci mgr->jpeg.fill_input_buffer = jpeg_fill_input_buffer; 1392141cc406Sopenharmony_ci mgr->jpeg.skip_input_data = jpeg_skip_input_data; 1393141cc406Sopenharmony_ci mgr->jpeg.resync_to_restart = jpeg_resync_to_restart; 1394141cc406Sopenharmony_ci mgr->jpeg.term_source = jpeg_term_source; 1395141cc406Sopenharmony_ci mgr->jpeg.bytes_in_buffer = 0; 1396141cc406Sopenharmony_ci mgr->jpeg.next_input_byte = NULL; 1397141cc406Sopenharmony_ci 1398141cc406Sopenharmony_ci s->jpeg_header_seen = 0; 1399141cc406Sopenharmony_ci 1400141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1401141cc406Sopenharmony_ci} 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_cistatic SANE_Status 1404141cc406Sopenharmony_cipixma_jpeg_read_header(pixma_sane_t *s) 1405141cc406Sopenharmony_ci{ 1406141cc406Sopenharmony_ci pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src; 1407141cc406Sopenharmony_ci 1408141cc406Sopenharmony_ci if (jpeg_read_header(&s->jpeg_cinfo, TRUE)) 1409141cc406Sopenharmony_ci { 1410141cc406Sopenharmony_ci s->jdst = sanei_jpeg_jinit_write_ppm(&s->jpeg_cinfo); 1411141cc406Sopenharmony_ci 1412141cc406Sopenharmony_ci if (jpeg_start_decompress(&s->jpeg_cinfo)) 1413141cc406Sopenharmony_ci { 1414141cc406Sopenharmony_ci int size; 1415141cc406Sopenharmony_ci 1416141cc406Sopenharmony_ci DBG(3, "%s: w: %d, h: %d, components: %d\n", 1417141cc406Sopenharmony_ci __func__, 1418141cc406Sopenharmony_ci s->jpeg_cinfo.output_width, s->jpeg_cinfo.output_height, 1419141cc406Sopenharmony_ci s->jpeg_cinfo.output_components); 1420141cc406Sopenharmony_ci 1421141cc406Sopenharmony_ci size = s->jpeg_cinfo.output_width * s->jpeg_cinfo.output_components * 1; 1422141cc406Sopenharmony_ci 1423141cc406Sopenharmony_ci src->linebuffer = (*s->jpeg_cinfo.mem->alloc_large)((j_common_ptr)&s->jpeg_cinfo, 1424141cc406Sopenharmony_ci JPOOL_PERMANENT, size); 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci src->linebuffer_size = 0; 1427141cc406Sopenharmony_ci src->linebuffer_index = 0; 1428141cc406Sopenharmony_ci 1429141cc406Sopenharmony_ci s->jpeg_header_seen = 1; 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1432141cc406Sopenharmony_ci } 1433141cc406Sopenharmony_ci else 1434141cc406Sopenharmony_ci { 1435141cc406Sopenharmony_ci DBG(0, "%s: decompression failed\n", __func__); 1436141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1437141cc406Sopenharmony_ci } 1438141cc406Sopenharmony_ci } 1439141cc406Sopenharmony_ci else 1440141cc406Sopenharmony_ci { 1441141cc406Sopenharmony_ci DBG(0, "%s: cannot read JPEG header\n", __func__); 1442141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1443141cc406Sopenharmony_ci } 1444141cc406Sopenharmony_ci} 1445141cc406Sopenharmony_ci 1446141cc406Sopenharmony_cistatic void 1447141cc406Sopenharmony_cipixma_jpeg_finish(pixma_sane_t *ss) 1448141cc406Sopenharmony_ci{ 1449141cc406Sopenharmony_ci jpeg_destroy_decompress(&ss->jpeg_cinfo); 1450141cc406Sopenharmony_ci} 1451141cc406Sopenharmony_ci 1452141cc406Sopenharmony_cistatic void 1453141cc406Sopenharmony_cipixma_jpeg_read(pixma_sane_t *ss, SANE_Byte *data, 1454141cc406Sopenharmony_ci SANE_Int max_length, SANE_Int *length) 1455141cc406Sopenharmony_ci{ 1456141cc406Sopenharmony_ci struct jpeg_decompress_struct *cinfo = &ss->jpeg_cinfo; 1457141cc406Sopenharmony_ci pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)cinfo->src; 1458141cc406Sopenharmony_ci 1459141cc406Sopenharmony_ci int l; 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci *length = 0; 1462141cc406Sopenharmony_ci 1463141cc406Sopenharmony_ci /* copy from line buffer if available */ 1464141cc406Sopenharmony_ci if (src->linebuffer_size && src->linebuffer_index < src->linebuffer_size) 1465141cc406Sopenharmony_ci { 1466141cc406Sopenharmony_ci *length = src->linebuffer_size - src->linebuffer_index; 1467141cc406Sopenharmony_ci 1468141cc406Sopenharmony_ci if (*length > max_length) 1469141cc406Sopenharmony_ci *length = max_length; 1470141cc406Sopenharmony_ci 1471141cc406Sopenharmony_ci memcpy(data, src->linebuffer + src->linebuffer_index, *length); 1472141cc406Sopenharmony_ci src->linebuffer_index += *length; 1473141cc406Sopenharmony_ci 1474141cc406Sopenharmony_ci return; 1475141cc406Sopenharmony_ci } 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci if (cinfo->output_scanline >= cinfo->output_height) 1478141cc406Sopenharmony_ci { 1479141cc406Sopenharmony_ci *length = 0; 1480141cc406Sopenharmony_ci return; 1481141cc406Sopenharmony_ci } 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ci /* scanlines of decompressed data will be in ss->jdst->buffer 1484141cc406Sopenharmony_ci * only one line at time is supported 1485141cc406Sopenharmony_ci */ 1486141cc406Sopenharmony_ci 1487141cc406Sopenharmony_ci l = jpeg_read_scanlines(cinfo, ss->jdst->buffer, 1); 1488141cc406Sopenharmony_ci if (l == 0) 1489141cc406Sopenharmony_ci return; 1490141cc406Sopenharmony_ci 1491141cc406Sopenharmony_ci /* from ss->jdst->buffer to linebuffer 1492141cc406Sopenharmony_ci * linebuffer holds width * bytesperpixel 1493141cc406Sopenharmony_ci */ 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_ci (*ss->jdst->put_pixel_rows)(cinfo, ss->jdst, 1, (char *)src->linebuffer); 1496141cc406Sopenharmony_ci 1497141cc406Sopenharmony_ci *length = ss->sp.w * ss->sp.channels; 1498141cc406Sopenharmony_ci /* Convert RGB into grayscale */ 1499141cc406Sopenharmony_ci if (ss->sp.channels == 1) 1500141cc406Sopenharmony_ci { 1501141cc406Sopenharmony_ci unsigned int i; 1502141cc406Sopenharmony_ci unsigned char *d = (unsigned char *)src->linebuffer; 1503141cc406Sopenharmony_ci unsigned char *s = (unsigned char *)src->linebuffer; 1504141cc406Sopenharmony_ci for (i = 0; i < ss->sp.w; i++) 1505141cc406Sopenharmony_ci { 1506141cc406Sopenharmony_ci /* Using BT.709 luma formula, fixed-point */ 1507141cc406Sopenharmony_ci int sum = ( s[0]*2126 + s[1]*7152 + s[2]*722 ); 1508141cc406Sopenharmony_ci *d = sum / 10000; 1509141cc406Sopenharmony_ci d ++; 1510141cc406Sopenharmony_ci s += 3; 1511141cc406Sopenharmony_ci } 1512141cc406Sopenharmony_ci } 1513141cc406Sopenharmony_ci 1514141cc406Sopenharmony_ci /* Maybe pack into lineary binary image */ 1515141cc406Sopenharmony_ci if (ss->sp.depth == 1) 1516141cc406Sopenharmony_ci { 1517141cc406Sopenharmony_ci *length /= 8; 1518141cc406Sopenharmony_ci unsigned int i; 1519141cc406Sopenharmony_ci unsigned char *d = (unsigned char *)src->linebuffer; 1520141cc406Sopenharmony_ci unsigned char *s = (unsigned char *)src->linebuffer; 1521141cc406Sopenharmony_ci unsigned char b = 0; 1522141cc406Sopenharmony_ci for (i = 1; i < ss->sp.w + 1; i++) 1523141cc406Sopenharmony_ci { 1524141cc406Sopenharmony_ci if (*(s++) > 127) 1525141cc406Sopenharmony_ci b = (b << 1) | 0; 1526141cc406Sopenharmony_ci else 1527141cc406Sopenharmony_ci b = (b << 1) | 1; 1528141cc406Sopenharmony_ci if ((i % 8) == 0) 1529141cc406Sopenharmony_ci *(d++) = b; 1530141cc406Sopenharmony_ci } 1531141cc406Sopenharmony_ci } 1532141cc406Sopenharmony_ci 1533141cc406Sopenharmony_ci src->linebuffer_size = *length; 1534141cc406Sopenharmony_ci src->linebuffer_index = 0; 1535141cc406Sopenharmony_ci 1536141cc406Sopenharmony_ci if (*length > max_length) 1537141cc406Sopenharmony_ci *length = max_length; 1538141cc406Sopenharmony_ci 1539141cc406Sopenharmony_ci memcpy(data, src->linebuffer + src->linebuffer_index, *length); 1540141cc406Sopenharmony_ci src->linebuffer_index += *length; 1541141cc406Sopenharmony_ci} 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci 1544141cc406Sopenharmony_ci 1545141cc406Sopenharmony_cistatic SANE_Status 1546141cc406Sopenharmony_ciread_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) 1547141cc406Sopenharmony_ci{ 1548141cc406Sopenharmony_ci int count, status; 1549141cc406Sopenharmony_ci 1550141cc406Sopenharmony_ci if (readlen) 1551141cc406Sopenharmony_ci *readlen = 0; 1552141cc406Sopenharmony_ci if (ss->image_bytes_read >= ss->sp.image_size) 1553141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1554141cc406Sopenharmony_ci 1555141cc406Sopenharmony_ci do 1556141cc406Sopenharmony_ci { 1557141cc406Sopenharmony_ci if (ss->cancel) 1558141cc406Sopenharmony_ci /* ss->rpipe has already been closed by sane_cancel(). */ 1559141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1560141cc406Sopenharmony_ci if (ss->sp.mode_jpeg && !ss->jpeg_header_seen) 1561141cc406Sopenharmony_ci { 1562141cc406Sopenharmony_ci status = pixma_jpeg_read_header(ss); 1563141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1564141cc406Sopenharmony_ci { 1565141cc406Sopenharmony_ci close (ss->rpipe); 1566141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 1567141cc406Sopenharmony_ci ss->rpipe = -1; 1568141cc406Sopenharmony_ci if (sanei_thread_is_valid (terminate_reader_task (ss, &status)) 1569141cc406Sopenharmony_ci && status != SANE_STATUS_GOOD) 1570141cc406Sopenharmony_ci { 1571141cc406Sopenharmony_ci return status; 1572141cc406Sopenharmony_ci } 1573141cc406Sopenharmony_ci else 1574141cc406Sopenharmony_ci { 1575141cc406Sopenharmony_ci /* either terminate_reader_task failed or 1576141cc406Sopenharmony_ci rpipe was closed but we expect more data */ 1577141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1578141cc406Sopenharmony_ci } 1579141cc406Sopenharmony_ci } 1580141cc406Sopenharmony_ci } 1581141cc406Sopenharmony_ci 1582141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 1583141cc406Sopenharmony_ci { 1584141cc406Sopenharmony_ci count = -1; 1585141cc406Sopenharmony_ci pixma_jpeg_read(ss, buf, size, &count); 1586141cc406Sopenharmony_ci } 1587141cc406Sopenharmony_ci else 1588141cc406Sopenharmony_ci count = read (ss->rpipe, buf, size); 1589141cc406Sopenharmony_ci } 1590141cc406Sopenharmony_ci while (count == -1 && errno == EINTR); 1591141cc406Sopenharmony_ci 1592141cc406Sopenharmony_ci if (count == -1) 1593141cc406Sopenharmony_ci { 1594141cc406Sopenharmony_ci if (errno == EAGAIN) 1595141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1596141cc406Sopenharmony_ci if (!ss->cancel) 1597141cc406Sopenharmony_ci { 1598141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING:read_image():read() failed %s\n", 1599141cc406Sopenharmony_ci strerror (errno))); 1600141cc406Sopenharmony_ci } 1601141cc406Sopenharmony_ci close (ss->rpipe); 1602141cc406Sopenharmony_ci ss->rpipe = -1; 1603141cc406Sopenharmony_ci terminate_reader_task (ss, NULL); 1604141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 1605141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 1606141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1607141cc406Sopenharmony_ci } 1608141cc406Sopenharmony_ci 1609141cc406Sopenharmony_ci /* here count >= 0 */ 1610141cc406Sopenharmony_ci ss->image_bytes_read += count; 1611141cc406Sopenharmony_ci if (ss->image_bytes_read > ss->sp.image_size) 1612141cc406Sopenharmony_ci { 1613141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "BUG:ss->image_bytes_read > ss->sp.image_size\n")); 1614141cc406Sopenharmony_ci } 1615141cc406Sopenharmony_ci if (ss->image_bytes_read >= ss->sp.image_size) 1616141cc406Sopenharmony_ci { 1617141cc406Sopenharmony_ci close (ss->rpipe); 1618141cc406Sopenharmony_ci ss->rpipe = -1; 1619141cc406Sopenharmony_ci terminate_reader_task (ss, NULL); 1620141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 1621141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 1622141cc406Sopenharmony_ci } 1623141cc406Sopenharmony_ci else if (count == 0) 1624141cc406Sopenharmony_ci { 1625141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "read_image():reader task closed the pipe:%" 1626141cc406Sopenharmony_ci PRIu64" bytes received, %"PRIu64" bytes expected\n", 1627141cc406Sopenharmony_ci ss->image_bytes_read, ss->sp.image_size)); 1628141cc406Sopenharmony_ci close (ss->rpipe); 1629141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 1630141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 1631141cc406Sopenharmony_ci ss->rpipe = -1; 1632141cc406Sopenharmony_ci if (sanei_thread_is_valid (terminate_reader_task (ss, &status)) 1633141cc406Sopenharmony_ci && status != SANE_STATUS_GOOD) 1634141cc406Sopenharmony_ci { 1635141cc406Sopenharmony_ci return status; 1636141cc406Sopenharmony_ci } 1637141cc406Sopenharmony_ci else 1638141cc406Sopenharmony_ci { 1639141cc406Sopenharmony_ci /* either terminate_reader_task failed or 1640141cc406Sopenharmony_ci rpipe was closed but we expect more data */ 1641141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1642141cc406Sopenharmony_ci } 1643141cc406Sopenharmony_ci } 1644141cc406Sopenharmony_ci if (readlen) 1645141cc406Sopenharmony_ci *readlen = count; 1646141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1647141cc406Sopenharmony_ci} 1648141cc406Sopenharmony_ci 1649141cc406Sopenharmony_ci 1650141cc406Sopenharmony_ci/******************************************************************* 1651141cc406Sopenharmony_ci ** SANE API 1652141cc406Sopenharmony_ci *******************************************************************/ 1653141cc406Sopenharmony_ciSANE_Status 1654141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 1655141cc406Sopenharmony_ci{ 1656141cc406Sopenharmony_ci int status, myversion, i; 1657141cc406Sopenharmony_ci SANEI_Config config; 1658141cc406Sopenharmony_ci 1659141cc406Sopenharmony_ci UNUSED (authorize); 1660141cc406Sopenharmony_ci 1661141cc406Sopenharmony_ci if (!version_code) 1662141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1663141cc406Sopenharmony_ci myversion = 100 * PIXMA_VERSION_MAJOR + PIXMA_VERSION_MINOR; 1664141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, myversion); 1665141cc406Sopenharmony_ci DBG_INIT (); 1666141cc406Sopenharmony_ci sanei_thread_init (); 1667141cc406Sopenharmony_ci pixma_set_debug_level (DBG_LEVEL); 1668141cc406Sopenharmony_ci 1669141cc406Sopenharmony_ci PDBG(pixma_dbg(2, "pixma is compiled %s pthread support.\n", 1670141cc406Sopenharmony_ci (sanei_thread_is_forked () ? "without" : "with"))); 1671141cc406Sopenharmony_ci 1672141cc406Sopenharmony_ci for (i = 0; i < MAX_CONF_DEVICES; i++) 1673141cc406Sopenharmony_ci conf_devices[i] = NULL; 1674141cc406Sopenharmony_ci 1675141cc406Sopenharmony_ci config.count = 0; 1676141cc406Sopenharmony_ci config.descriptors = NULL; 1677141cc406Sopenharmony_ci config.values = NULL; 1678141cc406Sopenharmony_ci 1679141cc406Sopenharmony_ci if (sanei_configure_attach(PIXMA_CONFIG_FILE, &config, 1680141cc406Sopenharmony_ci config_attach_pixma, NULL) != SANE_STATUS_GOOD) 1681141cc406Sopenharmony_ci PDBG(pixma_dbg(2, "Could not read pixma configuration file: %s\n", 1682141cc406Sopenharmony_ci PIXMA_CONFIG_FILE)); 1683141cc406Sopenharmony_ci 1684141cc406Sopenharmony_ci status = pixma_init (); 1685141cc406Sopenharmony_ci if (status < 0) 1686141cc406Sopenharmony_ci { 1687141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "pixma_init() failed %s\n", pixma_strerror (status))); 1688141cc406Sopenharmony_ci } 1689141cc406Sopenharmony_ci return map_error (status); 1690141cc406Sopenharmony_ci} 1691141cc406Sopenharmony_ci 1692141cc406Sopenharmony_civoid 1693141cc406Sopenharmony_cisane_exit (void) 1694141cc406Sopenharmony_ci{ 1695141cc406Sopenharmony_ci while (first_scanner) 1696141cc406Sopenharmony_ci sane_close (first_scanner); 1697141cc406Sopenharmony_ci cleanup_device_list (); 1698141cc406Sopenharmony_ci pixma_cleanup (); 1699141cc406Sopenharmony_ci sanei_usb_exit (); 1700141cc406Sopenharmony_ci} 1701141cc406Sopenharmony_ci 1702141cc406Sopenharmony_ciSANE_Status 1703141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 1704141cc406Sopenharmony_ci{ 1705141cc406Sopenharmony_ci if (!device_list) 1706141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1707141cc406Sopenharmony_ci find_scanners (local_only); 1708141cc406Sopenharmony_ci *device_list = dev_list; 1709141cc406Sopenharmony_ci return (dev_list) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM; 1710141cc406Sopenharmony_ci} 1711141cc406Sopenharmony_ci 1712141cc406Sopenharmony_ciSANE_Status 1713141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * h) 1714141cc406Sopenharmony_ci{ 1715141cc406Sopenharmony_ci unsigned i, j, nscanners; 1716141cc406Sopenharmony_ci int error = 0; 1717141cc406Sopenharmony_ci pixma_sane_t *ss = NULL; 1718141cc406Sopenharmony_ci const pixma_config_t *cfg; 1719141cc406Sopenharmony_ci 1720141cc406Sopenharmony_ci if (!name || !h) 1721141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1722141cc406Sopenharmony_ci 1723141cc406Sopenharmony_ci *h = NULL; 1724141cc406Sopenharmony_ci nscanners = pixma_find_scanners (conf_devices, SANE_FALSE); 1725141cc406Sopenharmony_ci if (nscanners == 0) 1726141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1727141cc406Sopenharmony_ci 1728141cc406Sopenharmony_ci /* also get device id if we replay a xml file 1729141cc406Sopenharmony_ci * otherwise name contains the xml filename 1730141cc406Sopenharmony_ci * and further replay will fail */ 1731141cc406Sopenharmony_ci if (name[0] == '\0' || strstr (name, ".xml")) 1732141cc406Sopenharmony_ci name = pixma_get_device_id (0); 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci /* Have we already opened the scanner? */ 1735141cc406Sopenharmony_ci for (ss = first_scanner; ss; ss = ss->next) 1736141cc406Sopenharmony_ci { 1737141cc406Sopenharmony_ci if (strcmp (pixma_get_string (ss->s, PIXMA_STRING_ID), name) == 0) 1738141cc406Sopenharmony_ci { 1739141cc406Sopenharmony_ci /* We have already opened it! */ 1740141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 1741141cc406Sopenharmony_ci } 1742141cc406Sopenharmony_ci } 1743141cc406Sopenharmony_ci 1744141cc406Sopenharmony_ci i = 0; 1745141cc406Sopenharmony_ci while (strcmp (pixma_get_device_id (i), name) != 0) 1746141cc406Sopenharmony_ci { 1747141cc406Sopenharmony_ci if (++i >= nscanners) 1748141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1749141cc406Sopenharmony_ci } 1750141cc406Sopenharmony_ci cfg = pixma_get_device_config (i); 1751141cc406Sopenharmony_ci if ((cfg->cap & PIXMA_CAP_EXPERIMENT) != 0) 1752141cc406Sopenharmony_ci { 1753141cc406Sopenharmony_ci#ifndef NDEBUG 1754141cc406Sopenharmony_ci pixma_dbg (1, "WARNING:" 1755141cc406Sopenharmony_ci "Experimental backend CAN DAMAGE your hardware!\n"); 1756141cc406Sopenharmony_ci if (getenv_atoi ("PIXMA_EXPERIMENT", 0) == 0) 1757141cc406Sopenharmony_ci { 1758141cc406Sopenharmony_ci pixma_dbg (1, "Experimental SANE backend for %s is disabled " 1759141cc406Sopenharmony_ci "by default.\n", pixma_get_device_model (i)); 1760141cc406Sopenharmony_ci pixma_dbg (1, "To enable it, set the environment variable " 1761141cc406Sopenharmony_ci "PIXMA_EXPERIMENT to non-zero.\n"); 1762141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1763141cc406Sopenharmony_ci } 1764141cc406Sopenharmony_ci#else 1765141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1766141cc406Sopenharmony_ci#endif 1767141cc406Sopenharmony_ci } 1768141cc406Sopenharmony_ci 1769141cc406Sopenharmony_ci ss = (pixma_sane_t *) calloc (1, sizeof (*ss)); 1770141cc406Sopenharmony_ci if (!ss) 1771141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1772141cc406Sopenharmony_ci ss->next = first_scanner; 1773141cc406Sopenharmony_ci first_scanner = ss; 1774141cc406Sopenharmony_ci sanei_thread_initialize (ss->reader_taskid); 1775141cc406Sopenharmony_ci ss->wpipe = -1; 1776141cc406Sopenharmony_ci ss->rpipe = -1; 1777141cc406Sopenharmony_ci ss->idle = SANE_TRUE; 1778141cc406Sopenharmony_ci ss->scanning = SANE_FALSE; 1779141cc406Sopenharmony_ci ss->sp.frontend_cancel = SANE_FALSE; 1780141cc406Sopenharmony_ci for (j=0; j < BUTTON_GROUP_SIZE; j++) 1781141cc406Sopenharmony_ci ss->button_option_is_cached[j] = 0; 1782141cc406Sopenharmony_ci error = pixma_open (i, &ss->s); 1783141cc406Sopenharmony_ci if (error < 0) 1784141cc406Sopenharmony_ci { 1785141cc406Sopenharmony_ci sane_close (ss); 1786141cc406Sopenharmony_ci return map_error (error); 1787141cc406Sopenharmony_ci } 1788141cc406Sopenharmony_ci pixma_enable_background (ss->s, 0); 1789141cc406Sopenharmony_ci init_option_descriptors (ss); 1790141cc406Sopenharmony_ci *h = ss; 1791141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1792141cc406Sopenharmony_ci} 1793141cc406Sopenharmony_ci 1794141cc406Sopenharmony_civoid 1795141cc406Sopenharmony_cisane_close (SANE_Handle h) 1796141cc406Sopenharmony_ci{ 1797141cc406Sopenharmony_ci pixma_sane_t **p, *ss; 1798141cc406Sopenharmony_ci 1799141cc406Sopenharmony_ci for (p = &first_scanner; *p && *p != (pixma_sane_t *) h; p = &((*p)->next)) 1800141cc406Sopenharmony_ci { 1801141cc406Sopenharmony_ci } 1802141cc406Sopenharmony_ci if (!(*p)) 1803141cc406Sopenharmony_ci return; 1804141cc406Sopenharmony_ci ss = *p; 1805141cc406Sopenharmony_ci sane_cancel (ss); 1806141cc406Sopenharmony_ci pixma_close (ss->s); 1807141cc406Sopenharmony_ci *p = ss->next; 1808141cc406Sopenharmony_ci free (ss); 1809141cc406Sopenharmony_ci} 1810141cc406Sopenharmony_ci 1811141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1812141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int n) 1813141cc406Sopenharmony_ci{ 1814141cc406Sopenharmony_ci DECL_CTX; 1815141cc406Sopenharmony_ci 1816141cc406Sopenharmony_ci if (ss && 0 <= n && n < opt_last) 1817141cc406Sopenharmony_ci return &SOD (n); 1818141cc406Sopenharmony_ci return NULL; 1819141cc406Sopenharmony_ci} 1820141cc406Sopenharmony_ci 1821141cc406Sopenharmony_ciSANE_Status 1822141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int n, 1823141cc406Sopenharmony_ci SANE_Action a, void *v, SANE_Int * i) 1824141cc406Sopenharmony_ci{ 1825141cc406Sopenharmony_ci DECL_CTX; 1826141cc406Sopenharmony_ci SANE_Int info = 0; 1827141cc406Sopenharmony_ci int error; 1828141cc406Sopenharmony_ci option_descriptor_t *opt; 1829141cc406Sopenharmony_ci 1830141cc406Sopenharmony_ci if (i) 1831141cc406Sopenharmony_ci *i = 0; 1832141cc406Sopenharmony_ci if (!ss) 1833141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1834141cc406Sopenharmony_ci if (n < 0 || n >= opt_last) 1835141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1836141cc406Sopenharmony_ci if (!ss->idle && a != SANE_ACTION_GET_VALUE) 1837141cc406Sopenharmony_ci { 1838141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Warning: !idle && !SANE_ACTION_GET_VALUE\n")); 1839141cc406Sopenharmony_ci if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) 1840141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1841141cc406Sopenharmony_ci } 1842141cc406Sopenharmony_ci 1843141cc406Sopenharmony_ci opt = &(OPT_IN_CTX[n]); 1844141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (opt->sod.cap)) 1845141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1846141cc406Sopenharmony_ci switch (a) 1847141cc406Sopenharmony_ci { 1848141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 1849141cc406Sopenharmony_ci if ((opt->sod.type != SANE_TYPE_BUTTON && !v) || 1850141cc406Sopenharmony_ci !SANE_OPTION_IS_SETTABLE (opt->sod.cap)) 1851141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ 1852141cc406Sopenharmony_ci break; 1853141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 1854141cc406Sopenharmony_ci if (!(opt->sod.cap & SANE_CAP_AUTOMATIC) || 1855141cc406Sopenharmony_ci !SANE_OPTION_IS_SETTABLE (opt->sod.cap)) 1856141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ 1857141cc406Sopenharmony_ci break; 1858141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 1859141cc406Sopenharmony_ci if (!v || !(opt->sod.cap & SANE_CAP_SOFT_DETECT)) 1860141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ 1861141cc406Sopenharmony_ci break; 1862141cc406Sopenharmony_ci default: 1863141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1864141cc406Sopenharmony_ci } 1865141cc406Sopenharmony_ci 1866141cc406Sopenharmony_ci error = control_option (ss, n, a, v, &info); 1867141cc406Sopenharmony_ci if (error == SANE_STATUS_GOOD && i) 1868141cc406Sopenharmony_ci *i = info; 1869141cc406Sopenharmony_ci return error; 1870141cc406Sopenharmony_ci} 1871141cc406Sopenharmony_ci 1872141cc406Sopenharmony_ciSANE_Status 1873141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters * p) 1874141cc406Sopenharmony_ci{ 1875141cc406Sopenharmony_ci DECL_CTX; 1876141cc406Sopenharmony_ci pixma_scan_param_t temp, *sp; 1877141cc406Sopenharmony_ci 1878141cc406Sopenharmony_ci if (!ss || !p) 1879141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1880141cc406Sopenharmony_ci 1881141cc406Sopenharmony_ci if (!ss->idle) 1882141cc406Sopenharmony_ci { 1883141cc406Sopenharmony_ci sp = &ss->sp; /* sp is calculated in sane_start() */ 1884141cc406Sopenharmony_ci } 1885141cc406Sopenharmony_ci else 1886141cc406Sopenharmony_ci { 1887141cc406Sopenharmony_ci calc_scan_param (ss, &temp); 1888141cc406Sopenharmony_ci sp = &temp; 1889141cc406Sopenharmony_ci } 1890141cc406Sopenharmony_ci p->format = (sp->channels == 3) ? SANE_FRAME_RGB : SANE_FRAME_GRAY; 1891141cc406Sopenharmony_ci p->last_frame = SANE_TRUE; 1892141cc406Sopenharmony_ci p->lines = sp->h; 1893141cc406Sopenharmony_ci p->depth = sp->depth; 1894141cc406Sopenharmony_ci p->pixels_per_line = sp->w; 1895141cc406Sopenharmony_ci /* p->bytes_per_line = sp->line_size; NOTE: It should work this way, but it doesn't. No SANE frontend can cope with this. */ 1896141cc406Sopenharmony_ci p->bytes_per_line = (sp->w * sp->channels * sp->depth) / 8; 1897141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1898141cc406Sopenharmony_ci} 1899141cc406Sopenharmony_ci 1900141cc406Sopenharmony_ciSANE_Status 1901141cc406Sopenharmony_cisane_start (SANE_Handle h) 1902141cc406Sopenharmony_ci{ 1903141cc406Sopenharmony_ci DECL_CTX; 1904141cc406Sopenharmony_ci int error = 0; 1905141cc406Sopenharmony_ci 1906141cc406Sopenharmony_ci if (!ss) 1907141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1908141cc406Sopenharmony_ci if (!ss->idle && ss->scanning) 1909141cc406Sopenharmony_ci { 1910141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Warning in Sane_start: !idle && scanning. idle=%d, ss->scanning=%d\n", 1911141cc406Sopenharmony_ci ss->idle, ss->scanning)); 1912141cc406Sopenharmony_ci if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) 1913141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1914141cc406Sopenharmony_ci } 1915141cc406Sopenharmony_ci 1916141cc406Sopenharmony_ci ss->cancel = SANE_FALSE; 1917141cc406Sopenharmony_ci if (ss->idle || 1918141cc406Sopenharmony_ci ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED || 1919141cc406Sopenharmony_ci ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU) 1920141cc406Sopenharmony_ci ss->page_count = 0; /* start from idle state or scan from flatbed or TPU */ 1921141cc406Sopenharmony_ci else 1922141cc406Sopenharmony_ci ss->page_count++; 1923141cc406Sopenharmony_ci if (calc_scan_param (ss, &ss->sp) < 0) 1924141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1925141cc406Sopenharmony_ci 1926141cc406Sopenharmony_ci /* Prepare the JPEG decompressor, if needed */ 1927141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 1928141cc406Sopenharmony_ci { 1929141cc406Sopenharmony_ci SANE_Status status; 1930141cc406Sopenharmony_ci status = pixma_jpeg_start(ss); 1931141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1932141cc406Sopenharmony_ci { 1933141cc406Sopenharmony_ci PDBG (pixma_dbg(1, "%s: pixma_jpeg_start: %s\n", __func__, sane_strstatus(status)) ); 1934141cc406Sopenharmony_ci return status; 1935141cc406Sopenharmony_ci } 1936141cc406Sopenharmony_ci } 1937141cc406Sopenharmony_ci 1938141cc406Sopenharmony_ci ss->image_bytes_read = 0; 1939141cc406Sopenharmony_ci /* TODO: Check paper here in sane_start(). A function like 1940141cc406Sopenharmony_ci pixma_get_status() is needed. */ 1941141cc406Sopenharmony_ci error = start_reader_task (ss); 1942141cc406Sopenharmony_ci if (error >= 0) 1943141cc406Sopenharmony_ci { 1944141cc406Sopenharmony_ci ss->output_line_size = (ss->sp.w * ss->sp.channels * ss->sp.depth) / 8; 1945141cc406Sopenharmony_ci ss->byte_pos_in_line = 0; 1946141cc406Sopenharmony_ci ss->last_read_status = SANE_STATUS_GOOD; 1947141cc406Sopenharmony_ci ss->scanning = SANE_TRUE; 1948141cc406Sopenharmony_ci ss->idle = SANE_FALSE; 1949141cc406Sopenharmony_ci if (ss->sp.mode_jpeg && !ss->jpeg_header_seen) 1950141cc406Sopenharmony_ci { 1951141cc406Sopenharmony_ci SANE_Status status; 1952141cc406Sopenharmony_ci status = pixma_jpeg_read_header(ss); 1953141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1954141cc406Sopenharmony_ci { 1955141cc406Sopenharmony_ci close (ss->rpipe); 1956141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 1957141cc406Sopenharmony_ci ss->rpipe = -1; 1958141cc406Sopenharmony_ci if (sanei_thread_is_valid (terminate_reader_task (ss, &error)) 1959141cc406Sopenharmony_ci && error != SANE_STATUS_GOOD) 1960141cc406Sopenharmony_ci { 1961141cc406Sopenharmony_ci return error; 1962141cc406Sopenharmony_ci } 1963141cc406Sopenharmony_ci } 1964141cc406Sopenharmony_ci } 1965141cc406Sopenharmony_ci } 1966141cc406Sopenharmony_ci return map_error (error); 1967141cc406Sopenharmony_ci} 1968141cc406Sopenharmony_ci 1969141cc406Sopenharmony_ciSANE_Status 1970141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) 1971141cc406Sopenharmony_ci{ 1972141cc406Sopenharmony_ci DECL_CTX; 1973141cc406Sopenharmony_ci int sum, n; 1974141cc406Sopenharmony_ci /* Due to 32 pixels alignment, sizeof(temp) is to be greater than: 1975141cc406Sopenharmony_ci * max(nchannels) * max (sp.line_size - output_line_size) 1976141cc406Sopenharmony_ci * so currently: 3 * 32 = 96 for better end line cropping efficiency */ 1977141cc406Sopenharmony_ci SANE_Byte temp[100]; 1978141cc406Sopenharmony_ci SANE_Status status; 1979141cc406Sopenharmony_ci 1980141cc406Sopenharmony_ci if (len) 1981141cc406Sopenharmony_ci *len = 0; 1982141cc406Sopenharmony_ci if (!ss || !buf || !len) 1983141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1984141cc406Sopenharmony_ci if (ss->cancel) 1985141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1986141cc406Sopenharmony_ci if ((ss->idle) 1987141cc406Sopenharmony_ci && (ss->sp.source == PIXMA_SOURCE_ADF || ss->sp.source == PIXMA_SOURCE_ADFDUP)) 1988141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1989141cc406Sopenharmony_ci if (!ss->scanning) 1990141cc406Sopenharmony_ci return ss->last_read_status; 1991141cc406Sopenharmony_ci 1992141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 1993141cc406Sopenharmony_ci /* CCD scanners use software lineart 1994141cc406Sopenharmony_ci * the scanner must scan 24 bit color or 8 bit grayscale for one bit lineart */ 1995141cc406Sopenharmony_ci if ((ss->sp.line_size - ((ss->sp.software_lineart == 1) ? (ss->output_line_size * 8) : ss->output_line_size)) == 0) 1996141cc406Sopenharmony_ci { 1997141cc406Sopenharmony_ci status = read_image (ss, buf, maxlen, &sum); 1998141cc406Sopenharmony_ci } 1999141cc406Sopenharmony_ci else 2000141cc406Sopenharmony_ci { 2001141cc406Sopenharmony_ci /* FIXME: Because there is no frontend that can cope with padding at 2002141cc406Sopenharmony_ci the end of line, we've to remove it here in the backend! */ 2003141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "*sane_read***** Warning: padding may cause incomplete scan results\n")); 2004141cc406Sopenharmony_ci sum = 0; 2005141cc406Sopenharmony_ci while (sum < maxlen) 2006141cc406Sopenharmony_ci { 2007141cc406Sopenharmony_ci if (ss->byte_pos_in_line < ss->output_line_size) 2008141cc406Sopenharmony_ci { 2009141cc406Sopenharmony_ci n = ss->output_line_size - ss->byte_pos_in_line; 2010141cc406Sopenharmony_ci if ((maxlen - sum) < n) 2011141cc406Sopenharmony_ci n = maxlen - sum; 2012141cc406Sopenharmony_ci status = read_image (ss, buf, n, &n); 2013141cc406Sopenharmony_ci if (n == 0) 2014141cc406Sopenharmony_ci break; 2015141cc406Sopenharmony_ci sum += n; 2016141cc406Sopenharmony_ci buf += n; 2017141cc406Sopenharmony_ci ss->byte_pos_in_line += n; 2018141cc406Sopenharmony_ci } 2019141cc406Sopenharmony_ci else 2020141cc406Sopenharmony_ci { 2021141cc406Sopenharmony_ci /* skip padding */ 2022141cc406Sopenharmony_ci n = ss->sp.line_size - ss->byte_pos_in_line; 2023141cc406Sopenharmony_ci if (n > (int) sizeof (temp)) 2024141cc406Sopenharmony_ci { 2025141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n)); 2026141cc406Sopenharmony_ci n = sizeof (temp); 2027141cc406Sopenharmony_ci } 2028141cc406Sopenharmony_ci status = read_image (ss, temp, n, &n); 2029141cc406Sopenharmony_ci if (n == 0) 2030141cc406Sopenharmony_ci break; 2031141cc406Sopenharmony_ci ss->byte_pos_in_line += n; 2032141cc406Sopenharmony_ci if (ss->byte_pos_in_line == ss->sp.line_size) 2033141cc406Sopenharmony_ci ss->byte_pos_in_line = 0; 2034141cc406Sopenharmony_ci } 2035141cc406Sopenharmony_ci } 2036141cc406Sopenharmony_ci } 2037141cc406Sopenharmony_ci if (ss->cancel) 2038141cc406Sopenharmony_ci status = SANE_STATUS_CANCELLED; 2039141cc406Sopenharmony_ci else if ((status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF) && 2040141cc406Sopenharmony_ci sum > 0) 2041141cc406Sopenharmony_ci { 2042141cc406Sopenharmony_ci *len = sum; 2043141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2044141cc406Sopenharmony_ci } 2045141cc406Sopenharmony_ci ss->scanning = (status == SANE_STATUS_GOOD); 2046141cc406Sopenharmony_ci ss->last_read_status = status; 2047141cc406Sopenharmony_ci return status; 2048141cc406Sopenharmony_ci} 2049141cc406Sopenharmony_ci 2050141cc406Sopenharmony_civoid 2051141cc406Sopenharmony_cisane_cancel (SANE_Handle h) 2052141cc406Sopenharmony_ci{ 2053141cc406Sopenharmony_ci DECL_CTX; 2054141cc406Sopenharmony_ci 2055141cc406Sopenharmony_ci if (!ss) 2056141cc406Sopenharmony_ci return; 2057141cc406Sopenharmony_ci ss->cancel = SANE_TRUE; 2058141cc406Sopenharmony_ci ss->sp.frontend_cancel = SANE_TRUE; 2059141cc406Sopenharmony_ci if (ss->idle) 2060141cc406Sopenharmony_ci return; 2061141cc406Sopenharmony_ci close (ss->rpipe); 2062141cc406Sopenharmony_ci if (ss->sp.mode_jpeg) 2063141cc406Sopenharmony_ci pixma_jpeg_finish(ss); 2064141cc406Sopenharmony_ci ss->rpipe = -1; 2065141cc406Sopenharmony_ci terminate_reader_task (ss, NULL); 2066141cc406Sopenharmony_ci ss->idle = SANE_TRUE; 2067141cc406Sopenharmony_ci} 2068141cc406Sopenharmony_ci 2069141cc406Sopenharmony_ciSANE_Status 2070141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool m) 2071141cc406Sopenharmony_ci{ 2072141cc406Sopenharmony_ci DECL_CTX; 2073141cc406Sopenharmony_ci 2074141cc406Sopenharmony_ci if (!ss || ss->idle || ss->rpipe == -1) 2075141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2076141cc406Sopenharmony_ci#ifdef HAVE_FCNTL_H 2077141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "Setting %sblocking mode\n", (m) ? "non-" : "")); 2078141cc406Sopenharmony_ci if (fcntl (ss->rpipe, F_SETFL, (m) ? O_NONBLOCK : 0) == -1) 2079141cc406Sopenharmony_ci { 2080141cc406Sopenharmony_ci PDBG (pixma_dbg 2081141cc406Sopenharmony_ci (1, "WARNING:fcntl(F_SETFL) failed %s\n", strerror (errno))); 2082141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 2083141cc406Sopenharmony_ci } 2084141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2085141cc406Sopenharmony_ci#else 2086141cc406Sopenharmony_ci return (m) ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD; 2087141cc406Sopenharmony_ci#endif 2088141cc406Sopenharmony_ci} 2089141cc406Sopenharmony_ci 2090141cc406Sopenharmony_ciSANE_Status 2091141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fd) 2092141cc406Sopenharmony_ci{ 2093141cc406Sopenharmony_ci DECL_CTX; 2094141cc406Sopenharmony_ci 2095141cc406Sopenharmony_ci *fd = -1; 2096141cc406Sopenharmony_ci if (!ss || !fd || ss->idle || ss->rpipe == -1) 2097141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2098141cc406Sopenharmony_ci *fd = ss->rpipe; 2099141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2100141cc406Sopenharmony_ci} 2101141cc406Sopenharmony_ci 2102141cc406Sopenharmony_ci/* CAUTION! 2103141cc406Sopenharmony_ci * Remove generated files pixma_sane_options.[ch] after editing SANE option 2104141cc406Sopenharmony_ci * descriptors below OR do a 'make clean' OR manually generate them as described 2105141cc406Sopenharmony_ci * below. 2106141cc406Sopenharmony_ci * However, make drops the circular dependency and the files won't be generated 2107141cc406Sopenharmony_ci * again (see merge request sane-project/backends!491). 2108141cc406Sopenharmony_ci 2109141cc406Sopenharmony_ciBEGIN SANE_Option_Descriptor 2110141cc406Sopenharmony_ci 2111141cc406Sopenharmony_cirem ------------------------------------------- 2112141cc406Sopenharmony_citype group 2113141cc406Sopenharmony_ci title Scan mode 2114141cc406Sopenharmony_ci 2115141cc406Sopenharmony_citype int resolution 2116141cc406Sopenharmony_ci unit dpi 2117141cc406Sopenharmony_ci constraint @word_list = ss->dpi_list 2118141cc406Sopenharmony_ci default 75 2119141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_RESOLUTION 2120141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_RESOLUTION 2121141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2122141cc406Sopenharmony_ci info reload_params 2123141cc406Sopenharmony_ci 2124141cc406Sopenharmony_citype string mode[30] 2125141cc406Sopenharmony_ci constraint @string_list = ss->mode_list 2126141cc406Sopenharmony_ci default @s = SANE_VALUE_SCAN_MODE_COLOR 2127141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_MODE 2128141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_MODE 2129141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2130141cc406Sopenharmony_ci info reload_params 2131141cc406Sopenharmony_ci 2132141cc406Sopenharmony_citype string source[30] 2133141cc406Sopenharmony_ci constraint @string_list = ss->source_list 2134141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_SOURCE 2135141cc406Sopenharmony_ci desc Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values. 2136141cc406Sopenharmony_ci default Flatbed 2137141cc406Sopenharmony_ci cap soft_select soft_detect 2138141cc406Sopenharmony_ci 2139141cc406Sopenharmony_citype bool button-controlled 2140141cc406Sopenharmony_ci title Button-controlled scan 2141141cc406Sopenharmony_ci desc When enabled, scan process will not start immediately. To proceed, press \"SCAN\" button (for MP150) or \"COLOR\" button (for other models). To cancel, press \"GRAY\" button. 2142141cc406Sopenharmony_ci default SANE_FALSE 2143141cc406Sopenharmony_ci cap soft_select soft_detect inactive 2144141cc406Sopenharmony_ci 2145141cc406Sopenharmony_cirem ------------------------------------------- 2146141cc406Sopenharmony_citype group 2147141cc406Sopenharmony_ci title Gamma 2148141cc406Sopenharmony_ci 2149141cc406Sopenharmony_citype bool custom-gamma 2150141cc406Sopenharmony_ci default SANE_FALSE 2151141cc406Sopenharmony_ci title @SANE_TITLE_CUSTOM_GAMMA 2152141cc406Sopenharmony_ci desc @SANE_DESC_CUSTOM_GAMMA 2153141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2154141cc406Sopenharmony_ci 2155141cc406Sopenharmony_citype int gamma-table[1024] 2156141cc406Sopenharmony_ci constraint (0,0xffff,0) 2157141cc406Sopenharmony_ci title @SANE_TITLE_GAMMA_VECTOR 2158141cc406Sopenharmony_ci desc Gamma-correction table with 1024 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table). 2159141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2160141cc406Sopenharmony_ci 2161141cc406Sopenharmony_citype fixed gamma 2162141cc406Sopenharmony_ci default AUTO_GAMMA 2163141cc406Sopenharmony_ci constraint (0.3,5,0) 2164141cc406Sopenharmony_ci title Gamma function exponent 2165141cc406Sopenharmony_ci desc Changes intensity of midtones 2166141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2167141cc406Sopenharmony_ci 2168141cc406Sopenharmony_cirem ------------------------------------------- 2169141cc406Sopenharmony_citype group 2170141cc406Sopenharmony_ci title Geometry 2171141cc406Sopenharmony_ci 2172141cc406Sopenharmony_citype fixed tl-x 2173141cc406Sopenharmony_ci unit mm 2174141cc406Sopenharmony_ci default 0 2175141cc406Sopenharmony_ci constraint @range = &ss->xrange 2176141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_TL_X 2177141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_TL_X 2178141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2179141cc406Sopenharmony_ci info reload_params 2180141cc406Sopenharmony_ci 2181141cc406Sopenharmony_citype fixed tl-y 2182141cc406Sopenharmony_ci unit mm 2183141cc406Sopenharmony_ci default 0 2184141cc406Sopenharmony_ci constraint @range = &ss->yrange 2185141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_TL_Y 2186141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_TL_Y 2187141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2188141cc406Sopenharmony_ci info reload_params 2189141cc406Sopenharmony_ci 2190141cc406Sopenharmony_citype fixed br-x 2191141cc406Sopenharmony_ci unit mm 2192141cc406Sopenharmony_ci default _MAX 2193141cc406Sopenharmony_ci constraint @range = &ss->xrange 2194141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_BR_X 2195141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_BR_X 2196141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2197141cc406Sopenharmony_ci info reload_params 2198141cc406Sopenharmony_ci 2199141cc406Sopenharmony_citype fixed br-y 2200141cc406Sopenharmony_ci unit mm 2201141cc406Sopenharmony_ci default _MAX 2202141cc406Sopenharmony_ci constraint @range = &ss->yrange 2203141cc406Sopenharmony_ci title @SANE_TITLE_SCAN_BR_Y 2204141cc406Sopenharmony_ci desc @SANE_DESC_SCAN_BR_Y 2205141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2206141cc406Sopenharmony_ci info reload_params 2207141cc406Sopenharmony_ci 2208141cc406Sopenharmony_cirem ------------------------------------------- 2209141cc406Sopenharmony_citype group 2210141cc406Sopenharmony_ci title Buttons 2211141cc406Sopenharmony_ci 2212141cc406Sopenharmony_citype button button-update 2213141cc406Sopenharmony_ci title Update button state 2214141cc406Sopenharmony_ci cap soft_select soft_detect advanced 2215141cc406Sopenharmony_ci 2216141cc406Sopenharmony_citype int button-1 2217141cc406Sopenharmony_ci default 0 2218141cc406Sopenharmony_ci title Button 1 2219141cc406Sopenharmony_ci cap soft_detect advanced 2220141cc406Sopenharmony_ci 2221141cc406Sopenharmony_citype int button-2 2222141cc406Sopenharmony_ci default 0 2223141cc406Sopenharmony_ci title Button 2 2224141cc406Sopenharmony_ci cap soft_detect advanced 2225141cc406Sopenharmony_ci 2226141cc406Sopenharmony_citype int original 2227141cc406Sopenharmony_ci default 0 2228141cc406Sopenharmony_ci title Type of original to scan 2229141cc406Sopenharmony_ci cap soft_detect advanced 2230141cc406Sopenharmony_ci 2231141cc406Sopenharmony_citype int target 2232141cc406Sopenharmony_ci default 0 2233141cc406Sopenharmony_ci title Target operation type 2234141cc406Sopenharmony_ci cap soft_detect advanced 2235141cc406Sopenharmony_ci 2236141cc406Sopenharmony_citype int scan-resolution 2237141cc406Sopenharmony_ci default 0 2238141cc406Sopenharmony_ci title Scan resolution 2239141cc406Sopenharmony_ci cap soft_detect advanced 2240141cc406Sopenharmony_ci 2241141cc406Sopenharmony_citype int document-type 2242141cc406Sopenharmony_ci default 0 2243141cc406Sopenharmony_ci title Document type 2244141cc406Sopenharmony_ci cap soft_detect advanced 2245141cc406Sopenharmony_ci 2246141cc406Sopenharmony_citype int adf-status 2247141cc406Sopenharmony_ci default 0 2248141cc406Sopenharmony_ci title ADF status 2249141cc406Sopenharmony_ci cap soft_detect advanced 2250141cc406Sopenharmony_ci 2251141cc406Sopenharmony_citype int adf-orientation 2252141cc406Sopenharmony_ci default 0 2253141cc406Sopenharmony_ci title ADF orientation 2254141cc406Sopenharmony_ci cap soft_detect advanced 2255141cc406Sopenharmony_ci 2256141cc406Sopenharmony_cirem ------------------------------------------- 2257141cc406Sopenharmony_citype group 2258141cc406Sopenharmony_ci title Extras 2259141cc406Sopenharmony_ci 2260141cc406Sopenharmony_citype int threshold 2261141cc406Sopenharmony_ci unit PERCENT 2262141cc406Sopenharmony_ci default 50 2263141cc406Sopenharmony_ci constraint (0,100,1) 2264141cc406Sopenharmony_ci title @SANE_TITLE_THRESHOLD 2265141cc406Sopenharmony_ci desc @SANE_DESC_THRESHOLD 2266141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2267141cc406Sopenharmony_ci 2268141cc406Sopenharmony_citype int threshold-curve 2269141cc406Sopenharmony_ci constraint (0,127,1) 2270141cc406Sopenharmony_ci title Threshold curve 2271141cc406Sopenharmony_ci desc Dynamic threshold curve, from light to dark, normally 50-65 2272141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2273141cc406Sopenharmony_ci 2274141cc406Sopenharmony_citype int adf-wait 2275141cc406Sopenharmony_ci default 0 2276141cc406Sopenharmony_ci constraint (0,3600,1) 2277141cc406Sopenharmony_ci title ADF Waiting Time 2278141cc406Sopenharmony_ci desc When set, the scanner waits up to the specified time in seconds for a new document inserted into the automatic document feeder. 2279141cc406Sopenharmony_ci cap soft_select soft_detect automatic inactive 2280141cc406Sopenharmony_ci 2281141cc406Sopenharmony_citype string calibrate[30] 2282141cc406Sopenharmony_ci constraint @string_list = ss->calibrate_list 2283141cc406Sopenharmony_ci title Calibration 2284141cc406Sopenharmony_ci desc When to perform scanner calibration. If you choose \"Once\" it will be performed a single time per driver init for single page scans, and for the first page for each ADF scan. 2285141cc406Sopenharmony_ci default Once 2286141cc406Sopenharmony_ci cap soft_select soft_detect automatic 2287141cc406Sopenharmony_ci 2288141cc406Sopenharmony_cirem ------------------------------------------- 2289141cc406Sopenharmony_ciEND SANE_Option_Descriptor 2290141cc406Sopenharmony_ci*/ 2291141cc406Sopenharmony_ci 2292141cc406Sopenharmony_ci/* pixma_sane_options.c generated by 2293141cc406Sopenharmony_ci * scripts/pixma_gen_options.py < pixma.c > pixma_sane_options.c 2294141cc406Sopenharmony_ci * 2295141cc406Sopenharmony_ci * pixma_sane_options.h generated by 2296141cc406Sopenharmony_ci * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h 2297141cc406Sopenharmony_ci */ 2298141cc406Sopenharmony_ci#include "pixma_sane_options.c" 2299