kopia lustrzana https://gitlab.com/sane-project/backends
4341 wiersze
94 KiB
C
4341 wiersze
94 KiB
C
/* sane - Scanner Access Now Easy.
|
||
Copyright (C) 2000 Jochen Eisinger <jochen.eisinger@gmx.net>
|
||
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 Mustek PP flatbed scanners. */
|
||
|
||
#include "../include/sane/config.h"
|
||
|
||
#include <ctype.h>
|
||
#include <errno.h>
|
||
#include <limits.h>
|
||
#include <signal.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <math.h>
|
||
|
||
#include <sys/time.h>
|
||
#include <sys/types.h>
|
||
|
||
#include "../include/sane/sane.h"
|
||
#include "../include/sane/sanei.h"
|
||
#include "../include/sane/saneopts.h"
|
||
#include "../include/sane/sanei_pa4s2.h"
|
||
|
||
#include "mustek_pp.h"
|
||
|
||
#define BACKEND_NAME mustek_pp
|
||
#include "../include/sane/sanei_backend.h"
|
||
|
||
#include "../include/sane/sanei_config.h"
|
||
#define MUSTEK_PP_CONFIG_FILE "mustek_pp.conf"
|
||
|
||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||
|
||
/* #define if you want to patch for ASIC 1505 */
|
||
/* #undef PATCH_MUSTEK_PP_1505 */
|
||
|
||
/* #define if you want authorization support */
|
||
/* please note:
|
||
* to use user authorization, you need to modify
|
||
* a) SANED: the protocoll doesn't realy support auth
|
||
* b) NET: ...nor does the backend
|
||
* c) your frontend: at least (x)scanimage doesn't support it
|
||
* d) the makefiles: libcrypt is needed for crypt()
|
||
*
|
||
* -> so, don't do it...
|
||
*
|
||
* the format of the file .auth is
|
||
* ressource:user:password
|
||
* ressource:user:password
|
||
* ...
|
||
*
|
||
* where password is encoded using crypt()
|
||
*
|
||
* please note, that the password is passed to the backend in plain text
|
||
*
|
||
*/
|
||
/* #undef HAVE_AUTHORIZATION */
|
||
|
||
/* #define for invert option
|
||
* inversion doesn't really work */
|
||
/* #undef HAVE_INVERSION */
|
||
|
||
/* TODO:
|
||
* - perhaps option bw should be set at runtime (i.e. SANE_OPT_TRESHOLD)
|
||
* - remove line ending handling code
|
||
* - test with 1015/ CCD 04&05 scanners
|
||
* - add 1505 code
|
||
* - sane_read should operate on a fd
|
||
* - there is an transparency adapter -> support it
|
||
* - make it possible to turn lamp off during scan
|
||
* - add API docu (what's this?)
|
||
* - make the user authentification work
|
||
* - make use of ppdev
|
||
*
|
||
* The primary goal at the moment is to support ASIC 1015 - CCD 01
|
||
*/
|
||
|
||
/* DEBUG
|
||
* for debug output, set SANE_DEBUG_MUSTEK_PP to
|
||
* 0 for nothing
|
||
* 1 for errors
|
||
* 2 for warnings
|
||
* 3 for additional information
|
||
* 4 for debug information
|
||
* 5 for code flow protocoll (there isn't any)
|
||
* 6 old debug info
|
||
* 129 if you want to know which parameters are unused
|
||
*/
|
||
|
||
/* history:
|
||
* 1.0.0-devel SANE backend structure taken from mustek backend
|
||
* 1.0.1-devel hardware functions taken from various sources
|
||
* 1.0.2-devel ld correction works now for ASIC 1015
|
||
* 1.0.3-alpha code tested for ASIC 1015 CCD-Type 0
|
||
* 1.0.4-devel added lots of options
|
||
* 1.0.5-devel removed AUTO options, added option niceload & auth
|
||
* fixed bug in set_ccd_channel_1013
|
||
* 1.0.6-alpha fixed bug in sane_cancel, changed return_home
|
||
* fixed bug in return_home_1013, added option wait-lamp
|
||
* added motor control codes for ASIC 1015 CCD 01
|
||
* fixed bug in config_ccd_1013 & config_ccd_1015
|
||
* added resolution code to attach & sane_get_parameters
|
||
* 1.0.7-devel added functions common the both 101x chipsets
|
||
* added option bw, fixed bug in sane_open
|
||
* fixed bug in sane_exit
|
||
* 1.0.8-devel added some code to config_ccd_1015 & set_dpi_value
|
||
* replaced fgets by sanei_config_read
|
||
* replaced #include <sane/...> by #include "sane/..."
|
||
* added option use600
|
||
* 1.0.9-devel added tons off 600 dpi code: kind of works for
|
||
* ASIC 1015 CCD 01 scanners (grayscale)
|
||
* option preview defaults to color mode
|
||
* replaced #include "sane/..." by
|
||
* #include "../include/sane/..."
|
||
*/
|
||
|
||
/* if you change the source, please set MUSTEK_PP_STATE to "devel". Do *not*
|
||
* change the MUSTEK_PP_BUILD. */
|
||
#define MUSTEK_PP_BUILD 9
|
||
#define MUSTEK_PP_STATE "devel"
|
||
|
||
static int num_devices = 0;
|
||
|
||
static Mustek_PP_Descriptor *devlist = NULL;
|
||
static SANE_Device **devarray = NULL;
|
||
|
||
static Mustek_PP_Device *first_dev = NULL;
|
||
|
||
static int strip_height = 0;
|
||
static unsigned int wait_bank = 700;
|
||
|
||
/* 1 Meg scan buffer */
|
||
static long int buf_size = 1024 * 1024;
|
||
|
||
static int niceload = 0;
|
||
|
||
static int wait_lamp = 5;
|
||
|
||
static int bw = 127;
|
||
|
||
#ifdef HAVE_AUTHORIZATION
|
||
static SANE_Auth_Callback auth_callback;
|
||
#endif
|
||
|
||
/* use600 test vars */
|
||
/* static char motor_command=0x43; */
|
||
/* static int first_time=1; */
|
||
/* static char unk1= 0xAA; */
|
||
/* static char expose_time = 0x64; */
|
||
/* static char volt[3]; */
|
||
/*static int do_calib=0; */
|
||
static void config_ccd_101x (Mustek_PP_Device * dev);
|
||
static void config_ccd (Mustek_PP_Device * dev);
|
||
static void lamp (Mustek_PP_Device * dev, int lamp_on);
|
||
/* end of test vars */
|
||
|
||
static const SANE_String_Const mode_list[] = {
|
||
"Lineart", "Gray", "Color", 0
|
||
};
|
||
|
||
static const SANE_Range u8_range = {
|
||
0, /* minimum */
|
||
255, /* maximum */
|
||
0 /* quantization */
|
||
};
|
||
|
||
|
||
#define MUSTEK_PP_CHANNEL_RED 0
|
||
#define MUSTEK_PP_CHANNEL_GREEN 1
|
||
#define MUSTEK_PP_CHANNEL_BLUE 2
|
||
#define MUSTEK_PP_CHANNEL_GRAY 1
|
||
|
||
#define MUSTEK_PP_STATE_SCANNING 2
|
||
#define MUSTEK_PP_STATE_CANCELLED 1
|
||
#define MUSTEK_PP_STATE_IDLE 0
|
||
|
||
#define MUSTEK_PP_MODE_LINEART 0
|
||
#define MUSTEK_PP_MODE_GRAYSCALE 1
|
||
#define MUSTEK_PP_MODE_COLOR 2
|
||
|
||
#define MM_PER_INCH 25.4
|
||
#define MM_TO_PIXEL(mm, res) (SANE_UNFIX(mm) * (float )res / MM_PER_INCH)
|
||
#define PIXEL_TO_MM(px, res) (SANE_FIX((float )(px * MM_PER_INCH / (res / 10)) / 10.0))
|
||
|
||
/* scan area is mixture of 8.5" x 11" (letter) and 8.2" x 11.6" (a4) */
|
||
/* actually it is 8.7" x 11.6" ;-) */
|
||
#define MUSTEK_PP_101x_MAX_H_PIXEL 2600
|
||
#define MUSTEK_PP_101x_MAX_V_PIXEL 3500
|
||
|
||
#define MUSTEK_PP_DEFAULT_PORT 0x378
|
||
|
||
|
||
#define MUSTEK_PP_ASIC_1013 0xA8
|
||
#define MUSTEK_PP_ASIC_1015 0xA5
|
||
#define MUSTEK_PP_ASIC_1505 0xA2
|
||
|
||
|
||
/*
|
||
* Here starts the driver code for the different chipsets
|
||
*
|
||
* The 1013 & 1015 chipsets share large portions of the code. This
|
||
* shared functions end with _101x.
|
||
*/
|
||
|
||
static const u_char chan_codes_1013[] = { 0x82, 0x42, 0xC2 };
|
||
static const u_char chan_codes_1015[] = { 0x80, 0x40, 0xC0 };
|
||
static const u_char fullstep[] = { 0x09, 0x0C, 0x06, 0x03 };
|
||
static const u_char halfstep[] = { 0x02, 0x03, 0x01, 0x09,
|
||
0x08, 0x0C, 0x04, 0x06
|
||
};
|
||
static const u_char voltages[4][3] = { {0x5C, 0x5A, 0x63},
|
||
{0xE6, 0xB4, 0xBE},
|
||
{0xB4, 0xB4, 0xB4},
|
||
{0x64, 0x50, 0x64}
|
||
};
|
||
|
||
/* Forward declarations of 1013/1015 functions */
|
||
static void set_ccd_channel_1013 (Mustek_PP_Device * dev, int channel);
|
||
static void motor_backward_1013 (Mustek_PP_Device * dev);
|
||
static void return_home_1013 (Mustek_PP_Device * dev, SANE_Bool nowait);
|
||
static void motor_forward_1013 (Mustek_PP_Device * dev);
|
||
static void config_ccd_1013 (Mustek_PP_Device * dev);
|
||
|
||
static void set_ccd_channel_1015 (Mustek_PP_Device * dev, int channel);
|
||
/* static void motor_backward_1015 (Mustek_PP_Device * dev); */
|
||
static void return_home_1015 (Mustek_PP_Device * dev, SANE_Bool nowait);
|
||
static void motor_forward_1015 (Mustek_PP_Device * dev);
|
||
static void config_ccd_1015 (Mustek_PP_Device * dev);
|
||
|
||
|
||
/* These functions are common to all 1013/1015 chipsets */
|
||
|
||
/*
|
||
static void
|
||
set_led (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6,
|
||
(dev->motor_step % 5 == 0 ? 0x03 : 0x13));
|
||
|
||
}*/
|
||
|
||
#define set_led(dev) sanei_pa4s2_writebyte (dev->fd, 6, \
|
||
(dev->motor_step % 5 == 0 ? 0x03 : 0x13))
|
||
|
||
/*
|
||
static void
|
||
set_sti (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 3, 0);
|
||
dev->bank_count++;
|
||
dev->bank_count &= 7;
|
||
|
||
}*/
|
||
|
||
#define set_sti(dev) do { \
|
||
if (dev->desc->use600 == SANE_TRUE) \
|
||
sanei_pa4s2_writebyte(dev->fd, 3, 0xFF); \
|
||
else \
|
||
sanei_pa4s2_writebyte (dev->fd, 3, 0); \
|
||
dev->bank_count++; \
|
||
dev->bank_count &= 7; \
|
||
} while (0)
|
||
/*
|
||
static void
|
||
get_bank_count (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
u_char val;
|
||
|
||
sanei_pa4s2_readbegin (dev->fd, 3);
|
||
sanei_pa4s2_readbyte (dev->fd, &val);
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
dev->bank_count = (val & 0x07);
|
||
|
||
}*/
|
||
#define get_bank_count(dev) do { \
|
||
sanei_pa4s2_readbegin (dev->fd, 3); \
|
||
sanei_pa4s2_readbyte \
|
||
(dev->fd, \
|
||
(u_char *)&dev->bank_count); \
|
||
sanei_pa4s2_readend (dev->fd); \
|
||
dev->bank_count &= 0x07; \
|
||
} while (0)
|
||
|
||
/*
|
||
static void
|
||
reset_bank_count (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 7);
|
||
|
||
}*/
|
||
#define reset_bank_count(dev) sanei_pa4s2_writebyte (dev->fd, 6, 7)
|
||
|
||
|
||
static void
|
||
wait_bank_change (Mustek_PP_Device * dev, int bankcount)
|
||
{
|
||
struct timeval start, end;
|
||
unsigned long diff;
|
||
int firsttime = 1;
|
||
|
||
if (dev->desc->use600)
|
||
{
|
||
|
||
if (niceload)
|
||
usleep (2);
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
gettimeofday (&start, NULL);
|
||
|
||
do
|
||
{
|
||
if (niceload)
|
||
{
|
||
if (firsttime)
|
||
firsttime = 0;
|
||
else
|
||
usleep (10); /* for a little nicer load */
|
||
}
|
||
get_bank_count (dev);
|
||
|
||
gettimeofday (&end, NULL);
|
||
diff = (end.tv_sec * 1000 + end.tv_usec / 1000) -
|
||
(start.tv_sec * 1000 + start.tv_usec / 1000);
|
||
|
||
}
|
||
while ((dev->bank_count != bankcount) && (diff < dev->desc->wait_bank));
|
||
|
||
}
|
||
|
||
static void
|
||
set_dpi_value (Mustek_PP_Device * dev)
|
||
{
|
||
u_char val = 0;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x80);
|
||
|
||
switch (dev->CCD.hwres * (600 / dev->desc->max_res))
|
||
{
|
||
case 100:
|
||
val = 0x08;
|
||
break;
|
||
case 200:
|
||
val = 0x00;
|
||
break;
|
||
case 300:
|
||
val = 0x50;
|
||
break;
|
||
case 400:
|
||
val = 0x10;
|
||
break;
|
||
case 600:
|
||
val = 0x20;
|
||
break;
|
||
/*
|
||
case 100: val=0x00; break;
|
||
case 200: val=0x10; break;
|
||
case 300: val=0x20; break; */
|
||
}
|
||
|
||
|
||
if (dev->ccd_type == 1)
|
||
val |= 0x01;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 5, val);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
DBG (4, "set_dpi_value: value 0x%02x\n", val);
|
||
|
||
}
|
||
|
||
static void
|
||
set_line_adjust (Mustek_PP_Device * dev)
|
||
{
|
||
int adjustline;
|
||
|
||
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
{
|
||
adjustline =
|
||
(dev->BottomX - dev->TopX) * dev->CCD.hwres / dev->desc->max_res;
|
||
dev->CCD.adjustskip =
|
||
dev->CCD.adjustskip * dev->CCD.hwres / dev->desc->max_res;
|
||
}
|
||
else
|
||
{
|
||
|
||
adjustline = dev->params.pixels_per_line;
|
||
|
||
adjustline = adjustline * dev->CCD.hwres / dev->CCD.res;
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
adjustline <<= 3;
|
||
|
||
/* adjustline = adjustline * dev->CCD.hwres / dev->CCD.res; */
|
||
adjustline += 2;
|
||
|
||
dev->CCD.adjustskip =
|
||
dev->CCD.adjustskip * dev->CCD.hwres / dev->CCD.res;
|
||
|
||
DBG (4, "set_line_adjust: value = %u (0x%04x)\n", adjustline,
|
||
adjustline);
|
||
|
||
}
|
||
|
||
DBG (4, "set_line_adjust: ppl %u (%u), adjust %u, skip %u\n",
|
||
dev->params.pixels_per_line, (dev->BottomX - dev->TopX), adjustline,
|
||
dev->CCD.adjustskip);
|
||
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x11);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, (adjustline + dev->CCD.adjustskip) >> 8);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x21);
|
||
sanei_pa4s2_writebyte (dev->fd, 5,
|
||
(adjustline + dev->CCD.adjustskip) & 0xFF);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
|
||
|
||
}
|
||
|
||
static void
|
||
set_lamp (Mustek_PP_Device * dev, int lamp_on)
|
||
{
|
||
|
||
int ctr;
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0xC3);
|
||
|
||
for (ctr = 0; ctr < 3; ctr++)
|
||
{
|
||
sanei_pa4s2_writebyte (dev->fd, 6, (lamp_on ? 0x47 : 0x57));
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
|
||
}
|
||
|
||
dev->motor_step = lamp_on;
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
set_led (dev);
|
||
|
||
}
|
||
|
||
static void
|
||
send_voltages (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
int voltage, sel = 8, ctr;
|
||
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 0:
|
||
voltage = 0;
|
||
break;
|
||
case 1:
|
||
voltage = 1;
|
||
/* if (dev->asic_id == MUSTEK_PP_ASIC_1015)
|
||
voltage = 3; */
|
||
break;
|
||
default:
|
||
voltage = 2;
|
||
break;
|
||
}
|
||
|
||
for (ctr = 0; ctr < 3; ctr++)
|
||
{
|
||
|
||
sel <<= 1;
|
||
sanei_pa4s2_writebyte (dev->fd, 6, sel);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, voltages[voltage][ctr]);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
}
|
||
|
||
static int
|
||
compar (const void *a, const void *b)
|
||
{
|
||
return (signed int) (*(const SANE_Byte *) a) -
|
||
(signed int) (*(const SANE_Byte *) b);
|
||
}
|
||
|
||
static void
|
||
set_ccd_channel_101x (Mustek_PP_Device * dev, int channel)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
set_ccd_channel_1013 (dev, channel);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
set_ccd_channel_1015 (dev, channel);
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
motor_forward_101x (Mustek_PP_Device * dev)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
motor_forward_1013 (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
motor_forward_1015 (dev);
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
motor_backward_101x (Mustek_PP_Device * dev)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
motor_backward_1013 (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
/* motor_backward_1015 (dev); */
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
move_motor_101x (Mustek_PP_Device * dev, int forward)
|
||
{
|
||
if (forward == SANE_TRUE)
|
||
motor_forward_101x (dev);
|
||
else
|
||
motor_backward_101x (dev);
|
||
|
||
wait_bank_change (dev, dev->bank_count);
|
||
reset_bank_count (dev);
|
||
}
|
||
|
||
|
||
static void
|
||
config_ccd_101x (Mustek_PP_Device * dev)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
config_ccd_1013 (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
config_ccd_1015 (dev);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
static void
|
||
read_line_101x (Mustek_PP_Device * dev, SANE_Byte * buf, SANE_Int pixel,
|
||
SANE_Int RefBlack, SANE_Byte * calib, SANE_Int * gamma)
|
||
{
|
||
|
||
SANE_Byte *cal = calib;
|
||
u_char color;
|
||
int ctr, skips = dev->CCD.adjustskip + 1, cval;
|
||
|
||
if (pixel <= 0)
|
||
return;
|
||
|
||
sanei_pa4s2_readbegin (dev->fd, 1);
|
||
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
|
||
|
||
if (dev->CCD.hwres == dev->CCD.res)
|
||
{
|
||
|
||
while (skips--)
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
for (ctr = 0; ctr < pixel; ctr++)
|
||
sanei_pa4s2_readbyte (dev->fd, &buf[ctr]);
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
int pos = 0, bpos = 0;
|
||
|
||
while (skips--)
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
ctr = 0;
|
||
|
||
do
|
||
{
|
||
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
if (ctr < (pos >> SANE_FIXED_SCALE_SHIFT))
|
||
{
|
||
ctr++;
|
||
continue;
|
||
}
|
||
|
||
ctr++;
|
||
pos += dev->CCD.res_step;
|
||
|
||
|
||
buf[bpos++] = color;
|
||
|
||
}
|
||
while (bpos < pixel);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
if (dev->CCD.hwres == dev->CCD.res)
|
||
{
|
||
|
||
while (skips--)
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
for (ctr = 0; ctr < pixel; ctr++)
|
||
{
|
||
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
cval = color;
|
||
|
||
if (cval < RefBlack)
|
||
cval = 0;
|
||
else
|
||
cval -= RefBlack;
|
||
|
||
if (cal)
|
||
{
|
||
if (cval >= cal[ctr])
|
||
cval = 0xFF;
|
||
else
|
||
{
|
||
cval <<= 8;
|
||
cval /= (int) cal[ctr];
|
||
}
|
||
}
|
||
|
||
if (gamma)
|
||
cval = gamma[cval];
|
||
|
||
buf[ctr] = cval;
|
||
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
int pos = 0, bpos = 0;
|
||
|
||
while (skips--)
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
ctr = 0;
|
||
|
||
do
|
||
{
|
||
|
||
sanei_pa4s2_readbyte (dev->fd, &color);
|
||
|
||
cval = color;
|
||
|
||
if (ctr < (pos >> SANE_FIXED_SCALE_SHIFT))
|
||
{
|
||
ctr++;
|
||
continue;
|
||
}
|
||
|
||
ctr++;
|
||
pos += dev->CCD.res_step;
|
||
|
||
|
||
if (cval < RefBlack)
|
||
cval = 0;
|
||
else
|
||
cval -= RefBlack;
|
||
|
||
if (cal)
|
||
{
|
||
if (cval >= cal[bpos])
|
||
cval = 0xFF;
|
||
else
|
||
{
|
||
cval <<= 8;
|
||
cval /= (int) cal[bpos];
|
||
}
|
||
}
|
||
|
||
if (gamma)
|
||
cval = gamma[cval];
|
||
|
||
buf[bpos++] = cval;
|
||
|
||
}
|
||
while (bpos < pixel);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
}
|
||
|
||
static void
|
||
read_average_line_101x (Mustek_PP_Device * dev, SANE_Byte * buf, int pixel,
|
||
int RefBlack)
|
||
{
|
||
|
||
SANE_Byte lbuf[4][MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
int ctr, sum;
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
wait_bank_change (dev, dev->bank_count);
|
||
read_line_101x (dev, lbuf[ctr], pixel, RefBlack, NULL, NULL);
|
||
reset_bank_count (dev);
|
||
if (ctr < 3)
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
for (ctr = 0; ctr < pixel; ctr++)
|
||
{
|
||
|
||
sum = lbuf[0][ctr] + lbuf[1][ctr] + lbuf[2][ctr] + lbuf[3][ctr];
|
||
|
||
buf[ctr] = (sum / 4);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
find_black_side_edge_101x (Mustek_PP_Device * dev)
|
||
{
|
||
SANE_Byte buf[MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
SANE_Byte blackposition[5];
|
||
int pos = 0, ctr, blackpos;
|
||
|
||
for (ctr = 0; ctr < 20; ctr++)
|
||
{
|
||
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
read_line_101x (dev, buf, dev->desc->max_h_size, 0, NULL, NULL);
|
||
reset_bank_count (dev);
|
||
|
||
dev->ref_black = dev->ref_red = dev->ref_green = dev->ref_blue = buf[0];
|
||
|
||
blackpos = dev->desc->max_h_size / 4;
|
||
|
||
while ((abs (buf[blackpos] - buf[0]) >= 15) && (blackpos > 0))
|
||
blackpos--;
|
||
|
||
if (blackpos > 1)
|
||
blackposition[pos++] = blackpos;
|
||
|
||
if (pos == 5)
|
||
break;
|
||
|
||
}
|
||
|
||
blackpos = 0;
|
||
|
||
for (ctr = 0; ctr < pos; ctr++)
|
||
if (blackposition[ctr] > blackpos)
|
||
blackpos = blackposition[ctr];
|
||
|
||
if (blackpos < 0x66)
|
||
blackpos = 0x6A;
|
||
|
||
dev->blackpos = blackpos;
|
||
dev->Saved_CCD.skipcount = (blackpos + 12) & 0xFF;
|
||
|
||
}
|
||
|
||
static void
|
||
min_color_levels_101x (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
SANE_Byte buf[MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
int ctr, sum = 0;
|
||
|
||
for (ctr = 0; ctr < 8; ctr++)
|
||
{
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_RED);
|
||
set_sti (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
read_line_101x (dev, buf, dev->desc->max_h_size, 0, NULL, NULL);
|
||
|
||
reset_bank_count (dev);
|
||
|
||
sum += buf[3];
|
||
|
||
}
|
||
|
||
dev->ref_red = sum / 8;
|
||
|
||
sum = 0;
|
||
|
||
for (ctr = 0; ctr < 8; ctr++)
|
||
{
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_GREEN);
|
||
set_sti (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
read_line_101x (dev, buf, dev->desc->max_h_size, 0, NULL, NULL);
|
||
|
||
reset_bank_count (dev);
|
||
|
||
sum += buf[3];
|
||
|
||
}
|
||
|
||
dev->ref_green = sum / 8;
|
||
|
||
sum = 0;
|
||
|
||
for (ctr = 0; ctr < 8; ctr++)
|
||
{
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_BLUE);
|
||
set_sti (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
read_line_101x (dev, buf, dev->desc->max_h_size, 0, NULL, NULL);
|
||
|
||
reset_bank_count (dev);
|
||
|
||
sum += buf[3];
|
||
|
||
}
|
||
|
||
dev->ref_blue = sum / 8;
|
||
|
||
}
|
||
|
||
|
||
static void
|
||
max_color_levels_101x (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
int ctr, line, sum;
|
||
SANE_Byte rbuf[32][MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
SANE_Byte gbuf[32][MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
SANE_Byte bbuf[32][MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
|
||
SANE_Byte maxbuf[32];
|
||
|
||
for (ctr = 0; ctr < 32; ctr++)
|
||
{
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
{
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_RED);
|
||
motor_forward_101x (dev);
|
||
|
||
read_average_line_101x (dev, rbuf[ctr], dev->params.pixels_per_line,
|
||
dev->ref_red);
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_GREEN);
|
||
set_sti (dev);
|
||
|
||
read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line,
|
||
dev->ref_green);
|
||
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_BLUE);
|
||
set_sti (dev);
|
||
|
||
read_average_line_101x (dev, bbuf[ctr], dev->params.pixels_per_line,
|
||
dev->ref_blue);
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GRAY;
|
||
|
||
motor_forward_101x (dev);
|
||
|
||
read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line,
|
||
dev->ref_black);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
for (line = 0; line < 32; line++)
|
||
maxbuf[line] = gbuf[line][ctr];
|
||
|
||
qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
|
||
|
||
sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
|
||
|
||
dev->calib_g[ctr] = sum / 4;
|
||
|
||
}
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
{
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
for (line = 0; line < 32; line++)
|
||
maxbuf[line] = rbuf[line][ctr];
|
||
|
||
qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
|
||
|
||
sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
|
||
|
||
dev->calib_r[ctr] = sum / 4;
|
||
|
||
}
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
for (line = 0; line < 32; line++)
|
||
maxbuf[line] = bbuf[line][ctr];
|
||
|
||
qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
|
||
|
||
sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
|
||
|
||
dev->calib_b[ctr] = sum / 4;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
find_black_top_edge_101x (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
int lines = 0, ctr, pos;
|
||
SANE_Byte buf[MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GRAY;
|
||
|
||
do
|
||
{
|
||
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
read_line_101x
|
||
(dev, buf, dev->desc->max_h_size, dev->ref_black, NULL, NULL);
|
||
|
||
reset_bank_count (dev);
|
||
|
||
pos = 0;
|
||
|
||
for (ctr = dev->blackpos; ctr > dev->blackpos - 10; ctr--)
|
||
if (buf[ctr] <= 15)
|
||
pos++;
|
||
|
||
}
|
||
while ((pos >= 8) && (lines++ < 67));
|
||
|
||
}
|
||
|
||
static void
|
||
calibrate_device_101x (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
int saved_ppl = dev->params.pixels_per_line, ctr;
|
||
|
||
DBG (1, "calibrate_device_101x: use600 = %s\n",
|
||
(dev->desc->use600 ? "yes" : "no"));
|
||
|
||
if (dev->desc->use600)
|
||
{
|
||
|
||
int i, j;
|
||
/* FILE *fptr; */
|
||
SANE_Byte buf[MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
|
||
dev->Saved_CCD = dev->CCD;
|
||
dev->CCD.mode = MUSTEK_PP_MODE_COLOR;
|
||
dev->CCD.hwres = dev->CCD.res = 600;
|
||
dev->unknown_value = 0xAA;
|
||
dev->expose_time = 0x64;
|
||
dev->CCD.skipcount = dev->CCD.skipimagebytes = 0;
|
||
dev->params.pixels_per_line = 10;
|
||
|
||
config_ccd (dev);
|
||
|
||
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x67);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x17);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x07);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x12);
|
||
|
||
for (i = 0; i < 8; i++)
|
||
for (j = 0; j < 255; j++)
|
||
sanei_pa4s2_writebyte (dev->fd, 5, j);
|
||
|
||
for (j = 0; j < 8; j++)
|
||
sanei_pa4s2_writebyte (dev->fd, 5, j);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x02);
|
||
|
||
/* fptr = fopen("/tmp/calib.1", "w"); */
|
||
|
||
|
||
for (ctr = 0; ctr < 100; ctr++)
|
||
{
|
||
|
||
reset_bank_count (dev);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
|
||
read_line_101x (dev, buf, 2048, 0, NULL, NULL);
|
||
|
||
/* fwrite(buf,2048,1,fptr); */
|
||
|
||
}
|
||
|
||
/* fclose (fptr); */
|
||
|
||
dev->CCD.hwres = dev->CCD.res = 300;
|
||
dev->unknown_value = 0xFE;
|
||
dev->expose_time = 0xFF;
|
||
dev->params.pixels_per_line = 150;
|
||
dev->voltages[0] = 0x6b;
|
||
dev->voltages[1] = 0x4f;
|
||
dev->voltages[2] = 0x65;
|
||
|
||
dev->send_voltages = 1;
|
||
|
||
config_ccd (dev);
|
||
get_bank_count (dev);
|
||
|
||
dev->motor_ctrl = 0x43;
|
||
for (ctr = 0; ctr < 3; ctr++)
|
||
move_motor_101x (dev, SANE_TRUE);
|
||
|
||
/* fptr = fopen("/tmp/calib.2","w"); */
|
||
|
||
read_line_101x (dev, buf, 150, 0, NULL, NULL);
|
||
|
||
/* fwrite(buf,150,1,fptr);
|
||
fclose(fptr); */
|
||
|
||
|
||
move_motor_101x (dev, SANE_TRUE);
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
|
||
dev->voltages[0] = 0x32;
|
||
dev->voltages[1] = 0x32;
|
||
dev->voltages[2] = 0x32;
|
||
dev->params.pixels_per_line = saved_ppl;
|
||
|
||
config_ccd (dev);
|
||
|
||
/*
|
||
if ((dev->CCD.hwres >= 300) && (dev->CCD.mode != MUSTEK_PP_MODE_COLOR))
|
||
motor_command = 0x63; */
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
}
|
||
|
||
dev->CCD.adjustskip = 3;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x7f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x7f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x7f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
/* fptr = fopen("/tmp/calib.3","w"); */
|
||
|
||
j = 0;
|
||
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
|
||
|
||
|
||
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x3f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x3f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x3f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x1f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x1f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x1f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x2f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x2f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x2f);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
/* fwrite(buf,saved_ppl, 1,fptr);*/
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
|
||
}
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
for (ctr = 0; ctr < 43; ctr++)
|
||
{
|
||
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
motor_forward_1015 (dev);
|
||
|
||
}
|
||
|
||
lamp (dev, SANE_FALSE);
|
||
|
||
for (ctr = 0; ctr < 13; ctr++)
|
||
{
|
||
|
||
read_line_101x (dev, buf, saved_ppl, 0, NULL, NULL);
|
||
|
||
i = saved_ppl;
|
||
while ((abs (buf[i] - buf[0]) >= 15) && (i > 0))
|
||
i--;
|
||
|
||
if (i > j)
|
||
j = i;
|
||
|
||
|
||
/*
|
||
|
||
for (i=0 ; i<saved_ppl ; i++)
|
||
if (abs(buf[i] - buf[0]) >= 15) {
|
||
|
||
|
||
if (i > j)
|
||
j=i;
|
||
|
||
break;
|
||
|
||
|
||
} */
|
||
/* fwrite(buf,saved_ppl, 1,fptr); */
|
||
reset_bank_count (dev);
|
||
get_bank_count (dev);
|
||
set_sti (dev);
|
||
}
|
||
lamp (dev, SANE_TRUE);
|
||
|
||
/* fclose(fptr); */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x37);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
|
||
|
||
dev->blackpos = 0x6a;
|
||
dev->Saved_CCD.skipcount = 0x6A; /*(120 + 12) & 0xFF; */
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
|
||
dev->send_voltages = 0;
|
||
config_ccd (dev);
|
||
|
||
for (ctr = 0; ctr < 3; ctr++)
|
||
{
|
||
|
||
motor_forward_1015 (dev);
|
||
|
||
|
||
}
|
||
|
||
for (ctr = 0; ctr < 100; ctr++)
|
||
{
|
||
read_line_101x (dev, buf, 150, 0, NULL, NULL);
|
||
motor_forward_1015 (dev);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
|
||
dev->send_voltages = 0;
|
||
config_ccd (dev);
|
||
|
||
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
dev->Saved_CCD = dev->CCD;
|
||
dev->params.pixels_per_line = dev->desc->max_h_size;
|
||
dev->CCD.hwres = dev->CCD.res = dev->desc->max_res;
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
dev->CCD.skipcount = dev->CCD.skipimagebytes = 0;
|
||
dev->CCD.invert = SANE_FALSE;
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GRAY;
|
||
|
||
config_ccd_101x (dev);
|
||
get_bank_count (dev);
|
||
|
||
find_black_side_edge_101x (dev);
|
||
|
||
for (ctr = 0; ctr < 4; ctr++)
|
||
move_motor_101x (dev, SANE_TRUE);
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
|
||
dev->CCD.hwres = dev->CCD.res = dev->desc->max_res;
|
||
dev->CCD.skipcount = dev->CCD.skipimagebytes = 0;
|
||
dev->CCD.invert = SANE_FALSE;
|
||
|
||
config_ccd_101x (dev);
|
||
get_bank_count (dev);
|
||
|
||
if ((dev->CCD.mode == MUSTEK_PP_MODE_COLOR) && (dev->ccd_type != 0))
|
||
min_color_levels_101x (dev);
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
dev->params.pixels_per_line = saved_ppl;
|
||
dev->CCD.invert = SANE_FALSE;
|
||
|
||
config_ccd_101x (dev);
|
||
get_bank_count (dev);
|
||
|
||
max_color_levels_101x (dev);
|
||
|
||
dev->params.pixels_per_line = dev->desc->max_h_size;
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
dev->CCD.hwres = dev->CCD.res = dev->desc->max_res;
|
||
dev->CCD.skipcount = dev->CCD.skipimagebytes = 0;
|
||
dev->CCD.invert = SANE_FALSE;
|
||
|
||
config_ccd_101x (dev);
|
||
get_bank_count (dev);
|
||
|
||
find_black_top_edge_101x (dev);
|
||
|
||
dev->CCD = dev->Saved_CCD;
|
||
|
||
dev->params.pixels_per_line = saved_ppl;
|
||
|
||
config_ccd_101x (dev);
|
||
get_bank_count (dev);
|
||
|
||
}
|
||
|
||
static void
|
||
get_grayscale_line_101x (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
int skips;
|
||
|
||
dev->line_diff +=
|
||
SANE_FIX ((float) dev->desc->max_res / (float) dev->CCD.res);
|
||
|
||
skips = (dev->line_diff >> SANE_FIXED_SCALE_SHIFT);
|
||
|
||
while (--skips)
|
||
{
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
reset_bank_count (dev);
|
||
}
|
||
|
||
dev->line_diff &= 0xFFFF;
|
||
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
read_line_101x (dev, buf, dev->params.pixels_per_line, dev->ref_black,
|
||
dev->calib_g,
|
||
(dev->val[OPT_CUSTOM_GAMMA].w ?
|
||
dev->gamma_table[0] : NULL));
|
||
|
||
reset_bank_count (dev);
|
||
|
||
}
|
||
|
||
static void
|
||
get_lineart_line_101x (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
int ctr;
|
||
SANE_Byte gbuf[MUSTEK_PP_101x_MAX_H_PIXEL * 2];
|
||
|
||
get_grayscale_line_101x (dev, gbuf);
|
||
|
||
memset (buf, 0xFF, dev->params.bytes_per_line);
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
buf[ctr >> 3] ^= ((gbuf[ctr] > dev->desc->bw) ? (1 << (7 - ctr % 8)) : 0);
|
||
|
||
}
|
||
|
||
static void
|
||
get_color_line_101x (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
SANE_Byte *red, *blue, *src, *dest;
|
||
int gotline = 0, ctr;
|
||
int gored, goblue, gogreen;
|
||
int step = dev->CCD.line_step;
|
||
|
||
do
|
||
{
|
||
|
||
red = dev->red[dev->redline];
|
||
blue = dev->blue[dev->blueline];
|
||
|
||
dev->ccd_line++;
|
||
|
||
if ((dev->rdiff >> SANE_FIXED_SCALE_SHIFT) == dev->ccd_line)
|
||
{
|
||
gored = 1;
|
||
dev->rdiff += step;
|
||
}
|
||
else
|
||
gored = 0;
|
||
|
||
if ((dev->bdiff >> SANE_FIXED_SCALE_SHIFT) == dev->ccd_line)
|
||
{
|
||
goblue = 1;
|
||
dev->bdiff += step;
|
||
}
|
||
else
|
||
goblue = 0;
|
||
|
||
if ((dev->gdiff >> SANE_FIXED_SCALE_SHIFT) == dev->ccd_line)
|
||
{
|
||
gogreen = 1;
|
||
dev->gdiff += step;
|
||
}
|
||
else
|
||
gogreen = 0;
|
||
|
||
if (!gored && !goblue && !gogreen)
|
||
{
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
reset_bank_count (dev);
|
||
if (dev->ccd_line >= (dev->CCD.line_step >> SANE_FIXED_SCALE_SHIFT))
|
||
dev->redline = ++dev->redline % dev->green_offs;
|
||
if (dev->ccd_line >=
|
||
dev->blue_offs + (dev->CCD.line_step >> SANE_FIXED_SCALE_SHIFT))
|
||
dev->blueline = ++dev->blueline % dev->blue_offs;
|
||
continue;
|
||
}
|
||
|
||
if (gored)
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_RED;
|
||
else if (goblue)
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_BLUE;
|
||
else
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GREEN;
|
||
|
||
motor_forward_101x (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
|
||
if (dev->ccd_line >= dev->green_offs && gogreen)
|
||
{
|
||
src = red;
|
||
dest = buf;
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
*dest = *src++;
|
||
dest += 3;
|
||
}
|
||
}
|
||
|
||
if (gored)
|
||
{
|
||
|
||
read_line_101x (dev, red, dev->params.pixels_per_line, dev->ref_red,
|
||
dev->calib_r,
|
||
(dev->val[OPT_CUSTOM_GAMMA].w ?
|
||
dev->gamma_table[1] : NULL));
|
||
|
||
reset_bank_count (dev);
|
||
|
||
}
|
||
|
||
dev->redline = ++dev->redline % dev->green_offs;
|
||
|
||
if (dev->ccd_line >= dev->green_offs && gogreen)
|
||
{
|
||
src = blue;
|
||
dest = buf + 2;
|
||
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
*dest = *src++;
|
||
dest += 3;
|
||
}
|
||
|
||
}
|
||
|
||
if (goblue)
|
||
{
|
||
if (gored)
|
||
{
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_BLUE);
|
||
set_sti (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
}
|
||
|
||
read_line_101x (dev, blue, dev->params.pixels_per_line,
|
||
dev->ref_blue, dev->calib_b,
|
||
(dev->val[OPT_CUSTOM_GAMMA].w ? dev->
|
||
gamma_table[3] : NULL));
|
||
|
||
reset_bank_count (dev);
|
||
|
||
}
|
||
|
||
if (dev->ccd_line >=
|
||
dev->blue_offs + (dev->CCD.line_step >> SANE_FIXED_SCALE_SHIFT))
|
||
dev->blueline = ++dev->blueline % dev->blue_offs;
|
||
|
||
if (gogreen)
|
||
{
|
||
|
||
if (gored || goblue)
|
||
{
|
||
set_ccd_channel_101x (dev, MUSTEK_PP_CHANNEL_GREEN);
|
||
set_sti (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
}
|
||
|
||
read_line_101x (dev, dev->green, dev->params.pixels_per_line,
|
||
dev->ref_green, dev->calib_g,
|
||
(dev->val[OPT_CUSTOM_GAMMA].w ?
|
||
dev->gamma_table[2] : NULL));
|
||
|
||
reset_bank_count (dev);
|
||
|
||
src = dev->green;
|
||
dest = buf + 1;
|
||
|
||
for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
|
||
{
|
||
*dest = *src++;
|
||
dest += 3;
|
||
}
|
||
|
||
gotline = 1;
|
||
}
|
||
|
||
}
|
||
while (!gotline);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* these functions are for the 1013 chipset */
|
||
|
||
static void
|
||
set_ccd_channel_1013 (Mustek_PP_Device * dev, int channel)
|
||
{
|
||
dev->CCD.channel = channel;
|
||
sanei_pa4s2_writebyte (dev->fd, 6, chan_codes_1013[channel]);
|
||
}
|
||
|
||
static void
|
||
motor_backward_1013 (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
dev->motor_step++;
|
||
set_led (dev);
|
||
|
||
if (dev->motor_phase > 3)
|
||
dev->motor_phase = 3;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x62);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, fullstep[dev->motor_phase]);
|
||
|
||
dev->motor_phase = (dev->motor_phase == 0 ? 3 : dev->motor_phase - 1);
|
||
|
||
set_ccd_channel_1013 (dev, dev->CCD.channel);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
static void
|
||
return_home_1013 (Mustek_PP_Device * dev, SANE_Bool nowait)
|
||
{
|
||
u_char ishome;
|
||
int ctr, saved_niceload;
|
||
|
||
/* 1013 can't return home all alone, nowait ignored */
|
||
|
||
saved_niceload = niceload;
|
||
|
||
niceload = 0;
|
||
|
||
for (ctr = 0; ctr < 4500; ctr++)
|
||
{
|
||
|
||
/* check_is_home_1013 */
|
||
sanei_pa4s2_readbegin (dev->fd, 2);
|
||
sanei_pa4s2_readbyte (dev->fd, &ishome);
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
/* yes, it should be is_not_home */
|
||
if ((ishome & 1) == 0)
|
||
break;
|
||
|
||
motor_backward_1013 (dev);
|
||
wait_bank_change (dev, dev->bank_count);
|
||
reset_bank_count (dev);
|
||
|
||
}
|
||
|
||
niceload = saved_niceload;
|
||
|
||
}
|
||
|
||
static void
|
||
motor_forward_1013 (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
int ctr;
|
||
|
||
dev->motor_step++;
|
||
set_led (dev);
|
||
|
||
for (ctr = 0; ctr < 2; ctr++)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x62);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, halfstep[dev->motor_phase]);
|
||
|
||
dev->motor_phase = (dev->motor_phase == 7 ? 0 : dev->motor_phase + 1);
|
||
|
||
}
|
||
|
||
set_ccd_channel_1013 (dev, dev->CCD.channel);
|
||
set_sti (dev);
|
||
}
|
||
|
||
|
||
|
||
static void
|
||
config_ccd_1013 (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
if (dev->CCD.res != 0)
|
||
dev->CCD.res_step =
|
||
SANE_FIX ((float) dev->CCD.hwres / (float) dev->CCD.res);
|
||
|
||
set_dpi_value (dev);
|
||
|
||
/* set_start_channel_1013 (dev); */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x05);
|
||
|
||
switch (dev->CCD.mode)
|
||
{
|
||
case MUSTEK_PP_MODE_LINEART:
|
||
case MUSTEK_PP_MODE_GRAYSCALE:
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GRAY;
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_COLOR:
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_RED;
|
||
break;
|
||
|
||
}
|
||
|
||
set_ccd_channel_1013 (dev, dev->CCD.channel);
|
||
|
||
/* set_invert_1013 (dev); */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6,
|
||
(dev->CCD.invert == SANE_TRUE ? 0x04 : 0x14));
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x37);
|
||
reset_bank_count (dev);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x67);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x17);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
|
||
|
||
/* set_initial_skip_1013 (dev); */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x41);
|
||
|
||
dev->CCD.adjustskip = dev->CCD.skipcount + dev->CCD.skipimagebytes;
|
||
|
||
DBG (4, "config_ccd_1013: adjustskip %u\n", dev->CCD.adjustskip);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 5, dev->CCD.adjustskip / 16 + 2);
|
||
|
||
dev->CCD.adjustskip %= 16;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x81);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x70);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
|
||
|
||
|
||
set_line_adjust (dev);
|
||
|
||
get_bank_count (dev);
|
||
|
||
}
|
||
|
||
/* these functions are for the 1015 chipset */
|
||
|
||
|
||
static void
|
||
motor_control_1015 (Mustek_PP_Device * dev, u_char control)
|
||
{
|
||
|
||
|
||
u_char val;
|
||
|
||
DBG (4, "motor_controll_1015: control code 0x%02x\n",
|
||
(unsigned int) control);
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0xF6);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x22);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, control);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x02);
|
||
|
||
do
|
||
{
|
||
|
||
sanei_pa4s2_readbegin (dev->fd, 2);
|
||
sanei_pa4s2_readbyte (dev->fd, &val);
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
}
|
||
while ((val & 0x08) != 0);
|
||
|
||
}
|
||
|
||
static void
|
||
return_home_1015 (Mustek_PP_Device * dev, SANE_Bool nowait)
|
||
{
|
||
|
||
u_char ishome, control = 0xC3;
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 1:
|
||
control = 0xD3;
|
||
break;
|
||
|
||
default:
|
||
control = 0xC3;
|
||
break;
|
||
}
|
||
}
|
||
|
||
motor_control_1015 (dev, control);
|
||
|
||
do
|
||
{
|
||
|
||
/* check_is_home_1015 */
|
||
sanei_pa4s2_readbegin (dev->fd, 2);
|
||
sanei_pa4s2_readbyte (dev->fd, &ishome);
|
||
sanei_pa4s2_readend (dev->fd);
|
||
|
||
if (nowait)
|
||
break;
|
||
|
||
usleep (1000); /* much nicer load */
|
||
|
||
}
|
||
while ((ishome & 2) == 0);
|
||
|
||
}
|
||
|
||
static void
|
||
motor_forward_1015 (Mustek_PP_Device * dev)
|
||
{
|
||
u_char control = 0x1B;
|
||
|
||
dev->motor_step++;
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
set_led (dev);
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 1:
|
||
control = dev->motor_ctrl;
|
||
break;
|
||
|
||
default:
|
||
control = 0x1B;
|
||
break;
|
||
}
|
||
}
|
||
|
||
motor_control_1015 (dev, control);
|
||
/*
|
||
|
||
if ((dev->desc->use600 == SANE_TRUE) && (dev->CCD.mode != MUSTEK_PP_MODE_COLOR) && (dev->CCD.hwres < 300))
|
||
motor_control_1015 (dev, control); */
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
set_ccd_channel_1015 (dev, dev->CCD.channel);
|
||
set_sti (dev);
|
||
|
||
}
|
||
|
||
/*
|
||
static void
|
||
motor_backward_1015 (Mustek_PP_Device * dev)
|
||
{
|
||
u_char control = 0x43;
|
||
|
||
|
||
dev->motor_step++;
|
||
|
||
set_led (dev);
|
||
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 1:
|
||
control = 0x1B;
|
||
break;
|
||
|
||
default:
|
||
control = 0x43;
|
||
break;
|
||
}
|
||
|
||
motor_control_1015 (dev, control);
|
||
|
||
set_ccd_channel_1015 (dev, dev->CCD.channel);
|
||
set_sti (dev);
|
||
|
||
}
|
||
*/
|
||
|
||
|
||
static void
|
||
set_ccd_channel_1015 (Mustek_PP_Device * dev, int channel)
|
||
{
|
||
|
||
u_char chancode = chan_codes_1015[channel];
|
||
|
||
dev->CCD.channel = channel;
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
chancode |= 0x14;
|
||
}
|
||
else
|
||
{
|
||
|
||
dev->image_control &= 0x34;
|
||
chancode |= dev->image_control;
|
||
|
||
}
|
||
|
||
dev->image_control = chancode;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, chancode);
|
||
|
||
}
|
||
|
||
|
||
static void
|
||
config_ccd_1015 (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
u_char val;
|
||
|
||
if (dev->CCD.res != 0)
|
||
dev->CCD.res_step =
|
||
SANE_FIX ((float) dev->CCD.hwres / (float) dev->CCD.res);
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
|
||
if (dev->first_time)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x86);
|
||
else
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0xC6);
|
||
|
||
dev->first_time = 0;
|
||
}
|
||
|
||
set_dpi_value (dev);
|
||
|
||
dev->image_control = 4;
|
||
|
||
/* set_start_channel_1015 (dev); */
|
||
|
||
switch (dev->CCD.mode)
|
||
{
|
||
case MUSTEK_PP_MODE_LINEART:
|
||
case MUSTEK_PP_MODE_GRAYSCALE:
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_GRAY;
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_COLOR:
|
||
dev->CCD.channel = MUSTEK_PP_CHANNEL_RED;
|
||
break;
|
||
|
||
}
|
||
|
||
set_ccd_channel_1015 (dev, dev->CCD.channel);
|
||
|
||
|
||
/* set_invert_1015 (dev); */
|
||
|
||
dev->image_control &= 0xE4;
|
||
|
||
if (dev->CCD.invert == SANE_FALSE)
|
||
dev->image_control |= 0x10;
|
||
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x13);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, dev->unknown_value); /* FIXME */
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x03);
|
||
|
||
}
|
||
else
|
||
{
|
||
sanei_pa4s2_writebyte (dev->fd, 6, dev->image_control);
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x23);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0x00);
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x03);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x43);
|
||
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 1:
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
val = 0x0F;
|
||
else
|
||
val = 0x6B;
|
||
break;
|
||
case 4:
|
||
val = 0x9F;
|
||
break;
|
||
default:
|
||
val = 0x92;
|
||
break;
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 5, val);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x03);
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x45); /* or 0x05 for no 8kbank */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x37);
|
||
reset_bank_count (dev);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x67);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x17);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
|
||
|
||
/* set_initial_skip_1015 (dev); */
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x41);
|
||
|
||
dev->CCD.adjustskip = dev->CCD.skipcount + dev->CCD.skipimagebytes;
|
||
|
||
/* if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
dev->CCD.adjustskip <<= 3; */
|
||
|
||
|
||
if ((dev->desc->use600 == SANE_TRUE) && (dev->CCD.adjustskip > 32))
|
||
dev->CCD.adjustskip += 26;
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 5,
|
||
dev->CCD.adjustskip / 32 + (dev->desc->use600 ==
|
||
SANE_TRUE ? 0 : 1));
|
||
|
||
/* if (dev->desc->use600 == SANE_FALSE) */
|
||
dev->CCD.adjustskip %= 32;
|
||
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x81);
|
||
|
||
/* expose time */
|
||
switch (dev->ccd_type)
|
||
{
|
||
case 1:
|
||
|
||
if (dev->desc->use600 == SANE_TRUE)
|
||
val = dev->expose_time;
|
||
else
|
||
val = 0xA8;
|
||
break;
|
||
case 0:
|
||
val = 0x8A;
|
||
break;
|
||
default:
|
||
val = 0xA8;
|
||
break;
|
||
}
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 5, val);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
|
||
|
||
if ((dev->desc->use600 == SANE_TRUE) && (dev->send_voltages == 1))
|
||
{
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x81);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0xFD);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x13);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, 0xFE);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x03);
|
||
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x10);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, dev->voltages[0]);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x20);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, dev->voltages[1]);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x40);
|
||
sanei_pa4s2_writebyte (dev->fd, 5, dev->voltages[2]);
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
|
||
|
||
|
||
}
|
||
|
||
set_line_adjust (dev);
|
||
|
||
get_bank_count (dev);
|
||
|
||
}
|
||
|
||
/* these functions are for the 1505 chipset */
|
||
static void
|
||
return_home_1505 (Mustek_PP_Device * dev, SANE_Bool nowait)
|
||
{
|
||
}
|
||
|
||
static void
|
||
config_ccd_1505 (Mustek_PP_Device * dev)
|
||
{
|
||
}
|
||
|
||
static void
|
||
lamp_1505 (Mustek_PP_Device * dev, int lamp_on)
|
||
{
|
||
}
|
||
|
||
static void
|
||
send_voltages_1505 (Mustek_PP_Device * dev)
|
||
{
|
||
}
|
||
|
||
static void
|
||
move_motor_1505 (Mustek_PP_Device * dev, int forward)
|
||
{
|
||
}
|
||
|
||
static void
|
||
calibrate_device_1505 (Mustek_PP_Device * dev)
|
||
{
|
||
}
|
||
|
||
static void
|
||
get_grayscale_line_1505 (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
}
|
||
|
||
static void
|
||
get_lineart_line_1505 (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
}
|
||
|
||
static void
|
||
get_color_line_1505 (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
}
|
||
|
||
/* these functions are interfaces only */
|
||
static void
|
||
config_ccd (Mustek_PP_Device * dev)
|
||
{
|
||
DBG (6, "config_ccd: %d dpi, mode %d, invert %d, size %d\n",
|
||
dev->CCD.hwres, dev->CCD.mode, dev->CCD.invert,
|
||
dev->params.pixels_per_line);
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
config_ccd_1013 (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
config_ccd_1015 (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
config_ccd_1505 (dev);
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
return_home (Mustek_PP_Device * dev, SANE_Bool nowait)
|
||
{
|
||
|
||
CCD_Info CCD = dev->CCD;
|
||
|
||
|
||
if (dev->desc->use600)
|
||
{
|
||
dev->CCD.mode = MUSTEK_PP_MODE_COLOR;
|
||
dev->CCD.hwres = dev->CCD.res = 600;
|
||
}
|
||
else
|
||
{
|
||
dev->CCD.hwres = dev->CCD.res = 100;
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
}
|
||
|
||
dev->CCD.skipcount = dev->CCD.skipimagebytes = 0;
|
||
|
||
config_ccd (dev);
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
return_home_1013 (dev, nowait);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
return_home_1015 (dev, nowait);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
return_home_1505 (dev, nowait);
|
||
break;
|
||
}
|
||
|
||
dev->CCD = CCD;
|
||
|
||
dev->motor_step = 0;
|
||
|
||
config_ccd (dev);
|
||
}
|
||
|
||
static void
|
||
lamp (Mustek_PP_Device * dev, int lamp_on)
|
||
{
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
case MUSTEK_PP_ASIC_1015:
|
||
set_lamp (dev, lamp_on);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
lamp_1505 (dev, lamp_on);
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
set_voltages (Mustek_PP_Device * dev)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
case MUSTEK_PP_ASIC_1015:
|
||
send_voltages (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
send_voltages_1505 (dev);
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
static void
|
||
move_motor (Mustek_PP_Device * dev, int count, int forward)
|
||
{
|
||
|
||
int ctr;
|
||
int saved_niceload = niceload;
|
||
|
||
DBG (4, "move_motor: %u steps (%s)\n", count,
|
||
(forward == SANE_TRUE ? "forward" : "backward"));
|
||
|
||
niceload = 0;
|
||
|
||
for (ctr = 0; ctr < count; ctr++)
|
||
{
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
case MUSTEK_PP_ASIC_1015:
|
||
move_motor_101x (dev, forward);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
move_motor_1505 (dev, forward);
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
niceload = saved_niceload;
|
||
|
||
}
|
||
|
||
static void
|
||
calibrate (Mustek_PP_Device * dev)
|
||
{
|
||
|
||
DBG (1, "calibrate entered (asic = 0x%02x)\n", dev->asic_id);
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1015:
|
||
case MUSTEK_PP_ASIC_1013:
|
||
calibrate_device_101x (dev);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
calibrate_device_1505 (dev);
|
||
break;
|
||
}
|
||
|
||
DBG (3, "calibrate: ref_black %d, blackpos %d\n",
|
||
dev->ref_black, dev->blackpos);
|
||
|
||
}
|
||
|
||
|
||
static void
|
||
get_lineart_line (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1015:
|
||
case MUSTEK_PP_ASIC_1013:
|
||
get_lineart_line_101x (dev, buf);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
get_lineart_line_1505 (dev, buf);
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
static void
|
||
get_grayscale_line (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1015:
|
||
case MUSTEK_PP_ASIC_1013:
|
||
get_grayscale_line_101x (dev, buf);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
get_grayscale_line_1505 (dev, buf);
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
get_color_line (Mustek_PP_Device * dev, SANE_Byte * buf)
|
||
{
|
||
|
||
switch (dev->asic_id)
|
||
{
|
||
case MUSTEK_PP_ASIC_1015:
|
||
case MUSTEK_PP_ASIC_1013:
|
||
get_color_line_101x (dev, buf);
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
get_color_line_1505 (dev, buf);
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
#ifdef HAVE_AUTHORIZATION
|
||
|
||
static SANE_Status
|
||
do_authorization (SANE_String_Const ressource)
|
||
{
|
||
/* This function implements a simple authorization function. It looks */
|
||
/* up an entry in the file SANE_PATH_CONFIG_DIR/.auth. Such an entry */
|
||
/* must be of the form device:user:password where password is a crypt() */
|
||
/* encrypted password. If several users are allowed to access a device */
|
||
/* an entry must be created for each user. If no entry exists for device */
|
||
/* or the file does not exist the authentication failes. If the */
|
||
/* file exists, but can't be opened the authentication fails */
|
||
|
||
SANE_Status status;
|
||
FILE *fp;
|
||
int device_found;
|
||
char username[SANE_MAX_USERNAME_LEN];
|
||
char password[SANE_MAX_PASSWORD_LEN];
|
||
char line[MAX_LINE_LEN];
|
||
char *linep;
|
||
char *device;
|
||
char *user;
|
||
char *passwd;
|
||
char *p;
|
||
|
||
if (auth_callback == NULL)
|
||
{
|
||
DBG (2, "auth: no auth callback\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
/* first check if an entry exists in for this device */
|
||
|
||
fp = sanei_config_open (PASSWD_FILE);
|
||
|
||
if (fp == NULL)
|
||
{
|
||
DBG (2, "auth: password file is missing\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
linep = &line[0];
|
||
device_found = SANE_FALSE;
|
||
|
||
while (sanei_config_read (line, MAX_LINE_LEN, fp))
|
||
{
|
||
p = index (linep, SEPARATOR);
|
||
if (p)
|
||
{
|
||
*p = '\0';
|
||
device = linep;
|
||
if (strcmp (device, ressource) == 0)
|
||
{
|
||
device_found = SANE_TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (device_found == SANE_FALSE)
|
||
{
|
||
DBG (2, "auth: requested resource (%s) not in file\n", ressource);
|
||
DEBUG ();
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
fseek (fp, 0L, SEEK_SET);
|
||
|
||
(*auth_callback) (ressource, username, password);
|
||
|
||
status = SANE_STATUS_ACCESS_DENIED;
|
||
|
||
do
|
||
{
|
||
sanei_config_read (line, MAX_LINE_LEN, fp);
|
||
if (!ferror (fp) && !feof (fp))
|
||
{
|
||
/* neither strsep(3) nor strtok(3) seem to work on my system */
|
||
p = index (linep, SEPARATOR);
|
||
if (p == NULL)
|
||
continue;
|
||
*p = '\0';
|
||
device = linep;
|
||
if (strcmp (device, ressource) != 0) /* not a matching entry */
|
||
continue;
|
||
|
||
linep = ++p;
|
||
p = index (linep, SEPARATOR);
|
||
if (p == NULL)
|
||
continue;
|
||
|
||
*p = '\0';
|
||
user = linep;
|
||
if (strncmp (user, username, SANE_MAX_USERNAME_LEN) != 0)
|
||
continue; /* username doesn<73>t match */
|
||
|
||
linep = ++p;
|
||
/* rest of the line is considered to be the password */
|
||
passwd = linep;
|
||
/* remove newline */
|
||
*(passwd + strlen (passwd) - 1) = '\0';
|
||
p = crypt (password, SALT);
|
||
if (strcmp (p, passwd) == 0)
|
||
{
|
||
/* authentication ok */
|
||
status = SANE_STATUS_GOOD;
|
||
break;
|
||
}
|
||
else
|
||
continue;
|
||
}
|
||
}
|
||
while (!ferror (fp) && !feof (fp));
|
||
fclose (fp);
|
||
|
||
if (status != SANE_STATUS_GOOD)
|
||
DBG (1, "auth: access denied\n");
|
||
|
||
return status;
|
||
}
|
||
#endif
|
||
|
||
static SANE_Status
|
||
attach (const char *devname)
|
||
{
|
||
Mustek_PP_Descriptor *dev;
|
||
int i, fd;
|
||
SANE_Status status;
|
||
u_char val;
|
||
|
||
|
||
for (i = 0; i < num_devices; i++)
|
||
if (strcmp (devlist[i].port, devname) == 0)
|
||
return SANE_STATUS_GOOD;
|
||
|
||
status = sanei_pa4s2_open (devname, &fd);
|
||
|
||
if (status != SANE_STATUS_GOOD)
|
||
{
|
||
DBG (2, "attach: couldn't attach to `%s' (%s)\n", devname,
|
||
sane_strstatus (status));
|
||
DEBUG ();
|
||
return status;
|
||
}
|
||
|
||
|
||
sanei_pa4s2_enable (fd, SANE_TRUE);
|
||
sanei_pa4s2_readbegin (fd, 0);
|
||
sanei_pa4s2_readbyte (fd, &val);
|
||
sanei_pa4s2_readend (fd);
|
||
sanei_pa4s2_enable (fd, SANE_FALSE);
|
||
|
||
|
||
#ifndef PATCH_MUSTEK_PP_1505
|
||
|
||
if (val == MUSTEK_PP_ASIC_1505)
|
||
{
|
||
|
||
DBG (2, "attach: this scanner reports ASIC 0x%02x\n", (int) val);
|
||
DBG (2, "attach: you'll have to enable this in the source\n");
|
||
sanei_pa4s2_close (fd);
|
||
return SANE_STATUS_INVAL;
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
dev = malloc (sizeof (Mustek_PP_Descriptor) * (num_devices + 1));
|
||
|
||
if (dev == NULL)
|
||
{
|
||
DBG (2, "attach: not enough memory for device descriptor\n");
|
||
DEBUG ();
|
||
sanei_pa4s2_close (fd);
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
|
||
memset (dev, 0, sizeof (Mustek_PP_Descriptor) * (num_devices + 1));
|
||
|
||
if (num_devices > 0)
|
||
{
|
||
memcpy (dev + 1, devlist,
|
||
sizeof (Mustek_PP_Descriptor) * (num_devices));
|
||
free (devlist);
|
||
}
|
||
|
||
devlist = dev;
|
||
num_devices++;
|
||
|
||
dev->sane.name = strdup (devname);
|
||
dev->sane.vendor = strdup ("Mustek");
|
||
dev->sane.type = "flatbed scanner";
|
||
|
||
dev->port = strdup (devname);
|
||
|
||
dev->buf_size = buf_size;
|
||
|
||
dev->requires_auth = SANE_FALSE;
|
||
|
||
dev->wait_lamp = wait_lamp;
|
||
|
||
dev->bw = bw;
|
||
|
||
dev->asic = val;
|
||
|
||
sanei_pa4s2_enable (fd, SANE_TRUE);
|
||
sanei_pa4s2_readbegin (fd, 2);
|
||
sanei_pa4s2_readbyte (fd, &val);
|
||
sanei_pa4s2_readend (fd);
|
||
sanei_pa4s2_enable (fd, SANE_FALSE);
|
||
|
||
dev->ccd = (val & (dev->asic == MUSTEK_PP_ASIC_1013 ? 0x04 : 0x05));
|
||
/* FIXME: ASIC 1505 scanners do *not* report their CCD type ...
|
||
at least not this way :-( */
|
||
|
||
sanei_pa4s2_close (fd);
|
||
|
||
|
||
switch (dev->asic)
|
||
{
|
||
case MUSTEK_PP_ASIC_1013:
|
||
dev->max_res = 300;
|
||
dev->max_h_size = MUSTEK_PP_101x_MAX_H_PIXEL;
|
||
dev->max_v_size = MUSTEK_PP_101x_MAX_V_PIXEL;
|
||
dev->wait_bank = wait_bank;
|
||
dev->strip_height = strip_height;
|
||
dev->sane.model = strdup ("MFS-600IIIP");
|
||
|
||
dev->use600 = SANE_FALSE;
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1015:
|
||
|
||
/* if (dev->ccd == 1)
|
||
{
|
||
dev->max_res = 600;
|
||
dev->max_h_size = MUSTEK_PP_101x_MAX_H_PIXEL * 2;
|
||
dev->max_v_size = MUSTEK_PP_101x_MAX_V_PIXEL * 2;
|
||
}
|
||
else
|
||
{*/
|
||
dev->max_res = 300;
|
||
dev->max_h_size = MUSTEK_PP_101x_MAX_H_PIXEL;
|
||
dev->max_v_size = MUSTEK_PP_101x_MAX_V_PIXEL;
|
||
/* }*/
|
||
|
||
dev->wait_bank = wait_bank;
|
||
dev->strip_height = strip_height;
|
||
dev->sane.model = strdup ("MFS-600IIIP");
|
||
|
||
dev->use600 = SANE_FALSE;
|
||
break;
|
||
|
||
case MUSTEK_PP_ASIC_1505:
|
||
|
||
DBG (2, "attach: don't know parameters for ASIC 1505 scanner\n");
|
||
DEBUG ();
|
||
|
||
dev->max_res = 600;
|
||
dev->max_h_size = 5100;
|
||
dev->max_v_size = 7000;
|
||
dev->wait_bank = wait_bank;
|
||
dev->strip_height = strip_height;
|
||
dev->sane.model = strdup ("MFS-600IIIP");
|
||
dev->use600 = SANE_TRUE;
|
||
break;
|
||
}
|
||
|
||
|
||
|
||
DBG (3, "attach: device %s attached\n", devname);
|
||
|
||
DBG (3, "attach: asic 0x%02x, ccd %02d\n", dev->asic, dev->ccd);
|
||
|
||
DBG (4, "attach: use600 is `%s'\n",
|
||
(dev->use600 == SANE_TRUE ? "yes" : "no"));
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
static size_t
|
||
max_string_size (const SANE_String_Const strings[])
|
||
{
|
||
size_t size, max_size = 0;
|
||
int i;
|
||
|
||
for (i = 0; strings[i]; ++i)
|
||
{
|
||
size = strlen (strings[i]) + 1;
|
||
if (size > max_size)
|
||
max_size = size;
|
||
}
|
||
|
||
return max_size;
|
||
}
|
||
|
||
|
||
|
||
static SANE_Status
|
||
init_options (Mustek_PP_Device * dev)
|
||
{
|
||
int i;
|
||
|
||
/* only this code is tested so far */
|
||
ASSERT ((dev->asic_id == MUSTEK_PP_ASIC_1013) ||
|
||
((dev->asic_id == MUSTEK_PP_ASIC_1015) && (dev->ccd_type == 0)));
|
||
|
||
memset (dev->opt, 0, sizeof (dev->opt));
|
||
memset (dev->val, 0, sizeof (dev->val));
|
||
|
||
for (i = 0; i < NUM_OPTIONS; ++i)
|
||
{
|
||
dev->opt[i].size = sizeof (SANE_Word);
|
||
dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
|
||
}
|
||
|
||
dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
|
||
dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
|
||
dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
|
||
dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
|
||
dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
|
||
|
||
/* "Mode" group: */
|
||
|
||
dev->opt[OPT_MODE_GROUP].title = "Scan Mode";
|
||
dev->opt[OPT_MODE_GROUP].desc = "";
|
||
dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
|
||
dev->opt[OPT_MODE_GROUP].cap = 0;
|
||
dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
||
/* scan mode */
|
||
dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
|
||
dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
|
||
dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
|
||
dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
|
||
dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
||
dev->opt[OPT_MODE].size = max_string_size (mode_list);
|
||
dev->opt[OPT_MODE].constraint.string_list = mode_list;
|
||
dev->val[OPT_MODE].s = strdup (mode_list[2]);
|
||
|
||
/* resolution */
|
||
dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
|
||
dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
|
||
dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
|
||
dev->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
|
||
dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
|
||
dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_RESOLUTION].constraint.range = &dev->dpi_range;
|
||
dev->val[OPT_RESOLUTION].w = dev->dpi_range.max;
|
||
|
||
/* preview */
|
||
dev->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
|
||
dev->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
|
||
dev->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
|
||
dev->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
|
||
dev->val[OPT_PREVIEW].w = SANE_FALSE;
|
||
|
||
/* gray preview */
|
||
dev->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
|
||
dev->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
|
||
dev->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
|
||
dev->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
|
||
dev->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
|
||
|
||
/* "Geometry" group: */
|
||
|
||
dev->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
|
||
dev->opt[OPT_GEOMETRY_GROUP].desc = "";
|
||
dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
|
||
dev->opt[OPT_GEOMETRY_GROUP].cap = 0;
|
||
dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
||
/* top-left x */
|
||
dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
|
||
dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
|
||
dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
|
||
dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
|
||
dev->opt[OPT_TL_X].unit = SANE_UNIT_MM;
|
||
dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_TL_X].constraint.range = &dev->x_range;
|
||
dev->val[OPT_TL_X].w = 0;
|
||
|
||
/* top-left y */
|
||
dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
|
||
dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
|
||
dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
|
||
dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
|
||
dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
|
||
dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_TL_Y].constraint.range = &dev->y_range;
|
||
dev->val[OPT_TL_Y].w = 0;
|
||
|
||
/* bottom-right x */
|
||
dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
|
||
dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
|
||
dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
|
||
dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
|
||
dev->opt[OPT_BR_X].unit = SANE_UNIT_MM;
|
||
dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_BR_X].constraint.range = &dev->x_range;
|
||
dev->val[OPT_BR_X].w = dev->x_range.max;
|
||
|
||
/* bottom-right y */
|
||
dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
|
||
dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
|
||
dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
|
||
dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
|
||
dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
|
||
dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_BR_Y].constraint.range = &dev->y_range;
|
||
dev->val[OPT_BR_Y].w = dev->y_range.max;
|
||
|
||
/* "Enhancement" group: */
|
||
|
||
dev->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
|
||
dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";
|
||
dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
|
||
dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
|
||
dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
||
|
||
#ifdef HAVE_INVERSION
|
||
|
||
/* invert */
|
||
dev->oPt[OPT_INVERT].name = SANE_NAME_NEGATIVE;
|
||
dev->opt[OPT_INVERT].title = SANE_TITLE_NEGATIVE;
|
||
dev->opt[OPT_INVERT].desc = "Invert colors colors/swap black and white";
|
||
dev->opt[OPT_INVERT].type = SANE_TYPE_BOOL;
|
||
dev->opt[OPT_INVERT].cap |= SANE_CAP_ADVANCED;
|
||
dev->val[OPT_INVERT].w = SANE_FALSE;
|
||
|
||
#endif
|
||
|
||
/* custom-gamma table */
|
||
dev->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
|
||
dev->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
|
||
dev->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
|
||
dev->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
|
||
dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED;
|
||
dev->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
|
||
|
||
/* grayscale gamma vector */
|
||
dev->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
|
||
dev->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
|
||
dev->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
|
||
dev->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
|
||
dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
|
||
dev->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
|
||
dev->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
|
||
dev->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
|
||
dev->val[OPT_GAMMA_VECTOR].wa = &dev->gamma_table[0][0];
|
||
|
||
/* red gamma vector */
|
||
dev->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
|
||
dev->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
|
||
dev->val[OPT_GAMMA_VECTOR_R].wa = &dev->gamma_table[1][0];
|
||
|
||
/* green gamma vector */
|
||
dev->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
|
||
dev->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
|
||
dev->val[OPT_GAMMA_VECTOR_G].wa = &dev->gamma_table[2][0];
|
||
|
||
/* blue gamma vector */
|
||
dev->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
|
||
dev->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
|
||
dev->val[OPT_GAMMA_VECTOR_B].wa = &dev->gamma_table[3][0];
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
|
||
|
||
SANE_Status
|
||
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
||
{
|
||
char dev_name[PATH_MAX], *cp;
|
||
size_t len;
|
||
FILE *fp;
|
||
u_int io_mode = SANEI_PA4S2_OPT_DEFAULT;
|
||
|
||
DBG_INIT ();
|
||
|
||
if (version_code != NULL)
|
||
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, MUSTEK_PP_BUILD);
|
||
|
||
DBG (3, "init: SANE v%s, backend v%d.%d.%d-%s\n", VERSION, V_MAJOR, V_MINOR,
|
||
MUSTEK_PP_BUILD, MUSTEK_PP_STATE);
|
||
|
||
#ifdef PATCH_MUSTEK_PP_1505
|
||
|
||
DBG (3, "init: patches for ASIC 1505 (0xA2) enabled\n");
|
||
|
||
#endif
|
||
|
||
#ifdef HAVE_AUTHORIZATION
|
||
|
||
auth_callback = authorize;
|
||
|
||
ASSERT (authorize != NULL);
|
||
|
||
#else
|
||
|
||
DBG (1, "I wouldn't let myself be root if I were you...\n");
|
||
|
||
#endif
|
||
|
||
fp = sanei_config_open (MUSTEK_PP_CONFIG_FILE);
|
||
|
||
|
||
if (fp == NULL)
|
||
{
|
||
DBG (2, "init: no configuration file, using default `port 0x%03x'\n",
|
||
MUSTEK_PP_DEFAULT_PORT);
|
||
|
||
attach (STRINGIFY (MUSTEK_PP_DEFAULT_PORT));
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
while (sanei_config_read (dev_name, sizeof (dev_name), fp))
|
||
{
|
||
cp = (char *) sanei_config_skip_whitespace (dev_name);
|
||
if (!*cp || *cp == '#') /* ignore line comments & empty lines */
|
||
continue;
|
||
|
||
len = strlen (cp);
|
||
/* if (cp[len - 1] == '\n')
|
||
cp[--len] = '\0';
|
||
|
||
while (len && isspace (cp[len - 1]))
|
||
cp[--len] = '\0';
|
||
|
||
if (!len)
|
||
continue;*/ /* ignore empty lines */
|
||
|
||
|
||
if (strncmp (cp, "option", 6) == 0 && isspace (cp[6]))
|
||
{
|
||
|
||
cp += 7;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
if (strncmp (cp, "strip-height", 12) == 0 && isspace (cp[12]))
|
||
{
|
||
char *end;
|
||
int val;
|
||
|
||
errno = 0;
|
||
cp += 13;
|
||
val = strtol (cp, &end, 0);
|
||
if ((end == cp || errno) || (val < 0))
|
||
{
|
||
DBG (2, "init: invalid value `%s`, falling back to %d\n",
|
||
cp, strip_height);
|
||
val = strip_height; /* safe fallback */
|
||
}
|
||
|
||
DBG (3, "init: option strip-height %d\n", val);
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (3, "init: setting global option strip-height to %d\n",
|
||
val);
|
||
strip_height = val;
|
||
}
|
||
else
|
||
{
|
||
DBG (3, "init: setting strip-height to %d for device %s\n",
|
||
val, devlist[0].sane.name);
|
||
devlist[0].strip_height = val;
|
||
}
|
||
}
|
||
else if (strncmp (cp, "io-mode", 7) == 0 && isspace (cp[7]))
|
||
{
|
||
|
||
cp += 8;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
if (strncmp (cp, "try_mode_uni", 12) == 0)
|
||
io_mode |= SANEI_PA4S2_OPT_TRY_MODE_UNI;
|
||
else if (strncmp (cp, "alt_lock", 8) == 0)
|
||
io_mode |= SANEI_PA4S2_OPT_ALT_LOCK;
|
||
else
|
||
DBG (2, "init: unknown io-mode `%s'\n", cp);
|
||
|
||
DBG (3, "init: option io-mode %d\n", io_mode);
|
||
|
||
}
|
||
else if (strncmp (cp, "wait-bank", 9) == 0 && isspace (cp[9]))
|
||
{
|
||
char *end;
|
||
int val;
|
||
|
||
cp += 10;
|
||
|
||
errno = 0;
|
||
val = strtol (cp, &end, 0);
|
||
|
||
if ((end == cp || errno) || (val < 0))
|
||
{
|
||
DBG (2, "init: invalid value `%s`, falling back to %d\n",
|
||
cp, wait_bank);
|
||
val = wait_bank; /* safe fallback */
|
||
}
|
||
|
||
DBG (3, "init: option wait-bank %d\n", val);
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (3, "init: setting global option wait-bank to %d\n",
|
||
val);
|
||
wait_bank = val;
|
||
}
|
||
else
|
||
{
|
||
DBG (3, "init: setting wait-bank to %d for device %s\n",
|
||
val, devlist[0].sane.name);
|
||
devlist[0].wait_bank = val;
|
||
}
|
||
}
|
||
else if (strncmp (cp, "bw", 2) == 0 && isspace (cp[2]))
|
||
{
|
||
char *end;
|
||
int val;
|
||
|
||
cp += 3;
|
||
|
||
errno = 0;
|
||
val = strtol (cp, &end, 0);
|
||
|
||
if ((end == cp || errno) || (val < 0) || (val > 255))
|
||
{
|
||
DBG (2, "init: invalid value `%s`, falling back to %d\n",
|
||
cp, bw);
|
||
val = bw; /* safe fallback */
|
||
}
|
||
|
||
DBG (3, "init: option bw %d\n", val);
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (3, "init: setting global option bw to %d\n", val);
|
||
bw = val;
|
||
}
|
||
else
|
||
{
|
||
DBG (3, "init: setting bw to %d for device %s\n",
|
||
val, devlist[0].sane.name);
|
||
devlist[0].bw = val;
|
||
}
|
||
}
|
||
else if (strncmp (cp, "wait-lamp", 9) == 0 && isspace (cp[9]))
|
||
{
|
||
char *end;
|
||
int val;
|
||
|
||
cp += 10;
|
||
|
||
errno = 0;
|
||
val = strtol (cp, &end, 0);
|
||
|
||
if ((end == cp || errno) || (val < 0))
|
||
{
|
||
DBG (2, "init: invalid value `%s`, falling back to %d\n",
|
||
cp, wait_lamp);
|
||
val = wait_lamp; /* safe fallback */
|
||
}
|
||
|
||
DBG (3, "init: option wait-lamp %d\n", val);
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (3, "init: setting global option wait-lamp to %d\n",
|
||
val);
|
||
wait_lamp = val;
|
||
}
|
||
else
|
||
{
|
||
DBG (3, "init: setting wait-lamp to %d for device %s\n",
|
||
val, devlist[0].sane.name);
|
||
devlist[0].wait_lamp = val;
|
||
}
|
||
}
|
||
else if (strncmp (cp, "buffer", 6) == 0 && isspace (cp[6]))
|
||
{
|
||
char *end;
|
||
long int val;
|
||
|
||
cp += 7;
|
||
|
||
errno = 0;
|
||
val = strtol (cp, &end, 0);
|
||
|
||
if ((end == cp || errno) || (val < 0))
|
||
{
|
||
DBG (2, "init: invalid value `%s`, falling back to %ld\n",
|
||
cp, buf_size);
|
||
val = buf_size; /* safe fallback */
|
||
}
|
||
|
||
DBG (3, "init: option buffer %ld\n", val);
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (3, "init: setting global option buffer to %ld\n", val);
|
||
buf_size = val;
|
||
}
|
||
else
|
||
{
|
||
DBG (3, "init: setting buffer to %ld for device %s\n",
|
||
val, devlist[0].sane.name);
|
||
devlist[0].buf_size = val;
|
||
}
|
||
}
|
||
else if (strncmp (cp, "niceload", 8) == 0)
|
||
{
|
||
DBG (3, "init: option niceload\n");
|
||
niceload = 1;
|
||
}
|
||
else if (strncmp (cp, "use600", 6) == 0)
|
||
{
|
||
if (num_devices == 0)
|
||
DBG (2, "init: option use600 isn't a global option\n");
|
||
else
|
||
{
|
||
DBG (3, "init: device %s is a 600 dpi scanner\n",
|
||
devlist[0].sane.name);
|
||
if (devlist[0].use600 == SANE_FALSE)
|
||
{
|
||
devlist[0].use600 = SANE_TRUE;
|
||
devlist[0].max_res = 600;
|
||
devlist[0].max_h_size = MUSTEK_PP_101x_MAX_H_PIXEL * 2;
|
||
devlist[0].max_v_size = MUSTEK_PP_101x_MAX_V_PIXEL * 2;
|
||
}
|
||
else
|
||
{
|
||
DBG (2, "init: option use600 alreay present...\n");
|
||
}
|
||
}
|
||
}
|
||
else if (strncmp (cp, "auth", 4) == 0)
|
||
{
|
||
#ifndef HAVE_AUTHORIZATION
|
||
DBG (1, "init: user authentification support not compiled\n");
|
||
DEBUG ();
|
||
#endif
|
||
if (num_devices == 0)
|
||
DBG (2, "init: option auth isn't a global option\n");
|
||
else
|
||
{
|
||
DBG (3, "init: device %s requires user authentification\n",
|
||
devlist[0].sane.name);
|
||
devlist[0].requires_auth = SANE_TRUE;
|
||
}
|
||
}
|
||
else
|
||
DBG (2, "init: unknown option `%s'\n", cp);
|
||
continue;
|
||
}
|
||
else if ((strncmp (cp, "port", 4) == 0) && isspace (cp[4]))
|
||
{
|
||
|
||
cp += 5;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
DBG (3, "init: trying port `%s'\n", cp);
|
||
|
||
if (*cp)
|
||
if (attach (cp) != SANE_STATUS_GOOD)
|
||
DBG (2, "init: couldn't attach to port `%s'\n", cp);
|
||
}
|
||
else if ((strncmp (cp, "name", 4) == 0) && isspace (cp[4]))
|
||
{
|
||
cp += 5;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
if (num_devices == 0)
|
||
DBG (2, "init: 'name' only allowed after 'port'\n");
|
||
else
|
||
{
|
||
DBG (3, "init: naming device %s '%s'\n", devlist[0].port, cp);
|
||
free (devlist[0].sane.name);
|
||
devlist[0].sane.name = strdup (cp);
|
||
}
|
||
}
|
||
else if ((strncmp (cp, "model", 5) == 0) && isspace (cp[5]))
|
||
{
|
||
cp += 6;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
if (num_devices == 0)
|
||
DBG (2, "init: 'model' only allowed after 'port'\n");
|
||
else
|
||
{
|
||
DBG (3, "init: device %s is a '%s'\n", devlist[0].port, cp);
|
||
free (devlist[0].sane.model);
|
||
devlist[0].sane.model = strdup (cp);
|
||
}
|
||
}
|
||
else if ((strncmp (cp, "vendor", 6) == 0) && isspace (cp[6]))
|
||
{
|
||
cp += 7;
|
||
cp = (char *) sanei_config_skip_whitespace (cp);
|
||
|
||
if (num_devices == 0)
|
||
DBG (2, "init: 'vendor' only allowed after 'port'\n");
|
||
else
|
||
{
|
||
DBG (3, "init: device %s is from '%s'\n", devlist[0].port, cp);
|
||
free (devlist[0].sane.vendor);
|
||
devlist[0].sane.vendor = strdup (cp);
|
||
}
|
||
}
|
||
else
|
||
DBG (2, "init: don't know what to do with `%s'\n", cp);
|
||
}
|
||
|
||
fclose (fp);
|
||
|
||
sanei_pa4s2_options (&io_mode, SANE_TRUE);
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
void
|
||
sane_exit (void)
|
||
{
|
||
int i;
|
||
Mustek_PP_Device *dev;
|
||
|
||
if (first_dev)
|
||
DBG (3, "exit: closing open devices\n");
|
||
|
||
while (first_dev)
|
||
{
|
||
dev = first_dev;
|
||
sane_close (dev);
|
||
}
|
||
|
||
for (i = 0; i < num_devices; i++)
|
||
{
|
||
free (devlist[i].port);
|
||
free (devlist[i].sane.name);
|
||
free (devlist[i].sane.model);
|
||
free (devlist[i].sane.vendor);
|
||
}
|
||
|
||
if (devlist != NULL)
|
||
free (devlist);
|
||
|
||
if (devarray != NULL)
|
||
free (devarray);
|
||
|
||
DBG (3, "exit: (...)\n");
|
||
|
||
num_devices = 0;
|
||
}
|
||
|
||
SANE_Status
|
||
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
||
{
|
||
int i;
|
||
|
||
DBG (129, "unused arg: local_only = %d\n", (int) local_only);
|
||
|
||
if (devarray != NULL)
|
||
free (devarray);
|
||
|
||
devarray = malloc ((num_devices + 1) * sizeof (devarray[0]));
|
||
|
||
if (devarray == NULL)
|
||
{
|
||
DBG (2, "get_devices: not enough memory for device list\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
|
||
for (i = 0; i < num_devices; i++)
|
||
devarray[i] = &devlist[i].sane;
|
||
|
||
devarray[num_devices] = NULL;
|
||
*device_list = devarray;
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
SANE_Status
|
||
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
||
{
|
||
Mustek_PP_Device *dev;
|
||
Mustek_PP_Descriptor *desc;
|
||
SANE_Status status;
|
||
int i, j, fd;
|
||
|
||
DBG (3, "open: device `%s'\n", devicename);
|
||
|
||
if (devicename[0])
|
||
{
|
||
for (i = 0; i < num_devices; i++)
|
||
if (strcmp (devlist[i].sane.name, devicename) == 0)
|
||
break;
|
||
|
||
if (i >= num_devices)
|
||
for (i = 0; i < num_devices; i++)
|
||
if (strcmp (devlist[i].port, devicename) == 0)
|
||
break;
|
||
|
||
if (i >= num_devices)
|
||
{
|
||
DBG (2, "open: device doesn't exist\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
desc = &devlist[i];
|
||
|
||
#ifdef HAVE_AUTHORIZATION
|
||
|
||
if (desc->requires_auth == SANE_TRUE)
|
||
if (do_authorization (devlist[i].port) != SANE_STATUS_GOOD)
|
||
{
|
||
DBG (2, "open: access denied\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
#else
|
||
|
||
/* authorization should realy be compiled */
|
||
/* DBG (1, "I wouldn't let myself be root if I were you\n"); */
|
||
|
||
if (desc->requires_auth == SANE_TRUE)
|
||
{
|
||
DBG (1, "open: ressource %s requires user authentification\n",
|
||
desc->port);
|
||
DBG (3, "open: ... which isn't compiled :-(\n");
|
||
DBG (2, "open: access denied\n");
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
#endif
|
||
|
||
status = sanei_pa4s2_open (devlist[i].port, &fd);
|
||
}
|
||
else
|
||
{
|
||
|
||
if (num_devices == 0)
|
||
{
|
||
DBG (1, "open: no devices present\n");
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
DBG (3, "open: trying default device %s\n", devlist[0].sane.name);
|
||
|
||
#ifdef HAVE_AUTHORIZATION
|
||
|
||
if (devlist[0].requires_auth == SANE_TRUE)
|
||
if (do_authorization (devlist[0].port) != SANE_STATUS_GOOD)
|
||
{
|
||
DBG (2, "open: access denied\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
#else
|
||
|
||
/* authorization should realy be compiled */
|
||
/* DBG (1, "I wouldn't let myself be root if I were you\n"); */
|
||
if (devlist[0].requires_auth == SANE_TRUE)
|
||
{
|
||
DBG (1, "open: ressource %s requires user authentification\n",
|
||
devlist[0].port);
|
||
DBG (3, "open: ... which isn't compiled :-(\n");
|
||
DBG (2, "open: access denied\n");
|
||
return SANE_STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
status = sanei_pa4s2_open (devlist[0].port, &fd);
|
||
|
||
desc = &devlist[0];
|
||
}
|
||
|
||
if (status != SANE_STATUS_GOOD)
|
||
{
|
||
DBG (2, "open: device not found (%s)\n", sane_strstatus (status));
|
||
DEBUG ();
|
||
return status;
|
||
}
|
||
|
||
dev = (Mustek_PP_Device *) malloc (sizeof (*dev));
|
||
|
||
if (dev == NULL)
|
||
{
|
||
DBG (2, "open: not enough memory for device descriptor\n");
|
||
DEBUG ();
|
||
sanei_pa4s2_close (fd);
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
|
||
memset (dev, 0, sizeof (*dev));
|
||
|
||
dev->fd = fd;
|
||
|
||
dev->desc = desc;
|
||
|
||
dev->asic_id = dev->desc->asic;
|
||
dev->ccd_type = dev->desc->ccd;
|
||
|
||
dev->motor_ctrl = 0x43;
|
||
dev->first_time = 1;
|
||
dev->unknown_value = 0xAA;
|
||
dev->expose_time = 0x64;
|
||
dev->send_voltages = 0;
|
||
|
||
for (i = 0; i < 4; ++i)
|
||
for (j = 0; j < 256; ++j)
|
||
dev->gamma_table[i][j] = j;
|
||
|
||
if (dev->desc->buf_size < 3 * dev->desc->max_h_size)
|
||
{
|
||
|
||
DBG (2, "open: scan buffer to small, falling back to %d bytes\n",
|
||
dev->desc->max_h_size * 3);
|
||
dev->desc->buf_size = dev->desc->max_h_size * 3;
|
||
}
|
||
|
||
dev->buf = malloc (dev->desc->buf_size);
|
||
dev->bufsize = dev->desc->buf_size;
|
||
|
||
dev->dpi_range.min = SANE_FIX (50);
|
||
dev->dpi_range.max = SANE_FIX (dev->desc->max_res);
|
||
dev->dpi_range.quant = SANE_FIX (1);
|
||
|
||
dev->x_range.min = 0;
|
||
dev->x_range.max =
|
||
PIXEL_TO_MM (dev->desc->max_h_size, (float) dev->desc->max_res);
|
||
dev->x_range.quant = 0;
|
||
|
||
dev->y_range.min = 0;
|
||
dev->y_range.max =
|
||
PIXEL_TO_MM (dev->desc->max_v_size, (float) dev->desc->max_res);
|
||
dev->y_range.quant = 0;
|
||
|
||
DBG (6, "open: range (0.0,0.0)-(%f,%f)\n", SANE_UNFIX (dev->x_range.max),
|
||
SANE_UNFIX (dev->y_range.max));
|
||
|
||
|
||
if (dev->buf == NULL)
|
||
{
|
||
DBG (2, "open: not enough memory for scan buffer (%lu bytes)\n",
|
||
(long int) dev->desc->buf_size);
|
||
DEBUG ();
|
||
sanei_pa4s2_close (fd);
|
||
free (dev);
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
|
||
init_options (dev);
|
||
|
||
dev->next = first_dev;
|
||
first_dev = dev;
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_TRUE);
|
||
|
||
lamp (dev, SANE_TRUE);
|
||
|
||
if (dev->desc->use600)
|
||
dev->params.pixels_per_line = 10;
|
||
|
||
dev->CCD.hwres = dev->CCD.res = dev->desc->max_res;
|
||
dev->CCD.mode = MUSTEK_PP_MODE_COLOR;
|
||
|
||
return_home (dev, SANE_TRUE);
|
||
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
dev->lamp_on = time (NULL);
|
||
dev->max_lines = dev->desc->strip_height;
|
||
|
||
*handle = dev;
|
||
|
||
DBG (3, "open: success\n");
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
void
|
||
sane_close (SANE_Handle handle)
|
||
{
|
||
Mustek_PP_Device *prev, *dev;
|
||
|
||
/* remove handle from list of open handles: */
|
||
prev = NULL;
|
||
|
||
for (dev = first_dev; dev; dev = dev->next)
|
||
{
|
||
if (dev == handle)
|
||
break;
|
||
prev = dev;
|
||
}
|
||
|
||
if (dev == NULL)
|
||
{
|
||
DBG (2, "close: unknown device\n");
|
||
DEBUG ();
|
||
return; /* oops, not a handle we know about */
|
||
}
|
||
|
||
if (dev->state == MUSTEK_PP_STATE_SCANNING)
|
||
sane_cancel (handle); /* remember: sane_cancel is a macro and
|
||
expands to sane_mustek_pp_cancel ()... */
|
||
|
||
if (prev != NULL)
|
||
prev->next = dev->next;
|
||
else
|
||
first_dev = dev->next; /* mustek.c had a bug at this point :-) */
|
||
|
||
DBG (3, "close: maybe waiting for lamp...\n");
|
||
while (time (NULL) - dev->lamp_on < 2)
|
||
sleep (1);
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_TRUE);
|
||
lamp (dev, SANE_FALSE);
|
||
return_home (dev, SANE_FALSE);
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
sanei_pa4s2_close (dev->fd);
|
||
free (dev->buf);
|
||
|
||
DBG (3, "close: device closed\n");
|
||
|
||
free (handle);
|
||
|
||
}
|
||
|
||
const SANE_Option_Descriptor *
|
||
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
|
||
if ((unsigned) option >= NUM_OPTIONS)
|
||
{
|
||
DBG (2, "get_option_descriptor: option %d doesn't exist\n", option);
|
||
DEBUG ();
|
||
return NULL;
|
||
}
|
||
|
||
DBG (6, "get_option_descriptor: requested option %d (%s)\n",
|
||
option, dev->opt[option].name);
|
||
|
||
return dev->opt + option;
|
||
}
|
||
|
||
SANE_Status
|
||
sane_control_option (SANE_Handle handle, SANE_Int option,
|
||
SANE_Action action, void *val, SANE_Int * info)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
SANE_Status status;
|
||
SANE_Word w, cap;
|
||
|
||
DBG (6, "control_option: option %d, action %d\n", option, action);
|
||
|
||
if (info)
|
||
*info = 0;
|
||
|
||
if (dev->state == MUSTEK_PP_STATE_SCANNING)
|
||
{
|
||
DBG (2, "control_option: device is scanning\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_DEVICE_BUSY;
|
||
}
|
||
|
||
if ((unsigned int) option >= NUM_OPTIONS)
|
||
{
|
||
DBG (2, "control_option: option doesn't exist\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
cap = dev->opt[option].cap;
|
||
|
||
if (!SANE_OPTION_IS_ACTIVE (cap))
|
||
{
|
||
DBG (2, "control_option: option isn't active\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
if (action == SANE_ACTION_GET_VALUE)
|
||
{
|
||
|
||
switch (option)
|
||
{
|
||
/* word options: */
|
||
case OPT_PREVIEW:
|
||
case OPT_GRAY_PREVIEW:
|
||
case OPT_RESOLUTION:
|
||
case OPT_TL_X:
|
||
case OPT_TL_Y:
|
||
case OPT_BR_X:
|
||
case OPT_BR_Y:
|
||
case OPT_NUM_OPTS:
|
||
case OPT_CUSTOM_GAMMA:
|
||
#ifdef HAVE_INVERSION
|
||
case OPT_INVERT:
|
||
#endif
|
||
|
||
*(SANE_Word *) val = dev->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:
|
||
|
||
memcpy (val, dev->val[option].wa, dev->opt[option].size);
|
||
return SANE_STATUS_GOOD;
|
||
|
||
/* string options: */
|
||
case OPT_MODE:
|
||
|
||
strcpy (val, dev->val[option].s);
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
}
|
||
else if (action == SANE_ACTION_SET_VALUE)
|
||
{
|
||
|
||
if (!SANE_OPTION_IS_SETTABLE (cap))
|
||
{
|
||
DBG (2, "control_option: option can't be set\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
status = sanei_constrain_value (dev->opt + option, val, info);
|
||
|
||
if (status != SANE_STATUS_GOOD)
|
||
{
|
||
DBG (2, "control_option: constrain_value failed (%s)\n",
|
||
sane_strstatus (status));
|
||
DEBUG ();
|
||
return status;
|
||
}
|
||
|
||
switch (option)
|
||
{
|
||
/* (mostly) side-effect-free word options: */
|
||
case OPT_RESOLUTION:
|
||
case OPT_TL_X:
|
||
case OPT_BR_X:
|
||
case OPT_TL_Y:
|
||
case OPT_BR_Y:
|
||
case OPT_PREVIEW:
|
||
case OPT_GRAY_PREVIEW:
|
||
#ifdef HAVE_INVERSION
|
||
case OPT_INVERT:
|
||
#endif
|
||
|
||
if (info)
|
||
*info |= SANE_INFO_RELOAD_PARAMS;
|
||
|
||
dev->val[option].w = *(SANE_Word *) val;
|
||
return SANE_STATUS_GOOD;
|
||
|
||
/* side-effect-free word-array options: */
|
||
case OPT_GAMMA_VECTOR:
|
||
case OPT_GAMMA_VECTOR_R:
|
||
case OPT_GAMMA_VECTOR_G:
|
||
case OPT_GAMMA_VECTOR_B:
|
||
|
||
memcpy (dev->val[option].wa, val, dev->opt[option].size);
|
||
return SANE_STATUS_GOOD;
|
||
|
||
|
||
/* options with side-effects: */
|
||
|
||
case OPT_CUSTOM_GAMMA:
|
||
w = *(SANE_Word *) val;
|
||
|
||
if (w == dev->val[OPT_CUSTOM_GAMMA].w)
|
||
return SANE_STATUS_GOOD; /* no change */
|
||
|
||
if (info)
|
||
*info |= SANE_INFO_RELOAD_OPTIONS;
|
||
|
||
dev->val[OPT_CUSTOM_GAMMA].w = w;
|
||
|
||
if (w == SANE_TRUE)
|
||
{
|
||
const char *mode = dev->val[OPT_MODE].s;
|
||
|
||
if (strcmp (mode, "Gray") == 0)
|
||
dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
else if (strcmp (mode, "Color") == 0)
|
||
{
|
||
dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
|
||
}
|
||
|
||
return SANE_STATUS_GOOD;
|
||
|
||
case OPT_MODE:
|
||
{
|
||
char *old_val = dev->val[option].s;
|
||
|
||
if (old_val)
|
||
{
|
||
if (strcmp (old_val, val) == 0)
|
||
return SANE_STATUS_GOOD; /* no change */
|
||
|
||
free (old_val);
|
||
}
|
||
|
||
if (info)
|
||
*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
|
||
|
||
dev->val[option].s = strdup (val);
|
||
|
||
dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
|
||
|
||
if (strcmp (val, "Lineart") != 0)
|
||
dev->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
|
||
|
||
if (dev->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
|
||
{
|
||
if (strcmp (val, "Gray") == 0)
|
||
dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
else if (strcmp (val, "Color") == 0)
|
||
{
|
||
dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
|
||
dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
|
||
}
|
||
}
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
}
|
||
}
|
||
|
||
DBG (2, "control_option: unknown action\n");
|
||
DEBUG ();
|
||
return SANE_STATUS_INVAL;
|
||
}
|
||
|
||
|
||
SANE_Status
|
||
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
char *mode;
|
||
|
||
if (dev->state != MUSTEK_PP_STATE_SCANNING)
|
||
{
|
||
|
||
int dpi;
|
||
|
||
memset (&dev->params, 0, sizeof (dev->params));
|
||
|
||
mode = dev->val[OPT_MODE].s;
|
||
|
||
if (strcmp (mode, "Lineart") == 0)
|
||
dev->CCD.mode = MUSTEK_PP_MODE_LINEART;
|
||
else if (strcmp (mode, "Gray") == 0)
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
else
|
||
dev->CCD.mode = MUSTEK_PP_MODE_COLOR;
|
||
|
||
|
||
if (dev->val[OPT_PREVIEW].w == SANE_TRUE)
|
||
{
|
||
|
||
if (dev->val[OPT_GRAY_PREVIEW].w == SANE_TRUE)
|
||
dev->CCD.mode = MUSTEK_PP_MODE_GRAYSCALE;
|
||
else
|
||
dev->CCD.mode = MUSTEK_PP_MODE_COLOR;
|
||
|
||
}
|
||
|
||
DBG (3, "get_parameters: mode `%s'\n", mode);
|
||
|
||
dpi = (int) (SANE_UNFIX (dev->val[OPT_RESOLUTION].w) + 0.5);
|
||
dev->CCD.res = dpi;
|
||
|
||
DBG (3, "get_parameters: %d dpi\n", dpi);
|
||
|
||
if (dpi <= 100)
|
||
dev->CCD.hwres = 100;
|
||
else if (dpi <= 200)
|
||
dev->CCD.hwres = 200;
|
||
else if (dpi <= 300)
|
||
dev->CCD.hwres = 300;
|
||
else if (dpi <= 400)
|
||
dev->CCD.hwres = 400;
|
||
else if (dpi <= 600)
|
||
dev->CCD.hwres = 600;
|
||
|
||
/* TODO: add 1505 code for hw resolution here */
|
||
|
||
DBG (6, "get_parameters: resolution %d dpi -> hardware %d dpi\n",
|
||
dev->CCD.res, dev->CCD.hwres);
|
||
|
||
#ifdef HAVE_INVERSION
|
||
dev->CCD.invert = dev->val[OPT_INVERT].w;
|
||
#else
|
||
dev->CCD.invert = SANE_FALSE;
|
||
#endif
|
||
|
||
dev->TopX =
|
||
MIN ((int)
|
||
(MM_TO_PIXEL (dev->val[OPT_TL_X].w, (float) dev->desc->max_res) +
|
||
0.5), dev->desc->max_h_size);
|
||
dev->TopY =
|
||
MIN ((int)
|
||
(MM_TO_PIXEL (dev->val[OPT_TL_Y].w, (float) dev->desc->max_res) +
|
||
0.5), dev->desc->max_v_size);
|
||
|
||
dev->BottomX =
|
||
MIN ((int)
|
||
(MM_TO_PIXEL (dev->val[OPT_BR_X].w, (float) dev->desc->max_res) +
|
||
0.5), dev->desc->max_h_size);
|
||
dev->BottomY =
|
||
MIN ((int)
|
||
(MM_TO_PIXEL (dev->val[OPT_BR_Y].w, (float) dev->desc->max_res) +
|
||
0.5), dev->desc->max_v_size);
|
||
|
||
dev->params.pixels_per_line = (dev->BottomX - dev->TopX) * dev->CCD.res
|
||
/ dev->desc->max_res;
|
||
|
||
dev->params.bytes_per_line = dev->params.pixels_per_line;
|
||
|
||
switch (dev->CCD.mode)
|
||
{
|
||
|
||
case MUSTEK_PP_MODE_LINEART:
|
||
dev->params.bytes_per_line /= 8;
|
||
|
||
if ((dev->params.pixels_per_line % 8) != 0)
|
||
dev->params.bytes_per_line++;
|
||
|
||
dev->params.depth = 1;
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_GRAYSCALE:
|
||
dev->params.depth = 8;
|
||
dev->params.format = SANE_FRAME_GRAY;
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_COLOR:
|
||
dev->params.depth = 8;
|
||
dev->params.bytes_per_line *= 3;
|
||
dev->params.format = SANE_FRAME_RGB;
|
||
break;
|
||
|
||
}
|
||
|
||
dev->params.last_frame = SANE_TRUE;
|
||
|
||
dev->params.lines = (dev->BottomY - dev->TopY) * dev->CCD.res /
|
||
dev->desc->max_res;
|
||
|
||
DBG (3, "get_parameters: %dx%d pixels\n", dev->params.pixels_per_line,
|
||
dev->params.lines);
|
||
|
||
dev->CCD.skipimagebytes = dev->TopX;
|
||
|
||
ASSERT (dev->params.lines > 0);
|
||
ASSERT (dev->params.pixels_per_line > 0);
|
||
|
||
}
|
||
else
|
||
{
|
||
DBG (2, "get_parameters: can't set parameters while scanning\n");
|
||
DEBUG ();
|
||
}
|
||
|
||
if (params != NULL)
|
||
*params = dev->params;
|
||
|
||
return SANE_STATUS_GOOD;
|
||
|
||
}
|
||
|
||
SANE_Status
|
||
sane_start (SANE_Handle handle)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
|
||
if (dev->state == MUSTEK_PP_STATE_SCANNING)
|
||
{
|
||
DBG (2, "start: device is already scanning\n");
|
||
DEBUG ();
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
|
||
sane_get_parameters (handle, NULL);
|
||
|
||
DBG (3, "start: maybe waiting for lamp...\n");
|
||
/* image quality increases when lamp isn't to cold */
|
||
while ((time (NULL) - dev->lamp_on) < dev->desc->wait_lamp)
|
||
sleep (1);
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_TRUE);
|
||
|
||
if (dev->desc->use600 == SANE_FALSE)
|
||
{
|
||
|
||
config_ccd (dev);
|
||
set_voltages (dev);
|
||
|
||
get_bank_count (dev);
|
||
ASSERT (dev->bank_count == 0);
|
||
|
||
}
|
||
|
||
return_home (dev, SANE_FALSE);
|
||
|
||
dev->motor_step = 0;
|
||
|
||
/* allocating memory for calibration */
|
||
|
||
dev->calib_g = malloc (dev->params.pixels_per_line);
|
||
|
||
if (dev->calib_g == NULL)
|
||
{
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
DBG (2, "start: not enough memory for calibration buffer\n");
|
||
DEBUG ();
|
||
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
{
|
||
|
||
dev->calib_r = malloc (dev->params.pixels_per_line);
|
||
dev->calib_b = malloc (dev->params.pixels_per_line);
|
||
|
||
if ((dev->calib_r == NULL) || (dev->calib_b == NULL))
|
||
{
|
||
free (dev->calib_g);
|
||
if (dev->calib_r)
|
||
free (dev->calib_r);
|
||
if (dev->calib_b)
|
||
free (dev->calib_b);
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
DBG (2, "start: not enough memory for color calib buffer\n");
|
||
DEBUG ();
|
||
|
||
return SANE_STATUS_NO_MEM;
|
||
}
|
||
}
|
||
|
||
DBG (3, "start: executing calibration\n");
|
||
|
||
calibrate (dev);
|
||
|
||
/* line distance correction for color mode */
|
||
if (dev->ccd_type == 1)
|
||
{
|
||
|
||
dev->blue_offs = 4;
|
||
dev->green_offs = 8;
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
dev->blue_offs = 8;
|
||
dev->green_offs = 16;
|
||
|
||
}
|
||
|
||
if (dev->desc->use600)
|
||
{
|
||
|
||
dev->blue_offs = 2;
|
||
dev->green_offs = 4;
|
||
|
||
if (dev->CCD.hwres > 300)
|
||
{
|
||
|
||
dev->blue_offs = 4;
|
||
dev->green_offs = 8;
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
if (dev->desc->use600)
|
||
{
|
||
|
||
dev->motor_ctrl = 0x63;
|
||
|
||
move_motor (dev, /* (dev->CCD.mode == MUSTEK_PP_MODE_COLOR ? */ 136 /* : 95) */
|
||
+ dev->TopY -
|
||
(dev->CCD.mode ==
|
||
MUSTEK_PP_MODE_COLOR ? dev->green_offs : 0), SANE_TRUE);
|
||
|
||
dev->motor_ctrl = 0x43;
|
||
}
|
||
else
|
||
/* musteka4s2 says 56 lines instead of 47 */
|
||
move_motor (dev, 47 + dev->TopY -
|
||
(dev->CCD.mode == MUSTEK_PP_MODE_COLOR ? dev->green_offs : 0),
|
||
SANE_TRUE);
|
||
|
||
if ((dev->ccd_type == 1) && (dev->desc->use600 == SANE_FALSE))
|
||
sanei_pa4s2_writebyte (dev->fd, 6, 0x15);
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
{
|
||
|
||
int failed = SANE_FALSE, cnt;
|
||
|
||
dev->CCD.line_step =
|
||
SANE_FIX ((float) dev->desc->max_res / (float) dev->CCD.res);
|
||
dev->rdiff = dev->CCD.line_step;
|
||
dev->bdiff = dev->rdiff + (dev->blue_offs << SANE_FIXED_SCALE_SHIFT);
|
||
dev->gdiff = dev->rdiff + (dev->green_offs << SANE_FIXED_SCALE_SHIFT);
|
||
|
||
|
||
|
||
dev->red = malloc (sizeof (SANE_Byte *) * dev->green_offs);
|
||
dev->blue = malloc (sizeof (SANE_Byte *) * dev->blue_offs);
|
||
dev->green = malloc (dev->params.pixels_per_line);
|
||
|
||
if ((dev->red == NULL) || (dev->blue == NULL) || (dev->green == NULL))
|
||
{
|
||
|
||
free (dev->calib_r);
|
||
free (dev->calib_b);
|
||
free (dev->calib_g);
|
||
|
||
if (dev->red != NULL)
|
||
free (dev->red);
|
||
if (dev->green != NULL)
|
||
free (dev->green);
|
||
if (dev->blue != NULL)
|
||
free (dev->blue);
|
||
|
||
DBG (2, "start: not enough memory for ld correction buffers\n");
|
||
DEBUG ();
|
||
|
||
return SANE_STATUS_NO_MEM;
|
||
|
||
}
|
||
|
||
for (cnt = 0; cnt < dev->green_offs; cnt++)
|
||
if ((dev->red[cnt] = malloc (dev->params.pixels_per_line)) == NULL)
|
||
failed = SANE_TRUE;
|
||
|
||
for (cnt = 0; cnt < dev->blue_offs; cnt++)
|
||
if ((dev->blue[cnt] = malloc (dev->params.pixels_per_line)) == NULL)
|
||
failed = SANE_TRUE;
|
||
|
||
if (failed == SANE_TRUE)
|
||
{
|
||
|
||
free (dev->calib_r);
|
||
free (dev->calib_b);
|
||
free (dev->calib_g);
|
||
|
||
|
||
for (cnt = 0; cnt < dev->green_offs; cnt++)
|
||
if (dev->red[cnt] != NULL)
|
||
free (dev->red[cnt]);
|
||
for (cnt = 0; cnt < dev->blue_offs; cnt++)
|
||
if (dev->blue[cnt] != NULL)
|
||
free (dev->blue[cnt]);
|
||
|
||
free (dev->red);
|
||
free (dev->green);
|
||
free (dev->blue);
|
||
|
||
DBG (2, "start: not enough memory for ld correction buffers\n");
|
||
DEBUG ();
|
||
|
||
return SANE_STATUS_NO_MEM;
|
||
|
||
}
|
||
|
||
dev->redline = 0;
|
||
dev->blueline = 0;
|
||
dev->ccd_line = 0;
|
||
|
||
}
|
||
|
||
dev->line = 0;
|
||
dev->lines_left = dev->params.lines;
|
||
|
||
dev->state = MUSTEK_PP_STATE_SCANNING;
|
||
|
||
DBG (3, "start: device ready for scanning\n");
|
||
|
||
return SANE_STATUS_GOOD;
|
||
|
||
}
|
||
|
||
|
||
SANE_Status
|
||
sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
|
||
SANE_Int * len)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
long int n, cnt;
|
||
|
||
*len = 0;
|
||
|
||
if ((dev->state != MUSTEK_PP_STATE_SCANNING) ||
|
||
((dev->lines_left == 0) && (dev->buflen == 0)))
|
||
{
|
||
/* device isn't scanning */
|
||
|
||
if (dev->state != MUSTEK_PP_STATE_SCANNING)
|
||
{
|
||
DBG (2, "read: device isn't scanning\n");
|
||
DEBUG ();
|
||
dev->state = MUSTEK_PP_STATE_IDLE;
|
||
return SANE_STATUS_CANCELLED;
|
||
}
|
||
else
|
||
{
|
||
DBG (2, "read: no more image data available\n");
|
||
DEBUG ();
|
||
|
||
DBG (3, "read: finishing scan request using sane_cancel\n");
|
||
|
||
sane_cancel (handle);
|
||
|
||
}
|
||
|
||
return SANE_STATUS_EOF;
|
||
}
|
||
|
||
|
||
if (dev->buflen == 0)
|
||
{
|
||
|
||
/* no image data in scan buffer -> get new */
|
||
|
||
if (dev->max_lines > 0)
|
||
cnt = MIN (dev->bufsize / dev->params.bytes_per_line, dev->max_lines);
|
||
else
|
||
cnt = dev->bufsize / dev->params.bytes_per_line;
|
||
|
||
cnt = MIN (cnt, dev->lines_left);
|
||
|
||
ASSERT (cnt > 0);
|
||
|
||
DBG (3, "read: scanning next %ld lines\n", cnt);
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_TRUE);
|
||
|
||
for (n = 0; n < cnt; n++)
|
||
{
|
||
|
||
switch (dev->CCD.mode)
|
||
{
|
||
|
||
case MUSTEK_PP_MODE_LINEART:
|
||
|
||
get_lineart_line (dev,
|
||
&dev->buf[dev->params.bytes_per_line * n]);
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_GRAYSCALE:
|
||
|
||
get_grayscale_line (dev,
|
||
&dev->buf[dev->params.bytes_per_line * n]);
|
||
break;
|
||
|
||
case MUSTEK_PP_MODE_COLOR:
|
||
|
||
get_color_line (dev, &dev->buf[dev->params.bytes_per_line * n]);
|
||
break;
|
||
|
||
}
|
||
|
||
dev->lines_left--;
|
||
dev->line++;
|
||
|
||
}
|
||
|
||
dev->buflen = cnt * dev->params.bytes_per_line;
|
||
|
||
if (dev->lines_left == 0)
|
||
{
|
||
DBG (3, "read: scan finished\n");
|
||
|
||
return_home (dev, SANE_TRUE);
|
||
|
||
}
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
}
|
||
|
||
/* return requested amount of data from buffer */
|
||
|
||
ASSERT (dev->buflen > 0);
|
||
|
||
memcpy (buf, dev->buf, MIN (max_len, dev->buflen));
|
||
|
||
*len = MIN (max_len, dev->buflen);
|
||
|
||
ASSERT (*len > 0) DBG (3, "read: delivering %d bytes\n", *len);
|
||
|
||
if (*len == dev->buflen)
|
||
dev->buflen = 0;
|
||
else
|
||
{
|
||
dev->buflen -= *len;
|
||
memmove (dev->buf, &dev->buf[*len], dev->buflen);
|
||
}
|
||
|
||
return SANE_STATUS_GOOD;
|
||
|
||
}
|
||
|
||
void
|
||
sane_cancel (SANE_Handle handle)
|
||
{
|
||
Mustek_PP_Device *dev = handle;
|
||
|
||
if (dev->state == MUSTEK_PP_STATE_SCANNING)
|
||
{
|
||
|
||
/* device is scanning: return lamp and free line distance correction
|
||
and calibration buffers
|
||
*/
|
||
|
||
DBG (3, "cancel: stopping current scan\n");
|
||
|
||
sanei_pa4s2_enable (dev->fd, SANE_TRUE);
|
||
return_home (dev, SANE_TRUE);
|
||
sanei_pa4s2_enable (dev->fd, SANE_FALSE);
|
||
|
||
free (dev->calib_g);
|
||
|
||
if (dev->CCD.mode == MUSTEK_PP_MODE_COLOR)
|
||
{
|
||
|
||
int cnt;
|
||
|
||
free (dev->calib_r);
|
||
free (dev->calib_b);
|
||
|
||
for (cnt = 0; cnt < dev->green_offs; cnt++)
|
||
free (dev->red[cnt]);
|
||
for (cnt = 0; cnt < dev->blue_offs; cnt++)
|
||
free (dev->blue[cnt]);
|
||
|
||
free (dev->red);
|
||
free (dev->blue);
|
||
free (dev->green);
|
||
|
||
}
|
||
|
||
dev->buflen = 0;
|
||
|
||
dev->state = MUSTEK_PP_STATE_CANCELLED;
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
DBG (2, "cancel: device isn't scanning\n");
|
||
DEBUG ();
|
||
}
|
||
}
|
||
|
||
SANE_Status
|
||
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
|
||
{
|
||
DBG (129, "unused arg: handle = %p, non_blocking = %d\n",
|
||
handle, (int) non_blocking);
|
||
|
||
DBG (2, "set_io_mode: not supported\n");
|
||
|
||
return SANE_STATUS_UNSUPPORTED;
|
||
}
|
||
|
||
SANE_Status
|
||
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
|
||
{
|
||
|
||
DBG (129, "unused arg: handle = %p, fd = %p\n", handle, fd);
|
||
|
||
DBG (2, "get_select_fd: not supported\n");
|
||
|
||
return SANE_STATUS_UNSUPPORTED;
|
||
}
|