From dce6df918232cac2e0693ac62bc784fde70336df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Voltz?= Date: Mon, 1 Oct 2007 04:27:24 +0000 Subject: [PATCH] - moved experimental version to current tree --- ChangeLog | 10 +- backend/Makefile.in | 5 +- backend/lexmark-x1100.c | 2916 ------------------- backend/lexmark.c | 652 +++-- backend/lexmark.conf.in | 6 +- backend/lexmark.h | 138 +- backend/lexmark_low.c | 5150 +++++++++++++++++++++++++++++++++ backend/lexmark_models.c | 93 + backend/lexmark_sensors.c | 122 + doc/descriptions/lexmark.desc | 29 +- doc/sane-lexmark.man | 136 +- 11 files changed, 6042 insertions(+), 3215 deletions(-) delete mode 100644 backend/lexmark-x1100.c create mode 100644 backend/lexmark_low.c create mode 100644 backend/lexmark_models.c create mode 100644 backend/lexmark_sensors.c diff --git a/ChangeLog b/ChangeLog index 3f40f492c..ae3141cb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ 2007-10-01 Stephane Voltz - * doc/sane-umax_pp.man doc/description/umax_pp.desc: + * doc/sane-lexmark.man doc/descriptions/lexmark.desc + backend/Makefile.in backend/lexmark.c backend/lexmark_low.c + backend/lexmark_sensors.c backend/lexmark_models.c + backend/lexmark.conf.in: + moved experimental version to current tree + +2007-10-01 Stephane Voltz + + * doc/sane-umax_pp.man doc/descriptions/umax_pp.desc: added Genius ColorPage-Life Pro as supported scanner by the umax_pp backend diff --git a/backend/Makefile.in b/backend/Makefile.in index e51a9c399..dea965c57 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -123,7 +123,8 @@ DISTFILES = abaton.c abaton.conf.in abaton.h agfafocus.c agfafocus.conf.in \ hp5400_sane.c hp5400_sanei.c hp5400_sanei.h \ ibm.c ibm.conf.in ibm.h ibm-scsi.c \ leo.c leo.h leo.conf.in \ - lexmark.c lexmark-x1100.c lexmark.h lexmark.conf.in \ + lexmark.c lexmark_low.c lexmark_sensors.c lexmark_devices.c lexmark.h \ + lexmark.conf.in \ lm9830.h \ ma1509.c ma1509.conf.in ma1509.h \ Makefile.in matsushita.c \ @@ -315,7 +316,7 @@ EXTRA_hp = hp-accessor hp-device hp-handle hp-hpmem hp-option hp-scl EXTRA_umax_pp = umax_pp_low umax_pp_mid EXTRA_epson = epson_scsi epson_usb EXTRA_epson2 = epson2_scsi epson_usb epson2_net epson2-io epson2-commands -EXTRA_lexmark = lexmark-x1100 +EXTRA_lexmark = lexmark_low EXTRA_pixma = pixma_io_sanei pixma_common pixma_mp150 pixma_mp730 pixma_mp750 # When preloading dll, we need to add in all preloaded objects: diff --git a/backend/lexmark-x1100.c b/backend/lexmark-x1100.c deleted file mode 100644 index bd99d72ca..000000000 --- a/backend/lexmark-x1100.c +++ /dev/null @@ -1,2916 +0,0 @@ -/* lexmark-x1100.c: scanner-interface file for x1100 Lexmark scanners. - - (C) 2005 Fred Odendaal - - 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. - - **************************************************************************/ - -#include "../include/sane/config.h" - -#include -#include -#include -#include - -#include "../include/sane/sane.h" -#include "../include/sane/sanei.h" -#include "../include/sane/saneopts.h" - -#include "../include/sane/sanei_usb.h" - -#define DEBUG_DECLARE_ONLY -#include "lexmark.h" -#include "../include/sane/sanei_backend.h" - - - -typedef enum -{ - black = 0, - white -} -region_type; - -#define HomeEdgePoint1 1235 -#define HomeEdgePoint2 1258 -#define HomeTolerance 30 - -/* F.O. Per device globals - moved to lexmark.h as part of Lexmark_Device */ -/* static SANE_Byte *transfer_buffer = NULL; */ -/* static size_t bytes_remaining = 0; */ -/* static size_t bytes_in_buffer = 0; */ -/* static SANE_Byte *read_pointer; */ -/* static Read_Buffer *read_buffer = NULL; */ -/* static int image_line_no = 0; */ - - - -static SANE_Byte shadow_regs[] = { - 0x00, 0x43, 0x9f, 0xa1, 0xa3, 0x9f, 0xa1, 0xa3, - 0x09, 0x0a, 0x06, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x0f, 0x01, 0x00, 0x01, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xeb, 0xee, 0xf7, 0x01, 0x0f, 0x51, 0x86, 0x11, - 0x48, 0x00, 0x00, 0x01, 0x0b, 0x01, 0x0b, 0x01, - 0x0a, 0x07, 0x20, 0x37, 0x88, 0x08, 0x00, 0x00, - 0x80, 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, - 0x22, 0x00, 0x12, 0x03, 0x01, 0x80, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x02, 0x01, 0x60, 0x80, - 0x00, 0x8c, 0x40, 0x06, 0x0e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xcc, 0x27, 0x24, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x83, 0x20, 0x0e, 0x09, 0x00, - 0x04, 0x3a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x0a, 0xed, 0x02, 0x29, 0x0a, 0x0e, 0x29, - 0x03, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* Static x1100 function proto-types */ -static SANE_Status x1100_usb_bulk_write (SANE_Int devnum, - SANE_Byte * cmd, - size_t * size); -static SANE_Status x1100_usb_bulk_read (SANE_Int devnum, - SANE_Byte * buf, - size_t * size); -static SANE_Status x1100_write_all_regs (SANE_Int devnum); -static SANE_Bool x1100_is_home_line (unsigned char *buffer); -static SANE_Status x1100_get_start_loc (SANE_Int resolution, - SANE_Int * vert_start, - SANE_Int * hor_start, - SANE_Int offset); -static void x1100_rewind (Lexmark_Device * dev); -static SANE_Status x1100_start_mvmt (SANE_Int devnum); -static SANE_Status x1100_stop_mvmt (SANE_Int devnum); -static SANE_Status x1100_clr_c6 (SANE_Int devnum); -static void x1100_set_scan_area (SANE_Int res, - SANE_Bool isColour, - SANE_Int height, - SANE_Int width, - SANE_Int offset); - -/* Static Read Buffer Proto-types */ -static SANE_Status read_buffer_init (Lexmark_Device *dev, int bytesperline); -static SANE_Status read_buffer_free (Read_Buffer *rb); -static size_t read_buffer_bytes_available (Read_Buffer *rb); -static SANE_Status read_buffer_add_byte (Read_Buffer *rb, - SANE_Byte * byte_pointer); -static SANE_Status read_buffer_add_byte_gray (Read_Buffer *rb, - SANE_Byte * byte_pointer); -static SANE_Status read_buffer_add_bit_lineart (Read_Buffer *rb, - SANE_Byte * byte_pointer, - SANE_Byte threshold); -static size_t read_buffer_get_bytes (Read_Buffer *rb, SANE_Byte * buffer, - size_t rqst_size); -static SANE_Bool read_buffer_is_empty (Read_Buffer *rb); - -SANE_Status -sanei_lexmark_x1100_init (void) -{ - - /* initialize sanei usb functions */ - sanei_usb_init (); - return SANE_STATUS_GOOD; -} - -void -sanei_lexmark_x1100_destroy (Lexmark_Device *dev) -{ - /* free the read buffer */ - if (dev->read_buffer != NULL) - read_buffer_free (dev->read_buffer); -} - - -SANE_Status -x1100_usb_bulk_write (SANE_Int devnum, SANE_Byte * cmd, size_t * size) -{ - SANE_Status status; - size_t cmd_size; - - cmd_size = *size; - status = sanei_usb_write_bulk (devnum, cmd, size); - if (status != SANE_STATUS_GOOD) - { - DBG (5, - "x1100_usb_bulk_write: returned %s (size = %ld, expected %d)\n", - sane_strstatus (status), (long int) *size, cmd_size); - /* F.O. should reset the pipe here... */ - } - return status; -} - -SANE_Status -x1100_usb_bulk_read (SANE_Int devnum, SANE_Byte * buf, size_t * size) -{ - SANE_Status status; - size_t exp_size; - - exp_size = *size; - status = sanei_usb_read_bulk (devnum, buf, size); - if (status != SANE_STATUS_GOOD) - { - DBG (5, - "x1100_usb_bulk_read: returned %s (size = %ld, expected %d)\n", - sane_strstatus (status), (long int) *size, exp_size); - /* F.O. should reset the pipe here... */ - } - return status; -} - -SANE_Status -x1100_start_mvmt (SANE_Int devnum) -{ - static SANE_Byte startscan_command_block[] = { - 0x88, 0x2c, 0x00, 0x01, 0x0f, - 0x88, 0xb3, 0x00, 0x01, 0x02, - 0x88, 0xb3, 0x00, 0x01, 0x02, - 0x88, 0xb3, 0x00, 0x01, 0x00, - 0x88, 0xb3, 0x00, 0x01, 0x00, - 0x88, 0xb3, 0x00, 0x01, 0x68, - 0x88, 0xb3, 0x00, 0x01, 0x68, - }; - size_t cmd_size; - - /* Colour depth = 0f; Start moving scanner: */ - cmd_size = 0x23; - return x1100_usb_bulk_write (devnum, startscan_command_block, &cmd_size); -} - -SANE_Status -x1100_stop_mvmt (SANE_Int devnum) -{ - static SANE_Byte stopscan_command_block[] = { - 0x88, 0xb3, 0x00, 0x01, 0x02, - 0x88, 0xb3, 0x00, 0x01, 0x02, - 0x88, 0xb3, 0x00, 0x01, 0x00, - 0x88, 0xb3, 0x00, 0x01, 0x00 - }; - size_t cmd_size; - - /* Stop scanner - clear reg 0xb3: */ - cmd_size = 0x14; - return x1100_usb_bulk_write (devnum, stopscan_command_block, &cmd_size); - -} - -SANE_Status -x1100_clr_c6 (SANE_Int devnum) -{ - static SANE_Byte clearC6_command_block[] = { - 0x88, 0xc6, 0x00, 0x01, 0x00 - }; - size_t cmd_size; - - /* Clear register 0xC6 */ - cmd_size = 0x05; - return x1100_usb_bulk_write (devnum, clearC6_command_block, &cmd_size); - -} - -SANE_Status -sanei_lexmark_x1100_open_device (SANE_String_Const devname, SANE_Int * devnum) -{ - /* This function calls the Sane Interface to open this usb device. - It also needlessly does what the Windows driver does and reads - the entire register set - this may be removed. */ - - SANE_Status result; - static SANE_Byte command_block[] = { 0x80, 0, 0x00, 0xFF }; - SANE_Byte registers[0x100]; - size_t size; - - result = sanei_usb_open (devname, devnum); - DBG (2, "sanei_lexmark_x1100_open_device: devnum=%d\n", *devnum); - - /* dump registers F.O. This is needless... */ - size = 4; - x1100_usb_bulk_write (*devnum, command_block, &size); - size = 0xFF; - x1100_usb_bulk_read (*devnum, registers, &size); - - return result; -} - -void -sanei_lexmark_x1100_close_device (SANE_Int devnum) -{ - /* This function calls the Sane USB library to close this usb device */ - - sanei_usb_close (devnum); - return; -} - - -SANE_Status -x1100_write_all_regs (SANE_Int devnum) -{ - /* This function writes the contents of the shadow registers to the - scanner. */ - int i; - size_t size; - static SANE_Byte command_block1[0xb7]; - static SANE_Byte command_block2[0x4f]; - command_block1[0] = 0x88; - command_block1[1] = 0x00; - command_block1[2] = 0x00; - command_block1[3] = 0xb3; - for (i = 0; i < 0xb3; i++) - { - command_block1[i + 4] = shadow_regs[i]; - } - command_block2[0] = 0x88; - command_block2[1] = 0xb4; - command_block2[2] = 0x00; - command_block2[3] = 0x4b; - for (i = 0; i < 0x4b; i++) - { - command_block2[i + 4] = shadow_regs[i + 0xb4]; - } - size = 0xb7; - x1100_usb_bulk_write (devnum, command_block1, &size); - size = 0x4f; - x1100_usb_bulk_write (devnum, command_block2, &size); - return SANE_STATUS_GOOD; -} - -SANE_Bool -x1100_is_home_line (unsigned char *buffer) -{ - /* - This function assumes the buffer has a size of 2500 bytes.It is - destructive to the buffer. - - Here is what it does: - - Go through the buffer finding low and high values, which are computed by - comparing to the average: - average = (lowest value + highest value)/2 - High bytes are changed to 0xFF (white), lower or equal bytes are changed - to 0x00 (black),so that the buffer only contains white (0xFF) or black - (0x00) values. - - Next, we go through the buffer. We use a tolerance of 5 bytes on each end - of the buffer and check a region from bytes 5 to 2495. We start assuming - we are in a white region and look for the start of a black region. We save - this index as the transition from white to black. We also save where we - change from black back to white. We continue checking for transitions - until the end of the check region. If we don't have exactly two - transitions when we reach the end we return SANE_FALSE. - - The final check compares the transition indices to the nominal values - plus or minus the tolerence. For the first transition (white to black - index) the value must lie in the range 1235-30 (1205) to 1235+30 (1265). - For the second transition (black to white) the value must lie in the range - 1258-30 (1228) to 1258+30 (1288). If the indices are out of range we - return SANE_FALSE. Otherwise, we return SANE_TRUE. - */ - - - unsigned char max_byte = 0; - unsigned char min_byte = 0xFF; - unsigned char average; - int i; - - region_type region; - int transition_counter; - int index1 = 0; - int index2 = 0; - int low_range, high_range; - - /* Find the max and the min */ - for (i = 0; i < 2500; i++) - { - if (*(buffer + i) > max_byte) - max_byte = *(buffer + i); - if (*(buffer + i) < min_byte) - min_byte = *(buffer + i); - } - - /* The average */ - average = ((max_byte + min_byte) / 2); - - /* Set bytes as white (0xFF) or black (0x00) */ - for (i = 0; i < 2500; i++) - { - if (*(buffer + i) > average) - *(buffer + i) = 0xFF; - else - *(buffer + i) = 0x00; - } - - region = white; - transition_counter = 0; - - /* Go through the check region - bytes 5 to 2495 */ - for (i = 5; i <= 2495; i++) - { - /* Check for transition to black */ - if ((region == white) && (*(buffer + i) == 0)) - { - if (transition_counter < 2) - { - region = black; - index1 = i; - transition_counter++; - } - else - { - return SANE_FALSE; - } - } - /* Check for transition to white */ - else if ((region == black) && (*(buffer + i) == 0xFF)) - { - if (transition_counter < 2) - { - region = white; - index2 = i; - transition_counter++; - } - else - { - return SANE_FALSE; - } - } - } - - /* Check that the number of transitions is 2 */ - if (transition_counter != 2) - { - return SANE_FALSE; - } - - /* Check that the 1st index is in range */ - low_range = HomeEdgePoint1 - HomeTolerance; - high_range = HomeEdgePoint1 + HomeTolerance; - - if ((index1 < low_range) || (index1 > high_range)) - { - return SANE_FALSE; - } - - /* Check that the 2nd index is in range */ - low_range = HomeEdgePoint2 - HomeTolerance; - high_range = HomeEdgePoint2 + HomeTolerance; - - if ((index2 < low_range) || (index2 > high_range)) - { - return SANE_FALSE; - } - - /* We made it this far, so its a good home line. Return True */ - return SANE_TRUE; - -} - -void -sanei_lexmark_x1100_move_fwd (SANE_Int distance, Lexmark_Device * dev) -{ - /* - This function moves the scan head forward with the highest vertical - resolution of 1200dpi. The distance moved is given by the distance - parameter. - - As an example, given a distance parameter of 600, the scan head will - move 600/1200", or 1/2" forward. - */ - - static SANE_Byte pollstopmoving_command_block[] = - { 0x80, 0xb3, 0x00, 0x01 }; - - int i; - size_t cmd_size; - SANE_Int devnum; - SANE_Bool scan_head_moving; - SANE_Byte read_result; - - devnum = dev->devnum; - /* Clear all the shadow registers */ - for (i = 0; i < 255; i++) - shadow_regs[i] = 0; - /* Some regiters are always set the same */ - shadow_regs[0x01] = 0x43; - shadow_regs[0x0b] = 0x70; - shadow_regs[0x11] = 0x01; - shadow_regs[0x12] = 0x0f; - shadow_regs[0x13] = 0x01; - shadow_regs[0x15] = 0x01; - shadow_regs[0x16] = 0x0f; - shadow_regs[0x1d] = 0x20; - shadow_regs[0x28] = 0xeb; - shadow_regs[0x29] = 0xee; - shadow_regs[0x2a] = 0xf7; - shadow_regs[0x2b] = 0x01; - shadow_regs[0x2c] = 0x00; /*not the same */ - shadow_regs[0x2d] = 0x41; /*not the same */ - shadow_regs[0x2e] = 0x86; - shadow_regs[0x30] = 0x48; - shadow_regs[0x33] = 0x01; - shadow_regs[0x3a] = 0x20; - shadow_regs[0x3b] = 0x37; - shadow_regs[0x3c] = 0x88; - shadow_regs[0x3d] = 0x08; - shadow_regs[0x40] = 0x80; - shadow_regs[0x65] = 0x80; - shadow_regs[0x72] = 0x05; - shadow_regs[0x74] = 0x0e; - shadow_regs[0x8b] = 0x00; /*not the same */ - shadow_regs[0x8c] = 0x00; /*not the same */ - shadow_regs[0x8d] = 0x01; - shadow_regs[0x8e] = 0x60; - shadow_regs[0x8f] = 0x80; - shadow_regs[0x94] = 0x0e; - shadow_regs[0xa3] = 0xcc; - shadow_regs[0xa4] = 0x27; - shadow_regs[0xa5] = 0x24; - shadow_regs[0xb0] = 0xb2; - shadow_regs[0xc2] = 0x80; - shadow_regs[0xc4] = 0x20; - shadow_regs[0xc8] = 0x04; - shadow_regs[0xf4] = 0xf8; - shadow_regs[0xf5] = 0x7f; - - /* set grayscale scan + ? */ - shadow_regs[0x2f] = 0xa1; - - /* set ? */ - shadow_regs[0x34] = 0x50; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x50; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x50; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x00; - /* set vertical start/end positions */ - shadow_regs[0x60] = (SANE_Byte) ((distance - 1) & 0x00FF); - shadow_regs[0x61] = (SANE_Byte) ((distance - 1) >> 8 & 0x00FF); - shadow_regs[0x62] = (SANE_Byte) (distance & 0x00FF); - shadow_regs[0x63] = (SANE_Byte) (distance >> 8 & 0x00FF); - /* set horizontal start position */ - shadow_regs[0x66] = 0x64; - shadow_regs[0x67] = 0x00; - /* set horizontal end position */ - shadow_regs[0x6c] = 0xc8; - shadow_regs[0x6d] = 0x00; - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x01; - /* ???? */ - shadow_regs[0x93] = 0x06; - /* don't buffer data for this scan */ - shadow_regs[0xb2] = 0x04; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x0a; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* step size range2 */ - shadow_regs[0xc9] = 0x3b; - /* ? */ - shadow_regs[0xca] = 0x0a; - /* motor curve stuff */ - - shadow_regs[0xe2] = 0x09; - shadow_regs[0xe3] = 0x1a; - shadow_regs[0xe6] = 0xdc; - shadow_regs[0xe9] = 0x1b; - shadow_regs[0xec] = 0x07; - shadow_regs[0xef] = 0x03; - - - /* Stop scanner - clear reg 0xb3: */ - x1100_stop_mvmt (devnum); - - /* Stop scanner - clear reg 0xb3: - Not sure this is necessary */ - x1100_stop_mvmt (devnum); - - /* Clear C6 why?: - Not sure this is necessary */ - x1100_clr_c6 (devnum); - -/* Move Forward without scanning: */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Stop scanner - clear reg 0xb3: */ - x1100_stop_mvmt (devnum); - - /* Colour depth = 0 (F.O Is this from logfile?); Start moving scanner: */ - x1100_start_mvmt (devnum); - - /* Poll for scanner stopped - return value(3:0) = 0: */ - scan_head_moving = SANE_TRUE; - while (scan_head_moving) - { - cmd_size = 0x04; - x1100_usb_bulk_write (devnum, pollstopmoving_command_block, &cmd_size); - cmd_size = 0x1; - x1100_usb_bulk_read (devnum, &read_result, &cmd_size); - if ((read_result & 0xF) == 0x0) - { - scan_head_moving = SANE_FALSE; - } - } -} - -SANE_Bool -sanei_lexmark_x1100_search_home_fwd (Lexmark_Device * dev) -{ - /* This function actually searches backwards one line looking for home */ - - SANE_Int devnum; - int i; - SANE_Byte poll_result[3]; - SANE_Byte *buffer; - SANE_Byte temp_byte; - - static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; - - static SANE_Byte command5_block[] = { 0x91, 0x00, 0x09, 0xc4 }; - - size_t cmd_size; - SANE_Bool got_line; - SANE_Bool ret_val; - - devnum = dev->devnum; - - DBG (2, "sanei_lexmark_x1100_search_home_fwd:\n"); - - - /* Clear all the shadow registers */ - for (i = 0; i < 255; i++) - shadow_regs[i] = 0; - /* Some regiters are always set the same */ - shadow_regs[0x01] = 0x43; - shadow_regs[0x0b] = 0x70; - shadow_regs[0x11] = 0x01; - shadow_regs[0x12] = 0x0f; - shadow_regs[0x13] = 0x01; - shadow_regs[0x15] = 0x01; - shadow_regs[0x16] = 0x0f; - shadow_regs[0x1d] = 0x20; - shadow_regs[0x28] = 0xeb; - shadow_regs[0x29] = 0xee; - shadow_regs[0x2a] = 0xf7; - shadow_regs[0x2b] = 0x01; - shadow_regs[0x2c] = 0x0f; - shadow_regs[0x2d] = 0x51; - shadow_regs[0x2e] = 0x86; - shadow_regs[0x30] = 0x48; - shadow_regs[0x33] = 0x01; - shadow_regs[0x3a] = 0x20; - shadow_regs[0x3b] = 0x37; - shadow_regs[0x3c] = 0x88; - shadow_regs[0x3d] = 0x08; - shadow_regs[0x40] = 0x80; - shadow_regs[0x65] = 0x80; - shadow_regs[0x72] = 0x05; - shadow_regs[0x74] = 0x0e; - shadow_regs[0x8b] = 0xff; - shadow_regs[0x8c] = 0x02; - shadow_regs[0x8d] = 0x01; - shadow_regs[0x8e] = 0x60; - shadow_regs[0x8f] = 0x80; - shadow_regs[0x94] = 0x0e; - shadow_regs[0xa3] = 0xcc; - shadow_regs[0xa4] = 0x27; - shadow_regs[0xa5] = 0x24; - shadow_regs[0xb0] = 0xb2; - shadow_regs[0xc2] = 0x80; - shadow_regs[0xc4] = 0x20; - shadow_regs[0xc8] = 0x04; - shadow_regs[0xf4] = 0xf8; - shadow_regs[0xf5] = 0x7f; - /* set calibration */ - shadow_regs[0x02] = 0x80; - shadow_regs[0x03] = 0x80; - shadow_regs[0x04] = 0x80; - shadow_regs[0x05] = 0x80; - shadow_regs[0x06] = 0x80; - shadow_regs[0x07] = 0x80; - shadow_regs[0x08] = 0x06; - shadow_regs[0x09] = 0x06; - shadow_regs[0x0a] = 0x06; - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x04; - shadow_regs[0x35] = 0x04; - shadow_regs[0x36] = 0x08; - shadow_regs[0x37] = 0x08; - shadow_regs[0x38] = 0x0b; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x07; - /* set vertical start/end positions */ - shadow_regs[0x60] = 0x01; - shadow_regs[0x61] = 0x00; - shadow_regs[0x62] = 0x02; - shadow_regs[0x63] = 0x00; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - /* set horizontal start position */ - shadow_regs[0x66] = 0x6a; - shadow_regs[0x67] = 0x00; - /* set horizontal end position */ - shadow_regs[0x6c] = 0xf2; - shadow_regs[0x6d] = 0x13; - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x02; - /* set for ? */ - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x01; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x01; - /* step size range2 */ - shadow_regs[0xc9] = 0x3b; - /* step size range0 */ - shadow_regs[0xe2] = 0x01; - /* ? */ - shadow_regs[0xe3] = 0x03; - - - /* Stop the scanner */ - /* cmd_size=0x14; */ - /* x1100_usb_bulk_write(devnum, command2_block, &cmd_size); */ - x1100_stop_mvmt (devnum); - - /* write regs out twice */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Start Scan */ - /* cmd_size=0x23; */ - /* x1100_usb_bulk_write(devnum, command3_block, &cmd_size); */ - x1100_start_mvmt (devnum); - - /* Poll the available byte count until not 0 */ - got_line = SANE_FALSE; - while (!got_line) - { - cmd_size = 4; - x1100_usb_bulk_write (devnum, command4_block, &cmd_size); - cmd_size = 0x3; - x1100_usb_bulk_read (devnum, poll_result, &cmd_size); - if (! - (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) - { - /* if result != 00 00 00 we got data */ - got_line = SANE_TRUE; - } - } - - /* create buffer for scan data */ - buffer = calloc (2500, sizeof (char)); - - /* Tell the scanner to send the data */ - /* Write: 91 00 09 c4 */ - cmd_size = 4; - x1100_usb_bulk_write (devnum, command5_block, &cmd_size); - /* Read it */ - cmd_size = 0x09c4; - x1100_usb_bulk_read (devnum, buffer, &cmd_size); - - /* Reverse order of bytes in words of buffer */ - for (i = 0; i < 2500; i = i + 2) - { - temp_byte = *(buffer + i); - *(buffer + i) = *(buffer + i + 1); - *(buffer + i + 1) = temp_byte; - } - - /* check for home position */ - ret_val = x1100_is_home_line (buffer); - - if (ret_val) - DBG (2, "sanei_lexmark_x1100_search_home_fwd: !!!HOME POSITION!!!\n"); - - /*free the buffer */ - free (buffer); - - return ret_val; -} - - - -SANE_Bool -sanei_lexmark_x1100_search_home_bwd (Lexmark_Device * dev) -{ -/* This funtion must only be called if the scan head is past the home dot. - It could damage the scanner if not. - - This function tells the scanner to do a grayscale scan backwards with a - 300dpi resolution. It reads 2500 bytes of data between horizontal - co-ordinates 0x6a and 0x13f2. - - The scan is set to read between vertical co-ordinates from 0x0a to 0x0f46, - or 3900 lines. This equates to 13" at 300dpi, so we must stop the scan - before it bangs against the end. A line limit is set so that a maximum of - 0x0F3C (13"*300dpi) lines can be read. - - To read the scan data we create a buffer space large enough to hold 10 - lines of data. For each read we poll twice, ingnoring the first poll. This - is required for timing. We repeat the double poll until there is data - available. The number of lines (or number of buffers in our buffer space) - is calculated from the size of the data available from the scanner. The - number of buffers is calculated as the space required to hold 1.5 times - the the size of the data available from the scanner. - - After data is read from the scanner each line is checked if it is on the - home dot. Lines are continued to be read until we are no longer on the home - dot. */ - - - SANE_Int devnum; - int i, j; - SANE_Byte poll_result[3]; - SANE_Byte *buffer; - SANE_Byte *buffer_start; - SANE_Byte temp_byte; - - SANE_Int buffer_limit = 0xF3C; /* should be a define */ - SANE_Int buffer_count = 0; - SANE_Int size_requested; - SANE_Int size_returned; - SANE_Int no_of_buffers; - SANE_Int high_byte, mid_byte, low_byte; - SANE_Int home_line_count; - SANE_Bool in_home_region; - - static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; - - static SANE_Byte command5_block[] = { 0x91, 0x00, 0xff, 0xc0 }; - - size_t cmd_size; - SANE_Bool got_line; - - devnum = dev->devnum; - - DBG (2, "sanei_lexmark_x1100_search_home_bwd:\n"); - /* Clear all the shadow registers */ - for (i = 0; i < 255; i++) - shadow_regs[i] = 0; - /* Some regiters are always set the same */ - shadow_regs[0x01] = 0x43; - shadow_regs[0x0b] = 0x70; - shadow_regs[0x11] = 0x01; - shadow_regs[0x12] = 0x0f; - shadow_regs[0x13] = 0x01; - shadow_regs[0x15] = 0x01; - shadow_regs[0x16] = 0x0f; - shadow_regs[0x1d] = 0x20; - shadow_regs[0x28] = 0xeb; - shadow_regs[0x29] = 0xee; - shadow_regs[0x2a] = 0xf7; - shadow_regs[0x2b] = 0x01; - shadow_regs[0x2c] = 0x0f; - shadow_regs[0x2d] = 0x51; - shadow_regs[0x2e] = 0x86; - shadow_regs[0x30] = 0x48; - shadow_regs[0x33] = 0x01; - shadow_regs[0x3a] = 0x20; - shadow_regs[0x3b] = 0x37; - shadow_regs[0x3c] = 0x88; - shadow_regs[0x3d] = 0x08; - shadow_regs[0x40] = 0x80; - shadow_regs[0x65] = 0x80; - shadow_regs[0x72] = 0x05; - shadow_regs[0x74] = 0x0e; - shadow_regs[0x8b] = 0xff; - shadow_regs[0x8c] = 0x02; - shadow_regs[0x8d] = 0x01; - shadow_regs[0x8e] = 0x60; - shadow_regs[0x8f] = 0x80; - shadow_regs[0x94] = 0x0e; - shadow_regs[0xa3] = 0xcc; - shadow_regs[0xa4] = 0x27; - shadow_regs[0xa5] = 0x24; - shadow_regs[0xb0] = 0xb2; - shadow_regs[0xc2] = 0x80; - shadow_regs[0xc4] = 0x20; - shadow_regs[0xc8] = 0x04; - shadow_regs[0xf4] = 0xf8; - shadow_regs[0xf5] = 0x7f; - /* set calibration */ - shadow_regs[0x02] = 0x80; - shadow_regs[0x03] = 0x80; - shadow_regs[0x04] = 0x80; - shadow_regs[0x05] = 0x80; - shadow_regs[0x06] = 0x80; - shadow_regs[0x07] = 0x80; - shadow_regs[0x08] = 0x06; - shadow_regs[0x09] = 0x06; - shadow_regs[0x0a] = 0x06; - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x07; - shadow_regs[0x35] = 0x07; - shadow_regs[0x36] = 0x0f; - shadow_regs[0x37] = 0x0f; - shadow_regs[0x38] = 0x15; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x03; - /* set vertical start/end positions */ - shadow_regs[0x60] = 0x0a; - shadow_regs[0x61] = 0x00; - shadow_regs[0x62] = 0x46; - shadow_regs[0x63] = 0x0f; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x02; - /* set horizontal start position */ - shadow_regs[0x66] = 0x6a; - shadow_regs[0x67] = 0x00; - /* set horizontal end position */ - shadow_regs[0x6c] = 0xf2; - shadow_regs[0x6d] = 0x13; - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x02; - /* set for ? */ - shadow_regs[0x85] = 0x20; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x19; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x01; - /* step size range2 */ - shadow_regs[0xc9] = 0x3a; - /* ? */ - shadow_regs[0xca] = 0x08; - /* motor curve stuff */ - shadow_regs[0xe0] = 0xe3; - shadow_regs[0xe1] = 0x18; - shadow_regs[0xe2] = 0x03; - shadow_regs[0xe3] = 0x06; - shadow_regs[0xe4] = 0x2b; - shadow_regs[0xe5] = 0x17; - shadow_regs[0xe6] = 0xdc; - shadow_regs[0xe7] = 0xb3; - shadow_regs[0xe8] = 0x07; - shadow_regs[0xe9] = 0x1b; - shadow_regs[0xec] = 0x07; - shadow_regs[0xef] = 0x03; - - /* Stop the scanner */ - x1100_stop_mvmt (devnum); - - /* write regs out twice */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Start Scan */ - x1100_start_mvmt (devnum); - - /* create buffer to hold up to 10 lines of scan data */ - buffer = calloc (10 * 2500, sizeof (char)); - - home_line_count = 0; - in_home_region = SANE_FALSE; - - while (buffer_count < buffer_limit) - { - size_returned = 0; - got_line = SANE_FALSE; - while (!got_line) - { - /* always poll twice (needed for timing) - disregard 1st poll */ - cmd_size = 4; - x1100_usb_bulk_write (devnum, command4_block, &cmd_size); - cmd_size = 0x3; - x1100_usb_bulk_read (devnum, poll_result, &cmd_size); - cmd_size = 4; - x1100_usb_bulk_write (devnum, command4_block, &cmd_size); - cmd_size = 0x3; - x1100_usb_bulk_read (devnum, poll_result, &cmd_size); - if (! - (poll_result[0] == 0 && poll_result[1] == 0 - && poll_result[2] == 0)) - { - /* if result != 00 00 00 we got data */ - got_line = SANE_TRUE; - high_byte = poll_result[2] << 16; - mid_byte = poll_result[1] << 8; - low_byte = poll_result[0]; - size_returned = high_byte + mid_byte + low_byte; - } - } - - size_requested = size_returned; - no_of_buffers = size_returned * 3; - no_of_buffers = no_of_buffers / 0x9C4; - no_of_buffers = no_of_buffers >> 1; - - if (no_of_buffers < 1) - no_of_buffers = 1; - else if (no_of_buffers > 10) - no_of_buffers = 10; - buffer_count = buffer_count + no_of_buffers; - size_requested = no_of_buffers * 0x9C4; - - /* Tell the scanner to send the data */ - /* Write: 91 */ - command5_block[1] = (SANE_Byte) (size_requested >> 16); - command5_block[2] = (SANE_Byte) (size_requested >> 8); - command5_block[3] = (SANE_Byte) (size_requested & 0xFF); - - cmd_size = 4; - x1100_usb_bulk_write (devnum, command5_block, &cmd_size); - /* Read it */ - cmd_size = size_requested; - x1100_usb_bulk_read (devnum, buffer, &cmd_size); - - for (i = 0; i < no_of_buffers; i++) - { - buffer_start = buffer + (i * 0x9c4); - /* Reverse order of bytes in words of buffer */ - for (j = 0; j < 2500; j = j + 2) - { - temp_byte = *(buffer_start + j); - *(buffer_start + j) = *(buffer_start + j + 1); - *(buffer_start + j + 1) = temp_byte; - } - if (x1100_is_home_line (buffer_start)) - { - home_line_count++; - in_home_region = SANE_TRUE; - } - else if (in_home_region) - { - free (buffer); - x1100_stop_mvmt (devnum); - return SANE_TRUE; - } - } - } /* end while (buffer_count > buffer_limit); */ - free (buffer); - x1100_stop_mvmt (devnum); - - /* Move forward to approximately the middle of the dot */ - sanei_lexmark_x1100_move_fwd (0x4c, dev); - - return SANE_FALSE; - -} - -SANE_Status -x1100_get_start_loc (SANE_Int resolution, SANE_Int * vert_start, - SANE_Int * hor_start, SANE_Int offset) -{ - SANE_Int start_600; - - /* Calculate vertical start distance at 600dpi */ - start_600 = 195 - offset; - - - switch (resolution) - { - case 75: - *vert_start = start_600 / 8; - *hor_start = 0x68; - break; - case 150: - *vert_start = start_600 / 4; - *hor_start = 0x68; - break; - case 300: - *vert_start = start_600 / 2; - *hor_start = 0x6a; - break; - case 600: - *vert_start = start_600; - *hor_start = 0x6b; - break; - case 1200: - *vert_start = start_600 * 2; - *hor_start = 0x6b; - break; - default: - /* If we're here we have an invalid resolution */ - return SANE_STATUS_INVAL; - } - - return SANE_STATUS_GOOD; -} - -void -x1100_set_scan_area (SANE_Int res, SANE_Bool isColour, SANE_Int pixel_height, - SANE_Int pixel_width, SANE_Int offset) -{ - - SANE_Status status; - SANE_Int vert_start; - SANE_Int hor_start; - SANE_Int vert_end; - SANE_Int hor_end; - SANE_Int hor_res; - unsigned long vert_dist; - - status = - x1100_get_start_loc (res, &vert_start, &hor_start, offset); - - /* convert pixel height to vertical location coordinates */ - vert_dist = pixel_height + 2; - if ((res >= 600) && (isColour)) - vert_dist = vert_dist * 2; - vert_end = vert_start + vert_dist; - /* set vertical start position registers */ - shadow_regs[0x60] = vert_start & 0xFF; - shadow_regs[0x61] = (vert_start >> 8) & 0xFF; - /* set vertical end position registers */ - shadow_regs[0x62] = (vert_end & 0xFF) + 2; /*F.O. TEST! */ - shadow_regs[0x63] = (vert_end >> 8) & 0xFF; - - - /* convert pixel width to horizontal location coordinates */ - hor_res = res; - if (hor_res > 600) - hor_res = 600; - hor_end = hor_start + (600 * pixel_width) / hor_res; - - /* set horizontal start position registers */ - shadow_regs[0x66] = hor_start & 0xFF; - shadow_regs[0x67] = (hor_start >> 8) & 0xFF; - /* set horizontal end position registers */ - shadow_regs[0x6c] = hor_end & 0xFF; - shadow_regs[0x6d] = (hor_end >> 8) & 0xFF; - - /* Debug */ - - DBG (2, "x1100_set_scan_area: vert_start: %x\n", vert_start); - DBG (2, "x1100_set_scan_area: vert_end: %x\n", vert_end); - DBG (2, "x1100_set_scan_area: hor_start: %x\n", hor_start); - DBG (2, "x1100_set_scan_area: hor_end: %x\n", hor_end); - -} - -SANE_Int -sanei_lexmark_x1100_find_start_line (SANE_Int devnum) -{ - /* - This function scans forward 59 lines, reading 88 bytes per line from the - middle of the horizontal line: pixel 0xa84 to pixel 0x9d4. It scans with - the following parameters: - dir=fwd - mode=grayscale - h.res=300 dpi - v.res=600 dpi - hor. pixels = (0xa84 - 0x9d4)/2 = 0x58 = 88 - vert. pixels = 0x3e - 0x03 = 0x3b = 59 - data = 88x59=5192=0x1448 - - It assumes we are in the start dot, or just before it. We are reading - enough lines at 600dpi to read past the dot. We return the number of - entirely white lines read consecutively, so we know how far past the - dot we are. - - To find the number of consecutive white lines we do the following: - - Byte swap the order of the bytes in the buffer. - - Go through the buffer finding low and high values, which are computed by - comparing to the weighted average: - weighted_average = (lowest value + (highest value - lowest value)/4) - Low bytes are changed to 0xFF (white), higher of equal bytes are changed - to 0x00 (black),so that the buffer only contains white (0xFF) or black - (0x00) values. - - Next, we go through the buffer a line (88 bytes) at a time for 59 lines - to read the entire buffer. For each byte in a line we check if the - byte is black. If it is we increment the black byte counter. - - After each line we check the black byte counter. If it is greater than 0 - we increment the black line count and set the white line count to 0. If - there were no black bytes in the line we set the black line count to 0 - and increment the white line count. - - When all lines have been processed we return the white line count. - */ - - - int blackLineCount = 0; - int whiteLineCount = 0; - int blackByteCounter = 0; - unsigned char max_byte = 0; - unsigned char min_byte = 0xFF; - unsigned char weighted_average; - int i, j; - - SANE_Byte poll_result[3]; - SANE_Byte *buffer; - SANE_Byte temp_byte; - - static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; - - static SANE_Byte command5_block[] = { 0x91, 0x00, 0x14, 0x48 }; - - size_t cmd_size; - SANE_Bool got_line; - - /* Clear all the shadow registers */ - for (i = 0; i < 255; i++) - shadow_regs[i] = 0; - /* Some regiters are always set the same */ - shadow_regs[0x01] = 0x43; - shadow_regs[0x0b] = 0x70; - shadow_regs[0x11] = 0x01; - shadow_regs[0x12] = 0x0f; - shadow_regs[0x13] = 0x01; - shadow_regs[0x15] = 0x01; - shadow_regs[0x16] = 0x0f; - shadow_regs[0x1d] = 0x20; - shadow_regs[0x28] = 0xeb; - shadow_regs[0x29] = 0xee; - shadow_regs[0x2a] = 0xf7; - shadow_regs[0x2b] = 0x01; - shadow_regs[0x2c] = 0x0f; - shadow_regs[0x2d] = 0x51; - shadow_regs[0x2e] = 0x86; - shadow_regs[0x30] = 0x48; - shadow_regs[0x33] = 0x01; - shadow_regs[0x3a] = 0x20; - shadow_regs[0x3b] = 0x37; - shadow_regs[0x3c] = 0x88; - shadow_regs[0x3d] = 0x08; - shadow_regs[0x40] = 0x80; - shadow_regs[0x65] = 0x80; - shadow_regs[0x72] = 0x05; - shadow_regs[0x74] = 0x0e; - shadow_regs[0x8b] = 0xff; - shadow_regs[0x8c] = 0x02; - shadow_regs[0x8d] = 0x01; - shadow_regs[0x8e] = 0x60; - shadow_regs[0x8f] = 0x80; - shadow_regs[0x94] = 0x0e; - shadow_regs[0xa3] = 0xcc; - shadow_regs[0xa4] = 0x27; - shadow_regs[0xa5] = 0x24; - shadow_regs[0xb0] = 0xb2; - shadow_regs[0xc2] = 0x80; - shadow_regs[0xc4] = 0x20; - shadow_regs[0xc8] = 0x04; - shadow_regs[0xf4] = 0xf8; - shadow_regs[0xf5] = 0x7f; - /* set calibration */ - shadow_regs[0x02] = 0x80; - shadow_regs[0x03] = 0x80; - shadow_regs[0x04] = 0x80; - shadow_regs[0x05] = 0x80; - shadow_regs[0x06] = 0x80; - shadow_regs[0x07] = 0x80; - shadow_regs[0x08] = 0x06; - shadow_regs[0x09] = 0x06; - shadow_regs[0x0a] = 0x06; - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x0d; - shadow_regs[0x35] = 0x0d; - shadow_regs[0x36] = 0x1d; - shadow_regs[0x37] = 0x1d; - shadow_regs[0x38] = 0x29; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x01; - /* set vertical start/end positions */ - shadow_regs[0x60] = 0x03; - shadow_regs[0x61] = 0x00; - shadow_regs[0x62] = 0x3e; - shadow_regs[0x63] = 0x00; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - /* set horizontal start position */ - shadow_regs[0x66] = 0xd4; - shadow_regs[0x67] = 0x09; - /* set horizontal end position */ - shadow_regs[0x6c] = 0x84; - shadow_regs[0x6d] = 0x0a; - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x02; - /* set for ? */ - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* set for ? */ - shadow_regs[0xc5] = 0x22; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* step size range2 */ - shadow_regs[0xc9] = 0x3b; - /* set for ? */ - shadow_regs[0xca] = 0x1f; - shadow_regs[0xe0] = 0xf7; - shadow_regs[0xe1] = 0x16; - /* step size range0 */ - shadow_regs[0xe2] = 0x87; - /* ? */ - shadow_regs[0xe3] = 0x13; - shadow_regs[0xe4] = 0x1b; - shadow_regs[0xe5] = 0x16; - shadow_regs[0xe6] = 0xdc; - shadow_regs[0xe9] = 0x1b; - shadow_regs[0xec] = 0x07; - shadow_regs[0xef] = 0x03; - - /* Stop the scanner */ - x1100_stop_mvmt (devnum); - - /* write regs out twice */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Start Scan */ - /* cmd_size=0x23; */ - /* x1100_usb_bulk_write(devnum, command3_block, &cmd_size); */ - x1100_start_mvmt (devnum); - - /* Poll the available byte count until not 0 */ - got_line = SANE_FALSE; - while (!got_line) - { - cmd_size = 4; - x1100_usb_bulk_write (devnum, command4_block, &cmd_size); - cmd_size = 0x3; - x1100_usb_bulk_read (devnum, poll_result, &cmd_size); - if (! - (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) - { - /* if result != 00 00 00 we got data */ - got_line = SANE_TRUE; - } - } - - - /* create buffer for scan data */ - buffer = calloc (5192, sizeof (char)); - - /* Tell the scanner to send the data */ - /* Write: 91 00 14 48 */ - cmd_size = 4; - x1100_usb_bulk_write (devnum, command5_block, &cmd_size); - /* Read it */ - cmd_size = 0x1448; - x1100_usb_bulk_read (devnum, buffer, &cmd_size); - - /* Stop the scanner */ - x1100_stop_mvmt (devnum); - - - /* Reverse order of bytes in words of buffer */ - for (i = 0; i < 5192; i = i + 2) - { - temp_byte = *(buffer + i); - *(buffer + i) = *(buffer + i + 1); - *(buffer + i + 1) = temp_byte; - } - /* Find the max and the min */ - for (i = 0; i < 5192; i++) - { - if (*(buffer + i) > max_byte) - max_byte = *(buffer + i); - if (*(buffer + i) < min_byte) - min_byte = *(buffer + i); - } - - weighted_average = min_byte + ((max_byte - min_byte) / 4); - - /* Set bytes as black (0x00) or white (0xFF) */ - for (i = 0; i < 5192; i++) - { - if (*(buffer + i) > weighted_average) - *(buffer + i) = 0xFF; - else - *(buffer + i) = 0x00; - } - /* Go through 59 lines */ - for (j = 0; j < 59; j++) - { - blackByteCounter = 0; - /* Go through 88 bytes per line */ - for (i = 0; i < 88; i++) - { - /* Is byte black? */ - if (*(buffer + (j * 88) + i) == 0) - { - blackByteCounter++; - } - } /* end for line*/ - if (blackByteCounter > 0) - { - /* This was a black line */ - blackLineCount++; - whiteLineCount = 0; - } - else - { - /* This is a white line */ - whiteLineCount++; - blackLineCount = 0; - } - } /* end for buffer */ - - return whiteLineCount; - -} - - -SANE_Status -sanei_lexmark_x1100_set_scan_regs (Lexmark_Device * dev, SANE_Int offset) -{ - SANE_Int yres; - SANE_Bool isColourScan; - int i; - - /* resolution */ - yres = dev->val[OPT_RESOLUTION].w; - - /* colour mode */ - if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) - isColourScan = SANE_TRUE; - else - isColourScan = SANE_FALSE; - - /* Clear all the shadow registers */ - for (i = 0; i < 255; i++) - shadow_regs[i] = 0; - /* Some regiters are always set the same */ - shadow_regs[0x01] = 0x43; - shadow_regs[0x0b] = 0x70; - shadow_regs[0x11] = 0x01; - shadow_regs[0x12] = 0x0f; - shadow_regs[0x13] = 0x01; - shadow_regs[0x15] = 0x01; - shadow_regs[0x16] = 0x0f; - shadow_regs[0x1d] = 0x20; - shadow_regs[0x28] = 0xeb; - shadow_regs[0x29] = 0xee; - shadow_regs[0x2a] = 0xf7; - shadow_regs[0x2b] = 0x01; - shadow_regs[0x2c] = 0x0f; - shadow_regs[0x2d] = 0x51; - shadow_regs[0x2e] = 0x86; - shadow_regs[0x30] = 0x48; - shadow_regs[0x33] = 0x01; - shadow_regs[0x3a] = 0x20; - shadow_regs[0x3b] = 0x37; - shadow_regs[0x3c] = 0x88; - shadow_regs[0x3d] = 0x08; - shadow_regs[0x40] = 0x80; - shadow_regs[0x65] = 0x80; - shadow_regs[0x72] = 0x05; - shadow_regs[0x74] = 0x0e; - shadow_regs[0x8b] = 0xff; - shadow_regs[0x8c] = 0x02; - shadow_regs[0x8d] = 0x01; - shadow_regs[0x8e] = 0x60; - shadow_regs[0x8f] = 0x80; - shadow_regs[0x94] = 0x0e; - shadow_regs[0xa3] = 0xcc; - shadow_regs[0xa4] = 0x27; - shadow_regs[0xa5] = 0x24; - shadow_regs[0xb0] = 0xb2; - shadow_regs[0xc2] = 0x80; - shadow_regs[0xc4] = 0x20; - shadow_regs[0xc8] = 0x04; - shadow_regs[0xf4] = 0xf8; - shadow_regs[0xf5] = 0x7f; - - - /* size */ - x1100_set_scan_area (yres, isColourScan, dev->pixel_height, - dev->pixel_width, offset); - - /*75dpi x 75dpi */ - if (yres == 75) - { - DBG (5, "sanei_lexmark_x1100_set_scan_regs(): 75 DPI resolution\n"); - /* set calibration */ - shadow_regs[0x02] = 0xa1; - shadow_regs[0x03] = 0x9d; - shadow_regs[0x04] = 0xa3; - shadow_regs[0x05] = 0xa1; - shadow_regs[0x06] = 0x9d; - shadow_regs[0x07] = 0xa3; - shadow_regs[0x08] = 0x0a; - shadow_regs[0x09] = 0x0b; - shadow_regs[0x0a] = 0x06; - - if (isColourScan) - { - /* set colour scan */ - shadow_regs[0x2f] = 0x11; - /* set ? */ - shadow_regs[0x34] = 0x05; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x05; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x05; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x0f; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x22; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x1a; */ -/* shadow_regs[0x63]=0x01; */ - /* set ? */ - shadow_regs[0x80] = 0x0c; - shadow_regs[0x81] = 0x0c; - shadow_regs[0x82] = 0x09; - shadow_regs[0x85] = 0x00; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x8c; - shadow_regs[0x92] = 0x40; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x83; - /* ? */ - shadow_regs[0xc5] = 0x0a; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3b; - shadow_regs[0xca] = 0x01; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x2b; - shadow_regs[0xe1] = 0x0a; - /* step size range0 */ - shadow_regs[0xe2] = 0x7f; - /* ? */ - shadow_regs[0xe3] = 0x01; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0xbb; - shadow_regs[0xe5] = 0x09; - /* step size range1 */ - shadow_regs[0xe6] = 0x0e; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x2b; - shadow_regs[0xe8] = 0x03; - /* step size range2 */ - shadow_regs[0xe9] = 0x05; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0xa0; - shadow_regs[0xeb] = 0x01; - /* step size range3 */ - shadow_regs[0xec] = 0x01; - /* step size range4 */ - shadow_regs[0xef] = 0x01; - - } - else - { - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x02; - shadow_regs[0x35] = 0x02; - shadow_regs[0x36] = 0x04; - shadow_regs[0x37] = 0x04; - shadow_regs[0x38] = 0x06; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x0f; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x14; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x8d; */ -/* shadow_regs[0x63]=0x01; */ - /* set ? only for colour? */ - shadow_regs[0x80] = 0x00; - shadow_regs[0x81] = 0x00; - shadow_regs[0x82] = 0x00; - shadow_regs[0x85] = 0x20; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x00; - shadow_regs[0x92] = 0x00; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x10; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3b; - shadow_regs[0xca] = 0x01; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x4d; - shadow_regs[0xe1] = 0x1c; - /* step size range0 */ - shadow_regs[0xe2] = 0x71; - /* ? */ - shadow_regs[0xe3] = 0x02; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x6d; - shadow_regs[0xe5] = 0x15; - /* step size range1 */ - shadow_regs[0xe6] = 0xdc; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0xad; - shadow_regs[0xe8] = 0x07; - /* step size range2 */ - shadow_regs[0xe9] = 0x1b; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0xe1; - shadow_regs[0xeb] = 0x03; - /* step size range3 */ - shadow_regs[0xec] = 0x07; - /* bounds of movement range4 -only for 75dpi grayscale */ - shadow_regs[0xed] = 0xc2; - shadow_regs[0xee] = 0x02; - /* step size range4 */ - shadow_regs[0xef] = 0x03; - } - - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - /* set horizontal start position */ -/* shadow_regs[0x66]=0x68; */ -/* shadow_regs[0x67]=0x00; */ - /* set horizontal end position */ -/* shadow_regs[0x6c]=0x78; */ -/* shadow_regs[0x6d]=0x07; */ - /* set horizontal resolution */ - shadow_regs[0x79] = 0x08; - shadow_regs[0x7a] = 0x08; - - } - - /*150dpi x 150dpi */ - if (yres == 150) - { - DBG (5, "sanei_lexmark_x1100_set_scan_regs(): 150 DPI resolution\n"); - /* set calibration */ - shadow_regs[0x02] = 0xa1; - shadow_regs[0x03] = 0xa1; - shadow_regs[0x04] = 0xa3; - shadow_regs[0x05] = 0xa1; - shadow_regs[0x06] = 0xa1; - shadow_regs[0x07] = 0xa3; - shadow_regs[0x08] = 0x0a; - shadow_regs[0x09] = 0x0a; - shadow_regs[0x0a] = 0x06; - - - if (isColourScan) - { - /* set colour scan */ - shadow_regs[0x2f] = 0x11; - /* set ? */ - shadow_regs[0x34] = 0x0b; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x0b; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x0a; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x07; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x22; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x12; */ -/* shadow_regs[0x63]=0x03; */ - /* set ? */ - shadow_regs[0x80] = 0x05; - shadow_regs[0x81] = 0x05; - shadow_regs[0x82] = 0x0a; - shadow_regs[0x85] = 0x83; - shadow_regs[0x86] = 0x7e; - shadow_regs[0x87] = 0xad; - shadow_regs[0x88] = 0x35; - shadow_regs[0x91] = 0xfe; - shadow_regs[0x92] = 0xdf; - shadow_regs[0x93] = 0x0e; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x83; - /* ? */ - shadow_regs[0xc5] = 0x0e; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x03; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x61; - shadow_regs[0xe1] = 0x0a; - /* step size range0 */ - shadow_regs[0xe2] = 0xed; - /* ? */ - shadow_regs[0xe3] = 0x02; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x29; - shadow_regs[0xe5] = 0x0a; - /* step size range1 */ - shadow_regs[0xe6] = 0x0e; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x29; - shadow_regs[0xe8] = 0x03; - /* step size range2 */ - shadow_regs[0xe9] = 0x05; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x01; - /* step size range4 */ - shadow_regs[0xef] = 0x01; - - } - else - { - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x04; - shadow_regs[0x35] = 0x04; - shadow_regs[0x36] = 0x07; - shadow_regs[0x37] = 0x07; - shadow_regs[0x38] = 0x0a; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x07; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x20; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x10; */ -/* shadow_regs[0x63]=0x03; */ - /* set ? only for colour? */ - shadow_regs[0x80] = 0x00; - shadow_regs[0x81] = 0x00; - shadow_regs[0x82] = 0x00; - shadow_regs[0x85] = 0x00; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x00; - shadow_regs[0x92] = 0x00; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x16; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3b; - shadow_regs[0xca] = 0x01; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0xdd; - shadow_regs[0xe1] = 0x18; - /* step size range0 */ - shadow_regs[0xe2] = 0x01; - /* ? */ - shadow_regs[0xe3] = 0x03; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x6d; - shadow_regs[0xe5] = 0x15; - /* step size range1 */ - shadow_regs[0xe6] = 0xdc; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0xad; - shadow_regs[0xe8] = 0x07; - /* step size range2 */ - shadow_regs[0xe9] = 0x1b; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0xe1; - shadow_regs[0xeb] = 0x03; - /* step size range3 */ - shadow_regs[0xec] = 0x07; - /* step size range4 */ - shadow_regs[0xef] = 0x03; - } - - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - /* set horizontal start position */ -/* shadow_regs[0x66]=0x68; */ -/* shadow_regs[0x67]=0x00; */ - /* set horizontal end position */ -/* shadow_regs[0x6c]=0x70; */ -/* shadow_regs[0x6d]=0x07; */ - /* set horizontal resolution */ - shadow_regs[0x79] = 0x08; - shadow_regs[0x7a] = 0x04; - - } - - /*300dpi x 300dpi */ - if (yres == 300) - { - DBG (5, "sanei_lexmark_x1100_set_scan_regs(): 300 DPI resolution\n"); - /* set calibration */ - shadow_regs[0x02] = 0xa1; - shadow_regs[0x03] = 0xa1; - shadow_regs[0x04] = 0xa3; - shadow_regs[0x05] = 0xa1; - shadow_regs[0x06] = 0xa1; - shadow_regs[0x07] = 0xa3; - shadow_regs[0x08] = 0x0a; - shadow_regs[0x09] = 0x0a; - shadow_regs[0x0a] = 0x06; - - if (isColourScan) - { - /* set colour scan */ - shadow_regs[0x2f] = 0x11; - /* set ? */ - shadow_regs[0x34] = 0x15; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x15; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x14; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x03; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x44; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x22; */ -/* shadow_regs[0x63]=0x06; */ - /* set ? */ - shadow_regs[0x80] = 0x0a; - shadow_regs[0x81] = 0x0a; - shadow_regs[0x82] = 0x06; - shadow_regs[0x85] = 0x83; - shadow_regs[0x86] = 0x7e; - shadow_regs[0x87] = 0xad; - shadow_regs[0x88] = 0x35; - shadow_regs[0x91] = 0xfe; - shadow_regs[0x92] = 0xdf; - shadow_regs[0x93] = 0x0e; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x83; - /* ? */ - shadow_regs[0xc5] = 0x17; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x0a; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x75; - shadow_regs[0xe1] = 0x0a; - /* step size range0 */ - shadow_regs[0xe2] = 0xdd; - /* ? */ - shadow_regs[0xe3] = 0x05; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x59; - shadow_regs[0xe5] = 0x0a; - /* step size range1 */ - shadow_regs[0xe6] = 0x0e; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x00; - shadow_regs[0xe8] = 0x00; - /* step size range2 */ - shadow_regs[0xe9] = 0x05; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x01; - /* step size range4 */ - shadow_regs[0xef] = 0x01; - } - else - { - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x08; - shadow_regs[0x35] = 0x08; - shadow_regs[0x36] = 0x0f; - shadow_regs[0x37] = 0x0f; - shadow_regs[0x38] = 0x16; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x03; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x40; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0xfe; */ -/* shadow_regs[0x63]=0x06; */ - /* set ? only for colour? */ - shadow_regs[0x80] = 0x00; - shadow_regs[0x81] = 0x00; - shadow_regs[0x82] = 0x00; - shadow_regs[0x85] = 0x00; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x00; - shadow_regs[0x92] = 0x00; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x19; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x08; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0xe3; - shadow_regs[0xe1] = 0x18; - /* step size range0 */ - shadow_regs[0xe2] = 0x03; - /* ? */ - shadow_regs[0xe3] = 0x06; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x2b; - shadow_regs[0xe5] = 0x17; - /* step size range1 */ - shadow_regs[0xe6] = 0xdc; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0xb3; - shadow_regs[0xe8] = 0x07; - /* step size range2 */ - shadow_regs[0xe9] = 0x1b; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x07; - /* step size range4 */ - shadow_regs[0xef] = 0x03; - } - - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - /* set horizontal start position */ - /* shadow_regs[0x66]=0x6a; */ -/* shadow_regs[0x67]=0x00; */ - /* set horizontal end position */ -/* shadow_regs[0x6c]=0x72; */ -/* shadow_regs[0x6d]=0x07; */ - /* set horizontal resolution */ - shadow_regs[0x79] = 0x20; - shadow_regs[0x7a] = 0x02; - - } - - /*600dpi x 600dpi */ - if (yres == 600) - { - DBG (5, "sanei_lexmark_x1100_set_scan_regs(): 600 DPI resolution\n"); - /* set calibration */ - shadow_regs[0x02] = 0xa1; - shadow_regs[0x03] = 0xa1; - shadow_regs[0x04] = 0xa3; - shadow_regs[0x05] = 0xa1; - shadow_regs[0x06] = 0xa1; - shadow_regs[0x07] = 0xa3; - shadow_regs[0x08] = 0x0a; - shadow_regs[0x09] = 0x0a; - shadow_regs[0x0a] = 0x06; - - if (isColourScan) - { - /* set colour scan */ - shadow_regs[0x2f] = 0x11; - /* set ? */ - shadow_regs[0x34] = 0x15; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x15; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x14; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x03; - /* set vertical start/end positions */ -/* shadow_regs[0x60]=0x14; */ -/* shadow_regs[0x61]=0x00; */ -/* shadow_regs[0x62]=0x88; */ -/* shadow_regs[0x63]=0x17; */ - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x02; - /* set ? */ - shadow_regs[0x80] = 0x02; - shadow_regs[0x81] = 0x02; - shadow_regs[0x82] = 0x08; - shadow_regs[0x85] = 0x83; - shadow_regs[0x86] = 0x7e; - shadow_regs[0x87] = 0xad; - shadow_regs[0x88] = 0x35; - shadow_regs[0x91] = 0xfe; - shadow_regs[0x92] = 0xdf; - shadow_regs[0x93] = 0x0e; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x86; - /* ? */ - shadow_regs[0xc5] = 0x27; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x0c; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x1a; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x57; - shadow_regs[0xe1] = 0x0a; - /* step size range0 */ - shadow_regs[0xe2] = 0xbf; - /* ? */ - shadow_regs[0xe3] = 0x05; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x3b; - shadow_regs[0xe5] = 0x0a; - /* step size range1 */ - shadow_regs[0xe6] = 0x0e; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x00; - shadow_regs[0xe8] = 0x00; - /* step size range2 */ - shadow_regs[0xe9] = 0x05; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x01; - /* step size range4 */ - shadow_regs[0xef] = 0x01; - } - else - { - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x11; - shadow_regs[0x35] = 0x11; - shadow_regs[0x36] = 0x21; - shadow_regs[0x37] = 0x21; - shadow_regs[0x38] = 0x31; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x01; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x01; - - /* set ? only for colour? */ - shadow_regs[0x80] = 0x00; - shadow_regs[0x81] = 0x00; - shadow_regs[0x82] = 0x00; - shadow_regs[0x85] = 0x00; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x00; - shadow_regs[0x92] = 0x00; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x22; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3b; - shadow_regs[0xca] = 0x1f; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0xf7; - shadow_regs[0xe1] = 0x16; - /* step size range0 */ - shadow_regs[0xe2] = 0x87; - /* ? */ - shadow_regs[0xe3] = 0x13; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x1b; - shadow_regs[0xe5] = 0x16; - /* step size range1 */ - shadow_regs[0xe6] = 0xdc; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x00; - shadow_regs[0xe8] = 0x00; - /* step size range2 */ - shadow_regs[0xe9] = 0x1b; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x07; - /* step size range4 */ - shadow_regs[0xef] = 0x03; - } - - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x01; - - } - /*600dpi x 1200dpi */ - if (yres == 1200) - { - DBG (5, "sanei_lexmark_x1100_set_scan_regs(): 1200 DPI resolution\n"); - /* set calibration */ - shadow_regs[0x02] = 0xa1; - shadow_regs[0x03] = 0xa1; - shadow_regs[0x04] = 0xa3; - shadow_regs[0x05] = 0xa1; - shadow_regs[0x06] = 0xa1; - shadow_regs[0x07] = 0xa3; - shadow_regs[0x08] = 0x0a; - shadow_regs[0x09] = 0x0a; - shadow_regs[0x0a] = 0x06; - - if (isColourScan) - { - /* set colour scan */ - shadow_regs[0x2f] = 0x11; - /* set ? */ - shadow_regs[0x34] = 0x29; - shadow_regs[0x35] = 0x01; - shadow_regs[0x36] = 0x29; - shadow_regs[0x37] = 0x01; - shadow_regs[0x38] = 0x28; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x01; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x02; - /* set ? */ - shadow_regs[0x80] = 0x04; - shadow_regs[0x81] = 0x04; - shadow_regs[0x82] = 0x08; - shadow_regs[0x85] = 0x83; - shadow_regs[0x86] = 0x7e; - shadow_regs[0x87] = 0xad; - shadow_regs[0x88] = 0x35; - shadow_regs[0x91] = 0xfe; - shadow_regs[0x92] = 0xdf; - shadow_regs[0x93] = 0x0e; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x86; - /* ? */ - shadow_regs[0xc5] = 0x41; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x0c; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x40; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x00; - shadow_regs[0xe1] = 0x00; - /* step size range0 */ - shadow_regs[0xe2] = 0x85; - /* ? */ - shadow_regs[0xe3] = 0x0b; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x00; - shadow_regs[0xe5] = 0x00; - /* step size range1 */ - shadow_regs[0xe6] = 0x0e; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x00; - shadow_regs[0xe8] = 0x00; - /* step size range2 */ - shadow_regs[0xe9] = 0x05; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x01; - /* step size range4 */ - shadow_regs[0xef] = 0x01; - } - else - { - /* set grayscale scan */ - shadow_regs[0x2f] = 0x21; - /* set ? */ - shadow_regs[0x34] = 0x22; - shadow_regs[0x35] = 0x22; - shadow_regs[0x36] = 0x42; - shadow_regs[0x37] = 0x42; - shadow_regs[0x38] = 0x62; - /* set motor resolution divisor */ - shadow_regs[0x39] = 0x01; - /* set # of head moves per CIS read */ - shadow_regs[0x64] = 0x00; - - /* set ? only for colour? */ - shadow_regs[0x80] = 0x00; - shadow_regs[0x81] = 0x00; - shadow_regs[0x82] = 0x00; - shadow_regs[0x85] = 0x00; - shadow_regs[0x86] = 0x00; - shadow_regs[0x87] = 0x00; - shadow_regs[0x88] = 0x00; - shadow_regs[0x91] = 0x00; - shadow_regs[0x92] = 0x00; - shadow_regs[0x93] = 0x06; - /* Motor enable & Coordinate space denominator */ - shadow_regs[0xc3] = 0x81; - /* ? */ - shadow_regs[0xc5] = 0x41; - /* Movement direction & step size */ - shadow_regs[0xc6] = 0x09; - /* ? */ - shadow_regs[0xc9] = 0x3a; - shadow_regs[0xca] = 0x40; - /* bounds of movement range0 */ - shadow_regs[0xe0] = 0x00; - shadow_regs[0xe1] = 0x00; - /* step size range0 */ - shadow_regs[0xe2] = 0xc7; - /* ? */ - shadow_regs[0xe3] = 0x29; - /* bounds of movement range1 */ - shadow_regs[0xe4] = 0x00; - shadow_regs[0xe5] = 0x00; - /* step size range1 */ - shadow_regs[0xe6] = 0xdc; - /* bounds of movement range2 */ - shadow_regs[0xe7] = 0x00; - shadow_regs[0xe8] = 0x00; - /* step size range2 */ - shadow_regs[0xe9] = 0x1b; - /* bounds of movement range3 */ - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - /* step size range3 */ - shadow_regs[0xec] = 0x07; - /* step size range4 */ - shadow_regs[0xef] = 0x03; - } - - /* set horizontal resolution */ - shadow_regs[0x79] = 0x40; - shadow_regs[0x7a] = 0x01; - - } - return SANE_STATUS_GOOD; -} - -SANE_Status -sanei_lexmark_x1100_start_scan (Lexmark_Device * dev) -{ - SANE_Int devnum; - - static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; - - static SANE_Byte command5_block[] = { 0x80, 0xb3, 0x00, 0x01 }; - - SANE_Byte poll_result[3]; - SANE_Byte read_result; - SANE_Bool scan_head_moving; - size_t size; - - devnum = dev->devnum; - - dev->transfer_buffer = NULL; /* No data xferred yet */ - DBG (2, "sanei_lexmark_x1100_start_scan:\n"); - - - /* 80 b3 00 01 - poll for scanner not moving */ - scan_head_moving = SANE_TRUE; - while (scan_head_moving) - { - size = 4; - x1100_usb_bulk_write (devnum, command5_block, &size); - size = 0x1; - x1100_usb_bulk_read (devnum, &read_result, &size); - if ((read_result & 0xF) == 0x0) - { - scan_head_moving = SANE_FALSE; - } - /* F.O. Should be a timeout here so we don't hang if something breaks */ - } - - /* Clear C6 */ - x1100_clr_c6 (devnum); - /* Stop the scanner */ - x1100_stop_mvmt (devnum); - - /*Set regs x2 */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Start Scan */ - x1100_start_mvmt (devnum); - - /* We start with 0 bytes remaining to be read */ - dev->bytes_remaining = 0; - /* and 0 bytes in the transfer buffer */ - dev->bytes_in_buffer = 0; - - /* Poll the available byte count until not 0 */ - while (1) - { - size = 4; - x1100_usb_bulk_write (devnum, command4_block, &size); - size = 0x3; - x1100_usb_bulk_read (devnum, poll_result, &size); - if (! - (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) - { - /* if result != 00 00 00 we got data */ - - /* data_size should be used to set bytes_remaining */ - /* data_size is set from sane_get_parameters () */ - dev->bytes_remaining = dev->data_size; - /* Initialize the read buffer */ - read_buffer_init (dev, dev->params.bytes_per_line); - return SANE_STATUS_GOOD; - - } - size = 4; - /* I'm not sure why the Windows driver does this - probably a timeout? */ - x1100_usb_bulk_write (devnum, command5_block, &size); - size = 0x1; - x1100_usb_bulk_read (devnum, &read_result, &size); - if (read_result != 0x68) - { - dev->bytes_remaining = 0; - return SANE_STATUS_IO_ERROR; - } - } - - return SANE_STATUS_GOOD; -} - -long -sanei_lexmark_x1100_read_scan_data (SANE_Byte * data, SANE_Int size, Lexmark_Device * dev) -{ - - SANE_Int devnum; - SANE_Bool isColourScan, isGrayScan; -/* SANE_Byte temp_byte; */ - static SANE_Byte command1_block[] = { 0x91, 0x00, 0xff, 0xc0 }; - size_t xfer_size, cmd_size, xfer_request, remainder; -/* unsigned int i; */ - long bytes_read; - SANE_Bool even_byte; - - DBG (2, "sanei_lexmark_x1100_read_scan_data:\n"); - - /* colour mode */ - isGrayScan = SANE_FALSE; - if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) - isColourScan = SANE_TRUE; - else - { - isColourScan = SANE_FALSE; - /* grayscale mode */ - if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) - isGrayScan = SANE_TRUE; - } - - devnum = dev->devnum; - - /* Check if we have a transfer buffer. Create one and fill it if we don't */ - if (dev->transfer_buffer == NULL) - { - if (dev->bytes_remaining > 0) - { - if (dev->bytes_remaining >= MAX_XFER_SIZE) - { - xfer_request = MAX_XFER_SIZE; - xfer_size = MAX_XFER_SIZE; - remainder = 0; - } - else - { - xfer_request = dev->bytes_remaining; - remainder = dev->bytes_remaining % 0x10; - xfer_size = dev->bytes_remaining - remainder; - } - - command1_block[2] = (SANE_Byte) (xfer_request >> 8); - command1_block[3] = (SANE_Byte) (xfer_request & 0xFF); - - /* Create buffer to hold the amount we will request */ - dev->transfer_buffer = (SANE_Byte *) malloc (xfer_request); - if (dev->transfer_buffer == NULL) - return SANE_STATUS_NO_MEM; - /* Fill it */ - /* Write: 91 00 (xfer_size) */ - cmd_size = 4; - x1100_usb_bulk_write (devnum, command1_block, &cmd_size); - - /* Read: xfer_size bytes */ - cmd_size = xfer_request; - x1100_usb_bulk_read (devnum, dev->transfer_buffer, &cmd_size); - - - dev->bytes_remaining -= xfer_request; - dev->bytes_in_buffer = xfer_request; - dev->read_pointer = dev->transfer_buffer; - DBG (2, "sanei_lexmark_x1100_read_scan_data:\n"); - DBG (2, " Filled a buffer from the scanner\n"); - DBG (2, " bytes_remaining: %lu\n", (u_long)dev->bytes_remaining); - DBG (2, " bytes_in_buffer: %lu\n", (u_long)dev->bytes_in_buffer); - DBG (2, " read_pointer: %p\n", dev->read_pointer); - } - } - - DBG (5, "READ BUFFER INFO: \n"); - DBG (5, " write ptr: %p\n", dev->read_buffer->writeptr); - DBG (5, " read ptr: %p\n", dev->read_buffer->readptr); - DBG (5, " max write ptr: %p\n", dev->read_buffer->max_writeptr); - DBG (5, " buffer size: %lu\n", (u_long)dev->read_buffer->size); - DBG (5, " line size: %lu\n", (u_long)dev->read_buffer->linesize); - DBG (5, " empty: %d\n", dev->read_buffer->empty); - DBG (5, " line no: %d\n", dev->read_buffer->image_line_no); - - - /* If there is space in the read buffer, copy the transfer buffer over */ - if (read_buffer_bytes_available (dev->read_buffer) >= dev->bytes_in_buffer) - { - even_byte = SANE_TRUE; - while (dev->bytes_in_buffer) - { - - /* Colour Scan */ - if (isColourScan) - { - if (even_byte) - read_buffer_add_byte (dev->read_buffer, dev->read_pointer+1); - else - read_buffer_add_byte (dev->read_buffer, dev->read_pointer-1); - even_byte = ! even_byte; - } - /* Gray Scan */ - else if (isGrayScan) - { - if (even_byte) - read_buffer_add_byte_gray (dev->read_buffer, - dev->read_pointer+1); - else - read_buffer_add_byte_gray (dev->read_buffer, - dev->read_pointer-1); - even_byte = ! even_byte; - } - /* Lineart Scan */ - else - { - if (even_byte) - read_buffer_add_bit_lineart (dev->read_buffer, - dev->read_pointer+1, - dev->threshold); - else - read_buffer_add_bit_lineart (dev->read_buffer, - dev->read_pointer-1, - dev->threshold); - even_byte = ! even_byte; - } - dev->read_pointer = dev->read_pointer + sizeof (SANE_Byte); - dev->bytes_in_buffer--; - } - /* free the transfer buffer */ - free (dev->transfer_buffer); - dev->transfer_buffer = NULL; - } - - DBG (5, "READ BUFFER INFO: \n"); - DBG (5, " write ptr: %p\n", dev->read_buffer->writeptr); - DBG (5, " read ptr: %p\n", dev->read_buffer->readptr); - DBG (5, " max write ptr: %p\n", dev->read_buffer->max_writeptr); - DBG (5, " buffer size: %lu\n", (u_long)dev->read_buffer->size); - DBG (5, " line size: %lu\n", (u_long)dev->read_buffer->linesize); - DBG (5, " empty: %d\n", dev->read_buffer->empty); - DBG (5, " line no: %d\n", dev->read_buffer->image_line_no); - - /* Read blocks out of read buffer */ - bytes_read = read_buffer_get_bytes (dev->read_buffer, data, size); - - DBG (2, "sanei_lexmark_x1100_read_scan_data:\n"); - DBG (2, " Copying lines from buffer to data\n"); - DBG (2, " bytes_remaining: %lu\n", (u_long)dev->bytes_remaining); - DBG (2, " bytes_in_buffer: %lu\n", (u_long)dev->bytes_in_buffer); - DBG (2, " read_pointer: %p\n", dev->read_buffer->readptr); - DBG (2, " bytes_read %lu\n", (u_long) bytes_read); - - /* if no more bytes to xfer and read buffer empty we're at the end */ - if ((dev->bytes_remaining == 0) && read_buffer_is_empty (dev->read_buffer)) - { - if (!dev->eof) - { - DBG (2, "sanei_lexmark_x1100_read_scan_data: EOF- parking the scanner\n"); - dev->eof = SANE_TRUE; - x1100_rewind (dev); - } - else - { - DBG (2, "ERROR: Why are we trying to set eof more than once?\n"); - } - } - - return bytes_read; -} - -void -x1100_rewind (Lexmark_Device * dev) -{ - - SANE_Int new_location; - SANE_Int location; - SANE_Int scan_resolution; - SANE_Int fudge_factor; - SANE_Bool colour_scan; - SANE_Int vert_scan_start; - SANE_Int hor_scan_start; - SANE_Int vert_scan_dist; - SANE_Int vert_rewind_dist; - SANE_Int devnum; - - DBG (3, "x1100_rewind\n"); - - /* We rewind at 1200dpi resolution. - The variable "vert_scan_dist" is the distance of the scan in the - resolution of the scan "scan_resolution". - vert_rewind_dist = vert_scan_dist * 1200/scan_resolution + fudge_factor - Note: fudge_factor is different for each resolution and between colour - and grayscale scans at the same resolution. */ - - /* Scan resolution */ - scan_resolution = dev->val[OPT_RESOLUTION].w; - - /* Colour mode */ - if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) - colour_scan = SANE_TRUE; - else - colour_scan = SANE_FALSE; - - /* Init fudge factor to 0 */ - fudge_factor = 0x00; - - if (scan_resolution == 75) - { - if (colour_scan) - fudge_factor = 0x90; - else - fudge_factor = 0xb0; - } - else if (scan_resolution == 150) - { - if (colour_scan) - fudge_factor = 0x78; - else - fudge_factor = 0xb0; - } - else if (scan_resolution == 300) - { - if (colour_scan) - fudge_factor = 0x60; - else - fudge_factor = 0x78; - } - else if (scan_resolution == 600) - { - if (colour_scan) - fudge_factor = 0x146; - else - fudge_factor = 0x142; - } - else if (scan_resolution == 1200) - { - if (colour_scan) - fudge_factor = 0x140; - else - fudge_factor = 0x13c; - } - - x1100_get_start_loc (scan_resolution, &vert_scan_start, - &hor_scan_start, 0); - vert_scan_dist = vert_scan_start + dev->pixel_height + 2; - vert_rewind_dist = vert_scan_dist * 1200 / scan_resolution + fudge_factor; - location = vert_rewind_dist - 1; - new_location = vert_rewind_dist; - - devnum = dev->devnum; - - - /* sleep for 10 ms */ - /* usleep(10000); */ - - /* park the scanner */ - x1100_clr_c6 (devnum); - x1100_stop_mvmt (devnum); - - /* sleep for 20 ms */ - usleep(20000); - - x1100_stop_mvmt (devnum); - x1100_clr_c6 (devnum); - - /* set regs for rewind */ - shadow_regs[0x2f] = 0xa1; - shadow_regs[0x32] = 0x00; - shadow_regs[0x39] = 0x00; - - /* all other regs are always the same. these ones change with parameters */ - /* the following 4 regs are the location 61,60 and the location+1 63,62 */ - - shadow_regs[0x60] = (SANE_Byte) (location & 0x00FF); - shadow_regs[0x61] = (SANE_Byte) (location >> 8 & 0x00FF); - shadow_regs[0x62] = (SANE_Byte) (new_location & 0x00FF); - shadow_regs[0x63] = (SANE_Byte) (new_location >> 8 & 0x00FF); - -/* set regs for rewind */ - shadow_regs[0x79] = 0x40; - shadow_regs[0xb2] = 0x04; - shadow_regs[0xc3] = 0x81; - shadow_regs[0xc6] = 0x01; - shadow_regs[0xc9] = 0x3b; - shadow_regs[0xe0] = 0x2b; - shadow_regs[0xe1] = 0x17; - shadow_regs[0xe2] = 0xe7; - shadow_regs[0xe3] = 0x03; - shadow_regs[0xe6] = 0xdc; - shadow_regs[0xe7] = 0xb3; - shadow_regs[0xe8] = 0x07; - shadow_regs[0xe9] = 0x1b; - shadow_regs[0xea] = 0x00; - shadow_regs[0xeb] = 0x00; - shadow_regs[0xec] = 0x07; - shadow_regs[0xef] = 0x03; - - /*Set regs x2 */ - shadow_regs[0x32] = 0x00; - x1100_write_all_regs (devnum); - shadow_regs[0x32] = 0x40; - x1100_write_all_regs (devnum); - - /* Move */ - x1100_stop_mvmt (devnum); - x1100_start_mvmt (devnum); -} - - -SANE_Status -read_buffer_init (Lexmark_Device *dev, int bytesperline) -{ - size_t no_lines_in_buffer; - - DBG (2, "read_buffer_init: Start\n"); - - dev->read_buffer = (Read_Buffer *) malloc (sizeof (Read_Buffer)); - if (dev->read_buffer == NULL) - return SANE_STATUS_NO_MEM; - dev->read_buffer->linesize = bytesperline; - dev->read_buffer->gray_offset = 0; - dev->read_buffer->max_gray_offset = bytesperline - 1; - dev->read_buffer->region = RED; - dev->read_buffer->red_offset = 0; - dev->read_buffer->green_offset = 1; - dev->read_buffer->blue_offset = 2; - dev->read_buffer->max_red_offset = bytesperline - 3; - dev->read_buffer->max_green_offset = bytesperline - 2; - dev->read_buffer->max_blue_offset = bytesperline - 1; - no_lines_in_buffer = 3 * MAX_XFER_SIZE / bytesperline; - dev->read_buffer->size = bytesperline * no_lines_in_buffer; - dev->read_buffer->data = (SANE_Byte *) malloc (dev->read_buffer->size); - if (dev->read_buffer->data == NULL) - return SANE_STATUS_NO_MEM; - dev->read_buffer->readptr = dev->read_buffer->data; - dev->read_buffer->writeptr = dev->read_buffer->data; - dev->read_buffer->max_writeptr = dev->read_buffer->data + - (no_lines_in_buffer - 1) * bytesperline; - dev->read_buffer->empty = SANE_TRUE; - dev->read_buffer->image_line_no = 0; - dev->read_buffer->bit_counter = 0; - dev->read_buffer->max_lineart_offset = dev->params.pixels_per_line - 1; - return SANE_STATUS_GOOD; -} - -SANE_Status -read_buffer_free (Read_Buffer *read_buffer) -{ - DBG (2, "read_buffer_free:\n"); - if (read_buffer) - { - free (read_buffer->data); - free (read_buffer); - read_buffer = NULL; - } - return SANE_STATUS_GOOD; -} - -size_t -read_buffer_bytes_available (Read_Buffer *rb) -{ - - DBG (2, "read_buffer_bytes_available:\n"); - - if (rb->empty) - return rb->size; - else if ((size_t)abs(rb->writeptr - rb->readptr) < rb->linesize) - return 0; /* ptrs are less than one line apart */ - else if (rb->writeptr < rb->readptr) - return (rb->readptr - rb->writeptr - rb->linesize); - else - return (rb->size + rb->readptr - rb->writeptr - rb->linesize); -} - -SANE_Status -read_buffer_add_byte (Read_Buffer *rb, SANE_Byte * byte_pointer) -{ - - /* DBG(2, "read_buffer_add_byte:\n"); */ - /* F.O. Need to fix the endian byte ordering here */ - - switch (rb->region) - { - case RED: - *(rb->writeptr + rb->red_offset) = *byte_pointer; - if (rb->red_offset == rb->max_red_offset) - { - rb->red_offset = 0; - rb->region = GREEN; - } - else - rb->red_offset = rb->red_offset + (3 * sizeof (SANE_Byte)); - return SANE_STATUS_GOOD; - case GREEN: - *(rb->writeptr + rb->green_offset) = *byte_pointer; - if (rb->green_offset == rb->max_green_offset) - { - rb->green_offset = 1; - rb->region = BLUE; - } - else - rb->green_offset = rb->green_offset + (3 * sizeof (SANE_Byte)); - return SANE_STATUS_GOOD; - case BLUE: - *(rb->writeptr + rb->blue_offset) = *byte_pointer; - if (rb->blue_offset == rb->max_blue_offset) - { - rb->image_line_no++; - /* finished a line. read_buffer no longer empty */ - rb->empty = SANE_FALSE; - rb->blue_offset = 2; - rb->region = RED; - if (rb->writeptr == rb->max_writeptr) - rb->writeptr = rb->data; /* back to beginning of buffer */ - else - rb->writeptr = rb->writeptr + rb->linesize; /* next line */ - } - else - rb->blue_offset = rb->blue_offset + (3 * sizeof (SANE_Byte)); - return SANE_STATUS_GOOD; - } - return SANE_STATUS_GOOD; -} - -SANE_Status -read_buffer_add_byte_gray (Read_Buffer *rb, SANE_Byte * byte_pointer) -{ - - /* DBG(2, "read_buffer_add_byte_gray:\n"); */ - - *(rb->writeptr + rb->gray_offset) = *byte_pointer; - - if (rb->gray_offset == rb->max_gray_offset) - { - rb->image_line_no++; - /* finished a line. read_buffer no longer empty */ - rb->empty = SANE_FALSE; - rb->gray_offset = 0; - - if (rb->writeptr == rb->max_writeptr) - rb->writeptr = rb->data; /* back to beginning of buffer */ - else - rb->writeptr = rb->writeptr + rb->linesize; /* next line */ - } - else - rb->gray_offset = rb->gray_offset + (1 * sizeof (SANE_Byte)); - return SANE_STATUS_GOOD; -} - -SANE_Status -read_buffer_add_bit_lineart (Read_Buffer *rb, SANE_Byte * byte_pointer, - SANE_Byte threshold) -{ - SANE_Byte tmpByte; - SANE_Byte *currentBytePtr; - SANE_Int bitIndex; - - /* DBG(2, "read_buffer_add_bit_lineart:\n"); */ - - /* threshold = 0x80; */ - tmpByte = 0; - /* Create a bit by comparing incoming byte to threshold */ - if (*byte_pointer >= threshold) - { - tmpByte = 128; - } - - /* Calculate the bit index in the current byte */ - bitIndex = rb->bit_counter % 8; - /* Move the bit to its correct position in the temporary byte */ - tmpByte = tmpByte >> bitIndex; - /* Get the pointer to the current byte */ - currentBytePtr = rb->writeptr + rb->gray_offset; - - /* If this is the first write to this byte, clear the byte */ - if ( bitIndex == 0 ) - *currentBytePtr = 0; - /* Set the value of the bit in the current byte */ - *currentBytePtr = *currentBytePtr | tmpByte; - - - - /* last bit in the line? */ - if (rb->bit_counter == rb->max_lineart_offset) - { - /* Check if we're at the last byte of the line - error if not */ - if (rb->gray_offset != rb->max_gray_offset) - { - DBG(5, "read_buffer_add_bit_lineart:\n"); - DBG(5, " Last bit of line is not last byte.\n"); - DBG(5, " Bit Index: %d, Byte Index: %d. \n", rb->bit_counter, - rb->max_gray_offset); - return SANE_STATUS_INVAL; - } - rb->image_line_no++; - /* line finished read_buffer no longer empty */ - rb->empty = SANE_FALSE; - rb->gray_offset = 0; - /* are we at the last line in the read buffer ? */ - if (rb->writeptr == rb->max_writeptr) - rb->writeptr = rb->data; /* back to beginning of buffer */ - else - rb->writeptr = rb->writeptr + rb->linesize; /* next line */ - /* clear the bit counter */ - rb->bit_counter = 0; - } - /* last bit in the byte? */ - else if ( bitIndex == 7 ) - { - /* Not at the end of the line, but byte done. Increment byte offset */ - rb->gray_offset = rb->gray_offset + (1 * sizeof (SANE_Byte)); - /* increment bit counter */ - rb->bit_counter++; - } - else - { - /* else increment bit counter */ - rb->bit_counter++; - } - - return SANE_STATUS_GOOD; -} - - -size_t -read_buffer_get_bytes (Read_Buffer *rb, SANE_Byte * buffer, size_t rqst_size) -{ - /* Read_Buffer *rb; */ - size_t available_bytes; - - /* rb = read_buffer; */ - if (rb->empty) - return 0; - else if (rb->writeptr > rb->readptr) - { - available_bytes = rb->writeptr - rb->readptr; - if (available_bytes <= rqst_size) - { - /* We can read from the read pointer up to the write pointer */ - memcpy (buffer, rb->readptr, available_bytes); - rb->readptr = rb->writeptr; - rb->empty = SANE_TRUE; - return available_bytes; - } - else - { - /* We can read from the full request size */ - memcpy (buffer, rb->readptr, rqst_size); - rb->readptr = rb->readptr + rqst_size; - return rqst_size; - } - } - else - { - /* The read pointer is ahead of the write pointer. Its wrapped around. */ - /* We can read to the end of the buffer and make a recursive call to */ - /* read any available lines at the beginning of the buffer */ - available_bytes = rb->data + rb->size - rb->readptr; - if (available_bytes <= rqst_size) - { - /* We can read from the read pointer up to the end of the buffer */ - memcpy (buffer, rb->readptr, available_bytes); - rb->readptr = rb->data; - if (rb->writeptr == rb->readptr) - rb->empty = SANE_TRUE; - return available_bytes + - read_buffer_get_bytes (rb, buffer + available_bytes, - rqst_size - available_bytes); - } - else - { - /* We can read from the full request size */ - memcpy (buffer, rb->readptr, rqst_size); - rb->readptr = rb->readptr + rqst_size; - return rqst_size; - } - } -} - -SANE_Bool -read_buffer_is_empty (Read_Buffer *read_buffer) -{ - return read_buffer->empty; -} - - diff --git a/backend/lexmark.c b/backend/lexmark.c index 7dee3680e..298918a50 100644 --- a/backend/lexmark.c +++ b/backend/lexmark.c @@ -2,6 +2,7 @@ (C) 2003-2004 Lexmark International, Inc. (Original Source code) (C) 2005 Fred Odendaal + (C) 2006-2007 Stéphane Voltz This file is part of the SANE package. @@ -69,11 +70,9 @@ #include "../include/sane/sanei_backend.h" - #define LEXMARK_CONFIG_FILE "lexmark.conf" -#define BUILD 0 +#define BUILD 19 #define MAX_OPTION_STRING_SIZE 255 -#define MM_PER_INCH 25.4 static Lexmark_Device *first_lexmark_device = 0; static SANE_Int num_lexmark_device = 0; @@ -85,41 +84,66 @@ static SANE_Bool initialized = SANE_FALSE; static SANE_String_Const mode_list[] = { SANE_VALUE_SCAN_MODE_COLOR, SANE_VALUE_SCAN_MODE_GRAY, - SANE_VALUE_SCAN_MODE_LINEART, + SANE_VALUE_SCAN_MODE_LINEART, NULL }; -/* possible resolutions are: 75x75, 150x150, 300x300, 600X600, 600X1200 */ +/* possible resolutions are: 75x75, 150x150, 300x300, 600x600, 600x1200 */ -static SANE_Int dpi_list[] = { +static SANE_Int x1100_dpi_list[] = { 5, 75, 150, 300, 600, 1200 }; -static SANE_String_Const size_list[] = { - "Wallet", "3x5", "4x6", "5x7", "8x10", "Letter", NULL +static SANE_Int a920_dpi_list[] = { + 4, 75, 150, 300, 600 +}; + +static SANE_Int x1200_dpi_list[] = { + 4, 75, 150, 300, 600 }; static SANE_Range threshold_range = { - SANE_FIX(0.0), /* minimum */ - SANE_FIX(100.0), /* maximum */ - SANE_FIX(1.0) /* quantization */ + SANE_FIX (0.0), /* minimum */ + SANE_FIX (100.0), /* maximum */ + SANE_FIX (1.0) /* quantization */ }; +static const SANE_Range gain_range = { + 0, /* minimum */ + 31, /* maximum */ + 0 /* quantization */ +}; + +/* for now known models (2 ...) have the same scan window geometry. + coordinates are expressed in pixels, with a quantization factor of + 8 to have 'even' coordinates at 75 dpi */ +static SANE_Range x_range = { + 0, /* minimum */ + 5104, /* maximum */ + 16 /* quantization : 16 is required so we + never have an odd width */ +}; + +static SANE_Range y_range = { + 0, /* minimum */ + 6848, /* maximum */ + 8 /* quantization */ +}; /* static functions */ static SANE_Status init_options (Lexmark_Device * lexmark_device); static SANE_Status attachLexmark (SANE_String_Const devname); SANE_Status -init_options (Lexmark_Device * lexmark_device) +init_options (Lexmark_Device * dev) { SANE_Option_Descriptor *od; - DBG (2, "init_options: lexmark_device = %p\n", (void *) lexmark_device); + DBG (2, "init_options: dev = %p\n", (void *) dev); /* number of options */ - od = &(lexmark_device->opt[OPT_NUM_OPTS]); + od = &(dev->opt[OPT_NUM_OPTS]); od->name = SANE_NAME_NUM_OPTIONS; od->title = SANE_TITLE_NUM_OPTIONS; od->desc = SANE_DESC_NUM_OPTIONS; @@ -129,10 +153,10 @@ init_options (Lexmark_Device * lexmark_device) od->cap = SANE_CAP_SOFT_DETECT; od->constraint_type = SANE_CONSTRAINT_NONE; od->constraint.range = 0; - lexmark_device->val[OPT_NUM_OPTS].w = NUM_OPTIONS; + dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS; /* mode - sets the scan mode: Color, Gray, or Line Art */ - od = &(lexmark_device->opt[OPT_MODE]); + od = &(dev->opt[OPT_MODE]); od->name = SANE_NAME_SCAN_MODE; od->title = SANE_TITLE_SCAN_MODE; od->desc = SANE_DESC_SCAN_MODE;; @@ -142,13 +166,13 @@ init_options (Lexmark_Device * lexmark_device) od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; od->constraint_type = SANE_CONSTRAINT_STRING_LIST; od->constraint.string_list = mode_list; - lexmark_device->val[OPT_MODE].s = malloc (od->size); - if (!lexmark_device->val[OPT_MODE].s) + dev->val[OPT_MODE].s = malloc (od->size); + if (!dev->val[OPT_MODE].s) return SANE_STATUS_NO_MEM; - strcpy (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR); + strcpy (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR); /* resolution */ - od = &(lexmark_device->opt[OPT_RESOLUTION]); + od = &(dev->opt[OPT_RESOLUTION]); od->name = SANE_NAME_SCAN_RESOLUTION; od->title = SANE_TITLE_SCAN_RESOLUTION; od->desc = SANE_DESC_SCAN_RESOLUTION; @@ -157,11 +181,24 @@ init_options (Lexmark_Device * lexmark_device) od->size = sizeof (SANE_Word); od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; od->constraint_type = SANE_CONSTRAINT_WORD_LIST; - od->constraint.word_list = dpi_list; - lexmark_device->val[OPT_RESOLUTION].w = 150; + switch (dev->model.sensor_type) + { + case X1100_2C_SENSOR: + case A920_SENSOR: + od->constraint.word_list = a920_dpi_list; + break; + case X1100_B2_SENSOR: + od->constraint.word_list = x1100_dpi_list; + od->constraint.word_list = x1100_dpi_list; + break; + case X1200_SENSOR: + od->constraint.word_list = x1200_dpi_list; + break; + } + dev->val[OPT_RESOLUTION].w = 75; /* preview mode */ - od = &(lexmark_device->opt[OPT_PREVIEW]); + od = &(dev->opt[OPT_PREVIEW]); od->name = SANE_NAME_PREVIEW; od->title = SANE_TITLE_PREVIEW; od->desc = SANE_DESC_PREVIEW; @@ -169,26 +206,72 @@ init_options (Lexmark_Device * lexmark_device) od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; od->type = SANE_TYPE_BOOL; od->constraint_type = SANE_CONSTRAINT_NONE; - lexmark_device->val[OPT_PREVIEW].w = SANE_FALSE; + dev->val[OPT_PREVIEW].w = SANE_FALSE; - /* scan size */ - od = &(lexmark_device->opt[OPT_SCAN_SIZE]); - od->name = SANE_NAME_PAPER_SIZE; - od->title = SANE_TITLE_PAPER_SIZE; - od->desc = SANE_DESC_PAPER_SIZE; - od->type = SANE_TYPE_STRING; - od->unit = SANE_UNIT_NONE; - od->size = MAX_OPTION_STRING_SIZE; + /* "Geometry" group: */ + od = &(dev->opt[OPT_GEOMETRY_GROUP]); + od->name = ""; + od->title = SANE_I18N ("Geometry"); + od->desc = ""; + od->type = SANE_TYPE_GROUP; od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; - od->constraint_type = SANE_CONSTRAINT_STRING_LIST; - od->constraint.string_list = size_list; - lexmark_device->val[OPT_SCAN_SIZE].s = malloc (od->size); - if (!lexmark_device->val[OPT_SCAN_SIZE].s) - return SANE_STATUS_NO_MEM; - strcpy (lexmark_device->val[OPT_SCAN_SIZE].s, "3x5"); + od->size = 0; + od->constraint_type = SANE_CONSTRAINT_NONE; + + /* top-left x */ + od = &(dev->opt[OPT_TL_X]); + od->name = SANE_NAME_SCAN_TL_X; + od->title = SANE_TITLE_SCAN_TL_X; + od->desc = SANE_DESC_SCAN_TL_X; + od->type = SANE_TYPE_INT; + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->size = sizeof (SANE_Word); + od->unit = SANE_UNIT_PIXEL; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &x_range; + dev->val[OPT_TL_X].w = 0; + + /* top-left y */ + od = &(dev->opt[OPT_TL_Y]); + od->name = SANE_NAME_SCAN_TL_Y; + od->title = SANE_TITLE_SCAN_TL_Y; + od->desc = SANE_DESC_SCAN_TL_Y; + od->type = SANE_TYPE_INT; + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->size = sizeof (SANE_Word); + od->unit = SANE_UNIT_PIXEL; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &y_range; + dev->val[OPT_TL_Y].w = 0; + + /* bottom-right x */ + od = &(dev->opt[OPT_BR_X]); + od->name = SANE_NAME_SCAN_BR_X; + od->title = SANE_TITLE_SCAN_BR_X; + od->desc = SANE_DESC_SCAN_BR_X; + od->type = SANE_TYPE_INT; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->unit = SANE_UNIT_PIXEL; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &x_range; + dev->val[OPT_BR_X].w = x_range.max; + + /* bottom-right y */ + od = &(dev->opt[OPT_BR_Y]); + od->name = SANE_NAME_SCAN_BR_Y; + od->title = SANE_TITLE_SCAN_BR_Y; + od->desc = SANE_DESC_SCAN_BR_Y; + od->type = SANE_TYPE_INT; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->unit = SANE_UNIT_PIXEL; + od->constraint_type = SANE_CONSTRAINT_RANGE; + od->constraint.range = &y_range; + dev->val[OPT_BR_Y].w = y_range.max; /* threshold */ - od = &(lexmark_device->opt[OPT_THRESHOLD]); + od = &(dev->opt[OPT_THRESHOLD]); od->name = SANE_NAME_THRESHOLD; od->title = SANE_TITLE_THRESHOLD; od->desc = SANE_DESC_THRESHOLD; @@ -198,7 +281,73 @@ init_options (Lexmark_Device * lexmark_device) od->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE; od->constraint_type = SANE_CONSTRAINT_RANGE; od->constraint.range = &threshold_range; - lexmark_device->val[OPT_THRESHOLD].w = SANE_FIX(50.0); + dev->val[OPT_THRESHOLD].w = SANE_FIX (50.0); + + /* gain group */ + dev->opt[OPT_MANUAL_GAIN].name = "manual-channel-gain"; + dev->opt[OPT_MANUAL_GAIN].title = SANE_I18N ("Gain"); + dev->opt[OPT_MANUAL_GAIN].desc = SANE_I18N ("Color channels gain settings"); + dev->opt[OPT_MANUAL_GAIN].type = SANE_TYPE_BOOL; + dev->opt[OPT_MANUAL_GAIN].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + dev->opt[OPT_MANUAL_GAIN].size = sizeof (SANE_Bool); + dev->val[OPT_MANUAL_GAIN].w = SANE_FALSE; + + /* gray gain */ + dev->opt[OPT_GRAY_GAIN].name = "gray-gain"; + dev->opt[OPT_GRAY_GAIN].title = SANE_I18N ("Gray gain"); + dev->opt[OPT_GRAY_GAIN].desc = SANE_I18N ("Sets gray channel gain"); + dev->opt[OPT_GRAY_GAIN].type = SANE_TYPE_INT; + dev->opt[OPT_GRAY_GAIN].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE | + SANE_CAP_ADVANCED; + dev->opt[OPT_GRAY_GAIN].unit = SANE_UNIT_NONE; + dev->opt[OPT_GRAY_GAIN].size = sizeof (SANE_Int); + dev->opt[OPT_GRAY_GAIN].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_GRAY_GAIN].constraint.range = &gain_range; + dev->val[OPT_GRAY_GAIN].w = 10; + + /* red gain */ + dev->opt[OPT_RED_GAIN].name = "red-gain"; + dev->opt[OPT_RED_GAIN].title = SANE_I18N ("Red gain"); + dev->opt[OPT_RED_GAIN].desc = SANE_I18N ("Sets red channel gain"); + dev->opt[OPT_RED_GAIN].type = SANE_TYPE_INT; + dev->opt[OPT_RED_GAIN].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE | + SANE_CAP_ADVANCED; + dev->opt[OPT_RED_GAIN].unit = SANE_UNIT_NONE; + dev->opt[OPT_RED_GAIN].size = sizeof (SANE_Int); + dev->opt[OPT_RED_GAIN].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_RED_GAIN].constraint.range = &gain_range; + dev->val[OPT_RED_GAIN].w = 10; + + /* green gain */ + dev->opt[OPT_GREEN_GAIN].name = "green-gain"; + dev->opt[OPT_GREEN_GAIN].title = SANE_I18N ("Green gain"); + dev->opt[OPT_GREEN_GAIN].desc = SANE_I18N ("Sets green channel gain"); + dev->opt[OPT_GREEN_GAIN].type = SANE_TYPE_INT; + dev->opt[OPT_GREEN_GAIN].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE | + SANE_CAP_ADVANCED; + dev->opt[OPT_GREEN_GAIN].unit = SANE_UNIT_NONE; + dev->opt[OPT_GREEN_GAIN].size = sizeof (SANE_Int); + dev->opt[OPT_GREEN_GAIN].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_GREEN_GAIN].constraint.range = &gain_range; + dev->val[OPT_GREEN_GAIN].w = 10; + + /* blue gain */ + dev->opt[OPT_BLUE_GAIN].name = "blue-gain"; + dev->opt[OPT_BLUE_GAIN].title = SANE_I18N ("Blue gain"); + dev->opt[OPT_BLUE_GAIN].desc = SANE_I18N ("Sets blue channel gain"); + dev->opt[OPT_BLUE_GAIN].type = SANE_TYPE_INT; + dev->opt[OPT_BLUE_GAIN].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE | + SANE_CAP_ADVANCED; + dev->opt[OPT_BLUE_GAIN].unit = SANE_UNIT_NONE; + dev->opt[OPT_BLUE_GAIN].size = sizeof (SANE_Int); + dev->opt[OPT_BLUE_GAIN].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_BLUE_GAIN].constraint.range = &gain_range; + dev->val[OPT_BLUE_GAIN].w = 10; return SANE_STATUS_GOOD; } @@ -210,6 +359,8 @@ SANE_Status attachLexmark (SANE_String_Const devname) { Lexmark_Device *lexmark_device; + SANE_Int dn, vendor, product; + SANE_Status status; DBG (2, "attachLexmark: devname=%s\n", devname); @@ -224,10 +375,63 @@ attachLexmark (SANE_String_Const devname) if (lexmark_device == NULL) return SANE_STATUS_NO_MEM; - lexmark_device->sane.name = strdup (devname); - lexmark_device->sane.vendor = "Lexmark"; - lexmark_device->sane.model = "X1100"; - lexmark_device->sane.type = "flatbed scanner"; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_open (devname, &dn); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attachLexmark: couldn't open device `%s': %s\n", devname, + sane_strstatus (status)); + return status; + } + else + DBG (2, "attachLexmark: device `%s' successfully opened\n", devname); + +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; + /* put the id of the model you want to fake here */ + vendor = 0x043d; + product = 0x007d; /* X12xx */ +#else + status = sanei_usb_get_vendor_product (dn, &vendor, &product); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "attachLexmark: couldn't get vendor and product ids of device `%s': %s\n", + devname, sane_strstatus (status)); +#ifndef FAKE_USB + sanei_usb_close (dn); +#endif + return status; + } +#ifndef FAKE_USB + sanei_usb_close (dn); +#endif + + DBG (2, "attachLexmark: testing device `%s': 0x%04x:0x%04x, no variant\n", + devname, vendor, product); + if (sanei_lexmark_low_assign_model (lexmark_device, + devname, + vendor, + product, + 0) != SANE_STATUS_GOOD) + { + DBG (2, "attachLexmark: unsupported device `%s': 0x%04x:0x%04x\n", + devname, vendor, product); + return SANE_STATUS_UNSUPPORTED; + } + + /* there are two variant of the scanner with the same USB id, + * so we need to read registers from scanner to detect which one + * is really connected */ + status = sanei_lexmark_low_open_device (lexmark_device); + sanei_usb_close (lexmark_device->devnum); + + /* set up scanner start status */ + sanei_lexmark_low_init (lexmark_device); /* Set the default resolution here */ lexmark_device->x_dpi = 75; @@ -239,6 +443,8 @@ attachLexmark (SANE_String_Const devname) /* Set the default threshold for lineart mode here */ lexmark_device->threshold = 0x80; + lexmark_device->shading_coeff = NULL; + lexmark_device->next = first_lexmark_device; first_lexmark_device = lexmark_device; @@ -255,12 +461,12 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) const char *lp; SANE_Int vendor, product; size_t len; - SANE_Status status; + SANE_Status status = SANE_STATUS_GOOD; SANE_Auth_Callback auth_callback; DBG_INIT (); - DBG (1, "SANE Lexmark backend version %d.%d-%d\n", V_MAJOR, V_MINOR, BUILD); + DBG (1, "SANE Lexmark backend version %d.%d-rc2-%d\n", V_MAJOR, V_MINOR, BUILD); auth_callback = authorize; @@ -269,15 +475,14 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (version_code) *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD); - status = sanei_lexmark_x1100_init (); - - if (status != SANE_STATUS_GOOD) - return status; +#ifndef FAKE_USB + sanei_usb_init (); +#endif fp = sanei_config_open (LEXMARK_CONFIG_FILE); if (!fp) { - /* sanei_lexmark_x1100_destroy (); */ + /* sanei_lexmark_low_destroy (); */ return SANE_STATUS_ACCESS_DENIED; } @@ -292,7 +497,6 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (line[len - 1] == '\n') line[--len] = '\0'; - /* lp = (SANE_String) sanei_config_skip_whitespace (line); */ lp = sanei_config_skip_whitespace (line); /* skip empty lines */ if (*lp == 0) @@ -305,21 +509,23 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { lp += 3; - /* lp = (SANE_String) sanei_config_skip_whitespace (lp); */ lp = sanei_config_skip_whitespace (lp); } else continue; +#ifdef FAKE_USB + attachLexmark ("FAKE_USB"); +#else sanei_usb_attach_matching_devices (lp, attachLexmark); - +#endif } fclose (fp); initialized = SANE_TRUE; - return SANE_STATUS_GOOD; + return status; } void @@ -336,7 +542,7 @@ sane_exit (void) lexmark_device = next_lexmark_device) { next_lexmark_device = lexmark_device->next; - sanei_lexmark_x1100_destroy (lexmark_device); + sanei_lexmark_low_destroy (lexmark_device); free (lexmark_device); } @@ -384,13 +590,21 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) return SANE_STATUS_GOOD; } + +/** + * Open the backend, ie return the struct handle of a detected scanner + * The struct returned is choosne if it matches the name given, which is + * usefull when several scanners handled by the backend have been detected. + * However, special case empty string "" and "lexmark" pick the first + * available handle. + */ SANE_Status sane_open (SANE_String_Const devicename, SANE_Handle * handle) { Lexmark_Device *lexmark_device; SANE_Status status; - DBG (2, "sane_open: devicename=\"%s\", handle=%p\n", devicename, + DBG (2, "sane_open: devicename=\"%s\", handle=%p\n", devicename, (void *) handle); if (!initialized) @@ -405,12 +619,16 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) return SANE_STATUS_INVAL; } + /* walk the linked list of scanner device until ther is a match + * with the device name */ for (lexmark_device = first_lexmark_device; lexmark_device; lexmark_device = lexmark_device->next) { DBG (2, "sane_open: devname from list: %s\n", lexmark_device->sane.name); - if (strcmp (devicename, lexmark_device->sane.name) == 0) + if (strcmp (devicename, "") == 0 + || strcmp (devicename, "lexmark") == 0 + || strcmp (devicename, lexmark_device->sane.name) == 0) break; } @@ -418,7 +636,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) if (!lexmark_device) { - DBG (2, "sane_open: Not a Lexmark device\n"); + DBG (2, "sane_open: Not a lexmark device\n"); return SANE_STATUS_INVAL; } @@ -426,13 +644,10 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) if (status != SANE_STATUS_GOOD) return status; -/* status = llpddk_open_device (lexmark_device->sane.name); */ - status = - sanei_lexmark_x1100_open_device (lexmark_device->sane.name, &(lexmark_device->devnum)); - if (status != SANE_STATUS_GOOD) - return status; + status = sanei_lexmark_low_open_device (lexmark_device); + DBG (2, "sane_open: end.\n"); - return SANE_STATUS_GOOD; + return status; } void @@ -455,8 +670,7 @@ sane_close (SANE_Handle handle) if (!lexmark_device) return; -/* llpddk_close_device (); */ - sanei_lexmark_x1100_close_device (lexmark_device->devnum); + sanei_lexmark_low_close_device (lexmark_device); return; } @@ -486,15 +700,65 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if (!lexmark_device) return NULL; + if (lexmark_device->opt[option].name) + { + DBG (2, "sane_get_option_descriptor: name=%s\n", + lexmark_device->opt[option].name); + } + return &(lexmark_device->opt[option]); } +/* rebuilds parameters if needed, called each time SANE_INFO_RELOAD_OPTIONS + is set */ +static void +calc_parameters (Lexmark_Device * lexmark_device) +{ + if (strcmp (lexmark_device->val[OPT_MODE].s, + SANE_VALUE_SCAN_MODE_LINEART) == 0) + { + lexmark_device->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; + } + else + { + lexmark_device->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; + } + + /* changing color mode implies changing gain setting */ + if (lexmark_device->val[OPT_MANUAL_GAIN].w == SANE_TRUE) + { + if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) + != 0) + { + lexmark_device->opt[OPT_GRAY_GAIN].cap &= ~SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE; + } + else + { + lexmark_device->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_RED_GAIN].cap &= ~SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_GREEN_GAIN].cap &= ~SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_BLUE_GAIN].cap &= ~SANE_CAP_INACTIVE; + } + } + else + { + lexmark_device->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE; + lexmark_device->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE; + } +} + SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int * info) { Lexmark_Device *lexmark_device; SANE_Status status; + SANE_Word w; DBG (2, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n", (void *) handle, option, action, (void *) value, (void *) info); @@ -557,7 +821,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, info); if (status != SANE_STATUS_GOOD) { - DBG(2, "SANE_CONTROL_OPTION: Bad value for range\n"); + DBG (2, "SANE_CONTROL_OPTION: Bad value for range\n"); return SANE_STATUS_INVAL; } } @@ -565,16 +829,42 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, switch (option) { case OPT_NUM_OPTS: - case OPT_RESOLUTION: + case OPT_RESOLUTION: lexmark_device->val[option].w = *(SANE_Int *) value; sane_get_parameters (handle, 0); break; + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + DBG (2, "Option value set to %d (%s)\n", *(SANE_Word *) value, + lexmark_device->opt[option].name); + lexmark_device->val[option].w = *(SANE_Word *) value; + if (lexmark_device->val[OPT_TL_X].w > + lexmark_device->val[OPT_BR_X].w) + { + w = lexmark_device->val[OPT_TL_X].w; + lexmark_device->val[OPT_TL_X].w = + lexmark_device->val[OPT_BR_X].w; + lexmark_device->val[OPT_BR_X].w = w; + if (info) + *info |= SANE_INFO_RELOAD_PARAMS; + } + if (lexmark_device->val[OPT_TL_Y].w > + lexmark_device->val[OPT_BR_Y].w) + { + w = lexmark_device->val[OPT_TL_Y].w; + lexmark_device->val[OPT_TL_Y].w = + lexmark_device->val[OPT_BR_Y].w; + lexmark_device->val[OPT_BR_Y].w = w; + if (info) + *info |= SANE_INFO_RELOAD_PARAMS; + } + break; case OPT_THRESHOLD: lexmark_device->val[option].w = *(SANE_Fixed *) value; - lexmark_device->threshold = 0xFF * (lexmark_device->val[option].w/100); - break; - case OPT_SCAN_SIZE: - strcpy (lexmark_device->val[option].s, value); + lexmark_device->threshold = + (0xFF * lexmark_device->val[option].w) / 100; break; case OPT_PREVIEW: lexmark_device->val[option].w = *(SANE_Int *) value; @@ -592,30 +882,38 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, sane_get_parameters (handle, 0); if (info) *info |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_GRAY_GAIN: + case OPT_GREEN_GAIN: + case OPT_RED_GAIN: + case OPT_BLUE_GAIN: + lexmark_device->val[option].w = *(SANE_Word *) value; return SANE_STATUS_GOOD; - lexmark_device->val[option].w = *(SANE_Int *) value; break; case OPT_MODE: - strcpy (lexmark_device->val[option].s, value); - if (strcmp (lexmark_device->val[option].s, - SANE_VALUE_SCAN_MODE_LINEART) == 0) - { - lexmark_device->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; - } - else - { - lexmark_device->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; - } + strcpy (lexmark_device->val[option].s, value); + calc_parameters (lexmark_device); if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; + return SANE_STATUS_GOOD; + case OPT_MANUAL_GAIN: + w = *(SANE_Word *) value; + + if (w == lexmark_device->val[OPT_MANUAL_GAIN].w) + return SANE_STATUS_GOOD; /* no change */ + + lexmark_device->val[OPT_MANUAL_GAIN].w = w; + calc_parameters (lexmark_device); + if (info) + *info |= SANE_INFO_RELOAD_OPTIONS; + return SANE_STATUS_GOOD; } if (info != NULL) *info |= SANE_INFO_RELOAD_PARAMS; break; - + case SANE_ACTION_GET_VALUE: switch (option) @@ -623,15 +921,24 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, case OPT_NUM_OPTS: case OPT_RESOLUTION: case OPT_PREVIEW: - *(SANE_Int *) value = lexmark_device->val[option].w; - DBG(2,"Option value = %d\n", *(SANE_Int *) value); + case OPT_MANUAL_GAIN: + case OPT_GRAY_GAIN: + case OPT_GREEN_GAIN: + case OPT_RED_GAIN: + case OPT_BLUE_GAIN: + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + *(SANE_Word *) value = lexmark_device->val[option].w; + DBG (2, "Option value = %d (%s)\n", *(SANE_Word *) value, + lexmark_device->opt[option].name); break; case OPT_THRESHOLD: *(SANE_Fixed *) value = lexmark_device->val[option].w; - DBG(2,"Option value = %f\n", SANE_UNFIX(*(SANE_Fixed *) value)); + DBG (2, "Option value = %f\n", SANE_UNFIX (*(SANE_Fixed *) value)); break; case OPT_MODE: - case OPT_SCAN_SIZE: strcpy (value, lexmark_device->val[option].s); break; default: @@ -655,10 +962,8 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) SANE_Parameters *device_params; SANE_Int xres, yres, width_px, height_px; SANE_Int channels, bitsperchannel; - double width, height; - SANE_Bool isColourScan; - DBG (2, "sane_get_parameters: handle=%p, params=%p\n", (void *) handle, + DBG (2, "sane_get_parameters: handle=%p, params=%p\n", (void *) handle, (void *) params); if (!initialized) @@ -683,78 +988,29 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /* 24 bit colour = 8 bits/channel for each of the RGB channels */ channels = 3; bitsperchannel = 8; - isColourScan = SANE_TRUE; /* If not color there is only 1 channel */ - if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) + if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) != 0) { channels = 1; bitsperchannel = 8; - isColourScan = SANE_FALSE; } + /* geometry in pixels */ + width_px = + lexmark_device->val[OPT_BR_X].w - lexmark_device->val[OPT_TL_X].w; + height_px = + lexmark_device->val[OPT_BR_Y].w - lexmark_device->val[OPT_TL_Y].w; + DBG (7, "sane_get_parameters: tl=(%d,%d) br=(%d,%d)\n", + lexmark_device->val[OPT_TL_X].w, lexmark_device->val[OPT_TL_Y].w, + lexmark_device->val[OPT_BR_X].w, lexmark_device->val[OPT_BR_Y].w); - /* size in inches */ - if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "Wallet") == 0) - { - width = 2.50; - height = 3.50; - } - else if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "3x5") == 0) - { - width = 3.00; - height = 5.00; - } - else if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "4x6") == 0) - { - width = 4.00; - height = 6.00; - } - else if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "5x7") == 0) - { - width = 5.00; - height = 7.00; - } - else if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "8x10") == 0) - { - width = 8.00; - height = 10.00; - } - else if (strcmp (lexmark_device->val[OPT_SCAN_SIZE].s, "Letter") == 0) - { - width = 8.50; - height = 11.00; - } - else - { - DBG (2, "sane_get_parameters - ERROR: Unknown Scan Size option\n"); - return SANE_STATUS_INVAL; - } - - /* in pixels */ - width_px = (SANE_Int) (width * xres); - /* not sure why this is so - if its odd add one */ - if ((width_px & 0x01) == 1) - width_px = width_px + 1; - - height_px = (SANE_Int) (height * yres); - - /* Stashed with device record for easy retrieval later */ - lexmark_device->pixel_width = width_px; - lexmark_device->pixel_height = height_px; - - /* data_size is the size transferred from the scanner to the backend */ - /* therefor bitsperchannel is the same for gray and lineart */ - lexmark_device->data_size = - width_px * height_px * channels * (bitsperchannel / 8); - DBG (2, "sane_get_parameters: Data size determined as %lx\n", - lexmark_device->data_size); /* we must tell the front end the bitsperchannel for lineart is really */ /* only 1, so it can calculate the correct image size */ /* If not color there is only 1 channel */ - if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART) + if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART) == 0) { bitsperchannel = 1; @@ -765,21 +1021,31 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) if (channels == 1) device_params->format = SANE_FRAME_GRAY; device_params->last_frame = SANE_TRUE; - device_params->lines = height_px; + device_params->lines = (height_px * yres) / 600; device_params->depth = bitsperchannel; - device_params->pixels_per_line = width_px; - device_params->bytes_per_line = - (SANE_Int) (channels * device_params->pixels_per_line * - (bitsperchannel / 8)); - if ( bitsperchannel == 1 ) - { - device_params->bytes_per_line = - (SANE_Int) (device_params->pixels_per_line / 8); - if ((device_params->pixels_per_line % 8) != 0) - device_params->bytes_per_line++; - } - + device_params->pixels_per_line = (width_px * xres) / 600; + /* we always read an even number of sensor pixels */ + if (device_params->pixels_per_line & 1) + device_params->pixels_per_line++; + /* data_size is the size transferred from the scanner to the backend */ + /* therefore bitsperchannel is the same for gray and lineart */ + /* note: bytes_per_line has been divided by 8 in lineart mode */ + lexmark_device->data_size = + channels * device_params->pixels_per_line * device_params->lines; + + if (bitsperchannel == 1) + { + device_params->bytes_per_line = + (SANE_Int) ((7 + device_params->pixels_per_line) / 8); + } + else + { + device_params->bytes_per_line = + (SANE_Int) (channels * device_params->pixels_per_line); + } + DBG (2, "sane_get_parameters: Data size determined as %ld\n", + lexmark_device->data_size); DBG (2, "sane_get_parameters: \n"); if (device_params->format == SANE_FRAME_GRAY) @@ -792,10 +1058,10 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) DBG (2, " last_frame: TRUE\n"); else DBG (2, " last_frame: FALSE\n"); - DBG (2, " lines %x\n", device_params->lines); - DBG (2, " depth %x\n", device_params->depth); - DBG (2, " pixels_per_line %x\n", device_params->pixels_per_line); - DBG (2, " bytes_per_line %x\n", device_params->bytes_per_line); + DBG (2, " lines %d\n", device_params->lines); + DBG (2, " depth %d\n", device_params->depth); + DBG (2, " pixels_per_line %d\n", device_params->pixels_per_line); + DBG (2, " bytes_per_line %d\n", device_params->bytes_per_line); if (params != 0) { @@ -815,6 +1081,8 @@ sane_start (SANE_Handle handle) { Lexmark_Device *lexmark_device; SANE_Int offset; + SANE_Status status; + int i; DBG (2, "sane_start: handle=%p\n", (void *) handle); @@ -834,9 +1102,10 @@ sane_start (SANE_Handle handle) (lexmark_device->params.pixels_per_line == 0) || (lexmark_device->params.bytes_per_line == 0)) { - DBG(2, "sane_start: \n"); - DBG(2, " ERROR: Zero size encountered in:\n"); - DBG(2, " number of lines, bytes per line, or pixels per line\n"); + DBG (2, "sane_start: \n"); + DBG (2, " ERROR: Zero size encountered in:\n"); + DBG (2, + " number of lines, bytes per line, or pixels per line\n"); return SANE_STATUS_INVAL; } @@ -850,7 +1119,7 @@ sane_start (SANE_Handle handle) lexmark_device->cancel_ctr = 0; /* Find Home */ - if (sanei_lexmark_x1100_search_home_fwd (lexmark_device)) + if (sanei_lexmark_low_search_home_fwd (lexmark_device)) { DBG (2, "sane_start: Scan head initially at home position\n"); } @@ -858,24 +1127,37 @@ sane_start (SANE_Handle handle) { /* We may have been rewound too far, so move forward the distance from the edge to the home position */ - /* sanei_lexmark_x1100_move_fwd_a_bit(lexmark_device); */ - sanei_lexmark_x1100_move_fwd (0x01a8, lexmark_device); + sanei_lexmark_low_move_fwd (0x01a8, lexmark_device, + lexmark_device->shadow_regs); + /* Scan backwards until we find home */ - sanei_lexmark_x1100_search_home_bwd (lexmark_device); + sanei_lexmark_low_search_home_bwd (lexmark_device); + } + + /* do calibration before offset detection */ + sanei_lexmark_low_set_scan_regs (lexmark_device, 0, SANE_FALSE); + status = sanei_lexmark_low_calibration (lexmark_device); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "sane_start: calibration failed : %s ! \n", + sane_strstatus (status)); + return status; } /* At this point we're somewhere in the dot. We need to read a number of lines greater than the diameter of the dot and determine how many lines past the dot we've gone. We then use this information to see how far the scan head must move before starting the scan. */ - offset = sanei_lexmark_x1100_find_start_line (lexmark_device->devnum); + /* offset is in 600 dpi unit */ + offset = sanei_lexmark_low_find_start_line (lexmark_device); + DBG (7, "start line offset=%d\n", offset); /* Set the shadow registers for scan with the options (resolution, mode, size) set in the front end. Pass the offset so we can get the vert. start. */ - sanei_lexmark_x1100_set_scan_regs (lexmark_device, offset); - - if (sanei_lexmark_x1100_start_scan (lexmark_device) == SANE_STATUS_GOOD) + sanei_lexmark_low_set_scan_regs (lexmark_device, offset, SANE_TRUE); + + if (sanei_lexmark_low_start_scan (lexmark_device) == SANE_STATUS_GOOD) { DBG (2, "sane_start: scan started\n"); return SANE_STATUS_GOOD; @@ -915,7 +1197,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, { DBG (2, "sane_read: Device was cancelled\n"); /* We don't know how far we've gone, so search for home. */ - sanei_lexmark_x1100_search_home_bwd (lexmark_device); + sanei_lexmark_low_search_home_bwd (lexmark_device); return SANE_STATUS_EOF; } @@ -936,7 +1218,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, if (!data) return SANE_STATUS_INVAL; - bytes_read = sanei_lexmark_x1100_read_scan_data (data, max_length, + bytes_read = sanei_lexmark_low_read_scan_data (data, max_length, lexmark_device); if (bytes_read < 0) return SANE_STATUS_IO_ERROR; @@ -970,7 +1252,7 @@ sane_cancel (SANE_Handle handle) } /*If sane_cancel called more than once, return */ - if (++lexmark_device->cancel_ctr > 1) + if (++lexmark_device->cancel_ctr > 1) return; /* Set the device flag so the next call to sane_read() can stop the scan. */ @@ -984,8 +1266,8 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) { Lexmark_Device *lexmark_device; - DBG (2, "sane_set_io_mode: handle = %p, non_blocking = %d\n", (void *) handle, - non_blocking); + DBG (2, "sane_set_io_mode: handle = %p, non_blocking = %d\n", + (void *) handle, non_blocking); if (!initialized) return SANE_STATUS_INVAL; diff --git a/backend/lexmark.conf.in b/backend/lexmark.conf.in index a6bfd62e6..61049e456 100644 --- a/backend/lexmark.conf.in +++ b/backend/lexmark.conf.in @@ -1,2 +1,6 @@ -#usb /dev/usb/scanner0 +# X11xx series usb 0x043d 0x007c +# X12xx series +usb 0x043d 0x007d +# Dell A920 +usb 0x413c 0x5105 diff --git a/backend/lexmark.h b/backend/lexmark.h index 3bca2b778..8fcb9b1b1 100644 --- a/backend/lexmark.h +++ b/backend/lexmark.h @@ -2,6 +2,7 @@ lexmark.h - SANE library for Lexmark scanners. Copyright (C) 2003-2004 Lexmark International, Inc. (original source) Copyright (C) 2005 Fred Odendaal + Copyright (C) 2006-2007 Stéphane Voltz This file is part of the SANE package. @@ -44,34 +45,70 @@ #ifndef LEXMARK_H #define LEXMARK_H -/* Force the backend name for all files using this include */ -#ifdef BACKEND_NAME -#undef BACKEND_NAME -#define BACKEND_NAME lexmark -#endif - -#define DEBUG_NOT_STATIC -#define SANE_NAME_PAPER_SIZE "paper-size" -#define SANE_TITLE_PAPER_SIZE SANE_I18N("Paper size") -#define SANE_DESC_PAPER_SIZE \ -SANE_I18N("Selects the size of the area to be scanned."); - - typedef enum { OPT_NUM_OPTS = 0, OPT_MODE, -/* OPT_X_DPI, */ -/* OPT_Y_DPI, */ OPT_RESOLUTION, OPT_PREVIEW, - OPT_SCAN_SIZE, OPT_THRESHOLD, + + OPT_GEOMETRY_GROUP, + OPT_TL_X, /* top-left x */ + OPT_TL_Y, /* top-left y */ + OPT_BR_X, /* bottom-right x */ + OPT_BR_Y, /* bottom-right y */ + + /* manual gain handling */ + OPT_MANUAL_GAIN, /* 6 */ + OPT_GRAY_GAIN, + OPT_RED_GAIN, + OPT_GREEN_GAIN, + OPT_BLUE_GAIN, + /* must come last: */ NUM_OPTIONS } Lexmark_Options; +/* + * this struct is used to described the specific parts of each model + */ +typedef struct Lexmark_Model +{ + SANE_Int vendor_id; + SANE_Int product_id; + SANE_Byte mainboard_id; /* matched against the content of reg B0 */ + SANE_String_Const name; + SANE_String_Const vendor; + SANE_String_Const model; + SANE_Int motor_type; + SANE_Int sensor_type; +} Lexmark_Model; + +/* + * this struct is used to store per sensor model constants + */ +typedef struct Lexmark_Sensor +{ + SANE_Int id; + SANE_Int offset_startx; /* starting x for offset calibration */ + SANE_Int offset_endx; /* end x for offset calibration */ + SANE_Int offset_threshold; /* target threshold for offset calibration */ + SANE_Int xoffset; /* number of unusable pixels on the start of the sensor */ + SANE_Int default_gain; /* value of the default gain for a scan */ + SANE_Int red_gain_target; + SANE_Int green_gain_target; + SANE_Int blue_gain_target; + SANE_Int gray_gain_target; + SANE_Int red_shading_target; + SANE_Int green_shading_target; + SANE_Int blue_shading_target; + SANE_Int gray_shading_target; + SANE_Int offset_fallback; /* offset to use in case offset calibration fails */ + SANE_Int gain_fallback; /* gain to use in case offset calibration fails */ +} Lexmark_Sensor; + typedef enum { RED = 0, @@ -80,6 +117,16 @@ typedef enum } Scan_Regions; +/* struct to hold pre channel settings */ +typedef struct Channels +{ + SANE_Word red; + SANE_Word green; + SANE_Word blue; + SANE_Word gray; +} +Channels; + /** @name Option_Value union * convenience union to access option values given to the backend * @{ @@ -131,8 +178,6 @@ typedef struct Lexmark_Device SANE_Parameters params; SANE_Int devnum; long data_size; - SANE_Int pixel_height; - SANE_Int pixel_width; SANE_Bool initialized; SANE_Bool eof; SANE_Int x_dpi; @@ -141,31 +186,62 @@ typedef struct Lexmark_Device SANE_Bool device_cancelled; SANE_Int cancel_ctr; SANE_Byte *transfer_buffer; + size_t bytes_read; size_t bytes_remaining; size_t bytes_in_buffer; SANE_Byte *read_pointer; Read_Buffer *read_buffer; SANE_Byte threshold; + + Lexmark_Model model; /* per model data */ + Lexmark_Sensor *sensor; + SANE_Byte shadow_regs[255]; /* shadow registers */ + struct Channels offset; + struct Channels gain; + float *shading_coeff; } Lexmark_Device; /* Maximum transfer size */ #define MAX_XFER_SIZE 0xFFC0 +/* motors and sensors type defines */ +#define X1100_MOTOR 1 +#define A920_MOTOR 2 + +#define X1100_B2_SENSOR 3 +#define A920_SENSOR 4 +#define X1100_2C_SENSOR 5 +#define X1200_SENSOR 6 /* X1200 on USB 1.0 */ +#define X1200_USB2_SENSOR 7 /* X1200 on USB 2.0 */ + /* Non-static Function Proto-types (called by lexmark.c) */ -SANE_Status sanei_lexmark_x1100_init (void); -void sanei_lexmark_x1100_destroy (Lexmark_Device * dev); -SANE_Status sanei_lexmark_x1100_open_device (SANE_String_Const devname, - SANE_Int * devnum); -void sanei_lexmark_x1100_close_device (SANE_Int devnum); -SANE_Bool sanei_lexmark_x1100_search_home_fwd (Lexmark_Device * dev); -void sanei_lexmark_x1100_move_fwd (SANE_Int distance, Lexmark_Device * dev); -SANE_Bool sanei_lexmark_x1100_search_home_bwd (Lexmark_Device * dev); -SANE_Int sanei_lexmark_x1100_find_start_line (SANE_Int devnum); -SANE_Status sanei_lexmark_x1100_set_scan_regs (Lexmark_Device * dev, - SANE_Int offset); -SANE_Status sanei_lexmark_x1100_start_scan (Lexmark_Device * dev); -long sanei_lexmark_x1100_read_scan_data (SANE_Byte * data, SANE_Int size, +SANE_Status sanei_lexmark_low_init (Lexmark_Device * dev); +void sanei_lexmark_low_destroy (Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_open_device (Lexmark_Device * dev); +void sanei_lexmark_low_close_device (Lexmark_Device * dev); +SANE_Bool sanei_lexmark_low_search_home_fwd (Lexmark_Device * dev); +void sanei_lexmark_low_move_fwd (SANE_Int distance, Lexmark_Device * dev, + SANE_Byte * regs); +SANE_Bool sanei_lexmark_low_search_home_bwd (Lexmark_Device * dev); +SANE_Int sanei_lexmark_low_find_start_line (Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_set_scan_regs (Lexmark_Device * dev, + SANE_Int offset, + SANE_Bool calibrated); +SANE_Status sanei_lexmark_low_start_scan (Lexmark_Device * dev); +long sanei_lexmark_low_read_scan_data (SANE_Byte * data, SANE_Int size, Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_assign_model (Lexmark_Device * dev, + char *devname, SANE_Int vendor, + SANE_Int product, + SANE_Byte mainboard); + +/* + * scanner calibration functions + */ +SANE_Status sanei_lexmark_low_offset_calibration (Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_gain_calibration (Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_shading_calibration (Lexmark_Device * dev); +SANE_Status sanei_lexmark_low_calibration (Lexmark_Device * dev); #endif /* LEXMARK_H */ diff --git a/backend/lexmark_low.c b/backend/lexmark_low.c new file mode 100644 index 000000000..5ab2ff13c --- /dev/null +++ b/backend/lexmark_low.c @@ -0,0 +1,5150 @@ +/* lexmark-low.c: scanner-interface file for low Lexmark scanners. + + (C) 2005 Fred Odendaal + (C) 2006-2007 Stéphane Voltz + + 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. + + **************************************************************************/ + +#include "../include/sane/config.h" + +#include +#include +#include +#include +#include + +#include "../include/sane/sane.h" +#include "../include/sane/sanei.h" +#include "../include/sane/saneopts.h" + +#include "../include/sane/sanei_usb.h" + +#include "lexmark.h" +#include "../include/sane/sanei_backend.h" + +#include "lexmark_sensors.c" +#include "lexmark_models.c" + +/* numbre of ranges for offset */ +#define OFFSET_RANGES 5 + +typedef enum +{ + black = 0, + white +} +region_type; + +/* + * all these defines may be move in device specific constant in per model + * struct if we need it + */ +#define HomeEdgePoint1 1235 +#define HomeEdgePoint2 1258 +#define HomeTolerance 30 + +#define LOBYTE(x) ((u_int8_t)((x) & 0xFF)) +#define HIBYTE(x) ((u_int8_t)((x) >> 8)) + +/* Static low function proto-types */ +static SANE_Status low_usb_bulk_write (SANE_Int devnum, + SANE_Byte * cmd, size_t * size); +static SANE_Status low_usb_bulk_read (SANE_Int devnum, + SANE_Byte * buf, size_t * size); +static SANE_Status low_write_all_regs (SANE_Int devnum, SANE_Byte * regs); +static SANE_Bool low_is_home_line (unsigned char *buffer); +static SANE_Status low_get_start_loc (SANE_Int resolution, + SANE_Int * vert_start, + SANE_Int * hor_start, + SANE_Int offset, + Lexmark_Device * dev); +static void low_rewind (Lexmark_Device * dev, SANE_Byte * regs); +static SANE_Status low_start_mvmt (SANE_Int devnum); +static SANE_Status low_stop_mvmt (SANE_Int devnum); +static SANE_Status low_clr_c6 (SANE_Int devnum); +static SANE_Status low_simple_scan (Lexmark_Device * dev, + SANE_Byte * regs, + int xoffset, + int pixels, + int yoffset, + int lines, SANE_Byte ** data); +static void low_set_scan_area (SANE_Int res, + SANE_Int tlx, + SANE_Int tly, + SANE_Int brx, + SANE_Int bry, + SANE_Int offset, + SANE_Bool half_step, + SANE_Byte * regs, Lexmark_Device * dev); + +/* Static Read Buffer Proto-types */ +static SANE_Status read_buffer_init (Lexmark_Device * dev, int bytesperline); +static SANE_Status read_buffer_free (Read_Buffer * rb); +static size_t read_buffer_bytes_available (Read_Buffer * rb); +static SANE_Status read_buffer_add_byte (Read_Buffer * rb, + SANE_Byte * byte_pointer); +static SANE_Status read_buffer_add_byte_gray (Read_Buffer * rb, + SANE_Byte * byte_pointer); +static SANE_Status read_buffer_add_bit_lineart (Read_Buffer * rb, + SANE_Byte * byte_pointer, + SANE_Byte threshold); +static size_t read_buffer_get_bytes (Read_Buffer * rb, SANE_Byte * buffer, + size_t rqst_size); +static SANE_Bool read_buffer_is_empty (Read_Buffer * rb); + + +/* + * RTS88XX START + * + * these rts88xx functions will be spin off in a separate lib + * so that they can be reused. + */ + +/* + * registers helpers to avoid direct access + */ +static SANE_Bool +rts88xx_is_color (SANE_Byte * regs) +{ + if ((regs[0x2f] & 0x11) == 0x11) + return SANE_TRUE; + return SANE_FALSE; +} + +static void +rts88xx_set_gray_scan (SANE_Byte * regs) +{ + regs[0x2f] = (regs[0x2f] & 0x0f) | 0x20; +} + +static void +rts88xx_set_color_scan (SANE_Byte * regs) +{ + regs[0x2f] = (regs[0x2f] & 0x0f) | 0x10; +} + +static void +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; +} + +static void +rts88xx_set_gain (SANE_Byte * regs, SANE_Byte red, SANE_Byte green, + SANE_Byte blue) +{ + regs[0x08] = red; + regs[0x09] = green; + regs[0x0a] = blue; +} + +/* set # of head moves per CIS read */ +static int +rts88xx_set_scan_frequency (SANE_Byte * regs, int frequency) +{ + regs[0x64] = (regs[0x64] & 0xf0) | (frequency & 0x0f); + return 0; +} + +/* + * read one register at given index + */ +static SANE_Status +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; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_write_bulk (devnum, cmd, &size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_read_reg: bulk write failed\n"); + return status; + } + size = 1; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_read_bulk (devnum, reg, &size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_read_reg: bulk read failed\n"); + return status; + } + DBG (15, "rts88xx_read_reg: reg[0x%02x]=0x%02x\n", index, *reg); + return status; +} + +/* + * write one register at given index + */ +static SANE_Status +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 }; + size_t size; + + cmd[1] = index; + + size = 4; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_write_bulk (devnum, cmd, &size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_write_reg: bulk write failed\n"); + return status; + } + size = 1; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_write_bulk (devnum, reg, &size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_write_reg: bulk write failed\n"); + return status; + } + DBG (15, "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 + */ +static SANE_Status +rts88xx_write_regs (SANE_Int devnum, SANE_Int start, SANE_Byte * source, + SANE_Int length) +{ + size_t size = 0; + + /* when writing several registers at a time, we avoid writing 0xb3 + register */ + if ((start + length > 0xb3) && (length > 1)) + { + size = 0xb3 - start; + if (low_usb_bulk_write (devnum, source, &size) != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_write_regs : write registers part 1 failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + + /* skip 0xB3 register */ + size++; + start = 0xb4; + source = source + size; + } + size = length - size; + if (low_usb_bulk_write (devnum, source, &size) != SANE_STATUS_GOOD) + { + DBG (5, "rts88xx_write_regs : write registers part 2 failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + + return SANE_STATUS_GOOD; + +} + +/* + * reads 'needed' bytes of scanned data into 'data'. Actual number of bytes get + * is retruned in 'size' + */ +static SANE_Status +rts88xx_read_data (SANE_Int devnum, size_t needed, SANE_Byte * data, + size_t * size) +{ + SANE_Byte read_cmd[] = { 0x91, 0x00, 0x00, 0x00 }; + size_t cmd_size; + SANE_Status status = SANE_STATUS_GOOD; + + /* this block would deserve to be a function */ + if (needed > MAX_XFER_SIZE) + *size = MAX_XFER_SIZE; + else + *size = needed; + read_cmd[3] = (*size) & 0xff; + read_cmd[2] = (*size >> 8) & 0xff; + read_cmd[1] = (*size >> 16) & 0xff; + + /* send header for 'get scanned data' */ + cmd_size = 4; + status = low_usb_bulk_write (devnum, read_cmd, &cmd_size); + if (status != SANE_STATUS_GOOD) + { + *size = 0; + DBG (5, "rts88xx_read_data : header sending failed ...\n"); + return status; + } + /* get actual scanned data */ + status = low_usb_bulk_read (devnum, data, size); + if (status != SANE_STATUS_GOOD) + { + *size = 0; + DBG (5, "rts88xx_read_data : data reading failed ...\n"); + } + return status; +} + +/* starts scan by sending color depth, stopping head, the starting it */ +SANE_Status +rts88xx_commit (SANE_Int devnum, SANE_Byte depth) +{ + SANE_Status status; + SANE_Byte reg; + + DBG (2, "rts88xx_commit: start\n"); + + /* send color depth depth ?? + * X1100 -> 0x0f + * X1100/B2 -> 0x0d + * X1200 -> 0x01 */ + reg = depth; + status = rts88xx_write_reg (devnum, 0x2c, ®); + + /* stop before starting */ + status = low_stop_mvmt (devnum); + + /* effective start */ + status = low_start_mvmt (devnum); + + DBG (2, "rts88xx_commit: end\n"); + + return status; +} + +/* + * RTS88XX END + */ + + + +/* + * sets the scanner idle + */ +static SANE_Status +lexmark_low_set_idle (SANE_Int devnum) +{ + SANE_Byte regs[14] = + { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60 + }; + if (rts88xx_write_regs (devnum, 16, regs, 14) != SANE_STATUS_GOOD) + { + DBG (5, "lexmark_low_set_idle : register write failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + return SANE_STATUS_GOOD; +} + + +/* wake up scanner */ +static SANE_Status +lexmark_low_wake_up (Lexmark_Device * dev) +{ + SANE_Byte regs[5] = { 0x12, 0x14, 0x16, 0x18, 0x1a }; + SANE_Byte values[5] = { 0x0f, 0x00, 0x07, 0x00, 0x00 }; + int i; + + /* send the wake-up sequence, one reg at at time */ + for (i = 0; i < 10; i++) + { + if (rts88xx_write_reg (dev->devnum, regs[i], values + i) != + SANE_STATUS_GOOD) + { + DBG (5, + "lexmark_low_wake_up : register write pass %d failed ...\n", + i); + return SANE_STATUS_IO_ERROR; + } + } + return SANE_STATUS_GOOD; +} + + +/** + * + */ +static void write_pnm_file(char *title, int pixels, int lines, int color, unsigned char *data) +{ +FILE * fdbg; +int x,y; + + fdbg = fopen (title, "wb"); + if (fdbg == NULL) + return; + + if (color) + { + fprintf (fdbg, "P6\n%d %d\n255\n", pixels, lines); + for (y = 0; y < lines; y++) + { + for (x = 0; x < pixels; x += 2) + { + fputc (data[y * pixels * 3 + x + 1], fdbg); + fputc (data[y * pixels * 3 + x + 1 + pixels], fdbg); + fputc (data[y * pixels * 3 + x + 1 + pixels * 2], fdbg); + fputc (data[y * pixels * 3 + x], fdbg); + fputc (data[y * pixels * 3 + x + pixels], fdbg); + fputc (data[y * pixels * 3 + x + pixels * 2], fdbg); + } + } + } + else + { + fprintf (fdbg, "P5\n%d %d\n255\n", pixels, lines); + fwrite (data, pixels, lines, fdbg); + } + fclose (fdbg); +} + +/* + * mid level hardware functions + */ +/* + * model init + */ +SANE_Status +sanei_lexmark_low_init (Lexmark_Device * dev) +{ + int i; + SANE_Status status; + + DBG_INIT(); + + status = SANE_STATUS_UNSUPPORTED; + DBG (2, "low_init: start\n"); + + /* clear all registers first */ + for (i = 0; i < 255; i++) + { + dev->shadow_regs[i] = 0; + } + + /* set up per model constant values */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x01] = 0x43; + dev->shadow_regs[0x0b] = 0x70; + dev->shadow_regs[0x11] = 0x01; + dev->shadow_regs[0x12] = 0x0f; + dev->shadow_regs[0x13] = 0x01; + dev->shadow_regs[0x15] = 0x01; + dev->shadow_regs[0x16] = 0x0f; + dev->shadow_regs[0x1d] = 0x20; + dev->shadow_regs[0x28] = 0xeb; + dev->shadow_regs[0x29] = 0xee; + dev->shadow_regs[0x2a] = 0xf7; + dev->shadow_regs[0x2b] = 0x01; + dev->shadow_regs[0x2e] = 0x86; + dev->shadow_regs[0x30] = 0x48; + dev->shadow_regs[0x33] = 0x01; + dev->shadow_regs[0x3a] = 0x20; + dev->shadow_regs[0x3b] = 0x37; + dev->shadow_regs[0x3c] = 0x88; + dev->shadow_regs[0x3d] = 0x08; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x72] = 0x05; + dev->shadow_regs[0x74] = 0x0e; + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x8c] = 0x02; + dev->shadow_regs[0x8d] = 0x01; + dev->shadow_regs[0x8e] = 0x60; + dev->shadow_regs[0x8f] = 0x80; + dev->shadow_regs[0x94] = 0x0e; + dev->shadow_regs[0xa3] = 0xcc; + dev->shadow_regs[0xa4] = 0x27; + dev->shadow_regs[0xa5] = 0x24; + dev->shadow_regs[0xb0] = 0xb2; + dev->shadow_regs[0xb2] = 0x04; + dev->shadow_regs[0xc2] = 0x80; + dev->shadow_regs[0xc4] = 0x20; + dev->shadow_regs[0xc8] = 0x04; + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xed] = 0xc2; + dev->shadow_regs[0xee] = 0x02; + dev->shadow_regs[0xf3] = 0xf8; + dev->shadow_regs[0xf4] = 0x7f; + status = SANE_STATUS_GOOD; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x00] = 0x00; + dev->shadow_regs[0x01] = 0x43; + dev->shadow_regs[0x0b] = 0x70; + dev->shadow_regs[0x0c] = 0x28; + dev->shadow_regs[0x0d] = 0xa4; + dev->shadow_regs[0x11] = 0x01; + dev->shadow_regs[0x12] = 0x0f; + dev->shadow_regs[0x13] = 0x01; + dev->shadow_regs[0x15] = 0x01; + dev->shadow_regs[0x16] = 0x0f; + dev->shadow_regs[0x17] = 0x00; + dev->shadow_regs[0x1d] = 0x20; + dev->shadow_regs[0x28] = 0xf5; + dev->shadow_regs[0x29] = 0xf7; + dev->shadow_regs[0x2a] = 0xf5; + dev->shadow_regs[0x2b] = 0x17; + dev->shadow_regs[0x2d] = 0x41; + dev->shadow_regs[0x2e] = 0x86; + dev->shadow_regs[0x2f] = 0x11; + dev->shadow_regs[0x30] = 0x48; + dev->shadow_regs[0x31] = 0x01; + dev->shadow_regs[0x33] = 0x01; + dev->shadow_regs[0x34] = 0x50; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x50; + dev->shadow_regs[0x37] = 0x01; + dev->shadow_regs[0x38] = 0x50; + dev->shadow_regs[0x3a] = 0x20; + dev->shadow_regs[0x3b] = 0x37; + dev->shadow_regs[0x3c] = 0x88; + dev->shadow_regs[0x3d] = 0x08; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x47] = 0x01; + dev->shadow_regs[0x48] = 0x1a; + dev->shadow_regs[0x49] = 0x5b; + dev->shadow_regs[0x4a] = 0x1b; + dev->shadow_regs[0x4b] = 0x5b; + dev->shadow_regs[0x4c] = 0x05; + dev->shadow_regs[0x4d] = 0x3f; + dev->shadow_regs[0x60] = 0x2f; + dev->shadow_regs[0x61] = 0x36; + dev->shadow_regs[0x62] = 0x30; + dev->shadow_regs[0x63] = 0x36; + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x66] = 0x64; + dev->shadow_regs[0x6c] = 0xc8; + dev->shadow_regs[0x6d] = 0x00; + dev->shadow_regs[0x72] = 0x35; + dev->shadow_regs[0x74] = 0x4e; + dev->shadow_regs[0x75] = 0x03; + dev->shadow_regs[0x79] = 0x40; + dev->shadow_regs[0x7a] = 0x01; + dev->shadow_regs[0x85] = 0x02; + dev->shadow_regs[0x86] = 0x33; + dev->shadow_regs[0x87] = 0x0f; + dev->shadow_regs[0x88] = 0x24; + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x8c] = 0x02; + dev->shadow_regs[0x8d] = 0x01; + dev->shadow_regs[0x8e] = 0x60; + dev->shadow_regs[0x8f] = 0x80; + dev->shadow_regs[0x91] = 0x19; + dev->shadow_regs[0x92] = 0x20; + dev->shadow_regs[0x93] = 0x02; + dev->shadow_regs[0x94] = 0x0e; + dev->shadow_regs[0xa3] = 0x0d; + dev->shadow_regs[0xa4] = 0x5e; + dev->shadow_regs[0xa5] = 0x23; + dev->shadow_regs[0xb0] = 0x2c; + dev->shadow_regs[0xb1] = 0x07; + dev->shadow_regs[0xb2] = 0x04; + dev->shadow_regs[0xc2] = 0x80; + dev->shadow_regs[0xc3] = 0x01; + dev->shadow_regs[0xc4] = 0x20; + dev->shadow_regs[0xc5] = 0x0a; + dev->shadow_regs[0xc8] = 0x04; + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x0a; + dev->shadow_regs[0xe2] = 0xf8; + dev->shadow_regs[0xe3] = 0x2a; + dev->shadow_regs[0xf3] = 0xf8; + dev->shadow_regs[0xf4] = 0x7f; + status = SANE_STATUS_GOOD; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x01] = 0x43; + dev->shadow_regs[0x11] = 0x01; + dev->shadow_regs[0x12] = 0x0f; + dev->shadow_regs[0x13] = 0x01; + dev->shadow_regs[0x15] = 0x01; + dev->shadow_regs[0x16] = 0x0f; + dev->shadow_regs[0x17] = 0x00; + dev->shadow_regs[0x1d] = 0x20; + dev->shadow_regs[0x28] = 0xf5; + dev->shadow_regs[0x29] = 0xf7; + dev->shadow_regs[0x2a] = 0xf5; + dev->shadow_regs[0x2b] = 0x17; + dev->shadow_regs[0x2d] = 0x41; + dev->shadow_regs[0x2e] = 0x86; + dev->shadow_regs[0x30] = 0x48; + dev->shadow_regs[0x31] = 0x01; + dev->shadow_regs[0x33] = 0x01; + dev->shadow_regs[0x34] = 0x50; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x50; + dev->shadow_regs[0x37] = 0x01; + dev->shadow_regs[0x38] = 0x50; + dev->shadow_regs[0x3c] = 0x88; + dev->shadow_regs[0x3d] = 0x08; + dev->shadow_regs[0x66] = 0x64; + dev->shadow_regs[0x67] = 0x00; + dev->shadow_regs[0x6c] = 0xc8; + dev->shadow_regs[0x6d] = 0x00; + dev->shadow_regs[0x72] = 0x35; + dev->shadow_regs[0x74] = 0x4e; + dev->shadow_regs[0x75] = 0x03; + dev->shadow_regs[0x7a] = 0x01; + dev->shadow_regs[0x93] = 0x0a; + dev->shadow_regs[0x94] = 0x0e; + + dev->shadow_regs[0xc3] = 0x01; + dev->shadow_regs[0xc4] = 0x20; + dev->shadow_regs[0xc5] = 0x0a; + dev->shadow_regs[0xc8] = 0x04; + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x0a; + dev->shadow_regs[0xe2] = 0xf8; + dev->shadow_regs[0xe3] = 0x2a; + dev->shadow_regs[0xf3] = 0xf8; + dev->shadow_regs[0xf4] = 0x7f; + status = SANE_STATUS_GOOD; + break; + case A920_SENSOR: + dev->shadow_regs[0x01] = 0x43; + dev->shadow_regs[0x0b] = 0x70; + dev->shadow_regs[0x0c] = 0x28; + dev->shadow_regs[0x0d] = 0xa4; + dev->shadow_regs[0x11] = 0x01; + dev->shadow_regs[0x12] = 0x0f; + dev->shadow_regs[0x13] = 0x01; + dev->shadow_regs[0x15] = 0x01; + dev->shadow_regs[0x16] = 0x07; + dev->shadow_regs[0x1d] = 0x20; + dev->shadow_regs[0x28] = 0xf5; + dev->shadow_regs[0x29] = 0xf7; + dev->shadow_regs[0x2a] = 0xf5; + dev->shadow_regs[0x2b] = 0x17; + dev->shadow_regs[0x2e] = 0x86; + dev->shadow_regs[0x30] = 0x48; + dev->shadow_regs[0x31] = 0x01; + dev->shadow_regs[0x33] = 0x01; + dev->shadow_regs[0x3a] = 0x20; + dev->shadow_regs[0x3b] = 0x37; + dev->shadow_regs[0x3c] = 0x88; + dev->shadow_regs[0x3d] = 0x08; + dev->shadow_regs[0x47] = 0x21; + dev->shadow_regs[0x48] = 0x1a; + dev->shadow_regs[0x49] = 0x5b; + dev->shadow_regs[0x4a] = 0x1b; + dev->shadow_regs[0x4b] = 0x5b; + dev->shadow_regs[0x4c] = 0x05; + dev->shadow_regs[0x4d] = 0x3f; + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x89] = 0xf5; + dev->shadow_regs[0x8d] = 0x01; + dev->shadow_regs[0x8e] = 0x60; + dev->shadow_regs[0x8f] = 0x80; + dev->shadow_regs[0x94] = 0x0e; + dev->shadow_regs[0xa3] = 0x0d; + dev->shadow_regs[0xa4] = 0x5e; + dev->shadow_regs[0xa5] = 0x23; + dev->shadow_regs[0xb0] = 0x2c; + dev->shadow_regs[0xb1] = 0x0f; + dev->shadow_regs[0xc2] = 0x80; + dev->shadow_regs[0xc4] = 0x20; + dev->shadow_regs[0xc8] = 0x04; + dev->shadow_regs[0xf3] = 0xf8; + dev->shadow_regs[0xf4] = 0x7f; + status = SANE_STATUS_GOOD; + break; + case X1200_SENSOR: + dev->shadow_regs[0x01] = 0x43; + dev->shadow_regs[0x0b] = 0x70; + dev->shadow_regs[0x0c] = 0x28; + dev->shadow_regs[0x0d] = 0xa4; + dev->shadow_regs[0x11] = 0x01; + dev->shadow_regs[0x12] = 0x0f; + dev->shadow_regs[0x13] = 0x01; + dev->shadow_regs[0x15] = 0x01; + dev->shadow_regs[0x16] = 0x0f; + dev->shadow_regs[0x1d] = 0x20; + dev->shadow_regs[0x28] = 0xe9; + dev->shadow_regs[0x29] = 0xeb; + dev->shadow_regs[0x2a] = 0xe9; + dev->shadow_regs[0x2b] = 0x0b; + dev->shadow_regs[0x2d] = 0x01; + dev->shadow_regs[0x2e] = 0x86; + dev->shadow_regs[0x2f] = 0x11; + dev->shadow_regs[0x30] = 0x48; + dev->shadow_regs[0x33] = 0x01; + dev->shadow_regs[0x34] = 0x50; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x50; + dev->shadow_regs[0x37] = 0x01; + dev->shadow_regs[0x38] = 0x50; + dev->shadow_regs[0x3a] = 0x20; + dev->shadow_regs[0x3b] = 0x37; + dev->shadow_regs[0x3c] = 0x88; + dev->shadow_regs[0x3d] = 0x08; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x47] = 0x01; + dev->shadow_regs[0x48] = 0x1a; + dev->shadow_regs[0x49] = 0x5b; + dev->shadow_regs[0x4a] = 0x1b; + dev->shadow_regs[0x4b] = 0x5b; + dev->shadow_regs[0x4c] = 0x05; + dev->shadow_regs[0x4d] = 0x3f; + dev->shadow_regs[0x60] = 0x12; + dev->shadow_regs[0x62] = 0x81; + dev->shadow_regs[0x63] = 0x03; + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x66] = 0x64; + dev->shadow_regs[0x6c] = 0xc8; + dev->shadow_regs[0x72] = 0x1e; + dev->shadow_regs[0x74] = 0x3c; + dev->shadow_regs[0x75] = 0x03; + dev->shadow_regs[0x79] = 0x40; + dev->shadow_regs[0x7a] = 0x01; + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x1e; + dev->shadow_regs[0x87] = 0x39; + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x8c] = 0x02; + dev->shadow_regs[0x8d] = 0x01; + dev->shadow_regs[0x8e] = 0x60; + dev->shadow_regs[0x8f] = 0x80; + dev->shadow_regs[0x92] = 0x92; + dev->shadow_regs[0x93] = 0x02; + dev->shadow_regs[0x94] = 0x0e; + dev->shadow_regs[0xa3] = 0x0d; + dev->shadow_regs[0xa4] = 0x5e; + dev->shadow_regs[0xa5] = 0x23; + dev->shadow_regs[0xb0] = 0x2c; + dev->shadow_regs[0xb1] = 0x07; + dev->shadow_regs[0xb2] = 0x04; + dev->shadow_regs[0xc2] = 0x80; + dev->shadow_regs[0xc3] = 0x01; + dev->shadow_regs[0xc4] = 0x20; + dev->shadow_regs[0xc5] = 0x0a; + dev->shadow_regs[0xc8] = 0x04; + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x0a; + dev->shadow_regs[0xe2] = 0xf8; + dev->shadow_regs[0xe3] = 0x2a; + dev->shadow_regs[0xf3] = 0xff; + dev->shadow_regs[0xf4] = 0x0f; + break; + } + DBG (5, "sanei_lexmark_low_init: init done for model %s/%s\n", + dev->model.model, dev->model.name); + DBG (2, "low_init: done\n"); + return status; +} + +void +sanei_lexmark_low_destroy (Lexmark_Device * dev) +{ + /* free the read buffer */ + if (dev->read_buffer != NULL) + read_buffer_free (dev->read_buffer); +} + + +SANE_Status +low_usb_bulk_write (SANE_Int devnum, SANE_Byte * cmd, size_t * size) +{ + SANE_Status status; + size_t cmd_size; + + cmd_size = *size; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_write_bulk (devnum, cmd, size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, + "low_usb_bulk_write: returned %s (size = %ld, expected %d)\n", + sane_strstatus (status), (long int) *size, cmd_size); + /* F.O. should reset the pipe here... */ + } + return status; +} + +SANE_Status +low_usb_bulk_read (SANE_Int devnum, SANE_Byte * buf, size_t * size) +{ + SANE_Status status; + size_t exp_size; + + exp_size = *size; +#ifdef FAKE_USB + status = SANE_STATUS_GOOD; +#else + status = sanei_usb_read_bulk (devnum, buf, size); +#endif + if (status != SANE_STATUS_GOOD) + { + DBG (5, + "low_usb_bulk_read: returned %s (size = %ld, expected %d)\n", + sane_strstatus (status), (long int) *size, exp_size); + /* F.O. should reset the pipe here... */ + } + DBG (7, "low_usb_bulk_read: returned size = %ld (required %d)\n", + (long int) *size, exp_size); + return status; +} + + +SANE_Status +low_start_mvmt (SANE_Int devnum) +{ + SANE_Status status; + SANE_Byte reg; + + reg = 0x68; + status = rts88xx_write_reg (devnum, 0xb3, ®); + status = rts88xx_write_reg (devnum, 0xb3, ®); + return status; +} + +SANE_Status +low_stop_mvmt (SANE_Int devnum) +{ + SANE_Status status; + SANE_Byte reg; + + /* Stop scanner - clear reg 0xb3: */ + reg = 0x02; + status = rts88xx_write_reg (devnum, 0xb3, ®); + status = rts88xx_write_reg (devnum, 0xb3, ®); + reg = 0x00; + status = rts88xx_write_reg (devnum, 0xb3, ®); + status = rts88xx_write_reg (devnum, 0xb3, ®); + return status; +} + +SANE_Status +low_clr_c6 (SANE_Int devnum) +{ + static SANE_Byte clearC6_command_block[] = { + 0x88, 0xc6, 0x00, 0x01, 0x00 + }; + size_t cmd_size; + SANE_Status status; + SANE_Byte reg; + + /* Clear register 0xC6 */ + /* cmd_size = 0x05; + return low_usb_bulk_write (devnum, clearC6_command_block, &cmd_size);*/ + + reg = 0x00; + status = rts88xx_write_reg (devnum, 0xc6, ®); + return status; +} + +/* stops current scan */ +static SANE_Status +low_cancel (SANE_Int devnum) +{ + SANE_Status status; + + DBG (2, "low_cancel: start\n"); + status = low_stop_mvmt (devnum); + if (status != SANE_STATUS_GOOD) + return status; + status = low_clr_c6 (devnum); + if (status != SANE_STATUS_GOOD) + return status; + DBG (2, "low_cancel: end.\n"); + return status; +} + +static SANE_Status +low_start_scan (SANE_Int devnum, SANE_Byte * regs) +{ + SANE_Status status; + + DBG (2, "low_start_scan: start\n"); + + /* writes registers to scanner */ + regs[0x32] = 0x00; + status = low_write_all_regs (devnum, regs); + if (status != SANE_STATUS_GOOD) + return status; + regs[0x32] = 0x40; + status = low_write_all_regs (devnum, regs); + if (status != SANE_STATUS_GOOD) + return status; + + /* Stop scanner - clear reg 0xb3: */ + /* status = low_stop_mvmt (devnum); + if (status != SANE_STATUS_GOOD) + return status; */ + + /* then start */ + status = rts88xx_commit (devnum, regs[0x2c]); + DBG (2, "low_start_scan: end.\n"); + return status; +} + +/* wait for scan data being available */ +static SANE_Status +low_poll_data (SANE_Int devnum) +{ + SANE_Status status; + int loops = 0; + size_t size; + static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; + SANE_Byte result[3]; + SANE_Word count; + + /* Poll the available byte count until not 0 */ + while (loops < 1000) + { + /* 10 ms sleep */ + usleep (10000); + + /* as stated in sanei_lexmark_low_search_home_bwd, we read + * available data count twice */ + size = 4; + status = low_usb_bulk_write (devnum, command4_block, &size); + if (status != SANE_STATUS_GOOD) + return status; + size = 0x3; + status = low_usb_bulk_read (devnum, result, &size); + if (status != SANE_STATUS_GOOD) + return status; + size = 4; + /* read availbale data size again */ + status = low_usb_bulk_write (devnum, command4_block, &size); + if (status != SANE_STATUS_GOOD) + return status; + size = 0x3; + status = low_usb_bulk_read (devnum, result, &size); + if (status != SANE_STATUS_GOOD) + return status; + count = result[0] + (result[1] << 8) + (result[2] << 16); + if (count != 0) + { + DBG (15, "low_poll_data: %d bytes available\n", count); + return SANE_STATUS_GOOD; + } + loops++; + } + return SANE_STATUS_IO_ERROR; +} + +/** + * do a simple scan with the given registers. data buffer is allocated within + * the function + */ +static SANE_Status +low_simple_scan (Lexmark_Device * dev, SANE_Byte * regs, int xoffset, + int pixels, int yoffset, int lines, SANE_Byte ** data) +{ + SANE_Status status = SANE_STATUS_GOOD; + static SANE_Byte reg; + size_t size, read, needed; + int i, bpl, yend; + + DBG (2, "low_simple_scan: start\n"); + DBG (15, "low_simple_scan: x=%d, pixels=%d (ex=%d), y=%d, lines=%d\n", + xoffset, pixels, xoffset + pixels * regs[0x7a], yoffset, lines); + + /* set up registers */ + regs[0x60] = LOBYTE (yoffset); + regs[0x61] = HIBYTE (yoffset); + yend = yoffset + lines; + if (dev->model.motor_type == A920_MOTOR && rts88xx_is_color (regs) + && dev->val[OPT_RESOLUTION].w == 600) + yend *= 2; + regs[0x62] = LOBYTE (yend); + regs[0x63] = HIBYTE (yend); + + regs[0x66] = LOBYTE (xoffset); + regs[0x67] = HIBYTE (xoffset); + + regs[0x6c] = LOBYTE (xoffset + pixels * regs[0x7a]); + regs[0x6d] = HIBYTE (xoffset + pixels * regs[0x7a]); + + /* allocate memory */ + if (rts88xx_is_color (regs)) + bpl = 3 * pixels; + else + bpl = pixels; + *data = (SANE_Byte *) malloc (bpl * lines); + if (*data == NULL) + { + DBG (2, + "low_simple_scan: failed to allocate %d bytes !\n", bpl * lines); + return SANE_STATUS_NO_MEM; + } + + /* start scan */ + status = low_cancel (dev->devnum); + if (status != SANE_STATUS_GOOD) + return status; + + + status = low_start_scan (dev->devnum, regs); + if (status != SANE_STATUS_GOOD) + return status; + + /* wait for data */ + status = low_poll_data (dev->devnum); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "low_simple_scan: time-out while waiting for data.\n"); + return status; + } + + /* data reading loop */ + needed = bpl * lines; + DBG (1, "low_simple_scan: bpl=%d, lines=%d, needed=%d.\n", bpl, lines, + needed); + read = 0; + do + { + /* this block would deserve to be a function */ + status = + rts88xx_read_data (dev->devnum, needed - read, (*data) + read, &size); + if (status != SANE_STATUS_GOOD) + return status; + read += size; + } + while (read < needed); + + /* if needed, wait for motor to stop */ + if (regs[0xc3] & 0x80) + { + i = 0; + do + { + if (rts88xx_read_reg (dev->devnum, 0xb3, ®) != SANE_STATUS_GOOD) + { + DBG (5, "low_simple_scan: register read failed ...\n"); + return SANE_STATUS_IO_ERROR; + } + usleep (100000); + i++; + } + while ((reg & 0x08) && (i < 100)); + if (reg & 0x08) + { + DBG (5, + "low_simple_scan : timeout waiting for motor to stop ...\n"); + return SANE_STATUS_IO_ERROR; + } + } + + /* stop scan */ + status = low_cancel (dev->devnum); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "low_simple_scan: cancel failed.\n"); + return status; + } + + DBG (2, "low_simple_scan: end.\n"); + return status; +} + +/* + * open USB device ,read initial registers values and probe sensor + */ +SANE_Status +sanei_lexmark_low_open_device (Lexmark_Device * dev) +{ + /* This function calls the Sane Interface to open this usb device. + It also needlessly does what the Windows driver does and reads + the entire register set - this may be removed. */ + + SANE_Status result; + static SANE_Byte command_block[] = { 0x80, 0, 0x00, 0xFF }; + size_t size; + SANE_Byte variant = 0; + SANE_Byte shadow_regs[255]; +#ifdef DEEP_DEBUG + int i; +#endif + int sx, ex; + int sy, ey; + + +#ifdef FAKE_USB + result = SANE_STATUS_GOOD; + shadow_regs[0x00] = 0x91; + shadow_regs[0xb0] = 0x2c; + shadow_regs[0x10] = 0x97; + shadow_regs[0x10] = 0x87; + shadow_regs[0xf3] = 0xf8; + shadow_regs[0xf4] = 0x7f; +#else + result = sanei_usb_open (dev->sane.name, &(dev->devnum)); +#endif + DBG (2, "sanei_lexmark_low_open_device: devnum=%d\n", dev->devnum); + + size = 4; + low_usb_bulk_write (dev->devnum, command_block, &size); + size = 0xFF; + low_usb_bulk_read (dev->devnum, shadow_regs, &size); +#ifdef DEEP_DEBUG + if (DBG_LEVEL > 2) + { + fprintf (stderr, + "sanei_lexmark_low_open_device: initial registers values\n"); + fprintf (stderr, "read_all(0x00,255)="); + for (i = 0; i < 255; i++) + { + fprintf (stderr, "0x%02x ", shadow_regs[i]); + } + fprintf (stderr, "\n"); + } +#endif + + /* it seems that at first read after reset, registers hold information + * about the scanner. Register 0x00 is overwritten with 0, so only first read + * after USB plug-in gives this value */ + if (shadow_regs[0] == 0x91) + { + sx = shadow_regs[0x67] * 256 + shadow_regs[0x66]; + ex = shadow_regs[0x6d] * 256 + shadow_regs[0x6c]; + DBG (7, "startx=%d, endx=%d, pixels=%d, coef=%d, r2f=0x%02x\n", sx, ex, + ex - sx, dev->shadow_regs[0x7a], shadow_regs[0x2f]); + sy = shadow_regs[0x61] * 256 + shadow_regs[0x60]; + ey = shadow_regs[0x63] * 256 + shadow_regs[0x62]; + DBG (7, "starty=%d, endy=%d, lines=%d\n", sy, ey, ey - sy); + } + + /* we use register 0xb0 to identify details about models */ + /* this register isn't overwritten during normal operation */ + if (shadow_regs[0xb0] == 0x2c && dev->model.sensor_type == X1100_B2_SENSOR) + { + variant = shadow_regs[0xb0]; + } + /* now the same with register 0x10 */ + /* which most likely signals USB2.0/USB1.1 */ + if ((dev->model.sensor_type == X1200_SENSOR) && (shadow_regs[0x10] == 0x97)) + { + variant = shadow_regs[0x10]; + } + + /* if find a case where default model given is inappropriate, reassign it + * since we have now the informations to get the real one. Such + * We could avoid this if attach() did open and read registers, not init */ + if (variant != 0) + { + DBG (3, + "sanei_lexmark_low_open_device: reassign model/sensor for varaint 0x%02x\n", + variant); + sanei_lexmark_low_assign_model (dev, dev->sane.name, + dev->model.vendor_id, + dev->model.product_id, variant); + /* since model has changed, run init again */ + sanei_lexmark_low_init (dev); + } + DBG (2, "sanei_lexmark_low_open_device: end\n"); + return result; +} + +void +sanei_lexmark_low_close_device (Lexmark_Device * dev) +{ + /* put scanner in idle state */ + lexmark_low_set_idle (dev->devnum); + + /* This function calls the Sane USB library to close this usb device */ +#ifndef FAKE_USB + sanei_usb_close (dev->devnum); +#endif + return; +} + + +/* This function writes the contents of the given registers to the + scanner. */ +SANE_Status +low_write_all_regs (SANE_Int devnum, SANE_Byte * regs) +{ + int i; + SANE_Status status; + size_t size; + static SANE_Byte command_block1[0xb7]; + static SANE_Byte command_block2[0x4f]; + command_block1[0] = 0x88; + command_block1[1] = 0x00; + command_block1[2] = 0x00; + command_block1[3] = 0xb3; + for (i = 0; i < 0xb3; i++) + { + command_block1[i + 4] = regs[i]; + } + command_block2[0] = 0x88; + command_block2[1] = 0xb4; + command_block2[2] = 0x00; + command_block2[3] = 0x4b; + for (i = 0; i < 0x4b; i++) + { + command_block2[i + 4] = regs[i + 0xb4]; + } + size = 0xb7; + +#ifdef DEEP_DEBUG + fprintf (stderr, "write_all(0x00,255)="); + for (i = 0; i < 255; i++) + { + fprintf (stderr, "0x%02x ", regs[i]); + } + fprintf (stderr, "\n"); +#endif + + status = low_usb_bulk_write (devnum, command_block1, &size); + if (status != SANE_STATUS_GOOD) + return status; + size = 0x4f; + status = low_usb_bulk_write (devnum, command_block2, &size); + if (status != SANE_STATUS_GOOD) + return status; + return SANE_STATUS_GOOD; +} + + +SANE_Bool +low_is_home_line (unsigned char *buffer) +{ + /* + This function assumes the buffer has a size of 2500 bytes.It is + destructive to the buffer. + + Here is what it does: + + Go through the buffer finding low and high values, which are computed by + comparing to the average: + average = (lowest value + highest value)/2 + High bytes are changed to 0xFF (white), lower or equal bytes are changed + to 0x00 (black),so that the buffer only contains white (0xFF) or black + (0x00) values. + + Next, we go through the buffer. We use a tolerance of 5 bytes on each end + of the buffer and check a region from bytes 5 to 2495. We start assuming + we are in a white region and look for the start of a black region. We save + this index as the transition from white to black. We also save where we + change from black back to white. We continue checking for transitions + until the end of the check region. If we don't have exactly two + transitions when we reach the end we return SANE_FALSE. + + The final check compares the transition indices to the nominal values + plus or minus the tolerence. For the first transition (white to black + index) the value must lie in the range 1235-30 (1205) to 1235+30 (1265). + For the second transition (black to white) the value must lie in the range + 1258-30 (1228) to 1258+30 (1288). If the indices are out of range we + return SANE_FALSE. Otherwise, we return SANE_TRUE. + */ + + + unsigned char max_byte = 0; + unsigned char min_byte = 0xFF; + unsigned char average; + int i; + + region_type region; + int transition_counter; + int index1 = 0; + int index2 = 0; + int low_range, high_range; + +#ifdef DEEP_DEBUG + static int numero = 0; + char titre[80]; + FILE *trace = NULL; + sprintf (titre, "lgn%03d.pnm", numero); + trace = fopen (titre, "wb"); + if (trace) + { + fprintf (trace, "P5\n2500 1\n255\n"); + fwrite (buffer, 2500, 1, trace); + fclose (trace); + } + numero++; +#endif + + /* Find the max and the min */ + for (i = 0; i < 2500; i++) + { + if (*(buffer + i) > max_byte) + max_byte = *(buffer + i); + if (*(buffer + i) < min_byte) + min_byte = *(buffer + i); + } + + /* The average */ + average = ((max_byte + min_byte) / 2); + + /* Set bytes as white (0xFF) or black (0x00) */ + for (i = 0; i < 2500; i++) + { + if (*(buffer + i) > average) + *(buffer + i) = 0xFF; + else + *(buffer + i) = 0x00; + } + + region = white; + transition_counter = 0; + + /* Go through the check region - bytes 5 to 2495 */ + for (i = 5; i <= 2495; i++) + { + /* Check for transition to black */ + if ((region == white) && (*(buffer + i) == 0)) + { + if (transition_counter < 2) + { + region = black; + index1 = i; + transition_counter++; + } + else + { + return SANE_FALSE; + } + } + /* Check for transition to white */ + else if ((region == black) && (*(buffer + i) == 0xFF)) + { + if (transition_counter < 2) + { + region = white; + index2 = i; + transition_counter++; + } + else + { + return SANE_FALSE; + } + } + } + + /* Check that the number of transitions is 2 */ + if (transition_counter != 2) + { + return SANE_FALSE; + } + + /* Check that the 1st index is in range */ + low_range = HomeEdgePoint1 - HomeTolerance; + high_range = HomeEdgePoint1 + HomeTolerance; + + if ((index1 < low_range) || (index1 > high_range)) + { + return SANE_FALSE; + } + + /* Check that the 2nd index is in range */ + low_range = HomeEdgePoint2 - HomeTolerance; + high_range = HomeEdgePoint2 + HomeTolerance; + + if ((index2 < low_range) || (index2 > high_range)) + { + return SANE_FALSE; + } + + /* We made it this far, so its a good home line. Return True */ + return SANE_TRUE; + +} + +void +sanei_lexmark_low_move_fwd (SANE_Int distance, Lexmark_Device * dev, + SANE_Byte * regs) +{ + /* + This function moves the scan head forward with the highest vertical + resolution of 1200dpi. The distance moved is given by the distance + parameter. + + As an example, given a distance parameter of 600, the scan head will + move 600/1200", or 1/2" forward. + */ + + static SANE_Byte pollstopmoving_command_block[] = + { 0x80, 0xb3, 0x00, 0x01 }; + + + size_t cmd_size; + SANE_Int devnum; + SANE_Bool scan_head_moving; + SANE_Byte read_result; + + DBG (2, "sanei_lexmark_low_move_fwd: \n"); + devnum = dev->devnum; + + + /* registers set-up */ + regs[0x2c] = 0x00; + regs[0x2d] = 0x41; + regs[0x65] = 0x80; + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + regs[0x8b] = 0x00; + regs[0x8c] = 0x00; + regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + rts88xx_set_scan_frequency (regs, 0); + regs[0x93] = 0x06; + break; + case A920_SENSOR: + rts88xx_set_scan_frequency (regs, 0); + regs[0x8b] = 0xff; + regs[0x8c] = 0x02; + regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x2d] = 0x01; + rts88xx_set_scan_frequency (regs, 0); + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x2d] = 0x4f; + rts88xx_set_scan_frequency (regs, 0); + break; + } + + /* set grayscale scan + nodata/nochannel? */ + regs[0x2f] = 0xa1; + + /* set ? */ + regs[0x34] = 0x50; + regs[0x35] = 0x01; + regs[0x36] = 0x50; + regs[0x37] = 0x01; + regs[0x38] = 0x50; + /* set motor resolution divisor */ + regs[0x39] = 0x00; + /* set vertical start/end positions */ + regs[0x60] = LOBYTE (distance - 1); + regs[0x61] = HIBYTE (distance - 1); + regs[0x62] = LOBYTE (distance); + regs[0x63] = HIBYTE (distance); + /* set horizontal start position */ + regs[0x66] = 0x64; + regs[0x67] = 0x00; + /* set horizontal end position */ + regs[0x6c] = 0xc8; + regs[0x6d] = 0x00; + /* set horizontal resolution */ + regs[0x79] = 0x40; + regs[0x7a] = 0x01; + /* don't buffer data for this scan */ + regs[0xb2] = 0x04; + /* Motor enable & Coordinate space denominator */ + regs[0xc3] = 0x81; + /* ? */ + regs[0x80] = 0x00; + regs[0x81] = 0x00; + regs[0x82] = 0x00; + regs[0xc5] = 0x0a; + /* Movement direction & step size */ + regs[0xc6] = 0x09; + /* step size range2 */ + regs[0xc9] = 0x3b; + /* ? */ + regs[0xca] = 0x0a; + /* motor curve stuff */ + regs[0xe0] = 0x00; + regs[0xe1] = 0x00; + regs[0xe4] = 0x00; + regs[0xe5] = 0x00; + regs[0xe7] = 0x00; + regs[0xe8] = 0x00; + + regs[0xe2] = 0x09; + regs[0xe3] = 0x1a; + regs[0xe6] = 0xdc; + regs[0xe9] = 0x1b; + regs[0xec] = 0x07; + regs[0xef] = 0x03; + + /* prepare for register write */ + low_clr_c6 (devnum); + low_stop_mvmt (devnum); + +/* Move Forward without scanning: */ + regs[0x32] = 0x00; + low_write_all_regs (devnum, regs); + regs[0x32] = 0x40; + low_write_all_regs (devnum, regs); + + /* Stop scanner - clear reg 0xb3: */ + /* low_stop_mvmt (devnum); */ + + rts88xx_commit (devnum, regs[0x2c]); + + /* Poll for scanner stopped - return value(3:0) = 0: */ + scan_head_moving = SANE_TRUE; + while (scan_head_moving) + { +#ifdef FAKE_USB + scan_head_moving = SANE_FALSE; +#else + cmd_size = 0x04; + low_usb_bulk_write (devnum, pollstopmoving_command_block, &cmd_size); + cmd_size = 0x1; + low_usb_bulk_read (devnum, &read_result, &cmd_size); + if ((read_result & 0xF) == 0x0) + { + scan_head_moving = SANE_FALSE; + } +#endif + } + DBG (2, "sanei_lexmark_low_move_fwd: end.\n"); +} + +SANE_Bool +sanei_lexmark_low_search_home_fwd (Lexmark_Device * dev) +{ + /* This function actually searches backwards one line looking for home */ + + SANE_Int devnum; + int i; + SANE_Byte poll_result[3]; + SANE_Byte *buffer; + SANE_Byte temp_byte; + + static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; + + static SANE_Byte command5_block[] = { 0x91, 0x00, 0x09, 0xc4 }; + + size_t cmd_size; + SANE_Bool got_line; + SANE_Bool ret_val; + + devnum = dev->devnum; + + DBG (2, "sanei_lexmark_low_search_home_fwd:\n"); + + /* set up registers according to the sensor type */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x2c] = 0x0f; + dev->shadow_regs[0x2d] = 0x51; + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x35] = 0x04; + dev->shadow_regs[0x36] = 0x08; + dev->shadow_regs[0x37] = 0x08; + dev->shadow_regs[0x38] = 0x0b; + dev->shadow_regs[0x93] = 0x06; + + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x35] = 0x05; + dev->shadow_regs[0x36] = 0x09; + dev->shadow_regs[0x37] = 0x09; + dev->shadow_regs[0x38] = 0x0d; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x72] = 0x35; + dev->shadow_regs[0x74] = 0x4e; + + dev->shadow_regs[0x85] = 0x20; /* 05 */ + dev->shadow_regs[0x86] = 0x00; /* 05 */ + dev->shadow_regs[0x87] = 0x00; /* 05 */ + dev->shadow_regs[0x88] = 0x00; /* 45 */ + dev->shadow_regs[0x89] = 0x00; + dev->shadow_regs[0x8b] = 0xff; + + dev->shadow_regs[0x93] = 0x06; /* 0e */ + + dev->shadow_regs[0x75] = 0x00; /* */ + dev->shadow_regs[0x91] = 0x00; /* 60 */ + dev->shadow_regs[0x92] = 0x00; /* 8d */ + dev->shadow_regs[0xb1] = 0x00; /* */ + dev->shadow_regs[0xc5] = 0x00; /* */ + dev->shadow_regs[0xca] = 0x00; /* */ + dev->shadow_regs[0xc3] = 0x01; /* */ + break; + case A920_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x35] = 0x05; + dev->shadow_regs[0x36] = 0x09; + dev->shadow_regs[0x37] = 0x09; + dev->shadow_regs[0x38] = 0x0d; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x72] = 0x35; + dev->shadow_regs[0x74] = 0x4e; + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x88] = 0x45; + dev->shadow_regs[0x89] = 0x00; + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x8d; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x35] = 0x04; + dev->shadow_regs[0x36] = 0x08; + dev->shadow_regs[0x37] = 0x08; + dev->shadow_regs[0x38] = 0x0b; + dev->shadow_regs[0x66] = 0x88; + dev->shadow_regs[0x6c] = 0x10; + dev->shadow_regs[0x6d] = 0x14; + dev->shadow_regs[0x75] = 0x00; + dev->shadow_regs[0x93] = 0x06; + dev->shadow_regs[0xc5] = 0x00; + dev->shadow_regs[0xca] = 0x00; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x0b] = 0x70; + dev->shadow_regs[0x0c] = 0x28; + dev->shadow_regs[0x0d] = 0xa4; + + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x2f] = 0x21; + dev->shadow_regs[0x32] = 0x40; + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x35] = 0x05; + dev->shadow_regs[0x36] = 0x09; + dev->shadow_regs[0x37] = 0x09; + dev->shadow_regs[0x38] = 0x0d; + dev->shadow_regs[0x3a] = 0x20; + dev->shadow_regs[0x3b] = 0x37; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x47] = 0x01; + dev->shadow_regs[0x48] = 0x1a; + dev->shadow_regs[0x49] = 0x5b; + dev->shadow_regs[0x4a] = 0x1b; + dev->shadow_regs[0x4b] = 0x5b; + dev->shadow_regs[0x4c] = 0x05; + dev->shadow_regs[0x4d] = 0x3f; + dev->shadow_regs[0x75] = 0x00; + + dev->shadow_regs[0x85] = 0x03; + dev->shadow_regs[0x86] = 0x33; + dev->shadow_regs[0x87] = 0x8f; + dev->shadow_regs[0x88] = 0x34; + + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x8e] = 0x60; + dev->shadow_regs[0x8f] = 0x80; + + dev->shadow_regs[0x91] = 0x59; + dev->shadow_regs[0x92] = 0x10; + dev->shadow_regs[0x93] = 0x06; + + dev->shadow_regs[0xa3] = 0x0d; + dev->shadow_regs[0xa4] = 0x5e; + dev->shadow_regs[0xa5] = 0x23; + dev->shadow_regs[0xb1] = 0x07; + + dev->shadow_regs[0xc2] = 0x80; + dev->shadow_regs[0xc5] = 0x00; + dev->shadow_regs[0xca] = 0x00; + break; + } + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x8c] = 0x02; + dev->shadow_regs[0x8d] = 0x01; + dev->shadow_regs[0xb2] = 0x00; + dev->shadow_regs[0xed] = 0x00; + dev->shadow_regs[0xee] = 0x00; + + rts88xx_set_gain (dev->shadow_regs, dev->sensor->default_gain, + dev->sensor->default_gain, dev->sensor->default_gain); + rts88xx_set_offset (dev->shadow_regs, 0x80, 0x80, 0x80); + + /* set grayscale scan */ + rts88xx_set_gray_scan (dev->shadow_regs); + + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x07; + + /* set vertical start/end positions */ + dev->shadow_regs[0x60] = 0x01; + dev->shadow_regs[0x61] = 0x00; + dev->shadow_regs[0x62] = 0x02; + dev->shadow_regs[0x63] = 0x00; + + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + + /* set horizontal start position */ + dev->shadow_regs[0x66] = 0x6a; /* 0x88 for X1200 */ + dev->shadow_regs[0x67] = 0x00; + /* set horizontal end position */ + dev->shadow_regs[0x6c] = 0xf2; /* 0x1410 for X1200 */ + dev->shadow_regs[0x6d] = 0x13; + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x40; + dev->shadow_regs[0x7a] = 0x02; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x01; + /* step size range2 */ + dev->shadow_regs[0xc9] = 0x3b; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x01; + /* ? */ + dev->shadow_regs[0xe3] = 0x03; + + /* Motor disable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x01; + + + /* Stop the scanner */ + low_stop_mvmt (devnum); + + /* write regs out twice */ + dev->shadow_regs[0x32] = 0x00; + low_write_all_regs (devnum, dev->shadow_regs); + dev->shadow_regs[0x32] = 0x40; + low_write_all_regs (devnum, dev->shadow_regs); + + /* Start Scan */ + rts88xx_commit (devnum, dev->shadow_regs[0x2c]); + + /* Poll the available byte count until not 0 */ + got_line = SANE_FALSE; + while (!got_line) + { + cmd_size = 4; + low_usb_bulk_write (devnum, command4_block, &cmd_size); + cmd_size = 0x3; + low_usb_bulk_read (devnum, poll_result, &cmd_size); + if (! + (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) + { + /* if result != 00 00 00 we got data */ + got_line = SANE_TRUE; + } + } + + /* create buffer for scan data */ + buffer = calloc (2500, sizeof (char)); + + /* Tell the scanner to send the data */ + /* Write: 91 00 09 c4 */ + cmd_size = 4; + low_usb_bulk_write (devnum, command5_block, &cmd_size); + /* Read it */ + cmd_size = 0x09c4; + low_usb_bulk_read (devnum, buffer, &cmd_size); + + /* Reverse order of bytes in words of buffer */ + for (i = 0; i < 2500; i = i + 2) + { + temp_byte = *(buffer + i); + *(buffer + i) = *(buffer + i + 1); + *(buffer + i + 1) = temp_byte; + } + + /* check for home position */ + ret_val = low_is_home_line (buffer); + + if (ret_val) + DBG (2, "sanei_lexmark_low_search_home_fwd: !!!HOME POSITION!!!\n"); + + /* free the buffer */ + free (buffer); + DBG (2, "sanei_lexmark_low_search_home_fwd: end.\n"); + + return ret_val; +} + + + +SANE_Bool +sanei_lexmark_low_search_home_bwd (Lexmark_Device * dev) +{ +/* This function must only be called if the scan head is past the home dot. + It could damage the scanner if not. + + This function tells the scanner to do a grayscale scan backwards with a + 300dpi resolution. It reads 2500 bytes of data between horizontal + co-ordinates 0x6a and 0x13f2. + + The scan is set to read between vertical co-ordinates from 0x0a to 0x0f46, + or 3900 lines. This equates to 13" at 300dpi, so we must stop the scan + before it bangs against the end. A line limit is set so that a maximum of + 0x0F3C (13"*300dpi) lines can be read. + + To read the scan data we create a buffer space large enough to hold 10 + lines of data. For each read we poll twice, ignoring the first poll. This + is required for timing. We repeat the double poll until there is data + available. The number of lines (or number of buffers in our buffer space) + is calculated from the size of the data available from the scanner. The + number of buffers is calculated as the space required to hold 1.5 times + the the size of the data available from the scanner. + + After data is read from the scanner each line is checked if it is on the + home dot. Lines are continued to be read until we are no longer on the home + dot. */ + + + SANE_Int devnum; + SANE_Status status; + int i, j; + SANE_Byte poll_result[3]; + SANE_Byte *buffer; + SANE_Byte *buffer_start; + SANE_Byte temp_byte; + + SANE_Int buffer_count = 0; + SANE_Int size_requested; + SANE_Int size_returned; + SANE_Int no_of_buffers; + SANE_Int buffer_limit = 0xF3C; + SANE_Int high_byte, mid_byte, low_byte; + SANE_Int home_line_count; + SANE_Bool in_home_region; + + static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; + + static SANE_Byte command5_block[] = { 0x91, 0x00, 0xff, 0xc0 }; +#ifdef DEEP_DEBUG + FILE *img = NULL; +#endif + + size_t cmd_size; + SANE_Bool got_line; + + devnum = dev->devnum; + + DBG (2, "sanei_lexmark_low_search_home_bwd:\n"); + + /* set up registers */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x2c] = 0x0f; + dev->shadow_regs[0x2d] = 0x51; + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x35] = 0x07; + dev->shadow_regs[0x36] = 0x0f; + dev->shadow_regs[0x37] = 0x0f; + dev->shadow_regs[0x38] = 0x15; + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x09; + dev->shadow_regs[0x35] = 0x09; + dev->shadow_regs[0x36] = 0x11; + dev->shadow_regs[0x37] = 0x11; + dev->shadow_regs[0x38] = 0x19; + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x09; + dev->shadow_regs[0x35] = 0x09; + dev->shadow_regs[0x36] = 0x11; + dev->shadow_regs[0x37] = 0x11; + dev->shadow_regs[0x38] = 0x19; + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x35] = 0x07; + dev->shadow_regs[0x36] = 0x0f; + dev->shadow_regs[0x37] = 0x0f; + dev->shadow_regs[0x38] = 0x15; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x09; + dev->shadow_regs[0x35] = 0x09; + dev->shadow_regs[0x36] = 0x11; + dev->shadow_regs[0x37] = 0x11; + dev->shadow_regs[0x38] = 0x19; + dev->shadow_regs[0x85] = 0x03; + dev->shadow_regs[0x93] = 0x06; + break; + } + rts88xx_set_gain (dev->shadow_regs, dev->sensor->default_gain, + dev->sensor->default_gain, dev->sensor->default_gain); + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x8b] = 0xff; + dev->shadow_regs[0x8c] = 0x02; + dev->shadow_regs[0xb2] = 0x00; + + /* set calibration */ + rts88xx_set_offset (dev->shadow_regs, 0x80, 0x80, 0x80); + + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x03; + /* set vertical start/end positions */ + dev->shadow_regs[0x60] = 0x0a; + dev->shadow_regs[0x61] = 0x00; + dev->shadow_regs[0x62] = 0x46; + dev->shadow_regs[0x63] = 0x0f; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 2); + /* set horizontal start position */ + dev->shadow_regs[0x66] = 0x6a; /* 0x88 for X1200 */ + dev->shadow_regs[0x67] = 0x00; + /* set horizontal end position */ + dev->shadow_regs[0x6c] = 0xf2; /* 0x1410 for X1200, 13f2 for X1200/rev. 97 */ + dev->shadow_regs[0x6d] = 0x13; + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x40; + dev->shadow_regs[0x7a] = 0x02; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x19; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x01; + /* step size range2 */ + dev->shadow_regs[0xc9] = 0x3a; + /* ? */ + dev->shadow_regs[0xca] = 0x08; + /* motor curve stuff */ + dev->shadow_regs[0xe0] = 0xe3; + dev->shadow_regs[0xe1] = 0x18; + dev->shadow_regs[0xe2] = 0x03; + dev->shadow_regs[0xe3] = 0x06; + dev->shadow_regs[0xe4] = 0x2b; + dev->shadow_regs[0xe5] = 0x17; + dev->shadow_regs[0xe6] = 0xdc; + dev->shadow_regs[0xe7] = 0xb3; + dev->shadow_regs[0xe8] = 0x07; + dev->shadow_regs[0xe9] = 0x1b; + dev->shadow_regs[0xec] = 0x07; + dev->shadow_regs[0xef] = 0x03; + + /* Stop the scanner */ + low_stop_mvmt (devnum); + + /* write regs out twice */ + dev->shadow_regs[0x32] = 0x00; + low_write_all_regs (devnum, dev->shadow_regs); + dev->shadow_regs[0x32] = 0x40; + low_write_all_regs (devnum, dev->shadow_regs); + + /* Start Scan */ + status = rts88xx_commit (devnum, dev->shadow_regs[0x2c]); + + /* create buffer to hold up to 10 lines of scan data */ + buffer = calloc (10 * 2500, sizeof (char)); + + home_line_count = 0; + in_home_region = SANE_FALSE; + +#ifdef DEEP_DEBUG + img = fopen ("find_bwd.pnm", "wb"); + fprintf (img, "P5\n2500 100\n255\n"); +#endif + while (buffer_count < buffer_limit) + { + size_returned = 0; + got_line = SANE_FALSE; + while (!got_line) + { + /* always poll twice (needed for timing) - disregard 1st poll */ + cmd_size = 4; + status = low_usb_bulk_write (devnum, command4_block, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + cmd_size = 0x3; + status = low_usb_bulk_read (devnum, poll_result, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + cmd_size = 4; + status = low_usb_bulk_write (devnum, command4_block, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + cmd_size = 0x3; + status = low_usb_bulk_read (devnum, poll_result, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + if (! + (poll_result[0] == 0 && poll_result[1] == 0 + && poll_result[2] == 0)) + { + /* if result != 00 00 00 we got data */ + got_line = SANE_TRUE; + high_byte = poll_result[2] << 16; + mid_byte = poll_result[1] << 8; + low_byte = poll_result[0]; + size_returned = high_byte + mid_byte + low_byte; + } + } + + size_requested = size_returned; + size_requested = 2500; + no_of_buffers = size_returned * 3; + no_of_buffers = no_of_buffers / 2500; + no_of_buffers = no_of_buffers >> 1; + /* force 1 buffer at a time to improve accuray, which slow downs search */ + no_of_buffers = 1; + + if (no_of_buffers < 1) + no_of_buffers = 1; + else if (no_of_buffers > 10) + no_of_buffers = 10; + buffer_count = buffer_count + no_of_buffers; + size_requested = no_of_buffers * 2500; + + /* Tell the scanner to send the data */ + /* Write: 91 */ + command5_block[1] = (SANE_Byte) (size_requested >> 16); + command5_block[2] = (SANE_Byte) (size_requested >> 8); + command5_block[3] = (SANE_Byte) (size_requested & 0xFF); + + cmd_size = 4; + status = low_usb_bulk_write (devnum, command5_block, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + /* Read it */ + cmd_size = size_requested; + status = low_usb_bulk_read (devnum, buffer, &cmd_size); + if (status != SANE_STATUS_GOOD) + return SANE_FALSE; + for (i = 0; i < no_of_buffers; i++) + { + buffer_start = buffer + (i * 2500); + /* Reverse order of bytes in words of buffer */ + for (j = 0; j < 2500; j = j + 2) + { + temp_byte = *(buffer_start + j); + *(buffer_start + j) = *(buffer_start + j + 1); + *(buffer_start + j + 1) = temp_byte; + } +#ifdef DEEP_DEBUG + fwrite (buffer + (i * 2500), 2500, 1, img); +#endif + if (low_is_home_line (buffer_start)) + { + home_line_count++; + if (home_line_count > 7) + in_home_region = SANE_TRUE; + } + if (in_home_region) + { + /* slow down scanning : on purpose backtracking */ + if (home_line_count) + sleep (1); + free (buffer); +#ifdef DEEP_DEBUG + fflush (img); + i = ftell (img) / 2500; + rewind (img); + DBG (2, "sanei_lexmark_low_search_home_bwd: offset=%d\n", i); + fprintf (img, "P5\n2500 %03d\n", i); + fclose (img); +#endif + low_stop_mvmt (devnum); + DBG (2, + "sanei_lexmark_low_search_home_bwd: in home region, end.\n"); + return SANE_TRUE; + } + } + } /* end while (buffer_count > buffer_limit); */ + free (buffer); +#ifdef DEEP_DEBUG + fflush (img); + i = ftell (img) / 2500; + rewind (img); + fprintf (img, "P5\n2500 %03d\n", i); + fclose (img); +#endif + low_stop_mvmt (devnum); + + DBG (2, "sanei_lexmark_low_search_home_bwd: end.\n"); + + return SANE_FALSE; +} + +SANE_Status +low_get_start_loc (SANE_Int resolution, SANE_Int * vert_start, + SANE_Int * hor_start, SANE_Int offset, + Lexmark_Device * dev) +{ + SANE_Int start_600; + + /* Calculate vertical start distance at 600dpi */ + start_600 = 195 - offset; + + switch (resolution) + { + case 75: + *vert_start = start_600 / 8; + *hor_start = 0x68; + break; + case 150: + *vert_start = start_600 / 4; + *hor_start = 0x68; + break; + case 300: + *vert_start = start_600 / 2; + *hor_start = 0x6a; + break; + case 600: + *vert_start = start_600; + *hor_start = 0x6b; + break; + case 1200: + *vert_start = start_600 * 2; + *hor_start = 0x6b; + break; + default: + /* If we're here we have an invalid resolution */ + return SANE_STATUS_INVAL; + } + + /* maybe left margin could be autodetected */ + if (dev->model.sensor_type != X1100_B2_SENSOR) + *hor_start = 0x68; + + return SANE_STATUS_GOOD; +} + +void +low_set_scan_area (SANE_Int res, + SANE_Int tlx, + SANE_Int tly, + SANE_Int brx, + SANE_Int bry, + SANE_Int offset, + SANE_Bool half_step, + SANE_Byte * regs, Lexmark_Device * dev) +{ + + SANE_Status status; + SANE_Int vert_start; + SANE_Int hor_start; + SANE_Int vert_end; + SANE_Int hor_end; + + status = low_get_start_loc (res, &vert_start, &hor_start, offset, dev); + + /* convert pixel height to vertical location coordinates */ + vert_end = vert_start + (bry * res) / 600; + vert_start += (tly * res) / 600; + + /* scan area size : for A920, 600 color scans are done at 1200 y dpi */ + /* this follow what was found in usb logs */ + if (half_step) + { + vert_end = vert_end * 2; + vert_start = vert_start * 2; + } + + /* set vertical start position registers */ + regs[0x60] = LOBYTE (vert_start); + regs[0x61] = HIBYTE (vert_start); + /* set vertical end position registers */ + regs[0x62] = LOBYTE (vert_end); + regs[0x63] = HIBYTE (vert_end); + + /* convert pixel width to horizontal location coordinates */ + hor_end = hor_start + brx; + + /* set horizontal start position registers */ + hor_start += tlx; + regs[0x66] = LOBYTE (hor_start); + regs[0x67] = HIBYTE (hor_start); + /* set horizontal end position registers */ + regs[0x6c] = LOBYTE (hor_end); + regs[0x6d] = HIBYTE (hor_end); + + /* Debug */ + DBG (2, "low_set_scan_area: vert_start: %d (tly=%d)\n", vert_start, tly); + DBG (2, "low_set_scan_area: vert_end: %d\n", vert_end); + DBG (2, "low_set_scan_area: hor_start: %d\n", hor_start); + DBG (2, "low_set_scan_area: hor_end: %d\n", hor_end); + +} + +SANE_Int +sanei_lexmark_low_find_start_line (Lexmark_Device * dev) +{ + /* + This function scans forward 59 lines, reading 88 bytes per line from the + middle of the horizontal line: pixel 0xa84 to pixel 0x9d4. It scans with + the following parameters: + dir=fwd + mode=grayscale + h.res=300 dpi + v.res=600 dpi + hor. pixels = (0xa84 - 0x9d4)/2 = 0x58 = 88 + vert. pixels = 0x3e - 0x03 = 0x3b = 59 + data = 88x59=5192=0x1448 + + It assumes we are in the start dot, or just before it. We are reading + enough lines at 600dpi to read past the dot. We return the number of + entirely white lines read consecutively, so we know how far past the + dot we are. + + To find the number of consecutive white lines we do the following: + + Byte swap the order of the bytes in the buffer. + + Go through the buffer finding low and high values, which are computed by + comparing to the weighted average: + weighted_average = (lowest value + (highest value - lowest value)/4) + Low bytes are changed to 0xFF (white), higher of equal bytes are changed + to 0x00 (black),so that the buffer only contains white (0xFF) or black + (0x00) values. + + Next, we go through the buffer a line (88 bytes) at a time for 59 lines + to read the entire buffer. For each byte in a line we check if the + byte is black. If it is we increment the black byte counter. + + After each line we check the black byte counter. If it is greater than 0 + we increment the black line count and set the white line count to 0. If + there were no black bytes in the line we set the black line count to 0 + and increment the white line count. + + When all lines have been processed we return the white line count. + */ + + + int blackLineCount = 0; + int whiteLineCount = 0; + int blackByteCounter = 0; + unsigned char max_byte = 0; + unsigned char min_byte = 0xFF; + unsigned char weighted_average; + int i, j; +#ifdef DEEP_DEBUG + FILE *fdbg = NULL; +#endif + + SANE_Byte poll_result[3]; + SANE_Byte *buffer; + SANE_Byte temp_byte; + + static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; + + static SANE_Byte command5_block[] = { 0x91, 0x00, 0x14, 0x48 }; + + size_t cmd_size; + SANE_Bool got_line; + + DBG (2, "sanei_lexmark_low_find_start_line:\n"); + + /* set up registers */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x2c] = 0x0f; + dev->shadow_regs[0x2d] = 0x51; + dev->shadow_regs[0x34] = 0x0d; + dev->shadow_regs[0x35] = 0x0d; + dev->shadow_regs[0x36] = 0x1d; + dev->shadow_regs[0x37] = 0x1d; + dev->shadow_regs[0x38] = 0x29; + dev->shadow_regs[0x65] = 0x80; + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x93] = 0x06; + rts88xx_set_gain (dev->shadow_regs, 6, 6, 6); + break; + case X1100_2C_SENSOR: + rts88xx_set_gain (dev->shadow_regs, 10, 10, 10); + dev->shadow_regs[0x28] = 0xf5; + dev->shadow_regs[0x29] = 0xf7; + dev->shadow_regs[0x2a] = 0xf5; + dev->shadow_regs[0x2b] = 0x17; + + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x31] = 0x01; + dev->shadow_regs[0x34] = 0x11; + dev->shadow_regs[0x35] = 0x11; + dev->shadow_regs[0x36] = 0x21; + dev->shadow_regs[0x37] = 0x21; + dev->shadow_regs[0x38] = 0x31; + dev->shadow_regs[0x72] = 0x35; + dev->shadow_regs[0x74] = 0x4e; + dev->shadow_regs[0x85] = 0x02; + dev->shadow_regs[0x86] = 0x33; + dev->shadow_regs[0x87] = 0x0f; + dev->shadow_regs[0x88] = 0x24; + dev->shadow_regs[0x91] = 0x19; + dev->shadow_regs[0x92] = 0x20; + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + dev->shadow_regs[0xf3] = 0xf8; + dev->shadow_regs[0xf4] = 0x7f; + break; + case A920_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + dev->shadow_regs[0x34] = 0x11; + dev->shadow_regs[0x35] = 0x11; + dev->shadow_regs[0x36] = 0x21; + dev->shadow_regs[0x37] = 0x21; + dev->shadow_regs[0x38] = 0x31; + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x88] = 0x44; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + rts88xx_set_gain (dev->shadow_regs, 6, 6, 6); + break; + case X1200_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + dev->shadow_regs[0x34] = 0x0d; + dev->shadow_regs[0x35] = 0x0d; + dev->shadow_regs[0x36] = 0x1d; + dev->shadow_regs[0x37] = 0x1d; + dev->shadow_regs[0x38] = 0x29; + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + dev->shadow_regs[0x92] = 0x00; + rts88xx_set_gain (dev->shadow_regs, 10, 10, 10); + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + dev->shadow_regs[0x34] = 0x0d; + dev->shadow_regs[0x35] = 0x0d; + dev->shadow_regs[0x36] = 0x1d; + dev->shadow_regs[0x37] = 0x1d; + dev->shadow_regs[0x38] = 0x29; + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + rts88xx_set_gain (dev->shadow_regs, 10, 10, 10); + break; + } + + /* set offset to a safe value */ + rts88xx_set_offset (dev->shadow_regs, 0x80, 0x80, 0x80); + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x01; + /* set vertical start/end positions */ + dev->shadow_regs[0x60] = 0x03; + dev->shadow_regs[0x61] = 0x00; + dev->shadow_regs[0x62] = 0x3e; + dev->shadow_regs[0x63] = 0x00; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + /* set horizontal start position */ + dev->shadow_regs[0x66] = 0xd4; /* 0xf2 for X1200 */ + dev->shadow_regs[0x67] = 0x09; + /* set horizontal end position */ + dev->shadow_regs[0x6c] = 0x84; /* 0xa2 for X1200 */ + dev->shadow_regs[0x6d] = 0x0a; + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x40; + dev->shadow_regs[0x7a] = 0x02; + /* set for ? */ + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* set for ? */ + dev->shadow_regs[0xc5] = 0x22; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + /* step size range2 */ + dev->shadow_regs[0xc9] = 0x3b; + /* set for ? */ + dev->shadow_regs[0xca] = 0x1f; + dev->shadow_regs[0xe0] = 0xf7; + dev->shadow_regs[0xe1] = 0x16; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x87; + /* ? */ + dev->shadow_regs[0xe3] = 0x13; + dev->shadow_regs[0xe4] = 0x1b; + dev->shadow_regs[0xe5] = 0x16; + dev->shadow_regs[0xe6] = 0xdc; + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + dev->shadow_regs[0xe9] = 0x1b; + dev->shadow_regs[0xec] = 0x07; + dev->shadow_regs[0xef] = 0x03; + + /* Stop the scanner */ + low_stop_mvmt (dev->devnum); + + /* write regs out twice */ + dev->shadow_regs[0x32] = 0x00; + low_write_all_regs (dev->devnum, dev->shadow_regs); + dev->shadow_regs[0x32] = 0x40; + low_write_all_regs (dev->devnum, dev->shadow_regs); + + /* Start Scan */ + rts88xx_commit (dev->devnum, dev->shadow_regs[0x2c]); + + /* Poll the available byte count until not 0 */ + got_line = SANE_FALSE; + while (!got_line) + { + cmd_size = 4; + low_usb_bulk_write (dev->devnum, command4_block, &cmd_size); + cmd_size = 0x3; + low_usb_bulk_read (dev->devnum, poll_result, &cmd_size); + if (! + (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) + { + /* if result != 00 00 00 we got data */ + got_line = SANE_TRUE; + } +#ifdef FAKE_USB + got_line = SANE_TRUE; +#endif + } + + + /* create buffer for scan data */ + buffer = calloc (5192, sizeof (char)); + + /* Tell the scanner to send the data */ + /* Write: 91 00 14 48 */ + cmd_size = 4; + low_usb_bulk_write (dev->devnum, command5_block, &cmd_size); + /* Read it */ + cmd_size = 0x1448; + low_usb_bulk_read (dev->devnum, buffer, &cmd_size); + + /* Stop the scanner */ + low_stop_mvmt (dev->devnum); + + + /* Reverse order of bytes in words of buffer */ + for (i = 0; i < 5192; i = i + 2) + { + temp_byte = *(buffer + i); + *(buffer + i) = *(buffer + i + 1); + *(buffer + i + 1) = temp_byte; + } + +#ifdef DEEP_DEBUG + fdbg = fopen ("find_start.pnm", "wb"); + if (fdbg != NULL) + { + fprintf (fdbg, "P5\n%d %d\n255\n", 88, 59); + fwrite (buffer, 5192, 1, fdbg); + fclose (fdbg); + } +#endif + + /* Find the max and the min */ + for (i = 0; i < 5192; i++) + { + if (*(buffer + i) > max_byte) + max_byte = *(buffer + i); + if (*(buffer + i) < min_byte) + min_byte = *(buffer + i); + } + + weighted_average = min_byte + ((max_byte - min_byte) / 4); + + /* Set bytes as black (0x00) or white (0xFF) */ + for (i = 0; i < 5192; i++) + { + if (*(buffer + i) > weighted_average) + *(buffer + i) = 0xFF; + else + *(buffer + i) = 0x00; + } + + /* Go through 59 lines */ + for (j = 0; j < 59; j++) + { + blackByteCounter = 0; + /* Go through 88 bytes per line */ + for (i = 0; i < 88; i++) + { + /* Is byte black? */ + if (*(buffer + (j * 88) + i) == 0) + { + blackByteCounter++; + } + } /* end for line */ + if (blackByteCounter > 0) + { + /* This was a black line */ + blackLineCount++; + whiteLineCount = 0; + } + else + { + /* This is a white line */ + whiteLineCount++; + blackLineCount = 0; + } + } /* end for buffer */ + + DBG (2, "sanei_lexmark_low_find_start_line: end.\n"); + return whiteLineCount; +} + + +SANE_Status +sanei_lexmark_low_set_scan_regs (Lexmark_Device * dev, SANE_Int offset, + SANE_Bool calibrated) +{ + SANE_Int yres; + SANE_Bool isColourScan; + + DBG (2, "sanei_lexmark_low_set_scan_regs:\n"); + /* resolution */ + yres = dev->val[OPT_RESOLUTION].w; + + DBG (7, "sanei_lexmark_low_set_scan_regs: yres=%d DPI\n", yres); + + /* colour mode */ + if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) + isColourScan = SANE_TRUE; + else + isColourScan = SANE_FALSE; + + /* set up registers */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x2c] = 0x0f; + dev->shadow_regs[0x2d] = 0x51; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + break; + case A920_SENSOR: + dev->shadow_regs[0x2c] = 0x0d; + dev->shadow_regs[0x2d] = 0x4f; + break; + case X1200_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x2c] = 0x01; + dev->shadow_regs[0x2d] = 0x03; + break; + } + + low_set_scan_area (yres, + dev->val[OPT_TL_X].w, + dev->val[OPT_TL_Y].w, + dev->val[OPT_BR_X].w, + dev->val[OPT_BR_Y].w, + offset, + dev->model.motor_type == A920_MOTOR && isColourScan + && (yres == 600), dev->shadow_regs, dev); + + /* may be we could use a sensor descriptor that would held the max horiz dpi */ + if (dev->val[OPT_RESOLUTION].w < 600) + dev->shadow_regs[0x7a] = 600 / dev->val[OPT_RESOLUTION].w; + else + dev->shadow_regs[0x7a] = 1; + + /* 75dpi x 75dpi */ + if (yres == 75) + { + DBG (5, "sanei_lexmark_low_set_scan_regs(): 75 DPI resolution\n"); + + if (isColourScan) + { + /* set colour scan */ + dev->shadow_regs[0x2f] = 0x11; + + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x36] = 0x05; + dev->shadow_regs[0x38] = 0x05; + + dev->shadow_regs[0x80] = 0x0c; + dev->shadow_regs[0x81] = 0x0c; + dev->shadow_regs[0x82] = 0x09; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x8c; + dev->shadow_regs[0x92] = 0x40; + dev->shadow_regs[0x93] = 0x06; + break; + + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x03; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x38] = 0x03; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x03; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x38] = 0x03; + + dev->shadow_regs[0x80] = 0x07; + dev->shadow_regs[0x81] = 0x0f; + dev->shadow_regs[0x82] = 0x03; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x44; + + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x36] = 0x03; + dev->shadow_regs[0x38] = 0x01; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x80] = 0x08; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x0d; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x1e; + dev->shadow_regs[0x87] = 0x39; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + /* dev->shadow_regs[0x92] = 0x92; */ + dev->shadow_regs[0x93] = 0x06; + break; + + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x36] = 0x05; + dev->shadow_regs[0x38] = 0x04; + + dev->shadow_regs[0x80] = 0x01; + dev->shadow_regs[0x81] = 0x0a; + dev->shadow_regs[0x82] = 0x0b; + break; + } + + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x37] = 0x01; + + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x83; + /* ? */ + dev->shadow_regs[0xc5] = 0x0a; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x2b; + dev->shadow_regs[0xe1] = 0x0a; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x7f; + /* ? */ + dev->shadow_regs[0xe3] = 0x01; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0xbb; + dev->shadow_regs[0xe5] = 0x09; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0x0e; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x2b; + dev->shadow_regs[0xe8] = 0x03; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x05; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0xa0; + dev->shadow_regs[0xeb] = 0x01; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x01; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x01; + } + else + { + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x35] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x37] = 0x04; + dev->shadow_regs[0x38] = 0x06; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x03; /* these are half of B2 sensor */ + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x03; + + dev->shadow_regs[0x85] = 0x0d; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x45; + + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x8d; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x02; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x00; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x02; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x00; + break; + } + + /* set ? only for colour? */ + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x10; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x4d; + dev->shadow_regs[0xe1] = 0x1c; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x71; + /* ? */ + dev->shadow_regs[0xe3] = 0x02; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x6d; + dev->shadow_regs[0xe5] = 0x15; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0xdc; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0xad; + dev->shadow_regs[0xe8] = 0x07; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x1b; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0xe1; + dev->shadow_regs[0xeb] = 0x03; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x07; + /* bounds of movement range4 -only for 75dpi grayscale */ + dev->shadow_regs[0xed] = 0xc2; + dev->shadow_regs[0xee] = 0x02; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x03; + } + + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x0f; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x01; + + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + /* set horizontal resolution */ + if (dev->model.sensor_type != X1200_SENSOR) + dev->shadow_regs[0x79] = 0x08; + } + + /* 150dpi x 150dpi */ + if (yres == 150) + { + DBG (5, "sanei_lexmark_low_set_scan_regs(): 150 DPI resolution\n"); + + if (isColourScan) + { + /* set colour scan */ + dev->shadow_regs[0x2f] = 0x11; + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x0b; + dev->shadow_regs[0x36] = 0x0b; + dev->shadow_regs[0x38] = 0x0a; + + dev->shadow_regs[0x80] = 0x05; + dev->shadow_regs[0x81] = 0x05; + dev->shadow_regs[0x82] = 0x0a; + + dev->shadow_regs[0x85] = 0x83; + dev->shadow_regs[0x86] = 0x7e; + dev->shadow_regs[0x87] = 0xad; + dev->shadow_regs[0x88] = 0x35; + + dev->shadow_regs[0x91] = 0xfe; + dev->shadow_regs[0x92] = 0xdf; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x36] = 0x07; + dev->shadow_regs[0x38] = 0x05; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x06; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x03; + dev->shadow_regs[0x36] = 0x08; + dev->shadow_regs[0x38] = 0x05; + + dev->shadow_regs[0x80] = 0x0e; + dev->shadow_regs[0x81] = 0x07; + dev->shadow_regs[0x82] = 0x02; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0xe0; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x36] = 0x05; + dev->shadow_regs[0x38] = 0x02; + /* data compression + dev->shadow_regs[0x40] = 0x90; + dev->shadow_regs[0x50] = 0x20; */ + /* no data compression */ + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x07; + dev->shadow_regs[0x82] = 0x0b; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x1e; + dev->shadow_regs[0x87] = 0x39; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x92] = 0x92; + + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x36] = 0x05; + dev->shadow_regs[0x38] = 0x02; + + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x07; + dev->shadow_regs[0x82] = 0x0b; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x1e; + dev->shadow_regs[0x87] = 0x39; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x92] = 0x92; + break; + } + /* set ? */ + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x37] = 0x01; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x83; + /* ? */ + dev->shadow_regs[0xc5] = 0x0e; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x03; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x61; + dev->shadow_regs[0xe1] = 0x0a; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0xed; + /* ? */ + dev->shadow_regs[0xe3] = 0x02; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x29; + dev->shadow_regs[0xe5] = 0x0a; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0x0e; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x29; + dev->shadow_regs[0xe8] = 0x03; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x05; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x01; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x01; + + } + else + { + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x35] = 0x04; + dev->shadow_regs[0x36] = 0x07; + dev->shadow_regs[0x37] = 0x07; + dev->shadow_regs[0x38] = 0x0a; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x35] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x37] = 0x04; + dev->shadow_regs[0x38] = 0x05; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x35] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x37] = 0x04; + dev->shadow_regs[0x38] = 0x05; + + dev->shadow_regs[0x85] = 0x0d; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x45; + + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x8d; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x03; + + /* dev->shadow_regs[0x40] = 0x90; + dev->shadow_regs[0x50] = 0x20;*/ + /* no data compression */ + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x92; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x01; + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x36] = 0x02; + dev->shadow_regs[0x37] = 0x02; + dev->shadow_regs[0x38] = 0x03; + + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x79] = 0x20; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x92; + break; + } + + /* set ? only for colour? */ + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x16; + /* ? */ + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x01; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0xdd; + dev->shadow_regs[0xe1] = 0x18; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x01; + /* ? */ + dev->shadow_regs[0xe3] = 0x03; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x6d; + dev->shadow_regs[0xe5] = 0x15; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0xdc; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0xad; + dev->shadow_regs[0xe8] = 0x07; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x1b; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0xe1; + dev->shadow_regs[0xeb] = 0x03; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x07; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x03; + } + + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x07; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + + /* hum, horizontal resolution different for X1200 ? */ + if (dev->model.sensor_type != X1200_SENSOR) + dev->shadow_regs[0x79] = 0x20; + } + + /*300dpi x 300dpi */ + if (yres == 300) + { + DBG (5, "sanei_lexmark_low_set_scan_regs(): 300 DPI resolution\n"); + + if (isColourScan) + { + /* set colour scan */ + dev->shadow_regs[0x2f] = 0x11; + + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x15; + dev->shadow_regs[0x36] = 0x15; + dev->shadow_regs[0x38] = 0x14; + + dev->shadow_regs[0x80] = 0x0a; + dev->shadow_regs[0x81] = 0x0a; + dev->shadow_regs[0x82] = 0x06; + + dev->shadow_regs[0x85] = 0x83; + dev->shadow_regs[0x86] = 0x7e; + dev->shadow_regs[0x87] = 0xad; + dev->shadow_regs[0x88] = 0x35; + + dev->shadow_regs[0x91] = 0xfe; + dev->shadow_regs[0x92] = 0xdf; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x08; + dev->shadow_regs[0x36] = 0x0d; + dev->shadow_regs[0x38] = 0x09; + + dev->shadow_regs[0x80] = 0x0e; + dev->shadow_regs[0x81] = 0x04; + dev->shadow_regs[0x82] = 0x0a; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x06; + dev->shadow_regs[0x36] = 0x10; + dev->shadow_regs[0x38] = 0x09; + + dev->shadow_regs[0x80] = 0x0c; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x04; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0xe0; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x36] = 0x09; + dev->shadow_regs[0x38] = 0x04; + + /* data compression + dev->shadow_regs[0x40] = 0x90; + dev->shadow_regs[0x50] = 0x20; */ + /* no data compression */ + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x0e; + dev->shadow_regs[0x82] = 0x06; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x36] = 0x09; + dev->shadow_regs[0x38] = 0x04; + + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x0e; + dev->shadow_regs[0x82] = 0x06; + break; + } + + /* set ? */ + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x37] = 0x01; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x03; + /* set ? */ + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x83; + /* ? */ + dev->shadow_regs[0xc5] = 0x17; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x0a; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x75; + dev->shadow_regs[0xe1] = 0x0a; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0xdd; + /* ? */ + dev->shadow_regs[0xe3] = 0x05; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x59; + dev->shadow_regs[0xe5] = 0x0a; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0x0e; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x05; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x01; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x01; + } + else + { + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + /* set ? */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x08; + dev->shadow_regs[0x35] = 0x08; + dev->shadow_regs[0x36] = 0x0f; + dev->shadow_regs[0x37] = 0x0f; + dev->shadow_regs[0x38] = 0x16; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x04; + dev->shadow_regs[0x35] = 0x04; + dev->shadow_regs[0x36] = 0x07; + dev->shadow_regs[0x37] = 0x07; + dev->shadow_regs[0x38] = 0x0a; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x03; + dev->shadow_regs[0x35] = 0x03; + dev->shadow_regs[0x36] = 0x06; + dev->shadow_regs[0x37] = 0x06; + dev->shadow_regs[0x38] = 0x09; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0xe0; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x35] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x37] = 0x04; + dev->shadow_regs[0x38] = 0x06; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x02; + dev->shadow_regs[0x35] = 0x02; + dev->shadow_regs[0x36] = 0x04; + dev->shadow_regs[0x37] = 0x04; + dev->shadow_regs[0x38] = 0x06; + break; + } + + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x03; + /* set ? only for colour? */ + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x19; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x08; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0xe3; + dev->shadow_regs[0xe1] = 0x18; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x03; + /* ? */ + dev->shadow_regs[0xe3] = 0x06; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x2b; + dev->shadow_regs[0xe5] = 0x17; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0xdc; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0xb3; + dev->shadow_regs[0xe8] = 0x07; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x1b; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x07; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x03; + } + + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x20; + } + + /* 600dpi x 600dpi */ + if (yres == 600) + { + DBG (5, "sanei_lexmark_low_set_scan_regs(): 600 DPI resolution\n"); + + if (isColourScan) + { + /* set colour scan */ + dev->shadow_regs[0x2f] = 0x11; + /* set ? */ + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x15; + dev->shadow_regs[0x36] = 0x15; + dev->shadow_regs[0x38] = 0x14; + + dev->shadow_regs[0x80] = 0x02; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x08; + + dev->shadow_regs[0x85] = 0x83; + dev->shadow_regs[0x86] = 0x7e; + dev->shadow_regs[0x87] = 0xad; + dev->shadow_regs[0x88] = 0x35; + + dev->shadow_regs[0x91] = 0xfe; + dev->shadow_regs[0x92] = 0xdf; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x08; + dev->shadow_regs[0x36] = 0x0d; + dev->shadow_regs[0x38] = 0x09; + + dev->shadow_regs[0x80] = 0x0e; + dev->shadow_regs[0x81] = 0x02; + dev->shadow_regs[0x82] = 0x0a; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x06; + dev->shadow_regs[0x36] = 0x0f; + dev->shadow_regs[0x38] = 0x09; + + dev->shadow_regs[0x79] = 0x40; + + dev->shadow_regs[0x80] = 0x0e; + dev->shadow_regs[0x81] = 0x0e; + dev->shadow_regs[0x82] = 0x00; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x36] = 0x0a; + dev->shadow_regs[0x38] = 0x04; + + /* data compression + dev->shadow_regs[0x40] = 0x90; + dev->shadow_regs[0x50] = 0x20; */ + + /* no data compression */ + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x80] = 0x02; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x06; + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x0d; + dev->shadow_regs[0x36] = 0x13; + dev->shadow_regs[0x38] = 0x10; + + dev->shadow_regs[0x80] = 0x04; + dev->shadow_regs[0x81] = 0x0e; + dev->shadow_regs[0x82] = 0x08; + + dev->shadow_regs[0x85] = 0x02; + dev->shadow_regs[0x86] = 0x3b; + dev->shadow_regs[0x87] = 0x0f; + dev->shadow_regs[0x88] = 0x24; + + dev->shadow_regs[0x91] = 0x19; + dev->shadow_regs[0x92] = 0x30; + dev->shadow_regs[0x93] = 0x0e; + dev->shadow_regs[0xc5] = 0x17; + dev->shadow_regs[0xc6] = 0x09; + dev->shadow_regs[0xca] = 0x0a; + break; + } + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x37] = 0x01; + + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x03; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 2); + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x86; + /* ? */ + dev->shadow_regs[0xc5] = 0x27; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x0c; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x1a; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x57; + dev->shadow_regs[0xe1] = 0x0a; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0xbf; + /* ? */ + dev->shadow_regs[0xe3] = 0x05; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x3b; + dev->shadow_regs[0xe5] = 0x0a; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0x0e; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x05; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x01; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x01; + } + else + { + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + switch (dev->model.sensor_type) + { + case X1100_B2_SENSOR: + dev->shadow_regs[0x34] = 0x11; + dev->shadow_regs[0x35] = 0x11; + dev->shadow_regs[0x36] = 0x21; + dev->shadow_regs[0x37] = 0x21; + dev->shadow_regs[0x38] = 0x31; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case X1100_2C_SENSOR: + dev->shadow_regs[0x34] = 0x07; + dev->shadow_regs[0x35] = 0x07; + dev->shadow_regs[0x36] = 0x0d; + dev->shadow_regs[0x37] = 0x0d; + dev->shadow_regs[0x38] = 0x13; + + dev->shadow_regs[0x85] = 0x20; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + break; + case A920_SENSOR: + dev->shadow_regs[0x34] = 0x05; + dev->shadow_regs[0x35] = 0x05; + dev->shadow_regs[0x36] = 0x0b; + dev->shadow_regs[0x37] = 0x0b; + dev->shadow_regs[0x38] = 0x11; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0xe0; + dev->shadow_regs[0x92] = 0x85; + dev->shadow_regs[0x93] = 0x0e; + break; + case X1200_SENSOR: + dev->shadow_regs[0x34] = 0x03; + dev->shadow_regs[0x35] = 0x03; + dev->shadow_regs[0x36] = 0x07; + dev->shadow_regs[0x37] = 0x07; + dev->shadow_regs[0x38] = 0x0b; + + /* data compression + dev->shadow_regs[0x40] = 0x90; + dev->shadow_regs[0x50] = 0x20; */ + /* no data compression */ + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x00; + + break; + case X1200_USB2_SENSOR: + dev->shadow_regs[0x34] = 0x03; + dev->shadow_regs[0x35] = 0x03; + dev->shadow_regs[0x36] = 0x07; + dev->shadow_regs[0x37] = 0x07; + dev->shadow_regs[0x38] = 0x0b; + + dev->shadow_regs[0x40] = 0x80; + dev->shadow_regs[0x50] = 0x00; + + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0xff; + dev->shadow_regs[0x88] = 0x02; + + dev->shadow_regs[0x92] = 0x00; + break; + } + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x01; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 1); + + /* set ? only for colour? */ + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x22; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + /* ? */ + dev->shadow_regs[0xc9] = 0x3b; + dev->shadow_regs[0xca] = 0x1f; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0xf7; + dev->shadow_regs[0xe1] = 0x16; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x87; + /* ? */ + dev->shadow_regs[0xe3] = 0x13; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x1b; + dev->shadow_regs[0xe5] = 0x16; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0xdc; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x1b; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x07; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x03; + } + + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x40; + } + /*600dpi x 1200dpi */ + if (yres == 1200) + { + DBG (5, "sanei_lexmark_low_set_scan_regs(): 1200 DPI resolution\n"); + + if (isColourScan) + { + /* set colour scan */ + dev->shadow_regs[0x2f] = 0x11; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x01; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 2); + + if (dev->model.sensor_type == X1100_B2_SENSOR) + { + /* set ? */ + dev->shadow_regs[0x34] = 0x29; + dev->shadow_regs[0x36] = 0x29; + dev->shadow_regs[0x38] = 0x28; + /* set ? */ + dev->shadow_regs[0x80] = 0x04; + dev->shadow_regs[0x81] = 0x04; + dev->shadow_regs[0x82] = 0x08; + dev->shadow_regs[0x85] = 0x83; + dev->shadow_regs[0x86] = 0x7e; + dev->shadow_regs[0x87] = 0xad; + dev->shadow_regs[0x88] = 0x35; + dev->shadow_regs[0x91] = 0xfe; + dev->shadow_regs[0x92] = 0xdf; + } + else + { /* A920 case */ + dev->shadow_regs[0x34] = 0x0c; + dev->shadow_regs[0x36] = 0x1e; + dev->shadow_regs[0x38] = 0x10; + + dev->shadow_regs[0x80] = 0x0c; + dev->shadow_regs[0x81] = 0x08; + dev->shadow_regs[0x82] = 0x0c; + + dev->shadow_regs[0x85] = 0x05; + dev->shadow_regs[0x86] = 0x14; + dev->shadow_regs[0x87] = 0x06; + dev->shadow_regs[0x88] = 0x04; + + dev->shadow_regs[0x91] = 0x60; + dev->shadow_regs[0x92] = 0x85; + } + + dev->shadow_regs[0x35] = 0x01; + dev->shadow_regs[0x37] = 0x01; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x01; + dev->shadow_regs[0x93] = 0x0e; + + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x86; + /* ? */ + dev->shadow_regs[0xc5] = 0x41; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x0c; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x40; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x00; + dev->shadow_regs[0xe1] = 0x00; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0x85; + /* ? */ + dev->shadow_regs[0xe3] = 0x0b; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x00; + dev->shadow_regs[0xe5] = 0x00; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0x0e; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x05; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x01; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x01; + } + else + { + /* set grayscale scan */ + dev->shadow_regs[0x2f] = 0x21; + /* set ? */ + dev->shadow_regs[0x34] = 0x22; + dev->shadow_regs[0x35] = 0x22; + dev->shadow_regs[0x36] = 0x42; + dev->shadow_regs[0x37] = 0x42; + dev->shadow_regs[0x38] = 0x62; + /* set motor resolution divisor */ + dev->shadow_regs[0x39] = 0x01; + /* set # of head moves per CIS read */ + rts88xx_set_scan_frequency (dev->shadow_regs, 0); + + /* set ? only for colour? */ + dev->shadow_regs[0x80] = 0x00; + dev->shadow_regs[0x81] = 0x00; + dev->shadow_regs[0x82] = 0x00; + dev->shadow_regs[0x85] = 0x00; + dev->shadow_regs[0x86] = 0x00; + dev->shadow_regs[0x87] = 0x00; + dev->shadow_regs[0x88] = 0x00; + dev->shadow_regs[0x91] = 0x00; + dev->shadow_regs[0x92] = 0x00; + dev->shadow_regs[0x93] = 0x06; + /* Motor enable & Coordinate space denominator */ + dev->shadow_regs[0xc3] = 0x81; + /* ? */ + dev->shadow_regs[0xc5] = 0x41; + /* Movement direction & step size */ + dev->shadow_regs[0xc6] = 0x09; + /* ? */ + dev->shadow_regs[0xc9] = 0x3a; + dev->shadow_regs[0xca] = 0x40; + /* bounds of movement range0 */ + dev->shadow_regs[0xe0] = 0x00; + dev->shadow_regs[0xe1] = 0x00; + /* step size range0 */ + dev->shadow_regs[0xe2] = 0xc7; + /* ? */ + dev->shadow_regs[0xe3] = 0x29; + /* bounds of movement range1 */ + dev->shadow_regs[0xe4] = 0x00; + dev->shadow_regs[0xe5] = 0x00; + /* step size range1 */ + dev->shadow_regs[0xe6] = 0xdc; + /* bounds of movement range2 */ + dev->shadow_regs[0xe7] = 0x00; + dev->shadow_regs[0xe8] = 0x00; + /* step size range2 */ + dev->shadow_regs[0xe9] = 0x1b; + /* bounds of movement range3 */ + dev->shadow_regs[0xea] = 0x00; + dev->shadow_regs[0xeb] = 0x00; + /* step size range3 */ + dev->shadow_regs[0xec] = 0x07; + /* step size range4 */ + dev->shadow_regs[0xef] = 0x03; + } + + /* set horizontal resolution */ + dev->shadow_regs[0x79] = 0x40; + } + + /* is calibration has been done, we override fixed settings with detected ones */ + if (calibrated) + { + /* override fixed values with ones from calibration */ + if (rts88xx_is_color (dev->shadow_regs)) + { + rts88xx_set_offset (dev->shadow_regs, + dev->offset.red, + dev->offset.green, dev->offset.blue); + rts88xx_set_gain (dev->shadow_regs, + dev->gain.red, dev->gain.green, dev->gain.blue); + } + else + { + rts88xx_set_offset (dev->shadow_regs, + dev->offset.gray, + dev->offset.gray, dev->offset.gray); + rts88xx_set_gain (dev->shadow_regs, + dev->gain.gray, dev->gain.gray, dev->gain.gray); + } + } + DBG (2, "sanei_lexmark_low_set_scan_regs: end.\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +sanei_lexmark_low_start_scan (Lexmark_Device * dev) +{ + SANE_Int devnum; + + static SANE_Byte command4_block[] = { 0x90, 0x00, 0x00, 0x03 }; + + static SANE_Byte command5_block[] = { 0x80, 0xb3, 0x00, 0x01 }; + + SANE_Byte poll_result[3]; + SANE_Byte read_result; + SANE_Bool scan_head_moving; + size_t size; + + devnum = dev->devnum; + + dev->transfer_buffer = NULL; /* No data xferred yet */ + DBG (2, "sanei_lexmark_low_start_scan:\n"); + + + /* 80 b3 00 01 - poll for scanner not moving */ + scan_head_moving = SANE_TRUE; + while (scan_head_moving) + { + size = 4; + low_usb_bulk_write (devnum, command5_block, &size); + size = 0x1; + low_usb_bulk_read (devnum, &read_result, &size); + if ((read_result & 0xF) == 0x0) + { + scan_head_moving = SANE_FALSE; + } + /* F.O. Should be a timeout here so we don't hang if something breaks */ +#ifdef FAKE_USB + scan_head_moving = SANE_FALSE; +#endif + } + + /* Clear C6 */ + low_clr_c6 (devnum); + /* Stop the scanner */ + low_stop_mvmt (devnum); + + /*Set regs x2 */ + dev->shadow_regs[0x32] = 0x00; + low_write_all_regs (devnum, dev->shadow_regs); + dev->shadow_regs[0x32] = 0x40; + low_write_all_regs (devnum, dev->shadow_regs); + + /* Start Scan */ + rts88xx_commit (devnum, dev->shadow_regs[0x2c]); + + /* We start with 0 bytes remaining to be read */ + dev->bytes_remaining = 0; + /* and 0 bytes in the transfer buffer */ + dev->bytes_in_buffer = 0; + dev->bytes_read = 0; + + /* Poll the available byte count until not 0 */ + while (1) + { + size = 4; + low_usb_bulk_write (devnum, command4_block, &size); + size = 0x3; + low_usb_bulk_read (devnum, poll_result, &size); + if (! + (poll_result[0] == 0 && poll_result[1] == 0 && poll_result[2] == 0)) + { + /* if result != 00 00 00 we got data */ + + /* data_size should be used to set bytes_remaining */ + /* data_size is set from sane_get_parameters () */ + dev->bytes_remaining = dev->data_size; + /* Initialize the read buffer */ + read_buffer_init (dev, dev->params.bytes_per_line); + return SANE_STATUS_GOOD; + + } + size = 4; + /* I'm not sure why the Windows driver does this - probably a timeout? */ + low_usb_bulk_write (devnum, command5_block, &size); + size = 0x1; + low_usb_bulk_read (devnum, &read_result, &size); + if (read_result != 0x68) + { + dev->bytes_remaining = 0; + return SANE_STATUS_IO_ERROR; + } + } + + DBG (2, "sanei_lexmark_low_start_scan: end.\n"); + return SANE_STATUS_GOOD; +} + +long +sanei_lexmark_low_read_scan_data (SANE_Byte * data, SANE_Int size, + Lexmark_Device * dev) +{ + SANE_Bool isColourScan, isGrayScan; + static SANE_Byte command1_block[] = { 0x91, 0x00, 0xff, 0xc0 }; + size_t cmd_size, xfer_request; + long bytes_read; + SANE_Bool even_byte; + SANE_Status status; + int i, k, val; + + DBG (2, "sanei_lexmark_low_read_scan_data:\n"); + + /* colour mode */ + isGrayScan = SANE_FALSE; + if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) + isColourScan = SANE_TRUE; + else + { + isColourScan = SANE_FALSE; + /* grayscale mode */ + if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) + isGrayScan = SANE_TRUE; + } + + /* Check if we have a transfer buffer. Create one and fill it if we don't */ + if (dev->transfer_buffer == NULL) + { + if (dev->bytes_remaining > 0) + { + if (dev->bytes_remaining > MAX_XFER_SIZE) + xfer_request = MAX_XFER_SIZE; + else + xfer_request = dev->bytes_remaining; + + command1_block[2] = (SANE_Byte) (xfer_request >> 8); + command1_block[3] = (SANE_Byte) (xfer_request & 0xFF); + + /* wait for data */ + status = low_poll_data (dev->devnum); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "sanei_lexmark_low_read_scan_data: time-out while waiting for data.\n"); + return status; + } + + /* Create buffer to hold the amount we will request */ + dev->transfer_buffer = (SANE_Byte *) malloc (MAX_XFER_SIZE); + if (dev->transfer_buffer == NULL) + return SANE_STATUS_NO_MEM; + + /* Fill it */ + /* Write: 91 00 (xfer_size) */ + cmd_size = 4; + low_usb_bulk_write (dev->devnum, command1_block, &cmd_size); + + /* Read: xfer_size bytes */ + cmd_size = xfer_request; + low_usb_bulk_read (dev->devnum, dev->transfer_buffer, &cmd_size); + + /* apply shading coefficients */ + k = dev->bytes_read % dev->read_buffer->linesize; + for (i = 0; i < (int) cmd_size; i++) + { + val = dev->transfer_buffer[i]; + val = (int) ((float) val * dev->shading_coeff[k] + 0.5); + if (val > 255) + val = 255; + dev->transfer_buffer[i] = val; + k++; + if ((size_t) k == dev->read_buffer->linesize) + k = 0; + } + + /* advance by the amount actually read from device */ + dev->bytes_read += cmd_size; + dev->bytes_remaining -= cmd_size; + dev->bytes_in_buffer = cmd_size; + dev->read_pointer = dev->transfer_buffer; + DBG (2, "sanei_lexmark_low_read_scan_data:\n"); + DBG (2, " Filled a buffer from the scanner\n"); + DBG (2, " bytes_remaining: %lu\n", (u_long) dev->bytes_remaining); + DBG (2, " bytes_in_buffer: %lu\n", (u_long) dev->bytes_in_buffer); + DBG (2, " read_pointer: %p\n", dev->read_pointer); + } + } + + DBG (5, "READ BUFFER INFO: \n"); + DBG (5, " write ptr: %p\n", dev->read_buffer->writeptr); + DBG (5, " read ptr: %p\n", dev->read_buffer->readptr); + DBG (5, " max write ptr: %p\n", dev->read_buffer->max_writeptr); + DBG (5, " buffer size: %lu\n", (u_long) dev->read_buffer->size); + DBG (5, " line size: %lu\n", (u_long) dev->read_buffer->linesize); + DBG (5, " empty: %d\n", dev->read_buffer->empty); + DBG (5, " line no: %d\n", dev->read_buffer->image_line_no); + + + /* If there is space in the read buffer, copy the transfer buffer over */ + if (read_buffer_bytes_available (dev->read_buffer) >= dev->bytes_in_buffer) + { + even_byte = SANE_TRUE; + while (dev->bytes_in_buffer) + { + + /* Colour Scan */ + if (isColourScan) + { + if (even_byte) + read_buffer_add_byte (dev->read_buffer, + dev->read_pointer + 1); + else + read_buffer_add_byte (dev->read_buffer, + dev->read_pointer - 1); + even_byte = !even_byte; + } + /* Gray Scan */ + else if (isGrayScan) + { + if (even_byte) + read_buffer_add_byte_gray (dev->read_buffer, + dev->read_pointer + 1); + else + read_buffer_add_byte_gray (dev->read_buffer, + dev->read_pointer - 1); + even_byte = !even_byte; + } + /* Lineart Scan */ + else + { + if (even_byte) + read_buffer_add_bit_lineart (dev->read_buffer, + dev->read_pointer + 1, + dev->threshold); + else + read_buffer_add_bit_lineart (dev->read_buffer, + dev->read_pointer - 1, + dev->threshold); + even_byte = !even_byte; + } + dev->read_pointer = dev->read_pointer + sizeof (SANE_Byte); + dev->bytes_in_buffer--; + } + /* free the transfer buffer */ + free (dev->transfer_buffer); + dev->transfer_buffer = NULL; + } + + DBG (5, "READ BUFFER INFO: \n"); + DBG (5, " write ptr: %p\n", dev->read_buffer->writeptr); + DBG (5, " read ptr: %p\n", dev->read_buffer->readptr); + DBG (5, " max write ptr: %p\n", dev->read_buffer->max_writeptr); + DBG (5, " buffer size: %lu\n", (u_long) dev->read_buffer->size); + DBG (5, " line size: %lu\n", (u_long) dev->read_buffer->linesize); + DBG (5, " empty: %d\n", dev->read_buffer->empty); + DBG (5, " line no: %d\n", dev->read_buffer->image_line_no); + + /* Read blocks out of read buffer */ + bytes_read = read_buffer_get_bytes (dev->read_buffer, data, size); + + DBG (2, "sanei_lexmark_low_read_scan_data:\n"); + DBG (2, " Copying lines from buffer to data\n"); + DBG (2, " bytes_remaining: %lu\n", (u_long) dev->bytes_remaining); + DBG (2, " bytes_in_buffer: %lu\n", (u_long) dev->bytes_in_buffer); + DBG (2, " read_pointer: %p\n", dev->read_buffer->readptr); + DBG (2, " bytes_read %lu\n", (u_long) bytes_read); + + /* if no more bytes to xfer and read buffer empty we're at the end */ + if ((dev->bytes_remaining == 0) && read_buffer_is_empty (dev->read_buffer)) + { + if (!dev->eof) + { + DBG (2, + "sanei_lexmark_low_read_scan_data: EOF- parking the scanner\n"); + dev->eof = SANE_TRUE; + low_rewind (dev, dev->shadow_regs); + } + else + { + DBG (2, "ERROR: Why are we trying to set eof more than once?\n"); + } + } + + DBG (2, "sanei_lexmark_low_read_scan_data: end.\n"); + return bytes_read; +} + +void +low_rewind (Lexmark_Device * dev, SANE_Byte * regs) +{ + SANE_Int new_location; + SANE_Int location; + SANE_Int scale; + + DBG (2, "low_rewind: \n"); + + /* We rewind at 1200dpi resolution. We rely on content of shadow registers + to compute the number of lines at 1200 dpi to go back */ + + /* first move to start of scanning area */ + scale = 600 / dev->val[OPT_RESOLUTION].w; + new_location = ((dev->val[OPT_BR_Y].w / scale) * scale) * 2; + + /* then add distance to go to the "origin dot" */ + if (rts88xx_is_color (regs)) + new_location += 400; + else + new_location += 420; + + location = new_location - 1; + DBG (2, "low_rewind: %d=>new_location=%d\n", dev->val[OPT_BR_Y].w, + new_location); + + /* stops any pending scan */ + low_clr_c6 (dev->devnum); + low_cancel (dev->devnum); + + /* set regs for rewind */ + regs[0x2f] = 0xa1; + regs[0x32] = 0x00; + regs[0x39] = 0x00; + + /* all other regs are always the same. these ones change with parameters */ + /* the following 4 regs are the location 61,60 and the location+1 63,62 */ + + regs[0x60] = LOBYTE (location); + regs[0x61] = HIBYTE (location); + regs[0x62] = LOBYTE (new_location); + regs[0x63] = HIBYTE (new_location); + +/* set regs for rewind */ + regs[0x79] = 0x40; + regs[0xb2] = 0x04; + regs[0xc3] = 0x81; + regs[0xc6] = 0x01; + regs[0xc9] = 0x3b; + regs[0xe0] = 0x2b; + regs[0xe1] = 0x17; + regs[0xe2] = 0xe7; + regs[0xe3] = 0x03; + regs[0xe6] = 0xdc; + regs[0xe7] = 0xb3; + regs[0xe8] = 0x07; + regs[0xe9] = 0x1b; + regs[0xea] = 0x00; + regs[0xeb] = 0x00; + regs[0xec] = 0x07; + regs[0xef] = 0x03; + + /* starts scan */ + low_start_scan (dev->devnum, regs); + DBG (2, "low_rewind: end.\n"); +} + + +SANE_Status +read_buffer_init (Lexmark_Device * dev, int bytesperline) +{ + size_t no_lines_in_buffer; + + DBG (2, "read_buffer_init: Start\n"); + + dev->read_buffer = (Read_Buffer *) malloc (sizeof (Read_Buffer)); + if (dev->read_buffer == NULL) + return SANE_STATUS_NO_MEM; + dev->read_buffer->linesize = bytesperline; + dev->read_buffer->gray_offset = 0; + dev->read_buffer->max_gray_offset = bytesperline - 1; + dev->read_buffer->region = RED; + dev->read_buffer->red_offset = 0; + dev->read_buffer->green_offset = 1; + dev->read_buffer->blue_offset = 2; + dev->read_buffer->max_red_offset = bytesperline - 3; + dev->read_buffer->max_green_offset = bytesperline - 2; + dev->read_buffer->max_blue_offset = bytesperline - 1; + no_lines_in_buffer = 3 * MAX_XFER_SIZE / bytesperline; + dev->read_buffer->size = bytesperline * no_lines_in_buffer; + dev->read_buffer->data = (SANE_Byte *) malloc (dev->read_buffer->size); + if (dev->read_buffer->data == NULL) + return SANE_STATUS_NO_MEM; + dev->read_buffer->readptr = dev->read_buffer->data; + dev->read_buffer->writeptr = dev->read_buffer->data; + dev->read_buffer->max_writeptr = dev->read_buffer->data + + (no_lines_in_buffer - 1) * bytesperline; + dev->read_buffer->empty = SANE_TRUE; + dev->read_buffer->image_line_no = 0; + dev->read_buffer->bit_counter = 0; + dev->read_buffer->max_lineart_offset = dev->params.pixels_per_line - 1; + return SANE_STATUS_GOOD; +} + +SANE_Status +read_buffer_free (Read_Buffer * read_buffer) +{ + DBG (2, "read_buffer_free:\n"); + if (read_buffer) + { + free (read_buffer->data); + free (read_buffer); + read_buffer = NULL; + } + return SANE_STATUS_GOOD; +} + +size_t +read_buffer_bytes_available (Read_Buffer * rb) +{ + + DBG (2, "read_buffer_bytes_available:\n"); + + if (rb->empty) + return rb->size; + else if ((size_t) abs (rb->writeptr - rb->readptr) < rb->linesize) + return 0; /* ptrs are less than one line apart */ + else if (rb->writeptr < rb->readptr) + return (rb->readptr - rb->writeptr - rb->linesize); + else + return (rb->size + rb->readptr - rb->writeptr - rb->linesize); +} + +SANE_Status +read_buffer_add_byte (Read_Buffer * rb, SANE_Byte * byte_pointer) +{ + + /* DBG(2, "read_buffer_add_byte:\n"); */ + /* F.O. Need to fix the endian byte ordering here */ + + switch (rb->region) + { + case RED: + *(rb->writeptr + rb->red_offset) = *byte_pointer; + if (rb->red_offset == rb->max_red_offset) + { + rb->red_offset = 0; + rb->region = GREEN; + } + else + rb->red_offset = rb->red_offset + (3 * sizeof (SANE_Byte)); + return SANE_STATUS_GOOD; + case GREEN: + *(rb->writeptr + rb->green_offset) = *byte_pointer; + if (rb->green_offset == rb->max_green_offset) + { + rb->green_offset = 1; + rb->region = BLUE; + } + else + rb->green_offset = rb->green_offset + (3 * sizeof (SANE_Byte)); + return SANE_STATUS_GOOD; + case BLUE: + *(rb->writeptr + rb->blue_offset) = *byte_pointer; + if (rb->blue_offset == rb->max_blue_offset) + { + rb->image_line_no++; + /* finished a line. read_buffer no longer empty */ + rb->empty = SANE_FALSE; + rb->blue_offset = 2; + rb->region = RED; + if (rb->writeptr == rb->max_writeptr) + rb->writeptr = rb->data; /* back to beginning of buffer */ + else + rb->writeptr = rb->writeptr + rb->linesize; /* next line */ + } + else + rb->blue_offset = rb->blue_offset + (3 * sizeof (SANE_Byte)); + return SANE_STATUS_GOOD; + } + return SANE_STATUS_GOOD; +} + +SANE_Status +read_buffer_add_byte_gray (Read_Buffer * rb, SANE_Byte * byte_pointer) +{ + + /* DBG(2, "read_buffer_add_byte_gray:\n"); */ + + *(rb->writeptr + rb->gray_offset) = *byte_pointer; + + if (rb->gray_offset == rb->max_gray_offset) + { + rb->image_line_no++; + /* finished a line. read_buffer no longer empty */ + rb->empty = SANE_FALSE; + rb->gray_offset = 0; + + if (rb->writeptr == rb->max_writeptr) + rb->writeptr = rb->data; /* back to beginning of buffer */ + else + rb->writeptr = rb->writeptr + rb->linesize; /* next line */ + } + else + rb->gray_offset = rb->gray_offset + (1 * sizeof (SANE_Byte)); + return SANE_STATUS_GOOD; +} + +SANE_Status +read_buffer_add_bit_lineart (Read_Buffer * rb, SANE_Byte * byte_pointer, + SANE_Byte threshold) +{ + SANE_Byte tmpByte; + SANE_Byte *currentBytePtr; + SANE_Int bitIndex; + + /* DBG(2, "read_buffer_add_bit_lineart:\n"); */ + + /* threshold = 0x80; */ + tmpByte = 0; + /* Create a bit by comparing incoming byte to threshold */ + if (*byte_pointer <= threshold) + { + tmpByte = 128; + } + + /* Calculate the bit index in the current byte */ + bitIndex = rb->bit_counter % 8; + /* Move the bit to its correct position in the temporary byte */ + tmpByte = tmpByte >> bitIndex; + /* Get the pointer to the current byte */ + currentBytePtr = rb->writeptr + rb->gray_offset; + + /* If this is the first write to this byte, clear the byte */ + if (bitIndex == 0) + *currentBytePtr = 0; + /* Set the value of the bit in the current byte */ + *currentBytePtr = *currentBytePtr | tmpByte; + + /* last bit in the line? */ + if (rb->bit_counter == rb->max_lineart_offset) + { + /* Check if we're at the last byte of the line - error if not */ + if (rb->gray_offset != rb->max_gray_offset) + { + DBG (5, "read_buffer_add_bit_lineart:\n"); + DBG (5, " Last bit of line is not last byte.\n"); + DBG (5, " Bit Index: %d, Byte Index: %d. \n", rb->bit_counter, + rb->max_gray_offset); + return SANE_STATUS_INVAL; + } + rb->image_line_no++; + /* line finished read_buffer no longer empty */ + rb->empty = SANE_FALSE; + rb->gray_offset = 0; + /* are we at the last line in the read buffer ? */ + if (rb->writeptr == rb->max_writeptr) + rb->writeptr = rb->data; /* back to beginning of buffer */ + else + rb->writeptr = rb->writeptr + rb->linesize; /* next line */ + /* clear the bit counter */ + rb->bit_counter = 0; + } + /* last bit in the byte? */ + else if (bitIndex == 7) + { + /* Not at the end of the line, but byte done. Increment byte offset */ + rb->gray_offset = rb->gray_offset + (1 * sizeof (SANE_Byte)); + /* increment bit counter */ + rb->bit_counter++; + } + else + { + /* else increment bit counter */ + rb->bit_counter++; + } + + return SANE_STATUS_GOOD; +} + + +size_t +read_buffer_get_bytes (Read_Buffer * rb, SANE_Byte * buffer, size_t rqst_size) +{ + /* Read_Buffer *rb; */ + size_t available_bytes; + + /* rb = read_buffer; */ + if (rb->empty) + return 0; + else if (rb->writeptr > rb->readptr) + { + available_bytes = rb->writeptr - rb->readptr; + if (available_bytes <= rqst_size) + { + /* We can read from the read pointer up to the write pointer */ + memcpy (buffer, rb->readptr, available_bytes); + rb->readptr = rb->writeptr; + rb->empty = SANE_TRUE; + return available_bytes; + } + else + { + /* We can read from the full request size */ + memcpy (buffer, rb->readptr, rqst_size); + rb->readptr = rb->readptr + rqst_size; + return rqst_size; + } + } + else + { + /* The read pointer is ahead of the write pointer. Its wrapped around. */ + /* We can read to the end of the buffer and make a recursive call to */ + /* read any available lines at the beginning of the buffer */ + available_bytes = rb->data + rb->size - rb->readptr; + if (available_bytes <= rqst_size) + { + /* We can read from the read pointer up to the end of the buffer */ + memcpy (buffer, rb->readptr, available_bytes); + rb->readptr = rb->data; + if (rb->writeptr == rb->readptr) + rb->empty = SANE_TRUE; + return available_bytes + + read_buffer_get_bytes (rb, buffer + available_bytes, + rqst_size - available_bytes); + } + else + { + /* We can read from the full request size */ + memcpy (buffer, rb->readptr, rqst_size); + rb->readptr = rb->readptr + rqst_size; + return rqst_size; + } + } +} + +SANE_Bool +read_buffer_is_empty (Read_Buffer * read_buffer) +{ + return read_buffer->empty; +} + +/* + * average a width*height rgb/monochrome area + * return values in given pointers + */ +static int +average_area (SANE_Byte * regs, SANE_Byte * data, int width, int height, + int *ra, int *ga, int *ba) +{ + int x, y; + int global = 0; + int rc, gc, bc; + + *ra = 0; + *ga = 0; + *ba = 0; + rc = 0; + gc = 0; + bc = 0; + if (rts88xx_is_color (regs)) + { + for (x = 0; x < width; x++) + for (y = 0; y < height; y++) + { + rc += data[3 * width * y + x]; + gc += data[3 * width * y + width + x]; + bc += data[3 * width * y + 2 * width + x]; + } + global = (rc + gc + bc) / (3 * width * height); + *ra = rc / (width * height); + *ga = gc / (width * height); + *ba = bc / (width * height); + } + else + { + for (x = 0; x < width; x++) + for (y = 0; y < height; y++) + { + gc += data[width * y + x]; + } + global = gc / (width * height); + *ga = gc / (width * height); + } + DBG (7, "average_area: global=%d, red=%d, green=%d, blue=%d\n", global, *ra, + *ga, *ba); + return global; +} + +/** + * we scan a dark area with gain minimum to detect offset + */ +SANE_Status +sanei_lexmark_low_offset_calibration (Lexmark_Device * dev) +{ + SANE_Byte regs[255]; /* we have our own copy of shadow registers */ + SANE_Status status = SANE_STATUS_GOOD; + int i, lines = 8, yoffset = 2; + int pixels; + int failed=0; + /* offsets */ + int ro = 0, go = 0, bo = 0; + /* averages */ + int ra, ga, ba, average, level; + SANE_Byte *data = NULL; + SANE_Byte top[OFFSET_RANGES] = { 0, 0x7f, 0x9f, 0xbf, 0xff }; +#ifdef DEEP_DEBUG + char title[20]; +#endif + + DBG (2, "sanei_lexmark_low_offset_calibration: start\n"); + /* copy registers */ + for (i = 0; i < 255; i++) + regs[i] = dev->shadow_regs[i]; + + /* we clear movement bit */ + regs[0xc3] = regs[0xc3] & 0x7f; + + pixels = + (dev->sensor->offset_endx - dev->sensor->offset_startx) / regs[0x7a]; + + /* there are 4 ranges of offset: + 00-7F : almost no offset + 80-9F : high noise + A0-BF : high noise + C0-FF : high noise + we start with the highest one and decrease until + overall offset is ok + First loop may have such an high offset that scanned data overflow + and gives a low average. So we allways skip its results + */ + + /* minimal gains */ + DBG (3, + "sanei_lexmark_low_offset_calibration: setting gains to (1,1,1).\n"); + rts88xx_set_gain (regs, 1, 1, 1); + + i = OFFSET_RANGES; + average = 255; + + /* loop on ranges until one fits. Then adjust offset, first loop is + * always done. TODO detect overflow by 'noise looking' data pattern */ + while (((i > 0) && (average > dev->sensor->offset_threshold)) + || (i == OFFSET_RANGES)) + { + /* next range */ + i--; + + /* sets to top of range */ + ro = top[i]; + go = top[i]; + bo = top[i]; + rts88xx_set_offset (regs, ro, ro, ro); + DBG (3, + "sanei_lexmark_low_offset_calibration: setting offsets to (%d,%d,%d).\n", + ro, ro, ro); + + status = + low_simple_scan (dev, regs, dev->sensor->offset_startx, pixels, + yoffset, lines, &data); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "sanei_lexmark_low_offset_calibration: low_simple_scan failed!\n"); + if (data != NULL) + free (data); + return status; + } +#ifdef DEEP_DEBUG + sprintf (title, "offset%02x.pnm", ro); + write_pnm_file(title,pixels,lines,rts88xx_is_color (regs),data); +#endif + average = average_area (regs, data, pixels, lines, &ra, &ga, &ba); + } + if (i == 0) + { + DBG (2, "sanei_lexmark_low_offset_calibration: failed !\n"); + failed=1; + } + + /* increase gain and scan again */ + /* increase gain for fine offset tuning */ + rts88xx_set_gain (regs, 6, 6, 6); + status = + low_simple_scan (dev, regs, dev->sensor->offset_startx, pixels, yoffset, + lines, &data); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "sanei_lexmark_low_offset_calibration: low_simple_scan failed!\n"); + if (data != NULL) + free (data); + return status; + } + average = average_area (regs, data, pixels, lines, &ra, &ga, &ba); +#ifdef DEEP_DEBUG + write_pnm_file("offset-final.pnm",pixels,lines,rts88xx_is_color (regs),data); +#endif + + /* this "law" is a guess, may (should?) be changed ... */ + if(!failed) + { + if (ro > ra) + dev->offset.red = ro - ra; + if (go > ga) + { + dev->offset.green = go - ga; + dev->offset.gray = go - ga; + } + if (bo > ba) + dev->offset.blue = bo - ba; + } + else + { + dev->offset.red=dev->sensor->offset_fallback; + dev->offset.green=dev->sensor->offset_fallback; + dev->offset.blue=dev->sensor->offset_fallback; + } + DBG (7, + "sanei_lexmark_low_offset_calibration: offset=(0x%02x,0x%02x,0x%02x).\n", + dev->offset.red, dev->offset.green, dev->offset.blue); + + DBG (2, "sanei_lexmark_low_offset_calibration: end.\n"); + free (data); + return status; +} + +/* + * we scan a white area until average is good enough + * level is good enough when it maximize the range value of output: + * ie max-min is maximum + */ +SANE_Status +sanei_lexmark_low_gain_calibration (Lexmark_Device * dev) +{ + SANE_Byte regs[255]; /* we have our own copy of shadow registers */ + SANE_Status status = SANE_STATUS_GOOD; + int i, lines = 4, yoffset = 1; + int sx, ex; + int pixels; + /* averages */ + int ra, ga, ba, average; + SANE_Byte *data = NULL; + int red, green, blue; +#ifdef DEEP_DEBUG + char title[20]; +#endif + + DBG (2, "sanei_lexmark_low_gain_calibration: start\n"); + /* copy registers */ + for (i = 0; i < 255; i++) + regs[i] = dev->shadow_regs[i]; + + /* we clear movement bit */ + regs[0xc3] = regs[0xc3] & 0x7f; + sx = regs[0x67] * 256 + regs[0x66]; + ex = regs[0x6d] * 256 + regs[0x6c]; + pixels = (ex - sx) / regs[0x7a]; + + /* set up inital gains */ + red = 6; + green = 6; + blue = 6; + rts88xx_set_gain (regs, red, green, blue); + + /* init loop */ + i = 0; + ra = 0; + ba = 0; + ga = 0; + + status = low_cancel (dev->devnum); + if (status != SANE_STATUS_GOOD) + return status; + + /* we do a simple scan all 3 averages give the choosen level */ + while (((rts88xx_is_color (regs) + && ((ra < dev->sensor->red_gain_target) + || (ga < dev->sensor->green_gain_target) + || (ba < dev->sensor->blue_gain_target))) + || (!rts88xx_is_color (regs) + && (ga < dev->sensor->gray_gain_target))) && (i < 25)) + { + status = + low_simple_scan (dev, regs, sx, pixels, yoffset, lines, &data); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "sanei_lexmark_low_gain_calibration: low_simple_scan failed!\n"); + if (data != NULL) + free (data); + return status; + } +#ifdef DEEP_DEBUG + sprintf (title, "gain%02d.pnm", i); + write_pnm_file(title,pixels,lines,rts88xx_is_color (regs),data); +#endif + average = average_area (regs, data, pixels, lines, &ra, &ga, &ba); + free (data); + if (ra < dev->sensor->red_gain_target) + red++; + if (ga < dev->sensor->green_gain_target + || (dev->sensor->gray_gain_target && !rts88xx_is_color (regs))) + green++; + if (ba < dev->sensor->blue_gain_target) + blue++; + rts88xx_set_gain (regs, red, green, blue); + i++; + } + dev->gain.red = red; + dev->gain.green = green; + dev->gain.blue = blue; + dev->gain.gray = green; + DBG (7, + "sanei_lexmark_low_gain_calibration: gain=(0x%02x,0x%02x,0x%02x).\n", + dev->gain.red, dev->gain.green, dev->gain.blue); + DBG (2, "sanei_lexmark_low_gain_calibration: end.\n"); + return status; +} + +/** + * there is no hardware shading correction. So we have to do it in software. + * We do it by scanning a pure white area which is before scanning area. Then + * we compute per pixel coefficient to move the scanned value to the target + * value. These coefficients are used later to correct scanned data. + * The scan is done with all the final scan settings but the heigth and vertical + * start position. + */ +SANE_Status +sanei_lexmark_low_shading_calibration (Lexmark_Device * dev) +{ + SANE_Byte regs[255]; /* we have our own copy of shadow registers */ + int i, j, pixels, bpl; + int sx, ex; + SANE_Byte *data = NULL; + SANE_Status status; + /* enough 75 dpi lines to "go off" home position dot, + and include shading area */ + int lines = 4 + 4; + int yoffset = 1; + int x, y; + float rtarget, btarget, gtarget; + + DBG (2, "sanei_lexmark_low_shading_calibration: start\n"); + /* copy registers */ + for (i = 0; i < 255; i++) + regs[i] = dev->shadow_regs[i]; + + /* allocate memory for scan */ + sx = regs[0x67] * 256 + regs[0x66]; + ex = regs[0x6d] * 256 + regs[0x6c]; + DBG (7, "startx=%d, endx=%d, coef=%d, r2f=0x%02x\n", + sx, ex, regs[0x7a], regs[0x2f]); + pixels = (ex - sx) / regs[0x7a]; + if (rts88xx_is_color (regs)) + bpl = 3 * pixels; + else + bpl = pixels; + + /* adjust the target area to the scanning resolution */ + lines = (8 * lines) / regs[0x7a]; + + data = (SANE_Byte *) malloc (bpl * lines); + DBG (7, "pixels=%d, lines=%d, size=%d\n", pixels, lines, bpl * lines); + if (data == NULL) + { + DBG (2, + "sanei_lexmark_low_shading_calibration: failed to allocate %d bytes !\n", + bpl * lines); + return SANE_STATUS_NO_MEM; + } + if (dev->shading_coeff != NULL) + free (dev->shading_coeff); + dev->shading_coeff = (float *) malloc (bpl * sizeof (float)); + if (dev->shading_coeff == NULL) + { + DBG (2, + "sanei_lexmark_low_shading_calibration: failed to allocate %d floats !\n", + bpl); + free (data); + return SANE_STATUS_NO_MEM; + } + + /* we set movement bit this time */ + regs[0xc3] = regs[0xc3] | 0x80; + + /* execute scan */ + status = low_simple_scan (dev, regs, sx, pixels, yoffset, lines, &data); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "sanei_lexmark_low_shading_calibration: low_simple_scan failed!\n"); + if (data != NULL) + free (data); + return status; + } + + yoffset = -1; + /* the very first lines of the scan may include the dark dot used + * locate park position. We find the first line free of it in the scan. + * We can't use is_home_line since it modifies data. + */ + for (y = 0; (y < lines) && (yoffset == y - 1); y++) + { + if (rts88xx_is_color (regs)) + { + for (x = 0; x < 3 * pixels; x++) + { + if (data[x + y * 3 * pixels] < 30) + yoffset = y; + } + } + else + { + for (x = 0; x < pixels; x++) + { + if (data[x + y * pixels] < 30) + yoffset = y; + } + } + } + /* make sure we are really out of the dot */ + yoffset++; + + /* yoffset is index of last dot line, go to first white line */ + if (yoffset >= lines - 1) + { + DBG (7, + "sanei_lexmark_low_shading_calibration: failed to detect yoffset.\n"); + /* fail safe fallback, picture will be altered at dot position, + but scanner is safe */ + yoffset = lines - 2; + } + else + yoffset++; + DBG (7, "sanei_lexmark_low_shading_calibration: yoffset=%d.\n", yoffset); + +#ifdef DEEP_DEBUG + write_pnm_file("shading.pnm",pixels,lines,rts88xx_is_color (regs),data); +#endif + + /* computes coefficients */ + /* there are 8 lines usable for shading calibration at 150 dpi, between + bottom of "home position" dot and the start of the scanner's window + assembly, we only use 7 of them */ + if (yoffset + (8 * 4) / regs[0x7a] < lines) + lines = yoffset + (8 * 4) / regs[0x7a]; + rtarget = dev->sensor->red_shading_target; + gtarget = dev->sensor->green_shading_target; + btarget = dev->sensor->blue_shading_target; + for (i = 0; i < pixels; i++) + { + /* we computes the coefficient needed to move the scanned value to + the target value */ + if (rts88xx_is_color (dev->shadow_regs)) + { + /* RED */ + dev->shading_coeff[i] = 0; + for (j = yoffset; j < lines; j++) + dev->shading_coeff[i] += data[i + j * bpl]; + dev->shading_coeff[i] = + (rtarget / (dev->shading_coeff[i] / (lines - yoffset))); + + /* GREEN */ + dev->shading_coeff[i + pixels] = 0; + for (j = yoffset; j < lines; j++) + dev->shading_coeff[i + pixels] += data[i + j * bpl + pixels]; + dev->shading_coeff[i + pixels] = + ((gtarget / dev->shading_coeff[i + pixels]) * (lines - yoffset)); + + /* BLUE */ + dev->shading_coeff[i + 2 * pixels] = 0; + for (j = yoffset; j < lines; j++) + dev->shading_coeff[i + 2 * pixels] += + data[i + j * bpl + 2 * pixels]; + dev->shading_coeff[i + 2 * pixels] = + ((btarget / dev->shading_coeff[i + 2 * pixels]) * + (lines - yoffset)); + } + else + { + dev->shading_coeff[i] = 0; + for (j = yoffset; j < lines; j++) + { + dev->shading_coeff[i] += data[i + j * bpl]; + } + dev->shading_coeff[i] = + (rtarget / dev->shading_coeff[i]) * (lines - yoffset); + } + } + + /* do the scan backward to go back to start position */ + regs[0xc6] &= 0xF7; + lines = (8 * 8) / regs[0x7a]; + + /* execute scan */ + status = low_simple_scan (dev, regs, sx, pixels, 1, lines, &data); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "sanei_lexmark_low_shading_calibration: low_simple_scan failed!\n"); + return status; + } + +#ifdef DEEP_DEBUG + write_pnm_file("shading_bwd.pnm",pixels,lines,rts88xx_is_color (regs),data); +#endif + free (data); + + DBG (2, "sanei_lexmark_low_shading_calibration: end.\n"); + return status; +} + + +SANE_Status +sanei_lexmark_low_calibration (Lexmark_Device * dev) +{ + SANE_Status status; + + status = sanei_lexmark_low_offset_calibration (dev); + if (status != SANE_STATUS_GOOD) + return status; + + /* we put the offset just computed in scanning regs */ + if (rts88xx_is_color (dev->shadow_regs)) + { + rts88xx_set_offset (dev->shadow_regs, + dev->offset.red, + dev->offset.green, dev->offset.blue); + } + else + { + rts88xx_set_offset (dev->shadow_regs, + dev->offset.gray, + dev->offset.gray, dev->offset.gray); + } + + /* if manual gain settings, no gain calibration */ + if (dev->val[OPT_MANUAL_GAIN].w == SANE_TRUE) + { + if (rts88xx_is_color (dev->shadow_regs)) + { + dev->gain.red = dev->val[OPT_RED_GAIN].w; + dev->gain.green = dev->val[OPT_GREEN_GAIN].w; + dev->gain.blue = dev->val[OPT_BLUE_GAIN].w; + } + else + dev->gain.gray = dev->val[OPT_GRAY_GAIN].w; + } + else + { + status = sanei_lexmark_low_gain_calibration (dev); + if (status != SANE_STATUS_GOOD) + return status; + } + + /* put the calibrated or manual settings before shading calibration + which must be done with final setting values */ + if (rts88xx_is_color (dev->shadow_regs)) + { + rts88xx_set_gain (dev->shadow_regs, dev->gain.red, dev->gain.green, + dev->gain.blue); + } + else + { + rts88xx_set_gain (dev->shadow_regs, dev->gain.gray, dev->gain.gray, + dev->gain.gray); + } + + status = sanei_lexmark_low_shading_calibration (dev); + if (status != SANE_STATUS_GOOD) + return status; + + DBG (2, "sanei_lexmark_low_calibration: end.\n"); + return SANE_STATUS_GOOD; +} + +/* assign sensor data */ +static SANE_Status +sanei_lexmark_low_assign_sensor (Lexmark_Device * dev) +{ + int dn; + + /* init sensor data */ + dn = 0; + while (sensor_list[dn].id != 0 + && sensor_list[dn].id != dev->model.sensor_type) + dn++; + if (sensor_list[dn].id == 0) + { + DBG (1, + "sanei_lexmark_low_assign_sensor: unknown sensor %d\n", + dev->model.sensor_type); + return SANE_STATUS_UNSUPPORTED; + } + dev->sensor = &(sensor_list[dn]); + DBG (1, "sanei_lexmark_low_assign_sensor: assigned sensor number %d\n", + dev->model.sensor_type); + return SANE_STATUS_GOOD; +} + +/* assign model description, based on USB id, and register B0 when + * available */ +SANE_Status +sanei_lexmark_low_assign_model (Lexmark_Device * dev, char *devname, + SANE_Int vendor, SANE_Int product, + SANE_Byte mainboard) +{ + int dn; + SANE_Bool found = SANE_FALSE; + + DBG (2, "sanei_lexmark_low_assign_model: start\n"); + DBG (3, + "sanei_lexmark_low_assign_model: assigning %04x:%04x, variant %d\n", + vendor, product, mainboard); + + dn = 0; + /* walk the list of known devices */ + while (!found && model_list[dn].vendor_id != 0) + { + /* no mainboard id given (at attach time) */ + if (mainboard == 0 + && vendor == model_list[dn].vendor_id + && product == model_list[dn].product_id) + found = SANE_TRUE; + /* mainboard given (init time) */ + if (mainboard != 0 + && mainboard == model_list[dn].mainboard_id + && vendor == model_list[dn].vendor_id + && product == model_list[dn].product_id) + found = SANE_TRUE; + + if (!found) + dn++; + } + + /* we hit the end of list, so we don't know about the current model */ + if (!found) + { + DBG (1, + "sanei_lexmark_low_assign_model: unknown device 0x%04x:0x%04x\n", + vendor, product); + return SANE_STATUS_UNSUPPORTED; + } + + dev->sane.name = strdup (devname); + dev->sane.vendor = model_list[dn].vendor; + dev->sane.model = model_list[dn].model; + dev->model = model_list[dn]; + dev->sane.type = "flatbed scanner"; + + DBG (3, "sanei_lexmark_low_assign_model: assigned %s\n", + dev->model.model); + + /* init sensor data */ + return sanei_lexmark_low_assign_sensor (dev); + DBG (2, "sanei_lexmark_low_assign_model: end.\n"); +} diff --git a/backend/lexmark_models.c b/backend/lexmark_models.c new file mode 100644 index 000000000..fec377607 --- /dev/null +++ b/backend/lexmark_models.c @@ -0,0 +1,93 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2006-2007 Stéphane Voltz + + 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. +*/ + +static Lexmark_Model model_list[] = { + { + 0x043d, /* vendor id */ + 0x007c, /* product id */ + 0xb2, /* submodel id */ + "Lexmark X1100", /* name */ + "Lexmark", /* vendor */ + "X1100/rev. B2", /* model */ + X1100_MOTOR, /* X1100 series has 2 sensors */ + X1100_B2_SENSOR}, + { + 0x043d, /* vendor id */ + 0x007c, /* product id */ + 0x2c, /* submodel id */ + "Lexmark X1100", /* name */ + "Lexmark", /* vendor */ + "X1100/rev. 2C", /* model */ + A920_MOTOR, /* X1100 series has 2 sensors, 2C or B2. It + is detected at sane_open() */ + X1100_2C_SENSOR}, + { + 0x413c, /* vendor id */ + 0x5105, /* product id */ + 0x2c, /* submodel id */ + "Dell A920", /* name */ + "Dell", /* vendor */ + "A920", /* model */ + A920_MOTOR, + A920_SENSOR}, + { + 0x043d, /* vendor id */ + 0x007d, /* product id */ + 0x87, /* submodel id */ + "Lexmark X1200", /* name */ + "Lexmark", /* vendor */ + "X1200/USB1.1", /* model */ + A920_MOTOR, + X1200_SENSOR}, + { + 0x043d, /* vendor id */ + 0x007d, /* product id */ + 0x97, /* submodel id */ + "Lexmark X1200", /* name */ + "Lexmark", /* vendor */ + "X1200/USB2.0", /* model */ + A920_MOTOR, + X1200_USB2_SENSOR}, + { /* termination model, must be last */ + 0, 0, 0, NULL, NULL, NULL, 0, 0} +}; /* end models description */ diff --git a/backend/lexmark_sensors.c b/backend/lexmark_sensors.c new file mode 100644 index 000000000..c661dd0eb --- /dev/null +++ b/backend/lexmark_sensors.c @@ -0,0 +1,122 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2006-2007 Stéphane Voltz + + 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. +*/ + +static Lexmark_Sensor sensor_list[] = { + { + X1100_B2_SENSOR, + /* start x, end x and target average for offset calibration */ + 48,80,6, + /* usable pixel sensor startx */ + 106, + /* default gain */ + 16, + /* gain calibration targets */ + 180, 180, 180, 180, + /* shading correction targets */ + 260, 260, 260, 260, + /* offset and gain fallback */ + 0x70, 17 + }, + { + X1100_2C_SENSOR, + /* start x, end x and target average for offset calibration */ + 48,80,12, + /* usable pixel sensor startx */ + 106, + /* default gain */ + 10, + /* gain calibration */ + 140, 150, 150, 150, + /* shading correction */ + 260, 260, 260, 260, + /* offset and gain fallback */ + 0x70, 11 + }, + { /* USB 1.1 settings */ + X1200_SENSOR, + /* start x, end x and target average for offset calibration */ + 32,64,15, + /* usable pixel sensor startx */ + 136, + /* default gain */ + 16, + /* gain calibration */ + 180, 180, 180, 180, + /* shading correction */ + 260, 260, 260, 260, + /* offset and gain fallback */ + 0x86, 16 + }, + { /* this one is a 1200 on USB2.0 */ + X1200_USB2_SENSOR, + /* start x, end x and target average for offset calibration */ + 32,64,12, + /* usable pixel sensor startx */ + 136, + /* default gain */ + 16, + /* gain calibration */ + 180, 180, 180, 180, + /* shading correction */ + 260, 260, 260, 260, + /* offset and gain fallback */ + 0x86, 16 + }, + { + A920_SENSOR, + /* start x, end x and target average for offset calibration */ + 48,80,6, + /* usable pixel sensor startx */ + 106, + /* default gain */ + 12, + /* gain calibration target */ + 130, 145, 150, 145, + /* gain calibration target */ + 260, 260, 260, 260, + /* offset and gain fallback */ + 0x70, 13 + }, + /* termination list sensor, must be last */ + {0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; diff --git a/doc/descriptions/lexmark.desc b/doc/descriptions/lexmark.desc index 10f94c900..328e56960 100644 --- a/doc/descriptions/lexmark.desc +++ b/doc/descriptions/lexmark.desc @@ -31,11 +31,10 @@ :status :untested :model "X1130" -:url "/unsupported/lexmark-x1150.html" :interface "USB" :usbid "0x043d" "0x007c" -:status :basic -:comment "The images scanned have a lot of vertical lines" +:status :good +:comment "Supports 75, 150, 300, 600 dpi" :model "X1140" :interface "USB" @@ -46,25 +45,35 @@ :url "/unsupported/lexmark-x1150.html" :interface "USB" :usbid "0x043d" "0x007c" -:status :minimal -:comment "Colors don't seem to be ok. Scanned white pages appear purple." +:status :good +:comment "Supports 75, 150, 300, 600 dpi" :model "X1170" :interface "USB" :usbid "0x043d" "0x007c" -:status :basic -:comment "Colors aren't so bright. Bed-wide pictures are unscannable because the scan head never reaches the end of the bed (neither with letter selected). It leaves almost 2 cm out." +:status :good +:comment "Supports 75, 150, 300, 600 dpi" :model "X1180" -:url "/unsupported/lexmark-x1150.html" :interface "USB" :usbid "0x043d" "0x007c" -:status :basic +:status :good :model "X1185" :interface "USB" :usbid "0x043d" "0x007c" -:status :basic +:status :good :comment "Tested with xscanimage. Supports 75, 150, 300, 600, 1200(600x1200) dpi resolutions. Does grayscale or colour scans in the following sizes: wallet, 3x5, 4x6, 5x7, 8x10, letter." +:model "X12xx" +:interface "USB" +:usbid "0x043d" "0x007d" +:status :good +:comment "USB1.1 is OK, USB2.0 needs testing" +:mfg "Dell" ; name a manufacturer +:model "A920" +:interface "USB" +:usbid "0x413c" "0x5105" +:status :good +:comment "Relabelled X11xx model" diff --git a/doc/sane-lexmark.man b/doc/sane-lexmark.man index eab04294a..b383713dd 100644 --- a/doc/sane-lexmark.man +++ b/doc/sane-lexmark.man @@ -1,30 +1,33 @@ -.TH sane-lexmark 5 "02 September 2005" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" -.IX sane-lexmark -.SH NAME -sane-lexmark \- SANE backend for Lexmark X1100 Series scanners -.SH DESCRIPTION +.\" .IX sane-lexmark +.TH "sane-lexmark" "5" "16 April 2007" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.SH "NAME" +sane\-lexmark \- SANE backend for Lexmark X1100/X1200 Series scanners +.SH "DESCRIPTION" The -.B sane-lexmark +.B sane\-lexmark library implements a SANE (Scanner Access Now Easy) backend that -provides access to the scanner part of Lexmark X1100 AIOs. This backend +provides access to the scanner part of Lexmark X1100/X1200 AIOs. This backend should be considered -.B beta-quality +.B beta\-quality software! -.PP +.PP The scanners that should work with this backend are: -.PP +.PP .RS .ft CR -.nf +.nf Vendor Model status ----------------------- ----------- +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- Lexmark X1110 untested Lexmark X1140 untested - Lexmark X1150 untested - Lexmark X1170 untested - Lexmark X1180 basic - Lexmark X1185 basic -.fi + Lexmark X1150 good + Lexmark X1170 good + Lexmark X1180 good + Lexmark X1185 complete + Lexmark X12xx good in USB1.1, + not fully tested in USB2.0 + Dell A920 good +.fi .ft R .RE @@ -32,22 +35,22 @@ The options the backend supports can either be selected through command line options to programs like scanimage or through GUI elements in xscanimage or xsane. -.br +.br If you have any strange behavior, please report to the backend maintainer or to the SANE mailing list. Valid command line options and their syntax can be listed by using .RS -scanimage --help -d lexmark:usb: +scanimage \-\-help \-d lexmark:usb: .RE -.TP +.TP .B Scan Mode Options -.TP -.B --mode +.TP +.B \-\-mode selects the basic mode of operation of the scanner valid choices are -.IR Color , +.I R Color , .I Gray and .I Lineart @@ -55,96 +58,91 @@ The default mode is Color. The Lineart mode is black and white only (1 bit). Grayscale will produce 256 levels of gray (8 bits). Color mode allows for over 16 million different colors produced from 24 bits of color information. -.TP -.B --resolution +.TP +.B \-\-resolution selects the resolution for a scan. The horizontal and vertical resolutions are set by the value of this option. The scanner is capable of the following resolutions for the specified option value: -.PP +.PP .RS .ft CR -.nf +.nf Value Hor. Resolution Vert. Resolution - ----- --------------- ------------------- + \-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 75 75dpi 75dpi 150 150dpi 150dpi 300 300dpi 300dpi 600 600dpi 600dpi - 1200 600dpi 1200dpi -.fi + 1200 600dpi 1200dpi (only for X11xx models with 'B2' sensor) +.fi .ft R .RE .TP -.B --preview +.B \-\-preview requests a preview scan. The resolution used for that scan is 75 dpi and the scan area and the scan mode are as specified through their options, or the default if not specified. The default value for preview mode is "no". -.TP -.B --paper-size -selects the size of the area to be scanned. Valid sizes are -.IR Wallet , -.IR 3x5 , -.IR 4x6 , -.IR 5x7 , -.IR 8x10 , -.IR Letter , -the default size is 3x5. - .TP -.B --threshold -selects the minimum-brightness to get a white point. The threshold is only used with Lineart mode scans. +.B \-\-threshold +selects the minimum\-brightness to get a white point. The threshold is only used with Lineart mode scans. It is specified as a percentage in the range 0..100% (in steps of 1). The default value of the threshold option is 50. -.SH CONFIGURATION FILE +.SH "CONFIGURATION FILE" The configuration file @CONFIGDIR@/lexmark.conf contains only the usb device id (eg usb 0x043d 0x007c). -.SH FILES -.TP -.I @LIBDIR@/libsane-lexmark.a +.SH "FILES" +.TP +.I @LIBDIR@/libsane\-lexmark.a The static library implementing this backend. -.TP -.I @LIBDIR@/libsane-lexmark.so +.TP +.I @LIBDIR@/libsane\-lexmark.so The shared library implementing this backend (present on systems that support dynamic loading). -.SH ENVIRONMENT -.TP +.SH "ENVIRONMENT" +.TP .B SANE_DEBUG_LEXMARK +.B SANE_DEBUG_LEXMARK_LOW If the library was compiled with debug support enabled, this environment variable controls the debug level for this backend. E.g., -a value of 128 requests all debug output to be printed. Smaller levels +a value of 255 requests all debug output to be printed. Smaller levels reduce verbosity. -.SH LIMITATIONS +.SH "LIMITATIONS" The windows TWAIN driver has many more options than this SANE backend. However they are only software adjustments. This backend only -implements what the scanner can support. - - -.SH BUGS +implements what the scanner can support. For instance, shading correction +(vertical stripes due to sensor variation across its width) is done in +software. Head park position is also detected by software. +The data compression isn't supported for the X1200 serie on USB 1.1, +leading to slow scans. +.SH "BUGS" .br -Jerky movement on 600dpi gray 8x10 scan. -.br -Color calibration not implemented. -.br -Dark compensation not implemented. +No bugs currently known. .SH "SEE ALSO" - -sane-scsi(5), scanimage(1), xscanimage(1), xsane(1), sane(7) +sane\-scsi(5), scanimage(1), xscanimage(1), xsane(1), sane(7) -.SH AUTHOR - -.TP -The package is actively maintained by Fred Odendaal. +.SH "AUTHOR" +.TP +The backend was originaly written by Fred Odendaal. .I http://ca.geocities.com/freshshelf@rogers.com/ +.TP +The new version is currently developped by StÃphane Voltz. +.I http://stef.dev.free.fr/sane/lexmark +.SH "CREDITS" +.TP +Many thanks go to: +Julien Furgerot who lend me a Dell A920. +Robert Price, Dani Ele and Dalai Felinto for the time they spent recording +USB activity and testing the experimental version.