From 316d7553e4390c3ccbb5fb75f08ee87d47cd218d Mon Sep 17 00:00:00 2001 From: Henning Geinitz Date: Sun, 20 Feb 2005 20:08:04 +0000 Subject: [PATCH] Added sm3840 backend (from "Earle F. Philhower, III" ). --- AUTHORS | 2 + backend/Makefile.in | 8 +- backend/dll.conf | 1 + backend/sm3840.c | 747 ++++++++++++++++++++++++++ backend/sm3840.conf | 3 + backend/sm3840.h | 123 +++++ backend/sm3840_lib.c | 996 +++++++++++++++++++++++++++++++++++ backend/sm3840_lib.h | 146 +++++ backend/sm3840_params.h | 69 +++ backend/sm3840_scan.c | 938 +++++++++++++++++++++++++++++++++ configure | 24 +- configure.in | 2 +- doc/Makefile.in | 4 +- doc/descriptions/sm3840.desc | 46 ++ doc/sane-sm3840.man | 89 ++++ doc/sane.man | 9 +- 16 files changed, 3189 insertions(+), 18 deletions(-) create mode 100755 backend/sm3840.c create mode 100644 backend/sm3840.conf create mode 100755 backend/sm3840.h create mode 100755 backend/sm3840_lib.c create mode 100755 backend/sm3840_lib.h create mode 100644 backend/sm3840_params.h create mode 100755 backend/sm3840_scan.c create mode 100644 doc/descriptions/sm3840.desc create mode 100644 doc/sane-sm3840.man diff --git a/AUTHORS b/AUTHORS index 551bfd220..da6486fb1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -65,6 +65,7 @@ Backends: sceptre: Frank Zago (*) sharp: Kazuya Fukuda and Abel Deuring (*) sm3600: Marian Eichholz (*) and Glenn Ramsey + sm3840: Earle F. Philhower III snapscan: Kevin Charter, Franck Schneider, Michel Roelofs, Sebastien Sable, Henrik Johansson, Chris Bagwell, and Oliver Schwartz (*) sp15c: Randolph Bentson @@ -131,6 +132,7 @@ David Huggins-Daines David Mosberger David Stevenson Didier Carlier +Earle F. Philhower III Eddy De Greef Eugene S. Weiss Feico W. Dillema diff --git a/backend/Makefile.in b/backend/Makefile.in index 8537edb1b..c25f25c3d 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -150,7 +150,10 @@ DISTFILES = abaton.c abaton.conf abaton.h agfafocus.c agfafocus.conf \ umax_pp_low.c umax_pp_low.h umax_pp_mid.c umax_pp_mid.h umax-scanner.c \ umax-scanner.h umax-scsidef.h umax-uc1200s.c umax-uc1200se.c umax-uc1260.c \ umax-uc630.c umax-uc840.c umax-ug630.c umax-ug80.c umax-usb.c v4l.c \ - v4l.conf v4l-frequencies.h v4l.h + v4l.conf v4l-frequencies.h v4l.h \ + sm3840.c sm3840_lib.c sm3840_params.h sm3840_scan.c sm3840.h \ + sm3840_lib.h sm3840-s.c + .PHONY: all clean depend dist distclean install uninstall @@ -394,6 +397,9 @@ libsane-sharp.la: ../sanei/sanei_config2.lo libsane-sharp.la: ../sanei/sanei_constrain_value.lo libsane-sharp.la: ../sanei/sanei_scsi.lo libsane-sm3600.la: ../sanei/sanei_constrain_value.lo +libsane-sm3840.la: ../sanei/sanei_config2.lo +libsane-sm3840.la: ../sanei/sanei_constrain_value.lo +libsane-sm3840.la: ../sanei/sanei_usb.lo libsane-snapscan.la: ../sanei/sanei_config2.lo libsane-snapscan.la: ../sanei/sanei_constrain_value.lo libsane-snapscan.la: ../sanei/sanei_scsi.lo diff --git a/backend/dll.conf b/backend/dll.conf index 8f91c6b03..d0bf05fd3 100644 --- a/backend/dll.conf +++ b/backend/dll.conf @@ -46,6 +46,7 @@ s9036 sceptre sharp sm3600 +sm3840 snapscan sp15c #st400 diff --git a/backend/sm3840.c b/backend/sm3840.c new file mode 100755 index 000000000..d561ab99e --- /dev/null +++ b/backend/sm3840.c @@ -0,0 +1,747 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_I18N ("Gray"), SANE_I18N ("Color"), + 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 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; + + DBG (2, "+sane-read:%p %p %d %p\n", (unsigned char *) s, buf, max_len, + (unsigned char *) len); + DBG (2, + "+sane-read:remain:%d offset:%d linesleft:%d linebuff:%p linesread:%d\n", + s->remaining, 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 ((usb_dev_handle *) s->udev); + /* Send lamp timeout */ + set_lamp_timer ((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, + (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--; + } + + 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 ((usb_dev_handle *) s->udev); + /* Send lamp timeout */ + set_lamp_timer ((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; + + setup_scan ((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_I18N ("Gray"))) ? 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.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; + 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: + *(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: + s->value[option].w = *(SANE_Word *) val; + DBG (1, "set brightness to\n"); + 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 (V_MAJOR, V_MINOR, 0); + if (authorize) + DBG(2, "Unused authorize\n"); + + sanei_usb_init (); + + return (SANE_STATUS_GOOD); +} + +/*--------------------------------------------------------------------------*/ + + +static SANE_Status +add_sm3840_device (SANE_String_Const devname) +{ + 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 = "ScanMaker 3840"; + dev->sane.vendor = "Microtek"; + dev->sane.type = "flatbed scanner"; + ++num_devices; + dev->next = first_dev; + first_dev = dev; + + return (SANE_STATUS_GOOD); +} + +/*--------------------------------------------------------------------------*/ +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; + + sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_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; + +} + +/*--------------------------------------------------------------------------*/ +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)); + + 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; +} diff --git a/backend/sm3840.conf b/backend/sm3840.conf new file mode 100644 index 000000000..fd4d3ce92 --- /dev/null +++ b/backend/sm3840.conf @@ -0,0 +1,3 @@ +# usb vendor product +# Microtek ScanMaker 3840 ID +usb 0x05da 0x30d4 diff --git a/backend/sm3840.h b/backend/sm3840.h new file mode 100755 index 000000000..34b1d351f --- /dev/null +++ b/backend/sm3840.h @@ -0,0 +1,123 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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. + +*/ + +#ifndef sm3840_h +#define sm3840_h + +#include +#include +#include + + +typedef enum SM3840_Option +{ + OPT_NUM_OPTS = 0, + OPT_MODE, + OPT_RESOLUTION, + OPT_BIT_DEPTH, + + OPT_TL_X, /* top-left x */ + OPT_TL_Y, /* top-left y */ + OPT_BR_X, /* bottom-right x */ + OPT_BR_Y, /* bottom-right y */ + + OPT_BRIGHTNESS, + OPT_CONTRAST, + + OPT_LAMP_TIMEOUT, + + /* must come last */ + NUM_OPTIONS +} SM3840_Option; + +#include "sm3840_params.h" + + +typedef struct SM3840_Device +{ + struct SM3840_Device *next; + SANE_Device sane; +} SM3840_Device; + + + +typedef struct SM3840_Scan +{ + struct SM3840_Scan *next; + SANE_Option_Descriptor options_list[NUM_OPTIONS]; + Option_Value value[NUM_OPTIONS]; + + SANE_Int udev; + + SANE_Bool scanning; + SANE_Bool cancelled; + SANE_Parameters sane_params; + SM3840_Params sm3840_params; + + SANE_Byte *line_buffer; /* One remapped/etc line */ + size_t remaining; /* How much of line_buffer is still good? */ + size_t offset; /* Offset in line_buffer where unread data lives */ + int linesleft; /* How many lines to read from scanner? */ + int linesread; /* Total lines returned to SANE */ + + /* record_line state parameters */ + int save_i; + unsigned char *save_scan_line; + unsigned char *save_dpi1200_remap; + unsigned char *save_color_remap; + +} SM3840_Scan; + + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define SM3840_CONFIG_FILE "sm3840.conf" + +#define MM_PER_INCH 25.4 + +#define SCAN_BUF_SIZE 65536 + +#endif /* sm3840_h */ diff --git a/backend/sm3840_lib.c b/backend/sm3840_lib.c new file mode 100755 index 000000000..d683d3745 --- /dev/null +++ b/backend/sm3840_lib.c @@ -0,0 +1,996 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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 +#include +#include "sm3840_lib.h" + +#ifndef BACKENDNAME +/* For standalone compilation */ +static void +DBG (int ignored, const char *fmt, ...) +{ + va_list a; + va_start (a, fmt); + vfprintf (stderr, fmt, a); + va_end (a); +} +#else +/* For SANE compilation, convert libusb to sanei_usb */ +static int +my_usb_bulk_write (usb_dev_handle * dev, int ep, + unsigned char *bytes, int size, int timeout) +{ + SANE_Status status; + size_t my_size; + + timeout = timeout; + ep = ep; + my_size = size; + status = + sanei_usb_write_bulk ((SANE_Int) dev, (SANE_Byte *) bytes, &my_size); + if (status != SANE_STATUS_GOOD) + my_size = -1; + return my_size; +} + +static int +my_usb_bulk_read (usb_dev_handle * dev, int ep, + unsigned char *bytes, int size, int timeout) +{ + SANE_Status status; + size_t my_size; + + timeout = timeout; + ep = ep; + my_size = size; + status = + sanei_usb_read_bulk ((SANE_Int) dev, (SANE_Byte *) bytes, &my_size); + if (status != SANE_STATUS_GOOD) + my_size = -1; + return my_size; +} + +static int +my_usb_control_msg (usb_dev_handle * dev, int requesttype, + int request, int value, int index, + unsigned char *bytes, int size, int timeout) +{ + SANE_Status status; + + timeout = timeout; + status = sanei_usb_control_msg ((SANE_Int) dev, (SANE_Int) requesttype, + (SANE_Int) request, (SANE_Int) value, + (SANE_Int) index, (SANE_Int) size, + (SANE_Byte *) bytes); + return status; +} +#endif + + +/* Sanitize and convert scan parameters from inches to pixels */ +static void +prepare_params (SM3840_Params * params) +{ + if (params->gray) + params->gray = 1; + if (params->dpi != 1200 && params->dpi != 600 && params->dpi != 300 + && params->dpi != 150) + params->dpi = 150; + if (params->bpp != 8 && params->bpp != 16) + params->bpp = 8; + + /* Sanity check input sizes */ + if (params->top < 0) + params->top = 0; + if (params->left < 0) + params->left = 0; + if (params->width < 0) + params->width = 0; + if (params->height < 0) + params->height = 0; + if ((params->top + params->height) > 11.7) + params->height = 11.7 - params->top; + if ((params->left + params->width) > 8.5) + params->width = 8.5 - params->left; + + params->topline = params->top * params->dpi; + params->scanlines = params->height * params->dpi; + params->leftpix = params->left * params->dpi; + params->leftpix &= ~1; /* Always start on even pixel boundary for remap */ + /* Scanpix always a multiple of 128 */ + params->scanpix = params->width * params->dpi; + params->scanpix = (params->scanpix + 127) & ~127; + + /* Sanity check outputs... */ + if (params->topline < 0) + params->topline = 0; + if (params->scanlines < 1) + params->scanlines = 1; + if (params->leftpix < 0) + params->leftpix = 0; + if (params->scanpix < 128) + params->scanpix = 128; + + /* Some handy calculations */ + params->linelen = + params->scanpix * (params->bpp / 8) * (params->gray ? 1 : 3); +} + +#ifndef BACKENDNAME +usb_dev_handle * +find_device (unsigned int idVendor, unsigned int idProduct) +{ + struct usb_bus *bus; + struct usb_device *dev; + + usb_init (); + usb_find_busses (); + usb_find_devices (); + + for (bus = usb_get_busses (); bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) + if (dev->descriptor.idVendor == idVendor && + dev->descriptor.idProduct == idProduct) + return usb_open (dev); + + return NULL; +} +#endif + +static void +idle_ab (usb_dev_handle * udev) +{ + int len, i; + unsigned char buff[8] = { 0x64, 0x65, 0x16, 0x17, 0x64, 0x65, 0x44, 0x45 }; + for (i = 0; i < 8; i++) + { + len = usb_control_msg (udev, 0x40, 0x0c, 0x0090, 0x0000, buff + i, + 0x0001, wr_timeout); + } +} + +/* CW: 40 04 00b0 0000 : ... */ +static void +write_regs (usb_dev_handle * udev, int regs, unsigned char reg1, + unsigned char val1, + ... /*unsigned char reg, unsigned char val, ... */ ) +{ + unsigned char buff[512]; + va_list marker; + int len, i; + + va_start (marker, val1); + buff[0] = reg1; + buff[1] = val1; + for (i = 1; i < regs; i++) + { + buff[i * 2] = va_arg (marker, int); + buff[i * 2 + 1] = va_arg (marker, int); + } + va_end (marker); + + len = usb_control_msg (udev, 0x40, 0x04, 0x00b0, 0x0000, buff, + regs * 2, wr_timeout); +} + +static int +write_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char byte) +{ + return usb_control_msg (udev, 0x40, request, value, index, + &byte, 1, wr_timeout); +} + +static int +read_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char *byte) +{ + return usb_control_msg (udev, 0xc0, request, value, index, + byte, 1, wr_timeout); +} + +#ifndef BACKENDNAME +/* Copy from a USB data pipe to a file with optional header */ +static void +record_head (usb_dev_handle * udev, char *fname, int bytes, char *header) +{ + FILE *fp; + unsigned char buff[65536]; + int len; + int toread; + + fp = fopen (fname, "wb"); + if (header) + fprintf (fp, "%s", header); + do + { + toread = (bytes > 65536) ? 65536 : bytes; + len = usb_bulk_read (udev, 1, buff, toread, rd_timeout); + if (len > 0) + { + fwrite (buff, len, 1, fp); + bytes -= len; + } + else + { + DBG (2, "TIMEOUT\n"); + } + } + while (bytes); + fclose (fp); +} + +/* Copy from a USB data pipe to a file without header */ +static void +record (usb_dev_handle * udev, char *fname, int bytes) +{ + record_head (udev, fname, bytes, ""); +} +#endif + +static int +max (int a, int b) +{ + return (a > b) ? a : b; +} + + +#define DPI1200SHUFFLE 6 +static void +record_line (int reset, + usb_dev_handle * udev, + unsigned char *storeline, + int dpi, int scanpix, int gray, int bpp16, + int *save_i, + unsigned char **save_scan_line, + unsigned char **save_dpi1200_remap, + unsigned char **save_color_remap) +{ + int len; + unsigned char *scan_line, *dpi1200_remap; + unsigned char *color_remap; + int i; + int red_delay, blue_delay, green_delay; + int j; + int linelen; + int pixsize; + unsigned char *ptrcur, *ptrprev; + unsigned char *savestoreline; + int lineptr, outline, bufflines; + + i = *save_i; + scan_line = *save_scan_line; + dpi1200_remap = *save_dpi1200_remap; + color_remap = *save_color_remap; + + pixsize = (gray ? 1 : 3) * (bpp16 ? 2 : 1); + linelen = scanpix * pixsize; + + if (gray) + { + red_delay = 0; + blue_delay = 0; + green_delay = 0; + } + else if (dpi == 150) + { + red_delay = 0; + blue_delay = 6; + green_delay = 3; + } + else if (dpi == 300) + { + red_delay = 0; + blue_delay = 12; + green_delay = 6; + } + else if (dpi == 600) + { + red_delay = 0; + blue_delay = 24; + green_delay = 12; + } + else /*(dpi==1200) */ + { + red_delay = 0; + blue_delay = 48; + green_delay = 24; + } + + bufflines = max (max (red_delay, blue_delay), green_delay) + 1; + + if (reset) + { + if (dpi1200_remap) + free (dpi1200_remap); + if (scan_line) + free (scan_line); + if (color_remap) + free (color_remap); + + *save_color_remap = color_remap = + (unsigned char *) malloc (bufflines * linelen); + + *save_scan_line = scan_line = (unsigned char *) calloc (linelen, 1); + if (dpi == 1200) + *save_dpi1200_remap = dpi1200_remap = + (unsigned char *) calloc (linelen, DPI1200SHUFFLE); + else + *save_dpi1200_remap = dpi1200_remap = NULL; + + *save_i = i = 0; /* i is our linenumber */ + } + + while (1) + { /* We'll exit inside the loop... */ + len = usb_bulk_read (udev, 1, scan_line, linelen, rd_timeout); + if (dpi == 1200) + { + ptrcur = dpi1200_remap + (linelen * (i % DPI1200SHUFFLE)); + ptrprev = + dpi1200_remap + + (linelen * ((i - (DPI1200SHUFFLE - 2)) % DPI1200SHUFFLE)); + } + else + { + ptrcur = scan_line; + ptrprev = NULL; + } + if (gray) + { + memcpy (ptrcur, scan_line, linelen); + } + else + { + int pixsize = bpp16 ? 2 : 1; + int pix = linelen / (3 * pixsize); + unsigned char *outbuff = ptrcur; + + outline = i; + lineptr = i % bufflines; + + memcpy (color_remap + linelen * lineptr, scan_line, linelen); + + outline++; + if (outline > bufflines) + { + int redline = (outline + red_delay) % bufflines; + int greenline = (outline + green_delay) % bufflines; + int blueline = (outline + blue_delay) % bufflines; + unsigned char *rp, *gp, *bp; + + rp = color_remap + linelen * redline; + gp = color_remap + linelen * greenline + 1 * pixsize; + bp = color_remap + linelen * blueline + 2 * pixsize; + + for (j = 0; j < pix; j++) + { + if (outbuff) + { + *(outbuff++) = *rp; + if (pixsize == 2) + *(outbuff++) = *(rp + 1); + *(outbuff++) = *gp; + if (pixsize == 2) + *(outbuff++) = *(gp + 1); + *(outbuff++) = *bp; + if (pixsize == 2) + *(outbuff++) = *(bp + 1); + } + rp += 3 * pixsize; + gp += 3 * pixsize; + bp += 3 * pixsize; + } + } + lineptr = (lineptr + 1) % bufflines; + } + + if (dpi != 1200) + { + if (i > blue_delay) + { + savestoreline = storeline; + for (j = 0; j < scanpix; j++) + { + memcpy (storeline, ptrcur + linelen - (j + 1) * pixsize, + pixsize); + storeline += pixsize; + } + if (dpi == 150) + { + /* 150 DPI skips every 4th returned line */ + if (i % 4) + { + i++; + *save_i = i; + if (bpp16) + fix_endian_short ((unsigned short *) storeline, + scanpix); + return; + } + storeline = savestoreline; + } + else + { + i++; + *save_i = i; + if (bpp16) + fix_endian_short ((unsigned short *) storeline, scanpix); + return; + } + } + } + else /* dpi==1200 */ + { + if (i > (DPI1200SHUFFLE + blue_delay)) + { + for (j = 0; j < scanpix; j++) + { + if (1 == (j & 1)) + memcpy (storeline, ptrcur + linelen - (j + 1) * pixsize, + pixsize); + else + memcpy (storeline, ptrprev + linelen - (j + 1) * pixsize, + pixsize); + storeline += pixsize; + } /* end for */ + i++; + *save_i = i; + if (bpp16) + fix_endian_short ((unsigned short *) storeline, scanpix); + return; + } /* end if >dpi1200shuffle */ + } /* end if dpi1200 */ + i++; + } /* end for */ +} + + +#ifndef BACKENDNAME +/* Record an image to a file with remapping/reordering/etc. */ +void +record_image (usb_dev_handle * udev, char *fname, int dpi, + int scanpix, int scanlines, int gray, char *head, int bpp16) +{ + FILE *fp; + int i; + int save_i; + unsigned char *save_scan_line; + unsigned char *save_dpi1200_remap; + unsigned char *save_color_remap; + unsigned char *storeline; + + save_i = 0; + save_scan_line = save_dpi1200_remap = save_color_remap = NULL; + storeline = + (unsigned char *) malloc (scanpix * (gray ? 1 : 3) * (bpp16 ? 2 : 1)); + + fp = fopen (fname, "wb"); + if (head) + fprintf (fp, "%s", head); + + for (i = 0; i < scanlines; i++) + { + record_line ((i == 0) ? 1 : 0, udev, storeline, dpi, scanpix, gray, + bpp16, &save_i, &save_scan_line, &save_dpi1200_remap, + &save_color_remap); + fwrite (storeline, scanpix * (gray ? 1 : 3) * (bpp16 ? 2 : 1), 1, fp); + } + fclose (fp); + if (save_scan_line) + free (save_scan_line); + if (save_dpi1200_remap) + free (save_dpi1200_remap); + if (save_color_remap) + free (save_color_remap); + free (storeline); +} +#endif + +static void +record_mem (usb_dev_handle * udev, unsigned char **dest, int bytes) +{ + unsigned char *mem; + unsigned char buff[65536]; + int len; + + mem = (unsigned char *) malloc (bytes); + *dest = mem; + do + { + len = + usb_bulk_read (udev, 1, buff, bytes > 65536 ? 65536 : bytes, + rd_timeout); + if (len > 0) + { + memcpy (mem, buff, len); + bytes -= len; + mem += len; + } + } + while (bytes); +} + + +static void +reset_scanner (usb_dev_handle * udev) +{ + unsigned char rd_byte; + + DBG (2, "+reset_scanner\n"); + write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff, + 0xa2, 0xff); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, + 0x88, 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, + 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, + 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc0, 0x00); + write_regs (udev, 16, 0x84, 0x94, 0x80, 0xd1, 0x80, 0xc1, 0x82, 0x7f, + 0xcf, 0x04, 0xc1, 0x02, 0xc2, 0x00, 0xc3, 0x06, + 0xc4, 0xff, 0xc5, 0x40, 0xc6, 0x8c, 0xc7, 0xdc, + 0xc8, 0x20, 0xc0, 0x72, 0x89, 0xff, 0x86, 0xff); + write_regs (udev, 7, 0xa8, 0x80, 0x83, 0xa2, 0x85, 0xc8, 0x83, 0x82, + 0x85, 0xaf, 0x83, 0x00, 0x93, 0x00); + write_regs (udev, 3, 0xa8, 0x0a, 0x8c, 0x08, 0x94, 0x00); + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + DBG (2, "-reset_scanner\n"); +} + +static void +poll1 (usb_dev_handle * udev) +{ + unsigned char rd_byte; + DBG (2, "+poll1\n"); + do + { + write_regs (udev, 1, 0x97, 0x00); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + } + while (0 == (rd_byte & 0x40)); + DBG (2, "-poll1\n"); +} + +static void +poll2 (usb_dev_handle * udev) +{ + unsigned char rd_byte; + DBG (2, "+poll2\n"); + do + { + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + } + while (0 == (rd_byte & 0x02)); + DBG (2, "-poll2\n"); +} + +#ifndef BACKENDNAME +static void +check_buttons (usb_dev_handle * udev, int *scan, int *print, int *mail) +{ + unsigned char rd_byte; + + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + if (scan) + { + if (0 == (rd_byte & 1)) + *scan = 1; + else + *scan = 0; + } + if (print) + { + if (0 == (rd_byte & 2)) + *print = 1; + else + *print = 0; + } + if (mail) + { + if (0 == (rd_byte & 4)) + *mail = 1; + else + *mail = 0; + } + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + idle_ab (udev); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + idle_ab (udev); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + idle_ab (udev); +} +#endif + +static int +lut (int val, double gain, int offset) +{ + /* int offset = 1800; */ + /* double exponent = 3.5; */ + return (offset + 8192.0 * (pow ((8192.0 - val) / 8192.0, gain))); +} + + +static void +calc_lightmap (unsigned short *buff, + unsigned short *storage, int index, int dpi, + double gain, int offset) +{ + int val, line; + int px = 5632; + int i; + + line = px * 3; + + for (i = 0; i < px; i++) + { + if ((i >= 2) && (i <= (px - 2))) + { + val = 0; + val += 1 * buff[i * 3 + index - 3 * 2]; + val += 3 * buff[i * 3 + index - 3 * 1]; + val += 5 * buff[i * 3 + index + 3 * 0]; + val += 3 * buff[i * 3 + index + 3 * 1]; + val += 1 * buff[i * 3 + index + 3 * 2]; + val += 2 * buff[i * 3 + index - 3 * 1 + line]; + val += 3 * buff[i * 3 + index + 3 * 0 + line]; + val += 2 * buff[i * 3 + index + 3 * 1 + line]; + val += 1 * buff[i * 3 + index + 3 * 0 + 2 * line]; + val /= 21; + } + else + { + val = 1 * buff[i * 3 + index]; + } + + val = val >> 3; + if (val > 8191) + val = 8191; + val = lut (val, gain, offset); + + if (val > 8191) + val = 8191; + if (val < 0) + val = 0; + storage[i * (dpi == 1200 ? 2 : 1)] = val; + if (dpi == 1200) + storage[i * 2 + 1] = val; + } + + fix_endian_short (storage, (dpi == 1200) ? i * 2 : i); +} + + + + +/*#define VALMAP 0x1fff */ +/*#define SCANMAP 0x2000*/ +#define RAWPIXELS600 7320 +#define RAWPIXELS1200 14640 + +static void +select_pixels (unsigned short *map, int dpi, int start, int end) +{ + int i; + int skip, offset; + unsigned short VALMAP = 0x1fff; + unsigned short SCANMAP = 0x2000; + + fix_endian_short (&VALMAP, 1); + fix_endian_short (&SCANMAP, 1); + + /* Clear the pixel-on flags for all bits */ + for (i = 0; i < ((dpi == 1200) ? RAWPIXELS1200 : RAWPIXELS600); i++) + map[i] &= VALMAP; + + /* 300 and 150 have subsampling */ + if (dpi == 300) + skip = -2; + else if (dpi == 150) + skip = -4; + else + skip = -1; + + /* 1200 has 2x pixels so start at 2x the offset */ + if (dpi == 1200) + offset = 234 + (8.5 * 1200); + else + offset = 117 + (8.5 * 600); + + if (0 == (offset & 1)) + offset++; + + DBG (2, "offset=%d start=%d skip=%d\n", offset, start, skip); + + for (i = 0; i < end; i++) + { + int x; + x = offset + (start * skip) + (i * skip); + if (x < 0 || x > ((dpi == 1200) ? RAWPIXELS1200 : RAWPIXELS600)) + DBG (2, "ERR %d\n", x); + else + map[x] |= SCANMAP; + } +} + + +static void +set_lightmap_white (unsigned short *map, int dpi, int color) +{ + int i; + unsigned short VALMAP = 0x1fff; + unsigned short SCANMAP = 0x2000; + + fix_endian_short (&VALMAP, 1); + fix_endian_short (&SCANMAP, 1); + + if (dpi != 1200) + { + memset (map, 0, RAWPIXELS600 * 2); + if (color != 0) + return; /* Only 1st has enables... */ + for (i = 0; i < 22; i++) + map[7 + i] = SCANMAP; /* Get some black... */ + for (i = 0; i < 1024; i++) + map[2048 + i] = SCANMAP; /* And some white... */ + } + else + { + memset (map, 0, RAWPIXELS1200 * 2); + if (color != 0) + return; + for (i = 16; i < 61; i++) + map[i] = SCANMAP; + for (i = 4076; i < 6145; i++) + map[i] = SCANMAP; + /* 3rd is all clear */ + } +} + + +static void +set_lamp_timer (usb_dev_handle * udev, int timeout_in_mins) +{ + write_regs (udev, 7, 0xa8, 0x80, 0x83, 0xa2, 0x85, 0xc8, 0x83, 0x82, + 0x85, 0xaf, 0x83, 0x00, 0x93, 0x00); + write_regs (udev, 3, 0xa8, timeout_in_mins * 2, 0x8c, 0x08, 0x94, 0x00); + idle_ab (udev); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0x26, 0x83, 0x00, 0x8d, 0xff); +} + + +static void +calculate_lut8 (double *poly, int skip, unsigned char *dest) +{ + int i; + double sum, x; + if (!poly || !dest) + return; + for (i = 0; i < 8192; i += skip) + { + sum = poly[0]; + x = (double) i; + sum += poly[1] * x; + x = x * i; + sum += poly[2] * x; + x = x * i; + sum += poly[3] * x; + x = x * i; + sum += poly[4] * x; + x = x * i; + sum += poly[5] * x; + x = x * i; + sum += poly[6] * x; + x = x * i; + sum += poly[7] * x; + x = x * i; + sum += poly[8] * x; + x = x * i; + sum += poly[9] * x; + x = x * i; + if (sum < 0) + sum = 0; + if (sum > 255) + sum = 255; + *dest = (unsigned char) sum; + dest++; + } +} + +static void +download_lut8 (usb_dev_handle * udev, int dpi, int incolor) +{ + double color[10] = { 0.0, 1.84615261590892E-01, -2.19613868292657E-04, + 1.79549523214101E-07, -8.69378513113239E-11, + 2.56694911984996E-14, -4.67288886157239E-18, + 5.11622894146250E-22, -3.08729724411991E-26, + 7.88581670873938E-31 + }; + double gray[10] = { 0.0, 1.73089945056694E-01, -1.39794924306080E-04, + 9.70266873814926E-08, -4.57503008236968E-11, + 1.37092321631794E-14, -2.54395068387198E-18, + 2.82432084125966E-22, -1.71787408822688E-26, + 4.40306800664567E-31 + }; + unsigned char *lut; + int len; + + DBG (2, "+download_lut8\n"); + switch (dpi) + { + case 150: + case 300: + case 600: + lut = (unsigned char *) malloc (4096); + if (!lut) + return; + + if (!incolor) + { + calculate_lut8 (gray, 2, lut); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff, + 0xb4, 0x2f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); + len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + } + else + { + calculate_lut8 (color, 2, lut); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x10, 0xb2, 0x07, 0xb3, 0xff, + 0xb4, 0x1f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); + len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff, + 0xb4, 0x2f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); + len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x30, 0xb2, 0x07, 0xb3, 0xff, + 0xb4, 0x3f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); + len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + } + break; + + case 1200: + default: + lut = (unsigned char *) malloc (8192); + if (!lut) + return; + + if (!incolor) + { + calculate_lut8 (gray, 1, lut); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff, + 0xb4, 0x5f, 0xb5, 0x06); + write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); + len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + } + else + { + calculate_lut8 (color, 1, lut); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x06, 0xb3, 0xff, + 0xb4, 0x3f, 0xb5, 0x06); + write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); + len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff, + 0xb4, 0x5f, 0xb5, 0x06); + write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); + len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x60, 0xb2, 0x06, 0xb3, 0xff, + 0xb4, 0x7f, 0xb5, 0x06); + write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); + len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + } + break; + } + + free (lut); + DBG (2, "-download_lut8\n"); +} + + +static void +set_gain_black (usb_dev_handle * udev, + int r_gain, int g_gain, int b_gain, + int r_black, int g_black, int b_black) +{ + write_regs (udev, 1, 0x80, 0x00); + write_regs (udev, 1, 0x80, 0x01); + write_regs (udev, 1, 0x04, 0x80); + write_regs (udev, 1, 0x04, 0x00); + write_regs (udev, 1, 0x00, 0x00); + write_regs (udev, 1, 0x01, 0x03); + write_regs (udev, 1, 0x02, 0x04); + write_regs (udev, 1, 0x03, 0x11); + write_regs (udev, 1, 0x05, 0x00); + write_regs (udev, 1, 0x28, r_gain); + write_regs (udev, 1, 0x29, g_gain); + write_regs (udev, 1, 0x2a, b_gain); + write_regs (udev, 1, 0x20, r_black); + write_regs (udev, 1, 0x21, g_black); + write_regs (udev, 1, 0x22, b_black); + write_regs (udev, 1, 0x24, 0x00); + write_regs (udev, 1, 0x25, 0x00); + write_regs (udev, 1, 0x26, 0x00); +} + +/* Handle short endianness issues */ +static void +fix_endian_short (unsigned short *data, int count) +{ + unsigned short testvalue = 255; + unsigned char *firstbyte = (unsigned char *) &testvalue; + int i; + + if (*firstbyte == 255) + return; /* INTC endianness */ + + DBG (2, "swapping endiannes...\n"); + for (i = 0; i < count; i++) + data[i] = ((data[i] >> 8) & 0x00ff) | ((data[i] << 8) & 0xff00); +} diff --git a/backend/sm3840_lib.h b/backend/sm3840_lib.h new file mode 100755 index 000000000..ebfde2b9b --- /dev/null +++ b/backend/sm3840_lib.h @@ -0,0 +1,146 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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 + +#ifndef BACKENDNAME +#include +static usb_dev_handle *find_device (unsigned int idVendor, + unsigned int idProduct); + +#else +#include "../include/sane/sanei_usb.h" + +#ifndef USBWRAPPER +#define USBWRAPPER + +#define usb_dev_handle SANE_Int +#define usb_control_msg my_usb_control_msg +#define usb_bulk_read my_usb_bulk_read +#define usb_bulk_write my_usb_bulk_write +static int my_usb_bulk_write (usb_dev_handle * dev, int ep, + unsigned char *bytes, + int size, int timeout); +static int my_usb_bulk_read (usb_dev_handle * dev, int ep, + unsigned char *bytes, + int size, int timeout); +static int my_usb_control_msg (usb_dev_handle * dev, int requesttype, + int request, int value, int index, + unsigned char *bytes, + int size, int timeout); +#endif /* USBWRAPPER */ + +#endif + +#include "sm3840_params.h" + +static void idle_ab (usb_dev_handle * udev); +static void write_regs (usb_dev_handle * udev, int regs, unsigned char reg1, + unsigned char val1, + ... /*unsigned char reg, unsigned char val, ... */ ); +static int write_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char byte); +static int read_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char *byte); + +#ifndef BACKENDNAME +static void record (usb_dev_handle * udev, char *fname, int bytes); +static void record_image (usb_dev_handle * udev, char *fname, int dpi, + int scanpix, int scanlines, int gray, char *head, + int bpp16); +static void check_buttons (usb_dev_handle * udev, int *scan, int *print, + int *mail); +static void record_head (usb_dev_handle * udev, char *fname, int bytes, + char *header); +#endif + +static void poll1 (usb_dev_handle * udev); +static void poll2 (usb_dev_handle * udev); + +static void reset_scanner (usb_dev_handle * udev); + + +static void set_lightmap_white (unsigned short *map, int dpi, int color); + +static void calc_lightmap (unsigned short *buff, + unsigned short *storage, int index, int dpi, + double gain, int offset); +static void select_pixels (unsigned short *map, int dpi, int start, int end); + +static void record_mem (usb_dev_handle * udev, unsigned char **dest, + int bytes); +static void set_lamp_timer (usb_dev_handle * udev, int timeout_in_mins); + +static void set_gain_black (usb_dev_handle * udev, + int r_gain, int g_gain, int b_gain, + int r_black, int g_black, int b_black); + +static void idle_ab (usb_dev_handle * udev); +static void write_regs (usb_dev_handle * udev, int regs, unsigned char reg1, + unsigned char val1, + ... /*unsigned char reg, unsigned char val, ... */ ); +static int write_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char byte); +static int read_vctl (usb_dev_handle * udev, int request, int value, + int index, unsigned char *byte); + +static void download_lut8 (usb_dev_handle * udev, int dpi, int incolor); + +static void record_line (int reset, + usb_dev_handle * udev, + unsigned char *storeline, + int dpi, int scanpix, int gray, int bpp16, + int *save_i, + unsigned char **save_scan_line, + unsigned char **save_dpi1200_remap, + unsigned char **save_color_remap); + + +static void prepare_params (SM3840_Params * params); + +static void fix_endian_short (unsigned short *data, int count); + +#define rd_timeout 10000 +#define wr_timeout 10000 diff --git a/backend/sm3840_params.h b/backend/sm3840_params.h new file mode 100644 index 000000000..03fa5ee49 --- /dev/null +++ b/backend/sm3840_params.h @@ -0,0 +1,69 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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. + +*/ + +#ifndef _SM3840_Params +#define _SM3840_Params +typedef struct SM3840_Params +{ + int gray; /* 0, 1 */ + int dpi; /* 150, 300, 600, 1200 */ + int bpp; /* 8, 16 */ + + double gain; /* 0.01...9.9 */ + int offset; /* 0..4095 */ + + int lamp; /* 1..15 mins */ + + /* Input to configure(), in inches */ + double top, left; + double width, height; + + /* Output from configure(), in pixels */ + int topline; + int scanlines; + int leftpix; + int scanpix; + int linelen; /* bytes per line */ +} SM3840_Params; +#endif diff --git a/backend/sm3840_scan.c b/backend/sm3840_scan.c new file mode 100755 index 000000000..d87aaa25c --- /dev/null +++ b/backend/sm3840_scan.c @@ -0,0 +1,938 @@ +/* sane - Scanner Access Now Easy. + + ScanMaker 3840 Backend + Copyright (C) 2005 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 +#include "sm3840_lib.h" + +#ifndef BACKENDNAME +static void setup_scan (usb_dev_handle * udev, SM3840_Params * p, + char *stname, int raw, int nohead); +#else +static void setup_scan (usb_dev_handle * udev, SM3840_Params * p); +#endif + + +#ifndef BACKENDNAME + +#include "sm3840_lib.c" + +int +main (int argc, char *argv[]) +{ + int i; + + int gray = 0; + int dpi = 1200; + int bpp16 = 0; + int raw = 0; + int nohead = 0; + double gain = 3.5; + int offset = 1800; + usb_dev_handle *udev; + + char *stname; + double topin, botin, leftin, rightin; + int topline, scanlines, leftpix, scanpix; + + stname = NULL; + topin = 0.0; + botin = 11.7; + leftin = 0.0; + rightin = 8.5; + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "-300")) + dpi = 300; + else if (!strcmp (argv[i], "-600")) + dpi = 600; + else if (!strcmp (argv[i], "-1200")) + dpi = 1200; + else if (!strcmp (argv[i], "-150")) + dpi = 150; + else if (!strcmp (argv[i], "-top")) + topin = atof (argv[++i]); + else if (!strcmp (argv[i], "-bot")) + botin = atof (argv[++i]); + else if (!strcmp (argv[i], "-left")) + leftin = atof (argv[++i]); + else if (!strcmp (argv[i], "-right")) + rightin = atof (argv[++i]); + else if (!strcmp (argv[i], "-gain")) + gain = atof (argv[++i]); + else if (!strcmp (argv[i], "-offset")) + offset = atoi (argv[++i]); + else if (!strcmp (argv[i], "-gray")) + gray = 1; + else if (!strcmp (argv[i], "-16bpp")) + bpp16 = 1; + else if (!strcmp (argv[i], "-raw")) + raw = 1; + else if (!strcmp (argv[i], "-nohead")) + nohead = 1; + else + stname = argv[i]; + } + + SM3840_Params params; + params.gray = gray; + params.dpi = dpi; + params.bpp = bpp16 ? 16 : 8; + params.gain = gain; + params.offset = offset; + params.lamp = 15; + params.top = topin; + params.left = leftin; + params.height = botin - topin; + params.width = rightin - leftin; + + prepare_params (¶ms); + udev = find_device (0x05da, 0x30d4); + if (!udev) + fprintf (stderr, "Unable to open scanner.\n"); + else + setup_scan (udev, ¶ms, stname, raw, nohead); + + return 0; +} +#endif + +#ifndef BACKENDNAME +static void +setup_scan (usb_dev_handle * udev, SM3840_Params * p, + char *stname, int raw, int nohead) +#else +static void +setup_scan (usb_dev_handle * udev, SM3840_Params * p) +#endif +{ + int gray = p->gray ? 1 : 0; + int dpi = p->dpi; + int bpp16 = (p->bpp == 16) ? 1 : 0; + double gain = p->gain; + int offset = p->offset; + int topline = p->topline; + int scanlines = p->scanlines; + int leftpix = p->leftpix; + int scanpix = p->scanpix; + int len; + unsigned char hello[2] = { 0x55, 0xaa }; + unsigned char howdy[3]; + unsigned short *whitebalance; + int whitebalancesize = (dpi == 1200) ? 12672 : 6528; + unsigned short *whitemap; + int whitemapsize = (dpi == 1200) ? 29282 : 14642; + unsigned short *whitescan; + unsigned short *lightmap; + unsigned int topreg, botreg; + int redreg, greenreg, bluereg, donered, donegreen, doneblue; + int rgreg = 0x00; + int ggreg = 0x00; + int bgreg = 0x00; + int i, j; + int red, green, blue; + unsigned char rd_byte; + +#ifndef BACKENDNAME + char fname[64]; + char head[128]; + + len = usb_set_configuration (udev, 1); + len = usb_claim_interface (udev, 0); + len = usb_clear_halt (udev, 1); + len = usb_clear_halt (udev, 2); + len = usb_clear_halt (udev, 3); +#endif + DBG (2, "params.gray = %d;\n", p->gray); + DBG (2, "params.dpi = %d\n", p->dpi); + DBG (2, "params.bpp = %d\n", p->bpp); + DBG (2, "params.gain = %f\n", p->gain); + DBG (2, "params.offset = %d\n", p->offset); + DBG (2, "params.lamp = %d\n", p->lamp); + DBG (2, "params.top = %f\n", p->top); + DBG (2, "params.left = %f\n", p->left); + DBG (2, "params.height = %f\n", p->height); + DBG (2, "params.width = %f\n", p->width); + + DBG (2, "params.topline = %d\n", p->topline); + DBG (2, "params.scanlines = %d\n", p->scanlines); + DBG (2, "params.leftpix = %d\n", p->leftpix); + DBG (2, "params.scanpix = %d\n", p->scanpix); + + DBG (2, "params.linelen = %d\n", p->linelen); + + reset_scanner (udev); + + idle_ab (udev); + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0b, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 7, 0xa8, 0x80, 0x83, 0xa2, 0x85, 0x01, 0x83, 0x82, 0x85, + 0x00, 0x83, 0x00, 0x93, 0x00); + write_regs (udev, 1, 0xa8, 0x80); + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xfe, 0x83, 0x00, 0x8d, 0xff); + write_regs (udev, 1, 0x97, 0x00); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 8, 0x80, 0x00, 0x84, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0x86, + 0x00, 0x89, 0x00, 0x94, 0x00, 0x01, 0x02); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 1, 0x94, 0x51); + write_regs (udev, 1, 0xb0, 0x00); + write_regs (udev, 1, 0xb1, 0x00); + write_regs (udev, 1, 0xb2, 0x00); + write_regs (udev, 1, 0xb3, 0x00); + write_regs (udev, 1, 0xb4, 0x10); + write_regs (udev, 1, 0xb5, 0x1f); + write_regs (udev, 1, 0xb0, 0x00); + write_regs (udev, 1, 0xb1, 0x00); + write_regs (udev, 1, 0xb2, 0x00); + write_vctl (udev, 0x0c, 0x0002, 0x0002, 0x00); + len = usb_bulk_write (udev, 2, hello, 2, wr_timeout); + write_regs (udev, 1, 0xb0, 0x00); + write_regs (udev, 1, 0xb1, 0x00); + write_regs (udev, 1, 0xb2, 0x00); + write_vctl (udev, 0x0c, 0x0003, 0x0003, 0x00); + len = usb_bulk_read (udev, 1, howdy, 3, rd_timeout); + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xfe, 0x83, 0x00, 0x8d, 0xff); + write_regs (udev, 1, 0x97, 0x00); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 8, 0x80, 0x00, 0x84, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0x86, + 0x00, 0x89, 0x00, 0x94, 0x00, 0x01, 0x02); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xff, 0x83, 0x00, 0x8d, 0xff); + write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff, 0xa2, + 0xf7); + write_regs (udev, 4, 0x83, 0x22, 0x87, 0x01, 0x83, 0x02, 0x87, 0x16); + write_regs (udev, 11, 0xa0, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0x9d, 0x00, 0x9e, + 0x00, 0xa0, 0x00, 0xce, 0x0c, 0x83, 0x20, 0xa5, 0x00, 0xa6, + 0x00, 0xa7, 0x00); + + set_gain_black (udev, 0x01, 0x01, 0x01, 0xaa, 0xaa, 0xaa); + + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x02, 0x98, + 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x03, 0x98, 0x00, 0x99, + 0x00, 0x9a, 0x00); + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x98, 0x83, 0x82, 0x85, 0x3a); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + + if (dpi == 1200) + write_regs (udev, 1, 0x94, 0x51); + else + write_regs (udev, 1, 0x94, 0x61); + + whitemap = (unsigned short *) malloc (whitemapsize); + + set_lightmap_white (whitemap, dpi, 0); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x06, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x06); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0x7f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + len = + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); + + set_lightmap_white (whitemap, dpi, 1); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0x7f, 0xb5, 0x07); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xbf, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + len = + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); + + set_lightmap_white (whitemap, dpi, 2); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x07); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0xc0, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + len = + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); + + free (whitemap); + + /* Move to head... */ + idle_ab (udev); + write_regs (udev, 1, 0x97, 0x00); + idle_ab (udev); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + idle_ab (udev); + write_regs (udev, 16, 0x84, 0x94, 0x80, 0xd1, 0x80, 0xc1, 0x82, 0x7f, 0xcf, + 0x04, 0xc1, 0x02, 0xc2, 0x00, 0xc3, 0x06, 0xc4, 0xff, 0xc5, + 0x40, 0xc6, 0x8c, 0xc7, 0xdc, 0xc8, 0x20, 0xc0, 0x72, 0x89, + 0xff, 0x86, 0xff); + poll1 (udev); + + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x01, 0x83, 0x82, 0x85, 0x00); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + if (dpi == 1200) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, 0x77, + 0xb9, 0x1e); + else + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, 0x3b, + 0xb9, 0x1f); + write_regs (udev, 5, 0xc0, 0x00, 0x84, 0x00, 0x80, 0xa1, 0xcf, 0x04, 0x82, + 0x00); + if (dpi == 1200) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x02, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x01, 0xbd, 0x01, 0x88, 0xa4, 0xc1, 0x02, 0xc2, 0x00, + 0xc3, 0x02, 0xc4, 0x01, 0xc5, 0x01, 0xc6, 0xa3, 0xc7, 0xa4, + 0xc8, 0x04, 0xc0, 0xd2, 0x89, 0x05, 0x86, 0x00); + else + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x01, 0xbd, 0x01, 0x88, 0xd0, 0xc1, 0x01, 0xc2, 0x00, + 0xc3, 0x04, 0xc4, 0x01, 0xc5, 0x01, 0xc6, 0xcf, 0xc7, 0xd0, + 0xc8, 0x14, 0xc0, 0xd1, 0x89, 0x0a, 0x86, 0x00); + write_regs (udev, 8, 0xbb, 0x01, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, 0xbf, + 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); + write_regs (udev, 1, 0xbe, 0x0d); + write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); + whitebalance = (unsigned short *) malloc (whitebalancesize); + len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + len = + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, whitebalancesize, + rd_timeout); + write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + redreg = greenreg = bluereg = 0x80; + red = green = blue = 0; + donered = donegreen = doneblue = 0; + DBG (2, "setting blackpoint\n"); + for (j = 0; (j < 16) && !(donered && donegreen && doneblue); j++) + { + set_gain_black (udev, 0x01, 0x01, 0x01, redreg, greenreg, bluereg); + + if (dpi == 1200) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x77, 0xb9, 0x1e); + else + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x3b, 0xb9, 0x1f); + write_regs (udev, 8, 0xbb, 0x01, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); + write_regs (udev, 1, 0xbe, 0x0d); + write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); + len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + len = + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, + whitebalancesize, rd_timeout); + if (!donered) + { + red = (whitebalance[0] + whitebalance[3] + whitebalance[6]) / 3; + if (red > 0x1000) + redreg += 0x10; + else if (red > 0x500) + redreg += 0x08; + else if (red > 0x0010) + redreg++; + else + donered = 1; + } + if (!donegreen) + { + green = (whitebalance[1] + whitebalance[4] + whitebalance[7]) / 3; + if (green > 0x1000) + greenreg += 0x10; + else if (green > 0x0500) + greenreg += 0x08; + else if (green > 0x0010) + greenreg++; + else + donegreen = 1; + } + if (!doneblue) + { + blue = (whitebalance[2] + whitebalance[5] + whitebalance[8]) / 3; + if (blue > 0x1000) + bluereg += 0x10; + else if (blue > 0x0500) + bluereg += 0x08; + else if (blue > 0x0010) + bluereg++; + else + doneblue = 1; + } + DBG (2, "red=%d(%d)%02x, green=%d(%d)%02x, blue=%d(%d)%02x\n", + red, donered, redreg, green, donegreen, greenreg, + blue, doneblue, bluereg); + write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + } + DBG (2, "setting whitepoint\n"); + donegreen = donered = doneblue = 0; + for (j = 0; (j < 16) && !(donered && donegreen && doneblue); j++) + { + set_gain_black (udev, rgreg, ggreg, bgreg, redreg, greenreg, bluereg); + + if (dpi == 1200) + idle_ab (udev); + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, 0x3b, + 0xb9, 0x1f); + if (dpi == 1200) + idle_ab (udev); + write_regs (udev, 8, 0xbb, 0x01, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); + write_regs (udev, 1, 0xbe, 0x0d); + write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); + len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + len = + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, + whitebalancesize, rd_timeout); + if (!donered) + { + red = + (whitebalance[180 * 3 + 0] + whitebalance[180 * 3 + 3] + + whitebalance[180 * 3 + 6]) / 3; + if (red < 0x5000) + rgreg += 0x02; + else if (red < 0x8000) + rgreg += 0x01; + else + donered = 1; + } + if (!donegreen) + { + green = + (whitebalance[180 * 3 + 1] + whitebalance[180 * 3 + 4] + + whitebalance[180 * 3 + 7]) / 3; + if (green < 0x5000) + ggreg += 0x02; + else if (green < 0x8000) + ggreg += 0x01; + else + donegreen = 1; + } + if (!doneblue) + { + blue = + (whitebalance[180 * 3 + 2] + whitebalance[180 * 3 + 5] + + whitebalance[180 * 3 + 8]) / 3; + if (blue < 0x5000) + bgreg += 0x02; + else if (blue < 0x8000) + bgreg += 0x01; + else + doneblue = 1; + } + DBG (2, "red=%d(%d)%02x, green=%d(%d)%02x, blue=%d(%d)%02x\n", + red, donered, rgreg, green, donegreen, ggreg, blue, doneblue, + bgreg); + write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + } + free (whitebalance); + + /* One step down for optimal contrast... */ + if (rgreg) + rgreg--; + if (bgreg) + bgreg--; + if (ggreg) + ggreg--; + + + write_regs (udev, 8, 0x80, 0x00, 0x84, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0x86, + 0x00, 0x89, 0x00, 0x94, 0x00, 0x01, 0x02); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xff, 0x83, 0x00, 0x8d, 0xff); + write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff, 0xa2, + 0xf7); + write_regs (udev, 4, 0x83, 0x22, 0x87, 0x01, 0x83, 0x02, 0x87, 0x16); + write_regs (udev, 11, 0xa0, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0x9d, 0x00, 0x9e, + 0x00, 0xa0, 0x00, 0xce, 0x0c, 0x83, 0x20, 0xa5, 0x00, 0xa6, + 0x00, 0xa7, 0x00); + set_gain_black (udev, rgreg, ggreg, bgreg, redreg, greenreg, bluereg); + + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x02, 0x98, + 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x03, 0x98, 0x00, 0x99, + 0x00, 0x9a, 0x00); + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x98, 0x83, 0x82, 0x85, 0x3a); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + if (dpi == 1200) + write_regs (udev, 1, 0x94, 0x71); + else + write_regs (udev, 1, 0x94, 0x61); + + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x01, 0x83, 0x82, 0x85, 0x00); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + if (dpi == 1200) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, 0xbf, + 0xb9, 0x17); + else + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, 0xdf, + 0xb9, 0x1b); + write_regs (udev, 6, 0xc0, 0x00, 0x84, 0x00, 0x84, 0xb4, 0x80, 0xe1, 0xcf, + 0x04, 0x82, 0x00); + if (dpi == 1200) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x02, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x08, 0x88, 0xa4, 0xc1, 0x02, 0xc2, 0x00, + 0xc3, 0x02, 0xc4, 0x20, 0xc5, 0x08, 0xc6, 0x96, 0xc7, 0xa4, + 0xc8, 0x06, 0xc0, 0xd2, 0x89, 0x24, 0x86, 0x01); + else + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x10, 0x88, 0xd0, 0xc1, 0x01, 0xc2, 0x00, + 0xc3, 0x04, 0xc4, 0x20, 0xc5, 0x10, 0xc6, 0xc3, 0xc7, 0xd0, + 0xc8, 0x1c, 0xc0, 0xd1, 0x89, 0x24, 0x86, 0x01); + write_regs (udev, 8, 0xbb, 0x05, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, 0xbf, + 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); + write_regs (udev, 1, 0xbe, 0x1d); + write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); + len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + record_mem (udev, (unsigned char **) (void *)&whitescan, + (5632 * 2 * 3 * (dpi == 1200 ? 2 : 1)) * 4); + write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff, 0xa2, + 0xff); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0b); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x0f); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x05); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xff, 0x83, 0x00, 0x8d, 0xff); + write_regs (udev, 1, 0x97, 0x00); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 1, 0x97, 0x00); + write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); + read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + write_regs (udev, 16, 0x84, 0x94, 0x80, 0xd1, 0x80, 0xc1, 0x82, 0x7f, 0xcf, + 0x04, 0xc1, 0x02, 0xc2, 0x00, 0xc3, 0x06, 0xc4, 0xff, 0xc5, + 0x40, 0xc6, 0x8c, 0xc7, 0xdc, 0xc8, 0x20, 0xc0, 0x72, 0x89, + 0xff, 0x86, 0xff); + poll1 (udev); + + /* ready scan position */ + /* 1/3" of unscannable area at top... */ + if (dpi == 300) + topreg = 120 * 4; + else if (dpi == 600) + topreg = 139 * 4; + else if (dpi == 1200) + topreg = 152 * 4; + else /*if (dpi == 150) */ + topreg = 120 * 4; + topreg += topline * (1200 / dpi); + + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + write_regs (udev, 14, 0x84, 0xb4, 0x80, 0xe1, 0xcf, 0x04, 0xc1, 0x02, 0xc2, + 0x00, 0xc3, 0x07, 0xc4, 0xff, 0xc5, 0x40, 0xc6, 0x8c, 0xc7, + 0xdc, 0xc8, 0x20, 0xc0, 0x72, 0x89, topreg & 255, 0x86, + 255 & (topreg >> 8)); + write_regs (udev, 1, 0x97, 0x00); + poll2 (udev); + + write_regs (udev, 8, 0x80, 0x00, 0x84, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0x86, + 0x00, 0x89, 0x00, 0x94, 0x00, 0x01, 0x02); + write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); + write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); + write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00, 0x88, + 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, + 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, + 0x00, 0xc0, 0x00); + if (dpi == 1200) + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0x24, 0x83, 0x00, 0x8d, 0xff); + else + write_regs (udev, 4, 0x83, 0x20, 0x8d, 0xff, 0x83, 0x00, 0x8d, 0xff); + if (dpi != 1200) + write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff, 0xa2, + 0xf7); + if (dpi == 1200) + write_regs (udev, 4, 0x83, 0x22, 0x87, 0x01, 0x83, 0x02, 0x87, 0x2c); + else + write_regs (udev, 4, 0x83, 0x22, 0x87, 0x01, 0x83, 0x02, 0x87, 0x16); + if (dpi == 1200) + write_regs (udev, 11, 0xa0, 0x00, 0x9c, 0x00, 0x9f, 0x40, 0x9d, 0x00, + 0x9e, 0x00, 0xa0, 0x00, 0xce, 0x0c, 0x83, 0x20, 0xa5, 0x00, + 0xa6, 0x00, 0xa7, 0x00); + else + write_regs (udev, 11, 0xa0, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0x9d, 0x00, + 0x9e, 0x00, 0xa0, 0x00, 0xce, 0x0c, 0x83, 0x20, 0xa5, 0x00, + 0xa6, 0x00, 0xa7, 0x00); + + set_gain_black (udev, rgreg, ggreg, bgreg, redreg, greenreg, bluereg); + if (!bpp16) + { + if (dpi == 1200) + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0xc7, 0x99, 0x99, 0x9a, 0xd5, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0xc8, 0x99, 0x99, 0x9a, 0xd3, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + else if (dpi == 150) + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0x94, 0x99, 0x67, 0x9a, 0x83, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0x7e, 0x99, 0x5d, 0x9a, 0x7d, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + else + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0xb3, 0x99, 0x72, 0x9a, 0x9d, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0xa3, 0x99, 0x6f, 0x9a, 0x94, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + } + else + { + if (dpi == 1200) + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0xb9, 0x99, 0x7a, 0x9a, 0xd6, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0xbc, 0x99, 0x7c, 0x9a, 0xd3, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + else if (dpi == 150) + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0x9c, 0x99, 0x5f, 0x9a, 0x87, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0x97, 0x99, 0x58, 0x9a, 0x81, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + else + write_regs (udev, 16, 0x9b, 0x00, 0x98, 0x9d, 0x99, 0x79, 0x9a, 0x8e, + 0x9b, 0x01, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, + 0x02, 0x98, 0x89, 0x99, 0x71, 0x9a, 0x80, 0x9b, 0x03, + 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00); + } + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x98, 0x83, 0x82, 0x85, 0x3a); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + if (!bpp16) + { + if (dpi == 1200) + write_regs (udev, 1, 0x94, 0x51); + else + write_regs (udev, 1, 0x94, 0x41); + } + else + { + if (dpi == 1200) + write_regs (udev, 1, 0x94, 0x71); + else + write_regs (udev, 1, 0x94, 0x61); + } + lightmap = (unsigned short *) malloc (whitemapsize); + calc_lightmap (whitescan, lightmap, 0, dpi, gain, offset); + select_pixels (lightmap, dpi, leftpix, scanpix); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x06, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x06); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0x7f, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + len = + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); + + calc_lightmap (whitescan, lightmap, 1, dpi, gain, offset); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0x7f, 0xb5, 0x07); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xbf, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + if (gray) + for (i = 0; i < whitemapsize / 2; i++) + lightmap[i] |= 0xc000; + len = + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); + + calc_lightmap (whitescan, lightmap, 2, dpi, gain, offset); + if (dpi == 1200) + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x07); + else + write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0xc0, 0xb2, 0x07, 0xb3, 0xff, 0xb4, + 0xff, 0xb5, 0x07); + write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); + len = + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); + + free (whitescan); + free (lightmap); + + if (!bpp16) + download_lut8 (udev, dpi, gray ? 0 : 1); + + write_regs (udev, 4, 0x83, 0xa2, 0x85, 0x01, 0x83, 0x82, 0x85, 0x00); + write_regs (udev, 1, 0x9d, 0x80); + write_regs (udev, 1, 0x9d, 0x00); + + if (!bpp16) + { + if (dpi == 1200) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0x1f, 0xb5, 0x06, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x43, 0xb9, 0x2d); + else if (dpi == 150) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0x0f, 0xb5, 0x07, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0xe0, 0xb9, 0x37); + else + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0x0f, 0xb5, 0x07, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x90, 0xb9, 0x37); + } + else + { + if (dpi == 1200) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x87, 0xb9, 0x18); + else if (dpi == 150) + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0xc1, 0xb9, 0x1e); + else + write_regs (udev, 10, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0xff, + 0xb4, 0xff, 0xb5, 0x03, 0xb6, 0x01, 0xb7, 0x00, 0xb8, + 0x21, 0xb9, 0x1e); + } + + /* [86,89] controls number of 300dpi steps to scan */ + botreg = scanlines * (1200 / dpi) + 400; + write_regs (udev, 6, 0xc0, 0x00, 0x84, 0x00, 0x84, 0xb4, 0x80, 0xe1, 0xcf, + 0x04, 0x82, 0x00); + + if (!bpp16) + { + if (dpi == 300) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x10, 0x88, 0xd0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x04, 0xc4, 0x20, 0xc5, 0x10, 0xc6, 0xc3, + 0xc7, 0xd0, 0xc8, 0x12, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 600) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x10, 0x88, 0xd0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x04, 0xc4, 0x20, 0xc5, 0x10, 0xc6, 0xc3, + 0xc7, 0xd0, 0xc8, 0x16, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 1200) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x02, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x08, 0x88, 0xa4, 0xc1, 0x02, 0xc2, + 0x00, 0xc3, 0x02, 0xc4, 0x20, 0xc5, 0x08, 0xc6, 0x96, + 0xc7, 0xa4, 0xc8, 0x06, 0xc0, 0xd2, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 150) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x06, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x1c, 0xbd, 0x08, 0x88, 0xe0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x03, 0xc4, 0x1c, 0xc5, 0x08, 0xc6, 0xd7, + 0xc7, 0xe0, 0xc8, 0x11, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + + if (dpi == 300) + write_regs (udev, 8, 0xbb, 0x01, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x20, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 600) + write_regs (udev, 8, 0xbb, 0x02, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x20, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 1200) + write_regs (udev, 8, 0xbb, 0x02, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x20, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 150) + write_regs (udev, 8, 0xbb, 0x00, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x20, 0x91, 0x00, 0x83, 0x82); + } + else + { + if (dpi == 300) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x10, 0x88, 0xd0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x04, 0xc4, 0x20, 0xc5, 0x10, 0xc6, 0xc3, + 0xc7, 0xd0, 0xc8, 0x13, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 150) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x06, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x1c, 0xbd, 0x08, 0x88, 0xe0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x03, 0xc4, 0x1c, 0xc5, 0x08, 0xc6, 0xd7, + 0xc7, 0xe0, 0xc8, 0x12, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 1200) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x02, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x08, 0x88, 0xa4, 0xc1, 0x02, 0xc2, + 0x00, 0xc3, 0x02, 0xc4, 0x20, 0xc5, 0x08, 0xc6, 0x96, + 0xc7, 0xa4, 0xc8, 0x0c, 0xc0, 0xd2, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + else if (dpi == 600) + write_regs (udev, 18, 0x83, 0xa2, 0x85, 0x04, 0x83, 0x82, 0x85, 0x00, + 0xbc, 0x20, 0xbd, 0x10, 0x88, 0xd0, 0xc1, 0x01, 0xc2, + 0x00, 0xc3, 0x04, 0xc4, 0x20, 0xc5, 0x10, 0xc6, 0xc3, + 0xc7, 0xd0, 0xc8, 0x1a, 0xc0, 0xd1, 0x89, botreg & 255, + 0x86, 255 & (botreg >> 8)); + + if (dpi == 300) + write_regs (udev, 8, 0xbb, 0x02, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x70, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 150) + write_regs (udev, 8, 0xbb, 0x01, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x70, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 1200) + write_regs (udev, 8, 0xbb, 0x05, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x70, 0x91, 0x00, 0x83, 0x82); + else if (dpi == 600) + write_regs (udev, 8, 0xbb, 0x04, 0x9b, 0x24, 0x8b, 0x00, 0x8e, 0x80, + 0xbf, 0x00, 0x90, 0x70, 0x91, 0x00, 0x83, 0x82); + + + } + + if (gray) + write_regs (udev, 1, 0xbe, 0x05); + else + write_regs (udev, 1, 0xbe, 0x0d); + write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); + len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); + +#ifndef BACKENDNAME + sprintf (fname, "%d.%s", dpi, gray ? "pgm" : "ppm"); + if (stname) + strcpy (fname, stname); + sprintf (head, "P%d\n%d %d\n%d\n", gray ? 5 : 6, scanpix, scanlines, + bpp16 ? 65535 : 255); + if (nohead) + head[0] = 0; + if (!raw) + record_image (udev, fname, dpi, scanpix, scanlines, gray, head, bpp16); + else + record_head (udev, fname, + scanpix * (gray ? 1 : 3) * (bpp16 ? 2 : 1) * scanlines, ""); + + reset_scanner (udev); + idle_ab (udev); + set_lamp_timer (udev, 5); +#endif +} diff --git a/configure b/configure index 8c0f7295a..f19df9fb1 100755 --- a/configure +++ b/configure @@ -9639,9 +9639,9 @@ fi; if test "${ac_cv_header_usb_h}" = "yes" && test "$USE_LIBUSB" = "yes" ; then -echo "$as_me:$LINENO: checking for usb_get_busses in -lusb" >&5 -echo $ECHO_N "checking for usb_get_busses in -lusb... $ECHO_C" >&6 -if test "${ac_cv_lib_usb_usb_get_busses+set}" = set; then +echo "$as_me:$LINENO: checking for usb_interrupt_read in -lusb" >&5 +echo $ECHO_N "checking for usb_interrupt_read in -lusb... $ECHO_C" >&6 +if test "${ac_cv_lib_usb_usb_interrupt_read+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9659,11 +9659,11 @@ extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char usb_get_busses (); +char usb_interrupt_read (); int main () { -usb_get_busses (); +usb_interrupt_read (); ; return 0; } @@ -9689,20 +9689,20 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_usb_usb_get_busses=yes + ac_cv_lib_usb_usb_interrupt_read=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_usb_usb_get_busses=no +ac_cv_lib_usb_usb_interrupt_read=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_get_busses" >&5 -echo "${ECHO_T}$ac_cv_lib_usb_usb_get_busses" >&6 -if test $ac_cv_lib_usb_usb_get_busses = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_interrupt_read" >&5 +echo "${ECHO_T}$ac_cv_lib_usb_usb_interrupt_read" >&6 +if test $ac_cv_lib_usb_usb_interrupt_read = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBUSB 1 _ACEOF @@ -9711,7 +9711,7 @@ _ACEOF fi - if test "${ac_cv_lib_usb_usb_get_busses}" = "yes" ; then + if test "${ac_cv_lib_usb_usb_interrupt_read}" = "yes" ; then HAVE_LIBUSB="yes" fi fi @@ -25618,7 +25618,7 @@ echo "$as_me: Manually selected backends: ${BACKENDS}" >&6;} microtek2 mustek mustek_usb nec pie plustek \ plustek_pp ricoh s9036 sceptre sharp \ sp15c st400 tamarack test teco1 teco2 teco3 umax umax_pp umax1220u \ - artec_eplus48u ma1509 ibm hp5400 u12 snapscan niash" + artec_eplus48u ma1509 ibm hp5400 u12 snapscan niash sm3840" if test "${sane_cv_use_libjpeg}" != "yes"; then echo "*** disabling DC210 backend (failed to find JPEG library)" diff --git a/configure.in b/configure.in index 0213407c2..1e8415e5c 100644 --- a/configure.in +++ b/configure.in @@ -299,7 +299,7 @@ else microtek2 mustek mustek_usb nec pie plustek \ plustek_pp ricoh s9036 sceptre sharp \ sp15c st400 tamarack test teco1 teco2 teco3 umax umax_pp umax1220u \ - artec_eplus48u ma1509 ibm hp5400 u12 snapscan niash" + artec_eplus48u ma1509 ibm hp5400 u12 snapscan niash sm3840" if test "${sane_cv_use_libjpeg}" != "yes"; then echo "*** disabling DC210 backend (failed to find JPEG library)" diff --git a/doc/Makefile.in b/doc/Makefile.in index 1eeb60f4b..8681c9b93 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -52,7 +52,7 @@ SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 sane-dll.5 \ sane-teco1.5 sane-teco2.5 sane-teco3.5 sane-test.5 sane-sp15c.5 \ sane-coolscan2.5 sane-hpsj5s.5 sane-gt68xx.5 sane-artec_eplus48u.5 \ sane-ma1509.5 sane-ibm.5 sane-hp5400.5 sane-plustek_pp.5 sane-u12.5 \ - sane-niash.5 + sane-niash.5 sane-sm3840.5 SECT7 = sane.7 SECT8 = saned.8 MANPAGES = $(SECT1) $(SECT5) $(SECT7) $(SECT8) @@ -103,7 +103,7 @@ DISTFILES = Makefile.in backend-writing.txt descriptions.txt \ sane-teco1.man sane-teco2.man sane-teco3.man sane-test.man sane-sp15c.man \ sane-hpsj5s.man gamma4scanimage.man sane-gt68xx.man sane-artec_eplus48u.man \ sane-ma1509.man sane-ibm.man sane-hp5400.man sane-plustek_pp.man \ - sane-u12.man sane-niash.man + sane-u12.man sane-niash.man sane-sm3840.man .PHONY: all clean depend dist distclean html html-man install \ sane-html uninstall diff --git a/doc/descriptions/sm3840.desc b/doc/descriptions/sm3840.desc new file mode 100644 index 000000000..66ea6ebf0 --- /dev/null +++ b/doc/descriptions/sm3840.desc @@ -0,0 +1,46 @@ +; +; SANE Backend specification file +; +; It's basically emacs-lisp --- so ";" indicates comment to end of line. +; All syntactic elements are keyword tokens, followed by a string or +; keyword argument, as specified. +; +; ":backend" *must* be specified. +; All other information is optional (but what good is the file without it?). +; +; See doc/descriptions.txt for details. + +:backend "sm3840" ; name of backend +:version "1.0" ; version of backend (or "unmaintained") +:new :yes ; Is the backend new to this SANE release? + ; :yes or :no +:manpage "sane-sm3840" ; name of manpage (if it exists) +:url "http://www.ziplabel.com/sm3840/" ; backend's web page +:comment "This reverse-engineered backend supports the USB ScanMaker 3840 model" + ; comment about the backend + +:devicetype :scanner ; start of a list of devices.... + ; other types: :stillcam, :vidcam, + ; :meta, :api + +:mfg "Microtek" ; name a manufacturer +:url "http://www.microtek.com/" ; manufacturer's URL +:comment "Microtek makes a wide variety of devices." + ; comment about the manufacturer + +:model "ScanMaker 3840" ; name models for above-specified mfg. +:status :good ; :minimal, :basic, :good, :complete + ; :untested, or :unsupported +:interface "USB" ; interface type of the device: + ; "SCSI", "USB", "Parport (EPP)", + ; "Parport (SPP)", "Parport (ECP)", + ; "Serial port", "IEEE-1394", "JetDirect", + ; or "Proprietary". +:comment "8 and 16 bit, color and grayscale" ; comment about the model + +; :comment and :url specifiers are optional after :mfg, :model, :desc, +; and at the top-level. + +; :status specifier is optional after :model and at the top-level + + diff --git a/doc/sane-sm3840.man b/doc/sane-sm3840.man new file mode 100644 index 000000000..ead46ca1f --- /dev/null +++ b/doc/sane-sm3840.man @@ -0,0 +1,89 @@ +.TH sane-sm3840 5 "Feb 6, 2005" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.IX sane-sm3840 +.SH NAME +sane-sm3840 \- SANE backend for Microtek scanners with SCAN08 USB chip +.SH DESCRIPTION +The +.B sane-sm3840 +library implements a SANE (Scanner Access Now Easy) backend that +provides access to some Microtek scanners with the SCAN08 +USB chip. +.PP +There exist backends for Microtek scanners with SCSI command set. +Refer to sane-microtek(5) and sane-microtek2(5) for details. +.PP +At present, the following +scanners are known positively to work with this backend: +.PP +.RS +Vendor Product id: Remark: +.br +-------- -------------- ----------- +.br +Microtek ScanMaker 3840 all modes ok +.RE +.PP +If you own a Microtek scanner with the SCAN08 chip other than the ones +listed above, it may or may not work with SANE. Feel free to contact the +backend author (earle@ziplabel.com) to report results with scanners not +on the list. + + +.SH "FRONTEND OPTIONS" +.PP +The following options are supported by the sm3840-driver: +.PP +.B --mode color|gray +.br +Color or grayscale mode. + +.B --resolution 150|300|600|1200 +.br +Pixels per inch for scans. + +.B --depth 8|16 +.br +Note that the least significant bits of 16bpp mode may be noise. + +.B --brightness 1..4096 +.br +Higher numbers increase brightness of returned image. + +.B --contrast 0.1..9.9 +.br +Larger numbers decrease contrast of returned image. + +.B --lamp-timeout 1..15 +.br +Time in minutes until the lamp is turned off after a scan. + +.SH CONFIGURATION +This backend does not support a configuration file right now. + +.SH FILES +.TP +.I @LIBDIR@/libsane-sm3840.a +The static library implementing this backend. +.TP +.I @LIBDIR@/libsane-sm3840.so +The shared library implementing this backend (present on systems that +support dynamic loading). + + +.SH ENVIRONMENT +.TP +.B SANE_DEBUG_SM3840 +If the library was compiled with debug support enabled, this +environment variable controls the debug level for this backend. E.g., +a value of 128 requests all debug output to be printed. Smaller +levels reduce verbosity. To see error messages on stderr set +SANE_DEBUG_SM3840 to 1. + +.SH "SEE ALSO" +sane-microtek2(5), sane-sm3600(5), http://www.ziplabel.com/sm3840 + +.SH AUTHOR +.br +Earle F. Philhower III (earle@ziplabel.com) +.br + diff --git a/doc/sane.man b/doc/sane.man index b4f7999b6..4076e8a11 100644 --- a/doc/sane.man +++ b/doc/sane.man @@ -1,4 +1,4 @@ -.TH sane 7 "03 Aug 2004" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.TH sane 7 "20 Feb 2005" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" .IX sane .SH NAME @@ -376,6 +376,11 @@ The SANE sm3600 backend supports the Microtek ScanMaker 3600 USB scanner. See .BR sane\-sm3600 (5) for details. .TP +.B sm3840 +The SANE sm3840 backend suppoert the Microtek ScanMaker 3840 USB scanner. See +.BR sane\-sm3840 (5) +for details. +.TP .B snapscan The snapscan backend supports AGFA SnapScan flatbed scanners. See .BR sane\-snapscan (5) @@ -804,4 +809,4 @@ David Mosberger-Tang and many many more (see for details). This man page was written by Henning Meier-Geinitz. Quite a lot of text was taken from the .B SANE -standard, several man pages, and README files. \ No newline at end of file +standard, several man pages, and README files.