sane-backends-1.0.15/ 40777 0 0 0 10220424765 12450 5ustar usergroupsane-backends-1.0.15/backend/ 40777 0 0 0 10220425015 14024 5ustar usergroupsane-backends-1.0.15/backend/sm3840.c100666 0 0 53306 10220425015 15252 0ustar usergroup/* 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_sm_device (SANE_String_Const devname, SANE_String_Const modname) { SM3840_Device *dev; dev = calloc (sizeof (*dev), 1); if (!dev) return (SANE_STATUS_NO_MEM); memset (dev, 0, sizeof (*dev)); dev->sane.name = strdup (devname); dev->sane.model = modname; dev->sane.vendor = "Microtek"; dev->sane.type = "flatbed scanner"; ++num_devices; dev->next = first_dev; first_dev = dev; return (SANE_STATUS_GOOD); } static SANE_Status add_sm3840_device (SANE_String_Const devname) { return add_sm_device (devname, "ScanMaker 3840"); } static SANE_Status add_sm4800_device (SANE_String_Const devname) { return add_sm_device (devname, "ScanMaker 4800"); } /*--------------------------------------------------------------------------*/ SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) { static const SANE_Device **devlist = 0; SM3840_Device *dev; int i; DBG (3, "sane_get_devices (local_only = %d)\n", local_only); while (first_dev) { dev = first_dev->next; free (first_dev); first_dev = dev; } first_dev = NULL; num_devices = 0; // If we get enough scanners should use an array, but for now // do it one-by-one... sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_device); sanei_usb_find_devices (0x05da, 0x30cf, add_sm4800_device); if (devlist) free (devlist); devlist = calloc ((num_devices + 1) * sizeof (devlist[0]), 1); if (!devlist) return SANE_STATUS_NO_MEM; i = 0; for (dev = first_dev; i < num_devices; dev = dev->next) devlist[i++] = &dev->sane; devlist[i++] = 0; if (device_list) *device_list = devlist; return (SANE_STATUS_GOOD); } /*--------------------------------------------------------------------------*/ static size_t max_string_size (const SANE_String_Const strings[]) { size_t size, max_size = 0; int i; for (i = 0; strings[i]; ++i) { size = strlen (strings[i]) + 1; if (size > max_size) max_size = size; } return (max_size); } /*--------------------------------------------------------------------------*/ static void initialize_options_list (SM3840_Scan * s) { SANE_Int option; DBG (2, "initialize_options_list\n"); for (option = 0; option < NUM_OPTIONS; ++option) { s->options_list[option].size = sizeof (SANE_Word); s->options_list[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT; s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE; s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word); s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE; s->value[OPT_NUM_OPTS].w = NUM_OPTIONS; s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE; s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE; s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE; s->options_list[OPT_MODE].type = SANE_TYPE_STRING; s->options_list[OPT_MODE].size = max_string_size (mode_list); s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; s->options_list[OPT_MODE].constraint.string_list = mode_list; s->value[OPT_MODE].s = strdup (mode_list[1]); s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT; s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI; s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list; s->value[OPT_RESOLUTION].w = 300; s->options_list[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].type = SANE_TYPE_INT; s->options_list[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE; s->options_list[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; s->options_list[OPT_BIT_DEPTH].constraint.word_list = bpp_list; s->value[OPT_BIT_DEPTH].w = 8; s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED; s->options_list[OPT_TL_X].unit = SANE_UNIT_MM; s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_TL_X].constraint.range = &x_range; s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min; s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED; s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM; s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_TL_Y].constraint.range = &y_range; s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min; s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED; s->options_list[OPT_BR_X].unit = SANE_UNIT_MM; s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BR_X].constraint.range = &x_range; s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max; s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED; s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM; s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BR_Y].constraint.range = &y_range; s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max; s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST; s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; s->options_list[OPT_CONTRAST].type = SANE_TYPE_FIXED; s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE; s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_CONTRAST].constraint.range = &contrast_range; s->value[OPT_CONTRAST].w = SANE_FIX (3.5); s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT; s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BRIGHTNESS].constraint.range = &brightness_range; s->value[OPT_BRIGHTNESS].w = 1800; s->options_list[OPT_LAMP_TIMEOUT].name = "lamp-timeout"; s->options_list[OPT_LAMP_TIMEOUT].title = SANE_I18N ("Lamp timeout"); s->options_list[OPT_LAMP_TIMEOUT].desc = SANE_I18N ("Minutes until lamp is turned off after scan"); s->options_list[OPT_LAMP_TIMEOUT].type = SANE_TYPE_INT; s->options_list[OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE; s->options_list[OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_LAMP_TIMEOUT].constraint.range = &lamp_range; s->value[OPT_LAMP_TIMEOUT].w = 15; } /*--------------------------------------------------------------------------*/ 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; } sane-backends-1.0.15/backend/sm3840.conf100666 0 0 164 10215442415 15716 0ustar usergroup# usb vendor product # Microtek ScanMaker 3840 ID usb 0x05da 0x30d4 # Microrek ScanMaker 4800 ID usb 0x05da 0x30cf sane-backends-1.0.15/backend/sm3840.c~100666 0 0 53306 10215442357 15464 0ustar usergroup/* 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_sm_device (SANE_String_Const devname, SANE_String_Const modname) { SM3840_Device *dev; dev = calloc (sizeof (*dev), 1); if (!dev) return (SANE_STATUS_NO_MEM); memset (dev, 0, sizeof (*dev)); dev->sane.name = strdup (devname); dev->sane.model = modname; dev->sane.vendor = "Microtek"; dev->sane.type = "flatbed scanner"; ++num_devices; dev->next = first_dev; first_dev = dev; return (SANE_STATUS_GOOD); } static SANE_Status add_sm3840_device (SANE_String_Const devname) { return add_dm_device (devname, "ScanMaker 3840"); } static SANE_Status add_sm4800_device (SANE_String_Const devname) { return add_dm_device (devname, "ScanMaker 4800"); } /*--------------------------------------------------------------------------*/ SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) { static const SANE_Device **devlist = 0; SM3840_Device *dev; int i; DBG (3, "sane_get_devices (local_only = %d)\n", local_only); while (first_dev) { dev = first_dev->next; free (first_dev); first_dev = dev; } first_dev = NULL; num_devices = 0; // If we get enough scanners should use an array, but for now // do it one-by-one... sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_device); sanei_usb_find_devices (0x05da, 0x30cf, add_sm4800_device); if (devlist) free (devlist); devlist = calloc ((num_devices + 1) * sizeof (devlist[0]), 1); if (!devlist) return SANE_STATUS_NO_MEM; i = 0; for (dev = first_dev; i < num_devices; dev = dev->next) devlist[i++] = &dev->sane; devlist[i++] = 0; if (device_list) *device_list = devlist; return (SANE_STATUS_GOOD); } /*--------------------------------------------------------------------------*/ static size_t max_string_size (const SANE_String_Const strings[]) { size_t size, max_size = 0; int i; for (i = 0; strings[i]; ++i) { size = strlen (strings[i]) + 1; if (size > max_size) max_size = size; } return (max_size); } /*--------------------------------------------------------------------------*/ static void initialize_options_list (SM3840_Scan * s) { SANE_Int option; DBG (2, "initialize_options_list\n"); for (option = 0; option < NUM_OPTIONS; ++option) { s->options_list[option].size = sizeof (SANE_Word); s->options_list[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT; s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE; s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word); s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE; s->value[OPT_NUM_OPTS].w = NUM_OPTIONS; s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE; s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE; s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE; s->options_list[OPT_MODE].type = SANE_TYPE_STRING; s->options_list[OPT_MODE].size = max_string_size (mode_list); s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; s->options_list[OPT_MODE].constraint.string_list = mode_list; s->value[OPT_MODE].s = strdup (mode_list[1]); s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT; s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI; s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list; s->value[OPT_RESOLUTION].w = 300; s->options_list[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; s->options_list[OPT_BIT_DEPTH].type = SANE_TYPE_INT; s->options_list[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE; s->options_list[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; s->options_list[OPT_BIT_DEPTH].constraint.word_list = bpp_list; s->value[OPT_BIT_DEPTH].w = 8; s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED; s->options_list[OPT_TL_X].unit = SANE_UNIT_MM; s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_TL_X].constraint.range = &x_range; s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min; s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED; s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM; s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_TL_Y].constraint.range = &y_range; s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min; s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED; s->options_list[OPT_BR_X].unit = SANE_UNIT_MM; s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BR_X].constraint.range = &x_range; s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max; s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED; s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM; s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BR_Y].constraint.range = &y_range; s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max; s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST; s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; s->options_list[OPT_CONTRAST].type = SANE_TYPE_FIXED; s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE; s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_CONTRAST].constraint.range = &contrast_range; s->value[OPT_CONTRAST].w = SANE_FIX (3.5); s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT; s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_BRIGHTNESS].constraint.range = &brightness_range; s->value[OPT_BRIGHTNESS].w = 1800; s->options_list[OPT_LAMP_TIMEOUT].name = "lamp-timeout"; s->options_list[OPT_LAMP_TIMEOUT].title = SANE_I18N ("Lamp timeout"); s->options_list[OPT_LAMP_TIMEOUT].desc = SANE_I18N ("Minutes until lamp is turned off after scan"); s->options_list[OPT_LAMP_TIMEOUT].type = SANE_TYPE_INT; s->options_list[OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE; s->options_list[OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE; s->options_list[OPT_LAMP_TIMEOUT].constraint.range = &lamp_range; s->value[OPT_LAMP_TIMEOUT].w = 15; } /*--------------------------------------------------------------------------*/ 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; } sane-backends-1.0.15/backend/sm3840.h100666 0 0 6454 10172572231 15252 0ustar usergroup/* 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 */ sane-backends-1.0.15/backend/sm3840_lib.c100666 0 0 61230 10201500055 16070 0ustar usergroup/* 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); } sane-backends-1.0.15/backend/sm3840_lib.h100666 0 0 12261 10201477531 16111 0ustar usergroup/* 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 sane-backends-1.0.15/backend/sm3840_params.h100666 0 0 4534 10172572231 16612 0ustar usergroup/* 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 sane-backends-1.0.15/backend/sm3840_scan.c100666 0 0 104702 10217415001 16273 0ustar usergroup/* 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 == NULL) udev = find_device (0x05da, 0x30cf); 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; unsigned short GRAYMASK = 0xc000; #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); fix_endian_short (whitebalance, whitebalancesize/2); 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); fix_endian_short (whitebalance, whitebalancesize/2); 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); fix_endian_short (whitescan, (5632 * 2 * 3 * (dpi == 1200 ? 2 : 1)) * 2); 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); fix_endian_short (&GRAYMASK, 1); if (gray) for (i = 0; i < whitemapsize / 2; i++) lightmap[i] |= GRAYMASK; 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 } sane-backends-1.0.15/doc/ 40777 0 0 0 10220424765 13215 5ustar usergroupsane-backends-1.0.15/doc/descriptions/ 40777 0 0 0 10220424765 15723 5ustar usergroupsane-backends-1.0.15/doc/descriptions/sm3840.desc100666 0 0 4235 10215443177 17624 0ustar usergroup; ; 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.1" ; version of backend (or "unmaintained") :new :yes ; Is the backend new to this SANE release? ; :yes or :no :manpage "sane-template" ; 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 :model "ScanMaker 4800" :status :good :interface "USB" :comment "Possible PPC endianness issues" ; :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 sane-backends-1.0.15/doc/sane-sm3840.man100666 0 0 4401 10215443457 15673 0ustar usergroup.TH sane-sm3840 5 "Mar 15, 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 .br Microtek ScanMaker 4800 Intel OK, PPC problems? .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