kopia lustrzana https://gitlab.com/sane-project/backends
846 wiersze
24 KiB
C
Executable File
846 wiersze
24 KiB
C
Executable File
/* sane - Scanner Access Now Easy.
|
|
|
|
ScanMaker 3840 Backend
|
|
Copyright (C) 2005-7 Earle F. Philhower, III
|
|
earle@ziplabel.com - http://www.ziplabel.com
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
to produce an executable, this does not by itself cause the
|
|
resulting executable to be covered by the GNU General Public
|
|
License. Your use of that executable is in no way restricted on
|
|
account of linking the SANE library code into it.
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
the executable file might be covered by the GNU General Public
|
|
License.
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
a subsequent release, you agree by submitting the changes that
|
|
those changes may be distributed with this exception intact.
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
whether to permit this exception to apply to your modifications.
|
|
If you do not wish that, delete this exception notice.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "../include/sane/config.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/saneopts.h"
|
|
|
|
#define BACKENDNAME sm3840
|
|
#include "../include/sane/sanei_backend.h"
|
|
#include "../include/sane/sanei_usb.h"
|
|
#include "../include/sane/sanei_config.h"
|
|
|
|
#include "sm3840.h"
|
|
|
|
#include "sm3840_scan.c"
|
|
#include "sm3840_lib.c"
|
|
|
|
static double sm3840_unit_convert (SANE_Int val);
|
|
|
|
static int num_devices;
|
|
static SM3840_Device *first_dev;
|
|
static SM3840_Scan *first_handle;
|
|
static const SANE_Device **devlist = 0;
|
|
|
|
static const SANE_String_Const mode_list[] = {
|
|
SANE_I18N ("Gray"), SANE_I18N ("Color"),
|
|
SANE_I18N ("Lineart"), SANE_I18N ("Halftone"),
|
|
0
|
|
};
|
|
|
|
static const SANE_Word resolution_list[] = {
|
|
4, 1200, 600, 300, 150
|
|
};
|
|
|
|
static const SANE_Word bpp_list[] = {
|
|
2, 8, 16
|
|
};
|
|
|
|
static const SANE_Range x_range = {
|
|
SANE_FIX (0),
|
|
SANE_FIX (215.91), /* 8.5 inches */
|
|
SANE_FIX (0)
|
|
};
|
|
|
|
static const SANE_Range y_range = {
|
|
SANE_FIX (0),
|
|
SANE_FIX (297.19), /* 11.7 inches */
|
|
SANE_FIX (0)
|
|
};
|
|
|
|
static const SANE_Range brightness_range = {
|
|
1,
|
|
4096,
|
|
1.0
|
|
};
|
|
|
|
static const SANE_Range contrast_range = {
|
|
SANE_FIX (0.1),
|
|
SANE_FIX (9.9),
|
|
SANE_FIX (0.1)
|
|
};
|
|
|
|
static const SANE_Range lamp_range = {
|
|
1,
|
|
15,
|
|
1
|
|
};
|
|
|
|
static const SANE_Range threshold_range = {
|
|
0,
|
|
255,
|
|
1
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int
|
|
min (int a, int b)
|
|
{
|
|
if (a < b)
|
|
return a;
|
|
else
|
|
return b;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
|
|
SANE_Int * len)
|
|
{
|
|
SM3840_Scan *s = handle;
|
|
unsigned char c, d;
|
|
int i;
|
|
|
|
DBG (2, "+sane-read:%p %p %d %p\n", (unsigned char *) s, buf, max_len,
|
|
(unsigned char *) len);
|
|
DBG (2,
|
|
"+sane-read:remain:%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--;
|
|
}
|
|
|
|
/* Need to software emulate 1-bpp modes, simple threshold and error */
|
|
/* diffusion dither implemented. */
|
|
if (s->sm3840_params.lineart || s->sm3840_params.halftone)
|
|
{
|
|
d = 0;
|
|
for (i = 0; i < min (max_len * 8, s->remaining); i++)
|
|
{
|
|
d = d << 1;
|
|
if (s->sm3840_params.halftone)
|
|
{
|
|
c = (*(unsigned char *) (s->offset + s->line_buffer + i));
|
|
if (c + s->save_dither_err < 128)
|
|
{
|
|
d |= 1;
|
|
s->save_dither_err += c;
|
|
}
|
|
else
|
|
{
|
|
s->save_dither_err += c - 255;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((*(unsigned char *) (s->offset + s->line_buffer + i)) < s->threshold )
|
|
d |= 1;
|
|
}
|
|
if (i % 8 == 7)
|
|
*(buf++) = d;
|
|
}
|
|
*len = i / 8;
|
|
s->offset += i;
|
|
s->remaining -= i;
|
|
}
|
|
else
|
|
{
|
|
memcpy (buf, s->offset + s->line_buffer, min (max_len, s->remaining));
|
|
*len = min (max_len, s->remaining);
|
|
s->offset += min (max_len, s->remaining);
|
|
s->remaining -= min (max_len, s->remaining);
|
|
}
|
|
|
|
DBG (2, "-sane_read\n");
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void
|
|
sane_cancel (SANE_Handle h)
|
|
{
|
|
SM3840_Scan *s = h;
|
|
|
|
DBG (2, "trying to cancel...\n");
|
|
if (s->scanning)
|
|
{
|
|
if (!s->cancelled)
|
|
{
|
|
/* Move to home position */
|
|
reset_scanner ((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;
|
|
|
|
s->save_dither_err = 0;
|
|
s->threshold = s->sm3840_params.threshold;
|
|
|
|
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.halftone =
|
|
(!strcasecmp (s->value[OPT_MODE].s, SANE_I18N ("Halftone"))) ? 1 : 0;
|
|
s->sm3840_params.lineart =
|
|
(!strcasecmp (s->value[OPT_MODE].s, SANE_I18N ("Lineart"))) ? 1 : 0;
|
|
|
|
s->sm3840_params.dpi = s->value[OPT_RESOLUTION].w;
|
|
s->sm3840_params.bpp = s->value[OPT_BIT_DEPTH].w;
|
|
s->sm3840_params.gain = SANE_UNFIX (s->value[OPT_CONTRAST].w);
|
|
s->sm3840_params.offset = s->value[OPT_BRIGHTNESS].w;
|
|
s->sm3840_params.lamp = s->value[OPT_LAMP_TIMEOUT].w;
|
|
s->sm3840_params.threshold = s->value[OPT_THRESHOLD].w;
|
|
|
|
if (s->sm3840_params.lineart || s->sm3840_params.halftone)
|
|
{
|
|
s->sm3840_params.gray = 1;
|
|
s->sm3840_params.bpp = 8;
|
|
}
|
|
|
|
s->sm3840_params.top = sm3840_unit_convert (s->value[OPT_TL_Y].w);
|
|
s->sm3840_params.left = sm3840_unit_convert (s->value[OPT_TL_X].w);
|
|
s->sm3840_params.width =
|
|
sm3840_unit_convert (s->value[OPT_BR_X].w) - s->sm3840_params.left;
|
|
s->sm3840_params.height =
|
|
sm3840_unit_convert (s->value[OPT_BR_Y].w) - s->sm3840_params.top;
|
|
|
|
/* Legalize and calculate pixel sizes */
|
|
prepare_params (&(s->sm3840_params));
|
|
|
|
/* Copy into sane_params */
|
|
s->sane_params.pixels_per_line = s->sm3840_params.scanpix;
|
|
s->sane_params.lines = s->sm3840_params.scanlines;
|
|
s->sane_params.format =
|
|
s->sm3840_params.gray ? SANE_FRAME_GRAY : SANE_FRAME_RGB;
|
|
s->sane_params.bytes_per_line = s->sm3840_params.linelen;
|
|
s->sane_params.depth = s->sm3840_params.bpp;
|
|
|
|
if (s->sm3840_params.lineart || s->sm3840_params.halftone)
|
|
{
|
|
s->sane_params.bytes_per_line += 7;
|
|
s->sane_params.bytes_per_line /= 8;
|
|
s->sane_params.depth = 1;
|
|
s->sane_params.pixels_per_line = s->sane_params.bytes_per_line * 8;
|
|
}
|
|
|
|
s->sane_params.last_frame = SANE_TRUE;
|
|
} /*!scanning */
|
|
|
|
if (params)
|
|
*params = s->sane_params;
|
|
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_control_option (SANE_Handle handle, SANE_Int option,
|
|
SANE_Action action, void *val, SANE_Int * info)
|
|
{
|
|
SM3840_Scan *s = handle;
|
|
SANE_Status status = 0;
|
|
SANE_Word cap;
|
|
DBG (2, "sane_control_option\n");
|
|
if (info)
|
|
*info = 0;
|
|
if (s->scanning)
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
if (option >= NUM_OPTIONS)
|
|
return SANE_STATUS_INVAL;
|
|
cap = s->options_list[option].cap;
|
|
if (!SANE_OPTION_IS_ACTIVE (cap))
|
|
return SANE_STATUS_INVAL;
|
|
if (action == SANE_ACTION_GET_VALUE)
|
|
{
|
|
DBG (1, "sane_control_option %d, get value\n", option);
|
|
switch (option)
|
|
{
|
|
/* word options: */
|
|
case OPT_RESOLUTION:
|
|
case OPT_BIT_DEPTH:
|
|
case OPT_TL_X:
|
|
case OPT_TL_Y:
|
|
case OPT_BR_X:
|
|
case OPT_BR_Y:
|
|
case OPT_NUM_OPTS:
|
|
case OPT_CONTRAST:
|
|
case OPT_BRIGHTNESS:
|
|
case OPT_LAMP_TIMEOUT:
|
|
case OPT_THRESHOLD:
|
|
*(SANE_Word *) val = s->value[option].w;
|
|
return (SANE_STATUS_GOOD);
|
|
/* string options: */
|
|
case OPT_MODE:
|
|
strcpy (val, s->value[option].s);
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
else if (action == SANE_ACTION_SET_VALUE)
|
|
{
|
|
DBG (1, "sane_control_option %d, set value\n", option);
|
|
if (!SANE_OPTION_IS_SETTABLE (cap))
|
|
return (SANE_STATUS_INVAL);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return (status);
|
|
status = sanei_constrain_value (s->options_list + option, val, info);
|
|
switch (option)
|
|
{
|
|
/* (mostly) side-effect-free word options: */
|
|
case OPT_RESOLUTION:
|
|
case OPT_BIT_DEPTH:
|
|
case OPT_BR_X:
|
|
case OPT_BR_Y:
|
|
case OPT_TL_X:
|
|
case OPT_TL_Y:
|
|
if (info)
|
|
*info |= SANE_INFO_RELOAD_PARAMS;
|
|
/* fall through */
|
|
case OPT_NUM_OPTS:
|
|
case OPT_CONTRAST:
|
|
case OPT_BRIGHTNESS:
|
|
case OPT_LAMP_TIMEOUT:
|
|
case OPT_THRESHOLD:
|
|
s->value[option].w = *(SANE_Word *) val;
|
|
return (SANE_STATUS_GOOD);
|
|
case OPT_MODE:
|
|
if (s->value[option].s)
|
|
free (s->value[option].s);
|
|
s->value[option].s = strdup (val);
|
|
|
|
if (info)
|
|
*info |= SANE_INFO_RELOAD_PARAMS;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
const SANE_Option_Descriptor *
|
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
|
{
|
|
SM3840_Scan *s = handle;
|
|
DBG (2, "sane_get_option_descriptor\n");
|
|
if ((unsigned) option >= NUM_OPTIONS)
|
|
return (0);
|
|
return (&s->options_list[option]);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
sane_close (SANE_Handle handle)
|
|
{
|
|
SM3840_Scan *prev, *s;
|
|
|
|
DBG (2, "sane_close\n");
|
|
/* remove handle from list of open handles: */
|
|
prev = 0;
|
|
for (s = first_handle; s; s = s->next)
|
|
{
|
|
if (s == handle)
|
|
break;
|
|
prev = s;
|
|
}
|
|
if (!s)
|
|
{
|
|
DBG (1, "close: invalid handle %p\n", handle);
|
|
return; /* oops, not a handle we know about */
|
|
}
|
|
|
|
if (s->scanning)
|
|
{
|
|
sane_cancel (handle);
|
|
}
|
|
|
|
sanei_usb_close (s->udev);
|
|
|
|
if (s->line_buffer)
|
|
free (s->line_buffer);
|
|
if (s->save_scan_line)
|
|
free (s->save_scan_line);
|
|
if (s->save_dpi1200_remap)
|
|
free (s->save_dpi1200_remap);
|
|
if (s->save_color_remap)
|
|
free (s->save_color_remap);
|
|
|
|
if (prev)
|
|
prev->next = s->next;
|
|
else
|
|
first_handle = s;
|
|
free (handle);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void
|
|
sane_exit (void)
|
|
{
|
|
SM3840_Device *next;
|
|
DBG (2, "sane_exit\n");
|
|
while (first_dev != NULL)
|
|
{
|
|
next = first_dev->next;
|
|
free (first_dev);
|
|
first_dev = next;
|
|
}
|
|
if (devlist)
|
|
free (devlist);
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|
{
|
|
DBG_INIT ();
|
|
if (version_code)
|
|
*version_code = SANE_VERSION_CODE (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;
|
|
|
|
s->options_list[OPT_THRESHOLD].name = "threshold";
|
|
s->options_list[OPT_THRESHOLD].title = SANE_I18N ("Threshold");
|
|
s->options_list[OPT_THRESHOLD].desc =
|
|
SANE_I18N ("Threshold value for lineart mode");
|
|
s->options_list[OPT_THRESHOLD].type = SANE_TYPE_INT;
|
|
s->options_list[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
|
|
s->options_list[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_THRESHOLD].constraint.range = &threshold_range;
|
|
s->value[OPT_THRESHOLD].w = 128;
|
|
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|
{
|
|
SANE_Status status;
|
|
SM3840_Device *dev;
|
|
SM3840_Scan *s;
|
|
DBG (2, "sane_open\n");
|
|
|
|
/* Make sure we have first_dev */
|
|
sane_get_devices (NULL, 0);
|
|
if (devicename[0])
|
|
{
|
|
for (dev = first_dev; dev; dev = dev->next)
|
|
if (strcmp (dev->sane.name, devicename) == 0)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* empty devicename -> use first device */
|
|
dev = first_dev;
|
|
}
|
|
DBG (2, "using device: %s %p\n", dev->sane.name, (unsigned char *) dev);
|
|
if (!dev)
|
|
return SANE_STATUS_INVAL;
|
|
s = calloc (sizeof (*s), 1);
|
|
if (!s)
|
|
return SANE_STATUS_NO_MEM;
|
|
|
|
s->udev = 0;
|
|
status = sanei_usb_open (dev->sane.name, &(s->udev));
|
|
if (!s->udev)
|
|
return SANE_STATUS_ACCESS_DENIED;
|
|
|
|
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;
|
|
}
|