1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   This file implements a SANE backend for Fujitsu ScanParner 15C
40141cc406Sopenharmony_ci   flatbed/ADF scanners.  It was derived from the COOLSCAN driver.
41141cc406Sopenharmony_ci   Written by Randolph Bentson <bentson@holmsjoen.com> */
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/*
44141cc406Sopenharmony_ci * Revision 1.17  2008/11/26 21:21:30  kitno-guest
45141cc406Sopenharmony_ci * * backend/ *.[ch]: nearly every backend used V_MAJOR
46141cc406Sopenharmony_ci * instead of SANE_CURRENT_MAJOR in sane_init()
47141cc406Sopenharmony_ci * * backend/snapscan.c: remove EXPECTED_VERSION check
48141cc406Sopenharmony_ci * since new SANE standard is forward compatible
49141cc406Sopenharmony_ci *
50141cc406Sopenharmony_ci * Revision 1.16  2008-07-26 03:53:44  kitno-guest
51141cc406Sopenharmony_ci * separate x-resolution from resolution, and update all backends that use
52141cc406Sopenharmony_ci * it, to prevent ui change
53141cc406Sopenharmony_ci *
54141cc406Sopenharmony_ci * Revision 1.15  2007-11-18 10:59:18  ellert-guest
55141cc406Sopenharmony_ci * Fix handling of valid "negative" PIDs
56141cc406Sopenharmony_ci *
57141cc406Sopenharmony_ci * Revision 1.14  2007-10-26 14:56:38  jblache
58141cc406Sopenharmony_ci * OPT_NUM_OPTS must be of type SANE_TYPE_INT.
59141cc406Sopenharmony_ci *
60141cc406Sopenharmony_ci * Revision 1.13  2006/03/29 20:48:50  hmg-guest
61141cc406Sopenharmony_ci * Fixed ADF support. Patch from Andreas Degert <ad@papyrus-gmbh.de>.
62141cc406Sopenharmony_ci *
63141cc406Sopenharmony_ci * Revision 1.12  2005/10/01 17:06:25  hmg-guest
64141cc406Sopenharmony_ci * Fixed some warnings (bug #302290).
65141cc406Sopenharmony_ci *
66141cc406Sopenharmony_ci * Revision 1.11  2005/07/15 18:12:49  hmg-guest
67141cc406Sopenharmony_ci * Better 4->8 bit depth expansion algorithm (from Mattias Ellert
68141cc406Sopenharmony_ci * <mattias.ellert@tsl.uu.se>).
69141cc406Sopenharmony_ci *
70141cc406Sopenharmony_ci * Revision 1.10  2004/10/06 15:59:40  hmg-guest
71141cc406Sopenharmony_ci * Don't eject medium twice after each page.
72141cc406Sopenharmony_ci *
73141cc406Sopenharmony_ci * Revision 1.9  2004/06/20 00:34:10  ellert-guest
74141cc406Sopenharmony_ci * Missed one...
75141cc406Sopenharmony_ci *
76141cc406Sopenharmony_ci * Revision 1.8  2004/05/29 10:27:47  hmg-guest
77141cc406Sopenharmony_ci * Fixed the fix of the sanei_thread fix (from Mattias Ellert).
78141cc406Sopenharmony_ci *
79141cc406Sopenharmony_ci * Revision 1.7  2004/05/28 18:52:53  hmg-guest
80141cc406Sopenharmony_ci * Fixed sanei_thread fix (bug #300634, by Mattias Ellert).
81141cc406Sopenharmony_ci *
82141cc406Sopenharmony_ci * Revision 1.6  2004/05/23 17:28:56  hmg-guest
83141cc406Sopenharmony_ci * Use sanei_thread instead of fork() in the unmaintained backends.
84141cc406Sopenharmony_ci * Patches from Mattias Ellert (bugs: 300635, 300634, 300633, 300629).
85141cc406Sopenharmony_ci *
86141cc406Sopenharmony_ci * Revision 1.5  2003/12/27 17:48:38  hmg-guest
87141cc406Sopenharmony_ci * Silenced some compilation warnings.
88141cc406Sopenharmony_ci *
89141cc406Sopenharmony_ci * Revision 1.4  2001/05/31 18:01:39  hmg
90141cc406Sopenharmony_ci * Fixed config_line[len-1] bug which could generate an access
91141cc406Sopenharmony_ci * violation if len==0.
92141cc406Sopenharmony_ci * Henning Meier-Geinitz <henning@meier-geinitz.de>
93141cc406Sopenharmony_ci *
94141cc406Sopenharmony_ci * Revision 1.3  2000/08/12 15:09:38  pere
95141cc406Sopenharmony_ci * Merge devel (v1.0.3) into head branch.
96141cc406Sopenharmony_ci *
97141cc406Sopenharmony_ci * Revision 1.1.2.6  2000/07/30 11:16:06  hmg
98141cc406Sopenharmony_ci * 2000-07-30  Henning Meier-Geinitz <hmg@gmx.de>
99141cc406Sopenharmony_ci *
100141cc406Sopenharmony_ci * 	* backend/mustek.*: Update to Mustek backend 1.0-95. Changed from
101141cc406Sopenharmony_ci * 	  wait() to waitpid() and removed unused code.
102141cc406Sopenharmony_ci * 	* configure configure.in backend/m3096g.c backend/sp15c.c: Reverted
103141cc406Sopenharmony_ci * 	  the V_REV patch. V_REV should not be used in backends.
104141cc406Sopenharmony_ci *
105141cc406Sopenharmony_ci * Revision 1.1.2.5  2000/07/29 21:38:13  hmg
106141cc406Sopenharmony_ci * 2000-07-29  Henning Meier-Geinitz <hmg@gmx.de>
107141cc406Sopenharmony_ci *
108141cc406Sopenharmony_ci * 	* backend/sp15.c backend/m3096g.c: Replace fgets with
109141cc406Sopenharmony_ci * 	  sanei_config_read, return V_REV as part of version_code string
110141cc406Sopenharmony_ci * 	  (patch from Randolph Bentson).
111141cc406Sopenharmony_ci *
112141cc406Sopenharmony_ci * Revision 1.1.2.4  2000/07/25 21:47:46  hmg
113141cc406Sopenharmony_ci * 2000-07-25  Henning Meier-Geinitz <hmg@gmx.de>
114141cc406Sopenharmony_ci *
115141cc406Sopenharmony_ci * 	* backend/snapscan.c: Use DBG(0, ...) instead of fprintf (stderr, ...).
116141cc406Sopenharmony_ci * 	* backend/abaton.c backend/agfafocus.c backend/apple.c backend/dc210.c
117141cc406Sopenharmony_ci *  	  backend/dll.c backend/dmc.c backend/microtek2.c backend/pint.c
118141cc406Sopenharmony_ci * 	  backend/qcam.c backend/ricoh.c backend/s9036.c backend/snapscan.c
119141cc406Sopenharmony_ci * 	  backend/tamarack.c: Use sanei_config_read instead of fgets.
120141cc406Sopenharmony_ci * 	* backend/dc210.c backend/microtek.c backend/pnm.c: Added
121141cc406Sopenharmony_ci * 	  #include "../include/sane/config.h".
122141cc406Sopenharmony_ci * 	* backend/dc25.c backend/m3096.c  backend/sp15.c
123141cc406Sopenharmony_ci *  	  backend/st400.c: Moved #include "../include/sane/config.h" to the beginning.
124141cc406Sopenharmony_ci * 	* AUTHORS: Changed agfa to agfafocus.
125141cc406Sopenharmony_ci *
126141cc406Sopenharmony_ci * Revision 1.1.2.3  2000/03/14 17:47:12  abel
127141cc406Sopenharmony_ci * new version of the Sharp backend added.
128141cc406Sopenharmony_ci *
129141cc406Sopenharmony_ci * Revision 1.1.2.2  2000/01/26 03:51:48  pere
130141cc406Sopenharmony_ci * Updated backends sp15c (v1.12) and m3096g (v1.11).
131141cc406Sopenharmony_ci *
132141cc406Sopenharmony_ci * Revision 1.12  2000/01/25 16:23:13  bentson
133141cc406Sopenharmony_ci * tab expansion; add one debug message
134141cc406Sopenharmony_ci *
135141cc406Sopenharmony_ci * Revision 1.11  2000/01/05 05:21:37  bentson
136141cc406Sopenharmony_ci * indent to barfable GNU style
137141cc406Sopenharmony_ci *
138141cc406Sopenharmony_ci * Revision 1.10  1999/12/06 17:36:55  bentson
139141cc406Sopenharmony_ci * show default value for scan size at the start
140141cc406Sopenharmony_ci *
141141cc406Sopenharmony_ci * Revision 1.9  1999/12/04 00:30:35  bentson
142141cc406Sopenharmony_ci * fold in 1.8.1.x versions
143141cc406Sopenharmony_ci *
144141cc406Sopenharmony_ci * Revision 1.8.1.2  1999/12/04 00:19:43  bentson
145141cc406Sopenharmony_ci * bunch of changes to complete MEDIA CHECK use
146141cc406Sopenharmony_ci *
147141cc406Sopenharmony_ci * Revision 1.8.1.1  1999/12/03 20:44:56  bentson
148141cc406Sopenharmony_ci * trial changes to use MEDIA CHECK command
149141cc406Sopenharmony_ci *
150141cc406Sopenharmony_ci * Revision 1.8  1999/12/03 18:30:56  bentson
151141cc406Sopenharmony_ci * cosmetic changes
152141cc406Sopenharmony_ci *
153141cc406Sopenharmony_ci * Revision 1.7  1999/11/24 20:09:25  bentson
154141cc406Sopenharmony_ci * fold in 1.6.1.x changes
155141cc406Sopenharmony_ci *
156141cc406Sopenharmony_ci * Revision 1.6.1.3  1999/11/24 15:56:48  bentson
157141cc406Sopenharmony_ci * remove some debugging; final :-) fix to option constraint processing
158141cc406Sopenharmony_ci *
159141cc406Sopenharmony_ci * Revision 1.6.1.2  1999/11/24 15:37:42  bentson
160141cc406Sopenharmony_ci * more constraint debugging
161141cc406Sopenharmony_ci *
162141cc406Sopenharmony_ci * Revision 1.6.1.1  1999/11/24 14:35:24  bentson
163141cc406Sopenharmony_ci * fix some of the constraint handling
164141cc406Sopenharmony_ci *
165141cc406Sopenharmony_ci * Revision 1.6  1999/11/23 18:48:27  bentson
166141cc406Sopenharmony_ci * add constraint checking and enforcement
167141cc406Sopenharmony_ci *
168141cc406Sopenharmony_ci * Revision 1.5  1999/11/23 08:26:03  bentson
169141cc406Sopenharmony_ci * basic color seems to work
170141cc406Sopenharmony_ci *
171141cc406Sopenharmony_ci * Revision 1.4  1999/11/23 06:41:26  bentson
172141cc406Sopenharmony_ci * 4-bit Grayscale works; now working on color
173141cc406Sopenharmony_ci *
174141cc406Sopenharmony_ci * Revision 1.3  1999/11/22 18:15:07  bentson
175141cc406Sopenharmony_ci * more work on color support
176141cc406Sopenharmony_ci *
177141cc406Sopenharmony_ci * Revision 1.2  1999/11/19 17:30:54  bentson
178141cc406Sopenharmony_ci * enhance control (works with xscanimage)
179141cc406Sopenharmony_ci *
180141cc406Sopenharmony_ci * Revision 1.1  1999/11/19 15:09:08  bentson
181141cc406Sopenharmony_ci * cribbed from m3096g
182141cc406Sopenharmony_ci *
183141cc406Sopenharmony_ci */
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci/* SANE-FLOW-DIAGRAM
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ci   - sane_init() : initialize backend, attach scanners
188141cc406Sopenharmony_ci   . - sane_get_devices() : query list of scanner-devices
189141cc406Sopenharmony_ci   . - sane_open() : open a particular scanner-device
190141cc406Sopenharmony_ci   . . - sane_set_io_mode : set blocking-mode
191141cc406Sopenharmony_ci   . . - sane_get_select_fd : get scanner-fd
192141cc406Sopenharmony_ci   . . - sane_get_option_descriptor() : get option information
193141cc406Sopenharmony_ci   . . - sane_control_option() : change option values
194141cc406Sopenharmony_ci   . .
195141cc406Sopenharmony_ci   . . - sane_start() : start image acquisition
196141cc406Sopenharmony_ci   . .   - sane_get_parameters() : returns actual scan-parameters
197141cc406Sopenharmony_ci   . .   - sane_read() : read image-data (from pipe)
198141cc406Sopenharmony_ci   . .
199141cc406Sopenharmony_ci   . . - sane_cancel() : cancel operation
200141cc406Sopenharmony_ci   . - sane_close() : close opened scanner-device
201141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend
202141cc406Sopenharmony_ci */
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci#include "../include/sane/config.h"
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci#include <errno.h>
209141cc406Sopenharmony_ci#include <fcntl.h>
210141cc406Sopenharmony_ci#include <limits.h>
211141cc406Sopenharmony_ci#include <signal.h>
212141cc406Sopenharmony_ci#include <stdio.h>
213141cc406Sopenharmony_ci#include <stdlib.h>
214141cc406Sopenharmony_ci#include <string.h>
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci#include <sys/types.h>
217141cc406Sopenharmony_ci#include <unistd.h>
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
220141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
221141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
222141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
223141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci#include "sp15c-scsi.h"
226141cc406Sopenharmony_ci#include "sp15c.h"
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_cistatic const char negativeStr[] = "Negative";
231141cc406Sopenharmony_cistatic const char positiveStr[] = "Positive";
232141cc406Sopenharmony_cistatic SANE_String_Const type_list[] =
233141cc406Sopenharmony_ci{positiveStr, negativeStr, 0};
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_cistatic SANE_String_Const source_list[] =
236141cc406Sopenharmony_ci{"ADF", "FB", NULL};
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_cistatic const SANE_Int resolution_list[] =
239141cc406Sopenharmony_ci{11, 0, 60, 75, 80, 100, 120, 150, 200, 240, 300, 600};
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_cistatic const SANE_Int x_res_list[] =
242141cc406Sopenharmony_ci{11, 0, 60, 75, 80, 100, 120, 150, 200, 240, 300, 600};
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_cistatic const SANE_Int y_res_list[] =
245141cc406Sopenharmony_ci{11, 0, 60, 75, 80, 100, 120, 150, 200, 240, 300, 600};
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_cistatic const char lineStr[] = SANE_VALUE_SCAN_MODE_LINEART;
248141cc406Sopenharmony_cistatic const char halfStr[] = SANE_VALUE_SCAN_MODE_HALFTONE;
249141cc406Sopenharmony_cistatic const char gray4Str[] = "4-bit Gray";
250141cc406Sopenharmony_cistatic const char gray8Str[] = "8-bit Gray";
251141cc406Sopenharmony_cistatic const char colorStr[] = SANE_VALUE_SCAN_MODE_COLOR;
252141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list[] =
253141cc406Sopenharmony_ci{lineStr, halfStr, gray4Str, gray8Str, colorStr, NULL};
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci/* how do the following work? */
256141cc406Sopenharmony_cistatic const SANE_Range brightness_range =
257141cc406Sopenharmony_ci{0, 255, 32};
258141cc406Sopenharmony_cistatic const SANE_Range threshold_range =
259141cc406Sopenharmony_ci{0, 255, 4};
260141cc406Sopenharmony_cistatic const SANE_Range x_range =
261141cc406Sopenharmony_ci{0, SANE_FIX (216), 1};
262141cc406Sopenharmony_cistatic const SANE_Range y_range_fb =
263141cc406Sopenharmony_ci{0, SANE_FIX (295), 1};
264141cc406Sopenharmony_cistatic const SANE_Range y_range_adf =
265141cc406Sopenharmony_ci{0, SANE_FIX (356), 1};
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci/* ################# externally visible routines ################{ */
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ciSANE_Status                     /* looks like frontend ignores results */
271141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
272141cc406Sopenharmony_ci{
273141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
274141cc406Sopenharmony_ci  size_t len;
275141cc406Sopenharmony_ci  FILE *fp;
276141cc406Sopenharmony_ci  (void) authorize; /* silence compilation warnings */
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci  DBG_INIT ();
279141cc406Sopenharmony_ci  DBG (10, "sane_init\n");
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci  sanei_thread_init ();
282141cc406Sopenharmony_ci
283141cc406Sopenharmony_ci  if (version_code)
284141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
285141cc406Sopenharmony_ci  fp = sanei_config_open (SP15C_CONFIG_FILE);
286141cc406Sopenharmony_ci  if (!fp)
287141cc406Sopenharmony_ci    {
288141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);       /* no config-file: /dev/scanner */
289141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
290141cc406Sopenharmony_ci    }
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
293141cc406Sopenharmony_ci    {
294141cc406Sopenharmony_ci      if (dev_name[0] == '#')
295141cc406Sopenharmony_ci        continue;
296141cc406Sopenharmony_ci      len = strlen (dev_name);
297141cc406Sopenharmony_ci      if (!len)
298141cc406Sopenharmony_ci        continue;
299141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
300141cc406Sopenharmony_ci    }
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci  fclose (fp);
303141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
304141cc406Sopenharmony_ci}                               /* sane_init */
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ciSANE_Status
308141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
309141cc406Sopenharmony_ci{
310141cc406Sopenharmony_ci  struct sp15c *dev;
311141cc406Sopenharmony_ci  int i;
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci  (void) local_only; /* silence compilation warnings */
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  DBG (10, "sane_get_devices\n");
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci  if (devlist)
318141cc406Sopenharmony_ci    free (devlist);
319141cc406Sopenharmony_ci  devlist = calloc (num_devices + 1, sizeof (devlist[0]));
320141cc406Sopenharmony_ci  if (!devlist)
321141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci  for (dev = first_dev, i = 0; i < num_devices; dev = dev->next)
324141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
325141cc406Sopenharmony_ci  devlist[i++] = 0;
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci  *device_list = devlist;
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
330141cc406Sopenharmony_ci}                               /* sane_get_devices */
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ciSANE_Status
334141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle)
335141cc406Sopenharmony_ci{
336141cc406Sopenharmony_ci  struct sp15c *dev = first_dev;
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci  (void) name; /* silence compilation warnings */
339141cc406Sopenharmony_ci  /* Strange, name is not used? */
340141cc406Sopenharmony_ci
341141cc406Sopenharmony_ci  DBG (10, "sane_open\n");
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci  if (!dev)
344141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  init_options (dev);
347141cc406Sopenharmony_ci  *handle = dev;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci  dev->use_adf = SANE_TRUE;
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci  dev->x_res = 200;
352141cc406Sopenharmony_ci  dev->y_res = 200;
353141cc406Sopenharmony_ci  dev->tl_x = 0;
354141cc406Sopenharmony_ci  dev->tl_y = 0;
355141cc406Sopenharmony_ci  dev->br_x = 1200 * 17 / 2;
356141cc406Sopenharmony_ci  dev->br_y = 1200 * 11;
357141cc406Sopenharmony_ci  dev->brightness = 128;
358141cc406Sopenharmony_ci  dev->threshold = 128;
359141cc406Sopenharmony_ci  dev->contrast = 128;
360141cc406Sopenharmony_ci  dev->composition = WD_comp_LA;
361141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].cap = SANE_CAP_INACTIVE;
362141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_DETECT
363141cc406Sopenharmony_ci    | SANE_CAP_SOFT_SELECT;
364141cc406Sopenharmony_ci  dev->bitsperpixel = 1;
365141cc406Sopenharmony_ci  dev->halftone = 0;
366141cc406Sopenharmony_ci  dev->rif = 0;
367141cc406Sopenharmony_ci  dev->bitorder = 0;
368141cc406Sopenharmony_ci  dev->compress_type = 0;
369141cc406Sopenharmony_ci  dev->compress_arg = 0;
370141cc406Sopenharmony_ci  dev->vendor_id_code = 0;
371141cc406Sopenharmony_ci  dev->outline = 0;
372141cc406Sopenharmony_ci  dev->emphasis = 0;
373141cc406Sopenharmony_ci  dev->auto_sep = 0;
374141cc406Sopenharmony_ci  dev->mirroring = 0;
375141cc406Sopenharmony_ci  dev->var_rate_dyn_thresh = 0;
376141cc406Sopenharmony_ci  dev->white_level_follow = 0;
377141cc406Sopenharmony_ci  dev->paper_size = 0x87;
378141cc406Sopenharmony_ci  dev->paper_width_X = 1200 * 17 / 2;
379141cc406Sopenharmony_ci  dev->paper_length_Y = 1200 * 11;
380141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint.range = &y_range_adf;
381141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint.range = &y_range_adf;
382141cc406Sopenharmony_ci  adjust_width (dev, 0);
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
385141cc406Sopenharmony_ci}                               /* sane_open */
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ciSANE_Status
389141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking)
390141cc406Sopenharmony_ci{
391141cc406Sopenharmony_ci  (void) h;
392141cc406Sopenharmony_ci  (void) non_blocking; /* silence compilation warnings */
393141cc406Sopenharmony_ci
394141cc406Sopenharmony_ci  DBG (10, "sane_set_io_mode\n");
395141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
396141cc406Sopenharmony_ci}                               /* sane_set_io_mode */
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ciSANE_Status
400141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fdp)
401141cc406Sopenharmony_ci{
402141cc406Sopenharmony_ci  (void) h;
403141cc406Sopenharmony_ci  (void) fdp; /* silence compilation warnings */
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci  DBG (10, "sane_get_select_fd\n");
406141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
407141cc406Sopenharmony_ci}                               /* sane_get_select_fd */
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
411141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
412141cc406Sopenharmony_ci{
413141cc406Sopenharmony_ci  struct sp15c *scanner = handle;
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  DBG (10, "sane_get_option_descriptor: \"%s\"\n",
416141cc406Sopenharmony_ci       scanner->opt[option].name);
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
419141cc406Sopenharmony_ci    return 0;
420141cc406Sopenharmony_ci  return &scanner->opt[option];
421141cc406Sopenharmony_ci}                               /* sane_get_option_descriptor */
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ciSANE_Status
425141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
426141cc406Sopenharmony_ci                     SANE_Action action, void *val,
427141cc406Sopenharmony_ci                     SANE_Int * info)
428141cc406Sopenharmony_ci{
429141cc406Sopenharmony_ci  struct sp15c *scanner = handle;
430141cc406Sopenharmony_ci  SANE_Status status;
431141cc406Sopenharmony_ci  SANE_Word cap;
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci  if (info)
434141cc406Sopenharmony_ci    *info = 0;
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci  if (scanner->scanning == SANE_TRUE)
437141cc406Sopenharmony_ci    {
438141cc406Sopenharmony_ci      DBG (5, "sane_control_option: device busy\n");
439141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
440141cc406Sopenharmony_ci    }
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
443141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci  cap = scanner->opt[option].cap;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
448141cc406Sopenharmony_ci    {
449141cc406Sopenharmony_ci      DBG (10, "sane_control_option: get value \"%s\"\n",
450141cc406Sopenharmony_ci           scanner->opt[option].name);
451141cc406Sopenharmony_ci      DBG (11, "\tcap = %d\n", cap);
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_ACTIVE (cap))
454141cc406Sopenharmony_ci        {
455141cc406Sopenharmony_ci          DBG (10, "\tinactive\n");
456141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
457141cc406Sopenharmony_ci        }
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci      switch (option)
460141cc406Sopenharmony_ci        {
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci        case OPT_NUM_OPTS:
463141cc406Sopenharmony_ci          *(SANE_Word *) val = NUM_OPTIONS;
464141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci        case OPT_SOURCE:
467141cc406Sopenharmony_ci          if (scanner->use_adf == SANE_TRUE)
468141cc406Sopenharmony_ci            {
469141cc406Sopenharmony_ci              strcpy (val, "ADF");
470141cc406Sopenharmony_ci            }
471141cc406Sopenharmony_ci          else
472141cc406Sopenharmony_ci            {
473141cc406Sopenharmony_ci              strcpy (val, "FB");
474141cc406Sopenharmony_ci            }
475141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
476141cc406Sopenharmony_ci
477141cc406Sopenharmony_ci        case OPT_MODE:
478141cc406Sopenharmony_ci          switch (scanner->composition)
479141cc406Sopenharmony_ci            {
480141cc406Sopenharmony_ci            case WD_comp_LA:
481141cc406Sopenharmony_ci              strcpy (val, lineStr);
482141cc406Sopenharmony_ci              break;
483141cc406Sopenharmony_ci            case WD_comp_HT:
484141cc406Sopenharmony_ci              strcpy (val, halfStr);
485141cc406Sopenharmony_ci              break;
486141cc406Sopenharmony_ci            case WD_comp_G4:
487141cc406Sopenharmony_ci              strcpy (val, gray4Str);
488141cc406Sopenharmony_ci              break;
489141cc406Sopenharmony_ci            case WD_comp_G8:
490141cc406Sopenharmony_ci              strcpy (val, gray8Str);
491141cc406Sopenharmony_ci              break;
492141cc406Sopenharmony_ci            case WD_comp_MC:
493141cc406Sopenharmony_ci              strcpy (val, colorStr);
494141cc406Sopenharmony_ci              break;
495141cc406Sopenharmony_ci            default:
496141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
497141cc406Sopenharmony_ci            }
498141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci        case OPT_TYPE:
501141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci        case OPT_PRESCAN:
504141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci        case OPT_X_RES:
507141cc406Sopenharmony_ci          *(SANE_Word *) val = scanner->x_res;
508141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci        case OPT_Y_RES:
511141cc406Sopenharmony_ci          *(SANE_Word *) val = scanner->y_res;
512141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci        case OPT_PREVIEW_RES:
515141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci        case OPT_TL_X:
518141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tl_x));
519141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci        case OPT_TL_Y:
522141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tl_y));
523141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci        case OPT_BR_X:
526141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->br_x));
527141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci        case OPT_BR_Y:
530141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->br_y));
531141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci        case OPT_AVERAGING:
534141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci        case OPT_BRIGHTNESS:
537141cc406Sopenharmony_ci          *(SANE_Word *) val = scanner->brightness;
538141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci        case OPT_THRESHOLD:
541141cc406Sopenharmony_ci          *(SANE_Word *) val = scanner->threshold;
542141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci        case OPT_PREVIEW:
545141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
546141cc406Sopenharmony_ci
547141cc406Sopenharmony_ci        }
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci    }
550141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
551141cc406Sopenharmony_ci    {
552141cc406Sopenharmony_ci      DBG (10, "sane_control_option: set value \"%s\"\n",
553141cc406Sopenharmony_ci           scanner->opt[option].name);
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_ACTIVE (cap))
556141cc406Sopenharmony_ci        {
557141cc406Sopenharmony_ci          DBG (10, "\tinactive\n");
558141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
559141cc406Sopenharmony_ci        }
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
562141cc406Sopenharmony_ci        {
563141cc406Sopenharmony_ci          DBG (10, "\tnot settable\n");
564141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
565141cc406Sopenharmony_ci        }
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci      status = sanei_constrain_value (scanner->opt + option, val, info);
568141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
569141cc406Sopenharmony_ci        {
570141cc406Sopenharmony_ci          DBG (10, "\tbad value\n");
571141cc406Sopenharmony_ci          return status;
572141cc406Sopenharmony_ci        }
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci      switch (option)
575141cc406Sopenharmony_ci        {
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci        case OPT_NUM_OPTS:
578141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci        case OPT_SOURCE:
581141cc406Sopenharmony_ci          if (strcmp (val, "ADF") == 0)
582141cc406Sopenharmony_ci            {
583141cc406Sopenharmony_ci              if (scanner->use_adf == SANE_TRUE)
584141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
585141cc406Sopenharmony_ci              scanner->use_adf = SANE_TRUE;
586141cc406Sopenharmony_ci              scanner->opt[OPT_TL_Y].constraint.range = &y_range_adf;
587141cc406Sopenharmony_ci              scanner->opt[OPT_BR_Y].constraint.range = &y_range_adf;
588141cc406Sopenharmony_ci              apply_constraints (scanner, OPT_TL_Y, &scanner->tl_y, info);
589141cc406Sopenharmony_ci              apply_constraints (scanner, OPT_BR_Y, &scanner->br_y, info);
590141cc406Sopenharmony_ci            }
591141cc406Sopenharmony_ci          else if (strcmp (val, "FB") == 0)
592141cc406Sopenharmony_ci            {
593141cc406Sopenharmony_ci              if (scanner->use_adf == SANE_FALSE)
594141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
595141cc406Sopenharmony_ci              scanner->use_adf = SANE_FALSE;
596141cc406Sopenharmony_ci              scanner->opt[OPT_TL_Y].constraint.range = &y_range_fb;
597141cc406Sopenharmony_ci              scanner->opt[OPT_BR_Y].constraint.range = &y_range_fb;
598141cc406Sopenharmony_ci              apply_constraints (scanner, OPT_TL_Y, &scanner->tl_y, info);
599141cc406Sopenharmony_ci              apply_constraints (scanner, OPT_BR_Y, &scanner->br_y, info);
600141cc406Sopenharmony_ci            }
601141cc406Sopenharmony_ci          else
602141cc406Sopenharmony_ci            {
603141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
604141cc406Sopenharmony_ci            }
605141cc406Sopenharmony_ci          if (info)
606141cc406Sopenharmony_ci            {
607141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
608141cc406Sopenharmony_ci            }
609141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci        case OPT_MODE:
612141cc406Sopenharmony_ci          if (strcmp (val, lineStr) == 0)
613141cc406Sopenharmony_ci            {
614141cc406Sopenharmony_ci              if (scanner->composition == WD_comp_LA)
615141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
616141cc406Sopenharmony_ci              scanner->composition = WD_comp_LA;
617141cc406Sopenharmony_ci              scanner->bitsperpixel = 1;
618141cc406Sopenharmony_ci              scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_INACTIVE;
619141cc406Sopenharmony_ci              scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_DETECT
620141cc406Sopenharmony_ci                | SANE_CAP_SOFT_SELECT;
621141cc406Sopenharmony_ci              scanner->vendor_id_code = 0;
622141cc406Sopenharmony_ci            }
623141cc406Sopenharmony_ci          else if (strcmp (val, halfStr) == 0)
624141cc406Sopenharmony_ci            {
625141cc406Sopenharmony_ci              if (scanner->composition == WD_comp_HT)
626141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
627141cc406Sopenharmony_ci              scanner->composition = WD_comp_HT;
628141cc406Sopenharmony_ci              scanner->bitsperpixel = 1;
629141cc406Sopenharmony_ci              scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_DETECT
630141cc406Sopenharmony_ci                | SANE_CAP_SOFT_SELECT;
631141cc406Sopenharmony_ci              scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_INACTIVE;
632141cc406Sopenharmony_ci              scanner->vendor_id_code = 0;
633141cc406Sopenharmony_ci            }
634141cc406Sopenharmony_ci          else if (strcmp (val, gray4Str) == 0)
635141cc406Sopenharmony_ci            {
636141cc406Sopenharmony_ci              if (scanner->composition == WD_comp_G4)
637141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
638141cc406Sopenharmony_ci              scanner->composition = WD_comp_G4;
639141cc406Sopenharmony_ci              scanner->bitsperpixel = 4;
640141cc406Sopenharmony_ci              scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_INACTIVE;
641141cc406Sopenharmony_ci              scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_INACTIVE;
642141cc406Sopenharmony_ci              scanner->vendor_id_code = 0;
643141cc406Sopenharmony_ci            }
644141cc406Sopenharmony_ci          else if (strcmp (val, gray8Str) == 0)
645141cc406Sopenharmony_ci            {
646141cc406Sopenharmony_ci              if (scanner->composition == WD_comp_G8)
647141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
648141cc406Sopenharmony_ci              scanner->composition = WD_comp_G8;
649141cc406Sopenharmony_ci              scanner->bitsperpixel = 8;
650141cc406Sopenharmony_ci              scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_INACTIVE;
651141cc406Sopenharmony_ci              scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_INACTIVE;
652141cc406Sopenharmony_ci              scanner->vendor_id_code = 0;
653141cc406Sopenharmony_ci            }
654141cc406Sopenharmony_ci          else if (strcmp (val, colorStr) == 0)
655141cc406Sopenharmony_ci            {
656141cc406Sopenharmony_ci              if (scanner->composition == WD_comp_MC)
657141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
658141cc406Sopenharmony_ci              scanner->composition = WD_comp_MC;
659141cc406Sopenharmony_ci              scanner->bitsperpixel = 8;
660141cc406Sopenharmony_ci              scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_INACTIVE;
661141cc406Sopenharmony_ci              scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_INACTIVE;
662141cc406Sopenharmony_ci              scanner->vendor_id_code = 0xff;
663141cc406Sopenharmony_ci            }
664141cc406Sopenharmony_ci          else
665141cc406Sopenharmony_ci            {
666141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
667141cc406Sopenharmony_ci            }
668141cc406Sopenharmony_ci          if (info)
669141cc406Sopenharmony_ci            {
670141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
671141cc406Sopenharmony_ci            }
672141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci        case OPT_TYPE:
675141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci        case OPT_PRESCAN:
678141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci        case OPT_X_RES:
681141cc406Sopenharmony_ci          scanner->x_res = (*(SANE_Word *) val);
682141cc406Sopenharmony_ci          adjust_width (scanner, info);
683141cc406Sopenharmony_ci          if (info)
684141cc406Sopenharmony_ci            {
685141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS;
686141cc406Sopenharmony_ci            }
687141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci        case OPT_Y_RES:
690141cc406Sopenharmony_ci          scanner->y_res = (*(SANE_Word *) val);
691141cc406Sopenharmony_ci          if (info)
692141cc406Sopenharmony_ci            {
693141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS;
694141cc406Sopenharmony_ci            }
695141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci        case OPT_PREVIEW_RES:
698141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci        case OPT_TL_X:
701141cc406Sopenharmony_ci          scanner->tl_x = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
702141cc406Sopenharmony_ci          adjust_width (scanner, info);
703141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tl_x));
704141cc406Sopenharmony_ci          if (info)
705141cc406Sopenharmony_ci            {
706141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_INEXACT;
707141cc406Sopenharmony_ci            }
708141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci        case OPT_TL_Y:
711141cc406Sopenharmony_ci          scanner->tl_y = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
712141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tl_y));
713141cc406Sopenharmony_ci          if (info)
714141cc406Sopenharmony_ci            {
715141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_INEXACT;
716141cc406Sopenharmony_ci            }
717141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
718141cc406Sopenharmony_ci
719141cc406Sopenharmony_ci        case OPT_BR_X:
720141cc406Sopenharmony_ci          scanner->br_x = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
721141cc406Sopenharmony_ci          adjust_width (scanner, info);
722141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->br_x));
723141cc406Sopenharmony_ci          if (info)
724141cc406Sopenharmony_ci            {
725141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_INEXACT;
726141cc406Sopenharmony_ci            }
727141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ci        case OPT_BR_Y:
730141cc406Sopenharmony_ci          scanner->br_y = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
731141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->br_y));
732141cc406Sopenharmony_ci          if (info)
733141cc406Sopenharmony_ci            {
734141cc406Sopenharmony_ci              *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_INEXACT;
735141cc406Sopenharmony_ci            }
736141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci        case OPT_AVERAGING:
739141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci        case OPT_BRIGHTNESS:
742141cc406Sopenharmony_ci          scanner->brightness = *(SANE_Word *) val;
743141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci        case OPT_THRESHOLD:
746141cc406Sopenharmony_ci          scanner->threshold = *(SANE_Word *) val;
747141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci        }                       /* switch */
750141cc406Sopenharmony_ci    }                           /* else */
751141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
752141cc406Sopenharmony_ci}                               /* sane_control_option */
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ciSANE_Status
756141cc406Sopenharmony_cisane_start (SANE_Handle handle)
757141cc406Sopenharmony_ci{
758141cc406Sopenharmony_ci  struct sp15c *scanner = handle;
759141cc406Sopenharmony_ci  int fds[2];
760141cc406Sopenharmony_ci  int ret;
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci  DBG (10, "sane_start\n");
763141cc406Sopenharmony_ci  if (scanner->scanning == SANE_TRUE)
764141cc406Sopenharmony_ci    {
765141cc406Sopenharmony_ci      DBG (5, "sane_start: device busy\n");
766141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
767141cc406Sopenharmony_ci    }
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci  if (scanner->sfd < 0)
770141cc406Sopenharmony_ci    {                           /* first call */
771141cc406Sopenharmony_ci      if (sanei_scsi_open (scanner->sane.name, &(scanner->sfd),
772141cc406Sopenharmony_ci                           sense_handler, 0) != SANE_STATUS_GOOD)
773141cc406Sopenharmony_ci        {
774141cc406Sopenharmony_ci          DBG (1, "sane_start: open of %s failed:\n",
775141cc406Sopenharmony_ci               scanner->sane.name);
776141cc406Sopenharmony_ci          return SANE_STATUS_INVAL;
777141cc406Sopenharmony_ci        }
778141cc406Sopenharmony_ci    }
779141cc406Sopenharmony_ci  scanner->scanning = SANE_TRUE;
780141cc406Sopenharmony_ci
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci  if ((ret = sp15c_check_values (scanner)) != 0)
783141cc406Sopenharmony_ci    {                           /* Verify values */
784141cc406Sopenharmony_ci      DBG (1, "sane_start: ERROR: invalid scan-values\n");
785141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
786141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
787141cc406Sopenharmony_ci      scanner->sfd = -1;
788141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
789141cc406Sopenharmony_ci    }
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ci  if ((ret = sp15c_grab_scanner (scanner)))
792141cc406Sopenharmony_ci    {
793141cc406Sopenharmony_ci      DBG (5, "sane_start: unable to reserve scanner\n");
794141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
795141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
796141cc406Sopenharmony_ci      scanner->sfd = -1;
797141cc406Sopenharmony_ci      return ret;
798141cc406Sopenharmony_ci    }
799141cc406Sopenharmony_ci
800141cc406Sopenharmony_ci  if ((ret = sp15c_set_window_param (scanner, 0)))
801141cc406Sopenharmony_ci    {
802141cc406Sopenharmony_ci      DBG (5, "sane_start: ERROR: failed to set window\n");
803141cc406Sopenharmony_ci      sp15c_free_scanner (scanner);
804141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
805141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
806141cc406Sopenharmony_ci      scanner->sfd = -1;
807141cc406Sopenharmony_ci      return ret;
808141cc406Sopenharmony_ci    }
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  /* Since the SET WINDOW can specify the use of the ADF, and since the
811141cc406Sopenharmony_ci     ScanPartner 15C automatically pre-loads sheets from the ADF, it
812141cc406Sopenharmony_ci     is only necessary to see if any paper is available.  The OEM
813141cc406Sopenharmony_ci     Manual offers the OBJECT POSITION command, but it causes the
814141cc406Sopenharmony_ci     carrier unit into a "homing" cycle.  The undocumented MEDIA CHECK
815141cc406Sopenharmony_ci     command avoids the "homing" cycle.  (Note the SET WINDOW command
816141cc406Sopenharmony_ci     had to use the color scanning vendor unique parameters, regardless
817141cc406Sopenharmony_ci     of scanning mode, so that it could invoke the ADF.) */
818141cc406Sopenharmony_ci  if (scanner->use_adf == SANE_TRUE
819141cc406Sopenharmony_ci      && (ret = sp15c_media_check (scanner)))
820141cc406Sopenharmony_ci    {
821141cc406Sopenharmony_ci      DBG (5, "sane_start: WARNING: ADF empty\n");
822141cc406Sopenharmony_ci      sp15c_free_scanner (scanner);
823141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
824141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
825141cc406Sopenharmony_ci      scanner->sfd = -1;
826141cc406Sopenharmony_ci      return ret;
827141cc406Sopenharmony_ci    }
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  swap_res (scanner);
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  DBG (10, "\tbytes per line = %d\n", bytes_per_line (scanner));
832141cc406Sopenharmony_ci  DBG (10, "\tpixels_per_line = %d\n", pixels_per_line (scanner));
833141cc406Sopenharmony_ci  DBG (10, "\tlines = %d\n", lines_per_scan (scanner));
834141cc406Sopenharmony_ci  DBG (10, "\tbrightness (halftone) = %d\n", scanner->brightness);
835141cc406Sopenharmony_ci  DBG (10, "\tthreshold (line art) = %d\n", scanner->threshold);
836141cc406Sopenharmony_ci
837141cc406Sopenharmony_ci  if (scanner->composition == WD_comp_MC
838141cc406Sopenharmony_ci      && (ret = sp15c_start_scan (scanner)))
839141cc406Sopenharmony_ci    {
840141cc406Sopenharmony_ci      DBG (5, "sane_start: start_scan failed\n");
841141cc406Sopenharmony_ci      sp15c_free_scanner (scanner);
842141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
843141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
844141cc406Sopenharmony_ci      scanner->sfd = -1;
845141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
846141cc406Sopenharmony_ci    }
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci  /* create a pipe, fds[0]=read-fd, fds[1]=write-fd */
849141cc406Sopenharmony_ci  if (pipe (fds) < 0)
850141cc406Sopenharmony_ci    {
851141cc406Sopenharmony_ci      DBG (1, "ERROR: could not create pipe\n");
852141cc406Sopenharmony_ci      swap_res (scanner);
853141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
854141cc406Sopenharmony_ci      sp15c_free_scanner (scanner);
855141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
856141cc406Sopenharmony_ci      scanner->sfd = -1;
857141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
858141cc406Sopenharmony_ci    }
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci  scanner->pipe = fds[0];
861141cc406Sopenharmony_ci  scanner->reader_pipe = fds[1];
862141cc406Sopenharmony_ci  scanner->reader_pid = sanei_thread_begin (reader_process, (void *) scanner);
863141cc406Sopenharmony_ci
864141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
865141cc406Sopenharmony_ci    close (scanner->reader_pipe);
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_ci  DBG (10, "sane_start: ok\n");
868141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
869141cc406Sopenharmony_ci}                               /* sane_start */
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci
872141cc406Sopenharmony_ciSANE_Status
873141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
874141cc406Sopenharmony_ci{
875141cc406Sopenharmony_ci  struct sp15c *scanner = handle;
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters\n");
878141cc406Sopenharmony_ci  if (scanner->composition == WD_comp_MC)
879141cc406Sopenharmony_ci    {
880141cc406Sopenharmony_ci      params->format = SANE_FRAME_RGB;
881141cc406Sopenharmony_ci      params->depth = 8;
882141cc406Sopenharmony_ci    }
883141cc406Sopenharmony_ci  else if (scanner->composition == WD_comp_LA
884141cc406Sopenharmony_ci           || scanner->composition == WD_comp_HT)
885141cc406Sopenharmony_ci    {
886141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
887141cc406Sopenharmony_ci      params->depth = 1;
888141cc406Sopenharmony_ci    }
889141cc406Sopenharmony_ci  else
890141cc406Sopenharmony_ci    {
891141cc406Sopenharmony_ci      params->format = SANE_FRAME_GRAY;
892141cc406Sopenharmony_ci      params->depth = 8;
893141cc406Sopenharmony_ci    }
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci  params->pixels_per_line = pixels_per_line (scanner);
896141cc406Sopenharmony_ci  params->lines = lines_per_scan (scanner);
897141cc406Sopenharmony_ci  params->bytes_per_line = bytes_per_line (scanner);
898141cc406Sopenharmony_ci  params->last_frame = 1;
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci  DBG (10, "\tdepth %d\n", params->depth);
901141cc406Sopenharmony_ci  DBG (10, "\tlines %d\n", params->lines);
902141cc406Sopenharmony_ci  DBG (10, "\tpixels_per_line %d\n", params->pixels_per_line);
903141cc406Sopenharmony_ci  DBG (10, "\tbytes_per_line %d\n", params->bytes_per_line);
904141cc406Sopenharmony_ci/*************************/
905141cc406Sopenharmony_ci  DBG (10, "\tlength %d\n", scanner->br_y - scanner->tl_y);
906141cc406Sopenharmony_ci  DBG (10, "\t(nom.) width %d\n", scanner->br_x - scanner->tl_x);
907141cc406Sopenharmony_ci  DBG (10, "\tx res %d\n", scanner->x_res);
908141cc406Sopenharmony_ci  DBG (10, "\ty res %d\n", scanner->y_res);
909141cc406Sopenharmony_ci/*************************/
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
912141cc406Sopenharmony_ci}                               /* sane_get_parameters */
913141cc406Sopenharmony_ci
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ciSANE_Status
916141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
917141cc406Sopenharmony_ci           SANE_Int max_len, SANE_Int * len)
918141cc406Sopenharmony_ci{
919141cc406Sopenharmony_ci  struct sp15c *scanner = handle;
920141cc406Sopenharmony_ci  ssize_t nread;
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci  DBG (10, "sane_read\n");
923141cc406Sopenharmony_ci  *len = 0;
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci  nread = read (scanner->pipe, buf, max_len);
926141cc406Sopenharmony_ci  DBG (10, "sane_read: read %ld bytes of %ld\n",
927141cc406Sopenharmony_ci       (long) nread, (long) max_len);
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci  if (scanner->scanning == SANE_FALSE)
930141cc406Sopenharmony_ci    {
931141cc406Sopenharmony_ci      /* PREDICATE WAS (!(scanner->scanning))  */
932141cc406Sopenharmony_ci      return do_cancel (scanner);
933141cc406Sopenharmony_ci    }
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci  if (nread < 0)
936141cc406Sopenharmony_ci    {
937141cc406Sopenharmony_ci      if (errno == EAGAIN)
938141cc406Sopenharmony_ci        {
939141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
940141cc406Sopenharmony_ci        }
941141cc406Sopenharmony_ci      else
942141cc406Sopenharmony_ci        {
943141cc406Sopenharmony_ci          do_cancel (scanner);
944141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
945141cc406Sopenharmony_ci        }
946141cc406Sopenharmony_ci    }
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci  *len = nread;
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci  if (nread == 0)
951141cc406Sopenharmony_ci    return do_eof (scanner);    /* close pipe */
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
954141cc406Sopenharmony_ci}                               /* sane_read */
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci
957141cc406Sopenharmony_civoid
958141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
959141cc406Sopenharmony_ci{
960141cc406Sopenharmony_ci  DBG (10, "sane_cancel\n");
961141cc406Sopenharmony_ci  do_cancel ((struct sp15c *) h);
962141cc406Sopenharmony_ci}                               /* sane_cancel */
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_civoid
966141cc406Sopenharmony_cisane_close (SANE_Handle handle)
967141cc406Sopenharmony_ci{
968141cc406Sopenharmony_ci  DBG (10, "sane_close\n");
969141cc406Sopenharmony_ci  if (((struct sp15c *) handle)->scanning == SANE_TRUE)
970141cc406Sopenharmony_ci    do_cancel (handle);
971141cc406Sopenharmony_ci}                               /* sane_close */
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_civoid
975141cc406Sopenharmony_cisane_exit (void)
976141cc406Sopenharmony_ci{
977141cc406Sopenharmony_ci  struct sp15c *dev, *next;
978141cc406Sopenharmony_ci
979141cc406Sopenharmony_ci  DBG (10, "sane_exit\n");
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
982141cc406Sopenharmony_ci    {
983141cc406Sopenharmony_ci      next = dev->next;
984141cc406Sopenharmony_ci      free (dev->devicename);
985141cc406Sopenharmony_ci      free (dev->buffer);
986141cc406Sopenharmony_ci      free (dev);
987141cc406Sopenharmony_ci    }
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci  if (devlist)
990141cc406Sopenharmony_ci    free (devlist);
991141cc406Sopenharmony_ci}                               /* sane_exit */
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci/* }################ internal (support) routines ################{ */
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_cistatic SANE_Status
996141cc406Sopenharmony_ciattach_scanner (const char *devicename, struct sp15c **devp)
997141cc406Sopenharmony_ci{
998141cc406Sopenharmony_ci  struct sp15c *dev;
999141cc406Sopenharmony_ci  int sfd;
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci  DBG (15, "attach_scanner: %s\n", devicename);
1002141cc406Sopenharmony_ci
1003141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
1004141cc406Sopenharmony_ci    {
1005141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
1006141cc406Sopenharmony_ci        {
1007141cc406Sopenharmony_ci          if (devp)
1008141cc406Sopenharmony_ci            {
1009141cc406Sopenharmony_ci              *devp = dev;
1010141cc406Sopenharmony_ci            }
1011141cc406Sopenharmony_ci          DBG (5, "attach_scanner: scanner already attached (is ok)!\n");
1012141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
1013141cc406Sopenharmony_ci        }
1014141cc406Sopenharmony_ci    }
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  DBG (15, "attach_scanner: opening %s\n", devicename);
1017141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, sense_handler, 0) != 0)
1018141cc406Sopenharmony_ci    {
1019141cc406Sopenharmony_ci      DBG (5, "attach_scanner: open failed\n");
1020141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1021141cc406Sopenharmony_ci    }
1022141cc406Sopenharmony_ci
1023141cc406Sopenharmony_ci  if (NULL == (dev = malloc (sizeof (*dev))))
1024141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci  dev->row_bufsize = (sanei_scsi_max_request_size < (64 * 1024))
1027141cc406Sopenharmony_ci    ? sanei_scsi_max_request_size
1028141cc406Sopenharmony_ci    : 64 * 1024;
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  if ((dev->buffer = malloc (dev->row_bufsize)) == NULL)
1031141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
1034141cc406Sopenharmony_ci  dev->sfd = sfd;
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci  if (sp15c_identify_scanner (dev) != 0)
1037141cc406Sopenharmony_ci    {
1038141cc406Sopenharmony_ci      DBG (5, "attach_scanner: scanner-identification failed\n");
1039141cc406Sopenharmony_ci      sanei_scsi_close (dev->sfd);
1040141cc406Sopenharmony_ci      free (dev->buffer);
1041141cc406Sopenharmony_ci      free (dev);
1042141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1043141cc406Sopenharmony_ci    }
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ci#if 0
1046141cc406Sopenharmony_ci  /* Get MUD (via mode_sense), internal info (via get_internal_info), and
1047141cc406Sopenharmony_ci     * initialize values */
1048141cc406Sopenharmony_ci  coolscan_initialize_values (dev);
1049141cc406Sopenharmony_ci#endif
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci  /* Why? */
1052141cc406Sopenharmony_ci  sanei_scsi_close (dev->sfd);
1053141cc406Sopenharmony_ci  dev->sfd = -1;
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
1056141cc406Sopenharmony_ci  dev->sane.vendor = dev->vendor;
1057141cc406Sopenharmony_ci  dev->sane.model = dev->product;
1058141cc406Sopenharmony_ci  dev->sane.type = "flatbed/ADF scanner";
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci  ++num_devices;
1061141cc406Sopenharmony_ci  dev->next = first_dev;
1062141cc406Sopenharmony_ci  first_dev = dev;
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci  if (devp)
1065141cc406Sopenharmony_ci    {
1066141cc406Sopenharmony_ci      *devp = dev;
1067141cc406Sopenharmony_ci    }
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci  DBG (15, "attach_scanner: done\n");
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1072141cc406Sopenharmony_ci}                               /* attach_scanner */
1073141cc406Sopenharmony_ci
1074141cc406Sopenharmony_cistatic SANE_Status
1075141cc406Sopenharmony_ciattach_one (const char *name)
1076141cc406Sopenharmony_ci{
1077141cc406Sopenharmony_ci  return attach_scanner (name, 0);
1078141cc406Sopenharmony_ci}                               /* attach_one */
1079141cc406Sopenharmony_ci
1080141cc406Sopenharmony_cistatic SANE_Status
1081141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char * result, void *arg)
1082141cc406Sopenharmony_ci{
1083141cc406Sopenharmony_ci  (void) scsi_fd;
1084141cc406Sopenharmony_ci  (void) arg; /* silence compilation warnings */
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci  return request_sense_parse (result);
1087141cc406Sopenharmony_ci}                               /* sense_handler */
1088141cc406Sopenharmony_ci
1089141cc406Sopenharmony_cistatic int
1090141cc406Sopenharmony_cirequest_sense_parse (u_char * sensed_data)
1091141cc406Sopenharmony_ci{
1092141cc406Sopenharmony_ci  unsigned int ret, sense, asc, ascq;
1093141cc406Sopenharmony_ci  sense = get_RS_sense_key (sensed_data);
1094141cc406Sopenharmony_ci  asc = get_RS_ASC (sensed_data);
1095141cc406Sopenharmony_ci  ascq = get_RS_ASCQ (sensed_data);
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci  ret = SANE_STATUS_IO_ERROR;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci  switch (sense)
1100141cc406Sopenharmony_ci    {
1101141cc406Sopenharmony_ci    case 0x0:                   /* No Sense */
1102141cc406Sopenharmony_ci      DBG (5, "\t%d/%d/%d: Scanner ready\n", sense, asc, ascq);
1103141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci    case 0x2:                   /* Not Ready */
1106141cc406Sopenharmony_ci      if ((0x00 == asc) && (0x00 == ascq))
1107141cc406Sopenharmony_ci        {
1108141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Not Ready \n", sense, asc, ascq);
1109141cc406Sopenharmony_ci        }
1110141cc406Sopenharmony_ci      else
1111141cc406Sopenharmony_ci        {
1112141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1113141cc406Sopenharmony_ci        }
1114141cc406Sopenharmony_ci      break;
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci    case 0x3:                   /* Medium Error */
1117141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x01 == ascq))
1118141cc406Sopenharmony_ci        {
1119141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Jam \n", sense, asc, ascq);
1120141cc406Sopenharmony_ci          ret = SANE_STATUS_JAMMED;
1121141cc406Sopenharmony_ci        }
1122141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x02 == ascq))
1123141cc406Sopenharmony_ci        {
1124141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: ADF cover open \n", sense, asc, ascq);
1125141cc406Sopenharmony_ci          ret = SANE_STATUS_COVER_OPEN;
1126141cc406Sopenharmony_ci        }
1127141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x03 == ascq))
1128141cc406Sopenharmony_ci        {
1129141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: ADF empty \n", sense, asc, ascq);
1130141cc406Sopenharmony_ci          ret = SANE_STATUS_NO_DOCS;
1131141cc406Sopenharmony_ci        }
1132141cc406Sopenharmony_ci      else
1133141cc406Sopenharmony_ci        {
1134141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1135141cc406Sopenharmony_ci        }
1136141cc406Sopenharmony_ci      break;
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci    case 0x4:                   /* Hardware Error */
1139141cc406Sopenharmony_ci      if ((0x80 == asc) && (0x01 == ascq))
1140141cc406Sopenharmony_ci        {
1141141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: FB motor fuse \n", sense, asc, ascq);
1142141cc406Sopenharmony_ci        }
1143141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x02 == ascq))
1144141cc406Sopenharmony_ci        {
1145141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: heater fuse \n", sense, asc, ascq);
1146141cc406Sopenharmony_ci        }
1147141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x04 == ascq))
1148141cc406Sopenharmony_ci        {
1149141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: ADF motor fuse \n", sense, asc, ascq);
1150141cc406Sopenharmony_ci        }
1151141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x05 == ascq))
1152141cc406Sopenharmony_ci        {
1153141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: mechanical alarm \n", sense, asc, ascq);
1154141cc406Sopenharmony_ci        }
1155141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x06 == ascq))
1156141cc406Sopenharmony_ci        {
1157141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: optical alarm \n", sense, asc, ascq);
1158141cc406Sopenharmony_ci        }
1159141cc406Sopenharmony_ci      else if ((0x44 == asc) && (0x00 == ascq))
1160141cc406Sopenharmony_ci        {
1161141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: abnormal internal target \n", sense, asc, ascq);
1162141cc406Sopenharmony_ci        }
1163141cc406Sopenharmony_ci      else if ((0x47 == asc) && (0x00 == ascq))
1164141cc406Sopenharmony_ci        {
1165141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: SCSI parity error \n", sense, asc, ascq);
1166141cc406Sopenharmony_ci        }
1167141cc406Sopenharmony_ci      else
1168141cc406Sopenharmony_ci        {
1169141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1170141cc406Sopenharmony_ci        }
1171141cc406Sopenharmony_ci      break;
1172141cc406Sopenharmony_ci
1173141cc406Sopenharmony_ci    case 0x5:                   /* Illegal Request */
1174141cc406Sopenharmony_ci      if ((0x20 == asc) && (0x00 == ascq))
1175141cc406Sopenharmony_ci        {
1176141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Invalid command \n", sense, asc, ascq);
1177141cc406Sopenharmony_ci          ret = SANE_STATUS_INVAL;
1178141cc406Sopenharmony_ci        }
1179141cc406Sopenharmony_ci      else if ((0x24 == asc) && (0x00 == ascq))
1180141cc406Sopenharmony_ci        {
1181141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Invalid field in CDB \n", sense, asc, ascq);
1182141cc406Sopenharmony_ci          ret = SANE_STATUS_INVAL;
1183141cc406Sopenharmony_ci        }
1184141cc406Sopenharmony_ci      else if ((0x25 == asc) && (0x00 == ascq))
1185141cc406Sopenharmony_ci        {
1186141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Unsupported logical unit \n", sense, asc, ascq);
1187141cc406Sopenharmony_ci          ret = SANE_STATUS_UNSUPPORTED;
1188141cc406Sopenharmony_ci        }
1189141cc406Sopenharmony_ci      else if ((0x26 == asc) && (0x00 == ascq))
1190141cc406Sopenharmony_ci        {
1191141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Invalid field in parm list \n", sense, asc, ascq);
1192141cc406Sopenharmony_ci          ret = SANE_STATUS_INVAL;
1193141cc406Sopenharmony_ci        }
1194141cc406Sopenharmony_ci      else if ((0x2C == asc) && (0x02 == ascq))
1195141cc406Sopenharmony_ci        {
1196141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: wrong window combination \n", sense, asc, ascq);
1197141cc406Sopenharmony_ci          ret = SANE_STATUS_INVAL;
1198141cc406Sopenharmony_ci        }
1199141cc406Sopenharmony_ci      else
1200141cc406Sopenharmony_ci        {
1201141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1202141cc406Sopenharmony_ci        }
1203141cc406Sopenharmony_ci      break;
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci    case 0x6:                   /* Unit Attention */
1206141cc406Sopenharmony_ci      if ((0x00 == asc) && (0x00 == ascq))
1207141cc406Sopenharmony_ci        {
1208141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: UNIT ATTENTION \n", sense, asc, ascq);
1209141cc406Sopenharmony_ci        }
1210141cc406Sopenharmony_ci      else
1211141cc406Sopenharmony_ci        {
1212141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1213141cc406Sopenharmony_ci        }
1214141cc406Sopenharmony_ci      break;
1215141cc406Sopenharmony_ci
1216141cc406Sopenharmony_ci    case 0xb:                   /* Aborted Command */
1217141cc406Sopenharmony_ci      if ((0x43 == asc) && (0x00 == ascq))
1218141cc406Sopenharmony_ci        {
1219141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Message error \n", sense, asc, ascq);
1220141cc406Sopenharmony_ci        }
1221141cc406Sopenharmony_ci      else if ((0x80 == asc) && (0x01 == ascq))
1222141cc406Sopenharmony_ci        {
1223141cc406Sopenharmony_ci          DBG (1, "\t%d/%d/%d: Image transfer error \n", sense, asc, ascq);
1224141cc406Sopenharmony_ci        }
1225141cc406Sopenharmony_ci      else
1226141cc406Sopenharmony_ci        {
1227141cc406Sopenharmony_ci          DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1228141cc406Sopenharmony_ci        }
1229141cc406Sopenharmony_ci      break;
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci    default:
1232141cc406Sopenharmony_ci      DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
1233141cc406Sopenharmony_ci    }
1234141cc406Sopenharmony_ci  return ret;
1235141cc406Sopenharmony_ci}                               /* request_sense_parse */
1236141cc406Sopenharmony_ci
1237141cc406Sopenharmony_cistatic SANE_Status
1238141cc406Sopenharmony_cisp15c_identify_scanner (struct sp15c *s)
1239141cc406Sopenharmony_ci{
1240141cc406Sopenharmony_ci  char vendor[9];
1241141cc406Sopenharmony_ci  char product[0x11];
1242141cc406Sopenharmony_ci  char version[5];
1243141cc406Sopenharmony_ci  char *pp;
1244141cc406Sopenharmony_ci  SANE_Status ret;
1245141cc406Sopenharmony_ci
1246141cc406Sopenharmony_ci  DBG (10, "identify_scanner\n");
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci  vendor[8] = product[0x10] = version[4] = 0;
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci  if ((ret = sp15c_do_inquiry (s)))
1251141cc406Sopenharmony_ci    {
1252141cc406Sopenharmony_ci      DBG (5, "identify_scanner: inquiry failed\n");
1253141cc406Sopenharmony_ci      return ret;
1254141cc406Sopenharmony_ci    }
1255141cc406Sopenharmony_ci  if (get_IN_periph_devtype (s->buffer) != IN_periph_devtype_scanner)
1256141cc406Sopenharmony_ci    {
1257141cc406Sopenharmony_ci      DBG (5, "identify_scanner: not a scanner\n");
1258141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1259141cc406Sopenharmony_ci    }
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci  get_IN_vendor ((char *) s->buffer, vendor);
1262141cc406Sopenharmony_ci  get_IN_product ((char *)s->buffer, product);
1263141cc406Sopenharmony_ci  get_IN_version ((char *)s->buffer, version);
1264141cc406Sopenharmony_ci
1265141cc406Sopenharmony_ci  if (strncmp ("FCPA    ", vendor, 8))
1266141cc406Sopenharmony_ci    {
1267141cc406Sopenharmony_ci      DBG (5, "identify_scanner: \"%s\" isn't a Fujitsu product\n", vendor);
1268141cc406Sopenharmony_ci      return 1;
1269141cc406Sopenharmony_ci    }
1270141cc406Sopenharmony_ci
1271141cc406Sopenharmony_ci  pp = &vendor[8];
1272141cc406Sopenharmony_ci  vendor[8] = ' ';
1273141cc406Sopenharmony_ci  while (*pp == ' ')
1274141cc406Sopenharmony_ci    {
1275141cc406Sopenharmony_ci      *pp-- = '\0';
1276141cc406Sopenharmony_ci    }
1277141cc406Sopenharmony_ci
1278141cc406Sopenharmony_ci  pp = &product[0x10];
1279141cc406Sopenharmony_ci  product[0x10] = ' ';
1280141cc406Sopenharmony_ci  while (*(pp - 1) == ' ')
1281141cc406Sopenharmony_ci    {
1282141cc406Sopenharmony_ci      *pp-- = '\0';
1283141cc406Sopenharmony_ci    }                           /* leave one blank at the end! */
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_ci  pp = &version[4];
1286141cc406Sopenharmony_ci  version[4] = ' ';
1287141cc406Sopenharmony_ci  while (*pp == ' ')
1288141cc406Sopenharmony_ci    {
1289141cc406Sopenharmony_ci      *pp-- = '\0';
1290141cc406Sopenharmony_ci    }
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  if (get_IN_adf (s->buffer))
1293141cc406Sopenharmony_ci    {
1294141cc406Sopenharmony_ci      s->autofeeder = 1;
1295141cc406Sopenharmony_ci    }
1296141cc406Sopenharmony_ci  else
1297141cc406Sopenharmony_ci    {
1298141cc406Sopenharmony_ci      s->autofeeder = 0;
1299141cc406Sopenharmony_ci    }
1300141cc406Sopenharmony_ci
1301141cc406Sopenharmony_ci  DBG (10, "Found %s scanner %s version %s on device %s  %x/%x/%x\n",
1302141cc406Sopenharmony_ci       vendor, product, version, s->devicename,
1303141cc406Sopenharmony_ci       s->autofeeder, get_IN_color_mode (s->buffer),
1304141cc406Sopenharmony_ci       get_IN_color_seq (s->buffer));
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci  vendor[8] = '\0';
1307141cc406Sopenharmony_ci  product[16] = '\0';
1308141cc406Sopenharmony_ci  version[4] = '\0';
1309141cc406Sopenharmony_ci
1310141cc406Sopenharmony_ci  strncpy (s->vendor, vendor, 9);
1311141cc406Sopenharmony_ci  strncpy (s->product, product, 17);
1312141cc406Sopenharmony_ci  strncpy (s->version, version, 5);
1313141cc406Sopenharmony_ci
1314141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1315141cc406Sopenharmony_ci}                               /* sp15c_identify_scanner */
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_cistatic SANE_Status
1318141cc406Sopenharmony_cisp15c_do_inquiry (struct sp15c *s)
1319141cc406Sopenharmony_ci{
1320141cc406Sopenharmony_ci  static SANE_Status ret;
1321141cc406Sopenharmony_ci
1322141cc406Sopenharmony_ci  DBG (10, "do_inquiry\n");
1323141cc406Sopenharmony_ci
1324141cc406Sopenharmony_ci  memset (s->buffer, '\0', 256);        /* clear buffer */
1325141cc406Sopenharmony_ci  set_IN_return_size (inquiryB.cmd, 96);
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, inquiryB.cmd, inquiryB.size, s->buffer, 96);
1328141cc406Sopenharmony_ci  return ret;
1329141cc406Sopenharmony_ci}                               /* sp15c_do_inquiry */
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_cistatic SANE_Status
1332141cc406Sopenharmony_cido_scsi_cmd (int fd, unsigned char *cmd, int cmd_len, unsigned char *out, size_t out_len)
1333141cc406Sopenharmony_ci{
1334141cc406Sopenharmony_ci  SANE_Status ret;
1335141cc406Sopenharmony_ci  size_t ol = out_len;
1336141cc406Sopenharmony_ci
1337141cc406Sopenharmony_ci  hexdump (20, "<cmd<", cmd, cmd_len);
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci  ret = sanei_scsi_cmd (fd, cmd, cmd_len, out, &ol);
1340141cc406Sopenharmony_ci  if ((out_len != 0) && (out_len != ol))
1341141cc406Sopenharmony_ci    {
1342141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd: asked %lu bytes, got %lu\n",
1343141cc406Sopenharmony_ci           (u_long) out_len, (u_long) ol);
1344141cc406Sopenharmony_ci    }
1345141cc406Sopenharmony_ci  if (ret)
1346141cc406Sopenharmony_ci    {
1347141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd: returning 0x%08x\n", ret);
1348141cc406Sopenharmony_ci    }
1349141cc406Sopenharmony_ci  DBG (10, "sanei_scsi_cmd: returning %lu bytes:\n", (u_long) ol);
1350141cc406Sopenharmony_ci  if (out != NULL && out_len != 0)
1351141cc406Sopenharmony_ci    hexdump (15, ">rslt>", out, (out_len > 0x60) ? 0x60 : out_len);
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci  return ret;
1354141cc406Sopenharmony_ci}                               /* do_scsi_cmd */
1355141cc406Sopenharmony_ci
1356141cc406Sopenharmony_cistatic void
1357141cc406Sopenharmony_cihexdump (int level, char *comment, unsigned char *p, int l)
1358141cc406Sopenharmony_ci{
1359141cc406Sopenharmony_ci  int i;
1360141cc406Sopenharmony_ci  char line[128];
1361141cc406Sopenharmony_ci  char *ptr;
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
1364141cc406Sopenharmony_ci  ptr = line;
1365141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++)
1366141cc406Sopenharmony_ci    {
1367141cc406Sopenharmony_ci      if ((i % 16) == 0)
1368141cc406Sopenharmony_ci        {
1369141cc406Sopenharmony_ci          if (ptr != line)
1370141cc406Sopenharmony_ci            {
1371141cc406Sopenharmony_ci              *ptr = '\0';
1372141cc406Sopenharmony_ci              DBG (level, "%s\n", line);
1373141cc406Sopenharmony_ci              ptr = line;
1374141cc406Sopenharmony_ci            }
1375141cc406Sopenharmony_ci          sprintf (ptr, "%3.3d:", i);
1376141cc406Sopenharmony_ci          ptr += 4;
1377141cc406Sopenharmony_ci        }
1378141cc406Sopenharmony_ci      sprintf (ptr, " %2.2x", *p);
1379141cc406Sopenharmony_ci      ptr += 3;
1380141cc406Sopenharmony_ci    }
1381141cc406Sopenharmony_ci  *ptr = '\0';
1382141cc406Sopenharmony_ci  DBG (level, "%s\n", line);
1383141cc406Sopenharmony_ci}                               /* hexdump */
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_cistatic SANE_Status
1386141cc406Sopenharmony_ciinit_options (struct sp15c *scanner)
1387141cc406Sopenharmony_ci{
1388141cc406Sopenharmony_ci  int i;
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  DBG (10, "init_options\n");
1391141cc406Sopenharmony_ci
1392141cc406Sopenharmony_ci  memset (scanner->opt, 0, sizeof (scanner->opt));
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
1395141cc406Sopenharmony_ci    {
1396141cc406Sopenharmony_ci      scanner->opt[i].size = sizeof (SANE_Word);
1397141cc406Sopenharmony_ci      scanner->opt[i].cap = SANE_CAP_INACTIVE;
1398141cc406Sopenharmony_ci    }
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1401141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1402141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1403141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci/************** "Mode" group: **************/
1406141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].title = "Scan Mode";
1407141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].desc = "";
1408141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1409141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci  /* source */
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
1414141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
1415141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
1416141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
1417141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].size = max_string_size (source_list);
1418141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1419141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].constraint.string_list = source_list;
1420141cc406Sopenharmony_ci  if (scanner->autofeeder)
1421141cc406Sopenharmony_ci    {
1422141cc406Sopenharmony_ci      scanner->opt[OPT_SOURCE].cap = SANE_CAP_SOFT_SELECT
1423141cc406Sopenharmony_ci        | SANE_CAP_SOFT_DETECT;
1424141cc406Sopenharmony_ci    }
1425141cc406Sopenharmony_ci
1426141cc406Sopenharmony_ci  /* scan mode */
1427141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1428141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1429141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1430141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].type = SANE_TYPE_STRING;
1431141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].size = max_string_size (scan_mode_list);
1432141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1433141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].constraint.string_list = scan_mode_list;
1434141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci  /* negative */
1437141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].name = "type";
1438141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].title = "Film type";
1439141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].desc = "positive or negative image";
1440141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].type = SANE_TYPE_STRING;
1441141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].size = max_string_size (type_list);
1442141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1443141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].constraint.string_list = type_list;
1444141cc406Sopenharmony_ci
1445141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].name = "prescan";
1446141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].title = "Prescan";
1447141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].desc = "Perform a prescan during preview";
1448141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].type = SANE_TYPE_BOOL;
1449141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].unit = SANE_UNIT_NONE;
1450141cc406Sopenharmony_ci
1451141cc406Sopenharmony_ci  /* resolution */
1452141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].name = SANE_NAME_SCAN_RESOLUTION;
1453141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].title = SANE_TITLE_SCAN_X_RESOLUTION;
1454141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].desc = SANE_DESC_SCAN_X_RESOLUTION;
1455141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].type = SANE_TYPE_INT;
1456141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].unit = SANE_UNIT_DPI;
1457141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1458141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].constraint.word_list = x_res_list;
1459141cc406Sopenharmony_ci  scanner->opt[OPT_X_RES].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].name = SANE_NAME_SCAN_Y_RESOLUTION;
1462141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].title = SANE_TITLE_SCAN_Y_RESOLUTION;
1463141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].desc = SANE_DESC_SCAN_Y_RESOLUTION;
1464141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].type = SANE_TYPE_INT;
1465141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].unit = SANE_UNIT_DPI;
1466141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1467141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].constraint.word_list = y_res_list;
1468141cc406Sopenharmony_ci  scanner->opt[OPT_Y_RES].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].name = "preview-resolution";
1471141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].title = "Preview resolution";
1472141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].desc = SANE_DESC_SCAN_RESOLUTION;
1473141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].type = SANE_TYPE_INT;
1474141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].unit = SANE_UNIT_DPI;
1475141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1476141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RES].constraint.word_list = resolution_list;
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci/************** "Geometry" group: **************/
1479141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
1480141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].desc = "";
1481141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1482141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci  /* top-left x */
1485141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1486141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1487141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1488141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1489141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1490141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1491141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint.range = &x_range;
1492141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1493141cc406Sopenharmony_ci
1494141cc406Sopenharmony_ci  /* top-left y */
1495141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1496141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1497141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1498141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1499141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1500141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1501141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint.range = &y_range_fb;
1502141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  /* bottom-right x */
1505141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1506141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1507141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1508141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1509141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1510141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1511141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint.range = &x_range;
1512141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1513141cc406Sopenharmony_ci
1514141cc406Sopenharmony_ci  /* bottom-right y */
1515141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1516141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1517141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1518141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1519141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1520141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1521141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint.range = &y_range_fb;
1522141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci
1525141cc406Sopenharmony_ci  /* ------------------------------ */
1526141cc406Sopenharmony_ci
1527141cc406Sopenharmony_ci/************** "Enhancement" group: **************/
1528141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1529141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].desc = "";
1530141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1531141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].name = "averaging";
1534141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].title = "Averaging";
1535141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].desc = "Averaging";
1536141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].type = SANE_TYPE_BOOL;
1537141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].unit = SANE_UNIT_NONE;
1538141cc406Sopenharmony_ci
1539141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1540141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1541141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
1542141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
1543141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
1544141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1545141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].constraint.range = &brightness_range;
1546141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_DETECT;
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1549141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1550141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1551141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1552141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1553141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1554141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].constraint.range = &threshold_range;
1555141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_DETECT;
1556141cc406Sopenharmony_ci
1557141cc406Sopenharmony_ci  /* ------------------------------ */
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci/************** "Advanced" group: **************/
1560141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced";
1561141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].desc = "";
1562141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
1563141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1564141cc406Sopenharmony_ci
1565141cc406Sopenharmony_ci  /* preview */
1566141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
1567141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1568141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
1569141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
1570141cc406Sopenharmony_ci
1571141cc406Sopenharmony_ci  DBG (10, "init_options:ok\n");
1572141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1573141cc406Sopenharmony_ci}                               /* init_options */
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_cistatic int
1576141cc406Sopenharmony_cisp15c_check_values (struct sp15c *s)
1577141cc406Sopenharmony_ci{
1578141cc406Sopenharmony_ci  if (s->use_adf == SANE_TRUE && s->autofeeder == 0)
1579141cc406Sopenharmony_ci    {
1580141cc406Sopenharmony_ci      DBG (1, "sp15c_check_values: %s\n",
1581141cc406Sopenharmony_ci           "ERROR: ADF-MODE NOT SUPPORTED BY SCANNER, ABORTING");
1582141cc406Sopenharmony_ci      return (1);
1583141cc406Sopenharmony_ci    }
1584141cc406Sopenharmony_ci  return (0);
1585141cc406Sopenharmony_ci}                               /* sp15c_check_values */
1586141cc406Sopenharmony_ci
1587141cc406Sopenharmony_ci/* sp15c_free_scanner should go through the following sequence:
1588141cc406Sopenharmony_ci * OBJECT POSITION DISCHARGE
1589141cc406Sopenharmony_ci *     GOOD
1590141cc406Sopenharmony_ci * RELEASE UNIT
1591141cc406Sopenharmony_ci *     GOOD
1592141cc406Sopenharmony_ci */
1593141cc406Sopenharmony_cistatic int
1594141cc406Sopenharmony_cisp15c_free_scanner (struct sp15c *s)
1595141cc406Sopenharmony_ci{
1596141cc406Sopenharmony_ci  int ret;
1597141cc406Sopenharmony_ci  DBG (10, "sp15c_free_scanner\n");
1598141cc406Sopenharmony_ci#if 0
1599141cc406Sopenharmony_ci  /* hmg: reports from several people show that this code ejects two pages
1600141cc406Sopenharmony_ci     instead of one. So I've commented it out for now. */
1601141cc406Sopenharmony_ci  ret = sp15c_object_discharge (s);
1602141cc406Sopenharmony_ci  if (ret)
1603141cc406Sopenharmony_ci    return ret;
1604141cc406Sopenharmony_ci#endif
1605141cc406Sopenharmony_ci
1606141cc406Sopenharmony_ci  wait_scanner (s);
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, release_unitB.cmd, release_unitB.size, NULL, 0);
1609141cc406Sopenharmony_ci  if (ret)
1610141cc406Sopenharmony_ci    return ret;
1611141cc406Sopenharmony_ci
1612141cc406Sopenharmony_ci  DBG (10, "sp15c_free_scanner: ok\n");
1613141cc406Sopenharmony_ci  return ret;
1614141cc406Sopenharmony_ci}                               /* sp15c_free_scanner */
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci/* sp15c_grab_scanner should go through the following command sequence:
1617141cc406Sopenharmony_ci * TEST UNIT READY
1618141cc406Sopenharmony_ci *     CHECK CONDITION  \
1619141cc406Sopenharmony_ci * REQUEST SENSE         > These should be handled automagically by
1620141cc406Sopenharmony_ci *     UNIT ATTENTION   /  the kernel if they happen (powerup/reset)
1621141cc406Sopenharmony_ci * TEST UNIT READY
1622141cc406Sopenharmony_ci *     GOOD
1623141cc406Sopenharmony_ci * RESERVE UNIT
1624141cc406Sopenharmony_ci *     GOOD
1625141cc406Sopenharmony_ci *
1626141cc406Sopenharmony_ci * It is then responsible for installing appropriate signal handlers
1627141cc406Sopenharmony_ci * to call emergency_give_scanner() if user aborts.
1628141cc406Sopenharmony_ci */
1629141cc406Sopenharmony_ci
1630141cc406Sopenharmony_cistatic int
1631141cc406Sopenharmony_cisp15c_grab_scanner (struct sp15c *s)
1632141cc406Sopenharmony_ci{
1633141cc406Sopenharmony_ci  int ret;
1634141cc406Sopenharmony_ci
1635141cc406Sopenharmony_ci  DBG (10, "sp15c_grab_scanner\n");
1636141cc406Sopenharmony_ci  wait_scanner (s);
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, reserve_unitB.cmd, reserve_unitB.size, NULL, 0);
1639141cc406Sopenharmony_ci  if (ret)
1640141cc406Sopenharmony_ci    return ret;
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_ci  DBG (10, "sp15c_grab_scanner: ok\n");
1643141cc406Sopenharmony_ci  return 0;
1644141cc406Sopenharmony_ci}                               /* sp15c_grab_scanner */
1645141cc406Sopenharmony_ci
1646141cc406Sopenharmony_ci/*
1647141cc406Sopenharmony_ci *  wait_scanner spins until TEST_UNIT_READY returns 0 (GOOD)
1648141cc406Sopenharmony_ci *  returns 0 on success,
1649141cc406Sopenharmony_ci *  returns -1 on error or timeout
1650141cc406Sopenharmony_ci */
1651141cc406Sopenharmony_cistatic int
1652141cc406Sopenharmony_ciwait_scanner (struct sp15c *s)
1653141cc406Sopenharmony_ci{
1654141cc406Sopenharmony_ci  int ret = -1;
1655141cc406Sopenharmony_ci  int cnt = 0;
1656141cc406Sopenharmony_ci
1657141cc406Sopenharmony_ci  DBG (10, "wait_scanner\n");
1658141cc406Sopenharmony_ci
1659141cc406Sopenharmony_ci  while (ret != 0)
1660141cc406Sopenharmony_ci    {
1661141cc406Sopenharmony_ci      ret = do_scsi_cmd (s->sfd, test_unit_readyB.cmd,
1662141cc406Sopenharmony_ci                         test_unit_readyB.size, 0, 0);
1663141cc406Sopenharmony_ci      if (ret == SANE_STATUS_DEVICE_BUSY)
1664141cc406Sopenharmony_ci        {
1665141cc406Sopenharmony_ci          usleep (50000);       /* wait 0.05 seconds */
1666141cc406Sopenharmony_ci          /* 20 sec. max (prescan takes up to 15 sec.) */
1667141cc406Sopenharmony_ci          if (cnt++ > 400)
1668141cc406Sopenharmony_ci            {
1669141cc406Sopenharmony_ci              DBG (1, "wait_scanner: scanner does NOT get ready\n");
1670141cc406Sopenharmony_ci              return -1;
1671141cc406Sopenharmony_ci            }
1672141cc406Sopenharmony_ci        }
1673141cc406Sopenharmony_ci      else if (ret == SANE_STATUS_GOOD)
1674141cc406Sopenharmony_ci        {
1675141cc406Sopenharmony_ci          DBG (10, "wait_scanner: ok\n");
1676141cc406Sopenharmony_ci          return ret;
1677141cc406Sopenharmony_ci        }
1678141cc406Sopenharmony_ci      else
1679141cc406Sopenharmony_ci        {
1680141cc406Sopenharmony_ci          DBG (1, "wait_scanner: unit ready failed (%s)\n",
1681141cc406Sopenharmony_ci               sane_strstatus (ret));
1682141cc406Sopenharmony_ci        }
1683141cc406Sopenharmony_ci    }
1684141cc406Sopenharmony_ci  DBG (10, "wait_scanner: ok\n");
1685141cc406Sopenharmony_ci  return 0;
1686141cc406Sopenharmony_ci}                               /* wait_scanner */
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci/* As noted above, this command has been supplanted by the
1689141cc406Sopenharmony_ci   MEDIA CHECK command.  Nevertheless, it's still available
1690141cc406Sopenharmony_ci   here in case some future need is discovered. */
1691141cc406Sopenharmony_cistatic int
1692141cc406Sopenharmony_cisp15c_object_position (struct sp15c *s)
1693141cc406Sopenharmony_ci{
1694141cc406Sopenharmony_ci  int ret;
1695141cc406Sopenharmony_ci  DBG (10, "sp15c_object_position\n");
1696141cc406Sopenharmony_ci  if (s->use_adf != SANE_TRUE)
1697141cc406Sopenharmony_ci    {
1698141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1699141cc406Sopenharmony_ci    }
1700141cc406Sopenharmony_ci  if (s->autofeeder == 0)
1701141cc406Sopenharmony_ci    {
1702141cc406Sopenharmony_ci      DBG (10, "sp15c_object_position: Autofeeder not present.\n");
1703141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1704141cc406Sopenharmony_ci    }
1705141cc406Sopenharmony_ci  memcpy (s->buffer, object_positionB.cmd, object_positionB.size);
1706141cc406Sopenharmony_ci  set_OP_autofeed (s->buffer, OP_Feed);
1707141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer,
1708141cc406Sopenharmony_ci                     object_positionB.size, NULL, 0);
1709141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1710141cc406Sopenharmony_ci    {
1711141cc406Sopenharmony_ci      return ret;
1712141cc406Sopenharmony_ci    }
1713141cc406Sopenharmony_ci  wait_scanner (s);
1714141cc406Sopenharmony_ci  DBG (10, "sp15c_object_position: ok\n");
1715141cc406Sopenharmony_ci  return ret;
1716141cc406Sopenharmony_ci}                               /* sp15c_object_position */
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_cistatic int
1719141cc406Sopenharmony_cisp15c_media_check (struct sp15c *s)
1720141cc406Sopenharmony_ci{
1721141cc406Sopenharmony_ci  static SANE_Status ret;
1722141cc406Sopenharmony_ci  DBG (10, "sp15c_media_check\n");
1723141cc406Sopenharmony_ci  if (s->use_adf != SANE_TRUE)
1724141cc406Sopenharmony_ci    {
1725141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1726141cc406Sopenharmony_ci    }
1727141cc406Sopenharmony_ci  if (s->autofeeder == 0)
1728141cc406Sopenharmony_ci    {
1729141cc406Sopenharmony_ci      DBG (10, "sp15c_media_check: Autofeeder not present.\n");
1730141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1731141cc406Sopenharmony_ci    }
1732141cc406Sopenharmony_ci
1733141cc406Sopenharmony_ci  memset (s->buffer, '\0', 256);        /* clear buffer */
1734141cc406Sopenharmony_ci  set_MC_return_size (media_checkB.cmd, 1);
1735141cc406Sopenharmony_ci
1736141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, media_checkB.cmd, media_checkB.size, s->buffer, 1);
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci  if (ret != SANE_STATUS_GOOD)
1739141cc406Sopenharmony_ci    {
1740141cc406Sopenharmony_ci      return ret;
1741141cc406Sopenharmony_ci    }
1742141cc406Sopenharmony_ci  wait_scanner (s);
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  if (get_MC_adf_status (s->buffer) == MC_ADF_OK)
1745141cc406Sopenharmony_ci    {
1746141cc406Sopenharmony_ci      DBG (10, "sp15c_media_check: ok\n");
1747141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1748141cc406Sopenharmony_ci    }
1749141cc406Sopenharmony_ci  return SANE_STATUS_NO_DOCS;
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci}                               /* sp15c_media_check */
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_cistatic SANE_Status
1754141cc406Sopenharmony_cido_cancel (struct sp15c *scanner)
1755141cc406Sopenharmony_ci{
1756141cc406Sopenharmony_ci  DBG (10, "do_cancel\n");
1757141cc406Sopenharmony_ci  swap_res (scanner);
1758141cc406Sopenharmony_ci
1759141cc406Sopenharmony_ci  do_eof (scanner);             /* close pipe and reposition scanner */
1760141cc406Sopenharmony_ci
1761141cc406Sopenharmony_ci  if (sanei_thread_is_valid (scanner->reader_pid))
1762141cc406Sopenharmony_ci    {
1763141cc406Sopenharmony_ci      int exit_status;
1764141cc406Sopenharmony_ci      DBG (10, "do_cancel: kill reader_process\n");
1765141cc406Sopenharmony_ci      /* ensure child knows it's time to stop: */
1766141cc406Sopenharmony_ci      sanei_thread_kill (scanner->reader_pid);
1767141cc406Sopenharmony_ci      DBG (50, "wait for scanner to stop\n");
1768141cc406Sopenharmony_ci      sanei_thread_waitpid (scanner->reader_pid, &exit_status);
1769141cc406Sopenharmony_ci      sanei_thread_invalidate (scanner->reader_pid);
1770141cc406Sopenharmony_ci    }
1771141cc406Sopenharmony_ci
1772141cc406Sopenharmony_ci  if (scanner->sfd >= 0)
1773141cc406Sopenharmony_ci    {
1774141cc406Sopenharmony_ci      sp15c_free_scanner (scanner);
1775141cc406Sopenharmony_ci      DBG (10, "do_cancel: close filedescriptor\n");
1776141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
1777141cc406Sopenharmony_ci      scanner->sfd = -1;
1778141cc406Sopenharmony_ci    }
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
1781141cc406Sopenharmony_ci}                               /* do_cancel */
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_cistatic void
1784141cc406Sopenharmony_ciswap_res (struct sp15c *s)
1785141cc406Sopenharmony_ci{
1786141cc406Sopenharmony_ci  (void) s; /* silence compilation warnings */
1787141cc406Sopenharmony_ci
1788141cc406Sopenharmony_ci  /* for the time being, do nothing */
1789141cc406Sopenharmony_ci}                               /* swap_res */
1790141cc406Sopenharmony_ci
1791141cc406Sopenharmony_cistatic int
1792141cc406Sopenharmony_cisp15c_object_discharge (struct sp15c *s)
1793141cc406Sopenharmony_ci{
1794141cc406Sopenharmony_ci  int ret;
1795141cc406Sopenharmony_ci
1796141cc406Sopenharmony_ci  DBG (10, "sp15c_object_discharge\n");
1797141cc406Sopenharmony_ci  if (s->use_adf != SANE_TRUE)
1798141cc406Sopenharmony_ci    {
1799141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1800141cc406Sopenharmony_ci    }
1801141cc406Sopenharmony_ci
1802141cc406Sopenharmony_ci  memcpy (s->buffer, object_positionB.cmd, object_positionB.size);
1803141cc406Sopenharmony_ci  set_OP_autofeed (s->buffer, OP_Discharge);
1804141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer,
1805141cc406Sopenharmony_ci                     object_positionB.size, NULL, 0);
1806141cc406Sopenharmony_ci  wait_scanner (s);
1807141cc406Sopenharmony_ci  DBG (10, "sp15c_object_discharge: ok\n");
1808141cc406Sopenharmony_ci  return ret;
1809141cc406Sopenharmony_ci}                               /* sp15c_object_discharge */
1810141cc406Sopenharmony_ci
1811141cc406Sopenharmony_cistatic int
1812141cc406Sopenharmony_cisp15c_set_window_param (struct sp15c *s, int prescan)
1813141cc406Sopenharmony_ci{
1814141cc406Sopenharmony_ci  unsigned char buffer_r[WDB_size_max];
1815141cc406Sopenharmony_ci  int ret;
1816141cc406Sopenharmony_ci  int active_buffer_size;
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci  (void) prescan; /* silence compilation warnings */
1819141cc406Sopenharmony_ci
1820141cc406Sopenharmony_ci  wait_scanner (s);
1821141cc406Sopenharmony_ci  DBG (10, "set_window_param\n");
1822141cc406Sopenharmony_ci  memset (buffer_r, '\0', WDB_size_max);        /* clear buffer */
1823141cc406Sopenharmony_ci  memcpy (buffer_r, window_descriptor_blockB.cmd,
1824141cc406Sopenharmony_ci          window_descriptor_blockB.size);       /* copy preset data */
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci  set_WD_wid (buffer_r, WD_wid_all);    /* window identifier */
1827141cc406Sopenharmony_ci
1828141cc406Sopenharmony_ci  set_WD_Xres (buffer_r, s->x_res);     /* x resolution in dpi */
1829141cc406Sopenharmony_ci  set_WD_Yres (buffer_r, s->y_res);     /* y resolution in dpi */
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ci  set_WD_ULX (buffer_r, s->tl_x);       /* top left x */
1832141cc406Sopenharmony_ci  set_WD_ULY (buffer_r, s->tl_y);       /* top left y */
1833141cc406Sopenharmony_ci
1834141cc406Sopenharmony_ci  set_WD_width (buffer_r, s->br_x - s->tl_x);
1835141cc406Sopenharmony_ci  set_WD_length (buffer_r, s->br_y - s->tl_y);
1836141cc406Sopenharmony_ci
1837141cc406Sopenharmony_ci  set_WD_brightness (buffer_r, s->brightness);
1838141cc406Sopenharmony_ci  set_WD_threshold (buffer_r, s->threshold);
1839141cc406Sopenharmony_ci  set_WD_contrast (buffer_r, s->contrast);
1840141cc406Sopenharmony_ci  set_WD_bitsperpixel (buffer_r, s->bitsperpixel);
1841141cc406Sopenharmony_ci  set_WD_rif (buffer_r, s->rif);
1842141cc406Sopenharmony_ci  set_WD_pad (buffer_r, 0x3);
1843141cc406Sopenharmony_ci  set_WD_halftone (buffer_r, s->halftone);
1844141cc406Sopenharmony_ci  set_WD_bitorder (buffer_r, s->bitorder);
1845141cc406Sopenharmony_ci  set_WD_compress_type (buffer_r, s->compress_type);
1846141cc406Sopenharmony_ci  set_WD_compress_arg (buffer_r, s->compress_arg);
1847141cc406Sopenharmony_ci  set_WD_composition (buffer_r, s->composition);        /* may be overridden below */
1848141cc406Sopenharmony_ci  set_WD_vendor_id_code (buffer_r, 0xff);
1849141cc406Sopenharmony_ci  set_WD_adf (buffer_r, s->use_adf == SANE_TRUE ? 1 : 0);
1850141cc406Sopenharmony_ci  set_WD_source (buffer_r, 1);
1851141cc406Sopenharmony_ci  set_WD_highlight_color (buffer_r, 0xff);
1852141cc406Sopenharmony_ci  set_WD_shadow_value (buffer_r, 0x00);
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci  switch (s->composition)
1855141cc406Sopenharmony_ci    {
1856141cc406Sopenharmony_ci    case WD_comp_LA:
1857141cc406Sopenharmony_ci    case WD_comp_HT:
1858141cc406Sopenharmony_ci      set_WD_line_width (buffer_r, ((s->br_x - s->tl_x) * s->x_res / 1200) / 8);
1859141cc406Sopenharmony_ci      set_WD_line_count (buffer_r, (s->br_y - s->tl_y) * s->y_res / 1200);
1860141cc406Sopenharmony_ci      goto b_and_w;
1861141cc406Sopenharmony_ci    case WD_comp_G4:
1862141cc406Sopenharmony_ci      set_WD_line_width (buffer_r, ((s->br_x - s->tl_x) * s->x_res / 1200) / 2);
1863141cc406Sopenharmony_ci      set_WD_line_count (buffer_r, (s->br_y - s->tl_y) * s->y_res / 1200);
1864141cc406Sopenharmony_ci      goto grayscale;
1865141cc406Sopenharmony_ci    case WD_comp_G8:
1866141cc406Sopenharmony_ci      set_WD_line_width (buffer_r, (s->br_x - s->tl_x) * s->x_res / 1200);
1867141cc406Sopenharmony_ci      set_WD_line_count (buffer_r, (s->br_y - s->tl_y) * s->y_res / 1200);
1868141cc406Sopenharmony_ci    grayscale:
1869141cc406Sopenharmony_ci      set_WD_composition (buffer_r, WD_comp_GS);
1870141cc406Sopenharmony_ci    b_and_w:
1871141cc406Sopenharmony_ci      set_WD_color (buffer_r, WD_color_greenx);
1872141cc406Sopenharmony_ci      break;
1873141cc406Sopenharmony_ci    case WD_comp_MC:
1874141cc406Sopenharmony_ci      set_WD_color (buffer_r, WD_color_rgb);
1875141cc406Sopenharmony_ci      set_WD_line_width (buffer_r, 3 * (s->br_x - s->tl_x) * s->x_res / 1200);
1876141cc406Sopenharmony_ci      set_WD_line_count (buffer_r, (s->br_y - s->tl_y) * s->y_res / 1200);
1877141cc406Sopenharmony_ci      break;
1878141cc406Sopenharmony_ci    case WD_comp_BC:
1879141cc406Sopenharmony_ci    case WD_comp_DC:
1880141cc406Sopenharmony_ci    default:
1881141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1882141cc406Sopenharmony_ci    }
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci  /* prepare SCSI-BUFFER */
1885141cc406Sopenharmony_ci  memcpy (s->buffer, set_windowB.cmd, set_windowB.size);
1886141cc406Sopenharmony_ci  memcpy ((s->buffer + set_windowB.size),
1887141cc406Sopenharmony_ci          window_parameter_data_blockB.cmd,
1888141cc406Sopenharmony_ci          window_parameter_data_blockB.size);
1889141cc406Sopenharmony_ci  memcpy ((s->buffer + set_windowB.size + window_parameter_data_blockB.size),
1890141cc406Sopenharmony_ci          buffer_r, window_descriptor_blockB.size);
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci  set_SW_xferlen (s->buffer,
1893141cc406Sopenharmony_ci                  (window_parameter_data_blockB.size
1894141cc406Sopenharmony_ci                   + WDB_size_Color));
1895141cc406Sopenharmony_ci  set_WDPB_wdblen ((s->buffer
1896141cc406Sopenharmony_ci                    + set_windowB.size),
1897141cc406Sopenharmony_ci                   WDB_size_Color);
1898141cc406Sopenharmony_ci  set_WD_parm_length ((s->buffer
1899141cc406Sopenharmony_ci                       + set_windowB.size
1900141cc406Sopenharmony_ci                       + window_parameter_data_blockB.size),
1901141cc406Sopenharmony_ci                      9);
1902141cc406Sopenharmony_ci
1903141cc406Sopenharmony_ci  DBG (10, "\tx_res=%d, y_res=%d\n",
1904141cc406Sopenharmony_ci       s->x_res, s->y_res);
1905141cc406Sopenharmony_ci  DBG (10, "\tupper left-x=%d, upper left-y=%d\n",
1906141cc406Sopenharmony_ci       s->tl_x, s->tl_y);
1907141cc406Sopenharmony_ci  DBG (10, "\twindow width=%d, length=%d\n",
1908141cc406Sopenharmony_ci       s->br_x - s->tl_x,
1909141cc406Sopenharmony_ci       s->br_y - s->tl_y);
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_ci  active_buffer_size = set_windowB.size + get_SW_xferlen (s->buffer);
1912141cc406Sopenharmony_ci
1913141cc406Sopenharmony_ci  hexdump (15, "Window set", s->buffer, active_buffer_size);
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer, active_buffer_size, NULL, 0);
1916141cc406Sopenharmony_ci  if (ret)
1917141cc406Sopenharmony_ci    return ret;
1918141cc406Sopenharmony_ci
1919141cc406Sopenharmony_ci  DBG (10, "set_window_param: ok\n");
1920141cc406Sopenharmony_ci  return ret;
1921141cc406Sopenharmony_ci}                               /* sp15c_set_window_param */
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_cistatic size_t
1924141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
1925141cc406Sopenharmony_ci{
1926141cc406Sopenharmony_ci  size_t size, max_size = 0;
1927141cc406Sopenharmony_ci  int i;
1928141cc406Sopenharmony_ci
1929141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
1930141cc406Sopenharmony_ci    {
1931141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
1932141cc406Sopenharmony_ci      if (size > max_size)
1933141cc406Sopenharmony_ci        max_size = size;
1934141cc406Sopenharmony_ci    }
1935141cc406Sopenharmony_ci  return max_size;
1936141cc406Sopenharmony_ci}                               /* max_string_size */
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_cistatic int
1939141cc406Sopenharmony_cisp15c_start_scan (struct sp15c *s)
1940141cc406Sopenharmony_ci{
1941141cc406Sopenharmony_ci  int ret;
1942141cc406Sopenharmony_ci  DBG (10, "sp15c_start_scan\n");
1943141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, scanB.cmd, scanB.size, NULL, 0);
1944141cc406Sopenharmony_ci  if (ret)
1945141cc406Sopenharmony_ci    return ret;
1946141cc406Sopenharmony_ci  DBG (10, "sp15c_start_scan:ok\n");
1947141cc406Sopenharmony_ci  return ret;
1948141cc406Sopenharmony_ci}                               /* sp15c_start_scan */
1949141cc406Sopenharmony_ci
1950141cc406Sopenharmony_cistatic void
1951141cc406Sopenharmony_cisigterm_handler (int signal)
1952141cc406Sopenharmony_ci{
1953141cc406Sopenharmony_ci  (void) signal; /* silence compilation warnings */
1954141cc406Sopenharmony_ci
1955141cc406Sopenharmony_ci  sanei_scsi_req_flush_all ();  /* flush SCSI queue */
1956141cc406Sopenharmony_ci  _exit (SANE_STATUS_GOOD);
1957141cc406Sopenharmony_ci}                               /* sigterm_handler */
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci/* This function is executed as a child process. */
1960141cc406Sopenharmony_cistatic int
1961141cc406Sopenharmony_cireader_process (void *data)
1962141cc406Sopenharmony_ci{
1963141cc406Sopenharmony_ci  struct sp15c *scanner = (struct sp15c *) data;
1964141cc406Sopenharmony_ci  int pipe_fd = scanner->reader_pipe;
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_ci  int status;
1967141cc406Sopenharmony_ci  unsigned int data_left;
1968141cc406Sopenharmony_ci  unsigned int data_to_read;
1969141cc406Sopenharmony_ci  FILE *fp;
1970141cc406Sopenharmony_ci  sigset_t ignore_set;
1971141cc406Sopenharmony_ci  sigset_t sigterm_set;
1972141cc406Sopenharmony_ci  struct SIGACTION act;
1973141cc406Sopenharmony_ci  unsigned int i;
1974141cc406Sopenharmony_ci  unsigned char *src, *dst;
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_ci  DBG (10, "reader_process started\n");
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
1979141cc406Sopenharmony_ci    close (scanner->pipe);
1980141cc406Sopenharmony_ci
1981141cc406Sopenharmony_ci  sigfillset (&ignore_set);
1982141cc406Sopenharmony_ci  sigdelset (&ignore_set, SIGTERM);
1983141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__)
1984141cc406Sopenharmony_ci  sigdelset (&ignore_set, SIGUSR2);
1985141cc406Sopenharmony_ci#endif
1986141cc406Sopenharmony_ci  sigprocmask (SIG_SETMASK, &ignore_set, 0);
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));
1989141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_ci  sigemptyset (&sigterm_set);
1992141cc406Sopenharmony_ci  sigaddset (&sigterm_set, SIGTERM);
1993141cc406Sopenharmony_ci
1994141cc406Sopenharmony_ci  fp = fdopen (pipe_fd, "w");
1995141cc406Sopenharmony_ci  if (!fp)
1996141cc406Sopenharmony_ci    {
1997141cc406Sopenharmony_ci      DBG (1, "reader_process: couldn't open pipe!\n");
1998141cc406Sopenharmony_ci      return 1;
1999141cc406Sopenharmony_ci    }
2000141cc406Sopenharmony_ci
2001141cc406Sopenharmony_ci  DBG (10, "reader_process: starting to READ data\n");
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci  data_left = bytes_per_line (scanner) *
2004141cc406Sopenharmony_ci    lines_per_scan (scanner);
2005141cc406Sopenharmony_ci
2006141cc406Sopenharmony_ci  sp15c_trim_rowbufsize (scanner);      /* trim bufsize */
2007141cc406Sopenharmony_ci
2008141cc406Sopenharmony_ci  DBG (10, "reader_process: reading %u bytes in blocks of %u bytes\n",
2009141cc406Sopenharmony_ci       data_left, scanner->row_bufsize);
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci  act.sa_handler = sigterm_handler;
2014141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
2015141cc406Sopenharmony_ci  /* wait_scanner(scanner); */
2016141cc406Sopenharmony_ci  do
2017141cc406Sopenharmony_ci    {
2018141cc406Sopenharmony_ci      data_to_read = (data_left < scanner->row_bufsize)
2019141cc406Sopenharmony_ci        ? data_left
2020141cc406Sopenharmony_ci        : scanner->row_bufsize;
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci      if (scanner->composition == WD_comp_G4)
2023141cc406Sopenharmony_ci        {
2024141cc406Sopenharmony_ci          data_to_read /= 2;    /* 'cause each byte holds two pixels */
2025141cc406Sopenharmony_ci        }
2026141cc406Sopenharmony_ci      status = sp15c_read_data_block (scanner, data_to_read);
2027141cc406Sopenharmony_ci      if (status == 0)
2028141cc406Sopenharmony_ci        {
2029141cc406Sopenharmony_ci          DBG (1, "reader_process: no data yet\n");
2030141cc406Sopenharmony_ci          fflush (stdout);
2031141cc406Sopenharmony_ci          fflush (stderr);
2032141cc406Sopenharmony_ci          usleep (50000);
2033141cc406Sopenharmony_ci          continue;
2034141cc406Sopenharmony_ci        }
2035141cc406Sopenharmony_ci      if (status == -1)
2036141cc406Sopenharmony_ci        {
2037141cc406Sopenharmony_ci          DBG (1, "reader_process: unable to get image data from scanner!\n");
2038141cc406Sopenharmony_ci          fflush (stdout);
2039141cc406Sopenharmony_ci          fflush (stderr);
2040141cc406Sopenharmony_ci          fclose (fp);
2041141cc406Sopenharmony_ci          return (-1);
2042141cc406Sopenharmony_ci        }
2043141cc406Sopenharmony_ci
2044141cc406Sopenharmony_ci      /* expand 4-bit pixels to 8-bit bytes */
2045141cc406Sopenharmony_ci      if (scanner->composition == WD_comp_G4)
2046141cc406Sopenharmony_ci        {
2047141cc406Sopenharmony_ci          src = &scanner->buffer[data_to_read - 1];
2048141cc406Sopenharmony_ci          dst = &scanner->buffer[data_to_read * 2 - 1];
2049141cc406Sopenharmony_ci          for (i = 0; i < data_to_read; i++)
2050141cc406Sopenharmony_ci            {
2051141cc406Sopenharmony_ci              *dst-- = ((*src << 4) & 0xf0) + ((*src)        & 0x0f);
2052141cc406Sopenharmony_ci              *dst-- = ((*src)      & 0xf0) + ((*src >> 4) & 0x0f);
2053141cc406Sopenharmony_ci	      --src;
2054141cc406Sopenharmony_ci            }
2055141cc406Sopenharmony_ci          data_to_read *= 2;
2056141cc406Sopenharmony_ci        }
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci      fwrite (scanner->buffer, 1, data_to_read, fp);
2059141cc406Sopenharmony_ci      fflush (fp);
2060141cc406Sopenharmony_ci
2061141cc406Sopenharmony_ci      data_left -= data_to_read;
2062141cc406Sopenharmony_ci      DBG (10, "reader_process: buffer of %d bytes read; %d bytes to go\n",
2063141cc406Sopenharmony_ci           data_to_read, data_left);
2064141cc406Sopenharmony_ci      fflush (stdout);
2065141cc406Sopenharmony_ci      fflush (stderr);
2066141cc406Sopenharmony_ci    }
2067141cc406Sopenharmony_ci  while (data_left);
2068141cc406Sopenharmony_ci
2069141cc406Sopenharmony_ci  fclose (fp);
2070141cc406Sopenharmony_ci
2071141cc406Sopenharmony_ci  DBG (10, "reader_process: finished\n");
2072141cc406Sopenharmony_ci
2073141cc406Sopenharmony_ci  return 0;
2074141cc406Sopenharmony_ci}                               /* reader_process */
2075141cc406Sopenharmony_ci
2076141cc406Sopenharmony_cistatic SANE_Status
2077141cc406Sopenharmony_cido_eof (struct sp15c *scanner)
2078141cc406Sopenharmony_ci{
2079141cc406Sopenharmony_ci  DBG (10, "do_eof\n");
2080141cc406Sopenharmony_ci
2081141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
2082141cc406Sopenharmony_ci  if (scanner->pipe >= 0)
2083141cc406Sopenharmony_ci    {
2084141cc406Sopenharmony_ci      close (scanner->pipe);
2085141cc406Sopenharmony_ci      scanner->pipe = -1;
2086141cc406Sopenharmony_ci    }
2087141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
2088141cc406Sopenharmony_ci}                               /* do_eof */
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_cistatic int
2091141cc406Sopenharmony_cipixels_per_line (struct sp15c *s)
2092141cc406Sopenharmony_ci{
2093141cc406Sopenharmony_ci  int pixels;
2094141cc406Sopenharmony_ci  pixels = s->x_res * (s->br_x - s->tl_x) / 1200;
2095141cc406Sopenharmony_ci  return pixels;
2096141cc406Sopenharmony_ci}                               /* pixels_per_line */
2097141cc406Sopenharmony_ci
2098141cc406Sopenharmony_cistatic int
2099141cc406Sopenharmony_cilines_per_scan (struct sp15c *s)
2100141cc406Sopenharmony_ci{
2101141cc406Sopenharmony_ci  int lines;
2102141cc406Sopenharmony_ci  lines = s->y_res * (s->br_y - s->tl_y) / 1200;
2103141cc406Sopenharmony_ci  return lines;
2104141cc406Sopenharmony_ci}                               /* lines_per_scan */
2105141cc406Sopenharmony_ci
2106141cc406Sopenharmony_cistatic int
2107141cc406Sopenharmony_cibytes_per_line (struct sp15c *s)
2108141cc406Sopenharmony_ci{
2109141cc406Sopenharmony_ci  int bytes;
2110141cc406Sopenharmony_ci  /* SEE PAGE 29 OF SANE SPEC!!! */
2111141cc406Sopenharmony_ci  if (s->bitsperpixel == 1)
2112141cc406Sopenharmony_ci    {
2113141cc406Sopenharmony_ci      bytes = (pixels_per_line (s) + 7) / 8;
2114141cc406Sopenharmony_ci    }
2115141cc406Sopenharmony_ci  else
2116141cc406Sopenharmony_ci    {
2117141cc406Sopenharmony_ci      bytes = pixels_per_line (s);
2118141cc406Sopenharmony_ci    }
2119141cc406Sopenharmony_ci  if (s->composition == WD_comp_MC)
2120141cc406Sopenharmony_ci    {
2121141cc406Sopenharmony_ci      bytes *= 3;
2122141cc406Sopenharmony_ci    }
2123141cc406Sopenharmony_ci  return bytes;
2124141cc406Sopenharmony_ci}                               /* bytes_per_line */
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_cistatic void
2127141cc406Sopenharmony_cisp15c_trim_rowbufsize (struct sp15c *s)
2128141cc406Sopenharmony_ci{
2129141cc406Sopenharmony_ci  unsigned int row_len;
2130141cc406Sopenharmony_ci  row_len = bytes_per_line (s);
2131141cc406Sopenharmony_ci  if (s->row_bufsize >= row_len)
2132141cc406Sopenharmony_ci    {
2133141cc406Sopenharmony_ci      s->row_bufsize = s->row_bufsize - (s->row_bufsize % row_len);
2134141cc406Sopenharmony_ci      DBG (10, "trim_rowbufsize to %d (%d lines)\n",
2135141cc406Sopenharmony_ci           s->row_bufsize, s->row_bufsize / row_len);
2136141cc406Sopenharmony_ci    }
2137141cc406Sopenharmony_ci}                               /* sp15c_trim_rowbufsize */
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_cistatic int
2140141cc406Sopenharmony_cisp15c_read_data_block (struct sp15c *s, unsigned int length)
2141141cc406Sopenharmony_ci{
2142141cc406Sopenharmony_ci  int r;
2143141cc406Sopenharmony_ci
2144141cc406Sopenharmony_ci  DBG (10, "sp15c_read_data_block (length = %d)\n", length);
2145141cc406Sopenharmony_ci  /*wait_scanner(s); */
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci  set_R_datatype_code (readB.cmd, R_datatype_imagedata);
2148141cc406Sopenharmony_ci  set_R_xfer_length (readB.cmd, length);
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci  r = do_scsi_cmd (s->sfd, readB.cmd, readB.size, s->buffer, length);
2151141cc406Sopenharmony_ci#if 0
2152141cc406Sopenharmony_ci  return ((r != 0) ? -1 : length);
2153141cc406Sopenharmony_ci#else
2154141cc406Sopenharmony_ci  if (r)
2155141cc406Sopenharmony_ci    {
2156141cc406Sopenharmony_ci      return -1;
2157141cc406Sopenharmony_ci    }
2158141cc406Sopenharmony_ci  else
2159141cc406Sopenharmony_ci    {
2160141cc406Sopenharmony_ci      return length;
2161141cc406Sopenharmony_ci    }
2162141cc406Sopenharmony_ci#endif
2163141cc406Sopenharmony_ci}                               /* sp15c_read_data_block */
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci/*  Increase initial width by increasing bottom right X
2166141cc406Sopenharmony_ci *  until we have a HAPPY number of bytes in line.
2167141cc406Sopenharmony_ci *  Should be called whenever s->composition, s->x_res,
2168141cc406Sopenharmony_ci *  s->br_x, or s->tl_x are changed */
2169141cc406Sopenharmony_cistatic void
2170141cc406Sopenharmony_ciadjust_width (struct sp15c *s, SANE_Int * info)
2171141cc406Sopenharmony_ci{
2172141cc406Sopenharmony_ci  int pixels;
2173141cc406Sopenharmony_ci  int changed = 0;
2174141cc406Sopenharmony_ci  if (s->composition == WD_comp_MC)
2175141cc406Sopenharmony_ci    {
2176141cc406Sopenharmony_ci      while (pixels = s->x_res * (s->br_x - s->tl_x) / 1200,
2177141cc406Sopenharmony_ci             (s->bitsperpixel * pixels) % (8 * 4))
2178141cc406Sopenharmony_ci        {
2179141cc406Sopenharmony_ci          s->br_x--;
2180141cc406Sopenharmony_ci          changed++;
2181141cc406Sopenharmony_ci        }
2182141cc406Sopenharmony_ci    }
2183141cc406Sopenharmony_ci  else
2184141cc406Sopenharmony_ci    {
2185141cc406Sopenharmony_ci      while (pixels = s->x_res * (s->br_x - s->tl_x) / 1200,
2186141cc406Sopenharmony_ci             (s->bitsperpixel * pixels) % 8)
2187141cc406Sopenharmony_ci        {
2188141cc406Sopenharmony_ci          s->br_x--;
2189141cc406Sopenharmony_ci          changed++;
2190141cc406Sopenharmony_ci        }
2191141cc406Sopenharmony_ci    }
2192141cc406Sopenharmony_ci  if (changed && info)
2193141cc406Sopenharmony_ci    *info |= SANE_INFO_INEXACT;
2194141cc406Sopenharmony_ci
2195141cc406Sopenharmony_ci  return;
2196141cc406Sopenharmony_ci}                               /* adjust_width */
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_cistatic SANE_Status
2199141cc406Sopenharmony_ciapply_constraints (struct sp15c *scanner, SANE_Int opt,
2200141cc406Sopenharmony_ci                   SANE_Int * target, SANE_Word * info)
2201141cc406Sopenharmony_ci{
2202141cc406Sopenharmony_ci  SANE_Status status;
2203141cc406Sopenharmony_ci  status = sanei_constrain_value (scanner->opt + opt, target, info);
2204141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2205141cc406Sopenharmony_ci    {
2206141cc406Sopenharmony_ci      if (SANE_CONSTRAINT_RANGE ==
2207141cc406Sopenharmony_ci          scanner->opt[opt].constraint_type)
2208141cc406Sopenharmony_ci        {
2209141cc406Sopenharmony_ci          if (*target < scanner->opt[opt].constraint.range->min)
2210141cc406Sopenharmony_ci            {
2211141cc406Sopenharmony_ci              *target = scanner->opt[opt].constraint.range->min;
2212141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
2213141cc406Sopenharmony_ci            }
2214141cc406Sopenharmony_ci          else if (scanner->opt[opt].constraint.range->max < *target)
2215141cc406Sopenharmony_ci            {
2216141cc406Sopenharmony_ci              *target = scanner->opt[opt].constraint.range->max;
2217141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
2218141cc406Sopenharmony_ci            }
2219141cc406Sopenharmony_ci        }
2220141cc406Sopenharmony_ci      return status;
2221141cc406Sopenharmony_ci    }
2222141cc406Sopenharmony_ci  else
2223141cc406Sopenharmony_ci    {
2224141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2225141cc406Sopenharmony_ci    }
2226141cc406Sopenharmony_ci}                               /* apply_constraints */
2227141cc406Sopenharmony_ci
2228141cc406Sopenharmony_ci/******************************************************************************
2229141cc406Sopenharmony_ci}#############################################################################
2230141cc406Sopenharmony_ci******************************************************************************/
2231