1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) 3141cc406Sopenharmony_ci 4141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 5141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License 6141cc406Sopenharmony_ci as published by the Free Software Foundation; either version 2 7141cc406Sopenharmony_ci of the License, or (at your option) any later version. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, 10141cc406Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 11141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12141cc406Sopenharmony_ci GNU General Public License for more details. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 15141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 16141cc406Sopenharmony_ci*/ 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci/* 19141cc406Sopenharmony_ci Concept for a backend for scanners based on the NIASH chipset, 20141cc406Sopenharmony_ci such as HP3300C, HP3400C, HP4300C, Agfa Touch. 21141cc406Sopenharmony_ci Parts of this source were inspired by other backends. 22141cc406Sopenharmony_ci*/ 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#include "../include/sane/config.h" 25141cc406Sopenharmony_ci#include "../include/sane/sane.h" 26141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 27141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 28141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 29141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci#include <stdlib.h> /* malloc, free */ 32141cc406Sopenharmony_ci#include <string.h> /* memcpy */ 33141cc406Sopenharmony_ci#include <stdio.h> 34141cc406Sopenharmony_ci#include <sys/time.h> 35141cc406Sopenharmony_ci#include <sys/wait.h> 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci/* definitions for debug */ 38141cc406Sopenharmony_ci#define BACKEND_NAME niash 39141cc406Sopenharmony_ci#define BUILD 1 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci#define DBG_ASSERT 1 42141cc406Sopenharmony_ci#define DBG_ERR 16 43141cc406Sopenharmony_ci#define DBG_MSG 32 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci/* Just to avoid conflicts between niash backend and testtool */ 46141cc406Sopenharmony_ci#define WITH_NIASH 1 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci/* (source) includes for data transfer methods */ 50141cc406Sopenharmony_ci#define STATIC static 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci#include "niash_core.c" 53141cc406Sopenharmony_ci#include "niash_xfer.c" 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci#define ASSERT(cond) (!(cond) ? DBG(DBG_ASSERT, "!!! ASSERT(%S) FAILED!!!\n",STRINGIFY(cond));) 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#define MM_TO_PIXEL(_mm_, _dpi_) ((_mm_) * (_dpi_) / 25.4 ) 60141cc406Sopenharmony_ci#define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_) ) 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_ci/* options enumerator */ 64141cc406Sopenharmony_citypedef enum 65141cc406Sopenharmony_ci{ 66141cc406Sopenharmony_ci optCount = 0, 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci optGroupGeometry, 69141cc406Sopenharmony_ci optTLX, optTLY, optBRX, optBRY, 70141cc406Sopenharmony_ci optDPI, 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci optGroupImage, 73141cc406Sopenharmony_ci optGammaTable, /* gamma table */ 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci optGroupMode, 76141cc406Sopenharmony_ci optMode, 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_ci optGroupEnhancement, 79141cc406Sopenharmony_ci optThreshold, 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 82141cc406Sopenharmony_ci optGroupMisc, 83141cc406Sopenharmony_ci optLamp, 84141cc406Sopenharmony_ci 85141cc406Sopenharmony_ci optCalibrate, 86141cc406Sopenharmony_ci optGamma, /* analog gamma = single number */ 87141cc406Sopenharmony_ci#endif 88141cc406Sopenharmony_ci optLast 89141cc406Sopenharmony_ci} EOptionIndex; 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci 92141cc406Sopenharmony_citypedef union 93141cc406Sopenharmony_ci{ 94141cc406Sopenharmony_ci SANE_Word w; 95141cc406Sopenharmony_ci SANE_Word *wa; /* word array */ 96141cc406Sopenharmony_ci SANE_String s; 97141cc406Sopenharmony_ci} TOptionValue; 98141cc406Sopenharmony_ci 99141cc406Sopenharmony_ci#define HW_GAMMA_SIZE 4096 100141cc406Sopenharmony_ci#define SANE_GAMMA_SIZE 4096 101141cc406Sopenharmony_ci 102141cc406Sopenharmony_citypedef struct 103141cc406Sopenharmony_ci{ 104141cc406Sopenharmony_ci SANE_Option_Descriptor aOptions[optLast]; 105141cc406Sopenharmony_ci TOptionValue aValues[optLast]; 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_ci TScanParams ScanParams; 108141cc406Sopenharmony_ci THWParams HWParams; 109141cc406Sopenharmony_ci 110141cc406Sopenharmony_ci TDataPipe DataPipe; 111141cc406Sopenharmony_ci int iLinesLeft; /* lines to scan */ 112141cc406Sopenharmony_ci int iBytesLeft; /* bytes to read */ 113141cc406Sopenharmony_ci int iPixelsPerLine; /* pixels in one scan line */ 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci SANE_Int aGammaTable[SANE_GAMMA_SIZE]; /* a 12-to-8 bit color lookup table */ 116141cc406Sopenharmony_ci 117141cc406Sopenharmony_ci /* fCancelled needed to let sane issue the cancel message 118141cc406Sopenharmony_ci instead of an error message */ 119141cc406Sopenharmony_ci SANE_Bool fCancelled; /* SANE_TRUE if scanning cancelled */ 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ci SANE_Bool fScanning; /* SANE_TRUE if actively scanning */ 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci int WarmUpTime; /* time to wait before a calibration starts */ 124141cc406Sopenharmony_ci unsigned char CalWhite[3]; /* values for the last calibration of white */ 125141cc406Sopenharmony_ci struct timeval WarmUpStarted; 126141cc406Sopenharmony_ci /* system type to trace the time elapsed */ 127141cc406Sopenharmony_ci} TScanner; 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci/* linked list of SANE_Device structures */ 131141cc406Sopenharmony_citypedef struct TDevListEntry 132141cc406Sopenharmony_ci{ 133141cc406Sopenharmony_ci struct TDevListEntry *pNext; 134141cc406Sopenharmony_ci SANE_Device dev; 135141cc406Sopenharmony_ci} TDevListEntry; 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_cistatic TDevListEntry *_pFirstSaneDev = 0; 139141cc406Sopenharmony_cistatic int iNumSaneDev = 0; 140141cc406Sopenharmony_cistatic const SANE_Device **_pSaneDevList = 0; 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_ci/* option constraints */ 144141cc406Sopenharmony_cistatic const SANE_Range rangeGammaTable = { 0, 255, 1 }; 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci/* available scanner resolutions */ 147141cc406Sopenharmony_cistatic const SANE_Int setResolutions[] = { 4, 75, 150, 300, 600 }; 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 150141cc406Sopenharmony_ci/* range of an analog gamma */ 151141cc406Sopenharmony_cistatic const SANE_Range rangeGamma = { SANE_FIX (0.25), SANE_FIX (4.0), 152141cc406Sopenharmony_ci SANE_FIX (0.0) 153141cc406Sopenharmony_ci}; 154141cc406Sopenharmony_ci#endif 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci/* interpolate a sane gamma table to a hardware appropriate one 157141cc406Sopenharmony_ci just in case the sane gamma table would be smaller */ 158141cc406Sopenharmony_cistatic void 159141cc406Sopenharmony_ci_ConvertGammaTable (SANE_Word * saneGamma, unsigned char *hwGamma) 160141cc406Sopenharmony_ci{ 161141cc406Sopenharmony_ci int i; 162141cc406Sopenharmony_ci int current = 0; 163141cc406Sopenharmony_ci for (i = 0; i < SANE_GAMMA_SIZE; ++i) 164141cc406Sopenharmony_ci { 165141cc406Sopenharmony_ci int j; 166141cc406Sopenharmony_ci int next; 167141cc406Sopenharmony_ci 168141cc406Sopenharmony_ci /* highest range of copy indices */ 169141cc406Sopenharmony_ci next = ((i + 1) * HW_GAMMA_SIZE) / SANE_GAMMA_SIZE; 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_ci /* always copy the first */ 172141cc406Sopenharmony_ci hwGamma[current] = saneGamma[i]; 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci /* the interpolation of the rest depends on the gap */ 175141cc406Sopenharmony_ci for (j = current + 1; j < HW_GAMMA_SIZE && j < next; ++j) 176141cc406Sopenharmony_ci { 177141cc406Sopenharmony_ci hwGamma[j] = 178141cc406Sopenharmony_ci (saneGamma[i] * (next - j) + 179141cc406Sopenharmony_ci saneGamma[i + 1] * (j - current)) / (next - current); 180141cc406Sopenharmony_ci } 181141cc406Sopenharmony_ci current = next; 182141cc406Sopenharmony_ci } 183141cc406Sopenharmony_ci} 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_ci/* create a unity gamma table */ 186141cc406Sopenharmony_cistatic void 187141cc406Sopenharmony_ci_UnityGammaTable (unsigned char *hwGamma) 188141cc406Sopenharmony_ci{ 189141cc406Sopenharmony_ci int i; 190141cc406Sopenharmony_ci for (i = 0; i < HW_GAMMA_SIZE; ++i) 191141cc406Sopenharmony_ci { 192141cc406Sopenharmony_ci hwGamma[i] = (i * 256) / HW_GAMMA_SIZE; 193141cc406Sopenharmony_ci } 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci} 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_cistatic const SANE_Range rangeXmm = { 0, 220, 1 }; 198141cc406Sopenharmony_cistatic const SANE_Range rangeYmm = { 0, 297, 1 }; 199141cc406Sopenharmony_cistatic const SANE_Int startUpGamma = SANE_FIX (1.6); 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_cistatic const char colorStr[] = { SANE_VALUE_SCAN_MODE_COLOR }; 202141cc406Sopenharmony_cistatic const char grayStr[] = { SANE_VALUE_SCAN_MODE_GRAY }; 203141cc406Sopenharmony_cistatic const char lineartStr[] = { SANE_VALUE_SCAN_MODE_LINEART }; 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci#define DEPTH_LINEART 1 206141cc406Sopenharmony_ci#define DEPTH_GRAY 8 207141cc406Sopenharmony_ci#define DEPTH_COLOR 8 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci#define BYTES_PER_PIXEL_GRAY 1 210141cc406Sopenharmony_ci#define BYTES_PER_PIXEL_COLOR 3 211141cc406Sopenharmony_ci 212141cc406Sopenharmony_ci#define BITS_PER_PIXEL_LINEART 1 213141cc406Sopenharmony_ci#define BITS_PER_PIXEL_GRAY DEPTH_GRAY 214141cc406Sopenharmony_ci#define BITS_PER_PIXEL_COLOR (DEPTH_COLOR*3) 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_ci#define BITS_PER_BYTE 8 217141cc406Sopenharmony_ci#define BITS_PADDING (BITS_PER_BYTE-1) 218141cc406Sopenharmony_ci 219141cc406Sopenharmony_ci#define MODE_COLOR 0 220141cc406Sopenharmony_ci#define MODE_GRAY 1 221141cc406Sopenharmony_ci#define MODE_LINEART 2 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci/* lineart threshold range */ 224141cc406Sopenharmony_cistatic const SANE_Range rangeThreshold = { 225141cc406Sopenharmony_ci 0, 226141cc406Sopenharmony_ci 100, 227141cc406Sopenharmony_ci 1 228141cc406Sopenharmony_ci}; 229141cc406Sopenharmony_ci 230141cc406Sopenharmony_ci/* scanning modes */ 231141cc406Sopenharmony_cistatic SANE_String_Const modeList[] = { 232141cc406Sopenharmony_ci colorStr, 233141cc406Sopenharmony_ci grayStr, 234141cc406Sopenharmony_ci lineartStr, 235141cc406Sopenharmony_ci NULL 236141cc406Sopenharmony_ci}; 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_cistatic int 239141cc406Sopenharmony_ci_bytesPerLineLineart (int pixelsPerLine) 240141cc406Sopenharmony_ci{ 241141cc406Sopenharmony_ci return (pixelsPerLine * BITS_PER_PIXEL_LINEART + 242141cc406Sopenharmony_ci BITS_PADDING) / BITS_PER_BYTE; 243141cc406Sopenharmony_ci} 244141cc406Sopenharmony_ci 245141cc406Sopenharmony_cistatic int 246141cc406Sopenharmony_ci_bytesPerLineGray (int pixelsPerLine) 247141cc406Sopenharmony_ci{ 248141cc406Sopenharmony_ci return (pixelsPerLine * BITS_PER_PIXEL_GRAY + BITS_PADDING) / BITS_PER_BYTE; 249141cc406Sopenharmony_ci} 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_cistatic int 252141cc406Sopenharmony_ci_bytesPerLineColor (int pixelsPerLine) 253141cc406Sopenharmony_ci{ 254141cc406Sopenharmony_ci return (pixelsPerLine * BITS_PER_PIXEL_COLOR + 255141cc406Sopenharmony_ci BITS_PADDING) / BITS_PER_BYTE; 256141cc406Sopenharmony_ci} 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci/* dummy*/ 260141cc406Sopenharmony_cistatic void 261141cc406Sopenharmony_ci_rgb2rgb (unsigned char __sane_unused__ *buffer, int __sane_unused__ pixels, int __sane_unused__ threshold) 262141cc406Sopenharmony_ci{ 263141cc406Sopenharmony_ci /* make the compiler content */ 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci/* convert 24bit RGB to 8bit GRAY */ 268141cc406Sopenharmony_cistatic void 269141cc406Sopenharmony_ci_rgb2gray (unsigned char *buffer, int pixels, int __sane_unused__ threshold) 270141cc406Sopenharmony_ci{ 271141cc406Sopenharmony_ci#define WEIGHT_R 27 272141cc406Sopenharmony_ci#define WEIGHT_G 54 273141cc406Sopenharmony_ci#define WEIGHT_B 19 274141cc406Sopenharmony_ci#define WEIGHT_W (WEIGHT_R + WEIGHT_G + WEIGHT_B) 275141cc406Sopenharmony_ci static int aWeight[BYTES_PER_PIXEL_COLOR] = 276141cc406Sopenharmony_ci { WEIGHT_R, WEIGHT_G, WEIGHT_B }; 277141cc406Sopenharmony_ci int nbyte = pixels * BYTES_PER_PIXEL_COLOR; 278141cc406Sopenharmony_ci int acc = 0; 279141cc406Sopenharmony_ci int x; 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_ci for (x = 0; x < nbyte; ++x) 282141cc406Sopenharmony_ci { 283141cc406Sopenharmony_ci acc += aWeight[x % BYTES_PER_PIXEL_COLOR] * buffer[x]; 284141cc406Sopenharmony_ci if ((x + 1) % BYTES_PER_PIXEL_COLOR == 0) 285141cc406Sopenharmony_ci { 286141cc406Sopenharmony_ci buffer[x / BYTES_PER_PIXEL_COLOR] = 287141cc406Sopenharmony_ci (unsigned char) (acc / WEIGHT_W); 288141cc406Sopenharmony_ci acc = 0; 289141cc406Sopenharmony_ci } 290141cc406Sopenharmony_ci } 291141cc406Sopenharmony_ci#undef WEIGHT_R 292141cc406Sopenharmony_ci#undef WEIGHT_G 293141cc406Sopenharmony_ci#undef WEIGHT_B 294141cc406Sopenharmony_ci#undef WEIGHT_W 295141cc406Sopenharmony_ci} 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci/* convert 24bit RGB to 1bit B/W */ 298141cc406Sopenharmony_cistatic void 299141cc406Sopenharmony_ci_rgb2lineart (unsigned char *buffer, int pixels, int threshold) 300141cc406Sopenharmony_ci{ 301141cc406Sopenharmony_ci static const int aMask[BITS_PER_BYTE] = { 128, 64, 32, 16, 8, 4, 2, 1 }; 302141cc406Sopenharmony_ci int acc = 0; 303141cc406Sopenharmony_ci int nx; 304141cc406Sopenharmony_ci int x; 305141cc406Sopenharmony_ci int thresh; 306141cc406Sopenharmony_ci _rgb2gray (buffer, pixels, 0); 307141cc406Sopenharmony_ci nx = ((pixels + BITS_PADDING) / BITS_PER_BYTE) * BITS_PER_BYTE; 308141cc406Sopenharmony_ci thresh = 255 * threshold / rangeThreshold.max; 309141cc406Sopenharmony_ci for (x = 0; x < nx; ++x) 310141cc406Sopenharmony_ci { 311141cc406Sopenharmony_ci if (x < pixels && buffer[x] < thresh) 312141cc406Sopenharmony_ci { 313141cc406Sopenharmony_ci acc |= aMask[x % BITS_PER_BYTE]; 314141cc406Sopenharmony_ci } 315141cc406Sopenharmony_ci if ((x + 1) % BITS_PER_BYTE == 0) 316141cc406Sopenharmony_ci { 317141cc406Sopenharmony_ci buffer[x / BITS_PER_BYTE] = (unsigned char) (acc); 318141cc406Sopenharmony_ci acc = 0; 319141cc406Sopenharmony_ci } 320141cc406Sopenharmony_ci } 321141cc406Sopenharmony_ci} 322141cc406Sopenharmony_ci 323141cc406Sopenharmony_citypedef struct tgModeParam 324141cc406Sopenharmony_ci{ 325141cc406Sopenharmony_ci SANE_Int depth; 326141cc406Sopenharmony_ci SANE_Frame format; 327141cc406Sopenharmony_ci int (*bytesPerLine) (int pixelsPerLine); 328141cc406Sopenharmony_ci void (*adaptFormat) (unsigned char *rgbBuffer, int pixels, int threshold); 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci} TModeParam; 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_cistatic const TModeParam modeParam[] = { 333141cc406Sopenharmony_ci {DEPTH_COLOR, SANE_FRAME_RGB, _bytesPerLineColor, _rgb2rgb}, 334141cc406Sopenharmony_ci {DEPTH_GRAY, SANE_FRAME_GRAY, _bytesPerLineGray, _rgb2gray}, 335141cc406Sopenharmony_ci {DEPTH_LINEART, SANE_FRAME_GRAY, _bytesPerLineLineart, _rgb2lineart} 336141cc406Sopenharmony_ci}; 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci#define WARMUP_AFTERSTART 1 /* flag for 1st warm up */ 340141cc406Sopenharmony_ci#define WARMUP_INSESSION 0 341141cc406Sopenharmony_ci#define WARMUP_TESTINTERVAL 15 /* test every 15sec */ 342141cc406Sopenharmony_ci#define WARMUP_TIME 30 /* first wait is 30sec minimum */ 343141cc406Sopenharmony_ci#define WARMUP_MAXTIME 90 /* after one and a half minute start latest */ 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci#define CAL_DEV_MAX 15 346141cc406Sopenharmony_ci/* maximum deviation of cal values in percent between 2 tests */ 347141cc406Sopenharmony_ci 348141cc406Sopenharmony_ci/* different warm up after start and after automatic off */ 349141cc406Sopenharmony_cistatic const int aiWarmUpTime[] = { WARMUP_TESTINTERVAL, WARMUP_TIME }; 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci/* returns 1, when the warm up time "iTime" has elasped */ 354141cc406Sopenharmony_cistatic int 355141cc406Sopenharmony_ci_TimeElapsed (struct timeval *start, struct timeval *now, int iTime) 356141cc406Sopenharmony_ci{ 357141cc406Sopenharmony_ci 358141cc406Sopenharmony_ci /* this is a bit strange, but can deal with overflows */ 359141cc406Sopenharmony_ci if (start->tv_sec > now->tv_sec) 360141cc406Sopenharmony_ci return (start->tv_sec / 2 - now->tv_sec / 2 > iTime / 2); 361141cc406Sopenharmony_ci else 362141cc406Sopenharmony_ci return (now->tv_sec - start->tv_sec >= iTime); 363141cc406Sopenharmony_ci} 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_cistatic void 366141cc406Sopenharmony_ci_WarmUpLamp (TScanner * s, int iMode) 367141cc406Sopenharmony_ci{ 368141cc406Sopenharmony_ci SANE_Bool fLampOn; 369141cc406Sopenharmony_ci /* on startup don't care what was before 370141cc406Sopenharmony_ci assume lamp was off, and the previous 371141cc406Sopenharmony_ci cal values can never be reached */ 372141cc406Sopenharmony_ci if (iMode == WARMUP_AFTERSTART) 373141cc406Sopenharmony_ci { 374141cc406Sopenharmony_ci fLampOn = SANE_FALSE; 375141cc406Sopenharmony_ci s->CalWhite[0] = s->CalWhite[1] = s->CalWhite[2] = (unsigned char) (-1); 376141cc406Sopenharmony_ci } 377141cc406Sopenharmony_ci else 378141cc406Sopenharmony_ci GetLamp (&s->HWParams, &fLampOn); 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci if (!fLampOn) 381141cc406Sopenharmony_ci { 382141cc406Sopenharmony_ci /* get the current system time */ 383141cc406Sopenharmony_ci gettimeofday (&s->WarmUpStarted, 0); 384141cc406Sopenharmony_ci /* determine the time to wait at least */ 385141cc406Sopenharmony_ci s->WarmUpTime = aiWarmUpTime[iMode]; 386141cc406Sopenharmony_ci /* switch on the lamp */ 387141cc406Sopenharmony_ci SetLamp (&s->HWParams, SANE_TRUE); 388141cc406Sopenharmony_ci } 389141cc406Sopenharmony_ci} 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_cistatic void 392141cc406Sopenharmony_ci_WaitForLamp (TScanner * s, unsigned char *pabCalibTable) 393141cc406Sopenharmony_ci{ 394141cc406Sopenharmony_ci struct timeval now[2]; /* toggling time holder */ 395141cc406Sopenharmony_ci int i; /* rgb loop */ 396141cc406Sopenharmony_ci int iCal = 0; /* counter */ 397141cc406Sopenharmony_ci int iCurrent = 0; /* buffer and time-holder swap flag */ 398141cc406Sopenharmony_ci SANE_Bool fHasCal; 399141cc406Sopenharmony_ci unsigned char CalWhite[2][3]; /* toggling buffer */ 400141cc406Sopenharmony_ci int iDelay = 0; /* delay loop counter */ 401141cc406Sopenharmony_ci _WarmUpLamp (s, SANE_FALSE); 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci 404141cc406Sopenharmony_ci /* get the time stamp for the wait loops */ 405141cc406Sopenharmony_ci if (s->WarmUpTime) 406141cc406Sopenharmony_ci gettimeofday (&now[iCurrent], 0); 407141cc406Sopenharmony_ci SimpleCalibExt (&s->HWParams, pabCalibTable, CalWhite[iCurrent]); 408141cc406Sopenharmony_ci fHasCal = SANE_TRUE; 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci DBG (DBG_MSG, "_WaitForLamp: first calibration\n"); 411141cc406Sopenharmony_ci 412141cc406Sopenharmony_ci 413141cc406Sopenharmony_ci /* wait until time has elapsed or for values to stabilze */ 414141cc406Sopenharmony_ci while (s->WarmUpTime) 415141cc406Sopenharmony_ci { 416141cc406Sopenharmony_ci /* check if the last scan has lower calibration values than 417141cc406Sopenharmony_ci the current one would have */ 418141cc406Sopenharmony_ci if (s->WarmUpTime && fHasCal) 419141cc406Sopenharmony_ci { 420141cc406Sopenharmony_ci SANE_Bool fOver = SANE_TRUE; 421141cc406Sopenharmony_ci for (i = 0; fOver && i < 3; ++i) 422141cc406Sopenharmony_ci { 423141cc406Sopenharmony_ci if (!s->CalWhite[i]) 424141cc406Sopenharmony_ci fOver = SANE_FALSE; 425141cc406Sopenharmony_ci else if (CalWhite[iCurrent][i] < s->CalWhite[i]) 426141cc406Sopenharmony_ci fOver = SANE_FALSE; 427141cc406Sopenharmony_ci } 428141cc406Sopenharmony_ci 429141cc406Sopenharmony_ci /* warm up is not needed, when calibration data is above 430141cc406Sopenharmony_ci the calibration data of the last scan */ 431141cc406Sopenharmony_ci if (fOver) 432141cc406Sopenharmony_ci { 433141cc406Sopenharmony_ci s->WarmUpTime = 0; 434141cc406Sopenharmony_ci DBG (DBG_MSG, 435141cc406Sopenharmony_ci "_WaitForLamp: Values seem stable, skipping next calibration cycle\n"); 436141cc406Sopenharmony_ci } 437141cc406Sopenharmony_ci } 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci 440141cc406Sopenharmony_ci /* break the loop, when the longest wait time has expired 441141cc406Sopenharmony_ci to prevent a hanging application, 442141cc406Sopenharmony_ci even if the values might not be good, yet */ 443141cc406Sopenharmony_ci if (s->WarmUpTime && fHasCal && iCal) 444141cc406Sopenharmony_ci { 445141cc406Sopenharmony_ci /* abort, when we have waited long enough */ 446141cc406Sopenharmony_ci if (_TimeElapsed 447141cc406Sopenharmony_ci (&s->WarmUpStarted, &now[iCurrent], WARMUP_MAXTIME)) 448141cc406Sopenharmony_ci { 449141cc406Sopenharmony_ci /* stop idling */ 450141cc406Sopenharmony_ci s->WarmUpTime = 0; 451141cc406Sopenharmony_ci DBG (DBG_MSG, "_WaitForLamp: WARMUP_MAXTIME=%ds elapsed!\n", 452141cc406Sopenharmony_ci WARMUP_MAXTIME); 453141cc406Sopenharmony_ci } 454141cc406Sopenharmony_ci } 455141cc406Sopenharmony_ci 456141cc406Sopenharmony_ci 457141cc406Sopenharmony_ci /* enter a delay loop, when there is still time to wait */ 458141cc406Sopenharmony_ci if (s->WarmUpTime) 459141cc406Sopenharmony_ci { 460141cc406Sopenharmony_ci /* if the (too low) calibration values have just been acquired 461141cc406Sopenharmony_ci we start waiting */ 462141cc406Sopenharmony_ci if (fHasCal) 463141cc406Sopenharmony_ci DBG (DBG_MSG, "_WaitForLamp: entering delay loop\r"); 464141cc406Sopenharmony_ci else 465141cc406Sopenharmony_ci DBG (DBG_MSG, "_WaitForLamp: delay loop %d \r", ++iDelay); 466141cc406Sopenharmony_ci sleep (1); 467141cc406Sopenharmony_ci fHasCal = SANE_FALSE; 468141cc406Sopenharmony_ci gettimeofday (&now[!iCurrent], 0); 469141cc406Sopenharmony_ci } 470141cc406Sopenharmony_ci 471141cc406Sopenharmony_ci 472141cc406Sopenharmony_ci /* look if we should check again */ 473141cc406Sopenharmony_ci if (s->WarmUpTime /* did we have to wait at all */ 474141cc406Sopenharmony_ci /* is the minimum time elapsed */ 475141cc406Sopenharmony_ci && _TimeElapsed (&s->WarmUpStarted, &now[!iCurrent], s->WarmUpTime) 476141cc406Sopenharmony_ci /* has the minimum time elapsed since the last calibration */ 477141cc406Sopenharmony_ci && _TimeElapsed (&now[iCurrent], &now[!iCurrent], 478141cc406Sopenharmony_ci WARMUP_TESTINTERVAL)) 479141cc406Sopenharmony_ci { 480141cc406Sopenharmony_ci int dev = 0; /* 0 percent deviation in cal value as default */ 481141cc406Sopenharmony_ci iDelay = 0; /* all delays processed */ 482141cc406Sopenharmony_ci /* new calibration */ 483141cc406Sopenharmony_ci ++iCal; 484141cc406Sopenharmony_ci iCurrent = !iCurrent; /* swap the test-buffer, and time-holder */ 485141cc406Sopenharmony_ci SimpleCalibExt (&s->HWParams, pabCalibTable, CalWhite[iCurrent]); 486141cc406Sopenharmony_ci fHasCal = SANE_TRUE; 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 489141cc406Sopenharmony_ci { 490141cc406Sopenharmony_ci /* copy for faster and clearer access */ 491141cc406Sopenharmony_ci int cwa; 492141cc406Sopenharmony_ci int cwb; 493141cc406Sopenharmony_ci int ldev; 494141cc406Sopenharmony_ci cwa = CalWhite[!iCurrent][i]; 495141cc406Sopenharmony_ci cwb = CalWhite[iCurrent][i]; 496141cc406Sopenharmony_ci /* find the biggest deviation of one color */ 497141cc406Sopenharmony_ci if (cwa > cwb) 498141cc406Sopenharmony_ci ldev = 0; 499141cc406Sopenharmony_ci else if (cwa && cwb) 500141cc406Sopenharmony_ci ldev = ((cwb - cwa) * 100) / cwb; 501141cc406Sopenharmony_ci else 502141cc406Sopenharmony_ci ldev = 100; 503141cc406Sopenharmony_ci dev = MAX (dev, ldev); 504141cc406Sopenharmony_ci } 505141cc406Sopenharmony_ci 506141cc406Sopenharmony_ci /* show the biggest deviation of the calibration values */ 507141cc406Sopenharmony_ci DBG (DBG_MSG, "_WaitForLamp: recalibration #%d, deviation = %d%%\n", 508141cc406Sopenharmony_ci iCal, dev); 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci /* the deviation to the previous calibration is tolerable */ 511141cc406Sopenharmony_ci if (dev <= CAL_DEV_MAX) 512141cc406Sopenharmony_ci s->WarmUpTime = 0; 513141cc406Sopenharmony_ci } 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci 516141cc406Sopenharmony_ci /* remember the values of this calibration 517141cc406Sopenharmony_ci for the next time */ 518141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 519141cc406Sopenharmony_ci { 520141cc406Sopenharmony_ci s->CalWhite[i] = CalWhite[iCurrent][i]; 521141cc406Sopenharmony_ci } 522141cc406Sopenharmony_ci} 523141cc406Sopenharmony_ci 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci/* used, when setting gamma as 1 value */ 526141cc406Sopenharmony_cistatic void 527141cc406Sopenharmony_ci_SetScalarGamma (SANE_Int * aiGamma, SANE_Int sfGamma) 528141cc406Sopenharmony_ci{ 529141cc406Sopenharmony_ci int j; 530141cc406Sopenharmony_ci double fGamma; 531141cc406Sopenharmony_ci fGamma = SANE_UNFIX (sfGamma); 532141cc406Sopenharmony_ci for (j = 0; j < SANE_GAMMA_SIZE; j++) 533141cc406Sopenharmony_ci { 534141cc406Sopenharmony_ci int iData; 535141cc406Sopenharmony_ci iData = 536141cc406Sopenharmony_ci floor (256.0 * 537141cc406Sopenharmony_ci pow (((double) j / (double) SANE_GAMMA_SIZE), 1.0 / fGamma)); 538141cc406Sopenharmony_ci if (iData > 255) 539141cc406Sopenharmony_ci iData = 255; 540141cc406Sopenharmony_ci aiGamma[j] = iData; 541141cc406Sopenharmony_ci } 542141cc406Sopenharmony_ci} 543141cc406Sopenharmony_ci 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci/* return size of longest string in a string list */ 546141cc406Sopenharmony_cistatic size_t 547141cc406Sopenharmony_ci_MaxStringSize (const SANE_String_Const strings[]) 548141cc406Sopenharmony_ci{ 549141cc406Sopenharmony_ci size_t size, max_size = 0; 550141cc406Sopenharmony_ci int i; 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) 553141cc406Sopenharmony_ci { 554141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 555141cc406Sopenharmony_ci if (size > max_size) 556141cc406Sopenharmony_ci max_size = size; 557141cc406Sopenharmony_ci } 558141cc406Sopenharmony_ci return max_size; 559141cc406Sopenharmony_ci} 560141cc406Sopenharmony_ci 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci/* change a sane cap and return true, when a change took place */ 563141cc406Sopenharmony_cistatic int 564141cc406Sopenharmony_ci_ChangeCap (SANE_Word * pCap, SANE_Word cap, int isSet) 565141cc406Sopenharmony_ci{ 566141cc406Sopenharmony_ci SANE_Word prevCap = *pCap; 567141cc406Sopenharmony_ci if (isSet) 568141cc406Sopenharmony_ci { 569141cc406Sopenharmony_ci *pCap |= cap; 570141cc406Sopenharmony_ci } 571141cc406Sopenharmony_ci else 572141cc406Sopenharmony_ci { 573141cc406Sopenharmony_ci *pCap &= ~cap; 574141cc406Sopenharmony_ci } 575141cc406Sopenharmony_ci return *pCap != prevCap; 576141cc406Sopenharmony_ci} 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_cistatic void 580141cc406Sopenharmony_ci_InitOptions (TScanner * s) 581141cc406Sopenharmony_ci{ 582141cc406Sopenharmony_ci int i; 583141cc406Sopenharmony_ci SANE_Option_Descriptor *pDesc; 584141cc406Sopenharmony_ci TOptionValue *pVal; 585141cc406Sopenharmony_ci _SetScalarGamma (s->aGammaTable, startUpGamma); 586141cc406Sopenharmony_ci 587141cc406Sopenharmony_ci for (i = optCount; i < optLast; i++) 588141cc406Sopenharmony_ci { 589141cc406Sopenharmony_ci 590141cc406Sopenharmony_ci pDesc = &s->aOptions[i]; 591141cc406Sopenharmony_ci pVal = &s->aValues[i]; 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci /* defaults */ 594141cc406Sopenharmony_ci pDesc->name = ""; 595141cc406Sopenharmony_ci pDesc->title = ""; 596141cc406Sopenharmony_ci pDesc->desc = ""; 597141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_INT; 598141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_NONE; 599141cc406Sopenharmony_ci pDesc->size = sizeof (SANE_Word); 600141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_NONE; 601141cc406Sopenharmony_ci pDesc->cap = 0; 602141cc406Sopenharmony_ci 603141cc406Sopenharmony_ci switch (i) 604141cc406Sopenharmony_ci { 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci case optCount: 607141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_NUM_OPTIONS; 608141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_NUM_OPTIONS; 609141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_DETECT; 610141cc406Sopenharmony_ci pVal->w = (SANE_Word) optLast; 611141cc406Sopenharmony_ci break; 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ci case optGroupGeometry: 614141cc406Sopenharmony_ci pDesc->title = "Geometry"; 615141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_GROUP; 616141cc406Sopenharmony_ci pDesc->size = 0; 617141cc406Sopenharmony_ci break; 618141cc406Sopenharmony_ci 619141cc406Sopenharmony_ci case optTLX: 620141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_TL_X; 621141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_TL_X; 622141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_TL_X; 623141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_MM; 624141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 625141cc406Sopenharmony_ci pDesc->constraint.range = &rangeXmm; 626141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 627141cc406Sopenharmony_ci pVal->w = rangeXmm.min; 628141cc406Sopenharmony_ci break; 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci case optTLY: 631141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_TL_Y; 632141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_TL_Y; 633141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_TL_Y; 634141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_MM; 635141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 636141cc406Sopenharmony_ci pDesc->constraint.range = &rangeYmm; 637141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 638141cc406Sopenharmony_ci pVal->w = rangeYmm.min; 639141cc406Sopenharmony_ci break; 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ci case optBRX: 642141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_BR_X; 643141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_BR_X; 644141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_BR_X; 645141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_MM; 646141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 647141cc406Sopenharmony_ci pDesc->constraint.range = &rangeXmm; 648141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 649141cc406Sopenharmony_ci pVal->w = 210 /* A4 width instead of rangeXmm.max */ ; 650141cc406Sopenharmony_ci break; 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci case optBRY: 653141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_BR_Y; 654141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_BR_Y; 655141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_BR_Y; 656141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_MM; 657141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 658141cc406Sopenharmony_ci pDesc->constraint.range = &rangeYmm; 659141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 660141cc406Sopenharmony_ci pVal->w = 290 /* have a bit reserve instead of rangeYmm.max */ ; 661141cc406Sopenharmony_ci break; 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci case optDPI: 664141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_RESOLUTION; 665141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_RESOLUTION; 666141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_RESOLUTION; 667141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_DPI; 668141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST; 669141cc406Sopenharmony_ci pDesc->constraint.word_list = setResolutions; 670141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 671141cc406Sopenharmony_ci pVal->w = setResolutions[2]; /* default to 150dpi */ 672141cc406Sopenharmony_ci break; 673141cc406Sopenharmony_ci 674141cc406Sopenharmony_ci case optGroupImage: 675141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Image"); 676141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_GROUP; 677141cc406Sopenharmony_ci pDesc->size = 0; 678141cc406Sopenharmony_ci break; 679141cc406Sopenharmony_ci 680141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 681141cc406Sopenharmony_ci case optGamma: 682141cc406Sopenharmony_ci pDesc->name = SANE_NAME_ANALOG_GAMMA; 683141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_ANALOG_GAMMA; 684141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_ANALOG_GAMMA; 685141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_FIXED; 686141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 687141cc406Sopenharmony_ci pDesc->constraint.range = &rangeGamma; 688141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 689141cc406Sopenharmony_ci pVal->w = startUpGamma; 690141cc406Sopenharmony_ci break; 691141cc406Sopenharmony_ci#endif 692141cc406Sopenharmony_ci 693141cc406Sopenharmony_ci case optGammaTable: 694141cc406Sopenharmony_ci pDesc->name = SANE_NAME_GAMMA_VECTOR; 695141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_GAMMA_VECTOR; 696141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_GAMMA_VECTOR; 697141cc406Sopenharmony_ci pDesc->size = sizeof (s->aGammaTable); 698141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 699141cc406Sopenharmony_ci pDesc->constraint.range = &rangeGammaTable; 700141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 701141cc406Sopenharmony_ci pVal->wa = s->aGammaTable; 702141cc406Sopenharmony_ci break; 703141cc406Sopenharmony_ci 704141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 705141cc406Sopenharmony_ci case optGroupMisc: 706141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Miscellaneous"); 707141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_GROUP; 708141cc406Sopenharmony_ci pDesc->size = 0; 709141cc406Sopenharmony_ci break; 710141cc406Sopenharmony_ci 711141cc406Sopenharmony_ci case optLamp: 712141cc406Sopenharmony_ci pDesc->name = "lamp"; 713141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Lamp status"); 714141cc406Sopenharmony_ci pDesc->desc = SANE_I18N ("Switches the lamp on or off."); 715141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_BOOL; 716141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 717141cc406Sopenharmony_ci /* switch the lamp on when starting for first the time */ 718141cc406Sopenharmony_ci pVal->w = SANE_TRUE; 719141cc406Sopenharmony_ci break; 720141cc406Sopenharmony_ci 721141cc406Sopenharmony_ci case optCalibrate: 722141cc406Sopenharmony_ci pDesc->name = "calibrate"; 723141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Calibrate"); 724141cc406Sopenharmony_ci pDesc->desc = SANE_I18N ("Calibrates for black and white level."); 725141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_BUTTON; 726141cc406Sopenharmony_ci pDesc->cap = SANE_CAP_SOFT_SELECT; 727141cc406Sopenharmony_ci pDesc->size = 0; 728141cc406Sopenharmony_ci break; 729141cc406Sopenharmony_ci#endif 730141cc406Sopenharmony_ci case optGroupMode: 731141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Scan Mode"); 732141cc406Sopenharmony_ci pDesc->desc = ""; 733141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_GROUP; 734141cc406Sopenharmony_ci break; 735141cc406Sopenharmony_ci 736141cc406Sopenharmony_ci case optMode: 737141cc406Sopenharmony_ci /* scan mode */ 738141cc406Sopenharmony_ci pDesc->name = SANE_NAME_SCAN_MODE; 739141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_SCAN_MODE; 740141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_SCAN_MODE; 741141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_STRING; 742141cc406Sopenharmony_ci pDesc->size = _MaxStringSize (modeList); 743141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST; 744141cc406Sopenharmony_ci pDesc->constraint.string_list = modeList; 745141cc406Sopenharmony_ci pDesc->cap = 746141cc406Sopenharmony_ci SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_EMULATED; 747141cc406Sopenharmony_ci pVal->w = MODE_COLOR; 748141cc406Sopenharmony_ci break; 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci case optGroupEnhancement: 751141cc406Sopenharmony_ci pDesc->title = SANE_I18N ("Enhancement"); 752141cc406Sopenharmony_ci pDesc->desc = ""; 753141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_GROUP; 754141cc406Sopenharmony_ci break; 755141cc406Sopenharmony_ci 756141cc406Sopenharmony_ci case optThreshold: 757141cc406Sopenharmony_ci pDesc->name = SANE_NAME_THRESHOLD; 758141cc406Sopenharmony_ci pDesc->title = SANE_TITLE_THRESHOLD; 759141cc406Sopenharmony_ci pDesc->desc = SANE_DESC_THRESHOLD; 760141cc406Sopenharmony_ci pDesc->type = SANE_TYPE_INT; 761141cc406Sopenharmony_ci pDesc->unit = SANE_UNIT_PERCENT; 762141cc406Sopenharmony_ci pDesc->constraint_type = SANE_CONSTRAINT_RANGE; 763141cc406Sopenharmony_ci pDesc->constraint.range = &rangeThreshold; 764141cc406Sopenharmony_ci pDesc->cap = 765141cc406Sopenharmony_ci SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE | 766141cc406Sopenharmony_ci SANE_CAP_EMULATED; 767141cc406Sopenharmony_ci pVal->w = 50; 768141cc406Sopenharmony_ci break; 769141cc406Sopenharmony_ci 770141cc406Sopenharmony_ci default: 771141cc406Sopenharmony_ci DBG (DBG_ERR, "Uninitialised option %d\n", i); 772141cc406Sopenharmony_ci break; 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci } 775141cc406Sopenharmony_ci} 776141cc406Sopenharmony_ci 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_cistatic int 779141cc406Sopenharmony_ci_ReportDevice (TScannerModel * pModel, const char *pszDeviceName) 780141cc406Sopenharmony_ci{ 781141cc406Sopenharmony_ci TDevListEntry *pNew, *pDev; 782141cc406Sopenharmony_ci 783141cc406Sopenharmony_ci DBG (DBG_MSG, "niash: _ReportDevice '%s'\n", pszDeviceName); 784141cc406Sopenharmony_ci 785141cc406Sopenharmony_ci pNew = malloc (sizeof (TDevListEntry)); 786141cc406Sopenharmony_ci if (!pNew) 787141cc406Sopenharmony_ci { 788141cc406Sopenharmony_ci DBG (DBG_ERR, "no mem\n"); 789141cc406Sopenharmony_ci return -1; 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci 792141cc406Sopenharmony_ci /* add new element to the end of the list */ 793141cc406Sopenharmony_ci if (_pFirstSaneDev == 0) 794141cc406Sopenharmony_ci { 795141cc406Sopenharmony_ci _pFirstSaneDev = pNew; 796141cc406Sopenharmony_ci } 797141cc406Sopenharmony_ci else 798141cc406Sopenharmony_ci { 799141cc406Sopenharmony_ci for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext) 800141cc406Sopenharmony_ci { 801141cc406Sopenharmony_ci ; 802141cc406Sopenharmony_ci } 803141cc406Sopenharmony_ci pDev->pNext = pNew; 804141cc406Sopenharmony_ci } 805141cc406Sopenharmony_ci 806141cc406Sopenharmony_ci /* fill in new element */ 807141cc406Sopenharmony_ci pNew->pNext = 0; 808141cc406Sopenharmony_ci pNew->dev.name = strdup (pszDeviceName); 809141cc406Sopenharmony_ci pNew->dev.vendor = pModel->pszVendor; 810141cc406Sopenharmony_ci pNew->dev.model = pModel->pszName; 811141cc406Sopenharmony_ci pNew->dev.type = "flatbed scanner"; 812141cc406Sopenharmony_ci 813141cc406Sopenharmony_ci iNumSaneDev++; 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci return 0; 816141cc406Sopenharmony_ci} 817141cc406Sopenharmony_ci 818141cc406Sopenharmony_ci 819141cc406Sopenharmony_ci 820141cc406Sopenharmony_ci/*****************************************************************************/ 821141cc406Sopenharmony_ci 822141cc406Sopenharmony_ciSANE_Status 823141cc406Sopenharmony_cisane_init (SANE_Int * piVersion, SANE_Auth_Callback __sane_unused__ pfnAuth) 824141cc406Sopenharmony_ci{ 825141cc406Sopenharmony_ci DBG_INIT (); 826141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_init\n"); 827141cc406Sopenharmony_ci 828141cc406Sopenharmony_ci if (piVersion != NULL) 829141cc406Sopenharmony_ci { 830141cc406Sopenharmony_ci *piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 831141cc406Sopenharmony_ci } 832141cc406Sopenharmony_ci 833141cc406Sopenharmony_ci /* initialise transfer methods */ 834141cc406Sopenharmony_ci iNumSaneDev = 0; 835141cc406Sopenharmony_ci NiashXferInit (_ReportDevice); 836141cc406Sopenharmony_ci 837141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 838141cc406Sopenharmony_ci} 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci 841141cc406Sopenharmony_civoid 842141cc406Sopenharmony_cisane_exit (void) 843141cc406Sopenharmony_ci{ 844141cc406Sopenharmony_ci TDevListEntry *pDev, *pNext; 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_exit\n"); 847141cc406Sopenharmony_ci 848141cc406Sopenharmony_ci /* free device list memory */ 849141cc406Sopenharmony_ci if (_pSaneDevList) 850141cc406Sopenharmony_ci { 851141cc406Sopenharmony_ci for (pDev = _pFirstSaneDev; pDev; pDev = pNext) 852141cc406Sopenharmony_ci { 853141cc406Sopenharmony_ci pNext = pDev->pNext; 854141cc406Sopenharmony_ci free ((void *) pDev->dev.name); 855141cc406Sopenharmony_ci free (pDev); 856141cc406Sopenharmony_ci } 857141cc406Sopenharmony_ci _pFirstSaneDev = 0; 858141cc406Sopenharmony_ci free (_pSaneDevList); 859141cc406Sopenharmony_ci _pSaneDevList = 0; 860141cc406Sopenharmony_ci } 861141cc406Sopenharmony_ci} 862141cc406Sopenharmony_ci 863141cc406Sopenharmony_ci 864141cc406Sopenharmony_ciSANE_Status 865141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only) 866141cc406Sopenharmony_ci{ 867141cc406Sopenharmony_ci TDevListEntry *pDev; 868141cc406Sopenharmony_ci int i; 869141cc406Sopenharmony_ci 870141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_get_devices\n"); 871141cc406Sopenharmony_ci 872141cc406Sopenharmony_ci if (_pSaneDevList) 873141cc406Sopenharmony_ci { 874141cc406Sopenharmony_ci free (_pSaneDevList); 875141cc406Sopenharmony_ci } 876141cc406Sopenharmony_ci 877141cc406Sopenharmony_ci _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1)); 878141cc406Sopenharmony_ci if (!_pSaneDevList) 879141cc406Sopenharmony_ci { 880141cc406Sopenharmony_ci DBG (DBG_MSG, "no mem\n"); 881141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 882141cc406Sopenharmony_ci } 883141cc406Sopenharmony_ci i = 0; 884141cc406Sopenharmony_ci for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext) 885141cc406Sopenharmony_ci { 886141cc406Sopenharmony_ci _pSaneDevList[i++] = &pDev->dev; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci _pSaneDevList[i++] = 0; /* last entry is 0 */ 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci *device_list = _pSaneDevList; 891141cc406Sopenharmony_ci 892141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 893141cc406Sopenharmony_ci} 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_ci 896141cc406Sopenharmony_ciSANE_Status 897141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * h) 898141cc406Sopenharmony_ci{ 899141cc406Sopenharmony_ci TScanner *s; 900141cc406Sopenharmony_ci 901141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_open: %s\n", name); 902141cc406Sopenharmony_ci 903141cc406Sopenharmony_ci /* check the name */ 904141cc406Sopenharmony_ci if (strlen (name) == 0) 905141cc406Sopenharmony_ci { 906141cc406Sopenharmony_ci /* default to first available device */ 907141cc406Sopenharmony_ci name = _pFirstSaneDev->dev.name; 908141cc406Sopenharmony_ci } 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_ci s = malloc (sizeof (TScanner)); 911141cc406Sopenharmony_ci if (!s) 912141cc406Sopenharmony_ci { 913141cc406Sopenharmony_ci DBG (DBG_MSG, "malloc failed\n"); 914141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 915141cc406Sopenharmony_ci } 916141cc406Sopenharmony_ci 917141cc406Sopenharmony_ci if (NiashOpen (&s->HWParams, name) < 0) 918141cc406Sopenharmony_ci { 919141cc406Sopenharmony_ci /* is this OK ? */ 920141cc406Sopenharmony_ci DBG (DBG_ERR, "NiashOpen failed\n"); 921141cc406Sopenharmony_ci free ((void *) s); 922141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 923141cc406Sopenharmony_ci } 924141cc406Sopenharmony_ci _InitOptions (s); 925141cc406Sopenharmony_ci s->fScanning = SANE_FALSE; 926141cc406Sopenharmony_ci s->fCancelled = SANE_FALSE; 927141cc406Sopenharmony_ci *h = s; 928141cc406Sopenharmony_ci 929141cc406Sopenharmony_ci /* Turn on lamp by default at startup */ 930141cc406Sopenharmony_ci _WarmUpLamp (s, WARMUP_AFTERSTART); 931141cc406Sopenharmony_ci 932141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 933141cc406Sopenharmony_ci} 934141cc406Sopenharmony_ci 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_civoid 937141cc406Sopenharmony_cisane_close (SANE_Handle h) 938141cc406Sopenharmony_ci{ 939141cc406Sopenharmony_ci TScanner *s; 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_close\n"); 942141cc406Sopenharmony_ci 943141cc406Sopenharmony_ci s = (TScanner *) h; 944141cc406Sopenharmony_ci 945141cc406Sopenharmony_ci /* turn off scanner lamp */ 946141cc406Sopenharmony_ci SetLamp (&s->HWParams, SANE_FALSE); 947141cc406Sopenharmony_ci 948141cc406Sopenharmony_ci /* close scanner */ 949141cc406Sopenharmony_ci NiashClose (&s->HWParams); 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci /* free scanner object memory */ 952141cc406Sopenharmony_ci free ((void *) s); 953141cc406Sopenharmony_ci} 954141cc406Sopenharmony_ci 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 957141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int n) 958141cc406Sopenharmony_ci{ 959141cc406Sopenharmony_ci TScanner *s; 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_get_option_descriptor %d\n", n); 962141cc406Sopenharmony_ci 963141cc406Sopenharmony_ci if ((n < optCount) || (n >= optLast)) 964141cc406Sopenharmony_ci { 965141cc406Sopenharmony_ci return NULL; 966141cc406Sopenharmony_ci } 967141cc406Sopenharmony_ci 968141cc406Sopenharmony_ci s = (TScanner *) h; 969141cc406Sopenharmony_ci return &s->aOptions[n]; 970141cc406Sopenharmony_ci} 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci 973141cc406Sopenharmony_ciSANE_Status 974141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action, 975141cc406Sopenharmony_ci void *pVal, SANE_Int * pInfo) 976141cc406Sopenharmony_ci{ 977141cc406Sopenharmony_ci TScanner *s; 978141cc406Sopenharmony_ci static char szTable[100]; 979141cc406Sopenharmony_ci int *pi; 980141cc406Sopenharmony_ci int i; 981141cc406Sopenharmony_ci SANE_Int info; 982141cc406Sopenharmony_ci SANE_Status status; 983141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 984141cc406Sopenharmony_ci SANE_Bool fLampIsOn; 985141cc406Sopenharmony_ci SANE_Bool fVal; 986141cc406Sopenharmony_ci SANE_Bool fSame; 987141cc406Sopenharmony_ci#endif 988141cc406Sopenharmony_ci 989141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_control_option: option %d, action %d\n", n, Action); 990141cc406Sopenharmony_ci 991141cc406Sopenharmony_ci if ((n < optCount) || (n >= optLast)) 992141cc406Sopenharmony_ci { 993141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci 996141cc406Sopenharmony_ci if (Action == SANE_ACTION_GET_VALUE || Action == SANE_ACTION_SET_VALUE) 997141cc406Sopenharmony_ci { 998141cc406Sopenharmony_ci if (pVal == NULL) 999141cc406Sopenharmony_ci { 1000141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1001141cc406Sopenharmony_ci } 1002141cc406Sopenharmony_ci } 1003141cc406Sopenharmony_ci 1004141cc406Sopenharmony_ci s = (TScanner *) h; 1005141cc406Sopenharmony_ci info = 0; 1006141cc406Sopenharmony_ci 1007141cc406Sopenharmony_ci switch (Action) 1008141cc406Sopenharmony_ci { 1009141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 1010141cc406Sopenharmony_ci switch (n) 1011141cc406Sopenharmony_ci { 1012141cc406Sopenharmony_ci 1013141cc406Sopenharmony_ci /* Get options of type SANE_Word */ 1014141cc406Sopenharmony_ci case optCount: 1015141cc406Sopenharmony_ci case optDPI: 1016141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1017141cc406Sopenharmony_ci case optGamma: 1018141cc406Sopenharmony_ci#endif 1019141cc406Sopenharmony_ci case optTLX: 1020141cc406Sopenharmony_ci case optTLY: 1021141cc406Sopenharmony_ci case optBRX: 1022141cc406Sopenharmony_ci case optBRY: 1023141cc406Sopenharmony_ci case optThreshold: 1024141cc406Sopenharmony_ci DBG (DBG_MSG, 1025141cc406Sopenharmony_ci "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n, 1026141cc406Sopenharmony_ci (int) s->aValues[n].w); 1027141cc406Sopenharmony_ci *(SANE_Word *) pVal = s->aValues[n].w; 1028141cc406Sopenharmony_ci break; 1029141cc406Sopenharmony_ci 1030141cc406Sopenharmony_ci /* Get options of type SANE_Word array */ 1031141cc406Sopenharmony_ci case optGammaTable: 1032141cc406Sopenharmony_ci DBG (DBG_MSG, "Reading gamma table\n"); 1033141cc406Sopenharmony_ci memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size); 1034141cc406Sopenharmony_ci break; 1035141cc406Sopenharmony_ci 1036141cc406Sopenharmony_ci case optMode: 1037141cc406Sopenharmony_ci DBG (DBG_MSG, "Reading scan mode %s\n", 1038141cc406Sopenharmony_ci modeList[s->aValues[optMode].w]); 1039141cc406Sopenharmony_ci strcpy ((char *) pVal, modeList[s->aValues[optMode].w]); 1040141cc406Sopenharmony_ci break; 1041141cc406Sopenharmony_ci 1042141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1043141cc406Sopenharmony_ci /* Get options of type SANE_Bool */ 1044141cc406Sopenharmony_ci case optLamp: 1045141cc406Sopenharmony_ci GetLamp (&s->HWParams, &fLampIsOn); 1046141cc406Sopenharmony_ci *(SANE_Bool *) pVal = fLampIsOn; 1047141cc406Sopenharmony_ci break; 1048141cc406Sopenharmony_ci 1049141cc406Sopenharmony_ci case optCalibrate: 1050141cc406Sopenharmony_ci /* although this option has nothing to read, 1051141cc406Sopenharmony_ci it's added here to avoid a warning when running scanimage --help */ 1052141cc406Sopenharmony_ci break; 1053141cc406Sopenharmony_ci#endif 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci default: 1056141cc406Sopenharmony_ci DBG (DBG_MSG, "SANE_ACTION_GET_VALUE: Invalid option (%d)\n", n); 1057141cc406Sopenharmony_ci } 1058141cc406Sopenharmony_ci break; 1059141cc406Sopenharmony_ci 1060141cc406Sopenharmony_ci 1061141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 1062141cc406Sopenharmony_ci if (s->fScanning) 1063141cc406Sopenharmony_ci { 1064141cc406Sopenharmony_ci DBG (DBG_ERR, 1065141cc406Sopenharmony_ci "sane_control_option: SANE_ACTION_SET_VALUE not allowed during scan\n"); 1066141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1067141cc406Sopenharmony_ci } 1068141cc406Sopenharmony_ci switch (n) 1069141cc406Sopenharmony_ci { 1070141cc406Sopenharmony_ci 1071141cc406Sopenharmony_ci case optCount: 1072141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1075141cc406Sopenharmony_ci case optGamma: 1076141cc406Sopenharmony_ci#endif 1077141cc406Sopenharmony_ci case optThreshold: 1078141cc406Sopenharmony_ci case optDPI: 1079141cc406Sopenharmony_ci 1080141cc406Sopenharmony_ci info |= SANE_INFO_RELOAD_PARAMS; 1081141cc406Sopenharmony_ci /* fall through */ 1082141cc406Sopenharmony_ci 1083141cc406Sopenharmony_ci case optTLX: 1084141cc406Sopenharmony_ci case optTLY: 1085141cc406Sopenharmony_ci case optBRX: 1086141cc406Sopenharmony_ci case optBRY: 1087141cc406Sopenharmony_ci 1088141cc406Sopenharmony_ci status = sanei_constrain_value (&s->aOptions[n], pVal, &info); 1089141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1090141cc406Sopenharmony_ci { 1091141cc406Sopenharmony_ci DBG (DBG_ERR, "Failed to constrain option %d (%s)\n", n, 1092141cc406Sopenharmony_ci s->aOptions[n].title); 1093141cc406Sopenharmony_ci return status; 1094141cc406Sopenharmony_ci } 1095141cc406Sopenharmony_ci 1096141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1097141cc406Sopenharmony_ci /* check values if they are equal */ 1098141cc406Sopenharmony_ci fSame = s->aValues[n].w == *(SANE_Word *) pVal; 1099141cc406Sopenharmony_ci#endif 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci /* set the values */ 1102141cc406Sopenharmony_ci s->aValues[n].w = *(SANE_Word *) pVal; 1103141cc406Sopenharmony_ci DBG (DBG_MSG, 1104141cc406Sopenharmony_ci "sane_control_option: SANE_ACTION_SET_VALUE %d = %d\n", n, 1105141cc406Sopenharmony_ci (int) s->aValues[n].w); 1106141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1107141cc406Sopenharmony_ci if (n == optGamma) 1108141cc406Sopenharmony_ci { 1109141cc406Sopenharmony_ci if (!fSame && optLast > optGammaTable) 1110141cc406Sopenharmony_ci { 1111141cc406Sopenharmony_ci info |= SANE_INFO_RELOAD_OPTIONS; 1112141cc406Sopenharmony_ci } 1113141cc406Sopenharmony_ci _SetScalarGamma (s->aGammaTable, s->aValues[n].w); 1114141cc406Sopenharmony_ci } 1115141cc406Sopenharmony_ci#endif 1116141cc406Sopenharmony_ci break; 1117141cc406Sopenharmony_ci 1118141cc406Sopenharmony_ci case optGammaTable: 1119141cc406Sopenharmony_ci DBG (DBG_MSG, "Writing gamma table\n"); 1120141cc406Sopenharmony_ci pi = (SANE_Int *) pVal; 1121141cc406Sopenharmony_ci memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size); 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_ci /* prepare table for debug */ 1124141cc406Sopenharmony_ci strcpy (szTable, "Gamma table summary:"); 1125141cc406Sopenharmony_ci for (i = 0; i < SANE_GAMMA_SIZE; i++) 1126141cc406Sopenharmony_ci { 1127141cc406Sopenharmony_ci if ((SANE_GAMMA_SIZE / 16) && (i % (SANE_GAMMA_SIZE / 16)) == 0) 1128141cc406Sopenharmony_ci { 1129141cc406Sopenharmony_ci DBG (DBG_MSG, "%s\n", szTable); 1130141cc406Sopenharmony_ci szTable[0] = '\0'; 1131141cc406Sopenharmony_ci } 1132141cc406Sopenharmony_ci /* test for number print */ 1133141cc406Sopenharmony_ci if ((SANE_GAMMA_SIZE / 64) && (i % (SANE_GAMMA_SIZE / 64)) == 0) 1134141cc406Sopenharmony_ci { 1135141cc406Sopenharmony_ci sprintf (szTable + strlen(szTable), " %04X", pi[i]); 1136141cc406Sopenharmony_ci } 1137141cc406Sopenharmony_ci } 1138141cc406Sopenharmony_ci if (strlen (szTable)) 1139141cc406Sopenharmony_ci { 1140141cc406Sopenharmony_ci DBG (DBG_MSG, "%s\n", szTable); 1141141cc406Sopenharmony_ci } 1142141cc406Sopenharmony_ci break; 1143141cc406Sopenharmony_ci 1144141cc406Sopenharmony_ci case optMode: 1145141cc406Sopenharmony_ci { 1146141cc406Sopenharmony_ci SANE_Word *pCap; 1147141cc406Sopenharmony_ci int fCapChanged = 0; 1148141cc406Sopenharmony_ci 1149141cc406Sopenharmony_ci pCap = &s->aOptions[optThreshold].cap; 1150141cc406Sopenharmony_ci 1151141cc406Sopenharmony_ci if (strcmp ((char const *) pVal, colorStr) == 0) 1152141cc406Sopenharmony_ci { 1153141cc406Sopenharmony_ci s->aValues[optMode].w = MODE_COLOR; 1154141cc406Sopenharmony_ci fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 1); 1155141cc406Sopenharmony_ci } 1156141cc406Sopenharmony_ci if (strcmp ((char const *) pVal, grayStr) == 0) 1157141cc406Sopenharmony_ci { 1158141cc406Sopenharmony_ci s->aValues[optMode].w = MODE_GRAY; 1159141cc406Sopenharmony_ci fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 1); 1160141cc406Sopenharmony_ci } 1161141cc406Sopenharmony_ci if (strcmp ((char const *) pVal, lineartStr) == 0) 1162141cc406Sopenharmony_ci { 1163141cc406Sopenharmony_ci s->aValues[optMode].w = MODE_LINEART; 1164141cc406Sopenharmony_ci fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 0); 1165141cc406Sopenharmony_ci 1166141cc406Sopenharmony_ci } 1167141cc406Sopenharmony_ci info |= SANE_INFO_RELOAD_PARAMS; 1168141cc406Sopenharmony_ci if (fCapChanged) 1169141cc406Sopenharmony_ci { 1170141cc406Sopenharmony_ci info |= SANE_INFO_RELOAD_OPTIONS; 1171141cc406Sopenharmony_ci } 1172141cc406Sopenharmony_ci DBG (DBG_MSG, "setting scan mode: %s\n", (char const *) pVal); 1173141cc406Sopenharmony_ci } 1174141cc406Sopenharmony_ci break; 1175141cc406Sopenharmony_ci 1176141cc406Sopenharmony_ci 1177141cc406Sopenharmony_ci 1178141cc406Sopenharmony_ci#ifdef EXPERIMENTAL 1179141cc406Sopenharmony_ci case optLamp: 1180141cc406Sopenharmony_ci fVal = *(SANE_Bool *) pVal; 1181141cc406Sopenharmony_ci DBG (DBG_MSG, "lamp %s\n", fVal ? "on" : "off"); 1182141cc406Sopenharmony_ci if (fVal) 1183141cc406Sopenharmony_ci _WarmUpLamp (s, WARMUP_INSESSION); 1184141cc406Sopenharmony_ci else 1185141cc406Sopenharmony_ci SetLamp (&s->HWParams, SANE_FALSE); 1186141cc406Sopenharmony_ci break; 1187141cc406Sopenharmony_ci 1188141cc406Sopenharmony_ci case optCalibrate: 1189141cc406Sopenharmony_ci/* SimpleCalib(&s->HWParams); */ 1190141cc406Sopenharmony_ci break; 1191141cc406Sopenharmony_ci#endif 1192141cc406Sopenharmony_ci 1193141cc406Sopenharmony_ci default: 1194141cc406Sopenharmony_ci DBG (DBG_ERR, "SANE_ACTION_SET_VALUE: Invalid option (%d)\n", n); 1195141cc406Sopenharmony_ci } 1196141cc406Sopenharmony_ci if (pInfo != NULL) 1197141cc406Sopenharmony_ci { 1198141cc406Sopenharmony_ci *pInfo |= info; 1199141cc406Sopenharmony_ci } 1200141cc406Sopenharmony_ci break; 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci 1203141cc406Sopenharmony_ci case SANE_ACTION_SET_AUTO: 1204141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1205141cc406Sopenharmony_ci 1206141cc406Sopenharmony_ci 1207141cc406Sopenharmony_ci default: 1208141cc406Sopenharmony_ci DBG (DBG_ERR, "Invalid action (%d)\n", Action); 1209141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1210141cc406Sopenharmony_ci } 1211141cc406Sopenharmony_ci 1212141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1213141cc406Sopenharmony_ci} 1214141cc406Sopenharmony_ci 1215141cc406Sopenharmony_ci 1216141cc406Sopenharmony_ci 1217141cc406Sopenharmony_ci 1218141cc406Sopenharmony_ci 1219141cc406Sopenharmony_ciSANE_Status 1220141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters * p) 1221141cc406Sopenharmony_ci{ 1222141cc406Sopenharmony_ci TScanner *s; 1223141cc406Sopenharmony_ci TModeParam const *pMode; 1224141cc406Sopenharmony_ci 1225141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_get_parameters\n"); 1226141cc406Sopenharmony_ci 1227141cc406Sopenharmony_ci s = (TScanner *) h; 1228141cc406Sopenharmony_ci 1229141cc406Sopenharmony_ci /* first do some checks */ 1230141cc406Sopenharmony_ci if (s->aValues[optTLX].w >= s->aValues[optBRX].w) 1231141cc406Sopenharmony_ci { 1232141cc406Sopenharmony_ci DBG (DBG_ERR, "TLX should be smaller than BRX\n"); 1233141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* proper error code? */ 1234141cc406Sopenharmony_ci } 1235141cc406Sopenharmony_ci if (s->aValues[optTLY].w >= s->aValues[optBRY].w) 1236141cc406Sopenharmony_ci { 1237141cc406Sopenharmony_ci DBG (DBG_ERR, "TLY should be smaller than BRY\n"); 1238141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* proper error code? */ 1239141cc406Sopenharmony_ci } 1240141cc406Sopenharmony_ci 1241141cc406Sopenharmony_ci 1242141cc406Sopenharmony_ci pMode = &modeParam[s->aValues[optMode].w]; 1243141cc406Sopenharmony_ci 1244141cc406Sopenharmony_ci /* return the data */ 1245141cc406Sopenharmony_ci p->format = pMode->format; 1246141cc406Sopenharmony_ci p->last_frame = SANE_TRUE; 1247141cc406Sopenharmony_ci 1248141cc406Sopenharmony_ci p->lines = MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w, 1249141cc406Sopenharmony_ci s->aValues[optDPI].w); 1250141cc406Sopenharmony_ci p->depth = pMode->depth; 1251141cc406Sopenharmony_ci p->pixels_per_line = 1252141cc406Sopenharmony_ci MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w, 1253141cc406Sopenharmony_ci s->aValues[optDPI].w); 1254141cc406Sopenharmony_ci p->bytes_per_line = pMode->bytesPerLine (p->pixels_per_line); 1255141cc406Sopenharmony_ci 1256141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1257141cc406Sopenharmony_ci} 1258141cc406Sopenharmony_ci 1259141cc406Sopenharmony_ci 1260141cc406Sopenharmony_ci/* get the scale down factor for a resolution that is 1261141cc406Sopenharmony_ci not supported by hardware */ 1262141cc406Sopenharmony_cistatic int 1263141cc406Sopenharmony_ci_SaneEmulateScaling (int iDpi) 1264141cc406Sopenharmony_ci{ 1265141cc406Sopenharmony_ci if (iDpi == 75) 1266141cc406Sopenharmony_ci return 2; 1267141cc406Sopenharmony_ci else 1268141cc406Sopenharmony_ci return 1; 1269141cc406Sopenharmony_ci} 1270141cc406Sopenharmony_ci 1271141cc406Sopenharmony_ci 1272141cc406Sopenharmony_ciSANE_Status 1273141cc406Sopenharmony_cisane_start (SANE_Handle h) 1274141cc406Sopenharmony_ci{ 1275141cc406Sopenharmony_ci TScanner *s; 1276141cc406Sopenharmony_ci SANE_Parameters par; 1277141cc406Sopenharmony_ci int iLineCorr; 1278141cc406Sopenharmony_ci int iScaleDown; 1279141cc406Sopenharmony_ci static unsigned char abGamma[HW_GAMMA_SIZE]; 1280141cc406Sopenharmony_ci static unsigned char abCalibTable[HW_PIXELS * 6]; 1281141cc406Sopenharmony_ci 1282141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_start\n"); 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci s = (TScanner *) h; 1285141cc406Sopenharmony_ci 1286141cc406Sopenharmony_ci if (sane_get_parameters (h, &par) != SANE_STATUS_GOOD) 1287141cc406Sopenharmony_ci { 1288141cc406Sopenharmony_ci DBG (DBG_MSG, "Invalid scan parameters\n"); 1289141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1290141cc406Sopenharmony_ci } 1291141cc406Sopenharmony_ci iScaleDown = _SaneEmulateScaling (s->aValues[optDPI].w); 1292141cc406Sopenharmony_ci s->iLinesLeft = par.lines; 1293141cc406Sopenharmony_ci 1294141cc406Sopenharmony_ci /* fill in the scanparams using the option values */ 1295141cc406Sopenharmony_ci s->ScanParams.iDpi = s->aValues[optDPI].w * iScaleDown; 1296141cc406Sopenharmony_ci s->ScanParams.iLpi = s->aValues[optDPI].w * iScaleDown; 1297141cc406Sopenharmony_ci 1298141cc406Sopenharmony_ci /* calculate correction for filling of circular buffer */ 1299141cc406Sopenharmony_ci iLineCorr = 3 * s->HWParams.iSensorSkew; /* usually 16 motor steps */ 1300141cc406Sopenharmony_ci /* calculate correction for garbage lines */ 1301141cc406Sopenharmony_ci iLineCorr += s->HWParams.iSkipLines * (HW_LPI / s->ScanParams.iLpi); 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ci s->ScanParams.iTop = 1304141cc406Sopenharmony_ci MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY, 1305141cc406Sopenharmony_ci HW_LPI) - iLineCorr; 1306141cc406Sopenharmony_ci s->ScanParams.iLeft = 1307141cc406Sopenharmony_ci MM_TO_PIXEL (s->aValues[optTLX].w + s->HWParams.iTopLeftX, HW_DPI); 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci s->ScanParams.iWidth = par.pixels_per_line * iScaleDown; 1310141cc406Sopenharmony_ci s->ScanParams.iHeight = par.lines * iScaleDown; 1311141cc406Sopenharmony_ci s->ScanParams.iBottom = HP3300C_BOTTOM; 1312141cc406Sopenharmony_ci s->ScanParams.fCalib = SANE_FALSE; 1313141cc406Sopenharmony_ci 1314141cc406Sopenharmony_ci /* perform a simple calibration just before scanning */ 1315141cc406Sopenharmony_ci _WaitForLamp (s, abCalibTable); 1316141cc406Sopenharmony_ci 1317141cc406Sopenharmony_ci if (s->aValues[optMode].w == MODE_LINEART) 1318141cc406Sopenharmony_ci { 1319141cc406Sopenharmony_ci /* use a unity gamma table for lineart to be independent from Gamma settings */ 1320141cc406Sopenharmony_ci _UnityGammaTable (abGamma); 1321141cc406Sopenharmony_ci } 1322141cc406Sopenharmony_ci else 1323141cc406Sopenharmony_ci { 1324141cc406Sopenharmony_ci /* copy gamma table */ 1325141cc406Sopenharmony_ci _ConvertGammaTable (s->aGammaTable, abGamma); 1326141cc406Sopenharmony_ci } 1327141cc406Sopenharmony_ci 1328141cc406Sopenharmony_ci WriteGammaCalibTable (abGamma, abGamma, abGamma, abCalibTable, 0, 0, 1329141cc406Sopenharmony_ci &s->HWParams); 1330141cc406Sopenharmony_ci 1331141cc406Sopenharmony_ci /* prepare the actual scan */ 1332141cc406Sopenharmony_ci if (!InitScan (&s->ScanParams, &s->HWParams)) 1333141cc406Sopenharmony_ci { 1334141cc406Sopenharmony_ci DBG (DBG_MSG, "Invalid scan parameters\n"); 1335141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1336141cc406Sopenharmony_ci } 1337141cc406Sopenharmony_ci 1338141cc406Sopenharmony_ci /* init data pipe */ 1339141cc406Sopenharmony_ci s->DataPipe.iSkipLines = s->HWParams.iSkipLines; 1340141cc406Sopenharmony_ci /* on the hp3400 and hp4300 we cannot set the top of the scan area (yet), 1341141cc406Sopenharmony_ci so instead we just scan and throw away the data until the top */ 1342141cc406Sopenharmony_ci if (s->HWParams.fReg07) 1343141cc406Sopenharmony_ci { 1344141cc406Sopenharmony_ci s->DataPipe.iSkipLines += 1345141cc406Sopenharmony_ci MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY, 1346141cc406Sopenharmony_ci s->aValues[optDPI].w * iScaleDown); 1347141cc406Sopenharmony_ci } 1348141cc406Sopenharmony_ci s->iBytesLeft = 0; 1349141cc406Sopenharmony_ci s->iPixelsPerLine = par.pixels_per_line; 1350141cc406Sopenharmony_ci 1351141cc406Sopenharmony_ci /* hack */ 1352141cc406Sopenharmony_ci s->DataPipe.pabLineBuf = (unsigned char *) malloc (HW_PIXELS * 3); 1353141cc406Sopenharmony_ci CircBufferInit (s->HWParams.iXferHandle, &s->DataPipe, 1354141cc406Sopenharmony_ci par.pixels_per_line, s->ScanParams.iHeight, 1355141cc406Sopenharmony_ci s->ScanParams.iLpi * s->HWParams.iSensorSkew / HW_LPI, 1356141cc406Sopenharmony_ci s->HWParams.iReversedHead, iScaleDown, iScaleDown); 1357141cc406Sopenharmony_ci 1358141cc406Sopenharmony_ci s->fScanning = SANE_TRUE; 1359141cc406Sopenharmony_ci s->fCancelled = SANE_FALSE; 1360141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1361141cc406Sopenharmony_ci} 1362141cc406Sopenharmony_ci 1363141cc406Sopenharmony_ci 1364141cc406Sopenharmony_ciSANE_Status 1365141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) 1366141cc406Sopenharmony_ci{ 1367141cc406Sopenharmony_ci TScanner *s; 1368141cc406Sopenharmony_ci TDataPipe *p; 1369141cc406Sopenharmony_ci TModeParam const *pMode; 1370141cc406Sopenharmony_ci 1371141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_read: buf=%p, maxlen=%d, ", (void *) buf, maxlen); 1372141cc406Sopenharmony_ci 1373141cc406Sopenharmony_ci s = (TScanner *) h; 1374141cc406Sopenharmony_ci 1375141cc406Sopenharmony_ci pMode = &modeParam[s->aValues[optMode].w]; 1376141cc406Sopenharmony_ci 1377141cc406Sopenharmony_ci /* sane_read only allowed after sane_start */ 1378141cc406Sopenharmony_ci if (!s->fScanning) 1379141cc406Sopenharmony_ci { 1380141cc406Sopenharmony_ci if (s->fCancelled) 1381141cc406Sopenharmony_ci { 1382141cc406Sopenharmony_ci DBG (DBG_MSG, "\n"); 1383141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_read: sane_read cancelled\n"); 1384141cc406Sopenharmony_ci s->fCancelled = SANE_FALSE; 1385141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1386141cc406Sopenharmony_ci } 1387141cc406Sopenharmony_ci else 1388141cc406Sopenharmony_ci { 1389141cc406Sopenharmony_ci DBG (DBG_ERR, 1390141cc406Sopenharmony_ci "sane_read: sane_read only allowed after sane_start\n"); 1391141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1392141cc406Sopenharmony_ci } 1393141cc406Sopenharmony_ci } 1394141cc406Sopenharmony_ci 1395141cc406Sopenharmony_ci p = &s->DataPipe; 1396141cc406Sopenharmony_ci 1397141cc406Sopenharmony_ci /* anything left to read? */ 1398141cc406Sopenharmony_ci if ((s->iLinesLeft == 0) && (s->iBytesLeft == 0)) 1399141cc406Sopenharmony_ci { 1400141cc406Sopenharmony_ci CircBufferExit (p); 1401141cc406Sopenharmony_ci free (p->pabLineBuf); 1402141cc406Sopenharmony_ci p->pabLineBuf = NULL; 1403141cc406Sopenharmony_ci FinishScan (&s->HWParams); 1404141cc406Sopenharmony_ci *len = 0; 1405141cc406Sopenharmony_ci DBG (DBG_MSG, "\n"); 1406141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_read: end of scan\n"); 1407141cc406Sopenharmony_ci s->fCancelled = SANE_FALSE; 1408141cc406Sopenharmony_ci s->fScanning = SANE_FALSE; 1409141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1410141cc406Sopenharmony_ci } 1411141cc406Sopenharmony_ci 1412141cc406Sopenharmony_ci /* time to read the next line? */ 1413141cc406Sopenharmony_ci if (s->iBytesLeft == 0) 1414141cc406Sopenharmony_ci { 1415141cc406Sopenharmony_ci /* read a line from the transfer buffer */ 1416141cc406Sopenharmony_ci if (CircBufferGetLineEx (s->HWParams.iXferHandle, p, p->pabLineBuf, 1417141cc406Sopenharmony_ci s->HWParams.iReversedHead, SANE_TRUE)) 1418141cc406Sopenharmony_ci { 1419141cc406Sopenharmony_ci pMode->adaptFormat (p->pabLineBuf, s->iPixelsPerLine, 1420141cc406Sopenharmony_ci s->aValues[optThreshold].w); 1421141cc406Sopenharmony_ci s->iBytesLeft = pMode->bytesPerLine (s->iPixelsPerLine); 1422141cc406Sopenharmony_ci s->iLinesLeft--; 1423141cc406Sopenharmony_ci } 1424141cc406Sopenharmony_ci /* stop scanning further, when the read action fails 1425141cc406Sopenharmony_ci because we try read after the end of the buffer */ 1426141cc406Sopenharmony_ci else 1427141cc406Sopenharmony_ci { 1428141cc406Sopenharmony_ci FinishScan (&s->HWParams); 1429141cc406Sopenharmony_ci CircBufferExit (p); 1430141cc406Sopenharmony_ci free (p->pabLineBuf); 1431141cc406Sopenharmony_ci p->pabLineBuf = NULL; 1432141cc406Sopenharmony_ci *len = 0; 1433141cc406Sopenharmony_ci DBG (DBG_MSG, "\n"); 1434141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_read: read after end of buffer\n"); 1435141cc406Sopenharmony_ci s->fCancelled = SANE_FALSE; 1436141cc406Sopenharmony_ci s->fScanning = SANE_FALSE; 1437141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1438141cc406Sopenharmony_ci } 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci } 1441141cc406Sopenharmony_ci 1442141cc406Sopenharmony_ci /* copy (part of) a line */ 1443141cc406Sopenharmony_ci *len = MIN (maxlen, s->iBytesLeft); 1444141cc406Sopenharmony_ci memcpy (buf, 1445141cc406Sopenharmony_ci &p->pabLineBuf[pMode->bytesPerLine (s->iPixelsPerLine) - 1446141cc406Sopenharmony_ci s->iBytesLeft], *len); 1447141cc406Sopenharmony_ci s->iBytesLeft -= *len; 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci DBG (DBG_MSG, " read=%d \n", *len); 1450141cc406Sopenharmony_ci 1451141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1452141cc406Sopenharmony_ci} 1453141cc406Sopenharmony_ci 1454141cc406Sopenharmony_ci 1455141cc406Sopenharmony_civoid 1456141cc406Sopenharmony_cisane_cancel (SANE_Handle h) 1457141cc406Sopenharmony_ci{ 1458141cc406Sopenharmony_ci TScanner *s; 1459141cc406Sopenharmony_ci 1460141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_cancel\n"); 1461141cc406Sopenharmony_ci 1462141cc406Sopenharmony_ci s = (TScanner *) h; 1463141cc406Sopenharmony_ci /* Make sure the scanner head returns home */ 1464141cc406Sopenharmony_ci FinishScan (&s->HWParams); 1465141cc406Sopenharmony_ci /* delete allocated data */ 1466141cc406Sopenharmony_ci if (s->fScanning) 1467141cc406Sopenharmony_ci { 1468141cc406Sopenharmony_ci CircBufferExit (&s->DataPipe); 1469141cc406Sopenharmony_ci free (s->DataPipe.pabLineBuf); 1470141cc406Sopenharmony_ci s->DataPipe.pabLineBuf = NULL; 1471141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_cancel: freeing buffers\n"); 1472141cc406Sopenharmony_ci } 1473141cc406Sopenharmony_ci s->fCancelled = SANE_TRUE; 1474141cc406Sopenharmony_ci s->fScanning = SANE_FALSE; 1475141cc406Sopenharmony_ci} 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci 1478141cc406Sopenharmony_ciSANE_Status 1479141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ h, SANE_Bool m) 1480141cc406Sopenharmony_ci{ 1481141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_set_io_mode %s\n", m ? "non-blocking" : "blocking"); 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ci if (m) 1484141cc406Sopenharmony_ci { 1485141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1486141cc406Sopenharmony_ci } 1487141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1488141cc406Sopenharmony_ci} 1489141cc406Sopenharmony_ci 1490141cc406Sopenharmony_ci 1491141cc406Sopenharmony_ciSANE_Status 1492141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ h, SANE_Int __sane_unused__ * fd) 1493141cc406Sopenharmony_ci{ 1494141cc406Sopenharmony_ci DBG (DBG_MSG, "sane_select_fd\n"); 1495141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1496141cc406Sopenharmony_ci} 1497