diff options
Diffstat (limited to 'backend/rts88xx_lib.c')
-rw-r--r-- | backend/rts88xx_lib.c | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/backend/rts88xx_lib.c b/backend/rts88xx_lib.c new file mode 100644 index 0000000..bbbc83a --- /dev/null +++ b/backend/rts88xx_lib.c @@ -0,0 +1,870 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2007-2012 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 functions common to rts88xx ASICs */ + +#undef BACKEND_NAME +#define BACKEND_NAME rts88xx_lib + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_usb.h" +#include "rts88xx_lib.h" + +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "../include/_stdint.h" + +#define RTS88XX_LIB_BUILD 30 + +/* init rts88xx library */ +void +sanei_rts88xx_lib_init (void) +{ + DBG_INIT (); + DBG (DBG_info, "RTS88XX library, version %d.%d-%d\n", SANE_CURRENT_MAJOR, V_MINOR, + RTS88XX_LIB_BUILD); +} + +/* + * registers helpers to avoid direct access + */ +SANE_Bool +sanei_rts88xx_is_color (SANE_Byte * regs) +{ + if ((regs[0x2f] & 0x11) == 0x11) + return SANE_TRUE; + return SANE_FALSE; +} + +void +sanei_rts88xx_set_gray_scan (SANE_Byte * regs) +{ + regs[0x2f] = (regs[0x2f] & 0x0f) | 0x20; +} + +void +sanei_rts88xx_set_color_scan (SANE_Byte * regs) +{ + regs[0x2f] = (regs[0x2f] & 0x0f) | 0x10; +} + +void +sanei_rts88xx_set_offset (SANE_Byte * regs, SANE_Byte red, SANE_Byte green, + SANE_Byte blue) +{ + /* offset for odd pixels */ + regs[0x02] = red; + regs[0x03] = green; + regs[0x04] = blue; + + /* offset for even pixels */ + regs[0x05] = red; + regs[0x06] = green; + regs[0x07] = blue; +} + +void +sanei_rts88xx_set_gain (SANE_Byte * regs, SANE_Byte red, SANE_Byte green, + SANE_Byte blue) +{ + regs[0x08] = red; + regs[0x09] = green; + regs[0x0a] = blue; +} + +void +sanei_rts88xx_set_scan_frequency (SANE_Byte * regs, int frequency) +{ + regs[0x64] = (regs[0x64] & 0xf0) | (frequency & 0x0f); +} + +/* + * read one register at given index + */ +SANE_Status +sanei_rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned char cmd[] = { 0x80, 0x00, 0x00, 0x01 }; + size_t size; + + cmd[1] = index; + + size = 4; + status = sanei_usb_write_bulk (devnum, cmd, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_reg: bulk write failed\n"); + return status; + } + size = 1; + status = sanei_usb_read_bulk (devnum, reg, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_reg: bulk read failed\n"); + return status; + } + DBG (DBG_io2, "sanei_rts88xx_read_reg: reg[0x%02x]=0x%02x\n", index, *reg); + return status; +} + +/* + * write one register at given index + */ +SANE_Status +sanei_rts88xx_write_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned char cmd[] = { 0x88, 0x00, 0x00, 0x01, 0xff }; + size_t size; + + cmd[1] = index; + cmd[4] = *reg; + + size = 5; + status = sanei_usb_write_bulk (devnum, cmd, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_write_reg: bulk write failed\n"); + return status; + } + DBG (DBG_io2, "sanei_rts88xx_write_reg: reg[0x%02x]=0x%02x\n", index, *reg); + return status; +} + +/* + * write length consecutive registers, starting at index + * register 0xb3 is never wrote in bulk register write, so we split + * write if it belongs to the register set sent + */ +SANE_Status +sanei_rts88xx_write_regs (SANE_Int devnum, SANE_Int start, + SANE_Byte * source, SANE_Int length) +{ + size_t size = 0; + size_t i; + SANE_Byte buffer[260]; + char message[256 * 5]; + + if (DBG_LEVEL > DBG_io) + { + for (i = 0; i < (size_t) length; i++) + { + sprintf (message + 5 * i, "0x%02x ", source[i]); + } + DBG (DBG_io, "sanei_rts88xx_write_regs : write_regs(0x%02x,%d)=%s\n", + start, length, message); + } + + /* when writing several registers at a time, we avoid writing the 0xb3 register + * which is used to control the status of the scanner */ + if ((start + length > 0xb3) && (length > 1)) + { + size = 0xb3 - start; + buffer[0] = 0x88; + buffer[1] = start; + buffer[2] = 0x00; + buffer[3] = size; + for (i = 0; i < size; i++) + buffer[i + 4] = source[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, + "sanei_rts88xx_write_regs : write registers part 1 failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + + /* skip 0xb3 register */ + size -= 3; + start = 0xb4; + source = source + size; + } + size = length - size; + buffer[0] = 0x88; + buffer[1] = start; + buffer[2] = 0x00; + buffer[3] = size; + for (i = 0; i < size; i++) + buffer[i + 4] = source[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, + "sanei_rts88xx_write_regs : write registers part 2 failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + + return SANE_STATUS_GOOD; + +} + +/* read several registers starting at the given index */ +SANE_Status +sanei_rts88xx_read_regs (SANE_Int devnum, SANE_Int start, + SANE_Byte * dest, SANE_Int length) +{ + SANE_Status status; + static SANE_Byte command_block[] = { 0x80, 0, 0x00, 0xFF }; + size_t size, i; + char message[256 * 5]; + + if (start + length > 255) + { + DBG (DBG_error, + "sanei_rts88xx_read_regs: start and length must be within [0..255]\n"); + return SANE_STATUS_INVAL; + } + + /* write header */ + size = 4; + command_block[1] = start; + command_block[3] = length; + status = sanei_usb_write_bulk (devnum, command_block, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_regs: failed to write header\n"); + return status; + } + + /* read data */ + size = length; + status = sanei_usb_read_bulk (devnum, dest, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_regs: failed to read data\n"); + return status; + } + if (size != (size_t) length) + { + DBG (DBG_warn, "sanei_rts88xx_read_regs: read got only %lu bytes\n", + (u_long) size); + } + if (DBG_LEVEL >= DBG_io) + { + for (i = 0; i < size; i++) + sprintf (message + 5 * i, "0x%02x ", dest[i]); + DBG (DBG_io, "sanei_rts88xx_read_regs: read_regs(0x%02x,%d)=%s\n", + start, length, message); + } + return status; +} + +/* + * get status by reading registers 0x10 and 0x11 + */ +SANE_Status +sanei_rts88xx_get_status (SANE_Int devnum, SANE_Byte * regs) +{ + SANE_Status status; + status = sanei_rts88xx_read_regs (devnum, 0x10, regs + 0x10, 2); + DBG (DBG_io, "sanei_rts88xx_get_status: get_status()=0x%02x 0x%02x\n", + regs[0x10], regs[0x11]); + return status; +} + +/* + * set status by writing registers 0x10 and 0x11 + */ +SANE_Status +sanei_rts88xx_set_status (SANE_Int devnum, SANE_Byte * regs, + SANE_Byte reg10, SANE_Byte reg11) +{ + SANE_Status status; + + regs[0x10] = reg10; + regs[0x11] = reg11; + status = sanei_rts88xx_write_regs (devnum, 0x10, regs + 0x10, 2); + DBG (DBG_io, "sanei_rts88xx_set_status: 0x%02x 0x%02x\n", regs[0x10], + regs[0x11]); + return status; +} + +/* + * get lamp status by reading registers 0x84 to 0x8f, only 0x8F is currently usefull + * 0x84 and following could "on" timers + */ +SANE_Status +sanei_rts88xx_get_lamp_status (SANE_Int devnum, SANE_Byte * regs) +{ + SANE_Status status; + status = sanei_rts88xx_read_regs (devnum, 0x84, regs + 0x84, 11); + return status; +} + +/* resets lamp */ +SANE_Status +sanei_rts88xx_reset_lamp (SANE_Int devnum, SANE_Byte * regs) +{ + SANE_Status status; + SANE_Byte reg; + + /* read the 0xda register, then clear lower nibble and write it back */ + status = sanei_rts88xx_read_reg (devnum, 0xda, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_reset_lamp: failed to read 0xda register\n"); + return status; + } + reg = 0xa0; + status = sanei_rts88xx_write_reg (devnum, 0xda, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_reset_lamp: failed to write 0xda register\n"); + return status; + } + + /* on cleared, get status */ + status = sanei_rts88xx_get_status (devnum, regs); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_reset_lamp: failed to get status\n"); + return status; + } + DBG (DBG_io, "sanei_rts88xx_reset_lamp: status=0x%02x 0x%02x\n", regs[0x10], + regs[0x11]); + + /* set low nibble to 7 and write it */ + reg = reg | 0x07; + status = sanei_rts88xx_write_reg (devnum, 0xda, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_reset_lamp: failed to write 0xda register\n"); + return status; + } + status = sanei_rts88xx_read_reg (devnum, 0xda, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_reset_lamp: failed to read 0xda register\n"); + return status; + } + if (reg != 0xa7) + { + DBG (DBG_warn, + "sanei_rts88xx_reset_lamp: expected reg[0xda]=0xa7, got 0x%02x\n", + reg); + } + + /* store read value in shadow register */ + regs[0xda] = reg; + + return status; +} + +/* + * get lcd status by reading registers 0x20, 0x21 and 0x22 + */ +SANE_Status +sanei_rts88xx_get_lcd (SANE_Int devnum, SANE_Byte * regs) +{ + SANE_Status status; + status = sanei_rts88xx_read_regs (devnum, 0x20, regs + 0x20, 3); + DBG (DBG_io, "sanei_rts88xx_get_lcd: 0x%02x 0x%02x 0x%02x\n", regs[0x20], + regs[0x21], regs[0x22]); + return status; +} + +/* + * write to special control register CONTROL_REG=0xb3 + */ +SANE_Status +sanei_rts88xx_write_control (SANE_Int devnum, SANE_Byte value) +{ + SANE_Status status; + status = sanei_rts88xx_write_reg (devnum, CONTROL_REG, &value); + return status; +} + +/* + * send the cancel control sequence + */ +SANE_Status +sanei_rts88xx_cancel (SANE_Int devnum) +{ + SANE_Status status; + + status = sanei_rts88xx_write_control (devnum, 0x02); + if (status != SANE_STATUS_GOOD) + return status; + status = sanei_rts88xx_write_control (devnum, 0x02); + if (status != SANE_STATUS_GOOD) + return status; + status = sanei_rts88xx_write_control (devnum, 0x00); + if (status != SANE_STATUS_GOOD) + return status; + status = sanei_rts88xx_write_control (devnum, 0x00); + return status; +} + +/* + * write the given number of bytes pointed by value into memory + * length is payload length + * extra is number of bytes to add to the usb write length + */ +SANE_Status +sanei_rts88xx_write_mem (SANE_Int devnum, SANE_Int length, SANE_Int extra, + SANE_Byte * value) +{ + SANE_Status status; + SANE_Byte *buffer; + size_t i, size; + char message[(0xFFC0 + 10) * 3] = ""; + + buffer = (SANE_Byte *) malloc (length + 10); + if (buffer == NULL) + return SANE_STATUS_NO_MEM; + memset (buffer, 0, length + 10); + + buffer[0] = 0x89; + buffer[1] = 0x00; + buffer[2] = HIBYTE (length); + buffer[3] = LOBYTE (length); + for (i = 0; i < (size_t) length; i++) + { + buffer[i + 4] = value[i]; + + if (DBG_LEVEL > DBG_io2) + { + sprintf (message + 3 * i, "%02x ", buffer[i + 4]); + } + } + DBG (DBG_io, "sanei_rts88xx_write_mem: %02x %02x %02x %02x -> %s\n", + buffer[0], buffer[1], buffer[2], buffer[3], message); + + size = length + 4 + extra; + status = sanei_usb_write_bulk (devnum, buffer, &size); + free (buffer); + if ((status == SANE_STATUS_GOOD) && (size != (size_t) length + 4 + extra)) + { + DBG (DBG_error, + "sanei_rts88xx_write_mem: only wrote %lu bytes out of %d\n", + (u_long) size, length + 4); + status = SANE_STATUS_IO_ERROR; + } + return status; +} + +/* + * set memory with the given data + */ +SANE_Status +sanei_rts88xx_set_mem (SANE_Int devnum, SANE_Byte ctrl1, + SANE_Byte ctrl2, SANE_Int length, SANE_Byte * value) +{ + SANE_Status status; + SANE_Byte regs[2]; + regs[0] = ctrl1; + regs[1] = ctrl2; + + status = sanei_rts88xx_write_regs (devnum, 0x91, regs, 2); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_set_mem: failed to write 0x91/0x92 registers\n"); + return status; + } + status = sanei_rts88xx_write_mem (devnum, length, 0, value); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_set_mem: failed to write memory\n"); + } + return status; +} + +/* + * read length bytes of memory into area pointed by value + */ +SANE_Status +sanei_rts88xx_read_mem (SANE_Int devnum, SANE_Int length, SANE_Byte * value) +{ + SANE_Status status; + size_t size, read, want; + SANE_Byte header[4]; + + /* build and write length header */ + header[0] = 0x81; + header[1] = 0x00; + header[2] = HIBYTE (length); + header[3] = LOBYTE (length); + size = 4; + status = sanei_usb_write_bulk (devnum, header, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_read_mem: failed to write length header\n"); + return status; + } + DBG (DBG_io, "sanei_rts88xx_read_mem: %02x %02x %02x %02x -> ...\n", + header[0], header[1], header[2], header[3]); + read = 0; + while (length > 0) + { + if (length > 2048) + want = 2048; + else + want = length; + size = want; + status = sanei_usb_read_bulk (devnum, value + read, &size); + if (size != want) + { + DBG (DBG_error, + "sanei_rts88xx_read_mem: only read %lu bytes out of %lu\n", + (u_long) size, (u_long) want); + status = SANE_STATUS_IO_ERROR; + } + length -= size; + read += size; + } + return status; +} + +/* + * set memory with the given data + */ +SANE_Status +sanei_rts88xx_get_mem (SANE_Int devnum, SANE_Byte ctrl1, + SANE_Byte ctrl2, SANE_Int length, SANE_Byte * value) +{ + SANE_Status status; + SANE_Byte regs[2]; + regs[0] = ctrl1; + regs[1] = ctrl2; + + status = sanei_rts88xx_write_regs (devnum, 0x91, regs, 2); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_get_mem: failed to write 0x91/0x92 registers\n"); + return status; + } + status = sanei_rts88xx_read_mem (devnum, length, value); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_get_mem: failed to read memory\n"); + } + return status; +} + +/* + * write to the nvram controler + */ +SANE_Status +sanei_rts88xx_nvram_ctrl (SANE_Int devnum, SANE_Int length, SANE_Byte * value) +{ + SANE_Status status; + SANE_Int i; + char message[60 * 5]; +#ifdef HAZARDOUS_EXPERIMENT + SANE_Int size = 0; + SANE_Byte buffer[60]; +#endif + + if (DBG_LEVEL > DBG_io) + { + for (i = 0; i < length; i++) + { + sprintf (message + 5 * i, "0x%02x ", value[i]); + } + DBG (DBG_io, "sanei_rts88xx_nvram_ctrl : devnum=%d, nvram_ctrl(0x00,%d)=%s\n", + devnum, length, message); + } + +#ifdef HAZARDOUS_EXPERIMENT + buffer[0] = 0x8a; + buffer[1] = 0x00; + buffer[2] = 0x00; + buffer[3] = length; + for (i = 0; i < size; i++) + buffer[i + 4] = value[i]; + /* the USB block is size + 4 bytes of header long */ + size = length + 4; + status = sanei_usb_write_bulk (devnum, buffer, &size); +#else + status = SANE_STATUS_GOOD; +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_nvram_ctrl : write failed ...\n"); + } + return status; +} + +/* + * setup nvram + */ +SANE_Status +sanei_rts88xx_setup_nvram (SANE_Int devnum, SANE_Int length, + SANE_Byte * value) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte local[2], reg; + int i; + + status = sanei_rts88xx_nvram_ctrl (devnum, length, value); + +#ifndef HAZARDOUS_EXPERIMENT + return SANE_STATUS_GOOD; +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_setup_nvram : failed step #1 ...\n"); + return status; + } + local[0] = 0x18; + local[1] = 0x08; + for (i = 0; i < 8; i++) + { + status = sanei_rts88xx_nvram_ctrl (devnum, 2, local); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_setup_nvram : failed loop #%d ...\n", + i); + return status; + } + status = sanei_rts88xx_read_reg (devnum, 0x10, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_setup_nvram : register reading failed loop #%d ...\n", + i); + return status; + } + DBG (DBG_io, "sanei_rts88xx_setup_nvram: reg[0x10]=0x%02x\n", reg); + } + reg = 0; + status = sanei_rts88xx_write_reg (devnum, CONTROLER_REG, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_setup_nvram : controler register write failed\n"); + return status; + } + reg = 1; + status = sanei_rts88xx_write_reg (devnum, CONTROLER_REG, ®); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_setup_nvram : controler register write failed\n"); + return status; + } + return status; +} + +/* + * Sets scan area, no checks are being done, so watch your steps + */ +void +sanei_rts88xx_set_scan_area (SANE_Byte * regs, SANE_Int ystart, + SANE_Int yend, SANE_Int xstart, SANE_Int xend) +{ + /* vertical lines to move before scan */ + regs[START_LINE] = LOBYTE (ystart); + regs[START_LINE + 1] = HIBYTE (ystart); + + /* total number of line to move */ + regs[END_LINE] = LOBYTE (yend); + regs[END_LINE + 1] = HIBYTE (yend); + + /* set horizontal start position */ + regs[START_PIXEL] = LOBYTE (xstart); + regs[START_PIXEL + 1] = HIBYTE (xstart); + + /* set horizontal end position */ + regs[END_PIXEL] = LOBYTE (xend); + regs[END_PIXEL + 1] = HIBYTE (xend); +} + +/** + * read available data count from scanner + * from tests it appears that advertised data + * may not be really available, and that a pause must be made + * before reading data so that it is really there. + * Such as reading data twice. + */ +SANE_Status +sanei_rts88xx_data_count (SANE_Int devnum, SANE_Word * count) +{ + SANE_Status status; + size_t size; + static SANE_Byte header[4] = { 0x90, 0x00, 0x00, 3 }; + SANE_Byte result[3]; + + /* set count in case of failure */ + *count = 0; + + size = 4; + status = sanei_usb_write_bulk (devnum, header, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_data_count : failed to write header\n"); + return status; + } + size = 3; + status = sanei_usb_read_bulk (devnum, result, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "sanei_rts88xx_data_count : failed to read data count\n"); + return status; + } + *count = result[0] + (result[1] << 8) + (result[2] << 16); + DBG (DBG_io2, "sanei_rts88xx_data_count: %d bytes available (0x%06x)\n", + *count, *count); + return status; +} + +/** + * Waits for data being available while optionally polling motor. There is a timeout + * to prevent scanner waiting forever non coming data. + */ +SANE_Status +sanei_rts88xx_wait_data (SANE_Int devnum, SANE_Bool busy, SANE_Word * count) +{ + SANE_Status status; + SANE_Byte control; + + /* poll the available byte count until not 0 */ + while (SANE_TRUE) + { + status = sanei_rts88xx_data_count (devnum, count); + if (*count != 0) + { + DBG (DBG_io, "sanei_rts88xx_wait_data: %d bytes available\n", + *count); + return status; + } + + /* check that the scanner is busy scanning */ + if (busy) + { + sanei_rts88xx_read_reg (devnum, CONTROL_REG, &control); + if ((control & 0x08) == 0 && (*count == 0)) + { + DBG (DBG_error, + "sanei_rts88xx_wait_data: scanner stopped being busy before data are available\n"); + return SANE_STATUS_IO_ERROR; + } + } + } + + /* we hit timeout */ + return SANE_STATUS_IO_ERROR; +} + +/* + * read scanned data from scanner up to the size given. The actual length read is returned. + */ +SANE_Status +sanei_rts88xx_read_data (SANE_Int devnum, SANE_Word * length, + unsigned char *dest) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte header[4]; + size_t size, len, remain, read; + + /* do not read too much data */ + if (*length > RTS88XX_MAX_XFER_SIZE) + len = RTS88XX_MAX_XFER_SIZE; + else + len = *length; + + /* write command header first */ + header[0] = 0x91; + header[1] = 0x00; + header[2] = HIBYTE (len); + header[3] = LOBYTE (len); + size = 4; + + status = sanei_usb_write_bulk (devnum, header, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_data: failed to write header\n"); + } + read = 0; + + /* first read blocks aligned on 64 bytes boundary */ + while (len - read > 64) + { + size = (len - read) & 0xFFC0; + status = sanei_usb_read_bulk (devnum, dest + read, &size); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_data: failed to read data\n"); + return status; + } + DBG (DBG_io2, "sanei_rts88xx_read_data: read %lu bytes\n", + (u_long) size); + read += size; + } + + /* then read remainder */ + remain = len - read; + if (remain > 0) + { + status = sanei_usb_read_bulk (devnum, dest + read, &remain); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "sanei_rts88xx_read_data: failed to read data\n"); + return status; + } + DBG (DBG_io2, "sanei_rts88xx_read_data: read %lu bytes\n", + (u_long) remain); + read += remain; + } + + /* update actual read length */ + DBG (DBG_io, "sanei_rts88xx_read_data: read %lu bytes, %d required\n", + (u_long) read, *length); + *length = read; + return status; +} |