kopia lustrzana https://gitlab.com/sane-project/backends
5542 wiersze
204 KiB
C
5542 wiersze
204 KiB
C
![]() |
/* --------------------------------------------------------------------------------------------------------- */
|
||
|
|
||
|
/* sane - Scanner Access Now Easy.
|
||
|
|
||
|
umax.c
|
||
|
|
||
|
(C) 1997-1999 Oliver Rauch
|
||
|
|
||
|
This file is part of the SANE package.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License as
|
||
|
published by the Free Software Foundation; either version 2 of the
|
||
|
License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||
|
MA 02111-1307, USA.
|
||
|
|
||
|
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.
|
||
|
|
||
|
This file implements a SANE backend for UMAX flatbed scanners. */
|
||
|
|
||
|
|
||
|
/* --------------------------------------------------------------------------------------------------------- */
|
||
|
|
||
|
#define BUILD 3
|
||
|
|
||
|
/* --------------------------------------------------------------------------------------------------------- */
|
||
|
|
||
|
|
||
|
/* SANE-FLOW-DIAGRAMM
|
||
|
|
||
|
- sane_init() : initialize backend, attach scanners(devicename,0)
|
||
|
. - sane_get_devices() : query list of scanner-devices
|
||
|
. - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev)
|
||
|
. . - sane_set_io_mode : set blocking-mode
|
||
|
. . - sane_get_select_fd : get scanner-fd
|
||
|
. . - sane_get_option_descriptor() : get option informations
|
||
|
. . - sane_control_option() : change option values
|
||
|
. .
|
||
|
. . - sane_start() : start image aquisition
|
||
|
. . - sane_get_parameters() : returns actual scan-parameters
|
||
|
. . - sane_read() : read image-data (from pipe)
|
||
|
. . - sane_cancel() : cancel operation, kill reader_process
|
||
|
|
||
|
. - sane_close() : close opened scanner-device, do_cancel, free buffer and handle
|
||
|
- sane_exit() : terminate use of backend, free devicename and device-struture
|
||
|
*/
|
||
|
|
||
|
/* ------------------------------------------------------------ COMPILER OPTIONS --------------------------- */
|
||
|
|
||
|
|
||
|
/* #define SANE_UMAX_DEBUG_S12 */
|
||
|
#define UMAX_HIDE_UNUSED
|
||
|
/* #define PREVIEW_FIX_ON */
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ DBG OUTPUT LEVELS -------------------------- */
|
||
|
|
||
|
|
||
|
#define DBG_error0 0
|
||
|
#define DBG_error 1
|
||
|
#define DBG_sense 2
|
||
|
#define DBG_warning 3
|
||
|
#define DBG_inquiry 4
|
||
|
#define DBG_info 5
|
||
|
#define DBG_info2 6
|
||
|
#define DBG_proc 7
|
||
|
#define DBG_read 8
|
||
|
#define DBG_sane_init 10
|
||
|
#define DBG_sane_proc 11
|
||
|
#define DBG_sane_info 12
|
||
|
#define DBG_sane_option 13
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE DEFINES ------------------------------- */
|
||
|
|
||
|
#define BACKEND_NAME umax
|
||
|
#define UMAX_CONFIG_FILE "umax.conf"
|
||
|
#define MM_PER_INCH 25.4
|
||
|
|
||
|
/* ------------------------------------------------------------ INCLUDES ----------------------------------- */
|
||
|
|
||
|
#include <sane/config.h>
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <limits.h>
|
||
|
#include <signal.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "sane/sane.h"
|
||
|
#include "sane/sanei.h"
|
||
|
#include "sane/saneopts.h"
|
||
|
#include "sane/sanei_scsi.h"
|
||
|
#include "sane/sanei_debug.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <math.h>
|
||
|
#include <getopt.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "umax-scsidef.h"
|
||
|
#include "umax-scanner.h"
|
||
|
|
||
|
#include "umax.h"
|
||
|
#include "sane/sanei_backend.h"
|
||
|
#include "sane/sanei_config.h"
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE DEFINES ------------------------------- */
|
||
|
|
||
|
#ifndef PATH_MAX
|
||
|
#define PATH_MAX 1024
|
||
|
#endif
|
||
|
|
||
|
/* ------------------------------------------------------------ STRINGDEFINITIONS -------------------------- */
|
||
|
|
||
|
#define FLB_STR "Flatbed"
|
||
|
#define UTA_STR "Transparency Adapter"
|
||
|
#define ADF_STR "Automatic Document Feeder"
|
||
|
|
||
|
#define LINEART_STR "Lineart"
|
||
|
#define HALFTONE_STR "Halftone"
|
||
|
#define GRAY_STR "Gray"
|
||
|
#define COLOR_LINEART_STR "Color Lineart"
|
||
|
#define COLOR_HALFTONE_STR "Color Halftone"
|
||
|
#define COLOR_STR "Color"
|
||
|
|
||
|
#define CALIB_MODE_0000 "Use Image Composition"
|
||
|
#define CALIB_MODE_1111 "Bi-level black and white (lineart mode)"
|
||
|
#define CALIB_MODE_1110 "Dithered/halftone black & white (halftone mode)"
|
||
|
#define CALIB_MODE_1101 "Multi-level black & white (grayscale mode)"
|
||
|
#define CALIB_MODE_1010 "Multi-level RGB color (one pass color)"
|
||
|
#define CALIB_MODE_1001 "ignore calibration"
|
||
|
|
||
|
#define SHADING_TYPE_ONE_LINE_TEXT "use one shading line"
|
||
|
#define SHADING_TYPE_AVERAGE_TEXT "calculate average"
|
||
|
#define SHADING_TYPE_ONE_LINE_INVERT_TEXT "use one shading line and invert"
|
||
|
#define SHADING_TYPE_AVERAGE_INVERT_TEXT "calculate average and invert"
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ DEFINITIONS -------------------------------- */
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
SHADING_TYPE_ONE_LINE = 0,
|
||
|
SHADING_TYPE_AVERAGE,
|
||
|
SHADING_TYPE_ONE_LINE_INVERT,
|
||
|
SHADING_TYPE_AVERAGE_INVERT,
|
||
|
};
|
||
|
|
||
|
/* ------------------------------------------------------------ DEFINITIONS -------------------------------- */
|
||
|
|
||
|
#define P_200_TO_255(per) SANE_UNFIX((per + 100) * 255/200 )
|
||
|
#define P_100_TO_255(per) SANE_UNFIX(per * 255/100 )
|
||
|
#define P_100_TO_254(per) 1+SANE_UNFIX(per * 254/100 )
|
||
|
|
||
|
/* ------------------------------------------------------------ GLOBAL VARIABLES --------------------------- */
|
||
|
|
||
|
|
||
|
static SANE_String_Const scan_mode_list[7];
|
||
|
static SANE_String_Const source_list[4];
|
||
|
static SANE_Int bit_depth_list[9];
|
||
|
|
||
|
static SANE_String_Const calibration_list[] =
|
||
|
{
|
||
|
CALIB_MODE_0000,
|
||
|
CALIB_MODE_1111,
|
||
|
CALIB_MODE_1110,
|
||
|
CALIB_MODE_1101,
|
||
|
CALIB_MODE_1010,
|
||
|
CALIB_MODE_1001,
|
||
|
0
|
||
|
};
|
||
|
|
||
|
static SANE_String_Const shading_list[] =
|
||
|
{
|
||
|
SHADING_TYPE_ONE_LINE_TEXT,
|
||
|
SHADING_TYPE_AVERAGE_TEXT,
|
||
|
SHADING_TYPE_ONE_LINE_INVERT_TEXT,
|
||
|
SHADING_TYPE_AVERAGE_INVERT_TEXT,
|
||
|
0
|
||
|
};
|
||
|
|
||
|
static const SANE_Int pattern_dim_list[] =
|
||
|
{
|
||
|
8, /* # of elements */
|
||
|
0, 2, 3, 4, 5, 6, 7, 8
|
||
|
};
|
||
|
|
||
|
static const SANE_Range u8_range =
|
||
|
{
|
||
|
0, /* minimum */
|
||
|
255, /* maximum */
|
||
|
0 /* quantization */
|
||
|
};
|
||
|
|
||
|
static const SANE_Range percentage_range =
|
||
|
{
|
||
|
-100 << SANE_FIXED_SCALE_SHIFT, /* minimum */
|
||
|
100 << SANE_FIXED_SCALE_SHIFT, /* maximum */
|
||
|
1 << SANE_FIXED_SCALE_SHIFT /* quantization */
|
||
|
};
|
||
|
|
||
|
static const SANE_Range percentage_range_100 =
|
||
|
{
|
||
|
0 << SANE_FIXED_SCALE_SHIFT, /* minimum */
|
||
|
100 << SANE_FIXED_SCALE_SHIFT, /* maximum */
|
||
|
0 << SANE_FIXED_SCALE_SHIFT /* quantization */
|
||
|
};
|
||
|
|
||
|
static int num_devices;
|
||
|
static Umax_Device *first_dev;
|
||
|
static Umax_Scanner *first_handle;
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ MATH-HELPERS ------------------------------- */
|
||
|
|
||
|
|
||
|
#define min(a,b) (((a)<(b))?(a):(b))
|
||
|
#define max(a,b) (((a)>(b))?(a):(b))
|
||
|
#define inrange(minimum, val, maximum) (min(maximum,max(val,minimum)))
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ umax_test_little_endian -------------------- */
|
||
|
|
||
|
static SANE_Bool umax_test_little_endian()
|
||
|
{
|
||
|
SANE_Int testvalue = 255;
|
||
|
unsigned char *firstbyte = (char *) &testvalue;
|
||
|
|
||
|
if (*firstbyte == 255)
|
||
|
{
|
||
|
return SANE_TRUE;
|
||
|
}
|
||
|
|
||
|
return SANE_FALSE;
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------ DBG_inq_nz --------------------------------- */
|
||
|
|
||
|
|
||
|
static void DBG_inq_nz(char *text, int flag)
|
||
|
{
|
||
|
if (flag != 0) { DBG(DBG_inquiry,"%s",text); }
|
||
|
}
|
||
|
|
||
|
|
||
|
/*------------------------------------------------------------- DBG_sense_nz ------------------------------- */
|
||
|
|
||
|
|
||
|
static void DBG_sense_nz(char *text, int flag)
|
||
|
{
|
||
|
if (flag != 0) { DBG(DBG_sense,"%s",text); }
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX PRINT INQUIRY ------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_print_inquiry(Umax_Device *dev)
|
||
|
{
|
||
|
unsigned char * inquiry_block;
|
||
|
|
||
|
inquiry_block=dev->buffer;
|
||
|
|
||
|
DBG(DBG_inquiry,"INQUIRY:\n");
|
||
|
DBG(DBG_inquiry,"========\n");
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"vendor........................: '%s'\n",dev->vendor);
|
||
|
DBG(DBG_inquiry,"product.......................: '%s'\n",dev->product);
|
||
|
DBG(DBG_inquiry,"version.......................: '%s'\n",dev->version);
|
||
|
|
||
|
DBG_inq_nz("RMB bit set (reserved)\n", get_inquiry_rmb(inquiry_block));
|
||
|
DBG_inq_nz("0x01 bit 6\n", get_inquiry_0x01_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x01 bit 5\n", get_inquiry_0x01_bit5(inquiry_block));
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"CBHS value range..............: %s\n", cbhs_str[dev->inquiry_cbhs]);
|
||
|
DBG(DBG_inquiry,"scanmode......................: %s\n", scanmode_str[get_inquiry_scanmode(inquiry_block)]);
|
||
|
if (dev->inquiry_transavail)
|
||
|
{
|
||
|
DBG(DBG_inquiry,"UTA (transparency)............: available\n");
|
||
|
|
||
|
if (get_inquiry_translamp(inquiry_block) == 0)
|
||
|
{ DBG(DBG_inquiry,"UTA lamp status ..............: false\n"); }
|
||
|
else
|
||
|
{ DBG(DBG_inquiry,"UTA lamp status ..............: true\n"); }
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
}
|
||
|
|
||
|
DBG(DBG_inquiry,"inquiry block length..........: %d bytes\n",dev->inquiry_len);
|
||
|
if (dev->inquiry_len<=0x8e)
|
||
|
{
|
||
|
DBG(DBG_inquiry, "Inquiry block is unexpected short, should be at least 147 bytes\n");
|
||
|
}
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"ISO Version (reserved).......: %d\n", get_inquiry_iso_version(inquiry_block));
|
||
|
DBG(DBG_inquiry,"ECMA Version (reserved).......: %d\n", get_inquiry_ecma_version(inquiry_block));
|
||
|
DBG(DBG_inquiry,"ANSI Version .................: %d\n", get_inquiry_ansi_version(inquiry_block));
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
DBG_inq_nz("AENC bit set (reserved)\n", get_inquiry_aenc(inquiry_block));
|
||
|
DBG_inq_nz("TmIOP bit set (reserved)\n", get_inquiry_tmiop(inquiry_block));
|
||
|
DBG_inq_nz("0x03 bit 5\n", get_inquiry_0x03_bit5(inquiry_block));
|
||
|
DBG_inq_nz("0x03 bit 4\n", get_inquiry_0x03_bit4(inquiry_block));
|
||
|
|
||
|
DBG(DBG_inquiry,"reserved byte 0x05 = %d\n",get_inquiry_0x05(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x06 = %d\n",get_inquiry_0x06(inquiry_block));
|
||
|
|
||
|
DBG_inq_nz("0x07 bit 7\n", get_inquiry_0x07_bit7(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 6\n", get_inquiry_0x07_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 5\n", get_inquiry_0x07_bit5(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 4\n", get_inquiry_0x07_bit4(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 3\n", get_inquiry_0x07_bit3(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 2\n", get_inquiry_0x07_bit2(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 1\n", get_inquiry_0x07_bit1(inquiry_block));
|
||
|
DBG_inq_nz("0x07 bit 0\n", get_inquiry_0x07_bit0(inquiry_block));
|
||
|
|
||
|
/* 0x24 */
|
||
|
if (dev->inquiry_len<=0x24) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"f/w support function:\n");
|
||
|
DBG(DBG_inquiry,"---------------------\n");
|
||
|
DBG_inq_nz(" - quality calibration\n", dev->inquiry_quality_ctrl);
|
||
|
DBG_inq_nz(" - fast preview function\n", dev->inquiry_preview);
|
||
|
DBG_inq_nz(" - shadow compensation by f/w\n", get_inquiry_fw_shadow_comp(inquiry_block));
|
||
|
DBG_inq_nz(" - reselection phase\n", get_inquiry_fw_reselection(inquiry_block));
|
||
|
DBG_inq_nz(" - lamp intensity control\n", dev->inquiry_lamp_ctrl);
|
||
|
DBG_inq_nz(" - batch scan function\n", get_inquiry_fw_batch_scan(inquiry_block));
|
||
|
DBG_inq_nz(" - calibration mode control by driver\n", get_inquiry_fw_calibration(inquiry_block));
|
||
|
|
||
|
/* 0x36, 0x37 */
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x36 = %d\n",get_inquiry_0x36(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x37 = %d\n",get_inquiry_0x37(inquiry_block));
|
||
|
|
||
|
if (get_inquiry_fw_adjust_exposure_tf(inquiry_block))
|
||
|
{
|
||
|
int unit;
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"adjust exposure time function\n");
|
||
|
unit=get_inquiry_exposure_time_step_unit(inquiry_block);
|
||
|
DBG(DBG_inquiry,"exposure time step units......: %d micro-sec\n",unit);
|
||
|
DBG(DBG_inquiry,"exposure time maximum.........: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_step_unit(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time minimum (LHG)...: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_lhg_min(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time minimum color...: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_color_min(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default FB (LH).: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_lh_def_fb(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default UTA (LH): %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_lh_def_uta(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default FB gray.: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_gray_def_fb(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default UTA gray: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_gray_def_uta(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default FB red..: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_r_fb(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default FB grn..: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_g_fb(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default FB blue.: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_b_fb(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default UTA red.: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_r_uta(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default UTA grn.: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_g_uta(inquiry_block));
|
||
|
DBG(DBG_inquiry,"exposure time default UTA blue: %d micro-sec\n",
|
||
|
unit*get_inquiry_exposure_time_def_b_uta(inquiry_block));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* 0x60 */
|
||
|
if (dev->inquiry_len<=0x60) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"scan modes:\n");
|
||
|
DBG(DBG_inquiry,"-----------\n");
|
||
|
DBG_inq_nz(" - three passes color mode\n", get_inquiry_sc_three_pass_color(inquiry_block));
|
||
|
DBG_inq_nz(" - single pass color mode\n", get_inquiry_sc_one_pass_color(inquiry_block));
|
||
|
DBG_inq_nz(" - lineart mode\n",dev->inquiry_lineart);
|
||
|
DBG_inq_nz(" - halftone mode\n",dev->inquiry_halftone);
|
||
|
DBG_inq_nz(" - gray mode\n",dev->inquiry_gray);
|
||
|
DBG_inq_nz(" - color mode\n",dev->inquiry_color);
|
||
|
DBG_inq_nz(" - transparency (UTA)\n",dev->inquiry_uta);
|
||
|
DBG_inq_nz(" - automatic document feeder (ADF)\n", dev->inquiry_adf);
|
||
|
|
||
|
/* 0x61 */
|
||
|
if (dev->inquiry_len<=0x61) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"scanner capability:\n");
|
||
|
DBG(DBG_inquiry,"-------------------\n");
|
||
|
DBG_inq_nz(" - double resolution\n", dev->inquiry_dor);
|
||
|
DBG_inq_nz(" - send high byte first\n", get_inquiry_sc_high_byte_first(inquiry_block));
|
||
|
DBG_inq_nz(" - bi-level image reverse\n", dev->inquiry_reverse);
|
||
|
DBG_inq_nz(" - multi-level image reverse\n", dev->inquiry_reverse_multi);
|
||
|
DBG_inq_nz(" - support shadow function\n", dev->inquiry_shadow);
|
||
|
DBG_inq_nz(" - support highlight function\n",dev->inquiry_highlight);
|
||
|
DBG_inq_nz(" - f/w downloadable\n", get_inquiry_sc_downloadable_fw(inquiry_block));
|
||
|
DBG_inq_nz(" - paper length can reach to 14 inch\n", get_inquiry_sc_paper_length_14(inquiry_block));
|
||
|
|
||
|
/* 0x62 */
|
||
|
if (dev->inquiry_len<=0x62) {return;}
|
||
|
DBG_inq_nz(" - shading data/gain uploadable\n", get_inquiry_sc_uploadable_shade(inquiry_block));
|
||
|
DBG_inq_nz(" - analog gamma correction\n", dev->inquiry_analog_gamma);
|
||
|
DBG_inq_nz(" - x,y coordinate base\n", get_inquiry_xy_coordinate_base(inquiry_block));
|
||
|
DBG_inq_nz("0x62 bit 4\n", get_inquiry_0x62_bit4(inquiry_block));
|
||
|
DBG_inq_nz("0x62 bit 5\n", get_inquiry_0x62_bit5(inquiry_block));
|
||
|
DBG_inq_nz("0x62 bit 6\n", get_inquiry_0x62_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x62 bit 7\n", get_inquiry_0x62_bit7(inquiry_block));
|
||
|
|
||
|
/* 0x63 */
|
||
|
if (dev->inquiry_len<=0x63) {return;}
|
||
|
DBG_inq_nz("ADF: no paper\n", get_inquiry_ADF_no_paper(inquiry_block));
|
||
|
DBG_inq_nz("ADF: cover open\n", get_inquiry_ADF_cover_open(inquiry_block));
|
||
|
DBG_inq_nz("ADF: paper jam\n", get_inquiry_ADF_paper_jam(inquiry_block));
|
||
|
DBG_inq_nz("0x63 bit 3\n", get_inquiry_0x63_bit3(inquiry_block));
|
||
|
DBG_inq_nz("0x63 bit 4\n", get_inquiry_0x63_bit4(inquiry_block));
|
||
|
DBG_inq_nz("0x63 bit 5\n", get_inquiry_0x63_bit5(inquiry_block));
|
||
|
DBG_inq_nz("0x63 bit 6\n", get_inquiry_0x63_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x63 bit 7\n", get_inquiry_0x63_bit7(inquiry_block));
|
||
|
|
||
|
/* 0x64 - 0x68*/
|
||
|
if (dev->inquiry_len<=0x68) {return;}
|
||
|
if (dev->inquiry_gamma_dwload)
|
||
|
{
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"gamma download available\n");
|
||
|
DBG_inq_nz("gamma download type 2\n", get_inquiry_gamma_type_2(inquiry_block));
|
||
|
DBG(DBG_inquiry,"lines of gamma curve: %s\n", gamma_lines_str[get_inquiry_gamma_lines(inquiry_block)]);
|
||
|
|
||
|
/* 0x66 */
|
||
|
DBG_inq_nz("gamma input 8 bits/pixel support\n", get_inquiry_gib_8bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma input 9 bits/pixel support\n", get_inquiry_gib_9bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma input 10 bits/pixel support\n", get_inquiry_gib_10bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma input 12 bits/pixel support\n", get_inquiry_gib_12bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma input 14 bits/pixel support\n", get_inquiry_gib_14bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma input 16 bits/pixel support\n", get_inquiry_gib_16bpp(inquiry_block));
|
||
|
DBG_inq_nz("0x66 bit 6\n", get_inquiry_0x66_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x66 bit 7\n", get_inquiry_0x66_bit7(inquiry_block));
|
||
|
|
||
|
/* 0x68 */
|
||
|
DBG_inq_nz("gamma output 8 bits/pixel support\n", get_inquiry_gob_8bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma output 9 bits/pixel support\n", get_inquiry_gob_9bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma output 10 bits/pixel support\n", get_inquiry_gob_10bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma output 12 bits/pixel support\n", get_inquiry_gob_12bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma output 14 bits/pixel support\n", get_inquiry_gob_14bpp(inquiry_block));
|
||
|
DBG_inq_nz("gamma output 16 bits/pixel support\n", get_inquiry_gob_16bpp(inquiry_block));
|
||
|
DBG_inq_nz("0x68 bit 6\n", get_inquiry_0x68_bit6(inquiry_block));
|
||
|
DBG_inq_nz("0x68 bit 7\n", get_inquiry_0x68_bit7(inquiry_block));
|
||
|
}
|
||
|
|
||
|
/* 0x64 - 0x68 reserved bits */
|
||
|
DBG_inq_nz("0x64 bit 2\n", get_inquiry_0x64_bit2(inquiry_block));
|
||
|
DBG_inq_nz("0x64 bit 3\n", get_inquiry_0x64_bit3(inquiry_block));
|
||
|
DBG_inq_nz("0x64 bit 4\n", get_inquiry_0x64_bit4(inquiry_block));
|
||
|
DBG_inq_nz("0x64 bit 6\n", get_inquiry_0x64_bit6(inquiry_block));
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x65 = %d\n",get_inquiry_0x65(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x67 = %d\n",get_inquiry_0x67(inquiry_block));
|
||
|
|
||
|
|
||
|
/* 0x69 */
|
||
|
if (dev->inquiry_len<=0x69) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
if (get_inquiry_hda(inquiry_block))
|
||
|
{
|
||
|
DBG(DBG_inquiry,"halftone download available\n");
|
||
|
DBG(DBG_inquiry,"halftone pattern download max matrix %dx%d\n",
|
||
|
get_inquiry_max_halftone_matrix(inquiry_block),
|
||
|
get_inquiry_max_halftone_matrix(inquiry_block));
|
||
|
}
|
||
|
|
||
|
/* 0x6a */
|
||
|
if (dev->inquiry_len<=0x6a) {return;}
|
||
|
DBG_inq_nz("built-in halftone patterns.................:\n", get_inquiry_halftones_supported(inquiry_block));
|
||
|
DBG_inq_nz("built-in halftone pattern size ............: 2x2\n",get_inquiry_halftones_2x2(inquiry_block));
|
||
|
DBG_inq_nz("built-in halftone pattern size ............: 4x4\n",get_inquiry_halftones_4x4(inquiry_block));
|
||
|
DBG_inq_nz("built-in halftone pattern size ............: 6x6\n",get_inquiry_halftones_6x6(inquiry_block));
|
||
|
DBG_inq_nz("built-in halftone pattern size ............: 8x8\n",get_inquiry_halftones_8x8(inquiry_block));
|
||
|
DBG_inq_nz("built-in halftone pattern size ............: 12x12\n",get_inquiry_halftones_12x12(inquiry_block));
|
||
|
|
||
|
/* 0x6b, 0x6c */
|
||
|
DBG(DBG_inquiry,"reserved byte 0x6b = %d\n",get_inquiry_0x6b(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x6c = %d\n",get_inquiry_0x6c(inquiry_block));
|
||
|
|
||
|
|
||
|
/* 0x6d */
|
||
|
if (dev->inquiry_len<=0x6d) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"color sequence............................: %s\n",
|
||
|
color_sequence_str[get_inquiry_colorseq(inquiry_block)]);
|
||
|
DBG_inq_nz("color ordering support....................: pixel\n",
|
||
|
get_inquiry_color_order_pixel(inquiry_block));
|
||
|
DBG_inq_nz("color ordering support....................: line without CCD distance\n",
|
||
|
get_inquiry_color_order_line_no_ccd(inquiry_block));
|
||
|
DBG_inq_nz("color ordering support....................: plane\n",
|
||
|
get_inquiry_color_order_plane(inquiry_block));
|
||
|
DBG_inq_nz("color ordering support....................: line with CCD distance\n",
|
||
|
get_inquiry_color_order_line_w_ccd(inquiry_block));
|
||
|
DBG_inq_nz("color ordering support....................: (reserved)\n",
|
||
|
get_inquiry_color_order_reserved(inquiry_block));
|
||
|
|
||
|
/* 0x6e */
|
||
|
if (dev->inquiry_len<=0x71) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"maximum video memory......................: %d KB\n",
|
||
|
get_inquiry_max_vidmem(inquiry_block)/1024);
|
||
|
|
||
|
/* 0x72 */
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x72 = %d\n",get_inquiry_0x72(inquiry_block));
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
/* 0x73/0x94 - 0x75/0x96 */
|
||
|
if (dev->inquiry_len<=0x75) {return;}
|
||
|
DBG(DBG_inquiry,"maximum optical resolution................: %d dpi\n", dev->inquiry_optical_res);
|
||
|
DBG(DBG_inquiry,"maximum x-resolution......................: %d dpi\n", dev->inquiry_x_res);
|
||
|
DBG(DBG_inquiry,"maximum y-resolution......................: %d dpi\n", dev->inquiry_y_res);
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x76 0x77 */
|
||
|
if (dev->inquiry_len<=0x77) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"FB (flatbed-mode):\n");
|
||
|
DBG(DBG_inquiry,"FB maximum scan width.....................: %2.2f inch\n", dev->inquiry_fb_width);
|
||
|
DBG(DBG_inquiry,"FB maximum scan length....................: %2.2f inch\n", dev->inquiry_fb_length);
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x7a - 0x81 */
|
||
|
if (dev->inquiry_len<=0x81) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"UTA (transparency-mode):\n");
|
||
|
DBG(DBG_inquiry,"UTA x-original point......................: %2.2f inch\n",
|
||
|
(double)get_inquiry_uta_x_original(inquiry_block) * 0.01);
|
||
|
DBG(DBG_inquiry,"UTA y-original point......................: %2.2f inch\n",
|
||
|
(double)get_inquiry_uta_y_original(inquiry_block) * 0.01);
|
||
|
DBG(DBG_inquiry,"UTA maximum scan width....................: %2.2f inch\n", dev->inquiry_uta_width);
|
||
|
DBG(DBG_inquiry,"UTA maximum scan length...................: %2.2f inch\n", dev->inquiry_uta_length);
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x82-0x85 */
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x82 = %d\n",get_inquiry_0x82(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x83 = %d\n",get_inquiry_0x83(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x84 = %d\n",get_inquiry_0x84(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x85 = %d\n",get_inquiry_0x85(inquiry_block));
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x86 - 0x8d */
|
||
|
if (dev->inquiry_len<=0x8d) {return;}
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"DOR (double optical resolution-mode):\n");
|
||
|
DBG(DBG_inquiry,"DOR x-original point......................: %2.2f inch\n",
|
||
|
(double)get_inquiry_dor_x_original_point(inquiry_block) * 0.01);
|
||
|
DBG(DBG_inquiry,"DOR y-original point......................: %2.2f inch\n",
|
||
|
(double)get_inquiry_dor_y_original_point(inquiry_block) * 0.01);
|
||
|
DBG(DBG_inquiry,"DOR maximum scan width....................: %2.2f inch\n", dev->inquiry_dor_width);
|
||
|
DBG(DBG_inquiry,"DOR maximum scan length...................: %2.2f inch\n", dev->inquiry_dor_length);
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x8e */
|
||
|
DBG(DBG_inquiry,"reserved byte 0x8e = %d\n",get_inquiry_0x8e(inquiry_block));
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
/* ---------- */
|
||
|
|
||
|
/* 0x8f */
|
||
|
if (dev->inquiry_len<=0x8f) {return;}
|
||
|
DBG(DBG_inquiry,"last calibration lamp density.............: %d\n",
|
||
|
get_inquiry_last_calibration_lamp_density(inquiry_block));
|
||
|
|
||
|
/* 0x90 */
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x90 = %d\n",get_inquiry_0x90(inquiry_block));
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
/* 0x91 */
|
||
|
if (dev->inquiry_len<=0x91) {return;}
|
||
|
DBG(DBG_inquiry,"lamp warmup maximum time..................: %d sec\n", dev->inquiry_max_warmup_time);
|
||
|
|
||
|
/* 0x92 */
|
||
|
if (dev->inquiry_len<=0x93) {return;}
|
||
|
DBG(DBG_inquiry,"window descriptor block length............: %d bytes\n",
|
||
|
get_inquiry_wdb_length(inquiry_block));
|
||
|
|
||
|
/* ----------------- */
|
||
|
|
||
|
/* 0x97 */
|
||
|
if (dev->inquiry_len<=0x97) {return;}
|
||
|
if (get_inquiry_analog_gamma_table(inquiry_block) == 0)
|
||
|
{ DBG(DBG_inquiry,"no analog gamma function\n"); }
|
||
|
else
|
||
|
{ DBG(DBG_inquiry,"mp 8832 analog gamma table\n"); }
|
||
|
|
||
|
/* 0x98, 0x99 */
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
DBG(DBG_inquiry,"reserved byte 0x98 = %d\n",get_inquiry_0x98(inquiry_block));
|
||
|
DBG(DBG_inquiry,"reserved byte 0x99 = %d\n",get_inquiry_0x99(inquiry_block));
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
|
||
|
/* 0x9a */
|
||
|
if (dev->inquiry_len<=0x9a) {return;}
|
||
|
DBG(DBG_inquiry,"maximum calibration data lines for shading: %d\n",
|
||
|
get_inquiry_max_calibration_data_lines(inquiry_block));
|
||
|
|
||
|
/* 0x9b */
|
||
|
if (dev->inquiry_len<=0x9b) {return;}
|
||
|
DBG(DBG_inquiry,"fb/uta: color line arrangement mode.......: %d\n",
|
||
|
get_inquiry_fb_uta_line_arrangement_mode(inquiry_block));
|
||
|
|
||
|
/* 0x9c */
|
||
|
if (dev->inquiry_len<=0x9c) {return;}
|
||
|
DBG(DBG_inquiry,"adf: color line arrangement mode.......: %d\n",
|
||
|
get_inquiry_adf_line_arrangement_mode(inquiry_block));
|
||
|
|
||
|
/* 0x9d */
|
||
|
if (dev->inquiry_len<=0x9d) {return;}
|
||
|
DBG(DBG_inquiry,"CCD line distance.........................: %d\n",
|
||
|
get_inquiry_CCD_line_distance(inquiry_block));
|
||
|
|
||
|
if (dev->inquiry_len<=0x9e) {return;}
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
DBG(DBG_inquiry,"\n");
|
||
|
for(i=0x9e; i<dev->inquiry_len; i++)
|
||
|
{
|
||
|
DBG(DBG_inquiry,"reserved byte 0x%x = %d\n",i,inquiry_block[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ CBHS_CORRECT ------------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_cbhs_correct(minimum, cbhs, maximum)
|
||
|
{
|
||
|
int range = maximum - minimum + 1;
|
||
|
|
||
|
if (range == 256) { return cbhs; }
|
||
|
|
||
|
return (int)( (cbhs/256.0)*range + minimum );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SENSE_HANDLER ------------------------------ */
|
||
|
|
||
|
|
||
|
static SANE_Status sense_handler(int scsi_fd, u_char *result, void *arg) /* is called by sanei_scsi */
|
||
|
{
|
||
|
u_char asc, ascq, sensekey;
|
||
|
int asc_ascq, len;
|
||
|
Umax_Device *dev = arg;
|
||
|
|
||
|
DBG(DBG_proc, "check condition sense handler\n");
|
||
|
|
||
|
sensekey = get_RS_sense_key(result);
|
||
|
asc = get_RS_ASC(result);
|
||
|
ascq = get_RS_ASCQ(result);
|
||
|
asc_ascq = (int)(256 * asc + ascq);
|
||
|
len = 7 + get_RS_additional_length(result);
|
||
|
|
||
|
if ( get_RS_error_code(result) != 0x70 )
|
||
|
{
|
||
|
DBG(DBG_proc, "invalid sense key => handled as DEVICE BUSY!\n");
|
||
|
return SANE_STATUS_DEVICE_BUSY; /* sense key invalid */
|
||
|
}
|
||
|
|
||
|
DBG(DBG_sense, "check condition sense: %s\n",sense_str[sensekey]);
|
||
|
|
||
|
if (len > 0x15)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> %s\n", scanner_error_str[get_RS_scanner_error_code(result)]);
|
||
|
}
|
||
|
|
||
|
if (get_RS_ILI(result) != 0)
|
||
|
{
|
||
|
DBG(DBG_sense, "-> ILI-ERROR: requested data length is larger than actual length\n");
|
||
|
}
|
||
|
|
||
|
switch(sensekey)
|
||
|
{
|
||
|
case 0x00: /* no sense */
|
||
|
return SANE_STATUS_GOOD;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0x03: /* medium error */
|
||
|
if (asc_ascq == 0x1400)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> misfeed, paper jam\n");
|
||
|
return SANE_STATUS_JAMMED;
|
||
|
}
|
||
|
else if (asc_ascq == 0x1401)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> adf not ready\n");
|
||
|
return SANE_STATUS_NO_DOCS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_sense,"-> unknown medium error: asc=%d, ascq=%d\n", asc, ascq);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0x04: /* hardware error */
|
||
|
if (asc_ascq == 0x4000)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> diagnostic error:\n");
|
||
|
if (len >= 0x13)
|
||
|
{
|
||
|
DBG_sense_nz(" dim light\n",get_RS_asb_dim_light(result));
|
||
|
DBG_sense_nz(" no light\n",get_RS_asb_no_light(result));
|
||
|
DBG_sense_nz(" sensor or motor error\n", get_RS_asb_sensor_motor(result));
|
||
|
DBG_sense_nz(" too light\n",get_RS_asb_too_light(result));
|
||
|
DBG_sense_nz(" calibration error\n",get_RS_asb_calibration(result));
|
||
|
DBG_sense_nz(" rom error\n",get_RS_asb_rom(result));
|
||
|
DBG_sense_nz(" ram error\n",get_RS_asb_ram(result));
|
||
|
DBG_sense_nz(" cpu error\n",get_RS_asb_cpu(result));
|
||
|
DBG_sense_nz(" scsi error\n",get_RS_asb_scsi(result));
|
||
|
DBG_sense_nz(" timer error\n",get_RS_asb_timer(result));
|
||
|
DBG_sense_nz(" filter motor error\n",get_RS_asb_filter_motor(result));
|
||
|
DBG_sense_nz(" dc adjust error\n",get_RS_asb_dc_adjust(result));
|
||
|
DBG_sense_nz(" uta home sensor or motor error\n", get_RS_asb_uta_sensor(result));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_sense,"-> unknown hardware error: asc=%d, ascq=%d\n", asc, ascq);
|
||
|
}
|
||
|
return SANE_STATUS_IO_ERROR;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0x05: /* illegal request */
|
||
|
if (asc_ascq == 0x2000)
|
||
|
{ DBG(DBG_sense,"-> invalid command operation code\n"); }
|
||
|
else if (asc_ascq == 0x2400)
|
||
|
{ DBG(DBG_sense,"-> illegal field in CDB\n"); }
|
||
|
else if (asc_ascq == 0x2500)
|
||
|
{ DBG(DBG_sense,"-> logical unit not supported\n"); }
|
||
|
else if (asc_ascq == 0x2600)
|
||
|
{ DBG(DBG_sense,"-> invalid field in parameter list\n"); }
|
||
|
else if (asc_ascq == 0x2c01)
|
||
|
{ DBG(DBG_sense,"-> too many windows specified\n"); }
|
||
|
else if (asc_ascq == 0x2c02)
|
||
|
{ DBG(DBG_sense,"-> invalid combination of windows specified\n"); }
|
||
|
else
|
||
|
{ DBG(DBG_sense,"-> illegal request: asc=%d, ascq=%d\n", asc, ascq); }
|
||
|
|
||
|
if (len >= 0x11)
|
||
|
{
|
||
|
if (get_RS_SKSV(result) != 0)
|
||
|
{
|
||
|
if (get_RS_CD(result) == 0)
|
||
|
{ DBG(DBG_sense,"-> illegal parameter in CDB\n"); }
|
||
|
else
|
||
|
{ DBG(DBG_sense,"-> illegal parameter is in the data parameters sent during data out phase\n"); }
|
||
|
|
||
|
DBG(DBG_sense,"-> error detected in byte %d\n", get_RS_field_pointer(result));
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_IO_ERROR;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0x06: /* unit attention */
|
||
|
if (asc_ascq == 0x2900)
|
||
|
{ DBG(DBG_sense,"-> power on, reset or bus device reset\n"); }
|
||
|
else if (asc_ascq == 0x3f01)
|
||
|
{ DBG(DBG_sense,"-> microcode has been changed\n"); }
|
||
|
else
|
||
|
{ DBG(DBG_sense,"-> unit attention: asc=%d, ascq=%d\n", asc, ascq); }
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0x09: /* vendor specific */
|
||
|
if (asc_ascq == 0x8001)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> lamp warmup\n");
|
||
|
return SANE_STATUS_DEVICE_BUSY;
|
||
|
}
|
||
|
else if (asc_ascq == 0x8002)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> calibration by driver\n");
|
||
|
if (dev)
|
||
|
{
|
||
|
dev->do_calibration = 1; /* set flag for calibration by driver */
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
else if (asc_ascq == 0x0004)
|
||
|
{
|
||
|
DBG(DBG_sense,"-> button pressed\n");
|
||
|
if (dev)
|
||
|
{
|
||
|
dev->button_pressed = 1;
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_sense,"-> vendor specific sense-code: asc=%d, ascq=%d\n",asc, ascq);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX FORGET LINE --------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_forget_line(Umax_Device *dev, int color)
|
||
|
/* tests if line related to optical resolution has to be skipped for selected resolution */
|
||
|
/* returns 0 if line is ok, -1 if line has to be skipped */
|
||
|
{
|
||
|
int opt_res = dev->inquiry_optical_res * dev->scale_y;
|
||
|
int forget;
|
||
|
|
||
|
dev->pixelline_opt_res++; /* increment number of lines in optical res */
|
||
|
|
||
|
if (opt_res != dev->y_resolution) /* are there any lines to skip ? */
|
||
|
{
|
||
|
|
||
|
forget = (dev->pixelline_del[color] * opt_res)/(opt_res - dev->y_resolution);
|
||
|
|
||
|
if (dev->pixelline_optic[color]++ == forget)
|
||
|
{
|
||
|
dev->pixelline_del[color]++; /* inc pointer to next line to skip */
|
||
|
return(-1); /* skip line */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(0); /* ok, order this line */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX ORDER LINE TO PIXEL ------------------- */
|
||
|
|
||
|
|
||
|
static void umax_order_line_to_pixel(Umax_Device *dev, unsigned char *source, int color)
|
||
|
/* reads a one-color line and writes it into a pixel-ordered-buffer if line */
|
||
|
/* is not skipped */
|
||
|
/* color = 0:red, 1:green, 2:blue */
|
||
|
{
|
||
|
int i;
|
||
|
unsigned int line = dev->pixelline_next[color]; /* bufferlinenumber */
|
||
|
unsigned char *dest = dev->pixelbuffer;
|
||
|
|
||
|
if (dest != NULL)
|
||
|
{
|
||
|
if (dev->bits_per_pixel_code == 1) /* 24 bpp */
|
||
|
{
|
||
|
dest += line * dev->width_in_pixels * 3 + color;
|
||
|
|
||
|
for(i=0; i<dev->width_in_pixels; i++) /* cp each pixel into pixelbuffer */
|
||
|
{
|
||
|
*dest++ = *source++;
|
||
|
dest++;
|
||
|
dest++;
|
||
|
}
|
||
|
}
|
||
|
else /* > 24 bpp */
|
||
|
{
|
||
|
dest += line * dev->width_in_pixels * 6 + color * 2;
|
||
|
|
||
|
for(i=0; i<dev->width_in_pixels; i++) /* cp each pixel into pixelbuffer */
|
||
|
{
|
||
|
*dest++ = *source++; /* byte order correct ? , don't know ! */
|
||
|
*dest++ = *source++;
|
||
|
|
||
|
dest++; dest++;
|
||
|
dest++; dest++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
line++;
|
||
|
if (line >= dev->pixelline_max) { line = 0; }
|
||
|
|
||
|
dev->pixelline_next[color] = line; /* next line of this color */
|
||
|
dev->pixelline_ready[color]++; /* number of ready lines for color */
|
||
|
|
||
|
DBG(DBG_read,"merged line as color %d to line %d\n", color, dev->pixelline_ready[color]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX ORDER LINE ---------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_order_line(Umax_Device *dev, unsigned char *source)
|
||
|
{
|
||
|
int CCD_distance = dev->CCD_distance * dev->scale_y;
|
||
|
int length = (dev->scanlength * dev->scale_y * dev->inquiry_optical_res) / dev->y_coordinate_base;
|
||
|
unsigned int color;
|
||
|
|
||
|
do /* search next valid line */
|
||
|
{
|
||
|
if (dev->pixelline_opt_res < CCD_distance)
|
||
|
{
|
||
|
color = dev->CCD_color[0]; /* color 0 */
|
||
|
}
|
||
|
else if (dev->pixelline_opt_res < CCD_distance * 3)
|
||
|
{
|
||
|
color = dev->CCD_color[1 + ((dev->pixelline_opt_res - CCD_distance) % 2)]; /* color 1,2 */
|
||
|
}
|
||
|
else if (dev->pixelline_opt_res < length * 3 - CCD_distance * 3 - 1)
|
||
|
/* else if (dev->pixelline_opt_res < length * 3 - CCD_distance * 3) */
|
||
|
{
|
||
|
color = dev->CCD_color[3 + (dev->pixelline_opt_res % 3)]; /* color 3,4,5 */
|
||
|
}
|
||
|
else if (dev->pixelline_opt_res < length * 3 - CCD_distance - 1)
|
||
|
/* else if (dev->pixelline_opt_res < length * 3 - CCD_distance) */
|
||
|
{
|
||
|
color = dev->CCD_color[6 + ((dev->pixelline_opt_res - length*3 + CCD_distance*3) % 2)]; /* color 6,7 */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
color = dev->CCD_color[8]; /* color 8 */
|
||
|
}
|
||
|
} while(umax_forget_line(dev, color) != 0); /* until found correct line */
|
||
|
|
||
|
umax_order_line_to_pixel(dev, source, color);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX GET PIXEL LINE ------------------------ */
|
||
|
|
||
|
|
||
|
static unsigned char * umax_get_pixel_line(Umax_Device *dev)
|
||
|
{
|
||
|
unsigned char *source = NULL;
|
||
|
|
||
|
if (dev->pixelbuffer != NULL)
|
||
|
{
|
||
|
if ( (dev->pixelline_ready[0] > dev->pixelline_written) &&
|
||
|
(dev->pixelline_ready[1] > dev->pixelline_written) &&
|
||
|
(dev->pixelline_ready[2] > dev->pixelline_written) )
|
||
|
{
|
||
|
source = dev->pixelbuffer + dev->pixelline_read * dev->width_in_pixels * 3;
|
||
|
|
||
|
dev->pixelline_written++;
|
||
|
dev->pixelline_read++;
|
||
|
if (dev->pixelline_read >= dev->pixelline_max) { dev->pixelline_read = 0; }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return source;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX GET DATA BUFFER STATUS ---------------- */
|
||
|
|
||
|
|
||
|
#ifndef UMAX_HIDE_UNUSED /* NOT USED */
|
||
|
static int umax_get_data_buffer_status(Umax_Device *dev)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
DBG(DBG_proc,"get_data_buffer_status\n");
|
||
|
set_GDBS_wait(get_data_buffer_status.cmd,1); /* wait for scanned data */
|
||
|
status = sanei_scsi_cmd(dev->sfd, get_data_buffer_status.cmd, get_data_buffer_status.size, NULL, NULL);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX DO REQUEST SENSE ---------------------- */
|
||
|
|
||
|
|
||
|
static void umax_do_request_sense(Umax_Device *dev)
|
||
|
{
|
||
|
size_t size = rs_return_block_size;
|
||
|
|
||
|
DBG(DBG_proc,"do_request_sense\n");
|
||
|
set_RS_allocation_length(request_sense.cmd, rs_return_block_size);
|
||
|
sanei_scsi_cmd(dev->sfd, request_sense.cmd, request_sense.size, dev->buffer, &size);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX WAIT SCANNER -------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_wait_scanner(Umax_Device *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
int cnt = 0;
|
||
|
|
||
|
DBG(DBG_proc,"wait_scanner\n");
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (cnt > 100) /* maximal 100 * 0.5 sec = 50 sec */
|
||
|
{
|
||
|
DBG(DBG_warning, "scanner does not get ready\n");
|
||
|
return -1;
|
||
|
}
|
||
|
/* test unit ready */
|
||
|
ret = sanei_scsi_cmd(dev->sfd, test_unit_ready.cmd,test_unit_ready.size, NULL, NULL);
|
||
|
cnt++;
|
||
|
|
||
|
if (ret != SANE_STATUS_GOOD)
|
||
|
{
|
||
|
if (cnt == 1)
|
||
|
{ DBG(DBG_info2,"scanner reports %s, waiting ...\n", sane_strstatus(ret)); }
|
||
|
|
||
|
usleep(500000); /* wait 0.5 seconds */
|
||
|
}
|
||
|
|
||
|
} while (ret != SANE_STATUS_GOOD );
|
||
|
|
||
|
switch (ret)
|
||
|
{
|
||
|
case SANE_STATUS_GOOD:
|
||
|
DBG(DBG_info,"scanner ready\n");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DBG(DBG_error,"scanner reports error: %s\n", sane_strstatus(ret));
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#define WAIT_SCANNER { int ret = umax_wait_scanner(dev); if (ret) return ret; }
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX GRAB SCANNER -------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_grab_scanner(Umax_Device *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
DBG(DBG_proc,"grab_scanner\n");
|
||
|
|
||
|
WAIT_SCANNER; /* wait for scanner ready */
|
||
|
ret = sanei_scsi_cmd(dev->sfd, reserve_unit.cmd, reserve_unit.size, NULL, NULL);
|
||
|
if (ret) { return ret; }
|
||
|
|
||
|
DBG(DBG_info, "scanner reserved\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX REPOSITION SCANNER -------------------- */
|
||
|
|
||
|
|
||
|
static int umax_reposition_scanner(Umax_Device *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
DBG(DBG_info2, "trying to reposition scanner ...\n");
|
||
|
ret = sanei_scsi_cmd(dev->sfd, object_position.cmd, object_position.size, NULL, NULL);
|
||
|
if (ret) { return ret; }
|
||
|
WAIT_SCANNER;
|
||
|
DBG(DBG_info, "scanner repositioned\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX GIVE SCANNER -------------------------- */
|
||
|
|
||
|
|
||
|
/* umax_give_scanner should go through the following sequence:
|
||
|
* OBJECT POSITION
|
||
|
* GOOD
|
||
|
* RELEASE UNIT
|
||
|
* GOOD
|
||
|
*/
|
||
|
|
||
|
static int umax_give_scanner(Umax_Device *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
DBG(DBG_info2, "trying to release scanner ...\n");
|
||
|
ret = sanei_scsi_cmd(dev->sfd, object_position.cmd, object_position.size, NULL, NULL);
|
||
|
if (ret) { return ret; }
|
||
|
WAIT_SCANNER;
|
||
|
ret = sanei_scsi_cmd(dev->sfd, release_unit.cmd, release_unit.size, NULL, NULL);
|
||
|
if (ret) { return ret; }
|
||
|
DBG(DBG_info, "scanner released\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SEND GAMMA DATA ----------------------- */
|
||
|
|
||
|
|
||
|
static void umax_send_gamma_data(Umax_Device *dev, char *data, int color)
|
||
|
{
|
||
|
unsigned char *dest;
|
||
|
int length;
|
||
|
|
||
|
DBG(DBG_proc, "send_gamma_data\n");
|
||
|
|
||
|
if (dev->inquiry_gamma_dwload == 0)
|
||
|
{
|
||
|
DBG(DBG_error, "gamma download not available\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
memcpy(dev->buffer, send.cmd, send.size); /* send */
|
||
|
set_S_datatype_code(dev->buffer, S_datatype_gamma); /* gamma curve */
|
||
|
|
||
|
dest = dev->buffer + send.size;
|
||
|
|
||
|
if (dev->inquiry_gamma_DCF == 0) /* gamma format type 0 */
|
||
|
{
|
||
|
DBG(DBG_info, "using gamma download curve format type 0\n");
|
||
|
|
||
|
memcpy(dest, gamma_DCF0.cmd, gamma_DCF0.size);
|
||
|
|
||
|
if (color == 1) /* one color */
|
||
|
{
|
||
|
set_DCF0_gamma_lines(dest, DCF0_gamma_one_line);
|
||
|
|
||
|
set_DCF0_gamma_color(dest, 0, DCF0_gamma_color_gray); /* grayscale */
|
||
|
if ( (dev->colormode == RGB) && (dev->three_pass != 0) ) /* 3 pass color */
|
||
|
{ set_DCF0_gamma_color(dest, 0, dev->three_pass_color); } /* set color */
|
||
|
|
||
|
dest = dest + 2;
|
||
|
memcpy(dest, data, 1024); /* copy data */
|
||
|
|
||
|
set_S_xfer_length(dev->buffer, 1026); /* set length */
|
||
|
sanei_scsi_cmd(dev->sfd, dev->buffer, send.size + 1026, NULL, NULL);
|
||
|
}
|
||
|
else /* three colors */
|
||
|
{
|
||
|
set_DCF0_gamma_lines(dest, DCF0_gamma_three_lines);
|
||
|
|
||
|
set_DCF0_gamma_color(dest, 0, DCF0_gamma_color_red); /* red */
|
||
|
set_DCF0_gamma_color(dest, 1, DCF0_gamma_color_green); /* green */
|
||
|
set_DCF0_gamma_color(dest, 2, DCF0_gamma_color_blue); /* blue */
|
||
|
|
||
|
dest = dest + 2;
|
||
|
memcpy(dest, data, 1024); /* copy red data */
|
||
|
|
||
|
dest = dest + 1025;
|
||
|
data = data + 1024;
|
||
|
memcpy(dest, data, 1024); /* copy green data */
|
||
|
|
||
|
dest = dest + 1025;
|
||
|
data = data + 1024;
|
||
|
memcpy(dest, data, 1024); /* copy blue data */
|
||
|
|
||
|
set_S_xfer_length(dev->buffer, 3076); /* set length */
|
||
|
sanei_scsi_cmd(dev->sfd, dev->buffer, send.size + 3076, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
else if (dev->inquiry_gamma_DCF == 1) /* gamma format type 1 */
|
||
|
{
|
||
|
DBG(DBG_info, "using gamma download curve format type 1\n");
|
||
|
|
||
|
memcpy(dest, gamma_DCF1.cmd, gamma_DCF1.size);
|
||
|
|
||
|
set_DCF1_gamma_color(dest, DCF0_gamma_color_gray); /* grayscale */
|
||
|
if ( (dev->colormode == RGB) && (dev->three_pass != 0) ) /* 3 pass color */
|
||
|
{ set_DCF1_gamma_color(dest, dev->three_pass_color); } /* set color */
|
||
|
|
||
|
dest = dest + 2;
|
||
|
memcpy(dest, data, 256); /* copy data */
|
||
|
|
||
|
set_S_xfer_length(dev->buffer, 258); /* set length */
|
||
|
sanei_scsi_cmd(dev->sfd, dev->buffer, send.size + 258, NULL, NULL);
|
||
|
}
|
||
|
else if (dev->inquiry_gamma_DCF == 2) /* gamma format type 2 */
|
||
|
{
|
||
|
DBG(DBG_info, "using gamma download curve format type 2\n");
|
||
|
|
||
|
memcpy(dest, gamma_DCF2.cmd, gamma_DCF2.size);
|
||
|
|
||
|
set_DCF2_gamma_color(dest, DCF2_gamma_color_gray); /* grayscale */
|
||
|
if ( (dev->colormode == RGB) && (dev->three_pass != 0) ) /* 3 pass color */
|
||
|
{ set_DCF2_gamma_color(dest, dev->three_pass_color); } /* set color */
|
||
|
|
||
|
if (color == 1)
|
||
|
{ set_DCF2_gamma_lines(dest, DCF2_gamma_one_line); }
|
||
|
else
|
||
|
{ set_DCF2_gamma_lines(dest, DCF2_gamma_three_lines); }
|
||
|
|
||
|
set_DCF2_gamma_input_bits(dest, dev->gamma_input_bits_code);
|
||
|
set_DCF2_gamma_output_bits(dest, dev->bits_per_pixel_code);
|
||
|
|
||
|
dest = dev->buffer + send.size + gamma_DCF2.size; /* write to dest */
|
||
|
|
||
|
if (dev->gamma_input_bits_code & 32)
|
||
|
{ length = 65536; } /* 16 input bits */
|
||
|
else if (dev->gamma_input_bits_code & 16)
|
||
|
{ length = 16384; } /* 14 input bits */
|
||
|
else if (dev->gamma_input_bits_code & 8)
|
||
|
{ length = 4096; } /* 12 input bits */
|
||
|
else if (dev->gamma_input_bits_code & 4)
|
||
|
{ length = 1024; } /* 10 input bits */
|
||
|
else if (dev->gamma_input_bits_code & 2)
|
||
|
{ length = 512; } /* 9 input bits */
|
||
|
else
|
||
|
{ length = 256; } /* 8 input bits */
|
||
|
|
||
|
if (dev->bits_per_pixel_code != 1) /* more than 8 output bits per pixel */
|
||
|
{ length = length * 2; } /* = 2 output bytes */
|
||
|
|
||
|
set_S_xfer_length(dev->buffer, color*length+gamma_DCF2.size); /* set length */
|
||
|
memcpy(dest, data, color*length); /* copy data */
|
||
|
|
||
|
sanei_scsi_cmd(dev->sfd, dev->buffer, send.size+gamma_DCF2.size + length * color, NULL, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_error, "unknown gamma download curve type for this scanner\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SEND DATA ---------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_send_data(Umax_Device *dev,char *data, int size, int datatype)
|
||
|
{
|
||
|
unsigned char *dest;
|
||
|
|
||
|
memcpy(dev->buffer, send.cmd, send.size); /* send */
|
||
|
set_S_datatype_code(dev->buffer, datatype); /* set datatype */
|
||
|
set_S_xfer_length(dev->buffer, size); /* bytes */
|
||
|
|
||
|
dest=dev->buffer + send.size;
|
||
|
memcpy(dest, data, size); /* copy data */
|
||
|
|
||
|
sanei_scsi_cmd(dev->sfd, dev->buffer, send.size + size, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SEND HALFTONE PATTERN ----------------- */
|
||
|
|
||
|
|
||
|
static void umax_send_halftone_pattern(Umax_Device *dev, char *data, int size)
|
||
|
{
|
||
|
DBG(DBG_proc,"send_halftone_pattern\n");
|
||
|
umax_send_data(dev, data, size*size, S_datatype_halftone);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SEND SHADING DATA -------------------- */
|
||
|
|
||
|
|
||
|
static void umax_send_shading_data(Umax_Device *dev, char *data, int size)
|
||
|
{
|
||
|
DBG(DBG_proc,"send_shading_data\n");
|
||
|
umax_send_data(dev, data, size, S_datatype_shading);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SEND GAIN DATA ----------------------- */
|
||
|
|
||
|
#ifndef UMAX_HIDE_UNUSED
|
||
|
static void umax_send_gain_data(Umax_Device *dev, char *data, int size)
|
||
|
{
|
||
|
DBG(DBG_proc,"send_gain_data\n");
|
||
|
umax_send_data(dev, data, size, S_datatype_gain);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX READ DATA ----------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_read_data(Umax_Device *dev, size_t length, int datatype)
|
||
|
{
|
||
|
set_R_xfer_length(sread.cmd, length); /* set length */
|
||
|
set_R_datatype_code(sread.cmd, datatype); /* set datatype */
|
||
|
if (sanei_scsi_cmd(dev->sfd, sread.cmd, sread.size, dev->buffer, &length) != 0) { return -1; }
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX READ SHADING DATA -------------------- */
|
||
|
|
||
|
|
||
|
static int umax_read_shading_data(Umax_Device *dev, unsigned int length)
|
||
|
{
|
||
|
DBG(DBG_proc,"read_shading_data\n");
|
||
|
return umax_read_data(dev, length, R_datatype_shading);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX READ GAIN DATA ----------------------- */
|
||
|
|
||
|
|
||
|
#ifndef UMAX_HIDE_UNUSED
|
||
|
static int umax_read_gain_data(Umax_Device *dev, unsigned int length)
|
||
|
{
|
||
|
DBG(DBG_proc,"read_gain_data\n");
|
||
|
return umax_read_data(dev, length, R_datatype_gain);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX READ IMAGE DATA ---------------------- */
|
||
|
|
||
|
|
||
|
static int umax_read_image_data(Umax_Device *dev, unsigned int length)
|
||
|
{
|
||
|
DBG(DBG_proc,"read_image_data\n");
|
||
|
WAIT_SCANNER;
|
||
|
return umax_read_data(dev, length, R_datatype_imagedata);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX CORRECT LIGHT ------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_correct_light(int light, int analog_gamma_byte) /* correct highlight/shadow if analog gamma is set */
|
||
|
{
|
||
|
double analog_gamma;
|
||
|
analog_gamma=analog_gamma_table[analog_gamma_byte];
|
||
|
return( (int) 255 * pow( ((double) light)/255.0 , (1.0/analog_gamma) )+.5 );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX SET WINDOW PARAM ---------------------- */
|
||
|
|
||
|
|
||
|
/* set_window_param sets all the window parameters. This means building a */
|
||
|
/* fairly complicated SCSI command before sending it... */
|
||
|
|
||
|
static int umax_set_window_param(Umax_Device *dev)
|
||
|
{
|
||
|
int num_dblocks = 1; /* number of window descriptor blocks, usually 1 or 3 */
|
||
|
unsigned char buffer_r[max_WDB_size], buffer_g[max_WDB_size], buffer_b[max_WDB_size];
|
||
|
|
||
|
DBG(DBG_proc, "set_window_param\n");
|
||
|
memset(buffer_r, '\0', max_WDB_size); /* clear buffer */
|
||
|
set_WDB_length(dev->wdb_len); /* length of win descriptor block */
|
||
|
memcpy(buffer_r,window_descriptor_block.cmd, window_descriptor_block.size); /* copy preset data */
|
||
|
|
||
|
set_WD_wid(buffer_r, 0); /* window identifier */
|
||
|
set_WD_auto(buffer_r, dev->set_auto); /* 0 or 1: don't know what it is */
|
||
|
|
||
|
/* geometry */
|
||
|
set_WD_Xres(buffer_r, dev->x_resolution); /* x resolution in dpi */
|
||
|
set_WD_Yres(buffer_r, dev->y_resolution); /* y resolution in dpi */
|
||
|
set_WD_ULX(buffer_r, dev->upper_left_x); /* left_edge x */
|
||
|
set_WD_ULY(buffer_r, dev->upper_left_y); /* upper_edge y */
|
||
|
set_WD_width(buffer_r, dev->scanwidth); /* width */
|
||
|
set_WD_length(buffer_r, dev->scanlength); /* length */
|
||
|
|
||
|
/* BTC */
|
||
|
set_WD_brightness(buffer_r, dev->brightness); /* brightness, only halftone */
|
||
|
set_WD_threshold(buffer_r, dev->threshold); /* threshold, only lineart */
|
||
|
set_WD_contrast(buffer_r, dev->contrast); /* contrast, only halftone */
|
||
|
|
||
|
/* scanmode, preset to LINEART */
|
||
|
set_WD_composition(buffer_r, WD_comp_lineart); /* image composition */
|
||
|
/* = (scan-mode) */
|
||
|
set_WD_bitsperpixel(buffer_r, WD_bits_1); /* bits/pixel (1,8,9,10,12,14,16) */
|
||
|
set_WD_halftone(buffer_r, dev->halftone); /* select halftone-pattern */
|
||
|
set_WD_RIF(buffer_r, dev->reverse); /* reverse, invert black and white */
|
||
|
set_WD_speed(buffer_r, dev->WD_speed); /* set speed */
|
||
|
set_WD_select_color(buffer_r, WD_color_gray); /* color for window-block */
|
||
|
|
||
|
/* set highlight and shadow in dependence of analog gamma */
|
||
|
set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_r, dev->analog_gamma_r));
|
||
|
set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r));
|
||
|
|
||
|
/* scan options */
|
||
|
set_WD_gamma(buffer_r, dev->digital_gamma_r); /* set digital gamma */
|
||
|
set_WD_module(buffer_r, dev->module); /* flatbed or transparency */
|
||
|
set_WD_CBHS(buffer_r, dev->cbhs_range); /* 50 or 255 */
|
||
|
set_WD_RMIF(buffer_r, dev->reverse_multi); /* reverse color-values */
|
||
|
set_WD_DOR(buffer_r, dev->dor); /* double-resolution-mode */
|
||
|
set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); /* scan exposure time */
|
||
|
set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_r);/* calibration exposure time */
|
||
|
set_WD_line_arrangement(buffer_r, WD_line_arrengement_by_fw); /* line arrangement by scanner */
|
||
|
set_WD_warmup(buffer_r, dev->warmup); /* warmup */
|
||
|
|
||
|
set_WD_calibration(buffer_r, dev->calibration); /* image calibration */
|
||
|
|
||
|
set_WD_color_sequence(buffer_r,WD_color_sequence_RGB); /* sequence RGB */
|
||
|
set_WD_color_ordering(buffer_r, WD_color_ordering_pixel); /* set to pixel for pbm,pgm,pnm-file */
|
||
|
set_WD_analog_gamma(buffer_r, dev->analog_gamma_r ); /* analog gamma */
|
||
|
set_WD_lamp_c_density(buffer_r, dev->c_density); /* calirat. lamp density */
|
||
|
set_WD_lamp_s_density(buffer_r, dev->s_density); /* scan lamp density */
|
||
|
set_WD_pixel_count(buffer_r, dev->width_in_pixels); /* pixel count */
|
||
|
set_WD_line_count(buffer_r, dev->length_in_pixels); /* line count */
|
||
|
set_WD_x_coordinate_base(buffer_r, dev->x_coordinate_base); /* dpi (1200) */
|
||
|
set_WD_y_coordinate_base(buffer_r, dev->y_coordinate_base); /* dpi (1200) */
|
||
|
set_WD_calibration_data_lines(buffer_r, dev->calib_lines); /* required lines for calibration by driver */
|
||
|
|
||
|
|
||
|
switch(dev->colormode)
|
||
|
{
|
||
|
case LINEART: /* LINEART */
|
||
|
set_WD_composition(buffer_r, WD_comp_lineart);
|
||
|
set_WD_bitsperpixel(buffer_r, WD_bits_1);
|
||
|
set_WD_select_color(buffer_r, WD_color_gray);
|
||
|
break;
|
||
|
|
||
|
case HALFTONE: /* HALFTONE */
|
||
|
set_WD_composition(buffer_r, WD_comp_dithered);
|
||
|
set_WD_bitsperpixel(buffer_r, WD_bits_1);
|
||
|
set_WD_select_color(buffer_r, WD_color_gray);
|
||
|
break;
|
||
|
|
||
|
case GRAYSCALE: /* GRAYSCALE */
|
||
|
set_WD_composition(buffer_r, WD_comp_gray);
|
||
|
set_WD_bitsperpixel(buffer_r, dev->bits_per_pixel);
|
||
|
set_WD_HBT(buffer_r, dev->low_byte_first);
|
||
|
|
||
|
set_WD_select_color(buffer_r, WD_color_gray);
|
||
|
break;
|
||
|
|
||
|
case RGB_LINEART: /* COLOR MODES */
|
||
|
case RGB_HALFTONE:
|
||
|
case RGB:
|
||
|
if (dev->colormode == RGB_LINEART )
|
||
|
{
|
||
|
set_WD_composition(buffer_r, WD_comp_rgb_bilevel);
|
||
|
set_WD_bitsperpixel(buffer_r, WD_bits_1);
|
||
|
}
|
||
|
else if (dev->colormode == RGB_HALFTONE )
|
||
|
{
|
||
|
set_WD_composition(buffer_r, WD_comp_rgb_dithered);
|
||
|
set_WD_bitsperpixel(buffer_r, WD_bits_1);
|
||
|
}
|
||
|
else /* RGB */
|
||
|
{
|
||
|
set_WD_composition(buffer_r, WD_comp_rgb_full);
|
||
|
set_WD_bitsperpixel(buffer_r, dev->bits_per_pixel);
|
||
|
set_WD_HBT(buffer_r, dev->low_byte_first);
|
||
|
}
|
||
|
|
||
|
if (dev->three_pass == 0)
|
||
|
{ /* singlepass */
|
||
|
num_dblocks = 3;
|
||
|
|
||
|
if (dev->do_color_ordering != 0)
|
||
|
{
|
||
|
set_WD_line_arrangement(buffer_r, WD_line_arrengement_by_driver);
|
||
|
|
||
|
if (dev->CCD_distance == 0)
|
||
|
{ set_WD_color_ordering(buffer_r, WD_color_ordering_line_no_ccd); }
|
||
|
else
|
||
|
{ set_WD_color_ordering(buffer_r, WD_color_ordering_line_w_ccd); }
|
||
|
}
|
||
|
|
||
|
memcpy(buffer_g, buffer_r, max_WDB_size); /* copy WDB for green */
|
||
|
memcpy(buffer_b, buffer_r, max_WDB_size); /* copy WDB for blue */
|
||
|
|
||
|
set_WD_wid(buffer_r, WD_wid_red); /* window identifier red */
|
||
|
set_WD_wid(buffer_g, WD_wid_green); /* window identifier green */
|
||
|
set_WD_wid(buffer_b, WD_wid_blue); /* window identifier blue */
|
||
|
|
||
|
set_WD_select_color(buffer_r, WD_color_red); /* select red for this window */
|
||
|
set_WD_select_color(buffer_g, WD_color_green); /* select green for this window */
|
||
|
set_WD_select_color(buffer_b, WD_color_blue); /* select blue for this window */
|
||
|
|
||
|
set_WD_gamma(buffer_r, dev->digital_gamma_r); /* digital gamma */
|
||
|
set_WD_gamma(buffer_g, dev->digital_gamma_g);
|
||
|
set_WD_gamma(buffer_b, dev->digital_gamma_b);
|
||
|
|
||
|
set_WD_analog_gamma(buffer_r, dev->analog_gamma_r); /* analog gamma */
|
||
|
set_WD_analog_gamma(buffer_g, dev->analog_gamma_g);
|
||
|
set_WD_analog_gamma(buffer_b, dev->analog_gamma_b);
|
||
|
|
||
|
/* set highlight in dependence of analog gamma */
|
||
|
set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_r, dev->analog_gamma_r));
|
||
|
set_WD_highlight(buffer_g, umax_correct_light(dev->highlight_g, dev->analog_gamma_g));
|
||
|
set_WD_highlight(buffer_b, umax_correct_light(dev->highlight_g, dev->analog_gamma_b));
|
||
|
|
||
|
/* set shadow in dependence of analog gamma */
|
||
|
set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r));
|
||
|
set_WD_shadow(buffer_g, umax_correct_light(dev->shadow_g, dev->analog_gamma_g));
|
||
|
set_WD_shadow(buffer_b, umax_correct_light(dev->shadow_b, dev->analog_gamma_b));
|
||
|
|
||
|
set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); /* set scan exposure times */
|
||
|
set_WD_scan_exposure_level(buffer_g, dev->exposure_time_scan_g);
|
||
|
set_WD_scan_exposure_level(buffer_b, dev->exposure_time_scan_b);
|
||
|
|
||
|
set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_r);/* set calib exp times */
|
||
|
set_WD_calibration_exposure_level(buffer_g, dev->exposure_time_calibration_g);
|
||
|
set_WD_calibration_exposure_level(buffer_b, dev->exposure_time_calibration_b);
|
||
|
}
|
||
|
else
|
||
|
{ /* threepass */
|
||
|
set_WD_wid(buffer_r, 0); /* window identifier */
|
||
|
set_WD_color_ordering(buffer_r, WD_color_ordering_plane); /* ???? */
|
||
|
|
||
|
if (dev->colormode == RGB_LINEART )
|
||
|
{ set_WD_composition(buffer_r, WD_comp_lineart); } /* color-lineart-mode */
|
||
|
else if (dev->colormode == RGB_HALFTONE )
|
||
|
{ set_WD_composition(buffer_r, WD_comp_dithered); } /* color-halftone-mode */
|
||
|
else /* RGB */
|
||
|
{ set_WD_composition(buffer_r, WD_comp_gray); } /* color-mode */
|
||
|
|
||
|
switch (dev->three_pass_color)
|
||
|
{
|
||
|
case WD_wid_red:
|
||
|
set_WD_select_color(buffer_r, WD_color_red); /* color red */
|
||
|
set_WD_gamma(buffer_r, dev->digital_gamma_r);
|
||
|
set_WD_analog_gamma(buffer_r, dev->analog_gamma_r);
|
||
|
set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_r, dev->analog_gamma_r));
|
||
|
set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r));
|
||
|
set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r);
|
||
|
set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_r);
|
||
|
break;
|
||
|
|
||
|
case WD_wid_green:
|
||
|
set_WD_select_color(buffer_r, WD_color_green); /* color green */
|
||
|
set_WD_gamma(buffer_r, dev->digital_gamma_g);
|
||
|
set_WD_analog_gamma(buffer_r,dev->analog_gamma_g);
|
||
|
set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_g, dev->analog_gamma_g));
|
||
|
set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_g, dev->analog_gamma_g));
|
||
|
set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_g);
|
||
|
set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_g);
|
||
|
break;
|
||
|
|
||
|
case WD_wid_blue:
|
||
|
set_WD_select_color(buffer_r, WD_color_blue); /* color blue */
|
||
|
set_WD_gamma(buffer_r, dev->digital_gamma_b);
|
||
|
set_WD_analog_gamma(buffer_r,dev->analog_gamma_b);
|
||
|
set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_b, dev->analog_gamma_b));
|
||
|
set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_b, dev->analog_gamma_b));
|
||
|
set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_b);
|
||
|
set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_b);
|
||
|
break;
|
||
|
|
||
|
} /* switch dev->three_pass_color */
|
||
|
|
||
|
} /* if (single_pass) else (three_pass) */
|
||
|
break;
|
||
|
} /* switch dev->colormode, case RGB */
|
||
|
|
||
|
/* prepare SCSI-BUFFER */
|
||
|
memcpy(dev->buffer, set_window.cmd, set_window.size); /* SET-WINDOW cmd */
|
||
|
memcpy(WPDB_OFF(dev->buffer), window_parameter_data_block.cmd, window_parameter_data_block.size); /* WPDB */
|
||
|
set_WPDB_wdbnum(WPDB_OFF(dev->buffer), num_dblocks); /* set WD_len */
|
||
|
memcpy(WDB_OFF(dev->buffer,1), buffer_r, window_descriptor_block.size); /* add WD_block */
|
||
|
|
||
|
if ( num_dblocks == 3) /* if singelpass RGB */
|
||
|
{
|
||
|
memcpy(WDB_OFF(dev->buffer,2), buffer_g, window_descriptor_block.size); /* add green */
|
||
|
memcpy(WDB_OFF(dev->buffer,3), buffer_b, window_descriptor_block.size); /* add blue */
|
||
|
}
|
||
|
|
||
|
|
||
|
DBG(DBG_info2, "window descriptor block created with %d bytes\n", dev->wdb_len);
|
||
|
|
||
|
set_SW_xferlen(dev->buffer, (window_parameter_data_block.size + (window_descriptor_block.size * num_dblocks)));
|
||
|
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
ret = sanei_scsi_cmd(dev->sfd, dev->buffer, set_window.size + window_parameter_data_block.size +
|
||
|
(window_descriptor_block.size * num_dblocks), NULL, NULL);
|
||
|
if (ret) { return ret; }
|
||
|
}
|
||
|
|
||
|
DBG(DBG_info, "window(s) set\n");
|
||
|
|
||
|
return (umax_wait_scanner(dev)); /* wait for scanner, lamp warmup */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX START SCAN ---------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_start_scan(Umax_Device *dev)
|
||
|
{
|
||
|
int size = 1;
|
||
|
|
||
|
DBG(DBG_proc,"start_scan\n");
|
||
|
|
||
|
set_SC_quality( scan.cmd, dev->quality); /* 1=qual, 0=fast */
|
||
|
set_SC_adf( scan.cmd, dev->adf); /* ADF, 0=off, 1=use */
|
||
|
set_SC_preview( scan.cmd, dev->preview); /* 1=preview */
|
||
|
|
||
|
if (dev->RGB_PREVIEW_FIX != 0) /* in RGB-mode set preview bit, eg. for UMAX S6E */
|
||
|
{ if (dev->colormode == RGB) { set_SC_preview(scan.cmd, 1); } }
|
||
|
|
||
|
set_SC_wid(scan.cmd, 1, 0); /* Window-Identifier */
|
||
|
|
||
|
set_SC_xfer_length(scan.cmd, size); /* following Bytes */
|
||
|
|
||
|
DBG(DBG_info,"starting scan\n");
|
||
|
|
||
|
return sanei_scsi_cmd(dev->sfd, scan.cmd, scan.size + size, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX DO CALIBRATION ------------------------ */
|
||
|
|
||
|
|
||
|
static int umax_do_calibration(Umax_Device *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
int width = 0;
|
||
|
int lines = 0;
|
||
|
int bytespp = 0;
|
||
|
|
||
|
DBG(DBG_proc,"do_calibration\n");
|
||
|
|
||
|
ret = umax_wait_scanner(dev);
|
||
|
|
||
|
if ((ret == SANE_STATUS_GOOD) && (dev->do_calibration != 0)) /* calibration by driver */
|
||
|
{
|
||
|
unsigned char *shading_data = 0;
|
||
|
int i,j;
|
||
|
|
||
|
DBG(DBG_info,"driver is doing calibration\n");
|
||
|
|
||
|
umax_do_request_sense(dev); /* new request-sense call to get all data */
|
||
|
|
||
|
if (get_RS_SCC_condition_code(dev->buffer) != 1)
|
||
|
{
|
||
|
DBG(DBG_warning,"WARNING: missing informations about shading-data\n");
|
||
|
DBG(DBG_warning," driver tries to guess missing values!\n");
|
||
|
|
||
|
width = dev->scanwidth * dev->inquiry_optical_res / dev->x_coordinate_base;
|
||
|
if (dev->colormode == RGB) { width = width * 3; }
|
||
|
|
||
|
lines = dev->calib_lines;
|
||
|
if (dev->bits_per_pixel_code == 1)
|
||
|
{ bytespp = 1; }
|
||
|
else
|
||
|
{ bytespp = 2; }
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
width = get_RS_SCC_calibration_width(dev->buffer);
|
||
|
lines = get_RS_SCC_calibration_lines(dev->buffer);
|
||
|
bytespp = get_RS_SCC_calibration_bytespp(dev->buffer);
|
||
|
}
|
||
|
|
||
|
DBG(DBG_info,"scanner sends %d lines with %d pixels and %d bytes/pixel\n", lines, width, bytespp);
|
||
|
/* scanner sends uncalibrated image data, bright -> 255, dark -> 0 (although 0 is not black) */
|
||
|
/* my scanner sends values around 220 */
|
||
|
|
||
|
if ( (dev->shading_type == SHADING_TYPE_ONE_LINE) || (dev->shading_type == SHADING_TYPE_ONE_LINE_INVERT) ) /* last line */
|
||
|
{
|
||
|
DBG(DBG_info,"using last shading line as shading data!\n");
|
||
|
|
||
|
shading_data = calloc(width, bytespp);
|
||
|
if (shading_data == 0) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
for (i=0; i<lines; i++)
|
||
|
{
|
||
|
umax_read_shading_data(dev, width * bytespp);
|
||
|
DBG(DBG_read,"shading-line %d read\n",i+1);
|
||
|
}
|
||
|
|
||
|
memcpy(shading_data, dev->buffer, width * bytespp);
|
||
|
}
|
||
|
else if ( (dev->shading_type == SHADING_TYPE_AVERAGE) || (dev->shading_type == SHADING_TYPE_AVERAGE_INVERT) ) /* average of all lines */
|
||
|
{
|
||
|
long *average;
|
||
|
|
||
|
DBG(DBG_info,"calculating average value for shading data!\n");
|
||
|
|
||
|
average = calloc(width, sizeof(long));
|
||
|
if (average == 0) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
shading_data = calloc(width, bytespp);
|
||
|
if (shading_data == 0) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
if (bytespp == 1) /* 1 byte per pixel */
|
||
|
{
|
||
|
for (i=0; i<lines; i++)
|
||
|
{
|
||
|
umax_read_shading_data(dev, width * bytespp);
|
||
|
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
average[j] += (long) dev->buffer[j];
|
||
|
}
|
||
|
|
||
|
DBG(DBG_read,"shading-line %d read\n",i+1);
|
||
|
}
|
||
|
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
shading_data[j] = (unsigned char) (average[j] / lines);
|
||
|
}
|
||
|
}
|
||
|
else /* 2 bytes per pixel */
|
||
|
{
|
||
|
for (i=0; i<lines; i++)
|
||
|
{
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
average[j] += (long) 256 * dev->buffer[2*j] + dev->buffer[2*j + 1] ;
|
||
|
}
|
||
|
|
||
|
DBG(DBG_read,"shading-line %d read\n",i+1);
|
||
|
}
|
||
|
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
shading_data[2*j] = (unsigned char) (average[j] / (256 * lines));
|
||
|
shading_data[2*j+1] = (unsigned char) (average[j] / lines);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(average);
|
||
|
} /* average */
|
||
|
|
||
|
if ( (dev->shading_type == SHADING_TYPE_ONE_LINE_INVERT) || (dev->shading_type == SHADING_TYPE_AVERAGE_INVERT) ) /* invert data */
|
||
|
{
|
||
|
DBG(DBG_info,"inverting shading data\n");
|
||
|
|
||
|
if (bytespp == 1)
|
||
|
{
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
shading_data[j] = 255 - shading_data[j];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned int value;
|
||
|
|
||
|
for (j=0; j<width; j++)
|
||
|
{
|
||
|
value = shading_data[2*j] + shading_data[2*j+1] * 256;
|
||
|
value = 65535 - value;
|
||
|
shading_data[2*j] = (unsigned char) value/256;
|
||
|
shading_data[2*j+1] = (unsigned char) value & 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
umax_send_shading_data(dev, shading_data, width * bytespp);
|
||
|
DBG(DBG_info,"shading-data sent\n");
|
||
|
free(shading_data);
|
||
|
|
||
|
umax_start_scan(dev); /* now start real scan */
|
||
|
|
||
|
dev->do_calibration = 0;
|
||
|
ret = SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX DO INQUIRY ---------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_do_inquiry(Umax_Device *dev)
|
||
|
{
|
||
|
size_t size;
|
||
|
|
||
|
DBG(DBG_proc,"do_inquiry\n");
|
||
|
memset(dev->buffer, '\0', 256); /* clear buffer */
|
||
|
|
||
|
size = 5;
|
||
|
|
||
|
set_inquiry_return_size(inquiry.cmd, size); /* first get only 5 bytes to get size of inquiry_return_block */
|
||
|
sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer, &size);
|
||
|
|
||
|
size = get_inquiry_additional_length(dev->buffer) + 5;
|
||
|
|
||
|
set_inquiry_return_size(inquiry.cmd, size); /* then get inquiry with actual size */
|
||
|
sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer, &size);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX DO NEW INQUIRY ------------------------ */
|
||
|
|
||
|
|
||
|
static void umax_do_new_inquiry(Umax_Device *dev, size_t size) /* call inquiry again if wrong length */
|
||
|
{
|
||
|
DBG(DBG_proc,"do_new_inquiry\n");
|
||
|
memset(dev->buffer, '\0', 256); /* clear buffer */
|
||
|
|
||
|
set_inquiry_return_size(inquiry.cmd, size);
|
||
|
sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer, &size);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX CORRECT INQUIRY ----------------------- */
|
||
|
|
||
|
|
||
|
static void umax_correct_inquiry(Umax_Device *dev, char *vendor, char *product, char *version)
|
||
|
{
|
||
|
if (!strncmp(vendor, "UMAX ", 5))
|
||
|
{
|
||
|
if (!strncmp(product, "Astra 600S ", 11))
|
||
|
{
|
||
|
int add_len = get_inquiry_additional_length(dev->buffer);
|
||
|
if (add_len == 0x8f)
|
||
|
{
|
||
|
DBG(DBG_warning,"correcting wrong inquiry data\n");
|
||
|
umax_do_new_inquiry(dev, 0x9b); /* get inquiry with correct length */
|
||
|
set_inquiry_length(dev->buffer, 0x9e); /* correct inquiry len */
|
||
|
/* correct color-ordering from pixel to line_with_ccd_distance */
|
||
|
set_inquiry_color_order(dev->buffer, IN_color_ordering_line_w_ccd);
|
||
|
set_inquiry_fb_uta_line_arrangement_mode(dev->buffer, 32);
|
||
|
set_inquiry_CCD_line_distance(dev->buffer, 8);
|
||
|
/* we should reset ADF-bit here too */
|
||
|
|
||
|
#ifdef PREVIEW_FIX_ON
|
||
|
dev->RGB_PREVIEW_FIX = 1;
|
||
|
DBG(DBG_warning,"activating preview fix\n");
|
||
|
#endif
|
||
|
DBG(DBG_warning,"activating inversion of shading data\n");
|
||
|
dev->shading_type = SHADING_TYPE_AVERAGE_INVERT; /* shading type = average value and invert */
|
||
|
}
|
||
|
}
|
||
|
else if (!strncmp(product, "Astra 610S ", 11))
|
||
|
{
|
||
|
int add_len = get_inquiry_additional_length(dev->buffer);
|
||
|
if (add_len == 0x8f)
|
||
|
{
|
||
|
DBG(DBG_warning,"correcting wrong inquiry data\n");
|
||
|
umax_do_new_inquiry(dev, 0x9b); /* get inquiry with correct length */
|
||
|
set_inquiry_length(dev->buffer, 0x9e); /* correct inquiry len */
|
||
|
/* correct color-ordering from pixel to line_with_ccd_distance */
|
||
|
set_inquiry_color_order(dev->buffer, IN_color_ordering_line_w_ccd);
|
||
|
set_inquiry_fb_uta_line_arrangement_mode(dev->buffer, 33);
|
||
|
set_inquiry_CCD_line_distance(dev->buffer, 8);
|
||
|
|
||
|
#ifdef PREVIEW_FIX_ON
|
||
|
dev->RGB_PREVIEW_FIX = 1;
|
||
|
DBG(DBG_warning,"activating preview fix\n");
|
||
|
#endif
|
||
|
DBG(DBG_warning,"activating inversion of shading data\n");
|
||
|
dev->shading_type = SHADING_TYPE_AVERAGE_INVERT; /* shading type = average value and invert */
|
||
|
}
|
||
|
}
|
||
|
else if ( (!strncmp(product, "Vista-S6E ", 9)) ||
|
||
|
(!strncmp(product, "UMAX S-6E ", 9)) ||
|
||
|
(!strncmp(product, "UMAX S-6EG ", 10)) )
|
||
|
{
|
||
|
#ifdef PREVIEW_FIX_ON
|
||
|
dev->RGB_PREVIEW_FIX = 1;
|
||
|
DBG(DBG_warning,"activating preview fix\n");
|
||
|
#endif
|
||
|
DBG(DBG_warning,"activating inversion of shading data\n");
|
||
|
dev->shading_type = SHADING_TYPE_AVERAGE_INVERT; /* shading type = average value and invert */
|
||
|
}
|
||
|
else if (!strncmp(product, "UC1260 ", 7))
|
||
|
{
|
||
|
DBG(DBG_warning,"setting gamma download curve format to type 1\n");
|
||
|
dev->inquiry_gamma_DCF = 1; /* define gamma download curve format */
|
||
|
}
|
||
|
else if (!strncmp(product, "UC1200S ", 8))
|
||
|
{
|
||
|
DBG(DBG_warning,"setting gamma download curve format to type 1\n");
|
||
|
dev->inquiry_gamma_DCF = 1; /* define gamma download curve format */
|
||
|
}
|
||
|
else if (!strncmp(product, "UC1200SE ", 9))
|
||
|
{
|
||
|
DBG(DBG_warning,"setting gamma download curve format to type 0\n");
|
||
|
dev->inquiry_gamma_DCF = 0; /* define gamma download curve format */
|
||
|
}
|
||
|
else if (!strncmp(product, "ARCUS PLUS ", 11))
|
||
|
{
|
||
|
DBG(DBG_warning,"setting gamma download curve format to type 0\n");
|
||
|
dev->inquiry_gamma_DCF = 0; /* define gamma download curve format */
|
||
|
}
|
||
|
|
||
|
#ifdef SANE_UMAX_DEBUG_S12
|
||
|
else if (!strncmp(product, "UMAX S-12G ", 11))
|
||
|
{
|
||
|
DBG(DBG_error,"changing inquiry data for UMAX S-12G\n");
|
||
|
set_inquiry_color_order(dev->buffer, IN_color_ordering_line_w_ccd);
|
||
|
}
|
||
|
DBG(DBG_warning,"activating inversion of shading data\n");
|
||
|
dev->shading_type = SHADING_TYPE_AVERAGE_INVERT; /* shading type = average value and invert */
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX IDENTIFY SCANNER ---------------------- */
|
||
|
|
||
|
|
||
|
static int umax_identify_scanner(Umax_Device *dev)
|
||
|
{
|
||
|
char vendor[9];
|
||
|
char product[0x11];
|
||
|
char version[5];
|
||
|
char *pp;
|
||
|
|
||
|
DBG(DBG_proc,"identify_scanner\n");
|
||
|
umax_do_inquiry(dev); /* get inquiry */
|
||
|
if (get_inquiry_periph_devtype(dev->buffer) != IN_periph_devtype_scanner) { return 1; } /* no scanner */
|
||
|
|
||
|
get_inquiry_vendor( (char *)dev->buffer, vendor);
|
||
|
get_inquiry_product((char *)dev->buffer, product);
|
||
|
get_inquiry_version((char *)dev->buffer, version);
|
||
|
|
||
|
pp = &vendor[8];
|
||
|
vendor[8] = ' '; /* leave one blank at the end! */
|
||
|
while (*(pp-1) == ' ')
|
||
|
{ *pp-- = '\0'; }
|
||
|
|
||
|
pp = &product[0x10];
|
||
|
product[0x10] = ' '; /* leave one blank at the end! */
|
||
|
while (*(pp-1) == ' ')
|
||
|
{ *pp-- = '\0'; }
|
||
|
|
||
|
pp = &version[4];
|
||
|
version[4] = ' ';
|
||
|
while (*pp == ' ')
|
||
|
{ *pp-- = '\0'; }
|
||
|
|
||
|
DBG(DBG_info, "Found %s scanner %sversion %s on device %s\n", vendor, product, version, dev->devicename);
|
||
|
|
||
|
/* look for scanners that do not give all inquiry-informations */
|
||
|
/* and if possible use driver-known inquiry-data */
|
||
|
|
||
|
if (get_inquiry_additional_length(dev->buffer)>=0x8f)
|
||
|
{
|
||
|
int i = 0;
|
||
|
while (strncmp("END_OF_LIST", scanner_str[2*i], 11) != 0) /* Now identify full supported scanners */
|
||
|
{
|
||
|
if (!strncmp(vendor, scanner_str[2*i], strlen(scanner_str[2*i])) )
|
||
|
{
|
||
|
if (!strncmp(product, scanner_str[2*i+1], strlen(scanner_str[2*i+1])) )
|
||
|
{
|
||
|
umax_correct_inquiry(dev,vendor,product,version);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (strncmp(vendor, "UMAX ", 5)) { return 1; } /* not UMAX then abort */
|
||
|
|
||
|
DBG(DBG_error0, "WARNING: %s scanner %s version %s on device %s\n"
|
||
|
"is currently an unrecognized device, but inquiry seems to be ok.\n"
|
||
|
"******************************************************************\n"
|
||
|
"*** !!!! CONTINUE AT YOUR OWN RISK !!!! ***\n"
|
||
|
"******************************************************************\n"
|
||
|
"Please contact Oliver.Rauch@Wolfsburg.DE\n",
|
||
|
vendor, product, version, dev->devicename);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
else /* inquiry-data not complete */
|
||
|
if (!strncmp(vendor, "UMAX ", 5)) /* test UMAX-scanners with short inquiry */
|
||
|
{
|
||
|
inquiry_blk inq_data;
|
||
|
int i;
|
||
|
|
||
|
for(i=0; i<known_inquiry; i++)
|
||
|
{
|
||
|
inq_data = *inquiry_table[i];
|
||
|
if (!strncmp(product, inq_data.scanner, strlen(inq_data.scanner)))
|
||
|
{
|
||
|
DBG(DBG_warning, "inquiry-block-length: %d\n"
|
||
|
"using driver-internal inquiry-data for this scanner!\n",
|
||
|
get_inquiry_additional_length(dev->buffer)+5);
|
||
|
|
||
|
/* copy driver-defined inquiry-data into inquiry-block */
|
||
|
memcpy( dev->buffer+0x24, inq_data.inquiry, inq_data.inquiry_len-0x24);
|
||
|
|
||
|
set_inquiry_length(dev->buffer,inq_data.inquiry_len);
|
||
|
|
||
|
return 0; /* ok */
|
||
|
}
|
||
|
}
|
||
|
DBG(DBG_error0, "ERROR: %s scanner %s version %s on device %s\n"
|
||
|
"is currently an unrecognized device, and inquiry is too short,\n"
|
||
|
"so we are not able to continue!\n"
|
||
|
"Please contact Oliver.Rauch@Wolfsburg.DE\n",
|
||
|
vendor, product, version, dev->devicename);
|
||
|
}
|
||
|
|
||
|
return 1; /* NO SUPPORTED SCANNER: short inquiry-block and unknown scanner */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX TRIM BUFSIZE -------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_trim_rowbufsize(Umax_Device *dev)
|
||
|
{
|
||
|
unsigned int lines=0;
|
||
|
|
||
|
if (dev->row_bufsize > dev->row_len)
|
||
|
{
|
||
|
lines = dev->row_bufsize / dev->row_len;
|
||
|
dev->row_bufsize = lines * dev->row_len;
|
||
|
}
|
||
|
|
||
|
DBG(DBG_proc,"trim_rowbufsize: row_bufsize = %d bytes = %d lines\n",dev->row_bufsize, lines);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX CALCULATE EXPOSURE TIME --------------- */
|
||
|
|
||
|
|
||
|
static void umax_calculate_exposure_time(Umax_Device *dev, int def,int *value)
|
||
|
{
|
||
|
int level;
|
||
|
|
||
|
DBG(DBG_proc,"calculate_exposure_time\n");
|
||
|
if ( (*value))
|
||
|
{
|
||
|
if ( (*value) == -1 ) { (*value) = def; }
|
||
|
else
|
||
|
{
|
||
|
level = (*value) / dev->inquiry_exposure_time_step_unit;
|
||
|
(*value) = inrange(dev->use_exposure_time_min, level, dev->inquiry_exposure_time_max);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX CHECK VALUES -------------------------- */
|
||
|
|
||
|
|
||
|
static int umax_check_values(Umax_Device *dev)
|
||
|
{
|
||
|
double inquiry_width;
|
||
|
double inquiry_length;
|
||
|
|
||
|
DBG(DBG_proc,"check_values\n");
|
||
|
|
||
|
/* ------------------------------- flatbed ------------------------------- */
|
||
|
|
||
|
dev->module = WD_module_flatbed; /* reset scanmode to flatbed first */
|
||
|
|
||
|
/* --------------------------------- uta --------------------------------- */
|
||
|
|
||
|
if (dev->uta != 0)
|
||
|
{
|
||
|
dev->module = WD_module_transparency;
|
||
|
if ( (dev->inquiry_uta == 0) || (dev->inquiry_transavail == 0) )
|
||
|
{
|
||
|
DBG(DBG_error, "ERROR: TRANSPARENCY-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* --------------------------------- adf --------------------------------- */
|
||
|
|
||
|
if (dev->adf != 0)
|
||
|
{
|
||
|
if (dev->inquiry_adf == 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: ADF-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* --------------------------------- dor --------------------------------- */
|
||
|
|
||
|
if (dev->dor != 0)
|
||
|
{
|
||
|
if (dev->inquiry_dor == 0)
|
||
|
{
|
||
|
DBG(DBG_error, "ERROR: double optical resolution not supported by scanner\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ------------------------------- resolution ------------------------ */
|
||
|
|
||
|
if (dev->x_resolution <= 0)
|
||
|
{ DBG(DBG_error,"ERROR: no x-resolution given\n"); return(1); }
|
||
|
|
||
|
if (dev->x_resolution > dev->inquiry_x_res)
|
||
|
{ dev->x_resolution = dev->inquiry_x_res; }
|
||
|
|
||
|
if (dev->x_resolution > dev->inquiry_optical_res)
|
||
|
{ dev->scale_x = 2; }
|
||
|
else
|
||
|
{ dev->scale_x = 1; }
|
||
|
|
||
|
if (dev->y_resolution <= 0)
|
||
|
{ DBG(DBG_error,"ERROR: no y-resolution given\n"); return(1); }
|
||
|
|
||
|
if (dev->y_resolution > dev->inquiry_y_res)
|
||
|
{ dev->y_resolution = dev->inquiry_y_res; }
|
||
|
|
||
|
if (dev->y_resolution > dev->inquiry_optical_res)
|
||
|
{ dev->scale_y = 2; }
|
||
|
else if (dev->y_resolution > dev->inquiry_optical_res / 2)
|
||
|
{ dev->scale_y = 1; }
|
||
|
else
|
||
|
{ dev->scale_y = 0.5; }
|
||
|
|
||
|
|
||
|
/* ------------------------------- scanarea ------------------------ */
|
||
|
|
||
|
if (dev->module == WD_module_flatbed) /* flatbed width */
|
||
|
{
|
||
|
inquiry_width = dev->inquiry_fb_width;
|
||
|
inquiry_length = dev->inquiry_fb_length;
|
||
|
}
|
||
|
else /* transparency width */
|
||
|
{
|
||
|
inquiry_width = dev->inquiry_uta_width;
|
||
|
inquiry_length = dev->inquiry_uta_length;
|
||
|
}
|
||
|
|
||
|
if (dev->dor != 0)
|
||
|
{
|
||
|
inquiry_width = dev->inquiry_dor_width; /* dor width */
|
||
|
inquiry_length = dev->inquiry_dor_length;
|
||
|
}
|
||
|
|
||
|
if ((inquiry_width > 0) && (inquiry_length > 0))
|
||
|
{
|
||
|
dev->maxwidth = inquiry_width * dev->x_coordinate_base;
|
||
|
dev->maxlength = inquiry_length * dev->y_coordinate_base;
|
||
|
}
|
||
|
/* limit the size to what the scanner can scan. */
|
||
|
/* this is particularly important because the scanners don't have */
|
||
|
/* built-in checks and will happily grind their gears if this is exceeded. */
|
||
|
{
|
||
|
int maxwidth;
|
||
|
|
||
|
maxwidth = dev->maxwidth - dev->upper_left_x - 1;
|
||
|
if ( (dev->scanwidth <= 0) || (dev->scanwidth > maxwidth) )
|
||
|
{ dev->scanwidth = maxwidth; }
|
||
|
}
|
||
|
|
||
|
{
|
||
|
int maxlength;
|
||
|
|
||
|
maxlength = dev->maxlength - dev->upper_left_y - 1;
|
||
|
if ( (dev->scanlength <= 0) || (dev->scanlength > maxlength) )
|
||
|
{ dev->scanlength = maxlength; }
|
||
|
}
|
||
|
/* Now calculate width in pixels */
|
||
|
{
|
||
|
int resolutionbase, intwidth_inch, intwidth_pixel, diffwidth, pixels, toomuch, del, pix;
|
||
|
|
||
|
resolutionbase = dev->inquiry_optical_res * dev->scale_x;
|
||
|
|
||
|
intwidth_inch = dev->scanwidth / dev->x_coordinate_base;
|
||
|
intwidth_pixel = intwidth_inch * dev->x_resolution;
|
||
|
|
||
|
diffwidth = dev->scanwidth % dev->x_coordinate_base;
|
||
|
del = resolutionbase - dev->x_resolution;
|
||
|
pixels = diffwidth * resolutionbase / dev->x_coordinate_base;
|
||
|
toomuch = 0;
|
||
|
|
||
|
if (del != 0)
|
||
|
{
|
||
|
pix = 0;
|
||
|
while (pix<=pixels)
|
||
|
{
|
||
|
toomuch++;
|
||
|
pix = toomuch * resolutionbase/del;
|
||
|
}
|
||
|
toomuch--;
|
||
|
}
|
||
|
|
||
|
dev->width_in_pixels = intwidth_pixel + pixels - toomuch;
|
||
|
dev->length_in_pixels = dev->scanlength * dev->y_resolution / dev->y_coordinate_base;
|
||
|
}
|
||
|
|
||
|
if ((dev->scanwidth <= 0) || (dev->scanlength <= 0))
|
||
|
{ DBG(DBG_error,"ERROR: scanwidth or scanlength not given\n"); return(1); }
|
||
|
|
||
|
if (dev->bits_per_pixel_code == 1)
|
||
|
{ dev->bytes_per_color = 1; }
|
||
|
else
|
||
|
{ dev->bytes_per_color = 2; }
|
||
|
|
||
|
switch(dev->colormode)
|
||
|
{
|
||
|
case LINEART:
|
||
|
dev->width_in_pixels -= dev->width_in_pixels % 8;
|
||
|
dev->row_len = (dev->width_in_pixels / 8);
|
||
|
break;
|
||
|
|
||
|
case HALFTONE:
|
||
|
dev->width_in_pixels -= dev->width_in_pixels % 8;
|
||
|
dev->row_len = (dev->width_in_pixels / 8);
|
||
|
break;
|
||
|
|
||
|
case GRAYSCALE:
|
||
|
dev->row_len = dev->width_in_pixels * dev->bytes_per_color;
|
||
|
break;
|
||
|
|
||
|
case RGB_LINEART:
|
||
|
case RGB_HALFTONE:
|
||
|
if (dev->three_pass)
|
||
|
{ dev->row_len = dev->width_in_pixels / 8 ; }
|
||
|
else
|
||
|
{ dev->row_len = (dev->width_in_pixels / 8 ) * 3; }
|
||
|
break;
|
||
|
|
||
|
case RGB:
|
||
|
if (dev->three_pass) /* three (24bpp) or six (30bpp) bytes per pixel */
|
||
|
{ dev->row_len = dev->width_in_pixels * dev->bytes_per_color; }
|
||
|
else
|
||
|
{ dev->row_len = dev->width_in_pixels * 3 * dev->bytes_per_color; }
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------- wdb length ------------------------ */
|
||
|
|
||
|
if (dev->wdb_len <= 0)
|
||
|
{
|
||
|
dev->wdb_len = dev->inquiry_wdb_len;
|
||
|
if (dev->wdb_len <= 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: wdb-length not given\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dev->wdb_len > used_WDB_size)
|
||
|
{
|
||
|
DBG(DBG_warning,"WARNING:window descriptor block too long, will be shortned!\n");
|
||
|
dev->wdb_len = used_WDB_size;
|
||
|
}
|
||
|
|
||
|
/* ----------------------------- cbhs-range ----------------------------- */
|
||
|
|
||
|
dev->threshold = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->threshold , dev->inquiry_cbhs_max);
|
||
|
dev->contrast = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->contrast , dev->inquiry_cbhs_max);
|
||
|
dev->brightness = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->brightness, dev->inquiry_cbhs_max);
|
||
|
|
||
|
dev->highlight_r = umax_cbhs_correct(dev->inquiry_cbhs_min+1, dev->highlight_r, dev->inquiry_cbhs_max);
|
||
|
dev->highlight_g = umax_cbhs_correct(dev->inquiry_cbhs_min+1, dev->highlight_g, dev->inquiry_cbhs_max);
|
||
|
dev->highlight_b = umax_cbhs_correct(dev->inquiry_cbhs_min+1, dev->highlight_b, dev->inquiry_cbhs_max);
|
||
|
|
||
|
dev->shadow_r = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->shadow_r, dev->inquiry_cbhs_max-1);
|
||
|
dev->shadow_g = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->shadow_g, dev->inquiry_cbhs_max-1);
|
||
|
dev->shadow_b = umax_cbhs_correct(dev->inquiry_cbhs_min, dev->shadow_b, dev->inquiry_cbhs_max-1);
|
||
|
|
||
|
if (dev->shadow_r >= dev->highlight_r) { dev->shadow_r = dev->highlight_r-1; }
|
||
|
if (dev->shadow_g >= dev->highlight_g) { dev->shadow_g = dev->highlight_g-1; }
|
||
|
if (dev->shadow_b >= dev->highlight_b) { dev->shadow_b = dev->highlight_b-1; }
|
||
|
|
||
|
/* ----------------------- quality calibration and preview -------------- */
|
||
|
|
||
|
if (dev->inquiry_preview == 0)
|
||
|
{
|
||
|
if (dev->preview)
|
||
|
{
|
||
|
DBG(DBG_warning, "WARNING: fast preview function not supported by scanner\n");
|
||
|
dev->preview = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dev->inquiry_quality_ctrl == 0)
|
||
|
{
|
||
|
if (dev->quality)
|
||
|
{
|
||
|
DBG(DBG_warning, "WARNING: quality calibration not supported by scanner\n");
|
||
|
dev->quality = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dev->calib_lines = dev->inquiry_max_calib_lines;
|
||
|
if (dev->preview != 0) { dev->quality = 0; } /* do not use quality calibration in preview mode */
|
||
|
}
|
||
|
|
||
|
/* --------------------------- lamp intensity control ------------------- */
|
||
|
|
||
|
if (dev->inquiry_lamp_ctrl == 0)
|
||
|
{
|
||
|
if (dev->c_density || dev->s_density)
|
||
|
{ DBG(DBG_warning, "WARNING: scanner doesn't support lamp intensity control\n"); }
|
||
|
dev->c_density = dev->s_density = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --------------------------- reverse (negative) ----------------------- */
|
||
|
|
||
|
if (dev->reverse != 0)
|
||
|
{
|
||
|
if ( (dev->colormode == LINEART) || (dev->colormode == HALFTONE) ||
|
||
|
(dev->colormode == RGB_LINEART) || (dev->colormode == RGB_HALFTONE) )
|
||
|
{
|
||
|
if (dev->inquiry_reverse == 0)
|
||
|
{
|
||
|
DBG(DBG_error, "ERROR: reverse for bi-level-image not supported\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ dev->reverse = 0; }
|
||
|
}
|
||
|
|
||
|
if (dev->reverse_multi != 0)
|
||
|
{
|
||
|
if ((dev->colormode == RGB) || (dev->colormode == GRAYSCALE) )
|
||
|
{
|
||
|
if (dev->inquiry_reverse_multi == 0)
|
||
|
{
|
||
|
DBG(DBG_error, "ERROR: reverse for multi-level-image not supported\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ dev->reverse_multi = 0; }
|
||
|
}
|
||
|
|
||
|
/* ----------------------------- analog gamma ---------------------------- */
|
||
|
|
||
|
if (dev->inquiry_analog_gamma == 0)
|
||
|
{
|
||
|
if (dev->analog_gamma_r + dev->analog_gamma_g + dev->analog_gamma_b != 0)
|
||
|
{ DBG(DBG_warning,"WARNING: analog gamma correction not supported by scanner!\n"); }
|
||
|
dev->analog_gamma_r = dev->analog_gamma_g = dev->analog_gamma_b = 0;
|
||
|
}
|
||
|
|
||
|
/* ---------------------------- digital gamma ---------------------------- */
|
||
|
|
||
|
if ( (dev->digital_gamma_r == 0) || (dev->digital_gamma_g == 0) ||
|
||
|
(dev->digital_gamma_b == 0) )
|
||
|
{
|
||
|
if (dev->inquiry_gamma_dwload == 0)
|
||
|
{
|
||
|
DBG(DBG_warning, "WARNING: gamma download not available\n");
|
||
|
dev->digital_gamma_r = dev->digital_gamma_g = dev->digital_gamma_b = 15;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ---------------------------- speed and smear ------------------------- */
|
||
|
|
||
|
#if 0
|
||
|
if (dev->slow != 0)
|
||
|
{dev->WD_speed = WD_speed_slow;}
|
||
|
else
|
||
|
{dev->WD_speed = WD_speed_fast;}
|
||
|
|
||
|
if (dev->smear != 0) {dev->WD_speed += WD_speed_smear;}
|
||
|
#endif
|
||
|
|
||
|
dev->WD_speed = WD_speed_fast; /* info from umax: only use this value */
|
||
|
|
||
|
/* ---------------------- test bits per pixel --------------------------- */
|
||
|
|
||
|
if ( ( (dev->inquiry_GIB | 1) & dev->gamma_input_bits_code) == 0 )
|
||
|
{
|
||
|
DBG(DBG_warning,"WARNING: selected gamma input bits not supported, gamma ignored\n");
|
||
|
dev->gamma_input_bits_code = 1;
|
||
|
dev->digital_gamma_r = dev->digital_gamma_g = dev->digital_gamma_b = 15;
|
||
|
}
|
||
|
|
||
|
if ( ( (dev->inquiry_GOB | 1) & dev->bits_per_pixel_code) == 0 )
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: selected bits per pixel not supported\n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
/* ----------------------- scan mode dependencies ------------------------ */
|
||
|
|
||
|
switch(dev->colormode)
|
||
|
{
|
||
|
case LINEART: /* ------------ LINEART ------------- */
|
||
|
case RGB_LINEART: /* ---------- RGB_LINEART ----------- */
|
||
|
dev->use_exposure_time_min = dev->inquiry_exposure_time_l_min;
|
||
|
if (dev->module == WD_module_flatbed)
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_l_fb_def; }
|
||
|
else
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_l_uta_def; }
|
||
|
if (dev->inquiry_lineart == 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: LINEART-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case HALFTONE: /* ----------- HALFTONE------------ */
|
||
|
case RGB_HALFTONE: /* --------- RGB_HALFTONE---------- */
|
||
|
dev->use_exposure_time_min = dev->inquiry_exposure_time_h_min;
|
||
|
if (dev->module == WD_module_flatbed)
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_h_fb_def; }
|
||
|
else
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_h_uta_def; }
|
||
|
if (dev->inquiry_halftone == 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: HALFTONE-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case GRAYSCALE: /* ---------- GRAYSCALE ------------- */
|
||
|
dev->use_exposure_time_min = dev->inquiry_exposure_time_g_min;
|
||
|
if (dev->module == WD_module_flatbed)
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_g_fb_def; }
|
||
|
else
|
||
|
{ dev->use_exposure_time_def_r = dev->inquiry_exposure_time_g_uta_def; }
|
||
|
if (dev->inquiry_gray == 0)
|
||
|
{
|
||
|
DBG(DBG_error, "ERROR: GRAYSCALE-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RGB: /* ----------------- COLOR ---------- */
|
||
|
dev->use_exposure_time_min = dev->inquiry_exposure_time_c_min;
|
||
|
if (dev->module == WD_module_flatbed)
|
||
|
{
|
||
|
dev->use_exposure_time_def_r = dev->inquiry_exposure_time_c_fb_def_r;
|
||
|
dev->use_exposure_time_def_g = dev->inquiry_exposure_time_c_fb_def_g;
|
||
|
dev->use_exposure_time_def_b = dev->inquiry_exposure_time_c_fb_def_b;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dev->use_exposure_time_def_r = dev->inquiry_exposure_time_c_uta_def_r;
|
||
|
dev->use_exposure_time_def_g = dev->inquiry_exposure_time_c_uta_def_g;
|
||
|
dev->use_exposure_time_def_b = dev->inquiry_exposure_time_c_uta_def_b;
|
||
|
}
|
||
|
|
||
|
if (dev->inquiry_color == 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: COLOR-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
if (dev->inquiry_one_pass_color)
|
||
|
{
|
||
|
DBG(DBG_info,"using one pass scanning mode\n");
|
||
|
|
||
|
if (dev->inquiry_color_order & IN_color_ordering_pixel)
|
||
|
{
|
||
|
DBG(DBG_info,"scanner uses color-pixel-ordering\n");
|
||
|
}
|
||
|
else if (dev->inquiry_color_order & IN_color_ordering_line_no_ccd)
|
||
|
{
|
||
|
dev->CCD_distance = 0;
|
||
|
dev->do_color_ordering = 1;
|
||
|
DBG(DBG_info,"scanner uses color-line-ordering without CCD-distance\n");
|
||
|
}
|
||
|
else if (dev->inquiry_color_order & IN_color_ordering_line_w_ccd)
|
||
|
{
|
||
|
dev->CCD_distance = dev->inquiry_CCD_line_distance;
|
||
|
dev->do_color_ordering = 1;
|
||
|
switch (dev->inquiry_fb_uta_color_arrangement) /* define color order for line ordering */
|
||
|
{
|
||
|
case 1:
|
||
|
dev->CCD_color[0] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_blue;
|
||
|
dev->CCD_color[2] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_blue;
|
||
|
dev->CCD_color[4] = CCD_color_red;
|
||
|
dev->CCD_color[5] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_blue;
|
||
|
dev->CCD_color[7] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_red;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
dev->CCD_color[0] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_green;
|
||
|
dev->CCD_color[2] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_green;
|
||
|
dev->CCD_color[4] = CCD_color_red;
|
||
|
dev->CCD_color[5] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_green;
|
||
|
dev->CCD_color[7] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_red;
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
dev->CCD_color[0] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_blue;
|
||
|
dev->CCD_color[2] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_blue;
|
||
|
dev->CCD_color[4] = CCD_color_green;
|
||
|
dev->CCD_color[5] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_blue;
|
||
|
dev->CCD_color[7] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_green;
|
||
|
break;
|
||
|
|
||
|
case 4: /* may be wrong !!! */
|
||
|
dev->CCD_color[0] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_green;
|
||
|
dev->CCD_color[2] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_green;
|
||
|
dev->CCD_color[4] = CCD_color_red;
|
||
|
dev->CCD_color[5] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_green;
|
||
|
dev->CCD_color[7] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_blue;
|
||
|
break;
|
||
|
|
||
|
case 32: /* not defined from UMAX, for Astra 600S */
|
||
|
dev->CCD_color[0] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_green;
|
||
|
dev->CCD_color[2] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_green;
|
||
|
dev->CCD_color[4] = CCD_color_red;
|
||
|
dev->CCD_color[5] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_red;
|
||
|
dev->CCD_color[7] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_red;
|
||
|
break;
|
||
|
|
||
|
case 33: /* not defined from UMAX, for Astra 610S */
|
||
|
dev->CCD_color[0] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_red;
|
||
|
dev->CCD_color[2] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_red;
|
||
|
dev->CCD_color[4] = CCD_color_green;
|
||
|
dev->CCD_color[5] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_green;
|
||
|
dev->CCD_color[7] = CCD_color_blue;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_green;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
dev->CCD_color[0] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[1] = CCD_color_blue;
|
||
|
dev->CCD_color[2] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[3] = CCD_color_blue;
|
||
|
dev->CCD_color[4] = CCD_color_red;
|
||
|
dev->CCD_color[5] = CCD_color_green;
|
||
|
|
||
|
dev->CCD_color[6] = CCD_color_blue;
|
||
|
dev->CCD_color[7] = CCD_color_red;
|
||
|
|
||
|
dev->CCD_color[8] = CCD_color_red;
|
||
|
}
|
||
|
DBG(DBG_info,"scanner uses color-line-ordering with CCD-distance of %d lines\n", dev->CCD_distance);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: AVAILABLE COLOR-ORDERING-TYPES NOT SUPPORTED, ABORTING\n");
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_info,"using three pass scanning mode\n");
|
||
|
dev->three_pass=1;
|
||
|
}
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
/* ----------------------------- color ordering ------------------------ */
|
||
|
|
||
|
if (dev->do_color_ordering != 0)
|
||
|
{
|
||
|
if ( (dev->colormode != RGB) || (dev->three_pass != 0) )
|
||
|
{ dev->do_color_ordering = 0; } /* color ordering not necessery */
|
||
|
}
|
||
|
|
||
|
/* ------------------------------- exposure ----------------------------- */
|
||
|
|
||
|
if ( dev->inquiry_exposure_adj )
|
||
|
{
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_r, &dev->exposure_time_calibration_r);
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_g, &dev->exposure_time_calibration_g);
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_b, &dev->exposure_time_calibration_b);
|
||
|
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_r, &dev->exposure_time_scan_r);
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_g, &dev->exposure_time_scan_g);
|
||
|
umax_calculate_exposure_time(dev, dev->use_exposure_time_def_b, &dev->exposure_time_scan_b);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dev->exposure_time_calibration_r = dev->exposure_time_calibration_g = dev->exposure_time_calibration_b =
|
||
|
dev->exposure_time_scan_r = dev->exposure_time_scan_g = dev->exposure_time_scan_b = 0;
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX GET INQUIRY VALUES -------------------- */
|
||
|
|
||
|
|
||
|
static void umax_get_inquiry_values(Umax_Device *dev)
|
||
|
{
|
||
|
unsigned char * inquiry_block;
|
||
|
|
||
|
DBG(DBG_proc,"get_inquiry_values\n");
|
||
|
|
||
|
inquiry_block = dev->buffer;
|
||
|
dev->inquiry_len = get_inquiry_additional_length(dev->buffer)+5;
|
||
|
dev->cbhs_range = dev->inquiry_cbhs = get_inquiry_CBHS(inquiry_block);
|
||
|
|
||
|
if (dev->cbhs_range > IN_CBHS_255)
|
||
|
{ dev->cbhs_range = IN_CBHS_255; }
|
||
|
|
||
|
if (dev->cbhs_range == IN_CBHS_50)
|
||
|
{
|
||
|
dev->inquiry_cbhs_min = 78;
|
||
|
dev->inquiry_cbhs_max = 178;
|
||
|
}
|
||
|
|
||
|
get_inquiry_vendor( (char *)inquiry_block, dev->vendor); dev->vendor[8] ='\0';
|
||
|
get_inquiry_product((char *)inquiry_block, dev->product); dev->product[16]='\0';
|
||
|
get_inquiry_version((char *)inquiry_block, dev->version); dev->version[4] ='\0';
|
||
|
|
||
|
dev->inquiry_quality_ctrl = get_inquiry_fw_quality(inquiry_block);
|
||
|
dev->inquiry_preview = get_inquiry_fw_fast_preview(inquiry_block);
|
||
|
dev->inquiry_lamp_ctrl = get_inquiry_fw_lamp_int_cont(inquiry_block);
|
||
|
dev->inquiry_calibration = get_inquiry_fw_calibration(inquiry_block);
|
||
|
dev->inquiry_transavail = get_inquiry_transavail(inquiry_block);
|
||
|
dev->inquiry_adfmode = get_inquiry_scanmode(inquiry_block);
|
||
|
|
||
|
if (dev->inquiry_len<=0x8f)
|
||
|
{ DBG(DBG_warning, "WARNING: inquiry return block is unexpected short.\n"); }
|
||
|
|
||
|
dev->inquiry_uta = get_inquiry_sc_uta(inquiry_block);
|
||
|
dev->inquiry_adf = get_inquiry_sc_adf(inquiry_block);
|
||
|
|
||
|
dev->inquiry_one_pass_color = get_inquiry_sc_one_pass_color(inquiry_block);
|
||
|
dev->inquiry_three_pass_color = get_inquiry_sc_three_pass_color(inquiry_block);
|
||
|
dev->inquiry_color = get_inquiry_sc_color(inquiry_block);
|
||
|
dev->inquiry_gray = get_inquiry_sc_gray(inquiry_block);
|
||
|
dev->inquiry_halftone = get_inquiry_sc_halftone(inquiry_block);
|
||
|
dev->inquiry_lineart = get_inquiry_sc_lineart(inquiry_block);
|
||
|
|
||
|
dev->inquiry_exposure_adj = get_inquiry_fw_adjust_exposure_tf(inquiry_block);
|
||
|
dev->inquiry_exposure_time_step_unit = get_inquiry_exposure_time_step_unit(inquiry_block);
|
||
|
dev->inquiry_exposure_time_max = get_inquiry_exposure_time_max(inquiry_block);
|
||
|
|
||
|
/* --- lineart --- */
|
||
|
dev->inquiry_exposure_time_l_min = get_inquiry_exposure_time_lhg_min(inquiry_block);
|
||
|
dev->inquiry_exposure_time_l_fb_def = get_inquiry_exposure_time_lh_def_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_l_uta_def = get_inquiry_exposure_time_lh_def_uta(inquiry_block);
|
||
|
|
||
|
/* --- halftone --- */
|
||
|
dev->inquiry_exposure_time_h_min = get_inquiry_exposure_time_lhg_min(inquiry_block);
|
||
|
dev->inquiry_exposure_time_h_fb_def = get_inquiry_exposure_time_lh_def_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_h_uta_def = get_inquiry_exposure_time_lh_def_uta(inquiry_block);
|
||
|
|
||
|
/* --- grayscale --- */
|
||
|
dev->inquiry_exposure_time_g_min = get_inquiry_exposure_time_lhg_min(inquiry_block);
|
||
|
dev->inquiry_exposure_time_g_fb_def = get_inquiry_exposure_time_gray_def_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_g_uta_def = get_inquiry_exposure_time_gray_def_uta(inquiry_block);
|
||
|
|
||
|
/* --- color --- */
|
||
|
dev->inquiry_exposure_time_c_min = get_inquiry_exposure_time_color_min(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_fb_def_r = get_inquiry_exposure_time_def_r_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_fb_def_g = get_inquiry_exposure_time_def_g_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_fb_def_b = get_inquiry_exposure_time_def_g_fb(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_uta_def_r = get_inquiry_exposure_time_def_r_uta(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_uta_def_g = get_inquiry_exposure_time_def_g_uta(inquiry_block);
|
||
|
dev->inquiry_exposure_time_c_uta_def_b = get_inquiry_exposure_time_def_b_uta(inquiry_block);
|
||
|
|
||
|
|
||
|
dev->inquiry_dor = get_inquiry_sc_double_res(inquiry_block);
|
||
|
dev->inquiry_reverse = get_inquiry_sc_bi_image_reverse(inquiry_block);
|
||
|
dev->inquiry_reverse_multi = get_inquiry_sc_multi_image_reverse(inquiry_block);
|
||
|
dev->inquiry_shadow = 1 - get_inquiry_sc_no_shadow(inquiry_block);
|
||
|
dev->inquiry_highlight = 1 - get_inquiry_sc_no_highlight(inquiry_block);
|
||
|
dev->inquiry_analog_gamma = get_inquiry_analog_gamma(inquiry_block);
|
||
|
dev->inquiry_gamma_dwload = get_inquiry_gamma_download_available(inquiry_block);
|
||
|
|
||
|
if (get_inquiry_gamma_type_2(inquiry_block) != 0)
|
||
|
{
|
||
|
dev->inquiry_gamma_DCF = 2;
|
||
|
}
|
||
|
|
||
|
dev->inquiry_GIB = get_inquiry_gib(inquiry_block);
|
||
|
dev->inquiry_GOB = get_inquiry_gob(inquiry_block);
|
||
|
dev->inquiry_color_order = get_inquiry_color_order(inquiry_block);
|
||
|
|
||
|
/* optical resolution = [0x73] * 100 + [0x94] , 0x94 is not always defined */
|
||
|
dev->inquiry_optical_res = 100 * get_inquiry_max_opt_res(inquiry_block);
|
||
|
if (dev->inquiry_len >= 0x94)
|
||
|
{
|
||
|
dev->inquiry_optical_res += get_inquiry_optical_resolution_residue(inquiry_block);
|
||
|
}
|
||
|
|
||
|
/* x resolution = [0x74] * 100 + [0x95] , 0x95 is not always defined */
|
||
|
dev->inquiry_x_res = 100*get_inquiry_max_x_res(inquiry_block);
|
||
|
if (dev->inquiry_len >= 0x95)
|
||
|
{ dev->inquiry_x_res+= get_inquiry_x_resolution_residue(inquiry_block); };
|
||
|
|
||
|
/* y resolution = [0x75] * 100 + [0x96] , 0x96 is not always defined */
|
||
|
dev->inquiry_y_res = 100*get_inquiry_max_y_res(inquiry_block);
|
||
|
if (dev->inquiry_len >= 0x96)
|
||
|
{ dev->inquiry_y_res+= get_inquiry_y_resolution_residue(inquiry_block); }
|
||
|
|
||
|
dev->inquiry_fb_width = (double)get_inquiry_fb_max_scan_width(inquiry_block) * 0.01;
|
||
|
dev->inquiry_fb_length = (double)get_inquiry_fb_max_scan_length(inquiry_block) * 0.01;
|
||
|
|
||
|
dev->inquiry_uta_width = (double)get_inquiry_uta_max_scan_width(inquiry_block) * 0.01;
|
||
|
dev->inquiry_uta_length = (double)get_inquiry_uta_max_scan_length(inquiry_block) * 0.01;
|
||
|
|
||
|
dev->inquiry_dor_width = (double)get_inquiry_dor_max_scan_width(inquiry_block) * 0.01;
|
||
|
dev->inquiry_dor_length = (double)get_inquiry_dor_max_scan_length(inquiry_block) * 0.01;
|
||
|
|
||
|
dev->inquiry_max_warmup_time = get_inquiry_lamp_warmup_maximum_time(inquiry_block) * 2;
|
||
|
|
||
|
dev->inquiry_wdb_len = get_inquiry_wdb_length(inquiry_block);
|
||
|
|
||
|
dev->inquiry_max_calib_lines = get_inquiry_max_calibration_data_lines(inquiry_block);
|
||
|
|
||
|
dev->inquiry_fb_uta_color_arrangement = get_inquiry_fb_uta_line_arrangement_mode(inquiry_block);
|
||
|
dev->inquiry_adf_color_arrangement = get_inquiry_adf_line_arrangement_mode(inquiry_block);
|
||
|
dev->inquiry_CCD_line_distance = get_inquiry_CCD_line_distance(inquiry_block);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX CALCULATE ANALOG GAMMA ---------------- */
|
||
|
|
||
|
|
||
|
static int umax_calculate_analog_gamma(double value)
|
||
|
{
|
||
|
int gamma;
|
||
|
|
||
|
if (value < 1.0)
|
||
|
{ value=1.0; }
|
||
|
|
||
|
if (value > 2.0)
|
||
|
{ value=2.0; }
|
||
|
|
||
|
gamma=0; /* select gamma_value from analog_gamma_table */
|
||
|
while (value>analog_gamma_table[gamma]) { gamma++; }
|
||
|
if (gamma)
|
||
|
{
|
||
|
if ((analog_gamma_table[gamma-1] + analog_gamma_table[gamma]) /2 > value)
|
||
|
{ gamma--;}
|
||
|
}
|
||
|
|
||
|
return(gamma);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX READER PROCESS ------------------------ */
|
||
|
|
||
|
|
||
|
static int umax_reader_process(Umax_Device *dev, FILE *fp, unsigned int data_left)
|
||
|
{
|
||
|
int status;
|
||
|
int bytes = 1;
|
||
|
unsigned int data_to_read;
|
||
|
|
||
|
dev->row_bufsize = dev->bufsize;
|
||
|
umax_trim_rowbufsize(dev); /* trim bufsize */
|
||
|
|
||
|
if (dev->bits_per_pixel_code != 1) { bytes = 2; } /* >24 bpp */
|
||
|
|
||
|
DBG(DBG_read,"reading %u bytes in blocks of %u bytes\n", data_left, dev->row_bufsize);
|
||
|
|
||
|
if (dev->pixelbuffer != NULL) /* buffer exists? */
|
||
|
{
|
||
|
free(dev->pixelbuffer);
|
||
|
dev->pixelbuffer = NULL;
|
||
|
}
|
||
|
|
||
|
if (dev->do_color_ordering != 0)
|
||
|
{
|
||
|
DBG(DBG_info,"ordering from line-order to pixel-order\n");
|
||
|
|
||
|
dev->pixelline_max = 3 * dev->CCD_distance * dev->scale_y + 2;
|
||
|
|
||
|
dev->pixelbuffer = malloc(dev->width_in_pixels * dev->pixelline_max * bytes * 3);
|
||
|
|
||
|
if (dev->pixelbuffer == NULL) { return -1; } /* NO MEMORY */
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
data_to_read = (data_left < dev->row_bufsize) ? data_left : dev->row_bufsize;
|
||
|
|
||
|
/* umax_get_data_buffer_status(dev); */
|
||
|
|
||
|
status = umax_read_image_data(dev, data_to_read);
|
||
|
if (status == 0) { continue; }
|
||
|
|
||
|
if (status == -1)
|
||
|
{
|
||
|
DBG(DBG_error,"umax_reader_process: unable to get image data from scanner!\n");
|
||
|
free(dev->pixelbuffer);
|
||
|
dev->pixelbuffer = NULL;
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
if (dev->do_color_ordering == 0) /* pixel ordering */
|
||
|
{
|
||
|
fwrite(dev->buffer, 1, data_to_read, fp);
|
||
|
}
|
||
|
else /* line ordering */
|
||
|
{
|
||
|
unsigned char *linesource = dev->buffer;
|
||
|
unsigned char *pixelsource;
|
||
|
int bytes = 1;
|
||
|
int lines;
|
||
|
int i;
|
||
|
|
||
|
if (dev->bits_per_pixel_code != 1) /* >24 bpp */
|
||
|
{ bytes = 2; }
|
||
|
|
||
|
lines = data_to_read / (dev->width_in_pixels * bytes);
|
||
|
|
||
|
for(i=0; i<lines; i++)
|
||
|
{
|
||
|
umax_order_line(dev, linesource);
|
||
|
linesource += dev->width_in_pixels * bytes;
|
||
|
|
||
|
pixelsource = umax_get_pixel_line(dev);
|
||
|
if (pixelsource != NULL)
|
||
|
{
|
||
|
fwrite(pixelsource, bytes, dev->width_in_pixels * 3, fp);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fflush(fp);
|
||
|
|
||
|
data_left -= data_to_read;
|
||
|
DBG(DBG_read, "reader_process: buffer of %d bytes read; %d bytes to go\n", data_to_read, data_left);
|
||
|
} while (data_left);
|
||
|
|
||
|
free(dev->pixelbuffer);
|
||
|
dev->pixelbuffer = NULL;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX INITIALIZE VALUES --------------------- */
|
||
|
|
||
|
|
||
|
static void umax_initialize_values(Umax_Device *dev) /* called each time before setting scan-values */
|
||
|
{ /* Initialize dev structure */
|
||
|
DBG(DBG_proc,"initialize_values\n");
|
||
|
|
||
|
dev->three_pass = 0; /* 1 if threepas_mode only */
|
||
|
dev->row_len = -1;
|
||
|
dev->max_value = 255; /* maximum value */
|
||
|
|
||
|
dev->wdb_len = 0;
|
||
|
dev->width_in_pixels = 0; /* scan width in pixels */
|
||
|
dev->length_in_pixels = 0; /* scan length in pixels */
|
||
|
dev->maxwidth = 0;
|
||
|
dev->maxlength = 0;
|
||
|
dev->scanwidth = 0; /* width in inch at x_coordinate_base dpi */
|
||
|
dev->scanlength = 0; /* length in inch at y_coordinate_base dpi */
|
||
|
dev->x_resolution = 0;
|
||
|
dev->y_resolution = 0;
|
||
|
dev->upper_left_x = 0; /* at 1200pt/inch */
|
||
|
dev->upper_left_y = 0; /* at 1200pt/inch */
|
||
|
dev->x_coordinate_base = 1200; /* these are the 1200pt/inch */
|
||
|
dev->y_coordinate_base = 1200; /* these are the 1200pt/inch */
|
||
|
dev->bytes_per_color = 0; /* bytes for each color */
|
||
|
|
||
|
dev->bits_per_pixel = 8; /* number of bits per pixel */
|
||
|
dev->bits_per_pixel_code = 1; /* 1 = 8/24 bpp, 2 = 9/27 bpp, 4 = 10/30 bpp */
|
||
|
dev->gamma_input_bits_code = 1; /* 8 = 12/36 bpp, 16 = 14/42 bpp, 32 = 16/48 bpp */
|
||
|
dev->set_auto = 0; /* 0 or 1 */
|
||
|
dev->preview = 0; /* 1 for preview */
|
||
|
dev->quality = 0; /* quality calibration */
|
||
|
dev->warmup = 0; /* warmup-bit */
|
||
|
dev->colormode = 0; /* LINEART,HALFTONE, GRAYSCALE or RGB */
|
||
|
dev->adf = 0; /* 1 if adf shall be used */
|
||
|
dev->uta = 0; /* 1 if uta shall be used */
|
||
|
dev->module = WD_module_flatbed;
|
||
|
dev->cbhs_range = WD_CBHS_255;
|
||
|
dev->dor = 0;
|
||
|
dev->halftone = WD_halftone_8x8_1;
|
||
|
dev->reverse = 0;
|
||
|
dev->reverse_multi = 0;
|
||
|
dev->slow = 0;
|
||
|
dev->smear = 0;
|
||
|
dev->calibration = 0;
|
||
|
|
||
|
dev->exposure_time_calibration_r = 0; /* use this for calibration */
|
||
|
dev->exposure_time_calibration_g = 0; /* use this for calibration */
|
||
|
dev->exposure_time_calibration_b = 0; /* use this for calibration */
|
||
|
dev->exposure_time_scan_r = 0; /* use this for scan */
|
||
|
dev->exposure_time_scan_g = 0; /* use this for scan */
|
||
|
dev->exposure_time_scan_b = 0; /* use this for scan */
|
||
|
|
||
|
dev->c_density = WD_lamp_c_density_auto; /* calibration lamp density */
|
||
|
dev->s_density = WD_lamp_s_density_auto; /* next scan lamp density */
|
||
|
|
||
|
dev->threshold = 128; /* threshold for lineart mode */
|
||
|
dev->brightness = 128; /* brightness for halftone mode */
|
||
|
dev->contrast = 128; /* contrast for halftone mode */
|
||
|
dev->highlight_r = 255; /* highlight gray/red */
|
||
|
dev->highlight_g = 255; /* highlight green */
|
||
|
dev->highlight_b = 255; /* highlight blue */
|
||
|
dev->shadow_r = 0; /* shadow gray/red */
|
||
|
dev->shadow_g = 0; /* shadow green */
|
||
|
dev->shadow_b = 0; /* shadow blue */
|
||
|
|
||
|
dev->digital_gamma_r = WD_gamma_normal;
|
||
|
dev->digital_gamma_g = WD_gamma_normal;
|
||
|
dev->digital_gamma_b = WD_gamma_normal;
|
||
|
|
||
|
dev->analog_gamma_r = 0; /* analog gamma for red and gray to 1.0 */
|
||
|
dev->analog_gamma_g = 0; /* analog gamma for green to 1.0 */
|
||
|
dev->analog_gamma_b = 0; /* analog gamma for blue to 1.0 */
|
||
|
|
||
|
|
||
|
dev->pixelline_ready[0] = 0; /* reset all values for color ordering */
|
||
|
dev->pixelline_ready[1] = 0;
|
||
|
dev->pixelline_ready[2] = 0;
|
||
|
dev->pixelline_next[0] = 0;
|
||
|
dev->pixelline_next[1] = 0;
|
||
|
dev->pixelline_next[2] = 0;
|
||
|
dev->pixelline_del[0] = 1;
|
||
|
dev->pixelline_del[1] = 1;
|
||
|
dev->pixelline_del[2] = 1;
|
||
|
dev->pixelline_optic[0] = 1;
|
||
|
dev->pixelline_optic[1] = 1;
|
||
|
dev->pixelline_optic[2] = 1;
|
||
|
dev->pixelline_max = 0;
|
||
|
dev->pixelline_opt_res = 0;
|
||
|
dev->pixelline_read = 0;
|
||
|
dev->pixelline_written = 0;
|
||
|
dev->CCD_distance = 0;
|
||
|
|
||
|
dev->calib_lines = 0; /* request calibration lines */
|
||
|
dev->do_calibration = 0; /* no calibration by driver */
|
||
|
dev->do_color_ordering = 0; /* no line- to pixel-mode ordering */
|
||
|
|
||
|
dev->button_pressed = 0; /* reset button pressed flag */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ UMAX INIT ---------------------------------- */
|
||
|
|
||
|
|
||
|
static void umax_init(Umax_Device *dev) /* umax_init is called once while driver-initialization */
|
||
|
{ /* you have to test if dev->buffer is != NULL after call umax_init */
|
||
|
DBG(DBG_proc,"init\n");
|
||
|
|
||
|
dev->devicename = NULL;
|
||
|
dev->sfd = -1;
|
||
|
|
||
|
dev->bufsize = sanei_scsi_max_request_size;
|
||
|
dev->buffer = malloc(dev->bufsize); /* allocate buffer */
|
||
|
dev->pixelbuffer = NULL;
|
||
|
|
||
|
dev->inquiry_len = 0;
|
||
|
dev->inquiry_wdb_len = -1;
|
||
|
dev->inquiry_optical_res = -1;
|
||
|
dev->inquiry_x_res = -1;
|
||
|
dev->inquiry_y_res = -1;
|
||
|
dev->inquiry_fb_width = -1;
|
||
|
dev->inquiry_fb_length = -1;
|
||
|
dev->inquiry_uta_width = -1;
|
||
|
dev->inquiry_uta_length = -1;
|
||
|
dev->inquiry_dor_width = -1;
|
||
|
dev->inquiry_dor_length = -1;
|
||
|
dev->inquiry_exposure_adj = 0;
|
||
|
dev->inquiry_exposure_time_step_unit = -1; /* exposure time unit in micro sec */
|
||
|
dev->inquiry_exposure_time_max = -1; /* exposure time maximum */
|
||
|
dev->inquiry_exposure_time_l_min = -1; /* exposure time minimum for lineart */
|
||
|
dev->inquiry_exposure_time_l_fb_def = -1; /* exposure time default for lineart flatbed */
|
||
|
dev->inquiry_exposure_time_l_uta_def = -1; /* exposure time default for lineart uta */
|
||
|
dev->inquiry_exposure_time_h_min = -1; /* exposure time minimum for halftone */
|
||
|
dev->inquiry_exposure_time_h_fb_def = -1; /* exposure time default for halftone flatbed */
|
||
|
dev->inquiry_exposure_time_h_uta_def = -1; /* exposure time default for halftone uta */
|
||
|
dev->inquiry_exposure_time_g_min = -1; /* exposure time minimum for grayscale */
|
||
|
dev->inquiry_exposure_time_g_fb_def = -1; /* exposure time default for grayscale flatbed */
|
||
|
dev->inquiry_exposure_time_g_uta_def = -1; /* exposure time default for grayscale uta */
|
||
|
dev->inquiry_exposure_time_c_min = -1; /* exposure time minimum for color */
|
||
|
dev->inquiry_exposure_time_c_fb_def_r = -1; /* exposure time default for color flatbed red */
|
||
|
dev->inquiry_exposure_time_c_fb_def_g = -1; /* exposure time default for color flatbed green */
|
||
|
dev->inquiry_exposure_time_c_fb_def_b = -1; /* exposure time default for color flatbed blue */
|
||
|
dev->inquiry_exposure_time_c_uta_def_r = -1; /* exposure time default for color uta red */
|
||
|
dev->inquiry_exposure_time_c_uta_def_g = -1; /* exposure time default for color uta green */
|
||
|
dev->inquiry_exposure_time_c_uta_def_b = -1; /* exposure time default for color uta blue */
|
||
|
dev->inquiry_max_warmup_time = 0; /* maximum warmup time */
|
||
|
dev->inquiry_cbhs = WD_CBHS_255;
|
||
|
dev->inquiry_cbhs_min = 0;
|
||
|
dev->inquiry_cbhs_max = 255;
|
||
|
dev->inquiry_quality_ctrl = 0;
|
||
|
dev->inquiry_preview = 0;
|
||
|
dev->inquiry_lamp_ctrl = 0;
|
||
|
dev->inquiry_transavail = 0;
|
||
|
dev->inquiry_uta = 0;
|
||
|
dev->inquiry_adfmode = 0;
|
||
|
dev->inquiry_adf = 0;
|
||
|
dev->inquiry_dor = 0;
|
||
|
dev->inquiry_reverse = 0;
|
||
|
dev->inquiry_reverse_multi = 0;
|
||
|
dev->inquiry_analog_gamma = 0;
|
||
|
dev->inquiry_gamma_dwload = 0;
|
||
|
dev->inquiry_one_pass_color = 0;
|
||
|
dev->inquiry_three_pass_color = 0;
|
||
|
dev->inquiry_color = 0;
|
||
|
dev->inquiry_gray = 0;
|
||
|
dev->inquiry_halftone = 0;
|
||
|
dev->inquiry_lineart = 0;
|
||
|
dev->inquiry_calibration = 1;
|
||
|
dev->inquiry_shadow = 0;
|
||
|
dev->inquiry_highlight = 0;
|
||
|
dev->inquiry_gamma_DCF = -1;
|
||
|
|
||
|
dev->shading_type = SHADING_TYPE_AVERAGE; /* shading type = average value */
|
||
|
dev->RGB_PREVIEW_FIX = 0; /* fix for umax s6e/ Astra 6X0S */
|
||
|
|
||
|
dev->button_pressed = 0; /* reset button pressed flag */
|
||
|
|
||
|
if (umax_test_little_endian() == SANE_TRUE)
|
||
|
{
|
||
|
dev->low_byte_first = 1; /* in 2 byte mode send lowbyte first */
|
||
|
DBG(DBG_info,"backend runs on little endian machine\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dev->low_byte_first = 0; /* in 2 byte mode send highbyte first */
|
||
|
DBG(DBG_info,"backend runs on big endian machine\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ MAX STRING SIZE ---------------------------- */
|
||
|
|
||
|
|
||
|
static size_t max_string_size(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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ CLOSE PIPE ---------------------------------- */
|
||
|
|
||
|
|
||
|
static SANE_Status close_pipe(Umax_Scanner *scanner)
|
||
|
{
|
||
|
DBG(DBG_sane_proc,"close_pipe\n");
|
||
|
|
||
|
if (scanner->pipe >= 0)
|
||
|
{
|
||
|
close(scanner->pipe);
|
||
|
scanner->pipe = -1;
|
||
|
}
|
||
|
return SANE_STATUS_EOF;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ DO CANCEL ---------------------------------- */
|
||
|
|
||
|
|
||
|
static SANE_Status do_cancel(Umax_Scanner *scanner)
|
||
|
{
|
||
|
DBG(DBG_sane_proc,"do_cancel\n");
|
||
|
|
||
|
scanner->scanning = SANE_FALSE;
|
||
|
|
||
|
if (scanner->reader_pid > 0)
|
||
|
{
|
||
|
DBG(DBG_sane_info,"killing reader_process\n");
|
||
|
kill(scanner->reader_pid, SIGTERM);
|
||
|
waitpid(scanner->reader_pid, 0, 0);
|
||
|
scanner->reader_pid = 0;
|
||
|
DBG(DBG_sane_info,"reader_process killed\n");
|
||
|
|
||
|
if (scanner->device->pixelbuffer != NULL) /* pixelbuffer exists? */
|
||
|
{
|
||
|
free(scanner->device->pixelbuffer); /* free pixelbuffer */
|
||
|
scanner->device->pixelbuffer = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (scanner->device->sfd >= 0)
|
||
|
{
|
||
|
umax_reposition_scanner(scanner->device);
|
||
|
umax_give_scanner(scanner->device);
|
||
|
DBG(DBG_sane_info,"closing scannerdevice filedescriptor\n");
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd = -1;
|
||
|
}
|
||
|
|
||
|
return SANE_STATUS_CANCELLED;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ ATTACH SCANNER ----------------------------- */
|
||
|
|
||
|
|
||
|
static SANE_Status attach_scanner(const char *devicename, Umax_Device **devp)
|
||
|
{
|
||
|
Umax_Device *dev;
|
||
|
int sfd;
|
||
|
|
||
|
DBG(DBG_sane_proc,"attach_scanner: %s\n", devicename);
|
||
|
|
||
|
for (dev = first_dev; dev; dev = dev->next)
|
||
|
{
|
||
|
if (strcmp(dev->sane.name, devicename) == 0)
|
||
|
{
|
||
|
if (devp) { *devp = dev; }
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dev = malloc( sizeof(*dev) );
|
||
|
if (!dev) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
DBG(DBG_info, "attach_scanner: opening %s\n", devicename);
|
||
|
if (sanei_scsi_open(devicename, &sfd, sense_handler, dev) != 0)
|
||
|
{
|
||
|
free(dev);
|
||
|
DBG(DBG_error, "attach_scanner: open failed\n");
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
|
||
|
umax_init(dev); /* preset values in structure dev and allocate buffer */
|
||
|
if (dev->buffer == NULL) { return SANE_STATUS_NO_MEM; } /* buffer not allocated */
|
||
|
|
||
|
umax_initialize_values(dev); /* reset values */
|
||
|
|
||
|
dev->devicename = strdup(devicename);
|
||
|
dev->sfd = sfd;
|
||
|
|
||
|
if (umax_identify_scanner(dev) != 0)
|
||
|
{
|
||
|
DBG(DBG_error, "attach_scanner: scanner-identification failed\n");
|
||
|
sanei_scsi_close(dev->sfd);
|
||
|
dev->sfd=-1;
|
||
|
free(dev);
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
|
||
|
umax_get_inquiry_values(dev);
|
||
|
umax_print_inquiry(dev);
|
||
|
sanei_scsi_close(dev->sfd);
|
||
|
dev->sfd=-1;
|
||
|
|
||
|
dev->sane.name = dev->devicename;
|
||
|
dev->sane.vendor = dev->vendor;
|
||
|
dev->sane.model = dev->product;
|
||
|
dev->sane.type = "flatbed scanner";
|
||
|
|
||
|
if (strcmp(dev->sane.model,"PSD ") == 0)
|
||
|
{ dev->sane.type = "page scanner"; }
|
||
|
|
||
|
dev->x_range.min = SANE_FIX(0);
|
||
|
dev->x_range.quant = SANE_FIX(0);
|
||
|
dev->x_range.max = SANE_FIX(dev->inquiry_fb_width * MM_PER_INCH);
|
||
|
|
||
|
dev->y_range.min = SANE_FIX(0);
|
||
|
dev->y_range.quant = SANE_FIX(0);
|
||
|
dev->y_range.max = SANE_FIX(dev->inquiry_fb_length * MM_PER_INCH);
|
||
|
|
||
|
dev->x_dpi_range.min = SANE_FIX(1);
|
||
|
dev->x_dpi_range.quant = SANE_FIX(1);
|
||
|
dev->x_dpi_range.max = SANE_FIX(dev->inquiry_x_res);
|
||
|
|
||
|
dev->y_dpi_range.min = SANE_FIX(1);
|
||
|
dev->y_dpi_range.quant = SANE_FIX(1);
|
||
|
dev->y_dpi_range.max = SANE_FIX(dev->inquiry_y_res);
|
||
|
|
||
|
dev->analog_gamma_range.min = SANE_FIX(1.0);
|
||
|
dev->analog_gamma_range.quant = SANE_FIX(0.01);
|
||
|
dev->analog_gamma_range.max = SANE_FIX(2.0);
|
||
|
|
||
|
++num_devices;
|
||
|
dev->next = first_dev;
|
||
|
first_dev = dev;
|
||
|
|
||
|
if (devp) { *devp = dev; }
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ READER PROCESS SIGTERM HANDLER ------------ */
|
||
|
|
||
|
|
||
|
static RETSIGTYPE reader_process_sigterm_handler(int signal)
|
||
|
{
|
||
|
DBG(DBG_sane_info,"reader_process: terminated by signal %d\n", signal);
|
||
|
sanei_scsi_req_flush_all(); /* flush SCSI queue */
|
||
|
_exit (SANE_STATUS_GOOD);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ READER PROCESS ----------------------------- */
|
||
|
|
||
|
|
||
|
static int reader_process(Umax_Scanner *scanner, int pipe_fd) /* executed as a child process */
|
||
|
{
|
||
|
int status;
|
||
|
unsigned int data_length;
|
||
|
FILE *fp;
|
||
|
struct SIGACTION act;
|
||
|
|
||
|
DBG(DBG_sane_proc,"reader_process started\n");
|
||
|
|
||
|
memset (&act, 0, sizeof (act)); /* define SIGTERM-handler */
|
||
|
act.sa_handler = reader_process_sigterm_handler;
|
||
|
sigaction (SIGTERM, &act, 0);
|
||
|
|
||
|
data_length = scanner->params.lines * scanner->params.bytes_per_line;
|
||
|
|
||
|
fp = fdopen (pipe_fd, "w");
|
||
|
if (!fp) {return SANE_STATUS_IO_ERROR;}
|
||
|
|
||
|
DBG(DBG_sane_info,"reader_process: starting to READ data\n");
|
||
|
|
||
|
status = umax_reader_process(scanner->device, fp, data_length);
|
||
|
|
||
|
fclose(fp);
|
||
|
|
||
|
DBG(DBG_sane_info,"reader_process: finished reading data\n");
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ INIT OPTIONS ------------------------------- */
|
||
|
|
||
|
|
||
|
static SANE_Status init_options(Umax_Scanner *scanner)
|
||
|
{
|
||
|
int i;
|
||
|
int scan_modes;
|
||
|
int bit_depths;
|
||
|
|
||
|
DBG(DBG_sane_proc,"init_options\n");
|
||
|
|
||
|
memset(scanner->opt, 0, sizeof (scanner->opt));
|
||
|
memset(scanner->val, 0, sizeof (scanner->val));
|
||
|
|
||
|
for (i = 0; i < NUM_OPTIONS; ++i)
|
||
|
{
|
||
|
scanner->opt[i].size = sizeof (SANE_Word);
|
||
|
scanner->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
|
||
|
}
|
||
|
|
||
|
scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
|
||
|
scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
|
||
|
scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
|
||
|
scanner->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
|
||
|
|
||
|
/* "Mode" group: */
|
||
|
scanner->opt[OPT_MODE_GROUP].title = "Scan Mode";
|
||
|
scanner->opt[OPT_MODE_GROUP].desc = "";
|
||
|
scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
|
||
|
scanner->opt[OPT_MODE_GROUP].cap = 0;
|
||
|
scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
|
||
|
scan_modes = -1;
|
||
|
|
||
|
if (scanner->device->inquiry_lineart)
|
||
|
{ scan_mode_list[++scan_modes] = LINEART_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_halftone)
|
||
|
{ scan_mode_list[++scan_modes]= HALFTONE_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_gray)
|
||
|
{ scan_mode_list[++scan_modes]= GRAY_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_color)
|
||
|
{
|
||
|
/*
|
||
|
if (scanner->device->inquiry_lineart)
|
||
|
{ scan_mode_list[++scan_modes]= COLOR_LINEART_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_halftone)
|
||
|
{ scan_mode_list[++scan_modes]= COLOR_HALFTONE_STR; }
|
||
|
*/
|
||
|
scan_mode_list[++scan_modes]= COLOR_STR;
|
||
|
}
|
||
|
|
||
|
scan_mode_list[scan_modes + 1] = 0;
|
||
|
|
||
|
{
|
||
|
int i=0;
|
||
|
{ source_list[i++]= FLB_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_adfmode)
|
||
|
{ source_list[i++] = ADF_STR; }
|
||
|
|
||
|
if (scanner->device->inquiry_transavail)
|
||
|
{ source_list[i++] = UTA_STR; }
|
||
|
|
||
|
source_list[i] = 0;
|
||
|
}
|
||
|
|
||
|
/* scan mode */
|
||
|
scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
|
||
|
scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
|
||
|
scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
|
||
|
scanner->opt[OPT_MODE].type = SANE_TYPE_STRING;
|
||
|
scanner->opt[OPT_MODE].size = max_string_size(scan_mode_list);
|
||
|
scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
||
|
scanner->opt[OPT_MODE].constraint.string_list = scan_mode_list;
|
||
|
scanner->val[OPT_MODE].s = (SANE_Char*)strdup(scan_mode_list[0]);
|
||
|
|
||
|
/* source */
|
||
|
scanner->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
|
||
|
scanner->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
|
||
|
scanner->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
|
||
|
scanner->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
|
||
|
scanner->opt[OPT_SOURCE].size = max_string_size(source_list);
|
||
|
scanner->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
||
|
scanner->opt[OPT_SOURCE].constraint.string_list = source_list;
|
||
|
scanner->val[OPT_SOURCE].s = (SANE_Char*)strdup(source_list[0]);
|
||
|
|
||
|
/* x-resolution */
|
||
|
scanner->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI;
|
||
|
scanner->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_X_RESOLUTION].constraint.range = &scanner->device->x_dpi_range;
|
||
|
scanner->val[OPT_X_RESOLUTION].w = 100 << SANE_FIXED_SCALE_SHIFT;
|
||
|
|
||
|
/* y-resolution */
|
||
|
scanner->opt[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].constraint.range = &scanner->device->y_dpi_range;
|
||
|
scanner->val[OPT_Y_RESOLUTION].w = 100 << SANE_FIXED_SCALE_SHIFT;
|
||
|
scanner->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* bind resolution */
|
||
|
scanner->opt[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
|
||
|
scanner->opt[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
|
||
|
scanner->opt[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
|
||
|
scanner->opt[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
|
||
|
|
||
|
|
||
|
/* negative */
|
||
|
scanner->opt[OPT_NEGATIVE].name = SANE_NAME_NEGATIVE;
|
||
|
scanner->opt[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE;
|
||
|
scanner->opt[OPT_NEGATIVE].desc = SANE_DESC_NEGATIVE;
|
||
|
scanner->opt[OPT_NEGATIVE].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_NEGATIVE].w = SANE_FALSE;
|
||
|
|
||
|
if (scanner->device->inquiry_reverse_multi == 0)
|
||
|
{ scanner->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
/* "Geometry" group: */
|
||
|
scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
|
||
|
scanner->opt[OPT_GEOMETRY_GROUP].desc = "";
|
||
|
scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
|
||
|
scanner->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
|
||
|
scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
|
||
|
/* top-left x */
|
||
|
scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
|
||
|
scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
|
||
|
scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
|
||
|
scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM;
|
||
|
scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_TL_X].constraint.range = &(scanner->device->x_range);
|
||
|
scanner->val[OPT_TL_X].w = 0;
|
||
|
|
||
|
/* top-left y */
|
||
|
scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
|
||
|
scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
|
||
|
scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
|
||
|
scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
|
||
|
scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_TL_Y].constraint.range = &(scanner->device->y_range);
|
||
|
scanner->val[OPT_TL_Y].w = 0;
|
||
|
|
||
|
/* bottom-right x */
|
||
|
scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
|
||
|
scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
|
||
|
scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
|
||
|
scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM;
|
||
|
scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_BR_X].constraint.range = &(scanner->device->x_range);
|
||
|
scanner->val[OPT_BR_X].w = scanner->device->x_range.max;
|
||
|
|
||
|
/* bottom-right y */
|
||
|
scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
|
||
|
scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
|
||
|
scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
|
||
|
scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
|
||
|
scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_BR_Y].constraint.range = &(scanner->device->y_range);
|
||
|
scanner->val[OPT_BR_Y].w = scanner->device->y_range.max;
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
|
||
|
/* "Enhancement" group: */
|
||
|
scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
|
||
|
scanner->opt[OPT_ENHANCEMENT_GROUP].desc = "";
|
||
|
scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
|
||
|
scanner->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
|
||
|
scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
|
||
|
|
||
|
/* bit depth */
|
||
|
bit_depths = 0;
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 1)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 8;
|
||
|
}
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 2)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 9;
|
||
|
}
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 4)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 10;
|
||
|
}
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 8)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 12;
|
||
|
}
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 16)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 14;
|
||
|
}
|
||
|
|
||
|
if (scanner->device->inquiry_GOB & 32)
|
||
|
{
|
||
|
bit_depth_list[++bit_depths] = 16;
|
||
|
}
|
||
|
|
||
|
bit_depth_list[0] = bit_depths;
|
||
|
|
||
|
scanner->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
|
||
|
scanner->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
|
||
|
scanner->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
|
||
|
scanner->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_BIT;
|
||
|
scanner->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
||
|
scanner->opt[OPT_BIT_DEPTH].constraint.word_list = bit_depth_list;
|
||
|
scanner->val[OPT_BIT_DEPTH].w = bit_depth_list[1];
|
||
|
|
||
|
|
||
|
/* quality-calibration */
|
||
|
scanner->opt[OPT_QUALITY].name = SANE_NAME_QUALITY_CAL;
|
||
|
scanner->opt[OPT_QUALITY].title = SANE_TITLE_QUALITY_CAL;
|
||
|
scanner->opt[OPT_QUALITY].desc = SANE_DESC_QUALITY_CAL;
|
||
|
scanner->opt[OPT_QUALITY].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_QUALITY].w = SANE_FALSE;
|
||
|
|
||
|
if (scanner->device->inquiry_quality_ctrl == 0)
|
||
|
{ scanner->opt[OPT_QUALITY].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
|
||
|
/* double optical resolution */
|
||
|
scanner->opt[OPT_DOR].name = SANE_NAME_DOR;
|
||
|
scanner->opt[OPT_DOR].title = SANE_TITLE_DOR;
|
||
|
scanner->opt[OPT_DOR].desc = SANE_DESC_DOR;
|
||
|
scanner->opt[OPT_DOR].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_DOR].w = SANE_FALSE;
|
||
|
|
||
|
if (scanner->device->inquiry_dor == 0)
|
||
|
{ scanner->opt[OPT_DOR].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
|
||
|
/* warmup */
|
||
|
scanner->opt[OPT_WARMUP].name = SANE_NAME_WARMUP;
|
||
|
scanner->opt[OPT_WARMUP].title = SANE_TITLE_WARMUP;
|
||
|
scanner->opt[OPT_WARMUP].desc = SANE_DESC_WARMUP;
|
||
|
scanner->opt[OPT_WARMUP].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_WARMUP].w = SANE_FALSE;
|
||
|
|
||
|
if (scanner->device->inquiry_max_warmup_time == 0)
|
||
|
{ scanner->opt[OPT_WARMUP].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
scanner->opt[OPT_RGB_BIND].name = SANE_NAME_RGB_BIND;
|
||
|
scanner->opt[OPT_RGB_BIND].title = SANE_TITLE_RGB_BIND;
|
||
|
scanner->opt[OPT_RGB_BIND].desc = SANE_DESC_RGB_BIND;
|
||
|
scanner->opt[OPT_RGB_BIND].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_RGB_BIND].w = SANE_TRUE;
|
||
|
|
||
|
/* brightness */
|
||
|
scanner->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
|
||
|
scanner->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
|
||
|
scanner->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
|
||
|
scanner->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
|
||
|
scanner->val[OPT_BRIGHTNESS].w = 0;
|
||
|
|
||
|
/* contrast */
|
||
|
scanner->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
|
||
|
scanner->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
|
||
|
scanner->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
|
||
|
scanner->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CONTRAST].constraint.range = &percentage_range;
|
||
|
scanner->val[OPT_CONTRAST].w = 0;
|
||
|
|
||
|
|
||
|
/* threshold */
|
||
|
scanner->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
|
||
|
scanner->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
|
||
|
scanner->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
|
||
|
scanner->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_THRESHOLD].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_THRESHOLD].w = SANE_FIX(50);
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
|
||
|
/* highlight, white level */
|
||
|
scanner->opt[OPT_HIGHLIGHT].name = SANE_NAME_HIGHLIGHT;
|
||
|
scanner->opt[OPT_HIGHLIGHT].title = SANE_TITLE_HIGHLIGHT;
|
||
|
scanner->opt[OPT_HIGHLIGHT].desc = SANE_DESC_HIGHLIGHT;
|
||
|
scanner->opt[OPT_HIGHLIGHT].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_HIGHLIGHT].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_HIGHLIGHT].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_HIGHLIGHT].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_HIGHLIGHT].w = SANE_FIX(100);
|
||
|
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].name = SANE_NAME_HIGHLIGHT_R;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].title = SANE_TITLE_HIGHLIGHT_R;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].desc = SANE_DESC_HIGHLIGHT_R;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_HIGHLIGHT_R].w = SANE_FIX(100);
|
||
|
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].name = SANE_NAME_HIGHLIGHT_G;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].title = SANE_TITLE_HIGHLIGHT_G;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].desc = SANE_DESC_HIGHLIGHT_G;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_HIGHLIGHT_G].w = SANE_FIX(100);
|
||
|
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].name = SANE_NAME_HIGHLIGHT_B;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].title = SANE_TITLE_HIGHLIGHT_B;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].desc = SANE_DESC_HIGHLIGHT_B;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_HIGHLIGHT_B].w = SANE_FIX(100);
|
||
|
|
||
|
|
||
|
/* shadow, black level */
|
||
|
scanner->opt[OPT_SHADOW].name = SANE_NAME_SHADOW;
|
||
|
scanner->opt[OPT_SHADOW].title = SANE_TITLE_SHADOW;
|
||
|
scanner->opt[OPT_SHADOW].desc = SANE_DESC_SHADOW;
|
||
|
scanner->opt[OPT_SHADOW].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SHADOW].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_SHADOW].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SHADOW].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_SHADOW].w = 0;
|
||
|
|
||
|
scanner->opt[OPT_SHADOW_R].name = SANE_NAME_SHADOW_R;
|
||
|
scanner->opt[OPT_SHADOW_R].title = SANE_TITLE_SHADOW_R;
|
||
|
scanner->opt[OPT_SHADOW_R].desc = SANE_DESC_SHADOW_R;
|
||
|
scanner->opt[OPT_SHADOW_R].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SHADOW_R].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_SHADOW_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SHADOW_R].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_SHADOW_R].w = 0;
|
||
|
|
||
|
scanner->opt[OPT_SHADOW_G].name = SANE_NAME_SHADOW_G;
|
||
|
scanner->opt[OPT_SHADOW_G].title = SANE_TITLE_SHADOW_G;
|
||
|
scanner->opt[OPT_SHADOW_G].desc = SANE_DESC_SHADOW_G;
|
||
|
scanner->opt[OPT_SHADOW_G].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SHADOW_G].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_SHADOW_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SHADOW_G].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_SHADOW_G].w = 0;
|
||
|
|
||
|
scanner->opt[OPT_SHADOW_B].name = SANE_NAME_SHADOW_B;
|
||
|
scanner->opt[OPT_SHADOW_B].title = SANE_TITLE_SHADOW_B;
|
||
|
scanner->opt[OPT_SHADOW_B].desc = SANE_DESC_SHADOW_B;
|
||
|
scanner->opt[OPT_SHADOW_B].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SHADOW_B].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_SHADOW_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SHADOW_B].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_SHADOW_B].w = 0;
|
||
|
|
||
|
|
||
|
|
||
|
/* analog-gamma */
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].name = SANE_NAME_ANALOG_GAMMA;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].title = SANE_TITLE_ANALOG_GAMMA;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].desc = SANE_DESC_ANALOG_GAMMA;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].constraint.range = &(scanner->device->analog_gamma_range);
|
||
|
scanner->val[OPT_ANALOG_GAMMA].w = 1 << SANE_FIXED_SCALE_SHIFT;
|
||
|
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].name = SANE_NAME_ANALOG_GAMMA_R;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].title = SANE_TITLE_ANALOG_GAMMA_R;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].desc = SANE_DESC_ANALOG_GAMMA_R;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].constraint.range = &(scanner->device->analog_gamma_range);
|
||
|
scanner->val[OPT_ANALOG_GAMMA_R].w = 1 << SANE_FIXED_SCALE_SHIFT;
|
||
|
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].name = SANE_NAME_ANALOG_GAMMA_G;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].title = SANE_TITLE_ANALOG_GAMMA_G;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].desc = SANE_DESC_ANALOG_GAMMA_G;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].constraint.range = &(scanner->device->analog_gamma_range);
|
||
|
scanner->val[OPT_ANALOG_GAMMA_G].w = 1 << SANE_FIXED_SCALE_SHIFT;
|
||
|
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].name = SANE_NAME_ANALOG_GAMMA_B;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].title = SANE_TITLE_ANALOG_GAMMA_B;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].desc = SANE_DESC_ANALOG_GAMMA_B;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].constraint.range = &(scanner->device->analog_gamma_range);
|
||
|
scanner->val[OPT_ANALOG_GAMMA_B].w = 1 << SANE_FIXED_SCALE_SHIFT;
|
||
|
|
||
|
|
||
|
/* custom-gamma table */
|
||
|
scanner->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
|
||
|
scanner->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
|
||
|
scanner->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
|
||
|
scanner->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
|
||
|
|
||
|
/* grayscale gamma vector */
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->val[OPT_GAMMA_VECTOR].wa = scanner->gamma_table[0];
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &scanner->output_range;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].size = scanner->gamma_length * sizeof(SANE_Word);
|
||
|
|
||
|
scanner->output_range.min = 0;
|
||
|
scanner->output_range.max = (int) pow(2, bit_depth_list[1]) - 1;
|
||
|
scanner->output_range.quant = 0;
|
||
|
|
||
|
/* red gamma vector */
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->val[OPT_GAMMA_VECTOR_R].wa = scanner->gamma_table[1];
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(scanner->gamma_range);
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].size = scanner->gamma_length * sizeof(SANE_Word);
|
||
|
|
||
|
/* green gamma vector */
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->val[OPT_GAMMA_VECTOR_G].wa = scanner->gamma_table[2];
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(scanner->gamma_range);
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].size = scanner->gamma_length * sizeof(SANE_Word);
|
||
|
|
||
|
/* blue gamma vector */
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->val[OPT_GAMMA_VECTOR_B].wa = scanner->gamma_table[3];
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(scanner->gamma_range);
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].size = scanner->gamma_length * sizeof(SANE_Word);
|
||
|
|
||
|
/* halftone dimension */
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].name = SANE_NAME_HALFTONE_DIMENSION;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].title = SANE_TITLE_HALFTONE_DIMENSION;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].desc = SANE_DESC_HALFTONE_DIMENSION;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].unit = SANE_UNIT_PIXEL;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].constraint.word_list = pattern_dim_list;
|
||
|
scanner->val[OPT_HALFTONE_DIMENSION].w = 0;
|
||
|
|
||
|
/* halftone pattern */
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_INT;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].size = 0;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].constraint.range = &u8_range;
|
||
|
scanner->val[OPT_HALFTONE_PATTERN].wa = scanner->halftone_pattern;
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
|
||
|
/* "Advanced" group: */
|
||
|
scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced";
|
||
|
scanner->opt[OPT_ADVANCED_GROUP].desc = "";
|
||
|
scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
|
||
|
scanner->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
|
||
|
scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
|
||
|
/* select exposure time */
|
||
|
scanner->opt[OPT_SELECT_EXPOSURE_TIME].name = SANE_NAME_SELECT_EXPOSURE_TIME;
|
||
|
scanner->opt[OPT_SELECT_EXPOSURE_TIME].title = SANE_TITLE_SELECT_EXPOSURE_TIME;
|
||
|
scanner->opt[OPT_SELECT_EXPOSURE_TIME].desc = SANE_DESC_SELECT_EXPOSURE_TIME;
|
||
|
scanner->opt[OPT_SELECT_EXPOSURE_TIME].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_SELECT_EXPOSURE_TIME].w = SANE_FALSE;
|
||
|
|
||
|
/* calibration exposure time */
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].name = SANE_NAME_CAL_EXPOS_TIME;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].title = SANE_TITLE_CAL_EXPOS_TIME;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].desc = SANE_DESC_CAL_EXPOS_TIME;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_CAL_EXPOS_TIME].w = SANE_FIX(scanner->device->inquiry_exposure_time_g_fb_def *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* calibration exposure time red */
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].name = SANE_NAME_CAL_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].title = SANE_TITLE_CAL_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].desc = SANE_DESC_CAL_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_CAL_EXPOS_TIME_R].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_r *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* calibration exposure time green */
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].name = SANE_NAME_CAL_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].title = SANE_TITLE_CAL_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].desc = SANE_DESC_CAL_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_CAL_EXPOS_TIME_G].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_g *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* calibration exposure time blue */
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].name = SANE_NAME_CAL_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].title = SANE_TITLE_CAL_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].desc = SANE_DESC_CAL_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_CAL_EXPOS_TIME_B].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_b *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* scan exposure time */
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].name = SANE_NAME_SCAN_EXPOS_TIME;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].title = SANE_TITLE_SCAN_EXPOS_TIME;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].desc = SANE_DESC_SCAN_EXPOS_TIME;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_SCAN_EXPOS_TIME].w = SANE_FIX(scanner->device->inquiry_exposure_time_g_fb_def *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* scan exposure time red */
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].name = SANE_NAME_SCAN_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].title = SANE_TITLE_SCAN_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].desc = SANE_DESC_SCAN_EXPOS_TIME_R;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_SCAN_EXPOS_TIME_R].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_r *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* scan exposure time green */
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].name = SANE_NAME_SCAN_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].title = SANE_TITLE_SCAN_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].desc = SANE_DESC_SCAN_EXPOS_TIME_G;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_SCAN_EXPOS_TIME_G].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_g *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* scan exposure time blue */
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].name = SANE_NAME_SCAN_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].title = SANE_TITLE_SCAN_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].desc = SANE_DESC_SCAN_EXPOS_TIME_B;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].unit = SANE_UNIT_MICROSECOND;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].constraint.range = &(scanner->exposure_time_range);
|
||
|
scanner->val[OPT_SCAN_EXPOS_TIME_B].w = SANE_FIX(scanner->device->inquiry_exposure_time_c_fb_def_b *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->device->inquiry_exposure_adj == 0)
|
||
|
{
|
||
|
scanner->opt[OPT_SELECT_EXPOSURE_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
|
||
|
/* select calibration lamp density */
|
||
|
scanner->opt[OPT_SELECT_LAMP_DENSITY].name = SANE_NAME_SELECT_LAMP_DENSITY;
|
||
|
scanner->opt[OPT_SELECT_LAMP_DENSITY].title = SANE_TITLE_SELECT_LAMP_DENSITY;
|
||
|
scanner->opt[OPT_SELECT_LAMP_DENSITY].desc = SANE_DESC_SELECT_LAMP_DENSITY;
|
||
|
scanner->opt[OPT_SELECT_LAMP_DENSITY].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_SELECT_LAMP_DENSITY].w = SANE_FALSE;
|
||
|
|
||
|
/* calibration lamp density */
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].name = SANE_NAME_CAL_LAMP_DEN;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].title = SANE_TITLE_CAL_LAMP_DEN;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].desc = SANE_DESC_CAL_LAMP_DEN;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_CAL_LAMP_DEN].w = SANE_FIX(50);
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
/* scan lamp density */
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].name = SANE_NAME_SCAN_LAMP_DEN;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].title = SANE_TITLE_SCAN_LAMP_DEN;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].desc = SANE_DESC_SCAN_LAMP_DEN;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].type = SANE_TYPE_FIXED;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].unit = SANE_UNIT_PERCENT;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].constraint.range = &percentage_range_100;
|
||
|
scanner->val[OPT_SCAN_LAMP_DEN].w = SANE_FIX(50);
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->device->inquiry_lamp_ctrl == 0)
|
||
|
{
|
||
|
scanner->opt[OPT_SELECT_LAMP_DENSITY].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------ */
|
||
|
|
||
|
#if 0 /* do not change this values, umax set always use the fastes setting */
|
||
|
/* slow-scan */
|
||
|
scanner->opt[OPT_SLOW].name = "slow";
|
||
|
scanner->opt[OPT_SLOW].title = "Slow speed";
|
||
|
scanner->opt[OPT_SLOW].desc = "Scan with slow speed";
|
||
|
scanner->opt[OPT_SLOW].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_SLOW].w = SANE_FALSE;
|
||
|
|
||
|
/* smear */
|
||
|
scanner->opt[OPT_SMEAR].name = SANE_NAME_SMEAR;
|
||
|
scanner->opt[OPT_SMEAR].title = SANE_TITLE_SMEAR;
|
||
|
scanner->opt[OPT_SMEAR].desc = SANE_DESC_SMEAR;
|
||
|
scanner->opt[OPT_SMEAR].type = SANE_TYPE_BOOL;
|
||
|
scanner->val[OPT_SMEAR].w = SANE_FALSE;
|
||
|
#endif
|
||
|
|
||
|
/* calibration mode */
|
||
|
scanner->opt[OPT_CALIB_MODE].name = "calibrationmode";
|
||
|
scanner->opt[OPT_CALIB_MODE].title = "Calibration mode";
|
||
|
scanner->opt[OPT_CALIB_MODE].desc = "Define calibration mode";
|
||
|
scanner->opt[OPT_CALIB_MODE].type = SANE_TYPE_STRING;
|
||
|
scanner->opt[OPT_CALIB_MODE].size = max_string_size(calibration_list);
|
||
|
scanner->opt[OPT_CALIB_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
||
|
scanner->opt[OPT_CALIB_MODE].constraint.string_list = calibration_list;
|
||
|
scanner->val[OPT_CALIB_MODE].s = (SANE_Char*)strdup(calibration_list[0]);
|
||
|
|
||
|
if (scanner->device->inquiry_calibration == 0)
|
||
|
{ scanner->opt[OPT_CALIB_MODE].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
/* shading type */
|
||
|
scanner->opt[OPT_SHADING_TYPE].name = "shadingtype";
|
||
|
scanner->opt[OPT_SHADING_TYPE].title = "Shading type";
|
||
|
scanner->opt[OPT_SHADING_TYPE].desc = "Define calculation of shading data";
|
||
|
scanner->opt[OPT_SHADING_TYPE].type = SANE_TYPE_STRING;
|
||
|
scanner->opt[OPT_SHADING_TYPE].size = max_string_size(shading_list);
|
||
|
scanner->opt[OPT_SHADING_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
||
|
scanner->opt[OPT_SHADING_TYPE].constraint.string_list = shading_list;
|
||
|
scanner->val[OPT_SHADING_TYPE].s = (SANE_Char*)strdup(shading_list[scanner->device->shading_type]);
|
||
|
|
||
|
if (scanner->device->inquiry_quality_ctrl == 0)
|
||
|
{ scanner->opt[OPT_SHADING_TYPE].cap |= SANE_CAP_INACTIVE; }
|
||
|
|
||
|
/* preview */
|
||
|
scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
|
||
|
scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
|
||
|
scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
|
||
|
scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
|
||
|
scanner->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
|
||
|
scanner->val[OPT_PREVIEW].w = SANE_FALSE;
|
||
|
|
||
|
sane_control_option(scanner, OPT_MODE, SANE_ACTION_SET_VALUE,
|
||
|
(SANE_String *) scan_mode_list[scan_modes], NULL );
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ ATTACH_ONE ---------------------------------- */
|
||
|
|
||
|
|
||
|
/* callback function for sanei_config_attach_matching_devices(dev_name, attach_one) */
|
||
|
static SANE_Status attach_one (const char *name)
|
||
|
{
|
||
|
attach_scanner(name, 0);
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE INIT ---------------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
|
||
|
{
|
||
|
char dev_name[PATH_MAX];
|
||
|
size_t len;
|
||
|
FILE *fp;
|
||
|
|
||
|
DBG_INIT();
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_init\n");
|
||
|
DBG(DBG_error,"This is sane-umax version %d.%d build %d\n",V_MAJOR, V_MINOR, BUILD);
|
||
|
DBG(DBG_error,"(C) 1997-1999 by Oliver Rauch\n");
|
||
|
DBG(DBG_error,"EMAIL: Oliver.Rauch@Wolfsburg.DE\n");
|
||
|
|
||
|
if (version_code)
|
||
|
{
|
||
|
*version_code = SANE_VERSION_CODE(V_MAJOR, V_MINOR, BUILD);
|
||
|
}
|
||
|
|
||
|
fp = sanei_config_open(UMAX_CONFIG_FILE);
|
||
|
if (!fp)
|
||
|
{
|
||
|
attach_scanner("/dev/scanner", 0); /* no config-file: /dev/scanner */
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
while(fgets(dev_name, sizeof(dev_name), fp))
|
||
|
{
|
||
|
if (dev_name[0] == '#') { continue; } /* ignore line comments */
|
||
|
|
||
|
len = strlen (dev_name);
|
||
|
if (dev_name[len - 1] == '\n') { dev_name[--len] = '\0'; }
|
||
|
|
||
|
if (!len) { continue; } /* ignore empty lines */
|
||
|
|
||
|
sanei_config_attach_matching_devices (dev_name, attach_one);
|
||
|
}
|
||
|
|
||
|
fclose(fp);
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE EXIT ---------------------------------- */
|
||
|
|
||
|
|
||
|
void sane_exit(void)
|
||
|
{
|
||
|
Umax_Device *dev, *next;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_exit\n");
|
||
|
|
||
|
for (dev = first_dev; dev; dev = next)
|
||
|
{
|
||
|
next = dev->next;
|
||
|
free(dev->devicename);
|
||
|
free(dev);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE GET DEVICES --------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
|
||
|
{
|
||
|
static const SANE_Device **devlist = 0;
|
||
|
Umax_Device *dev;
|
||
|
int i;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_get_devices\n");
|
||
|
|
||
|
if (devlist) { free (devlist); }
|
||
|
|
||
|
devlist = malloc((num_devices + 1) * sizeof (devlist[0]));
|
||
|
if (!devlist) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
i = 0;
|
||
|
|
||
|
for (dev = first_dev; i < num_devices; dev = dev->next)
|
||
|
{ devlist[i++] = &dev->sane; }
|
||
|
|
||
|
devlist[i++] = 0;
|
||
|
|
||
|
*device_list = devlist;
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE OPEN ---------------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_open(SANE_String_Const devicename, SANE_Handle *handle)
|
||
|
{
|
||
|
Umax_Device *dev;
|
||
|
SANE_Status status;
|
||
|
Umax_Scanner *scanner;
|
||
|
int i, j;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_open\n");
|
||
|
|
||
|
if (devicename[0]) /* search for devicename */
|
||
|
{
|
||
|
for (dev = first_dev; dev; dev = dev->next)
|
||
|
{ if (strcmp(dev->sane.name, devicename) == 0) { break; } }
|
||
|
|
||
|
if (!dev)
|
||
|
{
|
||
|
status = attach_scanner(devicename, &dev);
|
||
|
if (status != SANE_STATUS_GOOD) { return status; }
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ dev = first_dev; } /* empty devicename -> use first device */
|
||
|
|
||
|
if (!dev) { return SANE_STATUS_INVAL; }
|
||
|
|
||
|
scanner = malloc(sizeof (*scanner));
|
||
|
if (!scanner) { return SANE_STATUS_NO_MEM; }
|
||
|
|
||
|
memset(scanner, 0, sizeof (*scanner));
|
||
|
|
||
|
scanner->device = dev;
|
||
|
scanner->device->sfd = -1;
|
||
|
scanner->pipe = -1;
|
||
|
|
||
|
if (scanner->device->inquiry_GIB & 32)
|
||
|
{
|
||
|
scanner->gamma_length = 65536; /* 16 bits input */
|
||
|
DBG(DBG_sane_info, "Using 16 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 16)
|
||
|
{
|
||
|
scanner->gamma_length = 16384; /* 14 bits input */
|
||
|
DBG(DBG_sane_info, "Using 14 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 8)
|
||
|
{
|
||
|
scanner->gamma_length = 4096; /* 12 bits input */
|
||
|
DBG(DBG_sane_info, "Using 12 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 4)
|
||
|
{
|
||
|
scanner->gamma_length = 1024; /* 10 bits input */
|
||
|
DBG(DBG_sane_info, "Using 10 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 2)
|
||
|
{
|
||
|
scanner->gamma_length = 512; /* 9 bits input */
|
||
|
DBG(DBG_sane_info, "Using 9 bits for gamma input\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
scanner->gamma_length = 256; /* 8 bits input */
|
||
|
DBG(DBG_sane_info, "Using 8 bits for gamma input\n");
|
||
|
}
|
||
|
|
||
|
scanner->output_bytes = 1; /* 8 bits output */
|
||
|
|
||
|
scanner->gamma_range.min = 0;
|
||
|
scanner->gamma_range.max = scanner->gamma_length-1;
|
||
|
scanner->gamma_range.quant = 0;
|
||
|
|
||
|
scanner->gamma_table[0] = (SANE_Int *) malloc(scanner->gamma_length * sizeof(SANE_Int));
|
||
|
scanner->gamma_table[1] = (SANE_Int *) malloc(scanner->gamma_length * sizeof(SANE_Int));
|
||
|
scanner->gamma_table[2] = (SANE_Int *) malloc(scanner->gamma_length * sizeof(SANE_Int));
|
||
|
scanner->gamma_table[3] = (SANE_Int *) malloc(scanner->gamma_length * sizeof(SANE_Int));
|
||
|
|
||
|
for (j = 0; j < scanner->gamma_length; ++j) /* gamma_table[0] : converts GIB to GOB */
|
||
|
{
|
||
|
scanner->gamma_table[0][j] = j * scanner->device->max_value / scanner->gamma_length;
|
||
|
}
|
||
|
|
||
|
for (i = 1; i < 4; ++i) /* gamma_table[1,2,3] : doesn't convert anything (GIB->GIB) */
|
||
|
{
|
||
|
for (j = 0; j < scanner->gamma_length; ++j)
|
||
|
{ scanner->gamma_table[i][j] = j; }
|
||
|
}
|
||
|
|
||
|
scanner->exposure_time_range.min = SANE_FIX(scanner->device->inquiry_exposure_time_c_min *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->exposure_time_range.quant = SANE_FIX(scanner->device->inquiry_exposure_time_step_unit);
|
||
|
scanner->exposure_time_range.max = SANE_FIX(scanner->device->inquiry_exposure_time_max *
|
||
|
scanner->device->inquiry_exposure_time_step_unit);
|
||
|
|
||
|
init_options(scanner);
|
||
|
|
||
|
scanner->next = first_handle; /* insert newly opened handle into list of open handles: */
|
||
|
first_handle = scanner;
|
||
|
|
||
|
*handle = scanner;
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE CLOSE --------------------------------- */
|
||
|
|
||
|
|
||
|
void sane_close(SANE_Handle handle)
|
||
|
{
|
||
|
Umax_Scanner *prev, *scanner;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_close\n");
|
||
|
|
||
|
/* remove handle from list of open handles: */
|
||
|
prev = 0;
|
||
|
|
||
|
for (scanner = first_handle; scanner; scanner = scanner->next)
|
||
|
{
|
||
|
if (scanner == handle) { break; }
|
||
|
|
||
|
prev = scanner;
|
||
|
}
|
||
|
|
||
|
if (!scanner)
|
||
|
{
|
||
|
DBG(DBG_error, "close: invalid handle %p\n", handle);
|
||
|
return; /* oops, not a handle we know about */
|
||
|
}
|
||
|
|
||
|
if (scanner->scanning) { do_cancel(handle); }
|
||
|
|
||
|
if (prev)
|
||
|
{ prev->next = scanner->next; }
|
||
|
else
|
||
|
{ first_handle = scanner; }
|
||
|
|
||
|
free(scanner->gamma_table[0]); /* free custom gamma tables */
|
||
|
free(scanner->gamma_table[1]);
|
||
|
free(scanner->gamma_table[2]);
|
||
|
free(scanner->gamma_table[3]);
|
||
|
|
||
|
free(scanner->device->buffer); /* free buffer allocated by umax_init */
|
||
|
|
||
|
free(scanner); /* free scanner */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE GET OPTION DESCRIPTOR ----------------- */
|
||
|
|
||
|
|
||
|
const SANE_Option_Descriptor * sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
|
||
|
DBG(DBG_sane_option,"sane_get_option_descriptor %d\n", option);
|
||
|
|
||
|
if ((unsigned) option >= NUM_OPTIONS) { return 0; }
|
||
|
|
||
|
return scanner->opt + option;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE CONTROL OPTION ------------------------ */
|
||
|
|
||
|
|
||
|
SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action,
|
||
|
void *val, SANE_Int *info)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
SANE_Status status;
|
||
|
SANE_Word w, cap;
|
||
|
|
||
|
if (info) { *info = 0; }
|
||
|
|
||
|
if (scanner->scanning) { return SANE_STATUS_DEVICE_BUSY; }
|
||
|
|
||
|
if (option >= NUM_OPTIONS) { return SANE_STATUS_INVAL; }
|
||
|
|
||
|
cap = scanner->opt[option].cap;
|
||
|
|
||
|
if (!SANE_OPTION_IS_ACTIVE (cap)) { return SANE_STATUS_INVAL; }
|
||
|
|
||
|
if (action == SANE_ACTION_GET_VALUE)
|
||
|
{
|
||
|
DBG(DBG_sane_option,"sane_control_option %d, get value\n",option);
|
||
|
switch (option)
|
||
|
{
|
||
|
/* word options: */
|
||
|
case OPT_NUM_OPTS:
|
||
|
case OPT_RESOLUTION_BIND:
|
||
|
case OPT_X_RESOLUTION:
|
||
|
case OPT_Y_RESOLUTION:
|
||
|
case OPT_TL_X:
|
||
|
case OPT_TL_Y:
|
||
|
case OPT_BR_X:
|
||
|
case OPT_BR_Y:
|
||
|
case OPT_PREVIEW:
|
||
|
case OPT_BIT_DEPTH:
|
||
|
case OPT_NEGATIVE:
|
||
|
case OPT_QUALITY:
|
||
|
case OPT_DOR:
|
||
|
case OPT_WARMUP:
|
||
|
#if 0
|
||
|
case OPT_SLOW:
|
||
|
case OPT_SMEAR:
|
||
|
#endif
|
||
|
case OPT_RGB_BIND:
|
||
|
case OPT_ANALOG_GAMMA:
|
||
|
case OPT_ANALOG_GAMMA_R:
|
||
|
case OPT_ANALOG_GAMMA_G:
|
||
|
case OPT_ANALOG_GAMMA_B:
|
||
|
case OPT_BRIGHTNESS:
|
||
|
case OPT_CONTRAST:
|
||
|
case OPT_THRESHOLD:
|
||
|
case OPT_HIGHLIGHT:
|
||
|
case OPT_HIGHLIGHT_R:
|
||
|
case OPT_HIGHLIGHT_G:
|
||
|
case OPT_HIGHLIGHT_B:
|
||
|
case OPT_SHADOW:
|
||
|
case OPT_SHADOW_R:
|
||
|
case OPT_SHADOW_G:
|
||
|
case OPT_SHADOW_B:
|
||
|
case OPT_CUSTOM_GAMMA:
|
||
|
case OPT_HALFTONE_DIMENSION:
|
||
|
case OPT_SELECT_EXPOSURE_TIME:
|
||
|
case OPT_CAL_EXPOS_TIME:
|
||
|
case OPT_CAL_EXPOS_TIME_R:
|
||
|
case OPT_CAL_EXPOS_TIME_G:
|
||
|
case OPT_CAL_EXPOS_TIME_B:
|
||
|
case OPT_SCAN_EXPOS_TIME:
|
||
|
case OPT_SCAN_EXPOS_TIME_R:
|
||
|
case OPT_SCAN_EXPOS_TIME_G:
|
||
|
case OPT_SCAN_EXPOS_TIME_B:
|
||
|
case OPT_CAL_LAMP_DEN:
|
||
|
case OPT_SCAN_LAMP_DEN:
|
||
|
case OPT_SELECT_LAMP_DENSITY:
|
||
|
*(SANE_Word *) val = scanner->val[option].w;
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
/* word-array options: */
|
||
|
case OPT_GAMMA_VECTOR:
|
||
|
case OPT_GAMMA_VECTOR_R:
|
||
|
case OPT_GAMMA_VECTOR_G:
|
||
|
case OPT_GAMMA_VECTOR_B:
|
||
|
case OPT_HALFTONE_PATTERN:
|
||
|
memcpy (val, scanner->val[option].wa, scanner->opt[option].size);
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
/* string options: */
|
||
|
case OPT_SOURCE:
|
||
|
if ( (strcmp(val, FLB_STR) == 0) ||
|
||
|
(strcmp(val, ADF_STR) == 0) )
|
||
|
{
|
||
|
scanner->device->x_range.max = SANE_FIX(scanner->device->inquiry_fb_width * MM_PER_INCH);
|
||
|
scanner->device->y_range.max = SANE_FIX(scanner->device->inquiry_fb_length * MM_PER_INCH);
|
||
|
}
|
||
|
else if (strcmp(val, UTA_STR) == 0)
|
||
|
{
|
||
|
scanner->device->x_range.max = SANE_FIX(scanner->device->inquiry_uta_width * MM_PER_INCH);
|
||
|
scanner->device->y_range.max = SANE_FIX(scanner->device->inquiry_uta_length * MM_PER_INCH);
|
||
|
}
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_PARAMS; }
|
||
|
/* fall through */
|
||
|
case OPT_MODE:
|
||
|
case OPT_CALIB_MODE:
|
||
|
case OPT_SHADING_TYPE:
|
||
|
strcpy (val, scanner->val[option].s);
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
}
|
||
|
else if (action == SANE_ACTION_SET_VALUE)
|
||
|
{
|
||
|
DBG(DBG_sane_option,"sane_control_option %d, set value\n",option);
|
||
|
if (!SANE_OPTION_IS_SETTABLE (cap)) { return SANE_STATUS_INVAL; }
|
||
|
|
||
|
status = sanei_constrain_value(scanner->opt+option, val, info);
|
||
|
if (status != SANE_STATUS_GOOD) { return status; }
|
||
|
|
||
|
switch (option)
|
||
|
{
|
||
|
/* (mostly) side-effect-free word options: */
|
||
|
case OPT_X_RESOLUTION:
|
||
|
case OPT_Y_RESOLUTION:
|
||
|
case OPT_TL_X:
|
||
|
case OPT_TL_Y:
|
||
|
case OPT_BR_X:
|
||
|
case OPT_BR_Y:
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_PARAMS; }
|
||
|
/* fall through */
|
||
|
case OPT_NUM_OPTS:
|
||
|
case OPT_NEGATIVE:
|
||
|
case OPT_QUALITY:
|
||
|
case OPT_DOR:
|
||
|
case OPT_WARMUP:
|
||
|
#if 0
|
||
|
case OPT_SLOW:
|
||
|
case OPT_SMEAR:
|
||
|
#endif
|
||
|
case OPT_PREVIEW:
|
||
|
case OPT_ANALOG_GAMMA:
|
||
|
case OPT_ANALOG_GAMMA_R:
|
||
|
case OPT_ANALOG_GAMMA_G:
|
||
|
case OPT_ANALOG_GAMMA_B:
|
||
|
case OPT_BRIGHTNESS:
|
||
|
case OPT_CONTRAST:
|
||
|
case OPT_THRESHOLD:
|
||
|
case OPT_HIGHLIGHT:
|
||
|
case OPT_HIGHLIGHT_R:
|
||
|
case OPT_HIGHLIGHT_G:
|
||
|
case OPT_HIGHLIGHT_B:
|
||
|
case OPT_SHADOW:
|
||
|
case OPT_SHADOW_R:
|
||
|
case OPT_SHADOW_G:
|
||
|
case OPT_SHADOW_B:
|
||
|
case OPT_CAL_EXPOS_TIME:
|
||
|
case OPT_CAL_EXPOS_TIME_R:
|
||
|
case OPT_CAL_EXPOS_TIME_G:
|
||
|
case OPT_CAL_EXPOS_TIME_B:
|
||
|
case OPT_SCAN_EXPOS_TIME:
|
||
|
case OPT_SCAN_EXPOS_TIME_R:
|
||
|
case OPT_SCAN_EXPOS_TIME_G:
|
||
|
case OPT_SCAN_EXPOS_TIME_B:
|
||
|
case OPT_CAL_LAMP_DEN:
|
||
|
case OPT_SCAN_LAMP_DEN:
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_BIT_DEPTH:
|
||
|
if (scanner->val[option].w != *(SANE_Word *) val)
|
||
|
{
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
|
||
|
scanner->output_range.min = 0;
|
||
|
scanner->output_range.max = (int) pow(2, scanner->val[option].w) - 1;
|
||
|
scanner->output_range.quant = 0;
|
||
|
|
||
|
if (scanner->val[option].w == 8) /* 8 bit mode */
|
||
|
{
|
||
|
scanner->output_bytes = 1; /* 1 bytes output */
|
||
|
}
|
||
|
else /* > 8 bit mode */
|
||
|
{
|
||
|
scanner->output_bytes = 2; /* 2 bytes output */
|
||
|
}
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_PARAMS; }
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_RGB_BIND:
|
||
|
if (scanner->val[option].w != *(SANE_Word *) val)
|
||
|
{
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
if (scanner->val[option].w == SANE_FALSE)
|
||
|
{
|
||
|
if (scanner->device->inquiry_analog_gamma)
|
||
|
{
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_highlight)
|
||
|
{
|
||
|
scanner->opt[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_shadow)
|
||
|
{
|
||
|
scanner->opt[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_exposure_adj)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (scanner->device->inquiry_analog_gamma)
|
||
|
{
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_highlight)
|
||
|
{
|
||
|
scanner->opt[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_shadow)
|
||
|
{
|
||
|
scanner->opt[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (scanner->device->inquiry_exposure_adj)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_RESOLUTION_BIND:
|
||
|
if (scanner->val[option].w != *(SANE_Word *) val)
|
||
|
{
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
if (scanner->val[option].w == SANE_FALSE)
|
||
|
{ /* don't bind */
|
||
|
scanner->opt[OPT_Y_RESOLUTION].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_X_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_X_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_X_RESOLUTION;
|
||
|
}
|
||
|
else
|
||
|
{ /* bind */
|
||
|
scanner->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
|
||
|
scanner->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_SELECT_EXPOSURE_TIME:
|
||
|
if (scanner->val[option].w != *(SANE_Word *) val)
|
||
|
{
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
if (scanner->val[option].w == SANE_FALSE)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (strcmp(scanner->val[OPT_MODE].s, COLOR_STR) != 0) ||
|
||
|
(scanner->val[OPT_RGB_BIND].w == SANE_TRUE) )
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_SELECT_LAMP_DENSITY:
|
||
|
if (scanner->val[option].w != *(SANE_Word *) val)
|
||
|
{
|
||
|
scanner->val[option].w = *(SANE_Word *) val;
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
if (scanner->val[option].w == SANE_FALSE)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_LAMP_DEN].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_LAMP_DEN].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
/* side-effect-free word-array options: */
|
||
|
case OPT_HALFTONE_PATTERN:
|
||
|
case OPT_GAMMA_VECTOR:
|
||
|
case OPT_GAMMA_VECTOR_R:
|
||
|
case OPT_GAMMA_VECTOR_G:
|
||
|
case OPT_GAMMA_VECTOR_B:
|
||
|
memcpy (scanner->val[option].wa, val, scanner->opt[option].size);
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
/* side-effect-free single-string options: */
|
||
|
case OPT_SOURCE:
|
||
|
case OPT_CALIB_MODE:
|
||
|
case OPT_SHADING_TYPE:
|
||
|
if (scanner->val[option].s) { free (scanner->val[option].s); }
|
||
|
scanner->val[option].s = (SANE_Char*)strdup(val);
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
/* options with side-effects: */
|
||
|
|
||
|
case OPT_CUSTOM_GAMMA:
|
||
|
w = *(SANE_Word *) val;
|
||
|
if (w == scanner->val[OPT_CUSTOM_GAMMA].w) { return SANE_STATUS_GOOD; }
|
||
|
|
||
|
scanner->val[OPT_CUSTOM_GAMMA].w = w;
|
||
|
if (w) /* use custom_gamma_table */
|
||
|
{
|
||
|
const char *mode = scanner->val[OPT_MODE].s;
|
||
|
|
||
|
if ( (strcmp(mode, LINEART_STR) == 0) ||
|
||
|
(strcmp(mode, HALFTONE_STR) == 0) ||
|
||
|
(strcmp(mode, GRAY_STR) == 0) )
|
||
|
{ scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
else if (strcmp(mode, COLOR_STR) == 0)
|
||
|
{
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
else /* don't use custom_gamma_table */
|
||
|
{
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
return SANE_STATUS_GOOD;
|
||
|
|
||
|
case OPT_MODE:
|
||
|
{
|
||
|
int halftoning;
|
||
|
|
||
|
if (scanner->val[option].s) { free (scanner->val[option].s); }
|
||
|
|
||
|
scanner->val[option].s = (SANE_Char*)strdup(val);
|
||
|
|
||
|
if (info) {*info |=SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;}
|
||
|
|
||
|
scanner->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_RGB_BIND].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->val[OPT_RGB_BIND].w = SANE_TRUE;
|
||
|
|
||
|
scanner->opt[OPT_ANALOG_GAMMA].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_ANALOG_GAMMA_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_R].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_G].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME_B].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].cap |= SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
halftoning = (strcmp(val, HALFTONE_STR) == 0 || strcmp(val, COLOR_HALFTONE_STR) == 0);
|
||
|
|
||
|
if (halftoning || strcmp(val, LINEART_STR) == 0 || strcmp(val, COLOR_LINEART_STR) == 0)
|
||
|
{ /* one bit modes */
|
||
|
if (scanner->device->inquiry_reverse)
|
||
|
{ scanner->opt[OPT_NEGATIVE].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (halftoning)
|
||
|
{ /* halftoning modes */
|
||
|
scanner->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->device->inquiry_highlight)
|
||
|
{scanner->opt[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;}
|
||
|
|
||
|
if (scanner->device->inquiry_shadow)
|
||
|
{scanner->opt[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;}
|
||
|
|
||
|
scanner->opt[OPT_HALFTONE_DIMENSION].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->val[OPT_HALFTONE_DIMENSION].w)
|
||
|
{ scanner->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (scanner->device->inquiry_gamma_dwload)
|
||
|
{ scanner->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
else
|
||
|
{ scanner->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE; }
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
|
||
|
scanner->exposure_time_range.min = SANE_FIX(scanner->device->inquiry_exposure_time_h_min
|
||
|
* scanner->device->inquiry_exposure_time_step_unit);
|
||
|
}
|
||
|
else
|
||
|
{ /* lineart modes */
|
||
|
scanner->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->device->inquiry_gamma_dwload)
|
||
|
{ scanner->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
else
|
||
|
{ scanner->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE; }
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
|
||
|
scanner->exposure_time_range.min = SANE_FIX(scanner->device->inquiry_exposure_time_l_min
|
||
|
* scanner->device->inquiry_exposure_time_step_unit);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ /* multi-bit modes(gray or color) */
|
||
|
scanner->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (scanner->device->inquiry_highlight)
|
||
|
{ scanner->opt[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (scanner->device->inquiry_shadow)
|
||
|
{ scanner->opt[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (scanner->device->inquiry_reverse_multi)
|
||
|
{ scanner->opt[OPT_NEGATIVE].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (scanner->device->inquiry_gamma_dwload)
|
||
|
{ scanner->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
else
|
||
|
{ scanner->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE; }
|
||
|
|
||
|
if (scanner->device->inquiry_analog_gamma)
|
||
|
{ scanner->opt[OPT_ANALOG_GAMMA].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
|
||
|
if (strcmp(val, COLOR_STR) == 0)
|
||
|
{
|
||
|
if ( (scanner->device->inquiry_analog_gamma) ||
|
||
|
(scanner->device->inquiry_highlight) ||
|
||
|
(scanner->device->inquiry_shadow) ||
|
||
|
(scanner->device->inquiry_exposure_adj) )
|
||
|
{ scanner->opt[OPT_RGB_BIND].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
|
||
|
scanner->exposure_time_range.min = SANE_FIX(scanner->device->inquiry_exposure_time_c_min
|
||
|
* scanner->device->inquiry_exposure_time_step_unit);
|
||
|
}
|
||
|
else /* grayscale */
|
||
|
{
|
||
|
scanner->exposure_time_range.min = SANE_FIX(scanner->device->inquiry_exposure_time_g_min
|
||
|
* scanner->device->inquiry_exposure_time_step_unit);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (scanner->val[OPT_CUSTOM_GAMMA].w)
|
||
|
{
|
||
|
if ( (strcmp(val, LINEART_STR) == 0) ||
|
||
|
(strcmp(val, HALFTONE_STR) == 0) ||
|
||
|
(strcmp(val, GRAY_STR) == 0) )
|
||
|
{ scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; }
|
||
|
else if (strcmp(val, COLOR_STR) == 0)
|
||
|
{
|
||
|
scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
|
||
|
}
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
case OPT_HALFTONE_DIMENSION:
|
||
|
/* halftone pattern dimension affects halftone pattern option: */
|
||
|
{
|
||
|
unsigned dim = *(SANE_Word *) val;
|
||
|
|
||
|
scanner->val[option].w = dim;
|
||
|
|
||
|
if (info) { *info |= SANE_INFO_RELOAD_OPTIONS; }
|
||
|
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
|
||
|
|
||
|
if (dim > 0)
|
||
|
{
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
|
||
|
scanner->opt[OPT_HALFTONE_PATTERN].size = dim * sizeof (SANE_Word);
|
||
|
}
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
}
|
||
|
} /* else */
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE GET PARAMETERS ------------------------ */
|
||
|
|
||
|
|
||
|
SANE_Status sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
const char *mode;
|
||
|
|
||
|
DBG(DBG_sane_info,"sane_get_parameters\n");
|
||
|
|
||
|
if (!scanner->scanning)
|
||
|
{ /* not scanning, so lets use recent values */
|
||
|
double width, length, x_dpi, y_dpi;
|
||
|
|
||
|
memset(&scanner->params, 0, sizeof (scanner->params));
|
||
|
|
||
|
width = SANE_UNFIX(scanner->val[OPT_BR_X].w - scanner->val[OPT_TL_X].w);
|
||
|
length = SANE_UNFIX(scanner->val[OPT_BR_Y].w - scanner->val[OPT_TL_Y].w);
|
||
|
x_dpi = SANE_UNFIX(scanner->val[OPT_X_RESOLUTION].w);
|
||
|
y_dpi = SANE_UNFIX(scanner->val[OPT_Y_RESOLUTION].w);
|
||
|
if ( (scanner->val[OPT_RESOLUTION_BIND].w == SANE_TRUE) || (scanner->val[OPT_PREVIEW].w == SANE_TRUE) )
|
||
|
{ y_dpi = x_dpi; }
|
||
|
|
||
|
if (x_dpi > 0.0 && y_dpi > 0.0 && width > 0.0 && length > 0.0)
|
||
|
{
|
||
|
double x_dots_per_mm = x_dpi / MM_PER_INCH;
|
||
|
double y_dots_per_mm = y_dpi / MM_PER_INCH;
|
||
|
|
||
|
scanner->params.pixels_per_line = width * x_dots_per_mm;
|
||
|
scanner->params.lines = length * y_dots_per_mm;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mode = scanner->val[OPT_MODE].s;
|
||
|
|
||
|
if (strcmp(mode, LINEART_STR) == 0 || strcmp(mode, HALFTONE_STR) == 0)
|
||
|
{
|
||
|
scanner->params.format = SANE_FRAME_GRAY;
|
||
|
scanner->params.bytes_per_line = (scanner->params.pixels_per_line + 7) / 8;
|
||
|
scanner->params.depth = 1;
|
||
|
}
|
||
|
else if (strcmp(mode, GRAY_STR) == 0)
|
||
|
{
|
||
|
scanner->params.format = SANE_FRAME_GRAY;
|
||
|
scanner->params.bytes_per_line = scanner->params.pixels_per_line * scanner->output_bytes;
|
||
|
scanner->params.depth = 8 * scanner->output_bytes;
|
||
|
}
|
||
|
else if (strcmp(mode, COLOR_LINEART_STR) == 0 || strcmp(mode, COLOR_HALFTONE_STR) == 0 )
|
||
|
{
|
||
|
if (scanner->device->inquiry_one_pass_color)
|
||
|
{
|
||
|
scanner->device->three_pass = 0;
|
||
|
scanner->params.format = SANE_FRAME_RGB;
|
||
|
scanner->params.bytes_per_line = 3 * scanner->params.pixels_per_line;
|
||
|
scanner->params.depth = 8;
|
||
|
}
|
||
|
else /* three pass color */
|
||
|
{
|
||
|
scanner->device->three_pass = 1;
|
||
|
scanner->params.format = SANE_FRAME_RED + scanner->device->three_pass_color - 1;
|
||
|
scanner->params.bytes_per_line = scanner->params.pixels_per_line;
|
||
|
scanner->params.depth = 8;
|
||
|
}
|
||
|
}
|
||
|
else /* RGB */
|
||
|
{
|
||
|
if (scanner->device->inquiry_one_pass_color)
|
||
|
{
|
||
|
scanner->device->three_pass = 0;
|
||
|
scanner->params.format = SANE_FRAME_RGB;
|
||
|
scanner->params.bytes_per_line = 3 * scanner->params.pixels_per_line * scanner->output_bytes;
|
||
|
scanner->params.depth = 8 * scanner->output_bytes;
|
||
|
}
|
||
|
else /* three pass color */
|
||
|
{
|
||
|
scanner->device->three_pass = 1;
|
||
|
scanner->params.format = SANE_FRAME_RED + scanner->device->three_pass_color - 1;
|
||
|
scanner->params.bytes_per_line = scanner->params.pixels_per_line * scanner->output_bytes;
|
||
|
scanner->params.depth = 8 * scanner->output_bytes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
scanner->params.last_frame = (scanner->params.format != SANE_FRAME_RED && scanner->params.format != SANE_FRAME_GREEN);
|
||
|
|
||
|
if (params) { *params = scanner->params; }
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE START --------------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_start(SANE_Handle handle)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
int fds[2];
|
||
|
const char *mode;
|
||
|
double xbasedots, ybasedots;
|
||
|
const char *scan_source;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_start\n");
|
||
|
|
||
|
mode = scanner->val[OPT_MODE].s;
|
||
|
|
||
|
if (scanner->device->sfd < 0) /* first call for this scan */
|
||
|
{
|
||
|
if ( sanei_scsi_open(scanner->device->sane.name, &(scanner->device->sfd), sense_handler,
|
||
|
scanner->device) != SANE_STATUS_GOOD )
|
||
|
{
|
||
|
DBG(DBG_error, "sane_start: open of %s failed:\n", scanner->device->sane.name);
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
|
||
|
umax_initialize_values(scanner->device);
|
||
|
scanner->device->three_pass_color = 1;
|
||
|
|
||
|
/* test for adf and uta */
|
||
|
scan_source = scanner->val[OPT_SOURCE].s;
|
||
|
|
||
|
if (strcmp(scan_source, UTA_STR) == 0)
|
||
|
{
|
||
|
if ( (scanner->device->inquiry_uta != 0) &&
|
||
|
(scanner->device->inquiry_transavail != 0) )
|
||
|
{ scanner->device->uta=1; }
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: Transparency Adapter not available\n");
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd=-1;
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
scanner->device->uta=0;
|
||
|
|
||
|
if (strcmp(scan_source, ADF_STR) == 0)
|
||
|
{
|
||
|
if ( (scanner->device->inquiry_adf) && (scanner->device->inquiry_adfmode) )
|
||
|
{ scanner->device->adf=1; }
|
||
|
else
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: Automatic Document Feeder not available\n");
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd=-1;
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ scanner->device->adf=0; }
|
||
|
}
|
||
|
|
||
|
/* grab scanner */
|
||
|
if (umax_grab_scanner(scanner->device))
|
||
|
{
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd=-1;
|
||
|
DBG(DBG_warning,"WARNING: unable to reserve scanner: device busy\n");
|
||
|
return SANE_STATUS_DEVICE_BUSY;
|
||
|
}
|
||
|
|
||
|
scanner->scanning = SANE_TRUE;
|
||
|
|
||
|
if (scanner->device->inquiry_GIB & 32) /* 16 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 32;
|
||
|
DBG(DBG_sane_info, "Using 16 bits for gamma input\n");
|
||
|
}
|
||
|
if (scanner->device->inquiry_GIB & 16) /* 14 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 16;
|
||
|
DBG(DBG_sane_info, "Using 14 bits for gamma input\n");
|
||
|
}
|
||
|
if (scanner->device->inquiry_GIB & 8) /* 12 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 8;
|
||
|
DBG(DBG_sane_info, "Using 12 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 4) /* 10 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 4;
|
||
|
DBG(DBG_sane_info, "Using 10 bits for gamma input\n");
|
||
|
}
|
||
|
else if (scanner->device->inquiry_GIB & 2) /* 9 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 2;
|
||
|
DBG(DBG_sane_info, "Using 9 bits for gamma input\n");
|
||
|
}
|
||
|
else /* 8 bit input mode */
|
||
|
{
|
||
|
scanner->device->gamma_input_bits_code = 1;
|
||
|
DBG(DBG_sane_info, "Using 8 bits for gamma input\n");
|
||
|
}
|
||
|
|
||
|
if (scanner->val[OPT_BIT_DEPTH].w == 16) /* 16 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 16;
|
||
|
scanner->device->bits_per_pixel_code = 32;
|
||
|
scanner->device->max_value = 65536;
|
||
|
DBG(DBG_sane_info,"Using 16 bits for output\n");
|
||
|
}
|
||
|
else if (scanner->val[OPT_BIT_DEPTH].w == 14) /* 14 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 14;
|
||
|
scanner->device->bits_per_pixel_code = 16;
|
||
|
scanner->device->max_value = 16383;
|
||
|
DBG(DBG_sane_info,"Using 14 bits for output\n");
|
||
|
}
|
||
|
else if (scanner->val[OPT_BIT_DEPTH].w == 12) /* 12 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 12;
|
||
|
scanner->device->bits_per_pixel_code = 8;
|
||
|
scanner->device->max_value = 4095;
|
||
|
DBG(DBG_sane_info,"Using 12 bits for output\n");
|
||
|
}
|
||
|
else if (scanner->val[OPT_BIT_DEPTH].w == 10) /* 10 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 10;
|
||
|
scanner->device->bits_per_pixel_code = 4;
|
||
|
scanner->device->max_value = 1023;
|
||
|
DBG(DBG_sane_info,"Using 10 bits for output\n");
|
||
|
}
|
||
|
else if (scanner->val[OPT_BIT_DEPTH].w == 9) /* 9 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 9;
|
||
|
scanner->device->bits_per_pixel_code = 2;
|
||
|
scanner->device->max_value = 511;
|
||
|
DBG(DBG_sane_info,"Using 9 bits for output\n");
|
||
|
}
|
||
|
else /* 8 bit output mode */
|
||
|
{
|
||
|
scanner->device->bits_per_pixel = 8;
|
||
|
scanner->device->bits_per_pixel_code = 1;
|
||
|
scanner->device->max_value = 255;
|
||
|
DBG(DBG_sane_info,"Using 8 bits for output\n");
|
||
|
}
|
||
|
|
||
|
scanner->device->reverse = scanner->device->reverse_multi = scanner->val[OPT_NEGATIVE].w;
|
||
|
|
||
|
scanner->device->threshold = P_100_TO_255(scanner->val[OPT_THRESHOLD].w);
|
||
|
scanner->device->brightness = P_200_TO_255(scanner->val[OPT_BRIGHTNESS].w);
|
||
|
scanner->device->contrast = P_200_TO_255(scanner->val[OPT_CONTRAST].w);
|
||
|
|
||
|
scanner->device->quality = scanner->val[OPT_QUALITY].w;
|
||
|
scanner->device->dor = scanner->val[OPT_DOR].w;
|
||
|
scanner->device->preview = scanner->val[OPT_PREVIEW].w;
|
||
|
scanner->device->warmup = scanner->val[OPT_WARMUP].w;
|
||
|
|
||
|
#if 0
|
||
|
scanner->device->slow = scanner->val[OPT_SLOW].w;
|
||
|
scanner->device->smear = scanner->val[OPT_SMEAR].w;
|
||
|
#endif
|
||
|
|
||
|
scanner->device->analog_gamma_r =
|
||
|
scanner->device->analog_gamma_g =
|
||
|
scanner->device->analog_gamma_b =
|
||
|
umax_calculate_analog_gamma(SANE_UNFIX(scanner->val[OPT_ANALOG_GAMMA].w));
|
||
|
|
||
|
scanner->device->highlight_r =
|
||
|
scanner->device->highlight_g =
|
||
|
scanner->device->highlight_b = P_100_TO_255(scanner->val[OPT_HIGHLIGHT].w);
|
||
|
|
||
|
scanner->device->shadow_r =
|
||
|
scanner->device->shadow_g =
|
||
|
scanner->device->shadow_b = P_100_TO_255(scanner->val[OPT_SHADOW].w);
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->device->exposure_time_calibration_r =
|
||
|
scanner->device->exposure_time_calibration_g =
|
||
|
scanner->device->exposure_time_calibration_b = SANE_UNFIX(scanner->val[OPT_CAL_EXPOS_TIME].w);
|
||
|
|
||
|
scanner->device->exposure_time_scan_r =
|
||
|
scanner->device->exposure_time_scan_g =
|
||
|
scanner->device->exposure_time_scan_b = SANE_UNFIX(scanner->val[OPT_SCAN_EXPOS_TIME].w);
|
||
|
}
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_LAMP_DENSITY].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->device->c_density = P_100_TO_254(scanner->val[OPT_CAL_LAMP_DEN].w);
|
||
|
scanner->device->s_density = P_100_TO_254(scanner->val[OPT_SCAN_LAMP_DEN].w);
|
||
|
}
|
||
|
|
||
|
if (strcmp(mode, LINEART_STR) == 0) { scanner->device->colormode = LINEART; }
|
||
|
else if (strcmp(mode, HALFTONE_STR) == 0) { scanner->device->colormode = HALFTONE; }
|
||
|
else if (strcmp(mode, GRAY_STR) == 0) { scanner->device->colormode = GRAYSCALE; }
|
||
|
else if (strcmp(mode, COLOR_LINEART_STR) == 0) { scanner->device->colormode = RGB_LINEART; }
|
||
|
else if (strcmp(mode, COLOR_HALFTONE_STR) == 0) { scanner->device->colormode = RGB_HALFTONE; }
|
||
|
else if (strcmp(mode, COLOR_STR) == 0)
|
||
|
{
|
||
|
scanner->device->colormode = RGB;
|
||
|
if (scanner->val[OPT_RGB_BIND].w == SANE_FALSE)
|
||
|
{
|
||
|
scanner->device->analog_gamma_r =
|
||
|
umax_calculate_analog_gamma( SANE_UNFIX(scanner->val[OPT_ANALOG_GAMMA_R].w) );
|
||
|
scanner->device->analog_gamma_g =
|
||
|
umax_calculate_analog_gamma( SANE_UNFIX(scanner->val[OPT_ANALOG_GAMMA_G].w) );
|
||
|
scanner->device->analog_gamma_b =
|
||
|
umax_calculate_analog_gamma( SANE_UNFIX(scanner->val[OPT_ANALOG_GAMMA_B].w) );
|
||
|
|
||
|
scanner->device->highlight_r = P_100_TO_255(scanner->val[OPT_HIGHLIGHT_R].w);
|
||
|
scanner->device->highlight_g = P_100_TO_255(scanner->val[OPT_HIGHLIGHT_G].w);
|
||
|
scanner->device->highlight_b = P_100_TO_255(scanner->val[OPT_HIGHLIGHT_B].w);
|
||
|
|
||
|
scanner->device->shadow_r = P_100_TO_255(scanner->val[OPT_SHADOW_R].w);
|
||
|
scanner->device->shadow_g = P_100_TO_255(scanner->val[OPT_SHADOW_G].w);
|
||
|
scanner->device->shadow_b = P_100_TO_255(scanner->val[OPT_SHADOW_B].w);
|
||
|
|
||
|
if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE)
|
||
|
{
|
||
|
scanner->device->exposure_time_calibration_r = P_100_TO_255(scanner->val[OPT_CAL_EXPOS_TIME_R].w);
|
||
|
scanner->device->exposure_time_calibration_g = P_100_TO_255(scanner->val[OPT_CAL_EXPOS_TIME_G].w);
|
||
|
scanner->device->exposure_time_calibration_b = P_100_TO_255(scanner->val[OPT_CAL_EXPOS_TIME_B].w);
|
||
|
|
||
|
scanner->device->exposure_time_scan_r = P_100_TO_255(scanner->val[OPT_SCAN_EXPOS_TIME_R].w);
|
||
|
scanner->device->exposure_time_scan_g = P_100_TO_255(scanner->val[OPT_SCAN_EXPOS_TIME_G].w);
|
||
|
scanner->device->exposure_time_scan_b = P_100_TO_255(scanner->val[OPT_SCAN_EXPOS_TIME_B].w);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_0000) == 0)
|
||
|
{ scanner->device->calibration = 0; }
|
||
|
else if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_1111) == 0)
|
||
|
{ scanner->device->calibration = 15; }
|
||
|
else if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_1110) == 0)
|
||
|
{ scanner->device->calibration = 14; }
|
||
|
else if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_1101) == 0)
|
||
|
{ scanner->device->calibration = 13; }
|
||
|
else if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_1010) == 0)
|
||
|
{ scanner->device->calibration = 10; }
|
||
|
else if (strcmp(scanner->val[OPT_CALIB_MODE].s,CALIB_MODE_1001) == 0)
|
||
|
{ scanner->device->calibration = 9; }
|
||
|
|
||
|
if (strcmp(scanner->val[OPT_SHADING_TYPE].s,SHADING_TYPE_ONE_LINE_TEXT) == 0)
|
||
|
{ scanner->device->shading_type = SHADING_TYPE_ONE_LINE; }
|
||
|
else if (strcmp(scanner->val[OPT_SHADING_TYPE].s,SHADING_TYPE_AVERAGE_TEXT) == 0)
|
||
|
{ scanner->device->shading_type = SHADING_TYPE_AVERAGE; }
|
||
|
else if (strcmp(scanner->val[OPT_SHADING_TYPE].s,SHADING_TYPE_ONE_LINE_INVERT_TEXT) == 0)
|
||
|
{ scanner->device->shading_type = SHADING_TYPE_ONE_LINE_INVERT; }
|
||
|
else if (strcmp(scanner->val[OPT_SHADING_TYPE].s,SHADING_TYPE_AVERAGE_INVERT_TEXT) == 0)
|
||
|
{ scanner->device->shading_type = SHADING_TYPE_AVERAGE_INVERT; }
|
||
|
|
||
|
/* get and set geometric values for scanning */
|
||
|
scanner->device->x_resolution = SANE_UNFIX(scanner->val[OPT_X_RESOLUTION].w);
|
||
|
scanner->device->y_resolution = SANE_UNFIX(scanner->val[OPT_Y_RESOLUTION].w);
|
||
|
|
||
|
if ( (scanner->val[OPT_RESOLUTION_BIND].w == SANE_TRUE) || (scanner->val[OPT_PREVIEW].w == SANE_TRUE) )
|
||
|
{ scanner->device->y_resolution = scanner->device->x_resolution; }
|
||
|
|
||
|
xbasedots = scanner->device->x_coordinate_base / MM_PER_INCH;
|
||
|
ybasedots = scanner->device->y_coordinate_base / MM_PER_INCH;
|
||
|
|
||
|
scanner->device->upper_left_x = ((int) (SANE_UNFIX(scanner->val[OPT_TL_X].w) * xbasedots)) & 65534;
|
||
|
scanner->device->upper_left_y = ((int) (SANE_UNFIX(scanner->val[OPT_TL_Y].w) * ybasedots)) & 65534;
|
||
|
|
||
|
scanner->device->scanwidth = ((int)((SANE_UNFIX(scanner->val[OPT_BR_X].w - scanner->val[OPT_TL_X].w)) *
|
||
|
xbasedots)) & 65534;
|
||
|
scanner->device->scanlength = (SANE_UNFIX(scanner->val[OPT_BR_Y].w - scanner->val[OPT_TL_Y].w)) *
|
||
|
ybasedots;
|
||
|
|
||
|
if (umax_check_values(scanner->device) != 0)
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: invalid scan-values\n");
|
||
|
scanner->scanning = SANE_FALSE;
|
||
|
umax_give_scanner(scanner->device);
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd=-1;
|
||
|
return SANE_STATUS_INVAL;
|
||
|
}
|
||
|
|
||
|
scanner->params.bytes_per_line = scanner->device->row_len;
|
||
|
scanner->params.pixels_per_line = scanner->device->width_in_pixels;
|
||
|
scanner->params.lines = scanner->device->length_in_pixels;
|
||
|
|
||
|
sane_get_parameters(scanner, 0);
|
||
|
|
||
|
DBG(DBG_sane_info,"x_resolution (dpi) = %d\n", scanner->device->x_resolution);
|
||
|
DBG(DBG_sane_info,"y_resolution (dpi) = %d\n", scanner->device->y_resolution);
|
||
|
DBG(DBG_sane_info,"x_coordinate_base (dpi) = %d\n", scanner->device->x_coordinate_base);
|
||
|
DBG(DBG_sane_info,"y_coordinate_base (dpi) = %d\n", scanner->device->y_coordinate_base);
|
||
|
DBG(DBG_sane_info,"upper_left_x (xbase) = %d\n", scanner->device->upper_left_x);
|
||
|
DBG(DBG_sane_info,"upper_left_y (ybase) = %d\n", scanner->device->upper_left_y);
|
||
|
DBG(DBG_sane_info,"scanwidth (xbase) = %d\n", scanner->device->scanwidth);
|
||
|
DBG(DBG_sane_info,"scanlength (ybase) = %d\n", scanner->device->scanlength);
|
||
|
DBG(DBG_sane_info,"width in pixels = %d\n", scanner->device->width_in_pixels);
|
||
|
DBG(DBG_sane_info,"length in pixels = %d\n", scanner->device->length_in_pixels);
|
||
|
DBG(DBG_sane_info,"bits per pixel/color = %d\n", scanner->device->bits_per_pixel);
|
||
|
DBG(DBG_sane_info,"bytes per line = %d\n", scanner->params.bytes_per_line);
|
||
|
DBG(DBG_sane_info,"pixels_per_line = %d\n", scanner->params.pixels_per_line);
|
||
|
DBG(DBG_sane_info,"lines = %d\n", scanner->params.lines);
|
||
|
DBG(DBG_sane_info,"negative = %d\n", scanner->device->reverse);
|
||
|
DBG(DBG_sane_info,"threshold (lineart) = %d\n", scanner->device->threshold);
|
||
|
DBG(DBG_sane_info,"brightness (halftone) = %d\n", scanner->device->brightness);
|
||
|
DBG(DBG_sane_info,"contrast (halftone) = %d\n", scanner->device->contrast);
|
||
|
|
||
|
DBG(DBG_sane_info,"analog_gamma = %d %d %d\n",
|
||
|
scanner->device->analog_gamma_r,
|
||
|
scanner->device->analog_gamma_g,
|
||
|
scanner->device->analog_gamma_b);
|
||
|
DBG(DBG_sane_info,"highlight = %d %d %d\n",
|
||
|
scanner->device->highlight_r,
|
||
|
scanner->device->highlight_g,
|
||
|
scanner->device->highlight_b);
|
||
|
DBG(DBG_sane_info,"shadow = %d %d %d\n",
|
||
|
scanner->device->shadow_r,
|
||
|
scanner->device->shadow_g,
|
||
|
scanner->device->shadow_b);
|
||
|
DBG(DBG_sane_info,"calibrat. exposure time = %d %d %d\n",
|
||
|
scanner->device->exposure_time_calibration_r,
|
||
|
scanner->device->exposure_time_calibration_g,
|
||
|
scanner->device->exposure_time_calibration_b);
|
||
|
DBG(DBG_sane_info,"scan exposure time = %d %d %d\n",
|
||
|
scanner->device->exposure_time_scan_r,
|
||
|
scanner->device->exposure_time_scan_g,
|
||
|
scanner->device->exposure_time_scan_b);
|
||
|
|
||
|
DBG(DBG_sane_info,"calibration = %s\n", scanner->val[OPT_CALIB_MODE].s);
|
||
|
DBG(DBG_sane_info,"quality calibration = %d\n", scanner->device->quality);
|
||
|
DBG(DBG_sane_info,"fast preview function = %d\n", scanner->device->preview);
|
||
|
|
||
|
#if 0
|
||
|
DBG(DBG_sane_info,"slow scan speed = %d\n", scanner->device->slow);
|
||
|
DBG(DBG_sane_info,"smear = %d\n", scanner->device->smear);
|
||
|
#endif
|
||
|
|
||
|
/* send halftonepattern */
|
||
|
if ( (strcmp(mode, HALFTONE_STR) == 0) || (strcmp(mode, COLOR_HALFTONE_STR) == 0) )
|
||
|
{
|
||
|
umax_send_halftone_pattern(scanner->device, (char *) &(scanner->halftone_pattern[0]),
|
||
|
scanner->val[OPT_HALFTONE_DIMENSION].w );
|
||
|
scanner->device->halftone = WD_halftone_download;
|
||
|
} /* end of send halftonepattern */
|
||
|
|
||
|
|
||
|
} /* ------------ end of first call -------------- */
|
||
|
|
||
|
|
||
|
/* send gammacurves */
|
||
|
if (scanner->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
|
||
|
{
|
||
|
if (strcmp(mode, COLOR_STR) == 0)
|
||
|
{
|
||
|
if (scanner->device->three_pass == 0) /* one pass color scan */
|
||
|
{
|
||
|
unsigned int i, dest, color, value;
|
||
|
char *gamma;
|
||
|
|
||
|
gamma = malloc( (size_t) (3 * scanner->gamma_length * scanner->output_bytes) );
|
||
|
if (gamma == NULL)
|
||
|
{
|
||
|
DBG(DBG_warning,"WARNING: not able to allocate memory for gamma table, gamma ignored !!!\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dest=0;
|
||
|
for(color=1; color <= 3; color++)
|
||
|
{
|
||
|
for(i=0; i < scanner->gamma_length; i++)
|
||
|
{
|
||
|
value = scanner->gamma_table[color][i];
|
||
|
if (scanner->output_bytes == 2)
|
||
|
{ gamma[dest++] = scanner->gamma_table[0][value] / 256; }
|
||
|
gamma[dest++] = (scanner->gamma_table[0][value] & 255);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBG(DBG_sane_info,"sending 3 * %d bytes of gamma data for RGB\n",
|
||
|
scanner->gamma_length * scanner->output_bytes);
|
||
|
|
||
|
umax_send_gamma_data(scanner->device, &gamma[0], 3);
|
||
|
scanner->device->digital_gamma_r =
|
||
|
scanner->device->digital_gamma_g =
|
||
|
scanner->device->digital_gamma_b = WD_gamma_download;
|
||
|
free(gamma);
|
||
|
}
|
||
|
}
|
||
|
else /* three pass color scan */
|
||
|
{
|
||
|
unsigned int i, dest, color, value;
|
||
|
char *gamma;
|
||
|
|
||
|
gamma = malloc( (size_t) (scanner->gamma_length * scanner->output_bytes) );
|
||
|
if (gamma == NULL)
|
||
|
{
|
||
|
DBG(DBG_warning,"not able to allocate memory for gamma table, gamma ignored !!!\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dest = 0;
|
||
|
color = scanner->device->three_pass_color;
|
||
|
for(i = 0; i < scanner->gamma_length; i++)
|
||
|
{
|
||
|
value = scanner->gamma_table[color][i];
|
||
|
if (scanner->output_bytes == 2)
|
||
|
{ gamma[dest++] = scanner->gamma_table[0][value] / 256; }
|
||
|
gamma[dest++] = (scanner->gamma_table[0][value] & 255);
|
||
|
}
|
||
|
|
||
|
DBG(DBG_sane_info,"sending %d bytes of gamma data for color %d\n",
|
||
|
scanner->gamma_length * scanner->output_bytes, color);
|
||
|
|
||
|
umax_send_gamma_data(scanner->device, &gamma[0], 1);
|
||
|
scanner->device->digital_gamma_r =
|
||
|
scanner->device->digital_gamma_g =
|
||
|
scanner->device->digital_gamma_b = WD_gamma_download;
|
||
|
free(gamma);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else /* grayscale scan */
|
||
|
{
|
||
|
int i, dest;
|
||
|
char *gamma;
|
||
|
|
||
|
gamma = malloc( (size_t) (scanner->gamma_length * scanner->output_bytes) );
|
||
|
if (gamma == NULL)
|
||
|
{
|
||
|
DBG(DBG_warning,"WARNING: not able to allocate memory for gamma table, gamma ignored !!!\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dest=0;
|
||
|
for(i=0; i < scanner->gamma_length; i++)
|
||
|
{
|
||
|
if (scanner->output_bytes == 2)
|
||
|
{ gamma[dest++] = scanner->gamma_table[0][i] / 256; }
|
||
|
gamma[dest++] = (scanner->gamma_table[0][i] & 255);
|
||
|
}
|
||
|
|
||
|
DBG(DBG_sane_info,"sending %d bytes of gamma data for gray\n",
|
||
|
scanner->gamma_length * scanner->output_bytes);
|
||
|
|
||
|
umax_send_gamma_data(scanner->device, &gamma[0], 1);
|
||
|
scanner->device->digital_gamma_r = WD_gamma_download;
|
||
|
free(gamma);
|
||
|
}
|
||
|
}
|
||
|
} /* end of send gammacurves */
|
||
|
|
||
|
umax_reposition_scanner(scanner->device);
|
||
|
umax_set_window_param (scanner->device);
|
||
|
umax_start_scan (scanner->device);
|
||
|
umax_do_calibration (scanner->device);
|
||
|
|
||
|
|
||
|
if (pipe(fds) < 0) /* create a pipe, fds[0]=read-fd, fds[1]=write-fd */
|
||
|
{
|
||
|
DBG(DBG_error,"ERROR: could not create pipe\n");
|
||
|
scanner->scanning = SANE_FALSE;
|
||
|
umax_give_scanner(scanner->device);
|
||
|
sanei_scsi_close(scanner->device->sfd);
|
||
|
scanner->device->sfd=-1;
|
||
|
return SANE_STATUS_IO_ERROR;
|
||
|
}
|
||
|
|
||
|
scanner->reader_pid = fork(); /* create reader routine as new process */
|
||
|
if (scanner->reader_pid == 0)
|
||
|
{ /* reader_pid = 0 ===> child process */
|
||
|
sigset_t ignore_set;
|
||
|
struct SIGACTION act;
|
||
|
|
||
|
close(fds[0]);
|
||
|
|
||
|
sigfillset(&ignore_set);
|
||
|
sigdelset(&ignore_set, SIGTERM);
|
||
|
sigprocmask(SIG_SETMASK, &ignore_set, 0);
|
||
|
|
||
|
memset(&act, 0, sizeof (act));
|
||
|
sigaction (SIGTERM, &act, 0);
|
||
|
|
||
|
_exit(reader_process(scanner, fds[1])); /* don't use exit() since that would run the atexit() handlers */
|
||
|
}
|
||
|
close(fds[1]);
|
||
|
scanner->pipe = fds[0];
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE READ ---------------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
ssize_t nread;
|
||
|
|
||
|
*len = 0;
|
||
|
|
||
|
nread = read(scanner->pipe, buf, max_len);
|
||
|
DBG(DBG_sane_info, "sane_read: read %ld bytes\n", (long) nread);
|
||
|
|
||
|
if (!(scanner->scanning)) { return do_cancel(scanner); }
|
||
|
|
||
|
if (nread < 0)
|
||
|
{
|
||
|
if (errno == EAGAIN) { return SANE_STATUS_GOOD; }
|
||
|
else
|
||
|
{
|
||
|
do_cancel(scanner);
|
||
|
return SANE_STATUS_IO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*len = nread;
|
||
|
|
||
|
if (nread == 0)
|
||
|
{
|
||
|
if ( (scanner->device->three_pass == 0) ||
|
||
|
(scanner->device->colormode<=RGB_LINEART) ||
|
||
|
(++(scanner->device->three_pass_color) > 3) )
|
||
|
{ do_cancel(scanner); }
|
||
|
|
||
|
return close_pipe(scanner); /* close pipe */
|
||
|
}
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE CANCEL -------------------------------- */
|
||
|
|
||
|
|
||
|
void sane_cancel(SANE_Handle handle)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_cancel\n");
|
||
|
|
||
|
if (scanner->scanning)
|
||
|
{
|
||
|
do_cancel(scanner);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE SET IO MODE --------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_set_io_mode: non_blocking=%d\n",non_blocking);
|
||
|
|
||
|
if (!scanner->scanning) { return SANE_STATUS_INVAL; }
|
||
|
|
||
|
if (fcntl (scanner->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
|
||
|
{ return SANE_STATUS_IO_ERROR; }
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------ SANE GET SELECT FD ------------------------- */
|
||
|
|
||
|
|
||
|
SANE_Status sane_get_select_fd(SANE_Handle handle, SANE_Int *fd)
|
||
|
{
|
||
|
Umax_Scanner *scanner = handle;
|
||
|
|
||
|
DBG(DBG_sane_init,"sane_get_select_fd\n");
|
||
|
|
||
|
if (!scanner->scanning) { return SANE_STATUS_INVAL; }
|
||
|
*fd = scanner->pipe;
|
||
|
|
||
|
return SANE_STATUS_GOOD;
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------ EOF ---------------------------------------- */
|