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 <stdio.h> 46141cc406Sopenharmony_ci#include <stdlib.h> 47141cc406Sopenharmony_ci#include <string.h> 48141cc406Sopenharmony_ci#include <stdarg.h> 49141cc406Sopenharmony_ci#include <ctype.h> 50141cc406Sopenharmony_ci#include <math.h> /* pow(C90) */ 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci#include <sys/time.h> /* gettimeofday(4.3BSD) */ 53141cc406Sopenharmony_ci#include <unistd.h> /* usleep */ 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci#if defined(HAVE_LIBXML2) 56141cc406Sopenharmony_ci# include <libxml/parser.h> 57141cc406Sopenharmony_ci#endif 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#include "pixma_rename.h" 60141cc406Sopenharmony_ci#include "pixma_common.h" 61141cc406Sopenharmony_ci#include "pixma_io.h" 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 64141cc406Sopenharmony_ci#include "../include/sane/sane.h" 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_ci#ifdef __GNUC__ 67141cc406Sopenharmony_ci# define UNUSED(v) (void) v 68141cc406Sopenharmony_ci#else 69141cc406Sopenharmony_ci# define UNUSED(v) 70141cc406Sopenharmony_ci#endif 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ciextern const pixma_config_t pixma_mp150_devices[]; 73141cc406Sopenharmony_ciextern const pixma_config_t pixma_mp750_devices[]; 74141cc406Sopenharmony_ciextern const pixma_config_t pixma_mp730_devices[]; 75141cc406Sopenharmony_ciextern const pixma_config_t pixma_mp800_devices[]; 76141cc406Sopenharmony_ciextern const pixma_config_t pixma_iclass_devices[]; 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_cistatic const pixma_config_t *const pixma_devices[] = { 79141cc406Sopenharmony_ci pixma_mp150_devices, 80141cc406Sopenharmony_ci pixma_mp750_devices, 81141cc406Sopenharmony_ci pixma_mp730_devices, 82141cc406Sopenharmony_ci pixma_mp800_devices, 83141cc406Sopenharmony_ci pixma_iclass_devices, 84141cc406Sopenharmony_ci NULL 85141cc406Sopenharmony_ci}; 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_cistatic pixma_t *first_pixma = NULL; 88141cc406Sopenharmony_cistatic time_t tstart_sec = 0; 89141cc406Sopenharmony_cistatic uint32_t tstart_usec = 0; 90141cc406Sopenharmony_cistatic int debug_level = 1; 91141cc406Sopenharmony_ci 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_ci#ifndef NDEBUG 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_cistatic void 96141cc406Sopenharmony_ciu8tohex (uint8_t x, char *str) 97141cc406Sopenharmony_ci{ 98141cc406Sopenharmony_ci static const char hdigit[16] = 99141cc406Sopenharmony_ci { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 100141cc406Sopenharmony_ci 'e', 'f' 101141cc406Sopenharmony_ci }; 102141cc406Sopenharmony_ci str[0] = hdigit[(x >> 4) & 0xf]; 103141cc406Sopenharmony_ci str[1] = hdigit[x & 0xf]; 104141cc406Sopenharmony_ci str[2] = '\0'; 105141cc406Sopenharmony_ci} 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_cistatic void 108141cc406Sopenharmony_ciu32tohex (uint32_t x, char *str) 109141cc406Sopenharmony_ci{ 110141cc406Sopenharmony_ci u8tohex (x >> 24, str); 111141cc406Sopenharmony_ci u8tohex (x >> 16, str + 2); 112141cc406Sopenharmony_ci u8tohex (x >> 8, str + 4); 113141cc406Sopenharmony_ci u8tohex (x, str + 6); 114141cc406Sopenharmony_ci} 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_civoid 117141cc406Sopenharmony_cipixma_hexdump (int level, const void *d_, unsigned len) 118141cc406Sopenharmony_ci{ 119141cc406Sopenharmony_ci const uint8_t *d = (const uint8_t *) (d_); 120141cc406Sopenharmony_ci unsigned ofs, c, plen; 121141cc406Sopenharmony_ci char line[100]; /* actually only 1+8+1+8*3+1+8*3+1 = 61 bytes needed */ 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci if (level > debug_level) 124141cc406Sopenharmony_ci return; 125141cc406Sopenharmony_ci if (level == debug_level) 126141cc406Sopenharmony_ci /* if debuglevel == exact match and buffer contains more than 3 lines, print 2 lines + .... */ 127141cc406Sopenharmony_ci plen = (len > 64) ? 32: len; 128141cc406Sopenharmony_ci else 129141cc406Sopenharmony_ci plen = len; 130141cc406Sopenharmony_ci ofs = 0; 131141cc406Sopenharmony_ci while (ofs < plen) 132141cc406Sopenharmony_ci { 133141cc406Sopenharmony_ci char *p; 134141cc406Sopenharmony_ci line[0] = ' '; 135141cc406Sopenharmony_ci u32tohex (ofs, line + 1); 136141cc406Sopenharmony_ci line[9] = ':'; 137141cc406Sopenharmony_ci p = line + 10; 138141cc406Sopenharmony_ci for (c = 0; c != 16 && (ofs + c) < plen; c++) 139141cc406Sopenharmony_ci { 140141cc406Sopenharmony_ci u8tohex (d[ofs + c], p); 141141cc406Sopenharmony_ci p[2] = ' '; 142141cc406Sopenharmony_ci p += 3; 143141cc406Sopenharmony_ci if (c == 7) 144141cc406Sopenharmony_ci { 145141cc406Sopenharmony_ci p[0] = ' '; 146141cc406Sopenharmony_ci p++; 147141cc406Sopenharmony_ci } 148141cc406Sopenharmony_ci } 149141cc406Sopenharmony_ci for (c = 0; c < 4; c++) 150141cc406Sopenharmony_ci { 151141cc406Sopenharmony_ci p[0] = ' '; 152141cc406Sopenharmony_ci p++; 153141cc406Sopenharmony_ci } 154141cc406Sopenharmony_ci for (c = 0; c != 16 && (ofs + c) < plen; c++) 155141cc406Sopenharmony_ci { 156141cc406Sopenharmony_ci if (isprint(d[ofs + c])) 157141cc406Sopenharmony_ci p[0] = d[ofs + c]; 158141cc406Sopenharmony_ci else 159141cc406Sopenharmony_ci p[0] = '.'; 160141cc406Sopenharmony_ci p++; 161141cc406Sopenharmony_ci if (c == 7) 162141cc406Sopenharmony_ci { 163141cc406Sopenharmony_ci p[0] = ' '; 164141cc406Sopenharmony_ci p++; 165141cc406Sopenharmony_ci } 166141cc406Sopenharmony_ci } 167141cc406Sopenharmony_ci p[0] = '\0'; 168141cc406Sopenharmony_ci pixma_dbg (level, "%s\n", line); 169141cc406Sopenharmony_ci ofs += c; 170141cc406Sopenharmony_ci } 171141cc406Sopenharmony_ci if (len > plen) 172141cc406Sopenharmony_ci pixma_dbg(level, "......\n"); 173141cc406Sopenharmony_ci} 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_cistatic void 176141cc406Sopenharmony_citime2str (char *buf, unsigned size) 177141cc406Sopenharmony_ci{ 178141cc406Sopenharmony_ci time_t sec; 179141cc406Sopenharmony_ci uint32_t usec; 180141cc406Sopenharmony_ci 181141cc406Sopenharmony_ci pixma_get_time (&sec, &usec); 182141cc406Sopenharmony_ci sec -= tstart_sec; 183141cc406Sopenharmony_ci if (usec >= tstart_usec) 184141cc406Sopenharmony_ci { 185141cc406Sopenharmony_ci usec -= tstart_usec; 186141cc406Sopenharmony_ci } 187141cc406Sopenharmony_ci else 188141cc406Sopenharmony_ci { 189141cc406Sopenharmony_ci usec = 1000000 + usec - tstart_usec; 190141cc406Sopenharmony_ci sec--; 191141cc406Sopenharmony_ci } 192141cc406Sopenharmony_ci snprintf (buf, size, "%lu.%03u", (unsigned long) sec, 193141cc406Sopenharmony_ci (unsigned) (usec / 1000)); 194141cc406Sopenharmony_ci} 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_civoid 197141cc406Sopenharmony_cipixma_dump (int level, const char *type, const void *data, int len, 198141cc406Sopenharmony_ci int size, int max) 199141cc406Sopenharmony_ci{ 200141cc406Sopenharmony_ci int actual_len, print_len; 201141cc406Sopenharmony_ci char buf[20]; 202141cc406Sopenharmony_ci 203141cc406Sopenharmony_ci if (level > debug_level) 204141cc406Sopenharmony_ci return; 205141cc406Sopenharmony_ci if (debug_level >= 20) 206141cc406Sopenharmony_ci max = -1; /* dump every bytes */ 207141cc406Sopenharmony_ci 208141cc406Sopenharmony_ci time2str (buf, sizeof (buf)); 209141cc406Sopenharmony_ci pixma_dbg (level, "%s T=%s len=%d\n", type, buf, len); 210141cc406Sopenharmony_ci 211141cc406Sopenharmony_ci actual_len = (size >= 0) ? size : len; 212141cc406Sopenharmony_ci print_len = (max >= 0 && max < actual_len) ? max : actual_len; 213141cc406Sopenharmony_ci if (print_len >= 0) 214141cc406Sopenharmony_ci { 215141cc406Sopenharmony_ci pixma_hexdump (level, data, print_len); 216141cc406Sopenharmony_ci if (print_len < actual_len) 217141cc406Sopenharmony_ci pixma_dbg (level, " ...\n"); 218141cc406Sopenharmony_ci } 219141cc406Sopenharmony_ci if (len < 0) 220141cc406Sopenharmony_ci pixma_dbg (level, " ERROR: %s\n", pixma_strerror (len)); 221141cc406Sopenharmony_ci pixma_dbg (level, "\n"); 222141cc406Sopenharmony_ci} 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci#endif /* NDEBUG */ 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_ci/* NOTE: non-reentrant */ 228141cc406Sopenharmony_ciconst char * 229141cc406Sopenharmony_cipixma_strerror (int error) 230141cc406Sopenharmony_ci{ 231141cc406Sopenharmony_ci static char buf[50]; 232141cc406Sopenharmony_ci 233141cc406Sopenharmony_ci /* TODO: more human friendly messages */ 234141cc406Sopenharmony_ci switch (error) 235141cc406Sopenharmony_ci { 236141cc406Sopenharmony_ci case PIXMA_EIO: 237141cc406Sopenharmony_ci return "EIO"; 238141cc406Sopenharmony_ci case PIXMA_ENODEV: 239141cc406Sopenharmony_ci return "ENODEV"; 240141cc406Sopenharmony_ci case PIXMA_EACCES: 241141cc406Sopenharmony_ci return "EACCES"; 242141cc406Sopenharmony_ci case PIXMA_ENOMEM: 243141cc406Sopenharmony_ci return "ENOMEM"; 244141cc406Sopenharmony_ci case PIXMA_EINVAL: 245141cc406Sopenharmony_ci return "EINVAL"; 246141cc406Sopenharmony_ci case PIXMA_EBUSY: 247141cc406Sopenharmony_ci return "EBUSY"; 248141cc406Sopenharmony_ci case PIXMA_ECANCELED: 249141cc406Sopenharmony_ci return "ECANCELED"; 250141cc406Sopenharmony_ci case PIXMA_ENOTSUP: 251141cc406Sopenharmony_ci return "ENOTSUP"; 252141cc406Sopenharmony_ci case PIXMA_ETIMEDOUT: 253141cc406Sopenharmony_ci return "ETIMEDOUT"; 254141cc406Sopenharmony_ci case PIXMA_EPROTO: 255141cc406Sopenharmony_ci return "EPROTO"; 256141cc406Sopenharmony_ci case PIXMA_EPAPER_JAMMED: 257141cc406Sopenharmony_ci return "EPAPER_JAMMED"; 258141cc406Sopenharmony_ci case PIXMA_ECOVER_OPEN: 259141cc406Sopenharmony_ci return "ECOVER_OPEN"; 260141cc406Sopenharmony_ci case PIXMA_ENO_PAPER: 261141cc406Sopenharmony_ci return "ENO_PAPER"; 262141cc406Sopenharmony_ci case PIXMA_EOF: 263141cc406Sopenharmony_ci return "EEOF"; 264141cc406Sopenharmony_ci } 265141cc406Sopenharmony_ci snprintf (buf, sizeof (buf), "EUNKNOWN:%d", error); 266141cc406Sopenharmony_ci return buf; 267141cc406Sopenharmony_ci} 268141cc406Sopenharmony_ci 269141cc406Sopenharmony_civoid 270141cc406Sopenharmony_cipixma_set_debug_level (int level) 271141cc406Sopenharmony_ci{ 272141cc406Sopenharmony_ci debug_level = level; 273141cc406Sopenharmony_ci} 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_civoid 276141cc406Sopenharmony_cipixma_set_be16 (uint16_t x, uint8_t * buf) 277141cc406Sopenharmony_ci{ 278141cc406Sopenharmony_ci buf[0] = x >> 8; 279141cc406Sopenharmony_ci buf[1] = x; 280141cc406Sopenharmony_ci} 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_civoid 283141cc406Sopenharmony_cipixma_set_be32 (uint32_t x, uint8_t * buf) 284141cc406Sopenharmony_ci{ 285141cc406Sopenharmony_ci buf[0] = x >> 24; 286141cc406Sopenharmony_ci buf[1] = x >> 16; 287141cc406Sopenharmony_ci buf[2] = x >> 8; 288141cc406Sopenharmony_ci buf[3] = x; 289141cc406Sopenharmony_ci} 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ciuint16_t 292141cc406Sopenharmony_cipixma_get_be16 (const uint8_t * buf) 293141cc406Sopenharmony_ci{ 294141cc406Sopenharmony_ci return ((uint16_t) buf[0] << 8) | buf[1]; 295141cc406Sopenharmony_ci} 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ciuint32_t 298141cc406Sopenharmony_cipixma_get_be32 (const uint8_t * buf) 299141cc406Sopenharmony_ci{ 300141cc406Sopenharmony_ci return ((uint32_t) buf[0] << 24) + ((uint32_t) buf[1] << 16) + 301141cc406Sopenharmony_ci ((uint32_t) buf[2] << 8) + buf[3]; 302141cc406Sopenharmony_ci} 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ciuint8_t 305141cc406Sopenharmony_cipixma_sum_bytes (const void *data, unsigned len) 306141cc406Sopenharmony_ci{ 307141cc406Sopenharmony_ci const uint8_t *d = (const uint8_t *) data; 308141cc406Sopenharmony_ci unsigned i, sum = 0; 309141cc406Sopenharmony_ci for (i = 0; i != len; i++) 310141cc406Sopenharmony_ci sum += d[i]; 311141cc406Sopenharmony_ci return sum; 312141cc406Sopenharmony_ci} 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_civoid 315141cc406Sopenharmony_cipixma_sleep (unsigned long usec) 316141cc406Sopenharmony_ci{ 317141cc406Sopenharmony_ci usleep (usec); 318141cc406Sopenharmony_ci} 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_civoid 321141cc406Sopenharmony_cipixma_get_time (time_t * sec, uint32_t * usec) 322141cc406Sopenharmony_ci{ 323141cc406Sopenharmony_ci struct timeval tv; 324141cc406Sopenharmony_ci gettimeofday (&tv, NULL); 325141cc406Sopenharmony_ci if (sec) 326141cc406Sopenharmony_ci *sec = tv.tv_sec; 327141cc406Sopenharmony_ci if (usec) 328141cc406Sopenharmony_ci *usec = tv.tv_usec; 329141cc406Sopenharmony_ci} 330141cc406Sopenharmony_ci 331141cc406Sopenharmony_ci/* convert 24/48 bit RGB to 8/16 bit ir 332141cc406Sopenharmony_ci * 333141cc406Sopenharmony_ci * Formular: g = R 334141cc406Sopenharmony_ci * drop G + B 335141cc406Sopenharmony_ci * 336141cc406Sopenharmony_ci * sptr: source color scale buffer 337141cc406Sopenharmony_ci * gptr: destination gray scale buffer 338141cc406Sopenharmony_ci * c == 3: 24 bit RGB -> 8 bit ir 339141cc406Sopenharmony_ci * c == 6: 48 bit RGB -> 16 bit ir 340141cc406Sopenharmony_ci */ 341141cc406Sopenharmony_ciuint8_t * 342141cc406Sopenharmony_cipixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c) 343141cc406Sopenharmony_ci{ 344141cc406Sopenharmony_ci unsigned i; 345141cc406Sopenharmony_ci 346141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*pixma_rgb_to_ir*****\n")); */ 347141cc406Sopenharmony_ci 348141cc406Sopenharmony_ci for (i = 0; i < w; i++) 349141cc406Sopenharmony_ci { 350141cc406Sopenharmony_ci *gptr++ = *sptr++; 351141cc406Sopenharmony_ci if (c == 6) *gptr++ = *sptr++; /* 48 bit RGB: high byte */ 352141cc406Sopenharmony_ci sptr += (c == 6) ? 4 : 2; /* drop G + B */ 353141cc406Sopenharmony_ci } 354141cc406Sopenharmony_ci return gptr; 355141cc406Sopenharmony_ci} 356141cc406Sopenharmony_ci 357141cc406Sopenharmony_ci/* convert 24/48 bit RGB to 8/16 bit grayscale 358141cc406Sopenharmony_ci * 359141cc406Sopenharmony_ci * Formular: Y' = 0,2126 R' + 0,7152 G' + 0,0722 B' 360141cc406Sopenharmony_ci * 361141cc406Sopenharmony_ci * sptr: source color scale buffer 362141cc406Sopenharmony_ci * gptr: destination gray scale buffer 363141cc406Sopenharmony_ci * c == 3: 24 bit RGB -> 8 bit gray 364141cc406Sopenharmony_ci * c == 6: 48 bit RGB -> 16 bit gray 365141cc406Sopenharmony_ci */ 366141cc406Sopenharmony_ciuint8_t * 367141cc406Sopenharmony_cipixma_rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c) 368141cc406Sopenharmony_ci{ 369141cc406Sopenharmony_ci unsigned i, g; 370141cc406Sopenharmony_ci 371141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*pixma_rgb_to_gray*****\n")); */ 372141cc406Sopenharmony_ci 373141cc406Sopenharmony_ci for (i = 0; i < w; i++) 374141cc406Sopenharmony_ci { 375141cc406Sopenharmony_ci if (c == 6) 376141cc406Sopenharmony_ci { /* 48 bit RGB */ 377141cc406Sopenharmony_ci unsigned r = sptr[0] + (sptr[1] << 8); 378141cc406Sopenharmony_ci unsigned y = sptr[2] + (sptr[3] << 8); 379141cc406Sopenharmony_ci unsigned b = sptr[4] + (sptr[5] << 8); 380141cc406Sopenharmony_ci 381141cc406Sopenharmony_ci g = (r * 2126) + (y * 7152) + (b * 722); 382141cc406Sopenharmony_ci sptr += 6; 383141cc406Sopenharmony_ci } 384141cc406Sopenharmony_ci else 385141cc406Sopenharmony_ci { /* 24 bit RGB */ 386141cc406Sopenharmony_ci g = (sptr[0] * 2126) + (sptr[1] * 7152) + (sptr[2] * 722); 387141cc406Sopenharmony_ci sptr += 3; 388141cc406Sopenharmony_ci } 389141cc406Sopenharmony_ci g /= 10000; /* 8 and 16 bit gray */ 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci *gptr++ = g; 392141cc406Sopenharmony_ci if (c == 6) *gptr++ = (g >> 8); /* 16 bit gray: high byte */ 393141cc406Sopenharmony_ci } 394141cc406Sopenharmony_ci return gptr; 395141cc406Sopenharmony_ci} 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci/** 398141cc406Sopenharmony_ci * This code was taken from the genesys backend 399141cc406Sopenharmony_ci * uses threshold and threshold_curve to control software binarization 400141cc406Sopenharmony_ci * @param sp device set up for the scan 401141cc406Sopenharmony_ci * @param dst pointer where to store result 402141cc406Sopenharmony_ci * @param src pointer to raw data 403141cc406Sopenharmony_ci * @param width width of the processed line 404141cc406Sopenharmony_ci * @param c 1 for 1-channel single-byte data, 405141cc406Sopenharmony_ci * 3 for 3-channel single-byte data, 406141cc406Sopenharmony_ci * 6 for double-byte data 407141cc406Sopenharmony_ci * */ 408141cc406Sopenharmony_ciuint8_t * 409141cc406Sopenharmony_cipixma_binarize_line(pixma_scan_param_t * sp, uint8_t * dst, uint8_t * src, unsigned width, unsigned c) 410141cc406Sopenharmony_ci{ 411141cc406Sopenharmony_ci unsigned j, x, windowX, sum = 0; 412141cc406Sopenharmony_ci unsigned threshold; 413141cc406Sopenharmony_ci unsigned offset, addCol; 414141cc406Sopenharmony_ci int dropCol, offsetX; 415141cc406Sopenharmony_ci unsigned char mask; 416141cc406Sopenharmony_ci uint8_t min, max; 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*pixma_binarize_line***** src = %u, dst = %u, width = %u, c = %u, threshold = %u, threshold_curve = %u *****\n", 419141cc406Sopenharmony_ci src, dst, width, c, sp->threshold, sp->threshold_curve)); */ 420141cc406Sopenharmony_ci 421141cc406Sopenharmony_ci /* 16 bit grayscale not supported */ 422141cc406Sopenharmony_ci if (c == 6) 423141cc406Sopenharmony_ci { 424141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "*pixma_binarize_line***** Error: 16 bit grayscale not supported\n")); 425141cc406Sopenharmony_ci return dst; 426141cc406Sopenharmony_ci } 427141cc406Sopenharmony_ci 428141cc406Sopenharmony_ci /* first, color convert to grayscale */ 429141cc406Sopenharmony_ci if (c != 1) 430141cc406Sopenharmony_ci pixma_rgb_to_gray(dst, src, width, c); 431141cc406Sopenharmony_ci 432141cc406Sopenharmony_ci /* second, normalize line */ 433141cc406Sopenharmony_ci min = 255; 434141cc406Sopenharmony_ci max = 0; 435141cc406Sopenharmony_ci for (x = 0; x < width; x++) 436141cc406Sopenharmony_ci { 437141cc406Sopenharmony_ci if (src[x] > max) 438141cc406Sopenharmony_ci { 439141cc406Sopenharmony_ci max = src[x]; 440141cc406Sopenharmony_ci } 441141cc406Sopenharmony_ci if (src[x] < min) 442141cc406Sopenharmony_ci { 443141cc406Sopenharmony_ci min = src[x]; 444141cc406Sopenharmony_ci } 445141cc406Sopenharmony_ci } 446141cc406Sopenharmony_ci 447141cc406Sopenharmony_ci /* safeguard against dark or white areas */ 448141cc406Sopenharmony_ci if(min>80) 449141cc406Sopenharmony_ci min=0; 450141cc406Sopenharmony_ci if(max<80) 451141cc406Sopenharmony_ci max=255; 452141cc406Sopenharmony_ci for (x = 0; x < width; x++) 453141cc406Sopenharmony_ci { 454141cc406Sopenharmony_ci src[x] = ((src[x] - min) * 255) / (max - min); 455141cc406Sopenharmony_ci } 456141cc406Sopenharmony_ci 457141cc406Sopenharmony_ci /* third, create sliding window, prefill the sliding sum */ 458141cc406Sopenharmony_ci /* ~1mm works best, but the window needs to have odd # of pixels */ 459141cc406Sopenharmony_ci windowX = (6 * sp->xdpi) / 150; 460141cc406Sopenharmony_ci if (!(windowX % 2)) 461141cc406Sopenharmony_ci windowX++; 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ci /* to avoid conflicts with *dst start with offset */ 464141cc406Sopenharmony_ci offsetX = 1 + (windowX / 2) / 8; 465141cc406Sopenharmony_ci for (j = offsetX; j <= windowX; j++) 466141cc406Sopenharmony_ci sum += src[j]; 467141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** windowX = %u, startX = %u, sum = %u\n", 468141cc406Sopenharmony_ci windowX, startX, sum)); */ 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci /* fourth, walk the input buffer, output bits */ 471141cc406Sopenharmony_ci for (j = 0; j < width; j++) 472141cc406Sopenharmony_ci { 473141cc406Sopenharmony_ci /* output image location */ 474141cc406Sopenharmony_ci offset = j % 8; 475141cc406Sopenharmony_ci mask = 0x80 >> offset; 476141cc406Sopenharmony_ci threshold = sp->threshold; 477141cc406Sopenharmony_ci 478141cc406Sopenharmony_ci /* move sum/update threshold only if there is a curve */ 479141cc406Sopenharmony_ci if (sp->threshold_curve) 480141cc406Sopenharmony_ci { 481141cc406Sopenharmony_ci addCol = j + windowX / 2; 482141cc406Sopenharmony_ci dropCol = addCol - windowX; 483141cc406Sopenharmony_ci 484141cc406Sopenharmony_ci if (dropCol >= offsetX && addCol < width) 485141cc406Sopenharmony_ci { 486141cc406Sopenharmony_ci sum += src[addCol]; 487141cc406Sopenharmony_ci sum -= (sum < src[dropCol] ? sum : src[dropCol]); /* no negative sum */ 488141cc406Sopenharmony_ci } 489141cc406Sopenharmony_ci threshold = sp->lineart_lut[sum / windowX]; 490141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** addCol = %u, dropCol = %d, sum = %u, windowX = %u, lut-element = %d, threshold = %u\n", 491141cc406Sopenharmony_ci addCol, dropCol, sum, windowX, sum/windowX, threshold)); */ 492141cc406Sopenharmony_ci } 493141cc406Sopenharmony_ci 494141cc406Sopenharmony_ci /* lookup threshold */ 495141cc406Sopenharmony_ci if (src[j] > threshold) 496141cc406Sopenharmony_ci *dst &= ~mask; /* white */ 497141cc406Sopenharmony_ci else 498141cc406Sopenharmony_ci *dst |= mask; /* black */ 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci if (offset == 7) 501141cc406Sopenharmony_ci dst++; 502141cc406Sopenharmony_ci } 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** ready: src = %u, dst = %u *****\n", src, dst)); */ 505141cc406Sopenharmony_ci 506141cc406Sopenharmony_ci return dst; 507141cc406Sopenharmony_ci} 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci/** 510141cc406Sopenharmony_ci This code was taken from the genesys backend 511141cc406Sopenharmony_ci Function to build a lookup table (LUT), often 512141cc406Sopenharmony_ci used by scanners to implement brightness/contrast/gamma 513141cc406Sopenharmony_ci or by backends to speed binarization/thresholding 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci offset and slope inputs are -127 to +127 516141cc406Sopenharmony_ci 517141cc406Sopenharmony_ci slope rotates line around central input/output val, 518141cc406Sopenharmony_ci 0 makes horizontal line 519141cc406Sopenharmony_ci 520141cc406Sopenharmony_ci pos zero neg 521141cc406Sopenharmony_ci . x . . x 522141cc406Sopenharmony_ci . x . . x 523141cc406Sopenharmony_ci out . x .xxxxxxxxxxx . x 524141cc406Sopenharmony_ci . x . . x 525141cc406Sopenharmony_ci ....x....... ............ .......x.... 526141cc406Sopenharmony_ci in in in 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_ci offset moves line vertically, and clamps to output range 529141cc406Sopenharmony_ci 0 keeps the line crossing the center of the table 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_ci high low 532141cc406Sopenharmony_ci . xxxxxxxx . 533141cc406Sopenharmony_ci . x . 534141cc406Sopenharmony_ci out x . x 535141cc406Sopenharmony_ci . . x 536141cc406Sopenharmony_ci ............ xxxxxxxx.... 537141cc406Sopenharmony_ci in in 538141cc406Sopenharmony_ci 539141cc406Sopenharmony_ci out_min/max provide bounds on output values, 540141cc406Sopenharmony_ci useful when building thresholding lut. 541141cc406Sopenharmony_ci 0 and 255 are good defaults otherwise. 542141cc406Sopenharmony_ci * */ 543141cc406Sopenharmony_cistatic SANE_Status 544141cc406Sopenharmony_ciload_lut (unsigned char * lut, 545141cc406Sopenharmony_ci int in_bits, int out_bits, 546141cc406Sopenharmony_ci int out_min, int out_max, 547141cc406Sopenharmony_ci int slope, int offset) 548141cc406Sopenharmony_ci{ 549141cc406Sopenharmony_ci int i, j; 550141cc406Sopenharmony_ci double shift, rise; 551141cc406Sopenharmony_ci int max_in_val = (1 << in_bits) - 1; 552141cc406Sopenharmony_ci int max_out_val = (1 << out_bits) - 1; 553141cc406Sopenharmony_ci unsigned char * lut_p = lut; 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*load_lut***** start %d %d *****\n", slope, offset)); */ 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_ci /* slope is converted to rise per unit run: 558141cc406Sopenharmony_ci * first [-127,127] to [-1,1] 559141cc406Sopenharmony_ci * then multiply by PI/2 to convert to radians 560141cc406Sopenharmony_ci * then take the tangent (T.O.A) 561141cc406Sopenharmony_ci * then multiply by the normal linear slope 562141cc406Sopenharmony_ci * because the table may not be square, i.e. 1024x256*/ 563141cc406Sopenharmony_ci rise = tan((double)slope/127 * M_PI/2) * max_out_val / max_in_val; 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci /* line must stay vertically centered, so figure 566141cc406Sopenharmony_ci * out vertical offset at central input value */ 567141cc406Sopenharmony_ci shift = (double)max_out_val/2 - (rise*max_in_val/2); 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci /* convert the user offset setting to scale of output 570141cc406Sopenharmony_ci * first [-127,127] to [-1,1] 571141cc406Sopenharmony_ci * then to [-max_out_val/2,max_out_val/2]*/ 572141cc406Sopenharmony_ci shift += (double)offset / 127 * max_out_val / 2; 573141cc406Sopenharmony_ci 574141cc406Sopenharmony_ci for(i=0;i<=max_in_val;i++){ 575141cc406Sopenharmony_ci j = rise*i + shift; 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_ci if(j<out_min){ 578141cc406Sopenharmony_ci j=out_min; 579141cc406Sopenharmony_ci } 580141cc406Sopenharmony_ci else if(j>out_max){ 581141cc406Sopenharmony_ci j=out_max; 582141cc406Sopenharmony_ci } 583141cc406Sopenharmony_ci 584141cc406Sopenharmony_ci *lut_p=j; 585141cc406Sopenharmony_ci lut_p++; 586141cc406Sopenharmony_ci } 587141cc406Sopenharmony_ci 588141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*load_lut***** finish *****\n")); */ 589141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, lut, max_in_val+1)); */ 590141cc406Sopenharmony_ci 591141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 592141cc406Sopenharmony_ci} 593141cc406Sopenharmony_ci 594141cc406Sopenharmony_ciint 595141cc406Sopenharmony_cipixma_map_status_errno (unsigned status) 596141cc406Sopenharmony_ci{ 597141cc406Sopenharmony_ci switch (status) 598141cc406Sopenharmony_ci { 599141cc406Sopenharmony_ci case PIXMA_STATUS_OK: 600141cc406Sopenharmony_ci return 0; 601141cc406Sopenharmony_ci case PIXMA_STATUS_FAILED: 602141cc406Sopenharmony_ci return PIXMA_ECANCELED; 603141cc406Sopenharmony_ci case PIXMA_STATUS_BUSY: 604141cc406Sopenharmony_ci return PIXMA_EBUSY; 605141cc406Sopenharmony_ci default: 606141cc406Sopenharmony_ci return PIXMA_EPROTO; 607141cc406Sopenharmony_ci } 608141cc406Sopenharmony_ci} 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_ciint 611141cc406Sopenharmony_cipixma_check_result (pixma_cmdbuf_t * cb) 612141cc406Sopenharmony_ci{ 613141cc406Sopenharmony_ci const uint8_t *r = cb->buf; 614141cc406Sopenharmony_ci unsigned header_len = cb->res_header_len; 615141cc406Sopenharmony_ci unsigned expected_reslen = cb->expected_reslen; 616141cc406Sopenharmony_ci int error; 617141cc406Sopenharmony_ci unsigned len; 618141cc406Sopenharmony_ci 619141cc406Sopenharmony_ci if (cb->reslen < 0) 620141cc406Sopenharmony_ci return cb->reslen; 621141cc406Sopenharmony_ci 622141cc406Sopenharmony_ci len = (unsigned) cb->reslen; 623141cc406Sopenharmony_ci if (len >= header_len) 624141cc406Sopenharmony_ci { 625141cc406Sopenharmony_ci error = pixma_map_status_errno (pixma_get_be16 (r)); 626141cc406Sopenharmony_ci if (expected_reslen != 0) 627141cc406Sopenharmony_ci { 628141cc406Sopenharmony_ci if (len == expected_reslen) 629141cc406Sopenharmony_ci { 630141cc406Sopenharmony_ci if (pixma_sum_bytes (r + header_len, len - header_len) != 0) 631141cc406Sopenharmony_ci error = PIXMA_EPROTO; 632141cc406Sopenharmony_ci } 633141cc406Sopenharmony_ci else 634141cc406Sopenharmony_ci { 635141cc406Sopenharmony_ci /* This case will happen when a command cannot be completely 636141cc406Sopenharmony_ci executed, e.g. because you press the cancel button. The 637141cc406Sopenharmony_ci device will return only a header with PIXMA_STATUS_FAILED. */ 638141cc406Sopenharmony_ci if (len != header_len) 639141cc406Sopenharmony_ci error = PIXMA_EPROTO; 640141cc406Sopenharmony_ci } 641141cc406Sopenharmony_ci } 642141cc406Sopenharmony_ci } 643141cc406Sopenharmony_ci else 644141cc406Sopenharmony_ci error = PIXMA_EPROTO; 645141cc406Sopenharmony_ci 646141cc406Sopenharmony_ci#ifndef NDEBUG 647141cc406Sopenharmony_ci if (error == PIXMA_EPROTO) 648141cc406Sopenharmony_ci { 649141cc406Sopenharmony_ci pixma_dbg (1, "WARNING: result len=%d expected %d\n", 650141cc406Sopenharmony_ci len, cb->expected_reslen); 651141cc406Sopenharmony_ci pixma_hexdump (1, r, MIN (len, 64)); 652141cc406Sopenharmony_ci } 653141cc406Sopenharmony_ci#endif 654141cc406Sopenharmony_ci return error; 655141cc406Sopenharmony_ci} 656141cc406Sopenharmony_ci 657141cc406Sopenharmony_ciint 658141cc406Sopenharmony_cipixma_cmd_transaction (pixma_t * s, const void *cmd, unsigned cmdlen, 659141cc406Sopenharmony_ci void *data, unsigned expected_len) 660141cc406Sopenharmony_ci{ 661141cc406Sopenharmony_ci int error, tmo; 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci error = pixma_write (s->io, cmd, cmdlen); 664141cc406Sopenharmony_ci if (error != (int) cmdlen) 665141cc406Sopenharmony_ci { 666141cc406Sopenharmony_ci if (error >= 0) 667141cc406Sopenharmony_ci { 668141cc406Sopenharmony_ci /* Write timeout is too low? */ 669141cc406Sopenharmony_ci PDBG (pixma_dbg 670141cc406Sopenharmony_ci (1, "ERROR: incomplete write, %u out of %u written\n", 671141cc406Sopenharmony_ci (unsigned) error, cmdlen)); 672141cc406Sopenharmony_ci error = PIXMA_ETIMEDOUT; 673141cc406Sopenharmony_ci } 674141cc406Sopenharmony_ci return error; 675141cc406Sopenharmony_ci } 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci /* When you send the start_session command while the scanner optic is 678141cc406Sopenharmony_ci going back to the home position after the last scan session has been 679141cc406Sopenharmony_ci cancelled, you won't get the response before it arrives home. This takes 680141cc406Sopenharmony_ci about 5 seconds. If the last session was succeeded, the scanner will 681141cc406Sopenharmony_ci immediately answer with PIXMA_STATUS_BUSY. 682141cc406Sopenharmony_ci 683141cc406Sopenharmony_ci Is 8 seconds timeout enough? This affects ALL commands that use 684141cc406Sopenharmony_ci pixma_cmd_transaction(). Default value set in pixma_open(). */ 685141cc406Sopenharmony_ci tmo = s->rec_tmo; 686141cc406Sopenharmony_ci do 687141cc406Sopenharmony_ci { 688141cc406Sopenharmony_ci error = pixma_read (s->io, data, expected_len); 689141cc406Sopenharmony_ci if (error == PIXMA_ETIMEDOUT) 690141cc406Sopenharmony_ci { 691141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "No response yet. Timed out in %d sec.\n", tmo)); 692141cc406Sopenharmony_ci 693141cc406Sopenharmony_ci#ifndef HAVE_SANEI_USB_SET_TIMEOUT 694141cc406Sopenharmony_ci /* 1s timeout 695141cc406Sopenharmony_ci Only needed, if sanei_usb_set_timeout() isn't available. 696141cc406Sopenharmony_ci pixma_read() has an internal timeout of 1 sec. */ 697141cc406Sopenharmony_ci pixma_sleep (1000000); 698141cc406Sopenharmony_ci#endif 699141cc406Sopenharmony_ci } 700141cc406Sopenharmony_ci } 701141cc406Sopenharmony_ci while (error == PIXMA_ETIMEDOUT && --tmo != 0); 702141cc406Sopenharmony_ci if (error < 0) 703141cc406Sopenharmony_ci { 704141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Error in response phase. cmd:%02x%02x\n", 705141cc406Sopenharmony_ci ((const uint8_t *) cmd)[0], 706141cc406Sopenharmony_ci ((const uint8_t *) cmd)[1])); 707141cc406Sopenharmony_ci PDBG (pixma_dbg (1," If the scanner hangs, reset it and/or unplug the " 708141cc406Sopenharmony_ci "USB cable.\n")); 709141cc406Sopenharmony_ci } 710141cc406Sopenharmony_ci return error; /* length of the result packet or error */ 711141cc406Sopenharmony_ci} 712141cc406Sopenharmony_ci 713141cc406Sopenharmony_ciuint8_t * 714141cc406Sopenharmony_cipixma_newcmd (pixma_cmdbuf_t * cb, unsigned cmd, 715141cc406Sopenharmony_ci unsigned dataout, unsigned datain) 716141cc406Sopenharmony_ci{ 717141cc406Sopenharmony_ci unsigned cmdlen = cb->cmd_header_len + dataout; 718141cc406Sopenharmony_ci unsigned reslen = cb->res_header_len + datain; 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci if (cmdlen > cb->size || reslen > cb->size) 721141cc406Sopenharmony_ci return NULL; 722141cc406Sopenharmony_ci memset (cb->buf, 0, cmdlen); 723141cc406Sopenharmony_ci cb->cmdlen = cmdlen; 724141cc406Sopenharmony_ci cb->expected_reslen = reslen; 725141cc406Sopenharmony_ci pixma_set_be16 (cmd, cb->buf); 726141cc406Sopenharmony_ci pixma_set_be16 (dataout + datain, cb->buf + cb->cmd_len_field_ofs); 727141cc406Sopenharmony_ci if (dataout != 0) 728141cc406Sopenharmony_ci return cb->buf + cb->cmd_header_len; 729141cc406Sopenharmony_ci else 730141cc406Sopenharmony_ci return cb->buf + cb->res_header_len; 731141cc406Sopenharmony_ci} 732141cc406Sopenharmony_ci 733141cc406Sopenharmony_ciint 734141cc406Sopenharmony_cipixma_exec (pixma_t * s, pixma_cmdbuf_t * cb) 735141cc406Sopenharmony_ci{ 736141cc406Sopenharmony_ci if (cb->cmdlen > cb->cmd_header_len) 737141cc406Sopenharmony_ci pixma_fill_checksum (cb->buf + cb->cmd_header_len, 738141cc406Sopenharmony_ci cb->buf + cb->cmdlen - 1); 739141cc406Sopenharmony_ci cb->reslen = 740141cc406Sopenharmony_ci pixma_cmd_transaction (s, cb->buf, cb->cmdlen, cb->buf, 741141cc406Sopenharmony_ci cb->expected_reslen); 742141cc406Sopenharmony_ci return pixma_check_result (cb); 743141cc406Sopenharmony_ci} 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_ciint 746141cc406Sopenharmony_cipixma_exec_short_cmd (pixma_t * s, pixma_cmdbuf_t * cb, unsigned cmd) 747141cc406Sopenharmony_ci{ 748141cc406Sopenharmony_ci pixma_newcmd (cb, cmd, 0, 0); 749141cc406Sopenharmony_ci return pixma_exec (s, cb); 750141cc406Sopenharmony_ci} 751141cc406Sopenharmony_ci 752141cc406Sopenharmony_ciint 753141cc406Sopenharmony_cipixma_check_dpi (unsigned dpi, unsigned max) 754141cc406Sopenharmony_ci{ 755141cc406Sopenharmony_ci /* valid dpi = 75 * 2^n */ 756141cc406Sopenharmony_ci unsigned temp = dpi / 75; 757141cc406Sopenharmony_ci if (dpi > max || dpi < 75 || 75 * temp != dpi || (temp & (temp - 1)) != 0) 758141cc406Sopenharmony_ci return PIXMA_EINVAL; 759141cc406Sopenharmony_ci return 0; 760141cc406Sopenharmony_ci} 761141cc406Sopenharmony_ci 762141cc406Sopenharmony_ci 763141cc406Sopenharmony_ciint 764141cc406Sopenharmony_cipixma_init (void) 765141cc406Sopenharmony_ci{ 766141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "pixma version %d.%d.%d\n", PIXMA_VERSION_MAJOR, 767141cc406Sopenharmony_ci PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD)); 768141cc406Sopenharmony_ci PASSERT (first_pixma == NULL); 769141cc406Sopenharmony_ci if (tstart_sec == 0) 770141cc406Sopenharmony_ci pixma_get_time (&tstart_sec, &tstart_usec); 771141cc406Sopenharmony_ci return pixma_io_init (); 772141cc406Sopenharmony_ci} 773141cc406Sopenharmony_ci 774141cc406Sopenharmony_civoid 775141cc406Sopenharmony_cipixma_cleanup (void) 776141cc406Sopenharmony_ci{ 777141cc406Sopenharmony_ci while (first_pixma) 778141cc406Sopenharmony_ci pixma_close (first_pixma); 779141cc406Sopenharmony_ci pixma_io_cleanup (); 780141cc406Sopenharmony_ci} 781141cc406Sopenharmony_ci 782141cc406Sopenharmony_ciint 783141cc406Sopenharmony_cipixma_open (unsigned devnr, pixma_t ** handle) 784141cc406Sopenharmony_ci{ 785141cc406Sopenharmony_ci int error; 786141cc406Sopenharmony_ci pixma_t *s; 787141cc406Sopenharmony_ci const pixma_config_t *cfg; 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci *handle = NULL; 790141cc406Sopenharmony_ci cfg = pixma_get_device_config (devnr); 791141cc406Sopenharmony_ci if (!cfg) 792141cc406Sopenharmony_ci return PIXMA_EINVAL; /* invalid devnr */ 793141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "pixma_open(): %s\n", cfg->name)); 794141cc406Sopenharmony_ci 795141cc406Sopenharmony_ci s = (pixma_t *) calloc (1, sizeof (s[0])); 796141cc406Sopenharmony_ci if (!s) 797141cc406Sopenharmony_ci return PIXMA_ENOMEM; 798141cc406Sopenharmony_ci s->next = first_pixma; 799141cc406Sopenharmony_ci first_pixma = s; 800141cc406Sopenharmony_ci 801141cc406Sopenharmony_ci s->cfg = cfg; 802141cc406Sopenharmony_ci s->rec_tmo = 8; /* set receive timeout to 8 seconds */ 803141cc406Sopenharmony_ci error = pixma_connect (devnr, &s->io); 804141cc406Sopenharmony_ci if (error < 0) 805141cc406Sopenharmony_ci { 806141cc406Sopenharmony_ci PDBG (pixma_dbg 807141cc406Sopenharmony_ci (2, "pixma_connect() failed %s\n", pixma_strerror (error))); 808141cc406Sopenharmony_ci goto rollback; 809141cc406Sopenharmony_ci } 810141cc406Sopenharmony_ci strncpy (s->id, pixma_get_device_id (devnr), sizeof (s->id) - 1); 811141cc406Sopenharmony_ci s->ops = s->cfg->ops; 812141cc406Sopenharmony_ci s->scanning = 0; 813141cc406Sopenharmony_ci s->last_source = PIXMA_SOURCE_NONE; 814141cc406Sopenharmony_ci error = s->ops->open (s); 815141cc406Sopenharmony_ci if (error < 0) 816141cc406Sopenharmony_ci goto rollback; 817141cc406Sopenharmony_ci error = pixma_deactivate (s->io); 818141cc406Sopenharmony_ci if (error < 0) 819141cc406Sopenharmony_ci goto rollback; 820141cc406Sopenharmony_ci *handle = s; 821141cc406Sopenharmony_ci return 0; 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_cirollback: 824141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "pixma_open() failed %s\n", pixma_strerror (error))); 825141cc406Sopenharmony_ci pixma_close (s); 826141cc406Sopenharmony_ci return error; 827141cc406Sopenharmony_ci} 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_civoid 830141cc406Sopenharmony_cipixma_close (pixma_t * s) 831141cc406Sopenharmony_ci{ 832141cc406Sopenharmony_ci pixma_t **p; 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci if (!s) 835141cc406Sopenharmony_ci return; 836141cc406Sopenharmony_ci for (p = &first_pixma; *p && *p != s; p = &((*p)->next)) 837141cc406Sopenharmony_ci { 838141cc406Sopenharmony_ci } 839141cc406Sopenharmony_ci PASSERT (*p); 840141cc406Sopenharmony_ci if (!(*p)) 841141cc406Sopenharmony_ci return; 842141cc406Sopenharmony_ci PDBG (pixma_dbg (2, "pixma_close(): %s\n", s->cfg->name)); 843141cc406Sopenharmony_ci if (s->io) 844141cc406Sopenharmony_ci { 845141cc406Sopenharmony_ci if (s->scanning) 846141cc406Sopenharmony_ci { 847141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "pixma_close(): scanning in progress, call" 848141cc406Sopenharmony_ci " finish_scan()\n")); 849141cc406Sopenharmony_ci s->ops->finish_scan (s); 850141cc406Sopenharmony_ci } 851141cc406Sopenharmony_ci s->ops->close (s); 852141cc406Sopenharmony_ci pixma_disconnect (s->io); 853141cc406Sopenharmony_ci } 854141cc406Sopenharmony_ci *p = s->next; 855141cc406Sopenharmony_ci free (s); 856141cc406Sopenharmony_ci} 857141cc406Sopenharmony_ci 858141cc406Sopenharmony_ciint 859141cc406Sopenharmony_cipixma_scan (pixma_t * s, pixma_scan_param_t * sp) 860141cc406Sopenharmony_ci{ 861141cc406Sopenharmony_ci int error; 862141cc406Sopenharmony_ci 863141cc406Sopenharmony_ci error = pixma_check_scan_param (s, sp); 864141cc406Sopenharmony_ci if (error < 0) 865141cc406Sopenharmony_ci return error; 866141cc406Sopenharmony_ci 867141cc406Sopenharmony_ci if (sp->mode == PIXMA_SCAN_MODE_LINEART) 868141cc406Sopenharmony_ci { 869141cc406Sopenharmony_ci load_lut(sp->lineart_lut, 8, 8, 50, 205, 870141cc406Sopenharmony_ci sp->threshold_curve, sp->threshold-127); 871141cc406Sopenharmony_ci } 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci#ifndef NDEBUG 874141cc406Sopenharmony_ci pixma_dbg (3, "\n"); 875141cc406Sopenharmony_ci pixma_dbg (3, "pixma_scan(): start\n"); 876141cc406Sopenharmony_ci pixma_dbg (3, " line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n", 877141cc406Sopenharmony_ci sp->line_size, sp->image_size, sp->channels, sp->depth); 878141cc406Sopenharmony_ci pixma_dbg (3, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n", 879141cc406Sopenharmony_ci sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h); 880141cc406Sopenharmony_ci pixma_dbg (3, " gamma=%f gamma_table=%p source=%d\n", sp->gamma, (void *) sp->gamma_table, sp->source); 881141cc406Sopenharmony_ci pixma_dbg (3, " threshold=%d threshold_curve=%d\n", sp->threshold, sp->threshold_curve); 882141cc406Sopenharmony_ci pixma_dbg (3, " adf-wait=%d\n", sp->adf_wait); 883141cc406Sopenharmony_ci pixma_dbg (3, " ADF page count: %d\n", sp->adf_pageid); 884141cc406Sopenharmony_ci#endif 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ci s->param = sp; 887141cc406Sopenharmony_ci s->cancel = 0; 888141cc406Sopenharmony_ci s->cur_image_size = 0; 889141cc406Sopenharmony_ci s->imagebuf.wptr = NULL; 890141cc406Sopenharmony_ci s->imagebuf.wend = NULL; 891141cc406Sopenharmony_ci s->imagebuf.rptr = NULL; 892141cc406Sopenharmony_ci s->imagebuf.rend = NULL; 893141cc406Sopenharmony_ci s->underrun = 0; 894141cc406Sopenharmony_ci error = s->ops->scan (s); 895141cc406Sopenharmony_ci if (error >= 0) 896141cc406Sopenharmony_ci { 897141cc406Sopenharmony_ci s->scanning = 1; 898141cc406Sopenharmony_ci } 899141cc406Sopenharmony_ci else 900141cc406Sopenharmony_ci { 901141cc406Sopenharmony_ci PDBG (pixma_dbg 902141cc406Sopenharmony_ci (3, "pixma_scan() failed %s\n", pixma_strerror (error))); 903141cc406Sopenharmony_ci } 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci return error; 906141cc406Sopenharmony_ci} 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_cistatic uint8_t * 909141cc406Sopenharmony_cifill_pixels (pixma_t * s, uint8_t * ptr, uint8_t * end, uint8_t value) 910141cc406Sopenharmony_ci{ 911141cc406Sopenharmony_ci if (s->cur_image_size < s->param->image_size) 912141cc406Sopenharmony_ci { 913141cc406Sopenharmony_ci long n = s->param->image_size - s->cur_image_size; 914141cc406Sopenharmony_ci if (n > (end - ptr)) 915141cc406Sopenharmony_ci n = end - ptr; 916141cc406Sopenharmony_ci memset (ptr, value, n); 917141cc406Sopenharmony_ci s->cur_image_size += n; 918141cc406Sopenharmony_ci ptr += n; 919141cc406Sopenharmony_ci } 920141cc406Sopenharmony_ci return ptr; 921141cc406Sopenharmony_ci} 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ciint 924141cc406Sopenharmony_cipixma_read_image (pixma_t * s, void *buf, unsigned len) 925141cc406Sopenharmony_ci{ 926141cc406Sopenharmony_ci int result; 927141cc406Sopenharmony_ci pixma_imagebuf_t ib; 928141cc406Sopenharmony_ci 929141cc406Sopenharmony_ci if (!s->scanning) 930141cc406Sopenharmony_ci return 0; 931141cc406Sopenharmony_ci if (s->cancel) 932141cc406Sopenharmony_ci { 933141cc406Sopenharmony_ci result = PIXMA_ECANCELED; 934141cc406Sopenharmony_ci goto cancel; 935141cc406Sopenharmony_ci } 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci ib = s->imagebuf; /* get rptr and rend */ 938141cc406Sopenharmony_ci ib.wptr = (uint8_t *) buf; 939141cc406Sopenharmony_ci ib.wend = ib.wptr + len; 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ci if (s->underrun) 942141cc406Sopenharmony_ci { 943141cc406Sopenharmony_ci if (s->cur_image_size < s->param->image_size) 944141cc406Sopenharmony_ci { 945141cc406Sopenharmony_ci ib.wptr = fill_pixels (s, ib.wptr, ib.wend, 0xff); 946141cc406Sopenharmony_ci } 947141cc406Sopenharmony_ci else 948141cc406Sopenharmony_ci { 949141cc406Sopenharmony_ci PDBG (pixma_dbg 950141cc406Sopenharmony_ci (3, "pixma_read_image(): completed (underrun detected)\n")); 951141cc406Sopenharmony_ci s->scanning = 0; 952141cc406Sopenharmony_ci } 953141cc406Sopenharmony_ci return ib.wptr - (uint8_t *) buf; 954141cc406Sopenharmony_ci } 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci while (ib.wptr != ib.wend) 957141cc406Sopenharmony_ci { 958141cc406Sopenharmony_ci if (ib.rptr == ib.rend) 959141cc406Sopenharmony_ci { 960141cc406Sopenharmony_ci ib.rptr = ib.rend = NULL; 961141cc406Sopenharmony_ci result = s->ops->fill_buffer (s, &ib); 962141cc406Sopenharmony_ci if (result < 0) 963141cc406Sopenharmony_ci goto cancel; 964141cc406Sopenharmony_ci if (result == 0) 965141cc406Sopenharmony_ci { /* end of image? */ 966141cc406Sopenharmony_ci s->ops->finish_scan (s); 967141cc406Sopenharmony_ci /* set last source after successful scan */ 968141cc406Sopenharmony_ci s->last_source = s->param->source; 969141cc406Sopenharmony_ci if ((s->cur_image_size != s->param->image_size) && !s->param->mode_jpeg) 970141cc406Sopenharmony_ci { 971141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING:image size mismatches\n")); 972141cc406Sopenharmony_ci PDBG (pixma_dbg (1, 973141cc406Sopenharmony_ci " %"PRIu64" expected (%d lines) but %"PRIu64" received (%"PRIu64" lines)\n", 974141cc406Sopenharmony_ci s->param->image_size, s->param->h, 975141cc406Sopenharmony_ci s->cur_image_size, 976141cc406Sopenharmony_ci s->cur_image_size / s->param->line_size)); 977141cc406Sopenharmony_ci if ((s->cur_image_size % s->param->line_size) != 0) 978141cc406Sopenharmony_ci { 979141cc406Sopenharmony_ci PDBG (pixma_dbg (1, 980141cc406Sopenharmony_ci "BUG:received data not multiple of line_size\n")); 981141cc406Sopenharmony_ci } 982141cc406Sopenharmony_ci } 983141cc406Sopenharmony_ci if ((s->cur_image_size < s->param->image_size) && !s->param->mode_jpeg) 984141cc406Sopenharmony_ci { 985141cc406Sopenharmony_ci s->underrun = 1; 986141cc406Sopenharmony_ci ib.wptr = fill_pixels (s, ib.wptr, ib.wend, 0xff); 987141cc406Sopenharmony_ci } 988141cc406Sopenharmony_ci else 989141cc406Sopenharmony_ci { 990141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "pixma_read_image():completed\n")); 991141cc406Sopenharmony_ci s->scanning = 0; 992141cc406Sopenharmony_ci } 993141cc406Sopenharmony_ci break; 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci s->cur_image_size += result; 996141cc406Sopenharmony_ci 997141cc406Sopenharmony_ci PASSERT (s->cur_image_size <= s->param->image_size); 998141cc406Sopenharmony_ci } 999141cc406Sopenharmony_ci if (ib.rptr) 1000141cc406Sopenharmony_ci { 1001141cc406Sopenharmony_ci unsigned count = MIN (ib.rend - ib.rptr, ib.wend - ib.wptr); 1002141cc406Sopenharmony_ci memcpy (ib.wptr, ib.rptr, count); 1003141cc406Sopenharmony_ci ib.rptr += count; 1004141cc406Sopenharmony_ci ib.wptr += count; 1005141cc406Sopenharmony_ci } 1006141cc406Sopenharmony_ci } 1007141cc406Sopenharmony_ci s->imagebuf = ib; /* store rptr and rend */ 1008141cc406Sopenharmony_ci return ib.wptr - (uint8_t *) buf; 1009141cc406Sopenharmony_ci 1010141cc406Sopenharmony_cicancel: 1011141cc406Sopenharmony_ci s->ops->finish_scan (s); 1012141cc406Sopenharmony_ci s->scanning = 0; 1013141cc406Sopenharmony_ci if (result == PIXMA_ECANCELED) 1014141cc406Sopenharmony_ci { 1015141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "pixma_read_image(): cancelled by %sware\n", 1016141cc406Sopenharmony_ci (s->cancel) ? "soft" : "hard")); 1017141cc406Sopenharmony_ci } 1018141cc406Sopenharmony_ci else 1019141cc406Sopenharmony_ci { 1020141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "pixma_read_image() failed %s\n", 1021141cc406Sopenharmony_ci pixma_strerror (result))); 1022141cc406Sopenharmony_ci } 1023141cc406Sopenharmony_ci return result; 1024141cc406Sopenharmony_ci} 1025141cc406Sopenharmony_ci 1026141cc406Sopenharmony_civoid 1027141cc406Sopenharmony_cipixma_cancel (pixma_t * s) 1028141cc406Sopenharmony_ci{ 1029141cc406Sopenharmony_ci s->cancel = 1; 1030141cc406Sopenharmony_ci} 1031141cc406Sopenharmony_ci 1032141cc406Sopenharmony_ciint 1033141cc406Sopenharmony_cipixma_enable_background (pixma_t * s, int enabled) 1034141cc406Sopenharmony_ci{ 1035141cc406Sopenharmony_ci return pixma_set_interrupt_mode (s->io, enabled); 1036141cc406Sopenharmony_ci} 1037141cc406Sopenharmony_ci 1038141cc406Sopenharmony_ciint 1039141cc406Sopenharmony_cipixma_activate_connection(pixma_t * s) 1040141cc406Sopenharmony_ci{ 1041141cc406Sopenharmony_ci return pixma_activate (s->io); 1042141cc406Sopenharmony_ci} 1043141cc406Sopenharmony_ci 1044141cc406Sopenharmony_ciint 1045141cc406Sopenharmony_cipixma_deactivate_connection(pixma_t * s) 1046141cc406Sopenharmony_ci{ 1047141cc406Sopenharmony_ci return pixma_deactivate (s->io); 1048141cc406Sopenharmony_ci} 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_ciuint32_t 1051141cc406Sopenharmony_cipixma_wait_event (pixma_t * s, int timeout /*ms */ ) 1052141cc406Sopenharmony_ci{ 1053141cc406Sopenharmony_ci unsigned events; 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci if (s->events == PIXMA_EV_NONE && s->ops->wait_event) 1056141cc406Sopenharmony_ci s->ops->wait_event (s, timeout); 1057141cc406Sopenharmony_ci events = s->events; 1058141cc406Sopenharmony_ci s->events = PIXMA_EV_NONE; 1059141cc406Sopenharmony_ci return events; 1060141cc406Sopenharmony_ci} 1061141cc406Sopenharmony_ci 1062141cc406Sopenharmony_ci#define CLAMP2(x,w,min,max,dpi) do { \ 1063141cc406Sopenharmony_ci unsigned m = (max) * (dpi) / 75; \ 1064141cc406Sopenharmony_ci x = MIN(x, m - min); \ 1065141cc406Sopenharmony_ci w = MIN(w, m - x); \ 1066141cc406Sopenharmony_ci if (w < min) w = min; \ 1067141cc406Sopenharmony_ci} while(0) 1068141cc406Sopenharmony_ci 1069141cc406Sopenharmony_ciint 1070141cc406Sopenharmony_cipixma_check_scan_param (pixma_t * s, pixma_scan_param_t * sp) 1071141cc406Sopenharmony_ci{ 1072141cc406Sopenharmony_ci unsigned cfg_xdpi; 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci if (!(sp->channels == 3 || 1075141cc406Sopenharmony_ci (sp->channels == 1 && (s->cfg->cap & PIXMA_CAP_GRAY) != 0))) 1076141cc406Sopenharmony_ci return PIXMA_EINVAL; 1077141cc406Sopenharmony_ci 1078141cc406Sopenharmony_ci /* flatbed: use s->cfg->xdpi 1079141cc406Sopenharmony_ci * TPU/ADF: use s->cfg->adftpu_max_dpi, if configured with dpi value */ 1080141cc406Sopenharmony_ci cfg_xdpi = ((sp->source == PIXMA_SOURCE_FLATBED 1081141cc406Sopenharmony_ci || s->cfg->adftpu_max_dpi == 0) ? s->cfg->xdpi 1082141cc406Sopenharmony_ci : s->cfg->adftpu_max_dpi); 1083141cc406Sopenharmony_ci 1084141cc406Sopenharmony_ci if (pixma_check_dpi (sp->xdpi, cfg_xdpi) < 0 || 1085141cc406Sopenharmony_ci pixma_check_dpi (sp->ydpi, s->cfg->ydpi) < 0) 1086141cc406Sopenharmony_ci return PIXMA_EINVAL; 1087141cc406Sopenharmony_ci 1088141cc406Sopenharmony_ci /* xdpi must be equal to ydpi except that 1089141cc406Sopenharmony_ci xdpi = max_xdpi and ydpi = max_ydpi. */ 1090141cc406Sopenharmony_ci if (!(sp->xdpi == sp->ydpi || 1091141cc406Sopenharmony_ci (sp->xdpi == cfg_xdpi && sp->ydpi == s->cfg->ydpi))) 1092141cc406Sopenharmony_ci return PIXMA_EINVAL; 1093141cc406Sopenharmony_ci 1094141cc406Sopenharmony_ci if (s->ops->check_param (s, sp) < 0) 1095141cc406Sopenharmony_ci return PIXMA_EINVAL; 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci /* FIXME: I assume the same minimum width and height for every model. 1098141cc406Sopenharmony_ci * new scanners need minimum 16 px height 1099141cc406Sopenharmony_ci * minimum image size: 16 px x 16 px */ 1100141cc406Sopenharmony_ci CLAMP2 (sp->x, sp->w, 16, s->cfg->width, sp->xdpi); 1101141cc406Sopenharmony_ci CLAMP2 (sp->y, sp->h, 16, s->cfg->height, sp->ydpi); 1102141cc406Sopenharmony_ci 1103141cc406Sopenharmony_ci switch (sp->source) 1104141cc406Sopenharmony_ci { 1105141cc406Sopenharmony_ci case PIXMA_SOURCE_FLATBED: 1106141cc406Sopenharmony_ci break; 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_ci case PIXMA_SOURCE_TPU: 1109141cc406Sopenharmony_ci if ((s->cfg->cap & PIXMA_CAP_TPU) != PIXMA_CAP_TPU) 1110141cc406Sopenharmony_ci { 1111141cc406Sopenharmony_ci sp->source = PIXMA_SOURCE_FLATBED; 1112141cc406Sopenharmony_ci PDBG (pixma_dbg 1113141cc406Sopenharmony_ci (1, "WARNING: TPU unsupported, fallback to flatbed.\n")); 1114141cc406Sopenharmony_ci } 1115141cc406Sopenharmony_ci break; 1116141cc406Sopenharmony_ci 1117141cc406Sopenharmony_ci case PIXMA_SOURCE_ADF: 1118141cc406Sopenharmony_ci if ((s->cfg->cap & PIXMA_CAP_ADF) != PIXMA_CAP_ADF) 1119141cc406Sopenharmony_ci { 1120141cc406Sopenharmony_ci sp->source = PIXMA_SOURCE_FLATBED; 1121141cc406Sopenharmony_ci PDBG (pixma_dbg 1122141cc406Sopenharmony_ci (1, "WARNING: ADF unsupported, fallback to flatbed.\n")); 1123141cc406Sopenharmony_ci } 1124141cc406Sopenharmony_ci break; 1125141cc406Sopenharmony_ci 1126141cc406Sopenharmony_ci case PIXMA_SOURCE_ADFDUP: 1127141cc406Sopenharmony_ci if ((s->cfg->cap & PIXMA_CAP_ADFDUP) != PIXMA_CAP_ADFDUP) 1128141cc406Sopenharmony_ci { 1129141cc406Sopenharmony_ci if (s->cfg->cap & PIXMA_CAP_ADF) 1130141cc406Sopenharmony_ci { 1131141cc406Sopenharmony_ci sp->source = PIXMA_SOURCE_ADF; 1132141cc406Sopenharmony_ci } 1133141cc406Sopenharmony_ci else 1134141cc406Sopenharmony_ci { 1135141cc406Sopenharmony_ci sp->source = PIXMA_SOURCE_FLATBED; 1136141cc406Sopenharmony_ci } 1137141cc406Sopenharmony_ci PDBG (pixma_dbg 1138141cc406Sopenharmony_ci (1, "WARNING: ADF duplex unsupported, fallback to %d.\n", 1139141cc406Sopenharmony_ci sp->source)); 1140141cc406Sopenharmony_ci } 1141141cc406Sopenharmony_ci break; 1142141cc406Sopenharmony_ci case PIXMA_SOURCE_NONE: 1143141cc406Sopenharmony_ci /* this source can not be selected */ 1144141cc406Sopenharmony_ci break; 1145141cc406Sopenharmony_ci } 1146141cc406Sopenharmony_ci 1147141cc406Sopenharmony_ci if (sp->depth == 0) 1148141cc406Sopenharmony_ci sp->depth = 8; 1149141cc406Sopenharmony_ci if ((sp->depth % 8) != 0 && sp->depth != 1) 1150141cc406Sopenharmony_ci return PIXMA_EINVAL; 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci sp->line_size = 0; 1153141cc406Sopenharmony_ci 1154141cc406Sopenharmony_ci if (s->ops->check_param (s, sp) < 0) 1155141cc406Sopenharmony_ci return PIXMA_EINVAL; 1156141cc406Sopenharmony_ci 1157141cc406Sopenharmony_ci if (sp->line_size == 0) 1158141cc406Sopenharmony_ci sp->line_size = sp->depth / 8 * sp->channels * sp->w; 1159141cc406Sopenharmony_ci sp->image_size = sp->line_size * sp->h; 1160141cc406Sopenharmony_ci 1161141cc406Sopenharmony_ci /* image_size for software lineart is counted in bits */ 1162141cc406Sopenharmony_ci if (sp->software_lineart == 1) 1163141cc406Sopenharmony_ci sp->image_size /= 8; 1164141cc406Sopenharmony_ci return 0; 1165141cc406Sopenharmony_ci} 1166141cc406Sopenharmony_ci 1167141cc406Sopenharmony_ciconst char * 1168141cc406Sopenharmony_cipixma_get_string (pixma_t * s, pixma_string_index_t i) 1169141cc406Sopenharmony_ci{ 1170141cc406Sopenharmony_ci switch (i) 1171141cc406Sopenharmony_ci { 1172141cc406Sopenharmony_ci case PIXMA_STRING_MODEL: 1173141cc406Sopenharmony_ci return s->cfg->name; 1174141cc406Sopenharmony_ci case PIXMA_STRING_ID: 1175141cc406Sopenharmony_ci return s->id; 1176141cc406Sopenharmony_ci case PIXMA_STRING_LAST: 1177141cc406Sopenharmony_ci return NULL; 1178141cc406Sopenharmony_ci } 1179141cc406Sopenharmony_ci return NULL; 1180141cc406Sopenharmony_ci} 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ciconst pixma_config_t * 1183141cc406Sopenharmony_cipixma_get_config (pixma_t * s) 1184141cc406Sopenharmony_ci{ 1185141cc406Sopenharmony_ci return s->cfg; 1186141cc406Sopenharmony_ci} 1187141cc406Sopenharmony_ci 1188141cc406Sopenharmony_civoid 1189141cc406Sopenharmony_cipixma_fill_gamma_table (double gamma, uint8_t * table, unsigned n) 1190141cc406Sopenharmony_ci{ 1191141cc406Sopenharmony_ci unsigned i; 1192141cc406Sopenharmony_ci double r_gamma = 1.0 / gamma; 1193141cc406Sopenharmony_ci double in_scale = 1.0 / (n - 1); 1194141cc406Sopenharmony_ci 1195141cc406Sopenharmony_ci /* 8-bits gamma table 1196141cc406Sopenharmony_ci * for generation 1 scanners 1197141cc406Sopenharmony_ci */ 1198141cc406Sopenharmony_ci if (n == 4096) 1199141cc406Sopenharmony_ci { 1200141cc406Sopenharmony_ci double out_scale = 255.0; 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci for (i = 0; (unsigned) i != n; i++) 1203141cc406Sopenharmony_ci { 1204141cc406Sopenharmony_ci table[i] = (int) (out_scale * pow (i * in_scale, r_gamma) + 0.5); 1205141cc406Sopenharmony_ci } 1206141cc406Sopenharmony_ci } 1207141cc406Sopenharmony_ci 1208141cc406Sopenharmony_ci /* 16-bits gamma table */ 1209141cc406Sopenharmony_ci else 1210141cc406Sopenharmony_ci { 1211141cc406Sopenharmony_ci double out_scale = 65535.0; 1212141cc406Sopenharmony_ci uint16_t value; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci for (i = 0; i < n; i++) 1215141cc406Sopenharmony_ci { 1216141cc406Sopenharmony_ci value = (uint16_t) (out_scale * pow (i * in_scale, r_gamma) + 0.5); 1217141cc406Sopenharmony_ci table[2 * i] = (uint8_t) (value & 0xff); 1218141cc406Sopenharmony_ci table[2 * i + 1] = (uint8_t) (value >> 8); 1219141cc406Sopenharmony_ci } 1220141cc406Sopenharmony_ci } 1221141cc406Sopenharmony_ci} 1222141cc406Sopenharmony_ci 1223141cc406Sopenharmony_ciint 1224141cc406Sopenharmony_cipixma_find_scanners (const char **conf_devices, SANE_Bool local_only) 1225141cc406Sopenharmony_ci{ 1226141cc406Sopenharmony_ci return pixma_collect_devices (conf_devices, pixma_devices, local_only); 1227141cc406Sopenharmony_ci} 1228141cc406Sopenharmony_ci 1229141cc406Sopenharmony_ciconst char * 1230141cc406Sopenharmony_cipixma_get_device_model (unsigned devnr) 1231141cc406Sopenharmony_ci{ 1232141cc406Sopenharmony_ci const pixma_config_t *cfg = pixma_get_device_config (devnr); 1233141cc406Sopenharmony_ci return (cfg) ? cfg->name : NULL; 1234141cc406Sopenharmony_ci} 1235141cc406Sopenharmony_ci 1236141cc406Sopenharmony_ci 1237141cc406Sopenharmony_ciint 1238141cc406Sopenharmony_cipixma_get_device_status (pixma_t * s, pixma_device_status_t * status) 1239141cc406Sopenharmony_ci{ 1240141cc406Sopenharmony_ci if (!status) 1241141cc406Sopenharmony_ci return PIXMA_EINVAL; 1242141cc406Sopenharmony_ci memset (status, 0, sizeof (*status)); 1243141cc406Sopenharmony_ci return s->ops->get_status (s, status); 1244141cc406Sopenharmony_ci} 1245141cc406Sopenharmony_ci 1246141cc406Sopenharmony_ciunsigned 1247141cc406Sopenharmony_cipixma_calc_calibrate (pixma_t * p) 1248141cc406Sopenharmony_ci{ 1249141cc406Sopenharmony_ci pixma_scan_param_t * sp = p->param; 1250141cc406Sopenharmony_ci if (sp->calibrate == PIXMA_CALIBRATE_ALWAYS) 1251141cc406Sopenharmony_ci return 0x01; 1252141cc406Sopenharmony_ci if (sp->calibrate == PIXMA_CALIBRATE_NEVER) 1253141cc406Sopenharmony_ci return 0x00; 1254141cc406Sopenharmony_ci /* sp->calibrate == PIXMA_CALIBRATE_ONCE */ 1255141cc406Sopenharmony_ci if (sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) 1256141cc406Sopenharmony_ci return sp->adf_pageid == 0 ? 0x01 : 0x00; 1257141cc406Sopenharmony_ci /* sp->source == PIXMA_SOURCE_FLATBED | TPU */ 1258141cc406Sopenharmony_ci return sp->source == p->last_source ? 0x00 : 0x01; 1259141cc406Sopenharmony_ci} 1260141cc406Sopenharmony_ci 1261141cc406Sopenharmony_ci#if defined(HAVE_LIBXML2) 1262141cc406Sopenharmony_cistatic const char * 1263141cc406Sopenharmony_ciformat_xml_response(const char *resp_details) 1264141cc406Sopenharmony_ci{ 1265141cc406Sopenharmony_ci if (strcmp(resp_details, "DeviceBusy") == 0) 1266141cc406Sopenharmony_ci /* https://cromwell-intl.com/open-source/canon-pixma-printer-scanner.html */ 1267141cc406Sopenharmony_ci return "DeviceBusy - Device not initialized (yet). " \ 1268141cc406Sopenharmony_ci "Please check the USB power, try a different port or install the Ink Cartridges if the device supports them."; 1269141cc406Sopenharmony_ci else if (strcmp(resp_details, "ScannerCarriageLockError") == 0) 1270141cc406Sopenharmony_ci return "ScannerCarriageLockError - Please consult the manual to unlock the Carriage Lock."; 1271141cc406Sopenharmony_ci else if (strcmp(resp_details, "PCScanning") == 0) 1272141cc406Sopenharmony_ci return "PCScanning - Previous scan attempt was not completed. Try disconnecting and reconnecting the scanner. " \ 1273141cc406Sopenharmony_ci "If the problem persists, consider reporting it as a bug at http://www.sane-project.org/bugs.html."; 1274141cc406Sopenharmony_ci else if (strcmp(resp_details, "DeviceCheckError") == 0) 1275141cc406Sopenharmony_ci return "DeviceCheckError - Device detected a fault. Contact the repair center."; 1276141cc406Sopenharmony_ci else 1277141cc406Sopenharmony_ci return resp_details; 1278141cc406Sopenharmony_ci} 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ciint 1281141cc406Sopenharmony_cipixma_parse_xml_response(const char *xml_message) 1282141cc406Sopenharmony_ci{ 1283141cc406Sopenharmony_ci int status = PIXMA_EPROTO; 1284141cc406Sopenharmony_ci xmlDoc *doc = NULL; 1285141cc406Sopenharmony_ci xmlNode *node = NULL; 1286141cc406Sopenharmony_ci xmlChar *content = NULL; 1287141cc406Sopenharmony_ci 1288141cc406Sopenharmony_ci doc = xmlReadMemory(xml_message, strlen(xml_message), "mem:device-resp.xml", NULL, 0); 1289141cc406Sopenharmony_ci if (doc == NULL) { 1290141cc406Sopenharmony_ci PDBG(pixma_dbg(10, "unable to parse xml response\n")); 1291141cc406Sopenharmony_ci status = PIXMA_EINVAL; 1292141cc406Sopenharmony_ci goto clean; 1293141cc406Sopenharmony_ci } 1294141cc406Sopenharmony_ci 1295141cc406Sopenharmony_ci node = xmlDocGetRootElement(doc); 1296141cc406Sopenharmony_ci if (node == NULL) { 1297141cc406Sopenharmony_ci status = PIXMA_EPROTO; 1298141cc406Sopenharmony_ci goto clean; 1299141cc406Sopenharmony_ci } 1300141cc406Sopenharmony_ci 1301141cc406Sopenharmony_ci /* /cmd */ 1302141cc406Sopenharmony_ci for (; node; node = node->next) { 1303141cc406Sopenharmony_ci if (strcmp((const char*)node->name, "cmd") == 0) 1304141cc406Sopenharmony_ci break; 1305141cc406Sopenharmony_ci } 1306141cc406Sopenharmony_ci if (!node) { 1307141cc406Sopenharmony_ci status = PIXMA_EPROTO; 1308141cc406Sopenharmony_ci goto clean; 1309141cc406Sopenharmony_ci } 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_ci /* /cmd/contents */ 1312141cc406Sopenharmony_ci for (node = node->children; node; node = node->next) { 1313141cc406Sopenharmony_ci if (strcmp((const char*)node->name, "contents") == 0) 1314141cc406Sopenharmony_ci break; 1315141cc406Sopenharmony_ci } 1316141cc406Sopenharmony_ci if (!node) { 1317141cc406Sopenharmony_ci status = PIXMA_EPROTO; 1318141cc406Sopenharmony_ci goto clean; 1319141cc406Sopenharmony_ci } 1320141cc406Sopenharmony_ci 1321141cc406Sopenharmony_ci /* /cmd/contents/param_set */ 1322141cc406Sopenharmony_ci for (node = node->children; node; node = node->next) { 1323141cc406Sopenharmony_ci if (strcmp((const char*)node->name, "param_set") == 0) 1324141cc406Sopenharmony_ci break; 1325141cc406Sopenharmony_ci } 1326141cc406Sopenharmony_ci if (!node) { 1327141cc406Sopenharmony_ci status = PIXMA_EPROTO; 1328141cc406Sopenharmony_ci goto clean; 1329141cc406Sopenharmony_ci } 1330141cc406Sopenharmony_ci 1331141cc406Sopenharmony_ci /* /cmd/contents/param_set/response... */ 1332141cc406Sopenharmony_ci for (node = node->children; node; node = node->next) 1333141cc406Sopenharmony_ci { 1334141cc406Sopenharmony_ci if (strcmp((const char*)node->name, "response") == 0) { 1335141cc406Sopenharmony_ci content = xmlNodeGetContent(node); 1336141cc406Sopenharmony_ci if (strcmp((const char*)content, "OK") == 0) 1337141cc406Sopenharmony_ci status = PIXMA_STATUS_OK; 1338141cc406Sopenharmony_ci else 1339141cc406Sopenharmony_ci status = PIXMA_EINVAL; 1340141cc406Sopenharmony_ci xmlFree(content); 1341141cc406Sopenharmony_ci } else if (strcmp((const char*)node->name, "response_detail") == 0) { 1342141cc406Sopenharmony_ci content = xmlNodeGetContent(node); 1343141cc406Sopenharmony_ci if (strlen((const char*)content) > 0) { 1344141cc406Sopenharmony_ci PDBG(pixma_dbg(0, "device response: %s\n", 1345141cc406Sopenharmony_ci format_xml_response((const char*)content))); 1346141cc406Sopenharmony_ci } 1347141cc406Sopenharmony_ci xmlFree(content); 1348141cc406Sopenharmony_ci } 1349141cc406Sopenharmony_ci } 1350141cc406Sopenharmony_ci 1351141cc406Sopenharmony_ciclean: 1352141cc406Sopenharmony_ci xmlFreeDoc(doc); 1353141cc406Sopenharmony_ci return status; 1354141cc406Sopenharmony_ci} 1355141cc406Sopenharmony_ci#endif 1356