diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
commit | 6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch) | |
tree | 2e301d871bbeeb44aa57ff9cc070fcf3be484487 /backend/rts8891_low.c |
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'backend/rts8891_low.c')
-rw-r--r-- | backend/rts8891_low.c | 869 |
1 files changed, 869 insertions, 0 deletions
diff --git a/backend/rts8891_low.c b/backend/rts8891_low.c new file mode 100644 index 0000000..917d514 --- /dev/null +++ b/backend/rts8891_low.c @@ -0,0 +1,869 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2007-2013 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. + */ + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_usb.h" + +#include <stdio.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include "rts8891_low.h" + +#define RTS8891_BUILD 30 +#define RTS8891_MAX_REGISTERS 244 + +/* init rts8891 library */ +static void +rts8891_low_init (void) +{ + DBG_INIT (); + DBG (DBG_info, "RTS8891 low-level functions, version %d.%d-%d\n", + SANE_CURRENT_MAJOR, V_MINOR, RTS8891_BUILD); +} + + +/****************************************************************/ +/* 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_Byte reg; + + reg = value; + sanei_rts88xx_write_reg (devnum, 0xd3, ®); + sanei_rts88xx_cancel (devnum); + 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; + 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; +} + + /** + * set the data format. Is part of the commit sequence. Then returned + * value is the value used in d3 register for a scan. + */ +static SANE_Int +rts8891_data_format (SANE_Int dpi, int sensor) +{ + SANE_Byte reg = 0x00; + + /* it seems that lower nibble is a divisor */ + if (sensor == SENSOR_TYPE_BARE || sensor == SENSOR_TYPE_XPA) + { + 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; + } + } + return reg; +} + +/** + * set up default values for a 75xdpi, 150 ydpi scan + */ +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 +rts8891_move (struct Rts8891_Device *device, SANE_Byte * regs, + SANE_Int distance, SANE_Bool forward) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte regs10, regs11; + + DBG (DBG_proc, "rts8891_move: start\n"); + DBG (DBG_io, "rts8891_move: %d lines %s, sensor=%d\n", distance, + forward == SANE_TRUE ? "forward" : "backward", device->sensor); + + /* prepare scan */ + rts8891_set_default_regs (regs); + if (device->sensor != SENSOR_TYPE_4400 + && device->sensor != SENSOR_TYPE_4400_BARE) + { + regs10 = 0x20; + regs11 = 0x28; + } + else + { + regs10 = 0x10; + regs11 = 0x2a; + } + + 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; + + /* hp4400 sensors */ + if (device->sensor == SENSOR_TYPE_4400 + || device->sensor == SENSOR_TYPE_4400_BARE) + { + 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 */ + } + + /* disable CCD */ + regs[0] = 0xf5; + + sanei_rts88xx_set_status (device->devnum, regs, regs10, regs11); + 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 */ + status = rts8891_write_all (device->devnum, regs, RTS8891_MAX_REGISTERS); + + /* commit it */ + rts8891_commit (device->devnum, 0x00); + + return status; +} + + /** + * wait for the scanning head to reach home position + */ +static SANE_Status +rts8891_wait_for_home (struct Rts8891_Device *device, SANE_Byte * regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte motor, sensor, reg; + + DBG (DBG_proc, "rts8891_wait_for_home: start\n"); + + /* 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 + { + sanei_rts88xx_read_reg (device->devnum, CONTROL_REG, &motor); + sanei_rts88xx_read_reg (device->devnum, CONTROLER_REG, &sensor); + } + while ((motor & 0x08) && ((sensor & 0x02) == 0)); + + /* flag that device has finished parking */ + device->parking=SANE_FALSE; + + /* check for error */ + if (((motor & 0x08) == 0x00) && ((sensor & 0x02) == 0)) + { + DBG (DBG_error, + "rts8891_wait_for_home: error, motor stopped before head parked\n"); + status = SANE_STATUS_INVAL; + } + + /* re-enable CCD */ + regs[0] = regs[0] & 0xef; + + sanei_rts88xx_cancel (device->devnum); + + /* reset ? so we don't need to read data */ + reg = 0; + /* b7: movement on/off, b3-b0 : movement divisor */ + sanei_rts88xx_write_reg (device->devnum, 0x33, ®); + sanei_rts88xx_write_reg (device->devnum, 0x33, ®); + /* movement direction */ + sanei_rts88xx_write_reg (device->devnum, 0x36, ®); + sanei_rts88xx_cancel (device->devnum); + + DBG (DBG_proc, "rts8891_wait_for_home: end\n"); + 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 +rts8891_park (struct Rts8891_Device *device, SANE_Byte *regs, SANE_Bool wait) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG (DBG_proc, "rts8891_park: start\n"); + + device->parking=SANE_TRUE; + rts8891_move (device, regs, 8000, SANE_FALSE); + + if(wait==SANE_TRUE) + { + status = rts8891_wait_for_home (device,regs); + } + + 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 +read_data (struct Rts8891_Session *session, SANE_Byte * dest, SANE_Int length) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Int count, read, len, dummy; + struct Rts8891_Device *dev = session->dev; + 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 */ + if (session->non_blocking && count == 0) + { + + 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", + session->params.format == + SANE_FRAME_RGB + || session->emulated_gray == + 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 + */ + +/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ |