1141cc406Sopenharmony_ci/* ========================================================================= */
2141cc406Sopenharmony_ci/*
3141cc406Sopenharmony_ci   SANE - Scanner Access Now Easy.
4141cc406Sopenharmony_ci   coolscan2.c , version 0.1.8
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   This file implements a SANE backend for Nikon Coolscan film scanners.
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci   Written by András Major (andras@users.sourceforge.net), 2001-2002.
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci   The developers wish to express their thanks to Nikon Corporation
47141cc406Sopenharmony_ci   for providing technical information and thus making this backend
48141cc406Sopenharmony_ci   possible.
49141cc406Sopenharmony_ci*/
50141cc406Sopenharmony_ci/* ========================================================================= */
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci/* ========================================================================= */
54141cc406Sopenharmony_ci/*
55141cc406Sopenharmony_ci   Revision log:
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci   0.1.9, 20/10/2005, ariel: added support for the LS-50/5000
58141cc406Sopenharmony_ci   0.1.8, 27/09/2002, andras: added subframe and load options
59141cc406Sopenharmony_ci   0.1.7, 22/08/2002, andras: added exposure correction option
60141cc406Sopenharmony_ci                                and hack for LS-40 IR readout
61141cc406Sopenharmony_ci   0.1.6, 14/06/2002, andras: types etc. fixed, fixes for LS-8000
62141cc406Sopenharmony_ci   0.1.5, 26/04/2002, andras: lots of minor fixes related to saned
63141cc406Sopenharmony_ci   0.1.4, 22/04/2002, andras: first version to be included in SANE CVS
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci*/
66141cc406Sopenharmony_ci/* ========================================================================= */
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci#ifdef _AIX
69141cc406Sopenharmony_ci# include "../include/lalloca.h"	/* MUST come first for AIX! */
70141cc406Sopenharmony_ci#endif
71141cc406Sopenharmony_ci#include "../include/sane/config.h"
72141cc406Sopenharmony_ci#include "../include/lalloca.h"
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci#include <math.h>
75141cc406Sopenharmony_ci#include <stdio.h>
76141cc406Sopenharmony_ci#include <stdlib.h>
77141cc406Sopenharmony_ci#include <string.h>
78141cc406Sopenharmony_ci#include <ctype.h>
79141cc406Sopenharmony_ci#include <unistd.h>
80141cc406Sopenharmony_ci#include <time.h>
81141cc406Sopenharmony_ci/*
82141cc406Sopenharmony_ci#include <limits.h>
83141cc406Sopenharmony_ci#include <sys/types.h>
84141cc406Sopenharmony_ci*/
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci#include "../include/_stdint.h"
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci#include "../include/sane/sane.h"
89141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
90141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
91141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
92141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
93141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
94141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
95141cc406Sopenharmony_ci#define BACKEND_NAME coolscan2
96141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"	/* must be last */
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci#define CS2_VERSION_MAJOR 0
99141cc406Sopenharmony_ci#define CS2_VERSION_MINOR 1
100141cc406Sopenharmony_ci#define CS2_REVISION 8
101141cc406Sopenharmony_ci#define CS2_CONFIG_FILE "coolscan2.conf"
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci#define WSIZE (sizeof (SANE_Word))
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci/*
106141cc406Sopenharmony_ci#define CS2_BLEEDING_EDGE
107141cc406Sopenharmony_ci*/
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_ci/* ========================================================================= */
111141cc406Sopenharmony_ci/* typedefs */
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_citypedef enum
114141cc406Sopenharmony_ci{
115141cc406Sopenharmony_ci  CS2_TYPE_UNKOWN,
116141cc406Sopenharmony_ci  CS2_TYPE_LS30,
117141cc406Sopenharmony_ci  CS2_TYPE_LS40,
118141cc406Sopenharmony_ci  CS2_TYPE_LS50,
119141cc406Sopenharmony_ci  CS2_TYPE_LS2000,
120141cc406Sopenharmony_ci  CS2_TYPE_LS4000,
121141cc406Sopenharmony_ci  CS2_TYPE_LS5000,
122141cc406Sopenharmony_ci  CS2_TYPE_LS8000
123141cc406Sopenharmony_ci}
124141cc406Sopenharmony_cics2_type_t;
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_citypedef enum
127141cc406Sopenharmony_ci{
128141cc406Sopenharmony_ci  CS2_INTERFACE_UNKNOWN,
129141cc406Sopenharmony_ci  CS2_INTERFACE_SCSI,		/* includes IEEE1394 via SBP2 */
130141cc406Sopenharmony_ci  CS2_INTERFACE_USB
131141cc406Sopenharmony_ci}
132141cc406Sopenharmony_cics2_interface_t;
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_citypedef enum
135141cc406Sopenharmony_ci{
136141cc406Sopenharmony_ci  CS2_PHASE_NONE = 0x00,
137141cc406Sopenharmony_ci  CS2_PHASE_STATUS = 0x01,
138141cc406Sopenharmony_ci  CS2_PHASE_OUT = 0x02,
139141cc406Sopenharmony_ci  CS2_PHASE_IN = 0x03,
140141cc406Sopenharmony_ci  CS2_PHASE_BUSY = 0x04
141141cc406Sopenharmony_ci}
142141cc406Sopenharmony_cics2_phase_t;
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_citypedef enum
145141cc406Sopenharmony_ci{
146141cc406Sopenharmony_ci  CS2_SCAN_NORMAL,
147141cc406Sopenharmony_ci  CS2_SCAN_AE,
148141cc406Sopenharmony_ci  CS2_SCAN_AE_WB
149141cc406Sopenharmony_ci}
150141cc406Sopenharmony_cics2_scan_t;
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_citypedef enum
153141cc406Sopenharmony_ci{
154141cc406Sopenharmony_ci  CS2_INFRARED_OFF,
155141cc406Sopenharmony_ci  CS2_INFRARED_IN,
156141cc406Sopenharmony_ci  CS2_INFRARED_OUT
157141cc406Sopenharmony_ci}
158141cc406Sopenharmony_cics2_infrared_t;
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_citypedef enum
161141cc406Sopenharmony_ci{
162141cc406Sopenharmony_ci  CS2_STATUS_READY = 0,
163141cc406Sopenharmony_ci  CS2_STATUS_BUSY = 1,
164141cc406Sopenharmony_ci  CS2_STATUS_NO_DOCS = 2,
165141cc406Sopenharmony_ci  CS2_STATUS_PROCESSING = 4,
166141cc406Sopenharmony_ci  CS2_STATUS_ERROR = 8,
167141cc406Sopenharmony_ci  CS2_STATUS_REISSUE = 16,
168141cc406Sopenharmony_ci  CS2_STATUS_ALL = 31		/* sum of all others */
169141cc406Sopenharmony_ci}
170141cc406Sopenharmony_cics2_status_t;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_citypedef enum
173141cc406Sopenharmony_ci{
174141cc406Sopenharmony_ci  CS2_OPTION_NUM = 0,
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci  CS2_OPTION_PREVIEW,
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci  CS2_OPTION_NEGATIVE,
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci  CS2_OPTION_INFRARED,
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci  CS2_OPTION_SAMPLES_PER_SCAN,
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci  CS2_OPTION_DEPTH,
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci  CS2_OPTION_EXPOSURE,
187141cc406Sopenharmony_ci  CS2_OPTION_EXPOSURE_R,
188141cc406Sopenharmony_ci  CS2_OPTION_EXPOSURE_G,
189141cc406Sopenharmony_ci  CS2_OPTION_EXPOSURE_B,
190141cc406Sopenharmony_ci  CS2_OPTION_SCAN_AE,
191141cc406Sopenharmony_ci  CS2_OPTION_SCAN_AE_WB,
192141cc406Sopenharmony_ci
193141cc406Sopenharmony_ci  CS2_OPTION_LUT_R,
194141cc406Sopenharmony_ci  CS2_OPTION_LUT_G,
195141cc406Sopenharmony_ci  CS2_OPTION_LUT_B,
196141cc406Sopenharmony_ci
197141cc406Sopenharmony_ci  CS2_OPTION_RES,
198141cc406Sopenharmony_ci  CS2_OPTION_RESX,
199141cc406Sopenharmony_ci  CS2_OPTION_RESY,
200141cc406Sopenharmony_ci  CS2_OPTION_RES_INDEPENDENT,
201141cc406Sopenharmony_ci
202141cc406Sopenharmony_ci  CS2_OPTION_PREVIEW_RESOLUTION,
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci  CS2_OPTION_FRAME,
205141cc406Sopenharmony_ci  CS2_OPTION_SUBFRAME,
206141cc406Sopenharmony_ci  CS2_OPTION_XMIN,
207141cc406Sopenharmony_ci  CS2_OPTION_XMAX,
208141cc406Sopenharmony_ci  CS2_OPTION_YMIN,
209141cc406Sopenharmony_ci  CS2_OPTION_YMAX,
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci  CS2_OPTION_LOAD,
212141cc406Sopenharmony_ci  CS2_OPTION_EJECT,
213141cc406Sopenharmony_ci  CS2_OPTION_RESET,
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci  CS2_OPTION_FOCUS_ON_CENTRE,
216141cc406Sopenharmony_ci  CS2_OPTION_FOCUS,
217141cc406Sopenharmony_ci  CS2_OPTION_AUTOFOCUS,
218141cc406Sopenharmony_ci  CS2_OPTION_FOCUSX,
219141cc406Sopenharmony_ci  CS2_OPTION_FOCUSY,
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci  CS2_N_OPTIONS			/* must be last -- counts number of enum items */
222141cc406Sopenharmony_ci}
223141cc406Sopenharmony_cics2_option_t;
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_citypedef unsigned int cs2_pixel_t;
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_citypedef struct
228141cc406Sopenharmony_ci{
229141cc406Sopenharmony_ci  /* interface */
230141cc406Sopenharmony_ci  cs2_interface_t interface;
231141cc406Sopenharmony_ci  int fd;
232141cc406Sopenharmony_ci  SANE_Byte *send_buf, *recv_buf;
233141cc406Sopenharmony_ci  size_t send_buf_size, recv_buf_size;
234141cc406Sopenharmony_ci  size_t n_cmd, n_send, n_recv;
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci  /* device characteristics */
237141cc406Sopenharmony_ci  char vendor_string[9], product_string[17], revision_string[5];
238141cc406Sopenharmony_ci  cs2_type_t type;
239141cc406Sopenharmony_ci  int maxbits;
240141cc406Sopenharmony_ci  unsigned int resx_optical, resx_min, resx_max, *resx_list, resx_n_list;
241141cc406Sopenharmony_ci  unsigned int resy_optical, resy_min, resy_max, *resy_list, resy_n_list;
242141cc406Sopenharmony_ci  unsigned long boundaryx, boundaryy;
243141cc406Sopenharmony_ci  unsigned long frame_offset;
244141cc406Sopenharmony_ci  unsigned int unit_dpi;
245141cc406Sopenharmony_ci  double unit_mm;
246141cc406Sopenharmony_ci  int n_frames;
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci  int focus_min, focus_max;
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci  /* settings */
251141cc406Sopenharmony_ci  SANE_Bool preview, negative, infrared;
252141cc406Sopenharmony_ci  int samples_per_scan, depth, real_depth, bytes_per_pixel, shift_bits,
253141cc406Sopenharmony_ci	n_colour_in, n_colour_out;
254141cc406Sopenharmony_ci  cs2_pixel_t n_lut;
255141cc406Sopenharmony_ci  cs2_pixel_t *lut_r, *lut_g, *lut_b, *lut_neutral;
256141cc406Sopenharmony_ci  unsigned long resx, resy, res, res_independent, res_preview;
257141cc406Sopenharmony_ci  unsigned long xmin, xmax, ymin, ymax;
258141cc406Sopenharmony_ci  int i_frame;
259141cc406Sopenharmony_ci  double subframe;
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  unsigned int real_resx, real_resy, real_pitchx, real_pitchy;
262141cc406Sopenharmony_ci  unsigned long real_xoffset, real_yoffset, real_width, real_height,
263141cc406Sopenharmony_ci    logical_width, logical_height;
264141cc406Sopenharmony_ci  int odd_padding;
265141cc406Sopenharmony_ci  int block_padding;
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci  double exposure, exposure_r, exposure_g, exposure_b;
268141cc406Sopenharmony_ci  unsigned long real_exposure[10];
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci  SANE_Bool focus_on_centre;
271141cc406Sopenharmony_ci  unsigned long focusx, focusy, real_focusx, real_focusy;
272141cc406Sopenharmony_ci  int focus;
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci  /* status */
275141cc406Sopenharmony_ci  SANE_Bool scanning;
276141cc406Sopenharmony_ci  cs2_infrared_t infrared_stage, infrared_next;
277141cc406Sopenharmony_ci  SANE_Byte *infrared_buf;
278141cc406Sopenharmony_ci  size_t n_infrared_buf, infrared_index;
279141cc406Sopenharmony_ci  SANE_Byte *line_buf;
280141cc406Sopenharmony_ci  ssize_t n_line_buf, i_line_buf;
281141cc406Sopenharmony_ci  unsigned long sense_key, sense_asc, sense_ascq, sense_info;
282141cc406Sopenharmony_ci  unsigned long sense_code;
283141cc406Sopenharmony_ci  cs2_status_t status;
284141cc406Sopenharmony_ci  size_t xfer_position, xfer_bytes_total;
285141cc406Sopenharmony_ci
286141cc406Sopenharmony_ci  /* SANE stuff */
287141cc406Sopenharmony_ci  SANE_Option_Descriptor option_list[CS2_N_OPTIONS];
288141cc406Sopenharmony_ci}
289141cc406Sopenharmony_cics2_t;
290141cc406Sopenharmony_ci
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci/* ========================================================================= */
293141cc406Sopenharmony_ci/* prototypes */
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_cistatic SANE_Status cs2_open (const char *device, cs2_interface_t interface,
296141cc406Sopenharmony_ci			     cs2_t ** sp);
297141cc406Sopenharmony_cistatic void cs2_close (cs2_t * s);
298141cc406Sopenharmony_cistatic SANE_Status cs2_attach (const char *dev);
299141cc406Sopenharmony_cistatic SANE_Status cs2_scsi_sense_handler (int fd, u_char * sense_buffer,
300141cc406Sopenharmony_ci					   void *arg);
301141cc406Sopenharmony_cistatic SANE_Status cs2_parse_sense_data (cs2_t * s);
302141cc406Sopenharmony_cistatic void cs2_init_buffer (cs2_t * s);
303141cc406Sopenharmony_cistatic SANE_Status cs2_pack_byte (cs2_t * s, SANE_Byte byte);
304141cc406Sopenharmony_cistatic SANE_Status cs2_parse_cmd (cs2_t * s, char *text);
305141cc406Sopenharmony_cistatic SANE_Status cs2_grow_send_buffer (cs2_t * s);
306141cc406Sopenharmony_cistatic SANE_Status cs2_issue_cmd (cs2_t * s);
307141cc406Sopenharmony_cistatic cs2_phase_t cs2_phase_check (cs2_t * s);
308141cc406Sopenharmony_cistatic SANE_Status cs2_set_boundary (cs2_t *s);
309141cc406Sopenharmony_cistatic SANE_Status cs2_scanner_ready (cs2_t * s, int flags);
310141cc406Sopenharmony_cistatic SANE_Status cs2_page_inquiry (cs2_t * s, int page);
311141cc406Sopenharmony_cistatic SANE_Status cs2_full_inquiry (cs2_t * s);
312141cc406Sopenharmony_cistatic SANE_Status cs2_execute (cs2_t * s);
313141cc406Sopenharmony_cistatic SANE_Status cs2_load (cs2_t * s);
314141cc406Sopenharmony_cistatic SANE_Status cs2_eject (cs2_t * s);
315141cc406Sopenharmony_cistatic SANE_Status cs2_reset (cs2_t * s);
316141cc406Sopenharmony_cistatic SANE_Status cs2_focus (cs2_t * s);
317141cc406Sopenharmony_cistatic SANE_Status cs2_autofocus (cs2_t * s);
318141cc406Sopenharmony_cistatic SANE_Status cs2_get_exposure (cs2_t * s);
319141cc406Sopenharmony_cistatic SANE_Status cs2_convert_options (cs2_t * s);
320141cc406Sopenharmony_cistatic SANE_Status cs2_scan (cs2_t * s, cs2_scan_t type);
321141cc406Sopenharmony_cistatic void *cs2_xmalloc (size_t size);
322141cc406Sopenharmony_cistatic void *cs2_xrealloc (void *p, size_t size);
323141cc406Sopenharmony_cistatic void cs2_xfree (const void *p);
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci/* ========================================================================= */
327141cc406Sopenharmony_ci/* global variables */
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_cistatic int cs2_colour_list[] = { 1, 2, 3, 9 };
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_cistatic SANE_Device **device_list = NULL;
332141cc406Sopenharmony_cistatic int n_device_list = 0;
333141cc406Sopenharmony_cistatic cs2_interface_t try_interface = CS2_INTERFACE_UNKNOWN;
334141cc406Sopenharmony_cistatic int open_devices = 0;
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci/* ========================================================================= */
338141cc406Sopenharmony_ci/* SANE entry points */
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_ciSANE_Status
341141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
342141cc406Sopenharmony_ci{
343141cc406Sopenharmony_ci  DBG_INIT ();
344141cc406Sopenharmony_ci  DBG (10, "sane_init() called.\n");
345141cc406Sopenharmony_ci  DBG (1, "coolscan2 backend, version %i.%i.%i initializing.\n", CS2_VERSION_MAJOR, CS2_VERSION_MINOR, CS2_REVISION);
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci  (void) authorize;		/* to shut up compiler */
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci  if (version_code)
350141cc406Sopenharmony_ci    *version_code =
351141cc406Sopenharmony_ci      SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci  sanei_usb_init ();
354141cc406Sopenharmony_ci
355141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
356141cc406Sopenharmony_ci}
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_civoid
359141cc406Sopenharmony_cisane_exit (void)
360141cc406Sopenharmony_ci{
361141cc406Sopenharmony_ci  int i;
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci  DBG (10, "sane_exit() called.\n");
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  for (i = 0; i < n_device_list; i++)
366141cc406Sopenharmony_ci    {
367141cc406Sopenharmony_ci      cs2_xfree (device_list[i]->name);
368141cc406Sopenharmony_ci      cs2_xfree (device_list[i]->vendor);
369141cc406Sopenharmony_ci      cs2_xfree (device_list[i]->model);
370141cc406Sopenharmony_ci      cs2_xfree (device_list[i]);
371141cc406Sopenharmony_ci    }
372141cc406Sopenharmony_ci  cs2_xfree (device_list);
373141cc406Sopenharmony_ci}
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ciSANE_Status
376141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** list, SANE_Bool local_only)
377141cc406Sopenharmony_ci{
378141cc406Sopenharmony_ci  char line[PATH_MAX], *p;
379141cc406Sopenharmony_ci  FILE *config;
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci  (void) local_only;		/* to shut up compiler */
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci  DBG (10, "sane_get_devices() called.\n");
384141cc406Sopenharmony_ci
385141cc406Sopenharmony_ci  if (device_list)
386141cc406Sopenharmony_ci    DBG (6,
387141cc406Sopenharmony_ci	 "sane_get_devices(): Device list already populated, not probing again.\n");
388141cc406Sopenharmony_ci  else
389141cc406Sopenharmony_ci    {
390141cc406Sopenharmony_ci      if (open_devices)
391141cc406Sopenharmony_ci	{
392141cc406Sopenharmony_ci	  DBG (4,
393141cc406Sopenharmony_ci	       "sane_get_devices(): Devices open, not scanning for scanners.\n");
394141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
395141cc406Sopenharmony_ci	}
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci      config = sanei_config_open (CS2_CONFIG_FILE);
398141cc406Sopenharmony_ci      if (config)
399141cc406Sopenharmony_ci	{
400141cc406Sopenharmony_ci	  DBG (4, "sane_get_devices(): Reading config file.\n");
401141cc406Sopenharmony_ci	  while (sanei_config_read (line, sizeof (line), config))
402141cc406Sopenharmony_ci	    {
403141cc406Sopenharmony_ci	      p = line;
404141cc406Sopenharmony_ci	      p += strspn (line, " \t");
405141cc406Sopenharmony_ci	      if (strlen (p) && (p[0] != '\n') && (p[0] != '#'))
406141cc406Sopenharmony_ci		cs2_open (line, CS2_INTERFACE_UNKNOWN, NULL);
407141cc406Sopenharmony_ci	    }
408141cc406Sopenharmony_ci	  fclose (config);
409141cc406Sopenharmony_ci	}
410141cc406Sopenharmony_ci      else
411141cc406Sopenharmony_ci	{
412141cc406Sopenharmony_ci	  DBG (4, "sane_get_devices(): No config file found.\n");
413141cc406Sopenharmony_ci	  cs2_open ("auto", CS2_INTERFACE_UNKNOWN, NULL);
414141cc406Sopenharmony_ci	}
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci      switch (n_device_list)
417141cc406Sopenharmony_ci	{
418141cc406Sopenharmony_ci	case 0:
419141cc406Sopenharmony_ci	  DBG (6, "sane_get_devices(): No devices detected.\n");
420141cc406Sopenharmony_ci	  break;
421141cc406Sopenharmony_ci	case 1:
422141cc406Sopenharmony_ci	  DBG (6, "sane_get_devices(): 1 device detected.\n");
423141cc406Sopenharmony_ci	  break;
424141cc406Sopenharmony_ci	default:
425141cc406Sopenharmony_ci	  DBG (6, "sane_get_devices(): %i devices detected.\n",
426141cc406Sopenharmony_ci	       n_device_list);
427141cc406Sopenharmony_ci	  break;
428141cc406Sopenharmony_ci	}
429141cc406Sopenharmony_ci    }
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci  *list = (const SANE_Device **) device_list;
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
434141cc406Sopenharmony_ci}
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ciSANE_Status
437141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * h)
438141cc406Sopenharmony_ci{
439141cc406Sopenharmony_ci  SANE_Status status;
440141cc406Sopenharmony_ci  cs2_t *s;
441141cc406Sopenharmony_ci  int i_option;
442141cc406Sopenharmony_ci  unsigned int i_list;
443141cc406Sopenharmony_ci  SANE_Option_Descriptor o;
444141cc406Sopenharmony_ci  SANE_Word *word_list;
445141cc406Sopenharmony_ci  SANE_Range *range = NULL;
446141cc406Sopenharmony_ci  int alloc_failed = 0;
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci  DBG (10, "sane_open() called.\n");
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci  status = cs2_open (name, CS2_INTERFACE_UNKNOWN, &s);
451141cc406Sopenharmony_ci  if (status)
452141cc406Sopenharmony_ci    return status;
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci  *h = (SANE_Handle) s;
455141cc406Sopenharmony_ci
456141cc406Sopenharmony_ci  /* get device properties */
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci  s->lut_r = s->lut_g = s->lut_b = s->lut_neutral = NULL;
459141cc406Sopenharmony_ci  s->resx_list = s->resy_list = NULL;
460141cc406Sopenharmony_ci  s->resx_n_list = s->resy_n_list = 0;
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci  status = cs2_full_inquiry (s);
463141cc406Sopenharmony_ci  if (status)
464141cc406Sopenharmony_ci    return status;
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci  /* option descriptors */
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci  for (i_option = 0; i_option < CS2_N_OPTIONS; i_option++)
469141cc406Sopenharmony_ci    {
470141cc406Sopenharmony_ci      o.name = o.title = o.desc = NULL;
471141cc406Sopenharmony_ci      o.type = SANE_TYPE_BOOL;
472141cc406Sopenharmony_ci      o.unit = SANE_UNIT_NONE;
473141cc406Sopenharmony_ci      o.size = o.cap = 0;
474141cc406Sopenharmony_ci      o.constraint_type = SANE_CONSTRAINT_NONE;
475141cc406Sopenharmony_ci      o.constraint.range = NULL;	/* only one union member needs to be NULLed */
476141cc406Sopenharmony_ci      switch (i_option)
477141cc406Sopenharmony_ci	{
478141cc406Sopenharmony_ci	case CS2_OPTION_NUM:
479141cc406Sopenharmony_ci	  o.name = "";
480141cc406Sopenharmony_ci	  o.title = SANE_TITLE_NUM_OPTIONS;
481141cc406Sopenharmony_ci	  o.desc = SANE_DESC_NUM_OPTIONS;
482141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
483141cc406Sopenharmony_ci	  o.size = WSIZE;
484141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_DETECT;
485141cc406Sopenharmony_ci	  break;
486141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW:
487141cc406Sopenharmony_ci	  o.name = "preview";
488141cc406Sopenharmony_ci	  o.title = "Preview mode";
489141cc406Sopenharmony_ci	  o.desc = "Preview mode";
490141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BOOL;
491141cc406Sopenharmony_ci	  o.size = WSIZE;
492141cc406Sopenharmony_ci	  o.cap =
493141cc406Sopenharmony_ci	    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
494141cc406Sopenharmony_ci	  break;
495141cc406Sopenharmony_ci	case CS2_OPTION_NEGATIVE:
496141cc406Sopenharmony_ci	  o.name = "negative";
497141cc406Sopenharmony_ci	  o.title = "Negative";
498141cc406Sopenharmony_ci	  o.desc = "Negative film: make scanner invert colours";
499141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BOOL;
500141cc406Sopenharmony_ci	  o.size = WSIZE;
501141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
502141cc406Sopenharmony_ci#ifndef CS2_BLEEDING_EDGE
503141cc406Sopenharmony_ci	  o.cap |= SANE_CAP_INACTIVE;
504141cc406Sopenharmony_ci#endif
505141cc406Sopenharmony_ci	  break;
506141cc406Sopenharmony_ci	case CS2_OPTION_INFRARED:
507141cc406Sopenharmony_ci	  o.name = "infrared";
508141cc406Sopenharmony_ci	  o.title = "Read infrared channel";
509141cc406Sopenharmony_ci	  o.desc = "Read infrared channel in addition to scan colours";
510141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BOOL;
511141cc406Sopenharmony_ci	  o.size = WSIZE;
512141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
513141cc406Sopenharmony_ci	  break;
514141cc406Sopenharmony_ci	case CS2_OPTION_SAMPLES_PER_SCAN:
515141cc406Sopenharmony_ci	  o.name = "samples-per-scan";
516141cc406Sopenharmony_ci	  o.title = "Samples per Scan";
517141cc406Sopenharmony_ci	  o.desc = "Number of samples per scan";
518141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
519141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_NONE;
520141cc406Sopenharmony_ci	  o.size = WSIZE;
521141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
522141cc406Sopenharmony_ci	  if (s->type != CS2_TYPE_LS2000 && s->type != CS2_TYPE_LS4000
523141cc406Sopenharmony_ci		  && s->type != CS2_TYPE_LS5000 && s->type != CS2_TYPE_LS8000)
524141cc406Sopenharmony_ci		o.cap |= SANE_CAP_INACTIVE;
525141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
526141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
527141cc406Sopenharmony_ci	  if (! range)
528141cc406Sopenharmony_ci		alloc_failed = 1;
529141cc406Sopenharmony_ci	  else
530141cc406Sopenharmony_ci		{
531141cc406Sopenharmony_ci		  range->min = 1;
532141cc406Sopenharmony_ci		  range->max = 16;
533141cc406Sopenharmony_ci		  range->quant = 1;
534141cc406Sopenharmony_ci		  o.constraint.range = range;
535141cc406Sopenharmony_ci		}
536141cc406Sopenharmony_ci	  break;
537141cc406Sopenharmony_ci	case CS2_OPTION_DEPTH:
538141cc406Sopenharmony_ci	  o.name = "depth";
539141cc406Sopenharmony_ci	  o.title = "Bit depth per channel";
540141cc406Sopenharmony_ci	  o.desc = "Number of bits output by scanner for each channel";
541141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
542141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_NONE;
543141cc406Sopenharmony_ci	  o.size = WSIZE;
544141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
545141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_WORD_LIST;
546141cc406Sopenharmony_ci	  word_list = (SANE_Word *) cs2_xmalloc (2 * sizeof (SANE_Word));
547141cc406Sopenharmony_ci	  if (!word_list)
548141cc406Sopenharmony_ci	    alloc_failed = 1;
549141cc406Sopenharmony_ci	  else
550141cc406Sopenharmony_ci	    {
551141cc406Sopenharmony_ci	      word_list[1] = 8;
552141cc406Sopenharmony_ci	      word_list[2] = s->maxbits;
553141cc406Sopenharmony_ci	      word_list[0] = 2;
554141cc406Sopenharmony_ci	      o.constraint.word_list = word_list;
555141cc406Sopenharmony_ci	    }
556141cc406Sopenharmony_ci	  break;
557141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE:
558141cc406Sopenharmony_ci	  o.name = "exposure";
559141cc406Sopenharmony_ci	  o.title = "Exposure multiplier";
560141cc406Sopenharmony_ci	  o.desc = "Exposure multiplier for all channels";
561141cc406Sopenharmony_ci	  o.type = SANE_TYPE_FIXED;
562141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_NONE;
563141cc406Sopenharmony_ci	  o.size = WSIZE;
564141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
565141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
566141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
567141cc406Sopenharmony_ci	  if (!range)
568141cc406Sopenharmony_ci	    alloc_failed = 1;
569141cc406Sopenharmony_ci	  else
570141cc406Sopenharmony_ci	    {
571141cc406Sopenharmony_ci	      range->min = SANE_FIX (0.);
572141cc406Sopenharmony_ci	      range->max = SANE_FIX (10.);
573141cc406Sopenharmony_ci	      range->quant = SANE_FIX (0.1);
574141cc406Sopenharmony_ci	      o.constraint.range = range;
575141cc406Sopenharmony_ci	    }
576141cc406Sopenharmony_ci	  break;
577141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_R:
578141cc406Sopenharmony_ci	  o.name = "red-exposure";
579141cc406Sopenharmony_ci	  o.title = "Red exposure time";
580141cc406Sopenharmony_ci	  o.desc = "Exposure time for red channel";
581141cc406Sopenharmony_ci	  o.type = SANE_TYPE_FIXED;
582141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_MICROSECOND;
583141cc406Sopenharmony_ci	  o.size = WSIZE;
584141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
585141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
586141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
587141cc406Sopenharmony_ci	  if (!range)
588141cc406Sopenharmony_ci	    alloc_failed = 1;
589141cc406Sopenharmony_ci	  else
590141cc406Sopenharmony_ci	    {
591141cc406Sopenharmony_ci	      range->min = SANE_FIX (50.);
592141cc406Sopenharmony_ci	      range->max = SANE_FIX (20000.);
593141cc406Sopenharmony_ci	      range->quant = SANE_FIX (10.);
594141cc406Sopenharmony_ci	      o.constraint.range = range;
595141cc406Sopenharmony_ci	    }
596141cc406Sopenharmony_ci	  break;
597141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_G:
598141cc406Sopenharmony_ci	  o.name = "green-exposure";
599141cc406Sopenharmony_ci	  o.title = "Green exposure time";
600141cc406Sopenharmony_ci	  o.desc = "Exposure time for green channel";
601141cc406Sopenharmony_ci	  o.type = SANE_TYPE_FIXED;
602141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_MICROSECOND;
603141cc406Sopenharmony_ci	  o.size = WSIZE;
604141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
605141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
606141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
607141cc406Sopenharmony_ci	  if (!range)
608141cc406Sopenharmony_ci	    alloc_failed = 1;
609141cc406Sopenharmony_ci	  else
610141cc406Sopenharmony_ci	    {
611141cc406Sopenharmony_ci	      range->min = SANE_FIX (50.);
612141cc406Sopenharmony_ci	      range->max = SANE_FIX (20000.);
613141cc406Sopenharmony_ci	      range->quant = SANE_FIX (10.);
614141cc406Sopenharmony_ci	      o.constraint.range = range;
615141cc406Sopenharmony_ci	    }
616141cc406Sopenharmony_ci	  break;
617141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_B:
618141cc406Sopenharmony_ci	  o.name = "blue-exposure";
619141cc406Sopenharmony_ci	  o.title = "Blue exposure time";
620141cc406Sopenharmony_ci	  o.desc = "Exposure time for blue channel";
621141cc406Sopenharmony_ci	  o.type = SANE_TYPE_FIXED;
622141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_MICROSECOND;
623141cc406Sopenharmony_ci	  o.size = WSIZE;
624141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
625141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
626141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
627141cc406Sopenharmony_ci	  if (!range)
628141cc406Sopenharmony_ci	    alloc_failed = 1;
629141cc406Sopenharmony_ci	  else
630141cc406Sopenharmony_ci	    {
631141cc406Sopenharmony_ci	      range->min = SANE_FIX (50.);
632141cc406Sopenharmony_ci	      range->max = SANE_FIX (20000.);
633141cc406Sopenharmony_ci	      range->quant = SANE_FIX (10.);
634141cc406Sopenharmony_ci	      o.constraint.range = range;
635141cc406Sopenharmony_ci	    }
636141cc406Sopenharmony_ci	  break;
637141cc406Sopenharmony_ci	case CS2_OPTION_LUT_R:
638141cc406Sopenharmony_ci	  o.name = "red-gamma-table";
639141cc406Sopenharmony_ci	  o.title = "LUT for red channel";
640141cc406Sopenharmony_ci	  o.desc = "LUT for red channel";
641141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
642141cc406Sopenharmony_ci	  o.size = s->n_lut * WSIZE;
643141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
644141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
645141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
646141cc406Sopenharmony_ci	  if (!range)
647141cc406Sopenharmony_ci	    alloc_failed = 1;
648141cc406Sopenharmony_ci	  else
649141cc406Sopenharmony_ci	    {
650141cc406Sopenharmony_ci	      range->min = 0;
651141cc406Sopenharmony_ci	      range->max = s->n_lut - 1;
652141cc406Sopenharmony_ci	      range->quant = 1;
653141cc406Sopenharmony_ci	      o.constraint.range = range;
654141cc406Sopenharmony_ci	    }
655141cc406Sopenharmony_ci	  break;
656141cc406Sopenharmony_ci	case CS2_OPTION_LUT_G:
657141cc406Sopenharmony_ci	  o.name = "green-gamma-table";
658141cc406Sopenharmony_ci	  o.title = "LUT for green channel";
659141cc406Sopenharmony_ci	  o.desc = "LUT for green channel";
660141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
661141cc406Sopenharmony_ci	  o.size = s->n_lut * WSIZE;
662141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
663141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
664141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
665141cc406Sopenharmony_ci	  if (!range)
666141cc406Sopenharmony_ci	    alloc_failed = 1;
667141cc406Sopenharmony_ci	  else
668141cc406Sopenharmony_ci	    {
669141cc406Sopenharmony_ci	      range->min = 0;
670141cc406Sopenharmony_ci	      range->max = s->n_lut - 1;
671141cc406Sopenharmony_ci	      range->quant = 1;
672141cc406Sopenharmony_ci	      o.constraint.range = range;
673141cc406Sopenharmony_ci	    }
674141cc406Sopenharmony_ci	  break;
675141cc406Sopenharmony_ci	case CS2_OPTION_LUT_B:
676141cc406Sopenharmony_ci	  o.name = "blue-gamma-table";
677141cc406Sopenharmony_ci	  o.title = "LUT for blue channel";
678141cc406Sopenharmony_ci	  o.desc = "LUT for blue channel";
679141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
680141cc406Sopenharmony_ci	  o.size = s->n_lut * WSIZE;
681141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
682141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
683141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
684141cc406Sopenharmony_ci	  if (!range)
685141cc406Sopenharmony_ci	    alloc_failed = 1;
686141cc406Sopenharmony_ci	  else
687141cc406Sopenharmony_ci	    {
688141cc406Sopenharmony_ci	      range->min = 0;
689141cc406Sopenharmony_ci	      range->max = s->n_lut - 1;
690141cc406Sopenharmony_ci	      range->quant = 1;
691141cc406Sopenharmony_ci	      o.constraint.range = range;
692141cc406Sopenharmony_ci	    }
693141cc406Sopenharmony_ci	  break;
694141cc406Sopenharmony_ci	case CS2_OPTION_LOAD:
695141cc406Sopenharmony_ci	  o.name = "load";
696141cc406Sopenharmony_ci	  o.title = "Load";
697141cc406Sopenharmony_ci	  o.desc = "Load next slide";
698141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
699141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
700141cc406Sopenharmony_ci	  break;
701141cc406Sopenharmony_ci	case CS2_OPTION_EJECT:
702141cc406Sopenharmony_ci	  o.name = "eject";
703141cc406Sopenharmony_ci	  o.title = "Eject";
704141cc406Sopenharmony_ci	  o.desc = "Eject loaded medium";
705141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
706141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
707141cc406Sopenharmony_ci	  break;
708141cc406Sopenharmony_ci	case CS2_OPTION_RESET:
709141cc406Sopenharmony_ci	  o.name = "reset";
710141cc406Sopenharmony_ci	  o.title = "Reset scanner";
711141cc406Sopenharmony_ci	  o.desc = "Initialize scanner";
712141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
713141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
714141cc406Sopenharmony_ci	  break;
715141cc406Sopenharmony_ci	case CS2_OPTION_RESX:
716141cc406Sopenharmony_ci	case CS2_OPTION_RES:
717141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW_RESOLUTION:
718141cc406Sopenharmony_ci	  if (i_option == CS2_OPTION_PREVIEW_RESOLUTION)
719141cc406Sopenharmony_ci	    {
720141cc406Sopenharmony_ci	      o.name = "preview-resolution";
721141cc406Sopenharmony_ci	      o.title = "Preview resolution";
722141cc406Sopenharmony_ci	      o.desc =
723141cc406Sopenharmony_ci		"Scanning resolution for preview mode in dpi, affecting both x and y directions";
724141cc406Sopenharmony_ci	    }
725141cc406Sopenharmony_ci	  else if (i_option == CS2_OPTION_RES)
726141cc406Sopenharmony_ci	    {
727141cc406Sopenharmony_ci	      o.name = "resolution";
728141cc406Sopenharmony_ci	      o.title = "Resolution";
729141cc406Sopenharmony_ci	      o.desc =
730141cc406Sopenharmony_ci		"Scanning resolution in dpi, affecting both x and y directions";
731141cc406Sopenharmony_ci	    }
732141cc406Sopenharmony_ci	  else
733141cc406Sopenharmony_ci	    {
734141cc406Sopenharmony_ci	      o.name = "x-resolution";
735141cc406Sopenharmony_ci	      o.title = "X resolution";
736141cc406Sopenharmony_ci	      o.desc =
737141cc406Sopenharmony_ci		"Scanning resolution in dpi, affecting x direction only";
738141cc406Sopenharmony_ci	    }
739141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
740141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_DPI;
741141cc406Sopenharmony_ci	  o.size = WSIZE;
742141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
743141cc406Sopenharmony_ci	  if (i_option == CS2_OPTION_RESX)
744141cc406Sopenharmony_ci	    o.cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
745141cc406Sopenharmony_ci	  if (i_option == CS2_OPTION_PREVIEW_RESOLUTION)
746141cc406Sopenharmony_ci	    o.cap |= SANE_CAP_ADVANCED;
747141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_WORD_LIST;
748141cc406Sopenharmony_ci	  word_list =
749141cc406Sopenharmony_ci	    (SANE_Word *) cs2_xmalloc ((s->resx_n_list + 1) *
750141cc406Sopenharmony_ci				       sizeof (SANE_Word));
751141cc406Sopenharmony_ci	  if (!word_list)
752141cc406Sopenharmony_ci	    alloc_failed = 1;
753141cc406Sopenharmony_ci	  else
754141cc406Sopenharmony_ci	    {
755141cc406Sopenharmony_ci	      for (i_list = 0; i_list < s->resx_n_list; i_list++)
756141cc406Sopenharmony_ci		word_list[i_list + 1] = s->resx_list[i_list];
757141cc406Sopenharmony_ci	      word_list[0] = s->resx_n_list;
758141cc406Sopenharmony_ci	      o.constraint.word_list = word_list;
759141cc406Sopenharmony_ci	    }
760141cc406Sopenharmony_ci	  break;
761141cc406Sopenharmony_ci	case CS2_OPTION_RESY:
762141cc406Sopenharmony_ci	  o.name = "y-resolution";
763141cc406Sopenharmony_ci	  o.title = "Y resolution";
764141cc406Sopenharmony_ci	  o.desc = "Scanning resolution in dpi, affecting y direction only";
765141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
766141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_DPI;
767141cc406Sopenharmony_ci	  o.size = WSIZE;
768141cc406Sopenharmony_ci	  o.cap =
769141cc406Sopenharmony_ci	    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE |
770141cc406Sopenharmony_ci	    SANE_CAP_ADVANCED;
771141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_WORD_LIST;
772141cc406Sopenharmony_ci	  word_list =
773141cc406Sopenharmony_ci	    (SANE_Word *) cs2_xmalloc ((s->resy_n_list + 1) *
774141cc406Sopenharmony_ci				       sizeof (SANE_Word));
775141cc406Sopenharmony_ci	  if (!word_list)
776141cc406Sopenharmony_ci	    alloc_failed = 1;
777141cc406Sopenharmony_ci	  else
778141cc406Sopenharmony_ci	    {
779141cc406Sopenharmony_ci	      for (i_list = 0; i_list < s->resy_n_list; i_list++)
780141cc406Sopenharmony_ci		word_list[i_list + 1] = s->resy_list[i_list];
781141cc406Sopenharmony_ci	      word_list[0] = s->resy_n_list;
782141cc406Sopenharmony_ci	      o.constraint.word_list = word_list;
783141cc406Sopenharmony_ci	    }
784141cc406Sopenharmony_ci	  break;
785141cc406Sopenharmony_ci	case CS2_OPTION_RES_INDEPENDENT:
786141cc406Sopenharmony_ci	  o.name = "independent-res";
787141cc406Sopenharmony_ci	  o.title = "Independent x/y resolutions";
788141cc406Sopenharmony_ci	  o.desc =
789141cc406Sopenharmony_ci	    "Enable independent controls for scanning resolution in x and y direction";
790141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BOOL;
791141cc406Sopenharmony_ci	  o.size = WSIZE;
792141cc406Sopenharmony_ci	  o.cap =
793141cc406Sopenharmony_ci	    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE |
794141cc406Sopenharmony_ci	    SANE_CAP_ADVANCED;
795141cc406Sopenharmony_ci	  break;
796141cc406Sopenharmony_ci	case CS2_OPTION_FRAME:
797141cc406Sopenharmony_ci	  o.name = "frame";
798141cc406Sopenharmony_ci	  o.title = "Frame number";
799141cc406Sopenharmony_ci	  o.desc = "Number of frame to be scanned, starting with 1";
800141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
801141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_NONE;
802141cc406Sopenharmony_ci	  o.size = WSIZE;
803141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
804141cc406Sopenharmony_ci	  if (s->n_frames <= 1)
805141cc406Sopenharmony_ci	    o.cap |= SANE_CAP_INACTIVE;
806141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
807141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
808141cc406Sopenharmony_ci	  if (!range)
809141cc406Sopenharmony_ci	    alloc_failed = 1;
810141cc406Sopenharmony_ci	  else
811141cc406Sopenharmony_ci	    {
812141cc406Sopenharmony_ci	      range->min = 1;
813141cc406Sopenharmony_ci	      range->max = s->n_frames;
814141cc406Sopenharmony_ci	      range->quant = 1;
815141cc406Sopenharmony_ci	      o.constraint.range = range;
816141cc406Sopenharmony_ci	    }
817141cc406Sopenharmony_ci	  break;
818141cc406Sopenharmony_ci	case CS2_OPTION_SUBFRAME:
819141cc406Sopenharmony_ci	  o.name = "subframe";
820141cc406Sopenharmony_ci	  o.title = "Frame shift";
821141cc406Sopenharmony_ci	  o.desc = "Fine position within the selected frame";
822141cc406Sopenharmony_ci	  o.type = SANE_TYPE_FIXED;
823141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_MM;
824141cc406Sopenharmony_ci	  o.size = WSIZE;
825141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
826141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
827141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
828141cc406Sopenharmony_ci	  if (!range)
829141cc406Sopenharmony_ci	    alloc_failed = 1;
830141cc406Sopenharmony_ci	  else
831141cc406Sopenharmony_ci	    {
832141cc406Sopenharmony_ci	      range->min = SANE_FIX (0.);
833141cc406Sopenharmony_ci	      range->max = SANE_FIX ((s->boundaryy - 1) * s->unit_mm);
834141cc406Sopenharmony_ci	      range->quant = SANE_FIX (0.);
835141cc406Sopenharmony_ci	      o.constraint.range = range;
836141cc406Sopenharmony_ci	    }
837141cc406Sopenharmony_ci	  break;
838141cc406Sopenharmony_ci	case CS2_OPTION_XMIN:
839141cc406Sopenharmony_ci	  o.name = "tl-x";
840141cc406Sopenharmony_ci	  o.title = "Left x value of scan area";
841141cc406Sopenharmony_ci	  o.desc = "Left x value of scan area";
842141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
843141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
844141cc406Sopenharmony_ci	  o.size = WSIZE;
845141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
846141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
847141cc406Sopenharmony_ci	  if (!range)
848141cc406Sopenharmony_ci	    alloc_failed = 1;
849141cc406Sopenharmony_ci	  else
850141cc406Sopenharmony_ci	    {
851141cc406Sopenharmony_ci	      range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
852141cc406Sopenharmony_ci	      range->min = 0;
853141cc406Sopenharmony_ci	      range->max = s->boundaryx - 1;
854141cc406Sopenharmony_ci	      range->quant = 1;
855141cc406Sopenharmony_ci	      o.constraint.range = range;
856141cc406Sopenharmony_ci	    }
857141cc406Sopenharmony_ci	  break;
858141cc406Sopenharmony_ci	case CS2_OPTION_XMAX:
859141cc406Sopenharmony_ci	  o.name = "br-x";
860141cc406Sopenharmony_ci	  o.title = "Right x value of scan area";
861141cc406Sopenharmony_ci	  o.desc = "Right x value of scan area";
862141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
863141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
864141cc406Sopenharmony_ci	  o.size = WSIZE;
865141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
866141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
867141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
868141cc406Sopenharmony_ci	  if (!range)
869141cc406Sopenharmony_ci	    alloc_failed = 1;
870141cc406Sopenharmony_ci	  else
871141cc406Sopenharmony_ci	    {
872141cc406Sopenharmony_ci	      range->min = 0;
873141cc406Sopenharmony_ci	      range->max = s->boundaryx - 1;
874141cc406Sopenharmony_ci	      range->quant = 1;
875141cc406Sopenharmony_ci	      o.constraint.range = range;
876141cc406Sopenharmony_ci	    }
877141cc406Sopenharmony_ci	  break;
878141cc406Sopenharmony_ci	case CS2_OPTION_YMIN:
879141cc406Sopenharmony_ci	  o.name = "tl-y";
880141cc406Sopenharmony_ci	  o.title = "Top y value of scan area";
881141cc406Sopenharmony_ci	  o.desc = "Top y value of scan area";
882141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
883141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
884141cc406Sopenharmony_ci	  o.size = WSIZE;
885141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
886141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
887141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
888141cc406Sopenharmony_ci	  if (!range)
889141cc406Sopenharmony_ci	    alloc_failed = 1;
890141cc406Sopenharmony_ci	  else
891141cc406Sopenharmony_ci	    {
892141cc406Sopenharmony_ci	      range->min = 0;
893141cc406Sopenharmony_ci	      range->max = s->boundaryy - 1;
894141cc406Sopenharmony_ci	      range->quant = 1;
895141cc406Sopenharmony_ci	      o.constraint.range = range;
896141cc406Sopenharmony_ci	    }
897141cc406Sopenharmony_ci	  break;
898141cc406Sopenharmony_ci	case CS2_OPTION_YMAX:
899141cc406Sopenharmony_ci	  o.name = "br-y";
900141cc406Sopenharmony_ci	  o.title = "Bottom y value of scan area";
901141cc406Sopenharmony_ci	  o.desc = "Bottom y value of scan area";
902141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
903141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
904141cc406Sopenharmony_ci	  o.size = WSIZE;
905141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
906141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
907141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
908141cc406Sopenharmony_ci	  if (!range)
909141cc406Sopenharmony_ci	    alloc_failed = 1;
910141cc406Sopenharmony_ci	  else
911141cc406Sopenharmony_ci	    {
912141cc406Sopenharmony_ci	      range->min = 0;
913141cc406Sopenharmony_ci	      range->max = s->boundaryy - 1;
914141cc406Sopenharmony_ci	      range->quant = 1;
915141cc406Sopenharmony_ci	      o.constraint.range = range;
916141cc406Sopenharmony_ci	    }
917141cc406Sopenharmony_ci	  break;
918141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS_ON_CENTRE:
919141cc406Sopenharmony_ci	  o.name = "focus-on-centre";
920141cc406Sopenharmony_ci	  o.title = "Use centre of scan area as AF point";
921141cc406Sopenharmony_ci	  o.desc =
922141cc406Sopenharmony_ci	    "Use centre of scan area as AF point instead of manual AF point selection";
923141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BOOL;
924141cc406Sopenharmony_ci	  o.size = WSIZE;
925141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
926141cc406Sopenharmony_ci	  break;
927141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS:
928141cc406Sopenharmony_ci	  o.name = SANE_NAME_FOCUS;
929141cc406Sopenharmony_ci	  o.title = SANE_TITLE_FOCUS;
930141cc406Sopenharmony_ci	  o.desc = SANE_DESC_FOCUS;
931141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
932141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_NONE;
933141cc406Sopenharmony_ci	  o.size = WSIZE;
934141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
935141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
936141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
937141cc406Sopenharmony_ci	  if (!range)
938141cc406Sopenharmony_ci	    alloc_failed = 1;
939141cc406Sopenharmony_ci	  else
940141cc406Sopenharmony_ci	    {
941141cc406Sopenharmony_ci	      range->min = s->focus_min;
942141cc406Sopenharmony_ci	      range->max = s->focus_max;
943141cc406Sopenharmony_ci	      range->quant = 1;
944141cc406Sopenharmony_ci	      o.constraint.range = range;
945141cc406Sopenharmony_ci	    }
946141cc406Sopenharmony_ci	  break;
947141cc406Sopenharmony_ci	case CS2_OPTION_AUTOFOCUS:
948141cc406Sopenharmony_ci	  o.name = SANE_NAME_AUTOFOCUS;
949141cc406Sopenharmony_ci	  o.title = SANE_TITLE_AUTOFOCUS;
950141cc406Sopenharmony_ci	  o.desc = SANE_DESC_AUTOFOCUS;
951141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
952141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
953141cc406Sopenharmony_ci	  break;
954141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSX:
955141cc406Sopenharmony_ci	  o.name = "focusx";
956141cc406Sopenharmony_ci	  o.title = "X coordinate of AF point";
957141cc406Sopenharmony_ci	  o.desc = "X coordinate of AF point";
958141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
959141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
960141cc406Sopenharmony_ci	  o.size = WSIZE;
961141cc406Sopenharmony_ci	  o.cap =
962141cc406Sopenharmony_ci	    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE;
963141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
964141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
965141cc406Sopenharmony_ci	  if (!range)
966141cc406Sopenharmony_ci	    alloc_failed = 1;
967141cc406Sopenharmony_ci	  else
968141cc406Sopenharmony_ci	    {
969141cc406Sopenharmony_ci	      range->min = 0;
970141cc406Sopenharmony_ci	      range->max = s->boundaryx - 1;
971141cc406Sopenharmony_ci	      range->quant = 1;
972141cc406Sopenharmony_ci	      o.constraint.range = range;
973141cc406Sopenharmony_ci	    }
974141cc406Sopenharmony_ci	  break;
975141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSY:
976141cc406Sopenharmony_ci	  o.name = "focusy";
977141cc406Sopenharmony_ci	  o.title = "Y coordinate of AF point";
978141cc406Sopenharmony_ci	  o.desc = "Y coordinate of AF point";
979141cc406Sopenharmony_ci	  o.type = SANE_TYPE_INT;
980141cc406Sopenharmony_ci	  o.unit = SANE_UNIT_PIXEL;
981141cc406Sopenharmony_ci	  o.size = WSIZE;
982141cc406Sopenharmony_ci	  o.cap =
983141cc406Sopenharmony_ci	    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE;
984141cc406Sopenharmony_ci	  o.constraint_type = SANE_CONSTRAINT_RANGE;
985141cc406Sopenharmony_ci	  range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range));
986141cc406Sopenharmony_ci	  if (!range)
987141cc406Sopenharmony_ci	    alloc_failed = 1;
988141cc406Sopenharmony_ci	  else
989141cc406Sopenharmony_ci	    {
990141cc406Sopenharmony_ci	      range->min = 0;
991141cc406Sopenharmony_ci	      range->max = s->boundaryy - 1;
992141cc406Sopenharmony_ci	      range->quant = 1;
993141cc406Sopenharmony_ci	      o.constraint.range = range;
994141cc406Sopenharmony_ci	    }
995141cc406Sopenharmony_ci	  break;
996141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE:
997141cc406Sopenharmony_ci	  o.name = "ae";
998141cc406Sopenharmony_ci	  o.title = "Auto-exposure scan now";
999141cc406Sopenharmony_ci	  o.desc = "Perform auto-exposure scan";
1000141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
1001141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1002141cc406Sopenharmony_ci	  break;
1003141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE_WB:
1004141cc406Sopenharmony_ci	  o.name = "ae-wb";
1005141cc406Sopenharmony_ci	  o.title = "Auto-exposure scan with white balance now";
1006141cc406Sopenharmony_ci	  o.desc = "Perform auto-exposure scan with white balance";
1007141cc406Sopenharmony_ci	  o.type = SANE_TYPE_BUTTON;
1008141cc406Sopenharmony_ci	  o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1009141cc406Sopenharmony_ci	  break;
1010141cc406Sopenharmony_ci	default:
1011141cc406Sopenharmony_ci	  DBG (1, "BUG: sane_open(): Unknown option number.\n");
1012141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1013141cc406Sopenharmony_ci	  break;
1014141cc406Sopenharmony_ci	}
1015141cc406Sopenharmony_ci      s->option_list[i_option] = o;
1016141cc406Sopenharmony_ci    }
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
1019141cc406Sopenharmony_ci  s->preview = SANE_FALSE;
1020141cc406Sopenharmony_ci  s->negative = SANE_FALSE;
1021141cc406Sopenharmony_ci  s->depth = 8;
1022141cc406Sopenharmony_ci  s->infrared = 0;
1023141cc406Sopenharmony_ci  s->samples_per_scan = 1;
1024141cc406Sopenharmony_ci  s->i_frame = 1;
1025141cc406Sopenharmony_ci  s->subframe = 0.;
1026141cc406Sopenharmony_ci  s->res = s->resx = s->resx_max;
1027141cc406Sopenharmony_ci  s->resy = s->resy_max;
1028141cc406Sopenharmony_ci  s->res_independent = SANE_FALSE;
1029141cc406Sopenharmony_ci  s->res_preview = s->resx_max / 10;
1030141cc406Sopenharmony_ci  if (s->res_preview < s->resx_min)
1031141cc406Sopenharmony_ci    s->res_preview = s->resx_min;
1032141cc406Sopenharmony_ci  s->xmin = 0;
1033141cc406Sopenharmony_ci  s->xmax = s->boundaryx - 1;
1034141cc406Sopenharmony_ci  s->ymin = 0;
1035141cc406Sopenharmony_ci  s->ymax = s->boundaryy - 1;
1036141cc406Sopenharmony_ci  s->focus_on_centre = SANE_TRUE;
1037141cc406Sopenharmony_ci  s->focus = 0;
1038141cc406Sopenharmony_ci  s->focusx = 0;
1039141cc406Sopenharmony_ci  s->focusy = 0;
1040141cc406Sopenharmony_ci  s->exposure = 1.;
1041141cc406Sopenharmony_ci  s->exposure_r = 1200.;
1042141cc406Sopenharmony_ci  s->exposure_g = 1200.;
1043141cc406Sopenharmony_ci  s->exposure_b = 1000.;
1044141cc406Sopenharmony_ci  s->infrared_stage = CS2_INFRARED_OFF;
1045141cc406Sopenharmony_ci  s->infrared_next = CS2_INFRARED_OFF;
1046141cc406Sopenharmony_ci  s->infrared_buf = NULL;
1047141cc406Sopenharmony_ci  s->n_infrared_buf = 0;
1048141cc406Sopenharmony_ci  s->line_buf = NULL;
1049141cc406Sopenharmony_ci  s->n_line_buf = 0;
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci  if (alloc_failed)
1052141cc406Sopenharmony_ci    {
1053141cc406Sopenharmony_ci      cs2_close (s);
1054141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1055141cc406Sopenharmony_ci    }
1056141cc406Sopenharmony_ci
1057141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1058141cc406Sopenharmony_ci}
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_civoid
1061141cc406Sopenharmony_cisane_close (SANE_Handle h)
1062141cc406Sopenharmony_ci{
1063141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci  DBG (10, "sane_close() called.\n");
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci  cs2_close (s);
1068141cc406Sopenharmony_ci}
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1071141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int n)
1072141cc406Sopenharmony_ci{
1073141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci  DBG (10, "sane_get_option_descriptor() called, option #%i.\n", n);
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci  if ((n >= 0) && (n < CS2_N_OPTIONS))
1078141cc406Sopenharmony_ci    return &s->option_list[n];
1079141cc406Sopenharmony_ci  else
1080141cc406Sopenharmony_ci    return NULL;
1081141cc406Sopenharmony_ci}
1082141cc406Sopenharmony_ci
1083141cc406Sopenharmony_ciSANE_Status
1084141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int n, SANE_Action a, void *v,
1085141cc406Sopenharmony_ci		     SANE_Int * i)
1086141cc406Sopenharmony_ci{
1087141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1088141cc406Sopenharmony_ci  SANE_Int flags = 0;
1089141cc406Sopenharmony_ci  cs2_pixel_t pixel;
1090141cc406Sopenharmony_ci  SANE_Status status;
1091141cc406Sopenharmony_ci  SANE_Option_Descriptor o = s->option_list[n];
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci  DBG (10, "sane_control_option() called, option #%i, action #%i.\n", n, a);
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci  switch (a)
1096141cc406Sopenharmony_ci    {
1097141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci      switch (n)
1100141cc406Sopenharmony_ci	{
1101141cc406Sopenharmony_ci	case CS2_OPTION_NUM:
1102141cc406Sopenharmony_ci	  *(SANE_Word *) v = CS2_N_OPTIONS;
1103141cc406Sopenharmony_ci	  break;
1104141cc406Sopenharmony_ci	case CS2_OPTION_NEGATIVE:
1105141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->negative;
1106141cc406Sopenharmony_ci	  break;
1107141cc406Sopenharmony_ci	case CS2_OPTION_INFRARED:
1108141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->infrared;
1109141cc406Sopenharmony_ci	  break;
1110141cc406Sopenharmony_ci	case CS2_OPTION_SAMPLES_PER_SCAN:
1111141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->samples_per_scan;
1112141cc406Sopenharmony_ci	  break;
1113141cc406Sopenharmony_ci	case CS2_OPTION_DEPTH:
1114141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->depth;
1115141cc406Sopenharmony_ci	  break;
1116141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW:
1117141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->preview;
1118141cc406Sopenharmony_ci	  break;
1119141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE:
1120141cc406Sopenharmony_ci	  *(SANE_Word *) v = SANE_FIX (s->exposure);
1121141cc406Sopenharmony_ci	  break;
1122141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_R:
1123141cc406Sopenharmony_ci	  *(SANE_Word *) v = SANE_FIX (s->exposure_r);
1124141cc406Sopenharmony_ci	  break;
1125141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_G:
1126141cc406Sopenharmony_ci	  *(SANE_Word *) v = SANE_FIX (s->exposure_g);
1127141cc406Sopenharmony_ci	  break;
1128141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_B:
1129141cc406Sopenharmony_ci	  *(SANE_Word *) v = SANE_FIX (s->exposure_b);
1130141cc406Sopenharmony_ci	  break;
1131141cc406Sopenharmony_ci	case CS2_OPTION_LUT_R:
1132141cc406Sopenharmony_ci	  if (!(s->lut_r))
1133141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1134141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1135141cc406Sopenharmony_ci	    ((SANE_Word *) v)[pixel] = s->lut_r[pixel];
1136141cc406Sopenharmony_ci	  break;
1137141cc406Sopenharmony_ci	case CS2_OPTION_LUT_G:
1138141cc406Sopenharmony_ci	  if (!(s->lut_g))
1139141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1140141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1141141cc406Sopenharmony_ci	    ((SANE_Word *) v)[pixel] = s->lut_g[pixel];
1142141cc406Sopenharmony_ci	  break;
1143141cc406Sopenharmony_ci	case CS2_OPTION_LUT_B:
1144141cc406Sopenharmony_ci	  if (!(s->lut_b))
1145141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1146141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1147141cc406Sopenharmony_ci	    ((SANE_Word *) v)[pixel] = s->lut_b[pixel];
1148141cc406Sopenharmony_ci	  break;
1149141cc406Sopenharmony_ci	case CS2_OPTION_EJECT:
1150141cc406Sopenharmony_ci	  break;
1151141cc406Sopenharmony_ci	case CS2_OPTION_LOAD:
1152141cc406Sopenharmony_ci	  break;
1153141cc406Sopenharmony_ci	case CS2_OPTION_RESET:
1154141cc406Sopenharmony_ci	  break;
1155141cc406Sopenharmony_ci	case CS2_OPTION_FRAME:
1156141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->i_frame;
1157141cc406Sopenharmony_ci	  break;
1158141cc406Sopenharmony_ci	case CS2_OPTION_SUBFRAME:
1159141cc406Sopenharmony_ci	  *(SANE_Word *) v = SANE_FIX (s->subframe);
1160141cc406Sopenharmony_ci	  break;
1161141cc406Sopenharmony_ci	case CS2_OPTION_RES:
1162141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->res;
1163141cc406Sopenharmony_ci	  break;
1164141cc406Sopenharmony_ci	case CS2_OPTION_RESX:
1165141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->resx;
1166141cc406Sopenharmony_ci	  break;
1167141cc406Sopenharmony_ci	case CS2_OPTION_RESY:
1168141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->resy;
1169141cc406Sopenharmony_ci	  break;
1170141cc406Sopenharmony_ci	case CS2_OPTION_RES_INDEPENDENT:
1171141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->res_independent;
1172141cc406Sopenharmony_ci	  break;
1173141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW_RESOLUTION:
1174141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->res_preview;
1175141cc406Sopenharmony_ci	  break;
1176141cc406Sopenharmony_ci	case CS2_OPTION_XMIN:
1177141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->xmin;
1178141cc406Sopenharmony_ci	  break;
1179141cc406Sopenharmony_ci	case CS2_OPTION_XMAX:
1180141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->xmax;
1181141cc406Sopenharmony_ci	  break;
1182141cc406Sopenharmony_ci	case CS2_OPTION_YMIN:
1183141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->ymin;
1184141cc406Sopenharmony_ci	  break;
1185141cc406Sopenharmony_ci	case CS2_OPTION_YMAX:
1186141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->ymax;
1187141cc406Sopenharmony_ci	  break;
1188141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS_ON_CENTRE:
1189141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->focus_on_centre;
1190141cc406Sopenharmony_ci	  break;
1191141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS:
1192141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->focus;
1193141cc406Sopenharmony_ci	  break;
1194141cc406Sopenharmony_ci	case CS2_OPTION_AUTOFOCUS:
1195141cc406Sopenharmony_ci	  break;
1196141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSX:
1197141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->focusx;
1198141cc406Sopenharmony_ci	  break;
1199141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSY:
1200141cc406Sopenharmony_ci	  *(SANE_Word *) v = s->focusy;
1201141cc406Sopenharmony_ci	  break;
1202141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE:
1203141cc406Sopenharmony_ci	  break;
1204141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE_WB:
1205141cc406Sopenharmony_ci	  break;
1206141cc406Sopenharmony_ci	default:
1207141cc406Sopenharmony_ci	  DBG (4, "Error: sane_control_option(): Unknown option (bug?).\n");
1208141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1209141cc406Sopenharmony_ci	}
1210141cc406Sopenharmony_ci      break;
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
1213141cc406Sopenharmony_ci      if (s->scanning)
1214141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
1215141cc406Sopenharmony_ci/* XXXXXXXXXXXXXXXXX do this for all elements of arrays */
1216141cc406Sopenharmony_ci      switch (o.type)
1217141cc406Sopenharmony_ci	{
1218141cc406Sopenharmony_ci	case SANE_TYPE_BOOL:
1219141cc406Sopenharmony_ci	  if ((*(SANE_Word *) v != SANE_TRUE)
1220141cc406Sopenharmony_ci	      && (*(SANE_Word *) v != SANE_FALSE))
1221141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1222141cc406Sopenharmony_ci	  break;
1223141cc406Sopenharmony_ci	case SANE_TYPE_INT:
1224141cc406Sopenharmony_ci	case SANE_TYPE_FIXED:
1225141cc406Sopenharmony_ci	  switch (o.constraint_type)
1226141cc406Sopenharmony_ci	    {
1227141cc406Sopenharmony_ci	    case SANE_CONSTRAINT_RANGE:
1228141cc406Sopenharmony_ci	      if (*(SANE_Word *) v < o.constraint.range->min)
1229141cc406Sopenharmony_ci		{
1230141cc406Sopenharmony_ci		  *(SANE_Word *) v = o.constraint.range->min;
1231141cc406Sopenharmony_ci		  flags |= SANE_INFO_INEXACT;
1232141cc406Sopenharmony_ci		}
1233141cc406Sopenharmony_ci	      else if (*(SANE_Word *) v > o.constraint.range->max)
1234141cc406Sopenharmony_ci		{
1235141cc406Sopenharmony_ci		  *(SANE_Word *) v = o.constraint.range->max;
1236141cc406Sopenharmony_ci		  flags |= SANE_INFO_INEXACT;
1237141cc406Sopenharmony_ci		}
1238141cc406Sopenharmony_ci	      break;
1239141cc406Sopenharmony_ci	    case SANE_CONSTRAINT_WORD_LIST:
1240141cc406Sopenharmony_ci	      break;
1241141cc406Sopenharmony_ci	    default:
1242141cc406Sopenharmony_ci	      break;
1243141cc406Sopenharmony_ci	    }
1244141cc406Sopenharmony_ci	  break;
1245141cc406Sopenharmony_ci	case SANE_TYPE_STRING:
1246141cc406Sopenharmony_ci	  break;
1247141cc406Sopenharmony_ci	case SANE_TYPE_BUTTON:
1248141cc406Sopenharmony_ci	  break;
1249141cc406Sopenharmony_ci	case SANE_TYPE_GROUP:
1250141cc406Sopenharmony_ci	  break;
1251141cc406Sopenharmony_ci	}
1252141cc406Sopenharmony_ci      switch (n)
1253141cc406Sopenharmony_ci	{
1254141cc406Sopenharmony_ci	case CS2_OPTION_NUM:
1255141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1256141cc406Sopenharmony_ci	  break;
1257141cc406Sopenharmony_ci	case CS2_OPTION_NEGATIVE:
1258141cc406Sopenharmony_ci	  s->negative = *(SANE_Word *) v;
1259141cc406Sopenharmony_ci	  break;
1260141cc406Sopenharmony_ci	case CS2_OPTION_INFRARED:
1261141cc406Sopenharmony_ci	  s->infrared = *(SANE_Word *) v;
1262141cc406Sopenharmony_ci	  /*      flags |= SANE_INFO_RELOAD_PARAMS; XXXXXXXXXXXXXXXXX */
1263141cc406Sopenharmony_ci	  break;
1264141cc406Sopenharmony_ci	case CS2_OPTION_SAMPLES_PER_SCAN:
1265141cc406Sopenharmony_ci	  s->samples_per_scan = *(SANE_Word *) v;
1266141cc406Sopenharmony_ci	  break;
1267141cc406Sopenharmony_ci	case CS2_OPTION_DEPTH:
1268141cc406Sopenharmony_ci	  s->depth = *(SANE_Word *) v;
1269141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1270141cc406Sopenharmony_ci	  break;
1271141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW:
1272141cc406Sopenharmony_ci	  s->preview = *(SANE_Word *) v;
1273141cc406Sopenharmony_ci	  break;
1274141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE:
1275141cc406Sopenharmony_ci	  s->exposure = SANE_UNFIX (*(SANE_Word *) v);
1276141cc406Sopenharmony_ci	  break;
1277141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_R:
1278141cc406Sopenharmony_ci	  s->exposure_r = SANE_UNFIX (*(SANE_Word *) v);
1279141cc406Sopenharmony_ci	  break;
1280141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_G:
1281141cc406Sopenharmony_ci	  s->exposure_g = SANE_UNFIX (*(SANE_Word *) v);
1282141cc406Sopenharmony_ci	  break;
1283141cc406Sopenharmony_ci	case CS2_OPTION_EXPOSURE_B:
1284141cc406Sopenharmony_ci	  s->exposure_b = SANE_UNFIX (*(SANE_Word *) v);
1285141cc406Sopenharmony_ci	  break;
1286141cc406Sopenharmony_ci	case CS2_OPTION_LUT_R:
1287141cc406Sopenharmony_ci	  if (!(s->lut_r))
1288141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1289141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1290141cc406Sopenharmony_ci	    s->lut_r[pixel] = ((SANE_Word *) v)[pixel];
1291141cc406Sopenharmony_ci	  break;
1292141cc406Sopenharmony_ci	case CS2_OPTION_LUT_G:
1293141cc406Sopenharmony_ci	  if (!(s->lut_g))
1294141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1295141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1296141cc406Sopenharmony_ci	    s->lut_g[pixel] = ((SANE_Word *) v)[pixel];
1297141cc406Sopenharmony_ci	  break;
1298141cc406Sopenharmony_ci	case CS2_OPTION_LUT_B:
1299141cc406Sopenharmony_ci	  if (!(s->lut_b))
1300141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1301141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
1302141cc406Sopenharmony_ci	    s->lut_b[pixel] = ((SANE_Word *) v)[pixel];
1303141cc406Sopenharmony_ci	  break;
1304141cc406Sopenharmony_ci	case CS2_OPTION_LOAD:
1305141cc406Sopenharmony_ci	  cs2_load (s);
1306141cc406Sopenharmony_ci	  break;
1307141cc406Sopenharmony_ci	case CS2_OPTION_EJECT:
1308141cc406Sopenharmony_ci	  cs2_eject (s);
1309141cc406Sopenharmony_ci	  break;
1310141cc406Sopenharmony_ci	case CS2_OPTION_RESET:
1311141cc406Sopenharmony_ci	  cs2_reset (s);
1312141cc406Sopenharmony_ci	  break;
1313141cc406Sopenharmony_ci	case CS2_OPTION_FRAME:
1314141cc406Sopenharmony_ci	  s->i_frame = *(SANE_Word *) v;
1315141cc406Sopenharmony_ci	  break;
1316141cc406Sopenharmony_ci	case CS2_OPTION_SUBFRAME:
1317141cc406Sopenharmony_ci	  s->subframe = SANE_UNFIX (*(SANE_Word *) v);
1318141cc406Sopenharmony_ci	  break;
1319141cc406Sopenharmony_ci	case CS2_OPTION_RES:
1320141cc406Sopenharmony_ci	  s->res = *(SANE_Word *) v;
1321141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1322141cc406Sopenharmony_ci	  break;
1323141cc406Sopenharmony_ci	case CS2_OPTION_RESX:
1324141cc406Sopenharmony_ci	  s->resx = *(SANE_Word *) v;
1325141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1326141cc406Sopenharmony_ci	  break;
1327141cc406Sopenharmony_ci	case CS2_OPTION_RESY:
1328141cc406Sopenharmony_ci	  s->resy = *(SANE_Word *) v;
1329141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1330141cc406Sopenharmony_ci	  break;
1331141cc406Sopenharmony_ci	case CS2_OPTION_RES_INDEPENDENT:
1332141cc406Sopenharmony_ci	  s->res_independent = *(SANE_Word *) v;
1333141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1334141cc406Sopenharmony_ci	  break;
1335141cc406Sopenharmony_ci	case CS2_OPTION_PREVIEW_RESOLUTION:
1336141cc406Sopenharmony_ci	  s->res_preview = *(SANE_Word *) v;
1337141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1338141cc406Sopenharmony_ci	  break;
1339141cc406Sopenharmony_ci	case CS2_OPTION_XMIN:
1340141cc406Sopenharmony_ci	  s->xmin = *(SANE_Word *) v;
1341141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1342141cc406Sopenharmony_ci	  break;
1343141cc406Sopenharmony_ci	case CS2_OPTION_XMAX:
1344141cc406Sopenharmony_ci	  s->xmax = *(SANE_Word *) v;
1345141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1346141cc406Sopenharmony_ci	  break;
1347141cc406Sopenharmony_ci	case CS2_OPTION_YMIN:
1348141cc406Sopenharmony_ci	  s->ymin = *(SANE_Word *) v;
1349141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1350141cc406Sopenharmony_ci	  break;
1351141cc406Sopenharmony_ci	case CS2_OPTION_YMAX:
1352141cc406Sopenharmony_ci	  s->ymax = *(SANE_Word *) v;
1353141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_PARAMS;
1354141cc406Sopenharmony_ci	  break;
1355141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS_ON_CENTRE:
1356141cc406Sopenharmony_ci	  s->focus_on_centre = *(SANE_Word *) v;
1357141cc406Sopenharmony_ci	  if (s->focus_on_centre)
1358141cc406Sopenharmony_ci	    {
1359141cc406Sopenharmony_ci	      s->option_list[CS2_OPTION_FOCUSX].cap |= SANE_CAP_INACTIVE;
1360141cc406Sopenharmony_ci	      s->option_list[CS2_OPTION_FOCUSY].cap |= SANE_CAP_INACTIVE;
1361141cc406Sopenharmony_ci	    }
1362141cc406Sopenharmony_ci	  else
1363141cc406Sopenharmony_ci	    {
1364141cc406Sopenharmony_ci	      s->option_list[CS2_OPTION_FOCUSX].cap &= ~SANE_CAP_INACTIVE;
1365141cc406Sopenharmony_ci	      s->option_list[CS2_OPTION_FOCUSY].cap &= ~SANE_CAP_INACTIVE;
1366141cc406Sopenharmony_ci	    }
1367141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_OPTIONS;
1368141cc406Sopenharmony_ci	  break;
1369141cc406Sopenharmony_ci	case CS2_OPTION_FOCUS:
1370141cc406Sopenharmony_ci	  s->focus = *(SANE_Word *) v;
1371141cc406Sopenharmony_ci	  break;
1372141cc406Sopenharmony_ci	case CS2_OPTION_AUTOFOCUS:
1373141cc406Sopenharmony_ci	  cs2_autofocus (s);
1374141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_OPTIONS;
1375141cc406Sopenharmony_ci	  break;
1376141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSX:
1377141cc406Sopenharmony_ci	  s->focusx = *(SANE_Word *) v;
1378141cc406Sopenharmony_ci	  break;
1379141cc406Sopenharmony_ci	case CS2_OPTION_FOCUSY:
1380141cc406Sopenharmony_ci	  s->focusy = *(SANE_Word *) v;
1381141cc406Sopenharmony_ci	  break;
1382141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE:
1383141cc406Sopenharmony_ci	  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
1384141cc406Sopenharmony_ci	  status = cs2_scan (s, CS2_SCAN_AE);
1385141cc406Sopenharmony_ci	  if (status)
1386141cc406Sopenharmony_ci	    return status;
1387141cc406Sopenharmony_ci	  status = cs2_get_exposure (s);
1388141cc406Sopenharmony_ci	  if (status)
1389141cc406Sopenharmony_ci	    return status;
1390141cc406Sopenharmony_ci	  s->exposure = 1.;
1391141cc406Sopenharmony_ci	  s->exposure_r = s->real_exposure[1] / 100.;
1392141cc406Sopenharmony_ci	  s->exposure_g = s->real_exposure[2] / 100.;
1393141cc406Sopenharmony_ci	  s->exposure_b = s->real_exposure[3] / 100.;
1394141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_OPTIONS;
1395141cc406Sopenharmony_ci	  break;
1396141cc406Sopenharmony_ci	case CS2_OPTION_SCAN_AE_WB:
1397141cc406Sopenharmony_ci	  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
1398141cc406Sopenharmony_ci	  status = cs2_scan (s, CS2_SCAN_AE_WB);
1399141cc406Sopenharmony_ci	  if (status)
1400141cc406Sopenharmony_ci	    return status;
1401141cc406Sopenharmony_ci	  status = cs2_get_exposure (s);
1402141cc406Sopenharmony_ci	  if (status)
1403141cc406Sopenharmony_ci	    return status;
1404141cc406Sopenharmony_ci	  s->exposure = 1.;
1405141cc406Sopenharmony_ci	  s->exposure_r = s->real_exposure[1] / 100.;
1406141cc406Sopenharmony_ci	  s->exposure_g = s->real_exposure[2] / 100.;
1407141cc406Sopenharmony_ci	  s->exposure_b = s->real_exposure[3] / 100.;
1408141cc406Sopenharmony_ci	  flags |= SANE_INFO_RELOAD_OPTIONS;
1409141cc406Sopenharmony_ci	  break;
1410141cc406Sopenharmony_ci	default:
1411141cc406Sopenharmony_ci	  DBG (4,
1412141cc406Sopenharmony_ci	       "Error: sane_control_option(): Unknown option number (bug?).\n");
1413141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1414141cc406Sopenharmony_ci	  break;
1415141cc406Sopenharmony_ci	}
1416141cc406Sopenharmony_ci      break;
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci    default:
1419141cc406Sopenharmony_ci      DBG (1, "BUG: sane_control_option(): Unknown action number.\n");
1420141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1421141cc406Sopenharmony_ci      break;
1422141cc406Sopenharmony_ci    }
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci  if (i)
1425141cc406Sopenharmony_ci    *i = flags;
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1428141cc406Sopenharmony_ci}
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ciSANE_Status
1431141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters * p)
1432141cc406Sopenharmony_ci{
1433141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1434141cc406Sopenharmony_ci  SANE_Status status;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters() called.\n");
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci  if (!s->scanning)		/* only recalculate when not scanning */
1439141cc406Sopenharmony_ci    {
1440141cc406Sopenharmony_ci      status = cs2_convert_options (s);
1441141cc406Sopenharmony_ci      if (status)
1442141cc406Sopenharmony_ci	return status;
1443141cc406Sopenharmony_ci    }
1444141cc406Sopenharmony_ci
1445141cc406Sopenharmony_ci  if (s->infrared_stage == CS2_INFRARED_OUT)
1446141cc406Sopenharmony_ci    {
1447141cc406Sopenharmony_ci      p->format = SANE_FRAME_GRAY;
1448141cc406Sopenharmony_ci      p->bytes_per_line = s->logical_width * s->bytes_per_pixel;
1449141cc406Sopenharmony_ci    }
1450141cc406Sopenharmony_ci  else
1451141cc406Sopenharmony_ci    {
1452141cc406Sopenharmony_ci      p->format = SANE_FRAME_RGB;	/* XXXXXXXX CCCCCCCCCC */
1453141cc406Sopenharmony_ci      p->bytes_per_line =
1454141cc406Sopenharmony_ci	s->n_colour_out * s->logical_width * s->bytes_per_pixel;
1455141cc406Sopenharmony_ci    }
1456141cc406Sopenharmony_ci  p->last_frame = SANE_TRUE;
1457141cc406Sopenharmony_ci  p->lines = s->logical_height;
1458141cc406Sopenharmony_ci  p->depth = 8 * s->bytes_per_pixel;
1459141cc406Sopenharmony_ci  p->pixels_per_line = s->logical_width;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1462141cc406Sopenharmony_ci}
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_ciSANE_Status
1465141cc406Sopenharmony_cisane_start (SANE_Handle h)
1466141cc406Sopenharmony_ci{
1467141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1468141cc406Sopenharmony_ci  SANE_Status status;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci  DBG (10, "sane_start() called.\n");
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci  if (s->scanning)
1473141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1474141cc406Sopenharmony_ci
1475141cc406Sopenharmony_ci  status = cs2_convert_options (s);
1476141cc406Sopenharmony_ci  if (status)
1477141cc406Sopenharmony_ci    return status;
1478141cc406Sopenharmony_ci
1479141cc406Sopenharmony_ci  s->infrared_index = 0;
1480141cc406Sopenharmony_ci  s->i_line_buf = 0;
1481141cc406Sopenharmony_ci  s->xfer_position = 0;
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
1484141cc406Sopenharmony_ci
1485141cc406Sopenharmony_ci  if (s->infrared_stage == CS2_INFRARED_OUT)
1486141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1487141cc406Sopenharmony_ci  else
1488141cc406Sopenharmony_ci    return cs2_scan (s, CS2_SCAN_NORMAL);
1489141cc406Sopenharmony_ci}
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_ciSANE_Status
1492141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
1493141cc406Sopenharmony_ci{
1494141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1495141cc406Sopenharmony_ci  SANE_Status status;
1496141cc406Sopenharmony_ci  ssize_t xfer_len_in, xfer_len_line, xfer_len_out;
1497141cc406Sopenharmony_ci  unsigned long index;
1498141cc406Sopenharmony_ci  int colour, n_colours, sample_pass;
1499141cc406Sopenharmony_ci  uint8_t *s8 = NULL;
1500141cc406Sopenharmony_ci  uint16_t *s16 = NULL;
1501141cc406Sopenharmony_ci  double m_avg_sum;
1502141cc406Sopenharmony_ci  SANE_Byte *line_buf_new;
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  DBG (10, "sane_read() called, maxlen = %i.\n", maxlen);
1505141cc406Sopenharmony_ci
1506141cc406Sopenharmony_ci  if (!s->scanning) {
1507141cc406Sopenharmony_ci    *len = 0;
1508141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
1509141cc406Sopenharmony_ci  }
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci  if (s->infrared_stage == CS2_INFRARED_OUT)
1512141cc406Sopenharmony_ci    {
1513141cc406Sopenharmony_ci      xfer_len_out = maxlen;
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci      if (s->xfer_position + xfer_len_out > s->n_infrared_buf)
1516141cc406Sopenharmony_ci	xfer_len_out = s->n_infrared_buf - s->xfer_position;
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_ci      if (xfer_len_out == 0)	/* no more data */
1519141cc406Sopenharmony_ci	{
1520141cc406Sopenharmony_ci	  *len = 0;
1521141cc406Sopenharmony_ci	s->scanning = SANE_FALSE;
1522141cc406Sopenharmony_ci	  return SANE_STATUS_EOF;
1523141cc406Sopenharmony_ci	}
1524141cc406Sopenharmony_ci
1525141cc406Sopenharmony_ci      memcpy (buf, &(s->infrared_buf[s->xfer_position]), xfer_len_out);
1526141cc406Sopenharmony_ci
1527141cc406Sopenharmony_ci      s->xfer_position += xfer_len_out;
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci      if (s->xfer_position >= s->n_infrared_buf)
1530141cc406Sopenharmony_ci	s->infrared_next = CS2_INFRARED_OFF;
1531141cc406Sopenharmony_ci
1532141cc406Sopenharmony_ci      *len = xfer_len_out;
1533141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1534141cc406Sopenharmony_ci    }
1535141cc406Sopenharmony_ci
1536141cc406Sopenharmony_ci  if (s->i_line_buf > 0)
1537141cc406Sopenharmony_ci    {
1538141cc406Sopenharmony_ci      xfer_len_out = s->n_line_buf - s->i_line_buf;
1539141cc406Sopenharmony_ci      if (xfer_len_out > maxlen)
1540141cc406Sopenharmony_ci	xfer_len_out = maxlen;
1541141cc406Sopenharmony_ci
1542141cc406Sopenharmony_ci      memcpy (buf, &(s->line_buf[s->i_line_buf]), xfer_len_out);
1543141cc406Sopenharmony_ci
1544141cc406Sopenharmony_ci      s->i_line_buf += xfer_len_out;
1545141cc406Sopenharmony_ci      if (s->i_line_buf >= s->n_line_buf)
1546141cc406Sopenharmony_ci	s->i_line_buf = 0;
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci      *len = xfer_len_out;
1549141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1550141cc406Sopenharmony_ci    }
1551141cc406Sopenharmony_ci
1552141cc406Sopenharmony_ci  xfer_len_line = s->n_colour_out * s->logical_width * s->bytes_per_pixel;
1553141cc406Sopenharmony_ci  xfer_len_in =
1554141cc406Sopenharmony_ci    s->n_colour_in * s->logical_width * s->bytes_per_pixel +
1555141cc406Sopenharmony_ci    s->n_colour_in * s->odd_padding;
1556141cc406Sopenharmony_ci  /* Do not change the behaviour of older models */
1557141cc406Sopenharmony_ci  if ((s->type == CS2_TYPE_LS50) || (s->type == CS2_TYPE_LS5000))
1558141cc406Sopenharmony_ci    {
1559141cc406Sopenharmony_ci      /* Ariel - Check, win driver uses multiple of 64, docu seems to say 512? */
1560141cc406Sopenharmony_ci      ssize_t i;
1561141cc406Sopenharmony_ci      xfer_len_in += s->block_padding;
1562141cc406Sopenharmony_ci      i = (xfer_len_in & 0x3f);
1563141cc406Sopenharmony_ci      if (i != 0)
1564141cc406Sopenharmony_ci        DBG (1, "BUG: sane_read(): Read size is not a multiple of 64. (0x%06lx)\n", (long) i);
1565141cc406Sopenharmony_ci    }
1566141cc406Sopenharmony_ci
1567141cc406Sopenharmony_ci  if (s->xfer_position + xfer_len_line > s->xfer_bytes_total)
1568141cc406Sopenharmony_ci    xfer_len_line = s->xfer_bytes_total - s->xfer_position; /* just in case */
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci  if (xfer_len_line == 0)	/* no more data */
1571141cc406Sopenharmony_ci    {
1572141cc406Sopenharmony_ci      *len = 0;
1573141cc406Sopenharmony_ci	s->scanning = SANE_FALSE;
1574141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1575141cc406Sopenharmony_ci    }
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci  if (xfer_len_line != s->n_line_buf)
1578141cc406Sopenharmony_ci    {
1579141cc406Sopenharmony_ci      line_buf_new =
1580141cc406Sopenharmony_ci	(SANE_Byte *) cs2_xrealloc (s->line_buf,
1581141cc406Sopenharmony_ci				    xfer_len_line * sizeof (SANE_Byte));
1582141cc406Sopenharmony_ci      if (!line_buf_new)
1583141cc406Sopenharmony_ci	{
1584141cc406Sopenharmony_ci	  *len = 0;
1585141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
1586141cc406Sopenharmony_ci	}
1587141cc406Sopenharmony_ci      s->line_buf = line_buf_new;
1588141cc406Sopenharmony_ci      s->n_line_buf = xfer_len_line;
1589141cc406Sopenharmony_ci    }
1590141cc406Sopenharmony_ci
1591141cc406Sopenharmony_ci  /* adapt for multi-sampling */
1592141cc406Sopenharmony_ci  xfer_len_in *= s->samples_per_scan;
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
1595141cc406Sopenharmony_ci  cs2_init_buffer (s);
1596141cc406Sopenharmony_ci  cs2_parse_cmd (s, "28 00 00 00 00 00");
1597141cc406Sopenharmony_ci  cs2_pack_byte (s, (xfer_len_in >> 16) & 0xff);
1598141cc406Sopenharmony_ci  cs2_pack_byte (s, (xfer_len_in >> 8) & 0xff);
1599141cc406Sopenharmony_ci  cs2_pack_byte (s, xfer_len_in & 0xff);
1600141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00");
1601141cc406Sopenharmony_ci  s->n_recv = xfer_len_in;
1602141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci  if (status)
1605141cc406Sopenharmony_ci    {
1606141cc406Sopenharmony_ci      *len = 0;
1607141cc406Sopenharmony_ci      return status;
1608141cc406Sopenharmony_ci    }
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci  n_colours = s->n_colour_out +
1611141cc406Sopenharmony_ci	  (s->infrared_stage == CS2_INFRARED_IN ? 1 : 0);
1612141cc406Sopenharmony_ci
1613141cc406Sopenharmony_ci  for (index = 0; index < s->logical_width; index++)
1614141cc406Sopenharmony_ci    for (colour = 0; colour < n_colours; colour++) {
1615141cc406Sopenharmony_ci	  m_avg_sum = 0.0;
1616141cc406Sopenharmony_ci      switch (s->bytes_per_pixel)
1617141cc406Sopenharmony_ci	{
1618141cc406Sopenharmony_ci	case 1:
1619141cc406Sopenharmony_ci	  /* calculate target address */
1620141cc406Sopenharmony_ci	  if ((s->infrared_stage == CS2_INFRARED_IN)
1621141cc406Sopenharmony_ci	      && (colour == s->n_colour_out))
1622141cc406Sopenharmony_ci	    s8 = (uint8_t *) & (s->infrared_buf[s->infrared_index++]);
1623141cc406Sopenharmony_ci	  else
1624141cc406Sopenharmony_ci	    s8 =
1625141cc406Sopenharmony_ci	      (uint8_t *) & (s->line_buf[s->n_colour_out * index + colour]);
1626141cc406Sopenharmony_ci
1627141cc406Sopenharmony_ci	  if (s->samples_per_scan > 1)
1628141cc406Sopenharmony_ci		{
1629141cc406Sopenharmony_ci		  /* calculate average of multi samples */
1630141cc406Sopenharmony_ci		  for (sample_pass = 0;
1631141cc406Sopenharmony_ci			   sample_pass < s->samples_per_scan;
1632141cc406Sopenharmony_ci			   sample_pass++)
1633141cc406Sopenharmony_ci			m_avg_sum += (double)
1634141cc406Sopenharmony_ci			  s->recv_buf[s->logical_width *
1635141cc406Sopenharmony_ci			  (sample_pass * n_colours + colour) +
1636141cc406Sopenharmony_ci			  (colour + 1) * s->odd_padding + index];
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci		  *s8 = (uint8_t) (m_avg_sum / s->samples_per_scan + 0.5);
1639141cc406Sopenharmony_ci		}
1640141cc406Sopenharmony_ci	  else
1641141cc406Sopenharmony_ci		/* shortcut for single sample */
1642141cc406Sopenharmony_ci		*s8 =
1643141cc406Sopenharmony_ci		  s->recv_buf[colour * s->logical_width +
1644141cc406Sopenharmony_ci					  (colour + 1) * s->odd_padding + index];
1645141cc406Sopenharmony_ci	  break;
1646141cc406Sopenharmony_ci	case 2:
1647141cc406Sopenharmony_ci	  /* calculate target address */
1648141cc406Sopenharmony_ci	  if ((s->infrared_stage == CS2_INFRARED_IN)
1649141cc406Sopenharmony_ci	      && (colour == s->n_colour_out))
1650141cc406Sopenharmony_ci	    s16 =
1651141cc406Sopenharmony_ci	      (uint16_t *) & (s->infrared_buf[2 * (s->infrared_index++)]);
1652141cc406Sopenharmony_ci	  else
1653141cc406Sopenharmony_ci	    s16 =
1654141cc406Sopenharmony_ci	      (uint16_t *) & (s->
1655141cc406Sopenharmony_ci			       line_buf[2 *
1656141cc406Sopenharmony_ci					(s->n_colour_out * index + colour)]);
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci	  if (s->samples_per_scan > 1)
1659141cc406Sopenharmony_ci		{
1660141cc406Sopenharmony_ci		  /* calculate average of multi samples */
1661141cc406Sopenharmony_ci		  for (sample_pass = 0;
1662141cc406Sopenharmony_ci			   s->samples_per_scan > 1 && sample_pass < s->samples_per_scan;
1663141cc406Sopenharmony_ci			   sample_pass++)
1664141cc406Sopenharmony_ci			m_avg_sum += (double)
1665141cc406Sopenharmony_ci			  (s->recv_buf[2 * (s->logical_width * (sample_pass * n_colours + colour) + index)] * 256 +
1666141cc406Sopenharmony_ci			   s->recv_buf[2 * (s->logical_width * (sample_pass * n_colours + colour) + index) + 1]);
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci		  *s16 = (uint16_t) (m_avg_sum / s->samples_per_scan + 0.5);
1669141cc406Sopenharmony_ci		}
1670141cc406Sopenharmony_ci	  else
1671141cc406Sopenharmony_ci		/* shortcut for single sample */
1672141cc406Sopenharmony_ci		*s16 =
1673141cc406Sopenharmony_ci		  s->recv_buf[2 * (colour * s->logical_width + index)] * 256 +
1674141cc406Sopenharmony_ci		  s->recv_buf[2 * (colour * s->logical_width + index) + 1];
1675141cc406Sopenharmony_ci	  *s16 <<= s->shift_bits;
1676141cc406Sopenharmony_ci	  break;
1677141cc406Sopenharmony_ci	default:
1678141cc406Sopenharmony_ci	  DBG (1, "BUG: sane_read(): Unknown number of bytes per pixel.\n");
1679141cc406Sopenharmony_ci	  *len = 0;
1680141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1681141cc406Sopenharmony_ci	  break;
1682141cc406Sopenharmony_ci	}
1683141cc406Sopenharmony_ci	}
1684141cc406Sopenharmony_ci  s->xfer_position += xfer_len_line;
1685141cc406Sopenharmony_ci
1686141cc406Sopenharmony_ci  xfer_len_out = xfer_len_line;
1687141cc406Sopenharmony_ci  if (xfer_len_out > maxlen)
1688141cc406Sopenharmony_ci    xfer_len_out = maxlen;
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci  memcpy (buf, s->line_buf, xfer_len_out);
1691141cc406Sopenharmony_ci  if (xfer_len_out < xfer_len_line)
1692141cc406Sopenharmony_ci    s->i_line_buf = xfer_len_out; /* data left in the line buffer, read out next time */
1693141cc406Sopenharmony_ci
1694141cc406Sopenharmony_ci  if ((s->infrared_stage == CS2_INFRARED_IN)
1695141cc406Sopenharmony_ci      && (s->xfer_position >= s->n_infrared_buf))
1696141cc406Sopenharmony_ci    s->infrared_next = CS2_INFRARED_OUT;
1697141cc406Sopenharmony_ci
1698141cc406Sopenharmony_ci  *len = xfer_len_out;
1699141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1700141cc406Sopenharmony_ci}
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_civoid
1703141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
1704141cc406Sopenharmony_ci{
1705141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci  if (s->scanning)
1708141cc406Sopenharmony_ci    DBG (10, "sane_cancel() called while scanning.\n");
1709141cc406Sopenharmony_ci  else
1710141cc406Sopenharmony_ci    DBG (10, "sane_cancel() called while not scanning.\n");
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci  if (s->scanning && (s->infrared_stage != CS2_INFRARED_OUT))
1713141cc406Sopenharmony_ci    {
1714141cc406Sopenharmony_ci      cs2_init_buffer (s);
1715141cc406Sopenharmony_ci      cs2_parse_cmd (s, "c0 00 00 00 00 00");
1716141cc406Sopenharmony_ci      cs2_issue_cmd (s);
1717141cc406Sopenharmony_ci    }
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
1720141cc406Sopenharmony_ci}
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ciSANE_Status
1723141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool m)
1724141cc406Sopenharmony_ci{
1725141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci  DBG (10, "sane_set_io_mode() called.\n");
1728141cc406Sopenharmony_ci
1729141cc406Sopenharmony_ci  if (!s->scanning)
1730141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1731141cc406Sopenharmony_ci  if (m == SANE_FALSE)
1732141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1733141cc406Sopenharmony_ci  else
1734141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1735141cc406Sopenharmony_ci}
1736141cc406Sopenharmony_ci
1737141cc406Sopenharmony_ciSANE_Status
1738141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fd)
1739141cc406Sopenharmony_ci{
1740141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) h;
1741141cc406Sopenharmony_ci
1742141cc406Sopenharmony_ci  DBG (10, "sane_get_select_fd() called.\n");
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  (void) fd;			/* to shut up compiler */
1745141cc406Sopenharmony_ci  (void) s;			/* to shut up compiler */
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1748141cc406Sopenharmony_ci}
1749141cc406Sopenharmony_ci
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci/* ========================================================================= */
1752141cc406Sopenharmony_ci/* private functions */
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_cistatic SANE_Status
1755141cc406Sopenharmony_cics2_open (const char *device, cs2_interface_t interface, cs2_t ** sp)
1756141cc406Sopenharmony_ci{
1757141cc406Sopenharmony_ci  SANE_Status status;
1758141cc406Sopenharmony_ci  cs2_t *s;
1759141cc406Sopenharmony_ci  char *prefix = NULL, *line;
1760141cc406Sopenharmony_ci  const char *device2;
1761141cc406Sopenharmony_ci  int i;
1762141cc406Sopenharmony_ci  int alloc_failed = 0;
1763141cc406Sopenharmony_ci  SANE_Device **device_list_new;
1764141cc406Sopenharmony_ci
1765141cc406Sopenharmony_ci  DBG (6, "cs2_open() called, with device = %s and interface = %i\n", device,
1766141cc406Sopenharmony_ci       interface);
1767141cc406Sopenharmony_ci
1768141cc406Sopenharmony_ci  if (!strncmp (device, "auto", 5))
1769141cc406Sopenharmony_ci    {
1770141cc406Sopenharmony_ci      try_interface = CS2_INTERFACE_SCSI;
1771141cc406Sopenharmony_ci      sanei_config_attach_matching_devices ("scsi Nikon *", cs2_attach);
1772141cc406Sopenharmony_ci      try_interface = CS2_INTERFACE_USB;
1773141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices ("usb 0x04b0 0x4000", cs2_attach);
1774141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices ("usb 0x04b0 0x4001", cs2_attach);
1775141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices ("usb 0x04b0 0x4002", cs2_attach);
1776141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1777141cc406Sopenharmony_ci    }
1778141cc406Sopenharmony_ci
1779141cc406Sopenharmony_ci  if ((s = (cs2_t *) cs2_xmalloc (sizeof (cs2_t))) == NULL)
1780141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1781141cc406Sopenharmony_ci  memset (s, 0, sizeof (cs2_t));
1782141cc406Sopenharmony_ci  s->send_buf = s->recv_buf = NULL;
1783141cc406Sopenharmony_ci  s->send_buf_size = s->recv_buf_size = 0;
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  switch (interface)
1786141cc406Sopenharmony_ci    {
1787141cc406Sopenharmony_ci    case CS2_INTERFACE_UNKNOWN:
1788141cc406Sopenharmony_ci      for (i = 0; i < 2; i++)
1789141cc406Sopenharmony_ci	{
1790141cc406Sopenharmony_ci	  switch (i)
1791141cc406Sopenharmony_ci	    {
1792141cc406Sopenharmony_ci	    case 1:
1793141cc406Sopenharmony_ci	      prefix = "usb:";
1794141cc406Sopenharmony_ci	      try_interface = CS2_INTERFACE_USB;
1795141cc406Sopenharmony_ci	      break;
1796141cc406Sopenharmony_ci	    default:
1797141cc406Sopenharmony_ci	      prefix = "scsi:";
1798141cc406Sopenharmony_ci	      try_interface = CS2_INTERFACE_SCSI;
1799141cc406Sopenharmony_ci	      break;
1800141cc406Sopenharmony_ci	    }
1801141cc406Sopenharmony_ci	  if (!strncmp (device, prefix, strlen (prefix)))
1802141cc406Sopenharmony_ci	    {
1803141cc406Sopenharmony_ci	      device2 = device + strlen (prefix);
1804141cc406Sopenharmony_ci	      cs2_xfree (s);
1805141cc406Sopenharmony_ci	      return cs2_open (device2, try_interface, sp);
1806141cc406Sopenharmony_ci	    }
1807141cc406Sopenharmony_ci	}
1808141cc406Sopenharmony_ci      cs2_xfree (s);
1809141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1810141cc406Sopenharmony_ci      break;
1811141cc406Sopenharmony_ci    case CS2_INTERFACE_SCSI:
1812141cc406Sopenharmony_ci      s->interface = CS2_INTERFACE_SCSI;
1813141cc406Sopenharmony_ci      DBG (6,
1814141cc406Sopenharmony_ci	   "cs2_open(): Trying to open %s, assuming SCSI or SBP2 interface ...\n",
1815141cc406Sopenharmony_ci	   device);
1816141cc406Sopenharmony_ci      status = sanei_scsi_open (device, &s->fd, cs2_scsi_sense_handler, s);
1817141cc406Sopenharmony_ci      if (status)
1818141cc406Sopenharmony_ci	{
1819141cc406Sopenharmony_ci	  DBG (6, "cs2_open(): ... failed: %s.\n", sane_strstatus (status));
1820141cc406Sopenharmony_ci	  cs2_xfree (s);
1821141cc406Sopenharmony_ci	  return status;
1822141cc406Sopenharmony_ci	}
1823141cc406Sopenharmony_ci      break;
1824141cc406Sopenharmony_ci    case CS2_INTERFACE_USB:
1825141cc406Sopenharmony_ci      s->interface = CS2_INTERFACE_USB;
1826141cc406Sopenharmony_ci      DBG (6, "cs2_open(): Trying to open %s, assuming USB interface ...\n",
1827141cc406Sopenharmony_ci	   device);
1828141cc406Sopenharmony_ci      status = sanei_usb_open (device, &s->fd);
1829141cc406Sopenharmony_ci      if (status)
1830141cc406Sopenharmony_ci	{
1831141cc406Sopenharmony_ci	  DBG (6, "cs2_open(): ... failed: %s.\n", sane_strstatus (status));
1832141cc406Sopenharmony_ci	  cs2_xfree (s);
1833141cc406Sopenharmony_ci	  return status;
1834141cc406Sopenharmony_ci	}
1835141cc406Sopenharmony_ci      break;
1836141cc406Sopenharmony_ci    }
1837141cc406Sopenharmony_ci
1838141cc406Sopenharmony_ci  open_devices++;
1839141cc406Sopenharmony_ci  DBG (6, "cs2_open(): ... looks OK, trying to identify device.\n");
1840141cc406Sopenharmony_ci
1841141cc406Sopenharmony_ci  /* identify scanner */
1842141cc406Sopenharmony_ci  status = cs2_page_inquiry (s, -1);
1843141cc406Sopenharmony_ci  if (status)
1844141cc406Sopenharmony_ci    {
1845141cc406Sopenharmony_ci      DBG (4, "Error: cs2_open(): failed to get page: %s.\n",
1846141cc406Sopenharmony_ci	   sane_strstatus (status));
1847141cc406Sopenharmony_ci      cs2_close (s);
1848141cc406Sopenharmony_ci      return status;
1849141cc406Sopenharmony_ci    }
1850141cc406Sopenharmony_ci
1851141cc406Sopenharmony_ci  strncpy (s->vendor_string, (char *)s->recv_buf + 8, 8);
1852141cc406Sopenharmony_ci  s->vendor_string[8] = '\0';
1853141cc406Sopenharmony_ci  strncpy (s->product_string, (char *)s->recv_buf + 16, 16);
1854141cc406Sopenharmony_ci  s->product_string[16] = '\0';
1855141cc406Sopenharmony_ci  strncpy (s->revision_string, (char *)s->recv_buf + 32, 4);
1856141cc406Sopenharmony_ci  s->revision_string[4] = '\0';
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci  DBG (10,
1859141cc406Sopenharmony_ci       "cs2_open(): Inquiry reveals: vendor = '%s', product = '%s', revision = '%s'.\n",
1860141cc406Sopenharmony_ci       s->vendor_string, s->product_string, s->revision_string);
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_ci  if (!strncmp (s->product_string, "COOLSCANIII     ", 16))
1863141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS30;
1864141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-40 ED        ", 16))
1865141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS40;
1866141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-50 ED        ", 16))
1867141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS50;
1868141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-2000         ", 16))
1869141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS2000;
1870141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-4000 ED      ", 16))
1871141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS4000;
1872141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-5000 ED      ", 16))
1873141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS5000;
1874141cc406Sopenharmony_ci  else if (!strncmp (s->product_string, "LS-8000 ED      ", 16))
1875141cc406Sopenharmony_ci    s->type = CS2_TYPE_LS8000;
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci  if (s->type != CS2_TYPE_UNKOWN)
1878141cc406Sopenharmony_ci    DBG (10, "cs2_open(): Device identified as coolscan2 type #%i.\n",
1879141cc406Sopenharmony_ci	 s->type);
1880141cc406Sopenharmony_ci  else
1881141cc406Sopenharmony_ci    {
1882141cc406Sopenharmony_ci      DBG (10, "cs2_open(): Device not identified.\n");
1883141cc406Sopenharmony_ci      cs2_close (s);
1884141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1885141cc406Sopenharmony_ci    }
1886141cc406Sopenharmony_ci
1887141cc406Sopenharmony_ci  if (sp)
1888141cc406Sopenharmony_ci    *sp = s;
1889141cc406Sopenharmony_ci  else
1890141cc406Sopenharmony_ci    {
1891141cc406Sopenharmony_ci      device_list_new =
1892141cc406Sopenharmony_ci	(SANE_Device **) cs2_xrealloc (device_list,
1893141cc406Sopenharmony_ci				       (n_device_list +
1894141cc406Sopenharmony_ci					2) * sizeof (SANE_Device *));
1895141cc406Sopenharmony_ci      if (!device_list_new)
1896141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
1897141cc406Sopenharmony_ci      device_list = device_list_new;
1898141cc406Sopenharmony_ci      device_list[n_device_list] =
1899141cc406Sopenharmony_ci	(SANE_Device *) cs2_xmalloc (sizeof (SANE_Device));
1900141cc406Sopenharmony_ci      if (!device_list[n_device_list])
1901141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
1902141cc406Sopenharmony_ci      switch (interface)
1903141cc406Sopenharmony_ci	{
1904141cc406Sopenharmony_ci	case CS2_INTERFACE_UNKNOWN:
1905141cc406Sopenharmony_ci	  DBG (1, "BUG: cs2_open(): unknown interface.\n");
1906141cc406Sopenharmony_ci	  cs2_close (s);
1907141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
1908141cc406Sopenharmony_ci	  break;
1909141cc406Sopenharmony_ci	case CS2_INTERFACE_SCSI:
1910141cc406Sopenharmony_ci	  prefix = "scsi:";
1911141cc406Sopenharmony_ci	  break;
1912141cc406Sopenharmony_ci	case CS2_INTERFACE_USB:
1913141cc406Sopenharmony_ci	  prefix = "usb:";
1914141cc406Sopenharmony_ci	  break;
1915141cc406Sopenharmony_ci	}
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci      line = (char *) cs2_xmalloc (strlen (device) + strlen (prefix) + 1);
1918141cc406Sopenharmony_ci      if (!line)
1919141cc406Sopenharmony_ci	alloc_failed = 1;
1920141cc406Sopenharmony_ci      else
1921141cc406Sopenharmony_ci	{
1922141cc406Sopenharmony_ci	  strcpy (line, prefix);
1923141cc406Sopenharmony_ci	  strcat (line, device);
1924141cc406Sopenharmony_ci	  device_list[n_device_list]->name = line;
1925141cc406Sopenharmony_ci	}
1926141cc406Sopenharmony_ci
1927141cc406Sopenharmony_ci      line = (char *) cs2_xmalloc (strlen (s->vendor_string) + 1);
1928141cc406Sopenharmony_ci      if (!line)
1929141cc406Sopenharmony_ci	alloc_failed = 1;
1930141cc406Sopenharmony_ci      else
1931141cc406Sopenharmony_ci	{
1932141cc406Sopenharmony_ci	  strcpy (line, s->vendor_string);
1933141cc406Sopenharmony_ci	  device_list[n_device_list]->vendor = line;
1934141cc406Sopenharmony_ci	}
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci      line = (char *) cs2_xmalloc (strlen (s->product_string) + 1);
1937141cc406Sopenharmony_ci      if (!line)
1938141cc406Sopenharmony_ci	alloc_failed = 1;
1939141cc406Sopenharmony_ci      else
1940141cc406Sopenharmony_ci	{
1941141cc406Sopenharmony_ci	  strcpy (line, s->product_string);
1942141cc406Sopenharmony_ci	  device_list[n_device_list]->model = line;
1943141cc406Sopenharmony_ci	}
1944141cc406Sopenharmony_ci
1945141cc406Sopenharmony_ci      device_list[n_device_list]->type = "film scanner";
1946141cc406Sopenharmony_ci
1947141cc406Sopenharmony_ci      if (alloc_failed)
1948141cc406Sopenharmony_ci	{
1949141cc406Sopenharmony_ci	  cs2_xfree (device_list[n_device_list]->name);
1950141cc406Sopenharmony_ci	  cs2_xfree (device_list[n_device_list]->vendor);
1951141cc406Sopenharmony_ci	  cs2_xfree (device_list[n_device_list]->model);
1952141cc406Sopenharmony_ci	  cs2_xfree (device_list[n_device_list]);
1953141cc406Sopenharmony_ci	}
1954141cc406Sopenharmony_ci      else
1955141cc406Sopenharmony_ci	n_device_list++;
1956141cc406Sopenharmony_ci      device_list[n_device_list] = NULL;
1957141cc406Sopenharmony_ci
1958141cc406Sopenharmony_ci      cs2_close (s);
1959141cc406Sopenharmony_ci    }
1960141cc406Sopenharmony_ci
1961141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1962141cc406Sopenharmony_ci}
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_civoid
1965141cc406Sopenharmony_cics2_close (cs2_t * s)
1966141cc406Sopenharmony_ci{
1967141cc406Sopenharmony_ci  cs2_xfree (s->lut_r);
1968141cc406Sopenharmony_ci  cs2_xfree (s->lut_g);
1969141cc406Sopenharmony_ci  cs2_xfree (s->lut_b);
1970141cc406Sopenharmony_ci  cs2_xfree (s->lut_neutral);
1971141cc406Sopenharmony_ci  cs2_xfree (s->infrared_buf);
1972141cc406Sopenharmony_ci  cs2_xfree (s->line_buf);
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci  switch (s->interface)
1975141cc406Sopenharmony_ci    {
1976141cc406Sopenharmony_ci    case CS2_INTERFACE_UNKNOWN:
1977141cc406Sopenharmony_ci      DBG (1, "BUG: cs2_close(): Unknown interface number.\n");
1978141cc406Sopenharmony_ci      break;
1979141cc406Sopenharmony_ci    case CS2_INTERFACE_SCSI:
1980141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
1981141cc406Sopenharmony_ci      open_devices--;
1982141cc406Sopenharmony_ci      break;
1983141cc406Sopenharmony_ci    case CS2_INTERFACE_USB:
1984141cc406Sopenharmony_ci      sanei_usb_close (s->fd);
1985141cc406Sopenharmony_ci      open_devices--;
1986141cc406Sopenharmony_ci      break;
1987141cc406Sopenharmony_ci    }
1988141cc406Sopenharmony_ci
1989141cc406Sopenharmony_ci  cs2_xfree (s);
1990141cc406Sopenharmony_ci}
1991141cc406Sopenharmony_ci
1992141cc406Sopenharmony_cistatic SANE_Status
1993141cc406Sopenharmony_cics2_attach (const char *dev)
1994141cc406Sopenharmony_ci{
1995141cc406Sopenharmony_ci  SANE_Status status;
1996141cc406Sopenharmony_ci
1997141cc406Sopenharmony_ci  if (try_interface == CS2_INTERFACE_UNKNOWN)
1998141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1999141cc406Sopenharmony_ci
2000141cc406Sopenharmony_ci  status = cs2_open (dev, try_interface, NULL);
2001141cc406Sopenharmony_ci  return status;
2002141cc406Sopenharmony_ci}
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_cistatic SANE_Status
2005141cc406Sopenharmony_cics2_scsi_sense_handler (int fd, u_char * sense_buffer, void *arg)
2006141cc406Sopenharmony_ci{
2007141cc406Sopenharmony_ci  cs2_t *s = (cs2_t *) arg;
2008141cc406Sopenharmony_ci
2009141cc406Sopenharmony_ci  (void) fd;			/* to shut up compiler */
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  /* sort this out ! XXXXXXXXX */
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci  s->sense_key = sense_buffer[2] & 0x0f;
2014141cc406Sopenharmony_ci  s->sense_asc = sense_buffer[12];
2015141cc406Sopenharmony_ci  s->sense_ascq = sense_buffer[13];
2016141cc406Sopenharmony_ci  s->sense_info = sense_buffer[3];
2017141cc406Sopenharmony_ci
2018141cc406Sopenharmony_ci  return cs2_parse_sense_data (s);
2019141cc406Sopenharmony_ci}
2020141cc406Sopenharmony_ci
2021141cc406Sopenharmony_cistatic SANE_Status
2022141cc406Sopenharmony_cics2_parse_sense_data (cs2_t * s)
2023141cc406Sopenharmony_ci{
2024141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci  s->sense_code =
2027141cc406Sopenharmony_ci    (s->sense_key << 24) + (s->sense_asc << 16) + (s->sense_ascq << 8) +
2028141cc406Sopenharmony_ci    s->sense_info;
2029141cc406Sopenharmony_ci
2030141cc406Sopenharmony_ci  if (s->sense_key)
2031141cc406Sopenharmony_ci    DBG (10, "Sense code: %02lx-%02lx-%02lx-%02lx\n", s->sense_key,
2032141cc406Sopenharmony_ci	 s->sense_asc, s->sense_ascq, s->sense_info);
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci  switch (s->sense_key)
2035141cc406Sopenharmony_ci    {
2036141cc406Sopenharmony_ci    case 0x00:
2037141cc406Sopenharmony_ci      s->status = CS2_STATUS_READY;
2038141cc406Sopenharmony_ci      break;
2039141cc406Sopenharmony_ci    case 0x02:
2040141cc406Sopenharmony_ci      switch (s->sense_asc)
2041141cc406Sopenharmony_ci	{
2042141cc406Sopenharmony_ci	case 0x04:
2043141cc406Sopenharmony_ci	  s->status = CS2_STATUS_PROCESSING;
2044141cc406Sopenharmony_ci	  break;
2045141cc406Sopenharmony_ci	case 0x3a:
2046141cc406Sopenharmony_ci	  s->status = CS2_STATUS_NO_DOCS;
2047141cc406Sopenharmony_ci	  break;
2048141cc406Sopenharmony_ci	default:
2049141cc406Sopenharmony_ci	  s->status = CS2_STATUS_ERROR;
2050141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2051141cc406Sopenharmony_ci	  break;
2052141cc406Sopenharmony_ci	}
2053141cc406Sopenharmony_ci      break;
2054141cc406Sopenharmony_ci    default:
2055141cc406Sopenharmony_ci      s->status = CS2_STATUS_ERROR;
2056141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
2057141cc406Sopenharmony_ci      break;
2058141cc406Sopenharmony_ci    }
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci  if ((s->sense_code == 0x09800600) || (s->sense_code == 0x09800601))
2061141cc406Sopenharmony_ci    s->status = CS2_STATUS_REISSUE;
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_ci  return status;
2064141cc406Sopenharmony_ci}
2065141cc406Sopenharmony_ci
2066141cc406Sopenharmony_cistatic void
2067141cc406Sopenharmony_cics2_init_buffer (cs2_t * s)
2068141cc406Sopenharmony_ci{
2069141cc406Sopenharmony_ci  s->n_cmd = 0;
2070141cc406Sopenharmony_ci  s->n_send = 0;
2071141cc406Sopenharmony_ci  s->n_recv = 0;
2072141cc406Sopenharmony_ci}
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_cistatic SANE_Status
2075141cc406Sopenharmony_cics2_pack_byte (cs2_t * s, SANE_Byte byte)
2076141cc406Sopenharmony_ci{
2077141cc406Sopenharmony_ci  while (s->send_buf_size <= s->n_send)
2078141cc406Sopenharmony_ci    {
2079141cc406Sopenharmony_ci      s->send_buf_size += 16;
2080141cc406Sopenharmony_ci      s->send_buf =
2081141cc406Sopenharmony_ci	(SANE_Byte *) cs2_xrealloc (s->send_buf, s->send_buf_size);
2082141cc406Sopenharmony_ci      if (!s->send_buf)
2083141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
2084141cc406Sopenharmony_ci    }
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci  s->send_buf[s->n_send++] = byte;
2087141cc406Sopenharmony_ci
2088141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2089141cc406Sopenharmony_ci}
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_cistatic SANE_Status
2092141cc406Sopenharmony_cics2_parse_cmd (cs2_t * s, char *text)
2093141cc406Sopenharmony_ci{
2094141cc406Sopenharmony_ci  size_t i, j;
2095141cc406Sopenharmony_ci  char c, h;
2096141cc406Sopenharmony_ci  SANE_Status status;
2097141cc406Sopenharmony_ci
2098141cc406Sopenharmony_ci  for (i = 0; i < strlen (text); i += 2)
2099141cc406Sopenharmony_ci    if (text[i] == ' ')
2100141cc406Sopenharmony_ci      i--;			/* a bit dirty... advance by -1+2=1 */
2101141cc406Sopenharmony_ci    else
2102141cc406Sopenharmony_ci      {
2103141cc406Sopenharmony_ci	if ((!isxdigit (text[i])) || (!isxdigit (text[i + 1])))
2104141cc406Sopenharmony_ci	  DBG (1, "BUG: cs2_parse_cmd(): Parser got invalid character.\n");
2105141cc406Sopenharmony_ci	c = 0;
2106141cc406Sopenharmony_ci	for (j = 0; j < 2; j++)
2107141cc406Sopenharmony_ci	  {
2108141cc406Sopenharmony_ci	    h = tolower (text[i + j]);
2109141cc406Sopenharmony_ci	    if ((h >= 'a') && (h <= 'f'))
2110141cc406Sopenharmony_ci	      c += 10 + h - 'a';
2111141cc406Sopenharmony_ci	    else
2112141cc406Sopenharmony_ci	      c += h - '0';
2113141cc406Sopenharmony_ci	    if (j == 0)
2114141cc406Sopenharmony_ci	      c <<= 4;
2115141cc406Sopenharmony_ci	  }
2116141cc406Sopenharmony_ci	status = cs2_pack_byte (s, c);
2117141cc406Sopenharmony_ci	if (status)
2118141cc406Sopenharmony_ci	  return status;
2119141cc406Sopenharmony_ci      }
2120141cc406Sopenharmony_ci
2121141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2122141cc406Sopenharmony_ci}
2123141cc406Sopenharmony_ci
2124141cc406Sopenharmony_cistatic SANE_Status
2125141cc406Sopenharmony_cics2_grow_send_buffer (cs2_t * s)
2126141cc406Sopenharmony_ci{
2127141cc406Sopenharmony_ci  if (s->n_send > s->send_buf_size)
2128141cc406Sopenharmony_ci    {
2129141cc406Sopenharmony_ci      s->send_buf_size = s->n_send;
2130141cc406Sopenharmony_ci      s->send_buf =
2131141cc406Sopenharmony_ci	(SANE_Byte *) cs2_xrealloc (s->send_buf, s->send_buf_size);
2132141cc406Sopenharmony_ci      if (!s->send_buf)
2133141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
2134141cc406Sopenharmony_ci    }
2135141cc406Sopenharmony_ci
2136141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2137141cc406Sopenharmony_ci}
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_cistatic SANE_Status
2140141cc406Sopenharmony_cics2_issue_cmd (cs2_t * s)
2141141cc406Sopenharmony_ci{
2142141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_INVAL;
2143141cc406Sopenharmony_ci  size_t n_data, n_status;
2144141cc406Sopenharmony_ci  static SANE_Byte status_buf[8];
2145141cc406Sopenharmony_ci  int status_only = 0;
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci  DBG (20, "cs2_issue_cmd(): opcode = 0x%02x, n_send = %lu, n_recv = %lu.\n",
2148141cc406Sopenharmony_ci       s->send_buf[0], (unsigned long) s->n_send, (unsigned long) s->n_recv);
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci  s->status = CS2_STATUS_READY;
2151141cc406Sopenharmony_ci
2152141cc406Sopenharmony_ci  if (!s->n_cmd)
2153141cc406Sopenharmony_ci    switch (s->send_buf[0])
2154141cc406Sopenharmony_ci      {
2155141cc406Sopenharmony_ci      case 0x00:
2156141cc406Sopenharmony_ci      case 0x12:
2157141cc406Sopenharmony_ci      case 0x15:
2158141cc406Sopenharmony_ci      case 0x16:
2159141cc406Sopenharmony_ci      case 0x17:
2160141cc406Sopenharmony_ci      case 0x1a:
2161141cc406Sopenharmony_ci      case 0x1b:
2162141cc406Sopenharmony_ci      case 0x1c:
2163141cc406Sopenharmony_ci      case 0x1d:
2164141cc406Sopenharmony_ci      case 0xc0:
2165141cc406Sopenharmony_ci      case 0xc1:
2166141cc406Sopenharmony_ci	s->n_cmd = 6;
2167141cc406Sopenharmony_ci	break;
2168141cc406Sopenharmony_ci      case 0x24:
2169141cc406Sopenharmony_ci      case 0x25:
2170141cc406Sopenharmony_ci      case 0x28:
2171141cc406Sopenharmony_ci      case 0x2a:
2172141cc406Sopenharmony_ci      case 0xe0:
2173141cc406Sopenharmony_ci      case 0xe1:
2174141cc406Sopenharmony_ci	s->n_cmd = 10;
2175141cc406Sopenharmony_ci	break;
2176141cc406Sopenharmony_ci      default:
2177141cc406Sopenharmony_ci	DBG (1, "BUG: cs2_issue_cmd(): Unknown command opcode 0x%02x.\n",
2178141cc406Sopenharmony_ci	     s->send_buf[0]);
2179141cc406Sopenharmony_ci	break;
2180141cc406Sopenharmony_ci      }
2181141cc406Sopenharmony_ci
2182141cc406Sopenharmony_ci  if (s->n_send < s->n_cmd)
2183141cc406Sopenharmony_ci    {
2184141cc406Sopenharmony_ci      DBG (1,
2185141cc406Sopenharmony_ci	   "BUG: cs2_issue_cmd(): Negative number of data out bytes requested.\n");
2186141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2187141cc406Sopenharmony_ci    }
2188141cc406Sopenharmony_ci
2189141cc406Sopenharmony_ci  n_data = s->n_send - s->n_cmd;
2190141cc406Sopenharmony_ci  if (s->n_recv > 0)
2191141cc406Sopenharmony_ci    {
2192141cc406Sopenharmony_ci      if (n_data > 0)
2193141cc406Sopenharmony_ci	{
2194141cc406Sopenharmony_ci	  DBG (1,
2195141cc406Sopenharmony_ci	       "BUG: cs2_issue_cmd(): Both data in and data out requested.\n");
2196141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
2197141cc406Sopenharmony_ci	}
2198141cc406Sopenharmony_ci      else
2199141cc406Sopenharmony_ci	{
2200141cc406Sopenharmony_ci	  n_data = s->n_recv;
2201141cc406Sopenharmony_ci	}
2202141cc406Sopenharmony_ci    }
2203141cc406Sopenharmony_ci
2204141cc406Sopenharmony_ci  s->recv_buf = (SANE_Byte *) cs2_xrealloc (s->recv_buf, s->n_recv);
2205141cc406Sopenharmony_ci  if (!s->recv_buf)
2206141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_ci  switch (s->interface)
2209141cc406Sopenharmony_ci    {
2210141cc406Sopenharmony_ci    case CS2_INTERFACE_UNKNOWN:
2211141cc406Sopenharmony_ci      DBG (1,
2212141cc406Sopenharmony_ci	   "BUG: cs2_issue_cmd(): Unknown or uninitialized interface number.\n");
2213141cc406Sopenharmony_ci      break;
2214141cc406Sopenharmony_ci    case CS2_INTERFACE_SCSI:
2215141cc406Sopenharmony_ci      sanei_scsi_cmd2 (s->fd, s->send_buf, s->n_cmd, s->send_buf + s->n_cmd,
2216141cc406Sopenharmony_ci		       s->n_send - s->n_cmd, s->recv_buf, &s->n_recv);
2217141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2218141cc406Sopenharmony_ci      break;
2219141cc406Sopenharmony_ci    case CS2_INTERFACE_USB:
2220141cc406Sopenharmony_ci      status = sanei_usb_write_bulk (s->fd, s->send_buf, &s->n_cmd);
2221141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2222141cc406Sopenharmony_ci        {
2223141cc406Sopenharmony_ci          DBG (1, "Error: cs2_issue_cmd(): Could not write command.\n");
2224141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
2225141cc406Sopenharmony_ci        }
2226141cc406Sopenharmony_ci      switch (cs2_phase_check (s))
2227141cc406Sopenharmony_ci	{
2228141cc406Sopenharmony_ci	case CS2_PHASE_OUT:
2229141cc406Sopenharmony_ci	  if (s->n_send - s->n_cmd < n_data || !n_data)
2230141cc406Sopenharmony_ci	    {
2231141cc406Sopenharmony_ci	      DBG (4, "Error: cs2_issue_cmd(): Unexpected data out phase.\n");
2232141cc406Sopenharmony_ci	      return SANE_STATUS_IO_ERROR;
2233141cc406Sopenharmony_ci	    }
2234141cc406Sopenharmony_ci	  status =
2235141cc406Sopenharmony_ci	    sanei_usb_write_bulk (s->fd, s->send_buf + s->n_cmd, &n_data);
2236141cc406Sopenharmony_ci	  break;
2237141cc406Sopenharmony_ci	case CS2_PHASE_IN:
2238141cc406Sopenharmony_ci	  if (s->n_recv < n_data || !n_data)
2239141cc406Sopenharmony_ci	    {
2240141cc406Sopenharmony_ci	      DBG (4, "Error: cs2_issue_cmd(): Unexpected data in phase.\n");
2241141cc406Sopenharmony_ci	      return SANE_STATUS_IO_ERROR;
2242141cc406Sopenharmony_ci	    }
2243141cc406Sopenharmony_ci	  status = sanei_usb_read_bulk (s->fd, s->recv_buf, &n_data);
2244141cc406Sopenharmony_ci	  s->n_recv = n_data;
2245141cc406Sopenharmony_ci	  break;
2246141cc406Sopenharmony_ci	case CS2_PHASE_NONE:
2247141cc406Sopenharmony_ci	  DBG (4, "Error: cs2_issue_cmd(): No command received!\n");
2248141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
2249141cc406Sopenharmony_ci	default:
2250141cc406Sopenharmony_ci	  if (n_data)
2251141cc406Sopenharmony_ci	    {
2252141cc406Sopenharmony_ci	      DBG (4,
2253141cc406Sopenharmony_ci		   "Error: cs2_issue_cmd(): Unexpected non-data phase, but n_data != 0.\n");
2254141cc406Sopenharmony_ci	      status_only = 1;
2255141cc406Sopenharmony_ci	    }
2256141cc406Sopenharmony_ci	  break;
2257141cc406Sopenharmony_ci	}
2258141cc406Sopenharmony_ci      n_status = 8;
2259141cc406Sopenharmony_ci      status = sanei_usb_read_bulk (s->fd, status_buf, &n_status);
2260141cc406Sopenharmony_ci      if (n_status != 8)
2261141cc406Sopenharmony_ci	{
2262141cc406Sopenharmony_ci	  DBG (4,
2263141cc406Sopenharmony_ci	       "Error: cs2_issue_cmd(): Failed to read 8 status bytes from USB.\n");
2264141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
2265141cc406Sopenharmony_ci	}
2266141cc406Sopenharmony_ci      s->sense_key = status_buf[1] & 0x0f;
2267141cc406Sopenharmony_ci      s->sense_asc = status_buf[2] & 0xff;
2268141cc406Sopenharmony_ci      s->sense_ascq = status_buf[3] & 0xff;
2269141cc406Sopenharmony_ci      s->sense_info = status_buf[4] & 0xff;
2270141cc406Sopenharmony_ci      cs2_parse_sense_data (s);
2271141cc406Sopenharmony_ci      break;
2272141cc406Sopenharmony_ci    }
2273141cc406Sopenharmony_ci
2274141cc406Sopenharmony_ci  if (status_only)
2275141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
2276141cc406Sopenharmony_ci  else
2277141cc406Sopenharmony_ci    return status;
2278141cc406Sopenharmony_ci}
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_cistatic cs2_phase_t
2281141cc406Sopenharmony_cics2_phase_check (cs2_t * s)
2282141cc406Sopenharmony_ci{
2283141cc406Sopenharmony_ci  static SANE_Byte phase_send_buf[1] = { 0xd0 }, phase_recv_buf[1];
2284141cc406Sopenharmony_ci  SANE_Status status = 0;
2285141cc406Sopenharmony_ci  size_t n = 1;
2286141cc406Sopenharmony_ci
2287141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (s->fd, phase_send_buf, &n);
2288141cc406Sopenharmony_ci  status |= sanei_usb_read_bulk (s->fd, phase_recv_buf, &n);
2289141cc406Sopenharmony_ci
2290141cc406Sopenharmony_ci  DBG (6, "cs2_phase_check(): Phase check returned phase = 0x%02x.\n",
2291141cc406Sopenharmony_ci       phase_recv_buf[0]);
2292141cc406Sopenharmony_ci
2293141cc406Sopenharmony_ci  if (status)
2294141cc406Sopenharmony_ci    return -1;
2295141cc406Sopenharmony_ci  else
2296141cc406Sopenharmony_ci    return phase_recv_buf[0];
2297141cc406Sopenharmony_ci}
2298141cc406Sopenharmony_ci
2299141cc406Sopenharmony_cistatic SANE_Status
2300141cc406Sopenharmony_cics2_scanner_ready (cs2_t * s, int flags)
2301141cc406Sopenharmony_ci{
2302141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
2303141cc406Sopenharmony_ci  int i = -1;
2304141cc406Sopenharmony_ci  unsigned long count = 0;
2305141cc406Sopenharmony_ci  int retry = 3;
2306141cc406Sopenharmony_ci
2307141cc406Sopenharmony_ci  do
2308141cc406Sopenharmony_ci    {
2309141cc406Sopenharmony_ci      if (i >= 0)		/* dirty !!! */
2310141cc406Sopenharmony_ci	usleep (500000);
2311141cc406Sopenharmony_ci      cs2_init_buffer (s);
2312141cc406Sopenharmony_ci      for (i = 0; i < 6; i++)
2313141cc406Sopenharmony_ci	cs2_pack_byte (s, 0x00);
2314141cc406Sopenharmony_ci      status = cs2_issue_cmd (s);
2315141cc406Sopenharmony_ci      if (status)
2316141cc406Sopenharmony_ci	if (--retry < 0)
2317141cc406Sopenharmony_ci	  return status;
2318141cc406Sopenharmony_ci      if (++count > 240)
2319141cc406Sopenharmony_ci	{			/* 120s timeout */
2320141cc406Sopenharmony_ci	  DBG (4, "Error: cs2_scanner_ready(): Timeout expired.\n");
2321141cc406Sopenharmony_ci	  status = SANE_STATUS_IO_ERROR;
2322141cc406Sopenharmony_ci	  break;
2323141cc406Sopenharmony_ci	}
2324141cc406Sopenharmony_ci    }
2325141cc406Sopenharmony_ci  while (s->status & ~flags);	/* until all relevant bits are 0 */
2326141cc406Sopenharmony_ci
2327141cc406Sopenharmony_ci  return status;
2328141cc406Sopenharmony_ci}
2329141cc406Sopenharmony_ci
2330141cc406Sopenharmony_cistatic SANE_Status
2331141cc406Sopenharmony_cics2_page_inquiry (cs2_t * s, int page)
2332141cc406Sopenharmony_ci{
2333141cc406Sopenharmony_ci  SANE_Status status;
2334141cc406Sopenharmony_ci
2335141cc406Sopenharmony_ci  size_t n;
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_ci  if (page >= 0)
2338141cc406Sopenharmony_ci    {
2339141cc406Sopenharmony_ci
2340141cc406Sopenharmony_ci      cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2341141cc406Sopenharmony_ci      cs2_init_buffer (s);
2342141cc406Sopenharmony_ci      cs2_parse_cmd (s, "12 01");
2343141cc406Sopenharmony_ci      cs2_pack_byte (s, page);
2344141cc406Sopenharmony_ci      cs2_parse_cmd (s, "00 04 00");
2345141cc406Sopenharmony_ci      s->n_recv = 4;
2346141cc406Sopenharmony_ci      status = cs2_issue_cmd (s);
2347141cc406Sopenharmony_ci      if (status)
2348141cc406Sopenharmony_ci	{
2349141cc406Sopenharmony_ci	  DBG (4,
2350141cc406Sopenharmony_ci	       "Error: cs2_page_inquiry(): Inquiry of page size failed: %s.\n",
2351141cc406Sopenharmony_ci	       sane_strstatus (status));
2352141cc406Sopenharmony_ci	  return status;
2353141cc406Sopenharmony_ci	}
2354141cc406Sopenharmony_ci
2355141cc406Sopenharmony_ci      n = s->recv_buf[3] + 4;
2356141cc406Sopenharmony_ci
2357141cc406Sopenharmony_ci    }
2358141cc406Sopenharmony_ci  else
2359141cc406Sopenharmony_ci    n = 36;
2360141cc406Sopenharmony_ci
2361141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2362141cc406Sopenharmony_ci  cs2_init_buffer (s);
2363141cc406Sopenharmony_ci  if (page >= 0)
2364141cc406Sopenharmony_ci    {
2365141cc406Sopenharmony_ci      cs2_parse_cmd (s, "12 01");
2366141cc406Sopenharmony_ci      cs2_pack_byte (s, page);
2367141cc406Sopenharmony_ci      cs2_parse_cmd (s, "00");
2368141cc406Sopenharmony_ci    }
2369141cc406Sopenharmony_ci  else
2370141cc406Sopenharmony_ci    cs2_parse_cmd (s, "12 00 00 00");
2371141cc406Sopenharmony_ci  cs2_pack_byte (s, n);
2372141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00");
2373141cc406Sopenharmony_ci  s->n_recv = n;
2374141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2375141cc406Sopenharmony_ci  if (status)
2376141cc406Sopenharmony_ci    {
2377141cc406Sopenharmony_ci      DBG (4, "Error: cs2_page_inquiry(): Inquiry of page failed: %s.\n",
2378141cc406Sopenharmony_ci	   sane_strstatus (status));
2379141cc406Sopenharmony_ci      return status;
2380141cc406Sopenharmony_ci    }
2381141cc406Sopenharmony_ci
2382141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2383141cc406Sopenharmony_ci}
2384141cc406Sopenharmony_ci
2385141cc406Sopenharmony_cistatic SANE_Status
2386141cc406Sopenharmony_cics2_full_inquiry (cs2_t * s)
2387141cc406Sopenharmony_ci{
2388141cc406Sopenharmony_ci  SANE_Status status;
2389141cc406Sopenharmony_ci  int pitch, pitch_max;
2390141cc406Sopenharmony_ci  cs2_pixel_t pixel;
2391141cc406Sopenharmony_ci
2392141cc406Sopenharmony_ci  status = cs2_page_inquiry (s, 0xc1);
2393141cc406Sopenharmony_ci  if (status)
2394141cc406Sopenharmony_ci    {
2395141cc406Sopenharmony_ci      DBG (4, "Error: cs2_full_inquiry(): Failed to get page: %s\n",
2396141cc406Sopenharmony_ci	   sane_strstatus (status));
2397141cc406Sopenharmony_ci      return status;
2398141cc406Sopenharmony_ci    }
2399141cc406Sopenharmony_ci
2400141cc406Sopenharmony_ci  s->maxbits = s->recv_buf[82];
2401141cc406Sopenharmony_ci  if (s->type == CS2_TYPE_LS30)	/* must be overridden, LS-30 claims to have 12 bits */
2402141cc406Sopenharmony_ci    s->maxbits = 10;
2403141cc406Sopenharmony_ci
2404141cc406Sopenharmony_ci  s->n_lut = 1;
2405141cc406Sopenharmony_ci  s->n_lut <<= s->maxbits;
2406141cc406Sopenharmony_ci  s->lut_r =
2407141cc406Sopenharmony_ci    (cs2_pixel_t *) cs2_xrealloc (s->lut_r, s->n_lut * sizeof (cs2_pixel_t));
2408141cc406Sopenharmony_ci  s->lut_g =
2409141cc406Sopenharmony_ci    (cs2_pixel_t *) cs2_xrealloc (s->lut_g, s->n_lut * sizeof (cs2_pixel_t));
2410141cc406Sopenharmony_ci  s->lut_b =
2411141cc406Sopenharmony_ci    (cs2_pixel_t *) cs2_xrealloc (s->lut_b, s->n_lut * sizeof (cs2_pixel_t));
2412141cc406Sopenharmony_ci  s->lut_neutral =
2413141cc406Sopenharmony_ci    (cs2_pixel_t *) cs2_xrealloc (s->lut_neutral,
2414141cc406Sopenharmony_ci				  s->n_lut * sizeof (cs2_pixel_t));
2415141cc406Sopenharmony_ci
2416141cc406Sopenharmony_ci  if (!s->lut_r || !s->lut_g || !s->lut_b || !s->lut_neutral)
2417141cc406Sopenharmony_ci    {
2418141cc406Sopenharmony_ci      cs2_xfree (s->lut_r);
2419141cc406Sopenharmony_ci      cs2_xfree (s->lut_g);
2420141cc406Sopenharmony_ci      cs2_xfree (s->lut_b);
2421141cc406Sopenharmony_ci      cs2_xfree (s->lut_neutral);
2422141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2423141cc406Sopenharmony_ci    }
2424141cc406Sopenharmony_ci
2425141cc406Sopenharmony_ci  for (pixel = 0; pixel < s->n_lut; pixel++)
2426141cc406Sopenharmony_ci    s->lut_r[pixel] = s->lut_g[pixel] = s->lut_b[pixel] =
2427141cc406Sopenharmony_ci      s->lut_neutral[pixel] = pixel;
2428141cc406Sopenharmony_ci
2429141cc406Sopenharmony_ci  s->resx_optical = 256 * s->recv_buf[18] + s->recv_buf[19];
2430141cc406Sopenharmony_ci  s->resx_max = 256 * s->recv_buf[20] + s->recv_buf[21];
2431141cc406Sopenharmony_ci  s->resx_min = 256 * s->recv_buf[22] + s->recv_buf[23];
2432141cc406Sopenharmony_ci  s->boundaryx =
2433141cc406Sopenharmony_ci    65536 * (256 * s->recv_buf[36] + s->recv_buf[37]) +
2434141cc406Sopenharmony_ci    256 * s->recv_buf[38] + s->recv_buf[39];
2435141cc406Sopenharmony_ci
2436141cc406Sopenharmony_ci  s->resy_optical = 256 * s->recv_buf[40] + s->recv_buf[41];
2437141cc406Sopenharmony_ci  s->resy_max = 256 * s->recv_buf[42] + s->recv_buf[43];
2438141cc406Sopenharmony_ci  s->resy_min = 256 * s->recv_buf[44] + s->recv_buf[45];
2439141cc406Sopenharmony_ci  s->boundaryy =
2440141cc406Sopenharmony_ci    65536 * (256 * s->recv_buf[58] + s->recv_buf[59]) +
2441141cc406Sopenharmony_ci    256 * s->recv_buf[60] + s->recv_buf[61];
2442141cc406Sopenharmony_ci
2443141cc406Sopenharmony_ci  s->focus_min = 256 * s->recv_buf[76] + s->recv_buf[77];
2444141cc406Sopenharmony_ci  s->focus_max = 256 * s->recv_buf[78] + s->recv_buf[79];
2445141cc406Sopenharmony_ci
2446141cc406Sopenharmony_ci  s->n_frames = s->recv_buf[75];
2447141cc406Sopenharmony_ci
2448141cc406Sopenharmony_ci  s->frame_offset = s->resy_max * 1.5 + 1;	/* works for LS-30, maybe not for others */
2449141cc406Sopenharmony_ci
2450141cc406Sopenharmony_ci  /* generate resolution list for x */
2451141cc406Sopenharmony_ci  s->resx_n_list = pitch_max = floor (s->resx_max / (double) s->resx_min);
2452141cc406Sopenharmony_ci  s->resx_list =
2453141cc406Sopenharmony_ci    (unsigned int *) cs2_xrealloc (s->resx_list,
2454141cc406Sopenharmony_ci				   pitch_max * sizeof (unsigned int));
2455141cc406Sopenharmony_ci  for (pitch = 1; pitch <= pitch_max; pitch++)
2456141cc406Sopenharmony_ci    s->resx_list[pitch - 1] = s->resx_max / pitch;
2457141cc406Sopenharmony_ci
2458141cc406Sopenharmony_ci  /* generate resolution list for y */
2459141cc406Sopenharmony_ci  s->resy_n_list = pitch_max = floor (s->resy_max / (double) s->resy_min);
2460141cc406Sopenharmony_ci  s->resy_list =
2461141cc406Sopenharmony_ci    (unsigned int *) cs2_xrealloc (s->resy_list,
2462141cc406Sopenharmony_ci				   pitch_max * sizeof (unsigned int));
2463141cc406Sopenharmony_ci  for (pitch = 1; pitch <= pitch_max; pitch++)
2464141cc406Sopenharmony_ci    s->resy_list[pitch - 1] = s->resy_max / pitch;
2465141cc406Sopenharmony_ci
2466141cc406Sopenharmony_ci  s->unit_dpi = s->resx_max;
2467141cc406Sopenharmony_ci  s->unit_mm = 25.4 / s->unit_dpi;
2468141cc406Sopenharmony_ci
2469141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2470141cc406Sopenharmony_ci}
2471141cc406Sopenharmony_ci
2472141cc406Sopenharmony_cistatic SANE_Status
2473141cc406Sopenharmony_cics2_execute (cs2_t * s)
2474141cc406Sopenharmony_ci{
2475141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2476141cc406Sopenharmony_ci  cs2_init_buffer (s);
2477141cc406Sopenharmony_ci  cs2_parse_cmd (s, "c1 00 00 00 00 00");
2478141cc406Sopenharmony_ci  return cs2_issue_cmd (s);
2479141cc406Sopenharmony_ci}
2480141cc406Sopenharmony_ci
2481141cc406Sopenharmony_cistatic SANE_Status
2482141cc406Sopenharmony_cics2_load (cs2_t * s)
2483141cc406Sopenharmony_ci{
2484141cc406Sopenharmony_ci  SANE_Status status;
2485141cc406Sopenharmony_ci
2486141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2487141cc406Sopenharmony_ci  cs2_init_buffer (s);
2488141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e0 00 d1 00 00 00 00 00 0d 00");
2489141cc406Sopenharmony_ci  s->n_send += 13;
2490141cc406Sopenharmony_ci  status = cs2_grow_send_buffer (s);
2491141cc406Sopenharmony_ci  if (status)
2492141cc406Sopenharmony_ci    return status;
2493141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2494141cc406Sopenharmony_ci  if (status)
2495141cc406Sopenharmony_ci    return status;
2496141cc406Sopenharmony_ci
2497141cc406Sopenharmony_ci  return cs2_execute (s);
2498141cc406Sopenharmony_ci}
2499141cc406Sopenharmony_ci
2500141cc406Sopenharmony_cistatic SANE_Status
2501141cc406Sopenharmony_cics2_eject (cs2_t * s)
2502141cc406Sopenharmony_ci{
2503141cc406Sopenharmony_ci  SANE_Status status;
2504141cc406Sopenharmony_ci
2505141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2506141cc406Sopenharmony_ci  cs2_init_buffer (s);
2507141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e0 00 d0 00 00 00 00 00 0d 00");
2508141cc406Sopenharmony_ci  s->n_send += 13;
2509141cc406Sopenharmony_ci  status = cs2_grow_send_buffer (s);
2510141cc406Sopenharmony_ci  if (status)
2511141cc406Sopenharmony_ci    return status;
2512141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2513141cc406Sopenharmony_ci  if (status)
2514141cc406Sopenharmony_ci    return status;
2515141cc406Sopenharmony_ci
2516141cc406Sopenharmony_ci  return cs2_execute (s);
2517141cc406Sopenharmony_ci}
2518141cc406Sopenharmony_ci
2519141cc406Sopenharmony_cistatic SANE_Status
2520141cc406Sopenharmony_cics2_reset (cs2_t * s)
2521141cc406Sopenharmony_ci{
2522141cc406Sopenharmony_ci  SANE_Status status;
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2525141cc406Sopenharmony_ci  cs2_init_buffer (s);
2526141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e0 00 80 00 00 00 00 00 0d 00");
2527141cc406Sopenharmony_ci  s->n_send += 13;
2528141cc406Sopenharmony_ci  status = cs2_grow_send_buffer (s);
2529141cc406Sopenharmony_ci  if (status)
2530141cc406Sopenharmony_ci    return status;
2531141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2532141cc406Sopenharmony_ci  if (status)
2533141cc406Sopenharmony_ci    return status;
2534141cc406Sopenharmony_ci
2535141cc406Sopenharmony_ci  return cs2_execute (s);
2536141cc406Sopenharmony_ci}
2537141cc406Sopenharmony_ci
2538141cc406Sopenharmony_cistatic SANE_Status
2539141cc406Sopenharmony_cics2_focus (cs2_t * s)
2540141cc406Sopenharmony_ci{
2541141cc406Sopenharmony_ci  SANE_Status status;
2542141cc406Sopenharmony_ci
2543141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
2544141cc406Sopenharmony_ci  cs2_init_buffer (s);
2545141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e0 00 c1 00 00 00 00 00 0d 00 00");
2546141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->focus >> 24) & 0xff);
2547141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->focus >> 16) & 0xff);
2548141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->focus >> 8) & 0xff);
2549141cc406Sopenharmony_ci  cs2_pack_byte (s, s->focus & 0xff);
2550141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00 00 00 00 00 00 00 00");
2551141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2552141cc406Sopenharmony_ci  if (status)
2553141cc406Sopenharmony_ci    return status;
2554141cc406Sopenharmony_ci
2555141cc406Sopenharmony_ci  return cs2_execute (s);
2556141cc406Sopenharmony_ci}
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_cistatic SANE_Status
2559141cc406Sopenharmony_cics2_autofocus (cs2_t * s)
2560141cc406Sopenharmony_ci{
2561141cc406Sopenharmony_ci  SANE_Status status;
2562141cc406Sopenharmony_ci
2563141cc406Sopenharmony_ci  cs2_convert_options (s);
2564141cc406Sopenharmony_ci
2565141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
2566141cc406Sopenharmony_ci  cs2_init_buffer (s);
2567141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e0 00 a0 00 00 00 00 00 0d 00 00");
2568141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusx >> 24) & 0xff);
2569141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusx >> 16) & 0xff);
2570141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusx >> 8) & 0xff);
2571141cc406Sopenharmony_ci  cs2_pack_byte (s, s->real_focusx & 0xff);
2572141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusy >> 24) & 0xff);
2573141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusy >> 16) & 0xff);
2574141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->real_focusy >> 8) & 0xff);
2575141cc406Sopenharmony_ci  cs2_pack_byte (s, s->real_focusy & 0xff);
2576141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00 00 00 00");
2577141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2578141cc406Sopenharmony_ci  if (status)
2579141cc406Sopenharmony_ci    return status;
2580141cc406Sopenharmony_ci
2581141cc406Sopenharmony_ci  status = cs2_execute (s);
2582141cc406Sopenharmony_ci  if (status)
2583141cc406Sopenharmony_ci    return status;
2584141cc406Sopenharmony_ci
2585141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
2586141cc406Sopenharmony_ci  cs2_init_buffer (s);
2587141cc406Sopenharmony_ci  cs2_parse_cmd (s, "e1 00 c1 00 00 00 00 00 0d 00");
2588141cc406Sopenharmony_ci  s->n_recv = 13;
2589141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2590141cc406Sopenharmony_ci  if (status)
2591141cc406Sopenharmony_ci    return status;
2592141cc406Sopenharmony_ci
2593141cc406Sopenharmony_ci  s->focus =
2594141cc406Sopenharmony_ci    65536 * (256 * s->recv_buf[1] + s->recv_buf[2]) + 256 * s->recv_buf[3] +
2595141cc406Sopenharmony_ci    s->recv_buf[4];
2596141cc406Sopenharmony_ci
2597141cc406Sopenharmony_ci  return status;
2598141cc406Sopenharmony_ci}
2599141cc406Sopenharmony_ci
2600141cc406Sopenharmony_cistatic SANE_Status
2601141cc406Sopenharmony_cics2_get_exposure (cs2_t * s)
2602141cc406Sopenharmony_ci{
2603141cc406Sopenharmony_ci  SANE_Status status;
2604141cc406Sopenharmony_ci  int i_colour;
2605141cc406Sopenharmony_ci
2606141cc406Sopenharmony_ci  for (i_colour = 0; i_colour < 3; i_colour++)
2607141cc406Sopenharmony_ci    {				/* XXXXXXXXXXXXX CCCCCCCCCCCCC */
2608141cc406Sopenharmony_ci      cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2609141cc406Sopenharmony_ci
2610141cc406Sopenharmony_ci      cs2_init_buffer (s);
2611141cc406Sopenharmony_ci      cs2_parse_cmd (s, "25 01 00 00 00");
2612141cc406Sopenharmony_ci      cs2_pack_byte (s, cs2_colour_list[i_colour]);
2613141cc406Sopenharmony_ci      cs2_parse_cmd (s, "00 00 3a 00");
2614141cc406Sopenharmony_ci      s->n_recv = 58;
2615141cc406Sopenharmony_ci      status = cs2_issue_cmd (s);
2616141cc406Sopenharmony_ci      if (status)
2617141cc406Sopenharmony_ci	return status;
2618141cc406Sopenharmony_ci
2619141cc406Sopenharmony_ci      s->real_exposure[cs2_colour_list[i_colour]] =
2620141cc406Sopenharmony_ci	65536 * (256 * s->recv_buf[54] + s->recv_buf[55]) +
2621141cc406Sopenharmony_ci	256 * s->recv_buf[56] + s->recv_buf[57];
2622141cc406Sopenharmony_ci
2623141cc406Sopenharmony_ci      DBG (6, "cs2_get_exposure(): exposure for colour %i: %li * 10ns\n", cs2_colour_list[i_colour], s->real_exposure[cs2_colour_list[i_colour]]);
2624141cc406Sopenharmony_ci    }
2625141cc406Sopenharmony_ci
2626141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2627141cc406Sopenharmony_ci}
2628141cc406Sopenharmony_ci
2629141cc406Sopenharmony_cistatic SANE_Status
2630141cc406Sopenharmony_cics2_convert_options (cs2_t * s)
2631141cc406Sopenharmony_ci{
2632141cc406Sopenharmony_ci  int i_colour;
2633141cc406Sopenharmony_ci  unsigned long xmin, xmax, ymin, ymax;
2634141cc406Sopenharmony_ci  SANE_Byte *infrared_buf_new;
2635141cc406Sopenharmony_ci
2636141cc406Sopenharmony_ci  s->real_depth = (s->preview ? 8 : s->depth);
2637141cc406Sopenharmony_ci  s->bytes_per_pixel = (s->real_depth > 8 ? 2 : 1);
2638141cc406Sopenharmony_ci  s->shift_bits = 8 * s->bytes_per_pixel - s->real_depth;
2639141cc406Sopenharmony_ci
2640141cc406Sopenharmony_ci  if (s->preview)
2641141cc406Sopenharmony_ci    {
2642141cc406Sopenharmony_ci      s->real_resx = s->res_preview;
2643141cc406Sopenharmony_ci      s->real_resy = s->res_preview;
2644141cc406Sopenharmony_ci    }
2645141cc406Sopenharmony_ci  else if (s->res_independent)
2646141cc406Sopenharmony_ci    {
2647141cc406Sopenharmony_ci      s->real_resx = s->resx;
2648141cc406Sopenharmony_ci      s->real_resy = s->resy;
2649141cc406Sopenharmony_ci    }
2650141cc406Sopenharmony_ci  else
2651141cc406Sopenharmony_ci    {
2652141cc406Sopenharmony_ci      s->real_resx = s->res;
2653141cc406Sopenharmony_ci      s->real_resy = s->res;
2654141cc406Sopenharmony_ci    }
2655141cc406Sopenharmony_ci  s->real_pitchx = s->resx_max / s->real_resx;
2656141cc406Sopenharmony_ci  s->real_pitchy = s->resy_max / s->real_resy;
2657141cc406Sopenharmony_ci
2658141cc406Sopenharmony_ci  s->real_resx = s->resx_max / s->real_pitchx;
2659141cc406Sopenharmony_ci  s->real_resy = s->resy_max / s->real_pitchy;
2660141cc406Sopenharmony_ci
2661141cc406Sopenharmony_ci  /* The prefix "real_" refers to data in device units (1/maxdpi), "logical_" refers to resolution-dependent data. */
2662141cc406Sopenharmony_ci
2663141cc406Sopenharmony_ci  if (s->xmin < s->xmax)
2664141cc406Sopenharmony_ci    {
2665141cc406Sopenharmony_ci      xmin = s->xmin;
2666141cc406Sopenharmony_ci      xmax = s->xmax;
2667141cc406Sopenharmony_ci    }
2668141cc406Sopenharmony_ci  else
2669141cc406Sopenharmony_ci    {
2670141cc406Sopenharmony_ci      xmin = s->xmax;
2671141cc406Sopenharmony_ci      xmax = s->xmin;
2672141cc406Sopenharmony_ci    }
2673141cc406Sopenharmony_ci
2674141cc406Sopenharmony_ci  if (s->ymin < s->ymax)
2675141cc406Sopenharmony_ci    {
2676141cc406Sopenharmony_ci      ymin = s->ymin;
2677141cc406Sopenharmony_ci      ymax = s->ymax;
2678141cc406Sopenharmony_ci    }
2679141cc406Sopenharmony_ci  else
2680141cc406Sopenharmony_ci    {
2681141cc406Sopenharmony_ci      ymin = s->ymax;
2682141cc406Sopenharmony_ci      ymax = s->ymin;
2683141cc406Sopenharmony_ci    }
2684141cc406Sopenharmony_ci
2685141cc406Sopenharmony_ci  s->real_xoffset = xmin;
2686141cc406Sopenharmony_ci  s->real_yoffset =
2687141cc406Sopenharmony_ci    ymin + (s->i_frame - 1) * s->frame_offset + s->subframe / s->unit_mm;
2688141cc406Sopenharmony_ci  s->logical_width = (xmax - xmin + 1) / s->real_pitchx;	/* XXXXXXXXX use mm units */
2689141cc406Sopenharmony_ci  s->logical_height = (ymax - ymin + 1) / s->real_pitchy;
2690141cc406Sopenharmony_ci  s->real_width = s->logical_width * s->real_pitchx;
2691141cc406Sopenharmony_ci  s->real_height = s->logical_height * s->real_pitchy;
2692141cc406Sopenharmony_ci
2693141cc406Sopenharmony_ci  s->odd_padding = 0;
2694141cc406Sopenharmony_ci  if ((s->bytes_per_pixel == 1) && (s->logical_width & 0x01)
2695141cc406Sopenharmony_ci      && (s->type != CS2_TYPE_LS30) && (s->type != CS2_TYPE_LS2000))
2696141cc406Sopenharmony_ci    s->odd_padding = 1;
2697141cc406Sopenharmony_ci
2698141cc406Sopenharmony_ci  if (s->focus_on_centre)
2699141cc406Sopenharmony_ci    {
2700141cc406Sopenharmony_ci      s->real_focusx = s->real_xoffset + s->real_width / 2;
2701141cc406Sopenharmony_ci      s->real_focusy = s->real_yoffset + s->real_height / 2;
2702141cc406Sopenharmony_ci    }
2703141cc406Sopenharmony_ci  else
2704141cc406Sopenharmony_ci    {
2705141cc406Sopenharmony_ci      s->real_focusx = s->focusx;
2706141cc406Sopenharmony_ci      s->real_focusy =
2707141cc406Sopenharmony_ci	s->focusy + (s->i_frame - 1) * s->frame_offset +
2708141cc406Sopenharmony_ci	s->subframe / s->unit_mm;
2709141cc406Sopenharmony_ci    }
2710141cc406Sopenharmony_ci
2711141cc406Sopenharmony_ci  s->real_exposure[1] = s->exposure * s->exposure_r * 100.;
2712141cc406Sopenharmony_ci  s->real_exposure[2] = s->exposure * s->exposure_g * 100.;
2713141cc406Sopenharmony_ci  s->real_exposure[3] = s->exposure * s->exposure_b * 100.;
2714141cc406Sopenharmony_ci
2715141cc406Sopenharmony_ci  for (i_colour = 0; i_colour < 3; i_colour++)
2716141cc406Sopenharmony_ci    if (s->real_exposure[cs2_colour_list[i_colour]] < 1)
2717141cc406Sopenharmony_ci      s->real_exposure[cs2_colour_list[i_colour]] = 1;
2718141cc406Sopenharmony_ci
2719141cc406Sopenharmony_ci  s->n_colour_out = s->n_colour_in = 3;	/* XXXXXXXXXXXXXX CCCCCCCCCCCCCC */
2720141cc406Sopenharmony_ci
2721141cc406Sopenharmony_ci  s->xfer_bytes_total =
2722141cc406Sopenharmony_ci    s->bytes_per_pixel * s->n_colour_out * s->logical_width *
2723141cc406Sopenharmony_ci    s->logical_height;
2724141cc406Sopenharmony_ci
2725141cc406Sopenharmony_ci  if (s->preview)
2726141cc406Sopenharmony_ci    s->infrared_stage = s->infrared_next = CS2_INFRARED_OFF;
2727141cc406Sopenharmony_ci  else
2728141cc406Sopenharmony_ci    {
2729141cc406Sopenharmony_ci      if ((s->infrared) && (s->infrared_stage == CS2_INFRARED_OFF))
2730141cc406Sopenharmony_ci	s->infrared_next = CS2_INFRARED_IN;
2731141cc406Sopenharmony_ci
2732141cc406Sopenharmony_ci      s->infrared_stage = s->infrared_next;
2733141cc406Sopenharmony_ci
2734141cc406Sopenharmony_ci      if (s->infrared)
2735141cc406Sopenharmony_ci	{
2736141cc406Sopenharmony_ci	  s->n_colour_in ++;
2737141cc406Sopenharmony_ci	  s->n_infrared_buf =
2738141cc406Sopenharmony_ci	    s->bytes_per_pixel * s->logical_width * s->logical_height;
2739141cc406Sopenharmony_ci	  infrared_buf_new =
2740141cc406Sopenharmony_ci	    (SANE_Byte *) cs2_xrealloc (s->infrared_buf, s->n_infrared_buf);
2741141cc406Sopenharmony_ci	  if (infrared_buf_new)
2742141cc406Sopenharmony_ci	    s->infrared_buf = infrared_buf_new;
2743141cc406Sopenharmony_ci	  else
2744141cc406Sopenharmony_ci	    return SANE_STATUS_NO_MEM;
2745141cc406Sopenharmony_ci	}
2746141cc406Sopenharmony_ci    }
2747141cc406Sopenharmony_ci
2748141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2749141cc406Sopenharmony_ci}
2750141cc406Sopenharmony_ci
2751141cc406Sopenharmony_cistatic SANE_Status
2752141cc406Sopenharmony_cics2_set_boundary (cs2_t *s)
2753141cc406Sopenharmony_ci{
2754141cc406Sopenharmony_ci  SANE_Status status;
2755141cc406Sopenharmony_ci  int i_boundary;
2756141cc406Sopenharmony_ci  unsigned long lvalue;
2757141cc406Sopenharmony_ci
2758141cc406Sopenharmony_ci/* Ariel - Check this function */
2759141cc406Sopenharmony_ci
2760141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
2761141cc406Sopenharmony_ci  cs2_init_buffer (s);
2762141cc406Sopenharmony_ci  cs2_parse_cmd (s, "2a 00 88 00 00 03");
2763141cc406Sopenharmony_ci  cs2_pack_byte (s, ((4 + s->n_frames * 16) >> 16) & 0xff);
2764141cc406Sopenharmony_ci  cs2_pack_byte (s, ((4 + s->n_frames * 16) >> 8) & 0xff);
2765141cc406Sopenharmony_ci  cs2_pack_byte (s, (4 + s->n_frames * 16) & 0xff);
2766141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00");
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  cs2_pack_byte (s, ((4 + s->n_frames * 16) >> 8) & 0xff);
2769141cc406Sopenharmony_ci  cs2_pack_byte (s, (4 + s->n_frames * 16) & 0xff);
2770141cc406Sopenharmony_ci  cs2_pack_byte (s, s->n_frames);
2771141cc406Sopenharmony_ci  cs2_pack_byte (s, s->n_frames);
2772141cc406Sopenharmony_ci  for (i_boundary = 0; i_boundary < s->n_frames; i_boundary++)
2773141cc406Sopenharmony_ci    {
2774141cc406Sopenharmony_ci      lvalue = s->frame_offset * i_boundary + s->subframe / s->unit_mm;
2775141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 24) & 0xff);
2776141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 16) & 0xff);
2777141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 8) & 0xff);
2778141cc406Sopenharmony_ci      cs2_pack_byte (s, lvalue & 0xff);
2779141cc406Sopenharmony_ci
2780141cc406Sopenharmony_ci      lvalue = 0;
2781141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 24) & 0xff);
2782141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 16) & 0xff);
2783141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 8) & 0xff);
2784141cc406Sopenharmony_ci      cs2_pack_byte (s, lvalue & 0xff);
2785141cc406Sopenharmony_ci
2786141cc406Sopenharmony_ci      lvalue = s->frame_offset * i_boundary + s->subframe / s->unit_mm + s->frame_offset - 1;
2787141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 24) & 0xff);
2788141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 16) & 0xff);
2789141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 8) & 0xff);
2790141cc406Sopenharmony_ci      cs2_pack_byte (s, lvalue & 0xff);
2791141cc406Sopenharmony_ci
2792141cc406Sopenharmony_ci      lvalue = s->boundaryx - 1;
2793141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 24) & 0xff);
2794141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 16) & 0xff);
2795141cc406Sopenharmony_ci      cs2_pack_byte (s, (lvalue >> 8) & 0xff);
2796141cc406Sopenharmony_ci      cs2_pack_byte (s, lvalue & 0xff);
2797141cc406Sopenharmony_ci    }
2798141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2799141cc406Sopenharmony_ci  if (status)
2800141cc406Sopenharmony_ci    return status;
2801141cc406Sopenharmony_ci
2802141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2803141cc406Sopenharmony_ci}
2804141cc406Sopenharmony_ci
2805141cc406Sopenharmony_cistatic SANE_Status
2806141cc406Sopenharmony_cics2_scan (cs2_t * s, cs2_scan_t type)
2807141cc406Sopenharmony_ci{
2808141cc406Sopenharmony_ci  SANE_Status status;
2809141cc406Sopenharmony_ci  int i_colour;
2810141cc406Sopenharmony_ci  cs2_pixel_t pixel;
2811141cc406Sopenharmony_ci  cs2_pixel_t *lut;
2812141cc406Sopenharmony_ci
2813141cc406Sopenharmony_ci  /* wait for device to be ready with document, and set device unit */
2814141cc406Sopenharmony_ci
2815141cc406Sopenharmony_ci  status = cs2_scanner_ready (s, CS2_STATUS_NO_DOCS);
2816141cc406Sopenharmony_ci  if (status)
2817141cc406Sopenharmony_ci    return status;
2818141cc406Sopenharmony_ci  if (s->status & CS2_STATUS_NO_DOCS)
2819141cc406Sopenharmony_ci    return SANE_STATUS_NO_DOCS;
2820141cc406Sopenharmony_ci
2821141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
2822141cc406Sopenharmony_ci  cs2_init_buffer (s);
2823141cc406Sopenharmony_ci  /* Ariel - the '0b' byte in the 'else' part seems to be wrong, should be 0 */
2824141cc406Sopenharmony_ci  if ((s->type == CS2_TYPE_LS50) || (s->type == CS2_TYPE_LS5000))
2825141cc406Sopenharmony_ci    cs2_parse_cmd (s, "15 10 00 00 14 00 00 00 00 08 00 00 00 00 00 00 00 01 03 06 00 00");
2826141cc406Sopenharmony_ci  else
2827141cc406Sopenharmony_ci    cs2_parse_cmd (s, "15 10 00 00 0c 00 0b 00 00 00 03 06 00 00");
2828141cc406Sopenharmony_ci  cs2_pack_byte (s, (s->unit_dpi >> 8) & 0xff);
2829141cc406Sopenharmony_ci  cs2_pack_byte (s, s->unit_dpi & 0xff);
2830141cc406Sopenharmony_ci  cs2_parse_cmd (s, "00 00");
2831141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
2832141cc406Sopenharmony_ci  if (status)
2833141cc406Sopenharmony_ci    return status;
2834141cc406Sopenharmony_ci
2835141cc406Sopenharmony_ci  status = cs2_convert_options (s);
2836141cc406Sopenharmony_ci  if (status)
2837141cc406Sopenharmony_ci    return status;
2838141cc406Sopenharmony_ci
2839141cc406Sopenharmony_ci  /* Ariel - Is this the best place to initialize it? */
2840141cc406Sopenharmony_ci  s->block_padding = 0;
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_ci  status = cs2_set_boundary (s);
2843141cc406Sopenharmony_ci  if (status)
2844141cc406Sopenharmony_ci    return status;
2845141cc406Sopenharmony_ci
2846141cc406Sopenharmony_ci  switch (type)
2847141cc406Sopenharmony_ci    {
2848141cc406Sopenharmony_ci    case CS2_SCAN_NORMAL:
2849141cc406Sopenharmony_ci
2850141cc406Sopenharmony_ci      for (i_colour = 0; i_colour < s->n_colour_in; i_colour++)
2851141cc406Sopenharmony_ci	{
2852141cc406Sopenharmony_ci	  cs2_scanner_ready (s, CS2_STATUS_READY);
2853141cc406Sopenharmony_ci
2854141cc406Sopenharmony_ci	  switch (i_colour)
2855141cc406Sopenharmony_ci	    {
2856141cc406Sopenharmony_ci	    case 0:
2857141cc406Sopenharmony_ci	      lut = s->lut_r;
2858141cc406Sopenharmony_ci	      break;
2859141cc406Sopenharmony_ci	    case 1:
2860141cc406Sopenharmony_ci	      lut = s->lut_g;
2861141cc406Sopenharmony_ci	      break;
2862141cc406Sopenharmony_ci	    case 2:
2863141cc406Sopenharmony_ci	      lut = s->lut_b;
2864141cc406Sopenharmony_ci	      break;
2865141cc406Sopenharmony_ci	    case 3:
2866141cc406Sopenharmony_ci	      lut = s->lut_neutral;
2867141cc406Sopenharmony_ci	      break;
2868141cc406Sopenharmony_ci	    default:
2869141cc406Sopenharmony_ci	      DBG (1,
2870141cc406Sopenharmony_ci		   "BUG: cs2_scan(): Unknown colour number for LUT download.\n");
2871141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
2872141cc406Sopenharmony_ci	      break;
2873141cc406Sopenharmony_ci	    }
2874141cc406Sopenharmony_ci
2875141cc406Sopenharmony_ci	  cs2_init_buffer (s);
2876141cc406Sopenharmony_ci	  cs2_parse_cmd (s, "2a 00 03 00");
2877141cc406Sopenharmony_ci	  cs2_pack_byte (s, cs2_colour_list[i_colour]);
2878141cc406Sopenharmony_ci	  cs2_pack_byte (s, 2 - 1);	/* XXXXXXXXXX number of bytes per data point - 1 */
2879141cc406Sopenharmony_ci	  cs2_pack_byte (s, ((2 * s->n_lut) >> 16) & 0xff);	/* XXXXXXXXXX 2 bytes per point */
2880141cc406Sopenharmony_ci	  cs2_pack_byte (s, ((2 * s->n_lut) >> 8) & 0xff);	/* XXXXXXXXXX 2 bytes per point */
2881141cc406Sopenharmony_ci	  cs2_pack_byte (s, (2 * s->n_lut) & 0xff);	/* XXXXXXXXXX 2 bytes per point */
2882141cc406Sopenharmony_ci	  cs2_pack_byte (s, 0x00);
2883141cc406Sopenharmony_ci
2884141cc406Sopenharmony_ci	  for (pixel = 0; pixel < s->n_lut; pixel++)
2885141cc406Sopenharmony_ci	    {			/* XXXXXXXXXXXXXXX 2 bytes per point */
2886141cc406Sopenharmony_ci	      cs2_pack_byte (s, (lut[pixel] >> 8) & 0xff);
2887141cc406Sopenharmony_ci	      cs2_pack_byte (s, lut[pixel] & 0xff);
2888141cc406Sopenharmony_ci	    }
2889141cc406Sopenharmony_ci
2890141cc406Sopenharmony_ci	  status = cs2_issue_cmd (s);
2891141cc406Sopenharmony_ci	  if (status)
2892141cc406Sopenharmony_ci	    return status;
2893141cc406Sopenharmony_ci	}
2894141cc406Sopenharmony_ci
2895141cc406Sopenharmony_ci      break;
2896141cc406Sopenharmony_ci
2897141cc406Sopenharmony_ci    default:
2898141cc406Sopenharmony_ci      break;
2899141cc406Sopenharmony_ci    }
2900141cc406Sopenharmony_ci
2901141cc406Sopenharmony_ci  for (i_colour = 0; i_colour < s->n_colour_in; i_colour++)
2902141cc406Sopenharmony_ci    {
2903141cc406Sopenharmony_ci      cs2_scanner_ready (s, CS2_STATUS_READY);
2904141cc406Sopenharmony_ci
2905141cc406Sopenharmony_ci      cs2_init_buffer (s);
2906141cc406Sopenharmony_ci      if ((s->type == CS2_TYPE_LS40) || (s->type == CS2_TYPE_LS4000))
2907141cc406Sopenharmony_ci	cs2_parse_cmd (s, "24 00 00 00 00 00 00 00 3a 80");
2908141cc406Sopenharmony_ci      else
2909141cc406Sopenharmony_ci	cs2_parse_cmd (s, "24 00 00 00 00 00 00 00 3a 00");
2910141cc406Sopenharmony_ci      cs2_parse_cmd (s, "00 00 00 00 00 00 00 32");
2911141cc406Sopenharmony_ci
2912141cc406Sopenharmony_ci      cs2_pack_byte (s, cs2_colour_list[i_colour]);
2913141cc406Sopenharmony_ci
2914141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x00);
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_resx >> 8);
2917141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_resx & 0xff);
2918141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_resy >> 8);
2919141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_resy & 0xff);
2920141cc406Sopenharmony_ci
2921141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_xoffset >> 24) & 0xff);
2922141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_xoffset >> 16) & 0xff);
2923141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_xoffset >> 8) & 0xff);
2924141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_xoffset & 0xff);
2925141cc406Sopenharmony_ci
2926141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_yoffset >> 24) & 0xff);
2927141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_yoffset >> 16) & 0xff);
2928141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_yoffset >> 8) & 0xff);
2929141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_yoffset & 0xff);
2930141cc406Sopenharmony_ci
2931141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_width >> 24) & 0xff);
2932141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_width >> 16) & 0xff);
2933141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_width >> 8) & 0xff);
2934141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_width & 0xff);
2935141cc406Sopenharmony_ci
2936141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_height >> 24) & 0xff);
2937141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_height >> 16) & 0xff);
2938141cc406Sopenharmony_ci      cs2_pack_byte (s, (s->real_height >> 8) & 0xff);
2939141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_height & 0xff);
2940141cc406Sopenharmony_ci
2941141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x00);	/* brightness, etc. */
2942141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x00);
2943141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x00);
2944141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x05);	/* image composition CCCCCCC */
2945141cc406Sopenharmony_ci      cs2_pack_byte (s, s->real_depth);	/* pixel composition */
2946141cc406Sopenharmony_ci      cs2_parse_cmd (s, "00 00 00 00 00 00 00 00 00 00 00 00 00");
2947141cc406Sopenharmony_ci      cs2_pack_byte (s, ((s->samples_per_scan - 1) << 4) + 0x00);	/* multiread, ordering */
2948141cc406Sopenharmony_ci      /* No need to use an undocumented bit in LS50 */
2949141cc406Sopenharmony_ci      if ((s->type == CS2_TYPE_LS50) || (s->type == CS2_TYPE_LS5000))
2950141cc406Sopenharmony_ci        cs2_pack_byte (s, 0x00 + (s->negative ? 0 : 1));	/* averaging, pos/neg */
2951141cc406Sopenharmony_ci      else
2952141cc406Sopenharmony_ci        cs2_pack_byte (s, 0x80 + (s->negative ? 0 : 1));	/* averaging, pos/neg */
2953141cc406Sopenharmony_ci
2954141cc406Sopenharmony_ci      switch (type)
2955141cc406Sopenharmony_ci	{			/* scanning kind */
2956141cc406Sopenharmony_ci	case CS2_SCAN_NORMAL:
2957141cc406Sopenharmony_ci	  cs2_pack_byte (s, 0x01);
2958141cc406Sopenharmony_ci	  break;
2959141cc406Sopenharmony_ci	case CS2_SCAN_AE:
2960141cc406Sopenharmony_ci	  cs2_pack_byte (s, 0x20);
2961141cc406Sopenharmony_ci	  break;
2962141cc406Sopenharmony_ci	case CS2_SCAN_AE_WB:
2963141cc406Sopenharmony_ci	  cs2_pack_byte (s, 0x40);
2964141cc406Sopenharmony_ci	  break;
2965141cc406Sopenharmony_ci	default:
2966141cc406Sopenharmony_ci	  DBG (1, "BUG: cs2_scan(): Unknown scanning type.\n");
2967141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
2968141cc406Sopenharmony_ci	}
2969141cc406Sopenharmony_ci      if (s->samples_per_scan == 1)
2970141cc406Sopenharmony_ci        cs2_pack_byte (s, 0x02);	/* scanning mode single */
2971141cc406Sopenharmony_ci      else
2972141cc406Sopenharmony_ci        cs2_pack_byte (s, 0x10);	/* scanning mode multi */
2973141cc406Sopenharmony_ci      cs2_pack_byte (s, 0x02);	/* colour interleaving */
2974141cc406Sopenharmony_ci      cs2_pack_byte (s, 0xff);	/* (ae) */
2975141cc406Sopenharmony_ci      if (i_colour == 3)	/* infrared */
2976141cc406Sopenharmony_ci	cs2_parse_cmd (s, "00 00 00 00");	/* automatic */
2977141cc406Sopenharmony_ci      else
2978141cc406Sopenharmony_ci	{
2979141cc406Sopenharmony_ci	  cs2_pack_byte (s,
2980141cc406Sopenharmony_ci			 (s->
2981141cc406Sopenharmony_ci			  real_exposure[cs2_colour_list[i_colour]] >> 24) &
2982141cc406Sopenharmony_ci			 0xff);
2983141cc406Sopenharmony_ci	  cs2_pack_byte (s,
2984141cc406Sopenharmony_ci			 (s->
2985141cc406Sopenharmony_ci			  real_exposure[cs2_colour_list[i_colour]] >> 16) &
2986141cc406Sopenharmony_ci			 0xff);
2987141cc406Sopenharmony_ci	  cs2_pack_byte (s,
2988141cc406Sopenharmony_ci			 (s->
2989141cc406Sopenharmony_ci			  real_exposure[cs2_colour_list[i_colour]] >> 8) &
2990141cc406Sopenharmony_ci			 0xff);
2991141cc406Sopenharmony_ci	  cs2_pack_byte (s,
2992141cc406Sopenharmony_ci			 s->real_exposure[cs2_colour_list[i_colour]] & 0xff);
2993141cc406Sopenharmony_ci	}
2994141cc406Sopenharmony_ci      status = cs2_issue_cmd (s);
2995141cc406Sopenharmony_ci      if (status)
2996141cc406Sopenharmony_ci	return status;
2997141cc406Sopenharmony_ci    }
2998141cc406Sopenharmony_ci
2999141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
3000141cc406Sopenharmony_ci  cs2_focus (s);
3001141cc406Sopenharmony_ci
3002141cc406Sopenharmony_ci  cs2_scanner_ready (s, CS2_STATUS_READY);
3003141cc406Sopenharmony_ci  cs2_init_buffer (s);
3004141cc406Sopenharmony_ci  switch (s->n_colour_in)
3005141cc406Sopenharmony_ci    {
3006141cc406Sopenharmony_ci    case 3:
3007141cc406Sopenharmony_ci      cs2_parse_cmd (s, "1b 00 00 00 03 00 01 02 03");
3008141cc406Sopenharmony_ci      break;
3009141cc406Sopenharmony_ci    case 4:
3010141cc406Sopenharmony_ci      cs2_parse_cmd (s, "1b 00 00 00 04 00 01 02 03 09");
3011141cc406Sopenharmony_ci      break;
3012141cc406Sopenharmony_ci    default:
3013141cc406Sopenharmony_ci      DBG (1, "BUG: cs2_scan(): Unknown number of input colours.\n");
3014141cc406Sopenharmony_ci      break;
3015141cc406Sopenharmony_ci    }
3016141cc406Sopenharmony_ci  status = cs2_issue_cmd (s);
3017141cc406Sopenharmony_ci  if (status)
3018141cc406Sopenharmony_ci    return status;
3019141cc406Sopenharmony_ci  if (s->status == CS2_STATUS_REISSUE)
3020141cc406Sopenharmony_ci    {
3021141cc406Sopenharmony_ci      /* Make sure we don't affect the behaviour for other scanners */
3022141cc406Sopenharmony_ci      if ((s->type == CS2_TYPE_LS50) || (s->type == CS2_TYPE_LS5000))
3023141cc406Sopenharmony_ci        {
3024141cc406Sopenharmony_ci          cs2_init_buffer (s);
3025141cc406Sopenharmony_ci          cs2_parse_cmd (s, "28 00 87 00 00 00 00 00 06 00");
3026141cc406Sopenharmony_ci          s->n_recv = 6;
3027141cc406Sopenharmony_ci          status = cs2_issue_cmd (s);
3028141cc406Sopenharmony_ci          if (status)
3029141cc406Sopenharmony_ci            return status;
3030141cc406Sopenharmony_ci          cs2_init_buffer (s);
3031141cc406Sopenharmony_ci          cs2_parse_cmd (s, "28 00 87 00 00 00 00 00");
3032141cc406Sopenharmony_ci          cs2_pack_byte (s, s->recv_buf[5] + 6);
3033141cc406Sopenharmony_ci          cs2_parse_cmd (s, "00");
3034141cc406Sopenharmony_ci          s->n_recv = s->recv_buf[5] + 6;
3035141cc406Sopenharmony_ci          status = cs2_issue_cmd (s);
3036141cc406Sopenharmony_ci          if (status)
3037141cc406Sopenharmony_ci            return status;
3038141cc406Sopenharmony_ci          if ((s->recv_buf[11] != 0x08) || (s->recv_buf[12] != 0x00))
3039141cc406Sopenharmony_ci            DBG (1, "BUG: cs2_scan(): Unexpected block_padding position.\n");
3040141cc406Sopenharmony_ci          s->block_padding = 256 * s->recv_buf[19] + s->recv_buf[20];
3041141cc406Sopenharmony_ci          cs2_init_buffer (s);
3042141cc406Sopenharmony_ci          switch (s->n_colour_in)
3043141cc406Sopenharmony_ci            {
3044141cc406Sopenharmony_ci            case 3:
3045141cc406Sopenharmony_ci              cs2_parse_cmd (s, "1b 00 00 00 03 00 01 02 03");
3046141cc406Sopenharmony_ci              break;
3047141cc406Sopenharmony_ci            case 4:
3048141cc406Sopenharmony_ci              cs2_parse_cmd (s, "1b 00 00 00 04 00 01 02 03 09");
3049141cc406Sopenharmony_ci              break;
3050141cc406Sopenharmony_ci            }
3051141cc406Sopenharmony_ci        }
3052141cc406Sopenharmony_ci      status = cs2_issue_cmd (s);
3053141cc406Sopenharmony_ci      if (status)
3054141cc406Sopenharmony_ci	return status;
3055141cc406Sopenharmony_ci    }
3056141cc406Sopenharmony_ci
3057141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3058141cc406Sopenharmony_ci}
3059141cc406Sopenharmony_ci
3060141cc406Sopenharmony_cistatic void *
3061141cc406Sopenharmony_cics2_xmalloc (size_t size)
3062141cc406Sopenharmony_ci{
3063141cc406Sopenharmony_ci  register void *value = malloc (size);
3064141cc406Sopenharmony_ci
3065141cc406Sopenharmony_ci  if (!value)
3066141cc406Sopenharmony_ci    DBG (0, "Error: cs2_xmalloc(): Failed to malloc() %lu bytes.\n",
3067141cc406Sopenharmony_ci	 (unsigned long) size);
3068141cc406Sopenharmony_ci
3069141cc406Sopenharmony_ci  return value;
3070141cc406Sopenharmony_ci}
3071141cc406Sopenharmony_ci
3072141cc406Sopenharmony_cistatic void *
3073141cc406Sopenharmony_cics2_xrealloc (void *p, size_t size)
3074141cc406Sopenharmony_ci{
3075141cc406Sopenharmony_ci  register void *value;
3076141cc406Sopenharmony_ci
3077141cc406Sopenharmony_ci  if (!size)
3078141cc406Sopenharmony_ci    return p;
3079141cc406Sopenharmony_ci
3080141cc406Sopenharmony_ci  value = realloc (p, size);
3081141cc406Sopenharmony_ci
3082141cc406Sopenharmony_ci  if (!value)
3083141cc406Sopenharmony_ci    DBG (0, "Error: cs2_xrealloc(): Failed to realloc() %lu bytes.\n",
3084141cc406Sopenharmony_ci	 (unsigned long) size);
3085141cc406Sopenharmony_ci
3086141cc406Sopenharmony_ci  return value;
3087141cc406Sopenharmony_ci}
3088141cc406Sopenharmony_ci
3089141cc406Sopenharmony_cistatic void
3090141cc406Sopenharmony_cics2_xfree (const void *p)
3091141cc406Sopenharmony_ci{
3092141cc406Sopenharmony_ci  if (p)
3093141cc406Sopenharmony_ci    free ((void *) p);
3094141cc406Sopenharmony_ci}
3095