1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1999 Juergen G. Schimmer 3141cc406Sopenharmony_ci Updates and bugfixes (C) 2002 - 2004 Henning Meier-Geinitz 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 21141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 24141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 25141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 26141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 27141cc406Sopenharmony_ci account of linking the SANE library code into it. 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 30141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 31141cc406Sopenharmony_ci License. 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 34141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 35141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 38141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 39141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci This file implements a SANE backend for v4l-Devices. 42141cc406Sopenharmony_ci*/ 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci#define BUILD 5 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci#include "../include/sane/config.h" 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include <assert.h> 49141cc406Sopenharmony_ci#include <ctype.h> 50141cc406Sopenharmony_ci#include <errno.h> 51141cc406Sopenharmony_ci#include <fcntl.h> 52141cc406Sopenharmony_ci#include <limits.h> 53141cc406Sopenharmony_ci#include <math.h> 54141cc406Sopenharmony_ci#include <setjmp.h> 55141cc406Sopenharmony_ci#include <signal.h> 56141cc406Sopenharmony_ci#include <stdio.h> 57141cc406Sopenharmony_ci#include <stdlib.h> 58141cc406Sopenharmony_ci#include <string.h> 59141cc406Sopenharmony_ci#include <sys/types.h> 60141cc406Sopenharmony_ci#include <sys/wait.h> 61141cc406Sopenharmony_ci#include <unistd.h> 62141cc406Sopenharmony_ci#include <sys/mman.h> 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci#include <unistd.h> 65141cc406Sopenharmony_ci#include <sys/time.h> 66141cc406Sopenharmony_ci#include <sys/stat.h> 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci#include "../include/sane/sane.h" 69141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 70141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci#include <sys/ioctl.h> 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci#define BACKEND_NAME v4l 75141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci#ifndef PATH_MAX 78141cc406Sopenharmony_ci# define PATH_MAX 1024 79141cc406Sopenharmony_ci#endif 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 82141cc406Sopenharmony_ci#define V4L_CONFIG_FILE "v4l.conf" 83141cc406Sopenharmony_ci 84141cc406Sopenharmony_ci#include <libv4l1.h> 85141cc406Sopenharmony_ci#include "v4l.h" 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL; 88141cc406Sopenharmony_cistatic int num_devices; 89141cc406Sopenharmony_cistatic V4L_Device *first_dev; 90141cc406Sopenharmony_cistatic V4L_Scanner *first_handle; 91141cc406Sopenharmony_cistatic char *buffer; 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] = { 94141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_COLOR, 95141cc406Sopenharmony_ci 0 96141cc406Sopenharmony_ci}; 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_cistatic const SANE_Range u8_range = { 99141cc406Sopenharmony_ci /* min, max, quantization */ 100141cc406Sopenharmony_ci 0, 255, 0 101141cc406Sopenharmony_ci}; 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_cistatic SANE_Range x_range = { 0, 338, 2 }; 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_cistatic SANE_Range odd_x_range = { 1, 339, 2 }; 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_cistatic SANE_Range y_range = { 0, 249, 1 }; 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_cistatic SANE_Range odd_y_range = { 1, 250, 1 }; 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_cistatic SANE_Parameters parms = { 113141cc406Sopenharmony_ci SANE_FRAME_RGB, 114141cc406Sopenharmony_ci 1, /* 1 = Last Frame , 0 = More Frames to come */ 115141cc406Sopenharmony_ci 0, /* Number of bytes returned per scan line: */ 116141cc406Sopenharmony_ci 0, /* Number of pixels per scan line. */ 117141cc406Sopenharmony_ci 0, /* Number of lines for the current scan. */ 118141cc406Sopenharmony_ci 8, /* Number of bits per sample. */ 119141cc406Sopenharmony_ci}; 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_cistatic SANE_Status 122141cc406Sopenharmony_ciattach (const char *devname, V4L_Device ** devp) 123141cc406Sopenharmony_ci{ 124141cc406Sopenharmony_ci V4L_Device *dev; 125141cc406Sopenharmony_ci static int v4lfd; 126141cc406Sopenharmony_ci static struct video_capability capability; 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_ci errno = 0; 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 131141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 132141cc406Sopenharmony_ci { 133141cc406Sopenharmony_ci if (devp) 134141cc406Sopenharmony_ci *devp = dev; 135141cc406Sopenharmony_ci DBG (5, "attach: device %s is already known\n", devname); 136141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 137141cc406Sopenharmony_ci } 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci DBG (3, "attach: trying to open %s\n", devname); 140141cc406Sopenharmony_ci v4lfd = v4l1_open (devname, O_RDWR); 141141cc406Sopenharmony_ci if (v4lfd != -1) 142141cc406Sopenharmony_ci { 143141cc406Sopenharmony_ci if (v4l1_ioctl (v4lfd, VIDIOCGCAP, &capability) == -1) 144141cc406Sopenharmony_ci { 145141cc406Sopenharmony_ci DBG (1, 146141cc406Sopenharmony_ci "attach: ioctl (%d, VIDIOCGCAP,..) failed on `%s': %s\n", 147141cc406Sopenharmony_ci v4lfd, devname, strerror (errno)); 148141cc406Sopenharmony_ci v4l1_close (v4lfd); 149141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 150141cc406Sopenharmony_ci } 151141cc406Sopenharmony_ci if (!(VID_TYPE_CAPTURE & capability.type)) 152141cc406Sopenharmony_ci { 153141cc406Sopenharmony_ci DBG (1, "attach: device %s can't capture to memory -- exiting\n", 154141cc406Sopenharmony_ci devname); 155141cc406Sopenharmony_ci v4l1_close (v4lfd); 156141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 157141cc406Sopenharmony_ci } 158141cc406Sopenharmony_ci DBG (2, "attach: found videodev `%s' on `%s'\n", capability.name, 159141cc406Sopenharmony_ci devname); 160141cc406Sopenharmony_ci v4l1_close (v4lfd); 161141cc406Sopenharmony_ci } 162141cc406Sopenharmony_ci else 163141cc406Sopenharmony_ci { 164141cc406Sopenharmony_ci DBG (1, "attach: failed to open device `%s': %s\n", devname, 165141cc406Sopenharmony_ci strerror (errno)); 166141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 167141cc406Sopenharmony_ci } 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 170141cc406Sopenharmony_ci if (!dev) 171141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci memset (dev, 0, sizeof (*dev)); 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci dev->sane.name = strdup (devname); 176141cc406Sopenharmony_ci if (!dev->sane.name) 177141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 178141cc406Sopenharmony_ci dev->sane.vendor = "Noname"; 179141cc406Sopenharmony_ci dev->sane.model = strdup (capability.name); 180141cc406Sopenharmony_ci if (!dev->sane.model) 181141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 182141cc406Sopenharmony_ci dev->sane.type = "virtual device"; 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci ++num_devices; 185141cc406Sopenharmony_ci dev->next = first_dev; 186141cc406Sopenharmony_ci first_dev = dev; 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci if (devp) 189141cc406Sopenharmony_ci *devp = dev; 190141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 191141cc406Sopenharmony_ci} 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_cistatic void 194141cc406Sopenharmony_ciupdate_parameters (V4L_Scanner * s) 195141cc406Sopenharmony_ci{ 196141cc406Sopenharmony_ci /* ??? should be per-device */ 197141cc406Sopenharmony_ci x_range.min = 0; 198141cc406Sopenharmony_ci x_range.max = s->capability.maxwidth - s->capability.minwidth; 199141cc406Sopenharmony_ci x_range.quant = 1; 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci y_range.min = 0; 202141cc406Sopenharmony_ci y_range.max = s->capability.maxheight - s->capability.minheight; 203141cc406Sopenharmony_ci y_range.quant = 1; 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci odd_x_range.min = s->capability.minwidth; 206141cc406Sopenharmony_ci odd_x_range.max = s->capability.maxwidth; 207141cc406Sopenharmony_ci if (odd_x_range.max > 767) 208141cc406Sopenharmony_ci { 209141cc406Sopenharmony_ci odd_x_range.max = 767; 210141cc406Sopenharmony_ci x_range.max = 767 - s->capability.minwidth; 211141cc406Sopenharmony_ci }; 212141cc406Sopenharmony_ci odd_x_range.quant = 1; 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_ci odd_y_range.min = s->capability.minheight; 215141cc406Sopenharmony_ci odd_y_range.max = s->capability.maxheight; 216141cc406Sopenharmony_ci if (odd_y_range.max > 511) 217141cc406Sopenharmony_ci { 218141cc406Sopenharmony_ci odd_y_range.max = 511; 219141cc406Sopenharmony_ci y_range.max = 511 - s->capability.minheight; 220141cc406Sopenharmony_ci }; 221141cc406Sopenharmony_ci odd_y_range.quant = 1; 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci parms.lines = s->window.height; 224141cc406Sopenharmony_ci parms.pixels_per_line = s->window.width; 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci switch (s->pict.palette) 227141cc406Sopenharmony_ci { 228141cc406Sopenharmony_ci case VIDEO_PALETTE_GREY: /* Linear greyscale */ 229141cc406Sopenharmony_ci { 230141cc406Sopenharmony_ci parms.format = SANE_FRAME_GRAY; 231141cc406Sopenharmony_ci parms.depth = 8; 232141cc406Sopenharmony_ci parms.bytes_per_line = s->window.width; 233141cc406Sopenharmony_ci break; 234141cc406Sopenharmony_ci } 235141cc406Sopenharmony_ci case VIDEO_PALETTE_RGB24: /* 24bit RGB */ 236141cc406Sopenharmony_ci { 237141cc406Sopenharmony_ci parms.format = SANE_FRAME_RGB; 238141cc406Sopenharmony_ci parms.depth = 8; 239141cc406Sopenharmony_ci parms.bytes_per_line = s->window.width * 3; 240141cc406Sopenharmony_ci break; 241141cc406Sopenharmony_ci } 242141cc406Sopenharmony_ci default: 243141cc406Sopenharmony_ci { 244141cc406Sopenharmony_ci parms.format = SANE_FRAME_GRAY; 245141cc406Sopenharmony_ci parms.bytes_per_line = s->window.width; 246141cc406Sopenharmony_ci break; 247141cc406Sopenharmony_ci } 248141cc406Sopenharmony_ci } 249141cc406Sopenharmony_ci} 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_cistatic SANE_Status 252141cc406Sopenharmony_ciinit_options (V4L_Scanner * s) 253141cc406Sopenharmony_ci{ 254141cc406Sopenharmony_ci int i; 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci memset (s->opt, 0, sizeof (s->opt)); 257141cc406Sopenharmony_ci memset (s->val, 0, sizeof (s->val)); 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 260141cc406Sopenharmony_ci { 261141cc406Sopenharmony_ci s->opt[i].size = sizeof (SANE_Word); 262141cc406Sopenharmony_ci s->opt[i].cap = (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT); 263141cc406Sopenharmony_ci } 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_ci /* Number of options */ 266141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 267141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 268141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 269141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 270141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 271141cc406Sopenharmony_ci 272141cc406Sopenharmony_ci /* "Mode" group: */ 273141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = "Scan Mode"; 274141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = ""; 275141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 276141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 277141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci /* mode */ 280141cc406Sopenharmony_ci s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 281141cc406Sopenharmony_ci s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 282141cc406Sopenharmony_ci s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 283141cc406Sopenharmony_ci s->opt[OPT_MODE].type = SANE_TYPE_STRING; 284141cc406Sopenharmony_ci s->opt[OPT_MODE].unit = SANE_UNIT_NONE; 285141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 286141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list; 287141cc406Sopenharmony_ci s->val[OPT_MODE].s = strdup (mode_list[0]); 288141cc406Sopenharmony_ci if (!s->val[OPT_MODE].s) 289141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 290141cc406Sopenharmony_ci s->opt[OPT_MODE].size = 1; /* '\0' */ 291141cc406Sopenharmony_ci for (i = 0; mode_list[i] != 0; ++i) 292141cc406Sopenharmony_ci { 293141cc406Sopenharmony_ci int len = strlen(mode_list[i]) + 1; 294141cc406Sopenharmony_ci if (s->opt[OPT_MODE].size < len) 295141cc406Sopenharmony_ci s->opt[OPT_MODE].size = len; 296141cc406Sopenharmony_ci } 297141cc406Sopenharmony_ci 298141cc406Sopenharmony_ci /* channel */ 299141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].name = "channel"; 300141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].title = "Channel"; 301141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].desc = 302141cc406Sopenharmony_ci "Selects the channel of the v4l device (e.g. television " "or video-in."; 303141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].type = SANE_TYPE_STRING; 304141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].unit = SANE_UNIT_NONE; 305141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].constraint_type = SANE_CONSTRAINT_STRING_LIST; 306141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].constraint.string_list = s->channel; 307141cc406Sopenharmony_ci s->val[OPT_CHANNEL].s = strdup (s->channel[0]); 308141cc406Sopenharmony_ci if (!s->val[OPT_CHANNEL].s) 309141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 310141cc406Sopenharmony_ci if (s->channel[0] == 0 || s->channel[1] == 0) 311141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE; 312141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].size = 1; /* '\0' */ 313141cc406Sopenharmony_ci for (i = 0; s->channel[i] != 0; ++i) 314141cc406Sopenharmony_ci { 315141cc406Sopenharmony_ci int len = strlen(s->channel[i]) + 1; 316141cc406Sopenharmony_ci if (s->opt[OPT_CHANNEL].size < len) 317141cc406Sopenharmony_ci s->opt[OPT_CHANNEL].size = len; 318141cc406Sopenharmony_ci } 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ci /* "Geometry" group: */ 321141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 322141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = ""; 323141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 324141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 325141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci/* top-left x *//* ??? first check if window is settable at all */ 328141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 329141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 330141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 331141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_INT; 332141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; 333141cc406Sopenharmony_ci s->opt[OPT_TL_X].cap |= SANE_CAP_INACTIVE; 334141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 335141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = &x_range; 336141cc406Sopenharmony_ci s->val[OPT_TL_X].w = 0; 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci /* top-left y */ 339141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 340141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 341141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 342141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_INT; 343141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; 344141cc406Sopenharmony_ci s->opt[OPT_TL_Y].cap |= SANE_CAP_INACTIVE; 345141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 346141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = &y_range; 347141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = 0; 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci /* bottom-right x */ 350141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 351141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 352141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 353141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_INT; 354141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; 355141cc406Sopenharmony_ci s->opt[OPT_BR_X].cap |= SANE_CAP_INACTIVE; 356141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 357141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = &odd_x_range; 358141cc406Sopenharmony_ci s->val[OPT_BR_X].w = s->capability.maxwidth; 359141cc406Sopenharmony_ci if (s->val[OPT_BR_X].w > 767) 360141cc406Sopenharmony_ci s->val[OPT_BR_X].w = 767; 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci /* bottom-right y */ 363141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 364141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 365141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 366141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_INT; 367141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; 368141cc406Sopenharmony_ci s->opt[OPT_BR_Y].cap |= SANE_CAP_INACTIVE; 369141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 370141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = &odd_y_range; 371141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = s->capability.maxheight; 372141cc406Sopenharmony_ci if (s->val[OPT_BR_Y].w > 511) 373141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = 511; 374141cc406Sopenharmony_ci 375141cc406Sopenharmony_ci /* "Enhancement" group: */ 376141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 377141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 378141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 379141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 380141cc406Sopenharmony_ci s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 381141cc406Sopenharmony_ci 382141cc406Sopenharmony_ci /* brightness */ 383141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 384141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 385141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 386141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; 387141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 388141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &u8_range; 389141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = s->pict.brightness / 256; 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci /* hue */ 392141cc406Sopenharmony_ci s->opt[OPT_HUE].name = SANE_NAME_HUE; 393141cc406Sopenharmony_ci s->opt[OPT_HUE].title = SANE_TITLE_HUE; 394141cc406Sopenharmony_ci s->opt[OPT_HUE].desc = SANE_DESC_HUE; 395141cc406Sopenharmony_ci s->opt[OPT_HUE].type = SANE_TYPE_INT; 396141cc406Sopenharmony_ci s->opt[OPT_HUE].constraint_type = SANE_CONSTRAINT_RANGE; 397141cc406Sopenharmony_ci s->opt[OPT_HUE].constraint.range = &u8_range; 398141cc406Sopenharmony_ci s->val[OPT_HUE].w = s->pict.hue / 256; 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci /* colour */ 401141cc406Sopenharmony_ci s->opt[OPT_COLOR].name = "color"; 402141cc406Sopenharmony_ci s->opt[OPT_COLOR].title = "Picture color"; 403141cc406Sopenharmony_ci s->opt[OPT_COLOR].desc = "Sets the picture's color."; 404141cc406Sopenharmony_ci s->opt[OPT_COLOR].type = SANE_TYPE_INT; 405141cc406Sopenharmony_ci s->opt[OPT_COLOR].constraint_type = SANE_CONSTRAINT_RANGE; 406141cc406Sopenharmony_ci s->opt[OPT_COLOR].constraint.range = &u8_range; 407141cc406Sopenharmony_ci s->val[OPT_COLOR].w = s->pict.colour / 256; 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci /* contrast */ 410141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; 411141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; 412141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; 413141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; 414141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; 415141cc406Sopenharmony_ci s->opt[OPT_CONTRAST].constraint.range = &u8_range; 416141cc406Sopenharmony_ci s->val[OPT_CONTRAST].w = s->pict.contrast / 256; 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci /* whiteness */ 419141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].name = SANE_NAME_WHITE_LEVEL; 420141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].title = SANE_TITLE_WHITE_LEVEL; 421141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].desc = SANE_DESC_WHITE_LEVEL; 422141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].type = SANE_TYPE_INT; 423141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].constraint_type = SANE_CONSTRAINT_RANGE; 424141cc406Sopenharmony_ci s->opt[OPT_WHITE_LEVEL].constraint.range = &u8_range; 425141cc406Sopenharmony_ci s->val[OPT_WHITE_LEVEL].w = s->pict.whiteness / 256; 426141cc406Sopenharmony_ci 427141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 428141cc406Sopenharmony_ci} 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ciSANE_Status 431141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 432141cc406Sopenharmony_ci{ 433141cc406Sopenharmony_ci char dev_name[PATH_MAX], *str; 434141cc406Sopenharmony_ci size_t len; 435141cc406Sopenharmony_ci FILE *fp; 436141cc406Sopenharmony_ci 437141cc406Sopenharmony_ci (void) authorize; /* stop gcc from complaining */ 438141cc406Sopenharmony_ci DBG_INIT (); 439141cc406Sopenharmony_ci 440141cc406Sopenharmony_ci DBG (2, "SANE v4l backend version %d.%d build %d from %s\n", SANE_CURRENT_MAJOR, 441141cc406Sopenharmony_ci SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING); 442141cc406Sopenharmony_ci 443141cc406Sopenharmony_ci if (version_code) 444141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci fp = sanei_config_open (V4L_CONFIG_FILE); 447141cc406Sopenharmony_ci if (!fp) 448141cc406Sopenharmony_ci { 449141cc406Sopenharmony_ci DBG (2, 450141cc406Sopenharmony_ci "sane_init: file `%s' not accessible (%s), trying /dev/video0\n", 451141cc406Sopenharmony_ci V4L_CONFIG_FILE, strerror (errno)); 452141cc406Sopenharmony_ci 453141cc406Sopenharmony_ci return attach ("/dev/video0", 0); 454141cc406Sopenharmony_ci } 455141cc406Sopenharmony_ci 456141cc406Sopenharmony_ci while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 457141cc406Sopenharmony_ci { 458141cc406Sopenharmony_ci if (dev_name[0] == '#') /* ignore line comments */ 459141cc406Sopenharmony_ci continue; 460141cc406Sopenharmony_ci len = strlen (dev_name); 461141cc406Sopenharmony_ci 462141cc406Sopenharmony_ci if (!len) 463141cc406Sopenharmony_ci continue; /* ignore empty lines */ 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci /* Remove trailing space and trailing comments */ 466141cc406Sopenharmony_ci for (str = dev_name; *str && !isspace (*str) && *str != '#'; ++str); 467141cc406Sopenharmony_ci attach (dev_name, 0); 468141cc406Sopenharmony_ci } 469141cc406Sopenharmony_ci fclose (fp); 470141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 471141cc406Sopenharmony_ci} 472141cc406Sopenharmony_ci 473141cc406Sopenharmony_civoid 474141cc406Sopenharmony_cisane_exit (void) 475141cc406Sopenharmony_ci{ 476141cc406Sopenharmony_ci V4L_Device *dev, *next; 477141cc406Sopenharmony_ci 478141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 479141cc406Sopenharmony_ci { 480141cc406Sopenharmony_ci next = dev->next; 481141cc406Sopenharmony_ci free ((void *) dev->sane.name); 482141cc406Sopenharmony_ci free ((void *) dev->sane.model); 483141cc406Sopenharmony_ci free (dev); 484141cc406Sopenharmony_ci } 485141cc406Sopenharmony_ci 486141cc406Sopenharmony_ci if (NULL != devlist) 487141cc406Sopenharmony_ci { 488141cc406Sopenharmony_ci free (devlist); 489141cc406Sopenharmony_ci devlist = NULL; 490141cc406Sopenharmony_ci } 491141cc406Sopenharmony_ci DBG (5, "sane_exit: all devices freed\n"); 492141cc406Sopenharmony_ci} 493141cc406Sopenharmony_ci 494141cc406Sopenharmony_ciSANE_Status 495141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only) 496141cc406Sopenharmony_ci{ 497141cc406Sopenharmony_ci V4L_Device *dev; 498141cc406Sopenharmony_ci int i; 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci DBG (5, "sane_get_devices\n"); 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci if (devlist) 503141cc406Sopenharmony_ci free (devlist); 504141cc406Sopenharmony_ci 505141cc406Sopenharmony_ci devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 506141cc406Sopenharmony_ci if (!devlist) 507141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci i = 0; 510141cc406Sopenharmony_ci for (dev = first_dev; i < num_devices; dev = dev->next) 511141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 512141cc406Sopenharmony_ci devlist[i++] = 0; 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci *device_list = devlist; 515141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 516141cc406Sopenharmony_ci} 517141cc406Sopenharmony_ci 518141cc406Sopenharmony_ciSANE_Status 519141cc406Sopenharmony_cisane_open (SANE_String_Const devname, SANE_Handle * handle) 520141cc406Sopenharmony_ci{ 521141cc406Sopenharmony_ci V4L_Device *dev; 522141cc406Sopenharmony_ci V4L_Scanner *s; 523141cc406Sopenharmony_ci static int v4lfd; 524141cc406Sopenharmony_ci int i; 525141cc406Sopenharmony_ci struct video_channel channel; 526141cc406Sopenharmony_ci SANE_Status status; 527141cc406Sopenharmony_ci int max_channels = MAX_CHANNELS; 528141cc406Sopenharmony_ci 529141cc406Sopenharmony_ci if (!devname) 530141cc406Sopenharmony_ci { 531141cc406Sopenharmony_ci DBG (1, "sane_open: devname == 0\n"); 532141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 533141cc406Sopenharmony_ci } 534141cc406Sopenharmony_ci 535141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 536141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devname) == 0) 537141cc406Sopenharmony_ci { 538141cc406Sopenharmony_ci DBG (5, "sane_open: device %s found in devlist\n", devname); 539141cc406Sopenharmony_ci break; 540141cc406Sopenharmony_ci } 541141cc406Sopenharmony_ci if (!devname[0]) 542141cc406Sopenharmony_ci dev = first_dev; 543141cc406Sopenharmony_ci if (!dev) 544141cc406Sopenharmony_ci { 545141cc406Sopenharmony_ci DBG (1, "sane_open: device %s doesn't seem to be a v4l " 546141cc406Sopenharmony_ci "device\n", devname); 547141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 548141cc406Sopenharmony_ci } 549141cc406Sopenharmony_ci 550141cc406Sopenharmony_ci v4lfd = v4l1_open (devname, O_RDWR); 551141cc406Sopenharmony_ci if (v4lfd == -1) 552141cc406Sopenharmony_ci { 553141cc406Sopenharmony_ci DBG (1, "sane_open: can't open %s (%s)\n", devname, strerror (errno)); 554141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 555141cc406Sopenharmony_ci } 556141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 557141cc406Sopenharmony_ci if (!s) 558141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 559141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 560141cc406Sopenharmony_ci s->user_corner = 0; /* ??? */ 561141cc406Sopenharmony_ci s->devicename = devname; 562141cc406Sopenharmony_ci s->fd = v4lfd; 563141cc406Sopenharmony_ci 564141cc406Sopenharmony_ci if (v4l1_ioctl (s->fd, VIDIOCGCAP, &s->capability) == -1) 565141cc406Sopenharmony_ci { 566141cc406Sopenharmony_ci DBG (1, "sane_open: ioctl (%d, VIDIOCGCAP,..) failed on `%s': %s\n", 567141cc406Sopenharmony_ci s->fd, devname, strerror (errno)); 568141cc406Sopenharmony_ci v4l1_close (s->fd); 569141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 570141cc406Sopenharmony_ci } 571141cc406Sopenharmony_ci 572141cc406Sopenharmony_ci DBG (5, "sane_open: %d channels, %d audio devices\n", 573141cc406Sopenharmony_ci s->capability.channels, s->capability.audios); 574141cc406Sopenharmony_ci DBG (5, "sane_open: minwidth=%d, minheight=%d, maxwidth=%d, " 575141cc406Sopenharmony_ci "maxheight=%d\n", s->capability.minwidth, s->capability.minheight, 576141cc406Sopenharmony_ci s->capability.maxwidth, s->capability.maxheight); 577141cc406Sopenharmony_ci if (VID_TYPE_CAPTURE & s->capability.type) 578141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device can capture to memory\n"); 579141cc406Sopenharmony_ci if (VID_TYPE_TUNER & s->capability.type) 580141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device has a tuner of some form\n"); 581141cc406Sopenharmony_ci if (VID_TYPE_TELETEXT & s->capability.type) 582141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device supports teletext\n"); 583141cc406Sopenharmony_ci if (VID_TYPE_OVERLAY & s->capability.type) 584141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device can overlay its image onto the frame " 585141cc406Sopenharmony_ci "buffer\n"); 586141cc406Sopenharmony_ci if (VID_TYPE_CHROMAKEY & s->capability.type) 587141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device uses chromakey on overlay\n"); 588141cc406Sopenharmony_ci if (VID_TYPE_CLIPPING & s->capability.type) 589141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device supports overlay clipping\n"); 590141cc406Sopenharmony_ci if (VID_TYPE_FRAMERAM & s->capability.type) 591141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device overwrites frame buffer memory\n"); 592141cc406Sopenharmony_ci if (VID_TYPE_SCALES & s->capability.type) 593141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device supports hardware scaling\n"); 594141cc406Sopenharmony_ci if (VID_TYPE_MONOCHROME & s->capability.type) 595141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device is grey scale only\n"); 596141cc406Sopenharmony_ci if (VID_TYPE_SUBCAPTURE & s->capability.type) 597141cc406Sopenharmony_ci DBG (5, "sane_open: V4L device can capture parts of the image\n"); 598141cc406Sopenharmony_ci 599141cc406Sopenharmony_ci if (s->capability.channels < max_channels) 600141cc406Sopenharmony_ci max_channels = s->capability.channels; 601141cc406Sopenharmony_ci for (i = 0; i < max_channels; i++) 602141cc406Sopenharmony_ci { 603141cc406Sopenharmony_ci channel.channel = i; 604141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (v4lfd, VIDIOCGCHAN, &channel)) 605141cc406Sopenharmony_ci { 606141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCGCHAN %s: %s\n", devname, 607141cc406Sopenharmony_ci strerror (errno)); 608141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 609141cc406Sopenharmony_ci } 610141cc406Sopenharmony_ci DBG (5, "sane_open: channel %d (%s), tuners=%d, flags=0x%x, " 611141cc406Sopenharmony_ci "type=%d, norm=%d\n", channel.channel, channel.name, 612141cc406Sopenharmony_ci channel.tuners, channel.flags, channel.type, channel.norm); 613141cc406Sopenharmony_ci if (VIDEO_VC_TUNER & channel.flags) 614141cc406Sopenharmony_ci DBG (5, "sane_open: channel has tuner(s)\n"); 615141cc406Sopenharmony_ci if (VIDEO_VC_AUDIO & channel.flags) 616141cc406Sopenharmony_ci DBG (5, "sane_open: channel has audio\n"); 617141cc406Sopenharmony_ci if (VIDEO_TYPE_TV == channel.type) 618141cc406Sopenharmony_ci DBG (5, "sane_open: input is TV input\n"); 619141cc406Sopenharmony_ci if (VIDEO_TYPE_CAMERA == channel.type) 620141cc406Sopenharmony_ci DBG (5, "sane_open: input is camera input\n"); 621141cc406Sopenharmony_ci s->channel[i] = strdup (channel.name); 622141cc406Sopenharmony_ci if (!s->channel[i]) 623141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 624141cc406Sopenharmony_ci } 625141cc406Sopenharmony_ci s->channel[i] = 0; 626141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (v4lfd, VIDIOCGPICT, &s->pict)) 627141cc406Sopenharmony_ci { 628141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCGPICT %s: %s\n", devname, 629141cc406Sopenharmony_ci strerror (errno)); 630141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 631141cc406Sopenharmony_ci } 632141cc406Sopenharmony_ci DBG (5, "sane_open: brightness=%d, hue=%d, colour=%d, contrast=%d\n", 633141cc406Sopenharmony_ci s->pict.brightness, s->pict.hue, s->pict.colour, s->pict.contrast); 634141cc406Sopenharmony_ci DBG (5, "sane_open: whiteness=%d, depth=%d, palette=%d\n", 635141cc406Sopenharmony_ci s->pict.whiteness, s->pict.depth, s->pict.palette); 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci /* ??? */ 638141cc406Sopenharmony_ci s->pict.palette = VIDEO_PALETTE_GREY; 639141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCSPICT, &s->pict)) 640141cc406Sopenharmony_ci { 641141cc406Sopenharmony_ci DBG (1, "sane_open: ioctl VIDIOCSPICT failed (%s)\n", strerror (errno)); 642141cc406Sopenharmony_ci } 643141cc406Sopenharmony_ci 644141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGWIN, &s->window)) 645141cc406Sopenharmony_ci { 646141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCGWIN %s: %s\n", devname, 647141cc406Sopenharmony_ci strerror (errno)); 648141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 649141cc406Sopenharmony_ci } 650141cc406Sopenharmony_ci DBG (5, "sane_open: x=%d, y=%d, width=%d, height=%d\n", 651141cc406Sopenharmony_ci s->window.x, s->window.y, s->window.width, s->window.height); 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci /* already done in sane_start 654141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (v4lfd, VIDIOCGMBUF, &mbuf)) 655141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCGMBUF (no Fbuffer?)\n"); 656141cc406Sopenharmony_ci */ 657141cc406Sopenharmony_ci 658141cc406Sopenharmony_ci status = init_options (s); 659141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 660141cc406Sopenharmony_ci return status; 661141cc406Sopenharmony_ci update_parameters (s); 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci /* insert newly opened handle into list of open handles: */ 664141cc406Sopenharmony_ci s->next = first_handle; 665141cc406Sopenharmony_ci first_handle = s; 666141cc406Sopenharmony_ci 667141cc406Sopenharmony_ci *handle = s; 668141cc406Sopenharmony_ci 669141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 670141cc406Sopenharmony_ci} 671141cc406Sopenharmony_ci 672141cc406Sopenharmony_civoid 673141cc406Sopenharmony_cisane_close (SANE_Handle handle) 674141cc406Sopenharmony_ci{ 675141cc406Sopenharmony_ci V4L_Scanner *prev, *s; 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci DBG (2, "sane_close: trying to close handle %p\n", (void *) handle); 678141cc406Sopenharmony_ci /* remove handle from list of open handles: */ 679141cc406Sopenharmony_ci prev = 0; 680141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 681141cc406Sopenharmony_ci { 682141cc406Sopenharmony_ci if (s == handle) 683141cc406Sopenharmony_ci break; 684141cc406Sopenharmony_ci prev = s; 685141cc406Sopenharmony_ci } 686141cc406Sopenharmony_ci if (!s) 687141cc406Sopenharmony_ci { 688141cc406Sopenharmony_ci DBG (1, "sane_close: bad handle %p\n", handle); 689141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 690141cc406Sopenharmony_ci } 691141cc406Sopenharmony_ci if (prev) 692141cc406Sopenharmony_ci prev->next = s->next; 693141cc406Sopenharmony_ci else 694141cc406Sopenharmony_ci first_handle = s->next; 695141cc406Sopenharmony_ci 696141cc406Sopenharmony_ci if (s->scanning) 697141cc406Sopenharmony_ci sane_cancel (handle); 698141cc406Sopenharmony_ci v4l1_close (s->fd); 699141cc406Sopenharmony_ci free (s); 700141cc406Sopenharmony_ci} 701141cc406Sopenharmony_ci 702141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 703141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 704141cc406Sopenharmony_ci{ 705141cc406Sopenharmony_ci V4L_Scanner *s = handle; 706141cc406Sopenharmony_ci 707141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS || option < 0) 708141cc406Sopenharmony_ci return 0; 709141cc406Sopenharmony_ci DBG (4, "sane_get_option_descriptor: option %d (%s)\n", option, 710141cc406Sopenharmony_ci s->opt[option].name ? s->opt[option].name : s->opt[option].title); 711141cc406Sopenharmony_ci return s->opt + option; 712141cc406Sopenharmony_ci} 713141cc406Sopenharmony_ci 714141cc406Sopenharmony_ciSANE_Status 715141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 716141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 717141cc406Sopenharmony_ci{ 718141cc406Sopenharmony_ci V4L_Scanner *s = handle; 719141cc406Sopenharmony_ci SANE_Status status; 720141cc406Sopenharmony_ci SANE_Word cap; 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci if (info) 723141cc406Sopenharmony_ci *info = 0; 724141cc406Sopenharmony_ci 725141cc406Sopenharmony_ci if (option >= NUM_OPTIONS || option < 0) 726141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 727141cc406Sopenharmony_ci 728141cc406Sopenharmony_ci DBG (4, "sane_control_option: %s option %d (%s)\n", 729141cc406Sopenharmony_ci action == SANE_ACTION_GET_VALUE ? "get" : 730141cc406Sopenharmony_ci action == SANE_ACTION_SET_VALUE ? "set" : 731141cc406Sopenharmony_ci action == SANE_ACTION_SET_AUTO ? "auto set" : 732141cc406Sopenharmony_ci "(unknown action with)", option, 733141cc406Sopenharmony_ci s->opt[option].name ? s->opt[option].name : s->opt[option].title); 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci cap = s->opt[option].cap; 736141cc406Sopenharmony_ci 737141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 738141cc406Sopenharmony_ci { 739141cc406Sopenharmony_ci DBG (1, "sane_control option: option is inactive\n"); 740141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 741141cc406Sopenharmony_ci } 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_NUM_OPTS: 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_BRIGHTNESS: 754141cc406Sopenharmony_ci case OPT_HUE: 755141cc406Sopenharmony_ci case OPT_COLOR: 756141cc406Sopenharmony_ci case OPT_CONTRAST: 757141cc406Sopenharmony_ci case OPT_WHITE_LEVEL: 758141cc406Sopenharmony_ci *(SANE_Word *) val = s->val[option].w; 759141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 760141cc406Sopenharmony_ci case OPT_CHANNEL: /* string list options */ 761141cc406Sopenharmony_ci case OPT_MODE: 762141cc406Sopenharmony_ci strcpy (val, s->val[option].s); 763141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 764141cc406Sopenharmony_ci default: 765141cc406Sopenharmony_ci DBG (1, "sane_control_option: option %d unknown\n", option); 766141cc406Sopenharmony_ci } 767141cc406Sopenharmony_ci } 768141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 769141cc406Sopenharmony_ci { 770141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 771141cc406Sopenharmony_ci { 772141cc406Sopenharmony_ci DBG (1, "sane_control_option: option is not settable\n"); 773141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 774141cc406Sopenharmony_ci } 775141cc406Sopenharmony_ci status = sanei_constrain_value (s->opt + option, val, info); 776141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 777141cc406Sopenharmony_ci { 778141cc406Sopenharmony_ci DBG (1, "sane_control_option: sanei_constarin_value failed: %s\n", 779141cc406Sopenharmony_ci sane_strstatus (status)); 780141cc406Sopenharmony_ci return status; 781141cc406Sopenharmony_ci } 782141cc406Sopenharmony_ci if (option >= OPT_TL_X && option <= OPT_BR_Y) 783141cc406Sopenharmony_ci { 784141cc406Sopenharmony_ci s->user_corner |= 1 << (option - OPT_TL_X); 785141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGWIN, &s->window)) 786141cc406Sopenharmony_ci { 787141cc406Sopenharmony_ci DBG (1, "sane_control_option: ioctl VIDIOCGWIN failed " 788141cc406Sopenharmony_ci "(can not get window geometry)\n"); 789141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci s->window.clipcount = 0; 792141cc406Sopenharmony_ci s->window.clips = 0; 793141cc406Sopenharmony_ci s->window.height = parms.lines; 794141cc406Sopenharmony_ci s->window.width = parms.pixels_per_line; 795141cc406Sopenharmony_ci } 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci 798141cc406Sopenharmony_ci switch (option) 799141cc406Sopenharmony_ci { 800141cc406Sopenharmony_ci /* (mostly) side-effect-free word options: */ 801141cc406Sopenharmony_ci case OPT_TL_X: 802141cc406Sopenharmony_ci break; 803141cc406Sopenharmony_ci case OPT_TL_Y: 804141cc406Sopenharmony_ci break; 805141cc406Sopenharmony_ci case OPT_BR_X: 806141cc406Sopenharmony_ci s->window.width = *(SANE_Word *) val; 807141cc406Sopenharmony_ci parms.pixels_per_line = *(SANE_Word *) val; 808141cc406Sopenharmony_ci if (info) 809141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 810141cc406Sopenharmony_ci break; 811141cc406Sopenharmony_ci case OPT_BR_Y: 812141cc406Sopenharmony_ci s->window.height = *(SANE_Word *) val; 813141cc406Sopenharmony_ci parms.lines = *(SANE_Word *) val; 814141cc406Sopenharmony_ci if (info) 815141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 816141cc406Sopenharmony_ci break; 817141cc406Sopenharmony_ci case OPT_MODE: 818141cc406Sopenharmony_ci if (info) 819141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 820141cc406Sopenharmony_ci s->val[option].s = strdup (val); 821141cc406Sopenharmony_ci if (!s->val[option].s) 822141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 823141cc406Sopenharmony_ci if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) 824141cc406Sopenharmony_ci s->pict.palette = VIDEO_PALETTE_GREY; 825141cc406Sopenharmony_ci else 826141cc406Sopenharmony_ci s->pict.palette = VIDEO_PALETTE_RGB24; 827141cc406Sopenharmony_ci update_parameters (s); 828141cc406Sopenharmony_ci break; 829141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 830141cc406Sopenharmony_ci s->pict.brightness = *(SANE_Word *) val *256; 831141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 832141cc406Sopenharmony_ci break; 833141cc406Sopenharmony_ci case OPT_HUE: 834141cc406Sopenharmony_ci s->pict.hue = *(SANE_Word *) val *256; 835141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 836141cc406Sopenharmony_ci break; 837141cc406Sopenharmony_ci case OPT_COLOR: 838141cc406Sopenharmony_ci s->pict.colour = *(SANE_Word *) val *256; 839141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 840141cc406Sopenharmony_ci break; 841141cc406Sopenharmony_ci case OPT_CONTRAST: 842141cc406Sopenharmony_ci s->pict.contrast = *(SANE_Word *) val *256; 843141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 844141cc406Sopenharmony_ci break; 845141cc406Sopenharmony_ci case OPT_WHITE_LEVEL: 846141cc406Sopenharmony_ci s->pict.whiteness = *(SANE_Word *) val *256; 847141cc406Sopenharmony_ci s->val[option].w = *(SANE_Word *) val; 848141cc406Sopenharmony_ci break; 849141cc406Sopenharmony_ci case OPT_CHANNEL: 850141cc406Sopenharmony_ci { 851141cc406Sopenharmony_ci int i; 852141cc406Sopenharmony_ci struct video_channel channel; 853141cc406Sopenharmony_ci 854141cc406Sopenharmony_ci s->val[option].s = strdup (val); 855141cc406Sopenharmony_ci if (!s->val[option].s) 856141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 857141cc406Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) 858141cc406Sopenharmony_ci { 859141cc406Sopenharmony_ci if (strcmp (s->channel[i], val) == 0) 860141cc406Sopenharmony_ci { 861141cc406Sopenharmony_ci channel.channel = i; 862141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGCHAN, &channel)) 863141cc406Sopenharmony_ci { 864141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCGCHAN %s: %s\n", 865141cc406Sopenharmony_ci s->devicename, strerror (errno)); 866141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 867141cc406Sopenharmony_ci } 868141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCSCHAN, &channel)) 869141cc406Sopenharmony_ci { 870141cc406Sopenharmony_ci DBG (1, "sane_open: can't ioctl VIDIOCSCHAN %s: %s\n", 871141cc406Sopenharmony_ci s->devicename, strerror (errno)); 872141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 873141cc406Sopenharmony_ci } 874141cc406Sopenharmony_ci break; 875141cc406Sopenharmony_ci } 876141cc406Sopenharmony_ci } 877141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 878141cc406Sopenharmony_ci break; 879141cc406Sopenharmony_ci } 880141cc406Sopenharmony_ci default: 881141cc406Sopenharmony_ci DBG (1, "sane_control_option: option %d unknown\n", option); 882141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 883141cc406Sopenharmony_ci } 884141cc406Sopenharmony_ci if (option >= OPT_TL_X && option <= OPT_BR_Y) 885141cc406Sopenharmony_ci { 886141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCSWIN, &s->window)) 887141cc406Sopenharmony_ci { 888141cc406Sopenharmony_ci DBG (1, "sane_control_option: ioctl VIDIOCSWIN failed (%s)\n", 889141cc406Sopenharmony_ci strerror (errno)); 890141cc406Sopenharmony_ci /* return SANE_STATUS_INVAL; */ 891141cc406Sopenharmony_ci } 892141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGWIN, &s->window)) 893141cc406Sopenharmony_ci { 894141cc406Sopenharmony_ci DBG (1, "sane_control_option: ioctl VIDIOCGWIN failed (%s)\n", 895141cc406Sopenharmony_ci strerror (errno)); 896141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 897141cc406Sopenharmony_ci } 898141cc406Sopenharmony_ci } 899141cc406Sopenharmony_ci if (option >= OPT_BRIGHTNESS && option <= OPT_WHITE_LEVEL) 900141cc406Sopenharmony_ci { 901141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCSPICT, &s->pict)) 902141cc406Sopenharmony_ci { 903141cc406Sopenharmony_ci DBG (1, "sane_control_option: ioctl VIDIOCSPICT failed (%s)\n", 904141cc406Sopenharmony_ci strerror (errno)); 905141cc406Sopenharmony_ci /* return SANE_STATUS_INVAL; */ 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci } 908141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 909141cc406Sopenharmony_ci } 910141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_AUTO) 911141cc406Sopenharmony_ci { 912141cc406Sopenharmony_ci if (!(cap & SANE_CAP_AUTOMATIC)) 913141cc406Sopenharmony_ci { 914141cc406Sopenharmony_ci DBG (1, "sane_control_option: option can't be set automatically\n"); 915141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 916141cc406Sopenharmony_ci } 917141cc406Sopenharmony_ci switch (option) 918141cc406Sopenharmony_ci { 919141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 920141cc406Sopenharmony_ci /* not implemented yet */ 921141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ci default: 924141cc406Sopenharmony_ci break; 925141cc406Sopenharmony_ci } 926141cc406Sopenharmony_ci } 927141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 928141cc406Sopenharmony_ci} 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ciSANE_Status 931141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 932141cc406Sopenharmony_ci{ 933141cc406Sopenharmony_ci V4L_Scanner *s = handle; 934141cc406Sopenharmony_ci 935141cc406Sopenharmony_ci DBG (4, "sane_get_parameters\n"); 936141cc406Sopenharmony_ci update_parameters (s); 937141cc406Sopenharmony_ci if (params == 0) 938141cc406Sopenharmony_ci { 939141cc406Sopenharmony_ci DBG (1, "sane_get_parameters: params == 0\n"); 940141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 941141cc406Sopenharmony_ci } 942141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGWIN, &s->window)) 943141cc406Sopenharmony_ci { 944141cc406Sopenharmony_ci DBG (1, "sane_control_option: ioctl VIDIOCGWIN failed " 945141cc406Sopenharmony_ci "(can not get window geometry)\n"); 946141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 947141cc406Sopenharmony_ci } 948141cc406Sopenharmony_ci parms.pixels_per_line = s->window.width; 949141cc406Sopenharmony_ci parms.bytes_per_line = s->window.width; 950141cc406Sopenharmony_ci if (parms.format == SANE_FRAME_RGB) 951141cc406Sopenharmony_ci parms.bytes_per_line = s->window.width * 3; 952141cc406Sopenharmony_ci parms.lines = s->window.height; 953141cc406Sopenharmony_ci *params = parms; 954141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci} 957141cc406Sopenharmony_ci 958141cc406Sopenharmony_ciSANE_Status 959141cc406Sopenharmony_cisane_start (SANE_Handle handle) 960141cc406Sopenharmony_ci{ 961141cc406Sopenharmony_ci int len; 962141cc406Sopenharmony_ci V4L_Scanner *s; 963141cc406Sopenharmony_ci char data; 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ci DBG (2, "sane_start\n"); 966141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 967141cc406Sopenharmony_ci { 968141cc406Sopenharmony_ci if (s == handle) 969141cc406Sopenharmony_ci break; 970141cc406Sopenharmony_ci } 971141cc406Sopenharmony_ci if (!s) 972141cc406Sopenharmony_ci { 973141cc406Sopenharmony_ci DBG (1, "sane_start: bad handle %p\n", handle); 974141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* oops, not a handle we know about */ 975141cc406Sopenharmony_ci } 976141cc406Sopenharmony_ci len = v4l1_ioctl (s->fd, VIDIOCGCAP, &s->capability); 977141cc406Sopenharmony_ci if (-1 == len) 978141cc406Sopenharmony_ci { 979141cc406Sopenharmony_ci DBG (1, "sane_start: can not get capabilities\n"); 980141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 981141cc406Sopenharmony_ci } 982141cc406Sopenharmony_ci s->buffercount = 0; 983141cc406Sopenharmony_ci if (-1 == v4l1_ioctl (s->fd, VIDIOCGMBUF, &s->mbuf)) 984141cc406Sopenharmony_ci { 985141cc406Sopenharmony_ci s->is_mmap = SANE_FALSE; 986141cc406Sopenharmony_ci buffer = 987141cc406Sopenharmony_ci malloc (s->capability.maxwidth * s->capability.maxheight * 988141cc406Sopenharmony_ci s->pict.depth); 989141cc406Sopenharmony_ci if (0 == buffer) 990141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 991141cc406Sopenharmony_ci DBG (3, "sane_start: V4L trying to read frame\n"); 992141cc406Sopenharmony_ci len = v4l1_read (s->fd, buffer, parms.bytes_per_line * parms.lines); 993141cc406Sopenharmony_ci DBG (3, "sane_start: %d bytes read\n", len); 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci else 996141cc406Sopenharmony_ci { 997141cc406Sopenharmony_ci int loop; 998141cc406Sopenharmony_ci s->is_mmap = SANE_TRUE; 999141cc406Sopenharmony_ci DBG (3, 1000141cc406Sopenharmony_ci "sane_start: mmap frame, buffersize: %d bytes, buffers: %d, offset 0 %d\n", 1001141cc406Sopenharmony_ci s->mbuf.size, s->mbuf.frames, s->mbuf.offsets[0]); 1002141cc406Sopenharmony_ci buffer = 1003141cc406Sopenharmony_ci v4l1_mmap (0, s->mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, 0); 1004141cc406Sopenharmony_ci if (buffer == (void *)-1) 1005141cc406Sopenharmony_ci { 1006141cc406Sopenharmony_ci DBG (1, "sane_start: mmap failed: %s\n", strerror (errno)); 1007141cc406Sopenharmony_ci buffer = NULL; 1008141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1009141cc406Sopenharmony_ci } 1010141cc406Sopenharmony_ci DBG (3, "sane_start: mmapped frame, capture 1 pict into %p\n", (void *) buffer); 1011141cc406Sopenharmony_ci s->mmap.frame = 0; 1012141cc406Sopenharmony_ci s->mmap.width = s->window.width; 1013141cc406Sopenharmony_ci /* s->mmap.width = parms.pixels_per_line; ??? huh? */ 1014141cc406Sopenharmony_ci s->mmap.height = s->window.height; 1015141cc406Sopenharmony_ci /* s->mmap.height = parms.lines; ??? huh? */ 1016141cc406Sopenharmony_ci s->mmap.format = s->pict.palette; 1017141cc406Sopenharmony_ci DBG (2, "sane_start: mmapped frame %d x %d with palette %d\n", 1018141cc406Sopenharmony_ci s->mmap.width, s->mmap.height, s->mmap.format); 1019141cc406Sopenharmony_ci 1020141cc406Sopenharmony_ci /* We need to loop here to empty the read buffers, so we don't 1021141cc406Sopenharmony_ci get a stale image */ 1022141cc406Sopenharmony_ci for (loop = 0; loop <= s->mbuf.frames; loop++) 1023141cc406Sopenharmony_ci { 1024141cc406Sopenharmony_ci len = v4l1_ioctl (s->fd, VIDIOCMCAPTURE, &s->mmap); 1025141cc406Sopenharmony_ci if (len == -1) 1026141cc406Sopenharmony_ci { 1027141cc406Sopenharmony_ci DBG (1, "sane_start: ioctl VIDIOCMCAPTURE failed: %s\n", 1028141cc406Sopenharmony_ci strerror (errno)); 1029141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1030141cc406Sopenharmony_ci } 1031141cc406Sopenharmony_ci DBG (3, "sane_start: waiting for frame %x, loop %d\n", s->mmap.frame, loop); 1032141cc406Sopenharmony_ci len = v4l1_ioctl (s->fd, VIDIOCSYNC, &(s->mmap.frame)); 1033141cc406Sopenharmony_ci if (-1 == len) 1034141cc406Sopenharmony_ci { 1035141cc406Sopenharmony_ci DBG (1, "sane_start: call to ioctl(%d, VIDIOCSYNC, ..) failed\n", 1036141cc406Sopenharmony_ci s->fd); 1037141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1038141cc406Sopenharmony_ci } 1039141cc406Sopenharmony_ci } 1040141cc406Sopenharmony_ci DBG (3, "sane_start: frame %x done\n", s->mmap.frame); 1041141cc406Sopenharmony_ci } 1042141cc406Sopenharmony_ci 1043141cc406Sopenharmony_ci /* v4l1 actually returns BGR when we ask for RGB, so convert it */ 1044141cc406Sopenharmony_ci if (s->pict.palette == VIDEO_PALETTE_RGB24) 1045141cc406Sopenharmony_ci { 1046141cc406Sopenharmony_ci uint32_t loop; 1047141cc406Sopenharmony_ci DBG (3, "sane_start: converting from BGR to RGB\n"); 1048141cc406Sopenharmony_ci for (loop = 0; loop < (s->window.width * s->window.height * 3); loop += 3) 1049141cc406Sopenharmony_ci { 1050141cc406Sopenharmony_ci data = *(buffer + loop); 1051141cc406Sopenharmony_ci *(buffer + loop) = *(buffer + loop + 2); 1052141cc406Sopenharmony_ci *(buffer + loop + 2) = data; 1053141cc406Sopenharmony_ci } 1054141cc406Sopenharmony_ci } 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci DBG (3, "sane_start: done\n"); 1057141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1058141cc406Sopenharmony_ci} 1059141cc406Sopenharmony_ci 1060141cc406Sopenharmony_ciSANE_Status 1061141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, 1062141cc406Sopenharmony_ci SANE_Int * lenp) 1063141cc406Sopenharmony_ci{ 1064141cc406Sopenharmony_ci int i, min; 1065141cc406Sopenharmony_ci V4L_Scanner *s = handle; 1066141cc406Sopenharmony_ci 1067141cc406Sopenharmony_ci DBG (4, "sane_read: max_len = %d\n", max_len); 1068141cc406Sopenharmony_ci if (!lenp) 1069141cc406Sopenharmony_ci { 1070141cc406Sopenharmony_ci DBG (1, "sane_read: lenp == 0\n"); 1071141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1072141cc406Sopenharmony_ci } 1073141cc406Sopenharmony_ci if ((s->buffercount + 1) > (parms.lines * parms.bytes_per_line)) 1074141cc406Sopenharmony_ci { 1075141cc406Sopenharmony_ci *lenp = 0; 1076141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1077141cc406Sopenharmony_ci }; 1078141cc406Sopenharmony_ci min = parms.lines * parms.bytes_per_line; 1079141cc406Sopenharmony_ci if (min > (max_len + s->buffercount)) 1080141cc406Sopenharmony_ci min = (max_len + s->buffercount); 1081141cc406Sopenharmony_ci if (s->is_mmap == SANE_FALSE) 1082141cc406Sopenharmony_ci { 1083141cc406Sopenharmony_ci for (i = s->buffercount; i < (min + 0); i++) 1084141cc406Sopenharmony_ci { 1085141cc406Sopenharmony_ci *(buf + i - s->buffercount) = *(buffer + i); 1086141cc406Sopenharmony_ci }; 1087141cc406Sopenharmony_ci *lenp = (parms.lines * parms.bytes_per_line - s->buffercount); 1088141cc406Sopenharmony_ci if (max_len < *lenp) 1089141cc406Sopenharmony_ci *lenp = max_len; 1090141cc406Sopenharmony_ci DBG (3, "sane_read: transferred %d bytes (from %d to %d)\n", *lenp, 1091141cc406Sopenharmony_ci s->buffercount, i); 1092141cc406Sopenharmony_ci s->buffercount = i; 1093141cc406Sopenharmony_ci } 1094141cc406Sopenharmony_ci else 1095141cc406Sopenharmony_ci { 1096141cc406Sopenharmony_ci for (i = s->buffercount; i < (min + 0); i++) 1097141cc406Sopenharmony_ci { 1098141cc406Sopenharmony_ci *(buf + i - s->buffercount) = *(buffer + i); 1099141cc406Sopenharmony_ci }; 1100141cc406Sopenharmony_ci *lenp = (parms.lines * parms.bytes_per_line - s->buffercount); 1101141cc406Sopenharmony_ci if ((i - s->buffercount) < *lenp) 1102141cc406Sopenharmony_ci *lenp = (i - s->buffercount); 1103141cc406Sopenharmony_ci DBG (3, "sane_read: transferred %d bytes (from %d to %d)\n", *lenp, 1104141cc406Sopenharmony_ci s->buffercount, i); 1105141cc406Sopenharmony_ci s->buffercount = i; 1106141cc406Sopenharmony_ci } 1107141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1108141cc406Sopenharmony_ci} 1109141cc406Sopenharmony_ci 1110141cc406Sopenharmony_civoid 1111141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 1112141cc406Sopenharmony_ci{ 1113141cc406Sopenharmony_ci V4L_Scanner *s = handle; 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci DBG (2, "sane_cancel\n"); 1116141cc406Sopenharmony_ci 1117141cc406Sopenharmony_ci /* ??? buffer isn't checked in sane_read? */ 1118141cc406Sopenharmony_ci if (buffer) 1119141cc406Sopenharmony_ci { 1120141cc406Sopenharmony_ci if (s->is_mmap) 1121141cc406Sopenharmony_ci v4l1_munmap(buffer, s->mbuf.size); 1122141cc406Sopenharmony_ci else 1123141cc406Sopenharmony_ci free (buffer); 1124141cc406Sopenharmony_ci 1125141cc406Sopenharmony_ci buffer = NULL; 1126141cc406Sopenharmony_ci } 1127141cc406Sopenharmony_ci} 1128141cc406Sopenharmony_ci 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ciSANE_Status 1131141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool non_blocking) 1132141cc406Sopenharmony_ci{ 1133141cc406Sopenharmony_ci if (non_blocking == SANE_FALSE) 1134141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1135141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1136141cc406Sopenharmony_ci} 1137141cc406Sopenharmony_ci 1138141cc406Sopenharmony_ciSANE_Status 1139141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) 1140141cc406Sopenharmony_ci{ 1141141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1142141cc406Sopenharmony_ci} 1143