diff options
Diffstat (limited to 'backend/hp5590.c')
| -rw-r--r-- | backend/hp5590.c | 2150 | 
1 files changed, 1670 insertions, 480 deletions
diff --git a/backend/hp5590.c b/backend/hp5590.c index fabf40a..b206406 100644 --- a/backend/hp5590.c +++ b/backend/hp5590.c @@ -1,6 +1,8 @@  /* sane - Scanner Access Now Easy.     Copyright (C) 2007 Ilia Sotnikov <hostcc@gmail.com>     HP ScanJet 4570c support by Markham Thomas +   ADF page detection and high DPI fixes by Bernard Badeer +   scanbd integration by Damiano Scaramuzza and Bernard Badeer     This file is part of the SANE package.     This program is free software; you can redistribute it and/or @@ -59,47 +61,161 @@  #include "../include/sane/saneopts.h"  #include "hp5590_cmds.c"  #include "hp5590_low.c" +#include "../include/sane/sanei_net.h"  /* Debug levels */ -#define	DBG_err		0 -#define	DBG_proc	10 -#define	DBG_verbose	20 +#define DBG_err         0 +#define DBG_proc        10 +#define DBG_verbose     20 +#define DBG_details     30  #define hp5590_assert(exp) if(!(exp)) { \ -	DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ -	return SANE_STATUS_INVAL; \ +        DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ +        return SANE_STATUS_INVAL; \  }  #define hp5590_assert_void_return(exp) if(!(exp)) { \ -	DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ -	return; \ +        DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ +        return; \  } +#define MY_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MY_MAX(a, b) (((a) > (b)) ? (a) : (b)) +  /* #define HAS_WORKING_COLOR_48 */ -#define BUILD 		7 -#define USB_TIMEOUT	30 * 1000 +#define BUILD           8 +#define USB_TIMEOUT     30 * 1000  static SANE_Word  res_list[] = { 6, 100, 200, 300, 600, 1200, 2400 }; -#define SANE_VALUE_SCAN_SOURCE_FLATBED  	SANE_I18N("Flatbed") -#define SANE_VALUE_SCAN_SOURCE_ADF 		SANE_I18N("ADF") -#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX 	SANE_I18N("ADF Duplex") -#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES 	SANE_I18N("TMA Slides") -#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES 	SANE_I18N("TMA Negatives") +#define SANE_VALUE_SCAN_SOURCE_FLATBED          SANE_I18N("Flatbed") +#define SANE_VALUE_SCAN_SOURCE_ADF              SANE_I18N("ADF") +#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX       SANE_I18N("ADF Duplex") +#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES       SANE_I18N("TMA Slides") +#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES    SANE_I18N("TMA Negatives") +static SANE_String_Const +sources_list[] = { +  SANE_VALUE_SCAN_SOURCE_FLATBED, +  SANE_VALUE_SCAN_SOURCE_ADF, +  SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, +  SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, +  SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, +  NULL +}; + +#define SANE_VALUE_SCAN_MODE_COLOR_24           SANE_VALUE_SCAN_MODE_COLOR +#define SANE_VALUE_SCAN_MODE_COLOR_48           SANE_I18N("Color (48 bits)") +#define HAS_WORKING_COLOR_48 1 + +#define SANE_NAME_LAMP_TIMEOUT                  "extend-lamp-timeout" +#define SANE_TITLE_LAMP_TIMEOUT                 SANE_I18N("Extend lamp timeout") +#define SANE_DESC_LAMP_TIMEOUT                  SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)") +#define SANE_NAME_WAIT_FOR_BUTTON               "wait-for-button" +#define SANE_TITLE_WAIT_FOR_BUTTON              SANE_I18N("Wait for button") +#define SANE_DESC_WAIT_FOR_BUTTON               SANE_I18N("Waits for button before scanning") +#define SANE_NAME_BUTTON_PRESSED                "button-pressed" +#define SANE_TITLE_BUTTON_PRESSED               SANE_I18N("Last button pressed") +#define SANE_DESC_BUTTON_PRESSED                SANE_I18N("Get ID of last button pressed (read only)") +#define SANE_NAME_LCD_COUNTER                   "counter-value" +#define SANE_TITLE_LCD_COUNTER                  SANE_I18N("LCD counter") +#define SANE_DESC_LCD_COUNTER                   SANE_I18N("Get value of LCD counter (read only)") +#define SANE_NAME_COLOR_LED                     "color-led" +#define SANE_TITLE_COLOR_LED                    SANE_I18N("Color LED indicator") +#define SANE_DESC_COLOR_LED                     SANE_I18N("Get value of LED indicator (read only)") +#define SANE_NAME_DOC_IN_ADF                    "doc-in-adf" +#define SANE_TITLE_DOC_IN_ADF                   SANE_I18N("Document available in ADF") +#define SANE_DESC_DOC_IN_ADF                    SANE_I18N("Get state of document-available indicator in ADF (read only)") +#define SANE_NAME_OVERWRITE_EOP_PIXEL           "hide-eop-pixel" +#define SANE_TITLE_OVERWRITE_EOP_PIXEL          SANE_I18N("Hide end-of-page pixel") +#define SANE_DESC_OVERWRITE_EOP_PIXEL           SANE_I18N("Hide end-of-page indicator pixels and overwrite with neighbor pixels") +#define SANE_NAME_TRAILING_LINES_MODE           "trailing-lines-mode" +#define SANE_TITLE_TRAILING_LINES_MODE          SANE_I18N("Filling mode of trailing lines after scan data (ADF)") +#define SANE_DESC_TRAILING_LINES_MODE           SANE_I18N("raw = raw scan data, last = repeat last scan line, raster = b/w raster, "\ +                                                          "white = white color, black = black color, color = RGB or gray color value") +#define SANE_NAME_TRAILING_LINES_COLOR          "trailing-lines-color" +#define SANE_TITLE_TRAILING_LINES_COLOR         SANE_I18N("RGB or gray color value for filling mode 'color'") +#define SANE_DESC_TRAILING_LINES_COLOR          SANE_I18N("Color value for trailing lines filling mode 'color'. "\ +                                                          "RGB color as r*65536+256*g+b or gray value (default=violet or gray)") + +#define BUTTON_PRESSED_VALUE_COUNT 11 +#define BUTTON_PRESSED_VALUE_NONE_KEY "none" +#define BUTTON_PRESSED_VALUE_POWER_KEY "power" +#define BUTTON_PRESSED_VALUE_SCAN_KEY "scan" +#define BUTTON_PRESSED_VALUE_COLLECT_KEY "collect" +#define BUTTON_PRESSED_VALUE_FILE_KEY "file" +#define BUTTON_PRESSED_VALUE_EMAIL_KEY "email" +#define BUTTON_PRESSED_VALUE_COPY_KEY "copy" +#define BUTTON_PRESSED_VALUE_UP_KEY "up" +#define BUTTON_PRESSED_VALUE_DOWN_KEY "down" +#define BUTTON_PRESSED_VALUE_MODE_KEY "mode" +#define BUTTON_PRESSED_VALUE_CANCEL_KEY "cancel" +#define BUTTON_PRESSED_VALUE_MAX_KEY_LEN 32 +static SANE_String_Const +buttonstate_list[] = { +  BUTTON_PRESSED_VALUE_NONE_KEY, +  BUTTON_PRESSED_VALUE_POWER_KEY, +  BUTTON_PRESSED_VALUE_SCAN_KEY, +  BUTTON_PRESSED_VALUE_COLLECT_KEY, +  BUTTON_PRESSED_VALUE_FILE_KEY, +  BUTTON_PRESSED_VALUE_EMAIL_KEY, +  BUTTON_PRESSED_VALUE_COPY_KEY, +  BUTTON_PRESSED_VALUE_UP_KEY, +  BUTTON_PRESSED_VALUE_DOWN_KEY, +  BUTTON_PRESSED_VALUE_MODE_KEY, +  BUTTON_PRESSED_VALUE_CANCEL_KEY, +  NULL +}; + +#define COLOR_LED_VALUE_COUNT 2 +#define COLOR_LED_VALUE_COLOR_KEY "color" +#define COLOR_LED_VALUE_BLACKWHITE_KEY "black_white" +#define COLOR_LED_VALUE_MAX_KEY_LEN 32 +static SANE_String_Const +colorledstate_list[] = { +  COLOR_LED_VALUE_COLOR_KEY, +  COLOR_LED_VALUE_BLACKWHITE_KEY, +  NULL +}; -#define SANE_VALUE_SCAN_MODE_COLOR_24 		SANE_VALUE_SCAN_MODE_COLOR -#define SANE_VALUE_SCAN_MODE_COLOR_48 		SANE_I18N("Color (48 bits)") +#define LCD_COUNTER_VALUE_MIN 1 +#define LCD_COUNTER_VALUE_MAX 99 +#define LCD_COUNTER_VALUE_QUANT 1 +static SANE_Range +lcd_counter_range = { +  LCD_COUNTER_VALUE_MIN, +  LCD_COUNTER_VALUE_MAX, +  LCD_COUNTER_VALUE_QUANT +}; -#define SANE_NAME_LAMP_TIMEOUT 			"extend-lamp-timeout" -#define SANE_TITLE_LAMP_TIMEOUT 		SANE_I18N("Extend lamp timeout") -#define SANE_DESC_LAMP_TIMEOUT 			SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)") -#define SANE_NAME_WAIT_FOR_BUTTON 		"wait-for-button" -#define SANE_TITLE_WAIT_FOR_BUTTON 		SANE_I18N("Wait for button") -#define SANE_DESC_WAIT_FOR_BUTTON 		SANE_I18N("Waits for button before scanning") +#define TRAILING_LINES_MODE_RAW 0 +#define TRAILING_LINES_MODE_LAST 1 +#define TRAILING_LINES_MODE_RASTER 2 +#define TRAILING_LINES_MODE_WHITE 3 +#define TRAILING_LINES_MODE_BLACK 4 +#define TRAILING_LINES_MODE_COLOR 5 +#define TRAILING_LINES_MODE_VALUE_COUNT 6 + +#define TRAILING_LINES_MODE_RAW_KEY "raw" +#define TRAILING_LINES_MODE_LAST_KEY "last" +#define TRAILING_LINES_MODE_RASTER_KEY "raster" +#define TRAILING_LINES_MODE_WHITE_KEY "white" +#define TRAILING_LINES_MODE_BLACK_KEY "black" +#define TRAILING_LINES_MODE_COLOR_KEY "color" +#define TRAILING_LINES_MODE_MAX_KEY_LEN 24 +static SANE_String_Const +trailingmode_list[] = { +  TRAILING_LINES_MODE_RAW_KEY, +  TRAILING_LINES_MODE_LAST_KEY, +  TRAILING_LINES_MODE_RASTER_KEY, +  TRAILING_LINES_MODE_WHITE_KEY, +  TRAILING_LINES_MODE_BLACK_KEY, +  TRAILING_LINES_MODE_COLOR_KEY, +  NULL +}; -#define MAX_SCAN_SOURCE_VALUE_LEN 	24 -#define MAX_SCAN_MODE_VALUE_LEN		24 +#define MAX_SCAN_SOURCE_VALUE_LEN       24 +#define MAX_SCAN_MODE_VALUE_LEN         24  static SANE_Range  range_x, range_y, range_qual; @@ -126,29 +242,51 @@ enum hp5590_opt_idx {    HP5590_OPT_RESOLUTION,    HP5590_OPT_LAMP_TIMEOUT,    HP5590_OPT_WAIT_FOR_BUTTON, +  HP5590_OPT_BUTTON_PRESSED, +  HP5590_OPT_COLOR_LED, +  HP5590_OPT_LCD_COUNTER, +  HP5590_OPT_DOC_IN_ADF,    HP5590_OPT_PREVIEW, +  HP5590_OPT_OVERWRITE_EOP_PIXEL, +  HP5590_OPT_TRAILING_LINES_MODE, +  HP5590_OPT_TRAILING_LINES_COLOR,    HP5590_OPT_LAST  };  struct hp5590_scanner { -  struct scanner_info 		*info; -  enum proto_flags		proto_flags; -  SANE_Device 			sane; -  SANE_Int 			dn; -  float 			br_x, br_y, tl_x, tl_y; -  unsigned int 			dpi; -  enum color_depths 		depth; -  enum scan_sources	 	source; -  SANE_Bool 			extend_lamp_timeout; -  SANE_Bool 			wait_for_button; -  SANE_Bool 			preview; -  unsigned int 			quality; -  SANE_Option_Descriptor 	*opts; -  struct hp5590_scanner 	*next; -  unsigned int 			image_size; -  SANE_Int 			transferred_image_size; -  void			 	*bulk_read_state; -  SANE_Bool 			scanning; +  struct scanner_info           *info; +  enum proto_flags              proto_flags; +  SANE_Device                   sane; +  SANE_Int                      dn; +  float                         br_x, br_y, tl_x, tl_y; +  unsigned int                  dpi; +  enum color_depths             depth; +  enum scan_sources             source; +  SANE_Bool                     extend_lamp_timeout; +  SANE_Bool                     wait_for_button; +  SANE_Bool                     preview; +  unsigned int                  quality; +  SANE_Option_Descriptor        *opts; +  struct hp5590_scanner         *next; +  unsigned long long            image_size; +  unsigned long long            transferred_image_size; +  void                          *bulk_read_state; +  SANE_Bool                     scanning; +  SANE_Bool                     overwrite_eop_pixel; +  SANE_Byte                     *eop_last_line_data; +  unsigned int                  eop_last_line_data_rpos; +  SANE_Int                      eop_trailing_lines_mode; +  SANE_Int                      eop_trailing_lines_color; +  SANE_Byte                     *adf_next_page_lines_data; +  unsigned int                  adf_next_page_lines_data_size; +  unsigned int                  adf_next_page_lines_data_rpos; +  unsigned int                  adf_next_page_lines_data_wpos; +  SANE_Byte                     *one_line_read_buffer; +  unsigned int                  one_line_read_buffer_rpos; +  SANE_Byte                     *color_shift_line_buffer1; +  unsigned int                  color_shift_buffered_lines1; +  SANE_Byte                     *color_shift_line_buffer2; +  unsigned int                  color_shift_buffered_lines2;  };  static @@ -157,19 +295,19 @@ struct hp5590_scanner *scanners_list;  /******************************************************************************/  static SANE_Status  calc_image_params (struct hp5590_scanner *scanner, -		   unsigned int *pixel_bits, -		   unsigned int *pixels_per_line, -		   unsigned int *bytes_per_line, -		   unsigned int *lines, -		   unsigned int *image_size) +                   unsigned int *pixel_bits, +                   unsigned int *pixels_per_line, +                   unsigned int *bytes_per_line, +                   unsigned int *lines, +                   unsigned long long *image_size)  { -  unsigned int 	_pixel_bits; -  SANE_Status	ret; -  unsigned int	_pixels_per_line; -  unsigned int	_bytes_per_line; -  unsigned int	_lines; -  unsigned int	_image_size; -  float		var; +  unsigned int  _pixel_bits; +  SANE_Status   ret; +  unsigned int  _pixels_per_line; +  unsigned int  _bytes_per_line; +  unsigned int  _lines; +  unsigned int  _image_size; +  float         var;    DBG (DBG_proc, "%s\n", __func__); @@ -195,7 +333,7 @@ calc_image_params (struct hp5590_scanner *scanner,    if (var > _bytes_per_line)      _bytes_per_line++; -  _image_size 	   = _lines * _bytes_per_line; +  _image_size      = (unsigned long long) _lines * _bytes_per_line;    DBG (DBG_verbose, "%s: pixel_bits: %u, pixels_per_line: %u, "         "bytes_per_line: %u, lines: %u, image_size: %u\n", @@ -219,18 +357,18 @@ calc_image_params (struct hp5590_scanner *scanner,    return SANE_STATUS_GOOD;  } -     +  /******************************************************************************/  static SANE_Status  attach_usb_device (SANE_String_Const devname, -		   enum hp_scanner_types hp_scanner_type) +                   enum hp_scanner_types hp_scanner_type)  { -  struct scanner_info		*info; -  struct hp5590_scanner		*scanner, *ptr; -  unsigned int 			max_count, count; -  SANE_Int 			dn; -  SANE_Status			ret; -  const struct hp5590_model	*hp5590_model; +  struct scanner_info           *info; +  struct hp5590_scanner         *scanner, *ptr; +  unsigned int                  max_count, count; +  SANE_Int                      dn; +  SANE_Status                   ret; +  const struct hp5590_model     *hp5590_model;    DBG (DBG_proc, "%s: Opening USB device\n", __func__);    if (sanei_usb_open (devname, &dn) != SANE_STATUS_GOOD) @@ -242,7 +380,7 @@ attach_usb_device (SANE_String_Const devname,      return ret;    if (hp5590_init_scanner (dn, hp5590_model->proto_flags, -    			   &info, hp_scanner_type) != 0) +                           &info, hp_scanner_type) != 0)      return SANE_STATUS_IO_ERROR;    DBG (1, "%s: found HP%s scanner at '%s'\n", @@ -250,13 +388,13 @@ attach_usb_device (SANE_String_Const devname,    DBG (DBG_verbose, "%s: Reading max scan count\n", __func__);    if (hp5590_read_max_scan_count (dn, hp5590_model->proto_flags, -    				  &max_count) != 0) +                                  &max_count) != 0)      return SANE_STATUS_IO_ERROR;    DBG (DBG_verbose, "%s: Max Scanning count %u\n", __func__, max_count);    DBG (DBG_verbose, "%s: Reading scan count\n", __func__);    if (hp5590_read_scan_count (dn, hp5590_model->proto_flags, -    			      &count) != 0) +                              &count) != 0)      return SANE_STATUS_IO_ERROR;    DBG (DBG_verbose, "%s: Scanning count %u\n", __func__, count); @@ -282,6 +420,18 @@ attach_usb_device (SANE_String_Const devname,    scanner->info = info;    scanner->bulk_read_state = NULL;    scanner->opts = NULL; +  scanner->eop_last_line_data = NULL; +  scanner->eop_last_line_data_rpos = 0; +  scanner->adf_next_page_lines_data = NULL; +  scanner->adf_next_page_lines_data_size = 0; +  scanner->adf_next_page_lines_data_rpos = 0; +  scanner->adf_next_page_lines_data_wpos = 0; +  scanner->one_line_read_buffer = NULL; +  scanner->one_line_read_buffer_rpos = 0; +  scanner->color_shift_line_buffer1 = NULL; +  scanner->color_shift_buffered_lines1 = 0; +  scanner->color_shift_line_buffer2 = NULL; +  scanner->color_shift_buffered_lines2 = 0;    if (!scanners_list)      scanners_list = scanner; @@ -326,11 +476,11 @@ attach_hp7650 (SANE_String_Const devname)  SANE_Status  sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)  { -  SANE_Status 	ret; -  SANE_Word	vendor_id, product_id; -   +  SANE_Status   ret; +  SANE_Word     vendor_id, product_id; +    DBG_INIT(); -   +    DBG (1, "SANE backed for HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 %u.%u.%u\n",         SANE_CURRENT_MAJOR, V_MINOR, BUILD);    DBG (1, "(c) Ilia Sotnikov <hostcc@gmail.com>\n"); @@ -389,7 +539,34 @@ void sane_exit (void)    for (ptr = scanners_list; ptr; ptr = pnext)      {        if (ptr->opts != NULL) -	free (ptr->opts); +        free (ptr->opts); +      if (ptr->eop_last_line_data != NULL) { +        free (ptr->eop_last_line_data); +        ptr->eop_last_line_data = NULL; +        ptr->eop_last_line_data_rpos = 0; +      } +      if (ptr->adf_next_page_lines_data != NULL) { +        free (ptr->adf_next_page_lines_data); +        ptr->adf_next_page_lines_data = NULL; +        ptr->adf_next_page_lines_data_size = 0; +        ptr->adf_next_page_lines_data_wpos = 0; +        ptr->adf_next_page_lines_data_rpos = 0; +      } +      if (ptr->one_line_read_buffer != NULL) { +        free (ptr->one_line_read_buffer); +        ptr->one_line_read_buffer = NULL; +        ptr->one_line_read_buffer_rpos = 0; +      } +      if (ptr->color_shift_line_buffer1 != NULL) { +        free (ptr->color_shift_line_buffer1); +        ptr->color_shift_line_buffer1 = NULL; +        ptr->color_shift_buffered_lines1 = 0; +      } +      if (ptr->color_shift_line_buffer2 != NULL) { +        free (ptr->color_shift_line_buffer2); +        ptr->color_shift_line_buffer2 = NULL; +        ptr->color_shift_buffered_lines2 = 0; +      }        pnext = ptr->next;        free (ptr);      } @@ -428,11 +605,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)  SANE_Status  sane_open (SANE_String_Const devicename, SANE_Handle * handle)  { -  struct hp5590_scanner 	*ptr; -  SANE_Option_Descriptor 	*opts; -  unsigned int 			available_sources; -  SANE_String_Const 		*sources_list; -  unsigned int 			source_idx; +  struct hp5590_scanner         *ptr; +  SANE_Option_Descriptor        *opts;    DBG (DBG_proc, "%s: device name: %s\n", __func__, devicename); @@ -444,19 +618,31 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)      ptr = scanners_list;    } else {      for (ptr = scanners_list; -	 ptr && strcmp (ptr->sane.name, devicename) != 0; -	 ptr = ptr->next); +         ptr && strcmp (ptr->sane.name, devicename) != 0; +         ptr = ptr->next);    }    if (!ptr)      return SANE_STATUS_INVAL; +  /* DS: Without this after the first scan (and sane_close) +   * it was impossible to use again the read_buttons usb routine. +   * Function sane_close puts dn = -1. Now sane_open needs to open +   * the usb communication again. +   */ +  if (ptr->dn < 0) { +    DBG (DBG_proc, "%s: Reopening USB device\n", __func__); +    if (sanei_usb_open (ptr->sane.name, &ptr->dn) != SANE_STATUS_GOOD) +      return SANE_STATUS_IO_ERROR; +    DBG (DBG_proc, "%s: USB device reopened\n", __func__); +  } +    ptr->tl_x = 0;    ptr->tl_y = 0;    ptr->br_x = ptr->info->max_size_x;    ptr->br_y = ptr->info->max_size_y;    ptr->dpi = res_list[1]; -  ptr->depth = DEPTH_BW;  +  ptr->depth = DEPTH_BW;    ptr->source = SOURCE_FLATBED;    ptr->extend_lamp_timeout = SANE_FALSE;    ptr->wait_for_button = SANE_FALSE; @@ -464,6 +650,9 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)    ptr->quality = 4;    ptr->image_size = 0;    ptr->scanning = SANE_FALSE; +  ptr->overwrite_eop_pixel = SANE_TRUE; +  ptr->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST; +  ptr->eop_trailing_lines_color = 0x7f007f;    *handle = ptr; @@ -542,29 +731,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)    opts[HP5590_OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;    opts[HP5590_OPT_MODE].constraint.string_list = mode_list; -  available_sources = 1; /* Flatbed is always available */ -  if (ptr->info->features & FEATURE_ADF) -    available_sources += 2; -  if (ptr->info->features & FEATURE_TMA) -    available_sources += 2; -  available_sources++;	/* Count terminating NULL */ -  sources_list = malloc (available_sources * sizeof (SANE_String_Const)); -  if (!sources_list) -    return SANE_STATUS_NO_MEM; -  source_idx = 0; -  sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_FLATBED; -  if (ptr->info->features & FEATURE_ADF) -    { -      sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF; -      sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX; -    } -  if (ptr->info->features & FEATURE_TMA) -    { -      sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_SLIDES; -      sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES; -    } -  sources_list[source_idx] = NULL; - +  /* Show all features, check on feature in command line evaluation. */    opts[HP5590_OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;    opts[HP5590_OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;    opts[HP5590_OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; @@ -605,6 +772,46 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)    opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE;    opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint.string_list = NULL; +  opts[HP5590_OPT_BUTTON_PRESSED].name = SANE_NAME_BUTTON_PRESSED; +  opts[HP5590_OPT_BUTTON_PRESSED].title = SANE_TITLE_BUTTON_PRESSED; +  opts[HP5590_OPT_BUTTON_PRESSED].desc = SANE_DESC_BUTTON_PRESSED; +  opts[HP5590_OPT_BUTTON_PRESSED].type = SANE_TYPE_STRING; +  opts[HP5590_OPT_BUTTON_PRESSED].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_BUTTON_PRESSED].size = BUTTON_PRESSED_VALUE_MAX_KEY_LEN; +  opts[HP5590_OPT_BUTTON_PRESSED].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; +  opts[HP5590_OPT_BUTTON_PRESSED].constraint_type = SANE_CONSTRAINT_STRING_LIST; +  opts[HP5590_OPT_BUTTON_PRESSED].constraint.string_list = buttonstate_list; + +  opts[HP5590_OPT_COLOR_LED].name = SANE_NAME_COLOR_LED; +  opts[HP5590_OPT_COLOR_LED].title = SANE_TITLE_COLOR_LED; +  opts[HP5590_OPT_COLOR_LED].desc = SANE_DESC_COLOR_LED; +  opts[HP5590_OPT_COLOR_LED].type = SANE_TYPE_STRING; +  opts[HP5590_OPT_COLOR_LED].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_COLOR_LED].size = COLOR_LED_VALUE_MAX_KEY_LEN; +  opts[HP5590_OPT_COLOR_LED].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; +  opts[HP5590_OPT_COLOR_LED].constraint_type = SANE_CONSTRAINT_STRING_LIST; +  opts[HP5590_OPT_COLOR_LED].constraint.string_list = colorledstate_list; + +  opts[HP5590_OPT_LCD_COUNTER].name = SANE_NAME_LCD_COUNTER; +  opts[HP5590_OPT_LCD_COUNTER].title = SANE_TITLE_LCD_COUNTER; +  opts[HP5590_OPT_LCD_COUNTER].desc = SANE_DESC_LCD_COUNTER; +  opts[HP5590_OPT_LCD_COUNTER].type = SANE_TYPE_INT; +  opts[HP5590_OPT_LCD_COUNTER].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_LCD_COUNTER].size = sizeof(SANE_Int); +  opts[HP5590_OPT_LCD_COUNTER].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; +  opts[HP5590_OPT_LCD_COUNTER].constraint_type = SANE_CONSTRAINT_RANGE; +  opts[HP5590_OPT_LCD_COUNTER].constraint.range = &lcd_counter_range; + +  opts[HP5590_OPT_DOC_IN_ADF].name = SANE_NAME_DOC_IN_ADF; +  opts[HP5590_OPT_DOC_IN_ADF].title = SANE_TITLE_DOC_IN_ADF; +  opts[HP5590_OPT_DOC_IN_ADF].desc = SANE_DESC_DOC_IN_ADF; +  opts[HP5590_OPT_DOC_IN_ADF].type = SANE_TYPE_BOOL; +  opts[HP5590_OPT_DOC_IN_ADF].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_DOC_IN_ADF].size = sizeof(SANE_Bool); +  opts[HP5590_OPT_DOC_IN_ADF].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; +  opts[HP5590_OPT_DOC_IN_ADF].constraint_type = SANE_CONSTRAINT_NONE; +  opts[HP5590_OPT_DOC_IN_ADF].constraint.range = NULL; +    opts[HP5590_OPT_PREVIEW].name = SANE_NAME_PREVIEW;    opts[HP5590_OPT_PREVIEW].title = SANE_TITLE_PREVIEW;    opts[HP5590_OPT_PREVIEW].desc = SANE_DESC_PREVIEW; @@ -615,6 +822,36 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)    opts[HP5590_OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;    opts[HP5590_OPT_PREVIEW].constraint.string_list = NULL; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].name = SANE_NAME_OVERWRITE_EOP_PIXEL; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].title = SANE_TITLE_OVERWRITE_EOP_PIXEL; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].desc = SANE_DESC_OVERWRITE_EOP_PIXEL; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].type = SANE_TYPE_BOOL; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].size = sizeof(SANE_Bool); +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint_type = SANE_CONSTRAINT_NONE; +  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint.string_list = NULL; + +  opts[HP5590_OPT_TRAILING_LINES_MODE].name = SANE_NAME_TRAILING_LINES_MODE; +  opts[HP5590_OPT_TRAILING_LINES_MODE].title = SANE_TITLE_TRAILING_LINES_MODE; +  opts[HP5590_OPT_TRAILING_LINES_MODE].desc = SANE_DESC_TRAILING_LINES_MODE; +  opts[HP5590_OPT_TRAILING_LINES_MODE].type = SANE_TYPE_STRING; +  opts[HP5590_OPT_TRAILING_LINES_MODE].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_TRAILING_LINES_MODE].size = TRAILING_LINES_MODE_MAX_KEY_LEN; +  opts[HP5590_OPT_TRAILING_LINES_MODE].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +  opts[HP5590_OPT_TRAILING_LINES_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; +  opts[HP5590_OPT_TRAILING_LINES_MODE].constraint.string_list = trailingmode_list; + +  opts[HP5590_OPT_TRAILING_LINES_COLOR].name = SANE_NAME_TRAILING_LINES_COLOR; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].title = SANE_TITLE_TRAILING_LINES_COLOR; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].desc = SANE_DESC_TRAILING_LINES_COLOR; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].type = SANE_TYPE_INT; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].unit = SANE_UNIT_NONE; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].size = sizeof(SANE_Int); +  opts[HP5590_OPT_TRAILING_LINES_COLOR].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint_type = SANE_CONSTRAINT_NONE; +  opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint.string_list = NULL; +    ptr->opts = opts;    return SANE_STATUS_GOOD; @@ -646,285 +883,541 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)    return &scanner->opts[option];  } +/*************************************DS:Support function read buttons status */ +SANE_Status +read_button_pressed(SANE_Handle handle, enum button_status * button_pressed) +{ +  struct hp5590_scanner * scanner = handle; +  *button_pressed = BUTTON_NONE; +  enum button_status status = BUTTON_NONE; +  DBG (DBG_verbose, "%s: Checking button status (device_number = %u) (device_name = %s)\n", __func__, scanner->dn, scanner->sane.name); +  SANE_Status ret = hp5590_read_buttons (scanner->dn, scanner->proto_flags, &status); +  if (ret != SANE_STATUS_GOOD) +    { +      DBG (DBG_proc, "%s: Error reading button status (%u)\n", __func__, ret); +      return ret; +    } +  DBG (DBG_verbose, "%s: Button pressed = %d\n", __func__, status); +  *button_pressed = status; +  return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +SANE_Status +read_lcd_and_led_values(SANE_Handle handle, +        SANE_Int * lcd_counter, +        enum color_led_status * color_led) +{ +  struct hp5590_scanner * scanner = handle; +  *lcd_counter = 1; +  *color_led = LED_COLOR; +  DBG (DBG_verbose, "%s: Reading LCD and LED values (device_number = %u) (device_name = %s)\n", +        __func__, scanner->dn, scanner->sane.name); +  SANE_Status ret = hp5590_read_lcd_and_led (scanner->dn, scanner->proto_flags, lcd_counter, color_led); +  if (ret != SANE_STATUS_GOOD) +    { +      DBG (DBG_proc, "%s: Error reading LCD and LED values (%u)\n", __func__, ret); +      return ret; +    } +  DBG (DBG_verbose, "%s: LCD = %d, LED = %s\n", __func__, *lcd_counter, +        *color_led == LED_BLACKWHITE ? COLOR_LED_VALUE_BLACKWHITE_KEY : COLOR_LED_VALUE_COLOR_KEY); +  return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +SANE_Status +read_doc_in_adf_value(SANE_Handle handle, +        SANE_Bool * doc_in_adf) +{ +  struct hp5590_scanner * scanner = handle; +  DBG (DBG_verbose, "%s: Reading state of document-available in ADF (device_number = %u) (device_name = %s)\n", +        __func__, scanner->dn, scanner->sane.name); +  SANE_Status ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags); +  if (ret == SANE_STATUS_GOOD) +    *doc_in_adf = SANE_TRUE; +  else if (ret == SANE_STATUS_NO_DOCS) +    *doc_in_adf = SANE_FALSE; +  else +    { +      DBG (DBG_proc, "%s: Error reading state of document-available in ADF (%u)\n", __func__, ret); +      return ret; +    } +  DBG (DBG_verbose, "%s: doc_in_adf = %s\n", __func__, *doc_in_adf == SANE_FALSE ? "false" : "true"); +  return SANE_STATUS_GOOD; +} +  /******************************************************************************/  SANE_Status  sane_control_option (SANE_Handle handle, SANE_Int option, -		     SANE_Action action, void *value, +                     SANE_Action action, void *value,                       SANE_Int * info)  { -  struct hp5590_scanner	*scanner = handle; -   +  struct hp5590_scanner *scanner = handle; +    if (!value)      return SANE_STATUS_INVAL;    if (!handle)      return SANE_STATUS_INVAL; -  +    if (option >= HP5590_OPT_LAST)      return SANE_STATUS_INVAL;    if (action == SANE_ACTION_GET_VALUE)      {        if (option == HP5590_OPT_NUM) -	{ -	  DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST); -	  *((SANE_Int *) value) = HP5590_OPT_LAST; -	  return SANE_STATUS_GOOD; -	} -  +        { +          DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST); +          *((SANE_Int *) value) = HP5590_OPT_LAST; +          return SANE_STATUS_GOOD; +        } +        if (!scanner->opts) -	return SANE_STATUS_INVAL; -       +        return SANE_STATUS_INVAL; +        DBG (DBG_proc, "%s: get option '%s' value\n", __func__, scanner->opts[option].name);        if (option == HP5590_OPT_BR_X) -	{ -	  *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4); -	} +        { +          *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4); +        }        if (option == HP5590_OPT_BR_Y) -	{ -	  *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4); -	} +        { +          *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4); +        }        if (option == HP5590_OPT_TL_X) -	{ -	  *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4); -	} +        { +          *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4); +        }        if (option == HP5590_OPT_TL_Y) -	{ -	  *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4); -	} +        { +          *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4); +        }        if (option == HP5590_OPT_MODE) -	{ -	  switch (scanner->depth) { -	    case DEPTH_BW: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART)); -	      break; -	    case DEPTH_GRAY: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY)); -	      break; -	    case DEPTH_COLOR_24: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24)); -	      break; -	    case DEPTH_COLOR_48: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48)); -	      break; -	    default: -	      return SANE_STATUS_INVAL; -	  } -	} +        { +          switch (scanner->depth) { +            case DEPTH_BW: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART)); +              break; +            case DEPTH_GRAY: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY)); +              break; +            case DEPTH_COLOR_24: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24)); +              break; +            case DEPTH_COLOR_48: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48)); +              break; +            default: +              return SANE_STATUS_INVAL; +          } +        }        if (option == HP5590_OPT_SOURCE) -	{ -	  switch (scanner->source) { -	    case SOURCE_FLATBED: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED)); -	      break; -	    case SOURCE_ADF: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF)); -	      break; -	    case SOURCE_ADF_DUPLEX: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX)); -	      break; -	    case SOURCE_TMA_SLIDES: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES)); -	      break; -	    case SOURCE_TMA_NEGATIVES: -	      memset (value , 0, scanner->opts[option].size); -	      memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES)); -	      break; -	    case SOURCE_NONE: -	    default: -	      return SANE_STATUS_INVAL; -	  } -	} +        { +          switch (scanner->source) { +            case SOURCE_FLATBED: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED)); +              break; +            case SOURCE_ADF: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF)); +              break; +            case SOURCE_ADF_DUPLEX: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX)); +              break; +            case SOURCE_TMA_SLIDES: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES)); +              break; +            case SOURCE_TMA_NEGATIVES: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES)); +              break; +            case SOURCE_NONE: +            default: +              return SANE_STATUS_INVAL; +          } +        }        if (option == HP5590_OPT_RESOLUTION) -	{ -	  *(SANE_Int *) value = scanner->dpi; -	} +        { +          *(SANE_Int *) value = scanner->dpi; +        }        if (option == HP5590_OPT_LAMP_TIMEOUT) -	{ -	  *(SANE_Bool *) value = scanner->extend_lamp_timeout; -	} +        { +          *(SANE_Bool *) value = scanner->extend_lamp_timeout; +        }        if (option == HP5590_OPT_WAIT_FOR_BUTTON) -	{ -	  *(SANE_Bool *) value = scanner->wait_for_button; -	} +        { +          *(SANE_Bool *) value = scanner->wait_for_button; +        } + +      if (option == HP5590_OPT_BUTTON_PRESSED) +        { +          enum button_status button_pressed = BUTTON_NONE; +          SANE_Status ret = read_button_pressed(scanner, &button_pressed); +          if (ret != SANE_STATUS_GOOD) +            return ret; +          switch (button_pressed) { +            case BUTTON_POWER: +              strncpy (value, BUTTON_PRESSED_VALUE_POWER_KEY, scanner->opts[option].size); +              break; +            case BUTTON_SCAN: +              strncpy (value, BUTTON_PRESSED_VALUE_SCAN_KEY, scanner->opts[option].size); +              break; +            case BUTTON_COLLECT: +              strncpy (value, BUTTON_PRESSED_VALUE_COLLECT_KEY, scanner->opts[option].size); +              break; +            case BUTTON_FILE: +              strncpy (value, BUTTON_PRESSED_VALUE_FILE_KEY, scanner->opts[option].size); +              break; +            case BUTTON_EMAIL: +              strncpy (value, BUTTON_PRESSED_VALUE_EMAIL_KEY, scanner->opts[option].size); +              break; +            case BUTTON_COPY: +              strncpy (value, BUTTON_PRESSED_VALUE_COPY_KEY, scanner->opts[option].size); +              break; +            case BUTTON_UP: +              strncpy (value, BUTTON_PRESSED_VALUE_UP_KEY, scanner->opts[option].size); +              break; +            case BUTTON_DOWN: +              strncpy (value, BUTTON_PRESSED_VALUE_DOWN_KEY, scanner->opts[option].size); +              break; +            case BUTTON_MODE: +              strncpy (value, BUTTON_PRESSED_VALUE_MODE_KEY, scanner->opts[option].size); +              break; +            case BUTTON_CANCEL: +              strncpy (value, BUTTON_PRESSED_VALUE_CANCEL_KEY, scanner->opts[option].size); +              break; +            case BUTTON_NONE: +            default: +              strncpy (value, BUTTON_PRESSED_VALUE_NONE_KEY, scanner->opts[option].size); +          } +        } + +      if (option == HP5590_OPT_COLOR_LED) +        { +          SANE_Int lcd_counter = 0; +          enum color_led_status color_led = LED_COLOR; +          SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led); +          if (ret != SANE_STATUS_GOOD) +            return ret; +          switch (color_led) { +            case LED_BLACKWHITE: +              strncpy (value, COLOR_LED_VALUE_BLACKWHITE_KEY, scanner->opts[option].size); +              break; +            case LED_COLOR: +            default: +              strncpy (value, COLOR_LED_VALUE_COLOR_KEY, scanner->opts[option].size); +          } +        } + +      if (option == HP5590_OPT_LCD_COUNTER) +        { +          SANE_Int lcd_counter = 0; +          enum color_led_status color_led = LED_COLOR; +          SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led); +          if (ret != SANE_STATUS_GOOD) +            return ret; +          *(SANE_Int *) value = lcd_counter; +        } + +      if (option == HP5590_OPT_DOC_IN_ADF) +        { +          SANE_Bool doc_in_adf = SANE_FALSE; +          SANE_Status ret = read_doc_in_adf_value(scanner, &doc_in_adf); +          if (ret != SANE_STATUS_GOOD) +            return ret; +          *(SANE_Bool *) value = doc_in_adf; +        }        if (option == HP5590_OPT_PREVIEW) -	{ -	  *(SANE_Bool *) value = scanner->preview; -	} +        { +          *(SANE_Bool *) value = scanner->preview; +        } + +      if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL) +        { +          *(SANE_Bool *) value = scanner->overwrite_eop_pixel; +        } + +      if (option == HP5590_OPT_TRAILING_LINES_MODE) +        { +          switch (scanner->eop_trailing_lines_mode) { +            case TRAILING_LINES_MODE_RAW: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_RAW_KEY, strlen (TRAILING_LINES_MODE_RAW_KEY)); +              break; +            case TRAILING_LINES_MODE_LAST: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_LAST_KEY, strlen (TRAILING_LINES_MODE_LAST_KEY)); +              break; +            case TRAILING_LINES_MODE_RASTER: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_RASTER_KEY, strlen (TRAILING_LINES_MODE_RASTER_KEY)); +              break; +            case TRAILING_LINES_MODE_BLACK: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_BLACK_KEY, strlen (TRAILING_LINES_MODE_BLACK_KEY)); +              break; +            case TRAILING_LINES_MODE_WHITE: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_WHITE_KEY, strlen (TRAILING_LINES_MODE_WHITE_KEY)); +              break; +            case TRAILING_LINES_MODE_COLOR: +              memset (value , 0, scanner->opts[option].size); +              memcpy (value, TRAILING_LINES_MODE_COLOR_KEY, strlen (TRAILING_LINES_MODE_COLOR_KEY)); +              break; +            default: +              return SANE_STATUS_INVAL; +          } +        } + +      if (option == HP5590_OPT_TRAILING_LINES_COLOR) +        { +          *(SANE_Int *) value = scanner->eop_trailing_lines_color; +        }      } -  +    if (action == SANE_ACTION_SET_VALUE)      {        if (option == HP5590_OPT_NUM) -	return SANE_STATUS_INVAL; +        return SANE_STATUS_INVAL;        if (option == HP5590_OPT_BR_X) -	{ -	  float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; -	  if (val <= scanner->tl_x) -	    return SANE_STATUS_GOOD; -	  scanner->br_x = val; -	  if (info) -	    *info = SANE_INFO_RELOAD_PARAMS; -	} +        { +          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; +          if (val <= scanner->tl_x) +            return SANE_STATUS_GOOD; +          scanner->br_x = val; +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS; +        }        if (option == HP5590_OPT_BR_Y) -	{ -	  float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; -	  if (val <= scanner->tl_y) -	    return SANE_STATUS_GOOD; -	  scanner->br_y = val; -	  if (info) - 	    *info = SANE_INFO_RELOAD_PARAMS; -	} +        { +          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; +          if (val <= scanner->tl_y) +            return SANE_STATUS_GOOD; +          scanner->br_y = val; +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS; +        }        if (option == HP5590_OPT_TL_X) -	{ -	  float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; -	  if (val >= scanner->br_x) -	    return SANE_STATUS_GOOD; -	  scanner->tl_x = val; -	  if (info) - 	    *info = SANE_INFO_RELOAD_PARAMS; -	} +        { +          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; +          if (val >= scanner->br_x) +            return SANE_STATUS_GOOD; +          scanner->tl_x = val; +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS; +        }        if (option == HP5590_OPT_TL_Y) -	{ -	  float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; -	  if (val >= scanner->br_y) -	    return SANE_STATUS_GOOD; -	  scanner->tl_y = val; -	  if (info) -  	    *info = SANE_INFO_RELOAD_PARAMS; -	} +        { +          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; +          if (val >= scanner->br_y) +            return SANE_STATUS_GOOD; +          scanner->tl_y = val; +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS; +        }        if (option == HP5590_OPT_MODE) -	{ -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0) -	    { -	      scanner->depth = DEPTH_BW; -	    } - -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0) -	    { -	      scanner->depth = DEPTH_GRAY; -	    } - -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0) -	    { -	      scanner->depth = DEPTH_COLOR_24; -	    } - -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0) -	    { -	      scanner->depth = DEPTH_COLOR_48; -	    } -	  if (info) - 	    *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -	} +        { +          if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0) +            { +              scanner->depth = DEPTH_BW; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0) +            { +              scanner->depth = DEPTH_GRAY; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0) +            { +              scanner->depth = DEPTH_COLOR_24; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0) +            { +              scanner->depth = DEPTH_COLOR_48; +            } +          else +            { +              return SANE_STATUS_INVAL; +            } + +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; +        }        if (option == HP5590_OPT_SOURCE) -	{ +        {            range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0) -	    { -	      scanner->source = SOURCE_FLATBED; -	      range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); -	      range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); -	      scanner->br_x = scanner->info->max_size_x; -	      scanner->br_y = scanner->info->max_size_y; -	    } -	  /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually -	   * bigger than what scanner reports back during initialization -	   */ -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0) -	    { -	      scanner->source = SOURCE_ADF; -	      range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); -	      range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); -	      scanner->br_x = scanner->info->max_size_x; -	      scanner->br_y = ADF_MAX_Y_INCHES * 25.4; -	    } -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0) -	    { -	      scanner->source = SOURCE_ADF_DUPLEX; -	      range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); -	      range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4 * 2); -	      scanner->br_y = ADF_MAX_Y_INCHES * 25.4 * 2; -	      scanner->br_x = scanner->info->max_size_x; -	    } -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0) -	    { -	      scanner->source = SOURCE_TMA_SLIDES; -	      range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); -	      range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); -	      scanner->br_x = TMA_MAX_X_INCHES * 25.4; -	      scanner->br_y = TMA_MAX_Y_INCHES * 25.4; -	    } -	  if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0) -	    { -	      scanner->source = SOURCE_TMA_NEGATIVES; -	      range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); -	      range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); -	      scanner->br_x = TMA_MAX_X_INCHES * 25.4; -	      scanner->br_y = TMA_MAX_Y_INCHES * 25.4; -	    } -	  if (info) -	    *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -	} +          if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0) +            { +              scanner->source = SOURCE_FLATBED; +              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); +              range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); +              scanner->br_x = scanner->info->max_size_x; +              scanner->br_y = scanner->info->max_size_y; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0) +            { +              /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually +               * bigger than what scanner reports back during initialization +               */ +              if (! (scanner->info->features & FEATURE_ADF)) +                { +                  DBG(DBG_err, "ADF feature not available: %s\n", (char *) value); +                  return SANE_STATUS_UNSUPPORTED; +                } +              scanner->source = SOURCE_ADF; +              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); +              range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); +              scanner->br_x = scanner->info->max_size_x; +              scanner->br_y = ADF_MAX_Y_INCHES; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0) +            { +              if (! (scanner->info->features & FEATURE_ADF)) +                { +                  DBG(DBG_err, "ADF feature not available: %s\n", (char *) value); +                  return SANE_STATUS_UNSUPPORTED; +                } +              scanner->source = SOURCE_ADF_DUPLEX; +              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); +              range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); +              scanner->br_x = scanner->info->max_size_x; +              scanner->br_y = ADF_MAX_Y_INCHES; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0) +            { +              if (! (scanner->info->features & FEATURE_TMA)) +                { +                  DBG(DBG_err, "TMA feature not available: %s\n", (char *) value); +                  return SANE_STATUS_UNSUPPORTED; +                } +              scanner->source = SOURCE_TMA_SLIDES; +              range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); +              range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); +              scanner->br_x = TMA_MAX_X_INCHES; +              scanner->br_y = TMA_MAX_Y_INCHES; +            } +          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0) +            { +              if (! (scanner->info->features & FEATURE_TMA)) +                { +                  DBG(DBG_err, "TMA feature not available: %s\n", (char *) value); +                  return SANE_STATUS_UNSUPPORTED; +                } +              scanner->source = SOURCE_TMA_NEGATIVES; +              range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); +              range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); +              scanner->br_x = TMA_MAX_X_INCHES; +              scanner->br_y = TMA_MAX_Y_INCHES; +            } +          else +            { +              return SANE_STATUS_INVAL; +            } +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; +        }        if (option == HP5590_OPT_RESOLUTION) -	{ -	  scanner->dpi = *(SANE_Int *) value; -	  if (info) -	    *info = SANE_INFO_RELOAD_PARAMS; -	} +        { +          scanner->dpi = *(SANE_Int *) value; +          if (info) +            *info = SANE_INFO_RELOAD_PARAMS; +        }        if (option == HP5590_OPT_LAMP_TIMEOUT) -	{ -	  scanner->extend_lamp_timeout = *(SANE_Bool *) value; -	} +        { +          scanner->extend_lamp_timeout = *(SANE_Bool *) value; +        }        if (option == HP5590_OPT_WAIT_FOR_BUTTON) -	{ -	  scanner->wait_for_button = *(SANE_Bool *) value; -	} +        { +          scanner->wait_for_button = *(SANE_Bool *) value; +        } + +      if (option == HP5590_OPT_BUTTON_PRESSED) +        { +          DBG(DBG_verbose, "State of buttons is read only. Setting of state will be ignored.\n"); +        } + +      if (option == HP5590_OPT_COLOR_LED) +        { +          DBG(DBG_verbose, "State of color LED indicator is read only. Setting of state will be ignored.\n"); +        } + +      if (option == HP5590_OPT_LCD_COUNTER) +        { +          DBG(DBG_verbose, "Value of LCD counter is read only. Setting of value will be ignored.\n"); +        } + +      if (option == HP5590_OPT_DOC_IN_ADF) +        { +          DBG(DBG_verbose, "Value of document-available indicator is read only. Setting of value will be ignored.\n"); +        }        if (option == HP5590_OPT_PREVIEW) -	{ -	  scanner->preview = *(SANE_Bool *) value; -	} +        { +          scanner->preview = *(SANE_Bool *) value; +        } + +      if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL) +        { +          scanner->overwrite_eop_pixel = *(SANE_Bool *) value; +        } + +      if (option == HP5590_OPT_TRAILING_LINES_MODE) +        { +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RAW_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RAW; +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_LAST_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST; +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RASTER_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RASTER; +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_BLACK_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_BLACK; +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_WHITE_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_WHITE; +          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_COLOR_KEY) == 0) +            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_COLOR; +        } + +      if (option == HP5590_OPT_TRAILING_LINES_COLOR) +        { +          scanner->eop_trailing_lines_color = *(SANE_Int *) value; +        }      } -    +    return SANE_STATUS_GOOD;  }  /******************************************************************************/  SANE_Status sane_get_parameters (SANE_Handle handle, -		                 SANE_Parameters * params) +                                 SANE_Parameters * params)  { -  struct hp5590_scanner	*scanner = handle; -  SANE_Status		ret; -  unsigned int		pixel_bits; +  struct hp5590_scanner *scanner = handle; +  SANE_Status           ret; +  unsigned int          pixel_bits;    DBG (DBG_proc, "%s\n", __func__); @@ -935,10 +1428,10 @@ SANE_Status sane_get_parameters (SANE_Handle handle,      return SANE_STATUS_INVAL;    ret = calc_image_params (scanner, -			   (unsigned int *) &pixel_bits, -			   (unsigned int *) ¶ms->pixels_per_line, -			   (unsigned int *) ¶ms->bytes_per_line, -			   (unsigned int *) ¶ms->lines, NULL); +                           (unsigned int *) &pixel_bits, +                           (unsigned int *) ¶ms->pixels_per_line, +                           (unsigned int *) ¶ms->bytes_per_line, +                           (unsigned int *) ¶ms->lines, NULL);    if (ret != SANE_STATUS_GOOD)      return ret; @@ -964,11 +1457,11 @@ SANE_Status sane_get_parameters (SANE_Handle handle,        params->format = SANE_FRAME_RGB;        break;      default: -      DBG(0, "%s: Unknown depth\n", __func__); +      DBG(DBG_err, "%s: Unknown depth\n", __func__);        return SANE_STATUS_INVAL;    } -   +    DBG (DBG_proc, "format: %u, last_frame: %u, bytes_per_line: %u, "         "pixels_per_line: %u, lines: %u, depth: %u\n",         params->format, params->last_frame, @@ -982,31 +1475,61 @@ SANE_Status sane_get_parameters (SANE_Handle handle,  SANE_Status  sane_start (SANE_Handle handle)  { -  struct hp5590_scanner	*scanner = handle; -  SANE_Status		ret; -  unsigned int		bytes_per_line; +  struct hp5590_scanner *scanner = handle; +  SANE_Status           ret; +  unsigned int          bytes_per_line;    DBG (DBG_proc, "%s\n", __func__);    if (!scanner)      return SANE_STATUS_INVAL; +  /* Cleanup for all pages. */ +  if (scanner->eop_last_line_data) +    { +      /* Release last line data */ +      free (scanner->eop_last_line_data); +      scanner->eop_last_line_data = NULL; +      scanner->eop_last_line_data_rpos = 0; +    } +  if (scanner->one_line_read_buffer) +    { +      /* Release temporary line buffer. */ +      free (scanner->one_line_read_buffer); +      scanner->one_line_read_buffer = NULL; +      scanner->one_line_read_buffer_rpos = 0; +    } +  if (scanner->color_shift_line_buffer1) +    { +      /* Release line buffer1 for shifting colors. */ +      free (scanner->color_shift_line_buffer1); +      scanner->color_shift_line_buffer1 = NULL; +      scanner->color_shift_buffered_lines1 = 0; +    } +  if (scanner->color_shift_line_buffer2) +    { +      /* Release line buffer2 for shifting colors. */ +      free (scanner->color_shift_line_buffer2); +      scanner->color_shift_line_buffer2 = NULL; +      scanner->color_shift_buffered_lines2 = 0; +    } +    if (   scanner->scanning == SANE_TRUE        && (  scanner->source == SOURCE_ADF -	 || scanner->source == SOURCE_ADF_DUPLEX)) +         || scanner->source == SOURCE_ADF_DUPLEX))      {        DBG (DBG_verbose, "%s: Scanner is scanning, check if more data is available\n", -	   __func__); +           __func__);        ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags);        if (ret == SANE_STATUS_GOOD) -	{ -	  DBG (DBG_verbose, "%s: More data is available\n", __func__); -	  scanner->transferred_image_size = scanner->image_size; -	  return SANE_STATUS_GOOD; -	} +        { +          DBG (DBG_verbose, "%s: More data is available\n", __func__); +          scanner->transferred_image_size = scanner->image_size; +          return SANE_STATUS_GOOD; +        }        if (ret != SANE_STATUS_NO_DOCS) -	return ret; +        return ret;      }    sane_cancel (handle); @@ -1015,25 +1538,25 @@ sane_start (SANE_Handle handle)      {        enum button_status status;        for (;;) -	{ -	  ret = hp5590_read_buttons (scanner->dn, -	  		     	     scanner->proto_flags, -				     &status); -	  if (ret != SANE_STATUS_GOOD) -	    return ret; - -	  if (status == BUTTON_CANCEL) -	    return SANE_STATUS_CANCELLED; - -	  if (status != BUTTON_NONE && status != BUTTON_POWER) -	    break; -	  sleep (1); -	} +        { +          ret = hp5590_read_buttons (scanner->dn, +                                     scanner->proto_flags, +                                     &status); +          if (ret != SANE_STATUS_GOOD) +            return ret; + +          if (status == BUTTON_CANCEL) +            return SANE_STATUS_CANCELLED; + +          if (status != BUTTON_NONE && status != BUTTON_POWER) +            break; +          usleep (100 * 1000); +        }      } -  DBG (DBG_verbose, "Init scanner\n");   +  DBG (DBG_verbose, "Init scanner\n");    ret = hp5590_init_scanner (scanner->dn, scanner->proto_flags, -  			     NULL, SCANNER_NONE); +                             NULL, SCANNER_NONE);    if (ret != SANE_STATUS_GOOD)      return ret; @@ -1043,21 +1566,21 @@ sane_start (SANE_Handle handle)    DBG (DBG_verbose, "Wakeup\n");    ret = hp5590_select_source_and_wakeup (scanner->dn, scanner->proto_flags, -  					 scanner->source, -					 scanner->extend_lamp_timeout); +                                         scanner->source, +                                         scanner->extend_lamp_timeout);    if (ret != SANE_STATUS_GOOD)      return ret; -  +    ret = hp5590_set_scan_params (scanner->dn, -  				scanner->proto_flags, -  				scanner->info, -			      	scanner->tl_x * scanner->dpi, -			      	scanner->tl_y * scanner->dpi, -			      	(scanner->br_x - scanner->tl_x) * scanner->dpi, -			      	(scanner->br_y - scanner->tl_y) * scanner->dpi, -			      	scanner->dpi, -		              	scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL, -			      	scanner->source); +                                scanner->proto_flags, +                                scanner->info, +                                scanner->tl_x * scanner->dpi, +                                scanner->tl_y * scanner->dpi, +                                (scanner->br_x - scanner->tl_x) * scanner->dpi, +                                (scanner->br_y - scanner->tl_y) * scanner->dpi, +                                scanner->dpi, +                                scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL, +                                scanner->source);    if (ret != SANE_STATUS_GOOD)      {        hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); @@ -1065,8 +1588,8 @@ sane_start (SANE_Handle handle)      }    ret = calc_image_params (scanner, NULL, NULL, -			   &bytes_per_line, NULL, -			   &scanner->image_size); +                           &bytes_per_line, NULL, +                           &scanner->image_size);    if (ret != SANE_STATUS_GOOD)      {        hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); @@ -1079,35 +1602,35 @@ sane_start (SANE_Handle handle)        || scanner->depth == DEPTH_COLOR_48)      {        DBG (1, "Color 24/48 bits: checking if image size is correctly " -	   "aligned on number of colors\n"); +           "aligned on number of colors\n");        if (bytes_per_line % 3) -	{ -	  DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) " -	       "(image size: %u, bytes per line %u)\n", -	       scanner->image_size, bytes_per_line); +        { +          DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) " +               "(image size: %llu, bytes per line %u)\n", +               scanner->image_size, bytes_per_line);            hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); -	  return SANE_STATUS_INVAL; -	} +          return SANE_STATUS_INVAL; +        }        DBG (1, "Color 24/48 bits: image size is correctly aligned on number of colors " -	   "(image size: %u, bytes per line %u)\n", -	   scanner->image_size, bytes_per_line); +           "(image size: %llu, bytes per line %u)\n", +           scanner->image_size, bytes_per_line);        DBG (1, "Color 24/48 bits: checking if image size is correctly " -	   "aligned on bytes per line\n"); +           "aligned on bytes per line\n");        if (scanner->image_size % bytes_per_line) -	{ -	  DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line " -	       "(image size: %u, bytes per line %u)\n", -	       scanner->image_size, bytes_per_line); +        { +          DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line " +               "(image size: %llu, bytes per line %u)\n", +               scanner->image_size, bytes_per_line);            hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); -	  return SANE_STATUS_INVAL; -	} +          return SANE_STATUS_INVAL; +        }        DBG (1, "Color 24/48 bits: image size correctly aligned on bytes per line " -	   "(images size: %u, bytes per line: %u)\n", -	   scanner->image_size, bytes_per_line); +           "(images size: %llu, bytes per line: %u)\n", +           scanner->image_size, bytes_per_line);      } -  -  DBG (DBG_verbose, "Final image size: %u\n", scanner->image_size); + +  DBG (DBG_verbose, "Final image size: %llu\n", scanner->image_size);    DBG (DBG_verbose, "Reverse calibration maps\n");    ret = hp5590_send_reverse_calibration_map (scanner->dn, scanner->proto_flags); @@ -1125,14 +1648,23 @@ sane_start (SANE_Handle handle)        return ret;      } +  if (scanner->adf_next_page_lines_data) +    { +      free (scanner->adf_next_page_lines_data); +      scanner->adf_next_page_lines_data = NULL; +      scanner->adf_next_page_lines_data_size = 0; +      scanner->adf_next_page_lines_data_rpos = 0; +      scanner->adf_next_page_lines_data_wpos = 0; +    } +    scanner->scanning = SANE_TRUE;    DBG (DBG_verbose, "Starting scan\n");    ret = hp5590_start_scan (scanner->dn, scanner->proto_flags);    /* Check for paper jam */ -  if (	  ret == SANE_STATUS_DEVICE_BUSY +  if (    ret == SANE_STATUS_DEVICE_BUSY        && (   scanner->source == SOURCE_ADF -	  || scanner->source == SOURCE_ADF_DUPLEX)) +          || scanner->source == SOURCE_ADF_DUPLEX))      return SANE_STATUS_JAMMED;    if (ret != SANE_STATUS_GOOD) @@ -1145,44 +1677,218 @@ sane_start (SANE_Handle handle)  }  /******************************************************************************/ -static SANE_Status -convert_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) +static void +invert_negative_colors (unsigned char *buf, unsigned int bytes_per_line, struct hp5590_scanner *scanner)  { -  SANE_Int i; +  /* Invert lineart or negatives. */ +  int is_linear = (scanner->depth == DEPTH_BW); +  int is_negative = (scanner->source == SOURCE_TMA_NEGATIVES); +  if (is_linear ^ is_negative) +    { +      for (unsigned int k = 0; k < bytes_per_line; k++) +        buf[k] ^= 0xff; +    } +} -  DBG (DBG_proc, "%s\n", __func__); +/******************************************************************************/ +static SANE_Status +convert_gray_and_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) +{ +  unsigned int pixels_per_line; +  unsigned int pixel_bits; +  unsigned int bytes_per_line; +  unsigned int lines; +  unsigned char *buf; +  SANE_Status ret;    hp5590_assert (scanner != NULL);    hp5590_assert (data != NULL); -  /* Invert lineart */ -  if (scanner->depth == DEPTH_BW) +  if ( ! (scanner->depth == DEPTH_BW || scanner->depth == DEPTH_GRAY)) +    return SANE_STATUS_GOOD; + +  DBG (DBG_proc, "%s\n", __func__); + +  ret = calc_image_params (scanner, +                           &pixel_bits, +                           &pixels_per_line, &bytes_per_line, +                           NULL, NULL); +  if (ret != SANE_STATUS_GOOD) +    return ret; + +  lines = size / bytes_per_line; + +  buf = data; +  for (unsigned int i = 0; i < lines; buf += bytes_per_line, ++i)      { -      for (i = 0; i < size; i++) -	data[i] ^= 0xff; +      if (! scanner->eop_last_line_data) +        { +          if (pixels_per_line > 0) +            { +              /* Test for last-line indicator pixel. If found, store last line +               * and optionally overwrite indicator pixel with neighbor value. +               */ +              unsigned int j = bytes_per_line - 1; +              int eop_found = 0; +              if (scanner->depth == DEPTH_GRAY) +                { +                  eop_found = (buf[j] != 0); +                  if (scanner->overwrite_eop_pixel && (j > 0)) +                    { +                      buf[j] = buf[j-1]; +                    } +                } +              else if (scanner->depth == DEPTH_BW) +                { +                  eop_found = (buf[j] != 0); +                  if (scanner->overwrite_eop_pixel && (j > 0)) +                    { +                      buf[j] = (buf[j-1] & 0x01) ? 0xff : 0; +                    } +                } + +              invert_negative_colors (buf, bytes_per_line, scanner); + +              if (eop_found && (! scanner->eop_last_line_data)) +                { +                  DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", i); +                  scanner->eop_last_line_data = malloc(bytes_per_line); +                  if (! scanner->eop_last_line_data) +                    return SANE_STATUS_NO_MEM; + +                  memcpy (scanner->eop_last_line_data, buf, bytes_per_line); +                  scanner->eop_last_line_data_rpos = 0; + +                  /* Fill trailing line buffer with requested color. */ +                  if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER) +                    { +                      /* Black-white raster. */ +                      if (scanner->depth == DEPTH_BW) +                        { +                          memset (scanner->eop_last_line_data, 0xaa, bytes_per_line); +                        } +                      else +                        { +                          /* Gray. */ +                          for (unsigned int k = 0; k < bytes_per_line; ++k) +                            { +                              scanner->eop_last_line_data[k] = (k & 1 ? 0xff : 0); +                            } +                        } +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE) +                    { +                      /* White. */ +                      if (scanner->depth == DEPTH_BW) +                        { +                          memset (scanner->eop_last_line_data, 0x00, bytes_per_line); +                        } +                      else +                        { +                          memset (scanner->eop_last_line_data, 0xff, bytes_per_line); +                        } +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK) +                    { +                      /* Black. */ +                      if (scanner->depth == DEPTH_BW) +                        { +                          memset (scanner->eop_last_line_data, 0xff, bytes_per_line); +                        } +                      else +                        { +                          memset (scanner->eop_last_line_data, 0x00, bytes_per_line); +                        } +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR) +                    { +                      if (scanner->depth == DEPTH_BW) +                        { +                          /* Black or white. */ +                          memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0x01 ? 0x00 : 0xff, bytes_per_line); +                        } +                      else +                        { +                          /* Gray value */ +                          memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0xff, bytes_per_line); +                        } +                    } +                } +            } +        } +      else +        { +          DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n", +               i, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color); + +          if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) +            { +              /* We are in in ADF mode after last-line and store next page data +               * to buffer. +               */ +              if (! scanner->adf_next_page_lines_data) +                { +                  unsigned int n_rest_lines = lines - i; +                  unsigned int buf_size = n_rest_lines * bytes_per_line; +                  scanner->adf_next_page_lines_data = malloc(buf_size); +                  if (! scanner->adf_next_page_lines_data) +                    return SANE_STATUS_NO_MEM; +                  scanner->adf_next_page_lines_data_size = buf_size; +                  scanner->adf_next_page_lines_data_rpos = 0; +                  scanner->adf_next_page_lines_data_wpos = 0; +                  DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines); +                } +              DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", i, lines); +              invert_negative_colors (buf, bytes_per_line, scanner); +              memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line); +              scanner->adf_next_page_lines_data_wpos += bytes_per_line; +            } + +          if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW) +            { +              /* Copy last line data or corresponding color over trailing lines +               * data. +               */ +              memcpy (buf, scanner->eop_last_line_data, bytes_per_line); +            } +        }      }    return SANE_STATUS_GOOD;  }  /******************************************************************************/ +static unsigned char +get_checked (unsigned char *ptr, unsigned int i, unsigned int length) +{ +  if (i < length) +    { +      return ptr[i]; +    } +  DBG (DBG_details, "get from array out of range: idx=%u, size=%u\n", i, length); +  return 0; +} + +/******************************************************************************/  static SANE_Status  convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)  {    unsigned int pixels_per_line; +  unsigned int pixel_bits;    unsigned int bytes_per_color;    unsigned int bytes_per_line; +  unsigned int bytes_per_line_limit;    unsigned int lines;    unsigned int i, j;    unsigned char *buf; +  unsigned char *bufptr;    unsigned char *ptr; -  SANE_Status	ret; +  SANE_Status   ret;    hp5590_assert (scanner != NULL);    hp5590_assert (data != NULL); -  if (   scanner->depth == DEPTH_BW -      || scanner->depth == DEPTH_GRAY) +  if ( ! (scanner->depth == DEPTH_COLOR_24 || scanner->depth == DEPTH_COLOR_48))      return SANE_STATUS_GOOD;    DBG (DBG_proc, "%s\n", __func__); @@ -1193,79 +1899,555 @@ convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)  #endif    ret = calc_image_params (scanner, -			   NULL, -			   &pixels_per_line, &bytes_per_line, -			   NULL, NULL); +                           &pixel_bits, +                           &pixels_per_line, &bytes_per_line, +                           NULL, NULL);    if (ret != SANE_STATUS_GOOD)      return ret;    lines = size / bytes_per_line; -  bytes_per_color = bytes_per_line / 3; -   -  DBG (DBG_verbose, "Length : %u\n", size);  +  bytes_per_color = (pixel_bits + 7) / 8; + +  bytes_per_line_limit = bytes_per_line; +  if ((scanner->depth == DEPTH_COLOR_48) && (bytes_per_line_limit > 3)) +    { +      /* Last-line indicator pixel has only 3 bytes instead of 6. */ +      bytes_per_line_limit -= 3; +    } + +  DBG (DBG_verbose, "Length : %u\n", size);    DBG (DBG_verbose, "Converting row RGB to normal RGB\n");    DBG (DBG_verbose, "Bytes per line %u\n", bytes_per_line); +  DBG (DBG_verbose, "Bytes per line limited %u\n", bytes_per_line_limit);    DBG (DBG_verbose, "Bytes per color %u\n", bytes_per_color); +  DBG (DBG_verbose, "Pixels per line %u\n", pixels_per_line);    DBG (DBG_verbose, "Lines %u\n", lines); -  buf = malloc (bytes_per_line); -  if (!buf) +  /* Use working buffer for color mapping. */ +  bufptr = malloc (size); +  if (! bufptr)      return SANE_STATUS_NO_MEM; +  memset (bufptr, 0, size); +  buf = bufptr;    ptr = data; -  for (j = 0; j < lines; ptr += bytes_per_line, j++) +  for (j = 0; j < lines; ptr += bytes_per_line_limit, buf += bytes_per_line, j++)      { -      memset (buf, 0, bytes_per_line);        for (i = 0; i < pixels_per_line; i++) -	{ -	  if (scanner->depth == DEPTH_COLOR_24) -	    { -	      /* R */ -	      buf[i*3]   = ptr[i]; -	      /* G */ -	      buf[i*3+1] = ptr[i+bytes_per_color]; -	      /* B */ -	      buf[i*3+2] = ptr[i+bytes_per_color*2]; -	    } -	  else -	    { -	      /* R */ -	      buf[i*6]   = ptr[2*i+1]; -	      buf[i*6+1] = ptr[2*i]; -	      /* G */ -	      buf[i*6+2] = ptr[2*i+bytes_per_color+1]; -	      buf[i*6+3] = ptr[2*i+bytes_per_color]; -	      /* B */ -	      buf[i*6+4] = ptr[2*i+bytes_per_color*2+1]; -	      buf[i*6+5] = ptr[2*i+bytes_per_color*2]; -	    } -	} -       -      /* Invert pixels in case of TMA Negatives source has been selected */ -      if (scanner->source == SOURCE_TMA_NEGATIVES)          { -          for (i = 0; i < bytes_per_line; i++) -            buf[i] ^= 0xff; +          /* Color mapping from raw scanner data to RGB buffer. */ +          if (scanner->depth == DEPTH_COLOR_24) +            { +              /* R */ +              buf[i*3]   = get_checked(ptr, i, bytes_per_line_limit); +              /* G */ +              buf[i*3+1] = get_checked(ptr, i+pixels_per_line, bytes_per_line_limit);; +              /* B */ +              buf[i*3+2] = get_checked(ptr, i+pixels_per_line*2, bytes_per_line_limit); +            } +          else if (scanner->depth == DEPTH_COLOR_48) +            { +              /* Note: The last-line indicator pixel uses only 24 bits, not 48. +               *Blue uses offset of 2 bytes. Green swaps lo and hi. +               */ +              /* R lo, hi*/ +              buf[i*6]   = get_checked(ptr, 2*i+(pixels_per_line-1)*0+1, bytes_per_line_limit); +              buf[i*6+1] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+0, bytes_per_line_limit); +              /* G lo, hi*/ +              buf[i*6+2] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+0, bytes_per_line_limit); +              buf[i*6+3] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+1, bytes_per_line_limit); +              /* B lo, hi*/ +              buf[i*6+4] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+1+2, bytes_per_line_limit); +              buf[i*6+5] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+0+2, bytes_per_line_limit); +            } +        } + +      if (! scanner->eop_last_line_data) +        { +          if (pixels_per_line > 0) +            { +              /* Test for last-line indicator pixel on blue. If found, store +               * last line and optionally overwrite indicator pixel with +               * neighbor value. +               */ +              i = pixels_per_line - 1; +              int eop_found = 0; +              if (scanner->depth == DEPTH_COLOR_24) +                { +                  /* DBG (DBG_details, "BUF24: %u %u %u\n", buf[i*3], buf[i*3+1], buf[i*3+2]); */ +                  eop_found = (buf[i*3+2] != 0); +                  if (scanner->overwrite_eop_pixel && (i > 0)) +                    { +                      buf[i*3] = buf[(i-1)*3]; +                      buf[i*3+1] = buf[(i-1)*3+1]; +                      buf[i*3+2] = buf[(i-1)*3+2]; +                    } +                } +              else if (scanner->depth == DEPTH_COLOR_48) +                { +                  /* DBG (DBG_details, "BUF48: %u %u %u\n", buf[i*6+1], buf[i*6+3], buf[i*6+5]); */ +                  eop_found = (buf[i*6+5] != 0); +                  if (scanner->overwrite_eop_pixel && (i > 0)) +                    { +                      buf[i*6] = buf[(i-1)*6]; +                      buf[i*6+1] = buf[(i-1)*6+1]; +                      buf[i*6+2] = buf[(i-1)*6+2]; +                      buf[i*6+3] = buf[(i-1)*6+3]; +                      buf[i*6+4] = buf[(i-1)*6+4]; +                      buf[i*6+5] = buf[(i-1)*6+5]; +                    } +                } + +              invert_negative_colors (buf, bytes_per_line, scanner); + +              if (eop_found && (! scanner->eop_last_line_data)) +                { +                  DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", j); +                  scanner->eop_last_line_data = malloc(bytes_per_line); +                  if (! scanner->eop_last_line_data) +                    return SANE_STATUS_NO_MEM; + +                  memcpy (scanner->eop_last_line_data, buf, bytes_per_line); +                  scanner->eop_last_line_data_rpos = 0; + +                  /* Fill trailing line buffer with requested color. */ +                  if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER) +                    { +                      /* Black-white raster. */ +                      if (scanner->depth == DEPTH_COLOR_24) +                        { +                          for (unsigned int k = 0; k < bytes_per_line; ++k) +                            { +                              scanner->eop_last_line_data[k] = (k % 6 < 3 ? 0xff : 0); +                            } +                        } +                      else +                        { +                          /* Color48. */ +                          for (unsigned int k = 0; k < bytes_per_line; ++k) +                            { +                              scanner->eop_last_line_data[k] = (k % 12 < 6 ? 0xff : 0); +                            } +                        } +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE) +                    { +                      memset (scanner->eop_last_line_data, 0xff, bytes_per_line); +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK) +                    { +                      memset (scanner->eop_last_line_data, 0x00, bytes_per_line); +                    } +                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR) +                    { +                      /* RGB color value. */ +                      int rgb[3]; +                      rgb[0] = (scanner->eop_trailing_lines_color >> 16) & 0xff; +                      rgb[1] = (scanner->eop_trailing_lines_color >> 8) & 0xff; +                      rgb[2] = scanner->eop_trailing_lines_color & 0xff; +                      if (scanner->depth == DEPTH_COLOR_24) +                        { +                          for (unsigned int k = 0; k < bytes_per_line; ++k) +                            { +                              scanner->eop_last_line_data[k] = rgb[k % 3]; +                            } +                        } +                      else +                        { +                          /* Color48. */ +                          for (unsigned int k = 0; k < bytes_per_line; ++k) +                            { +                              scanner->eop_last_line_data[k] = rgb[(k % 6) >> 1]; +                            } +                        } +                    } +                } +            } +        } +      else +        { +          DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n", +               j, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color); + +          if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) +            { +              /* We are in in ADF mode after last-line and store next page data +               * to buffer. +               */ +              if (! scanner->adf_next_page_lines_data) +                { +                  unsigned int n_rest_lines = lines - j; +                  unsigned int buf_size = n_rest_lines * bytes_per_line; +                  scanner->adf_next_page_lines_data = malloc(buf_size); +                  if (! scanner->adf_next_page_lines_data) +                    return SANE_STATUS_NO_MEM; +                  scanner->adf_next_page_lines_data_size = buf_size; +                  scanner->adf_next_page_lines_data_rpos = 0; +                  scanner->adf_next_page_lines_data_wpos = 0; +                  DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines); +                } +              DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", j, lines); +              invert_negative_colors (buf, bytes_per_line, scanner); +              memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line); +              scanner->adf_next_page_lines_data_wpos += bytes_per_line; +            } + +          if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW) +            { +              /* Copy last line data or corresponding color over trailing lines +               * data. +               */ +              memcpy (buf, scanner->eop_last_line_data, bytes_per_line); +            } +        } +    } +  memcpy (data, bufptr, size); +  free (bufptr); + +  return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +static void +read_data_from_temporary_buffer(struct hp5590_scanner *scanner, +    SANE_Byte * data, unsigned int max_length, +    unsigned int bytes_per_line, SANE_Int *length) +{ +  *length = 0; +  if (scanner && scanner->one_line_read_buffer) +  { +    /* Copy scan data from temporary read buffer and return size copied data. */ +    /* Release buffer, when no data left. */ +    unsigned int rest_len; +    rest_len = bytes_per_line - scanner->one_line_read_buffer_rpos; +    rest_len = (rest_len < max_length) ? rest_len : max_length; +    if (rest_len > 0) +      { +        memcpy (data, scanner->one_line_read_buffer + scanner->one_line_read_buffer_rpos, rest_len); +        scanner->one_line_read_buffer_rpos += rest_len; +        scanner->transferred_image_size -= rest_len; +        *length = rest_len; +      } + +    DBG (DBG_verbose, "Copy scan data from temporary buffer: length = %u, rest in buffer = %u.\n", +        *length, bytes_per_line - scanner->one_line_read_buffer_rpos); + +    if (scanner->one_line_read_buffer_rpos >= bytes_per_line) +      { +        DBG (DBG_verbose, "Release temporary buffer.\n"); +        free (scanner->one_line_read_buffer); +        scanner->one_line_read_buffer = NULL; +        scanner->one_line_read_buffer_rpos = 0; +      } +  } +} + +/******************************************************************************/ +static SANE_Status +sane_read_internal (struct hp5590_scanner * scanner, SANE_Byte * data, +    SANE_Int max_length, SANE_Int * length, unsigned int bytes_per_line) +{ +  SANE_Status ret; + +  DBG (DBG_proc, "%s, length %u, left %llu\n", +       __func__, +       max_length, +       scanner->transferred_image_size); + +  SANE_Int length_limited = 0; +  *length = max_length; +  if ((unsigned long long) *length > scanner->transferred_image_size) +    *length = (SANE_Int) scanner->transferred_image_size; + +  /* Align reading size to bytes per line. */ +  *length -= *length % bytes_per_line; + +  if (scanner->depth == DEPTH_COLOR_48) +    { +      /* Note: The last-line indicator pixel uses only 24 bits (3 bytes), not +       * 48 bits (6 bytes). +       */ +      if (bytes_per_line > 3) +        { +          length_limited = *length - *length % (bytes_per_line - 3); +        } +    } + +  DBG (DBG_verbose, "Aligning requested size to bytes per line " +      "(requested: %d, aligned: %u, limit_for_48bit: %u)\n", +      max_length, *length, length_limited); + +  if (max_length <= 0) +    { +      DBG (DBG_verbose, "Buffer too small for one scan line. Need at least %u bytes per line.\n", +          bytes_per_line); +      scanner->scanning = SANE_FALSE; +      return SANE_STATUS_UNSUPPORTED; +    } + +  if (scanner->one_line_read_buffer) +    { +      /* Copy scan data from temporary read buffer. */ +      read_data_from_temporary_buffer (scanner, data, max_length, bytes_per_line, length); +      if (*length > 0) +        { +          DBG (DBG_verbose, "Return %d bytes, left %llu bytes.\n", *length, scanner->transferred_image_size); +          return SANE_STATUS_GOOD; +        } +    } + +  /* Buffer to return scanned data. We need at least space for one line to +   * simplify color processing and last-line detection. If call buffer is too +   * small, use temporary read buffer for reading one line instead. +   */ +  SANE_Byte * scan_data; +  SANE_Int scan_data_length; +  scan_data = data; +  scan_data_length = *length; + +  /* Note, read length is shorter in 48bit mode. */ +  SANE_Int length_for_read = length_limited ? length_limited : scan_data_length; +  if (length_for_read == 0) +    { +      /* Call buffer is too small for one line. Use temporary read buffer +       * instead. +       */ +      if (! scanner->one_line_read_buffer) +        { +          scanner->one_line_read_buffer = malloc (bytes_per_line); +          if (! scanner->one_line_read_buffer) +            return SANE_STATUS_NO_MEM; +          memset (scanner->one_line_read_buffer, 0, bytes_per_line);          } -      memcpy (ptr, buf, bytes_per_line); +      DBG (DBG_verbose, "Call buffer too small for one scan line. Use temporary read buffer for one line with %u bytes.\n", +          bytes_per_line); + +      /* Scan and process next line in temporary buffer. */ +      scan_data = scanner->one_line_read_buffer; +      scan_data_length = bytes_per_line; +      length_for_read = bytes_per_line; +      if (scanner->depth == DEPTH_COLOR_48) +        { +          /* The last-line indicator pixel uses only 24 bits (3 bytes), not 48 +           * bits (6 bytes). +           */ +          if (length_for_read > 3) +            { +              length_for_read -= 3; +            } +        }      } -  free (buf); +  int read_from_scanner = 1; +  if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) +    { +      if (scanner->eop_last_line_data) +        { +          /* Scanner is in ADF mode between last-line of previous page and +           * start of next page. +           * Fill remaining lines with last-line data. +           */ +          unsigned int wpos = 0; +          while (wpos < (unsigned int) scan_data_length) +            { +              unsigned int n1 = scan_data_length - wpos; +              unsigned int n2 = bytes_per_line - scanner->eop_last_line_data_rpos; +              n1 = (n1 < n2) ? n1 : n2; +              memcpy (scan_data + wpos, scanner->eop_last_line_data + scanner->eop_last_line_data_rpos, n1); +              wpos += n1; +              scanner->eop_last_line_data_rpos += n1; +              if (scanner->eop_last_line_data_rpos >= bytes_per_line) +                scanner->eop_last_line_data_rpos = 0; +            } +          read_from_scanner = (wpos == 0); +          DBG (DBG_verbose, "ADF use last-line data, wlength=%u, length=%u\n", wpos, scan_data_length); +        } +      else if (scanner->adf_next_page_lines_data) +        { +          /* Scanner is in ADF mode at start of next page and already some next +           * page data is available from earlier read operation. Return this +           * data. +           */ +          unsigned int wpos = 0; +          while ((wpos < (unsigned int) scan_data_length) && +                 (scanner->adf_next_page_lines_data_rpos < scanner->adf_next_page_lines_data_size)) +            { +              unsigned int n1 = scan_data_length - wpos; +              unsigned int n2 = scanner->adf_next_page_lines_data_size - scanner->adf_next_page_lines_data_rpos; +              n1 = (n1 < n2) ? n1 : n2; +              memcpy (scan_data + wpos, scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_rpos, n1); +              wpos += n1; +              scanner->adf_next_page_lines_data_rpos += n1; +              if (scanner->adf_next_page_lines_data_rpos >= scanner->adf_next_page_lines_data_size) +                { +                  free (scanner->adf_next_page_lines_data); +                  scanner->adf_next_page_lines_data = NULL; +                  scanner->adf_next_page_lines_data_size = 0; +                  scanner->adf_next_page_lines_data_rpos = 0; +                  scanner->adf_next_page_lines_data_wpos = 0; +                } +            } +          scan_data_length = wpos; +          read_from_scanner = (wpos == 0); +          DBG (DBG_verbose, "ADF use next-page data, wlength=%u, length=%u\n", wpos, scan_data_length); +        } +    } + +  if (read_from_scanner) +    { +      /* Read data from scanner. */ +      ret = hp5590_read (scanner->dn, scanner->proto_flags, +                         scan_data, length_for_read, +                         scanner->bulk_read_state); +      if (ret != SANE_STATUS_GOOD) +        { +          scanner->scanning = SANE_FALSE; +          return ret; +        } + +      /* Look for last-line indicator pixels in convert functions. +       * If found: +       *   - Overwrite indicator pixel with neighboring color (optional). +       *   - Save last line data for later use. +       */ +      ret = convert_to_rgb (scanner, scan_data, scan_data_length); +      if (ret != SANE_STATUS_GOOD) +        { +          scanner->scanning = SANE_FALSE; +          return ret; +        } + +      ret = convert_gray_and_lineart (scanner, scan_data, scan_data_length); +      if (ret != SANE_STATUS_GOOD) +        return ret; +    } + +  if (data == scan_data) +    { +      /* Scanned to call buffer. */ +      scanner->transferred_image_size -= scan_data_length; +      *length = scan_data_length; +    } +  else +    { +      /* Scanned to temporary read buffer. */ +      if (scanner->one_line_read_buffer) +        { +          /* Copy scan data from temporary read buffer. */ +          read_data_from_temporary_buffer (scanner, data, max_length, scan_data_length, length); +        } +      else +        { +          *length = 0; +        } +    } + +  DBG (DBG_verbose, "Return %d bytes, left %llu bytes\n", *length, scanner->transferred_image_size);    return SANE_STATUS_GOOD;  } +/****************************************************************************** + * Copy at maximum the last n lines from the src buffer to the begin of the dst + * buffer. + * Return number of lines copied. + */ +static SANE_Int +copy_n_last_lines(SANE_Byte * src, SANE_Int src_len, SANE_Byte * dst, SANE_Int n, unsigned int bytes_per_line) +{ +  DBG (DBG_proc, "%s\n", __func__); +  SANE_Int n_copy = MY_MIN(src_len, n); +  SANE_Byte * src1 = src + (src_len - n_copy) * bytes_per_line; +  memcpy (dst, src1, n_copy * bytes_per_line); +  return n_copy; +} + +/****************************************************************************** + * Copy the color values from line - delta_lines to line. + * buffer2 : Source and target buffer. + * buffer1 : Only source buffer. Contains lines scanned before lines in buffer1. + * color_idx : Index of color to be copied (0..2). + * delta_lines : color shift. + * color_48 : True = 2 byte , false = 1 byte per color. + */ +static void +shift_color_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, SANE_Int n_lines1, SANE_Int color_idx, SANE_Int delta_lines, SANE_Bool color_48, unsigned int bytes_per_line) +{ +  DBG (DBG_proc, "%s\n", __func__); +  for (SANE_Int i = n_lines2 - 1; i >= 0; --i) { +    SANE_Byte * dst = buffer2 + i * bytes_per_line; +    SANE_Int ii = i - delta_lines; +    SANE_Byte * src = NULL; +    SANE_Int source_color_idx = color_idx; +    if (ii >= 0) { +      /* Read from source and target buffer. */ +      src = buffer2 + ii * bytes_per_line; +    } else { +      ii += n_lines1; +      if (ii >= 0) { +        /* Read from source only buffer. */ +        src = buffer1 + ii * bytes_per_line; +      } else { +        /* Read other color from source position. */ +        src = dst; +        source_color_idx = 2; +      } +    } +    /* Copy selected color values. */ +    SANE_Int step = color_48 ? 2 : 1; +    SANE_Int stride = 3 * step; +    for (unsigned int pos = 0; pos < bytes_per_line; pos += stride) { +      SANE_Int p1 = pos + step * source_color_idx; +      SANE_Int p2 = pos + step * color_idx; +      dst[p2] = src[p1]; +      if (color_48) { +        dst[p2 + 1] = src[p1 + 1]; +      } +    } +  } +} + +/****************************************************************************** + * Append all lines from buffer2 to the end of buffer1 and keep max_lines last + * lines. + * buffer2 : Source line buffer. + * buffer1 : Target line buffer. Length will be adjusted. + * max_lines : Max number of lines in buffer1. + */ +static void +append_and_move_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, unsigned int * n_lines1_ptr, SANE_Int max_lines, unsigned int bytes_per_line) +{ +  DBG (DBG_proc, "%s\n", __func__); +  SANE_Int rest1 = max_lines - *n_lines1_ptr; +  SANE_Int copy2 = MY_MIN(n_lines2, max_lines); +  if (copy2 > rest1) { +    SANE_Int shift1 = *n_lines1_ptr + copy2 - max_lines; +    SANE_Int blen = MY_MIN(max_lines - shift1, (SANE_Int) *n_lines1_ptr); +    SANE_Byte * pdst = buffer1; +    SANE_Byte * psrc = pdst + shift1 * bytes_per_line; +    for (SANE_Int i = 0; i < blen; ++i) { +      memcpy (pdst, psrc, bytes_per_line); +      pdst += bytes_per_line; +      psrc += bytes_per_line; +    } +    *n_lines1_ptr -= shift1; +  } +  SANE_Int n_copied = copy_n_last_lines(buffer2, n_lines2, buffer1 + *n_lines1_ptr * bytes_per_line, copy2, bytes_per_line); +  *n_lines1_ptr += n_copied; +} + +  /******************************************************************************/  SANE_Status  sane_read (SANE_Handle handle, SANE_Byte * data, -	   SANE_Int max_length, SANE_Int * length) +           SANE_Int max_length, SANE_Int * length)  { -  struct hp5590_scanner	*scanner = handle; -  SANE_Status 		ret; +  struct hp5590_scanner *scanner = handle; +  SANE_Status ret; -  DBG (DBG_proc, "%s, length %u, left %u\n", +  DBG (DBG_proc, "%s, length %u, left %llu\n",         __func__,         max_length,         scanner->transferred_image_size); @@ -1283,7 +2465,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data,        ret = hp5590_inc_scan_count (scanner->dn, scanner->proto_flags);        if (ret != SANE_STATUS_GOOD) -	return ret; +        return ret;        /* Don't free bulk read state, some bytes could be left         * for the next images from ADF @@ -1295,70 +2477,78 @@ sane_read (SANE_Handle handle, SANE_Byte * data,      {        ret = hp5590_low_init_bulk_read_state (&scanner->bulk_read_state);        if (ret != SANE_STATUS_GOOD) -	{ -	  scanner->scanning = SANE_FALSE; -	  return ret; -	} +        { +          scanner->scanning = SANE_FALSE; +          return ret; +        }      } -  *length = max_length; -  if (*length > scanner->transferred_image_size) -    *length = scanner->transferred_image_size; - -  if (   scanner->depth == DEPTH_COLOR_24 -      || scanner->depth == DEPTH_COLOR_48) -   { -      unsigned int bytes_per_line; -      ret = calc_image_params (scanner, -			       NULL, NULL, -			       &bytes_per_line, -			       NULL, NULL); -      if (ret != SANE_STATUS_GOOD) -	return ret; +  unsigned int bytes_per_line; +  ret = calc_image_params (scanner, +                           NULL, NULL, +                           &bytes_per_line, +                           NULL, NULL); +  if (ret != SANE_STATUS_GOOD) +    return ret; -     *length -= *length % bytes_per_line; -     DBG (2, "Aligning requested size to bytes per line " -	  "(requested: %u, aligned: %u)\n", -	  max_length, *length); -   } +  ret = sane_read_internal(scanner, data, max_length, length, bytes_per_line); -  ret = hp5590_read (scanner->dn, scanner->proto_flags, -  		     data, *length, scanner->bulk_read_state); -  if (ret != SANE_STATUS_GOOD) +  if ((ret == SANE_STATUS_GOOD) && (scanner->dpi == 2400) && +          ((scanner->depth == DEPTH_COLOR_48) || (scanner->depth == DEPTH_COLOR_24)))      { -      scanner->scanning = SANE_FALSE; -      return ret; -    } +      /* Correct color shift bug for 2400 dpi. +       * Note: 2400 dpi only works in color mode. Grey mode and lineart seem to +       * fail. +       * Align colors by shifting B channel by 48 lines and G channel by 24 +       * lines. +       */ +      const SANE_Int offset_max = 48; +      const SANE_Int offset_part = 24; +      SANE_Bool color_48 = (scanner->depth == DEPTH_COLOR_48); -  scanner->transferred_image_size -= *length; +      if (! scanner->color_shift_line_buffer1) +        { +          scanner->color_shift_buffered_lines1 = 0; +          scanner->color_shift_line_buffer1 = malloc (bytes_per_line * offset_max); +          if (! scanner->color_shift_line_buffer1) +            return SANE_STATUS_NO_MEM; +          memset (scanner->color_shift_line_buffer1, 0, bytes_per_line * offset_max); +        } +      if (! scanner->color_shift_line_buffer2) +        { +          scanner->color_shift_buffered_lines2 = 0; +          scanner->color_shift_line_buffer2 = malloc (bytes_per_line * offset_max); +          if (! scanner->color_shift_line_buffer2) +            return SANE_STATUS_NO_MEM; +          memset (scanner->color_shift_line_buffer2, 0, bytes_per_line * offset_max); +        } -  ret = convert_to_rgb (scanner, data, *length); -  if (ret != SANE_STATUS_GOOD) -    { -      scanner->scanning = SANE_FALSE; -      return ret; -    } +      SANE_Int n_lines = *length / bytes_per_line; +      scanner->color_shift_buffered_lines2 = MY_MIN(n_lines, offset_max); +      copy_n_last_lines(data, n_lines, scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, bytes_per_line); -  ret = convert_lineart (scanner, data, *length); -  if (ret != SANE_STATUS_GOOD) -    return ret; +      shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 1, offset_part, color_48, bytes_per_line); +      shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 0, offset_max, color_48, bytes_per_line); -  return SANE_STATUS_GOOD; +      append_and_move_lines(scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, scanner->color_shift_line_buffer1, &(scanner->color_shift_buffered_lines1), offset_max, bytes_per_line); +    } + +  return ret;  }  /******************************************************************************/  void  sane_cancel (SANE_Handle handle)  { -  struct hp5590_scanner	*scanner = handle; -  SANE_Status		ret; +  struct hp5590_scanner *scanner = handle; +  SANE_Status ret;    DBG (DBG_proc, "%s\n", __func__);    scanner->scanning = SANE_FALSE;    if (scanner->dn < 0) -   return;  +   return;    hp5590_low_free_bulk_read_state (&scanner->bulk_read_state); @@ -1371,7 +2561,7 @@ sane_cancel (SANE_Handle handle)  SANE_Status  sane_set_io_mode (SANE_Handle __sane_unused__ handle, -		  SANE_Bool __sane_unused__ non_blocking) +                  SANE_Bool __sane_unused__ non_blocking)  {    DBG (DBG_proc, "%s\n", __func__); @@ -1381,7 +2571,7 @@ sane_set_io_mode (SANE_Handle __sane_unused__ handle,  /******************************************************************************/  SANE_Status  sane_get_select_fd (SANE_Handle __sane_unused__ handle, -		    SANE_Int __sane_unused__ * fd) +                    SANE_Int __sane_unused__ * fd)  {    DBG (DBG_proc, "%s\n", __func__);  | 
