kopia lustrzana https://gitlab.com/sane-project/backends
1084 wiersze
27 KiB
C
1084 wiersze
27 KiB
C
/* sane - Scanner Access Now Easy.
|
|
Copyright (C) 2003 James Perry
|
|
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 the Mustek SCSI-over-parallel port protocol
|
|
used by, for example, the Paragon 600 II EP
|
|
*/
|
|
|
|
|
|
/**************************************************************************/
|
|
#include "../include/sane/config.h"
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/timeb.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/sanei.h"
|
|
#include "../include/sane/saneopts.h"
|
|
#include "../include/sane/sanei_debug.h"
|
|
#include "../include/sane/sanei_pa4s2.h"
|
|
|
|
/*
|
|
* Number of times to retry sending a SCSI command before giving up
|
|
*/
|
|
#define MUSTEK_SCSI_PP_NUM_RETRIES 4
|
|
|
|
/*
|
|
* Internal middle-level API functionality
|
|
*/
|
|
static int mustek_scsi_pp_timeout = 5000;
|
|
|
|
/* FIXME: use same method as mustek.c ? */
|
|
static int
|
|
mustek_scsi_pp_get_time ()
|
|
{
|
|
struct timeb tp;
|
|
int retval;
|
|
|
|
ftime (&tp);
|
|
retval = tp.time * 1000 + tp.millitm;
|
|
return retval;
|
|
}
|
|
|
|
static u_char mustek_scsi_pp_register = 0;
|
|
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_select_register (int fd, u_char reg)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_select_register: selecting register %d on fd %d\n",
|
|
reg, fd);
|
|
|
|
mustek_scsi_pp_register = reg;
|
|
|
|
return sanei_pa4s2_scsi_pp_reg_select (fd, reg);
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_valid_status (int fd)
|
|
{
|
|
int start_time;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_valid_status: entering\n");
|
|
|
|
start_time = mustek_scsi_pp_get_time ();
|
|
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_wait_for_valid_status: I/O error while getting status\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
status &= 0xf0;
|
|
|
|
if ((status != 0xf0) && (!(status & 0x40)) && (status & 0x20))
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_valid_status: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - start_time) < mustek_scsi_pp_timeout);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_valid_status: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_5_set (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_5_set: entering\n");
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_5_set: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (status & 0x20)
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_5_set: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_5_set: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_5_clear (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_5_clear: entering\n");
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_5_clear: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (!(status & 0x20))
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_5_clear: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_5_clear: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_7_set (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_7_set: entering\n");
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_7_set: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (status & 0x80)
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_7_set: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_7_set: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_7_clear (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_7_clear: entering\n");
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_7_clear: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (!(status & 0x80))
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_7_clear: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_7_clear: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_4_set (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_4_set: entering\n");
|
|
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_set: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (status & 0x10)
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_set: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_set: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (status & 0x40)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_set: bit 6 set\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (status & 0x10)
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_set: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_set: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_4_clear (int fd)
|
|
{
|
|
int t;
|
|
u_char status;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_4_clear: entering\n");
|
|
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_clear: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (!(status & 0x10))
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_clear: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
t = mustek_scsi_pp_get_time ();
|
|
do
|
|
{
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_clear: I/O error\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (status & 0x40)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_clear: bit 6 set\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (!(status & 0x10))
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_clear: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
while ((mustek_scsi_pp_get_time () - t) < mustek_scsi_pp_timeout);
|
|
|
|
DBG (2, "mustek_scsi_pp_wait_for_status_bit_4_clear: timed out\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
static u_char mustek_scsi_pp_bit_4_state = 0;
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_wait_for_status_bit_4_toggle (int fd)
|
|
{
|
|
SANE_Status result;
|
|
|
|
DBG (5, "mustek_scsi_pp_wait_for_status_bit_4_toggle: entering\n");
|
|
|
|
mustek_scsi_pp_bit_4_state ^= 0xff;
|
|
if (mustek_scsi_pp_bit_4_state)
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_toggle: waiting for set\n");
|
|
result = mustek_scsi_pp_wait_for_status_bit_4_set (fd);
|
|
mustek_scsi_pp_timeout = 5000;
|
|
}
|
|
else
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_wait_for_status_bit_4_toggle: waiting for clear\n");
|
|
result = mustek_scsi_pp_wait_for_status_bit_4_clear (fd);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_send_command_byte (int fd, u_char cmd)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_send_command byte: sending 0x%02X\n", cmd);
|
|
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_7_clear (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (sanei_pa4s2_writebyte (fd, mustek_scsi_pp_register, cmd) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
mustek_scsi_pp_select_register (fd, 1);
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_7_set (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
|
|
DBG (5, "mustek_scsi_pp_send_command_byte: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static u_char
|
|
mustek_scsi_pp_read_response (int fd)
|
|
{
|
|
u_char result;
|
|
|
|
DBG (5, "mustek_scsi_pp_read_response: entering\n");
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_7_set (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
return 0xff;
|
|
}
|
|
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) != SANE_STATUS_GOOD)
|
|
{
|
|
return 0xff;
|
|
}
|
|
if (sanei_pa4s2_readbyte (fd, &result) != SANE_STATUS_GOOD)
|
|
{
|
|
return 0xff;
|
|
}
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
return 0xff;
|
|
}
|
|
|
|
mustek_scsi_pp_select_register (fd, 1);
|
|
if (mustek_scsi_pp_wait_for_status_bit_7_clear (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
result = 0xff;
|
|
}
|
|
mustek_scsi_pp_select_register (fd, 0);
|
|
|
|
DBG (5, "mustek_scsi_pp_read_response: returning 0x%02X\n", result);
|
|
return result;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_check_response (int fd)
|
|
{
|
|
if (mustek_scsi_pp_wait_for_status_bit_5_clear (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (mustek_scsi_pp_read_response (fd) != 0xA5)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_check_response: response!=0xA5\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
DBG (5, "mustek_scsi_pp_check_response: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_send_command (int fd, const u_char * cmd)
|
|
{
|
|
int i;
|
|
signed char checksum;
|
|
|
|
DBG (5, "mustek_scsi_pp_send_command: sending SCSI command 0x%02X\n",
|
|
cmd[0]);
|
|
|
|
/* Set timeout depending on command type */
|
|
switch (cmd[0])
|
|
{
|
|
case 0xf:
|
|
case 0x8:
|
|
mustek_scsi_pp_timeout = 1000;
|
|
break;
|
|
case 0x2:
|
|
mustek_scsi_pp_timeout = 80;
|
|
break;
|
|
case 0x12:
|
|
case 0x3:
|
|
case 0x11:
|
|
mustek_scsi_pp_timeout = 500;
|
|
break;
|
|
default:
|
|
mustek_scsi_pp_timeout = 1000;
|
|
break;
|
|
}
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_5_set (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_command: timed out waiting for bit 5 to set\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
checksum = 0;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (mustek_scsi_pp_send_command_byte (fd, cmd[i]) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_command: error sending byte %d (0x%02X)\n",
|
|
i, cmd[i]);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
checksum += cmd[i];
|
|
}
|
|
if (mustek_scsi_pp_send_command_byte (fd, -checksum) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_command: error sending checksum (0x%02X)\n",
|
|
-checksum);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
return mustek_scsi_pp_check_response (fd);
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_send_data_block (int fd, const u_char * data, int len)
|
|
{
|
|
int i;
|
|
signed char checksum;
|
|
|
|
DBG (5, "mustek_scsi_pp_send_data_block: sending block of length %d\n",
|
|
len);
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_5_set (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_data_block: timed out waiting for bit 5 to set\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
checksum = 0;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (mustek_scsi_pp_send_command_byte (fd, data[i]) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_data_block: error sending byte %d (0x%02X)\n",
|
|
i, data[i]);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
checksum += data[i];
|
|
}
|
|
if (mustek_scsi_pp_send_command_byte (fd, -checksum) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_send_data_block: error sending checksum (0x%02X)\n",
|
|
-checksum);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
return mustek_scsi_pp_check_response (fd);
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_read_data_block (int fd, u_char * buffer, int len)
|
|
{
|
|
int i;
|
|
signed char checksum;
|
|
|
|
DBG (5, "mustek_scsi_pp_read_data_block: reading block of length %d\n",
|
|
len);
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_5_clear (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_read_data_block: timed out waiting for bit 5 to clear\n");
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
checksum = 0;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
buffer[i] = mustek_scsi_pp_read_response (fd);
|
|
checksum += buffer[i];
|
|
}
|
|
if ((signed char) mustek_scsi_pp_read_response (fd) != (-checksum))
|
|
{
|
|
mustek_scsi_pp_send_command_byte (fd, 0xff);
|
|
DBG (2, "mustek_scsi_pp_read_data_block: checksums do not match\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (mustek_scsi_pp_wait_for_status_bit_5_set (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_read_data_block: error waiting for bit 5 to set\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (mustek_scsi_pp_send_command_byte (fd, 0) != SANE_STATUS_GOOD)
|
|
{
|
|
mustek_scsi_pp_send_command_byte (fd, 0xff);
|
|
DBG (2, "mustek_scsi_pp_read_data_block: error sending final 0 byte\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
DBG (5, "mustek_scsi_pp_read_data_block: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Externally visible functions
|
|
*/
|
|
SANE_Status
|
|
mustek_scsi_pp_open (const char *dev, int *fd)
|
|
{
|
|
SANE_Status status;
|
|
|
|
status = sanei_pa4s2_scsi_pp_open (dev, fd);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_open: device %s opened as fd %d\n", dev, *fd);
|
|
}
|
|
else
|
|
{
|
|
DBG (2, "mustek_scsi_pp_open: error opening device %s\n", dev);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
mustek_scsi_pp_close (int fd)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_close: closing fd %d\n", fd);
|
|
sanei_pa4s2_close (fd);
|
|
}
|
|
|
|
static void
|
|
mustek_scsi_pp_exit (void)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_exit: entering\n");
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_test_ready (int fd)
|
|
{
|
|
u_char status;
|
|
SANE_Status retval;
|
|
|
|
DBG (5, "mustek_scsi_pp_test_ready: entering with fd=%d\n", fd);
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_TRUE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_test_ready: error enabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (sanei_pa4s2_scsi_pp_get_status (fd, &status) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_test_ready: error getting status\n");
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
retval = SANE_STATUS_GOOD;
|
|
|
|
status &= 0xf0;
|
|
|
|
if (status == 0xf0)
|
|
{
|
|
retval = SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
if (status & 0x40)
|
|
{
|
|
retval = SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
if (!(status & 0x20))
|
|
{
|
|
retval = SANE_STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_FALSE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_test_ready: error disabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (retval == SANE_STATUS_GOOD)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_test_ready: returning SANE_STATUS_GOOD\n");
|
|
}
|
|
else
|
|
{
|
|
DBG (5,
|
|
"mustek_scsi_pp_test_ready: returning SANE_STATUS_DEVICE_BUSY\n");
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_cmd (int fd, const void *src, size_t src_size,
|
|
void *dst, size_t * dst_size)
|
|
{
|
|
SANE_Status stat;
|
|
int num_tries = 0;
|
|
static u_char scan_options = 0;
|
|
const u_char *cmd;
|
|
u_char stop_cmd[6] = { 0x1b, 0, 0, 0, 0, 0 };
|
|
int max_tries;
|
|
|
|
max_tries = MUSTEK_SCSI_PP_NUM_RETRIES;
|
|
|
|
cmd = (const u_char *) src;
|
|
|
|
DBG (5, "mustek_scsi_pp_cmd: sending command 0x%02X to device %d\n",
|
|
cmd[0], fd);
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_TRUE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_cmd: error enabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (cmd[0] == 0x1b)
|
|
{
|
|
if (!(cmd[4] & 0x1))
|
|
{
|
|
unsigned char c;
|
|
int i;
|
|
|
|
DBG (5, "mustek_scsi_pp_cmd: doing stop-specific stuff\n");
|
|
|
|
/*
|
|
* Remembers what flags were sent with a 'start' command, and
|
|
* replicate them with a stop command.
|
|
*/
|
|
stop_cmd[4] = scan_options & 0xfe;
|
|
cmd = &stop_cmd[0];
|
|
|
|
/*
|
|
* In color mode at least, the scanner doesn't seem to like stopping at
|
|
* the end. It's a bit of a horrible hack, but reading loads of bytes and
|
|
* allowing 20 tries for the stop command is the only way I've found that
|
|
* solves the problem.
|
|
*/
|
|
max_tries = 20;
|
|
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_cmd: error in readbegin for stop\n");
|
|
}
|
|
|
|
for (i = 0; i < 10000; i++)
|
|
{
|
|
if (sanei_pa4s2_readbyte (fd, &c) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_cmd: error reading byte for stop\n");
|
|
break;
|
|
}
|
|
DBG (5, "mustek_scsi_pp_cmd: successfully read byte %d\n", i);
|
|
}
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_cmd: error in readend for stop\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd[0] == 0x08)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_cmd: doing read-specific stuff\n");
|
|
mustek_scsi_pp_timeout = 30000;
|
|
mustek_scsi_pp_bit_4_state = 0xff;
|
|
}
|
|
|
|
/*
|
|
* Send the command itself in one block, then any extra input data in a second
|
|
* block. Not sure if that's necessary.
|
|
*/
|
|
if (src_size < 6)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2, "mustek_scsi_pp_cmd: source size is only %d (<6)\n", src_size);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
/*
|
|
* Retry the command several times, as occasionally it doesn't
|
|
* work first time.
|
|
*/
|
|
do
|
|
{
|
|
stat = mustek_scsi_pp_send_command (fd, cmd);
|
|
num_tries++;
|
|
}
|
|
while ((stat != SANE_STATUS_GOOD) && (num_tries < max_tries));
|
|
|
|
if (stat != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2, "mustek_scsi_pp_cmd: sending command failed\n");
|
|
return stat;
|
|
}
|
|
|
|
if (src_size > 6)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_cmd: sending data block of length %d\n",
|
|
src_size - 6);
|
|
|
|
stat =
|
|
mustek_scsi_pp_send_data_block (fd, ((const u_char *) src) + 6,
|
|
src_size - 6);
|
|
if (stat != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2, "mustek_scsi_pp_cmd: sending data block failed\n");
|
|
return stat;
|
|
}
|
|
}
|
|
|
|
|
|
if (dst)
|
|
{
|
|
unsigned int length;
|
|
|
|
/* check buffer is big enough to receive data */
|
|
length = (cmd[3] << 8) | cmd[4];
|
|
|
|
DBG (5, "mustek_scsi_pp_cmd: reading %d bytes\n", length);
|
|
|
|
if (length > *dst_size)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_cmd: buffer (size %d) not big enough for data (size %d)\n",
|
|
*dst_size, length);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
stat = mustek_scsi_pp_read_data_block (fd, dst, length);
|
|
if (stat != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_cmd: error reading data block\n");
|
|
}
|
|
}
|
|
|
|
if (cmd[0] == 0x1b)
|
|
{
|
|
if (cmd[4] & 0x1)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_cmd: doing start-specific stuff\n");
|
|
|
|
scan_options = cmd[4];
|
|
|
|
/* 'Start' command - wait for valid status */
|
|
mustek_scsi_pp_timeout = 70000;
|
|
stat = mustek_scsi_pp_wait_for_valid_status (fd);
|
|
|
|
if (stat != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2,
|
|
"mustek_scsi_pp_cmd: error waiting for valid status after start\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_FALSE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_cmd: error disabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
if (stat == SANE_STATUS_GOOD)
|
|
{
|
|
DBG (5, "mustek_scsi_pp_cmd: returning success\n");
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
static SANE_Status
|
|
mustek_scsi_pp_rdata (int fd, int planes, SANE_Byte * buf, int lines, int bpl)
|
|
{
|
|
int i, j;
|
|
|
|
DBG (5,
|
|
"mustek_scsi_pp_rdata: reading %d lines at %d bpl, %d planes from %d\n",
|
|
lines, bpl, planes, fd);
|
|
|
|
if ((planes != 1) && (planes != 3))
|
|
{
|
|
DBG (2, "mustek_scsi_pp_rdata: invalid number of planes (%d)\n",
|
|
planes);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_TRUE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_rdata: error enabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < lines; i++)
|
|
{
|
|
if (planes == 3)
|
|
{
|
|
if (mustek_scsi_pp_wait_for_status_bit_4_toggle (fd) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error waiting for bit 4 toggle for red, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readbegin for red, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
for (j = 0; j < (bpl / 3); j++)
|
|
{
|
|
if (sanei_pa4s2_readbyte (fd, &buf[j]) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_readend (fd);
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error reading red byte, line %d, byte %d\n",
|
|
i, j);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readend for red, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_4_toggle (fd) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error waiting for bit 4 toggle for green, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readbegin for green, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
for (j = 0; j < (bpl / 3); j++)
|
|
{
|
|
if (sanei_pa4s2_readbyte (fd, &buf[j + (bpl / 3)]) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_readend (fd);
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error reading green byte, line %d, byte %d\n",
|
|
i, j);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readend for green, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
|
|
if (mustek_scsi_pp_wait_for_status_bit_4_toggle (fd) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error waiting for bit 4 toggle for blue, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readbegin for blue, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
for (j = 0; j < (bpl / 3); j++)
|
|
{
|
|
if (sanei_pa4s2_readbyte (fd, &buf[j + (2 * (bpl / 3))]) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_readend (fd);
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error reading blue byte, line %d, byte %d\n",
|
|
i, j);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error in readend for blue, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mustek_scsi_pp_wait_for_status_bit_4_toggle (fd) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error waiting for bit 4 toggle, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
if (sanei_pa4s2_readbegin (fd, mustek_scsi_pp_register) !=
|
|
SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2, "mustek_scsi_pp_rdata: error in readbegin, line %d\n",
|
|
i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
for (j = 0; j < bpl; j++)
|
|
{
|
|
if (sanei_pa4s2_readbyte (fd, &buf[j]) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_readend (fd);
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2,
|
|
"mustek_scsi_pp_rdata: error reading byte, line %d, byte %d\n",
|
|
i, j);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (sanei_pa4s2_readend (fd) != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_pa4s2_enable (fd, SANE_FALSE);
|
|
DBG (2, "mustek_scsi_pp_rdata: error in readend, line %d\n", i);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
buf += bpl;
|
|
}
|
|
|
|
if (sanei_pa4s2_enable (fd, SANE_FALSE) != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (2, "mustek_scsi_pp_rdata: error enabling scanner\n");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
DBG (5, "mustek_scsi_pp_rdata: returning success\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|