1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 2007 Ilia Sotnikov <hostcc@gmail.com>
3141cc406Sopenharmony_ci   HP ScanJet 4570c support by Markham Thomas
4141cc406Sopenharmony_ci   ADF page detection and high DPI fixes by Bernard Badeer
5141cc406Sopenharmony_ci   scanbd integration by Damiano Scaramuzza and Bernard Badeer
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   This file is part of a SANE backend for
43141cc406Sopenharmony_ci   HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 Scanners
44141cc406Sopenharmony_ci*/
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include "../include/sane/config.h"
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#include <stdio.h>
49141cc406Sopenharmony_ci#include <string.h>
50141cc406Sopenharmony_ci#include <unistd.h>
51141cc406Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
52141cc406Sopenharmony_ci#include <sys/types.h>
53141cc406Sopenharmony_ci#endif
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#include "../include/sane/sane.h"
56141cc406Sopenharmony_ci#define BACKEND_NAME hp5590
57141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
58141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
59141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
60141cc406Sopenharmony_ci#include "hp5590_cmds.c"
61141cc406Sopenharmony_ci#include "hp5590_low.c"
62141cc406Sopenharmony_ci#include "../include/sane/sanei_net.h"
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci/* Debug levels */
65141cc406Sopenharmony_ci#define DBG_err         0
66141cc406Sopenharmony_ci#define DBG_proc        10
67141cc406Sopenharmony_ci#define DBG_verbose     20
68141cc406Sopenharmony_ci#define DBG_details     30
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#define hp5590_assert(exp) if(!(exp)) { \
71141cc406Sopenharmony_ci        DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
72141cc406Sopenharmony_ci        return SANE_STATUS_INVAL; \
73141cc406Sopenharmony_ci}
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci#define hp5590_assert_void_return(exp) if(!(exp)) { \
76141cc406Sopenharmony_ci        DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
77141cc406Sopenharmony_ci        return; \
78141cc406Sopenharmony_ci}
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci#define MY_MIN(a, b) (((a) < (b)) ? (a) : (b))
81141cc406Sopenharmony_ci#define MY_MAX(a, b) (((a) > (b)) ? (a) : (b))
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci/* #define HAS_WORKING_COLOR_48 */
84141cc406Sopenharmony_ci#define BUILD           8
85141cc406Sopenharmony_ci#define USB_TIMEOUT     30 * 1000
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_cistatic SANE_Word
88141cc406Sopenharmony_cires_list[] = { 6, 100, 200, 300, 600, 1200, 2400 };
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_SOURCE_FLATBED          SANE_I18N("Flatbed")
91141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_SOURCE_ADF              SANE_I18N("ADF")
92141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX       SANE_I18N("ADF Duplex")
93141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES       SANE_I18N("TMA Slides")
94141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES    SANE_I18N("TMA Negatives")
95141cc406Sopenharmony_cistatic SANE_String_Const
96141cc406Sopenharmony_cisources_list[] = {
97141cc406Sopenharmony_ci  SANE_VALUE_SCAN_SOURCE_FLATBED,
98141cc406Sopenharmony_ci  SANE_VALUE_SCAN_SOURCE_ADF,
99141cc406Sopenharmony_ci  SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX,
100141cc406Sopenharmony_ci  SANE_VALUE_SCAN_SOURCE_TMA_SLIDES,
101141cc406Sopenharmony_ci  SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES,
102141cc406Sopenharmony_ci  NULL
103141cc406Sopenharmony_ci};
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_MODE_COLOR_24           SANE_VALUE_SCAN_MODE_COLOR
106141cc406Sopenharmony_ci#define SANE_VALUE_SCAN_MODE_COLOR_48           SANE_I18N("Color (48 bits)")
107141cc406Sopenharmony_ci#define HAS_WORKING_COLOR_48 1
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci#define SANE_NAME_LAMP_TIMEOUT                  "extend-lamp-timeout"
110141cc406Sopenharmony_ci#define SANE_TITLE_LAMP_TIMEOUT                 SANE_I18N("Extend lamp timeout")
111141cc406Sopenharmony_ci#define SANE_DESC_LAMP_TIMEOUT                  SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)")
112141cc406Sopenharmony_ci#define SANE_NAME_WAIT_FOR_BUTTON               "wait-for-button"
113141cc406Sopenharmony_ci#define SANE_TITLE_WAIT_FOR_BUTTON              SANE_I18N("Wait for button")
114141cc406Sopenharmony_ci#define SANE_DESC_WAIT_FOR_BUTTON               SANE_I18N("Waits for button before scanning")
115141cc406Sopenharmony_ci#define SANE_NAME_BUTTON_PRESSED                "button-pressed"
116141cc406Sopenharmony_ci#define SANE_TITLE_BUTTON_PRESSED               SANE_I18N("Last button pressed")
117141cc406Sopenharmony_ci#define SANE_DESC_BUTTON_PRESSED                SANE_I18N("Get ID of last button pressed (read only)")
118141cc406Sopenharmony_ci#define SANE_NAME_LCD_COUNTER                   "counter-value"
119141cc406Sopenharmony_ci#define SANE_TITLE_LCD_COUNTER                  SANE_I18N("LCD counter")
120141cc406Sopenharmony_ci#define SANE_DESC_LCD_COUNTER                   SANE_I18N("Get value of LCD counter (read only)")
121141cc406Sopenharmony_ci#define SANE_NAME_COLOR_LED                     "color-led"
122141cc406Sopenharmony_ci#define SANE_TITLE_COLOR_LED                    SANE_I18N("Color LED indicator")
123141cc406Sopenharmony_ci#define SANE_DESC_COLOR_LED                     SANE_I18N("Get value of LED indicator (read only)")
124141cc406Sopenharmony_ci#define SANE_NAME_DOC_IN_ADF                    "doc-in-adf"
125141cc406Sopenharmony_ci#define SANE_TITLE_DOC_IN_ADF                   SANE_I18N("Document available in ADF")
126141cc406Sopenharmony_ci#define SANE_DESC_DOC_IN_ADF                    SANE_I18N("Get state of document-available indicator in ADF (read only)")
127141cc406Sopenharmony_ci#define SANE_NAME_OVERWRITE_EOP_PIXEL           "hide-eop-pixel"
128141cc406Sopenharmony_ci#define SANE_TITLE_OVERWRITE_EOP_PIXEL          SANE_I18N("Hide end-of-page pixel")
129141cc406Sopenharmony_ci#define SANE_DESC_OVERWRITE_EOP_PIXEL           SANE_I18N("Hide end-of-page indicator pixels and overwrite with neighbor pixels")
130141cc406Sopenharmony_ci#define SANE_NAME_TRAILING_LINES_MODE           "trailing-lines-mode"
131141cc406Sopenharmony_ci#define SANE_TITLE_TRAILING_LINES_MODE          SANE_I18N("Filling mode of trailing lines after scan data (ADF)")
132141cc406Sopenharmony_ci#define SANE_DESC_TRAILING_LINES_MODE           SANE_I18N("raw = raw scan data, last = repeat last scan line, raster = b/w raster, "\
133141cc406Sopenharmony_ci                                                          "white = white color, black = black color, color = RGB or gray color value")
134141cc406Sopenharmony_ci#define SANE_NAME_TRAILING_LINES_COLOR          "trailing-lines-color"
135141cc406Sopenharmony_ci#define SANE_TITLE_TRAILING_LINES_COLOR         SANE_I18N("RGB or gray color value for filling mode 'color'")
136141cc406Sopenharmony_ci#define SANE_DESC_TRAILING_LINES_COLOR          SANE_I18N("Color value for trailing lines filling mode 'color'. "\
137141cc406Sopenharmony_ci                                                          "RGB color as r*65536+256*g+b or gray value (default=violet or gray)")
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_COUNT 11
140141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_NONE_KEY "none"
141141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_POWER_KEY "power"
142141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_SCAN_KEY "scan"
143141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_COLLECT_KEY "collect"
144141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_FILE_KEY "file"
145141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_EMAIL_KEY "email"
146141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_COPY_KEY "copy"
147141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_UP_KEY "up"
148141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_DOWN_KEY "down"
149141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_MODE_KEY "mode"
150141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_CANCEL_KEY "cancel"
151141cc406Sopenharmony_ci#define BUTTON_PRESSED_VALUE_MAX_KEY_LEN 32
152141cc406Sopenharmony_cistatic SANE_String_Const
153141cc406Sopenharmony_cibuttonstate_list[] = {
154141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_NONE_KEY,
155141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_POWER_KEY,
156141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_SCAN_KEY,
157141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_COLLECT_KEY,
158141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_FILE_KEY,
159141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_EMAIL_KEY,
160141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_COPY_KEY,
161141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_UP_KEY,
162141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_DOWN_KEY,
163141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_MODE_KEY,
164141cc406Sopenharmony_ci  BUTTON_PRESSED_VALUE_CANCEL_KEY,
165141cc406Sopenharmony_ci  NULL
166141cc406Sopenharmony_ci};
167141cc406Sopenharmony_ci
168141cc406Sopenharmony_ci#define COLOR_LED_VALUE_COUNT 2
169141cc406Sopenharmony_ci#define COLOR_LED_VALUE_COLOR_KEY "color"
170141cc406Sopenharmony_ci#define COLOR_LED_VALUE_BLACKWHITE_KEY "black_white"
171141cc406Sopenharmony_ci#define COLOR_LED_VALUE_MAX_KEY_LEN 32
172141cc406Sopenharmony_cistatic SANE_String_Const
173141cc406Sopenharmony_cicolorledstate_list[] = {
174141cc406Sopenharmony_ci  COLOR_LED_VALUE_COLOR_KEY,
175141cc406Sopenharmony_ci  COLOR_LED_VALUE_BLACKWHITE_KEY,
176141cc406Sopenharmony_ci  NULL
177141cc406Sopenharmony_ci};
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci#define LCD_COUNTER_VALUE_MIN 1
180141cc406Sopenharmony_ci#define LCD_COUNTER_VALUE_MAX 99
181141cc406Sopenharmony_ci#define LCD_COUNTER_VALUE_QUANT 1
182141cc406Sopenharmony_cistatic SANE_Range
183141cc406Sopenharmony_cilcd_counter_range = {
184141cc406Sopenharmony_ci  LCD_COUNTER_VALUE_MIN,
185141cc406Sopenharmony_ci  LCD_COUNTER_VALUE_MAX,
186141cc406Sopenharmony_ci  LCD_COUNTER_VALUE_QUANT
187141cc406Sopenharmony_ci};
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_RAW 0
190141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_LAST 1
191141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_RASTER 2
192141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_WHITE 3
193141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_BLACK 4
194141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_COLOR 5
195141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_VALUE_COUNT 6
196141cc406Sopenharmony_ci
197141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_RAW_KEY "raw"
198141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_LAST_KEY "last"
199141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_RASTER_KEY "raster"
200141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_WHITE_KEY "white"
201141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_BLACK_KEY "black"
202141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_COLOR_KEY "color"
203141cc406Sopenharmony_ci#define TRAILING_LINES_MODE_MAX_KEY_LEN 24
204141cc406Sopenharmony_cistatic SANE_String_Const
205141cc406Sopenharmony_citrailingmode_list[] = {
206141cc406Sopenharmony_ci  TRAILING_LINES_MODE_RAW_KEY,
207141cc406Sopenharmony_ci  TRAILING_LINES_MODE_LAST_KEY,
208141cc406Sopenharmony_ci  TRAILING_LINES_MODE_RASTER_KEY,
209141cc406Sopenharmony_ci  TRAILING_LINES_MODE_WHITE_KEY,
210141cc406Sopenharmony_ci  TRAILING_LINES_MODE_BLACK_KEY,
211141cc406Sopenharmony_ci  TRAILING_LINES_MODE_COLOR_KEY,
212141cc406Sopenharmony_ci  NULL
213141cc406Sopenharmony_ci};
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci#define MAX_SCAN_SOURCE_VALUE_LEN       24
216141cc406Sopenharmony_ci#define MAX_SCAN_MODE_VALUE_LEN         24
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_cistatic SANE_Range
219141cc406Sopenharmony_cirange_x, range_y, range_qual;
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_cistatic SANE_String_Const
222141cc406Sopenharmony_cimode_list[] = {
223141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR_24,
224141cc406Sopenharmony_ci#ifdef HAS_WORKING_COLOR_48
225141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR_48,
226141cc406Sopenharmony_ci#endif /* HAS_WORKING_COLOR_48 */
227141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
228141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
229141cc406Sopenharmony_ci  NULL
230141cc406Sopenharmony_ci};
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_cienum hp5590_opt_idx {
233141cc406Sopenharmony_ci  HP5590_OPT_NUM = 0,
234141cc406Sopenharmony_ci  HP5590_OPT_TL_X,
235141cc406Sopenharmony_ci  HP5590_OPT_TL_Y,
236141cc406Sopenharmony_ci  HP5590_OPT_BR_X,
237141cc406Sopenharmony_ci  HP5590_OPT_BR_Y,
238141cc406Sopenharmony_ci  HP5590_OPT_MODE,
239141cc406Sopenharmony_ci  HP5590_OPT_SOURCE,
240141cc406Sopenharmony_ci  HP5590_OPT_RESOLUTION,
241141cc406Sopenharmony_ci  HP5590_OPT_LAMP_TIMEOUT,
242141cc406Sopenharmony_ci  HP5590_OPT_WAIT_FOR_BUTTON,
243141cc406Sopenharmony_ci  HP5590_OPT_BUTTON_PRESSED,
244141cc406Sopenharmony_ci  HP5590_OPT_COLOR_LED,
245141cc406Sopenharmony_ci  HP5590_OPT_LCD_COUNTER,
246141cc406Sopenharmony_ci  HP5590_OPT_DOC_IN_ADF,
247141cc406Sopenharmony_ci  HP5590_OPT_PREVIEW,
248141cc406Sopenharmony_ci  HP5590_OPT_OVERWRITE_EOP_PIXEL,
249141cc406Sopenharmony_ci  HP5590_OPT_TRAILING_LINES_MODE,
250141cc406Sopenharmony_ci  HP5590_OPT_TRAILING_LINES_COLOR,
251141cc406Sopenharmony_ci  HP5590_OPT_LAST
252141cc406Sopenharmony_ci};
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_cistruct hp5590_scanner {
255141cc406Sopenharmony_ci  struct scanner_info           *info;
256141cc406Sopenharmony_ci  enum proto_flags              proto_flags;
257141cc406Sopenharmony_ci  SANE_Device                   sane;
258141cc406Sopenharmony_ci  SANE_Int                      dn;
259141cc406Sopenharmony_ci  float                         br_x, br_y, tl_x, tl_y;
260141cc406Sopenharmony_ci  unsigned int                  dpi;
261141cc406Sopenharmony_ci  enum color_depths             depth;
262141cc406Sopenharmony_ci  enum scan_sources             source;
263141cc406Sopenharmony_ci  SANE_Bool                     extend_lamp_timeout;
264141cc406Sopenharmony_ci  SANE_Bool                     wait_for_button;
265141cc406Sopenharmony_ci  SANE_Bool                     preview;
266141cc406Sopenharmony_ci  unsigned int                  quality;
267141cc406Sopenharmony_ci  SANE_Option_Descriptor        *opts;
268141cc406Sopenharmony_ci  struct hp5590_scanner         *next;
269141cc406Sopenharmony_ci  unsigned long long            image_size;
270141cc406Sopenharmony_ci  unsigned long long            transferred_image_size;
271141cc406Sopenharmony_ci  void                          *bulk_read_state;
272141cc406Sopenharmony_ci  SANE_Bool                     scanning;
273141cc406Sopenharmony_ci  SANE_Bool                     overwrite_eop_pixel;
274141cc406Sopenharmony_ci  SANE_Byte                     *eop_last_line_data;
275141cc406Sopenharmony_ci  unsigned int                  eop_last_line_data_rpos;
276141cc406Sopenharmony_ci  SANE_Int                      eop_trailing_lines_mode;
277141cc406Sopenharmony_ci  SANE_Int                      eop_trailing_lines_color;
278141cc406Sopenharmony_ci  SANE_Byte                     *adf_next_page_lines_data;
279141cc406Sopenharmony_ci  unsigned int                  adf_next_page_lines_data_size;
280141cc406Sopenharmony_ci  unsigned int                  adf_next_page_lines_data_rpos;
281141cc406Sopenharmony_ci  unsigned int                  adf_next_page_lines_data_wpos;
282141cc406Sopenharmony_ci  SANE_Byte                     *one_line_read_buffer;
283141cc406Sopenharmony_ci  unsigned int                  one_line_read_buffer_rpos;
284141cc406Sopenharmony_ci  SANE_Byte                     *color_shift_line_buffer1;
285141cc406Sopenharmony_ci  unsigned int                  color_shift_buffered_lines1;
286141cc406Sopenharmony_ci  SANE_Byte                     *color_shift_line_buffer2;
287141cc406Sopenharmony_ci  unsigned int                  color_shift_buffered_lines2;
288141cc406Sopenharmony_ci};
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_cistatic
291141cc406Sopenharmony_cistruct hp5590_scanner *scanners_list;
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci/******************************************************************************/
294141cc406Sopenharmony_cistatic SANE_Status
295141cc406Sopenharmony_cicalc_image_params (struct hp5590_scanner *scanner,
296141cc406Sopenharmony_ci                   unsigned int *pixel_bits,
297141cc406Sopenharmony_ci                   unsigned int *pixels_per_line,
298141cc406Sopenharmony_ci                   unsigned int *bytes_per_line,
299141cc406Sopenharmony_ci                   unsigned int *lines,
300141cc406Sopenharmony_ci                   unsigned long long *image_size)
301141cc406Sopenharmony_ci{
302141cc406Sopenharmony_ci  unsigned int  _pixel_bits;
303141cc406Sopenharmony_ci  SANE_Status   ret;
304141cc406Sopenharmony_ci  unsigned int  _pixels_per_line;
305141cc406Sopenharmony_ci  unsigned int  _bytes_per_line;
306141cc406Sopenharmony_ci  unsigned int  _lines;
307141cc406Sopenharmony_ci  unsigned int  _image_size;
308141cc406Sopenharmony_ci  float         var;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  if (!scanner)
313141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  ret = hp5590_calc_pixel_bits (scanner->dpi, scanner->depth, &_pixel_bits);
316141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
317141cc406Sopenharmony_ci    return ret;
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci  var = (float) (1.0 * (scanner->br_x - scanner->tl_x) * scanner->dpi);
320141cc406Sopenharmony_ci  _pixels_per_line = var;
321141cc406Sopenharmony_ci  if (var > _pixels_per_line)
322141cc406Sopenharmony_ci    _pixels_per_line++;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci  var  = (float) (1.0 * (scanner->br_y - scanner->tl_y) * scanner->dpi);
325141cc406Sopenharmony_ci  _lines = var;
326141cc406Sopenharmony_ci  if (var > _lines)
327141cc406Sopenharmony_ci    _lines++;
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci  var  = (float) (1.0 * _pixels_per_line / 8 * _pixel_bits);
330141cc406Sopenharmony_ci  _bytes_per_line  = var;
331141cc406Sopenharmony_ci  if (var > _bytes_per_line)
332141cc406Sopenharmony_ci    _bytes_per_line++;
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ci  _image_size      = (unsigned long long) _lines * _bytes_per_line;
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: pixel_bits: %u, pixels_per_line: %u, "
337141cc406Sopenharmony_ci       "bytes_per_line: %u, lines: %u, image_size: %u\n",
338141cc406Sopenharmony_ci       __func__,
339141cc406Sopenharmony_ci       _pixel_bits, _pixels_per_line, _bytes_per_line, _lines, _image_size);
340141cc406Sopenharmony_ci
341141cc406Sopenharmony_ci  if (pixel_bits)
342141cc406Sopenharmony_ci    *pixel_bits = _pixel_bits;
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci  if (pixels_per_line)
345141cc406Sopenharmony_ci    *pixels_per_line = _pixels_per_line;
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci  if (bytes_per_line)
348141cc406Sopenharmony_ci    *bytes_per_line = _bytes_per_line;
349141cc406Sopenharmony_ci
350141cc406Sopenharmony_ci  if (lines)
351141cc406Sopenharmony_ci    *lines = _lines;
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci  if (image_size)
354141cc406Sopenharmony_ci    *image_size = _image_size;
355141cc406Sopenharmony_ci
356141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
357141cc406Sopenharmony_ci}
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci/******************************************************************************/
360141cc406Sopenharmony_cistatic SANE_Status
361141cc406Sopenharmony_ciattach_usb_device (SANE_String_Const devname,
362141cc406Sopenharmony_ci                   enum hp_scanner_types hp_scanner_type)
363141cc406Sopenharmony_ci{
364141cc406Sopenharmony_ci  struct scanner_info           *info;
365141cc406Sopenharmony_ci  struct hp5590_scanner         *scanner, *ptr;
366141cc406Sopenharmony_ci  unsigned int                  max_count, count;
367141cc406Sopenharmony_ci  SANE_Int                      dn;
368141cc406Sopenharmony_ci  SANE_Status                   ret;
369141cc406Sopenharmony_ci  const struct hp5590_model     *hp5590_model;
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci  DBG (DBG_proc, "%s: Opening USB device\n", __func__);
372141cc406Sopenharmony_ci  if (sanei_usb_open (devname, &dn) != SANE_STATUS_GOOD)
373141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
374141cc406Sopenharmony_ci  DBG (DBG_proc, "%s: USB device opened\n", __func__);
375141cc406Sopenharmony_ci
376141cc406Sopenharmony_ci  ret = hp5590_model_def (hp_scanner_type, &hp5590_model);
377141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
378141cc406Sopenharmony_ci    return ret;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  if (hp5590_init_scanner (dn, hp5590_model->proto_flags,
381141cc406Sopenharmony_ci                           &info, hp_scanner_type) != 0)
382141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  DBG (1, "%s: found HP%s scanner at '%s'\n",
385141cc406Sopenharmony_ci       __func__, info->model, devname);
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Reading max scan count\n", __func__);
388141cc406Sopenharmony_ci  if (hp5590_read_max_scan_count (dn, hp5590_model->proto_flags,
389141cc406Sopenharmony_ci                                  &max_count) != 0)
390141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
391141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Max Scanning count %u\n", __func__, max_count);
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Reading scan count\n", __func__);
394141cc406Sopenharmony_ci  if (hp5590_read_scan_count (dn, hp5590_model->proto_flags,
395141cc406Sopenharmony_ci                              &count) != 0)
396141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
397141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Scanning count %u\n", __func__, count);
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci  ret = hp5590_read_part_number (dn, hp5590_model->proto_flags);
400141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
401141cc406Sopenharmony_ci    return ret;
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci  ret = hp5590_stop_scan (dn, hp5590_model->proto_flags);
404141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
405141cc406Sopenharmony_ci    return ret;
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci  scanner = malloc (sizeof(struct hp5590_scanner));
408141cc406Sopenharmony_ci  if (!scanner)
409141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
410141cc406Sopenharmony_ci  memset (scanner, 0, sizeof(struct hp5590_scanner));
411141cc406Sopenharmony_ci
412141cc406Sopenharmony_ci  scanner->sane.model = info->model;
413141cc406Sopenharmony_ci  scanner->sane.vendor = "HP";
414141cc406Sopenharmony_ci  scanner->sane.type = info->kind;
415141cc406Sopenharmony_ci  scanner->sane.name = devname;
416141cc406Sopenharmony_ci  scanner->dn = dn;
417141cc406Sopenharmony_ci  scanner->proto_flags = hp5590_model->proto_flags;
418141cc406Sopenharmony_ci  scanner->info = info;
419141cc406Sopenharmony_ci  scanner->bulk_read_state = NULL;
420141cc406Sopenharmony_ci  scanner->opts = NULL;
421141cc406Sopenharmony_ci  scanner->eop_last_line_data = NULL;
422141cc406Sopenharmony_ci  scanner->eop_last_line_data_rpos = 0;
423141cc406Sopenharmony_ci  scanner->adf_next_page_lines_data = NULL;
424141cc406Sopenharmony_ci  scanner->adf_next_page_lines_data_size = 0;
425141cc406Sopenharmony_ci  scanner->adf_next_page_lines_data_rpos = 0;
426141cc406Sopenharmony_ci  scanner->adf_next_page_lines_data_wpos = 0;
427141cc406Sopenharmony_ci  scanner->one_line_read_buffer = NULL;
428141cc406Sopenharmony_ci  scanner->one_line_read_buffer_rpos = 0;
429141cc406Sopenharmony_ci  scanner->color_shift_line_buffer1 = NULL;
430141cc406Sopenharmony_ci  scanner->color_shift_buffered_lines1 = 0;
431141cc406Sopenharmony_ci  scanner->color_shift_line_buffer2 = NULL;
432141cc406Sopenharmony_ci  scanner->color_shift_buffered_lines2 = 0;
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci  if (!scanners_list)
435141cc406Sopenharmony_ci    scanners_list = scanner;
436141cc406Sopenharmony_ci  else
437141cc406Sopenharmony_ci    {
438141cc406Sopenharmony_ci      for (ptr = scanners_list; ptr->next; ptr = ptr->next);
439141cc406Sopenharmony_ci      ptr->next = scanner;
440141cc406Sopenharmony_ci    }
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
443141cc406Sopenharmony_ci}
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci/******************************************************************************/
446141cc406Sopenharmony_cistatic SANE_Status
447141cc406Sopenharmony_ciattach_hp4570 (SANE_String_Const devname)
448141cc406Sopenharmony_ci{
449141cc406Sopenharmony_ci  return attach_usb_device (devname, SCANNER_HP4570);
450141cc406Sopenharmony_ci}
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci/******************************************************************************/
453141cc406Sopenharmony_cistatic SANE_Status
454141cc406Sopenharmony_ciattach_hp5550 (SANE_String_Const devname)
455141cc406Sopenharmony_ci{
456141cc406Sopenharmony_ci  return attach_usb_device (devname, SCANNER_HP5550);
457141cc406Sopenharmony_ci}
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci/******************************************************************************/
460141cc406Sopenharmony_cistatic SANE_Status
461141cc406Sopenharmony_ciattach_hp5590 (SANE_String_Const devname)
462141cc406Sopenharmony_ci{
463141cc406Sopenharmony_ci  return attach_usb_device (devname, SCANNER_HP5590);
464141cc406Sopenharmony_ci}
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci/******************************************************************************/
467141cc406Sopenharmony_cistatic SANE_Status
468141cc406Sopenharmony_ciattach_hp7650 (SANE_String_Const devname)
469141cc406Sopenharmony_ci{
470141cc406Sopenharmony_ci  return attach_usb_device (devname, SCANNER_HP7650);
471141cc406Sopenharmony_ci}
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci/******************************************************************************/
474141cc406Sopenharmony_ciSANE_Status
475141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
476141cc406Sopenharmony_ci{
477141cc406Sopenharmony_ci  SANE_Status   ret;
478141cc406Sopenharmony_ci  SANE_Word     vendor_id, product_id;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci  DBG_INIT();
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci  DBG (1, "SANE backed for HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 %u.%u.%u\n",
483141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
484141cc406Sopenharmony_ci  DBG (1, "(c) Ilia Sotnikov <hostcc@gmail.com>\n");
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci  if (version_code)
487141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
488141cc406Sopenharmony_ci
489141cc406Sopenharmony_ci  sanei_usb_init();
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci  sanei_usb_set_timeout (USB_TIMEOUT);
492141cc406Sopenharmony_ci
493141cc406Sopenharmony_ci  scanners_list = NULL;
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci  ret = hp5590_vendor_product_id (SCANNER_HP4570, &vendor_id, &product_id);
496141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
497141cc406Sopenharmony_ci    return ret;
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci  ret = sanei_usb_find_devices (vendor_id, product_id, attach_hp4570);
500141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
501141cc406Sopenharmony_ci    return ret;
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci  ret = hp5590_vendor_product_id (SCANNER_HP5550, &vendor_id, &product_id);
504141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
505141cc406Sopenharmony_ci    return ret;
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  ret = sanei_usb_find_devices (vendor_id, product_id, attach_hp5550);
508141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
509141cc406Sopenharmony_ci    return ret;
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci  ret = hp5590_vendor_product_id (SCANNER_HP5590, &vendor_id, &product_id);
512141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
513141cc406Sopenharmony_ci    return ret;
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci  ret = sanei_usb_find_devices (vendor_id, product_id, attach_hp5590);
516141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
517141cc406Sopenharmony_ci    return ret;
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  ret = hp5590_vendor_product_id (SCANNER_HP7650, &vendor_id, &product_id);
520141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
521141cc406Sopenharmony_ci    return ret;
522141cc406Sopenharmony_ci
523141cc406Sopenharmony_ci  ret = sanei_usb_find_devices (vendor_id, product_id, attach_hp7650);
524141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
525141cc406Sopenharmony_ci    return ret;
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
528141cc406Sopenharmony_ci}
529141cc406Sopenharmony_ci
530141cc406Sopenharmony_ci/******************************************************************************/
531141cc406Sopenharmony_civoid sane_exit (void)
532141cc406Sopenharmony_ci{
533141cc406Sopenharmony_ci  struct hp5590_scanner *ptr, *pnext;
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci  for (ptr = scanners_list; ptr; ptr = pnext)
538141cc406Sopenharmony_ci    {
539141cc406Sopenharmony_ci      if (ptr->opts != NULL)
540141cc406Sopenharmony_ci        free (ptr->opts);
541141cc406Sopenharmony_ci      if (ptr->eop_last_line_data != NULL) {
542141cc406Sopenharmony_ci        free (ptr->eop_last_line_data);
543141cc406Sopenharmony_ci        ptr->eop_last_line_data = NULL;
544141cc406Sopenharmony_ci        ptr->eop_last_line_data_rpos = 0;
545141cc406Sopenharmony_ci      }
546141cc406Sopenharmony_ci      if (ptr->adf_next_page_lines_data != NULL) {
547141cc406Sopenharmony_ci        free (ptr->adf_next_page_lines_data);
548141cc406Sopenharmony_ci        ptr->adf_next_page_lines_data = NULL;
549141cc406Sopenharmony_ci        ptr->adf_next_page_lines_data_size = 0;
550141cc406Sopenharmony_ci        ptr->adf_next_page_lines_data_wpos = 0;
551141cc406Sopenharmony_ci        ptr->adf_next_page_lines_data_rpos = 0;
552141cc406Sopenharmony_ci      }
553141cc406Sopenharmony_ci      if (ptr->one_line_read_buffer != NULL) {
554141cc406Sopenharmony_ci        free (ptr->one_line_read_buffer);
555141cc406Sopenharmony_ci        ptr->one_line_read_buffer = NULL;
556141cc406Sopenharmony_ci        ptr->one_line_read_buffer_rpos = 0;
557141cc406Sopenharmony_ci      }
558141cc406Sopenharmony_ci      if (ptr->color_shift_line_buffer1 != NULL) {
559141cc406Sopenharmony_ci        free (ptr->color_shift_line_buffer1);
560141cc406Sopenharmony_ci        ptr->color_shift_line_buffer1 = NULL;
561141cc406Sopenharmony_ci        ptr->color_shift_buffered_lines1 = 0;
562141cc406Sopenharmony_ci      }
563141cc406Sopenharmony_ci      if (ptr->color_shift_line_buffer2 != NULL) {
564141cc406Sopenharmony_ci        free (ptr->color_shift_line_buffer2);
565141cc406Sopenharmony_ci        ptr->color_shift_line_buffer2 = NULL;
566141cc406Sopenharmony_ci        ptr->color_shift_buffered_lines2 = 0;
567141cc406Sopenharmony_ci      }
568141cc406Sopenharmony_ci      pnext = ptr->next;
569141cc406Sopenharmony_ci      free (ptr);
570141cc406Sopenharmony_ci    }
571141cc406Sopenharmony_ci}
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci/******************************************************************************/
574141cc406Sopenharmony_ciSANE_Status
575141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
576141cc406Sopenharmony_ci{
577141cc406Sopenharmony_ci  struct hp5590_scanner *ptr;
578141cc406Sopenharmony_ci  unsigned int found, i;
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci  DBG (DBG_proc, "%s, local only: %u\n", __func__, local_only);
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci  if (!device_list)
583141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci  for (found = 0, ptr = scanners_list; ptr; found++, ptr = ptr->next);
586141cc406Sopenharmony_ci  DBG (1, "Found %u devices\n", found);
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_ci  found++;
589141cc406Sopenharmony_ci  *device_list = malloc (found * sizeof (SANE_Device));
590141cc406Sopenharmony_ci  if (!*device_list)
591141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
592141cc406Sopenharmony_ci  memset (*device_list, 0, found * sizeof(SANE_Device));
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci  for (i = 0, ptr = scanners_list; ptr; i++, ptr = ptr->next)
595141cc406Sopenharmony_ci    {
596141cc406Sopenharmony_ci      (*device_list)[i] = &(ptr->sane);
597141cc406Sopenharmony_ci    }
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
600141cc406Sopenharmony_ci}
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci/******************************************************************************/
603141cc406Sopenharmony_ciSANE_Status
604141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
605141cc406Sopenharmony_ci{
606141cc406Sopenharmony_ci  struct hp5590_scanner         *ptr;
607141cc406Sopenharmony_ci  SANE_Option_Descriptor        *opts;
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci  DBG (DBG_proc, "%s: device name: %s\n", __func__, devicename);
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  if (!handle)
612141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci  /* Allow to open the first available device by specifying zero-length name */
615141cc406Sopenharmony_ci  if (!devicename || !devicename[0]) {
616141cc406Sopenharmony_ci    ptr = scanners_list;
617141cc406Sopenharmony_ci  } else {
618141cc406Sopenharmony_ci    for (ptr = scanners_list;
619141cc406Sopenharmony_ci         ptr && strcmp (ptr->sane.name, devicename) != 0;
620141cc406Sopenharmony_ci         ptr = ptr->next);
621141cc406Sopenharmony_ci  }
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci  if (!ptr)
624141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci  /* DS: Without this after the first scan (and sane_close)
627141cc406Sopenharmony_ci   * it was impossible to use again the read_buttons usb routine.
628141cc406Sopenharmony_ci   * Function sane_close puts dn = -1. Now sane_open needs to open
629141cc406Sopenharmony_ci   * the usb communication again.
630141cc406Sopenharmony_ci   */
631141cc406Sopenharmony_ci  if (ptr->dn < 0) {
632141cc406Sopenharmony_ci    DBG (DBG_proc, "%s: Reopening USB device\n", __func__);
633141cc406Sopenharmony_ci    if (sanei_usb_open (ptr->sane.name, &ptr->dn) != SANE_STATUS_GOOD)
634141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
635141cc406Sopenharmony_ci    DBG (DBG_proc, "%s: USB device reopened\n", __func__);
636141cc406Sopenharmony_ci  }
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci  ptr->tl_x = 0;
639141cc406Sopenharmony_ci  ptr->tl_y = 0;
640141cc406Sopenharmony_ci  ptr->br_x = ptr->info->max_size_x;
641141cc406Sopenharmony_ci  ptr->br_y = ptr->info->max_size_y;
642141cc406Sopenharmony_ci  ptr->dpi = res_list[1];
643141cc406Sopenharmony_ci  ptr->depth = DEPTH_BW;
644141cc406Sopenharmony_ci  ptr->source = SOURCE_FLATBED;
645141cc406Sopenharmony_ci  ptr->extend_lamp_timeout = SANE_FALSE;
646141cc406Sopenharmony_ci  ptr->wait_for_button = SANE_FALSE;
647141cc406Sopenharmony_ci  ptr->preview = SANE_FALSE;
648141cc406Sopenharmony_ci  ptr->quality = 4;
649141cc406Sopenharmony_ci  ptr->image_size = 0;
650141cc406Sopenharmony_ci  ptr->scanning = SANE_FALSE;
651141cc406Sopenharmony_ci  ptr->overwrite_eop_pixel = SANE_TRUE;
652141cc406Sopenharmony_ci  ptr->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST;
653141cc406Sopenharmony_ci  ptr->eop_trailing_lines_color = 0x7f007f;
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci  *handle = ptr;
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci  opts = malloc (sizeof (SANE_Option_Descriptor) * HP5590_OPT_LAST);
658141cc406Sopenharmony_ci  if (!opts)
659141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].name = SANE_NAME_NUM_OPTIONS;
662141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].title = SANE_TITLE_NUM_OPTIONS;
663141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].desc = SANE_DESC_NUM_OPTIONS;
664141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].type = SANE_TYPE_INT;
665141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].unit = SANE_UNIT_NONE;
666141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].size = sizeof(SANE_Word);
667141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].cap =  SANE_CAP_INACTIVE | SANE_CAP_SOFT_DETECT;
668141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].constraint_type = SANE_CONSTRAINT_NONE;
669141cc406Sopenharmony_ci  opts[HP5590_OPT_NUM].constraint.string_list = NULL;
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci  range_x.min = SANE_FIX(0);
672141cc406Sopenharmony_ci  range_x.max = SANE_FIX(ptr->info->max_size_x * 25.4);
673141cc406Sopenharmony_ci  range_x.quant = SANE_FIX(0.1);
674141cc406Sopenharmony_ci  range_y.min = SANE_FIX(0);
675141cc406Sopenharmony_ci  range_y.max = SANE_FIX(ptr->info->max_size_y * 25.4);
676141cc406Sopenharmony_ci  range_y.quant = SANE_FIX(0.1);
677141cc406Sopenharmony_ci
678141cc406Sopenharmony_ci  range_qual.min = SANE_FIX(4);
679141cc406Sopenharmony_ci  range_qual.max = SANE_FIX(16);
680141cc406Sopenharmony_ci  range_qual.quant = SANE_FIX(1);
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
683141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
684141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
685141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].type = SANE_TYPE_FIXED;
686141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].unit = SANE_UNIT_MM;
687141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].size = sizeof(SANE_Fixed);
688141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
689141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
690141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_X].constraint.range = &range_x;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
693141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
694141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
695141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].type = SANE_TYPE_FIXED;
696141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].unit = SANE_UNIT_MM;
697141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].size = sizeof(SANE_Fixed);
698141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
699141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
700141cc406Sopenharmony_ci  opts[HP5590_OPT_TL_Y].constraint.range = &range_y;
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
703141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
704141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
705141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].type = SANE_TYPE_FIXED;
706141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].unit = SANE_UNIT_MM;
707141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].size = sizeof(SANE_Fixed);
708141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
709141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
710141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_X].constraint.range = &range_x;
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
713141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
714141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
715141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].type = SANE_TYPE_FIXED;
716141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].unit = SANE_UNIT_MM;
717141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].size = sizeof(SANE_Fixed);
718141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
719141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
720141cc406Sopenharmony_ci  opts[HP5590_OPT_BR_Y].constraint.range = &range_y;
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].name = SANE_NAME_SCAN_MODE;
723141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].title = SANE_TITLE_SCAN_MODE;
724141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].desc = SANE_DESC_SCAN_MODE;
725141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].type = SANE_TYPE_STRING;
726141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].unit = SANE_UNIT_NONE;
727141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].size = MAX_SCAN_MODE_VALUE_LEN;
728141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
729141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
730141cc406Sopenharmony_ci  opts[HP5590_OPT_MODE].constraint.string_list = mode_list;
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci  /* Show all features, check on feature in command line evaluation. */
733141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
734141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
735141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
736141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].type = SANE_TYPE_STRING;
737141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].unit = SANE_UNIT_NONE;
738141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].size = MAX_SCAN_SOURCE_VALUE_LEN;
739141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
740141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
741141cc406Sopenharmony_ci  opts[HP5590_OPT_SOURCE].constraint.string_list = sources_list;
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
744141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
745141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
746141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].type = SANE_TYPE_INT;
747141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].unit = SANE_UNIT_DPI;
748141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].size = sizeof(SANE_Int);
749141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
750141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
751141cc406Sopenharmony_ci  opts[HP5590_OPT_RESOLUTION].constraint.word_list = res_list;
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].name = SANE_NAME_LAMP_TIMEOUT;
754141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].title = SANE_TITLE_LAMP_TIMEOUT;
755141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].desc = SANE_DESC_LAMP_TIMEOUT;
756141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].type = SANE_TYPE_BOOL;
757141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE;
758141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].size = sizeof(SANE_Bool);
759141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
760141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_NONE;
761141cc406Sopenharmony_ci  opts[HP5590_OPT_LAMP_TIMEOUT].constraint.string_list = NULL;
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].name = SANE_NAME_WAIT_FOR_BUTTON;
764141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].title = SANE_TITLE_WAIT_FOR_BUTTON;
765141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].desc = SANE_DESC_WAIT_FOR_BUTTON;
766141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].type = SANE_TYPE_BOOL;
767141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].unit = SANE_UNIT_NONE;
768141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].size = sizeof(SANE_Bool);
769141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
770141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE;
771141cc406Sopenharmony_ci  opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint.string_list = NULL;
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].name = SANE_NAME_BUTTON_PRESSED;
774141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].title = SANE_TITLE_BUTTON_PRESSED;
775141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].desc = SANE_DESC_BUTTON_PRESSED;
776141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].type = SANE_TYPE_STRING;
777141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].unit = SANE_UNIT_NONE;
778141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].size = BUTTON_PRESSED_VALUE_MAX_KEY_LEN;
779141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
780141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
781141cc406Sopenharmony_ci  opts[HP5590_OPT_BUTTON_PRESSED].constraint.string_list = buttonstate_list;
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].name = SANE_NAME_COLOR_LED;
784141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].title = SANE_TITLE_COLOR_LED;
785141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].desc = SANE_DESC_COLOR_LED;
786141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].type = SANE_TYPE_STRING;
787141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].unit = SANE_UNIT_NONE;
788141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].size = COLOR_LED_VALUE_MAX_KEY_LEN;
789141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
790141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
791141cc406Sopenharmony_ci  opts[HP5590_OPT_COLOR_LED].constraint.string_list = colorledstate_list;
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].name = SANE_NAME_LCD_COUNTER;
794141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].title = SANE_TITLE_LCD_COUNTER;
795141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].desc = SANE_DESC_LCD_COUNTER;
796141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].type = SANE_TYPE_INT;
797141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].unit = SANE_UNIT_NONE;
798141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].size = sizeof(SANE_Int);
799141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
800141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].constraint_type = SANE_CONSTRAINT_RANGE;
801141cc406Sopenharmony_ci  opts[HP5590_OPT_LCD_COUNTER].constraint.range = &lcd_counter_range;
802141cc406Sopenharmony_ci
803141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].name = SANE_NAME_DOC_IN_ADF;
804141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].title = SANE_TITLE_DOC_IN_ADF;
805141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].desc = SANE_DESC_DOC_IN_ADF;
806141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].type = SANE_TYPE_BOOL;
807141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].unit = SANE_UNIT_NONE;
808141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].size = sizeof(SANE_Bool);
809141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].cap =  SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
810141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].constraint_type = SANE_CONSTRAINT_NONE;
811141cc406Sopenharmony_ci  opts[HP5590_OPT_DOC_IN_ADF].constraint.range = NULL;
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].name = SANE_NAME_PREVIEW;
814141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
815141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
816141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].type = SANE_TYPE_BOOL;
817141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].unit = SANE_UNIT_NONE;
818141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].size = sizeof(SANE_Bool);
819141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
820141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
821141cc406Sopenharmony_ci  opts[HP5590_OPT_PREVIEW].constraint.string_list = NULL;
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].name = SANE_NAME_OVERWRITE_EOP_PIXEL;
824141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].title = SANE_TITLE_OVERWRITE_EOP_PIXEL;
825141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].desc = SANE_DESC_OVERWRITE_EOP_PIXEL;
826141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].type = SANE_TYPE_BOOL;
827141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].unit = SANE_UNIT_NONE;
828141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].size = sizeof(SANE_Bool);
829141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
830141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint_type = SANE_CONSTRAINT_NONE;
831141cc406Sopenharmony_ci  opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint.string_list = NULL;
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].name = SANE_NAME_TRAILING_LINES_MODE;
834141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].title = SANE_TITLE_TRAILING_LINES_MODE;
835141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].desc = SANE_DESC_TRAILING_LINES_MODE;
836141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].type = SANE_TYPE_STRING;
837141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].unit = SANE_UNIT_NONE;
838141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].size = TRAILING_LINES_MODE_MAX_KEY_LEN;
839141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
840141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
841141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_MODE].constraint.string_list = trailingmode_list;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].name = SANE_NAME_TRAILING_LINES_COLOR;
844141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].title = SANE_TITLE_TRAILING_LINES_COLOR;
845141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].desc = SANE_DESC_TRAILING_LINES_COLOR;
846141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].type = SANE_TYPE_INT;
847141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].unit = SANE_UNIT_NONE;
848141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].size = sizeof(SANE_Int);
849141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].cap =  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
850141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint_type = SANE_CONSTRAINT_NONE;
851141cc406Sopenharmony_ci  opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint.string_list = NULL;
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci  ptr->opts = opts;
854141cc406Sopenharmony_ci
855141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
856141cc406Sopenharmony_ci}
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci/******************************************************************************/
859141cc406Sopenharmony_civoid
860141cc406Sopenharmony_cisane_close (SANE_Handle handle)
861141cc406Sopenharmony_ci{
862141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
863141cc406Sopenharmony_ci
864141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci  sanei_usb_close (scanner->dn);
867141cc406Sopenharmony_ci  scanner->dn = -1;
868141cc406Sopenharmony_ci}
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci/******************************************************************************/
871141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
872141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
873141cc406Sopenharmony_ci{
874141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci  DBG (DBG_proc, "%s, option: %u\n", __func__, option);
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci  if (option >= HP5590_OPT_LAST)
879141cc406Sopenharmony_ci    return NULL;
880141cc406Sopenharmony_ci
881141cc406Sopenharmony_ci  return &scanner->opts[option];
882141cc406Sopenharmony_ci}
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci/*************************************DS:Support function read buttons status */
885141cc406Sopenharmony_ciSANE_Status
886141cc406Sopenharmony_ciread_button_pressed(SANE_Handle handle, enum button_status * button_pressed)
887141cc406Sopenharmony_ci{
888141cc406Sopenharmony_ci  struct hp5590_scanner * scanner = handle;
889141cc406Sopenharmony_ci  *button_pressed = BUTTON_NONE;
890141cc406Sopenharmony_ci  enum button_status status = BUTTON_NONE;
891141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Checking button status (device_number = %u) (device_name = %s)\n", __func__, scanner->dn, scanner->sane.name);
892141cc406Sopenharmony_ci  SANE_Status ret = hp5590_read_buttons (scanner->dn, scanner->proto_flags, &status);
893141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
894141cc406Sopenharmony_ci    {
895141cc406Sopenharmony_ci      DBG (DBG_proc, "%s: Error reading button status (%u)\n", __func__, ret);
896141cc406Sopenharmony_ci      return ret;
897141cc406Sopenharmony_ci    }
898141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Button pressed = %d\n", __func__, status);
899141cc406Sopenharmony_ci  *button_pressed = status;
900141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
901141cc406Sopenharmony_ci}
902141cc406Sopenharmony_ci
903141cc406Sopenharmony_ci/******************************************************************************/
904141cc406Sopenharmony_ciSANE_Status
905141cc406Sopenharmony_ciread_lcd_and_led_values(SANE_Handle handle,
906141cc406Sopenharmony_ci        SANE_Int * lcd_counter,
907141cc406Sopenharmony_ci        enum color_led_status * color_led)
908141cc406Sopenharmony_ci{
909141cc406Sopenharmony_ci  struct hp5590_scanner * scanner = handle;
910141cc406Sopenharmony_ci  *lcd_counter = 1;
911141cc406Sopenharmony_ci  *color_led = LED_COLOR;
912141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Reading LCD and LED values (device_number = %u) (device_name = %s)\n",
913141cc406Sopenharmony_ci        __func__, scanner->dn, scanner->sane.name);
914141cc406Sopenharmony_ci  SANE_Status ret = hp5590_read_lcd_and_led (scanner->dn, scanner->proto_flags, lcd_counter, color_led);
915141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
916141cc406Sopenharmony_ci    {
917141cc406Sopenharmony_ci      DBG (DBG_proc, "%s: Error reading LCD and LED values (%u)\n", __func__, ret);
918141cc406Sopenharmony_ci      return ret;
919141cc406Sopenharmony_ci    }
920141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: LCD = %d, LED = %s\n", __func__, *lcd_counter,
921141cc406Sopenharmony_ci        *color_led == LED_BLACKWHITE ? COLOR_LED_VALUE_BLACKWHITE_KEY : COLOR_LED_VALUE_COLOR_KEY);
922141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
923141cc406Sopenharmony_ci}
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci/******************************************************************************/
926141cc406Sopenharmony_ciSANE_Status
927141cc406Sopenharmony_ciread_doc_in_adf_value(SANE_Handle handle,
928141cc406Sopenharmony_ci        SANE_Bool * doc_in_adf)
929141cc406Sopenharmony_ci{
930141cc406Sopenharmony_ci  struct hp5590_scanner * scanner = handle;
931141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: Reading state of document-available in ADF (device_number = %u) (device_name = %s)\n",
932141cc406Sopenharmony_ci        __func__, scanner->dn, scanner->sane.name);
933141cc406Sopenharmony_ci  SANE_Status ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags);
934141cc406Sopenharmony_ci  if (ret == SANE_STATUS_GOOD)
935141cc406Sopenharmony_ci    *doc_in_adf = SANE_TRUE;
936141cc406Sopenharmony_ci  else if (ret == SANE_STATUS_NO_DOCS)
937141cc406Sopenharmony_ci    *doc_in_adf = SANE_FALSE;
938141cc406Sopenharmony_ci  else
939141cc406Sopenharmony_ci    {
940141cc406Sopenharmony_ci      DBG (DBG_proc, "%s: Error reading state of document-available in ADF (%u)\n", __func__, ret);
941141cc406Sopenharmony_ci      return ret;
942141cc406Sopenharmony_ci    }
943141cc406Sopenharmony_ci  DBG (DBG_verbose, "%s: doc_in_adf = %s\n", __func__, *doc_in_adf == SANE_FALSE ? "false" : "true");
944141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
945141cc406Sopenharmony_ci}
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci/******************************************************************************/
948141cc406Sopenharmony_ciSANE_Status
949141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
950141cc406Sopenharmony_ci                     SANE_Action action, void *value,
951141cc406Sopenharmony_ci                     SANE_Int * info)
952141cc406Sopenharmony_ci{
953141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci  if (!value)
956141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  if (!handle)
959141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci  if (option >= HP5590_OPT_LAST)
962141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
965141cc406Sopenharmony_ci    {
966141cc406Sopenharmony_ci      if (option == HP5590_OPT_NUM)
967141cc406Sopenharmony_ci        {
968141cc406Sopenharmony_ci          DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST);
969141cc406Sopenharmony_ci          *((SANE_Int *) value) = HP5590_OPT_LAST;
970141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
971141cc406Sopenharmony_ci        }
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci      if (!scanner->opts)
974141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci      DBG (DBG_proc, "%s: get option '%s' value\n", __func__, scanner->opts[option].name);
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci      if (option == HP5590_OPT_BR_X)
979141cc406Sopenharmony_ci        {
980141cc406Sopenharmony_ci          *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4);
981141cc406Sopenharmony_ci        }
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci      if (option == HP5590_OPT_BR_Y)
984141cc406Sopenharmony_ci        {
985141cc406Sopenharmony_ci          *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4);
986141cc406Sopenharmony_ci        }
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci      if (option == HP5590_OPT_TL_X)
989141cc406Sopenharmony_ci        {
990141cc406Sopenharmony_ci          *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4);
991141cc406Sopenharmony_ci        }
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci      if (option == HP5590_OPT_TL_Y)
994141cc406Sopenharmony_ci        {
995141cc406Sopenharmony_ci          *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4);
996141cc406Sopenharmony_ci        }
997141cc406Sopenharmony_ci
998141cc406Sopenharmony_ci      if (option == HP5590_OPT_MODE)
999141cc406Sopenharmony_ci        {
1000141cc406Sopenharmony_ci          switch (scanner->depth) {
1001141cc406Sopenharmony_ci            case DEPTH_BW:
1002141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1003141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART));
1004141cc406Sopenharmony_ci              break;
1005141cc406Sopenharmony_ci            case DEPTH_GRAY:
1006141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1007141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY));
1008141cc406Sopenharmony_ci              break;
1009141cc406Sopenharmony_ci            case DEPTH_COLOR_24:
1010141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1011141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24));
1012141cc406Sopenharmony_ci              break;
1013141cc406Sopenharmony_ci            case DEPTH_COLOR_48:
1014141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1015141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48));
1016141cc406Sopenharmony_ci              break;
1017141cc406Sopenharmony_ci            default:
1018141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
1019141cc406Sopenharmony_ci          }
1020141cc406Sopenharmony_ci        }
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci      if (option == HP5590_OPT_SOURCE)
1023141cc406Sopenharmony_ci        {
1024141cc406Sopenharmony_ci          switch (scanner->source) {
1025141cc406Sopenharmony_ci            case SOURCE_FLATBED:
1026141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1027141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED));
1028141cc406Sopenharmony_ci              break;
1029141cc406Sopenharmony_ci            case SOURCE_ADF:
1030141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1031141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF));
1032141cc406Sopenharmony_ci              break;
1033141cc406Sopenharmony_ci            case SOURCE_ADF_DUPLEX:
1034141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1035141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX));
1036141cc406Sopenharmony_ci              break;
1037141cc406Sopenharmony_ci            case SOURCE_TMA_SLIDES:
1038141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1039141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES));
1040141cc406Sopenharmony_ci              break;
1041141cc406Sopenharmony_ci            case SOURCE_TMA_NEGATIVES:
1042141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1043141cc406Sopenharmony_ci              memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES));
1044141cc406Sopenharmony_ci              break;
1045141cc406Sopenharmony_ci            case SOURCE_NONE:
1046141cc406Sopenharmony_ci            default:
1047141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
1048141cc406Sopenharmony_ci          }
1049141cc406Sopenharmony_ci        }
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci      if (option == HP5590_OPT_RESOLUTION)
1052141cc406Sopenharmony_ci        {
1053141cc406Sopenharmony_ci          *(SANE_Int *) value = scanner->dpi;
1054141cc406Sopenharmony_ci        }
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci      if (option == HP5590_OPT_LAMP_TIMEOUT)
1057141cc406Sopenharmony_ci        {
1058141cc406Sopenharmony_ci          *(SANE_Bool *) value = scanner->extend_lamp_timeout;
1059141cc406Sopenharmony_ci        }
1060141cc406Sopenharmony_ci
1061141cc406Sopenharmony_ci      if (option == HP5590_OPT_WAIT_FOR_BUTTON)
1062141cc406Sopenharmony_ci        {
1063141cc406Sopenharmony_ci          *(SANE_Bool *) value = scanner->wait_for_button;
1064141cc406Sopenharmony_ci        }
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci      if (option == HP5590_OPT_BUTTON_PRESSED)
1067141cc406Sopenharmony_ci        {
1068141cc406Sopenharmony_ci          enum button_status button_pressed = BUTTON_NONE;
1069141cc406Sopenharmony_ci          SANE_Status ret = read_button_pressed(scanner, &button_pressed);
1070141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD)
1071141cc406Sopenharmony_ci            return ret;
1072141cc406Sopenharmony_ci          switch (button_pressed) {
1073141cc406Sopenharmony_ci            case BUTTON_POWER:
1074141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_POWER_KEY, scanner->opts[option].size);
1075141cc406Sopenharmony_ci              break;
1076141cc406Sopenharmony_ci            case BUTTON_SCAN:
1077141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_SCAN_KEY, scanner->opts[option].size);
1078141cc406Sopenharmony_ci              break;
1079141cc406Sopenharmony_ci            case BUTTON_COLLECT:
1080141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_COLLECT_KEY, scanner->opts[option].size);
1081141cc406Sopenharmony_ci              break;
1082141cc406Sopenharmony_ci            case BUTTON_FILE:
1083141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_FILE_KEY, scanner->opts[option].size);
1084141cc406Sopenharmony_ci              break;
1085141cc406Sopenharmony_ci            case BUTTON_EMAIL:
1086141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_EMAIL_KEY, scanner->opts[option].size);
1087141cc406Sopenharmony_ci              break;
1088141cc406Sopenharmony_ci            case BUTTON_COPY:
1089141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_COPY_KEY, scanner->opts[option].size);
1090141cc406Sopenharmony_ci              break;
1091141cc406Sopenharmony_ci            case BUTTON_UP:
1092141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_UP_KEY, scanner->opts[option].size);
1093141cc406Sopenharmony_ci              break;
1094141cc406Sopenharmony_ci            case BUTTON_DOWN:
1095141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_DOWN_KEY, scanner->opts[option].size);
1096141cc406Sopenharmony_ci              break;
1097141cc406Sopenharmony_ci            case BUTTON_MODE:
1098141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_MODE_KEY, scanner->opts[option].size);
1099141cc406Sopenharmony_ci              break;
1100141cc406Sopenharmony_ci            case BUTTON_CANCEL:
1101141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_CANCEL_KEY, scanner->opts[option].size);
1102141cc406Sopenharmony_ci              break;
1103141cc406Sopenharmony_ci            case BUTTON_NONE:
1104141cc406Sopenharmony_ci            default:
1105141cc406Sopenharmony_ci              strncpy (value, BUTTON_PRESSED_VALUE_NONE_KEY, scanner->opts[option].size);
1106141cc406Sopenharmony_ci          }
1107141cc406Sopenharmony_ci        }
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci      if (option == HP5590_OPT_COLOR_LED)
1110141cc406Sopenharmony_ci        {
1111141cc406Sopenharmony_ci          SANE_Int lcd_counter = 0;
1112141cc406Sopenharmony_ci          enum color_led_status color_led = LED_COLOR;
1113141cc406Sopenharmony_ci          SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led);
1114141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD)
1115141cc406Sopenharmony_ci            return ret;
1116141cc406Sopenharmony_ci          switch (color_led) {
1117141cc406Sopenharmony_ci            case LED_BLACKWHITE:
1118141cc406Sopenharmony_ci              strncpy (value, COLOR_LED_VALUE_BLACKWHITE_KEY, scanner->opts[option].size);
1119141cc406Sopenharmony_ci              break;
1120141cc406Sopenharmony_ci            case LED_COLOR:
1121141cc406Sopenharmony_ci            default:
1122141cc406Sopenharmony_ci              strncpy (value, COLOR_LED_VALUE_COLOR_KEY, scanner->opts[option].size);
1123141cc406Sopenharmony_ci          }
1124141cc406Sopenharmony_ci        }
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci      if (option == HP5590_OPT_LCD_COUNTER)
1127141cc406Sopenharmony_ci        {
1128141cc406Sopenharmony_ci          SANE_Int lcd_counter = 0;
1129141cc406Sopenharmony_ci          enum color_led_status color_led = LED_COLOR;
1130141cc406Sopenharmony_ci          SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led);
1131141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD)
1132141cc406Sopenharmony_ci            return ret;
1133141cc406Sopenharmony_ci          *(SANE_Int *) value = lcd_counter;
1134141cc406Sopenharmony_ci        }
1135141cc406Sopenharmony_ci
1136141cc406Sopenharmony_ci      if (option == HP5590_OPT_DOC_IN_ADF)
1137141cc406Sopenharmony_ci        {
1138141cc406Sopenharmony_ci          SANE_Bool doc_in_adf = SANE_FALSE;
1139141cc406Sopenharmony_ci          SANE_Status ret = read_doc_in_adf_value(scanner, &doc_in_adf);
1140141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD)
1141141cc406Sopenharmony_ci            return ret;
1142141cc406Sopenharmony_ci          *(SANE_Bool *) value = doc_in_adf;
1143141cc406Sopenharmony_ci        }
1144141cc406Sopenharmony_ci
1145141cc406Sopenharmony_ci      if (option == HP5590_OPT_PREVIEW)
1146141cc406Sopenharmony_ci        {
1147141cc406Sopenharmony_ci          *(SANE_Bool *) value = scanner->preview;
1148141cc406Sopenharmony_ci        }
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_ci      if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL)
1151141cc406Sopenharmony_ci        {
1152141cc406Sopenharmony_ci          *(SANE_Bool *) value = scanner->overwrite_eop_pixel;
1153141cc406Sopenharmony_ci        }
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci      if (option == HP5590_OPT_TRAILING_LINES_MODE)
1156141cc406Sopenharmony_ci        {
1157141cc406Sopenharmony_ci          switch (scanner->eop_trailing_lines_mode) {
1158141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_RAW:
1159141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1160141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_RAW_KEY, strlen (TRAILING_LINES_MODE_RAW_KEY));
1161141cc406Sopenharmony_ci              break;
1162141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_LAST:
1163141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1164141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_LAST_KEY, strlen (TRAILING_LINES_MODE_LAST_KEY));
1165141cc406Sopenharmony_ci              break;
1166141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_RASTER:
1167141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1168141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_RASTER_KEY, strlen (TRAILING_LINES_MODE_RASTER_KEY));
1169141cc406Sopenharmony_ci              break;
1170141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_BLACK:
1171141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1172141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_BLACK_KEY, strlen (TRAILING_LINES_MODE_BLACK_KEY));
1173141cc406Sopenharmony_ci              break;
1174141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_WHITE:
1175141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1176141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_WHITE_KEY, strlen (TRAILING_LINES_MODE_WHITE_KEY));
1177141cc406Sopenharmony_ci              break;
1178141cc406Sopenharmony_ci            case TRAILING_LINES_MODE_COLOR:
1179141cc406Sopenharmony_ci              memset (value , 0, scanner->opts[option].size);
1180141cc406Sopenharmony_ci              memcpy (value, TRAILING_LINES_MODE_COLOR_KEY, strlen (TRAILING_LINES_MODE_COLOR_KEY));
1181141cc406Sopenharmony_ci              break;
1182141cc406Sopenharmony_ci            default:
1183141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
1184141cc406Sopenharmony_ci          }
1185141cc406Sopenharmony_ci        }
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci      if (option == HP5590_OPT_TRAILING_LINES_COLOR)
1188141cc406Sopenharmony_ci        {
1189141cc406Sopenharmony_ci          *(SANE_Int *) value = scanner->eop_trailing_lines_color;
1190141cc406Sopenharmony_ci        }
1191141cc406Sopenharmony_ci    }
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  if (action == SANE_ACTION_SET_VALUE)
1194141cc406Sopenharmony_ci    {
1195141cc406Sopenharmony_ci      if (option == HP5590_OPT_NUM)
1196141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci      if (option == HP5590_OPT_BR_X)
1199141cc406Sopenharmony_ci        {
1200141cc406Sopenharmony_ci          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
1201141cc406Sopenharmony_ci          if (val <= scanner->tl_x)
1202141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
1203141cc406Sopenharmony_ci          scanner->br_x = val;
1204141cc406Sopenharmony_ci          if (info)
1205141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS;
1206141cc406Sopenharmony_ci        }
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci      if (option == HP5590_OPT_BR_Y)
1209141cc406Sopenharmony_ci        {
1210141cc406Sopenharmony_ci          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
1211141cc406Sopenharmony_ci          if (val <= scanner->tl_y)
1212141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
1213141cc406Sopenharmony_ci          scanner->br_y = val;
1214141cc406Sopenharmony_ci          if (info)
1215141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS;
1216141cc406Sopenharmony_ci        }
1217141cc406Sopenharmony_ci
1218141cc406Sopenharmony_ci      if (option == HP5590_OPT_TL_X)
1219141cc406Sopenharmony_ci        {
1220141cc406Sopenharmony_ci          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
1221141cc406Sopenharmony_ci          if (val >= scanner->br_x)
1222141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
1223141cc406Sopenharmony_ci          scanner->tl_x = val;
1224141cc406Sopenharmony_ci          if (info)
1225141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS;
1226141cc406Sopenharmony_ci        }
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci      if (option == HP5590_OPT_TL_Y)
1229141cc406Sopenharmony_ci        {
1230141cc406Sopenharmony_ci          float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
1231141cc406Sopenharmony_ci          if (val >= scanner->br_y)
1232141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
1233141cc406Sopenharmony_ci          scanner->tl_y = val;
1234141cc406Sopenharmony_ci          if (info)
1235141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS;
1236141cc406Sopenharmony_ci        }
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci      if (option == HP5590_OPT_MODE)
1239141cc406Sopenharmony_ci        {
1240141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0)
1241141cc406Sopenharmony_ci            {
1242141cc406Sopenharmony_ci              scanner->depth = DEPTH_BW;
1243141cc406Sopenharmony_ci            }
1244141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0)
1245141cc406Sopenharmony_ci            {
1246141cc406Sopenharmony_ci              scanner->depth = DEPTH_GRAY;
1247141cc406Sopenharmony_ci            }
1248141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0)
1249141cc406Sopenharmony_ci            {
1250141cc406Sopenharmony_ci              scanner->depth = DEPTH_COLOR_24;
1251141cc406Sopenharmony_ci            }
1252141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0)
1253141cc406Sopenharmony_ci            {
1254141cc406Sopenharmony_ci              scanner->depth = DEPTH_COLOR_48;
1255141cc406Sopenharmony_ci            }
1256141cc406Sopenharmony_ci          else
1257141cc406Sopenharmony_ci            {
1258141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
1259141cc406Sopenharmony_ci            }
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci          if (info)
1262141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
1263141cc406Sopenharmony_ci        }
1264141cc406Sopenharmony_ci
1265141cc406Sopenharmony_ci      if (option == HP5590_OPT_SOURCE)
1266141cc406Sopenharmony_ci        {
1267141cc406Sopenharmony_ci          range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4);
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0)
1270141cc406Sopenharmony_ci            {
1271141cc406Sopenharmony_ci              scanner->source = SOURCE_FLATBED;
1272141cc406Sopenharmony_ci              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
1273141cc406Sopenharmony_ci              range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4);
1274141cc406Sopenharmony_ci              scanner->br_x = scanner->info->max_size_x;
1275141cc406Sopenharmony_ci              scanner->br_y = scanner->info->max_size_y;
1276141cc406Sopenharmony_ci            }
1277141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0)
1278141cc406Sopenharmony_ci            {
1279141cc406Sopenharmony_ci              /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually
1280141cc406Sopenharmony_ci               * bigger than what scanner reports back during initialization
1281141cc406Sopenharmony_ci               */
1282141cc406Sopenharmony_ci              if (! (scanner->info->features & FEATURE_ADF))
1283141cc406Sopenharmony_ci                {
1284141cc406Sopenharmony_ci                  DBG(DBG_err, "ADF feature not available: %s\n", (char *) value);
1285141cc406Sopenharmony_ci                  return SANE_STATUS_UNSUPPORTED;
1286141cc406Sopenharmony_ci                }
1287141cc406Sopenharmony_ci              scanner->source = SOURCE_ADF;
1288141cc406Sopenharmony_ci              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
1289141cc406Sopenharmony_ci              range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4);
1290141cc406Sopenharmony_ci              scanner->br_x = scanner->info->max_size_x;
1291141cc406Sopenharmony_ci              scanner->br_y = ADF_MAX_Y_INCHES;
1292141cc406Sopenharmony_ci            }
1293141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0)
1294141cc406Sopenharmony_ci            {
1295141cc406Sopenharmony_ci              if (! (scanner->info->features & FEATURE_ADF))
1296141cc406Sopenharmony_ci                {
1297141cc406Sopenharmony_ci                  DBG(DBG_err, "ADF feature not available: %s\n", (char *) value);
1298141cc406Sopenharmony_ci                  return SANE_STATUS_UNSUPPORTED;
1299141cc406Sopenharmony_ci                }
1300141cc406Sopenharmony_ci              scanner->source = SOURCE_ADF_DUPLEX;
1301141cc406Sopenharmony_ci              range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
1302141cc406Sopenharmony_ci              range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4);
1303141cc406Sopenharmony_ci              scanner->br_x = scanner->info->max_size_x;
1304141cc406Sopenharmony_ci              scanner->br_y = ADF_MAX_Y_INCHES;
1305141cc406Sopenharmony_ci            }
1306141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0)
1307141cc406Sopenharmony_ci            {
1308141cc406Sopenharmony_ci              if (! (scanner->info->features & FEATURE_TMA))
1309141cc406Sopenharmony_ci                {
1310141cc406Sopenharmony_ci                  DBG(DBG_err, "TMA feature not available: %s\n", (char *) value);
1311141cc406Sopenharmony_ci                  return SANE_STATUS_UNSUPPORTED;
1312141cc406Sopenharmony_ci                }
1313141cc406Sopenharmony_ci              scanner->source = SOURCE_TMA_SLIDES;
1314141cc406Sopenharmony_ci              range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
1315141cc406Sopenharmony_ci              range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
1316141cc406Sopenharmony_ci              scanner->br_x = TMA_MAX_X_INCHES;
1317141cc406Sopenharmony_ci              scanner->br_y = TMA_MAX_Y_INCHES;
1318141cc406Sopenharmony_ci            }
1319141cc406Sopenharmony_ci          else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0)
1320141cc406Sopenharmony_ci            {
1321141cc406Sopenharmony_ci              if (! (scanner->info->features & FEATURE_TMA))
1322141cc406Sopenharmony_ci                {
1323141cc406Sopenharmony_ci                  DBG(DBG_err, "TMA feature not available: %s\n", (char *) value);
1324141cc406Sopenharmony_ci                  return SANE_STATUS_UNSUPPORTED;
1325141cc406Sopenharmony_ci                }
1326141cc406Sopenharmony_ci              scanner->source = SOURCE_TMA_NEGATIVES;
1327141cc406Sopenharmony_ci              range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
1328141cc406Sopenharmony_ci              range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
1329141cc406Sopenharmony_ci              scanner->br_x = TMA_MAX_X_INCHES;
1330141cc406Sopenharmony_ci              scanner->br_y = TMA_MAX_Y_INCHES;
1331141cc406Sopenharmony_ci            }
1332141cc406Sopenharmony_ci          else
1333141cc406Sopenharmony_ci            {
1334141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
1335141cc406Sopenharmony_ci            }
1336141cc406Sopenharmony_ci          if (info)
1337141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
1338141cc406Sopenharmony_ci        }
1339141cc406Sopenharmony_ci
1340141cc406Sopenharmony_ci      if (option == HP5590_OPT_RESOLUTION)
1341141cc406Sopenharmony_ci        {
1342141cc406Sopenharmony_ci          scanner->dpi = *(SANE_Int *) value;
1343141cc406Sopenharmony_ci          if (info)
1344141cc406Sopenharmony_ci            *info = SANE_INFO_RELOAD_PARAMS;
1345141cc406Sopenharmony_ci        }
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci      if (option == HP5590_OPT_LAMP_TIMEOUT)
1348141cc406Sopenharmony_ci        {
1349141cc406Sopenharmony_ci          scanner->extend_lamp_timeout = *(SANE_Bool *) value;
1350141cc406Sopenharmony_ci        }
1351141cc406Sopenharmony_ci
1352141cc406Sopenharmony_ci      if (option == HP5590_OPT_WAIT_FOR_BUTTON)
1353141cc406Sopenharmony_ci        {
1354141cc406Sopenharmony_ci          scanner->wait_for_button = *(SANE_Bool *) value;
1355141cc406Sopenharmony_ci        }
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci      if (option == HP5590_OPT_BUTTON_PRESSED)
1358141cc406Sopenharmony_ci        {
1359141cc406Sopenharmony_ci          DBG(DBG_verbose, "State of buttons is read only. Setting of state will be ignored.\n");
1360141cc406Sopenharmony_ci        }
1361141cc406Sopenharmony_ci
1362141cc406Sopenharmony_ci      if (option == HP5590_OPT_COLOR_LED)
1363141cc406Sopenharmony_ci        {
1364141cc406Sopenharmony_ci          DBG(DBG_verbose, "State of color LED indicator is read only. Setting of state will be ignored.\n");
1365141cc406Sopenharmony_ci        }
1366141cc406Sopenharmony_ci
1367141cc406Sopenharmony_ci      if (option == HP5590_OPT_LCD_COUNTER)
1368141cc406Sopenharmony_ci        {
1369141cc406Sopenharmony_ci          DBG(DBG_verbose, "Value of LCD counter is read only. Setting of value will be ignored.\n");
1370141cc406Sopenharmony_ci        }
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci      if (option == HP5590_OPT_DOC_IN_ADF)
1373141cc406Sopenharmony_ci        {
1374141cc406Sopenharmony_ci          DBG(DBG_verbose, "Value of document-available indicator is read only. Setting of value will be ignored.\n");
1375141cc406Sopenharmony_ci        }
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci      if (option == HP5590_OPT_PREVIEW)
1378141cc406Sopenharmony_ci        {
1379141cc406Sopenharmony_ci          scanner->preview = *(SANE_Bool *) value;
1380141cc406Sopenharmony_ci        }
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci      if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL)
1383141cc406Sopenharmony_ci        {
1384141cc406Sopenharmony_ci          scanner->overwrite_eop_pixel = *(SANE_Bool *) value;
1385141cc406Sopenharmony_ci        }
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci      if (option == HP5590_OPT_TRAILING_LINES_MODE)
1388141cc406Sopenharmony_ci        {
1389141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RAW_KEY) == 0)
1390141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RAW;
1391141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_LAST_KEY) == 0)
1392141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST;
1393141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RASTER_KEY) == 0)
1394141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RASTER;
1395141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_BLACK_KEY) == 0)
1396141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_BLACK;
1397141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_WHITE_KEY) == 0)
1398141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_WHITE;
1399141cc406Sopenharmony_ci          if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_COLOR_KEY) == 0)
1400141cc406Sopenharmony_ci            scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_COLOR;
1401141cc406Sopenharmony_ci        }
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci      if (option == HP5590_OPT_TRAILING_LINES_COLOR)
1404141cc406Sopenharmony_ci        {
1405141cc406Sopenharmony_ci          scanner->eop_trailing_lines_color = *(SANE_Int *) value;
1406141cc406Sopenharmony_ci        }
1407141cc406Sopenharmony_ci    }
1408141cc406Sopenharmony_ci
1409141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1410141cc406Sopenharmony_ci}
1411141cc406Sopenharmony_ci
1412141cc406Sopenharmony_ci/******************************************************************************/
1413141cc406Sopenharmony_ciSANE_Status sane_get_parameters (SANE_Handle handle,
1414141cc406Sopenharmony_ci                                 SANE_Parameters * params)
1415141cc406Sopenharmony_ci{
1416141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
1417141cc406Sopenharmony_ci  SANE_Status           ret;
1418141cc406Sopenharmony_ci  unsigned int          pixel_bits;
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
1421141cc406Sopenharmony_ci
1422141cc406Sopenharmony_ci  if (!params)
1423141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci  if (!handle)
1426141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1427141cc406Sopenharmony_ci
1428141cc406Sopenharmony_ci  ret = calc_image_params (scanner,
1429141cc406Sopenharmony_ci                           (unsigned int *) &pixel_bits,
1430141cc406Sopenharmony_ci                           (unsigned int *) &params->pixels_per_line,
1431141cc406Sopenharmony_ci                           (unsigned int *) &params->bytes_per_line,
1432141cc406Sopenharmony_ci                           (unsigned int *) &params->lines, NULL);
1433141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1434141cc406Sopenharmony_ci    return ret;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci  switch (scanner->depth) {
1437141cc406Sopenharmony_ci    case DEPTH_BW:
1438141cc406Sopenharmony_ci      params->depth = pixel_bits;
1439141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
1440141cc406Sopenharmony_ci      params->last_frame = SANE_TRUE;
1441141cc406Sopenharmony_ci      break;
1442141cc406Sopenharmony_ci    case DEPTH_GRAY:
1443141cc406Sopenharmony_ci      params->depth = pixel_bits;
1444141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
1445141cc406Sopenharmony_ci      params->last_frame = SANE_TRUE;
1446141cc406Sopenharmony_ci      break;
1447141cc406Sopenharmony_ci    case DEPTH_COLOR_24:
1448141cc406Sopenharmony_ci      params->depth = pixel_bits / 3;
1449141cc406Sopenharmony_ci      params->last_frame = SANE_TRUE;
1450141cc406Sopenharmony_ci      params->format = SANE_FRAME_RGB;
1451141cc406Sopenharmony_ci      break;
1452141cc406Sopenharmony_ci    case DEPTH_COLOR_48:
1453141cc406Sopenharmony_ci      params->depth = pixel_bits / 3;
1454141cc406Sopenharmony_ci      params->last_frame = SANE_TRUE;
1455141cc406Sopenharmony_ci      params->format = SANE_FRAME_RGB;
1456141cc406Sopenharmony_ci      break;
1457141cc406Sopenharmony_ci    default:
1458141cc406Sopenharmony_ci      DBG(DBG_err, "%s: Unknown depth\n", __func__);
1459141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1460141cc406Sopenharmony_ci  }
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci  DBG (DBG_proc, "format: %u, last_frame: %u, bytes_per_line: %u, "
1464141cc406Sopenharmony_ci       "pixels_per_line: %u, lines: %u, depth: %u\n",
1465141cc406Sopenharmony_ci       params->format, params->last_frame,
1466141cc406Sopenharmony_ci       params->bytes_per_line, params->pixels_per_line,
1467141cc406Sopenharmony_ci       params->lines, params->depth);
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1470141cc406Sopenharmony_ci}
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci/******************************************************************************/
1473141cc406Sopenharmony_ciSANE_Status
1474141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1475141cc406Sopenharmony_ci{
1476141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
1477141cc406Sopenharmony_ci  SANE_Status           ret;
1478141cc406Sopenharmony_ci  unsigned int          bytes_per_line;
1479141cc406Sopenharmony_ci
1480141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
1481141cc406Sopenharmony_ci
1482141cc406Sopenharmony_ci  if (!scanner)
1483141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1484141cc406Sopenharmony_ci
1485141cc406Sopenharmony_ci  /* Cleanup for all pages. */
1486141cc406Sopenharmony_ci  if (scanner->eop_last_line_data)
1487141cc406Sopenharmony_ci    {
1488141cc406Sopenharmony_ci      /* Release last line data */
1489141cc406Sopenharmony_ci      free (scanner->eop_last_line_data);
1490141cc406Sopenharmony_ci      scanner->eop_last_line_data = NULL;
1491141cc406Sopenharmony_ci      scanner->eop_last_line_data_rpos = 0;
1492141cc406Sopenharmony_ci    }
1493141cc406Sopenharmony_ci  if (scanner->one_line_read_buffer)
1494141cc406Sopenharmony_ci    {
1495141cc406Sopenharmony_ci      /* Release temporary line buffer. */
1496141cc406Sopenharmony_ci      free (scanner->one_line_read_buffer);
1497141cc406Sopenharmony_ci      scanner->one_line_read_buffer = NULL;
1498141cc406Sopenharmony_ci      scanner->one_line_read_buffer_rpos = 0;
1499141cc406Sopenharmony_ci    }
1500141cc406Sopenharmony_ci  if (scanner->color_shift_line_buffer1)
1501141cc406Sopenharmony_ci    {
1502141cc406Sopenharmony_ci      /* Release line buffer1 for shifting colors. */
1503141cc406Sopenharmony_ci      free (scanner->color_shift_line_buffer1);
1504141cc406Sopenharmony_ci      scanner->color_shift_line_buffer1 = NULL;
1505141cc406Sopenharmony_ci      scanner->color_shift_buffered_lines1 = 0;
1506141cc406Sopenharmony_ci    }
1507141cc406Sopenharmony_ci  if (scanner->color_shift_line_buffer2)
1508141cc406Sopenharmony_ci    {
1509141cc406Sopenharmony_ci      /* Release line buffer2 for shifting colors. */
1510141cc406Sopenharmony_ci      free (scanner->color_shift_line_buffer2);
1511141cc406Sopenharmony_ci      scanner->color_shift_line_buffer2 = NULL;
1512141cc406Sopenharmony_ci      scanner->color_shift_buffered_lines2 = 0;
1513141cc406Sopenharmony_ci    }
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci  if (   scanner->scanning == SANE_TRUE
1516141cc406Sopenharmony_ci      && (  scanner->source == SOURCE_ADF
1517141cc406Sopenharmony_ci         || scanner->source == SOURCE_ADF_DUPLEX))
1518141cc406Sopenharmony_ci    {
1519141cc406Sopenharmony_ci      DBG (DBG_verbose, "%s: Scanner is scanning, check if more data is available\n",
1520141cc406Sopenharmony_ci           __func__);
1521141cc406Sopenharmony_ci      ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags);
1522141cc406Sopenharmony_ci      if (ret == SANE_STATUS_GOOD)
1523141cc406Sopenharmony_ci        {
1524141cc406Sopenharmony_ci          DBG (DBG_verbose, "%s: More data is available\n", __func__);
1525141cc406Sopenharmony_ci          scanner->transferred_image_size = scanner->image_size;
1526141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
1527141cc406Sopenharmony_ci        }
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci      if (ret != SANE_STATUS_NO_DOCS)
1530141cc406Sopenharmony_ci        return ret;
1531141cc406Sopenharmony_ci    }
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci  sane_cancel (handle);
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci  if (scanner->wait_for_button)
1536141cc406Sopenharmony_ci    {
1537141cc406Sopenharmony_ci      enum button_status status;
1538141cc406Sopenharmony_ci      for (;;)
1539141cc406Sopenharmony_ci        {
1540141cc406Sopenharmony_ci          ret = hp5590_read_buttons (scanner->dn,
1541141cc406Sopenharmony_ci                                     scanner->proto_flags,
1542141cc406Sopenharmony_ci                                     &status);
1543141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD)
1544141cc406Sopenharmony_ci            return ret;
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci          if (status == BUTTON_CANCEL)
1547141cc406Sopenharmony_ci            return SANE_STATUS_CANCELLED;
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_ci          if (status != BUTTON_NONE && status != BUTTON_POWER)
1550141cc406Sopenharmony_ci            break;
1551141cc406Sopenharmony_ci          usleep (100 * 1000);
1552141cc406Sopenharmony_ci        }
1553141cc406Sopenharmony_ci    }
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  DBG (DBG_verbose, "Init scanner\n");
1556141cc406Sopenharmony_ci  ret = hp5590_init_scanner (scanner->dn, scanner->proto_flags,
1557141cc406Sopenharmony_ci                             NULL, SCANNER_NONE);
1558141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1559141cc406Sopenharmony_ci    return ret;
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci  ret = hp5590_power_status (scanner->dn, scanner->proto_flags);
1562141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1563141cc406Sopenharmony_ci    return ret;
1564141cc406Sopenharmony_ci
1565141cc406Sopenharmony_ci  DBG (DBG_verbose, "Wakeup\n");
1566141cc406Sopenharmony_ci  ret = hp5590_select_source_and_wakeup (scanner->dn, scanner->proto_flags,
1567141cc406Sopenharmony_ci                                         scanner->source,
1568141cc406Sopenharmony_ci                                         scanner->extend_lamp_timeout);
1569141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1570141cc406Sopenharmony_ci    return ret;
1571141cc406Sopenharmony_ci
1572141cc406Sopenharmony_ci  ret = hp5590_set_scan_params (scanner->dn,
1573141cc406Sopenharmony_ci                                scanner->proto_flags,
1574141cc406Sopenharmony_ci                                scanner->info,
1575141cc406Sopenharmony_ci                                scanner->tl_x * scanner->dpi,
1576141cc406Sopenharmony_ci                                scanner->tl_y * scanner->dpi,
1577141cc406Sopenharmony_ci                                (scanner->br_x - scanner->tl_x) * scanner->dpi,
1578141cc406Sopenharmony_ci                                (scanner->br_y - scanner->tl_y) * scanner->dpi,
1579141cc406Sopenharmony_ci                                scanner->dpi,
1580141cc406Sopenharmony_ci                                scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL,
1581141cc406Sopenharmony_ci                                scanner->source);
1582141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1583141cc406Sopenharmony_ci    {
1584141cc406Sopenharmony_ci      hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1585141cc406Sopenharmony_ci      return ret;
1586141cc406Sopenharmony_ci    }
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci  ret = calc_image_params (scanner, NULL, NULL,
1589141cc406Sopenharmony_ci                           &bytes_per_line, NULL,
1590141cc406Sopenharmony_ci                           &scanner->image_size);
1591141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1592141cc406Sopenharmony_ci    {
1593141cc406Sopenharmony_ci      hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1594141cc406Sopenharmony_ci      return ret;
1595141cc406Sopenharmony_ci    }
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  scanner->transferred_image_size = scanner->image_size;
1598141cc406Sopenharmony_ci
1599141cc406Sopenharmony_ci  if (   scanner->depth == DEPTH_COLOR_24
1600141cc406Sopenharmony_ci      || scanner->depth == DEPTH_COLOR_48)
1601141cc406Sopenharmony_ci    {
1602141cc406Sopenharmony_ci      DBG (1, "Color 24/48 bits: checking if image size is correctly "
1603141cc406Sopenharmony_ci           "aligned on number of colors\n");
1604141cc406Sopenharmony_ci      if (bytes_per_line % 3)
1605141cc406Sopenharmony_ci        {
1606141cc406Sopenharmony_ci          DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) "
1607141cc406Sopenharmony_ci               "(image size: %llu, bytes per line %u)\n",
1608141cc406Sopenharmony_ci               scanner->image_size, bytes_per_line);
1609141cc406Sopenharmony_ci          hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1610141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
1611141cc406Sopenharmony_ci        }
1612141cc406Sopenharmony_ci      DBG (1, "Color 24/48 bits: image size is correctly aligned on number of colors "
1613141cc406Sopenharmony_ci           "(image size: %llu, bytes per line %u)\n",
1614141cc406Sopenharmony_ci           scanner->image_size, bytes_per_line);
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci      DBG (1, "Color 24/48 bits: checking if image size is correctly "
1617141cc406Sopenharmony_ci           "aligned on bytes per line\n");
1618141cc406Sopenharmony_ci      if (scanner->image_size % bytes_per_line)
1619141cc406Sopenharmony_ci        {
1620141cc406Sopenharmony_ci          DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line "
1621141cc406Sopenharmony_ci               "(image size: %llu, bytes per line %u)\n",
1622141cc406Sopenharmony_ci               scanner->image_size, bytes_per_line);
1623141cc406Sopenharmony_ci          hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1624141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
1625141cc406Sopenharmony_ci        }
1626141cc406Sopenharmony_ci      DBG (1, "Color 24/48 bits: image size correctly aligned on bytes per line "
1627141cc406Sopenharmony_ci           "(images size: %llu, bytes per line: %u)\n",
1628141cc406Sopenharmony_ci           scanner->image_size, bytes_per_line);
1629141cc406Sopenharmony_ci    }
1630141cc406Sopenharmony_ci
1631141cc406Sopenharmony_ci  DBG (DBG_verbose, "Final image size: %llu\n", scanner->image_size);
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci  DBG (DBG_verbose, "Reverse calibration maps\n");
1634141cc406Sopenharmony_ci  ret = hp5590_send_reverse_calibration_map (scanner->dn, scanner->proto_flags);
1635141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1636141cc406Sopenharmony_ci    {
1637141cc406Sopenharmony_ci      hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1638141cc406Sopenharmony_ci      return ret;
1639141cc406Sopenharmony_ci    }
1640141cc406Sopenharmony_ci
1641141cc406Sopenharmony_ci  DBG (DBG_verbose, "Forward calibration maps\n");
1642141cc406Sopenharmony_ci  ret = hp5590_send_forward_calibration_maps (scanner->dn, scanner->proto_flags);
1643141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1644141cc406Sopenharmony_ci    {
1645141cc406Sopenharmony_ci      hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1646141cc406Sopenharmony_ci      return ret;
1647141cc406Sopenharmony_ci    }
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci  if (scanner->adf_next_page_lines_data)
1650141cc406Sopenharmony_ci    {
1651141cc406Sopenharmony_ci      free (scanner->adf_next_page_lines_data);
1652141cc406Sopenharmony_ci      scanner->adf_next_page_lines_data = NULL;
1653141cc406Sopenharmony_ci      scanner->adf_next_page_lines_data_size = 0;
1654141cc406Sopenharmony_ci      scanner->adf_next_page_lines_data_rpos = 0;
1655141cc406Sopenharmony_ci      scanner->adf_next_page_lines_data_wpos = 0;
1656141cc406Sopenharmony_ci    }
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci  scanner->scanning = SANE_TRUE;
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci  DBG (DBG_verbose, "Starting scan\n");
1661141cc406Sopenharmony_ci  ret = hp5590_start_scan (scanner->dn, scanner->proto_flags);
1662141cc406Sopenharmony_ci  /* Check for paper jam */
1663141cc406Sopenharmony_ci  if (    ret == SANE_STATUS_DEVICE_BUSY
1664141cc406Sopenharmony_ci      && (   scanner->source == SOURCE_ADF
1665141cc406Sopenharmony_ci          || scanner->source == SOURCE_ADF_DUPLEX))
1666141cc406Sopenharmony_ci    return SANE_STATUS_JAMMED;
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1669141cc406Sopenharmony_ci    {
1670141cc406Sopenharmony_ci      hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
1671141cc406Sopenharmony_ci      return ret;
1672141cc406Sopenharmony_ci    }
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1675141cc406Sopenharmony_ci}
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci/******************************************************************************/
1678141cc406Sopenharmony_cistatic void
1679141cc406Sopenharmony_ciinvert_negative_colors (unsigned char *buf, unsigned int bytes_per_line, struct hp5590_scanner *scanner)
1680141cc406Sopenharmony_ci{
1681141cc406Sopenharmony_ci  /* Invert lineart or negatives. */
1682141cc406Sopenharmony_ci  int is_linear = (scanner->depth == DEPTH_BW);
1683141cc406Sopenharmony_ci  int is_negative = (scanner->source == SOURCE_TMA_NEGATIVES);
1684141cc406Sopenharmony_ci  if (is_linear ^ is_negative)
1685141cc406Sopenharmony_ci    {
1686141cc406Sopenharmony_ci      for (unsigned int k = 0; k < bytes_per_line; k++)
1687141cc406Sopenharmony_ci        buf[k] ^= 0xff;
1688141cc406Sopenharmony_ci    }
1689141cc406Sopenharmony_ci}
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci/******************************************************************************/
1692141cc406Sopenharmony_cistatic SANE_Status
1693141cc406Sopenharmony_ciconvert_gray_and_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
1694141cc406Sopenharmony_ci{
1695141cc406Sopenharmony_ci  unsigned int pixels_per_line;
1696141cc406Sopenharmony_ci  unsigned int pixel_bits;
1697141cc406Sopenharmony_ci  unsigned int bytes_per_line;
1698141cc406Sopenharmony_ci  unsigned int lines;
1699141cc406Sopenharmony_ci  unsigned char *buf;
1700141cc406Sopenharmony_ci  SANE_Status ret;
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_ci  hp5590_assert (scanner != NULL);
1703141cc406Sopenharmony_ci  hp5590_assert (data != NULL);
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci  if ( ! (scanner->depth == DEPTH_BW || scanner->depth == DEPTH_GRAY))
1706141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1707141cc406Sopenharmony_ci
1708141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci  ret = calc_image_params (scanner,
1711141cc406Sopenharmony_ci                           &pixel_bits,
1712141cc406Sopenharmony_ci                           &pixels_per_line, &bytes_per_line,
1713141cc406Sopenharmony_ci                           NULL, NULL);
1714141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1715141cc406Sopenharmony_ci    return ret;
1716141cc406Sopenharmony_ci
1717141cc406Sopenharmony_ci  lines = size / bytes_per_line;
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_ci  buf = data;
1720141cc406Sopenharmony_ci  for (unsigned int i = 0; i < lines; buf += bytes_per_line, ++i)
1721141cc406Sopenharmony_ci    {
1722141cc406Sopenharmony_ci      if (! scanner->eop_last_line_data)
1723141cc406Sopenharmony_ci        {
1724141cc406Sopenharmony_ci          if (pixels_per_line > 0)
1725141cc406Sopenharmony_ci            {
1726141cc406Sopenharmony_ci              /* Test for last-line indicator pixel. If found, store last line
1727141cc406Sopenharmony_ci               * and optionally overwrite indicator pixel with neighbor value.
1728141cc406Sopenharmony_ci               */
1729141cc406Sopenharmony_ci              unsigned int j = bytes_per_line - 1;
1730141cc406Sopenharmony_ci              int eop_found = 0;
1731141cc406Sopenharmony_ci              if (scanner->depth == DEPTH_GRAY)
1732141cc406Sopenharmony_ci                {
1733141cc406Sopenharmony_ci                  eop_found = (buf[j] != 0);
1734141cc406Sopenharmony_ci                  if (scanner->overwrite_eop_pixel && (j > 0))
1735141cc406Sopenharmony_ci                    {
1736141cc406Sopenharmony_ci                      buf[j] = buf[j-1];
1737141cc406Sopenharmony_ci                    }
1738141cc406Sopenharmony_ci                }
1739141cc406Sopenharmony_ci              else if (scanner->depth == DEPTH_BW)
1740141cc406Sopenharmony_ci                {
1741141cc406Sopenharmony_ci                  eop_found = (buf[j] != 0);
1742141cc406Sopenharmony_ci                  if (scanner->overwrite_eop_pixel && (j > 0))
1743141cc406Sopenharmony_ci                    {
1744141cc406Sopenharmony_ci                      buf[j] = (buf[j-1] & 0x01) ? 0xff : 0;
1745141cc406Sopenharmony_ci                    }
1746141cc406Sopenharmony_ci                }
1747141cc406Sopenharmony_ci
1748141cc406Sopenharmony_ci              invert_negative_colors (buf, bytes_per_line, scanner);
1749141cc406Sopenharmony_ci
1750141cc406Sopenharmony_ci              if (eop_found && (! scanner->eop_last_line_data))
1751141cc406Sopenharmony_ci                {
1752141cc406Sopenharmony_ci                  DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", i);
1753141cc406Sopenharmony_ci                  scanner->eop_last_line_data = malloc(bytes_per_line);
1754141cc406Sopenharmony_ci                  if (! scanner->eop_last_line_data)
1755141cc406Sopenharmony_ci                    return SANE_STATUS_NO_MEM;
1756141cc406Sopenharmony_ci
1757141cc406Sopenharmony_ci                  memcpy (scanner->eop_last_line_data, buf, bytes_per_line);
1758141cc406Sopenharmony_ci                  scanner->eop_last_line_data_rpos = 0;
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci                  /* Fill trailing line buffer with requested color. */
1761141cc406Sopenharmony_ci                  if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER)
1762141cc406Sopenharmony_ci                    {
1763141cc406Sopenharmony_ci                      /* Black-white raster. */
1764141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_BW)
1765141cc406Sopenharmony_ci                        {
1766141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, 0xaa, bytes_per_line);
1767141cc406Sopenharmony_ci                        }
1768141cc406Sopenharmony_ci                      else
1769141cc406Sopenharmony_ci                        {
1770141cc406Sopenharmony_ci                          /* Gray. */
1771141cc406Sopenharmony_ci                          for (unsigned int k = 0; k < bytes_per_line; ++k)
1772141cc406Sopenharmony_ci                            {
1773141cc406Sopenharmony_ci                              scanner->eop_last_line_data[k] = (k & 1 ? 0xff : 0);
1774141cc406Sopenharmony_ci                            }
1775141cc406Sopenharmony_ci                        }
1776141cc406Sopenharmony_ci                    }
1777141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE)
1778141cc406Sopenharmony_ci                    {
1779141cc406Sopenharmony_ci                      /* White. */
1780141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_BW)
1781141cc406Sopenharmony_ci                        {
1782141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
1783141cc406Sopenharmony_ci                        }
1784141cc406Sopenharmony_ci                      else
1785141cc406Sopenharmony_ci                        {
1786141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
1787141cc406Sopenharmony_ci                        }
1788141cc406Sopenharmony_ci                    }
1789141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK)
1790141cc406Sopenharmony_ci                    {
1791141cc406Sopenharmony_ci                      /* Black. */
1792141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_BW)
1793141cc406Sopenharmony_ci                        {
1794141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
1795141cc406Sopenharmony_ci                        }
1796141cc406Sopenharmony_ci                      else
1797141cc406Sopenharmony_ci                        {
1798141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
1799141cc406Sopenharmony_ci                        }
1800141cc406Sopenharmony_ci                    }
1801141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR)
1802141cc406Sopenharmony_ci                    {
1803141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_BW)
1804141cc406Sopenharmony_ci                        {
1805141cc406Sopenharmony_ci                          /* Black or white. */
1806141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0x01 ? 0x00 : 0xff, bytes_per_line);
1807141cc406Sopenharmony_ci                        }
1808141cc406Sopenharmony_ci                      else
1809141cc406Sopenharmony_ci                        {
1810141cc406Sopenharmony_ci                          /* Gray value */
1811141cc406Sopenharmony_ci                          memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0xff, bytes_per_line);
1812141cc406Sopenharmony_ci                        }
1813141cc406Sopenharmony_ci                    }
1814141cc406Sopenharmony_ci                }
1815141cc406Sopenharmony_ci            }
1816141cc406Sopenharmony_ci        }
1817141cc406Sopenharmony_ci      else
1818141cc406Sopenharmony_ci        {
1819141cc406Sopenharmony_ci          DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n",
1820141cc406Sopenharmony_ci               i, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color);
1821141cc406Sopenharmony_ci
1822141cc406Sopenharmony_ci          if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
1823141cc406Sopenharmony_ci            {
1824141cc406Sopenharmony_ci              /* We are in in ADF mode after last-line and store next page data
1825141cc406Sopenharmony_ci               * to buffer.
1826141cc406Sopenharmony_ci               */
1827141cc406Sopenharmony_ci              if (! scanner->adf_next_page_lines_data)
1828141cc406Sopenharmony_ci                {
1829141cc406Sopenharmony_ci                  unsigned int n_rest_lines = lines - i;
1830141cc406Sopenharmony_ci                  unsigned int buf_size = n_rest_lines * bytes_per_line;
1831141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data = malloc(buf_size);
1832141cc406Sopenharmony_ci                  if (! scanner->adf_next_page_lines_data)
1833141cc406Sopenharmony_ci                    return SANE_STATUS_NO_MEM;
1834141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_size = buf_size;
1835141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_rpos = 0;
1836141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_wpos = 0;
1837141cc406Sopenharmony_ci                  DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines);
1838141cc406Sopenharmony_ci                }
1839141cc406Sopenharmony_ci              DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", i, lines);
1840141cc406Sopenharmony_ci              invert_negative_colors (buf, bytes_per_line, scanner);
1841141cc406Sopenharmony_ci              memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line);
1842141cc406Sopenharmony_ci              scanner->adf_next_page_lines_data_wpos += bytes_per_line;
1843141cc406Sopenharmony_ci            }
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_ci          if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW)
1846141cc406Sopenharmony_ci            {
1847141cc406Sopenharmony_ci              /* Copy last line data or corresponding color over trailing lines
1848141cc406Sopenharmony_ci               * data.
1849141cc406Sopenharmony_ci               */
1850141cc406Sopenharmony_ci              memcpy (buf, scanner->eop_last_line_data, bytes_per_line);
1851141cc406Sopenharmony_ci            }
1852141cc406Sopenharmony_ci        }
1853141cc406Sopenharmony_ci    }
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1856141cc406Sopenharmony_ci}
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci/******************************************************************************/
1859141cc406Sopenharmony_cistatic unsigned char
1860141cc406Sopenharmony_ciget_checked (unsigned char *ptr, unsigned int i, unsigned int length)
1861141cc406Sopenharmony_ci{
1862141cc406Sopenharmony_ci  if (i < length)
1863141cc406Sopenharmony_ci    {
1864141cc406Sopenharmony_ci      return ptr[i];
1865141cc406Sopenharmony_ci    }
1866141cc406Sopenharmony_ci  DBG (DBG_details, "get from array out of range: idx=%u, size=%u\n", i, length);
1867141cc406Sopenharmony_ci  return 0;
1868141cc406Sopenharmony_ci}
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci/******************************************************************************/
1871141cc406Sopenharmony_cistatic SANE_Status
1872141cc406Sopenharmony_ciconvert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
1873141cc406Sopenharmony_ci{
1874141cc406Sopenharmony_ci  unsigned int pixels_per_line;
1875141cc406Sopenharmony_ci  unsigned int pixel_bits;
1876141cc406Sopenharmony_ci  unsigned int bytes_per_color;
1877141cc406Sopenharmony_ci  unsigned int bytes_per_line;
1878141cc406Sopenharmony_ci  unsigned int bytes_per_line_limit;
1879141cc406Sopenharmony_ci  unsigned int lines;
1880141cc406Sopenharmony_ci  unsigned int i, j;
1881141cc406Sopenharmony_ci  unsigned char *buf;
1882141cc406Sopenharmony_ci  unsigned char *bufptr;
1883141cc406Sopenharmony_ci  unsigned char *ptr;
1884141cc406Sopenharmony_ci  SANE_Status   ret;
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci  hp5590_assert (scanner != NULL);
1887141cc406Sopenharmony_ci  hp5590_assert (data != NULL);
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_ci  if ( ! (scanner->depth == DEPTH_COLOR_24 || scanner->depth == DEPTH_COLOR_48))
1890141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
1893141cc406Sopenharmony_ci
1894141cc406Sopenharmony_ci#ifndef HAS_WORKING_COLOR_48
1895141cc406Sopenharmony_ci  if (scanner->depth == DEPTH_COLOR_48)
1896141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1897141cc406Sopenharmony_ci#endif
1898141cc406Sopenharmony_ci
1899141cc406Sopenharmony_ci  ret = calc_image_params (scanner,
1900141cc406Sopenharmony_ci                           &pixel_bits,
1901141cc406Sopenharmony_ci                           &pixels_per_line, &bytes_per_line,
1902141cc406Sopenharmony_ci                           NULL, NULL);
1903141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1904141cc406Sopenharmony_ci    return ret;
1905141cc406Sopenharmony_ci
1906141cc406Sopenharmony_ci  lines = size / bytes_per_line;
1907141cc406Sopenharmony_ci  bytes_per_color = (pixel_bits + 7) / 8;
1908141cc406Sopenharmony_ci
1909141cc406Sopenharmony_ci  bytes_per_line_limit = bytes_per_line;
1910141cc406Sopenharmony_ci  if ((scanner->depth == DEPTH_COLOR_48) && (bytes_per_line_limit > 3))
1911141cc406Sopenharmony_ci    {
1912141cc406Sopenharmony_ci      /* Last-line indicator pixel has only 3 bytes instead of 6. */
1913141cc406Sopenharmony_ci      bytes_per_line_limit -= 3;
1914141cc406Sopenharmony_ci    }
1915141cc406Sopenharmony_ci
1916141cc406Sopenharmony_ci  DBG (DBG_verbose, "Length : %u\n", size);
1917141cc406Sopenharmony_ci
1918141cc406Sopenharmony_ci  DBG (DBG_verbose, "Converting row RGB to normal RGB\n");
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci  DBG (DBG_verbose, "Bytes per line %u\n", bytes_per_line);
1921141cc406Sopenharmony_ci  DBG (DBG_verbose, "Bytes per line limited %u\n", bytes_per_line_limit);
1922141cc406Sopenharmony_ci  DBG (DBG_verbose, "Bytes per color %u\n", bytes_per_color);
1923141cc406Sopenharmony_ci  DBG (DBG_verbose, "Pixels per line %u\n", pixels_per_line);
1924141cc406Sopenharmony_ci  DBG (DBG_verbose, "Lines %u\n", lines);
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci  /* Use working buffer for color mapping. */
1927141cc406Sopenharmony_ci  bufptr = malloc (size);
1928141cc406Sopenharmony_ci  if (! bufptr)
1929141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1930141cc406Sopenharmony_ci  memset (bufptr, 0, size);
1931141cc406Sopenharmony_ci  buf = bufptr;
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci  ptr = data;
1934141cc406Sopenharmony_ci  for (j = 0; j < lines; ptr += bytes_per_line_limit, buf += bytes_per_line, j++)
1935141cc406Sopenharmony_ci    {
1936141cc406Sopenharmony_ci      for (i = 0; i < pixels_per_line; i++)
1937141cc406Sopenharmony_ci        {
1938141cc406Sopenharmony_ci          /* Color mapping from raw scanner data to RGB buffer. */
1939141cc406Sopenharmony_ci          if (scanner->depth == DEPTH_COLOR_24)
1940141cc406Sopenharmony_ci            {
1941141cc406Sopenharmony_ci              /* R */
1942141cc406Sopenharmony_ci              buf[i*3]   = get_checked(ptr, i, bytes_per_line_limit);
1943141cc406Sopenharmony_ci              /* G */
1944141cc406Sopenharmony_ci              buf[i*3+1] = get_checked(ptr, i+pixels_per_line, bytes_per_line_limit);;
1945141cc406Sopenharmony_ci              /* B */
1946141cc406Sopenharmony_ci              buf[i*3+2] = get_checked(ptr, i+pixels_per_line*2, bytes_per_line_limit);
1947141cc406Sopenharmony_ci            }
1948141cc406Sopenharmony_ci          else if (scanner->depth == DEPTH_COLOR_48)
1949141cc406Sopenharmony_ci            {
1950141cc406Sopenharmony_ci              /* Note: The last-line indicator pixel uses only 24 bits, not 48.
1951141cc406Sopenharmony_ci               *Blue uses offset of 2 bytes. Green swaps lo and hi.
1952141cc406Sopenharmony_ci               */
1953141cc406Sopenharmony_ci              /* R lo, hi*/
1954141cc406Sopenharmony_ci              buf[i*6]   = get_checked(ptr, 2*i+(pixels_per_line-1)*0+1, bytes_per_line_limit);
1955141cc406Sopenharmony_ci              buf[i*6+1] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+0, bytes_per_line_limit);
1956141cc406Sopenharmony_ci              /* G lo, hi*/
1957141cc406Sopenharmony_ci              buf[i*6+2] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+0, bytes_per_line_limit);
1958141cc406Sopenharmony_ci              buf[i*6+3] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+1, bytes_per_line_limit);
1959141cc406Sopenharmony_ci              /* B lo, hi*/
1960141cc406Sopenharmony_ci              buf[i*6+4] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+1+2, bytes_per_line_limit);
1961141cc406Sopenharmony_ci              buf[i*6+5] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+0+2, bytes_per_line_limit);
1962141cc406Sopenharmony_ci            }
1963141cc406Sopenharmony_ci        }
1964141cc406Sopenharmony_ci
1965141cc406Sopenharmony_ci      if (! scanner->eop_last_line_data)
1966141cc406Sopenharmony_ci        {
1967141cc406Sopenharmony_ci          if (pixels_per_line > 0)
1968141cc406Sopenharmony_ci            {
1969141cc406Sopenharmony_ci              /* Test for last-line indicator pixel on blue. If found, store
1970141cc406Sopenharmony_ci               * last line and optionally overwrite indicator pixel with
1971141cc406Sopenharmony_ci               * neighbor value.
1972141cc406Sopenharmony_ci               */
1973141cc406Sopenharmony_ci              i = pixels_per_line - 1;
1974141cc406Sopenharmony_ci              int eop_found = 0;
1975141cc406Sopenharmony_ci              if (scanner->depth == DEPTH_COLOR_24)
1976141cc406Sopenharmony_ci                {
1977141cc406Sopenharmony_ci                  /* DBG (DBG_details, "BUF24: %u %u %u\n", buf[i*3], buf[i*3+1], buf[i*3+2]); */
1978141cc406Sopenharmony_ci                  eop_found = (buf[i*3+2] != 0);
1979141cc406Sopenharmony_ci                  if (scanner->overwrite_eop_pixel && (i > 0))
1980141cc406Sopenharmony_ci                    {
1981141cc406Sopenharmony_ci                      buf[i*3] = buf[(i-1)*3];
1982141cc406Sopenharmony_ci                      buf[i*3+1] = buf[(i-1)*3+1];
1983141cc406Sopenharmony_ci                      buf[i*3+2] = buf[(i-1)*3+2];
1984141cc406Sopenharmony_ci                    }
1985141cc406Sopenharmony_ci                }
1986141cc406Sopenharmony_ci              else if (scanner->depth == DEPTH_COLOR_48)
1987141cc406Sopenharmony_ci                {
1988141cc406Sopenharmony_ci                  /* DBG (DBG_details, "BUF48: %u %u %u\n", buf[i*6+1], buf[i*6+3], buf[i*6+5]); */
1989141cc406Sopenharmony_ci                  eop_found = (buf[i*6+5] != 0);
1990141cc406Sopenharmony_ci                  if (scanner->overwrite_eop_pixel && (i > 0))
1991141cc406Sopenharmony_ci                    {
1992141cc406Sopenharmony_ci                      buf[i*6] = buf[(i-1)*6];
1993141cc406Sopenharmony_ci                      buf[i*6+1] = buf[(i-1)*6+1];
1994141cc406Sopenharmony_ci                      buf[i*6+2] = buf[(i-1)*6+2];
1995141cc406Sopenharmony_ci                      buf[i*6+3] = buf[(i-1)*6+3];
1996141cc406Sopenharmony_ci                      buf[i*6+4] = buf[(i-1)*6+4];
1997141cc406Sopenharmony_ci                      buf[i*6+5] = buf[(i-1)*6+5];
1998141cc406Sopenharmony_ci                    }
1999141cc406Sopenharmony_ci                }
2000141cc406Sopenharmony_ci
2001141cc406Sopenharmony_ci              invert_negative_colors (buf, bytes_per_line, scanner);
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci              if (eop_found && (! scanner->eop_last_line_data))
2004141cc406Sopenharmony_ci                {
2005141cc406Sopenharmony_ci                  DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", j);
2006141cc406Sopenharmony_ci                  scanner->eop_last_line_data = malloc(bytes_per_line);
2007141cc406Sopenharmony_ci                  if (! scanner->eop_last_line_data)
2008141cc406Sopenharmony_ci                    return SANE_STATUS_NO_MEM;
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci                  memcpy (scanner->eop_last_line_data, buf, bytes_per_line);
2011141cc406Sopenharmony_ci                  scanner->eop_last_line_data_rpos = 0;
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci                  /* Fill trailing line buffer with requested color. */
2014141cc406Sopenharmony_ci                  if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER)
2015141cc406Sopenharmony_ci                    {
2016141cc406Sopenharmony_ci                      /* Black-white raster. */
2017141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_COLOR_24)
2018141cc406Sopenharmony_ci                        {
2019141cc406Sopenharmony_ci                          for (unsigned int k = 0; k < bytes_per_line; ++k)
2020141cc406Sopenharmony_ci                            {
2021141cc406Sopenharmony_ci                              scanner->eop_last_line_data[k] = (k % 6 < 3 ? 0xff : 0);
2022141cc406Sopenharmony_ci                            }
2023141cc406Sopenharmony_ci                        }
2024141cc406Sopenharmony_ci                      else
2025141cc406Sopenharmony_ci                        {
2026141cc406Sopenharmony_ci                          /* Color48. */
2027141cc406Sopenharmony_ci                          for (unsigned int k = 0; k < bytes_per_line; ++k)
2028141cc406Sopenharmony_ci                            {
2029141cc406Sopenharmony_ci                              scanner->eop_last_line_data[k] = (k % 12 < 6 ? 0xff : 0);
2030141cc406Sopenharmony_ci                            }
2031141cc406Sopenharmony_ci                        }
2032141cc406Sopenharmony_ci                    }
2033141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE)
2034141cc406Sopenharmony_ci                    {
2035141cc406Sopenharmony_ci                      memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
2036141cc406Sopenharmony_ci                    }
2037141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK)
2038141cc406Sopenharmony_ci                    {
2039141cc406Sopenharmony_ci                      memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
2040141cc406Sopenharmony_ci                    }
2041141cc406Sopenharmony_ci                  else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR)
2042141cc406Sopenharmony_ci                    {
2043141cc406Sopenharmony_ci                      /* RGB color value. */
2044141cc406Sopenharmony_ci                      int rgb[3];
2045141cc406Sopenharmony_ci                      rgb[0] = (scanner->eop_trailing_lines_color >> 16) & 0xff;
2046141cc406Sopenharmony_ci                      rgb[1] = (scanner->eop_trailing_lines_color >> 8) & 0xff;
2047141cc406Sopenharmony_ci                      rgb[2] = scanner->eop_trailing_lines_color & 0xff;
2048141cc406Sopenharmony_ci                      if (scanner->depth == DEPTH_COLOR_24)
2049141cc406Sopenharmony_ci                        {
2050141cc406Sopenharmony_ci                          for (unsigned int k = 0; k < bytes_per_line; ++k)
2051141cc406Sopenharmony_ci                            {
2052141cc406Sopenharmony_ci                              scanner->eop_last_line_data[k] = rgb[k % 3];
2053141cc406Sopenharmony_ci                            }
2054141cc406Sopenharmony_ci                        }
2055141cc406Sopenharmony_ci                      else
2056141cc406Sopenharmony_ci                        {
2057141cc406Sopenharmony_ci                          /* Color48. */
2058141cc406Sopenharmony_ci                          for (unsigned int k = 0; k < bytes_per_line; ++k)
2059141cc406Sopenharmony_ci                            {
2060141cc406Sopenharmony_ci                              scanner->eop_last_line_data[k] = rgb[(k % 6) >> 1];
2061141cc406Sopenharmony_ci                            }
2062141cc406Sopenharmony_ci                        }
2063141cc406Sopenharmony_ci                    }
2064141cc406Sopenharmony_ci                }
2065141cc406Sopenharmony_ci            }
2066141cc406Sopenharmony_ci        }
2067141cc406Sopenharmony_ci      else
2068141cc406Sopenharmony_ci        {
2069141cc406Sopenharmony_ci          DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n",
2070141cc406Sopenharmony_ci               j, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color);
2071141cc406Sopenharmony_ci
2072141cc406Sopenharmony_ci          if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
2073141cc406Sopenharmony_ci            {
2074141cc406Sopenharmony_ci              /* We are in in ADF mode after last-line and store next page data
2075141cc406Sopenharmony_ci               * to buffer.
2076141cc406Sopenharmony_ci               */
2077141cc406Sopenharmony_ci              if (! scanner->adf_next_page_lines_data)
2078141cc406Sopenharmony_ci                {
2079141cc406Sopenharmony_ci                  unsigned int n_rest_lines = lines - j;
2080141cc406Sopenharmony_ci                  unsigned int buf_size = n_rest_lines * bytes_per_line;
2081141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data = malloc(buf_size);
2082141cc406Sopenharmony_ci                  if (! scanner->adf_next_page_lines_data)
2083141cc406Sopenharmony_ci                    return SANE_STATUS_NO_MEM;
2084141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_size = buf_size;
2085141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_rpos = 0;
2086141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_wpos = 0;
2087141cc406Sopenharmony_ci                  DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines);
2088141cc406Sopenharmony_ci                }
2089141cc406Sopenharmony_ci              DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", j, lines);
2090141cc406Sopenharmony_ci              invert_negative_colors (buf, bytes_per_line, scanner);
2091141cc406Sopenharmony_ci              memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line);
2092141cc406Sopenharmony_ci              scanner->adf_next_page_lines_data_wpos += bytes_per_line;
2093141cc406Sopenharmony_ci            }
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci          if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW)
2096141cc406Sopenharmony_ci            {
2097141cc406Sopenharmony_ci              /* Copy last line data or corresponding color over trailing lines
2098141cc406Sopenharmony_ci               * data.
2099141cc406Sopenharmony_ci               */
2100141cc406Sopenharmony_ci              memcpy (buf, scanner->eop_last_line_data, bytes_per_line);
2101141cc406Sopenharmony_ci            }
2102141cc406Sopenharmony_ci        }
2103141cc406Sopenharmony_ci    }
2104141cc406Sopenharmony_ci  memcpy (data, bufptr, size);
2105141cc406Sopenharmony_ci  free (bufptr);
2106141cc406Sopenharmony_ci
2107141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2108141cc406Sopenharmony_ci}
2109141cc406Sopenharmony_ci
2110141cc406Sopenharmony_ci/******************************************************************************/
2111141cc406Sopenharmony_cistatic void
2112141cc406Sopenharmony_ciread_data_from_temporary_buffer(struct hp5590_scanner *scanner,
2113141cc406Sopenharmony_ci    SANE_Byte * data, unsigned int max_length,
2114141cc406Sopenharmony_ci    unsigned int bytes_per_line, SANE_Int *length)
2115141cc406Sopenharmony_ci{
2116141cc406Sopenharmony_ci  *length = 0;
2117141cc406Sopenharmony_ci  if (scanner && scanner->one_line_read_buffer)
2118141cc406Sopenharmony_ci  {
2119141cc406Sopenharmony_ci    /* Copy scan data from temporary read buffer and return size copied data. */
2120141cc406Sopenharmony_ci    /* Release buffer, when no data left. */
2121141cc406Sopenharmony_ci    unsigned int rest_len;
2122141cc406Sopenharmony_ci    rest_len = bytes_per_line - scanner->one_line_read_buffer_rpos;
2123141cc406Sopenharmony_ci    rest_len = (rest_len < max_length) ? rest_len : max_length;
2124141cc406Sopenharmony_ci    if (rest_len > 0)
2125141cc406Sopenharmony_ci      {
2126141cc406Sopenharmony_ci        memcpy (data, scanner->one_line_read_buffer + scanner->one_line_read_buffer_rpos, rest_len);
2127141cc406Sopenharmony_ci        scanner->one_line_read_buffer_rpos += rest_len;
2128141cc406Sopenharmony_ci        scanner->transferred_image_size -= rest_len;
2129141cc406Sopenharmony_ci        *length = rest_len;
2130141cc406Sopenharmony_ci      }
2131141cc406Sopenharmony_ci
2132141cc406Sopenharmony_ci    DBG (DBG_verbose, "Copy scan data from temporary buffer: length = %u, rest in buffer = %u.\n",
2133141cc406Sopenharmony_ci        *length, bytes_per_line - scanner->one_line_read_buffer_rpos);
2134141cc406Sopenharmony_ci
2135141cc406Sopenharmony_ci    if (scanner->one_line_read_buffer_rpos >= bytes_per_line)
2136141cc406Sopenharmony_ci      {
2137141cc406Sopenharmony_ci        DBG (DBG_verbose, "Release temporary buffer.\n");
2138141cc406Sopenharmony_ci        free (scanner->one_line_read_buffer);
2139141cc406Sopenharmony_ci        scanner->one_line_read_buffer = NULL;
2140141cc406Sopenharmony_ci        scanner->one_line_read_buffer_rpos = 0;
2141141cc406Sopenharmony_ci      }
2142141cc406Sopenharmony_ci  }
2143141cc406Sopenharmony_ci}
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci/******************************************************************************/
2146141cc406Sopenharmony_cistatic SANE_Status
2147141cc406Sopenharmony_cisane_read_internal (struct hp5590_scanner * scanner, SANE_Byte * data,
2148141cc406Sopenharmony_ci    SANE_Int max_length, SANE_Int * length, unsigned int bytes_per_line)
2149141cc406Sopenharmony_ci{
2150141cc406Sopenharmony_ci  SANE_Status ret;
2151141cc406Sopenharmony_ci
2152141cc406Sopenharmony_ci  DBG (DBG_proc, "%s, length %u, left %llu\n",
2153141cc406Sopenharmony_ci       __func__,
2154141cc406Sopenharmony_ci       max_length,
2155141cc406Sopenharmony_ci       scanner->transferred_image_size);
2156141cc406Sopenharmony_ci
2157141cc406Sopenharmony_ci  SANE_Int length_limited = 0;
2158141cc406Sopenharmony_ci  *length = max_length;
2159141cc406Sopenharmony_ci  if ((unsigned long long) *length > scanner->transferred_image_size)
2160141cc406Sopenharmony_ci    *length = (SANE_Int) scanner->transferred_image_size;
2161141cc406Sopenharmony_ci
2162141cc406Sopenharmony_ci  /* Align reading size to bytes per line. */
2163141cc406Sopenharmony_ci  *length -= *length % bytes_per_line;
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci  if (scanner->depth == DEPTH_COLOR_48)
2166141cc406Sopenharmony_ci    {
2167141cc406Sopenharmony_ci      /* Note: The last-line indicator pixel uses only 24 bits (3 bytes), not
2168141cc406Sopenharmony_ci       * 48 bits (6 bytes).
2169141cc406Sopenharmony_ci       */
2170141cc406Sopenharmony_ci      if (bytes_per_line > 3)
2171141cc406Sopenharmony_ci        {
2172141cc406Sopenharmony_ci          length_limited = *length - *length % (bytes_per_line - 3);
2173141cc406Sopenharmony_ci        }
2174141cc406Sopenharmony_ci    }
2175141cc406Sopenharmony_ci
2176141cc406Sopenharmony_ci  DBG (DBG_verbose, "Aligning requested size to bytes per line "
2177141cc406Sopenharmony_ci      "(requested: %d, aligned: %u, limit_for_48bit: %u)\n",
2178141cc406Sopenharmony_ci      max_length, *length, length_limited);
2179141cc406Sopenharmony_ci
2180141cc406Sopenharmony_ci  if (max_length <= 0)
2181141cc406Sopenharmony_ci    {
2182141cc406Sopenharmony_ci      DBG (DBG_verbose, "Buffer too small for one scan line. Need at least %u bytes per line.\n",
2183141cc406Sopenharmony_ci          bytes_per_line);
2184141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
2185141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2186141cc406Sopenharmony_ci    }
2187141cc406Sopenharmony_ci
2188141cc406Sopenharmony_ci  if (scanner->one_line_read_buffer)
2189141cc406Sopenharmony_ci    {
2190141cc406Sopenharmony_ci      /* Copy scan data from temporary read buffer. */
2191141cc406Sopenharmony_ci      read_data_from_temporary_buffer (scanner, data, max_length, bytes_per_line, length);
2192141cc406Sopenharmony_ci      if (*length > 0)
2193141cc406Sopenharmony_ci        {
2194141cc406Sopenharmony_ci          DBG (DBG_verbose, "Return %d bytes, left %llu bytes.\n", *length, scanner->transferred_image_size);
2195141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
2196141cc406Sopenharmony_ci        }
2197141cc406Sopenharmony_ci    }
2198141cc406Sopenharmony_ci
2199141cc406Sopenharmony_ci  /* Buffer to return scanned data. We need at least space for one line to
2200141cc406Sopenharmony_ci   * simplify color processing and last-line detection. If call buffer is too
2201141cc406Sopenharmony_ci   * small, use temporary read buffer for reading one line instead.
2202141cc406Sopenharmony_ci   */
2203141cc406Sopenharmony_ci  SANE_Byte * scan_data;
2204141cc406Sopenharmony_ci  SANE_Int scan_data_length;
2205141cc406Sopenharmony_ci  scan_data = data;
2206141cc406Sopenharmony_ci  scan_data_length = *length;
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_ci  /* Note, read length is shorter in 48bit mode. */
2209141cc406Sopenharmony_ci  SANE_Int length_for_read = length_limited ? length_limited : scan_data_length;
2210141cc406Sopenharmony_ci  if (length_for_read == 0)
2211141cc406Sopenharmony_ci    {
2212141cc406Sopenharmony_ci      /* Call buffer is too small for one line. Use temporary read buffer
2213141cc406Sopenharmony_ci       * instead.
2214141cc406Sopenharmony_ci       */
2215141cc406Sopenharmony_ci      if (! scanner->one_line_read_buffer)
2216141cc406Sopenharmony_ci        {
2217141cc406Sopenharmony_ci          scanner->one_line_read_buffer = malloc (bytes_per_line);
2218141cc406Sopenharmony_ci          if (! scanner->one_line_read_buffer)
2219141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
2220141cc406Sopenharmony_ci          memset (scanner->one_line_read_buffer, 0, bytes_per_line);
2221141cc406Sopenharmony_ci        }
2222141cc406Sopenharmony_ci
2223141cc406Sopenharmony_ci      DBG (DBG_verbose, "Call buffer too small for one scan line. Use temporary read buffer for one line with %u bytes.\n",
2224141cc406Sopenharmony_ci          bytes_per_line);
2225141cc406Sopenharmony_ci
2226141cc406Sopenharmony_ci      /* Scan and process next line in temporary buffer. */
2227141cc406Sopenharmony_ci      scan_data = scanner->one_line_read_buffer;
2228141cc406Sopenharmony_ci      scan_data_length = bytes_per_line;
2229141cc406Sopenharmony_ci      length_for_read = bytes_per_line;
2230141cc406Sopenharmony_ci      if (scanner->depth == DEPTH_COLOR_48)
2231141cc406Sopenharmony_ci        {
2232141cc406Sopenharmony_ci          /* The last-line indicator pixel uses only 24 bits (3 bytes), not 48
2233141cc406Sopenharmony_ci           * bits (6 bytes).
2234141cc406Sopenharmony_ci           */
2235141cc406Sopenharmony_ci          if (length_for_read > 3)
2236141cc406Sopenharmony_ci            {
2237141cc406Sopenharmony_ci              length_for_read -= 3;
2238141cc406Sopenharmony_ci            }
2239141cc406Sopenharmony_ci        }
2240141cc406Sopenharmony_ci    }
2241141cc406Sopenharmony_ci
2242141cc406Sopenharmony_ci  int read_from_scanner = 1;
2243141cc406Sopenharmony_ci  if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
2244141cc406Sopenharmony_ci    {
2245141cc406Sopenharmony_ci      if (scanner->eop_last_line_data)
2246141cc406Sopenharmony_ci        {
2247141cc406Sopenharmony_ci          /* Scanner is in ADF mode between last-line of previous page and
2248141cc406Sopenharmony_ci           * start of next page.
2249141cc406Sopenharmony_ci           * Fill remaining lines with last-line data.
2250141cc406Sopenharmony_ci           */
2251141cc406Sopenharmony_ci          unsigned int wpos = 0;
2252141cc406Sopenharmony_ci          while (wpos < (unsigned int) scan_data_length)
2253141cc406Sopenharmony_ci            {
2254141cc406Sopenharmony_ci              unsigned int n1 = scan_data_length - wpos;
2255141cc406Sopenharmony_ci              unsigned int n2 = bytes_per_line - scanner->eop_last_line_data_rpos;
2256141cc406Sopenharmony_ci              n1 = (n1 < n2) ? n1 : n2;
2257141cc406Sopenharmony_ci              memcpy (scan_data + wpos, scanner->eop_last_line_data + scanner->eop_last_line_data_rpos, n1);
2258141cc406Sopenharmony_ci              wpos += n1;
2259141cc406Sopenharmony_ci              scanner->eop_last_line_data_rpos += n1;
2260141cc406Sopenharmony_ci              if (scanner->eop_last_line_data_rpos >= bytes_per_line)
2261141cc406Sopenharmony_ci                scanner->eop_last_line_data_rpos = 0;
2262141cc406Sopenharmony_ci            }
2263141cc406Sopenharmony_ci          read_from_scanner = (wpos == 0);
2264141cc406Sopenharmony_ci          DBG (DBG_verbose, "ADF use last-line data, wlength=%u, length=%u\n", wpos, scan_data_length);
2265141cc406Sopenharmony_ci        }
2266141cc406Sopenharmony_ci      else if (scanner->adf_next_page_lines_data)
2267141cc406Sopenharmony_ci        {
2268141cc406Sopenharmony_ci          /* Scanner is in ADF mode at start of next page and already some next
2269141cc406Sopenharmony_ci           * page data is available from earlier read operation. Return this
2270141cc406Sopenharmony_ci           * data.
2271141cc406Sopenharmony_ci           */
2272141cc406Sopenharmony_ci          unsigned int wpos = 0;
2273141cc406Sopenharmony_ci          while ((wpos < (unsigned int) scan_data_length) &&
2274141cc406Sopenharmony_ci                 (scanner->adf_next_page_lines_data_rpos < scanner->adf_next_page_lines_data_size))
2275141cc406Sopenharmony_ci            {
2276141cc406Sopenharmony_ci              unsigned int n1 = scan_data_length - wpos;
2277141cc406Sopenharmony_ci              unsigned int n2 = scanner->adf_next_page_lines_data_size - scanner->adf_next_page_lines_data_rpos;
2278141cc406Sopenharmony_ci              n1 = (n1 < n2) ? n1 : n2;
2279141cc406Sopenharmony_ci              memcpy (scan_data + wpos, scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_rpos, n1);
2280141cc406Sopenharmony_ci              wpos += n1;
2281141cc406Sopenharmony_ci              scanner->adf_next_page_lines_data_rpos += n1;
2282141cc406Sopenharmony_ci              if (scanner->adf_next_page_lines_data_rpos >= scanner->adf_next_page_lines_data_size)
2283141cc406Sopenharmony_ci                {
2284141cc406Sopenharmony_ci                  free (scanner->adf_next_page_lines_data);
2285141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data = NULL;
2286141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_size = 0;
2287141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_rpos = 0;
2288141cc406Sopenharmony_ci                  scanner->adf_next_page_lines_data_wpos = 0;
2289141cc406Sopenharmony_ci                }
2290141cc406Sopenharmony_ci            }
2291141cc406Sopenharmony_ci          scan_data_length = wpos;
2292141cc406Sopenharmony_ci          read_from_scanner = (wpos == 0);
2293141cc406Sopenharmony_ci          DBG (DBG_verbose, "ADF use next-page data, wlength=%u, length=%u\n", wpos, scan_data_length);
2294141cc406Sopenharmony_ci        }
2295141cc406Sopenharmony_ci    }
2296141cc406Sopenharmony_ci
2297141cc406Sopenharmony_ci  if (read_from_scanner)
2298141cc406Sopenharmony_ci    {
2299141cc406Sopenharmony_ci      /* Read data from scanner. */
2300141cc406Sopenharmony_ci      ret = hp5590_read (scanner->dn, scanner->proto_flags,
2301141cc406Sopenharmony_ci                         scan_data, length_for_read,
2302141cc406Sopenharmony_ci                         scanner->bulk_read_state);
2303141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
2304141cc406Sopenharmony_ci        {
2305141cc406Sopenharmony_ci          scanner->scanning = SANE_FALSE;
2306141cc406Sopenharmony_ci          return ret;
2307141cc406Sopenharmony_ci        }
2308141cc406Sopenharmony_ci
2309141cc406Sopenharmony_ci      /* Look for last-line indicator pixels in convert functions.
2310141cc406Sopenharmony_ci       * If found:
2311141cc406Sopenharmony_ci       *   - Overwrite indicator pixel with neighboring color (optional).
2312141cc406Sopenharmony_ci       *   - Save last line data for later use.
2313141cc406Sopenharmony_ci       */
2314141cc406Sopenharmony_ci      ret = convert_to_rgb (scanner, scan_data, scan_data_length);
2315141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
2316141cc406Sopenharmony_ci        {
2317141cc406Sopenharmony_ci          scanner->scanning = SANE_FALSE;
2318141cc406Sopenharmony_ci          return ret;
2319141cc406Sopenharmony_ci        }
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci      ret = convert_gray_and_lineart (scanner, scan_data, scan_data_length);
2322141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
2323141cc406Sopenharmony_ci        return ret;
2324141cc406Sopenharmony_ci    }
2325141cc406Sopenharmony_ci
2326141cc406Sopenharmony_ci  if (data == scan_data)
2327141cc406Sopenharmony_ci    {
2328141cc406Sopenharmony_ci      /* Scanned to call buffer. */
2329141cc406Sopenharmony_ci      scanner->transferred_image_size -= scan_data_length;
2330141cc406Sopenharmony_ci      *length = scan_data_length;
2331141cc406Sopenharmony_ci    }
2332141cc406Sopenharmony_ci  else
2333141cc406Sopenharmony_ci    {
2334141cc406Sopenharmony_ci      /* Scanned to temporary read buffer. */
2335141cc406Sopenharmony_ci      if (scanner->one_line_read_buffer)
2336141cc406Sopenharmony_ci        {
2337141cc406Sopenharmony_ci          /* Copy scan data from temporary read buffer. */
2338141cc406Sopenharmony_ci          read_data_from_temporary_buffer (scanner, data, max_length, scan_data_length, length);
2339141cc406Sopenharmony_ci        }
2340141cc406Sopenharmony_ci      else
2341141cc406Sopenharmony_ci        {
2342141cc406Sopenharmony_ci          *length = 0;
2343141cc406Sopenharmony_ci        }
2344141cc406Sopenharmony_ci    }
2345141cc406Sopenharmony_ci
2346141cc406Sopenharmony_ci  DBG (DBG_verbose, "Return %d bytes, left %llu bytes\n", *length, scanner->transferred_image_size);
2347141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2348141cc406Sopenharmony_ci}
2349141cc406Sopenharmony_ci
2350141cc406Sopenharmony_ci/******************************************************************************
2351141cc406Sopenharmony_ci * Copy at maximum the last n lines from the src buffer to the begin of the dst
2352141cc406Sopenharmony_ci * buffer.
2353141cc406Sopenharmony_ci * Return number of lines copied.
2354141cc406Sopenharmony_ci */
2355141cc406Sopenharmony_cistatic SANE_Int
2356141cc406Sopenharmony_cicopy_n_last_lines(SANE_Byte * src, SANE_Int src_len, SANE_Byte * dst, SANE_Int n, unsigned int bytes_per_line)
2357141cc406Sopenharmony_ci{
2358141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2359141cc406Sopenharmony_ci  SANE_Int n_copy = MY_MIN(src_len, n);
2360141cc406Sopenharmony_ci  SANE_Byte * src1 = src + (src_len - n_copy) * bytes_per_line;
2361141cc406Sopenharmony_ci  memcpy (dst, src1, n_copy * bytes_per_line);
2362141cc406Sopenharmony_ci  return n_copy;
2363141cc406Sopenharmony_ci}
2364141cc406Sopenharmony_ci
2365141cc406Sopenharmony_ci/******************************************************************************
2366141cc406Sopenharmony_ci * Copy the color values from line - delta_lines to line.
2367141cc406Sopenharmony_ci * buffer2 : Source and target buffer.
2368141cc406Sopenharmony_ci * buffer1 : Only source buffer. Contains lines scanned before lines in buffer1.
2369141cc406Sopenharmony_ci * color_idx : Index of color to be copied (0..2).
2370141cc406Sopenharmony_ci * delta_lines : color shift.
2371141cc406Sopenharmony_ci * color_48 : True = 2 byte , false = 1 byte per color.
2372141cc406Sopenharmony_ci */
2373141cc406Sopenharmony_cistatic void
2374141cc406Sopenharmony_cishift_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)
2375141cc406Sopenharmony_ci{
2376141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2377141cc406Sopenharmony_ci  for (SANE_Int i = n_lines2 - 1; i >= 0; --i) {
2378141cc406Sopenharmony_ci    SANE_Byte * dst = buffer2 + i * bytes_per_line;
2379141cc406Sopenharmony_ci    SANE_Int ii = i - delta_lines;
2380141cc406Sopenharmony_ci    SANE_Byte * src = NULL;
2381141cc406Sopenharmony_ci    SANE_Int source_color_idx = color_idx;
2382141cc406Sopenharmony_ci    if (ii >= 0) {
2383141cc406Sopenharmony_ci      /* Read from source and target buffer. */
2384141cc406Sopenharmony_ci      src = buffer2 + ii * bytes_per_line;
2385141cc406Sopenharmony_ci    } else {
2386141cc406Sopenharmony_ci      ii += n_lines1;
2387141cc406Sopenharmony_ci      if (ii >= 0) {
2388141cc406Sopenharmony_ci        /* Read from source only buffer. */
2389141cc406Sopenharmony_ci        src = buffer1 + ii * bytes_per_line;
2390141cc406Sopenharmony_ci      } else {
2391141cc406Sopenharmony_ci        /* Read other color from source position. */
2392141cc406Sopenharmony_ci        src = dst;
2393141cc406Sopenharmony_ci        source_color_idx = 2;
2394141cc406Sopenharmony_ci      }
2395141cc406Sopenharmony_ci    }
2396141cc406Sopenharmony_ci    /* Copy selected color values. */
2397141cc406Sopenharmony_ci    SANE_Int step = color_48 ? 2 : 1;
2398141cc406Sopenharmony_ci    SANE_Int stride = 3 * step;
2399141cc406Sopenharmony_ci    for (unsigned int pos = 0; pos < bytes_per_line; pos += stride) {
2400141cc406Sopenharmony_ci      SANE_Int p1 = pos + step * source_color_idx;
2401141cc406Sopenharmony_ci      SANE_Int p2 = pos + step * color_idx;
2402141cc406Sopenharmony_ci      dst[p2] = src[p1];
2403141cc406Sopenharmony_ci      if (color_48) {
2404141cc406Sopenharmony_ci        dst[p2 + 1] = src[p1 + 1];
2405141cc406Sopenharmony_ci      }
2406141cc406Sopenharmony_ci    }
2407141cc406Sopenharmony_ci  }
2408141cc406Sopenharmony_ci}
2409141cc406Sopenharmony_ci
2410141cc406Sopenharmony_ci/******************************************************************************
2411141cc406Sopenharmony_ci * Append all lines from buffer2 to the end of buffer1 and keep max_lines last
2412141cc406Sopenharmony_ci * lines.
2413141cc406Sopenharmony_ci * buffer2 : Source line buffer.
2414141cc406Sopenharmony_ci * buffer1 : Target line buffer. Length will be adjusted.
2415141cc406Sopenharmony_ci * max_lines : Max number of lines in buffer1.
2416141cc406Sopenharmony_ci */
2417141cc406Sopenharmony_cistatic void
2418141cc406Sopenharmony_ciappend_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)
2419141cc406Sopenharmony_ci{
2420141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2421141cc406Sopenharmony_ci  SANE_Int rest1 = max_lines - *n_lines1_ptr;
2422141cc406Sopenharmony_ci  SANE_Int copy2 = MY_MIN(n_lines2, max_lines);
2423141cc406Sopenharmony_ci  if (copy2 > rest1) {
2424141cc406Sopenharmony_ci    SANE_Int shift1 = *n_lines1_ptr + copy2 - max_lines;
2425141cc406Sopenharmony_ci    SANE_Int blen = MY_MIN(max_lines - shift1, (SANE_Int) *n_lines1_ptr);
2426141cc406Sopenharmony_ci    SANE_Byte * pdst = buffer1;
2427141cc406Sopenharmony_ci    SANE_Byte * psrc = pdst + shift1 * bytes_per_line;
2428141cc406Sopenharmony_ci    for (SANE_Int i = 0; i < blen; ++i) {
2429141cc406Sopenharmony_ci      memcpy (pdst, psrc, bytes_per_line);
2430141cc406Sopenharmony_ci      pdst += bytes_per_line;
2431141cc406Sopenharmony_ci      psrc += bytes_per_line;
2432141cc406Sopenharmony_ci    }
2433141cc406Sopenharmony_ci    *n_lines1_ptr -= shift1;
2434141cc406Sopenharmony_ci  }
2435141cc406Sopenharmony_ci  SANE_Int n_copied = copy_n_last_lines(buffer2, n_lines2, buffer1 + *n_lines1_ptr * bytes_per_line, copy2, bytes_per_line);
2436141cc406Sopenharmony_ci  *n_lines1_ptr += n_copied;
2437141cc406Sopenharmony_ci}
2438141cc406Sopenharmony_ci
2439141cc406Sopenharmony_ci
2440141cc406Sopenharmony_ci/******************************************************************************/
2441141cc406Sopenharmony_ciSANE_Status
2442141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data,
2443141cc406Sopenharmony_ci           SANE_Int max_length, SANE_Int * length)
2444141cc406Sopenharmony_ci{
2445141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
2446141cc406Sopenharmony_ci  SANE_Status ret;
2447141cc406Sopenharmony_ci
2448141cc406Sopenharmony_ci  DBG (DBG_proc, "%s, length %u, left %llu\n",
2449141cc406Sopenharmony_ci       __func__,
2450141cc406Sopenharmony_ci       max_length,
2451141cc406Sopenharmony_ci       scanner->transferred_image_size);
2452141cc406Sopenharmony_ci
2453141cc406Sopenharmony_ci  if (!length)
2454141cc406Sopenharmony_ci    {
2455141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
2456141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2457141cc406Sopenharmony_ci    }
2458141cc406Sopenharmony_ci
2459141cc406Sopenharmony_ci  if (scanner->transferred_image_size == 0)
2460141cc406Sopenharmony_ci    {
2461141cc406Sopenharmony_ci      *length = 0;
2462141cc406Sopenharmony_ci      DBG (DBG_verbose, "Setting scan count\n");
2463141cc406Sopenharmony_ci
2464141cc406Sopenharmony_ci      ret = hp5590_inc_scan_count (scanner->dn, scanner->proto_flags);
2465141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
2466141cc406Sopenharmony_ci        return ret;
2467141cc406Sopenharmony_ci
2468141cc406Sopenharmony_ci      /* Don't free bulk read state, some bytes could be left
2469141cc406Sopenharmony_ci       * for the next images from ADF
2470141cc406Sopenharmony_ci       */
2471141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
2472141cc406Sopenharmony_ci    }
2473141cc406Sopenharmony_ci
2474141cc406Sopenharmony_ci  if (!scanner->bulk_read_state)
2475141cc406Sopenharmony_ci    {
2476141cc406Sopenharmony_ci      ret = hp5590_low_init_bulk_read_state (&scanner->bulk_read_state);
2477141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
2478141cc406Sopenharmony_ci        {
2479141cc406Sopenharmony_ci          scanner->scanning = SANE_FALSE;
2480141cc406Sopenharmony_ci          return ret;
2481141cc406Sopenharmony_ci        }
2482141cc406Sopenharmony_ci    }
2483141cc406Sopenharmony_ci
2484141cc406Sopenharmony_ci  unsigned int bytes_per_line;
2485141cc406Sopenharmony_ci  ret = calc_image_params (scanner,
2486141cc406Sopenharmony_ci                           NULL, NULL,
2487141cc406Sopenharmony_ci                           &bytes_per_line,
2488141cc406Sopenharmony_ci                           NULL, NULL);
2489141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
2490141cc406Sopenharmony_ci    return ret;
2491141cc406Sopenharmony_ci
2492141cc406Sopenharmony_ci  ret = sane_read_internal(scanner, data, max_length, length, bytes_per_line);
2493141cc406Sopenharmony_ci
2494141cc406Sopenharmony_ci  if ((ret == SANE_STATUS_GOOD) && (scanner->dpi == 2400) &&
2495141cc406Sopenharmony_ci          ((scanner->depth == DEPTH_COLOR_48) || (scanner->depth == DEPTH_COLOR_24)))
2496141cc406Sopenharmony_ci    {
2497141cc406Sopenharmony_ci      /* Correct color shift bug for 2400 dpi.
2498141cc406Sopenharmony_ci       * Note: 2400 dpi only works in color mode. Grey mode and lineart seem to
2499141cc406Sopenharmony_ci       * fail.
2500141cc406Sopenharmony_ci       * Align colors by shifting B channel by 48 lines and G channel by 24
2501141cc406Sopenharmony_ci       * lines.
2502141cc406Sopenharmony_ci       */
2503141cc406Sopenharmony_ci      const SANE_Int offset_max = 48;
2504141cc406Sopenharmony_ci      const SANE_Int offset_part = 24;
2505141cc406Sopenharmony_ci      SANE_Bool color_48 = (scanner->depth == DEPTH_COLOR_48);
2506141cc406Sopenharmony_ci
2507141cc406Sopenharmony_ci      if (! scanner->color_shift_line_buffer1)
2508141cc406Sopenharmony_ci        {
2509141cc406Sopenharmony_ci          scanner->color_shift_buffered_lines1 = 0;
2510141cc406Sopenharmony_ci          scanner->color_shift_line_buffer1 = malloc (bytes_per_line * offset_max);
2511141cc406Sopenharmony_ci          if (! scanner->color_shift_line_buffer1)
2512141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
2513141cc406Sopenharmony_ci          memset (scanner->color_shift_line_buffer1, 0, bytes_per_line * offset_max);
2514141cc406Sopenharmony_ci        }
2515141cc406Sopenharmony_ci      if (! scanner->color_shift_line_buffer2)
2516141cc406Sopenharmony_ci        {
2517141cc406Sopenharmony_ci          scanner->color_shift_buffered_lines2 = 0;
2518141cc406Sopenharmony_ci          scanner->color_shift_line_buffer2 = malloc (bytes_per_line * offset_max);
2519141cc406Sopenharmony_ci          if (! scanner->color_shift_line_buffer2)
2520141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
2521141cc406Sopenharmony_ci          memset (scanner->color_shift_line_buffer2, 0, bytes_per_line * offset_max);
2522141cc406Sopenharmony_ci        }
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_ci      SANE_Int n_lines = *length / bytes_per_line;
2525141cc406Sopenharmony_ci      scanner->color_shift_buffered_lines2 = MY_MIN(n_lines, offset_max);
2526141cc406Sopenharmony_ci      copy_n_last_lines(data, n_lines, scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, bytes_per_line);
2527141cc406Sopenharmony_ci
2528141cc406Sopenharmony_ci      shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 1, offset_part, color_48, bytes_per_line);
2529141cc406Sopenharmony_ci      shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 0, offset_max, color_48, bytes_per_line);
2530141cc406Sopenharmony_ci
2531141cc406Sopenharmony_ci      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);
2532141cc406Sopenharmony_ci    }
2533141cc406Sopenharmony_ci
2534141cc406Sopenharmony_ci  return ret;
2535141cc406Sopenharmony_ci}
2536141cc406Sopenharmony_ci
2537141cc406Sopenharmony_ci/******************************************************************************/
2538141cc406Sopenharmony_civoid
2539141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2540141cc406Sopenharmony_ci{
2541141cc406Sopenharmony_ci  struct hp5590_scanner *scanner = handle;
2542141cc406Sopenharmony_ci  SANE_Status ret;
2543141cc406Sopenharmony_ci
2544141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
2547141cc406Sopenharmony_ci
2548141cc406Sopenharmony_ci  if (scanner->dn < 0)
2549141cc406Sopenharmony_ci   return;
2550141cc406Sopenharmony_ci
2551141cc406Sopenharmony_ci  hp5590_low_free_bulk_read_state (&scanner->bulk_read_state);
2552141cc406Sopenharmony_ci
2553141cc406Sopenharmony_ci  ret = hp5590_stop_scan (scanner->dn, scanner->proto_flags);
2554141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
2555141cc406Sopenharmony_ci    return;
2556141cc406Sopenharmony_ci}
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_ci/******************************************************************************/
2559141cc406Sopenharmony_ci
2560141cc406Sopenharmony_ciSANE_Status
2561141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle,
2562141cc406Sopenharmony_ci                  SANE_Bool __sane_unused__ non_blocking)
2563141cc406Sopenharmony_ci{
2564141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2565141cc406Sopenharmony_ci
2566141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2567141cc406Sopenharmony_ci}
2568141cc406Sopenharmony_ci
2569141cc406Sopenharmony_ci/******************************************************************************/
2570141cc406Sopenharmony_ciSANE_Status
2571141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle,
2572141cc406Sopenharmony_ci                    SANE_Int __sane_unused__ * fd)
2573141cc406Sopenharmony_ci{
2574141cc406Sopenharmony_ci  DBG (DBG_proc, "%s\n", __func__);
2575141cc406Sopenharmony_ci
2576141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2577141cc406Sopenharmony_ci}
2578141cc406Sopenharmony_ci
2579141cc406Sopenharmony_ci/* vim: sw=2 ts=8
2580141cc406Sopenharmony_ci */
2581