1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   This file is part of the SANE package, and implements a SANE backend
4141cc406Sopenharmony_ci   for various Fujitsu scanners.
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   Copyright (C) 2000 Randolph Bentson
7141cc406Sopenharmony_ci   Copyright (C) 2001 Frederik Ramm
8141cc406Sopenharmony_ci   Copyright (C) 2001-2004 Oliver Schirrmeister
9141cc406Sopenharmony_ci   Copyright (C) 2003-2022 m. allan noah
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci   JPEG output and low memory usage support funded by:
12141cc406Sopenharmony_ci     Archivista GmbH, www.archivista.ch
13141cc406Sopenharmony_ci   Endorser support funded by:
14141cc406Sopenharmony_ci     O A S Oilfield Accounting Service Ltd, www.oas.ca
15141cc406Sopenharmony_ci   Automatic length detection support funded by:
16141cc406Sopenharmony_ci     Martin G. Miller, mgmiller at optonline.net
17141cc406Sopenharmony_ci   Software image enhancement routines and recent scanner support funded by:
18141cc406Sopenharmony_ci     PFU America, Inc., fujitsuscanners.com
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   --------------------------------------------------------------------------
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
23141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
24141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
25141cc406Sopenharmony_ci   License, or (at your option) any later version.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
28141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
29141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30141cc406Sopenharmony_ci   General Public License for more details.
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
33141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
36141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
39141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
40141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
41141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
42141cc406Sopenharmony_ci   account of linking the SANE library code into it.
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
45141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
46141cc406Sopenharmony_ci   License.
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
49141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
50141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
53141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
54141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci   --------------------------------------------------------------------------
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci   The source code is divided in sections which you can easily find by
59141cc406Sopenharmony_ci   searching for the tag "@@".
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci   Section 1 - Boilerplate: Init & static stuff
62141cc406Sopenharmony_ci   Section 2 - Init: sane_init, _get_devices, _open ...
63141cc406Sopenharmony_ci   Section 3 - Options: sane_*_option functions
64141cc406Sopenharmony_ci   Section 4 - Scanning: sane_start, _get_param, _read ...
65141cc406Sopenharmony_ci   Section 5 - Cleanup: sane_cancel, ...
66141cc406Sopenharmony_ci   Section 6 - Misc: sense_handler, hexdump, ...
67141cc406Sopenharmony_ci   Section 7 - Image processing: deskew, crop, despeck
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci   Changes:
70141cc406Sopenharmony_ci      v1, 2002-05-05, OS
71141cc406Sopenharmony_ci         - release memory allocated by sane_get_devices
72141cc406Sopenharmony_ci         - several bugfixes
73141cc406Sopenharmony_ci         - supports the M3097
74141cc406Sopenharmony_ci         - get threshold, contrast and brightness from vpd
75141cc406Sopenharmony_ci         - imprinter support
76141cc406Sopenharmony_ci         - get_hardware_status now works before calling sane_start
77141cc406Sopenharmony_ci         - avoid unnecessary reload of options when using source=fb
78141cc406Sopenharmony_ci      v2, 2002-08-08, OS
79141cc406Sopenharmony_ci         - bugfix. Imprinter didn't print the first time after
80141cc406Sopenharmony_ci           switching on the scanner
81141cc406Sopenharmony_ci         - bugfix. reader_generic_passthrough ignored the number of bytes
82141cc406Sopenharmony_ci           returned by the scanner
83141cc406Sopenharmony_ci      v3, 2002-09-13, OS
84141cc406Sopenharmony_ci         - 3092 support (mgoppold a t tbz-pariv.de)
85141cc406Sopenharmony_ci         - tested 4097 support
86141cc406Sopenharmony_ci         - changed some functions to receive compressed data
87141cc406Sopenharmony_ci      v4, 2003-02-13, OS
88141cc406Sopenharmony_ci         - fi-4220C support (ron a t roncemer.com)
89141cc406Sopenharmony_ci         - SCSI over USB support (ron a t roncemer.com)
90141cc406Sopenharmony_ci      v5, 2003-02-20, OS
91141cc406Sopenharmony_ci         - set availability of options THRESHOLD und VARIANCE
92141cc406Sopenharmony_ci         - option RIF is available for 3091 and 3092
93141cc406Sopenharmony_ci      v6, 2003-03-04, OS
94141cc406Sopenharmony_ci         - renamed some variables
95141cc406Sopenharmony_ci         - bugfix: duplex scanning now works when disconnect is enabled
96141cc406Sopenharmony_ci      v7, 2003-03-10, OS
97141cc406Sopenharmony_ci         - displays the offending byte in the window descriptor block
98141cc406Sopenharmony_ci      v8, 2003-03-28, OS
99141cc406Sopenharmony_ci         - fi-4120C support, MAN
100141cc406Sopenharmony_ci         - display information about gamma in vital_product_data
101141cc406Sopenharmony_ci      v9 2003-06-04, MAN
102141cc406Sopenharmony_ci         - separated the 4120 and 4220 into another model
103141cc406Sopenharmony_ci         - color support for the 4x20
104141cc406Sopenharmony_ci      v10 2003-06-04, MAN
105141cc406Sopenharmony_ci         - removed SP15 code
106141cc406Sopenharmony_ci         - sane_open actually opens the device you request
107141cc406Sopenharmony_ci      v11 2003-06-11, MAN
108141cc406Sopenharmony_ci         - fixed bug in that code when a scanner is disconnected
109141cc406Sopenharmony_ci      v12 2003-10-06, MAN
110141cc406Sopenharmony_ci         - added code to support color modes of more recent scanners
111141cc406Sopenharmony_ci      v13 2003-11-07, OS
112141cc406Sopenharmony_ci	 - Bugfix. If a scanner returned a color image
113141cc406Sopenharmony_ci	   in format rr...r gg...g bb...b the reader process crashed
114141cc406Sopenharmony_ci	 - Bugfix. Disable option gamma was for the fi-4120
115141cc406Sopenharmony_ci      v14 2003-12-15, OS
116141cc406Sopenharmony_ci         - Bugfix: set default threshold range to 0..255 There is a problem
117141cc406Sopenharmony_ci           with the M3093 when you are not allows to set the threshold to 0
118141cc406Sopenharmony_ci         - Bugfix: set the allowable x- and y-DPI values from VPD. Scanning
119141cc406Sopenharmony_ci           with x=100 and y=100 dpi with an fi4120 resulted in an image
120141cc406Sopenharmony_ci           with 100,75 dpi
121141cc406Sopenharmony_ci         - Bugfix: Set the default value of gamma to 0x80 for all scanners
122141cc406Sopenharmony_ci           that don't have built in gamma patterns
123141cc406Sopenharmony_ci         - Bugfix: fi-4530 and fi-4210 don't support standard paper size
124141cc406Sopenharmony_ci      v15 2003-12-16, OS
125141cc406Sopenharmony_ci         - Bugfix: pagewidth and pageheight were disabled for the fi-4530C
126141cc406Sopenharmony_ci      v16 2004-02-20, OS
127141cc406Sopenharmony_ci         - merged the 3092-routines with the 3091-routines
128141cc406Sopenharmony_ci         - inverted the image in mode color and grayscale
129141cc406Sopenharmony_ci         - jpg hardware compression support (fi-4530C)
130141cc406Sopenharmony_ci      v17 2004-03-04, OS
131141cc406Sopenharmony_ci         - enabled option dropoutcolor for the fi-4530C, and fi-4x20C
132141cc406Sopenharmony_ci      v18 2004-06-02, OS
133141cc406Sopenharmony_ci         - bugfix: can read duplex color now
134141cc406Sopenharmony_ci      v19 2004-06-28, MAN
135141cc406Sopenharmony_ci         - 4220 use model code not strcmp (stan a t saticed.me.uk)
136141cc406Sopenharmony_ci      v20 2004-08-24, OS
137141cc406Sopenharmony_ci         - bugfix: 3091 did not work since 15.12.2003
138141cc406Sopenharmony_ci         - M4099 supported (bw only)
139141cc406Sopenharmony_ci      v21 2006-05-01, MAN
140141cc406Sopenharmony_ci         - Complete rewrite, half code size
141141cc406Sopenharmony_ci         - better (read: correct) usb command support
142141cc406Sopenharmony_ci         - basic support for most fi-series
143141cc406Sopenharmony_ci         - most scanner capabilities read from VPD
144141cc406Sopenharmony_ci         - reduced model-specific code
145141cc406Sopenharmony_ci         - improved scanner detection/initialization
146141cc406Sopenharmony_ci         - improved SANE_Option handling
147141cc406Sopenharmony_ci         - basic button support
148141cc406Sopenharmony_ci         - all IPC and Imprinter options removed temporarily
149141cc406Sopenharmony_ci         - duplex broken temporarily
150141cc406Sopenharmony_ci      v22 2006-05-04, MAN
151141cc406Sopenharmony_ci         - do_scsi_cmd gets basic looping capability
152141cc406Sopenharmony_ci         - reverse now divided by mode
153141cc406Sopenharmony_ci         - re-write sane_fix/unfix value handling
154141cc406Sopenharmony_ci         - fix several bugs in options code
155141cc406Sopenharmony_ci         - some options' ranges modified by other options vals
156141cc406Sopenharmony_ci         - added advanced read-only options for all
157141cc406Sopenharmony_ci           known hardware sensors and buttons
158141cc406Sopenharmony_ci         - rewrote hw status function
159141cc406Sopenharmony_ci         - initial testing with M3091dc- color mode broken
160141cc406Sopenharmony_ci      v23 2006-05-14, MAN
161141cc406Sopenharmony_ci         - initial attempt to recover duplex mode
162141cc406Sopenharmony_ci         - fix bad usb prodID when config file missing
163141cc406Sopenharmony_ci      v24 2006-05-17, MAN
164141cc406Sopenharmony_ci         - sane_read must set len=0 when return != good
165141cc406Sopenharmony_ci         - simplify do_cmd() calls by removing timeouts
166141cc406Sopenharmony_ci         - lengthen most timeouts, shorten those for wait_scanner()
167141cc406Sopenharmony_ci      v25 2006-05-19, MAN
168141cc406Sopenharmony_ci         - rename scsi-buffer-size to buffer-size, usb uses it too
169141cc406Sopenharmony_ci         - default buffer-size increased to 64k
170141cc406Sopenharmony_ci         - use sanei_scsi_open_extended() to set buffer size
171141cc406Sopenharmony_ci         - fix some compiler warns: 32&64 bit gcc
172141cc406Sopenharmony_ci      v26 2006-05-23, MAN
173141cc406Sopenharmony_ci         - don't send scanner control (F1) if unsupported
174141cc406Sopenharmony_ci      v27 2006-05-30, MAN
175141cc406Sopenharmony_ci         - speed up hexdump (adeuring A T gmx D O T net)
176141cc406Sopenharmony_ci         - duplex request same size block from both sides
177141cc406Sopenharmony_ci         - don't #include or call sanei_thread
178141cc406Sopenharmony_ci         - split usb/scsi command DBG into 25 and 30
179141cc406Sopenharmony_ci      v28 2006-06-01, MAN
180141cc406Sopenharmony_ci         - sane_read() usleep if scanner is busy
181141cc406Sopenharmony_ci         - do_*_cmd() no looping (only one caller used it),
182141cc406Sopenharmony_ci           remove unneeded casts, cleanup/add error messages
183141cc406Sopenharmony_ci         - scanner_control() look at correct has_cmd_* var,
184141cc406Sopenharmony_ci           handles own looping on busy
185141cc406Sopenharmony_ci      v29 2006-06-04, MAN
186141cc406Sopenharmony_ci         - M3091/2 Color mode support (duplex still broken)
187141cc406Sopenharmony_ci         - all sensors option names start with 'button-'
188141cc406Sopenharmony_ci         - rewrite sane_read and helpers to use buffers,
189141cc406Sopenharmony_ci           currently an extreme waste of ram, but should
190141cc406Sopenharmony_ci           work with saned and scanimage -T
191141cc406Sopenharmony_ci         - merge color conversion funcs into read_from_buf()
192141cc406Sopenharmony_ci         - compare bytes tx v/s rx instead of storing EOFs
193141cc406Sopenharmony_ci         - remove scanner cmd buf, use buf per func instead
194141cc406Sopenharmony_ci         - print color and duplex raster offsets (inquiry)
195141cc406Sopenharmony_ci         - print EOM, ILI, and info bytes (request sense)
196141cc406Sopenharmony_ci      v30 2006-06-06, MAN
197141cc406Sopenharmony_ci         - M3091/2 duplex support, color/gray/ht/lineart ok
198141cc406Sopenharmony_ci         - sane_read helpers share code, report more errors
199141cc406Sopenharmony_ci         - add error msg if VPD missing or non-extended
200141cc406Sopenharmony_ci         - remove references to color_lineart and ht units
201141cc406Sopenharmony_ci         - rework init_model to support more known models
202141cc406Sopenharmony_ci         - don't send paper size data if using flatbed
203141cc406Sopenharmony_ci      v31 2006-06-13, MAN
204141cc406Sopenharmony_ci         - add 5220C usb id
205141cc406Sopenharmony_ci         - don't show ink level buttons if no imprinter
206141cc406Sopenharmony_ci         - run ghs/rs every second instead of every other
207141cc406Sopenharmony_ci      v32 2006-06-14, MAN
208141cc406Sopenharmony_ci         - add 4220C2 usb id
209141cc406Sopenharmony_ci      v33 2006-06-14, MAN (SANE v1.0.18)
210141cc406Sopenharmony_ci         - add Fi-5900 usb id and init_model section
211141cc406Sopenharmony_ci      v34 2006-07-04, MAN
212141cc406Sopenharmony_ci         - add S500 usb id
213141cc406Sopenharmony_ci         - gather more data from inq and vpd
214141cc406Sopenharmony_ci         - allow background color setting
215141cc406Sopenharmony_ci      v35 2006-07-05, MAN
216141cc406Sopenharmony_ci         - allow double feed sensor settings
217141cc406Sopenharmony_ci         - more consistent naming of global strings
218141cc406Sopenharmony_ci      v36 2006-07-06, MAN
219141cc406Sopenharmony_ci         - deal with fi-5900 even bytes problem
220141cc406Sopenharmony_ci         - less verbose calculateDerivedValues()
221141cc406Sopenharmony_ci      v37 2006-07-14, MAN
222141cc406Sopenharmony_ci         - mode sense command support
223141cc406Sopenharmony_ci         - detect mode page codes instead of hardcoding
224141cc406Sopenharmony_ci         - send command support
225141cc406Sopenharmony_ci         - brightness/contrast support via LUT
226141cc406Sopenharmony_ci         - merge global mode page buffers
227141cc406Sopenharmony_ci      v38 2006-07-15, MAN
228141cc406Sopenharmony_ci         - add 'useless noise' debug level (35)
229141cc406Sopenharmony_ci         - move mode sense probe errors to DBG 35
230141cc406Sopenharmony_ci      v39 2006-07-17, MAN
231141cc406Sopenharmony_ci         - rewrite contrast slope math for readability
232141cc406Sopenharmony_ci      v40 2006-08-26, MAN
233141cc406Sopenharmony_ci         - rewrite brightness/contrast more like xsane
234141cc406Sopenharmony_ci         - initial gamma support
235141cc406Sopenharmony_ci         - add fi-5530 usb id
236141cc406Sopenharmony_ci         - rewrite do_*_cmd functions to handle short reads
237141cc406Sopenharmony_ci           and to use ptr to return read in length
238141cc406Sopenharmony_ci         - new init_user function split from init_model
239141cc406Sopenharmony_ci         - init_vpd allows short vpd block for older models
240141cc406Sopenharmony_ci         - support MS buffer (s.scipioni AT harvardgroup DOT it)
241141cc406Sopenharmony_ci         - support MS prepick
242141cc406Sopenharmony_ci         - read only 1 byte of mode sense output
243141cc406Sopenharmony_ci      v41 2006-08-28, MAN
244141cc406Sopenharmony_ci         - do_usb_cmd() returns io error on cmd/out/status/rs EOF
245141cc406Sopenharmony_ci         - fix bug in MS buffer/prepick scsi data block
246141cc406Sopenharmony_ci      v42 2006-08-31, MAN
247141cc406Sopenharmony_ci         - fix bug in get_hardware_status (#303798)
248141cc406Sopenharmony_ci      v43 2006-09-19, MAN
249141cc406Sopenharmony_ci         - add model-specific code to init_vpd for M3099
250141cc406Sopenharmony_ci      v44 2007-01-26, MAN
251141cc406Sopenharmony_ci         - set SANE_CAP_HARD_SELECT on all buttons/sensors
252141cc406Sopenharmony_ci         - disable sending gamma LUT, seems wrong on some units?
253141cc406Sopenharmony_ci         - support MS overscan
254141cc406Sopenharmony_ci         - clamp the scan area to the pagesize on ADF
255141cc406Sopenharmony_ci      v45 2007-01-28, MAN
256141cc406Sopenharmony_ci         - update overscan code to extend max scan area
257141cc406Sopenharmony_ci      v46 2007-03-08, MAN
258141cc406Sopenharmony_ci         - tweak fi-4x20c2 and M3093 settings
259141cc406Sopenharmony_ci	 - add fi-5110EOXM usb id
260141cc406Sopenharmony_ci	 - add M3093 non-alternating duplex code
261141cc406Sopenharmony_ci      v47 2007-04-13, MAN
262141cc406Sopenharmony_ci         - change window_gamma determination
263141cc406Sopenharmony_ci         - add fi-5650C usb id and color mode
264141cc406Sopenharmony_ci      v48 2007-04-16, MAN
265141cc406Sopenharmony_ci         - re-enable brightness/contrast for built-in models
266141cc406Sopenharmony_ci      v49 2007-06-28, MAN
267141cc406Sopenharmony_ci         - add fi-5750C usb id and color mode
268141cc406Sopenharmony_ci      v50 2007-07-10, MAN
269141cc406Sopenharmony_ci         - updated overscan and bgcolor option descriptions
270141cc406Sopenharmony_ci	 - added jpeg output support
271141cc406Sopenharmony_ci         - restructured usb reading code to use RS len for short reads
272141cc406Sopenharmony_ci         - combined calcDerivedValues with sane_get_params
273141cc406Sopenharmony_ci      v51 2007-07-26, MAN
274141cc406Sopenharmony_ci	 - fix bug in jpeg output support
275141cc406Sopenharmony_ci      v52 2007-07-27, MAN
276141cc406Sopenharmony_ci	 - remove unused jpeg function
277141cc406Sopenharmony_ci	 - reactivate look-up-table based brightness and contrast options
278141cc406Sopenharmony_ci	 - change range of hardware brightness/contrast to match LUT versions
279141cc406Sopenharmony_ci	 - call send_lut() from sane_control_option instead of sane_start
280141cc406Sopenharmony_ci      v53 2007-11-18, MAN
281141cc406Sopenharmony_ci         - add S510 usb id
282141cc406Sopenharmony_ci	 - OPT_NUM_OPTS type is SANE_TYPE_INT (jblache)
283141cc406Sopenharmony_ci      v54 2007-12-29, MAN
284141cc406Sopenharmony_ci	 - disable SANE_FRAME_JPEG support until SANE 1.1.0
285141cc406Sopenharmony_ci      v55 2007-12-29, MAN (SANE v1.0.19)
286141cc406Sopenharmony_ci	 - add S500M usb id
287141cc406Sopenharmony_ci      v56 2008-02-14, MAN
288141cc406Sopenharmony_ci	 - sanei_config_read has already cleaned string (#310597)
289141cc406Sopenharmony_ci      v57 2008-02-24, MAN
290141cc406Sopenharmony_ci         - fi-5900 does not (initially) interlace colors
291141cc406Sopenharmony_ci	 - add mode sense for color interlacing? (page code 32)
292141cc406Sopenharmony_ci	 - more debug output in init_ms()
293141cc406Sopenharmony_ci      v58 2008-04-19, MAN
294141cc406Sopenharmony_ci         - page code 32 is not color interlacing, rename to 'unknown'
295141cc406Sopenharmony_ci         - increase number of bytes in response buffer of init_ms()
296141cc406Sopenharmony_ci         - protect debug modification code in init_ms() if NDEBUG is set
297141cc406Sopenharmony_ci         - proper async sane_cancel support
298141cc406Sopenharmony_ci         - re-enable JPEG support
299141cc406Sopenharmony_ci         - replace s->img_count with s->side
300141cc406Sopenharmony_ci         - sane_get_parameters(): don't round up larger than current paper size
301141cc406Sopenharmony_ci         - sane_start() rewritten, shorter, more clear
302141cc406Sopenharmony_ci         - return values are SANE_Status, not int
303141cc406Sopenharmony_ci         - hide unused functions
304141cc406Sopenharmony_ci      v59 2008-04-22, MAN
305141cc406Sopenharmony_ci         - add fi-6140 usb ID, and fi-6x40 color mode
306141cc406Sopenharmony_ci      v60 2008-04-27, MAN
307141cc406Sopenharmony_ci         - move call to sanei_usb_init() from sane_init() to find_scanners
308141cc406Sopenharmony_ci	 - free sane_devArray before calloc'ing a new one
309141cc406Sopenharmony_ci      v61 2008-05-11, MAN
310141cc406Sopenharmony_ci         - minor cleanups to init_ms()
311141cc406Sopenharmony_ci	 - add fi-5530C2 usb id
312141cc406Sopenharmony_ci	 - merge find_scanners into sane_get_devices
313141cc406Sopenharmony_ci	 - inspect correct bool to enable prepick mode option
314141cc406Sopenharmony_ci      v62 2008-05-20, MAN
315141cc406Sopenharmony_ci         - check for all supported scsi commands
316141cc406Sopenharmony_ci	 - use well-known option group strings from saneopts.h
317141cc406Sopenharmony_ci	 - rename pagewidth to page-width, to meet sane 1.1.0, same for height
318141cc406Sopenharmony_ci	 - add unused get_window()
319141cc406Sopenharmony_ci      v63 2008-05-21, MAN
320141cc406Sopenharmony_ci         - use sane 1.1.0 well-known option names for some buttons
321141cc406Sopenharmony_ci	 - remove 'button-' from other buttons and sensors
322141cc406Sopenharmony_ci      v64 2008-05-28, MAN
323141cc406Sopenharmony_ci         - strcpy device_name[] instead of strdup/free *device_name
324141cc406Sopenharmony_ci	 - add send/read diag commands to get scanner serial number
325141cc406Sopenharmony_ci	 - use model and serial to build sane.name (idea from Ryan Duryea)
326141cc406Sopenharmony_ci	 - allow both serial_name and device_name to sane_open scanner
327141cc406Sopenharmony_ci	 - correct mode select/sense 6 vs 10 booleans
328141cc406Sopenharmony_ci	 - rename product_name to model_name
329141cc406Sopenharmony_ci	 - simulate missing VPD data for M3097G
330141cc406Sopenharmony_ci	 - hide get_window
331141cc406Sopenharmony_ci	 - improve handling of vendor unique section of set_window
332141cc406Sopenharmony_ci	 - add init_interlace to detect proper color mode without hardcoding
333141cc406Sopenharmony_ci	 - add ascii output to hexdump
334141cc406Sopenharmony_ci      v65 2008-06-24, MAN
335141cc406Sopenharmony_ci         - detect endorser type during init_inquiry()
336141cc406Sopenharmony_ci         - add endorser options
337141cc406Sopenharmony_ci	 - add send_endorser() and call from sane_control_option()
338141cc406Sopenharmony_ci	 - add endorser() and call from sane_start()
339141cc406Sopenharmony_ci	 - convert set_window() to use local cmd and payload copies
340141cc406Sopenharmony_ci	 - remove get_window()
341141cc406Sopenharmony_ci	 - mode_select_buff() now clears the buffer, and called in sane_close()
342141cc406Sopenharmony_ci	 - fi-4990 quirks added, including modified even_scan_line code
343141cc406Sopenharmony_ci      v66 2008-06-26, MAN
344141cc406Sopenharmony_ci	 - restructure double feed detection options for finer-grained control
345141cc406Sopenharmony_ci	 - add endorser side option
346141cc406Sopenharmony_ci	 - prevent init_interlace() from overriding init_model()
347141cc406Sopenharmony_ci	 - simplify sane_start() and fix interlaced duplex jpeg support
348141cc406Sopenharmony_ci	 - simplify sane_read() and add non-interlaced duplex jpeg support
349141cc406Sopenharmony_ci	 - removed unused code
350141cc406Sopenharmony_ci      v67 2008-07-01, MAN
351141cc406Sopenharmony_ci         - add IPC/DTC/SDTC options
352141cc406Sopenharmony_ci         - call check_for_cancel() in sane_cancel, unless s->reader flag is set
353141cc406Sopenharmony_ci      v68 2008-07-02, MAN
354141cc406Sopenharmony_ci	 - add halftone type and pattern options
355141cc406Sopenharmony_ci         - support M3097G with IPC and CMP options via modified VPD response
356141cc406Sopenharmony_ci      v69 2008-07-03, MAN
357141cc406Sopenharmony_ci         - support hot-unplugging scanners
358141cc406Sopenharmony_ci      v70 2008-07-05, MAN
359141cc406Sopenharmony_ci         - fix bug in sane_get_parameters (failed to copy values)
360141cc406Sopenharmony_ci	 - autodetect jpeg duplex interlacing mode by inspecting scan width
361141cc406Sopenharmony_ci      v71 2008-07-13, MAN
362141cc406Sopenharmony_ci         - disable overscan option if vpd does not tell overscan size
363141cc406Sopenharmony_ci	 - fi-5110EOX crops scan area based on absolute maximum, not paper
364141cc406Sopenharmony_ci	 - fi-5530C/2 and fi-5650C can't handle 10 bit LUT via USB
365141cc406Sopenharmony_ci	 - fi-5900 has background color, though it reports otherwise
366141cc406Sopenharmony_ci      v72 2008-07-13, MAN
367141cc406Sopenharmony_ci	 - use mode_sense to determine background color support
368141cc406Sopenharmony_ci	 - remove fi-5900 background color override
369141cc406Sopenharmony_ci      v73 2008-07-14, MAN
370141cc406Sopenharmony_ci	 - correct overscan dimension calculation
371141cc406Sopenharmony_ci	 - provide correct overscan size overrides for fi-5110C and fi-4x20C2
372141cc406Sopenharmony_ci	 - add fi-6130 usb ID
373141cc406Sopenharmony_ci	 - fi-5750C can't handle 10 bit LUT via USB
374141cc406Sopenharmony_ci      v74 2008-08-02, MAN
375141cc406Sopenharmony_ci	 - replace global scsi blocks with local ones in each function
376141cc406Sopenharmony_ci      v75 2008-08-07, ReneR
377141cc406Sopenharmony_ci	 - added fi-6230 usb ID
378141cc406Sopenharmony_ci      v76 2008-08-13, MAN
379141cc406Sopenharmony_ci	 - add independent maximum area values for flatbed
380141cc406Sopenharmony_ci	 - override said values for fi-4220C, fi-4220C2 and fi-5220C
381141cc406Sopenharmony_ci      v77 2008-08-26, MAN
382141cc406Sopenharmony_ci	 - override flatbed maximum area for fi-6230C and fi-6240C
383141cc406Sopenharmony_ci	 - set PF bit in all mode_select(6) CDB's
384141cc406Sopenharmony_ci	 - set SANE_CAP_INACTIVE on all disabled options
385141cc406Sopenharmony_ci         - fix bug in mode_select page for sleep timer
386141cc406Sopenharmony_ci      v78 2008-08-26, MAN
387141cc406Sopenharmony_ci	 - recent model names (fi-6xxx) don't end in 'C'
388141cc406Sopenharmony_ci         - simplify flatbed area overrides
389141cc406Sopenharmony_ci         - call scanner_control to change source during sane_start
390141cc406Sopenharmony_ci      v79 2008-10-01, MAN
391141cc406Sopenharmony_ci	 - add usb ids for several models
392141cc406Sopenharmony_ci         - print additional hardware capability bits
393141cc406Sopenharmony_ci         - detect front-side endorser
394141cc406Sopenharmony_ci         - disable endorser-side controls if only one side installed
395141cc406Sopenharmony_ci         - add quirks for fi-6x70
396141cc406Sopenharmony_ci      v80 2008-10-08, MAN
397141cc406Sopenharmony_ci         - front-side endorser uses data ID 0x80
398141cc406Sopenharmony_ci      v81 2008-10-20, MAN
399141cc406Sopenharmony_ci         - increase USB timeouts
400141cc406Sopenharmony_ci         - enable get_pixelsize() to update scan params after set_window()
401141cc406Sopenharmony_ci         - remove even_scan_line hack
402141cc406Sopenharmony_ci      v82 2008-10-31, MAN
403141cc406Sopenharmony_ci         - improved front-side endorser vpd detection
404141cc406Sopenharmony_ci         - send scanner_control_ric during sane_read of each side
405141cc406Sopenharmony_ci         - add fi-6770A and fi-6670A USB ID's
406141cc406Sopenharmony_ci      v83 2008-11-06, MAN
407141cc406Sopenharmony_ci         - round binary bpl and Bpl up to byte boundary
408141cc406Sopenharmony_ci         - use s->params instead of user data in set_window()
409141cc406Sopenharmony_ci         - read_from_scanner() only grabs an even number of lines
410141cc406Sopenharmony_ci      v84 2008-11-07, MAN
411141cc406Sopenharmony_ci         - round lines down to even number to get even # of total bytes
412141cc406Sopenharmony_ci         - round binary bpl and Bpl down to byte boundary
413141cc406Sopenharmony_ci      v85 2008-12-10, MAN
414141cc406Sopenharmony_ci         - round pixels_per_line down to arbitrary limits for fi-4990 & fi-4860
415141cc406Sopenharmony_ci         - fi-4860 returns random garbage to serial number queries
416141cc406Sopenharmony_ci         - initialize *info to 0 in sane_control_option()
417141cc406Sopenharmony_ci      v86 2008-12-18, MAN
418141cc406Sopenharmony_ci         - get_pixelsize() sets back window ID for back side scans
419141cc406Sopenharmony_ci      v87 2008-12-21, MAN
420141cc406Sopenharmony_ci         - accept null pointer as empty device name
421141cc406Sopenharmony_ci         - track frontend reading sensor/button values to reload
422141cc406Sopenharmony_ci         - deactivate double feed options if df-action == default
423141cc406Sopenharmony_ci      v88 2009-01-21, MAN
424141cc406Sopenharmony_ci         - don't export private symbols
425141cc406Sopenharmony_ci      v89 2009-02-20, MAN
426141cc406Sopenharmony_ci         - fi-4750 returns random garbage to serial number queries
427141cc406Sopenharmony_ci      v90 2009-02-23, MAN
428141cc406Sopenharmony_ci         - added ScanSnap S510M usb ids
429141cc406Sopenharmony_ci      v91 2009-03-20, MAN
430141cc406Sopenharmony_ci         - remove unused temp file code
431141cc406Sopenharmony_ci      v92 2009-04-12, MAN
432141cc406Sopenharmony_ci	 - disable SANE_FRAME_JPEG support (again)
433141cc406Sopenharmony_ci      v93 2009-04-14, MAN (SANE 1.0.20)
434141cc406Sopenharmony_ci         - return cmd status for reads on sensors
435141cc406Sopenharmony_ci         - ignore errors in scanner_control(),
436141cc406Sopenharmony_ci           M3091 has not worked since sane 1.0.19, due to this.
437141cc406Sopenharmony_ci         - copy_buffer needs to count lines, or M309[12] cannot duplex
438141cc406Sopenharmony_ci      v94 2009-05-22, MAN
439141cc406Sopenharmony_ci         - add side option to show which duplex image is being transferred
440141cc406Sopenharmony_ci         - convert front and simplex buffers to use much less ram
441141cc406Sopenharmony_ci         - add lowmemory option which makes duplex back buffer small too
442141cc406Sopenharmony_ci         - refactor image handling code to track eof's instead of lengths
443141cc406Sopenharmony_ci         - do color deinterlacing after reading from scanner, before buffering
444141cc406Sopenharmony_ci      v95 2009-06-02, MAN
445141cc406Sopenharmony_ci         - scanner_control_ric should return a subset of the possible errors
446141cc406Sopenharmony_ci      v96 2009-08-07, MAN
447141cc406Sopenharmony_ci         - split sane_get_parameters into two functions
448141cc406Sopenharmony_ci         - remove unused code from get_pixelsize
449141cc406Sopenharmony_ci         - support hardware based auto length detection
450141cc406Sopenharmony_ci      v97 2009-09-14, MAN
451141cc406Sopenharmony_ci         - use sanei_magic to provide software deskew, autocrop and despeckle
452141cc406Sopenharmony_ci      v98 2010-02-09, MAN (SANE 1.0.21)
453141cc406Sopenharmony_ci         - clean up #include lines and copyright
454141cc406Sopenharmony_ci         - add SANE_I18N to static strings
455141cc406Sopenharmony_ci         - don't fail if scsi buffer is too small
456141cc406Sopenharmony_ci         - disable bg_color for S1500
457141cc406Sopenharmony_ci         - enable flatbed for M3092
458141cc406Sopenharmony_ci      v99 2010-05-14, MAN
459141cc406Sopenharmony_ci         - sense_handler(): collect rs_info for any ILI, not just EOM
460141cc406Sopenharmony_ci         - do_usb_cmd(): use rs_info whenever set, not just EOF
461141cc406Sopenharmony_ci         - read_from_*(): better handling of EOF from lower level functions
462141cc406Sopenharmony_ci         - sane_read(): improve duplexing logic
463141cc406Sopenharmony_ci      v100 2010-06-01, MAN
464141cc406Sopenharmony_ci         - store more Request Sense data in scanner struct
465141cc406Sopenharmony_ci         - clear Request Sense data at start of every do_cmd() call
466141cc406Sopenharmony_ci         - track per-side ILI and global EOM flags
467141cc406Sopenharmony_ci         - set per-side EOF flag if ILI and EOM are set
468141cc406Sopenharmony_ci      v101 2010-06-23, MAN
469141cc406Sopenharmony_ci         - fix compilation bug when jpeg is enabled
470141cc406Sopenharmony_ci      v102 2010-09-22, MAN
471141cc406Sopenharmony_ci         - fix infinite loop when scan is an odd number of lines
472141cc406Sopenharmony_ci      v103 2010-11-23, MAN
473141cc406Sopenharmony_ci         - remove compiled-in default config file
474141cc406Sopenharmony_ci         - initial support for new fi-6xxx machines
475141cc406Sopenharmony_ci      v104 2010-11-24, MAN
476141cc406Sopenharmony_ci         - never request more than s->buffer_size from scanner
477141cc406Sopenharmony_ci         - silence noisy set_window() calls from init_interlace()
478141cc406Sopenharmony_ci      v105 2010-12-02, MAN
479141cc406Sopenharmony_ci         - backup and restore image params around image processing code
480141cc406Sopenharmony_ci         - cache software crop/deskew parameters for use on backside of duplex
481141cc406Sopenharmony_ci         - fi-6110 does not support bgcolor or prepick
482141cc406Sopenharmony_ci      v106 2011-01-30, MAN (SANE 1.0.22)
483141cc406Sopenharmony_ci         - don't call mode_select with a page code the scanner does not support
484141cc406Sopenharmony_ci      v107 2011-11-03, MAN
485141cc406Sopenharmony_ci         - M3091 does not support scanner_control(adf)
486141cc406Sopenharmony_ci         - Correct buffer overflow in read_from_3091duplex()
487141cc406Sopenharmony_ci         - sane_read() now always calls read_from_*()
488141cc406Sopenharmony_ci         - read_from_*() are callable when there is no data, and read to eof
489141cc406Sopenharmony_ci         - sane_read() will keep alternate duplex reads to similar length
490141cc406Sopenharmony_ci         - Added debugging statements
491141cc406Sopenharmony_ci         - Corrected comments
492141cc406Sopenharmony_ci         - Updated Copyright
493141cc406Sopenharmony_ci      v108 2011-11-21, MAN
494141cc406Sopenharmony_ci         - merged x/y resolution options
495141cc406Sopenharmony_ci         - moved page width/height to start of geometry group
496141cc406Sopenharmony_ci         - use mode to pick resolution list v/s range
497141cc406Sopenharmony_ci         - improved M3091 resolution choices
498141cc406Sopenharmony_ci      v109 2011-12-20, MAN
499141cc406Sopenharmony_ci         - added some MS and INQ information
500141cc406Sopenharmony_ci         - increased default buffer size for later machines in config file
501141cc406Sopenharmony_ci         - renamed new fi-6xx0Z models
502141cc406Sopenharmony_ci      v110 2012-05-09, MAN
503141cc406Sopenharmony_ci         - correct max_y_fb for fi-62x0 series
504141cc406Sopenharmony_ci         - add must_fully_buffer helper routine
505141cc406Sopenharmony_ci         - add hwdeskewcrop option, with fallback to software versions
506141cc406Sopenharmony_ci         - add 'actual' param to get_pixelsize for post-scan
507141cc406Sopenharmony_ci         - add recent model VPD params
508141cc406Sopenharmony_ci         - only set params->lines = -1 when using ald without buffering
509141cc406Sopenharmony_ci         - fix bugs in background color when using software deskew
510141cc406Sopenharmony_ci      v111 2012-05-10, MAN (SANE 1.0.23)
511141cc406Sopenharmony_ci         - call send_* and mode_select_* from sane_start
512141cc406Sopenharmony_ci         - split read payloads into new debug level
513141cc406Sopenharmony_ci         - add paper-protect, staple-detect and df-recovery options
514141cc406Sopenharmony_ci      v112 2013-02-22, MAN
515141cc406Sopenharmony_ci         - some scanners (fi-6x70 and later) don't enable IPC by default
516141cc406Sopenharmony_ci      v113 2013-02-24, MAN
517141cc406Sopenharmony_ci         - support for ScanSnap iX500
518141cc406Sopenharmony_ci         - fix bug with jpeg de-interlacing code
519141cc406Sopenharmony_ci         - allow has_MS_* and has_pixelsize to be set in init_model
520141cc406Sopenharmony_ci         - fix use of uninitialized buffer in send_lut
521141cc406Sopenharmony_ci         - add send_q_table()
522141cc406Sopenharmony_ci         - allow wait_scanner() to be bypassed in object_position
523141cc406Sopenharmony_ci         - moved send_lut() to after set_window
524141cc406Sopenharmony_ci      v114 2013-03-01, MAN
525141cc406Sopenharmony_ci         - support resolutions > 300 for iX500 using diag_preread()
526141cc406Sopenharmony_ci         - remove most communication with scanner during sane_control_option()
527141cc406Sopenharmony_ci      v115 2013-03-09, MAN
528141cc406Sopenharmony_ci         - separate s->mode into s_mode and u_mode
529141cc406Sopenharmony_ci         - separate s->params into s_params and u_params
530141cc406Sopenharmony_ci         - generate grayscale and binary in software if required (iX500)
531141cc406Sopenharmony_ci      v116 2013-03-23, MAN
532141cc406Sopenharmony_ci         - call set_mode() in init_interlace
533141cc406Sopenharmony_ci         - add swskip option
534141cc406Sopenharmony_ci      v117 2013-06-11, MAN (SANE 1.0.24)
535141cc406Sopenharmony_ci         - default buffer-mode to off
536141cc406Sopenharmony_ci         - improved error handling in sane_start
537141cc406Sopenharmony_ci         - image width must be multiple of 8 when swcrop is used before binarization (iX500)
538141cc406Sopenharmony_ci         - check hopper sensor before calling object_position(load) on iX500
539141cc406Sopenharmony_ci      v118 2013-12-09, MAN
540141cc406Sopenharmony_ci         - support fi-7160, fi-7260, fi-7180 and fi-7280
541141cc406Sopenharmony_ci         - remove unused var from do_scsi_cmd()
542141cc406Sopenharmony_ci         - added more request_sense options
543141cc406Sopenharmony_ci         - add adv_paper_protect option
544141cc406Sopenharmony_ci         - enable paper protection by default
545141cc406Sopenharmony_ci         - increase max_x_fb for fi-6240 and fi-6230
546141cc406Sopenharmony_ci      v119 2013-12-18, MAN
547141cc406Sopenharmony_ci         - call get_pixelsize after start_scan, not before
548141cc406Sopenharmony_ci         - extend get_pixelsize to request backside data
549141cc406Sopenharmony_ci         - stop using backup/restore_params
550141cc406Sopenharmony_ci         - don't use extended get_pixelsize on M3091 or M3092
551141cc406Sopenharmony_ci         - call software crop code on backside images too
552141cc406Sopenharmony_ci      v120 2014-01-29, MAN
553141cc406Sopenharmony_ci         - only call hopper_before_op code at batch start
554141cc406Sopenharmony_ci         - remove unused backup/restore_params
555141cc406Sopenharmony_ci      v121 2014-04-07, MAN
556141cc406Sopenharmony_ci         - add JFIF APP0 marker with resolution to jpeg images
557141cc406Sopenharmony_ci         - improve jpeg duplex parsing code
558141cc406Sopenharmony_ci         - simplify jpeg ifdefs
559141cc406Sopenharmony_ci         - add offtimer option for more recent scanners
560141cc406Sopenharmony_ci         - don't print 0 length line in hexdump
561141cc406Sopenharmony_ci      v122 2014-10-28, MAN
562141cc406Sopenharmony_ci         - add support for object_position halt
563141cc406Sopenharmony_ci         - call object_position halt in check_for_cancel when requested
564141cc406Sopenharmony_ci      v123 2014-11-06, MAN
565141cc406Sopenharmony_ci         - workaround Linux USB3 bugs by adding command counting code and
566141cc406Sopenharmony_ci           sending an even number of reads and writes during disconnect_fd
567141cc406Sopenharmony_ci      v124 2014-12-09, MAN
568141cc406Sopenharmony_ci         - support resolution controlled max page-height (fi-6/7xxx scanners)
569141cc406Sopenharmony_ci         - reorder scanner sections in init_model chronologically
570141cc406Sopenharmony_ci      v125 2014-12-16, MAN
571141cc406Sopenharmony_ci         - remove USB packet counting code from v123, fix sanei_usb instead
572141cc406Sopenharmony_ci      v126 2015-08-23, MAN
573141cc406Sopenharmony_ci         - initial support for iX100
574141cc406Sopenharmony_ci         - add late_lut support for iX500/iX100
575141cc406Sopenharmony_ci      v127 2015-08-25, MAN (SANE 1.0.25)
576141cc406Sopenharmony_ci         - separate iX100 from iX500 settings
577141cc406Sopenharmony_ci         - iX100 has gray and lineart
578141cc406Sopenharmony_ci      v128 2015-11-08, MAN
579141cc406Sopenharmony_ci         - do not ask fi-4340 for serial number
580141cc406Sopenharmony_ci      v129 2015-11-21, MAN
581141cc406Sopenharmony_ci         - br_x and br_y locked to page_width/height until changed
582141cc406Sopenharmony_ci      v130 2016-02-23, MAN
583141cc406Sopenharmony_ci         - run init_model before init_ms so some scanners can override
584141cc406Sopenharmony_ci         - set all M309x and M409x scanners s->broken_diag_serial = 1
585141cc406Sopenharmony_ci      v131 2016-06-06, MAN
586141cc406Sopenharmony_ci         - hide compression-arg option when jpeg disabled
587141cc406Sopenharmony_ci         - add Send/SC/GHS macros for recent scanners
588141cc406Sopenharmony_ci         - add initial support for fi-74x0
589141cc406Sopenharmony_ci         - add initial support for fi-7030
590141cc406Sopenharmony_ci         - set has_MS_lamp=0 for fi-71x0
591141cc406Sopenharmony_ci         - add I18N macros to all option titles and descriptions
592141cc406Sopenharmony_ci      v132 2016-10-07, MAN
593141cc406Sopenharmony_ci         - remove ipc_mode option and variables
594141cc406Sopenharmony_ci         - set ipc mode based on other options
595141cc406Sopenharmony_ci         - cleanup inverted logic DTC options
596141cc406Sopenharmony_ci         - fixes threshold option reported in #315069
597141cc406Sopenharmony_ci      v133 2017-04-08, MAN
598141cc406Sopenharmony_ci         - initial support for fi-7600/7700
599141cc406Sopenharmony_ci         - autodetect various double feed capabilities using VPD
600141cc406Sopenharmony_ci         - call send_lut if we are using a downloaded gamma table
601141cc406Sopenharmony_ci      v134 2019-02-23, MAN
602141cc406Sopenharmony_ci         - rewrite init_vpd for scanners which fail to report
603141cc406Sopenharmony_ci           overscan correctly
604141cc406Sopenharmony_ci      v135 2019-11-10, MAN (SANE 1.0.29)
605141cc406Sopenharmony_ci         - set has_MS_lamp=0 for fi-72x0, bug #134
606141cc406Sopenharmony_ci      v136 2020-02-07, MAN
607141cc406Sopenharmony_ci         - add support for fi-800R
608141cc406Sopenharmony_ci         - add support for card scanning slot (Return Path)
609141cc406Sopenharmony_ci         - fix bug with reading hardware sensors on first invocation
610141cc406Sopenharmony_ci      v137 2020-09-23, MAN
611141cc406Sopenharmony_ci         - fix JPEG duplex memory corruption
612141cc406Sopenharmony_ci         - change window_gamma init (fixes bright/contrast for iX1500)
613141cc406Sopenharmony_ci         - only call send_lut after set_window (remove late_lut)
614141cc406Sopenharmony_ci      v138 2022-06-01, MAN
615141cc406Sopenharmony_ci         - minor updates to company name (FCPA -> PFU)
616141cc406Sopenharmony_ci      v139 2022-11-15, MAN
617141cc406Sopenharmony_ci         - move updated window_gamma logic to set_window
618141cc406Sopenharmony_ci         - use internal gamma table if possible (fixes #618)
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci   SANE FLOW DIAGRAM
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci   - sane_init() : initialize backend
623141cc406Sopenharmony_ci   . - sane_get_devices() : query list of scanner devices
624141cc406Sopenharmony_ci   . - sane_open() : open a particular scanner device
625141cc406Sopenharmony_ci   . . - sane_set_io_mode : set blocking mode
626141cc406Sopenharmony_ci   . . - sane_get_select_fd : get scanner fd
627141cc406Sopenharmony_ci   . .
628141cc406Sopenharmony_ci   . . - sane_get_option_descriptor() : get option information
629141cc406Sopenharmony_ci   . . - sane_control_option() : change option values
630141cc406Sopenharmony_ci   . . - sane_get_parameters() : returns estimated scan parameters
631141cc406Sopenharmony_ci   . . - (repeat previous 3 functions)
632141cc406Sopenharmony_ci   . .
633141cc406Sopenharmony_ci   . . - sane_start() : start image acquisition
634141cc406Sopenharmony_ci   . .   - sane_get_parameters() : returns actual scan parameters
635141cc406Sopenharmony_ci   . .   - sane_read() : read image data (from pipe)
636141cc406Sopenharmony_ci   . . (sane_read called multiple times; after sane_read returns EOF,
637141cc406Sopenharmony_ci   . . loop may continue with sane_start which may return a 2nd page
638141cc406Sopenharmony_ci   . . when doing duplex scans, or load the next page from the ADF)
639141cc406Sopenharmony_ci   . .
640141cc406Sopenharmony_ci   . . - sane_cancel() : cancel operation
641141cc406Sopenharmony_ci   . - sane_close() : close opened scanner device
642141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend
643141cc406Sopenharmony_ci
644141cc406Sopenharmony_ci*/
645141cc406Sopenharmony_ci
646141cc406Sopenharmony_ci/*
647141cc406Sopenharmony_ci * @@ Section 1 - Boilerplate
648141cc406Sopenharmony_ci */
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_ci#include "../include/sane/config.h"
651141cc406Sopenharmony_ci
652141cc406Sopenharmony_ci#include <string.h> /*memcpy...*/
653141cc406Sopenharmony_ci#include <ctype.h> /*isspace*/
654141cc406Sopenharmony_ci#include <math.h> /*tan*/
655141cc406Sopenharmony_ci#include <unistd.h> /*usleep*/
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
658141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
659141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
660141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
661141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
662141cc406Sopenharmony_ci#include "../include/sane/sanei_magic.h"
663141cc406Sopenharmony_ci
664141cc406Sopenharmony_ci#include "fujitsu-scsi.h"
665141cc406Sopenharmony_ci#include "fujitsu.h"
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci#define DEBUG 1
668141cc406Sopenharmony_ci#define BUILD 139
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci/* values for SANE_DEBUG_FUJITSU env var:
671141cc406Sopenharmony_ci - errors           5
672141cc406Sopenharmony_ci - function trace  10
673141cc406Sopenharmony_ci - function detail 15
674141cc406Sopenharmony_ci - get/setopt cmds 20
675141cc406Sopenharmony_ci - scsi/usb trace  25
676141cc406Sopenharmony_ci - scsi/usb writes 30
677141cc406Sopenharmony_ci - scsi/usb reads  31
678141cc406Sopenharmony_ci - useless noise   35
679141cc406Sopenharmony_ci*/
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
682141cc406Sopenharmony_ci/* if JPEG support is not enabled in sane.h, we setup our own defines */
683141cc406Sopenharmony_ci#ifndef SANE_FRAME_JPEG
684141cc406Sopenharmony_ci#define SANE_FRAME_JPEG 0x0B
685141cc406Sopenharmony_ci#define SANE_JPEG_DISABLED 1
686141cc406Sopenharmony_ci#endif
687141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
688141cc406Sopenharmony_ci#define STRING_FLATBED SANE_I18N("Flatbed")
689141cc406Sopenharmony_ci#define STRING_ADFFRONT SANE_I18N("ADF Front")
690141cc406Sopenharmony_ci#define STRING_ADFBACK SANE_I18N("ADF Back")
691141cc406Sopenharmony_ci#define STRING_ADFDUPLEX SANE_I18N("ADF Duplex")
692141cc406Sopenharmony_ci#define STRING_CARDFRONT SANE_I18N("Card Front")
693141cc406Sopenharmony_ci#define STRING_CARDBACK SANE_I18N("Card Back")
694141cc406Sopenharmony_ci#define STRING_CARDDUPLEX SANE_I18N("Card Duplex")
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci#define STRING_LINEART SANE_VALUE_SCAN_MODE_LINEART
697141cc406Sopenharmony_ci#define STRING_HALFTONE SANE_VALUE_SCAN_MODE_HALFTONE
698141cc406Sopenharmony_ci#define STRING_GRAYSCALE SANE_VALUE_SCAN_MODE_GRAY
699141cc406Sopenharmony_ci#define STRING_COLOR SANE_VALUE_SCAN_MODE_COLOR
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci#define STRING_DEFAULT SANE_I18N("Default")
702141cc406Sopenharmony_ci#define STRING_ON SANE_I18N("On")
703141cc406Sopenharmony_ci#define STRING_OFF SANE_I18N("Off")
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci#define STRING_DTC SANE_I18N("DTC")
706141cc406Sopenharmony_ci#define STRING_SDTC SANE_I18N("SDTC")
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci#define STRING_DITHER SANE_I18N("Dither")
709141cc406Sopenharmony_ci#define STRING_DIFFUSION SANE_I18N("Diffusion")
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci#define STRING_RED SANE_I18N("Red")
712141cc406Sopenharmony_ci#define STRING_GREEN SANE_I18N("Green")
713141cc406Sopenharmony_ci#define STRING_BLUE SANE_I18N("Blue")
714141cc406Sopenharmony_ci#define STRING_WHITE SANE_I18N("White")
715141cc406Sopenharmony_ci#define STRING_BLACK SANE_I18N("Black")
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci#define STRING_NONE SANE_I18N("None")
718141cc406Sopenharmony_ci#define STRING_JPEG SANE_I18N("JPEG")
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci#define STRING_CONTINUE SANE_I18N("Continue")
721141cc406Sopenharmony_ci#define STRING_STOP SANE_I18N("Stop")
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci#define STRING_10MM SANE_I18N("10mm")
724141cc406Sopenharmony_ci#define STRING_15MM SANE_I18N("15mm")
725141cc406Sopenharmony_ci#define STRING_20MM SANE_I18N("20mm")
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci#define STRING_HORIZONTAL SANE_I18N("Horizontal")
728141cc406Sopenharmony_ci#define STRING_HORIZONTALBOLD SANE_I18N("Horizontal bold")
729141cc406Sopenharmony_ci#define STRING_HORIZONTALNARROW SANE_I18N("Horizontal narrow")
730141cc406Sopenharmony_ci#define STRING_VERTICAL SANE_I18N("Vertical")
731141cc406Sopenharmony_ci#define STRING_VERTICALBOLD SANE_I18N("Vertical bold")
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci#define STRING_TOPTOBOTTOM SANE_I18N("Top to bottom")
734141cc406Sopenharmony_ci#define STRING_BOTTOMTOTOP SANE_I18N("Bottom to top")
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci#define STRING_FRONT SANE_I18N("Front")
737141cc406Sopenharmony_ci#define STRING_BACK SANE_I18N("Back")
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci#define max(a,b) (((a)>(b))?(a):(b))
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci/* Also set via config file. */
742141cc406Sopenharmony_cistatic int global_buffer_size = 64 * 1024;
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci/*
745141cc406Sopenharmony_ci * used by attach* and sane_get_devices
746141cc406Sopenharmony_ci * a ptr to a null term array of ptrs to SANE_Device structs
747141cc406Sopenharmony_ci * a ptr to a single-linked list of fujitsu structs
748141cc406Sopenharmony_ci */
749141cc406Sopenharmony_cistatic const SANE_Device **sane_devArray = NULL;
750141cc406Sopenharmony_cistatic struct fujitsu *fujitsu_devList = NULL;
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci/*
753141cc406Sopenharmony_ci * @@ Section 2 - SANE & scanner init code
754141cc406Sopenharmony_ci */
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci/*
757141cc406Sopenharmony_ci * Called by SANE initially.
758141cc406Sopenharmony_ci *
759141cc406Sopenharmony_ci * From the SANE spec:
760141cc406Sopenharmony_ci * This function must be called before any other SANE function can be
761141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this
762141cc406Sopenharmony_ci * function is not called first. The version code of the backend is
763141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer
764141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either
765141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires
766141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does
767141cc406Sopenharmony_ci * not support authentication.
768141cc406Sopenharmony_ci */
769141cc406Sopenharmony_ciSANE_Status
770141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
771141cc406Sopenharmony_ci{
772141cc406Sopenharmony_ci  (void) authorize;             /* get rid of compiler warning */
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  DBG_INIT ();
775141cc406Sopenharmony_ci  DBG (10, "sane_init: start\n");
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci  if (version_code)
778141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci  DBG (5, "sane_init: fujitsu backend %d.%d.%d, from %s\n",
781141cc406Sopenharmony_ci    SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ci  sanei_magic_init();
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci  DBG (10, "sane_init: finish\n");
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
788141cc406Sopenharmony_ci}
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci/*
791141cc406Sopenharmony_ci * Called by SANE to find out about supported devices.
792141cc406Sopenharmony_ci *
793141cc406Sopenharmony_ci * From the SANE spec:
794141cc406Sopenharmony_ci * This function can be used to query the list of devices that are
795141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a
796141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device
797141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to
798141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function
799141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This
800141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become
801141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are
802141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is
803141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote
804141cc406Sopenharmony_ci * devices that are accessible to the SANE library.
805141cc406Sopenharmony_ci *
806141cc406Sopenharmony_ci * SANE does not require that this function is called before a
807141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified
808141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and
809141cc406Sopenharmony_ci * undesirable to call this function first.
810141cc406Sopenharmony_ci */
811141cc406Sopenharmony_ci/*
812141cc406Sopenharmony_ci * Read the config file, find scanners with help from sanei_*
813141cc406Sopenharmony_ci * and store in global device structs
814141cc406Sopenharmony_ci */
815141cc406Sopenharmony_ciSANE_Status
816141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
817141cc406Sopenharmony_ci{
818141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
819141cc406Sopenharmony_ci  struct fujitsu * s;
820141cc406Sopenharmony_ci  struct fujitsu * prev = NULL;
821141cc406Sopenharmony_ci  char line[PATH_MAX];
822141cc406Sopenharmony_ci  const char *lp;
823141cc406Sopenharmony_ci  FILE *fp;
824141cc406Sopenharmony_ci  int num_devices=0;
825141cc406Sopenharmony_ci  int i=0;
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci  (void) local_only;            /* get rid of compiler warning */
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  DBG (10, "sane_get_devices: start\n");
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  /* mark all existing scanners as missing, attach_one will remove mark */
832141cc406Sopenharmony_ci  for (s = fujitsu_devList; s; s = s->next) {
833141cc406Sopenharmony_ci    s->missing = 1;
834141cc406Sopenharmony_ci  }
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  sanei_usb_init();
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci  /* set this to 64K before reading the file */
839141cc406Sopenharmony_ci  global_buffer_size = 64 * 1024;
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci  fp = sanei_config_open (FUJITSU_CONFIG_FILE);
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci  if (fp) {
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci      DBG (15, "sane_get_devices: reading config file %s\n",
846141cc406Sopenharmony_ci        FUJITSU_CONFIG_FILE);
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci      while (sanei_config_read (line, PATH_MAX, fp)) {
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci          lp = line;
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_ci          /* ignore comments */
853141cc406Sopenharmony_ci          if (*lp == '#')
854141cc406Sopenharmony_ci            continue;
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci          /* skip empty lines */
857141cc406Sopenharmony_ci          if (*lp == 0)
858141cc406Sopenharmony_ci            continue;
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci          if ((strncmp ("option", lp, 6) == 0) && isspace (lp[6])) {
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci              lp += 6;
863141cc406Sopenharmony_ci              lp = sanei_config_skip_whitespace (lp);
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci              /* we allow setting buffersize too big */
866141cc406Sopenharmony_ci              if ((strncmp (lp, "buffer-size", 11) == 0) && isspace (lp[11])) {
867141cc406Sopenharmony_ci
868141cc406Sopenharmony_ci                  int buf;
869141cc406Sopenharmony_ci                  lp += 11;
870141cc406Sopenharmony_ci                  lp = sanei_config_skip_whitespace (lp);
871141cc406Sopenharmony_ci                  buf = atoi (lp);
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci                  if (buf < 4096) {
874141cc406Sopenharmony_ci                    DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is < 4096, ignoring!\n", buf);
875141cc406Sopenharmony_ci                    continue;
876141cc406Sopenharmony_ci                  }
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci                  if (buf > 64*1024) {
879141cc406Sopenharmony_ci                    DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is > %d, warning!\n", buf, 64*1024);
880141cc406Sopenharmony_ci                  }
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci                  DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n", buf);
883141cc406Sopenharmony_ci                  global_buffer_size = buf;
884141cc406Sopenharmony_ci              }
885141cc406Sopenharmony_ci              else {
886141cc406Sopenharmony_ci                  DBG (5, "sane_get_devices: config option \"%s\" unrecognized - ignored.\n", lp);
887141cc406Sopenharmony_ci              }
888141cc406Sopenharmony_ci          }
889141cc406Sopenharmony_ci          else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) {
890141cc406Sopenharmony_ci              DBG (15, "sane_get_devices: looking for '%s'\n", lp);
891141cc406Sopenharmony_ci              sanei_usb_attach_matching_devices(lp, attach_one_usb);
892141cc406Sopenharmony_ci          }
893141cc406Sopenharmony_ci          else if ((strncmp ("scsi", lp, 4) == 0) && isspace (lp[4])) {
894141cc406Sopenharmony_ci              DBG (15, "sane_get_devices: looking for '%s'\n", lp);
895141cc406Sopenharmony_ci              sanei_config_attach_matching_devices (lp, attach_one_scsi);
896141cc406Sopenharmony_ci          }
897141cc406Sopenharmony_ci          else{
898141cc406Sopenharmony_ci              DBG (5, "sane_get_devices: config line \"%s\" unrecognized - ignored.\n", lp);
899141cc406Sopenharmony_ci          }
900141cc406Sopenharmony_ci      }
901141cc406Sopenharmony_ci      fclose (fp);
902141cc406Sopenharmony_ci  }
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci  else {
905141cc406Sopenharmony_ci      DBG (5, "sane_get_devices: missing required config file '%s'!\n",
906141cc406Sopenharmony_ci        FUJITSU_CONFIG_FILE);
907141cc406Sopenharmony_ci  }
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci  /*delete missing scanners from list*/
910141cc406Sopenharmony_ci  for (s = fujitsu_devList; s;) {
911141cc406Sopenharmony_ci    if(s->missing){
912141cc406Sopenharmony_ci      DBG (5, "sane_get_devices: missing scanner %s\n",s->device_name);
913141cc406Sopenharmony_ci
914141cc406Sopenharmony_ci      /*splice s out of list by changing pointer in prev to next*/
915141cc406Sopenharmony_ci      if(prev){
916141cc406Sopenharmony_ci        prev->next = s->next;
917141cc406Sopenharmony_ci        free(s);
918141cc406Sopenharmony_ci        s=prev->next;
919141cc406Sopenharmony_ci      }
920141cc406Sopenharmony_ci      /*remove s from head of list, using prev to cache it*/
921141cc406Sopenharmony_ci      else{
922141cc406Sopenharmony_ci        prev = s;
923141cc406Sopenharmony_ci        s = s->next;
924141cc406Sopenharmony_ci        free(prev);
925141cc406Sopenharmony_ci	prev=NULL;
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci	/*reset head to next s*/
928141cc406Sopenharmony_ci	fujitsu_devList = s;
929141cc406Sopenharmony_ci      }
930141cc406Sopenharmony_ci    }
931141cc406Sopenharmony_ci    else{
932141cc406Sopenharmony_ci      prev = s;
933141cc406Sopenharmony_ci      s=prev->next;
934141cc406Sopenharmony_ci    }
935141cc406Sopenharmony_ci  }
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci  for (s = fujitsu_devList; s; s=s->next) {
938141cc406Sopenharmony_ci    DBG (15, "sane_get_devices: found scanner %s\n",s->device_name);
939141cc406Sopenharmony_ci    num_devices++;
940141cc406Sopenharmony_ci  }
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci  DBG (15, "sane_get_devices: found %d scanner(s)\n",num_devices);
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci  if (sane_devArray)
945141cc406Sopenharmony_ci    free (sane_devArray);
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci  sane_devArray = calloc (num_devices + 1, sizeof (SANE_Device*));
948141cc406Sopenharmony_ci  if (!sane_devArray)
949141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci  for (s = fujitsu_devList; s; s=s->next) {
952141cc406Sopenharmony_ci    sane_devArray[i++] = (SANE_Device *)&s->sane;
953141cc406Sopenharmony_ci  }
954141cc406Sopenharmony_ci  sane_devArray[i] = 0;
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci  if(device_list){
957141cc406Sopenharmony_ci      *device_list = sane_devArray;
958141cc406Sopenharmony_ci  }
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci  DBG (10, "sane_get_devices: finish\n");
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci  return ret;
963141cc406Sopenharmony_ci}
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci/* callbacks used by sane_get_devices */
966141cc406Sopenharmony_cistatic SANE_Status
967141cc406Sopenharmony_ciattach_one_scsi (const char *device_name)
968141cc406Sopenharmony_ci{
969141cc406Sopenharmony_ci  return attach_one(device_name,CONNECTION_SCSI);
970141cc406Sopenharmony_ci}
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_cistatic SANE_Status
973141cc406Sopenharmony_ciattach_one_usb (const char *device_name)
974141cc406Sopenharmony_ci{
975141cc406Sopenharmony_ci  return attach_one(device_name,CONNECTION_USB);
976141cc406Sopenharmony_ci}
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci/* build the scanner struct and link to global list
979141cc406Sopenharmony_ci * unless struct is already loaded, then pretend
980141cc406Sopenharmony_ci */
981141cc406Sopenharmony_cistatic SANE_Status
982141cc406Sopenharmony_ciattach_one (const char *device_name, int connType)
983141cc406Sopenharmony_ci{
984141cc406Sopenharmony_ci  struct fujitsu *s;
985141cc406Sopenharmony_ci  int ret;
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci  DBG (10, "attach_one: start\n");
988141cc406Sopenharmony_ci  DBG (15, "attach_one: looking for '%s'\n", device_name);
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci  for (s = fujitsu_devList; s; s = s->next) {
991141cc406Sopenharmony_ci    if (strcmp (s->device_name, device_name) == 0){
992141cc406Sopenharmony_ci      DBG (10, "attach_one: already attached!\n");
993141cc406Sopenharmony_ci      s->missing = 0;
994141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
995141cc406Sopenharmony_ci    }
996141cc406Sopenharmony_ci  }
997141cc406Sopenharmony_ci
998141cc406Sopenharmony_ci  /* build a fujitsu struct to hold it */
999141cc406Sopenharmony_ci  if ((s = calloc (sizeof (*s), 1)) == NULL)
1000141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci  /* scsi command/data buffer */
1003141cc406Sopenharmony_ci  s->buffer_size = global_buffer_size;
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci  /* copy the device name */
1006141cc406Sopenharmony_ci  strcpy (s->device_name, device_name);
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci  /* connect the fd */
1009141cc406Sopenharmony_ci  s->connection = connType;
1010141cc406Sopenharmony_ci  s->fd = -1;
1011141cc406Sopenharmony_ci  ret = connect_fd(s);
1012141cc406Sopenharmony_ci  if(ret != SANE_STATUS_GOOD){
1013141cc406Sopenharmony_ci    free (s);
1014141cc406Sopenharmony_ci    return ret;
1015141cc406Sopenharmony_ci  }
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ci  /* Now query the device to load its vendor/model/version */
1018141cc406Sopenharmony_ci  ret = init_inquire (s);
1019141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1020141cc406Sopenharmony_ci    disconnect_fd(s);
1021141cc406Sopenharmony_ci    free (s);
1022141cc406Sopenharmony_ci    DBG (5, "attach_one: inquiry failed\n");
1023141cc406Sopenharmony_ci    return ret;
1024141cc406Sopenharmony_ci  }
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci  /* load detailed specs/capabilities from the device */
1027141cc406Sopenharmony_ci  ret = init_vpd (s);
1028141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1029141cc406Sopenharmony_ci    disconnect_fd(s);
1030141cc406Sopenharmony_ci    free (s);
1031141cc406Sopenharmony_ci    DBG (5, "attach_one: vpd failed\n");
1032141cc406Sopenharmony_ci    return ret;
1033141cc406Sopenharmony_ci  }
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci  /* clean up the scanner struct based on model */
1036141cc406Sopenharmony_ci  /* this is the only piece of model specific code */
1037141cc406Sopenharmony_ci  ret = init_model (s);
1038141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1039141cc406Sopenharmony_ci    disconnect_fd(s);
1040141cc406Sopenharmony_ci    free (s);
1041141cc406Sopenharmony_ci    DBG (5, "attach_one: model failed\n");
1042141cc406Sopenharmony_ci    return ret;
1043141cc406Sopenharmony_ci  }
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ci  /* see what mode pages device supports */
1046141cc406Sopenharmony_ci  ret = init_ms (s);
1047141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1048141cc406Sopenharmony_ci    disconnect_fd(s);
1049141cc406Sopenharmony_ci    free (s);
1050141cc406Sopenharmony_ci    DBG (5, "attach_one: ms failed\n");
1051141cc406Sopenharmony_ci    return ret;
1052141cc406Sopenharmony_ci  }
1053141cc406Sopenharmony_ci
1054141cc406Sopenharmony_ci  /* sets SANE option 'values' to good defaults */
1055141cc406Sopenharmony_ci  ret = init_user (s);
1056141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1057141cc406Sopenharmony_ci    disconnect_fd(s);
1058141cc406Sopenharmony_ci    free (s);
1059141cc406Sopenharmony_ci    DBG (5, "attach_one: user failed\n");
1060141cc406Sopenharmony_ci    return ret;
1061141cc406Sopenharmony_ci  }
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci  ret = init_options (s);
1064141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1065141cc406Sopenharmony_ci    disconnect_fd(s);
1066141cc406Sopenharmony_ci    free (s);
1067141cc406Sopenharmony_ci    DBG (5, "attach_one: options failed\n");
1068141cc406Sopenharmony_ci    return ret;
1069141cc406Sopenharmony_ci  }
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  ret = init_interlace (s);
1072141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
1073141cc406Sopenharmony_ci    disconnect_fd(s);
1074141cc406Sopenharmony_ci    free (s);
1075141cc406Sopenharmony_ci    DBG (5, "attach_one: interlace failed\n");
1076141cc406Sopenharmony_ci    return ret;
1077141cc406Sopenharmony_ci  }
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci  /* load strings into sane_device struct */
1080141cc406Sopenharmony_ci  s->sane.name = s->device_name;
1081141cc406Sopenharmony_ci  s->sane.vendor = s->vendor_name;
1082141cc406Sopenharmony_ci  s->sane.model = s->model_name;
1083141cc406Sopenharmony_ci  s->sane.type = "scanner";
1084141cc406Sopenharmony_ci
1085141cc406Sopenharmony_ci  /* change name in sane_device struct if scanner has serial number */
1086141cc406Sopenharmony_ci  ret = init_serial (s);
1087141cc406Sopenharmony_ci  if (ret == SANE_STATUS_GOOD) {
1088141cc406Sopenharmony_ci    s->sane.name = s->serial_name;
1089141cc406Sopenharmony_ci  }
1090141cc406Sopenharmony_ci  else{
1091141cc406Sopenharmony_ci    DBG (5, "attach_one: serial number unsupported?\n");
1092141cc406Sopenharmony_ci  }
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci  /* we close the connection, so that another backend can talk to scanner */
1095141cc406Sopenharmony_ci  disconnect_fd(s);
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci  /* store this scanner in global vars */
1098141cc406Sopenharmony_ci  s->next = fujitsu_devList;
1099141cc406Sopenharmony_ci  fujitsu_devList = s;
1100141cc406Sopenharmony_ci
1101141cc406Sopenharmony_ci  DBG (10, "attach_one: finish\n");
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1104141cc406Sopenharmony_ci}
1105141cc406Sopenharmony_ci
1106141cc406Sopenharmony_ci/*
1107141cc406Sopenharmony_ci * connect the fd in the scanner struct
1108141cc406Sopenharmony_ci */
1109141cc406Sopenharmony_cistatic SANE_Status
1110141cc406Sopenharmony_ciconnect_fd (struct fujitsu *s)
1111141cc406Sopenharmony_ci{
1112141cc406Sopenharmony_ci  SANE_Status ret;
1113141cc406Sopenharmony_ci  int buffer_size = s->buffer_size;
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  DBG (10, "connect_fd: start\n");
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci  if(s->fd > -1){
1118141cc406Sopenharmony_ci    DBG (5, "connect_fd: already open\n");
1119141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
1120141cc406Sopenharmony_ci  }
1121141cc406Sopenharmony_ci  else if (s->connection == CONNECTION_USB) {
1122141cc406Sopenharmony_ci    DBG (15, "connect_fd: opening USB device\n");
1123141cc406Sopenharmony_ci    ret = sanei_usb_open (s->device_name, &(s->fd));
1124141cc406Sopenharmony_ci  }
1125141cc406Sopenharmony_ci  else {
1126141cc406Sopenharmony_ci    DBG (15, "connect_fd: opening SCSI device\n");
1127141cc406Sopenharmony_ci    ret = sanei_scsi_open_extended (s->device_name, &(s->fd), sense_handler, s,
1128141cc406Sopenharmony_ci      &s->buffer_size);
1129141cc406Sopenharmony_ci    if(!ret && buffer_size != s->buffer_size){
1130141cc406Sopenharmony_ci      DBG (5, "connect_fd: cannot get requested buffer size (%d/%d)\n",
1131141cc406Sopenharmony_ci        buffer_size, s->buffer_size);
1132141cc406Sopenharmony_ci    }
1133141cc406Sopenharmony_ci  }
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci  if(ret == SANE_STATUS_GOOD){
1136141cc406Sopenharmony_ci
1137141cc406Sopenharmony_ci    /* first generation usb scanners can get flaky if not closed
1138141cc406Sopenharmony_ci     * properly after last use. very first commands sent to device
1139141cc406Sopenharmony_ci     * must be prepared to correct this- see wait_scanner() */
1140141cc406Sopenharmony_ci    ret = wait_scanner(s);
1141141cc406Sopenharmony_ci    if (ret != SANE_STATUS_GOOD) {
1142141cc406Sopenharmony_ci      DBG (5, "connect_fd: could not wait_scanner\n");
1143141cc406Sopenharmony_ci      disconnect_fd(s);
1144141cc406Sopenharmony_ci    }
1145141cc406Sopenharmony_ci
1146141cc406Sopenharmony_ci  }
1147141cc406Sopenharmony_ci  else{
1148141cc406Sopenharmony_ci    DBG (5, "connect_fd: could not open device: %d\n", ret);
1149141cc406Sopenharmony_ci  }
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci  DBG (10, "connect_fd: finish\n");
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci  return ret;
1154141cc406Sopenharmony_ci}
1155141cc406Sopenharmony_ci
1156141cc406Sopenharmony_ci/*
1157141cc406Sopenharmony_ci * This routine will check if a certain device is a Fujitsu scanner
1158141cc406Sopenharmony_ci * It also copies interesting data from INQUIRY into the handle structure
1159141cc406Sopenharmony_ci */
1160141cc406Sopenharmony_cistatic SANE_Status
1161141cc406Sopenharmony_ciinit_inquire (struct fujitsu *s)
1162141cc406Sopenharmony_ci{
1163141cc406Sopenharmony_ci  int i;
1164141cc406Sopenharmony_ci  SANE_Status ret;
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci  unsigned char cmd[INQUIRY_len];
1167141cc406Sopenharmony_ci  size_t cmdLen = INQUIRY_len;
1168141cc406Sopenharmony_ci
1169141cc406Sopenharmony_ci  unsigned char in[INQUIRY_std_len];
1170141cc406Sopenharmony_ci  size_t inLen = INQUIRY_std_len;
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_ci  DBG (10, "init_inquire: start\n");
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
1175141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, INQUIRY_code);
1176141cc406Sopenharmony_ci  set_IN_return_size (cmd, inLen);
1177141cc406Sopenharmony_ci  set_IN_evpd (cmd, 0);
1178141cc406Sopenharmony_ci  set_IN_page_code (cmd, 0);
1179141cc406Sopenharmony_ci
1180141cc406Sopenharmony_ci  ret = do_cmd (
1181141cc406Sopenharmony_ci    s, 1, 0,
1182141cc406Sopenharmony_ci    cmd, cmdLen,
1183141cc406Sopenharmony_ci    NULL, 0,
1184141cc406Sopenharmony_ci    in, &inLen
1185141cc406Sopenharmony_ci  );
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
1188141cc406Sopenharmony_ci    return ret;
1189141cc406Sopenharmony_ci  }
1190141cc406Sopenharmony_ci
1191141cc406Sopenharmony_ci  if (get_IN_periph_devtype (in) != IN_periph_devtype_scanner){
1192141cc406Sopenharmony_ci    DBG (5, "The device at '%s' is not a scanner.\n", s->device_name);
1193141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1194141cc406Sopenharmony_ci  }
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci  get_IN_vendor (in, s->vendor_name);
1197141cc406Sopenharmony_ci  get_IN_product (in, s->model_name);
1198141cc406Sopenharmony_ci  get_IN_version (in, s->version_name);
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci  s->vendor_name[8] = 0;
1201141cc406Sopenharmony_ci  s->model_name[16] = 0;
1202141cc406Sopenharmony_ci  s->version_name[4] = 0;
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci  /* gobble trailing spaces */
1205141cc406Sopenharmony_ci  for (i = 7; s->vendor_name[i] == ' ' && i >= 0; i--)
1206141cc406Sopenharmony_ci    s->vendor_name[i] = 0;
1207141cc406Sopenharmony_ci  for (i = 15; s->model_name[i] == ' ' && i >= 0; i--)
1208141cc406Sopenharmony_ci    s->model_name[i] = 0;
1209141cc406Sopenharmony_ci  for (i = 3; s->version_name[i] == ' ' && i >= 0; i--)
1210141cc406Sopenharmony_ci    s->version_name[i] = 0;
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci  if (strcmp ("FUJITSU", s->vendor_name)) {
1213141cc406Sopenharmony_ci    DBG (5, "The device at '%s' is reported to be made by '%s'\n", s->device_name, s->vendor_name);
1214141cc406Sopenharmony_ci    DBG (5, "This backend only supports Fujitsu products.\n");
1215141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1216141cc406Sopenharmony_ci  }
1217141cc406Sopenharmony_ci
1218141cc406Sopenharmony_ci  DBG (15, "init_inquire: Found %s scanner %s version %s at %s\n",
1219141cc406Sopenharmony_ci    s->vendor_name, s->model_name, s->version_name, s->device_name);
1220141cc406Sopenharmony_ci
1221141cc406Sopenharmony_ci  /*some scanners list random data here*/
1222141cc406Sopenharmony_ci  DBG (15, "inquiry options\n");
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci  s->color_raster_offset = get_IN_color_offset(in);
1225141cc406Sopenharmony_ci  DBG (15, "  color offset: %d lines\n",s->color_raster_offset);
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci  /* FIXME: we don't store all of these? */
1228141cc406Sopenharmony_ci  DBG (15, "  long gray scan: %d\n",get_IN_long_gray(in));
1229141cc406Sopenharmony_ci  DBG (15, "  long color scan: %d\n",get_IN_long_color(in));
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci  DBG (15, "  emulation mode: %d\n",get_IN_emulation(in));
1232141cc406Sopenharmony_ci  DBG (15, "  CMP/CGA: %d\n",get_IN_cmp_cga(in));
1233141cc406Sopenharmony_ci  DBG (15, "  background back: %d\n",get_IN_bg_back(in));
1234141cc406Sopenharmony_ci  DBG (15, "  background front: %d\n",get_IN_bg_front(in));
1235141cc406Sopenharmony_ci  DBG (15, "  background fb: %d\n",get_IN_bg_fb(in));
1236141cc406Sopenharmony_ci  DBG (15, "  back only scan: %d\n",get_IN_has_back(in));
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci  s->duplex_raster_offset = get_IN_duplex_offset(in);
1239141cc406Sopenharmony_ci  DBG (15, "  duplex offset: %d lines\n",s->duplex_raster_offset);
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci  DBG (10, "init_inquire: finish\n");
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1244141cc406Sopenharmony_ci}
1245141cc406Sopenharmony_ci
1246141cc406Sopenharmony_ci/*
1247141cc406Sopenharmony_ci * Use INQUIRY VPD to setup more detail about the scanner
1248141cc406Sopenharmony_ci */
1249141cc406Sopenharmony_cistatic SANE_Status
1250141cc406Sopenharmony_ciinit_vpd (struct fujitsu *s)
1251141cc406Sopenharmony_ci{
1252141cc406Sopenharmony_ci  SANE_Status ret;
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  unsigned char cmd[INQUIRY_len];
1255141cc406Sopenharmony_ci  size_t cmdLen = INQUIRY_len;
1256141cc406Sopenharmony_ci
1257141cc406Sopenharmony_ci  unsigned char in[INQUIRY_vpd_len];
1258141cc406Sopenharmony_ci  size_t inLen = INQUIRY_vpd_len;
1259141cc406Sopenharmony_ci
1260141cc406Sopenharmony_ci  int payload_len, payload_off;
1261141cc406Sopenharmony_ci
1262141cc406Sopenharmony_ci  DBG (10, "init_vpd: start\n");
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci  /* get EVPD */
1265141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
1266141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, INQUIRY_code);
1267141cc406Sopenharmony_ci  set_IN_return_size (cmd, inLen);
1268141cc406Sopenharmony_ci  set_IN_evpd (cmd, 1);
1269141cc406Sopenharmony_ci  set_IN_page_code (cmd, 0xf0);
1270141cc406Sopenharmony_ci
1271141cc406Sopenharmony_ci  ret = do_cmd (
1272141cc406Sopenharmony_ci    s, 1, 0,
1273141cc406Sopenharmony_ci    cmd, cmdLen,
1274141cc406Sopenharmony_ci    NULL, 0,
1275141cc406Sopenharmony_ci    in, &inLen
1276141cc406Sopenharmony_ci  );
1277141cc406Sopenharmony_ci
1278141cc406Sopenharmony_ci  /*FIXME no vpd, set some defaults? */
1279141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_EOF) {
1280141cc406Sopenharmony_ci    DBG (5, "init_vpd: Your scanner does not support VPD?\n");
1281141cc406Sopenharmony_ci    DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n");
1282141cc406Sopenharmony_ci    DBG (5, "init_vpd: with details of your scanner model.\n");
1283141cc406Sopenharmony_ci    return ret;
1284141cc406Sopenharmony_ci  }
1285141cc406Sopenharmony_ci
1286141cc406Sopenharmony_ci  /* In byte 4, the scanner sends the length of the remainder of
1287141cc406Sopenharmony_ci   * the payload. But, this value is often bogus. */
1288141cc406Sopenharmony_ci  payload_len = get_IN_page_length(in);
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  DBG (15, "init_vpd: length=%0x\n", payload_len);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  /* M3099 gives all data, but wrong length */
1293141cc406Sopenharmony_ci  if (strstr (s->model_name, "M3099") && payload_len == 0x19){
1294141cc406Sopenharmony_ci    DBG (5, "init_vpd: M3099 repair\n");
1295141cc406Sopenharmony_ci    payload_len = 0x5f;
1296141cc406Sopenharmony_ci  }
1297141cc406Sopenharmony_ci
1298141cc406Sopenharmony_ci  /* M3097G has short vpd, fill in missing part */
1299141cc406Sopenharmony_ci  else if (strstr (s->model_name, "M3097G") && payload_len == 0x19){
1300141cc406Sopenharmony_ci    unsigned char vpd3097g[] = {
1301141cc406Sopenharmony_ci0, 0,
1302141cc406Sopenharmony_ci0xc2, 0x08, 0, 0, 0, 0, 0, 0, 0xed, 0xbf, 0, 0, 0, 0, 0, 0,
1303141cc406Sopenharmony_ci0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1304141cc406Sopenharmony_ci0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1305141cc406Sopenharmony_ci0, 0, 0xff, 0xff, 0xff, 0, 0x45, 0x35, 0, 0xe0, 0, 0, 0, 0, 0, 0,
1306141cc406Sopenharmony_ci0, 0, 0, 0
1307141cc406Sopenharmony_ci    };
1308141cc406Sopenharmony_ci
1309141cc406Sopenharmony_ci    DBG (5, "init_vpd: M3097G repair\n");
1310141cc406Sopenharmony_ci    payload_len = 0x5f;
1311141cc406Sopenharmony_ci    memcpy(in+0x1e,vpd3097g,sizeof(vpd3097g));
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci    /*IPC*/
1314141cc406Sopenharmony_ci    if(strstr (s->model_name, "i")){
1315141cc406Sopenharmony_ci      DBG (5, "init_vpd: M3097G IPC repair\n");
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_ci      /*subwin cmd*/
1318141cc406Sopenharmony_ci      in[0x2b] = 1;
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci      /*rif/dtc/sdtc/outline/emph/sep/mirr/wlf*/
1321141cc406Sopenharmony_ci      in[0x58] = 0xff;
1322141cc406Sopenharmony_ci
1323141cc406Sopenharmony_ci      /*subwin/diffusion*/
1324141cc406Sopenharmony_ci      in[0x59] = 0xc0;
1325141cc406Sopenharmony_ci    }
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci    /*CMP*/
1328141cc406Sopenharmony_ci    if(strstr (s->model_name, "m")){
1329141cc406Sopenharmony_ci      DBG (5, "init_vpd: M3097G CMP repair\n");
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci      /*4megs*/
1332141cc406Sopenharmony_ci      in[0x23] = 0x40;
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci      /*mh/mr/mmr*/
1335141cc406Sopenharmony_ci      in[0x5a] = 0xe0;
1336141cc406Sopenharmony_ci    }
1337141cc406Sopenharmony_ci  }
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci  /* all other known scanners have at least 0x5f,
1340141cc406Sopenharmony_ci   * less would require software changes like above */
1341141cc406Sopenharmony_ci  else if (payload_len < 0x5f) {
1342141cc406Sopenharmony_ci    DBG (5, "init_vpd: Your scanner supports only partial VPD?\n");
1343141cc406Sopenharmony_ci    DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n");
1344141cc406Sopenharmony_ci    DBG (5, "init_vpd: with details of your scanner model.\n");
1345141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1346141cc406Sopenharmony_ci  }
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci  /* Special case- some scanners will under-report the amount of
1349141cc406Sopenharmony_ci   * valid vpd that they send, and return the default length.
1350141cc406Sopenharmony_ci   * Adding 4 more bytes allows us to include the overscan info.
1351141cc406Sopenharmony_ci   * Scanners that don't support overscan seem to have all zeros
1352141cc406Sopenharmony_ci   * in these bytes, so no harm is done.
1353141cc406Sopenharmony_ci   * This may be an 'off-by-four' error in the firmware. */
1354141cc406Sopenharmony_ci  else if (payload_len == 0x5f){
1355141cc406Sopenharmony_ci    payload_len += 4;
1356141cc406Sopenharmony_ci  }
1357141cc406Sopenharmony_ci
1358141cc406Sopenharmony_ci  /* Having an offset from the beginning of the payload
1359141cc406Sopenharmony_ci   * is more useful than from byte 4, as that matches the
1360141cc406Sopenharmony_ci   * documentation more closely. */
1361141cc406Sopenharmony_ci  payload_off = payload_len + 4;
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci  /* everything that appears in bytes 0 to 0x1d */
1364141cc406Sopenharmony_ci  DBG (15, "standard options\n");
1365141cc406Sopenharmony_ci
1366141cc406Sopenharmony_ci  s->basic_x_res = get_IN_basic_x_res (in);
1367141cc406Sopenharmony_ci  DBG (15, "  basic x res: %d dpi\n",s->basic_x_res);
1368141cc406Sopenharmony_ci
1369141cc406Sopenharmony_ci  s->basic_y_res = get_IN_basic_y_res (in);
1370141cc406Sopenharmony_ci  DBG (15, "  basic y res: %d dpi\n",s->basic_y_res);
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci  s->step_x_res[MODE_LINEART] = get_IN_step_x_res (in);
1373141cc406Sopenharmony_ci  DBG (15, "  step x res: %d dpi\n", s->step_x_res[MODE_LINEART]);
1374141cc406Sopenharmony_ci
1375141cc406Sopenharmony_ci  s->step_y_res[MODE_LINEART] = get_IN_step_y_res (in);
1376141cc406Sopenharmony_ci  DBG (15, "  step y res: %d dpi\n", s->step_y_res[MODE_LINEART]);
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci  s->max_x_res = get_IN_max_x_res (in);
1379141cc406Sopenharmony_ci  DBG (15, "  max x res: %d dpi\n", s->max_x_res);
1380141cc406Sopenharmony_ci
1381141cc406Sopenharmony_ci  s->max_y_res = get_IN_max_y_res (in);
1382141cc406Sopenharmony_ci  DBG (15, "  max y res: %d dpi\n", s->max_y_res);
1383141cc406Sopenharmony_ci
1384141cc406Sopenharmony_ci  s->min_x_res = get_IN_min_x_res (in);
1385141cc406Sopenharmony_ci  DBG (15, "  min x res: %d dpi\n", s->min_x_res);
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci  s->min_y_res = get_IN_min_y_res (in);
1388141cc406Sopenharmony_ci  DBG (15, "  min y res: %d dpi\n", s->min_y_res);
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  /* some scanners list B&W resolutions. */
1391141cc406Sopenharmony_ci  s->std_res[0] = get_IN_std_res_60 (in);
1392141cc406Sopenharmony_ci  DBG (15, "  60 dpi: %d\n", s->std_res[0]);
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci  s->std_res[1] = get_IN_std_res_75 (in);
1395141cc406Sopenharmony_ci  DBG (15, "  75 dpi: %d\n", s->std_res[1]);
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_ci  s->std_res[2] = get_IN_std_res_100 (in);
1398141cc406Sopenharmony_ci  DBG (15, "  100 dpi: %d\n", s->std_res[2]);
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_ci  s->std_res[3] = get_IN_std_res_120 (in);
1401141cc406Sopenharmony_ci  DBG (15, "  120 dpi: %d\n", s->std_res[3]);
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci  s->std_res[4] = get_IN_std_res_150 (in);
1404141cc406Sopenharmony_ci  DBG (15, "  150 dpi: %d\n", s->std_res[4]);
1405141cc406Sopenharmony_ci
1406141cc406Sopenharmony_ci  s->std_res[5] = get_IN_std_res_160 (in);
1407141cc406Sopenharmony_ci  DBG (15, "  160 dpi: %d\n", s->std_res[5]);
1408141cc406Sopenharmony_ci
1409141cc406Sopenharmony_ci  s->std_res[6] = get_IN_std_res_180 (in);
1410141cc406Sopenharmony_ci  DBG (15, "  180 dpi: %d\n", s->std_res[6]);
1411141cc406Sopenharmony_ci
1412141cc406Sopenharmony_ci  s->std_res[7] = get_IN_std_res_200 (in);
1413141cc406Sopenharmony_ci  DBG (15, "  200 dpi: %d\n", s->std_res[7]);
1414141cc406Sopenharmony_ci
1415141cc406Sopenharmony_ci  s->std_res[8] = get_IN_std_res_240 (in);
1416141cc406Sopenharmony_ci  DBG (15, "  240 dpi: %d\n", s->std_res[8]);
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci  s->std_res[9] = get_IN_std_res_300 (in);
1419141cc406Sopenharmony_ci  DBG (15, "  300 dpi: %d\n", s->std_res[9]);
1420141cc406Sopenharmony_ci
1421141cc406Sopenharmony_ci  s->std_res[10] = get_IN_std_res_320 (in);
1422141cc406Sopenharmony_ci  DBG (15, "  320 dpi: %d\n", s->std_res[10]);
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci  s->std_res[11] = get_IN_std_res_400 (in);
1425141cc406Sopenharmony_ci  DBG (15, "  400 dpi: %d\n", s->std_res[11]);
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci  s->std_res[12] = get_IN_std_res_480 (in);
1428141cc406Sopenharmony_ci  DBG (15, "  480 dpi: %d\n", s->std_res[12]);
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ci  s->std_res[13] = get_IN_std_res_600 (in);
1431141cc406Sopenharmony_ci  DBG (15, "  600 dpi: %d\n", s->std_res[13]);
1432141cc406Sopenharmony_ci
1433141cc406Sopenharmony_ci  s->std_res[14] = get_IN_std_res_800 (in);
1434141cc406Sopenharmony_ci  DBG (15, "  800 dpi: %d\n", s->std_res[14]);
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci  s->std_res[15] = get_IN_std_res_1200 (in);
1437141cc406Sopenharmony_ci  DBG (15, "  1200 dpi: %d\n", s->std_res[15]);
1438141cc406Sopenharmony_ci
1439141cc406Sopenharmony_ci  /* maximum window width and length are reported in basic units.*/
1440141cc406Sopenharmony_ci  s->max_x_basic = get_IN_window_width(in);
1441141cc406Sopenharmony_ci  DBG(15, "  max width: %2.2f inches\n",(float)s->max_x_basic/s->basic_x_res);
1442141cc406Sopenharmony_ci
1443141cc406Sopenharmony_ci  s->max_y_basic = get_IN_window_length(in);
1444141cc406Sopenharmony_ci  DBG(15, "  max length: %2.2f inches\n",(float)s->max_y_basic/s->basic_y_res);
1445141cc406Sopenharmony_ci
1446141cc406Sopenharmony_ci  /* known modes */
1447141cc406Sopenharmony_ci  s->can_overflow = get_IN_overflow(in);
1448141cc406Sopenharmony_ci  DBG (15, "  overflow: %d\n", s->can_overflow);
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci  s->can_mode[MODE_LINEART] = get_IN_monochrome (in);
1451141cc406Sopenharmony_ci  DBG (15, "  monochrome: %d\n", s->can_mode[MODE_LINEART]);
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci  s->can_mode[MODE_HALFTONE] = get_IN_half_tone (in);
1454141cc406Sopenharmony_ci  DBG (15, "  halftone: %d\n", s->can_mode[MODE_HALFTONE]);
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci  s->can_mode[MODE_GRAYSCALE] = get_IN_multilevel (in);
1457141cc406Sopenharmony_ci  DBG (15, "  grayscale: %d\n", s->can_mode[MODE_GRAYSCALE]);
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci  DBG (15, "  color_monochrome: %d\n", get_IN_monochrome_rgb(in));
1460141cc406Sopenharmony_ci  DBG (15, "  color_halftone: %d\n", get_IN_half_tone_rgb(in));
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci  s->can_mode[MODE_COLOR] = get_IN_multilevel_rgb (in);
1463141cc406Sopenharmony_ci  DBG (15, "  color_grayscale: %d\n", s->can_mode[MODE_COLOR]);
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  /* now we look at vendor specific data in bytes 0x1e onward */
1466141cc406Sopenharmony_ci  DBG (15, "vendor options\n");
1467141cc406Sopenharmony_ci
1468141cc406Sopenharmony_ci  s->has_adf = get_IN_adf(in);
1469141cc406Sopenharmony_ci  DBG (15, "  adf: %d\n", s->has_adf);
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_ci  s->has_flatbed = get_IN_flatbed(in);
1472141cc406Sopenharmony_ci  DBG (15, "  flatbed: %d\n", s->has_flatbed);
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci  s->has_transparency = get_IN_transparency(in);
1475141cc406Sopenharmony_ci  DBG (15, "  transparency: %d\n", s->has_transparency);
1476141cc406Sopenharmony_ci
1477141cc406Sopenharmony_ci  s->has_duplex = get_IN_duplex(in);
1478141cc406Sopenharmony_ci  s->has_back = s->has_duplex;
1479141cc406Sopenharmony_ci  DBG (15, "  duplex: %d\n", s->has_duplex);
1480141cc406Sopenharmony_ci
1481141cc406Sopenharmony_ci  s->has_endorser_b = get_IN_endorser_b(in);
1482141cc406Sopenharmony_ci  DBG (15, "  back endorser: %d\n", s->has_endorser_b);
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci  s->has_barcode = get_IN_barcode(in);
1485141cc406Sopenharmony_ci  DBG (15, "  barcode: %d\n", s->has_barcode);
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  s->has_operator_panel = get_IN_operator_panel(in);
1488141cc406Sopenharmony_ci  DBG (15, "  operator panel: %d\n", s->has_operator_panel);
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci  s->has_endorser_f = get_IN_endorser_f(in);
1491141cc406Sopenharmony_ci  DBG (15, "  front endorser: %d\n", s->has_endorser_f);
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci  DBG (15, "  multi-purpose stacker: %d\n", get_IN_mp_stacker(in));
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  DBG (15, "  prepick: %d\n", get_IN_prepick(in));
1496141cc406Sopenharmony_ci  DBG (15, "  mf detect: %d\n", get_IN_mf_detect(in));
1497141cc406Sopenharmony_ci
1498141cc406Sopenharmony_ci  s->has_paper_protect = get_IN_paperprot(in);
1499141cc406Sopenharmony_ci  DBG (15, "  paper protection: %d\n", s->has_paper_protect);
1500141cc406Sopenharmony_ci
1501141cc406Sopenharmony_ci  s->adbits = get_IN_adbits(in);
1502141cc406Sopenharmony_ci  DBG (15, "  A/D bits: %d\n",s->adbits);
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  s->buffer_bytes = get_IN_buffer_bytes(in);
1505141cc406Sopenharmony_ci  DBG (15, "  buffer bytes: %d\n",s->buffer_bytes);
1506141cc406Sopenharmony_ci
1507141cc406Sopenharmony_ci  DBG (15, "Standard commands\n");
1508141cc406Sopenharmony_ci
1509141cc406Sopenharmony_ci  /* std scsi command support byte 26*/
1510141cc406Sopenharmony_ci  s->has_cmd_msen10 = get_IN_has_cmd_msen10(in);
1511141cc406Sopenharmony_ci  DBG (15, "  mode_sense_10 cmd: %d\n", s->has_cmd_msen10);
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci  s->has_cmd_msel10 = get_IN_has_cmd_msel10(in);
1514141cc406Sopenharmony_ci  DBG (15, "  mode_select_10 cmd: %d\n", s->has_cmd_msel10);
1515141cc406Sopenharmony_ci
1516141cc406Sopenharmony_ci  /* std scsi command support byte 27*/
1517141cc406Sopenharmony_ci  s->has_cmd_lsen = get_IN_has_cmd_lsen(in);
1518141cc406Sopenharmony_ci  DBG (15, "  log_sense cmd: %d\n", s->has_cmd_lsen);
1519141cc406Sopenharmony_ci
1520141cc406Sopenharmony_ci  s->has_cmd_lsel = get_IN_has_cmd_lsel(in);
1521141cc406Sopenharmony_ci  DBG (15, "  log_select cmd: %d\n", s->has_cmd_lsel);
1522141cc406Sopenharmony_ci
1523141cc406Sopenharmony_ci  s->has_cmd_change = get_IN_has_cmd_change(in);
1524141cc406Sopenharmony_ci  DBG (15, "  change cmd: %d\n", s->has_cmd_change);
1525141cc406Sopenharmony_ci
1526141cc406Sopenharmony_ci  s->has_cmd_rbuff = get_IN_has_cmd_rbuff(in);
1527141cc406Sopenharmony_ci  DBG (15, "  read_buffer cmd: %d\n", s->has_cmd_rbuff);
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci  s->has_cmd_wbuff = get_IN_has_cmd_wbuff(in);
1530141cc406Sopenharmony_ci  DBG (15, "  write_buffer cmd: %d\n", s->has_cmd_wbuff);
1531141cc406Sopenharmony_ci
1532141cc406Sopenharmony_ci  s->has_cmd_cav = get_IN_has_cmd_cav(in);
1533141cc406Sopenharmony_ci  DBG (15, "  copy_and_verify cmd: %d\n", s->has_cmd_cav);
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci  s->has_cmd_comp = get_IN_has_cmd_comp(in);
1536141cc406Sopenharmony_ci  DBG (15, "  compare cmd: %d\n", s->has_cmd_comp);
1537141cc406Sopenharmony_ci
1538141cc406Sopenharmony_ci  s->has_cmd_gdbs = get_IN_has_cmd_gdbs(in);
1539141cc406Sopenharmony_ci  DBG (15, "  get_d_b_status cmd: %d\n", s->has_cmd_gdbs);
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci  /* std scsi command support byte 28*/
1542141cc406Sopenharmony_ci  s->has_cmd_op = get_IN_has_cmd_op(in);
1543141cc406Sopenharmony_ci  DBG (15, "  object_pos cmd: %d\n", s->has_cmd_op);
1544141cc406Sopenharmony_ci
1545141cc406Sopenharmony_ci  s->has_cmd_send = get_IN_has_cmd_send(in);
1546141cc406Sopenharmony_ci  DBG (15, "  send cmd: %d\n", s->has_cmd_send);
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci  s->has_cmd_read = get_IN_has_cmd_read(in);
1549141cc406Sopenharmony_ci  DBG (15, "  read cmd: %d\n", s->has_cmd_read);
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci  s->has_cmd_gwin = get_IN_has_cmd_gwin(in);
1552141cc406Sopenharmony_ci  DBG (15, "  get_window cmd: %d\n", s->has_cmd_gwin);
1553141cc406Sopenharmony_ci
1554141cc406Sopenharmony_ci  s->has_cmd_swin = get_IN_has_cmd_swin(in);
1555141cc406Sopenharmony_ci  DBG (15, "  set_window cmd: %d\n", s->has_cmd_swin);
1556141cc406Sopenharmony_ci
1557141cc406Sopenharmony_ci  s->has_cmd_sdiag = get_IN_has_cmd_sdiag(in);
1558141cc406Sopenharmony_ci  DBG (15, "  send_diag cmd: %d\n", s->has_cmd_sdiag);
1559141cc406Sopenharmony_ci
1560141cc406Sopenharmony_ci  s->has_cmd_rdiag = get_IN_has_cmd_rdiag(in);
1561141cc406Sopenharmony_ci  DBG (15, "  read_diag cmd: %d\n", s->has_cmd_rdiag);
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci  s->has_cmd_scan = get_IN_has_cmd_scan(in);
1564141cc406Sopenharmony_ci  DBG (15, "  scan cmd: %d\n", s->has_cmd_scan);
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci  /* std scsi command support byte 29*/
1567141cc406Sopenharmony_ci  s->has_cmd_msen6 = get_IN_has_cmd_msen6(in);
1568141cc406Sopenharmony_ci  DBG (15, "  mode_sense_6 cmd: %d\n", s->has_cmd_msen6);
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci  s->has_cmd_copy = get_IN_has_cmd_copy(in);
1571141cc406Sopenharmony_ci  DBG (15, "  copy cmd: %d\n", s->has_cmd_copy);
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_ci  s->has_cmd_rel = get_IN_has_cmd_rel(in);
1574141cc406Sopenharmony_ci  DBG (15, "  release cmd: %d\n", s->has_cmd_rel);
1575141cc406Sopenharmony_ci
1576141cc406Sopenharmony_ci  s->has_cmd_runit = get_IN_has_cmd_runit(in);
1577141cc406Sopenharmony_ci  DBG (15, "  reserve_unit cmd: %d\n", s->has_cmd_runit);
1578141cc406Sopenharmony_ci
1579141cc406Sopenharmony_ci  s->has_cmd_msel6 = get_IN_has_cmd_msel6(in);
1580141cc406Sopenharmony_ci  DBG (15, "  mode_select_6 cmd: %d\n", s->has_cmd_msel6);
1581141cc406Sopenharmony_ci
1582141cc406Sopenharmony_ci  s->has_cmd_inq = get_IN_has_cmd_inq(in);
1583141cc406Sopenharmony_ci  DBG (15, "  inquiry cmd: %d\n", s->has_cmd_inq);
1584141cc406Sopenharmony_ci
1585141cc406Sopenharmony_ci  s->has_cmd_rs = get_IN_has_cmd_rs(in);
1586141cc406Sopenharmony_ci  DBG (15, "  request_sense cmd: %d\n", s->has_cmd_rs);
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci  s->has_cmd_tur = get_IN_has_cmd_tur(in);
1589141cc406Sopenharmony_ci  DBG (15, "  test_unit_ready cmd: %d\n", s->has_cmd_tur);
1590141cc406Sopenharmony_ci
1591141cc406Sopenharmony_ci  /* vendor added scsi command support */
1592141cc406Sopenharmony_ci  /* FIXME: there are more of these... */
1593141cc406Sopenharmony_ci  DBG (15, "Vendor commands\n");
1594141cc406Sopenharmony_ci
1595141cc406Sopenharmony_ci  s->has_cmd_subwindow = get_IN_has_cmd_subwindow(in);
1596141cc406Sopenharmony_ci  DBG (15, "  subwindow cmd: %d\n", s->has_cmd_subwindow);
1597141cc406Sopenharmony_ci
1598141cc406Sopenharmony_ci  s->has_cmd_endorser = get_IN_has_cmd_endorser(in);
1599141cc406Sopenharmony_ci  DBG (15, "  endorser cmd: %d\n", s->has_cmd_endorser);
1600141cc406Sopenharmony_ci
1601141cc406Sopenharmony_ci  s->has_cmd_hw_status = get_IN_has_cmd_hw_status (in);
1602141cc406Sopenharmony_ci  DBG (15, "  hardware status cmd: %d\n", s->has_cmd_hw_status);
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci  s->has_cmd_hw_status_2 = get_IN_has_cmd_hw_status_2 (in);
1605141cc406Sopenharmony_ci  DBG (15, "  hardware status 2 cmd: %d\n", s->has_cmd_hw_status_2);
1606141cc406Sopenharmony_ci
1607141cc406Sopenharmony_ci  s->has_cmd_hw_status_3 = get_IN_has_cmd_hw_status_3 (in);
1608141cc406Sopenharmony_ci  DBG (15, "  hardware status 3 cmd: %d\n", s->has_cmd_hw_status_3);
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci  s->has_cmd_scanner_ctl = get_IN_has_cmd_scanner_ctl(in);
1611141cc406Sopenharmony_ci  DBG (15, "  scanner control cmd: %d\n", s->has_cmd_scanner_ctl);
1612141cc406Sopenharmony_ci
1613141cc406Sopenharmony_ci  s->has_cmd_device_restart = get_IN_has_cmd_device_restart(in);
1614141cc406Sopenharmony_ci  DBG (15, "  device restart cmd: %d\n", s->has_cmd_device_restart);
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci  /* get threshold, brightness and contrast ranges. */
1617141cc406Sopenharmony_ci  s->brightness_steps = get_IN_brightness_steps(in);
1618141cc406Sopenharmony_ci  DBG (15, "  brightness steps: %d\n", s->brightness_steps);
1619141cc406Sopenharmony_ci
1620141cc406Sopenharmony_ci  s->threshold_steps = get_IN_threshold_steps(in);
1621141cc406Sopenharmony_ci  DBG (15, "  threshold steps: %d\n", s->threshold_steps);
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci  s->contrast_steps = get_IN_contrast_steps(in);
1624141cc406Sopenharmony_ci  DBG (15, "  contrast steps: %d\n", s->contrast_steps);
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci  /* dither/gamma patterns */
1627141cc406Sopenharmony_ci  s->num_internal_gamma = get_IN_num_gamma_internal (in);
1628141cc406Sopenharmony_ci  DBG (15, "  built in gamma patterns: %d\n", s->num_internal_gamma);
1629141cc406Sopenharmony_ci
1630141cc406Sopenharmony_ci  s->num_download_gamma = get_IN_num_gamma_download (in);
1631141cc406Sopenharmony_ci  DBG (15, "  download gamma patterns: %d\n", s->num_download_gamma);
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci  s->num_internal_dither = get_IN_num_dither_internal (in);
1634141cc406Sopenharmony_ci  DBG (15, "  built in dither patterns: %d\n", s->num_internal_dither);
1635141cc406Sopenharmony_ci
1636141cc406Sopenharmony_ci  s->num_download_dither = get_IN_num_dither_download (in);
1637141cc406Sopenharmony_ci  DBG (15, "  download dither patterns: %d\n", s->num_download_dither);
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_ci  /* ipc functions */
1640141cc406Sopenharmony_ci  s->has_rif = get_IN_ipc_bw_rif (in);
1641141cc406Sopenharmony_ci  DBG (15, "  RIF: %d\n", s->has_rif);
1642141cc406Sopenharmony_ci
1643141cc406Sopenharmony_ci  s->has_dtc = get_IN_ipc_dtc(in);
1644141cc406Sopenharmony_ci  DBG (15, "  DTC (AutoI): %d\n", s->has_dtc);
1645141cc406Sopenharmony_ci
1646141cc406Sopenharmony_ci  s->has_sdtc = get_IN_ipc_sdtc(in);
1647141cc406Sopenharmony_ci  DBG (15, "  SDTC (AutoII): %d\n", s->has_sdtc);
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci  s->has_outline = get_IN_ipc_outline_extraction (in);
1650141cc406Sopenharmony_ci  DBG (15, "  outline extraction: %d\n", s->has_outline);
1651141cc406Sopenharmony_ci
1652141cc406Sopenharmony_ci  s->has_emphasis = get_IN_ipc_image_emphasis (in);
1653141cc406Sopenharmony_ci  DBG (15, "  image emphasis: %d\n", s->has_emphasis);
1654141cc406Sopenharmony_ci
1655141cc406Sopenharmony_ci  s->has_autosep = get_IN_ipc_auto_separation (in);
1656141cc406Sopenharmony_ci  DBG (15, "  automatic separation: %d\n", s->has_autosep);
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci  s->has_mirroring = get_IN_ipc_mirroring (in);
1659141cc406Sopenharmony_ci  DBG (15, "  mirror image: %d\n", s->has_mirroring);
1660141cc406Sopenharmony_ci
1661141cc406Sopenharmony_ci  s->has_wl_follow = get_IN_ipc_wl_follow (in);
1662141cc406Sopenharmony_ci  DBG (15, "  white level follower: %d\n", s->has_wl_follow);
1663141cc406Sopenharmony_ci
1664141cc406Sopenharmony_ci  /* byte 58 */
1665141cc406Sopenharmony_ci  s->has_subwindow = get_IN_ipc_subwindow (in);
1666141cc406Sopenharmony_ci  DBG (15, "  subwindow: %d\n", s->has_subwindow);
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci  s->has_diffusion = get_IN_ipc_diffusion (in);
1669141cc406Sopenharmony_ci  DBG (15, "  diffusion: %d\n", s->has_diffusion);
1670141cc406Sopenharmony_ci
1671141cc406Sopenharmony_ci  s->has_ipc3 = get_IN_ipc_ipc3 (in);
1672141cc406Sopenharmony_ci  DBG (15, "  ipc3: %d\n", s->has_ipc3);
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci  s->has_rotation = get_IN_ipc_rotation (in);
1675141cc406Sopenharmony_ci  DBG (15, "  rotation: %d\n", s->has_rotation);
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci  s->has_hybrid_crop_deskew = get_IN_ipc_hybrid_crop_deskew(in);
1678141cc406Sopenharmony_ci  DBG (15, "  hybrid crop deskew: %d\n", s->has_hybrid_crop_deskew);
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_ci  /* this one is weird, overrides the payload length from scanner */
1681141cc406Sopenharmony_ci  DBG (15, "  vpd extends to byte 6f: %d\n", get_IN_vpd_thru_byte_6f(in));
1682141cc406Sopenharmony_ci  if(get_IN_vpd_thru_byte_6f(in) && payload_off < 0x6f){
1683141cc406Sopenharmony_ci    payload_off = 0x6f;
1684141cc406Sopenharmony_ci  }
1685141cc406Sopenharmony_ci
1686141cc406Sopenharmony_ci  /* compression modes */
1687141cc406Sopenharmony_ci  s->has_comp_MH = get_IN_compression_MH (in);
1688141cc406Sopenharmony_ci  DBG (15, "  compression MH: %d\n", s->has_comp_MH);
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci  s->has_comp_MR = get_IN_compression_MR (in);
1691141cc406Sopenharmony_ci  DBG (15, "  compression MR: %d\n", s->has_comp_MR);
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci  s->has_comp_MMR = get_IN_compression_MMR (in);
1694141cc406Sopenharmony_ci  DBG (15, "  compression MMR: %d\n", s->has_comp_MMR);
1695141cc406Sopenharmony_ci
1696141cc406Sopenharmony_ci  s->has_comp_JBIG = get_IN_compression_JBIG (in);
1697141cc406Sopenharmony_ci  DBG (15, "  compression JBIG: %d\n", s->has_comp_JBIG);
1698141cc406Sopenharmony_ci
1699141cc406Sopenharmony_ci  s->has_comp_JPG1 = get_IN_compression_JPG_BASE (in);
1700141cc406Sopenharmony_ci  DBG (15, "  compression JPG1: %d\n", s->has_comp_JPG1);
1701141cc406Sopenharmony_ci#ifdef SANE_JPEG_DISABLED
1702141cc406Sopenharmony_ci  DBG (15, "  (Disabled)\n");
1703141cc406Sopenharmony_ci#endif
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci  s->has_comp_JPG2 = get_IN_compression_JPG_EXT (in);
1706141cc406Sopenharmony_ci  DBG (15, "  compression JPG2: %d\n", s->has_comp_JPG2);
1707141cc406Sopenharmony_ci
1708141cc406Sopenharmony_ci  s->has_comp_JPG3 = get_IN_compression_JPG_INDEP (in);
1709141cc406Sopenharmony_ci  DBG (15, "  compression JPG3: %d\n", s->has_comp_JPG3);
1710141cc406Sopenharmony_ci
1711141cc406Sopenharmony_ci  /* FIXME: we don't store these? */
1712141cc406Sopenharmony_ci  DBG (15, "  back endorser mech: %d\n", get_IN_endorser_b_mech(in));
1713141cc406Sopenharmony_ci  DBG (15, "  back endorser stamp: %d\n", get_IN_endorser_b_stamp(in));
1714141cc406Sopenharmony_ci  DBG (15, "  back endorser elec: %d\n", get_IN_endorser_b_elec(in));
1715141cc406Sopenharmony_ci  DBG (15, "  endorser max id: %d\n", get_IN_endorser_max_id(in));
1716141cc406Sopenharmony_ci
1717141cc406Sopenharmony_ci  DBG (15, "  front endorser mech: %d\n", get_IN_endorser_f_mech(in));
1718141cc406Sopenharmony_ci  DBG (15, "  front endorser stamp: %d\n", get_IN_endorser_f_stamp(in));
1719141cc406Sopenharmony_ci  DBG (15, "  front endorser elec: %d\n", get_IN_endorser_f_elec(in));
1720141cc406Sopenharmony_ci
1721141cc406Sopenharmony_ci  s->endorser_type_b = get_IN_endorser_b_type(in);
1722141cc406Sopenharmony_ci  DBG (15, "  back endorser type: %d\n", s->endorser_type_b);
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_ci  s->endorser_type_f = get_IN_endorser_f_type(in);
1725141cc406Sopenharmony_ci  DBG (15, "  back endorser type: %d\n", s->endorser_type_f);
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci  DBG (15, "  connection type: %d\n", get_IN_connection(in));
1728141cc406Sopenharmony_ci
1729141cc406Sopenharmony_ci  DBG (15, "  endorser ext: %d\n", get_IN_endorser_type_ext(in));
1730141cc406Sopenharmony_ci  DBG (15, "  endorser pr_b: %d\n", get_IN_endorser_pre_back(in));
1731141cc406Sopenharmony_ci  DBG (15, "  endorser pr_f: %d\n", get_IN_endorser_pre_front(in));
1732141cc406Sopenharmony_ci  DBG (15, "  endorser po_b: %d\n", get_IN_endorser_post_back(in));
1733141cc406Sopenharmony_ci  DBG (15, "  endorser po_f: %d\n", get_IN_endorser_post_front(in));
1734141cc406Sopenharmony_ci
1735141cc406Sopenharmony_ci  s->os_x_basic = get_IN_x_overscan_size(in);
1736141cc406Sopenharmony_ci  DBG (15, "  horizontal overscan: %d\n", s->os_x_basic);
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci  s->os_y_basic = get_IN_y_overscan_size(in);
1739141cc406Sopenharmony_ci  DBG (15, "  vertical overscan: %d\n", s->os_y_basic);
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci  /* not all scanners go this far */
1742141cc406Sopenharmony_ci  if (payload_off >= 0x68) {
1743141cc406Sopenharmony_ci    DBG (15, "  default bg adf b: %d\n", get_IN_default_bg_adf_b(in));
1744141cc406Sopenharmony_ci    DBG (15, "  default bg adf f: %d\n", get_IN_default_bg_adf_f(in));
1745141cc406Sopenharmony_ci    DBG (15, "  default bg fb: %d\n", get_IN_default_bg_fb(in));
1746141cc406Sopenharmony_ci  }
1747141cc406Sopenharmony_ci
1748141cc406Sopenharmony_ci  if (payload_off >= 0x69) {
1749141cc406Sopenharmony_ci    DBG (15, "  auto color: %d\n", get_IN_auto_color(in));
1750141cc406Sopenharmony_ci    DBG (15, "  blank skip: %d\n", get_IN_blank_skip(in));
1751141cc406Sopenharmony_ci    DBG (15, "  multi image: %d\n", get_IN_multi_image(in));
1752141cc406Sopenharmony_ci    DBG (15, "  f b type indep: %d\n", get_IN_f_b_type_indep(in));
1753141cc406Sopenharmony_ci    DBG (15, "  f b res indep: %d\n", get_IN_f_b_res_indep(in));
1754141cc406Sopenharmony_ci  }
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci  if (payload_off >= 0x6a) {
1757141cc406Sopenharmony_ci    DBG (15, "  dropout spec: %d\n", get_IN_dropout_spec(in));
1758141cc406Sopenharmony_ci    DBG (15, "  dropout non: %d\n", get_IN_dropout_non(in));
1759141cc406Sopenharmony_ci    DBG (15, "  dropout white: %d\n", get_IN_dropout_white(in));
1760141cc406Sopenharmony_ci  }
1761141cc406Sopenharmony_ci
1762141cc406Sopenharmony_ci  if (payload_off >= 0x6d) {
1763141cc406Sopenharmony_ci    DBG (15, "  skew check: %d\n", get_IN_skew_check(in));
1764141cc406Sopenharmony_ci    DBG (15, "  new feed roller: %d\n", get_IN_new_fd_roll(in));
1765141cc406Sopenharmony_ci    s->has_adv_paper_prot = get_IN_paper_prot_2(in);
1766141cc406Sopenharmony_ci    DBG (15, "  paper protection: %d\n", s->has_adv_paper_prot);
1767141cc406Sopenharmony_ci  }
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci  /* this one is weird, overrides the payload length from scanner,
1770141cc406Sopenharmony_ci   * but the enlarged area is just null bytes, so we ignore this */
1771141cc406Sopenharmony_ci  if (payload_off >= 0x6f) {
1772141cc406Sopenharmony_ci    DBG (15, "  extra evpd length: %d\n", get_IN_evpd_len(in));
1773141cc406Sopenharmony_ci  }
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci  if (payload_off >= 0x70) {
1776141cc406Sopenharmony_ci    DBG (15, "  paper count: %d\n", get_IN_paper_count(in));
1777141cc406Sopenharmony_ci    DBG (15, "  paper number: %d\n", get_IN_paper_number(in));
1778141cc406Sopenharmony_ci    DBG (15, "  ext send to: %d\n", get_IN_ext_send_to(in));
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci    s->has_staple_detect = get_IN_staple_det(in);
1781141cc406Sopenharmony_ci    DBG (15, "  staple det: %d\n", s->has_staple_detect);
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_ci    DBG (15, "  pause host: %d\n", get_IN_pause_host(in));
1784141cc406Sopenharmony_ci    DBG (15, "  pause panel: %d\n", get_IN_pause_panel(in));
1785141cc406Sopenharmony_ci    DBG (15, "  pause conf: %d\n", get_IN_pause_conf(in));
1786141cc406Sopenharmony_ci    DBG (15, "  hq print: %d\n", get_IN_hq_print(in));
1787141cc406Sopenharmony_ci  }
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci  if (payload_off >= 0x71) {
1790141cc406Sopenharmony_ci    DBG (15, "  ext GHS len: %d\n", get_IN_ext_GHS_len(in));
1791141cc406Sopenharmony_ci  }
1792141cc406Sopenharmony_ci
1793141cc406Sopenharmony_ci  if (payload_off >= 0x72) {
1794141cc406Sopenharmony_ci    DBG (15, "  smbc func: %d\n", get_IN_smbc_func(in));
1795141cc406Sopenharmony_ci    DBG (15, "  imprint chk b: %d\n", get_IN_imprint_chk_b(in));
1796141cc406Sopenharmony_ci    DBG (15, "  imprint chk f: %d\n", get_IN_imprint_chk_f(in));
1797141cc406Sopenharmony_ci    DBG (15, "  force w bg: %d\n", get_IN_force_w_bg(in));
1798141cc406Sopenharmony_ci
1799141cc406Sopenharmony_ci    s->has_df_recovery = get_IN_mf_recover_lvl(in);
1800141cc406Sopenharmony_ci    DBG (15, "  mf recover lvl: %d\n", s->has_df_recovery);
1801141cc406Sopenharmony_ci  }
1802141cc406Sopenharmony_ci
1803141cc406Sopenharmony_ci  if (payload_off >= 0x73) {
1804141cc406Sopenharmony_ci    DBG (15, "  first read time: %d\n", get_IN_first_read_time(in));
1805141cc406Sopenharmony_ci    DBG (15, "  div scanning: %d\n", get_IN_div_scanning(in));
1806141cc406Sopenharmony_ci    DBG (15, "  start job: %d\n", get_IN_start_job(in));
1807141cc406Sopenharmony_ci    DBG (15, "  lifetime log: %d\n", get_IN_lifetime_log(in));
1808141cc406Sopenharmony_ci    DBG (15, "  imff save rest: %d\n", get_IN_imff_save_rest(in));
1809141cc406Sopenharmony_ci    DBG (15, "  wide scsi type: %d\n", get_IN_wide_scsi_type(in));
1810141cc406Sopenharmony_ci  }
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci  if (payload_off >= 0x74) {
1813141cc406Sopenharmony_ci    DBG (15, "  lut hybrid crop: %d\n", get_IN_lut_hybrid_crop(in));
1814141cc406Sopenharmony_ci    DBG (15, "  over under amt: %d\n", get_IN_over_under_amt(in));
1815141cc406Sopenharmony_ci    DBG (15, "  rgb lut: %d\n", get_IN_rgb_lut(in));
1816141cc406Sopenharmony_ci    DBG (15, "  num lut dl: %d\n", get_IN_num_lut_dl(in));
1817141cc406Sopenharmony_ci  }
1818141cc406Sopenharmony_ci
1819141cc406Sopenharmony_ci  /* Various items below are poorly documented or missing */
1820141cc406Sopenharmony_ci
1821141cc406Sopenharmony_ci  if (payload_off >= 0x76) {
1822141cc406Sopenharmony_ci    s->has_off_mode = get_IN_erp_lot6_supp(in);
1823141cc406Sopenharmony_ci    DBG (15, "  ErP Lot6 (power off timer): %d\n", s->has_off_mode);
1824141cc406Sopenharmony_ci    DBG (15, "  sync next feed: %d\n", get_IN_sync_next_feed(in));
1825141cc406Sopenharmony_ci  }
1826141cc406Sopenharmony_ci
1827141cc406Sopenharmony_ci  if (payload_off >= 0x79) {
1828141cc406Sopenharmony_ci    DBG (15, "  battery: %d\n", get_IN_battery(in));
1829141cc406Sopenharmony_ci    DBG (15, "  battery save: %d\n", get_IN_battery_save(in));
1830141cc406Sopenharmony_ci    DBG (15, "  object position reverse: %d\n", get_IN_op_reverse(in));
1831141cc406Sopenharmony_ci  }
1832141cc406Sopenharmony_ci
1833141cc406Sopenharmony_ci  if (payload_off >= 0x7a) {
1834141cc406Sopenharmony_ci    s->has_op_halt = get_IN_op_halt(in);
1835141cc406Sopenharmony_ci    DBG (15, "  object position halt: %d\n", s->has_op_halt);
1836141cc406Sopenharmony_ci  }
1837141cc406Sopenharmony_ci
1838141cc406Sopenharmony_ci  if (payload_off >= 0x7c) {
1839141cc406Sopenharmony_ci    s->has_return_path = get_IN_return_path(in);
1840141cc406Sopenharmony_ci    DBG (15, "  return path (card) scanning: %d\n", s->has_return_path);
1841141cc406Sopenharmony_ci    DBG (15, "  energy star 3: %d\n", get_IN_energy_star3(in));
1842141cc406Sopenharmony_ci  }
1843141cc406Sopenharmony_ci
1844141cc406Sopenharmony_ci  DBG (10, "init_vpd: finish\n");
1845141cc406Sopenharmony_ci
1846141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1847141cc406Sopenharmony_ci}
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_cistatic SANE_Status
1850141cc406Sopenharmony_ciinit_ms(struct fujitsu *s)
1851141cc406Sopenharmony_ci{
1852141cc406Sopenharmony_ci  int ret;
1853141cc406Sopenharmony_ci  int oldDbg=0;
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci  unsigned char cmd[MODE_SENSE_len];
1856141cc406Sopenharmony_ci  size_t cmdLen = MODE_SENSE_len;
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci  unsigned char in[MODE_SENSE_data_len];
1859141cc406Sopenharmony_ci  size_t inLen = MODE_SENSE_data_len;
1860141cc406Sopenharmony_ci
1861141cc406Sopenharmony_ci  DBG (10, "init_ms: start\n");
1862141cc406Sopenharmony_ci
1863141cc406Sopenharmony_ci  if(!s->has_cmd_msen6){
1864141cc406Sopenharmony_ci    DBG (10, "init_ms: unsupported\n");
1865141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1866141cc406Sopenharmony_ci  }
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci  /* some of the following probes will produce errors */
1869141cc406Sopenharmony_ci  /* so we reduce the dbg level to reduce the noise */
1870141cc406Sopenharmony_ci  /* however, if user builds with NDEBUG, we can't do that */
1871141cc406Sopenharmony_ci  /* so we protect the code with the following macro */
1872141cc406Sopenharmony_ci  IF_DBG( oldDbg=DBG_LEVEL; )
1873141cc406Sopenharmony_ci  IF_DBG( if(DBG_LEVEL < 35){ DBG_LEVEL = 0; } )
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
1876141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SENSE_code);
1877141cc406Sopenharmony_ci  set_MSEN_xfer_length (cmd, inLen);
1878141cc406Sopenharmony_ci
1879141cc406Sopenharmony_ci  if(s->has_MS_autocolor){
1880141cc406Sopenharmony_ci    DBG (35, "init_ms: autocolor\n");
1881141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_autocolor);
1882141cc406Sopenharmony_ci    ret = do_cmd (
1883141cc406Sopenharmony_ci      s, 1, 0,
1884141cc406Sopenharmony_ci      cmd, cmdLen,
1885141cc406Sopenharmony_ci      NULL, 0,
1886141cc406Sopenharmony_ci      in, &inLen
1887141cc406Sopenharmony_ci    );
1888141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1889141cc406Sopenharmony_ci      s->has_MS_autocolor=0;
1890141cc406Sopenharmony_ci    }
1891141cc406Sopenharmony_ci  }
1892141cc406Sopenharmony_ci
1893141cc406Sopenharmony_ci  if(s->has_MS_prepick){
1894141cc406Sopenharmony_ci    DBG (35, "init_ms: prepick\n");
1895141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_prepick);
1896141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1897141cc406Sopenharmony_ci    ret = do_cmd (
1898141cc406Sopenharmony_ci      s, 1, 0,
1899141cc406Sopenharmony_ci      cmd, cmdLen,
1900141cc406Sopenharmony_ci      NULL, 0,
1901141cc406Sopenharmony_ci      in, &inLen
1902141cc406Sopenharmony_ci    );
1903141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1904141cc406Sopenharmony_ci      s->has_MS_prepick=0;
1905141cc406Sopenharmony_ci    }
1906141cc406Sopenharmony_ci  }
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_ci  if(s->has_MS_sleep){
1909141cc406Sopenharmony_ci    DBG (35, "init_ms: sleep\n");
1910141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_sleep);
1911141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1912141cc406Sopenharmony_ci    ret = do_cmd (
1913141cc406Sopenharmony_ci      s, 1, 0,
1914141cc406Sopenharmony_ci      cmd, cmdLen,
1915141cc406Sopenharmony_ci      NULL, 0,
1916141cc406Sopenharmony_ci      in, &inLen
1917141cc406Sopenharmony_ci    );
1918141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1919141cc406Sopenharmony_ci      s->has_MS_sleep=0;
1920141cc406Sopenharmony_ci    }
1921141cc406Sopenharmony_ci  }
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_ci  if(s->has_MS_duplex){
1924141cc406Sopenharmony_ci    DBG (35, "init_ms: duplex\n");
1925141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_duplex);
1926141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1927141cc406Sopenharmony_ci    ret = do_cmd (
1928141cc406Sopenharmony_ci      s, 1, 0,
1929141cc406Sopenharmony_ci      cmd, cmdLen,
1930141cc406Sopenharmony_ci      NULL, 0,
1931141cc406Sopenharmony_ci      in, &inLen
1932141cc406Sopenharmony_ci    );
1933141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1934141cc406Sopenharmony_ci      s->has_MS_duplex=0;
1935141cc406Sopenharmony_ci    }
1936141cc406Sopenharmony_ci  }
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_ci  if(s->has_MS_rand){
1939141cc406Sopenharmony_ci    DBG (35, "init_ms: rand\n");
1940141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_rand);
1941141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1942141cc406Sopenharmony_ci    ret = do_cmd (
1943141cc406Sopenharmony_ci      s, 1, 0,
1944141cc406Sopenharmony_ci      cmd, cmdLen,
1945141cc406Sopenharmony_ci      NULL, 0,
1946141cc406Sopenharmony_ci      in, &inLen
1947141cc406Sopenharmony_ci    );
1948141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1949141cc406Sopenharmony_ci      s->has_MS_rand=0;
1950141cc406Sopenharmony_ci    }
1951141cc406Sopenharmony_ci  }
1952141cc406Sopenharmony_ci
1953141cc406Sopenharmony_ci  if(s->has_MS_bg){
1954141cc406Sopenharmony_ci    DBG (35, "init_ms: bg\n");
1955141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_bg);
1956141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1957141cc406Sopenharmony_ci    ret = do_cmd (
1958141cc406Sopenharmony_ci      s, 1, 0,
1959141cc406Sopenharmony_ci      cmd, cmdLen,
1960141cc406Sopenharmony_ci      NULL, 0,
1961141cc406Sopenharmony_ci      in, &inLen
1962141cc406Sopenharmony_ci    );
1963141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1964141cc406Sopenharmony_ci      s->has_MS_bg=0;
1965141cc406Sopenharmony_ci    }
1966141cc406Sopenharmony_ci  }
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ci  if(s->has_MS_df){
1969141cc406Sopenharmony_ci    DBG (35, "init_ms: df\n");
1970141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_df);
1971141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1972141cc406Sopenharmony_ci    ret = do_cmd (
1973141cc406Sopenharmony_ci      s, 1, 0,
1974141cc406Sopenharmony_ci      cmd, cmdLen,
1975141cc406Sopenharmony_ci      NULL, 0,
1976141cc406Sopenharmony_ci      in, &inLen
1977141cc406Sopenharmony_ci    );
1978141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1979141cc406Sopenharmony_ci      s->has_MS_df=0;
1980141cc406Sopenharmony_ci    }
1981141cc406Sopenharmony_ci  }
1982141cc406Sopenharmony_ci
1983141cc406Sopenharmony_ci  if(s->has_MS_dropout){
1984141cc406Sopenharmony_ci    DBG (35, "init_ms: dropout\n");
1985141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_dropout);
1986141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
1987141cc406Sopenharmony_ci    ret = do_cmd (
1988141cc406Sopenharmony_ci      s, 1, 0,
1989141cc406Sopenharmony_ci      cmd, cmdLen,
1990141cc406Sopenharmony_ci      NULL, 0,
1991141cc406Sopenharmony_ci      in, &inLen
1992141cc406Sopenharmony_ci    );
1993141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
1994141cc406Sopenharmony_ci      s->has_MS_dropout=0;
1995141cc406Sopenharmony_ci    }
1996141cc406Sopenharmony_ci  }
1997141cc406Sopenharmony_ci
1998141cc406Sopenharmony_ci  if(s->has_MS_buff){
1999141cc406Sopenharmony_ci    DBG (35, "init_ms: buffer\n");
2000141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_buff);
2001141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
2002141cc406Sopenharmony_ci    ret = do_cmd (
2003141cc406Sopenharmony_ci      s, 1, 0,
2004141cc406Sopenharmony_ci      cmd, cmdLen,
2005141cc406Sopenharmony_ci      NULL, 0,
2006141cc406Sopenharmony_ci      in, &inLen
2007141cc406Sopenharmony_ci    );
2008141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
2009141cc406Sopenharmony_ci      s->has_MS_buff=0;
2010141cc406Sopenharmony_ci    }
2011141cc406Sopenharmony_ci  }
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci  if(s->has_MS_auto){
2014141cc406Sopenharmony_ci    DBG (35, "init_ms: auto\n");
2015141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_auto);
2016141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
2017141cc406Sopenharmony_ci    ret = do_cmd (
2018141cc406Sopenharmony_ci      s, 1, 0,
2019141cc406Sopenharmony_ci      cmd, cmdLen,
2020141cc406Sopenharmony_ci      NULL, 0,
2021141cc406Sopenharmony_ci      in, &inLen
2022141cc406Sopenharmony_ci    );
2023141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
2024141cc406Sopenharmony_ci      s->has_MS_auto=0;
2025141cc406Sopenharmony_ci    }
2026141cc406Sopenharmony_ci  }
2027141cc406Sopenharmony_ci
2028141cc406Sopenharmony_ci  if(s->has_MS_lamp){
2029141cc406Sopenharmony_ci    DBG (35, "init_ms: lamp\n");
2030141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_lamp);
2031141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
2032141cc406Sopenharmony_ci    ret = do_cmd (
2033141cc406Sopenharmony_ci      s, 1, 0,
2034141cc406Sopenharmony_ci      cmd, cmdLen,
2035141cc406Sopenharmony_ci      NULL, 0,
2036141cc406Sopenharmony_ci      in, &inLen
2037141cc406Sopenharmony_ci    );
2038141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
2039141cc406Sopenharmony_ci      s->has_MS_lamp=0;
2040141cc406Sopenharmony_ci    }
2041141cc406Sopenharmony_ci  }
2042141cc406Sopenharmony_ci
2043141cc406Sopenharmony_ci  if(s->has_MS_jobsep){
2044141cc406Sopenharmony_ci    DBG (35, "init_ms: jobsep\n");
2045141cc406Sopenharmony_ci    set_MSEN_pc(cmd, MS_pc_jobsep);
2046141cc406Sopenharmony_ci    inLen = MODE_SENSE_data_len;
2047141cc406Sopenharmony_ci    ret = do_cmd (
2048141cc406Sopenharmony_ci      s, 1, 0,
2049141cc406Sopenharmony_ci      cmd, cmdLen,
2050141cc406Sopenharmony_ci      NULL, 0,
2051141cc406Sopenharmony_ci      in, &inLen
2052141cc406Sopenharmony_ci    );
2053141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
2054141cc406Sopenharmony_ci      s->has_MS_jobsep=0;
2055141cc406Sopenharmony_ci    }
2056141cc406Sopenharmony_ci  }
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci  IF_DBG (DBG_LEVEL = oldDbg;)
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci  DBG (15, "  autocolor: %d\n", s->has_MS_autocolor);
2061141cc406Sopenharmony_ci  DBG (15, "  prepick: %d\n", s->has_MS_prepick);
2062141cc406Sopenharmony_ci  DBG (15, "  sleep: %d\n", s->has_MS_sleep);
2063141cc406Sopenharmony_ci  DBG (15, "  duplex: %d\n", s->has_MS_duplex);
2064141cc406Sopenharmony_ci  DBG (15, "  rand: %d\n", s->has_MS_rand);
2065141cc406Sopenharmony_ci  DBG (15, "  bg: %d\n", s->has_MS_bg);
2066141cc406Sopenharmony_ci  DBG (15, "  df: %d\n", s->has_MS_df);
2067141cc406Sopenharmony_ci  DBG (15, "  dropout: %d\n", s->has_MS_dropout);
2068141cc406Sopenharmony_ci  DBG (15, "  buff: %d\n", s->has_MS_buff);
2069141cc406Sopenharmony_ci  DBG (15, "  auto: %d\n", s->has_MS_auto);
2070141cc406Sopenharmony_ci  DBG (15, "  lamp: %d\n", s->has_MS_lamp);
2071141cc406Sopenharmony_ci  DBG (15, "  jobsep: %d\n", s->has_MS_jobsep);
2072141cc406Sopenharmony_ci
2073141cc406Sopenharmony_ci  DBG (10, "init_ms: finish\n");
2074141cc406Sopenharmony_ci
2075141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2076141cc406Sopenharmony_ci}
2077141cc406Sopenharmony_ci
2078141cc406Sopenharmony_ci/*
2079141cc406Sopenharmony_ci * get model specific info that is not in vpd, and correct
2080141cc406Sopenharmony_ci * errors in vpd data. struct is already initialized to 0.
2081141cc406Sopenharmony_ci */
2082141cc406Sopenharmony_cistatic SANE_Status
2083141cc406Sopenharmony_ciinit_model (struct fujitsu *s)
2084141cc406Sopenharmony_ci{
2085141cc406Sopenharmony_ci  int i;
2086141cc406Sopenharmony_ci
2087141cc406Sopenharmony_ci  DBG (10, "init_model: start\n");
2088141cc406Sopenharmony_ci
2089141cc406Sopenharmony_ci  /* for most scanners these are good defaults */
2090141cc406Sopenharmony_ci  if(s->can_mode[MODE_LINEART]
2091141cc406Sopenharmony_ci    || s->can_mode[MODE_HALFTONE]
2092141cc406Sopenharmony_ci    || s->can_mode[MODE_GRAYSCALE]
2093141cc406Sopenharmony_ci  ){
2094141cc406Sopenharmony_ci    s->has_vuid_mono = 1;
2095141cc406Sopenharmony_ci  }
2096141cc406Sopenharmony_ci  if(s->can_mode[MODE_COLOR]){
2097141cc406Sopenharmony_ci    s->has_vuid_color = 1;
2098141cc406Sopenharmony_ci  }
2099141cc406Sopenharmony_ci
2100141cc406Sopenharmony_ci  for(i=MODE_HALFTONE;i<=MODE_COLOR;i++){
2101141cc406Sopenharmony_ci    s->step_x_res[i] = s->step_x_res[MODE_LINEART];
2102141cc406Sopenharmony_ci    s->step_y_res[i] = s->step_y_res[MODE_LINEART];
2103141cc406Sopenharmony_ci  }
2104141cc406Sopenharmony_ci
2105141cc406Sopenharmony_ci  s->reverse_by_mode[MODE_LINEART] = 0;
2106141cc406Sopenharmony_ci  s->reverse_by_mode[MODE_HALFTONE] = 0;
2107141cc406Sopenharmony_ci  s->reverse_by_mode[MODE_GRAYSCALE] = 1;
2108141cc406Sopenharmony_ci  s->reverse_by_mode[MODE_COLOR] = 1;
2109141cc406Sopenharmony_ci
2110141cc406Sopenharmony_ci  s->ppl_mod_by_mode[MODE_LINEART] = 8;
2111141cc406Sopenharmony_ci  s->ppl_mod_by_mode[MODE_HALFTONE] = 8;
2112141cc406Sopenharmony_ci  s->ppl_mod_by_mode[MODE_GRAYSCALE] = 1;
2113141cc406Sopenharmony_ci  s->ppl_mod_by_mode[MODE_COLOR] = 1;
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_ci  /* endorser type tells string length (among other things) */
2116141cc406Sopenharmony_ci  if(s->has_endorser_b){
2117141cc406Sopenharmony_ci    /*old-style is 40 bytes*/
2118141cc406Sopenharmony_ci    if(s->endorser_type_b == ET_OLD){
2119141cc406Sopenharmony_ci      s->endorser_string_len = 40;
2120141cc406Sopenharmony_ci    }
2121141cc406Sopenharmony_ci    /*short new style is 60 bytes*/
2122141cc406Sopenharmony_ci    else if(s->endorser_type_b == ET_30){
2123141cc406Sopenharmony_ci      s->endorser_string_len = 60;
2124141cc406Sopenharmony_ci    }
2125141cc406Sopenharmony_ci    /*long new style is 80 bytes*/
2126141cc406Sopenharmony_ci    else if(s->endorser_type_b == ET_40){
2127141cc406Sopenharmony_ci      s->endorser_string_len = 80;
2128141cc406Sopenharmony_ci    }
2129141cc406Sopenharmony_ci  }
2130141cc406Sopenharmony_ci  else if(s->has_endorser_f){
2131141cc406Sopenharmony_ci    /*old-style is 40 bytes*/
2132141cc406Sopenharmony_ci    if(s->endorser_type_f == ET_OLD){
2133141cc406Sopenharmony_ci      s->endorser_string_len = 40;
2134141cc406Sopenharmony_ci    }
2135141cc406Sopenharmony_ci    /*short new style is 60 bytes*/
2136141cc406Sopenharmony_ci    else if(s->endorser_type_f == ET_30){
2137141cc406Sopenharmony_ci      s->endorser_string_len = 60;
2138141cc406Sopenharmony_ci    }
2139141cc406Sopenharmony_ci    /*long new style is 80 bytes*/
2140141cc406Sopenharmony_ci    else if(s->endorser_type_f == ET_40){
2141141cc406Sopenharmony_ci      s->endorser_string_len = 80;
2142141cc406Sopenharmony_ci    }
2143141cc406Sopenharmony_ci  }
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci  /* convert to 1200dpi units */
2146141cc406Sopenharmony_ci  s->max_x = s->max_x_basic * 1200 / s->basic_x_res;
2147141cc406Sopenharmony_ci  s->max_y = s->max_y_basic * 1200 / s->basic_y_res;
2148141cc406Sopenharmony_ci
2149141cc406Sopenharmony_ci  /* setup the list with a single choice, in 1200dpi units, at max res */
2150141cc406Sopenharmony_ci  s->max_y_by_res[0].res = s->max_y_res;
2151141cc406Sopenharmony_ci  s->max_y_by_res[0].len = s->max_y;
2152141cc406Sopenharmony_ci
2153141cc406Sopenharmony_ci  /* assume these are same as adf, override below */
2154141cc406Sopenharmony_ci  s->max_x_fb = s->max_x;
2155141cc406Sopenharmony_ci  s->max_y_fb = s->max_y;
2156141cc406Sopenharmony_ci
2157141cc406Sopenharmony_ci  /* assume we can do these. we will disable
2158141cc406Sopenharmony_ci   * them at runtime if they cannot */
2159141cc406Sopenharmony_ci  s->has_pixelsize = 1;
2160141cc406Sopenharmony_ci  s->has_MS_autocolor = 1;
2161141cc406Sopenharmony_ci  s->has_MS_prepick = 1;
2162141cc406Sopenharmony_ci  s->has_MS_sleep = 1;
2163141cc406Sopenharmony_ci  s->has_MS_duplex = 1;
2164141cc406Sopenharmony_ci  s->has_MS_rand = 1;
2165141cc406Sopenharmony_ci  s->has_MS_bg = 1;
2166141cc406Sopenharmony_ci  s->has_MS_df = 1;
2167141cc406Sopenharmony_ci  s->has_MS_dropout = 1;
2168141cc406Sopenharmony_ci  s->has_MS_buff = 1;
2169141cc406Sopenharmony_ci  s->has_MS_auto = 1;
2170141cc406Sopenharmony_ci  s->has_MS_lamp = 1;
2171141cc406Sopenharmony_ci  s->has_MS_jobsep = 1;
2172141cc406Sopenharmony_ci
2173141cc406Sopenharmony_ci  /* these two scanners lie about their capabilities,
2174141cc406Sopenharmony_ci   * and/or differ significantly from most other models */
2175141cc406Sopenharmony_ci  if (strstr (s->model_name, "M3091")
2176141cc406Sopenharmony_ci   || strstr (s->model_name, "M3092")) {
2177141cc406Sopenharmony_ci
2178141cc406Sopenharmony_ci    /* lies */
2179141cc406Sopenharmony_ci    s->has_rif = 1;
2180141cc406Sopenharmony_ci    s->has_back = 0;
2181141cc406Sopenharmony_ci    s->adbits = 8;
2182141cc406Sopenharmony_ci    if (strstr (s->model_name, "M3092"))
2183141cc406Sopenharmony_ci      s->has_flatbed = 1;
2184141cc406Sopenharmony_ci
2185141cc406Sopenharmony_ci    /*actually does have res range in non-color modes */
2186141cc406Sopenharmony_ci    for(i=MODE_LINEART;i<MODE_COLOR;i++){
2187141cc406Sopenharmony_ci      s->step_x_res[i] = 1;
2188141cc406Sopenharmony_ci      s->step_y_res[i] = 1;
2189141cc406Sopenharmony_ci    }
2190141cc406Sopenharmony_ci
2191141cc406Sopenharmony_ci    /*but the color mode y list is very limited, only 75, 150, 300 (and 600)*/
2192141cc406Sopenharmony_ci    for(i=0;i<16;i++){
2193141cc406Sopenharmony_ci      s->std_res[i] = 0;
2194141cc406Sopenharmony_ci    }
2195141cc406Sopenharmony_ci    s->std_res[1] = 1;
2196141cc406Sopenharmony_ci    s->std_res[4] = 1;
2197141cc406Sopenharmony_ci    s->std_res[9] = 1;
2198141cc406Sopenharmony_ci
2199141cc406Sopenharmony_ci    /* weirdness */
2200141cc406Sopenharmony_ci    s->has_vuid_3091 = 1;
2201141cc406Sopenharmony_ci    s->has_vuid_color = 0;
2202141cc406Sopenharmony_ci    s->has_vuid_mono = 0;
2203141cc406Sopenharmony_ci    s->has_short_pixelsize = 1;
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci    s->color_interlace = COLOR_INTERLACE_3091;
2206141cc406Sopenharmony_ci    s->duplex_interlace = DUPLEX_INTERLACE_3091;
2207141cc406Sopenharmony_ci    s->ghs_in_rs = 1;
2208141cc406Sopenharmony_ci
2209141cc406Sopenharmony_ci    /* might be inaccurate */
2210141cc406Sopenharmony_ci    s->num_internal_gamma = 1;
2211141cc406Sopenharmony_ci    s->num_download_gamma = 0;
2212141cc406Sopenharmony_ci
2213141cc406Sopenharmony_ci    s->reverse_by_mode[MODE_LINEART] = 1;
2214141cc406Sopenharmony_ci    s->reverse_by_mode[MODE_HALFTONE] = 1;
2215141cc406Sopenharmony_ci    s->reverse_by_mode[MODE_GRAYSCALE] = 0;
2216141cc406Sopenharmony_ci    s->reverse_by_mode[MODE_COLOR] = 0;
2217141cc406Sopenharmony_ci  }
2218141cc406Sopenharmony_ci
2219141cc406Sopenharmony_ci  else if (strstr (s->model_name, "M3093")){
2220141cc406Sopenharmony_ci
2221141cc406Sopenharmony_ci    /* lies */
2222141cc406Sopenharmony_ci    s->has_back = 0;
2223141cc406Sopenharmony_ci    s->adbits = 8;
2224141cc406Sopenharmony_ci
2225141cc406Sopenharmony_ci    /* weirdness */
2226141cc406Sopenharmony_ci    s->duplex_interlace = DUPLEX_INTERLACE_NONE;
2227141cc406Sopenharmony_ci  }
2228141cc406Sopenharmony_ci
2229141cc406Sopenharmony_ci  else if ( strstr (s->model_name, "M309")
2230141cc406Sopenharmony_ci   || strstr (s->model_name, "M409")){
2231141cc406Sopenharmony_ci
2232141cc406Sopenharmony_ci    /* weirdness */
2233141cc406Sopenharmony_ci    s->broken_diag_serial = 1;
2234141cc406Sopenharmony_ci
2235141cc406Sopenharmony_ci    /* lies */
2236141cc406Sopenharmony_ci    s->adbits = 8;
2237141cc406Sopenharmony_ci  }
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_ci  else if (strstr (s->model_name, "fi-4120C2")
2240141cc406Sopenharmony_ci   || strstr (s->model_name, "fi-4220C2") ) {
2241141cc406Sopenharmony_ci
2242141cc406Sopenharmony_ci    /* missing from vpd */
2243141cc406Sopenharmony_ci    s->os_x_basic = 118;
2244141cc406Sopenharmony_ci    s->os_y_basic = 118;
2245141cc406Sopenharmony_ci    s->max_y_fb = 14032;
2246141cc406Sopenharmony_ci  }
2247141cc406Sopenharmony_ci
2248141cc406Sopenharmony_ci  else if (strstr (s->model_name, "fi-4220C")){
2249141cc406Sopenharmony_ci
2250141cc406Sopenharmony_ci    /* missing from vpd */
2251141cc406Sopenharmony_ci    s->max_y_fb = 14032;
2252141cc406Sopenharmony_ci  }
2253141cc406Sopenharmony_ci
2254141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-4340")
2255141cc406Sopenharmony_ci   || strstr (s->model_name, "fi-4750") ) {
2256141cc406Sopenharmony_ci    /* weirdness */
2257141cc406Sopenharmony_ci    s->broken_diag_serial = 1;
2258141cc406Sopenharmony_ci  }
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci  /* some firmware versions use capital f? */
2261141cc406Sopenharmony_ci  else if (strstr (s->model_name, "Fi-4860")
2262141cc406Sopenharmony_ci   || strstr (s->model_name, "fi-4860") ) {
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci    /* weirdness */
2265141cc406Sopenharmony_ci    s->broken_diag_serial = 1;
2266141cc406Sopenharmony_ci
2267141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_LINEART] = 32;
2268141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_HALFTONE] = 32;
2269141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_GRAYSCALE] = 4;
2270141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_COLOR] = 4;
2271141cc406Sopenharmony_ci  }
2272141cc406Sopenharmony_ci
2273141cc406Sopenharmony_ci  /* some firmware versions use capital f? */
2274141cc406Sopenharmony_ci  else if (strstr (s->model_name, "Fi-4990")
2275141cc406Sopenharmony_ci   || strstr (s->model_name, "fi-4990") ) {
2276141cc406Sopenharmony_ci
2277141cc406Sopenharmony_ci    /* weirdness */
2278141cc406Sopenharmony_ci    s->duplex_interlace = DUPLEX_INTERLACE_NONE;
2279141cc406Sopenharmony_ci    s->color_interlace = COLOR_INTERLACE_RRGGBB;
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_LINEART] = 32;
2282141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_HALFTONE] = 32;
2283141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_GRAYSCALE] = 4;
2284141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_COLOR] = 4;
2285141cc406Sopenharmony_ci  }
2286141cc406Sopenharmony_ci
2287141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-5110C")){
2288141cc406Sopenharmony_ci
2289141cc406Sopenharmony_ci    /* missing from vpd */
2290141cc406Sopenharmony_ci    s->os_x_basic = 147;
2291141cc406Sopenharmony_ci    s->os_y_basic = 147;
2292141cc406Sopenharmony_ci  }
2293141cc406Sopenharmony_ci
2294141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-5110EOX")){
2295141cc406Sopenharmony_ci
2296141cc406Sopenharmony_ci    /* weirdness */
2297141cc406Sopenharmony_ci    s->cropping_mode = CROP_ABSOLUTE;
2298141cc406Sopenharmony_ci  }
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-5220C")){
2301141cc406Sopenharmony_ci
2302141cc406Sopenharmony_ci    /* missing from vpd */
2303141cc406Sopenharmony_ci    s->max_x_fb = 10764;
2304141cc406Sopenharmony_ci    s->max_y_fb = 14032;
2305141cc406Sopenharmony_ci  }
2306141cc406Sopenharmony_ci
2307141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-5530")
2308141cc406Sopenharmony_ci    || strstr (s->model_name,"fi-5650")
2309141cc406Sopenharmony_ci    || strstr (s->model_name,"fi-5750")){
2310141cc406Sopenharmony_ci
2311141cc406Sopenharmony_ci    /* lies - usb only */
2312141cc406Sopenharmony_ci    if(s->connection == CONNECTION_USB)
2313141cc406Sopenharmony_ci      s->adbits = 8;
2314141cc406Sopenharmony_ci  }
2315141cc406Sopenharmony_ci
2316141cc406Sopenharmony_ci  else if (strstr (s->model_name,"S1500")){
2317141cc406Sopenharmony_ci
2318141cc406Sopenharmony_ci    /*lies*/
2319141cc406Sopenharmony_ci    s->has_MS_bg=0;
2320141cc406Sopenharmony_ci    s->has_MS_prepick=0;
2321141cc406Sopenharmony_ci  }
2322141cc406Sopenharmony_ci
2323141cc406Sopenharmony_ci  /* also includes the 'Z' models */
2324141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-6130")
2325141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-6140")){
2326141cc406Sopenharmony_ci
2327141cc406Sopenharmony_ci    /* weirdness */
2328141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2329141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 200;
2330141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 151512;
2331141cc406Sopenharmony_ci  }
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci  /* also includes the 'Z' models */
2334141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-6230")
2335141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-6240")){
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_ci    /* weirdness */
2338141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2339141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 200;
2340141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 151512;
2341141cc406Sopenharmony_ci
2342141cc406Sopenharmony_ci    /* missing from vpd */
2343141cc406Sopenharmony_ci    s->max_x_fb = 10764; /* was previously 10488 */
2344141cc406Sopenharmony_ci    s->max_y_fb = 14032; /* some scanners can be slightly more? */
2345141cc406Sopenharmony_ci  }
2346141cc406Sopenharmony_ci
2347141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-6110")){
2348141cc406Sopenharmony_ci
2349141cc406Sopenharmony_ci    /* weirdness */
2350141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2351141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 200;
2352141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 151512;
2353141cc406Sopenharmony_ci
2354141cc406Sopenharmony_ci    /*lies*/
2355141cc406Sopenharmony_ci    s->has_MS_bg=0;
2356141cc406Sopenharmony_ci    s->has_MS_prepick=0;
2357141cc406Sopenharmony_ci  }
2358141cc406Sopenharmony_ci
2359141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-6800")
2360141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-5900")){
2361141cc406Sopenharmony_ci    /* do not need overrides */
2362141cc406Sopenharmony_ci  }
2363141cc406Sopenharmony_ci
2364141cc406Sopenharmony_ci  else if (strstr (s->model_name,"iX500")){
2365141cc406Sopenharmony_ci    /* locks up scanner if we try to auto detect */
2366141cc406Sopenharmony_ci    s->has_MS_lamp = 0;
2367141cc406Sopenharmony_ci
2368141cc406Sopenharmony_ci    /* weirdness */
2369141cc406Sopenharmony_ci    s->need_q_table = 1;
2370141cc406Sopenharmony_ci    s->need_diag_preread = 1;
2371141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_COLOR] = 2;
2372141cc406Sopenharmony_ci    s->hopper_before_op = 1;
2373141cc406Sopenharmony_ci    s->no_wait_after_op = 1;
2374141cc406Sopenharmony_ci
2375141cc406Sopenharmony_ci    /* lies */
2376141cc406Sopenharmony_ci    s->adbits = 8;
2377141cc406Sopenharmony_ci
2378141cc406Sopenharmony_ci    /* we have to simulate these in software*/
2379141cc406Sopenharmony_ci    s->can_mode[MODE_LINEART] = 2;
2380141cc406Sopenharmony_ci    s->can_mode[MODE_GRAYSCALE] = 2;
2381141cc406Sopenharmony_ci
2382141cc406Sopenharmony_ci    /* don't bother with this one */
2383141cc406Sopenharmony_ci    s->can_mode[MODE_HALFTONE] = 0;
2384141cc406Sopenharmony_ci  }
2385141cc406Sopenharmony_ci
2386141cc406Sopenharmony_ci  /*mostly copied from iX500*/
2387141cc406Sopenharmony_ci  else if (strstr (s->model_name,"iX100")){
2388141cc406Sopenharmony_ci    /* locks up scanner if we try to auto detect */
2389141cc406Sopenharmony_ci    s->has_MS_lamp = 0;
2390141cc406Sopenharmony_ci
2391141cc406Sopenharmony_ci    /* weirdness */
2392141cc406Sopenharmony_ci    s->need_q_table = 1;
2393141cc406Sopenharmony_ci    s->need_diag_preread = 1;
2394141cc406Sopenharmony_ci    s->ppl_mod_by_mode[MODE_COLOR] = 2;
2395141cc406Sopenharmony_ci    s->hopper_before_op = 1;
2396141cc406Sopenharmony_ci    s->no_wait_after_op = 1;
2397141cc406Sopenharmony_ci
2398141cc406Sopenharmony_ci    /* lies */
2399141cc406Sopenharmony_ci    s->adbits = 8;
2400141cc406Sopenharmony_ci
2401141cc406Sopenharmony_ci    /* don't bother with this one */
2402141cc406Sopenharmony_ci    s->can_mode[MODE_HALFTONE] = 0;
2403141cc406Sopenharmony_ci  }
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-7180")
2406141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-7160")){
2407141cc406Sopenharmony_ci    /* locks up scanner if we try to auto detect */
2408141cc406Sopenharmony_ci    s->has_MS_lamp = 0;
2409141cc406Sopenharmony_ci
2410141cc406Sopenharmony_ci    /* weirdness */
2411141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2412141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 400;
2413141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 194268;
2414141cc406Sopenharmony_ci    s->max_y_by_res[2].res = 300;
2415141cc406Sopenharmony_ci    s->max_y_by_res[2].len = 260268;
2416141cc406Sopenharmony_ci    s->max_y_by_res[3].res = 200;
2417141cc406Sopenharmony_ci    s->max_y_by_res[3].len = 266268;
2418141cc406Sopenharmony_ci  }
2419141cc406Sopenharmony_ci
2420141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-7280")
2421141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-7260")){
2422141cc406Sopenharmony_ci    /* locks up scanner if we try to auto detect */
2423141cc406Sopenharmony_ci    s->has_MS_lamp = 0;
2424141cc406Sopenharmony_ci
2425141cc406Sopenharmony_ci    /* weirdness */
2426141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2427141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 400;
2428141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 194268;
2429141cc406Sopenharmony_ci    s->max_y_by_res[2].res = 300;
2430141cc406Sopenharmony_ci    s->max_y_by_res[2].len = 260268;
2431141cc406Sopenharmony_ci    s->max_y_by_res[3].res = 200;
2432141cc406Sopenharmony_ci    s->max_y_by_res[3].len = 266268;
2433141cc406Sopenharmony_ci
2434141cc406Sopenharmony_ci    /* missing from vpd */
2435141cc406Sopenharmony_ci    s->max_x_fb = 10764;
2436141cc406Sopenharmony_ci    s->max_y_fb = 14032; /* some scanners can be slightly more? */
2437141cc406Sopenharmony_ci  }
2438141cc406Sopenharmony_ci
2439141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-7480")
2440141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-7460")){
2441141cc406Sopenharmony_ci
2442141cc406Sopenharmony_ci    /* weirdness */
2443141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2444141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 400;
2445141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 194268;
2446141cc406Sopenharmony_ci    s->max_y_by_res[2].res = 300;
2447141cc406Sopenharmony_ci    s->max_y_by_res[2].len = 260268;
2448141cc406Sopenharmony_ci    s->max_y_by_res[3].res = 200;
2449141cc406Sopenharmony_ci    s->max_y_by_res[3].len = 266268;
2450141cc406Sopenharmony_ci  }
2451141cc406Sopenharmony_ci
2452141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-7030")){
2453141cc406Sopenharmony_ci
2454141cc406Sopenharmony_ci    /* weirdness */
2455141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2456141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 400;
2457141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 192000;
2458141cc406Sopenharmony_ci    s->max_y_by_res[2].res = 300;
2459141cc406Sopenharmony_ci    s->max_y_by_res[2].len = 258000;
2460141cc406Sopenharmony_ci    s->max_y_by_res[3].res = 200;
2461141cc406Sopenharmony_ci    s->max_y_by_res[3].len = 264000;
2462141cc406Sopenharmony_ci  }
2463141cc406Sopenharmony_ci
2464141cc406Sopenharmony_ci  else if (strstr (s->model_name,"fi-7700")
2465141cc406Sopenharmony_ci   || strstr (s->model_name,"fi-7600")){
2466141cc406Sopenharmony_ci
2467141cc406Sopenharmony_ci    /* weirdness */
2468141cc406Sopenharmony_ci    /* these machines have longer max paper at lower res */
2469141cc406Sopenharmony_ci    s->max_y_by_res[1].res = 400;
2470141cc406Sopenharmony_ci    s->max_y_by_res[1].len = 192000;
2471141cc406Sopenharmony_ci    s->max_y_by_res[2].res = 300;
2472141cc406Sopenharmony_ci    s->max_y_by_res[2].len = 258000;
2473141cc406Sopenharmony_ci    s->max_y_by_res[3].res = 200;
2474141cc406Sopenharmony_ci    s->max_y_by_res[3].len = 264000;
2475141cc406Sopenharmony_ci  }
2476141cc406Sopenharmony_ci
2477141cc406Sopenharmony_ci  DBG (10, "init_model: finish\n");
2478141cc406Sopenharmony_ci
2479141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2480141cc406Sopenharmony_ci}
2481141cc406Sopenharmony_ci
2482141cc406Sopenharmony_cistatic SANE_Status
2483141cc406Sopenharmony_ciset_mode (struct fujitsu *s, int mode)
2484141cc406Sopenharmony_ci{
2485141cc406Sopenharmony_ci  int i;
2486141cc406Sopenharmony_ci  /* give the user what they asked for */
2487141cc406Sopenharmony_ci  s->u_mode = mode;
2488141cc406Sopenharmony_ci
2489141cc406Sopenharmony_ci  /* give the scanner the closest mode */
2490141cc406Sopenharmony_ci  for(i=MODE_COLOR;i>=mode;i--){
2491141cc406Sopenharmony_ci    if(s->can_mode[i] == 1){
2492141cc406Sopenharmony_ci      s->s_mode = i;
2493141cc406Sopenharmony_ci    }
2494141cc406Sopenharmony_ci  }
2495141cc406Sopenharmony_ci
2496141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2497141cc406Sopenharmony_ci}
2498141cc406Sopenharmony_ci
2499141cc406Sopenharmony_ci/*
2500141cc406Sopenharmony_ci * set good default user values.
2501141cc406Sopenharmony_ci * struct is already initialized to 0.
2502141cc406Sopenharmony_ci */
2503141cc406Sopenharmony_cistatic SANE_Status
2504141cc406Sopenharmony_ciinit_user (struct fujitsu *s)
2505141cc406Sopenharmony_ci{
2506141cc406Sopenharmony_ci
2507141cc406Sopenharmony_ci  DBG (10, "init_user: start\n");
2508141cc406Sopenharmony_ci
2509141cc406Sopenharmony_ci  /* source */
2510141cc406Sopenharmony_ci  if(s->has_flatbed)
2511141cc406Sopenharmony_ci    s->source = SOURCE_FLATBED;
2512141cc406Sopenharmony_ci  else if(s->has_adf)
2513141cc406Sopenharmony_ci    s->source = SOURCE_ADF_FRONT;
2514141cc406Sopenharmony_ci  else if(s->has_return_path)
2515141cc406Sopenharmony_ci    s->source = SOURCE_CARD_FRONT;
2516141cc406Sopenharmony_ci
2517141cc406Sopenharmony_ci  /* scan mode */
2518141cc406Sopenharmony_ci  if(s->can_mode[MODE_LINEART])
2519141cc406Sopenharmony_ci    set_mode(s,MODE_LINEART);
2520141cc406Sopenharmony_ci  else if(s->can_mode[MODE_HALFTONE])
2521141cc406Sopenharmony_ci    set_mode(s,MODE_HALFTONE);
2522141cc406Sopenharmony_ci  else if(s->can_mode[MODE_GRAYSCALE])
2523141cc406Sopenharmony_ci    set_mode(s,MODE_GRAYSCALE);
2524141cc406Sopenharmony_ci  else if(s->can_mode[MODE_COLOR])
2525141cc406Sopenharmony_ci    set_mode(s,MODE_COLOR);
2526141cc406Sopenharmony_ci
2527141cc406Sopenharmony_ci  /*x res*/
2528141cc406Sopenharmony_ci  s->resolution_x = s->basic_x_res;
2529141cc406Sopenharmony_ci
2530141cc406Sopenharmony_ci  /*y res*/
2531141cc406Sopenharmony_ci  s->resolution_y = s->basic_y_res;
2532141cc406Sopenharmony_ci  if(s->resolution_y > s->resolution_x){
2533141cc406Sopenharmony_ci    s->resolution_y = s->resolution_x;
2534141cc406Sopenharmony_ci  }
2535141cc406Sopenharmony_ci
2536141cc406Sopenharmony_ci  /* page width US-Letter */
2537141cc406Sopenharmony_ci  s->page_width = 8.5 * 1200;
2538141cc406Sopenharmony_ci  if(s->page_width > s->max_x){
2539141cc406Sopenharmony_ci    s->page_width = s->max_x;
2540141cc406Sopenharmony_ci  }
2541141cc406Sopenharmony_ci
2542141cc406Sopenharmony_ci  /* page height US-Letter */
2543141cc406Sopenharmony_ci  s->page_height = 11 * 1200;
2544141cc406Sopenharmony_ci  set_max_y(s);
2545141cc406Sopenharmony_ci  if(s->page_height > s->max_y){
2546141cc406Sopenharmony_ci    s->page_height = s->max_y;
2547141cc406Sopenharmony_ci  }
2548141cc406Sopenharmony_ci
2549141cc406Sopenharmony_ci  /* bottom-right x */
2550141cc406Sopenharmony_ci  s->br_x = s->page_width;
2551141cc406Sopenharmony_ci
2552141cc406Sopenharmony_ci  /* bottom-right y */
2553141cc406Sopenharmony_ci  s->br_y = s->page_height;
2554141cc406Sopenharmony_ci
2555141cc406Sopenharmony_ci  /* gamma ramp exponent */
2556141cc406Sopenharmony_ci  s->gamma = 1;
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_ci  /* safe endorser settings */
2559141cc406Sopenharmony_ci  s->u_endorser_bits=16;
2560141cc406Sopenharmony_ci  s->u_endorser_step=1;
2561141cc406Sopenharmony_ci  s->u_endorser_side=ED_back;
2562141cc406Sopenharmony_ci  if(s->has_endorser_f){
2563141cc406Sopenharmony_ci    s->u_endorser_side=ED_front;
2564141cc406Sopenharmony_ci  }
2565141cc406Sopenharmony_ci  s->u_endorser_dir=DIR_TTB;
2566141cc406Sopenharmony_ci  strcpy((char *)s->u_endorser_string,"%05ud");
2567141cc406Sopenharmony_ci
2568141cc406Sopenharmony_ci  /* more recent machines default to this being 'on',  *
2569141cc406Sopenharmony_ci   * which causes the scanner to ingest multiple pages *
2570141cc406Sopenharmony_ci   * even when the user only wants one */
2571141cc406Sopenharmony_ci  s->buff_mode = MSEL_OFF;
2572141cc406Sopenharmony_ci
2573141cc406Sopenharmony_ci  /* useful features of newer scanners which we turn on,
2574141cc406Sopenharmony_ci   * even though the scanner defaults to off */
2575141cc406Sopenharmony_ci  if(s->has_paper_protect){
2576141cc406Sopenharmony_ci    s->paper_protect = MSEL_ON;
2577141cc406Sopenharmony_ci  }
2578141cc406Sopenharmony_ci  if(s->has_staple_detect){
2579141cc406Sopenharmony_ci    s->staple_detect = MSEL_ON;
2580141cc406Sopenharmony_ci  }
2581141cc406Sopenharmony_ci  if(s->has_df_recovery){
2582141cc406Sopenharmony_ci    s->df_recovery = MSEL_ON;
2583141cc406Sopenharmony_ci  }
2584141cc406Sopenharmony_ci  if(s->has_adv_paper_prot){
2585141cc406Sopenharmony_ci    s->adv_paper_prot = MSEL_ON;
2586141cc406Sopenharmony_ci  }
2587141cc406Sopenharmony_ci
2588141cc406Sopenharmony_ci  s->off_time = 240;
2589141cc406Sopenharmony_ci
2590141cc406Sopenharmony_ci  DBG (10, "init_user: finish\n");
2591141cc406Sopenharmony_ci
2592141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2593141cc406Sopenharmony_ci}
2594141cc406Sopenharmony_ci
2595141cc406Sopenharmony_ci/*
2596141cc406Sopenharmony_ci * This function presets the "option" array to blank
2597141cc406Sopenharmony_ci */
2598141cc406Sopenharmony_cistatic SANE_Status
2599141cc406Sopenharmony_ciinit_options (struct fujitsu *s)
2600141cc406Sopenharmony_ci{
2601141cc406Sopenharmony_ci  int i;
2602141cc406Sopenharmony_ci
2603141cc406Sopenharmony_ci  DBG (10, "init_options: start\n");
2604141cc406Sopenharmony_ci
2605141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
2606141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i) {
2607141cc406Sopenharmony_ci      s->opt[i].name = "filler";
2608141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
2609141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_INACTIVE;
2610141cc406Sopenharmony_ci  }
2611141cc406Sopenharmony_ci
2612141cc406Sopenharmony_ci  /* go ahead and setup the first opt, because
2613141cc406Sopenharmony_ci   * frontend may call control_option on it
2614141cc406Sopenharmony_ci   * before calling get_option_descriptor
2615141cc406Sopenharmony_ci   */
2616141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
2617141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2618141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2619141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2620141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2621141cc406Sopenharmony_ci
2622141cc406Sopenharmony_ci  DBG (10, "init_options: finish\n");
2623141cc406Sopenharmony_ci
2624141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2625141cc406Sopenharmony_ci}
2626141cc406Sopenharmony_ci
2627141cc406Sopenharmony_ci/*
2628141cc406Sopenharmony_ci * send set window repeatedly to color scanners,
2629141cc406Sopenharmony_ci * searching for valid color interlacing mode
2630141cc406Sopenharmony_ci */
2631141cc406Sopenharmony_cistatic SANE_Status
2632141cc406Sopenharmony_ciinit_interlace (struct fujitsu *s)
2633141cc406Sopenharmony_ci{
2634141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
2635141cc406Sopenharmony_ci  int curr_mode = s->u_mode;
2636141cc406Sopenharmony_ci  int oldDbg=0;
2637141cc406Sopenharmony_ci
2638141cc406Sopenharmony_ci  DBG (10, "init_interlace: start\n");
2639141cc406Sopenharmony_ci
2640141cc406Sopenharmony_ci  if(s->color_interlace != COLOR_INTERLACE_UNK){
2641141cc406Sopenharmony_ci    DBG (10, "init_interlace: already loaded\n");
2642141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2643141cc406Sopenharmony_ci  }
2644141cc406Sopenharmony_ci
2645141cc406Sopenharmony_ci  if(!s->has_vuid_color){
2646141cc406Sopenharmony_ci    DBG (10, "init_interlace: color unsupported\n");
2647141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2648141cc406Sopenharmony_ci  }
2649141cc406Sopenharmony_ci
2650141cc406Sopenharmony_ci  /* set to color mode first */
2651141cc406Sopenharmony_ci  set_mode(s,MODE_COLOR);
2652141cc406Sopenharmony_ci
2653141cc406Sopenharmony_ci  /* load our own private copy of scan params */
2654141cc406Sopenharmony_ci  ret = update_params(s);
2655141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
2656141cc406Sopenharmony_ci    DBG (5, "init_interlace: ERROR: cannot update params\n");
2657141cc406Sopenharmony_ci    return ret;
2658141cc406Sopenharmony_ci  }
2659141cc406Sopenharmony_ci
2660141cc406Sopenharmony_ci  /*loop thru all the formats we support*/
2661141cc406Sopenharmony_ci  for(s->color_interlace = COLOR_INTERLACE_RGB;
2662141cc406Sopenharmony_ci   s->color_interlace <= COLOR_INTERLACE_RRGGBB;
2663141cc406Sopenharmony_ci   s->color_interlace++){
2664141cc406Sopenharmony_ci
2665141cc406Sopenharmony_ci    /* some of the following probes will produce errors */
2666141cc406Sopenharmony_ci    /* so we reduce the dbg level to reduce the noise */
2667141cc406Sopenharmony_ci    /* however, if user builds with NDEBUG, we can't do that */
2668141cc406Sopenharmony_ci    /* so we protect the code with the following macro */
2669141cc406Sopenharmony_ci    IF_DBG( oldDbg=DBG_LEVEL; )
2670141cc406Sopenharmony_ci    IF_DBG( if(DBG_LEVEL < 35){ DBG_LEVEL = 0; } )
2671141cc406Sopenharmony_ci
2672141cc406Sopenharmony_ci    ret = set_window(s);
2673141cc406Sopenharmony_ci
2674141cc406Sopenharmony_ci    IF_DBG (DBG_LEVEL = oldDbg;)
2675141cc406Sopenharmony_ci
2676141cc406Sopenharmony_ci    if (ret == SANE_STATUS_GOOD){
2677141cc406Sopenharmony_ci      break;
2678141cc406Sopenharmony_ci    }
2679141cc406Sopenharmony_ci    else{
2680141cc406Sopenharmony_ci      DBG (15, "init_interlace: not %d\n", s->color_interlace);
2681141cc406Sopenharmony_ci    }
2682141cc406Sopenharmony_ci  }
2683141cc406Sopenharmony_ci
2684141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
2685141cc406Sopenharmony_ci    DBG (5, "init_interlace: no valid interlacings\n");
2686141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2687141cc406Sopenharmony_ci  }
2688141cc406Sopenharmony_ci
2689141cc406Sopenharmony_ci  DBG (15, "init_interlace: color_interlace: %d\n",s->color_interlace);
2690141cc406Sopenharmony_ci
2691141cc406Sopenharmony_ci  /* restore mode */
2692141cc406Sopenharmony_ci  set_mode(s,curr_mode);
2693141cc406Sopenharmony_ci
2694141cc406Sopenharmony_ci  DBG (10, "init_interlace: finish\n");
2695141cc406Sopenharmony_ci
2696141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2697141cc406Sopenharmony_ci}
2698141cc406Sopenharmony_ci
2699141cc406Sopenharmony_ci/*
2700141cc406Sopenharmony_ci * send diag query for serial number, and read result back
2701141cc406Sopenharmony_ci * use it to build a unique name for scanner in s->serial_name
2702141cc406Sopenharmony_ci */
2703141cc406Sopenharmony_cistatic SANE_Status
2704141cc406Sopenharmony_ciinit_serial (struct fujitsu *s)
2705141cc406Sopenharmony_ci{
2706141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
2707141cc406Sopenharmony_ci  unsigned int sn = 0;
2708141cc406Sopenharmony_ci
2709141cc406Sopenharmony_ci  unsigned char cmd[SEND_DIAGNOSTIC_len]; /*also big enough for READ_DIAG*/
2710141cc406Sopenharmony_ci  size_t cmdLen = SEND_DIAGNOSTIC_len;
2711141cc406Sopenharmony_ci
2712141cc406Sopenharmony_ci  unsigned char out[SD_gdi_len];
2713141cc406Sopenharmony_ci  size_t outLen = SD_gdi_len;
2714141cc406Sopenharmony_ci
2715141cc406Sopenharmony_ci  unsigned char in[RD_gdi_len];
2716141cc406Sopenharmony_ci  size_t inLen = RD_gdi_len;
2717141cc406Sopenharmony_ci
2718141cc406Sopenharmony_ci  DBG (10, "init_serial: start\n");
2719141cc406Sopenharmony_ci
2720141cc406Sopenharmony_ci  if (!s->has_cmd_sdiag || !s->has_cmd_rdiag || s->broken_diag_serial){
2721141cc406Sopenharmony_ci    DBG (5, "init_serial: send/read diag not supported, returning\n");
2722141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2723141cc406Sopenharmony_ci  }
2724141cc406Sopenharmony_ci
2725141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
2726141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_DIAGNOSTIC_code);
2727141cc406Sopenharmony_ci  set_SD_slftst(cmd, 0);
2728141cc406Sopenharmony_ci  set_SD_xferlen(cmd, outLen);
2729141cc406Sopenharmony_ci
2730141cc406Sopenharmony_ci  memcpy(out,SD_gdi_string,outLen);
2731141cc406Sopenharmony_ci
2732141cc406Sopenharmony_ci  ret = do_cmd (
2733141cc406Sopenharmony_ci    s, 1, 0,
2734141cc406Sopenharmony_ci    cmd, cmdLen,
2735141cc406Sopenharmony_ci    out, outLen,
2736141cc406Sopenharmony_ci    NULL, NULL
2737141cc406Sopenharmony_ci  );
2738141cc406Sopenharmony_ci
2739141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
2740141cc406Sopenharmony_ci    DBG (5, "init_serial: send diag error: %d\n", ret);
2741141cc406Sopenharmony_ci    return ret;
2742141cc406Sopenharmony_ci  }
2743141cc406Sopenharmony_ci
2744141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
2745141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, READ_DIAGNOSTIC_code);
2746141cc406Sopenharmony_ci  set_RD_xferlen(cmd, inLen);
2747141cc406Sopenharmony_ci
2748141cc406Sopenharmony_ci  ret = do_cmd (
2749141cc406Sopenharmony_ci    s, 1, 0,
2750141cc406Sopenharmony_ci    cmd, cmdLen,
2751141cc406Sopenharmony_ci    NULL, 0,
2752141cc406Sopenharmony_ci    in, &inLen
2753141cc406Sopenharmony_ci  );
2754141cc406Sopenharmony_ci
2755141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
2756141cc406Sopenharmony_ci    DBG (5, "init_serial: read diag error: %d\n", ret);
2757141cc406Sopenharmony_ci    return ret;
2758141cc406Sopenharmony_ci  }
2759141cc406Sopenharmony_ci
2760141cc406Sopenharmony_ci  sn = get_RD_id_serial(in);
2761141cc406Sopenharmony_ci
2762141cc406Sopenharmony_ci  DBG (15, "init_serial: found sn %d\n",sn);
2763141cc406Sopenharmony_ci
2764141cc406Sopenharmony_ci  sprintf(s->serial_name, "%s:%d", s->model_name, sn);
2765141cc406Sopenharmony_ci
2766141cc406Sopenharmony_ci  DBG (15, "init_serial: serial_name: %s\n",s->serial_name);
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  DBG (10, "init_serial: finish\n");
2769141cc406Sopenharmony_ci
2770141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2771141cc406Sopenharmony_ci}
2772141cc406Sopenharmony_ci
2773141cc406Sopenharmony_ci/*
2774141cc406Sopenharmony_ci * From the SANE spec:
2775141cc406Sopenharmony_ci * This function is used to establish a connection to a particular
2776141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument
2777141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device
2778141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length
2779141cc406Sopenharmony_ci * string as the device requests opening the first available device
2780141cc406Sopenharmony_ci * (if there is such a device).
2781141cc406Sopenharmony_ci */
2782141cc406Sopenharmony_ciSANE_Status
2783141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle)
2784141cc406Sopenharmony_ci{
2785141cc406Sopenharmony_ci  struct fujitsu *dev = NULL;
2786141cc406Sopenharmony_ci  struct fujitsu *s = NULL;
2787141cc406Sopenharmony_ci  SANE_Status ret;
2788141cc406Sopenharmony_ci
2789141cc406Sopenharmony_ci  DBG (10, "sane_open: start\n");
2790141cc406Sopenharmony_ci
2791141cc406Sopenharmony_ci  if(fujitsu_devList){
2792141cc406Sopenharmony_ci    DBG (15, "sane_open: searching currently attached scanners\n");
2793141cc406Sopenharmony_ci  }
2794141cc406Sopenharmony_ci  else{
2795141cc406Sopenharmony_ci    DBG (15, "sane_open: no scanners currently attached, attaching\n");
2796141cc406Sopenharmony_ci
2797141cc406Sopenharmony_ci    ret = sane_get_devices(NULL,0);
2798141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
2799141cc406Sopenharmony_ci      return ret;
2800141cc406Sopenharmony_ci    }
2801141cc406Sopenharmony_ci  }
2802141cc406Sopenharmony_ci
2803141cc406Sopenharmony_ci  if(!name || !name[0]){
2804141cc406Sopenharmony_ci    DBG (15, "sane_open: no device requested, using default\n");
2805141cc406Sopenharmony_ci    s = fujitsu_devList;
2806141cc406Sopenharmony_ci  }
2807141cc406Sopenharmony_ci  else{
2808141cc406Sopenharmony_ci    DBG (15, "sane_open: device %s requested\n", name);
2809141cc406Sopenharmony_ci
2810141cc406Sopenharmony_ci    for (dev = fujitsu_devList; dev; dev = dev->next) {
2811141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, name) == 0
2812141cc406Sopenharmony_ci       || strcmp (dev->device_name, name) == 0) { /*always allow sanei devname*/
2813141cc406Sopenharmony_ci        s = dev;
2814141cc406Sopenharmony_ci        break;
2815141cc406Sopenharmony_ci      }
2816141cc406Sopenharmony_ci    }
2817141cc406Sopenharmony_ci  }
2818141cc406Sopenharmony_ci
2819141cc406Sopenharmony_ci  if (!s) {
2820141cc406Sopenharmony_ci    DBG (5, "sane_open: no device found\n");
2821141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2822141cc406Sopenharmony_ci  }
2823141cc406Sopenharmony_ci
2824141cc406Sopenharmony_ci  DBG (15, "sane_open: device %s found\n", s->sane.name);
2825141cc406Sopenharmony_ci
2826141cc406Sopenharmony_ci  *handle = s;
2827141cc406Sopenharmony_ci
2828141cc406Sopenharmony_ci  /* connect the fd so we can talk to scanner */
2829141cc406Sopenharmony_ci  ret = connect_fd(s);
2830141cc406Sopenharmony_ci  if(ret != SANE_STATUS_GOOD){
2831141cc406Sopenharmony_ci    return ret;
2832141cc406Sopenharmony_ci  }
2833141cc406Sopenharmony_ci
2834141cc406Sopenharmony_ci  DBG (10, "sane_open: finish\n");
2835141cc406Sopenharmony_ci
2836141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2837141cc406Sopenharmony_ci}
2838141cc406Sopenharmony_ci
2839141cc406Sopenharmony_ci/*
2840141cc406Sopenharmony_ci * @@ Section 3 - SANE Options functions
2841141cc406Sopenharmony_ci */
2842141cc406Sopenharmony_ci
2843141cc406Sopenharmony_ci/*
2844141cc406Sopenharmony_ci * Returns the options we know.
2845141cc406Sopenharmony_ci *
2846141cc406Sopenharmony_ci * From the SANE spec:
2847141cc406Sopenharmony_ci * This function is used to access option descriptors. The function
2848141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device
2849141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a
2850141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of
2851141cc406Sopenharmony_ci * options that are available for device handle h (the count includes
2852141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns
2853141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid
2854141cc406Sopenharmony_ci * (and at the returned address) until the device is closed.
2855141cc406Sopenharmony_ci */
2856141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
2857141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
2858141cc406Sopenharmony_ci{
2859141cc406Sopenharmony_ci  struct fujitsu *s = handle;
2860141cc406Sopenharmony_ci  int i,j;
2861141cc406Sopenharmony_ci  SANE_Option_Descriptor *opt = &s->opt[option];
2862141cc406Sopenharmony_ci
2863141cc406Sopenharmony_ci  DBG (20, "sane_get_option_descriptor: %d\n", option);
2864141cc406Sopenharmony_ci
2865141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
2866141cc406Sopenharmony_ci    return NULL;
2867141cc406Sopenharmony_ci
2868141cc406Sopenharmony_ci  /* "Mode" group -------------------------------------------------------- */
2869141cc406Sopenharmony_ci  if(option==OPT_STANDARD_GROUP){
2870141cc406Sopenharmony_ci    opt->name = SANE_NAME_STANDARD;
2871141cc406Sopenharmony_ci    opt->title = SANE_TITLE_STANDARD;
2872141cc406Sopenharmony_ci    opt->desc = SANE_DESC_STANDARD;
2873141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
2874141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
2875141cc406Sopenharmony_ci  }
2876141cc406Sopenharmony_ci
2877141cc406Sopenharmony_ci  /* source */
2878141cc406Sopenharmony_ci  if(option==OPT_SOURCE){
2879141cc406Sopenharmony_ci    i=0;
2880141cc406Sopenharmony_ci    if(s->has_flatbed){
2881141cc406Sopenharmony_ci      s->source_list[i++]=STRING_FLATBED;
2882141cc406Sopenharmony_ci    }
2883141cc406Sopenharmony_ci    if(s->has_adf){
2884141cc406Sopenharmony_ci      s->source_list[i++]=STRING_ADFFRONT;
2885141cc406Sopenharmony_ci
2886141cc406Sopenharmony_ci      if(s->has_back){
2887141cc406Sopenharmony_ci        s->source_list[i++]=STRING_ADFBACK;
2888141cc406Sopenharmony_ci      }
2889141cc406Sopenharmony_ci      if(s->has_duplex){
2890141cc406Sopenharmony_ci        s->source_list[i++]=STRING_ADFDUPLEX;
2891141cc406Sopenharmony_ci      }
2892141cc406Sopenharmony_ci    }
2893141cc406Sopenharmony_ci    if(s->has_return_path){
2894141cc406Sopenharmony_ci      s->source_list[i++]=STRING_CARDFRONT;
2895141cc406Sopenharmony_ci
2896141cc406Sopenharmony_ci      if(s->has_back){
2897141cc406Sopenharmony_ci        s->source_list[i++]=STRING_CARDBACK;
2898141cc406Sopenharmony_ci      }
2899141cc406Sopenharmony_ci      if(s->has_duplex){
2900141cc406Sopenharmony_ci        s->source_list[i++]=STRING_CARDDUPLEX;
2901141cc406Sopenharmony_ci      }
2902141cc406Sopenharmony_ci    }
2903141cc406Sopenharmony_ci    s->source_list[i]=NULL;
2904141cc406Sopenharmony_ci
2905141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_SOURCE;
2906141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_SOURCE;
2907141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_SOURCE;
2908141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
2909141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
2910141cc406Sopenharmony_ci    opt->constraint.string_list = s->source_list;
2911141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
2912141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2913141cc406Sopenharmony_ci  }
2914141cc406Sopenharmony_ci
2915141cc406Sopenharmony_ci  /* scan mode */
2916141cc406Sopenharmony_ci  if(option==OPT_MODE){
2917141cc406Sopenharmony_ci    i=0;
2918141cc406Sopenharmony_ci    if(s->can_mode[MODE_LINEART]){
2919141cc406Sopenharmony_ci      s->mode_list[i++]=STRING_LINEART;
2920141cc406Sopenharmony_ci    }
2921141cc406Sopenharmony_ci    if(s->can_mode[MODE_HALFTONE]){
2922141cc406Sopenharmony_ci      s->mode_list[i++]=STRING_HALFTONE;
2923141cc406Sopenharmony_ci    }
2924141cc406Sopenharmony_ci    if(s->can_mode[MODE_GRAYSCALE]){
2925141cc406Sopenharmony_ci      s->mode_list[i++]=STRING_GRAYSCALE;
2926141cc406Sopenharmony_ci    }
2927141cc406Sopenharmony_ci    if(s->can_mode[MODE_COLOR]){
2928141cc406Sopenharmony_ci      s->mode_list[i++]=STRING_COLOR;
2929141cc406Sopenharmony_ci    }
2930141cc406Sopenharmony_ci    s->mode_list[i]=NULL;
2931141cc406Sopenharmony_ci
2932141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_MODE;
2933141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_MODE;
2934141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_MODE;
2935141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
2936141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
2937141cc406Sopenharmony_ci    opt->constraint.string_list = s->mode_list;
2938141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
2939141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2940141cc406Sopenharmony_ci  }
2941141cc406Sopenharmony_ci
2942141cc406Sopenharmony_ci  /* resolution */
2943141cc406Sopenharmony_ci  /* some scanners only support fixed res
2944141cc406Sopenharmony_ci   * build a list of possible choices */
2945141cc406Sopenharmony_ci  if(option==OPT_RES){
2946141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_RESOLUTION;
2947141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_RESOLUTION;
2948141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_RESOLUTION;
2949141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
2950141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_DPI;
2951141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2952141cc406Sopenharmony_ci
2953141cc406Sopenharmony_ci    if(s->step_x_res[s->s_mode] && s->step_y_res[s->s_mode]){
2954141cc406Sopenharmony_ci      s->res_range.min = s->min_x_res;
2955141cc406Sopenharmony_ci      s->res_range.max = s->max_x_res;
2956141cc406Sopenharmony_ci      s->res_range.quant = s->step_x_res[s->s_mode];
2957141cc406Sopenharmony_ci      opt->constraint_type = SANE_CONSTRAINT_RANGE;
2958141cc406Sopenharmony_ci      opt->constraint.range = &s->res_range;
2959141cc406Sopenharmony_ci    }
2960141cc406Sopenharmony_ci    else{
2961141cc406Sopenharmony_ci      int reses[]
2962141cc406Sopenharmony_ci        = {60,75,100,120,150,160,180,200,240,300,320,400,480,600,800,1200};
2963141cc406Sopenharmony_ci
2964141cc406Sopenharmony_ci      i=0;
2965141cc406Sopenharmony_ci      for(j=0;j<16;j++){
2966141cc406Sopenharmony_ci        if(s->std_res[j]
2967141cc406Sopenharmony_ci          && s->max_x_res >= reses[j] && s->min_x_res <= reses[j]
2968141cc406Sopenharmony_ci          && s->max_y_res >= reses[j] && s->min_y_res <= reses[j]
2969141cc406Sopenharmony_ci        ){
2970141cc406Sopenharmony_ci          s->res_list[++i] = reses[j];
2971141cc406Sopenharmony_ci        }
2972141cc406Sopenharmony_ci      }
2973141cc406Sopenharmony_ci      s->res_list[0] = i;
2974141cc406Sopenharmony_ci
2975141cc406Sopenharmony_ci      opt->constraint_type = SANE_CONSTRAINT_WORD_LIST;
2976141cc406Sopenharmony_ci      opt->constraint.word_list = s->res_list;
2977141cc406Sopenharmony_ci    }
2978141cc406Sopenharmony_ci  }
2979141cc406Sopenharmony_ci
2980141cc406Sopenharmony_ci  /* "Geometry" group ---------------------------------------------------- */
2981141cc406Sopenharmony_ci  if(option==OPT_GEOMETRY_GROUP){
2982141cc406Sopenharmony_ci    opt->name = SANE_NAME_GEOMETRY;
2983141cc406Sopenharmony_ci    opt->title = SANE_TITLE_GEOMETRY;
2984141cc406Sopenharmony_ci    opt->desc = SANE_DESC_GEOMETRY;
2985141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
2986141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
2987141cc406Sopenharmony_ci  }
2988141cc406Sopenharmony_ci
2989141cc406Sopenharmony_ci  /* top-left x */
2990141cc406Sopenharmony_ci  if(option==OPT_TL_X){
2991141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
2992141cc406Sopenharmony_ci    /* must be converted to MM for sane */
2993141cc406Sopenharmony_ci    s->tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x);
2994141cc406Sopenharmony_ci    s->tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s));
2995141cc406Sopenharmony_ci    s->tl_x_range.quant = MM_PER_UNIT_FIX;
2996141cc406Sopenharmony_ci
2997141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_TL_X;
2998141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_TL_X;
2999141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_TL_X;
3000141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3001141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3002141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3003141cc406Sopenharmony_ci    opt->constraint.range = &(s->tl_x_range);
3004141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3005141cc406Sopenharmony_ci  }
3006141cc406Sopenharmony_ci
3007141cc406Sopenharmony_ci  /* top-left y */
3008141cc406Sopenharmony_ci  if(option==OPT_TL_Y){
3009141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
3010141cc406Sopenharmony_ci    /* must be converted to MM for sane */
3011141cc406Sopenharmony_ci    s->tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y);
3012141cc406Sopenharmony_ci    s->tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s));
3013141cc406Sopenharmony_ci    s->tl_y_range.quant = MM_PER_UNIT_FIX;
3014141cc406Sopenharmony_ci
3015141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_TL_Y;
3016141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_TL_Y;
3017141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_TL_Y;
3018141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3019141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3020141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3021141cc406Sopenharmony_ci    opt->constraint.range = &(s->tl_y_range);
3022141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3023141cc406Sopenharmony_ci  }
3024141cc406Sopenharmony_ci
3025141cc406Sopenharmony_ci  /* bottom-right x */
3026141cc406Sopenharmony_ci  if(option==OPT_BR_X){
3027141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
3028141cc406Sopenharmony_ci    /* must be converted to MM for sane */
3029141cc406Sopenharmony_ci    s->br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x);
3030141cc406Sopenharmony_ci    s->br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s));
3031141cc406Sopenharmony_ci    s->br_x_range.quant = MM_PER_UNIT_FIX;
3032141cc406Sopenharmony_ci
3033141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_BR_X;
3034141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_BR_X;
3035141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_BR_X;
3036141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3037141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3038141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3039141cc406Sopenharmony_ci    opt->constraint.range = &(s->br_x_range);
3040141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3041141cc406Sopenharmony_ci  }
3042141cc406Sopenharmony_ci
3043141cc406Sopenharmony_ci  /* bottom-right y */
3044141cc406Sopenharmony_ci  if(option==OPT_BR_Y){
3045141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
3046141cc406Sopenharmony_ci    /* must be converted to MM for sane */
3047141cc406Sopenharmony_ci    s->br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y);
3048141cc406Sopenharmony_ci    s->br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s));
3049141cc406Sopenharmony_ci    s->br_y_range.quant = MM_PER_UNIT_FIX;
3050141cc406Sopenharmony_ci
3051141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN_BR_Y;
3052141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN_BR_Y;
3053141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN_BR_Y;
3054141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3055141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3056141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3057141cc406Sopenharmony_ci    opt->constraint.range = &(s->br_y_range);
3058141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3059141cc406Sopenharmony_ci  }
3060141cc406Sopenharmony_ci
3061141cc406Sopenharmony_ci  /* page width */
3062141cc406Sopenharmony_ci  if(option==OPT_PAGE_WIDTH){
3063141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
3064141cc406Sopenharmony_ci    /* must be converted to MM for sane */
3065141cc406Sopenharmony_ci    s->paper_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x);
3066141cc406Sopenharmony_ci    s->paper_x_range.max = SCANNER_UNIT_TO_FIXED_MM(s->max_x);
3067141cc406Sopenharmony_ci    s->paper_x_range.quant = MM_PER_UNIT_FIX;
3068141cc406Sopenharmony_ci
3069141cc406Sopenharmony_ci    opt->name = SANE_NAME_PAGE_WIDTH;
3070141cc406Sopenharmony_ci    opt->title = SANE_TITLE_PAGE_WIDTH;
3071141cc406Sopenharmony_ci    opt->desc = SANE_DESC_PAGE_WIDTH;
3072141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3073141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3074141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3075141cc406Sopenharmony_ci    opt->constraint.range = &s->paper_x_range;
3076141cc406Sopenharmony_ci
3077141cc406Sopenharmony_ci    if(s->has_adf || s->has_return_path){
3078141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3079141cc406Sopenharmony_ci      if(s->source == SOURCE_FLATBED){
3080141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3081141cc406Sopenharmony_ci      }
3082141cc406Sopenharmony_ci    }
3083141cc406Sopenharmony_ci    else{
3084141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3085141cc406Sopenharmony_ci    }
3086141cc406Sopenharmony_ci  }
3087141cc406Sopenharmony_ci
3088141cc406Sopenharmony_ci  /* page height */
3089141cc406Sopenharmony_ci  if(option==OPT_PAGE_HEIGHT){
3090141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
3091141cc406Sopenharmony_ci    /* must be converted to MM for sane */
3092141cc406Sopenharmony_ci    s->paper_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y);
3093141cc406Sopenharmony_ci    s->paper_y_range.max = SCANNER_UNIT_TO_FIXED_MM(s->max_y);
3094141cc406Sopenharmony_ci    s->paper_y_range.quant = MM_PER_UNIT_FIX;
3095141cc406Sopenharmony_ci
3096141cc406Sopenharmony_ci    opt->name = SANE_NAME_PAGE_HEIGHT;
3097141cc406Sopenharmony_ci    opt->title = SANE_TITLE_PAGE_HEIGHT;
3098141cc406Sopenharmony_ci    opt->desc = SANE_DESC_PAGE_HEIGHT;
3099141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3100141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
3101141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3102141cc406Sopenharmony_ci    opt->constraint.range = &s->paper_y_range;
3103141cc406Sopenharmony_ci
3104141cc406Sopenharmony_ci    if(s->has_adf || s->has_return_path){
3105141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3106141cc406Sopenharmony_ci      if(s->source == SOURCE_FLATBED){
3107141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3108141cc406Sopenharmony_ci      }
3109141cc406Sopenharmony_ci    }
3110141cc406Sopenharmony_ci    else{
3111141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3112141cc406Sopenharmony_ci    }
3113141cc406Sopenharmony_ci  }
3114141cc406Sopenharmony_ci
3115141cc406Sopenharmony_ci  /* "Enhancement" group ------------------------------------------------- */
3116141cc406Sopenharmony_ci  if(option==OPT_ENHANCEMENT_GROUP){
3117141cc406Sopenharmony_ci    opt->name = SANE_NAME_ENHANCEMENT;
3118141cc406Sopenharmony_ci    opt->title = SANE_TITLE_ENHANCEMENT;
3119141cc406Sopenharmony_ci    opt->desc = SANE_DESC_ENHANCEMENT;
3120141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
3121141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3122141cc406Sopenharmony_ci  }
3123141cc406Sopenharmony_ci
3124141cc406Sopenharmony_ci  /* brightness */
3125141cc406Sopenharmony_ci  if(option==OPT_BRIGHTNESS){
3126141cc406Sopenharmony_ci    opt->name = SANE_NAME_BRIGHTNESS;
3127141cc406Sopenharmony_ci    opt->title = SANE_TITLE_BRIGHTNESS;
3128141cc406Sopenharmony_ci    opt->desc = SANE_DESC_BRIGHTNESS;
3129141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3130141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3131141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3132141cc406Sopenharmony_ci    opt->constraint.range = &s->brightness_range;
3133141cc406Sopenharmony_ci    s->brightness_range.quant=1;
3134141cc406Sopenharmony_ci
3135141cc406Sopenharmony_ci    /* some have hardware brightness (always 0 to 255?) */
3136141cc406Sopenharmony_ci    /* some use LUT or GT (-127 to +127)*/
3137141cc406Sopenharmony_ci    if (s->brightness_steps || s->num_download_gamma){
3138141cc406Sopenharmony_ci      s->brightness_range.min=-127;
3139141cc406Sopenharmony_ci      s->brightness_range.max=127;
3140141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3141141cc406Sopenharmony_ci    }
3142141cc406Sopenharmony_ci    else{
3143141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3144141cc406Sopenharmony_ci    }
3145141cc406Sopenharmony_ci  }
3146141cc406Sopenharmony_ci
3147141cc406Sopenharmony_ci  /* contrast */
3148141cc406Sopenharmony_ci  if(option==OPT_CONTRAST){
3149141cc406Sopenharmony_ci    opt->name = SANE_NAME_CONTRAST;
3150141cc406Sopenharmony_ci    opt->title = SANE_TITLE_CONTRAST;
3151141cc406Sopenharmony_ci    opt->desc = SANE_DESC_CONTRAST;
3152141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3153141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3154141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3155141cc406Sopenharmony_ci    opt->constraint.range = &s->contrast_range;
3156141cc406Sopenharmony_ci    s->contrast_range.quant=1;
3157141cc406Sopenharmony_ci
3158141cc406Sopenharmony_ci    /* some have hardware contrast (always 0 to 255?) */
3159141cc406Sopenharmony_ci    /* some use LUT or GT (-127 to +127)*/
3160141cc406Sopenharmony_ci    if (s->contrast_steps || s->num_download_gamma){
3161141cc406Sopenharmony_ci      s->contrast_range.min=-127;
3162141cc406Sopenharmony_ci      s->contrast_range.max=127;
3163141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3164141cc406Sopenharmony_ci    }
3165141cc406Sopenharmony_ci    else {
3166141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3167141cc406Sopenharmony_ci    }
3168141cc406Sopenharmony_ci  }
3169141cc406Sopenharmony_ci
3170141cc406Sopenharmony_ci  /* gamma */
3171141cc406Sopenharmony_ci  if(option==OPT_GAMMA){
3172141cc406Sopenharmony_ci    opt->name = "gamma";
3173141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Gamma function exponent");
3174141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Changes intensity of midtones");
3175141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
3176141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3177141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3178141cc406Sopenharmony_ci    opt->constraint.range = &s->gamma_range;
3179141cc406Sopenharmony_ci
3180141cc406Sopenharmony_ci    /* value ranges from .3 to 5, should be log scale? */
3181141cc406Sopenharmony_ci    s->gamma_range.quant=SANE_FIX(0.01);
3182141cc406Sopenharmony_ci    s->gamma_range.min=SANE_FIX(0.3);
3183141cc406Sopenharmony_ci    s->gamma_range.max=SANE_FIX(5);
3184141cc406Sopenharmony_ci
3185141cc406Sopenharmony_ci    /* scanner has gamma via LUT or GT */
3186141cc406Sopenharmony_ci    /*if (s->num_download_gamma){
3187141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3188141cc406Sopenharmony_ci    }
3189141cc406Sopenharmony_ci    else {
3190141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3191141cc406Sopenharmony_ci    }*/
3192141cc406Sopenharmony_ci
3193141cc406Sopenharmony_ci    opt->cap = SANE_CAP_INACTIVE;
3194141cc406Sopenharmony_ci  }
3195141cc406Sopenharmony_ci
3196141cc406Sopenharmony_ci  /*threshold*/
3197141cc406Sopenharmony_ci  if(option==OPT_THRESHOLD){
3198141cc406Sopenharmony_ci    opt->name = SANE_NAME_THRESHOLD;
3199141cc406Sopenharmony_ci    opt->title = SANE_TITLE_THRESHOLD;
3200141cc406Sopenharmony_ci    opt->desc = SANE_DESC_THRESHOLD;
3201141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3202141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3203141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3204141cc406Sopenharmony_ci    opt->constraint.range = &s->threshold_range;
3205141cc406Sopenharmony_ci    s->threshold_range.min=0;
3206141cc406Sopenharmony_ci    s->threshold_range.max=s->threshold_steps;
3207141cc406Sopenharmony_ci    s->threshold_range.quant=1;
3208141cc406Sopenharmony_ci
3209141cc406Sopenharmony_ci    if (s->threshold_steps){
3210141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3211141cc406Sopenharmony_ci      if(s->u_mode != MODE_LINEART){
3212141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3213141cc406Sopenharmony_ci      }
3214141cc406Sopenharmony_ci    }
3215141cc406Sopenharmony_ci    else {
3216141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3217141cc406Sopenharmony_ci    }
3218141cc406Sopenharmony_ci  }
3219141cc406Sopenharmony_ci
3220141cc406Sopenharmony_ci  /* =============== common ipc params ================================ */
3221141cc406Sopenharmony_ci  if(option==OPT_RIF){
3222141cc406Sopenharmony_ci    opt->name = "rif";
3223141cc406Sopenharmony_ci    opt->title = SANE_I18N ("RIF");
3224141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Reverse image format");
3225141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3226141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3227141cc406Sopenharmony_ci    if (s->has_rif)
3228141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3229141cc406Sopenharmony_ci    else
3230141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3231141cc406Sopenharmony_ci  }
3232141cc406Sopenharmony_ci
3233141cc406Sopenharmony_ci  if(option==OPT_HT_TYPE){
3234141cc406Sopenharmony_ci    i=0;
3235141cc406Sopenharmony_ci    s->ht_type_list[i++]=STRING_DEFAULT;
3236141cc406Sopenharmony_ci    s->ht_type_list[i++]=STRING_DITHER;
3237141cc406Sopenharmony_ci    s->ht_type_list[i++]=STRING_DIFFUSION;
3238141cc406Sopenharmony_ci    s->ht_type_list[i]=NULL;
3239141cc406Sopenharmony_ci
3240141cc406Sopenharmony_ci    opt->name = "ht-type";
3241141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Halftone type");
3242141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Control type of halftone filter");
3243141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3244141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3245141cc406Sopenharmony_ci
3246141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3247141cc406Sopenharmony_ci    opt->constraint.string_list = s->ht_type_list;
3248141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3249141cc406Sopenharmony_ci
3250141cc406Sopenharmony_ci    if(s->has_diffusion){
3251141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3252141cc406Sopenharmony_ci      if(s->s_mode != MODE_HALFTONE){
3253141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3254141cc406Sopenharmony_ci      }
3255141cc406Sopenharmony_ci    }
3256141cc406Sopenharmony_ci    else
3257141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3258141cc406Sopenharmony_ci  }
3259141cc406Sopenharmony_ci
3260141cc406Sopenharmony_ci  if(option==OPT_HT_PATTERN){
3261141cc406Sopenharmony_ci    opt->name = "ht-pattern";
3262141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Halftone pattern");
3263141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Control pattern of halftone filter");
3264141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3265141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3266141cc406Sopenharmony_ci
3267141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3268141cc406Sopenharmony_ci    opt->constraint.range = &s->ht_pattern_range;
3269141cc406Sopenharmony_ci    s->ht_pattern_range.min=0;
3270141cc406Sopenharmony_ci    s->ht_pattern_range.max=s->num_internal_dither - 1;
3271141cc406Sopenharmony_ci    s->ht_pattern_range.quant=1;
3272141cc406Sopenharmony_ci
3273141cc406Sopenharmony_ci    if (s->num_internal_dither){
3274141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3275141cc406Sopenharmony_ci      if(s->s_mode != MODE_HALFTONE){
3276141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3277141cc406Sopenharmony_ci      }
3278141cc406Sopenharmony_ci    }
3279141cc406Sopenharmony_ci    else
3280141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3281141cc406Sopenharmony_ci  }
3282141cc406Sopenharmony_ci
3283141cc406Sopenharmony_ci  if(option==OPT_OUTLINE){
3284141cc406Sopenharmony_ci    opt->name = "outline";
3285141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Outline");
3286141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Perform outline extraction");
3287141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3288141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3289141cc406Sopenharmony_ci    if (s->has_outline)
3290141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3291141cc406Sopenharmony_ci    else
3292141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3293141cc406Sopenharmony_ci  }
3294141cc406Sopenharmony_ci
3295141cc406Sopenharmony_ci  if(option==OPT_EMPHASIS){
3296141cc406Sopenharmony_ci    opt->name = "emphasis";
3297141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Emphasis");
3298141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Negative to smooth or positive to sharpen image");
3299141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3300141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3301141cc406Sopenharmony_ci
3302141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3303141cc406Sopenharmony_ci    opt->constraint.range = &s->emphasis_range;
3304141cc406Sopenharmony_ci    s->emphasis_range.min=-128;
3305141cc406Sopenharmony_ci    s->emphasis_range.max=127;
3306141cc406Sopenharmony_ci    s->emphasis_range.quant=1;
3307141cc406Sopenharmony_ci
3308141cc406Sopenharmony_ci    if (s->has_emphasis)
3309141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3310141cc406Sopenharmony_ci    else
3311141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3312141cc406Sopenharmony_ci  }
3313141cc406Sopenharmony_ci
3314141cc406Sopenharmony_ci  if(option==OPT_SEPARATION){
3315141cc406Sopenharmony_ci    opt->name = "separation";
3316141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Separation");
3317141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable automatic separation of image and text");
3318141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3319141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3320141cc406Sopenharmony_ci    if (s->has_autosep)
3321141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3322141cc406Sopenharmony_ci    else
3323141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3324141cc406Sopenharmony_ci  }
3325141cc406Sopenharmony_ci
3326141cc406Sopenharmony_ci  if(option==OPT_MIRRORING){
3327141cc406Sopenharmony_ci    opt->name = "mirroring";
3328141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Mirroring");
3329141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Reflect output image horizontally");
3330141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3331141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3332141cc406Sopenharmony_ci    if (s->has_mirroring)
3333141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3334141cc406Sopenharmony_ci    else
3335141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3336141cc406Sopenharmony_ci  }
3337141cc406Sopenharmony_ci
3338141cc406Sopenharmony_ci  if(option==OPT_WL_FOLLOW){
3339141cc406Sopenharmony_ci    i=0;
3340141cc406Sopenharmony_ci    s->wl_follow_list[i++]=STRING_DEFAULT;
3341141cc406Sopenharmony_ci    s->wl_follow_list[i++]=STRING_ON;
3342141cc406Sopenharmony_ci    s->wl_follow_list[i++]=STRING_OFF;
3343141cc406Sopenharmony_ci    s->wl_follow_list[i]=NULL;
3344141cc406Sopenharmony_ci
3345141cc406Sopenharmony_ci    opt->name = "wl-follow";
3346141cc406Sopenharmony_ci    opt->title = SANE_I18N ("White level follower");
3347141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Control white level follower");
3348141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3349141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3350141cc406Sopenharmony_ci
3351141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3352141cc406Sopenharmony_ci    opt->constraint.string_list = s->wl_follow_list;
3353141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3354141cc406Sopenharmony_ci
3355141cc406Sopenharmony_ci    if (s->has_wl_follow)
3356141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3357141cc406Sopenharmony_ci    else
3358141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3359141cc406Sopenharmony_ci  }
3360141cc406Sopenharmony_ci
3361141cc406Sopenharmony_ci  /* =============== DTC params ================================ */
3362141cc406Sopenharmony_ci  /* enabled when in dtc mode (manually or by default) */
3363141cc406Sopenharmony_ci  if(option==OPT_BP_FILTER){
3364141cc406Sopenharmony_ci    opt->name = "bp-filter";
3365141cc406Sopenharmony_ci    opt->title = SANE_I18N ("BP filter");
3366141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Improves quality of high resolution ball-point pen text");
3367141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3368141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3369141cc406Sopenharmony_ci
3370141cc406Sopenharmony_ci    if ( s->has_dtc ){
3371141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3372141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3373141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3374141cc406Sopenharmony_ci      }
3375141cc406Sopenharmony_ci    }
3376141cc406Sopenharmony_ci    else
3377141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3378141cc406Sopenharmony_ci  }
3379141cc406Sopenharmony_ci
3380141cc406Sopenharmony_ci  if(option==OPT_SMOOTHING){
3381141cc406Sopenharmony_ci    opt->name = "smoothing";
3382141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Smoothing");
3383141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable smoothing for improved OCR");
3384141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3385141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3386141cc406Sopenharmony_ci
3387141cc406Sopenharmony_ci    if ( s->has_dtc ){
3388141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3389141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3390141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3391141cc406Sopenharmony_ci      }
3392141cc406Sopenharmony_ci    }
3393141cc406Sopenharmony_ci    else
3394141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3395141cc406Sopenharmony_ci  }
3396141cc406Sopenharmony_ci
3397141cc406Sopenharmony_ci  if(option==OPT_GAMMA_CURVE){
3398141cc406Sopenharmony_ci    opt->name = "gamma-curve";
3399141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Gamma curve");
3400141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Gamma curve, from light to dark, but upper two may not work");
3401141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3402141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3403141cc406Sopenharmony_ci
3404141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3405141cc406Sopenharmony_ci    opt->constraint.range = &s->gamma_curve_range;
3406141cc406Sopenharmony_ci    s->gamma_curve_range.min=0;
3407141cc406Sopenharmony_ci    s->gamma_curve_range.max=3;
3408141cc406Sopenharmony_ci    s->gamma_curve_range.quant=1;
3409141cc406Sopenharmony_ci
3410141cc406Sopenharmony_ci    if ( s->has_dtc ){
3411141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3412141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3413141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3414141cc406Sopenharmony_ci      }
3415141cc406Sopenharmony_ci    }
3416141cc406Sopenharmony_ci    else
3417141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3418141cc406Sopenharmony_ci  }
3419141cc406Sopenharmony_ci
3420141cc406Sopenharmony_ci  if(option==OPT_THRESHOLD_CURVE){
3421141cc406Sopenharmony_ci    opt->name = "threshold-curve";
3422141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Threshold curve");
3423141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Threshold curve, from light to dark, but upper two may not be linear");
3424141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3425141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3426141cc406Sopenharmony_ci
3427141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3428141cc406Sopenharmony_ci    opt->constraint.range = &s->threshold_curve_range;
3429141cc406Sopenharmony_ci    s->threshold_curve_range.min=0;
3430141cc406Sopenharmony_ci    s->threshold_curve_range.max=7;
3431141cc406Sopenharmony_ci    s->threshold_curve_range.quant=1;
3432141cc406Sopenharmony_ci
3433141cc406Sopenharmony_ci    if ( s->has_dtc ){
3434141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3435141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3436141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3437141cc406Sopenharmony_ci      }
3438141cc406Sopenharmony_ci    }
3439141cc406Sopenharmony_ci    else
3440141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3441141cc406Sopenharmony_ci  }
3442141cc406Sopenharmony_ci
3443141cc406Sopenharmony_ci  if(option==OPT_THRESHOLD_WHITE){
3444141cc406Sopenharmony_ci    opt->name = "threshold-white";
3445141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Threshold white");
3446141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Set pixels equal to threshold to white instead of black");
3447141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3448141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3449141cc406Sopenharmony_ci
3450141cc406Sopenharmony_ci    if ( s->has_dtc ){
3451141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3452141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3453141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3454141cc406Sopenharmony_ci      }
3455141cc406Sopenharmony_ci    }
3456141cc406Sopenharmony_ci    else
3457141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3458141cc406Sopenharmony_ci  }
3459141cc406Sopenharmony_ci
3460141cc406Sopenharmony_ci  if(option==OPT_NOISE_REMOVAL){
3461141cc406Sopenharmony_ci    opt->name = "noise-removal";
3462141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Noise removal");
3463141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Noise removal");
3464141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3465141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3466141cc406Sopenharmony_ci
3467141cc406Sopenharmony_ci    if ( s->has_dtc ){
3468141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3469141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_SDTC){
3470141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3471141cc406Sopenharmony_ci      }
3472141cc406Sopenharmony_ci    }
3473141cc406Sopenharmony_ci    else
3474141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3475141cc406Sopenharmony_ci  }
3476141cc406Sopenharmony_ci
3477141cc406Sopenharmony_ci  if(option==OPT_MATRIX_5){
3478141cc406Sopenharmony_ci    opt->name = "matrix-5x5";
3479141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Matrix 5x5");
3480141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Remove 5 pixel square noise");
3481141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3482141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3483141cc406Sopenharmony_ci
3484141cc406Sopenharmony_ci    if ( s->has_dtc ){
3485141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3486141cc406Sopenharmony_ci      if(!s->noise_removal){
3487141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3488141cc406Sopenharmony_ci      }
3489141cc406Sopenharmony_ci    }
3490141cc406Sopenharmony_ci    else
3491141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3492141cc406Sopenharmony_ci  }
3493141cc406Sopenharmony_ci
3494141cc406Sopenharmony_ci  if(option==OPT_MATRIX_4){
3495141cc406Sopenharmony_ci    opt->name = "matrix-4x4";
3496141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Matrix 4x4");
3497141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Remove 4 pixel square noise");
3498141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3499141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3500141cc406Sopenharmony_ci
3501141cc406Sopenharmony_ci    if ( s->has_dtc ){
3502141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3503141cc406Sopenharmony_ci      if(!s->noise_removal){
3504141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3505141cc406Sopenharmony_ci      }
3506141cc406Sopenharmony_ci    }
3507141cc406Sopenharmony_ci    else
3508141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3509141cc406Sopenharmony_ci  }
3510141cc406Sopenharmony_ci
3511141cc406Sopenharmony_ci  if(option==OPT_MATRIX_3){
3512141cc406Sopenharmony_ci    opt->name = "matrix-3x3";
3513141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Matrix 3x3");
3514141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Remove 3 pixel square noise");
3515141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3516141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3517141cc406Sopenharmony_ci
3518141cc406Sopenharmony_ci    if ( s->has_dtc ){
3519141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3520141cc406Sopenharmony_ci      if(!s->noise_removal){
3521141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3522141cc406Sopenharmony_ci      }
3523141cc406Sopenharmony_ci    }
3524141cc406Sopenharmony_ci    else
3525141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3526141cc406Sopenharmony_ci  }
3527141cc406Sopenharmony_ci
3528141cc406Sopenharmony_ci  if(option==OPT_MATRIX_2){
3529141cc406Sopenharmony_ci    opt->name = "matrix-2x2";
3530141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Matrix 2x2");
3531141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Remove 2 pixel square noise");
3532141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3533141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3534141cc406Sopenharmony_ci
3535141cc406Sopenharmony_ci    if ( s->has_dtc ){
3536141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3537141cc406Sopenharmony_ci      if(!s->noise_removal){
3538141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3539141cc406Sopenharmony_ci      }
3540141cc406Sopenharmony_ci    }
3541141cc406Sopenharmony_ci    else
3542141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3543141cc406Sopenharmony_ci  }
3544141cc406Sopenharmony_ci
3545141cc406Sopenharmony_ci  /* =============== SDTC param ================================ */
3546141cc406Sopenharmony_ci  /* enabled when in sdtc mode (manually or by default) */
3547141cc406Sopenharmony_ci  /* called variance with ipc2, sensitivity with ipc3 */
3548141cc406Sopenharmony_ci  if(option==OPT_VARIANCE){
3549141cc406Sopenharmony_ci    opt->name = "variance";
3550141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Variance");
3551141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Set SDTC variance rate (sensitivity), 0 equals 127");
3552141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3553141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3554141cc406Sopenharmony_ci
3555141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3556141cc406Sopenharmony_ci    opt->constraint.range = &s->variance_range;
3557141cc406Sopenharmony_ci    s->variance_range.min=0;
3558141cc406Sopenharmony_ci    s->variance_range.max=255;
3559141cc406Sopenharmony_ci    s->variance_range.quant=1;
3560141cc406Sopenharmony_ci
3561141cc406Sopenharmony_ci    if ( s->has_sdtc ){
3562141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3563141cc406Sopenharmony_ci      if(get_ipc_mode(s) == WD_ipc_DTC){
3564141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3565141cc406Sopenharmony_ci      }
3566141cc406Sopenharmony_ci    }
3567141cc406Sopenharmony_ci    else
3568141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3569141cc406Sopenharmony_ci  }
3570141cc406Sopenharmony_ci
3571141cc406Sopenharmony_ci  /* "Advanced" group ------------------------------------------------------ */
3572141cc406Sopenharmony_ci  if(option==OPT_ADVANCED_GROUP){
3573141cc406Sopenharmony_ci    opt->name = SANE_NAME_ADVANCED;
3574141cc406Sopenharmony_ci    opt->title = SANE_TITLE_ADVANCED;
3575141cc406Sopenharmony_ci    opt->desc = SANE_DESC_ADVANCED;
3576141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
3577141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3578141cc406Sopenharmony_ci  }
3579141cc406Sopenharmony_ci
3580141cc406Sopenharmony_ci  /*automatic width detection */
3581141cc406Sopenharmony_ci  if(option==OPT_AWD){
3582141cc406Sopenharmony_ci
3583141cc406Sopenharmony_ci    opt->name = "awd";
3584141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Auto width detection");
3585141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Scanner detects paper sides. May reduce scanning speed.");
3586141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3587141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3588141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3589141cc406Sopenharmony_ci
3590141cc406Sopenharmony_ci    /* this option is useless by itself? */
3591141cc406Sopenharmony_ci    if (0 && s->has_MS_auto && s->has_hybrid_crop_deskew){
3592141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3593141cc406Sopenharmony_ci    }
3594141cc406Sopenharmony_ci    else
3595141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3596141cc406Sopenharmony_ci  }
3597141cc406Sopenharmony_ci
3598141cc406Sopenharmony_ci  /*automatic length detection */
3599141cc406Sopenharmony_ci  if(option==OPT_ALD){
3600141cc406Sopenharmony_ci
3601141cc406Sopenharmony_ci    opt->name = "ald";
3602141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Auto length detection");
3603141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Scanner detects paper lower edge. May confuse some frontends.");
3604141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3605141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3606141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3607141cc406Sopenharmony_ci
3608141cc406Sopenharmony_ci    if (s->has_MS_auto){
3609141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3610141cc406Sopenharmony_ci    }
3611141cc406Sopenharmony_ci    else
3612141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3613141cc406Sopenharmony_ci  }
3614141cc406Sopenharmony_ci
3615141cc406Sopenharmony_ci  /*image compression*/
3616141cc406Sopenharmony_ci  if(option==OPT_COMPRESS){
3617141cc406Sopenharmony_ci    i=0;
3618141cc406Sopenharmony_ci    s->compress_list[i++]=STRING_NONE;
3619141cc406Sopenharmony_ci
3620141cc406Sopenharmony_ci    if(s->has_comp_JPG1){
3621141cc406Sopenharmony_ci#ifndef SANE_JPEG_DISABLED
3622141cc406Sopenharmony_ci      s->compress_list[i++]=STRING_JPEG;
3623141cc406Sopenharmony_ci#endif
3624141cc406Sopenharmony_ci    }
3625141cc406Sopenharmony_ci
3626141cc406Sopenharmony_ci    s->compress_list[i]=NULL;
3627141cc406Sopenharmony_ci
3628141cc406Sopenharmony_ci    opt->name = "compression";
3629141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Compression");
3630141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable compressed data. May crash your front-end program");
3631141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3632141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3633141cc406Sopenharmony_ci    opt->constraint.string_list = s->compress_list;
3634141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3635141cc406Sopenharmony_ci
3636141cc406Sopenharmony_ci    if (i > 1){
3637141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3638141cc406Sopenharmony_ci      if ( must_downsample(s) || s->s_mode < MODE_GRAYSCALE ){
3639141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3640141cc406Sopenharmony_ci      }
3641141cc406Sopenharmony_ci    }
3642141cc406Sopenharmony_ci    else
3643141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3644141cc406Sopenharmony_ci  }
3645141cc406Sopenharmony_ci
3646141cc406Sopenharmony_ci  /*image compression arg*/
3647141cc406Sopenharmony_ci  if(option==OPT_COMPRESS_ARG){
3648141cc406Sopenharmony_ci
3649141cc406Sopenharmony_ci    opt->name = "compression-arg";
3650141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Compression argument");
3651141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Level of JPEG compression. 1 is small file, 7 is large file. 0 (default) is same as 4");
3652141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3653141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3654141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3655141cc406Sopenharmony_ci    opt->constraint.range = &s->compress_arg_range;
3656141cc406Sopenharmony_ci    s->compress_arg_range.quant=1;
3657141cc406Sopenharmony_ci
3658141cc406Sopenharmony_ci    if(s->has_comp_JPG1){
3659141cc406Sopenharmony_ci      s->compress_arg_range.min=0;
3660141cc406Sopenharmony_ci      s->compress_arg_range.max=7;
3661141cc406Sopenharmony_ci#ifndef SANE_JPEG_DISABLED
3662141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
3663141cc406Sopenharmony_ci#endif
3664141cc406Sopenharmony_ci
3665141cc406Sopenharmony_ci      if(s->compress != COMP_JPEG){
3666141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3667141cc406Sopenharmony_ci      }
3668141cc406Sopenharmony_ci    }
3669141cc406Sopenharmony_ci    else
3670141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3671141cc406Sopenharmony_ci  }
3672141cc406Sopenharmony_ci
3673141cc406Sopenharmony_ci  /*double feed detection*/
3674141cc406Sopenharmony_ci  if(option==OPT_DF_ACTION){
3675141cc406Sopenharmony_ci    s->df_action_list[0] = STRING_DEFAULT;
3676141cc406Sopenharmony_ci    s->df_action_list[1] = STRING_CONTINUE;
3677141cc406Sopenharmony_ci    s->df_action_list[2] = STRING_STOP;
3678141cc406Sopenharmony_ci    s->df_action_list[3] = NULL;
3679141cc406Sopenharmony_ci
3680141cc406Sopenharmony_ci    opt->name = "df-action";
3681141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF action");
3682141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Action following double feed error");
3683141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3684141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3685141cc406Sopenharmony_ci    opt->constraint.string_list = s->df_action_list;
3686141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3687141cc406Sopenharmony_ci
3688141cc406Sopenharmony_ci    if (s->has_MS_df)
3689141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3690141cc406Sopenharmony_ci    else
3691141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3692141cc406Sopenharmony_ci  }
3693141cc406Sopenharmony_ci
3694141cc406Sopenharmony_ci  /*double feed by skew*/
3695141cc406Sopenharmony_ci  if(option==OPT_DF_SKEW){
3696141cc406Sopenharmony_ci
3697141cc406Sopenharmony_ci    opt->name = "df-skew";
3698141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF skew");
3699141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable double feed error due to skew");
3700141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3701141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3702141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3703141cc406Sopenharmony_ci
3704141cc406Sopenharmony_ci    if (s->has_MS_df){
3705141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3706141cc406Sopenharmony_ci     if(!s->df_action)
3707141cc406Sopenharmony_ci       opt->cap |= SANE_CAP_INACTIVE;
3708141cc406Sopenharmony_ci    }
3709141cc406Sopenharmony_ci    else
3710141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3711141cc406Sopenharmony_ci  }
3712141cc406Sopenharmony_ci
3713141cc406Sopenharmony_ci  /*double feed by thickness */
3714141cc406Sopenharmony_ci  if(option==OPT_DF_THICKNESS){
3715141cc406Sopenharmony_ci
3716141cc406Sopenharmony_ci    opt->name = "df-thickness";
3717141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF thickness");
3718141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable double feed error due to paper thickness");
3719141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3720141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3721141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3722141cc406Sopenharmony_ci
3723141cc406Sopenharmony_ci    if (s->has_MS_df){
3724141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3725141cc406Sopenharmony_ci     if(!s->df_action)
3726141cc406Sopenharmony_ci       opt->cap |= SANE_CAP_INACTIVE;
3727141cc406Sopenharmony_ci    }
3728141cc406Sopenharmony_ci    else
3729141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3730141cc406Sopenharmony_ci  }
3731141cc406Sopenharmony_ci
3732141cc406Sopenharmony_ci  /*double feed by length*/
3733141cc406Sopenharmony_ci  if(option==OPT_DF_LENGTH){
3734141cc406Sopenharmony_ci
3735141cc406Sopenharmony_ci    opt->name = "df-length";
3736141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF length");
3737141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable double feed error due to paper length");
3738141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
3739141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3740141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
3741141cc406Sopenharmony_ci
3742141cc406Sopenharmony_ci    if (s->has_MS_df){
3743141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3744141cc406Sopenharmony_ci     if(!s->df_action)
3745141cc406Sopenharmony_ci       opt->cap |= SANE_CAP_INACTIVE;
3746141cc406Sopenharmony_ci    }
3747141cc406Sopenharmony_ci    else
3748141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3749141cc406Sopenharmony_ci  }
3750141cc406Sopenharmony_ci
3751141cc406Sopenharmony_ci  /*double feed length difference*/
3752141cc406Sopenharmony_ci  if(option==OPT_DF_DIFF){
3753141cc406Sopenharmony_ci    s->df_diff_list[0] = STRING_DEFAULT;
3754141cc406Sopenharmony_ci    s->df_diff_list[1] = STRING_10MM;
3755141cc406Sopenharmony_ci    s->df_diff_list[2] = STRING_15MM;
3756141cc406Sopenharmony_ci    s->df_diff_list[3] = STRING_20MM;
3757141cc406Sopenharmony_ci    s->df_diff_list[4] = NULL;
3758141cc406Sopenharmony_ci
3759141cc406Sopenharmony_ci    opt->name = "df-diff";
3760141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF length difference");
3761141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Difference in page length to trigger double feed error");
3762141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3763141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3764141cc406Sopenharmony_ci    opt->constraint.string_list = s->df_diff_list;
3765141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3766141cc406Sopenharmony_ci
3767141cc406Sopenharmony_ci    if (s->has_MS_df){
3768141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3769141cc406Sopenharmony_ci     if(!s->df_action || !s->df_diff)
3770141cc406Sopenharmony_ci       opt->cap |= SANE_CAP_INACTIVE;
3771141cc406Sopenharmony_ci    }
3772141cc406Sopenharmony_ci    else
3773141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
3774141cc406Sopenharmony_ci  }
3775141cc406Sopenharmony_ci
3776141cc406Sopenharmony_ci  /*df_recovery*/
3777141cc406Sopenharmony_ci  if(option==OPT_DF_RECOVERY){
3778141cc406Sopenharmony_ci    s->df_recovery_list[0] = STRING_DEFAULT;
3779141cc406Sopenharmony_ci    s->df_recovery_list[1] = STRING_OFF;
3780141cc406Sopenharmony_ci    s->df_recovery_list[2] = STRING_ON;
3781141cc406Sopenharmony_ci    s->df_recovery_list[3] = NULL;
3782141cc406Sopenharmony_ci
3783141cc406Sopenharmony_ci    opt->name = "df-recovery";
3784141cc406Sopenharmony_ci    opt->title = SANE_I18N ("DF recovery mode");
3785141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to reverse feed on paper jam");
3786141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3787141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3788141cc406Sopenharmony_ci    opt->constraint.string_list = s->df_recovery_list;
3789141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3790141cc406Sopenharmony_ci    if (s->has_MS_df && s->has_df_recovery)
3791141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3792141cc406Sopenharmony_ci    else
3793141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3794141cc406Sopenharmony_ci  }
3795141cc406Sopenharmony_ci
3796141cc406Sopenharmony_ci  /*paper_protect*/
3797141cc406Sopenharmony_ci  if(option==OPT_PAPER_PROTECT){
3798141cc406Sopenharmony_ci    s->paper_protect_list[0] = STRING_DEFAULT;
3799141cc406Sopenharmony_ci    s->paper_protect_list[1] = STRING_OFF;
3800141cc406Sopenharmony_ci    s->paper_protect_list[2] = STRING_ON;
3801141cc406Sopenharmony_ci    s->paper_protect_list[3] = NULL;
3802141cc406Sopenharmony_ci
3803141cc406Sopenharmony_ci    opt->name = "paper-protect";
3804141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Paper protection");
3805141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF");
3806141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3807141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3808141cc406Sopenharmony_ci    opt->constraint.string_list = s->paper_protect_list;
3809141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3810141cc406Sopenharmony_ci    if (s->has_MS_df && s->has_paper_protect)
3811141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3812141cc406Sopenharmony_ci    else
3813141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3814141cc406Sopenharmony_ci  }
3815141cc406Sopenharmony_ci
3816141cc406Sopenharmony_ci  /*adv_paper_prot*/
3817141cc406Sopenharmony_ci  if(option==OPT_ADV_PAPER_PROT){
3818141cc406Sopenharmony_ci    s->adv_paper_prot_list[0] = STRING_DEFAULT;
3819141cc406Sopenharmony_ci    s->adv_paper_prot_list[1] = STRING_OFF;
3820141cc406Sopenharmony_ci    s->adv_paper_prot_list[2] = STRING_ON;
3821141cc406Sopenharmony_ci    s->adv_paper_prot_list[3] = NULL;
3822141cc406Sopenharmony_ci
3823141cc406Sopenharmony_ci    opt->name = "adv-paper-protect";
3824141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Advanced paper protection");
3825141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF using improved sensors");
3826141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3827141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3828141cc406Sopenharmony_ci    opt->constraint.string_list = s->adv_paper_prot_list;
3829141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3830141cc406Sopenharmony_ci    if (s->has_MS_df && s->has_adv_paper_prot)
3831141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3832141cc406Sopenharmony_ci    else
3833141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3834141cc406Sopenharmony_ci  }
3835141cc406Sopenharmony_ci
3836141cc406Sopenharmony_ci  /*staple detection*/
3837141cc406Sopenharmony_ci  if(option==OPT_STAPLE_DETECT){
3838141cc406Sopenharmony_ci    s->staple_detect_list[0] = STRING_DEFAULT;
3839141cc406Sopenharmony_ci    s->staple_detect_list[1] = STRING_OFF;
3840141cc406Sopenharmony_ci    s->staple_detect_list[2] = STRING_ON;
3841141cc406Sopenharmony_ci    s->staple_detect_list[3] = NULL;
3842141cc406Sopenharmony_ci
3843141cc406Sopenharmony_ci    opt->name = "staple-detect";
3844141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Staple detection");
3845141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to detect jams in the ADF caused by staples");
3846141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3847141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3848141cc406Sopenharmony_ci    opt->constraint.string_list = s->staple_detect_list;
3849141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3850141cc406Sopenharmony_ci    if (s->has_MS_df && s->has_staple_detect)
3851141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3852141cc406Sopenharmony_ci    else
3853141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3854141cc406Sopenharmony_ci  }
3855141cc406Sopenharmony_ci
3856141cc406Sopenharmony_ci  /*background color*/
3857141cc406Sopenharmony_ci  if(option==OPT_BG_COLOR){
3858141cc406Sopenharmony_ci    s->bg_color_list[0] = STRING_DEFAULT;
3859141cc406Sopenharmony_ci    s->bg_color_list[1] = STRING_WHITE;
3860141cc406Sopenharmony_ci    s->bg_color_list[2] = STRING_BLACK;
3861141cc406Sopenharmony_ci    s->bg_color_list[3] = NULL;
3862141cc406Sopenharmony_ci
3863141cc406Sopenharmony_ci    opt->name = "bgcolor";
3864141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Background color");
3865141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Set color of background for scans. May conflict with overscan option");
3866141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3867141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3868141cc406Sopenharmony_ci    opt->constraint.string_list = s->bg_color_list;
3869141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3870141cc406Sopenharmony_ci    if (s->has_MS_bg)
3871141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3872141cc406Sopenharmony_ci    else
3873141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3874141cc406Sopenharmony_ci  }
3875141cc406Sopenharmony_ci
3876141cc406Sopenharmony_ci  /*dropout color*/
3877141cc406Sopenharmony_ci  if(option==OPT_DROPOUT_COLOR){
3878141cc406Sopenharmony_ci    s->do_color_list[0] = STRING_DEFAULT;
3879141cc406Sopenharmony_ci    s->do_color_list[1] = STRING_RED;
3880141cc406Sopenharmony_ci    s->do_color_list[2] = STRING_GREEN;
3881141cc406Sopenharmony_ci    s->do_color_list[3] = STRING_BLUE;
3882141cc406Sopenharmony_ci    s->do_color_list[4] = NULL;
3883141cc406Sopenharmony_ci
3884141cc406Sopenharmony_ci    opt->name = "dropoutcolor";
3885141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Dropout color");
3886141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink");
3887141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3888141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3889141cc406Sopenharmony_ci    opt->constraint.string_list = s->do_color_list;
3890141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3891141cc406Sopenharmony_ci
3892141cc406Sopenharmony_ci    if (s->has_MS_dropout || s->has_vuid_3091 || must_downsample(s)){
3893141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
3894141cc406Sopenharmony_ci      if(s->u_mode == MODE_COLOR)
3895141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
3896141cc406Sopenharmony_ci    }
3897141cc406Sopenharmony_ci    else
3898141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3899141cc406Sopenharmony_ci  }
3900141cc406Sopenharmony_ci
3901141cc406Sopenharmony_ci  /*buffer mode*/
3902141cc406Sopenharmony_ci  if(option==OPT_BUFF_MODE){
3903141cc406Sopenharmony_ci    s->buff_mode_list[0] = STRING_DEFAULT;
3904141cc406Sopenharmony_ci    s->buff_mode_list[1] = STRING_OFF;
3905141cc406Sopenharmony_ci    s->buff_mode_list[2] = STRING_ON;
3906141cc406Sopenharmony_ci    s->buff_mode_list[3] = NULL;
3907141cc406Sopenharmony_ci
3908141cc406Sopenharmony_ci    opt->name = "buffermode";
3909141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Buffer mode");
3910141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to read pages quickly from ADF into internal memory");
3911141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3912141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3913141cc406Sopenharmony_ci    opt->constraint.string_list = s->buff_mode_list;
3914141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3915141cc406Sopenharmony_ci    if (s->has_MS_buff)
3916141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3917141cc406Sopenharmony_ci    else
3918141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3919141cc406Sopenharmony_ci  }
3920141cc406Sopenharmony_ci
3921141cc406Sopenharmony_ci  /*prepick*/
3922141cc406Sopenharmony_ci  if(option==OPT_PREPICK){
3923141cc406Sopenharmony_ci    s->prepick_list[0] = STRING_DEFAULT;
3924141cc406Sopenharmony_ci    s->prepick_list[1] = STRING_OFF;
3925141cc406Sopenharmony_ci    s->prepick_list[2] = STRING_ON;
3926141cc406Sopenharmony_ci    s->prepick_list[3] = NULL;
3927141cc406Sopenharmony_ci
3928141cc406Sopenharmony_ci    opt->name = "prepick";
3929141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Prepick");
3930141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to grab next page from ADF");
3931141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3932141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3933141cc406Sopenharmony_ci    opt->constraint.string_list = s->prepick_list;
3934141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3935141cc406Sopenharmony_ci    if (s->has_MS_prepick)
3936141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3937141cc406Sopenharmony_ci    else
3938141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3939141cc406Sopenharmony_ci  }
3940141cc406Sopenharmony_ci
3941141cc406Sopenharmony_ci  /*overscan*/
3942141cc406Sopenharmony_ci  if(option==OPT_OVERSCAN){
3943141cc406Sopenharmony_ci    s->overscan_list[0] = STRING_DEFAULT;
3944141cc406Sopenharmony_ci    s->overscan_list[1] = STRING_OFF;
3945141cc406Sopenharmony_ci    s->overscan_list[2] = STRING_ON;
3946141cc406Sopenharmony_ci    s->overscan_list[3] = NULL;
3947141cc406Sopenharmony_ci
3948141cc406Sopenharmony_ci    opt->name = "overscan";
3949141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Overscan");
3950141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Collect a few mm of background on top side of scan, before paper enters ADF, and increase maximum scan area beyond paper size, to allow collection on remaining sides. May conflict with bgcolor option");
3951141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
3952141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
3953141cc406Sopenharmony_ci    opt->constraint.string_list = s->overscan_list;
3954141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
3955141cc406Sopenharmony_ci    if (s->has_MS_auto && (s->os_x_basic || s->os_y_basic))
3956141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3957141cc406Sopenharmony_ci    else
3958141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3959141cc406Sopenharmony_ci  }
3960141cc406Sopenharmony_ci
3961141cc406Sopenharmony_ci  /*sleep_time*/
3962141cc406Sopenharmony_ci  if(option==OPT_SLEEP_TIME){
3963141cc406Sopenharmony_ci    s->sleep_time_range.min = 0;
3964141cc406Sopenharmony_ci    s->sleep_time_range.max = 60;
3965141cc406Sopenharmony_ci    s->sleep_time_range.quant = 1;
3966141cc406Sopenharmony_ci
3967141cc406Sopenharmony_ci    opt->name = "sleeptimer";
3968141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Sleep timer");
3969141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches to sleep mode");
3970141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3971141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3972141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3973141cc406Sopenharmony_ci    opt->constraint.range=&s->sleep_time_range;
3974141cc406Sopenharmony_ci    if(s->has_MS_sleep)
3975141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3976141cc406Sopenharmony_ci    else
3977141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3978141cc406Sopenharmony_ci  }
3979141cc406Sopenharmony_ci
3980141cc406Sopenharmony_ci  /*off_time*/
3981141cc406Sopenharmony_ci  if(option==OPT_OFF_TIME){
3982141cc406Sopenharmony_ci    s->off_time_range.min = 0;
3983141cc406Sopenharmony_ci    s->off_time_range.max = 960;
3984141cc406Sopenharmony_ci    s->off_time_range.quant = 1;
3985141cc406Sopenharmony_ci
3986141cc406Sopenharmony_ci    opt->name = "offtimer";
3987141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Off timer");
3988141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches the scanner off. Will be rounded to nearest 15 minutes. Zero means never power off.");
3989141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
3990141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
3991141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
3992141cc406Sopenharmony_ci    opt->constraint.range=&s->off_time_range;
3993141cc406Sopenharmony_ci    if(s->has_off_mode)
3994141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
3995141cc406Sopenharmony_ci    else
3996141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
3997141cc406Sopenharmony_ci  }
3998141cc406Sopenharmony_ci
3999141cc406Sopenharmony_ci  /*duplex offset*/
4000141cc406Sopenharmony_ci  if(option==OPT_DUPLEX_OFFSET){
4001141cc406Sopenharmony_ci    s->duplex_offset_range.min = -16;
4002141cc406Sopenharmony_ci    s->duplex_offset_range.max = 16;
4003141cc406Sopenharmony_ci    s->duplex_offset_range.quant = 1;
4004141cc406Sopenharmony_ci
4005141cc406Sopenharmony_ci    opt->name = "duplexoffset";
4006141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Duplex offset");
4007141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Adjust front/back offset");
4008141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4009141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4010141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4011141cc406Sopenharmony_ci    opt->constraint.range = &s->duplex_offset_range;
4012141cc406Sopenharmony_ci    if(s->duplex_interlace == DUPLEX_INTERLACE_3091)
4013141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4014141cc406Sopenharmony_ci    else
4015141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4016141cc406Sopenharmony_ci  }
4017141cc406Sopenharmony_ci
4018141cc406Sopenharmony_ci  if(option==OPT_GREEN_OFFSET){
4019141cc406Sopenharmony_ci    s->green_offset_range.min = -16;
4020141cc406Sopenharmony_ci    s->green_offset_range.max = 16;
4021141cc406Sopenharmony_ci    s->green_offset_range.quant = 1;
4022141cc406Sopenharmony_ci
4023141cc406Sopenharmony_ci    opt->name = "greenoffset";
4024141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Green offset");
4025141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Adjust green/red offset");
4026141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4027141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4028141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4029141cc406Sopenharmony_ci    opt->constraint.range = &s->green_offset_range;
4030141cc406Sopenharmony_ci    if(s->color_interlace == COLOR_INTERLACE_3091)
4031141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4032141cc406Sopenharmony_ci    else
4033141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4034141cc406Sopenharmony_ci  }
4035141cc406Sopenharmony_ci
4036141cc406Sopenharmony_ci  if(option==OPT_BLUE_OFFSET){
4037141cc406Sopenharmony_ci    s->blue_offset_range.min = -16;
4038141cc406Sopenharmony_ci    s->blue_offset_range.max = 16;
4039141cc406Sopenharmony_ci    s->blue_offset_range.quant = 1;
4040141cc406Sopenharmony_ci
4041141cc406Sopenharmony_ci    opt->name = "blueoffset";
4042141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Blue offset");
4043141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Adjust blue/red offset");
4044141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4045141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4046141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4047141cc406Sopenharmony_ci    opt->constraint.range = &s->blue_offset_range;
4048141cc406Sopenharmony_ci    if(s->color_interlace == COLOR_INTERLACE_3091)
4049141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4050141cc406Sopenharmony_ci    else
4051141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4052141cc406Sopenharmony_ci  }
4053141cc406Sopenharmony_ci
4054141cc406Sopenharmony_ci  if(option==OPT_LOW_MEM){
4055141cc406Sopenharmony_ci    opt->name = "lowmemory";
4056141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Low Memory");
4057141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Limit driver memory usage for use in embedded systems. Causes some duplex transfers to alternate sides on each call to sane_read. Value of option 'side' can be used to determine correct image. This option should only be used with custom front-end software.");
4058141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4059141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4060141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4061141cc406Sopenharmony_ci
4062141cc406Sopenharmony_ci    if (1)
4063141cc406Sopenharmony_ci      opt->cap= SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4064141cc406Sopenharmony_ci    else
4065141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4066141cc406Sopenharmony_ci
4067141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4068141cc406Sopenharmony_ci  }
4069141cc406Sopenharmony_ci
4070141cc406Sopenharmony_ci  if(option==OPT_SIDE){
4071141cc406Sopenharmony_ci    opt->name = "side";
4072141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Duplex side");
4073141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Tells which side (0=front, 1=back) of a duplex scan the next call to sane_read will return.");
4074141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4075141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4076141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4077141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4078141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4079141cc406Sopenharmony_ci  }
4080141cc406Sopenharmony_ci
4081141cc406Sopenharmony_ci  /*deskew and crop by hardware*/
4082141cc406Sopenharmony_ci  if(option==OPT_HWDESKEWCROP){
4083141cc406Sopenharmony_ci    opt->name = "hwdeskewcrop";
4084141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Hardware deskew and crop");
4085141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request scanner to rotate and crop pages digitally.");
4086141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4087141cc406Sopenharmony_ci    if (s->has_hybrid_crop_deskew)
4088141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4089141cc406Sopenharmony_ci    else
4090141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
4091141cc406Sopenharmony_ci  }
4092141cc406Sopenharmony_ci
4093141cc406Sopenharmony_ci  /*deskew by software*/
4094141cc406Sopenharmony_ci  if(option==OPT_SWDESKEW){
4095141cc406Sopenharmony_ci    opt->name = "swdeskew";
4096141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Software deskew");
4097141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request driver to rotate skewed pages digitally.");
4098141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4099141cc406Sopenharmony_ci    if (1)
4100141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4101141cc406Sopenharmony_ci    else
4102141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
4103141cc406Sopenharmony_ci  }
4104141cc406Sopenharmony_ci
4105141cc406Sopenharmony_ci  /*software despeckle radius*/
4106141cc406Sopenharmony_ci  if(option==OPT_SWDESPECK){
4107141cc406Sopenharmony_ci
4108141cc406Sopenharmony_ci    opt->name = "swdespeck";
4109141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Software despeckle diameter");
4110141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Maximum diameter of lone dots to remove from scan.");
4111141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4112141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4113141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4114141cc406Sopenharmony_ci    opt->constraint.range = &s->swdespeck_range;
4115141cc406Sopenharmony_ci    s->swdespeck_range.quant=1;
4116141cc406Sopenharmony_ci
4117141cc406Sopenharmony_ci    if(1){
4118141cc406Sopenharmony_ci      s->swdespeck_range.min=0;
4119141cc406Sopenharmony_ci      s->swdespeck_range.max=9;
4120141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
4121141cc406Sopenharmony_ci    }
4122141cc406Sopenharmony_ci    else
4123141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4124141cc406Sopenharmony_ci  }
4125141cc406Sopenharmony_ci
4126141cc406Sopenharmony_ci  /*crop by software*/
4127141cc406Sopenharmony_ci  if(option==OPT_SWCROP){
4128141cc406Sopenharmony_ci    opt->name = "swcrop";
4129141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Software crop");
4130141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request driver to remove border from pages digitally.");
4131141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4132141cc406Sopenharmony_ci    if (1)
4133141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4134141cc406Sopenharmony_ci    else
4135141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
4136141cc406Sopenharmony_ci  }
4137141cc406Sopenharmony_ci
4138141cc406Sopenharmony_ci  /* Software blank page skip */
4139141cc406Sopenharmony_ci  if(option==OPT_SWSKIP){
4140141cc406Sopenharmony_ci
4141141cc406Sopenharmony_ci    opt->name = "swskip";
4142141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Software blank skip percentage");
4143141cc406Sopenharmony_ci    opt->desc = SANE_I18N("Request driver to discard pages with low percentage of dark pixels");
4144141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
4145141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_PERCENT;
4146141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4147141cc406Sopenharmony_ci    opt->constraint.range = &s->swskip_range;
4148141cc406Sopenharmony_ci
4149141cc406Sopenharmony_ci    s->swskip_range.quant=SANE_FIX(0.10001);
4150141cc406Sopenharmony_ci    s->swskip_range.min=SANE_FIX(0);
4151141cc406Sopenharmony_ci    s->swskip_range.max=SANE_FIX(100);
4152141cc406Sopenharmony_ci
4153141cc406Sopenharmony_ci    opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
4154141cc406Sopenharmony_ci  }
4155141cc406Sopenharmony_ci
4156141cc406Sopenharmony_ci  /*halt scanner feeder when cancelling*/
4157141cc406Sopenharmony_ci  if(option==OPT_HALT_ON_CANCEL){
4158141cc406Sopenharmony_ci    opt->name = "halt-on-cancel";
4159141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Halt on Cancel");
4160141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Request driver to halt the paper feed instead of eject during a cancel.");
4161141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4162141cc406Sopenharmony_ci    if (s->has_op_halt)
4163141cc406Sopenharmony_ci     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4164141cc406Sopenharmony_ci    else
4165141cc406Sopenharmony_ci     opt->cap = SANE_CAP_INACTIVE;
4166141cc406Sopenharmony_ci  }
4167141cc406Sopenharmony_ci
4168141cc406Sopenharmony_ci  /* "Endorser" group ------------------------------------------------------ */
4169141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_GROUP){
4170141cc406Sopenharmony_ci    opt->name = "endorser-options";
4171141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser Options");
4172141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Controls for endorser unit");
4173141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
4174141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4175141cc406Sopenharmony_ci
4176141cc406Sopenharmony_ci    /*flaming hack to get scanimage to hide group*/
4177141cc406Sopenharmony_ci    if ( !(s->has_endorser_f || s->has_endorser_b) )
4178141cc406Sopenharmony_ci      opt->type = SANE_TYPE_BOOL;
4179141cc406Sopenharmony_ci  }
4180141cc406Sopenharmony_ci
4181141cc406Sopenharmony_ci  if(option==OPT_ENDORSER){
4182141cc406Sopenharmony_ci    opt->name = "endorser";
4183141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser");
4184141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Enable endorser unit");
4185141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4186141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4187141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4188141cc406Sopenharmony_ci
4189141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b)
4190141cc406Sopenharmony_ci      opt->cap= SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4191141cc406Sopenharmony_ci    else
4192141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4193141cc406Sopenharmony_ci
4194141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4195141cc406Sopenharmony_ci  }
4196141cc406Sopenharmony_ci
4197141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_BITS){
4198141cc406Sopenharmony_ci    opt->name = "endorser-bits";
4199141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser bits");
4200141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Determines maximum endorser counter value.");
4201141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4202141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4203141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4204141cc406Sopenharmony_ci
4205141cc406Sopenharmony_ci    /*old type can't do this?*/
4206141cc406Sopenharmony_ci    if ((s->has_endorser_f && s->endorser_type_f != ET_OLD)
4207141cc406Sopenharmony_ci     || (s->has_endorser_b && s->endorser_type_b != ET_OLD)){
4208141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4209141cc406Sopenharmony_ci      if(!s->u_endorser)
4210141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4211141cc406Sopenharmony_ci    }
4212141cc406Sopenharmony_ci    else
4213141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4214141cc406Sopenharmony_ci
4215141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4216141cc406Sopenharmony_ci    opt->constraint.range = &s->endorser_bits_range;
4217141cc406Sopenharmony_ci
4218141cc406Sopenharmony_ci    s->endorser_bits_range.min = 16;
4219141cc406Sopenharmony_ci    s->endorser_bits_range.max = 24;
4220141cc406Sopenharmony_ci    s->endorser_bits_range.quant = 8;
4221141cc406Sopenharmony_ci  }
4222141cc406Sopenharmony_ci
4223141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_VAL){
4224141cc406Sopenharmony_ci    opt->name = "endorser-val";
4225141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser value");
4226141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Initial endorser counter value.");
4227141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4228141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4229141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4230141cc406Sopenharmony_ci
4231141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b){
4232141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4233141cc406Sopenharmony_ci      if(!s->u_endorser)
4234141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4235141cc406Sopenharmony_ci    }
4236141cc406Sopenharmony_ci    else
4237141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4238141cc406Sopenharmony_ci
4239141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4240141cc406Sopenharmony_ci    opt->constraint.range = &s->endorser_val_range;
4241141cc406Sopenharmony_ci
4242141cc406Sopenharmony_ci    s->endorser_val_range.min = 0;
4243141cc406Sopenharmony_ci    s->endorser_val_range.max = (1 << s->u_endorser_bits)-1;
4244141cc406Sopenharmony_ci    s->endorser_val_range.quant = 1;
4245141cc406Sopenharmony_ci  }
4246141cc406Sopenharmony_ci
4247141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_STEP){
4248141cc406Sopenharmony_ci    opt->name = "endorser-step";
4249141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser step");
4250141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Change endorser counter value by this much for each page.");
4251141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4252141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4253141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4254141cc406Sopenharmony_ci
4255141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b){
4256141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4257141cc406Sopenharmony_ci      if(!s->u_endorser)
4258141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4259141cc406Sopenharmony_ci    }
4260141cc406Sopenharmony_ci    else
4261141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4262141cc406Sopenharmony_ci
4263141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4264141cc406Sopenharmony_ci    opt->constraint.range = &s->endorser_step_range;
4265141cc406Sopenharmony_ci
4266141cc406Sopenharmony_ci    s->endorser_step_range.min = -2;
4267141cc406Sopenharmony_ci    s->endorser_step_range.max = 2;
4268141cc406Sopenharmony_ci    s->endorser_step_range.quant = 1;
4269141cc406Sopenharmony_ci  }
4270141cc406Sopenharmony_ci
4271141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_Y){
4272141cc406Sopenharmony_ci    opt->name = "endorser-y";
4273141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser Y");
4274141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Endorser print offset from top of paper.");
4275141cc406Sopenharmony_ci    opt->type = SANE_TYPE_FIXED;
4276141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_MM;
4277141cc406Sopenharmony_ci    opt->size = sizeof(SANE_Word);
4278141cc406Sopenharmony_ci
4279141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b){
4280141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4281141cc406Sopenharmony_ci      if(!s->u_endorser)
4282141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4283141cc406Sopenharmony_ci    }
4284141cc406Sopenharmony_ci    else
4285141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4286141cc406Sopenharmony_ci
4287141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_RANGE;
4288141cc406Sopenharmony_ci    opt->constraint.range = &(s->endorser_y_range);
4289141cc406Sopenharmony_ci
4290141cc406Sopenharmony_ci    /* values stored in 1200 dpi units */
4291141cc406Sopenharmony_ci    /* must be converted to MM for sane */
4292141cc406Sopenharmony_ci    s->endorser_y_range.min = SCANNER_UNIT_TO_FIXED_MM(0);
4293141cc406Sopenharmony_ci    s->endorser_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s));
4294141cc406Sopenharmony_ci    s->endorser_y_range.quant = MM_PER_UNIT_FIX;
4295141cc406Sopenharmony_ci  }
4296141cc406Sopenharmony_ci
4297141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_FONT){
4298141cc406Sopenharmony_ci    opt->name = "endorser-font";
4299141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser font");
4300141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Endorser printing font.");
4301141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
4302141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4303141cc406Sopenharmony_ci
4304141cc406Sopenharmony_ci    /*only newest can do this?*/
4305141cc406Sopenharmony_ci    if ((s->has_endorser_f && s->endorser_type_f == ET_40)
4306141cc406Sopenharmony_ci     || (s->has_endorser_b && s->endorser_type_b == ET_40)){
4307141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4308141cc406Sopenharmony_ci      if(!s->u_endorser)
4309141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4310141cc406Sopenharmony_ci    }
4311141cc406Sopenharmony_ci    else
4312141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4313141cc406Sopenharmony_ci
4314141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
4315141cc406Sopenharmony_ci    opt->constraint.string_list = s->endorser_font_list;
4316141cc406Sopenharmony_ci
4317141cc406Sopenharmony_ci    s->endorser_font_list[0] = STRING_HORIZONTAL;
4318141cc406Sopenharmony_ci    s->endorser_font_list[1] = STRING_HORIZONTALBOLD;
4319141cc406Sopenharmony_ci    s->endorser_font_list[2] = STRING_HORIZONTALNARROW;
4320141cc406Sopenharmony_ci    s->endorser_font_list[3] = STRING_VERTICAL;
4321141cc406Sopenharmony_ci    s->endorser_font_list[4] = STRING_VERTICALBOLD;
4322141cc406Sopenharmony_ci    s->endorser_font_list[5] = NULL;
4323141cc406Sopenharmony_ci
4324141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
4325141cc406Sopenharmony_ci  }
4326141cc406Sopenharmony_ci
4327141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_DIR){
4328141cc406Sopenharmony_ci    opt->name = "endorser-dir";
4329141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser direction");
4330141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Endorser printing direction.");
4331141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
4332141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4333141cc406Sopenharmony_ci
4334141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b){
4335141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4336141cc406Sopenharmony_ci      if(!s->u_endorser)
4337141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4338141cc406Sopenharmony_ci    }
4339141cc406Sopenharmony_ci    else
4340141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4341141cc406Sopenharmony_ci
4342141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
4343141cc406Sopenharmony_ci    opt->constraint.string_list = s->endorser_dir_list;
4344141cc406Sopenharmony_ci
4345141cc406Sopenharmony_ci    s->endorser_dir_list[0] = STRING_TOPTOBOTTOM;
4346141cc406Sopenharmony_ci    s->endorser_dir_list[1] = STRING_BOTTOMTOTOP;
4347141cc406Sopenharmony_ci    s->endorser_dir_list[2] = NULL;
4348141cc406Sopenharmony_ci
4349141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
4350141cc406Sopenharmony_ci  }
4351141cc406Sopenharmony_ci
4352141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_SIDE){
4353141cc406Sopenharmony_ci    opt->name = "endorser-side";
4354141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser side");
4355141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Endorser printing side, requires hardware support to change");
4356141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
4357141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4358141cc406Sopenharmony_ci
4359141cc406Sopenharmony_ci    /* only show if both endorsers are installed */
4360141cc406Sopenharmony_ci    if (s->has_endorser_f && s->has_endorser_b){
4361141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4362141cc406Sopenharmony_ci      if(!s->u_endorser)
4363141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4364141cc406Sopenharmony_ci    }
4365141cc406Sopenharmony_ci    else
4366141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4367141cc406Sopenharmony_ci
4368141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
4369141cc406Sopenharmony_ci    opt->constraint.string_list = s->endorser_side_list;
4370141cc406Sopenharmony_ci
4371141cc406Sopenharmony_ci    s->endorser_side_list[0] = STRING_FRONT;
4372141cc406Sopenharmony_ci    s->endorser_side_list[1] = STRING_BACK;
4373141cc406Sopenharmony_ci    s->endorser_side_list[2] = NULL;
4374141cc406Sopenharmony_ci
4375141cc406Sopenharmony_ci    opt->size = maxStringSize (opt->constraint.string_list);
4376141cc406Sopenharmony_ci  }
4377141cc406Sopenharmony_ci
4378141cc406Sopenharmony_ci  if(option==OPT_ENDORSER_STRING){
4379141cc406Sopenharmony_ci    opt->name = "endorser-string";
4380141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Endorser string");
4381141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Endorser alphanumeric print format. %05ud or %08ud at the end will be replaced by counter value.");
4382141cc406Sopenharmony_ci    opt->type = SANE_TYPE_STRING;
4383141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4384141cc406Sopenharmony_ci    opt->size = s->endorser_string_len + 1;
4385141cc406Sopenharmony_ci
4386141cc406Sopenharmony_ci    if (s->has_endorser_f || s->has_endorser_b){
4387141cc406Sopenharmony_ci      opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
4388141cc406Sopenharmony_ci      if(!s->u_endorser)
4389141cc406Sopenharmony_ci        opt->cap |= SANE_CAP_INACTIVE;
4390141cc406Sopenharmony_ci    }
4391141cc406Sopenharmony_ci    else
4392141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4393141cc406Sopenharmony_ci
4394141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4395141cc406Sopenharmony_ci  }
4396141cc406Sopenharmony_ci
4397141cc406Sopenharmony_ci  /* "Sensor" group ------------------------------------------------------ */
4398141cc406Sopenharmony_ci  if(option==OPT_SENSOR_GROUP){
4399141cc406Sopenharmony_ci    opt->name = SANE_NAME_SENSORS;
4400141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SENSORS;
4401141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SENSORS;
4402141cc406Sopenharmony_ci    opt->type = SANE_TYPE_GROUP;
4403141cc406Sopenharmony_ci    opt->constraint_type = SANE_CONSTRAINT_NONE;
4404141cc406Sopenharmony_ci  }
4405141cc406Sopenharmony_ci
4406141cc406Sopenharmony_ci  if(option==OPT_TOP){
4407141cc406Sopenharmony_ci    opt->name = "top-edge";
4408141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Top edge");
4409141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Paper is pulled partly into ADF");
4410141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4411141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4412141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4413141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4414141cc406Sopenharmony_ci    else
4415141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4416141cc406Sopenharmony_ci  }
4417141cc406Sopenharmony_ci
4418141cc406Sopenharmony_ci  if(option==OPT_A3){
4419141cc406Sopenharmony_ci    opt->name = "a3-paper";
4420141cc406Sopenharmony_ci    opt->title = SANE_I18N ("A3 paper");
4421141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("A3 paper detected");
4422141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4423141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4424141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4425141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4426141cc406Sopenharmony_ci    else
4427141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4428141cc406Sopenharmony_ci  }
4429141cc406Sopenharmony_ci
4430141cc406Sopenharmony_ci  if(option==OPT_B4){
4431141cc406Sopenharmony_ci    opt->name = "b4-paper";
4432141cc406Sopenharmony_ci    opt->title = SANE_I18N ("B4 paper");
4433141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("B4 paper detected");
4434141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4435141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4436141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4437141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4438141cc406Sopenharmony_ci    else
4439141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4440141cc406Sopenharmony_ci  }
4441141cc406Sopenharmony_ci
4442141cc406Sopenharmony_ci  if(option==OPT_A4){
4443141cc406Sopenharmony_ci    opt->name = "a4-paper";
4444141cc406Sopenharmony_ci    opt->title = SANE_I18N ("A4 paper");
4445141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("A4 paper detected");
4446141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4447141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4448141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4449141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4450141cc406Sopenharmony_ci    else
4451141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4452141cc406Sopenharmony_ci  }
4453141cc406Sopenharmony_ci
4454141cc406Sopenharmony_ci  if(option==OPT_B5){
4455141cc406Sopenharmony_ci    opt->name = "b5-paper";
4456141cc406Sopenharmony_ci    opt->title = SANE_I18N ("B5 paper");
4457141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("B5 paper detected");
4458141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4459141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4460141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4461141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4462141cc406Sopenharmony_ci    else
4463141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4464141cc406Sopenharmony_ci  }
4465141cc406Sopenharmony_ci
4466141cc406Sopenharmony_ci  if(option==OPT_HOPPER){
4467141cc406Sopenharmony_ci    opt->name = SANE_NAME_PAGE_LOADED;
4468141cc406Sopenharmony_ci    opt->title = SANE_TITLE_PAGE_LOADED;
4469141cc406Sopenharmony_ci    opt->desc = SANE_DESC_PAGE_LOADED;
4470141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4471141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4472141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4473141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4474141cc406Sopenharmony_ci    else
4475141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4476141cc406Sopenharmony_ci  }
4477141cc406Sopenharmony_ci
4478141cc406Sopenharmony_ci  if(option==OPT_OMR){
4479141cc406Sopenharmony_ci    opt->name = "omr-df";
4480141cc406Sopenharmony_ci    opt->title = SANE_I18N ("OMR or DF");
4481141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("OMR or double feed detected");
4482141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4483141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4484141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4485141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4486141cc406Sopenharmony_ci    else
4487141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4488141cc406Sopenharmony_ci  }
4489141cc406Sopenharmony_ci
4490141cc406Sopenharmony_ci  if(option==OPT_ADF_OPEN){
4491141cc406Sopenharmony_ci    opt->name = SANE_NAME_COVER_OPEN;
4492141cc406Sopenharmony_ci    opt->title = SANE_TITLE_COVER_OPEN;
4493141cc406Sopenharmony_ci    opt->desc = SANE_DESC_COVER_OPEN;
4494141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4495141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4496141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4497141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4498141cc406Sopenharmony_ci    else
4499141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4500141cc406Sopenharmony_ci  }
4501141cc406Sopenharmony_ci
4502141cc406Sopenharmony_ci  if(option==OPT_CARD_LOADED){
4503141cc406Sopenharmony_ci    opt->name = "card-loaded";
4504141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Card loaded");
4505141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Card slot contains paper");
4506141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4507141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4508141cc406Sopenharmony_ci    if (s->has_cmd_hw_status && s->has_return_path)
4509141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4510141cc406Sopenharmony_ci    else
4511141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4512141cc406Sopenharmony_ci  }
4513141cc406Sopenharmony_ci
4514141cc406Sopenharmony_ci  if(option==OPT_SLEEP){
4515141cc406Sopenharmony_ci    opt->name = "power-save";
4516141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Power saving");
4517141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Scanner in power saving mode");
4518141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4519141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4520141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4521141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4522141cc406Sopenharmony_ci    else
4523141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4524141cc406Sopenharmony_ci  }
4525141cc406Sopenharmony_ci
4526141cc406Sopenharmony_ci  if(option==OPT_SEND_SW){
4527141cc406Sopenharmony_ci    opt->name = SANE_NAME_EMAIL;
4528141cc406Sopenharmony_ci    opt->title = SANE_TITLE_EMAIL;
4529141cc406Sopenharmony_ci    opt->desc = SANE_DESC_EMAIL;
4530141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4531141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4532141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4533141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4534141cc406Sopenharmony_ci    else
4535141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4536141cc406Sopenharmony_ci  }
4537141cc406Sopenharmony_ci
4538141cc406Sopenharmony_ci  if(option==OPT_MANUAL_FEED){
4539141cc406Sopenharmony_ci    opt->name = "manual-feed";
4540141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Manual feed");
4541141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Manual feed selected");
4542141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4543141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4544141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4545141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4546141cc406Sopenharmony_ci    else
4547141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4548141cc406Sopenharmony_ci  }
4549141cc406Sopenharmony_ci
4550141cc406Sopenharmony_ci  if(option==OPT_SCAN_SW){
4551141cc406Sopenharmony_ci    opt->name = SANE_NAME_SCAN;
4552141cc406Sopenharmony_ci    opt->title = SANE_TITLE_SCAN;
4553141cc406Sopenharmony_ci    opt->desc = SANE_DESC_SCAN;
4554141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4555141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4556141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4557141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4558141cc406Sopenharmony_ci    else
4559141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4560141cc406Sopenharmony_ci  }
4561141cc406Sopenharmony_ci
4562141cc406Sopenharmony_ci  if(option==OPT_FUNCTION){
4563141cc406Sopenharmony_ci    opt->name = "function";
4564141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Function");
4565141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Function character on screen");
4566141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4567141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4568141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4569141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4570141cc406Sopenharmony_ci    else
4571141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4572141cc406Sopenharmony_ci  }
4573141cc406Sopenharmony_ci
4574141cc406Sopenharmony_ci  if(option==OPT_INK_EMPTY){
4575141cc406Sopenharmony_ci    opt->name = "ink-low";
4576141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Ink low");
4577141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Imprinter ink running low");
4578141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4579141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4580141cc406Sopenharmony_ci    if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b))
4581141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4582141cc406Sopenharmony_ci    else
4583141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4584141cc406Sopenharmony_ci  }
4585141cc406Sopenharmony_ci
4586141cc406Sopenharmony_ci  if(option==OPT_DOUBLE_FEED){
4587141cc406Sopenharmony_ci    opt->name = "double-feed";
4588141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Double feed");
4589141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Double feed detected");
4590141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4591141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4592141cc406Sopenharmony_ci    if (s->has_cmd_hw_status || s->ghs_in_rs)
4593141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4594141cc406Sopenharmony_ci    else
4595141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4596141cc406Sopenharmony_ci  }
4597141cc406Sopenharmony_ci
4598141cc406Sopenharmony_ci  if(option==OPT_ERROR_CODE){
4599141cc406Sopenharmony_ci    opt->name = "error-code";
4600141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Error code");
4601141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Hardware error code");
4602141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4603141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4604141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4605141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4606141cc406Sopenharmony_ci    else
4607141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4608141cc406Sopenharmony_ci  }
4609141cc406Sopenharmony_ci
4610141cc406Sopenharmony_ci  if(option==OPT_SKEW_ANGLE){
4611141cc406Sopenharmony_ci    opt->name = "skew-angle";
4612141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Skew angle");
4613141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Requires black background for scanning");
4614141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4615141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4616141cc406Sopenharmony_ci    if (s->has_cmd_hw_status)
4617141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4618141cc406Sopenharmony_ci    else
4619141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4620141cc406Sopenharmony_ci  }
4621141cc406Sopenharmony_ci
4622141cc406Sopenharmony_ci  if(option==OPT_INK_REMAIN){
4623141cc406Sopenharmony_ci    opt->name = "ink-remain";
4624141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Ink remaining");
4625141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Imprinter ink level");
4626141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4627141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4628141cc406Sopenharmony_ci    if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b))
4629141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4630141cc406Sopenharmony_ci    else
4631141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4632141cc406Sopenharmony_ci  }
4633141cc406Sopenharmony_ci
4634141cc406Sopenharmony_ci  if(option==OPT_DENSITY_SW){
4635141cc406Sopenharmony_ci    opt->name = "density";
4636141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Density");
4637141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Density dial");
4638141cc406Sopenharmony_ci    opt->type = SANE_TYPE_INT;
4639141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4640141cc406Sopenharmony_ci    if (s->ghs_in_rs)
4641141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4642141cc406Sopenharmony_ci    else
4643141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4644141cc406Sopenharmony_ci  }
4645141cc406Sopenharmony_ci
4646141cc406Sopenharmony_ci  if(option==OPT_DUPLEX_SW){
4647141cc406Sopenharmony_ci    opt->name = "duplex";
4648141cc406Sopenharmony_ci    opt->title = SANE_I18N ("Duplex switch");
4649141cc406Sopenharmony_ci    opt->desc = SANE_I18N ("Duplex switch");
4650141cc406Sopenharmony_ci    opt->type = SANE_TYPE_BOOL;
4651141cc406Sopenharmony_ci    opt->unit = SANE_UNIT_NONE;
4652141cc406Sopenharmony_ci    if (s->ghs_in_rs)
4653141cc406Sopenharmony_ci      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
4654141cc406Sopenharmony_ci    else
4655141cc406Sopenharmony_ci      opt->cap = SANE_CAP_INACTIVE;
4656141cc406Sopenharmony_ci  }
4657141cc406Sopenharmony_ci
4658141cc406Sopenharmony_ci  return opt;
4659141cc406Sopenharmony_ci}
4660141cc406Sopenharmony_ci
4661141cc406Sopenharmony_ci/**
4662141cc406Sopenharmony_ci * Gets or sets an option value.
4663141cc406Sopenharmony_ci *
4664141cc406Sopenharmony_ci * From the SANE spec:
4665141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option
4666141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which
4667141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The
4668141cc406Sopenharmony_ci * possible values of this parameter are described in more detail
4669141cc406Sopenharmony_ci * below.  The value of the option is passed through argument val. It
4670141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory
4671141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option
4672141cc406Sopenharmony_ci * value (determined by member size in the corresponding option
4673141cc406Sopenharmony_ci * descriptor).
4674141cc406Sopenharmony_ci *
4675141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a
4676141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter
4677141cc406Sopenharmony_ci * since the backend will stop reading the option value upon
4678141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i
4679141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how
4680141cc406Sopenharmony_ci * well the request has been met.
4681141cc406Sopenharmony_ci */
4682141cc406Sopenharmony_ciSANE_Status
4683141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
4684141cc406Sopenharmony_ci                     SANE_Action action, void *val, SANE_Int * info)
4685141cc406Sopenharmony_ci{
4686141cc406Sopenharmony_ci  struct fujitsu *s = (struct fujitsu *) handle;
4687141cc406Sopenharmony_ci  SANE_Int dummy = 0;
4688141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
4689141cc406Sopenharmony_ci
4690141cc406Sopenharmony_ci  /* Make sure that all those statements involving *info cannot break (better
4691141cc406Sopenharmony_ci   * than having to do "if (info) ..." everywhere!)
4692141cc406Sopenharmony_ci   */
4693141cc406Sopenharmony_ci  if (info == 0)
4694141cc406Sopenharmony_ci    info = &dummy;
4695141cc406Sopenharmony_ci
4696141cc406Sopenharmony_ci  /*blast info in case frontend forgot*/
4697141cc406Sopenharmony_ci  *info = 0;
4698141cc406Sopenharmony_ci
4699141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS) {
4700141cc406Sopenharmony_ci    DBG (5, "sane_control_option: %d too big\n", option);
4701141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4702141cc406Sopenharmony_ci  }
4703141cc406Sopenharmony_ci
4704141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (s->opt[option].cap)) {
4705141cc406Sopenharmony_ci    DBG (5, "sane_control_option: %d inactive\n", option);
4706141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4707141cc406Sopenharmony_ci  }
4708141cc406Sopenharmony_ci
4709141cc406Sopenharmony_ci  /*
4710141cc406Sopenharmony_ci   * SANE_ACTION_GET_VALUE: We have to find out the current setting and
4711141cc406Sopenharmony_ci   * return it in a human-readable form (often, text).
4712141cc406Sopenharmony_ci   */
4713141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE) {
4714141cc406Sopenharmony_ci      SANE_Word * val_p = (SANE_Word *) val;
4715141cc406Sopenharmony_ci
4716141cc406Sopenharmony_ci      DBG (20, "sane_control_option: get value for '%s' (%d)\n", s->opt[option].name,option);
4717141cc406Sopenharmony_ci
4718141cc406Sopenharmony_ci      switch (option) {
4719141cc406Sopenharmony_ci
4720141cc406Sopenharmony_ci        case OPT_NUM_OPTS:
4721141cc406Sopenharmony_ci          *val_p = NUM_OPTIONS;
4722141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4723141cc406Sopenharmony_ci
4724141cc406Sopenharmony_ci        case OPT_SOURCE:
4725141cc406Sopenharmony_ci          if(s->source == SOURCE_FLATBED){
4726141cc406Sopenharmony_ci            strcpy (val, STRING_FLATBED);
4727141cc406Sopenharmony_ci          }
4728141cc406Sopenharmony_ci          else if(s->source == SOURCE_ADF_FRONT){
4729141cc406Sopenharmony_ci            strcpy (val, STRING_ADFFRONT);
4730141cc406Sopenharmony_ci          }
4731141cc406Sopenharmony_ci          else if(s->source == SOURCE_ADF_BACK){
4732141cc406Sopenharmony_ci            strcpy (val, STRING_ADFBACK);
4733141cc406Sopenharmony_ci          }
4734141cc406Sopenharmony_ci          else if(s->source == SOURCE_ADF_DUPLEX){
4735141cc406Sopenharmony_ci            strcpy (val, STRING_ADFDUPLEX);
4736141cc406Sopenharmony_ci          }
4737141cc406Sopenharmony_ci          else if(s->source == SOURCE_CARD_FRONT){
4738141cc406Sopenharmony_ci            strcpy (val, STRING_CARDFRONT);
4739141cc406Sopenharmony_ci          }
4740141cc406Sopenharmony_ci          else if(s->source == SOURCE_CARD_BACK){
4741141cc406Sopenharmony_ci            strcpy (val, STRING_CARDBACK);
4742141cc406Sopenharmony_ci          }
4743141cc406Sopenharmony_ci          else if(s->source == SOURCE_CARD_DUPLEX){
4744141cc406Sopenharmony_ci            strcpy (val, STRING_CARDDUPLEX);
4745141cc406Sopenharmony_ci          }
4746141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4747141cc406Sopenharmony_ci
4748141cc406Sopenharmony_ci        case OPT_MODE:
4749141cc406Sopenharmony_ci          if(s->u_mode == MODE_LINEART){
4750141cc406Sopenharmony_ci            strcpy (val, STRING_LINEART);
4751141cc406Sopenharmony_ci          }
4752141cc406Sopenharmony_ci          else if(s->u_mode == MODE_HALFTONE){
4753141cc406Sopenharmony_ci            strcpy (val, STRING_HALFTONE);
4754141cc406Sopenharmony_ci          }
4755141cc406Sopenharmony_ci          else if(s->u_mode == MODE_GRAYSCALE){
4756141cc406Sopenharmony_ci            strcpy (val, STRING_GRAYSCALE);
4757141cc406Sopenharmony_ci          }
4758141cc406Sopenharmony_ci          else if(s->u_mode == MODE_COLOR){
4759141cc406Sopenharmony_ci            strcpy (val, STRING_COLOR);
4760141cc406Sopenharmony_ci          }
4761141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4762141cc406Sopenharmony_ci
4763141cc406Sopenharmony_ci        case OPT_RES:
4764141cc406Sopenharmony_ci          *val_p = s->resolution_x;
4765141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4766141cc406Sopenharmony_ci
4767141cc406Sopenharmony_ci        case OPT_TL_X:
4768141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->tl_x);
4769141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4770141cc406Sopenharmony_ci
4771141cc406Sopenharmony_ci        case OPT_TL_Y:
4772141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->tl_y);
4773141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4774141cc406Sopenharmony_ci
4775141cc406Sopenharmony_ci        case OPT_BR_X:
4776141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->br_x);
4777141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4778141cc406Sopenharmony_ci
4779141cc406Sopenharmony_ci        case OPT_BR_Y:
4780141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->br_y);
4781141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4782141cc406Sopenharmony_ci
4783141cc406Sopenharmony_ci        case OPT_PAGE_WIDTH:
4784141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->page_width);
4785141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4786141cc406Sopenharmony_ci
4787141cc406Sopenharmony_ci        case OPT_PAGE_HEIGHT:
4788141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->page_height);
4789141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4790141cc406Sopenharmony_ci
4791141cc406Sopenharmony_ci        case OPT_BRIGHTNESS:
4792141cc406Sopenharmony_ci          *val_p = s->brightness;
4793141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4794141cc406Sopenharmony_ci
4795141cc406Sopenharmony_ci        case OPT_CONTRAST:
4796141cc406Sopenharmony_ci          *val_p = s->contrast;
4797141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4798141cc406Sopenharmony_ci
4799141cc406Sopenharmony_ci        case OPT_GAMMA:
4800141cc406Sopenharmony_ci          *val_p = SANE_FIX(s->gamma);
4801141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4802141cc406Sopenharmony_ci
4803141cc406Sopenharmony_ci        case OPT_THRESHOLD:
4804141cc406Sopenharmony_ci          *val_p = s->threshold;
4805141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4806141cc406Sopenharmony_ci
4807141cc406Sopenharmony_ci        /* IPC */
4808141cc406Sopenharmony_ci        case OPT_RIF:
4809141cc406Sopenharmony_ci          *val_p = s->rif;
4810141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4811141cc406Sopenharmony_ci
4812141cc406Sopenharmony_ci        case OPT_HT_TYPE:
4813141cc406Sopenharmony_ci          switch (s->ht_type) {
4814141cc406Sopenharmony_ci            case WD_ht_type_DEFAULT:
4815141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4816141cc406Sopenharmony_ci              break;
4817141cc406Sopenharmony_ci            case WD_ht_type_DITHER:
4818141cc406Sopenharmony_ci              strcpy (val, STRING_DITHER);
4819141cc406Sopenharmony_ci              break;
4820141cc406Sopenharmony_ci            case WD_ht_type_DIFFUSION:
4821141cc406Sopenharmony_ci              strcpy (val, STRING_DIFFUSION);
4822141cc406Sopenharmony_ci              break;
4823141cc406Sopenharmony_ci          }
4824141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4825141cc406Sopenharmony_ci
4826141cc406Sopenharmony_ci        case OPT_HT_PATTERN:
4827141cc406Sopenharmony_ci          *val_p = s->ht_pattern;
4828141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4829141cc406Sopenharmony_ci
4830141cc406Sopenharmony_ci        case OPT_OUTLINE:
4831141cc406Sopenharmony_ci          *val_p = s->outline;
4832141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4833141cc406Sopenharmony_ci
4834141cc406Sopenharmony_ci        case OPT_EMPHASIS:
4835141cc406Sopenharmony_ci          *val_p = s->emphasis;
4836141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4837141cc406Sopenharmony_ci
4838141cc406Sopenharmony_ci        case OPT_SEPARATION:
4839141cc406Sopenharmony_ci          *val_p = s->separation;
4840141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4841141cc406Sopenharmony_ci
4842141cc406Sopenharmony_ci        case OPT_MIRRORING:
4843141cc406Sopenharmony_ci          *val_p = s->mirroring;
4844141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4845141cc406Sopenharmony_ci
4846141cc406Sopenharmony_ci        case OPT_WL_FOLLOW:
4847141cc406Sopenharmony_ci          switch (s->wl_follow) {
4848141cc406Sopenharmony_ci            case WD_wl_follow_DEFAULT:
4849141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4850141cc406Sopenharmony_ci              break;
4851141cc406Sopenharmony_ci            case WD_wl_follow_ON:
4852141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
4853141cc406Sopenharmony_ci              break;
4854141cc406Sopenharmony_ci            case WD_wl_follow_OFF:
4855141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
4856141cc406Sopenharmony_ci              break;
4857141cc406Sopenharmony_ci          }
4858141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4859141cc406Sopenharmony_ci
4860141cc406Sopenharmony_ci        /* DTC params*/
4861141cc406Sopenharmony_ci        case OPT_BP_FILTER:
4862141cc406Sopenharmony_ci          *val_p = s->bp_filter;
4863141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4864141cc406Sopenharmony_ci
4865141cc406Sopenharmony_ci        case OPT_SMOOTHING:
4866141cc406Sopenharmony_ci          *val_p = s->smoothing;
4867141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4868141cc406Sopenharmony_ci
4869141cc406Sopenharmony_ci        case OPT_GAMMA_CURVE:
4870141cc406Sopenharmony_ci          *val_p = s->gamma_curve;
4871141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4872141cc406Sopenharmony_ci
4873141cc406Sopenharmony_ci        case OPT_THRESHOLD_CURVE:
4874141cc406Sopenharmony_ci          *val_p = s->threshold_curve;
4875141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4876141cc406Sopenharmony_ci
4877141cc406Sopenharmony_ci        case OPT_THRESHOLD_WHITE:
4878141cc406Sopenharmony_ci          *val_p = s->threshold_white;
4879141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4880141cc406Sopenharmony_ci
4881141cc406Sopenharmony_ci        case OPT_NOISE_REMOVAL:
4882141cc406Sopenharmony_ci          *val_p = s->noise_removal;
4883141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4884141cc406Sopenharmony_ci
4885141cc406Sopenharmony_ci        case OPT_MATRIX_5:
4886141cc406Sopenharmony_ci          *val_p = s->matrix_5;
4887141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4888141cc406Sopenharmony_ci
4889141cc406Sopenharmony_ci        case OPT_MATRIX_4:
4890141cc406Sopenharmony_ci          *val_p = s->matrix_4;
4891141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4892141cc406Sopenharmony_ci
4893141cc406Sopenharmony_ci        case OPT_MATRIX_3:
4894141cc406Sopenharmony_ci          *val_p = s->matrix_3;
4895141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4896141cc406Sopenharmony_ci
4897141cc406Sopenharmony_ci        case OPT_MATRIX_2:
4898141cc406Sopenharmony_ci          *val_p = s->matrix_2;
4899141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4900141cc406Sopenharmony_ci
4901141cc406Sopenharmony_ci        /* SDTC params*/
4902141cc406Sopenharmony_ci        case OPT_VARIANCE:
4903141cc406Sopenharmony_ci          *val_p = s->variance;
4904141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4905141cc406Sopenharmony_ci
4906141cc406Sopenharmony_ci        /* Advanced Group */
4907141cc406Sopenharmony_ci        case OPT_AWD:
4908141cc406Sopenharmony_ci          *val_p = s->awd;
4909141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4910141cc406Sopenharmony_ci
4911141cc406Sopenharmony_ci        case OPT_ALD:
4912141cc406Sopenharmony_ci          *val_p = s->ald;
4913141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4914141cc406Sopenharmony_ci
4915141cc406Sopenharmony_ci        case OPT_COMPRESS:
4916141cc406Sopenharmony_ci          if(s->compress == COMP_JPEG){
4917141cc406Sopenharmony_ci            strcpy (val, STRING_JPEG);
4918141cc406Sopenharmony_ci          }
4919141cc406Sopenharmony_ci          else{
4920141cc406Sopenharmony_ci            strcpy (val, STRING_NONE);
4921141cc406Sopenharmony_ci          }
4922141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4923141cc406Sopenharmony_ci
4924141cc406Sopenharmony_ci        case OPT_COMPRESS_ARG:
4925141cc406Sopenharmony_ci          *val_p = s->compress_arg;
4926141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4927141cc406Sopenharmony_ci
4928141cc406Sopenharmony_ci        case OPT_DF_ACTION:
4929141cc406Sopenharmony_ci          switch (s->df_action) {
4930141cc406Sopenharmony_ci            case DF_DEFAULT:
4931141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4932141cc406Sopenharmony_ci              break;
4933141cc406Sopenharmony_ci            case DF_CONTINUE:
4934141cc406Sopenharmony_ci              strcpy (val, STRING_CONTINUE);
4935141cc406Sopenharmony_ci              break;
4936141cc406Sopenharmony_ci            case DF_STOP:
4937141cc406Sopenharmony_ci              strcpy (val, STRING_STOP);
4938141cc406Sopenharmony_ci              break;
4939141cc406Sopenharmony_ci          }
4940141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4941141cc406Sopenharmony_ci
4942141cc406Sopenharmony_ci        case OPT_DF_SKEW:
4943141cc406Sopenharmony_ci          *val_p = s->df_skew;
4944141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4945141cc406Sopenharmony_ci
4946141cc406Sopenharmony_ci        case OPT_DF_THICKNESS:
4947141cc406Sopenharmony_ci          *val_p = s->df_thickness;
4948141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4949141cc406Sopenharmony_ci
4950141cc406Sopenharmony_ci        case OPT_DF_LENGTH:
4951141cc406Sopenharmony_ci          *val_p = s->df_length;
4952141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4953141cc406Sopenharmony_ci
4954141cc406Sopenharmony_ci        case OPT_DF_DIFF:
4955141cc406Sopenharmony_ci          switch (s->df_diff) {
4956141cc406Sopenharmony_ci            case MSEL_df_diff_DEFAULT:
4957141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4958141cc406Sopenharmony_ci              break;
4959141cc406Sopenharmony_ci            case MSEL_df_diff_10MM:
4960141cc406Sopenharmony_ci              strcpy (val, STRING_10MM);
4961141cc406Sopenharmony_ci              break;
4962141cc406Sopenharmony_ci            case MSEL_df_diff_15MM:
4963141cc406Sopenharmony_ci              strcpy (val, STRING_15MM);
4964141cc406Sopenharmony_ci              break;
4965141cc406Sopenharmony_ci            case MSEL_df_diff_20MM:
4966141cc406Sopenharmony_ci              strcpy (val, STRING_20MM);
4967141cc406Sopenharmony_ci              break;
4968141cc406Sopenharmony_ci          }
4969141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4970141cc406Sopenharmony_ci
4971141cc406Sopenharmony_ci        case OPT_DF_RECOVERY:
4972141cc406Sopenharmony_ci          switch (s->df_recovery) {
4973141cc406Sopenharmony_ci            case MSEL_DEFAULT:
4974141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4975141cc406Sopenharmony_ci              break;
4976141cc406Sopenharmony_ci            case MSEL_ON:
4977141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
4978141cc406Sopenharmony_ci              break;
4979141cc406Sopenharmony_ci            case MSEL_OFF:
4980141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
4981141cc406Sopenharmony_ci              break;
4982141cc406Sopenharmony_ci          }
4983141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4984141cc406Sopenharmony_ci
4985141cc406Sopenharmony_ci        case OPT_PAPER_PROTECT:
4986141cc406Sopenharmony_ci          switch (s->paper_protect) {
4987141cc406Sopenharmony_ci            case MSEL_DEFAULT:
4988141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
4989141cc406Sopenharmony_ci              break;
4990141cc406Sopenharmony_ci            case MSEL_ON:
4991141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
4992141cc406Sopenharmony_ci              break;
4993141cc406Sopenharmony_ci            case MSEL_OFF:
4994141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
4995141cc406Sopenharmony_ci              break;
4996141cc406Sopenharmony_ci          }
4997141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
4998141cc406Sopenharmony_ci
4999141cc406Sopenharmony_ci        case OPT_ADV_PAPER_PROT:
5000141cc406Sopenharmony_ci          switch (s->adv_paper_prot) {
5001141cc406Sopenharmony_ci            case MSEL_DEFAULT:
5002141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5003141cc406Sopenharmony_ci              break;
5004141cc406Sopenharmony_ci            case MSEL_ON:
5005141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
5006141cc406Sopenharmony_ci              break;
5007141cc406Sopenharmony_ci            case MSEL_OFF:
5008141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
5009141cc406Sopenharmony_ci              break;
5010141cc406Sopenharmony_ci          }
5011141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5012141cc406Sopenharmony_ci
5013141cc406Sopenharmony_ci        case OPT_STAPLE_DETECT:
5014141cc406Sopenharmony_ci          switch (s->staple_detect) {
5015141cc406Sopenharmony_ci            case MSEL_DEFAULT:
5016141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5017141cc406Sopenharmony_ci              break;
5018141cc406Sopenharmony_ci            case MSEL_ON:
5019141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
5020141cc406Sopenharmony_ci              break;
5021141cc406Sopenharmony_ci            case MSEL_OFF:
5022141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
5023141cc406Sopenharmony_ci              break;
5024141cc406Sopenharmony_ci          }
5025141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5026141cc406Sopenharmony_ci
5027141cc406Sopenharmony_ci        case OPT_BG_COLOR:
5028141cc406Sopenharmony_ci          switch (s->bg_color) {
5029141cc406Sopenharmony_ci            case COLOR_DEFAULT:
5030141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5031141cc406Sopenharmony_ci              break;
5032141cc406Sopenharmony_ci            case COLOR_WHITE:
5033141cc406Sopenharmony_ci              strcpy (val, STRING_WHITE);
5034141cc406Sopenharmony_ci              break;
5035141cc406Sopenharmony_ci            case COLOR_BLACK:
5036141cc406Sopenharmony_ci              strcpy (val, STRING_BLACK);
5037141cc406Sopenharmony_ci              break;
5038141cc406Sopenharmony_ci          }
5039141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5040141cc406Sopenharmony_ci
5041141cc406Sopenharmony_ci        case OPT_DROPOUT_COLOR:
5042141cc406Sopenharmony_ci          switch (s->dropout_color) {
5043141cc406Sopenharmony_ci            case COLOR_DEFAULT:
5044141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5045141cc406Sopenharmony_ci              break;
5046141cc406Sopenharmony_ci            case COLOR_RED:
5047141cc406Sopenharmony_ci              strcpy (val, STRING_RED);
5048141cc406Sopenharmony_ci              break;
5049141cc406Sopenharmony_ci            case COLOR_GREEN:
5050141cc406Sopenharmony_ci              strcpy (val, STRING_GREEN);
5051141cc406Sopenharmony_ci              break;
5052141cc406Sopenharmony_ci            case COLOR_BLUE:
5053141cc406Sopenharmony_ci              strcpy (val, STRING_BLUE);
5054141cc406Sopenharmony_ci              break;
5055141cc406Sopenharmony_ci          }
5056141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5057141cc406Sopenharmony_ci
5058141cc406Sopenharmony_ci        case OPT_BUFF_MODE:
5059141cc406Sopenharmony_ci          switch (s->buff_mode) {
5060141cc406Sopenharmony_ci            case MSEL_DEFAULT:
5061141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5062141cc406Sopenharmony_ci              break;
5063141cc406Sopenharmony_ci            case MSEL_ON:
5064141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
5065141cc406Sopenharmony_ci              break;
5066141cc406Sopenharmony_ci            case MSEL_OFF:
5067141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
5068141cc406Sopenharmony_ci              break;
5069141cc406Sopenharmony_ci          }
5070141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5071141cc406Sopenharmony_ci
5072141cc406Sopenharmony_ci        case OPT_PREPICK:
5073141cc406Sopenharmony_ci          switch (s->prepick) {
5074141cc406Sopenharmony_ci            case MSEL_DEFAULT:
5075141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5076141cc406Sopenharmony_ci              break;
5077141cc406Sopenharmony_ci            case MSEL_ON:
5078141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
5079141cc406Sopenharmony_ci              break;
5080141cc406Sopenharmony_ci            case MSEL_OFF:
5081141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
5082141cc406Sopenharmony_ci              break;
5083141cc406Sopenharmony_ci          }
5084141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5085141cc406Sopenharmony_ci
5086141cc406Sopenharmony_ci        case OPT_OVERSCAN:
5087141cc406Sopenharmony_ci          switch (s->overscan) {
5088141cc406Sopenharmony_ci            case MSEL_DEFAULT:
5089141cc406Sopenharmony_ci              strcpy (val, STRING_DEFAULT);
5090141cc406Sopenharmony_ci              break;
5091141cc406Sopenharmony_ci            case MSEL_ON:
5092141cc406Sopenharmony_ci              strcpy (val, STRING_ON);
5093141cc406Sopenharmony_ci              break;
5094141cc406Sopenharmony_ci            case MSEL_OFF:
5095141cc406Sopenharmony_ci              strcpy (val, STRING_OFF);
5096141cc406Sopenharmony_ci              break;
5097141cc406Sopenharmony_ci          }
5098141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5099141cc406Sopenharmony_ci
5100141cc406Sopenharmony_ci        case OPT_SLEEP_TIME:
5101141cc406Sopenharmony_ci          *val_p = s->sleep_time;
5102141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5103141cc406Sopenharmony_ci
5104141cc406Sopenharmony_ci        case OPT_OFF_TIME:
5105141cc406Sopenharmony_ci          *val_p = s->off_time;
5106141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5107141cc406Sopenharmony_ci
5108141cc406Sopenharmony_ci        case OPT_DUPLEX_OFFSET:
5109141cc406Sopenharmony_ci          *val_p = s->duplex_offset;
5110141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5111141cc406Sopenharmony_ci
5112141cc406Sopenharmony_ci        case OPT_GREEN_OFFSET:
5113141cc406Sopenharmony_ci          *val_p = s->green_offset;
5114141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5115141cc406Sopenharmony_ci
5116141cc406Sopenharmony_ci        case OPT_BLUE_OFFSET:
5117141cc406Sopenharmony_ci          *val_p = s->blue_offset;
5118141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5119141cc406Sopenharmony_ci
5120141cc406Sopenharmony_ci        case OPT_LOW_MEM:
5121141cc406Sopenharmony_ci          *val_p = s->low_mem;
5122141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5123141cc406Sopenharmony_ci
5124141cc406Sopenharmony_ci        case OPT_SIDE:
5125141cc406Sopenharmony_ci          *val_p = s->side;
5126141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5127141cc406Sopenharmony_ci
5128141cc406Sopenharmony_ci        case OPT_HWDESKEWCROP:
5129141cc406Sopenharmony_ci          *val_p = s->hwdeskewcrop;
5130141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5131141cc406Sopenharmony_ci
5132141cc406Sopenharmony_ci        case OPT_SWDESKEW:
5133141cc406Sopenharmony_ci          *val_p = s->swdeskew;
5134141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5135141cc406Sopenharmony_ci
5136141cc406Sopenharmony_ci        case OPT_SWDESPECK:
5137141cc406Sopenharmony_ci          *val_p = s->swdespeck;
5138141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5139141cc406Sopenharmony_ci
5140141cc406Sopenharmony_ci        case OPT_SWCROP:
5141141cc406Sopenharmony_ci          *val_p = s->swcrop;
5142141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5143141cc406Sopenharmony_ci
5144141cc406Sopenharmony_ci        case OPT_SWSKIP:
5145141cc406Sopenharmony_ci          *val_p = SANE_FIX(s->swskip);
5146141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5147141cc406Sopenharmony_ci
5148141cc406Sopenharmony_ci        case OPT_HALT_ON_CANCEL:
5149141cc406Sopenharmony_ci          *val_p = s->halt_on_cancel;
5150141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5151141cc406Sopenharmony_ci
5152141cc406Sopenharmony_ci        /* Endorser Group */
5153141cc406Sopenharmony_ci        case OPT_ENDORSER:
5154141cc406Sopenharmony_ci          *val_p = s->u_endorser;
5155141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5156141cc406Sopenharmony_ci
5157141cc406Sopenharmony_ci        case OPT_ENDORSER_BITS:
5158141cc406Sopenharmony_ci          *val_p = s->u_endorser_bits;
5159141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5160141cc406Sopenharmony_ci
5161141cc406Sopenharmony_ci        case OPT_ENDORSER_VAL:
5162141cc406Sopenharmony_ci          *val_p = s->u_endorser_val;
5163141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5164141cc406Sopenharmony_ci
5165141cc406Sopenharmony_ci        case OPT_ENDORSER_STEP:
5166141cc406Sopenharmony_ci          *val_p = s->u_endorser_step;
5167141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5168141cc406Sopenharmony_ci
5169141cc406Sopenharmony_ci        case OPT_ENDORSER_Y:
5170141cc406Sopenharmony_ci          *val_p = SCANNER_UNIT_TO_FIXED_MM(s->u_endorser_y);
5171141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5172141cc406Sopenharmony_ci
5173141cc406Sopenharmony_ci        case OPT_ENDORSER_FONT:
5174141cc406Sopenharmony_ci          switch (s->u_endorser_font) {
5175141cc406Sopenharmony_ci            case FONT_H:
5176141cc406Sopenharmony_ci              strcpy (val, STRING_HORIZONTAL);
5177141cc406Sopenharmony_ci              break;
5178141cc406Sopenharmony_ci            case FONT_HB:
5179141cc406Sopenharmony_ci              strcpy (val, STRING_HORIZONTALBOLD);
5180141cc406Sopenharmony_ci              break;
5181141cc406Sopenharmony_ci            case FONT_HN:
5182141cc406Sopenharmony_ci              strcpy (val, STRING_HORIZONTALNARROW);
5183141cc406Sopenharmony_ci              break;
5184141cc406Sopenharmony_ci            case FONT_V:
5185141cc406Sopenharmony_ci              strcpy (val, STRING_VERTICAL);
5186141cc406Sopenharmony_ci              break;
5187141cc406Sopenharmony_ci            case FONT_VB:
5188141cc406Sopenharmony_ci              strcpy (val, STRING_VERTICALBOLD);
5189141cc406Sopenharmony_ci              break;
5190141cc406Sopenharmony_ci          }
5191141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5192141cc406Sopenharmony_ci
5193141cc406Sopenharmony_ci        case OPT_ENDORSER_DIR:
5194141cc406Sopenharmony_ci          switch (s->u_endorser_dir) {
5195141cc406Sopenharmony_ci            case DIR_TTB:
5196141cc406Sopenharmony_ci              strcpy (val, STRING_TOPTOBOTTOM);
5197141cc406Sopenharmony_ci              break;
5198141cc406Sopenharmony_ci            case DIR_BTT:
5199141cc406Sopenharmony_ci              strcpy (val, STRING_BOTTOMTOTOP);
5200141cc406Sopenharmony_ci              break;
5201141cc406Sopenharmony_ci          }
5202141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5203141cc406Sopenharmony_ci
5204141cc406Sopenharmony_ci        case OPT_ENDORSER_SIDE:
5205141cc406Sopenharmony_ci          switch (s->u_endorser_side) {
5206141cc406Sopenharmony_ci            case ED_front:
5207141cc406Sopenharmony_ci              strcpy (val, STRING_FRONT);
5208141cc406Sopenharmony_ci              break;
5209141cc406Sopenharmony_ci            case ED_back:
5210141cc406Sopenharmony_ci              strcpy (val, STRING_BACK);
5211141cc406Sopenharmony_ci              break;
5212141cc406Sopenharmony_ci          }
5213141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5214141cc406Sopenharmony_ci
5215141cc406Sopenharmony_ci        case OPT_ENDORSER_STRING:
5216141cc406Sopenharmony_ci	  strncpy(
5217141cc406Sopenharmony_ci	    (SANE_String)val,
5218141cc406Sopenharmony_ci	    (SANE_String)s->u_endorser_string,
5219141cc406Sopenharmony_ci	    s->endorser_string_len+1
5220141cc406Sopenharmony_ci	  );
5221141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5222141cc406Sopenharmony_ci
5223141cc406Sopenharmony_ci        /* Sensor Group */
5224141cc406Sopenharmony_ci        case OPT_TOP:
5225141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5226141cc406Sopenharmony_ci          *val_p = s->hw_top;
5227141cc406Sopenharmony_ci          return ret;
5228141cc406Sopenharmony_ci
5229141cc406Sopenharmony_ci        case OPT_A3:
5230141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5231141cc406Sopenharmony_ci          *val_p = s->hw_A3;
5232141cc406Sopenharmony_ci          return ret;
5233141cc406Sopenharmony_ci
5234141cc406Sopenharmony_ci        case OPT_B4:
5235141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5236141cc406Sopenharmony_ci          *val_p = s->hw_B4;
5237141cc406Sopenharmony_ci          return ret;
5238141cc406Sopenharmony_ci
5239141cc406Sopenharmony_ci        case OPT_A4:
5240141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5241141cc406Sopenharmony_ci          *val_p = s->hw_A4;
5242141cc406Sopenharmony_ci          return ret;
5243141cc406Sopenharmony_ci
5244141cc406Sopenharmony_ci        case OPT_B5:
5245141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5246141cc406Sopenharmony_ci          *val_p = s->hw_B5;
5247141cc406Sopenharmony_ci          return ret;
5248141cc406Sopenharmony_ci
5249141cc406Sopenharmony_ci        case OPT_HOPPER:
5250141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5251141cc406Sopenharmony_ci          *val_p = s->hw_hopper;
5252141cc406Sopenharmony_ci          return ret;
5253141cc406Sopenharmony_ci
5254141cc406Sopenharmony_ci        case OPT_OMR:
5255141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5256141cc406Sopenharmony_ci          *val_p = s->hw_omr;
5257141cc406Sopenharmony_ci          return ret;
5258141cc406Sopenharmony_ci
5259141cc406Sopenharmony_ci        case OPT_ADF_OPEN:
5260141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5261141cc406Sopenharmony_ci          *val_p = s->hw_adf_open;
5262141cc406Sopenharmony_ci          return ret;
5263141cc406Sopenharmony_ci
5264141cc406Sopenharmony_ci        case OPT_CARD_LOADED:
5265141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5266141cc406Sopenharmony_ci          *val_p = s->hw_card_loaded;
5267141cc406Sopenharmony_ci          return ret;
5268141cc406Sopenharmony_ci
5269141cc406Sopenharmony_ci        case OPT_SLEEP:
5270141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5271141cc406Sopenharmony_ci          *val_p = s->hw_sleep;
5272141cc406Sopenharmony_ci          return ret;
5273141cc406Sopenharmony_ci
5274141cc406Sopenharmony_ci        case OPT_SEND_SW:
5275141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5276141cc406Sopenharmony_ci          *val_p = s->hw_send_sw;
5277141cc406Sopenharmony_ci          return ret;
5278141cc406Sopenharmony_ci
5279141cc406Sopenharmony_ci        case OPT_MANUAL_FEED:
5280141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5281141cc406Sopenharmony_ci          *val_p = s->hw_manual_feed;
5282141cc406Sopenharmony_ci          return ret;
5283141cc406Sopenharmony_ci
5284141cc406Sopenharmony_ci        case OPT_SCAN_SW:
5285141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5286141cc406Sopenharmony_ci          *val_p = s->hw_scan_sw;
5287141cc406Sopenharmony_ci          return ret;
5288141cc406Sopenharmony_ci
5289141cc406Sopenharmony_ci        case OPT_FUNCTION:
5290141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5291141cc406Sopenharmony_ci          *val_p = s->hw_function;
5292141cc406Sopenharmony_ci          return ret;
5293141cc406Sopenharmony_ci
5294141cc406Sopenharmony_ci        case OPT_INK_EMPTY:
5295141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5296141cc406Sopenharmony_ci          *val_p = s->hw_ink_empty;
5297141cc406Sopenharmony_ci          return ret;
5298141cc406Sopenharmony_ci
5299141cc406Sopenharmony_ci        case OPT_DOUBLE_FEED:
5300141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5301141cc406Sopenharmony_ci          *val_p = s->hw_double_feed;
5302141cc406Sopenharmony_ci          return ret;
5303141cc406Sopenharmony_ci
5304141cc406Sopenharmony_ci        case OPT_ERROR_CODE:
5305141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5306141cc406Sopenharmony_ci          *val_p = s->hw_error_code;
5307141cc406Sopenharmony_ci          return ret;
5308141cc406Sopenharmony_ci
5309141cc406Sopenharmony_ci        case OPT_SKEW_ANGLE:
5310141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5311141cc406Sopenharmony_ci          *val_p = s->hw_skew_angle;
5312141cc406Sopenharmony_ci          return ret;
5313141cc406Sopenharmony_ci
5314141cc406Sopenharmony_ci        case OPT_INK_REMAIN:
5315141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5316141cc406Sopenharmony_ci          *val_p = s->hw_ink_remain;
5317141cc406Sopenharmony_ci          return ret;
5318141cc406Sopenharmony_ci
5319141cc406Sopenharmony_ci        case OPT_DENSITY_SW:
5320141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5321141cc406Sopenharmony_ci          *val_p = s->hw_density_sw;
5322141cc406Sopenharmony_ci          return ret;
5323141cc406Sopenharmony_ci
5324141cc406Sopenharmony_ci        case OPT_DUPLEX_SW:
5325141cc406Sopenharmony_ci          ret = get_hardware_status(s,option);
5326141cc406Sopenharmony_ci          *val_p = s->hw_duplex_sw;
5327141cc406Sopenharmony_ci          return ret;
5328141cc406Sopenharmony_ci
5329141cc406Sopenharmony_ci      }
5330141cc406Sopenharmony_ci  }
5331141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE) {
5332141cc406Sopenharmony_ci      int tmp;
5333141cc406Sopenharmony_ci      SANE_Word val_c;
5334141cc406Sopenharmony_ci      SANE_Status status;
5335141cc406Sopenharmony_ci
5336141cc406Sopenharmony_ci      DBG (20, "sane_control_option: set value for '%s' (%d)\n", s->opt[option].name,option);
5337141cc406Sopenharmony_ci
5338141cc406Sopenharmony_ci      if ( s->started ) {
5339141cc406Sopenharmony_ci        DBG (5, "sane_control_option: can't set, device busy\n");
5340141cc406Sopenharmony_ci        return SANE_STATUS_DEVICE_BUSY;
5341141cc406Sopenharmony_ci      }
5342141cc406Sopenharmony_ci
5343141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap)) {
5344141cc406Sopenharmony_ci        DBG (5, "sane_control_option: not settable\n");
5345141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
5346141cc406Sopenharmony_ci      }
5347141cc406Sopenharmony_ci
5348141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, info);
5349141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD) {
5350141cc406Sopenharmony_ci        DBG (5, "sane_control_option: bad value\n");
5351141cc406Sopenharmony_ci        return status;
5352141cc406Sopenharmony_ci      }
5353141cc406Sopenharmony_ci
5354141cc406Sopenharmony_ci      /* may have been changed by constrain, so don't copy until now */
5355141cc406Sopenharmony_ci      val_c = *(SANE_Word *)val;
5356141cc406Sopenharmony_ci
5357141cc406Sopenharmony_ci      /*
5358141cc406Sopenharmony_ci       * Note - for those options which can assume one of a list of
5359141cc406Sopenharmony_ci       * valid values, we can safely assume that they will have
5360141cc406Sopenharmony_ci       * exactly one of those values because that's what
5361141cc406Sopenharmony_ci       * sanei_constrain_value does. Hence no "else: invalid" branches
5362141cc406Sopenharmony_ci       * below.
5363141cc406Sopenharmony_ci       */
5364141cc406Sopenharmony_ci      switch (option) {
5365141cc406Sopenharmony_ci
5366141cc406Sopenharmony_ci        /* Mode Group */
5367141cc406Sopenharmony_ci        case OPT_SOURCE:
5368141cc406Sopenharmony_ci          if (!strcmp (val, STRING_ADFFRONT)) {
5369141cc406Sopenharmony_ci            tmp = SOURCE_ADF_FRONT;
5370141cc406Sopenharmony_ci          }
5371141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_ADFBACK)) {
5372141cc406Sopenharmony_ci            tmp = SOURCE_ADF_BACK;
5373141cc406Sopenharmony_ci          }
5374141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_ADFDUPLEX)) {
5375141cc406Sopenharmony_ci            tmp = SOURCE_ADF_DUPLEX;
5376141cc406Sopenharmony_ci          }
5377141cc406Sopenharmony_ci	  else if (!strcmp (val, STRING_CARDFRONT)) {
5378141cc406Sopenharmony_ci            tmp = SOURCE_CARD_FRONT;
5379141cc406Sopenharmony_ci          }
5380141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_CARDBACK)) {
5381141cc406Sopenharmony_ci            tmp = SOURCE_CARD_BACK;
5382141cc406Sopenharmony_ci          }
5383141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_CARDDUPLEX)) {
5384141cc406Sopenharmony_ci            tmp = SOURCE_CARD_DUPLEX;
5385141cc406Sopenharmony_ci          }
5386141cc406Sopenharmony_ci          else{
5387141cc406Sopenharmony_ci            tmp = SOURCE_FLATBED;
5388141cc406Sopenharmony_ci          }
5389141cc406Sopenharmony_ci
5390141cc406Sopenharmony_ci          if (s->source == tmp)
5391141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5392141cc406Sopenharmony_ci
5393141cc406Sopenharmony_ci          s->source = tmp;
5394141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5395141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5396141cc406Sopenharmony_ci
5397141cc406Sopenharmony_ci        case OPT_MODE:
5398141cc406Sopenharmony_ci          if (!strcmp (val, STRING_LINEART)) {
5399141cc406Sopenharmony_ci            tmp = MODE_LINEART;
5400141cc406Sopenharmony_ci          }
5401141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_HALFTONE)) {
5402141cc406Sopenharmony_ci            tmp = MODE_HALFTONE;
5403141cc406Sopenharmony_ci          }
5404141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_GRAYSCALE)) {
5405141cc406Sopenharmony_ci            tmp = MODE_GRAYSCALE;
5406141cc406Sopenharmony_ci          }
5407141cc406Sopenharmony_ci          else{
5408141cc406Sopenharmony_ci            tmp = MODE_COLOR;
5409141cc406Sopenharmony_ci          }
5410141cc406Sopenharmony_ci
5411141cc406Sopenharmony_ci          if (tmp == s->u_mode)
5412141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5413141cc406Sopenharmony_ci
5414141cc406Sopenharmony_ci          set_mode(s,tmp);
5415141cc406Sopenharmony_ci
5416141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5417141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5418141cc406Sopenharmony_ci
5419141cc406Sopenharmony_ci        case OPT_RES:
5420141cc406Sopenharmony_ci
5421141cc406Sopenharmony_ci          if (s->resolution_x == val_c)
5422141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5423141cc406Sopenharmony_ci
5424141cc406Sopenharmony_ci          s->resolution_x = val_c;
5425141cc406Sopenharmony_ci          s->resolution_y = val_c;
5426141cc406Sopenharmony_ci          set_max_y(s);
5427141cc406Sopenharmony_ci
5428141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5429141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5430141cc406Sopenharmony_ci
5431141cc406Sopenharmony_ci        /* Geometry Group */
5432141cc406Sopenharmony_ci        case OPT_TL_X:
5433141cc406Sopenharmony_ci          if (s->tl_x == FIXED_MM_TO_SCANNER_UNIT(val_c))
5434141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5435141cc406Sopenharmony_ci
5436141cc406Sopenharmony_ci          s->tl_x = FIXED_MM_TO_SCANNER_UNIT(val_c);
5437141cc406Sopenharmony_ci
5438141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5439141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5440141cc406Sopenharmony_ci
5441141cc406Sopenharmony_ci        case OPT_TL_Y:
5442141cc406Sopenharmony_ci          if (s->tl_y == FIXED_MM_TO_SCANNER_UNIT(val_c))
5443141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5444141cc406Sopenharmony_ci
5445141cc406Sopenharmony_ci          s->tl_y = FIXED_MM_TO_SCANNER_UNIT(val_c);
5446141cc406Sopenharmony_ci
5447141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5448141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5449141cc406Sopenharmony_ci
5450141cc406Sopenharmony_ci        case OPT_BR_X:
5451141cc406Sopenharmony_ci          if (s->br_x == FIXED_MM_TO_SCANNER_UNIT(val_c))
5452141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5453141cc406Sopenharmony_ci
5454141cc406Sopenharmony_ci          s->br_x = FIXED_MM_TO_SCANNER_UNIT(val_c);
5455141cc406Sopenharmony_ci
5456141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5457141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5458141cc406Sopenharmony_ci
5459141cc406Sopenharmony_ci        case OPT_BR_Y:
5460141cc406Sopenharmony_ci          if (s->br_y == FIXED_MM_TO_SCANNER_UNIT(val_c))
5461141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5462141cc406Sopenharmony_ci
5463141cc406Sopenharmony_ci          s->br_y = FIXED_MM_TO_SCANNER_UNIT(val_c);
5464141cc406Sopenharmony_ci
5465141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
5466141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5467141cc406Sopenharmony_ci
5468141cc406Sopenharmony_ci        case OPT_PAGE_WIDTH:
5469141cc406Sopenharmony_ci          if (s->page_width == FIXED_MM_TO_SCANNER_UNIT(val_c))
5470141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5471141cc406Sopenharmony_ci
5472141cc406Sopenharmony_ci          /* if full width image, and paper size is changed,
5473141cc406Sopenharmony_ci             change the image size to match new paper */
5474141cc406Sopenharmony_ci          if (s->tl_x == 0 && s->br_x == s->page_width){
5475141cc406Sopenharmony_ci              DBG (20, "sane_control_option: br_x tracking page_width\n");
5476141cc406Sopenharmony_ci              s->br_x = FIXED_MM_TO_SCANNER_UNIT(val_c);
5477141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS;
5478141cc406Sopenharmony_ci          }
5479141cc406Sopenharmony_ci
5480141cc406Sopenharmony_ci          s->page_width = FIXED_MM_TO_SCANNER_UNIT(val_c);
5481141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5482141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5483141cc406Sopenharmony_ci
5484141cc406Sopenharmony_ci        case OPT_PAGE_HEIGHT:
5485141cc406Sopenharmony_ci          if (s->page_height == FIXED_MM_TO_SCANNER_UNIT(val_c))
5486141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5487141cc406Sopenharmony_ci
5488141cc406Sopenharmony_ci          /* if full height image, and paper size is changed,
5489141cc406Sopenharmony_ci             change the image size to match new paper */
5490141cc406Sopenharmony_ci          if (s->tl_y == 0 && s->br_y == s->page_height){
5491141cc406Sopenharmony_ci              DBG (20, "sane_control_option: br_y tracking page_height\n");
5492141cc406Sopenharmony_ci              s->br_y = FIXED_MM_TO_SCANNER_UNIT(val_c);
5493141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS;
5494141cc406Sopenharmony_ci          }
5495141cc406Sopenharmony_ci
5496141cc406Sopenharmony_ci          s->page_height = FIXED_MM_TO_SCANNER_UNIT(val_c);
5497141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5498141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5499141cc406Sopenharmony_ci
5500141cc406Sopenharmony_ci        /* Enhancement Group */
5501141cc406Sopenharmony_ci        case OPT_BRIGHTNESS:
5502141cc406Sopenharmony_ci          s->brightness = val_c;
5503141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5504141cc406Sopenharmony_ci
5505141cc406Sopenharmony_ci        case OPT_CONTRAST:
5506141cc406Sopenharmony_ci          s->contrast = val_c;
5507141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5508141cc406Sopenharmony_ci
5509141cc406Sopenharmony_ci        case OPT_GAMMA:
5510141cc406Sopenharmony_ci          s->gamma = SANE_UNFIX(val_c);
5511141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5512141cc406Sopenharmony_ci
5513141cc406Sopenharmony_ci        case OPT_THRESHOLD:
5514141cc406Sopenharmony_ci          s->threshold = val_c;
5515141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5516141cc406Sopenharmony_ci
5517141cc406Sopenharmony_ci        /* IPC */
5518141cc406Sopenharmony_ci        case OPT_RIF:
5519141cc406Sopenharmony_ci          s->rif = val_c;
5520141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5521141cc406Sopenharmony_ci
5522141cc406Sopenharmony_ci        case OPT_HT_TYPE:
5523141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5524141cc406Sopenharmony_ci            s->ht_type = WD_ht_type_DEFAULT;
5525141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_DITHER))
5526141cc406Sopenharmony_ci            s->ht_type = WD_ht_type_DITHER;
5527141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_DIFFUSION))
5528141cc406Sopenharmony_ci            s->ht_type = WD_ht_type_DIFFUSION;
5529141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5530141cc406Sopenharmony_ci
5531141cc406Sopenharmony_ci        case OPT_HT_PATTERN:
5532141cc406Sopenharmony_ci          s->ht_pattern = val_c;
5533141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5534141cc406Sopenharmony_ci
5535141cc406Sopenharmony_ci        case OPT_OUTLINE:
5536141cc406Sopenharmony_ci          s->outline = val_c;
5537141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5538141cc406Sopenharmony_ci
5539141cc406Sopenharmony_ci        case OPT_EMPHASIS:
5540141cc406Sopenharmony_ci          s->emphasis = val_c;
5541141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5542141cc406Sopenharmony_ci
5543141cc406Sopenharmony_ci        case OPT_SEPARATION:
5544141cc406Sopenharmony_ci          s->separation = val_c;
5545141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5546141cc406Sopenharmony_ci
5547141cc406Sopenharmony_ci        case OPT_MIRRORING:
5548141cc406Sopenharmony_ci          s->mirroring = val_c;
5549141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5550141cc406Sopenharmony_ci
5551141cc406Sopenharmony_ci        case OPT_WL_FOLLOW:
5552141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5553141cc406Sopenharmony_ci            s->wl_follow = WD_wl_follow_DEFAULT;
5554141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5555141cc406Sopenharmony_ci            s->wl_follow = WD_wl_follow_ON;
5556141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5557141cc406Sopenharmony_ci            s->wl_follow = WD_wl_follow_OFF;
5558141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5559141cc406Sopenharmony_ci
5560141cc406Sopenharmony_ci        /* DTC params*/
5561141cc406Sopenharmony_ci        case OPT_BP_FILTER:
5562141cc406Sopenharmony_ci          s->bp_filter = val_c;
5563141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5564141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5565141cc406Sopenharmony_ci
5566141cc406Sopenharmony_ci        case OPT_SMOOTHING:
5567141cc406Sopenharmony_ci          s->smoothing = val_c;
5568141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5569141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5570141cc406Sopenharmony_ci
5571141cc406Sopenharmony_ci        case OPT_GAMMA_CURVE:
5572141cc406Sopenharmony_ci          s->gamma_curve = val_c;
5573141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5574141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5575141cc406Sopenharmony_ci
5576141cc406Sopenharmony_ci        case OPT_THRESHOLD_CURVE:
5577141cc406Sopenharmony_ci          s->threshold_curve = val_c;
5578141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5579141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5580141cc406Sopenharmony_ci
5581141cc406Sopenharmony_ci        case OPT_THRESHOLD_WHITE:
5582141cc406Sopenharmony_ci          s->threshold_white = val_c;
5583141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5584141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5585141cc406Sopenharmony_ci
5586141cc406Sopenharmony_ci        case OPT_NOISE_REMOVAL:
5587141cc406Sopenharmony_ci          s->noise_removal = val_c;
5588141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5589141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5590141cc406Sopenharmony_ci
5591141cc406Sopenharmony_ci        case OPT_MATRIX_5:
5592141cc406Sopenharmony_ci          s->matrix_5 = val_c;
5593141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5594141cc406Sopenharmony_ci
5595141cc406Sopenharmony_ci        case OPT_MATRIX_4:
5596141cc406Sopenharmony_ci          s->matrix_4 = val_c;
5597141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5598141cc406Sopenharmony_ci
5599141cc406Sopenharmony_ci        case OPT_MATRIX_3:
5600141cc406Sopenharmony_ci          s->matrix_3 = val_c;
5601141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5602141cc406Sopenharmony_ci
5603141cc406Sopenharmony_ci        case OPT_MATRIX_2:
5604141cc406Sopenharmony_ci          s->matrix_2 = val_c;
5605141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5606141cc406Sopenharmony_ci
5607141cc406Sopenharmony_ci        /* SDTC params*/
5608141cc406Sopenharmony_ci        case OPT_VARIANCE:
5609141cc406Sopenharmony_ci          s->variance = val_c;
5610141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5611141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5612141cc406Sopenharmony_ci
5613141cc406Sopenharmony_ci        /* Advanced Group */
5614141cc406Sopenharmony_ci        case OPT_AWD:
5615141cc406Sopenharmony_ci          s->awd = val_c;
5616141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5617141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5618141cc406Sopenharmony_ci
5619141cc406Sopenharmony_ci        case OPT_ALD:
5620141cc406Sopenharmony_ci          s->ald = val_c;
5621141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5622141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5623141cc406Sopenharmony_ci
5624141cc406Sopenharmony_ci        case OPT_COMPRESS:
5625141cc406Sopenharmony_ci          if (!strcmp (val, STRING_JPEG)) {
5626141cc406Sopenharmony_ci            tmp = COMP_JPEG;
5627141cc406Sopenharmony_ci          }
5628141cc406Sopenharmony_ci          else{
5629141cc406Sopenharmony_ci            tmp = COMP_NONE;
5630141cc406Sopenharmony_ci          }
5631141cc406Sopenharmony_ci
5632141cc406Sopenharmony_ci          if (tmp == s->compress)
5633141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
5634141cc406Sopenharmony_ci
5635141cc406Sopenharmony_ci          s->compress = tmp;
5636141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5637141cc406Sopenharmony_ci
5638141cc406Sopenharmony_ci        case OPT_COMPRESS_ARG:
5639141cc406Sopenharmony_ci          s->compress_arg = val_c;
5640141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5641141cc406Sopenharmony_ci
5642141cc406Sopenharmony_ci        case OPT_DF_ACTION:
5643141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5644141cc406Sopenharmony_ci            s->df_action = DF_DEFAULT;
5645141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_CONTINUE))
5646141cc406Sopenharmony_ci            s->df_action = DF_CONTINUE;
5647141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_STOP))
5648141cc406Sopenharmony_ci            s->df_action = DF_STOP;
5649141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5650141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5651141cc406Sopenharmony_ci
5652141cc406Sopenharmony_ci        case OPT_DF_SKEW:
5653141cc406Sopenharmony_ci          s->df_skew = val_c;
5654141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5655141cc406Sopenharmony_ci
5656141cc406Sopenharmony_ci        case OPT_DF_THICKNESS:
5657141cc406Sopenharmony_ci          s->df_thickness = val_c;
5658141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5659141cc406Sopenharmony_ci
5660141cc406Sopenharmony_ci        case OPT_DF_LENGTH:
5661141cc406Sopenharmony_ci          s->df_length = val_c;
5662141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5663141cc406Sopenharmony_ci
5664141cc406Sopenharmony_ci        case OPT_DF_DIFF:
5665141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5666141cc406Sopenharmony_ci            s->df_diff = MSEL_df_diff_DEFAULT;
5667141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_10MM))
5668141cc406Sopenharmony_ci            s->df_diff = MSEL_df_diff_10MM;
5669141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_15MM))
5670141cc406Sopenharmony_ci            s->df_diff = MSEL_df_diff_15MM;
5671141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_20MM))
5672141cc406Sopenharmony_ci            s->df_diff = MSEL_df_diff_20MM;
5673141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5674141cc406Sopenharmony_ci
5675141cc406Sopenharmony_ci        case OPT_DF_RECOVERY:
5676141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5677141cc406Sopenharmony_ci            s->df_recovery = MSEL_DEFAULT;
5678141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5679141cc406Sopenharmony_ci            s->df_recovery = MSEL_ON;
5680141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5681141cc406Sopenharmony_ci            s->df_recovery = MSEL_OFF;
5682141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5683141cc406Sopenharmony_ci
5684141cc406Sopenharmony_ci        case OPT_PAPER_PROTECT:
5685141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5686141cc406Sopenharmony_ci            s->paper_protect = MSEL_DEFAULT;
5687141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5688141cc406Sopenharmony_ci            s->paper_protect = MSEL_ON;
5689141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5690141cc406Sopenharmony_ci            s->paper_protect = MSEL_OFF;
5691141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5692141cc406Sopenharmony_ci
5693141cc406Sopenharmony_ci        case OPT_ADV_PAPER_PROT:
5694141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5695141cc406Sopenharmony_ci            s->adv_paper_prot = MSEL_DEFAULT;
5696141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5697141cc406Sopenharmony_ci            s->adv_paper_prot = MSEL_ON;
5698141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5699141cc406Sopenharmony_ci            s->adv_paper_prot = MSEL_OFF;
5700141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5701141cc406Sopenharmony_ci
5702141cc406Sopenharmony_ci        case OPT_STAPLE_DETECT:
5703141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5704141cc406Sopenharmony_ci            s->staple_detect = MSEL_DEFAULT;
5705141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5706141cc406Sopenharmony_ci            s->staple_detect = MSEL_ON;
5707141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5708141cc406Sopenharmony_ci            s->staple_detect = MSEL_OFF;
5709141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5710141cc406Sopenharmony_ci
5711141cc406Sopenharmony_ci        case OPT_BG_COLOR:
5712141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5713141cc406Sopenharmony_ci            s->bg_color = COLOR_DEFAULT;
5714141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_WHITE))
5715141cc406Sopenharmony_ci            s->bg_color = COLOR_WHITE;
5716141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_BLACK))
5717141cc406Sopenharmony_ci            s->bg_color = COLOR_BLACK;
5718141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5719141cc406Sopenharmony_ci
5720141cc406Sopenharmony_ci        case OPT_DROPOUT_COLOR:
5721141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5722141cc406Sopenharmony_ci            s->dropout_color = COLOR_DEFAULT;
5723141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_RED))
5724141cc406Sopenharmony_ci            s->dropout_color = COLOR_RED;
5725141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_GREEN))
5726141cc406Sopenharmony_ci            s->dropout_color = COLOR_GREEN;
5727141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_BLUE))
5728141cc406Sopenharmony_ci            s->dropout_color = COLOR_BLUE;
5729141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5730141cc406Sopenharmony_ci
5731141cc406Sopenharmony_ci        case OPT_BUFF_MODE:
5732141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5733141cc406Sopenharmony_ci            s->buff_mode = MSEL_DEFAULT;
5734141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5735141cc406Sopenharmony_ci            s->buff_mode= MSEL_ON;
5736141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5737141cc406Sopenharmony_ci            s->buff_mode= MSEL_OFF;
5738141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5739141cc406Sopenharmony_ci
5740141cc406Sopenharmony_ci        case OPT_PREPICK:
5741141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5742141cc406Sopenharmony_ci            s->prepick = MSEL_DEFAULT;
5743141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5744141cc406Sopenharmony_ci            s->prepick = MSEL_ON;
5745141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5746141cc406Sopenharmony_ci            s->prepick = MSEL_OFF;
5747141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5748141cc406Sopenharmony_ci
5749141cc406Sopenharmony_ci        case OPT_OVERSCAN:
5750141cc406Sopenharmony_ci          if (!strcmp(val, STRING_DEFAULT))
5751141cc406Sopenharmony_ci            s->overscan = MSEL_DEFAULT;
5752141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_ON))
5753141cc406Sopenharmony_ci            s->overscan = MSEL_ON;
5754141cc406Sopenharmony_ci          else if (!strcmp(val, STRING_OFF))
5755141cc406Sopenharmony_ci            s->overscan = MSEL_OFF;
5756141cc406Sopenharmony_ci
5757141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5758141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5759141cc406Sopenharmony_ci
5760141cc406Sopenharmony_ci        case OPT_SLEEP_TIME:
5761141cc406Sopenharmony_ci          s->sleep_time = val_c;
5762141cc406Sopenharmony_ci          return set_sleep_mode(s);
5763141cc406Sopenharmony_ci
5764141cc406Sopenharmony_ci        case OPT_OFF_TIME:
5765141cc406Sopenharmony_ci          /* do our own constrain, because we want to round up */
5766141cc406Sopenharmony_ci          s->off_time = (val_c + 14)/15*15;
5767141cc406Sopenharmony_ci          if(s->off_time != val_c){
5768141cc406Sopenharmony_ci            *info |= SANE_INFO_INEXACT;
5769141cc406Sopenharmony_ci          }
5770141cc406Sopenharmony_ci          return set_off_mode(s);
5771141cc406Sopenharmony_ci
5772141cc406Sopenharmony_ci        case OPT_DUPLEX_OFFSET:
5773141cc406Sopenharmony_ci          s->duplex_offset = val_c;
5774141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5775141cc406Sopenharmony_ci
5776141cc406Sopenharmony_ci        case OPT_GREEN_OFFSET:
5777141cc406Sopenharmony_ci          s->green_offset = val_c;
5778141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5779141cc406Sopenharmony_ci
5780141cc406Sopenharmony_ci        case OPT_BLUE_OFFSET:
5781141cc406Sopenharmony_ci          s->blue_offset = val_c;
5782141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5783141cc406Sopenharmony_ci
5784141cc406Sopenharmony_ci        case OPT_LOW_MEM:
5785141cc406Sopenharmony_ci          s->low_mem = val_c;
5786141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5787141cc406Sopenharmony_ci
5788141cc406Sopenharmony_ci        case OPT_HWDESKEWCROP:
5789141cc406Sopenharmony_ci          s->hwdeskewcrop = val_c;
5790141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5791141cc406Sopenharmony_ci
5792141cc406Sopenharmony_ci        case OPT_SWDESKEW:
5793141cc406Sopenharmony_ci          s->swdeskew = val_c;
5794141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5795141cc406Sopenharmony_ci
5796141cc406Sopenharmony_ci        case OPT_SWDESPECK:
5797141cc406Sopenharmony_ci          s->swdespeck = val_c;
5798141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5799141cc406Sopenharmony_ci
5800141cc406Sopenharmony_ci        case OPT_SWCROP:
5801141cc406Sopenharmony_ci          s->swcrop = val_c;
5802141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5803141cc406Sopenharmony_ci
5804141cc406Sopenharmony_ci        case OPT_SWSKIP:
5805141cc406Sopenharmony_ci          s->swskip = SANE_UNFIX(val_c);
5806141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5807141cc406Sopenharmony_ci
5808141cc406Sopenharmony_ci        case OPT_HALT_ON_CANCEL:
5809141cc406Sopenharmony_ci          s->halt_on_cancel = val_c;
5810141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5811141cc406Sopenharmony_ci
5812141cc406Sopenharmony_ci        /* Endorser Group */
5813141cc406Sopenharmony_ci        case OPT_ENDORSER:
5814141cc406Sopenharmony_ci          s->u_endorser = val_c;
5815141cc406Sopenharmony_ci          *info |= SANE_INFO_RELOAD_OPTIONS;
5816141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5817141cc406Sopenharmony_ci
5818141cc406Sopenharmony_ci        case OPT_ENDORSER_BITS:
5819141cc406Sopenharmony_ci          s->u_endorser_bits = val_c;
5820141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5821141cc406Sopenharmony_ci
5822141cc406Sopenharmony_ci	/*this val not used in send_endorser*/
5823141cc406Sopenharmony_ci        case OPT_ENDORSER_VAL:
5824141cc406Sopenharmony_ci          s->u_endorser_val = val_c;
5825141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5826141cc406Sopenharmony_ci
5827141cc406Sopenharmony_ci        case OPT_ENDORSER_STEP:
5828141cc406Sopenharmony_ci          s->u_endorser_step = val_c;
5829141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5830141cc406Sopenharmony_ci
5831141cc406Sopenharmony_ci        case OPT_ENDORSER_Y:
5832141cc406Sopenharmony_ci          s->u_endorser_y = FIXED_MM_TO_SCANNER_UNIT(val_c);
5833141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5834141cc406Sopenharmony_ci
5835141cc406Sopenharmony_ci        case OPT_ENDORSER_FONT:
5836141cc406Sopenharmony_ci
5837141cc406Sopenharmony_ci          if (!strcmp (val, STRING_HORIZONTAL)){
5838141cc406Sopenharmony_ci            s->u_endorser_font = FONT_H;
5839141cc406Sopenharmony_ci          }
5840141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_HORIZONTALBOLD)){
5841141cc406Sopenharmony_ci            s->u_endorser_font = FONT_HB;
5842141cc406Sopenharmony_ci          }
5843141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_HORIZONTALNARROW)){
5844141cc406Sopenharmony_ci            s->u_endorser_font = FONT_HN;
5845141cc406Sopenharmony_ci          }
5846141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_VERTICAL)){
5847141cc406Sopenharmony_ci            s->u_endorser_font = FONT_V;
5848141cc406Sopenharmony_ci          }
5849141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_VERTICALBOLD)){
5850141cc406Sopenharmony_ci            s->u_endorser_font = FONT_VB;
5851141cc406Sopenharmony_ci          }
5852141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5853141cc406Sopenharmony_ci
5854141cc406Sopenharmony_ci        case OPT_ENDORSER_DIR:
5855141cc406Sopenharmony_ci          if (!strcmp (val, STRING_TOPTOBOTTOM)){
5856141cc406Sopenharmony_ci            s->u_endorser_dir = DIR_TTB;
5857141cc406Sopenharmony_ci          }
5858141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_BOTTOMTOTOP)){
5859141cc406Sopenharmony_ci            s->u_endorser_dir = DIR_BTT;
5860141cc406Sopenharmony_ci          }
5861141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5862141cc406Sopenharmony_ci
5863141cc406Sopenharmony_ci	/*this val not used in send_endorser*/
5864141cc406Sopenharmony_ci        case OPT_ENDORSER_SIDE:
5865141cc406Sopenharmony_ci          if (!strcmp (val, STRING_FRONT)){
5866141cc406Sopenharmony_ci            s->u_endorser_side = ED_front;
5867141cc406Sopenharmony_ci          }
5868141cc406Sopenharmony_ci          else if (!strcmp (val, STRING_BACK)){
5869141cc406Sopenharmony_ci            s->u_endorser_side = ED_back;
5870141cc406Sopenharmony_ci          }
5871141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5872141cc406Sopenharmony_ci
5873141cc406Sopenharmony_ci        case OPT_ENDORSER_STRING:
5874141cc406Sopenharmony_ci	  strncpy(
5875141cc406Sopenharmony_ci	    (SANE_String)s->u_endorser_string,
5876141cc406Sopenharmony_ci	    (SANE_String)val,
5877141cc406Sopenharmony_ci	    s->endorser_string_len+1
5878141cc406Sopenharmony_ci	  );
5879141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5880141cc406Sopenharmony_ci      }                       /* switch */
5881141cc406Sopenharmony_ci  }                           /* else */
5882141cc406Sopenharmony_ci
5883141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
5884141cc406Sopenharmony_ci}
5885141cc406Sopenharmony_ci
5886141cc406Sopenharmony_cistatic SANE_Status
5887141cc406Sopenharmony_ciset_sleep_mode(struct fujitsu *s)
5888141cc406Sopenharmony_ci{
5889141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
5890141cc406Sopenharmony_ci
5891141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
5892141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
5893141cc406Sopenharmony_ci
5894141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
5895141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
5896141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
5897141cc406Sopenharmony_ci
5898141cc406Sopenharmony_ci  DBG (10, "set_sleep_mode: start\n");
5899141cc406Sopenharmony_ci
5900141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
5901141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
5902141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
5903141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
5904141cc406Sopenharmony_ci
5905141cc406Sopenharmony_ci  memset(out,0,outLen);
5906141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_sleep);
5907141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
5908141cc406Sopenharmony_ci  set_MSEL_sleep_mode(page, s->sleep_time);
5909141cc406Sopenharmony_ci
5910141cc406Sopenharmony_ci  ret = do_cmd (
5911141cc406Sopenharmony_ci    s, 1, 0,
5912141cc406Sopenharmony_ci    cmd, cmdLen,
5913141cc406Sopenharmony_ci    out, outLen,
5914141cc406Sopenharmony_ci    NULL, NULL
5915141cc406Sopenharmony_ci  );
5916141cc406Sopenharmony_ci
5917141cc406Sopenharmony_ci  DBG (10, "set_sleep_mode: finish\n");
5918141cc406Sopenharmony_ci
5919141cc406Sopenharmony_ci  return ret;
5920141cc406Sopenharmony_ci}
5921141cc406Sopenharmony_ci
5922141cc406Sopenharmony_cistatic SANE_Status
5923141cc406Sopenharmony_ciset_off_mode(struct fujitsu *s)
5924141cc406Sopenharmony_ci{
5925141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
5926141cc406Sopenharmony_ci
5927141cc406Sopenharmony_ci  unsigned char cmd[SEND_DIAGNOSTIC_len]; /*also big enough for READ_DIAG*/
5928141cc406Sopenharmony_ci  size_t cmdLen = SEND_DIAGNOSTIC_len;
5929141cc406Sopenharmony_ci
5930141cc406Sopenharmony_ci  unsigned char out[SD_powoff_len];
5931141cc406Sopenharmony_ci  size_t outLen = SD_powoff_len;
5932141cc406Sopenharmony_ci
5933141cc406Sopenharmony_ci  DBG (10, "set_off_mode: start\n");
5934141cc406Sopenharmony_ci
5935141cc406Sopenharmony_ci  if (!s->has_cmd_sdiag || !s->has_cmd_rdiag || !s->has_off_mode){
5936141cc406Sopenharmony_ci    DBG (5, "set_off_mode: not supported, returning\n");
5937141cc406Sopenharmony_ci    return ret;
5938141cc406Sopenharmony_ci  }
5939141cc406Sopenharmony_ci
5940141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
5941141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_DIAGNOSTIC_code);
5942141cc406Sopenharmony_ci  set_SD_slftst(cmd, 0);
5943141cc406Sopenharmony_ci  set_SD_xferlen(cmd, outLen);
5944141cc406Sopenharmony_ci
5945141cc406Sopenharmony_ci  memcpy(out,SD_powoff_string,SD_powoff_stringlen);
5946141cc406Sopenharmony_ci  set_SD_powoff_disable(out,!s->off_time);
5947141cc406Sopenharmony_ci  set_SD_powoff_interval(out,s->off_time/15);
5948141cc406Sopenharmony_ci
5949141cc406Sopenharmony_ci  ret = do_cmd (
5950141cc406Sopenharmony_ci    s, 1, 0,
5951141cc406Sopenharmony_ci    cmd, cmdLen,
5952141cc406Sopenharmony_ci    out, outLen,
5953141cc406Sopenharmony_ci    NULL, NULL
5954141cc406Sopenharmony_ci  );
5955141cc406Sopenharmony_ci
5956141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
5957141cc406Sopenharmony_ci    DBG (5, "set_off_mode: send diag error: %d\n", ret);
5958141cc406Sopenharmony_ci    return ret;
5959141cc406Sopenharmony_ci  }
5960141cc406Sopenharmony_ci
5961141cc406Sopenharmony_ci  DBG (10, "set_off_mode: finish\n");
5962141cc406Sopenharmony_ci
5963141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5964141cc406Sopenharmony_ci}
5965141cc406Sopenharmony_ci
5966141cc406Sopenharmony_cistatic SANE_Status
5967141cc406Sopenharmony_ciget_hardware_status (struct fujitsu *s, SANE_Int option)
5968141cc406Sopenharmony_ci{
5969141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
5970141cc406Sopenharmony_ci
5971141cc406Sopenharmony_ci  DBG (10, "get_hardware_status: start\n");
5972141cc406Sopenharmony_ci
5973141cc406Sopenharmony_ci  /* only run this if frontend has already read the last time we got it */
5974141cc406Sopenharmony_ci  /* or if we don't care for such bookkeeping (private use) */
5975141cc406Sopenharmony_ci  if (!option || !s->hw_data_avail[option-OPT_TOP]) {
5976141cc406Sopenharmony_ci
5977141cc406Sopenharmony_ci      DBG (15, "get_hardware_status: running\n");
5978141cc406Sopenharmony_ci
5979141cc406Sopenharmony_ci      /* mark all values as available */
5980141cc406Sopenharmony_ci      memset(s->hw_data_avail,1,sizeof(s->hw_data_avail));
5981141cc406Sopenharmony_ci
5982141cc406Sopenharmony_ci      if (s->has_cmd_hw_status){
5983141cc406Sopenharmony_ci          unsigned char cmd[GET_HW_STATUS_len];
5984141cc406Sopenharmony_ci          size_t cmdLen = GET_HW_STATUS_len;
5985141cc406Sopenharmony_ci
5986141cc406Sopenharmony_ci          unsigned char in[GHS_data_len];
5987141cc406Sopenharmony_ci          size_t inLen = GHS_data_len;
5988141cc406Sopenharmony_ci
5989141cc406Sopenharmony_ci          memset(cmd,0,cmdLen);
5990141cc406Sopenharmony_ci          set_SCSI_opcode(cmd, GET_HW_STATUS_code);
5991141cc406Sopenharmony_ci          set_GHS_allocation_length(cmd, inLen);
5992141cc406Sopenharmony_ci
5993141cc406Sopenharmony_ci          DBG (15, "get_hardware_status: calling ghs\n");
5994141cc406Sopenharmony_ci
5995141cc406Sopenharmony_ci          ret = do_cmd (
5996141cc406Sopenharmony_ci            s, 1, 0,
5997141cc406Sopenharmony_ci            cmd, cmdLen,
5998141cc406Sopenharmony_ci            NULL, 0,
5999141cc406Sopenharmony_ci            in, &inLen
6000141cc406Sopenharmony_ci          );
6001141cc406Sopenharmony_ci
6002141cc406Sopenharmony_ci          if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) {
6003141cc406Sopenharmony_ci
6004141cc406Sopenharmony_ci              s->hw_top = get_GHS_top(in);
6005141cc406Sopenharmony_ci              s->hw_A3 = get_GHS_A3(in);
6006141cc406Sopenharmony_ci              s->hw_B4 = get_GHS_B4(in);
6007141cc406Sopenharmony_ci              s->hw_A4 = get_GHS_A4(in);
6008141cc406Sopenharmony_ci              s->hw_B5 = get_GHS_B5(in);
6009141cc406Sopenharmony_ci
6010141cc406Sopenharmony_ci              s->hw_hopper = get_GHS_hopper(in);
6011141cc406Sopenharmony_ci              s->hw_omr = get_GHS_omr(in);
6012141cc406Sopenharmony_ci              s->hw_adf_open = get_GHS_adf_open(in);
6013141cc406Sopenharmony_ci              s->hw_card_loaded = get_GHS_exit(in);
6014141cc406Sopenharmony_ci
6015141cc406Sopenharmony_ci              s->hw_sleep = get_GHS_sleep(in);
6016141cc406Sopenharmony_ci              s->hw_send_sw = get_GHS_send_sw(in);
6017141cc406Sopenharmony_ci              s->hw_manual_feed = get_GHS_manual_feed(in);
6018141cc406Sopenharmony_ci              s->hw_scan_sw = get_GHS_scan_sw(in);
6019141cc406Sopenharmony_ci
6020141cc406Sopenharmony_ci              s->hw_function = get_GHS_function(in);
6021141cc406Sopenharmony_ci              s->hw_ink_empty = get_GHS_ink_empty(in);
6022141cc406Sopenharmony_ci
6023141cc406Sopenharmony_ci              s->hw_double_feed = get_GHS_double_feed(in);
6024141cc406Sopenharmony_ci
6025141cc406Sopenharmony_ci              s->hw_error_code = get_GHS_error_code(in);
6026141cc406Sopenharmony_ci
6027141cc406Sopenharmony_ci              s->hw_skew_angle = get_GHS_skew_angle(in);
6028141cc406Sopenharmony_ci
6029141cc406Sopenharmony_ci              if(inLen > 9){
6030141cc406Sopenharmony_ci                s->hw_ink_remain = get_GHS_ink_remain(in);
6031141cc406Sopenharmony_ci              }
6032141cc406Sopenharmony_ci
6033141cc406Sopenharmony_ci              ret = SANE_STATUS_GOOD;
6034141cc406Sopenharmony_ci          }
6035141cc406Sopenharmony_ci      }
6036141cc406Sopenharmony_ci
6037141cc406Sopenharmony_ci      /* 3091/2 put hardware status in RS data */
6038141cc406Sopenharmony_ci      else if (s->ghs_in_rs){
6039141cc406Sopenharmony_ci          unsigned char cmd[REQUEST_SENSE_len];
6040141cc406Sopenharmony_ci          size_t cmdLen = REQUEST_SENSE_len;
6041141cc406Sopenharmony_ci
6042141cc406Sopenharmony_ci          unsigned char in[RS_return_size];
6043141cc406Sopenharmony_ci          size_t inLen = RS_return_size;
6044141cc406Sopenharmony_ci
6045141cc406Sopenharmony_ci          memset(cmd,0,cmdLen);
6046141cc406Sopenharmony_ci          set_SCSI_opcode(cmd, REQUEST_SENSE_code);
6047141cc406Sopenharmony_ci	  set_RS_return_size(cmd, inLen);
6048141cc406Sopenharmony_ci
6049141cc406Sopenharmony_ci          DBG(15,"get_hardware_status: calling rs\n");
6050141cc406Sopenharmony_ci
6051141cc406Sopenharmony_ci          ret = do_cmd(
6052141cc406Sopenharmony_ci            s,0,0,
6053141cc406Sopenharmony_ci            cmd, cmdLen,
6054141cc406Sopenharmony_ci            NULL,0,
6055141cc406Sopenharmony_ci            in, &inLen
6056141cc406Sopenharmony_ci          );
6057141cc406Sopenharmony_ci
6058141cc406Sopenharmony_ci          /* parse the rs data */
6059141cc406Sopenharmony_ci          if(ret == SANE_STATUS_GOOD){
6060141cc406Sopenharmony_ci            if(get_RS_sense_key(in)==0 && get_RS_ASC(in)==0x80){
6061141cc406Sopenharmony_ci
6062141cc406Sopenharmony_ci              s->hw_adf_open = get_RS_adf_open(in);
6063141cc406Sopenharmony_ci              s->hw_send_sw = get_RS_send_sw(in);
6064141cc406Sopenharmony_ci              s->hw_scan_sw = get_RS_scan_sw(in);
6065141cc406Sopenharmony_ci              s->hw_duplex_sw = get_RS_duplex_sw(in);
6066141cc406Sopenharmony_ci              s->hw_top = get_RS_top(in);
6067141cc406Sopenharmony_ci              s->hw_hopper = get_RS_hopper(in);
6068141cc406Sopenharmony_ci              s->hw_function = get_RS_function(in);
6069141cc406Sopenharmony_ci              s->hw_density_sw = get_RS_density(in);
6070141cc406Sopenharmony_ci            }
6071141cc406Sopenharmony_ci            else{
6072141cc406Sopenharmony_ci              DBG (10, "get_hardware_status: unexpected RS values\n");
6073141cc406Sopenharmony_ci            }
6074141cc406Sopenharmony_ci          }
6075141cc406Sopenharmony_ci      }
6076141cc406Sopenharmony_ci  }
6077141cc406Sopenharmony_ci
6078141cc406Sopenharmony_ci  if(option)
6079141cc406Sopenharmony_ci    s->hw_data_avail[option-OPT_TOP] = 0;
6080141cc406Sopenharmony_ci
6081141cc406Sopenharmony_ci  DBG (10, "get_hardware_status: finish\n");
6082141cc406Sopenharmony_ci
6083141cc406Sopenharmony_ci  return ret;
6084141cc406Sopenharmony_ci}
6085141cc406Sopenharmony_ci
6086141cc406Sopenharmony_cistatic SANE_Status
6087141cc406Sopenharmony_cisend_endorser(struct fujitsu *s)
6088141cc406Sopenharmony_ci{
6089141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6090141cc406Sopenharmony_ci
6091141cc406Sopenharmony_ci  unsigned char cmd[SEND_len];
6092141cc406Sopenharmony_ci  size_t cmdLen = SEND_len;
6093141cc406Sopenharmony_ci
6094141cc406Sopenharmony_ci  size_t strLen = strlen(s->u_endorser_string);
6095141cc406Sopenharmony_ci
6096141cc406Sopenharmony_ci  unsigned char out[S_e_data_max_len]; /*we probably send less below*/
6097141cc406Sopenharmony_ci  size_t outLen = S_e_data_min_len + strLen; /*fi-5900 might want 1 more byte?*/
6098141cc406Sopenharmony_ci
6099141cc406Sopenharmony_ci  DBG (10, "send_endorser: start\n");
6100141cc406Sopenharmony_ci
6101141cc406Sopenharmony_ci  if (!s->has_endorser_f && !s->has_endorser_b){
6102141cc406Sopenharmony_ci    DBG (10, "send_endorser: unsupported\n");
6103141cc406Sopenharmony_ci    return ret;
6104141cc406Sopenharmony_ci  }
6105141cc406Sopenharmony_ci
6106141cc406Sopenharmony_ci  /*build the payload*/
6107141cc406Sopenharmony_ci  memset(out,0,outLen);
6108141cc406Sopenharmony_ci
6109141cc406Sopenharmony_ci  /*fi-5900 front side uses 0x80, assume all others*/
6110141cc406Sopenharmony_ci  if(s->u_endorser_side == ED_front){
6111141cc406Sopenharmony_ci    set_S_endorser_data_id(out,0x80);
6112141cc406Sopenharmony_ci  }
6113141cc406Sopenharmony_ci  else{
6114141cc406Sopenharmony_ci    set_S_endorser_data_id(out,0);
6115141cc406Sopenharmony_ci  }
6116141cc406Sopenharmony_ci
6117141cc406Sopenharmony_ci  set_S_endorser_stamp(out,0);
6118141cc406Sopenharmony_ci  set_S_endorser_elec(out,0);
6119141cc406Sopenharmony_ci
6120141cc406Sopenharmony_ci  if(s->u_endorser_step < 0){
6121141cc406Sopenharmony_ci    set_S_endorser_decr(out,S_e_decr_dec);
6122141cc406Sopenharmony_ci  }
6123141cc406Sopenharmony_ci  else{
6124141cc406Sopenharmony_ci    set_S_endorser_decr(out,S_e_decr_inc);
6125141cc406Sopenharmony_ci  }
6126141cc406Sopenharmony_ci
6127141cc406Sopenharmony_ci  if(s->u_endorser_bits == 24){
6128141cc406Sopenharmony_ci    set_S_endorser_lap24(out,S_e_lap_24bit);
6129141cc406Sopenharmony_ci  }
6130141cc406Sopenharmony_ci  else{
6131141cc406Sopenharmony_ci    set_S_endorser_lap24(out,S_e_lap_16bit);
6132141cc406Sopenharmony_ci  }
6133141cc406Sopenharmony_ci
6134141cc406Sopenharmony_ci  set_S_endorser_ctstep(out,abs(s->u_endorser_step));
6135141cc406Sopenharmony_ci  set_S_endorser_ulx(out,0);
6136141cc406Sopenharmony_ci  set_S_endorser_uly(out,s->u_endorser_y);
6137141cc406Sopenharmony_ci
6138141cc406Sopenharmony_ci  switch (s->u_endorser_font) {
6139141cc406Sopenharmony_ci    case FONT_H:
6140141cc406Sopenharmony_ci      set_S_endorser_font(out,S_e_font_horiz);
6141141cc406Sopenharmony_ci      set_S_endorser_bold(out,0);
6142141cc406Sopenharmony_ci      break;
6143141cc406Sopenharmony_ci    case FONT_HB:
6144141cc406Sopenharmony_ci      set_S_endorser_font(out,S_e_font_horiz);
6145141cc406Sopenharmony_ci      set_S_endorser_bold(out,1);
6146141cc406Sopenharmony_ci      break;
6147141cc406Sopenharmony_ci    case FONT_HN:
6148141cc406Sopenharmony_ci      set_S_endorser_font(out,S_e_font_horiz_narrow);
6149141cc406Sopenharmony_ci      set_S_endorser_bold(out,0);
6150141cc406Sopenharmony_ci      break;
6151141cc406Sopenharmony_ci    case FONT_V:
6152141cc406Sopenharmony_ci      set_S_endorser_font(out,S_e_font_vert);
6153141cc406Sopenharmony_ci      set_S_endorser_bold(out,0);
6154141cc406Sopenharmony_ci      break;
6155141cc406Sopenharmony_ci    case FONT_VB:
6156141cc406Sopenharmony_ci      set_S_endorser_font(out,S_e_font_vert);
6157141cc406Sopenharmony_ci      set_S_endorser_bold(out,1);
6158141cc406Sopenharmony_ci      break;
6159141cc406Sopenharmony_ci  }
6160141cc406Sopenharmony_ci
6161141cc406Sopenharmony_ci  set_S_endorser_size(out,0);
6162141cc406Sopenharmony_ci  set_S_endorser_revs(out,0);
6163141cc406Sopenharmony_ci
6164141cc406Sopenharmony_ci  if(s->u_endorser_dir == DIR_BTT){
6165141cc406Sopenharmony_ci    set_S_endorser_dirs(out,S_e_dir_bottom_top);
6166141cc406Sopenharmony_ci  }
6167141cc406Sopenharmony_ci  else{
6168141cc406Sopenharmony_ci    set_S_endorser_dirs(out,S_e_dir_top_bottom);
6169141cc406Sopenharmony_ci  }
6170141cc406Sopenharmony_ci
6171141cc406Sopenharmony_ci  set_S_endorser_string_length(out, strLen);
6172141cc406Sopenharmony_ci  set_S_endorser_string(out, s->u_endorser_string, strLen);
6173141cc406Sopenharmony_ci
6174141cc406Sopenharmony_ci  /*build the command*/
6175141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6176141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_code);
6177141cc406Sopenharmony_ci  set_S_xfer_datatype (cmd, S_datatype_endorser_data);
6178141cc406Sopenharmony_ci  set_S_xfer_length (cmd, outLen);
6179141cc406Sopenharmony_ci
6180141cc406Sopenharmony_ci  ret = do_cmd (
6181141cc406Sopenharmony_ci      s, 1, 0,
6182141cc406Sopenharmony_ci      cmd, cmdLen,
6183141cc406Sopenharmony_ci      out, outLen,
6184141cc406Sopenharmony_ci      NULL, NULL
6185141cc406Sopenharmony_ci  );
6186141cc406Sopenharmony_ci
6187141cc406Sopenharmony_ci  DBG (10, "send_endorser: finish %d\n", ret);
6188141cc406Sopenharmony_ci
6189141cc406Sopenharmony_ci  return ret;
6190141cc406Sopenharmony_ci}
6191141cc406Sopenharmony_ci
6192141cc406Sopenharmony_ci/* instead of internal brightness/contrast/gamma
6193141cc406Sopenharmony_ci   most scanners use a 256x256 or 1024x256 LUT
6194141cc406Sopenharmony_ci   default is linear table of slope 1 or 1/4 resp.
6195141cc406Sopenharmony_ci   brightness and contrast inputs are -127 to +127
6196141cc406Sopenharmony_ci
6197141cc406Sopenharmony_ci   contrast rotates slope of line around central input val
6198141cc406Sopenharmony_ci
6199141cc406Sopenharmony_ci       high           low
6200141cc406Sopenharmony_ci       .       x      .
6201141cc406Sopenharmony_ci       .      x       .         xx
6202141cc406Sopenharmony_ci   out .     x        . xxxxxxxx
6203141cc406Sopenharmony_ci       .    x         xx
6204141cc406Sopenharmony_ci       ....x.......   ............
6205141cc406Sopenharmony_ci            in             in
6206141cc406Sopenharmony_ci
6207141cc406Sopenharmony_ci   then brightness moves line vertically, and clamps to 8bit
6208141cc406Sopenharmony_ci
6209141cc406Sopenharmony_ci       bright         dark
6210141cc406Sopenharmony_ci       .   xxxxxxxx   .
6211141cc406Sopenharmony_ci       . x            .
6212141cc406Sopenharmony_ci   out x              .          x
6213141cc406Sopenharmony_ci       .              .        x
6214141cc406Sopenharmony_ci       ............   xxxxxxxx....
6215141cc406Sopenharmony_ci            in             in
6216141cc406Sopenharmony_ci  */
6217141cc406Sopenharmony_cistatic SANE_Status
6218141cc406Sopenharmony_cisend_lut (struct fujitsu *s)
6219141cc406Sopenharmony_ci{
6220141cc406Sopenharmony_ci  int i, j, bytes = 1 << s->adbits;
6221141cc406Sopenharmony_ci  double b, slope, offset;
6222141cc406Sopenharmony_ci
6223141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6224141cc406Sopenharmony_ci
6225141cc406Sopenharmony_ci  unsigned char cmd[SEND_len];
6226141cc406Sopenharmony_ci  size_t cmdLen = SEND_len;
6227141cc406Sopenharmony_ci
6228141cc406Sopenharmony_ci  unsigned char out[S_lut_header_len + S_lut_data_max_len];
6229141cc406Sopenharmony_ci  size_t outLen = S_lut_header_len + S_lut_data_max_len;
6230141cc406Sopenharmony_ci  unsigned char * p = out + S_lut_header_len;
6231141cc406Sopenharmony_ci
6232141cc406Sopenharmony_ci  DBG (10, "send_lut: start\n");
6233141cc406Sopenharmony_ci
6234141cc406Sopenharmony_ci  if(!s->num_download_gamma || !s->adbits){
6235141cc406Sopenharmony_ci    DBG (10, "send_lut: unsupported\n");
6236141cc406Sopenharmony_ci    return ret;
6237141cc406Sopenharmony_ci  }
6238141cc406Sopenharmony_ci
6239141cc406Sopenharmony_ci  /* contrast is converted to a slope [0,90] degrees:
6240141cc406Sopenharmony_ci   * first [-127,127] to [0,254] then to [0,1]
6241141cc406Sopenharmony_ci   * then multiply by PI/2 to convert to radians
6242141cc406Sopenharmony_ci   * then take the tangent to get slope (T.O.A)
6243141cc406Sopenharmony_ci   * then multiply by the normal linear slope
6244141cc406Sopenharmony_ci   * because the table may not be square, i.e. 1024x256*/
6245141cc406Sopenharmony_ci  slope = tan(((double)s->contrast+127)/254 * M_PI/2) * 256/bytes;
6246141cc406Sopenharmony_ci
6247141cc406Sopenharmony_ci  /* contrast slope must stay centered, so figure
6248141cc406Sopenharmony_ci   * out vertical offset at central input value */
6249141cc406Sopenharmony_ci  offset = 127.5-(slope*bytes/2);
6250141cc406Sopenharmony_ci
6251141cc406Sopenharmony_ci  /* convert the user brightness setting (-127 to +127)
6252141cc406Sopenharmony_ci   * into a scale that covers the range required
6253141cc406Sopenharmony_ci   * to slide the contrast curve entirely off the table */
6254141cc406Sopenharmony_ci  b = ((double)s->brightness/127) * (256 - offset);
6255141cc406Sopenharmony_ci
6256141cc406Sopenharmony_ci  DBG (15, "send_lut: %d %f %d %f %f\n", s->brightness, b,
6257141cc406Sopenharmony_ci    s->contrast, slope, offset);
6258141cc406Sopenharmony_ci
6259141cc406Sopenharmony_ci  outLen = S_lut_header_len + bytes;
6260141cc406Sopenharmony_ci
6261141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6262141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_code);
6263141cc406Sopenharmony_ci
6264141cc406Sopenharmony_ci  set_S_xfer_datatype (cmd, S_datatype_lut_data);
6265141cc406Sopenharmony_ci  set_S_xfer_length (cmd, outLen);
6266141cc406Sopenharmony_ci
6267141cc406Sopenharmony_ci  memset(out,0,outLen);
6268141cc406Sopenharmony_ci  set_S_lut_order (out, S_lut_order_single);
6269141cc406Sopenharmony_ci  set_S_lut_ssize (out, bytes);
6270141cc406Sopenharmony_ci  set_S_lut_dsize (out, 256);
6271141cc406Sopenharmony_ci
6272141cc406Sopenharmony_ci  for(i=0;i<bytes;i++){
6273141cc406Sopenharmony_ci    j=slope*i + offset + b;
6274141cc406Sopenharmony_ci
6275141cc406Sopenharmony_ci    if(j<0){
6276141cc406Sopenharmony_ci      j=0;
6277141cc406Sopenharmony_ci    }
6278141cc406Sopenharmony_ci
6279141cc406Sopenharmony_ci    if(j>255){
6280141cc406Sopenharmony_ci      j=255;
6281141cc406Sopenharmony_ci    }
6282141cc406Sopenharmony_ci
6283141cc406Sopenharmony_ci    *p=j;
6284141cc406Sopenharmony_ci    p++;
6285141cc406Sopenharmony_ci  }
6286141cc406Sopenharmony_ci
6287141cc406Sopenharmony_ci  ret = do_cmd (
6288141cc406Sopenharmony_ci      s, 1, 0,
6289141cc406Sopenharmony_ci      cmd, cmdLen,
6290141cc406Sopenharmony_ci      out, outLen,
6291141cc406Sopenharmony_ci      NULL, NULL
6292141cc406Sopenharmony_ci  );
6293141cc406Sopenharmony_ci
6294141cc406Sopenharmony_ci  DBG (10, "send_lut: finish\n");
6295141cc406Sopenharmony_ci
6296141cc406Sopenharmony_ci  return ret;
6297141cc406Sopenharmony_ci}
6298141cc406Sopenharmony_ci
6299141cc406Sopenharmony_cistatic SANE_Status
6300141cc406Sopenharmony_cisend_q_table (struct fujitsu *s)
6301141cc406Sopenharmony_ci{
6302141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6303141cc406Sopenharmony_ci
6304141cc406Sopenharmony_ci  unsigned char cmd[SEND_len];
6305141cc406Sopenharmony_ci  size_t cmdLen = SEND_len;
6306141cc406Sopenharmony_ci
6307141cc406Sopenharmony_ci  unsigned char out[S_q_table_header_len + S_q_table_y_len + S_q_table_uv_len];
6308141cc406Sopenharmony_ci  size_t outLen = S_q_table_header_len + S_q_table_y_len + S_q_table_uv_len;
6309141cc406Sopenharmony_ci  unsigned char * yp = out + S_q_table_header_len;
6310141cc406Sopenharmony_ci  unsigned char * uvp = out + S_q_table_header_len + S_q_table_y_len;
6311141cc406Sopenharmony_ci
6312141cc406Sopenharmony_ci  /* FIXME: generate these instead of hardcode */
6313141cc406Sopenharmony_ci  unsigned char ydata[] = {
6314141cc406Sopenharmony_ci 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
6315141cc406Sopenharmony_ci 0x03, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0c,
6316141cc406Sopenharmony_ci 0x07, 0x07, 0x06, 0x06, 0x07, 0x0e, 0x0a, 0x0b,
6317141cc406Sopenharmony_ci 0x08, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f,
6318141cc406Sopenharmony_ci 0x10, 0x10, 0x13, 0x15, 0x1b, 0x17, 0x13, 0x14,
6319141cc406Sopenharmony_ci 0x1a, 0x14, 0x10, 0x10, 0x18, 0x20, 0x18, 0x1a,
6320141cc406Sopenharmony_ci 0x1c, 0x1d, 0x1e, 0x1f, 0x1e, 0x12, 0x17, 0x21,
6321141cc406Sopenharmony_ci 0x24, 0x21, 0x1e, 0x24, 0x1b, 0x1e, 0x1e, 0x1d };
6322141cc406Sopenharmony_ci
6323141cc406Sopenharmony_ci  unsigned char uvdata[] = {
6324141cc406Sopenharmony_ci 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0e, 0x07,
6325141cc406Sopenharmony_ci 0x07, 0x0e, 0x1d, 0x13, 0x10, 0x13, 0x1d, 0x1d,
6326141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
6327141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
6328141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
6329141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
6330141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
6331141cc406Sopenharmony_ci 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d };
6332141cc406Sopenharmony_ci
6333141cc406Sopenharmony_ci  DBG (10, "send_q_table: start\n");
6334141cc406Sopenharmony_ci
6335141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6336141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_code);
6337141cc406Sopenharmony_ci  set_S_xfer_datatype (cmd, S_datatype_jpg_q_table);
6338141cc406Sopenharmony_ci  set_S_xfer_length (cmd, outLen);
6339141cc406Sopenharmony_ci
6340141cc406Sopenharmony_ci  memset(out,0,outLen);
6341141cc406Sopenharmony_ci  set_S_q_table_y_len (out, S_q_table_y_len);
6342141cc406Sopenharmony_ci  set_S_q_table_uv_len (out, S_q_table_uv_len);
6343141cc406Sopenharmony_ci  memcpy (yp, ydata, S_q_table_y_len);
6344141cc406Sopenharmony_ci  memcpy (uvp, uvdata, S_q_table_uv_len);
6345141cc406Sopenharmony_ci
6346141cc406Sopenharmony_ci  ret = do_cmd (
6347141cc406Sopenharmony_ci      s, 1, 0,
6348141cc406Sopenharmony_ci      cmd, cmdLen,
6349141cc406Sopenharmony_ci      out, outLen,
6350141cc406Sopenharmony_ci      NULL, NULL
6351141cc406Sopenharmony_ci  );
6352141cc406Sopenharmony_ci
6353141cc406Sopenharmony_ci  DBG (10, "send_q_table: finish\n");
6354141cc406Sopenharmony_ci
6355141cc406Sopenharmony_ci  return ret;
6356141cc406Sopenharmony_ci}
6357141cc406Sopenharmony_ci
6358141cc406Sopenharmony_ci/* only used by iX500? */
6359141cc406Sopenharmony_ci#if 0
6360141cc406Sopenharmony_cistatic SANE_Status
6361141cc406Sopenharmony_cimode_select_unk (struct fujitsu *s, int foo)
6362141cc406Sopenharmony_ci{
6363141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6364141cc406Sopenharmony_ci
6365141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6366141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6367141cc406Sopenharmony_ci
6368141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6369141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6370141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6371141cc406Sopenharmony_ci
6372141cc406Sopenharmony_ci  DBG (10, "mode_select_unk: start\n");
6373141cc406Sopenharmony_ci
6374141cc406Sopenharmony_ci  /*if (!s->has_MS_unk){
6375141cc406Sopenharmony_ci    DBG (10, "mode_select_unk: unsupported\n");
6376141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6377141cc406Sopenharmony_ci  }*/
6378141cc406Sopenharmony_ci
6379141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6380141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6381141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6382141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6383141cc406Sopenharmony_ci
6384141cc406Sopenharmony_ci  memset(out,0,outLen);
6385141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_unk);
6386141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6387141cc406Sopenharmony_ci
6388141cc406Sopenharmony_ci  *(page + 0x02) = foo;
6389141cc406Sopenharmony_ci
6390141cc406Sopenharmony_ci  ret = do_cmd (
6391141cc406Sopenharmony_ci      s, 1, 0,
6392141cc406Sopenharmony_ci      cmd, cmdLen,
6393141cc406Sopenharmony_ci      out, outLen,
6394141cc406Sopenharmony_ci      NULL, NULL
6395141cc406Sopenharmony_ci  );
6396141cc406Sopenharmony_ci
6397141cc406Sopenharmony_ci  DBG (10, "mode_select_unk: finish\n");
6398141cc406Sopenharmony_ci
6399141cc406Sopenharmony_ci  return ret;
6400141cc406Sopenharmony_ci}
6401141cc406Sopenharmony_ci#endif
6402141cc406Sopenharmony_ci
6403141cc406Sopenharmony_ci/* only used by iX500? */
6404141cc406Sopenharmony_cistatic SANE_Status
6405141cc406Sopenharmony_cidiag_preread (struct fujitsu *s)
6406141cc406Sopenharmony_ci{
6407141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6408141cc406Sopenharmony_ci
6409141cc406Sopenharmony_ci  unsigned char cmd[SEND_DIAGNOSTIC_len]; /*also big enough for READ_DIAG*/
6410141cc406Sopenharmony_ci  size_t cmdLen = SEND_DIAGNOSTIC_len;
6411141cc406Sopenharmony_ci
6412141cc406Sopenharmony_ci  unsigned char out[SD_preread_len];
6413141cc406Sopenharmony_ci  size_t outLen = SD_preread_len;
6414141cc406Sopenharmony_ci
6415141cc406Sopenharmony_ci  DBG (10, "diag_preread: start\n");
6416141cc406Sopenharmony_ci
6417141cc406Sopenharmony_ci  if (!s->has_cmd_sdiag || !s->has_cmd_rdiag || !s->need_diag_preread){
6418141cc406Sopenharmony_ci    DBG (5, "diag_preread: not supported, returning\n");
6419141cc406Sopenharmony_ci    return ret;
6420141cc406Sopenharmony_ci  }
6421141cc406Sopenharmony_ci
6422141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6423141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SEND_DIAGNOSTIC_code);
6424141cc406Sopenharmony_ci  set_SD_slftst(cmd, 0);
6425141cc406Sopenharmony_ci  set_SD_xferlen(cmd, outLen);
6426141cc406Sopenharmony_ci
6427141cc406Sopenharmony_ci  memcpy(out,SD_preread_string,SD_preread_stringlen);
6428141cc406Sopenharmony_ci  set_SD_preread_xres(out,s->resolution_x);
6429141cc406Sopenharmony_ci  set_SD_preread_yres(out,s->resolution_y);
6430141cc406Sopenharmony_ci  /* call helper function, scanner wants lies about paper width */
6431141cc406Sopenharmony_ci  set_SD_preread_paper_width(out, get_page_width(s));
6432141cc406Sopenharmony_ci  /* don't call helper function, scanner wants actual length?  */
6433141cc406Sopenharmony_ci  set_SD_preread_paper_length(out, s->page_height);
6434141cc406Sopenharmony_ci  set_SD_preread_composition(out, s->s_mode);
6435141cc406Sopenharmony_ci
6436141cc406Sopenharmony_ci  ret = do_cmd (
6437141cc406Sopenharmony_ci    s, 1, 0,
6438141cc406Sopenharmony_ci    cmd, cmdLen,
6439141cc406Sopenharmony_ci    out, outLen,
6440141cc406Sopenharmony_ci    NULL, NULL
6441141cc406Sopenharmony_ci  );
6442141cc406Sopenharmony_ci
6443141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD){
6444141cc406Sopenharmony_ci    DBG (5, "diag_preread: send diag error: %d\n", ret);
6445141cc406Sopenharmony_ci    return ret;
6446141cc406Sopenharmony_ci  }
6447141cc406Sopenharmony_ci
6448141cc406Sopenharmony_ci  DBG (10, "diag_preread: finish\n");
6449141cc406Sopenharmony_ci
6450141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6451141cc406Sopenharmony_ci}
6452141cc406Sopenharmony_ci
6453141cc406Sopenharmony_cistatic SANE_Status
6454141cc406Sopenharmony_cimode_select_df (struct fujitsu *s)
6455141cc406Sopenharmony_ci{
6456141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6457141cc406Sopenharmony_ci
6458141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6459141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6460141cc406Sopenharmony_ci
6461141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6462141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6463141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6464141cc406Sopenharmony_ci
6465141cc406Sopenharmony_ci  DBG (10, "mode_select_df: start\n");
6466141cc406Sopenharmony_ci
6467141cc406Sopenharmony_ci  if(!s->has_MS_df){
6468141cc406Sopenharmony_ci    DBG (10, "mode_select_df: unsupported\n");
6469141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6470141cc406Sopenharmony_ci  }
6471141cc406Sopenharmony_ci
6472141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6473141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6474141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6475141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6476141cc406Sopenharmony_ci
6477141cc406Sopenharmony_ci  memset(out,0,outLen);
6478141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_df);
6479141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6480141cc406Sopenharmony_ci
6481141cc406Sopenharmony_ci  /* continue/stop */
6482141cc406Sopenharmony_ci  if(s->df_action != DF_DEFAULT){
6483141cc406Sopenharmony_ci    set_MSEL_df_enable (page, 1);
6484141cc406Sopenharmony_ci
6485141cc406Sopenharmony_ci    /* continue */
6486141cc406Sopenharmony_ci    if(s->df_action == DF_CONTINUE){
6487141cc406Sopenharmony_ci      set_MSEL_df_continue (page, 1);
6488141cc406Sopenharmony_ci    }
6489141cc406Sopenharmony_ci
6490141cc406Sopenharmony_ci    /* skew */
6491141cc406Sopenharmony_ci    if(s->df_skew){
6492141cc406Sopenharmony_ci      set_MSEL_df_skew (page, 1);
6493141cc406Sopenharmony_ci    }
6494141cc406Sopenharmony_ci
6495141cc406Sopenharmony_ci    /* thickness */
6496141cc406Sopenharmony_ci    if(s->df_thickness){
6497141cc406Sopenharmony_ci      set_MSEL_df_thickness (page, 1);
6498141cc406Sopenharmony_ci    }
6499141cc406Sopenharmony_ci
6500141cc406Sopenharmony_ci    /* length */
6501141cc406Sopenharmony_ci    if(s->df_length){
6502141cc406Sopenharmony_ci      set_MSEL_df_length (page, 1);
6503141cc406Sopenharmony_ci      set_MSEL_df_diff (page, s->df_diff);
6504141cc406Sopenharmony_ci    }
6505141cc406Sopenharmony_ci  }
6506141cc406Sopenharmony_ci
6507141cc406Sopenharmony_ci  set_MSEL_df_paperprot(page,s->paper_protect);
6508141cc406Sopenharmony_ci  set_MSEL_df_stapledet(page,s->staple_detect);
6509141cc406Sopenharmony_ci  set_MSEL_df_recovery(page,s->df_recovery);
6510141cc406Sopenharmony_ci  set_MSEL_df_paperprot2(page,s->adv_paper_prot);
6511141cc406Sopenharmony_ci
6512141cc406Sopenharmony_ci  ret = do_cmd (
6513141cc406Sopenharmony_ci      s, 1, 0,
6514141cc406Sopenharmony_ci      cmd, cmdLen,
6515141cc406Sopenharmony_ci      out, outLen,
6516141cc406Sopenharmony_ci      NULL, NULL
6517141cc406Sopenharmony_ci  );
6518141cc406Sopenharmony_ci
6519141cc406Sopenharmony_ci  DBG (10, "mode_select_df: finish\n");
6520141cc406Sopenharmony_ci
6521141cc406Sopenharmony_ci  return ret;
6522141cc406Sopenharmony_ci}
6523141cc406Sopenharmony_ci
6524141cc406Sopenharmony_cistatic SANE_Status
6525141cc406Sopenharmony_cimode_select_bg (struct fujitsu *s)
6526141cc406Sopenharmony_ci{
6527141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6528141cc406Sopenharmony_ci
6529141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6530141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6531141cc406Sopenharmony_ci
6532141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6533141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6534141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6535141cc406Sopenharmony_ci
6536141cc406Sopenharmony_ci  DBG (10, "mode_select_bg: start\n");
6537141cc406Sopenharmony_ci
6538141cc406Sopenharmony_ci  if(!s->has_MS_bg){
6539141cc406Sopenharmony_ci    DBG (10, "mode_select_bg: unsupported\n");
6540141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6541141cc406Sopenharmony_ci  }
6542141cc406Sopenharmony_ci
6543141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6544141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6545141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6546141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6547141cc406Sopenharmony_ci
6548141cc406Sopenharmony_ci  memset(out,0,outLen);
6549141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_bg);
6550141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6551141cc406Sopenharmony_ci
6552141cc406Sopenharmony_ci  if(s->bg_color != COLOR_DEFAULT){
6553141cc406Sopenharmony_ci    set_MSEL_bg_enable (page, 1);
6554141cc406Sopenharmony_ci
6555141cc406Sopenharmony_ci    if(s->bg_color == COLOR_BLACK){
6556141cc406Sopenharmony_ci      set_MSEL_bg_front (page, 1);
6557141cc406Sopenharmony_ci      set_MSEL_bg_back (page, 1);
6558141cc406Sopenharmony_ci      set_MSEL_bg_fb (page, 1);
6559141cc406Sopenharmony_ci    }
6560141cc406Sopenharmony_ci  }
6561141cc406Sopenharmony_ci
6562141cc406Sopenharmony_ci  ret = do_cmd (
6563141cc406Sopenharmony_ci      s, 1, 0,
6564141cc406Sopenharmony_ci      cmd, cmdLen,
6565141cc406Sopenharmony_ci      out, outLen,
6566141cc406Sopenharmony_ci      NULL, NULL
6567141cc406Sopenharmony_ci  );
6568141cc406Sopenharmony_ci
6569141cc406Sopenharmony_ci  DBG (10, "mode_select_bg: finish\n");
6570141cc406Sopenharmony_ci
6571141cc406Sopenharmony_ci  return ret;
6572141cc406Sopenharmony_ci}
6573141cc406Sopenharmony_ci
6574141cc406Sopenharmony_cistatic SANE_Status
6575141cc406Sopenharmony_cimode_select_dropout (struct fujitsu *s)
6576141cc406Sopenharmony_ci{
6577141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6578141cc406Sopenharmony_ci
6579141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6580141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6581141cc406Sopenharmony_ci
6582141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_max_len];
6583141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_max_len;
6584141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6585141cc406Sopenharmony_ci
6586141cc406Sopenharmony_ci  DBG (10, "mode_select_dropout: start\n");
6587141cc406Sopenharmony_ci
6588141cc406Sopenharmony_ci  if(!s->has_MS_dropout){
6589141cc406Sopenharmony_ci    DBG (10, "mode_select_dropout: unsupported\n");
6590141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6591141cc406Sopenharmony_ci  }
6592141cc406Sopenharmony_ci
6593141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6594141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6595141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6596141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6597141cc406Sopenharmony_ci
6598141cc406Sopenharmony_ci  memset(out,0,outLen);
6599141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_dropout);
6600141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_max_len-2);
6601141cc406Sopenharmony_ci
6602141cc406Sopenharmony_ci  set_MSEL_dropout_front (page, s->dropout_color);
6603141cc406Sopenharmony_ci  set_MSEL_dropout_back (page, s->dropout_color);
6604141cc406Sopenharmony_ci
6605141cc406Sopenharmony_ci  ret = do_cmd (
6606141cc406Sopenharmony_ci      s, 1, 0,
6607141cc406Sopenharmony_ci      cmd, cmdLen,
6608141cc406Sopenharmony_ci      out, outLen,
6609141cc406Sopenharmony_ci      NULL, NULL
6610141cc406Sopenharmony_ci  );
6611141cc406Sopenharmony_ci
6612141cc406Sopenharmony_ci  DBG (10, "mode_select_dropout: finish\n");
6613141cc406Sopenharmony_ci
6614141cc406Sopenharmony_ci  return ret;
6615141cc406Sopenharmony_ci}
6616141cc406Sopenharmony_ci
6617141cc406Sopenharmony_cistatic SANE_Status
6618141cc406Sopenharmony_cimode_select_buff (struct fujitsu *s)
6619141cc406Sopenharmony_ci{
6620141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6621141cc406Sopenharmony_ci
6622141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6623141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6624141cc406Sopenharmony_ci
6625141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6626141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6627141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6628141cc406Sopenharmony_ci
6629141cc406Sopenharmony_ci  DBG (10, "mode_select_buff: start\n");
6630141cc406Sopenharmony_ci
6631141cc406Sopenharmony_ci  if (!s->has_MS_buff){
6632141cc406Sopenharmony_ci    DBG (10, "mode_select_buff: unsupported\n");
6633141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6634141cc406Sopenharmony_ci  }
6635141cc406Sopenharmony_ci
6636141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6637141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6638141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6639141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6640141cc406Sopenharmony_ci
6641141cc406Sopenharmony_ci  memset(out,0,outLen);
6642141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_buff);
6643141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6644141cc406Sopenharmony_ci
6645141cc406Sopenharmony_ci  set_MSEL_buff_mode(page, s->buff_mode);
6646141cc406Sopenharmony_ci  set_MSEL_buff_clear(page, 3);
6647141cc406Sopenharmony_ci
6648141cc406Sopenharmony_ci  ret = do_cmd (
6649141cc406Sopenharmony_ci      s, 1, 0,
6650141cc406Sopenharmony_ci      cmd, cmdLen,
6651141cc406Sopenharmony_ci      out, outLen,
6652141cc406Sopenharmony_ci      NULL, NULL
6653141cc406Sopenharmony_ci  );
6654141cc406Sopenharmony_ci
6655141cc406Sopenharmony_ci  DBG (10, "mode_select_buff: finish\n");
6656141cc406Sopenharmony_ci
6657141cc406Sopenharmony_ci  return ret;
6658141cc406Sopenharmony_ci}
6659141cc406Sopenharmony_ci
6660141cc406Sopenharmony_cistatic SANE_Status
6661141cc406Sopenharmony_cimode_select_prepick (struct fujitsu *s)
6662141cc406Sopenharmony_ci{
6663141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6664141cc406Sopenharmony_ci
6665141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6666141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6667141cc406Sopenharmony_ci
6668141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6669141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6670141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6671141cc406Sopenharmony_ci
6672141cc406Sopenharmony_ci  DBG (10, "mode_select_prepick: start\n");
6673141cc406Sopenharmony_ci
6674141cc406Sopenharmony_ci  if (!s->has_MS_prepick){
6675141cc406Sopenharmony_ci    DBG (10, "mode_select_prepick: unsupported\n");
6676141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6677141cc406Sopenharmony_ci  }
6678141cc406Sopenharmony_ci
6679141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6680141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6681141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6682141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6683141cc406Sopenharmony_ci
6684141cc406Sopenharmony_ci  memset(out,0,outLen);
6685141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_prepick);
6686141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6687141cc406Sopenharmony_ci
6688141cc406Sopenharmony_ci  set_MSEL_prepick(page, s->prepick);
6689141cc406Sopenharmony_ci
6690141cc406Sopenharmony_ci  ret = do_cmd (
6691141cc406Sopenharmony_ci      s, 1, 0,
6692141cc406Sopenharmony_ci      cmd, cmdLen,
6693141cc406Sopenharmony_ci      out, outLen,
6694141cc406Sopenharmony_ci      NULL, NULL
6695141cc406Sopenharmony_ci  );
6696141cc406Sopenharmony_ci
6697141cc406Sopenharmony_ci  DBG (10, "mode_select_prepick: finish\n");
6698141cc406Sopenharmony_ci
6699141cc406Sopenharmony_ci  return ret;
6700141cc406Sopenharmony_ci}
6701141cc406Sopenharmony_ci
6702141cc406Sopenharmony_cistatic SANE_Status
6703141cc406Sopenharmony_cimode_select_auto (struct fujitsu *s)
6704141cc406Sopenharmony_ci{
6705141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6706141cc406Sopenharmony_ci
6707141cc406Sopenharmony_ci  unsigned char cmd[MODE_SELECT_len];
6708141cc406Sopenharmony_ci  size_t cmdLen = MODE_SELECT_len;
6709141cc406Sopenharmony_ci
6710141cc406Sopenharmony_ci  unsigned char out[MSEL_header_len + MSEL_data_min_len];
6711141cc406Sopenharmony_ci  size_t outLen = MSEL_header_len + MSEL_data_min_len;
6712141cc406Sopenharmony_ci  unsigned char * page = out+MSEL_header_len;
6713141cc406Sopenharmony_ci
6714141cc406Sopenharmony_ci  DBG (10, "mode_select_auto: start\n");
6715141cc406Sopenharmony_ci
6716141cc406Sopenharmony_ci  if(!s->has_MS_auto){
6717141cc406Sopenharmony_ci    DBG (10, "mode_select_auto: unsupported\n");
6718141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6719141cc406Sopenharmony_ci  }
6720141cc406Sopenharmony_ci
6721141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
6722141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, MODE_SELECT_code);
6723141cc406Sopenharmony_ci  set_MSEL_pf(cmd, 1);
6724141cc406Sopenharmony_ci  set_MSEL_xferlen(cmd, outLen);
6725141cc406Sopenharmony_ci
6726141cc406Sopenharmony_ci  memset(out,0,outLen);
6727141cc406Sopenharmony_ci  set_MSEL_pc(page, MS_pc_auto);
6728141cc406Sopenharmony_ci  set_MSEL_page_len(page, MSEL_data_min_len-2);
6729141cc406Sopenharmony_ci
6730141cc406Sopenharmony_ci  set_MSEL_overscan(page, s->overscan);
6731141cc406Sopenharmony_ci  set_MSEL_ald(page, s->ald || s->hwdeskewcrop);
6732141cc406Sopenharmony_ci  set_MSEL_awd(page, s->awd || s->hwdeskewcrop);
6733141cc406Sopenharmony_ci  set_MSEL_req_driv_crop(page, s->hwdeskewcrop && (s->swcrop || s->swdeskew));
6734141cc406Sopenharmony_ci  set_MSEL_deskew(page, s->hwdeskewcrop);
6735141cc406Sopenharmony_ci
6736141cc406Sopenharmony_ci  ret = do_cmd (
6737141cc406Sopenharmony_ci      s, 1, 0,
6738141cc406Sopenharmony_ci      cmd, cmdLen,
6739141cc406Sopenharmony_ci      out, outLen,
6740141cc406Sopenharmony_ci      NULL, NULL
6741141cc406Sopenharmony_ci  );
6742141cc406Sopenharmony_ci
6743141cc406Sopenharmony_ci  DBG (10, "mode_select_auto: finish\n");
6744141cc406Sopenharmony_ci
6745141cc406Sopenharmony_ci  return ret;
6746141cc406Sopenharmony_ci}
6747141cc406Sopenharmony_ci
6748141cc406Sopenharmony_ci
6749141cc406Sopenharmony_ci/*
6750141cc406Sopenharmony_ci * @@ Section 4 - SANE scanning functions
6751141cc406Sopenharmony_ci */
6752141cc406Sopenharmony_ci/*
6753141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data
6754141cc406Sopenharmony_ci * that the current scan will return.
6755141cc406Sopenharmony_ci *
6756141cc406Sopenharmony_ci * From the SANE spec:
6757141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The
6758141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time
6759141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the
6760141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned
6761141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be
6762141cc406Sopenharmony_ci * when sane_start() gets invoked.
6763141cc406Sopenharmony_ci *
6764141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows,
6765141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will
6766141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle h of the
6767141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer p
6768141cc406Sopenharmony_ci * to a parameter structure.
6769141cc406Sopenharmony_ci */
6770141cc406Sopenharmony_ciSANE_Status
6771141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
6772141cc406Sopenharmony_ci{
6773141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6774141cc406Sopenharmony_ci  struct fujitsu *s = (struct fujitsu *) handle;
6775141cc406Sopenharmony_ci
6776141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters: start\n");
6777141cc406Sopenharmony_ci
6778141cc406Sopenharmony_ci  /* not started? update param data from user settings */
6779141cc406Sopenharmony_ci  if(!s->started){
6780141cc406Sopenharmony_ci    ret = update_params(s);
6781141cc406Sopenharmony_ci    if(ret)
6782141cc406Sopenharmony_ci      return ret;
6783141cc406Sopenharmony_ci  }
6784141cc406Sopenharmony_ci
6785141cc406Sopenharmony_ci  params->format = s->u_params.format;
6786141cc406Sopenharmony_ci  params->last_frame = s->u_params.last_frame;
6787141cc406Sopenharmony_ci  params->lines = s->u_params.lines;
6788141cc406Sopenharmony_ci  params->depth = s->u_params.depth;
6789141cc406Sopenharmony_ci  params->pixels_per_line = s->u_params.pixels_per_line;
6790141cc406Sopenharmony_ci  params->bytes_per_line = s->u_params.bytes_per_line;
6791141cc406Sopenharmony_ci
6792141cc406Sopenharmony_ci  /* we won't know the end until we get to it */
6793141cc406Sopenharmony_ci  if(s->ald && !must_fully_buffer(s)){
6794141cc406Sopenharmony_ci    DBG (15, "sane_get_parameters: hand-scanner mode\n");
6795141cc406Sopenharmony_ci    params->lines = -1;
6796141cc406Sopenharmony_ci  }
6797141cc406Sopenharmony_ci
6798141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters: finish\n");
6799141cc406Sopenharmony_ci  return ret;
6800141cc406Sopenharmony_ci}
6801141cc406Sopenharmony_ci
6802141cc406Sopenharmony_ci/* set s_params and u_params data based on user settings
6803141cc406Sopenharmony_ci * and scanner capabilities. */
6804141cc406Sopenharmony_ciSANE_Status
6805141cc406Sopenharmony_ciupdate_params (struct fujitsu * s)
6806141cc406Sopenharmony_ci{
6807141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6808141cc406Sopenharmony_ci  SANE_Parameters * params = &(s->s_params);
6809141cc406Sopenharmony_ci
6810141cc406Sopenharmony_ci  DBG (10, "update_params: start\n");
6811141cc406Sopenharmony_ci
6812141cc406Sopenharmony_ci  /* first, we setup s_params to describe the image to the scanner */
6813141cc406Sopenharmony_ci  /* this backend only sends single frame images */
6814141cc406Sopenharmony_ci  params->last_frame = 1;
6815141cc406Sopenharmony_ci
6816141cc406Sopenharmony_ci  /* initial ppl from user settings */
6817141cc406Sopenharmony_ci  params->pixels_per_line = s->resolution_x * (s->br_x - s->tl_x) / 1200;
6818141cc406Sopenharmony_ci
6819141cc406Sopenharmony_ci  /* some scanners require even number of bytes in each transfer block,
6820141cc406Sopenharmony_ci   * so we round to even # of total lines, to ensure last block is even */
6821141cc406Sopenharmony_ci  params->lines = s->resolution_y * (s->br_y - s->tl_y) / 1200;
6822141cc406Sopenharmony_ci  params->lines -= params->lines % 2;
6823141cc406Sopenharmony_ci
6824141cc406Sopenharmony_ci  if (s->s_mode == MODE_COLOR) {
6825141cc406Sopenharmony_ci    params->depth = 8;
6826141cc406Sopenharmony_ci
6827141cc406Sopenharmony_ci    /* jpeg requires 8x8 squares */
6828141cc406Sopenharmony_ci    if(s->compress == COMP_JPEG){
6829141cc406Sopenharmony_ci      params->format = SANE_FRAME_JPEG;
6830141cc406Sopenharmony_ci      params->pixels_per_line -= params->pixels_per_line % 8;
6831141cc406Sopenharmony_ci      params->lines -= params->lines % 8;
6832141cc406Sopenharmony_ci    }
6833141cc406Sopenharmony_ci    else{
6834141cc406Sopenharmony_ci      params->format = SANE_FRAME_RGB;
6835141cc406Sopenharmony_ci      params->pixels_per_line -= params->pixels_per_line
6836141cc406Sopenharmony_ci        % max(s->ppl_mod_by_mode[s->s_mode], s->ppl_mod_by_mode[s->u_mode]);
6837141cc406Sopenharmony_ci    }
6838141cc406Sopenharmony_ci
6839141cc406Sopenharmony_ci    params->bytes_per_line = params->pixels_per_line * 3;
6840141cc406Sopenharmony_ci  }
6841141cc406Sopenharmony_ci  else if (s->s_mode == MODE_GRAYSCALE) {
6842141cc406Sopenharmony_ci    params->depth = 8;
6843141cc406Sopenharmony_ci
6844141cc406Sopenharmony_ci    /* jpeg requires 8x8 squares */
6845141cc406Sopenharmony_ci    if(s->compress == COMP_JPEG){
6846141cc406Sopenharmony_ci      params->format = SANE_FRAME_JPEG;
6847141cc406Sopenharmony_ci      params->pixels_per_line -= params->pixels_per_line % 8;
6848141cc406Sopenharmony_ci      params->lines -= params->lines % 8;
6849141cc406Sopenharmony_ci    }
6850141cc406Sopenharmony_ci    else{
6851141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
6852141cc406Sopenharmony_ci      params->pixels_per_line -= params->pixels_per_line
6853141cc406Sopenharmony_ci        % max(s->ppl_mod_by_mode[s->s_mode], s->ppl_mod_by_mode[s->u_mode]);
6854141cc406Sopenharmony_ci    }
6855141cc406Sopenharmony_ci
6856141cc406Sopenharmony_ci    params->bytes_per_line = params->pixels_per_line;
6857141cc406Sopenharmony_ci  }
6858141cc406Sopenharmony_ci  else {
6859141cc406Sopenharmony_ci    params->depth = 1;
6860141cc406Sopenharmony_ci    params->format = SANE_FRAME_GRAY;
6861141cc406Sopenharmony_ci    params->pixels_per_line -= params->pixels_per_line
6862141cc406Sopenharmony_ci      % max(s->ppl_mod_by_mode[s->s_mode], s->ppl_mod_by_mode[s->u_mode]);
6863141cc406Sopenharmony_ci    params->bytes_per_line = params->pixels_per_line / 8;
6864141cc406Sopenharmony_ci  }
6865141cc406Sopenharmony_ci
6866141cc406Sopenharmony_ci  DBG(15,"update_params: x: max=%d, page=%d, gpw=%d, res=%d\n",
6867141cc406Sopenharmony_ci    s->max_x, s->page_width, get_page_width(s), s->resolution_x);
6868141cc406Sopenharmony_ci
6869141cc406Sopenharmony_ci  DBG(15,"update_params: y: max=%d, page=%d, gph=%d, res=%d\n",
6870141cc406Sopenharmony_ci    s->max_y, s->page_height, get_page_height(s), s->resolution_y);
6871141cc406Sopenharmony_ci
6872141cc406Sopenharmony_ci  DBG(15,"update_params: area: tlx=%d, brx=%d, tly=%d, bry=%d\n",
6873141cc406Sopenharmony_ci    s->tl_x, s->br_x, s->tl_y, s->br_y);
6874141cc406Sopenharmony_ci
6875141cc406Sopenharmony_ci  DBG(15,"update_params: params: ppl=%d, Bpl=%d, lines=%d\n",
6876141cc406Sopenharmony_ci    params->pixels_per_line, params->bytes_per_line, params->lines);
6877141cc406Sopenharmony_ci
6878141cc406Sopenharmony_ci  DBG(15,"update_params: params: format=%d, depth=%d, last=%d\n",
6879141cc406Sopenharmony_ci    params->format, params->depth, params->last_frame);
6880141cc406Sopenharmony_ci
6881141cc406Sopenharmony_ci  /* second, we setup u_params to describe the image to the user */
6882141cc406Sopenharmony_ci  /* use a helper function cause it is called elsewhere */
6883141cc406Sopenharmony_ci  ret = update_u_params(s);
6884141cc406Sopenharmony_ci
6885141cc406Sopenharmony_ci  DBG (10, "update_params: finish\n");
6886141cc406Sopenharmony_ci  return ret;
6887141cc406Sopenharmony_ci}
6888141cc406Sopenharmony_ci
6889141cc406Sopenharmony_ci/* set u_param data based on user settings, and s_params */
6890141cc406Sopenharmony_ciSANE_Status
6891141cc406Sopenharmony_ciupdate_u_params (struct fujitsu * s)
6892141cc406Sopenharmony_ci{
6893141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6894141cc406Sopenharmony_ci  SANE_Parameters * params = &(s->u_params);
6895141cc406Sopenharmony_ci
6896141cc406Sopenharmony_ci  DBG (10, "update_u_params: start\n");
6897141cc406Sopenharmony_ci
6898141cc406Sopenharmony_ci  /* for most machines, it is the same, so we just copy */
6899141cc406Sopenharmony_ci  memcpy(&(s->u_params), &(s->s_params), sizeof(SANE_Parameters));
6900141cc406Sopenharmony_ci
6901141cc406Sopenharmony_ci  /* some scanners don't support the user's mode, so params differ */
6902141cc406Sopenharmony_ci  /* but not in jpeg mode. we don't support that. */
6903141cc406Sopenharmony_ci  if(must_downsample(s)){
6904141cc406Sopenharmony_ci
6905141cc406Sopenharmony_ci    /* making gray from a color scan */
6906141cc406Sopenharmony_ci    if (s->u_mode == MODE_GRAYSCALE) {
6907141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
6908141cc406Sopenharmony_ci      params->bytes_per_line = params->pixels_per_line;
6909141cc406Sopenharmony_ci    }
6910141cc406Sopenharmony_ci    /* making binary from a gray or color scan */
6911141cc406Sopenharmony_ci    else if (s->u_mode == MODE_LINEART) {
6912141cc406Sopenharmony_ci      params->depth = 1;
6913141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
6914141cc406Sopenharmony_ci      params->bytes_per_line = params->pixels_per_line / 8;
6915141cc406Sopenharmony_ci    }
6916141cc406Sopenharmony_ci
6917141cc406Sopenharmony_ci    DBG(15,"update_u_params: x: max=%d, page=%d, gpw=%d, res=%d\n",
6918141cc406Sopenharmony_ci      s->max_x, s->page_width, get_page_width(s), s->resolution_x);
6919141cc406Sopenharmony_ci
6920141cc406Sopenharmony_ci    DBG(15,"update_u_params: y: max=%d, page=%d, gph=%d, res=%d\n",
6921141cc406Sopenharmony_ci      s->max_y, s->page_height, get_page_height(s), s->resolution_y);
6922141cc406Sopenharmony_ci
6923141cc406Sopenharmony_ci    DBG(15,"update_u_params: area: tlx=%d, brx=%d, tly=%d, bry=%d\n",
6924141cc406Sopenharmony_ci      s->tl_x, s->br_x, s->tl_y, s->br_y);
6925141cc406Sopenharmony_ci
6926141cc406Sopenharmony_ci    DBG(15,"update_u_params: params: ppl=%d, Bpl=%d, lines=%d\n",
6927141cc406Sopenharmony_ci      params->pixels_per_line, params->bytes_per_line, params->lines);
6928141cc406Sopenharmony_ci
6929141cc406Sopenharmony_ci    DBG(15,"update_u_params: params: format=%d, depth=%d, last=%d\n",
6930141cc406Sopenharmony_ci      params->format, params->depth, params->last_frame);
6931141cc406Sopenharmony_ci  }
6932141cc406Sopenharmony_ci
6933141cc406Sopenharmony_ci  DBG (10, "update_u_params: finish\n");
6934141cc406Sopenharmony_ci  return ret;
6935141cc406Sopenharmony_ci}
6936141cc406Sopenharmony_ci
6937141cc406Sopenharmony_ci/*
6938141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started.
6939141cc406Sopenharmony_ci * commands: scanner control (lampon), send (lut), send (dither),
6940141cc406Sopenharmony_ci * set window, object pos, and scan
6941141cc406Sopenharmony_ci *
6942141cc406Sopenharmony_ci * this will be called between sides of a duplex scan,
6943141cc406Sopenharmony_ci * and at the start of each page of an adf batch.
6944141cc406Sopenharmony_ci * hence, we spend a lot of time playing with s->started, etc.
6945141cc406Sopenharmony_ci */
6946141cc406Sopenharmony_ciSANE_Status
6947141cc406Sopenharmony_cisane_start (SANE_Handle handle)
6948141cc406Sopenharmony_ci{
6949141cc406Sopenharmony_ci  struct fujitsu *s = handle;
6950141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
6951141cc406Sopenharmony_ci
6952141cc406Sopenharmony_ci  DBG (10, "sane_start: start\n");
6953141cc406Sopenharmony_ci  DBG (15, "started=%d, side=%d, source=%d\n", s->started, s->side, s->source);
6954141cc406Sopenharmony_ci
6955141cc406Sopenharmony_ci  /* undo any prior sane_cancel calls */
6956141cc406Sopenharmony_ci  s->cancelled=0;
6957141cc406Sopenharmony_ci
6958141cc406Sopenharmony_ci  /* protect this block from sane_cancel */
6959141cc406Sopenharmony_ci  s->reading=1;
6960141cc406Sopenharmony_ci
6961141cc406Sopenharmony_ci  /* not finished with current side, error */
6962141cc406Sopenharmony_ci  if (s->started && !s->eof_tx[s->side]) {
6963141cc406Sopenharmony_ci      DBG(5,"sane_start: previous transfer not finished?");
6964141cc406Sopenharmony_ci      ret = SANE_STATUS_INVAL;
6965141cc406Sopenharmony_ci      goto errors;
6966141cc406Sopenharmony_ci  }
6967141cc406Sopenharmony_ci
6968141cc406Sopenharmony_ci  /* low mem mode messes up the side marker, reset it */
6969141cc406Sopenharmony_ci  if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
6970141cc406Sopenharmony_ci    && s->low_mem && s->eof_tx[SIDE_FRONT] && s->eof_tx[SIDE_BACK]
6971141cc406Sopenharmony_ci  ){
6972141cc406Sopenharmony_ci    s->side = SIDE_BACK;
6973141cc406Sopenharmony_ci  }
6974141cc406Sopenharmony_ci
6975141cc406Sopenharmony_ci  /* batch start? initialize struct and scanner */
6976141cc406Sopenharmony_ci  if(!s->started){
6977141cc406Sopenharmony_ci
6978141cc406Sopenharmony_ci      /* load side marker */
6979141cc406Sopenharmony_ci      if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
6980141cc406Sopenharmony_ci        s->side = SIDE_BACK;
6981141cc406Sopenharmony_ci      }
6982141cc406Sopenharmony_ci      else{
6983141cc406Sopenharmony_ci        s->side = SIDE_FRONT;
6984141cc406Sopenharmony_ci      }
6985141cc406Sopenharmony_ci
6986141cc406Sopenharmony_ci      /* load our own private copy of scan params */
6987141cc406Sopenharmony_ci      ret = update_params(s);
6988141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
6989141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot update params\n");
6990141cc406Sopenharmony_ci        goto errors;
6991141cc406Sopenharmony_ci      }
6992141cc406Sopenharmony_ci
6993141cc406Sopenharmony_ci      /* switch source */
6994141cc406Sopenharmony_ci      if(s->source == SOURCE_FLATBED){
6995141cc406Sopenharmony_ci        ret = scanner_control(s, SC_function_fb);
6996141cc406Sopenharmony_ci        if (ret != SANE_STATUS_GOOD) {
6997141cc406Sopenharmony_ci          DBG (5, "sane_start: ERROR: cannot control fb, ignoring\n");
6998141cc406Sopenharmony_ci        }
6999141cc406Sopenharmony_ci      }
7000141cc406Sopenharmony_ci      else if(s->source == SOURCE_CARD_FRONT || s->source == SOURCE_CARD_BACK || s->source == SOURCE_CARD_DUPLEX){
7001141cc406Sopenharmony_ci        ret = scanner_control(s, SC_function_rpath);
7002141cc406Sopenharmony_ci        if (ret != SANE_STATUS_GOOD) {
7003141cc406Sopenharmony_ci          DBG (5, "sane_start: ERROR: cannot control rp, ignoring\n");
7004141cc406Sopenharmony_ci        }
7005141cc406Sopenharmony_ci      }
7006141cc406Sopenharmony_ci      else{
7007141cc406Sopenharmony_ci        ret = scanner_control(s, SC_function_adf);
7008141cc406Sopenharmony_ci        if (ret != SANE_STATUS_GOOD) {
7009141cc406Sopenharmony_ci          DBG (5, "sane_start: ERROR: cannot control ADF, ignoring\n");
7010141cc406Sopenharmony_ci        }
7011141cc406Sopenharmony_ci      }
7012141cc406Sopenharmony_ci
7013141cc406Sopenharmony_ci      /* required for hi res scans on iX500? */
7014141cc406Sopenharmony_ci      ret = diag_preread(s);
7015141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7016141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot diag_preread %d\n", ret);
7017141cc406Sopenharmony_ci
7018141cc406Sopenharmony_ci      /* enable overscan/auto detection */
7019141cc406Sopenharmony_ci      ret = mode_select_auto(s);
7020141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7021141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_auto %d\n", ret);
7022141cc406Sopenharmony_ci
7023141cc406Sopenharmony_ci      /* enable double feed detection */
7024141cc406Sopenharmony_ci      ret = mode_select_df(s);
7025141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7026141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_df %d\n", ret);
7027141cc406Sopenharmony_ci
7028141cc406Sopenharmony_ci      /* enable background color setting */
7029141cc406Sopenharmony_ci      ret = mode_select_bg(s);
7030141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7031141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_bg %d\n", ret);
7032141cc406Sopenharmony_ci
7033141cc406Sopenharmony_ci      /* enable dropout color setting */
7034141cc406Sopenharmony_ci      ret = mode_select_dropout(s);
7035141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7036141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_dropout %d\n", ret);
7037141cc406Sopenharmony_ci
7038141cc406Sopenharmony_ci      /* enable buffering setting */
7039141cc406Sopenharmony_ci      ret = mode_select_buff(s);
7040141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7041141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_buff %d\n", ret);
7042141cc406Sopenharmony_ci
7043141cc406Sopenharmony_ci      /* enable prepick setting */
7044141cc406Sopenharmony_ci      ret = mode_select_prepick(s);
7045141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7046141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot mode_select_prepick %d\n", ret);
7047141cc406Sopenharmony_ci
7048141cc406Sopenharmony_ci      /* send endorser config */
7049141cc406Sopenharmony_ci      ret = send_endorser(s);
7050141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD)
7051141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot send_endorser %d\n", ret);
7052141cc406Sopenharmony_ci
7053141cc406Sopenharmony_ci      /* set window command */
7054141cc406Sopenharmony_ci      ret = set_window(s);
7055141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7056141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot set window\n");
7057141cc406Sopenharmony_ci        goto errors;
7058141cc406Sopenharmony_ci      }
7059141cc406Sopenharmony_ci
7060141cc406Sopenharmony_ci      /* send lut if set_window said we would */
7061141cc406Sopenharmony_ci      if ( s->window_gamma ){
7062141cc406Sopenharmony_ci        ret = send_lut(s);
7063141cc406Sopenharmony_ci        if (ret != SANE_STATUS_GOOD)
7064141cc406Sopenharmony_ci          DBG (5, "sane_start: WARNING: cannot send_lut %d\n", ret);
7065141cc406Sopenharmony_ci      }
7066141cc406Sopenharmony_ci
7067141cc406Sopenharmony_ci      /* some scanners need the q table sent, even when not scanning jpeg */
7068141cc406Sopenharmony_ci      if (s->need_q_table){
7069141cc406Sopenharmony_ci        ret = send_q_table(s);
7070141cc406Sopenharmony_ci        if (ret != SANE_STATUS_GOOD)
7071141cc406Sopenharmony_ci          DBG (5, "sane_start: WARNING: cannot send_q_table %d\n", ret);
7072141cc406Sopenharmony_ci      }
7073141cc406Sopenharmony_ci
7074141cc406Sopenharmony_ci      /* start/stop endorser */
7075141cc406Sopenharmony_ci      ret = endorser(s);
7076141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7077141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot start/stop endorser\n");
7078141cc406Sopenharmony_ci        goto errors;
7079141cc406Sopenharmony_ci      }
7080141cc406Sopenharmony_ci
7081141cc406Sopenharmony_ci      /* turn lamp on */
7082141cc406Sopenharmony_ci      ret = scanner_control(s, SC_function_lamp_on);
7083141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7084141cc406Sopenharmony_ci        DBG (5, "sane_start: WARNING: cannot start lamp, ignoring\n");
7085141cc406Sopenharmony_ci      }
7086141cc406Sopenharmony_ci
7087141cc406Sopenharmony_ci      /* iX500 errors if op is called with no paper
7088141cc406Sopenharmony_ci       * at the beginning of a batch, so we check */
7089141cc406Sopenharmony_ci      if(s->hopper_before_op && s->source != SOURCE_FLATBED){
7090141cc406Sopenharmony_ci        ret = get_hardware_status(s,0);
7091141cc406Sopenharmony_ci        if(!s->hw_hopper){
7092141cc406Sopenharmony_ci          ret = SANE_STATUS_NO_DOCS;
7093141cc406Sopenharmony_ci          DBG (5, "sane_start: ERROR: hopper empty\n");
7094141cc406Sopenharmony_ci          goto errors;
7095141cc406Sopenharmony_ci        }
7096141cc406Sopenharmony_ci      }
7097141cc406Sopenharmony_ci  }
7098141cc406Sopenharmony_ci  /* if already running, duplex needs to switch sides */
7099141cc406Sopenharmony_ci  else if(s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX){
7100141cc406Sopenharmony_ci      s->side = !s->side;
7101141cc406Sopenharmony_ci  }
7102141cc406Sopenharmony_ci
7103141cc406Sopenharmony_ci  /* set clean defaults with new sheet of paper */
7104141cc406Sopenharmony_ci  /* don't reset the transfer vars on backside of duplex page */
7105141cc406Sopenharmony_ci  /* otherwise buffered back page will be lost */
7106141cc406Sopenharmony_ci  /* ingest paper with adf (no-op for fb) */
7107141cc406Sopenharmony_ci  /* don't call object pos or scan on back side of duplex scan */
7108141cc406Sopenharmony_ci  if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
7109141cc406Sopenharmony_ci
7110141cc406Sopenharmony_ci      s->bytes_rx[0]=0;
7111141cc406Sopenharmony_ci      s->bytes_rx[1]=0;
7112141cc406Sopenharmony_ci      s->lines_rx[0]=0;
7113141cc406Sopenharmony_ci      s->lines_rx[1]=0;
7114141cc406Sopenharmony_ci      s->eof_rx[0]=0;
7115141cc406Sopenharmony_ci      s->eof_rx[1]=0;
7116141cc406Sopenharmony_ci      s->ili_rx[0]=0;
7117141cc406Sopenharmony_ci      s->ili_rx[1]=0;
7118141cc406Sopenharmony_ci      s->eom_rx=0;
7119141cc406Sopenharmony_ci
7120141cc406Sopenharmony_ci      s->bytes_tx[0]=0;
7121141cc406Sopenharmony_ci      s->bytes_tx[1]=0;
7122141cc406Sopenharmony_ci      s->eof_tx[0]=0;
7123141cc406Sopenharmony_ci      s->eof_tx[1]=0;
7124141cc406Sopenharmony_ci
7125141cc406Sopenharmony_ci      s->buff_rx[0]=0;
7126141cc406Sopenharmony_ci      s->buff_rx[1]=0;
7127141cc406Sopenharmony_ci      s->buff_tx[0]=0;
7128141cc406Sopenharmony_ci      s->buff_tx[1]=0;
7129141cc406Sopenharmony_ci
7130141cc406Sopenharmony_ci      /* reset jpeg just in case... */
7131141cc406Sopenharmony_ci      s->jpeg_stage = JPEG_STAGE_NONE;
7132141cc406Sopenharmony_ci      s->jpeg_ff_offset = -1;
7133141cc406Sopenharmony_ci      s->jpeg_front_rst = 0;
7134141cc406Sopenharmony_ci      s->jpeg_back_rst = 0;
7135141cc406Sopenharmony_ci
7136141cc406Sopenharmony_ci      ret = object_position (s, OP_Feed);
7137141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7138141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot load page\n");
7139141cc406Sopenharmony_ci        goto errors;
7140141cc406Sopenharmony_ci      }
7141141cc406Sopenharmony_ci
7142141cc406Sopenharmony_ci      ret = start_scan (s);
7143141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7144141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot start_scan\n");
7145141cc406Sopenharmony_ci        goto errors;
7146141cc406Sopenharmony_ci      }
7147141cc406Sopenharmony_ci
7148141cc406Sopenharmony_ci      /* try to read scan size from scanner */
7149141cc406Sopenharmony_ci      ret = get_pixelsize(s,0);
7150141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7151141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot get pixelsize\n");
7152141cc406Sopenharmony_ci        goto errors;
7153141cc406Sopenharmony_ci      }
7154141cc406Sopenharmony_ci
7155141cc406Sopenharmony_ci      /* store the number of front bytes */
7156141cc406Sopenharmony_ci      if ( s->source != SOURCE_ADF_BACK && s->source != SOURCE_CARD_BACK ){
7157141cc406Sopenharmony_ci        s->bytes_tot[SIDE_FRONT] = s->s_params.bytes_per_line * s->s_params.lines;
7158141cc406Sopenharmony_ci        s->buff_tot[SIDE_FRONT] = s->buffer_size;
7159141cc406Sopenharmony_ci
7160141cc406Sopenharmony_ci        /* the front buffer is normally very small, but some scanners or
7161141cc406Sopenharmony_ci         * option combinations can't handle it, so we make a big one */
7162141cc406Sopenharmony_ci        if(
7163141cc406Sopenharmony_ci          (s->s_mode == MODE_COLOR && s->color_interlace == COLOR_INTERLACE_3091)
7164141cc406Sopenharmony_ci          || must_fully_buffer(s)
7165141cc406Sopenharmony_ci        ){
7166141cc406Sopenharmony_ci          s->buff_tot[SIDE_FRONT] = s->bytes_tot[SIDE_FRONT];
7167141cc406Sopenharmony_ci        }
7168141cc406Sopenharmony_ci      }
7169141cc406Sopenharmony_ci      else{
7170141cc406Sopenharmony_ci        s->bytes_tot[SIDE_FRONT] = 0;
7171141cc406Sopenharmony_ci        s->buff_tot[SIDE_FRONT] = 0;
7172141cc406Sopenharmony_ci      }
7173141cc406Sopenharmony_ci
7174141cc406Sopenharmony_ci      /* store the number of back bytes */
7175141cc406Sopenharmony_ci      if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK
7176141cc406Sopenharmony_ci	|| s->source == SOURCE_CARD_DUPLEX || s->source == SOURCE_CARD_BACK ){
7177141cc406Sopenharmony_ci        s->bytes_tot[SIDE_BACK] = s->s_params.bytes_per_line * s->s_params.lines;
7178141cc406Sopenharmony_ci        s->buff_tot[SIDE_BACK] = s->bytes_tot[SIDE_BACK];
7179141cc406Sopenharmony_ci
7180141cc406Sopenharmony_ci        /* the back buffer is normally very large, but some scanners or
7181141cc406Sopenharmony_ci         * option combinations don't need it, so we make a small one */
7182141cc406Sopenharmony_ci        if(s->low_mem || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
7183141cc406Sopenharmony_ci         || s->duplex_interlace == DUPLEX_INTERLACE_NONE)
7184141cc406Sopenharmony_ci          s->buff_tot[SIDE_BACK] = s->buffer_size;
7185141cc406Sopenharmony_ci      }
7186141cc406Sopenharmony_ci      else{
7187141cc406Sopenharmony_ci        s->bytes_tot[SIDE_BACK] = 0;
7188141cc406Sopenharmony_ci        s->buff_tot[SIDE_BACK] = 0;
7189141cc406Sopenharmony_ci      }
7190141cc406Sopenharmony_ci
7191141cc406Sopenharmony_ci      /* first page of batch */
7192141cc406Sopenharmony_ci      /* make large buffer to hold the images */
7193141cc406Sopenharmony_ci      /* and set started flag */
7194141cc406Sopenharmony_ci      if(!s->started){
7195141cc406Sopenharmony_ci          ret = setup_buffers(s);
7196141cc406Sopenharmony_ci          if (ret != SANE_STATUS_GOOD) {
7197141cc406Sopenharmony_ci              DBG (5, "sane_start: ERROR: cannot load buffers\n");
7198141cc406Sopenharmony_ci              goto errors;
7199141cc406Sopenharmony_ci          }
7200141cc406Sopenharmony_ci
7201141cc406Sopenharmony_ci          s->started=1;
7202141cc406Sopenharmony_ci      }
7203141cc406Sopenharmony_ci  }
7204141cc406Sopenharmony_ci  else{
7205141cc406Sopenharmony_ci      /* try to read scan size from scanner */
7206141cc406Sopenharmony_ci      ret = get_pixelsize(s,0);
7207141cc406Sopenharmony_ci      if (ret != SANE_STATUS_GOOD) {
7208141cc406Sopenharmony_ci        DBG (5, "sane_start: ERROR: cannot get pixelsize\n");
7209141cc406Sopenharmony_ci        goto errors;
7210141cc406Sopenharmony_ci      }
7211141cc406Sopenharmony_ci  }
7212141cc406Sopenharmony_ci
7213141cc406Sopenharmony_ci  DBG (15, "started=%d, side=%d, source=%d\n", s->started, s->side, s->source);
7214141cc406Sopenharmony_ci
7215141cc406Sopenharmony_ci  /* certain options require the entire image to
7216141cc406Sopenharmony_ci   * be collected from the scanner before we can
7217141cc406Sopenharmony_ci   * tell the user the size of the image. the sane
7218141cc406Sopenharmony_ci   * API has no way to inform the frontend of this,
7219141cc406Sopenharmony_ci   * so we block and buffer. yuck */
7220141cc406Sopenharmony_ci  if( must_fully_buffer(s) ){
7221141cc406Sopenharmony_ci
7222141cc406Sopenharmony_ci    /* get image */
7223141cc406Sopenharmony_ci    while(!s->eof_rx[s->side] && !ret){
7224141cc406Sopenharmony_ci      SANE_Int len = 0;
7225141cc406Sopenharmony_ci      ret = sane_read((SANE_Handle)s, NULL, 0, &len);
7226141cc406Sopenharmony_ci    }
7227141cc406Sopenharmony_ci
7228141cc406Sopenharmony_ci    /* check for errors */
7229141cc406Sopenharmony_ci    if (ret != SANE_STATUS_GOOD) {
7230141cc406Sopenharmony_ci      DBG (5, "sane_start: ERROR: cannot buffer image\n");
7231141cc406Sopenharmony_ci      goto errors;
7232141cc406Sopenharmony_ci    }
7233141cc406Sopenharmony_ci
7234141cc406Sopenharmony_ci    DBG (5, "sane_start: OK: done buffering\n");
7235141cc406Sopenharmony_ci
7236141cc406Sopenharmony_ci    /* hardware deskew will tell image size after transfer */
7237141cc406Sopenharmony_ci    ret = get_pixelsize(s,1);
7238141cc406Sopenharmony_ci    if (ret != SANE_STATUS_GOOD) {
7239141cc406Sopenharmony_ci      DBG (5, "sane_start: ERROR: cannot get final pixelsize\n");
7240141cc406Sopenharmony_ci      goto errors;
7241141cc406Sopenharmony_ci    }
7242141cc406Sopenharmony_ci
7243141cc406Sopenharmony_ci    /* finished buffering, adjust image as required */
7244141cc406Sopenharmony_ci    if(s->swdeskew && (!s->hwdeskewcrop || s->req_driv_crop)){
7245141cc406Sopenharmony_ci      buffer_deskew(s,s->side);
7246141cc406Sopenharmony_ci    }
7247141cc406Sopenharmony_ci    if(s->swcrop && (!s->hwdeskewcrop || s->req_driv_crop)){
7248141cc406Sopenharmony_ci      buffer_crop(s,s->side);
7249141cc406Sopenharmony_ci    }
7250141cc406Sopenharmony_ci    if(s->swdespeck){
7251141cc406Sopenharmony_ci      buffer_despeck(s,s->side);
7252141cc406Sopenharmony_ci    }
7253141cc406Sopenharmony_ci    if(s->swskip){
7254141cc406Sopenharmony_ci      /* Skipping means throwing out this image.
7255141cc406Sopenharmony_ci       * Pretend the user read the whole thing
7256141cc406Sopenharmony_ci       * and call sane_start again.
7257141cc406Sopenharmony_ci       * This assumes we are running in batch mode. */
7258141cc406Sopenharmony_ci      if(buffer_isblank(s,s->side)){
7259141cc406Sopenharmony_ci        s->bytes_tx[s->side] = s->bytes_rx[s->side];
7260141cc406Sopenharmony_ci        s->eof_tx[s->side] = 1;
7261141cc406Sopenharmony_ci        return sane_start(handle);
7262141cc406Sopenharmony_ci      }
7263141cc406Sopenharmony_ci    }
7264141cc406Sopenharmony_ci
7265141cc406Sopenharmony_ci  }
7266141cc406Sopenharmony_ci
7267141cc406Sopenharmony_ci  /* check if user cancelled during this start */
7268141cc406Sopenharmony_ci  ret = check_for_cancel(s);
7269141cc406Sopenharmony_ci
7270141cc406Sopenharmony_ci  /* unprotect this block from sane_cancel */
7271141cc406Sopenharmony_ci  s->reading=0;
7272141cc406Sopenharmony_ci
7273141cc406Sopenharmony_ci  DBG (10, "sane_start: finish %d\n", ret);
7274141cc406Sopenharmony_ci  return ret;
7275141cc406Sopenharmony_ci
7276141cc406Sopenharmony_ci  errors:
7277141cc406Sopenharmony_ci    DBG (10, "sane_start: error %d\n", ret);
7278141cc406Sopenharmony_ci
7279141cc406Sopenharmony_ci    /* if we are started, but something went wrong,
7280141cc406Sopenharmony_ci     * chances are there is image data inside scanner,
7281141cc406Sopenharmony_ci     * which should be discarded via cancel command */
7282141cc406Sopenharmony_ci    if(s->started){
7283141cc406Sopenharmony_ci      s->cancelled = 1;
7284141cc406Sopenharmony_ci      check_for_cancel(s);
7285141cc406Sopenharmony_ci    }
7286141cc406Sopenharmony_ci
7287141cc406Sopenharmony_ci    s->started = 0;
7288141cc406Sopenharmony_ci    s->cancelled = 0;
7289141cc406Sopenharmony_ci    s->reading = 0;
7290141cc406Sopenharmony_ci    return ret;
7291141cc406Sopenharmony_ci}
7292141cc406Sopenharmony_ci
7293141cc406Sopenharmony_cistatic SANE_Status
7294141cc406Sopenharmony_ciendorser(struct fujitsu *s)
7295141cc406Sopenharmony_ci{
7296141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7297141cc406Sopenharmony_ci
7298141cc406Sopenharmony_ci  unsigned char cmd[ENDORSER_len];
7299141cc406Sopenharmony_ci  size_t cmdLen = ENDORSER_len;
7300141cc406Sopenharmony_ci
7301141cc406Sopenharmony_ci  unsigned char out[ED_max_len];
7302141cc406Sopenharmony_ci  size_t outLen = ED_max_len;
7303141cc406Sopenharmony_ci
7304141cc406Sopenharmony_ci  DBG (10, "endorser: start\n");
7305141cc406Sopenharmony_ci
7306141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
7307141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, ENDORSER_code);
7308141cc406Sopenharmony_ci
7309141cc406Sopenharmony_ci  memset(out,0,outLen);
7310141cc406Sopenharmony_ci
7311141cc406Sopenharmony_ci  if (s->has_endorser_f || s->has_endorser_b){
7312141cc406Sopenharmony_ci
7313141cc406Sopenharmony_ci    /*fi-5900 front side uses 0x80, assume all others*/
7314141cc406Sopenharmony_ci    if(s->u_endorser_side == ED_front){
7315141cc406Sopenharmony_ci      set_ED_endorser_data_id(out,0x80);
7316141cc406Sopenharmony_ci    }
7317141cc406Sopenharmony_ci    else{
7318141cc406Sopenharmony_ci      set_ED_endorser_data_id(out,0);
7319141cc406Sopenharmony_ci    }
7320141cc406Sopenharmony_ci
7321141cc406Sopenharmony_ci    if(s->u_endorser){
7322141cc406Sopenharmony_ci      set_ED_stop(out,ED_start);
7323141cc406Sopenharmony_ci    }
7324141cc406Sopenharmony_ci    else{
7325141cc406Sopenharmony_ci      set_ED_stop(out,ED_stop);
7326141cc406Sopenharmony_ci    }
7327141cc406Sopenharmony_ci
7328141cc406Sopenharmony_ci    set_ED_side(out,s->u_endorser_side);
7329141cc406Sopenharmony_ci
7330141cc406Sopenharmony_ci    if(s->u_endorser_bits == 24){
7331141cc406Sopenharmony_ci      set_ED_lap24(out,ED_lap_24bit);
7332141cc406Sopenharmony_ci      set_ED_initial_count_24(out,s->u_endorser_val);
7333141cc406Sopenharmony_ci    }
7334141cc406Sopenharmony_ci
7335141cc406Sopenharmony_ci    else{
7336141cc406Sopenharmony_ci      outLen = ED_min_len;
7337141cc406Sopenharmony_ci      set_ED_lap24(out,ED_lap_16bit);
7338141cc406Sopenharmony_ci      set_ED_initial_count_16(out,s->u_endorser_val);
7339141cc406Sopenharmony_ci    }
7340141cc406Sopenharmony_ci
7341141cc406Sopenharmony_ci    set_E_xferlen(cmd, outLen);
7342141cc406Sopenharmony_ci    ret = do_cmd (
7343141cc406Sopenharmony_ci      s, 1, 0,
7344141cc406Sopenharmony_ci      cmd, cmdLen,
7345141cc406Sopenharmony_ci      out, outLen,
7346141cc406Sopenharmony_ci      NULL, NULL
7347141cc406Sopenharmony_ci    );
7348141cc406Sopenharmony_ci  }
7349141cc406Sopenharmony_ci
7350141cc406Sopenharmony_ci  DBG (10, "endorser: finish %d\n", ret);
7351141cc406Sopenharmony_ci
7352141cc406Sopenharmony_ci  return ret;
7353141cc406Sopenharmony_ci}
7354141cc406Sopenharmony_ci
7355141cc406Sopenharmony_cistatic SANE_Status
7356141cc406Sopenharmony_ciscanner_control (struct fujitsu *s, int function)
7357141cc406Sopenharmony_ci{
7358141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7359141cc406Sopenharmony_ci  int tries = 0;
7360141cc406Sopenharmony_ci
7361141cc406Sopenharmony_ci  unsigned char cmd[SCANNER_CONTROL_len];
7362141cc406Sopenharmony_ci  size_t cmdLen = SCANNER_CONTROL_len;
7363141cc406Sopenharmony_ci
7364141cc406Sopenharmony_ci  DBG (10, "scanner_control: start\n");
7365141cc406Sopenharmony_ci
7366141cc406Sopenharmony_ci  if(s->has_cmd_scanner_ctl){
7367141cc406Sopenharmony_ci
7368141cc406Sopenharmony_ci    memset(cmd,0,cmdLen);
7369141cc406Sopenharmony_ci    set_SCSI_opcode(cmd, SCANNER_CONTROL_code);
7370141cc406Sopenharmony_ci    set_SC_function_1 (cmd, function);
7371141cc406Sopenharmony_ci    set_SC_function_2 (cmd, function);
7372141cc406Sopenharmony_ci
7373141cc406Sopenharmony_ci    DBG (15, "scanner_control: function %d\n",function);
7374141cc406Sopenharmony_ci
7375141cc406Sopenharmony_ci    /* don't really need to ask for adf if that's the only option */
7376141cc406Sopenharmony_ci    /* doing so causes the 3091 to complain */
7377141cc406Sopenharmony_ci    if(function == SC_function_adf && !s->has_flatbed && !s->has_return_path){
7378141cc406Sopenharmony_ci      DBG (10, "scanner_control: adf function not required\n");
7379141cc406Sopenharmony_ci      return ret;
7380141cc406Sopenharmony_ci    }
7381141cc406Sopenharmony_ci
7382141cc406Sopenharmony_ci    /* extremely long retry period */
7383141cc406Sopenharmony_ci    while(tries++ < 120){
7384141cc406Sopenharmony_ci
7385141cc406Sopenharmony_ci      ret = do_cmd (
7386141cc406Sopenharmony_ci        s, 1, 0,
7387141cc406Sopenharmony_ci        cmd, cmdLen,
7388141cc406Sopenharmony_ci        NULL, 0,
7389141cc406Sopenharmony_ci        NULL, NULL
7390141cc406Sopenharmony_ci      );
7391141cc406Sopenharmony_ci
7392141cc406Sopenharmony_ci      if(ret == SANE_STATUS_GOOD || function != SC_function_lamp_on){
7393141cc406Sopenharmony_ci        break;
7394141cc406Sopenharmony_ci      }
7395141cc406Sopenharmony_ci
7396141cc406Sopenharmony_ci      usleep(500000);
7397141cc406Sopenharmony_ci    }
7398141cc406Sopenharmony_ci
7399141cc406Sopenharmony_ci    if(ret == SANE_STATUS_GOOD){
7400141cc406Sopenharmony_ci      DBG (15, "scanner_control: success, tries %d, ret %d\n",tries,ret);
7401141cc406Sopenharmony_ci    }
7402141cc406Sopenharmony_ci    else{
7403141cc406Sopenharmony_ci      DBG (5, "scanner_control: error, tries %d, ret %d\n",tries,ret);
7404141cc406Sopenharmony_ci    }
7405141cc406Sopenharmony_ci  }
7406141cc406Sopenharmony_ci
7407141cc406Sopenharmony_ci  DBG (10, "scanner_control: finish\n");
7408141cc406Sopenharmony_ci
7409141cc406Sopenharmony_ci  return ret;
7410141cc406Sopenharmony_ci}
7411141cc406Sopenharmony_ci
7412141cc406Sopenharmony_cistatic SANE_Status
7413141cc406Sopenharmony_ciscanner_control_ric (struct fujitsu *s, int bytes, int side)
7414141cc406Sopenharmony_ci{
7415141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7416141cc406Sopenharmony_ci  int tries = 0;
7417141cc406Sopenharmony_ci
7418141cc406Sopenharmony_ci  unsigned char cmd[SCANNER_CONTROL_len];
7419141cc406Sopenharmony_ci  size_t cmdLen = SCANNER_CONTROL_len;
7420141cc406Sopenharmony_ci
7421141cc406Sopenharmony_ci  DBG (10, "scanner_control_ric: start\n");
7422141cc406Sopenharmony_ci
7423141cc406Sopenharmony_ci  if(s->has_cmd_scanner_ctl){
7424141cc406Sopenharmony_ci
7425141cc406Sopenharmony_ci    memset(cmd,0,cmdLen);
7426141cc406Sopenharmony_ci    set_SCSI_opcode(cmd, SCANNER_CONTROL_code);
7427141cc406Sopenharmony_ci
7428141cc406Sopenharmony_ci    set_SC_ric(cmd, 1);
7429141cc406Sopenharmony_ci    if (side == SIDE_BACK) {
7430141cc406Sopenharmony_ci        set_SC_ric_dtq(cmd, WD_wid_back);
7431141cc406Sopenharmony_ci    }
7432141cc406Sopenharmony_ci    else{
7433141cc406Sopenharmony_ci        set_SC_ric_dtq(cmd, WD_wid_front);
7434141cc406Sopenharmony_ci    }
7435141cc406Sopenharmony_ci
7436141cc406Sopenharmony_ci    set_SC_ric_len(cmd, bytes);
7437141cc406Sopenharmony_ci
7438141cc406Sopenharmony_ci    DBG (15, "scanner_control_ric: %d %d\n",bytes,side);
7439141cc406Sopenharmony_ci
7440141cc406Sopenharmony_ci    /* extremely long retry period */
7441141cc406Sopenharmony_ci    while(tries++ < 120){
7442141cc406Sopenharmony_ci
7443141cc406Sopenharmony_ci      ret = do_cmd (
7444141cc406Sopenharmony_ci        s, 1, 0,
7445141cc406Sopenharmony_ci        cmd, cmdLen,
7446141cc406Sopenharmony_ci        NULL, 0,
7447141cc406Sopenharmony_ci        NULL, NULL
7448141cc406Sopenharmony_ci      );
7449141cc406Sopenharmony_ci
7450141cc406Sopenharmony_ci      if(ret != SANE_STATUS_DEVICE_BUSY){
7451141cc406Sopenharmony_ci        break;
7452141cc406Sopenharmony_ci      }
7453141cc406Sopenharmony_ci
7454141cc406Sopenharmony_ci      usleep(500000);
7455141cc406Sopenharmony_ci    }
7456141cc406Sopenharmony_ci
7457141cc406Sopenharmony_ci    if(ret == SANE_STATUS_GOOD){
7458141cc406Sopenharmony_ci      DBG (15, "scanner_control_ric: success, tries %d, ret %d\n",tries,ret);
7459141cc406Sopenharmony_ci    }
7460141cc406Sopenharmony_ci    /* some errors pass thru unchanged */
7461141cc406Sopenharmony_ci    else if(ret == SANE_STATUS_CANCELLED || ret == SANE_STATUS_JAMMED
7462141cc406Sopenharmony_ci      || ret == SANE_STATUS_NO_DOCS || ret == SANE_STATUS_COVER_OPEN
7463141cc406Sopenharmony_ci    ){
7464141cc406Sopenharmony_ci      DBG (5, "scanner_control_ric: error, tries %d, ret %d\n",tries,ret);
7465141cc406Sopenharmony_ci    }
7466141cc406Sopenharmony_ci    /* other errors are ignored, since scanner may not support RIC */
7467141cc406Sopenharmony_ci    else{
7468141cc406Sopenharmony_ci      DBG (5, "scanner_control_ric: ignoring, tries %d, ret %d\n",tries,ret);
7469141cc406Sopenharmony_ci      ret = SANE_STATUS_GOOD;
7470141cc406Sopenharmony_ci    }
7471141cc406Sopenharmony_ci  }
7472141cc406Sopenharmony_ci
7473141cc406Sopenharmony_ci  DBG (10, "scanner_control_ric: finish\n");
7474141cc406Sopenharmony_ci
7475141cc406Sopenharmony_ci  return ret;
7476141cc406Sopenharmony_ci}
7477141cc406Sopenharmony_ci
7478141cc406Sopenharmony_ci/*
7479141cc406Sopenharmony_ci * callocs a buffer to hold the scan data
7480141cc406Sopenharmony_ci */
7481141cc406Sopenharmony_cistatic SANE_Status
7482141cc406Sopenharmony_cisetup_buffers (struct fujitsu *s)
7483141cc406Sopenharmony_ci{
7484141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7485141cc406Sopenharmony_ci  int side;
7486141cc406Sopenharmony_ci
7487141cc406Sopenharmony_ci  DBG (10, "setup_buffers: start\n");
7488141cc406Sopenharmony_ci
7489141cc406Sopenharmony_ci  for(side=0;side<2;side++){
7490141cc406Sopenharmony_ci
7491141cc406Sopenharmony_ci    /* free old mem */
7492141cc406Sopenharmony_ci    if (s->buffers[side]) {
7493141cc406Sopenharmony_ci      DBG (15, "setup_buffers: free buffer %d.\n",side);
7494141cc406Sopenharmony_ci      free(s->buffers[side]);
7495141cc406Sopenharmony_ci      s->buffers[side] = NULL;
7496141cc406Sopenharmony_ci    }
7497141cc406Sopenharmony_ci
7498141cc406Sopenharmony_ci    if(s->buff_tot[side]){
7499141cc406Sopenharmony_ci      s->buffers[side] = calloc (1,s->buff_tot[side]);
7500141cc406Sopenharmony_ci
7501141cc406Sopenharmony_ci      if (!s->buffers[side]) {
7502141cc406Sopenharmony_ci        DBG (5, "setup_buffers: Error, no buffer %d.\n",side);
7503141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
7504141cc406Sopenharmony_ci      }
7505141cc406Sopenharmony_ci    }
7506141cc406Sopenharmony_ci  }
7507141cc406Sopenharmony_ci
7508141cc406Sopenharmony_ci  DBG (10, "setup_buffers: finish\n");
7509141cc406Sopenharmony_ci
7510141cc406Sopenharmony_ci  return ret;
7511141cc406Sopenharmony_ci}
7512141cc406Sopenharmony_ci
7513141cc406Sopenharmony_ci/*
7514141cc406Sopenharmony_ci * This routine issues a SCSI SET WINDOW command to the scanner, using the
7515141cc406Sopenharmony_ci * values currently in the scanner data structure.
7516141cc406Sopenharmony_ci */
7517141cc406Sopenharmony_cistatic SANE_Status
7518141cc406Sopenharmony_ciset_window (struct fujitsu *s)
7519141cc406Sopenharmony_ci{
7520141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7521141cc406Sopenharmony_ci
7522141cc406Sopenharmony_ci  /* The command specifies the number of bytes in the data phase
7523141cc406Sopenharmony_ci   * the data phase has a header, followed by 1 or 2 window desc blocks
7524141cc406Sopenharmony_ci   * the header specifies the number of bytes in 1 window desc block
7525141cc406Sopenharmony_ci   */
7526141cc406Sopenharmony_ci
7527141cc406Sopenharmony_ci  unsigned char cmd[SET_WINDOW_len];
7528141cc406Sopenharmony_ci  size_t cmdLen = SET_WINDOW_len;
7529141cc406Sopenharmony_ci
7530141cc406Sopenharmony_ci  /*this is max size, we might send less below*/
7531141cc406Sopenharmony_ci  unsigned char out[SW_header_len + SW_desc_len + SW_desc_len];
7532141cc406Sopenharmony_ci  size_t outLen = SW_header_len + SW_desc_len + SW_desc_len;
7533141cc406Sopenharmony_ci
7534141cc406Sopenharmony_ci  unsigned char * header = out;                              /*header*/
7535141cc406Sopenharmony_ci  unsigned char * desc1 = out + SW_header_len;               /*1st desc*/
7536141cc406Sopenharmony_ci  unsigned char * desc2 = out + SW_header_len + SW_desc_len; /*2nd desc*/
7537141cc406Sopenharmony_ci
7538141cc406Sopenharmony_ci  int length = 0;
7539141cc406Sopenharmony_ci
7540141cc406Sopenharmony_ci  DBG (10, "set_window: start\n");
7541141cc406Sopenharmony_ci
7542141cc406Sopenharmony_ci  /*build the payload*/
7543141cc406Sopenharmony_ci  memset(out,0,outLen);
7544141cc406Sopenharmony_ci
7545141cc406Sopenharmony_ci  /* set window desc size in header */
7546141cc406Sopenharmony_ci  set_WPDB_wdblen(header, SW_desc_len);
7547141cc406Sopenharmony_ci
7548141cc406Sopenharmony_ci  /* init the window block */
7549141cc406Sopenharmony_ci  if (s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
7550141cc406Sopenharmony_ci    set_WD_wid (desc1, WD_wid_back);
7551141cc406Sopenharmony_ci  }
7552141cc406Sopenharmony_ci  else{
7553141cc406Sopenharmony_ci    set_WD_wid (desc1, WD_wid_front);
7554141cc406Sopenharmony_ci  }
7555141cc406Sopenharmony_ci
7556141cc406Sopenharmony_ci  set_WD_Xres (desc1, s->resolution_x);
7557141cc406Sopenharmony_ci  set_WD_Yres (desc1, s->resolution_y);
7558141cc406Sopenharmony_ci
7559141cc406Sopenharmony_ci  set_WD_ULX (desc1, s->tl_x);
7560141cc406Sopenharmony_ci  /* low-end scanners ignore paper-size,
7561141cc406Sopenharmony_ci   * so we have to center the window ourselves */
7562141cc406Sopenharmony_ci  if(s->cropping_mode == CROP_ABSOLUTE){
7563141cc406Sopenharmony_ci    set_WD_ULX (desc1, s->tl_x + (s->max_x - s->page_width) / 2);
7564141cc406Sopenharmony_ci  }
7565141cc406Sopenharmony_ci
7566141cc406Sopenharmony_ci  set_WD_ULY (desc1, s->tl_y);
7567141cc406Sopenharmony_ci  set_WD_width (desc1, s->s_params.pixels_per_line * 1200/s->resolution_x);
7568141cc406Sopenharmony_ci
7569141cc406Sopenharmony_ci  length = s->s_params.lines * 1200/s->resolution_y;
7570141cc406Sopenharmony_ci
7571141cc406Sopenharmony_ci  /* stupid trick. 3091/2 require reading extra lines,
7572141cc406Sopenharmony_ci   * because they have a gap between R G and B */
7573141cc406Sopenharmony_ci  if(s->s_mode == MODE_COLOR && s->color_interlace == COLOR_INTERLACE_3091){
7574141cc406Sopenharmony_ci    length += (s->color_raster_offset+s->green_offset) * 1200/300 * 2;
7575141cc406Sopenharmony_ci    DBG(5,"set_window: Increasing length to %d\n",length);
7576141cc406Sopenharmony_ci  }
7577141cc406Sopenharmony_ci  set_WD_length (desc1, length);
7578141cc406Sopenharmony_ci
7579141cc406Sopenharmony_ci  set_WD_brightness (desc1, 0);
7580141cc406Sopenharmony_ci  if(s->brightness_steps){
7581141cc406Sopenharmony_ci    /*convert our common -127 to +127 range into HW's range
7582141cc406Sopenharmony_ci     *FIXME: this code assumes hardware range of 0-255 */
7583141cc406Sopenharmony_ci    set_WD_brightness (desc1, s->brightness+128);
7584141cc406Sopenharmony_ci  }
7585141cc406Sopenharmony_ci
7586141cc406Sopenharmony_ci  set_WD_threshold (desc1, s->threshold);
7587141cc406Sopenharmony_ci
7588141cc406Sopenharmony_ci  set_WD_contrast (desc1, 0);
7589141cc406Sopenharmony_ci  if(s->contrast_steps){
7590141cc406Sopenharmony_ci    /*convert our common -127 to +127 range into HW's range
7591141cc406Sopenharmony_ci     *FIXME: this code assumes hardware range of 0-255 */
7592141cc406Sopenharmony_ci    set_WD_contrast (desc1, s->contrast+128);
7593141cc406Sopenharmony_ci  }
7594141cc406Sopenharmony_ci
7595141cc406Sopenharmony_ci  set_WD_composition (desc1, s->s_mode);
7596141cc406Sopenharmony_ci
7597141cc406Sopenharmony_ci  set_WD_bitsperpixel (desc1, s->s_params.depth);
7598141cc406Sopenharmony_ci
7599141cc406Sopenharmony_ci  if(s->s_mode == MODE_HALFTONE){
7600141cc406Sopenharmony_ci    set_WD_ht_type(desc1, s->ht_type);
7601141cc406Sopenharmony_ci    set_WD_ht_pattern(desc1, s->ht_pattern);
7602141cc406Sopenharmony_ci  }
7603141cc406Sopenharmony_ci
7604141cc406Sopenharmony_ci  set_WD_rif (desc1, s->rif);
7605141cc406Sopenharmony_ci
7606141cc406Sopenharmony_ci  set_WD_compress_type(desc1, COMP_NONE);
7607141cc406Sopenharmony_ci  set_WD_compress_arg(desc1, 0);
7608141cc406Sopenharmony_ci
7609141cc406Sopenharmony_ci  /* some scanners support jpeg image compression, for color/gs only */
7610141cc406Sopenharmony_ci  if(s->s_params.format == SANE_FRAME_JPEG){
7611141cc406Sopenharmony_ci      set_WD_compress_type(desc1, COMP_JPEG);
7612141cc406Sopenharmony_ci      set_WD_compress_arg(desc1, s->compress_arg);
7613141cc406Sopenharmony_ci  }
7614141cc406Sopenharmony_ci
7615141cc406Sopenharmony_ci  /* the remainder of the block varies based on model and mode,
7616141cc406Sopenharmony_ci   * except for gamma and paper size, those are in the same place */
7617141cc406Sopenharmony_ci
7618141cc406Sopenharmony_ci  /* determine if we need to send gamma LUT.
7619141cc406Sopenharmony_ci   * send lut if scanner supports it and any of:
7620141cc406Sopenharmony_ci   * has no hardware brightness but user changed it
7621141cc406Sopenharmony_ci   * has no hardware contrast but user changed it
7622141cc406Sopenharmony_ci   * has no internal gamma table */
7623141cc406Sopenharmony_ci  if ( s->num_download_gamma && (
7624141cc406Sopenharmony_ci       (!s->brightness_steps && s->brightness != 0)
7625141cc406Sopenharmony_ci    || (!s->contrast_steps && s->contrast != 0 )
7626141cc406Sopenharmony_ci    || !s->num_internal_gamma
7627141cc406Sopenharmony_ci  ) ){
7628141cc406Sopenharmony_ci    s->window_gamma = 0x80;
7629141cc406Sopenharmony_ci  }
7630141cc406Sopenharmony_ci  /* otherwise, use the internal table */
7631141cc406Sopenharmony_ci  else{
7632141cc406Sopenharmony_ci    s->window_gamma = 0;
7633141cc406Sopenharmony_ci  }
7634141cc406Sopenharmony_ci
7635141cc406Sopenharmony_ci  /*vuid c0*/
7636141cc406Sopenharmony_ci  if(s->has_vuid_3091){
7637141cc406Sopenharmony_ci    set_WD_vendor_id_code (desc1, WD_VUID_3091);
7638141cc406Sopenharmony_ci    set_WD_gamma (desc1, s->window_gamma);
7639141cc406Sopenharmony_ci
7640141cc406Sopenharmony_ci    if (s->s_mode != MODE_COLOR){
7641141cc406Sopenharmony_ci      switch (s->dropout_color) {
7642141cc406Sopenharmony_ci        case COLOR_RED:
7643141cc406Sopenharmony_ci          set_WD_lamp_color (desc1, WD_LAMP_RED);
7644141cc406Sopenharmony_ci          break;
7645141cc406Sopenharmony_ci        case COLOR_GREEN:
7646141cc406Sopenharmony_ci          set_WD_lamp_color (desc1, WD_LAMP_GREEN);
7647141cc406Sopenharmony_ci          break;
7648141cc406Sopenharmony_ci        case COLOR_BLUE:
7649141cc406Sopenharmony_ci          set_WD_lamp_color (desc1, WD_LAMP_BLUE);
7650141cc406Sopenharmony_ci          break;
7651141cc406Sopenharmony_ci        default:
7652141cc406Sopenharmony_ci          set_WD_lamp_color (desc1, WD_LAMP_DEFAULT);
7653141cc406Sopenharmony_ci          break;
7654141cc406Sopenharmony_ci      }
7655141cc406Sopenharmony_ci    }
7656141cc406Sopenharmony_ci    /*set_WD_quality(desc1,s->quality);*/
7657141cc406Sopenharmony_ci  }
7658141cc406Sopenharmony_ci
7659141cc406Sopenharmony_ci  /*vuid c1*/
7660141cc406Sopenharmony_ci  else if(s->s_mode == MODE_COLOR && s->has_vuid_color){
7661141cc406Sopenharmony_ci    set_WD_vendor_id_code (desc1, WD_VUID_COLOR);
7662141cc406Sopenharmony_ci    set_WD_gamma (desc1, s->window_gamma);
7663141cc406Sopenharmony_ci
7664141cc406Sopenharmony_ci    if(s->color_interlace == COLOR_INTERLACE_RGB){
7665141cc406Sopenharmony_ci      set_WD_scanning_order (desc1, WD_SCAN_ORDER_DOT);
7666141cc406Sopenharmony_ci      set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_RGB);
7667141cc406Sopenharmony_ci    }
7668141cc406Sopenharmony_ci    else if(s->color_interlace == COLOR_INTERLACE_BGR){
7669141cc406Sopenharmony_ci      set_WD_scanning_order (desc1, WD_SCAN_ORDER_DOT);
7670141cc406Sopenharmony_ci      set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_BGR);
7671141cc406Sopenharmony_ci    }
7672141cc406Sopenharmony_ci    else if(s->color_interlace == COLOR_INTERLACE_RRGGBB){
7673141cc406Sopenharmony_ci      set_WD_scanning_order (desc1, WD_SCAN_ORDER_LINE);
7674141cc406Sopenharmony_ci      set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_RGB);
7675141cc406Sopenharmony_ci    }
7676141cc406Sopenharmony_ci    else{
7677141cc406Sopenharmony_ci      DBG (5,"set_window: unknown color interlacing\n");
7678141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
7679141cc406Sopenharmony_ci    }
7680141cc406Sopenharmony_ci
7681141cc406Sopenharmony_ci    /*scanner emphasis ranges from 0 to 7f and smoothing from 80 to ff*/
7682141cc406Sopenharmony_ci    /* but we expose them to user as a single linear range smooth->emphasis */
7683141cc406Sopenharmony_ci    /* flip the smooth part over, and tack it onto the upper end of emphasis */
7684141cc406Sopenharmony_ci    if(s->emphasis < 0)
7685141cc406Sopenharmony_ci      set_WD_c1_emphasis(desc1,127-s->emphasis);
7686141cc406Sopenharmony_ci    else
7687141cc406Sopenharmony_ci      set_WD_c1_emphasis(desc1,s->emphasis);
7688141cc406Sopenharmony_ci
7689141cc406Sopenharmony_ci    set_WD_c1_mirroring(desc1,s->mirroring);
7690141cc406Sopenharmony_ci
7691141cc406Sopenharmony_ci    set_WD_wl_follow(desc1,s->wl_follow);
7692141cc406Sopenharmony_ci  }
7693141cc406Sopenharmony_ci
7694141cc406Sopenharmony_ci  /*vuid 00*/
7695141cc406Sopenharmony_ci  else if(s->has_vuid_mono){
7696141cc406Sopenharmony_ci    set_WD_vendor_id_code (desc1, WD_VUID_MONO);
7697141cc406Sopenharmony_ci    set_WD_gamma (desc1, s->window_gamma);
7698141cc406Sopenharmony_ci
7699141cc406Sopenharmony_ci    set_WD_outline(desc1,s->outline);
7700141cc406Sopenharmony_ci
7701141cc406Sopenharmony_ci    /*scanner emphasis ranges from 0 to 7f and smoothing from 80 to ff*/
7702141cc406Sopenharmony_ci    /* but we expose them to user as a single linear range smooth->emphasis */
7703141cc406Sopenharmony_ci    /* flip the smooth part over, and tack it onto the upper end of emphasis */
7704141cc406Sopenharmony_ci    if(s->emphasis < 0)
7705141cc406Sopenharmony_ci      set_WD_emphasis(desc1,127-s->emphasis);
7706141cc406Sopenharmony_ci    else
7707141cc406Sopenharmony_ci      set_WD_emphasis(desc1,s->emphasis);
7708141cc406Sopenharmony_ci
7709141cc406Sopenharmony_ci    set_WD_separation(desc1,s->separation);
7710141cc406Sopenharmony_ci    set_WD_mirroring(desc1,s->mirroring);
7711141cc406Sopenharmony_ci
7712141cc406Sopenharmony_ci    if (get_ipc_mode(s) == WD_ipc_SDTC)
7713141cc406Sopenharmony_ci      set_WD_variance(desc1,s->variance);
7714141cc406Sopenharmony_ci
7715141cc406Sopenharmony_ci    else if (get_ipc_mode(s) == WD_ipc_DTC){
7716141cc406Sopenharmony_ci      set_WD_filtering(desc1,s->bp_filter);
7717141cc406Sopenharmony_ci      set_WD_smoothing(desc1,s->smoothing);
7718141cc406Sopenharmony_ci      set_WD_gamma_curve(desc1,s->gamma_curve);
7719141cc406Sopenharmony_ci      set_WD_threshold_curve(desc1,s->threshold_curve);
7720141cc406Sopenharmony_ci      set_WD_noise_removal(desc1,s->noise_removal);
7721141cc406Sopenharmony_ci      if(s->noise_removal){
7722141cc406Sopenharmony_ci        set_WD_matrix5x5(desc1,s->matrix_5);
7723141cc406Sopenharmony_ci        set_WD_matrix4x4(desc1,s->matrix_4);
7724141cc406Sopenharmony_ci        set_WD_matrix3x3(desc1,s->matrix_3);
7725141cc406Sopenharmony_ci        set_WD_matrix2x2(desc1,s->matrix_2);
7726141cc406Sopenharmony_ci      }
7727141cc406Sopenharmony_ci      set_WD_background(desc1,s->threshold_white);
7728141cc406Sopenharmony_ci    }
7729141cc406Sopenharmony_ci
7730141cc406Sopenharmony_ci    set_WD_wl_follow(desc1,s->wl_follow);
7731141cc406Sopenharmony_ci    set_WD_subwindow_list(desc1,0);
7732141cc406Sopenharmony_ci    set_WD_ipc_mode(desc1,get_ipc_mode(s));
7733141cc406Sopenharmony_ci  }
7734141cc406Sopenharmony_ci
7735141cc406Sopenharmony_ci  else{
7736141cc406Sopenharmony_ci    DBG (5,"set_window: no vuid to send?\n");
7737141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
7738141cc406Sopenharmony_ci  }
7739141cc406Sopenharmony_ci
7740141cc406Sopenharmony_ci  /* common to all vuids */
7741141cc406Sopenharmony_ci  if(s->source == SOURCE_FLATBED){
7742141cc406Sopenharmony_ci    set_WD_paper_selection(desc1,WD_paper_SEL_UNDEFINED);
7743141cc406Sopenharmony_ci  }
7744141cc406Sopenharmony_ci  else{
7745141cc406Sopenharmony_ci    set_WD_paper_selection (desc1, WD_paper_SEL_NON_STANDARD);
7746141cc406Sopenharmony_ci
7747141cc406Sopenharmony_ci    /* call helper function, scanner wants lies about paper width */
7748141cc406Sopenharmony_ci    set_WD_paper_width_X (desc1, get_page_width(s));
7749141cc406Sopenharmony_ci
7750141cc406Sopenharmony_ci    /* don't call helper function, scanner wants actual length?  */
7751141cc406Sopenharmony_ci    set_WD_paper_length_Y (desc1, s->page_height);
7752141cc406Sopenharmony_ci  }
7753141cc406Sopenharmony_ci
7754141cc406Sopenharmony_ci  /* when in duplex mode, copy first desc block into second */
7755141cc406Sopenharmony_ci  if (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX) {
7756141cc406Sopenharmony_ci      memcpy (desc2, desc1, SW_desc_len);
7757141cc406Sopenharmony_ci
7758141cc406Sopenharmony_ci      set_WD_wid (desc2, WD_wid_back);
7759141cc406Sopenharmony_ci
7760141cc406Sopenharmony_ci      /* FIXME: do we really need these on back of page? */
7761141cc406Sopenharmony_ci      set_WD_paper_selection (desc2, WD_paper_SEL_UNDEFINED);
7762141cc406Sopenharmony_ci      set_WD_paper_width_X (desc2, 0);
7763141cc406Sopenharmony_ci      set_WD_paper_length_Y (desc2, 0);
7764141cc406Sopenharmony_ci  }
7765141cc406Sopenharmony_ci  /* output shorter if not using duplex */
7766141cc406Sopenharmony_ci  else{
7767141cc406Sopenharmony_ci    outLen -= SW_desc_len;
7768141cc406Sopenharmony_ci  }
7769141cc406Sopenharmony_ci
7770141cc406Sopenharmony_ci  /*build the command*/
7771141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
7772141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SET_WINDOW_code);
7773141cc406Sopenharmony_ci  set_SW_xferlen(cmd, outLen);
7774141cc406Sopenharmony_ci
7775141cc406Sopenharmony_ci  ret = do_cmd (
7776141cc406Sopenharmony_ci    s, 1, 0,
7777141cc406Sopenharmony_ci    cmd, cmdLen,
7778141cc406Sopenharmony_ci    out, outLen,
7779141cc406Sopenharmony_ci    NULL, NULL
7780141cc406Sopenharmony_ci  );
7781141cc406Sopenharmony_ci
7782141cc406Sopenharmony_ci  DBG (10, "set_window: finish\n");
7783141cc406Sopenharmony_ci
7784141cc406Sopenharmony_ci  return ret;
7785141cc406Sopenharmony_ci}
7786141cc406Sopenharmony_ci
7787141cc406Sopenharmony_ci/* update s_params with actual data size scanner reports */
7788141cc406Sopenharmony_ci/* then copy as required to the u_params to send to user */
7789141cc406Sopenharmony_cistatic SANE_Status
7790141cc406Sopenharmony_ciget_pixelsize(struct fujitsu *s, int actual)
7791141cc406Sopenharmony_ci{
7792141cc406Sopenharmony_ci    SANE_Status ret;
7793141cc406Sopenharmony_ci
7794141cc406Sopenharmony_ci    unsigned char cmd[READ_len];
7795141cc406Sopenharmony_ci    size_t cmdLen = READ_len;
7796141cc406Sopenharmony_ci
7797141cc406Sopenharmony_ci    unsigned char in[R_PSIZE_len];
7798141cc406Sopenharmony_ci    size_t inLen = R_PSIZE_len;
7799141cc406Sopenharmony_ci
7800141cc406Sopenharmony_ci    DBG (10, "get_pixelsize: start %d\n",actual);
7801141cc406Sopenharmony_ci
7802141cc406Sopenharmony_ci    if (!s->has_pixelsize){
7803141cc406Sopenharmony_ci      DBG (10, "get_pixelsize: unsupported\n");
7804141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
7805141cc406Sopenharmony_ci    }
7806141cc406Sopenharmony_ci
7807141cc406Sopenharmony_ci    memset(cmd,0,cmdLen);
7808141cc406Sopenharmony_ci    set_SCSI_opcode(cmd, READ_code);
7809141cc406Sopenharmony_ci    set_R_datatype_code (cmd, R_datatype_pixelsize);
7810141cc406Sopenharmony_ci
7811141cc406Sopenharmony_ci    if(s->side == SIDE_BACK){
7812141cc406Sopenharmony_ci      set_R_window_id (cmd, WD_wid_back);
7813141cc406Sopenharmony_ci    }
7814141cc406Sopenharmony_ci    else{
7815141cc406Sopenharmony_ci      set_R_window_id (cmd, WD_wid_front);
7816141cc406Sopenharmony_ci    }
7817141cc406Sopenharmony_ci    set_R_xfer_length (cmd, inLen);
7818141cc406Sopenharmony_ci
7819141cc406Sopenharmony_ci    ret = do_cmd (
7820141cc406Sopenharmony_ci      s, 1, 0,
7821141cc406Sopenharmony_ci      cmd, cmdLen,
7822141cc406Sopenharmony_ci      NULL, 0,
7823141cc406Sopenharmony_ci      in, &inLen
7824141cc406Sopenharmony_ci    );
7825141cc406Sopenharmony_ci    if (ret == SANE_STATUS_GOOD){
7826141cc406Sopenharmony_ci
7827141cc406Sopenharmony_ci      /* when we are called post-scan, the scanner may give
7828141cc406Sopenharmony_ci       * more accurate data in other fields */
7829141cc406Sopenharmony_ci      if(actual && !s->has_short_pixelsize && get_PSIZE_paper_w(in)){
7830141cc406Sopenharmony_ci        DBG(5,"get_pixelsize: Actual width %d -> %d\n", s->s_params.pixels_per_line, get_PSIZE_paper_w(in));
7831141cc406Sopenharmony_ci        s->s_params.pixels_per_line = get_PSIZE_paper_w(in);
7832141cc406Sopenharmony_ci      }
7833141cc406Sopenharmony_ci      else{
7834141cc406Sopenharmony_ci        s->s_params.pixels_per_line = get_PSIZE_num_x(in);
7835141cc406Sopenharmony_ci      }
7836141cc406Sopenharmony_ci
7837141cc406Sopenharmony_ci      /* stupid trick. 3091/2 require reading extra lines,
7838141cc406Sopenharmony_ci       * because they have a gap between R G and B
7839141cc406Sopenharmony_ci       * we only want to report the shorter value to the frontend */
7840141cc406Sopenharmony_ci      if(s->s_mode == MODE_COLOR && s->color_interlace == COLOR_INTERLACE_3091){
7841141cc406Sopenharmony_ci        DBG(5,"get_pixelsize: Ignoring length %d\n",get_PSIZE_num_y(in));
7842141cc406Sopenharmony_ci      }
7843141cc406Sopenharmony_ci      /* when we are called post-scan, the scanner may give
7844141cc406Sopenharmony_ci       * more accurate data in other fields */
7845141cc406Sopenharmony_ci      else if(actual && !s->has_short_pixelsize && get_PSIZE_paper_l(in)){
7846141cc406Sopenharmony_ci        DBG(5,"get_pixelsize: Actual length %d -> %d\n", s->s_params.lines, get_PSIZE_paper_l(in));
7847141cc406Sopenharmony_ci        s->s_params.lines = get_PSIZE_paper_l(in);
7848141cc406Sopenharmony_ci      }
7849141cc406Sopenharmony_ci      else{
7850141cc406Sopenharmony_ci        s->s_params.lines = get_PSIZE_num_y(in);
7851141cc406Sopenharmony_ci      }
7852141cc406Sopenharmony_ci
7853141cc406Sopenharmony_ci      /* bytes per line differs by mode */
7854141cc406Sopenharmony_ci      if (s->s_mode == MODE_COLOR) {
7855141cc406Sopenharmony_ci        s->s_params.bytes_per_line = s->s_params.pixels_per_line * 3;
7856141cc406Sopenharmony_ci      }
7857141cc406Sopenharmony_ci      else if (s->s_mode == MODE_GRAYSCALE) {
7858141cc406Sopenharmony_ci        s->s_params.bytes_per_line = s->s_params.pixels_per_line;
7859141cc406Sopenharmony_ci      }
7860141cc406Sopenharmony_ci      else {
7861141cc406Sopenharmony_ci        s->s_params.bytes_per_line = s->s_params.pixels_per_line / 8;
7862141cc406Sopenharmony_ci      }
7863141cc406Sopenharmony_ci
7864141cc406Sopenharmony_ci      /* some scanners can request that the driver clean img */
7865141cc406Sopenharmony_ci      if(!s->has_short_pixelsize && get_PSIZE_req_driv_valid(in)){
7866141cc406Sopenharmony_ci        s->req_driv_crop = get_PSIZE_req_driv_crop(in);
7867141cc406Sopenharmony_ci        s->req_driv_lut = get_PSIZE_req_driv_lut(in);
7868141cc406Sopenharmony_ci        DBG(5,"get_pixelsize: scanner requests: crop=%d, lut=%d\n",
7869141cc406Sopenharmony_ci          s->req_driv_crop,s->req_driv_lut);
7870141cc406Sopenharmony_ci      }
7871141cc406Sopenharmony_ci
7872141cc406Sopenharmony_ci      DBG (15, "get_pixelsize: scan_x=%d, Bpl=%d, scan_y=%d\n",
7873141cc406Sopenharmony_ci        s->s_params.pixels_per_line, s->s_params.bytes_per_line, s->s_params.lines );
7874141cc406Sopenharmony_ci
7875141cc406Sopenharmony_ci      /* the user params are usually the same */
7876141cc406Sopenharmony_ci      s->u_params.pixels_per_line = s->s_params.pixels_per_line;
7877141cc406Sopenharmony_ci      s->u_params.lines = s->s_params.lines;
7878141cc406Sopenharmony_ci
7879141cc406Sopenharmony_ci      /* bytes per line differs by mode */
7880141cc406Sopenharmony_ci      if (s->u_mode == MODE_COLOR) {
7881141cc406Sopenharmony_ci        s->u_params.bytes_per_line = s->u_params.pixels_per_line * 3;
7882141cc406Sopenharmony_ci      }
7883141cc406Sopenharmony_ci      else if (s->u_mode == MODE_GRAYSCALE) {
7884141cc406Sopenharmony_ci        s->u_params.bytes_per_line = s->u_params.pixels_per_line;
7885141cc406Sopenharmony_ci      }
7886141cc406Sopenharmony_ci      else {
7887141cc406Sopenharmony_ci        s->u_params.bytes_per_line = s->u_params.pixels_per_line / 8;
7888141cc406Sopenharmony_ci      }
7889141cc406Sopenharmony_ci
7890141cc406Sopenharmony_ci    }
7891141cc406Sopenharmony_ci    else{
7892141cc406Sopenharmony_ci      DBG (10, "get_pixelsize: got bad status %d, ignoring\n", ret);
7893141cc406Sopenharmony_ci      s->has_pixelsize = 0;
7894141cc406Sopenharmony_ci      ret = SANE_STATUS_GOOD;
7895141cc406Sopenharmony_ci    }
7896141cc406Sopenharmony_ci
7897141cc406Sopenharmony_ci    DBG (10, "get_pixelsize: finish\n");
7898141cc406Sopenharmony_ci
7899141cc406Sopenharmony_ci    return ret;
7900141cc406Sopenharmony_ci}
7901141cc406Sopenharmony_ci
7902141cc406Sopenharmony_ci/*
7903141cc406Sopenharmony_ci * Issues the SCSI OBJECT POSITION command if an ADF or card scanner is in use.
7904141cc406Sopenharmony_ci */
7905141cc406Sopenharmony_cistatic SANE_Status
7906141cc406Sopenharmony_ciobject_position (struct fujitsu *s, int action)
7907141cc406Sopenharmony_ci{
7908141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7909141cc406Sopenharmony_ci
7910141cc406Sopenharmony_ci  unsigned char cmd[OBJECT_POSITION_len];
7911141cc406Sopenharmony_ci  size_t cmdLen = OBJECT_POSITION_len;
7912141cc406Sopenharmony_ci
7913141cc406Sopenharmony_ci  DBG (10, "object_position: start %d\n", action);
7914141cc406Sopenharmony_ci
7915141cc406Sopenharmony_ci  if (s->source == SOURCE_FLATBED && action < OP_Halt) {
7916141cc406Sopenharmony_ci    DBG (10, "object_position: flatbed no-op\n");
7917141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7918141cc406Sopenharmony_ci  }
7919141cc406Sopenharmony_ci
7920141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
7921141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, OBJECT_POSITION_code);
7922141cc406Sopenharmony_ci  set_OP_action (cmd, action);
7923141cc406Sopenharmony_ci
7924141cc406Sopenharmony_ci  ret = do_cmd (
7925141cc406Sopenharmony_ci    s, 1, 0,
7926141cc406Sopenharmony_ci    cmd, cmdLen,
7927141cc406Sopenharmony_ci    NULL, 0,
7928141cc406Sopenharmony_ci    NULL, NULL
7929141cc406Sopenharmony_ci  );
7930141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
7931141cc406Sopenharmony_ci    return ret;
7932141cc406Sopenharmony_ci
7933141cc406Sopenharmony_ci  if(!s->no_wait_after_op)
7934141cc406Sopenharmony_ci    wait_scanner (s);
7935141cc406Sopenharmony_ci
7936141cc406Sopenharmony_ci  DBG (10, "object_position: finish\n");
7937141cc406Sopenharmony_ci
7938141cc406Sopenharmony_ci  return ret;
7939141cc406Sopenharmony_ci}
7940141cc406Sopenharmony_ci
7941141cc406Sopenharmony_ci/*
7942141cc406Sopenharmony_ci * Issues SCAN command.
7943141cc406Sopenharmony_ci *
7944141cc406Sopenharmony_ci * (This doesn't actually read anything, it just tells the scanner
7945141cc406Sopenharmony_ci * to start scanning.)
7946141cc406Sopenharmony_ci */
7947141cc406Sopenharmony_cistatic SANE_Status
7948141cc406Sopenharmony_cistart_scan (struct fujitsu *s)
7949141cc406Sopenharmony_ci{
7950141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
7951141cc406Sopenharmony_ci
7952141cc406Sopenharmony_ci  unsigned char cmd[SCAN_len];
7953141cc406Sopenharmony_ci  size_t cmdLen = SCAN_len;
7954141cc406Sopenharmony_ci
7955141cc406Sopenharmony_ci  unsigned char out[] = {WD_wid_front, WD_wid_back};
7956141cc406Sopenharmony_ci  size_t outLen = 2;
7957141cc406Sopenharmony_ci
7958141cc406Sopenharmony_ci  DBG (10, "start_scan: start\n");
7959141cc406Sopenharmony_ci
7960141cc406Sopenharmony_ci  if (s->source != SOURCE_ADF_DUPLEX && s->source != SOURCE_CARD_DUPLEX) {
7961141cc406Sopenharmony_ci    outLen--;
7962141cc406Sopenharmony_ci    if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
7963141cc406Sopenharmony_ci      out[0] = WD_wid_back;
7964141cc406Sopenharmony_ci    }
7965141cc406Sopenharmony_ci  }
7966141cc406Sopenharmony_ci
7967141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
7968141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, SCAN_code);
7969141cc406Sopenharmony_ci  set_SC_xfer_length (cmd, outLen);
7970141cc406Sopenharmony_ci
7971141cc406Sopenharmony_ci  ret = do_cmd (
7972141cc406Sopenharmony_ci    s, 1, 0,
7973141cc406Sopenharmony_ci    cmd, cmdLen,
7974141cc406Sopenharmony_ci    out, outLen,
7975141cc406Sopenharmony_ci    NULL, NULL
7976141cc406Sopenharmony_ci  );
7977141cc406Sopenharmony_ci
7978141cc406Sopenharmony_ci  DBG (10, "start_scan: finish\n");
7979141cc406Sopenharmony_ci
7980141cc406Sopenharmony_ci  return ret;
7981141cc406Sopenharmony_ci}
7982141cc406Sopenharmony_ci
7983141cc406Sopenharmony_ci/* checks started and cancelled flags in scanner struct,
7984141cc406Sopenharmony_ci * sends cancel command to scanner if required. don't call
7985141cc406Sopenharmony_ci * this function asynchronously, wait for pending operation */
7986141cc406Sopenharmony_cistatic SANE_Status
7987141cc406Sopenharmony_cicheck_for_cancel(struct fujitsu *s)
7988141cc406Sopenharmony_ci{
7989141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
7990141cc406Sopenharmony_ci
7991141cc406Sopenharmony_ci  DBG (10, "check_for_cancel: start %d %d\n",s->started,s->cancelled);
7992141cc406Sopenharmony_ci
7993141cc406Sopenharmony_ci  if(s->started && s->cancelled){
7994141cc406Sopenharmony_ci
7995141cc406Sopenharmony_ci    /* halt scan */
7996141cc406Sopenharmony_ci    if(s->halt_on_cancel){
7997141cc406Sopenharmony_ci      DBG (15, "check_for_cancel: halting\n");
7998141cc406Sopenharmony_ci      ret = object_position (s, OP_Halt);
7999141cc406Sopenharmony_ci    }
8000141cc406Sopenharmony_ci    /* cancel scan */
8001141cc406Sopenharmony_ci    else{
8002141cc406Sopenharmony_ci      DBG (15, "check_for_cancel: cancelling\n");
8003141cc406Sopenharmony_ci      ret = scanner_control(s, SC_function_cancel);
8004141cc406Sopenharmony_ci    }
8005141cc406Sopenharmony_ci
8006141cc406Sopenharmony_ci    if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_CANCELLED) {
8007141cc406Sopenharmony_ci      ret = SANE_STATUS_CANCELLED;
8008141cc406Sopenharmony_ci    }
8009141cc406Sopenharmony_ci    else{
8010141cc406Sopenharmony_ci      DBG (5, "check_for_cancel: ERROR: cannot cancel\n");
8011141cc406Sopenharmony_ci    }
8012141cc406Sopenharmony_ci
8013141cc406Sopenharmony_ci    s->started = 0;
8014141cc406Sopenharmony_ci    s->cancelled = 0;
8015141cc406Sopenharmony_ci  }
8016141cc406Sopenharmony_ci  else if(s->cancelled){
8017141cc406Sopenharmony_ci    DBG (15, "check_for_cancel: already cancelled\n");
8018141cc406Sopenharmony_ci    ret = SANE_STATUS_CANCELLED;
8019141cc406Sopenharmony_ci    s->cancelled = 0;
8020141cc406Sopenharmony_ci  }
8021141cc406Sopenharmony_ci
8022141cc406Sopenharmony_ci  DBG (10, "check_for_cancel: finish %d\n",ret);
8023141cc406Sopenharmony_ci  return ret;
8024141cc406Sopenharmony_ci}
8025141cc406Sopenharmony_ci
8026141cc406Sopenharmony_ci/*
8027141cc406Sopenharmony_ci * Called by SANE to read data.
8028141cc406Sopenharmony_ci *
8029141cc406Sopenharmony_ci * From the SANE spec:
8030141cc406Sopenharmony_ci * This function is used to read image data from the device
8031141cc406Sopenharmony_ci * represented by handle h.  Argument buf is a pointer to a memory
8032141cc406Sopenharmony_ci * area that is at least maxlen bytes long.  The number of bytes
8033141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when
8034141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is
8035141cc406Sopenharmony_ci * returned).
8036141cc406Sopenharmony_ci *
8037141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be
8038141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes.
8039141cc406Sopenharmony_ci */
8040141cc406Sopenharmony_ciSANE_Status
8041141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len)
8042141cc406Sopenharmony_ci{
8043141cc406Sopenharmony_ci  struct fujitsu *s = (struct fujitsu *) handle;
8044141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8045141cc406Sopenharmony_ci
8046141cc406Sopenharmony_ci  DBG (10, "sane_read: start\n");
8047141cc406Sopenharmony_ci
8048141cc406Sopenharmony_ci  *len=0;
8049141cc406Sopenharmony_ci
8050141cc406Sopenharmony_ci  /* maybe cancelled? */
8051141cc406Sopenharmony_ci  if(!s->started){
8052141cc406Sopenharmony_ci    DBG (5, "sane_read: not started, call sane_start\n");
8053141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
8054141cc406Sopenharmony_ci  }
8055141cc406Sopenharmony_ci
8056141cc406Sopenharmony_ci  /* sane_start required between sides */
8057141cc406Sopenharmony_ci  if(s->eof_rx[s->side] && s->bytes_tx[s->side] == s->bytes_rx[s->side]){
8058141cc406Sopenharmony_ci    DBG (15, "sane_read: returning eof\n");
8059141cc406Sopenharmony_ci    s->eof_tx[s->side] = 1;
8060141cc406Sopenharmony_ci
8061141cc406Sopenharmony_ci    /* swap sides if user asked for low-mem mode, we are duplexing,
8062141cc406Sopenharmony_ci     * and there is data waiting on the other side */
8063141cc406Sopenharmony_ci    if(s->low_mem
8064141cc406Sopenharmony_ci      && (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
8065141cc406Sopenharmony_ci      && (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
8066141cc406Sopenharmony_ci        || (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
8067141cc406Sopenharmony_ci      )
8068141cc406Sopenharmony_ci    ){
8069141cc406Sopenharmony_ci      s->side = !s->side;
8070141cc406Sopenharmony_ci    }
8071141cc406Sopenharmony_ci
8072141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
8073141cc406Sopenharmony_ci  }
8074141cc406Sopenharmony_ci
8075141cc406Sopenharmony_ci  /* protect this block from sane_cancel */
8076141cc406Sopenharmony_ci  s->reading = 1;
8077141cc406Sopenharmony_ci
8078141cc406Sopenharmony_ci  /* ----------------------------------------------
8079141cc406Sopenharmony_ci   * try to read some data from scanner into buffer
8080141cc406Sopenharmony_ci   * these functions are expected not to overrun */
8081141cc406Sopenharmony_ci
8082141cc406Sopenharmony_ci  /* 3091/2 are on crack, get their own duplex reader function */
8083141cc406Sopenharmony_ci  if(s->source == SOURCE_ADF_DUPLEX
8084141cc406Sopenharmony_ci    && s->duplex_interlace == DUPLEX_INTERLACE_3091
8085141cc406Sopenharmony_ci  ){
8086141cc406Sopenharmony_ci    ret = read_from_3091duplex(s);
8087141cc406Sopenharmony_ci    if(ret){
8088141cc406Sopenharmony_ci      DBG(5,"sane_read: 3091 returning %d\n",ret);
8089141cc406Sopenharmony_ci      return ret;
8090141cc406Sopenharmony_ci    }
8091141cc406Sopenharmony_ci  } /* end 3091 */
8092141cc406Sopenharmony_ci
8093141cc406Sopenharmony_ci  /* alternating jpeg duplex interlacing */
8094141cc406Sopenharmony_ci  else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
8095141cc406Sopenharmony_ci    && s->s_params.format == SANE_FRAME_JPEG
8096141cc406Sopenharmony_ci    && s->jpeg_interlace == JPEG_INTERLACE_ALT
8097141cc406Sopenharmony_ci  ){
8098141cc406Sopenharmony_ci    ret = read_from_JPEGduplex(s);
8099141cc406Sopenharmony_ci    if(ret){
8100141cc406Sopenharmony_ci      DBG(5,"sane_read: jpeg duplex returning %d\n",ret);
8101141cc406Sopenharmony_ci      return ret;
8102141cc406Sopenharmony_ci    }
8103141cc406Sopenharmony_ci  } /* end alt jpeg */
8104141cc406Sopenharmony_ci
8105141cc406Sopenharmony_ci  /* alternating pnm duplex interlacing */
8106141cc406Sopenharmony_ci  else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
8107141cc406Sopenharmony_ci    && s->s_params.format != SANE_FRAME_JPEG
8108141cc406Sopenharmony_ci    && s->duplex_interlace == DUPLEX_INTERLACE_ALT
8109141cc406Sopenharmony_ci  ){
8110141cc406Sopenharmony_ci
8111141cc406Sopenharmony_ci    /* buffer front side */
8112141cc406Sopenharmony_ci    ret = read_from_scanner(s, SIDE_FRONT);
8113141cc406Sopenharmony_ci    if(ret){
8114141cc406Sopenharmony_ci      DBG(5,"sane_read: front returning %d\n",ret);
8115141cc406Sopenharmony_ci      return ret;
8116141cc406Sopenharmony_ci    }
8117141cc406Sopenharmony_ci
8118141cc406Sopenharmony_ci    /* buffer back side, but don't get too far ahead of the front! */
8119141cc406Sopenharmony_ci    if(s->bytes_rx[SIDE_BACK] < s->bytes_rx[SIDE_FRONT] + s->buffer_size){
8120141cc406Sopenharmony_ci      ret = read_from_scanner(s, SIDE_BACK);
8121141cc406Sopenharmony_ci      if(ret){
8122141cc406Sopenharmony_ci        DBG(5,"sane_read: back returning %d\n",ret);
8123141cc406Sopenharmony_ci        return ret;
8124141cc406Sopenharmony_ci      }
8125141cc406Sopenharmony_ci    }
8126141cc406Sopenharmony_ci  } /* end alt pnm */
8127141cc406Sopenharmony_ci
8128141cc406Sopenharmony_ci  /* simplex or non-alternating duplex */
8129141cc406Sopenharmony_ci  else{
8130141cc406Sopenharmony_ci    ret = read_from_scanner(s, s->side);
8131141cc406Sopenharmony_ci    if(ret){
8132141cc406Sopenharmony_ci      DBG(5,"sane_read: side %d returning %d\n",s->side,ret);
8133141cc406Sopenharmony_ci      return ret;
8134141cc406Sopenharmony_ci    }
8135141cc406Sopenharmony_ci  } /*end simplex*/
8136141cc406Sopenharmony_ci
8137141cc406Sopenharmony_ci  /* uncommon case, downsample and copy a block from buffer to frontend */
8138141cc406Sopenharmony_ci  if(must_downsample(s)){
8139141cc406Sopenharmony_ci    ret = downsample_from_buffer(s,buf,max_len,len,s->side);
8140141cc406Sopenharmony_ci  }
8141141cc406Sopenharmony_ci
8142141cc406Sopenharmony_ci  /* common case, memcpy a block from buffer to frontend */
8143141cc406Sopenharmony_ci  else{
8144141cc406Sopenharmony_ci    ret = read_from_buffer(s,buf,max_len,len,s->side);
8145141cc406Sopenharmony_ci  }
8146141cc406Sopenharmony_ci
8147141cc406Sopenharmony_ci  /*finished sending small buffer, reset it*/
8148141cc406Sopenharmony_ci  if(s->buff_tx[s->side] == s->buff_rx[s->side]
8149141cc406Sopenharmony_ci    && s->buff_tot[s->side] < s->bytes_tot[s->side]
8150141cc406Sopenharmony_ci  ){
8151141cc406Sopenharmony_ci    DBG (15, "sane_read: reset buffers\n");
8152141cc406Sopenharmony_ci    s->buff_rx[s->side] = 0;
8153141cc406Sopenharmony_ci    s->buff_tx[s->side] = 0;
8154141cc406Sopenharmony_ci  }
8155141cc406Sopenharmony_ci
8156141cc406Sopenharmony_ci  /* check if user cancelled during this read */
8157141cc406Sopenharmony_ci  ret = check_for_cancel(s);
8158141cc406Sopenharmony_ci
8159141cc406Sopenharmony_ci  /* swap sides if user asked for low-mem mode, we are duplexing,
8160141cc406Sopenharmony_ci   * and there is data waiting on the other side */
8161141cc406Sopenharmony_ci  if(s->low_mem
8162141cc406Sopenharmony_ci    && (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
8163141cc406Sopenharmony_ci    && (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
8164141cc406Sopenharmony_ci      || (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
8165141cc406Sopenharmony_ci    )
8166141cc406Sopenharmony_ci  ){
8167141cc406Sopenharmony_ci    s->side = !s->side;
8168141cc406Sopenharmony_ci  }
8169141cc406Sopenharmony_ci
8170141cc406Sopenharmony_ci  /* unprotect this block from sane_cancel */
8171141cc406Sopenharmony_ci  s->reading = 0;
8172141cc406Sopenharmony_ci
8173141cc406Sopenharmony_ci  DBG (10, "sane_read: finish %d\n", ret);
8174141cc406Sopenharmony_ci  return ret;
8175141cc406Sopenharmony_ci}
8176141cc406Sopenharmony_ci
8177141cc406Sopenharmony_ci/* bare jpeg images don't contain resolution, but JFIF APP0 does, so we add */
8178141cc406Sopenharmony_cistatic SANE_Status
8179141cc406Sopenharmony_ciinject_jfif_header(struct fujitsu *s, int side)
8180141cc406Sopenharmony_ci{
8181141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8182141cc406Sopenharmony_ci
8183141cc406Sopenharmony_ci  unsigned char out[] = {
8184141cc406Sopenharmony_ci    0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46,
8185141cc406Sopenharmony_ci    0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48,
8186141cc406Sopenharmony_ci    0x00, 0x00
8187141cc406Sopenharmony_ci  };
8188141cc406Sopenharmony_ci  size_t outLen=JFIF_APP0_LENGTH;
8189141cc406Sopenharmony_ci
8190141cc406Sopenharmony_ci  DBG (10, "inject_jfif_header: start %d\n", side);
8191141cc406Sopenharmony_ci
8192141cc406Sopenharmony_ci  putnbyte(out + 12, s->resolution_x, 2);
8193141cc406Sopenharmony_ci  putnbyte(out + 14, s->resolution_y, 2);
8194141cc406Sopenharmony_ci
8195141cc406Sopenharmony_ci  memcpy(s->buffers[side]+s->buff_rx[side], out, outLen);
8196141cc406Sopenharmony_ci  s->buff_rx[side] += outLen;
8197141cc406Sopenharmony_ci  s->bytes_rx[side] += outLen;
8198141cc406Sopenharmony_ci
8199141cc406Sopenharmony_ci  DBG (10, "inject_jfif_header: finish %d\n", ret);
8200141cc406Sopenharmony_ci
8201141cc406Sopenharmony_ci  return ret;
8202141cc406Sopenharmony_ci}
8203141cc406Sopenharmony_ci
8204141cc406Sopenharmony_cistatic SANE_Status
8205141cc406Sopenharmony_ciread_from_JPEGduplex(struct fujitsu *s)
8206141cc406Sopenharmony_ci{
8207141cc406Sopenharmony_ci    SANE_Status ret=SANE_STATUS_GOOD;
8208141cc406Sopenharmony_ci
8209141cc406Sopenharmony_ci    unsigned char cmd[READ_len];
8210141cc406Sopenharmony_ci    size_t cmdLen = READ_len;
8211141cc406Sopenharmony_ci
8212141cc406Sopenharmony_ci    unsigned char * in;
8213141cc406Sopenharmony_ci    size_t inLen = 0;
8214141cc406Sopenharmony_ci
8215141cc406Sopenharmony_ci    int bytes = s->buffer_size;
8216141cc406Sopenharmony_ci    int i = 0;
8217141cc406Sopenharmony_ci
8218141cc406Sopenharmony_ci    DBG (10, "read_from_JPEGduplex: start\n");
8219141cc406Sopenharmony_ci
8220141cc406Sopenharmony_ci    if(s->eof_rx[SIDE_FRONT] && s->eof_rx[SIDE_BACK]){
8221141cc406Sopenharmony_ci      DBG (10, "read_from_JPEGduplex: already have eofs, done\n");
8222141cc406Sopenharmony_ci      return ret;
8223141cc406Sopenharmony_ci    }
8224141cc406Sopenharmony_ci
8225141cc406Sopenharmony_ci    /* we don't know if the following read will give us front or back data
8226141cc406Sopenharmony_ci     * so we only get enough to fill whichever is smaller (and not yet done) */
8227141cc406Sopenharmony_ci    if(!s->eof_rx[SIDE_FRONT]){
8228141cc406Sopenharmony_ci      int avail = s->buff_tot[SIDE_FRONT] - s->buff_rx[SIDE_FRONT];
8229141cc406Sopenharmony_ci      if(bytes > avail){
8230141cc406Sopenharmony_ci        bytes = avail;
8231141cc406Sopenharmony_ci      }
8232141cc406Sopenharmony_ci    }
8233141cc406Sopenharmony_ci    if(!s->eof_rx[SIDE_BACK]){
8234141cc406Sopenharmony_ci      int avail = s->buff_tot[SIDE_BACK] - s->buff_rx[SIDE_BACK];
8235141cc406Sopenharmony_ci      if(bytes > avail){
8236141cc406Sopenharmony_ci        bytes = avail;
8237141cc406Sopenharmony_ci      }
8238141cc406Sopenharmony_ci    }
8239141cc406Sopenharmony_ci
8240141cc406Sopenharmony_ci    /* leave space for JFIF header in the small front side buffer,
8241141cc406Sopenharmony_ci     * if we are at the beginning of the image */
8242141cc406Sopenharmony_ci    if(s->bytes_rx[SIDE_FRONT] < 3){
8243141cc406Sopenharmony_ci      bytes -= JFIF_APP0_LENGTH;
8244141cc406Sopenharmony_ci    }
8245141cc406Sopenharmony_ci
8246141cc406Sopenharmony_ci    DBG(15, "read_from_JPEGduplex: fto:%d frx:%d bto:%d brx:%d pa:%d\n",
8247141cc406Sopenharmony_ci      s->bytes_tot[SIDE_FRONT], s->bytes_rx[SIDE_FRONT],
8248141cc406Sopenharmony_ci      s->bytes_tot[SIDE_BACK], s->bytes_rx[SIDE_BACK],
8249141cc406Sopenharmony_ci      bytes);
8250141cc406Sopenharmony_ci
8251141cc406Sopenharmony_ci    /* this will happen if buffer is not drained yet */
8252141cc406Sopenharmony_ci    if(bytes < 1){
8253141cc406Sopenharmony_ci      DBG(5, "read_from_JPEGduplex: Warning: no bytes this pass\n");
8254141cc406Sopenharmony_ci      return ret;
8255141cc406Sopenharmony_ci    }
8256141cc406Sopenharmony_ci
8257141cc406Sopenharmony_ci    /* fi-6770A gets mad if you 'read' too soon on usb, see if it is ready */
8258141cc406Sopenharmony_ci    if(!s->bytes_rx[SIDE_FRONT] && s->connection == CONNECTION_USB){
8259141cc406Sopenharmony_ci      DBG (15, "read: start of usb page, checking RIC\n");
8260141cc406Sopenharmony_ci      ret = scanner_control_ric(s,bytes,SIDE_FRONT);
8261141cc406Sopenharmony_ci      if(ret){
8262141cc406Sopenharmony_ci        DBG(5,"read: ric returning %d\n",ret);
8263141cc406Sopenharmony_ci        return ret;
8264141cc406Sopenharmony_ci      }
8265141cc406Sopenharmony_ci    }
8266141cc406Sopenharmony_ci
8267141cc406Sopenharmony_ci    inLen = bytes;
8268141cc406Sopenharmony_ci    in = malloc(inLen);
8269141cc406Sopenharmony_ci    if(!in){
8270141cc406Sopenharmony_ci        DBG(5, "read_from_JPEGduplex: not enough mem for buffer: %d\n",(int)inLen);
8271141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
8272141cc406Sopenharmony_ci    }
8273141cc406Sopenharmony_ci
8274141cc406Sopenharmony_ci    memset(cmd,0,cmdLen);
8275141cc406Sopenharmony_ci    set_SCSI_opcode(cmd, READ_code);
8276141cc406Sopenharmony_ci    set_R_datatype_code (cmd, R_datatype_imagedata);
8277141cc406Sopenharmony_ci    /* interlaced jpeg duplex always reads from front */
8278141cc406Sopenharmony_ci    set_R_window_id (cmd, WD_wid_front);
8279141cc406Sopenharmony_ci    set_R_xfer_length (cmd, inLen);
8280141cc406Sopenharmony_ci
8281141cc406Sopenharmony_ci    ret = do_cmd (
8282141cc406Sopenharmony_ci      s, 1, 0,
8283141cc406Sopenharmony_ci      cmd, cmdLen,
8284141cc406Sopenharmony_ci      NULL, 0,
8285141cc406Sopenharmony_ci      in, &inLen
8286141cc406Sopenharmony_ci    );
8287141cc406Sopenharmony_ci
8288141cc406Sopenharmony_ci    if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) {
8289141cc406Sopenharmony_ci        DBG(15, "read_from_JPEGduplex: got GOOD/EOF, returning GOOD\n");
8290141cc406Sopenharmony_ci    }
8291141cc406Sopenharmony_ci    else if (ret == SANE_STATUS_DEVICE_BUSY) {
8292141cc406Sopenharmony_ci        DBG(5, "read_from_JPEGduplex: got BUSY, returning GOOD\n");
8293141cc406Sopenharmony_ci        inLen = 0;
8294141cc406Sopenharmony_ci        ret = SANE_STATUS_GOOD;
8295141cc406Sopenharmony_ci    }
8296141cc406Sopenharmony_ci    else {
8297141cc406Sopenharmony_ci        DBG(5, "read_from_JPEGduplex: error reading data status = %d\n", ret);
8298141cc406Sopenharmony_ci        inLen = 0;
8299141cc406Sopenharmony_ci    }
8300141cc406Sopenharmony_ci
8301141cc406Sopenharmony_ci    for(i=0;i<(int)inLen;i++){
8302141cc406Sopenharmony_ci
8303141cc406Sopenharmony_ci        /* about to change stage */
8304141cc406Sopenharmony_ci        if(in[i] == 0xff && s->jpeg_ff_offset != 0){
8305141cc406Sopenharmony_ci            s->jpeg_ff_offset=0;
8306141cc406Sopenharmony_ci            continue;
8307141cc406Sopenharmony_ci        }
8308141cc406Sopenharmony_ci
8309141cc406Sopenharmony_ci        /* last byte was an ff, this byte will change stage */
8310141cc406Sopenharmony_ci        if(s->jpeg_ff_offset == 0){
8311141cc406Sopenharmony_ci
8312141cc406Sopenharmony_ci            /* first marker after SOI is not APP0, add one */
8313141cc406Sopenharmony_ci            if(s->jpeg_stage == JPEG_STAGE_SOI && in[i] != 0xe0){
8314141cc406Sopenharmony_ci                inject_jfif_header(s,SIDE_FRONT);
8315141cc406Sopenharmony_ci                inject_jfif_header(s,SIDE_BACK);
8316141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_HEAD;
8317141cc406Sopenharmony_ci            }
8318141cc406Sopenharmony_ci
8319141cc406Sopenharmony_ci            /* SOI header, in both sides */
8320141cc406Sopenharmony_ci            if(in[i] == 0xd8){
8321141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_SOI;
8322141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: stage SOI\n");
8323141cc406Sopenharmony_ci            }
8324141cc406Sopenharmony_ci
8325141cc406Sopenharmony_ci            /* headers (HuffTab/QTab/DRI), in both sides */
8326141cc406Sopenharmony_ci            else if(in[i] == 0xc4 || in[i] == 0xdb || in[i] == 0xdd){
8327141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_HEAD;
8328141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: stage head\n");
8329141cc406Sopenharmony_ci            }
8330141cc406Sopenharmony_ci
8331141cc406Sopenharmony_ci            /* start of frame, in both sides, update x first */
8332141cc406Sopenharmony_ci            else if(in[i]==0xc0){
8333141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_SOF;
8334141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: stage sof\n");
8335141cc406Sopenharmony_ci            }
8336141cc406Sopenharmony_ci
8337141cc406Sopenharmony_ci            /* start of scan, first few bytes of marker in both sides
8338141cc406Sopenharmony_ci             * but rest in front */
8339141cc406Sopenharmony_ci            else if(in[i]==0xda){
8340141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_SOS;
8341141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: stage sos\n");
8342141cc406Sopenharmony_ci            }
8343141cc406Sopenharmony_ci
8344141cc406Sopenharmony_ci            /* found image block. images are not interlaced */
8345141cc406Sopenharmony_ci            /* copy to front, don't change RST */
8346141cc406Sopenharmony_ci            else if(in[i] >= 0xd0 && in[i] <= 0xd7
8347141cc406Sopenharmony_ci              && s->jpeg_interlace == JPEG_INTERLACE_NONE){
8348141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_FRONT;
8349141cc406Sopenharmony_ci                DBG(35, "read_from_JPEGduplex: stage front (all)\n");
8350141cc406Sopenharmony_ci            }
8351141cc406Sopenharmony_ci
8352141cc406Sopenharmony_ci            /* found even numbered image block. */
8353141cc406Sopenharmony_ci            /* images are interlaced, so switch to back. */
8354141cc406Sopenharmony_ci            /* also change from even RST to proper one */
8355141cc406Sopenharmony_ci            else if(in[i] == 0xd0 || in[i] == 0xd2
8356141cc406Sopenharmony_ci              || in[i] == 0xd4 || in[i] == 0xd6){
8357141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_BACK;
8358141cc406Sopenharmony_ci                DBG(35, "read_from_JPEGduplex: stage back\n");
8359141cc406Sopenharmony_ci
8360141cc406Sopenharmony_ci                /* skip first RST for back side*/
8361141cc406Sopenharmony_ci                if(!s->jpeg_back_rst){
8362141cc406Sopenharmony_ci                  DBG(15, "read_from_JPEGduplex: stage back jump\n");
8363141cc406Sopenharmony_ci                  s->jpeg_ff_offset++;
8364141cc406Sopenharmony_ci                  s->jpeg_back_rst++;
8365141cc406Sopenharmony_ci                  continue;
8366141cc406Sopenharmony_ci                }
8367141cc406Sopenharmony_ci
8368141cc406Sopenharmony_ci                in[i] = 0xd0 + (s->jpeg_back_rst-1) % 8;
8369141cc406Sopenharmony_ci                s->jpeg_back_rst++;
8370141cc406Sopenharmony_ci            }
8371141cc406Sopenharmony_ci
8372141cc406Sopenharmony_ci            /* finished back image block, switch to front */
8373141cc406Sopenharmony_ci            /* also change from odd RST to proper one */
8374141cc406Sopenharmony_ci            else if(in[i] == 0xd1 || in[i] == 0xd3
8375141cc406Sopenharmony_ci              || in[i] == 0xd5 || in[i] == 0xd7){
8376141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_FRONT;
8377141cc406Sopenharmony_ci                DBG(35, "read_from_JPEGduplex: stage front\n");
8378141cc406Sopenharmony_ci                in[i] = 0xd0 + (s->jpeg_front_rst % 8);
8379141cc406Sopenharmony_ci                s->jpeg_front_rst++;
8380141cc406Sopenharmony_ci            }
8381141cc406Sopenharmony_ci
8382141cc406Sopenharmony_ci            /* finished image, update totals */
8383141cc406Sopenharmony_ci            else if(in[i]==0xd9){
8384141cc406Sopenharmony_ci                s->jpeg_stage = JPEG_STAGE_EOI;
8385141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: stage eoi %d %d\n",(int)inLen,i);
8386141cc406Sopenharmony_ci            }
8387141cc406Sopenharmony_ci
8388141cc406Sopenharmony_ci            /* unknown, warn */
8389141cc406Sopenharmony_ci            else if(in[i] != 0x00){
8390141cc406Sopenharmony_ci                DBG(15, "read_from_JPEGduplex: unknown %02x\n", in[i]);
8391141cc406Sopenharmony_ci            }
8392141cc406Sopenharmony_ci        }
8393141cc406Sopenharmony_ci        s->jpeg_ff_offset++;
8394141cc406Sopenharmony_ci
8395141cc406Sopenharmony_ci        /* first x byte in start of frame, buffer it */
8396141cc406Sopenharmony_ci        if(s->jpeg_stage == JPEG_STAGE_SOF && s->jpeg_ff_offset == 7){
8397141cc406Sopenharmony_ci          s->jpeg_x_byte = in[i];
8398141cc406Sopenharmony_ci	  continue;
8399141cc406Sopenharmony_ci        }
8400141cc406Sopenharmony_ci
8401141cc406Sopenharmony_ci        /* second x byte in start of frame */
8402141cc406Sopenharmony_ci        if(s->jpeg_stage == JPEG_STAGE_SOF && s->jpeg_ff_offset == 8){
8403141cc406Sopenharmony_ci
8404141cc406Sopenharmony_ci	  int width = (s->jpeg_x_byte << 8) | in[i];
8405141cc406Sopenharmony_ci
8406141cc406Sopenharmony_ci	  /* if image width equals what we asked for, then
8407141cc406Sopenharmony_ci	   * the image is not interlaced, clean up the mess */
8408141cc406Sopenharmony_ci	  if(width == s->s_params.pixels_per_line){
8409141cc406Sopenharmony_ci
8410141cc406Sopenharmony_ci            DBG(15, "read_from_JPEGduplex: right width, req:%d got:%d\n",
8411141cc406Sopenharmony_ci	      s->s_params.pixels_per_line,width);
8412141cc406Sopenharmony_ci
8413141cc406Sopenharmony_ci	    /* stop copying to the back */
8414141cc406Sopenharmony_ci	    s->jpeg_interlace = JPEG_INTERLACE_NONE;
8415141cc406Sopenharmony_ci
8416141cc406Sopenharmony_ci	    /* clear what is already in the back */
8417141cc406Sopenharmony_ci            s->bytes_rx[SIDE_BACK]=0;
8418141cc406Sopenharmony_ci            s->lines_rx[SIDE_BACK]=0;
8419141cc406Sopenharmony_ci            s->buff_rx[SIDE_BACK]=0;
8420141cc406Sopenharmony_ci
8421141cc406Sopenharmony_ci	    /* and put the high-order width byte into front unchanged */
8422141cc406Sopenharmony_ci            s->buffers[SIDE_FRONT][s->buff_rx[SIDE_FRONT]++] = s->jpeg_x_byte;
8423141cc406Sopenharmony_ci            s->bytes_rx[SIDE_FRONT]++;
8424141cc406Sopenharmony_ci	  }
8425141cc406Sopenharmony_ci
8426141cc406Sopenharmony_ci	  /* image is interlaced after all, continue */
8427141cc406Sopenharmony_ci	  else{
8428141cc406Sopenharmony_ci            DBG(15, "read_from_JPEGduplex: wrong width, req:%d got:%d\n",
8429141cc406Sopenharmony_ci	      s->s_params.pixels_per_line,width);
8430141cc406Sopenharmony_ci
8431141cc406Sopenharmony_ci	    /* put the high-order width byte into front side, shifted down */
8432141cc406Sopenharmony_ci            s->buffers[SIDE_FRONT][s->buff_rx[SIDE_FRONT]++] = width >> 9;
8433141cc406Sopenharmony_ci            s->bytes_rx[SIDE_FRONT]++;
8434141cc406Sopenharmony_ci
8435141cc406Sopenharmony_ci	    /* put the high-order width byte into back side, shifted down */
8436141cc406Sopenharmony_ci            s->buffers[SIDE_BACK][s->buff_rx[SIDE_BACK]++] = width >> 9;
8437141cc406Sopenharmony_ci            s->bytes_rx[SIDE_BACK]++;
8438141cc406Sopenharmony_ci
8439141cc406Sopenharmony_ci	    /* shift down low order byte */
8440141cc406Sopenharmony_ci            in[i] = (width >> 1) & 0xff;
8441141cc406Sopenharmony_ci	  }
8442141cc406Sopenharmony_ci        }
8443141cc406Sopenharmony_ci
8444141cc406Sopenharmony_ci        /* copy these stages to front */
8445141cc406Sopenharmony_ci        if(s->jpeg_stage == JPEG_STAGE_SOI
8446141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_HEAD
8447141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_SOF
8448141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_SOS
8449141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_EOI
8450141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_FRONT
8451141cc406Sopenharmony_ci        ){
8452141cc406Sopenharmony_ci            /* first byte after ff, send the ff first */
8453141cc406Sopenharmony_ci            if(s->jpeg_ff_offset == 1){
8454141cc406Sopenharmony_ci              s->buffers[SIDE_FRONT][s->buff_rx[SIDE_FRONT]++] = 0xff;
8455141cc406Sopenharmony_ci              s->bytes_rx[SIDE_FRONT]++;
8456141cc406Sopenharmony_ci            }
8457141cc406Sopenharmony_ci            s->buffers[SIDE_FRONT][s->buff_rx[SIDE_FRONT]++] = in[i];
8458141cc406Sopenharmony_ci            s->bytes_rx[SIDE_FRONT]++;
8459141cc406Sopenharmony_ci        }
8460141cc406Sopenharmony_ci
8461141cc406Sopenharmony_ci        /* copy these stages to back */
8462141cc406Sopenharmony_ci        if( s->jpeg_interlace == JPEG_INTERLACE_ALT
8463141cc406Sopenharmony_ci	  &&
8464141cc406Sopenharmony_ci	  ( s->jpeg_stage == JPEG_STAGE_SOI
8465141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_HEAD
8466141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_SOF
8467141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_SOS
8468141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_EOI
8469141cc406Sopenharmony_ci          || s->jpeg_stage == JPEG_STAGE_BACK )
8470141cc406Sopenharmony_ci        ){
8471141cc406Sopenharmony_ci            /* first byte after ff, send the ff first */
8472141cc406Sopenharmony_ci            if(s->jpeg_ff_offset == 1){
8473141cc406Sopenharmony_ci              s->buffers[SIDE_BACK][s->buff_rx[SIDE_BACK]++] = 0xff;
8474141cc406Sopenharmony_ci              s->bytes_rx[SIDE_BACK]++;
8475141cc406Sopenharmony_ci            }
8476141cc406Sopenharmony_ci            s->buffers[SIDE_BACK][s->buff_rx[SIDE_BACK]++] = in[i];
8477141cc406Sopenharmony_ci            s->bytes_rx[SIDE_BACK]++;
8478141cc406Sopenharmony_ci        }
8479141cc406Sopenharmony_ci
8480141cc406Sopenharmony_ci        /* reached last byte of SOS section, next byte front */
8481141cc406Sopenharmony_ci        if(s->jpeg_stage == JPEG_STAGE_SOS && s->jpeg_ff_offset == 0x0d){
8482141cc406Sopenharmony_ci            s->jpeg_stage = JPEG_STAGE_FRONT;
8483141cc406Sopenharmony_ci        }
8484141cc406Sopenharmony_ci
8485141cc406Sopenharmony_ci        /* last byte of file, update totals, bail out */
8486141cc406Sopenharmony_ci        if(s->jpeg_stage == JPEG_STAGE_EOI){
8487141cc406Sopenharmony_ci            s->eof_rx[SIDE_FRONT] = 1;
8488141cc406Sopenharmony_ci            if(s->jpeg_interlace == JPEG_INTERLACE_ALT)
8489141cc406Sopenharmony_ci              s->eof_rx[SIDE_BACK] = 1;
8490141cc406Sopenharmony_ci        }
8491141cc406Sopenharmony_ci    }
8492141cc406Sopenharmony_ci
8493141cc406Sopenharmony_ci    free(in);
8494141cc406Sopenharmony_ci
8495141cc406Sopenharmony_ci    /* jpeg uses in-band EOI marker, so this is usually redundant */
8496141cc406Sopenharmony_ci    if(ret == SANE_STATUS_EOF){
8497141cc406Sopenharmony_ci      DBG(15, "read_from_JPEGduplex: got EOF, finishing\n");
8498141cc406Sopenharmony_ci      s->eof_rx[SIDE_FRONT] = 1;
8499141cc406Sopenharmony_ci      if(s->jpeg_interlace == JPEG_INTERLACE_ALT)
8500141cc406Sopenharmony_ci        s->eof_rx[SIDE_BACK] = 1;
8501141cc406Sopenharmony_ci      ret = SANE_STATUS_GOOD;
8502141cc406Sopenharmony_ci    }
8503141cc406Sopenharmony_ci
8504141cc406Sopenharmony_ci    DBG (10, "read_from_JPEGduplex: finish\n");
8505141cc406Sopenharmony_ci
8506141cc406Sopenharmony_ci    return ret;
8507141cc406Sopenharmony_ci}
8508141cc406Sopenharmony_ci
8509141cc406Sopenharmony_cistatic SANE_Status
8510141cc406Sopenharmony_ciread_from_3091duplex(struct fujitsu *s)
8511141cc406Sopenharmony_ci{
8512141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8513141cc406Sopenharmony_ci
8514141cc406Sopenharmony_ci  unsigned char cmd[READ_len];
8515141cc406Sopenharmony_ci  size_t cmdLen = READ_len;
8516141cc406Sopenharmony_ci
8517141cc406Sopenharmony_ci  unsigned char * in;
8518141cc406Sopenharmony_ci  size_t inLen = 0;
8519141cc406Sopenharmony_ci
8520141cc406Sopenharmony_ci  int side = SIDE_FRONT;
8521141cc406Sopenharmony_ci  int bytes = s->buffer_size;
8522141cc406Sopenharmony_ci  int off = (s->duplex_raster_offset+s->duplex_offset) * s->resolution_y/300;
8523141cc406Sopenharmony_ci  unsigned int i;
8524141cc406Sopenharmony_ci
8525141cc406Sopenharmony_ci  DBG (10, "read_from_3091duplex: start\n");
8526141cc406Sopenharmony_ci
8527141cc406Sopenharmony_ci  if(s->eof_rx[SIDE_FRONT] && s->eof_rx[SIDE_BACK]){
8528141cc406Sopenharmony_ci    DBG (10, "read_from_3091duplex: already have eofs, done\n");
8529141cc406Sopenharmony_ci    return ret;
8530141cc406Sopenharmony_ci  }
8531141cc406Sopenharmony_ci
8532141cc406Sopenharmony_ci  /* we don't know if the following read will give us front,back or both data
8533141cc406Sopenharmony_ci   * so we only get enough to fill whichever is smaller (and not yet done) */
8534141cc406Sopenharmony_ci  if(!s->eof_rx[SIDE_FRONT]){
8535141cc406Sopenharmony_ci    int avail = s->buff_tot[SIDE_FRONT] - s->buff_rx[SIDE_FRONT];
8536141cc406Sopenharmony_ci    if(bytes > avail)
8537141cc406Sopenharmony_ci      bytes = avail;
8538141cc406Sopenharmony_ci  }
8539141cc406Sopenharmony_ci  if(!s->eof_rx[SIDE_BACK]){
8540141cc406Sopenharmony_ci    int avail = s->buff_tot[SIDE_BACK] - s->buff_rx[SIDE_BACK];
8541141cc406Sopenharmony_ci    if(bytes > avail)
8542141cc406Sopenharmony_ci      bytes = avail;
8543141cc406Sopenharmony_ci  }
8544141cc406Sopenharmony_ci
8545141cc406Sopenharmony_ci  /* all requests must end on a line boundary */
8546141cc406Sopenharmony_ci  bytes -= (bytes % s->s_params.bytes_per_line);
8547141cc406Sopenharmony_ci
8548141cc406Sopenharmony_ci  DBG(15, "read_from_3091duplex: front img: to:%d rx:%d tx:%d li:%d\n",
8549141cc406Sopenharmony_ci      s->bytes_tot[SIDE_FRONT], s->bytes_rx[SIDE_FRONT],
8550141cc406Sopenharmony_ci      s->bytes_tx[SIDE_FRONT], s->lines_rx[SIDE_FRONT]);
8551141cc406Sopenharmony_ci
8552141cc406Sopenharmony_ci  DBG(15, "read_from_3091duplex: front buf: to:%d rx:%d tx:%d\n",
8553141cc406Sopenharmony_ci      s->buff_tot[SIDE_FRONT], s->buff_rx[SIDE_FRONT],
8554141cc406Sopenharmony_ci      s->buff_tx[SIDE_FRONT]);
8555141cc406Sopenharmony_ci
8556141cc406Sopenharmony_ci  DBG(15, "read_from_3091duplex: back img: to:%d rx:%d tx:%d li:%d\n",
8557141cc406Sopenharmony_ci      s->bytes_tot[SIDE_BACK], s->bytes_rx[SIDE_BACK],
8558141cc406Sopenharmony_ci      s->bytes_tx[SIDE_BACK], s->lines_rx[SIDE_BACK]);
8559141cc406Sopenharmony_ci
8560141cc406Sopenharmony_ci  DBG(15, "read_from_3091duplex: back buf: to:%d rx:%d tx:%d\n",
8561141cc406Sopenharmony_ci      s->buff_tot[SIDE_BACK], s->buff_rx[SIDE_BACK],
8562141cc406Sopenharmony_ci      s->buff_tx[SIDE_BACK]);
8563141cc406Sopenharmony_ci
8564141cc406Sopenharmony_ci  DBG(15, "read_from_3091duplex: bu:%d pa:%d of:%d\n",
8565141cc406Sopenharmony_ci      s->buffer_size, bytes, off);
8566141cc406Sopenharmony_ci
8567141cc406Sopenharmony_ci  /* this could happen if the front buffer is not drained fast enough */
8568141cc406Sopenharmony_ci  if(bytes < 1){
8569141cc406Sopenharmony_ci    DBG(10, "read_from_3091duplex: Warning: no bytes this pass\n");
8570141cc406Sopenharmony_ci    return ret;
8571141cc406Sopenharmony_ci  }
8572141cc406Sopenharmony_ci
8573141cc406Sopenharmony_ci  inLen = bytes;
8574141cc406Sopenharmony_ci
8575141cc406Sopenharmony_ci  in = malloc(inLen);
8576141cc406Sopenharmony_ci  if(!in){
8577141cc406Sopenharmony_ci    DBG(5, "read_from_3091duplex: not enough mem for buffer: %d\n",(int)inLen);
8578141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
8579141cc406Sopenharmony_ci  }
8580141cc406Sopenharmony_ci
8581141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
8582141cc406Sopenharmony_ci  set_SCSI_opcode(cmd, READ_code);
8583141cc406Sopenharmony_ci  set_R_datatype_code (cmd, R_datatype_imagedata);
8584141cc406Sopenharmony_ci  /* 3091 duplex always reads from front */
8585141cc406Sopenharmony_ci  set_R_window_id (cmd, WD_wid_front);
8586141cc406Sopenharmony_ci  set_R_xfer_length (cmd, inLen);
8587141cc406Sopenharmony_ci
8588141cc406Sopenharmony_ci  ret = do_cmd (
8589141cc406Sopenharmony_ci    s, 1, 0,
8590141cc406Sopenharmony_ci    cmd, cmdLen,
8591141cc406Sopenharmony_ci    NULL, 0,
8592141cc406Sopenharmony_ci    in, &inLen
8593141cc406Sopenharmony_ci  );
8594141cc406Sopenharmony_ci
8595141cc406Sopenharmony_ci  if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) {
8596141cc406Sopenharmony_ci    DBG(15, "read_from_3091duplex: got GOOD/EOF, returning GOOD\n");
8597141cc406Sopenharmony_ci  }
8598141cc406Sopenharmony_ci  else if (ret == SANE_STATUS_DEVICE_BUSY) {
8599141cc406Sopenharmony_ci    DBG(5, "read_from_3091duplex: got BUSY, returning GOOD\n");
8600141cc406Sopenharmony_ci    inLen = 0;
8601141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
8602141cc406Sopenharmony_ci  }
8603141cc406Sopenharmony_ci  else {
8604141cc406Sopenharmony_ci    DBG(5, "read_from_3091duplex: error reading data block status = %d\n", ret);
8605141cc406Sopenharmony_ci    inLen = 0;
8606141cc406Sopenharmony_ci  }
8607141cc406Sopenharmony_ci
8608141cc406Sopenharmony_ci  /* loop thru all lines in read buffer */
8609141cc406Sopenharmony_ci  for(i=0;i<inLen/s->s_params.bytes_per_line;i++){
8610141cc406Sopenharmony_ci
8611141cc406Sopenharmony_ci      /* start is front */
8612141cc406Sopenharmony_ci      if(s->lines_rx[SIDE_FRONT] < off){
8613141cc406Sopenharmony_ci        side=SIDE_FRONT;
8614141cc406Sopenharmony_ci      }
8615141cc406Sopenharmony_ci
8616141cc406Sopenharmony_ci      /* end is back */
8617141cc406Sopenharmony_ci      else if(s->eof_rx[SIDE_FRONT]){
8618141cc406Sopenharmony_ci        side=SIDE_BACK;
8619141cc406Sopenharmony_ci      }
8620141cc406Sopenharmony_ci
8621141cc406Sopenharmony_ci      /* odd are back */
8622141cc406Sopenharmony_ci      else if( ((s->lines_rx[SIDE_FRONT] + s->lines_rx[SIDE_BACK] - off) % 2) ){
8623141cc406Sopenharmony_ci        side=SIDE_BACK;
8624141cc406Sopenharmony_ci      }
8625141cc406Sopenharmony_ci
8626141cc406Sopenharmony_ci      /* even are front */
8627141cc406Sopenharmony_ci      else{
8628141cc406Sopenharmony_ci        side=SIDE_FRONT;
8629141cc406Sopenharmony_ci      }
8630141cc406Sopenharmony_ci
8631141cc406Sopenharmony_ci      if(s->s_mode == MODE_COLOR && s->color_interlace == COLOR_INTERLACE_3091){
8632141cc406Sopenharmony_ci        copy_3091 (s, in + i*s->s_params.bytes_per_line, s->s_params.bytes_per_line, side);
8633141cc406Sopenharmony_ci      }
8634141cc406Sopenharmony_ci      else{
8635141cc406Sopenharmony_ci        copy_buffer (s, in + i*s->s_params.bytes_per_line, s->s_params.bytes_per_line, side);
8636141cc406Sopenharmony_ci      }
8637141cc406Sopenharmony_ci  }
8638141cc406Sopenharmony_ci
8639141cc406Sopenharmony_ci  if(ret == SANE_STATUS_EOF){
8640141cc406Sopenharmony_ci    DBG(15, "read_from_3091duplex: got EOF, finishing both sides\n");
8641141cc406Sopenharmony_ci    s->eof_rx[SIDE_FRONT] = 1;
8642141cc406Sopenharmony_ci    s->eof_rx[SIDE_BACK] = 1;
8643141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
8644141cc406Sopenharmony_ci  }
8645141cc406Sopenharmony_ci
8646141cc406Sopenharmony_ci  free(in);
8647141cc406Sopenharmony_ci
8648141cc406Sopenharmony_ci  DBG (10, "read_from_3091duplex: finish\n");
8649141cc406Sopenharmony_ci
8650141cc406Sopenharmony_ci  return ret;
8651141cc406Sopenharmony_ci}
8652141cc406Sopenharmony_ci
8653141cc406Sopenharmony_cistatic SANE_Status
8654141cc406Sopenharmony_ciread_from_scanner(struct fujitsu *s, int side)
8655141cc406Sopenharmony_ci{
8656141cc406Sopenharmony_ci    SANE_Status ret=SANE_STATUS_GOOD;
8657141cc406Sopenharmony_ci
8658141cc406Sopenharmony_ci    unsigned char cmd[READ_len];
8659141cc406Sopenharmony_ci    size_t cmdLen = READ_len;
8660141cc406Sopenharmony_ci
8661141cc406Sopenharmony_ci    unsigned char * in;
8662141cc406Sopenharmony_ci    size_t inLen = 0;
8663141cc406Sopenharmony_ci
8664141cc406Sopenharmony_ci    int bytes = s->buffer_size;
8665141cc406Sopenharmony_ci    int avail = s->buff_tot[side] - s->buff_rx[side];
8666141cc406Sopenharmony_ci    int remain = s->bytes_tot[side] - s->bytes_rx[side];
8667141cc406Sopenharmony_ci
8668141cc406Sopenharmony_ci    DBG (10, "read_from_scanner: start %d\n", side);
8669141cc406Sopenharmony_ci
8670141cc406Sopenharmony_ci    if(s->eof_rx[side]){
8671141cc406Sopenharmony_ci      DBG (10, "read_from_scanner: already have eof, done\n");
8672141cc406Sopenharmony_ci      return ret;
8673141cc406Sopenharmony_ci    }
8674141cc406Sopenharmony_ci
8675141cc406Sopenharmony_ci    /* figure out the max amount to transfer */
8676141cc406Sopenharmony_ci    if(bytes > avail)
8677141cc406Sopenharmony_ci      bytes = avail;
8678141cc406Sopenharmony_ci
8679141cc406Sopenharmony_ci    /* all requests must end on line boundary */
8680141cc406Sopenharmony_ci    bytes -= (bytes % s->s_params.bytes_per_line);
8681141cc406Sopenharmony_ci
8682141cc406Sopenharmony_ci    /* some larger scanners require even bytes per block */
8683141cc406Sopenharmony_ci    /* so we get even lines, but not on the last block */
8684141cc406Sopenharmony_ci    /* cause odd number of lines would never finish */
8685141cc406Sopenharmony_ci    if(bytes % 2 && bytes < remain){
8686141cc406Sopenharmony_ci       bytes -= s->s_params.bytes_per_line;
8687141cc406Sopenharmony_ci    }
8688141cc406Sopenharmony_ci
8689141cc406Sopenharmony_ci    /* jpeg scans leave space for JFIF header at start of image */
8690141cc406Sopenharmony_ci    if(s->s_params.format == SANE_FRAME_JPEG && s->bytes_rx[side] < 2)
8691141cc406Sopenharmony_ci      bytes -= JFIF_APP0_LENGTH;
8692141cc406Sopenharmony_ci
8693141cc406Sopenharmony_ci    DBG(15, "read_from_scanner: si:%d re:%d bs:%d by:%d av:%d\n",
8694141cc406Sopenharmony_ci      side, remain, s->buffer_size, bytes, avail);
8695141cc406Sopenharmony_ci
8696141cc406Sopenharmony_ci    DBG(15, "read_from_scanner: img to:%d rx:%d tx:%d li:%d\n",
8697141cc406Sopenharmony_ci      s->bytes_tot[side], s->bytes_rx[side], s->bytes_tx[side],
8698141cc406Sopenharmony_ci      s->lines_rx[side]);
8699141cc406Sopenharmony_ci
8700141cc406Sopenharmony_ci    DBG(15, "read_from_scanner: buf to:%d rx:%d tx:%d\n",
8701141cc406Sopenharmony_ci      s->buff_tot[side], s->buff_rx[side], s->buff_tx[side]);
8702141cc406Sopenharmony_ci
8703141cc406Sopenharmony_ci    /* this will happen if buffer is not drained yet */
8704141cc406Sopenharmony_ci    if(bytes < 1){
8705141cc406Sopenharmony_ci      DBG(5, "read_from_scanner: no bytes this pass\n");
8706141cc406Sopenharmony_ci      return ret;
8707141cc406Sopenharmony_ci    }
8708141cc406Sopenharmony_ci
8709141cc406Sopenharmony_ci    /* fi-6770A gets mad if you 'read' too soon on usb, see if it is ready */
8710141cc406Sopenharmony_ci    if(!s->bytes_rx[side] && s->connection == CONNECTION_USB){
8711141cc406Sopenharmony_ci      DBG (15, "read_from_scanner: start of usb page, checking RIC\n");
8712141cc406Sopenharmony_ci      ret = scanner_control_ric(s,bytes,side);
8713141cc406Sopenharmony_ci      if(ret){
8714141cc406Sopenharmony_ci        DBG(5,"read_from_scanner: ric returning %d\n",ret);
8715141cc406Sopenharmony_ci        return ret;
8716141cc406Sopenharmony_ci      }
8717141cc406Sopenharmony_ci    }
8718141cc406Sopenharmony_ci
8719141cc406Sopenharmony_ci    inLen = bytes;
8720141cc406Sopenharmony_ci    in = malloc(inLen);
8721141cc406Sopenharmony_ci    if(!in){
8722141cc406Sopenharmony_ci        DBG(5, "read_from_scanner: not enough mem for buffer: %d\n",(int)inLen);
8723141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
8724141cc406Sopenharmony_ci    }
8725141cc406Sopenharmony_ci
8726141cc406Sopenharmony_ci    memset(cmd,0,cmdLen);
8727141cc406Sopenharmony_ci    set_SCSI_opcode(cmd, READ_code);
8728141cc406Sopenharmony_ci    set_R_datatype_code (cmd, R_datatype_imagedata);
8729141cc406Sopenharmony_ci
8730141cc406Sopenharmony_ci    if (side == SIDE_BACK) {
8731141cc406Sopenharmony_ci        set_R_window_id (cmd, WD_wid_back);
8732141cc406Sopenharmony_ci    }
8733141cc406Sopenharmony_ci    else{
8734141cc406Sopenharmony_ci        set_R_window_id (cmd, WD_wid_front);
8735141cc406Sopenharmony_ci    }
8736141cc406Sopenharmony_ci
8737141cc406Sopenharmony_ci    set_R_xfer_length (cmd, inLen);
8738141cc406Sopenharmony_ci
8739141cc406Sopenharmony_ci    ret = do_cmd (
8740141cc406Sopenharmony_ci      s, 1, 0,
8741141cc406Sopenharmony_ci      cmd, cmdLen,
8742141cc406Sopenharmony_ci      NULL, 0,
8743141cc406Sopenharmony_ci      in, &inLen
8744141cc406Sopenharmony_ci    );
8745141cc406Sopenharmony_ci
8746141cc406Sopenharmony_ci    if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) {
8747141cc406Sopenharmony_ci        DBG(15, "read_from_scanner: got GOOD/EOF, returning GOOD\n");
8748141cc406Sopenharmony_ci        ret = SANE_STATUS_GOOD;
8749141cc406Sopenharmony_ci    }
8750141cc406Sopenharmony_ci    else if (ret == SANE_STATUS_DEVICE_BUSY) {
8751141cc406Sopenharmony_ci        DBG(5, "read_from_scanner: got BUSY, returning GOOD\n");
8752141cc406Sopenharmony_ci        inLen = 0;
8753141cc406Sopenharmony_ci        ret = SANE_STATUS_GOOD;
8754141cc406Sopenharmony_ci    }
8755141cc406Sopenharmony_ci    else {
8756141cc406Sopenharmony_ci        DBG(5, "read_from_scanner: error reading data block status = %d\n",ret);
8757141cc406Sopenharmony_ci        inLen = 0;
8758141cc406Sopenharmony_ci    }
8759141cc406Sopenharmony_ci
8760141cc406Sopenharmony_ci    DBG(15, "read_from_scanner: read %lu bytes\n",(unsigned long)inLen);
8761141cc406Sopenharmony_ci
8762141cc406Sopenharmony_ci    if(inLen){
8763141cc406Sopenharmony_ci        if(s->s_mode==MODE_COLOR && s->color_interlace == COLOR_INTERLACE_3091){
8764141cc406Sopenharmony_ci            copy_3091 (s, in, inLen, side);
8765141cc406Sopenharmony_ci        }
8766141cc406Sopenharmony_ci        else if(s->s_params.format == SANE_FRAME_JPEG){
8767141cc406Sopenharmony_ci            copy_JPEG (s, in, inLen, side);
8768141cc406Sopenharmony_ci        }
8769141cc406Sopenharmony_ci        else{
8770141cc406Sopenharmony_ci            copy_buffer (s, in, inLen, side);
8771141cc406Sopenharmony_ci        }
8772141cc406Sopenharmony_ci    }
8773141cc406Sopenharmony_ci
8774141cc406Sopenharmony_ci    free(in);
8775141cc406Sopenharmony_ci
8776141cc406Sopenharmony_ci    /* if this was a short read or not, log it */
8777141cc406Sopenharmony_ci    s->ili_rx[side] = s->rs_ili;
8778141cc406Sopenharmony_ci    if(s->ili_rx[side]){
8779141cc406Sopenharmony_ci      DBG(15, "read_from_scanner: got ILI\n");
8780141cc406Sopenharmony_ci    }
8781141cc406Sopenharmony_ci
8782141cc406Sopenharmony_ci    /* if this was an end of medium, log it */
8783141cc406Sopenharmony_ci    if(s->rs_eom){
8784141cc406Sopenharmony_ci      DBG(15, "read_from_scanner: got EOM\n");
8785141cc406Sopenharmony_ci      s->eom_rx = 1;
8786141cc406Sopenharmony_ci    }
8787141cc406Sopenharmony_ci
8788141cc406Sopenharmony_ci    /* paper ran out. lets try to set the eof flag on both sides,
8789141cc406Sopenharmony_ci     * but only if that side had a short read last time */
8790141cc406Sopenharmony_ci    if(s->eom_rx){
8791141cc406Sopenharmony_ci      int i;
8792141cc406Sopenharmony_ci      for(i=0;i<2;i++){
8793141cc406Sopenharmony_ci        if(s->ili_rx[i]){
8794141cc406Sopenharmony_ci          DBG(15, "read_from_scanner: finishing side %d\n",i);
8795141cc406Sopenharmony_ci          s->eof_rx[i] = 1;
8796141cc406Sopenharmony_ci        }
8797141cc406Sopenharmony_ci      }
8798141cc406Sopenharmony_ci    }
8799141cc406Sopenharmony_ci
8800141cc406Sopenharmony_ci    DBG (10, "read_from_scanner: finish\n");
8801141cc406Sopenharmony_ci
8802141cc406Sopenharmony_ci    return ret;
8803141cc406Sopenharmony_ci}
8804141cc406Sopenharmony_ci
8805141cc406Sopenharmony_cistatic SANE_Status
8806141cc406Sopenharmony_cicopy_3091(struct fujitsu *s, unsigned char * buf, int len, int side)
8807141cc406Sopenharmony_ci{
8808141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8809141cc406Sopenharmony_ci  int i, j, dest, boff, goff;
8810141cc406Sopenharmony_ci
8811141cc406Sopenharmony_ci  DBG (10, "copy_3091: start\n");
8812141cc406Sopenharmony_ci
8813141cc406Sopenharmony_ci  /* Data is RR...GG...BB... on each line,
8814141cc406Sopenharmony_ci   * green is back 8 lines from red at 300 dpi
8815141cc406Sopenharmony_ci   * blue is back 4 lines from red at 300 dpi.
8816141cc406Sopenharmony_ci   *
8817141cc406Sopenharmony_ci   * Here, we get things on correct line, and
8818141cc406Sopenharmony_ci   * interlace to make RGBRGB.
8819141cc406Sopenharmony_ci   *
8820141cc406Sopenharmony_ci   * We add the user-supplied offsets before we scale
8821141cc406Sopenharmony_ci   * so that they are independent of scanning resolution.
8822141cc406Sopenharmony_ci   */
8823141cc406Sopenharmony_ci  goff = (s->color_raster_offset+s->green_offset) * s->resolution_y/150;
8824141cc406Sopenharmony_ci  boff = (s->color_raster_offset+s->blue_offset) * s->resolution_y/300;
8825141cc406Sopenharmony_ci
8826141cc406Sopenharmony_ci  /* loop thru all lines in read buffer */
8827141cc406Sopenharmony_ci  for(i=0;i<len;i+=s->s_params.bytes_per_line){
8828141cc406Sopenharmony_ci
8829141cc406Sopenharmony_ci      /* red at start of line */
8830141cc406Sopenharmony_ci      dest = s->lines_rx[side] * s->s_params.bytes_per_line;
8831141cc406Sopenharmony_ci
8832141cc406Sopenharmony_ci      if(dest >= 0 && dest < s->bytes_tot[side]){
8833141cc406Sopenharmony_ci        for (j=0; j<s->s_params.pixels_per_line; j++){
8834141cc406Sopenharmony_ci          s->buffers[side][dest+j*3] = buf[i+j];
8835141cc406Sopenharmony_ci        }
8836141cc406Sopenharmony_ci      }
8837141cc406Sopenharmony_ci
8838141cc406Sopenharmony_ci      /* green is in middle of line */
8839141cc406Sopenharmony_ci      dest = (s->lines_rx[side] - goff) * s->s_params.bytes_per_line;
8840141cc406Sopenharmony_ci
8841141cc406Sopenharmony_ci      if(dest >= 0 && dest < s->bytes_tot[side]){
8842141cc406Sopenharmony_ci        for (j=0; j<s->s_params.pixels_per_line; j++){
8843141cc406Sopenharmony_ci          s->buffers[side][dest+j*3+1] = buf[i+s->s_params.pixels_per_line+j];
8844141cc406Sopenharmony_ci        }
8845141cc406Sopenharmony_ci      }
8846141cc406Sopenharmony_ci
8847141cc406Sopenharmony_ci      /* blue is at end of line */
8848141cc406Sopenharmony_ci      dest = (s->lines_rx[side] - boff) * s->s_params.bytes_per_line;
8849141cc406Sopenharmony_ci
8850141cc406Sopenharmony_ci      if(dest >= 0 && dest < s->bytes_tot[side]){
8851141cc406Sopenharmony_ci        for (j=0; j<s->s_params.pixels_per_line; j++){
8852141cc406Sopenharmony_ci          s->buffers[side][dest+j*3+2] = buf[i+2*s->s_params.pixels_per_line+j];
8853141cc406Sopenharmony_ci        }
8854141cc406Sopenharmony_ci      }
8855141cc406Sopenharmony_ci
8856141cc406Sopenharmony_ci      s->lines_rx[side]++;
8857141cc406Sopenharmony_ci  }
8858141cc406Sopenharmony_ci
8859141cc406Sopenharmony_ci  /* even if we have read data, we may not have any
8860141cc406Sopenharmony_ci   * full lines loaded yet, so we may have to lie */
8861141cc406Sopenharmony_ci  i = (s->lines_rx[side]-goff) * s->s_params.bytes_per_line;
8862141cc406Sopenharmony_ci  if(i < 0){
8863141cc406Sopenharmony_ci    i = 0;
8864141cc406Sopenharmony_ci  }
8865141cc406Sopenharmony_ci  s->bytes_rx[side] = i;
8866141cc406Sopenharmony_ci  s->buff_rx[side] = i;
8867141cc406Sopenharmony_ci
8868141cc406Sopenharmony_ci  if(s->bytes_rx[side] == s->bytes_tot[side]){
8869141cc406Sopenharmony_ci    s->eof_rx[side] = 1;
8870141cc406Sopenharmony_ci  }
8871141cc406Sopenharmony_ci
8872141cc406Sopenharmony_ci  DBG(15, "copy_3091: si:%d imgrx:%d bufrx:%d li:%d eof:%d\n",
8873141cc406Sopenharmony_ci    side, s->bytes_rx[side], s->buff_rx[side], s->lines_rx[side],
8874141cc406Sopenharmony_ci    s->eof_rx[side]);
8875141cc406Sopenharmony_ci
8876141cc406Sopenharmony_ci  DBG (10, "copy_3091: finish\n");
8877141cc406Sopenharmony_ci
8878141cc406Sopenharmony_ci  return ret;
8879141cc406Sopenharmony_ci}
8880141cc406Sopenharmony_ci
8881141cc406Sopenharmony_cistatic SANE_Status
8882141cc406Sopenharmony_cicopy_JPEG(struct fujitsu *s, unsigned char * buf, int len, int side)
8883141cc406Sopenharmony_ci{
8884141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8885141cc406Sopenharmony_ci  int i, seen = 0;
8886141cc406Sopenharmony_ci
8887141cc406Sopenharmony_ci  DBG (10, "copy_JPEG: start\n");
8888141cc406Sopenharmony_ci
8889141cc406Sopenharmony_ci  /* A jpeg image starts with the SOI marker, FF D8.
8890141cc406Sopenharmony_ci   * This is optionally followed by the JFIF APP0
8891141cc406Sopenharmony_ci   * marker, FF E0. If that marker is not present,
8892141cc406Sopenharmony_ci   * we add it, so we can insert the resolution */
8893141cc406Sopenharmony_ci
8894141cc406Sopenharmony_ci  if(!s->bytes_rx[side] && len >= 4
8895141cc406Sopenharmony_ci    && buf[0] == 0xFF && buf[1] == 0xD8
8896141cc406Sopenharmony_ci    && buf[2] == 0xFF && buf[3] != 0xE0
8897141cc406Sopenharmony_ci  ){
8898141cc406Sopenharmony_ci    /* SOI marker */
8899141cc406Sopenharmony_ci    for (i=0; i<2; i++){
8900141cc406Sopenharmony_ci      s->buffers[side][s->buff_rx[side]++] = buf[i];
8901141cc406Sopenharmony_ci      s->bytes_rx[side]++;
8902141cc406Sopenharmony_ci      seen++;
8903141cc406Sopenharmony_ci    }
8904141cc406Sopenharmony_ci
8905141cc406Sopenharmony_ci    /* JFIF header after SOI */
8906141cc406Sopenharmony_ci    inject_jfif_header(s,side);
8907141cc406Sopenharmony_ci  }
8908141cc406Sopenharmony_ci
8909141cc406Sopenharmony_ci  memcpy(s->buffers[side]+s->buff_rx[side],buf+seen,len-seen);
8910141cc406Sopenharmony_ci  s->buff_rx[side] += len-seen;
8911141cc406Sopenharmony_ci  s->bytes_rx[side] += len-seen;
8912141cc406Sopenharmony_ci
8913141cc406Sopenharmony_ci  /* should never happen with jpeg */
8914141cc406Sopenharmony_ci  if(s->bytes_rx[side] == s->bytes_tot[side]){
8915141cc406Sopenharmony_ci    s->eof_rx[side] = 1;
8916141cc406Sopenharmony_ci  }
8917141cc406Sopenharmony_ci
8918141cc406Sopenharmony_ci  DBG (10, "copy_JPEG: finish\n");
8919141cc406Sopenharmony_ci
8920141cc406Sopenharmony_ci  return ret;
8921141cc406Sopenharmony_ci}
8922141cc406Sopenharmony_ci
8923141cc406Sopenharmony_cistatic SANE_Status
8924141cc406Sopenharmony_cicopy_buffer(struct fujitsu *s, unsigned char * buf, int len, int side)
8925141cc406Sopenharmony_ci{
8926141cc406Sopenharmony_ci  SANE_Status ret=SANE_STATUS_GOOD;
8927141cc406Sopenharmony_ci  int i, j;
8928141cc406Sopenharmony_ci  int bwidth = s->s_params.bytes_per_line;
8929141cc406Sopenharmony_ci  int pwidth = s->s_params.pixels_per_line;
8930141cc406Sopenharmony_ci
8931141cc406Sopenharmony_ci  DBG (10, "copy_buffer: start\n");
8932141cc406Sopenharmony_ci
8933141cc406Sopenharmony_ci  /* invert image if scanner needs it for this mode */
8934141cc406Sopenharmony_ci  /* jpeg data does not use inverting */
8935141cc406Sopenharmony_ci  if(s->s_params.format != SANE_FRAME_JPEG && s->reverse_by_mode[s->s_mode]){
8936141cc406Sopenharmony_ci    for(i=0; i<len; i++){
8937141cc406Sopenharmony_ci      buf[i] ^= 0xff;
8938141cc406Sopenharmony_ci    }
8939141cc406Sopenharmony_ci  }
8940141cc406Sopenharmony_ci
8941141cc406Sopenharmony_ci  /* scanners interlace colors in many different ways */
8942141cc406Sopenharmony_ci  if(s->s_params.format == SANE_FRAME_RGB){
8943141cc406Sopenharmony_ci
8944141cc406Sopenharmony_ci    switch (s->color_interlace) {
8945141cc406Sopenharmony_ci
8946141cc406Sopenharmony_ci      /* scanner returns pixel data as bgrbgr... */
8947141cc406Sopenharmony_ci      case COLOR_INTERLACE_BGR:
8948141cc406Sopenharmony_ci        for(i=0; i<len; i+=bwidth){
8949141cc406Sopenharmony_ci          for (j=0; j<pwidth; j++){
8950141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+j*3+2];
8951141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+j*3+1];
8952141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+j*3];
8953141cc406Sopenharmony_ci          }
8954141cc406Sopenharmony_ci        }
8955141cc406Sopenharmony_ci        break;
8956141cc406Sopenharmony_ci
8957141cc406Sopenharmony_ci      /* one line has the following format: rrr...rrrggg...gggbbb...bbb */
8958141cc406Sopenharmony_ci      case COLOR_INTERLACE_RRGGBB:
8959141cc406Sopenharmony_ci        for(i=0; i<len; i+=bwidth){
8960141cc406Sopenharmony_ci          for (j=0; j<pwidth; j++){
8961141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+j];
8962141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+pwidth+j];
8963141cc406Sopenharmony_ci            s->buffers[side][s->buff_rx[side]++] = buf[i+2*pwidth+j];
8964141cc406Sopenharmony_ci          }
8965141cc406Sopenharmony_ci        }
8966141cc406Sopenharmony_ci        break;
8967141cc406Sopenharmony_ci
8968141cc406Sopenharmony_ci      default:
8969141cc406Sopenharmony_ci        memcpy(s->buffers[side]+s->buff_rx[side],buf,len);
8970141cc406Sopenharmony_ci        s->buff_rx[side] += len;
8971141cc406Sopenharmony_ci        break;
8972141cc406Sopenharmony_ci    }
8973141cc406Sopenharmony_ci  }
8974141cc406Sopenharmony_ci
8975141cc406Sopenharmony_ci  /* jpeg/gray/ht/binary */
8976141cc406Sopenharmony_ci  else{
8977141cc406Sopenharmony_ci    memcpy(s->buffers[side]+s->buff_rx[side],buf,len);
8978141cc406Sopenharmony_ci    s->buff_rx[side] += len;
8979141cc406Sopenharmony_ci  }
8980141cc406Sopenharmony_ci
8981141cc406Sopenharmony_ci  s->bytes_rx[side] += len;
8982141cc406Sopenharmony_ci  s->lines_rx[side] += len/s->s_params.bytes_per_line;
8983141cc406Sopenharmony_ci
8984141cc406Sopenharmony_ci  if(s->bytes_rx[side] == s->bytes_tot[side]){
8985141cc406Sopenharmony_ci    s->eof_rx[side] = 1;
8986141cc406Sopenharmony_ci  }
8987141cc406Sopenharmony_ci
8988141cc406Sopenharmony_ci  DBG (10, "copy_buffer: finish\n");
8989141cc406Sopenharmony_ci
8990141cc406Sopenharmony_ci  return ret;
8991141cc406Sopenharmony_ci}
8992141cc406Sopenharmony_ci
8993141cc406Sopenharmony_cistatic SANE_Status
8994141cc406Sopenharmony_ciread_from_buffer(struct fujitsu *s, SANE_Byte * buf,
8995141cc406Sopenharmony_ci  SANE_Int max_len, SANE_Int * len, int side)
8996141cc406Sopenharmony_ci{
8997141cc406Sopenharmony_ci    SANE_Status ret=SANE_STATUS_GOOD;
8998141cc406Sopenharmony_ci    int bytes = max_len;
8999141cc406Sopenharmony_ci    int remain = s->buff_rx[side] - s->buff_tx[side];
9000141cc406Sopenharmony_ci
9001141cc406Sopenharmony_ci    DBG (10, "read_from_buffer: start\n");
9002141cc406Sopenharmony_ci
9003141cc406Sopenharmony_ci    /* figure out the max amount to transfer */
9004141cc406Sopenharmony_ci    if(bytes > remain){
9005141cc406Sopenharmony_ci        bytes = remain;
9006141cc406Sopenharmony_ci    }
9007141cc406Sopenharmony_ci
9008141cc406Sopenharmony_ci    *len = bytes;
9009141cc406Sopenharmony_ci
9010141cc406Sopenharmony_ci    DBG(15, "read_from_buffer: si:%d re:%d ml:%d by:%d\n",
9011141cc406Sopenharmony_ci      side, remain, max_len, bytes);
9012141cc406Sopenharmony_ci
9013141cc406Sopenharmony_ci    DBG(15, "read_from_buffer: img to:%d rx:%d tx:%d\n",
9014141cc406Sopenharmony_ci      s->bytes_tot[side], s->bytes_rx[side], s->bytes_tx[side]);
9015141cc406Sopenharmony_ci
9016141cc406Sopenharmony_ci    DBG(15, "read_from_buffer: buf to:%d rx:%d tx:%d\n",
9017141cc406Sopenharmony_ci      s->buff_tot[side], s->buff_rx[side], s->buff_tx[side]);
9018141cc406Sopenharmony_ci
9019141cc406Sopenharmony_ci    /*FIXME this needs to timeout eventually */
9020141cc406Sopenharmony_ci    if(!bytes){
9021141cc406Sopenharmony_ci        DBG(5,"read_from_buffer: nothing to do\n");
9022141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
9023141cc406Sopenharmony_ci    }
9024141cc406Sopenharmony_ci
9025141cc406Sopenharmony_ci    memcpy(buf,s->buffers[side]+s->buff_tx[side],bytes);
9026141cc406Sopenharmony_ci    s->buff_tx[side] += bytes;
9027141cc406Sopenharmony_ci    s->bytes_tx[side] += bytes;
9028141cc406Sopenharmony_ci
9029141cc406Sopenharmony_ci    DBG (10, "read_from_buffer: finish\n");
9030141cc406Sopenharmony_ci
9031141cc406Sopenharmony_ci    return ret;
9032141cc406Sopenharmony_ci}
9033141cc406Sopenharmony_ci
9034141cc406Sopenharmony_ci/* we have bytes of higher mode image data in s->buffers */
9035141cc406Sopenharmony_ci/* user asked for lower mode image. downsample and copy to buf */
9036141cc406Sopenharmony_ci
9037141cc406Sopenharmony_cistatic SANE_Status
9038141cc406Sopenharmony_cidownsample_from_buffer(struct fujitsu *s, SANE_Byte * buf,
9039141cc406Sopenharmony_ci  SANE_Int max_len, SANE_Int * len, int side)
9040141cc406Sopenharmony_ci{
9041141cc406Sopenharmony_ci    SANE_Status ret=SANE_STATUS_GOOD;
9042141cc406Sopenharmony_ci
9043141cc406Sopenharmony_ci    DBG (10, "downsample_from_buffer: start %d %d %d %d\n", s->bytes_rx[side], s->bytes_tx[side], s->buff_rx[side], s->buff_tx[side]);
9044141cc406Sopenharmony_ci
9045141cc406Sopenharmony_ci    if(s->s_mode == MODE_COLOR && s->u_mode == MODE_GRAYSCALE){
9046141cc406Sopenharmony_ci
9047141cc406Sopenharmony_ci      while(*len < max_len && s->buff_rx[side] - s->buff_tx[side] >= 3){
9048141cc406Sopenharmony_ci
9049141cc406Sopenharmony_ci        int gray = 0;
9050141cc406Sopenharmony_ci
9051141cc406Sopenharmony_ci        switch (s->dropout_color) {
9052141cc406Sopenharmony_ci          case COLOR_RED:
9053141cc406Sopenharmony_ci            gray = *(s->buffers[side]+s->buff_tx[side]) * 3;
9054141cc406Sopenharmony_ci            break;
9055141cc406Sopenharmony_ci          case COLOR_GREEN:
9056141cc406Sopenharmony_ci            gray = *(s->buffers[side]+s->buff_tx[side]+1) * 3;
9057141cc406Sopenharmony_ci            break;
9058141cc406Sopenharmony_ci          case COLOR_BLUE:
9059141cc406Sopenharmony_ci            gray = *(s->buffers[side]+s->buff_tx[side]+2) * 3;
9060141cc406Sopenharmony_ci            break;
9061141cc406Sopenharmony_ci          default:
9062141cc406Sopenharmony_ci            gray = *(s->buffers[side]+s->buff_tx[side])
9063141cc406Sopenharmony_ci              + *(s->buffers[side]+s->buff_tx[side]+1)
9064141cc406Sopenharmony_ci              + *(s->buffers[side]+s->buff_tx[side]+2);
9065141cc406Sopenharmony_ci            break;
9066141cc406Sopenharmony_ci        }
9067141cc406Sopenharmony_ci
9068141cc406Sopenharmony_ci        /* bookkeeping for input */
9069141cc406Sopenharmony_ci        s->buff_tx[side] += 3;
9070141cc406Sopenharmony_ci        s->bytes_tx[side] += 3;
9071141cc406Sopenharmony_ci
9072141cc406Sopenharmony_ci        /* add byte to output */
9073141cc406Sopenharmony_ci        *(buf + *len) = gray/3;
9074141cc406Sopenharmony_ci        (*len)++;
9075141cc406Sopenharmony_ci      }
9076141cc406Sopenharmony_ci    }
9077141cc406Sopenharmony_ci
9078141cc406Sopenharmony_ci    else if(s->s_mode == MODE_COLOR && s->u_mode == MODE_LINEART){
9079141cc406Sopenharmony_ci
9080141cc406Sopenharmony_ci      /* threshold of 0 is actually middle of range */
9081141cc406Sopenharmony_ci      /*FIXME: add dynamic threshold? */
9082141cc406Sopenharmony_ci      unsigned char thresh = (s->threshold ? s->threshold : 127);
9083141cc406Sopenharmony_ci
9084141cc406Sopenharmony_ci      while(*len < max_len && s->buff_rx[side] - s->buff_tx[side] >= 24){
9085141cc406Sopenharmony_ci
9086141cc406Sopenharmony_ci        int i;
9087141cc406Sopenharmony_ci        unsigned char out = 0;
9088141cc406Sopenharmony_ci
9089141cc406Sopenharmony_ci        for(i=0; i<8; i++){
9090141cc406Sopenharmony_ci
9091141cc406Sopenharmony_ci          int gray = 0;
9092141cc406Sopenharmony_ci
9093141cc406Sopenharmony_ci          switch (s->dropout_color) {
9094141cc406Sopenharmony_ci            case COLOR_RED:
9095141cc406Sopenharmony_ci              gray = *(s->buffers[side]+s->buff_tx[side]) * 3;
9096141cc406Sopenharmony_ci              break;
9097141cc406Sopenharmony_ci            case COLOR_GREEN:
9098141cc406Sopenharmony_ci              gray = *(s->buffers[side]+s->buff_tx[side]+1) * 3;
9099141cc406Sopenharmony_ci              break;
9100141cc406Sopenharmony_ci            case COLOR_BLUE:
9101141cc406Sopenharmony_ci              gray = *(s->buffers[side]+s->buff_tx[side]+2) * 3;
9102141cc406Sopenharmony_ci              break;
9103141cc406Sopenharmony_ci            default:
9104141cc406Sopenharmony_ci              gray = *(s->buffers[side]+s->buff_tx[side])
9105141cc406Sopenharmony_ci                + *(s->buffers[side]+s->buff_tx[side]+1)
9106141cc406Sopenharmony_ci                + *(s->buffers[side]+s->buff_tx[side]+2);
9107141cc406Sopenharmony_ci              break;
9108141cc406Sopenharmony_ci          }
9109141cc406Sopenharmony_ci
9110141cc406Sopenharmony_ci          /* black if input gray is lower than threshold */
9111141cc406Sopenharmony_ci          if(gray/3 < thresh){
9112141cc406Sopenharmony_ci            out |= (0x80 >> i);
9113141cc406Sopenharmony_ci          }
9114141cc406Sopenharmony_ci
9115141cc406Sopenharmony_ci          /* bookkeeping for input */
9116141cc406Sopenharmony_ci          s->buff_tx[side] += 3;
9117141cc406Sopenharmony_ci          s->bytes_tx[side] += 3;
9118141cc406Sopenharmony_ci        }
9119141cc406Sopenharmony_ci
9120141cc406Sopenharmony_ci        /* add byte to output */
9121141cc406Sopenharmony_ci        *(buf + *len) = out;
9122141cc406Sopenharmony_ci        (*len)++;
9123141cc406Sopenharmony_ci      }
9124141cc406Sopenharmony_ci    }
9125141cc406Sopenharmony_ci
9126141cc406Sopenharmony_ci    else{
9127141cc406Sopenharmony_ci      DBG (5, "downsample_from_buffer: invalid mode combination\n");
9128141cc406Sopenharmony_ci      ret = SANE_STATUS_INVAL;
9129141cc406Sopenharmony_ci    }
9130141cc406Sopenharmony_ci
9131141cc406Sopenharmony_ci    DBG (10, "downsample_from_buffer: finish %d %d %d %d\n", s->bytes_rx[side], s->bytes_tx[side], s->buff_rx[side], s->buff_tx[side]);
9132141cc406Sopenharmony_ci
9133141cc406Sopenharmony_ci    return ret;
9134141cc406Sopenharmony_ci}
9135141cc406Sopenharmony_ci
9136141cc406Sopenharmony_ci
9137141cc406Sopenharmony_ci/*
9138141cc406Sopenharmony_ci * @@ Section 5 - SANE cleanup functions
9139141cc406Sopenharmony_ci */
9140141cc406Sopenharmony_ci/*
9141141cc406Sopenharmony_ci * Cancels a scan.
9142141cc406Sopenharmony_ci *
9143141cc406Sopenharmony_ci * It has been said on the mailing list that sane_cancel is a bit of a
9144141cc406Sopenharmony_ci * misnomer because it is routinely called to signal the end of a
9145141cc406Sopenharmony_ci * batch - quoting David Mosberger-Tang:
9146141cc406Sopenharmony_ci *
9147141cc406Sopenharmony_ci * > In other words, the idea is to have sane_start() be called, and
9148141cc406Sopenharmony_ci * > collect as many images as the frontend wants (which could in turn
9149141cc406Sopenharmony_ci * > consist of multiple frames each as indicated by frame-type) and
9150141cc406Sopenharmony_ci * > when the frontend is done, it should call sane_cancel().
9151141cc406Sopenharmony_ci * > Sometimes it's better to think of sane_cancel() as "sane_stop()"
9152141cc406Sopenharmony_ci * > but that name would have had some misleading connotations as
9153141cc406Sopenharmony_ci * > well, that's why we stuck with "cancel".
9154141cc406Sopenharmony_ci *
9155141cc406Sopenharmony_ci * The current consensus regarding duplex and ADF scans seems to be
9156141cc406Sopenharmony_ci * the following call sequence: sane_start; sane_read (repeat until
9157141cc406Sopenharmony_ci * EOF); sane_start; sane_read...  and then call sane_cancel if the
9158141cc406Sopenharmony_ci * batch is at an end. I.e. do not call sane_cancel during the run but
9159141cc406Sopenharmony_ci * as soon as you get a SANE_STATUS_NO_DOCS.
9160141cc406Sopenharmony_ci *
9161141cc406Sopenharmony_ci * From the SANE spec:
9162141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible
9163141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by
9164141cc406Sopenharmony_ci * handle h.  This function can be called at any time (as long as
9165141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running
9166141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call
9167141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler).
9168141cc406Sopenharmony_ci * It is important to note that completion of this operation does not
9169141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It
9170141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation
9171141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a
9172141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED).  Since the SANE API does
9173141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies
9174141cc406Sopenharmony_ci * that a frontend must not call any other operation until the
9175141cc406Sopenharmony_ci * cancelled operation has returned.
9176141cc406Sopenharmony_ci */
9177141cc406Sopenharmony_civoid
9178141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
9179141cc406Sopenharmony_ci{
9180141cc406Sopenharmony_ci  struct fujitsu * s = (struct fujitsu *) handle;
9181141cc406Sopenharmony_ci
9182141cc406Sopenharmony_ci  DBG (10, "sane_cancel: start\n");
9183141cc406Sopenharmony_ci  s->cancelled = 1;
9184141cc406Sopenharmony_ci
9185141cc406Sopenharmony_ci  /* if there is no other running function to check, we do it */
9186141cc406Sopenharmony_ci  if(!s->reading)
9187141cc406Sopenharmony_ci    check_for_cancel(s);
9188141cc406Sopenharmony_ci
9189141cc406Sopenharmony_ci  DBG (10, "sane_cancel: finish\n");
9190141cc406Sopenharmony_ci}
9191141cc406Sopenharmony_ci
9192141cc406Sopenharmony_ci/*
9193141cc406Sopenharmony_ci * Ends use of the scanner.
9194141cc406Sopenharmony_ci *
9195141cc406Sopenharmony_ci * From the SANE spec:
9196141cc406Sopenharmony_ci * This function terminates the association between the device handle
9197141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is
9198141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After
9199141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore.
9200141cc406Sopenharmony_ci */
9201141cc406Sopenharmony_civoid
9202141cc406Sopenharmony_cisane_close (SANE_Handle handle)
9203141cc406Sopenharmony_ci{
9204141cc406Sopenharmony_ci  struct fujitsu * s = (struct fujitsu *) handle;
9205141cc406Sopenharmony_ci
9206141cc406Sopenharmony_ci  DBG (10, "sane_close: start\n");
9207141cc406Sopenharmony_ci  /*clears any held scans*/
9208141cc406Sopenharmony_ci  mode_select_buff(s);
9209141cc406Sopenharmony_ci  disconnect_fd(s);
9210141cc406Sopenharmony_ci  DBG (10, "sane_close: finish\n");
9211141cc406Sopenharmony_ci}
9212141cc406Sopenharmony_ci
9213141cc406Sopenharmony_cistatic SANE_Status
9214141cc406Sopenharmony_cidisconnect_fd (struct fujitsu *s)
9215141cc406Sopenharmony_ci{
9216141cc406Sopenharmony_ci  DBG (10, "disconnect_fd: start\n");
9217141cc406Sopenharmony_ci
9218141cc406Sopenharmony_ci  if(s->fd > -1){
9219141cc406Sopenharmony_ci    if (s->connection == CONNECTION_USB) {
9220141cc406Sopenharmony_ci      DBG (15, "disconnecting usb device\n");
9221141cc406Sopenharmony_ci      sanei_usb_close (s->fd);
9222141cc406Sopenharmony_ci    }
9223141cc406Sopenharmony_ci    else if (s->connection == CONNECTION_SCSI) {
9224141cc406Sopenharmony_ci      DBG (15, "disconnecting scsi device\n");
9225141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
9226141cc406Sopenharmony_ci    }
9227141cc406Sopenharmony_ci    s->fd = -1;
9228141cc406Sopenharmony_ci  }
9229141cc406Sopenharmony_ci
9230141cc406Sopenharmony_ci  DBG (10, "disconnect_fd: finish\n");
9231141cc406Sopenharmony_ci
9232141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
9233141cc406Sopenharmony_ci}
9234141cc406Sopenharmony_ci
9235141cc406Sopenharmony_ci/*
9236141cc406Sopenharmony_ci * Terminates the backend.
9237141cc406Sopenharmony_ci *
9238141cc406Sopenharmony_ci * From the SANE spec:
9239141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The
9240141cc406Sopenharmony_ci * function will first close all device handles that still might be
9241141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through
9242141cc406Sopenharmony_ci * a call to sane_close(), but backends are required to release all
9243141cc406Sopenharmony_ci * resources upon a call to this function). After this function
9244141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called
9245141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting
9246141cc406Sopenharmony_ci * to call this function may result in some resources not being
9247141cc406Sopenharmony_ci * released properly.
9248141cc406Sopenharmony_ci */
9249141cc406Sopenharmony_civoid
9250141cc406Sopenharmony_cisane_exit (void)
9251141cc406Sopenharmony_ci{
9252141cc406Sopenharmony_ci  struct fujitsu *dev, *next;
9253141cc406Sopenharmony_ci
9254141cc406Sopenharmony_ci  DBG (10, "sane_exit: start\n");
9255141cc406Sopenharmony_ci
9256141cc406Sopenharmony_ci  for (dev = fujitsu_devList; dev; dev = next) {
9257141cc406Sopenharmony_ci      disconnect_fd(dev);
9258141cc406Sopenharmony_ci      next = dev->next;
9259141cc406Sopenharmony_ci      free (dev);
9260141cc406Sopenharmony_ci  }
9261141cc406Sopenharmony_ci
9262141cc406Sopenharmony_ci  if (sane_devArray)
9263141cc406Sopenharmony_ci    free (sane_devArray);
9264141cc406Sopenharmony_ci
9265141cc406Sopenharmony_ci  fujitsu_devList = NULL;
9266141cc406Sopenharmony_ci  sane_devArray = NULL;
9267141cc406Sopenharmony_ci
9268141cc406Sopenharmony_ci  DBG (10, "sane_exit: finish\n");
9269141cc406Sopenharmony_ci}
9270141cc406Sopenharmony_ci
9271141cc406Sopenharmony_ci/*
9272141cc406Sopenharmony_ci * @@ Section 6 - misc helper functions
9273141cc406Sopenharmony_ci */
9274141cc406Sopenharmony_ci/*
9275141cc406Sopenharmony_ci * Called by the SANE SCSI core and our usb code on device errors
9276141cc406Sopenharmony_ci * parses the request sense return data buffer,
9277141cc406Sopenharmony_ci * decides the best SANE_Status for the problem, produces debug msgs,
9278141cc406Sopenharmony_ci * and copies the sense buffer into the scanner struct
9279141cc406Sopenharmony_ci */
9280141cc406Sopenharmony_cistatic SANE_Status
9281141cc406Sopenharmony_cisense_handler (int fd, unsigned char * sensed_data, void *arg)
9282141cc406Sopenharmony_ci{
9283141cc406Sopenharmony_ci  struct fujitsu *s = arg;
9284141cc406Sopenharmony_ci  unsigned int sense = get_RS_sense_key (sensed_data);
9285141cc406Sopenharmony_ci  unsigned int asc = get_RS_ASC (sensed_data);
9286141cc406Sopenharmony_ci  unsigned int ascq = get_RS_ASCQ (sensed_data);
9287141cc406Sopenharmony_ci
9288141cc406Sopenharmony_ci  DBG (5, "sense_handler: start\n");
9289141cc406Sopenharmony_ci
9290141cc406Sopenharmony_ci  /* kill compiler warning */
9291141cc406Sopenharmony_ci  (void) fd;
9292141cc406Sopenharmony_ci
9293141cc406Sopenharmony_ci  /* copy the rs return data into the scanner struct
9294141cc406Sopenharmony_ci     so that the caller can use it if he wants */
9295141cc406Sopenharmony_ci  s->rs_info = get_RS_information (sensed_data);
9296141cc406Sopenharmony_ci  s->rs_eom = get_RS_EOM (sensed_data);
9297141cc406Sopenharmony_ci  s->rs_ili = get_RS_ILI (sensed_data);
9298141cc406Sopenharmony_ci
9299141cc406Sopenharmony_ci  DBG (5, "Sense=%#02x, ASC=%#02x, ASCQ=%#02x, EOM=%d, ILI=%d, info=%#08lx\n", sense, asc, ascq, s->rs_eom, s->rs_ili, (unsigned long)s->rs_info);
9300141cc406Sopenharmony_ci
9301141cc406Sopenharmony_ci  switch (sense) {
9302141cc406Sopenharmony_ci    case 0x0:
9303141cc406Sopenharmony_ci      if (0x80 == asc) {
9304141cc406Sopenharmony_ci        DBG  (5, "No sense: hardware status bits?\n");
9305141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
9306141cc406Sopenharmony_ci      }
9307141cc406Sopenharmony_ci      if (0x00 != asc) {
9308141cc406Sopenharmony_ci        DBG  (5, "No sense: unknown asc\n");
9309141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9310141cc406Sopenharmony_ci      }
9311141cc406Sopenharmony_ci      if (0x00 != ascq) {
9312141cc406Sopenharmony_ci        DBG  (5, "No sense: unknown ascq\n");
9313141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9314141cc406Sopenharmony_ci      }
9315141cc406Sopenharmony_ci      /* ready, but short read */
9316141cc406Sopenharmony_ci      if (s->rs_ili) {
9317141cc406Sopenharmony_ci        DBG  (5, "No sense: ILI remainder:%lu\n",(unsigned long)s->rs_info);
9318141cc406Sopenharmony_ci      }
9319141cc406Sopenharmony_ci      /* ready, but end of paper */
9320141cc406Sopenharmony_ci      if (s->rs_eom) {
9321141cc406Sopenharmony_ci        DBG  (5, "No sense: EOM\n");
9322141cc406Sopenharmony_ci        return SANE_STATUS_EOF;
9323141cc406Sopenharmony_ci      }
9324141cc406Sopenharmony_ci      DBG  (5, "No sense: ready\n");
9325141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
9326141cc406Sopenharmony_ci
9327141cc406Sopenharmony_ci    case 0x2:
9328141cc406Sopenharmony_ci      if (0x00 != asc) {
9329141cc406Sopenharmony_ci        DBG  (5, "Not ready: unknown asc\n");
9330141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9331141cc406Sopenharmony_ci      }
9332141cc406Sopenharmony_ci      if (0x00 != ascq) {
9333141cc406Sopenharmony_ci        DBG  (5, "Not ready: unknown ascq\n");
9334141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9335141cc406Sopenharmony_ci      }
9336141cc406Sopenharmony_ci      DBG  (5, "Not ready: busy\n");
9337141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
9338141cc406Sopenharmony_ci      break;
9339141cc406Sopenharmony_ci
9340141cc406Sopenharmony_ci    case 0x3:
9341141cc406Sopenharmony_ci      if (0x80 != asc) {
9342141cc406Sopenharmony_ci        DBG  (5, "Medium error: unknown asc\n");
9343141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9344141cc406Sopenharmony_ci      }
9345141cc406Sopenharmony_ci      if (0x01 == ascq) {
9346141cc406Sopenharmony_ci        DBG  (5, "Medium error: paper jam\n");
9347141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9348141cc406Sopenharmony_ci      }
9349141cc406Sopenharmony_ci      if (0x02 == ascq) {
9350141cc406Sopenharmony_ci        DBG  (5, "Medium error: cover open\n");
9351141cc406Sopenharmony_ci        return SANE_STATUS_COVER_OPEN;
9352141cc406Sopenharmony_ci      }
9353141cc406Sopenharmony_ci      if (0x03 == ascq) {
9354141cc406Sopenharmony_ci        DBG  (5, "Medium error: hopper empty\n");
9355141cc406Sopenharmony_ci        return SANE_STATUS_NO_DOCS;
9356141cc406Sopenharmony_ci      }
9357141cc406Sopenharmony_ci      if (0x04 == ascq) {
9358141cc406Sopenharmony_ci        DBG  (5, "Medium error: unusual paper\n");
9359141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9360141cc406Sopenharmony_ci      }
9361141cc406Sopenharmony_ci      if (0x07 == ascq) {
9362141cc406Sopenharmony_ci        DBG  (5, "Medium error: double feed\n");
9363141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9364141cc406Sopenharmony_ci      }
9365141cc406Sopenharmony_ci      if (0x08 == ascq) {
9366141cc406Sopenharmony_ci        DBG  (5, "Medium error: ADF setup error\n");
9367141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9368141cc406Sopenharmony_ci      }
9369141cc406Sopenharmony_ci      if (0x09 == ascq) {
9370141cc406Sopenharmony_ci        DBG  (5, "Medium error: Carrier sheet\n");
9371141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9372141cc406Sopenharmony_ci      }
9373141cc406Sopenharmony_ci      if (0x0c == ascq) {
9374141cc406Sopenharmony_ci        DBG  (5, "Medium error: ADF blocked by card\n");
9375141cc406Sopenharmony_ci        return SANE_STATUS_JAMMED;
9376141cc406Sopenharmony_ci      }
9377141cc406Sopenharmony_ci      if (0x10 == ascq) {
9378141cc406Sopenharmony_ci        DBG  (5, "Medium error: no ink cartridge\n");
9379141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9380141cc406Sopenharmony_ci      }
9381141cc406Sopenharmony_ci      if (0x13 == ascq) {
9382141cc406Sopenharmony_ci        DBG  (5, "Medium error: temporary no data\n");
9383141cc406Sopenharmony_ci        return SANE_STATUS_DEVICE_BUSY;
9384141cc406Sopenharmony_ci      }
9385141cc406Sopenharmony_ci      if (0x14 == ascq) {
9386141cc406Sopenharmony_ci        DBG  (5, "Medium error: endorser error\n");
9387141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9388141cc406Sopenharmony_ci      }
9389141cc406Sopenharmony_ci      if (0x20 == ascq) {
9390141cc406Sopenharmony_ci        DBG  (5, "Medium error: Stop button\n");
9391141cc406Sopenharmony_ci        return SANE_STATUS_NO_DOCS;
9392141cc406Sopenharmony_ci      }
9393141cc406Sopenharmony_ci      if (0x22 == ascq) {
9394141cc406Sopenharmony_ci        DBG  (5, "Medium error: scanning halted\n");
9395141cc406Sopenharmony_ci        return SANE_STATUS_CANCELLED;
9396141cc406Sopenharmony_ci      }
9397141cc406Sopenharmony_ci      if (0x30 == ascq) {
9398141cc406Sopenharmony_ci        DBG  (5, "Medium error: Not enough paper\n");
9399141cc406Sopenharmony_ci        return SANE_STATUS_NO_DOCS;
9400141cc406Sopenharmony_ci      }
9401141cc406Sopenharmony_ci      if (0x31 == ascq) {
9402141cc406Sopenharmony_ci        DBG  (5, "Medium error: scanning disabled\n");
9403141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9404141cc406Sopenharmony_ci      }
9405141cc406Sopenharmony_ci      if (0x32 == ascq) {
9406141cc406Sopenharmony_ci        DBG  (5, "Medium error: scanning paused\n");
9407141cc406Sopenharmony_ci        return SANE_STATUS_DEVICE_BUSY;
9408141cc406Sopenharmony_ci      }
9409141cc406Sopenharmony_ci      if (0x33 == ascq) {
9410141cc406Sopenharmony_ci        DBG  (5, "Medium error: WiFi control error\n");
9411141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9412141cc406Sopenharmony_ci      }
9413141cc406Sopenharmony_ci      DBG  (5, "Medium error: unknown ascq\n");
9414141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9415141cc406Sopenharmony_ci      break;
9416141cc406Sopenharmony_ci
9417141cc406Sopenharmony_ci    case 0x4:
9418141cc406Sopenharmony_ci      if (0x80 != asc && 0x44 != asc) {
9419141cc406Sopenharmony_ci        DBG  (5, "Hardware error: unknown asc\n");
9420141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9421141cc406Sopenharmony_ci      }
9422141cc406Sopenharmony_ci      if ((0x44 == asc) && (0x00 == ascq)) {
9423141cc406Sopenharmony_ci        DBG  (5, "Hardware error: EEPROM error\n");
9424141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9425141cc406Sopenharmony_ci      }
9426141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x01 == ascq)) {
9427141cc406Sopenharmony_ci        DBG  (5, "Hardware error: FB motor fuse\n");
9428141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9429141cc406Sopenharmony_ci      }
9430141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x02 == ascq)) {
9431141cc406Sopenharmony_ci        DBG  (5, "Hardware error: heater fuse\n");
9432141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9433141cc406Sopenharmony_ci      }
9434141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x03 == ascq)) {
9435141cc406Sopenharmony_ci        DBG  (5, "Hardware error: lamp fuse\n");
9436141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9437141cc406Sopenharmony_ci      }
9438141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x04 == ascq)) {
9439141cc406Sopenharmony_ci        DBG  (5, "Hardware error: ADF motor fuse\n");
9440141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9441141cc406Sopenharmony_ci      }
9442141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x05 == ascq)) {
9443141cc406Sopenharmony_ci        DBG  (5, "Hardware error: mechanical error\n");
9444141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9445141cc406Sopenharmony_ci      }
9446141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x06 == ascq)) {
9447141cc406Sopenharmony_ci        DBG  (5, "Hardware error: optical error\n");
9448141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9449141cc406Sopenharmony_ci      }
9450141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x07 == ascq)) {
9451141cc406Sopenharmony_ci        DBG  (5, "Hardware error: Fan error\n");
9452141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9453141cc406Sopenharmony_ci      }
9454141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x08 == ascq)) {
9455141cc406Sopenharmony_ci        DBG  (5, "Hardware error: IPC option error\n");
9456141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9457141cc406Sopenharmony_ci      }
9458141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x10 == ascq)) {
9459141cc406Sopenharmony_ci        DBG  (5, "Hardware error: endorser error\n");
9460141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9461141cc406Sopenharmony_ci      }
9462141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x11 == ascq)) {
9463141cc406Sopenharmony_ci        DBG  (5, "Hardware error: endorser fuse\n");
9464141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9465141cc406Sopenharmony_ci      }
9466141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x80 == ascq)) {
9467141cc406Sopenharmony_ci        DBG  (5, "Hardware error: interface board timeout\n");
9468141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9469141cc406Sopenharmony_ci      }
9470141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x81 == ascq)) {
9471141cc406Sopenharmony_ci        DBG  (5, "Hardware error: interface board error 1\n");
9472141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9473141cc406Sopenharmony_ci      }
9474141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x82 == ascq)) {
9475141cc406Sopenharmony_ci        DBG  (5, "Hardware error: interface board error 2\n");
9476141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9477141cc406Sopenharmony_ci      }
9478141cc406Sopenharmony_ci      DBG  (5, "Hardware error: unknown asc/ascq\n");
9479141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9480141cc406Sopenharmony_ci      break;
9481141cc406Sopenharmony_ci
9482141cc406Sopenharmony_ci    case 0x5:
9483141cc406Sopenharmony_ci      if ((0x00 == asc) && (0x00 == ascq)) {
9484141cc406Sopenharmony_ci        DBG  (5, "Illegal request: paper edge detected too soon\n");
9485141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9486141cc406Sopenharmony_ci      }
9487141cc406Sopenharmony_ci      if ((0x1a == asc) && (0x00 == ascq)) {
9488141cc406Sopenharmony_ci        DBG  (5, "Illegal request: Parameter list error\n");
9489141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9490141cc406Sopenharmony_ci      }
9491141cc406Sopenharmony_ci      if ((0x20 == asc) && (0x00 == ascq)) {
9492141cc406Sopenharmony_ci        DBG  (5, "Illegal request: invalid command\n");
9493141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9494141cc406Sopenharmony_ci      }
9495141cc406Sopenharmony_ci      if ((0x24 == asc) && (0x00 == ascq)) {
9496141cc406Sopenharmony_ci        DBG  (5, "Illegal request: invalid CDB field\n");
9497141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9498141cc406Sopenharmony_ci      }
9499141cc406Sopenharmony_ci      if ((0x25 == asc) && (0x00 == ascq)) {
9500141cc406Sopenharmony_ci        DBG  (5, "Illegal request: unsupported logical unit\n");
9501141cc406Sopenharmony_ci        return SANE_STATUS_UNSUPPORTED;
9502141cc406Sopenharmony_ci      }
9503141cc406Sopenharmony_ci      if ((0x26 == asc) && (0x00 == ascq)) {
9504141cc406Sopenharmony_ci        DBG  (5, "Illegal request: invalid field in parm list\n");
9505141cc406Sopenharmony_ci        if (get_RS_additional_length(sensed_data) >= 0x0a) {
9506141cc406Sopenharmony_ci          DBG (5, "Offending byte is %#02x\n", get_RS_offending_byte(sensed_data));
9507141cc406Sopenharmony_ci
9508141cc406Sopenharmony_ci          /* move this to set_window() ? */
9509141cc406Sopenharmony_ci          if (get_RS_offending_byte(sensed_data) >= 8) {
9510141cc406Sopenharmony_ci            DBG (5, "Window desc block? byte %#02x\n",get_RS_offending_byte(sensed_data)-8);
9511141cc406Sopenharmony_ci          }
9512141cc406Sopenharmony_ci        }
9513141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9514141cc406Sopenharmony_ci      }
9515141cc406Sopenharmony_ci      if ((0x2C == asc) && (0x00 == ascq)) {
9516141cc406Sopenharmony_ci        DBG  (5, "Illegal request: command sequence error\n");
9517141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9518141cc406Sopenharmony_ci      }
9519141cc406Sopenharmony_ci      if ((0x2C == asc) && (0x02 == ascq)) {
9520141cc406Sopenharmony_ci        DBG  (5, "Illegal request: wrong window combination \n");
9521141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
9522141cc406Sopenharmony_ci      }
9523141cc406Sopenharmony_ci      DBG  (5, "Illegal request: unknown asc/ascq\n");
9524141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9525141cc406Sopenharmony_ci      break;
9526141cc406Sopenharmony_ci
9527141cc406Sopenharmony_ci    case 0x6:
9528141cc406Sopenharmony_ci      if ((0x00 == asc) && (0x00 == ascq)) {
9529141cc406Sopenharmony_ci        DBG  (5, "Unit attention: device reset\n");
9530141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
9531141cc406Sopenharmony_ci      }
9532141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x01 == ascq)) {
9533141cc406Sopenharmony_ci        DBG  (5, "Unit attention: power saving\n");
9534141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
9535141cc406Sopenharmony_ci      }
9536141cc406Sopenharmony_ci      DBG  (5, "Unit attention: unknown asc/ascq\n");
9537141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9538141cc406Sopenharmony_ci      break;
9539141cc406Sopenharmony_ci
9540141cc406Sopenharmony_ci    case 0xb:
9541141cc406Sopenharmony_ci      if ((0x43 == asc) && (0x00 == ascq)) {
9542141cc406Sopenharmony_ci        DBG  (5, "Aborted command: message error\n");
9543141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9544141cc406Sopenharmony_ci      }
9545141cc406Sopenharmony_ci      if ((0x45 == asc) && (0x00 == ascq)) {
9546141cc406Sopenharmony_ci        DBG  (5, "Aborted command: select failure\n");
9547141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9548141cc406Sopenharmony_ci      }
9549141cc406Sopenharmony_ci      if ((0x47 == asc) && (0x00 == ascq)) {
9550141cc406Sopenharmony_ci        DBG  (5, "Aborted command: SCSI parity error\n");
9551141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9552141cc406Sopenharmony_ci      }
9553141cc406Sopenharmony_ci      if ((0x48 == asc) && (0x00 == ascq)) {
9554141cc406Sopenharmony_ci        DBG  (5, "Aborted command: initiator error message\n");
9555141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9556141cc406Sopenharmony_ci      }
9557141cc406Sopenharmony_ci      if ((0x4e == asc) && (0x00 == ascq)) {
9558141cc406Sopenharmony_ci        DBG  (5, "Aborted command: overlapped commands\n");
9559141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9560141cc406Sopenharmony_ci      }
9561141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x01 == ascq)) {
9562141cc406Sopenharmony_ci        DBG  (5, "Aborted command: image transfer error\n");
9563141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9564141cc406Sopenharmony_ci      }
9565141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x03 == ascq)) {
9566141cc406Sopenharmony_ci        DBG  (5, "Aborted command: JPEG overflow error\n");
9567141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
9568141cc406Sopenharmony_ci      }
9569141cc406Sopenharmony_ci      DBG  (5, "Aborted command: unknown asc/ascq\n");
9570141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9571141cc406Sopenharmony_ci      break;
9572141cc406Sopenharmony_ci
9573141cc406Sopenharmony_ci    default:
9574141cc406Sopenharmony_ci      DBG (5, "Unknown Sense Code\n");
9575141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
9576141cc406Sopenharmony_ci  }
9577141cc406Sopenharmony_ci
9578141cc406Sopenharmony_ci  DBG (5, "sense_handler: should never happen!\n");
9579141cc406Sopenharmony_ci
9580141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
9581141cc406Sopenharmony_ci}
9582141cc406Sopenharmony_ci
9583141cc406Sopenharmony_ci/*
9584141cc406Sopenharmony_ci * take a bunch of pointers, send commands to scanner
9585141cc406Sopenharmony_ci */
9586141cc406Sopenharmony_cistatic SANE_Status
9587141cc406Sopenharmony_cido_cmd(struct fujitsu *s, int runRS, int shortTime,
9588141cc406Sopenharmony_ci unsigned char * cmdBuff, size_t cmdLen,
9589141cc406Sopenharmony_ci unsigned char * outBuff, size_t outLen,
9590141cc406Sopenharmony_ci unsigned char * inBuff, size_t * inLen
9591141cc406Sopenharmony_ci)
9592141cc406Sopenharmony_ci{
9593141cc406Sopenharmony_ci
9594141cc406Sopenharmony_ci    /* unset the request sense vars first */
9595141cc406Sopenharmony_ci    s->rs_info = 0;
9596141cc406Sopenharmony_ci    s->rs_ili = 0;
9597141cc406Sopenharmony_ci    s->rs_eom = 0;
9598141cc406Sopenharmony_ci
9599141cc406Sopenharmony_ci    if (s->connection == CONNECTION_SCSI) {
9600141cc406Sopenharmony_ci        return do_scsi_cmd(s, runRS, shortTime,
9601141cc406Sopenharmony_ci                 cmdBuff, cmdLen,
9602141cc406Sopenharmony_ci                 outBuff, outLen,
9603141cc406Sopenharmony_ci                 inBuff, inLen
9604141cc406Sopenharmony_ci        );
9605141cc406Sopenharmony_ci    }
9606141cc406Sopenharmony_ci    if (s->connection == CONNECTION_USB) {
9607141cc406Sopenharmony_ci        return do_usb_cmd(s, runRS, shortTime,
9608141cc406Sopenharmony_ci                 cmdBuff, cmdLen,
9609141cc406Sopenharmony_ci                 outBuff, outLen,
9610141cc406Sopenharmony_ci                 inBuff, inLen
9611141cc406Sopenharmony_ci        );
9612141cc406Sopenharmony_ci    }
9613141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
9614141cc406Sopenharmony_ci}
9615141cc406Sopenharmony_ci
9616141cc406Sopenharmony_ciSANE_Status
9617141cc406Sopenharmony_cido_scsi_cmd(struct fujitsu *s, int runRS, int shortTime,
9618141cc406Sopenharmony_ci unsigned char * cmdBuff, size_t cmdLen,
9619141cc406Sopenharmony_ci unsigned char * outBuff, size_t outLen,
9620141cc406Sopenharmony_ci unsigned char * inBuff, size_t * inLen
9621141cc406Sopenharmony_ci)
9622141cc406Sopenharmony_ci{
9623141cc406Sopenharmony_ci  int ret;
9624141cc406Sopenharmony_ci
9625141cc406Sopenharmony_ci  /*shut up compiler*/
9626141cc406Sopenharmony_ci  (void) runRS;
9627141cc406Sopenharmony_ci  (void) shortTime;
9628141cc406Sopenharmony_ci
9629141cc406Sopenharmony_ci  DBG(10, "do_scsi_cmd: start\n");
9630141cc406Sopenharmony_ci
9631141cc406Sopenharmony_ci  DBG(25, "cmd: writing %d bytes\n", (int)cmdLen);
9632141cc406Sopenharmony_ci  hexdump(30, "cmd: >>", cmdBuff, cmdLen);
9633141cc406Sopenharmony_ci
9634141cc406Sopenharmony_ci  if(outBuff && outLen){
9635141cc406Sopenharmony_ci    DBG(25, "out: writing %d bytes\n", (int)outLen);
9636141cc406Sopenharmony_ci    hexdump(30, "out: >>", outBuff, outLen);
9637141cc406Sopenharmony_ci  }
9638141cc406Sopenharmony_ci  if (inBuff && inLen){
9639141cc406Sopenharmony_ci    DBG(25, "in: reading %d bytes\n", (int)*inLen);
9640141cc406Sopenharmony_ci    memset(inBuff,0,*inLen);
9641141cc406Sopenharmony_ci  }
9642141cc406Sopenharmony_ci
9643141cc406Sopenharmony_ci  ret = sanei_scsi_cmd2(s->fd, cmdBuff, cmdLen, outBuff, outLen, inBuff, inLen);
9644141cc406Sopenharmony_ci
9645141cc406Sopenharmony_ci  if(ret != SANE_STATUS_GOOD && ret != SANE_STATUS_EOF){
9646141cc406Sopenharmony_ci    DBG(5,"do_scsi_cmd: return '%s'\n",sane_strstatus(ret));
9647141cc406Sopenharmony_ci    return ret;
9648141cc406Sopenharmony_ci  }
9649141cc406Sopenharmony_ci
9650141cc406Sopenharmony_ci  /* FIXME: should we look at s->rs_info here? */
9651141cc406Sopenharmony_ci  if (inBuff && inLen){
9652141cc406Sopenharmony_ci    hexdump(30, "in: <<", inBuff, *inLen);
9653141cc406Sopenharmony_ci    DBG(25, "in: read %d bytes\n", (int)*inLen);
9654141cc406Sopenharmony_ci  }
9655141cc406Sopenharmony_ci
9656141cc406Sopenharmony_ci  DBG(10, "do_scsi_cmd: finish\n");
9657141cc406Sopenharmony_ci
9658141cc406Sopenharmony_ci  return ret;
9659141cc406Sopenharmony_ci}
9660141cc406Sopenharmony_ci
9661141cc406Sopenharmony_ciSANE_Status
9662141cc406Sopenharmony_cido_usb_cmd(struct fujitsu *s, int runRS, int shortTime,
9663141cc406Sopenharmony_ci unsigned char * cmdBuff, size_t cmdLen,
9664141cc406Sopenharmony_ci unsigned char * outBuff, size_t outLen,
9665141cc406Sopenharmony_ci unsigned char * inBuff, size_t * inLen
9666141cc406Sopenharmony_ci)
9667141cc406Sopenharmony_ci{
9668141cc406Sopenharmony_ci    /*sanei_usb overwrites the transfer size,
9669141cc406Sopenharmony_ci     * so make some local copies */
9670141cc406Sopenharmony_ci    size_t usb_cmdLen = USB_COMMAND_LEN;
9671141cc406Sopenharmony_ci    size_t usb_outLen = outLen;
9672141cc406Sopenharmony_ci    size_t usb_statLen = USB_STATUS_LEN;
9673141cc406Sopenharmony_ci    size_t askLen = 0;
9674141cc406Sopenharmony_ci
9675141cc406Sopenharmony_ci    /*copy the callers buffs into larger, padded ones*/
9676141cc406Sopenharmony_ci    unsigned char usb_cmdBuff[USB_COMMAND_LEN];
9677141cc406Sopenharmony_ci    unsigned char usb_statBuff[USB_STATUS_LEN];
9678141cc406Sopenharmony_ci
9679141cc406Sopenharmony_ci    int cmdTime = USB_COMMAND_TIME;
9680141cc406Sopenharmony_ci    int outTime = USB_DATA_TIME;
9681141cc406Sopenharmony_ci    int inTime = USB_DATA_TIME;
9682141cc406Sopenharmony_ci    int statTime = USB_STATUS_TIME;
9683141cc406Sopenharmony_ci
9684141cc406Sopenharmony_ci    int ret = 0;
9685141cc406Sopenharmony_ci    int ret2 = 0;
9686141cc406Sopenharmony_ci
9687141cc406Sopenharmony_ci    DBG (10, "do_usb_cmd: start\n");
9688141cc406Sopenharmony_ci
9689141cc406Sopenharmony_ci    if(shortTime){
9690141cc406Sopenharmony_ci        cmdTime = USB_COMMAND_TIME/60;
9691141cc406Sopenharmony_ci        outTime = USB_DATA_TIME/60;
9692141cc406Sopenharmony_ci        inTime = USB_DATA_TIME/60;
9693141cc406Sopenharmony_ci        statTime = USB_STATUS_TIME/60;
9694141cc406Sopenharmony_ci    }
9695141cc406Sopenharmony_ci
9696141cc406Sopenharmony_ci    /* build a USB packet around the SCSI command */
9697141cc406Sopenharmony_ci    memset(&usb_cmdBuff,0,USB_COMMAND_LEN);
9698141cc406Sopenharmony_ci    usb_cmdBuff[0] = USB_COMMAND_CODE;
9699141cc406Sopenharmony_ci    memcpy(&usb_cmdBuff[USB_COMMAND_OFFSET],cmdBuff,cmdLen);
9700141cc406Sopenharmony_ci
9701141cc406Sopenharmony_ci    /* change timeout */
9702141cc406Sopenharmony_ci    sanei_usb_set_timeout(cmdTime);
9703141cc406Sopenharmony_ci
9704141cc406Sopenharmony_ci    /* write the command out */
9705141cc406Sopenharmony_ci    DBG(25, "cmd: writing %d bytes, timeout %d\n", USB_COMMAND_LEN, cmdTime);
9706141cc406Sopenharmony_ci    hexdump(30, "cmd: >>", usb_cmdBuff, USB_COMMAND_LEN);
9707141cc406Sopenharmony_ci    ret = sanei_usb_write_bulk(s->fd, usb_cmdBuff, &usb_cmdLen);
9708141cc406Sopenharmony_ci    DBG(25, "cmd: wrote %d bytes, retVal %d\n", (int)usb_cmdLen, ret);
9709141cc406Sopenharmony_ci
9710141cc406Sopenharmony_ci    if(ret == SANE_STATUS_EOF){
9711141cc406Sopenharmony_ci        DBG(5,"cmd: got EOF, returning IO_ERROR\n");
9712141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9713141cc406Sopenharmony_ci    }
9714141cc406Sopenharmony_ci    if(ret != SANE_STATUS_GOOD){
9715141cc406Sopenharmony_ci        DBG(5,"cmd: return error '%s'\n",sane_strstatus(ret));
9716141cc406Sopenharmony_ci        return ret;
9717141cc406Sopenharmony_ci    }
9718141cc406Sopenharmony_ci    if(usb_cmdLen != USB_COMMAND_LEN){
9719141cc406Sopenharmony_ci        DBG(5,"cmd: wrong size %d/%d\n", USB_COMMAND_LEN, (int)usb_cmdLen);
9720141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9721141cc406Sopenharmony_ci    }
9722141cc406Sopenharmony_ci
9723141cc406Sopenharmony_ci    /* this command has a write component, and a place to get it */
9724141cc406Sopenharmony_ci    if(outBuff && outLen && outTime){
9725141cc406Sopenharmony_ci
9726141cc406Sopenharmony_ci        /* change timeout */
9727141cc406Sopenharmony_ci        sanei_usb_set_timeout(outTime);
9728141cc406Sopenharmony_ci
9729141cc406Sopenharmony_ci        DBG(25, "out: writing %d bytes, timeout %d\n", (int)outLen, outTime);
9730141cc406Sopenharmony_ci        hexdump(30, "out: >>", outBuff, outLen);
9731141cc406Sopenharmony_ci        ret = sanei_usb_write_bulk(s->fd, outBuff, &usb_outLen);
9732141cc406Sopenharmony_ci        DBG(25, "out: wrote %d bytes, retVal %d\n", (int)usb_outLen, ret);
9733141cc406Sopenharmony_ci
9734141cc406Sopenharmony_ci        if(ret == SANE_STATUS_EOF){
9735141cc406Sopenharmony_ci            DBG(5,"out: got EOF, returning IO_ERROR\n");
9736141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
9737141cc406Sopenharmony_ci        }
9738141cc406Sopenharmony_ci        if(ret != SANE_STATUS_GOOD){
9739141cc406Sopenharmony_ci            DBG(5,"out: return error '%s'\n",sane_strstatus(ret));
9740141cc406Sopenharmony_ci            return ret;
9741141cc406Sopenharmony_ci        }
9742141cc406Sopenharmony_ci        if(usb_outLen != outLen){
9743141cc406Sopenharmony_ci            DBG(5,"out: wrong size %d/%d\n", (int)outLen, (int)usb_outLen);
9744141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
9745141cc406Sopenharmony_ci        }
9746141cc406Sopenharmony_ci    }
9747141cc406Sopenharmony_ci
9748141cc406Sopenharmony_ci    /* this command has a read component, and a place to put it */
9749141cc406Sopenharmony_ci    if(inBuff && inLen && inTime){
9750141cc406Sopenharmony_ci
9751141cc406Sopenharmony_ci        askLen = *inLen;
9752141cc406Sopenharmony_ci        memset(inBuff,0,askLen);
9753141cc406Sopenharmony_ci
9754141cc406Sopenharmony_ci        /* change timeout */
9755141cc406Sopenharmony_ci        sanei_usb_set_timeout(inTime);
9756141cc406Sopenharmony_ci
9757141cc406Sopenharmony_ci        DBG(25, "in: reading %lu bytes, timeout %d\n",
9758141cc406Sopenharmony_ci          (unsigned long)askLen, inTime);
9759141cc406Sopenharmony_ci
9760141cc406Sopenharmony_ci        ret = sanei_usb_read_bulk(s->fd, inBuff, inLen);
9761141cc406Sopenharmony_ci        DBG(25, "in: retVal %d\n", ret);
9762141cc406Sopenharmony_ci
9763141cc406Sopenharmony_ci        if(ret == SANE_STATUS_EOF){
9764141cc406Sopenharmony_ci            DBG(5,"in: got EOF, continuing\n");
9765141cc406Sopenharmony_ci            ret = SANE_STATUS_GOOD;
9766141cc406Sopenharmony_ci        }
9767141cc406Sopenharmony_ci
9768141cc406Sopenharmony_ci        if(ret != SANE_STATUS_GOOD){
9769141cc406Sopenharmony_ci            DBG(5,"in: return error '%s'\n",sane_strstatus(ret));
9770141cc406Sopenharmony_ci            return ret;
9771141cc406Sopenharmony_ci        }
9772141cc406Sopenharmony_ci
9773141cc406Sopenharmony_ci        DBG(25, "in: read %lu bytes\n", (unsigned long)*inLen);
9774141cc406Sopenharmony_ci        if(*inLen){
9775141cc406Sopenharmony_ci            hexdump(31, "in: <<", inBuff, *inLen);
9776141cc406Sopenharmony_ci        }
9777141cc406Sopenharmony_ci
9778141cc406Sopenharmony_ci        if(*inLen && *inLen != askLen){
9779141cc406Sopenharmony_ci            ret = SANE_STATUS_EOF;
9780141cc406Sopenharmony_ci            DBG(5,"in: short read, %lu/%lu\n",
9781141cc406Sopenharmony_ci              (unsigned long)*inLen,(unsigned long)askLen);
9782141cc406Sopenharmony_ci        }
9783141cc406Sopenharmony_ci    }
9784141cc406Sopenharmony_ci
9785141cc406Sopenharmony_ci    /*gather the scsi status byte. use ret2 instead of ret for status*/
9786141cc406Sopenharmony_ci
9787141cc406Sopenharmony_ci    memset(&usb_statBuff,0,USB_STATUS_LEN);
9788141cc406Sopenharmony_ci
9789141cc406Sopenharmony_ci    /* change timeout */
9790141cc406Sopenharmony_ci    sanei_usb_set_timeout(statTime);
9791141cc406Sopenharmony_ci
9792141cc406Sopenharmony_ci    DBG(25, "stat: reading %d bytes, timeout %d\n", USB_STATUS_LEN, statTime);
9793141cc406Sopenharmony_ci    ret2 = sanei_usb_read_bulk(s->fd, usb_statBuff, &usb_statLen);
9794141cc406Sopenharmony_ci    hexdump(30, "stat: <<", usb_statBuff, usb_statLen);
9795141cc406Sopenharmony_ci    DBG(25, "stat: read %d bytes, retVal %d\n", (int)usb_statLen, ret2);
9796141cc406Sopenharmony_ci
9797141cc406Sopenharmony_ci    if(ret2 == SANE_STATUS_EOF){
9798141cc406Sopenharmony_ci        DBG(5,"stat: got EOF, returning IO_ERROR\n");
9799141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9800141cc406Sopenharmony_ci    }
9801141cc406Sopenharmony_ci    if(ret2 != SANE_STATUS_GOOD){
9802141cc406Sopenharmony_ci        DBG(5,"stat: return error '%s'\n",sane_strstatus(ret2));
9803141cc406Sopenharmony_ci        return ret2;
9804141cc406Sopenharmony_ci    }
9805141cc406Sopenharmony_ci    if(usb_statLen != USB_STATUS_LEN){
9806141cc406Sopenharmony_ci        DBG(5,"stat: wrong size %d/%d\n", USB_STATUS_LEN, (int)usb_statLen);
9807141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9808141cc406Sopenharmony_ci    }
9809141cc406Sopenharmony_ci
9810141cc406Sopenharmony_ci    /* busy status */
9811141cc406Sopenharmony_ci    if(usb_statBuff[USB_STATUS_OFFSET] == 8){
9812141cc406Sopenharmony_ci        DBG(25,"stat: busy\n");
9813141cc406Sopenharmony_ci        return SANE_STATUS_DEVICE_BUSY;
9814141cc406Sopenharmony_ci    }
9815141cc406Sopenharmony_ci
9816141cc406Sopenharmony_ci    /* if there is a non-busy status >0, try to figure out why */
9817141cc406Sopenharmony_ci    if(usb_statBuff[USB_STATUS_OFFSET] > 0){
9818141cc406Sopenharmony_ci      DBG(25,"stat: value %d\n", usb_statBuff[USB_STATUS_OFFSET]);
9819141cc406Sopenharmony_ci
9820141cc406Sopenharmony_ci      /* caller is interested in having RS run on errors */
9821141cc406Sopenharmony_ci      if(runRS){
9822141cc406Sopenharmony_ci        unsigned char rs_cmd[REQUEST_SENSE_len];
9823141cc406Sopenharmony_ci        size_t rs_cmdLen = REQUEST_SENSE_len;
9824141cc406Sopenharmony_ci
9825141cc406Sopenharmony_ci        unsigned char rs_in[RS_return_size];
9826141cc406Sopenharmony_ci        size_t rs_inLen = RS_return_size;
9827141cc406Sopenharmony_ci
9828141cc406Sopenharmony_ci        memset(rs_cmd,0,rs_cmdLen);
9829141cc406Sopenharmony_ci        set_SCSI_opcode(rs_cmd, REQUEST_SENSE_code);
9830141cc406Sopenharmony_ci	set_RS_return_size(rs_cmd, rs_inLen);
9831141cc406Sopenharmony_ci
9832141cc406Sopenharmony_ci        DBG(25,"rs sub call >>\n");
9833141cc406Sopenharmony_ci        ret2 = do_cmd(
9834141cc406Sopenharmony_ci          s,0,0,
9835141cc406Sopenharmony_ci          rs_cmd, rs_cmdLen,
9836141cc406Sopenharmony_ci          NULL,0,
9837141cc406Sopenharmony_ci          rs_in, &rs_inLen
9838141cc406Sopenharmony_ci        );
9839141cc406Sopenharmony_ci        DBG(25,"rs sub call <<\n");
9840141cc406Sopenharmony_ci
9841141cc406Sopenharmony_ci        if(ret2 == SANE_STATUS_EOF){
9842141cc406Sopenharmony_ci          DBG(5,"rs: got EOF, returning IO_ERROR\n");
9843141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
9844141cc406Sopenharmony_ci        }
9845141cc406Sopenharmony_ci        if(ret2 != SANE_STATUS_GOOD){
9846141cc406Sopenharmony_ci          DBG(5,"rs: return error '%s'\n",sane_strstatus(ret2));
9847141cc406Sopenharmony_ci          return ret2;
9848141cc406Sopenharmony_ci        }
9849141cc406Sopenharmony_ci
9850141cc406Sopenharmony_ci        /* parse the rs data */
9851141cc406Sopenharmony_ci        ret2 = sense_handler( 0, rs_in, (void *)s );
9852141cc406Sopenharmony_ci
9853141cc406Sopenharmony_ci        /* this was a short read, but the usb layer did not know */
9854141cc406Sopenharmony_ci        if(s->rs_ili && inBuff && inLen && inTime){
9855141cc406Sopenharmony_ci            *inLen = askLen - s->rs_info;
9856141cc406Sopenharmony_ci            DBG(5,"do_usb_cmd: short read via rs, %lu/%lu\n",
9857141cc406Sopenharmony_ci              (unsigned long)*inLen,(unsigned long)askLen);
9858141cc406Sopenharmony_ci        }
9859141cc406Sopenharmony_ci        return ret2;
9860141cc406Sopenharmony_ci      }
9861141cc406Sopenharmony_ci      else{
9862141cc406Sopenharmony_ci        DBG(5,"do_usb_cmd: Not calling rs!\n");
9863141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
9864141cc406Sopenharmony_ci      }
9865141cc406Sopenharmony_ci    }
9866141cc406Sopenharmony_ci
9867141cc406Sopenharmony_ci    DBG (10, "do_usb_cmd: finish\n");
9868141cc406Sopenharmony_ci
9869141cc406Sopenharmony_ci    return ret;
9870141cc406Sopenharmony_ci}
9871141cc406Sopenharmony_ci
9872141cc406Sopenharmony_cistatic SANE_Status
9873141cc406Sopenharmony_ciwait_scanner(struct fujitsu *s)
9874141cc406Sopenharmony_ci{
9875141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
9876141cc406Sopenharmony_ci
9877141cc406Sopenharmony_ci  unsigned char cmd[TEST_UNIT_READY_len];
9878141cc406Sopenharmony_ci  size_t cmdLen = TEST_UNIT_READY_len;
9879141cc406Sopenharmony_ci
9880141cc406Sopenharmony_ci  DBG (10, "wait_scanner: start\n");
9881141cc406Sopenharmony_ci
9882141cc406Sopenharmony_ci  memset(cmd,0,cmdLen);
9883141cc406Sopenharmony_ci  set_SCSI_opcode(cmd,TEST_UNIT_READY_code);
9884141cc406Sopenharmony_ci
9885141cc406Sopenharmony_ci  ret = do_cmd (
9886141cc406Sopenharmony_ci    s, 0, 1,
9887141cc406Sopenharmony_ci    cmd, cmdLen,
9888141cc406Sopenharmony_ci    NULL, 0,
9889141cc406Sopenharmony_ci    NULL, NULL
9890141cc406Sopenharmony_ci  );
9891141cc406Sopenharmony_ci
9892141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
9893141cc406Sopenharmony_ci    DBG(5,"WARNING: Brain-dead scanner. Hitting with stick\n");
9894141cc406Sopenharmony_ci    ret = do_cmd (
9895141cc406Sopenharmony_ci      s, 0, 1,
9896141cc406Sopenharmony_ci      cmd, cmdLen,
9897141cc406Sopenharmony_ci      NULL, 0,
9898141cc406Sopenharmony_ci      NULL, NULL
9899141cc406Sopenharmony_ci    );
9900141cc406Sopenharmony_ci  }
9901141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
9902141cc406Sopenharmony_ci    DBG(5,"WARNING: Brain-dead scanner. Hitting with stick again\n");
9903141cc406Sopenharmony_ci    ret = do_cmd (
9904141cc406Sopenharmony_ci      s, 0, 1,
9905141cc406Sopenharmony_ci      cmd, cmdLen,
9906141cc406Sopenharmony_ci      NULL, 0,
9907141cc406Sopenharmony_ci      NULL, NULL
9908141cc406Sopenharmony_ci    );
9909141cc406Sopenharmony_ci  }
9910141cc406Sopenharmony_ci
9911141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD) {
9912141cc406Sopenharmony_ci    DBG (5, "wait_scanner: error '%s'\n", sane_strstatus (ret));
9913141cc406Sopenharmony_ci  }
9914141cc406Sopenharmony_ci
9915141cc406Sopenharmony_ci  DBG (10, "wait_scanner: finish\n");
9916141cc406Sopenharmony_ci
9917141cc406Sopenharmony_ci  return ret;
9918141cc406Sopenharmony_ci}
9919141cc406Sopenharmony_ci
9920141cc406Sopenharmony_ci/* certain options require the entire image to
9921141cc406Sopenharmony_ci * be collected from the scanner before we can
9922141cc406Sopenharmony_ci * tell the user the size of the image. */
9923141cc406Sopenharmony_cistatic int
9924141cc406Sopenharmony_cimust_fully_buffer(struct fujitsu *s)
9925141cc406Sopenharmony_ci{
9926141cc406Sopenharmony_ci  if(s->hwdeskewcrop){
9927141cc406Sopenharmony_ci    return 1;
9928141cc406Sopenharmony_ci  }
9929141cc406Sopenharmony_ci
9930141cc406Sopenharmony_ci  if(
9931141cc406Sopenharmony_ci    (s->swdeskew || s->swdespeck || s->swcrop || s->swskip)
9932141cc406Sopenharmony_ci    && s->s_params.format != SANE_FRAME_JPEG
9933141cc406Sopenharmony_ci  ){
9934141cc406Sopenharmony_ci    return 1;
9935141cc406Sopenharmony_ci  }
9936141cc406Sopenharmony_ci
9937141cc406Sopenharmony_ci  return 0;
9938141cc406Sopenharmony_ci}
9939141cc406Sopenharmony_ci
9940141cc406Sopenharmony_ci/* certain scanners require the mode of the
9941141cc406Sopenharmony_ci * image to be changed in software. */
9942141cc406Sopenharmony_cistatic int
9943141cc406Sopenharmony_cimust_downsample(struct fujitsu *s)
9944141cc406Sopenharmony_ci{
9945141cc406Sopenharmony_ci  if(s->s_mode != s->u_mode
9946141cc406Sopenharmony_ci    && s->compress != COMP_JPEG
9947141cc406Sopenharmony_ci  ){
9948141cc406Sopenharmony_ci    return 1;
9949141cc406Sopenharmony_ci  }
9950141cc406Sopenharmony_ci
9951141cc406Sopenharmony_ci  return 0;
9952141cc406Sopenharmony_ci}
9953141cc406Sopenharmony_ci
9954141cc406Sopenharmony_ci/* s->page_width stores the user setting
9955141cc406Sopenharmony_ci * for the paper width in adf. sometimes,
9956141cc406Sopenharmony_ci * we need a value that differs from this
9957141cc406Sopenharmony_ci * due to using FB or overscan.
9958141cc406Sopenharmony_ci */
9959141cc406Sopenharmony_cistatic int
9960141cc406Sopenharmony_ciget_page_width(struct fujitsu *s)
9961141cc406Sopenharmony_ci{
9962141cc406Sopenharmony_ci  int width = s->page_width + 2 * (s->os_x_basic*1200/s->basic_x_res);
9963141cc406Sopenharmony_ci
9964141cc406Sopenharmony_ci  /* scanner max for fb */
9965141cc406Sopenharmony_ci  if(s->source == SOURCE_FLATBED){
9966141cc406Sopenharmony_ci      return s->max_x_fb;
9967141cc406Sopenharmony_ci  }
9968141cc406Sopenharmony_ci
9969141cc406Sopenharmony_ci  /* current paper size for adf not overscan */
9970141cc406Sopenharmony_ci  if(s->overscan != MSEL_ON){
9971141cc406Sopenharmony_ci      return s->page_width;
9972141cc406Sopenharmony_ci  }
9973141cc406Sopenharmony_ci
9974141cc406Sopenharmony_ci  /* can't overscan larger than scanner max */
9975141cc406Sopenharmony_ci  if(width > s->max_x){
9976141cc406Sopenharmony_ci      return s->max_x;
9977141cc406Sopenharmony_ci  }
9978141cc406Sopenharmony_ci
9979141cc406Sopenharmony_ci  /* overscan adds a margin to both sides */
9980141cc406Sopenharmony_ci  return width;
9981141cc406Sopenharmony_ci}
9982141cc406Sopenharmony_ci
9983141cc406Sopenharmony_ci/* s->page_height stores the user setting
9984141cc406Sopenharmony_ci * for the paper height in adf. sometimes,
9985141cc406Sopenharmony_ci * we need a value that differs from this
9986141cc406Sopenharmony_ci * due to using FB or overscan.
9987141cc406Sopenharmony_ci */
9988141cc406Sopenharmony_cistatic int
9989141cc406Sopenharmony_ciget_page_height(struct fujitsu *s)
9990141cc406Sopenharmony_ci{
9991141cc406Sopenharmony_ci  int height = s->page_height + 2 * (s->os_y_basic*1200/s->basic_y_res);
9992141cc406Sopenharmony_ci
9993141cc406Sopenharmony_ci  /* scanner max for fb */
9994141cc406Sopenharmony_ci  if(s->source == SOURCE_FLATBED){
9995141cc406Sopenharmony_ci      return s->max_y_fb;
9996141cc406Sopenharmony_ci  }
9997141cc406Sopenharmony_ci
9998141cc406Sopenharmony_ci  /* current paper size for adf not overscan */
9999141cc406Sopenharmony_ci  if(s->overscan != MSEL_ON){
10000141cc406Sopenharmony_ci      return s->page_height;
10001141cc406Sopenharmony_ci  }
10002141cc406Sopenharmony_ci
10003141cc406Sopenharmony_ci  /* can't overscan larger than scanner max */
10004141cc406Sopenharmony_ci  if(height > s->max_y){
10005141cc406Sopenharmony_ci      return s->max_y;
10006141cc406Sopenharmony_ci  }
10007141cc406Sopenharmony_ci
10008141cc406Sopenharmony_ci  /* overscan adds a margin to both sides */
10009141cc406Sopenharmony_ci  return height;
10010141cc406Sopenharmony_ci}
10011141cc406Sopenharmony_ci
10012141cc406Sopenharmony_ci/* scanners have two different possible IPC
10013141cc406Sopenharmony_ci * modes, which enable a different series of
10014141cc406Sopenharmony_ci * subordinate options. Rather than provide
10015141cc406Sopenharmony_ci * the user with an option to pick the IPC
10016141cc406Sopenharmony_ci * mode, we show them the subordinate ones,
10017141cc406Sopenharmony_ci * and pick the right mode to match.
10018141cc406Sopenharmony_ci */
10019141cc406Sopenharmony_cistatic int
10020141cc406Sopenharmony_ciget_ipc_mode(struct fujitsu *s)
10021141cc406Sopenharmony_ci{
10022141cc406Sopenharmony_ci  if ( s->bp_filter
10023141cc406Sopenharmony_ci    || s->smoothing
10024141cc406Sopenharmony_ci    || s->gamma_curve
10025141cc406Sopenharmony_ci    || s->threshold_curve
10026141cc406Sopenharmony_ci    || s->threshold_white
10027141cc406Sopenharmony_ci    || s->noise_removal
10028141cc406Sopenharmony_ci    || s->matrix_5
10029141cc406Sopenharmony_ci    || s->matrix_4
10030141cc406Sopenharmony_ci    || s->matrix_3
10031141cc406Sopenharmony_ci    || s->matrix_2
10032141cc406Sopenharmony_ci  )
10033141cc406Sopenharmony_ci    return WD_ipc_DTC;
10034141cc406Sopenharmony_ci
10035141cc406Sopenharmony_ci  if(s->variance)
10036141cc406Sopenharmony_ci    return WD_ipc_SDTC;
10037141cc406Sopenharmony_ci
10038141cc406Sopenharmony_ci  /* special case: 0 threshold should activate IPC */
10039141cc406Sopenharmony_ci  if(!s->threshold){
10040141cc406Sopenharmony_ci    if(s->has_sdtc)
10041141cc406Sopenharmony_ci      return WD_ipc_SDTC;
10042141cc406Sopenharmony_ci    if(s->has_dtc)
10043141cc406Sopenharmony_ci      return WD_ipc_DTC;
10044141cc406Sopenharmony_ci  }
10045141cc406Sopenharmony_ci
10046141cc406Sopenharmony_ci  return WD_ipc_DEFAULT;
10047141cc406Sopenharmony_ci}
10048141cc406Sopenharmony_ci
10049141cc406Sopenharmony_ci/* s->max_y gives the maximum height of paper which can be scanned
10050141cc406Sopenharmony_ci * this actually varies by resolution, so a helper to change it */
10051141cc406Sopenharmony_cistatic int
10052141cc406Sopenharmony_ciset_max_y(struct fujitsu *s)
10053141cc406Sopenharmony_ci{
10054141cc406Sopenharmony_ci  int i;
10055141cc406Sopenharmony_ci
10056141cc406Sopenharmony_ci  for(i=0;i<4;i++){
10057141cc406Sopenharmony_ci    if(!s->max_y_by_res[i].res)
10058141cc406Sopenharmony_ci      break;
10059141cc406Sopenharmony_ci    if(s->resolution_x <= s->max_y_by_res[i].res){
10060141cc406Sopenharmony_ci      s->max_y = s->max_y_by_res[i].len;
10061141cc406Sopenharmony_ci    }
10062141cc406Sopenharmony_ci  }
10063141cc406Sopenharmony_ci
10064141cc406Sopenharmony_ci  return s->max_y;
10065141cc406Sopenharmony_ci}
10066141cc406Sopenharmony_ci
10067141cc406Sopenharmony_ci/**
10068141cc406Sopenharmony_ci * Convenience method to determine longest string size in a list.
10069141cc406Sopenharmony_ci */
10070141cc406Sopenharmony_cistatic size_t
10071141cc406Sopenharmony_cimaxStringSize (const SANE_String_Const strings[])
10072141cc406Sopenharmony_ci{
10073141cc406Sopenharmony_ci  size_t size, max_size = 0;
10074141cc406Sopenharmony_ci  int i;
10075141cc406Sopenharmony_ci
10076141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i) {
10077141cc406Sopenharmony_ci    size = strlen (strings[i]) + 1;
10078141cc406Sopenharmony_ci    if (size > max_size)
10079141cc406Sopenharmony_ci      max_size = size;
10080141cc406Sopenharmony_ci  }
10081141cc406Sopenharmony_ci
10082141cc406Sopenharmony_ci  return max_size;
10083141cc406Sopenharmony_ci}
10084141cc406Sopenharmony_ci
10085141cc406Sopenharmony_ci/*
10086141cc406Sopenharmony_ci * Prints a hex dump of the given buffer onto the debug output stream.
10087141cc406Sopenharmony_ci */
10088141cc406Sopenharmony_cistatic void
10089141cc406Sopenharmony_cihexdump (int level, char *comment, unsigned char *p, int l)
10090141cc406Sopenharmony_ci{
10091141cc406Sopenharmony_ci  int i;
10092141cc406Sopenharmony_ci  char line[70]; /* 'xxx: xx xx ... xx xx abc */
10093141cc406Sopenharmony_ci  char *hex = line+4;
10094141cc406Sopenharmony_ci  char *bin = line+53;
10095141cc406Sopenharmony_ci
10096141cc406Sopenharmony_ci  if(DBG_LEVEL < level)
10097141cc406Sopenharmony_ci    return;
10098141cc406Sopenharmony_ci
10099141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
10100141cc406Sopenharmony_ci
10101141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++) {
10102141cc406Sopenharmony_ci
10103141cc406Sopenharmony_ci    /* at start of line */
10104141cc406Sopenharmony_ci    if ((i % 16) == 0) {
10105141cc406Sopenharmony_ci
10106141cc406Sopenharmony_ci      /* not at start of first line, print current, reset */
10107141cc406Sopenharmony_ci      if (i) {
10108141cc406Sopenharmony_ci        DBG (level, "%s\n", line);
10109141cc406Sopenharmony_ci      }
10110141cc406Sopenharmony_ci
10111141cc406Sopenharmony_ci      memset(line,0x20,69);
10112141cc406Sopenharmony_ci      line[69] = 0;
10113141cc406Sopenharmony_ci      hex = line + 4;
10114141cc406Sopenharmony_ci      bin = line + 53;
10115141cc406Sopenharmony_ci
10116141cc406Sopenharmony_ci      sprintf (line, "%3.3x:", i);
10117141cc406Sopenharmony_ci    }
10118141cc406Sopenharmony_ci
10119141cc406Sopenharmony_ci    /* the hex section */
10120141cc406Sopenharmony_ci    sprintf (hex, " %2.2x", *p);
10121141cc406Sopenharmony_ci    hex += 3;
10122141cc406Sopenharmony_ci    *hex = ' ';
10123141cc406Sopenharmony_ci
10124141cc406Sopenharmony_ci    /* the char section */
10125141cc406Sopenharmony_ci    if(*p >= 0x20 && *p <= 0x7e){
10126141cc406Sopenharmony_ci      *bin=*p;
10127141cc406Sopenharmony_ci    }
10128141cc406Sopenharmony_ci    else{
10129141cc406Sopenharmony_ci      *bin='.';
10130141cc406Sopenharmony_ci    }
10131141cc406Sopenharmony_ci    bin++;
10132141cc406Sopenharmony_ci  }
10133141cc406Sopenharmony_ci
10134141cc406Sopenharmony_ci  /* print last (partial) line */
10135141cc406Sopenharmony_ci  if (i)
10136141cc406Sopenharmony_ci    DBG (level, "%s\n", line);
10137141cc406Sopenharmony_ci}
10138141cc406Sopenharmony_ci
10139141cc406Sopenharmony_ci/**
10140141cc406Sopenharmony_ci * An advanced method we don't support but have to define.
10141141cc406Sopenharmony_ci */
10142141cc406Sopenharmony_ciSANE_Status
10143141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking)
10144141cc406Sopenharmony_ci{
10145141cc406Sopenharmony_ci  DBG (10, "sane_set_io_mode\n");
10146141cc406Sopenharmony_ci  DBG (15, "%d %p\n", non_blocking, h);
10147141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
10148141cc406Sopenharmony_ci}
10149141cc406Sopenharmony_ci
10150141cc406Sopenharmony_ci/**
10151141cc406Sopenharmony_ci * An advanced method we don't support but have to define.
10152141cc406Sopenharmony_ci */
10153141cc406Sopenharmony_ciSANE_Status
10154141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int *fdp)
10155141cc406Sopenharmony_ci{
10156141cc406Sopenharmony_ci  DBG (10, "sane_get_select_fd\n");
10157141cc406Sopenharmony_ci  DBG (15, "%p %d\n", h, *fdp);
10158141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
10159141cc406Sopenharmony_ci}
10160141cc406Sopenharmony_ci
10161141cc406Sopenharmony_ci/*
10162141cc406Sopenharmony_ci * @@ Section 7 - Image processing functions
10163141cc406Sopenharmony_ci */
10164141cc406Sopenharmony_ci
10165141cc406Sopenharmony_ci/* Look in image for likely upper and left paper edges, then rotate
10166141cc406Sopenharmony_ci * image so that upper left corner of paper is upper left of image.
10167141cc406Sopenharmony_ci * FIXME: should we do this before we binarize instead of after? */
10168141cc406Sopenharmony_cistatic SANE_Status
10169141cc406Sopenharmony_cibuffer_deskew(struct fujitsu *s, int side)
10170141cc406Sopenharmony_ci{
10171141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
10172141cc406Sopenharmony_ci
10173141cc406Sopenharmony_ci  int bg_color = 0xd6;
10174141cc406Sopenharmony_ci
10175141cc406Sopenharmony_ci  DBG (10, "buffer_deskew: start\n");
10176141cc406Sopenharmony_ci
10177141cc406Sopenharmony_ci  /*only find skew on first image from a page, or if first image had error */
10178141cc406Sopenharmony_ci  if(s->side == SIDE_FRONT
10179141cc406Sopenharmony_ci    || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
10180141cc406Sopenharmony_ci    || s->deskew_stat){
10181141cc406Sopenharmony_ci
10182141cc406Sopenharmony_ci    s->deskew_stat = sanei_magic_findSkew(
10183141cc406Sopenharmony_ci      &s->s_params,s->buffers[side],s->resolution_x,s->resolution_y,
10184141cc406Sopenharmony_ci      &s->deskew_vals[0],&s->deskew_vals[1],&s->deskew_slope);
10185141cc406Sopenharmony_ci
10186141cc406Sopenharmony_ci    if(s->deskew_stat){
10187141cc406Sopenharmony_ci      DBG (5, "buffer_deskew: bad findSkew, bailing\n");
10188141cc406Sopenharmony_ci      goto cleanup;
10189141cc406Sopenharmony_ci    }
10190141cc406Sopenharmony_ci  }
10191141cc406Sopenharmony_ci  /* backside images can use a 'flipped' version of frontside data */
10192141cc406Sopenharmony_ci  else{
10193141cc406Sopenharmony_ci    s->deskew_slope *= -1;
10194141cc406Sopenharmony_ci    s->deskew_vals[0] = s->s_params.pixels_per_line - s->deskew_vals[0];
10195141cc406Sopenharmony_ci  }
10196141cc406Sopenharmony_ci
10197141cc406Sopenharmony_ci  /* tweak the bg color based on scanner settings */
10198141cc406Sopenharmony_ci  if(s->s_mode == MODE_HALFTONE || s->s_mode == MODE_LINEART){
10199141cc406Sopenharmony_ci    if(s->bg_color == COLOR_BLACK || s->hwdeskewcrop || s->overscan)
10200141cc406Sopenharmony_ci      bg_color = 0xff;
10201141cc406Sopenharmony_ci    else
10202141cc406Sopenharmony_ci      bg_color = 0;
10203141cc406Sopenharmony_ci  }
10204141cc406Sopenharmony_ci  else if(s->bg_color == COLOR_BLACK || s->hwdeskewcrop || s->overscan)
10205141cc406Sopenharmony_ci    bg_color = 0;
10206141cc406Sopenharmony_ci
10207141cc406Sopenharmony_ci  ret = sanei_magic_rotate(&s->s_params,s->buffers[side],
10208141cc406Sopenharmony_ci    s->deskew_vals[0],s->deskew_vals[1],s->deskew_slope,bg_color);
10209141cc406Sopenharmony_ci
10210141cc406Sopenharmony_ci  if(ret){
10211141cc406Sopenharmony_ci    DBG(5,"buffer_deskew: rotate error: %d",ret);
10212141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
10213141cc406Sopenharmony_ci    goto cleanup;
10214141cc406Sopenharmony_ci  }
10215141cc406Sopenharmony_ci
10216141cc406Sopenharmony_ci  cleanup:
10217141cc406Sopenharmony_ci  DBG (10, "buffer_deskew: finish\n");
10218141cc406Sopenharmony_ci  return ret;
10219141cc406Sopenharmony_ci}
10220141cc406Sopenharmony_ci
10221141cc406Sopenharmony_ci/* Look in image for likely left/right/bottom paper edges, then crop image.
10222141cc406Sopenharmony_ci * Does not attempt to rotate the image, that should be done first.
10223141cc406Sopenharmony_ci * FIXME: should we do this before we binarize instead of after? */
10224141cc406Sopenharmony_cistatic SANE_Status
10225141cc406Sopenharmony_cibuffer_crop(struct fujitsu *s, int side)
10226141cc406Sopenharmony_ci{
10227141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
10228141cc406Sopenharmony_ci
10229141cc406Sopenharmony_ci  DBG (10, "buffer_crop: start\n");
10230141cc406Sopenharmony_ci
10231141cc406Sopenharmony_ci  ret = sanei_magic_findEdges(
10232141cc406Sopenharmony_ci    &s->s_params,s->buffers[side],s->resolution_x,s->resolution_y,
10233141cc406Sopenharmony_ci    &s->crop_vals[0],&s->crop_vals[1],&s->crop_vals[2],&s->crop_vals[3]);
10234141cc406Sopenharmony_ci
10235141cc406Sopenharmony_ci  if(ret){
10236141cc406Sopenharmony_ci    DBG (5, "buffer_crop: bad edges, bailing\n");
10237141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
10238141cc406Sopenharmony_ci    goto cleanup;
10239141cc406Sopenharmony_ci  }
10240141cc406Sopenharmony_ci
10241141cc406Sopenharmony_ci  DBG (15, "buffer_crop: t:%d b:%d l:%d r:%d\n",
10242141cc406Sopenharmony_ci    s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]);
10243141cc406Sopenharmony_ci
10244141cc406Sopenharmony_ci  /* if we will later binarize this image, make sure the width
10245141cc406Sopenharmony_ci   * is a multiple of 8 pixels, by adjusting the right side */
10246141cc406Sopenharmony_ci  if ( must_downsample(s) && s->u_mode < MODE_GRAYSCALE ){
10247141cc406Sopenharmony_ci    s->crop_vals[3] -= (s->crop_vals[3]-s->crop_vals[2]) % 8;
10248141cc406Sopenharmony_ci  }
10249141cc406Sopenharmony_ci
10250141cc406Sopenharmony_ci  /* now crop the image */
10251141cc406Sopenharmony_ci  ret = sanei_magic_crop(&s->s_params,s->buffers[side],
10252141cc406Sopenharmony_ci      s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]);
10253141cc406Sopenharmony_ci
10254141cc406Sopenharmony_ci  if(ret){
10255141cc406Sopenharmony_ci    DBG (5, "buffer_crop: bad crop, bailing\n");
10256141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
10257141cc406Sopenharmony_ci    goto cleanup;
10258141cc406Sopenharmony_ci  }
10259141cc406Sopenharmony_ci
10260141cc406Sopenharmony_ci  /* need to update user with new size */
10261141cc406Sopenharmony_ci  update_u_params(s);
10262141cc406Sopenharmony_ci
10263141cc406Sopenharmony_ci  /* update image size counter to new, smaller size */
10264141cc406Sopenharmony_ci  s->bytes_rx[side] = s->s_params.lines * s->s_params.bytes_per_line;
10265141cc406Sopenharmony_ci  s->buff_rx[side] = s->bytes_rx[side];
10266141cc406Sopenharmony_ci
10267141cc406Sopenharmony_ci  cleanup:
10268141cc406Sopenharmony_ci  DBG (10, "buffer_crop: finish\n");
10269141cc406Sopenharmony_ci  return ret;
10270141cc406Sopenharmony_ci}
10271141cc406Sopenharmony_ci
10272141cc406Sopenharmony_ci/* Look in image for disconnected 'spots' of the requested size.
10273141cc406Sopenharmony_ci * Replace the spots with the average color of the surrounding pixels.
10274141cc406Sopenharmony_ci * FIXME: should we do this before we binarize instead of after? */
10275141cc406Sopenharmony_cistatic SANE_Status
10276141cc406Sopenharmony_cibuffer_despeck(struct fujitsu *s, int side)
10277141cc406Sopenharmony_ci{
10278141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
10279141cc406Sopenharmony_ci
10280141cc406Sopenharmony_ci  DBG (10, "buffer_despeck: start\n");
10281141cc406Sopenharmony_ci
10282141cc406Sopenharmony_ci  ret = sanei_magic_despeck(&s->s_params,s->buffers[side],s->swdespeck);
10283141cc406Sopenharmony_ci  if(ret){
10284141cc406Sopenharmony_ci    DBG (5, "buffer_despeck: bad despeck, bailing\n");
10285141cc406Sopenharmony_ci    ret = SANE_STATUS_GOOD;
10286141cc406Sopenharmony_ci    goto cleanup;
10287141cc406Sopenharmony_ci  }
10288141cc406Sopenharmony_ci
10289141cc406Sopenharmony_ci  cleanup:
10290141cc406Sopenharmony_ci  DBG (10, "buffer_despeck: finish\n");
10291141cc406Sopenharmony_ci  return ret;
10292141cc406Sopenharmony_ci}
10293141cc406Sopenharmony_ci
10294141cc406Sopenharmony_ci/* Look if image has too few dark pixels.*/
10295141cc406Sopenharmony_cistatic int
10296141cc406Sopenharmony_cibuffer_isblank(struct fujitsu *s, int side)
10297141cc406Sopenharmony_ci{
10298141cc406Sopenharmony_ci  SANE_Status ret = SANE_STATUS_GOOD;
10299141cc406Sopenharmony_ci  int status = 0;
10300141cc406Sopenharmony_ci
10301141cc406Sopenharmony_ci  DBG (10, "buffer_isblank: start\n");
10302141cc406Sopenharmony_ci
10303141cc406Sopenharmony_ci  ret = sanei_magic_isBlank2(&s->s_params, s->buffers[side],
10304141cc406Sopenharmony_ci    s->resolution_x, s->resolution_y, s->swskip);
10305141cc406Sopenharmony_ci
10306141cc406Sopenharmony_ci  if(ret == SANE_STATUS_NO_DOCS){
10307141cc406Sopenharmony_ci    DBG (5, "buffer_isblank: blank!\n");
10308141cc406Sopenharmony_ci    status = 1;
10309141cc406Sopenharmony_ci  }
10310141cc406Sopenharmony_ci  else if(ret){
10311141cc406Sopenharmony_ci    DBG (5, "buffer_isblank: error %d\n",ret);
10312141cc406Sopenharmony_ci  }
10313141cc406Sopenharmony_ci
10314141cc406Sopenharmony_ci  DBG (10, "buffer_isblank: finished\n");
10315141cc406Sopenharmony_ci  return status;
10316141cc406Sopenharmony_ci}
10317