1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1997 Gordon Matzigkeit 3141cc406Sopenharmony_ci Copyright (C) 1997 David Mosberger-Tang 4141cc406Sopenharmony_ci This file is part of the SANE package. 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 7141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 8141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 9141cc406Sopenharmony_ci License, or (at your option) any later version. 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 12141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14141cc406Sopenharmony_ci General Public License for more details. 15141cc406Sopenharmony_ci 16141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 17141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 20141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 23141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 24141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 25141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 26141cc406Sopenharmony_ci account of linking the SANE library code into it. 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 29141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 30141cc406Sopenharmony_ci License. 31141cc406Sopenharmony_ci 32141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 33141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 34141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 37141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 38141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. */ 39141cc406Sopenharmony_ci 40141cc406Sopenharmony_ci#include "../include/sane/config.h" 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci#include <limits.h> 43141cc406Sopenharmony_ci#include <stdlib.h> 44141cc406Sopenharmony_ci#include <string.h> 45141cc406Sopenharmony_ciextern int errno; 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci#include "../include/sane/sane.h" 48141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci#include <unistd.h> 51141cc406Sopenharmony_ci#include <fcntl.h> 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci#ifndef PATH_MAX 56141cc406Sopenharmony_ci# define PATH_MAX 1024 57141cc406Sopenharmony_ci#endif 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 60141cc406Sopenharmony_ci#define PINT_CONFIG_FILE "pint.conf" 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci#include "pint.h" 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci#define DECIPOINTS_PER_MM (720.0 / MM_PER_INCH) 65141cc406Sopenharmony_ci#define TWELVEHUNDS_PER_MM (1200.0 / MM_PER_INCH) 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_cistatic int num_devices; 69141cc406Sopenharmony_cistatic PINT_Device *first_dev; 70141cc406Sopenharmony_cistatic PINT_Scanner *first_handle; 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci/* A zero-terminated list of valid scanner modes. */ 73141cc406Sopenharmony_cistatic SANE_String_Const mode_list[8]; 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_cistatic const SANE_Range s7_range = 76141cc406Sopenharmony_ci { 77141cc406Sopenharmony_ci -127, /* minimum */ 78141cc406Sopenharmony_ci 127, /* maximum */ 79141cc406Sopenharmony_ci 1 /* quantization */ 80141cc406Sopenharmony_ci }; 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_cistatic size_t 83141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[]) 84141cc406Sopenharmony_ci{ 85141cc406Sopenharmony_ci size_t size, max_size = 0; 86141cc406Sopenharmony_ci int i; 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) 89141cc406Sopenharmony_ci { 90141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 91141cc406Sopenharmony_ci if (size > max_size) 92141cc406Sopenharmony_ci max_size = size; 93141cc406Sopenharmony_ci } 94141cc406Sopenharmony_ci return max_size; 95141cc406Sopenharmony_ci} 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_cistatic SANE_Status 98141cc406Sopenharmony_ciattach (const char *devname, PINT_Device **devp) 99141cc406Sopenharmony_ci{ 100141cc406Sopenharmony_ci int fd; 101141cc406Sopenharmony_ci long lastguess, inc; 102141cc406Sopenharmony_ci PINT_Device *dev; 103141cc406Sopenharmony_ci struct scan_io scanio; 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 106141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 107141cc406Sopenharmony_ci { 108141cc406Sopenharmony_ci if (devp) 109141cc406Sopenharmony_ci *devp = dev; 110141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 111141cc406Sopenharmony_ci } 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_ci DBG(3, "attach: opening %s\n", devname); 114141cc406Sopenharmony_ci fd = open (devname, O_RDONLY, 0); 115141cc406Sopenharmony_ci if (fd < 0) 116141cc406Sopenharmony_ci { 117141cc406Sopenharmony_ci DBG(1, "attach: open failed (%s)\n", strerror (errno)); 118141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 119141cc406Sopenharmony_ci } 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ci DBG(3, "attach: sending SCIOCGET\n"); 122141cc406Sopenharmony_ci if (ioctl (fd, SCIOCGET, &scanio) < 0) 123141cc406Sopenharmony_ci { 124141cc406Sopenharmony_ci DBG(1, "attach: get status failed (%s)\n", strerror (errno)); 125141cc406Sopenharmony_ci close (fd); 126141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 127141cc406Sopenharmony_ci } 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 130141cc406Sopenharmony_ci if (!dev) 131141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci memset(dev, 0, sizeof (*dev)); 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_ci /* Copy the original scanner state to the device structure. */ 136141cc406Sopenharmony_ci memcpy (&dev->scanio, &scanio, sizeof (dev->scanio)); 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci /* FIXME: PINT currently has no good way to determine maxima and minima. 139141cc406Sopenharmony_ci So, do binary searches to find out what limits the driver has. */ 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_ci /* Assume that minimum range of x and y is 0. */ 142141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0); 143141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 144141cc406Sopenharmony_ci dev->x_range.quant = 0; 145141cc406Sopenharmony_ci dev->y_range.quant = 0; 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci /* x range */ 148141cc406Sopenharmony_ci inc = 8.5 * 1200; 149141cc406Sopenharmony_ci 150141cc406Sopenharmony_ci /* Converge on the maximum scan width. */ 151141cc406Sopenharmony_ci while ((inc /= 2) != 0) 152141cc406Sopenharmony_ci { 153141cc406Sopenharmony_ci /* Move towards the extremum until we overflow. */ 154141cc406Sopenharmony_ci do 155141cc406Sopenharmony_ci { 156141cc406Sopenharmony_ci lastguess = scanio.scan_width; 157141cc406Sopenharmony_ci scanio.scan_width += inc; 158141cc406Sopenharmony_ci } 159141cc406Sopenharmony_ci while (ioctl (fd, SCIOCSET, &scanio) >= 0); 160141cc406Sopenharmony_ci 161141cc406Sopenharmony_ci /* Pick the last valid guess, divide by two, and try again. */ 162141cc406Sopenharmony_ci scanio.scan_width = lastguess; 163141cc406Sopenharmony_ci } 164141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (scanio.scan_width / TWELVEHUNDS_PER_MM); 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_ci /* y range */ 167141cc406Sopenharmony_ci inc = 11 * 1200; 168141cc406Sopenharmony_ci while ((inc /= 2) != 0) 169141cc406Sopenharmony_ci { 170141cc406Sopenharmony_ci do 171141cc406Sopenharmony_ci { 172141cc406Sopenharmony_ci lastguess = scanio.scan_height; 173141cc406Sopenharmony_ci scanio.scan_height += inc; 174141cc406Sopenharmony_ci } 175141cc406Sopenharmony_ci while (ioctl (fd, SCIOCSET, &scanio) >= 0); 176141cc406Sopenharmony_ci scanio.scan_height = lastguess; 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (scanio.scan_height / TWELVEHUNDS_PER_MM); 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_ci /* Converge on the minimum scan resolution. */ 181141cc406Sopenharmony_ci dev->dpi_range.quant = 1; 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci if (scanio.scan_x_resolution > scanio.scan_y_resolution) 184141cc406Sopenharmony_ci scanio.scan_x_resolution = scanio.scan_y_resolution; 185141cc406Sopenharmony_ci else 186141cc406Sopenharmony_ci scanio.scan_y_resolution = scanio.scan_x_resolution; 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci inc = -scanio.scan_x_resolution; 189141cc406Sopenharmony_ci while ((inc /= 2) != 0) 190141cc406Sopenharmony_ci { 191141cc406Sopenharmony_ci do 192141cc406Sopenharmony_ci { 193141cc406Sopenharmony_ci lastguess = scanio.scan_x_resolution; 194141cc406Sopenharmony_ci scanio.scan_x_resolution = scanio.scan_y_resolution += inc; 195141cc406Sopenharmony_ci } 196141cc406Sopenharmony_ci while (ioctl (fd, SCIOCSET, &scanio) >= 0); 197141cc406Sopenharmony_ci scanio.scan_x_resolution = scanio.scan_y_resolution = lastguess; 198141cc406Sopenharmony_ci } 199141cc406Sopenharmony_ci dev->dpi_range.min = scanio.scan_x_resolution; 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci /* Converge on the maximum scan resolution. */ 202141cc406Sopenharmony_ci inc = 600; 203141cc406Sopenharmony_ci while ((inc /= 2) != 0) 204141cc406Sopenharmony_ci { 205141cc406Sopenharmony_ci do 206141cc406Sopenharmony_ci { 207141cc406Sopenharmony_ci lastguess = scanio.scan_x_resolution; 208141cc406Sopenharmony_ci scanio.scan_x_resolution = scanio.scan_y_resolution += inc; 209141cc406Sopenharmony_ci } 210141cc406Sopenharmony_ci while (ioctl (fd, SCIOCSET, &scanio) >= 0); 211141cc406Sopenharmony_ci scanio.scan_x_resolution = scanio.scan_y_resolution = lastguess; 212141cc406Sopenharmony_ci } 213141cc406Sopenharmony_ci dev->dpi_range.max = scanio.scan_x_resolution; 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci /* Determine the valid scan modes for mode_list. */ 216141cc406Sopenharmony_ci lastguess = 0; 217141cc406Sopenharmony_ci#define CHECK_MODE(flag,modename) \ 218141cc406Sopenharmony_ci scanio.scan_image_mode = flag; \ 219141cc406Sopenharmony_ci if (ioctl (fd, SCIOCSET, &scanio) >= 0) \ 220141cc406Sopenharmony_ci mode_list[lastguess ++] = modename 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ci CHECK_MODE(SIM_BINARY_MONOCHROME, SANE_VALUE_SCAN_MODE_LINEART); 223141cc406Sopenharmony_ci CHECK_MODE(SIM_DITHERED_MONOCHROME, SANE_VALUE_SCAN_MODE_HALFTONE); 224141cc406Sopenharmony_ci CHECK_MODE(SIM_GRAYSCALE, SANE_VALUE_SCAN_MODE_GRAY); 225141cc406Sopenharmony_ci CHECK_MODE(SIM_COLOR, SANE_VALUE_SCAN_MODE_COLOR); 226141cc406Sopenharmony_ci CHECK_MODE(SIM_RED, "Red"); 227141cc406Sopenharmony_ci CHECK_MODE(SIM_GREEN, "Green"); 228141cc406Sopenharmony_ci CHECK_MODE(SIM_BLUE, "Blue"); 229141cc406Sopenharmony_ci#undef CHECK_MODE 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci /* Zero-terminate the list of modes. */ 232141cc406Sopenharmony_ci mode_list[lastguess] = 0; 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci /* Restore the scanner state. */ 235141cc406Sopenharmony_ci if (ioctl (fd, SCIOCSET, &dev->scanio)) 236141cc406Sopenharmony_ci DBG (2, "cannot reset original scanner state: %s\n", strerror (errno)); 237141cc406Sopenharmony_ci close (fd); 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_ci dev->sane.name = strdup (devname); 240141cc406Sopenharmony_ci 241141cc406Sopenharmony_ci /* Determine vendor. */ 242141cc406Sopenharmony_ci switch (scanio.scan_scanner_type) 243141cc406Sopenharmony_ci { 244141cc406Sopenharmony_ci case EPSON_ES300C: 245141cc406Sopenharmony_ci dev->sane.vendor = "Epson"; 246141cc406Sopenharmony_ci break; 247141cc406Sopenharmony_ci 248141cc406Sopenharmony_ci case FUJITSU_M3096G: 249141cc406Sopenharmony_ci dev->sane.vendor = "Fujitsu"; 250141cc406Sopenharmony_ci break; 251141cc406Sopenharmony_ci 252141cc406Sopenharmony_ci case HP_SCANJET_IIC: 253141cc406Sopenharmony_ci dev->sane.vendor = "HP"; 254141cc406Sopenharmony_ci break; 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci case IBM_2456: 257141cc406Sopenharmony_ci dev->sane.vendor = "IBM"; 258141cc406Sopenharmony_ci break; 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_ci case MUSTEK_06000CX: 261141cc406Sopenharmony_ci case MUSTEK_12000CX: 262141cc406Sopenharmony_ci dev->sane.vendor = "Mustek"; 263141cc406Sopenharmony_ci break; 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_ci case RICOH_FS1: 266141cc406Sopenharmony_ci case RICOH_IS410: 267141cc406Sopenharmony_ci case RICOH_IS50: 268141cc406Sopenharmony_ci dev->sane.vendor = "Ricoh"; 269141cc406Sopenharmony_ci break; 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci case SHARP_JX600: 272141cc406Sopenharmony_ci dev->sane.vendor = "Sharp"; 273141cc406Sopenharmony_ci break; 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_ci case UMAX_UC630: 276141cc406Sopenharmony_ci case UMAX_UG630: 277141cc406Sopenharmony_ci dev->sane.vendor = "UMAX"; 278141cc406Sopenharmony_ci break; 279141cc406Sopenharmony_ci 280141cc406Sopenharmony_ci default: 281141cc406Sopenharmony_ci dev->sane.vendor = "PINT"; 282141cc406Sopenharmony_ci } 283141cc406Sopenharmony_ci 284141cc406Sopenharmony_ci /* Determine model. */ 285141cc406Sopenharmony_ci switch (scanio.scan_scanner_type) 286141cc406Sopenharmony_ci { 287141cc406Sopenharmony_ci case EPSON_ES300C: 288141cc406Sopenharmony_ci dev->sane.vendor = "Epson"; 289141cc406Sopenharmony_ci break; 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci case FUJITSU_M3096G: 292141cc406Sopenharmony_ci dev->sane.model = "M3096G"; 293141cc406Sopenharmony_ci break; 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_ci case HP_SCANJET_IIC: 296141cc406Sopenharmony_ci dev->sane.model = "ScanJet IIc"; 297141cc406Sopenharmony_ci break; 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci case IBM_2456: 300141cc406Sopenharmony_ci dev->sane.vendor = "IBM"; 301141cc406Sopenharmony_ci break; 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_ci case MUSTEK_06000CX: 304141cc406Sopenharmony_ci case MUSTEK_12000CX: 305141cc406Sopenharmony_ci dev->sane.vendor = "Mustek"; 306141cc406Sopenharmony_ci break; 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_ci case RICOH_FS1: 309141cc406Sopenharmony_ci dev->sane.model = "FS1"; 310141cc406Sopenharmony_ci break; 311141cc406Sopenharmony_ci 312141cc406Sopenharmony_ci case RICOH_IS410: 313141cc406Sopenharmony_ci dev->sane.model = "IS-410"; 314141cc406Sopenharmony_ci break; 315141cc406Sopenharmony_ci 316141cc406Sopenharmony_ci case RICOH_IS50: 317141cc406Sopenharmony_ci dev->sane.vendor = "Ricoh"; 318141cc406Sopenharmony_ci break; 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ci case SHARP_JX600: 321141cc406Sopenharmony_ci dev->sane.vendor = "Sharp"; 322141cc406Sopenharmony_ci break; 323141cc406Sopenharmony_ci 324141cc406Sopenharmony_ci case UMAX_UC630: 325141cc406Sopenharmony_ci case UMAX_UG630: 326141cc406Sopenharmony_ci dev->sane.vendor = "UMAX"; 327141cc406Sopenharmony_ci break; 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_ci default: 330141cc406Sopenharmony_ci dev->sane.model = "unknown"; 331141cc406Sopenharmony_ci } 332141cc406Sopenharmony_ci 333141cc406Sopenharmony_ci /* Determine the scanner type. */ 334141cc406Sopenharmony_ci switch (scanio.scan_scanner_type) 335141cc406Sopenharmony_ci { 336141cc406Sopenharmony_ci case HP_SCANJET_IIC: 337141cc406Sopenharmony_ci dev->sane.type = "flatbed scanner"; 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci /* FIXME: which of these are flatbed or handhelds? */ 340141cc406Sopenharmony_ci case EPSON_ES300C: 341141cc406Sopenharmony_ci case FUJITSU_M3096G: 342141cc406Sopenharmony_ci case IBM_2456: 343141cc406Sopenharmony_ci case MUSTEK_06000CX: 344141cc406Sopenharmony_ci case MUSTEK_12000CX: 345141cc406Sopenharmony_ci case RICOH_FS1: 346141cc406Sopenharmony_ci case RICOH_IS410: 347141cc406Sopenharmony_ci case RICOH_IS50: 348141cc406Sopenharmony_ci case SHARP_JX600: 349141cc406Sopenharmony_ci case UMAX_UC630: 350141cc406Sopenharmony_ci case UMAX_UG630: 351141cc406Sopenharmony_ci default: 352141cc406Sopenharmony_ci dev->sane.type = "generic scanner"; 353141cc406Sopenharmony_ci } 354141cc406Sopenharmony_ci 355141cc406Sopenharmony_ci DBG(1, "attach: found %s %s, x=%g-%gmm, y=%g-%gmm, " 356141cc406Sopenharmony_ci "resolution=%d-%ddpi\n", dev->sane.vendor, dev->sane.model, 357141cc406Sopenharmony_ci SANE_UNFIX (dev->x_range.min), SANE_UNFIX (dev->x_range.max), 358141cc406Sopenharmony_ci SANE_UNFIX (dev->y_range.min), SANE_UNFIX (dev->y_range.max), 359141cc406Sopenharmony_ci dev->dpi_range.min, dev->dpi_range.max); 360141cc406Sopenharmony_ci 361141cc406Sopenharmony_ci ++num_devices; 362141cc406Sopenharmony_ci dev->next = first_dev; 363141cc406Sopenharmony_ci first_dev = dev; 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_ci if (devp) 366141cc406Sopenharmony_ci *devp = dev; 367141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 368141cc406Sopenharmony_ci} 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_cistatic SANE_Status 371141cc406Sopenharmony_ciinit_options (PINT_Scanner *s) 372141cc406Sopenharmony_ci{ 373141cc406Sopenharmony_ci int i; 374141cc406Sopenharmony_ci int x0, x1, y0, y1; 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 377141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 378141cc406Sopenharmony_ci 379141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 380141cc406Sopenharmony_ci { 381141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 382141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 383141cc406Sopenharmony_ci } 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 386141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 387141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 388141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 389141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci /* "Mode" group: */ 392141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 393141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 394141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 395141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 396141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci /* scan mode */ 399141cc406Sopenharmony_ci s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 400141cc406Sopenharmony_ci s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 401141cc406Sopenharmony_ci s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 402141cc406Sopenharmony_ci s->opt[OPT_MODE].type = SANE_TYPE_STRING; 403141cc406Sopenharmony_ci s->opt[OPT_MODE].size = max_string_size (mode_list); 404141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 405141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list; 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_ci /* Translate the current PINT mode into a string. */ 408141cc406Sopenharmony_ci switch (s->hw->scanio.scan_image_mode) 409141cc406Sopenharmony_ci { 410141cc406Sopenharmony_ci case SIM_BINARY_MONOCHROME: 411141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[0]); 412141cc406Sopenharmony_ci break; 413141cc406Sopenharmony_ci 414141cc406Sopenharmony_ci case SIM_DITHERED_MONOCHROME: 415141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[1]); 416141cc406Sopenharmony_ci break; 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci case SIM_COLOR: 419141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[3]); 420141cc406Sopenharmony_ci break; 421141cc406Sopenharmony_ci 422141cc406Sopenharmony_ci case SIM_RED: 423141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[4]); 424141cc406Sopenharmony_ci break; 425141cc406Sopenharmony_ci 426141cc406Sopenharmony_ci case SIM_GREEN: 427141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[5]); 428141cc406Sopenharmony_ci break; 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci case SIM_BLUE: 431141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[6]); 432141cc406Sopenharmony_ci break; 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci case SIM_GRAYSCALE: 435141cc406Sopenharmony_ci default: 436141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[2]); 437141cc406Sopenharmony_ci } 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci /* resolution */ 440141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 441141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 442141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 443141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; 444141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 445141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 446141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range; 447141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].w = 448141cc406Sopenharmony_ci (s->hw->scanio.scan_x_resolution > s->hw->scanio.scan_y_resolution) ? 449141cc406Sopenharmony_ci s->hw->scanio.scan_x_resolution : s->hw->scanio.scan_y_resolution; 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci /* "Geometry" group: */ 452141cc406Sopenharmony_ci 453141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 454141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 455141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 456141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 457141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_ci /* Calculate the x and y millimetre coordinates from the scanio. */ 460141cc406Sopenharmony_ci x0 = SANE_FIX (s->hw->scanio.scan_x_origin / TWELVEHUNDS_PER_MM); 461141cc406Sopenharmony_ci y0 = SANE_FIX (s->hw->scanio.scan_y_origin / TWELVEHUNDS_PER_MM); 462141cc406Sopenharmony_ci x1 = SANE_FIX ((s->hw->scanio.scan_x_origin + s->hw->scanio.scan_width) 463141cc406Sopenharmony_ci / TWELVEHUNDS_PER_MM); 464141cc406Sopenharmony_ci y1 = SANE_FIX ((s->hw->scanio.scan_y_origin + s->hw->scanio.scan_height) 465141cc406Sopenharmony_ci / TWELVEHUNDS_PER_MM); 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci /* top-left x */ 468141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 469141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 470141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 471141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 472141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 473141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 474141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &s->hw->x_range; 475141cc406Sopenharmony_ci s->val[OPT_TL_X].w = x0; 476141cc406Sopenharmony_ci 477141cc406Sopenharmony_ci /* top-left y */ 478141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 479141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 480141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 481141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 482141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 483141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 484141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range; 485141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = y0; 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_ci /* bottom-right x */ 488141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 489141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 490141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 491141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 492141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 493141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 494141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &s->hw->x_range; 495141cc406Sopenharmony_ci s->val[OPT_BR_X].w = x1; 496141cc406Sopenharmony_ci 497141cc406Sopenharmony_ci /* bottom-right y */ 498141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 499141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 500141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 501141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 502141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 503141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 504141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range; 505141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = y1; 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci /* "Enhancement" group: */ 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 510141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 511141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 512141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 513141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci /* brightness */ 516141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 517141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 518141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 519141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; 520141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; 521141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 522141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &s7_range; 523141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = s->hw->scanio.scan_brightness - 128; 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci /* contrast */ 526141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 527141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 528141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 529141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; 530141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; 531141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 532141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &s7_range; 533141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = s->hw->scanio.scan_contrast - 128; 534141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 535141cc406Sopenharmony_ci} 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_cistatic SANE_Status 538141cc406Sopenharmony_cido_cancel (PINT_Scanner *s) 539141cc406Sopenharmony_ci{ 540141cc406Sopenharmony_ci /* FIXME: PINT doesn't have any good way to cancel ScanJets right now. */ 541141cc406Sopenharmony_ci#define gobble_up_buf_len 1024 542141cc406Sopenharmony_ci char buf[gobble_up_buf_len]; 543141cc406Sopenharmony_ci 544141cc406Sopenharmony_ci /* Send the restart code. */ 545141cc406Sopenharmony_ci buf[0] = ioctl (s->fd, SCIOCRESTART, 0); 546141cc406Sopenharmony_ci 547141cc406Sopenharmony_ci if (!s->scanning) 548141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 549141cc406Sopenharmony_ci 550141cc406Sopenharmony_ci s->scanning = SANE_FALSE; 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_ci /* Read to the end of the file. */ 553141cc406Sopenharmony_ci while (read (s->fd, buf, gobble_up_buf_len) > 0) 554141cc406Sopenharmony_ci ; 555141cc406Sopenharmony_ci#undef gobble_up_buf_len 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_ci /* Finally, close the file descriptor. */ 558141cc406Sopenharmony_ci if (s->fd >= 0) 559141cc406Sopenharmony_ci { 560141cc406Sopenharmony_ci close (s->fd); 561141cc406Sopenharmony_ci s->fd = -1; 562141cc406Sopenharmony_ci } 563141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 564141cc406Sopenharmony_ci} 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ciSANE_Status 567141cc406Sopenharmony_cisane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) 568141cc406Sopenharmony_ci{ 569141cc406Sopenharmony_ci char dev_name[PATH_MAX]; 570141cc406Sopenharmony_ci size_t len; 571141cc406Sopenharmony_ci FILE *fp; 572141cc406Sopenharmony_ci 573141cc406Sopenharmony_ci DBG_INIT(); 574141cc406Sopenharmony_ci 575141cc406Sopenharmony_ci if (version_code) 576141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci fp = sanei_config_open (PINT_CONFIG_FILE); 579141cc406Sopenharmony_ci if (!fp) 580141cc406Sopenharmony_ci { 581141cc406Sopenharmony_ci /* default to /dev/scanner instead of insisting on config file */ 582141cc406Sopenharmony_ci attach ("/dev/scanner", 0); 583141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 584141cc406Sopenharmony_ci } 585141cc406Sopenharmony_ci 586141cc406Sopenharmony_ci while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 587141cc406Sopenharmony_ci { 588141cc406Sopenharmony_ci if (dev_name[0] == '#') /* ignore line comments */ 589141cc406Sopenharmony_ci continue; 590141cc406Sopenharmony_ci len = strlen (dev_name); 591141cc406Sopenharmony_ci 592141cc406Sopenharmony_ci if (!len) 593141cc406Sopenharmony_ci continue; /* ignore empty lines */ 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_ci attach (dev_name, 0); 596141cc406Sopenharmony_ci } 597141cc406Sopenharmony_ci fclose (fp); 598141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 599141cc406Sopenharmony_ci} 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_civoid 602141cc406Sopenharmony_cisane_exit (void) 603141cc406Sopenharmony_ci{ 604141cc406Sopenharmony_ci PINT_Device *dev, *next; 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 607141cc406Sopenharmony_ci { 608141cc406Sopenharmony_ci next = dev->next; 609141cc406Sopenharmony_ci free ((void *) dev->sane.name); 610141cc406Sopenharmony_ci free (dev); 611141cc406Sopenharmony_ci } 612141cc406Sopenharmony_ci} 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ciSANE_Status 615141cc406Sopenharmony_cisane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only) 616141cc406Sopenharmony_ci{ 617141cc406Sopenharmony_ci static const SANE_Device **devlist = 0; 618141cc406Sopenharmony_ci PINT_Device *dev; 619141cc406Sopenharmony_ci int i; 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci if (devlist) 622141cc406Sopenharmony_ci free (devlist); 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 625141cc406Sopenharmony_ci if (!devlist) 626141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 627141cc406Sopenharmony_ci 628141cc406Sopenharmony_ci i = 0; 629141cc406Sopenharmony_ci for (dev = first_dev; i < num_devices; dev = dev->next) 630141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 631141cc406Sopenharmony_ci devlist[i++] = 0; 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci *device_list = devlist; 634141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 635141cc406Sopenharmony_ci} 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ciSANE_Status 638141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle *handle) 639141cc406Sopenharmony_ci{ 640141cc406Sopenharmony_ci SANE_Status status; 641141cc406Sopenharmony_ci PINT_Device *dev; 642141cc406Sopenharmony_ci PINT_Scanner *s; 643141cc406Sopenharmony_ci 644141cc406Sopenharmony_ci if (devicename[0]) 645141cc406Sopenharmony_ci { 646141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 647141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devicename) == 0) 648141cc406Sopenharmony_ci break; 649141cc406Sopenharmony_ci 650141cc406Sopenharmony_ci if (!dev) 651141cc406Sopenharmony_ci { 652141cc406Sopenharmony_ci status = attach (devicename, &dev); 653141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 654141cc406Sopenharmony_ci return status; 655141cc406Sopenharmony_ci } 656141cc406Sopenharmony_ci } 657141cc406Sopenharmony_ci else 658141cc406Sopenharmony_ci /* empty devicename -> use first device */ 659141cc406Sopenharmony_ci dev = first_dev; 660141cc406Sopenharmony_ci 661141cc406Sopenharmony_ci if (!dev) 662141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 665141cc406Sopenharmony_ci if (!s) 666141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 667141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 668141cc406Sopenharmony_ci s->hw = dev; 669141cc406Sopenharmony_ci s->fd = -1; 670141cc406Sopenharmony_ci 671141cc406Sopenharmony_ci init_options (s); 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci /* insert newly opened handle into list of open handles: */ 674141cc406Sopenharmony_ci s->next = first_handle; 675141cc406Sopenharmony_ci first_handle = s; 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci *handle = s; 678141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 679141cc406Sopenharmony_ci} 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_civoid 682141cc406Sopenharmony_cisane_close (SANE_Handle handle) 683141cc406Sopenharmony_ci{ 684141cc406Sopenharmony_ci PINT_Scanner *prev, *s; 685141cc406Sopenharmony_ci 686141cc406Sopenharmony_ci /* remove handle from list of open handles: */ 687141cc406Sopenharmony_ci prev = 0; 688141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 689141cc406Sopenharmony_ci { 690141cc406Sopenharmony_ci if (s == handle) 691141cc406Sopenharmony_ci break; 692141cc406Sopenharmony_ci prev = s; 693141cc406Sopenharmony_ci } 694141cc406Sopenharmony_ci if (!s) 695141cc406Sopenharmony_ci { 696141cc406Sopenharmony_ci DBG(1, "close: invalid handle %p\n", handle); 697141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 698141cc406Sopenharmony_ci } 699141cc406Sopenharmony_ci 700141cc406Sopenharmony_ci if (s->scanning) 701141cc406Sopenharmony_ci do_cancel (handle); 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci if (prev) 704141cc406Sopenharmony_ci prev->next = s->next; 705141cc406Sopenharmony_ci else 706141cc406Sopenharmony_ci first_handle = s->next; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci free (handle); 709141cc406Sopenharmony_ci} 710141cc406Sopenharmony_ci 711141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 712141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 713141cc406Sopenharmony_ci{ 714141cc406Sopenharmony_ci PINT_Scanner *s = handle; 715141cc406Sopenharmony_ci 716141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 717141cc406Sopenharmony_ci return 0; 718141cc406Sopenharmony_ci return s->opt + option; 719141cc406Sopenharmony_ci} 720141cc406Sopenharmony_ci 721141cc406Sopenharmony_ciSANE_Status 722141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 723141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int *info) 724141cc406Sopenharmony_ci{ 725141cc406Sopenharmony_ci PINT_Scanner *s = handle; 726141cc406Sopenharmony_ci SANE_Status status; 727141cc406Sopenharmony_ci SANE_Word cap; 728141cc406Sopenharmony_ci 729141cc406Sopenharmony_ci if (info) 730141cc406Sopenharmony_ci *info = 0; 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci if (s->scanning) 733141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci if (option >= NUM_OPTIONS) 736141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 737141cc406Sopenharmony_ci 738141cc406Sopenharmony_ci cap = s->opt[option].cap; 739141cc406Sopenharmony_ci 740141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 741141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 744141cc406Sopenharmony_ci { 745141cc406Sopenharmony_ci switch (option) 746141cc406Sopenharmony_ci { 747141cc406Sopenharmony_ci /* word options: */ 748141cc406Sopenharmony_ci case OPT_RESOLUTION: 749141cc406Sopenharmony_ci case OPT_TL_X: 750141cc406Sopenharmony_ci case OPT_TL_Y: 751141cc406Sopenharmony_ci case OPT_BR_X: 752141cc406Sopenharmony_ci case OPT_BR_Y: 753141cc406Sopenharmony_ci case OPT_NUM_OPTS: 754141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 755141cc406Sopenharmony_ci case OPT_CONTRAST: 756141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option].w; 757141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 758141cc406Sopenharmony_ci 759141cc406Sopenharmony_ci /* string options: */ 760141cc406Sopenharmony_ci case OPT_MODE: 761141cc406Sopenharmony_ci strcpy (val, s->val[option].s); 762141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 763141cc406Sopenharmony_ci } 764141cc406Sopenharmony_ci } 765141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 766141cc406Sopenharmony_ci { 767141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 768141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 769141cc406Sopenharmony_ci 770141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 771141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 772141cc406Sopenharmony_ci return status; 773141cc406Sopenharmony_ci 774141cc406Sopenharmony_ci switch (option) 775141cc406Sopenharmony_ci { 776141cc406Sopenharmony_ci /* (mostly) side-effect-free word options: */ 777141cc406Sopenharmony_ci case OPT_RESOLUTION: 778141cc406Sopenharmony_ci case OPT_TL_X: 779141cc406Sopenharmony_ci case OPT_TL_Y: 780141cc406Sopenharmony_ci case OPT_BR_X: 781141cc406Sopenharmony_ci case OPT_BR_Y: 782141cc406Sopenharmony_ci if (info) 783141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 784141cc406Sopenharmony_ci /* fall through */ 785141cc406Sopenharmony_ci case OPT_NUM_OPTS: 786141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 787141cc406Sopenharmony_ci case OPT_CONTRAST: 788141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 789141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci case OPT_MODE: 792141cc406Sopenharmony_ci if (s->val[option].s) 793141cc406Sopenharmony_ci free (s->val[option].s); 794141cc406Sopenharmony_ci s->val[option].s = strdup (val); 795141cc406Sopenharmony_ci if (info) 796141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 797141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 798141cc406Sopenharmony_ci } 799141cc406Sopenharmony_ci } 800141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 801141cc406Sopenharmony_ci} 802141cc406Sopenharmony_ci 803141cc406Sopenharmony_ciSANE_Status 804141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters *params) 805141cc406Sopenharmony_ci{ 806141cc406Sopenharmony_ci PINT_Scanner *s = handle; 807141cc406Sopenharmony_ci struct scan_io scanio; 808141cc406Sopenharmony_ci 809141cc406Sopenharmony_ci if (!s->scanning) 810141cc406Sopenharmony_ci { 811141cc406Sopenharmony_ci u_long x0, y0, width, height; 812141cc406Sopenharmony_ci const char *mode; 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci /* Grab the scanio for this device. */ 815141cc406Sopenharmony_ci if (s->fd < 0) 816141cc406Sopenharmony_ci { 817141cc406Sopenharmony_ci s->fd = open (s->hw->sane.name, O_RDONLY, 0); 818141cc406Sopenharmony_ci if (s->fd < 0) 819141cc406Sopenharmony_ci { 820141cc406Sopenharmony_ci DBG(1, "open of %s failed: %s\n", 821141cc406Sopenharmony_ci s->hw->sane.name, strerror (errno)); 822141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 823141cc406Sopenharmony_ci } 824141cc406Sopenharmony_ci } 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci if (ioctl (s->fd, SCIOCGET, &scanio) < 0) 827141cc406Sopenharmony_ci { 828141cc406Sopenharmony_ci DBG(1, "getting scanner state failed: %s", strerror (errno)); 829141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 830141cc406Sopenharmony_ci } 831141cc406Sopenharmony_ci 832141cc406Sopenharmony_ci memset (&s->params, 0, sizeof (s->params)); 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci /* FIXME: there is some lossage here: the parameters change due to 835141cc406Sopenharmony_ci roundoff errors between converting to fixed point millimetres 836141cc406Sopenharmony_ci and back. */ 837141cc406Sopenharmony_ci x0 = SANE_UNFIX (s->val[OPT_TL_X].w * TWELVEHUNDS_PER_MM); 838141cc406Sopenharmony_ci y0 = SANE_UNFIX (s->val[OPT_TL_Y].w * TWELVEHUNDS_PER_MM); 839141cc406Sopenharmony_ci width = SANE_UNFIX ((s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) 840141cc406Sopenharmony_ci * TWELVEHUNDS_PER_MM); 841141cc406Sopenharmony_ci height = SANE_UNFIX ((s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) 842141cc406Sopenharmony_ci * TWELVEHUNDS_PER_MM); 843141cc406Sopenharmony_ci 844141cc406Sopenharmony_ci /* x and y dpi: */ 845141cc406Sopenharmony_ci scanio.scan_x_resolution = s->val[OPT_RESOLUTION].w; 846141cc406Sopenharmony_ci scanio.scan_y_resolution = s->val[OPT_RESOLUTION].w; 847141cc406Sopenharmony_ci 848141cc406Sopenharmony_ci /* set scan extents, in 1/1200'ths of an inch */ 849141cc406Sopenharmony_ci scanio.scan_x_origin = x0; 850141cc406Sopenharmony_ci scanio.scan_y_origin = y0; 851141cc406Sopenharmony_ci scanio.scan_width = width; 852141cc406Sopenharmony_ci scanio.scan_height = height; 853141cc406Sopenharmony_ci 854141cc406Sopenharmony_ci /* brightness and contrast */ 855141cc406Sopenharmony_ci scanio.scan_brightness = s->val[OPT_BRIGHTNESS].w + 128; 856141cc406Sopenharmony_ci scanio.scan_contrast = s->val[OPT_CONTRAST].w + 128; 857141cc406Sopenharmony_ci 858141cc406Sopenharmony_ci /* set the scan image mode */ 859141cc406Sopenharmony_ci mode = s->val[OPT_MODE].s; 860141cc406Sopenharmony_ci if (!strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART)) 861141cc406Sopenharmony_ci { 862141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 863141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_BINARY_MONOCHROME; 864141cc406Sopenharmony_ci } 865141cc406Sopenharmony_ci else if (!strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE)) 866141cc406Sopenharmony_ci { 867141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 868141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_DITHERED_MONOCHROME; 869141cc406Sopenharmony_ci } 870141cc406Sopenharmony_ci else if (!strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY)) 871141cc406Sopenharmony_ci { 872141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 873141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_GRAYSCALE; 874141cc406Sopenharmony_ci } 875141cc406Sopenharmony_ci else if (!strcmp (mode, "Red")) 876141cc406Sopenharmony_ci { 877141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RED; 878141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_RED; 879141cc406Sopenharmony_ci } 880141cc406Sopenharmony_ci else if (!strcmp (mode, "Green")) 881141cc406Sopenharmony_ci { 882141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GREEN; 883141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_GREEN; 884141cc406Sopenharmony_ci } 885141cc406Sopenharmony_ci else if (!strcmp (mode, "Blue")) 886141cc406Sopenharmony_ci { 887141cc406Sopenharmony_ci s->params.format = SANE_FRAME_BLUE; 888141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_BLUE; 889141cc406Sopenharmony_ci } 890141cc406Sopenharmony_ci else 891141cc406Sopenharmony_ci { 892141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 893141cc406Sopenharmony_ci scanio.scan_image_mode = SIM_COLOR; 894141cc406Sopenharmony_ci } 895141cc406Sopenharmony_ci 896141cc406Sopenharmony_ci /* inquire resulting size of image after setting it up */ 897141cc406Sopenharmony_ci if (ioctl (s->fd, SCIOCSET, &scanio) < 0) 898141cc406Sopenharmony_ci { 899141cc406Sopenharmony_ci DBG(1, "setting scan parameters failed: %s", strerror (errno)); 900141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 901141cc406Sopenharmony_ci } 902141cc406Sopenharmony_ci if (ioctl (s->fd, SCIOCGET, &scanio) < 0) 903141cc406Sopenharmony_ci { 904141cc406Sopenharmony_ci DBG(1, "getting scan parameters failed: %s", strerror (errno)); 905141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci /* Save all the PINT-computed values. */ 909141cc406Sopenharmony_ci s->params.pixels_per_line = scanio.scan_pixels_per_line; 910141cc406Sopenharmony_ci s->params.bytes_per_line = 911141cc406Sopenharmony_ci (scanio.scan_bits_per_pixel * scanio.scan_pixels_per_line + 7) / 8; 912141cc406Sopenharmony_ci s->params.lines = scanio.scan_lines; 913141cc406Sopenharmony_ci s->params.depth = (scanio.scan_image_mode == SIM_COLOR) ? 914141cc406Sopenharmony_ci scanio.scan_bits_per_pixel / 3 : scanio.scan_bits_per_pixel; 915141cc406Sopenharmony_ci 916141cc406Sopenharmony_ci /* FIXME: this will need to be different for hand scanners. */ 917141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 918141cc406Sopenharmony_ci } 919141cc406Sopenharmony_ci if (params) 920141cc406Sopenharmony_ci *params = s->params; 921141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 922141cc406Sopenharmony_ci} 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ciSANE_Status 925141cc406Sopenharmony_cisane_start (SANE_Handle handle) 926141cc406Sopenharmony_ci{ 927141cc406Sopenharmony_ci PINT_Scanner *s = handle; 928141cc406Sopenharmony_ci SANE_Status status; 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci /* First make sure we have a current parameter set. This call actually 931141cc406Sopenharmony_ci uses the PINT driver to do the calculations, so we trust its results. */ 932141cc406Sopenharmony_ci status = sane_get_parameters (s, 0); 933141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 934141cc406Sopenharmony_ci return status; 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ci DBG(1, "%d pixels per line, %d bytes, %d lines high, dpi=%d\n", 937141cc406Sopenharmony_ci s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines, 938141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].w); 939141cc406Sopenharmony_ci 940141cc406Sopenharmony_ci /* The scan is triggered in sane_read. */ 941141cc406Sopenharmony_ci s->scanning = SANE_TRUE; 942141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 943141cc406Sopenharmony_ci} 944141cc406Sopenharmony_ci 945141cc406Sopenharmony_ciSANE_Status 946141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) 947141cc406Sopenharmony_ci{ 948141cc406Sopenharmony_ci PINT_Scanner *s = handle; 949141cc406Sopenharmony_ci ssize_t nread; 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci *len = 0; 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci if (!s->scanning) 954141cc406Sopenharmony_ci return do_cancel (s); 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci /* Verrry simple. Just suck up all the data PINT passes to us. */ 957141cc406Sopenharmony_ci nread = read (s->fd, buf, max_len); 958141cc406Sopenharmony_ci if (nread <= 0) 959141cc406Sopenharmony_ci { 960141cc406Sopenharmony_ci do_cancel (s); 961141cc406Sopenharmony_ci return (nread == 0) ? SANE_STATUS_EOF : SANE_STATUS_IO_ERROR; 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci 964141cc406Sopenharmony_ci *len = nread; 965141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 966141cc406Sopenharmony_ci} 967141cc406Sopenharmony_ci 968141cc406Sopenharmony_civoid 969141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 970141cc406Sopenharmony_ci{ 971141cc406Sopenharmony_ci PINT_Scanner *s = handle; 972141cc406Sopenharmony_ci do_cancel (s); 973141cc406Sopenharmony_ci} 974141cc406Sopenharmony_ci 975141cc406Sopenharmony_ciSANE_Status 976141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 977141cc406Sopenharmony_ci{ 978141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 979141cc406Sopenharmony_ci} 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ciSANE_Status 982141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int *fd) 983141cc406Sopenharmony_ci{ 984141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 985141cc406Sopenharmony_ci} 986