diff options
Diffstat (limited to 'backend/sm3840.c')
-rwxr-xr-x | backend/sm3840.c | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/backend/sm3840.c b/backend/sm3840.c new file mode 100755 index 0000000..41b72ec --- /dev/null +++ b/backend/sm3840.c @@ -0,0 +1,846 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005-7 Earle F. Philhower, III + earle@ziplabel.com - http://www.ziplabel.com + + 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. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + +*/ + + + + +#include "../include/sane/config.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <limits.h> +#include <stdarg.h> +#include <string.h> +#include <signal.h> +#include <sys/stat.h> + +#include "../include/sane/sane.h" +#include "../include/sane/saneopts.h" + +#define BACKENDNAME sm3840 +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_usb.h" +#include "../include/sane/sanei_config.h" + +#include "sm3840.h" + +#include "sm3840_scan.c" +#include "sm3840_lib.c" + +static double sm3840_unit_convert (SANE_Int val); + +static int num_devices; +static SM3840_Device *first_dev; +static SM3840_Scan *first_handle; +static const SANE_Device **devlist = 0; + +static const SANE_String_Const mode_list[] = { + SANE_VALUE_SCAN_MODE_GRAY, + SANE_VALUE_SCAN_MODE_COLOR, + SANE_VALUE_SCAN_MODE_LINEART, + SANE_VALUE_SCAN_MODE_HALFTONE, + 0 +}; + +static const SANE_Word resolution_list[] = { + 4, 1200, 600, 300, 150 +}; + +static const SANE_Word bpp_list[] = { + 2, 8, 16 +}; + +static const SANE_Range x_range = { + SANE_FIX (0), + SANE_FIX (215.91), /* 8.5 inches */ + SANE_FIX (0) +}; + +static const SANE_Range y_range = { + SANE_FIX (0), + SANE_FIX (297.19), /* 11.7 inches */ + SANE_FIX (0) +}; + +static const SANE_Range brightness_range = { + 1, + 4096, + 1.0 +}; + +static const SANE_Range contrast_range = { + SANE_FIX (0.1), + SANE_FIX (9.9), + SANE_FIX (0.1) +}; + +static const SANE_Range lamp_range = { + 1, + 15, + 1 +}; + +static const SANE_Range threshold_range = { + 0, + 255, + 1 +}; + +/*--------------------------------------------------------------------------*/ +static int +min (int a, int b) +{ + if (a < b) + return a; + else + return b; +} + +SANE_Status +sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, + SANE_Int * len) +{ + SM3840_Scan *s = handle; + unsigned char c, d; + int i; + + DBG (2, "+sane-read:%p %p %d %p\n", (unsigned char *) s, buf, max_len, + (unsigned char *) len); + DBG (2, + "+sane-read:remain:%lu offset:%lu linesleft:%d linebuff:%p linesread:%d\n", + (u_long)s->remaining, (u_long)s->offset, s->linesleft, s->line_buffer, s->linesread); + + if (!s->scanning) + return SANE_STATUS_INVAL; + + if (!s->remaining) + { + if (!s->linesleft) + { + *len = 0; + s->scanning = 0; + /* Move to home position */ + reset_scanner ((p_usb_dev_handle)s->udev); + /* Send lamp timeout */ + set_lamp_timer ((p_usb_dev_handle)s->udev, s->sm3840_params.lamp); + + /* Free memory */ + if (s->save_scan_line) + free (s->save_scan_line); + s->save_scan_line = NULL; + if (s->save_dpi1200_remap) + free (s->save_dpi1200_remap); + s->save_dpi1200_remap = NULL; + if (s->save_color_remap) + free (s->save_color_remap); + s->save_color_remap = NULL; + + return SANE_STATUS_EOF; + } + + record_line ((s->linesread == 0) ? 1 : 0, + (p_usb_dev_handle) s->udev, + s->line_buffer, + s->sm3840_params.dpi, + s->sm3840_params.scanpix, + s->sm3840_params.gray, + (s->sm3840_params.bpp == 16) ? 1 : 0, + &s->save_i, + &s->save_scan_line, + &s->save_dpi1200_remap, &s->save_color_remap); + s->remaining = s->sm3840_params.linelen; + s->offset = 0; + s->linesread++; + s->linesleft--; + } + + /* Need to software emulate 1-bpp modes, simple threshold and error */ + /* diffusion dither implemented. */ + if (s->sm3840_params.lineart || s->sm3840_params.halftone) + { + d = 0; + for (i = 0; i < min (max_len * 8, s->remaining); i++) + { + d = d << 1; + if (s->sm3840_params.halftone) + { + c = (*(unsigned char *) (s->offset + s->line_buffer + i)); + if (c + s->save_dither_err < 128) + { + d |= 1; + s->save_dither_err += c; + } + else + { + s->save_dither_err += c - 255; + } + } + else + { + if ((*(unsigned char *) (s->offset + s->line_buffer + i)) < s->threshold ) + d |= 1; + } + if (i % 8 == 7) + *(buf++) = d; + } + *len = i / 8; + s->offset += i; + s->remaining -= i; + } + else + { + memcpy (buf, s->offset + s->line_buffer, min (max_len, s->remaining)); + *len = min (max_len, s->remaining); + s->offset += min (max_len, s->remaining); + s->remaining -= min (max_len, s->remaining); + } + + DBG (2, "-sane_read\n"); + + return SANE_STATUS_GOOD; +} + +/*--------------------------------------------------------------------------*/ +void +sane_cancel (SANE_Handle h) +{ + SM3840_Scan *s = h; + + DBG (2, "trying to cancel...\n"); + if (s->scanning) + { + if (!s->cancelled) + { + /* Move to home position */ + reset_scanner ((p_usb_dev_handle) s->udev); + /* Send lamp timeout */ + set_lamp_timer ((p_usb_dev_handle) s->udev, s->sm3840_params.lamp); + + /* Free memory */ + if (s->save_scan_line) + free (s->save_scan_line); + s->save_scan_line = NULL; + if (s->save_dpi1200_remap) + free (s->save_dpi1200_remap); + s->save_dpi1200_remap = NULL; + if (s->save_color_remap) + free (s->save_color_remap); + s->save_color_remap = NULL; + + s->scanning = 0; + s->cancelled = SANE_TRUE; + } + } +} + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_start (SANE_Handle handle) +{ + SM3840_Scan *s = handle; + SANE_Status status; + + /* First make sure we have a current parameter set. Some of the + * parameters will be overwritten below, but that's OK. */ + DBG (2, "sane_start\n"); + status = sane_get_parameters (s, 0); + if (status != SANE_STATUS_GOOD) + return status; + DBG (1, "Got params again...\n"); + + s->scanning = SANE_TRUE; + s->cancelled = 0; + + s->line_buffer = malloc (s->sm3840_params.linelen); + s->remaining = 0; + s->offset = 0; + s->linesleft = s->sm3840_params.scanlines; + s->linesread = 0; + + s->save_i = 0; + s->save_scan_line = NULL; + s->save_dpi1200_remap = NULL; + s->save_color_remap = NULL; + + s->save_dither_err = 0; + s->threshold = s->sm3840_params.threshold; + + setup_scan ((p_usb_dev_handle) s->udev, &(s->sm3840_params)); + + return (SANE_STATUS_GOOD); +} + +static double +sm3840_unit_convert (SANE_Int val) +{ + double d; + d = SANE_UNFIX (val); + d /= MM_PER_INCH; + return d; +} + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) +{ + SM3840_Scan *s = handle; + + DBG (2, "sane_get_parameters\n"); + if (!s->scanning) + { + memset (&s->sane_params, 0, sizeof (s->sane_params)); + /* Copy from options to sm3840_params */ + s->sm3840_params.gray = + (!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) ? 1 : 0; + s->sm3840_params.halftone = + (!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE)) ? 1 : 0; + s->sm3840_params.lineart = + (!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) ? 1 : 0; + + s->sm3840_params.dpi = s->value[OPT_RESOLUTION].w; + s->sm3840_params.bpp = s->value[OPT_BIT_DEPTH].w; + s->sm3840_params.gain = SANE_UNFIX (s->value[OPT_CONTRAST].w); + s->sm3840_params.offset = s->value[OPT_BRIGHTNESS].w; + s->sm3840_params.lamp = s->value[OPT_LAMP_TIMEOUT].w; + s->sm3840_params.threshold = s->value[OPT_THRESHOLD].w; + + if (s->sm3840_params.lineart || s->sm3840_params.halftone) + { + s->sm3840_params.gray = 1; + s->sm3840_params.bpp = 8; + } + + s->sm3840_params.top = sm3840_unit_convert (s->value[OPT_TL_Y].w); + s->sm3840_params.left = sm3840_unit_convert (s->value[OPT_TL_X].w); + s->sm3840_params.width = + sm3840_unit_convert (s->value[OPT_BR_X].w) - s->sm3840_params.left; + s->sm3840_params.height = + sm3840_unit_convert (s->value[OPT_BR_Y].w) - s->sm3840_params.top; + + /* Legalize and calculate pixel sizes */ + prepare_params (&(s->sm3840_params)); + + /* Copy into sane_params */ + s->sane_params.pixels_per_line = s->sm3840_params.scanpix; + s->sane_params.lines = s->sm3840_params.scanlines; + s->sane_params.format = + s->sm3840_params.gray ? SANE_FRAME_GRAY : SANE_FRAME_RGB; + s->sane_params.bytes_per_line = s->sm3840_params.linelen; + s->sane_params.depth = s->sm3840_params.bpp; + + if (s->sm3840_params.lineart || s->sm3840_params.halftone) + { + s->sane_params.bytes_per_line += 7; + s->sane_params.bytes_per_line /= 8; + s->sane_params.depth = 1; + s->sane_params.pixels_per_line = s->sane_params.bytes_per_line * 8; + } + + s->sane_params.last_frame = SANE_TRUE; + } /*!scanning */ + + if (params) + *params = s->sane_params; + + return (SANE_STATUS_GOOD); +} + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_control_option (SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + SM3840_Scan *s = handle; + SANE_Status status = 0; + SANE_Word cap; + DBG (2, "sane_control_option\n"); + if (info) + *info = 0; + if (s->scanning) + return SANE_STATUS_DEVICE_BUSY; + if (option >= NUM_OPTIONS) + return SANE_STATUS_INVAL; + cap = s->options_list[option].cap; + if (!SANE_OPTION_IS_ACTIVE (cap)) + return SANE_STATUS_INVAL; + if (action == SANE_ACTION_GET_VALUE) + { + DBG (1, "sane_control_option %d, get value\n", option); + switch (option) + { + /* word options: */ + case OPT_RESOLUTION: + case OPT_BIT_DEPTH: + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_NUM_OPTS: + case OPT_CONTRAST: + case OPT_BRIGHTNESS: + case OPT_LAMP_TIMEOUT: + case OPT_THRESHOLD: + *(SANE_Word *) val = s->value[option].w; + return (SANE_STATUS_GOOD); + /* string options: */ + case OPT_MODE: + strcpy (val, s->value[option].s); + return (SANE_STATUS_GOOD); + } + } + else if (action == SANE_ACTION_SET_VALUE) + { + DBG (1, "sane_control_option %d, set value\n", option); + if (!SANE_OPTION_IS_SETTABLE (cap)) + return (SANE_STATUS_INVAL); + if (status != SANE_STATUS_GOOD) + return (status); + status = sanei_constrain_value (s->options_list + option, val, info); + switch (option) + { + /* (mostly) side-effect-free word options: */ + case OPT_RESOLUTION: + case OPT_BIT_DEPTH: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_TL_X: + case OPT_TL_Y: + if (info) + *info |= SANE_INFO_RELOAD_PARAMS; + /* fall through */ + case OPT_NUM_OPTS: + case OPT_CONTRAST: + case OPT_BRIGHTNESS: + case OPT_LAMP_TIMEOUT: + case OPT_THRESHOLD: + s->value[option].w = *(SANE_Word *) val; + return (SANE_STATUS_GOOD); + case OPT_MODE: + if (s->value[option].s) + free (s->value[option].s); + s->value[option].s = strdup (val); + + if (info) + *info |= SANE_INFO_RELOAD_PARAMS; + return (SANE_STATUS_GOOD); + } + } + return (SANE_STATUS_INVAL); +} + +/*--------------------------------------------------------------------------*/ +const SANE_Option_Descriptor * +sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) +{ + SM3840_Scan *s = handle; + DBG (2, "sane_get_option_descriptor\n"); + if ((unsigned) option >= NUM_OPTIONS) + return (0); + return (&s->options_list[option]); +} + +/*--------------------------------------------------------------------------*/ + +void +sane_close (SANE_Handle handle) +{ + SM3840_Scan *prev, *s; + + DBG (2, "sane_close\n"); + /* remove handle from list of open handles: */ + prev = 0; + for (s = first_handle; s; s = s->next) + { + if (s == handle) + break; + prev = s; + } + if (!s) + { + DBG (1, "close: invalid handle %p\n", handle); + return; /* oops, not a handle we know about */ + } + + if (s->scanning) + { + sane_cancel (handle); + } + + sanei_usb_close (s->udev); + + if (s->line_buffer) + free (s->line_buffer); + if (s->save_scan_line) + free (s->save_scan_line); + if (s->save_dpi1200_remap) + free (s->save_dpi1200_remap); + if (s->save_color_remap) + free (s->save_color_remap); + + if (prev) + prev->next = s->next; + else + first_handle = s; + free (handle); +} + +/*--------------------------------------------------------------------------*/ +void +sane_exit (void) +{ + SM3840_Device *next; + DBG (2, "sane_exit\n"); + while (first_dev != NULL) + { + next = first_dev->next; + free (first_dev); + first_dev = next; + } + if (devlist) + free (devlist); +} + + + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + DBG_INIT (); + if (version_code) + *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); + if (authorize) + DBG (2, "Unused authorize\n"); + + sanei_usb_init (); + + return (SANE_STATUS_GOOD); +} + +/*--------------------------------------------------------------------------*/ + + +static SANE_Status +add_sm_device (SANE_String_Const devname, SANE_String_Const modname) +{ + SM3840_Device *dev; + + dev = calloc (sizeof (*dev), 1); + if (!dev) + return (SANE_STATUS_NO_MEM); + + memset (dev, 0, sizeof (*dev)); + dev->sane.name = strdup (devname); + dev->sane.model = modname; + dev->sane.vendor = "Microtek"; + dev->sane.type = "flatbed scanner"; + ++num_devices; + dev->next = first_dev; + first_dev = dev; + + return (SANE_STATUS_GOOD); +} + +static SANE_Status +add_sm3840_device (SANE_String_Const devname) +{ + return add_sm_device (devname, "ScanMaker 3840"); +} + +static SANE_Status +add_sm4800_device (SANE_String_Const devname) +{ + return add_sm_device (devname, "ScanMaker 4800"); +} + + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) +{ + static const SANE_Device **devlist = 0; + SM3840_Device *dev; + int i; + + DBG (3, "sane_get_devices (local_only = %d)\n", local_only); + + while (first_dev) + { + dev = first_dev->next; + free (first_dev); + first_dev = dev; + } + first_dev = NULL; + num_devices = 0; + + /* If we get enough scanners should use an array, but for now */ + /* do it one-by-one... */ + sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_device); + sanei_usb_find_devices (0x05da, 0x30cf, add_sm4800_device); + + if (devlist) + free (devlist); + devlist = calloc ((num_devices + 1) * sizeof (devlist[0]), 1); + 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; + if (device_list) + *device_list = devlist; + return (SANE_STATUS_GOOD); +} + + +/*--------------------------------------------------------------------------*/ + +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + int i; + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + + return (max_size); +} + +/*--------------------------------------------------------------------------*/ + +static void +initialize_options_list (SM3840_Scan * s) +{ + + SANE_Int option; + DBG (2, "initialize_options_list\n"); + for (option = 0; option < NUM_OPTIONS; ++option) + { + s->options_list[option].size = sizeof (SANE_Word); + s->options_list[option].cap = + SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + + s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; + s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT; + s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE; + s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word); + s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE; + s->value[OPT_NUM_OPTS].w = NUM_OPTIONS; + + s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE; + s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + s->options_list[OPT_MODE].type = SANE_TYPE_STRING; + s->options_list[OPT_MODE].size = max_string_size (mode_list); + s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->options_list[OPT_MODE].constraint.string_list = mode_list; + s->value[OPT_MODE].s = strdup (mode_list[1]); + + s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; + s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; + s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT; + s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI; + s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list; + s->value[OPT_RESOLUTION].w = 300; + + s->options_list[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; + s->options_list[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; + s->options_list[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; + s->options_list[OPT_BIT_DEPTH].type = SANE_TYPE_INT; + s->options_list[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE; + s->options_list[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->options_list[OPT_BIT_DEPTH].constraint.word_list = bpp_list; + s->value[OPT_BIT_DEPTH].w = 8; + + s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED; + s->options_list[OPT_TL_X].unit = SANE_UNIT_MM; + s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_TL_X].constraint.range = &x_range; + s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min; + s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED; + s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM; + s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_TL_Y].constraint.range = &y_range; + s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min; + s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED; + s->options_list[OPT_BR_X].unit = SANE_UNIT_MM; + s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_BR_X].constraint.range = &x_range; + s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max; + s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED; + s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM; + s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_BR_Y].constraint.range = &y_range; + s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max; + + s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST; + s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; + s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; + s->options_list[OPT_CONTRAST].type = SANE_TYPE_FIXED; + s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE; + s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_CONTRAST].constraint.range = &contrast_range; + s->value[OPT_CONTRAST].w = SANE_FIX (3.5); + + s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; + s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; + s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; + s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT; + s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; + s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_BRIGHTNESS].constraint.range = &brightness_range; + s->value[OPT_BRIGHTNESS].w = 1800; + + s->options_list[OPT_LAMP_TIMEOUT].name = "lamp-timeout"; + s->options_list[OPT_LAMP_TIMEOUT].title = SANE_I18N ("Lamp timeout"); + s->options_list[OPT_LAMP_TIMEOUT].desc = + SANE_I18N ("Minutes until lamp is turned off after scan"); + s->options_list[OPT_LAMP_TIMEOUT].type = SANE_TYPE_INT; + s->options_list[OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE; + s->options_list[OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_LAMP_TIMEOUT].constraint.range = &lamp_range; + s->value[OPT_LAMP_TIMEOUT].w = 15; + + s->options_list[OPT_THRESHOLD].name = "threshold"; + s->options_list[OPT_THRESHOLD].title = SANE_I18N ("Threshold"); + s->options_list[OPT_THRESHOLD].desc = + SANE_I18N ("Threshold value for lineart mode"); + s->options_list[OPT_THRESHOLD].type = SANE_TYPE_INT; + s->options_list[OPT_THRESHOLD].unit = SANE_UNIT_NONE; + s->options_list[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; + s->options_list[OPT_THRESHOLD].constraint.range = &threshold_range; + s->value[OPT_THRESHOLD].w = 128; + +} + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_open (SANE_String_Const devicename, SANE_Handle * handle) +{ + SANE_Status status; + SM3840_Device *dev; + SM3840_Scan *s; + DBG (2, "sane_open\n"); + + /* Make sure we have first_dev */ + sane_get_devices (NULL, 0); + if (devicename[0]) + { + for (dev = first_dev; dev; dev = dev->next) + if (strcmp (dev->sane.name, devicename) == 0) + break; + } + else + { + /* empty devicename -> use first device */ + dev = first_dev; + } + DBG (2, "using device: %s %p\n", dev->sane.name, (unsigned char *) dev); + if (!dev) + return SANE_STATUS_INVAL; + s = calloc (sizeof (*s), 1); + if (!s) + return SANE_STATUS_NO_MEM; + + status = sanei_usb_open (dev->sane.name, &(s->udev)); + if (status != SANE_STATUS_GOOD) + return status; + + initialize_options_list (s); + s->scanning = 0; + /* insert newly opened handle into list of open handles: */ + s->next = first_handle; + first_handle = s; + *handle = s; + return (SANE_STATUS_GOOD); +} + +/*--------------------------------------------------------------------------*/ +SANE_Status +sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) +{ + SM3840_Scan *s = handle; + DBG (2, "sane_set_io_mode( %p, %d )\n", handle, non_blocking); + if (s->scanning) + { + if (non_blocking == SANE_FALSE) + return SANE_STATUS_GOOD; + else + return (SANE_STATUS_UNSUPPORTED); + } + else + return SANE_STATUS_INVAL; +} + +/*---------------------------------------------------------------------------*/ +SANE_Status +sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) +{ + DBG (2, "sane_get_select_fd( %p, %p )\n", (void *) handle, (void *) fd); + return SANE_STATUS_UNSUPPORTED; +} |