2008-03-22 14:33:36 +00:00
|
|
|
/* sane - Scanner Access Now Easy.
|
|
|
|
|
|
|
|
Copyright (C) 2007-2008 stef.dev@free.fr
|
|
|
|
|
|
|
|
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 contains all the low level functions needed for the higher level
|
|
|
|
* functions of the sane standard. They are put there to keep files smaller
|
|
|
|
* and separate functions with different goals.
|
|
|
|
*/
|
|
|
|
|
2008-05-26 04:48:20 +00:00
|
|
|
#include "../include/sane/config.h"
|
|
|
|
#include "../include/sane/sane.h"
|
|
|
|
#include "../include/sane/sanei_backend.h"
|
|
|
|
#include "../include/sane/sanei_usb.h"
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
#include "rts8891_low.h"
|
|
|
|
|
2008-12-03 20:33:31 +00:00
|
|
|
#define RTS8891_BUILD 12
|
2008-03-22 14:33:36 +00:00
|
|
|
#define RTS8891_MAX_REGISTERS 244
|
|
|
|
|
|
|
|
/* init rts8891 library */
|
|
|
|
static void
|
|
|
|
rts8891_low_init (void)
|
|
|
|
{
|
|
|
|
DBG_INIT ();
|
2008-05-06 20:00:32 +00:00
|
|
|
DBG (DBG_info, "RTS8891 low-level functions, version %d.%d-%d\n",
|
2008-11-26 21:21:31 +00:00
|
|
|
SANE_CURRENT_MAJOR, V_MINOR, RTS8891_BUILD);
|
2008-03-22 14:33:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
/* ASIC specific functions */
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
/* write all registers, taking care of the special 0xaa value which
|
|
|
|
* must be escaped with a zero
|
|
|
|
*/
|
|
|
|
static SANE_Status
|
|
|
|
rts8891_write_all (SANE_Int devnum, SANE_Byte * regs, SANE_Int count)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Byte local_regs[RTS8891_MAX_REGISTERS];
|
|
|
|
size_t size = 0;
|
|
|
|
SANE_Byte buffer[260];
|
|
|
|
unsigned int i, j;
|
|
|
|
char message[256 * 5];
|
|
|
|
|
|
|
|
if (DBG_LEVEL > DBG_io)
|
|
|
|
{
|
|
|
|
for (i = 0; i < (unsigned int) count; i++)
|
|
|
|
{
|
|
|
|
if (i != 0xb3)
|
|
|
|
sprintf (message + 5 * i, "0x%02x ", regs[i]);
|
|
|
|
else
|
|
|
|
sprintf (message + 5 * i, "---- ");
|
|
|
|
}
|
|
|
|
DBG (DBG_io, "rts8891_write_all : write_all(0x00,%d)=%s\n", count,
|
|
|
|
message);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy register set and escaping 0xaa values */
|
|
|
|
/* b0, b1 abd b3 values may be scribled, but that isn't important */
|
|
|
|
/* since they are read-only registers */
|
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < 0xb3; i++)
|
|
|
|
{
|
|
|
|
local_regs[j] = regs[i];
|
|
|
|
if (local_regs[j] == 0xaa && i < 0xb3)
|
|
|
|
{
|
|
|
|
j++;
|
|
|
|
local_regs[j] = 0x00;
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
buffer[0] = 0x88;
|
|
|
|
buffer[1] = 0;
|
|
|
|
buffer[2] = 0x00;
|
|
|
|
buffer[3] = 0xb3;
|
|
|
|
for (i = 0; i < j; i++)
|
|
|
|
buffer[i + 4] = local_regs[i];
|
|
|
|
/* the USB block is size + 4 bytes of header long */
|
|
|
|
size = j + 4;
|
|
|
|
if (sanei_usb_write_bulk (devnum, buffer, &size) != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"rts88xx_write_all : write registers part 1 failed ...\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = count - 0xb4; /* we need to substract one reg since b3 won't be written */
|
|
|
|
buffer[0] = 0x88;
|
|
|
|
buffer[1] = 0xb4;
|
|
|
|
buffer[2] = 0x00;
|
|
|
|
buffer[3] = size;
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
buffer[i + 4] = regs[0xb4 + i];
|
|
|
|
/* the USB block is size + 4 bytes of header long */
|
|
|
|
size += 4;
|
|
|
|
if (sanei_usb_write_bulk (devnum, buffer, &size) != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"rts88xx_write_all : write registers part 2 failed ...\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* this functions "commits" pending scan command */
|
|
|
|
static SANE_Status
|
|
|
|
rts8891_commit (SANE_Int devnum, SANE_Byte value)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Byte reg;
|
|
|
|
|
|
|
|
reg = value;
|
|
|
|
status = sanei_rts88xx_write_reg (devnum, 0xd3, ®);
|
|
|
|
status = sanei_rts88xx_cancel (devnum);
|
|
|
|
status = sanei_rts88xx_write_control (devnum, 0x08);
|
|
|
|
status = sanei_rts88xx_write_control (devnum, 0x08);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this functions reads button status */
|
|
|
|
static SANE_Status
|
|
|
|
rts8891_read_buttons (SANE_Int devnum, SANE_Int * mask)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Byte reg;
|
|
|
|
|
|
|
|
/* check CONTROL_REG */
|
|
|
|
sanei_rts88xx_read_reg (devnum, CONTROL_REG, ®);
|
|
|
|
|
|
|
|
/* read 'base' button status */
|
|
|
|
sanei_rts88xx_read_reg (devnum, 0x25, ®);
|
|
|
|
DBG (DBG_io, "rts8891_read_buttons: r25=0x%02x\n", reg);
|
|
|
|
*mask |= reg;
|
|
|
|
|
|
|
|
/* read 'extended' button status */
|
|
|
|
sanei_rts88xx_read_reg (devnum, 0x1a, ®);
|
|
|
|
DBG (DBG_io, "rts8891_read_buttons: r1a=0x%02x\n", reg);
|
|
|
|
*mask |= reg << 8;
|
|
|
|
|
|
|
|
/* clear register r25 */
|
|
|
|
reg = 0x00;
|
|
|
|
status = sanei_rts88xx_write_reg (devnum, 0x25, ®);
|
|
|
|
|
|
|
|
/* clear register r1a */
|
|
|
|
sanei_rts88xx_read_reg (devnum, 0x1a, ®);
|
|
|
|
reg = 0x00;
|
|
|
|
status = sanei_rts88xx_write_reg (devnum, 0x1a, ®);
|
|
|
|
|
|
|
|
DBG (DBG_info, "rts8891_read_buttons: mask=0x%04x\n", *mask);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Does a simple scan based on the given register set, returning data in a
|
|
|
|
* preallocated buffer of the claimed size.
|
|
|
|
* sanei_rts88xx_data_count cannot be made reliable, when the announced data
|
|
|
|
* amount is read, it may no be ready, leading to errors. To work around
|
|
|
|
* it, we read data count one more time before reading.
|
|
|
|
*/
|
|
|
|
static SANE_Status
|
|
|
|
rts8891_simple_scan (SANE_Int devnum, SANE_Byte * regs, int regcount,
|
|
|
|
SANE_Int format, SANE_Word total, unsigned char *image)
|
|
|
|
{
|
|
|
|
SANE_Word count, read, len, dummy;
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Byte control;
|
|
|
|
|
|
|
|
rts8891_write_all (devnum, regs, regcount);
|
|
|
|
rts8891_commit (devnum, format);
|
|
|
|
|
|
|
|
read = 0;
|
|
|
|
count = 0;
|
|
|
|
while (count == 0)
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_data_count (devnum, &count);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "simple_scan: failed to wait for data\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_read_reg (devnum, CONTROL_REG, &control);
|
|
|
|
if (((control & 0x08) == 0) || (status != SANE_STATUS_GOOD))
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "simple_scan: failed to wait for data\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* data reading */
|
|
|
|
read = 0;
|
|
|
|
while ((read < total) && (count != 0 || (control & 0x08) == 0x08))
|
|
|
|
{
|
|
|
|
/* sync ? */
|
|
|
|
status = sanei_rts88xx_data_count (devnum, &dummy);
|
|
|
|
|
|
|
|
/* read */
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
len = count;
|
|
|
|
/* read even size unless last chunk */
|
|
|
|
if ((len & 1) && (read + len < total))
|
|
|
|
{
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
if (len > RTS88XX_MAX_XFER_SIZE)
|
|
|
|
{
|
|
|
|
len = RTS88XX_MAX_XFER_SIZE;
|
|
|
|
}
|
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_read_data (devnum, &len, image + read);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"simple_scan: failed to read from scanner\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
read += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* don't try to read data count if we have enough data */
|
|
|
|
if (read < total)
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_data_count (devnum, &count);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (devnum, CONTROL_REG, &control);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (read < total)
|
|
|
|
{
|
|
|
|
DBG (DBG_io2, "simple_scan: ERROR, %d bytes missing ... \n",
|
|
|
|
total - read);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for the motor to stop */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (devnum, CONTROL_REG, &control);
|
|
|
|
}
|
|
|
|
while ((control & 0x08) == 0x08);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-12-03 20:33:31 +00:00
|
|
|
* set the data format. Is part of the commit sequence. Then returned
|
|
|
|
* value is the value used in d3 register for a scan.
|
2008-03-22 14:33:36 +00:00
|
|
|
*/
|
|
|
|
static SANE_Int
|
2008-12-03 20:33:31 +00:00
|
|
|
rts8891_data_format (SANE_Int dpi, int sensor)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
|
|
|
SANE_Byte reg = 0x00;
|
|
|
|
|
2008-12-03 20:33:31 +00:00
|
|
|
/* it seems that lower nibble is a divisor */
|
|
|
|
if (sensor == SENSOR_TYPE_BARE || sensor == SENSOR_TYPE_XPA)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
2008-12-03 20:33:31 +00:00
|
|
|
switch (dpi)
|
|
|
|
{
|
|
|
|
case 75:
|
|
|
|
reg = 0x02;
|
|
|
|
break;
|
|
|
|
case 150:
|
|
|
|
if (sensor == SENSOR_TYPE_BARE)
|
|
|
|
reg = 0x0e;
|
|
|
|
else
|
|
|
|
reg = 0x0b;
|
|
|
|
break;
|
|
|
|
case 300:
|
|
|
|
reg = 0x17;
|
|
|
|
break;
|
|
|
|
case 600:
|
|
|
|
if (sensor == SENSOR_TYPE_BARE)
|
|
|
|
reg = 0x02;
|
|
|
|
else
|
|
|
|
reg = 0x0e;
|
|
|
|
break;
|
|
|
|
case 1200:
|
|
|
|
if (sensor == SENSOR_TYPE_BARE)
|
|
|
|
reg = 0x17;
|
|
|
|
else
|
|
|
|
reg = 0x05;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sensor == SENSOR_TYPE_4400 || sensor == SENSOR_TYPE_4400_BARE)
|
|
|
|
{
|
|
|
|
switch (dpi)
|
|
|
|
{
|
|
|
|
case 75:
|
|
|
|
reg = 0x02;
|
|
|
|
break;
|
|
|
|
case 150:
|
|
|
|
if (sensor == SENSOR_TYPE_4400)
|
|
|
|
reg = 0x0b;
|
|
|
|
else
|
|
|
|
reg = 0x17;
|
|
|
|
break;
|
|
|
|
case 300:
|
|
|
|
reg = 0x17;
|
|
|
|
break;
|
|
|
|
case 600:
|
|
|
|
if (sensor == SENSOR_TYPE_4400)
|
|
|
|
reg = 0x0e;
|
|
|
|
else
|
|
|
|
reg = 0x02;
|
|
|
|
break;
|
|
|
|
case 1200:
|
|
|
|
if (sensor == SENSOR_TYPE_4400)
|
|
|
|
reg = 0x05;
|
|
|
|
else
|
|
|
|
reg = 0x17;
|
|
|
|
break;
|
|
|
|
}
|
2008-03-22 14:33:36 +00:00
|
|
|
}
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-09-20 07:00:10 +00:00
|
|
|
* set up default values for a 75xdpi, 150 ydpi scan
|
2008-03-22 14:33:36 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
rts8891_set_default_regs (SANE_Byte * scanner_regs)
|
|
|
|
{
|
|
|
|
SANE_Byte default_75[RTS8891_MAX_REGISTERS] =
|
|
|
|
{ 0xe5, 0x41, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x0a, 0x0a, 0x0a, 0x70,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x28, 0x3f, 0xff, 0x20, 0xf8, 0x28, 0x07, 0x00,
|
|
|
|
0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
|
|
|
|
0x00, 0x3a, 0xf2, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x8c,
|
|
|
|
0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x14, 0x18, 0x15, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0xff, 0x3f, 0x80, 0x68, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc,
|
|
|
|
0x27, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00,
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
|
|
|
0x0e, 0x00, 0x00, 0xf0, 0xff, 0xf5, 0xf7, 0xea, 0x0b, 0x03, 0x05, 0x86,
|
|
|
|
0x1b, 0x30, 0xf6, 0xa2, 0x27, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < RTS8891_MAX_REGISTERS; i++)
|
|
|
|
scanner_regs[i] = default_75[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
static SANE_Status
|
2008-09-20 07:00:10 +00:00
|
|
|
rts8891_move (struct Rts8891_Device *device, SANE_Byte * regs,
|
|
|
|
SANE_Int distance, SANE_Bool forward)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
2008-12-03 20:33:31 +00:00
|
|
|
SANE_Byte regs10, regs11;
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
DBG (DBG_proc, "rts8891_move: start\n");
|
2008-09-20 07:00:10 +00:00
|
|
|
DBG (DBG_io, "rts8891_move: %d lines %s, sensor=%d\n", distance,
|
2008-12-03 20:33:31 +00:00
|
|
|
forward == SANE_TRUE ? "forward" : "backward", device->sensor);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
/* prepare scan */
|
|
|
|
rts8891_set_default_regs (regs);
|
2008-12-03 20:33:31 +00:00
|
|
|
if (device->sensor != SENSOR_TYPE_4400
|
|
|
|
&& device->sensor != SENSOR_TYPE_4400_BARE)
|
2008-09-20 07:00:10 +00:00
|
|
|
{
|
2008-09-26 04:47:54 +00:00
|
|
|
regs10 = 0x20;
|
|
|
|
regs11 = 0x28;
|
2008-09-20 07:00:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-26 04:47:54 +00:00
|
|
|
regs10 = 0x10;
|
|
|
|
regs11 = 0x2a;
|
2008-09-20 07:00:10 +00:00
|
|
|
}
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
regs[0x32] = 0x80;
|
|
|
|
regs[0x33] = 0x81;
|
|
|
|
regs[0x35] = 0x10;
|
|
|
|
regs[0x36] = 0x24;
|
|
|
|
regs[0x39] = 0x02;
|
|
|
|
regs[0x3a] = 0x0e;
|
|
|
|
|
|
|
|
regs[0x64] = 0x01;
|
|
|
|
regs[0x65] = 0x20;
|
|
|
|
|
|
|
|
regs[0x79] = 0x20;
|
|
|
|
regs[0x7a] = 0x01;
|
|
|
|
|
|
|
|
regs[0x80] = 0x32;
|
|
|
|
regs[0x82] = 0x33;
|
|
|
|
regs[0x85] = 0x46;
|
|
|
|
regs[0x86] = 0x0b;
|
|
|
|
regs[0x87] = 0x8c;
|
|
|
|
regs[0x88] = 0x10;
|
|
|
|
regs[0x89] = 0xb2;
|
|
|
|
regs[0x8d] = 0x3b;
|
|
|
|
regs[0x8e] = 0x60;
|
|
|
|
|
|
|
|
regs[0x90] = 0x1c;
|
|
|
|
regs[0xb2] = 0x16; /* 0x10 : stop when at home, 0x04: no data */
|
|
|
|
regs[0xc0] = 0x00;
|
|
|
|
regs[0xc1] = 0x00;
|
|
|
|
regs[0xc3] = 0x00;
|
|
|
|
regs[0xc4] = 0x00;
|
|
|
|
regs[0xc5] = 0x00;
|
|
|
|
regs[0xc6] = 0x00;
|
|
|
|
regs[0xc7] = 0x00;
|
|
|
|
regs[0xc8] = 0x00;
|
|
|
|
regs[0xca] = 0x00;
|
|
|
|
regs[0xcd] = 0x00;
|
|
|
|
regs[0xce] = 0x00;
|
|
|
|
regs[0xcf] = 0x00;
|
|
|
|
regs[0xd0] = 0x00;
|
|
|
|
regs[0xd1] = 0x00;
|
|
|
|
regs[0xd2] = 0x00;
|
|
|
|
regs[0xd3] = 0x00;
|
|
|
|
regs[0xd4] = 0x00;
|
|
|
|
regs[0xd6] = 0x6b;
|
|
|
|
regs[0xd7] = 0x00;
|
|
|
|
regs[0xd8] = 0x00;
|
|
|
|
regs[0xd9] = 0xad;
|
|
|
|
regs[0xda] = 0xa7;
|
|
|
|
regs[0xe2] = 0x17;
|
|
|
|
regs[0xe3] = 0x0d;
|
|
|
|
regs[0xe4] = 0x06;
|
|
|
|
regs[0xe5] = 0xf9;
|
|
|
|
regs[0xe7] = 0x53;
|
|
|
|
regs[0xe8] = 0x02;
|
|
|
|
regs[0xe9] = 0x02;
|
|
|
|
|
2008-09-26 04:47:54 +00:00
|
|
|
/* hp4400 sensors */
|
2008-12-03 20:33:31 +00:00
|
|
|
if (device->sensor == SENSOR_TYPE_4400
|
|
|
|
|| device->sensor == SENSOR_TYPE_4400_BARE)
|
2008-09-11 04:38:19 +00:00
|
|
|
{
|
2008-09-26 04:47:54 +00:00
|
|
|
regs[0x13] = 0x39; /* 0x20 */
|
|
|
|
regs[0x14] = 0xf0; /* 0xf8 */
|
|
|
|
regs[0x15] = 0x29; /* 0x28 */
|
|
|
|
regs[0x16] = 0x0f; /* 0x07 */
|
|
|
|
regs[0x17] = 0x10; /* 0x00 */
|
|
|
|
regs[0x23] = 0x00; /* 0xff */
|
|
|
|
regs[0x35] = 0x29; /* 0x10 */
|
|
|
|
regs[0x36] = 0x21; /* 0x24 */
|
|
|
|
regs[0x39] = 0x00; /* 0x02 */
|
|
|
|
regs[0x80] = 0xb0; /* 0x32 */
|
|
|
|
regs[0x82] = 0xb1; /* 0x33 */
|
|
|
|
regs[0xe2] = 0x0b; /* 0x17 */
|
|
|
|
regs[0xe5] = 0xf3; /* 0xf9 */
|
|
|
|
regs[0xe6] = 0x01; /* 0x00 */
|
2008-09-11 04:38:19 +00:00
|
|
|
}
|
|
|
|
|
2008-03-22 14:33:36 +00:00
|
|
|
/* disable CCD */
|
|
|
|
regs[0] = 0xf5;
|
|
|
|
|
2008-09-26 04:47:54 +00:00
|
|
|
sanei_rts88xx_set_status (device->devnum, regs, regs10, regs11);
|
2008-03-22 14:33:36 +00:00
|
|
|
sanei_rts88xx_set_scan_area (regs, distance, distance + 1, 100, 200);
|
|
|
|
sanei_rts88xx_set_gain (regs, 16, 16, 16);
|
|
|
|
sanei_rts88xx_set_offset (regs, 127, 127, 127);
|
|
|
|
|
|
|
|
/* forward/backward */
|
|
|
|
/* 0x2c is forward, 0x24 backward */
|
|
|
|
if (forward == SANE_TRUE)
|
|
|
|
{ /* forward */
|
|
|
|
regs[0x36] = regs[0x36] | 0x08;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* backward */
|
|
|
|
regs[0x36] = regs[0x36] & 0xf7;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write regiters values */
|
2008-09-11 04:38:19 +00:00
|
|
|
status = rts8891_write_all (device->devnum, regs, RTS8891_MAX_REGISTERS);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
/* commit it */
|
2008-09-11 04:38:19 +00:00
|
|
|
rts8891_commit (device->devnum, 0x00);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* move the head backward by a huge line number then poll home sensor until
|
|
|
|
* head has get back home. We have our own copy of the registers to avoid
|
|
|
|
* messing scanner status
|
|
|
|
*/
|
|
|
|
static SANE_Status
|
2008-09-11 04:38:19 +00:00
|
|
|
rts8891_park (struct Rts8891_Device *device, SANE_Byte * regs)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Byte motor, sensor, reg;
|
|
|
|
|
|
|
|
DBG (DBG_proc, "rts8891_park: start\n");
|
|
|
|
|
2008-09-11 04:38:19 +00:00
|
|
|
rts8891_move (device, regs, 8000, SANE_FALSE);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
/* wait for controller home bit to raise, no timeout */
|
|
|
|
/* at each loop we check that motor is on, then that the sensor bit it cleared */
|
|
|
|
do
|
|
|
|
{
|
2008-09-11 04:38:19 +00:00
|
|
|
sanei_rts88xx_read_reg (device->devnum, CONTROL_REG, &motor);
|
|
|
|
sanei_rts88xx_read_reg (device->devnum, CONTROLER_REG, &sensor);
|
2008-03-22 14:33:36 +00:00
|
|
|
}
|
|
|
|
while ((motor & 0x08) && ((sensor & 0x02) == 0));
|
|
|
|
|
|
|
|
/* check for error */
|
|
|
|
if (((motor & 0x08) == 0x00) && ((sensor & 0x02) == 0))
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"rts8891_park: error, motor stopped before head parked\n");
|
|
|
|
status = SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* re-enable CCD */
|
|
|
|
regs[0] = regs[0] & 0xef;
|
|
|
|
|
2008-09-11 04:38:19 +00:00
|
|
|
sanei_rts88xx_cancel (device->devnum);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
/* reset ? so we don't need to read data */
|
|
|
|
reg = 0;
|
|
|
|
/* b7: movement on/off, b3-b0 : movement divisor */
|
2008-09-11 04:38:19 +00:00
|
|
|
sanei_rts88xx_write_reg (device->devnum, 0x33, ®);
|
|
|
|
sanei_rts88xx_write_reg (device->devnum, 0x33, ®);
|
2008-03-22 14:33:36 +00:00
|
|
|
/* movement direction */
|
2008-09-11 04:38:19 +00:00
|
|
|
sanei_rts88xx_write_reg (device->devnum, 0x36, ®);
|
|
|
|
sanei_rts88xx_cancel (device->devnum);
|
2008-03-22 14:33:36 +00:00
|
|
|
|
|
|
|
DBG (DBG_proc, "rts8891_park: end\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* reads data from scanner.
|
|
|
|
* First we wait for some data to be available and then loop reading
|
|
|
|
* from scanner until the required amount is reached.
|
|
|
|
* We handle non blocking I/O by returning immediatly (with SANE_STATUS_BUSY)
|
|
|
|
* if there is no data available from scanner. But once read is started,
|
|
|
|
* all the required amount is read. Once wait for data succeeded, we still poll
|
|
|
|
* for data in order no to read it too fast, but we don' take care of non blocking
|
|
|
|
* mode since we cope with it on first data wait.
|
|
|
|
*/
|
|
|
|
static SANE_Status
|
2008-05-26 04:48:20 +00:00
|
|
|
read_data (struct Rts8891_Session *session, SANE_Byte * dest, SANE_Int length)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Int count, read, len, dummy;
|
2008-05-26 04:48:20 +00:00
|
|
|
struct Rts8891_Device *dev = session->dev;
|
2008-03-22 14:33:36 +00:00
|
|
|
static FILE *raw = NULL; /* for debugging purpose we need it static */
|
|
|
|
SANE_Byte control = 0x08;
|
|
|
|
unsigned char buffer[RTS88XX_MAX_XFER_SIZE];
|
|
|
|
|
|
|
|
DBG (DBG_proc, "read_data: start\n");
|
|
|
|
DBG (DBG_proc, "read_data: requiring %d bytes\n", length);
|
|
|
|
|
|
|
|
/* wait for data being available and handle non blocking mode */
|
|
|
|
/* only when data reading hasn't produce any data yet */
|
|
|
|
if (dev->read == 0)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_data_count (dev->devnum, &count);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "read_data: failed to wait for data\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
|
|
|
|
if ((control & 0x08) == 0 && (count == 0))
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"read_data: scanner stopped being busy before data are available\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in case there is no data, we return BUSY since this mean */
|
|
|
|
/* that scanning head hasn't reach is position and data hasn't */
|
|
|
|
/* come yet */
|
2008-05-26 04:48:20 +00:00
|
|
|
if (session->non_blocking && count == 0)
|
2008-03-22 14:33:36 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
dev->regs[LAMP_REG] = 0x8d;
|
|
|
|
sanei_rts88xx_write_reg (dev->devnum, LAMP_REG,
|
|
|
|
&(dev->regs[LAMP_REG]));
|
|
|
|
DBG (DBG_io, "read_data: no data vailable\n");
|
|
|
|
DBG (DBG_proc, "read_data: end\n");
|
|
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (count == 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* start of read for a new block */
|
|
|
|
status = sanei_rts88xx_data_count (dev->devnum, &count);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "read_data: failed to wait for data\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
|
|
|
|
if ((control & 0x08) == 0 && (count == 0))
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"read_data: scanner stopped being busy before data are available\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill scanned data buffer */
|
|
|
|
read = 0;
|
|
|
|
|
|
|
|
/* now loop reading data until we have the amount requested */
|
|
|
|
/* we also take care of not reading too much data */
|
|
|
|
while (read < length && dev->read < dev->to_read
|
|
|
|
&& ((control & 0x08) == 0x08))
|
|
|
|
{
|
|
|
|
/* used to sync */
|
|
|
|
if (dev->read == 0)
|
|
|
|
{
|
|
|
|
status = sanei_rts88xx_data_count (dev->devnum, &dummy);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "read_data: failed to read data count\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if there is data to read, read it */
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
len = count;
|
|
|
|
|
|
|
|
if (len > RTS88XX_MAX_XFER_SIZE)
|
|
|
|
{
|
|
|
|
len = RTS88XX_MAX_XFER_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we only read even size blocks of data */
|
|
|
|
if (len & 1)
|
|
|
|
{
|
|
|
|
DBG (DBG_io, "read_data: round to next even number\n");
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > length - read)
|
|
|
|
{
|
|
|
|
len = length - read;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = sanei_rts88xx_read_data (dev->devnum, &len, dest + read);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "read_data: failed to read from scanner\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* raw data tracing */
|
|
|
|
if (DBG_LEVEL >= DBG_io2)
|
|
|
|
{
|
|
|
|
/* open a new file only when no data scanned */
|
|
|
|
if (dev->read == 0)
|
|
|
|
{
|
|
|
|
raw = fopen ("raw_data.pnm", "wb");
|
|
|
|
if (raw != NULL)
|
|
|
|
{
|
|
|
|
/* PNM header */
|
|
|
|
fprintf (raw, "P%c\n%d %d\n255\n",
|
2008-05-26 04:48:20 +00:00
|
|
|
session->params.format ==
|
2008-03-22 14:33:36 +00:00
|
|
|
SANE_FRAME_RGB
|
2008-05-26 04:48:20 +00:00
|
|
|
|| session->emulated_gray ==
|
2008-03-22 14:33:36 +00:00
|
|
|
SANE_TRUE ? '6' : '5', dev->pixels,
|
|
|
|
dev->lines);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (raw != NULL)
|
|
|
|
{
|
|
|
|
fwrite (dest + read, 1, len, raw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* move pointer and counter */
|
|
|
|
read += len;
|
|
|
|
dev->read += len;
|
|
|
|
DBG (DBG_io2, "read_data: %d/%d\n", dev->read, dev->to_read);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in fast scan mode, read data count
|
|
|
|
* in slow scan, head moves by the amount of data read */
|
|
|
|
status = sanei_rts88xx_data_count (dev->devnum, &count);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
DBG (DBG_error, "read_data: failed to read data count\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if no data, check if still scanning */
|
|
|
|
if (count == 0 && dev->read < dev->to_read)
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
|
|
|
|
if ((control & 0x08) == 0x00)
|
|
|
|
{
|
|
|
|
DBG (DBG_error,
|
|
|
|
"read_data: scanner stopped being busy before data are available\n");
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* end of physical reads */
|
|
|
|
if (dev->read >= dev->to_read)
|
|
|
|
{
|
|
|
|
/* check there is no more data in case of a bug */
|
|
|
|
sanei_rts88xx_data_count (dev->devnum, &count);
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
DBG (DBG_warn,
|
|
|
|
"read_data: %d bytes are still available from scanner\n",
|
|
|
|
count);
|
|
|
|
|
|
|
|
/* flush left-over data */
|
|
|
|
while (count > 0)
|
|
|
|
{
|
|
|
|
len = count;
|
|
|
|
if (len > RTS88XX_MAX_XFER_SIZE)
|
|
|
|
{
|
|
|
|
len = RTS88XX_MAX_XFER_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we only read even size blocks of data */
|
|
|
|
if (len & 1)
|
|
|
|
{
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
sanei_rts88xx_read_data (dev->devnum, &len, buffer);
|
|
|
|
sanei_rts88xx_data_count (dev->devnum, &count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for motor to stop at the end of the scan */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
|
|
|
|
}
|
|
|
|
while ((control & 0x08) != 0);
|
|
|
|
|
|
|
|
/* close log file if needed */
|
|
|
|
if (DBG_LEVEL >= DBG_io2)
|
|
|
|
{
|
|
|
|
if (raw != NULL)
|
|
|
|
{
|
|
|
|
fclose (raw);
|
|
|
|
raw = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG (DBG_io, "read_data: read %d bytes from scanner\n", length);
|
|
|
|
DBG (DBG_proc, "read_data: end\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set scanner idle before leaving xxx_quiet()
|
|
|
|
write_reg(0x33,1)=0x00
|
|
|
|
write_reg(0x33,1)=0x00
|
|
|
|
write_reg(0x36,1)=0x00
|
|
|
|
prepare();
|
|
|
|
------
|
|
|
|
write_reg(LAMP_REG,1)=0x80
|
|
|
|
write_reg(LAMP_REG,1)=0xad
|
|
|
|
read_reg(0x14,2)=0xf8 0x28
|
|
|
|
write_reg(0x14,2)=0x78 0x28
|
|
|
|
get_status()=0x20 0x3f
|
|
|
|
read_reg(0xb1,1)=0x00
|
|
|
|
read_control()=0x00
|
|
|
|
reset_lamp()=(0x20,0x3f)
|
|
|
|
write_reg(LAMP_REG,1)=0x8d
|
|
|
|
write_reg(LAMP_REG,1)=0xad
|
|
|
|
*/
|