diff options
Diffstat (limited to 'backend/mustek_scsi_pp.c')
-rw-r--r-- | backend/mustek_scsi_pp.c | 1086 |
1 files changed, 1086 insertions, 0 deletions
diff --git a/backend/mustek_scsi_pp.c b/backend/mustek_scsi_pp.c new file mode 100644 index 0000000..3dab544 --- /dev/null +++ b/backend/mustek_scsi_pp.c @@ -0,0 +1,1086 @@ +/* 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/types.h> +#include <sys/wait.h> + +#include <time.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 timeval tv; + int retval; + + gettimeofday (&tv, 0); + + retval = tv.tv_sec * 1000 + tv.tv_usec / 1000; + + 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 %lu (<6)\n", (u_long) 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 %lu\n", + (u_long) (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 %lu) not big enough for data (size %d)\n", + (u_long) *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; +} |