1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci   epson.c - SANE library for Epson flatbed scanners.
3141cc406Sopenharmony_ci
4141cc406Sopenharmony_ci   Based on Kazuhiro Sasayama previous
5141cc406Sopenharmony_ci   Work on epson.[ch] file from the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   Original code taken from sane-0.71
8141cc406Sopenharmony_ci   Copyright (C) 1997 Hypercore Software Design, Ltd.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   modifications
11141cc406Sopenharmony_ci   Copyright (C) 1998-1999 Christian Bucher <bucher@vernetzt.at>
12141cc406Sopenharmony_ci   Copyright (C) 1998-1999 Kling & Hautzinger GmbH
13141cc406Sopenharmony_ci   Copyright (C) 1999 Norihiko Sawa <sawa@yb3.so-net.ne.jp>
14141cc406Sopenharmony_ci   Copyright (C) 2000 Mike Porter <mike@udel.edu> (mjp)
15141cc406Sopenharmony_ci   Copyright (C) 2003 EPSON KOWA Corporation
16141cc406Sopenharmony_ci   Copyright (C) 1999-2005 Karl Heinz Kremer <khk@khk.net>
17141cc406Sopenharmony_ci   Copyright (C) 2006 Claus Boje <claus@egehuset.dk>
18141cc406Sopenharmony_ci*/
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci#define SANE_EPSON_VERSION      "SANE Epson Backend v0.2.47 - 2006-08-21"
21141cc406Sopenharmony_ci#define SANE_EPSON_BUILD        247
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci/*
24141cc406Sopenharmony_ci   This file is part of the SANE package.
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
27141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
28141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
29141cc406Sopenharmony_ci   License, or (at your option) any later version.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
32141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
33141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
34141cc406Sopenharmony_ci   General Public License for more details.
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
37141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
40141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
43141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
44141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
45141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
46141cc406Sopenharmony_ci   account of linking the SANE library code into it.
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
49141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
50141cc406Sopenharmony_ci   License.
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
53141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
54141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
57141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
58141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.  */
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci/*
61141cc406Sopenharmony_ci         2006-08-21   Fix buffer overflow error (submitted by Johannes Meixner)
62141cc406Sopenharmony_ci   2006-06-11   Applied patch from Henning. Fixed a number of compiler warnings
63141cc406Sopenharmony_ci   2006-03-12   Added support for perfetion 4990 photo 4800 dpi
64141cc406Sopenharmony_ci   2005-01-09   "flaming hack to get USB scanners working without timeouts under linux"
65141cc406Sopenharmony_ci                submitted by "Steve" (in comment to bug #300830)
66141cc406Sopenharmony_ci   2004-12-18   Added USB IDs for CX-4600 and CX-3650
67141cc406Sopenharmony_ci   2004-10-16   Added USB ID for Expression 10000XL
68141cc406Sopenharmony_ci   2004-05-08   Disable feed() for Perfection1640
69141cc406Sopenharmony_ci   2004-02-08   Reformat all source code with "indent -bli0"
70141cc406Sopenharmony_ci   2004-02-01   Added D7 function level as copy of D1 for CX-6400
71141cc406Sopenharmony_ci                Added IDs for CX-6400 and Perfection 4870
72141cc406Sopenharmony_ci   2003-10-27   Replaced DBG(0, ... with DBG(1, ...
73141cc406Sopenharmony_ci   2003-09-12   Increment only once in loop to find USB scanners
74141cc406Sopenharmony_ci                Fix rounding problem when determining number of lines to scan
75141cc406Sopenharmony_ci   2003-08-21   Removed '//' comments - again ...
76141cc406Sopenharmony_ci                Added EPSON Kowa copyright message
77141cc406Sopenharmony_ci   2003-08-15   Added support for GT-30000, with support for the ADF in simplex mode
78141cc406Sopenharmony_ci                Borrowed some code from the EPSON Kowa IScan version of the backend
79141cc406Sopenharmony_ci                Use sanei_scsi_cmd2() to send commands. This makes this backend
80141cc406Sopenharmony_ci                useable for SBP-2 under FreeBSD
81141cc406Sopenharmony_ci   2003-05-11   Initialize OPT_LIMIT_RESOLUTION before first call to filter_resolution_list()
82141cc406Sopenharmony_ci                Fix memory problem in get_identity_information(). Both problems were
83141cc406Sopenharmony_ci                reported to the Debian bug database.
84141cc406Sopenharmony_ci   2003-03-26   Fixed two warnings reported by der Mouse
85141cc406Sopenharmony_ci   2003-02-16   Code cleanup, use more descriptive variable names.
86141cc406Sopenharmony_ci   2003-02-15   Move sanei_usb_init() to sane_init(). Thanks to Ron Cemer
87141cc406Sopenharmony_ci                                for providing the patch.
88141cc406Sopenharmony_ci   2003-02-15   Fix problem with "usb <vendor> <product> syntax in config file
89141cc406Sopenharmony_ci   2002-12-28   Added advanced option to display only short resolution list for
90141cc406Sopenharmony_ci                displays that can not show the complete list.
91141cc406Sopenharmony_ci   2002-11-23   Fixed problem with dropout color.
92141cc406Sopenharmony_ci   2002-11-03   Full libusb support.
93141cc406Sopenharmony_ci   2002-10-05   Fixed problem with incorrect response to sane_get_parameters()
94141cc406Sopenharmony_ci                in certain situations.
95141cc406Sopenharmony_ci   2002-09-01   USB scanners are now using libsane-usb functions
96141cc406Sopenharmony_ci   2002-08-17   Fixed typo in variable name.
97141cc406Sopenharmony_ci                Fixed IEEE-1394 problem with Perfection-2450.
98141cc406Sopenharmony_ci                Fixed problem with older B3 level SCSI scanners that do
99141cc406Sopenharmony_ci                not support the extended status request.
100141cc406Sopenharmony_ci   2002-04-22   Declare close_scanner() and open_scanner() before they
101141cc406Sopenharmony_ci                are used.
102141cc406Sopenharmony_ci   2002-04-13   Check if scanner needs to be opened for the reset call.
103141cc406Sopenharmony_ci                (Thanks to Thomas Wenrich for pointing this out)
104141cc406Sopenharmony_ci                Added product IDs for Perfection 1650 and 2450
105141cc406Sopenharmony_ci   2002-01-18   Recognize GT-xxxx type scanners also when using the SCSI
106141cc406Sopenharmony_ci                or IEEE-1394 interface
107141cc406Sopenharmony_ci   2002-01-06   Disable TEST_IOCTL again, which was enabled by accident. Also
108141cc406Sopenharmony_ci                protect the ioctl portion with an #ifdef __linux__
109141cc406Sopenharmony_ci   2002-01-05   Version 0.2.17
110141cc406Sopenharmony_ci                Check for and set s->fd to -1 when device is closed.
111141cc406Sopenharmony_ci                Removed black gamma table - only use RGB even for grayscale
112141cc406Sopenharmony_ci   2002-01-01   Do not call access() for OS/2 systems
113141cc406Sopenharmony_ci   2001-11-13   Version 0.2.16
114141cc406Sopenharmony_ci                Do not call access() for parallel port scanners.
115141cc406Sopenharmony_ci   2001-11-11   Version 0.2.15
116141cc406Sopenharmony_ci                Fixed "wait-for-button" functionality, accidentally merged back wrong
117141cc406Sopenharmony_ci                version after code freeze.
118141cc406Sopenharmony_ci                Corrected "need-strange-reorder" recognition.
119141cc406Sopenharmony_ci                Added IOCTL support to header file.
120141cc406Sopenharmony_ci   2001-11-10   Version 0.2.14
121141cc406Sopenharmony_ci                Added "wait-for-button" functionality
122141cc406Sopenharmony_ci   2001-10-30   I18N patches (Stefan Roellin)
123141cc406Sopenharmony_ci   2001-10-28   Fixed bug with 1650 recognition
124141cc406Sopenharmony_ci   2001-06-09   Version 0.2.09
125141cc406Sopenharmony_ci                Changed debug level for sense handler from 0 to 2
126141cc406Sopenharmony_ci   2001-05-25   Version 0.2.07
127141cc406Sopenharmony_ci                Allow more than 8 bit color depth even for preview mode
128141cc406Sopenharmony_ci                since Xsane can handle this. Some code cleanup.
129141cc406Sopenharmony_ci   2001-05-24   Removed ancient code that was used to determine the resolution
130141cc406Sopenharmony_ci                back when the backend still had a slider for the resolution
131141cc406Sopenharmony_ci                selection.
132141cc406Sopenharmony_ci   2001-05-22   Version 0.2.06
133141cc406Sopenharmony_ci                Added sense_handler to support the GT-8000 scanner. Thanks to Matthias Trute
134141cc406Sopenharmony_ci                for figuring out the details.
135141cc406Sopenharmony_ci                Also added experimental code to use USB scanner probing. Need kernel patch
136141cc406Sopenharmony_ci                for this.
137141cc406Sopenharmony_ci   2001-05-19   Version 0.2.05
138141cc406Sopenharmony_ci                fixed the year in the recent change log entries - I now that it's
139141cc406Sopenharmony_ci                2001...
140141cc406Sopenharmony_ci                Finally fixed the TPU problem with B4 level scanners
141141cc406Sopenharmony_ci   2001-05-13   Version 0.2.04
142141cc406Sopenharmony_ci                Removed check for '\n' before end of line
143141cc406Sopenharmony_ci                Free memory malloced in sane_get_devices() in sane_exit() again
144141cc406Sopenharmony_ci   2001-04-22   Version 0.2.03
145141cc406Sopenharmony_ci                Check first if the scanner does support the set film type
146141cc406Sopenharmony_ci                and set focus position before the GUI elements are displayed.
147141cc406Sopenharmony_ci                This caused problems with older (B4 level) scanners when a TPU
148141cc406Sopenharmony_ci                was connected.
149141cc406Sopenharmony_ci   2001-03-31   Version 0.2.02
150141cc406Sopenharmony_ci   2001-03-17   Next attempt to get the reported number of lines correct
151141cc406Sopenharmony_ci                for the "color shuffling" part.
152141cc406Sopenharmony_ci                Added more comments.
153141cc406Sopenharmony_ci   2000-12-25   Version 0.2.01
154141cc406Sopenharmony_ci                Fixed problem with bilevel scanning with Perfection610: The
155141cc406Sopenharmony_ci                line count has to be an even number with this scanner.
156141cc406Sopenharmony_ci                Several initialization fixes regarding bit depth selection.
157141cc406Sopenharmony_ci                This version goes back into the CVS repository, the 1.0.4
158141cc406Sopenharmony_ci                release is out and therefore the code freeze is over.
159141cc406Sopenharmony_ci                Some general cleanup, added more comments.
160141cc406Sopenharmony_ci   2000-12-09   Version 0.2.00
161141cc406Sopenharmony_ci                Cleaned up printing of gamma table data. 16 elements
162141cc406Sopenharmony_ci                are now printed in one line without the [epson] in
163141cc406Sopenharmony_ci                between the values. Values are only printed for
164141cc406Sopenharmony_ci                Debug levels >= 10.
165141cc406Sopenharmony_ci   2000-12-04   We've introduced the concept of inverting images
166141cc406Sopenharmony_ci                when scanning from a TPU.  This is fine, but
167141cc406Sopenharmony_ci                the user supplied gamma tables no longer work.
168141cc406Sopenharmony_ci                This is because the data a frontend is going
169141cc406Sopenharmony_ci                to compute a gamma table for is not what the
170141cc406Sopenharmony_ci                scanner actually sent.  So, we have to back into
171141cc406Sopenharmony_ci                the proper gamma table.  I think this works.  See
172141cc406Sopenharmony_ci                set_gamma_table.  (mjp)
173141cc406Sopenharmony_ci   2000-12-03   added the 12/14/16 bit support again.
174141cc406Sopenharmony_ci   2000-12-03   Version 0.1.38
175141cc406Sopenharmony_ci                removed changes regarding 12/14 bit support because
176141cc406Sopenharmony_ci                of SANE feature freeze for 1.0.4. The D1 fix for
177141cc406Sopenharmony_ci                reading the values from the scanner instead of using
178141cc406Sopenharmony_ci                hardcoded values and the fix for the off-by-one error
179141cc406Sopenharmony_ci                in the reorder routine are still in the code base.
180141cc406Sopenharmony_ci                Also force reload after change of scan mode.
181141cc406Sopenharmony_ci                The full backend can be downloaded from my web site at
182141cc406Sopenharmony_ci                http://www.freecolormanagement.com/sane
183141cc406Sopenharmony_ci   2000-12-03   Fixed off-by-one error in color reordering function.
184141cc406Sopenharmony_ci   2000-12-02   Read information about optical resolution and line
185141cc406Sopenharmony_ci                distance from scanner instead of hardcoded values.
186141cc406Sopenharmony_ci                Add support for color depth > 8 bits per channel.
187141cc406Sopenharmony_ci   2000-11-23   Display "Set Focus" control only for scanners that
188141cc406Sopenharmony_ci                can actually handle the command.
189141cc406Sopenharmony_ci   2000-11-19   Added support for the "set focus position" command,
190141cc406Sopenharmony_ci                this is necessary for the Expression1600.
191141cc406Sopenharmony_ci   2000-07-28   Changed #include <...> to #include "..." for the
192141cc406Sopenharmony_ci                sane/... include files.
193141cc406Sopenharmony_ci   2000-07-26   Fixed problem with Perfection610: The variable
194141cc406Sopenharmony_ci                s->color_shuffle_line was never correctly initialized
195141cc406Sopenharmony_ci   2000-06-28   When closing the scanner device the data that's
196141cc406Sopenharmony_ci                still in the scanner, waiting to be transferred
197141cc406Sopenharmony_ci                is flushed. This fixes the problem with scanimage -T
198141cc406Sopenharmony_ci   2000-06-13   Invert image when scanning negative with TPU,
199141cc406Sopenharmony_ci                Show film type only when TPU is selected
200141cc406Sopenharmony_ci   2000-06-13   Initialize optical_res to 0 (Dave Hill)
201141cc406Sopenharmony_ci   2000-06-07   Fix in sane_close() - found by Henning Meier-Geinitz
202141cc406Sopenharmony_ci   2000-06-01   Threshold should only be active when scan depth
203141cc406Sopenharmony_ci                is 1 and halftoning is off.  (mjp)
204141cc406Sopenharmony_ci   2000-05-28   Turned on scanner based color correction.
205141cc406Sopenharmony_ci                Dependencies between many options are now
206141cc406Sopenharmony_ci                being enforced.  For instance, auto area seg
207141cc406Sopenharmony_ci                (AAS) should only be on when scan depth == 1.
208141cc406Sopenharmony_ci                Added some routines to active and deactivate
209141cc406Sopenharmony_ci                options.  Routines report if option changed.
210141cc406Sopenharmony_ci                Help prevent extraneous option reloads.  Split
211141cc406Sopenharmony_ci                sane_control_option in getvalue and setvalue.
212141cc406Sopenharmony_ci                Further split up setvalue into several different
213141cc406Sopenharmony_ci                routines. (mjp)
214141cc406Sopenharmony_ci   2000-05-21   In sane_close use close_scanner instead of just the
215141cc406Sopenharmony_ci                SCSI close function.
216141cc406Sopenharmony_ci   2000-05-20   ... finally fixed the problem with the 610
217141cc406Sopenharmony_ci                Added resolution_list to Epson_Device structure in
218141cc406Sopenharmony_ci                epson.h - this fixes a bug that caused problems when
219141cc406Sopenharmony_ci                more than one EPSON scanner was connected.
220141cc406Sopenharmony_ci   2000-05-13   Fixed the color problem with the Perfection 610. The few
221141cc406Sopenharmony_ci                lines with "garbage" at the beginning of the scan are not
222141cc406Sopenharmony_ci                yet removed.
223141cc406Sopenharmony_ci   2000-05-06   Added support for multiple EPSON scanners. At this time
224141cc406Sopenharmony_ci                this may not be bug free, but it's a start and it seems
225141cc406Sopenharmony_ci                to work well with just one scanner.
226141cc406Sopenharmony_ci   2000-04-06   Did some cleanup on the gamma correction part. The user
227141cc406Sopenharmony_ci                defined table is now initialized to gamma=1, the gamma
228141cc406Sopenharmony_ci                handling is also no longer depending on platform specific
229141cc406Sopenharmony_ci                tables (handled instead by pointers to the actual tables)
230141cc406Sopenharmony_ci   2000-03-27   Disable request for push button status
231141cc406Sopenharmony_ci   2000-03-22   Removed free() calls to static strings to remove
232141cc406Sopenharmony_ci                compile warnings. These were introduced to apparently
233141cc406Sopenharmony_ci                fix an OS/2 bug. It now turned out that they are not
234141cc406Sopenharmony_ci                necessary. The real fix was in the repository for a
235141cc406Sopenharmony_ci                long time (2000-01-25).
236141cc406Sopenharmony_ci   2000-03-19   Fixed problem with A4 level devices - they use the
237141cc406Sopenharmony_ci                line mode instead of the block mode. The routine to
238141cc406Sopenharmony_ci                handle this was screwed up pretty bad. Now I have
239141cc406Sopenharmony_ci                a solid version that handles all variations of line
240141cc406Sopenharmony_ci                mode (automatically deals with the order the color
241141cc406Sopenharmony_ci                lines are sent).
242141cc406Sopenharmony_ci   2000-03-06   Fixed occasional crash after warm up when the "in warmup
243141cc406Sopenharmony_ci                state" went away in between doing ESC G and getting the
244141cc406Sopenharmony_ci                extended status message.
245141cc406Sopenharmony_ci   2000-03-02   Code cleanup, disabled ZOOM until I have time to
246141cc406Sopenharmony_ci                deal with all the side effects.
247141cc406Sopenharmony_ci   2000-03-01   More D1 fixes. In the future I have to come up with
248141cc406Sopenharmony_ci                a more elegant solution to distinguish between different
249141cc406Sopenharmony_ci                function levels. The level > n does not work anymore with
250141cc406Sopenharmony_ci                D1.
251141cc406Sopenharmony_ci                Added support for "set threshold" and "set zoom".
252141cc406Sopenharmony_ci   2000-02-23   First stab at level D1 support, also added a test
253141cc406Sopenharmony_ci                for valid "set halftone" command to enable OPT_HALFTONE
254141cc406Sopenharmony_ci   2000-02-21   Check for "warming up" in after sane_start. This is
255141cc406Sopenharmony_ci                IMHO a horrible hack, but that's the only way without
256141cc406Sopenharmony_ci                a major redesign that will work. (KHK)
257141cc406Sopenharmony_ci   2000-02-20   Added some cleanup on error conditions in attach()
258141cc406Sopenharmony_ci                Use new sanei_config_read() instead of fgets() for
259141cc406Sopenharmony_ci                compatibility with OS/2 (Yuri Dario)
260141cc406Sopenharmony_ci   2000-02-19   Changed some "int" to "size_t" types
261141cc406Sopenharmony_ci                Removed "Preview Resolution"
262141cc406Sopenharmony_ci                Implemented resolution list as WORD_LIST instead of
263141cc406Sopenharmony_ci                a RANGE (KHK)
264141cc406Sopenharmony_ci   2000-02-11   Default scan source is always "Flatbed", regardless
265141cc406Sopenharmony_ci                of installed options. Corrected some typos. (KHK)
266141cc406Sopenharmony_ci   2000-02-03   Gamma curves now coupled with gamma correction menu.
267141cc406Sopenharmony_ci                Only when "User defined" is selected are the curves
268141cc406Sopenharmony_ci                selected. (Dave Hill)
269141cc406Sopenharmony_ci                Renamed "Contrast" to "Gamma Correction" (KHK)
270141cc406Sopenharmony_ci   2000-02-02   "Brown Paper Bag Release" Put the USB fix finally
271141cc406Sopenharmony_ci                into the CVS repository.
272141cc406Sopenharmony_ci   2000-02-01   Fixed problem with USB scanner not being recognized
273141cc406Sopenharmony_ci                because of the changes to attach a few days ago. (KHK)
274141cc406Sopenharmony_ci   2000-01-29   fixed core dump with xscanimage by moving the gamma
275141cc406Sopenharmony_ci                curves to the standard interface (no longer advanced)
276141cc406Sopenharmony_ci                Removed pragma pack() from source code to make it
277141cc406Sopenharmony_ci                easier to compile on non-gcc compilers (KHK)
278141cc406Sopenharmony_ci   2000-01-26   fixed problem with resolution selection when using the
279141cc406Sopenharmony_ci                resolution list in xsane (KHK)
280141cc406Sopenharmony_ci   2000-01-25   moved the section where the device name is assigned
281141cc406Sopenharmony_ci                in attach. This avoids the core dump of frontend
282141cc406Sopenharmony_ci                applications when no scanner is found (Dave Hill)
283141cc406Sopenharmony_ci   2000-01-24   reorganization of SCSI related "helper" functions
284141cc406Sopenharmony_ci                started support for user defined color correction -
285141cc406Sopenharmony_ci                this is not yet available via the UI (Christian Bucher)
286141cc406Sopenharmony_ci   2000-01-24   Removed C++ style comments '//' (KHK)
287141cc406Sopenharmony_ci*/
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci/* #define TEST_IOCTL */
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci/* DON'T CHANGE THE NEXT LINE ! */
293141cc406Sopenharmony_ci/* #undef FORCE_COLOR_SHUFFLE */
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci#ifdef  _AIX
297141cc406Sopenharmony_ci#include  <lalloca.h>           /* MUST come first for AIX! */
298141cc406Sopenharmony_ci#endif
299141cc406Sopenharmony_ci
300141cc406Sopenharmony_ci/* --------------------- SANE INTERNATIONALISATION ------------------ */
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci#ifndef SANE_I18N
303141cc406Sopenharmony_ci#define SANE_I18N(text) (text)
304141cc406Sopenharmony_ci#endif
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci#include "../include/sane/config.h"
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci#include  <lalloca.h>
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci#include  <limits.h>
311141cc406Sopenharmony_ci#include  <stdio.h>
312141cc406Sopenharmony_ci#include  <string.h>
313141cc406Sopenharmony_ci#include  <stdlib.h>
314141cc406Sopenharmony_ci#include  <ctype.h>
315141cc406Sopenharmony_ci#include  <fcntl.h>
316141cc406Sopenharmony_ci#include  <unistd.h>
317141cc406Sopenharmony_ci#include  <errno.h>
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci#include "../include/sane/sane.h"
320141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
321141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci#include "../include/sane/sanei_pio.h"
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci#define  BACKEND_NAME epson
328141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci#include  "epson.h"
333141cc406Sopenharmony_ci#include  "epson_scsi.h"
334141cc406Sopenharmony_ci#include  "epson_usb.h"
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci#define  EPSON_CONFIG_FILE      "epson.conf"
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci#ifndef  PATH_MAX
339141cc406Sopenharmony_ci#define  PATH_MAX       (1024)
340141cc406Sopenharmony_ci#endif
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci#define  walloc(x)      (x *)malloc(sizeof(x))
343141cc406Sopenharmony_ci#define  walloca(x)     (x *)alloca(sizeof(x))
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci#ifndef  XtNumber
346141cc406Sopenharmony_ci#define  XtNumber(x)  ( sizeof(x)/ sizeof(x[0]) )
347141cc406Sopenharmony_ci#define  XtOffset(p_type,field)  ((size_t)&(((p_type)NULL)->field))
348141cc406Sopenharmony_ci#define  XtOffsetOf(s_type,field)  XtOffset(s_type*,field)
349141cc406Sopenharmony_ci#endif
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci#define NUM_OF_HEX_ELEMENTS (16)        /* number of hex numbers per line for data dump */
352141cc406Sopenharmony_ci#define DEVICE_NAME_LEN (16)    /* length of device name in extended status */
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci/* NOTE: you can find these codes with "man ascii". */
355141cc406Sopenharmony_ci#define  STX    0x02
356141cc406Sopenharmony_ci#define  ACK    0x06
357141cc406Sopenharmony_ci#define  NAK    0x15
358141cc406Sopenharmony_ci#define  CAN    0x18
359141cc406Sopenharmony_ci#define  ESC    0x1B
360141cc406Sopenharmony_ci#define  PF     0x19
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci#define  S_ACK  "\006"
363141cc406Sopenharmony_ci#define  S_CAN  "\030"
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci#define  STATUS_FER             0x80    /* fatal error */
366141cc406Sopenharmony_ci#define  STATUS_AREA_END        0x20    /* area end */
367141cc406Sopenharmony_ci#define  STATUS_OPTION          0x10    /* option installed */
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci#define  EXT_STATUS_FER         0x80    /* fatal error */
370141cc406Sopenharmony_ci#define  EXT_STATUS_FBF         0x40    /* flat bed scanner */
371141cc406Sopenharmony_ci#define  EXT_STATUS_WU          0x02    /* warming up */
372141cc406Sopenharmony_ci#define  EXT_STATUS_PB          0x01    /* scanner has a push button */
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci#define  EXT_STATUS_IST         0x80    /* option detected */
375141cc406Sopenharmony_ci#define  EXT_STATUS_EN          0x40    /* option enabled */
376141cc406Sopenharmony_ci#define  EXT_STATUS_ERR         0x20    /* other error */
377141cc406Sopenharmony_ci#define  EXT_STATUS_PE          0x08    /* no paper */
378141cc406Sopenharmony_ci#define  EXT_STATUS_PJ          0x04    /* paper jam */
379141cc406Sopenharmony_ci#define  EXT_STATUS_OPN         0x02    /* cover open */
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci#define  EPSON_LEVEL_A1          0
382141cc406Sopenharmony_ci#define  EPSON_LEVEL_A2          1
383141cc406Sopenharmony_ci#define  EPSON_LEVEL_B1          2
384141cc406Sopenharmony_ci#define  EPSON_LEVEL_B2          3
385141cc406Sopenharmony_ci#define  EPSON_LEVEL_B3          4
386141cc406Sopenharmony_ci#define  EPSON_LEVEL_B4          5
387141cc406Sopenharmony_ci#define  EPSON_LEVEL_B5          6
388141cc406Sopenharmony_ci#define  EPSON_LEVEL_B6          7
389141cc406Sopenharmony_ci#define  EPSON_LEVEL_B7          8
390141cc406Sopenharmony_ci#define  EPSON_LEVEL_B8          9
391141cc406Sopenharmony_ci#define  EPSON_LEVEL_F5         10
392141cc406Sopenharmony_ci#define  EPSON_LEVEL_D1         11
393141cc406Sopenharmony_ci#define  EPSON_LEVEL_D7         12
394141cc406Sopenharmony_ci#define  EPSON_LEVEL_D8         13
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci/* there is also a function level "A5", which I'm ignoring here until somebody can
397141cc406Sopenharmony_ci   convince me that this is still needed. The A5 level was for the GT-300, which
398141cc406Sopenharmony_ci   was (is) a monochrome only scanner. So if somebody really wants to use this
399141cc406Sopenharmony_ci   scanner with SANE get in touch with me and we can work something out - khk */
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci#define  EPSON_LEVEL_DEFAULT    EPSON_LEVEL_B3
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_cistatic EpsonCmdRec epson_cmd[] = {
404141cc406Sopenharmony_ci/*
405141cc406Sopenharmony_ci *        request identity
406141cc406Sopenharmony_ci *        |   request identity2
407141cc406Sopenharmony_ci *        |   |   request status
408141cc406Sopenharmony_ci *        |   |   |   request condition
409141cc406Sopenharmony_ci *        |   |   |   |   set color mode
410141cc406Sopenharmony_ci *        |   |   |   |   |   start scanning
411141cc406Sopenharmony_ci *        |   |   |   |   |   |   set data format
412141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   set resolution
413141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   set zoom
414141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   set scan area
415141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   set brightness
416141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             set gamma
417141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   set halftoning
418141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   set color correction
419141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   initialize scanner
420141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   set speed
421141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   set lcount
422141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   mirror image
423141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   set gamma table
424141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   set outline emphasis
425141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   set dither
426141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   set color correction coefficients
427141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   request extension status
428141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   control an extension
429141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    forward feed / eject
430141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   feed
431141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     request push button status
432141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   control auto area segmentation
433141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   set film type
434141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   set exposure time
435141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   set bay
436141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   |   set threshold
437141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   |   |   set focus position
438141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   |   |   |   request focus position
439141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   |   |   |   |
440141cc406Sopenharmony_ci *        |   |   |   |   |   |   |   |   |   |   |             |   |   |   |   |   |   |   |   |   |   |   |   |    |   |     |   |   |   |   |   |   |   |
441141cc406Sopenharmony_ci */
442141cc406Sopenharmony_ci  {"A1", 'I', 0, 'F','S', 0, 'G', 0, 'R', 0, 'A', 0, {0,0,0},   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
443141cc406Sopenharmony_ci  {"A2", 'I', 0, 'F','S', 0, 'G','D','R','H','A','L',{-3,3,0}, 'Z','B', 0, '@', 0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
444141cc406Sopenharmony_ci  {"B1", 'I', 0, 'F','S','C','G','D','R', 0, 'A', 0, {0,0,0},   0, 'B', 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
445141cc406Sopenharmony_ci  {"B2", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z','B', 0, '@', 0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
446141cc406Sopenharmony_ci  {"B3", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z','B','M','@', 0,  0,  0,  0,  0,  0, 'm','f','e',  0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
447141cc406Sopenharmony_ci  {"B4", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z','B','M','@','g','d', 0, 'z','Q','b','m','f','e',  0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
448141cc406Sopenharmony_ci  {"B5", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z','B','M','@','g','d','K','z','Q','b','m','f','e',  0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
449141cc406Sopenharmony_ci  {"B6", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z','B','M','@','g','d','K','z','Q','b','m','f','e',  0,  0,    0,  0,  0,  0,  0,  0,  0,  0},
450141cc406Sopenharmony_ci  {"B7", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-4,3,0}, 'Z','B','M','@','g','d','K','z','Q','b','m','f','e','\f', 0,   '!','s','N', 0,  0, 't', 0,  0},
451141cc406Sopenharmony_ci  {"B8", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-4,3,0}, 'Z','B','M','@','g','d','K','z','Q','b','m','f','e','\f', 0x19,'!','s','N', 0,  0,  0, 'p','q'},
452141cc406Sopenharmony_ci  {"F5", 'I', 0, 'F','S','C','G','D','R','H','A','L',{-3,3,0}, 'Z', 0, 'M','@','g','d','K','z','Q', 0, 'm','f','e','\f', 0,    0,  0, 'N','T','P', 0,  0,  0},
453141cc406Sopenharmony_ci  {"D1", 'I','i','F', 0, 'C','G','D','R', 0, 'A', 0, {0,0,0},  'Z', 0,  0, '@','g','d', 0, 'z', 0,  0,  0, 'f', 0,   0,  0,   '!', 0,  0,  0,  0,  0,  0,  0},
454141cc406Sopenharmony_ci  {"D7", 'I', 0, 'F', 0, 'C','G','D','R', 0, 'A', 0, {0,0,0},  'Z', 0,  0, '@','g','d', 0, 'z', 0,  0,  0, 'f', 0,   0,  0,   '!', 0,  0,  0,  0,  0,  0,  0},
455141cc406Sopenharmony_ci  {"D8", 'I','i','F', 0, 'C','G','D','R', 0, 'A', 0, {0,0,0},  'Z', 0,  0, '@','g','d', 0, 'z', 0,  0,  0, 'f','e',  0,  0,   '!', 0,  0,  0,  0,  0,  0,  0},
456141cc406Sopenharmony_ci};
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci/*
461141cc406Sopenharmony_ci * Definition of the mode_param struct, that is used to
462141cc406Sopenharmony_ci * specify the valid parameters for the different scan modes.
463141cc406Sopenharmony_ci *
464141cc406Sopenharmony_ci * The depth variable gets updated when the bit depth is modified.
465141cc406Sopenharmony_ci */
466141cc406Sopenharmony_ci
467141cc406Sopenharmony_cistruct mode_param
468141cc406Sopenharmony_ci{
469141cc406Sopenharmony_ci  int color;
470141cc406Sopenharmony_ci  int mode_flags;
471141cc406Sopenharmony_ci  int dropout_mask;
472141cc406Sopenharmony_ci  int depth;
473141cc406Sopenharmony_ci};
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_cistatic struct mode_param mode_params[] = {
476141cc406Sopenharmony_ci  {0, 0x00, 0x30, 1},
477141cc406Sopenharmony_ci  {0, 0x00, 0x30, 8},
478141cc406Sopenharmony_ci  {1, 0x02, 0x00, 8}
479141cc406Sopenharmony_ci};
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] = {
482141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
483141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
484141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
485141cc406Sopenharmony_ci  NULL
486141cc406Sopenharmony_ci};
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_cistatic const SANE_String_Const adf_mode_list[] = {
489141cc406Sopenharmony_ci  SANE_I18N ("Simplex"),
490141cc406Sopenharmony_ci  SANE_I18N ("Duplex"),
491141cc406Sopenharmony_ci  NULL
492141cc406Sopenharmony_ci};
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci/*
496141cc406Sopenharmony_ci * Define the different scan sources:
497141cc406Sopenharmony_ci */
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci#define  FBF_STR        SANE_I18N("Flatbed")
500141cc406Sopenharmony_ci#define  TPU_STR        SANE_I18N("Transparency Unit")
501141cc406Sopenharmony_ci#define  ADF_STR        SANE_I18N("Automatic Document Feeder")
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci/*
504141cc406Sopenharmony_ci * source list need one dummy entry (save device settings is crashing).
505141cc406Sopenharmony_ci * NOTE: no const - this list gets created while exploring the capabilities
506141cc406Sopenharmony_ci * of the scanner.
507141cc406Sopenharmony_ci */
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_cistatic SANE_String_Const source_list[] = {
510141cc406Sopenharmony_ci  FBF_STR,
511141cc406Sopenharmony_ci  NULL,
512141cc406Sopenharmony_ci  NULL,
513141cc406Sopenharmony_ci  NULL
514141cc406Sopenharmony_ci};
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci/* some defines to make handling the TPU easier: */
517141cc406Sopenharmony_ci#define FILM_TYPE_POSITIVE      (0)
518141cc406Sopenharmony_ci#define FILM_TYPE_NEGATIVE      (1)
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_cistatic const SANE_String_Const film_list[] = {
521141cc406Sopenharmony_ci  SANE_I18N ("Positive Film"),
522141cc406Sopenharmony_ci  SANE_I18N ("Negative Film"),
523141cc406Sopenharmony_ci  NULL
524141cc406Sopenharmony_ci};
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_cistatic const SANE_String_Const focus_list[] = {
527141cc406Sopenharmony_ci  SANE_I18N ("Focus on glass"),
528141cc406Sopenharmony_ci  SANE_I18N ("Focus 2.5mm above glass"),
529141cc406Sopenharmony_ci  NULL
530141cc406Sopenharmony_ci};
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci/*
533141cc406Sopenharmony_ci * TODO: add some missing const.
534141cc406Sopenharmony_ci */
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci#define HALFTONE_NONE 0x01
537141cc406Sopenharmony_ci#define HALFTONE_TET 0x03
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_cistatic int halftone_params[] = {
540141cc406Sopenharmony_ci  HALFTONE_NONE,
541141cc406Sopenharmony_ci  0x00,
542141cc406Sopenharmony_ci  0x10,
543141cc406Sopenharmony_ci  0x20,
544141cc406Sopenharmony_ci  0x80,
545141cc406Sopenharmony_ci  0x90,
546141cc406Sopenharmony_ci  0xa0,
547141cc406Sopenharmony_ci  0xb0,
548141cc406Sopenharmony_ci  HALFTONE_TET,
549141cc406Sopenharmony_ci  0xc0,
550141cc406Sopenharmony_ci  0xd0
551141cc406Sopenharmony_ci};
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list[] = {
554141cc406Sopenharmony_ci  SANE_I18N ("None"),
555141cc406Sopenharmony_ci  SANE_I18N ("Halftone A (Hard Tone)"),
556141cc406Sopenharmony_ci  SANE_I18N ("Halftone B (Soft Tone)"),
557141cc406Sopenharmony_ci  SANE_I18N ("Halftone C (Net Screen)"),
558141cc406Sopenharmony_ci  NULL
559141cc406Sopenharmony_ci};
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list_4[] = {
562141cc406Sopenharmony_ci  SANE_I18N ("None"),
563141cc406Sopenharmony_ci  SANE_I18N ("Halftone A (Hard Tone)"),
564141cc406Sopenharmony_ci  SANE_I18N ("Halftone B (Soft Tone)"),
565141cc406Sopenharmony_ci  SANE_I18N ("Halftone C (Net Screen)"),
566141cc406Sopenharmony_ci  SANE_I18N ("Dither A (4x4 Bayer)"),
567141cc406Sopenharmony_ci  SANE_I18N ("Dither B (4x4 Spiral)"),
568141cc406Sopenharmony_ci  SANE_I18N ("Dither C (4x4 Net Screen)"),
569141cc406Sopenharmony_ci  SANE_I18N ("Dither D (8x4 Net Screen)"),
570141cc406Sopenharmony_ci  NULL
571141cc406Sopenharmony_ci};
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list_7[] = {
574141cc406Sopenharmony_ci  SANE_I18N ("None"),
575141cc406Sopenharmony_ci  SANE_I18N ("Halftone A (Hard Tone)"),
576141cc406Sopenharmony_ci  SANE_I18N ("Halftone B (Soft Tone)"),
577141cc406Sopenharmony_ci  SANE_I18N ("Halftone C (Net Screen)"),
578141cc406Sopenharmony_ci  SANE_I18N ("Dither A (4x4 Bayer)"),
579141cc406Sopenharmony_ci  SANE_I18N ("Dither B (4x4 Spiral)"),
580141cc406Sopenharmony_ci  SANE_I18N ("Dither C (4x4 Net Screen)"),
581141cc406Sopenharmony_ci  SANE_I18N ("Dither D (8x4 Net Screen)"),
582141cc406Sopenharmony_ci  SANE_I18N ("Text Enhanced Technology"),
583141cc406Sopenharmony_ci  SANE_I18N ("Download pattern A"),
584141cc406Sopenharmony_ci  SANE_I18N ("Download pattern B"),
585141cc406Sopenharmony_ci  NULL
586141cc406Sopenharmony_ci};
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_cistatic int dropout_params[] = {
589141cc406Sopenharmony_ci  0x00, /* none */
590141cc406Sopenharmony_ci  0x10, /* red */
591141cc406Sopenharmony_ci  0x20, /* green */
592141cc406Sopenharmony_ci  0x30  /* blue */
593141cc406Sopenharmony_ci};
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_cistatic const SANE_String_Const dropout_list[] = {
596141cc406Sopenharmony_ci  SANE_I18N ("None"),
597141cc406Sopenharmony_ci  SANE_I18N ("Red"),
598141cc406Sopenharmony_ci  SANE_I18N ("Green"),
599141cc406Sopenharmony_ci  SANE_I18N ("Blue"),
600141cc406Sopenharmony_ci  NULL
601141cc406Sopenharmony_ci};
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci/*
604141cc406Sopenharmony_ci * Color correction:
605141cc406Sopenharmony_ci * One array for the actual parameters that get sent to the scanner (color_params[]),
606141cc406Sopenharmony_ci * one array for the strings that get displayed in the user interface (color_list[])
607141cc406Sopenharmony_ci * and one array to mark the user defined color correction (dolor_userdefined[]).
608141cc406Sopenharmony_ci */
609141cc406Sopenharmony_ci
610141cc406Sopenharmony_cistatic int color_params[] = {
611141cc406Sopenharmony_ci  0x00,
612141cc406Sopenharmony_ci  0x01,
613141cc406Sopenharmony_ci  0x10,
614141cc406Sopenharmony_ci  0x20,
615141cc406Sopenharmony_ci  0x40,
616141cc406Sopenharmony_ci  0x80
617141cc406Sopenharmony_ci};
618141cc406Sopenharmony_ci
619141cc406Sopenharmony_cistatic SANE_Bool color_userdefined[] = {
620141cc406Sopenharmony_ci  SANE_FALSE,
621141cc406Sopenharmony_ci  SANE_TRUE,
622141cc406Sopenharmony_ci  SANE_FALSE,
623141cc406Sopenharmony_ci  SANE_FALSE,
624141cc406Sopenharmony_ci  SANE_FALSE,
625141cc406Sopenharmony_ci  SANE_FALSE
626141cc406Sopenharmony_ci};
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_cistatic const SANE_String_Const color_list[] = {
629141cc406Sopenharmony_ci  SANE_I18N ("No Correction"),
630141cc406Sopenharmony_ci  SANE_I18N ("User defined"),
631141cc406Sopenharmony_ci  SANE_I18N ("Impact-dot printers"),
632141cc406Sopenharmony_ci  SANE_I18N ("Thermal printers"),
633141cc406Sopenharmony_ci  SANE_I18N ("Ink-jet printers"),
634141cc406Sopenharmony_ci  SANE_I18N ("CRT monitors"),
635141cc406Sopenharmony_ci  NULL
636141cc406Sopenharmony_ci};
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci/*
639141cc406Sopenharmony_ci * Gamma correction:
640141cc406Sopenharmony_ci * The A and B level scanners work differently than the D level scanners, therefore
641141cc406Sopenharmony_ci * I define two different sets of arrays, plus one set of variables that get set to
642141cc406Sopenharmony_ci * the actually used params and list arrays at runtime.
643141cc406Sopenharmony_ci */
644141cc406Sopenharmony_ci
645141cc406Sopenharmony_cistatic int gamma_params_ab[] = {
646141cc406Sopenharmony_ci  0x01,
647141cc406Sopenharmony_ci  0x03,
648141cc406Sopenharmony_ci  0x00,
649141cc406Sopenharmony_ci  0x10,
650141cc406Sopenharmony_ci  0x20
651141cc406Sopenharmony_ci};
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_cistatic const SANE_String_Const gamma_list_ab[] = {
654141cc406Sopenharmony_ci  SANE_I18N ("Default"),
655141cc406Sopenharmony_ci  SANE_I18N ("User defined"),
656141cc406Sopenharmony_ci  SANE_I18N ("High density printing"),
657141cc406Sopenharmony_ci  SANE_I18N ("Low density printing"),
658141cc406Sopenharmony_ci  SANE_I18N ("High contrast printing"),
659141cc406Sopenharmony_ci  NULL
660141cc406Sopenharmony_ci};
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_cistatic SANE_Bool gamma_userdefined_ab[] = {
663141cc406Sopenharmony_ci  SANE_FALSE,
664141cc406Sopenharmony_ci  SANE_TRUE,
665141cc406Sopenharmony_ci  SANE_FALSE,
666141cc406Sopenharmony_ci  SANE_FALSE,
667141cc406Sopenharmony_ci  SANE_FALSE,
668141cc406Sopenharmony_ci};
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_cistatic int gamma_params_d[] = {
671141cc406Sopenharmony_ci  0x03,
672141cc406Sopenharmony_ci  0x04
673141cc406Sopenharmony_ci};
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_cistatic const SANE_String_Const gamma_list_d[] = {
676141cc406Sopenharmony_ci  SANE_I18N ("User defined (Gamma=1.0)"),
677141cc406Sopenharmony_ci  SANE_I18N ("User defined (Gamma=1.8)"),
678141cc406Sopenharmony_ci  NULL
679141cc406Sopenharmony_ci};
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_cistatic SANE_Bool gamma_userdefined_d[] = {
682141cc406Sopenharmony_ci  SANE_TRUE,
683141cc406Sopenharmony_ci  SANE_TRUE
684141cc406Sopenharmony_ci};
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_cistatic SANE_Bool *gamma_userdefined;
687141cc406Sopenharmony_cistatic int *gamma_params;
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci/* flaming hack to get USB scanners
690141cc406Sopenharmony_ci   working without timeouts under linux */
691141cc406Sopenharmony_ci/* (cribbed from fujitsu.c) */
692141cc406Sopenharmony_cistatic unsigned int r_cmd_count = 0;
693141cc406Sopenharmony_cistatic unsigned int w_cmd_count = 0;
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci/* Bay list:
699141cc406Sopenharmony_ci * this is used for the FilmScan
700141cc406Sopenharmony_ci */
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_cistatic const SANE_String_Const bay_list[] = {
703141cc406Sopenharmony_ci  " 1 ",
704141cc406Sopenharmony_ci  " 2 ",
705141cc406Sopenharmony_ci  " 3 ",
706141cc406Sopenharmony_ci  " 4 ",
707141cc406Sopenharmony_ci  " 5 ",
708141cc406Sopenharmony_ci  " 6 ",
709141cc406Sopenharmony_ci  NULL
710141cc406Sopenharmony_ci};
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci/*
713141cc406Sopenharmony_ci *  minimum, maximum, quantization.
714141cc406Sopenharmony_ci */
715141cc406Sopenharmony_ci
716141cc406Sopenharmony_cistatic const SANE_Range u8_range = { 0, 255, 0 };
717141cc406Sopenharmony_cistatic const SANE_Range s8_range = { -127, 127, 0 };
718141cc406Sopenharmony_cistatic const SANE_Range zoom_range = { 50, 200, 0 };
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci/*
721141cc406Sopenharmony_ci * The "switch_params" are used for several boolean choices
722141cc406Sopenharmony_ci */
723141cc406Sopenharmony_cistatic int switch_params[] = {
724141cc406Sopenharmony_ci  0,
725141cc406Sopenharmony_ci  1
726141cc406Sopenharmony_ci};
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci#define  mirror_params  switch_params
729141cc406Sopenharmony_ci#define  speed_params   switch_params
730141cc406Sopenharmony_ci#define  film_params    switch_params
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_cistatic const SANE_Range outline_emphasis_range = { -2, 2, 0 };
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci/* static const SANE_Range gamma_range = { -2, 2, 0 }; */
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_cistruct qf_param
737141cc406Sopenharmony_ci{
738141cc406Sopenharmony_ci  SANE_Word tl_x;
739141cc406Sopenharmony_ci  SANE_Word tl_y;
740141cc406Sopenharmony_ci  SANE_Word br_x;
741141cc406Sopenharmony_ci  SANE_Word br_y;
742141cc406Sopenharmony_ci};
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci/* gcc don't like to overwrite const field */
745141cc406Sopenharmony_cistatic /*const */ struct qf_param qf_params[] = {
746141cc406Sopenharmony_ci  {0, 0, SANE_FIX (120.0), SANE_FIX (120.0)},
747141cc406Sopenharmony_ci  {0, 0, SANE_FIX (148.5), SANE_FIX (210.0)},
748141cc406Sopenharmony_ci  {0, 0, SANE_FIX (210.0), SANE_FIX (148.5)},
749141cc406Sopenharmony_ci  {0, 0, SANE_FIX (215.9), SANE_FIX (279.4)},   /* 8.5" x 11" */
750141cc406Sopenharmony_ci  {0, 0, SANE_FIX (210.0), SANE_FIX (297.0)},
751141cc406Sopenharmony_ci  {0, 0, 0, 0}
752141cc406Sopenharmony_ci};
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_cistatic const SANE_String_Const qf_list[] = {
755141cc406Sopenharmony_ci  SANE_I18N ("CD"),
756141cc406Sopenharmony_ci  SANE_I18N ("A5 portrait"),
757141cc406Sopenharmony_ci  SANE_I18N ("A5 landscape"),
758141cc406Sopenharmony_ci  SANE_I18N ("Letter"),
759141cc406Sopenharmony_ci  SANE_I18N ("A4"),
760141cc406Sopenharmony_ci  SANE_I18N ("Max"),
761141cc406Sopenharmony_ci  NULL
762141cc406Sopenharmony_ci};
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_cistatic SANE_Word *bitDepthList = NULL;
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci/*
770141cc406Sopenharmony_ci * List of pointers to devices - will be dynamically allocated depending
771141cc406Sopenharmony_ci * on the number of devices found.
772141cc406Sopenharmony_ci */
773141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci
776141cc406Sopenharmony_ci/*
777141cc406Sopenharmony_ci * Some utility functions
778141cc406Sopenharmony_ci */
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_cistatic size_t
781141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
782141cc406Sopenharmony_ci{
783141cc406Sopenharmony_ci  size_t size, max_size = 0;
784141cc406Sopenharmony_ci  int i;
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci  for (i = 0; strings[i]; i++)
787141cc406Sopenharmony_ci  {
788141cc406Sopenharmony_ci    size = strlen (strings[i]) + 1;
789141cc406Sopenharmony_ci    if (size > max_size)
790141cc406Sopenharmony_ci      max_size = size;
791141cc406Sopenharmony_ci  }
792141cc406Sopenharmony_ci  return max_size;
793141cc406Sopenharmony_ci}
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_citypedef struct
796141cc406Sopenharmony_ci{
797141cc406Sopenharmony_ci  u_char code;
798141cc406Sopenharmony_ci  u_char status;
799141cc406Sopenharmony_ci  u_char count1;
800141cc406Sopenharmony_ci  u_char count2;
801141cc406Sopenharmony_ci  u_char buf[1];
802141cc406Sopenharmony_ci
803141cc406Sopenharmony_ci} EpsonHdrRec, *EpsonHdr;
804141cc406Sopenharmony_ci
805141cc406Sopenharmony_citypedef struct
806141cc406Sopenharmony_ci{
807141cc406Sopenharmony_ci  u_char code;
808141cc406Sopenharmony_ci  u_char status;
809141cc406Sopenharmony_ci  u_char count1;
810141cc406Sopenharmony_ci  u_char count2;
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_ci  u_char type;
813141cc406Sopenharmony_ci  u_char level;
814141cc406Sopenharmony_ci
815141cc406Sopenharmony_ci  u_char buf[1];
816141cc406Sopenharmony_ci
817141cc406Sopenharmony_ci} EpsonIdentRec, *EpsonIdent;
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_citypedef union
820141cc406Sopenharmony_ci{
821141cc406Sopenharmony_ci  EpsonHdrRec hdr;
822141cc406Sopenharmony_ci  EpsonIdentRec ident;
823141cc406Sopenharmony_ci} EpsonHdrUnionRec, *EpsonHdrUnion;
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_citypedef struct
827141cc406Sopenharmony_ci{
828141cc406Sopenharmony_ci  u_char code;
829141cc406Sopenharmony_ci  u_char status;
830141cc406Sopenharmony_ci  u_short count;
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci  u_char buf[1];
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci} EpsonParameterRec, *EpsonParameter;
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_citypedef struct
837141cc406Sopenharmony_ci{
838141cc406Sopenharmony_ci  u_char code;
839141cc406Sopenharmony_ci  u_char status;
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci  u_char buf[4];
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci} EpsonDataRec, *EpsonData;
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci/*
846141cc406Sopenharmony_ci *
847141cc406Sopenharmony_ci *
848141cc406Sopenharmony_ci */
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_cistatic EpsonHdrUnion command (Epson_Scanner * s, u_char * cmd, size_t cmd_size,
851141cc406Sopenharmony_ci                         SANE_Status * status);
852141cc406Sopenharmony_cistatic SANE_Status get_identity_information (SANE_Handle handle);
853141cc406Sopenharmony_cistatic SANE_Status get_identity2_information (SANE_Handle handle);
854141cc406Sopenharmony_cistatic int send (Epson_Scanner * s, void *buf, size_t buf_size,
855141cc406Sopenharmony_ci                 SANE_Status * status);
856141cc406Sopenharmony_cistatic ssize_t receive (Epson_Scanner * s, void *buf, ssize_t buf_size,
857141cc406Sopenharmony_ci                        SANE_Status * status);
858141cc406Sopenharmony_cistatic SANE_Status color_shuffle (SANE_Handle handle, int *new_length);
859141cc406Sopenharmony_cistatic SANE_Status request_focus_position (SANE_Handle handle,
860141cc406Sopenharmony_ci                                           u_char * position);
861141cc406Sopenharmony_cistatic SANE_Bool request_push_button_status (SANE_Handle handle,
862141cc406Sopenharmony_ci                                             SANE_Bool * theButtonStatus);
863141cc406Sopenharmony_cistatic void activateOption (Epson_Scanner * s, SANE_Int option,
864141cc406Sopenharmony_ci                            SANE_Bool * change);
865141cc406Sopenharmony_cistatic void deactivateOption (Epson_Scanner * s, SANE_Int option,
866141cc406Sopenharmony_ci                              SANE_Bool * change);
867141cc406Sopenharmony_cistatic void setOptionState (Epson_Scanner * s, SANE_Bool state,
868141cc406Sopenharmony_ci                            SANE_Int option, SANE_Bool * change);
869141cc406Sopenharmony_cistatic void close_scanner (Epson_Scanner * s);
870141cc406Sopenharmony_cistatic SANE_Status open_scanner (Epson_Scanner * s);
871141cc406Sopenharmony_ciSANE_Status sane_auto_eject (Epson_Scanner * s);
872141cc406Sopenharmony_cistatic SANE_Status attach_one_usb (SANE_String_Const devname);
873141cc406Sopenharmony_cistatic void filter_resolution_list (Epson_Scanner * s);
874141cc406Sopenharmony_cistatic void get_size (char c1, char c2, double *w, double *h);
875141cc406Sopenharmony_cistatic void scan_finish (Epson_Scanner * s);
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_ci/*
878141cc406Sopenharmony_ci *
879141cc406Sopenharmony_ci *
880141cc406Sopenharmony_ci */
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_cistatic int
883141cc406Sopenharmony_cisend (Epson_Scanner * s, void *buf, size_t buf_size, SANE_Status * status)
884141cc406Sopenharmony_ci{
885141cc406Sopenharmony_ci  DBG (3, "send buf, size = %lu\n", (u_long) buf_size);
886141cc406Sopenharmony_ci
887141cc406Sopenharmony_ci#if 1
888141cc406Sopenharmony_ci  {
889141cc406Sopenharmony_ci    unsigned int k;
890141cc406Sopenharmony_ci    const u_char *s = buf;
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci    for (k = 0; k < buf_size; k++)
893141cc406Sopenharmony_ci    {
894141cc406Sopenharmony_ci      DBG (125, "buf[%d] %02x %c\n", k, s[k], isprint (s[k]) ? s[k] : '.');
895141cc406Sopenharmony_ci    }
896141cc406Sopenharmony_ci  }
897141cc406Sopenharmony_ci#endif
898141cc406Sopenharmony_ci
899141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
900141cc406Sopenharmony_ci  {
901141cc406Sopenharmony_ci    return sanei_epson_scsi_write (s->fd, buf, buf_size, status);
902141cc406Sopenharmony_ci  }
903141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_PIO)
904141cc406Sopenharmony_ci  {
905141cc406Sopenharmony_ci    size_t n;
906141cc406Sopenharmony_ci
907141cc406Sopenharmony_ci    if (buf_size == (n = sanei_pio_write (s->fd, buf, buf_size)))
908141cc406Sopenharmony_ci      *status = SANE_STATUS_GOOD;
909141cc406Sopenharmony_ci    else
910141cc406Sopenharmony_ci      *status = SANE_STATUS_INVAL;
911141cc406Sopenharmony_ci
912141cc406Sopenharmony_ci    return n;
913141cc406Sopenharmony_ci  }
914141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
915141cc406Sopenharmony_ci  {
916141cc406Sopenharmony_ci    size_t n;
917141cc406Sopenharmony_ci    n = buf_size;
918141cc406Sopenharmony_ci    *status = sanei_usb_write_bulk (s->fd, buf, &n);
919141cc406Sopenharmony_ci    w_cmd_count++;
920141cc406Sopenharmony_ci    DBG (5, "w_cmd_count = %d\n",w_cmd_count);
921141cc406Sopenharmony_ci    DBG (5, "r_cmd_count = %d\n",r_cmd_count);
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ci    return n;
924141cc406Sopenharmony_ci  }
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
927141cc406Sopenharmony_ci  /* never reached */
928141cc406Sopenharmony_ci}
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci/*
931141cc406Sopenharmony_ci *
932141cc406Sopenharmony_ci *
933141cc406Sopenharmony_ci */
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_cistatic ssize_t
936141cc406Sopenharmony_cireceive (Epson_Scanner * s, void *buf, ssize_t buf_size, SANE_Status * status)
937141cc406Sopenharmony_ci{
938141cc406Sopenharmony_ci  ssize_t n = 0;
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
941141cc406Sopenharmony_ci  {
942141cc406Sopenharmony_ci    n = sanei_epson_scsi_read (s->fd, buf, buf_size, status);
943141cc406Sopenharmony_ci  }
944141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_PIO)
945141cc406Sopenharmony_ci  {
946141cc406Sopenharmony_ci    if (buf_size == (n = sanei_pio_read (s->fd, buf, (size_t) buf_size)))
947141cc406Sopenharmony_ci      *status = SANE_STATUS_GOOD;
948141cc406Sopenharmony_ci    else
949141cc406Sopenharmony_ci      *status = SANE_STATUS_INVAL;
950141cc406Sopenharmony_ci  }
951141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
952141cc406Sopenharmony_ci  {
953141cc406Sopenharmony_ci    /* !!! only report an error if we don't read anything */
954141cc406Sopenharmony_ci    n = buf_size;               /* buf_size gets overwritten */
955141cc406Sopenharmony_ci    *status = sanei_usb_read_bulk (s->fd, (SANE_Byte *) buf, (size_t *) & n);
956141cc406Sopenharmony_ci    r_cmd_count += (n+63)/64; /* add # of packets, rounding up */
957141cc406Sopenharmony_ci    DBG (5, "w_cmd_count = %d\n",w_cmd_count);
958141cc406Sopenharmony_ci    DBG (5, "r_cmd_count = %d\n",r_cmd_count);
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci    if (n > 0)
961141cc406Sopenharmony_ci      *status = SANE_STATUS_GOOD;
962141cc406Sopenharmony_ci  }
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci  DBG (7, "receive buf, expected = %lu, got = %ld\n", (u_long) buf_size, (long) n);
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci#if 1
967141cc406Sopenharmony_ci  if (n > 0)
968141cc406Sopenharmony_ci  {
969141cc406Sopenharmony_ci    int k;
970141cc406Sopenharmony_ci    const u_char *s = buf;
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci    for (k = 0; k < n; k++)
973141cc406Sopenharmony_ci    {
974141cc406Sopenharmony_ci      DBG (127, "buf[%d] %02x %c\n", k, s[k], isprint (s[k]) ? s[k] : '.');
975141cc406Sopenharmony_ci    }
976141cc406Sopenharmony_ci  }
977141cc406Sopenharmony_ci#else
978141cc406Sopenharmony_ci  {
979141cc406Sopenharmony_ci    int i;
980141cc406Sopenharmony_ci    ssize_t k;
981141cc406Sopenharmony_ci    ssize_t hex_start = 0;
982141cc406Sopenharmony_ci    const u_char *s = buf;
983141cc406Sopenharmony_ci    char hex_str[NUM_OF_HEX_ELEMENTS * 3 + 1];
984141cc406Sopenharmony_ci    char tmp_str[NUM_OF_HEX_ELEMENTS * 3 + 1];
985141cc406Sopenharmony_ci    char ascii_str[NUM_OF_HEX_ELEMENTS * 2 + 1];
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci    hex_str[0] = '\0';
988141cc406Sopenharmony_ci    ascii_str[0] = '\0';
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci    for (k = 0; k < buf_size; k++)
991141cc406Sopenharmony_ci    {
992141cc406Sopenharmony_ci      /* write out the data in lines of 16 bytes */
993141cc406Sopenharmony_ci      /* add the next hex value to the hex string */
994141cc406Sopenharmony_ci      sprintf (tmp_str, "%s %02x", hex_str, s[k]);
995141cc406Sopenharmony_ci      strcpy (hex_str, tmp_str);
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci      /* add the character to the ascii string */
998141cc406Sopenharmony_ci      sprintf (tmp_str, "%s %c", ascii_str, isprint (s[k]) ? s[k] : '.');
999141cc406Sopenharmony_ci      strcpy (ascii_str, tmp_str);
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci      if ((k % (NUM_OF_HEX_ELEMENTS)) == 0)
1002141cc406Sopenharmony_ci      {
1003141cc406Sopenharmony_ci        if (k != 0)             /* don't do this the first time */
1004141cc406Sopenharmony_ci        {
1005141cc406Sopenharmony_ci          for (i = strlen (hex_str); i < (NUM_OF_HEX_ELEMENTS * 3); i++)
1006141cc406Sopenharmony_ci          {
1007141cc406Sopenharmony_ci            hex_str[i] = ' ';
1008141cc406Sopenharmony_ci          }
1009141cc406Sopenharmony_ci          hex_str[NUM_OF_HEX_ELEMENTS + 1] = '\0';
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci          DBG (125, "recv buf[%05d]: %s   %s\n", hex_start, hex_str,
1012141cc406Sopenharmony_ci               ascii_str);
1013141cc406Sopenharmony_ci          hex_start = k;
1014141cc406Sopenharmony_ci          hex_str[0] = '\0';
1015141cc406Sopenharmony_ci          ascii_str[0] = '\0';
1016141cc406Sopenharmony_ci        }
1017141cc406Sopenharmony_ci      }
1018141cc406Sopenharmony_ci    }
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci    for (i = strlen (hex_str); i < NUM_OF_HEX_ELEMENTS * 3; i++)
1021141cc406Sopenharmony_ci    {
1022141cc406Sopenharmony_ci      hex_str[i] = ' ';
1023141cc406Sopenharmony_ci    }
1024141cc406Sopenharmony_ci    hex_str[NUM_OF_HEX_ELEMENTS + 1] = '\0';
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci    DBG (125, "recv buf[%05d]: %s   %s\n", hex_start, hex_str, ascii_str);
1027141cc406Sopenharmony_ci  }
1028141cc406Sopenharmony_ci#endif
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  return n;
1031141cc406Sopenharmony_ci}
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci/*
1034141cc406Sopenharmony_ci *
1035141cc406Sopenharmony_ci *
1036141cc406Sopenharmony_ci */
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_cistatic SANE_Status
1039141cc406Sopenharmony_ciexpect_ack (Epson_Scanner * s)
1040141cc406Sopenharmony_ci{
1041141cc406Sopenharmony_ci  u_char result[1];
1042141cc406Sopenharmony_ci  size_t len;
1043141cc406Sopenharmony_ci  SANE_Status status;
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ci  len = sizeof (result);
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci  receive (s, result, len, &status);
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
1050141cc406Sopenharmony_ci    return status;
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci  if (ACK != result[0])
1053141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1056141cc406Sopenharmony_ci}
1057141cc406Sopenharmony_ci
1058141cc406Sopenharmony_ci/*
1059141cc406Sopenharmony_ci *
1060141cc406Sopenharmony_ci *
1061141cc406Sopenharmony_ci */
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_cistatic SANE_Status
1064141cc406Sopenharmony_ciset_cmd (Epson_Scanner * s, u_char cmd, int val)
1065141cc406Sopenharmony_ci{
1066141cc406Sopenharmony_ci  SANE_Status status;
1067141cc406Sopenharmony_ci  u_char params[2];
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci  if (!cmd)
1070141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1071141cc406Sopenharmony_ci
1072141cc406Sopenharmony_ci  params[0] = ESC;
1073141cc406Sopenharmony_ci  params[1] = cmd;
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci  send (s, params, 2, &status);
1076141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1077141cc406Sopenharmony_ci    return status;
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci  params[0] = val;
1080141cc406Sopenharmony_ci  send (s, params, 1, &status);
1081141cc406Sopenharmony_ci  status = expect_ack (s);
1082141cc406Sopenharmony_ci
1083141cc406Sopenharmony_ci  return status;
1084141cc406Sopenharmony_ci}
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci/* A little helper function to correct the extended status reply
1087141cc406Sopenharmony_ci      gotten from scanners with known buggy firmware.
1088141cc406Sopenharmony_ci */
1089141cc406Sopenharmony_cistatic void
1090141cc406Sopenharmony_cifix_up_extended_status_reply (const char *model, u_char * buf)
1091141cc406Sopenharmony_ci{
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci  if (0 == strncmp (model, "ES-9000H", strlen ("ES-9000H"))
1094141cc406Sopenharmony_ci      || 0 == strncmp (model, "GT-30000", strlen ("GT-30000")))
1095141cc406Sopenharmony_ci  {
1096141cc406Sopenharmony_ci    DBG (1, "Fixing up buggy ADF max scan dimensions.\n");
1097141cc406Sopenharmony_ci    buf[2] = 0xB0;
1098141cc406Sopenharmony_ci    buf[3] = 0x6D;
1099141cc406Sopenharmony_ci    buf[4] = 0x60;
1100141cc406Sopenharmony_ci    buf[5] = 0x9F;
1101141cc406Sopenharmony_ci  }
1102141cc406Sopenharmony_ci}
1103141cc406Sopenharmony_ci
1104141cc406Sopenharmony_cistatic void
1105141cc406Sopenharmony_ciprint_params (const SANE_Parameters params)
1106141cc406Sopenharmony_ci{
1107141cc406Sopenharmony_ci  DBG (5, "params.format = %d\n", params.format);
1108141cc406Sopenharmony_ci  DBG (5, "params.last_frame = %d\n", params.last_frame);
1109141cc406Sopenharmony_ci  DBG (5, "params.bytes_per_line = %d\n", params.bytes_per_line);
1110141cc406Sopenharmony_ci  DBG (5, "params.pixels_per_line = %d\n", params.pixels_per_line);
1111141cc406Sopenharmony_ci  DBG (5, "params.lines = %d\n", params.lines);
1112141cc406Sopenharmony_ci  DBG (5, "params.depth = %d\n", params.depth);
1113141cc406Sopenharmony_ci}
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci/*
1117141cc406Sopenharmony_ci *
1118141cc406Sopenharmony_ci *
1119141cc406Sopenharmony_ci */
1120141cc406Sopenharmony_ci
1121141cc406Sopenharmony_ci#define  set_focus_position(s,v)        set_cmd( s,(s)->hw->cmd->set_focus_position,v)
1122141cc406Sopenharmony_ci#define  set_color_mode(s,v)            set_cmd( s,(s)->hw->cmd->set_color_mode,v)
1123141cc406Sopenharmony_ci#define  set_data_format(s,v)           set_cmd( s,(s)->hw->cmd->set_data_format, v)
1124141cc406Sopenharmony_ci#define  set_halftoning(s,v)            set_cmd( s,(s)->hw->cmd->set_halftoning, v)
1125141cc406Sopenharmony_ci#define  set_gamma(s,v)                 set_cmd( s,(s)->hw->cmd->set_gamma, v)
1126141cc406Sopenharmony_ci#define  set_color_correction(s,v)      set_cmd( s,(s)->hw->cmd->set_color_correction, v)
1127141cc406Sopenharmony_ci#define  set_lcount(s,v)                set_cmd( s,(s)->hw->cmd->set_lcount, v)
1128141cc406Sopenharmony_ci#define  set_bright(s,v)                set_cmd( s,(s)->hw->cmd->set_bright, v)
1129141cc406Sopenharmony_ci#define  mirror_image(s,v)              set_cmd( s,(s)->hw->cmd->mirror_image, v)
1130141cc406Sopenharmony_ci#define  set_speed(s,v)                 set_cmd( s,(s)->hw->cmd->set_speed, v)
1131141cc406Sopenharmony_ci#define  set_outline_emphasis(s,v)      set_cmd( s,(s)->hw->cmd->set_outline_emphasis, v)
1132141cc406Sopenharmony_ci#define  control_auto_area_segmentation(s,v)    set_cmd( s,(s)->hw->cmd->control_auto_area_segmentation, v)
1133141cc406Sopenharmony_ci#define  set_film_type(s,v)             set_cmd( s,(s)->hw->cmd->set_film_type, v)
1134141cc406Sopenharmony_ci#define  set_exposure_time(s,v)         set_cmd( s,(s)->hw->cmd->set_exposure_time, v)
1135141cc406Sopenharmony_ci#define  set_bay(s,v)                   set_cmd( s,(s)->hw->cmd->set_bay, v)
1136141cc406Sopenharmony_ci#define  set_threshold(s,v)             set_cmd( s,(s)->hw->cmd->set_threshold, v)
1137141cc406Sopenharmony_ci#define  control_extension(s,v)         set_cmd( s,(s)->hw->cmd->control_an_extension, v)
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci/*#define  (s,v)                set_cmd( s,(s)->hw->cmd->, v) */
1140141cc406Sopenharmony_ci
1141141cc406Sopenharmony_cistatic SANE_Status
1142141cc406Sopenharmony_ciset_zoom (Epson_Scanner * s, int x_zoom, int y_zoom)
1143141cc406Sopenharmony_ci{
1144141cc406Sopenharmony_ci  SANE_Status status;
1145141cc406Sopenharmony_ci  u_char cmd[2];
1146141cc406Sopenharmony_ci  u_char params[2];
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci  if (!s->hw->cmd->set_zoom)
1149141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci  cmd[0] = ESC;
1152141cc406Sopenharmony_ci  cmd[1] = s->hw->cmd->set_zoom;
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ci  send (s, cmd, 2, &status);
1155141cc406Sopenharmony_ci  status = expect_ack (s);
1156141cc406Sopenharmony_ci
1157141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1158141cc406Sopenharmony_ci    return status;
1159141cc406Sopenharmony_ci
1160141cc406Sopenharmony_ci  params[0] = x_zoom;
1161141cc406Sopenharmony_ci  params[1] = y_zoom;
1162141cc406Sopenharmony_ci
1163141cc406Sopenharmony_ci  send (s, params, 2, &status);
1164141cc406Sopenharmony_ci  status = expect_ack (s);
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci  return status;
1167141cc406Sopenharmony_ci}
1168141cc406Sopenharmony_ci
1169141cc406Sopenharmony_ci
1170141cc406Sopenharmony_cistatic SANE_Status
1171141cc406Sopenharmony_ciset_resolution (Epson_Scanner * s, int xres, int yres)
1172141cc406Sopenharmony_ci{
1173141cc406Sopenharmony_ci  SANE_Status status;
1174141cc406Sopenharmony_ci  u_char params[4];
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci  if (!s->hw->cmd->set_resolution)
1177141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1178141cc406Sopenharmony_ci
1179141cc406Sopenharmony_ci  params[0] = ESC;
1180141cc406Sopenharmony_ci  params[1] = s->hw->cmd->set_resolution;
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci  send (s, params, 2, &status);
1183141cc406Sopenharmony_ci  status = expect_ack (s);
1184141cc406Sopenharmony_ci
1185141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1186141cc406Sopenharmony_ci    return status;
1187141cc406Sopenharmony_ci
1188141cc406Sopenharmony_ci  params[0] = xres;
1189141cc406Sopenharmony_ci  params[1] = xres >> 8;
1190141cc406Sopenharmony_ci  params[2] = yres;
1191141cc406Sopenharmony_ci  params[3] = yres >> 8;
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  send (s, params, 4, &status);
1194141cc406Sopenharmony_ci  status = expect_ack (s);
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci  return status;
1197141cc406Sopenharmony_ci}
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci/*
1200141cc406Sopenharmony_ci * set_scan_area()
1201141cc406Sopenharmony_ci *
1202141cc406Sopenharmony_ci * Sends the "set scan area" command to the scanner with the currently selected
1203141cc406Sopenharmony_ci * scan area. This scan area is already corrected for "color shuffling" if
1204141cc406Sopenharmony_ci * necessary.
1205141cc406Sopenharmony_ci */
1206141cc406Sopenharmony_cistatic SANE_Status
1207141cc406Sopenharmony_ciset_scan_area (Epson_Scanner * s, int x, int y, int width, int height)
1208141cc406Sopenharmony_ci{
1209141cc406Sopenharmony_ci  SANE_Status status;
1210141cc406Sopenharmony_ci  u_char params[8];
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci  DBG (1, "set_scan_area: %p %d %d %d %d\n", (void *) s, x, y, width, height);
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci  if (!s->hw->cmd->set_scan_area)
1215141cc406Sopenharmony_ci  {
1216141cc406Sopenharmony_ci    DBG (1, "set_scan_area not supported\n");
1217141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1218141cc406Sopenharmony_ci  }
1219141cc406Sopenharmony_ci
1220141cc406Sopenharmony_ci  /* verify the scan area */
1221141cc406Sopenharmony_ci  if (x < 0 || y < 0 || width <= 0 || height <= 0)
1222141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci  params[0] = ESC;
1225141cc406Sopenharmony_ci  params[1] = s->hw->cmd->set_scan_area;
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci  send (s, params, 2, &status);
1228141cc406Sopenharmony_ci  status = expect_ack (s);
1229141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1230141cc406Sopenharmony_ci    return status;
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci  params[0] = x;
1233141cc406Sopenharmony_ci  params[1] = x >> 8;
1234141cc406Sopenharmony_ci  params[2] = y;
1235141cc406Sopenharmony_ci  params[3] = y >> 8;
1236141cc406Sopenharmony_ci  params[4] = width;
1237141cc406Sopenharmony_ci  params[5] = width >> 8;
1238141cc406Sopenharmony_ci  params[6] = height;
1239141cc406Sopenharmony_ci  params[7] = height >> 8;
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci  send (s, params, 8, &status);
1242141cc406Sopenharmony_ci  status = expect_ack (s);
1243141cc406Sopenharmony_ci
1244141cc406Sopenharmony_ci  return status;
1245141cc406Sopenharmony_ci}
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci/*
1248141cc406Sopenharmony_ci * set_color_correction_coefficients()
1249141cc406Sopenharmony_ci *
1250141cc406Sopenharmony_ci * Sends the "set color correction coefficients" command with the currently selected
1251141cc406Sopenharmony_ci * parameters to the scanner.
1252141cc406Sopenharmony_ci */
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_cistatic SANE_Status
1255141cc406Sopenharmony_ciset_color_correction_coefficients (Epson_Scanner * s)
1256141cc406Sopenharmony_ci{
1257141cc406Sopenharmony_ci  SANE_Status status;
1258141cc406Sopenharmony_ci  u_char cmd = s->hw->cmd->set_color_correction_coefficients;
1259141cc406Sopenharmony_ci  u_char params[2];
1260141cc406Sopenharmony_ci  const int length = 9;
1261141cc406Sopenharmony_ci  signed char cct[9];
1262141cc406Sopenharmony_ci
1263141cc406Sopenharmony_ci  DBG (1, "set_color_correction_coefficients: starting.\n");
1264141cc406Sopenharmony_ci  if (!cmd)
1265141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci  params[0] = ESC;
1268141cc406Sopenharmony_ci  params[1] = cmd;
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  send (s, params, 2, &status);
1271141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1272141cc406Sopenharmony_ci    return status;
1273141cc406Sopenharmony_ci
1274141cc406Sopenharmony_ci  cct[0] = s->val[OPT_CCT_1].w;
1275141cc406Sopenharmony_ci  cct[1] = s->val[OPT_CCT_2].w;
1276141cc406Sopenharmony_ci  cct[2] = s->val[OPT_CCT_3].w;
1277141cc406Sopenharmony_ci  cct[3] = s->val[OPT_CCT_4].w;
1278141cc406Sopenharmony_ci  cct[4] = s->val[OPT_CCT_5].w;
1279141cc406Sopenharmony_ci  cct[5] = s->val[OPT_CCT_6].w;
1280141cc406Sopenharmony_ci  cct[6] = s->val[OPT_CCT_7].w;
1281141cc406Sopenharmony_ci  cct[7] = s->val[OPT_CCT_8].w;
1282141cc406Sopenharmony_ci  cct[8] = s->val[OPT_CCT_9].w;
1283141cc406Sopenharmony_ci
1284141cc406Sopenharmony_ci  DBG (1, "set_color_correction_coefficients: %d,%d,%d %d,%d,%d %d,%d,%d.\n",
1285141cc406Sopenharmony_ci       cct[0], cct[1], cct[2], cct[3],
1286141cc406Sopenharmony_ci       cct[4], cct[5], cct[6], cct[7], cct[8]);
1287141cc406Sopenharmony_ci
1288141cc406Sopenharmony_ci  send (s, cct, length, &status);
1289141cc406Sopenharmony_ci  status = expect_ack (s);
1290141cc406Sopenharmony_ci  DBG (1, "set_color_correction_coefficients: ending=%d.\n", status);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  return status;
1293141cc406Sopenharmony_ci}
1294141cc406Sopenharmony_ci
1295141cc406Sopenharmony_ci/*
1296141cc406Sopenharmony_ci *
1297141cc406Sopenharmony_ci *
1298141cc406Sopenharmony_ci */
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_cistatic SANE_Status
1301141cc406Sopenharmony_ciset_gamma_table (Epson_Scanner * s)
1302141cc406Sopenharmony_ci{
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci  SANE_Status status;
1305141cc406Sopenharmony_ci  u_char cmd = s->hw->cmd->set_gamma_table;
1306141cc406Sopenharmony_ci  u_char params[2];
1307141cc406Sopenharmony_ci  const int length = 257;
1308141cc406Sopenharmony_ci  u_char gamma[257];
1309141cc406Sopenharmony_ci  int n;
1310141cc406Sopenharmony_ci  int table;
1311141cc406Sopenharmony_ci/*      static const char gamma_cmds[] = { 'M', 'R', 'G', 'B' }; */
1312141cc406Sopenharmony_ci  static const char gamma_cmds[] = { 'R', 'G', 'B' };
1313141cc406Sopenharmony_ci
1314141cc406Sopenharmony_ci
1315141cc406Sopenharmony_ci  DBG (1, "set_gamma_table: starting.\n");
1316141cc406Sopenharmony_ci  if (!cmd)
1317141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1318141cc406Sopenharmony_ci
1319141cc406Sopenharmony_ci  params[0] = ESC;
1320141cc406Sopenharmony_ci  params[1] = cmd;
1321141cc406Sopenharmony_ci
1322141cc406Sopenharmony_ci/*
1323141cc406Sopenharmony_ci *      Print the gamma tables before sending them to the scanner.
1324141cc406Sopenharmony_ci */
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  if (DBG_LEVEL > 0)
1327141cc406Sopenharmony_ci  {
1328141cc406Sopenharmony_ci    int c, i, j;
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci    DBG (1, "set_gamma_table()\n");
1331141cc406Sopenharmony_ci    for (c = 0; c < 3; c++)
1332141cc406Sopenharmony_ci    {
1333141cc406Sopenharmony_ci      for (i = 0; i < 256; i += 16)
1334141cc406Sopenharmony_ci      {
1335141cc406Sopenharmony_ci        char gammaValues[16 * 3 + 1], newValue[4];
1336141cc406Sopenharmony_ci
1337141cc406Sopenharmony_ci        gammaValues[0] = '\0';
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci        for (j = 0; j < 16; j++)
1340141cc406Sopenharmony_ci        {
1341141cc406Sopenharmony_ci          sprintf (newValue, " %02x", s->gamma_table[c][i + j]);
1342141cc406Sopenharmony_ci          strcat (gammaValues, newValue);
1343141cc406Sopenharmony_ci        }
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci        DBG (10, "Gamma Table[%d][%d] %s\n", c, i, gammaValues);
1346141cc406Sopenharmony_ci      }
1347141cc406Sopenharmony_ci    }
1348141cc406Sopenharmony_ci  }
1349141cc406Sopenharmony_ci
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci/*
1352141cc406Sopenharmony_ci * TODO: &status in send makes no sense like that.
1353141cc406Sopenharmony_ci */
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci/*
1356141cc406Sopenharmony_ci *  When handling inverted images, we must also invert the user
1357141cc406Sopenharmony_ci *  supplied gamma function.  This is *not* just 255-gamma -
1358141cc406Sopenharmony_ci *  this gives a negative image.
1359141cc406Sopenharmony_ci */
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci  for (table = 0; table < 3; table++)
1362141cc406Sopenharmony_ci  {
1363141cc406Sopenharmony_ci    gamma[0] = gamma_cmds[table];
1364141cc406Sopenharmony_ci    if (s->invert_image)
1365141cc406Sopenharmony_ci    {
1366141cc406Sopenharmony_ci      for (n = 0; n < 256; ++n)
1367141cc406Sopenharmony_ci      {
1368141cc406Sopenharmony_ci        gamma[n + 1] = 255 - s->gamma_table[table][255 - n];
1369141cc406Sopenharmony_ci      }
1370141cc406Sopenharmony_ci    }
1371141cc406Sopenharmony_ci    else
1372141cc406Sopenharmony_ci    {
1373141cc406Sopenharmony_ci      for (n = 0; n < 256; ++n)
1374141cc406Sopenharmony_ci      {
1375141cc406Sopenharmony_ci        gamma[n + 1] = s->gamma_table[table][n];
1376141cc406Sopenharmony_ci      }
1377141cc406Sopenharmony_ci    }
1378141cc406Sopenharmony_ci
1379141cc406Sopenharmony_ci    send (s, params, 2, &status);
1380141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1381141cc406Sopenharmony_ci      return status;
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci    send (s, gamma, length, &status);
1384141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1385141cc406Sopenharmony_ci      return status;
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci  }
1388141cc406Sopenharmony_ci
1389141cc406Sopenharmony_ci  DBG (1, "set_gamma_table: complete = %d.\n", status);
1390141cc406Sopenharmony_ci
1391141cc406Sopenharmony_ci  return status;
1392141cc406Sopenharmony_ci}
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_civoid
1397141cc406Sopenharmony_ciget_size (char c1, char c2, double *w, double *h)
1398141cc406Sopenharmony_ci{
1399141cc406Sopenharmony_ci  int ind;
1400141cc406Sopenharmony_ci  unsigned char flag;
1401141cc406Sopenharmony_ci
1402141cc406Sopenharmony_ci  double wsizetbl[] = {
1403141cc406Sopenharmony_ci    11.60,                      /* A3V */
1404141cc406Sopenharmony_ci    11.00,                      /* WLT */
1405141cc406Sopenharmony_ci    10.12,                      /* B4V */
1406141cc406Sopenharmony_ci    8.50,                       /* LGV */
1407141cc406Sopenharmony_ci    8.27,                       /* A4V */
1408141cc406Sopenharmony_ci    11.69,                      /* A4H */
1409141cc406Sopenharmony_ci    8.50,                       /* LTV */
1410141cc406Sopenharmony_ci    11.00,                      /* LTH */
1411141cc406Sopenharmony_ci    7.17,                       /* B5V */
1412141cc406Sopenharmony_ci    10.12,                      /* B5H */
1413141cc406Sopenharmony_ci    5.83,                       /* A5V */
1414141cc406Sopenharmony_ci    8.27,                       /* A5H */
1415141cc406Sopenharmony_ci    7.25,                       /* EXV */
1416141cc406Sopenharmony_ci    10.50,                      /* EXH */
1417141cc406Sopenharmony_ci    11.69,                      /* unknown */
1418141cc406Sopenharmony_ci    11.69,                      /* unknown */
1419141cc406Sopenharmony_ci    11.69,                      /* unknown */
1420141cc406Sopenharmony_ci  };
1421141cc406Sopenharmony_ci  double hsizetbl[] = {
1422141cc406Sopenharmony_ci    16.54,                      /* A3V */
1423141cc406Sopenharmony_ci    17.00,                      /* WLT */
1424141cc406Sopenharmony_ci    14.33,                      /* B4V */
1425141cc406Sopenharmony_ci    14.00,                      /* LGV */
1426141cc406Sopenharmony_ci    11.69,                      /* A4V */
1427141cc406Sopenharmony_ci    8.27,                       /* A4H */
1428141cc406Sopenharmony_ci    11.00,                      /* LTV */
1429141cc406Sopenharmony_ci    8.50,                       /* LTH */
1430141cc406Sopenharmony_ci    10.12,                      /* B5V */
1431141cc406Sopenharmony_ci    7.17,                       /* B5H */
1432141cc406Sopenharmony_ci    8.27,                       /* A5V */
1433141cc406Sopenharmony_ci    5.83,                       /* A5H */
1434141cc406Sopenharmony_ci    10.50,                      /* EXV */
1435141cc406Sopenharmony_ci    7.25,                       /* EXH */
1436141cc406Sopenharmony_ci    17.00,                      /* unknown */
1437141cc406Sopenharmony_ci    17.00,                      /* unknown */
1438141cc406Sopenharmony_ci    17.00,                      /* unknown */
1439141cc406Sopenharmony_ci  };
1440141cc406Sopenharmony_ci
1441141cc406Sopenharmony_ci  flag = c1;
1442141cc406Sopenharmony_ci  for (ind = 0; ind < 8; ind++)
1443141cc406Sopenharmony_ci  {
1444141cc406Sopenharmony_ci    if (flag & 0x80)
1445141cc406Sopenharmony_ci      goto DetectSize;
1446141cc406Sopenharmony_ci    flag = flag << 1;
1447141cc406Sopenharmony_ci  }
1448141cc406Sopenharmony_ci  flag = c2;
1449141cc406Sopenharmony_ci  for (; ind < 16; ind++)
1450141cc406Sopenharmony_ci  {
1451141cc406Sopenharmony_ci    if (flag & 0x80)
1452141cc406Sopenharmony_ci      goto DetectSize;
1453141cc406Sopenharmony_ci    flag = flag << 1;
1454141cc406Sopenharmony_ci  }
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ciDetectSize:
1457141cc406Sopenharmony_ci
1458141cc406Sopenharmony_ci  *w = wsizetbl[ind];
1459141cc406Sopenharmony_ci  *h = hsizetbl[ind];
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  DBG (10, "detected width: %f\n", *w);
1462141cc406Sopenharmony_ci  DBG (10, "detected height: %f\n", *h);
1463141cc406Sopenharmony_ci}
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci
1466141cc406Sopenharmony_ci/*
1467141cc406Sopenharmony_ci * check_ext_status()
1468141cc406Sopenharmony_ci *
1469141cc406Sopenharmony_ci * Requests the extended status flag from the scanner. The "warming up" condition
1470141cc406Sopenharmony_ci * is reported as a warning (only visible if debug level is set to 10 or greater) -
1471141cc406Sopenharmony_ci * every other condition is reported as an error.
1472141cc406Sopenharmony_ci *
1473141cc406Sopenharmony_ci * This function only gets called when we are dealing with a scanner that supports the
1474141cc406Sopenharmony_ci * "warming up" code, so it's not a problem for B3 level scanners, that don't handle
1475141cc406Sopenharmony_ci * request extended status commands.
1476141cc406Sopenharmony_ci */
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_cistatic SANE_Status
1479141cc406Sopenharmony_cicheck_ext_status (Epson_Scanner * s, int *max_x, int *max_y)
1480141cc406Sopenharmony_ci{
1481141cc406Sopenharmony_ci  SANE_Status status;
1482141cc406Sopenharmony_ci  u_char cmd = s->hw->cmd->request_extended_status;
1483141cc406Sopenharmony_ci  u_char params[2];
1484141cc406Sopenharmony_ci  u_char *buf;
1485141cc406Sopenharmony_ci  EpsonHdr head;
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  *max_x = 0;
1488141cc406Sopenharmony_ci  *max_y = 0;
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci  if (cmd == 0)
1491141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci  params[0] = ESC;
1494141cc406Sopenharmony_ci  params[1] = cmd;
1495141cc406Sopenharmony_ci
1496141cc406Sopenharmony_ci  head = (EpsonHdr) command (s, params, 2, &status);
1497141cc406Sopenharmony_ci  if (NULL == head)
1498141cc406Sopenharmony_ci  {
1499141cc406Sopenharmony_ci    DBG (1, "Extended status flag request failed\n");
1500141cc406Sopenharmony_ci    return status;
1501141cc406Sopenharmony_ci  }
1502141cc406Sopenharmony_ci
1503141cc406Sopenharmony_ci  buf = &head->buf[0];
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci  if (buf[0] & EXT_STATUS_WU)
1506141cc406Sopenharmony_ci  {
1507141cc406Sopenharmony_ci    DBG (10, "option: warming up\n");
1508141cc406Sopenharmony_ci    status = SANE_STATUS_DEVICE_BUSY;
1509141cc406Sopenharmony_ci  }
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci  if (buf[0] & EXT_STATUS_FER)
1512141cc406Sopenharmony_ci  {
1513141cc406Sopenharmony_ci    DBG (1, "option: fatal error\n");
1514141cc406Sopenharmony_ci    status = SANE_STATUS_INVAL;
1515141cc406Sopenharmony_ci  }
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci  if (s->hw->ADF && s->hw->use_extension && s->hw->cmd->feed)
1518141cc406Sopenharmony_ci  {
1519141cc406Sopenharmony_ci    fix_up_extended_status_reply (s->hw->sane.model, buf);
1520141cc406Sopenharmony_ci
1521141cc406Sopenharmony_ci    *max_x = buf[3] << 8 | buf[2];
1522141cc406Sopenharmony_ci    *max_y = buf[5] << 8 | buf[4];
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci    if (0 == strcmp ("ES-9000H", s->hw->sane.model)
1525141cc406Sopenharmony_ci        || 0 == strcmp ("GT-30000", s->hw->sane.model))
1526141cc406Sopenharmony_ci    {
1527141cc406Sopenharmony_ci      /* set size of current sheet, but don't clobber zoom
1528141cc406Sopenharmony_ci         settings (which should always be smaller than the
1529141cc406Sopenharmony_ci         detected sheet size) */
1530141cc406Sopenharmony_ci      double w, h;
1531141cc406Sopenharmony_ci      get_size (buf[16], buf[17], &w, &h);
1532141cc406Sopenharmony_ci      w = SANE_FIX (w * MM_PER_INCH);
1533141cc406Sopenharmony_ci      h = SANE_FIX (h * MM_PER_INCH);
1534141cc406Sopenharmony_ci      if (w < s->val[OPT_BR_X].w)
1535141cc406Sopenharmony_ci        s->val[OPT_BR_X].w = w;
1536141cc406Sopenharmony_ci      if (h < s->val[OPT_BR_Y].w)
1537141cc406Sopenharmony_ci        s->val[OPT_BR_Y].w = h;
1538141cc406Sopenharmony_ci    }
1539141cc406Sopenharmony_ci  }
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci
1542141cc406Sopenharmony_ci  if (buf[1] & EXT_STATUS_ERR)
1543141cc406Sopenharmony_ci  {
1544141cc406Sopenharmony_ci    DBG (1, "ADF: other error\n");
1545141cc406Sopenharmony_ci    status = SANE_STATUS_INVAL;
1546141cc406Sopenharmony_ci  }
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci  if (buf[1] & EXT_STATUS_PE)
1549141cc406Sopenharmony_ci  {
1550141cc406Sopenharmony_ci    DBG (1, "ADF: no paper\n");
1551141cc406Sopenharmony_ci    status = SANE_STATUS_NO_DOCS;
1552141cc406Sopenharmony_ci    return status;
1553141cc406Sopenharmony_ci  }
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  if (buf[1] & EXT_STATUS_PJ)
1556141cc406Sopenharmony_ci  {
1557141cc406Sopenharmony_ci    DBG (1, "ADF: paper jam\n");
1558141cc406Sopenharmony_ci    status = SANE_STATUS_JAMMED;
1559141cc406Sopenharmony_ci  }
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci  if (buf[1] & EXT_STATUS_OPN)
1562141cc406Sopenharmony_ci  {
1563141cc406Sopenharmony_ci    DBG (1, "ADF: cover open\n");
1564141cc406Sopenharmony_ci    status = SANE_STATUS_COVER_OPEN;
1565141cc406Sopenharmony_ci  }
1566141cc406Sopenharmony_ci
1567141cc406Sopenharmony_ci  if (buf[6] & EXT_STATUS_ERR)
1568141cc406Sopenharmony_ci  {
1569141cc406Sopenharmony_ci    DBG (1, "TPU: other error\n");
1570141cc406Sopenharmony_ci    status = SANE_STATUS_INVAL;
1571141cc406Sopenharmony_ci  }
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_ci  /* return the max. scan area for the ADF */
1574141cc406Sopenharmony_ci  if (buf[6] & EXT_STATUS_IST)
1575141cc406Sopenharmony_ci  {
1576141cc406Sopenharmony_ci    *max_x = buf[8] << 8 | buf[7];
1577141cc406Sopenharmony_ci    *max_y = buf[10] << 8 | buf[9];
1578141cc406Sopenharmony_ci  }
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_ci  /* return the max. scan area for the flatbed */
1581141cc406Sopenharmony_ci  if (s->hw->devtype == 3 && s->hw->use_extension == 0)
1582141cc406Sopenharmony_ci  {
1583141cc406Sopenharmony_ci    double w, h;
1584141cc406Sopenharmony_ci    get_size (buf[18], buf[19], &w, &h);
1585141cc406Sopenharmony_ci    *max_x = (int) (w * s->hw->dpi_range.max);
1586141cc406Sopenharmony_ci    *max_y = (int) (h * s->hw->dpi_range.max);
1587141cc406Sopenharmony_ci  }
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci  free (head);
1590141cc406Sopenharmony_ci
1591141cc406Sopenharmony_ci  return status;
1592141cc406Sopenharmony_ci}
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci/*
1595141cc406Sopenharmony_ci * reset()
1596141cc406Sopenharmony_ci *
1597141cc406Sopenharmony_ci * Send the "initialize scanner" command to the device and reset it.
1598141cc406Sopenharmony_ci *
1599141cc406Sopenharmony_ci */
1600141cc406Sopenharmony_ci
1601141cc406Sopenharmony_cistatic SANE_Status
1602141cc406Sopenharmony_cireset (Epson_Scanner * s)
1603141cc406Sopenharmony_ci{
1604141cc406Sopenharmony_ci  SANE_Status status;
1605141cc406Sopenharmony_ci  u_char param[2];
1606141cc406Sopenharmony_ci  SANE_Bool needToClose = SANE_FALSE;
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci  DBG (5, "reset()\n");
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci  if (!s->hw->cmd->initialize_scanner)
1611141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1612141cc406Sopenharmony_ci
1613141cc406Sopenharmony_ci  param[0] = ESC;
1614141cc406Sopenharmony_ci  param[1] = s->hw->cmd->initialize_scanner;
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci  if (s->fd == -1)
1617141cc406Sopenharmony_ci  {
1618141cc406Sopenharmony_ci    needToClose = SANE_TRUE;
1619141cc406Sopenharmony_ci    DBG (5, "reset calling open_scanner\n");
1620141cc406Sopenharmony_ci    if ((status = open_scanner (s)) != SANE_STATUS_GOOD)
1621141cc406Sopenharmony_ci      return status;
1622141cc406Sopenharmony_ci  }
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_ci  send (s, param, 2, &status);
1625141cc406Sopenharmony_ci  status = expect_ack (s);
1626141cc406Sopenharmony_ci
1627141cc406Sopenharmony_ci  if (needToClose)
1628141cc406Sopenharmony_ci  {
1629141cc406Sopenharmony_ci    close_scanner (s);
1630141cc406Sopenharmony_ci  }
1631141cc406Sopenharmony_ci
1632141cc406Sopenharmony_ci  return status;
1633141cc406Sopenharmony_ci}
1634141cc406Sopenharmony_ci
1635141cc406Sopenharmony_ci
1636141cc406Sopenharmony_ci/*
1637141cc406Sopenharmony_ci * close_scanner()
1638141cc406Sopenharmony_ci *
1639141cc406Sopenharmony_ci * Close the open scanner. Depending on the connection method, a different
1640141cc406Sopenharmony_ci * close function is called.
1641141cc406Sopenharmony_ci */
1642141cc406Sopenharmony_ci
1643141cc406Sopenharmony_cistatic void
1644141cc406Sopenharmony_ciclose_scanner (Epson_Scanner * s)
1645141cc406Sopenharmony_ci{
1646141cc406Sopenharmony_ci  DBG (5, "close_scanner(fd = %d)\n", s->fd);
1647141cc406Sopenharmony_ci
1648141cc406Sopenharmony_ci  if (s->fd == -1)
1649141cc406Sopenharmony_ci    return;
1650141cc406Sopenharmony_ci
1651141cc406Sopenharmony_ci  if (r_cmd_count % 2)
1652141cc406Sopenharmony_ci  {
1653141cc406Sopenharmony_ci    /* send a request_status. This toggles w_cmd_count and r_cmd_count */
1654141cc406Sopenharmony_ci    u_char param[3];
1655141cc406Sopenharmony_ci    u_char result[5];
1656141cc406Sopenharmony_ci    SANE_Status status;
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci    param[0] = ESC;
1659141cc406Sopenharmony_ci    param[1] = s->hw->cmd->request_status;
1660141cc406Sopenharmony_ci    param[2]='\0';
1661141cc406Sopenharmony_ci    send(s,param,2,&status);
1662141cc406Sopenharmony_ci    receive(s,result,4,&status);
1663141cc406Sopenharmony_ci  }
1664141cc406Sopenharmony_ci
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci  DBG (5, "w_cmd_count = %d\n",w_cmd_count);
1667141cc406Sopenharmony_ci  DBG (5, "r_cmd_count = %d\n",r_cmd_count);
1668141cc406Sopenharmony_ci
1669141cc406Sopenharmony_ci  if (w_cmd_count % 2)
1670141cc406Sopenharmony_ci  {
1671141cc406Sopenharmony_ci    int junk1,junk2;
1672141cc406Sopenharmony_ci
1673141cc406Sopenharmony_ci    /* check extended status. This toggles w_cmd_count%2 only */
1674141cc406Sopenharmony_ci    check_ext_status (s,&junk1,&junk2);
1675141cc406Sopenharmony_ci  }
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci  DBG (5, "w_cmd_count = %d\n",w_cmd_count);
1678141cc406Sopenharmony_ci  DBG (5, "r_cmd_count = %d\n",r_cmd_count);
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
1682141cc406Sopenharmony_ci  {
1683141cc406Sopenharmony_ci    sanei_scsi_close (s->fd);
1684141cc406Sopenharmony_ci  }
1685141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_PIO)
1686141cc406Sopenharmony_ci  {
1687141cc406Sopenharmony_ci    sanei_pio_close (s->fd);
1688141cc406Sopenharmony_ci  }
1689141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
1690141cc406Sopenharmony_ci  {
1691141cc406Sopenharmony_ci    sanei_usb_close (s->fd);
1692141cc406Sopenharmony_ci  }
1693141cc406Sopenharmony_ci
1694141cc406Sopenharmony_ci  s->fd = -1;
1695141cc406Sopenharmony_ci  return;
1696141cc406Sopenharmony_ci}
1697141cc406Sopenharmony_ci
1698141cc406Sopenharmony_ci/*
1699141cc406Sopenharmony_ci * open_scanner()
1700141cc406Sopenharmony_ci *
1701141cc406Sopenharmony_ci * Open the scanner device. Depending on the connection method,
1702141cc406Sopenharmony_ci * different open functions are called.
1703141cc406Sopenharmony_ci */
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_cistatic SANE_Status
1706141cc406Sopenharmony_ciopen_scanner (Epson_Scanner * s)
1707141cc406Sopenharmony_ci{
1708141cc406Sopenharmony_ci  SANE_Status status = 0;
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci  DBG (5, "open_scanner()\n");
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci  if (s->fd != -1)
1713141cc406Sopenharmony_ci  {
1714141cc406Sopenharmony_ci    DBG (5, "scanner is already open: fd = %d\n", s->fd);
1715141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;    /* no need to open the scanner */
1716141cc406Sopenharmony_ci  }
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_ci  /* don't do this for OS2: */
1719141cc406Sopenharmony_ci#ifndef HAVE_OS2_H
1720141cc406Sopenharmony_ci#if 0
1721141cc406Sopenharmony_ci  /* test the device name */
1722141cc406Sopenharmony_ci  if ((s->hw->connection != SANE_EPSON_PIO)
1723141cc406Sopenharmony_ci      && (access (s->hw->sane.name, R_OK | W_OK) != 0))
1724141cc406Sopenharmony_ci  {
1725141cc406Sopenharmony_ci    DBG (1, "sane_start: access(%s, R_OK | W_OK) failed\n", s->hw->sane.name);
1726141cc406Sopenharmony_ci    return SANE_STATUS_ACCESS_DENIED;
1727141cc406Sopenharmony_ci  }
1728141cc406Sopenharmony_ci#endif
1729141cc406Sopenharmony_ci#endif
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci
1732141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
1733141cc406Sopenharmony_ci  {
1734141cc406Sopenharmony_ci    status = sanei_scsi_open (s->hw->sane.name, &s->fd,
1735141cc406Sopenharmony_ci                              sanei_epson_scsi_sense_handler, NULL);
1736141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
1737141cc406Sopenharmony_ci    {
1738141cc406Sopenharmony_ci      DBG (1, "sane_start: %s open failed: %s\n", s->hw->sane.name,
1739141cc406Sopenharmony_ci           sane_strstatus (status));
1740141cc406Sopenharmony_ci      return status;
1741141cc406Sopenharmony_ci    }
1742141cc406Sopenharmony_ci  }
1743141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_PIO)
1744141cc406Sopenharmony_ci  {
1745141cc406Sopenharmony_ci    status = sanei_pio_open (s->hw->sane.name, &s->fd);
1746141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
1747141cc406Sopenharmony_ci    {
1748141cc406Sopenharmony_ci      DBG (1, "sane_start: %s open failed: %s\n", s->hw->sane.name,
1749141cc406Sopenharmony_ci           sane_strstatus (status));
1750141cc406Sopenharmony_ci      return status;
1751141cc406Sopenharmony_ci    }
1752141cc406Sopenharmony_ci  }
1753141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
1754141cc406Sopenharmony_ci  {
1755141cc406Sopenharmony_ci    status = sanei_usb_open (s->hw->sane.name, &s->fd);
1756141cc406Sopenharmony_ci
1757141cc406Sopenharmony_ci    return status;
1758141cc406Sopenharmony_ci  }
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1761141cc406Sopenharmony_ci}
1762141cc406Sopenharmony_ci
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_ci/*
1765141cc406Sopenharmony_ci * feed ( )
1766141cc406Sopenharmony_ci */
1767141cc406Sopenharmony_ci
1768141cc406Sopenharmony_cistatic SANE_Status
1769141cc406Sopenharmony_cifeed (Epson_Scanner * s)
1770141cc406Sopenharmony_ci{
1771141cc406Sopenharmony_ci  SANE_Status status;
1772141cc406Sopenharmony_ci  u_char params[2];
1773141cc406Sopenharmony_ci  u_char cmd = s->hw->cmd->feed;
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci  DBG (5, "feed()\n");
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci  if (!cmd)
1778141cc406Sopenharmony_ci  {
1779141cc406Sopenharmony_ci    DBG (5, "feed() is not supported\n");
1780141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1781141cc406Sopenharmony_ci  }
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_ci  params[0] = cmd;
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  send (s, params, 1, &status);
1786141cc406Sopenharmony_ci
1787141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1788141cc406Sopenharmony_ci  {
1789141cc406Sopenharmony_ci    close_scanner (s);
1790141cc406Sopenharmony_ci    return status;
1791141cc406Sopenharmony_ci  }
1792141cc406Sopenharmony_ci
1793141cc406Sopenharmony_ci  return status;
1794141cc406Sopenharmony_ci}
1795141cc406Sopenharmony_ci
1796141cc406Sopenharmony_ci
1797141cc406Sopenharmony_ci/*
1798141cc406Sopenharmony_ci * eject()
1799141cc406Sopenharmony_ci *
1800141cc406Sopenharmony_ci * Eject the current page from the ADF. The scanner is opened prior to
1801141cc406Sopenharmony_ci * sending the command and closed afterwards.
1802141cc406Sopenharmony_ci *
1803141cc406Sopenharmony_ci */
1804141cc406Sopenharmony_ci
1805141cc406Sopenharmony_cistatic SANE_Status
1806141cc406Sopenharmony_cieject (Epson_Scanner * s)
1807141cc406Sopenharmony_ci{
1808141cc406Sopenharmony_ci  SANE_Status status;
1809141cc406Sopenharmony_ci  u_char params[2];
1810141cc406Sopenharmony_ci  u_char cmd = s->hw->cmd->eject;
1811141cc406Sopenharmony_ci  SANE_Bool needToClose = SANE_FALSE;
1812141cc406Sopenharmony_ci
1813141cc406Sopenharmony_ci  DBG (5, "eject()\n");
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci  if (!cmd)
1816141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci  if (s->fd == -1)
1819141cc406Sopenharmony_ci  {
1820141cc406Sopenharmony_ci    needToClose = SANE_TRUE;
1821141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = open_scanner (s)))
1822141cc406Sopenharmony_ci      return status;
1823141cc406Sopenharmony_ci  }
1824141cc406Sopenharmony_ci
1825141cc406Sopenharmony_ci  params[0] = cmd;
1826141cc406Sopenharmony_ci
1827141cc406Sopenharmony_ci  send (s, params, 1, &status);
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != (status = expect_ack (s)))
1830141cc406Sopenharmony_ci  {
1831141cc406Sopenharmony_ci    close_scanner (s);
1832141cc406Sopenharmony_ci    return status;
1833141cc406Sopenharmony_ci  }
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_ci  if (needToClose)
1836141cc406Sopenharmony_ci    close_scanner (s);
1837141cc406Sopenharmony_ci
1838141cc406Sopenharmony_ci  return status;
1839141cc406Sopenharmony_ci}
1840141cc406Sopenharmony_ci
1841141cc406Sopenharmony_ci/*
1842141cc406Sopenharmony_ci *
1843141cc406Sopenharmony_ci *
1844141cc406Sopenharmony_ci */
1845141cc406Sopenharmony_ci
1846141cc406Sopenharmony_cistatic int num_devices = 0;     /* number of EPSON scanners attached to backend */
1847141cc406Sopenharmony_cistatic Epson_Device *first_dev = NULL;  /* first EPSON scanner in list */
1848141cc406Sopenharmony_cistatic Epson_Scanner *first_handle = NULL;
1849141cc406Sopenharmony_ci
1850141cc406Sopenharmony_ci
1851141cc406Sopenharmony_cistatic EpsonHdrUnion
1852141cc406Sopenharmony_cicommand (Epson_Scanner * s, u_char * cmd, size_t cmd_size,
1853141cc406Sopenharmony_ci         SANE_Status * status)
1854141cc406Sopenharmony_ci{
1855141cc406Sopenharmony_ci  EpsonHdrUnion hdrunion, hdrunion_bak;
1856141cc406Sopenharmony_ci  EpsonHdr head;
1857141cc406Sopenharmony_ci  u_char *buf;
1858141cc406Sopenharmony_ci  int count;
1859141cc406Sopenharmony_ci
1860141cc406Sopenharmony_ci  if (NULL == (hdrunion = walloc (EpsonHdrUnionRec)))
1861141cc406Sopenharmony_ci  {
1862141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
1863141cc406Sopenharmony_ci    *status = SANE_STATUS_NO_MEM;
1864141cc406Sopenharmony_ci    return (EpsonHdrUnion) 0;
1865141cc406Sopenharmony_ci  }
1866141cc406Sopenharmony_ci
1867141cc406Sopenharmony_ci  head = &(hdrunion->hdr);
1868141cc406Sopenharmony_ci
1869141cc406Sopenharmony_ci  send (s, cmd, cmd_size, status);
1870141cc406Sopenharmony_ci
1871141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != *status)
1872141cc406Sopenharmony_ci  {
1873141cc406Sopenharmony_ci    /* this is necessary for the GT-8000. I don't know why, but
1874141cc406Sopenharmony_ci       it seems to fix the problem. It should not have any
1875141cc406Sopenharmony_ci       ill effects on other scanners.  */
1876141cc406Sopenharmony_ci    *status = SANE_STATUS_GOOD;
1877141cc406Sopenharmony_ci    send (s, cmd, cmd_size, status);
1878141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != *status)
1879141cc406Sopenharmony_ci      return (EpsonHdrUnion) 0;
1880141cc406Sopenharmony_ci  }
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_ci  buf = (u_char *) head;
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
1885141cc406Sopenharmony_ci  {
1886141cc406Sopenharmony_ci    receive (s, buf, 4, status);
1887141cc406Sopenharmony_ci    buf += 4;
1888141cc406Sopenharmony_ci  }
1889141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
1890141cc406Sopenharmony_ci  {
1891141cc406Sopenharmony_ci    int bytes_read;
1892141cc406Sopenharmony_ci    bytes_read = receive (s, buf, 4, status);
1893141cc406Sopenharmony_ci    buf += bytes_read;
1894141cc406Sopenharmony_ci  }
1895141cc406Sopenharmony_ci  else
1896141cc406Sopenharmony_ci  {
1897141cc406Sopenharmony_ci    receive (s, buf, 1, status);
1898141cc406Sopenharmony_ci    buf += 1;
1899141cc406Sopenharmony_ci  }
1900141cc406Sopenharmony_ci
1901141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != *status)
1902141cc406Sopenharmony_ci    return (EpsonHdrUnion) 0;
1903141cc406Sopenharmony_ci
1904141cc406Sopenharmony_ci  DBG (4, "code   %02x\n", (int) head->code);
1905141cc406Sopenharmony_ci
1906141cc406Sopenharmony_ci  switch (head->code)
1907141cc406Sopenharmony_ci  {
1908141cc406Sopenharmony_ci
1909141cc406Sopenharmony_ci  case NAK:
1910141cc406Sopenharmony_ci    /* fall through */
1911141cc406Sopenharmony_ci    /* !!! is this really sufficient to report an error ? */
1912141cc406Sopenharmony_ci  case ACK:
1913141cc406Sopenharmony_ci    break;                      /* no need to read any more data after ACK or NAK */
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci  case STX:
1916141cc406Sopenharmony_ci    if (s->hw->connection == SANE_EPSON_SCSI)
1917141cc406Sopenharmony_ci    {
1918141cc406Sopenharmony_ci      /* nope */
1919141cc406Sopenharmony_ci    }
1920141cc406Sopenharmony_ci    else if (s->hw->connection == SANE_EPSON_USB)
1921141cc406Sopenharmony_ci    {
1922141cc406Sopenharmony_ci      /* we've already read the complete data */
1923141cc406Sopenharmony_ci    }
1924141cc406Sopenharmony_ci    else
1925141cc406Sopenharmony_ci    {
1926141cc406Sopenharmony_ci      receive (s, buf, 3, status);
1927141cc406Sopenharmony_ci      /*              buf += 3; */
1928141cc406Sopenharmony_ci    }
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != *status)
1931141cc406Sopenharmony_ci      return (EpsonHdrUnion) 0;
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci    DBG (4, "status %02x\n", (int) head->status);
1934141cc406Sopenharmony_ci
1935141cc406Sopenharmony_ci    count = head->count2 * 255 + head->count1;
1936141cc406Sopenharmony_ci    DBG (4, "count  %d\n", count);
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_ci    hdrunion_bak = hdrunion;
1939141cc406Sopenharmony_ci    if (NULL == (hdrunion = realloc (hdrunion,
1940141cc406Sopenharmony_ci            sizeof (EpsonHdrUnionRec) + count)))
1941141cc406Sopenharmony_ci    {
1942141cc406Sopenharmony_ci      free(hdrunion_bak);
1943141cc406Sopenharmony_ci      DBG (1, "out of memory (line %d)\n", __LINE__);
1944141cc406Sopenharmony_ci      *status = SANE_STATUS_NO_MEM;
1945141cc406Sopenharmony_ci      return (EpsonHdrUnion) 0;
1946141cc406Sopenharmony_ci    }
1947141cc406Sopenharmony_ci
1948141cc406Sopenharmony_ci    head = &(hdrunion->hdr);
1949141cc406Sopenharmony_ci
1950141cc406Sopenharmony_ci    buf = head->buf;
1951141cc406Sopenharmony_ci    receive (s, buf, count, status);
1952141cc406Sopenharmony_ci
1953141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != *status)
1954141cc406Sopenharmony_ci      return (EpsonHdrUnion) 0;
1955141cc406Sopenharmony_ci
1956141cc406Sopenharmony_ci    break;
1957141cc406Sopenharmony_ci
1958141cc406Sopenharmony_ci  default:
1959141cc406Sopenharmony_ci    if (0 == head->code)
1960141cc406Sopenharmony_ci      DBG (1, "Incompatible printer port (probably bi/directional)\n");
1961141cc406Sopenharmony_ci    else if (cmd[cmd_size - 1] == head->code)
1962141cc406Sopenharmony_ci      DBG (1, "Incompatible printer port (probably not bi/directional)\n");
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_ci    DBG (2, "Illegal response of scanner for command: %02x\n", head->code);
1965141cc406Sopenharmony_ci    break;
1966141cc406Sopenharmony_ci  }
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ci  return hdrunion;
1969141cc406Sopenharmony_ci}
1970141cc406Sopenharmony_ci
1971141cc406Sopenharmony_ci
1972141cc406Sopenharmony_ci/*
1973141cc406Sopenharmony_ci * static SANE_Status attach()
1974141cc406Sopenharmony_ci *
1975141cc406Sopenharmony_ci * Attach one device with name *dev_name to the backend.
1976141cc406Sopenharmony_ci */
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_cistatic SANE_Status
1979141cc406Sopenharmony_ciattach (const char *dev_name, Epson_Device * *devp, int type)
1980141cc406Sopenharmony_ci{
1981141cc406Sopenharmony_ci  SANE_Status status;
1982141cc406Sopenharmony_ci  Epson_Scanner *s = walloca (Epson_Scanner);
1983141cc406Sopenharmony_ci  char *str;
1984141cc406Sopenharmony_ci  struct Epson_Device *dev;
1985141cc406Sopenharmony_ci  SANE_String_Const *source_list_add = source_list;
1986141cc406Sopenharmony_ci  int port;
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci  DBG (1, "%s\n", SANE_EPSON_VERSION);
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_ci  DBG (5, "attach(%s, %d)\n", dev_name, type);
1991141cc406Sopenharmony_ci
1992141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
1993141cc406Sopenharmony_ci  {
1994141cc406Sopenharmony_ci    if (strcmp (dev->sane.name, dev_name) == 0)
1995141cc406Sopenharmony_ci    {
1996141cc406Sopenharmony_ci      if (devp)
1997141cc406Sopenharmony_ci      {
1998141cc406Sopenharmony_ci        *devp = dev;
1999141cc406Sopenharmony_ci      }
2000141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2001141cc406Sopenharmony_ci    }
2002141cc406Sopenharmony_ci  }
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
2005141cc406Sopenharmony_ci  if (!dev)
2006141cc406Sopenharmony_ci  {
2007141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
2008141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2009141cc406Sopenharmony_ci  }
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  /* check for PIO devices */
2012141cc406Sopenharmony_ci  /* can we convert the device name to an integer? This is only possible
2013141cc406Sopenharmony_ci     with PIO devices */
2014141cc406Sopenharmony_ci  port = atoi (dev_name);
2015141cc406Sopenharmony_ci  if (port != 0)
2016141cc406Sopenharmony_ci  {
2017141cc406Sopenharmony_ci    type = SANE_EPSON_PIO;
2018141cc406Sopenharmony_ci  }
2019141cc406Sopenharmony_ci
2020141cc406Sopenharmony_ci  if (strncmp
2021141cc406Sopenharmony_ci      (dev_name, SANE_EPSON_CONFIG_PIO, strlen (SANE_EPSON_CONFIG_PIO)) == 0)
2022141cc406Sopenharmony_ci  {
2023141cc406Sopenharmony_ci    /* we have a match for the PIO string and adjust the device name */
2024141cc406Sopenharmony_ci    dev_name += strlen (SANE_EPSON_CONFIG_PIO);
2025141cc406Sopenharmony_ci    dev_name = sanei_config_skip_whitespace (dev_name);
2026141cc406Sopenharmony_ci    type = SANE_EPSON_PIO;
2027141cc406Sopenharmony_ci  }
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci
2030141cc406Sopenharmony_ci  /*
2031141cc406Sopenharmony_ci   *  set dummy values.
2032141cc406Sopenharmony_ci   */
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci  s->hw = dev;
2035141cc406Sopenharmony_ci  s->hw->sane.name = NULL;
2036141cc406Sopenharmony_ci  s->hw->sane.type = "flatbed scanner";
2037141cc406Sopenharmony_ci  s->hw->sane.vendor = "Epson";
2038141cc406Sopenharmony_ci  s->hw->sane.model = NULL;
2039141cc406Sopenharmony_ci  s->hw->optical_res = 0;       /* just to have it initialized */
2040141cc406Sopenharmony_ci  s->hw->color_shuffle = SANE_FALSE;
2041141cc406Sopenharmony_ci  s->hw->extension = SANE_FALSE;
2042141cc406Sopenharmony_ci  s->hw->use_extension = SANE_FALSE;
2043141cc406Sopenharmony_ci
2044141cc406Sopenharmony_ci  s->hw->need_color_reorder = SANE_FALSE;
2045141cc406Sopenharmony_ci  s->hw->need_double_vertical = SANE_FALSE;
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ci  s->hw->cmd = &epson_cmd[EPSON_LEVEL_DEFAULT]; /* default function level */
2048141cc406Sopenharmony_ci  s->hw->connection = type;
2049141cc406Sopenharmony_ci
2050141cc406Sopenharmony_ci  DBG (3, "attach: opening %s\n", dev_name);
2051141cc406Sopenharmony_ci
2052141cc406Sopenharmony_ci  s->hw->last_res = 0;
2053141cc406Sopenharmony_ci  s->hw->last_res_preview = 0;  /* set resolution to safe values */
2054141cc406Sopenharmony_ci
2055141cc406Sopenharmony_ci  /*
2056141cc406Sopenharmony_ci   *  decide if interface is USB, SCSI or parallel.
2057141cc406Sopenharmony_ci   */
2058141cc406Sopenharmony_ci
2059141cc406Sopenharmony_ci  /*
2060141cc406Sopenharmony_ci   *  if interface is SCSI do an inquiry.
2061141cc406Sopenharmony_ci   */
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_ci  if (s->hw->connection == SANE_EPSON_SCSI)
2064141cc406Sopenharmony_ci  {
2065141cc406Sopenharmony_ci    u_char buf[INQUIRY_BUF_SIZE + 1];
2066141cc406Sopenharmony_ci    size_t buf_size = INQUIRY_BUF_SIZE;
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci    status =
2069141cc406Sopenharmony_ci      sanei_scsi_open (dev_name, &s->fd, sanei_epson_scsi_sense_handler,
2070141cc406Sopenharmony_ci                       NULL);
2071141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
2072141cc406Sopenharmony_ci    {
2073141cc406Sopenharmony_ci      DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
2074141cc406Sopenharmony_ci      return status;
2075141cc406Sopenharmony_ci    }
2076141cc406Sopenharmony_ci    DBG (3, "attach: sending INQUIRY\n");
2077141cc406Sopenharmony_ci
2078141cc406Sopenharmony_ci    status = sanei_epson_scsi_inquiry (s->fd, 0, buf, &buf_size);
2079141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
2080141cc406Sopenharmony_ci    {
2081141cc406Sopenharmony_ci      DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
2082141cc406Sopenharmony_ci      close_scanner (s);
2083141cc406Sopenharmony_ci      return status;
2084141cc406Sopenharmony_ci    }
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci    buf[INQUIRY_BUF_SIZE] = 0;
2087141cc406Sopenharmony_ci    DBG (1, ">%s<\n", buf + 8);
2088141cc406Sopenharmony_ci
2089141cc406Sopenharmony_ci    /*
2090141cc406Sopenharmony_ci     * For USB and PIO scanners this will be done later, once
2091141cc406Sopenharmony_ci     * we have communication established with the device.
2092141cc406Sopenharmony_ci     */
2093141cc406Sopenharmony_ci
2094141cc406Sopenharmony_ci    if (buf[0] != TYPE_PROCESSOR
2095141cc406Sopenharmony_ci        || strncmp ((char *) (buf + 8), "EPSON", 5) != 0
2096141cc406Sopenharmony_ci        || (strncmp ((char *) buf + 16, "SCANNER ", 8) != 0
2097141cc406Sopenharmony_ci            && strncmp ((char *) buf + 14, "SCANNER ", 8) != 0
2098141cc406Sopenharmony_ci            && strncmp ((char *) buf + 14, "Perfection", 10) != 0
2099141cc406Sopenharmony_ci            && strncmp ((char *) buf + 16, "Perfection", 10) != 0
2100141cc406Sopenharmony_ci            && strncmp ((char *) buf + 16, "Expression", 10) != 0
2101141cc406Sopenharmony_ci            && strncmp ((char *) buf + 16, "GT", 2) != 0))
2102141cc406Sopenharmony_ci    {
2103141cc406Sopenharmony_ci      DBG (1, "attach: device doesn't look like an EPSON  scanner\n");
2104141cc406Sopenharmony_ci      close_scanner (s);
2105141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2106141cc406Sopenharmony_ci    }
2107141cc406Sopenharmony_ci  }
2108141cc406Sopenharmony_ci  /* use the SANEI functions to handle a PIO device */
2109141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_PIO)
2110141cc406Sopenharmony_ci  {
2111141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = sanei_pio_open (dev_name, &s->fd)))
2112141cc406Sopenharmony_ci    {
2113141cc406Sopenharmony_ci      DBG (1, "Cannot open %s as a parallel-port device: %s\n",
2114141cc406Sopenharmony_ci           dev_name, sane_strstatus (status));
2115141cc406Sopenharmony_ci      return status;
2116141cc406Sopenharmony_ci    }
2117141cc406Sopenharmony_ci  }
2118141cc406Sopenharmony_ci  /* use the SANEI functions to handle a USB device */
2119141cc406Sopenharmony_ci  else if (s->hw->connection == SANE_EPSON_USB)
2120141cc406Sopenharmony_ci  {
2121141cc406Sopenharmony_ci    SANE_Word vendor;
2122141cc406Sopenharmony_ci    SANE_Word product;
2123141cc406Sopenharmony_ci    SANE_Bool isLibUSB;
2124141cc406Sopenharmony_ci
2125141cc406Sopenharmony_ci    isLibUSB = (strncmp (dev_name, "libusb:", strlen ("libusb:")) == 0);
2126141cc406Sopenharmony_ci
2127141cc406Sopenharmony_ci    if ((!isLibUSB) && (strlen (dev_name) == 0))
2128141cc406Sopenharmony_ci    {
2129141cc406Sopenharmony_ci      int i;
2130141cc406Sopenharmony_ci      int numIds;
2131141cc406Sopenharmony_ci
2132141cc406Sopenharmony_ci      numIds = sanei_epson_getNumberOfUSBProductIds ();
2133141cc406Sopenharmony_ci
2134141cc406Sopenharmony_ci      for (i = 0; i < numIds; i++)
2135141cc406Sopenharmony_ci      {
2136141cc406Sopenharmony_ci        product = sanei_epson_usb_product_ids[i];
2137141cc406Sopenharmony_ci        vendor = 0x4b8;
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_ci        status = sanei_usb_find_devices (vendor, product, attach_one_usb);
2140141cc406Sopenharmony_ci      }
2141141cc406Sopenharmony_ci      return SANE_STATUS_INVAL; /* return - the attach_one_usb()
2142141cc406Sopenharmony_ci                                   will take care of this */
2143141cc406Sopenharmony_ci    }
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci    status = sanei_usb_open (dev_name, &s->fd);
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
2148141cc406Sopenharmony_ci    {
2149141cc406Sopenharmony_ci      return status;
2150141cc406Sopenharmony_ci    }
2151141cc406Sopenharmony_ci
2152141cc406Sopenharmony_ci    /* if the sanei_usb_get_vendor_product call is not supported,
2153141cc406Sopenharmony_ci       then we just ignore this and rely on the user to config
2154141cc406Sopenharmony_ci       the correct device.
2155141cc406Sopenharmony_ci     */
2156141cc406Sopenharmony_ci
2157141cc406Sopenharmony_ci    if (sanei_usb_get_vendor_product (s->fd, &vendor, &product) ==
2158141cc406Sopenharmony_ci        SANE_STATUS_GOOD)
2159141cc406Sopenharmony_ci    {
2160141cc406Sopenharmony_ci      int i;                    /* loop variable */
2161141cc406Sopenharmony_ci      int numIds;
2162141cc406Sopenharmony_ci      SANE_Bool is_valid;
2163141cc406Sopenharmony_ci
2164141cc406Sopenharmony_ci      /* check the vendor ID to see if we are dealing with an EPSON device */
2165141cc406Sopenharmony_ci      if (vendor != SANE_EPSON_VENDOR_ID)
2166141cc406Sopenharmony_ci      {
2167141cc406Sopenharmony_ci        /* this is not a supported vendor ID */
2168141cc406Sopenharmony_ci        DBG (1,
2169141cc406Sopenharmony_ci             "The device at %s is not manufactured by EPSON (vendor id=0x%x)\n",
2170141cc406Sopenharmony_ci             dev_name, vendor);
2171141cc406Sopenharmony_ci        sanei_usb_close (s->fd);
2172141cc406Sopenharmony_ci        s->fd = -1;
2173141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
2174141cc406Sopenharmony_ci      }
2175141cc406Sopenharmony_ci
2176141cc406Sopenharmony_ci      numIds = sanei_epson_getNumberOfUSBProductIds ();
2177141cc406Sopenharmony_ci      is_valid = SANE_FALSE;
2178141cc406Sopenharmony_ci      i = 0;
2179141cc406Sopenharmony_ci
2180141cc406Sopenharmony_ci      /* check all known product IDs to verify that we know
2181141cc406Sopenharmony_ci         about the device */
2182141cc406Sopenharmony_ci      while (i != numIds && !is_valid)
2183141cc406Sopenharmony_ci      {
2184141cc406Sopenharmony_ci        if (product == sanei_epson_usb_product_ids[i])
2185141cc406Sopenharmony_ci          is_valid = SANE_TRUE;
2186141cc406Sopenharmony_ci
2187141cc406Sopenharmony_ci        i++;
2188141cc406Sopenharmony_ci      }
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_ci      if (is_valid == SANE_FALSE)
2191141cc406Sopenharmony_ci      {
2192141cc406Sopenharmony_ci        DBG (1,
2193141cc406Sopenharmony_ci             "The device at %s is not a supported EPSON scanner (product id=0x%x)\n",
2194141cc406Sopenharmony_ci             dev_name, product);
2195141cc406Sopenharmony_ci        sanei_usb_close (s->fd);
2196141cc406Sopenharmony_ci        s->fd = -1;
2197141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
2198141cc406Sopenharmony_ci      }
2199141cc406Sopenharmony_ci      DBG (1, "Found valid EPSON scanner: 0x%x/0x%x (vendorID/productID)\n",
2200141cc406Sopenharmony_ci           vendor, product);
2201141cc406Sopenharmony_ci    }
2202141cc406Sopenharmony_ci    else
2203141cc406Sopenharmony_ci    {
2204141cc406Sopenharmony_ci      DBG (1,
2205141cc406Sopenharmony_ci           "Cannot use IOCTL interface to verify that device is a scanner - will continue\n");
2206141cc406Sopenharmony_ci    }
2207141cc406Sopenharmony_ci  }
2208141cc406Sopenharmony_ci
2209141cc406Sopenharmony_ci  /*
2210141cc406Sopenharmony_ci   * Initialize the scanner (ESC @).
2211141cc406Sopenharmony_ci   */
2212141cc406Sopenharmony_ci  reset (s);
2213141cc406Sopenharmony_ci
2214141cc406Sopenharmony_ci
2215141cc406Sopenharmony_ci
2216141cc406Sopenharmony_ci  /*
2217141cc406Sopenharmony_ci   *  Identification Request (ESC I).
2218141cc406Sopenharmony_ci   */
2219141cc406Sopenharmony_ci  if (s->hw->cmd->request_identity != 0)
2220141cc406Sopenharmony_ci  {
2221141cc406Sopenharmony_ci    status = get_identity_information (s);
2222141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
2223141cc406Sopenharmony_ci      return status;
2224141cc406Sopenharmony_ci  }                             /* request identity */
2225141cc406Sopenharmony_ci
2226141cc406Sopenharmony_ci
2227141cc406Sopenharmony_ci  /*
2228141cc406Sopenharmony_ci   * Check for "Request Identity 2" command. If this command is available
2229141cc406Sopenharmony_ci   * get the information from the scanner and store it in dev
2230141cc406Sopenharmony_ci   */
2231141cc406Sopenharmony_ci
2232141cc406Sopenharmony_ci  if (s->hw->cmd->request_identity2 != 0)
2233141cc406Sopenharmony_ci  {
2234141cc406Sopenharmony_ci    status = get_identity2_information (s);
2235141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
2236141cc406Sopenharmony_ci      return status;
2237141cc406Sopenharmony_ci  }                             /* request identity 2 */
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_ci
2240141cc406Sopenharmony_ci  /*
2241141cc406Sopenharmony_ci   * Check for the max. supported color depth and assign
2242141cc406Sopenharmony_ci   * the values to the bitDepthList.
2243141cc406Sopenharmony_ci   */
2244141cc406Sopenharmony_ci
2245141cc406Sopenharmony_ci  bitDepthList = malloc (sizeof (SANE_Word) * 4);
2246141cc406Sopenharmony_ci  if (bitDepthList == NULL)
2247141cc406Sopenharmony_ci  {
2248141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
2249141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2250141cc406Sopenharmony_ci  }
2251141cc406Sopenharmony_ci
2252141cc406Sopenharmony_ci  bitDepthList[0] = 1;          /* we start with one element in the list */
2253141cc406Sopenharmony_ci  bitDepthList[1] = 8;          /* 8bit is the default */
2254141cc406Sopenharmony_ci
2255141cc406Sopenharmony_ci  if (set_data_format (s, 16) == SANE_STATUS_GOOD)
2256141cc406Sopenharmony_ci  {
2257141cc406Sopenharmony_ci    s->hw->maxDepth = 16;
2258141cc406Sopenharmony_ci
2259141cc406Sopenharmony_ci    bitDepthList[0]++;
2260141cc406Sopenharmony_ci    bitDepthList[bitDepthList[0]] = 16;
2261141cc406Sopenharmony_ci
2262141cc406Sopenharmony_ci  }
2263141cc406Sopenharmony_ci  else if (set_data_format (s, 14) == SANE_STATUS_GOOD)
2264141cc406Sopenharmony_ci  {
2265141cc406Sopenharmony_ci    s->hw->maxDepth = 14;
2266141cc406Sopenharmony_ci
2267141cc406Sopenharmony_ci    bitDepthList[0]++;
2268141cc406Sopenharmony_ci    bitDepthList[bitDepthList[0]] = 14;
2269141cc406Sopenharmony_ci  }
2270141cc406Sopenharmony_ci  else if (set_data_format (s, 12) == SANE_STATUS_GOOD)
2271141cc406Sopenharmony_ci  {
2272141cc406Sopenharmony_ci    s->hw->maxDepth = 12;
2273141cc406Sopenharmony_ci
2274141cc406Sopenharmony_ci    bitDepthList[0]++;
2275141cc406Sopenharmony_ci    bitDepthList[bitDepthList[0]] = 12;
2276141cc406Sopenharmony_ci  }
2277141cc406Sopenharmony_ci  else
2278141cc406Sopenharmony_ci  {
2279141cc406Sopenharmony_ci    s->hw->maxDepth = 8;
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_ci    /* the default depth is already in the list */
2282141cc406Sopenharmony_ci  }
2283141cc406Sopenharmony_ci
2284141cc406Sopenharmony_ci  DBG (1, "Max. supported color depth = %d\n", s->hw->maxDepth);
2285141cc406Sopenharmony_ci
2286141cc406Sopenharmony_ci
2287141cc406Sopenharmony_ci  /*
2288141cc406Sopenharmony_ci   * Check for "request focus position" command. If this command is
2289141cc406Sopenharmony_ci   * supported, then the scanner does also support the "set focus
2290141cc406Sopenharmony_ci   * position" command.
2291141cc406Sopenharmony_ci   */
2292141cc406Sopenharmony_ci
2293141cc406Sopenharmony_ci  if (request_focus_position (s, &s->currentFocusPosition) ==
2294141cc406Sopenharmony_ci      SANE_STATUS_GOOD)
2295141cc406Sopenharmony_ci  {
2296141cc406Sopenharmony_ci    DBG (1, "Enabling 'Set Focus' support\n");
2297141cc406Sopenharmony_ci    s->hw->focusSupport = SANE_TRUE;
2298141cc406Sopenharmony_ci    s->opt[OPT_FOCUS].cap &= ~SANE_CAP_INACTIVE;
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci    /* reflect the current focus position in the GUI */
2301141cc406Sopenharmony_ci    if (s->currentFocusPosition < 0x4C)
2302141cc406Sopenharmony_ci    {
2303141cc406Sopenharmony_ci      /* focus on glass */
2304141cc406Sopenharmony_ci      s->val[OPT_FOCUS].w = 0;
2305141cc406Sopenharmony_ci    }
2306141cc406Sopenharmony_ci    else
2307141cc406Sopenharmony_ci    {
2308141cc406Sopenharmony_ci      /* focus 2.5mm above glass */
2309141cc406Sopenharmony_ci      s->val[OPT_FOCUS].w = 1;
2310141cc406Sopenharmony_ci    }
2311141cc406Sopenharmony_ci
2312141cc406Sopenharmony_ci  }
2313141cc406Sopenharmony_ci  else
2314141cc406Sopenharmony_ci  {
2315141cc406Sopenharmony_ci    DBG (1, "Disabling 'Set Focus' support\n");
2316141cc406Sopenharmony_ci    s->hw->focusSupport = SANE_FALSE;
2317141cc406Sopenharmony_ci    s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE;
2318141cc406Sopenharmony_ci    s->val[OPT_FOCUS].w = 0;    /* on glass - just in case */
2319141cc406Sopenharmony_ci  }
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci
2322141cc406Sopenharmony_ci
2323141cc406Sopenharmony_ci/*
2324141cc406Sopenharmony_ci *  Set defaults for no extension.
2325141cc406Sopenharmony_ci */
2326141cc406Sopenharmony_ci
2327141cc406Sopenharmony_ci  dev->x_range = &dev->fbf_x_range;
2328141cc406Sopenharmony_ci  dev->y_range = &dev->fbf_y_range;
2329141cc406Sopenharmony_ci
2330141cc406Sopenharmony_ci/*
2331141cc406Sopenharmony_ci * Correct for a firmware bug in some Perfection 1650 scanners:
2332141cc406Sopenharmony_ci * Firmware version 1.08 reports only half the vertical scan area, we have
2333141cc406Sopenharmony_ci * to double the number. To find out if we have to do this, we just compare
2334141cc406Sopenharmony_ci * is the vertical range is smaller than the horizontal range.
2335141cc406Sopenharmony_ci */
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_ci  if ((dev->x_range->max - dev->x_range->min) >
2338141cc406Sopenharmony_ci      (dev->y_range->max - dev->y_range->min))
2339141cc406Sopenharmony_ci  {
2340141cc406Sopenharmony_ci    dev->y_range->max += (dev->y_range->max - dev->y_range->min);
2341141cc406Sopenharmony_ci    dev->need_double_vertical = SANE_TRUE;
2342141cc406Sopenharmony_ci    dev->need_color_reorder = SANE_TRUE;
2343141cc406Sopenharmony_ci  }
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci
2346141cc406Sopenharmony_ci/*
2347141cc406Sopenharmony_ci *  Extended status flag request (ESC f).
2348141cc406Sopenharmony_ci *    this also requests the scanner device name from the scanner
2349141cc406Sopenharmony_ci */
2350141cc406Sopenharmony_ci  /*
2351141cc406Sopenharmony_ci   * because we are also using the device name from this command,
2352141cc406Sopenharmony_ci   * we have to run this block even if the scanner does not report
2353141cc406Sopenharmony_ci   * an extension. The extensions are only reported if the ADF or
2354141cc406Sopenharmony_ci   * the TPU are actually detected.
2355141cc406Sopenharmony_ci   */
2356141cc406Sopenharmony_ci  if (s->hw->cmd->request_extended_status != 0)
2357141cc406Sopenharmony_ci  {
2358141cc406Sopenharmony_ci    u_char *buf;
2359141cc406Sopenharmony_ci    u_char params[2];
2360141cc406Sopenharmony_ci    EpsonHdr head;
2361141cc406Sopenharmony_ci
2362141cc406Sopenharmony_ci    params[0] = ESC;
2363141cc406Sopenharmony_ci    params[1] = s->hw->cmd->request_extended_status;
2364141cc406Sopenharmony_ci
2365141cc406Sopenharmony_ci    if (NULL == (head = (EpsonHdr) command (s, params, 2, &status)))
2366141cc406Sopenharmony_ci    {
2367141cc406Sopenharmony_ci      DBG (1, "Extended status flag request failed\n");
2368141cc406Sopenharmony_ci      dev->sane.model = strdup ("Unknown model");
2369141cc406Sopenharmony_ci      *source_list_add++ = FBF_STR;
2370141cc406Sopenharmony_ci    }
2371141cc406Sopenharmony_ci    else
2372141cc406Sopenharmony_ci    {
2373141cc406Sopenharmony_ci      buf = &head->buf[0];
2374141cc406Sopenharmony_ci
2375141cc406Sopenharmony_ci/*
2376141cc406Sopenharmony_ci *  Add the flatbed option to the source list
2377141cc406Sopenharmony_ci */
2378141cc406Sopenharmony_ci
2379141cc406Sopenharmony_ci      *source_list_add++ = FBF_STR;
2380141cc406Sopenharmony_ci
2381141cc406Sopenharmony_ci      s->hw->devtype = buf[11] >> 6;
2382141cc406Sopenharmony_ci
2383141cc406Sopenharmony_ci/*
2384141cc406Sopenharmony_ci *      Get the device name and copy it to dev->sane.model.
2385141cc406Sopenharmony_ci *      The device name starts at buf[0x1A] and is up to 16 bytes long
2386141cc406Sopenharmony_ci *      We are overwriting whatever was set previously!
2387141cc406Sopenharmony_ci */
2388141cc406Sopenharmony_ci      {
2389141cc406Sopenharmony_ci        char device_name[DEVICE_NAME_LEN + 1];
2390141cc406Sopenharmony_ci        char *end_ptr;
2391141cc406Sopenharmony_ci        int len;
2392141cc406Sopenharmony_ci
2393141cc406Sopenharmony_ci        /* make sure that the end of string is marked */
2394141cc406Sopenharmony_ci        device_name[DEVICE_NAME_LEN] = '\0';
2395141cc406Sopenharmony_ci
2396141cc406Sopenharmony_ci        /* copy the string to an area where we can work with it */
2397141cc406Sopenharmony_ci        memcpy (device_name, buf + 0x1A, DEVICE_NAME_LEN);
2398141cc406Sopenharmony_ci        end_ptr = strchr (device_name, ' ');
2399141cc406Sopenharmony_ci        if (end_ptr != NULL)
2400141cc406Sopenharmony_ci        {
2401141cc406Sopenharmony_ci          *end_ptr = '\0';
2402141cc406Sopenharmony_ci        }
2403141cc406Sopenharmony_ci
2404141cc406Sopenharmony_ci        len = strlen (device_name);
2405141cc406Sopenharmony_ci
2406141cc406Sopenharmony_ci        str = malloc (len + 1);
2407141cc406Sopenharmony_ci        str[len] = '\0';
2408141cc406Sopenharmony_ci
2409141cc406Sopenharmony_ci        dev->sane.model = (char *) memcpy (str, device_name, len);
2410141cc406Sopenharmony_ci      }
2411141cc406Sopenharmony_ci/*
2412141cc406Sopenharmony_ci *  ADF
2413141cc406Sopenharmony_ci */
2414141cc406Sopenharmony_ci
2415141cc406Sopenharmony_ci      if (dev->extension && (buf[1] & EXT_STATUS_IST))
2416141cc406Sopenharmony_ci      {
2417141cc406Sopenharmony_ci        DBG (1, "ADF detected\n");
2418141cc406Sopenharmony_ci
2419141cc406Sopenharmony_ci        /* the GT-30000 does not report the ADF scan area */
2420141cc406Sopenharmony_ci        if ((strcmp (dev->sane.model, "GT-30000") == 0) ||
2421141cc406Sopenharmony_ci            (strcmp (dev->sane.model, "ES-9000H") == 0))
2422141cc406Sopenharmony_ci        {
2423141cc406Sopenharmony_ci          fix_up_extended_status_reply ((const char *) buf + 26, buf);
2424141cc406Sopenharmony_ci
2425141cc406Sopenharmony_ci          dev->duplexSupport = (buf[0] & 0x10) != 0;
2426141cc406Sopenharmony_ci          if (dev->duplexSupport)
2427141cc406Sopenharmony_ci          {
2428141cc406Sopenharmony_ci            DBG (1, "Found DUPLEX ADF\n");
2429141cc406Sopenharmony_ci          }
2430141cc406Sopenharmony_ci
2431141cc406Sopenharmony_ci
2432141cc406Sopenharmony_ci
2433141cc406Sopenharmony_ci
2434141cc406Sopenharmony_ci        }
2435141cc406Sopenharmony_ci
2436141cc406Sopenharmony_ci        if (buf[1] & EXT_STATUS_EN)
2437141cc406Sopenharmony_ci        {
2438141cc406Sopenharmony_ci          DBG (1, "ADF is enabled\n");
2439141cc406Sopenharmony_ci          dev->x_range = &dev->adf_x_range;
2440141cc406Sopenharmony_ci          dev->y_range = &dev->adf_y_range;
2441141cc406Sopenharmony_ci        }
2442141cc406Sopenharmony_ci
2443141cc406Sopenharmony_ci        dev->adf_x_range.min = 0;
2444141cc406Sopenharmony_ci        dev->adf_x_range.max =
2445141cc406Sopenharmony_ci          SANE_FIX ((buf[3] << 8 | buf[2]) * 25.4 / dev->dpi_range.max);
2446141cc406Sopenharmony_ci        dev->adf_x_range.quant = 0;
2447141cc406Sopenharmony_ci
2448141cc406Sopenharmony_ci        dev->adf_max_x = buf[3] << 8 | buf[2];
2449141cc406Sopenharmony_ci
2450141cc406Sopenharmony_ci        dev->adf_y_range.min = 0;
2451141cc406Sopenharmony_ci        dev->adf_y_range.max =
2452141cc406Sopenharmony_ci          SANE_FIX ((buf[5] << 8 | buf[4]) * 25.4 / dev->dpi_range.max);
2453141cc406Sopenharmony_ci        dev->adf_y_range.quant = 0;
2454141cc406Sopenharmony_ci
2455141cc406Sopenharmony_ci        dev->adf_max_y = buf[5] << 8 | buf[4];
2456141cc406Sopenharmony_ci
2457141cc406Sopenharmony_ci        DBG (5, "adf tlx %f tly %f brx %f bry %f [mm]\n",
2458141cc406Sopenharmony_ci             SANE_UNFIX (dev->adf_x_range.min),
2459141cc406Sopenharmony_ci             SANE_UNFIX (dev->adf_y_range.min),
2460141cc406Sopenharmony_ci             SANE_UNFIX (dev->adf_x_range.max),
2461141cc406Sopenharmony_ci             SANE_UNFIX (dev->adf_y_range.max));
2462141cc406Sopenharmony_ci
2463141cc406Sopenharmony_ci        *source_list_add++ = ADF_STR;
2464141cc406Sopenharmony_ci
2465141cc406Sopenharmony_ci        dev->ADF = SANE_TRUE;
2466141cc406Sopenharmony_ci      }
2467141cc406Sopenharmony_ci
2468141cc406Sopenharmony_ci
2469141cc406Sopenharmony_ci/*
2470141cc406Sopenharmony_ci *  TPU
2471141cc406Sopenharmony_ci */
2472141cc406Sopenharmony_ci
2473141cc406Sopenharmony_ci      if (dev->extension && (buf[6] & EXT_STATUS_IST))
2474141cc406Sopenharmony_ci      {
2475141cc406Sopenharmony_ci        DBG (1, "TPU detected\n");
2476141cc406Sopenharmony_ci
2477141cc406Sopenharmony_ci        if (buf[6] & EXT_STATUS_EN)
2478141cc406Sopenharmony_ci        {
2479141cc406Sopenharmony_ci          DBG (1, "TPU is enabled\n");
2480141cc406Sopenharmony_ci          dev->x_range = &dev->tpu_x_range;
2481141cc406Sopenharmony_ci          dev->y_range = &dev->tpu_y_range;
2482141cc406Sopenharmony_ci        }
2483141cc406Sopenharmony_ci
2484141cc406Sopenharmony_ci        dev->tpu_x_range.min = 0;
2485141cc406Sopenharmony_ci        dev->tpu_x_range.max =
2486141cc406Sopenharmony_ci          SANE_FIX ((buf[8] << 8 | buf[7]) * 25.4 / dev->dpi_range.max);
2487141cc406Sopenharmony_ci        dev->tpu_x_range.quant = 0;
2488141cc406Sopenharmony_ci
2489141cc406Sopenharmony_ci        dev->tpu_y_range.min = 0;
2490141cc406Sopenharmony_ci        dev->tpu_y_range.max =
2491141cc406Sopenharmony_ci          SANE_FIX ((buf[10] << 8 | buf[9]) * 25.4 / dev->dpi_range.max);
2492141cc406Sopenharmony_ci        dev->tpu_y_range.quant = 0;
2493141cc406Sopenharmony_ci
2494141cc406Sopenharmony_ci        /*
2495141cc406Sopenharmony_ci         * Check for Perfection 4990 photo/GT-X800 scanner.
2496141cc406Sopenharmony_ci         * This scanner only report 3200 dpi back.
2497141cc406Sopenharmony_ci         * The scanner physically supports 4800 dpi.
2498141cc406Sopenharmony_ci         * This is simulated here...
2499141cc406Sopenharmony_ci         * Further details read:
2500141cc406Sopenharmony_ci         * EPSON Programming guide for EPSON Color Image Scanner Perfection 4990
2501141cc406Sopenharmony_ci         */
2502141cc406Sopenharmony_ci        if (strncmp((char *) buf + 0x1A,"GT-X800",7) == 0)
2503141cc406Sopenharmony_ci        {
2504141cc406Sopenharmony_ci          dev->tpu_x_range.max = (dev->tpu_x_range.max/32)*48;
2505141cc406Sopenharmony_ci          dev->tpu_y_range.max = (dev->tpu_y_range.max/32)*48;
2506141cc406Sopenharmony_ci          DBG (5, "dpi_range.max %x \n",  dev->dpi_range.max);
2507141cc406Sopenharmony_ci        }
2508141cc406Sopenharmony_ci
2509141cc406Sopenharmony_ci        DBG (5, "tpu tlx %f tly %f brx %f bry %f [mm]\n",
2510141cc406Sopenharmony_ci             SANE_UNFIX (dev->tpu_x_range.min),
2511141cc406Sopenharmony_ci             SANE_UNFIX (dev->tpu_y_range.min),
2512141cc406Sopenharmony_ci             SANE_UNFIX (dev->tpu_x_range.max),
2513141cc406Sopenharmony_ci             SANE_UNFIX (dev->tpu_y_range.max));
2514141cc406Sopenharmony_ci
2515141cc406Sopenharmony_ci        *source_list_add++ = TPU_STR;
2516141cc406Sopenharmony_ci
2517141cc406Sopenharmony_ci        dev->TPU = SANE_TRUE;
2518141cc406Sopenharmony_ci      }
2519141cc406Sopenharmony_ci
2520141cc406Sopenharmony_ci/*
2521141cc406Sopenharmony_ci *      Get the device name and copy it to dev->sane.model.
2522141cc406Sopenharmony_ci *      The device name starts at buf[0x1A] and is up to 16 bytes long
2523141cc406Sopenharmony_ci *      We are overwriting whatever was set previously!
2524141cc406Sopenharmony_ci */
2525141cc406Sopenharmony_ci      {
2526141cc406Sopenharmony_ci        char device_name[DEVICE_NAME_LEN + 1];
2527141cc406Sopenharmony_ci        char *end_ptr;
2528141cc406Sopenharmony_ci        int len;
2529141cc406Sopenharmony_ci
2530141cc406Sopenharmony_ci        /* make sure that the end of string is marked */
2531141cc406Sopenharmony_ci        device_name[DEVICE_NAME_LEN] = '\0';
2532141cc406Sopenharmony_ci
2533141cc406Sopenharmony_ci        /* copy the string to an area where we can work with it */
2534141cc406Sopenharmony_ci        memcpy (device_name, buf + 0x1A, DEVICE_NAME_LEN);
2535141cc406Sopenharmony_ci        end_ptr = strchr (device_name, ' ');
2536141cc406Sopenharmony_ci        if (end_ptr != NULL)
2537141cc406Sopenharmony_ci        {
2538141cc406Sopenharmony_ci          *end_ptr = '\0';
2539141cc406Sopenharmony_ci        }
2540141cc406Sopenharmony_ci
2541141cc406Sopenharmony_ci        len = strlen (device_name);
2542141cc406Sopenharmony_ci
2543141cc406Sopenharmony_ci        str = malloc (len + 1);
2544141cc406Sopenharmony_ci        str[len] = '\0';
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci        /* finally copy the device name to the structure */
2547141cc406Sopenharmony_ci        dev->sane.model = (char *) memcpy (str, device_name, len);
2548141cc406Sopenharmony_ci      }
2549141cc406Sopenharmony_ci    }
2550141cc406Sopenharmony_ci  }
2551141cc406Sopenharmony_ci  else                          /* command is not known */
2552141cc406Sopenharmony_ci  {
2553141cc406Sopenharmony_ci    dev->sane.model = strdup ("EPSON Scanner");
2554141cc406Sopenharmony_ci  }
2555141cc406Sopenharmony_ci
2556141cc406Sopenharmony_ci  *source_list_add = NULL;      /* add end marker to source list */
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_ci  DBG (1, "scanner model: %s\n", dev->sane.model);
2559141cc406Sopenharmony_ci
2560141cc406Sopenharmony_ci  /* establish defaults */
2561141cc406Sopenharmony_ci  s->hw->need_reset_on_source_change = SANE_FALSE;
2562141cc406Sopenharmony_ci
2563141cc406Sopenharmony_ci  if (strcmp ("ES-9000H", dev->sane.model) == 0 ||
2564141cc406Sopenharmony_ci      strcmp ("GT-30000", dev->sane.model) == 0)
2565141cc406Sopenharmony_ci  {
2566141cc406Sopenharmony_ci    s->hw->cmd->set_focus_position = 0;
2567141cc406Sopenharmony_ci    s->hw->cmd->feed = 0x19;
2568141cc406Sopenharmony_ci  }
2569141cc406Sopenharmony_ci  else if (strcmp ("GT-8200", dev->sane.model) == 0 ||
2570141cc406Sopenharmony_ci           strcmp ("Perfection1650", dev->sane.model) == 0 ||
2571141cc406Sopenharmony_ci                 strcmp ("Perfection1640", dev->sane.model) == 0 ||
2572141cc406Sopenharmony_ci                 strcmp ("GT-8700", dev->sane.model) == 0)
2573141cc406Sopenharmony_ci  {
2574141cc406Sopenharmony_ci    s->hw->cmd->feed = 0;
2575141cc406Sopenharmony_ci    s->hw->cmd->set_focus_position = 0;
2576141cc406Sopenharmony_ci    s->hw->need_reset_on_source_change = SANE_TRUE;
2577141cc406Sopenharmony_ci  }
2578141cc406Sopenharmony_ci
2579141cc406Sopenharmony_ci
2580141cc406Sopenharmony_ci/*
2581141cc406Sopenharmony_ci *  Set values for quick format "max" entry.
2582141cc406Sopenharmony_ci */
2583141cc406Sopenharmony_ci
2584141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].tl_x = dev->x_range->min;
2585141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].tl_y = dev->y_range->min;
2586141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].br_x = dev->x_range->max;
2587141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].br_y = dev->y_range->max;
2588141cc406Sopenharmony_ci
2589141cc406Sopenharmony_ci
2590141cc406Sopenharmony_ci/*
2591141cc406Sopenharmony_ci *      Now we can finally set the device name:
2592141cc406Sopenharmony_ci */
2593141cc406Sopenharmony_ci  str = malloc (strlen (dev_name) + 1);
2594141cc406Sopenharmony_ci  dev->sane.name = strcpy (str, dev_name);
2595141cc406Sopenharmony_ci
2596141cc406Sopenharmony_ci  close_scanner (s);
2597141cc406Sopenharmony_ci
2598141cc406Sopenharmony_ci  /*
2599141cc406Sopenharmony_ci   * we are done with this one, prepare for the next scanner:
2600141cc406Sopenharmony_ci   */
2601141cc406Sopenharmony_ci
2602141cc406Sopenharmony_ci  ++num_devices;
2603141cc406Sopenharmony_ci  dev->next = first_dev;
2604141cc406Sopenharmony_ci  first_dev = dev;
2605141cc406Sopenharmony_ci
2606141cc406Sopenharmony_ci  if (devp)
2607141cc406Sopenharmony_ci  {
2608141cc406Sopenharmony_ci    *devp = dev;
2609141cc406Sopenharmony_ci  }
2610141cc406Sopenharmony_ci
2611141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2612141cc406Sopenharmony_ci}
2613141cc406Sopenharmony_ci
2614141cc406Sopenharmony_ci
2615141cc406Sopenharmony_ci
2616141cc406Sopenharmony_ci/*
2617141cc406Sopenharmony_ci * attach_one()
2618141cc406Sopenharmony_ci *
2619141cc406Sopenharmony_ci * Part of the SANE API: Attaches the scanner with the device name in *dev.
2620141cc406Sopenharmony_ci */
2621141cc406Sopenharmony_ci
2622141cc406Sopenharmony_cistatic SANE_Status
2623141cc406Sopenharmony_ciattach_one (const char *dev)
2624141cc406Sopenharmony_ci{
2625141cc406Sopenharmony_ci  DBG (5, "attach_one(%s)\n", dev);
2626141cc406Sopenharmony_ci
2627141cc406Sopenharmony_ci  return attach (dev, 0, SANE_EPSON_SCSI);
2628141cc406Sopenharmony_ci}
2629141cc406Sopenharmony_ci
2630141cc406Sopenharmony_ciSANE_Status
2631141cc406Sopenharmony_ciattach_one_usb (SANE_String_Const devname)
2632141cc406Sopenharmony_ci{
2633141cc406Sopenharmony_ci  int len = strlen (devname);
2634141cc406Sopenharmony_ci  char *attach_string;
2635141cc406Sopenharmony_ci
2636141cc406Sopenharmony_ci  DBG (5, "attach_one_usb(%s)\n", devname);
2637141cc406Sopenharmony_ci
2638141cc406Sopenharmony_ci  attach_string = alloca (len + 5);
2639141cc406Sopenharmony_ci  if (attach_string == NULL)
2640141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2641141cc406Sopenharmony_ci
2642141cc406Sopenharmony_ci  return attach (devname, 0, SANE_EPSON_USB);
2643141cc406Sopenharmony_ci}
2644141cc406Sopenharmony_ci
2645141cc406Sopenharmony_ci/*
2646141cc406Sopenharmony_ci * sane_init()
2647141cc406Sopenharmony_ci *
2648141cc406Sopenharmony_ci *
2649141cc406Sopenharmony_ci */
2650141cc406Sopenharmony_ciSANE_Status
2651141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
2652141cc406Sopenharmony_ci{
2653141cc406Sopenharmony_ci  size_t len;
2654141cc406Sopenharmony_ci  FILE *fp;
2655141cc406Sopenharmony_ci
2656141cc406Sopenharmony_ci  (void) authorize;             /* get rid of compiler warning */
2657141cc406Sopenharmony_ci
2658141cc406Sopenharmony_ci  /* sanei_authorization(devicename, STRINGIFY(BACKEND_NAME), auth_callback); */
2659141cc406Sopenharmony_ci
2660141cc406Sopenharmony_ci  DBG_INIT ();
2661141cc406Sopenharmony_ci#if defined PACKAGE && defined VERSION
2662141cc406Sopenharmony_ci  DBG (2, "sane_init: " PACKAGE " " VERSION "\n");
2663141cc406Sopenharmony_ci#endif
2664141cc406Sopenharmony_ci
2665141cc406Sopenharmony_ci  if (version_code != NULL)
2666141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, SANE_EPSON_BUILD);
2667141cc406Sopenharmony_ci
2668141cc406Sopenharmony_ci  sanei_usb_init ();
2669141cc406Sopenharmony_ci
2670141cc406Sopenharmony_ci  /* default to /dev/scanner instead of insisting on config file */
2671141cc406Sopenharmony_ci  if ((fp = sanei_config_open (EPSON_CONFIG_FILE)))
2672141cc406Sopenharmony_ci  {
2673141cc406Sopenharmony_ci    char line[PATH_MAX];
2674141cc406Sopenharmony_ci
2675141cc406Sopenharmony_ci    while (sanei_config_read (line, sizeof (line), fp))
2676141cc406Sopenharmony_ci    {
2677141cc406Sopenharmony_ci      int vendor, product;
2678141cc406Sopenharmony_ci
2679141cc406Sopenharmony_ci      DBG (4, "sane_init, >%s<\n", line);
2680141cc406Sopenharmony_ci      if (line[0] == '#')       /* ignore line comments */
2681141cc406Sopenharmony_ci        continue;
2682141cc406Sopenharmony_ci      len = strlen (line);
2683141cc406Sopenharmony_ci      if (!len)
2684141cc406Sopenharmony_ci        continue;               /* ignore empty lines */
2685141cc406Sopenharmony_ci
2686141cc406Sopenharmony_ci      if (sscanf (line, "usb %i %i", &vendor, &product) == 2)
2687141cc406Sopenharmony_ci      {
2688141cc406Sopenharmony_ci        int numIds;
2689141cc406Sopenharmony_ci
2690141cc406Sopenharmony_ci        /* add the vendor and product IDs to the list of
2691141cc406Sopenharmony_ci           known devices before we call the attach function */
2692141cc406Sopenharmony_ci        numIds = sanei_epson_getNumberOfUSBProductIds ();
2693141cc406Sopenharmony_ci        if (vendor != 0x4b8)
2694141cc406Sopenharmony_ci          continue;             /* this is not an EPSON device */
2695141cc406Sopenharmony_ci
2696141cc406Sopenharmony_ci        sanei_epson_usb_product_ids[numIds - 1] = product;
2697141cc406Sopenharmony_ci        sanei_usb_attach_matching_devices (line, attach_one_usb);
2698141cc406Sopenharmony_ci      }
2699141cc406Sopenharmony_ci      else if (strncmp (line, "usb", 3) == 0)
2700141cc406Sopenharmony_ci      {
2701141cc406Sopenharmony_ci        const char *dev_name;
2702141cc406Sopenharmony_ci        /* remove the "usb" sub string */
2703141cc406Sopenharmony_ci        dev_name = sanei_config_skip_whitespace (line + 3);
2704141cc406Sopenharmony_ci        attach_one_usb (dev_name);
2705141cc406Sopenharmony_ci      }
2706141cc406Sopenharmony_ci      else
2707141cc406Sopenharmony_ci      {
2708141cc406Sopenharmony_ci        sanei_config_attach_matching_devices (line, attach_one);
2709141cc406Sopenharmony_ci      }
2710141cc406Sopenharmony_ci    }
2711141cc406Sopenharmony_ci    fclose (fp);
2712141cc406Sopenharmony_ci  }
2713141cc406Sopenharmony_ci
2714141cc406Sopenharmony_ci  /* read the option section and assign the connection type to the
2715141cc406Sopenharmony_ci     scanner structure - which we don't have at this time. So I have
2716141cc406Sopenharmony_ci     to come up with something :-) */
2717141cc406Sopenharmony_ci
2718141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2719141cc406Sopenharmony_ci}
2720141cc406Sopenharmony_ci
2721141cc406Sopenharmony_ci/*
2722141cc406Sopenharmony_ci * void sane_exit(void)
2723141cc406Sopenharmony_ci *
2724141cc406Sopenharmony_ci * Clean up the list of attached scanners.
2725141cc406Sopenharmony_ci */
2726141cc406Sopenharmony_ci
2727141cc406Sopenharmony_civoid
2728141cc406Sopenharmony_cisane_exit (void)
2729141cc406Sopenharmony_ci{
2730141cc406Sopenharmony_ci  Epson_Device *dev, *next;
2731141cc406Sopenharmony_ci
2732141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
2733141cc406Sopenharmony_ci  {
2734141cc406Sopenharmony_ci    next = dev->next;
2735141cc406Sopenharmony_ci    free ((void *) dev->sane.name);
2736141cc406Sopenharmony_ci    free ((void *) dev->sane.model);
2737141cc406Sopenharmony_ci    free (dev);
2738141cc406Sopenharmony_ci  }
2739141cc406Sopenharmony_ci
2740141cc406Sopenharmony_ci  free (devlist);
2741141cc406Sopenharmony_ci}
2742141cc406Sopenharmony_ci
2743141cc406Sopenharmony_ci/*
2744141cc406Sopenharmony_ci *
2745141cc406Sopenharmony_ci *
2746141cc406Sopenharmony_ci */
2747141cc406Sopenharmony_ci
2748141cc406Sopenharmony_ciSANE_Status
2749141cc406Sopenharmony_cisane_get_devices (const SANE_Device * **device_list, SANE_Bool local_only)
2750141cc406Sopenharmony_ci{
2751141cc406Sopenharmony_ci  Epson_Device *dev;
2752141cc406Sopenharmony_ci  int i;
2753141cc406Sopenharmony_ci
2754141cc406Sopenharmony_ci  DBG (5, "sane_get_devices()\n");
2755141cc406Sopenharmony_ci
2756141cc406Sopenharmony_ci  (void) local_only;            /* just to get rid of the compiler warning */
2757141cc406Sopenharmony_ci
2758141cc406Sopenharmony_ci  if (devlist)
2759141cc406Sopenharmony_ci  {
2760141cc406Sopenharmony_ci    free (devlist);
2761141cc406Sopenharmony_ci  }
2762141cc406Sopenharmony_ci
2763141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
2764141cc406Sopenharmony_ci  if (!devlist)
2765141cc406Sopenharmony_ci  {
2766141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
2767141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2768141cc406Sopenharmony_ci  }
2769141cc406Sopenharmony_ci
2770141cc406Sopenharmony_ci  i = 0;
2771141cc406Sopenharmony_ci
2772141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
2773141cc406Sopenharmony_ci  {
2774141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
2775141cc406Sopenharmony_ci  }
2776141cc406Sopenharmony_ci
2777141cc406Sopenharmony_ci  devlist[i++] = 0;
2778141cc406Sopenharmony_ci
2779141cc406Sopenharmony_ci  *device_list = devlist;
2780141cc406Sopenharmony_ci
2781141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2782141cc406Sopenharmony_ci}
2783141cc406Sopenharmony_ci
2784141cc406Sopenharmony_ci/*
2785141cc406Sopenharmony_ci *
2786141cc406Sopenharmony_ci *
2787141cc406Sopenharmony_ci */
2788141cc406Sopenharmony_ci
2789141cc406Sopenharmony_cistatic SANE_Status
2790141cc406Sopenharmony_ciinit_options (Epson_Scanner * s)
2791141cc406Sopenharmony_ci{
2792141cc406Sopenharmony_ci  int i;
2793141cc406Sopenharmony_ci  SANE_Bool dummy;
2794141cc406Sopenharmony_ci
2795141cc406Sopenharmony_ci  DBG (5, "init_options()\n");
2796141cc406Sopenharmony_ci
2797141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
2798141cc406Sopenharmony_ci  {
2799141cc406Sopenharmony_ci    s->opt[i].size = sizeof (SANE_Word);
2800141cc406Sopenharmony_ci    s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2801141cc406Sopenharmony_ci  }
2802141cc406Sopenharmony_ci
2803141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2804141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2805141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2806141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2807141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
2808141cc406Sopenharmony_ci
2809141cc406Sopenharmony_ci  /* "Scan Mode" group: */
2810141cc406Sopenharmony_ci
2811141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
2812141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
2813141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2814141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
2815141cc406Sopenharmony_ci
2816141cc406Sopenharmony_ci  /* scan mode */
2817141cc406Sopenharmony_ci  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2818141cc406Sopenharmony_ci  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2819141cc406Sopenharmony_ci  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2820141cc406Sopenharmony_ci  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
2821141cc406Sopenharmony_ci  s->opt[OPT_MODE].size = max_string_size (mode_list);
2822141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2823141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint.string_list = mode_list;
2824141cc406Sopenharmony_ci  s->val[OPT_MODE].w = 0;       /* Binary */
2825141cc406Sopenharmony_ci
2826141cc406Sopenharmony_ci  /* bit depth */
2827141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
2828141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
2829141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
2830141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
2831141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE;
2832141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2833141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].constraint.word_list = bitDepthList;
2834141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
2835141cc406Sopenharmony_ci  s->val[OPT_BIT_DEPTH].w = bitDepthList[1];    /* the first "real" element is the default */
2836141cc406Sopenharmony_ci
2837141cc406Sopenharmony_ci  if (bitDepthList[0] == 1)     /* only one element in the list -> hide the option */
2838141cc406Sopenharmony_ci    s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
2839141cc406Sopenharmony_ci
2840141cc406Sopenharmony_ci  /* halftone */
2841141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].name = SANE_NAME_HALFTONE;
2842141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
2843141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].desc = SANE_I18N ("Selects the halftone.");
2844141cc406Sopenharmony_ci
2845141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].type = SANE_TYPE_STRING;
2846141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].size = max_string_size (halftone_list_7);
2847141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2848141cc406Sopenharmony_ci
2849141cc406Sopenharmony_ci  if (s->hw->level >= 7)
2850141cc406Sopenharmony_ci    s->opt[OPT_HALFTONE].constraint.string_list = halftone_list_7;
2851141cc406Sopenharmony_ci  else if (s->hw->level >= 4)
2852141cc406Sopenharmony_ci    s->opt[OPT_HALFTONE].constraint.string_list = halftone_list_4;
2853141cc406Sopenharmony_ci  else
2854141cc406Sopenharmony_ci    s->opt[OPT_HALFTONE].constraint.string_list = halftone_list;
2855141cc406Sopenharmony_ci
2856141cc406Sopenharmony_ci  s->val[OPT_HALFTONE].w = 1;   /* Halftone A */
2857141cc406Sopenharmony_ci
2858141cc406Sopenharmony_ci  if (!s->hw->cmd->set_halftoning)
2859141cc406Sopenharmony_ci  {
2860141cc406Sopenharmony_ci    s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2861141cc406Sopenharmony_ci  }
2862141cc406Sopenharmony_ci
2863141cc406Sopenharmony_ci  /* dropout */
2864141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].name = "dropout";
2865141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].title = SANE_I18N ("Dropout");
2866141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].desc = SANE_I18N ("Selects the dropout.");
2867141cc406Sopenharmony_ci
2868141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].type = SANE_TYPE_STRING;
2869141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].size = max_string_size (dropout_list);
2870141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].cap |= SANE_CAP_ADVANCED;
2871141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2872141cc406Sopenharmony_ci  s->opt[OPT_DROPOUT].constraint.string_list = dropout_list;
2873141cc406Sopenharmony_ci  s->val[OPT_DROPOUT].w = 0;    /* None */
2874141cc406Sopenharmony_ci
2875141cc406Sopenharmony_ci  /* brightness */
2876141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2877141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2878141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].desc = SANE_I18N ("Selects the brightness.");
2879141cc406Sopenharmony_ci
2880141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
2881141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
2882141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2883141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->cmd->bright_range;
2884141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS].w = 0; /* Normal */
2885141cc406Sopenharmony_ci
2886141cc406Sopenharmony_ci  if (!s->hw->cmd->set_bright)
2887141cc406Sopenharmony_ci  {
2888141cc406Sopenharmony_ci    s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2889141cc406Sopenharmony_ci  }
2890141cc406Sopenharmony_ci
2891141cc406Sopenharmony_ci  /* sharpness */
2892141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].name = "sharpness";
2893141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].title = SANE_I18N ("Sharpness");
2894141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].desc = "";
2895141cc406Sopenharmony_ci
2896141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].type = SANE_TYPE_INT;
2897141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].unit = SANE_UNIT_NONE;
2898141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2899141cc406Sopenharmony_ci  s->opt[OPT_SHARPNESS].constraint.range = &outline_emphasis_range;
2900141cc406Sopenharmony_ci  s->val[OPT_SHARPNESS].w = 0;  /* Normal */
2901141cc406Sopenharmony_ci
2902141cc406Sopenharmony_ci  if (!s->hw->cmd->set_outline_emphasis)
2903141cc406Sopenharmony_ci  {
2904141cc406Sopenharmony_ci    s->opt[OPT_SHARPNESS].cap |= SANE_CAP_INACTIVE;
2905141cc406Sopenharmony_ci  }
2906141cc406Sopenharmony_ci
2907141cc406Sopenharmony_ci
2908141cc406Sopenharmony_ci  /* gamma */
2909141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_CORRECTION].name = SANE_NAME_GAMMA_CORRECTION;
2910141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_CORRECTION].title = SANE_TITLE_GAMMA_CORRECTION;
2911141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_CORRECTION].desc = SANE_DESC_GAMMA_CORRECTION;
2912141cc406Sopenharmony_ci
2913141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_CORRECTION].type = SANE_TYPE_STRING;
2914141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_CORRECTION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2915141cc406Sopenharmony_ci  /*
2916141cc406Sopenharmony_ci   * special handling for D1 function level - at this time I'm not
2917141cc406Sopenharmony_ci   * testing for D1, I'm just assuming that all D level scanners will
2918141cc406Sopenharmony_ci   * behave the same way. This has to be confirmed with the next D-level
2919141cc406Sopenharmony_ci   * scanner
2920141cc406Sopenharmony_ci   */
2921141cc406Sopenharmony_ci  if (s->hw->cmd->level[0] == 'D')
2922141cc406Sopenharmony_ci  {
2923141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_CORRECTION].size = max_string_size (gamma_list_d);
2924141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_CORRECTION].constraint.string_list = gamma_list_d;
2925141cc406Sopenharmony_ci    s->val[OPT_GAMMA_CORRECTION].w = 1; /* Default */
2926141cc406Sopenharmony_ci    gamma_userdefined = gamma_userdefined_d;
2927141cc406Sopenharmony_ci    gamma_params = gamma_params_d;
2928141cc406Sopenharmony_ci  }
2929141cc406Sopenharmony_ci  else
2930141cc406Sopenharmony_ci  {
2931141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_CORRECTION].size = max_string_size (gamma_list_ab);
2932141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_CORRECTION].constraint.string_list = gamma_list_ab;
2933141cc406Sopenharmony_ci    s->val[OPT_GAMMA_CORRECTION].w = 0; /* Default */
2934141cc406Sopenharmony_ci    gamma_userdefined = gamma_userdefined_ab;
2935141cc406Sopenharmony_ci    gamma_params = gamma_params_ab;
2936141cc406Sopenharmony_ci  }
2937141cc406Sopenharmony_ci
2938141cc406Sopenharmony_ci  if (!s->hw->cmd->set_gamma)
2939141cc406Sopenharmony_ci  {
2940141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_CORRECTION].cap |= SANE_CAP_INACTIVE;
2941141cc406Sopenharmony_ci  }
2942141cc406Sopenharmony_ci
2943141cc406Sopenharmony_ci
2944141cc406Sopenharmony_ci  /* gamma vector */
2945141cc406Sopenharmony_ci/*
2946141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].name  = SANE_NAME_GAMMA_VECTOR;
2947141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
2948141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].desc  = SANE_DESC_GAMMA_VECTOR;
2949141cc406Sopenharmony_ci
2950141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
2951141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
2952141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
2953141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
2954141cc406Sopenharmony_ci                s->opt[ OPT_GAMMA_VECTOR].constraint.range = &u8_range;
2955141cc406Sopenharmony_ci                s->val[ OPT_GAMMA_VECTOR].wa = &s->gamma_table [ 0] [ 0];
2956141cc406Sopenharmony_ci*/
2957141cc406Sopenharmony_ci
2958141cc406Sopenharmony_ci
2959141cc406Sopenharmony_ci  /* red gamma vector */
2960141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
2961141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
2962141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
2963141cc406Sopenharmony_ci
2964141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
2965141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
2966141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
2967141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
2968141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
2969141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[0][0];
2970141cc406Sopenharmony_ci
2971141cc406Sopenharmony_ci
2972141cc406Sopenharmony_ci  /* green gamma vector */
2973141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
2974141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
2975141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
2976141cc406Sopenharmony_ci
2977141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
2978141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
2979141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
2980141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
2981141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
2982141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[1][0];
2983141cc406Sopenharmony_ci
2984141cc406Sopenharmony_ci
2985141cc406Sopenharmony_ci  /* red gamma vector */
2986141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
2987141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
2988141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
2989141cc406Sopenharmony_ci
2990141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
2991141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
2992141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
2993141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
2994141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
2995141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[2][0];
2996141cc406Sopenharmony_ci
2997141cc406Sopenharmony_ci  if (s->hw->cmd->set_gamma_table &&
2998141cc406Sopenharmony_ci      gamma_userdefined[s->val[OPT_GAMMA_CORRECTION].w] == SANE_TRUE)
2999141cc406Sopenharmony_ci  {
3000141cc406Sopenharmony_ci/*                      s->opt[ OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; */
3001141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
3002141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
3003141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
3004141cc406Sopenharmony_ci  }
3005141cc406Sopenharmony_ci  else
3006141cc406Sopenharmony_ci  {
3007141cc406Sopenharmony_ci/*                      s->opt[ OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; */
3008141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3009141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3010141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3011141cc406Sopenharmony_ci  }
3012141cc406Sopenharmony_ci
3013141cc406Sopenharmony_ci  /* initialize the Gamma tables */
3014141cc406Sopenharmony_ci  memset (&s->gamma_table[0], 0, 256 * sizeof (SANE_Word));
3015141cc406Sopenharmony_ci  memset (&s->gamma_table[1], 0, 256 * sizeof (SANE_Word));
3016141cc406Sopenharmony_ci  memset (&s->gamma_table[2], 0, 256 * sizeof (SANE_Word));
3017141cc406Sopenharmony_ci/*              memset(&s->gamma_table[3], 0, 256 * sizeof(SANE_Word)); */
3018141cc406Sopenharmony_ci  for (i = 0; i < 256; i++)
3019141cc406Sopenharmony_ci  {
3020141cc406Sopenharmony_ci    s->gamma_table[0][i] = i;
3021141cc406Sopenharmony_ci    s->gamma_table[1][i] = i;
3022141cc406Sopenharmony_ci    s->gamma_table[2][i] = i;
3023141cc406Sopenharmony_ci/*                      s->gamma_table[3][i] = i; */
3024141cc406Sopenharmony_ci  }
3025141cc406Sopenharmony_ci
3026141cc406Sopenharmony_ci
3027141cc406Sopenharmony_ci  /* color correction */
3028141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].name = "color-correction";
3029141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].title = SANE_I18N ("Color correction");
3030141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].desc =
3031141cc406Sopenharmony_ci    SANE_I18N
3032141cc406Sopenharmony_ci    ("Sets the color correction table for the selected output device.");
3033141cc406Sopenharmony_ci
3034141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].type = SANE_TYPE_STRING;
3035141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].size = 32;
3036141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].cap |= SANE_CAP_ADVANCED;
3037141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3038141cc406Sopenharmony_ci  s->opt[OPT_COLOR_CORRECTION].constraint.string_list = color_list;
3039141cc406Sopenharmony_ci  s->val[OPT_COLOR_CORRECTION].w = 5;   /* scanner default: CRT monitors */
3040141cc406Sopenharmony_ci
3041141cc406Sopenharmony_ci  if (!s->hw->cmd->set_color_correction)
3042141cc406Sopenharmony_ci  {
3043141cc406Sopenharmony_ci    s->opt[OPT_COLOR_CORRECTION].cap |= SANE_CAP_INACTIVE;
3044141cc406Sopenharmony_ci  }
3045141cc406Sopenharmony_ci
3046141cc406Sopenharmony_ci  /* resolution */
3047141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
3048141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
3049141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
3050141cc406Sopenharmony_ci
3051141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
3052141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
3053141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
3054141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.word_list = s->hw->resolution_list;
3055141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
3056141cc406Sopenharmony_ci
3057141cc406Sopenharmony_ci  /* threshold */
3058141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
3059141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
3060141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
3061141cc406Sopenharmony_ci
3062141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
3063141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
3064141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
3065141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint.range = &u8_range;
3066141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD].w = 0x80;
3067141cc406Sopenharmony_ci
3068141cc406Sopenharmony_ci  if (!s->hw->cmd->set_threshold)
3069141cc406Sopenharmony_ci  {
3070141cc406Sopenharmony_ci    s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
3071141cc406Sopenharmony_ci  }
3072141cc406Sopenharmony_ci
3073141cc406Sopenharmony_ci  s->opt[OPT_CCT_GROUP].title = SANE_I18N ("Color correction coefficients");
3074141cc406Sopenharmony_ci  s->opt[OPT_CCT_GROUP].desc = SANE_I18N ("Matrix multiplication of RGB");
3075141cc406Sopenharmony_ci  s->opt[OPT_CCT_GROUP].type = SANE_TYPE_GROUP;
3076141cc406Sopenharmony_ci  s->opt[OPT_CCT_GROUP].cap = SANE_CAP_ADVANCED;
3077141cc406Sopenharmony_ci
3078141cc406Sopenharmony_ci
3079141cc406Sopenharmony_ci  /* color correction coefficients */
3080141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].name = "cct-1";
3081141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].name = "cct-2";
3082141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].name = "cct-3";
3083141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].name = "cct-4";
3084141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].name = "cct-5";
3085141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].name = "cct-6";
3086141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].name = "cct-7";
3087141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].name = "cct-8";
3088141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].name = "cct-9";
3089141cc406Sopenharmony_ci
3090141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].title = SANE_I18N ("Green");
3091141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].title = SANE_I18N ("Shift green to red");
3092141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].title = SANE_I18N ("Shift green to blue");
3093141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].title = SANE_I18N ("Shift red to green");
3094141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].title = SANE_I18N ("Red");
3095141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].title = SANE_I18N ("Shift red to blue");
3096141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].title = SANE_I18N ("Shift blue to green");
3097141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].title = SANE_I18N ("Shift blue to red");
3098141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].title = SANE_I18N ("Blue");
3099141cc406Sopenharmony_ci
3100141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].desc = SANE_I18N ("Controls green level");
3101141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].desc = SANE_I18N ("Adds to red based on green level");
3102141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].desc = SANE_I18N ("Adds to blue based on green level");
3103141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].desc = SANE_I18N ("Adds to green based on red level");
3104141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].desc = SANE_I18N ("Controls red level");
3105141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].desc = SANE_I18N ("Adds to blue based on red level");
3106141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].desc = SANE_I18N ("Adds to green based on blue level");
3107141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].desc = SANE_I18N ("Adds to red based on blue level");
3108141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].desc = SANE_I18N ("Controls blue level");
3109141cc406Sopenharmony_ci
3110141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].type = SANE_TYPE_INT;
3111141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].type = SANE_TYPE_INT;
3112141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].type = SANE_TYPE_INT;
3113141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].type = SANE_TYPE_INT;
3114141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].type = SANE_TYPE_INT;
3115141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].type = SANE_TYPE_INT;
3116141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].type = SANE_TYPE_INT;
3117141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].type = SANE_TYPE_INT;
3118141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].type = SANE_TYPE_INT;
3119141cc406Sopenharmony_ci
3120141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].cap |= SANE_CAP_ADVANCED;
3121141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].cap |= SANE_CAP_ADVANCED;
3122141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].cap |= SANE_CAP_ADVANCED;
3123141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].cap |= SANE_CAP_ADVANCED;
3124141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].cap |= SANE_CAP_ADVANCED;
3125141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].cap |= SANE_CAP_ADVANCED;
3126141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].cap |= SANE_CAP_ADVANCED;
3127141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].cap |= SANE_CAP_ADVANCED;
3128141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].cap |= SANE_CAP_ADVANCED;
3129141cc406Sopenharmony_ci
3130141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].cap |= SANE_CAP_INACTIVE;
3131141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].cap |= SANE_CAP_INACTIVE;
3132141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].cap |= SANE_CAP_INACTIVE;
3133141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].cap |= SANE_CAP_INACTIVE;
3134141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].cap |= SANE_CAP_INACTIVE;
3135141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].cap |= SANE_CAP_INACTIVE;
3136141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].cap |= SANE_CAP_INACTIVE;
3137141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].cap |= SANE_CAP_INACTIVE;
3138141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].cap |= SANE_CAP_INACTIVE;
3139141cc406Sopenharmony_ci
3140141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].unit = SANE_UNIT_NONE;
3141141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].unit = SANE_UNIT_NONE;
3142141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].unit = SANE_UNIT_NONE;
3143141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].unit = SANE_UNIT_NONE;
3144141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].unit = SANE_UNIT_NONE;
3145141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].unit = SANE_UNIT_NONE;
3146141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].unit = SANE_UNIT_NONE;
3147141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].unit = SANE_UNIT_NONE;
3148141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].unit = SANE_UNIT_NONE;
3149141cc406Sopenharmony_ci
3150141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].constraint_type = SANE_CONSTRAINT_RANGE;
3151141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].constraint_type = SANE_CONSTRAINT_RANGE;
3152141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].constraint_type = SANE_CONSTRAINT_RANGE;
3153141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].constraint_type = SANE_CONSTRAINT_RANGE;
3154141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].constraint_type = SANE_CONSTRAINT_RANGE;
3155141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].constraint_type = SANE_CONSTRAINT_RANGE;
3156141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].constraint_type = SANE_CONSTRAINT_RANGE;
3157141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].constraint_type = SANE_CONSTRAINT_RANGE;
3158141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].constraint_type = SANE_CONSTRAINT_RANGE;
3159141cc406Sopenharmony_ci
3160141cc406Sopenharmony_ci  s->opt[OPT_CCT_1].constraint.range = &s8_range;
3161141cc406Sopenharmony_ci  s->opt[OPT_CCT_2].constraint.range = &s8_range;
3162141cc406Sopenharmony_ci  s->opt[OPT_CCT_3].constraint.range = &s8_range;
3163141cc406Sopenharmony_ci  s->opt[OPT_CCT_4].constraint.range = &s8_range;
3164141cc406Sopenharmony_ci  s->opt[OPT_CCT_5].constraint.range = &s8_range;
3165141cc406Sopenharmony_ci  s->opt[OPT_CCT_6].constraint.range = &s8_range;
3166141cc406Sopenharmony_ci  s->opt[OPT_CCT_7].constraint.range = &s8_range;
3167141cc406Sopenharmony_ci  s->opt[OPT_CCT_8].constraint.range = &s8_range;
3168141cc406Sopenharmony_ci  s->opt[OPT_CCT_9].constraint.range = &s8_range;
3169141cc406Sopenharmony_ci
3170141cc406Sopenharmony_ci  s->val[OPT_CCT_1].w = 32;
3171141cc406Sopenharmony_ci  s->val[OPT_CCT_2].w = 0;
3172141cc406Sopenharmony_ci  s->val[OPT_CCT_3].w = 0;
3173141cc406Sopenharmony_ci  s->val[OPT_CCT_4].w = 0;
3174141cc406Sopenharmony_ci  s->val[OPT_CCT_5].w = 32;
3175141cc406Sopenharmony_ci  s->val[OPT_CCT_6].w = 0;
3176141cc406Sopenharmony_ci  s->val[OPT_CCT_7].w = 0;
3177141cc406Sopenharmony_ci  s->val[OPT_CCT_8].w = 0;
3178141cc406Sopenharmony_ci  s->val[OPT_CCT_9].w = 32;
3179141cc406Sopenharmony_ci
3180141cc406Sopenharmony_ci  if (!s->hw->cmd->set_color_correction_coefficients)
3181141cc406Sopenharmony_ci  {
3182141cc406Sopenharmony_ci    s->opt[OPT_CCT_1].cap |= SANE_CAP_INACTIVE;
3183141cc406Sopenharmony_ci    s->opt[OPT_CCT_2].cap |= SANE_CAP_INACTIVE;
3184141cc406Sopenharmony_ci    s->opt[OPT_CCT_3].cap |= SANE_CAP_INACTIVE;
3185141cc406Sopenharmony_ci    s->opt[OPT_CCT_4].cap |= SANE_CAP_INACTIVE;
3186141cc406Sopenharmony_ci    s->opt[OPT_CCT_5].cap |= SANE_CAP_INACTIVE;
3187141cc406Sopenharmony_ci    s->opt[OPT_CCT_6].cap |= SANE_CAP_INACTIVE;
3188141cc406Sopenharmony_ci    s->opt[OPT_CCT_7].cap |= SANE_CAP_INACTIVE;
3189141cc406Sopenharmony_ci    s->opt[OPT_CCT_8].cap |= SANE_CAP_INACTIVE;
3190141cc406Sopenharmony_ci    s->opt[OPT_CCT_9].cap |= SANE_CAP_INACTIVE;
3191141cc406Sopenharmony_ci  }
3192141cc406Sopenharmony_ci
3193141cc406Sopenharmony_ci
3194141cc406Sopenharmony_ci  /* "Advanced" group: */
3195141cc406Sopenharmony_ci  s->opt[OPT_ADVANCED_GROUP].title = SANE_I18N ("Advanced");
3196141cc406Sopenharmony_ci  s->opt[OPT_ADVANCED_GROUP].desc = "";
3197141cc406Sopenharmony_ci  s->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
3198141cc406Sopenharmony_ci  s->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
3199141cc406Sopenharmony_ci
3200141cc406Sopenharmony_ci
3201141cc406Sopenharmony_ci  /* mirror */
3202141cc406Sopenharmony_ci  s->opt[OPT_MIRROR].name = "mirror";
3203141cc406Sopenharmony_ci  s->opt[OPT_MIRROR].title = SANE_I18N ("Mirror image");
3204141cc406Sopenharmony_ci  s->opt[OPT_MIRROR].desc = SANE_I18N ("Mirror the image.");
3205141cc406Sopenharmony_ci
3206141cc406Sopenharmony_ci  s->opt[OPT_MIRROR].type = SANE_TYPE_BOOL;
3207141cc406Sopenharmony_ci  s->val[OPT_MIRROR].w = SANE_FALSE;
3208141cc406Sopenharmony_ci
3209141cc406Sopenharmony_ci  if (!s->hw->cmd->mirror_image)
3210141cc406Sopenharmony_ci  {
3211141cc406Sopenharmony_ci    s->opt[OPT_MIRROR].cap |= SANE_CAP_INACTIVE;
3212141cc406Sopenharmony_ci  }
3213141cc406Sopenharmony_ci
3214141cc406Sopenharmony_ci
3215141cc406Sopenharmony_ci  /* speed */
3216141cc406Sopenharmony_ci  s->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED;
3217141cc406Sopenharmony_ci  s->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
3218141cc406Sopenharmony_ci  s->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED;
3219141cc406Sopenharmony_ci
3220141cc406Sopenharmony_ci  s->opt[OPT_SPEED].type = SANE_TYPE_BOOL;
3221141cc406Sopenharmony_ci  s->val[OPT_SPEED].w = SANE_FALSE;
3222141cc406Sopenharmony_ci
3223141cc406Sopenharmony_ci  if (!s->hw->cmd->set_speed)
3224141cc406Sopenharmony_ci  {
3225141cc406Sopenharmony_ci    s->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE;
3226141cc406Sopenharmony_ci  }
3227141cc406Sopenharmony_ci
3228141cc406Sopenharmony_ci  /* preview speed */
3229141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_SPEED].name = "preview-speed";
3230141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_SPEED].title = SANE_I18N ("Fast preview");
3231141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_SPEED].desc = "";
3232141cc406Sopenharmony_ci
3233141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_SPEED].type = SANE_TYPE_BOOL;
3234141cc406Sopenharmony_ci  s->val[OPT_PREVIEW_SPEED].w = SANE_FALSE;
3235141cc406Sopenharmony_ci
3236141cc406Sopenharmony_ci  if (!s->hw->cmd->set_speed)
3237141cc406Sopenharmony_ci  {
3238141cc406Sopenharmony_ci    s->opt[OPT_PREVIEW_SPEED].cap |= SANE_CAP_INACTIVE;
3239141cc406Sopenharmony_ci  }
3240141cc406Sopenharmony_ci
3241141cc406Sopenharmony_ci  /* auto area segmentation */
3242141cc406Sopenharmony_ci  s->opt[OPT_AAS].name = "auto-area-segmentation";
3243141cc406Sopenharmony_ci  s->opt[OPT_AAS].title = SANE_I18N ("Auto area segmentation");
3244141cc406Sopenharmony_ci  s->opt[OPT_AAS].desc = "";
3245141cc406Sopenharmony_ci
3246141cc406Sopenharmony_ci  s->opt[OPT_AAS].type = SANE_TYPE_BOOL;
3247141cc406Sopenharmony_ci  s->val[OPT_AAS].w = SANE_TRUE;
3248141cc406Sopenharmony_ci
3249141cc406Sopenharmony_ci  if (!s->hw->cmd->control_auto_area_segmentation)
3250141cc406Sopenharmony_ci  {
3251141cc406Sopenharmony_ci    s->opt[OPT_AAS].cap |= SANE_CAP_INACTIVE;
3252141cc406Sopenharmony_ci  }
3253141cc406Sopenharmony_ci
3254141cc406Sopenharmony_ci  /* limit resolution list */
3255141cc406Sopenharmony_ci  s->opt[OPT_LIMIT_RESOLUTION].name = "short-resolution";
3256141cc406Sopenharmony_ci  s->opt[OPT_LIMIT_RESOLUTION].title = SANE_I18N ("Short resolution list");
3257141cc406Sopenharmony_ci  s->opt[OPT_LIMIT_RESOLUTION].desc =
3258141cc406Sopenharmony_ci    SANE_I18N ("Display short resolution list");
3259141cc406Sopenharmony_ci  s->opt[OPT_LIMIT_RESOLUTION].type = SANE_TYPE_BOOL;
3260141cc406Sopenharmony_ci  s->val[OPT_LIMIT_RESOLUTION].w = SANE_FALSE;
3261141cc406Sopenharmony_ci
3262141cc406Sopenharmony_ci
3263141cc406Sopenharmony_ci  /* zoom */
3264141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].name = "zoom";
3265141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].title = SANE_I18N ("Zoom");
3266141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].desc =
3267141cc406Sopenharmony_ci    SANE_I18N ("Defines the zoom factor the scanner will use");
3268141cc406Sopenharmony_ci
3269141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].type = SANE_TYPE_INT;
3270141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].unit = SANE_UNIT_NONE;
3271141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].constraint_type = SANE_CONSTRAINT_RANGE;
3272141cc406Sopenharmony_ci  s->opt[OPT_ZOOM].constraint.range = &zoom_range;
3273141cc406Sopenharmony_ci  s->val[OPT_ZOOM].w = 100;
3274141cc406Sopenharmony_ci
3275141cc406Sopenharmony_ci/*              if( ! s->hw->cmd->set_zoom) */
3276141cc406Sopenharmony_ci  {
3277141cc406Sopenharmony_ci    s->opt[OPT_ZOOM].cap |= SANE_CAP_INACTIVE;
3278141cc406Sopenharmony_ci  }
3279141cc406Sopenharmony_ci
3280141cc406Sopenharmony_ci
3281141cc406Sopenharmony_ci  /* "Preview settings" group: */
3282141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_GROUP].title = SANE_TITLE_PREVIEW;
3283141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_GROUP].desc = "";
3284141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_GROUP].type = SANE_TYPE_GROUP;
3285141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW_GROUP].cap = SANE_CAP_ADVANCED;
3286141cc406Sopenharmony_ci
3287141cc406Sopenharmony_ci  /* preview */
3288141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
3289141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
3290141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
3291141cc406Sopenharmony_ci
3292141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
3293141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w = SANE_FALSE;
3294141cc406Sopenharmony_ci
3295141cc406Sopenharmony_ci  /* "Geometry" group: */
3296141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
3297141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
3298141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
3299141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
3300141cc406Sopenharmony_ci
3301141cc406Sopenharmony_ci  /* top-left x */
3302141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
3303141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
3304141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
3305141cc406Sopenharmony_ci
3306141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
3307141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
3308141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
3309141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = s->hw->x_range;
3310141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = 0;
3311141cc406Sopenharmony_ci
3312141cc406Sopenharmony_ci  /* top-left y */
3313141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
3314141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
3315141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
3316141cc406Sopenharmony_ci
3317141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
3318141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
3319141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
3320141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = s->hw->y_range;
3321141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = 0;
3322141cc406Sopenharmony_ci
3323141cc406Sopenharmony_ci  /* bottom-right x */
3324141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
3325141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
3326141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
3327141cc406Sopenharmony_ci
3328141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
3329141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
3330141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
3331141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
3332141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = s->hw->x_range->max;
3333141cc406Sopenharmony_ci
3334141cc406Sopenharmony_ci  /* bottom-right y */
3335141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
3336141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
3337141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
3338141cc406Sopenharmony_ci
3339141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
3340141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
3341141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
3342141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
3343141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = s->hw->y_range->max;
3344141cc406Sopenharmony_ci
3345141cc406Sopenharmony_ci  /* Quick format */
3346141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].name = "quick-format";
3347141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].title = SANE_I18N ("Quick format");
3348141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].desc = "";
3349141cc406Sopenharmony_ci
3350141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].type = SANE_TYPE_STRING;
3351141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].size = max_string_size (qf_list);
3352141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].cap |= SANE_CAP_ADVANCED;
3353141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3354141cc406Sopenharmony_ci  s->opt[OPT_QUICK_FORMAT].constraint.string_list = qf_list;
3355141cc406Sopenharmony_ci  s->val[OPT_QUICK_FORMAT].w = XtNumber (qf_params) - 1;        /* max */
3356141cc406Sopenharmony_ci
3357141cc406Sopenharmony_ci  /* "Optional equipment" group: */
3358141cc406Sopenharmony_ci  s->opt[OPT_EQU_GROUP].title = SANE_I18N ("Optional equipment");
3359141cc406Sopenharmony_ci  s->opt[OPT_EQU_GROUP].desc = "";
3360141cc406Sopenharmony_ci  s->opt[OPT_EQU_GROUP].type = SANE_TYPE_GROUP;
3361141cc406Sopenharmony_ci  s->opt[OPT_EQU_GROUP].cap = SANE_CAP_ADVANCED;
3362141cc406Sopenharmony_ci
3363141cc406Sopenharmony_ci
3364141cc406Sopenharmony_ci  /* source */
3365141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
3366141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
3367141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
3368141cc406Sopenharmony_ci
3369141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
3370141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].size = max_string_size (source_list);
3371141cc406Sopenharmony_ci
3372141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3373141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].constraint.string_list = source_list;
3374141cc406Sopenharmony_ci
3375141cc406Sopenharmony_ci  if (!s->hw->extension)
3376141cc406Sopenharmony_ci  {
3377141cc406Sopenharmony_ci    s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
3378141cc406Sopenharmony_ci  }
3379141cc406Sopenharmony_ci  s->val[OPT_SOURCE].w = 0;     /* always use Flatbed as default */
3380141cc406Sopenharmony_ci
3381141cc406Sopenharmony_ci
3382141cc406Sopenharmony_ci  /* film type */
3383141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].name = "film-type";
3384141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].title = SANE_I18N ("Film type");
3385141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].desc = "";
3386141cc406Sopenharmony_ci
3387141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].type = SANE_TYPE_STRING;
3388141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].size = max_string_size (film_list);
3389141cc406Sopenharmony_ci
3390141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3391141cc406Sopenharmony_ci  s->opt[OPT_FILM_TYPE].constraint.string_list = film_list;
3392141cc406Sopenharmony_ci
3393141cc406Sopenharmony_ci  s->val[OPT_FILM_TYPE].w = 0;
3394141cc406Sopenharmony_ci
3395141cc406Sopenharmony_ci  deactivateOption (s, OPT_FILM_TYPE, &dummy);  /* default is inactive */
3396141cc406Sopenharmony_ci
3397141cc406Sopenharmony_ci  /* focus position */
3398141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].name = SANE_EPSON_FOCUS_NAME;
3399141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].title = SANE_EPSON_FOCUS_TITLE;
3400141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].desc = SANE_EPSON_FOCUS_DESC;
3401141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].type = SANE_TYPE_STRING;
3402141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].size = max_string_size (focus_list);
3403141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3404141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].constraint.string_list = focus_list;
3405141cc406Sopenharmony_ci  s->val[OPT_FOCUS].w = 0;
3406141cc406Sopenharmony_ci
3407141cc406Sopenharmony_ci  s->opt[OPT_FOCUS].cap |= SANE_CAP_ADVANCED;
3408141cc406Sopenharmony_ci  if (s->hw->focusSupport == SANE_TRUE)
3409141cc406Sopenharmony_ci  {
3410141cc406Sopenharmony_ci    s->opt[OPT_FOCUS].cap &= ~SANE_CAP_INACTIVE;
3411141cc406Sopenharmony_ci  }
3412141cc406Sopenharmony_ci  else
3413141cc406Sopenharmony_ci  {
3414141cc406Sopenharmony_ci    s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE;
3415141cc406Sopenharmony_ci  }
3416141cc406Sopenharmony_ci
3417141cc406Sopenharmony_ci#if 0
3418141cc406Sopenharmony_ci  if ((!s->hw->TPU) && (!s->hw->cmd->set_bay))
3419141cc406Sopenharmony_ci  {                             /* Hack: Using set_bay to indicate. */
3420141cc406Sopenharmony_ci    SANE_Bool dummy;
3421141cc406Sopenharmony_ci    deactivateOption (s, OPT_FILM_TYPE, &dummy);
3422141cc406Sopenharmony_ci
3423141cc406Sopenharmony_ci  }
3424141cc406Sopenharmony_ci#endif
3425141cc406Sopenharmony_ci
3426141cc406Sopenharmony_ci
3427141cc406Sopenharmony_ci  /* forward feed / eject */
3428141cc406Sopenharmony_ci  s->opt[OPT_EJECT].name = "eject";
3429141cc406Sopenharmony_ci  s->opt[OPT_EJECT].title = SANE_I18N ("Eject");
3430141cc406Sopenharmony_ci  s->opt[OPT_EJECT].desc = SANE_I18N ("Eject the sheet in the ADF");
3431141cc406Sopenharmony_ci
3432141cc406Sopenharmony_ci  s->opt[OPT_EJECT].type = SANE_TYPE_BUTTON;
3433141cc406Sopenharmony_ci
3434141cc406Sopenharmony_ci  if ((!s->hw->ADF) && (!s->hw->cmd->set_bay))
3435141cc406Sopenharmony_ci  {                             /* Hack: Using set_bay to indicate. */
3436141cc406Sopenharmony_ci    s->opt[OPT_EJECT].cap |= SANE_CAP_INACTIVE;
3437141cc406Sopenharmony_ci  }
3438141cc406Sopenharmony_ci
3439141cc406Sopenharmony_ci
3440141cc406Sopenharmony_ci  /* auto forward feed / eject */
3441141cc406Sopenharmony_ci  s->opt[OPT_AUTO_EJECT].name = "auto-eject";
3442141cc406Sopenharmony_ci  s->opt[OPT_AUTO_EJECT].title = SANE_I18N ("Auto eject");
3443141cc406Sopenharmony_ci  s->opt[OPT_AUTO_EJECT].desc = SANE_I18N ("Eject document after scanning");
3444141cc406Sopenharmony_ci
3445141cc406Sopenharmony_ci  s->opt[OPT_AUTO_EJECT].type = SANE_TYPE_BOOL;
3446141cc406Sopenharmony_ci  s->val[OPT_AUTO_EJECT].w = SANE_FALSE;
3447141cc406Sopenharmony_ci
3448141cc406Sopenharmony_ci  if (!s->hw->ADF)
3449141cc406Sopenharmony_ci  {
3450141cc406Sopenharmony_ci    s->opt[OPT_AUTO_EJECT].cap |= SANE_CAP_INACTIVE;
3451141cc406Sopenharmony_ci  }
3452141cc406Sopenharmony_ci
3453141cc406Sopenharmony_ci
3454141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].name = "adf_mode";
3455141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].title = SANE_I18N ("ADF Mode");
3456141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].desc =
3457141cc406Sopenharmony_ci    SANE_I18N ("Selects the ADF mode (simplex/duplex)");
3458141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].type = SANE_TYPE_STRING;
3459141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].size = max_string_size (adf_mode_list);
3460141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3461141cc406Sopenharmony_ci  s->opt[OPT_ADF_MODE].constraint.string_list = adf_mode_list;
3462141cc406Sopenharmony_ci  s->val[OPT_ADF_MODE].w = 0;   /* simplex */
3463141cc406Sopenharmony_ci
3464141cc406Sopenharmony_ci  if ((!s->hw->ADF) || (s->hw->duplexSupport == SANE_FALSE))
3465141cc406Sopenharmony_ci  {
3466141cc406Sopenharmony_ci    s->opt[OPT_ADF_MODE].cap |= SANE_CAP_INACTIVE;
3467141cc406Sopenharmony_ci  }
3468141cc406Sopenharmony_ci
3469141cc406Sopenharmony_ci  /* select bay */
3470141cc406Sopenharmony_ci  s->opt[OPT_BAY].name = "bay";
3471141cc406Sopenharmony_ci  s->opt[OPT_BAY].title = SANE_I18N ("Bay");
3472141cc406Sopenharmony_ci  s->opt[OPT_BAY].desc = SANE_I18N ("Select bay to scan");
3473141cc406Sopenharmony_ci
3474141cc406Sopenharmony_ci  s->opt[OPT_BAY].type = SANE_TYPE_STRING;
3475141cc406Sopenharmony_ci  s->opt[OPT_BAY].size = max_string_size (bay_list);
3476141cc406Sopenharmony_ci  s->opt[OPT_BAY].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3477141cc406Sopenharmony_ci  s->opt[OPT_BAY].constraint.string_list = bay_list;
3478141cc406Sopenharmony_ci  s->val[OPT_BAY].w = 0;        /* Bay 1 */
3479141cc406Sopenharmony_ci
3480141cc406Sopenharmony_ci  if (!s->hw->cmd->set_bay)
3481141cc406Sopenharmony_ci  {
3482141cc406Sopenharmony_ci    s->opt[OPT_BAY].cap |= SANE_CAP_INACTIVE;
3483141cc406Sopenharmony_ci  }
3484141cc406Sopenharmony_ci
3485141cc406Sopenharmony_ci
3486141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].name = SANE_EPSON_WAIT_FOR_BUTTON_NAME;
3487141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].title = SANE_EPSON_WAIT_FOR_BUTTON_TITLE;
3488141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].desc = SANE_EPSON_WAIT_FOR_BUTTON_DESC;
3489141cc406Sopenharmony_ci
3490141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].type = SANE_TYPE_BOOL;
3491141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].unit = SANE_UNIT_NONE;
3492141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE;
3493141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].constraint.range = NULL;
3494141cc406Sopenharmony_ci  s->opt[OPT_WAIT_FOR_BUTTON].cap |= SANE_CAP_ADVANCED;
3495141cc406Sopenharmony_ci
3496141cc406Sopenharmony_ci  if (!s->hw->cmd->request_push_button_status)
3497141cc406Sopenharmony_ci  {
3498141cc406Sopenharmony_ci    s->opt[OPT_WAIT_FOR_BUTTON].cap |= SANE_CAP_INACTIVE;
3499141cc406Sopenharmony_ci  }
3500141cc406Sopenharmony_ci
3501141cc406Sopenharmony_ci
3502141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3503141cc406Sopenharmony_ci}
3504141cc406Sopenharmony_ci
3505141cc406Sopenharmony_ci/*
3506141cc406Sopenharmony_ci *
3507141cc406Sopenharmony_ci *
3508141cc406Sopenharmony_ci */
3509141cc406Sopenharmony_ci
3510141cc406Sopenharmony_ciSANE_Status
3511141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
3512141cc406Sopenharmony_ci{
3513141cc406Sopenharmony_ci  Epson_Device *dev;
3514141cc406Sopenharmony_ci  Epson_Scanner *s;
3515141cc406Sopenharmony_ci
3516141cc406Sopenharmony_ci  DBG (5, "sane_open(%s)\n", devicename);
3517141cc406Sopenharmony_ci
3518141cc406Sopenharmony_ci  /* search for device */
3519141cc406Sopenharmony_ci  if (devicename[0])
3520141cc406Sopenharmony_ci  {
3521141cc406Sopenharmony_ci    for (dev = first_dev; dev; dev = dev->next)
3522141cc406Sopenharmony_ci    {
3523141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
3524141cc406Sopenharmony_ci      {
3525141cc406Sopenharmony_ci        break;
3526141cc406Sopenharmony_ci      }
3527141cc406Sopenharmony_ci    }
3528141cc406Sopenharmony_ci
3529141cc406Sopenharmony_ci    if (!dev)
3530141cc406Sopenharmony_ci    {
3531141cc406Sopenharmony_ci#if 0
3532141cc406Sopenharmony_ci      status = attach (devicename, &dev, SANE_EPSON_);
3533141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3534141cc406Sopenharmony_ci      {
3535141cc406Sopenharmony_ci        return status;
3536141cc406Sopenharmony_ci      }
3537141cc406Sopenharmony_ci#endif
3538141cc406Sopenharmony_ci      DBG (1, "Error opening the device");
3539141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3540141cc406Sopenharmony_ci    }
3541141cc406Sopenharmony_ci  }
3542141cc406Sopenharmony_ci  else
3543141cc406Sopenharmony_ci  {
3544141cc406Sopenharmony_ci    dev = first_dev;
3545141cc406Sopenharmony_ci  }
3546141cc406Sopenharmony_ci
3547141cc406Sopenharmony_ci  if (!dev)
3548141cc406Sopenharmony_ci  {
3549141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3550141cc406Sopenharmony_ci  }
3551141cc406Sopenharmony_ci
3552141cc406Sopenharmony_ci  s = calloc (sizeof (Epson_Scanner), 1);
3553141cc406Sopenharmony_ci  if (!s)
3554141cc406Sopenharmony_ci  {
3555141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
3556141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
3557141cc406Sopenharmony_ci  }
3558141cc406Sopenharmony_ci
3559141cc406Sopenharmony_ci  s->fd = -1;
3560141cc406Sopenharmony_ci  s->hw = dev;
3561141cc406Sopenharmony_ci
3562141cc406Sopenharmony_ci  init_options (s);
3563141cc406Sopenharmony_ci
3564141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles */
3565141cc406Sopenharmony_ci  s->next = first_handle;
3566141cc406Sopenharmony_ci  first_handle = s;
3567141cc406Sopenharmony_ci
3568141cc406Sopenharmony_ci  *handle = (SANE_Handle) s;
3569141cc406Sopenharmony_ci
3570141cc406Sopenharmony_ci  open_scanner (s);
3571141cc406Sopenharmony_ci
3572141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3573141cc406Sopenharmony_ci}
3574141cc406Sopenharmony_ci
3575141cc406Sopenharmony_ci/*
3576141cc406Sopenharmony_ci *
3577141cc406Sopenharmony_ci *
3578141cc406Sopenharmony_ci */
3579141cc406Sopenharmony_ci
3580141cc406Sopenharmony_civoid
3581141cc406Sopenharmony_cisane_close (SANE_Handle handle)
3582141cc406Sopenharmony_ci{
3583141cc406Sopenharmony_ci  Epson_Scanner *s, *prev;
3584141cc406Sopenharmony_ci
3585141cc406Sopenharmony_ci  /*
3586141cc406Sopenharmony_ci   * Test if there is still data pending from
3587141cc406Sopenharmony_ci   * the scanner. If so, then do a cancel
3588141cc406Sopenharmony_ci   */
3589141cc406Sopenharmony_ci
3590141cc406Sopenharmony_ci  s = (Epson_Scanner *) handle;
3591141cc406Sopenharmony_ci
3592141cc406Sopenharmony_ci  /* remove handle from list of open handles */
3593141cc406Sopenharmony_ci  prev = 0;
3594141cc406Sopenharmony_ci  for (s = first_handle; s; s = s->next)
3595141cc406Sopenharmony_ci  {
3596141cc406Sopenharmony_ci    if (s == handle)
3597141cc406Sopenharmony_ci      break;
3598141cc406Sopenharmony_ci    prev = s;
3599141cc406Sopenharmony_ci  }
3600141cc406Sopenharmony_ci
3601141cc406Sopenharmony_ci  if (!s)
3602141cc406Sopenharmony_ci  {
3603141cc406Sopenharmony_ci    DBG (1, "close: invalid handle (0x%p)\n", handle);
3604141cc406Sopenharmony_ci    return;
3605141cc406Sopenharmony_ci  }
3606141cc406Sopenharmony_ci
3607141cc406Sopenharmony_ci  if (prev)
3608141cc406Sopenharmony_ci    prev->next = s->next;
3609141cc406Sopenharmony_ci  else
3610141cc406Sopenharmony_ci    first_handle = s->next;
3611141cc406Sopenharmony_ci
3612141cc406Sopenharmony_ci  if (s->fd != -1)
3613141cc406Sopenharmony_ci    close_scanner (s);
3614141cc406Sopenharmony_ci
3615141cc406Sopenharmony_ci  free (s);
3616141cc406Sopenharmony_ci}
3617141cc406Sopenharmony_ci
3618141cc406Sopenharmony_ci/*
3619141cc406Sopenharmony_ci *
3620141cc406Sopenharmony_ci *
3621141cc406Sopenharmony_ci */
3622141cc406Sopenharmony_ci
3623141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3624141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
3625141cc406Sopenharmony_ci{
3626141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
3627141cc406Sopenharmony_ci
3628141cc406Sopenharmony_ci  if (option < 0 || option >= NUM_OPTIONS)
3629141cc406Sopenharmony_ci    return NULL;
3630141cc406Sopenharmony_ci
3631141cc406Sopenharmony_ci  return (s->opt + option);
3632141cc406Sopenharmony_ci}
3633141cc406Sopenharmony_ci
3634141cc406Sopenharmony_ci/*
3635141cc406Sopenharmony_ci *
3636141cc406Sopenharmony_ci *
3637141cc406Sopenharmony_ci */
3638141cc406Sopenharmony_ci
3639141cc406Sopenharmony_cistatic const SANE_String_Const *
3640141cc406Sopenharmony_cisearch_string_list (const SANE_String_Const * list, SANE_String value)
3641141cc406Sopenharmony_ci{
3642141cc406Sopenharmony_ci  while (*list != NULL && strcmp (value, *list) != 0)
3643141cc406Sopenharmony_ci  {
3644141cc406Sopenharmony_ci    ++list;
3645141cc406Sopenharmony_ci  }
3646141cc406Sopenharmony_ci
3647141cc406Sopenharmony_ci  return ((*list == NULL) ? NULL : list);
3648141cc406Sopenharmony_ci}
3649141cc406Sopenharmony_ci
3650141cc406Sopenharmony_ci/*
3651141cc406Sopenharmony_ci *
3652141cc406Sopenharmony_ci *
3653141cc406Sopenharmony_ci */
3654141cc406Sopenharmony_ci
3655141cc406Sopenharmony_ci/*
3656141cc406Sopenharmony_ci    Activate, deactivate an option.  Subroutines so we can add
3657141cc406Sopenharmony_ci    debugging info if we want.  The change flag is set to TRUE
3658141cc406Sopenharmony_ci    if we changed an option.  If we did not change an option,
3659141cc406Sopenharmony_ci    then the value of the changed flag is not modified.
3660141cc406Sopenharmony_ci*/
3661141cc406Sopenharmony_ci
3662141cc406Sopenharmony_cistatic void
3663141cc406Sopenharmony_ciactivateOption (Epson_Scanner * s, SANE_Int option, SANE_Bool * change)
3664141cc406Sopenharmony_ci{
3665141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (s->opt[option].cap))
3666141cc406Sopenharmony_ci  {
3667141cc406Sopenharmony_ci    s->opt[option].cap &= ~SANE_CAP_INACTIVE;
3668141cc406Sopenharmony_ci    *change = SANE_TRUE;
3669141cc406Sopenharmony_ci  }
3670141cc406Sopenharmony_ci}
3671141cc406Sopenharmony_ci
3672141cc406Sopenharmony_cistatic void
3673141cc406Sopenharmony_cideactivateOption (Epson_Scanner * s, SANE_Int option, SANE_Bool * change)
3674141cc406Sopenharmony_ci{
3675141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[option].cap))
3676141cc406Sopenharmony_ci  {
3677141cc406Sopenharmony_ci    s->opt[option].cap |= SANE_CAP_INACTIVE;
3678141cc406Sopenharmony_ci    *change = SANE_TRUE;
3679141cc406Sopenharmony_ci  }
3680141cc406Sopenharmony_ci}
3681141cc406Sopenharmony_ci
3682141cc406Sopenharmony_cistatic void
3683141cc406Sopenharmony_cisetOptionState (Epson_Scanner * s, SANE_Bool state,
3684141cc406Sopenharmony_ci                SANE_Int option, SANE_Bool * change)
3685141cc406Sopenharmony_ci{
3686141cc406Sopenharmony_ci  if (state)
3687141cc406Sopenharmony_ci  {
3688141cc406Sopenharmony_ci    activateOption (s, option, change);
3689141cc406Sopenharmony_ci  }
3690141cc406Sopenharmony_ci  else
3691141cc406Sopenharmony_ci  {
3692141cc406Sopenharmony_ci    deactivateOption (s, option, change);
3693141cc406Sopenharmony_ci  }
3694141cc406Sopenharmony_ci}
3695141cc406Sopenharmony_ci
3696141cc406Sopenharmony_ci/**
3697141cc406Sopenharmony_ci    End of activateOption, deactivateOption, setOptionState.
3698141cc406Sopenharmony_ci**/
3699141cc406Sopenharmony_ci
3700141cc406Sopenharmony_cistatic SANE_Status
3701141cc406Sopenharmony_cigetvalue (SANE_Handle handle, SANE_Int option, void *value)
3702141cc406Sopenharmony_ci{
3703141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
3704141cc406Sopenharmony_ci  SANE_Option_Descriptor *sopt = &(s->opt[option]);
3705141cc406Sopenharmony_ci  Option_Value *sval = &(s->val[option]);
3706141cc406Sopenharmony_ci
3707141cc406Sopenharmony_ci  switch (option)
3708141cc406Sopenharmony_ci  {
3709141cc406Sopenharmony_ci/*      case OPT_GAMMA_VECTOR: */
3710141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_R:
3711141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_G:
3712141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_B:
3713141cc406Sopenharmony_ci    memcpy (value, sval->wa, sopt->size);
3714141cc406Sopenharmony_ci    break;
3715141cc406Sopenharmony_ci
3716141cc406Sopenharmony_ci  case OPT_NUM_OPTS:
3717141cc406Sopenharmony_ci  case OPT_RESOLUTION:
3718141cc406Sopenharmony_ci  case OPT_TL_X:
3719141cc406Sopenharmony_ci  case OPT_TL_Y:
3720141cc406Sopenharmony_ci  case OPT_BR_X:
3721141cc406Sopenharmony_ci  case OPT_BR_Y:
3722141cc406Sopenharmony_ci  case OPT_MIRROR:
3723141cc406Sopenharmony_ci  case OPT_SPEED:
3724141cc406Sopenharmony_ci  case OPT_PREVIEW_SPEED:
3725141cc406Sopenharmony_ci  case OPT_AAS:
3726141cc406Sopenharmony_ci  case OPT_PREVIEW:
3727141cc406Sopenharmony_ci  case OPT_BRIGHTNESS:
3728141cc406Sopenharmony_ci  case OPT_SHARPNESS:
3729141cc406Sopenharmony_ci  case OPT_AUTO_EJECT:
3730141cc406Sopenharmony_ci  case OPT_CCT_1:
3731141cc406Sopenharmony_ci  case OPT_CCT_2:
3732141cc406Sopenharmony_ci  case OPT_CCT_3:
3733141cc406Sopenharmony_ci  case OPT_CCT_4:
3734141cc406Sopenharmony_ci  case OPT_CCT_5:
3735141cc406Sopenharmony_ci  case OPT_CCT_6:
3736141cc406Sopenharmony_ci  case OPT_CCT_7:
3737141cc406Sopenharmony_ci  case OPT_CCT_8:
3738141cc406Sopenharmony_ci  case OPT_CCT_9:
3739141cc406Sopenharmony_ci  case OPT_THRESHOLD:
3740141cc406Sopenharmony_ci  case OPT_ZOOM:
3741141cc406Sopenharmony_ci  case OPT_BIT_DEPTH:
3742141cc406Sopenharmony_ci  case OPT_WAIT_FOR_BUTTON:
3743141cc406Sopenharmony_ci  case OPT_LIMIT_RESOLUTION:
3744141cc406Sopenharmony_ci    *((SANE_Word *) value) = sval->w;
3745141cc406Sopenharmony_ci    break;
3746141cc406Sopenharmony_ci  case OPT_MODE:
3747141cc406Sopenharmony_ci  case OPT_ADF_MODE:
3748141cc406Sopenharmony_ci  case OPT_HALFTONE:
3749141cc406Sopenharmony_ci  case OPT_DROPOUT:
3750141cc406Sopenharmony_ci  case OPT_QUICK_FORMAT:
3751141cc406Sopenharmony_ci  case OPT_SOURCE:
3752141cc406Sopenharmony_ci  case OPT_FILM_TYPE:
3753141cc406Sopenharmony_ci  case OPT_GAMMA_CORRECTION:
3754141cc406Sopenharmony_ci  case OPT_COLOR_CORRECTION:
3755141cc406Sopenharmony_ci  case OPT_BAY:
3756141cc406Sopenharmony_ci  case OPT_FOCUS:
3757141cc406Sopenharmony_ci    strcpy ((char *) value, sopt->constraint.string_list[sval->w]);
3758141cc406Sopenharmony_ci    break;
3759141cc406Sopenharmony_ci#if 0
3760141cc406Sopenharmony_ci  case OPT_MODEL:
3761141cc406Sopenharmony_ci    strcpy (value, sval->s);
3762141cc406Sopenharmony_ci    break;
3763141cc406Sopenharmony_ci#endif
3764141cc406Sopenharmony_ci
3765141cc406Sopenharmony_ci
3766141cc406Sopenharmony_ci  default:
3767141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3768141cc406Sopenharmony_ci
3769141cc406Sopenharmony_ci  }
3770141cc406Sopenharmony_ci
3771141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3772141cc406Sopenharmony_ci}
3773141cc406Sopenharmony_ci
3774141cc406Sopenharmony_ci
3775141cc406Sopenharmony_ci/**
3776141cc406Sopenharmony_ci    End of getvalue.
3777141cc406Sopenharmony_ci**/
3778141cc406Sopenharmony_ci
3779141cc406Sopenharmony_ci
3780141cc406Sopenharmony_cistatic void
3781141cc406Sopenharmony_cihandle_depth_halftone (Epson_Scanner * s, SANE_Bool * reload)
3782141cc406Sopenharmony_ci/*
3783141cc406Sopenharmony_ci    This routine handles common options between OPT_MODE and
3784141cc406Sopenharmony_ci    OPT_HALFTONE.  These options are TET (a HALFTONE mode), AAS
3785141cc406Sopenharmony_ci    - auto area segmentation, and threshold.  Apparently AAS
3786141cc406Sopenharmony_ci    is some method to differentiate between text and photos.
3787141cc406Sopenharmony_ci    Or something like that.
3788141cc406Sopenharmony_ci
3789141cc406Sopenharmony_ci    AAS is available when the scan color depth is 1 and the
3790141cc406Sopenharmony_ci    halftone method is not TET.
3791141cc406Sopenharmony_ci
3792141cc406Sopenharmony_ci    Threshold is available when halftone is NONE, and depth is 1.
3793141cc406Sopenharmony_ci*/
3794141cc406Sopenharmony_ci{
3795141cc406Sopenharmony_ci  int hti = s->val[OPT_HALFTONE].w;
3796141cc406Sopenharmony_ci  int mdi = s->val[OPT_MODE].w;
3797141cc406Sopenharmony_ci  SANE_Bool aas = SANE_FALSE;
3798141cc406Sopenharmony_ci  SANE_Bool thresh = SANE_FALSE;
3799141cc406Sopenharmony_ci
3800141cc406Sopenharmony_ci  if (!s->hw->cmd->control_auto_area_segmentation)
3801141cc406Sopenharmony_ci    return;
3802141cc406Sopenharmony_ci
3803141cc406Sopenharmony_ci  if (mode_params[mdi].depth == 1)
3804141cc406Sopenharmony_ci  {
3805141cc406Sopenharmony_ci    if (halftone_params[hti] != HALFTONE_TET)
3806141cc406Sopenharmony_ci    {
3807141cc406Sopenharmony_ci      aas = SANE_TRUE;
3808141cc406Sopenharmony_ci    }
3809141cc406Sopenharmony_ci    if (halftone_params[hti] == HALFTONE_NONE)
3810141cc406Sopenharmony_ci    {
3811141cc406Sopenharmony_ci      thresh = SANE_TRUE;
3812141cc406Sopenharmony_ci    }
3813141cc406Sopenharmony_ci  }
3814141cc406Sopenharmony_ci  setOptionState (s, aas, OPT_AAS, reload);
3815141cc406Sopenharmony_ci  setOptionState (s, thresh, OPT_THRESHOLD, reload);
3816141cc406Sopenharmony_ci}
3817141cc406Sopenharmony_ci
3818141cc406Sopenharmony_ci/**
3819141cc406Sopenharmony_ci    End of handle_depth_halftone.
3820141cc406Sopenharmony_ci**/
3821141cc406Sopenharmony_ci
3822141cc406Sopenharmony_ci
3823141cc406Sopenharmony_cistatic void
3824141cc406Sopenharmony_cihandle_source (Epson_Scanner * s, SANE_Int optindex, char *value)
3825141cc406Sopenharmony_ci/*
3826141cc406Sopenharmony_ci    Handles setting the source (flatbed, transparency adapter (TPU),
3827141cc406Sopenharmony_ci    or auto document feeder (ADF)).
3828141cc406Sopenharmony_ci
3829141cc406Sopenharmony_ci    For newer scanners it also sets the focus according to the
3830141cc406Sopenharmony_ci    glass / TPU settings.
3831141cc406Sopenharmony_ci*/
3832141cc406Sopenharmony_ci{
3833141cc406Sopenharmony_ci  int force_max = SANE_FALSE;
3834141cc406Sopenharmony_ci  SANE_Bool dummy;
3835141cc406Sopenharmony_ci
3836141cc406Sopenharmony_ci  /* reset the scanner when we are changing the source setting -
3837141cc406Sopenharmony_ci     this is necessary for the Perfection 1650 */
3838141cc406Sopenharmony_ci  if (s->hw->need_reset_on_source_change)
3839141cc406Sopenharmony_ci    reset (s);
3840141cc406Sopenharmony_ci
3841141cc406Sopenharmony_ci  s->focusOnGlass = SANE_TRUE;  /* this is the default */
3842141cc406Sopenharmony_ci
3843141cc406Sopenharmony_ci  if (s->val[OPT_SOURCE].w == optindex)
3844141cc406Sopenharmony_ci    return;
3845141cc406Sopenharmony_ci
3846141cc406Sopenharmony_ci  s->val[OPT_SOURCE].w = optindex;
3847141cc406Sopenharmony_ci
3848141cc406Sopenharmony_ci  if (s->val[OPT_TL_X].w == s->hw->x_range->min
3849141cc406Sopenharmony_ci      && s->val[OPT_TL_Y].w == s->hw->y_range->min
3850141cc406Sopenharmony_ci      && s->val[OPT_BR_X].w == s->hw->x_range->max
3851141cc406Sopenharmony_ci      && s->val[OPT_BR_Y].w == s->hw->y_range->max)
3852141cc406Sopenharmony_ci  {
3853141cc406Sopenharmony_ci    force_max = SANE_TRUE;
3854141cc406Sopenharmony_ci  }
3855141cc406Sopenharmony_ci  if (strcmp (ADF_STR, value) == 0)
3856141cc406Sopenharmony_ci  {
3857141cc406Sopenharmony_ci    s->hw->x_range = &s->hw->adf_x_range;
3858141cc406Sopenharmony_ci    s->hw->y_range = &s->hw->adf_y_range;
3859141cc406Sopenharmony_ci    s->hw->use_extension = SANE_TRUE;
3860141cc406Sopenharmony_ci    /* disable film type option */
3861141cc406Sopenharmony_ci    deactivateOption (s, OPT_FILM_TYPE, &dummy);
3862141cc406Sopenharmony_ci    s->val[OPT_FOCUS].w = 0;
3863141cc406Sopenharmony_ci    if (s->hw->duplexSupport)
3864141cc406Sopenharmony_ci    {
3865141cc406Sopenharmony_ci      activateOption (s, OPT_ADF_MODE, &dummy);
3866141cc406Sopenharmony_ci    }
3867141cc406Sopenharmony_ci    else
3868141cc406Sopenharmony_ci    {
3869141cc406Sopenharmony_ci      deactivateOption (s, OPT_ADF_MODE, &dummy);
3870141cc406Sopenharmony_ci      s->val[OPT_ADF_MODE].w = 0;
3871141cc406Sopenharmony_ci    }
3872141cc406Sopenharmony_ci  }
3873141cc406Sopenharmony_ci  else if (strcmp (TPU_STR, value) == 0)
3874141cc406Sopenharmony_ci  {
3875141cc406Sopenharmony_ci    s->hw->x_range = &s->hw->tpu_x_range;
3876141cc406Sopenharmony_ci    s->hw->y_range = &s->hw->tpu_y_range;
3877141cc406Sopenharmony_ci    s->hw->use_extension = SANE_TRUE;
3878141cc406Sopenharmony_ci    /* enable film type option only if the scanner supports it */
3879141cc406Sopenharmony_ci    if (s->hw->cmd->set_film_type != 0)
3880141cc406Sopenharmony_ci    {
3881141cc406Sopenharmony_ci      activateOption (s, OPT_FILM_TYPE, &dummy);
3882141cc406Sopenharmony_ci    }
3883141cc406Sopenharmony_ci    else
3884141cc406Sopenharmony_ci    {
3885141cc406Sopenharmony_ci      deactivateOption (s, OPT_FILM_TYPE, &dummy);
3886141cc406Sopenharmony_ci    }
3887141cc406Sopenharmony_ci    /* enable focus position if the scanner supports it */
3888141cc406Sopenharmony_ci    if (s->hw->cmd->set_focus_position != 0)
3889141cc406Sopenharmony_ci    {
3890141cc406Sopenharmony_ci      s->val[OPT_FOCUS].w = 1;
3891141cc406Sopenharmony_ci      s->focusOnGlass = SANE_FALSE;
3892141cc406Sopenharmony_ci    }
3893141cc406Sopenharmony_ci    deactivateOption (s, OPT_ADF_MODE, &dummy);
3894141cc406Sopenharmony_ci    deactivateOption (s, OPT_EJECT, &dummy);
3895141cc406Sopenharmony_ci    deactivateOption (s, OPT_AUTO_EJECT, &dummy);
3896141cc406Sopenharmony_ci  }
3897141cc406Sopenharmony_ci  else                          /* neither ADF nor TPU active */
3898141cc406Sopenharmony_ci  {
3899141cc406Sopenharmony_ci    s->hw->x_range = &s->hw->fbf_x_range;
3900141cc406Sopenharmony_ci    s->hw->y_range = &s->hw->fbf_y_range;
3901141cc406Sopenharmony_ci    s->hw->use_extension = SANE_FALSE;
3902141cc406Sopenharmony_ci    /* disable film type option */
3903141cc406Sopenharmony_ci    deactivateOption (s, OPT_FILM_TYPE, &dummy);
3904141cc406Sopenharmony_ci    s->val[OPT_FOCUS].w = 0;
3905141cc406Sopenharmony_ci    deactivateOption (s, OPT_ADF_MODE, &dummy);
3906141cc406Sopenharmony_ci  }
3907141cc406Sopenharmony_ci
3908141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].tl_x = s->hw->x_range->min;
3909141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].tl_y = s->hw->y_range->min;
3910141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].br_x = s->hw->x_range->max;
3911141cc406Sopenharmony_ci  qf_params[XtNumber (qf_params) - 1].br_y = s->hw->y_range->max;
3912141cc406Sopenharmony_ci
3913141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
3914141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
3915141cc406Sopenharmony_ci
3916141cc406Sopenharmony_ci  if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max)
3917141cc406Sopenharmony_ci    s->val[OPT_TL_X].w = s->hw->x_range->min;
3918141cc406Sopenharmony_ci
3919141cc406Sopenharmony_ci  if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max)
3920141cc406Sopenharmony_ci    s->val[OPT_TL_Y].w = s->hw->y_range->min;
3921141cc406Sopenharmony_ci
3922141cc406Sopenharmony_ci  if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max)
3923141cc406Sopenharmony_ci    s->val[OPT_BR_X].w = s->hw->x_range->max;
3924141cc406Sopenharmony_ci
3925141cc406Sopenharmony_ci  if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max)
3926141cc406Sopenharmony_ci    s->val[OPT_BR_Y].w = s->hw->y_range->max;
3927141cc406Sopenharmony_ci
3928141cc406Sopenharmony_ci  setOptionState (s, s->hw->ADF && s->hw->use_extension,
3929141cc406Sopenharmony_ci                  OPT_AUTO_EJECT, &dummy);
3930141cc406Sopenharmony_ci  setOptionState (s, s->hw->ADF && s->hw->use_extension, OPT_EJECT, &dummy);
3931141cc406Sopenharmony_ci
3932141cc406Sopenharmony_ci#if 0
3933141cc406Sopenharmony_ci  BAY is part of the filmscan device.We are not sure
3934141cc406Sopenharmony_ci    if we are really going to support this device in this
3935141cc406Sopenharmony_ci    code.Is there an online manual for it ?
3936141cc406Sopenharmony_ci    setOptionState (s, s->hw->ADF && s->hw->use_extension, OPT_BAY, &reload);
3937141cc406Sopenharmony_ci#endif
3938141cc406Sopenharmony_ci}
3939141cc406Sopenharmony_ci
3940141cc406Sopenharmony_ci/**
3941141cc406Sopenharmony_ci    End of handle_source.
3942141cc406Sopenharmony_ci**/
3943141cc406Sopenharmony_ci
3944141cc406Sopenharmony_cistatic SANE_Status
3945141cc406Sopenharmony_cisetvalue (SANE_Handle handle, SANE_Int option, void *value, SANE_Int * info)
3946141cc406Sopenharmony_ci{
3947141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
3948141cc406Sopenharmony_ci  SANE_Option_Descriptor *sopt = &(s->opt[option]);
3949141cc406Sopenharmony_ci  Option_Value *sval = &(s->val[option]);
3950141cc406Sopenharmony_ci
3951141cc406Sopenharmony_ci  SANE_Status status;
3952141cc406Sopenharmony_ci  const SANE_String_Const *optval;
3953141cc406Sopenharmony_ci  int optindex;
3954141cc406Sopenharmony_ci  SANE_Bool reload = SANE_FALSE;
3955141cc406Sopenharmony_ci
3956141cc406Sopenharmony_ci  DBG (5, "setvalue(option = %d, value = %p)\n", option, value);
3957141cc406Sopenharmony_ci
3958141cc406Sopenharmony_ci  status = sanei_constrain_value (sopt, value, info);
3959141cc406Sopenharmony_ci
3960141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3961141cc406Sopenharmony_ci    return status;
3962141cc406Sopenharmony_ci
3963141cc406Sopenharmony_ci  s->option_has_changed = SANE_TRUE;
3964141cc406Sopenharmony_ci
3965141cc406Sopenharmony_ci  optval = NULL;
3966141cc406Sopenharmony_ci  optindex = 0;
3967141cc406Sopenharmony_ci
3968141cc406Sopenharmony_ci  if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST)
3969141cc406Sopenharmony_ci  {
3970141cc406Sopenharmony_ci    optval = search_string_list (sopt->constraint.string_list,
3971141cc406Sopenharmony_ci                                 (char *) value);
3972141cc406Sopenharmony_ci
3973141cc406Sopenharmony_ci    if (optval == NULL)
3974141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3975141cc406Sopenharmony_ci    optindex = optval - sopt->constraint.string_list;
3976141cc406Sopenharmony_ci  }
3977141cc406Sopenharmony_ci
3978141cc406Sopenharmony_ci  switch (option)
3979141cc406Sopenharmony_ci  {
3980141cc406Sopenharmony_ci/*      case OPT_GAMMA_VECTOR: */
3981141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_R:
3982141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_G:
3983141cc406Sopenharmony_ci  case OPT_GAMMA_VECTOR_B:
3984141cc406Sopenharmony_ci    memcpy (sval->wa, value, sopt->size);       /* Word arrays */
3985141cc406Sopenharmony_ci    break;
3986141cc406Sopenharmony_ci
3987141cc406Sopenharmony_ci  case OPT_CCT_1:
3988141cc406Sopenharmony_ci  case OPT_CCT_2:
3989141cc406Sopenharmony_ci  case OPT_CCT_3:
3990141cc406Sopenharmony_ci  case OPT_CCT_4:
3991141cc406Sopenharmony_ci  case OPT_CCT_5:
3992141cc406Sopenharmony_ci  case OPT_CCT_6:
3993141cc406Sopenharmony_ci  case OPT_CCT_7:
3994141cc406Sopenharmony_ci  case OPT_CCT_8:
3995141cc406Sopenharmony_ci  case OPT_CCT_9:
3996141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);   /* Simple values */
3997141cc406Sopenharmony_ci    break;
3998141cc406Sopenharmony_ci
3999141cc406Sopenharmony_ci  case OPT_DROPOUT:
4000141cc406Sopenharmony_ci  case OPT_FILM_TYPE:
4001141cc406Sopenharmony_ci  case OPT_BAY:
4002141cc406Sopenharmony_ci  case OPT_FOCUS:
4003141cc406Sopenharmony_ci    sval->w = optindex;         /* Simple lists */
4004141cc406Sopenharmony_ci    break;
4005141cc406Sopenharmony_ci
4006141cc406Sopenharmony_ci  case OPT_EJECT:
4007141cc406Sopenharmony_ci/*              return eject( s ); */
4008141cc406Sopenharmony_ci    eject (s);
4009141cc406Sopenharmony_ci    break;
4010141cc406Sopenharmony_ci
4011141cc406Sopenharmony_ci  case OPT_RESOLUTION:
4012141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);
4013141cc406Sopenharmony_ci    reload = SANE_TRUE;
4014141cc406Sopenharmony_ci    break;
4015141cc406Sopenharmony_ci
4016141cc406Sopenharmony_ci  case OPT_TL_X:
4017141cc406Sopenharmony_ci  case OPT_TL_Y:
4018141cc406Sopenharmony_ci  case OPT_BR_X:
4019141cc406Sopenharmony_ci  case OPT_BR_Y:
4020141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);
4021141cc406Sopenharmony_ci    DBG (1, "set = %f\n", SANE_UNFIX (sval->w));
4022141cc406Sopenharmony_ci    if (NULL != info)
4023141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
4024141cc406Sopenharmony_ci    break;
4025141cc406Sopenharmony_ci
4026141cc406Sopenharmony_ci  case OPT_SOURCE:
4027141cc406Sopenharmony_ci    handle_source (s, optindex, (char *) value);
4028141cc406Sopenharmony_ci    reload = SANE_TRUE;
4029141cc406Sopenharmony_ci    break;
4030141cc406Sopenharmony_ci
4031141cc406Sopenharmony_ci  case OPT_MODE:
4032141cc406Sopenharmony_ci    {
4033141cc406Sopenharmony_ci      SANE_Bool isColor = mode_params[optindex].color;
4034141cc406Sopenharmony_ci      SANE_Bool userDefined =
4035141cc406Sopenharmony_ci        color_userdefined[s->val[OPT_COLOR_CORRECTION].w];
4036141cc406Sopenharmony_ci
4037141cc406Sopenharmony_ci      sval->w = optindex;
4038141cc406Sopenharmony_ci
4039141cc406Sopenharmony_ci      if (s->hw->cmd->set_halftoning != 0)
4040141cc406Sopenharmony_ci      {
4041141cc406Sopenharmony_ci        setOptionState (s, mode_params[optindex].depth == 1,
4042141cc406Sopenharmony_ci                        OPT_HALFTONE, &reload);
4043141cc406Sopenharmony_ci      }
4044141cc406Sopenharmony_ci
4045141cc406Sopenharmony_ci      setOptionState (s, !isColor, OPT_DROPOUT, &reload);
4046141cc406Sopenharmony_ci      if (s->hw->cmd->set_color_correction)
4047141cc406Sopenharmony_ci      {
4048141cc406Sopenharmony_ci        setOptionState (s, isColor, OPT_COLOR_CORRECTION, &reload);
4049141cc406Sopenharmony_ci      }
4050141cc406Sopenharmony_ci      if (s->hw->cmd->set_color_correction_coefficients)
4051141cc406Sopenharmony_ci      {
4052141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_1, &reload);
4053141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_2, &reload);
4054141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_3, &reload);
4055141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_4, &reload);
4056141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_5, &reload);
4057141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_6, &reload);
4058141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_7, &reload);
4059141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_8, &reload);
4060141cc406Sopenharmony_ci        setOptionState (s, isColor && userDefined, OPT_CCT_9, &reload);
4061141cc406Sopenharmony_ci      }
4062141cc406Sopenharmony_ci
4063141cc406Sopenharmony_ci      /* if binary, then disable the bit depth selection */
4064141cc406Sopenharmony_ci      if (optindex == 0)
4065141cc406Sopenharmony_ci      {
4066141cc406Sopenharmony_ci        s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
4067141cc406Sopenharmony_ci      }
4068141cc406Sopenharmony_ci      else
4069141cc406Sopenharmony_ci      {
4070141cc406Sopenharmony_ci        if (bitDepthList[0] == 1)
4071141cc406Sopenharmony_ci          s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
4072141cc406Sopenharmony_ci        else
4073141cc406Sopenharmony_ci        {
4074141cc406Sopenharmony_ci          s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
4075141cc406Sopenharmony_ci          s->val[OPT_BIT_DEPTH].w = mode_params[optindex].depth;
4076141cc406Sopenharmony_ci        }
4077141cc406Sopenharmony_ci      }
4078141cc406Sopenharmony_ci
4079141cc406Sopenharmony_ci      handle_depth_halftone (s, &reload);
4080141cc406Sopenharmony_ci      reload = SANE_TRUE;
4081141cc406Sopenharmony_ci
4082141cc406Sopenharmony_ci      break;
4083141cc406Sopenharmony_ci    }
4084141cc406Sopenharmony_ci
4085141cc406Sopenharmony_ci  case OPT_ADF_MODE:
4086141cc406Sopenharmony_ci    sval->w = optindex;
4087141cc406Sopenharmony_ci    break;
4088141cc406Sopenharmony_ci
4089141cc406Sopenharmony_ci  case OPT_BIT_DEPTH:
4090141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);
4091141cc406Sopenharmony_ci    mode_params[s->val[OPT_MODE].w].depth = sval->w;
4092141cc406Sopenharmony_ci    reload = SANE_TRUE;
4093141cc406Sopenharmony_ci    break;
4094141cc406Sopenharmony_ci
4095141cc406Sopenharmony_ci  case OPT_HALFTONE:
4096141cc406Sopenharmony_ci    sval->w = optindex;
4097141cc406Sopenharmony_ci    handle_depth_halftone (s, &reload);
4098141cc406Sopenharmony_ci    break;
4099141cc406Sopenharmony_ci
4100141cc406Sopenharmony_ci  case OPT_COLOR_CORRECTION:
4101141cc406Sopenharmony_ci    {
4102141cc406Sopenharmony_ci      SANE_Bool f = color_userdefined[optindex];
4103141cc406Sopenharmony_ci
4104141cc406Sopenharmony_ci      sval->w = optindex;
4105141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_1, &reload);
4106141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_2, &reload);
4107141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_3, &reload);
4108141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_4, &reload);
4109141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_5, &reload);
4110141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_6, &reload);
4111141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_7, &reload);
4112141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_8, &reload);
4113141cc406Sopenharmony_ci      setOptionState (s, f, OPT_CCT_9, &reload);
4114141cc406Sopenharmony_ci
4115141cc406Sopenharmony_ci      break;
4116141cc406Sopenharmony_ci    }
4117141cc406Sopenharmony_ci
4118141cc406Sopenharmony_ci  case OPT_GAMMA_CORRECTION:
4119141cc406Sopenharmony_ci    {
4120141cc406Sopenharmony_ci      SANE_Bool f = gamma_userdefined[optindex];
4121141cc406Sopenharmony_ci
4122141cc406Sopenharmony_ci      sval->w = optindex;
4123141cc406Sopenharmony_ci/*              setOptionState(s, f, OPT_GAMMA_VECTOR, &reload ); */
4124141cc406Sopenharmony_ci      setOptionState (s, f, OPT_GAMMA_VECTOR_R, &reload);
4125141cc406Sopenharmony_ci      setOptionState (s, f, OPT_GAMMA_VECTOR_G, &reload);
4126141cc406Sopenharmony_ci      setOptionState (s, f, OPT_GAMMA_VECTOR_B, &reload);
4127141cc406Sopenharmony_ci      setOptionState (s, !f, OPT_BRIGHTNESS, &reload);  /* Note... */
4128141cc406Sopenharmony_ci
4129141cc406Sopenharmony_ci      break;
4130141cc406Sopenharmony_ci    }
4131141cc406Sopenharmony_ci
4132141cc406Sopenharmony_ci  case OPT_MIRROR:
4133141cc406Sopenharmony_ci  case OPT_SPEED:
4134141cc406Sopenharmony_ci  case OPT_PREVIEW_SPEED:
4135141cc406Sopenharmony_ci  case OPT_AAS:
4136141cc406Sopenharmony_ci  case OPT_PREVIEW:             /* needed? */
4137141cc406Sopenharmony_ci  case OPT_BRIGHTNESS:
4138141cc406Sopenharmony_ci  case OPT_SHARPNESS:
4139141cc406Sopenharmony_ci  case OPT_AUTO_EJECT:
4140141cc406Sopenharmony_ci  case OPT_THRESHOLD:
4141141cc406Sopenharmony_ci  case OPT_ZOOM:
4142141cc406Sopenharmony_ci  case OPT_WAIT_FOR_BUTTON:
4143141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);
4144141cc406Sopenharmony_ci    break;
4145141cc406Sopenharmony_ci
4146141cc406Sopenharmony_ci  case OPT_LIMIT_RESOLUTION:
4147141cc406Sopenharmony_ci    sval->w = *((SANE_Word *) value);
4148141cc406Sopenharmony_ci    filter_resolution_list (s);
4149141cc406Sopenharmony_ci    reload = SANE_TRUE;
4150141cc406Sopenharmony_ci    break;
4151141cc406Sopenharmony_ci
4152141cc406Sopenharmony_ci  case OPT_QUICK_FORMAT:
4153141cc406Sopenharmony_ci    sval->w = optindex;
4154141cc406Sopenharmony_ci
4155141cc406Sopenharmony_ci    s->val[OPT_TL_X].w = qf_params[sval->w].tl_x;
4156141cc406Sopenharmony_ci    s->val[OPT_TL_Y].w = qf_params[sval->w].tl_y;
4157141cc406Sopenharmony_ci    s->val[OPT_BR_X].w = qf_params[sval->w].br_x;
4158141cc406Sopenharmony_ci    s->val[OPT_BR_Y].w = qf_params[sval->w].br_y;
4159141cc406Sopenharmony_ci
4160141cc406Sopenharmony_ci    if (s->val[OPT_TL_X].w < s->hw->x_range->min)
4161141cc406Sopenharmony_ci      s->val[OPT_TL_X].w = s->hw->x_range->min;
4162141cc406Sopenharmony_ci
4163141cc406Sopenharmony_ci    if (s->val[OPT_TL_Y].w < s->hw->y_range->min)
4164141cc406Sopenharmony_ci      s->val[OPT_TL_Y].w = s->hw->y_range->min;
4165141cc406Sopenharmony_ci
4166141cc406Sopenharmony_ci    if (s->val[OPT_BR_X].w > s->hw->x_range->max)
4167141cc406Sopenharmony_ci      s->val[OPT_BR_X].w = s->hw->x_range->max;
4168141cc406Sopenharmony_ci
4169141cc406Sopenharmony_ci    if (s->val[OPT_BR_Y].w > s->hw->y_range->max)
4170141cc406Sopenharmony_ci      s->val[OPT_BR_Y].w = s->hw->y_range->max;
4171141cc406Sopenharmony_ci
4172141cc406Sopenharmony_ci    reload = SANE_TRUE;
4173141cc406Sopenharmony_ci    break;
4174141cc406Sopenharmony_ci
4175141cc406Sopenharmony_ci  default:
4176141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4177141cc406Sopenharmony_ci  }
4178141cc406Sopenharmony_ci
4179141cc406Sopenharmony_ci  if (reload && info != NULL)
4180141cc406Sopenharmony_ci  {
4181141cc406Sopenharmony_ci    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
4182141cc406Sopenharmony_ci  }
4183141cc406Sopenharmony_ci
4184141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4185141cc406Sopenharmony_ci}
4186141cc406Sopenharmony_ci
4187141cc406Sopenharmony_ci/**
4188141cc406Sopenharmony_ci    End of setvalue.
4189141cc406Sopenharmony_ci**/
4190141cc406Sopenharmony_ci
4191141cc406Sopenharmony_ciSANE_Status
4192141cc406Sopenharmony_cisane_control_option (SANE_Handle handle,
4193141cc406Sopenharmony_ci                     SANE_Int option,
4194141cc406Sopenharmony_ci                     SANE_Action action, void *value, SANE_Int * info)
4195141cc406Sopenharmony_ci{
4196141cc406Sopenharmony_ci  if (option < 0 || option >= NUM_OPTIONS)
4197141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4198141cc406Sopenharmony_ci
4199141cc406Sopenharmony_ci  if (info != NULL)
4200141cc406Sopenharmony_ci    *info = 0;
4201141cc406Sopenharmony_ci
4202141cc406Sopenharmony_ci  switch (action)
4203141cc406Sopenharmony_ci  {
4204141cc406Sopenharmony_ci  case SANE_ACTION_GET_VALUE:
4205141cc406Sopenharmony_ci    return (getvalue (handle, option, value));
4206141cc406Sopenharmony_ci
4207141cc406Sopenharmony_ci  case SANE_ACTION_SET_VALUE:
4208141cc406Sopenharmony_ci    return (setvalue (handle, option, value, info));
4209141cc406Sopenharmony_ci  default:
4210141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4211141cc406Sopenharmony_ci  }
4212141cc406Sopenharmony_ci
4213141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4214141cc406Sopenharmony_ci}
4215141cc406Sopenharmony_ci
4216141cc406Sopenharmony_ci/*
4217141cc406Sopenharmony_ci * sane_get_parameters()
4218141cc406Sopenharmony_ci *
4219141cc406Sopenharmony_ci * This function is part of the SANE API and gets called when the front end
4220141cc406Sopenharmony_ci * requests information aobut the scan configuration (e.g. color depth, mode,
4221141cc406Sopenharmony_ci * bytes and pixels per line, number of lines. This information is returned
4222141cc406Sopenharmony_ci * in the SANE_Parameters structure.
4223141cc406Sopenharmony_ci *
4224141cc406Sopenharmony_ci * Once a scan was started, this routine has to report the correct values, if
4225141cc406Sopenharmony_ci * it is called before the scan is actually started, the values are based on
4226141cc406Sopenharmony_ci * the current settings.
4227141cc406Sopenharmony_ci *
4228141cc406Sopenharmony_ci */
4229141cc406Sopenharmony_ciSANE_Status
4230141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
4231141cc406Sopenharmony_ci{
4232141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
4233141cc406Sopenharmony_ci  int ndpi;
4234141cc406Sopenharmony_ci  int bytes_per_pixel;
4235141cc406Sopenharmony_ci
4236141cc406Sopenharmony_ci  DBG (5, "sane_get_parameters()\n");
4237141cc406Sopenharmony_ci
4238141cc406Sopenharmony_ci  /*
4239141cc406Sopenharmony_ci   * If sane_start was already called, then just retrieve the parameters
4240141cc406Sopenharmony_ci   * from the scanner data structure
4241141cc406Sopenharmony_ci   */
4242141cc406Sopenharmony_ci
4243141cc406Sopenharmony_ci  if (!s->eof && s->ptr != NULL)
4244141cc406Sopenharmony_ci  {
4245141cc406Sopenharmony_ci    DBG (5, "Returning saved params structure\n");
4246141cc406Sopenharmony_ci    if (params != NULL)
4247141cc406Sopenharmony_ci    {
4248141cc406Sopenharmony_ci                        DBG(1, "Restoring parameters from saved parameters\n");
4249141cc406Sopenharmony_ci                        *params = s->params;
4250141cc406Sopenharmony_ci    }
4251141cc406Sopenharmony_ci
4252141cc406Sopenharmony_ci    DBG (3, "Preview = %d\n", s->val[OPT_PREVIEW].w);
4253141cc406Sopenharmony_ci    DBG (3, "Resolution = %d\n", s->val[OPT_RESOLUTION].w);
4254141cc406Sopenharmony_ci
4255141cc406Sopenharmony_ci    DBG (1, "get para %p %p tlx %f tly %f brx %f bry %f [mm]\n", (void *) s,
4256141cc406Sopenharmony_ci         (void *) s->val, SANE_UNFIX (s->val[OPT_TL_X].w),
4257141cc406Sopenharmony_ci         SANE_UNFIX (s->val[OPT_TL_Y].w), SANE_UNFIX (s->val[OPT_BR_X].w),
4258141cc406Sopenharmony_ci         SANE_UNFIX (s->val[OPT_BR_Y].w));
4259141cc406Sopenharmony_ci
4260141cc406Sopenharmony_ci    print_params (s->params);
4261141cc406Sopenharmony_ci
4262141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4263141cc406Sopenharmony_ci  }
4264141cc406Sopenharmony_ci
4265141cc406Sopenharmony_ci  /* otherwise initialize the params structure and gather the data */
4266141cc406Sopenharmony_ci
4267141cc406Sopenharmony_ci  memset (&s->params, 0, sizeof (SANE_Parameters));
4268141cc406Sopenharmony_ci
4269141cc406Sopenharmony_ci  ndpi = s->val[OPT_RESOLUTION].w;
4270141cc406Sopenharmony_ci
4271141cc406Sopenharmony_ci  s->params.pixels_per_line =
4272141cc406Sopenharmony_ci    SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) / 25.4 * ndpi + 0.5;
4273141cc406Sopenharmony_ci  s->params.lines =
4274141cc406Sopenharmony_ci    SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) / 25.4 * ndpi + 0.5;
4275141cc406Sopenharmony_ci
4276141cc406Sopenharmony_ci  /*
4277141cc406Sopenharmony_ci   * Make sure that the number of lines is correct for color shuffling:
4278141cc406Sopenharmony_ci   * The shuffling algorithm produces 2xline_distance lines at the
4279141cc406Sopenharmony_ci   * beginning and the same amount at the end of the scan that are not
4280141cc406Sopenharmony_ci   * useable. If s->params.lines gets negative, 0 lines are reported
4281141cc406Sopenharmony_ci   * back to the frontend.
4282141cc406Sopenharmony_ci   */
4283141cc406Sopenharmony_ci  if (s->hw->color_shuffle)
4284141cc406Sopenharmony_ci  {
4285141cc406Sopenharmony_ci    s->params.lines -= 4 * s->line_distance;
4286141cc406Sopenharmony_ci    if (s->params.lines < 0)
4287141cc406Sopenharmony_ci    {
4288141cc406Sopenharmony_ci      s->params.lines = 0;
4289141cc406Sopenharmony_ci    }
4290141cc406Sopenharmony_ci    DBG (1, "Adjusted params.lines for color_shuffle by %d to %d\n",
4291141cc406Sopenharmony_ci         4 * s->line_distance, s->params.lines);
4292141cc406Sopenharmony_ci  }
4293141cc406Sopenharmony_ci
4294141cc406Sopenharmony_ci  DBG (3, "Preview = %d\n", s->val[OPT_PREVIEW].w);
4295141cc406Sopenharmony_ci  DBG (3, "Resolution = %d\n", s->val[OPT_RESOLUTION].w);
4296141cc406Sopenharmony_ci
4297141cc406Sopenharmony_ci  DBG (1, "get para %p %p tlx %f tly %f brx %f bry %f [mm]\n", (void *) s,
4298141cc406Sopenharmony_ci       (void *) s->val, SANE_UNFIX (s->val[OPT_TL_X].w),
4299141cc406Sopenharmony_ci       SANE_UNFIX (s->val[OPT_TL_Y].w), SANE_UNFIX (s->val[OPT_BR_X].w),
4300141cc406Sopenharmony_ci       SANE_UNFIX (s->val[OPT_BR_Y].w));
4301141cc406Sopenharmony_ci
4302141cc406Sopenharmony_ci
4303141cc406Sopenharmony_ci  /*
4304141cc406Sopenharmony_ci   * Calculate bytes_per_pixel and bytes_per_line for
4305141cc406Sopenharmony_ci   * any color depths.
4306141cc406Sopenharmony_ci   *
4307141cc406Sopenharmony_ci   * The default color depth is stored in mode_params.depth:
4308141cc406Sopenharmony_ci   */
4309141cc406Sopenharmony_ci
4310141cc406Sopenharmony_ci  if (mode_params[s->val[OPT_MODE].w].depth == 1)
4311141cc406Sopenharmony_ci  {
4312141cc406Sopenharmony_ci    s->params.depth = 1;
4313141cc406Sopenharmony_ci  }
4314141cc406Sopenharmony_ci  else
4315141cc406Sopenharmony_ci  {
4316141cc406Sopenharmony_ci    s->params.depth = s->val[OPT_BIT_DEPTH].w;
4317141cc406Sopenharmony_ci  }
4318141cc406Sopenharmony_ci
4319141cc406Sopenharmony_ci  if (s->params.depth > 8)
4320141cc406Sopenharmony_ci  {
4321141cc406Sopenharmony_ci    s->params.depth = 16;       /*
4322141cc406Sopenharmony_ci                                 * The frontends can only handle 8 or 16 bits
4323141cc406Sopenharmony_ci                                 * for gray or color - so if it's more than 8,
4324141cc406Sopenharmony_ci                                 * it gets automatically set to 16. This works
4325141cc406Sopenharmony_ci                                 * as long as EPSON does not come out with a
4326141cc406Sopenharmony_ci                                 * scanner that can handle more than 16 bits
4327141cc406Sopenharmony_ci                                 * per color channel.
4328141cc406Sopenharmony_ci                                 */
4329141cc406Sopenharmony_ci
4330141cc406Sopenharmony_ci  }
4331141cc406Sopenharmony_ci
4332141cc406Sopenharmony_ci  bytes_per_pixel = s->params.depth / 8;        /* this works because it can only be set to 1, 8 or 16 */
4333141cc406Sopenharmony_ci  if (s->params.depth % 8)      /* just in case ... */
4334141cc406Sopenharmony_ci  {
4335141cc406Sopenharmony_ci    bytes_per_pixel++;
4336141cc406Sopenharmony_ci  }
4337141cc406Sopenharmony_ci
4338141cc406Sopenharmony_ci  /* pixels_per_line is rounded to the next 8bit boundary */
4339141cc406Sopenharmony_ci  s->params.pixels_per_line = s->params.pixels_per_line & ~7;
4340141cc406Sopenharmony_ci
4341141cc406Sopenharmony_ci  s->params.last_frame = SANE_TRUE;
4342141cc406Sopenharmony_ci
4343141cc406Sopenharmony_ci  if (mode_params[s->val[OPT_MODE].w].color)
4344141cc406Sopenharmony_ci  {
4345141cc406Sopenharmony_ci    s->params.format = SANE_FRAME_RGB;
4346141cc406Sopenharmony_ci    s->params.bytes_per_line =
4347141cc406Sopenharmony_ci      3 * s->params.pixels_per_line * bytes_per_pixel;
4348141cc406Sopenharmony_ci  }
4349141cc406Sopenharmony_ci  else
4350141cc406Sopenharmony_ci  {
4351141cc406Sopenharmony_ci    s->params.format = SANE_FRAME_GRAY;
4352141cc406Sopenharmony_ci    s->params.bytes_per_line =
4353141cc406Sopenharmony_ci      s->params.pixels_per_line * s->params.depth / 8;
4354141cc406Sopenharmony_ci  }
4355141cc406Sopenharmony_ci
4356141cc406Sopenharmony_ci  if (NULL != params)
4357141cc406Sopenharmony_ci    *params = s->params;
4358141cc406Sopenharmony_ci
4359141cc406Sopenharmony_ci  print_params (s->params);
4360141cc406Sopenharmony_ci
4361141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4362141cc406Sopenharmony_ci}
4363141cc406Sopenharmony_ci
4364141cc406Sopenharmony_ci/*
4365141cc406Sopenharmony_ci * sane_start()
4366141cc406Sopenharmony_ci *
4367141cc406Sopenharmony_ci * This function is part of the SANE API and gets called from the front end to
4368141cc406Sopenharmony_ci * start the scan process.
4369141cc406Sopenharmony_ci *
4370141cc406Sopenharmony_ci */
4371141cc406Sopenharmony_ci
4372141cc406Sopenharmony_ciSANE_Status
4373141cc406Sopenharmony_cisane_start (SANE_Handle handle)
4374141cc406Sopenharmony_ci{
4375141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
4376141cc406Sopenharmony_ci  SANE_Status status;
4377141cc406Sopenharmony_ci  SANE_Bool button_status;
4378141cc406Sopenharmony_ci  const struct mode_param *mparam;
4379141cc406Sopenharmony_ci  u_char params[4];
4380141cc406Sopenharmony_ci  int ndpi;
4381141cc406Sopenharmony_ci  int left, top;
4382141cc406Sopenharmony_ci  int lcount;
4383141cc406Sopenharmony_ci  int i, j;                     /* loop counter */
4384141cc406Sopenharmony_ci
4385141cc406Sopenharmony_ci  DBG (5, "sane_start()\n");
4386141cc406Sopenharmony_ci
4387141cc406Sopenharmony_ci  open_scanner (s);
4388141cc406Sopenharmony_ci
4389141cc406Sopenharmony_ci/*
4390141cc406Sopenharmony_ci *  There is some undocumented special behavior with the TPU enable/disable.
4391141cc406Sopenharmony_ci *      TPU power       ESC e           status
4392141cc406Sopenharmony_ci *      on              0               NAK
4393141cc406Sopenharmony_ci *      on              1               ACK
4394141cc406Sopenharmony_ci *      off             0               ACK
4395141cc406Sopenharmony_ci *      off             1               NAK
4396141cc406Sopenharmony_ci *
4397141cc406Sopenharmony_ci * It makes no sense to scan with TPU powered on and source flatbed, because
4398141cc406Sopenharmony_ci * light will come from both sides.
4399141cc406Sopenharmony_ci */
4400141cc406Sopenharmony_ci
4401141cc406Sopenharmony_ci  if (s->hw->extension)
4402141cc406Sopenharmony_ci  {
4403141cc406Sopenharmony_ci    int max_x, max_y;
4404141cc406Sopenharmony_ci
4405141cc406Sopenharmony_ci    int extensionCtrl;
4406141cc406Sopenharmony_ci    extensionCtrl = (s->hw->use_extension ? 1 : 0);
4407141cc406Sopenharmony_ci    if (s->hw->use_extension && (s->val[OPT_ADF_MODE].w == 1))
4408141cc406Sopenharmony_ci      extensionCtrl = 2;
4409141cc406Sopenharmony_ci
4410141cc406Sopenharmony_ci    status = control_extension (s, extensionCtrl);
4411141cc406Sopenharmony_ci
4412141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4413141cc406Sopenharmony_ci    {
4414141cc406Sopenharmony_ci      DBG (1, "You may have to power %s your TPU\n",
4415141cc406Sopenharmony_ci           s->hw->use_extension ? "on" : "off");
4416141cc406Sopenharmony_ci
4417141cc406Sopenharmony_ci      DBG (1, "Also you may have to restart the Sane frontend.\n");
4418141cc406Sopenharmony_ci      close_scanner (s);
4419141cc406Sopenharmony_ci      return status;
4420141cc406Sopenharmony_ci    }
4421141cc406Sopenharmony_ci
4422141cc406Sopenharmony_ci    if (s->hw->cmd->request_extended_status != 0)
4423141cc406Sopenharmony_ci    {
4424141cc406Sopenharmony_ci      status = check_ext_status (s, &max_x, &max_y);
4425141cc406Sopenharmony_ci
4426141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status && SANE_STATUS_DEVICE_BUSY != status)
4427141cc406Sopenharmony_ci      {
4428141cc406Sopenharmony_ci        close_scanner (s);
4429141cc406Sopenharmony_ci        return status;
4430141cc406Sopenharmony_ci      }
4431141cc406Sopenharmony_ci    }
4432141cc406Sopenharmony_ci
4433141cc406Sopenharmony_ci    if (s->hw->ADF && s->hw->use_extension && s->hw->cmd->feed)
4434141cc406Sopenharmony_ci    {
4435141cc406Sopenharmony_ci      status = feed (s);
4436141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
4437141cc406Sopenharmony_ci      {
4438141cc406Sopenharmony_ci        close_scanner (s);
4439141cc406Sopenharmony_ci        return status;
4440141cc406Sopenharmony_ci      }
4441141cc406Sopenharmony_ci
4442141cc406Sopenharmony_ci      check_ext_status (s, &max_x, &max_y);
4443141cc406Sopenharmony_ci      s->hw->adf_max_x = max_x;
4444141cc406Sopenharmony_ci      s->hw->adf_max_y = max_y;
4445141cc406Sopenharmony_ci    }
4446141cc406Sopenharmony_ci
4447141cc406Sopenharmony_ci
4448141cc406Sopenharmony_ci    /*
4449141cc406Sopenharmony_ci     * set the focus position according to the extension used:
4450141cc406Sopenharmony_ci     * if the TPU is selected, then focus 2.5mm above the glass,
4451141cc406Sopenharmony_ci     * otherwise focus on the glass. Scanners that don't support
4452141cc406Sopenharmony_ci     * this feature, will just ignore these calls.
4453141cc406Sopenharmony_ci     */
4454141cc406Sopenharmony_ci
4455141cc406Sopenharmony_ci    if (s->hw->focusSupport == SANE_TRUE)
4456141cc406Sopenharmony_ci    {
4457141cc406Sopenharmony_ci      if (s->val[OPT_FOCUS].w == 0)
4458141cc406Sopenharmony_ci      {
4459141cc406Sopenharmony_ci        DBG (1, "Setting focus to glass surface\n");
4460141cc406Sopenharmony_ci        set_focus_position (s, 0x40);
4461141cc406Sopenharmony_ci      }
4462141cc406Sopenharmony_ci      else
4463141cc406Sopenharmony_ci      {
4464141cc406Sopenharmony_ci        DBG (1, "Setting focus to 2.5mm above glass\n");
4465141cc406Sopenharmony_ci        set_focus_position (s, 0x59);
4466141cc406Sopenharmony_ci      }
4467141cc406Sopenharmony_ci    }
4468141cc406Sopenharmony_ci  }
4469141cc406Sopenharmony_ci
4470141cc406Sopenharmony_ci  /* use the flatbed size for the max. scansize for the GT-30000
4471141cc406Sopenharmony_ci     and similar scanners if the ADF is not enabled */
4472141cc406Sopenharmony_ci  if (s->hw->devtype == 3 && s->hw->use_extension == 0)
4473141cc406Sopenharmony_ci  {
4474141cc406Sopenharmony_ci    int max_x, max_y;
4475141cc406Sopenharmony_ci
4476141cc406Sopenharmony_ci    status = check_ext_status (s, &max_x, &max_y);
4477141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status && SANE_STATUS_DEVICE_BUSY != status)
4478141cc406Sopenharmony_ci    {
4479141cc406Sopenharmony_ci      close_scanner (s);
4480141cc406Sopenharmony_ci      return status;
4481141cc406Sopenharmony_ci    }
4482141cc406Sopenharmony_ci
4483141cc406Sopenharmony_ci    s->hw->fbf_max_x = max_x;
4484141cc406Sopenharmony_ci    s->hw->fbf_max_y = max_y;
4485141cc406Sopenharmony_ci  }
4486141cc406Sopenharmony_ci
4487141cc406Sopenharmony_ci
4488141cc406Sopenharmony_ci  mparam = mode_params + s->val[OPT_MODE].w;
4489141cc406Sopenharmony_ci  DBG (1, "sane_start: Setting data format to %d bits\n", mparam->depth);
4490141cc406Sopenharmony_ci  status = set_data_format (s, mparam->depth);
4491141cc406Sopenharmony_ci
4492141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
4493141cc406Sopenharmony_ci  {
4494141cc406Sopenharmony_ci    DBG (1, "sane_start: set_data_format failed: %s\n",
4495141cc406Sopenharmony_ci         sane_strstatus (status));
4496141cc406Sopenharmony_ci    return status;
4497141cc406Sopenharmony_ci  }
4498141cc406Sopenharmony_ci
4499141cc406Sopenharmony_ci  /*
4500141cc406Sopenharmony_ci   * The byte sequence mode was introduced in B5, for B[34] we need line sequence mode
4501141cc406Sopenharmony_ci   */
4502141cc406Sopenharmony_ci
4503141cc406Sopenharmony_ci  if ((s->hw->cmd->level[0] == 'D' ||
4504141cc406Sopenharmony_ci       (s->hw->cmd->level[0] == 'B' && s->hw->level >= 5)) &&
4505141cc406Sopenharmony_ci      mparam->mode_flags == 0x02)
4506141cc406Sopenharmony_ci  {
4507141cc406Sopenharmony_ci    status = set_color_mode (s, 0x13);
4508141cc406Sopenharmony_ci  }
4509141cc406Sopenharmony_ci  else
4510141cc406Sopenharmony_ci  {
4511141cc406Sopenharmony_ci    status = set_color_mode (s, mparam->mode_flags | (mparam->dropout_mask
4512141cc406Sopenharmony_ci                                                      & dropout_params[s->
4513141cc406Sopenharmony_ci                                                                       val
4514141cc406Sopenharmony_ci                                                                       [OPT_DROPOUT].
4515141cc406Sopenharmony_ci                                                                       w]));
4516141cc406Sopenharmony_ci  }
4517141cc406Sopenharmony_ci
4518141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
4519141cc406Sopenharmony_ci  {
4520141cc406Sopenharmony_ci    DBG (1, "sane_start: set_color_mode failed: %s\n",
4521141cc406Sopenharmony_ci         sane_strstatus (status));
4522141cc406Sopenharmony_ci    return status;
4523141cc406Sopenharmony_ci  }
4524141cc406Sopenharmony_ci
4525141cc406Sopenharmony_ci  if (s->hw->cmd->set_halftoning &&
4526141cc406Sopenharmony_ci      SANE_OPTION_IS_ACTIVE (s->opt[OPT_HALFTONE].cap))
4527141cc406Sopenharmony_ci  {
4528141cc406Sopenharmony_ci    status = set_halftoning (s, halftone_params[s->val[OPT_HALFTONE].w]);
4529141cc406Sopenharmony_ci
4530141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4531141cc406Sopenharmony_ci    {
4532141cc406Sopenharmony_ci      DBG (1, "sane_start: set_halftoning failed: %s\n",
4533141cc406Sopenharmony_ci           sane_strstatus (status));
4534141cc406Sopenharmony_ci      return status;
4535141cc406Sopenharmony_ci    }
4536141cc406Sopenharmony_ci  }
4537141cc406Sopenharmony_ci
4538141cc406Sopenharmony_ci
4539141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_BRIGHTNESS].cap))
4540141cc406Sopenharmony_ci  {
4541141cc406Sopenharmony_ci    status = set_bright (s, s->val[OPT_BRIGHTNESS].w);
4542141cc406Sopenharmony_ci
4543141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4544141cc406Sopenharmony_ci    {
4545141cc406Sopenharmony_ci      DBG (1, "sane_start: set_bright failed: %s\n", sane_strstatus (status));
4546141cc406Sopenharmony_ci      return status;
4547141cc406Sopenharmony_ci    }
4548141cc406Sopenharmony_ci  }
4549141cc406Sopenharmony_ci
4550141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_MIRROR].cap))
4551141cc406Sopenharmony_ci  {
4552141cc406Sopenharmony_ci    status = mirror_image (s, mirror_params[s->val[OPT_MIRROR].w]);
4553141cc406Sopenharmony_ci
4554141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4555141cc406Sopenharmony_ci    {
4556141cc406Sopenharmony_ci      DBG (1, "sane_start: mirror_image failed: %s\n",
4557141cc406Sopenharmony_ci           sane_strstatus (status));
4558141cc406Sopenharmony_ci      return status;
4559141cc406Sopenharmony_ci    }
4560141cc406Sopenharmony_ci
4561141cc406Sopenharmony_ci  }
4562141cc406Sopenharmony_ci
4563141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_SPEED].cap))
4564141cc406Sopenharmony_ci  {
4565141cc406Sopenharmony_ci
4566141cc406Sopenharmony_ci    if (s->val[OPT_PREVIEW].w)
4567141cc406Sopenharmony_ci      status = set_speed (s, speed_params[s->val[OPT_PREVIEW_SPEED].w]);
4568141cc406Sopenharmony_ci    else
4569141cc406Sopenharmony_ci      status = set_speed (s, speed_params[s->val[OPT_SPEED].w]);
4570141cc406Sopenharmony_ci
4571141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4572141cc406Sopenharmony_ci    {
4573141cc406Sopenharmony_ci      DBG (1, "sane_start: set_speed failed: %s\n", sane_strstatus (status));
4574141cc406Sopenharmony_ci      return status;
4575141cc406Sopenharmony_ci    }
4576141cc406Sopenharmony_ci
4577141cc406Sopenharmony_ci  }
4578141cc406Sopenharmony_ci
4579141cc406Sopenharmony_ci/*
4580141cc406Sopenharmony_ci *  use of speed_params is ok here since they are false and true.
4581141cc406Sopenharmony_ci *  NOTE: I think I should throw that "params" stuff as long w is already the value.
4582141cc406Sopenharmony_ci */
4583141cc406Sopenharmony_ci
4584141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_AAS].cap))
4585141cc406Sopenharmony_ci  {
4586141cc406Sopenharmony_ci    status = control_auto_area_segmentation (s,
4587141cc406Sopenharmony_ci                                             speed_params[s->val[OPT_AAS].w]);
4588141cc406Sopenharmony_ci
4589141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4590141cc406Sopenharmony_ci    {
4591141cc406Sopenharmony_ci      DBG (1, "sane_start: control_auto_area_segmentation failed: %s\n",
4592141cc406Sopenharmony_ci           sane_strstatus (status));
4593141cc406Sopenharmony_ci      return status;
4594141cc406Sopenharmony_ci    }
4595141cc406Sopenharmony_ci  }
4596141cc406Sopenharmony_ci
4597141cc406Sopenharmony_ci  s->invert_image = SANE_FALSE; /* default: to not inverting the image */
4598141cc406Sopenharmony_ci
4599141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_FILM_TYPE].cap))
4600141cc406Sopenharmony_ci  {
4601141cc406Sopenharmony_ci    s->invert_image = (s->val[OPT_FILM_TYPE].w == FILM_TYPE_NEGATIVE);
4602141cc406Sopenharmony_ci    status = set_film_type (s, film_params[s->val[OPT_FILM_TYPE].w]);
4603141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4604141cc406Sopenharmony_ci    {
4605141cc406Sopenharmony_ci      DBG (1, "sane_start: set_film_type failed: %s\n",
4606141cc406Sopenharmony_ci           sane_strstatus (status));
4607141cc406Sopenharmony_ci      return status;
4608141cc406Sopenharmony_ci    }
4609141cc406Sopenharmony_ci  }
4610141cc406Sopenharmony_ci
4611141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_BAY].cap))
4612141cc406Sopenharmony_ci  {
4613141cc406Sopenharmony_ci    status = set_bay (s, s->val[OPT_BAY].w);
4614141cc406Sopenharmony_ci
4615141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4616141cc406Sopenharmony_ci    {
4617141cc406Sopenharmony_ci      DBG (1, "sane_start: set_bay: %s\n", sane_strstatus (status));
4618141cc406Sopenharmony_ci      return status;
4619141cc406Sopenharmony_ci    }
4620141cc406Sopenharmony_ci  }
4621141cc406Sopenharmony_ci
4622141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_SHARPNESS].cap))
4623141cc406Sopenharmony_ci  {
4624141cc406Sopenharmony_ci
4625141cc406Sopenharmony_ci    status = set_outline_emphasis (s, s->val[OPT_SHARPNESS].w);
4626141cc406Sopenharmony_ci
4627141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4628141cc406Sopenharmony_ci    {
4629141cc406Sopenharmony_ci      DBG (1, "sane_start: set_outline_emphasis failed: %s\n",
4630141cc406Sopenharmony_ci           sane_strstatus (status));
4631141cc406Sopenharmony_ci      return status;
4632141cc406Sopenharmony_ci    }
4633141cc406Sopenharmony_ci  }
4634141cc406Sopenharmony_ci
4635141cc406Sopenharmony_ci  if (s->hw->cmd->set_gamma &&
4636141cc406Sopenharmony_ci      SANE_OPTION_IS_ACTIVE (s->opt[OPT_GAMMA_CORRECTION].cap))
4637141cc406Sopenharmony_ci  {
4638141cc406Sopenharmony_ci    int val;
4639141cc406Sopenharmony_ci    if (s->hw->cmd->level[0] == 'D')
4640141cc406Sopenharmony_ci    {
4641141cc406Sopenharmony_ci      /*
4642141cc406Sopenharmony_ci       * The D1 level has only the two user defined gamma
4643141cc406Sopenharmony_ci       * settings.
4644141cc406Sopenharmony_ci       */
4645141cc406Sopenharmony_ci      val = gamma_params[s->val[OPT_GAMMA_CORRECTION].w];
4646141cc406Sopenharmony_ci    }
4647141cc406Sopenharmony_ci    else
4648141cc406Sopenharmony_ci    {
4649141cc406Sopenharmony_ci      val = gamma_params[s->val[OPT_GAMMA_CORRECTION].w];
4650141cc406Sopenharmony_ci
4651141cc406Sopenharmony_ci      /*
4652141cc406Sopenharmony_ci       * If "Default" is selected then determine the actual value
4653141cc406Sopenharmony_ci       * to send to the scanner: If bilevel mode, just send the
4654141cc406Sopenharmony_ci       * value from the table (0x01), for grayscale or color mode
4655141cc406Sopenharmony_ci       * add one and send 0x02.
4656141cc406Sopenharmony_ci       */
4657141cc406Sopenharmony_ci/*                      if( s->val[ OPT_GAMMA_CORRECTION].w <= 1) { */
4658141cc406Sopenharmony_ci      if (s->val[OPT_GAMMA_CORRECTION].w == 0)
4659141cc406Sopenharmony_ci      {
4660141cc406Sopenharmony_ci        val += mparam->depth == 1 ? 0 : 1;
4661141cc406Sopenharmony_ci      }
4662141cc406Sopenharmony_ci    }
4663141cc406Sopenharmony_ci
4664141cc406Sopenharmony_ci    DBG (1, "sane_start: set_gamma( s, 0x%x ).\n", val);
4665141cc406Sopenharmony_ci    status = set_gamma (s, val);
4666141cc406Sopenharmony_ci
4667141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4668141cc406Sopenharmony_ci    {
4669141cc406Sopenharmony_ci      DBG (1, "sane_start: set_gamma failed: %s\n", sane_strstatus (status));
4670141cc406Sopenharmony_ci      return status;
4671141cc406Sopenharmony_ci    }
4672141cc406Sopenharmony_ci  }
4673141cc406Sopenharmony_ci
4674141cc406Sopenharmony_ci  if (s->hw->cmd->set_gamma_table &&
4675141cc406Sopenharmony_ci      gamma_userdefined[s->val[OPT_GAMMA_CORRECTION].w])
4676141cc406Sopenharmony_ci  {                             /* user defined. */
4677141cc406Sopenharmony_ci    status = set_gamma_table (s);
4678141cc406Sopenharmony_ci
4679141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4680141cc406Sopenharmony_ci    {
4681141cc406Sopenharmony_ci      DBG (1, "sane_start: set_gamma_table failed: %s\n",
4682141cc406Sopenharmony_ci           sane_strstatus (status));
4683141cc406Sopenharmony_ci      return status;
4684141cc406Sopenharmony_ci    }
4685141cc406Sopenharmony_ci  }
4686141cc406Sopenharmony_ci
4687141cc406Sopenharmony_ci/*
4688141cc406Sopenharmony_ci * TODO: think about if SANE_OPTION_IS_ACTIVE is a good criteria to send commands.
4689141cc406Sopenharmony_ci */
4690141cc406Sopenharmony_ci
4691141cc406Sopenharmony_ci  if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_COLOR_CORRECTION].cap))
4692141cc406Sopenharmony_ci  {
4693141cc406Sopenharmony_ci    int val = color_params[s->val[OPT_COLOR_CORRECTION].w];
4694141cc406Sopenharmony_ci
4695141cc406Sopenharmony_ci    DBG (1, "sane_start: set_color_correction( s, 0x%x )\n", val);
4696141cc406Sopenharmony_ci    status = set_color_correction (s, val);
4697141cc406Sopenharmony_ci
4698141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4699141cc406Sopenharmony_ci    {
4700141cc406Sopenharmony_ci      DBG (1, "sane_start: set_color_correction failed: %s\n",
4701141cc406Sopenharmony_ci           sane_strstatus (status));
4702141cc406Sopenharmony_ci      return status;
4703141cc406Sopenharmony_ci    }
4704141cc406Sopenharmony_ci  }
4705141cc406Sopenharmony_ci  if (1 == s->val[OPT_COLOR_CORRECTION].w)
4706141cc406Sopenharmony_ci  {                             /* user defined. */
4707141cc406Sopenharmony_ci    status = set_color_correction_coefficients (s);
4708141cc406Sopenharmony_ci
4709141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4710141cc406Sopenharmony_ci    {
4711141cc406Sopenharmony_ci      DBG (1, "sane_start: set_color_correction_coefficients failed: %s\n",
4712141cc406Sopenharmony_ci           sane_strstatus (status));
4713141cc406Sopenharmony_ci      return status;
4714141cc406Sopenharmony_ci    }
4715141cc406Sopenharmony_ci  }
4716141cc406Sopenharmony_ci
4717141cc406Sopenharmony_ci
4718141cc406Sopenharmony_ci  if (s->hw->cmd->set_threshold != 0
4719141cc406Sopenharmony_ci      && SANE_OPTION_IS_ACTIVE (s->opt[OPT_THRESHOLD].cap))
4720141cc406Sopenharmony_ci  {
4721141cc406Sopenharmony_ci    status = set_threshold (s, s->val[OPT_THRESHOLD].w);
4722141cc406Sopenharmony_ci
4723141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4724141cc406Sopenharmony_ci    {
4725141cc406Sopenharmony_ci      DBG (1, "sane_start: set_threshold(%d) failed: %s\n",
4726141cc406Sopenharmony_ci           s->val[OPT_THRESHOLD].w, sane_strstatus (status));
4727141cc406Sopenharmony_ci      return status;
4728141cc406Sopenharmony_ci    }
4729141cc406Sopenharmony_ci  }
4730141cc406Sopenharmony_ci
4731141cc406Sopenharmony_ci  ndpi = s->val[OPT_RESOLUTION].w;
4732141cc406Sopenharmony_ci
4733141cc406Sopenharmony_ci  status = set_resolution (s, ndpi, ndpi);
4734141cc406Sopenharmony_ci
4735141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
4736141cc406Sopenharmony_ci  {
4737141cc406Sopenharmony_ci    DBG (1, "sane_start: set_resolution(%d, %d) failed: %s\n",
4738141cc406Sopenharmony_ci         ndpi, ndpi, sane_strstatus (status));
4739141cc406Sopenharmony_ci    return status;
4740141cc406Sopenharmony_ci  }
4741141cc406Sopenharmony_ci
4742141cc406Sopenharmony_ci  status = sane_get_parameters (handle, NULL);
4743141cc406Sopenharmony_ci
4744141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
4745141cc406Sopenharmony_ci    return status;
4746141cc406Sopenharmony_ci
4747141cc406Sopenharmony_ci  /* set the zoom */
4748141cc406Sopenharmony_ci  if (s->hw->cmd->set_zoom != 0
4749141cc406Sopenharmony_ci      && SANE_OPTION_IS_ACTIVE (s->opt[OPT_ZOOM].cap))
4750141cc406Sopenharmony_ci  {
4751141cc406Sopenharmony_ci    status = set_zoom (s, s->val[OPT_ZOOM].w, s->val[OPT_ZOOM].w);
4752141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
4753141cc406Sopenharmony_ci    {
4754141cc406Sopenharmony_ci      DBG (1, "sane_start: set_zoom(%d) failed: %s\n",
4755141cc406Sopenharmony_ci           s->val[OPT_ZOOM].w, sane_strstatus (status));
4756141cc406Sopenharmony_ci      return status;
4757141cc406Sopenharmony_ci    }
4758141cc406Sopenharmony_ci  }
4759141cc406Sopenharmony_ci
4760141cc406Sopenharmony_ci
4761141cc406Sopenharmony_ci/*
4762141cc406Sopenharmony_ci *  Now s->params is initialized.
4763141cc406Sopenharmony_ci */
4764141cc406Sopenharmony_ci
4765141cc406Sopenharmony_ci
4766141cc406Sopenharmony_ci/*
4767141cc406Sopenharmony_ci * If WAIT_FOR_BUTTON is active, then do just that: Wait until the button is
4768141cc406Sopenharmony_ci * pressed. If the button was already pressed, then we will get the button
4769141cc406Sopenharmony_ci * Pressed event right away.
4770141cc406Sopenharmony_ci */
4771141cc406Sopenharmony_ci
4772141cc406Sopenharmony_ci  if (s->val[OPT_WAIT_FOR_BUTTON].w == SANE_TRUE)
4773141cc406Sopenharmony_ci  {
4774141cc406Sopenharmony_ci    s->hw->wait_for_button = SANE_TRUE;
4775141cc406Sopenharmony_ci
4776141cc406Sopenharmony_ci    while (s->hw->wait_for_button == SANE_TRUE)
4777141cc406Sopenharmony_ci    {
4778141cc406Sopenharmony_ci      if (s->canceling == SANE_TRUE)
4779141cc406Sopenharmony_ci      {
4780141cc406Sopenharmony_ci        s->hw->wait_for_button = SANE_FALSE;
4781141cc406Sopenharmony_ci      }
4782141cc406Sopenharmony_ci      /* get the button status from the scanner */
4783141cc406Sopenharmony_ci      else if (request_push_button_status (s, &button_status) ==
4784141cc406Sopenharmony_ci               SANE_STATUS_GOOD)
4785141cc406Sopenharmony_ci      {
4786141cc406Sopenharmony_ci        if (button_status == SANE_TRUE)
4787141cc406Sopenharmony_ci        {
4788141cc406Sopenharmony_ci          s->hw->wait_for_button = SANE_FALSE;
4789141cc406Sopenharmony_ci        }
4790141cc406Sopenharmony_ci        else
4791141cc406Sopenharmony_ci        {
4792141cc406Sopenharmony_ci          sleep (1);
4793141cc406Sopenharmony_ci        }
4794141cc406Sopenharmony_ci      }
4795141cc406Sopenharmony_ci      else
4796141cc406Sopenharmony_ci      {
4797141cc406Sopenharmony_ci        /* we ran into an error condition, just continue */
4798141cc406Sopenharmony_ci        s->hw->wait_for_button = SANE_FALSE;
4799141cc406Sopenharmony_ci      }
4800141cc406Sopenharmony_ci    }
4801141cc406Sopenharmony_ci  }
4802141cc406Sopenharmony_ci
4803141cc406Sopenharmony_ci
4804141cc406Sopenharmony_ci/*
4805141cc406Sopenharmony_ci *  in file:frontend/preview.c
4806141cc406Sopenharmony_ci *
4807141cc406Sopenharmony_ci *  The preview strategy is as follows:
4808141cc406Sopenharmony_ci *
4809141cc406Sopenharmony_ci *   1) A preview always acquires an image that covers the entire
4810141cc406Sopenharmony_ci *      scan surface.  This is necessary so the user can see not
4811141cc406Sopenharmony_ci *      only what is, but also what isn't selected.
4812141cc406Sopenharmony_ci */
4813141cc406Sopenharmony_ci
4814141cc406Sopenharmony_ci  left = SANE_UNFIX (s->val[OPT_TL_X].w) / 25.4 * ndpi + 0.5;
4815141cc406Sopenharmony_ci  top = SANE_UNFIX (s->val[OPT_TL_Y].w) / 25.4 * ndpi + 0.5;
4816141cc406Sopenharmony_ci
4817141cc406Sopenharmony_ci  /*
4818141cc406Sopenharmony_ci   * Calculate correction for line_distance in D1 scanner:
4819141cc406Sopenharmony_ci   * Start line_distance lines earlier and add line_distance lines at the end
4820141cc406Sopenharmony_ci   *
4821141cc406Sopenharmony_ci   * Because the actual line_distance is not yet calculated we have to do this
4822141cc406Sopenharmony_ci   * first.
4823141cc406Sopenharmony_ci   */
4824141cc406Sopenharmony_ci
4825141cc406Sopenharmony_ci  s->hw->color_shuffle = SANE_FALSE;
4826141cc406Sopenharmony_ci  s->current_output_line = 0;
4827141cc406Sopenharmony_ci  s->lines_written = 0;
4828141cc406Sopenharmony_ci  s->color_shuffle_line = 0;
4829141cc406Sopenharmony_ci
4830141cc406Sopenharmony_ci  if ((s->hw->optical_res != 0) && (mparam->depth == 8)
4831141cc406Sopenharmony_ci      && (mparam->mode_flags != 0))
4832141cc406Sopenharmony_ci  {
4833141cc406Sopenharmony_ci    s->line_distance = s->hw->max_line_distance * ndpi / s->hw->optical_res;
4834141cc406Sopenharmony_ci    if (s->line_distance != 0)
4835141cc406Sopenharmony_ci    {
4836141cc406Sopenharmony_ci      s->hw->color_shuffle = SANE_TRUE;
4837141cc406Sopenharmony_ci    }
4838141cc406Sopenharmony_ci    else
4839141cc406Sopenharmony_ci      s->hw->color_shuffle = SANE_FALSE;
4840141cc406Sopenharmony_ci  }
4841141cc406Sopenharmony_ci
4842141cc406Sopenharmony_ci/*
4843141cc406Sopenharmony_ci * for debugging purposes:
4844141cc406Sopenharmony_ci */
4845141cc406Sopenharmony_ci#ifdef FORCE_COLOR_SHUFFLE
4846141cc406Sopenharmony_ci  DBG (1, "Test mode: FORCE_COLOR_SHUFFLE = TRUE\n");
4847141cc406Sopenharmony_ci  s->hw->color_shuffle = SANE_TRUE;
4848141cc406Sopenharmony_ci#endif
4849141cc406Sopenharmony_ci
4850141cc406Sopenharmony_ci
4851141cc406Sopenharmony_ci  /*
4852141cc406Sopenharmony_ci   * Modify the scan area: If the scanner requires color shuffling, then we try to
4853141cc406Sopenharmony_ci   * scan more lines to compensate for the lines that will be removed from the scan
4854141cc406Sopenharmony_ci   * due to the color shuffling algorithm.
4855141cc406Sopenharmony_ci   * At this time we add two times the line distance to the number of scan lines if
4856141cc406Sopenharmony_ci   * this is possible - if not, then we try to calculate the number of additional
4857141cc406Sopenharmony_ci   * lines according to the selected scan area.
4858141cc406Sopenharmony_ci   */
4859141cc406Sopenharmony_ci  if (s->hw->color_shuffle == SANE_TRUE)
4860141cc406Sopenharmony_ci  {
4861141cc406Sopenharmony_ci
4862141cc406Sopenharmony_ci    /* start the scan 2*line_distance earlier */
4863141cc406Sopenharmony_ci    top -= 2 * s->line_distance;
4864141cc406Sopenharmony_ci    if (top < 0)
4865141cc406Sopenharmony_ci    {
4866141cc406Sopenharmony_ci      top = 0;
4867141cc406Sopenharmony_ci    }
4868141cc406Sopenharmony_ci
4869141cc406Sopenharmony_ci    /* scan 4*line_distance lines more */
4870141cc406Sopenharmony_ci    s->params.lines += 4 * s->line_distance;
4871141cc406Sopenharmony_ci  }
4872141cc406Sopenharmony_ci
4873141cc406Sopenharmony_ci  /*
4874141cc406Sopenharmony_ci   * If (top + s->params.lines) is larger than the max scan area, reset
4875141cc406Sopenharmony_ci   * the number of scan lines:
4876141cc406Sopenharmony_ci   */
4877141cc406Sopenharmony_ci  if (SANE_UNFIX (s->val[OPT_BR_Y].w) / 25.4 * ndpi < (s->params.lines + top))
4878141cc406Sopenharmony_ci  {
4879141cc406Sopenharmony_ci    s->params.lines = ((int) SANE_UNFIX (s->val[OPT_BR_Y].w) /
4880141cc406Sopenharmony_ci                       25.4 * ndpi + 0.5) - top;
4881141cc406Sopenharmony_ci  }
4882141cc406Sopenharmony_ci
4883141cc406Sopenharmony_ci
4884141cc406Sopenharmony_ci  status =
4885141cc406Sopenharmony_ci    set_scan_area (s, left, top, s->params.pixels_per_line, s->params.lines);
4886141cc406Sopenharmony_ci
4887141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
4888141cc406Sopenharmony_ci  {
4889141cc406Sopenharmony_ci    DBG (1, "sane_start: set_scan_area failed: %s\n",
4890141cc406Sopenharmony_ci         sane_strstatus (status));
4891141cc406Sopenharmony_ci    return status;
4892141cc406Sopenharmony_ci  }
4893141cc406Sopenharmony_ci
4894141cc406Sopenharmony_ci  s->block = SANE_FALSE;
4895141cc406Sopenharmony_ci  lcount = 1;
4896141cc406Sopenharmony_ci
4897141cc406Sopenharmony_ci  /*
4898141cc406Sopenharmony_ci   * The set line count commands needs to be sent for certain scanners in
4899141cc406Sopenharmony_ci   * color mode. The D1 level requires it, we are however only testing for
4900141cc406Sopenharmony_ci   * 'D' and not for the actual numeric level.
4901141cc406Sopenharmony_ci   */
4902141cc406Sopenharmony_ci
4903141cc406Sopenharmony_ci  if (((s->hw->cmd->level[0] == 'B') &&
4904141cc406Sopenharmony_ci       ((s->hw->level >= 5) || ((s->hw->level >= 4) &&
4905141cc406Sopenharmony_ci                                (!mode_params[s->val[OPT_MODE].w].color))))
4906141cc406Sopenharmony_ci      || (s->hw->cmd->level[0] == 'D'))
4907141cc406Sopenharmony_ci  {
4908141cc406Sopenharmony_ci    s->block = SANE_TRUE;
4909141cc406Sopenharmony_ci    lcount = sanei_scsi_max_request_size / s->params.bytes_per_line;
4910141cc406Sopenharmony_ci
4911141cc406Sopenharmony_ci    if (lcount >= 255)
4912141cc406Sopenharmony_ci    {
4913141cc406Sopenharmony_ci      lcount = 255;
4914141cc406Sopenharmony_ci    }
4915141cc406Sopenharmony_ci
4916141cc406Sopenharmony_ci    if (s->hw->TPU && s->hw->use_extension && lcount > 32)
4917141cc406Sopenharmony_ci    {
4918141cc406Sopenharmony_ci      lcount = 32;
4919141cc406Sopenharmony_ci    }
4920141cc406Sopenharmony_ci
4921141cc406Sopenharmony_ci
4922141cc406Sopenharmony_ci    /*
4923141cc406Sopenharmony_ci     * The D1 series of scanners only allow an even line number
4924141cc406Sopenharmony_ci     * for bi-level scanning. If a bit depth of 1 is selected, then
4925141cc406Sopenharmony_ci     * make sure the next lower even number is selected.
4926141cc406Sopenharmony_ci     */
4927141cc406Sopenharmony_ci    if (s->hw->cmd->level[0] == 'D')
4928141cc406Sopenharmony_ci    {
4929141cc406Sopenharmony_ci      if (lcount % 2)
4930141cc406Sopenharmony_ci      {
4931141cc406Sopenharmony_ci        lcount -= 1;
4932141cc406Sopenharmony_ci      }
4933141cc406Sopenharmony_ci    }
4934141cc406Sopenharmony_ci
4935141cc406Sopenharmony_ci    if (lcount == 0)
4936141cc406Sopenharmony_ci    {
4937141cc406Sopenharmony_ci      DBG (1, "out of memory (line %d)\n", __LINE__);
4938141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
4939141cc406Sopenharmony_ci    }
4940141cc406Sopenharmony_ci
4941141cc406Sopenharmony_ci    status = set_lcount (s, lcount);
4942141cc406Sopenharmony_ci
4943141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
4944141cc406Sopenharmony_ci    {
4945141cc406Sopenharmony_ci      DBG (1, "sane_start: set_lcount(%d) failed: %s\n",
4946141cc406Sopenharmony_ci           lcount, sane_strstatus (status));
4947141cc406Sopenharmony_ci      return status;
4948141cc406Sopenharmony_ci    }
4949141cc406Sopenharmony_ci  }
4950141cc406Sopenharmony_ci
4951141cc406Sopenharmony_ci  if (s->hw->cmd->request_extended_status != 0
4952141cc406Sopenharmony_ci      && SANE_TRUE == s->hw->extension)
4953141cc406Sopenharmony_ci  {
4954141cc406Sopenharmony_ci    u_char result[4];
4955141cc406Sopenharmony_ci    u_char *buf;
4956141cc406Sopenharmony_ci    size_t len;
4957141cc406Sopenharmony_ci
4958141cc406Sopenharmony_ci    params[0] = ESC;
4959141cc406Sopenharmony_ci    params[1] = s->hw->cmd->request_extended_status;
4960141cc406Sopenharmony_ci
4961141cc406Sopenharmony_ci    send (s, params, 2, &status);       /* send ESC f (request extended status) */
4962141cc406Sopenharmony_ci
4963141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD == status)
4964141cc406Sopenharmony_ci    {
4965141cc406Sopenharmony_ci      len = 4;                  /* receive header */
4966141cc406Sopenharmony_ci
4967141cc406Sopenharmony_ci      receive (s, result, len, &status);
4968141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
4969141cc406Sopenharmony_ci        return status;
4970141cc406Sopenharmony_ci
4971141cc406Sopenharmony_ci      len = result[3] << 8 | result[2];
4972141cc406Sopenharmony_ci      buf = alloca (len);
4973141cc406Sopenharmony_ci
4974141cc406Sopenharmony_ci      receive (s, buf, len, &status);   /* receive actual status data */
4975141cc406Sopenharmony_ci
4976141cc406Sopenharmony_ci      if (buf[0] & 0x80)
4977141cc406Sopenharmony_ci      {
4978141cc406Sopenharmony_ci        close_scanner (s);
4979141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
4980141cc406Sopenharmony_ci      }
4981141cc406Sopenharmony_ci    }
4982141cc406Sopenharmony_ci    else
4983141cc406Sopenharmony_ci    {
4984141cc406Sopenharmony_ci      DBG (1, "Extended status flag request failed\n");
4985141cc406Sopenharmony_ci    }
4986141cc406Sopenharmony_ci  }
4987141cc406Sopenharmony_ci
4988141cc406Sopenharmony_ci/*
4989141cc406Sopenharmony_ci *  for debug purpose
4990141cc406Sopenharmony_ci *  check scanner conditions
4991141cc406Sopenharmony_ci */
4992141cc406Sopenharmony_ci#if 1
4993141cc406Sopenharmony_ci  if (s->hw->cmd->request_condition != 0)
4994141cc406Sopenharmony_ci  {
4995141cc406Sopenharmony_ci    u_char result[4];
4996141cc406Sopenharmony_ci    u_char *buf;
4997141cc406Sopenharmony_ci    size_t len;
4998141cc406Sopenharmony_ci
4999141cc406Sopenharmony_ci    params[0] = ESC;
5000141cc406Sopenharmony_ci    params[1] = s->hw->cmd->request_condition;
5001141cc406Sopenharmony_ci
5002141cc406Sopenharmony_ci    send (s, params, 2, &status);       /* send request condition */
5003141cc406Sopenharmony_ci
5004141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
5005141cc406Sopenharmony_ci      return status;
5006141cc406Sopenharmony_ci
5007141cc406Sopenharmony_ci    len = 4;
5008141cc406Sopenharmony_ci    receive (s, result, len, &status);
5009141cc406Sopenharmony_ci
5010141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
5011141cc406Sopenharmony_ci      return status;
5012141cc406Sopenharmony_ci
5013141cc406Sopenharmony_ci    len = result[3] << 8 | result[2];
5014141cc406Sopenharmony_ci    buf = alloca (len);
5015141cc406Sopenharmony_ci    receive (s, buf, len, &status);
5016141cc406Sopenharmony_ci
5017141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != status)
5018141cc406Sopenharmony_ci      return status;
5019141cc406Sopenharmony_ci
5020141cc406Sopenharmony_ci#if 0
5021141cc406Sopenharmony_ci    DBG (10, "SANE_START: length=%d\n", len);
5022141cc406Sopenharmony_ci    for (i = 1; i <= len; i++)
5023141cc406Sopenharmony_ci    {
5024141cc406Sopenharmony_ci      DBG (10, "SANE_START: %d: %c\n", i, buf[i - 1]);
5025141cc406Sopenharmony_ci    }
5026141cc406Sopenharmony_ci#endif
5027141cc406Sopenharmony_ci
5028141cc406Sopenharmony_ci    DBG (5, "SANE_START: Color: %d\n", (int) buf[1]);
5029141cc406Sopenharmony_ci    DBG (5, "SANE_START: Resolution (x, y): (%d, %d)\n",
5030141cc406Sopenharmony_ci         (int) (buf[4] << 8 | buf[3]), (int) (buf[6] << 8 | buf[5]));
5031141cc406Sopenharmony_ci    DBG (5,
5032141cc406Sopenharmony_ci         "SANE_START: Scan area(pixels) (x0, y0), (x1, y1): (%d, %d), (%d, %d)\n",
5033141cc406Sopenharmony_ci         (int) (buf[9] << 8 | buf[8]), (int) (buf[11] << 8 | buf[10]),
5034141cc406Sopenharmony_ci         (int) (buf[13] << 8 | buf[12]), (int) (buf[15] << 8 | buf[14]));
5035141cc406Sopenharmony_ci    DBG (5, "SANE_START: Data format: %d\n", (int) buf[17]);
5036141cc406Sopenharmony_ci    DBG (5, "SANE_START: Halftone: %d\n", (int) buf[19]);
5037141cc406Sopenharmony_ci    DBG (5, "SANE_START: Brightness: %d\n", (int) buf[21]);
5038141cc406Sopenharmony_ci    DBG (5, "SANE_START: Gamma: %d\n", (int) buf[23]);
5039141cc406Sopenharmony_ci    DBG (5, "SANE_START: Zoom (x, y): (%d, %d)\n", (int) buf[26],
5040141cc406Sopenharmony_ci         (int) buf[25]);
5041141cc406Sopenharmony_ci    DBG (5, "SANE_START: Color correction: %d\n", (int) buf[28]);
5042141cc406Sopenharmony_ci    DBG (5, "SANE_START: Sharpness control: %d\n", (int) buf[30]);
5043141cc406Sopenharmony_ci    DBG (5, "SANE_START: Scanning mode: %d\n", (int) buf[32]);
5044141cc406Sopenharmony_ci    DBG (5, "SANE_START: Mirroring: %d\n", (int) buf[34]);
5045141cc406Sopenharmony_ci    DBG (5, "SANE_START: Auto area segmentation: %d\n", (int) buf[36]);
5046141cc406Sopenharmony_ci    DBG (5, "SANE_START: Threshold: %d\n", (int) buf[38]);
5047141cc406Sopenharmony_ci    DBG (5, "SANE_START: Line counter: %d\n", (int) buf[40]);
5048141cc406Sopenharmony_ci    DBG (5, "SANE_START: Option unit control: %d\n", (int) buf[42]);
5049141cc406Sopenharmony_ci    DBG (5, "SANE_START: Film type: %d\n", (int) buf[44]);
5050141cc406Sopenharmony_ci  }
5051141cc406Sopenharmony_ci#endif
5052141cc406Sopenharmony_ci
5053141cc406Sopenharmony_ci
5054141cc406Sopenharmony_ci  /* set the retry count to 0 */
5055141cc406Sopenharmony_ci  s->retry_count = 0;
5056141cc406Sopenharmony_ci
5057141cc406Sopenharmony_ci  if (s->hw->color_shuffle == SANE_TRUE)
5058141cc406Sopenharmony_ci  {
5059141cc406Sopenharmony_ci
5060141cc406Sopenharmony_ci    /* initialize the line buffers */
5061141cc406Sopenharmony_ci    for (i = 0; i < s->line_distance * 2 + 1; i++)
5062141cc406Sopenharmony_ci    {
5063141cc406Sopenharmony_ci      if (s->line_buffer[i] != NULL)
5064141cc406Sopenharmony_ci        free (s->line_buffer[i]);
5065141cc406Sopenharmony_ci
5066141cc406Sopenharmony_ci      s->line_buffer[i] = malloc (s->params.bytes_per_line);
5067141cc406Sopenharmony_ci      if (s->line_buffer[i] == NULL)
5068141cc406Sopenharmony_ci      {
5069141cc406Sopenharmony_ci        /* free the memory we've malloced so far */
5070141cc406Sopenharmony_ci        for (j = 0; j < i; j++)
5071141cc406Sopenharmony_ci        {
5072141cc406Sopenharmony_ci          free (s->line_buffer[j]);
5073141cc406Sopenharmony_ci          s->line_buffer[j] = NULL;
5074141cc406Sopenharmony_ci        }
5075141cc406Sopenharmony_ci        DBG (1, "out of memory (line %d)\n", __LINE__);
5076141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
5077141cc406Sopenharmony_ci      }
5078141cc406Sopenharmony_ci    }
5079141cc406Sopenharmony_ci  }
5080141cc406Sopenharmony_ci
5081141cc406Sopenharmony_ci  params[0] = ESC;
5082141cc406Sopenharmony_ci  params[1] = s->hw->cmd->start_scanning;
5083141cc406Sopenharmony_ci
5084141cc406Sopenharmony_ci  send (s, params, 2, &status);
5085141cc406Sopenharmony_ci
5086141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
5087141cc406Sopenharmony_ci  {
5088141cc406Sopenharmony_ci    DBG (1, "sane_start: start failed: %s\n", sane_strstatus (status));
5089141cc406Sopenharmony_ci    return status;
5090141cc406Sopenharmony_ci  }
5091141cc406Sopenharmony_ci
5092141cc406Sopenharmony_ci  s->eof = SANE_FALSE;
5093141cc406Sopenharmony_ci  s->buf = realloc (s->buf, lcount * s->params.bytes_per_line);
5094141cc406Sopenharmony_ci  s->ptr = s->end = s->buf;
5095141cc406Sopenharmony_ci  s->canceling = SANE_FALSE;
5096141cc406Sopenharmony_ci
5097141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5098141cc406Sopenharmony_ci}                               /* sane_start */
5099141cc406Sopenharmony_ci
5100141cc406Sopenharmony_ci/*
5101141cc406Sopenharmony_ci *
5102141cc406Sopenharmony_ci * TODO: clean up the eject and direct cmd mess.
5103141cc406Sopenharmony_ci */
5104141cc406Sopenharmony_ci
5105141cc406Sopenharmony_ciSANE_Status
5106141cc406Sopenharmony_cisane_auto_eject (Epson_Scanner * s)
5107141cc406Sopenharmony_ci{
5108141cc406Sopenharmony_ci
5109141cc406Sopenharmony_ci  DBG (5, "sane_auto_eject()\n");
5110141cc406Sopenharmony_ci
5111141cc406Sopenharmony_ci  if (s->hw->ADF && s->hw->use_extension && s->val[OPT_AUTO_EJECT].w)
5112141cc406Sopenharmony_ci  {                             /* sequence! */
5113141cc406Sopenharmony_ci    SANE_Status status;
5114141cc406Sopenharmony_ci
5115141cc406Sopenharmony_ci    u_char params[1];
5116141cc406Sopenharmony_ci    u_char cmd = s->hw->cmd->eject;
5117141cc406Sopenharmony_ci
5118141cc406Sopenharmony_ci    if (!cmd)
5119141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
5120141cc406Sopenharmony_ci
5121141cc406Sopenharmony_ci    params[0] = cmd;
5122141cc406Sopenharmony_ci
5123141cc406Sopenharmony_ci    send (s, params, 1, &status);
5124141cc406Sopenharmony_ci
5125141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = expect_ack (s)))
5126141cc406Sopenharmony_ci    {
5127141cc406Sopenharmony_ci      return status;
5128141cc406Sopenharmony_ci    }
5129141cc406Sopenharmony_ci  }
5130141cc406Sopenharmony_ci
5131141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5132141cc406Sopenharmony_ci}
5133141cc406Sopenharmony_ci
5134141cc406Sopenharmony_ci/*
5135141cc406Sopenharmony_ci *
5136141cc406Sopenharmony_ci *
5137141cc406Sopenharmony_ci */
5138141cc406Sopenharmony_ci
5139141cc406Sopenharmony_cistatic SANE_Status
5140141cc406Sopenharmony_ciread_data_block (Epson_Scanner * s, EpsonDataRec * result)
5141141cc406Sopenharmony_ci{
5142141cc406Sopenharmony_ci  SANE_Status status;
5143141cc406Sopenharmony_ci  u_char param[3];
5144141cc406Sopenharmony_ci
5145141cc406Sopenharmony_ci  receive (s, result, s->block ? 6 : 4, &status);
5146141cc406Sopenharmony_ci
5147141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
5148141cc406Sopenharmony_ci    return status;
5149141cc406Sopenharmony_ci
5150141cc406Sopenharmony_ci  if (STX != result->code)
5151141cc406Sopenharmony_ci  {
5152141cc406Sopenharmony_ci    DBG (1, "code   %02x\n", (int) result->code);
5153141cc406Sopenharmony_ci    DBG (1, "error, expected STX\n");
5154141cc406Sopenharmony_ci
5155141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
5156141cc406Sopenharmony_ci  }
5157141cc406Sopenharmony_ci
5158141cc406Sopenharmony_ci  if (result->status & STATUS_FER)
5159141cc406Sopenharmony_ci  {
5160141cc406Sopenharmony_ci    int dummy_x, dummy_y;
5161141cc406Sopenharmony_ci
5162141cc406Sopenharmony_ci    DBG (1, "fatal error - Status = %02x\n", result->status);
5163141cc406Sopenharmony_ci
5164141cc406Sopenharmony_ci    status = check_ext_status (s, &dummy_x, &dummy_y);
5165141cc406Sopenharmony_ci
5166141cc406Sopenharmony_ci    /*
5167141cc406Sopenharmony_ci     * Hack Alert!!!
5168141cc406Sopenharmony_ci     * If the status is SANE_STATUS_DEVICE_BUSY then we need to
5169141cc406Sopenharmony_ci     * re-issue the command again. We can assume that the command that
5170141cc406Sopenharmony_ci     * caused this problem was ESC G, so in a loop with a sleep 1 we
5171141cc406Sopenharmony_ci     * are testing this over and over and over again, until the lamp
5172141cc406Sopenharmony_ci     * "thinks" it is ready.
5173141cc406Sopenharmony_ci     *
5174141cc406Sopenharmony_ci     * TODO: Store the last command and execute what was actually used
5175141cc406Sopenharmony_ci     *       as the last command. For all situations this error may occur
5176141cc406Sopenharmony_ci     *       ESC G is very very likely to be the command in question, but
5177141cc406Sopenharmony_ci     *       we better make sure that this is the case.
5178141cc406Sopenharmony_ci     *
5179141cc406Sopenharmony_ci     */
5180141cc406Sopenharmony_ci
5181141cc406Sopenharmony_ci    /*
5182141cc406Sopenharmony_ci     * let's safe some stack space: If this is not the first go around,
5183141cc406Sopenharmony_ci     * then just return the status and let the loop handle this - otherwise
5184141cc406Sopenharmony_ci     * we would run this function recursively.
5185141cc406Sopenharmony_ci     */
5186141cc406Sopenharmony_ci
5187141cc406Sopenharmony_ci    if ((status == SANE_STATUS_DEVICE_BUSY && s->retry_count > 0) ||
5188141cc406Sopenharmony_ci        (status == SANE_STATUS_GOOD && s->retry_count > 0))
5189141cc406Sopenharmony_ci    {
5190141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;   /* return busy even if we just read OK
5191141cc406Sopenharmony_ci                                           so that the following loop can end
5192141cc406Sopenharmony_ci                                           gracefully */
5193141cc406Sopenharmony_ci    }
5194141cc406Sopenharmony_ci
5195141cc406Sopenharmony_ci    while (status == SANE_STATUS_DEVICE_BUSY)
5196141cc406Sopenharmony_ci    {
5197141cc406Sopenharmony_ci      if (s->retry_count > SANE_EPSON_MAX_RETRIES)
5198141cc406Sopenharmony_ci      {
5199141cc406Sopenharmony_ci        DBG (1, "Max retry count exceeded (%d)\n", s->retry_count);
5200141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
5201141cc406Sopenharmony_ci      }
5202141cc406Sopenharmony_ci
5203141cc406Sopenharmony_ci      sleep (1);                /* wait one second for the next attempt */
5204141cc406Sopenharmony_ci
5205141cc406Sopenharmony_ci      DBG (1, "retrying ESC G - %d\n", ++(s->retry_count));
5206141cc406Sopenharmony_ci
5207141cc406Sopenharmony_ci      param[0] = ESC;
5208141cc406Sopenharmony_ci      param[1] = s->hw->cmd->start_scanning;
5209141cc406Sopenharmony_ci
5210141cc406Sopenharmony_ci      send (s, param, 2, &status);
5211141cc406Sopenharmony_ci
5212141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
5213141cc406Sopenharmony_ci      {
5214141cc406Sopenharmony_ci        DBG (1, "read_data_block: start failed: %s\n",
5215141cc406Sopenharmony_ci             sane_strstatus (status));
5216141cc406Sopenharmony_ci        return status;
5217141cc406Sopenharmony_ci      }
5218141cc406Sopenharmony_ci
5219141cc406Sopenharmony_ci      status = read_data_block (s, result);
5220141cc406Sopenharmony_ci    }
5221141cc406Sopenharmony_ci
5222141cc406Sopenharmony_ci  }
5223141cc406Sopenharmony_ci
5224141cc406Sopenharmony_ci  return status;
5225141cc406Sopenharmony_ci}
5226141cc406Sopenharmony_ci
5227141cc406Sopenharmony_ci/*
5228141cc406Sopenharmony_ci *
5229141cc406Sopenharmony_ci *
5230141cc406Sopenharmony_ci */
5231141cc406Sopenharmony_ci
5232141cc406Sopenharmony_ci
5233141cc406Sopenharmony_civoid
5234141cc406Sopenharmony_ciscan_finish (Epson_Scanner * s)
5235141cc406Sopenharmony_ci{
5236141cc406Sopenharmony_ci  SANE_Status status;
5237141cc406Sopenharmony_ci  int i, x, y;
5238141cc406Sopenharmony_ci
5239141cc406Sopenharmony_ci  DBG (5, "scan_finish()\n");
5240141cc406Sopenharmony_ci
5241141cc406Sopenharmony_ci  free (s->buf);
5242141cc406Sopenharmony_ci  s->buf = NULL;
5243141cc406Sopenharmony_ci
5244141cc406Sopenharmony_ci  status = check_ext_status (s, &x, &y);
5245141cc406Sopenharmony_ci
5246141cc406Sopenharmony_ci  if (SANE_STATUS_NO_DOCS == status && s->hw->ADF && s->hw->use_extension)
5247141cc406Sopenharmony_ci    sane_auto_eject (s);
5248141cc406Sopenharmony_ci
5249141cc406Sopenharmony_ci  for (i = 0; i < s->line_distance; i++)
5250141cc406Sopenharmony_ci  {
5251141cc406Sopenharmony_ci    if (s->line_buffer[i] != NULL)
5252141cc406Sopenharmony_ci    {
5253141cc406Sopenharmony_ci      free (s->line_buffer[i]);
5254141cc406Sopenharmony_ci      s->line_buffer[i] = NULL;
5255141cc406Sopenharmony_ci    }
5256141cc406Sopenharmony_ci  }
5257141cc406Sopenharmony_ci}
5258141cc406Sopenharmony_ci
5259141cc406Sopenharmony_ci#define GET_COLOR(x)    ((x.status>>2) & 0x03)
5260141cc406Sopenharmony_ci
5261141cc406Sopenharmony_ciSANE_Status
5262141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
5263141cc406Sopenharmony_ci           SANE_Int * length)
5264141cc406Sopenharmony_ci{
5265141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
5266141cc406Sopenharmony_ci  SANE_Status status;
5267141cc406Sopenharmony_ci  int index = 0;
5268141cc406Sopenharmony_ci  SANE_Bool reorder = SANE_FALSE;
5269141cc406Sopenharmony_ci  SANE_Bool needStrangeReorder = SANE_FALSE;
5270141cc406Sopenharmony_ci
5271141cc406Sopenharmony_ciSTART_READ:
5272141cc406Sopenharmony_ci  DBG (5, "sane_read: begin\n");
5273141cc406Sopenharmony_ci
5274141cc406Sopenharmony_ci  if (s->ptr == s->end)
5275141cc406Sopenharmony_ci  {
5276141cc406Sopenharmony_ci    EpsonDataRec result;
5277141cc406Sopenharmony_ci    size_t buf_len;
5278141cc406Sopenharmony_ci
5279141cc406Sopenharmony_ci    if ((s->fd != -1) && s->eof)
5280141cc406Sopenharmony_ci    {
5281141cc406Sopenharmony_ci      if (s->hw->color_shuffle)
5282141cc406Sopenharmony_ci      {
5283141cc406Sopenharmony_ci        DBG (1, "Written %d lines after color shuffle\n", s->lines_written);
5284141cc406Sopenharmony_ci        DBG (1, "Lines requested: %d\n", s->params.lines);
5285141cc406Sopenharmony_ci      }
5286141cc406Sopenharmony_ci
5287141cc406Sopenharmony_ci      *length = 0;
5288141cc406Sopenharmony_ci      scan_finish (s);
5289141cc406Sopenharmony_ci
5290141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
5291141cc406Sopenharmony_ci    }
5292141cc406Sopenharmony_ci
5293141cc406Sopenharmony_ci
5294141cc406Sopenharmony_ci    DBG (5, "sane_read: begin scan1\n");
5295141cc406Sopenharmony_ci
5296141cc406Sopenharmony_ci    if (SANE_STATUS_GOOD != (status = read_data_block (s, &result)))
5297141cc406Sopenharmony_ci    {
5298141cc406Sopenharmony_ci      *length = 0;
5299141cc406Sopenharmony_ci      scan_finish (s);
5300141cc406Sopenharmony_ci      return status;
5301141cc406Sopenharmony_ci    }
5302141cc406Sopenharmony_ci
5303141cc406Sopenharmony_ci    buf_len = result.buf[1] << 8 | result.buf[0];
5304141cc406Sopenharmony_ci
5305141cc406Sopenharmony_ci    DBG (5, "sane_read: buf len = %lu\n", (u_long) buf_len);
5306141cc406Sopenharmony_ci
5307141cc406Sopenharmony_ci    if (s->block)
5308141cc406Sopenharmony_ci    {
5309141cc406Sopenharmony_ci      buf_len *= (result.buf[3] << 8 | result.buf[2]);
5310141cc406Sopenharmony_ci      DBG (5, "sane_read: buf len (adjusted) = %lu\n", (u_long) buf_len);
5311141cc406Sopenharmony_ci    }
5312141cc406Sopenharmony_ci
5313141cc406Sopenharmony_ci    if (!s->block && SANE_FRAME_RGB == s->params.format)
5314141cc406Sopenharmony_ci    {
5315141cc406Sopenharmony_ci      /*
5316141cc406Sopenharmony_ci       * Read color data in line mode
5317141cc406Sopenharmony_ci       */
5318141cc406Sopenharmony_ci
5319141cc406Sopenharmony_ci
5320141cc406Sopenharmony_ci      /*
5321141cc406Sopenharmony_ci       * read the first color line - the number of bytes to read
5322141cc406Sopenharmony_ci       * is already known (from last call to read_data_block()
5323141cc406Sopenharmony_ci       * We determine where to write the line from the color information
5324141cc406Sopenharmony_ci       * in the data block. At the end we want the order RGB, but the
5325141cc406Sopenharmony_ci       * way the data is delivered does not guarantee this - actually it's
5326141cc406Sopenharmony_ci       * most likely that the order is GRB if it's not RGB!
5327141cc406Sopenharmony_ci       */
5328141cc406Sopenharmony_ci      switch (GET_COLOR (result))
5329141cc406Sopenharmony_ci      {
5330141cc406Sopenharmony_ci      case 1:
5331141cc406Sopenharmony_ci        index = 1;
5332141cc406Sopenharmony_ci        break;
5333141cc406Sopenharmony_ci      case 2:
5334141cc406Sopenharmony_ci        index = 0;
5335141cc406Sopenharmony_ci        break;
5336141cc406Sopenharmony_ci      case 3:
5337141cc406Sopenharmony_ci        index = 2;
5338141cc406Sopenharmony_ci        break;
5339141cc406Sopenharmony_ci      }
5340141cc406Sopenharmony_ci
5341141cc406Sopenharmony_ci      receive (s, s->buf + index * s->params.pixels_per_line, buf_len,
5342141cc406Sopenharmony_ci               &status);
5343141cc406Sopenharmony_ci
5344141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
5345141cc406Sopenharmony_ci        return status;
5346141cc406Sopenharmony_ci      /*
5347141cc406Sopenharmony_ci       * send the ACK signal to the scanner in order to make
5348141cc406Sopenharmony_ci       * it ready for the next data block.
5349141cc406Sopenharmony_ci       */
5350141cc406Sopenharmony_ci      send (s, S_ACK, 1, &status);
5351141cc406Sopenharmony_ci
5352141cc406Sopenharmony_ci      /*
5353141cc406Sopenharmony_ci       * ... and request the next data block
5354141cc406Sopenharmony_ci       */
5355141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != (status = read_data_block (s, &result)))
5356141cc406Sopenharmony_ci        return status;
5357141cc406Sopenharmony_ci
5358141cc406Sopenharmony_ci      buf_len = result.buf[1] << 8 | result.buf[0];
5359141cc406Sopenharmony_ci      /*
5360141cc406Sopenharmony_ci       * this should never happen, because we are already in
5361141cc406Sopenharmony_ci       * line mode, but it does not hurt to check ...
5362141cc406Sopenharmony_ci       */
5363141cc406Sopenharmony_ci      if (s->block)
5364141cc406Sopenharmony_ci        buf_len *= (result.buf[3] << 8 | result.buf[2]);
5365141cc406Sopenharmony_ci
5366141cc406Sopenharmony_ci      DBG (5, "sane_read: buf len2 = %lu\n", (u_long) buf_len);
5367141cc406Sopenharmony_ci
5368141cc406Sopenharmony_ci      switch (GET_COLOR (result))
5369141cc406Sopenharmony_ci      {
5370141cc406Sopenharmony_ci      case 1:
5371141cc406Sopenharmony_ci        index = 1;
5372141cc406Sopenharmony_ci        break;
5373141cc406Sopenharmony_ci      case 2:
5374141cc406Sopenharmony_ci        index = 0;
5375141cc406Sopenharmony_ci        break;
5376141cc406Sopenharmony_ci      case 3:
5377141cc406Sopenharmony_ci        index = 2;
5378141cc406Sopenharmony_ci        break;
5379141cc406Sopenharmony_ci      }
5380141cc406Sopenharmony_ci
5381141cc406Sopenharmony_ci      receive (s, s->buf + index * s->params.pixels_per_line, buf_len,
5382141cc406Sopenharmony_ci               &status);
5383141cc406Sopenharmony_ci
5384141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
5385141cc406Sopenharmony_ci      {
5386141cc406Sopenharmony_ci        scan_finish (s);
5387141cc406Sopenharmony_ci        *length = 0;
5388141cc406Sopenharmony_ci        return status;
5389141cc406Sopenharmony_ci      }
5390141cc406Sopenharmony_ci
5391141cc406Sopenharmony_ci      send (s, S_ACK, 1, &status);
5392141cc406Sopenharmony_ci
5393141cc406Sopenharmony_ci      /*
5394141cc406Sopenharmony_ci       * ... and the last data block
5395141cc406Sopenharmony_ci       */
5396141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != (status = read_data_block (s, &result)))
5397141cc406Sopenharmony_ci      {
5398141cc406Sopenharmony_ci        *length = 0;
5399141cc406Sopenharmony_ci        scan_finish (s);
5400141cc406Sopenharmony_ci        return status;
5401141cc406Sopenharmony_ci      }
5402141cc406Sopenharmony_ci
5403141cc406Sopenharmony_ci      buf_len = result.buf[1] << 8 | result.buf[0];
5404141cc406Sopenharmony_ci
5405141cc406Sopenharmony_ci      if (s->block)
5406141cc406Sopenharmony_ci        buf_len *= (result.buf[3] << 8 | result.buf[2]);
5407141cc406Sopenharmony_ci
5408141cc406Sopenharmony_ci      DBG (5, "sane_read: buf len3 = %lu\n", (u_long) buf_len);
5409141cc406Sopenharmony_ci
5410141cc406Sopenharmony_ci      switch (GET_COLOR (result))
5411141cc406Sopenharmony_ci      {
5412141cc406Sopenharmony_ci      case 1:
5413141cc406Sopenharmony_ci        index = 1;
5414141cc406Sopenharmony_ci        break;
5415141cc406Sopenharmony_ci      case 2:
5416141cc406Sopenharmony_ci        index = 0;
5417141cc406Sopenharmony_ci        break;
5418141cc406Sopenharmony_ci      case 3:
5419141cc406Sopenharmony_ci        index = 2;
5420141cc406Sopenharmony_ci        break;
5421141cc406Sopenharmony_ci      }
5422141cc406Sopenharmony_ci
5423141cc406Sopenharmony_ci      receive (s, s->buf + index * s->params.pixels_per_line, buf_len,
5424141cc406Sopenharmony_ci               &status);
5425141cc406Sopenharmony_ci
5426141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
5427141cc406Sopenharmony_ci      {
5428141cc406Sopenharmony_ci        *length = 0;
5429141cc406Sopenharmony_ci        scan_finish (s);
5430141cc406Sopenharmony_ci        return status;
5431141cc406Sopenharmony_ci      }
5432141cc406Sopenharmony_ci    }
5433141cc406Sopenharmony_ci    else
5434141cc406Sopenharmony_ci    {
5435141cc406Sopenharmony_ci      /*
5436141cc406Sopenharmony_ci       * Read data in block mode
5437141cc406Sopenharmony_ci       */
5438141cc406Sopenharmony_ci
5439141cc406Sopenharmony_ci      /* do we have to reorder the data ? */
5440141cc406Sopenharmony_ci      if (GET_COLOR (result) == 0x01)
5441141cc406Sopenharmony_ci      {
5442141cc406Sopenharmony_ci        reorder = SANE_TRUE;
5443141cc406Sopenharmony_ci      }
5444141cc406Sopenharmony_ci
5445141cc406Sopenharmony_ci      receive (s, s->buf, buf_len, &status);
5446141cc406Sopenharmony_ci
5447141cc406Sopenharmony_ci      if (SANE_STATUS_GOOD != status)
5448141cc406Sopenharmony_ci      {
5449141cc406Sopenharmony_ci        *length = 0;
5450141cc406Sopenharmony_ci        scan_finish (s);
5451141cc406Sopenharmony_ci        return status;
5452141cc406Sopenharmony_ci      }
5453141cc406Sopenharmony_ci    }
5454141cc406Sopenharmony_ci
5455141cc406Sopenharmony_ci    if (result.status & STATUS_AREA_END)
5456141cc406Sopenharmony_ci    {
5457141cc406Sopenharmony_ci      s->eof = SANE_TRUE;
5458141cc406Sopenharmony_ci    }
5459141cc406Sopenharmony_ci    else
5460141cc406Sopenharmony_ci    {
5461141cc406Sopenharmony_ci      if (s->canceling)
5462141cc406Sopenharmony_ci      {
5463141cc406Sopenharmony_ci        send (s, S_CAN, 1, &status);
5464141cc406Sopenharmony_ci        expect_ack (s);
5465141cc406Sopenharmony_ci
5466141cc406Sopenharmony_ci        *length = 0;
5467141cc406Sopenharmony_ci
5468141cc406Sopenharmony_ci        scan_finish (s);
5469141cc406Sopenharmony_ci
5470141cc406Sopenharmony_ci        return SANE_STATUS_CANCELLED;
5471141cc406Sopenharmony_ci      }
5472141cc406Sopenharmony_ci      else
5473141cc406Sopenharmony_ci        send (s, S_ACK, 1, &status);
5474141cc406Sopenharmony_ci    }
5475141cc406Sopenharmony_ci
5476141cc406Sopenharmony_ci    s->end = s->buf + buf_len;
5477141cc406Sopenharmony_ci    s->ptr = s->buf;
5478141cc406Sopenharmony_ci
5479141cc406Sopenharmony_ci    /*
5480141cc406Sopenharmony_ci     * if we have to re-order the color components (GRB->RGB) we
5481141cc406Sopenharmony_ci     * are doing this here:
5482141cc406Sopenharmony_ci     */
5483141cc406Sopenharmony_ci
5484141cc406Sopenharmony_ci    /*
5485141cc406Sopenharmony_ci     * Some scaners (e.g. the Perfection 1640 and GT-2200) seem
5486141cc406Sopenharmony_ci     * to have the R and G channels swapped.
5487141cc406Sopenharmony_ci     * The GT-8700 is the Asian version of the Perfection1640.
5488141cc406Sopenharmony_ci     * If the scanner name is one of these, and the scan mode is
5489141cc406Sopenharmony_ci     * RGB then swap the colors.
5490141cc406Sopenharmony_ci     */
5491141cc406Sopenharmony_ci
5492141cc406Sopenharmony_ci    needStrangeReorder =
5493141cc406Sopenharmony_ci      (strstr (s->hw->sane.model, "GT-2200") ||
5494141cc406Sopenharmony_ci       ((strstr (s->hw->sane.model, "1640") &&
5495141cc406Sopenharmony_ci         strstr (s->hw->sane.model, "Perfection")) ||
5496141cc406Sopenharmony_ci        strstr (s->hw->sane.model, "GT-8700"))) &&
5497141cc406Sopenharmony_ci      s->params.format == SANE_FRAME_RGB;
5498141cc406Sopenharmony_ci
5499141cc406Sopenharmony_ci    /*
5500141cc406Sopenharmony_ci     * Certain Perfection 1650 also need this re-ordering of the two
5501141cc406Sopenharmony_ci     * color channels. These scanners are identified by the problem
5502141cc406Sopenharmony_ci     * with the half vertical scanning area. When we corrected this,
5503141cc406Sopenharmony_ci     * we also set the variable s->hw->need_color_reorder
5504141cc406Sopenharmony_ci     */
5505141cc406Sopenharmony_ci    if (s->hw->need_color_reorder)
5506141cc406Sopenharmony_ci    {
5507141cc406Sopenharmony_ci      needStrangeReorder = SANE_TRUE;
5508141cc406Sopenharmony_ci    }
5509141cc406Sopenharmony_ci
5510141cc406Sopenharmony_ci    if (needStrangeReorder)
5511141cc406Sopenharmony_ci      reorder = SANE_FALSE;     /* reordering once is enough */
5512141cc406Sopenharmony_ci
5513141cc406Sopenharmony_ci    if (s->params.format != SANE_FRAME_RGB)
5514141cc406Sopenharmony_ci      reorder = SANE_FALSE;     /* don't reorder for BW or gray */
5515141cc406Sopenharmony_ci
5516141cc406Sopenharmony_ci    if (reorder)
5517141cc406Sopenharmony_ci    {
5518141cc406Sopenharmony_ci      SANE_Byte *ptr;
5519141cc406Sopenharmony_ci
5520141cc406Sopenharmony_ci      ptr = s->buf;
5521141cc406Sopenharmony_ci      while (ptr < s->end)
5522141cc406Sopenharmony_ci      {
5523141cc406Sopenharmony_ci        if (s->params.depth > 8)
5524141cc406Sopenharmony_ci        {
5525141cc406Sopenharmony_ci          SANE_Byte tmp;
5526141cc406Sopenharmony_ci
5527141cc406Sopenharmony_ci          /* R->G G->R */
5528141cc406Sopenharmony_ci          tmp = ptr[0];
5529141cc406Sopenharmony_ci          ptr[0] = ptr[2];      /* first Byte G */
5530141cc406Sopenharmony_ci          ptr[2] = tmp;         /* first Byte R */
5531141cc406Sopenharmony_ci
5532141cc406Sopenharmony_ci          tmp = ptr[1];
5533141cc406Sopenharmony_ci          ptr[1] = ptr[3];      /* second Byte G */
5534141cc406Sopenharmony_ci          ptr[3] = tmp;         /* second Byte R */
5535141cc406Sopenharmony_ci
5536141cc406Sopenharmony_ci          ptr += 6;             /* go to next pixel */
5537141cc406Sopenharmony_ci        }
5538141cc406Sopenharmony_ci        else
5539141cc406Sopenharmony_ci        {
5540141cc406Sopenharmony_ci          /* R->G G->R */
5541141cc406Sopenharmony_ci          SANE_Byte tmp;
5542141cc406Sopenharmony_ci
5543141cc406Sopenharmony_ci          tmp = ptr[0];
5544141cc406Sopenharmony_ci          ptr[0] = ptr[1];      /* G */
5545141cc406Sopenharmony_ci          ptr[1] = tmp;         /* R */
5546141cc406Sopenharmony_ci          /* B stays the same */
5547141cc406Sopenharmony_ci          ptr += 3;             /* go to next pixel */
5548141cc406Sopenharmony_ci        }
5549141cc406Sopenharmony_ci      }
5550141cc406Sopenharmony_ci    }
5551141cc406Sopenharmony_ci
5552141cc406Sopenharmony_ci    /*
5553141cc406Sopenharmony_ci     * Do the color_shuffle if everything else is correct - at this time
5554141cc406Sopenharmony_ci     * most of the stuff is hardcoded for the Perfection 610
5555141cc406Sopenharmony_ci     */
5556141cc406Sopenharmony_ci
5557141cc406Sopenharmony_ci    if (s->hw->color_shuffle)
5558141cc406Sopenharmony_ci    {
5559141cc406Sopenharmony_ci      int new_length = 0;
5560141cc406Sopenharmony_ci
5561141cc406Sopenharmony_ci      status = color_shuffle (s, &new_length);
5562141cc406Sopenharmony_ci
5563141cc406Sopenharmony_ci      /*
5564141cc406Sopenharmony_ci       * If no bytes are returned, check if the scanner is already done, if so,
5565141cc406Sopenharmony_ci       * we'll probably just return, but if there is more data to process get
5566141cc406Sopenharmony_ci       * the next batch.
5567141cc406Sopenharmony_ci       */
5568141cc406Sopenharmony_ci
5569141cc406Sopenharmony_ci      if (new_length == 0 && s->end != s->ptr)
5570141cc406Sopenharmony_ci      {
5571141cc406Sopenharmony_ci        goto START_READ;
5572141cc406Sopenharmony_ci      }
5573141cc406Sopenharmony_ci
5574141cc406Sopenharmony_ci      s->end = s->buf + new_length;
5575141cc406Sopenharmony_ci      s->ptr = s->buf;
5576141cc406Sopenharmony_ci
5577141cc406Sopenharmony_ci    }
5578141cc406Sopenharmony_ci
5579141cc406Sopenharmony_ci
5580141cc406Sopenharmony_ci    DBG (5, "sane_read: begin scan2\n");
5581141cc406Sopenharmony_ci  }
5582141cc406Sopenharmony_ci
5583141cc406Sopenharmony_ci
5584141cc406Sopenharmony_ci
5585141cc406Sopenharmony_ci  /*
5586141cc406Sopenharmony_ci   * copy the image data to the data memory area
5587141cc406Sopenharmony_ci   */
5588141cc406Sopenharmony_ci
5589141cc406Sopenharmony_ci  if (!s->block && SANE_FRAME_RGB == s->params.format)
5590141cc406Sopenharmony_ci  {
5591141cc406Sopenharmony_ci
5592141cc406Sopenharmony_ci    max_length /= 3;
5593141cc406Sopenharmony_ci
5594141cc406Sopenharmony_ci    if (max_length > s->end - s->ptr)
5595141cc406Sopenharmony_ci      max_length = s->end - s->ptr;
5596141cc406Sopenharmony_ci
5597141cc406Sopenharmony_ci    *length = 3 * max_length;
5598141cc406Sopenharmony_ci
5599141cc406Sopenharmony_ci    if (s->invert_image == SANE_TRUE)
5600141cc406Sopenharmony_ci    {
5601141cc406Sopenharmony_ci      while (max_length-- != 0)
5602141cc406Sopenharmony_ci      {
5603141cc406Sopenharmony_ci        /* invert the three values */
5604141cc406Sopenharmony_ci        *data++ = (u_char) ~ (s->ptr[0]);
5605141cc406Sopenharmony_ci        *data++ = (u_char) ~ (s->ptr[s->params.pixels_per_line]);
5606141cc406Sopenharmony_ci        *data++ = (u_char) ~ (s->ptr[2 * s->params.pixels_per_line]);
5607141cc406Sopenharmony_ci        ++s->ptr;
5608141cc406Sopenharmony_ci      }
5609141cc406Sopenharmony_ci    }
5610141cc406Sopenharmony_ci    else
5611141cc406Sopenharmony_ci    {
5612141cc406Sopenharmony_ci      while (max_length-- != 0)
5613141cc406Sopenharmony_ci      {
5614141cc406Sopenharmony_ci        *data++ = s->ptr[0];
5615141cc406Sopenharmony_ci        *data++ = s->ptr[s->params.pixels_per_line];
5616141cc406Sopenharmony_ci        *data++ = s->ptr[2 * s->params.pixels_per_line];
5617141cc406Sopenharmony_ci        ++s->ptr;
5618141cc406Sopenharmony_ci      }
5619141cc406Sopenharmony_ci    }
5620141cc406Sopenharmony_ci  }
5621141cc406Sopenharmony_ci  else
5622141cc406Sopenharmony_ci  {
5623141cc406Sopenharmony_ci    if (max_length > s->end - s->ptr)
5624141cc406Sopenharmony_ci      max_length = s->end - s->ptr;
5625141cc406Sopenharmony_ci
5626141cc406Sopenharmony_ci    *length = max_length;
5627141cc406Sopenharmony_ci
5628141cc406Sopenharmony_ci    if (1 == s->params.depth)
5629141cc406Sopenharmony_ci    {
5630141cc406Sopenharmony_ci      if (s->invert_image == SANE_TRUE)
5631141cc406Sopenharmony_ci      {
5632141cc406Sopenharmony_ci        while (max_length-- != 0)
5633141cc406Sopenharmony_ci          *data++ = *s->ptr++;
5634141cc406Sopenharmony_ci      }
5635141cc406Sopenharmony_ci      else
5636141cc406Sopenharmony_ci      {
5637141cc406Sopenharmony_ci        while (max_length-- != 0)
5638141cc406Sopenharmony_ci          *data++ = ~*s->ptr++;
5639141cc406Sopenharmony_ci      }
5640141cc406Sopenharmony_ci    }
5641141cc406Sopenharmony_ci    else
5642141cc406Sopenharmony_ci    {
5643141cc406Sopenharmony_ci
5644141cc406Sopenharmony_ci      if (s->invert_image == SANE_TRUE)
5645141cc406Sopenharmony_ci      {
5646141cc406Sopenharmony_ci        int i;
5647141cc406Sopenharmony_ci
5648141cc406Sopenharmony_ci        for (i = 0; i < max_length; i++)
5649141cc406Sopenharmony_ci        {
5650141cc406Sopenharmony_ci          data[i] = (u_char) ~ (s->ptr[i]);
5651141cc406Sopenharmony_ci        }
5652141cc406Sopenharmony_ci      }
5653141cc406Sopenharmony_ci      else
5654141cc406Sopenharmony_ci      {
5655141cc406Sopenharmony_ci        memcpy (data, s->ptr, max_length);
5656141cc406Sopenharmony_ci      }
5657141cc406Sopenharmony_ci      s->ptr += max_length;
5658141cc406Sopenharmony_ci    }
5659141cc406Sopenharmony_ci  }
5660141cc406Sopenharmony_ci
5661141cc406Sopenharmony_ci  DBG (5, "sane_read: end\n");
5662141cc406Sopenharmony_ci
5663141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5664141cc406Sopenharmony_ci}
5665141cc406Sopenharmony_ci
5666141cc406Sopenharmony_ci
5667141cc406Sopenharmony_cistatic SANE_Status
5668141cc406Sopenharmony_cicolor_shuffle (SANE_Handle handle, int *new_length)
5669141cc406Sopenharmony_ci{
5670141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
5671141cc406Sopenharmony_ci  SANE_Byte *buf = s->buf;
5672141cc406Sopenharmony_ci  int length = s->end - s->buf;
5673141cc406Sopenharmony_ci
5674141cc406Sopenharmony_ci  if (s->hw->color_shuffle == SANE_TRUE)
5675141cc406Sopenharmony_ci  {
5676141cc406Sopenharmony_ci    SANE_Byte *data_ptr;        /* ptr to data to process */
5677141cc406Sopenharmony_ci    SANE_Byte *data_end;        /* ptr to end of processed data */
5678141cc406Sopenharmony_ci    SANE_Byte *out_data_ptr;    /* ptr to memory when writing data */
5679141cc406Sopenharmony_ci    int i;                      /* loop counter */
5680141cc406Sopenharmony_ci
5681141cc406Sopenharmony_ci    /*
5682141cc406Sopenharmony_ci     * It looks like we are dealing with a scanner that has an odd way
5683141cc406Sopenharmony_ci     * of dealing with colors... The red and blue scan lines are shifted
5684141cc406Sopenharmony_ci     * up or down by a certain number of lines relative to the green line.
5685141cc406Sopenharmony_ci     */
5686141cc406Sopenharmony_ci    DBG (5, "sane_read: color_shuffle\n");
5687141cc406Sopenharmony_ci
5688141cc406Sopenharmony_ci
5689141cc406Sopenharmony_ci    /*
5690141cc406Sopenharmony_ci     * Initialize the variables we are going to use for the
5691141cc406Sopenharmony_ci     * copying of the data. data_ptr is the pointer to
5692141cc406Sopenharmony_ci     * the currently worked on scan line. data_end is the
5693141cc406Sopenharmony_ci     * end of the data area as calculated from adding *length
5694141cc406Sopenharmony_ci     * to the start of data.
5695141cc406Sopenharmony_ci     * out_data_ptr is used when writing out the processed data
5696141cc406Sopenharmony_ci     * and always points to the beginning of the next line to
5697141cc406Sopenharmony_ci     * write.
5698141cc406Sopenharmony_ci     */
5699141cc406Sopenharmony_ci
5700141cc406Sopenharmony_ci    data_ptr = out_data_ptr = buf;
5701141cc406Sopenharmony_ci    data_end = data_ptr + length;
5702141cc406Sopenharmony_ci
5703141cc406Sopenharmony_ci    /*
5704141cc406Sopenharmony_ci     * The image data is in *buf, we know that the buffer contains s->end - s->buf ( = length)
5705141cc406Sopenharmony_ci     * bytes of data. The width of one line is in s->params.bytes_per_line
5706141cc406Sopenharmony_ci     */
5707141cc406Sopenharmony_ci
5708141cc406Sopenharmony_ci    /*
5709141cc406Sopenharmony_ci     * The buffer area is supposed to have a number of full scan
5710141cc406Sopenharmony_ci     * lines, let's test if this is the case.
5711141cc406Sopenharmony_ci     */
5712141cc406Sopenharmony_ci
5713141cc406Sopenharmony_ci    if (length % s->params.bytes_per_line != 0)
5714141cc406Sopenharmony_ci    {
5715141cc406Sopenharmony_ci      DBG (1, "ERROR in size of buffer: %d / %d\n",
5716141cc406Sopenharmony_ci           length, s->params.bytes_per_line);
5717141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5718141cc406Sopenharmony_ci    }
5719141cc406Sopenharmony_ci
5720141cc406Sopenharmony_ci    while (data_ptr < data_end)
5721141cc406Sopenharmony_ci    {
5722141cc406Sopenharmony_ci      SANE_Byte *source_ptr, *dest_ptr;
5723141cc406Sopenharmony_ci      int loop;
5724141cc406Sopenharmony_ci
5725141cc406Sopenharmony_ci      /* copy the green information into the current line */
5726141cc406Sopenharmony_ci
5727141cc406Sopenharmony_ci      source_ptr = data_ptr + 1;
5728141cc406Sopenharmony_ci      dest_ptr = s->line_buffer[s->color_shuffle_line] + 1;
5729141cc406Sopenharmony_ci
5730141cc406Sopenharmony_ci      for (i = 0; i < s->params.bytes_per_line / 3; i++)
5731141cc406Sopenharmony_ci      {
5732141cc406Sopenharmony_ci        *dest_ptr = *source_ptr;
5733141cc406Sopenharmony_ci        dest_ptr += 3;
5734141cc406Sopenharmony_ci        source_ptr += 3;
5735141cc406Sopenharmony_ci      }
5736141cc406Sopenharmony_ci
5737141cc406Sopenharmony_ci      /* copy the red information n lines back */
5738141cc406Sopenharmony_ci
5739141cc406Sopenharmony_ci      if (s->color_shuffle_line >= s->line_distance)
5740141cc406Sopenharmony_ci      {
5741141cc406Sopenharmony_ci        source_ptr = data_ptr + 2;
5742141cc406Sopenharmony_ci        dest_ptr =
5743141cc406Sopenharmony_ci          s->line_buffer[s->color_shuffle_line - s->line_distance] + 2;
5744141cc406Sopenharmony_ci
5745141cc406Sopenharmony_ci/*                              while (source_ptr < s->line_buffer[s->color_shuffle_line] + s->params.bytes_per_line) */
5746141cc406Sopenharmony_ci        for (loop = 0; loop < s->params.bytes_per_line / 3; loop++)
5747141cc406Sopenharmony_ci
5748141cc406Sopenharmony_ci        {
5749141cc406Sopenharmony_ci          *dest_ptr = *source_ptr;
5750141cc406Sopenharmony_ci          dest_ptr += 3;
5751141cc406Sopenharmony_ci          source_ptr += 3;
5752141cc406Sopenharmony_ci        }
5753141cc406Sopenharmony_ci      }
5754141cc406Sopenharmony_ci
5755141cc406Sopenharmony_ci      /* copy the blue information n lines forward */
5756141cc406Sopenharmony_ci
5757141cc406Sopenharmony_ci      source_ptr = data_ptr;
5758141cc406Sopenharmony_ci      dest_ptr = s->line_buffer[s->color_shuffle_line + s->line_distance];
5759141cc406Sopenharmony_ci
5760141cc406Sopenharmony_ci/*                      while (source_ptr < s->line_buffer[s->color_shuffle_line] + s->params.bytes_per_line) */
5761141cc406Sopenharmony_ci      for (loop = 0; loop < s->params.bytes_per_line / 3; loop++)
5762141cc406Sopenharmony_ci      {
5763141cc406Sopenharmony_ci        *dest_ptr = *source_ptr;
5764141cc406Sopenharmony_ci        dest_ptr += 3;
5765141cc406Sopenharmony_ci        source_ptr += 3;
5766141cc406Sopenharmony_ci      }
5767141cc406Sopenharmony_ci
5768141cc406Sopenharmony_ci      data_ptr += s->params.bytes_per_line;
5769141cc406Sopenharmony_ci
5770141cc406Sopenharmony_ci      if (s->color_shuffle_line == s->line_distance)
5771141cc406Sopenharmony_ci      {
5772141cc406Sopenharmony_ci        /*
5773141cc406Sopenharmony_ci         * we just finished the line in line_buffer[0] - write it to the
5774141cc406Sopenharmony_ci         * output buffer and continue.
5775141cc406Sopenharmony_ci         */
5776141cc406Sopenharmony_ci
5777141cc406Sopenharmony_ci
5778141cc406Sopenharmony_ci        /*
5779141cc406Sopenharmony_ci         * The output buffer is still "buf", but because we are
5780141cc406Sopenharmony_ci         * only overwriting from the beginning of the memory area
5781141cc406Sopenharmony_ci         * we are not interfering with the "still to shuffle" data
5782141cc406Sopenharmony_ci         * in the same area.
5783141cc406Sopenharmony_ci         */
5784141cc406Sopenharmony_ci
5785141cc406Sopenharmony_ci        /*
5786141cc406Sopenharmony_ci         * Strip the first and last n lines and limit to
5787141cc406Sopenharmony_ci         */
5788141cc406Sopenharmony_ci        if ((s->current_output_line >= s->line_distance) &&
5789141cc406Sopenharmony_ci            (s->current_output_line < s->params.lines + s->line_distance))
5790141cc406Sopenharmony_ci        {
5791141cc406Sopenharmony_ci          memcpy (out_data_ptr, s->line_buffer[0], s->params.bytes_per_line);
5792141cc406Sopenharmony_ci          out_data_ptr += s->params.bytes_per_line;
5793141cc406Sopenharmony_ci
5794141cc406Sopenharmony_ci          s->lines_written++;
5795141cc406Sopenharmony_ci        }
5796141cc406Sopenharmony_ci
5797141cc406Sopenharmony_ci        s->current_output_line++;
5798141cc406Sopenharmony_ci
5799141cc406Sopenharmony_ci
5800141cc406Sopenharmony_ci        /*
5801141cc406Sopenharmony_ci         * Now remove the 0-entry and move all other
5802141cc406Sopenharmony_ci         * lines up by one. There are 2*line_distance + 1
5803141cc406Sopenharmony_ci         * buffers, * therefore the loop has to run from 0
5804141cc406Sopenharmony_ci         * to * 2*line_distance, and because we want to
5805141cc406Sopenharmony_ci         * copy every n+1st entry to n the loop runs
5806141cc406Sopenharmony_ci         * from - to 2*line_distance-1!
5807141cc406Sopenharmony_ci         */
5808141cc406Sopenharmony_ci
5809141cc406Sopenharmony_ci        free (s->line_buffer[0]);
5810141cc406Sopenharmony_ci
5811141cc406Sopenharmony_ci        for (i = 0; i < s->line_distance * 2; i++)
5812141cc406Sopenharmony_ci        {
5813141cc406Sopenharmony_ci          s->line_buffer[i] = s->line_buffer[i + 1];
5814141cc406Sopenharmony_ci        }
5815141cc406Sopenharmony_ci
5816141cc406Sopenharmony_ci        /*
5817141cc406Sopenharmony_ci         * and create one new buffer at the end
5818141cc406Sopenharmony_ci         */
5819141cc406Sopenharmony_ci
5820141cc406Sopenharmony_ci        s->line_buffer[s->line_distance * 2] =
5821141cc406Sopenharmony_ci          malloc (s->params.bytes_per_line);
5822141cc406Sopenharmony_ci        if (s->line_buffer[s->line_distance * 2] == NULL)
5823141cc406Sopenharmony_ci        {
5824141cc406Sopenharmony_ci          int i;
5825141cc406Sopenharmony_ci          for (i = 0; i < s->line_distance * 2; i++)
5826141cc406Sopenharmony_ci          {
5827141cc406Sopenharmony_ci            free (s->line_buffer[i]);
5828141cc406Sopenharmony_ci            s->line_buffer[i] = NULL;
5829141cc406Sopenharmony_ci          }
5830141cc406Sopenharmony_ci          DBG (1, "out of memory (line %d)\n", __LINE__);
5831141cc406Sopenharmony_ci          return SANE_STATUS_NO_MEM;
5832141cc406Sopenharmony_ci        }
5833141cc406Sopenharmony_ci      }
5834141cc406Sopenharmony_ci      else
5835141cc406Sopenharmony_ci      {
5836141cc406Sopenharmony_ci        s->color_shuffle_line++;        /* increase the buffer number */
5837141cc406Sopenharmony_ci      }
5838141cc406Sopenharmony_ci    }
5839141cc406Sopenharmony_ci
5840141cc406Sopenharmony_ci    /*
5841141cc406Sopenharmony_ci     * At this time we've used up all the new data from the scanner, some of
5842141cc406Sopenharmony_ci     * it is still in the line_buffers, but we are ready to return some of it
5843141cc406Sopenharmony_ci     * to the front end software. To do so we have to adjust the size of the
5844141cc406Sopenharmony_ci     * data area and the *new_length variable.
5845141cc406Sopenharmony_ci     */
5846141cc406Sopenharmony_ci
5847141cc406Sopenharmony_ci    *new_length = out_data_ptr - buf;
5848141cc406Sopenharmony_ci  }
5849141cc406Sopenharmony_ci
5850141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5851141cc406Sopenharmony_ci
5852141cc406Sopenharmony_ci}
5853141cc406Sopenharmony_ci
5854141cc406Sopenharmony_ci
5855141cc406Sopenharmony_ci
5856141cc406Sopenharmony_ci
5857141cc406Sopenharmony_ci/*
5858141cc406Sopenharmony_ci * static SANE_Status get_identity_information ( SANE_Handle handle)
5859141cc406Sopenharmony_ci *
5860141cc406Sopenharmony_ci * Request Identity information from scanner and fill in information
5861141cc406Sopenharmony_ci * into dev and/or scanner structures.
5862141cc406Sopenharmony_ci */
5863141cc406Sopenharmony_cistatic SANE_Status
5864141cc406Sopenharmony_ciget_identity_information (SANE_Handle handle)
5865141cc406Sopenharmony_ci{
5866141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
5867141cc406Sopenharmony_ci  Epson_Device *dev = s->hw;
5868141cc406Sopenharmony_ci  EpsonIdent ident;
5869141cc406Sopenharmony_ci  u_char param[3];
5870141cc406Sopenharmony_ci  SANE_Status status;
5871141cc406Sopenharmony_ci  u_char *buf;
5872141cc406Sopenharmony_ci
5873141cc406Sopenharmony_ci  DBG (5, "get_identity_information()\n");
5874141cc406Sopenharmony_ci
5875141cc406Sopenharmony_ci  if (!s->hw->cmd->request_identity)
5876141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
5877141cc406Sopenharmony_ci
5878141cc406Sopenharmony_ci
5879141cc406Sopenharmony_ci  param[0] = ESC;
5880141cc406Sopenharmony_ci  param[1] = s->hw->cmd->request_identity;
5881141cc406Sopenharmony_ci  param[2] = '\0';
5882141cc406Sopenharmony_ci
5883141cc406Sopenharmony_ci  if (NULL == (ident = (EpsonIdent) command (s, param, 2, &status)))
5884141cc406Sopenharmony_ci  {
5885141cc406Sopenharmony_ci    DBG (1, "ident failed\n");
5886141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
5887141cc406Sopenharmony_ci  }
5888141cc406Sopenharmony_ci
5889141cc406Sopenharmony_ci  DBG (1, "type  %3c 0x%02x\n", ident->type, ident->type);
5890141cc406Sopenharmony_ci  DBG (1, "level %3c 0x%02x\n", ident->level, ident->level);
5891141cc406Sopenharmony_ci
5892141cc406Sopenharmony_ci  {
5893141cc406Sopenharmony_ci    char *force = getenv ("SANE_EPSON_CMD_LVL");
5894141cc406Sopenharmony_ci
5895141cc406Sopenharmony_ci    if (force)
5896141cc406Sopenharmony_ci    {
5897141cc406Sopenharmony_ci      ident->type = force[0];
5898141cc406Sopenharmony_ci      ident->level = force[1];
5899141cc406Sopenharmony_ci
5900141cc406Sopenharmony_ci      DBG (1, "type  %3c 0x%02x\n", ident->type, ident->type);
5901141cc406Sopenharmony_ci      DBG (1, "level %3c 0x%02x\n", ident->level, ident->level);
5902141cc406Sopenharmony_ci
5903141cc406Sopenharmony_ci      DBG (1, "forced\n");
5904141cc406Sopenharmony_ci    }
5905141cc406Sopenharmony_ci  }
5906141cc406Sopenharmony_ci
5907141cc406Sopenharmony_ci/*
5908141cc406Sopenharmony_ci *  check if option equipment is installed.
5909141cc406Sopenharmony_ci */
5910141cc406Sopenharmony_ci
5911141cc406Sopenharmony_ci  if (ident->status & STATUS_OPTION)
5912141cc406Sopenharmony_ci  {
5913141cc406Sopenharmony_ci    DBG (1, "option equipment is installed\n");
5914141cc406Sopenharmony_ci    dev->extension = SANE_TRUE;
5915141cc406Sopenharmony_ci  }
5916141cc406Sopenharmony_ci  else
5917141cc406Sopenharmony_ci  {
5918141cc406Sopenharmony_ci    DBG (1, "no option equipment installed\n");
5919141cc406Sopenharmony_ci    dev->extension = SANE_FALSE;
5920141cc406Sopenharmony_ci  }
5921141cc406Sopenharmony_ci
5922141cc406Sopenharmony_ci  dev->TPU = SANE_FALSE;
5923141cc406Sopenharmony_ci  dev->ADF = SANE_FALSE;
5924141cc406Sopenharmony_ci
5925141cc406Sopenharmony_ci/*
5926141cc406Sopenharmony_ci *  set command type and level.
5927141cc406Sopenharmony_ci */
5928141cc406Sopenharmony_ci
5929141cc406Sopenharmony_ci  {
5930141cc406Sopenharmony_ci    int n;
5931141cc406Sopenharmony_ci
5932141cc406Sopenharmony_ci    for (n = 0; n < NELEMS (epson_cmd); n++)
5933141cc406Sopenharmony_ci    {
5934141cc406Sopenharmony_ci      char type_level[3];
5935141cc406Sopenharmony_ci      sprintf(type_level, "%c%c", ident->type, ident->level);
5936141cc406Sopenharmony_ci      if (!strncmp (type_level, epson_cmd[n].level, 2))
5937141cc406Sopenharmony_ci        break;
5938141cc406Sopenharmony_ci    }
5939141cc406Sopenharmony_ci
5940141cc406Sopenharmony_ci    if (n < NELEMS (epson_cmd))
5941141cc406Sopenharmony_ci    {
5942141cc406Sopenharmony_ci      dev->cmd = &epson_cmd[n];
5943141cc406Sopenharmony_ci    }
5944141cc406Sopenharmony_ci    else
5945141cc406Sopenharmony_ci    {
5946141cc406Sopenharmony_ci      dev->cmd = &epson_cmd[EPSON_LEVEL_DEFAULT];
5947141cc406Sopenharmony_ci      DBG (1, "Unknown type %c or level %c, using %s\n",
5948141cc406Sopenharmony_ci           ident->type, ident->level, dev->cmd->level);
5949141cc406Sopenharmony_ci    }
5950141cc406Sopenharmony_ci
5951141cc406Sopenharmony_ci    s->hw->level = dev->cmd->level[1] - '0';
5952141cc406Sopenharmony_ci  }                             /* set command type and level */
5953141cc406Sopenharmony_ci
5954141cc406Sopenharmony_ci/*
5955141cc406Sopenharmony_ci *  Setting available resolutions and xy ranges for sane frontend.
5956141cc406Sopenharmony_ci */
5957141cc406Sopenharmony_ci
5958141cc406Sopenharmony_ci  s->hw->res_list_size = 0;
5959141cc406Sopenharmony_ci  s->hw->res_list =
5960141cc406Sopenharmony_ci    (SANE_Int *) calloc (s->hw->res_list_size, sizeof (SANE_Int));
5961141cc406Sopenharmony_ci
5962141cc406Sopenharmony_ci  if (NULL == s->hw->res_list)
5963141cc406Sopenharmony_ci  {
5964141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
5965141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
5966141cc406Sopenharmony_ci  }
5967141cc406Sopenharmony_ci
5968141cc406Sopenharmony_ci  {
5969141cc406Sopenharmony_ci    int n, k;
5970141cc406Sopenharmony_ci    int x = 0, y = 0;
5971141cc406Sopenharmony_ci    int count = ident->count2 * 255 + ident->count1;
5972141cc406Sopenharmony_ci
5973141cc406Sopenharmony_ci    /* we need to correct for the difference in size between
5974141cc406Sopenharmony_ci       the EpsonIdentRec and the EpsonHdrRec */
5975141cc406Sopenharmony_ci    int correction = sizeof (EpsonIdentRec) - sizeof (EpsonHdrRec);
5976141cc406Sopenharmony_ci    for (n = (count - correction), buf = ident->buf; n; n -= k, buf += k)
5977141cc406Sopenharmony_ci    {
5978141cc406Sopenharmony_ci      switch (*buf)
5979141cc406Sopenharmony_ci      {
5980141cc406Sopenharmony_ci      case 'R':
5981141cc406Sopenharmony_ci        {
5982141cc406Sopenharmony_ci          int val = buf[2] << 8 | buf[1];
5983141cc406Sopenharmony_ci
5984141cc406Sopenharmony_ci          s->hw->res_list_size++;
5985141cc406Sopenharmony_ci          s->hw->res_list =
5986141cc406Sopenharmony_ci            (SANE_Int *) realloc (s->hw->res_list,
5987141cc406Sopenharmony_ci                                  s->hw->res_list_size * sizeof (SANE_Int));
5988141cc406Sopenharmony_ci
5989141cc406Sopenharmony_ci          if (NULL == s->hw->res_list)
5990141cc406Sopenharmony_ci          {
5991141cc406Sopenharmony_ci            DBG (1, "out of memory (line %d)\n", __LINE__);
5992141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
5993141cc406Sopenharmony_ci          }
5994141cc406Sopenharmony_ci
5995141cc406Sopenharmony_ci          s->hw->res_list[s->hw->res_list_size - 1] = (SANE_Int) val;
5996141cc406Sopenharmony_ci
5997141cc406Sopenharmony_ci          DBG (1, "resolution (dpi): %d\n", val);
5998141cc406Sopenharmony_ci          k = 3;
5999141cc406Sopenharmony_ci          continue;
6000141cc406Sopenharmony_ci        }
6001141cc406Sopenharmony_ci      case 'A':
6002141cc406Sopenharmony_ci        {
6003141cc406Sopenharmony_ci          x = buf[2] << 8 | buf[1];
6004141cc406Sopenharmony_ci          y = buf[4] << 8 | buf[3];
6005141cc406Sopenharmony_ci
6006141cc406Sopenharmony_ci          DBG (1, "maximum scan area: x %d y %d\n", x, y);
6007141cc406Sopenharmony_ci          k = 5;
6008141cc406Sopenharmony_ci
6009141cc406Sopenharmony_ci          /*
6010141cc406Sopenharmony_ci           * Check for Perfection 4990 photo/GT-X800 scanner.
6011141cc406Sopenharmony_ci           * This scanner only report 3200 dpi back.
6012141cc406Sopenharmony_ci           * The scanner physically supports 4800 dpi.
6013141cc406Sopenharmony_ci           * This is simulated here...
6014141cc406Sopenharmony_ci           * Further details read:
6015141cc406Sopenharmony_ci           * EPSON Programming guide for EPSON Color Image Scanner Perfection 4990
6016141cc406Sopenharmony_ci           */
6017141cc406Sopenharmony_ci          if (s->hw->cmd->request_extended_status != 0)
6018141cc406Sopenharmony_ci          {
6019141cc406Sopenharmony_ci            u_char *buf;
6020141cc406Sopenharmony_ci            u_char params[2];
6021141cc406Sopenharmony_ci            EpsonHdr head;
6022141cc406Sopenharmony_ci
6023141cc406Sopenharmony_ci            params[0] = ESC;
6024141cc406Sopenharmony_ci            params[1] = s->hw->cmd->request_extended_status;
6025141cc406Sopenharmony_ci
6026141cc406Sopenharmony_ci            if (NULL != (head = (EpsonHdr) command (s, params, 2, &status)))
6027141cc406Sopenharmony_ci            {
6028141cc406Sopenharmony_ci              buf = &head->buf[0x1A];
6029141cc406Sopenharmony_ci              DBG (1, "product name %x %x %x %x %x %x %x %x \n", buf[0], buf[1],buf[2],buf[3],buf[4], buf[5],buf[6], buf[7] );
6030141cc406Sopenharmony_ci              if (strncmp((char *) buf,"GT-X800",7) == 0)
6031141cc406Sopenharmony_ci              {
6032141cc406Sopenharmony_ci                int val = 0x12 << 8 | 0xC0;
6033141cc406Sopenharmony_ci
6034141cc406Sopenharmony_ci                s->hw->res_list_size++;
6035141cc406Sopenharmony_ci                s->hw->res_list =
6036141cc406Sopenharmony_ci                 (SANE_Int *) realloc (s->hw->res_list,
6037141cc406Sopenharmony_ci                                          s->hw->res_list_size * sizeof (SANE_Int));
6038141cc406Sopenharmony_ci
6039141cc406Sopenharmony_ci                if (NULL == s->hw->res_list)
6040141cc406Sopenharmony_ci                {
6041141cc406Sopenharmony_ci                  DBG (1, "out of memory (line %d)\n", __LINE__);
6042141cc406Sopenharmony_ci                  return SANE_STATUS_NO_MEM;
6043141cc406Sopenharmony_ci                }
6044141cc406Sopenharmony_ci
6045141cc406Sopenharmony_ci                s->hw->res_list[s->hw->res_list_size - 1] = (SANE_Int) val;
6046141cc406Sopenharmony_ci                x = (x/32)*48;
6047141cc406Sopenharmony_ci                y = (y/32)*48;
6048141cc406Sopenharmony_ci
6049141cc406Sopenharmony_ci                DBG (1, "resolution (dpi): %d\n", val);
6050141cc406Sopenharmony_ci                DBG (1, "maximum scan area GT-X800: x %d y %d\n", x, y);
6051141cc406Sopenharmony_ci              }
6052141cc406Sopenharmony_ci            }
6053141cc406Sopenharmony_ci          }
6054141cc406Sopenharmony_ci
6055141cc406Sopenharmony_ci          continue;
6056141cc406Sopenharmony_ci        }
6057141cc406Sopenharmony_ci      default:
6058141cc406Sopenharmony_ci        break;
6059141cc406Sopenharmony_ci      }                         /* case */
6060141cc406Sopenharmony_ci
6061141cc406Sopenharmony_ci      break;
6062141cc406Sopenharmony_ci    }                           /* for */
6063141cc406Sopenharmony_ci
6064141cc406Sopenharmony_ci    dev->dpi_range.min = s->hw->res_list[0];
6065141cc406Sopenharmony_ci    dev->dpi_range.max = s->hw->res_list[s->hw->res_list_size - 1];
6066141cc406Sopenharmony_ci    dev->dpi_range.quant = 0;
6067141cc406Sopenharmony_ci
6068141cc406Sopenharmony_ci    dev->fbf_x_range.min = 0;
6069141cc406Sopenharmony_ci    dev->fbf_x_range.max = SANE_FIX (x * 25.4 / dev->dpi_range.max);
6070141cc406Sopenharmony_ci    dev->fbf_x_range.quant = 0;
6071141cc406Sopenharmony_ci
6072141cc406Sopenharmony_ci    dev->fbf_y_range.min = 0;
6073141cc406Sopenharmony_ci    dev->fbf_y_range.max = SANE_FIX (y * 25.4 / dev->dpi_range.max);
6074141cc406Sopenharmony_ci    dev->fbf_y_range.quant = 0;
6075141cc406Sopenharmony_ci
6076141cc406Sopenharmony_ci    DBG (5, "fbf tlx %f tly %f brx %f bry %f [mm]\n",
6077141cc406Sopenharmony_ci         SANE_UNFIX (dev->fbf_x_range.min), SANE_UNFIX (dev->fbf_y_range.min),
6078141cc406Sopenharmony_ci         SANE_UNFIX (dev->fbf_x_range.max),
6079141cc406Sopenharmony_ci         SANE_UNFIX (dev->fbf_y_range.max));
6080141cc406Sopenharmony_ci
6081141cc406Sopenharmony_ci  }
6082141cc406Sopenharmony_ci
6083141cc406Sopenharmony_ci  /*
6084141cc406Sopenharmony_ci   * Copy the resolution list to the resolution_list array so that the frontend can
6085141cc406Sopenharmony_ci   * display the correct values
6086141cc406Sopenharmony_ci   */
6087141cc406Sopenharmony_ci
6088141cc406Sopenharmony_ci  s->hw->resolution_list =
6089141cc406Sopenharmony_ci    malloc ((s->hw->res_list_size + 1) * sizeof (SANE_Word));
6090141cc406Sopenharmony_ci
6091141cc406Sopenharmony_ci  if (s->hw->resolution_list == NULL)
6092141cc406Sopenharmony_ci  {
6093141cc406Sopenharmony_ci    DBG (1, "out of memory (line %d)\n", __LINE__);
6094141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
6095141cc406Sopenharmony_ci  }
6096141cc406Sopenharmony_ci  *(s->hw->resolution_list) = s->hw->res_list_size;
6097141cc406Sopenharmony_ci  memcpy (&(s->hw->resolution_list[1]), s->hw->res_list,
6098141cc406Sopenharmony_ci          s->hw->res_list_size * sizeof (SANE_Word));
6099141cc406Sopenharmony_ci
6100141cc406Sopenharmony_ci  /* filter the resolution list */
6101141cc406Sopenharmony_ci  /* the option is not yet initialized, for now just set it to false */
6102141cc406Sopenharmony_ci  s->val[OPT_LIMIT_RESOLUTION].w = SANE_FALSE;
6103141cc406Sopenharmony_ci  filter_resolution_list (s);
6104141cc406Sopenharmony_ci
6105141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6106141cc406Sopenharmony_ci
6107141cc406Sopenharmony_ci}                               /* request identity */
6108141cc406Sopenharmony_ci
6109141cc406Sopenharmony_ci
6110141cc406Sopenharmony_ci/*
6111141cc406Sopenharmony_ci * static SANE_Status get_identity2_information ( SANE_Handle handle)
6112141cc406Sopenharmony_ci *
6113141cc406Sopenharmony_ci * Request Identity2 information from scanner and fill in information
6114141cc406Sopenharmony_ci * into dev and/or scanner structures.
6115141cc406Sopenharmony_ci */
6116141cc406Sopenharmony_cistatic SANE_Status
6117141cc406Sopenharmony_ciget_identity2_information (SANE_Handle handle)
6118141cc406Sopenharmony_ci{
6119141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
6120141cc406Sopenharmony_ci  SANE_Status status;
6121141cc406Sopenharmony_ci  int len;
6122141cc406Sopenharmony_ci  u_char param[3];
6123141cc406Sopenharmony_ci  u_char result[4];
6124141cc406Sopenharmony_ci  u_char *buf;
6125141cc406Sopenharmony_ci
6126141cc406Sopenharmony_ci  DBG (5, "get_identity2_information()\n");
6127141cc406Sopenharmony_ci
6128141cc406Sopenharmony_ci  if (s->hw->cmd->request_identity2 == 0)
6129141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
6130141cc406Sopenharmony_ci
6131141cc406Sopenharmony_ci  param[0] = ESC;
6132141cc406Sopenharmony_ci  param[1] = s->hw->cmd->request_identity2;
6133141cc406Sopenharmony_ci  param[2] = '\0';
6134141cc406Sopenharmony_ci
6135141cc406Sopenharmony_ci  send (s, param, 2, &status);
6136141cc406Sopenharmony_ci
6137141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6138141cc406Sopenharmony_ci    return status;
6139141cc406Sopenharmony_ci
6140141cc406Sopenharmony_ci  len = 4;                      /* receive header */
6141141cc406Sopenharmony_ci
6142141cc406Sopenharmony_ci  receive (s, result, len, &status);
6143141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6144141cc406Sopenharmony_ci    return status;
6145141cc406Sopenharmony_ci
6146141cc406Sopenharmony_ci  len = result[3] << 8 | result[2];
6147141cc406Sopenharmony_ci  buf = alloca (len);
6148141cc406Sopenharmony_ci
6149141cc406Sopenharmony_ci  receive (s, buf, len, &status);       /* receive actual status data */
6150141cc406Sopenharmony_ci
6151141cc406Sopenharmony_ci  /* the first two bytes of the buffer contain the optical resolution */
6152141cc406Sopenharmony_ci  s->hw->optical_res = buf[1] << 8 | buf[0];
6153141cc406Sopenharmony_ci
6154141cc406Sopenharmony_ci  /*
6155141cc406Sopenharmony_ci   * the 4th and 5th byte contain the line distance. Both values have to
6156141cc406Sopenharmony_ci   * be identical, otherwise this software can not handle this scanner.
6157141cc406Sopenharmony_ci   */
6158141cc406Sopenharmony_ci  if (buf[4] != buf[5])
6159141cc406Sopenharmony_ci  {
6160141cc406Sopenharmony_ci    close_scanner (s);
6161141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
6162141cc406Sopenharmony_ci  }
6163141cc406Sopenharmony_ci  s->hw->max_line_distance = buf[4];
6164141cc406Sopenharmony_ci
6165141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6166141cc406Sopenharmony_ci}
6167141cc406Sopenharmony_ci
6168141cc406Sopenharmony_ci/*
6169141cc406Sopenharmony_ci * void sane_cancel(SANE_Handle handle)
6170141cc406Sopenharmony_ci *
6171141cc406Sopenharmony_ci * Set the cancel flag to true. The next time the backend requests data
6172141cc406Sopenharmony_ci * from the scanner the CAN message will be sent.
6173141cc406Sopenharmony_ci */
6174141cc406Sopenharmony_ci
6175141cc406Sopenharmony_civoid
6176141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
6177141cc406Sopenharmony_ci{
6178141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
6179141cc406Sopenharmony_ci
6180141cc406Sopenharmony_ci  /*
6181141cc406Sopenharmony_ci   * If the s->ptr pointer is not NULL, then a scan operation
6182141cc406Sopenharmony_ci   * was started and if s->eof is FALSE, it was not finished.
6183141cc406Sopenharmony_ci   */
6184141cc406Sopenharmony_ci
6185141cc406Sopenharmony_ci  if (s->buf != NULL)
6186141cc406Sopenharmony_ci  {
6187141cc406Sopenharmony_ci    u_char *dummy;
6188141cc406Sopenharmony_ci    int len;
6189141cc406Sopenharmony_ci
6190141cc406Sopenharmony_ci    /* malloc one line */
6191141cc406Sopenharmony_ci    dummy = malloc (s->params.bytes_per_line);
6192141cc406Sopenharmony_ci    if (dummy == NULL)
6193141cc406Sopenharmony_ci    {
6194141cc406Sopenharmony_ci      DBG (1, "Out of memory\n");
6195141cc406Sopenharmony_ci      return;
6196141cc406Sopenharmony_ci    }
6197141cc406Sopenharmony_ci    else
6198141cc406Sopenharmony_ci    {
6199141cc406Sopenharmony_ci
6200141cc406Sopenharmony_ci      /* there is still data to read from the scanner */
6201141cc406Sopenharmony_ci
6202141cc406Sopenharmony_ci      s->canceling = SANE_TRUE;
6203141cc406Sopenharmony_ci
6204141cc406Sopenharmony_ci      while (!s->eof &&
6205141cc406Sopenharmony_ci             SANE_STATUS_CANCELLED != sane_read (s, dummy,
6206141cc406Sopenharmony_ci                                                 s->params.bytes_per_line,
6207141cc406Sopenharmony_ci                                                 &len))
6208141cc406Sopenharmony_ci      {
6209141cc406Sopenharmony_ci        /* empty body, the while condition does the processing */
6210141cc406Sopenharmony_ci      }
6211141cc406Sopenharmony_ci      free (dummy);
6212141cc406Sopenharmony_ci    }
6213141cc406Sopenharmony_ci
6214141cc406Sopenharmony_ci  }
6215141cc406Sopenharmony_ci}
6216141cc406Sopenharmony_ci
6217141cc406Sopenharmony_ci
6218141cc406Sopenharmony_cistatic SANE_Status
6219141cc406Sopenharmony_cirequest_focus_position (SANE_Handle handle, u_char * position)
6220141cc406Sopenharmony_ci{
6221141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
6222141cc406Sopenharmony_ci  SANE_Status status;
6223141cc406Sopenharmony_ci  int len;
6224141cc406Sopenharmony_ci  u_char param[3];
6225141cc406Sopenharmony_ci  u_char result[4];
6226141cc406Sopenharmony_ci  u_char *buf;
6227141cc406Sopenharmony_ci
6228141cc406Sopenharmony_ci  DBG (5, "request_focus_position()\n");
6229141cc406Sopenharmony_ci
6230141cc406Sopenharmony_ci  if (s->hw->cmd->request_focus_position == 0)
6231141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
6232141cc406Sopenharmony_ci
6233141cc406Sopenharmony_ci  param[0] = ESC;
6234141cc406Sopenharmony_ci  param[1] = s->hw->cmd->request_focus_position;
6235141cc406Sopenharmony_ci  param[2] = '\0';
6236141cc406Sopenharmony_ci
6237141cc406Sopenharmony_ci  send (s, param, 2, &status);
6238141cc406Sopenharmony_ci
6239141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6240141cc406Sopenharmony_ci    return status;
6241141cc406Sopenharmony_ci
6242141cc406Sopenharmony_ci  len = 4;                      /* receive header */
6243141cc406Sopenharmony_ci
6244141cc406Sopenharmony_ci  receive (s, result, len, &status);
6245141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6246141cc406Sopenharmony_ci    return status;
6247141cc406Sopenharmony_ci
6248141cc406Sopenharmony_ci  len = result[3] << 8 | result[2];
6249141cc406Sopenharmony_ci  buf = alloca (len);
6250141cc406Sopenharmony_ci
6251141cc406Sopenharmony_ci  receive (s, buf, len, &status);       /* receive actual status data */
6252141cc406Sopenharmony_ci
6253141cc406Sopenharmony_ci  *position = buf[1];
6254141cc406Sopenharmony_ci  DBG (1, "Focus position = 0x%x\n", buf[1]);
6255141cc406Sopenharmony_ci
6256141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6257141cc406Sopenharmony_ci}
6258141cc406Sopenharmony_ci
6259141cc406Sopenharmony_ci
6260141cc406Sopenharmony_ci/*
6261141cc406Sopenharmony_ci * Request the push button status
6262141cc406Sopenharmony_ci * returns SANE_TRUE if the button was pressed
6263141cc406Sopenharmony_ci * and SANE_FALSE if the button was not pressed
6264141cc406Sopenharmony_ci * it also returns SANE_TRUE in case of an error.
6265141cc406Sopenharmony_ci * This is necessary so that a process that waits for
6266141cc406Sopenharmony_ci * the button does not block indefinitely.
6267141cc406Sopenharmony_ci */
6268141cc406Sopenharmony_cistatic SANE_Bool
6269141cc406Sopenharmony_cirequest_push_button_status (SANE_Handle handle, SANE_Bool * theButtonStatus)
6270141cc406Sopenharmony_ci{
6271141cc406Sopenharmony_ci  Epson_Scanner *s = (Epson_Scanner *) handle;
6272141cc406Sopenharmony_ci  SANE_Status status;
6273141cc406Sopenharmony_ci  int len;
6274141cc406Sopenharmony_ci  u_char param[3];
6275141cc406Sopenharmony_ci  u_char result[4];
6276141cc406Sopenharmony_ci  u_char *buf;
6277141cc406Sopenharmony_ci
6278141cc406Sopenharmony_ci  DBG (5, "request_push_button_status()\n");
6279141cc406Sopenharmony_ci
6280141cc406Sopenharmony_ci  if (s->hw->cmd->request_push_button_status == 0)
6281141cc406Sopenharmony_ci  {
6282141cc406Sopenharmony_ci    DBG (1, "push button status unsupported\n");
6283141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
6284141cc406Sopenharmony_ci  }
6285141cc406Sopenharmony_ci
6286141cc406Sopenharmony_ci  param[0] = ESC;
6287141cc406Sopenharmony_ci  param[1] = s->hw->cmd->request_push_button_status;
6288141cc406Sopenharmony_ci  param[2] = '\0';
6289141cc406Sopenharmony_ci
6290141cc406Sopenharmony_ci  send (s, param, 2, &status);
6291141cc406Sopenharmony_ci
6292141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6293141cc406Sopenharmony_ci  {
6294141cc406Sopenharmony_ci    DBG (1, "error sending command\n");
6295141cc406Sopenharmony_ci    return status;
6296141cc406Sopenharmony_ci  }
6297141cc406Sopenharmony_ci
6298141cc406Sopenharmony_ci  len = 4;                      /* receive header */
6299141cc406Sopenharmony_ci
6300141cc406Sopenharmony_ci  receive (s, result, len, &status);
6301141cc406Sopenharmony_ci  if (SANE_STATUS_GOOD != status)
6302141cc406Sopenharmony_ci    return status;
6303141cc406Sopenharmony_ci
6304141cc406Sopenharmony_ci  len = result[3] << 8 | result[2];     /* this should be 1 for scanners with one button */
6305141cc406Sopenharmony_ci  buf = alloca (len);
6306141cc406Sopenharmony_ci
6307141cc406Sopenharmony_ci  receive (s, buf, len, &status);       /* receive actual status data */
6308141cc406Sopenharmony_ci
6309141cc406Sopenharmony_ci  DBG (1, "Push button status = %d\n", buf[0] & 0x01);
6310141cc406Sopenharmony_ci  *theButtonStatus = ((buf[0] & 0x01) != 0);
6311141cc406Sopenharmony_ci
6312141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
6313141cc406Sopenharmony_ci}
6314141cc406Sopenharmony_ci
6315141cc406Sopenharmony_ci
6316141cc406Sopenharmony_ci
6317141cc406Sopenharmony_cistatic void
6318141cc406Sopenharmony_cifilter_resolution_list (Epson_Scanner * s)
6319141cc406Sopenharmony_ci{
6320141cc406Sopenharmony_ci  /* re-create the list */
6321141cc406Sopenharmony_ci
6322141cc406Sopenharmony_ci  if (s->val[OPT_LIMIT_RESOLUTION].w == SANE_TRUE)
6323141cc406Sopenharmony_ci  {
6324141cc406Sopenharmony_ci    /* copy the short list */
6325141cc406Sopenharmony_ci
6326141cc406Sopenharmony_ci    /* filter out all values that are not 300 or 400 dpi based */
6327141cc406Sopenharmony_ci    int i;
6328141cc406Sopenharmony_ci
6329141cc406Sopenharmony_ci    int new_size = 0;
6330141cc406Sopenharmony_ci    SANE_Bool is_correct_resolution = SANE_FALSE;
6331141cc406Sopenharmony_ci
6332141cc406Sopenharmony_ci    for (i = 1; i <= s->hw->res_list_size; i++)
6333141cc406Sopenharmony_ci    {
6334141cc406Sopenharmony_ci      SANE_Word res;
6335141cc406Sopenharmony_ci      res = s->hw->res_list[i];
6336141cc406Sopenharmony_ci      if ((res < 100) || (0 == (res % 300)) || (0 == (res % 400)))
6337141cc406Sopenharmony_ci      {
6338141cc406Sopenharmony_ci        /* add the value */
6339141cc406Sopenharmony_ci        new_size++;
6340141cc406Sopenharmony_ci
6341141cc406Sopenharmony_ci        s->hw->resolution_list[new_size] = s->hw->res_list[i];
6342141cc406Sopenharmony_ci
6343141cc406Sopenharmony_ci        /* check for a valid current resolution */
6344141cc406Sopenharmony_ci        if (res == s->val[OPT_RESOLUTION].w)
6345141cc406Sopenharmony_ci        {
6346141cc406Sopenharmony_ci          is_correct_resolution = SANE_TRUE;
6347141cc406Sopenharmony_ci        }
6348141cc406Sopenharmony_ci      }
6349141cc406Sopenharmony_ci    }
6350141cc406Sopenharmony_ci    s->hw->resolution_list[0] = new_size;
6351141cc406Sopenharmony_ci
6352141cc406Sopenharmony_ci    if (is_correct_resolution == SANE_FALSE)
6353141cc406Sopenharmony_ci    {
6354141cc406Sopenharmony_ci      for (i = 1; i <= new_size; i++)
6355141cc406Sopenharmony_ci      {
6356141cc406Sopenharmony_ci        if (s->val[OPT_RESOLUTION].w < s->hw->resolution_list[i])
6357141cc406Sopenharmony_ci        {
6358141cc406Sopenharmony_ci          s->val[OPT_RESOLUTION].w = s->hw->resolution_list[i];
6359141cc406Sopenharmony_ci          i = new_size + 1;
6360141cc406Sopenharmony_ci        }
6361141cc406Sopenharmony_ci      }
6362141cc406Sopenharmony_ci    }
6363141cc406Sopenharmony_ci
6364141cc406Sopenharmony_ci  }
6365141cc406Sopenharmony_ci  else
6366141cc406Sopenharmony_ci  {
6367141cc406Sopenharmony_ci    /* copy the full list */
6368141cc406Sopenharmony_ci    s->hw->resolution_list[0] = s->hw->res_list_size;
6369141cc406Sopenharmony_ci    memcpy (&(s->hw->resolution_list[1]), s->hw->res_list,
6370141cc406Sopenharmony_ci            s->hw->res_list_size * sizeof (SANE_Word));
6371141cc406Sopenharmony_ci  }
6372141cc406Sopenharmony_ci}
6373141cc406Sopenharmony_ci
6374141cc406Sopenharmony_ci/**********************************************************************************/
6375141cc406Sopenharmony_ci
6376141cc406Sopenharmony_ci/*
6377141cc406Sopenharmony_ci * SANE_Status sane_set_io_mode()
6378141cc406Sopenharmony_ci *
6379141cc406Sopenharmony_ci * not supported - for asynchronous I/O
6380141cc406Sopenharmony_ci */
6381141cc406Sopenharmony_ci
6382141cc406Sopenharmony_ciSANE_Status
6383141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
6384141cc406Sopenharmony_ci{
6385141cc406Sopenharmony_ci  /* get rid of compiler warning */
6386141cc406Sopenharmony_ci  (void) handle;
6387141cc406Sopenharmony_ci  (void) non_blocking;
6388141cc406Sopenharmony_ci
6389141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
6390141cc406Sopenharmony_ci}
6391141cc406Sopenharmony_ci
6392141cc406Sopenharmony_ci/*
6393141cc406Sopenharmony_ci * SANE_Status sane_get_select_fd()
6394141cc406Sopenharmony_ci *
6395141cc406Sopenharmony_ci * not supported - for asynchronous I/O
6396141cc406Sopenharmony_ci */
6397141cc406Sopenharmony_ci
6398141cc406Sopenharmony_ciSANE_Status
6399141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
6400141cc406Sopenharmony_ci{
6401141cc406Sopenharmony_ci  /* get rid of compiler warnings */
6402141cc406Sopenharmony_ci  (void) handle;
6403141cc406Sopenharmony_ci  (void) fd;
6404141cc406Sopenharmony_ci
6405141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
6406141cc406Sopenharmony_ci}
6407141cc406Sopenharmony_ci
6408141cc406Sopenharmony_ci/*
6409141cc406Sopenharmony_civim:ts=2:sw=2:cindent:
6410141cc406Sopenharmony_ci*/
6411