1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1997 David Mosberger-Tang 3141cc406Sopenharmony_ci This file is part of the SANE package. 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 6141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 7141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 8141cc406Sopenharmony_ci License, or (at your option) any later version. 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 11141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 12141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13141cc406Sopenharmony_ci General Public License for more details. 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 16141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 19141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 22141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 23141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 24141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 25141cc406Sopenharmony_ci account of linking the SANE library code into it. 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 28141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 29141cc406Sopenharmony_ci License. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 32141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 33141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 36141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 37141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci This file implements a SANE backend for the Connectix QuickCam. At 40141cc406Sopenharmony_ci present, only the color camera is supported though the driver 41141cc406Sopenharmony_ci should be able to easily accommodate black and white cameras. 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci Portions of this code are derived from Scott Laird's qcam driver. 44141cc406Sopenharmony_ci It's copyright notice is reproduced here: 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci Copyright (C) 1996 by Scott Laird 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci Permission is hereby granted, free of charge, to any person 49141cc406Sopenharmony_ci obtaining a copy of this software and associated documentation 50141cc406Sopenharmony_ci files (the "Software"), to deal in the Software without 51141cc406Sopenharmony_ci restriction, including without limitation the rights to use, copy, 52141cc406Sopenharmony_ci modify, merge, publish, distribute, sublicense, and/or sell copies 53141cc406Sopenharmony_ci of the Software, and to permit persons to whom the Software is 54141cc406Sopenharmony_ci furnished to do so, subject to the following conditions: 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci The above copyright notice and this permission notice shall be 57141cc406Sopenharmony_ci included in all copies or substantial portions of the Software. 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 60141cc406Sopenharmony_ci EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 61141cc406Sopenharmony_ci MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 62141cc406Sopenharmony_ci NONINFRINGEMENT. IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY 63141cc406Sopenharmony_ci CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 64141cc406Sopenharmony_ci CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 65141cc406Sopenharmony_ci WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci#ifdef _AIX 68141cc406Sopenharmony_ci# include "lalloca.h" /* MUST come first for AIX! */ 69141cc406Sopenharmony_ci#endif 70141cc406Sopenharmony_ci 71141cc406Sopenharmony_ci#include "../include/sane/config.h" 72141cc406Sopenharmony_ci#include "lalloca.h" 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci#include <assert.h> 75141cc406Sopenharmony_ci#include <ctype.h> 76141cc406Sopenharmony_ci#include <errno.h> 77141cc406Sopenharmony_ci#include <fcntl.h> 78141cc406Sopenharmony_ci#include <limits.h> 79141cc406Sopenharmony_ci#include <math.h> 80141cc406Sopenharmony_ci#include <setjmp.h> 81141cc406Sopenharmony_ci#include <signal.h> 82141cc406Sopenharmony_ci#include <stdio.h> 83141cc406Sopenharmony_ci#include <stdlib.h> 84141cc406Sopenharmony_ci#include <string.h> 85141cc406Sopenharmony_ci#include <sys/types.h> 86141cc406Sopenharmony_ci#include <sys/wait.h> 87141cc406Sopenharmony_ci#include <unistd.h> 88141cc406Sopenharmony_ci 89141cc406Sopenharmony_ci#include "../include/sane/sane.h" 90141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 91141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci#define BACKEND_NAME qcam 95141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci#ifndef PATH_MAX 98141cc406Sopenharmony_ci# define PATH_MAX 1024 99141cc406Sopenharmony_ci#endif 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 102141cc406Sopenharmony_ci#define QCAM_CONFIG_FILE "qcam.conf" 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci#include "qcam.h" 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci/* status bits */ 107141cc406Sopenharmony_ci#define NeedRamTable (1 << 1) 108141cc406Sopenharmony_ci#define BlackBalanceInProgress (1 << 6) 109141cc406Sopenharmony_ci#define CameraNotReady (1 << 7) 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci/* lpdata bits: */ 112141cc406Sopenharmony_ci#define Cmd0_7 0xff 113141cc406Sopenharmony_ci#define CamRdy2 ( 1 << 0) /* byte mode */ 114141cc406Sopenharmony_ci#define Data0_6 (0x7f << 1) /* byte mode */ 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_ci/* lpstatus bits: */ 117141cc406Sopenharmony_ci#define CamRdy1 ( 1 << 3) /* nibble mode */ 118141cc406Sopenharmony_ci#define Nibble0_3 (0x0f << 4) /* nibble mode */ 119141cc406Sopenharmony_ci#define Data7_11 (0x1f << 3) /* byte mode */ 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ci/* lpcontrol bits: */ 122141cc406Sopenharmony_ci#define Strobe ( 1 << 0) /* unused */ 123141cc406Sopenharmony_ci#define Autofeed ( 1 << 1) 124141cc406Sopenharmony_ci#define Reset_N ( 1 << 2) 125141cc406Sopenharmony_ci#define PCAck ( 1 << 3) 126141cc406Sopenharmony_ci#define BiDir ( 1 << 5) 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_cistatic int num_devices; 129141cc406Sopenharmony_cistatic QC_Device *first_dev; 130141cc406Sopenharmony_cistatic QC_Scanner *first_handle; 131141cc406Sopenharmony_ci 132141cc406Sopenharmony_cistatic const SANE_String_Const resolution_list[] = { 133141cc406Sopenharmony_ci "Low", /* million-mode */ 134141cc406Sopenharmony_ci "High", /* billion-mode */ 135141cc406Sopenharmony_ci 0 136141cc406Sopenharmony_ci}; 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_cistatic const SANE_Int mono_depth_list[] = { 139141cc406Sopenharmony_ci 2, /* # of elements */ 140141cc406Sopenharmony_ci 4, 6 141141cc406Sopenharmony_ci}; 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_cistatic const SANE_Int color_depth_list[] = { 144141cc406Sopenharmony_ci /*2 */ 1, 145141cc406Sopenharmony_ci /* # of elements */ 146141cc406Sopenharmony_ci /*16, */ 24 147141cc406Sopenharmony_ci /* "thousand" mode not implemented yet */ 148141cc406Sopenharmony_ci}; 149141cc406Sopenharmony_ci 150141cc406Sopenharmony_cistatic const SANE_Int xfer_scale_list[] = { 151141cc406Sopenharmony_ci 3, /* # of elements */ 152141cc406Sopenharmony_ci 1, 2, 4 153141cc406Sopenharmony_ci}; 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_cistatic const SANE_Range u8_range = { 156141cc406Sopenharmony_ci /* min, max, quantization */ 157141cc406Sopenharmony_ci 0, 255, 0 158141cc406Sopenharmony_ci}; 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cistatic const SANE_Range brightness_range = { 161141cc406Sopenharmony_ci /* min, max, quantization */ 162141cc406Sopenharmony_ci 0, 254, 0 /* 255 is bulb mode! */ 163141cc406Sopenharmony_ci}; 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_cistatic const SANE_Range x_range[] = { 166141cc406Sopenharmony_ci /* min, max, quantization */ 167141cc406Sopenharmony_ci {0, 338, 2}, /* million mode */ 168141cc406Sopenharmony_ci {0, 676, 4}, /* billion mode */ 169141cc406Sopenharmony_ci}; 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_cistatic const SANE_Range odd_x_range[] = { 172141cc406Sopenharmony_ci /* min, max, quantization */ 173141cc406Sopenharmony_ci {1, 339, 2}, /* million mode */ 174141cc406Sopenharmony_ci {3, 683, 4}, /* billion mode */ 175141cc406Sopenharmony_ci}; 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_cistatic const SANE_Range y_range[] = { 178141cc406Sopenharmony_ci /* min, max, quantization */ 179141cc406Sopenharmony_ci {0, 249, 1}, /* million mode */ 180141cc406Sopenharmony_ci {0, 498, 2}, /* billion mode */ 181141cc406Sopenharmony_ci}; 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_cistatic const SANE_Range odd_y_range[] = { 184141cc406Sopenharmony_ci /* min, max, quantization */ 185141cc406Sopenharmony_ci {0, 249, 1}, /* million mode */ 186141cc406Sopenharmony_ci {1, 499, 2}, /* billion mode */ 187141cc406Sopenharmony_ci}; 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_cistatic const SANE_Range bw_x_range = { 0, 334, 2 }; 190141cc406Sopenharmony_cistatic const SANE_Range odd_bw_x_range = { 1, 335, 2 }; 191141cc406Sopenharmony_cistatic const SANE_Range bw_y_range = { 0, 241, 1 }; 192141cc406Sopenharmony_cistatic const SANE_Range odd_bw_y_range = { 1, 242, 1 }; 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci#include "../include/sane/sanei_directio.h" 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci#define read_lpdata(d) sanei_inb ((d)->port) 197141cc406Sopenharmony_ci#define read_lpstatus(d) sanei_inb ((d)->port + 1) 198141cc406Sopenharmony_ci#define read_lpcontrol(d) sanei_inb ((d)->port + 2) 199141cc406Sopenharmony_ci#define write_lpdata(d,v) sanei_outb ((d)->port, (v)) 200141cc406Sopenharmony_ci#define write_lpcontrol(d,v) sanei_outb ((d)->port + 2, (v)) 201141cc406Sopenharmony_ci 202141cc406Sopenharmony_ci 203141cc406Sopenharmony_cistatic SANE_Status 204141cc406Sopenharmony_cienable_ports (QC_Device * q) 205141cc406Sopenharmony_ci{ 206141cc406Sopenharmony_ci /* better safe than sorry */ 207141cc406Sopenharmony_ci if (q->port < 0x278 || q->port > 0x3bc) 208141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci if (sanei_ioperm (q->port, 3, 1) < 0) 211141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 214141cc406Sopenharmony_ci} 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_cistatic SANE_Status 217141cc406Sopenharmony_cidisable_ports (QC_Device * q) 218141cc406Sopenharmony_ci{ 219141cc406Sopenharmony_ci if (sanei_ioperm (q->port, 3, 0) < 0) 220141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 223141cc406Sopenharmony_ci} 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci/* We need a short delay loop -- something well under a millisecond. 226141cc406Sopenharmony_ci Unfortunately, adding 2 usleep(1)'s to qc_command slowed it down by 227141cc406Sopenharmony_ci a factor of over 1000 over the same loop with 2 usleep(0)'s, and 228141cc406Sopenharmony_ci that's too slow -- qc_start was taking over a second to run. This 229141cc406Sopenharmony_ci seems to help, but if anyone has a good speed-independent pause 230141cc406Sopenharmony_ci routine, please tell me. -- Scott 231141cc406Sopenharmony_ci 232141cc406Sopenharmony_ci If you're worried about hogging the CPU: don't worry, the qcam 233141cc406Sopenharmony_ci interface leaves you no choice, so this doesn't make the situation 234141cc406Sopenharmony_ci any worse... */ 235141cc406Sopenharmony_ci 236141cc406Sopenharmony_cistatic int 237141cc406Sopenharmony_ciqc_wait (QC_Device * q) 238141cc406Sopenharmony_ci{ 239141cc406Sopenharmony_ci return read_lpstatus (q); 240141cc406Sopenharmony_ci} 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci 243141cc406Sopenharmony_ci/* This function uses POSIX fcntl-style locking on a file created in 244141cc406Sopenharmony_ci the /tmp directory. Because it uses the Unix record locking 245141cc406Sopenharmony_ci facility, locks are relinquished automatically on process 246141cc406Sopenharmony_ci termination, so "dead locks" are not a problem. (FYI, the lock 247141cc406Sopenharmony_ci file will remain after process termination, but this is actually 248141cc406Sopenharmony_ci desired so that the next process need not re-creat(2)e it... just 249141cc406Sopenharmony_ci lock it.) The wait argument indicates whether or not this function 250141cc406Sopenharmony_ci should "block" waiting for the previous lock to be relinquished. 251141cc406Sopenharmony_ci This is ideal so that multiple processes (eg. qcam) taking 252141cc406Sopenharmony_ci "snapshots" can peacefully coexist. 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_ci -- Dave Plonka (plonka@carroll1.cc.edu) */ 255141cc406Sopenharmony_cistatic SANE_Status 256141cc406Sopenharmony_ciqc_lock_wait (QC_Device * q, int wait) 257141cc406Sopenharmony_ci{ 258141cc406Sopenharmony_ci#ifdef F_SETLK 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_ci#ifndef HAVE_STRUCT_FLOCK 261141cc406Sopenharmony_ci struct flock 262141cc406Sopenharmony_ci { 263141cc406Sopenharmony_ci off_t l_start; 264141cc406Sopenharmony_ci off_t l_len; 265141cc406Sopenharmony_ci pid_t l_pid; 266141cc406Sopenharmony_ci short l_type; 267141cc406Sopenharmony_ci short l_whence; 268141cc406Sopenharmony_ci }; 269141cc406Sopenharmony_ci#endif /* !HAVE_STRUCT_FLOCK */ 270141cc406Sopenharmony_ci struct flock sfl; 271141cc406Sopenharmony_ci#endif 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_ci DBG (3, "qc_lock_wait: acquiring lock for 0x%x\n", q->port); 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_ci#ifdef F_SETLK 276141cc406Sopenharmony_ci memset (&sfl, 0, sizeof (sfl)); 277141cc406Sopenharmony_ci#endif 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci if (q->lock_fd < 0) 280141cc406Sopenharmony_ci { 281141cc406Sopenharmony_ci char lockfile[128]; 282141cc406Sopenharmony_ci 283141cc406Sopenharmony_ci sprintf (lockfile, "/tmp/LOCK.qcam.0x%x", q->port); 284141cc406Sopenharmony_ci q->lock_fd = open (lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666); 285141cc406Sopenharmony_ci if (q->lock_fd < 0) 286141cc406Sopenharmony_ci { 287141cc406Sopenharmony_ci DBG (1, "qc_lock_wait: failed to open %s (%s)\n", 288141cc406Sopenharmony_ci lockfile, strerror (errno)); 289141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 290141cc406Sopenharmony_ci } 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci } 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ci#ifdef F_SETLK 295141cc406Sopenharmony_ci sfl.l_type = F_WRLCK; 296141cc406Sopenharmony_ci if (fcntl (q->lock_fd, wait ? F_SETLKW : F_SETLK, &sfl) != 0) 297141cc406Sopenharmony_ci { 298141cc406Sopenharmony_ci DBG (1, "qc_lock_wait: failed to acquire lock (%s)\n", 299141cc406Sopenharmony_ci strerror (errno)); 300141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 301141cc406Sopenharmony_ci } 302141cc406Sopenharmony_ci#endif 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci DBG (3, "qc_lock_wait: got lock for 0x%x\n", q->port); 305141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 306141cc406Sopenharmony_ci} 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_cistatic SANE_Status 309141cc406Sopenharmony_ciqc_unlock (QC_Device * q) 310141cc406Sopenharmony_ci{ 311141cc406Sopenharmony_ci SANE_Status status; 312141cc406Sopenharmony_ci char lockfile[128]; 313141cc406Sopenharmony_ci#ifdef F_SETLK 314141cc406Sopenharmony_ci#ifndef HAVE_STRUCT_FLOCK 315141cc406Sopenharmony_ci struct flock 316141cc406Sopenharmony_ci { 317141cc406Sopenharmony_ci off_t l_start; 318141cc406Sopenharmony_ci off_t l_len; 319141cc406Sopenharmony_ci pid_t l_pid; 320141cc406Sopenharmony_ci short l_type; 321141cc406Sopenharmony_ci short l_whence; 322141cc406Sopenharmony_ci }; 323141cc406Sopenharmony_ci#endif /* !HAVE_STRUCT_FLOCK */ 324141cc406Sopenharmony_ci struct flock sfl; 325141cc406Sopenharmony_ci#endif 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci DBG (3, "qc_unlock: releasing lock for 0x%x\n", q->port); 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_ci#ifdef F_SETLK 330141cc406Sopenharmony_ci memset (&sfl, 0, sizeof (sfl)); 331141cc406Sopenharmony_ci#endif 332141cc406Sopenharmony_ci if (q->lock_fd < 0) 333141cc406Sopenharmony_ci { 334141cc406Sopenharmony_ci DBG (3, "qc_unlock; port was not locked\n"); 335141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 336141cc406Sopenharmony_ci } 337141cc406Sopenharmony_ci /* clear the exclusive lock */ 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci#ifdef F_SETLK 340141cc406Sopenharmony_ci sfl.l_type = F_UNLCK; 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci if (fcntl (q->lock_fd, F_SETLK, &sfl) != 0) 343141cc406Sopenharmony_ci { 344141cc406Sopenharmony_ci DBG (3, "qc_unlock: failed to release lock (%s)\n", strerror (errno)); 345141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 346141cc406Sopenharmony_ci } 347141cc406Sopenharmony_ci#endif 348141cc406Sopenharmony_ci sprintf (lockfile, "/tmp/LOCK.qcam.0x%x", q->port); 349141cc406Sopenharmony_ci DBG (1, "qc_unlock: /tmp/LOCK.qcam.0x%x\n", q->port); 350141cc406Sopenharmony_ci unlink (lockfile); 351141cc406Sopenharmony_ci close (q->lock_fd); 352141cc406Sopenharmony_ci q->lock_fd = -1; 353141cc406Sopenharmony_ci DBG (1, "qc_unlock: exit\n"); 354141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 355141cc406Sopenharmony_ci return status; 356141cc406Sopenharmony_ci} 357141cc406Sopenharmony_ci 358141cc406Sopenharmony_cistatic SANE_Status 359141cc406Sopenharmony_ciqc_lock (QC_Device * q) 360141cc406Sopenharmony_ci{ 361141cc406Sopenharmony_ci return qc_lock_wait (q, 1); 362141cc406Sopenharmony_ci} 363141cc406Sopenharmony_ci 364141cc406Sopenharmony_ci/* Busy-waits for a handshake signal from the QuickCam. Almost all 365141cc406Sopenharmony_ci communication with the camera requires handshaking. This is why 366141cc406Sopenharmony_ci qcam is a CPU hog. */ 367141cc406Sopenharmony_cistatic int 368141cc406Sopenharmony_ciqc_waithand (QC_Device * q, int val) 369141cc406Sopenharmony_ci{ 370141cc406Sopenharmony_ci int status; 371141cc406Sopenharmony_ci 372141cc406Sopenharmony_ci while (((status = read_lpstatus (q)) & CamRdy1) != val); 373141cc406Sopenharmony_ci return status; 374141cc406Sopenharmony_ci} 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci/* This is used when the qcam is in bidirectional ("byte") mode, and 377141cc406Sopenharmony_ci the handshaking signal is CamRdy2 (bit 0 of data reg) instead of 378141cc406Sopenharmony_ci CamRdy1 (bit 3 of status register). It also returns the last value 379141cc406Sopenharmony_ci read, since this data is useful. */ 380141cc406Sopenharmony_cistatic unsigned int 381141cc406Sopenharmony_ciqc_waithand2 (QC_Device * q, int val) 382141cc406Sopenharmony_ci{ 383141cc406Sopenharmony_ci unsigned int status; 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci do 386141cc406Sopenharmony_ci { 387141cc406Sopenharmony_ci status = read_lpdata (q); 388141cc406Sopenharmony_ci } 389141cc406Sopenharmony_ci while ((status & CamRdy2) != (unsigned int) val); 390141cc406Sopenharmony_ci return status; 391141cc406Sopenharmony_ci} 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_cistatic unsigned int 394141cc406Sopenharmony_ciqc_send (QC_Device * q, unsigned int byte) 395141cc406Sopenharmony_ci{ 396141cc406Sopenharmony_ci unsigned int echo; 397141cc406Sopenharmony_ci int n1, n2; 398141cc406Sopenharmony_ci 399141cc406Sopenharmony_ci write_lpdata (q, byte); 400141cc406Sopenharmony_ci qc_wait (q); 401141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N); 402141cc406Sopenharmony_ci qc_wait (q); 403141cc406Sopenharmony_ci 404141cc406Sopenharmony_ci n1 = qc_waithand (q, CamRdy1); 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck); 407141cc406Sopenharmony_ci qc_wait (q); 408141cc406Sopenharmony_ci n2 = qc_waithand (q, 0); 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci echo = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); 411141cc406Sopenharmony_ci#ifndef NDEBUG 412141cc406Sopenharmony_ci if (echo != byte) 413141cc406Sopenharmony_ci { 414141cc406Sopenharmony_ci DBG (1, "qc_send: sent 0x%02x, camera echoed 0x%02x\n", byte, echo); 415141cc406Sopenharmony_ci n2 = read_lpstatus (q); 416141cc406Sopenharmony_ci echo = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); 417141cc406Sopenharmony_ci if (echo != byte) 418141cc406Sopenharmony_ci DBG (1, "qc_send: (re-read does not help)\n"); 419141cc406Sopenharmony_ci else 420141cc406Sopenharmony_ci DBG (1, "qc_send: (fixed on re-read)\n"); 421141cc406Sopenharmony_ci } 422141cc406Sopenharmony_ci#endif 423141cc406Sopenharmony_ci return echo; 424141cc406Sopenharmony_ci} 425141cc406Sopenharmony_ci 426141cc406Sopenharmony_cistatic int 427141cc406Sopenharmony_ciqc_readparam (QC_Device * q) 428141cc406Sopenharmony_ci{ 429141cc406Sopenharmony_ci int n1, n2; 430141cc406Sopenharmony_ci int cmd; 431141cc406Sopenharmony_ci 432141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N); /* clear PCAck */ 433141cc406Sopenharmony_ci n1 = qc_waithand (q, CamRdy1); 434141cc406Sopenharmony_ci 435141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck); /* set PCAck */ 436141cc406Sopenharmony_ci n2 = qc_waithand (q, 0); 437141cc406Sopenharmony_ci 438141cc406Sopenharmony_ci cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); 439141cc406Sopenharmony_ci return cmd; 440141cc406Sopenharmony_ci} 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_cistatic unsigned int 443141cc406Sopenharmony_ciqc_getstatus (QC_Device * q) 444141cc406Sopenharmony_ci{ 445141cc406Sopenharmony_ci unsigned int status; 446141cc406Sopenharmony_ci 447141cc406Sopenharmony_ci qc_send (q, QC_SEND_STATUS); 448141cc406Sopenharmony_ci status = qc_readparam (q); 449141cc406Sopenharmony_ci DBG (3, "qc_getstatus: status=0x%02x\n", status); 450141cc406Sopenharmony_ci return status; 451141cc406Sopenharmony_ci} 452141cc406Sopenharmony_ci 453141cc406Sopenharmony_cistatic void 454141cc406Sopenharmony_ciqc_setscanmode (QC_Scanner * s, u_int * modep) 455141cc406Sopenharmony_ci{ 456141cc406Sopenharmony_ci QC_Device *q = s->hw; 457141cc406Sopenharmony_ci u_int mode = 0; 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_ci if (q->version != QC_COLOR) 460141cc406Sopenharmony_ci { 461141cc406Sopenharmony_ci switch (s->val[OPT_XFER_SCALE].w) 462141cc406Sopenharmony_ci { 463141cc406Sopenharmony_ci case 1: 464141cc406Sopenharmony_ci mode = 0; 465141cc406Sopenharmony_ci break; 466141cc406Sopenharmony_ci case 2: 467141cc406Sopenharmony_ci mode = 4; 468141cc406Sopenharmony_ci break; 469141cc406Sopenharmony_ci case 4: 470141cc406Sopenharmony_ci mode = 8; 471141cc406Sopenharmony_ci break; 472141cc406Sopenharmony_ci } 473141cc406Sopenharmony_ci switch (s->val[OPT_DEPTH].w) 474141cc406Sopenharmony_ci { 475141cc406Sopenharmony_ci case 4: 476141cc406Sopenharmony_ci break; 477141cc406Sopenharmony_ci case 6: 478141cc406Sopenharmony_ci mode += 2; 479141cc406Sopenharmony_ci break; 480141cc406Sopenharmony_ci } 481141cc406Sopenharmony_ci } 482141cc406Sopenharmony_ci else 483141cc406Sopenharmony_ci { 484141cc406Sopenharmony_ci switch (s->val[OPT_XFER_SCALE].w) 485141cc406Sopenharmony_ci { 486141cc406Sopenharmony_ci case 1: 487141cc406Sopenharmony_ci mode = 0; 488141cc406Sopenharmony_ci break; 489141cc406Sopenharmony_ci case 2: 490141cc406Sopenharmony_ci mode = 2; 491141cc406Sopenharmony_ci break; 492141cc406Sopenharmony_ci case 4: 493141cc406Sopenharmony_ci mode = 4; 494141cc406Sopenharmony_ci break; 495141cc406Sopenharmony_ci } 496141cc406Sopenharmony_ci if (s->resolution == QC_RES_LOW) 497141cc406Sopenharmony_ci mode |= 0x18; /* millions mode */ 498141cc406Sopenharmony_ci else 499141cc406Sopenharmony_ci mode |= 0x10; /* billions mode */ 500141cc406Sopenharmony_ci } 501141cc406Sopenharmony_ci if (s->val[OPT_TEST].w) 502141cc406Sopenharmony_ci mode |= 0x40; /* test mode */ 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_ci if (q->port_mode == QC_BIDIR) 505141cc406Sopenharmony_ci mode |= 1; 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci DBG (2, "scanmode (before increment): 0x%x\n", mode); 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci if (q->version == QC_COLOR) 510141cc406Sopenharmony_ci ++mode; 511141cc406Sopenharmony_ci 512141cc406Sopenharmony_ci *modep = mode; 513141cc406Sopenharmony_ci} 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci/* Read data bytes from the camera. The number of bytes read is 516141cc406Sopenharmony_ci returned as the function result. Depending on the mode, it may be 517141cc406Sopenharmony_ci either 1, 3 or 6. On failure, 0 is returned. If buffer is 0, the 518141cc406Sopenharmony_ci internal state-machine is reset. */ 519141cc406Sopenharmony_cistatic size_t 520141cc406Sopenharmony_ciqc_readbytes (QC_Scanner * s, unsigned char buffer[]) 521141cc406Sopenharmony_ci{ 522141cc406Sopenharmony_ci QC_Device *q = s->hw; 523141cc406Sopenharmony_ci unsigned int hi, lo; 524141cc406Sopenharmony_ci unsigned int hi2, lo2; 525141cc406Sopenharmony_ci size_t bytes = 0; 526141cc406Sopenharmony_ci 527141cc406Sopenharmony_ci if (!buffer) 528141cc406Sopenharmony_ci { 529141cc406Sopenharmony_ci s->readbytes_state = 0; 530141cc406Sopenharmony_ci return 0; 531141cc406Sopenharmony_ci } 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci switch (q->port_mode) 534141cc406Sopenharmony_ci { 535141cc406Sopenharmony_ci case QC_BIDIR: 536141cc406Sopenharmony_ci /* bi-directional port */ 537141cc406Sopenharmony_ci 538141cc406Sopenharmony_ci /* read off 24 bits: */ 539141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | BiDir); 540141cc406Sopenharmony_ci lo = qc_waithand2 (q, 1) >> 1; 541141cc406Sopenharmony_ci hi = (read_lpstatus (q) >> 3) & 0x1f; 542141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck | BiDir); 543141cc406Sopenharmony_ci lo2 = qc_waithand2 (q, 0) >> 1; 544141cc406Sopenharmony_ci hi2 = (read_lpstatus (q) >> 3) & 0x1f; 545141cc406Sopenharmony_ci if (q->version == QC_COLOR) 546141cc406Sopenharmony_ci { 547141cc406Sopenharmony_ci /* is Nibble3 inverted for color quickcams only? */ 548141cc406Sopenharmony_ci hi ^= 0x10; 549141cc406Sopenharmony_ci hi2 ^= 0x10; 550141cc406Sopenharmony_ci } 551141cc406Sopenharmony_ci switch (s->val[OPT_DEPTH].w) 552141cc406Sopenharmony_ci { 553141cc406Sopenharmony_ci case 4: 554141cc406Sopenharmony_ci buffer[0] = lo & 0xf; 555141cc406Sopenharmony_ci buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); 556141cc406Sopenharmony_ci buffer[2] = (hi & 0x1e) >> 1; 557141cc406Sopenharmony_ci buffer[3] = lo2 & 0xf; 558141cc406Sopenharmony_ci buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); 559141cc406Sopenharmony_ci buffer[5] = (hi2 & 0x1e) >> 1; 560141cc406Sopenharmony_ci bytes = 6; 561141cc406Sopenharmony_ci break; 562141cc406Sopenharmony_ci 563141cc406Sopenharmony_ci case 6: 564141cc406Sopenharmony_ci buffer[0] = lo & 0x3f; 565141cc406Sopenharmony_ci buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); 566141cc406Sopenharmony_ci buffer[2] = lo2 & 0x3f; 567141cc406Sopenharmony_ci buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); 568141cc406Sopenharmony_ci bytes = 4; 569141cc406Sopenharmony_ci break; 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci case 24: 572141cc406Sopenharmony_ci buffer[0] = lo | ((hi & 0x1) << 7); 573141cc406Sopenharmony_ci buffer[1] = ((hi2 & 0x1e) >> 1) | ((hi & 0x1e) << 3); 574141cc406Sopenharmony_ci buffer[2] = lo2 | ((hi2 & 0x1) << 7); 575141cc406Sopenharmony_ci bytes = 3; 576141cc406Sopenharmony_ci break; 577141cc406Sopenharmony_ci } 578141cc406Sopenharmony_ci break; 579141cc406Sopenharmony_ci 580141cc406Sopenharmony_ci case QC_UNIDIR: /* Unidirectional Port */ 581141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N); 582141cc406Sopenharmony_ci lo = (qc_waithand (q, CamRdy1) & 0xf0) >> 4; 583141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck); 584141cc406Sopenharmony_ci hi = (qc_waithand (q, 0) & 0xf0) >> 4; 585141cc406Sopenharmony_ci 586141cc406Sopenharmony_ci if (q->version == QC_COLOR) 587141cc406Sopenharmony_ci { 588141cc406Sopenharmony_ci /* invert Nibble3 */ 589141cc406Sopenharmony_ci hi ^= 8; 590141cc406Sopenharmony_ci lo ^= 8; 591141cc406Sopenharmony_ci } 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci switch (s->val[OPT_DEPTH].w) 594141cc406Sopenharmony_ci { 595141cc406Sopenharmony_ci case 4: 596141cc406Sopenharmony_ci buffer[0] = lo; 597141cc406Sopenharmony_ci buffer[1] = hi; 598141cc406Sopenharmony_ci bytes = 2; 599141cc406Sopenharmony_ci break; 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_ci case 6: 602141cc406Sopenharmony_ci switch (s->readbytes_state) 603141cc406Sopenharmony_ci { 604141cc406Sopenharmony_ci case 0: 605141cc406Sopenharmony_ci buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); 606141cc406Sopenharmony_ci s->saved_bits = (hi & 3) << 4; 607141cc406Sopenharmony_ci s->readbytes_state = 1; 608141cc406Sopenharmony_ci bytes = 1; 609141cc406Sopenharmony_ci break; 610141cc406Sopenharmony_ci 611141cc406Sopenharmony_ci case 1: 612141cc406Sopenharmony_ci buffer[0] = lo | s->saved_bits; 613141cc406Sopenharmony_ci s->saved_bits = hi << 2; 614141cc406Sopenharmony_ci s->readbytes_state = 2; 615141cc406Sopenharmony_ci bytes = 1; 616141cc406Sopenharmony_ci break; 617141cc406Sopenharmony_ci 618141cc406Sopenharmony_ci case 2: 619141cc406Sopenharmony_ci buffer[0] = ((lo & 0xc) >> 2) | s->saved_bits; 620141cc406Sopenharmony_ci buffer[1] = ((lo & 3) << 4) | hi; 621141cc406Sopenharmony_ci s->readbytes_state = 0; 622141cc406Sopenharmony_ci bytes = 2; 623141cc406Sopenharmony_ci break; 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci default: 626141cc406Sopenharmony_ci DBG (1, "qc_readbytes: bad unidir 6-bit stat %d\n", 627141cc406Sopenharmony_ci s->readbytes_state); 628141cc406Sopenharmony_ci break; 629141cc406Sopenharmony_ci } 630141cc406Sopenharmony_ci break; 631141cc406Sopenharmony_ci 632141cc406Sopenharmony_ci case 24: 633141cc406Sopenharmony_ci buffer[0] = (lo << 4) | hi; 634141cc406Sopenharmony_ci bytes = 1; 635141cc406Sopenharmony_ci break; 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci default: 638141cc406Sopenharmony_ci DBG (1, "qc_readbytes: bad unidir bit depth %d\n", 639141cc406Sopenharmony_ci s->val[OPT_DEPTH].w); 640141cc406Sopenharmony_ci break; 641141cc406Sopenharmony_ci } 642141cc406Sopenharmony_ci break; 643141cc406Sopenharmony_ci 644141cc406Sopenharmony_ci default: 645141cc406Sopenharmony_ci DBG (1, "qc_readbytes: bad port_mode %d\n", q->port_mode); 646141cc406Sopenharmony_ci break; 647141cc406Sopenharmony_ci } 648141cc406Sopenharmony_ci return bytes; 649141cc406Sopenharmony_ci} 650141cc406Sopenharmony_ci 651141cc406Sopenharmony_cistatic void 652141cc406Sopenharmony_ciqc_reset (QC_Device * q) 653141cc406Sopenharmony_ci{ 654141cc406Sopenharmony_ci write_lpcontrol (q, Strobe | Autofeed | Reset_N | PCAck); 655141cc406Sopenharmony_ci qc_wait (q); 656141cc406Sopenharmony_ci write_lpcontrol (q, Strobe | Autofeed | PCAck); 657141cc406Sopenharmony_ci qc_wait (q); 658141cc406Sopenharmony_ci write_lpcontrol (q, Strobe | Autofeed | Reset_N | PCAck); 659141cc406Sopenharmony_ci} 660141cc406Sopenharmony_ci 661141cc406Sopenharmony_ci/* This function is executed as a child process. The reason this is 662141cc406Sopenharmony_ci executed as a subprocess is because the qcam interface directly reads 663141cc406Sopenharmony_ci off of a I/O port (rather than a filedescriptor). Thus, to have 664141cc406Sopenharmony_ci something to select() on, we transfer the data through a pipe. 665141cc406Sopenharmony_ci 666141cc406Sopenharmony_ci WARNING: Since this is executed as a subprocess, it's NOT possible 667141cc406Sopenharmony_ci to update any of the variables in the main process (in particular 668141cc406Sopenharmony_ci the scanner state cannot be updated). */ 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_cistatic jmp_buf env; 671141cc406Sopenharmony_ci 672141cc406Sopenharmony_cistatic void 673141cc406Sopenharmony_cisighandler (int signal) 674141cc406Sopenharmony_ci{ 675141cc406Sopenharmony_ci DBG (3, "sighandler: got signal %d\n", signal); 676141cc406Sopenharmony_ci longjmp (env, 1); 677141cc406Sopenharmony_ci} 678141cc406Sopenharmony_ci 679141cc406Sopenharmony_ci/* Original despeckling code by Patrick Reynolds <patrickr@virginia.edu> */ 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_cistatic void 682141cc406Sopenharmony_cidespeckle (int width, int height, SANE_Byte * in, SANE_Byte * out) 683141cc406Sopenharmony_ci{ 684141cc406Sopenharmony_ci long x, i; 685141cc406Sopenharmony_ci /* The light-check threshold. Higher numbers remove more lights but 686141cc406Sopenharmony_ci blur the image more. 30 is good for indoor lighting. */ 687141cc406Sopenharmony_ci# define NO_LIGHTS 30 688141cc406Sopenharmony_ci 689141cc406Sopenharmony_ci /* macros to make the code a little more readable, p=previous, n=next */ 690141cc406Sopenharmony_ci# define R in[i*3] 691141cc406Sopenharmony_ci# define G in[i*3+1] 692141cc406Sopenharmony_ci# define B in[i*3+2] 693141cc406Sopenharmony_ci# define pR in[i*3-3] 694141cc406Sopenharmony_ci# define pG in[i*3-2] 695141cc406Sopenharmony_ci# define pB in[i*3-1] 696141cc406Sopenharmony_ci# define nR in[i*3+3] 697141cc406Sopenharmony_ci# define nG in[i*3+4] 698141cc406Sopenharmony_ci# define nB in[i*3+5] 699141cc406Sopenharmony_ci 700141cc406Sopenharmony_ci DBG (1, "despeckle: width=%d, height=%d\n", width, height); 701141cc406Sopenharmony_ci 702141cc406Sopenharmony_ci for (x = i = 0; i < width * height; ++i) 703141cc406Sopenharmony_ci { 704141cc406Sopenharmony_ci if (x == 0 || x == width - 1) 705141cc406Sopenharmony_ci memcpy (&out[i * 3], &in[i * 3], 3); 706141cc406Sopenharmony_ci else 707141cc406Sopenharmony_ci { 708141cc406Sopenharmony_ci if (R - (G + B) / 2 > 709141cc406Sopenharmony_ci NO_LIGHTS + ((pR - (pG + pB) / 2) + (nR - (nG + nB) / 2))) 710141cc406Sopenharmony_ci out[i * 3] = (pR + nR) / 2; 711141cc406Sopenharmony_ci else 712141cc406Sopenharmony_ci out[i * 3] = R; 713141cc406Sopenharmony_ci 714141cc406Sopenharmony_ci if (G - (R + B) / 2 > 715141cc406Sopenharmony_ci NO_LIGHTS + ((pG - (pR + pB) / 2) + (nG - (nR + nB) / 2))) 716141cc406Sopenharmony_ci out[i * 3 + 1] = (pG + nG) / 2; 717141cc406Sopenharmony_ci else 718141cc406Sopenharmony_ci out[i * 3 + 1] = G; 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci if (B - (G + R) / 2 > 721141cc406Sopenharmony_ci NO_LIGHTS + ((pB - (pG + pR) / 2) + (nB - (nG + nR) / 2))) 722141cc406Sopenharmony_ci out[i * 3 + 2] = (pB + nB) / 2; 723141cc406Sopenharmony_ci else 724141cc406Sopenharmony_ci out[i * 3 + 2] = B; 725141cc406Sopenharmony_ci } 726141cc406Sopenharmony_ci if (++x >= width) 727141cc406Sopenharmony_ci x = 0; 728141cc406Sopenharmony_ci } 729141cc406Sopenharmony_ci# undef R 730141cc406Sopenharmony_ci# undef G 731141cc406Sopenharmony_ci# undef B 732141cc406Sopenharmony_ci# undef pR 733141cc406Sopenharmony_ci# undef pG 734141cc406Sopenharmony_ci# undef pB 735141cc406Sopenharmony_ci# undef nR 736141cc406Sopenharmony_ci# undef nG 737141cc406Sopenharmony_ci# undef nB 738141cc406Sopenharmony_ci} 739141cc406Sopenharmony_ci 740141cc406Sopenharmony_cistatic void 741141cc406Sopenharmony_cidespeckle32 (int width, int height, SANE_Byte * in, SANE_Byte * out) 742141cc406Sopenharmony_ci{ 743141cc406Sopenharmony_ci long x, i; 744141cc406Sopenharmony_ci /* macros to make the code a little more readable, p=previous, n=next */ 745141cc406Sopenharmony_ci# define B in[i*4] 746141cc406Sopenharmony_ci# define Ga in[i*4 + 1] 747141cc406Sopenharmony_ci# define Gb in[i*4 + 1] /* ignore Gb and use Ga instead---Gb is weird */ 748141cc406Sopenharmony_ci# define R in[i*4 + 3] 749141cc406Sopenharmony_ci# define pB in[i*4 - 4] 750141cc406Sopenharmony_ci# define pGa in[i*4 - 3] 751141cc406Sopenharmony_ci# define pGb in[i*4 - 1] /* ignore Gb and use Ga instead---Gb is weird */ 752141cc406Sopenharmony_ci# define pR in[i*4 - 1] 753141cc406Sopenharmony_ci# define nB in[i*4 + 4] 754141cc406Sopenharmony_ci# define nGa in[i*4 + 5] 755141cc406Sopenharmony_ci# define nGb in[i*4 + 5] /* ignore Gb and use Ga instead---Gb is weird */ 756141cc406Sopenharmony_ci# define nR in[i*4 + 7] 757141cc406Sopenharmony_ci 758141cc406Sopenharmony_ci DBG (1, "despeckle32: width=%d, height=%d\n", width, height); 759141cc406Sopenharmony_ci 760141cc406Sopenharmony_ci for (x = i = 0; i < width * height; ++i) 761141cc406Sopenharmony_ci { 762141cc406Sopenharmony_ci if (x == 0 || x == width - 1) 763141cc406Sopenharmony_ci memcpy (&out[i * 4], &in[i * 4], 4); 764141cc406Sopenharmony_ci else 765141cc406Sopenharmony_ci { 766141cc406Sopenharmony_ci if (x >= width - 2) 767141cc406Sopenharmony_ci /* the last red pixel seems to be black at all times, use 768141cc406Sopenharmony_ci R instead: */ 769141cc406Sopenharmony_ci nR = R; 770141cc406Sopenharmony_ci 771141cc406Sopenharmony_ci if (R - ((Ga + Gb) / 2 + B) / 2 > 772141cc406Sopenharmony_ci NO_LIGHTS + ((pR - ((pGa + pGb) / 2 + pB) / 2) + 773141cc406Sopenharmony_ci (nR - ((nGa + nGb) / 2 + nB) / 2))) 774141cc406Sopenharmony_ci out[i * 4 + 3] = (pR + nR) / 2; 775141cc406Sopenharmony_ci else 776141cc406Sopenharmony_ci out[i * 4 + 3] = R; 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_ci if (Ga - (R + B) / 2 > NO_LIGHTS + ((pGa - (pR + pB) / 2) + 779141cc406Sopenharmony_ci (nGa - (nR + nB) / 2))) 780141cc406Sopenharmony_ci out[i * 4 + 1] = (pGa + nGa) / 2; 781141cc406Sopenharmony_ci else 782141cc406Sopenharmony_ci out[i * 4 + 1] = Ga; 783141cc406Sopenharmony_ci 784141cc406Sopenharmony_ci if (Gb - (R + B) / 2 > NO_LIGHTS + ((pGb - (pR + pB) / 2) + 785141cc406Sopenharmony_ci (nGb - (nR + nB) / 2))) 786141cc406Sopenharmony_ci out[i * 4 + 2] = (pGb + nGb) / 2; 787141cc406Sopenharmony_ci else 788141cc406Sopenharmony_ci out[i * 4 + 2] = Gb; 789141cc406Sopenharmony_ci 790141cc406Sopenharmony_ci if (B - ((Ga + Gb) / 2 + R) / 2 > 791141cc406Sopenharmony_ci NO_LIGHTS + ((pB - ((pGa + pGb) / 2 + pR) / 2) + 792141cc406Sopenharmony_ci (nB - ((nGa + nGb) / 2 + nR) / 2))) 793141cc406Sopenharmony_ci out[i * 4 + 0] = (pB + nB) / 2; 794141cc406Sopenharmony_ci else 795141cc406Sopenharmony_ci out[i * 4 + 0] = B; 796141cc406Sopenharmony_ci } 797141cc406Sopenharmony_ci if (++x >= width) 798141cc406Sopenharmony_ci x = 0; 799141cc406Sopenharmony_ci } 800141cc406Sopenharmony_ci# undef R 801141cc406Sopenharmony_ci# undef Ga 802141cc406Sopenharmony_ci# undef Gb 803141cc406Sopenharmony_ci# undef B 804141cc406Sopenharmony_ci# undef pR 805141cc406Sopenharmony_ci# undef pGa 806141cc406Sopenharmony_ci# undef pGb 807141cc406Sopenharmony_ci# undef pB 808141cc406Sopenharmony_ci# undef nR 809141cc406Sopenharmony_ci# undef nGa 810141cc406Sopenharmony_ci# undef nGb 811141cc406Sopenharmony_ci# undef nB 812141cc406Sopenharmony_ci} 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_cistatic int 815141cc406Sopenharmony_cireader_process (QC_Scanner * s, int in_fd, int out_fd) 816141cc406Sopenharmony_ci{ 817141cc406Sopenharmony_ci static SANE_Byte *buffer = 0, *extra = 0; 818141cc406Sopenharmony_ci static size_t buffer_size = 0; 819141cc406Sopenharmony_ci size_t count, len, num_bytes; 820141cc406Sopenharmony_ci QC_Device *q = s->hw; 821141cc406Sopenharmony_ci QC_Scan_Request req; 822141cc406Sopenharmony_ci int width, height; 823141cc406Sopenharmony_ci SANE_Byte *src; 824141cc406Sopenharmony_ci FILE *ofp; 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci DBG (5, "reader_process: enter\n"); 827141cc406Sopenharmony_ci 828141cc406Sopenharmony_ci enable_ports (q); 829141cc406Sopenharmony_ci 830141cc406Sopenharmony_ci ofp = fdopen (out_fd, "w"); 831141cc406Sopenharmony_ci if (!ofp) 832141cc406Sopenharmony_ci return 1; 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci while (1) 835141cc406Sopenharmony_ci { 836141cc406Sopenharmony_ci if (setjmp (env)) 837141cc406Sopenharmony_ci { 838141cc406Sopenharmony_ci char ch; 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci /* acknowledge the signal: */ 841141cc406Sopenharmony_ci DBG (1, "reader_process: sending signal ACK\n"); 842141cc406Sopenharmony_ci fwrite (&ch, 1, 1, ofp); 843141cc406Sopenharmony_ci fflush (ofp); /* force everything out the pipe */ 844141cc406Sopenharmony_ci continue; 845141cc406Sopenharmony_ci } 846141cc406Sopenharmony_ci signal (SIGINT, sighandler); 847141cc406Sopenharmony_ci 848141cc406Sopenharmony_ci /* the main process gets us started by writing a size_t giving 849141cc406Sopenharmony_ci the number of bytes we should expect: */ 850141cc406Sopenharmony_ci if (read (in_fd, &req, sizeof (req)) != sizeof (req)) 851141cc406Sopenharmony_ci { 852141cc406Sopenharmony_ci perror ("read"); 853141cc406Sopenharmony_ci return 1; 854141cc406Sopenharmony_ci } 855141cc406Sopenharmony_ci num_bytes = req.num_bytes; 856141cc406Sopenharmony_ci 857141cc406Sopenharmony_ci DBG (3, "reader_process: got request for %lu bytes\n", 858141cc406Sopenharmony_ci (u_long) num_bytes); 859141cc406Sopenharmony_ci 860141cc406Sopenharmony_ci /* Don't do this in sane_start() since there may be a long 861141cc406Sopenharmony_ci timespan between it and the first sane_read(), which would 862141cc406Sopenharmony_ci result in poor images. */ 863141cc406Sopenharmony_ci qc_send (q, QC_SEND_VIDEO_FRAME); 864141cc406Sopenharmony_ci qc_send (q, req.mode); 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci if (req.despeckle 867141cc406Sopenharmony_ci && (!extra || buffer_size < num_bytes 868141cc406Sopenharmony_ci || buffer_size >= 2 * num_bytes)) 869141cc406Sopenharmony_ci { 870141cc406Sopenharmony_ci if (extra) 871141cc406Sopenharmony_ci extra = realloc (extra, num_bytes); 872141cc406Sopenharmony_ci else 873141cc406Sopenharmony_ci extra = malloc (num_bytes); 874141cc406Sopenharmony_ci if (!extra) 875141cc406Sopenharmony_ci { 876141cc406Sopenharmony_ci DBG (1, "reader_process: malloc(%ld) failed\n", 877141cc406Sopenharmony_ci (long) num_bytes); 878141cc406Sopenharmony_ci exit (1); 879141cc406Sopenharmony_ci } 880141cc406Sopenharmony_ci } 881141cc406Sopenharmony_ci 882141cc406Sopenharmony_ci if (buffer_size < num_bytes || buffer_size >= 2 * num_bytes) 883141cc406Sopenharmony_ci { 884141cc406Sopenharmony_ci if (buffer) 885141cc406Sopenharmony_ci buffer = realloc (buffer, num_bytes); 886141cc406Sopenharmony_ci else 887141cc406Sopenharmony_ci buffer = malloc (num_bytes); 888141cc406Sopenharmony_ci if (!buffer) 889141cc406Sopenharmony_ci { 890141cc406Sopenharmony_ci DBG (1, "reader_process: malloc(%ld) failed\n", 891141cc406Sopenharmony_ci (long) num_bytes); 892141cc406Sopenharmony_ci exit (1); 893141cc406Sopenharmony_ci } 894141cc406Sopenharmony_ci buffer_size = num_bytes; 895141cc406Sopenharmony_ci } 896141cc406Sopenharmony_ci 897141cc406Sopenharmony_ci if (q->port_mode == QC_BIDIR) 898141cc406Sopenharmony_ci { 899141cc406Sopenharmony_ci /* turn port into input port */ 900141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck | BiDir); 901141cc406Sopenharmony_ci usleep (3); 902141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | BiDir); 903141cc406Sopenharmony_ci qc_waithand (q, CamRdy1); 904141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck | BiDir); 905141cc406Sopenharmony_ci qc_waithand (q, 0); 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci if (q->version == QC_COLOR) 909141cc406Sopenharmony_ci for (len = 0; len < num_bytes; len += count) 910141cc406Sopenharmony_ci count = qc_readbytes (s, buffer + len); 911141cc406Sopenharmony_ci else 912141cc406Sopenharmony_ci { 913141cc406Sopenharmony_ci /* strange -- should be 15:63 below, but 4bpp is odd */ 914141cc406Sopenharmony_ci int shift, invert; 915141cc406Sopenharmony_ci unsigned int i; 916141cc406Sopenharmony_ci u_char val; 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_ci switch (s->val[OPT_DEPTH].w) 919141cc406Sopenharmony_ci { 920141cc406Sopenharmony_ci case 4: 921141cc406Sopenharmony_ci invert = 16; 922141cc406Sopenharmony_ci shift = 4; 923141cc406Sopenharmony_ci break; 924141cc406Sopenharmony_ci 925141cc406Sopenharmony_ci case 6: 926141cc406Sopenharmony_ci invert = 63; 927141cc406Sopenharmony_ci shift = 2; 928141cc406Sopenharmony_ci break; 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci default: 931141cc406Sopenharmony_ci DBG (1, "reader_process: unexpected depth %d\n", 932141cc406Sopenharmony_ci s->val[OPT_DEPTH].w); 933141cc406Sopenharmony_ci return 1; 934141cc406Sopenharmony_ci } 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ci for (len = 0; len < num_bytes; len += count) 937141cc406Sopenharmony_ci { 938141cc406Sopenharmony_ci count = qc_readbytes (s, buffer + len); 939141cc406Sopenharmony_ci for (i = 0; i < count; ++i) 940141cc406Sopenharmony_ci { 941141cc406Sopenharmony_ci /* 4bpp is odd (again) -- inverter is 16, not 15, 942141cc406Sopenharmony_ci but output must be 0-15 */ 943141cc406Sopenharmony_ci val = buffer[len + i]; 944141cc406Sopenharmony_ci if (val > 0 || invert != 16) 945141cc406Sopenharmony_ci val = invert - val; 946141cc406Sopenharmony_ci buffer[len + i] = (val << shift) | (val >> (8 - 2 * shift)); 947141cc406Sopenharmony_ci } 948141cc406Sopenharmony_ci } 949141cc406Sopenharmony_ci qc_readbytes (s, 0); /* reset state machine */ 950141cc406Sopenharmony_ci } 951141cc406Sopenharmony_ci /* we're done reading this frame: */ 952141cc406Sopenharmony_ci DBG (2, "reader_process: frame complete\n"); 953141cc406Sopenharmony_ci 954141cc406Sopenharmony_ci if (q->port_mode == QC_BIDIR) 955141cc406Sopenharmony_ci { 956141cc406Sopenharmony_ci /* return port to output mode */ 957141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed); 958141cc406Sopenharmony_ci usleep (3); 959141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N); 960141cc406Sopenharmony_ci usleep (3); 961141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck); 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci 964141cc406Sopenharmony_ci if (req.resolution == QC_RES_HIGH) 965141cc406Sopenharmony_ci { 966141cc406Sopenharmony_ci SANE_Byte buf[6]; 967141cc406Sopenharmony_ci int x, y; 968141cc406Sopenharmony_ci 969141cc406Sopenharmony_ci /* in billions mode, we need to oversample the data: */ 970141cc406Sopenharmony_ci src = buffer; 971141cc406Sopenharmony_ci width = req.params.pixels_per_line; 972141cc406Sopenharmony_ci height = req.params.lines; 973141cc406Sopenharmony_ci 974141cc406Sopenharmony_ci if (req.despeckle) 975141cc406Sopenharmony_ci { 976141cc406Sopenharmony_ci despeckle32 (width / 2, req.params.lines / 2, buffer, extra); 977141cc406Sopenharmony_ci src = extra; 978141cc406Sopenharmony_ci } 979141cc406Sopenharmony_ci 980141cc406Sopenharmony_ci assert (!(width & 1)); /* width must be even */ 981141cc406Sopenharmony_ci 982141cc406Sopenharmony_ci for (y = 0; y < height; ++y) 983141cc406Sopenharmony_ci { 984141cc406Sopenharmony_ci /* even line */ 985141cc406Sopenharmony_ci 986141cc406Sopenharmony_ci for (x = 0; x < width; x += 2) 987141cc406Sopenharmony_ci { 988141cc406Sopenharmony_ci int red1, green1, blue1, green2, blue2; 989141cc406Sopenharmony_ci 990141cc406Sopenharmony_ci blue1 = src[0]; 991141cc406Sopenharmony_ci green1 = src[1]; 992141cc406Sopenharmony_ci red1 = src[3]; 993141cc406Sopenharmony_ci if (x >= width - 2) 994141cc406Sopenharmony_ci { 995141cc406Sopenharmony_ci red1 = src[-1]; /* last red seems to be missing */ 996141cc406Sopenharmony_ci blue2 = blue1; 997141cc406Sopenharmony_ci green2 = green1; 998141cc406Sopenharmony_ci } 999141cc406Sopenharmony_ci else 1000141cc406Sopenharmony_ci { 1001141cc406Sopenharmony_ci blue2 = src[4]; 1002141cc406Sopenharmony_ci green2 = src[5]; 1003141cc406Sopenharmony_ci } 1004141cc406Sopenharmony_ci src += 4; 1005141cc406Sopenharmony_ci 1006141cc406Sopenharmony_ci buf[0] = red1; 1007141cc406Sopenharmony_ci buf[1] = green1; 1008141cc406Sopenharmony_ci buf[2] = blue1; 1009141cc406Sopenharmony_ci buf[3] = red1; 1010141cc406Sopenharmony_ci buf[4] = green2; 1011141cc406Sopenharmony_ci buf[5] = blue2; 1012141cc406Sopenharmony_ci if (fwrite (buf, 1, 6, ofp) != 6) 1013141cc406Sopenharmony_ci { 1014141cc406Sopenharmony_ci perror ("fwrite: short write"); 1015141cc406Sopenharmony_ci return 1; 1016141cc406Sopenharmony_ci } 1017141cc406Sopenharmony_ci } 1018141cc406Sopenharmony_ci if (++y >= height) 1019141cc406Sopenharmony_ci break; 1020141cc406Sopenharmony_ci 1021141cc406Sopenharmony_ci src -= 2 * width; /* 4 bytes/pixel -> 2 pixels of 3 bytes each */ 1022141cc406Sopenharmony_ci 1023141cc406Sopenharmony_ci /* odd line */ 1024141cc406Sopenharmony_ci for (x = 0; x < width; x += 2) 1025141cc406Sopenharmony_ci { 1026141cc406Sopenharmony_ci int red1, green3, blue3, green4, blue4; 1027141cc406Sopenharmony_ci int yoff; 1028141cc406Sopenharmony_ci 1029141cc406Sopenharmony_ci if (x >= width - 2) 1030141cc406Sopenharmony_ci red1 = src[-1]; /* last red seems to be missing */ 1031141cc406Sopenharmony_ci else 1032141cc406Sopenharmony_ci red1 = src[3]; 1033141cc406Sopenharmony_ci yoff = 2 * width; 1034141cc406Sopenharmony_ci if (y >= height - 1) 1035141cc406Sopenharmony_ci yoff = 0; 1036141cc406Sopenharmony_ci green3 = src[yoff + 1]; 1037141cc406Sopenharmony_ci blue3 = src[yoff + 0]; 1038141cc406Sopenharmony_ci if (x >= width - 2) 1039141cc406Sopenharmony_ci { 1040141cc406Sopenharmony_ci blue4 = blue3; 1041141cc406Sopenharmony_ci green4 = green3; 1042141cc406Sopenharmony_ci } 1043141cc406Sopenharmony_ci else 1044141cc406Sopenharmony_ci { 1045141cc406Sopenharmony_ci blue4 = src[yoff + 4]; 1046141cc406Sopenharmony_ci green4 = src[yoff + 5]; 1047141cc406Sopenharmony_ci } 1048141cc406Sopenharmony_ci src += 4; 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_ci buf[0] = red1; 1051141cc406Sopenharmony_ci buf[1] = green3; 1052141cc406Sopenharmony_ci buf[2] = blue3; 1053141cc406Sopenharmony_ci buf[3] = red1; 1054141cc406Sopenharmony_ci buf[4] = green4; 1055141cc406Sopenharmony_ci buf[5] = blue4; 1056141cc406Sopenharmony_ci if (fwrite (buf, 1, 6, ofp) != 6) 1057141cc406Sopenharmony_ci { 1058141cc406Sopenharmony_ci perror ("fwrite: short write"); 1059141cc406Sopenharmony_ci return 1; 1060141cc406Sopenharmony_ci } 1061141cc406Sopenharmony_ci } 1062141cc406Sopenharmony_ci } 1063141cc406Sopenharmony_ci } 1064141cc406Sopenharmony_ci else 1065141cc406Sopenharmony_ci { 1066141cc406Sopenharmony_ci src = buffer; 1067141cc406Sopenharmony_ci if (req.despeckle) 1068141cc406Sopenharmony_ci { 1069141cc406Sopenharmony_ci despeckle (req.params.pixels_per_line, req.params.lines, 1070141cc406Sopenharmony_ci buffer, extra); 1071141cc406Sopenharmony_ci src = extra; 1072141cc406Sopenharmony_ci } 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci /* now write the whole thing to the main process: */ 1075141cc406Sopenharmony_ci if (fwrite (src, 1, num_bytes, ofp) != num_bytes) 1076141cc406Sopenharmony_ci { 1077141cc406Sopenharmony_ci perror ("fwrite: short write"); 1078141cc406Sopenharmony_ci return 1; 1079141cc406Sopenharmony_ci } 1080141cc406Sopenharmony_ci } 1081141cc406Sopenharmony_ci fflush (ofp); 1082141cc406Sopenharmony_ci } 1083141cc406Sopenharmony_ci assert (SANE_FALSE); /* not reached */ 1084141cc406Sopenharmony_ci DBG (5, "reader_process: exit\n"); 1085141cc406Sopenharmony_ci return 1; 1086141cc406Sopenharmony_ci} 1087141cc406Sopenharmony_ci 1088141cc406Sopenharmony_cistatic SANE_Status 1089141cc406Sopenharmony_ciattach (const char *devname, QC_Device ** devp) 1090141cc406Sopenharmony_ci{ 1091141cc406Sopenharmony_ci int i, n1, n2, s1, s2, cmd, port, force_unidir; 1092141cc406Sopenharmony_ci SANE_Status result, status; 1093141cc406Sopenharmony_ci QC_Device *q; 1094141cc406Sopenharmony_ci char *endp; 1095141cc406Sopenharmony_ci 1096141cc406Sopenharmony_ci DBG (3, "attach: enter\n"); 1097141cc406Sopenharmony_ci errno = 0; 1098141cc406Sopenharmony_ci force_unidir = 0; 1099141cc406Sopenharmony_ci if (devname[0] == 'u') 1100141cc406Sopenharmony_ci { 1101141cc406Sopenharmony_ci force_unidir = 1; 1102141cc406Sopenharmony_ci ++devname; 1103141cc406Sopenharmony_ci } 1104141cc406Sopenharmony_ci port = strtol (devname, &endp, 0); 1105141cc406Sopenharmony_ci if (endp == devname || errno == ERANGE) 1106141cc406Sopenharmony_ci { 1107141cc406Sopenharmony_ci DBG (1, "attach: invalid port address `%s'\n", devname); 1108141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1109141cc406Sopenharmony_ci } 1110141cc406Sopenharmony_ci 1111141cc406Sopenharmony_ci for (q = first_dev; q; q = q->next) 1112141cc406Sopenharmony_ci if (port == q->port) 1113141cc406Sopenharmony_ci { 1114141cc406Sopenharmony_ci if (devp) 1115141cc406Sopenharmony_ci *devp = q; 1116141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1117141cc406Sopenharmony_ci } 1118141cc406Sopenharmony_ci 1119141cc406Sopenharmony_ci q = malloc (sizeof (*q)); 1120141cc406Sopenharmony_ci if (!q) 1121141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_ci memset (q, 0, sizeof (*q)); 1124141cc406Sopenharmony_ci q->port = port; 1125141cc406Sopenharmony_ci q->lock_fd = -1; 1126141cc406Sopenharmony_ci 1127141cc406Sopenharmony_ci result = enable_ports (q); 1128141cc406Sopenharmony_ci if (result != SANE_STATUS_GOOD) 1129141cc406Sopenharmony_ci { 1130141cc406Sopenharmony_ci DBG (1, "attach: cannot enable ports (%s)\n", strerror (errno)); 1131141cc406Sopenharmony_ci free (q); 1132141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1133141cc406Sopenharmony_ci } 1134141cc406Sopenharmony_ci 1135141cc406Sopenharmony_ci /* lock camera while we determine its version: */ 1136141cc406Sopenharmony_ci qc_lock (q); 1137141cc406Sopenharmony_ci 1138141cc406Sopenharmony_ci qc_reset (q); 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci write_lpdata (q, QC_SEND_VERSION); 1141141cc406Sopenharmony_ci qc_wait (q); 1142141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N); /* make PCAck inactive */ 1143141cc406Sopenharmony_ci qc_wait (q); 1144141cc406Sopenharmony_ci 1145141cc406Sopenharmony_ci for (i = 0; (i < 1000) && !(s1 = (n1 = read_lpstatus (q)) & CamRdy1); i++); 1146141cc406Sopenharmony_ci if (!s1) 1147141cc406Sopenharmony_ci { 1148141cc406Sopenharmony_ci DBG (2, "attach: failed to get CamRdy1 at port 0x%x\n", q->port); 1149141cc406Sopenharmony_ci goto unlock_and_fail; 1150141cc406Sopenharmony_ci } 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci write_lpcontrol (q, Autofeed | Reset_N | PCAck); 1153141cc406Sopenharmony_ci qc_wait (q); 1154141cc406Sopenharmony_ci 1155141cc406Sopenharmony_ci for (i = 0; (i < 1000) && (s2 = (n2 = read_lpstatus (q)) & CamRdy1); i++); 1156141cc406Sopenharmony_ci if (s2) 1157141cc406Sopenharmony_ci { 1158141cc406Sopenharmony_ci DBG (2, "attach: CamRdy1 failed to clear at port 0x%x\n", q->port); 1159141cc406Sopenharmony_ci goto unlock_and_fail; 1160141cc406Sopenharmony_ci } 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); 1163141cc406Sopenharmony_ci 1164141cc406Sopenharmony_ci if (cmd != QC_SEND_VERSION) 1165141cc406Sopenharmony_ci { 1166141cc406Sopenharmony_ci DBG (2, "attach: got 0x%02x instead of 0x%02x\n", cmd, QC_SEND_VERSION); 1167141cc406Sopenharmony_ci goto unlock_and_fail; 1168141cc406Sopenharmony_ci } 1169141cc406Sopenharmony_ci 1170141cc406Sopenharmony_ci q->version = qc_readparam (q); 1171141cc406Sopenharmony_ci DBG (1, "attach: found QuickCam version 0x%02x\n", q->version); 1172141cc406Sopenharmony_ci 1173141cc406Sopenharmony_ci q->port_mode = QC_UNIDIR; 1174141cc406Sopenharmony_ci if (!force_unidir) 1175141cc406Sopenharmony_ci { 1176141cc406Sopenharmony_ci write_lpcontrol (q, BiDir); 1177141cc406Sopenharmony_ci write_lpdata (q, 0x75); 1178141cc406Sopenharmony_ci if (read_lpdata (q) != 0x75) 1179141cc406Sopenharmony_ci q->port_mode = QC_BIDIR; 1180141cc406Sopenharmony_ci } 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci /* For some reason the color quickcam needs two set-black commands 1183141cc406Sopenharmony_ci after a reset. Thus, we now set the black-level to some 1184141cc406Sopenharmony_ci reasonable value (0) so that the next set-black level command 1185141cc406Sopenharmony_ci will really go through. */ 1186141cc406Sopenharmony_ci if (q->version == QC_COLOR) 1187141cc406Sopenharmony_ci { 1188141cc406Sopenharmony_ci qc_send (q, QC_SET_BLACK); 1189141cc406Sopenharmony_ci qc_send (q, 0); 1190141cc406Sopenharmony_ci 1191141cc406Sopenharmony_ci DBG (3, "attach: resetting black_level\n"); 1192141cc406Sopenharmony_ci 1193141cc406Sopenharmony_ci /* wait for set black level command to finish: */ 1194141cc406Sopenharmony_ci while (qc_getstatus (q) & (CameraNotReady | BlackBalanceInProgress)) 1195141cc406Sopenharmony_ci usleep (10000); 1196141cc406Sopenharmony_ci } 1197141cc406Sopenharmony_ci 1198141cc406Sopenharmony_ci status = qc_unlock (q); 1199141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1200141cc406Sopenharmony_ci { 1201141cc406Sopenharmony_ci DBG (1, "attach: status qc_unlock NOK\n"); 1202141cc406Sopenharmony_ci /* status = SANE_STATUS_GOOD; */ 1203141cc406Sopenharmony_ci } 1204141cc406Sopenharmony_ci q->sane.name = strdup (devname); 1205141cc406Sopenharmony_ci q->sane.vendor = "Connectix"; 1206141cc406Sopenharmony_ci q->sane.model = 1207141cc406Sopenharmony_ci (q->version == QC_COLOR) ? "Color QuickCam" : "B&W QuickCam"; 1208141cc406Sopenharmony_ci q->sane.type = "video camera"; 1209141cc406Sopenharmony_ci 1210141cc406Sopenharmony_ci ++num_devices; 1211141cc406Sopenharmony_ci q->next = first_dev; 1212141cc406Sopenharmony_ci first_dev = q; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci if (devp) 1215141cc406Sopenharmony_ci *devp = q; 1216141cc406Sopenharmony_ci DBG (3, "attach: exit status OK\n"); 1217141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 1218141cc406Sopenharmony_ci return status; 1219141cc406Sopenharmony_ci 1220141cc406Sopenharmony_ci 1221141cc406Sopenharmony_ciunlock_and_fail: 1222141cc406Sopenharmony_ci status = qc_unlock (q); 1223141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1224141cc406Sopenharmony_ci { 1225141cc406Sopenharmony_ci DBG (1, "attach: unlock_and_fail status qc_unlock NOK\n"); 1226141cc406Sopenharmony_ci } 1227141cc406Sopenharmony_ci free (q); 1228141cc406Sopenharmony_ci DBG (3, "attach: exit status NOK\n"); 1229141cc406Sopenharmony_ci status = SANE_STATUS_INVAL; 1230141cc406Sopenharmony_ci return status; 1231141cc406Sopenharmony_ci} 1232141cc406Sopenharmony_ci 1233141cc406Sopenharmony_cistatic SANE_Status 1234141cc406Sopenharmony_ciinit_options (QC_Scanner * s) 1235141cc406Sopenharmony_ci{ 1236141cc406Sopenharmony_ci int i; 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci DBG (3, "init_options: enter\n"); 1239141cc406Sopenharmony_ci 1240141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 1241141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 1244141cc406Sopenharmony_ci { 1245141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 1246141cc406Sopenharmony_ci s->opt[i].cap = (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT); 1247141cc406Sopenharmony_ci } 1248141cc406Sopenharmony_ci 1249141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 1250141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 1251141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 1252141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 1253141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 1254141cc406Sopenharmony_ci 1255141cc406Sopenharmony_ci /* "Mode" group: */ 1256141cc406Sopenharmony_ci 1257141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 1258141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 1259141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 1260141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 1261141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 1262141cc406Sopenharmony_ci 1263141cc406Sopenharmony_ci /* resolution */ 1264141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 1265141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 1266141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 1267141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].type = SANE_TYPE_STRING; 1268141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].size = 5; /* sizeof("High") */ 1269141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].unit = SANE_UNIT_NONE; 1270141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_STRING_LIST; 1271141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint.string_list = resolution_list; 1272141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].s = strdup (resolution_list[QC_RES_LOW]); 1273141cc406Sopenharmony_ci 1274141cc406Sopenharmony_ci /* bit-depth */ 1275141cc406Sopenharmony_ci s->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH; 1276141cc406Sopenharmony_ci s->opt[OPT_DEPTH].title = "Pixel depth"; 1277141cc406Sopenharmony_ci s->opt[OPT_DEPTH].desc = "Number of bits per pixel."; 1278141cc406Sopenharmony_ci s->opt[OPT_DEPTH].type = SANE_TYPE_INT; 1279141cc406Sopenharmony_ci s->opt[OPT_DEPTH].unit = SANE_UNIT_BIT; 1280141cc406Sopenharmony_ci s->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; 1281141cc406Sopenharmony_ci s->opt[OPT_DEPTH].constraint.word_list = color_depth_list; 1282141cc406Sopenharmony_ci s->val[OPT_DEPTH].w = color_depth_list[NELEMS (color_depth_list) - 1]; 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci /* test */ 1285141cc406Sopenharmony_ci s->opt[OPT_TEST].name = "test-image"; 1286141cc406Sopenharmony_ci s->opt[OPT_TEST].title = "Force test image"; 1287141cc406Sopenharmony_ci s->opt[OPT_TEST].desc = 1288141cc406Sopenharmony_ci "Acquire a test-image instead of the image seen by the camera. " 1289141cc406Sopenharmony_ci "The test image consists of red, green, and blue squares of " 1290141cc406Sopenharmony_ci "32x32 pixels each. Use this to find out whether the " 1291141cc406Sopenharmony_ci "camera is connected properly."; 1292141cc406Sopenharmony_ci s->opt[OPT_TEST].type = SANE_TYPE_BOOL; 1293141cc406Sopenharmony_ci s->val[OPT_TEST].w = SANE_FALSE; 1294141cc406Sopenharmony_ci 1295141cc406Sopenharmony_ci /* "Geometry" group: */ 1296141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 1297141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 1298141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 1299141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 1300141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 1301141cc406Sopenharmony_ci 1302141cc406Sopenharmony_ci /* top-left x */ 1303141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 1304141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 1305141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 1306141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_INT; 1307141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; 1308141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 1309141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &x_range[QC_RES_LOW]; 1310141cc406Sopenharmony_ci s->val[OPT_TL_X].w = 10; 1311141cc406Sopenharmony_ci 1312141cc406Sopenharmony_ci /* top-left y */ 1313141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 1314141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 1315141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 1316141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_INT; 1317141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; 1318141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 1319141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &y_range[QC_RES_LOW]; 1320141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = 0; 1321141cc406Sopenharmony_ci 1322141cc406Sopenharmony_ci /* bottom-right x */ 1323141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 1324141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 1325141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 1326141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_INT; 1327141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; 1328141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 1329141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &odd_x_range[QC_RES_LOW]; 1330141cc406Sopenharmony_ci s->val[OPT_BR_X].w = 339; 1331141cc406Sopenharmony_ci 1332141cc406Sopenharmony_ci /* bottom-right y */ 1333141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 1334141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 1335141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 1336141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_INT; 1337141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; 1338141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 1339141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &odd_y_range[QC_RES_LOW]; 1340141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = 245; 1341141cc406Sopenharmony_ci 1342141cc406Sopenharmony_ci /* xfer-scale */ 1343141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].name = "transfer-scale"; 1344141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].title = "Transfer scale"; 1345141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].desc = 1346141cc406Sopenharmony_ci "The transferscale determines how many of the acquired pixels actually " 1347141cc406Sopenharmony_ci "get sent to the computer. For example, a transfer scale of 2 would " 1348141cc406Sopenharmony_ci "request that every other acquired pixel would be omitted. That is, " 1349141cc406Sopenharmony_ci "when scanning a 200 pixel wide and 100 pixel tall area, the resulting " 1350141cc406Sopenharmony_ci "image would be only 100x50 pixels large. Using a large transfer scale " 1351141cc406Sopenharmony_ci "improves acquisition speed, but reduces resolution."; 1352141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].type = SANE_TYPE_INT; 1353141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].constraint_type = SANE_CONSTRAINT_WORD_LIST; 1354141cc406Sopenharmony_ci s->opt[OPT_XFER_SCALE].constraint.word_list = xfer_scale_list; 1355141cc406Sopenharmony_ci s->val[OPT_XFER_SCALE].w = xfer_scale_list[1]; 1356141cc406Sopenharmony_ci 1357141cc406Sopenharmony_ci /* despeckle */ 1358141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].name = "despeckle"; 1359141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].title = "Speckle filter"; 1360141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].desc = "Turning on this filter will remove the " 1361141cc406Sopenharmony_ci "christmas lights that are typically present in dark images."; 1362141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].type = SANE_TYPE_BOOL; 1363141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].constraint_type = SANE_CONSTRAINT_NONE; 1364141cc406Sopenharmony_ci s->val[OPT_DESPECKLE].w = 0; 1365141cc406Sopenharmony_ci 1366141cc406Sopenharmony_ci 1367141cc406Sopenharmony_ci /* "Enhancement" group: */ 1368141cc406Sopenharmony_ci 1369141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 1370141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 1371141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 1372141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 1373141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 1374141cc406Sopenharmony_ci 1375141cc406Sopenharmony_ci /* brightness */ 1376141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 1377141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 1378141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS 1379141cc406Sopenharmony_ci " In a conventional camera, this control corresponds to the " 1380141cc406Sopenharmony_ci "exposure time."; 1381141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; 1382141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_AUTOMATIC; 1383141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 1384141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &brightness_range; 1385141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = 135; 1386141cc406Sopenharmony_ci 1387141cc406Sopenharmony_ci /* contrast */ 1388141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 1389141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 1390141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 1391141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; 1392141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 1393141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &u8_range; 1394141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = 104; 1395141cc406Sopenharmony_ci 1396141cc406Sopenharmony_ci /* black-level */ 1397141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].name = SANE_NAME_BLACK_LEVEL; 1398141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].title = SANE_TITLE_BLACK_LEVEL; 1399141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].desc = SANE_DESC_BLACK_LEVEL 1400141cc406Sopenharmony_ci " This value should be selected so that black areas just start " 1401141cc406Sopenharmony_ci "to look really black (not gray)."; 1402141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].type = SANE_TYPE_INT; 1403141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].constraint_type = SANE_CONSTRAINT_RANGE; 1404141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].constraint.range = &u8_range; 1405141cc406Sopenharmony_ci s->val[OPT_BLACK_LEVEL].w = 0; 1406141cc406Sopenharmony_ci 1407141cc406Sopenharmony_ci /* white-level */ 1408141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].name = SANE_NAME_WHITE_LEVEL; 1409141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].title = SANE_TITLE_WHITE_LEVEL; 1410141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].desc = SANE_DESC_WHITE_LEVEL 1411141cc406Sopenharmony_ci " This value should be selected so that white areas just start " 1412141cc406Sopenharmony_ci "to look really white (not gray)."; 1413141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].type = SANE_TYPE_INT; 1414141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].constraint_type = SANE_CONSTRAINT_RANGE; 1415141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].constraint.range = &u8_range; 1416141cc406Sopenharmony_ci s->val[OPT_WHITE_LEVEL].w = 150; 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci /* hue */ 1419141cc406Sopenharmony_ci s->opt[OPT_HUE].name = SANE_NAME_HUE; 1420141cc406Sopenharmony_ci s->opt[OPT_HUE].title = SANE_TITLE_HUE; 1421141cc406Sopenharmony_ci s->opt[OPT_HUE].desc = SANE_DESC_HUE; 1422141cc406Sopenharmony_ci s->opt[OPT_HUE].type = SANE_TYPE_INT; 1423141cc406Sopenharmony_ci s->opt[OPT_HUE].constraint_type = SANE_CONSTRAINT_RANGE; 1424141cc406Sopenharmony_ci s->opt[OPT_HUE].constraint.range = &u8_range; 1425141cc406Sopenharmony_ci s->val[OPT_HUE].w = 128; 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci /* saturation */ 1428141cc406Sopenharmony_ci s->opt[OPT_SATURATION].name = SANE_NAME_SATURATION; 1429141cc406Sopenharmony_ci s->opt[OPT_SATURATION].title = SANE_TITLE_SATURATION; 1430141cc406Sopenharmony_ci s->opt[OPT_SATURATION].desc = SANE_DESC_SATURATION; 1431141cc406Sopenharmony_ci s->opt[OPT_SATURATION].type = SANE_TYPE_INT; 1432141cc406Sopenharmony_ci s->opt[OPT_SATURATION].constraint_type = SANE_CONSTRAINT_RANGE; 1433141cc406Sopenharmony_ci s->opt[OPT_SATURATION].constraint.range = &u8_range; 1434141cc406Sopenharmony_ci s->val[OPT_SATURATION].w = 100; 1435141cc406Sopenharmony_ci 1436141cc406Sopenharmony_ci DBG (3, "init_options: exit\n"); 1437141cc406Sopenharmony_ci 1438141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1439141cc406Sopenharmony_ci} 1440141cc406Sopenharmony_ci 1441141cc406Sopenharmony_ciSANE_Status 1442141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 1443141cc406Sopenharmony_ci{ 1444141cc406Sopenharmony_ci char dev_name[PATH_MAX], *str; 1445141cc406Sopenharmony_ci size_t len; 1446141cc406Sopenharmony_ci FILE *fp; 1447141cc406Sopenharmony_ci (void) authorize; /* silence compilation warnings */ 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci DBG_INIT (); 1450141cc406Sopenharmony_ci 1451141cc406Sopenharmony_ci DBG (1, "sane_init: enter\n"); 1452141cc406Sopenharmony_ci 1453141cc406Sopenharmony_ci if (version_code) 1454141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 1455141cc406Sopenharmony_ci 1456141cc406Sopenharmony_ci fp = sanei_config_open (QCAM_CONFIG_FILE); 1457141cc406Sopenharmony_ci if (!fp) 1458141cc406Sopenharmony_ci { 1459141cc406Sopenharmony_ci DBG (1, "sane_init: file `%s' not accessible\n", QCAM_CONFIG_FILE); 1460141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1461141cc406Sopenharmony_ci } 1462141cc406Sopenharmony_ci 1463141cc406Sopenharmony_ci while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 1464141cc406Sopenharmony_ci { 1465141cc406Sopenharmony_ci if (dev_name[0] == '#') /* ignore line comments */ 1466141cc406Sopenharmony_ci continue; 1467141cc406Sopenharmony_ci len = strlen (dev_name); 1468141cc406Sopenharmony_ci 1469141cc406Sopenharmony_ci if (!len) 1470141cc406Sopenharmony_ci continue; /* ignore empty lines */ 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci for (str = dev_name; *str && !isspace (*str) && *str != '#'; ++str); 1473141cc406Sopenharmony_ci *str = '\0'; 1474141cc406Sopenharmony_ci 1475141cc406Sopenharmony_ci attach (dev_name, 0); 1476141cc406Sopenharmony_ci } 1477141cc406Sopenharmony_ci fclose (fp); 1478141cc406Sopenharmony_ci 1479141cc406Sopenharmony_ci DBG (1, "sane_init: exit\n"); 1480141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1481141cc406Sopenharmony_ci} 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_civoid 1484141cc406Sopenharmony_cisane_exit (void) 1485141cc406Sopenharmony_ci{ 1486141cc406Sopenharmony_ci QC_Device *dev, *next; 1487141cc406Sopenharmony_ci static const SANE_Device **devlist; 1488141cc406Sopenharmony_ci 1489141cc406Sopenharmony_ci DBG (5, "sane_exit: enter\n"); 1490141cc406Sopenharmony_ci 1491141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 1492141cc406Sopenharmony_ci { 1493141cc406Sopenharmony_ci next = dev->next; 1494141cc406Sopenharmony_ci free ((void *) dev->sane.name); 1495141cc406Sopenharmony_ci disable_ports (dev); 1496141cc406Sopenharmony_ci free (dev); 1497141cc406Sopenharmony_ci } 1498141cc406Sopenharmony_ci if (devlist) { 1499141cc406Sopenharmony_ci free (devlist); 1500141cc406Sopenharmony_ci devlist = NULL; 1501141cc406Sopenharmony_ci } 1502141cc406Sopenharmony_ci DBG (5, "sane_exit: exit\n"); 1503141cc406Sopenharmony_ci} 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ciSANE_Status 1506141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 1507141cc406Sopenharmony_ci{ 1508141cc406Sopenharmony_ci static const SANE_Device **devlist = 0; 1509141cc406Sopenharmony_ci QC_Device *dev; 1510141cc406Sopenharmony_ci int i; 1511141cc406Sopenharmony_ci 1512141cc406Sopenharmony_ci DBG (5, "sane_get_devices: enter\n"); 1513141cc406Sopenharmony_ci 1514141cc406Sopenharmony_ci (void) local_only; /* silence compilation warnings */ 1515141cc406Sopenharmony_ci 1516141cc406Sopenharmony_ci if (devlist) 1517141cc406Sopenharmony_ci free (devlist); 1518141cc406Sopenharmony_ci 1519141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 1520141cc406Sopenharmony_ci if (!devlist) 1521141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1522141cc406Sopenharmony_ci 1523141cc406Sopenharmony_ci i = 0; 1524141cc406Sopenharmony_ci for (dev = first_dev; i < num_devices; dev = dev->next) 1525141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 1526141cc406Sopenharmony_ci devlist[i++] = 0; 1527141cc406Sopenharmony_ci 1528141cc406Sopenharmony_ci *device_list = devlist; 1529141cc406Sopenharmony_ci 1530141cc406Sopenharmony_ci DBG (5, "sane_get_devices: exit\n"); 1531141cc406Sopenharmony_ci 1532141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1533141cc406Sopenharmony_ci} 1534141cc406Sopenharmony_ci 1535141cc406Sopenharmony_ciSANE_Status 1536141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle) 1537141cc406Sopenharmony_ci{ 1538141cc406Sopenharmony_ci SANE_Status status; 1539141cc406Sopenharmony_ci QC_Device *dev; 1540141cc406Sopenharmony_ci QC_Scanner *s; 1541141cc406Sopenharmony_ci 1542141cc406Sopenharmony_ci DBG (5, "sane_open: enter: (devicename = %s)\n", devicename); 1543141cc406Sopenharmony_ci if (devicename[0]) 1544141cc406Sopenharmony_ci { 1545141cc406Sopenharmony_ci status = attach (devicename, &dev); 1546141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1547141cc406Sopenharmony_ci return status; 1548141cc406Sopenharmony_ci } 1549141cc406Sopenharmony_ci else 1550141cc406Sopenharmony_ci /* empty devicname -> use first device */ 1551141cc406Sopenharmony_ci dev = first_dev; 1552141cc406Sopenharmony_ci 1553141cc406Sopenharmony_ci if (!dev) 1554141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1555141cc406Sopenharmony_ci 1556141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 1557141cc406Sopenharmony_ci if (!s) 1558141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1559141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 1560141cc406Sopenharmony_ci s->user_corner = 0; 1561141cc406Sopenharmony_ci s->hw = dev; 1562141cc406Sopenharmony_ci s->value_changed = ~0; /* ensure all options get updated */ 1563141cc406Sopenharmony_ci s->reader_pid = -1; 1564141cc406Sopenharmony_ci s->to_child = -1; 1565141cc406Sopenharmony_ci s->from_child = -1; 1566141cc406Sopenharmony_ci s->read_fd = -1; 1567141cc406Sopenharmony_ci 1568141cc406Sopenharmony_ci init_options (s); 1569141cc406Sopenharmony_ci 1570141cc406Sopenharmony_ci /* The contrast option seems to have an effect for b&w cameras only, 1571141cc406Sopenharmony_ci so don't give the user the impression that this is a useful thing 1572141cc406Sopenharmony_ci to set... */ 1573141cc406Sopenharmony_ci if (s->hw->version == QC_COLOR) 1574141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; 1575141cc406Sopenharmony_ci else 1576141cc406Sopenharmony_ci { 1577141cc406Sopenharmony_ci /* Black level, Hue and Saturation are things the b&w cameras 1578141cc406Sopenharmony_ci know nothing about. Despeckle might be useful, but this code 1579141cc406Sopenharmony_ci seems to work for color cameras only right now. The framesize 1580141cc406Sopenharmony_ci seems to work better in these ranges. */ 1581141cc406Sopenharmony_ci s->opt[OPT_DESPECKLE].cap |= SANE_CAP_INACTIVE; 1582141cc406Sopenharmony_ci s->opt[OPT_BLACK_LEVEL].cap |= SANE_CAP_INACTIVE; 1583141cc406Sopenharmony_ci s->opt[OPT_HUE].cap |= SANE_CAP_INACTIVE; 1584141cc406Sopenharmony_ci s->opt[OPT_SATURATION].cap |= SANE_CAP_INACTIVE; 1585141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].cap |= SANE_CAP_INACTIVE; 1586141cc406Sopenharmony_ci s->opt[OPT_TEST].cap |= SANE_CAP_INACTIVE; 1587141cc406Sopenharmony_ci 1588141cc406Sopenharmony_ci s->opt[OPT_DEPTH].constraint.word_list = mono_depth_list; 1589141cc406Sopenharmony_ci s->val[OPT_DEPTH].w = mono_depth_list[NELEMS (mono_depth_list) - 1]; 1590141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &bw_x_range; 1591141cc406Sopenharmony_ci s->val[OPT_TL_X].w = 14; 1592141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &bw_y_range; 1593141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = 0; 1594141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &odd_bw_x_range; 1595141cc406Sopenharmony_ci s->val[OPT_BR_X].w = 333; 1596141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &odd_bw_y_range; 1597141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = 239; 1598141cc406Sopenharmony_ci 1599141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = 170; 1600141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = 150; 1601141cc406Sopenharmony_ci s->val[OPT_WHITE_LEVEL].w = 150; 1602141cc406Sopenharmony_ci } 1603141cc406Sopenharmony_ci 1604141cc406Sopenharmony_ci /* insert newly opened handle into list of open handles: */ 1605141cc406Sopenharmony_ci s->next = first_handle; 1606141cc406Sopenharmony_ci first_handle = s; 1607141cc406Sopenharmony_ci 1608141cc406Sopenharmony_ci *handle = s; 1609141cc406Sopenharmony_ci 1610141cc406Sopenharmony_ci DBG (5, "sane_open: exit\n"); 1611141cc406Sopenharmony_ci 1612141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1613141cc406Sopenharmony_ci} 1614141cc406Sopenharmony_ci 1615141cc406Sopenharmony_civoid 1616141cc406Sopenharmony_cisane_close (SANE_Handle handle) 1617141cc406Sopenharmony_ci{ 1618141cc406Sopenharmony_ci QC_Scanner *prev, *s; 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci DBG (5, "sane_close: enter\n"); 1621141cc406Sopenharmony_ci 1622141cc406Sopenharmony_ci /* remove handle from list of open handles: */ 1623141cc406Sopenharmony_ci prev = 0; 1624141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 1625141cc406Sopenharmony_ci { 1626141cc406Sopenharmony_ci if (s == handle) 1627141cc406Sopenharmony_ci break; 1628141cc406Sopenharmony_ci prev = s; 1629141cc406Sopenharmony_ci } 1630141cc406Sopenharmony_ci if (!s) 1631141cc406Sopenharmony_ci { 1632141cc406Sopenharmony_ci DBG (1, "sane_close: bad handle %p\n", handle); 1633141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 1634141cc406Sopenharmony_ci } 1635141cc406Sopenharmony_ci if (prev) 1636141cc406Sopenharmony_ci prev->next = s->next; 1637141cc406Sopenharmony_ci else 1638141cc406Sopenharmony_ci first_handle = s->next; 1639141cc406Sopenharmony_ci 1640141cc406Sopenharmony_ci if (s->scanning) 1641141cc406Sopenharmony_ci sane_cancel (handle); 1642141cc406Sopenharmony_ci 1643141cc406Sopenharmony_ci if (s->reader_pid >= 0) 1644141cc406Sopenharmony_ci { 1645141cc406Sopenharmony_ci kill (s->reader_pid, SIGTERM); 1646141cc406Sopenharmony_ci waitpid (s->reader_pid, 0, 0); 1647141cc406Sopenharmony_ci s->reader_pid = 0; 1648141cc406Sopenharmony_ci } 1649141cc406Sopenharmony_ci if (s->to_child >= 0) 1650141cc406Sopenharmony_ci close (s->to_child); 1651141cc406Sopenharmony_ci if (s->from_child >= 0) 1652141cc406Sopenharmony_ci close (s->from_child); 1653141cc406Sopenharmony_ci if (s->read_fd >= 0) 1654141cc406Sopenharmony_ci close (s->read_fd); 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci free (s); 1657141cc406Sopenharmony_ci 1658141cc406Sopenharmony_ci DBG (5, "sane_close: exit\n"); 1659141cc406Sopenharmony_ci 1660141cc406Sopenharmony_ci} 1661141cc406Sopenharmony_ci 1662141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1663141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1664141cc406Sopenharmony_ci{ 1665141cc406Sopenharmony_ci QC_Scanner *s = handle; 1666141cc406Sopenharmony_ci 1667141cc406Sopenharmony_ci DBG (5, "sane_get_option_descriptor: enter\n"); 1668141cc406Sopenharmony_ci 1669141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 1670141cc406Sopenharmony_ci return 0; 1671141cc406Sopenharmony_ci 1672141cc406Sopenharmony_ci DBG (5, "sane_get_option_descriptor: exit\n"); 1673141cc406Sopenharmony_ci 1674141cc406Sopenharmony_ci return s->opt + option; 1675141cc406Sopenharmony_ci} 1676141cc406Sopenharmony_ci 1677141cc406Sopenharmony_ciSANE_Status 1678141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 1679141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 1680141cc406Sopenharmony_ci{ 1681141cc406Sopenharmony_ci QC_Scanner *s = handle; 1682141cc406Sopenharmony_ci QC_Resolution old_res; 1683141cc406Sopenharmony_ci SANE_Status status; 1684141cc406Sopenharmony_ci SANE_Word cap; 1685141cc406Sopenharmony_ci char *old_val; 1686141cc406Sopenharmony_ci int i; 1687141cc406Sopenharmony_ci 1688141cc406Sopenharmony_ci DBG (5, "sane_control_option: enter\n"); 1689141cc406Sopenharmony_ci 1690141cc406Sopenharmony_ci if (info) 1691141cc406Sopenharmony_ci *info = 0; 1692141cc406Sopenharmony_ci 1693141cc406Sopenharmony_ci if (option >= NUM_OPTIONS) 1694141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1695141cc406Sopenharmony_ci 1696141cc406Sopenharmony_ci cap = s->opt[option].cap; 1697141cc406Sopenharmony_ci 1698141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 1699141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1700141cc406Sopenharmony_ci 1701141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 1702141cc406Sopenharmony_ci { 1703141cc406Sopenharmony_ci switch (option) 1704141cc406Sopenharmony_ci { 1705141cc406Sopenharmony_ci /* word options: */ 1706141cc406Sopenharmony_ci case OPT_NUM_OPTS: 1707141cc406Sopenharmony_ci case OPT_DEPTH: 1708141cc406Sopenharmony_ci case OPT_DESPECKLE: 1709141cc406Sopenharmony_ci case OPT_TEST: 1710141cc406Sopenharmony_ci case OPT_TL_X: 1711141cc406Sopenharmony_ci case OPT_TL_Y: 1712141cc406Sopenharmony_ci case OPT_BR_X: 1713141cc406Sopenharmony_ci case OPT_BR_Y: 1714141cc406Sopenharmony_ci case OPT_XFER_SCALE: 1715141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1716141cc406Sopenharmony_ci case OPT_CONTRAST: 1717141cc406Sopenharmony_ci case OPT_BLACK_LEVEL: 1718141cc406Sopenharmony_ci case OPT_WHITE_LEVEL: 1719141cc406Sopenharmony_ci case OPT_HUE: 1720141cc406Sopenharmony_ci case OPT_SATURATION: 1721141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option].w; 1722141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1723141cc406Sopenharmony_ci 1724141cc406Sopenharmony_ci /* string options: */ 1725141cc406Sopenharmony_ci case OPT_RESOLUTION: 1726141cc406Sopenharmony_ci strcpy (val, s->val[option].s); 1727141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1728141cc406Sopenharmony_ci 1729141cc406Sopenharmony_ci default: 1730141cc406Sopenharmony_ci DBG (1, "control_option: option %d unknown\n", option); 1731141cc406Sopenharmony_ci } 1732141cc406Sopenharmony_ci } 1733141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 1734141cc406Sopenharmony_ci { 1735141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 1736141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1737141cc406Sopenharmony_ci 1738141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 1739141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1740141cc406Sopenharmony_ci return status; 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_ci if (option >= OPT_TL_X && option <= OPT_BR_Y) 1743141cc406Sopenharmony_ci s->user_corner |= 1 << (option - OPT_TL_X); 1744141cc406Sopenharmony_ci 1745141cc406Sopenharmony_ci assert (option <= 31); 1746141cc406Sopenharmony_ci s->value_changed |= 1 << option; 1747141cc406Sopenharmony_ci 1748141cc406Sopenharmony_ci switch (option) 1749141cc406Sopenharmony_ci { 1750141cc406Sopenharmony_ci /* (mostly) side-effect-free word options: */ 1751141cc406Sopenharmony_ci case OPT_TL_X: 1752141cc406Sopenharmony_ci case OPT_TL_Y: 1753141cc406Sopenharmony_ci case OPT_BR_X: 1754141cc406Sopenharmony_ci case OPT_BR_Y: 1755141cc406Sopenharmony_ci case OPT_XFER_SCALE: 1756141cc406Sopenharmony_ci case OPT_DEPTH: 1757141cc406Sopenharmony_ci if (!s->scanning && info && s->val[option].w != *(SANE_Word *) val) 1758141cc406Sopenharmony_ci /* only signal the reload params if we're not scanning---no point 1759141cc406Sopenharmony_ci in creating the frontend useless work */ 1760141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1761141cc406Sopenharmony_ci /* fall through */ 1762141cc406Sopenharmony_ci case OPT_NUM_OPTS: 1763141cc406Sopenharmony_ci case OPT_TEST: 1764141cc406Sopenharmony_ci case OPT_DESPECKLE: 1765141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1766141cc406Sopenharmony_ci case OPT_CONTRAST: 1767141cc406Sopenharmony_ci case OPT_BLACK_LEVEL: 1768141cc406Sopenharmony_ci case OPT_WHITE_LEVEL: 1769141cc406Sopenharmony_ci case OPT_HUE: 1770141cc406Sopenharmony_ci case OPT_SATURATION: 1771141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 1772141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1773141cc406Sopenharmony_ci 1774141cc406Sopenharmony_ci /* options with side-effects: */ 1775141cc406Sopenharmony_ci case OPT_RESOLUTION: 1776141cc406Sopenharmony_ci old_val = s->val[OPT_RESOLUTION].s; 1777141cc406Sopenharmony_ci 1778141cc406Sopenharmony_ci if (strcmp (old_val, val) != 0) 1779141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no change */ 1780141cc406Sopenharmony_ci 1781141cc406Sopenharmony_ci if (info) 1782141cc406Sopenharmony_ci { 1783141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 1784141cc406Sopenharmony_ci if (!s->scanning) 1785141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 1786141cc406Sopenharmony_ci } 1787141cc406Sopenharmony_ci free (old_val); 1788141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].s = strdup (val); 1789141cc406Sopenharmony_ci 1790141cc406Sopenharmony_ci /* low-resolution mode: */ 1791141cc406Sopenharmony_ci old_res = s->resolution; 1792141cc406Sopenharmony_ci s->resolution = QC_RES_LOW; 1793141cc406Sopenharmony_ci if (strcmp (val, resolution_list[QC_RES_HIGH]) == 0) 1794141cc406Sopenharmony_ci /* high-resolution mode: */ 1795141cc406Sopenharmony_ci s->resolution = QC_RES_HIGH; 1796141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &x_range[s->resolution]; 1797141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &odd_x_range[s->resolution]; 1798141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &y_range[s->resolution]; 1799141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &odd_y_range[s->resolution]; 1800141cc406Sopenharmony_ci 1801141cc406Sopenharmony_ci if (old_res == QC_RES_LOW && s->resolution == QC_RES_HIGH) 1802141cc406Sopenharmony_ci { 1803141cc406Sopenharmony_ci for (i = OPT_TL_X; i <= OPT_BR_Y; ++i) 1804141cc406Sopenharmony_ci s->val[i].w *= 2; 1805141cc406Sopenharmony_ci s->val[OPT_BR_X].w += 1; 1806141cc406Sopenharmony_ci s->val[OPT_BR_Y].w += 1; 1807141cc406Sopenharmony_ci s->opt[OPT_TEST].cap |= SANE_CAP_INACTIVE; 1808141cc406Sopenharmony_ci } 1809141cc406Sopenharmony_ci else if (old_res == QC_RES_HIGH && s->resolution == QC_RES_LOW) 1810141cc406Sopenharmony_ci { 1811141cc406Sopenharmony_ci for (i = OPT_TL_X; i <= OPT_BR_Y; ++i) 1812141cc406Sopenharmony_ci s->val[i].w /= 2; 1813141cc406Sopenharmony_ci s->opt[OPT_TEST].cap &= ~SANE_CAP_INACTIVE; 1814141cc406Sopenharmony_ci } 1815141cc406Sopenharmony_ci 1816141cc406Sopenharmony_ci if (!(s->user_corner & 0x4)) 1817141cc406Sopenharmony_ci s->val[OPT_BR_X].w = odd_x_range[s->resolution].max; 1818141cc406Sopenharmony_ci if (!(s->user_corner & 0x8)) 1819141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = odd_y_range[s->resolution].max - 4; 1820141cc406Sopenharmony_ci 1821141cc406Sopenharmony_ci /* make sure the affected options have valid values: */ 1822141cc406Sopenharmony_ci for (i = OPT_TL_X; i <= OPT_BR_Y; ++i) 1823141cc406Sopenharmony_ci if (s->val[i].w > s->opt[i].constraint.range->max) 1824141cc406Sopenharmony_ci s->val[i].w = s->opt[i].constraint.range->max; 1825141cc406Sopenharmony_ci 1826141cc406Sopenharmony_ci DBG (5, "sane_control_option: exit\n"); 1827141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1828141cc406Sopenharmony_ci } 1829141cc406Sopenharmony_ci } 1830141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_AUTO) 1831141cc406Sopenharmony_ci { 1832141cc406Sopenharmony_ci switch (option) 1833141cc406Sopenharmony_ci { 1834141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 1835141cc406Sopenharmony_ci /* not implemented yet */ 1836141cc406Sopenharmony_ci DBG (5, "sane_control_option: exit\n"); 1837141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1838141cc406Sopenharmony_ci 1839141cc406Sopenharmony_ci default: 1840141cc406Sopenharmony_ci break; 1841141cc406Sopenharmony_ci } 1842141cc406Sopenharmony_ci } 1843141cc406Sopenharmony_ci 1844141cc406Sopenharmony_ci DBG (5, "sane_control_option: NOK exit\n"); 1845141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1846141cc406Sopenharmony_ci} 1847141cc406Sopenharmony_ci 1848141cc406Sopenharmony_ciSANE_Status 1849141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 1850141cc406Sopenharmony_ci{ 1851141cc406Sopenharmony_ci QC_Scanner *s = handle; 1852141cc406Sopenharmony_ci QC_Device *q = s->hw; 1853141cc406Sopenharmony_ci int xfer_scale; 1854141cc406Sopenharmony_ci size_t Bpp = 3; /* # of bytes per pixel */ 1855141cc406Sopenharmony_ci 1856141cc406Sopenharmony_ci DBG (5, "sane_get_parameters: enter\n"); 1857141cc406Sopenharmony_ci 1858141cc406Sopenharmony_ci if (!s->scanning) 1859141cc406Sopenharmony_ci { 1860141cc406Sopenharmony_ci /* Only compute new parameters when not scanning---allows 1861141cc406Sopenharmony_ci changing width/height etc while scan is in progress. */ 1862141cc406Sopenharmony_ci xfer_scale = s->val[OPT_XFER_SCALE].w; 1863141cc406Sopenharmony_ci 1864141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 1865141cc406Sopenharmony_ci if (q->version != QC_COLOR) 1866141cc406Sopenharmony_ci { 1867141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 1868141cc406Sopenharmony_ci Bpp = 1; 1869141cc406Sopenharmony_ci } 1870141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 1871141cc406Sopenharmony_ci 1872141cc406Sopenharmony_ci s->params.pixels_per_line = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w + 1; 1873141cc406Sopenharmony_ci s->params.pixels_per_line /= xfer_scale; 1874141cc406Sopenharmony_ci s->params.pixels_per_line &= ~1UL; /* ensure it's even */ 1875141cc406Sopenharmony_ci if (s->params.pixels_per_line < 2) 1876141cc406Sopenharmony_ci s->params.pixels_per_line = 2; 1877141cc406Sopenharmony_ci 1878141cc406Sopenharmony_ci s->params.lines = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w + 1; 1879141cc406Sopenharmony_ci s->params.lines /= xfer_scale; 1880141cc406Sopenharmony_ci if (s->params.lines < 1) 1881141cc406Sopenharmony_ci s->params.lines = 1; 1882141cc406Sopenharmony_ci 1883141cc406Sopenharmony_ci s->params.bytes_per_line = Bpp * s->params.pixels_per_line; 1884141cc406Sopenharmony_ci s->params.depth = 8; 1885141cc406Sopenharmony_ci } 1886141cc406Sopenharmony_ci if (params) 1887141cc406Sopenharmony_ci *params = s->params; 1888141cc406Sopenharmony_ci 1889141cc406Sopenharmony_ci DBG (5, "sane_get_parameters: exit\n"); 1890141cc406Sopenharmony_ci 1891141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1892141cc406Sopenharmony_ci} 1893141cc406Sopenharmony_ci 1894141cc406Sopenharmony_ciSANE_Status 1895141cc406Sopenharmony_cisane_start (SANE_Handle handle) 1896141cc406Sopenharmony_ci{ 1897141cc406Sopenharmony_ci int top, left, width, height, undecimated_width, undecimated_height; 1898141cc406Sopenharmony_ci QC_Scanner *s = handle; 1899141cc406Sopenharmony_ci QC_Device *q = s->hw; 1900141cc406Sopenharmony_ci QC_Scan_Request req; 1901141cc406Sopenharmony_ci 1902141cc406Sopenharmony_ci DBG (5, "sane_start: enter\n"); 1903141cc406Sopenharmony_ci 1904141cc406Sopenharmony_ci if (s->scanning) 1905141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 1906141cc406Sopenharmony_ci 1907141cc406Sopenharmony_ci if (s->reader_pid < 0) 1908141cc406Sopenharmony_ci { 1909141cc406Sopenharmony_ci int p2c_pipe[2]; /* parent->child pipe */ 1910141cc406Sopenharmony_ci int c2p_pipe[2]; /* child->parent pipe */ 1911141cc406Sopenharmony_ci 1912141cc406Sopenharmony_ci if (pipe (p2c_pipe) < 0 || pipe (c2p_pipe) < 0) 1913141cc406Sopenharmony_ci { 1914141cc406Sopenharmony_ci DBG (3, "start: failed to create pipes\n"); 1915141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1916141cc406Sopenharmony_ci } 1917141cc406Sopenharmony_ci 1918141cc406Sopenharmony_ci s->reader_pid = fork (); 1919141cc406Sopenharmony_ci if (s->reader_pid == 0) 1920141cc406Sopenharmony_ci { 1921141cc406Sopenharmony_ci /* this is the child */ 1922141cc406Sopenharmony_ci signal (SIGHUP, SIG_DFL); 1923141cc406Sopenharmony_ci signal (SIGINT, SIG_DFL); 1924141cc406Sopenharmony_ci signal (SIGPIPE, SIG_DFL); 1925141cc406Sopenharmony_ci signal (SIGTERM, SIG_DFL); 1926141cc406Sopenharmony_ci _exit (reader_process (s, p2c_pipe[0], c2p_pipe[1])); 1927141cc406Sopenharmony_ci } 1928141cc406Sopenharmony_ci close (p2c_pipe[0]); 1929141cc406Sopenharmony_ci close (c2p_pipe[1]); 1930141cc406Sopenharmony_ci s->to_child = p2c_pipe[1]; 1931141cc406Sopenharmony_ci s->from_child = c2p_pipe[0]; 1932141cc406Sopenharmony_ci } 1933141cc406Sopenharmony_ci 1934141cc406Sopenharmony_ci s->read_fd = dup (s->from_child); 1935141cc406Sopenharmony_ci sane_get_parameters (s, 0); /* ensure up-to-date parameters */ 1936141cc406Sopenharmony_ci 1937141cc406Sopenharmony_ci qc_lock (q); 1938141cc406Sopenharmony_ci s->holding_lock = SANE_TRUE; 1939141cc406Sopenharmony_ci 1940141cc406Sopenharmony_ci if (q->version == QC_COLOR) 1941141cc406Sopenharmony_ci { 1942141cc406Sopenharmony_ci qc_send (q, QC_SET_SPEED); 1943141cc406Sopenharmony_ci qc_send (q, 2); 1944141cc406Sopenharmony_ci 1945141cc406Sopenharmony_ci /* wait for camera to become ready: */ 1946141cc406Sopenharmony_ci while (qc_getstatus (q) & CameraNotReady) 1947141cc406Sopenharmony_ci usleep (10000); 1948141cc406Sopenharmony_ci 1949141cc406Sopenharmony_ci /* Only send black_level if necessary; this optimization may 1950141cc406Sopenharmony_ci fail if two applications access the camera in an interleaved 1951141cc406Sopenharmony_ci fashion; but the black-level command is slow enough that it 1952141cc406Sopenharmony_ci cannot be issued for every image acquisition. */ 1953141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_BLACK_LEVEL)) 1954141cc406Sopenharmony_ci { 1955141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_BLACK_LEVEL); 1956141cc406Sopenharmony_ci 1957141cc406Sopenharmony_ci qc_send (q, QC_SET_BLACK); 1958141cc406Sopenharmony_ci qc_send (q, s->val[OPT_BLACK_LEVEL].w); 1959141cc406Sopenharmony_ci 1960141cc406Sopenharmony_ci DBG (3, "start: black_level=%d\n", s->val[OPT_BLACK_LEVEL].w); 1961141cc406Sopenharmony_ci 1962141cc406Sopenharmony_ci /* wait for set black level command to finish: */ 1963141cc406Sopenharmony_ci while (qc_getstatus (q) & (CameraNotReady | BlackBalanceInProgress)) 1964141cc406Sopenharmony_ci usleep (10000); 1965141cc406Sopenharmony_ci } 1966141cc406Sopenharmony_ci 1967141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_HUE)) 1968141cc406Sopenharmony_ci { 1969141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_HUE); 1970141cc406Sopenharmony_ci qc_send (q, QC_COL_SET_HUE); 1971141cc406Sopenharmony_ci qc_send (q, s->val[OPT_HUE].w); 1972141cc406Sopenharmony_ci } 1973141cc406Sopenharmony_ci 1974141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_SATURATION)) 1975141cc406Sopenharmony_ci { 1976141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_SATURATION); 1977141cc406Sopenharmony_ci qc_send (q, QC_SET_SATURATION); 1978141cc406Sopenharmony_ci qc_send (q, s->val[OPT_SATURATION].w); 1979141cc406Sopenharmony_ci } 1980141cc406Sopenharmony_ci } 1981141cc406Sopenharmony_ci 1982141cc406Sopenharmony_ci if (q->version != QC_COLOR) 1983141cc406Sopenharmony_ci qc_reset (q); 1984141cc406Sopenharmony_ci 1985141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_CONTRAST)) 1986141cc406Sopenharmony_ci { 1987141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_CONTRAST); 1988141cc406Sopenharmony_ci qc_send (q, ((q->version == QC_COLOR) 1989141cc406Sopenharmony_ci ? QC_COL_SET_CONTRAST : QC_MONO_SET_CONTRAST)); 1990141cc406Sopenharmony_ci qc_send (q, s->val[OPT_CONTRAST].w); 1991141cc406Sopenharmony_ci } 1992141cc406Sopenharmony_ci 1993141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_BRIGHTNESS)) 1994141cc406Sopenharmony_ci { 1995141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_BRIGHTNESS); 1996141cc406Sopenharmony_ci qc_send (q, QC_SET_BRIGHTNESS); 1997141cc406Sopenharmony_ci qc_send (q, s->val[OPT_BRIGHTNESS].w); 1998141cc406Sopenharmony_ci } 1999141cc406Sopenharmony_ci 2000141cc406Sopenharmony_ci width = s->params.pixels_per_line; 2001141cc406Sopenharmony_ci height = s->params.lines; 2002141cc406Sopenharmony_ci if (s->resolution == QC_RES_HIGH) 2003141cc406Sopenharmony_ci { 2004141cc406Sopenharmony_ci width /= 2; /* the expansion occurs through oversampling */ 2005141cc406Sopenharmony_ci height /= 2; /* we acquire only half the lines that we generate */ 2006141cc406Sopenharmony_ci } 2007141cc406Sopenharmony_ci undecimated_width = width * s->val[OPT_XFER_SCALE].w; 2008141cc406Sopenharmony_ci undecimated_height = height * s->val[OPT_XFER_SCALE].w; 2009141cc406Sopenharmony_ci 2010141cc406Sopenharmony_ci s->num_bytes = 0; 2011141cc406Sopenharmony_ci s->bytes_per_frame = s->params.lines * s->params.bytes_per_line; 2012141cc406Sopenharmony_ci 2013141cc406Sopenharmony_ci qc_send (q, QC_SET_NUM_V); 2014141cc406Sopenharmony_ci qc_send (q, undecimated_height); 2015141cc406Sopenharmony_ci 2016141cc406Sopenharmony_ci if (q->version == QC_COLOR) 2017141cc406Sopenharmony_ci { 2018141cc406Sopenharmony_ci qc_send (q, QC_SET_NUM_H); 2019141cc406Sopenharmony_ci qc_send (q, undecimated_width / 2); 2020141cc406Sopenharmony_ci } 2021141cc406Sopenharmony_ci else 2022141cc406Sopenharmony_ci { 2023141cc406Sopenharmony_ci int val, val2; 2024141cc406Sopenharmony_ci 2025141cc406Sopenharmony_ci if (q->port_mode == QC_UNIDIR && s->val[OPT_DEPTH].w == 6) 2026141cc406Sopenharmony_ci { 2027141cc406Sopenharmony_ci val = undecimated_width; 2028141cc406Sopenharmony_ci val2 = s->val[OPT_XFER_SCALE].w * 4; 2029141cc406Sopenharmony_ci } 2030141cc406Sopenharmony_ci else 2031141cc406Sopenharmony_ci { 2032141cc406Sopenharmony_ci val = undecimated_width * s->val[OPT_DEPTH].w; 2033141cc406Sopenharmony_ci val2 = 2034141cc406Sopenharmony_ci ((q->port_mode == QC_BIDIR) ? 24 : 8) * s->val[OPT_XFER_SCALE].w; 2035141cc406Sopenharmony_ci } 2036141cc406Sopenharmony_ci val = (val + val2 - 1) / val2; 2037141cc406Sopenharmony_ci qc_send (q, QC_SET_NUM_H); 2038141cc406Sopenharmony_ci qc_send (q, val); 2039141cc406Sopenharmony_ci } 2040141cc406Sopenharmony_ci 2041141cc406Sopenharmony_ci left = s->val[OPT_TL_X].w / 2; 2042141cc406Sopenharmony_ci top = s->val[OPT_TL_Y].w; 2043141cc406Sopenharmony_ci if (s->resolution == QC_RES_HIGH) 2044141cc406Sopenharmony_ci { 2045141cc406Sopenharmony_ci left /= 2; 2046141cc406Sopenharmony_ci top /= 2; 2047141cc406Sopenharmony_ci } 2048141cc406Sopenharmony_ci 2049141cc406Sopenharmony_ci DBG (3, "sane_start: top=%d, left=%d, white=%d, bright=%d, contr=%d\n", 2050141cc406Sopenharmony_ci top, left, s->val[OPT_WHITE_LEVEL].w, s->val[OPT_BRIGHTNESS].w, 2051141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w); 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_ci qc_send (q, QC_SET_LEFT); 2054141cc406Sopenharmony_ci qc_send (q, left); 2055141cc406Sopenharmony_ci 2056141cc406Sopenharmony_ci qc_send (q, QC_SET_TOP); 2057141cc406Sopenharmony_ci qc_send (q, top + 1); /* not sure why this is so... ;-( */ 2058141cc406Sopenharmony_ci 2059141cc406Sopenharmony_ci if (s->value_changed & (1 << OPT_WHITE_LEVEL)) 2060141cc406Sopenharmony_ci { 2061141cc406Sopenharmony_ci s->value_changed &= ~(1 << OPT_WHITE_LEVEL); 2062141cc406Sopenharmony_ci qc_send (q, QC_SET_WHITE); 2063141cc406Sopenharmony_ci qc_send (q, s->val[OPT_WHITE_LEVEL].w); 2064141cc406Sopenharmony_ci } 2065141cc406Sopenharmony_ci 2066141cc406Sopenharmony_ci DBG (2, "start: %s %d lines of %d pixels each (%ld bytes) => %dx%d\n", 2067141cc406Sopenharmony_ci (q->port_mode == QC_BIDIR) ? "bidir" : "unidir", 2068141cc406Sopenharmony_ci height, width, (long) s->bytes_per_frame, 2069141cc406Sopenharmony_ci s->params.pixels_per_line, s->params.lines); 2070141cc406Sopenharmony_ci 2071141cc406Sopenharmony_ci /* send scan request to reader process: */ 2072141cc406Sopenharmony_ci qc_setscanmode (s, &req.mode); 2073141cc406Sopenharmony_ci req.num_bytes = width * height; 2074141cc406Sopenharmony_ci if (q->version == QC_COLOR) 2075141cc406Sopenharmony_ci { 2076141cc406Sopenharmony_ci if (s->resolution == QC_RES_LOW) 2077141cc406Sopenharmony_ci req.num_bytes *= 3; 2078141cc406Sopenharmony_ci else 2079141cc406Sopenharmony_ci req.num_bytes *= 4; 2080141cc406Sopenharmony_ci } 2081141cc406Sopenharmony_ci req.resolution = s->resolution; 2082141cc406Sopenharmony_ci req.params = s->params; 2083141cc406Sopenharmony_ci req.despeckle = s->val[OPT_DESPECKLE].w; 2084141cc406Sopenharmony_ci write (s->to_child, &req, sizeof (req)); 2085141cc406Sopenharmony_ci 2086141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 2087141cc406Sopenharmony_ci s->deliver_eof = 0; 2088141cc406Sopenharmony_ci 2089141cc406Sopenharmony_ci DBG (5, "sane_start: exit\n"); 2090141cc406Sopenharmony_ci 2091141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2092141cc406Sopenharmony_ci} 2093141cc406Sopenharmony_ci 2094141cc406Sopenharmony_ciSANE_Status 2095141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, 2096141cc406Sopenharmony_ci SANE_Int * lenp) 2097141cc406Sopenharmony_ci{ 2098141cc406Sopenharmony_ci SANE_Status status; 2099141cc406Sopenharmony_ci QC_Scanner *s = handle; 2100141cc406Sopenharmony_ci QC_Device *q = s->hw; 2101141cc406Sopenharmony_ci ssize_t nread; 2102141cc406Sopenharmony_ci size_t len; 2103141cc406Sopenharmony_ci 2104141cc406Sopenharmony_ci DBG (5, "sane_read: enter\n"); 2105141cc406Sopenharmony_ci 2106141cc406Sopenharmony_ci *lenp = 0; 2107141cc406Sopenharmony_ci 2108141cc406Sopenharmony_ci if (s->deliver_eof) 2109141cc406Sopenharmony_ci { 2110141cc406Sopenharmony_ci s->deliver_eof = 0; 2111141cc406Sopenharmony_ci return SANE_STATUS_EOF; 2112141cc406Sopenharmony_ci } 2113141cc406Sopenharmony_ci 2114141cc406Sopenharmony_ci if (!s->scanning) 2115141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 2116141cc406Sopenharmony_ci 2117141cc406Sopenharmony_ci len = max_len; 2118141cc406Sopenharmony_ci if (s->num_bytes + len > s->bytes_per_frame) 2119141cc406Sopenharmony_ci len = s->bytes_per_frame - s->num_bytes; 2120141cc406Sopenharmony_ci 2121141cc406Sopenharmony_ci DBG (8, "read(buf=%p,num_bytes=%ld,max_len=%d,len=%ld)\n", 2122141cc406Sopenharmony_ci (void *) buf, (long) s->num_bytes, max_len, (long) len); 2123141cc406Sopenharmony_ci 2124141cc406Sopenharmony_ci nread = read (s->read_fd, buf, len); 2125141cc406Sopenharmony_ci if (nread <= 0) 2126141cc406Sopenharmony_ci { 2127141cc406Sopenharmony_ci if (nread == 0 || errno == EAGAIN) 2128141cc406Sopenharmony_ci { 2129141cc406Sopenharmony_ci DBG (3, "read: no more data available\n"); 2130141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2131141cc406Sopenharmony_ci } 2132141cc406Sopenharmony_ci DBG (3, "read: short read (%s)\n", strerror (errno)); 2133141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2134141cc406Sopenharmony_ci } 2135141cc406Sopenharmony_ci 2136141cc406Sopenharmony_ci if (nread > 0 && s->holding_lock) 2137141cc406Sopenharmony_ci { 2138141cc406Sopenharmony_ci status = qc_unlock (q); /* now we can unlock the camera */ 2139141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2140141cc406Sopenharmony_ci DBG(3, "sane_read: qc_unlock error\n"); 2141141cc406Sopenharmony_ci s->holding_lock = SANE_FALSE; 2142141cc406Sopenharmony_ci } 2143141cc406Sopenharmony_ci 2144141cc406Sopenharmony_ci s->num_bytes += nread; 2145141cc406Sopenharmony_ci if (s->num_bytes >= s->bytes_per_frame) 2146141cc406Sopenharmony_ci { 2147141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 2148141cc406Sopenharmony_ci close (s->read_fd); 2149141cc406Sopenharmony_ci s->read_fd = -1; 2150141cc406Sopenharmony_ci s->deliver_eof = 1; 2151141cc406Sopenharmony_ci } 2152141cc406Sopenharmony_ci 2153141cc406Sopenharmony_ci if (lenp) 2154141cc406Sopenharmony_ci *lenp = nread; 2155141cc406Sopenharmony_ci 2156141cc406Sopenharmony_ci DBG (5, "sane_read: exit, read got %d bytes\n", *lenp); 2157141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2158141cc406Sopenharmony_ci} 2159141cc406Sopenharmony_ci 2160141cc406Sopenharmony_civoid 2161141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 2162141cc406Sopenharmony_ci{ 2163141cc406Sopenharmony_ci QC_Scanner *s = handle; 2164141cc406Sopenharmony_ci SANE_Bool was_scanning; 2165141cc406Sopenharmony_ci SANE_Status status; 2166141cc406Sopenharmony_ci 2167141cc406Sopenharmony_ci DBG (5, "sane_cancel: enter\n"); 2168141cc406Sopenharmony_ci 2169141cc406Sopenharmony_ci was_scanning = s->scanning; 2170141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 2171141cc406Sopenharmony_ci s->deliver_eof = 0; 2172141cc406Sopenharmony_ci if (s->read_fd >= 0) 2173141cc406Sopenharmony_ci { 2174141cc406Sopenharmony_ci close (s->read_fd); 2175141cc406Sopenharmony_ci s->read_fd = -1; 2176141cc406Sopenharmony_ci } 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci if (s->reader_pid >= 0 && was_scanning) 2179141cc406Sopenharmony_ci { 2180141cc406Sopenharmony_ci char buf[1024]; 2181141cc406Sopenharmony_ci ssize_t nread; 2182141cc406Sopenharmony_ci int flags; 2183141cc406Sopenharmony_ci 2184141cc406Sopenharmony_ci DBG (1, "cancel: cancelling read request\n"); 2185141cc406Sopenharmony_ci 2186141cc406Sopenharmony_ci kill (s->reader_pid, SIGINT); /* tell reader to stop reading */ 2187141cc406Sopenharmony_ci 2188141cc406Sopenharmony_ci /* save non-blocking i/o flags: */ 2189141cc406Sopenharmony_ci flags = fcntl (s->from_child, F_GETFL, 0); 2190141cc406Sopenharmony_ci 2191141cc406Sopenharmony_ci /* block until we read at least one byte: */ 2192141cc406Sopenharmony_ci read (s->from_child, buf, 1); 2193141cc406Sopenharmony_ci 2194141cc406Sopenharmony_ci /* put descriptor in non-blocking i/o: */ 2195141cc406Sopenharmony_ci fcntl (s->from_child, F_SETFL, O_NONBLOCK); 2196141cc406Sopenharmony_ci 2197141cc406Sopenharmony_ci /* read what's left over in the pipe/file buffer: */ 2198141cc406Sopenharmony_ci do 2199141cc406Sopenharmony_ci { 2200141cc406Sopenharmony_ci while ((nread = read (s->from_child, buf, sizeof (buf))) > 0); 2201141cc406Sopenharmony_ci usleep (100000); 2202141cc406Sopenharmony_ci nread = read (s->from_child, buf, sizeof (buf)); 2203141cc406Sopenharmony_ci } 2204141cc406Sopenharmony_ci while (nread > 0); 2205141cc406Sopenharmony_ci 2206141cc406Sopenharmony_ci /* now restore non-blocking i/o flag: */ 2207141cc406Sopenharmony_ci fcntl (s->from_child, F_SETFL, flags & O_NONBLOCK); 2208141cc406Sopenharmony_ci 2209141cc406Sopenharmony_ci waitpid (s->reader_pid, 0, 0); 2210141cc406Sopenharmony_ci s->reader_pid = 0; 2211141cc406Sopenharmony_ci 2212141cc406Sopenharmony_ci DBG (1, "cancel: cancellation completed\n"); 2213141cc406Sopenharmony_ci } 2214141cc406Sopenharmony_ci if (s->holding_lock) 2215141cc406Sopenharmony_ci { 2216141cc406Sopenharmony_ci status = qc_unlock (s->hw); 2217141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2218141cc406Sopenharmony_ci DBG(3, "sane_cancel: qc_unlock error\n"); 2219141cc406Sopenharmony_ci s->holding_lock = SANE_FALSE; 2220141cc406Sopenharmony_ci } 2221141cc406Sopenharmony_ci DBG (5, "sane_cancel: exit\n"); 2222141cc406Sopenharmony_ci} 2223141cc406Sopenharmony_ci 2224141cc406Sopenharmony_ciSANE_Status 2225141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 2226141cc406Sopenharmony_ci{ 2227141cc406Sopenharmony_ci QC_Scanner *s = handle; 2228141cc406Sopenharmony_ci 2229141cc406Sopenharmony_ci DBG (5, "sane_set_io_mode: enter\n"); 2230141cc406Sopenharmony_ci 2231141cc406Sopenharmony_ci if (!s->scanning) 2232141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2233141cc406Sopenharmony_ci 2234141cc406Sopenharmony_ci if (fcntl (s->read_fd, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) 2235141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2236141cc406Sopenharmony_ci DBG (5, "sane_set_io_mode: exit\n"); 2237141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2238141cc406Sopenharmony_ci} 2239141cc406Sopenharmony_ci 2240141cc406Sopenharmony_ciSANE_Status 2241141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 2242141cc406Sopenharmony_ci{ 2243141cc406Sopenharmony_ci QC_Scanner *s = handle; 2244141cc406Sopenharmony_ci 2245141cc406Sopenharmony_ci DBG (5, "sane_get_select_fd: enter\n"); 2246141cc406Sopenharmony_ci if (!s->scanning) 2247141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2248141cc406Sopenharmony_ci 2249141cc406Sopenharmony_ci *fd = s->read_fd; 2250141cc406Sopenharmony_ci DBG (5, "sane_get_select_fd: exit\n"); 2251141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2252141cc406Sopenharmony_ci} 2253