diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:44:51 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:44:51 +0200 |
commit | ad38bc6ecb80ddeb562841b33258dd53659b1da6 (patch) | |
tree | e02e9c3ff760554fd87f70df0e18b88594091a48 /backend/canon_lide70.c | |
parent | 9c23ed018d72eed2554f4f9cff1ae6e6bb0cd479 (diff) |
New upstream version 1.0.31upstream/1.0.31
Diffstat (limited to 'backend/canon_lide70.c')
-rw-r--r-- | backend/canon_lide70.c | 960 |
1 files changed, 960 insertions, 0 deletions
diff --git a/backend/canon_lide70.c b/backend/canon_lide70.c new file mode 100644 index 0000000..100a45f --- /dev/null +++ b/backend/canon_lide70.c @@ -0,0 +1,960 @@ +/* sane - Scanner Access Now Easy. + + BACKEND canon_lide70 + + Copyright (C) 2019 Juergen Ernst and pimvantend. + + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + This file implements a SANE backend for the Canon CanoScan LiDE 70 */ + +#define BUILD 0 +#define MM_IN_INCH 25.4 + +#include "../include/sane/config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#include "../include/sane/sane.h" +#include "../include/sane/sanei.h" +#include "../include/sane/saneopts.h" +#include "../include/sane/sanei_config.h" +#include "../include/sane/sanei_usb.h" +#define BACKEND_NAME canon_lide70 +#define CANONUSB_CONFIG_FILE "canon_lide70.conf" +#include "../include/sane/sanei_backend.h" + +typedef enum +{ + opt_num_opts = 0, + opt_mode_group, + opt_threshold, + opt_mode, + opt_resolution, + opt_non_blocking, + opt_geometry_group, + opt_tl_x, + opt_tl_y, + opt_br_x, + opt_br_y, + /* must come last: */ + num_options +} +canon_opts; + +#include "canon_lide70-common.c" + +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + SANE_Int i; + + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + return max_size; +} + +static SANE_String_Const mode_list[] = { + SANE_VALUE_SCAN_MODE_COLOR, + SANE_VALUE_SCAN_MODE_GRAY, + SANE_VALUE_SCAN_MODE_LINEART, + 0 +}; + +static SANE_Fixed init_tl_x = SANE_FIX (0.0); +static SANE_Fixed init_tl_y = SANE_FIX (0.0); +static SANE_Fixed init_br_x = SANE_FIX (80.0); +static SANE_Fixed init_br_y = SANE_FIX (100.0); +static SANE_Int init_threshold = 75; +static SANE_Int init_resolution = 600; +static SANE_String init_mode = SANE_VALUE_SCAN_MODE_COLOR; +static SANE_Int init_graymode = 0; +static SANE_Bool init_non_blocking = SANE_FALSE; + +/*-----------------------------------------------------------------*/ +/* +Scan range +*/ + +static const SANE_Range widthRange = { + 0, /* minimum */ + SANE_FIX (CANON_MAX_WIDTH * MM_IN_INCH / 600), /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range heightRange = { + 0, /* minimum */ +/* SANE_FIX (CANON_MAX_HEIGHT * MM_IN_INCH / 600 - TOP_EDGE ), maximum */ + SANE_FIX (297.0), + 0 /* quantization */ +}; + +static const SANE_Range threshold_range = { + 0, + 100, + 1 +}; + +static SANE_Int resolution_list[] = { 5, + 75, + 150, + 300, + 600, + 1200 +}; + +typedef struct Canon_Device +{ + struct Canon_Device *next; + SANE_String name; + SANE_Device sane; +} +Canon_Device; + +/* Canon_Scanner is the type used for the sane handle */ +typedef struct Canon_Scanner +{ + struct Canon_Scanner *next; + Canon_Device *device; + CANON_Handle scan; +} +Canon_Scanner; + +static int num_devices = 0; +static const SANE_Device **devlist = NULL; +static Canon_Device *first_dev = NULL; +static Canon_Scanner *first_handle = NULL; + +/*-----------------------------------------------------------------*/ +static SANE_Status +attach_scanner (const char *devicename, Canon_Device ** devp) +{ + CANON_Handle scan; + Canon_Device *dev; + SANE_Status status; + + DBG (3, "attach_scanner: %s\n", devicename); + + for (dev = first_dev; dev; dev = dev->next) + { + if (strcmp (dev->sane.name, devicename) == 0) + { + if (devp) + *devp = dev; + return SANE_STATUS_GOOD; + } + } + + dev = malloc (sizeof (*dev)); + if (!dev) + return SANE_STATUS_NO_MEM; + memset (dev, '\0', sizeof (Canon_Device)); /* clear structure */ + + DBG (4, "attach_scanner: opening %s\n", devicename); + + status = CANON_open_device (&scan, devicename); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename); + free (dev); + return status; + } + dev->name = strdup (devicename); + dev->sane.name = dev->name; + dev->sane.vendor = "CANON"; + dev->sane.model = CANON_get_device_name (&scan); + dev->sane.type = "flatbed scanner"; + CANON_close_device (&scan); + + ++num_devices; + dev->next = first_dev; + first_dev = dev; + + if (devp) + *devp = dev; + return SANE_STATUS_GOOD; +} + + +/* callback function for sanei_usb_attach_matching_devices */ +static SANE_Status +attach_one (const char *name) +{ + attach_scanner (name, 0); + return SANE_STATUS_GOOD; +} + + +/* Find our devices */ +SANE_Status +sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + char config_line[PATH_MAX]; + size_t len; + FILE *fp; + + DBG_INIT (); + +#if 0 + DBG_LEVEL = 10; +#endif + + DBG (2, "sane_init: version_code %s 0, authorize %s 0\n", + version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!="); + DBG (1, "sane_init: SANE Canon LiDE70 backend version %d.%d.%d from %s\n", + V_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); + + if (version_code) + *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD); + + sanei_usb_init (); + + fp = sanei_config_open (CANONUSB_CONFIG_FILE); + + if (!fp) + { + /* no config-file: try these */ + attach_scanner ("/dev/scanner", 0); + attach_scanner ("/dev/usbscanner", 0); + attach_scanner ("/dev/usb/scanner", 0); + return SANE_STATUS_GOOD; + } + + DBG (3, "reading configure file %s\n", CANONUSB_CONFIG_FILE); + + while (sanei_config_read (config_line, sizeof (config_line), fp)) + { + if (config_line[0] == '#') + continue; /* ignore line comments */ + + len = strlen (config_line); + + if (!len) + continue; /* ignore empty lines */ + + DBG (4, "attach_matching_devices(%s)\n", config_line); + sanei_usb_attach_matching_devices (config_line, attach_one); + } + + DBG (4, "finished reading configure file\n"); + + fclose (fp); + + return SANE_STATUS_GOOD; +} + + +void +sane_exit (void) +{ + Canon_Device *dev, *next; + + DBG (3, "sane_exit\n"); + + for (dev = first_dev; dev; dev = next) + { + next = dev->next; + free (dev->name); + free (dev); + } + + if (devlist) + free (devlist); + return; +} + + +SANE_Status +sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) +{ + Canon_Device *dev; + int i; + + DBG (3, "sane_get_devices(local_only = %d)\n", local_only); + + if (devlist) + free (devlist); + + devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); + if (!devlist) + return SANE_STATUS_NO_MEM; + + i = 0; + + for (dev = first_dev; i < num_devices; dev = dev->next) + devlist[i++] = &dev->sane; + + devlist[i++] = 0; + + *device_list = devlist; + + return SANE_STATUS_GOOD; +} + +static SANE_Status +init_options (CANON_Handle * chndl) +{ + SANE_Option_Descriptor *od; + + DBG (2, "begin init_options: chndl=%p\n", (void *) chndl); + + /* opt_num_opts */ + od = &chndl->opt[opt_num_opts]; + od->name = ""; + od->title = SANE_TITLE_NUM_OPTIONS; + od->desc = SANE_DESC_NUM_OPTIONS; + od->type = SANE_TYPE_INT; + od->unit = SANE_UNIT_NONE; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT; + od->constraint_type = SANE_CONSTRAINT_NONE; + od->constraint.range = 0; + chndl->val[opt_num_opts].w = num_options; + + DBG (2, "val[opt_num_opts]: %d\n", chndl->val[opt_num_opts].w); + + /* opt_mode_group */ + od = &chndl->opt[opt_mode_group]; + od->name = ""; + od->title = SANE_I18N ("Scan Mode"); + od->desc = ""; + od->type = SANE_TYPE_GROUP; + od->unit = SANE_UNIT_NONE; + od->size = 0; + od->cap = 0; + od->constraint_type = SANE_CONSTRAINT_NONE; + od->constraint.range = 0; + chndl->val[opt_mode_group].w = 0; + + /* opt_mode */ + od = &chndl->opt[opt_mode]; + od->name = SANE_NAME_SCAN_MODE; + od->title = SANE_TITLE_SCAN_MODE; + od->desc = SANE_DESC_SCAN_MODE; + od->type = SANE_TYPE_STRING; + od->unit = SANE_UNIT_NONE; + od->size = max_string_size (mode_list); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_STRING_LIST; + od->constraint.string_list = mode_list; + chndl->val[opt_mode].s = malloc (od->size); + if (!chndl->val[opt_mode].s) + return SANE_STATUS_NO_MEM; + strcpy (chndl->val[opt_mode].s, init_mode); + chndl->graymode = init_graymode; + + /* opt_threshold */ + od = &chndl->opt[opt_threshold]; + od->name = SANE_NAME_THRESHOLD; + od->title = SANE_TITLE_THRESHOLD; + od->desc = SANE_DESC_THRESHOLD; + od->type = SANE_TYPE_INT; + od->unit = SANE_UNIT_PERCENT; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &threshold_range; + chndl->val[opt_threshold].w = init_threshold; + + /* opt_resolution */ + od = &chndl->opt[opt_resolution]; + od->name = SANE_NAME_SCAN_RESOLUTION; + od->title = SANE_TITLE_SCAN_RESOLUTION; + od->desc = SANE_DESC_SCAN_RESOLUTION; + od->type = SANE_TYPE_INT; + od->unit = SANE_UNIT_DPI; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_WORD_LIST; + od->constraint.word_list = resolution_list; + chndl->val[opt_resolution].w = init_resolution; + + /* opt_non_blocking */ + od = &chndl->opt[opt_non_blocking]; + od->name = "non-blocking"; + od->title = SANE_I18N ("Use non-blocking IO"); + od->desc = SANE_I18N ("Use non-blocking IO for sane_read() if supported " + "by the frontend."); + od->type = SANE_TYPE_BOOL; + od->unit = SANE_UNIT_NONE; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE; + od->constraint_type = SANE_CONSTRAINT_NONE; + od->constraint.range = 0; + chndl->val[opt_non_blocking].w = init_non_blocking; + + /* opt_geometry_group */ + od = &chndl->opt[opt_geometry_group]; + od->name = ""; + od->title = SANE_I18N ("Geometry"); + od->desc = ""; + od->type = SANE_TYPE_GROUP; + od->unit = SANE_UNIT_NONE; + od->size = 0; + od->cap = 0; + od->constraint_type = SANE_CONSTRAINT_NONE; + od->constraint.range = 0; + chndl->val[opt_geometry_group].w = 0; + + /* opt_tl_x */ + od = &chndl->opt[opt_tl_x]; + od->name = SANE_NAME_SCAN_TL_X; + od->title = SANE_TITLE_SCAN_TL_X; + od->desc = SANE_DESC_SCAN_TL_X; + od->type = SANE_TYPE_FIXED; + od->unit = SANE_UNIT_MM; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &widthRange; + chndl->val[opt_tl_x].w = init_tl_x; + + /* opt_tl_y */ + od = &chndl->opt[opt_tl_y]; + od->name = SANE_NAME_SCAN_TL_Y; + od->title = SANE_TITLE_SCAN_TL_Y; + od->desc = SANE_DESC_SCAN_TL_Y; + od->type = SANE_TYPE_FIXED; + od->unit = SANE_UNIT_MM; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &heightRange; + chndl->val[opt_tl_y].w = init_tl_y; + + /* opt_br_x */ + od = &chndl->opt[opt_br_x]; + od->name = SANE_NAME_SCAN_BR_X; + od->title = SANE_TITLE_SCAN_BR_X; + od->desc = SANE_DESC_SCAN_BR_X; + od->type = SANE_TYPE_FIXED; + od->unit = SANE_UNIT_MM; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &widthRange; + chndl->val[opt_br_x].w = init_br_x; + + /* opt_br_y */ + od = &chndl->opt[opt_br_y]; + od->name = SANE_NAME_SCAN_BR_Y; + od->title = SANE_TITLE_SCAN_BR_Y; + od->desc = SANE_DESC_SCAN_BR_Y; + od->type = SANE_TYPE_FIXED; + od->unit = SANE_UNIT_MM; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &heightRange; + chndl->val[opt_br_y].w = init_br_y; + + DBG (2, "end init_options: chndl=%p\n", (void *) chndl); + + return SANE_STATUS_GOOD; +} + +SANE_Status +sane_open (SANE_String_Const devicename, SANE_Handle * handle) +{ + Canon_Device *dev; + SANE_Status status; + Canon_Scanner *scanner; + + DBG (3, "sane_open\n"); + + if (devicename[0]) /* search for devicename */ + { + DBG (4, "sane_open: devicename=%s\n", devicename); + + for (dev = first_dev; dev; dev = dev->next) + if (strcmp (dev->sane.name, devicename) == 0) + break; + + if (!dev) + { + status = attach_scanner (devicename, &dev); + + if (status != SANE_STATUS_GOOD) + return status; + } + } + else + { + DBG (2, "sane_open: no devicename, opening first device\n"); + dev = first_dev; + } + + if (!dev) + return SANE_STATUS_INVAL; + + scanner = malloc (sizeof (*scanner)); + + if (!scanner) + return SANE_STATUS_NO_MEM; + + memset (scanner, 0, sizeof (*scanner)); + scanner->device = dev; + + status = CANON_open_device (&scanner->scan, dev->sane.name); + + if (status != SANE_STATUS_GOOD) + { + free (scanner); + return status; + } + + status = init_options (&scanner->scan); + + *handle = scanner; + + /* insert newly opened handle into list of open handles: */ + scanner->next = first_handle; + + first_handle = scanner; + + return status; +} + +static void +print_options (CANON_Handle * chndl) +{ + SANE_Option_Descriptor *od; + SANE_Word option_number; + SANE_Char caps[1024]; + + for (option_number = 0; option_number < num_options; option_number++) + { + od = &chndl->opt[option_number]; + DBG (50, "-----> number: %d\n", option_number); + DBG (50, " name: `%s'\n", od->name); + DBG (50, " title: `%s'\n", od->title); + DBG (50, " description: `%s'\n", od->desc); + DBG (50, " type: %s\n", + od->type == SANE_TYPE_BOOL ? "SANE_TYPE_BOOL" : + od->type == SANE_TYPE_INT ? "SANE_TYPE_INT" : + od->type == SANE_TYPE_FIXED ? "SANE_TYPE_FIXED" : + od->type == SANE_TYPE_STRING ? "SANE_TYPE_STRING" : + od->type == SANE_TYPE_BUTTON ? "SANE_TYPE_BUTTON" : + od->type == SANE_TYPE_GROUP ? "SANE_TYPE_GROUP" : "unknown"); + DBG (50, " unit: %s\n", + od->unit == SANE_UNIT_NONE ? "SANE_UNIT_NONE" : + od->unit == SANE_UNIT_PIXEL ? "SANE_UNIT_PIXEL" : + od->unit == SANE_UNIT_BIT ? "SANE_UNIT_BIT" : + od->unit == SANE_UNIT_MM ? "SANE_UNIT_MM" : + od->unit == SANE_UNIT_DPI ? "SANE_UNIT_DPI" : + od->unit == SANE_UNIT_PERCENT ? "SANE_UNIT_PERCENT" : + od->unit == SANE_UNIT_MICROSECOND ? "SANE_UNIT_MICROSECOND" : + "unknown"); + DBG (50, " size: %d\n", od->size); + caps[0] = '\0'; + if (od->cap & SANE_CAP_SOFT_SELECT) + strcat (caps, "SANE_CAP_SOFT_SELECT "); + if (od->cap & SANE_CAP_HARD_SELECT) + strcat (caps, "SANE_CAP_HARD_SELECT "); + if (od->cap & SANE_CAP_SOFT_DETECT) + strcat (caps, "SANE_CAP_SOFT_DETECT "); + if (od->cap & SANE_CAP_EMULATED) + strcat (caps, "SANE_CAP_EMULATED "); + if (od->cap & SANE_CAP_AUTOMATIC) + strcat (caps, "SANE_CAP_AUTOMATIC "); + if (od->cap & SANE_CAP_INACTIVE) + strcat (caps, "SANE_CAP_INACTIVE "); + if (od->cap & SANE_CAP_ADVANCED) + strcat (caps, "SANE_CAP_ADVANCED "); + DBG (50, " capabilities: %s\n", caps); + DBG (50, "constraint type: %s\n", + od->constraint_type == SANE_CONSTRAINT_NONE ? + "SANE_CONSTRAINT_NONE" : + od->constraint_type == SANE_CONSTRAINT_RANGE ? + "SANE_CONSTRAINT_RANGE" : + od->constraint_type == SANE_CONSTRAINT_WORD_LIST ? + "SANE_CONSTRAINT_WORD_LIST" : + od->constraint_type == SANE_CONSTRAINT_STRING_LIST ? + "SANE_CONSTRAINT_STRING_LIST" : "unknown"); + if (od->type == SANE_TYPE_INT) + DBG (50, " value: %d\n", chndl->val[option_number].w); + else if (od->type == SANE_TYPE_FIXED) + DBG (50, " value: %f\n", + SANE_UNFIX (chndl->val[option_number].w)); + else if (od->type == SANE_TYPE_STRING) + DBG (50, " value: %s\n", chndl->val[option_number].s); + } +} + +void +sane_close (SANE_Handle handle) +{ + Canon_Scanner *prev, *scanner; + SANE_Status res; + + DBG (3, "sane_close\n"); + + scanner = handle; + print_options (&scanner->scan); + + if (!first_handle) + { + DBG (1, "ERROR: sane_close: no handles opened\n"); + return; + } + + /* remove handle from list of open handles: */ + + prev = NULL; + + for (scanner = first_handle; scanner; scanner = scanner->next) + { + if (scanner == handle) + break; + + prev = scanner; + } + + if (!scanner) + { + DBG (1, "ERROR: sane_close: invalid handle %p\n", handle); + return; /* oops, not a handle we know about */ + } + + if (prev) + prev->next = scanner->next; + else + first_handle = scanner->next; + + res = CANON_close_device (&scanner->scan); + DBG (3, "CANON_close_device returned: %d\n", res); + free (scanner); +} + +const SANE_Option_Descriptor * +sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) +{ + Canon_Scanner *scanner = handle; + CANON_Handle *chndl = &scanner->scan; + + + DBG (4, "sane_get_option_descriptor: handle=%p, option = %d\n", + (void *) handle, option); + if (option < 0 || option >= num_options) + { + DBG (3, "sane_get_option_descriptor: option < 0 || " + "option > num_options\n"); + return 0; + } + + return &chndl->opt[option]; +} + +SANE_Status +sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, + void *value, SANE_Int * info) +{ + Canon_Scanner *scanner = handle; + CANON_Handle *chndl = &scanner->scan; + + SANE_Int myinfo = 0; + SANE_Status status; + + DBG (4, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n", + (void *) handle, option, action, (void *) value, (void *) info); + + if (option < 0 || option >= num_options) + { + DBG (1, "sane_control_option: option < 0 || option > num_options\n"); + return SANE_STATUS_INVAL; + } + + if (!SANE_OPTION_IS_ACTIVE (chndl->opt[option].cap)) + { + DBG (1, "sane_control_option: option is inactive\n"); + return SANE_STATUS_INVAL; + } + + if (chndl->opt[option].type == SANE_TYPE_GROUP) + { + DBG (1, "sane_control_option: option is a group\n"); + return SANE_STATUS_INVAL; + } + + switch (action) + { + case SANE_ACTION_SET_VALUE: + if (!SANE_OPTION_IS_SETTABLE (chndl->opt[option].cap)) + { + DBG (1, "sane_control_option: option is not setable\n"); + return SANE_STATUS_INVAL; + } + status = sanei_constrain_value (&chndl->opt[option], value, &myinfo); + if (status != SANE_STATUS_GOOD) + { + DBG (3, "sane_control_option: sanei_constrain_value returned %s\n", + sane_strstatus (status)); + return status; + } + switch (option) + { + case opt_tl_x: /* Fixed with parameter reloading */ + case opt_tl_y: + case opt_br_x: + case opt_br_y: + if (chndl->val[option].w == *(SANE_Fixed *) value) + { + DBG (4, "sane_control_option: option %d (%s) not changed\n", + option, chndl->opt[option].name); + break; + } + chndl->val[option].w = *(SANE_Fixed *) value; + myinfo |= SANE_INFO_RELOAD_PARAMS; + DBG (4, "sane_control_option: set option %d (%s) to %.0f %s\n", + option, chndl->opt[option].name, + SANE_UNFIX (*(SANE_Fixed *) value), + chndl->opt[option].unit == SANE_UNIT_MM ? "mm" : "dpi"); + break; + case opt_non_blocking: + if (chndl->val[option].w == *(SANE_Bool *) value) + { + DBG (4, "sane_control_option: option %d (%s) not changed\n", + option, chndl->opt[option].name); + break; + } + chndl->val[option].w = *(SANE_Bool *) value; + DBG (4, "sane_control_option: set option %d (%s) to %s\n", + option, chndl->opt[option].name, + *(SANE_Bool *) value == SANE_TRUE ? "true" : "false"); + break; + case opt_resolution: + case opt_threshold: + if (chndl->val[option].w == *(SANE_Int *) value) + { + DBG (4, "sane_control_option: option %d (%s) not changed\n", + option, chndl->opt[option].name); + break; + } + chndl->val[option].w = *(SANE_Int *) value; + myinfo |= SANE_INFO_RELOAD_PARAMS; + myinfo |= SANE_INFO_RELOAD_OPTIONS; + DBG (4, "sane_control_option: set option %d (%s) to %d\n", + option, chndl->opt[option].name, *(SANE_Int *) value); + break; + case opt_mode: + if (strcmp (chndl->val[option].s, value) == 0) + { + DBG (4, "sane_control_option: option %d (%s) not changed\n", + option, chndl->opt[option].name); + break; + } + strcpy (chndl->val[option].s, (SANE_String) value); + + if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) == + 0) + { + chndl->opt[opt_threshold].cap &= ~SANE_CAP_INACTIVE; + chndl->graymode = 2; + } + if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) + { + chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE; + chndl->graymode = 0; + } + if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) + { + chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE; + chndl->graymode = 1; + } + + + myinfo |= SANE_INFO_RELOAD_PARAMS; + myinfo |= SANE_INFO_RELOAD_OPTIONS; + DBG (4, "sane_control_option: set option %d (%s) to %s\n", + option, chndl->opt[option].name, (SANE_String) value); + break; + default: + DBG (1, "sane_control_option: trying to set unexpected option\n"); + return SANE_STATUS_INVAL; + } + break; + + case SANE_ACTION_GET_VALUE: + switch (option) + { + case opt_num_opts: + *(SANE_Word *) value = num_options; + DBG (4, "sane_control_option: get option 0, value = %d\n", + num_options); + break; + case opt_tl_x: /* Fixed options */ + case opt_tl_y: + case opt_br_x: + case opt_br_y: + { + *(SANE_Fixed *) value = chndl->val[option].w; + DBG (4, + "sane_control_option: get option %d (%s), value=%.1f %s\n", + option, chndl->opt[option].name, + SANE_UNFIX (*(SANE_Fixed *) value), + chndl->opt[option].unit == + SANE_UNIT_MM ? "mm" : SANE_UNIT_DPI ? "dpi" : ""); + break; + } + case opt_non_blocking: + *(SANE_Bool *) value = chndl->val[option].w; + DBG (4, + "sane_control_option: get option %d (%s), value=%s\n", + option, chndl->opt[option].name, + *(SANE_Bool *) value == SANE_TRUE ? "true" : "false"); + break; + case opt_mode: /* String (list) options */ + strcpy (value, chndl->val[option].s); + DBG (4, "sane_control_option: get option %d (%s), value=`%s'\n", + option, chndl->opt[option].name, (SANE_String) value); + break; + case opt_resolution: + case opt_threshold: + *(SANE_Int *) value = chndl->val[option].w; + DBG (4, "sane_control_option: get option %d (%s), value=%d\n", + option, chndl->opt[option].name, *(SANE_Int *) value); + break; + default: + DBG (1, "sane_control_option: trying to get unexpected option\n"); + return SANE_STATUS_INVAL; + } + break; + default: + DBG (1, "sane_control_option: trying unexpected action %d\n", action); + return SANE_STATUS_INVAL; + } + + if (info) + *info = myinfo; + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) +{ + Canon_Scanner *hndl = handle; /* Eliminate compiler warning */ + CANON_Handle *chndl = &hndl->scan; + + int rc = SANE_STATUS_GOOD; + int w = SANE_UNFIX (chndl->val[opt_br_x].w - + chndl->val[opt_tl_x].w) / MM_IN_INCH * + chndl->val[opt_resolution].w; + int h = + SANE_UNFIX (chndl->val[opt_br_y].w - + chndl->val[opt_tl_y].w) / MM_IN_INCH * + chndl->val[opt_resolution].w; + + DBG (3, "sane_get_parameters\n"); + chndl->params.depth = 8; + chndl->params.last_frame = SANE_TRUE; + chndl->params.pixels_per_line = w; + chndl->params.lines = h; + + if (chndl->graymode == 1) + { + chndl->params.format = SANE_FRAME_GRAY; + chndl->params.bytes_per_line = w; + } + else if (chndl->graymode == 2) + { + chndl->params.format = SANE_FRAME_GRAY; + w /= 8; + + if ((chndl->params.pixels_per_line % 8) != 0) + w++; + + chndl->params.bytes_per_line = w; + chndl->params.depth = 1; + } + else + { + chndl->params.format = SANE_FRAME_RGB; + chndl->params.bytes_per_line = w * 3; + } + + *params = chndl->params; + DBG (1, "%d\n", chndl->params.format); + return rc; +} + + +SANE_Status +sane_start (SANE_Handle handle) +{ + Canon_Scanner *scanner = handle; + CANON_Handle *chndl = &scanner->scan; + SANE_Status res; + + DBG (3, "sane_start\n"); + + res = sane_get_parameters (handle, &chndl->params); + res = CANON_set_scan_parameters (&scanner->scan); + + if (res != SANE_STATUS_GOOD) + return res; + + return CANON_start_scan (&scanner->scan); +} + + +SANE_Status +sane_read (SANE_Handle handle, SANE_Byte * data, + SANE_Int max_length, SANE_Int * length) +{ + Canon_Scanner *scanner = handle; + return CANON_read (&scanner->scan, data, max_length, length); +} + + +void +sane_cancel (SANE_Handle handle) +{ + DBG (3, "sane_cancel: handle = %p\n", handle); + DBG (3, "sane_cancel: cancelling is unsupported in this backend\n"); +} + + +SANE_Status +sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) +{ + DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle, + non_blocking); + if (non_blocking != SANE_FALSE) + return SANE_STATUS_UNSUPPORTED; + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) +{ + handle = handle; /* silence gcc */ + fd = fd; /* silence gcc */ + return SANE_STATUS_UNSUPPORTED; +} |