1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2007-2013 stef.dev@free.fr
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   --------------------------------------------------------------------------
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci   SANE FLOW DIAGRAM
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci   - sane_init() : initialize backend, attach scanners
46141cc406Sopenharmony_ci   . - sane_get_devices() : query list of scanner devices
47141cc406Sopenharmony_ci   . - sane_open() : open a particular scanner device, adding a handle
48141cc406Sopenharmony_ci   		     to the opened device
49141cc406Sopenharmony_ci   . . - sane_set_io_mode : set blocking mode
50141cc406Sopenharmony_ci   . . - sane_get_select_fd : get scanner fd
51141cc406Sopenharmony_ci   . . - sane_get_option_descriptor() : get option information
52141cc406Sopenharmony_ci   . . - sane_control_option() : change option values
53141cc406Sopenharmony_ci   . .
54141cc406Sopenharmony_ci   . . - sane_start() : start image acquisition
55141cc406Sopenharmony_ci   . .   - sane_get_parameters() : returns actual scan parameters
56141cc406Sopenharmony_ci   . .   - sane_read() : read image data
57141cc406Sopenharmony_ci   . .
58141cc406Sopenharmony_ci   . . - sane_cancel() : cancel operation
59141cc406Sopenharmony_ci   . - sane_close() : close opened scanner device, freeing scanner handle
60141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend, freeing all resources for attached
61141cc406Sopenharmony_ci   		   devices
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci   BACKEND USB locking policy
64141cc406Sopenharmony_ci   - interface is released at the end of sane_open() to allow
65141cc406Sopenharmony_ci   	multiple usage by fronteds
66141cc406Sopenharmony_ci   - if free, interface is claimed at sane_start(), and held until
67141cc406Sopenharmony_ci   	sane_cancel() is called
68141cc406Sopenharmony_ci   - if free interface is claimed then released just during the access
69141cc406Sopenharmony_ci        to buttons registers
70141cc406Sopenharmony_ci*/
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci#include "../include/sane/config.h"
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#include <errno.h>
77141cc406Sopenharmony_ci#include <fcntl.h>
78141cc406Sopenharmony_ci#include <limits.h>
79141cc406Sopenharmony_ci#include <math.h>
80141cc406Sopenharmony_ci#include <signal.h>
81141cc406Sopenharmony_ci#include <stdio.h>
82141cc406Sopenharmony_ci#include <stdlib.h>
83141cc406Sopenharmony_ci#include <string.h>
84141cc406Sopenharmony_ci#include <ctype.h>
85141cc406Sopenharmony_ci#include <time.h>
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci#include <sys/types.h>
88141cc406Sopenharmony_ci#include <unistd.h>
89141cc406Sopenharmony_ci#ifdef HAVE_LIBC_H
90141cc406Sopenharmony_ci# include <libc.h>
91141cc406Sopenharmony_ci#endif
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci#include "../include/sane/sane.h"
94141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
95141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
96141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
97141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci#define DARK_TARGET		3.1	/* 3.5 target average for dark calibration */
100141cc406Sopenharmony_ci#define DARK_MARGIN		0.3	/* acceptable margin for dark average */
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci#define OFFSET_TARGET		3.5	/* target average for offset calibration */
103141cc406Sopenharmony_ci#define OFFSET_MARGIN		0.3	/* acceptable margin for offset average */
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci#define RED_GAIN_TARGET	    	170	/* target average for gain calibration for blue color */
106141cc406Sopenharmony_ci#define GREEN_GAIN_TARGET	170	/* target average for gain calibration for blue color */
107141cc406Sopenharmony_ci#define BLUE_GAIN_TARGET	180	/* target average for gain calibration for blue color */
108141cc406Sopenharmony_ci#define GAIN_MARGIN		  2	/* acceptable margin for gain average */
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_ci#define MARGIN_LEVEL            128	/* white level for margin detection */
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci/* width used for calibration */
113141cc406Sopenharmony_ci#define CALIBRATION_WIDTH       637
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci/* data size for calibration: one RGB line*/
116141cc406Sopenharmony_ci#define CALIBRATION_SIZE        CALIBRATION_WIDTH*3
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci/* #define FAST_INIT 1 */
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci#define BUILD 2401
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci#define MOVE_DPI 100
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_ci#include "rts8891.h"
125141cc406Sopenharmony_ci#include "rts88xx_lib.h"
126141cc406Sopenharmony_ci#include "rts8891_low.c"
127141cc406Sopenharmony_ci#include "rts8891_devices.c"
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci#define DEEP_DEBUG 1
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_ci/**
133141cc406Sopenharmony_ci * Pointer to the first Rts8891_Session in the linked list of
134141cc406Sopenharmony_ci * opened device. Sessions are inserted here on sane_open() and
135141cc406Sopenharmony_ci * removed on sane_close().
136141cc406Sopenharmony_ci */
137141cc406Sopenharmony_cistatic Rts8891_Session *first_handle = NULL;
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ci/* pointer to the first device attached to the backend
141141cc406Sopenharmony_ci * the same device may be opened several time
142141cc406Sopenharmony_ci * entry are inserted here by attach_rts8891 */
143141cc406Sopenharmony_cistatic Rts8891_Device *first_device = NULL;
144141cc406Sopenharmony_cistatic SANE_Int num_devices = 0;
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci/*
147141cc406Sopenharmony_ci * needed by sane_get_devices
148141cc406Sopenharmony_ci */
149141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = {
153141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
154141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
155141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
156141cc406Sopenharmony_ci  0
157141cc406Sopenharmony_ci};
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_cistatic SANE_Range x_range = {
160141cc406Sopenharmony_ci  SANE_FIX (0.0),		/* minimum */
161141cc406Sopenharmony_ci  SANE_FIX (216.0),		/* maximum */
162141cc406Sopenharmony_ci  SANE_FIX (0.0)		/* quantization */
163141cc406Sopenharmony_ci};
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_cistatic SANE_Range y_range = {
166141cc406Sopenharmony_ci  SANE_FIX (0.0),		/* minimum */
167141cc406Sopenharmony_ci  SANE_FIX (299.0),		/* maximum */
168141cc406Sopenharmony_ci  SANE_FIX (0.0)		/* no quantization */
169141cc406Sopenharmony_ci};
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci/* model number ranges from 0 to 2, must be changed if
172141cc406Sopenharmony_ci * Rts8891_USB_Device_Entry changes */
173141cc406Sopenharmony_cistatic const SANE_Range model_range = {
174141cc406Sopenharmony_ci  0,				/* minimum */
175141cc406Sopenharmony_ci  2,				/* maximum */
176141cc406Sopenharmony_ci  0				/* no quantization */
177141cc406Sopenharmony_ci};
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci/* sensor number ranges from 0 to SENSOR_TYPE_MAX, must be changed if */
180141cc406Sopenharmony_cistatic const SANE_Range sensor_range = {
181141cc406Sopenharmony_ci  0,				/* minimum */
182141cc406Sopenharmony_ci  SENSOR_TYPE_MAX,		/* maximum */
183141cc406Sopenharmony_ci  0				/* no quantization */
184141cc406Sopenharmony_ci};
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_cistatic const SANE_Range u8_range = {
187141cc406Sopenharmony_ci  0,				/* minimum */
188141cc406Sopenharmony_ci  255,				/* maximum */
189141cc406Sopenharmony_ci  0				/* no quantization */
190141cc406Sopenharmony_ci};
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_cistatic const SANE_Range threshold_percentage_range = {
193141cc406Sopenharmony_ci  SANE_FIX (0),			/* minimum */
194141cc406Sopenharmony_ci  SANE_FIX (100),		/* maximum */
195141cc406Sopenharmony_ci  SANE_FIX (1)			/* quantization */
196141cc406Sopenharmony_ci};
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_cistatic size_t
199141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
200141cc406Sopenharmony_ci{
201141cc406Sopenharmony_ci  size_t size, max_size = 0;
202141cc406Sopenharmony_ci  SANE_Int i;
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
205141cc406Sopenharmony_ci    {
206141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
207141cc406Sopenharmony_ci      if (size > max_size)
208141cc406Sopenharmony_ci	max_size = size;
209141cc406Sopenharmony_ci    }
210141cc406Sopenharmony_ci  return max_size;
211141cc406Sopenharmony_ci}
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci  /**> placeholders for decoded configuration values */
214141cc406Sopenharmony_cistatic Rts8891_Config rtscfg;
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
217141cc406Sopenharmony_cistatic SANE_Status probe_rts8891_devices (void);
218141cc406Sopenharmony_cistatic SANE_Status config_attach_rts8891 (SANEI_Config * config,
219141cc406Sopenharmony_ci					  const char *devname, void *data);
220141cc406Sopenharmony_cistatic SANE_Status attach_rts8891 (const char *name);
221141cc406Sopenharmony_cistatic SANE_Status set_lamp_brightness (struct Rts8891_Device *dev,
222141cc406Sopenharmony_ci					int level);
223141cc406Sopenharmony_cistatic SANE_Status init_options (struct Rts8891_Session *session);
224141cc406Sopenharmony_ci#ifndef FAST_INIT
225141cc406Sopenharmony_cistatic SANE_Status init_device (struct Rts8891_Device *dev);
226141cc406Sopenharmony_ci#else
227141cc406Sopenharmony_cistatic SANE_Status detect_device (struct Rts8891_Device *dev);
228141cc406Sopenharmony_cistatic SANE_Status initialize_device (struct Rts8891_Device *dev);
229141cc406Sopenharmony_ci#endif
230141cc406Sopenharmony_cistatic SANE_Status init_lamp (struct Rts8891_Device *dev);
231141cc406Sopenharmony_cistatic SANE_Status find_origin (struct Rts8891_Device *dev,
232141cc406Sopenharmony_ci				SANE_Bool * changed);
233141cc406Sopenharmony_cistatic SANE_Status find_margin (struct Rts8891_Device *dev);
234141cc406Sopenharmony_cistatic SANE_Status dark_calibration (struct Rts8891_Device *dev, int mode,
235141cc406Sopenharmony_ci				     int light);
236141cc406Sopenharmony_cistatic SANE_Status gain_calibration (struct Rts8891_Device *dev, int mode,
237141cc406Sopenharmony_ci				     int light);
238141cc406Sopenharmony_cistatic SANE_Status offset_calibration (struct Rts8891_Device *dev, int mode,
239141cc406Sopenharmony_ci				       int light);
240141cc406Sopenharmony_cistatic SANE_Status shading_calibration (struct Rts8891_Device *dev,
241141cc406Sopenharmony_ci					SANE_Bool color, int mode, int light);
242141cc406Sopenharmony_cistatic SANE_Status send_calibration_data (struct Rts8891_Session *session);
243141cc406Sopenharmony_cistatic SANE_Status write_scan_registers (struct Rts8891_Session *session);
244141cc406Sopenharmony_cistatic SANE_Status read_data (struct Rts8891_Session *session,
245141cc406Sopenharmony_ci			      SANE_Byte * dest, SANE_Int length);
246141cc406Sopenharmony_cistatic SANE_Status compute_parameters (struct Rts8891_Session *session);
247141cc406Sopenharmony_cistatic SANE_Status move_to_scan_area (struct Rts8891_Session *session);
248141cc406Sopenharmony_cistatic SANE_Status park_head (struct Rts8891_Device *dev, SANE_Bool wait);
249141cc406Sopenharmony_cistatic SANE_Status update_button_status (struct Rts8891_Session *session);
250141cc406Sopenharmony_cistatic SANE_Status set_lamp_state (struct Rts8891_Session *session, int on);
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
254141cc406Sopenharmony_ci/* writes gray data to a pnm file */
255141cc406Sopenharmony_cistatic void
256141cc406Sopenharmony_ciwrite_gray_data (unsigned char *image, char *name, SANE_Int width,
257141cc406Sopenharmony_ci		 SANE_Int height)
258141cc406Sopenharmony_ci{
259141cc406Sopenharmony_ci  FILE *fdbg = NULL;
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  fdbg = fopen (name, "wb");
262141cc406Sopenharmony_ci  if (fdbg == NULL)
263141cc406Sopenharmony_ci    return;
264141cc406Sopenharmony_ci  fprintf (fdbg, "P5\n%d %d\n255\n", width, height);
265141cc406Sopenharmony_ci  fwrite (image, width, height, fdbg);
266141cc406Sopenharmony_ci  fclose (fdbg);
267141cc406Sopenharmony_ci}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
270141cc406Sopenharmony_ci/* writes rgb data to a pnm file */
271141cc406Sopenharmony_cistatic void
272141cc406Sopenharmony_ciwrite_rgb_data (char *name, unsigned char *image, SANE_Int width,
273141cc406Sopenharmony_ci		SANE_Int height)
274141cc406Sopenharmony_ci{
275141cc406Sopenharmony_ci  FILE *fdbg = NULL;
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci  fdbg = fopen (name, "wb");
278141cc406Sopenharmony_ci  if (fdbg == NULL)
279141cc406Sopenharmony_ci    return;
280141cc406Sopenharmony_ci  fprintf (fdbg, "P6\n%d %d\n255\n", width, height);
281141cc406Sopenharmony_ci  fwrite (image, width * 3, height, fdbg);
282141cc406Sopenharmony_ci  fclose (fdbg);
283141cc406Sopenharmony_ci}
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci/*
288141cc406Sopenharmony_ci * SANE Interface
289141cc406Sopenharmony_ci */
290141cc406Sopenharmony_ci
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci/**
293141cc406Sopenharmony_ci * Called by SANE initially.
294141cc406Sopenharmony_ci *
295141cc406Sopenharmony_ci * From the SANE spec:
296141cc406Sopenharmony_ci * This function must be called before any other SANE function can be
297141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this
298141cc406Sopenharmony_ci * function is not called first. The version code of the backend is
299141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer
300141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either
301141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires
302141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does
303141cc406Sopenharmony_ci * not support authentication.
304141cc406Sopenharmony_ci */
305141cc406Sopenharmony_ciSANE_Status
306141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
307141cc406Sopenharmony_ci{
308141cc406Sopenharmony_ci  SANE_Status status;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  (void) authorize;		/* get rid of compiler warning */
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  /* init ASIC libraries */
313141cc406Sopenharmony_ci  sanei_rts88xx_lib_init ();
314141cc406Sopenharmony_ci  rts8891_low_init ();
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_ci  /* init backend debug */
317141cc406Sopenharmony_ci  DBG_INIT ();
318141cc406Sopenharmony_ci  DBG (DBG_info, "SANE Rts8891 backend version %d.%d-%d\n",
319141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
320141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: start\n");
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci  if (version_code)
323141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci  /* cold-plugging case : probe for already plugged devices */
326141cc406Sopenharmony_ci  status = probe_rts8891_devices ();
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: exit\n");
329141cc406Sopenharmony_ci  return status;
330141cc406Sopenharmony_ci}
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci/**
334141cc406Sopenharmony_ci * Called by SANE to find out about supported devices.
335141cc406Sopenharmony_ci *
336141cc406Sopenharmony_ci * From the SANE spec:
337141cc406Sopenharmony_ci * This function can be used to query the list of devices that are
338141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a
339141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device
340141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to
341141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function
342141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This
343141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become
344141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are
345141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is
346141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote
347141cc406Sopenharmony_ci * devices that are accessible to the SANE library.
348141cc406Sopenharmony_ci *
349141cc406Sopenharmony_ci * SANE does not require that this function is called before a
350141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified
351141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and
352141cc406Sopenharmony_ci * undesirable to call this function first.
353141cc406Sopenharmony_ci */
354141cc406Sopenharmony_ciSANE_Status
355141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci  SANE_Int dev_num;
358141cc406Sopenharmony_ci  struct Rts8891_Device *device;
359141cc406Sopenharmony_ci  SANE_Device *sane_device;
360141cc406Sopenharmony_ci  int i;
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: start: local_only = %s\n",
363141cc406Sopenharmony_ci       local_only == SANE_TRUE ? "true" : "false");
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  /* hot-plugging case : probe for devices plugged since sane_init called */
366141cc406Sopenharmony_ci  probe_rts8891_devices ();
367141cc406Sopenharmony_ci
368141cc406Sopenharmony_ci  /* reset devlist first if needed */
369141cc406Sopenharmony_ci  if (devlist)
370141cc406Sopenharmony_ci    {
371141cc406Sopenharmony_ci      for (i = 0; i < num_devices; i++)
372141cc406Sopenharmony_ci	free ((char *) devlist[i]);
373141cc406Sopenharmony_ci      free (devlist);
374141cc406Sopenharmony_ci      devlist = NULL;
375141cc406Sopenharmony_ci    }
376141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
377141cc406Sopenharmony_ci  if (!devlist)
378141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  *device_list = devlist;
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci  dev_num = 0;
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  /* we build a list of SANE_Device from the list of attached devices */
385141cc406Sopenharmony_ci  for (device = first_device; dev_num < num_devices; device = device->next)
386141cc406Sopenharmony_ci    {
387141cc406Sopenharmony_ci      sane_device = malloc (sizeof (*sane_device));
388141cc406Sopenharmony_ci      if (!sane_device)
389141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
390141cc406Sopenharmony_ci      sane_device->name = device->file_name;
391141cc406Sopenharmony_ci      sane_device->vendor = device->model->vendor;
392141cc406Sopenharmony_ci      sane_device->model = device->model->product;
393141cc406Sopenharmony_ci      sane_device->type = device->model->type;
394141cc406Sopenharmony_ci      devlist[dev_num++] = sane_device;
395141cc406Sopenharmony_ci    }
396141cc406Sopenharmony_ci  devlist[dev_num++] = 0;
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci  *device_list = devlist;
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: exit\n");
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
403141cc406Sopenharmony_ci}
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci/**
407141cc406Sopenharmony_ci * Called to establish connection with the session. This function will
408141cc406Sopenharmony_ci * also establish meaningful defaults and initialize the options.
409141cc406Sopenharmony_ci *
410141cc406Sopenharmony_ci * From the SANE spec:
411141cc406Sopenharmony_ci * This function is used to establish a connection to a particular
412141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument
413141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device
414141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length
415141cc406Sopenharmony_ci * string as the device requests opening the first available device
416141cc406Sopenharmony_ci * (if there is such a device).
417141cc406Sopenharmony_ci * TODO handle SANE_STATUS_BUSY
418141cc406Sopenharmony_ci */
419141cc406Sopenharmony_ciSANE_Status
420141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle)
421141cc406Sopenharmony_ci{
422141cc406Sopenharmony_ci  struct Rts8891_Session *session = NULL;
423141cc406Sopenharmony_ci  struct Rts8891_Device *device = NULL;
424141cc406Sopenharmony_ci  SANE_Status status;
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: start (devicename=%s)\n", name);
427141cc406Sopenharmony_ci  if (name[0] == 0 || strncmp (name, "rts8891", 7) == 0)
428141cc406Sopenharmony_ci    {
429141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: no device requested, using default\n");
430141cc406Sopenharmony_ci      if (first_device)
431141cc406Sopenharmony_ci	{
432141cc406Sopenharmony_ci	  device = first_device;
433141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_open: device %s used as default device\n",
434141cc406Sopenharmony_ci	       device->file_name);
435141cc406Sopenharmony_ci	}
436141cc406Sopenharmony_ci    }
437141cc406Sopenharmony_ci  else
438141cc406Sopenharmony_ci    {
439141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: device %s requested\n", name);
440141cc406Sopenharmony_ci      /* walk the device list until we find a matching name */
441141cc406Sopenharmony_ci      device = first_device;
442141cc406Sopenharmony_ci      while (device && strcmp (device->file_name, name) != 0)
443141cc406Sopenharmony_ci	{
444141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_open: device %s doesn't match\n",
445141cc406Sopenharmony_ci	       device->file_name);
446141cc406Sopenharmony_ci	  device = device->next;
447141cc406Sopenharmony_ci	}
448141cc406Sopenharmony_ci    }
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci  /* check whether we have found a match or reach the end of the device list */
451141cc406Sopenharmony_ci  if (!device)
452141cc406Sopenharmony_ci    {
453141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: no device found\n");
454141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
455141cc406Sopenharmony_ci    }
456141cc406Sopenharmony_ci
457141cc406Sopenharmony_ci  /* now we have a device, duplicate it and return it in handle */
458141cc406Sopenharmony_ci  DBG (DBG_info, "sane_open: device %s found\n", name);
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci  if (device->model->flags & RTS8891_FLAG_UNTESTED)
461141cc406Sopenharmony_ci    {
462141cc406Sopenharmony_ci      DBG (DBG_error0,
463141cc406Sopenharmony_ci	   "WARNING: Your scanner is not fully supported or at least \n");
464141cc406Sopenharmony_ci      DBG (DBG_error0,
465141cc406Sopenharmony_ci	   "         had only limited testing. Please be careful and \n");
466141cc406Sopenharmony_ci      DBG (DBG_error0, "         report any failure/success to \n");
467141cc406Sopenharmony_ci      DBG (DBG_error0,
468141cc406Sopenharmony_ci	   "         sane-devel@alioth-lists.debian.net. Please provide as many\n");
469141cc406Sopenharmony_ci      DBG (DBG_error0,
470141cc406Sopenharmony_ci	   "         details as possible, e.g. the exact name of your\n");
471141cc406Sopenharmony_ci      DBG (DBG_error0, "         scanner and what does (not) work.\n");
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci    }
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci  /* open USB link */
476141cc406Sopenharmony_ci  status = sanei_usb_open (device->file_name, &device->devnum);
477141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
478141cc406Sopenharmony_ci    {
479141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_open: couldn't open device `%s': %s\n",
480141cc406Sopenharmony_ci	   device->file_name, sane_strstatus (status));
481141cc406Sopenharmony_ci      return status;
482141cc406Sopenharmony_ci    }
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci  /* device initialization */
485141cc406Sopenharmony_ci  if (device->initialized == SANE_FALSE)
486141cc406Sopenharmony_ci    {
487141cc406Sopenharmony_ci#ifdef FAST_INIT
488141cc406Sopenharmony_ci      status = detect_device (device);
489141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
490141cc406Sopenharmony_ci	{
491141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_open: detect_device failed\n");
492141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_open: exit on error\n");
493141cc406Sopenharmony_ci	  return status;
494141cc406Sopenharmony_ci	}
495141cc406Sopenharmony_ci      status = initialize_device (device);
496141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
497141cc406Sopenharmony_ci	{
498141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_open: initialize_device failed\n");
499141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_open: exit on error\n");
500141cc406Sopenharmony_ci	  return status;
501141cc406Sopenharmony_ci	}
502141cc406Sopenharmony_ci#else
503141cc406Sopenharmony_ci      status = init_device (device);
504141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
505141cc406Sopenharmony_ci	{
506141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_open: init_device failed\n");
507141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_open: exit on error\n");
508141cc406Sopenharmony_ci	  return status;
509141cc406Sopenharmony_ci	}
510141cc406Sopenharmony_ci      device->initialized = SANE_TRUE;
511141cc406Sopenharmony_ci#endif
512141cc406Sopenharmony_ci    }
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci  /* prepare handle to return */
515141cc406Sopenharmony_ci  session = (Rts8891_Session *) malloc (sizeof (Rts8891_Session));
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci  session->scanning = SANE_FALSE;
518141cc406Sopenharmony_ci  session->dev = device;
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci  init_options (session);
521141cc406Sopenharmony_ci  session->scanning = SANE_FALSE;
522141cc406Sopenharmony_ci  session->non_blocking = SANE_FALSE;
523141cc406Sopenharmony_ci  *handle = session;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  /* add the handle to the list */
526141cc406Sopenharmony_ci  session->next = first_handle;
527141cc406Sopenharmony_ci  first_handle = session;
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci  /* release the interface to allow device sharing */
530141cc406Sopenharmony_ci  if (session->dev->conf.allowsharing == SANE_TRUE)
531141cc406Sopenharmony_ci    {
532141cc406Sopenharmony_ci      sanei_usb_release_interface (device->devnum, 0);
533141cc406Sopenharmony_ci    }
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: exit\n");
536141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
537141cc406Sopenharmony_ci}
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci/**
541141cc406Sopenharmony_ci * Set non blocking mode. In this mode, read return immediately when
542141cc406Sopenharmony_ci * no data is available, instead of polling the scanner.
543141cc406Sopenharmony_ci */
544141cc406Sopenharmony_ciSANE_Status
545141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
546141cc406Sopenharmony_ci{
547141cc406Sopenharmony_ci  Rts8891_Session *session = (Rts8891_Session *) handle;
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: start\n");
550141cc406Sopenharmony_ci  if (session->scanning != SANE_TRUE)
551141cc406Sopenharmony_ci    {
552141cc406Sopenharmony_ci      DBG (DBG_error, "sane_set_io_mode: called out of a scan\n");
553141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
554141cc406Sopenharmony_ci    }
555141cc406Sopenharmony_ci  session->non_blocking = non_blocking;
556141cc406Sopenharmony_ci  DBG (DBG_warn, "sane_set_io_mode: I/O mode set to %sblocking.\n",
557141cc406Sopenharmony_ci       non_blocking ? "non " : " ");
558141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: exit\n");
559141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
560141cc406Sopenharmony_ci}
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci
563141cc406Sopenharmony_ci/**
564141cc406Sopenharmony_ci * An advanced method we don't support but have to define.
565141cc406Sopenharmony_ci */
566141cc406Sopenharmony_ciSANE_Status
567141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fdp)
568141cc406Sopenharmony_ci{
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: start\n");
571141cc406Sopenharmony_ci  if(handle==0 || fdp==NULL)
572141cc406Sopenharmony_ci    {
573141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
574141cc406Sopenharmony_ci    }
575141cc406Sopenharmony_ci  DBG (DBG_warn, "sane_get_select_fd: unsupported ...\n");
576141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: exit\n");
577141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
578141cc406Sopenharmony_ci}
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci/**
582141cc406Sopenharmony_ci * Returns the options we know.
583141cc406Sopenharmony_ci *
584141cc406Sopenharmony_ci * From the SANE spec:
585141cc406Sopenharmony_ci * This function is used to access option descriptors. The function
586141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device
587141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a
588141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of
589141cc406Sopenharmony_ci * options that are available for device handle h (the count includes
590141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns
591141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid
592141cc406Sopenharmony_ci * (and at the returned address) until the device is closed.
593141cc406Sopenharmony_ci */
594141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
595141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
596141cc406Sopenharmony_ci{
597141cc406Sopenharmony_ci  struct Rts8891_Session *session = handle;
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: start\n");
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
602141cc406Sopenharmony_ci    return NULL;
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci  DBG (DBG_info, "sane_get_option_descriptor: \"%s\"\n",
605141cc406Sopenharmony_ci       session->opt[option].name);
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
608141cc406Sopenharmony_ci  return &(session->opt[option]);
609141cc406Sopenharmony_ci}
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci/**
612141cc406Sopenharmony_ci * sets automatic value for an option , called by sane_control_option after
613141cc406Sopenharmony_ci * all checks have been done */
614141cc406Sopenharmony_cistatic SANE_Status
615141cc406Sopenharmony_ciset_automatic_value (Rts8891_Session * s, int option, SANE_Int * myinfo)
616141cc406Sopenharmony_ci{
617141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
618141cc406Sopenharmony_ci  SANE_Int i, min;
619141cc406Sopenharmony_ci  const SANE_Word *dpi_list;
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci  switch (option)
622141cc406Sopenharmony_ci    {
623141cc406Sopenharmony_ci    case OPT_TL_X:
624141cc406Sopenharmony_ci      s->val[OPT_TL_X].w = x_range.min;
625141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
626141cc406Sopenharmony_ci      break;
627141cc406Sopenharmony_ci    case OPT_TL_Y:
628141cc406Sopenharmony_ci      s->val[OPT_TL_Y].w = y_range.min;
629141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
630141cc406Sopenharmony_ci      break;
631141cc406Sopenharmony_ci    case OPT_BR_X:
632141cc406Sopenharmony_ci      s->val[OPT_BR_X].w = x_range.max;
633141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
634141cc406Sopenharmony_ci      break;
635141cc406Sopenharmony_ci    case OPT_BR_Y:
636141cc406Sopenharmony_ci      s->val[OPT_BR_Y].w = y_range.max;
637141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
638141cc406Sopenharmony_ci      break;
639141cc406Sopenharmony_ci    case OPT_RESOLUTION:
640141cc406Sopenharmony_ci      /* we set up to the lowest available dpi value */
641141cc406Sopenharmony_ci      dpi_list = s->opt[OPT_RESOLUTION].constraint.word_list;
642141cc406Sopenharmony_ci      min = 65536;
643141cc406Sopenharmony_ci      for (i = 1; i < dpi_list[0]; i++)
644141cc406Sopenharmony_ci	{
645141cc406Sopenharmony_ci	  if (dpi_list[i] < min)
646141cc406Sopenharmony_ci	    min = dpi_list[i];
647141cc406Sopenharmony_ci	}
648141cc406Sopenharmony_ci      s->val[OPT_RESOLUTION].w = min;
649141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
650141cc406Sopenharmony_ci      break;
651141cc406Sopenharmony_ci    case OPT_THRESHOLD:
652141cc406Sopenharmony_ci      s->val[OPT_THRESHOLD].w = SANE_FIX (50);
653141cc406Sopenharmony_ci      break;
654141cc406Sopenharmony_ci    case OPT_PREVIEW:
655141cc406Sopenharmony_ci      s->val[OPT_PREVIEW].w = SANE_FALSE;
656141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
657141cc406Sopenharmony_ci      break;
658141cc406Sopenharmony_ci    case OPT_MODE:
659141cc406Sopenharmony_ci      if (s->val[OPT_MODE].s)
660141cc406Sopenharmony_ci	free (s->val[OPT_MODE].s);
661141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (mode_list[0]);
662141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_OPTIONS;
663141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
664141cc406Sopenharmony_ci      break;
665141cc406Sopenharmony_ci    case OPT_CUSTOM_GAMMA:
666141cc406Sopenharmony_ci      s->val[option].b = SANE_FALSE;
667141cc406Sopenharmony_ci      DISABLE (OPT_GAMMA_VECTOR);
668141cc406Sopenharmony_ci      DISABLE (OPT_GAMMA_VECTOR_R);
669141cc406Sopenharmony_ci      DISABLE (OPT_GAMMA_VECTOR_G);
670141cc406Sopenharmony_ci      DISABLE (OPT_GAMMA_VECTOR_B);
671141cc406Sopenharmony_ci      break;
672141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR:
673141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_R:
674141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_G:
675141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_B:
676141cc406Sopenharmony_ci      if (s->dev->model->gamma != s->val[option].wa)
677141cc406Sopenharmony_ci	free (s->val[option].wa);
678141cc406Sopenharmony_ci      s->val[option].wa = s->dev->model->gamma;
679141cc406Sopenharmony_ci      break;
680141cc406Sopenharmony_ci    default:
681141cc406Sopenharmony_ci      DBG (DBG_warn, "set_automatic_value: can't set unknown option %d\n",
682141cc406Sopenharmony_ci	   option);
683141cc406Sopenharmony_ci    }
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  return status;
686141cc406Sopenharmony_ci}
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci/**
689141cc406Sopenharmony_ci * sets an option , called by sane_control_option after all
690141cc406Sopenharmony_ci * checks have been done */
691141cc406Sopenharmony_cistatic SANE_Status
692141cc406Sopenharmony_ciset_option_value (Rts8891_Session * s, int option, void *val,
693141cc406Sopenharmony_ci		  SANE_Int * myinfo)
694141cc406Sopenharmony_ci{
695141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
696141cc406Sopenharmony_ci  SANE_Int i;
697141cc406Sopenharmony_ci  SANE_Word tmpw;
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci  switch (option)
700141cc406Sopenharmony_ci    {
701141cc406Sopenharmony_ci    case OPT_TL_X:
702141cc406Sopenharmony_ci    case OPT_TL_Y:
703141cc406Sopenharmony_ci    case OPT_BR_X:
704141cc406Sopenharmony_ci    case OPT_BR_Y:
705141cc406Sopenharmony_ci      s->val[option].w = *(SANE_Word *) val;
706141cc406Sopenharmony_ci      /* we ensure geometry is coherent */
707141cc406Sopenharmony_ci      /* this happens when user drags TL corner right or below the BR point */
708141cc406Sopenharmony_ci      if (s->val[OPT_BR_Y].w < s->val[OPT_TL_Y].w)
709141cc406Sopenharmony_ci	{
710141cc406Sopenharmony_ci	  tmpw = s->val[OPT_BR_Y].w;
711141cc406Sopenharmony_ci	  s->val[OPT_BR_Y].w = s->val[OPT_TL_Y].w;
712141cc406Sopenharmony_ci	  s->val[OPT_TL_Y].w = tmpw;
713141cc406Sopenharmony_ci	}
714141cc406Sopenharmony_ci      if (s->val[OPT_BR_X].w < s->val[OPT_TL_X].w)
715141cc406Sopenharmony_ci	{
716141cc406Sopenharmony_ci	  tmpw = s->val[OPT_BR_X].w;
717141cc406Sopenharmony_ci	  s->val[OPT_BR_X].w = s->val[OPT_TL_X].w;
718141cc406Sopenharmony_ci	  s->val[OPT_TL_X].w = tmpw;
719141cc406Sopenharmony_ci	}
720141cc406Sopenharmony_ci
721141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
722141cc406Sopenharmony_ci      break;
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci    case OPT_RESOLUTION:
725141cc406Sopenharmony_ci    case OPT_THRESHOLD:
726141cc406Sopenharmony_ci    case OPT_PREVIEW:
727141cc406Sopenharmony_ci      s->val[option].w = *(SANE_Word *) val;
728141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
729141cc406Sopenharmony_ci      break;
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci    case OPT_MODE:
732141cc406Sopenharmony_ci      if (s->val[option].s)
733141cc406Sopenharmony_ci	free (s->val[option].s);
734141cc406Sopenharmony_ci      s->val[option].s = strdup (val);
735141cc406Sopenharmony_ci      if (strcmp (s->val[option].s, LINEART_MODE) == 0)
736141cc406Sopenharmony_ci	{
737141cc406Sopenharmony_ci	  ENABLE (OPT_THRESHOLD);
738141cc406Sopenharmony_ci	}
739141cc406Sopenharmony_ci      else
740141cc406Sopenharmony_ci	{
741141cc406Sopenharmony_ci	  DISABLE (OPT_THRESHOLD);
742141cc406Sopenharmony_ci	}
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci      /* if custom gamma, toggle gamma table options according to the mode */
745141cc406Sopenharmony_ci      if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE)
746141cc406Sopenharmony_ci	{
747141cc406Sopenharmony_ci	  if (strcmp (s->val[option].s, COLOR_MODE) == 0)
748141cc406Sopenharmony_ci	    {
749141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR);
750141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_R);
751141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_G);
752141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_B);
753141cc406Sopenharmony_ci	    }
754141cc406Sopenharmony_ci	  else
755141cc406Sopenharmony_ci	    {
756141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR);
757141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_R);
758141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_G);
759141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_B);
760141cc406Sopenharmony_ci	    }
761141cc406Sopenharmony_ci	}
762141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
763141cc406Sopenharmony_ci      break;
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci    case OPT_CUSTOM_GAMMA:
766141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
767141cc406Sopenharmony_ci      s->val[OPT_CUSTOM_GAMMA].b = *(SANE_Bool *) val;
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci      if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE)
770141cc406Sopenharmony_ci	{
771141cc406Sopenharmony_ci	  if (strcmp (s->val[OPT_MODE].s, COLOR_MODE) == 0)
772141cc406Sopenharmony_ci	    {
773141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR);
774141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_R);
775141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_G);
776141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR_B);
777141cc406Sopenharmony_ci	    }
778141cc406Sopenharmony_ci	  else
779141cc406Sopenharmony_ci	    {
780141cc406Sopenharmony_ci	      ENABLE (OPT_GAMMA_VECTOR);
781141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_R);
782141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_G);
783141cc406Sopenharmony_ci	      DISABLE (OPT_GAMMA_VECTOR_B);
784141cc406Sopenharmony_ci	    }
785141cc406Sopenharmony_ci	}
786141cc406Sopenharmony_ci      else
787141cc406Sopenharmony_ci	{
788141cc406Sopenharmony_ci	  DISABLE (OPT_GAMMA_VECTOR);
789141cc406Sopenharmony_ci	  DISABLE (OPT_GAMMA_VECTOR_R);
790141cc406Sopenharmony_ci	  DISABLE (OPT_GAMMA_VECTOR_G);
791141cc406Sopenharmony_ci	  DISABLE (OPT_GAMMA_VECTOR_B);
792141cc406Sopenharmony_ci	}
793141cc406Sopenharmony_ci      break;
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR:
796141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_R:
797141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_G:
798141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_B:
799141cc406Sopenharmony_ci      /* sanity checks */
800141cc406Sopenharmony_ci      for (i = 0; i < (int) (s->opt[option].size / sizeof (SANE_Word)); i++)
801141cc406Sopenharmony_ci	{
802141cc406Sopenharmony_ci	  /* avoid 0xaa values since they will be problematic */
803141cc406Sopenharmony_ci	  if (((SANE_Int *) val)[i] == 0xaa)
804141cc406Sopenharmony_ci	    ((SANE_Int *) val)[i] = 0xab;
805141cc406Sopenharmony_ci	}
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci      /* free memory from previous set */
808141cc406Sopenharmony_ci      if (s->dev->model->gamma != s->val[option].wa)
809141cc406Sopenharmony_ci	free (s->val[option].wa);
810141cc406Sopenharmony_ci
811141cc406Sopenharmony_ci      /* then alloc memory */
812141cc406Sopenharmony_ci      s->val[option].wa = (SANE_Word *) malloc (256 * sizeof (SANE_Word));
813141cc406Sopenharmony_ci      if (s->val[option].wa == NULL)
814141cc406Sopenharmony_ci	{
815141cc406Sopenharmony_ci	  s->val[option].wa = s->dev->model->gamma;
816141cc406Sopenharmony_ci	  DBG (DBG_error0,
817141cc406Sopenharmony_ci	       "set_option_value: not enough memory for %lu bytes!\n",
818141cc406Sopenharmony_ci	       (u_long) (256 * sizeof (SANE_Word)));
819141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
820141cc406Sopenharmony_ci	}
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci      /* data copy */
823141cc406Sopenharmony_ci      memcpy (s->val[option].wa, val, s->opt[option].size);
824141cc406Sopenharmony_ci      break;
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci    case OPT_LAMP_ON:
827141cc406Sopenharmony_ci      return set_lamp_state (s, 1);
828141cc406Sopenharmony_ci      break;
829141cc406Sopenharmony_ci
830141cc406Sopenharmony_ci    case OPT_LAMP_OFF:
831141cc406Sopenharmony_ci      return set_lamp_state (s, 0);
832141cc406Sopenharmony_ci      break;
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci    default:
835141cc406Sopenharmony_ci      DBG (DBG_warn, "set_option_value: can't set unknown option %d\n",
836141cc406Sopenharmony_ci	   option);
837141cc406Sopenharmony_ci    }
838141cc406Sopenharmony_ci  return status;
839141cc406Sopenharmony_ci}
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci/**
842141cc406Sopenharmony_ci * gets an option , called by sane_control_option after all checks
843141cc406Sopenharmony_ci * have been done */
844141cc406Sopenharmony_cistatic SANE_Status
845141cc406Sopenharmony_ciget_option_value (Rts8891_Session * s, int option, void *val)
846141cc406Sopenharmony_ci{
847141cc406Sopenharmony_ci  switch (option)
848141cc406Sopenharmony_ci    {
849141cc406Sopenharmony_ci      /* word or word equivalent options: */
850141cc406Sopenharmony_ci    case OPT_NUM_OPTS:
851141cc406Sopenharmony_ci    case OPT_RESOLUTION:
852141cc406Sopenharmony_ci    case OPT_PREVIEW:
853141cc406Sopenharmony_ci    case OPT_TL_X:
854141cc406Sopenharmony_ci    case OPT_TL_Y:
855141cc406Sopenharmony_ci    case OPT_BR_X:
856141cc406Sopenharmony_ci    case OPT_BR_Y:
857141cc406Sopenharmony_ci    case OPT_THRESHOLD:
858141cc406Sopenharmony_ci    case OPT_CUSTOM_GAMMA:
859141cc406Sopenharmony_ci      *(SANE_Word *) val = s->val[option].w;
860141cc406Sopenharmony_ci      break;
861141cc406Sopenharmony_ci    case OPT_BUTTON_1:
862141cc406Sopenharmony_ci    case OPT_BUTTON_2:
863141cc406Sopenharmony_ci    case OPT_BUTTON_3:
864141cc406Sopenharmony_ci    case OPT_BUTTON_4:
865141cc406Sopenharmony_ci    case OPT_BUTTON_5:
866141cc406Sopenharmony_ci    case OPT_BUTTON_6:
867141cc406Sopenharmony_ci    case OPT_BUTTON_7:
868141cc406Sopenharmony_ci    case OPT_BUTTON_8:
869141cc406Sopenharmony_ci    case OPT_BUTTON_9:
870141cc406Sopenharmony_ci    case OPT_BUTTON_10:
871141cc406Sopenharmony_ci    case OPT_BUTTON_11:
872141cc406Sopenharmony_ci      /* no button pressed by default */
873141cc406Sopenharmony_ci      *(SANE_Word *) val = SANE_FALSE;
874141cc406Sopenharmony_ci      if (option - OPT_BUTTON_1 > s->dev->model->buttons)
875141cc406Sopenharmony_ci	{
876141cc406Sopenharmony_ci	  DBG (DBG_warn,
877141cc406Sopenharmony_ci	       "get_option_value: invalid button option %d\n", option);
878141cc406Sopenharmony_ci	}
879141cc406Sopenharmony_ci      else
880141cc406Sopenharmony_ci	{
881141cc406Sopenharmony_ci	  update_button_status (s);
882141cc406Sopenharmony_ci	  /* copy the button state */
883141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
884141cc406Sopenharmony_ci	  /* clear the button state */
885141cc406Sopenharmony_ci	  s->val[option].w = SANE_FALSE;
886141cc406Sopenharmony_ci	  DBG (DBG_io,
887141cc406Sopenharmony_ci	       "get_option_value: button option %d=%d\n", option,
888141cc406Sopenharmony_ci	       *(SANE_Word *) val);
889141cc406Sopenharmony_ci	}
890141cc406Sopenharmony_ci      break;
891141cc406Sopenharmony_ci      /* string options: */
892141cc406Sopenharmony_ci    case OPT_MODE:
893141cc406Sopenharmony_ci      strcpy (val, s->val[option].s);
894141cc406Sopenharmony_ci      break;
895141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR:
896141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_R:
897141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_G:
898141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_B:
899141cc406Sopenharmony_ci      memcpy (val, s->val[option].wa, s->opt[option].size);
900141cc406Sopenharmony_ci      break;
901141cc406Sopenharmony_ci    default:
902141cc406Sopenharmony_ci      DBG (DBG_warn, "get_option_value: can't get unknown option %d\n",
903141cc406Sopenharmony_ci	   option);
904141cc406Sopenharmony_ci    }
905141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
906141cc406Sopenharmony_ci}
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci/**
909141cc406Sopenharmony_ci * Gets or sets an option value.
910141cc406Sopenharmony_ci *
911141cc406Sopenharmony_ci * From the SANE spec:
912141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option
913141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which
914141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The
915141cc406Sopenharmony_ci * possible values of this parameter are described in more detail
916141cc406Sopenharmony_ci * below.  The value of the option is passed through argument val. It
917141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory
918141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option
919141cc406Sopenharmony_ci * value (determined by member size in the corresponding option
920141cc406Sopenharmony_ci * descriptor).
921141cc406Sopenharmony_ci *
922141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a
923141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter
924141cc406Sopenharmony_ci * since the backend will stop reading the option value upon
925141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i
926141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how
927141cc406Sopenharmony_ci * well the request has been met.
928141cc406Sopenharmony_ci * action is SANE_ACTION_GET_VALUE, SANE_ACTION_SET_VALUE or SANE_ACTION_SET_AUTO
929141cc406Sopenharmony_ci */
930141cc406Sopenharmony_ciSANE_Status
931141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
932141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
933141cc406Sopenharmony_ci{
934141cc406Sopenharmony_ci  Rts8891_Session *s = handle;
935141cc406Sopenharmony_ci  SANE_Status status;
936141cc406Sopenharmony_ci  SANE_Word cap;
937141cc406Sopenharmony_ci  SANE_Int myinfo = 0;
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  DBG (DBG_io2,
940141cc406Sopenharmony_ci       "sane_control_option: start: action = %s, option = %s (%d)\n",
941141cc406Sopenharmony_ci       (action == SANE_ACTION_GET_VALUE) ? "get" : (action ==
942141cc406Sopenharmony_ci						    SANE_ACTION_SET_VALUE) ?
943141cc406Sopenharmony_ci       "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown",
944141cc406Sopenharmony_ci       s->opt[option].name, option);
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci  if (info)
947141cc406Sopenharmony_ci    *info = 0;
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_ci  /* do checks before trying to apply action */
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci  if (s->scanning)
952141cc406Sopenharmony_ci    {
953141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_control_option: don't call this function while "
954141cc406Sopenharmony_ci	   "scanning (option = %s (%d))\n", s->opt[option].name, option);
955141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
956141cc406Sopenharmony_ci    }
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  /* option must be within existing range */
959141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS || option < 0)
960141cc406Sopenharmony_ci    {
961141cc406Sopenharmony_ci      DBG (DBG_warn,
962141cc406Sopenharmony_ci	   "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n",
963141cc406Sopenharmony_ci	   option);
964141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
965141cc406Sopenharmony_ci    }
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci  /* don't access an inactive option */
968141cc406Sopenharmony_ci  cap = s->opt[option].cap;
969141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
970141cc406Sopenharmony_ci    {
971141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_control_option: option %d is inactive\n", option);
972141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
973141cc406Sopenharmony_ci    }
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci  /* now checks have been done, apply action */
976141cc406Sopenharmony_ci  switch (action)
977141cc406Sopenharmony_ci    {
978141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
979141cc406Sopenharmony_ci      status = get_option_value (s, option, val);
980141cc406Sopenharmony_ci      break;
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
983141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
984141cc406Sopenharmony_ci	{
985141cc406Sopenharmony_ci	  DBG (DBG_warn, "sane_control_option: option %d is not settable\n",
986141cc406Sopenharmony_ci	       option);
987141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
988141cc406Sopenharmony_ci	}
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, &myinfo);
991141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
992141cc406Sopenharmony_ci	{
993141cc406Sopenharmony_ci	  DBG (DBG_warn,
994141cc406Sopenharmony_ci	       "sane_control_option: sanei_constrain_value returned %s\n",
995141cc406Sopenharmony_ci	       sane_strstatus (status));
996141cc406Sopenharmony_ci	  return status;
997141cc406Sopenharmony_ci	}
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci      /* return immediately if no change */
1000141cc406Sopenharmony_ci      if (s->opt[option].type == SANE_TYPE_INT
1001141cc406Sopenharmony_ci	  && *(SANE_Word *) val == s->val[option].w)
1002141cc406Sopenharmony_ci	{
1003141cc406Sopenharmony_ci	  status = SANE_STATUS_GOOD;
1004141cc406Sopenharmony_ci	}
1005141cc406Sopenharmony_ci      else
1006141cc406Sopenharmony_ci	{			/* apply change */
1007141cc406Sopenharmony_ci	  status = set_option_value (s, option, val, &myinfo);
1008141cc406Sopenharmony_ci	}
1009141cc406Sopenharmony_ci      break;
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
1012141cc406Sopenharmony_ci      /* sets automatic values */
1013141cc406Sopenharmony_ci      if (!(cap & SANE_CAP_AUTOMATIC))
1014141cc406Sopenharmony_ci	{
1015141cc406Sopenharmony_ci	  DBG (DBG_warn,
1016141cc406Sopenharmony_ci	       "sane_control_option: option %d is not autosettable\n",
1017141cc406Sopenharmony_ci	       option);
1018141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1019141cc406Sopenharmony_ci	}
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci      status = set_automatic_value (s, option, &myinfo);
1022141cc406Sopenharmony_ci      break;
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci    default:
1025141cc406Sopenharmony_ci      DBG (DBG_error, "sane_control_option: invalid action %d\n", action);
1026141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
1027141cc406Sopenharmony_ci      break;
1028141cc406Sopenharmony_ci    }
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  if (info)
1031141cc406Sopenharmony_ci    *info = myinfo;
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci  DBG (DBG_io2, "sane_control_option: exit\n");
1034141cc406Sopenharmony_ci  return status;
1035141cc406Sopenharmony_ci}
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci/**
1038141cc406Sopenharmony_ci * returns the name of the sensor
1039141cc406Sopenharmony_ci * @param sensor sensor numnber
1040141cc406Sopenharmony_ci * @return string holding the name of the sensor
1041141cc406Sopenharmony_ci */
1042141cc406Sopenharmony_cistatic char *sensor_name (int sensor)
1043141cc406Sopenharmony_ci{
1044141cc406Sopenharmony_ci  switch (sensor)
1045141cc406Sopenharmony_ci    {
1046141cc406Sopenharmony_ci    case SENSOR_TYPE_BARE:
1047141cc406Sopenharmony_ci      return "SENSOR_TYPE_BARE";
1048141cc406Sopenharmony_ci    case SENSOR_TYPE_XPA:
1049141cc406Sopenharmony_ci      return "SENSOR_TYPE_XPA";
1050141cc406Sopenharmony_ci    case SENSOR_TYPE_4400:
1051141cc406Sopenharmony_ci      return "SENSOR_TYPE_4400";
1052141cc406Sopenharmony_ci    case SENSOR_TYPE_4400_BARE:
1053141cc406Sopenharmony_ci      return "SENSOR_TYPE_4400_BARE";
1054141cc406Sopenharmony_ci    default:
1055141cc406Sopenharmony_ci      return "BOGUS";
1056141cc406Sopenharmony_ci    }
1057141cc406Sopenharmony_ci}
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci/**
1060141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started.
1061141cc406Sopenharmony_ci * @param handle opaque handle to a frontend session
1062141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success, SANE_STATUS_BUSY if the device is
1063141cc406Sopenharmony_ci * in use by another session or SANE_STATUS_WARMING_UP if the device is
1064141cc406Sopenharmony_ci * warming up. In this case the fronted as to call sane_start again until
1065141cc406Sopenharmony_ci * warming up is done. Any other values returned are error status.
1066141cc406Sopenharmony_ci */
1067141cc406Sopenharmony_ciSANE_Status
1068141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1069141cc406Sopenharmony_ci{
1070141cc406Sopenharmony_ci  struct Rts8891_Session *session = handle;
1071141cc406Sopenharmony_ci  int light, mode;
1072141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
1073141cc406Sopenharmony_ci  SANE_Status status;
1074141cc406Sopenharmony_ci  SANE_Bool changed;
1075141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
1076141cc406Sopenharmony_ci  struct timeval current;
1077141cc406Sopenharmony_ci#endif
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: start\n");
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci  /* if already scanning, tell we're busy */
1082141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
1083141cc406Sopenharmony_ci    {
1084141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_start: device is already scanning\n");
1085141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1086141cc406Sopenharmony_ci    }
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  /* claim the interface reserve device */
1089141cc406Sopenharmony_ci  if (dev->conf.allowsharing == SANE_TRUE)
1090141cc406Sopenharmony_ci    {
1091141cc406Sopenharmony_ci      status = sanei_usb_claim_interface (dev->devnum, 0);
1092141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1093141cc406Sopenharmony_ci	{
1094141cc406Sopenharmony_ci	  DBG (DBG_warn, "sane_start: cannot claim usb interface\n");
1095141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
1096141cc406Sopenharmony_ci	}
1097141cc406Sopenharmony_ci    }
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci  /* check if we need warming-up */
1100141cc406Sopenharmony_ci  sanei_rts88xx_get_lamp_status (dev->devnum, dev->regs);
1101141cc406Sopenharmony_ci  if ((dev->regs[0x8e] & 0x60) != 0x60)
1102141cc406Sopenharmony_ci    {
1103141cc406Sopenharmony_ci      DBG (DBG_info, "sane_start: lamp needs warming (0x%02x)\n",
1104141cc406Sopenharmony_ci	   dev->regs[0x8e]);
1105141cc406Sopenharmony_ci      dev->needs_warming = SANE_TRUE;
1106141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
1107141cc406Sopenharmony_ci      dev->start_time.tv_sec = current.tv_sec;
1108141cc406Sopenharmony_ci      dev->last_scan.tv_sec = current.tv_sec;
1109141cc406Sopenharmony_ci#endif
1110141cc406Sopenharmony_ci    }
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
1113141cc406Sopenharmony_ci  /* if last scan time is more than 10 minutes ago, scanner also needs
1114141cc406Sopenharmony_ci   * warming-up */
1115141cc406Sopenharmony_ci  gettimeofday (&current, NULL);
1116141cc406Sopenharmony_ci  if ((current.tv_sec - dev->last_scan.tv_sec) / 60 > 10)
1117141cc406Sopenharmony_ci    {
1118141cc406Sopenharmony_ci      DBG (DBG_info,
1119141cc406Sopenharmony_ci	   "sane_start: more than 10 minutes without scanning, lamp needs warming\n");
1120141cc406Sopenharmony_ci      dev->needs_warming = SANE_TRUE;
1121141cc406Sopenharmony_ci      dev->start_time.tv_sec = current.tv_sec;
1122141cc406Sopenharmony_ci      dev->last_scan.tv_sec = current.tv_sec;
1123141cc406Sopenharmony_ci    }
1124141cc406Sopenharmony_ci#endif
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci  /* if parking, wait for head to stop */
1127141cc406Sopenharmony_ci  if(dev->parking==SANE_TRUE)
1128141cc406Sopenharmony_ci    {
1129141cc406Sopenharmony_ci      rts8891_wait_for_home (dev, dev->regs);
1130141cc406Sopenharmony_ci    }
1131141cc406Sopenharmony_ci
1132141cc406Sopenharmony_ci  /* reinit registers to start values */
1133141cc406Sopenharmony_ci  rts8891_set_default_regs (dev->regs);
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci  /* step 0: light up */
1136141cc406Sopenharmony_ci  init_lamp (dev);
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci  /* do warming up if needed: just detected or at sane_open() */
1139141cc406Sopenharmony_ci  if (dev->needs_warming == SANE_TRUE)
1140141cc406Sopenharmony_ci    {
1141141cc406Sopenharmony_ci      DBG (DBG_info, "sane_start: warming lamp ...\n");
1142141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
1143141cc406Sopenharmony_ci      /* check if current time is >15s after warming-up start */
1144141cc406Sopenharmony_ci      gettimeofday (&current, NULL);
1145141cc406Sopenharmony_ci      if ((current.tv_sec - dev->start_time.tv_sec) < 15)
1146141cc406Sopenharmony_ci	{
1147141cc406Sopenharmony_ci#ifdef SANE_STATUS_WARMING_UP
1148141cc406Sopenharmony_ci	  if (dev->conf.allowsharing == SANE_TRUE)
1149141cc406Sopenharmony_ci	    {
1150141cc406Sopenharmony_ci	      sanei_usb_release_interface (dev->devnum, 0);
1151141cc406Sopenharmony_ci	    }
1152141cc406Sopenharmony_ci	  return SANE_STATUS_WARMING_UP;
1153141cc406Sopenharmony_ci#else
1154141cc406Sopenharmony_ci	  DBG (DBG_info,
1155141cc406Sopenharmony_ci	       "sane_start: waiting to let lamp get warm enough ...\n");
1156141cc406Sopenharmony_ci	  sleep (15 - (current.tv_sec - dev->start_time.tv_sec));
1157141cc406Sopenharmony_ci#endif
1158141cc406Sopenharmony_ci	}
1159141cc406Sopenharmony_ci#else
1160141cc406Sopenharmony_ci      DBG (DBG_info,
1161141cc406Sopenharmony_ci	   "sane_start: waiting 15s to let lamp get warm enough ...\n");
1162141cc406Sopenharmony_ci      sleep (15);
1163141cc406Sopenharmony_ci#endif
1164141cc406Sopenharmony_ci    }
1165141cc406Sopenharmony_ci  dev->needs_warming = SANE_FALSE;
1166141cc406Sopenharmony_ci
1167141cc406Sopenharmony_ci  /* restore default brightness */
1168141cc406Sopenharmony_ci  dev->regs[LAMP_BRIGHT_REG] = 0xA7;
1169141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_BRIGHT_REG,
1170141cc406Sopenharmony_ci			   dev->regs + LAMP_BRIGHT_REG);
1171141cc406Sopenharmony_ci  DBG (DBG_info, "sane_start: sensor initial type is %s (%d)\n",
1172141cc406Sopenharmony_ci       sensor_name (dev->sensor), dev->sensor);
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci  /* step 1: locate scan area by doing a scan, then goto calibration area */
1175141cc406Sopenharmony_ci  /* we also detect if the sensor type is inadequate and then change it   */
1176141cc406Sopenharmony_ci  do
1177141cc406Sopenharmony_ci    {
1178141cc406Sopenharmony_ci      changed = SANE_FALSE;
1179141cc406Sopenharmony_ci      status = find_origin (dev, &changed);
1180141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1181141cc406Sopenharmony_ci	{
1182141cc406Sopenharmony_ci	  if (dev->conf.allowsharing == SANE_TRUE)
1183141cc406Sopenharmony_ci	    {
1184141cc406Sopenharmony_ci	      sanei_usb_release_interface (dev->devnum, 0);
1185141cc406Sopenharmony_ci	    }
1186141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_start: failed to find origin!\n");
1187141cc406Sopenharmony_ci	  return status;
1188141cc406Sopenharmony_ci	}
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci      /* in case find_origin detected we need to change sensor */
1191141cc406Sopenharmony_ci      if (changed)
1192141cc406Sopenharmony_ci	{
1193141cc406Sopenharmony_ci	  /* for a sensor 'pair', we switch */
1194141cc406Sopenharmony_ci	  switch (dev->sensor)
1195141cc406Sopenharmony_ci	    {
1196141cc406Sopenharmony_ci	    case SENSOR_TYPE_BARE:
1197141cc406Sopenharmony_ci	      DBG (DBG_info,
1198141cc406Sopenharmony_ci		   "sane_start: sensor changed to type 'SENSOR_TYPE_XPA'!\n");
1199141cc406Sopenharmony_ci	      dev->sensor = SENSOR_TYPE_XPA;
1200141cc406Sopenharmony_ci	      break;
1201141cc406Sopenharmony_ci	    case SENSOR_TYPE_XPA:
1202141cc406Sopenharmony_ci	      DBG (DBG_info,
1203141cc406Sopenharmony_ci		   "sane_start: sensor changed to type 'SENSOR_TYPE_BARE'!\n");
1204141cc406Sopenharmony_ci	      dev->sensor = SENSOR_TYPE_BARE;
1205141cc406Sopenharmony_ci	      break;
1206141cc406Sopenharmony_ci	    case SENSOR_TYPE_4400:
1207141cc406Sopenharmony_ci	      DBG (DBG_info,
1208141cc406Sopenharmony_ci		   "sane_start: sensor changed to type '4400 SENSOR_TYPE_4400_BARE'!\n");
1209141cc406Sopenharmony_ci	      dev->sensor = SENSOR_TYPE_4400_BARE;
1210141cc406Sopenharmony_ci	      break;
1211141cc406Sopenharmony_ci	    case SENSOR_TYPE_4400_BARE:
1212141cc406Sopenharmony_ci	      DBG (DBG_info,
1213141cc406Sopenharmony_ci		   "sane_start: sensor changed to type 'SENSOR_TYPE_4400'!\n");
1214141cc406Sopenharmony_ci	      dev->sensor = SENSOR_TYPE_4400;
1215141cc406Sopenharmony_ci	      break;
1216141cc406Sopenharmony_ci	    }
1217141cc406Sopenharmony_ci	}
1218141cc406Sopenharmony_ci    }
1219141cc406Sopenharmony_ci  while (changed);
1220141cc406Sopenharmony_ci
1221141cc406Sopenharmony_ci  /* light source to use */
1222141cc406Sopenharmony_ci  switch (dev->sensor)
1223141cc406Sopenharmony_ci    {
1224141cc406Sopenharmony_ci    case SENSOR_TYPE_XPA:
1225141cc406Sopenharmony_ci      light = 0x3f;
1226141cc406Sopenharmony_ci      mode = 0x20;
1227141cc406Sopenharmony_ci      break;
1228141cc406Sopenharmony_ci    case SENSOR_TYPE_BARE:
1229141cc406Sopenharmony_ci      light = 0x3b;
1230141cc406Sopenharmony_ci      mode = 0x20;
1231141cc406Sopenharmony_ci      break;
1232141cc406Sopenharmony_ci    case SENSOR_TYPE_4400:
1233141cc406Sopenharmony_ci    case SENSOR_TYPE_4400_BARE:
1234141cc406Sopenharmony_ci      light = 0x2a;
1235141cc406Sopenharmony_ci      mode = 0x10;
1236141cc406Sopenharmony_ci      break;
1237141cc406Sopenharmony_ci    default:
1238141cc406Sopenharmony_ci      light = 0x3b;
1239141cc406Sopenharmony_ci      mode = 0x20;
1240141cc406Sopenharmony_ci      break;
1241141cc406Sopenharmony_ci    }
1242141cc406Sopenharmony_ci  DBG (DBG_info, "sane_start: sensor final type is %s (%d)\n",
1243141cc406Sopenharmony_ci       sensor_name (dev->sensor), dev->sensor);
1244141cc406Sopenharmony_ci  DBG (DBG_info, "sane_start: mode=0x%02x, light=0x%02x\n", mode, light);
1245141cc406Sopenharmony_ci
1246141cc406Sopenharmony_ci  /* step 2: dark calibration */
1247141cc406Sopenharmony_ci  status = dark_calibration (dev, mode, light);
1248141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1249141cc406Sopenharmony_ci    {
1250141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1251141cc406Sopenharmony_ci	{
1252141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1253141cc406Sopenharmony_ci	}
1254141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to do dark calibration!\n");
1255141cc406Sopenharmony_ci      return status;
1256141cc406Sopenharmony_ci    }
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci  /* step 3: find left margin */
1259141cc406Sopenharmony_ci  status = find_margin (dev);
1260141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1261141cc406Sopenharmony_ci    {
1262141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1263141cc406Sopenharmony_ci	{
1264141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1265141cc406Sopenharmony_ci	}
1266141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed find left margin!\n");
1267141cc406Sopenharmony_ci      return status;
1268141cc406Sopenharmony_ci    }
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  /* restore brightness */
1271141cc406Sopenharmony_ci  dev->regs[LAMP_BRIGHT_REG] = 0xA7;
1272141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_BRIGHT_REG,
1273141cc406Sopenharmony_ci			   dev->regs + LAMP_BRIGHT_REG);
1274141cc406Sopenharmony_ci
1275141cc406Sopenharmony_ci  /* step 4: gain calibration */
1276141cc406Sopenharmony_ci  status = gain_calibration (dev, mode, light);
1277141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1278141cc406Sopenharmony_ci    {
1279141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1280141cc406Sopenharmony_ci	{
1281141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1282141cc406Sopenharmony_ci	}
1283141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to do gain calibration!\n");
1284141cc406Sopenharmony_ci      return status;
1285141cc406Sopenharmony_ci    }
1286141cc406Sopenharmony_ci
1287141cc406Sopenharmony_ci  /* step 5: fine offset calibration */
1288141cc406Sopenharmony_ci  status = offset_calibration (dev, mode, light);
1289141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1290141cc406Sopenharmony_ci    {
1291141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1292141cc406Sopenharmony_ci	{
1293141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1294141cc406Sopenharmony_ci	}
1295141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to do offset calibration!\n");
1296141cc406Sopenharmony_ci      return status;
1297141cc406Sopenharmony_ci    }
1298141cc406Sopenharmony_ci
1299141cc406Sopenharmony_ci  /* we compute all the scan parameters so that */
1300141cc406Sopenharmony_ci  /* we will be able to set up the registers correctly */
1301141cc406Sopenharmony_ci  compute_parameters (session);
1302141cc406Sopenharmony_ci
1303141cc406Sopenharmony_ci  /* allocate buffer and compute start pointer */
1304141cc406Sopenharmony_ci  if (dev->scanned_data != NULL)
1305141cc406Sopenharmony_ci    free (dev->scanned_data);
1306141cc406Sopenharmony_ci  dev->scanned_data =
1307141cc406Sopenharmony_ci    (SANE_Byte *) malloc (dev->data_size + dev->lds_max + dev->ripple);
1308141cc406Sopenharmony_ci  dev->start = dev->scanned_data + dev->lds_max + dev->ripple;
1309141cc406Sopenharmony_ci
1310141cc406Sopenharmony_ci  /* computes data end pointer */
1311141cc406Sopenharmony_ci  dev->end = dev->start + dev->data_size;
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci  /* no bytes sent yet to frontend */
1314141cc406Sopenharmony_ci  session->sent = 0;
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (dev->regs, dev->red_offset, dev->green_offset,
1317141cc406Sopenharmony_ci			    dev->blue_offset);
1318141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, dev->red_gain, dev->green_gain,
1319141cc406Sopenharmony_ci			  dev->blue_gain);
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci  /* step 6: shading calibration */
1322141cc406Sopenharmony_ci  status =
1323141cc406Sopenharmony_ci    shading_calibration (dev, session->params.format == SANE_FRAME_RGB
1324141cc406Sopenharmony_ci			 || session->emulated_gray == SANE_TRUE, mode, light);
1325141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1326141cc406Sopenharmony_ci    {
1327141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1328141cc406Sopenharmony_ci	{
1329141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1330141cc406Sopenharmony_ci	}
1331141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to do shading calibration!\n");
1332141cc406Sopenharmony_ci      return status;
1333141cc406Sopenharmony_ci    }
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci  /* step 6b: move at dev->model->min_ydpi to target area */
1336141cc406Sopenharmony_ci  if (dev->ydpi > dev->model->min_ydpi
1337141cc406Sopenharmony_ci      && (dev->ystart * MOVE_DPI) / dev->ydpi > 150)
1338141cc406Sopenharmony_ci    {
1339141cc406Sopenharmony_ci      status = move_to_scan_area (session);
1340141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1341141cc406Sopenharmony_ci	{
1342141cc406Sopenharmony_ci	  if (dev->conf.allowsharing == SANE_TRUE)
1343141cc406Sopenharmony_ci	    {
1344141cc406Sopenharmony_ci	      sanei_usb_release_interface (dev->devnum, 0);
1345141cc406Sopenharmony_ci	    }
1346141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_start: failed to move to scan area!\n");
1347141cc406Sopenharmony_ci	  return status;
1348141cc406Sopenharmony_ci	}
1349141cc406Sopenharmony_ci    }
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci  /* step 7: effective scan start   */
1352141cc406Sopenharmony_ci  /* build register set and send it */
1353141cc406Sopenharmony_ci  status = write_scan_registers (session);
1354141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1355141cc406Sopenharmony_ci    {
1356141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1357141cc406Sopenharmony_ci	{
1358141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1359141cc406Sopenharmony_ci	}
1360141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to write scan registers!\n");
1361141cc406Sopenharmony_ci      return status;
1362141cc406Sopenharmony_ci    }
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci  /* step 8: send calibration data  */
1365141cc406Sopenharmony_ci  status = send_calibration_data (session);
1366141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1367141cc406Sopenharmony_ci    {
1368141cc406Sopenharmony_ci      if (dev->conf.allowsharing == SANE_TRUE)
1369141cc406Sopenharmony_ci	{
1370141cc406Sopenharmony_ci	  sanei_usb_release_interface (dev->devnum, 0);
1371141cc406Sopenharmony_ci	}
1372141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to send calibration data!\n");
1373141cc406Sopenharmony_ci      return status;
1374141cc406Sopenharmony_ci    }
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_ci  /* commit the scan */
1377141cc406Sopenharmony_ci  /* TODO send_calibration seems to embbed its commit */
1378141cc406Sopenharmony_ci  sanei_rts88xx_cancel (dev->devnum);
1379141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x08);
1380141cc406Sopenharmony_ci  status = sanei_rts88xx_write_control (dev->devnum, 0x08);
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci  session->scanning = SANE_TRUE;
1383141cc406Sopenharmony_ci
1384141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
1385141cc406Sopenharmony_ci  return status;
1386141cc406Sopenharmony_ci}
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci/**
1389141cc406Sopenharmony_ci * This function computes two set of parameters. The one for the SANE's standard
1390141cc406Sopenharmony_ci * and the other for the hardware. Among these parameters are the bit depth, total
1391141cc406Sopenharmony_ci * number of lines, total number of columns, extra line to read for data reordering...
1392141cc406Sopenharmony_ci */
1393141cc406Sopenharmony_cistatic SANE_Status
1394141cc406Sopenharmony_cicompute_parameters (Rts8891_Session * session)
1395141cc406Sopenharmony_ci{
1396141cc406Sopenharmony_ci  Rts8891_Device *dev = session->dev;
1397141cc406Sopenharmony_ci  SANE_Int dpi;			/* dpi for scan */
1398141cc406Sopenharmony_ci  SANE_String mode;
1399141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
1400141cc406Sopenharmony_ci  SANE_Int yshift;
1401141cc406Sopenharmony_ci  SANE_Int xshift;
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci  int tl_x, tl_y, br_x, br_y;
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci  mode = session->val[OPT_MODE].s;
1406141cc406Sopenharmony_ci  dpi = session->val[OPT_RESOLUTION].w;
1407141cc406Sopenharmony_ci
1408141cc406Sopenharmony_ci  /* scan coordinates */
1409141cc406Sopenharmony_ci  tl_x = SANE_UNFIX (session->val[OPT_TL_X].w);
1410141cc406Sopenharmony_ci  tl_y = SANE_UNFIX (session->val[OPT_TL_Y].w);
1411141cc406Sopenharmony_ci  br_x = SANE_UNFIX (session->val[OPT_BR_X].w);
1412141cc406Sopenharmony_ci  br_y = SANE_UNFIX (session->val[OPT_BR_Y].w);
1413141cc406Sopenharmony_ci
1414141cc406Sopenharmony_ci  /* only single pass scanning supported */
1415141cc406Sopenharmony_ci  session->params.last_frame = SANE_TRUE;
1416141cc406Sopenharmony_ci  session->emulated_gray = SANE_FALSE;
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci  /* gray modes */
1419141cc406Sopenharmony_ci  dev->threshold = (255 * SANE_UNFIX (session->val[OPT_THRESHOLD].w)) / 100;
1420141cc406Sopenharmony_ci  if (strcmp (mode, GRAY_MODE) == 0 || strcmp (mode, LINEART_MODE) == 0)
1421141cc406Sopenharmony_ci    {
1422141cc406Sopenharmony_ci      session->params.format = SANE_FRAME_GRAY;
1423141cc406Sopenharmony_ci      if (dev->model->flags & RTS8891_FLAG_EMULATED_GRAY_MODE)
1424141cc406Sopenharmony_ci	session->emulated_gray = SANE_TRUE;
1425141cc406Sopenharmony_ci    }
1426141cc406Sopenharmony_ci  else
1427141cc406Sopenharmony_ci    {
1428141cc406Sopenharmony_ci      /* Color */
1429141cc406Sopenharmony_ci      session->params.format = SANE_FRAME_RGB;
1430141cc406Sopenharmony_ci    }
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci  /* SANE level values */
1433141cc406Sopenharmony_ci  session->params.lines = ((br_y - tl_y) * dpi) / MM_PER_INCH;
1434141cc406Sopenharmony_ci  if (session->params.lines == 0)
1435141cc406Sopenharmony_ci    session->params.lines = 1;
1436141cc406Sopenharmony_ci  session->params.pixels_per_line = ((br_x - tl_x) * dpi) / MM_PER_INCH;
1437141cc406Sopenharmony_ci  if (session->params.pixels_per_line == 0)
1438141cc406Sopenharmony_ci    session->params.pixels_per_line = 1;
1439141cc406Sopenharmony_ci
1440141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: pixels_per_line   =%d\n",
1441141cc406Sopenharmony_ci       session->params.pixels_per_line);
1442141cc406Sopenharmony_ci
1443141cc406Sopenharmony_ci  if (strcmp (mode, LINEART_MODE) == 0)
1444141cc406Sopenharmony_ci    {
1445141cc406Sopenharmony_ci      session->params.depth = 1;
1446141cc406Sopenharmony_ci      /* in lineart, having pixels multiple of 8 avoids a costly test */
1447141cc406Sopenharmony_ci      /* at each bit to see we must go to the next byte               */
1448141cc406Sopenharmony_ci      /* TODO : implement this requirement in sane_control_option */
1449141cc406Sopenharmony_ci      session->params.pixels_per_line =
1450141cc406Sopenharmony_ci	((session->params.pixels_per_line + 7) / 8) * 8;
1451141cc406Sopenharmony_ci    }
1452141cc406Sopenharmony_ci  else
1453141cc406Sopenharmony_ci    session->params.depth = 8;
1454141cc406Sopenharmony_ci
1455141cc406Sopenharmony_ci  /* width needs to be even */
1456141cc406Sopenharmony_ci  if (session->params.pixels_per_line & 1)
1457141cc406Sopenharmony_ci    session->params.pixels_per_line++;
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci  /* Hardware settings : they can differ from the ones at SANE level */
1460141cc406Sopenharmony_ci  /* for instance the effective DPI used by a sensor may be higher   */
1461141cc406Sopenharmony_ci  /* than the one needed for the SANE scan parameters                */
1462141cc406Sopenharmony_ci  dev->lines = session->params.lines;
1463141cc406Sopenharmony_ci  dev->pixels = session->params.pixels_per_line;
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  /* motor and sensor DPI */
1466141cc406Sopenharmony_ci  dev->xdpi = dpi;
1467141cc406Sopenharmony_ci  dev->ydpi = dpi;
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci  /* handle bounds of motor's dpi range */
1470141cc406Sopenharmony_ci  if (dev->ydpi > dev->model->max_ydpi)
1471141cc406Sopenharmony_ci    {
1472141cc406Sopenharmony_ci      dev->ydpi = dev->model->max_ydpi;
1473141cc406Sopenharmony_ci      dev->lines = (dev->lines * dev->model->max_ydpi) / dpi;
1474141cc406Sopenharmony_ci      if (dev->lines == 0)
1475141cc406Sopenharmony_ci	dev->lines = 1;
1476141cc406Sopenharmony_ci
1477141cc406Sopenharmony_ci      /* round number of lines */
1478141cc406Sopenharmony_ci      session->params.lines =
1479141cc406Sopenharmony_ci	(session->params.lines / dev->lines) * dev->lines;
1480141cc406Sopenharmony_ci      if (session->params.lines == 0)
1481141cc406Sopenharmony_ci	session->params.lines = 1;
1482141cc406Sopenharmony_ci    }
1483141cc406Sopenharmony_ci  if (dev->ydpi < dev->model->min_ydpi)
1484141cc406Sopenharmony_ci    {
1485141cc406Sopenharmony_ci      dev->ydpi = dev->model->min_ydpi;
1486141cc406Sopenharmony_ci      dev->lines = (dev->lines * dev->model->min_ydpi) / dpi;
1487141cc406Sopenharmony_ci    }
1488141cc406Sopenharmony_ci
1489141cc406Sopenharmony_ci  /* hardware values */
1490141cc406Sopenharmony_ci  dev->xstart =
1491141cc406Sopenharmony_ci    ((SANE_UNFIX (dev->model->x_offset) + tl_x) * dev->xdpi) / MM_PER_INCH;
1492141cc406Sopenharmony_ci  dev->ystart =
1493141cc406Sopenharmony_ci    ((SANE_UNFIX (dev->model->y_offset) + tl_y) * dev->ydpi) / MM_PER_INCH;
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  /* xstart needs to be even */
1496141cc406Sopenharmony_ci  if (dev->xstart & 1)
1497141cc406Sopenharmony_ci    dev->xstart++;
1498141cc406Sopenharmony_ci
1499141cc406Sopenharmony_ci  /* computes bytes per line */
1500141cc406Sopenharmony_ci  session->params.bytes_per_line = session->params.pixels_per_line;
1501141cc406Sopenharmony_ci  dev->bytes_per_line = dev->pixels;
1502141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_RGB
1503141cc406Sopenharmony_ci      || session->emulated_gray == SANE_TRUE)
1504141cc406Sopenharmony_ci    {
1505141cc406Sopenharmony_ci      if (session->emulated_gray != SANE_TRUE)
1506141cc406Sopenharmony_ci	{
1507141cc406Sopenharmony_ci	  session->params.bytes_per_line *= 3;
1508141cc406Sopenharmony_ci	}
1509141cc406Sopenharmony_ci      dev->bytes_per_line *= 3;
1510141cc406Sopenharmony_ci    }
1511141cc406Sopenharmony_ci  session->to_send = session->params.bytes_per_line * session->params.lines;
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci  /* in lineart mode we adjust bytes_per_line needed by frontend */
1514141cc406Sopenharmony_ci  /* we do that here because we needed sent/to_send to be as if  */
1515141cc406Sopenharmony_ci  /* there was no lineart                                        */
1516141cc406Sopenharmony_ci  if (session->params.depth == 1)
1517141cc406Sopenharmony_ci    {
1518141cc406Sopenharmony_ci      session->params.bytes_per_line =
1519141cc406Sopenharmony_ci	(session->params.bytes_per_line + 7) / 8;
1520141cc406Sopenharmony_ci    }
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci  /* compute how many extra bytes we need to reorder data */
1523141cc406Sopenharmony_ci  dev->ripple = 0;
1524141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_RGB
1525141cc406Sopenharmony_ci      || session->emulated_gray == SANE_TRUE)
1526141cc406Sopenharmony_ci    {
1527141cc406Sopenharmony_ci      dev->lds_r
1528141cc406Sopenharmony_ci	= ((dev->model->ld_shift_r * dev->ydpi) / dev->model->max_ydpi)
1529141cc406Sopenharmony_ci	* dev->bytes_per_line;
1530141cc406Sopenharmony_ci      dev->lds_g
1531141cc406Sopenharmony_ci	= ((dev->model->ld_shift_g * dev->ydpi) / dev->model->max_ydpi)
1532141cc406Sopenharmony_ci	* dev->bytes_per_line;
1533141cc406Sopenharmony_ci      dev->lds_b
1534141cc406Sopenharmony_ci	= ((dev->model->ld_shift_b * dev->ydpi) / dev->model->max_ydpi)
1535141cc406Sopenharmony_ci	* dev->bytes_per_line;
1536141cc406Sopenharmony_ci      if (dev->xdpi == dev->model->max_xdpi)
1537141cc406Sopenharmony_ci	{
1538141cc406Sopenharmony_ci	  dev->ripple = 2 * dev->bytes_per_line;
1539141cc406Sopenharmony_ci	}
1540141cc406Sopenharmony_ci    }
1541141cc406Sopenharmony_ci  else
1542141cc406Sopenharmony_ci    {
1543141cc406Sopenharmony_ci      dev->lds_r = 0;
1544141cc406Sopenharmony_ci      dev->lds_g = 0;
1545141cc406Sopenharmony_ci      dev->lds_b = 0;
1546141cc406Sopenharmony_ci    }
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci  /* pick max lds value */
1549141cc406Sopenharmony_ci  dev->lds_max = dev->lds_r;
1550141cc406Sopenharmony_ci  if (dev->lds_g > dev->lds_max)
1551141cc406Sopenharmony_ci    dev->lds_max = dev->lds_g;
1552141cc406Sopenharmony_ci  if (dev->lds_b > dev->lds_max)
1553141cc406Sopenharmony_ci    dev->lds_max = dev->lds_b;
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  /* since the extra lines for reordering are before data */
1556141cc406Sopenharmony_ci  /* we subtract lds_max */
1557141cc406Sopenharmony_ci  dev->lds_r -= dev->lds_max;
1558141cc406Sopenharmony_ci  dev->lds_g -= dev->lds_max;
1559141cc406Sopenharmony_ci  dev->lds_b -= dev->lds_max;
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci  /* we need to add extra line to handle line distance reordering  */
1562141cc406Sopenharmony_ci  /* highest correction value is the blue one for our case         */
1563141cc406Sopenharmony_ci  /* decrease y start to take these extra lines into account       */
1564141cc406Sopenharmony_ci  dev->lines += (dev->lds_max + dev->ripple) / dev->bytes_per_line;
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci  /* shading calibration is always 66 lines regardless of ydpi, so */
1567141cc406Sopenharmony_ci  /* we take this into account to compute ystart                    */
1568141cc406Sopenharmony_ci  if (dev->ydpi > dev->model->min_ydpi)
1569141cc406Sopenharmony_ci    {
1570141cc406Sopenharmony_ci      /* no that clean, but works ... */
1571141cc406Sopenharmony_ci      switch (dev->ydpi)
1572141cc406Sopenharmony_ci	{
1573141cc406Sopenharmony_ci	case 300:
1574141cc406Sopenharmony_ci	  yshift = 0;
1575141cc406Sopenharmony_ci	  break;
1576141cc406Sopenharmony_ci	case 600:
1577141cc406Sopenharmony_ci	  yshift = 33;
1578141cc406Sopenharmony_ci	  break;
1579141cc406Sopenharmony_ci	default:
1580141cc406Sopenharmony_ci	  yshift = 0;
1581141cc406Sopenharmony_ci	}
1582141cc406Sopenharmony_ci      dev->ystart += yshift;
1583141cc406Sopenharmony_ci    }
1584141cc406Sopenharmony_ci  dev->ystart -= (dev->lds_max + dev->ripple) / dev->bytes_per_line;
1585141cc406Sopenharmony_ci
1586141cc406Sopenharmony_ci  /* 1200 and 600 dpi scans seems to have other timings that
1587141cc406Sopenharmony_ci   * need their own xstart */
1588141cc406Sopenharmony_ci  /* no that clean, but works ... */
1589141cc406Sopenharmony_ci  switch (dev->xdpi)
1590141cc406Sopenharmony_ci    {
1591141cc406Sopenharmony_ci    case 600:
1592141cc406Sopenharmony_ci      xshift = -38;
1593141cc406Sopenharmony_ci      break;
1594141cc406Sopenharmony_ci    case 1200:
1595141cc406Sopenharmony_ci      xshift = -76;
1596141cc406Sopenharmony_ci      break;
1597141cc406Sopenharmony_ci    default:
1598141cc406Sopenharmony_ci      xshift = 0;
1599141cc406Sopenharmony_ci    }
1600141cc406Sopenharmony_ci  dev->xstart += xshift;
1601141cc406Sopenharmony_ci
1602141cc406Sopenharmony_ci  dev->read = 0;
1603141cc406Sopenharmony_ci  dev->to_read = dev->lines * dev->bytes_per_line;
1604141cc406Sopenharmony_ci
1605141cc406Sopenharmony_ci  /* compute best size for scanned data buffer  */
1606141cc406Sopenharmony_ci  /* we must have a round number of lines, with */
1607141cc406Sopenharmony_ci  /* enough space to handle line distance shift */
1608141cc406Sopenharmony_ci  if (dev->xdpi < dev->model->max_ydpi)
1609141cc406Sopenharmony_ci    {
1610141cc406Sopenharmony_ci      dev->data_size =
1611141cc406Sopenharmony_ci	(PREFERED_BUFFER_SIZE / dev->bytes_per_line) * (dev->bytes_per_line);
1612141cc406Sopenharmony_ci    }
1613141cc406Sopenharmony_ci  else
1614141cc406Sopenharmony_ci    {
1615141cc406Sopenharmony_ci      dev->data_size =
1616141cc406Sopenharmony_ci	(((PREFERED_BUFFER_SIZE / 2) - dev->lds_max -
1617141cc406Sopenharmony_ci	  dev->ripple) / dev->bytes_per_line) * dev->bytes_per_line;
1618141cc406Sopenharmony_ci    }
1619141cc406Sopenharmony_ci
1620141cc406Sopenharmony_ci  /* 32 lines minimum in buffer */
1621141cc406Sopenharmony_ci  if (dev->data_size < 32 * dev->bytes_per_line)
1622141cc406Sopenharmony_ci    dev->data_size = 32 * dev->bytes_per_line;
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_ci  /* buffer must be smaller than total amount to read from session */
1625141cc406Sopenharmony_ci  if (dev->data_size > dev->to_read)
1626141cc406Sopenharmony_ci    dev->data_size = dev->to_read;
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: bytes_per_line    =%d\n",
1629141cc406Sopenharmony_ci       session->params.bytes_per_line);
1630141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: depth             =%d\n",
1631141cc406Sopenharmony_ci       session->params.depth);
1632141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: lines             =%d\n",
1633141cc406Sopenharmony_ci       session->params.lines);
1634141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: pixels_per_line   =%d\n",
1635141cc406Sopenharmony_ci       session->params.pixels_per_line);
1636141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: image size        =%d\n",
1637141cc406Sopenharmony_ci       session->to_send);
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: xstart            =%d\n", dev->xstart);
1640141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: ystart            =%d\n", dev->ystart);
1641141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev lines         =%d\n", dev->lines);
1642141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev extra lines   =%d\n",
1643141cc406Sopenharmony_ci       (dev->lds_max + dev->ripple) / dev->bytes_per_line);
1644141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev bytes per line=%d\n",
1645141cc406Sopenharmony_ci       dev->bytes_per_line);
1646141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev pixels        =%d\n", dev->pixels);
1647141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: data size         =%d\n",
1648141cc406Sopenharmony_ci       dev->data_size);
1649141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: to read           =%d\n", dev->to_read);
1650141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: threshold         =%d\n",
1651141cc406Sopenharmony_ci       dev->threshold);
1652141cc406Sopenharmony_ci
1653141cc406Sopenharmony_ci  return status;
1654141cc406Sopenharmony_ci}
1655141cc406Sopenharmony_ci
1656141cc406Sopenharmony_ci
1657141cc406Sopenharmony_ci/**
1658141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data
1659141cc406Sopenharmony_ci * that the current scan will return.
1660141cc406Sopenharmony_ci *
1661141cc406Sopenharmony_ci * From the SANE spec:
1662141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The
1663141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time
1664141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the
1665141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned
1666141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be
1667141cc406Sopenharmony_ci * when sane_start() gets invoked.
1668141cc406Sopenharmony_ci *
1669141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows,
1670141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will
1671141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle of the
1672141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer
1673141cc406Sopenharmony_ci * to a parameter structure.
1674141cc406Sopenharmony_ci */
1675141cc406Sopenharmony_ciSANE_Status
1676141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1677141cc406Sopenharmony_ci{
1678141cc406Sopenharmony_ci  SANE_Status status;
1679141cc406Sopenharmony_ci  struct Rts8891_Session *session = (struct Rts8891_Session *) handle;
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: start\n");
1682141cc406Sopenharmony_ci
1683141cc406Sopenharmony_ci  /* call parameters computing function */
1684141cc406Sopenharmony_ci  status = compute_parameters (session);
1685141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD && params)
1686141cc406Sopenharmony_ci    *params = session->params;
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
1689141cc406Sopenharmony_ci  return status;
1690141cc406Sopenharmony_ci}
1691141cc406Sopenharmony_ci
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci/**
1694141cc406Sopenharmony_ci * Called by SANE to read data.
1695141cc406Sopenharmony_ci *
1696141cc406Sopenharmony_ci * From the SANE spec:
1697141cc406Sopenharmony_ci * This function is used to read image data from the device
1698141cc406Sopenharmony_ci * represented by handle h.  Argument buf is a pointer to a memory
1699141cc406Sopenharmony_ci * area that is at least maxlen bytes long.  The number of bytes
1700141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when
1701141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is
1702141cc406Sopenharmony_ci * returned).
1703141cc406Sopenharmony_ci *
1704141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be
1705141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes.
1706141cc406Sopenharmony_ci */
1707141cc406Sopenharmony_ciSANE_Status
1708141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
1709141cc406Sopenharmony_ci	   SANE_Int max_len, SANE_Int * len)
1710141cc406Sopenharmony_ci{
1711141cc406Sopenharmony_ci  struct Rts8891_Session *session;
1712141cc406Sopenharmony_ci  struct Rts8891_Device *dev;
1713141cc406Sopenharmony_ci  SANE_Status status;
1714141cc406Sopenharmony_ci  SANE_Int length;
1715141cc406Sopenharmony_ci  SANE_Int data_size;
1716141cc406Sopenharmony_ci  SANE_Byte val = 0;
1717141cc406Sopenharmony_ci  SANE_Int bit;
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: start\n");
1720141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: up to %d bytes required by frontend\n", max_len);
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci  /* some sanity checks first to protect from would be buggy frontends */
1723141cc406Sopenharmony_ci  if (!handle)
1724141cc406Sopenharmony_ci    {
1725141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: handle is null!\n");
1726141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1727141cc406Sopenharmony_ci    }
1728141cc406Sopenharmony_ci
1729141cc406Sopenharmony_ci  session = (struct Rts8891_Session *) handle;
1730141cc406Sopenharmony_ci  if (!session)
1731141cc406Sopenharmony_ci    {
1732141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: session is null!\n");
1733141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1734141cc406Sopenharmony_ci    }
1735141cc406Sopenharmony_ci  dev = session->dev;
1736141cc406Sopenharmony_ci
1737141cc406Sopenharmony_ci  if (!buf)
1738141cc406Sopenharmony_ci    {
1739141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: buf is null!\n");
1740141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1741141cc406Sopenharmony_ci    }
1742141cc406Sopenharmony_ci
1743141cc406Sopenharmony_ci  if (!len)
1744141cc406Sopenharmony_ci    {
1745141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: len is null!\n");
1746141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1747141cc406Sopenharmony_ci    }
1748141cc406Sopenharmony_ci
1749141cc406Sopenharmony_ci  /* no data read yet */
1750141cc406Sopenharmony_ci  *len = 0;
1751141cc406Sopenharmony_ci  buf[*len] = 0;
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_ci  /* check if session is scanning */
1754141cc406Sopenharmony_ci  if (!session->scanning)
1755141cc406Sopenharmony_ci    {
1756141cc406Sopenharmony_ci      DBG (DBG_warn,
1757141cc406Sopenharmony_ci	   "sane_read: scan was cancelled, is over or has not been initiated yet\n");
1758141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
1759141cc406Sopenharmony_ci    }
1760141cc406Sopenharmony_ci
1761141cc406Sopenharmony_ci  /* check for EOF, must be done before any physical read */
1762141cc406Sopenharmony_ci  if (session->sent >= session->to_send)
1763141cc406Sopenharmony_ci    {
1764141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: end of scan reached\n");
1765141cc406Sopenharmony_ci
1766141cc406Sopenharmony_ci      /* signal end of scanning */
1767141cc406Sopenharmony_ci      session->scanning=SANE_FALSE;
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci      /* send asynchronous head parking command then return */
1770141cc406Sopenharmony_ci      park_head (session->dev, SANE_FALSE);
1771141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1772141cc406Sopenharmony_ci    }
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = 0xad;
1775141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &(dev->regs[LAMP_REG]));
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci  /* byte length for high dpi mode */
1778141cc406Sopenharmony_ci  length = (session->params.bytes_per_line * 8) / session->params.depth;
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci  /* checks if buffer has been pre filled with the extra data needed for */
1781141cc406Sopenharmony_ci  /* line distance reordering                                            */
1782141cc406Sopenharmony_ci  if (dev->read == 0
1783141cc406Sopenharmony_ci      && (session->params.format == SANE_FRAME_RGB
1784141cc406Sopenharmony_ci	  || session->emulated_gray == SANE_TRUE))
1785141cc406Sopenharmony_ci    {
1786141cc406Sopenharmony_ci      /* the data need if the size of the highest line distance shift */
1787141cc406Sopenharmony_ci      /* we must only read what's needed */
1788141cc406Sopenharmony_ci      data_size = dev->data_size + dev->lds_max + dev->ripple;
1789141cc406Sopenharmony_ci      if (dev->to_read - dev->read < data_size)
1790141cc406Sopenharmony_ci	data_size = dev->to_read - dev->read;
1791141cc406Sopenharmony_ci
1792141cc406Sopenharmony_ci      status = read_data (session, dev->scanned_data, data_size);
1793141cc406Sopenharmony_ci      if (status == SANE_STATUS_DEVICE_BUSY)
1794141cc406Sopenharmony_ci	{
1795141cc406Sopenharmony_ci	  DBG (DBG_io, "sane_read: no data currently available\n");
1796141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1797141cc406Sopenharmony_ci	}
1798141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1799141cc406Sopenharmony_ci	{
1800141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_read: failed to read data from scanner\n");
1801141cc406Sopenharmony_ci	  return status;
1802141cc406Sopenharmony_ci	}
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci      /* now buffer is filled with data and an extra amount for line reordering */
1805141cc406Sopenharmony_ci      dev->current = dev->start;
1806141cc406Sopenharmony_ci    }
1807141cc406Sopenharmony_ci
1808141cc406Sopenharmony_ci  /* if all buffer has been used, get the next block of data from scanner */
1809141cc406Sopenharmony_ci  if (dev->read == 0 || dev->current >= dev->end)
1810141cc406Sopenharmony_ci    {
1811141cc406Sopenharmony_ci      /* effective buffer filling */
1812141cc406Sopenharmony_ci      /* we must only read what's needed */
1813141cc406Sopenharmony_ci      data_size = dev->data_size;
1814141cc406Sopenharmony_ci      if (dev->to_read - dev->read < data_size)
1815141cc406Sopenharmony_ci	data_size = dev->to_read - dev->read;
1816141cc406Sopenharmony_ci
1817141cc406Sopenharmony_ci      status = read_data (session, dev->start, data_size);
1818141cc406Sopenharmony_ci      if (status == SANE_STATUS_DEVICE_BUSY)
1819141cc406Sopenharmony_ci	{
1820141cc406Sopenharmony_ci	  DBG (DBG_io, "sane_read: no data currently available\n");
1821141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1822141cc406Sopenharmony_ci	}
1823141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1824141cc406Sopenharmony_ci	{
1825141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_read: failed to read data from scanner\n");
1826141cc406Sopenharmony_ci	  return status;
1827141cc406Sopenharmony_ci	}
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci      /* reset current pointer */
1830141cc406Sopenharmony_ci      dev->current = dev->start;
1831141cc406Sopenharmony_ci    }
1832141cc406Sopenharmony_ci
1833141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = 0x8d;
1834141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &(dev->regs[LAMP_REG]));
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  /* it seems there is no gray or lineart hardware mode for the rts8891 */
1837141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_GRAY
1838141cc406Sopenharmony_ci      && session->emulated_gray == SANE_FALSE)
1839141cc406Sopenharmony_ci    {
1840141cc406Sopenharmony_ci      DBG (DBG_error0, "sane_read: unimplemented native gray scanning\n");
1841141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1842141cc406Sopenharmony_ci    }
1843141cc406Sopenharmony_ci  else				/* hardware data is 3 bytes/per pixels */
1844141cc406Sopenharmony_ci    {
1845141cc406Sopenharmony_ci      /* we return as much data as possible from current buffer  */
1846141cc406Sopenharmony_ci      /* if buffer is smaller than what is asked, we only return */
1847141cc406Sopenharmony_ci
1848141cc406Sopenharmony_ci      /* here we have made sure there is something to read from data buffers */
1849141cc406Sopenharmony_ci      /* data from scanner is in R,G,B format, but we have to cope with line */
1850141cc406Sopenharmony_ci      /* distance correction. We also take care that motor resolution may be */
1851141cc406Sopenharmony_ci      /* higher than the scan resolution asked for some modes.               */
1852141cc406Sopenharmony_ci      /* We also handle emulated color mode                                  */
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci      /* we loop until we reach max_len or end of data buffer  */
1855141cc406Sopenharmony_ci      /* or we sent what we advised to frontend                */
1856141cc406Sopenharmony_ci      while (dev->current < dev->end && *len < max_len
1857141cc406Sopenharmony_ci	     && session->sent < session->to_send)
1858141cc406Sopenharmony_ci	{
1859141cc406Sopenharmony_ci	  /* data is received in RGB format */
1860141cc406Sopenharmony_ci	  /* these switches are there to handle reads not aligned
1861141cc406Sopenharmony_ci	   * on pixels that are allowed by the SANE standard */
1862141cc406Sopenharmony_ci	  if (dev->xdpi == dev->model->max_xdpi)
1863141cc406Sopenharmony_ci	    {			/* at max xdpi, data received is distorted and ydpi is half of xdpi */
1864141cc406Sopenharmony_ci	      if (session->emulated_gray == SANE_TRUE)
1865141cc406Sopenharmony_ci		{
1866141cc406Sopenharmony_ci		  /* in emulated gray mode we are always reading 3 bytes of raw data */
1867141cc406Sopenharmony_ci		  /* at a time                                                        */
1868141cc406Sopenharmony_ci		  switch (((session->sent * 3) % dev->bytes_per_line) % 6)
1869141cc406Sopenharmony_ci		    {
1870141cc406Sopenharmony_ci		    case 0:
1871141cc406Sopenharmony_ci		    case 1:
1872141cc406Sopenharmony_ci		    case 2:
1873141cc406Sopenharmony_ci		      val = dev->current[dev->lds_g];
1874141cc406Sopenharmony_ci		      break;
1875141cc406Sopenharmony_ci		    case 3:
1876141cc406Sopenharmony_ci		    case 4:
1877141cc406Sopenharmony_ci		    case 5:
1878141cc406Sopenharmony_ci		      val = dev->current[dev->lds_g - dev->ripple];
1879141cc406Sopenharmony_ci		      break;
1880141cc406Sopenharmony_ci		    }
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_ci		  if (session->params.depth == 1)
1883141cc406Sopenharmony_ci		    {
1884141cc406Sopenharmony_ci		      bit = 7 - (session->sent) % 8;
1885141cc406Sopenharmony_ci		      if (val <= dev->threshold)
1886141cc406Sopenharmony_ci			{
1887141cc406Sopenharmony_ci			  buf[*len] |= 1 << bit;
1888141cc406Sopenharmony_ci			}
1889141cc406Sopenharmony_ci		      if (bit == 0)
1890141cc406Sopenharmony_ci			{
1891141cc406Sopenharmony_ci			  (*len)++;
1892141cc406Sopenharmony_ci			  buf[*len] = 0;
1893141cc406Sopenharmony_ci			}
1894141cc406Sopenharmony_ci		    }
1895141cc406Sopenharmony_ci		  else
1896141cc406Sopenharmony_ci		    {
1897141cc406Sopenharmony_ci		      buf[*len] = val;
1898141cc406Sopenharmony_ci		      (*len)++;
1899141cc406Sopenharmony_ci		    }
1900141cc406Sopenharmony_ci		  session->sent++;
1901141cc406Sopenharmony_ci		  dev->current += 3;
1902141cc406Sopenharmony_ci		}
1903141cc406Sopenharmony_ci	      else
1904141cc406Sopenharmony_ci		{
1905141cc406Sopenharmony_ci		  switch ((session->sent % dev->bytes_per_line) % 6)
1906141cc406Sopenharmony_ci		    {
1907141cc406Sopenharmony_ci		    case 0:
1908141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_r];
1909141cc406Sopenharmony_ci		      break;
1910141cc406Sopenharmony_ci		    case 1:
1911141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_g];
1912141cc406Sopenharmony_ci		      break;
1913141cc406Sopenharmony_ci		    case 2:
1914141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_b];
1915141cc406Sopenharmony_ci		      break;
1916141cc406Sopenharmony_ci		    case 3:
1917141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_r - dev->ripple];
1918141cc406Sopenharmony_ci		      break;
1919141cc406Sopenharmony_ci		    case 4:
1920141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_g - dev->ripple];
1921141cc406Sopenharmony_ci		      break;
1922141cc406Sopenharmony_ci		    case 5:
1923141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_b - dev->ripple];
1924141cc406Sopenharmony_ci		      break;
1925141cc406Sopenharmony_ci		    }
1926141cc406Sopenharmony_ci		  (*len)++;
1927141cc406Sopenharmony_ci		  session->sent++;
1928141cc406Sopenharmony_ci		  dev->current++;
1929141cc406Sopenharmony_ci		}
1930141cc406Sopenharmony_ci
1931141cc406Sopenharmony_ci	      /* we currently double lines to have match xdpy */
1932141cc406Sopenharmony_ci	      /* so we logically rewind for each odd line     */
1933141cc406Sopenharmony_ci	      /* we test at start of a scanned picture line   */
1934141cc406Sopenharmony_ci	      if (((session->sent / length) % 2 == 1)
1935141cc406Sopenharmony_ci		  && (session->sent % length == 0))
1936141cc406Sopenharmony_ci		{
1937141cc406Sopenharmony_ci		  DBG (DBG_io,
1938141cc406Sopenharmony_ci		       "sane_read: rewind by %d bytes after %d bytes sent\n",
1939141cc406Sopenharmony_ci		       dev->bytes_per_line, session->sent);
1940141cc406Sopenharmony_ci		  dev->current -= dev->bytes_per_line;
1941141cc406Sopenharmony_ci		}
1942141cc406Sopenharmony_ci	    }
1943141cc406Sopenharmony_ci	  else if (dev->ydpi == session->val[OPT_RESOLUTION].w)
1944141cc406Sopenharmony_ci	    {
1945141cc406Sopenharmony_ci	      if (session->emulated_gray == SANE_TRUE)
1946141cc406Sopenharmony_ci		{
1947141cc406Sopenharmony_ci		  /* in emulated gray mode we are always reading 3 bytes of raw data */
1948141cc406Sopenharmony_ci		  /* at a time, so we know where we are                               */
1949141cc406Sopenharmony_ci		  val = dev->current[dev->lds_g];
1950141cc406Sopenharmony_ci		  if (session->params.depth == 1)
1951141cc406Sopenharmony_ci		    {
1952141cc406Sopenharmony_ci		      bit = 7 - (session->sent) % 8;
1953141cc406Sopenharmony_ci		      if (val <= dev->threshold)
1954141cc406Sopenharmony_ci			{
1955141cc406Sopenharmony_ci			  buf[*len] |= 1 << bit;
1956141cc406Sopenharmony_ci			}
1957141cc406Sopenharmony_ci		      else
1958141cc406Sopenharmony_ci			{
1959141cc406Sopenharmony_ci			  buf[*len] &= ~(1 << bit);
1960141cc406Sopenharmony_ci			}
1961141cc406Sopenharmony_ci		      if (bit == 0)
1962141cc406Sopenharmony_ci			{
1963141cc406Sopenharmony_ci			  (*len)++;
1964141cc406Sopenharmony_ci			}
1965141cc406Sopenharmony_ci		    }
1966141cc406Sopenharmony_ci		  else
1967141cc406Sopenharmony_ci		    {
1968141cc406Sopenharmony_ci		      buf[*len] = val;
1969141cc406Sopenharmony_ci		      (*len)++;
1970141cc406Sopenharmony_ci		    }
1971141cc406Sopenharmony_ci		  session->sent++;
1972141cc406Sopenharmony_ci		  dev->current += 3;
1973141cc406Sopenharmony_ci		}
1974141cc406Sopenharmony_ci	      else
1975141cc406Sopenharmony_ci		{
1976141cc406Sopenharmony_ci		  switch ((dev->current - dev->start) % 3)
1977141cc406Sopenharmony_ci		    {
1978141cc406Sopenharmony_ci		    case 0:
1979141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_r];
1980141cc406Sopenharmony_ci		      break;
1981141cc406Sopenharmony_ci		    case 1:
1982141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_g];
1983141cc406Sopenharmony_ci		      break;
1984141cc406Sopenharmony_ci		    case 2:
1985141cc406Sopenharmony_ci		      buf[*len] = dev->current[dev->lds_b];
1986141cc406Sopenharmony_ci		      break;
1987141cc406Sopenharmony_ci		    }
1988141cc406Sopenharmony_ci		  (*len)++;
1989141cc406Sopenharmony_ci		  session->sent++;
1990141cc406Sopenharmony_ci		  dev->current++;
1991141cc406Sopenharmony_ci		}
1992141cc406Sopenharmony_ci	    }
1993141cc406Sopenharmony_ci	  else
1994141cc406Sopenharmony_ci	    {
1995141cc406Sopenharmony_ci	      /* we currently handle ydi=2*dpi */
1996141cc406Sopenharmony_ci	      if (session->emulated_gray == SANE_TRUE)
1997141cc406Sopenharmony_ci		{
1998141cc406Sopenharmony_ci		  /* in emulated gray mode we are always reading 3 bytes of raw data */
1999141cc406Sopenharmony_ci		  /* at a time, so we know where we are                               */
2000141cc406Sopenharmony_ci		  val = (dev->current[dev->lds_g]
2001141cc406Sopenharmony_ci			 + dev->current[dev->lds_g +
2002141cc406Sopenharmony_ci					dev->bytes_per_line]) / 2;
2003141cc406Sopenharmony_ci		  if (session->params.depth == 1)
2004141cc406Sopenharmony_ci		    {
2005141cc406Sopenharmony_ci		      bit = 7 - (session->sent) % 8;
2006141cc406Sopenharmony_ci		      if (val <= dev->threshold)
2007141cc406Sopenharmony_ci			{
2008141cc406Sopenharmony_ci			  buf[*len] |= 1 << bit;
2009141cc406Sopenharmony_ci			}
2010141cc406Sopenharmony_ci		      else
2011141cc406Sopenharmony_ci			{
2012141cc406Sopenharmony_ci			  buf[*len] &= ~(1 << bit);
2013141cc406Sopenharmony_ci			}
2014141cc406Sopenharmony_ci		      if (bit == 0)
2015141cc406Sopenharmony_ci			{
2016141cc406Sopenharmony_ci			  (*len)++;
2017141cc406Sopenharmony_ci			}
2018141cc406Sopenharmony_ci		    }
2019141cc406Sopenharmony_ci		  else
2020141cc406Sopenharmony_ci		    {
2021141cc406Sopenharmony_ci		      buf[*len] = val;
2022141cc406Sopenharmony_ci		      (*len)++;
2023141cc406Sopenharmony_ci		    }
2024141cc406Sopenharmony_ci		  dev->current += 3;
2025141cc406Sopenharmony_ci		}
2026141cc406Sopenharmony_ci	      else
2027141cc406Sopenharmony_ci		{
2028141cc406Sopenharmony_ci		  switch ((dev->current - dev->start) % 3)
2029141cc406Sopenharmony_ci		    {
2030141cc406Sopenharmony_ci		    case 0:
2031141cc406Sopenharmony_ci		      buf[*len] = (dev->current[dev->lds_r]
2032141cc406Sopenharmony_ci				   + dev->current[dev->lds_r +
2033141cc406Sopenharmony_ci						  dev->bytes_per_line]) / 2;
2034141cc406Sopenharmony_ci		      break;
2035141cc406Sopenharmony_ci		    case 1:
2036141cc406Sopenharmony_ci		      buf[*len] = (dev->current[dev->lds_g]
2037141cc406Sopenharmony_ci				   + dev->current[dev->lds_g +
2038141cc406Sopenharmony_ci						  dev->bytes_per_line]) / 2;
2039141cc406Sopenharmony_ci		      break;
2040141cc406Sopenharmony_ci		    case 2:
2041141cc406Sopenharmony_ci		      buf[*len] = (dev->current[dev->lds_b]
2042141cc406Sopenharmony_ci				   + dev->current[dev->lds_b +
2043141cc406Sopenharmony_ci						  dev->bytes_per_line]) / 2;
2044141cc406Sopenharmony_ci		      break;
2045141cc406Sopenharmony_ci		    }
2046141cc406Sopenharmony_ci		  (*len)++;
2047141cc406Sopenharmony_ci		  dev->current++;
2048141cc406Sopenharmony_ci		}
2049141cc406Sopenharmony_ci	      session->sent++;
2050141cc406Sopenharmony_ci
2051141cc406Sopenharmony_ci	      /* at the end of each line, we must count another one because */
2052141cc406Sopenharmony_ci	      /* 2 lines are used to produce one                            */
2053141cc406Sopenharmony_ci	      if ((dev->current - dev->start) % dev->bytes_per_line == 0)
2054141cc406Sopenharmony_ci		dev->current += dev->bytes_per_line;
2055141cc406Sopenharmony_ci	    }
2056141cc406Sopenharmony_ci	}
2057141cc406Sopenharmony_ci    }
2058141cc406Sopenharmony_ci
2059141cc406Sopenharmony_ci  /* if we exhausted data buffer, we prepare for the next read */
2060141cc406Sopenharmony_ci  /* in color mode, we need to copy the remainder of the      */
2061141cc406Sopenharmony_ci  /* buffer because of line distance handling, when blue data */
2062141cc406Sopenharmony_ci  /* is exhausted, read and green haven't been fully read yet */
2063141cc406Sopenharmony_ci  if (dev->current >= dev->end
2064141cc406Sopenharmony_ci      && (session->params.format == SANE_FRAME_RGB
2065141cc406Sopenharmony_ci	  || session->emulated_gray == SANE_TRUE))
2066141cc406Sopenharmony_ci    {
2067141cc406Sopenharmony_ci      memcpy (dev->scanned_data, dev->end - (dev->lds_max + dev->ripple),
2068141cc406Sopenharmony_ci	      dev->lds_max + dev->ripple);
2069141cc406Sopenharmony_ci    }
2070141cc406Sopenharmony_ci
2071141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
2072141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: sent %d bytes to frontend\n", *len);
2073141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: exit\n");
2074141cc406Sopenharmony_ci  return status;
2075141cc406Sopenharmony_ci}
2076141cc406Sopenharmony_ci
2077141cc406Sopenharmony_ci
2078141cc406Sopenharmony_ci/**
2079141cc406Sopenharmony_ci * Cancels a scan.
2080141cc406Sopenharmony_ci *
2081141cc406Sopenharmony_ci * From the SANE spec:
2082141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible
2083141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by
2084141cc406Sopenharmony_ci * handle h.  This function can be called at any time (as long as
2085141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running
2086141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call
2087141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler).
2088141cc406Sopenharmony_ci * It is important to note that completion of this operation does not
2089141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It
2090141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation
2091141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a
2092141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED).  Since the SANE API does
2093141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies
2094141cc406Sopenharmony_ci * that a frontend must not call any other operation until the
2095141cc406Sopenharmony_ci * cancelled operation has returned.
2096141cc406Sopenharmony_ci */
2097141cc406Sopenharmony_civoid
2098141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2099141cc406Sopenharmony_ci{
2100141cc406Sopenharmony_ci  Rts8891_Session *session = handle;
2101141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
2102141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
2103141cc406Sopenharmony_ci  struct timeval current;
2104141cc406Sopenharmony_ci#endif
2105141cc406Sopenharmony_ci
2106141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: start\n");
2107141cc406Sopenharmony_ci
2108141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
2109141cc406Sopenharmony_ci  /* store last scan time for the device */
2110141cc406Sopenharmony_ci  gettimeofday (&current, NULL);
2111141cc406Sopenharmony_ci  dev->last_scan.tv_sec = current.tv_sec;
2112141cc406Sopenharmony_ci#endif
2113141cc406Sopenharmony_ci
2114141cc406Sopenharmony_ci  /* if scanning, abort and park head */
2115141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
2116141cc406Sopenharmony_ci    {
2117141cc406Sopenharmony_ci      /* canceling while all data hasn't bee read */
2118141cc406Sopenharmony_ci      if (dev->read < dev->to_read)
2119141cc406Sopenharmony_ci	{
2120141cc406Sopenharmony_ci	  sanei_rts88xx_cancel (dev->devnum);
2121141cc406Sopenharmony_ci	  usleep (500000);
2122141cc406Sopenharmony_ci	  sanei_rts88xx_cancel (dev->devnum);
2123141cc406Sopenharmony_ci	}
2124141cc406Sopenharmony_ci      session->scanning = SANE_FALSE;
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci      /* head parking */
2127141cc406Sopenharmony_ci      if (park_head (dev, SANE_FALSE) != SANE_STATUS_GOOD)
2128141cc406Sopenharmony_ci        {
2129141cc406Sopenharmony_ci          DBG (DBG_error, "sane_cancel: failed to park head!\n");
2130141cc406Sopenharmony_ci        }
2131141cc406Sopenharmony_ci    }
2132141cc406Sopenharmony_ci
2133141cc406Sopenharmony_ci  /* free resources used by scanning */
2134141cc406Sopenharmony_ci  if (dev->scanned_data != NULL)
2135141cc406Sopenharmony_ci    {
2136141cc406Sopenharmony_ci      free (dev->scanned_data);
2137141cc406Sopenharmony_ci      dev->scanned_data = NULL;
2138141cc406Sopenharmony_ci    }
2139141cc406Sopenharmony_ci  if (dev->shading_data != NULL)
2140141cc406Sopenharmony_ci    {
2141141cc406Sopenharmony_ci      free (dev->shading_data);
2142141cc406Sopenharmony_ci      dev->shading_data = NULL;
2143141cc406Sopenharmony_ci    }
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci  /* release the interface to allow device sharing */
2146141cc406Sopenharmony_ci  if (dev->conf.allowsharing == SANE_TRUE)
2147141cc406Sopenharmony_ci    {
2148141cc406Sopenharmony_ci      sanei_usb_release_interface (dev->devnum, 0);
2149141cc406Sopenharmony_ci    }
2150141cc406Sopenharmony_ci
2151141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: exit\n");
2152141cc406Sopenharmony_ci}
2153141cc406Sopenharmony_ci
2154141cc406Sopenharmony_ci
2155141cc406Sopenharmony_ci/**
2156141cc406Sopenharmony_ci * Ends use of the session.
2157141cc406Sopenharmony_ci *
2158141cc406Sopenharmony_ci * From the SANE spec:
2159141cc406Sopenharmony_ci * This function terminates the association between the device handle
2160141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is
2161141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After
2162141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore.
2163141cc406Sopenharmony_ci *
2164141cc406Sopenharmony_ci * Handle resources are free'd before disposing the handle. But devices
2165141cc406Sopenharmony_ci * resources must not be mdofied, since it could be used or reused until
2166141cc406Sopenharmony_ci * sane_exit() is called.
2167141cc406Sopenharmony_ci */
2168141cc406Sopenharmony_civoid
2169141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2170141cc406Sopenharmony_ci{
2171141cc406Sopenharmony_ci  Rts8891_Session *prev, *session;
2172141cc406Sopenharmony_ci  Rts8891_Device *dev;
2173141cc406Sopenharmony_ci  int i;
2174141cc406Sopenharmony_ci
2175141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: start\n");
2176141cc406Sopenharmony_ci
2177141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
2178141cc406Sopenharmony_ci  prev = NULL;
2179141cc406Sopenharmony_ci  for (session = first_handle; session; session = session->next)
2180141cc406Sopenharmony_ci    {
2181141cc406Sopenharmony_ci      if (session == handle)
2182141cc406Sopenharmony_ci	break;
2183141cc406Sopenharmony_ci      prev = session;
2184141cc406Sopenharmony_ci    }
2185141cc406Sopenharmony_ci  if (!session)
2186141cc406Sopenharmony_ci    {
2187141cc406Sopenharmony_ci      DBG (DBG_error, "close: invalid handle %p\n", handle);
2188141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
2189141cc406Sopenharmony_ci    }
2190141cc406Sopenharmony_ci
2191141cc406Sopenharmony_ci  dev=session->dev;
2192141cc406Sopenharmony_ci
2193141cc406Sopenharmony_ci  /* cancel any active scan */
2194141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
2195141cc406Sopenharmony_ci    {
2196141cc406Sopenharmony_ci      sane_cancel (handle);
2197141cc406Sopenharmony_ci    }
2198141cc406Sopenharmony_ci  /* if head is parking, wait for completion */
2199141cc406Sopenharmony_ci  if(dev->parking==SANE_TRUE)
2200141cc406Sopenharmony_ci    {
2201141cc406Sopenharmony_ci      rts8891_wait_for_home (dev, dev->regs);
2202141cc406Sopenharmony_ci    }
2203141cc406Sopenharmony_ci  set_lamp_brightness (dev, 0);
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci
2206141cc406Sopenharmony_ci  if (prev)
2207141cc406Sopenharmony_ci    prev->next = session->next;
2208141cc406Sopenharmony_ci  else
2209141cc406Sopenharmony_ci    first_handle = session->next;
2210141cc406Sopenharmony_ci
2211141cc406Sopenharmony_ci  /* switch off lamp and close usb */
2212141cc406Sopenharmony_ci  if (dev->conf.allowsharing == SANE_TRUE)
2213141cc406Sopenharmony_ci    {
2214141cc406Sopenharmony_ci      SANE_Status status = sanei_usb_claim_interface (dev->devnum, 0);
2215141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2216141cc406Sopenharmony_ci        {
2217141cc406Sopenharmony_ci          DBG (DBG_warn, "sane_close: cannot claim usb interface: %s\n",
2218141cc406Sopenharmony_ci               sane_strstatus(status));
2219141cc406Sopenharmony_ci          DBG (DBG_warn, "sane_close: continuing anyway\n");
2220141cc406Sopenharmony_ci        }
2221141cc406Sopenharmony_ci    }
2222141cc406Sopenharmony_ci  set_lamp_state (session, 0);
2223141cc406Sopenharmony_ci  sanei_usb_close (dev->devnum);
2224141cc406Sopenharmony_ci
2225141cc406Sopenharmony_ci  /* free per session data */
2226141cc406Sopenharmony_ci  if (session->dev->model->gamma != session->val[OPT_GAMMA_VECTOR].wa)
2227141cc406Sopenharmony_ci    free (session->val[OPT_GAMMA_VECTOR].wa);
2228141cc406Sopenharmony_ci  if (session->dev->model->gamma != session->val[OPT_GAMMA_VECTOR_R].wa)
2229141cc406Sopenharmony_ci    free (session->val[OPT_GAMMA_VECTOR_R].wa);
2230141cc406Sopenharmony_ci  if (session->dev->model->gamma != session->val[OPT_GAMMA_VECTOR_G].wa)
2231141cc406Sopenharmony_ci    free (session->val[OPT_GAMMA_VECTOR_G].wa);
2232141cc406Sopenharmony_ci  if (session->dev->model->gamma != session->val[OPT_GAMMA_VECTOR_B].wa)
2233141cc406Sopenharmony_ci    free (session->val[OPT_GAMMA_VECTOR_B].wa);
2234141cc406Sopenharmony_ci  free (session->val[OPT_MODE].s);
2235141cc406Sopenharmony_ci  free ((void *) session->opt[OPT_RESOLUTION].constraint.word_list);
2236141cc406Sopenharmony_ci  for (i = OPT_BUTTON_1; i <= OPT_BUTTON_11; i++)
2237141cc406Sopenharmony_ci    {
2238141cc406Sopenharmony_ci      free ((void *) session->opt[i].name);
2239141cc406Sopenharmony_ci      free ((void *) session->opt[i].title);
2240141cc406Sopenharmony_ci    }
2241141cc406Sopenharmony_ci
2242141cc406Sopenharmony_ci  free (session);
2243141cc406Sopenharmony_ci
2244141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: exit\n");
2245141cc406Sopenharmony_ci}
2246141cc406Sopenharmony_ci
2247141cc406Sopenharmony_ci
2248141cc406Sopenharmony_ci/**
2249141cc406Sopenharmony_ci * Terminates the backend.
2250141cc406Sopenharmony_ci *
2251141cc406Sopenharmony_ci * From the SANE spec:
2252141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The
2253141cc406Sopenharmony_ci * function will first close all device handles that still might be
2254141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through
2255141cc406Sopenharmony_ci * a call to sane_close(), but backends are required to release all
2256141cc406Sopenharmony_ci * resources upon a call to this function). After this function
2257141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called
2258141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting
2259141cc406Sopenharmony_ci * to call this function may result in some resources not being
2260141cc406Sopenharmony_ci * released properly.
2261141cc406Sopenharmony_ci */
2262141cc406Sopenharmony_civoid
2263141cc406Sopenharmony_cisane_exit (void)
2264141cc406Sopenharmony_ci{
2265141cc406Sopenharmony_ci  struct Rts8891_Session *session, *next;
2266141cc406Sopenharmony_ci  struct Rts8891_Device *dev, *nextdev;
2267141cc406Sopenharmony_ci  int i;
2268141cc406Sopenharmony_ci
2269141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: start\n");
2270141cc406Sopenharmony_ci
2271141cc406Sopenharmony_ci  /* free session structs */
2272141cc406Sopenharmony_ci  for (session = first_handle; session; session = next)
2273141cc406Sopenharmony_ci    {
2274141cc406Sopenharmony_ci      next = session->next;
2275141cc406Sopenharmony_ci      sane_close ((SANE_Handle *) session);
2276141cc406Sopenharmony_ci      free (session);
2277141cc406Sopenharmony_ci    }
2278141cc406Sopenharmony_ci  first_handle = NULL;
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_ci  /* free devices structs */
2281141cc406Sopenharmony_ci  for (dev = first_device; dev; dev = nextdev)
2282141cc406Sopenharmony_ci    {
2283141cc406Sopenharmony_ci      nextdev = dev->next;
2284141cc406Sopenharmony_ci      free (dev->file_name);
2285141cc406Sopenharmony_ci      free (dev);
2286141cc406Sopenharmony_ci    }
2287141cc406Sopenharmony_ci  first_device = NULL;
2288141cc406Sopenharmony_ci
2289141cc406Sopenharmony_ci  /* now list of devices */
2290141cc406Sopenharmony_ci  if (devlist)
2291141cc406Sopenharmony_ci    {
2292141cc406Sopenharmony_ci      for (i = 0; i < num_devices; i++)
2293141cc406Sopenharmony_ci	{
2294141cc406Sopenharmony_ci	  free ((SANE_Device *) devlist[i]);
2295141cc406Sopenharmony_ci	}
2296141cc406Sopenharmony_ci      free (devlist);
2297141cc406Sopenharmony_ci      devlist = NULL;
2298141cc406Sopenharmony_ci    }
2299141cc406Sopenharmony_ci  num_devices = 0;
2300141cc406Sopenharmony_ci
2301141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
2302141cc406Sopenharmony_ci}
2303141cc406Sopenharmony_ci
2304141cc406Sopenharmony_ci
2305141cc406Sopenharmony_ci/** This function tries to find plugged relevant devices
2306141cc406Sopenharmony_ci */
2307141cc406Sopenharmony_cistatic SANE_Status
2308141cc406Sopenharmony_ciprobe_rts8891_devices (void)
2309141cc406Sopenharmony_ci{
2310141cc406Sopenharmony_ci  /**> configuration structure used during attach */
2311141cc406Sopenharmony_ci  SANEI_Config config;
2312141cc406Sopenharmony_ci  /**> list of configuration options */
2313141cc406Sopenharmony_ci  SANE_Option_Descriptor *options[NUM_CFG_OPTIONS];
2314141cc406Sopenharmony_ci  /**> placeholders pointers for option values */
2315141cc406Sopenharmony_ci  void *values[NUM_CFG_OPTIONS];
2316141cc406Sopenharmony_ci  int i;
2317141cc406Sopenharmony_ci  SANE_Status status;
2318141cc406Sopenharmony_ci
2319141cc406Sopenharmony_ci  DBG (DBG_proc, "probe_rts8891_devices: start\n");
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci  /* sharing is off by default and no model option */
2322141cc406Sopenharmony_ci  rtscfg.allowsharing = SANE_FALSE;
2323141cc406Sopenharmony_ci  rtscfg.modelnumber = -1;
2324141cc406Sopenharmony_ci  rtscfg.sensornumber = -1;
2325141cc406Sopenharmony_ci
2326141cc406Sopenharmony_ci  /* initialize configuration options */
2327141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER] =
2328141cc406Sopenharmony_ci    (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
2329141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->name = "modelnumber";
2330141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->desc =
2331141cc406Sopenharmony_ci    "user provided scanner's internal model number";
2332141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->type = SANE_TYPE_INT;
2333141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->unit = SANE_UNIT_NONE;
2334141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->size = sizeof (SANE_Word);
2335141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->cap = SANE_CAP_SOFT_SELECT;
2336141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->constraint_type = SANE_CONSTRAINT_RANGE;
2337141cc406Sopenharmony_ci  options[CFG_MODEL_NUMBER]->constraint.range = &model_range;
2338141cc406Sopenharmony_ci  values[CFG_MODEL_NUMBER] = &rtscfg.modelnumber;
2339141cc406Sopenharmony_ci
2340141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING] =
2341141cc406Sopenharmony_ci    (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
2342141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->name = "allowsharing";
2343141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->desc =
2344141cc406Sopenharmony_ci    "allow sharing of the scanner by several frontends";
2345141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->type = SANE_TYPE_BOOL;
2346141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->unit = SANE_UNIT_NONE;
2347141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->size = sizeof (SANE_Bool);
2348141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->cap = SANE_CAP_SOFT_SELECT;
2349141cc406Sopenharmony_ci  options[CFG_ALLOW_SHARING]->constraint_type = SANE_CONSTRAINT_NONE;
2350141cc406Sopenharmony_ci  values[CFG_ALLOW_SHARING] = &rtscfg.allowsharing;
2351141cc406Sopenharmony_ci
2352141cc406Sopenharmony_ci  /* sensor type override */
2353141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER] =
2354141cc406Sopenharmony_ci    (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
2355141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->name = "sensornumber";
2356141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->desc =
2357141cc406Sopenharmony_ci    "user provided scanner's internal sensor number";
2358141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->type = SANE_TYPE_INT;
2359141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->unit = SANE_UNIT_NONE;
2360141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->size = sizeof (SANE_Word);
2361141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->cap = SANE_CAP_SOFT_SELECT;
2362141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->constraint_type = SANE_CONSTRAINT_RANGE;
2363141cc406Sopenharmony_ci  options[CFG_SENSOR_NUMBER]->constraint.range = &sensor_range;
2364141cc406Sopenharmony_ci  values[CFG_SENSOR_NUMBER] = &rtscfg.sensornumber;
2365141cc406Sopenharmony_ci
2366141cc406Sopenharmony_ci  /* set configuration options structure */
2367141cc406Sopenharmony_ci  config.descriptors = options;
2368141cc406Sopenharmony_ci  config.values = values;
2369141cc406Sopenharmony_ci  config.count = NUM_CFG_OPTIONS;
2370141cc406Sopenharmony_ci
2371141cc406Sopenharmony_ci  /* init usb use */
2372141cc406Sopenharmony_ci  sanei_usb_init ();
2373141cc406Sopenharmony_ci
2374141cc406Sopenharmony_ci  /* generic configure and attach function */
2375141cc406Sopenharmony_ci  status = sanei_configure_attach (RTS8891_CONFIG_FILE, &config,
2376141cc406Sopenharmony_ci				   config_attach_rts8891, NULL);
2377141cc406Sopenharmony_ci  /* free allocated options */
2378141cc406Sopenharmony_ci  for (i = 0; i < NUM_CFG_OPTIONS; i++)
2379141cc406Sopenharmony_ci    {
2380141cc406Sopenharmony_ci      free (options[i]);
2381141cc406Sopenharmony_ci    }
2382141cc406Sopenharmony_ci
2383141cc406Sopenharmony_ci  DBG (DBG_proc, "probe_rts8891_devices: end\n");
2384141cc406Sopenharmony_ci  return status;
2385141cc406Sopenharmony_ci}
2386141cc406Sopenharmony_ci
2387141cc406Sopenharmony_ci/** This function is called by sanei_configure_attach to try
2388141cc406Sopenharmony_ci * to attach the backend to a device specified by the configuration file.
2389141cc406Sopenharmony_ci *
2390141cc406Sopenharmony_ci * @param config configuration structure filled with values read
2391141cc406Sopenharmony_ci * 	         from configuration file
2392141cc406Sopenharmony_ci * @param devname name of the device to try to attach to, it is
2393141cc406Sopenharmony_ci * 	          the unprocessed line of the configuration file
2394141cc406Sopenharmony_ci *
2395141cc406Sopenharmony_ci * @return status SANE_STATUS_GOOD if no errors (even if no matching
2396141cc406Sopenharmony_ci * 	    devices found)
2397141cc406Sopenharmony_ci * 	   SANE_STATUS_INVAL in case of error
2398141cc406Sopenharmony_ci */
2399141cc406Sopenharmony_cistatic SANE_Status
2400141cc406Sopenharmony_ciconfig_attach_rts8891 (SANEI_Config * config, const char *devname,
2401141cc406Sopenharmony_ci                       void __sane_unused__ *data)
2402141cc406Sopenharmony_ci{
2403141cc406Sopenharmony_ci  /* currently, the config is a global variable so config is useless here */
2404141cc406Sopenharmony_ci  /* the correct thing would be to have a generic sanei_attach_matching_devices
2405141cc406Sopenharmony_ci   * using an attach function with a config parameter */
2406141cc406Sopenharmony_ci  if(config==NULL)
2407141cc406Sopenharmony_ci    {
2408141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2409141cc406Sopenharmony_ci    }
2410141cc406Sopenharmony_ci
2411141cc406Sopenharmony_ci  /* the devname has been processed and is ready to be used
2412141cc406Sopenharmony_ci   * directly. Since the backend is an USB only one, we can
2413141cc406Sopenharmony_ci   * call sanei_usb_attach_matching_devices straight */
2414141cc406Sopenharmony_ci  sanei_usb_attach_matching_devices (devname, attach_rts8891);
2415141cc406Sopenharmony_ci
2416141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2417141cc406Sopenharmony_ci}
2418141cc406Sopenharmony_ci
2419141cc406Sopenharmony_ci/**
2420141cc406Sopenharmony_ci * The attach tries to open the given usb device and match it
2421141cc406Sopenharmony_ci * with devices handled by the backend. The configuration parameter
2422141cc406Sopenharmony_ci * contains the values of the already parsed configuration options
2423141cc406Sopenharmony_ci * from the conf file.
2424141cc406Sopenharmony_ci * @param config configuration structure filled with values read
2425141cc406Sopenharmony_ci * 	         from configuration file
2426141cc406Sopenharmony_ci * @param devicename name of the device to try to attach to, it is
2427141cc406Sopenharmony_ci * 	          the unprocessed line of the configuration file
2428141cc406Sopenharmony_ci *
2429141cc406Sopenharmony_ci * @return status SANE_STATUS_GOOD if no errors (even if no matching
2430141cc406Sopenharmony_ci * 	    devices found)
2431141cc406Sopenharmony_ci * 	   SANE_STATUS_NOM_MEM if there isn't enough memory to allocate the
2432141cc406Sopenharmony_ci * 	   			device structure
2433141cc406Sopenharmony_ci * 	   SANE_STATUS_UNSUPPORTED if the device if unknown by the backend
2434141cc406Sopenharmony_ci * 	   SANE_STATUS_INVAL in case of other error
2435141cc406Sopenharmony_ci */
2436141cc406Sopenharmony_cistatic SANE_Status
2437141cc406Sopenharmony_ciattach_rts8891 (const char *devicename)
2438141cc406Sopenharmony_ci{
2439141cc406Sopenharmony_ci  struct Rts8891_Device *device;
2440141cc406Sopenharmony_ci  SANE_Int dn, vendor, product;
2441141cc406Sopenharmony_ci  SANE_Status status;
2442141cc406Sopenharmony_ci
2443141cc406Sopenharmony_ci  DBG (DBG_proc, "attach_rts8891(%s): start\n", devicename);
2444141cc406Sopenharmony_ci
2445141cc406Sopenharmony_ci  /* search if we already have it attached */
2446141cc406Sopenharmony_ci  for (device = first_device; device; device = device->next)
2447141cc406Sopenharmony_ci    {
2448141cc406Sopenharmony_ci      if (strcmp (device->file_name, devicename) == 0)
2449141cc406Sopenharmony_ci	{
2450141cc406Sopenharmony_ci	  DBG (DBG_warn,
2451141cc406Sopenharmony_ci	       "attach_rts8891: device already attached (is ok)!\n");
2452141cc406Sopenharmony_ci	  DBG (DBG_proc, "attach_rts8891: exit\n");
2453141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2454141cc406Sopenharmony_ci	}
2455141cc406Sopenharmony_ci    }
2456141cc406Sopenharmony_ci
2457141cc406Sopenharmony_ci  /* open usb device */
2458141cc406Sopenharmony_ci  status = sanei_usb_open (devicename, &dn);
2459141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2460141cc406Sopenharmony_ci    {
2461141cc406Sopenharmony_ci      DBG (DBG_error, "attach_rts8891: couldn't open device `%s': %s\n",
2462141cc406Sopenharmony_ci	   devicename, sane_strstatus (status));
2463141cc406Sopenharmony_ci      return status;
2464141cc406Sopenharmony_ci    }
2465141cc406Sopenharmony_ci  else
2466141cc406Sopenharmony_ci    {
2467141cc406Sopenharmony_ci      DBG (DBG_info, "attach_rts8891: device `%s' successfully opened\n",
2468141cc406Sopenharmony_ci	   devicename);
2469141cc406Sopenharmony_ci    }
2470141cc406Sopenharmony_ci
2471141cc406Sopenharmony_ci  /* get vendor and product id */
2472141cc406Sopenharmony_ci  status = sanei_usb_get_vendor_product (dn, &vendor, &product);
2473141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2474141cc406Sopenharmony_ci    {
2475141cc406Sopenharmony_ci      DBG (DBG_error,
2476141cc406Sopenharmony_ci	   "attach_rts8891: couldn't get vendor and product ids of device `%s': %s\n",
2477141cc406Sopenharmony_ci	   devicename, sane_strstatus (status));
2478141cc406Sopenharmony_ci      sanei_usb_close (dn);
2479141cc406Sopenharmony_ci      DBG (DBG_proc, "attach_rts8891: exit\n");
2480141cc406Sopenharmony_ci      return status;
2481141cc406Sopenharmony_ci    }
2482141cc406Sopenharmony_ci  sanei_usb_close (dn);
2483141cc406Sopenharmony_ci
2484141cc406Sopenharmony_ci  /* get the index of the device in the device description table */
2485141cc406Sopenharmony_ci  /* if the value is provided by configuration option, just use it */
2486141cc406Sopenharmony_ci  if (rtscfg.modelnumber < 0)
2487141cc406Sopenharmony_ci    {
2488141cc406Sopenharmony_ci      /* walk the list of devices to find matching entry */
2489141cc406Sopenharmony_ci      dn = 0;
2490141cc406Sopenharmony_ci      while ((vendor != rts8891_usb_device_list[dn].vendor_id
2491141cc406Sopenharmony_ci	      || product != rts8891_usb_device_list[dn].product_id)
2492141cc406Sopenharmony_ci	     && (rts8891_usb_device_list[dn].vendor_id != 0))
2493141cc406Sopenharmony_ci	dn++;
2494141cc406Sopenharmony_ci      /* if we reach the list termination entry, the device is unknown */
2495141cc406Sopenharmony_ci      if (rts8891_usb_device_list[dn].vendor_id == 0)
2496141cc406Sopenharmony_ci	{
2497141cc406Sopenharmony_ci	  DBG (DBG_info,
2498141cc406Sopenharmony_ci	       "attach_rts8891: unknown device `%s': 0x%04x:0x%04x\n",
2499141cc406Sopenharmony_ci	       devicename, vendor, product);
2500141cc406Sopenharmony_ci	  DBG (DBG_proc, "attach_rts8891: exit\n");
2501141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
2502141cc406Sopenharmony_ci	}
2503141cc406Sopenharmony_ci    }
2504141cc406Sopenharmony_ci  else
2505141cc406Sopenharmony_ci    {
2506141cc406Sopenharmony_ci      /* user provided value */
2507141cc406Sopenharmony_ci      dn = rtscfg.modelnumber;
2508141cc406Sopenharmony_ci    }
2509141cc406Sopenharmony_ci
2510141cc406Sopenharmony_ci  /* allocate device struct */
2511141cc406Sopenharmony_ci  device = malloc (sizeof (*device));
2512141cc406Sopenharmony_ci  if (device == NULL)
2513141cc406Sopenharmony_ci    {
2514141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2515141cc406Sopenharmony_ci    }
2516141cc406Sopenharmony_ci  memset (device, 0, sizeof (*device));
2517141cc406Sopenharmony_ci
2518141cc406Sopenharmony_ci  /* struct describing low lvel device */
2519141cc406Sopenharmony_ci  device->model = rts8891_usb_device_list[dn].model;
2520141cc406Sopenharmony_ci
2521141cc406Sopenharmony_ci  /* name of the device */
2522141cc406Sopenharmony_ci  device->file_name = strdup (devicename);
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_ci  DBG (DBG_info, "attach_rts8891: found %s %s %s at %s\n",
2525141cc406Sopenharmony_ci       device->model->vendor,
2526141cc406Sopenharmony_ci       device->model->product, device->model->type, device->file_name);
2527141cc406Sopenharmony_ci
2528141cc406Sopenharmony_ci  /* we insert new device at start of the chained list */
2529141cc406Sopenharmony_ci  /* head of the list becomes the next, and start is replaced */
2530141cc406Sopenharmony_ci  /* with the new session struct */
2531141cc406Sopenharmony_ci  num_devices++;
2532141cc406Sopenharmony_ci  device->next = first_device;
2533141cc406Sopenharmony_ci  first_device = device;
2534141cc406Sopenharmony_ci
2535141cc406Sopenharmony_ci  device->reg_count = 244;
2536141cc406Sopenharmony_ci  /* initialization is done at sane_open */
2537141cc406Sopenharmony_ci  device->initialized = SANE_FALSE;
2538141cc406Sopenharmony_ci  device->needs_warming = SANE_TRUE;
2539141cc406Sopenharmony_ci  device->parking = SANE_FALSE;
2540141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
2541141cc406Sopenharmony_ci  device->last_scan.tv_sec = 0;
2542141cc406Sopenharmony_ci  device->start_time.tv_sec = 0;
2543141cc406Sopenharmony_ci#endif
2544141cc406Sopenharmony_ci
2545141cc406Sopenharmony_ci  /* in case autodection au sensor doesn't work, use the given override */
2546141cc406Sopenharmony_ci  device->sensor = rtscfg.sensornumber;
2547141cc406Sopenharmony_ci
2548141cc406Sopenharmony_ci  /* copy configuration settings to device */
2549141cc406Sopenharmony_ci  device->conf.modelnumber = dn;
2550141cc406Sopenharmony_ci  device->conf.allowsharing = rtscfg.allowsharing;
2551141cc406Sopenharmony_ci
2552141cc406Sopenharmony_ci  DBG (DBG_proc, "attach_rts8891: exit\n");
2553141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2554141cc406Sopenharmony_ci}
2555141cc406Sopenharmony_ci
2556141cc406Sopenharmony_ci
2557141cc406Sopenharmony_ci/* set initial value for the scanning options */
2558141cc406Sopenharmony_cistatic SANE_Status
2559141cc406Sopenharmony_ciinit_options (struct Rts8891_Session *session)
2560141cc406Sopenharmony_ci{
2561141cc406Sopenharmony_ci  SANE_Int option, count, i, min, idx;
2562141cc406Sopenharmony_ci  SANE_Word *dpi_list;
2563141cc406Sopenharmony_ci  Rts8891_Model *model = session->dev->model;
2564141cc406Sopenharmony_ci
2565141cc406Sopenharmony_ci  DBG (DBG_proc, "init_options: start\n");
2566141cc406Sopenharmony_ci
2567141cc406Sopenharmony_ci  /* we first initialize each options with a default value */
2568141cc406Sopenharmony_ci  memset (session->opt, 0, sizeof (session->opt));
2569141cc406Sopenharmony_ci  memset (session->val, 0, sizeof (session->val));
2570141cc406Sopenharmony_ci
2571141cc406Sopenharmony_ci  for (option = 0; option < NUM_OPTIONS; option++)
2572141cc406Sopenharmony_ci    {
2573141cc406Sopenharmony_ci      session->opt[option].size = sizeof (SANE_Word);
2574141cc406Sopenharmony_ci      session->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2575141cc406Sopenharmony_ci    }
2576141cc406Sopenharmony_ci
2577141cc406Sopenharmony_ci  /* we set up all the options listed in the Rts8891_Option enum */
2578141cc406Sopenharmony_ci
2579141cc406Sopenharmony_ci  /* last option / end of list marker */
2580141cc406Sopenharmony_ci  session->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
2581141cc406Sopenharmony_ci  session->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2582141cc406Sopenharmony_ci  session->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2583141cc406Sopenharmony_ci  session->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2584141cc406Sopenharmony_ci  session->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2585141cc406Sopenharmony_ci  session->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
2586141cc406Sopenharmony_ci
2587141cc406Sopenharmony_ci  /* "Standard" group: */
2588141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].title = SANE_TITLE_STANDARD;
2589141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].name = SANE_NAME_STANDARD;
2590141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].desc = SANE_DESC_STANDARD;
2591141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].type = SANE_TYPE_GROUP;
2592141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].size = 0;
2593141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].cap = 0;
2594141cc406Sopenharmony_ci  session->opt[OPT_STANDARD_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2595141cc406Sopenharmony_ci
2596141cc406Sopenharmony_ci  /* scan mode */
2597141cc406Sopenharmony_ci  session->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2598141cc406Sopenharmony_ci  session->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2599141cc406Sopenharmony_ci  session->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2600141cc406Sopenharmony_ci  session->opt[OPT_MODE].type = SANE_TYPE_STRING;
2601141cc406Sopenharmony_ci  session->opt[OPT_MODE].cap |= SANE_CAP_AUTOMATIC;
2602141cc406Sopenharmony_ci  session->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2603141cc406Sopenharmony_ci  session->opt[OPT_MODE].size = max_string_size (mode_list);
2604141cc406Sopenharmony_ci  session->opt[OPT_MODE].constraint.string_list = mode_list;
2605141cc406Sopenharmony_ci  session->val[OPT_MODE].s = strdup (mode_list[0]);
2606141cc406Sopenharmony_ci
2607141cc406Sopenharmony_ci  /* preview */
2608141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
2609141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
2610141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
2611141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
2612141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].cap |= SANE_CAP_AUTOMATIC;
2613141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE;
2614141cc406Sopenharmony_ci  session->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
2615141cc406Sopenharmony_ci  session->val[OPT_PREVIEW].w = SANE_FALSE;
2616141cc406Sopenharmony_ci
2617141cc406Sopenharmony_ci  /* build resolution list */
2618141cc406Sopenharmony_ci  /* TODO we build it from xdpi, one could prefer building it from
2619141cc406Sopenharmony_ci   * ydpi list, or even allow for independent X and Y dpi (with 2 options then)
2620141cc406Sopenharmony_ci   */
2621141cc406Sopenharmony_ci  for (count = 0; model->xdpi_values[count] != 0; count++);
2622141cc406Sopenharmony_ci  dpi_list = malloc ((count + 1) * sizeof (SANE_Word));
2623141cc406Sopenharmony_ci  if (!dpi_list)
2624141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2625141cc406Sopenharmony_ci  dpi_list[0] = count;
2626141cc406Sopenharmony_ci  for (count = 0; model->xdpi_values[count] != 0; count++)
2627141cc406Sopenharmony_ci    dpi_list[count + 1] = model->xdpi_values[count];
2628141cc406Sopenharmony_ci
2629141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2630141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
2631141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
2632141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
2633141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].cap |= SANE_CAP_AUTOMATIC;
2634141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
2635141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2636141cc406Sopenharmony_ci  session->opt[OPT_RESOLUTION].constraint.word_list = dpi_list;
2637141cc406Sopenharmony_ci
2638141cc406Sopenharmony_ci  /* initial value is lowest available dpi */
2639141cc406Sopenharmony_ci  min = 65536;
2640141cc406Sopenharmony_ci  for (i = 1; i < count; i++)
2641141cc406Sopenharmony_ci    {
2642141cc406Sopenharmony_ci      if (dpi_list[i] < min)
2643141cc406Sopenharmony_ci	min = dpi_list[i];
2644141cc406Sopenharmony_ci    }
2645141cc406Sopenharmony_ci  session->val[OPT_RESOLUTION].w = min;
2646141cc406Sopenharmony_ci
2647141cc406Sopenharmony_ci  /* "Geometry" group: */
2648141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY;
2649141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].name = SANE_NAME_GEOMETRY;
2650141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
2651141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2652141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
2653141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].size = 0;
2654141cc406Sopenharmony_ci  session->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2655141cc406Sopenharmony_ci
2656141cc406Sopenharmony_ci  /* adapt the constraint range to the detected model */
2657141cc406Sopenharmony_ci  x_range.max = model->x_size;
2658141cc406Sopenharmony_ci  y_range.max = model->y_size;
2659141cc406Sopenharmony_ci
2660141cc406Sopenharmony_ci  /* top-left x */
2661141cc406Sopenharmony_ci  session->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2662141cc406Sopenharmony_ci  session->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2663141cc406Sopenharmony_ci  session->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2664141cc406Sopenharmony_ci  session->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
2665141cc406Sopenharmony_ci  session->opt[OPT_TL_X].cap |= SANE_CAP_AUTOMATIC;
2666141cc406Sopenharmony_ci  session->opt[OPT_TL_X].unit = SANE_UNIT_MM;
2667141cc406Sopenharmony_ci  session->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
2668141cc406Sopenharmony_ci  session->opt[OPT_TL_X].constraint.range = &x_range;
2669141cc406Sopenharmony_ci  session->val[OPT_TL_X].w = 0;
2670141cc406Sopenharmony_ci
2671141cc406Sopenharmony_ci  /* top-left y */
2672141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2673141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2674141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2675141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
2676141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].cap |= SANE_CAP_AUTOMATIC;
2677141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
2678141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2679141cc406Sopenharmony_ci  session->opt[OPT_TL_Y].constraint.range = &y_range;
2680141cc406Sopenharmony_ci  session->val[OPT_TL_Y].w = 0;
2681141cc406Sopenharmony_ci
2682141cc406Sopenharmony_ci  /* bottom-right x */
2683141cc406Sopenharmony_ci  session->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2684141cc406Sopenharmony_ci  session->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2685141cc406Sopenharmony_ci  session->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2686141cc406Sopenharmony_ci  session->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
2687141cc406Sopenharmony_ci  session->opt[OPT_BR_X].cap |= SANE_CAP_AUTOMATIC;
2688141cc406Sopenharmony_ci  session->opt[OPT_BR_X].unit = SANE_UNIT_MM;
2689141cc406Sopenharmony_ci  session->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
2690141cc406Sopenharmony_ci  session->opt[OPT_BR_X].constraint.range = &x_range;
2691141cc406Sopenharmony_ci  session->val[OPT_BR_X].w = x_range.max;
2692141cc406Sopenharmony_ci
2693141cc406Sopenharmony_ci  /* bottom-right y */
2694141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2695141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2696141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2697141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
2698141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].cap |= SANE_CAP_AUTOMATIC;
2699141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
2700141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2701141cc406Sopenharmony_ci  session->opt[OPT_BR_Y].constraint.range = &y_range;
2702141cc406Sopenharmony_ci  session->val[OPT_BR_Y].w = y_range.max;
2703141cc406Sopenharmony_ci
2704141cc406Sopenharmony_ci  /* "Enhancement" group: */
2705141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].title = SANE_TITLE_ENHANCEMENT;
2706141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].name = SANE_NAME_ENHANCEMENT;
2707141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].desc = SANE_DESC_ENHANCEMENT;
2708141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2709141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
2710141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].size = 0;
2711141cc406Sopenharmony_ci  session->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2712141cc406Sopenharmony_ci
2713141cc406Sopenharmony_ci  /* BW threshold */
2714141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
2715141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
2716141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
2717141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
2718141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
2719141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].cap |=
2720141cc406Sopenharmony_ci    SANE_CAP_INACTIVE | SANE_CAP_AUTOMATIC | SANE_CAP_EMULATED;
2721141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
2722141cc406Sopenharmony_ci  session->opt[OPT_THRESHOLD].constraint.range = &threshold_percentage_range;
2723141cc406Sopenharmony_ci  session->val[OPT_THRESHOLD].w = SANE_FIX (50);
2724141cc406Sopenharmony_ci
2725141cc406Sopenharmony_ci  /* custom-gamma table */
2726141cc406Sopenharmony_ci  session->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
2727141cc406Sopenharmony_ci  session->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
2728141cc406Sopenharmony_ci  session->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
2729141cc406Sopenharmony_ci  session->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
2730141cc406Sopenharmony_ci  session->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED;
2731141cc406Sopenharmony_ci  session->val[OPT_CUSTOM_GAMMA].b = SANE_FALSE;
2732141cc406Sopenharmony_ci
2733141cc406Sopenharmony_ci  /* grayscale gamma vector */
2734141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
2735141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
2736141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
2737141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
2738141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].cap |=
2739141cc406Sopenharmony_ci    SANE_CAP_INACTIVE | SANE_CAP_AUTOMATIC | SANE_CAP_ADVANCED;
2740141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
2741141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
2742141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
2743141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
2744141cc406Sopenharmony_ci  session->val[OPT_GAMMA_VECTOR].wa = model->gamma;
2745141cc406Sopenharmony_ci
2746141cc406Sopenharmony_ci  /* red gamma vector */
2747141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
2748141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
2749141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
2750141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
2751141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].cap |=
2752141cc406Sopenharmony_ci    SANE_CAP_INACTIVE | SANE_CAP_AUTOMATIC | SANE_CAP_ADVANCED;
2753141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
2754141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
2755141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
2756141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
2757141cc406Sopenharmony_ci  session->val[OPT_GAMMA_VECTOR_R].wa = model->gamma;
2758141cc406Sopenharmony_ci
2759141cc406Sopenharmony_ci  /* green gamma vector */
2760141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
2761141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
2762141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
2763141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
2764141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].cap |=
2765141cc406Sopenharmony_ci    SANE_CAP_INACTIVE | SANE_CAP_AUTOMATIC | SANE_CAP_ADVANCED;
2766141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
2767141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
2768141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
2769141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
2770141cc406Sopenharmony_ci  session->val[OPT_GAMMA_VECTOR_G].wa = model->gamma;
2771141cc406Sopenharmony_ci
2772141cc406Sopenharmony_ci  /* blue gamma vector */
2773141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
2774141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
2775141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
2776141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
2777141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].cap |=
2778141cc406Sopenharmony_ci    SANE_CAP_INACTIVE | SANE_CAP_AUTOMATIC | SANE_CAP_ADVANCED;
2779141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
2780141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
2781141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
2782141cc406Sopenharmony_ci  session->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
2783141cc406Sopenharmony_ci  session->val[OPT_GAMMA_VECTOR_B].wa = model->gamma;
2784141cc406Sopenharmony_ci
2785141cc406Sopenharmony_ci  /* "Sensors" group */
2786141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS;
2787141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].name = SANE_NAME_SENSORS;
2788141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS;
2789141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP;
2790141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED;
2791141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].size = 0;
2792141cc406Sopenharmony_ci  session->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2793141cc406Sopenharmony_ci
2794141cc406Sopenharmony_ci  /* scanner buttons */
2795141cc406Sopenharmony_ci  for (i = OPT_BUTTON_1; i <= OPT_BUTTON_11; i++)
2796141cc406Sopenharmony_ci    {
2797141cc406Sopenharmony_ci      char name[39];
2798141cc406Sopenharmony_ci      char title[64];
2799141cc406Sopenharmony_ci
2800141cc406Sopenharmony_ci      idx = i - OPT_BUTTON_1;
2801141cc406Sopenharmony_ci
2802141cc406Sopenharmony_ci      if (idx < model->buttons)
2803141cc406Sopenharmony_ci	{
2804141cc406Sopenharmony_ci	  sprintf (name, "button-%s", model->button_name[idx]);
2805141cc406Sopenharmony_ci	  sprintf (title, "%s", model->button_title[idx]);
2806141cc406Sopenharmony_ci
2807141cc406Sopenharmony_ci	  session->opt[i].name = strdup (name);
2808141cc406Sopenharmony_ci	  session->opt[i].title = strdup (title);
2809141cc406Sopenharmony_ci	  session->opt[i].desc = SANE_I18N ("This option reflects the status "
2810141cc406Sopenharmony_ci					    "of a scanner button.");
2811141cc406Sopenharmony_ci	  session->opt[i].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
2812141cc406Sopenharmony_ci	}
2813141cc406Sopenharmony_ci      else
2814141cc406Sopenharmony_ci	{
2815141cc406Sopenharmony_ci	  session->opt[i].name = strdup ("unused");
2816141cc406Sopenharmony_ci	  session->opt[i].title = strdup ("unused button");
2817141cc406Sopenharmony_ci	  session->opt[i].cap |= SANE_CAP_INACTIVE;
2818141cc406Sopenharmony_ci	}
2819141cc406Sopenharmony_ci
2820141cc406Sopenharmony_ci      session->opt[i].type = SANE_TYPE_BOOL;
2821141cc406Sopenharmony_ci      session->opt[i].unit = SANE_UNIT_NONE;
2822141cc406Sopenharmony_ci      session->opt[i].size = sizeof (SANE_Bool);
2823141cc406Sopenharmony_ci      session->opt[i].constraint_type = SANE_CONSTRAINT_NONE;
2824141cc406Sopenharmony_ci      session->opt[i].constraint.range = 0;
2825141cc406Sopenharmony_ci      session->val[i].w = SANE_FALSE;
2826141cc406Sopenharmony_ci    }
2827141cc406Sopenharmony_ci
2828141cc406Sopenharmony_ci  update_button_status (session);
2829141cc406Sopenharmony_ci
2830141cc406Sopenharmony_ci  /* "Advanced" group: */
2831141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].title = SANE_I18N ("Advanced");
2832141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].desc = "";
2833141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
2834141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
2835141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].size = 0;
2836141cc406Sopenharmony_ci  session->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2837141cc406Sopenharmony_ci
2838141cc406Sopenharmony_ci  /* lamp on */
2839141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].name = "lamp-on";
2840141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].title = SANE_I18N ("Lamp on");
2841141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].desc = SANE_I18N ("Turn on scanner lamp");
2842141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].type = SANE_TYPE_BUTTON;
2843141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].cap |= SANE_CAP_ADVANCED;
2844141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].unit = SANE_UNIT_NONE;
2845141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].size = 0;
2846141cc406Sopenharmony_ci  session->opt[OPT_LAMP_ON].constraint_type = SANE_CONSTRAINT_NONE;
2847141cc406Sopenharmony_ci  session->val[OPT_LAMP_ON].w = 0;
2848141cc406Sopenharmony_ci
2849141cc406Sopenharmony_ci  /* lamp off */
2850141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].name = "lamp-off";
2851141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off");
2852141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].desc = SANE_I18N ("Turn off scanner lamp");
2853141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].type = SANE_TYPE_BUTTON;
2854141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].cap |= SANE_CAP_ADVANCED;
2855141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE;
2856141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].size = 0;
2857141cc406Sopenharmony_ci  session->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE;
2858141cc406Sopenharmony_ci  session->val[OPT_LAMP_OFF].w = 0;
2859141cc406Sopenharmony_ci
2860141cc406Sopenharmony_ci  DBG (DBG_proc, "init_options: exit\n");
2861141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2862141cc406Sopenharmony_ci}
2863141cc406Sopenharmony_ci
2864141cc406Sopenharmony_ci/**
2865141cc406Sopenharmony_ci * average scanned rgb data, returns the global average. Each channel avearge is also
2866141cc406Sopenharmony_ci * returned.
2867141cc406Sopenharmony_ci */
2868141cc406Sopenharmony_cistatic float
2869141cc406Sopenharmony_ciaverage_area (int color, SANE_Byte * data, int width, int height,
2870141cc406Sopenharmony_ci	      float *ra, float *ga, float *ba)
2871141cc406Sopenharmony_ci{
2872141cc406Sopenharmony_ci  int x, y;
2873141cc406Sopenharmony_ci  float global, pixels;
2874141cc406Sopenharmony_ci  float rc, gc, bc;
2875141cc406Sopenharmony_ci  pixels = width * height;
2876141cc406Sopenharmony_ci  *ra = 0;
2877141cc406Sopenharmony_ci  *ga = 0;
2878141cc406Sopenharmony_ci  *ba = 0;
2879141cc406Sopenharmony_ci  rc = 0;
2880141cc406Sopenharmony_ci  gc = 0;
2881141cc406Sopenharmony_ci  bc = 0;
2882141cc406Sopenharmony_ci  if (color == SANE_TRUE)
2883141cc406Sopenharmony_ci    {
2884141cc406Sopenharmony_ci      for (y = 0; y < height; y++)
2885141cc406Sopenharmony_ci	{
2886141cc406Sopenharmony_ci	  for (x = 0; x < width; x++)
2887141cc406Sopenharmony_ci	    {
2888141cc406Sopenharmony_ci	      rc += data[3 * width * y + x];
2889141cc406Sopenharmony_ci	      gc += data[3 * width * y + x + 1];
2890141cc406Sopenharmony_ci	      bc += data[3 * width * y + x + 2];
2891141cc406Sopenharmony_ci	    }
2892141cc406Sopenharmony_ci	}
2893141cc406Sopenharmony_ci      global = (rc + gc + bc) / (3 * pixels);
2894141cc406Sopenharmony_ci      *ra = rc / pixels;
2895141cc406Sopenharmony_ci      *ga = gc / pixels;
2896141cc406Sopenharmony_ci      *ba = bc / pixels;
2897141cc406Sopenharmony_ci    }
2898141cc406Sopenharmony_ci  else
2899141cc406Sopenharmony_ci    {
2900141cc406Sopenharmony_ci      for (y = 0; y < height; y++)
2901141cc406Sopenharmony_ci	{
2902141cc406Sopenharmony_ci	  for (x = 0; x < width; x++)
2903141cc406Sopenharmony_ci	    {
2904141cc406Sopenharmony_ci	      gc += data[width * y + x];
2905141cc406Sopenharmony_ci	    }
2906141cc406Sopenharmony_ci	}
2907141cc406Sopenharmony_ci      global = gc / pixels;
2908141cc406Sopenharmony_ci      *ga = gc / pixels;
2909141cc406Sopenharmony_ci    }
2910141cc406Sopenharmony_ci  DBG (7, "average_area: global=%.2f, red=%.2f, green=%.2f, blue=%.2f\n",
2911141cc406Sopenharmony_ci       global, *ra, *ga, *ba);
2912141cc406Sopenharmony_ci  return global;
2913141cc406Sopenharmony_ci}
2914141cc406Sopenharmony_ci
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci/**
2917141cc406Sopenharmony_ci * Sets lamp brightness (hum, maybe some timing before light off)
2918141cc406Sopenharmony_ci */
2919141cc406Sopenharmony_cistatic SANE_Status
2920141cc406Sopenharmony_ciset_lamp_brightness (struct Rts8891_Device *dev, int level)
2921141cc406Sopenharmony_ci{
2922141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
2923141cc406Sopenharmony_ci  SANE_Byte reg;
2924141cc406Sopenharmony_ci
2925141cc406Sopenharmony_ci  reg = 0xA0 | (level & 0x0F);
2926141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_BRIGHT_REG, &reg);
2927141cc406Sopenharmony_ci  switch (level)
2928141cc406Sopenharmony_ci    {
2929141cc406Sopenharmony_ci    case 0:
2930141cc406Sopenharmony_ci      reg = 0x8d;
2931141cc406Sopenharmony_ci      break;
2932141cc406Sopenharmony_ci    case 7:
2933141cc406Sopenharmony_ci      reg = 0x82;
2934141cc406Sopenharmony_ci      break;
2935141cc406Sopenharmony_ci    default:
2936141cc406Sopenharmony_ci      reg = 0x8d;
2937141cc406Sopenharmony_ci      break;
2938141cc406Sopenharmony_ci    }
2939141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
2940141cc406Sopenharmony_ci  reg = (reg & 0xF0) | 0x20 | ((~reg) & 0x0F);
2941141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = reg;
2942141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
2943141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2944141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2945141cc406Sopenharmony_ci  sanei_rts88xx_get_status (dev->devnum, dev->regs);
2946141cc406Sopenharmony_ci  DBG (DBG_io, "set_lamp_brightness: status=0x%02x 0x%02x\n", dev->regs[0x10],
2947141cc406Sopenharmony_ci       dev->regs[0x11]);
2948141cc406Sopenharmony_ci  if (dev->sensor != SENSOR_TYPE_4400)
2949141cc406Sopenharmony_ci    {
2950141cc406Sopenharmony_ci      dev->regs[0x10] = 0x28;
2951141cc406Sopenharmony_ci      dev->regs[0x11] = 0x3f;
2952141cc406Sopenharmony_ci    }
2953141cc406Sopenharmony_ci  else
2954141cc406Sopenharmony_ci    {
2955141cc406Sopenharmony_ci      dev->regs[0x10] = 0x10;
2956141cc406Sopenharmony_ci      dev->regs[0x11] = 0x2f;
2957141cc406Sopenharmony_ci    }
2958141cc406Sopenharmony_ci  reg = dev->regs[LAMP_REG];
2959141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
2960141cc406Sopenharmony_ci  status = sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &reg);
2961141cc406Sopenharmony_ci  if (reg != 0x00)
2962141cc406Sopenharmony_ci    {
2963141cc406Sopenharmony_ci      DBG (DBG_warn,
2964141cc406Sopenharmony_ci	   "set_lamp_brightness: unexpected CONTROL_REG value, 0x%02x instead of 0x00\n",
2965141cc406Sopenharmony_ci	   reg);
2966141cc406Sopenharmony_ci    }
2967141cc406Sopenharmony_ci  return status;
2968141cc406Sopenharmony_ci}
2969141cc406Sopenharmony_ci
2970141cc406Sopenharmony_ci
2971141cc406Sopenharmony_ci/**
2972141cc406Sopenharmony_ci * Sets the lamp to half brightness and standard parameters
2973141cc406Sopenharmony_ci */
2974141cc406Sopenharmony_cistatic SANE_Status
2975141cc406Sopenharmony_ciinit_lamp (struct Rts8891_Device *dev)
2976141cc406Sopenharmony_ci{
2977141cc406Sopenharmony_ci  SANE_Byte reg;
2978141cc406Sopenharmony_ci
2979141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
2980141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
2981141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2982141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2983141cc406Sopenharmony_ci  sanei_rts88xx_cancel (dev->devnum);
2984141cc406Sopenharmony_ci  dev->regs[0x12] = 0xff;
2985141cc406Sopenharmony_ci  dev->regs[0x13] = 0x20;
2986141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x12, dev->regs + 0x12, 2);
2987141cc406Sopenharmony_ci  /* 0xF8/0x28 expected */
2988141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x14, dev->regs + 0x14, 2);
2989141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2990141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
2991141cc406Sopenharmony_ci  if (dev->sensor != SENSOR_TYPE_4400 && dev->sensor != SENSOR_TYPE_4400_BARE)
2992141cc406Sopenharmony_ci    {
2993141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x3f);
2994141cc406Sopenharmony_ci      dev->regs[0x11] = 0x3f;
2995141cc406Sopenharmony_ci    }
2996141cc406Sopenharmony_ci  else
2997141cc406Sopenharmony_ci    {
2998141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x10, 0x22);
2999141cc406Sopenharmony_ci      dev->regs[0x11] = 0x22;
3000141cc406Sopenharmony_ci    }
3001141cc406Sopenharmony_ci  reg = 0x8d;
3002141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
3003141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = 0xa2;
3004141cc406Sopenharmony_ci  dev->regs[LAMP_BRIGHT_REG] = 0xa0;
3005141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
3006141cc406Sopenharmony_ci  return set_lamp_brightness (dev, 7);
3007141cc406Sopenharmony_ci}
3008141cc406Sopenharmony_ci
3009141cc406Sopenharmony_ci/**
3010141cc406Sopenharmony_ci * This function detects physical start of scanning area find finding a black area below the "roof"
3011141cc406Sopenharmony_ci * if during scan we detect that sensor is inadequate, changed is set to SANE_TRUE
3012141cc406Sopenharmony_ci */
3013141cc406Sopenharmony_cistatic SANE_Status
3014141cc406Sopenharmony_cifind_origin (struct Rts8891_Device *dev, SANE_Bool * changed)
3015141cc406Sopenharmony_ci{
3016141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
3017141cc406Sopenharmony_ci  SANE_Byte control, reg;
3018141cc406Sopenharmony_ci  unsigned int max = 0;
3019141cc406Sopenharmony_ci  unsigned char *image = NULL;
3020141cc406Sopenharmony_ci  unsigned char *data = NULL;
3021141cc406Sopenharmony_ci  SANE_Word total;
3022141cc406Sopenharmony_ci  int startx = 300;
3023141cc406Sopenharmony_ci  int width = 1200;
3024141cc406Sopenharmony_ci  int x, y, sum, current;
3025141cc406Sopenharmony_ci  int starty = 18;
3026141cc406Sopenharmony_ci  int height = 180;
3027141cc406Sopenharmony_ci  int timing;
3028141cc406Sopenharmony_ci
3029141cc406Sopenharmony_ci  DBG (DBG_proc, "find_origin: start\n");
3030141cc406Sopenharmony_ci
3031141cc406Sopenharmony_ci  /* check if head is at home
3032141cc406Sopenharmony_ci   * once sensor is correctly set up, we are always park here,
3033141cc406Sopenharmony_ci   * but in case sensor has just changed, we are not so we park head */
3034141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, &reg);
3035141cc406Sopenharmony_ci  if ((reg & 0x02) == 0)
3036141cc406Sopenharmony_ci    {
3037141cc406Sopenharmony_ci      if (park_head (dev, SANE_TRUE) != SANE_STATUS_GOOD)
3038141cc406Sopenharmony_ci	{
3039141cc406Sopenharmony_ci	  DBG (DBG_error, "find_origin: failed to park head!\n");
3040141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
3041141cc406Sopenharmony_ci	}
3042141cc406Sopenharmony_ci      DBG (DBG_info, "find_origin: head parked\n");
3043141cc406Sopenharmony_ci    }
3044141cc406Sopenharmony_ci
3045141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
3046141cc406Sopenharmony_ci  if (control != 0)
3047141cc406Sopenharmony_ci    {
3048141cc406Sopenharmony_ci      DBG (DBG_warn, "find_origin: unexpected control value 0x%02x\n",
3049141cc406Sopenharmony_ci	   control);
3050141cc406Sopenharmony_ci    }
3051141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
3052141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
3053141cc406Sopenharmony_ci  if (control != 0)
3054141cc406Sopenharmony_ci    {
3055141cc406Sopenharmony_ci      DBG (DBG_warn, "find_origin: unexpected control value 0x%02x\n",
3056141cc406Sopenharmony_ci	   control);
3057141cc406Sopenharmony_ci    }
3058141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
3059141cc406Sopenharmony_ci
3060141cc406Sopenharmony_ci  /* set lamp to standard settings */
3061141cc406Sopenharmony_ci  init_lamp (dev);
3062141cc406Sopenharmony_ci
3063141cc406Sopenharmony_ci  /* set scan parameters */
3064141cc406Sopenharmony_ci  dev->regs[0x00] = 0xe5;
3065141cc406Sopenharmony_ci  dev->regs[0x32] = 0x80;
3066141cc406Sopenharmony_ci  dev->regs[0x33] = 0x81;
3067141cc406Sopenharmony_ci  dev->regs[0x39] = 0x02;
3068141cc406Sopenharmony_ci  dev->regs[0x64] = 0x01;
3069141cc406Sopenharmony_ci  dev->regs[0x65] = 0x20;
3070141cc406Sopenharmony_ci  dev->regs[0x79] = 0x20;
3071141cc406Sopenharmony_ci  dev->regs[0x7a] = 0x01;
3072141cc406Sopenharmony_ci  dev->regs[0x90] = 0x1c;
3073141cc406Sopenharmony_ci
3074141cc406Sopenharmony_ci  dev->regs[0x35] = 0x1b;
3075141cc406Sopenharmony_ci  dev->regs[0x36] = 0x29;
3076141cc406Sopenharmony_ci  dev->regs[0x3a] = 0x1b;
3077141cc406Sopenharmony_ci  timing=0x32;
3078141cc406Sopenharmony_ci  dev->regs[0x85] = 0x00;
3079141cc406Sopenharmony_ci  dev->regs[0x86] = 0x06;
3080141cc406Sopenharmony_ci  dev->regs[0x87] = 0x00;
3081141cc406Sopenharmony_ci  dev->regs[0x88] = 0x06;
3082141cc406Sopenharmony_ci  dev->regs[0x8d] = 0x80;
3083141cc406Sopenharmony_ci  dev->regs[0x8e] = 0x68;
3084141cc406Sopenharmony_ci
3085141cc406Sopenharmony_ci  dev->regs[0xb2] = 0x02;	/* 0x04 -> no data */
3086141cc406Sopenharmony_ci
3087141cc406Sopenharmony_ci  dev->regs[0xc0] = 0xff;
3088141cc406Sopenharmony_ci  dev->regs[0xc1] = 0x0f;
3089141cc406Sopenharmony_ci  dev->regs[0xc3] = 0xff;
3090141cc406Sopenharmony_ci  dev->regs[0xc4] = 0xff;
3091141cc406Sopenharmony_ci  dev->regs[0xc5] = 0xff;
3092141cc406Sopenharmony_ci  dev->regs[0xc6] = 0xff;
3093141cc406Sopenharmony_ci  dev->regs[0xc7] = 0xff;
3094141cc406Sopenharmony_ci  dev->regs[0xc8] = 0xff;
3095141cc406Sopenharmony_ci  dev->regs[0xc9] = 0x00;
3096141cc406Sopenharmony_ci  dev->regs[0xca] = 0x0e;
3097141cc406Sopenharmony_ci  dev->regs[0xcb] = 0x00;
3098141cc406Sopenharmony_ci  dev->regs[0xcd] = 0xf0;
3099141cc406Sopenharmony_ci  dev->regs[0xce] = 0xff;
3100141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xf5;
3101141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xf7;
3102141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xea;
3103141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x0b;
3104141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x03;
3105141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x05;
3106141cc406Sopenharmony_ci  dev->regs[0xd6] = 0xab;
3107141cc406Sopenharmony_ci  dev->regs[0xd7] = 0x30;
3108141cc406Sopenharmony_ci  dev->regs[0xd8] = 0xf6;
3109141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x01;
3110141cc406Sopenharmony_ci  dev->regs[0xe3] = 0x00;
3111141cc406Sopenharmony_ci  dev->regs[0xe4] = 0x00;
3112141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 4124);
3113141cc406Sopenharmony_ci  /* dev->regs[0xe5] = 0x1c;
3114141cc406Sopenharmony_ci     dev->regs[0xe6] = 0x10;     101c=4124 */
3115141cc406Sopenharmony_ci  dev->regs[0xe7] = 0x00;
3116141cc406Sopenharmony_ci  dev->regs[0xe8] = 0x00;
3117141cc406Sopenharmony_ci  dev->regs[0xe9] = 0x00;
3118141cc406Sopenharmony_ci
3119141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
3120141cc406Sopenharmony_ci    {
3121141cc406Sopenharmony_ci      dev->regs[0xc3] = 0x00;
3122141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xf0;
3123141cc406Sopenharmony_ci      dev->regs[0xc7] = 0x0f;
3124141cc406Sopenharmony_ci      dev->regs[0xc8] = 0x00;
3125141cc406Sopenharmony_ci      dev->regs[0xc9] = 0xff;
3126141cc406Sopenharmony_ci      dev->regs[0xca] = 0xf1;
3127141cc406Sopenharmony_ci      dev->regs[0xcb] = 0xff;
3128141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x10;
3129141cc406Sopenharmony_ci    }
3130141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400 || dev->sensor == SENSOR_TYPE_4400_BARE)
3131141cc406Sopenharmony_ci    {
3132141cc406Sopenharmony_ci      /* 4400 values / 'XPA' values */
3133141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;	/* 0x20 */
3134141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;	/* 0xf8 */
3135141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;	/* 0x28 */
3136141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;	/* 0x07 */
3137141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;	/* 0x00 */
3138141cc406Sopenharmony_ci
3139141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;	/* 0xff */
3140141cc406Sopenharmony_ci
3141141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;	/* 0x02 */
3142141cc406Sopenharmony_ci    }
3143141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
3144141cc406Sopenharmony_ci    {
3145141cc406Sopenharmony_ci      dev->regs[0xc3] = 0xff;	/* 0x00 */
3146141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xff;	/* 0xf0 */
3147141cc406Sopenharmony_ci      dev->regs[0xc7] = 0xff;	/* 0x0f */
3148141cc406Sopenharmony_ci      dev->regs[0xc8] = 0xff;	/* 0x00 */
3149141cc406Sopenharmony_ci      dev->regs[0xc9] = 0x00;	/* 0xff */
3150141cc406Sopenharmony_ci      dev->regs[0xca] = 0x0e;	/* 0xf1 */
3151141cc406Sopenharmony_ci      dev->regs[0xcb] = 0x00;	/* 0xff */
3152141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x30;	/* 0x10 */
3153141cc406Sopenharmony_ci      dev->regs[0xda] = 0xa7;	/* 0xa0 */
3154141cc406Sopenharmony_ci    }
3155141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING_REG, timing);
3156141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING1_REG, timing+1);
3157141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING2_REG, timing+2);
3158141cc406Sopenharmony_ci
3159141cc406Sopenharmony_ci
3160141cc406Sopenharmony_ci  /* allocate memory for the data */
3161141cc406Sopenharmony_ci  total = width * height;
3162141cc406Sopenharmony_ci  data = (unsigned char *) malloc (total);
3163141cc406Sopenharmony_ci  if (data == NULL)
3164141cc406Sopenharmony_ci    {
3165141cc406Sopenharmony_ci      DBG (DBG_error, "find_origin: failed to allocate %d bytes\n", total);
3166141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3167141cc406Sopenharmony_ci    }
3168141cc406Sopenharmony_ci  image = (unsigned char *) malloc (total);
3169141cc406Sopenharmony_ci  if (image == NULL)
3170141cc406Sopenharmony_ci    {
3171141cc406Sopenharmony_ci      free(data);
3172141cc406Sopenharmony_ci      DBG (DBG_error, "find_origin: failed to allocate %d bytes\n", total);
3173141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3174141cc406Sopenharmony_ci    }
3175141cc406Sopenharmony_ci
3176141cc406Sopenharmony_ci  /* set vertical and horizontal start/end positions */
3177141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (dev->regs, starty, starty + height, startx,
3178141cc406Sopenharmony_ci			       startx + width);
3179141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (dev->regs, 0x7f, 0x7f, 0x7f);
3180141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, 0x10, 0x10, 0x10);
3181141cc406Sopenharmony_ci
3182141cc406Sopenharmony_ci  /* gray level scan */
3183141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = 0xad;
3184141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, dev->regs + LAMP_REG);
3185141cc406Sopenharmony_ci  if (dev->sensor != SENSOR_TYPE_4400
3186141cc406Sopenharmony_ci      && (dev->sensor != SENSOR_TYPE_4400_BARE))
3187141cc406Sopenharmony_ci    {
3188141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x20, 0x3b);
3189141cc406Sopenharmony_ci    }
3190141cc406Sopenharmony_ci  else
3191141cc406Sopenharmony_ci    {
3192141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x10, 0x22);
3193141cc406Sopenharmony_ci    }
3194141cc406Sopenharmony_ci
3195141cc406Sopenharmony_ci  status =
3196141cc406Sopenharmony_ci    rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, 0x03,
3197141cc406Sopenharmony_ci			 total, data);
3198141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3199141cc406Sopenharmony_ci    {
3200141cc406Sopenharmony_ci      free(image);
3201141cc406Sopenharmony_ci      free(data);
3202141cc406Sopenharmony_ci      DBG (DBG_error, "find_origin: failed to scan\n");
3203141cc406Sopenharmony_ci      return status;
3204141cc406Sopenharmony_ci    }
3205141cc406Sopenharmony_ci
3206141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io2)
3207141cc406Sopenharmony_ci    {
3208141cc406Sopenharmony_ci      write_gray_data (data, "find_origin.pnm", width, height);
3209141cc406Sopenharmony_ci    }
3210141cc406Sopenharmony_ci
3211141cc406Sopenharmony_ci  /* now we have the data, search for the black area so that we can      */
3212141cc406Sopenharmony_ci  /* deduce start of scan area                                           */
3213141cc406Sopenharmony_ci  /* we apply an Y direction sobel filter to get reliable edge detection */
3214141cc406Sopenharmony_ci  /* Meanwhile we check that picture is correct, if not, sensor needs to */
3215141cc406Sopenharmony_ci  /* be changed .                                                        */
3216141cc406Sopenharmony_ci  /* TODO possibly check for insufficient warming                        */
3217141cc406Sopenharmony_ci  for (y = 1; y < height - 1; y++)
3218141cc406Sopenharmony_ci    for (x = 1; x < width - 1; x++)
3219141cc406Sopenharmony_ci      {
3220141cc406Sopenharmony_ci	/* if sensor is wrong, picture is black, so max will be low */
3221141cc406Sopenharmony_ci	if (data[y * width + x] > max)
3222141cc406Sopenharmony_ci	  max = data[y * width + x];
3223141cc406Sopenharmony_ci
3224141cc406Sopenharmony_ci	/* sobel y filter */
3225141cc406Sopenharmony_ci	current =
3226141cc406Sopenharmony_ci	  -data[(y - 1) * width + x + 1] - 2 * data[(y - 1) * width + x] -
3227141cc406Sopenharmony_ci	  data[(y - 1) * width + x - 1] + data[(y + 1) * width + x + 1] +
3228141cc406Sopenharmony_ci	  2 * data[(y + 1) * width + x] + data[(y + 1) * width + x - 1];
3229141cc406Sopenharmony_ci	if (current < 0)
3230141cc406Sopenharmony_ci	  current = -current;
3231141cc406Sopenharmony_ci	image[y * width + x] = current;
3232141cc406Sopenharmony_ci      }
3233141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io2)
3234141cc406Sopenharmony_ci    {
3235141cc406Sopenharmony_ci      write_gray_data (image, "find_origin_ysobel.pnm", width, height);
3236141cc406Sopenharmony_ci    }
3237141cc406Sopenharmony_ci
3238141cc406Sopenharmony_ci  /* sensor test */
3239141cc406Sopenharmony_ci  if (max < 10)
3240141cc406Sopenharmony_ci    {
3241141cc406Sopenharmony_ci      DBG (DBG_info,
3242141cc406Sopenharmony_ci	   "find_origin: sensor type needs to be changed (max=%d)\n", max);
3243141cc406Sopenharmony_ci      *changed = SANE_TRUE;
3244141cc406Sopenharmony_ci    }
3245141cc406Sopenharmony_ci  else
3246141cc406Sopenharmony_ci    {
3247141cc406Sopenharmony_ci      *changed = SANE_FALSE;
3248141cc406Sopenharmony_ci    }
3249141cc406Sopenharmony_ci
3250141cc406Sopenharmony_ci  /* the edge will be where the white area stops                     */
3251141cc406Sopenharmony_ci  /* we average y position of white->black transition on each column */
3252141cc406Sopenharmony_ci  sum = 0;
3253141cc406Sopenharmony_ci  for (x = 1; x < width - 1; x++)
3254141cc406Sopenharmony_ci    {
3255141cc406Sopenharmony_ci      for (y = 1; y < height - 2; y++)
3256141cc406Sopenharmony_ci	{
3257141cc406Sopenharmony_ci	  /* edge detection on each line */
3258141cc406Sopenharmony_ci	  if (image[x + (y + 1) * width] - image[x + y * width] >= 20)
3259141cc406Sopenharmony_ci	    {
3260141cc406Sopenharmony_ci	      sum += y;
3261141cc406Sopenharmony_ci	      break;
3262141cc406Sopenharmony_ci	    }
3263141cc406Sopenharmony_ci	}
3264141cc406Sopenharmony_ci    }
3265141cc406Sopenharmony_ci  sum /= width;
3266141cc406Sopenharmony_ci  DBG (DBG_info, "find_origin: scan area offset=%d lines\n", sum);
3267141cc406Sopenharmony_ci
3268141cc406Sopenharmony_ci  /* convert the detected value into max ydpi */
3269141cc406Sopenharmony_ci  dev->top_offset = (48 * dev->model->max_ydpi) / 300;
3270141cc406Sopenharmony_ci
3271141cc406Sopenharmony_ci  /* no we're done */
3272141cc406Sopenharmony_ci  free (image);
3273141cc406Sopenharmony_ci  free (data);
3274141cc406Sopenharmony_ci
3275141cc406Sopenharmony_ci  /* safe guard test against moving to far toward the top */
3276141cc406Sopenharmony_ci  if (sum > 11)
3277141cc406Sopenharmony_ci    {
3278141cc406Sopenharmony_ci      /* now go back to the white area so that calibration can work on it */
3279141cc406Sopenharmony_ci      dev->regs[0x35] = 0x0e;
3280141cc406Sopenharmony_ci      dev->regs[0x3a] = 0x0e;
3281141cc406Sopenharmony_ci
3282141cc406Sopenharmony_ci      dev->regs[0xb2] = 0x06;	/* no data (0x04) */
3283141cc406Sopenharmony_ci
3284141cc406Sopenharmony_ci      if (dev->sensor == SENSOR_TYPE_4400)
3285141cc406Sopenharmony_ci	{
3286141cc406Sopenharmony_ci	  dev->regs[0x36] = 0x21;	/* direction reverse (& ~0x08) */
3287141cc406Sopenharmony_ci
3288141cc406Sopenharmony_ci	  dev->regs[0xe2] = 0x03;	/* 0x01 */
3289141cc406Sopenharmony_ci
3290141cc406Sopenharmony_ci	  /* dev->regs[0xe5] = 0x0d;     0x1c
3291141cc406Sopenharmony_ci	     dev->regs[0xe6] = 0x08;     0x10 080d=2061=1030*2+1 */
3292141cc406Sopenharmony_ci	  SET_DOUBLE (dev->regs, EXPOSURE_REG, 2061);
3293141cc406Sopenharmony_ci	}
3294141cc406Sopenharmony_ci      else
3295141cc406Sopenharmony_ci	{
3296141cc406Sopenharmony_ci	  dev->regs[0x11] = 0x3f;	/* 0x3b */
3297141cc406Sopenharmony_ci
3298141cc406Sopenharmony_ci	  dev->regs[0x36] = 0x24;	/* direction reverse (& ~0x08) */
3299141cc406Sopenharmony_ci
3300141cc406Sopenharmony_ci	  dev->regs[0xe2] = 0x07;
3301141cc406Sopenharmony_ci
3302141cc406Sopenharmony_ci	  /*
3303141cc406Sopenharmony_ci	     dev->regs[0xe5] = 0x06;
3304141cc406Sopenharmony_ci	     dev->regs[0xe6] = 0x04;     406=1030 */
3305141cc406Sopenharmony_ci	  SET_DOUBLE (dev->regs, EXPOSURE_REG, 1030);
3306141cc406Sopenharmony_ci	}
3307141cc406Sopenharmony_ci
3308141cc406Sopenharmony_ci      /* move by a fixed amount relative to the 'top' of the scanner */
3309141cc406Sopenharmony_ci      sanei_rts88xx_set_scan_area (dev->regs, height - sum + 10,
3310141cc406Sopenharmony_ci				   height - sum + 11, 637, 893);
3311141cc406Sopenharmony_ci      rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
3312141cc406Sopenharmony_ci      rts8891_commit (dev->devnum, 0x03);
3313141cc406Sopenharmony_ci
3314141cc406Sopenharmony_ci      /* wait for the motor to stop */
3315141cc406Sopenharmony_ci      do
3316141cc406Sopenharmony_ci	{
3317141cc406Sopenharmony_ci	  status = sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &reg);
3318141cc406Sopenharmony_ci	}
3319141cc406Sopenharmony_ci      while ((reg & 0x08) == 0x08);
3320141cc406Sopenharmony_ci    }
3321141cc406Sopenharmony_ci
3322141cc406Sopenharmony_ci  DBG (DBG_proc, "find_origin: exit\n");
3323141cc406Sopenharmony_ci  return status;
3324141cc406Sopenharmony_ci}
3325141cc406Sopenharmony_ci
3326141cc406Sopenharmony_ci/**
3327141cc406Sopenharmony_ci * This function detects the left margin (ie x offset of scanning area) by doing
3328141cc406Sopenharmony_ci * a grey scan of the very beginning of the sensor and finding the start of the
3329141cc406Sopenharmony_ci * white area of calibration zone, which is start of usable pixels.
3330141cc406Sopenharmony_ci */
3331141cc406Sopenharmony_cistatic SANE_Status
3332141cc406Sopenharmony_cifind_margin (struct Rts8891_Device *dev)
3333141cc406Sopenharmony_ci{
3334141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
3335141cc406Sopenharmony_ci  unsigned char *data = NULL;
3336141cc406Sopenharmony_ci  SANE_Word total;
3337141cc406Sopenharmony_ci  int startx = 33;
3338141cc406Sopenharmony_ci  int width = 250;
3339141cc406Sopenharmony_ci  int x;
3340141cc406Sopenharmony_ci  int starty = 1;
3341141cc406Sopenharmony_ci  int height = 1;
3342141cc406Sopenharmony_ci  SANE_Byte reg = 0xa2;
3343141cc406Sopenharmony_ci  int timing=0;
3344141cc406Sopenharmony_ci
3345141cc406Sopenharmony_ci  DBG (DBG_proc, "find_margin: start\n");
3346141cc406Sopenharmony_ci
3347141cc406Sopenharmony_ci  /* increase brightness to have better margin detection */
3348141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_BRIGHT_REG, &reg);
3349141cc406Sopenharmony_ci
3350141cc406Sopenharmony_ci  /* maximum gain, offsets untouched */
3351141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400 || dev->sensor == SENSOR_TYPE_4400_BARE)
3352141cc406Sopenharmony_ci    {
3353141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x10, 0x23);
3354141cc406Sopenharmony_ci    }
3355141cc406Sopenharmony_ci  else
3356141cc406Sopenharmony_ci    {
3357141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x3b);
3358141cc406Sopenharmony_ci    }
3359141cc406Sopenharmony_ci
3360141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, 0x3f, 0x3f, 0x3f);
3361141cc406Sopenharmony_ci
3362141cc406Sopenharmony_ci  /* set scan parameters */
3363141cc406Sopenharmony_ci  dev->regs[0x33] = 0x01;
3364141cc406Sopenharmony_ci  dev->regs[0x34] = 0x10;
3365141cc406Sopenharmony_ci  dev->regs[0x35] = 0x1b;
3366141cc406Sopenharmony_ci  dev->regs[0x3a] = 0x1b;
3367141cc406Sopenharmony_ci
3368141cc406Sopenharmony_ci  dev->regs[0x72] = 0x3a;
3369141cc406Sopenharmony_ci  dev->regs[0x73] = 0x15;
3370141cc406Sopenharmony_ci  dev->regs[0x74] = 0x62;
3371141cc406Sopenharmony_ci
3372141cc406Sopenharmony_ci  timing=0;
3373141cc406Sopenharmony_ci
3374141cc406Sopenharmony_ci  dev->regs[0xc0] = 0xff;
3375141cc406Sopenharmony_ci  dev->regs[0xc1] = 0xff;
3376141cc406Sopenharmony_ci  dev->regs[0xc2] = 0xff;
3377141cc406Sopenharmony_ci  dev->regs[0xc3] = 0x00;
3378141cc406Sopenharmony_ci  dev->regs[0xc4] = 0xf0;
3379141cc406Sopenharmony_ci  dev->regs[0xc7] = 0x0f;
3380141cc406Sopenharmony_ci  dev->regs[0xc8] = 0x00;
3381141cc406Sopenharmony_ci  dev->regs[0xcb] = 0xe0;
3382141cc406Sopenharmony_ci  dev->regs[0xcc] = 0xff;
3383141cc406Sopenharmony_ci  dev->regs[0xcd] = 0xff;
3384141cc406Sopenharmony_ci  dev->regs[0xce] = 0xff;
3385141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xe9;
3386141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xeb;
3387141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x0c;
3388141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x0e;
3389141cc406Sopenharmony_ci  dev->regs[0xd6] = 0xab;
3390141cc406Sopenharmony_ci  dev->regs[0xd7] = 0x14;
3391141cc406Sopenharmony_ci  dev->regs[0xd8] = 0xf6;
3392141cc406Sopenharmony_ci
3393141cc406Sopenharmony_ci  dev->regs[0xda] = 0xa7;	/* XXX STEF XXX à l'origine, pas 'bare' */
3394141cc406Sopenharmony_ci
3395141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x01;
3396141cc406Sopenharmony_ci
3397141cc406Sopenharmony_ci  /* dev->regs[0xe5] = 0x7b;
3398141cc406Sopenharmony_ci     dev->regs[0xe6] = 0x15;     157b=5499 */
3399141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 5499);
3400141cc406Sopenharmony_ci
3401141cc406Sopenharmony_ci  dev->regs[0xe7] = 0x00;
3402141cc406Sopenharmony_ci  dev->regs[0xe8] = 0x00;
3403141cc406Sopenharmony_ci  dev->regs[0xe9] = 0x00;
3404141cc406Sopenharmony_ci  dev->regs[0xea] = 0x00;
3405141cc406Sopenharmony_ci  dev->regs[0xeb] = 0x00;
3406141cc406Sopenharmony_ci  dev->regs[0xec] = 0x00;
3407141cc406Sopenharmony_ci  dev->regs[0xed] = 0x00;
3408141cc406Sopenharmony_ci  dev->regs[0xef] = 0x00;
3409141cc406Sopenharmony_ci  dev->regs[0xf0] = 0x00;
3410141cc406Sopenharmony_ci  dev->regs[0xf2] = 0x00;
3411141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
3412141cc406Sopenharmony_ci    {
3413141cc406Sopenharmony_ci      dev->regs[0xc0] = 0x00;
3414141cc406Sopenharmony_ci      dev->regs[0xc1] = 0xf8;
3415141cc406Sopenharmony_ci      dev->regs[0xc2] = 0x7f;
3416141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xf8;
3417141cc406Sopenharmony_ci      dev->regs[0xc5] = 0x7f;
3418141cc406Sopenharmony_ci      dev->regs[0xc6] = 0x00;
3419141cc406Sopenharmony_ci      dev->regs[0xc7] = 0xf8;
3420141cc406Sopenharmony_ci      dev->regs[0xc8] = 0x7f;
3421141cc406Sopenharmony_ci      dev->regs[0xc9] = 0xff;
3422141cc406Sopenharmony_ci      dev->regs[0xca] = 0xff;
3423141cc406Sopenharmony_ci      dev->regs[0xcb] = 0x8f;
3424141cc406Sopenharmony_ci      dev->regs[0xcd] = 0x07;
3425141cc406Sopenharmony_ci      dev->regs[0xce] = 0x80;
3426141cc406Sopenharmony_ci      dev->regs[0xcf] = 0xea;
3427141cc406Sopenharmony_ci      dev->regs[0xd0] = 0xec;
3428141cc406Sopenharmony_ci      dev->regs[0xd1] = 0xf7;
3429141cc406Sopenharmony_ci      dev->regs[0xd2] = 0x00;
3430141cc406Sopenharmony_ci      dev->regs[0xd3] = 0x10;
3431141cc406Sopenharmony_ci      dev->regs[0xd4] = 0x12;
3432141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x31;
3433141cc406Sopenharmony_ci    }
3434141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
3435141cc406Sopenharmony_ci    {
3436141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;	/* 0x20 */
3437141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;	/* 0xf8 */
3438141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;	/* 0x28 */
3439141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;	/* 0x07 */
3440141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;	/* 0x00 */
3441141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;	/* 0xff */
3442141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;	/* 0x02 */
3443141cc406Sopenharmony_ci      dev->regs[0x85] = 0x46;	/* 0x00 */
3444141cc406Sopenharmony_ci      dev->regs[0x86] = 0x0b;	/* 0x06 */
3445141cc406Sopenharmony_ci      dev->regs[0x87] = 0x8c;	/* 0x00 */
3446141cc406Sopenharmony_ci      dev->regs[0x88] = 0x10;	/* 0x06 */
3447141cc406Sopenharmony_ci      dev->regs[0x8d] = 0x3b;	/* 0x00 */
3448141cc406Sopenharmony_ci      timing=0x00b0;
3449141cc406Sopenharmony_ci    }
3450141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING_REG, timing);
3451141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING1_REG, timing+1);
3452141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING2_REG, timing+2);
3453141cc406Sopenharmony_ci
3454141cc406Sopenharmony_ci  /* set vertical and horizontal start/end positions */
3455141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (dev->regs, starty, starty + height, startx,
3456141cc406Sopenharmony_ci			       startx + width);
3457141cc406Sopenharmony_ci
3458141cc406Sopenharmony_ci  /* allocate memory for the data */
3459141cc406Sopenharmony_ci  total = width * height;
3460141cc406Sopenharmony_ci  data = (unsigned char *) malloc (total);
3461141cc406Sopenharmony_ci  if (data == NULL)
3462141cc406Sopenharmony_ci    {
3463141cc406Sopenharmony_ci      DBG (DBG_error, "find_margin: failed to allocate %d bytes\n", total);
3464141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3465141cc406Sopenharmony_ci    }
3466141cc406Sopenharmony_ci
3467141cc406Sopenharmony_ci  /* gray level scan */
3468141cc406Sopenharmony_ci  status =
3469141cc406Sopenharmony_ci    rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, 0x0c,
3470141cc406Sopenharmony_ci			 total, data);
3471141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3472141cc406Sopenharmony_ci    {
3473141cc406Sopenharmony_ci      free(data);
3474141cc406Sopenharmony_ci      DBG (DBG_error, "find_margin: failed to scan\n");
3475141cc406Sopenharmony_ci      return status;
3476141cc406Sopenharmony_ci    }
3477141cc406Sopenharmony_ci
3478141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io2)
3479141cc406Sopenharmony_ci    {
3480141cc406Sopenharmony_ci      write_gray_data (data, "find_margin.pnm", width, height);
3481141cc406Sopenharmony_ci    }
3482141cc406Sopenharmony_ci
3483141cc406Sopenharmony_ci  /* we search from left to right the first white pixel */
3484141cc406Sopenharmony_ci  x = 0;
3485141cc406Sopenharmony_ci  while (x < width && data[x] < MARGIN_LEVEL)
3486141cc406Sopenharmony_ci    x++;
3487141cc406Sopenharmony_ci  if (x == width)
3488141cc406Sopenharmony_ci    {
3489141cc406Sopenharmony_ci      DBG (DBG_warn, "find_margin: failed to find left margin!\n");
3490141cc406Sopenharmony_ci      DBG (DBG_warn, "find_margin: using default...\n");
3491141cc406Sopenharmony_ci      x = 48 + 40;
3492141cc406Sopenharmony_ci    }
3493141cc406Sopenharmony_ci  DBG (DBG_info, "find_margin: scan area margin=%d pixels\n", x);
3494141cc406Sopenharmony_ci
3495141cc406Sopenharmony_ci  /* convert the detected value into max ydpi */
3496141cc406Sopenharmony_ci  dev->left_offset = ((x - 40) * dev->model->max_xdpi) / 150;
3497141cc406Sopenharmony_ci  DBG (DBG_info, "find_margin: left_offset=%d pixels\n", x);
3498141cc406Sopenharmony_ci
3499141cc406Sopenharmony_ci  /* no we're done */
3500141cc406Sopenharmony_ci  free (data);
3501141cc406Sopenharmony_ci
3502141cc406Sopenharmony_ci  DBG (DBG_proc, "find_margin: exit\n");
3503141cc406Sopenharmony_ci  return status;
3504141cc406Sopenharmony_ci}
3505141cc406Sopenharmony_ci
3506141cc406Sopenharmony_ci#ifdef FAST_INIT
3507141cc406Sopenharmony_ci/*
3508141cc406Sopenharmony_ci * This function initializes the device:
3509141cc406Sopenharmony_ci * 	- initial registers values
3510141cc406Sopenharmony_ci * 	- test if at home
3511141cc406Sopenharmony_ci * 	- head parking if needed
3512141cc406Sopenharmony_ci */
3513141cc406Sopenharmony_cistatic SANE_Status
3514141cc406Sopenharmony_ciinitialize_device (struct Rts8891_Device *dev)
3515141cc406Sopenharmony_ci{
3516141cc406Sopenharmony_ci  SANE_Status status;
3517141cc406Sopenharmony_ci  SANE_Byte reg, control;
3518141cc406Sopenharmony_ci
3519141cc406Sopenharmony_ci  DBG (DBG_proc, "initialize_device: start\n");
3520141cc406Sopenharmony_ci  if (dev->initialized == SANE_TRUE)
3521141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3522141cc406Sopenharmony_ci
3523141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x20, 0x28);
3524141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
3525141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
3526141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
3527141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
3528141cc406Sopenharmony_ci
3529141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0xb0, &control);
3530141cc406Sopenharmony_ci  DBG (DBG_io, "initialize_device: reg[0xb0]=0x%02x\n", control);
3531141cc406Sopenharmony_ci
3532141cc406Sopenharmony_ci  /* we expect to get 0x80 */
3533141cc406Sopenharmony_ci  if (control != 0x80)
3534141cc406Sopenharmony_ci    {
3535141cc406Sopenharmony_ci      DBG (DBG_warn,
3536141cc406Sopenharmony_ci	   "initialize_device: expected reg[0xb0]=0x80, got 0x%02x\n",
3537141cc406Sopenharmony_ci	   control);
3538141cc406Sopenharmony_ci      /* TODO fail here ??? */
3539141cc406Sopenharmony_ci    }
3540141cc406Sopenharmony_ci
3541141cc406Sopenharmony_ci  /* get lamp status */
3542141cc406Sopenharmony_ci  status = sanei_rts88xx_get_lamp_status (dev->devnum, dev->regs);
3543141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3544141cc406Sopenharmony_ci    {
3545141cc406Sopenharmony_ci      DBG (DBG_error, "initialize_device: failed to read lamp status!\n");
3546141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
3547141cc406Sopenharmony_ci    }
3548141cc406Sopenharmony_ci  DBG (DBG_io, "initialize_device: lamp status=0x%02x\n", dev->regs[0x8e]);
3549141cc406Sopenharmony_ci
3550141cc406Sopenharmony_ci  /* sensor type the one for 4470c sold with XPA is slightly different
3551141cc406Sopenharmony_ci   * than those sold bare, for this model we always start with xpa type sensor,
3552141cc406Sopenharmony_ci   * and change it later if we detect black scans in find_origin(). In case the
3553141cc406Sopenharmony_ci   * attach function set up the sensor type, we don't modify it */
3554141cc406Sopenharmony_ci  if (dev->sensor == -1)
3555141cc406Sopenharmony_ci    {
3556141cc406Sopenharmony_ci      dev->sensor = device->model->sensor;
3557141cc406Sopenharmony_ci    }
3558141cc406Sopenharmony_ci  DBG (DBG_info, "initialize_device: initial sensor type is %d\n", dev->sensor);
3559141cc406Sopenharmony_ci  DBG (DBG_info, "initialize_device: reg[8e]=0x%02x\n", dev->regs[0x8e]);
3560141cc406Sopenharmony_ci
3561141cc406Sopenharmony_ci  /* detects if warming up is needed */
3562141cc406Sopenharmony_ci  if ((dev->regs[0x8e] & 0x60) != 0x60)
3563141cc406Sopenharmony_ci    {
3564141cc406Sopenharmony_ci      DBG (DBG_info, "initialize_device: lamp needs warming\n");
3565141cc406Sopenharmony_ci      dev->needs_warming = SANE_TRUE;
3566141cc406Sopenharmony_ci    }
3567141cc406Sopenharmony_ci  else
3568141cc406Sopenharmony_ci    {
3569141cc406Sopenharmony_ci      dev->needs_warming = SANE_FALSE;
3570141cc406Sopenharmony_ci    }
3571141cc406Sopenharmony_ci
3572141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LAMP_REG, &reg);
3573141cc406Sopenharmony_ci
3574141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
3575141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
3576141cc406Sopenharmony_ci
3577141cc406Sopenharmony_ci  /* read scanner present register */
3578141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &control);
3579141cc406Sopenharmony_ci  if (control != 0x00 && control != 0x01)
3580141cc406Sopenharmony_ci    {
3581141cc406Sopenharmony_ci      DBG (DBG_warn,
3582141cc406Sopenharmony_ci	   "initialize_device: unexpected LINK_REG=0x%02x\n", control);
3583141cc406Sopenharmony_ci    }
3584141cc406Sopenharmony_ci
3585141cc406Sopenharmony_ci  /* head parking if needed */
3586141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, &control);
3587141cc406Sopenharmony_ci  if (!(control & 0x02))
3588141cc406Sopenharmony_ci    {
3589141cc406Sopenharmony_ci      if (park_head (dev, SANE_TRUE) != SANE_STATUS_GOOD)
3590141cc406Sopenharmony_ci	{
3591141cc406Sopenharmony_ci	  DBG (DBG_error, "initialize_device: failed to park head!\n");
3592141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
3593141cc406Sopenharmony_ci	}
3594141cc406Sopenharmony_ci    }
3595141cc406Sopenharmony_ci
3596141cc406Sopenharmony_ci  /* writes initial register set */
3597141cc406Sopenharmony_ci  dev->regs[0x00] = 0xe5;	/* 0xf5 */
3598141cc406Sopenharmony_ci  dev->regs[0x02] = 0x1f;	/* 0x00 */
3599141cc406Sopenharmony_ci  dev->regs[0x03] = 0x1f;	/* 0x00 */
3600141cc406Sopenharmony_ci  dev->regs[0x04] = 0x1f;	/* 0x00 */
3601141cc406Sopenharmony_ci  dev->regs[0x05] = 0x1f;	/* 0x00 */
3602141cc406Sopenharmony_ci  dev->regs[0x06] = 0x1f;	/* 0x00 */
3603141cc406Sopenharmony_ci  dev->regs[0x07] = 0x1f;	/* 0x00 */
3604141cc406Sopenharmony_ci  dev->regs[0x08] = 0x0a;	/* 0x00 */
3605141cc406Sopenharmony_ci  dev->regs[0x09] = 0x0a;	/* 0x00 */
3606141cc406Sopenharmony_ci  dev->regs[0x0a] = 0x0a;	/* 0x00 */
3607141cc406Sopenharmony_ci  dev->regs[0x10] = 0x28;	/* 0x60 */
3608141cc406Sopenharmony_ci  dev->regs[0x11] = 0x28;	/* 0x1b */
3609141cc406Sopenharmony_ci  dev->regs[0x13] = 0x20;	/* 0x3e */
3610141cc406Sopenharmony_ci  dev->regs[0x14] = 0xf8;	/* 0x00 */
3611141cc406Sopenharmony_ci  dev->regs[0x15] = 0x28;	/* 0x00 */
3612141cc406Sopenharmony_ci  dev->regs[0x16] = 0x07;	/* 0xff */
3613141cc406Sopenharmony_ci  dev->regs[0x17] = 0x00;	/* 0x3e */
3614141cc406Sopenharmony_ci  dev->regs[0x18] = 0xff;	/* 0x00 */
3615141cc406Sopenharmony_ci  dev->regs[0x1d] = 0x20;	/* 0x22 */
3616141cc406Sopenharmony_ci
3617141cc406Sopenharmony_ci  /* LCD display */
3618141cc406Sopenharmony_ci  dev->regs[0x20] = 0x3a;	/* 0x00 */
3619141cc406Sopenharmony_ci  dev->regs[0x21] = 0xf2;	/* 0x00 */
3620141cc406Sopenharmony_ci  dev->regs[0x24] = 0xff;	/* 0x00 */
3621141cc406Sopenharmony_ci  dev->regs[0x25] = 0x00;	/* 0xff */
3622141cc406Sopenharmony_ci
3623141cc406Sopenharmony_ci  dev->regs[0x30] = 0x00;	/* 0x01 */
3624141cc406Sopenharmony_ci  dev->regs[0x31] = 0x00;	/* 0x42 */
3625141cc406Sopenharmony_ci  dev->regs[0x36] = 0x07;	/* 0x00 */
3626141cc406Sopenharmony_ci  dev->regs[0x39] = 0x00;	/* 0x02 */
3627141cc406Sopenharmony_ci  dev->regs[0x40] = 0x20;	/* 0x80 */
3628141cc406Sopenharmony_ci  dev->regs[0x44] = 0x8c;	/* 0x18 */
3629141cc406Sopenharmony_ci  dev->regs[0x45] = 0x76;	/* 0x00 */
3630141cc406Sopenharmony_ci  dev->regs[0x50] = 0x00;	/* 0x20 */
3631141cc406Sopenharmony_ci  dev->regs[0x51] = 0x00;	/* 0x24 */
3632141cc406Sopenharmony_ci  dev->regs[0x52] = 0x00;	/* 0x04 */
3633141cc406Sopenharmony_ci  dev->regs[0x64] = 0x00;	/* 0x10 */
3634141cc406Sopenharmony_ci  dev->regs[0x68] = 0x00;	/* 0x10 */
3635141cc406Sopenharmony_ci  dev->regs[0x6a] = 0x00;	/* 0x01 */
3636141cc406Sopenharmony_ci  dev->regs[0x70] = 0x00;	/* 0x20 */
3637141cc406Sopenharmony_ci  dev->regs[0x71] = 0x00;	/* 0x20 */
3638141cc406Sopenharmony_ci  dev->regs[0x72] = 0xe1;	/* 0x00 */
3639141cc406Sopenharmony_ci  dev->regs[0x73] = 0x14;	/* 0x00 */
3640141cc406Sopenharmony_ci  dev->regs[0x74] = 0x18;	/* 0x00 */
3641141cc406Sopenharmony_ci  dev->regs[0x75] = 0x15;	/* 0x00 */
3642141cc406Sopenharmony_ci  dev->regs[0x76] = 0x00;	/* 0x20 */
3643141cc406Sopenharmony_ci  dev->regs[0x77] = 0x00;	/* 0x01 */
3644141cc406Sopenharmony_ci  dev->regs[0x79] = 0x00;	/* 0x02 */
3645141cc406Sopenharmony_ci  dev->regs[0x81] = 0x00;	/* 0x41 */
3646141cc406Sopenharmony_ci  dev->regs[0x83] = 0x00;	/* 0x10 */
3647141cc406Sopenharmony_ci  dev->regs[0x84] = 0x00;	/* 0x21 */
3648141cc406Sopenharmony_ci  dev->regs[0x85] = 0x00;	/* 0x20 */
3649141cc406Sopenharmony_ci  dev->regs[0x87] = 0x00;	/* 0x20 */
3650141cc406Sopenharmony_ci  dev->regs[0x88] = 0x00;	/* 0x81 */
3651141cc406Sopenharmony_ci  dev->regs[0x89] = 0x00;	/* 0x20 */
3652141cc406Sopenharmony_ci  dev->regs[0x8a] = 0x00;	/* 0x01 */
3653141cc406Sopenharmony_ci  dev->regs[0x8b] = 0x00;	/* 0x01 */
3654141cc406Sopenharmony_ci  dev->regs[0x8d] = 0x80;	/* 0x22 */
3655141cc406Sopenharmony_ci  dev->regs[0x8e] = 0x68;	/* 0x00 */
3656141cc406Sopenharmony_ci  dev->regs[0x8f] = 0x00;	/* 0x40 */
3657141cc406Sopenharmony_ci  dev->regs[0x90] = 0x00;	/* 0x05 */
3658141cc406Sopenharmony_ci  dev->regs[0x93] = 0x02;	/* 0x01 */
3659141cc406Sopenharmony_ci  dev->regs[0x94] = 0x0e;	/* 0x1e */
3660141cc406Sopenharmony_ci  dev->regs[0xb0] = 0x00;	/* 0x80 */
3661141cc406Sopenharmony_ci  dev->regs[0xb2] = 0x02;	/* 0x06 */
3662141cc406Sopenharmony_ci  dev->regs[0xc0] = 0xff;	/* 0x00 */
3663141cc406Sopenharmony_ci  dev->regs[0xc1] = 0x0f;	/* 0x00 */
3664141cc406Sopenharmony_ci  dev->regs[0xc3] = 0xff;	/* 0x00 */
3665141cc406Sopenharmony_ci  dev->regs[0xc4] = 0xff;	/* 0x00 */
3666141cc406Sopenharmony_ci  dev->regs[0xc5] = 0xff;	/* 0x00 */
3667141cc406Sopenharmony_ci  dev->regs[0xc6] = 0xff;	/* 0x00 */
3668141cc406Sopenharmony_ci  dev->regs[0xc7] = 0xff;	/* 0x00 */
3669141cc406Sopenharmony_ci  dev->regs[0xc8] = 0xff;	/* 0x00 */
3670141cc406Sopenharmony_ci  dev->regs[0xca] = 0x0e;	/* 0x00 */
3671141cc406Sopenharmony_ci  dev->regs[0xcd] = 0xf0;	/* 0x00 */
3672141cc406Sopenharmony_ci  dev->regs[0xce] = 0xff;	/* 0x00 */
3673141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xf5;	/* 0x00 */
3674141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xf7;	/* 0x00 */
3675141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xea;	/* 0x00 */
3676141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x0b;	/* 0x00 */
3677141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x03;	/* 0x00 */
3678141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x05;	/* 0x01 */
3679141cc406Sopenharmony_ci  dev->regs[0xd5] = 0x86;	/* 0x06 */
3680141cc406Sopenharmony_ci  dev->regs[0xd7] = 0x30;	/* 0x10 */
3681141cc406Sopenharmony_ci  dev->regs[0xd8] = 0xf6;	/* 0x7a */
3682141cc406Sopenharmony_ci  dev->regs[0xd9] = 0x80;	/* 0x00 */
3683141cc406Sopenharmony_ci  dev->regs[0xda] = 0x00;	/* 0x15 */
3684141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x01;	/* 0x00 */
3685141cc406Sopenharmony_ci  /* dev->regs[0xe5] = 0x14;     0x0f */
3686141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 20);
3687141cc406Sopenharmony_ci
3688141cc406Sopenharmony_ci  status = rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
3689141cc406Sopenharmony_ci
3690141cc406Sopenharmony_ci  DBG (DBG_proc, "initialize_device: exit\n");
3691141cc406Sopenharmony_ci  dev->initialized = SANE_TRUE;
3692141cc406Sopenharmony_ci
3693141cc406Sopenharmony_ci  return status;
3694141cc406Sopenharmony_ci}
3695141cc406Sopenharmony_ci#else /* FAST_INIT */
3696141cc406Sopenharmony_ci
3697141cc406Sopenharmony_cistatic SANE_Status
3698141cc406Sopenharmony_ciinit_registers (struct Rts8891_Device *dev)
3699141cc406Sopenharmony_ci{
3700141cc406Sopenharmony_ciint i;
3701141cc406Sopenharmony_ci
3702141cc406Sopenharmony_ci  /* initial set written to scanner
3703141cc406Sopenharmony_ci   * 0xe5 0x41 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x0a 0x0a 0x0a 0x70 0x00 0x00 0x00 0x00 0x60 0x1b 0x08 0x20 0x00 0x20 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x00 0x00 0x3a 0xf2 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x10 0x00 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x00 0x00 0x00 0x8c 0x76 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x68 0x00 0x00 0x00 0x00 0x02 0x0e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xcc 0x27 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 ---- 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xe0 0x00 0x00 0x00 0x00 0x86 0x1b 0x00 0xff 0x00 0x27 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
3704141cc406Sopenharmony_ci   */
3705141cc406Sopenharmony_ci  /* lengthy set up to make register content obvious, may be some day I will
3706141cc406Sopenharmony_ci   * group corresponding values between models */
3707141cc406Sopenharmony_ci  switch (dev->sensor)
3708141cc406Sopenharmony_ci    {
3709141cc406Sopenharmony_ci    case SENSOR_TYPE_BARE:
3710141cc406Sopenharmony_ci    case SENSOR_TYPE_XPA:
3711141cc406Sopenharmony_ci      dev->regs[0x01] = 0x41;
3712141cc406Sopenharmony_ci      dev->regs[0x0b] = 0x70;
3713141cc406Sopenharmony_ci      dev->regs[0x0c] = 0x00;
3714141cc406Sopenharmony_ci      dev->regs[0x0d] = 0x00;
3715141cc406Sopenharmony_ci      dev->regs[0x0e] = 0x00;
3716141cc406Sopenharmony_ci      dev->regs[0x0f] = 0x00;
3717141cc406Sopenharmony_ci
3718141cc406Sopenharmony_ci      dev->regs[0x12] = 0x00;
3719141cc406Sopenharmony_ci      dev->regs[0x13] = 0x20;
3720141cc406Sopenharmony_ci      dev->regs[0x14] = 0x00;
3721141cc406Sopenharmony_ci      dev->regs[0x15] = 0x20;
3722141cc406Sopenharmony_ci      dev->regs[0x16] = 0x00;
3723141cc406Sopenharmony_ci      dev->regs[0x17] = 0x00;
3724141cc406Sopenharmony_ci      dev->regs[0x18] = 0x00;
3725141cc406Sopenharmony_ci      dev->regs[0x19] = 0x00;
3726141cc406Sopenharmony_ci      dev->regs[0x1a] = 0x00;
3727141cc406Sopenharmony_ci      dev->regs[0x1b] = 0x00;
3728141cc406Sopenharmony_ci      dev->regs[0x1c] = 0x00;
3729141cc406Sopenharmony_ci      dev->regs[0x1d] = 0x20;
3730141cc406Sopenharmony_ci      dev->regs[0x1e] = 0x00;
3731141cc406Sopenharmony_ci      dev->regs[0x1f] = 0x00;
3732141cc406Sopenharmony_ci
3733141cc406Sopenharmony_ci      /* LCD display */
3734141cc406Sopenharmony_ci      dev->regs[0x20] = 0x3a;
3735141cc406Sopenharmony_ci      dev->regs[0x21] = 0xf2;
3736141cc406Sopenharmony_ci      dev->regs[0x22] = 0x00;
3737141cc406Sopenharmony_ci
3738141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;
3739141cc406Sopenharmony_ci      dev->regs[0x24] = 0x00;
3740141cc406Sopenharmony_ci      dev->regs[0x25] = 0x00;
3741141cc406Sopenharmony_ci      dev->regs[0x26] = 0x00;
3742141cc406Sopenharmony_ci      dev->regs[0x27] = 0x00;
3743141cc406Sopenharmony_ci      dev->regs[0x28] = 0x00;
3744141cc406Sopenharmony_ci      dev->regs[0x29] = 0x00;
3745141cc406Sopenharmony_ci      dev->regs[0x2a] = 0x00;
3746141cc406Sopenharmony_ci      dev->regs[0x2b] = 0x00;
3747141cc406Sopenharmony_ci      dev->regs[0x2c] = 0x00;
3748141cc406Sopenharmony_ci      dev->regs[0x2d] = 0x00;
3749141cc406Sopenharmony_ci      dev->regs[0x2e] = 0x00;
3750141cc406Sopenharmony_ci      dev->regs[0x2f] = 0x00;
3751141cc406Sopenharmony_ci      dev->regs[0x30] = 0x00;
3752141cc406Sopenharmony_ci      dev->regs[0x31] = 0x00;
3753141cc406Sopenharmony_ci      dev->regs[0x32] = 0x00;
3754141cc406Sopenharmony_ci      dev->regs[0x33] = 0x00;
3755141cc406Sopenharmony_ci      dev->regs[0x34] = 0x10;
3756141cc406Sopenharmony_ci      dev->regs[0x35] = 0x00;
3757141cc406Sopenharmony_ci      dev->regs[0x36] = 0x07;
3758141cc406Sopenharmony_ci      dev->regs[0x37] = 0x00;
3759141cc406Sopenharmony_ci      dev->regs[0x38] = 0x00;
3760141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;
3761141cc406Sopenharmony_ci      dev->regs[0x3a] = 0x00;
3762141cc406Sopenharmony_ci      dev->regs[0x3b] = 0x00;
3763141cc406Sopenharmony_ci      dev->regs[0x3c] = 0x00;
3764141cc406Sopenharmony_ci      dev->regs[0x3d] = 0x00;
3765141cc406Sopenharmony_ci      dev->regs[0x3e] = 0x00;
3766141cc406Sopenharmony_ci      dev->regs[0x3f] = 0x00;
3767141cc406Sopenharmony_ci      dev->regs[0x40] = 0x20;
3768141cc406Sopenharmony_ci      dev->regs[0x41] = 0x00;
3769141cc406Sopenharmony_ci      dev->regs[0x42] = 0x00;
3770141cc406Sopenharmony_ci      dev->regs[0x43] = 0x00;
3771141cc406Sopenharmony_ci      dev->regs[0x44] = 0x8c;
3772141cc406Sopenharmony_ci      dev->regs[0x45] = 0x76;
3773141cc406Sopenharmony_ci      dev->regs[0x46] = 0x00;
3774141cc406Sopenharmony_ci      dev->regs[0x47] = 0x00;
3775141cc406Sopenharmony_ci      dev->regs[0x48] = 0x00;
3776141cc406Sopenharmony_ci      dev->regs[0x49] = 0x00;
3777141cc406Sopenharmony_ci      dev->regs[0x4a] = 0x00;
3778141cc406Sopenharmony_ci      dev->regs[0x4b] = 0x00;
3779141cc406Sopenharmony_ci      dev->regs[0x4c] = 0x00;
3780141cc406Sopenharmony_ci      dev->regs[0x4d] = 0x00;
3781141cc406Sopenharmony_ci      dev->regs[0x4e] = 0x00;
3782141cc406Sopenharmony_ci      dev->regs[0x4f] = 0x00;
3783141cc406Sopenharmony_ci      dev->regs[0x50] = 0x00;
3784141cc406Sopenharmony_ci      dev->regs[0x51] = 0x00;
3785141cc406Sopenharmony_ci      dev->regs[0x52] = 0x00;
3786141cc406Sopenharmony_ci      dev->regs[0x53] = 0x00;
3787141cc406Sopenharmony_ci      dev->regs[0x54] = 0x00;
3788141cc406Sopenharmony_ci      dev->regs[0x55] = 0x00;
3789141cc406Sopenharmony_ci      dev->regs[0x56] = 0x00;
3790141cc406Sopenharmony_ci      dev->regs[0x57] = 0x00;
3791141cc406Sopenharmony_ci      dev->regs[0x58] = 0x00;
3792141cc406Sopenharmony_ci      dev->regs[0x59] = 0x00;
3793141cc406Sopenharmony_ci      dev->regs[0x5a] = 0x00;
3794141cc406Sopenharmony_ci      dev->regs[0x5b] = 0x00;
3795141cc406Sopenharmony_ci      dev->regs[0x5c] = 0x00;
3796141cc406Sopenharmony_ci      dev->regs[0x5d] = 0x00;
3797141cc406Sopenharmony_ci      dev->regs[0x5e] = 0x00;
3798141cc406Sopenharmony_ci      dev->regs[0x5f] = 0x00;
3799141cc406Sopenharmony_ci      dev->regs[0x64] = 0x00;
3800141cc406Sopenharmony_ci      dev->regs[0x65] = 0x00;
3801141cc406Sopenharmony_ci      dev->regs[0x66] = 0x00;
3802141cc406Sopenharmony_ci      dev->regs[0x67] = 0x00;
3803141cc406Sopenharmony_ci      dev->regs[0x68] = 0x00;
3804141cc406Sopenharmony_ci      dev->regs[0x69] = 0x00;
3805141cc406Sopenharmony_ci      dev->regs[0x6a] = 0x00;
3806141cc406Sopenharmony_ci      dev->regs[0x6b] = 0x00;
3807141cc406Sopenharmony_ci      dev->regs[0x6e] = 0x00;
3808141cc406Sopenharmony_ci      dev->regs[0x6f] = 0x00;
3809141cc406Sopenharmony_ci      dev->regs[0x70] = 0x00;
3810141cc406Sopenharmony_ci      dev->regs[0x71] = 0x00;
3811141cc406Sopenharmony_ci      dev->regs[0x72] = 0x00;
3812141cc406Sopenharmony_ci      dev->regs[0x73] = 0x00;
3813141cc406Sopenharmony_ci      dev->regs[0x74] = 0x00;
3814141cc406Sopenharmony_ci      dev->regs[0x75] = 0x00;
3815141cc406Sopenharmony_ci      dev->regs[0x76] = 0x00;
3816141cc406Sopenharmony_ci      dev->regs[0x77] = 0x00;
3817141cc406Sopenharmony_ci      dev->regs[0x78] = 0x00;
3818141cc406Sopenharmony_ci      dev->regs[0x79] = 0x00;
3819141cc406Sopenharmony_ci      dev->regs[0x7a] = 0x00;
3820141cc406Sopenharmony_ci      dev->regs[0x7b] = 0x00;
3821141cc406Sopenharmony_ci      dev->regs[0x7c] = 0x00;
3822141cc406Sopenharmony_ci      dev->regs[0x7d] = 0x00;
3823141cc406Sopenharmony_ci      dev->regs[0x7e] = 0x00;
3824141cc406Sopenharmony_ci      dev->regs[0x7f] = 0x00;
3825141cc406Sopenharmony_ci      dev->regs[0x80] = 0x00;
3826141cc406Sopenharmony_ci      dev->regs[0x81] = 0x00;
3827141cc406Sopenharmony_ci      dev->regs[0x82] = 0x00;
3828141cc406Sopenharmony_ci      dev->regs[0x83] = 0x00;
3829141cc406Sopenharmony_ci      dev->regs[0x84] = 0x00;
3830141cc406Sopenharmony_ci      dev->regs[0x85] = 0x00;
3831141cc406Sopenharmony_ci      dev->regs[0x86] = 0x00;
3832141cc406Sopenharmony_ci      dev->regs[0x87] = 0x00;
3833141cc406Sopenharmony_ci      dev->regs[0x88] = 0x00;
3834141cc406Sopenharmony_ci      dev->regs[0x89] = 0x00;
3835141cc406Sopenharmony_ci      dev->regs[0x8a] = 0x00;
3836141cc406Sopenharmony_ci      dev->regs[0x8b] = 0x00;
3837141cc406Sopenharmony_ci      dev->regs[0x8c] = 0x00;
3838141cc406Sopenharmony_ci      dev->regs[0x8d] = 0x80;
3839141cc406Sopenharmony_ci      dev->regs[0x8e] = 0x68;
3840141cc406Sopenharmony_ci      dev->regs[0x8f] = 0x00;
3841141cc406Sopenharmony_ci      dev->regs[0x90] = 0x00;
3842141cc406Sopenharmony_ci      dev->regs[0x91] = 0x00;
3843141cc406Sopenharmony_ci      dev->regs[0x92] = 0x00;
3844141cc406Sopenharmony_ci      dev->regs[0x93] = 0x02;
3845141cc406Sopenharmony_ci      dev->regs[0x94] = 0x0e;
3846141cc406Sopenharmony_ci      dev->regs[0x95] = 0x00;
3847141cc406Sopenharmony_ci      dev->regs[0x96] = 0x00;
3848141cc406Sopenharmony_ci      dev->regs[0x97] = 0x00;
3849141cc406Sopenharmony_ci      dev->regs[0x98] = 0x00;
3850141cc406Sopenharmony_ci      dev->regs[0x99] = 0x00;
3851141cc406Sopenharmony_ci      dev->regs[0x9a] = 0x00;
3852141cc406Sopenharmony_ci      dev->regs[0x9b] = 0x00;
3853141cc406Sopenharmony_ci      dev->regs[0x9c] = 0x00;
3854141cc406Sopenharmony_ci      dev->regs[0x9d] = 0x00;
3855141cc406Sopenharmony_ci      dev->regs[0x9e] = 0x00;
3856141cc406Sopenharmony_ci      dev->regs[0x9f] = 0x00;
3857141cc406Sopenharmony_ci      dev->regs[0xa0] = 0x00;
3858141cc406Sopenharmony_ci      dev->regs[0xa1] = 0x00;
3859141cc406Sopenharmony_ci      dev->regs[0xa2] = 0x00;
3860141cc406Sopenharmony_ci      dev->regs[0xa3] = 0xcc;
3861141cc406Sopenharmony_ci      dev->regs[0xa4] = 0x27;
3862141cc406Sopenharmony_ci      dev->regs[0xa5] = 0x64;
3863141cc406Sopenharmony_ci      dev->regs[0xa6] = 0x00;
3864141cc406Sopenharmony_ci      dev->regs[0xa7] = 0x00;
3865141cc406Sopenharmony_ci      dev->regs[0xa8] = 0x00;
3866141cc406Sopenharmony_ci      dev->regs[0xa9] = 0x00;
3867141cc406Sopenharmony_ci      dev->regs[0xaa] = 0x00;
3868141cc406Sopenharmony_ci      dev->regs[0xab] = 0x00;
3869141cc406Sopenharmony_ci      dev->regs[0xac] = 0x00;
3870141cc406Sopenharmony_ci      dev->regs[0xad] = 0x00;
3871141cc406Sopenharmony_ci      dev->regs[0xae] = 0x00;
3872141cc406Sopenharmony_ci      dev->regs[0xaf] = 0x00;
3873141cc406Sopenharmony_ci      dev->regs[0xb0] = 0x00;
3874141cc406Sopenharmony_ci      dev->regs[0xb1] = 0x00;
3875141cc406Sopenharmony_ci      dev->regs[0xb2] = 0x02;
3876141cc406Sopenharmony_ci      dev->regs[0xb4] = 0x00;
3877141cc406Sopenharmony_ci      dev->regs[0xb5] = 0x00;
3878141cc406Sopenharmony_ci      dev->regs[0xb6] = 0x00;
3879141cc406Sopenharmony_ci      dev->regs[0xb7] = 0x00;
3880141cc406Sopenharmony_ci      dev->regs[0xb8] = 0x00;
3881141cc406Sopenharmony_ci      dev->regs[0xb9] = 0x00;
3882141cc406Sopenharmony_ci      dev->regs[0xba] = 0x00;
3883141cc406Sopenharmony_ci      dev->regs[0xbb] = 0x00;
3884141cc406Sopenharmony_ci      dev->regs[0xbc] = 0x00;
3885141cc406Sopenharmony_ci      dev->regs[0xbd] = 0x00;
3886141cc406Sopenharmony_ci      dev->regs[0xbe] = 0x00;
3887141cc406Sopenharmony_ci      dev->regs[0xbf] = 0x00;
3888141cc406Sopenharmony_ci      dev->regs[0xc0] = 0x00;
3889141cc406Sopenharmony_ci      dev->regs[0xc1] = 0x00;
3890141cc406Sopenharmony_ci      dev->regs[0xc2] = 0x00;
3891141cc406Sopenharmony_ci      dev->regs[0xc3] = 0x00;
3892141cc406Sopenharmony_ci      dev->regs[0xc4] = 0x00;
3893141cc406Sopenharmony_ci      dev->regs[0xc5] = 0x00;
3894141cc406Sopenharmony_ci      dev->regs[0xc6] = 0x00;
3895141cc406Sopenharmony_ci      dev->regs[0xc7] = 0x00;
3896141cc406Sopenharmony_ci      dev->regs[0xc8] = 0x00;
3897141cc406Sopenharmony_ci      dev->regs[0xc9] = 0x00;
3898141cc406Sopenharmony_ci      dev->regs[0xca] = 0x00;
3899141cc406Sopenharmony_ci      dev->regs[0xcb] = 0x00;
3900141cc406Sopenharmony_ci      dev->regs[0xcc] = 0x00;
3901141cc406Sopenharmony_ci      dev->regs[0xcd] = 0x00;
3902141cc406Sopenharmony_ci      dev->regs[0xce] = 0x00;
3903141cc406Sopenharmony_ci      dev->regs[0xcf] = 0x00;
3904141cc406Sopenharmony_ci      dev->regs[0xd0] = 0x00;
3905141cc406Sopenharmony_ci      dev->regs[0xd1] = 0x00;
3906141cc406Sopenharmony_ci      dev->regs[0xd2] = 0x00;
3907141cc406Sopenharmony_ci      dev->regs[0xd3] = 0x00;
3908141cc406Sopenharmony_ci      dev->regs[0xd4] = 0x00;
3909141cc406Sopenharmony_ci      dev->regs[0xd5] = 0x86;
3910141cc406Sopenharmony_ci      dev->regs[0xd6] = 0x1b;
3911141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x00;
3912141cc406Sopenharmony_ci      dev->regs[0xd8] = 0xff;
3913141cc406Sopenharmony_ci      dev->regs[0xd9] = 0x00;
3914141cc406Sopenharmony_ci      dev->regs[0xda] = 0x27;
3915141cc406Sopenharmony_ci      dev->regs[0xdb] = 0x00;
3916141cc406Sopenharmony_ci      dev->regs[0xdc] = 0x00;
3917141cc406Sopenharmony_ci      dev->regs[0xdd] = 0x00;
3918141cc406Sopenharmony_ci      dev->regs[0xde] = 0x00;
3919141cc406Sopenharmony_ci      dev->regs[0xdf] = 0x00;
3920141cc406Sopenharmony_ci      dev->regs[0xe0] = 0x00;
3921141cc406Sopenharmony_ci      dev->regs[0xe1] = 0x00;
3922141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x01;
3923141cc406Sopenharmony_ci      dev->regs[0xe3] = 0x00;
3924141cc406Sopenharmony_ci      dev->regs[0xe4] = 0x00;
3925141cc406Sopenharmony_ci
3926141cc406Sopenharmony_ci      /*dev->regs[0xe5] = 0x14;
3927141cc406Sopenharmony_ci         dev->regs[0xe6] = 0x00;    14=20 */
3928141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 20);
3929141cc406Sopenharmony_ci
3930141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x00;
3931141cc406Sopenharmony_ci      dev->regs[0xe8] = 0x00;
3932141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x00;
3933141cc406Sopenharmony_ci      dev->regs[0xea] = 0x00;
3934141cc406Sopenharmony_ci      dev->regs[0xeb] = 0x00;
3935141cc406Sopenharmony_ci      dev->regs[0xec] = 0x00;
3936141cc406Sopenharmony_ci      dev->regs[0xed] = 0x00;
3937141cc406Sopenharmony_ci      dev->regs[0xee] = 0x00;
3938141cc406Sopenharmony_ci      dev->regs[0xef] = 0x00;
3939141cc406Sopenharmony_ci      dev->regs[0xf0] = 0x00;
3940141cc406Sopenharmony_ci      dev->regs[0xf1] = 0x00;
3941141cc406Sopenharmony_ci      dev->regs[0xf2] = 0x00;
3942141cc406Sopenharmony_ci      dev->regs[0xf3] = 0x00;
3943141cc406Sopenharmony_ci      break;
3944141cc406Sopenharmony_ci    case SENSOR_TYPE_4400:
3945141cc406Sopenharmony_ci    case SENSOR_TYPE_4400_BARE:
3946141cc406Sopenharmony_ci      for (i = 0; i < dev->reg_count; i++)
3947141cc406Sopenharmony_ci	dev->regs[i] = 0x00;
3948141cc406Sopenharmony_ci      /* 2d may be 0x20 or 0x22: signals something */
3949141cc406Sopenharmony_ci      dev->regs[0x00] = 0xf5;
3950141cc406Sopenharmony_ci      dev->regs[0x01] = 0x41;
3951141cc406Sopenharmony_ci      dev->regs[0x0b] = 0x70;
3952141cc406Sopenharmony_ci      dev->regs[0x10] = 0x50;
3953141cc406Sopenharmony_ci      dev->regs[0x11] = 0x03;
3954141cc406Sopenharmony_ci      dev->regs[0x12] = 0xff;
3955141cc406Sopenharmony_ci      dev->regs[0x13] = 0x3e;
3956141cc406Sopenharmony_ci      dev->regs[0x16] = 0xff;
3957141cc406Sopenharmony_ci      dev->regs[0x17] = 0x3e;
3958141cc406Sopenharmony_ci      dev->regs[0x1d] = 0x22;
3959141cc406Sopenharmony_ci      dev->regs[0x22] = 0x01;
3960141cc406Sopenharmony_ci      dev->regs[0x23] = 0xff;
3961141cc406Sopenharmony_ci      dev->regs[0x25] = 0xfe;
3962141cc406Sopenharmony_ci      dev->regs[0x34] = 0x10;
3963141cc406Sopenharmony_ci      dev->regs[0x39] = 0x02;
3964141cc406Sopenharmony_ci      dev->regs[0x40] = 0x80;
3965141cc406Sopenharmony_ci      dev->regs[0x44] = 0x8c;
3966141cc406Sopenharmony_ci      dev->regs[0x45] = 0x76;
3967141cc406Sopenharmony_ci      dev->regs[0x50] = 0x20;
3968141cc406Sopenharmony_ci      dev->regs[0x8b] = 0xff;
3969141cc406Sopenharmony_ci      dev->regs[0x8c] = 0x3f;
3970141cc406Sopenharmony_ci      dev->regs[0x8d] = 0x80;
3971141cc406Sopenharmony_ci      dev->regs[0x8e] = 0x68;
3972141cc406Sopenharmony_ci      dev->regs[0x93] = 0x01;
3973141cc406Sopenharmony_ci      dev->regs[0x94] = 0x1e;
3974141cc406Sopenharmony_ci      dev->regs[0xa3] = 0xcc;
3975141cc406Sopenharmony_ci      dev->regs[0xa4] = 0x27;
3976141cc406Sopenharmony_ci      dev->regs[0xa5] = 0x64;
3977141cc406Sopenharmony_ci      dev->regs[0xb0] = 0x80;
3978141cc406Sopenharmony_ci      dev->regs[0xb1] = 0x01;
3979141cc406Sopenharmony_ci      dev->regs[0xb2] = 0x06;
3980141cc406Sopenharmony_ci      dev->regs[0xd4] = 0x01;
3981141cc406Sopenharmony_ci      dev->regs[0xd5] = 0x06;
3982141cc406Sopenharmony_ci      dev->regs[0xd6] = 0x1b;
3983141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x10;
3984141cc406Sopenharmony_ci      dev->regs[0xd8] = 0x7a;
3985141cc406Sopenharmony_ci      dev->regs[0xda] = 0xa7;
3986141cc406Sopenharmony_ci      dev->regs[0xe5] = 0x0f;
3987141cc406Sopenharmony_ci      if (dev->sensor == SENSOR_TYPE_4400_BARE)
3988141cc406Sopenharmony_ci	{
3989141cc406Sopenharmony_ci	  dev->regs[0x30] = 0x40;	/* 0x00 */
3990141cc406Sopenharmony_ci	  dev->regs[0x31] = 0x80;	/* 0x00 */
3991141cc406Sopenharmony_ci	  dev->regs[0x44] = 0x00;	/* 0x8c */
3992141cc406Sopenharmony_ci	  dev->regs[0x45] = 0x00;	/* 0x76 */
3993141cc406Sopenharmony_ci	  dev->regs[0x52] = 0x04;	/* 0x00 */
3994141cc406Sopenharmony_ci	  dev->regs[0x69] = 0x01;	/* 0x00 */
3995141cc406Sopenharmony_ci	  dev->regs[0x6a] = 0x10;	/* 0x00 */
3996141cc406Sopenharmony_ci	  dev->regs[0x6e] = 0x08;	/* 0x00 */
3997141cc406Sopenharmony_ci	  dev->regs[0x70] = 0x40;	/* 0x00 */
3998141cc406Sopenharmony_ci	  dev->regs[0x71] = 0x08;	/* 0x00 */
3999141cc406Sopenharmony_ci	  dev->regs[0x78] = 0x08;	/* 0x00 */
4000141cc406Sopenharmony_ci	  dev->regs[0x79] = 0x11;	/* 0x00 */
4001141cc406Sopenharmony_ci	  dev->regs[0x82] = 0x40;	/* 0x00 */
4002141cc406Sopenharmony_ci	  dev->regs[0x83] = 0x30;	/* 0x00 */
4003141cc406Sopenharmony_ci	  dev->regs[0x84] = 0x45;	/* 0x00 */
4004141cc406Sopenharmony_ci	  dev->regs[0x87] = 0x02;	/* 0x00 */
4005141cc406Sopenharmony_ci	  dev->regs[0x88] = 0x05;	/* 0x00 */
4006141cc406Sopenharmony_ci	  dev->regs[0x8b] = 0x01;	/* 0xff */
4007141cc406Sopenharmony_ci	  dev->regs[0x8c] = 0x80;	/* 0x3f */
4008141cc406Sopenharmony_ci	  dev->regs[0x8d] = 0x04;	/* 0x80 */
4009141cc406Sopenharmony_ci	  dev->regs[0x8e] = 0x10;	/* 0x68 */
4010141cc406Sopenharmony_ci	  dev->regs[0x8f] = 0x01;	/* 0x00 */
4011141cc406Sopenharmony_ci	  dev->regs[0x90] = 0x80;	/* 0x00 */
4012141cc406Sopenharmony_ci	}
4013141cc406Sopenharmony_ci      break;
4014141cc406Sopenharmony_ci    }
4015141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4016141cc406Sopenharmony_ci}
4017141cc406Sopenharmony_ci
4018141cc406Sopenharmony_ci/*
4019141cc406Sopenharmony_ci * This function initializes the device:
4020141cc406Sopenharmony_ci * 	- initial registers values
4021141cc406Sopenharmony_ci * 	- test if at home
4022141cc406Sopenharmony_ci * 	- head parking if needed
4023141cc406Sopenharmony_ci */
4024141cc406Sopenharmony_cistatic SANE_Status
4025141cc406Sopenharmony_ciinit_device (struct Rts8891_Device *dev)
4026141cc406Sopenharmony_ci{
4027141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
4028141cc406Sopenharmony_ci  SANE_Byte control, reg, id;
4029141cc406Sopenharmony_ci  SANE_Int i, page;
4030141cc406Sopenharmony_ci  SANE_Byte buffer[2072];
4031141cc406Sopenharmony_ci  char message[256 * 6];
4032141cc406Sopenharmony_ci  SANE_Int val;
4033141cc406Sopenharmony_ci
4034141cc406Sopenharmony_ci  /* these commands are used to access NVRAM through a serial manner */
4035141cc406Sopenharmony_ci  /* we ignore NVRAM settingsd for now                              */
4036141cc406Sopenharmony_ci  SANE_Byte nv_cmd1[21] =
4037141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x28, 0x38,
4038141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x08
4039141cc406Sopenharmony_ci  };
4040141cc406Sopenharmony_ci  SANE_Byte nv_cmd2[21] =
4041141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x28, 0x38,
4042141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x08
4043141cc406Sopenharmony_ci  };
4044141cc406Sopenharmony_ci  SANE_Byte nv_cmd3[21] =
4045141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x28, 0x38,
4046141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x28, 0x38, 0x08
4047141cc406Sopenharmony_ci  };
4048141cc406Sopenharmony_ci  SANE_Byte nv_cmd4[21] =
4049141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18,
4050141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x08
4051141cc406Sopenharmony_ci  };
4052141cc406Sopenharmony_ci  SANE_Byte nv_cmd5[21] =
4053141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18,
4054141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x08
4055141cc406Sopenharmony_ci  };
4056141cc406Sopenharmony_ci  SANE_Byte nv_cmd6[21] =
4057141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18,
4058141cc406Sopenharmony_ci    0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x28, 0x38, 0x08
4059141cc406Sopenharmony_ci  };
4060141cc406Sopenharmony_ci  SANE_Byte nv_cmd7[21] =
4061141cc406Sopenharmony_ci    { 0x28, 0x38, 0x28, 0x38, 0x08, 0x18, 0x28, 0x38, 0x28, 0x38, 0x08, 0x18,
4062141cc406Sopenharmony_ci    0x28, 0x38, 0x08, 0x18, 0x08, 0x18, 0x08, 0x18, 0x08
4063141cc406Sopenharmony_ci  };
4064141cc406Sopenharmony_ci
4065141cc406Sopenharmony_ci  DBG (DBG_proc, "init_device: start\n");
4066141cc406Sopenharmony_ci  if (dev->initialized == SANE_TRUE)
4067141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4068141cc406Sopenharmony_ci
4069141cc406Sopenharmony_ci  /* read control register, if busy, something will have to be done ... */
4070141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4071141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: control=0x%02x\n", control);
4072141cc406Sopenharmony_ci
4073141cc406Sopenharmony_ci  /* when just plugged, we expect to get 0x04 */
4074141cc406Sopenharmony_ci  if (control != 0x04)
4075141cc406Sopenharmony_ci    {
4076141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: expected control=0x04, got 0x%02x\n",
4077141cc406Sopenharmony_ci	   control);
4078141cc406Sopenharmony_ci    }
4079141cc406Sopenharmony_ci
4080141cc406Sopenharmony_ci  /* then read "link" register */
4081141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0xb0, &control);
4082141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: link=0x%02x\n", control);
4083141cc406Sopenharmony_ci
4084141cc406Sopenharmony_ci  /* we expect to get 0x80 */
4085141cc406Sopenharmony_ci  if (control != 0x80)
4086141cc406Sopenharmony_ci    {
4087141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: expected link=0x80, got 0x%02x\n",
4088141cc406Sopenharmony_ci	   control);
4089141cc406Sopenharmony_ci    }
4090141cc406Sopenharmony_ci
4091141cc406Sopenharmony_ci  /* reads scanner status */
4092141cc406Sopenharmony_ci  sanei_rts88xx_get_status (dev->devnum, dev->regs);
4093141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: status=0x%02x 0x%02x\n", dev->regs[0x10],
4094141cc406Sopenharmony_ci       dev->regs[0x11]);
4095141cc406Sopenharmony_ci
4096141cc406Sopenharmony_ci  /* reads lamp status and sensor information */
4097141cc406Sopenharmony_ci  sanei_rts88xx_get_lamp_status (dev->devnum, dev->regs);
4098141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: lamp status=0x%02x\n", dev->regs[0x8e]);
4099141cc406Sopenharmony_ci
4100141cc406Sopenharmony_ci  /* initialize sensor with default from model */
4101141cc406Sopenharmony_ci  dev->sensor = dev->model->sensor;
4102141cc406Sopenharmony_ci  DBG (DBG_info, "init_device: reg[8e]=0x%02x\n", dev->regs[0x8e]);
4103141cc406Sopenharmony_ci
4104141cc406Sopenharmony_ci  /* reset lamp */
4105141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
4106141cc406Sopenharmony_ci  if ((dev->regs[0x8e] & 0x60) != 0x60)
4107141cc406Sopenharmony_ci    {
4108141cc406Sopenharmony_ci      DBG (DBG_info, "init_device: lamp needs warming\n");
4109141cc406Sopenharmony_ci      dev->needs_warming = SANE_TRUE;
4110141cc406Sopenharmony_ci    }
4111141cc406Sopenharmony_ci  else
4112141cc406Sopenharmony_ci    {
4113141cc406Sopenharmony_ci      dev->needs_warming = SANE_FALSE;
4114141cc406Sopenharmony_ci    }
4115141cc406Sopenharmony_ci
4116141cc406Sopenharmony_ci  /* reads lcd panel status */
4117141cc406Sopenharmony_ci  sanei_rts88xx_get_lcd (dev->devnum, dev->regs);
4118141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: lcd panel=0x%02x 0x%02x 0x%02x\n",
4119141cc406Sopenharmony_ci       dev->regs[0x20], dev->regs[0x21], dev->regs[0x22]);
4120141cc406Sopenharmony_ci
4121141cc406Sopenharmony_ci  /* read mainboard ID/scanner present register */
4122141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &id);
4123141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: link=0x%02x\n", id);
4124141cc406Sopenharmony_ci
4125141cc406Sopenharmony_ci  /* only known ID is currently 0x00 or 0x01 */
4126141cc406Sopenharmony_ci  if (id != 0x00 && id != 0x01)
4127141cc406Sopenharmony_ci    {
4128141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: expected id=0x00 or 0x01, got 0x%02x\n",
4129141cc406Sopenharmony_ci	   id);
4130141cc406Sopenharmony_ci    }
4131141cc406Sopenharmony_ci
4132141cc406Sopenharmony_ci  /* write 0x00 twice to control */
4133141cc406Sopenharmony_ci  control = 0x00;
4134141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, control);
4135141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, control);
4136141cc406Sopenharmony_ci
4137141cc406Sopenharmony_ci  /* read initial register set */
4138141cc406Sopenharmony_ci  sanei_rts88xx_read_regs (dev->devnum, 0, dev->regs, dev->reg_count);
4139141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io2)
4140141cc406Sopenharmony_ci    {
4141141cc406Sopenharmony_ci      sprintf (message, "init_device: initial register settings: ");
4142141cc406Sopenharmony_ci      for (i = 0; i < dev->reg_count; i++)
4143141cc406Sopenharmony_ci	sprintf (message + strlen (message), "0x%02x ", dev->regs[i]);
4144141cc406Sopenharmony_ci
4145141cc406Sopenharmony_ci      DBG (DBG_io2, "%s\n", message);
4146141cc406Sopenharmony_ci    }
4147141cc406Sopenharmony_ci
4148141cc406Sopenharmony_ci  /* initial sensor guess */
4149141cc406Sopenharmony_ci  val = dev->regs[0x44] + 256 * dev->regs[0x45];
4150141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: R44/45=0x%04x\n", val);
4151141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
4152141cc406Sopenharmony_ci    {
4153141cc406Sopenharmony_ci      if(val != 0x00)
4154141cc406Sopenharmony_ci        {
4155141cc406Sopenharmony_ci          DBG (DBG_info, "init_device: SENSOR_TYPE_4400 detected\n");
4156141cc406Sopenharmony_ci        }
4157141cc406Sopenharmony_ci      else
4158141cc406Sopenharmony_ci        {
4159141cc406Sopenharmony_ci          DBG (DBG_info, "init_device: SENSOR_TYPE_4400_BARE detected\n");
4160141cc406Sopenharmony_ci          dev->sensor = SENSOR_TYPE_4400_BARE;
4161141cc406Sopenharmony_ci        }
4162141cc406Sopenharmony_ci    }
4163141cc406Sopenharmony_ci
4164141cc406Sopenharmony_ci  init_registers(dev);
4165141cc406Sopenharmony_ci
4166141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (dev->regs, 31, 31, 31);
4167141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, 10, 10, 10);
4168141cc406Sopenharmony_ci  dev->regs[0] = dev->regs[0] & 0xef;
4169141cc406Sopenharmony_ci
4170141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
4171141cc406Sopenharmony_ci  /* now read button status read_reg(0x1a,2)=0x00 0x00 */
4172141cc406Sopenharmony_ci  sanei_rts88xx_read_regs (dev->devnum, 0x1a, dev->regs + 0x1a, 2);
4173141cc406Sopenharmony_ci  /* we expect 0x00 0x00 here */
4174141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: 0x%02x 0x%02x\n", dev->regs[0x1a],
4175141cc406Sopenharmony_ci       dev->regs[0x1b]);
4176141cc406Sopenharmony_ci
4177141cc406Sopenharmony_ci  dev->regs[0xcf] = 0x00;
4178141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xe0;
4179141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
4180141cc406Sopenharmony_ci  sanei_rts88xx_read_regs (dev->devnum, 0x1a, dev->regs + 0x1a, 2);
4181141cc406Sopenharmony_ci  /* we expect 0x08 0x00 here */
4182141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: 0x%02x 0x%02x\n", dev->regs[0x1a],
4183141cc406Sopenharmony_ci       dev->regs[0x1b]);
4184141cc406Sopenharmony_ci
4185141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x20, 0x28);
4186141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x28);
4187141cc406Sopenharmony_ci  sanei_rts88xx_cancel (dev->devnum);
4188141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LAMP_REG, &control);
4189141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4190141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4191141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &id);
4192141cc406Sopenharmony_ci  if (id != 0x00 && id != 0x01)
4193141cc406Sopenharmony_ci    {
4194141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: got unexpected id 0x%02x\n", id);
4195141cc406Sopenharmony_ci    }
4196141cc406Sopenharmony_ci
4197141cc406Sopenharmony_ci
4198141cc406Sopenharmony_ci  dev->regs[0x12] = 0xff;
4199141cc406Sopenharmony_ci  dev->regs[0x14] = 0xf8;
4200141cc406Sopenharmony_ci  dev->regs[0x15] = 0x28;
4201141cc406Sopenharmony_ci  dev->regs[0x16] = 0x07;
4202141cc406Sopenharmony_ci  dev->regs[0x18] = 0xff;
4203141cc406Sopenharmony_ci  dev->regs[0x23] = 0xff;
4204141cc406Sopenharmony_ci  dev->regs[0x24] = 0xff;
4205141cc406Sopenharmony_ci
4206141cc406Sopenharmony_ci  dev->regs[0x72] = 0xe1;
4207141cc406Sopenharmony_ci  dev->regs[0x73] = 0x14;
4208141cc406Sopenharmony_ci  dev->regs[0x74] = 0x18;
4209141cc406Sopenharmony_ci  dev->regs[0x75] = 0x15;
4210141cc406Sopenharmony_ci  dev->regs[0xc0] = 0xff;
4211141cc406Sopenharmony_ci  dev->regs[0xc1] = 0x0f;
4212141cc406Sopenharmony_ci  dev->regs[0xc3] = 0xff;
4213141cc406Sopenharmony_ci  dev->regs[0xc4] = 0xff;
4214141cc406Sopenharmony_ci  dev->regs[0xc5] = 0xff;
4215141cc406Sopenharmony_ci  dev->regs[0xc6] = 0xff;
4216141cc406Sopenharmony_ci  dev->regs[0xc7] = 0xff;
4217141cc406Sopenharmony_ci  dev->regs[0xc8] = 0xff;
4218141cc406Sopenharmony_ci  dev->regs[0xca] = 0x0e;
4219141cc406Sopenharmony_ci  dev->regs[0xcd] = 0xf0;
4220141cc406Sopenharmony_ci  dev->regs[0xce] = 0xff;
4221141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xf5;
4222141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xf7;
4223141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xea;
4224141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x0b;
4225141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x03;
4226141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x05;
4227141cc406Sopenharmony_ci  dev->regs[0xd7] = 0x30;
4228141cc406Sopenharmony_ci  dev->regs[0xd8] = 0xf6;
4229141cc406Sopenharmony_ci  dev->regs[0xd9] = 0x80;
4230141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
4231141cc406Sopenharmony_ci
4232141cc406Sopenharmony_ci  /* now we are writing and reading back from memory, it is surely a memory test since the written data
4233141cc406Sopenharmony_ci   * don't look useful at first glance
4234141cc406Sopenharmony_ci   */
4235141cc406Sopenharmony_ci  reg = 0x06;
4236141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x93, &reg);
4237141cc406Sopenharmony_ci  for (i = 0; i < 2072; i++)
4238141cc406Sopenharmony_ci    {
4239141cc406Sopenharmony_ci      buffer[i] = i % 97;
4240141cc406Sopenharmony_ci    }
4241141cc406Sopenharmony_ci  sanei_rts88xx_set_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4242141cc406Sopenharmony_ci  sanei_rts88xx_get_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4243141cc406Sopenharmony_ci  /* check the data returned */
4244141cc406Sopenharmony_ci  for (i = 0; i < 2072; i++)
4245141cc406Sopenharmony_ci    {
4246141cc406Sopenharmony_ci      if (buffer[i] != id)
4247141cc406Sopenharmony_ci	{
4248141cc406Sopenharmony_ci	  DBG (DBG_error,
4249141cc406Sopenharmony_ci	       "init_device: memory at %d is not 0x%02d (0x%02x)\n", i, id,
4250141cc406Sopenharmony_ci	       buffer[i]);
4251141cc406Sopenharmony_ci	  /* XXX STEF XXX return SANE_STATUS_IO_ERROR; */
4252141cc406Sopenharmony_ci	}
4253141cc406Sopenharmony_ci    }
4254141cc406Sopenharmony_ci  DBG (DBG_info, "init_device: memory set #1 passed\n");
4255141cc406Sopenharmony_ci
4256141cc406Sopenharmony_ci  /* now test (or set?) #2 */
4257141cc406Sopenharmony_ci  reg = 0x02;
4258141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x93, &reg);
4259141cc406Sopenharmony_ci  for (i = 0; i < 2072; i++)
4260141cc406Sopenharmony_ci    {
4261141cc406Sopenharmony_ci      buffer[i] = i % 97;
4262141cc406Sopenharmony_ci    }
4263141cc406Sopenharmony_ci  sanei_rts88xx_set_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4264141cc406Sopenharmony_ci  sanei_rts88xx_get_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4265141cc406Sopenharmony_ci  /* check the data returned */
4266141cc406Sopenharmony_ci  for (i = 0; i < 970; i++)
4267141cc406Sopenharmony_ci    {
4268141cc406Sopenharmony_ci      if (buffer[i] != (i + 0x36) % 97)
4269141cc406Sopenharmony_ci	{
4270141cc406Sopenharmony_ci	  DBG (DBG_error,
4271141cc406Sopenharmony_ci	       "init_device: memory at %d is not 0x%02x (0x%02x)\n", i,
4272141cc406Sopenharmony_ci	       (i + 0x36) % 97, buffer[i]);
4273141cc406Sopenharmony_ci	  /* XXX STEF XXX return SANE_STATUS_IO_ERROR; */
4274141cc406Sopenharmony_ci	}
4275141cc406Sopenharmony_ci    }
4276141cc406Sopenharmony_ci  for (i = 993; i < 2072; i++)
4277141cc406Sopenharmony_ci    {
4278141cc406Sopenharmony_ci      if (buffer[i] != i % 97)
4279141cc406Sopenharmony_ci	{
4280141cc406Sopenharmony_ci	  DBG (DBG_error,
4281141cc406Sopenharmony_ci	       "init_device: memory at %d is invalid 0x%02x, instead of 0x%02x\n",
4282141cc406Sopenharmony_ci	       i, buffer[i], i % 97);
4283141cc406Sopenharmony_ci	  /* XXX STEF XXX return SANE_STATUS_IO_ERROR; */
4284141cc406Sopenharmony_ci	}
4285141cc406Sopenharmony_ci    }
4286141cc406Sopenharmony_ci  DBG (DBG_info, "init_device: memory set #2 passed\n");
4287141cc406Sopenharmony_ci
4288141cc406Sopenharmony_ci
4289141cc406Sopenharmony_ci  /* now test (or set?) #3 */
4290141cc406Sopenharmony_ci  reg = 0x01;
4291141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x93, &reg);
4292141cc406Sopenharmony_ci  for (i = 0; i < 2072; i++)
4293141cc406Sopenharmony_ci    {
4294141cc406Sopenharmony_ci      buffer[i] = i % 97;
4295141cc406Sopenharmony_ci    }
4296141cc406Sopenharmony_ci  sanei_rts88xx_set_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4297141cc406Sopenharmony_ci  sanei_rts88xx_get_mem (dev->devnum, 0x81, 0x00, 2072, buffer);
4298141cc406Sopenharmony_ci  /* check the data returned */
4299141cc406Sopenharmony_ci  for (i = 0; i < 2072; i++)
4300141cc406Sopenharmony_ci    {
4301141cc406Sopenharmony_ci      if (buffer[i] != i % 97)
4302141cc406Sopenharmony_ci	{
4303141cc406Sopenharmony_ci	  DBG (DBG_error,
4304141cc406Sopenharmony_ci	       "init_device: memory at %d is invalid 0x%02x, instead of 0x%02x\n",
4305141cc406Sopenharmony_ci	       i, buffer[i], i % 97);
4306141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
4307141cc406Sopenharmony_ci	}
4308141cc406Sopenharmony_ci    }
4309141cc406Sopenharmony_ci  DBG (DBG_info, "init_device: memory set #3 passed\n");
4310141cc406Sopenharmony_ci
4311141cc406Sopenharmony_ci  /* we are writing page after page the same pattern, and reading at page 0 until we find we have 'wrapped' */
4312141cc406Sopenharmony_ci  /* this is surely some memory amount/number pages detection */
4313141cc406Sopenharmony_ci  dev->regs[0x91] = 0x00;	/* page 0 ? */
4314141cc406Sopenharmony_ci  dev->regs[0x92] = 0x00;
4315141cc406Sopenharmony_ci  dev->regs[0x93] = 0x01;
4316141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
4317141cc406Sopenharmony_ci
4318141cc406Sopenharmony_ci  /* write pattern at page 0 */
4319141cc406Sopenharmony_ci  for (i = 0; i < 32; i += 2)
4320141cc406Sopenharmony_ci    {
4321141cc406Sopenharmony_ci      buffer[i] = i;
4322141cc406Sopenharmony_ci      buffer[i + 1] = 0x00;
4323141cc406Sopenharmony_ci    }
4324141cc406Sopenharmony_ci  sanei_rts88xx_set_mem (dev->devnum, 0x00, 0x00, 32, buffer);
4325141cc406Sopenharmony_ci
4326141cc406Sopenharmony_ci  page = 0;
4327141cc406Sopenharmony_ci  do
4328141cc406Sopenharmony_ci    {
4329141cc406Sopenharmony_ci      /* next page */
4330141cc406Sopenharmony_ci      page++;
4331141cc406Sopenharmony_ci
4332141cc406Sopenharmony_ci      /* fill buffer with pattern for page */
4333141cc406Sopenharmony_ci      for (i = 0; i < 32; i += 2)
4334141cc406Sopenharmony_ci	{
4335141cc406Sopenharmony_ci	  buffer[i] = i;
4336141cc406Sopenharmony_ci	  buffer[i + 1] = page;
4337141cc406Sopenharmony_ci	}
4338141cc406Sopenharmony_ci      /* write it to memory */
4339141cc406Sopenharmony_ci      sanei_rts88xx_set_mem (dev->devnum, 0x00, page * 16, 32, buffer);
4340141cc406Sopenharmony_ci      /* read memory from page 0 */
4341141cc406Sopenharmony_ci      sanei_rts88xx_get_mem (dev->devnum, 0x00, 0x00, 32, buffer);
4342141cc406Sopenharmony_ci      for (i = 0; i < 32; i += 2)
4343141cc406Sopenharmony_ci	{
4344141cc406Sopenharmony_ci	  if (buffer[i] != i)
4345141cc406Sopenharmony_ci	    {
4346141cc406Sopenharmony_ci	      DBG (DBG_error,
4347141cc406Sopenharmony_ci		   "init_device: memory at %d is invalid: 0x%02x instead of 0x%02x\n",
4348141cc406Sopenharmony_ci		   i, buffer[i], i);
4349141cc406Sopenharmony_ci	      return SANE_STATUS_IO_ERROR;
4350141cc406Sopenharmony_ci	    }
4351141cc406Sopenharmony_ci	  if (buffer[i + 1] != page && buffer[i + 1] != 0)
4352141cc406Sopenharmony_ci	    {
4353141cc406Sopenharmony_ci	      DBG (DBG_error,
4354141cc406Sopenharmony_ci		   "init_device: page %d, memory at %d is invalid: 0x%02x instead of 0x%02x\n",
4355141cc406Sopenharmony_ci		   page, i + 1, buffer[i + 1], 0);
4356141cc406Sopenharmony_ci	      return SANE_STATUS_IO_ERROR;
4357141cc406Sopenharmony_ci	    }
4358141cc406Sopenharmony_ci	}
4359141cc406Sopenharmony_ci    }
4360141cc406Sopenharmony_ci  while (buffer[1] == 0);
4361141cc406Sopenharmony_ci  DBG (DBG_info, "init_device: %d pages detected\n", page - 1);
4362141cc406Sopenharmony_ci
4363141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4364141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, &control);
4365141cc406Sopenharmony_ci  if (!(control & 0x02))
4366141cc406Sopenharmony_ci    {
4367141cc406Sopenharmony_ci      if (park_head (dev, SANE_TRUE) != SANE_STATUS_GOOD)
4368141cc406Sopenharmony_ci	{
4369141cc406Sopenharmony_ci	  DBG (DBG_error, "init_device: failed to park head!\n");
4370141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
4371141cc406Sopenharmony_ci	}
4372141cc406Sopenharmony_ci    }
4373141cc406Sopenharmony_ci  reg = 0x80;
4374141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
4375141cc406Sopenharmony_ci  reg = 0xad;
4376141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
4377141cc406Sopenharmony_ci  sanei_rts88xx_read_regs (dev->devnum, 0x14, dev->regs + 0x14, 2);
4378141cc406Sopenharmony_ci  /* we expect 0xF8 0x28 here */
4379141cc406Sopenharmony_ci  dev->regs[0x14] = dev->regs[0x14] & 0x7F;
4380141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x14, dev->regs + 0x14, 2);
4381141cc406Sopenharmony_ci
4382141cc406Sopenharmony_ci  /* reads scanner status */
4383141cc406Sopenharmony_ci  sanei_rts88xx_get_status (dev->devnum, dev->regs);
4384141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: status=0x%02x 0x%02x\n", dev->regs[0x10],
4385141cc406Sopenharmony_ci       dev->regs[0x11]);
4386141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &control);
4387141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: link=0x%02x\n", control);
4388141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4389141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
4390141cc406Sopenharmony_ci  reg = 0x8d;
4391141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
4392141cc406Sopenharmony_ci  reg = 0xad;
4393141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
4394141cc406Sopenharmony_ci
4395141cc406Sopenharmony_ci  /* here, we are in iddle state */
4396141cc406Sopenharmony_ci
4397141cc406Sopenharmony_ci  /* check link status (scanner still plugged) */
4398141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &control);
4399141cc406Sopenharmony_ci  DBG (DBG_io, "init_device: link=0x%02x\n", control);
4400141cc406Sopenharmony_ci
4401141cc406Sopenharmony_ci  /* this block appears twice */
4402141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4403141cc406Sopenharmony_ci  if (control != 0)
4404141cc406Sopenharmony_ci    {
4405141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: unexpected control value 0x%02x\n",
4406141cc406Sopenharmony_ci	   control);
4407141cc406Sopenharmony_ci    }
4408141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
4409141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x40, &reg);
4410141cc406Sopenharmony_ci  reg |= 0x80;
4411141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x40, &reg);
4412141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x10, &reg);
4413141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x14, &reg);
4414141cc406Sopenharmony_ci  reg = 0x78;
4415141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x10, &reg);
4416141cc406Sopenharmony_ci  reg = 0x38;
4417141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x14, &reg);
4418141cc406Sopenharmony_ci  reg = 0x78;
4419141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x10, &reg);
4420141cc406Sopenharmony_ci  reg = 0x01;
4421141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, CONTROLER_REG, &reg);
4422141cc406Sopenharmony_ci
4423141cc406Sopenharmony_ci  /* now we init nvram */
4424141cc406Sopenharmony_ci  /* this is highly dangerous and thus deactivated
4425141cc406Sopenharmony_ci   * in sanei_rts88xx_setup_nvram (HAZARDOUS_EXPERIMENT #define) */
4426141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd1);
4427141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd2);
4428141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd3);
4429141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x28);
4430141cc406Sopenharmony_ci
4431141cc406Sopenharmony_ci  /* second occurrence of this block */
4432141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4433141cc406Sopenharmony_ci  if (control != 0)
4434141cc406Sopenharmony_ci    {
4435141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: unexpected control value 0x%02x\n",
4436141cc406Sopenharmony_ci	   control);
4437141cc406Sopenharmony_ci    }
4438141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
4439141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x40, &reg);
4440141cc406Sopenharmony_ci  reg |= 0x80;
4441141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x40, &reg);
4442141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x10, &reg);
4443141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0x14, &reg);
4444141cc406Sopenharmony_ci  reg = 0x78;
4445141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x10, &reg);
4446141cc406Sopenharmony_ci  reg = 0x38;
4447141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x14, &reg);
4448141cc406Sopenharmony_ci  reg = 0x78;
4449141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x10, &reg);
4450141cc406Sopenharmony_ci  reg = 0x01;
4451141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, CONTROLER_REG, &reg);
4452141cc406Sopenharmony_ci
4453141cc406Sopenharmony_ci  /* nvram again */
4454141cc406Sopenharmony_ci  /* this is highly dangerous and commented out in rts88xx_lib */
4455141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd4);
4456141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd5);
4457141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd6);
4458141cc406Sopenharmony_ci  sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd7);
4459141cc406Sopenharmony_ci
4460141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x28);
4461141cc406Sopenharmony_ci
4462141cc406Sopenharmony_ci  /* then we do a simple scan to detect a black zone to locate scan area */
4463141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4464141cc406Sopenharmony_ci  if (control != 0)
4465141cc406Sopenharmony_ci    {
4466141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: unexpected control value 0x%02x\n",
4467141cc406Sopenharmony_ci	   control);
4468141cc406Sopenharmony_ci    }
4469141cc406Sopenharmony_ci  sanei_rts88xx_reset_lamp (dev->devnum, dev->regs);
4470141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4471141cc406Sopenharmony_ci  if (control != 0)
4472141cc406Sopenharmony_ci    {
4473141cc406Sopenharmony_ci      DBG (DBG_warn, "init_device: unexpected control value 0x%02x\n",
4474141cc406Sopenharmony_ci	   control);
4475141cc406Sopenharmony_ci    }
4476141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
4477141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x01);
4478141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4479141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4480141cc406Sopenharmony_ci  dev->regs[0x12] = 0xff;
4481141cc406Sopenharmony_ci  dev->regs[0x13] = 0x20;
4482141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x12, dev->regs + 0x12, 2);
4483141cc406Sopenharmony_ci  dev->regs[0x14] = 0xf8;
4484141cc406Sopenharmony_ci  dev->regs[0x15] = 0x28;
4485141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x14, dev->regs + 0x14, 2);
4486141cc406Sopenharmony_ci  reg = 0;
4487141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4488141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, 0x00);
4489141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, 0x28, 0x28);
4490141cc406Sopenharmony_ci  reg = 0x80;
4491141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
4492141cc406Sopenharmony_ci
4493141cc406Sopenharmony_ci  dev->regs[0x8b] = 0xff;
4494141cc406Sopenharmony_ci  dev->regs[0x8c] = 0x3f;
4495141cc406Sopenharmony_ci  dev->regs[LAMP_REG] = 0xad;
4496141cc406Sopenharmony_ci  rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
4497141cc406Sopenharmony_ci
4498141cc406Sopenharmony_ci  set_lamp_brightness (dev, 0);
4499141cc406Sopenharmony_ci  dev->initialized = SANE_TRUE;
4500141cc406Sopenharmony_ci  DBG (DBG_proc, "init_device: exit\n");
4501141cc406Sopenharmony_ci  return status;
4502141cc406Sopenharmony_ci}
4503141cc406Sopenharmony_ci#endif /* FAST_INIT */
4504141cc406Sopenharmony_ci
4505141cc406Sopenharmony_ci#ifdef FAST_INIT
4506141cc406Sopenharmony_ci/*
4507141cc406Sopenharmony_ci * This function detects the scanner
4508141cc406Sopenharmony_ci */
4509141cc406Sopenharmony_cistatic SANE_Status
4510141cc406Sopenharmony_cidetect_device (struct Rts8891_Device *dev)
4511141cc406Sopenharmony_ci{
4512141cc406Sopenharmony_ci/*
4513141cc406Sopenharmony_ci---     5  74945 bulk_out len     4  wrote 0x80 0xb0 0x00 0x01
4514141cc406Sopenharmony_ci---     6  74946 bulk_in  len     1  read  0x80
4515141cc406Sopenharmony_ci---     7  74947 bulk_out len     4  wrote 0x80 0xb3 0x00 0x01
4516141cc406Sopenharmony_ci---     8  74948 bulk_in  len     1  read  0x04
4517141cc406Sopenharmony_ci---     9  74949 bulk_out len     4  wrote 0x80 0xb1 0x00 0x01
4518141cc406Sopenharmony_ci---    10  74950 bulk_in  len     1  read  0x00
4519141cc406Sopenharmony_ci---    11  74951 bulk_out len     5  wrote 0x88 0xb3 0x00 0x01 0x00
4520141cc406Sopenharmony_ci---    12  74952 bulk_out len     5  wrote 0x88 0xb3 0x00 0x01 0x00
4521141cc406Sopenharmony_ci---    13  74953 bulk_out len     4  wrote 0x80 0x00 0x00 0xf4
4522141cc406Sopenharmony_ci---    14  74954 bulk_in  len   192  read  0xf5 0x41 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x70 0x00 0x00 0x00 0x00 0x60 0x1b 0xff 0x3e 0x00 0x00 0xff 0x3e 0x00 0x00 0x00 0x00 0x00 0x22 0x00 0x00 0x00 0x00 0x00 0xff 0x00 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x42 0x00 0x00 0x10 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x00 0x00 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x24 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x10 0x00 0x80 0x00 0x10 0x00 0x01 0x00 0x00 0x10 0x00 0x00 0x20 0x20 0x00 0x00 0x00 0x00 0x20 0x01 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x41 0x00 0x10 0x21 0x20 0x00 0x20 0x81 0x20 0x01 0x01 0x00 0x22 0x00 0x40 0x05 0x00 0x00 0x01 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xcc 0x27 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
4523141cc406Sopenharmony_ci---    15  74955 bulk_in  len    52  read  0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x06 0x1b 0x10 0x7a 0x00 0x15 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
4524141cc406Sopenharmony_ci*/
4525141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
4526141cc406Sopenharmony_ci  SANE_Byte control;
4527141cc406Sopenharmony_ci  char message[256 * 5];
4528141cc406Sopenharmony_ci  int i;
4529141cc406Sopenharmony_ci
4530141cc406Sopenharmony_ci  DBG (DBG_proc, "detect_device: start\n");
4531141cc406Sopenharmony_ci
4532141cc406Sopenharmony_ci  /* read "b0" register */
4533141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, 0xb0, &control);
4534141cc406Sopenharmony_ci  DBG (DBG_io, "detect_device: reg[b0]=0x%02x\n", control);
4535141cc406Sopenharmony_ci
4536141cc406Sopenharmony_ci  /* we expect to get 0x80 */
4537141cc406Sopenharmony_ci  if (control != 0x80)
4538141cc406Sopenharmony_ci    {
4539141cc406Sopenharmony_ci      DBG (DBG_warn, "detect_device: expected reg[b0]=0x80, got 0x%02x\n",
4540141cc406Sopenharmony_ci	   control);
4541141cc406Sopenharmony_ci      /* TODO : fail here ? */
4542141cc406Sopenharmony_ci    }
4543141cc406Sopenharmony_ci
4544141cc406Sopenharmony_ci  /* read control register, if busy, something will have to be done ... */
4545141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
4546141cc406Sopenharmony_ci
4547141cc406Sopenharmony_ci  /* when just plugged, we expect to get 0x04 */
4548141cc406Sopenharmony_ci  if (control != 0x04)
4549141cc406Sopenharmony_ci    {
4550141cc406Sopenharmony_ci      DBG (DBG_warn, "detect_device: expected control=0x04, got 0x%02x\n",
4551141cc406Sopenharmony_ci	   control);
4552141cc406Sopenharmony_ci      /* TODO ok if re-run without plugging */
4553141cc406Sopenharmony_ci    }
4554141cc406Sopenharmony_ci
4555141cc406Sopenharmony_ci  /* read "LINK" register */
4556141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, LINK_REG, &control);
4557141cc406Sopenharmony_ci  DBG (DBG_io, "detect_device: LINK_REG=0x%02x\n", control);
4558141cc406Sopenharmony_ci
4559141cc406Sopenharmony_ci  /* we expect to get 0x00 */
4560141cc406Sopenharmony_ci  if (control != 0x00)
4561141cc406Sopenharmony_ci    {
4562141cc406Sopenharmony_ci      DBG (DBG_warn, "detect_device: expected LINK_REG=0x00, got 0x%02x\n",
4563141cc406Sopenharmony_ci	   control);
4564141cc406Sopenharmony_ci    }
4565141cc406Sopenharmony_ci
4566141cc406Sopenharmony_ci  /* write 0x00 twice to control:  cancel/stop ? */
4567141cc406Sopenharmony_ci  control = 0x00;
4568141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, control);
4569141cc406Sopenharmony_ci  sanei_rts88xx_write_control (dev->devnum, control);
4570141cc406Sopenharmony_ci
4571141cc406Sopenharmony_ci  /* read initial register set */
4572141cc406Sopenharmony_ci  sanei_rts88xx_read_regs (dev->devnum, 0, dev->regs, dev->reg_count);
4573141cc406Sopenharmony_ci  if (DBG_LEVEL >= DBG_io2)
4574141cc406Sopenharmony_ci    {
4575141cc406Sopenharmony_ci      sprintf (message, "init_device: initial register settings: ");
4576141cc406Sopenharmony_ci      for (i = 0; i < dev->reg_count; i++)
4577141cc406Sopenharmony_ci	sprintf (message + strlen (message), "0x%02x ", dev->regs[i]);
4578141cc406Sopenharmony_ci      sprintf (message + strlen (message), "\n");
4579141cc406Sopenharmony_ci      DBG (DBG_io2, message);
4580141cc406Sopenharmony_ci    }
4581141cc406Sopenharmony_ci
4582141cc406Sopenharmony_ci  /* initial sensor guess */
4583141cc406Sopenharmony_ci  val = dev->regs[0x44] + 256 * dev->regs[0x45];
4584141cc406Sopenharmony_ci  DBG (DBG_io, "detect_device: R44/45=0x%04x\n", val);
4585141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400 && val == 0x00)
4586141cc406Sopenharmony_ci    {
4587141cc406Sopenharmony_ci      dev->sensor = SENSOR_TYPE_4400_BARE;
4588141cc406Sopenharmony_ci      DBG (DBG_info, "detect_device: changing to SENSOR_TYPE_4400_BARE\n");
4589141cc406Sopenharmony_ci    }
4590141cc406Sopenharmony_ci
4591141cc406Sopenharmony_ci  DBG (DBG_io, "detect_device: status=0x%02x 0x%02x\n", dev->regs[0x10],
4592141cc406Sopenharmony_ci       dev->regs[0x11]);
4593141cc406Sopenharmony_ci  DBG (DBG_io, "detect_device: lamp status=0x%02x\n", dev->regs[0x8e]);
4594141cc406Sopenharmony_ci
4595141cc406Sopenharmony_ci  dev->initialized = SANE_FALSE;
4596141cc406Sopenharmony_ci  DBG (DBG_proc, "detect_device: exit\n");
4597141cc406Sopenharmony_ci  return status;
4598141cc406Sopenharmony_ci}
4599141cc406Sopenharmony_ci#endif
4600141cc406Sopenharmony_ci
4601141cc406Sopenharmony_ci/**
4602141cc406Sopenharmony_ci * Do dark calibration. We scan a well defined area until average pixel value
4603141cc406Sopenharmony_ci * of the black area is about 0x03 for each color channel. This calibration is
4604141cc406Sopenharmony_ci * currently done at 75 dpi regardless of the final scan dpi.
4605141cc406Sopenharmony_ci */
4606141cc406Sopenharmony_cistatic SANE_Status
4607141cc406Sopenharmony_cidark_calibration (struct Rts8891_Device *dev, int mode, int light)
4608141cc406Sopenharmony_ci{
4609141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
4610141cc406Sopenharmony_ci/* red, green and blue offset, within a 't'op and 'b'ottom value */
4611141cc406Sopenharmony_ci  int ro = 250, tro = 250, bro = 0;
4612141cc406Sopenharmony_ci  int bo = 250, tbo = 250, bbo = 0;
4613141cc406Sopenharmony_ci  int go = 250, tgo = 250, bgo = 0;
4614141cc406Sopenharmony_ci  unsigned char image[CALIBRATION_SIZE];
4615141cc406Sopenharmony_ci  float global, ra, ga, ba;
4616141cc406Sopenharmony_ci  int num = 0;
4617141cc406Sopenharmony_ci  char name[32];
4618141cc406Sopenharmony_ci
4619141cc406Sopenharmony_ci  DBG (DBG_proc, "dark_calibration: start\n");
4620141cc406Sopenharmony_ci
4621141cc406Sopenharmony_ci  /* set up sensor specific bottom values */
4622141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
4623141cc406Sopenharmony_ci    {
4624141cc406Sopenharmony_ci      bro = 128;
4625141cc406Sopenharmony_ci      bgo = 128;
4626141cc406Sopenharmony_ci      bbo = 128;
4627141cc406Sopenharmony_ci    }
4628141cc406Sopenharmony_ci
4629141cc406Sopenharmony_ci  /* set up starting values */
4630141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, 0, 0, 0);
4631141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (dev->regs, 1, 2, 4, 4 + CALIBRATION_WIDTH);
4632141cc406Sopenharmony_ci
4633141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, mode, light);
4634141cc406Sopenharmony_ci
4635141cc406Sopenharmony_ci  dev->regs[0x00] = 0xe5;	/* scan */
4636141cc406Sopenharmony_ci  dev->regs[0x32] = 0x00;
4637141cc406Sopenharmony_ci  dev->regs[0x33] = 0x03;
4638141cc406Sopenharmony_ci  dev->regs[0x35] = 0x45;
4639141cc406Sopenharmony_ci  dev->regs[0x36] = 0x22;
4640141cc406Sopenharmony_ci  dev->regs[0x3a] = 0x43;
4641141cc406Sopenharmony_ci
4642141cc406Sopenharmony_ci  dev->regs[0x8d] = 0x00;
4643141cc406Sopenharmony_ci  dev->regs[0x8e] = 0x60;
4644141cc406Sopenharmony_ci
4645141cc406Sopenharmony_ci  dev->regs[0xb2] = 0x02;
4646141cc406Sopenharmony_ci
4647141cc406Sopenharmony_ci  dev->regs[0xc0] = 0x06;
4648141cc406Sopenharmony_ci  dev->regs[0xc1] = 0xe6;
4649141cc406Sopenharmony_ci  dev->regs[0xc2] = 0x67;
4650141cc406Sopenharmony_ci  dev->regs[0xc9] = 0x07;
4651141cc406Sopenharmony_ci  dev->regs[0xca] = 0x00;
4652141cc406Sopenharmony_ci  dev->regs[0xcb] = 0xfe;
4653141cc406Sopenharmony_ci  dev->regs[0xcc] = 0xf9;
4654141cc406Sopenharmony_ci  dev->regs[0xcd] = 0x19;
4655141cc406Sopenharmony_ci  dev->regs[0xce] = 0x98;
4656141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xe8;
4657141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xea;
4658141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xf3;
4659141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x14;
4660141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x02;
4661141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x04;
4662141cc406Sopenharmony_ci  dev->regs[0xd6] = 0x0f;
4663141cc406Sopenharmony_ci  dev->regs[0xd8] = 0x52;
4664141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x1f;
4665141cc406Sopenharmony_ci
4666141cc406Sopenharmony_ci  /*dev->regs[0xe5] = 0x28;      28=40
4667141cc406Sopenharmony_ci     dev->regs[0xe6] = 0x00; */
4668141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 40);
4669141cc406Sopenharmony_ci
4670141cc406Sopenharmony_ci  dev->regs[0xe7] = 0x75;
4671141cc406Sopenharmony_ci  dev->regs[0xe8] = 0x01;
4672141cc406Sopenharmony_ci  dev->regs[0xe9] = 0x0b;
4673141cc406Sopenharmony_ci  dev->regs[0xea] = 0x54;
4674141cc406Sopenharmony_ci  dev->regs[0xeb] = 0x01;
4675141cc406Sopenharmony_ci  dev->regs[0xec] = 0x04;
4676141cc406Sopenharmony_ci  dev->regs[0xed] = 0xb8;
4677141cc406Sopenharmony_ci  dev->regs[0xef] = 0x03;
4678141cc406Sopenharmony_ci  dev->regs[0xf0] = 0x70;
4679141cc406Sopenharmony_ci  dev->regs[0xf2] = 0x01;
4680141cc406Sopenharmony_ci
4681141cc406Sopenharmony_ci  /* handling of different sensors */
4682141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
4683141cc406Sopenharmony_ci    {
4684141cc406Sopenharmony_ci      dev->regs[0xc0] = 0x67;
4685141cc406Sopenharmony_ci      dev->regs[0xc1] = 0x06;
4686141cc406Sopenharmony_ci      dev->regs[0xc2] = 0xe6;
4687141cc406Sopenharmony_ci      dev->regs[0xc3] = 0x98;
4688141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xf9;
4689141cc406Sopenharmony_ci      dev->regs[0xc5] = 0x19;
4690141cc406Sopenharmony_ci      dev->regs[0xc6] = 0x67;
4691141cc406Sopenharmony_ci      dev->regs[0xc7] = 0x06;
4692141cc406Sopenharmony_ci      dev->regs[0xc8] = 0xe6;
4693141cc406Sopenharmony_ci      dev->regs[0xc9] = 0x01;
4694141cc406Sopenharmony_ci      dev->regs[0xca] = 0xf8;
4695141cc406Sopenharmony_ci      dev->regs[0xcb] = 0xff;
4696141cc406Sopenharmony_ci      dev->regs[0xcc] = 0x98;
4697141cc406Sopenharmony_ci      dev->regs[0xcd] = 0xf9;
4698141cc406Sopenharmony_ci      dev->regs[0xce] = 0x19;
4699141cc406Sopenharmony_ci      dev->regs[0xcf] = 0xe0;
4700141cc406Sopenharmony_ci      dev->regs[0xd0] = 0xe2;
4701141cc406Sopenharmony_ci      dev->regs[0xd1] = 0xeb;
4702141cc406Sopenharmony_ci      dev->regs[0xd2] = 0x0c;
4703141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x10;
4704141cc406Sopenharmony_ci      dev->regs[0xda] = 0xa7;
4705141cc406Sopenharmony_ci    }
4706141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
4707141cc406Sopenharmony_ci    {
4708141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;	/* 0x20 */
4709141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;	/* 0xf8 */
4710141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;	/* 0x28 */
4711141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;	/* 0x07 */
4712141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;	/* 0x00 */
4713141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;	/* 0xff */
4714141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;	/* 0x45 */
4715141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;	/* 0x02 */
4716141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;	/* 0x1f */
4717141cc406Sopenharmony_ci      /* dev->regs[0xe5] = 0x52; 0x28 */
4718141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);	/* 2*40+2 */
4719141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;	/* 0x75 */
4720141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;	/* 0x0b */
4721141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;	/* 0x54 */
4722141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;	/* 0xb8 */
4723141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;	/* 0x03 */
4724141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;	/* 0x70 */
4725141cc406Sopenharmony_ci    }
4726141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
4727141cc406Sopenharmony_ci    {
4728141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;	/* 0x20 */
4729141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;	/* 0xf8 */
4730141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;	/* 0x28 */
4731141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;	/* 0x07 */
4732141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;	/* 0x00 */
4733141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;	/* 0xff */
4734141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;	/* 0x45 */
4735141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;	/* 0x02 */
4736141cc406Sopenharmony_ci      dev->regs[0xda] = 0xa7;	/* 0xa0 */
4737141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;	/* 0x1f */
4738141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);
4739141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;	/* 0x75 */
4740141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;	/* 0x0b */
4741141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;	/* 0x54 */
4742141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;	/* 0xb8 */
4743141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;	/* 0x03 */
4744141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;	/* 0x70 */
4745141cc406Sopenharmony_ci    }
4746141cc406Sopenharmony_ci
4747141cc406Sopenharmony_ci  /* we loop scanning a 637 (1911 bytes) pixels wide area in color mode
4748141cc406Sopenharmony_ci   * until each black average reaches the desired value */
4749141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, mode, light);
4750141cc406Sopenharmony_ci  do
4751141cc406Sopenharmony_ci    {
4752141cc406Sopenharmony_ci      /* set scan with the values to try */
4753141cc406Sopenharmony_ci      sanei_rts88xx_set_offset (dev->regs, ro, go, bo);
4754141cc406Sopenharmony_ci      DBG (DBG_info, "dark_calibration: trying offsets=(%d,%d,%d)\n", ro, go,
4755141cc406Sopenharmony_ci	   bo);
4756141cc406Sopenharmony_ci
4757141cc406Sopenharmony_ci      /* do scan */
4758141cc406Sopenharmony_ci      status =
4759141cc406Sopenharmony_ci	rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, 0x02,
4760141cc406Sopenharmony_ci			     CALIBRATION_SIZE, image);
4761141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
4762141cc406Sopenharmony_ci	{
4763141cc406Sopenharmony_ci	  DBG (DBG_error, "dark_calibration: failed to scan\n");
4764141cc406Sopenharmony_ci	  return status;
4765141cc406Sopenharmony_ci	}
4766141cc406Sopenharmony_ci
4767141cc406Sopenharmony_ci      /* save scanned picture for data debugging */
4768141cc406Sopenharmony_ci      if (DBG_LEVEL >= DBG_io2)
4769141cc406Sopenharmony_ci	{
4770141cc406Sopenharmony_ci	  sprintf (name, "dark%03d.pnm", num);
4771141cc406Sopenharmony_ci	  write_rgb_data (name, image, CALIBRATION_WIDTH, 1);
4772141cc406Sopenharmony_ci	  num++;
4773141cc406Sopenharmony_ci	}
4774141cc406Sopenharmony_ci
4775141cc406Sopenharmony_ci      /* we now compute the average of red pixels from the first 15 pixels */
4776141cc406Sopenharmony_ci      global = average_area (SANE_TRUE, image, 15, 1, &ra, &ga, &ba);
4777141cc406Sopenharmony_ci      DBG (DBG_info,
4778141cc406Sopenharmony_ci	   "dark_calibration: global=%.2f, channels=(%.2f,%.2f,%.2f)\n",
4779141cc406Sopenharmony_ci	   global, ra, ga, ba);
4780141cc406Sopenharmony_ci
4781141cc406Sopenharmony_ci      /* dichotomie ... */
4782141cc406Sopenharmony_ci      if (fabs (ra - DARK_TARGET) < DARK_MARGIN)
4783141cc406Sopenharmony_ci	{
4784141cc406Sopenharmony_ci	  /* offset is OK */
4785141cc406Sopenharmony_ci	  tro = ro;
4786141cc406Sopenharmony_ci	  bro = ro;
4787141cc406Sopenharmony_ci	}
4788141cc406Sopenharmony_ci      else
4789141cc406Sopenharmony_ci	{			/* NOK */
4790141cc406Sopenharmony_ci	  if (ra > DARK_TARGET)
4791141cc406Sopenharmony_ci	    {
4792141cc406Sopenharmony_ci	      tro = ro;
4793141cc406Sopenharmony_ci	      ro = (tro + bro) / 2;
4794141cc406Sopenharmony_ci	    }
4795141cc406Sopenharmony_ci	  if (ra < DARK_TARGET)
4796141cc406Sopenharmony_ci	    {
4797141cc406Sopenharmony_ci	      bro = ro;
4798141cc406Sopenharmony_ci	      ro = (tro + bro + 1) / 2;
4799141cc406Sopenharmony_ci	    }
4800141cc406Sopenharmony_ci
4801141cc406Sopenharmony_ci	}
4802141cc406Sopenharmony_ci
4803141cc406Sopenharmony_ci      /* same for blue channel */
4804141cc406Sopenharmony_ci      if (fabs (ba - DARK_TARGET) < DARK_MARGIN)
4805141cc406Sopenharmony_ci	{
4806141cc406Sopenharmony_ci	  bbo = bo;
4807141cc406Sopenharmony_ci	  tbo = bo;
4808141cc406Sopenharmony_ci	}
4809141cc406Sopenharmony_ci      else
4810141cc406Sopenharmony_ci	{			/* NOK */
4811141cc406Sopenharmony_ci	  if (ba > DARK_TARGET)
4812141cc406Sopenharmony_ci	    {
4813141cc406Sopenharmony_ci	      tbo = bo;
4814141cc406Sopenharmony_ci	      bo = (tbo + bbo) / 2;
4815141cc406Sopenharmony_ci	    }
4816141cc406Sopenharmony_ci	  if (ba < DARK_TARGET)
4817141cc406Sopenharmony_ci	    {
4818141cc406Sopenharmony_ci	      bbo = bo;
4819141cc406Sopenharmony_ci	      bo = (tbo + bbo + 1) / 2;
4820141cc406Sopenharmony_ci	    }
4821141cc406Sopenharmony_ci
4822141cc406Sopenharmony_ci	}
4823141cc406Sopenharmony_ci
4824141cc406Sopenharmony_ci      /* and for green channel */
4825141cc406Sopenharmony_ci      if (fabs (ga - DARK_TARGET) < DARK_MARGIN)
4826141cc406Sopenharmony_ci	{
4827141cc406Sopenharmony_ci	  tgo = go;
4828141cc406Sopenharmony_ci	  bgo = go;
4829141cc406Sopenharmony_ci	}
4830141cc406Sopenharmony_ci      else
4831141cc406Sopenharmony_ci	{			/* NOK */
4832141cc406Sopenharmony_ci	  if (ga > DARK_TARGET)
4833141cc406Sopenharmony_ci	    {
4834141cc406Sopenharmony_ci	      tgo = go;
4835141cc406Sopenharmony_ci	      go = (tgo + bgo) / 2;
4836141cc406Sopenharmony_ci	    }
4837141cc406Sopenharmony_ci	  if (ga < DARK_TARGET)
4838141cc406Sopenharmony_ci	    {
4839141cc406Sopenharmony_ci	      bgo = go;
4840141cc406Sopenharmony_ci	      go = (tgo + bgo + 1) / 2;
4841141cc406Sopenharmony_ci	    }
4842141cc406Sopenharmony_ci	}
4843141cc406Sopenharmony_ci    }
4844141cc406Sopenharmony_ci  while ((tro != bro) || (tgo != bgo) || (tbo != bbo));
4845141cc406Sopenharmony_ci
4846141cc406Sopenharmony_ci  /* store detected values in device struct */
4847141cc406Sopenharmony_ci  dev->red_offset = bro;
4848141cc406Sopenharmony_ci  dev->green_offset = bgo;
4849141cc406Sopenharmony_ci  dev->blue_offset = bbo;
4850141cc406Sopenharmony_ci
4851141cc406Sopenharmony_ci  DBG (DBG_info, "dark_calibration: final offsets=(%d,%d,%d)\n", bro, bgo,
4852141cc406Sopenharmony_ci       bbo);
4853141cc406Sopenharmony_ci  DBG (DBG_proc, "dark_calibration: exit\n");
4854141cc406Sopenharmony_ci  return status;
4855141cc406Sopenharmony_ci}
4856141cc406Sopenharmony_ci
4857141cc406Sopenharmony_ci/*
4858141cc406Sopenharmony_ci * do gain calibration. We do scans until averaged values of the area match
4859141cc406Sopenharmony_ci * the target code. We're doing a dichotomy again.
4860141cc406Sopenharmony_ci */
4861141cc406Sopenharmony_cistatic SANE_Status
4862141cc406Sopenharmony_cigain_calibration (struct Rts8891_Device *dev, int mode, int light)
4863141cc406Sopenharmony_ci{
4864141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
4865141cc406Sopenharmony_ci  float global, ra, ga, ba;
4866141cc406Sopenharmony_ci  /* previous values */
4867141cc406Sopenharmony_ci  int xrg, xbg, xgg;
4868141cc406Sopenharmony_ci/* current gains */
4869141cc406Sopenharmony_ci  int rg, bg, gg;
4870141cc406Sopenharmony_ci/* intervals for dichotomy */
4871141cc406Sopenharmony_ci  int trg, tbg, tgg, bgg, brg, bbg;
4872141cc406Sopenharmony_ci  int num = 0;
4873141cc406Sopenharmony_ci  char name[32];
4874141cc406Sopenharmony_ci  int width = CALIBRATION_WIDTH;
4875141cc406Sopenharmony_ci  int length = CALIBRATION_SIZE;
4876141cc406Sopenharmony_ci  unsigned char image[CALIBRATION_SIZE];
4877141cc406Sopenharmony_ci  int pass = 0;
4878141cc406Sopenharmony_ci  int timing=0;
4879141cc406Sopenharmony_ci
4880141cc406Sopenharmony_ci  int xstart = (dev->left_offset * 75) / dev->model->max_xdpi;
4881141cc406Sopenharmony_ci
4882141cc406Sopenharmony_ci  DBG (DBG_proc, "gain_calibration: start\n");
4883141cc406Sopenharmony_ci
4884141cc406Sopenharmony_ci  /* set up starting values */
4885141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (dev->regs, 1, 2, xstart, xstart + width);
4886141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (dev->regs, dev->red_offset, dev->green_offset,
4887141cc406Sopenharmony_ci			    dev->blue_offset);
4888141cc406Sopenharmony_ci
4889141cc406Sopenharmony_ci  /* same register set than dark calibration */
4890141cc406Sopenharmony_ci  dev->regs[0x32] = 0x00;
4891141cc406Sopenharmony_ci  dev->regs[0x33] = 0x03;
4892141cc406Sopenharmony_ci  dev->regs[0x35] = 0x45;
4893141cc406Sopenharmony_ci  dev->regs[0x36] = 0x22;
4894141cc406Sopenharmony_ci  dev->regs[0x3a] = 0x43;
4895141cc406Sopenharmony_ci
4896141cc406Sopenharmony_ci  dev->regs[0x8d] = 0x00;
4897141cc406Sopenharmony_ci  dev->regs[0x8e] = 0x60;
4898141cc406Sopenharmony_ci
4899141cc406Sopenharmony_ci  dev->regs[0xb2] = 0x02;
4900141cc406Sopenharmony_ci
4901141cc406Sopenharmony_ci  dev->regs[0xc0] = 0x06;
4902141cc406Sopenharmony_ci  dev->regs[0xc1] = 0xe6;
4903141cc406Sopenharmony_ci  dev->regs[0xc2] = 0x67;
4904141cc406Sopenharmony_ci  dev->regs[0xc9] = 0x07;
4905141cc406Sopenharmony_ci  dev->regs[0xca] = 0x00;
4906141cc406Sopenharmony_ci  dev->regs[0xcb] = 0xfe;
4907141cc406Sopenharmony_ci  dev->regs[0xcc] = 0xf9;
4908141cc406Sopenharmony_ci  dev->regs[0xcd] = 0x19;
4909141cc406Sopenharmony_ci  dev->regs[0xce] = 0x98;
4910141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xe8;
4911141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xea;
4912141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xf3;
4913141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x14;
4914141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x02;
4915141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x04;
4916141cc406Sopenharmony_ci  dev->regs[0xd6] = 0x0f;
4917141cc406Sopenharmony_ci  dev->regs[0xd8] = 0x52;
4918141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x1f;
4919141cc406Sopenharmony_ci
4920141cc406Sopenharmony_ci  /* dev->regs[0xe5] = 0x28;
4921141cc406Sopenharmony_ci     dev->regs[0xe6] = 0x00;    28=40  */
4922141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 40);
4923141cc406Sopenharmony_ci
4924141cc406Sopenharmony_ci  dev->regs[0xe7] = 0x75;
4925141cc406Sopenharmony_ci  dev->regs[0xe8] = 0x01;
4926141cc406Sopenharmony_ci  dev->regs[0xe9] = 0x0b;
4927141cc406Sopenharmony_ci  dev->regs[0xea] = 0x54;
4928141cc406Sopenharmony_ci  dev->regs[0xeb] = 0x01;
4929141cc406Sopenharmony_ci  dev->regs[0xec] = 0x04;
4930141cc406Sopenharmony_ci  dev->regs[0xed] = 0xb8;
4931141cc406Sopenharmony_ci  dev->regs[0xef] = 0x03;
4932141cc406Sopenharmony_ci  dev->regs[0xf0] = 0x70;
4933141cc406Sopenharmony_ci  dev->regs[0xf2] = 0x01;
4934141cc406Sopenharmony_ci
4935141cc406Sopenharmony_ci  dev->regs[0x72] = 0xe1;
4936141cc406Sopenharmony_ci  dev->regs[0x73] = 0x14;
4937141cc406Sopenharmony_ci  dev->regs[0x74] = 0x18;
4938141cc406Sopenharmony_ci
4939141cc406Sopenharmony_ci  dev->regs[0xc3] = 0xff;
4940141cc406Sopenharmony_ci  dev->regs[0xc4] = 0xff;
4941141cc406Sopenharmony_ci  dev->regs[0xc7] = 0xff;
4942141cc406Sopenharmony_ci  dev->regs[0xc8] = 0xff;
4943141cc406Sopenharmony_ci
4944141cc406Sopenharmony_ci  dev->regs[0xd7] = 0x30;
4945141cc406Sopenharmony_ci
4946141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
4947141cc406Sopenharmony_ci    {
4948141cc406Sopenharmony_ci      dev->regs[0xc0] = 0x67;
4949141cc406Sopenharmony_ci      dev->regs[0xc1] = 0x06;
4950141cc406Sopenharmony_ci      dev->regs[0xc2] = 0xe6;
4951141cc406Sopenharmony_ci      dev->regs[0xc3] = 0x98;
4952141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xf9;
4953141cc406Sopenharmony_ci      dev->regs[0xc5] = 0x19;
4954141cc406Sopenharmony_ci      dev->regs[0xc6] = 0x67;
4955141cc406Sopenharmony_ci      dev->regs[0xc7] = 0x06;
4956141cc406Sopenharmony_ci      dev->regs[0xc8] = 0xe6;
4957141cc406Sopenharmony_ci      dev->regs[0xc9] = 0x01;
4958141cc406Sopenharmony_ci      dev->regs[0xca] = 0xf8;
4959141cc406Sopenharmony_ci      dev->regs[0xcb] = 0xff;
4960141cc406Sopenharmony_ci      dev->regs[0xcc] = 0x98;
4961141cc406Sopenharmony_ci      dev->regs[0xcd] = 0xf9;
4962141cc406Sopenharmony_ci      dev->regs[0xce] = 0x19;
4963141cc406Sopenharmony_ci      dev->regs[0xcf] = 0xe0;
4964141cc406Sopenharmony_ci      dev->regs[0xd0] = 0xe2;
4965141cc406Sopenharmony_ci      dev->regs[0xd1] = 0xeb;
4966141cc406Sopenharmony_ci      dev->regs[0xd2] = 0x0c;
4967141cc406Sopenharmony_ci      dev->regs[0xd3] = 0x02;
4968141cc406Sopenharmony_ci      dev->regs[0xd4] = 0x04;
4969141cc406Sopenharmony_ci      dev->regs[0xd6] = 0x0f;
4970141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x10;
4971141cc406Sopenharmony_ci      dev->regs[0xd8] = 0x52;
4972141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x1f;
4973141cc406Sopenharmony_ci      /* dev->regs[0xe5] = 0x28;    0028 -> 40
4974141cc406Sopenharmony_ci         dev->regs[0xe6] = 0x00; */
4975141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 40);
4976141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x75;
4977141cc406Sopenharmony_ci      dev->regs[0xe8] = 0x01;
4978141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0b;
4979141cc406Sopenharmony_ci      dev->regs[0xea] = 0x54;
4980141cc406Sopenharmony_ci      dev->regs[0xeb] = 0x01;
4981141cc406Sopenharmony_ci      dev->regs[0xec] = 0x04;
4982141cc406Sopenharmony_ci      dev->regs[0xed] = 0xb8;
4983141cc406Sopenharmony_ci      dev->regs[0xef] = 0x03;
4984141cc406Sopenharmony_ci      dev->regs[0xf0] = 0x70;
4985141cc406Sopenharmony_ci      dev->regs[0xf2] = 0x01;
4986141cc406Sopenharmony_ci    }
4987141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
4988141cc406Sopenharmony_ci    {
4989141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;	/* 0x45 */
4990141cc406Sopenharmony_ci      /* c5, c6 ? : untouched from previous scan ... */
4991141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;	/* 0x1f */
4992141cc406Sopenharmony_ci      /* dev->regs[0xe5] = 0x52;        */
4993141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);	/* 2*40+2 */
4994141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;	/* 0x75 */
4995141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;	/* 0x0b */
4996141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;	/* 0x54 */
4997141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;	/* 0xb8 */
4998141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;	/* 0x03 */
4999141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;	/* 0x70 */
5000141cc406Sopenharmony_ci    }
5001141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
5002141cc406Sopenharmony_ci    {
5003141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;
5004141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;
5005141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;
5006141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;
5007141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;
5008141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;
5009141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;
5010141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;
5011141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;
5012141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);
5013141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;
5014141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;
5015141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;
5016141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;
5017141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;
5018141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;
5019141cc406Sopenharmony_ci
5020141cc406Sopenharmony_ci      timing=0x32;
5021141cc406Sopenharmony_ci      dev->regs[0x85] = 0x00;
5022141cc406Sopenharmony_ci      dev->regs[0x86] = 0x06;
5023141cc406Sopenharmony_ci      dev->regs[0x87] = 0x00;
5024141cc406Sopenharmony_ci      dev->regs[0x88] = 0x06;
5025141cc406Sopenharmony_ci    }
5026141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING_REG, timing);
5027141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING1_REG, timing+1);
5028141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, TIMING2_REG, timing+2);
5029141cc406Sopenharmony_ci
5030141cc406Sopenharmony_ci
5031141cc406Sopenharmony_ci  /* we loop scanning a 637 (1911 bytes) pixels wide area in color mode until each white average
5032141cc406Sopenharmony_ci   * reaches the desired value, doing a dichotomy */
5033141cc406Sopenharmony_ci  rg = 0x1f;
5034141cc406Sopenharmony_ci  bg = 0x1f;
5035141cc406Sopenharmony_ci  gg = 0x1f;
5036141cc406Sopenharmony_ci  /* dichotomy interval */
5037141cc406Sopenharmony_ci  /* bottom values */
5038141cc406Sopenharmony_ci  brg = 0;
5039141cc406Sopenharmony_ci  bgg = 0;
5040141cc406Sopenharmony_ci  bbg = 0;
5041141cc406Sopenharmony_ci  /* top values */
5042141cc406Sopenharmony_ci  trg = 0x1f;
5043141cc406Sopenharmony_ci  tgg = 0x1f;
5044141cc406Sopenharmony_ci  tbg = 0x1f;
5045141cc406Sopenharmony_ci
5046141cc406Sopenharmony_ci  /* loop on gain calibration until we find until we find stable value
5047141cc406Sopenharmony_ci   * or we do more than 20 tries */
5048141cc406Sopenharmony_ci  do
5049141cc406Sopenharmony_ci    {
5050141cc406Sopenharmony_ci      /* store current values as previous */
5051141cc406Sopenharmony_ci      xrg = rg;
5052141cc406Sopenharmony_ci      xbg = bg;
5053141cc406Sopenharmony_ci      xgg = gg;
5054141cc406Sopenharmony_ci
5055141cc406Sopenharmony_ci      /* set up for scan */
5056141cc406Sopenharmony_ci      DBG (DBG_info,
5057141cc406Sopenharmony_ci	   "gain_calibration: trying gains=(0x%02x,0x%02x,0x%02x)\n", rg, gg,
5058141cc406Sopenharmony_ci	   bg);
5059141cc406Sopenharmony_ci      sanei_rts88xx_set_gain (dev->regs, rg, gg, bg);
5060141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, mode, light);
5061141cc406Sopenharmony_ci
5062141cc406Sopenharmony_ci      /* scan on line in RGB */
5063141cc406Sopenharmony_ci      status =
5064141cc406Sopenharmony_ci	rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, 0x02,
5065141cc406Sopenharmony_ci			     length, image);
5066141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
5067141cc406Sopenharmony_ci	{
5068141cc406Sopenharmony_ci	  DBG (DBG_error, "gain_calibration: failed scan data\n");
5069141cc406Sopenharmony_ci	  return status;
5070141cc406Sopenharmony_ci	}
5071141cc406Sopenharmony_ci
5072141cc406Sopenharmony_ci      /* save scanned picture for data debugging */
5073141cc406Sopenharmony_ci      if (DBG_LEVEL >= DBG_io2)
5074141cc406Sopenharmony_ci	{
5075141cc406Sopenharmony_ci	  sprintf (name, "gain%03d.pnm", num);
5076141cc406Sopenharmony_ci	  write_rgb_data (name, image, width, 1);
5077141cc406Sopenharmony_ci	  num++;
5078141cc406Sopenharmony_ci	}
5079141cc406Sopenharmony_ci
5080141cc406Sopenharmony_ci      /* we now compute the average pixel value on the scanned line */
5081141cc406Sopenharmony_ci      /* TODO use computed left margin */
5082141cc406Sopenharmony_ci      global = average_area (SANE_TRUE, image, width, 1, &ra, &ga, &ba);
5083141cc406Sopenharmony_ci      DBG (DBG_info,
5084141cc406Sopenharmony_ci	   "gain_calibration: global=%.2f, channels=(%.2f,%.2f,%.2f)\n",
5085141cc406Sopenharmony_ci	   global, ra, ga, ba);
5086141cc406Sopenharmony_ci
5087141cc406Sopenharmony_ci      /* dichotomy again ... */
5088141cc406Sopenharmony_ci      if (fabs (ra - RED_GAIN_TARGET) < GAIN_MARGIN)
5089141cc406Sopenharmony_ci	{
5090141cc406Sopenharmony_ci	  /* gain is OK, it is whitin the tolerance margin */
5091141cc406Sopenharmony_ci	  trg = rg;
5092141cc406Sopenharmony_ci	  brg = rg;
5093141cc406Sopenharmony_ci	}
5094141cc406Sopenharmony_ci      else
5095141cc406Sopenharmony_ci	{			/* average is higher than the desired value */
5096141cc406Sopenharmony_ci	  if (ra > RED_GAIN_TARGET)
5097141cc406Sopenharmony_ci	    {
5098141cc406Sopenharmony_ci	      /* changing gain for another channel alters other output */
5099141cc406Sopenharmony_ci	      /* a stable value is shown by top value == bottom value */
5100141cc406Sopenharmony_ci	      if (trg == brg)
5101141cc406Sopenharmony_ci		{
5102141cc406Sopenharmony_ci		  brg--;
5103141cc406Sopenharmony_ci		  rg = brg;
5104141cc406Sopenharmony_ci		}
5105141cc406Sopenharmony_ci	      else
5106141cc406Sopenharmony_ci		{
5107141cc406Sopenharmony_ci		  /* since we'ra above target value, current gain becomes top value */
5108141cc406Sopenharmony_ci		  trg = rg;
5109141cc406Sopenharmony_ci		  rg = (trg + brg) / 2;
5110141cc406Sopenharmony_ci		}
5111141cc406Sopenharmony_ci	    }
5112141cc406Sopenharmony_ci	  else			/* below target value */
5113141cc406Sopenharmony_ci	    {
5114141cc406Sopenharmony_ci	      if (trg == brg)
5115141cc406Sopenharmony_ci		{
5116141cc406Sopenharmony_ci		  trg++;
5117141cc406Sopenharmony_ci		  rg = trg;
5118141cc406Sopenharmony_ci		}
5119141cc406Sopenharmony_ci	      else
5120141cc406Sopenharmony_ci		{
5121141cc406Sopenharmony_ci		  /* since we are below target, current value is assigned to bottom value */
5122141cc406Sopenharmony_ci		  brg = rg;
5123141cc406Sopenharmony_ci		  rg = (trg + brg + 1) / 2;
5124141cc406Sopenharmony_ci		}
5125141cc406Sopenharmony_ci	    }
5126141cc406Sopenharmony_ci	}
5127141cc406Sopenharmony_ci
5128141cc406Sopenharmony_ci      /* same for blue channel */
5129141cc406Sopenharmony_ci      if (fabs (ba - BLUE_GAIN_TARGET) < GAIN_MARGIN)
5130141cc406Sopenharmony_ci	{
5131141cc406Sopenharmony_ci	  bbg = bg;
5132141cc406Sopenharmony_ci	  tbg = bg;
5133141cc406Sopenharmony_ci	}
5134141cc406Sopenharmony_ci      else
5135141cc406Sopenharmony_ci	{			/* NOK */
5136141cc406Sopenharmony_ci	  if (ba > BLUE_GAIN_TARGET)
5137141cc406Sopenharmony_ci	    {
5138141cc406Sopenharmony_ci	      if (tbg == bbg)
5139141cc406Sopenharmony_ci		{
5140141cc406Sopenharmony_ci		  bbg--;
5141141cc406Sopenharmony_ci		  bg = bbg;
5142141cc406Sopenharmony_ci		}
5143141cc406Sopenharmony_ci	      else
5144141cc406Sopenharmony_ci		{
5145141cc406Sopenharmony_ci		  tbg = bg;
5146141cc406Sopenharmony_ci		  bg = (tbg + bbg) / 2;
5147141cc406Sopenharmony_ci		}
5148141cc406Sopenharmony_ci	    }
5149141cc406Sopenharmony_ci	  else
5150141cc406Sopenharmony_ci	    {
5151141cc406Sopenharmony_ci	      if (tbg == bbg)
5152141cc406Sopenharmony_ci		{
5153141cc406Sopenharmony_ci		  tbg++;
5154141cc406Sopenharmony_ci		  bg = tbg;
5155141cc406Sopenharmony_ci		}
5156141cc406Sopenharmony_ci	      else
5157141cc406Sopenharmony_ci		{
5158141cc406Sopenharmony_ci		  bbg = bg;
5159141cc406Sopenharmony_ci		  bg = (tbg + bbg + 1) / 2;
5160141cc406Sopenharmony_ci		}
5161141cc406Sopenharmony_ci	    }
5162141cc406Sopenharmony_ci	}
5163141cc406Sopenharmony_ci
5164141cc406Sopenharmony_ci      /* and for green channel */
5165141cc406Sopenharmony_ci      if (fabs (ga - GREEN_GAIN_TARGET) < GAIN_MARGIN)
5166141cc406Sopenharmony_ci	{
5167141cc406Sopenharmony_ci	  tgg = gg;
5168141cc406Sopenharmony_ci	  bgg = gg;
5169141cc406Sopenharmony_ci	}
5170141cc406Sopenharmony_ci      else
5171141cc406Sopenharmony_ci	{			/* NOK */
5172141cc406Sopenharmony_ci	  if (ga > GREEN_GAIN_TARGET)
5173141cc406Sopenharmony_ci	    {
5174141cc406Sopenharmony_ci	      if (tgg == bgg)
5175141cc406Sopenharmony_ci		{
5176141cc406Sopenharmony_ci		  bgg--;
5177141cc406Sopenharmony_ci		  gg = bgg;
5178141cc406Sopenharmony_ci		}
5179141cc406Sopenharmony_ci	      else
5180141cc406Sopenharmony_ci		{
5181141cc406Sopenharmony_ci		  tgg = gg;
5182141cc406Sopenharmony_ci		  gg = (tgg + bgg) / 2;
5183141cc406Sopenharmony_ci		}
5184141cc406Sopenharmony_ci	    }
5185141cc406Sopenharmony_ci	  else
5186141cc406Sopenharmony_ci	    {
5187141cc406Sopenharmony_ci	      if (tgg == bgg)
5188141cc406Sopenharmony_ci		{
5189141cc406Sopenharmony_ci		  tgg++;
5190141cc406Sopenharmony_ci		  gg = tgg;
5191141cc406Sopenharmony_ci		}
5192141cc406Sopenharmony_ci	      else
5193141cc406Sopenharmony_ci		{
5194141cc406Sopenharmony_ci		  bgg = gg;
5195141cc406Sopenharmony_ci		  gg = (tgg + bgg + 1) / 2;
5196141cc406Sopenharmony_ci		}
5197141cc406Sopenharmony_ci	    }
5198141cc406Sopenharmony_ci	}
5199141cc406Sopenharmony_ci      pass++;
5200141cc406Sopenharmony_ci    }
5201141cc406Sopenharmony_ci  while ((pass < 20)
5202141cc406Sopenharmony_ci	 && ((trg != brg && xrg != rg)
5203141cc406Sopenharmony_ci	     || (tgg != bgg && xgg != gg) || (tbg != bbg && xbg != bg)));
5204141cc406Sopenharmony_ci
5205141cc406Sopenharmony_ci  /* store detected values in device struct */
5206141cc406Sopenharmony_ci  dev->red_gain = brg;
5207141cc406Sopenharmony_ci  dev->green_gain = bgg;
5208141cc406Sopenharmony_ci  dev->blue_gain = bbg;
5209141cc406Sopenharmony_ci  DBG (DBG_info, "gain_calibration: gain=(0x%02x,0x%02x,0x%02x)\n", brg, bgg,
5210141cc406Sopenharmony_ci       bbg);
5211141cc406Sopenharmony_ci
5212141cc406Sopenharmony_ci  DBG (DBG_proc, "gain_calibration: exit\n");
5213141cc406Sopenharmony_ci  return status;
5214141cc406Sopenharmony_ci}
5215141cc406Sopenharmony_ci
5216141cc406Sopenharmony_ci/**
5217141cc406Sopenharmony_ci * Do fine offset calibration. Scans are done with gains from gain calibration
5218141cc406Sopenharmony_ci * at 75 dpi regardless of the dpi of the final scan. We loop scanning a 637
5219141cc406Sopenharmony_ci * (1911 bytes) pixels wide area in color mode until each black average
5220141cc406Sopenharmony_ci * reaches the desired value (OFFSET_TARGET).
5221141cc406Sopenharmony_ci */
5222141cc406Sopenharmony_cistatic SANE_Status
5223141cc406Sopenharmony_cioffset_calibration (struct Rts8891_Device *dev, int mode, int light)
5224141cc406Sopenharmony_ci{
5225141cc406Sopenharmony_ci
5226141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
5227141cc406Sopenharmony_ci  /* red, green and blue offset, within a 't'op and 'b'ottom value */
5228141cc406Sopenharmony_ci  int ro = 250, tro = 250, bro = 123;
5229141cc406Sopenharmony_ci  int go = 250, tgo = 250, bgo = 123;
5230141cc406Sopenharmony_ci  int bo = 250, tbo = 250, bbo = 123;
5231141cc406Sopenharmony_ci  unsigned char image[CALIBRATION_SIZE];
5232141cc406Sopenharmony_ci  float global, ra, ga, ba;
5233141cc406Sopenharmony_ci  int num = 0;
5234141cc406Sopenharmony_ci  char name[32];
5235141cc406Sopenharmony_ci
5236141cc406Sopenharmony_ci  DBG (DBG_proc, "offset_calibration: start\n");
5237141cc406Sopenharmony_ci
5238141cc406Sopenharmony_ci  /* set up starting values */
5239141cc406Sopenharmony_ci  /* gains from previous step are a little higher than the one used */
5240141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (dev->regs, dev->red_gain, dev->green_gain,
5241141cc406Sopenharmony_ci			  dev->blue_gain);
5242141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (dev->regs, 1, 2, 4, 4 + CALIBRATION_WIDTH);
5243141cc406Sopenharmony_ci
5244141cc406Sopenharmony_ci  dev->regs[0x32] = 0x00;
5245141cc406Sopenharmony_ci  dev->regs[0x33] = 0x03;
5246141cc406Sopenharmony_ci  dev->regs[0x35] = 0x45;
5247141cc406Sopenharmony_ci  dev->regs[0x36] = 0x22;
5248141cc406Sopenharmony_ci  dev->regs[0x3a] = 0x43;
5249141cc406Sopenharmony_ci
5250141cc406Sopenharmony_ci  dev->regs[0x8d] = 0x00;
5251141cc406Sopenharmony_ci  dev->regs[0x8e] = 0x60;
5252141cc406Sopenharmony_ci  dev->regs[0xb2] = 0x02;
5253141cc406Sopenharmony_ci  dev->regs[0xc0] = 0x06;
5254141cc406Sopenharmony_ci  dev->regs[0xc1] = 0xe6;
5255141cc406Sopenharmony_ci  dev->regs[0xc2] = 0x67;
5256141cc406Sopenharmony_ci  dev->regs[0xc9] = 0x07;
5257141cc406Sopenharmony_ci  dev->regs[0xca] = 0x00;
5258141cc406Sopenharmony_ci  dev->regs[0xcb] = 0xfe;
5259141cc406Sopenharmony_ci  dev->regs[0xcc] = 0xf9;
5260141cc406Sopenharmony_ci  dev->regs[0xcd] = 0x19;
5261141cc406Sopenharmony_ci  dev->regs[0xce] = 0x98;
5262141cc406Sopenharmony_ci  dev->regs[0xcf] = 0xe8;
5263141cc406Sopenharmony_ci  dev->regs[0xd0] = 0xea;
5264141cc406Sopenharmony_ci  dev->regs[0xd1] = 0xf3;
5265141cc406Sopenharmony_ci  dev->regs[0xd2] = 0x14;
5266141cc406Sopenharmony_ci  dev->regs[0xd3] = 0x02;
5267141cc406Sopenharmony_ci  dev->regs[0xd4] = 0x04;
5268141cc406Sopenharmony_ci  dev->regs[0xd6] = 0x0f;
5269141cc406Sopenharmony_ci  dev->regs[0xd8] = 0x52;
5270141cc406Sopenharmony_ci  dev->regs[0xe2] = 0x1f;
5271141cc406Sopenharmony_ci  /* dev->regs[0xe5] = 0x28;
5272141cc406Sopenharmony_ci     dev->regs[0xe6] = 0x00;     0x0028=40 */
5273141cc406Sopenharmony_ci  SET_DOUBLE (dev->regs, EXPOSURE_REG, 40);
5274141cc406Sopenharmony_ci  dev->regs[0xe7] = 0x75;
5275141cc406Sopenharmony_ci  dev->regs[0xe8] = 0x01;
5276141cc406Sopenharmony_ci  dev->regs[0xe9] = 0x0b;
5277141cc406Sopenharmony_ci  dev->regs[0xea] = 0x54;
5278141cc406Sopenharmony_ci  dev->regs[0xeb] = 0x01;
5279141cc406Sopenharmony_ci  dev->regs[0xec] = 0x04;
5280141cc406Sopenharmony_ci  dev->regs[0xed] = 0xb8;
5281141cc406Sopenharmony_ci  dev->regs[0xef] = 0x03;
5282141cc406Sopenharmony_ci  dev->regs[0xf0] = 0x70;
5283141cc406Sopenharmony_ci  dev->regs[0xf2] = 0x01;
5284141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
5285141cc406Sopenharmony_ci    {
5286141cc406Sopenharmony_ci      dev->regs[0x72] = 0xe1;
5287141cc406Sopenharmony_ci      dev->regs[0x73] = 0x14;
5288141cc406Sopenharmony_ci      dev->regs[0x74] = 0x18;
5289141cc406Sopenharmony_ci
5290141cc406Sopenharmony_ci      dev->regs[0xc0] = 0x67;
5291141cc406Sopenharmony_ci      dev->regs[0xc1] = 0x06;
5292141cc406Sopenharmony_ci      dev->regs[0xc2] = 0xe6;
5293141cc406Sopenharmony_ci      dev->regs[0xc3] = 0x98;
5294141cc406Sopenharmony_ci      dev->regs[0xc4] = 0xf9;
5295141cc406Sopenharmony_ci      dev->regs[0xc5] = 0x19;
5296141cc406Sopenharmony_ci      dev->regs[0xc6] = 0x67;
5297141cc406Sopenharmony_ci      dev->regs[0xc7] = 0x06;
5298141cc406Sopenharmony_ci      dev->regs[0xc8] = 0xe6;
5299141cc406Sopenharmony_ci      dev->regs[0xc9] = 0x01;
5300141cc406Sopenharmony_ci      dev->regs[0xca] = 0xf8;
5301141cc406Sopenharmony_ci      dev->regs[0xcb] = 0xff;
5302141cc406Sopenharmony_ci      dev->regs[0xcc] = 0x98;
5303141cc406Sopenharmony_ci      dev->regs[0xcd] = 0xf9;
5304141cc406Sopenharmony_ci      dev->regs[0xce] = 0x19;
5305141cc406Sopenharmony_ci      dev->regs[0xcf] = 0xe0;
5306141cc406Sopenharmony_ci      dev->regs[0xd0] = 0xe2;
5307141cc406Sopenharmony_ci      dev->regs[0xd1] = 0xeb;
5308141cc406Sopenharmony_ci      dev->regs[0xd2] = 0x0c;
5309141cc406Sopenharmony_ci      dev->regs[0xd7] = 0x10;
5310141cc406Sopenharmony_ci    }
5311141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
5312141cc406Sopenharmony_ci    {
5313141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;	/* 0x45 */
5314141cc406Sopenharmony_ci      /* c5,c6 ?? */
5315141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;	/* 0x1f */
5316141cc406Sopenharmony_ci      /* dev->regs[0xe5] = 0x52;        0x28 */
5317141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);	/* 2*40+2 */
5318141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;	/* 0x75 */
5319141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;	/* 0x0b */
5320141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;	/* 0x54 */
5321141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;	/* 0xb8 */
5322141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;	/* 0x03 */
5323141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;	/* 0x70 */
5324141cc406Sopenharmony_ci    }
5325141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
5326141cc406Sopenharmony_ci    {
5327141cc406Sopenharmony_ci      dev->regs[0x13] = 0x39;	/* 0x20 */
5328141cc406Sopenharmony_ci      dev->regs[0x14] = 0xf0;	/* 0xf8 */
5329141cc406Sopenharmony_ci      dev->regs[0x15] = 0x29;	/* 0x28 */
5330141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;	/* 0x07 */
5331141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;	/* 0x00 */
5332141cc406Sopenharmony_ci      dev->regs[0x23] = 0x00;	/* 0xff */
5333141cc406Sopenharmony_ci      dev->regs[0x35] = 0x48;	/* 0x45 */
5334141cc406Sopenharmony_ci      dev->regs[0x39] = 0x00;	/* 0x02 */
5335141cc406Sopenharmony_ci      dev->regs[0xe2] = 0x0f;	/* 0x1f */
5336141cc406Sopenharmony_ci      SET_DOUBLE (dev->regs, EXPOSURE_REG, 82);	/* 2*40+2 */
5337141cc406Sopenharmony_ci      dev->regs[0xe7] = 0x0e;	/* 0x75 */
5338141cc406Sopenharmony_ci      dev->regs[0xe9] = 0x0a;	/* 0x0b */
5339141cc406Sopenharmony_ci      dev->regs[0xea] = 0xc2;	/* 0x54 */
5340141cc406Sopenharmony_ci      dev->regs[0xed] = 0xf6;	/* 0xb8 */
5341141cc406Sopenharmony_ci      dev->regs[0xef] = 0x02;	/* 0x03 */
5342141cc406Sopenharmony_ci      dev->regs[0xf0] = 0xa8;	/* 0x70 */
5343141cc406Sopenharmony_ci    }
5344141cc406Sopenharmony_ci
5345141cc406Sopenharmony_ci  /* we loop scanning a 637 (1911 bytes) pixels wide area in color mode until each black average
5346141cc406Sopenharmony_ci   * reaches the desired value */
5347141cc406Sopenharmony_ci  do
5348141cc406Sopenharmony_ci    {
5349141cc406Sopenharmony_ci      DBG (DBG_info, "offset_calibration: trying offsets=(%d,%d,%d) ...\n",
5350141cc406Sopenharmony_ci	   ro, go, bo);
5351141cc406Sopenharmony_ci      sanei_rts88xx_set_offset (dev->regs, ro, go, bo);
5352141cc406Sopenharmony_ci      sanei_rts88xx_set_status (dev->devnum, dev->regs, mode, light);
5353141cc406Sopenharmony_ci      rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, 0x02,
5354141cc406Sopenharmony_ci			   CALIBRATION_SIZE, image);
5355141cc406Sopenharmony_ci
5356141cc406Sopenharmony_ci      /* save scanned picture for data debugging */
5357141cc406Sopenharmony_ci      if (DBG_LEVEL >= DBG_io2)
5358141cc406Sopenharmony_ci	{
5359141cc406Sopenharmony_ci	  sprintf (name, "offset%03d.pnm", num);
5360141cc406Sopenharmony_ci	  write_rgb_data (name, image, CALIBRATION_WIDTH, 1);
5361141cc406Sopenharmony_ci	  num++;
5362141cc406Sopenharmony_ci	}
5363141cc406Sopenharmony_ci
5364141cc406Sopenharmony_ci      /* we now compute the average of red pixels from the first 15 pixels */
5365141cc406Sopenharmony_ci      global = average_area (SANE_TRUE, image, 15, 1, &ra, &ga, &ba);
5366141cc406Sopenharmony_ci      DBG (DBG_info,
5367141cc406Sopenharmony_ci	   "offset_calibration: global=%.2f, channels=(%.2f,%.2f,%.2f)\n",
5368141cc406Sopenharmony_ci	   global, ra, ga, ba);
5369141cc406Sopenharmony_ci
5370141cc406Sopenharmony_ci      /* dichotomie ... */
5371141cc406Sopenharmony_ci      if (fabs (ra - OFFSET_TARGET) < OFFSET_MARGIN)
5372141cc406Sopenharmony_ci	{
5373141cc406Sopenharmony_ci	  /* offset is OK */
5374141cc406Sopenharmony_ci	  tro = ro;
5375141cc406Sopenharmony_ci	  bro = ro;
5376141cc406Sopenharmony_ci	}
5377141cc406Sopenharmony_ci      else
5378141cc406Sopenharmony_ci	{			/* NOK */
5379141cc406Sopenharmony_ci	  if (ra > OFFSET_TARGET)
5380141cc406Sopenharmony_ci	    {
5381141cc406Sopenharmony_ci	      tro = ro;
5382141cc406Sopenharmony_ci	      ro = (tro + bro) / 2;
5383141cc406Sopenharmony_ci	    }
5384141cc406Sopenharmony_ci	  if (ra < OFFSET_TARGET)
5385141cc406Sopenharmony_ci	    {
5386141cc406Sopenharmony_ci	      bro = ro;
5387141cc406Sopenharmony_ci	      ro = (tro + bro + 1) / 2;
5388141cc406Sopenharmony_ci	    }
5389141cc406Sopenharmony_ci
5390141cc406Sopenharmony_ci	}
5391141cc406Sopenharmony_ci
5392141cc406Sopenharmony_ci      /* same for blue channel */
5393141cc406Sopenharmony_ci      if (fabs (ba - OFFSET_TARGET) < OFFSET_MARGIN)
5394141cc406Sopenharmony_ci	{
5395141cc406Sopenharmony_ci	  bbo = bo;
5396141cc406Sopenharmony_ci	  tbo = bo;
5397141cc406Sopenharmony_ci	}
5398141cc406Sopenharmony_ci      else
5399141cc406Sopenharmony_ci	{
5400141cc406Sopenharmony_ci	  if (ba > OFFSET_TARGET)
5401141cc406Sopenharmony_ci	    {
5402141cc406Sopenharmony_ci	      tbo = bo;
5403141cc406Sopenharmony_ci	      bo = (tbo + bbo) / 2;
5404141cc406Sopenharmony_ci	    }
5405141cc406Sopenharmony_ci	  if (ba < OFFSET_TARGET)
5406141cc406Sopenharmony_ci	    {
5407141cc406Sopenharmony_ci	      bbo = bo;
5408141cc406Sopenharmony_ci	      bo = (tbo + bbo + 1) / 2;
5409141cc406Sopenharmony_ci	    }
5410141cc406Sopenharmony_ci
5411141cc406Sopenharmony_ci	}
5412141cc406Sopenharmony_ci
5413141cc406Sopenharmony_ci      /* and for green channel */
5414141cc406Sopenharmony_ci      if (fabs (ga - OFFSET_TARGET) < OFFSET_MARGIN)
5415141cc406Sopenharmony_ci	{
5416141cc406Sopenharmony_ci	  tgo = go;
5417141cc406Sopenharmony_ci	  bgo = go;
5418141cc406Sopenharmony_ci	}
5419141cc406Sopenharmony_ci      else
5420141cc406Sopenharmony_ci	{
5421141cc406Sopenharmony_ci	  if (ga > OFFSET_TARGET)
5422141cc406Sopenharmony_ci	    {
5423141cc406Sopenharmony_ci	      tgo = go;
5424141cc406Sopenharmony_ci	      go = (tgo + bgo) / 2;
5425141cc406Sopenharmony_ci	    }
5426141cc406Sopenharmony_ci	  if (ga < OFFSET_TARGET)
5427141cc406Sopenharmony_ci	    {
5428141cc406Sopenharmony_ci	      bgo = go;
5429141cc406Sopenharmony_ci	      go = (tgo + bgo + 1) / 2;
5430141cc406Sopenharmony_ci	    }
5431141cc406Sopenharmony_ci	}
5432141cc406Sopenharmony_ci    }
5433141cc406Sopenharmony_ci  while ((tro != bro) || (tgo != bgo) || (tbo != bbo));
5434141cc406Sopenharmony_ci
5435141cc406Sopenharmony_ci  /* store detected values in device struct */
5436141cc406Sopenharmony_ci  dev->red_offset = bro;
5437141cc406Sopenharmony_ci  dev->green_offset = bgo;
5438141cc406Sopenharmony_ci  dev->blue_offset = bbo;
5439141cc406Sopenharmony_ci
5440141cc406Sopenharmony_ci  DBG (DBG_proc, "offset_calibration: exit\n");
5441141cc406Sopenharmony_ci  return status;
5442141cc406Sopenharmony_ci}
5443141cc406Sopenharmony_ci
5444141cc406Sopenharmony_ci/*
5445141cc406Sopenharmony_ci * do shading calibration
5446141cc406Sopenharmony_ci * We scan a 637 pixels by 66 linesxoffset=24 , xend=661, pixels=637
5447141cc406Sopenharmony_ciy			 offset=1 , yend=67, lines =66
5448141cc406Sopenharmony_ci */
5449141cc406Sopenharmony_cistatic SANE_Status
5450141cc406Sopenharmony_cisetup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int *status1, SANE_Byte * regs)
5451141cc406Sopenharmony_ci{
5452141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
5453141cc406Sopenharmony_ci  int lines = 66;
5454141cc406Sopenharmony_ci  int exposure=0;
5455141cc406Sopenharmony_ci  int timing=0;
5456141cc406Sopenharmony_ci
5457141cc406Sopenharmony_ci  DBG (DBG_proc, "setup_shading_calibration: start\n");
5458141cc406Sopenharmony_ci  DBG (DBG_info, "setup_shading_calibration: sensor type is %s (%d)\n", sensor_name (dev->sensor), dev->sensor);
5459141cc406Sopenharmony_ci
5460141cc406Sopenharmony_ci  /* set up registers */
5461141cc406Sopenharmony_ci  /* 0x20/0x28 0x3b/0x3f seen in logs */
5462141cc406Sopenharmony_ci  *status1 = mode;
5463141cc406Sopenharmony_ci  if (dev->xdpi > 300)
5464141cc406Sopenharmony_ci    {
5465141cc406Sopenharmony_ci      *status1 |= 0x08;
5466141cc406Sopenharmony_ci    }
5467141cc406Sopenharmony_ci
5468141cc406Sopenharmony_ci  /* we default to 75 dpi then override needed registers */
5469141cc406Sopenharmony_ci  timing=0x00b0;
5470141cc406Sopenharmony_ci  regs[0x32] = 0x20;
5471141cc406Sopenharmony_ci  regs[0x33] = 0x83;
5472141cc406Sopenharmony_ci  regs[0x35] = 0x0e;
5473141cc406Sopenharmony_ci  regs[0x36] = 0x2c;
5474141cc406Sopenharmony_ci  regs[0x3a] = 0x0e;
5475141cc406Sopenharmony_ci
5476141cc406Sopenharmony_ci  regs[0xe2] = 0x05;
5477141cc406Sopenharmony_ci  regs[0xe7] = 0x00;
5478141cc406Sopenharmony_ci  regs[0xe8] = 0x00;
5479141cc406Sopenharmony_ci  regs[0xe9] = 0x00;
5480141cc406Sopenharmony_ci  regs[0xea] = 0x00;
5481141cc406Sopenharmony_ci  regs[0xeb] = 0x00;
5482141cc406Sopenharmony_ci  regs[0xec] = 0x00;
5483141cc406Sopenharmony_ci  regs[0xed] = 0x00;
5484141cc406Sopenharmony_ci  regs[0xef] = 0x00;
5485141cc406Sopenharmony_ci  regs[0xf0] = 0x00;
5486141cc406Sopenharmony_ci  regs[0xf2] = 0x00;
5487141cc406Sopenharmony_ci  /* regs[0xe5] = 0xdd; */
5488141cc406Sopenharmony_ci
5489141cc406Sopenharmony_ci  exposure=221;
5490141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
5491141cc406Sopenharmony_ci    {
5492141cc406Sopenharmony_ci      regs[0xc0] = 0x67;
5493141cc406Sopenharmony_ci      regs[0xc1] = 0x06;
5494141cc406Sopenharmony_ci      regs[0xc2] = 0xe6;
5495141cc406Sopenharmony_ci      regs[0xc3] = 0x98;
5496141cc406Sopenharmony_ci      regs[0xc4] = 0xf9;
5497141cc406Sopenharmony_ci      regs[0xc5] = 0x19;
5498141cc406Sopenharmony_ci      regs[0xc6] = 0x67;
5499141cc406Sopenharmony_ci      regs[0xc7] = 0x06;
5500141cc406Sopenharmony_ci      regs[0xc8] = 0xe6;
5501141cc406Sopenharmony_ci      regs[0xc9] = 0x01;
5502141cc406Sopenharmony_ci      regs[0xca] = 0xf8;
5503141cc406Sopenharmony_ci      regs[0xcb] = 0xff;
5504141cc406Sopenharmony_ci      regs[0xcc] = 0x98;
5505141cc406Sopenharmony_ci      regs[0xcd] = 0xf9;
5506141cc406Sopenharmony_ci      regs[0xce] = 0x19;
5507141cc406Sopenharmony_ci      regs[0xcf] = 0xe0;
5508141cc406Sopenharmony_ci      regs[0xd0] = 0xe2;
5509141cc406Sopenharmony_ci
5510141cc406Sopenharmony_ci      regs[0xd1] = 0xeb;
5511141cc406Sopenharmony_ci      regs[0xd2] = 0x0c;
5512141cc406Sopenharmony_ci
5513141cc406Sopenharmony_ci      regs[0xd7] = 0x10;
5514141cc406Sopenharmony_ci    }
5515141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
5516141cc406Sopenharmony_ci    {
5517141cc406Sopenharmony_ci      *light &= 0xf7;		/* clear bit 3 */
5518141cc406Sopenharmony_ci      regs[0x36] = 0x29;	/* 0x2c */
5519141cc406Sopenharmony_ci      timing=0x0032;
5520141cc406Sopenharmony_ci      regs[0x85] = 0x00;	/* 0x8c */
5521141cc406Sopenharmony_ci      regs[0x86] = 0x06;	/* 0x10 */
5522141cc406Sopenharmony_ci      regs[0x87] = 0x00;	/* 0x18 */
5523141cc406Sopenharmony_ci      regs[0x88] = 0x06;	/* 0x1b */
5524141cc406Sopenharmony_ci      regs[0x8d] = 0x00;	/* 0x77 */
5525141cc406Sopenharmony_ci      /* c5,c6 ?? */
5526141cc406Sopenharmony_ci      /* regs[0xd3] = 0x02;         0x0e */
5527141cc406Sopenharmony_ci      regs[0xd4] = 0x04;	/* 0x10 */
5528141cc406Sopenharmony_ci      regs[0xe2] = 0x02;	/* 0x05 */
5529141cc406Sopenharmony_ci      /* regs[0xe5] = 0xbb;
5530141cc406Sopenharmony_ci         regs[0xe6] = 0x01;    1bb =443 */
5531141cc406Sopenharmony_ci      exposure=443;
5532141cc406Sopenharmony_ci    }
5533141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
5534141cc406Sopenharmony_ci    {
5535141cc406Sopenharmony_ci      regs[0x13] = 0x39;	/* 0x20 */
5536141cc406Sopenharmony_ci      regs[0x14] = 0xf0;	/* 0xf8 */
5537141cc406Sopenharmony_ci      regs[0x15] = 0x29;	/* 0x28 */
5538141cc406Sopenharmony_ci      regs[0x16] = 0x0f;	/* 0x07 */
5539141cc406Sopenharmony_ci      regs[0x17] = 0x10;	/* 0x00 */
5540141cc406Sopenharmony_ci      regs[0x23] = 0x00;	/* 0xff */
5541141cc406Sopenharmony_ci      regs[0x36] = 0x29;	/* 0x2c */
5542141cc406Sopenharmony_ci      regs[0x39] = 0x00;	/* 0x02 */
5543141cc406Sopenharmony_ci      regs[0xe2] = 0x02;	/* 0x05 */
5544141cc406Sopenharmony_ci      exposure=443;
5545141cc406Sopenharmony_ci    }
5546141cc406Sopenharmony_ci
5547141cc406Sopenharmony_ci  switch (dev->xdpi)
5548141cc406Sopenharmony_ci    {
5549141cc406Sopenharmony_ci    case 75:
5550141cc406Sopenharmony_ci      break;
5551141cc406Sopenharmony_ci
5552141cc406Sopenharmony_ci    case 150:
5553141cc406Sopenharmony_ci      /* X resolution related registers */
5554141cc406Sopenharmony_ci      switch (dev->sensor)
5555141cc406Sopenharmony_ci	{
5556141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
5557141cc406Sopenharmony_ci	  DBG (DBG_io,
5558141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_XPA for 150 dpi\n");
5559141cc406Sopenharmony_ci          timing=0x022b;
5560141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
5561141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
5562141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
5563141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
5564141cc406Sopenharmony_ci	  regs[0x8d] = 0xef;
5565141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
5566141cc406Sopenharmony_ci	  regs[0xc1] = 0x8e;
5567141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
5568141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
5569141cc406Sopenharmony_ci	  regs[0xc4] = 0x71;
5570141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
5571141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
5572141cc406Sopenharmony_ci	  regs[0xc7] = 0x8e;
5573141cc406Sopenharmony_ci	  regs[0xc8] = 0xff;
5574141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5575141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
5576141cc406Sopenharmony_ci	  regs[0xcb] = 0x1f;
5577141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5578141cc406Sopenharmony_ci	  regs[0xcd] = 0x71;
5579141cc406Sopenharmony_ci	  regs[0xce] = 0x00;
5580141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
5581141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
5582141cc406Sopenharmony_ci	  regs[0xd1] = 0xf6;
5583141cc406Sopenharmony_ci	  regs[0xd2] = 0x17;
5584141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x0b; */
5585141cc406Sopenharmony_ci	  regs[0xd4] = 0x0d;
5586141cc406Sopenharmony_ci	  /* regs[0xe5] = 0xe4; */
5587141cc406Sopenharmony_ci          exposure=228;
5588141cc406Sopenharmony_ci	  break;
5589141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
5590141cc406Sopenharmony_ci	  DBG (DBG_io,
5591141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_BARE for 150 dpi\n");
5592141cc406Sopenharmony_ci          timing=0x012e;
5593141cc406Sopenharmony_ci	  regs[0x85] = 0x8c;
5594141cc406Sopenharmony_ci	  regs[0x86] = 0x10;
5595141cc406Sopenharmony_ci	  regs[0x87] = 0x18;
5596141cc406Sopenharmony_ci	  regs[0x88] = 0x1b;
5597141cc406Sopenharmony_ci	  regs[0x8d] = 0x77;
5598141cc406Sopenharmony_ci	  regs[0xc0] = 0x80;
5599141cc406Sopenharmony_ci	  regs[0xc1] = 0x87;
5600141cc406Sopenharmony_ci	  regs[0xc2] = 0x7f;
5601141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
5602141cc406Sopenharmony_ci	  regs[0xcb] = 0x78;
5603141cc406Sopenharmony_ci	  regs[0xcc] = 0x7f;
5604141cc406Sopenharmony_ci	  regs[0xcd] = 0x78;
5605141cc406Sopenharmony_ci	  regs[0xce] = 0x80;
5606141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
5607141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
5608141cc406Sopenharmony_ci
5609141cc406Sopenharmony_ci	  regs[0xd1] = 0xf7;
5610141cc406Sopenharmony_ci	  regs[0xd2] = 0x00;
5611141cc406Sopenharmony_ci
5612141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x0e; */
5613141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
5614141cc406Sopenharmony_ci
5615141cc406Sopenharmony_ci	  /* regs[0xe5] = 0xe4; */
5616141cc406Sopenharmony_ci          exposure=228;
5617141cc406Sopenharmony_ci	  break;
5618141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
5619141cc406Sopenharmony_ci	  DBG (DBG_io,
5620141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400 for 150 dpi\n");
5621141cc406Sopenharmony_ci          timing=0x012e;
5622141cc406Sopenharmony_ci	  regs[0x85] = 0x8c;
5623141cc406Sopenharmony_ci	  regs[0x86] = 0x10;
5624141cc406Sopenharmony_ci	  regs[0x87] = 0x18;
5625141cc406Sopenharmony_ci	  regs[0x88] = 0x1b;
5626141cc406Sopenharmony_ci	  regs[0x8d] = 0x77;
5627141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
5628141cc406Sopenharmony_ci	  regs[0xc1] = 0x8e;
5629141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
5630141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
5631141cc406Sopenharmony_ci	  regs[0xc4] = 0x71;
5632141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
5633141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
5634141cc406Sopenharmony_ci	  regs[0xc7] = 0x8e;
5635141cc406Sopenharmony_ci	  regs[0xc8] = 0xff;
5636141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5637141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
5638141cc406Sopenharmony_ci	  regs[0xcb] = 0x1f;
5639141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5640141cc406Sopenharmony_ci	  regs[0xcd] = 0x71;
5641141cc406Sopenharmony_ci	  regs[0xce] = 0x00;
5642141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
5643141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
5644141cc406Sopenharmony_ci	  regs[0xd1] = 0xf6;
5645141cc406Sopenharmony_ci	  regs[0xd2] = 0x17;
5646141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x0b; */
5647141cc406Sopenharmony_ci	  regs[0xd4] = 0x0d;
5648141cc406Sopenharmony_ci          exposure=457;
5649141cc406Sopenharmony_ci	  break;
5650141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
5651141cc406Sopenharmony_ci	  DBG (DBG_io,
5652141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400_BARE for 150 dpi\n");
5653141cc406Sopenharmony_ci	  regs[0x13] = 0x39;	/* 0x20 */
5654141cc406Sopenharmony_ci	  regs[0x14] = 0xf0;	/* 0xf8 */
5655141cc406Sopenharmony_ci	  regs[0x15] = 0x29;	/* 0x28 */
5656141cc406Sopenharmony_ci	  regs[0x16] = 0x0f;	/* 0x07 */
5657141cc406Sopenharmony_ci	  regs[0x17] = 0x10;	/* 0x00 */
5658141cc406Sopenharmony_ci	  regs[0x23] = 0x00;	/* 0xff */
5659141cc406Sopenharmony_ci	  regs[0x36] = 0x29;	/* 0x2c */
5660141cc406Sopenharmony_ci	  regs[0x39] = 0x00;	/* 0x02 */
5661141cc406Sopenharmony_ci          timing=0x00b0;
5662141cc406Sopenharmony_ci	  regs[0x85] = 0x46;	/* 0x00 */
5663141cc406Sopenharmony_ci	  regs[0x86] = 0x0b;	/* 0x06 */
5664141cc406Sopenharmony_ci	  regs[0x87] = 0x8c;	/* 0x00 */
5665141cc406Sopenharmony_ci	  regs[0x88] = 0x10;	/* 0x06 */
5666141cc406Sopenharmony_ci	  regs[0x8d] = 0x3b;	/* 0x00 */
5667141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;	/* 0x06 */
5668141cc406Sopenharmony_ci	  regs[0xc1] = 0x0f;	/* 0xe6 */
5669141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;	/* 0x67 */
5670141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;	/* 0x07 */
5671141cc406Sopenharmony_ci	  regs[0xca] = 0x0e;	/* 0x00 */
5672141cc406Sopenharmony_ci	  regs[0xcb] = 0x00;	/* 0xfe */
5673141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;	/* 0xf9 */
5674141cc406Sopenharmony_ci	  regs[0xcd] = 0xf0;	/* 0x19 */
5675141cc406Sopenharmony_ci	  regs[0xce] = 0xff;	/* 0x98 */
5676141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;	/* 0xe8 */
5677141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;	/* 0xea */
5678141cc406Sopenharmony_ci	  regs[0xd1] = 0xea;	/* 0xf3 */
5679141cc406Sopenharmony_ci	  regs[0xd2] = 0x0b;	/* 0x14 */
5680141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x17;     0x02 */
5681141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;	/* 0x04 */
5682141cc406Sopenharmony_ci	  regs[0xe2] = 0x02;	/* 0x05 */
5683141cc406Sopenharmony_ci	  /* regs[0xe5] = 0x93;   regs[0xe6] = 0x03; */
5684141cc406Sopenharmony_ci          exposure=915;
5685141cc406Sopenharmony_ci	  break;
5686141cc406Sopenharmony_ci	}
5687141cc406Sopenharmony_ci      break;
5688141cc406Sopenharmony_ci
5689141cc406Sopenharmony_ci    case 300:
5690141cc406Sopenharmony_ci      switch (dev->sensor)
5691141cc406Sopenharmony_ci	{
5692141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
5693141cc406Sopenharmony_ci	  DBG (DBG_io,
5694141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_XPA for 300 dpi\n");
5695141cc406Sopenharmony_ci          timing=0x00b0;
5696141cc406Sopenharmony_ci	  regs[0x85] = 0x46;
5697141cc406Sopenharmony_ci	  regs[0x86] = 0x0b;
5698141cc406Sopenharmony_ci	  regs[0x87] = 0x8c;
5699141cc406Sopenharmony_ci	  regs[0x88] = 0x10;
5700141cc406Sopenharmony_ci	  regs[0x8d] = 0x3b;
5701141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
5702141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
5703141cc406Sopenharmony_ci	  regs[0xc2] = 0x0f;
5704141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
5705141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
5706141cc406Sopenharmony_ci	  regs[0xc5] = 0xf0;
5707141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
5708141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
5709141cc406Sopenharmony_ci	  regs[0xc8] = 0x0f;
5710141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5711141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
5712141cc406Sopenharmony_ci	  regs[0xcb] = 0xf1;
5713141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5714141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
5715141cc406Sopenharmony_ci	  regs[0xce] = 0xf0;
5716141cc406Sopenharmony_ci	  regs[0xcf] = 0xed;
5717141cc406Sopenharmony_ci	  regs[0xd0] = 0xef;
5718141cc406Sopenharmony_ci	  regs[0xd1] = 0xe2;
5719141cc406Sopenharmony_ci	  regs[0xd2] = 0x03;
5720141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x17; */
5721141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
5722141cc406Sopenharmony_ci	  /* regs[0xe5] = 0xc9;
5723141cc406Sopenharmony_ci	     regs[0xe6] = 0x01;     0x01c9=457 */
5724141cc406Sopenharmony_ci          exposure=457;
5725141cc406Sopenharmony_ci	  break;
5726141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
5727141cc406Sopenharmony_ci	  DBG (DBG_io,
5728141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_BARE for 300 dpi\n");
5729141cc406Sopenharmony_ci          timing=0x012e;
5730141cc406Sopenharmony_ci	  regs[0x85] = 0x8c;
5731141cc406Sopenharmony_ci	  regs[0x86] = 0x10;
5732141cc406Sopenharmony_ci	  regs[0x87] = 0x18;
5733141cc406Sopenharmony_ci	  regs[0x88] = 0x1b;
5734141cc406Sopenharmony_ci
5735141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
5736141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;	/* low nibble of 8e and 8d are proportional to
5737141cc406Sopenharmony_ci					   the scanned width 1de => 5100 wide scan */
5738141cc406Sopenharmony_ci
5739141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
5740141cc406Sopenharmony_ci	  regs[0xc1] = 0x0f;
5741141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
5742141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
5743141cc406Sopenharmony_ci	  regs[0xca] = 0x0e;
5744141cc406Sopenharmony_ci	  regs[0xcb] = 0x00;
5745141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
5746141cc406Sopenharmony_ci	  regs[0xcd] = 0xf0;
5747141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
5748141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
5749141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
5750141cc406Sopenharmony_ci
5751141cc406Sopenharmony_ci	  regs[0xd1] = 0xea;
5752141cc406Sopenharmony_ci	  regs[0xd2] = 0x0b;
5753141cc406Sopenharmony_ci
5754141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x17; */
5755141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
5756141cc406Sopenharmony_ci	  /* regs[0xe5] = 0xc9;
5757141cc406Sopenharmony_ci	     regs[0xe6] = 0x01;    0x1c9=457 */
5758141cc406Sopenharmony_ci          exposure=457;
5759141cc406Sopenharmony_ci	  break;
5760141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
5761141cc406Sopenharmony_ci	  DBG (DBG_io,
5762141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400 for 300 dpi\n");
5763141cc406Sopenharmony_ci          timing=0x022b;
5764141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
5765141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
5766141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
5767141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
5768141cc406Sopenharmony_ci	  regs[0x8d] = 0xef;
5769141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
5770141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
5771141cc406Sopenharmony_ci	  regs[0xc2] = 0x0f;
5772141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
5773141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
5774141cc406Sopenharmony_ci	  regs[0xc5] = 0xf0;
5775141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
5776141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
5777141cc406Sopenharmony_ci	  regs[0xc8] = 0x0f;
5778141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5779141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
5780141cc406Sopenharmony_ci	  regs[0xcb] = 0xf1;
5781141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5782141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
5783141cc406Sopenharmony_ci	  regs[0xce] = 0xf0;
5784141cc406Sopenharmony_ci	  regs[0xcf] = 0xed;
5785141cc406Sopenharmony_ci	  regs[0xd0] = 0xef;
5786141cc406Sopenharmony_ci	  regs[0xd1] = 0xe2;
5787141cc406Sopenharmony_ci	  regs[0xd2] = 0x03;
5788141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x17; */
5789141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
5790141cc406Sopenharmony_ci	  /* 0x0393 = 915 = 2*457+1 */
5791141cc406Sopenharmony_ci          exposure=915;
5792141cc406Sopenharmony_ci	  break;
5793141cc406Sopenharmony_ci
5794141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
5795141cc406Sopenharmony_ci	  DBG (DBG_io,
5796141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400_BARE for 300 dpi\n");
5797141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
5798141cc406Sopenharmony_ci	  break;
5799141cc406Sopenharmony_ci	}
5800141cc406Sopenharmony_ci      break;
5801141cc406Sopenharmony_ci
5802141cc406Sopenharmony_ci    case 600:
5803141cc406Sopenharmony_ci      switch (dev->sensor)
5804141cc406Sopenharmony_ci	{
5805141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
5806141cc406Sopenharmony_ci	  DBG (DBG_io,
5807141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_BARE for 600 dpi\n");
5808141cc406Sopenharmony_ci	  regs[0x34] = 0x10;
5809141cc406Sopenharmony_ci
5810141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
5811141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
5812141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
5813141cc406Sopenharmony_ci
5814141cc406Sopenharmony_ci          timing=0x022b;
5815141cc406Sopenharmony_ci
5816141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
5817141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
5818141cc406Sopenharmony_ci
5819141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
5820141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
5821141cc406Sopenharmony_ci
5822141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
5823141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;	/* low nibble of 8e and 8d are proportional to
5824141cc406Sopenharmony_ci					   the scanned width 1de => 5100 wide scan */
5825141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
5826141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
5827141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
5828141cc406Sopenharmony_ci	  regs[0xc3] = 0x00;
5829141cc406Sopenharmony_ci	  regs[0xc4] = 0xf0;
5830141cc406Sopenharmony_ci	  regs[0xc7] = 0x0f;
5831141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
5832141cc406Sopenharmony_ci	  regs[0xcb] = 0xe0;
5833141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5834141cc406Sopenharmony_ci	  regs[0xcd] = 0xff;
5835141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
5836141cc406Sopenharmony_ci	  regs[0xcf] = 0xe9;
5837141cc406Sopenharmony_ci	  regs[0xd0] = 0xeb;
5838141cc406Sopenharmony_ci
5839141cc406Sopenharmony_ci	  regs[0xd7] = 0x14;
5840141cc406Sopenharmony_ci
5841141cc406Sopenharmony_ci	  /* regs[0xe5] = 0x93;
5842141cc406Sopenharmony_ci	     regs[0xe6] = 0x03;         0x393=915 = 457*2+1 */
5843141cc406Sopenharmony_ci          exposure=915;
5844141cc406Sopenharmony_ci	  break;
5845141cc406Sopenharmony_ci
5846141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
5847141cc406Sopenharmony_ci	  DBG (DBG_io,
5848141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_XPA for 600 dpi\n");
5849141cc406Sopenharmony_ci          *light &= 0xfb;		/* clear bit 2 */
5850141cc406Sopenharmony_ci          regs[0x16] = 0x07;
5851141cc406Sopenharmony_ci	  regs[0x33] = 0x83;       /* 0x86 */
5852141cc406Sopenharmony_ci	  regs[0x34] = 0x10;
5853141cc406Sopenharmony_ci	  regs[0x50] = 0x00;       /* 0x18 */
5854141cc406Sopenharmony_ci	  regs[0x64] = 0x01;       /* 0x02 */
5855141cc406Sopenharmony_ci	  regs[0x65] = 0x20;       /* 0x10 */
5856141cc406Sopenharmony_ci
5857141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
5858141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
5859141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
5860141cc406Sopenharmony_ci
5861141cc406Sopenharmony_ci	  regs[0x85] = 0x00;
5862141cc406Sopenharmony_ci	  regs[0x86] = 0x06;
5863141cc406Sopenharmony_ci
5864141cc406Sopenharmony_ci	  regs[0x87] = 0x00;
5865141cc406Sopenharmony_ci	  regs[0x88] = 0x06;
5866141cc406Sopenharmony_ci
5867141cc406Sopenharmony_ci	  regs[0x8d] = 0x00;
5868141cc406Sopenharmony_ci	  regs[0x8e] = 0x60; /* XXX STEF XXX */
5869141cc406Sopenharmony_ci
5870141cc406Sopenharmony_ci	  regs[0xc0] = 0xf8;
5871141cc406Sopenharmony_ci	  regs[0xc1] = 0x7f;
5872141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
5873141cc406Sopenharmony_ci	  regs[0xc3] = 0xf8;
5874141cc406Sopenharmony_ci	  regs[0xc4] = 0x7f;
5875141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
5876141cc406Sopenharmony_ci	  regs[0xc6] = 0xf8;
5877141cc406Sopenharmony_ci	  regs[0xc7] = 0x7f;
5878141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
5879141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5880141cc406Sopenharmony_ci	  regs[0xca] = 0x8f;
5881141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
5882141cc406Sopenharmony_ci	  regs[0xcc] = 0x07;
5883141cc406Sopenharmony_ci	  regs[0xcd] = 0x80;
5884141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
5885141cc406Sopenharmony_ci	  regs[0xcf] = 0xf2;
5886141cc406Sopenharmony_ci	  regs[0xd0] = 0xf4;
5887141cc406Sopenharmony_ci	  regs[0xd1] = 0xe7;
5888141cc406Sopenharmony_ci	  regs[0xd2] = 0x08;
5889141cc406Sopenharmony_ci	  regs[0xd3] = 0x0e;
5890141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
5891141cc406Sopenharmony_ci	  regs[0xd7] = 0x31;
5892141cc406Sopenharmony_ci
5893141cc406Sopenharmony_ci          timing=0x0032;
5894141cc406Sopenharmony_ci          exposure=915;
5895141cc406Sopenharmony_ci	  break;
5896141cc406Sopenharmony_ci
5897141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
5898141cc406Sopenharmony_ci	  DBG (DBG_io,
5899141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400 for 600 dpi\n");
5900141cc406Sopenharmony_ci	  *light = 0x23;
5901141cc406Sopenharmony_ci
5902141cc406Sopenharmony_ci	  regs[0x13] = 0x39;
5903141cc406Sopenharmony_ci	  regs[0x14] = 0xf0;
5904141cc406Sopenharmony_ci	  regs[0x15] = 0x29;
5905141cc406Sopenharmony_ci	  regs[0x16] = 0x0f;
5906141cc406Sopenharmony_ci	  regs[0x17] = 0x10;
5907141cc406Sopenharmony_ci	  regs[0x23] = 0x00;
5908141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
5909141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
5910141cc406Sopenharmony_ci	  regs[0x39] = 0x00;
5911141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
5912141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
5913141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
5914141cc406Sopenharmony_ci          timing=0x0426;
5915141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
5916141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
5917141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
5918141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
5919141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
5920141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;
5921141cc406Sopenharmony_ci	  regs[0xc0] = 0xf8;
5922141cc406Sopenharmony_ci	  regs[0xc1] = 0x7f;
5923141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
5924141cc406Sopenharmony_ci	  regs[0xc3] = 0xf8;
5925141cc406Sopenharmony_ci	  regs[0xc4] = 0x7f;
5926141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
5927141cc406Sopenharmony_ci	  regs[0xc6] = 0xf8;
5928141cc406Sopenharmony_ci	  regs[0xc7] = 0x7f;
5929141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
5930141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
5931141cc406Sopenharmony_ci	  regs[0xca] = 0x8f;
5932141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
5933141cc406Sopenharmony_ci	  regs[0xcc] = 0x07;
5934141cc406Sopenharmony_ci	  regs[0xcd] = 0x80;
5935141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
5936141cc406Sopenharmony_ci	  regs[0xcf] = 0xf2;
5937141cc406Sopenharmony_ci	  regs[0xd0] = 0xf4;
5938141cc406Sopenharmony_ci	  regs[0xd1] = 0xe7;
5939141cc406Sopenharmony_ci	  regs[0xd2] = 0x08;
5940141cc406Sopenharmony_ci	  regs[0xd3] = 0x0e;
5941141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
5942141cc406Sopenharmony_ci	  regs[0xd7] = 0x31;
5943141cc406Sopenharmony_ci	  regs[0xe2] = 0x02;
5944141cc406Sopenharmony_ci          exposure=1832;
5945141cc406Sopenharmony_ci
5946141cc406Sopenharmony_ci	  break;
5947141cc406Sopenharmony_ci
5948141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
5949141cc406Sopenharmony_ci	  DBG (DBG_io,
5950141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400_BARE for 600 dpi\n");
5951141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
5952141cc406Sopenharmony_ci	  break;
5953141cc406Sopenharmony_ci	}
5954141cc406Sopenharmony_ci      break;
5955141cc406Sopenharmony_ci
5956141cc406Sopenharmony_ci    case 1200:
5957141cc406Sopenharmony_ci      switch (dev->sensor)
5958141cc406Sopenharmony_ci	{
5959141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
5960141cc406Sopenharmony_ci	  DBG (DBG_io,
5961141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_BARE for 1200 dpi\n");
5962141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
5963141cc406Sopenharmony_ci	  regs[0x40] = 0xa0;
5964141cc406Sopenharmony_ci
5965141cc406Sopenharmony_ci          timing=0x0426;
5966141cc406Sopenharmony_ci
5967141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
5968141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
5969141cc406Sopenharmony_ci
5970141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
5971141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
5972141cc406Sopenharmony_ci
5973141cc406Sopenharmony_ci	  regs[0x8d] = 0xbd;
5974141cc406Sopenharmony_ci	  regs[0x8e] = 0x63;
5975141cc406Sopenharmony_ci
5976141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
5977141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
5978141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
5979141cc406Sopenharmony_ci	  regs[0xc4] = 0x0f;
5980141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
5981141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
5982141cc406Sopenharmony_ci	  regs[0xc7] = 0xf0;
5983141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
5984141cc406Sopenharmony_ci	  regs[0xca] = 0x0e;
5985141cc406Sopenharmony_ci	  regs[0xcb] = 0x00;
5986141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
5987141cc406Sopenharmony_ci	  regs[0xcd] = 0xff;
5988141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
5989141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
5990141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
5991141cc406Sopenharmony_ci	  regs[0xd1] = 0xea;
5992141cc406Sopenharmony_ci	  regs[0xd2] = 0x0b;
5993141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x17; */
5994141cc406Sopenharmony_ci	  regs[0xd4] = 0xc1;
5995141cc406Sopenharmony_ci	  regs[0xd7] = 0x14;
5996141cc406Sopenharmony_ci	  regs[0xd8] = 0xa4;
5997141cc406Sopenharmony_ci	  /* regs[0xe5] = 0x28;
5998141cc406Sopenharmony_ci	     regs[0xe6] = 0x07;         0x728=1832=915*2+2 */
5999141cc406Sopenharmony_ci          exposure=1832;
6000141cc406Sopenharmony_ci	  break;
6001141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
6002141cc406Sopenharmony_ci	  DBG (DBG_io,
6003141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_XPA for 1200 dpi\n");
6004141cc406Sopenharmony_ci	  regs[0x34] = 0x10;
6005141cc406Sopenharmony_ci	  regs[0x40] = 0xa0;
6006141cc406Sopenharmony_ci
6007141cc406Sopenharmony_ci          timing=0x00b0;
6008141cc406Sopenharmony_ci          exposure=1832;
6009141cc406Sopenharmony_ci
6010141cc406Sopenharmony_ci          /* XXX STEF XXX */
6011141cc406Sopenharmony_ci	  regs[0x85] = 0x46;
6012141cc406Sopenharmony_ci	  regs[0x86] = 0x0b;
6013141cc406Sopenharmony_ci
6014141cc406Sopenharmony_ci	  regs[0x87] = 0x8c;
6015141cc406Sopenharmony_ci	  regs[0x88] = 0x10;
6016141cc406Sopenharmony_ci
6017141cc406Sopenharmony_ci	  regs[0x8e] = 0x3b;
6018141cc406Sopenharmony_ci	  regs[0x8d] = 0x60;
6019141cc406Sopenharmony_ci
6020141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
6021141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
6022141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
6023141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
6024141cc406Sopenharmony_ci	  regs[0x33] = 0x83;
6025141cc406Sopenharmony_ci	  regs[0x50] = 0x00;
6026141cc406Sopenharmony_ci	  regs[0x64] = 0x01;
6027141cc406Sopenharmony_ci	  regs[0x65] = 0x20;
6028141cc406Sopenharmony_ci	  regs[0x8d] = 0xbc;
6029141cc406Sopenharmony_ci	  regs[0xc0] = 0xe0;
6030141cc406Sopenharmony_ci	  regs[0xc2] = 0x01;
6031141cc406Sopenharmony_ci	  regs[0xc3] = 0x1f;
6032141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
6033141cc406Sopenharmony_ci	  regs[0xc5] = 0xfe;
6034141cc406Sopenharmony_ci	  regs[0xc6] = 0xff;
6035141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
6036141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
6037141cc406Sopenharmony_ci	  regs[0xc9] = 0x3f;
6038141cc406Sopenharmony_ci	  regs[0xca] = 0xfe;
6039141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
6040141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
6041141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
6042141cc406Sopenharmony_ci	  regs[0xd1] = 0xec;
6043141cc406Sopenharmony_ci	  regs[0xd2] = 0x0d;
6044141cc406Sopenharmony_ci	  regs[0xd3] = 0x05;
6045141cc406Sopenharmony_ci	  regs[0xd4] = 0x67;
6046141cc406Sopenharmony_ci	  regs[0xd7] = 0x10;
6047141cc406Sopenharmony_ci	  regs[0xd8] = 0x52;
6048141cc406Sopenharmony_ci	  break;
6049141cc406Sopenharmony_ci
6050141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
6051141cc406Sopenharmony_ci	  DBG (DBG_io,
6052141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400 for 1200 dpi\n");
6053141cc406Sopenharmony_ci	  regs[0x13] = 0x39;
6054141cc406Sopenharmony_ci	  regs[0x14] = 0xf0;
6055141cc406Sopenharmony_ci	  regs[0x15] = 0x29;
6056141cc406Sopenharmony_ci	  regs[0x16] = 0x0f;
6057141cc406Sopenharmony_ci	  regs[0x17] = 0x10;
6058141cc406Sopenharmony_ci	  regs[0x23] = 0x00;
6059141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
6060141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
6061141cc406Sopenharmony_ci	  regs[0x39] = 0x00;
6062141cc406Sopenharmony_ci	  regs[0x40] = 0xa0;
6063141cc406Sopenharmony_ci          timing=0x0426;
6064141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
6065141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
6066141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
6067141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
6068141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
6069141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;
6070141cc406Sopenharmony_ci	  regs[0xc0] = 0xe0;
6071141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
6072141cc406Sopenharmony_ci	  regs[0xc2] = 0x01;
6073141cc406Sopenharmony_ci	  regs[0xc3] = 0x1f;
6074141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
6075141cc406Sopenharmony_ci	  regs[0xc5] = 0xfe;
6076141cc406Sopenharmony_ci	  regs[0xc6] = 0xff;
6077141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
6078141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
6079141cc406Sopenharmony_ci	  regs[0xc9] = 0x3f;
6080141cc406Sopenharmony_ci	  regs[0xca] = 0xfe;
6081141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
6082141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
6083141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
6084141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
6085141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
6086141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
6087141cc406Sopenharmony_ci	  regs[0xd1] = 0xec;
6088141cc406Sopenharmony_ci	  regs[0xd2] = 0x0d;
6089141cc406Sopenharmony_ci	  /* regs[0xd3] = 0x05; */
6090141cc406Sopenharmony_ci	  regs[0xd4] = 0x67;
6091141cc406Sopenharmony_ci	  regs[0xd7] = 0x10;
6092141cc406Sopenharmony_ci	  regs[0xd8] = 0x52;
6093141cc406Sopenharmony_ci	  regs[0xe2] = 0x02;
6094141cc406Sopenharmony_ci	  *light = 0x23;
6095141cc406Sopenharmony_ci          exposure=3665;
6096141cc406Sopenharmony_ci	  break;
6097141cc406Sopenharmony_ci
6098141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
6099141cc406Sopenharmony_ci	  DBG (DBG_io,
6100141cc406Sopenharmony_ci	       "setup_shading_calibration: setting up SENSOR_TYPE_4400_BARE for 1200 dpi\n");
6101141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
6102141cc406Sopenharmony_ci	  break;
6103141cc406Sopenharmony_ci	}
6104141cc406Sopenharmony_ci      break;
6105141cc406Sopenharmony_ci    }
6106141cc406Sopenharmony_ci
6107141cc406Sopenharmony_ci  /* apply computed settings */
6108141cc406Sopenharmony_ci  SET_DOUBLE (regs, EXPOSURE_REG, exposure);
6109141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING_REG, timing);
6110141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING1_REG, timing+1);
6111141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING2_REG, timing+2);
6112141cc406Sopenharmony_ci
6113141cc406Sopenharmony_ci  /* in logs, the driver use the computed offset minus 2 */
6114141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (regs, dev->red_offset, dev->green_offset, dev->blue_offset);
6115141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (regs, dev->red_gain, dev->green_gain, dev->blue_gain);
6116141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (regs, 1, 1 + lines, dev->xstart, dev->xstart + dev->pixels);
6117141cc406Sopenharmony_ci
6118141cc406Sopenharmony_ci  DBG (DBG_proc, "setup_shading_calibration: exit\n");
6119141cc406Sopenharmony_ci  return status;
6120141cc406Sopenharmony_ci}
6121141cc406Sopenharmony_ci
6122141cc406Sopenharmony_ci/*
6123141cc406Sopenharmony_ci * do shading calibration
6124141cc406Sopenharmony_ci * We scan a 637 pixels by 66 linesxoffset=24 , xend=661, pixels=637
6125141cc406Sopenharmony_ciy			 offset=1 , yend=67, lines =66
6126141cc406Sopenharmony_ci */
6127141cc406Sopenharmony_cistatic SANE_Status
6128141cc406Sopenharmony_cishading_calibration (struct Rts8891_Device *dev, SANE_Bool color, int mode, int light)
6129141cc406Sopenharmony_ci{
6130141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
6131141cc406Sopenharmony_ci  int width;
6132141cc406Sopenharmony_ci  int lines = 66;
6133141cc406Sopenharmony_ci  SANE_Byte format;
6134141cc406Sopenharmony_ci  int size;
6135141cc406Sopenharmony_ci  int status1;
6136141cc406Sopenharmony_ci  int x, y, sum;
6137141cc406Sopenharmony_ci  SANE_Byte *image = NULL;
6138141cc406Sopenharmony_ci  FILE *dbg = NULL;
6139141cc406Sopenharmony_ci
6140141cc406Sopenharmony_ci  DBG (DBG_proc, "shading_calibration: start\n");
6141141cc406Sopenharmony_ci  DBG (DBG_info, "shading_calibration: sensor type is %s (%d)\n",
6142141cc406Sopenharmony_ci       sensor_name (dev->sensor), dev->sensor);
6143141cc406Sopenharmony_ci
6144141cc406Sopenharmony_ci  width = dev->pixels;
6145141cc406Sopenharmony_ci  size = lines * dev->bytes_per_line;
6146141cc406Sopenharmony_ci
6147141cc406Sopenharmony_ci  image = (SANE_Byte *) malloc (size);
6148141cc406Sopenharmony_ci  if (image == NULL)
6149141cc406Sopenharmony_ci    {
6150141cc406Sopenharmony_ci      DBG (DBG_error,
6151141cc406Sopenharmony_ci	   "shading_calibration: failed to allocate memory for image\n");
6152141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
6153141cc406Sopenharmony_ci    }
6154141cc406Sopenharmony_ci  if (dev->shading_data != NULL)
6155141cc406Sopenharmony_ci    free (dev->shading_data);
6156141cc406Sopenharmony_ci  dev->shading_data = (unsigned char *) malloc (dev->bytes_per_line);
6157141cc406Sopenharmony_ci  if (dev->shading_data == NULL)
6158141cc406Sopenharmony_ci    {
6159141cc406Sopenharmony_ci      free (image);
6160141cc406Sopenharmony_ci      DBG (DBG_error,
6161141cc406Sopenharmony_ci	   "shading_calibration: failed to allocate memory for data\n");
6162141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
6163141cc406Sopenharmony_ci    }
6164141cc406Sopenharmony_ci
6165141cc406Sopenharmony_ci  /* set up registers */
6166141cc406Sopenharmony_ci  status=setup_shading_calibration(dev, mode, &light, &status1, dev->regs);
6167141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
6168141cc406Sopenharmony_ci    {
6169141cc406Sopenharmony_ci      DBG (DBG_error, "shading_calibration: failed to set up registers\n");
6170141cc406Sopenharmony_ci      free (dev->shading_data);
6171141cc406Sopenharmony_ci      dev->shading_data = NULL;
6172141cc406Sopenharmony_ci      free (image);
6173141cc406Sopenharmony_ci      return status;
6174141cc406Sopenharmony_ci    }
6175141cc406Sopenharmony_ci
6176141cc406Sopenharmony_ci  /* scan shading area */
6177141cc406Sopenharmony_ci  sanei_rts88xx_set_status (dev->devnum, dev->regs, status1, light);
6178141cc406Sopenharmony_ci  format = rts8891_data_format (dev->xdpi, dev->sensor);
6179141cc406Sopenharmony_ci  status = rts8891_simple_scan (dev->devnum, dev->regs, dev->reg_count, format, size, image);
6180141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
6181141cc406Sopenharmony_ci    {
6182141cc406Sopenharmony_ci      DBG (DBG_error, "shading_calibration: failed scan shading area\n");
6183141cc406Sopenharmony_ci      free (dev->shading_data);
6184141cc406Sopenharmony_ci      dev->shading_data = NULL;
6185141cc406Sopenharmony_ci      free (image);
6186141cc406Sopenharmony_ci      return status;
6187141cc406Sopenharmony_ci    }
6188141cc406Sopenharmony_ci
6189141cc406Sopenharmony_ci  if (DBG_LEVEL >= DBG_io2)
6190141cc406Sopenharmony_ci    {
6191141cc406Sopenharmony_ci      dbg = fopen ("shading.pnm", "wb");
6192141cc406Sopenharmony_ci      if (color)
6193141cc406Sopenharmony_ci	{
6194141cc406Sopenharmony_ci	  fprintf (dbg, "P6\n%d %d\n255\n", width, lines);
6195141cc406Sopenharmony_ci	  fwrite (image, width * 3, lines, dbg);
6196141cc406Sopenharmony_ci	}
6197141cc406Sopenharmony_ci      else
6198141cc406Sopenharmony_ci	{
6199141cc406Sopenharmony_ci	  fprintf (dbg, "P5\n%d %d\n255\n", width, lines);
6200141cc406Sopenharmony_ci	  fwrite (image, width, lines, dbg);
6201141cc406Sopenharmony_ci	}
6202141cc406Sopenharmony_ci      fclose (dbg);
6203141cc406Sopenharmony_ci    }
6204141cc406Sopenharmony_ci
6205141cc406Sopenharmony_ci  /* now we can compute shading calibration data */
6206141cc406Sopenharmony_ci  /* we average each row */
6207141cc406Sopenharmony_ci  /* we take the maximum of each row */
6208141cc406Sopenharmony_ci  /* we skip first 3 lines and last 10 lines due to some bugs */
6209141cc406Sopenharmony_ci  if (color)
6210141cc406Sopenharmony_ci    {
6211141cc406Sopenharmony_ci      width = width * 3;
6212141cc406Sopenharmony_ci    }
6213141cc406Sopenharmony_ci  for (x = 0; x < width; x++)
6214141cc406Sopenharmony_ci    {
6215141cc406Sopenharmony_ci      sum = 0;
6216141cc406Sopenharmony_ci      for (y = 3; y < lines - 10; y++)
6217141cc406Sopenharmony_ci	{
6218141cc406Sopenharmony_ci	  sum += image[x + y * width];
6219141cc406Sopenharmony_ci	}
6220141cc406Sopenharmony_ci      dev->shading_data[x] = sum / (lines - 13);
6221141cc406Sopenharmony_ci    }
6222141cc406Sopenharmony_ci  if (DBG_LEVEL >= DBG_io2)
6223141cc406Sopenharmony_ci    {
6224141cc406Sopenharmony_ci      dbg = fopen ("shading_data.pnm", "wb");
6225141cc406Sopenharmony_ci      if (color)
6226141cc406Sopenharmony_ci	{
6227141cc406Sopenharmony_ci	  fprintf (dbg, "P6\n%d %d\n255\n", width / 3, 1);
6228141cc406Sopenharmony_ci	  fwrite (dev->shading_data, width, 1, dbg);
6229141cc406Sopenharmony_ci	}
6230141cc406Sopenharmony_ci      else
6231141cc406Sopenharmony_ci	{
6232141cc406Sopenharmony_ci	  fprintf (dbg, "P5\n%d %d\n255\n", width, 1);
6233141cc406Sopenharmony_ci	  fwrite (dev->shading_data, width, 1, dbg);
6234141cc406Sopenharmony_ci	}
6235141cc406Sopenharmony_ci      fclose (dbg);
6236141cc406Sopenharmony_ci    }
6237141cc406Sopenharmony_ci
6238141cc406Sopenharmony_ci  free (image);
6239141cc406Sopenharmony_ci  DBG (DBG_proc, "shading_calibration: exit\n");
6240141cc406Sopenharmony_ci  return status;
6241141cc406Sopenharmony_ci}
6242141cc406Sopenharmony_ci
6243141cc406Sopenharmony_cistatic void
6244141cc406Sopenharmony_cifill_gamma (SANE_Byte * calibration, int *idx, SANE_Word * gamma)
6245141cc406Sopenharmony_ci{
6246141cc406Sopenharmony_ci  int i;
6247141cc406Sopenharmony_ci
6248141cc406Sopenharmony_ci  calibration[*idx] = 0;
6249141cc406Sopenharmony_ci  (*idx)++;
6250141cc406Sopenharmony_ci  for (i = 0; i < 255; i++)
6251141cc406Sopenharmony_ci    {
6252141cc406Sopenharmony_ci      calibration[*idx] = gamma[i];
6253141cc406Sopenharmony_ci      /* escape 0xaa with 0 */
6254141cc406Sopenharmony_ci      if (calibration[*idx] == 0xaa)
6255141cc406Sopenharmony_ci	{
6256141cc406Sopenharmony_ci	  (*idx)++;
6257141cc406Sopenharmony_ci	  calibration[*idx] = 0;
6258141cc406Sopenharmony_ci	}
6259141cc406Sopenharmony_ci      (*idx)++;
6260141cc406Sopenharmony_ci      calibration[*idx] = gamma[i];
6261141cc406Sopenharmony_ci      /* escape 0xaa with 0 */
6262141cc406Sopenharmony_ci      if (calibration[*idx] == 0xaa)
6263141cc406Sopenharmony_ci	{
6264141cc406Sopenharmony_ci	  (*idx)++;
6265141cc406Sopenharmony_ci	  calibration[*idx] = 0;
6266141cc406Sopenharmony_ci	}
6267141cc406Sopenharmony_ci      (*idx)++;
6268141cc406Sopenharmony_ci    }
6269141cc406Sopenharmony_ci  calibration[*idx] = 0xff;
6270141cc406Sopenharmony_ci  (*idx)++;
6271141cc406Sopenharmony_ci}
6272141cc406Sopenharmony_ci
6273141cc406Sopenharmony_ci/*
6274141cc406Sopenharmony_ci * build and send calibration data which contains gamma table and
6275141cc406Sopenharmony_ci * shading correction coefficient
6276141cc406Sopenharmony_ci *
6277141cc406Sopenharmony_ci */
6278141cc406Sopenharmony_cistatic SANE_Status
6279141cc406Sopenharmony_cisend_calibration_data (struct Rts8891_Session *session)
6280141cc406Sopenharmony_ci{
6281141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
6282141cc406Sopenharmony_ci  int size, width, data_size;
6283141cc406Sopenharmony_ci  SANE_Byte *calibration = NULL, format, val;
6284141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
6285141cc406Sopenharmony_ci  int i, idx;
6286141cc406Sopenharmony_ci  unsigned int value, red_code, blue_code, green_code;
6287141cc406Sopenharmony_ci  FILE *calib = NULL;
6288141cc406Sopenharmony_ci  SANE_Word *gamma_r, *gamma_g, *gamma_b;
6289141cc406Sopenharmony_ci
6290141cc406Sopenharmony_ci  DBG (DBG_proc, "send_calibration_data: start\n");
6291141cc406Sopenharmony_ci
6292141cc406Sopenharmony_ci  /* 675 pixels at 75 DPI, 16 bits values, 3 color channels */
6293141cc406Sopenharmony_ci  /* 5400 pixels at max sensor 600 dpi                      */
6294141cc406Sopenharmony_ci  /* 3 16bits 256 value gamma tables plus start/end markers */
6295141cc406Sopenharmony_ci  /* must multiple of 32 */
6296141cc406Sopenharmony_ci  data_size = (675 * dev->xdpi) / 75;
6297141cc406Sopenharmony_ci
6298141cc406Sopenharmony_ci  width = dev->pixels;
6299141cc406Sopenharmony_ci
6300141cc406Sopenharmony_ci  /* effective data calibration size */
6301141cc406Sopenharmony_ci  size = data_size * 2 * 3 + 3 * (512 + 2);
6302141cc406Sopenharmony_ci  size = ((size + 31) / 32) * 32;
6303141cc406Sopenharmony_ci
6304141cc406Sopenharmony_ci  DBG (DBG_io, "send_calibration_data: size=%d\n", size);
6305141cc406Sopenharmony_ci
6306141cc406Sopenharmony_ci  /*
6307141cc406Sopenharmony_ci   * FORMAT:
6308141cc406Sopenharmony_ci   * 00
6309141cc406Sopenharmony_ci   * 512 bytes gamma table (256 16 bit entry)
6310141cc406Sopenharmony_ci   * FF
6311141cc406Sopenharmony_ci   * 00
6312141cc406Sopenharmony_ci   * 512 bytes gamma table (256 16 bit entry)
6313141cc406Sopenharmony_ci   * FF
6314141cc406Sopenharmony_ci   * 00
6315141cc406Sopenharmony_ci   * 512 bytes gamma table (256 16 bit entry)
6316141cc406Sopenharmony_ci   * FF
6317141cc406Sopenharmony_ci   * 5400 max shading coefficients at 600 dpi repeated 3 times
6318141cc406Sopenharmony_ci   * overall size rounded at 32 bytes multiple
6319141cc406Sopenharmony_ci   * 675 CCD elements at 75 DPI. 16 bit per element. 1 or 3 channels.
6320141cc406Sopenharmony_ci   * there is a 0xFF marker at end of each coefficients row.
6321141cc406Sopenharmony_ci   * a gamma table comes first
6322141cc406Sopenharmony_ci   * 75  DPI:  5600=1542+(675)*2*3+8                ->size rounded to 'upper 32'
6323141cc406Sopenharmony_ci   * 150 DPI: 9664=675*2*2*3=1542+(675*2)*2*3+22
6324141cc406Sopenharmony_ci   * 17760                                        4         +18
6325141cc406Sopenharmony_ci   * 33952                                        8     +10
6326141cc406Sopenharmony_ci   * 65472+896=66368=                16     +26
6327141cc406Sopenharmony_ci   *
6328141cc406Sopenharmony_ci   * COEFFICIENT 16 bit value
6329141cc406Sopenharmony_ci   * first is 00, 0x40, 0x80 or 0xC0 => 10 significant bit
6330141cc406Sopenharmony_ci   * coeff*average=K  => coeff=K/average
6331141cc406Sopenharmony_ci   */
6332141cc406Sopenharmony_ci
6333141cc406Sopenharmony_ci  calibration = (SANE_Byte *) malloc (size);
6334141cc406Sopenharmony_ci  if (calibration == NULL)
6335141cc406Sopenharmony_ci    {
6336141cc406Sopenharmony_ci      DBG (DBG_error,
6337141cc406Sopenharmony_ci	   "send_calibration_data: failed to allocate memory for calibration data\n");
6338141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
6339141cc406Sopenharmony_ci    }
6340141cc406Sopenharmony_ci  memset (calibration, 0x00, size);
6341141cc406Sopenharmony_ci
6342141cc406Sopenharmony_ci  /* fill gamma tables first, markers and static gamma table */
6343141cc406Sopenharmony_ci  idx = 0;
6344141cc406Sopenharmony_ci
6345141cc406Sopenharmony_ci  /* select red gamma table */
6346141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_RGB)
6347141cc406Sopenharmony_ci    {
6348141cc406Sopenharmony_ci      /* 3 different gamma table */
6349141cc406Sopenharmony_ci      gamma_r = session->val[OPT_GAMMA_VECTOR_R].wa;
6350141cc406Sopenharmony_ci      gamma_g = session->val[OPT_GAMMA_VECTOR_G].wa;
6351141cc406Sopenharmony_ci      gamma_b = session->val[OPT_GAMMA_VECTOR_B].wa;
6352141cc406Sopenharmony_ci    }
6353141cc406Sopenharmony_ci  else
6354141cc406Sopenharmony_ci    {
6355141cc406Sopenharmony_ci      /* 3 time the same gamma table */
6356141cc406Sopenharmony_ci      gamma_r = session->val[OPT_GAMMA_VECTOR].wa;
6357141cc406Sopenharmony_ci      gamma_g = session->val[OPT_GAMMA_VECTOR].wa;
6358141cc406Sopenharmony_ci      gamma_b = session->val[OPT_GAMMA_VECTOR].wa;
6359141cc406Sopenharmony_ci    }
6360141cc406Sopenharmony_ci
6361141cc406Sopenharmony_ci  fill_gamma (calibration, &idx, gamma_r);
6362141cc406Sopenharmony_ci  fill_gamma (calibration, &idx, gamma_g);
6363141cc406Sopenharmony_ci  fill_gamma (calibration, &idx, gamma_b);
6364141cc406Sopenharmony_ci
6365141cc406Sopenharmony_ci  /* compute calibration coefficients */
6366141cc406Sopenharmony_ci  /* real width != 675 --> 637
6367141cc406Sopenharmony_ci   * shading data calibration starts at 1542. There are 3 rows of 16 bits values
6368141cc406Sopenharmony_ci   * first row is green calibration
6369141cc406Sopenharmony_ci   */
6370141cc406Sopenharmony_ci
6371141cc406Sopenharmony_ci  /* to avoid problems with 0xaa values which must be escaped, we change them
6372141cc406Sopenharmony_ci   * into 0xab values, which unnoticeable on scans */
6373141cc406Sopenharmony_ci  for (i = 0; i < width; i++)
6374141cc406Sopenharmony_ci    {
6375141cc406Sopenharmony_ci      /* average TARGET CODE 3431046 */
6376141cc406Sopenharmony_ci/* #define RED_SHADING_TARGET_CODE   3000000
6377141cc406Sopenharmony_ci   #define GREEN_SHADING_TARGET_CODE 300000
6378141cc406Sopenharmony_ci   #define BLUE_SHADING_TARGET_CODE  2800000*/
6379141cc406Sopenharmony_ci#define RED_SHADING_TARGET_CODE   2800000
6380141cc406Sopenharmony_ci#define GREEN_SHADING_TARGET_CODE 2800000
6381141cc406Sopenharmony_ci#define BLUE_SHADING_TARGET_CODE  2700000
6382141cc406Sopenharmony_ci
6383141cc406Sopenharmony_ci      red_code = RED_SHADING_TARGET_CODE;
6384141cc406Sopenharmony_ci      green_code = GREEN_SHADING_TARGET_CODE;
6385141cc406Sopenharmony_ci      blue_code = BLUE_SHADING_TARGET_CODE;
6386141cc406Sopenharmony_ci
6387141cc406Sopenharmony_ci      /* target code debug, will be removed for the release */
6388141cc406Sopenharmony_ci      if (getenv ("RED_CODE") != NULL)
6389141cc406Sopenharmony_ci	{
6390141cc406Sopenharmony_ci	  red_code = atoi (getenv ("RED_CODE"));
6391141cc406Sopenharmony_ci	}
6392141cc406Sopenharmony_ci      if (getenv ("GREEN_CODE") != NULL)
6393141cc406Sopenharmony_ci	{
6394141cc406Sopenharmony_ci	  blue_code = atoi (getenv ("GREEN_CODE"));
6395141cc406Sopenharmony_ci	}
6396141cc406Sopenharmony_ci      if (getenv ("BLUE_CODE") != NULL)
6397141cc406Sopenharmony_ci	{
6398141cc406Sopenharmony_ci	  green_code = atoi (getenv ("BLUE_CODE"));
6399141cc406Sopenharmony_ci	}
6400141cc406Sopenharmony_ci
6401141cc406Sopenharmony_ci      /* correction coefficient is target code divided by average scanned value
6402141cc406Sopenharmony_ci       * but it is put in a 16 bits number. Only 10 first bits are significants.
6403141cc406Sopenharmony_ci       */
6404141cc406Sopenharmony_ci      /* first color component red data  */
6405141cc406Sopenharmony_ci      if (gamma_r[dev->shading_data[i * 3]] < 5)
6406141cc406Sopenharmony_ci	value = 0x8000;
6407141cc406Sopenharmony_ci      else
6408141cc406Sopenharmony_ci	value = red_code / gamma_r[dev->shading_data[i * 3]];
6409141cc406Sopenharmony_ci      val = (SANE_Byte) (value / 256);
6410141cc406Sopenharmony_ci      if (val == 0xaa)
6411141cc406Sopenharmony_ci	val++;
6412141cc406Sopenharmony_ci      calibration[idx + i * 2 + 1] = val;
6413141cc406Sopenharmony_ci      calibration[idx + i * 2] = (SANE_Byte) (value % 256) & 0xC0;
6414141cc406Sopenharmony_ci
6415141cc406Sopenharmony_ci      /* second color component: green data */
6416141cc406Sopenharmony_ci      if (gamma_r[dev->shading_data[i * 3 + 1]] < 5)
6417141cc406Sopenharmony_ci	value = 0x8000;
6418141cc406Sopenharmony_ci      else
6419141cc406Sopenharmony_ci	value = green_code / gamma_g[dev->shading_data[i * 3 + 1]];
6420141cc406Sopenharmony_ci      val = (SANE_Byte) (value / 256);
6421141cc406Sopenharmony_ci      if (val == 0xaa)
6422141cc406Sopenharmony_ci	val++;
6423141cc406Sopenharmony_ci      calibration[idx + data_size * 2 + i * 2 + 1] = val;
6424141cc406Sopenharmony_ci      calibration[idx + data_size * 2 + i * 2] =
6425141cc406Sopenharmony_ci	(SANE_Byte) (value % 256) & 0xC0;
6426141cc406Sopenharmony_ci
6427141cc406Sopenharmony_ci      /* third color component: blue data */
6428141cc406Sopenharmony_ci      if (gamma_r[dev->shading_data[i * 3 + 2]] < 5)
6429141cc406Sopenharmony_ci	value = 0x8000;
6430141cc406Sopenharmony_ci      else
6431141cc406Sopenharmony_ci	value = blue_code / gamma_b[dev->shading_data[i * 3 + 2]];
6432141cc406Sopenharmony_ci      val = (SANE_Byte) (value / 256);
6433141cc406Sopenharmony_ci      if (val == 0xaa)
6434141cc406Sopenharmony_ci	val++;
6435141cc406Sopenharmony_ci      calibration[idx + data_size * 4 + i * 2 + 1] = val;
6436141cc406Sopenharmony_ci      calibration[idx + data_size * 4 + i * 2] =
6437141cc406Sopenharmony_ci	(SANE_Byte) (value % 256) & 0xC0;
6438141cc406Sopenharmony_ci    }
6439141cc406Sopenharmony_ci
6440141cc406Sopenharmony_ci  /* DEEP TRACING */
6441141cc406Sopenharmony_ci  if (DBG_LEVEL >= DBG_io2)
6442141cc406Sopenharmony_ci    {
6443141cc406Sopenharmony_ci      calib = fopen ("calibration.hex", "wb");
6444141cc406Sopenharmony_ci      fprintf (calib, "shading_data(%d)=", width);
6445141cc406Sopenharmony_ci      for (i = 0; i < width * 3; i++)
6446141cc406Sopenharmony_ci	{
6447141cc406Sopenharmony_ci	  fprintf (calib, "%02x ", dev->shading_data[i]);
6448141cc406Sopenharmony_ci	}
6449141cc406Sopenharmony_ci      fprintf (calib, "\n");
6450141cc406Sopenharmony_ci      fprintf (calib, "write_mem(0x00,%d)=", size);
6451141cc406Sopenharmony_ci      for (i = 0; i < size; i++)
6452141cc406Sopenharmony_ci	{
6453141cc406Sopenharmony_ci	  fprintf (calib, "%02x ", calibration[i]);
6454141cc406Sopenharmony_ci	}
6455141cc406Sopenharmony_ci      fclose (calib);
6456141cc406Sopenharmony_ci    }
6457141cc406Sopenharmony_ci
6458141cc406Sopenharmony_ci  /* signals color format/divisor from hardware */
6459141cc406Sopenharmony_ci  format = rts8891_data_format (dev->xdpi, dev->sensor);
6460141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (dev->devnum, 0xd3, &format);
6461141cc406Sopenharmony_ci
6462141cc406Sopenharmony_ci  /* for some reason, we have to add 6 to the size for the first write */
6463141cc406Sopenharmony_ci  /* related to the 6 0xaa in gamma table ? */
6464141cc406Sopenharmony_ci  if (size > RTS88XX_MAX_XFER_SIZE)
6465141cc406Sopenharmony_ci    {
6466141cc406Sopenharmony_ci      status =
6467141cc406Sopenharmony_ci	sanei_rts88xx_write_mem (dev->devnum, RTS88XX_MAX_XFER_SIZE, 6,
6468141cc406Sopenharmony_ci				 calibration);
6469141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6470141cc406Sopenharmony_ci	{
6471141cc406Sopenharmony_ci	  DBG (DBG_error,
6472141cc406Sopenharmony_ci	       "send_calibration_data: failed to write calibration data (part 1)\n");
6473141cc406Sopenharmony_ci	  return status;
6474141cc406Sopenharmony_ci	}
6475141cc406Sopenharmony_ci      size -= RTS88XX_MAX_XFER_SIZE;
6476141cc406Sopenharmony_ci      status =
6477141cc406Sopenharmony_ci	sanei_rts88xx_write_mem (dev->devnum, size, 0,
6478141cc406Sopenharmony_ci				 calibration + RTS88XX_MAX_XFER_SIZE);
6479141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6480141cc406Sopenharmony_ci	{
6481141cc406Sopenharmony_ci	  DBG (DBG_error,
6482141cc406Sopenharmony_ci	       "send_calibration_data: failed to write calibration data (part 2)\n");
6483141cc406Sopenharmony_ci	  return status;
6484141cc406Sopenharmony_ci	}
6485141cc406Sopenharmony_ci    }
6486141cc406Sopenharmony_ci  else
6487141cc406Sopenharmony_ci    {
6488141cc406Sopenharmony_ci      status = sanei_rts88xx_write_mem (dev->devnum, size, 6, calibration);
6489141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6490141cc406Sopenharmony_ci	{
6491141cc406Sopenharmony_ci	  DBG (DBG_error,
6492141cc406Sopenharmony_ci	       "send_calibration_data: failed to write calibration data\n");
6493141cc406Sopenharmony_ci	  return status;
6494141cc406Sopenharmony_ci	}
6495141cc406Sopenharmony_ci    }
6496141cc406Sopenharmony_ci
6497141cc406Sopenharmony_ci  /* set mem start */
6498141cc406Sopenharmony_ci  dev->regs[0x91] = 0x00;
6499141cc406Sopenharmony_ci  dev->regs[0x92] = 0x00;
6500141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x91, dev->regs + 0x91, 2);
6501141cc406Sopenharmony_ci
6502141cc406Sopenharmony_ci  free (calibration);
6503141cc406Sopenharmony_ci  DBG (DBG_proc, "send_calibration_data: exit\n");
6504141cc406Sopenharmony_ci  return status;
6505141cc406Sopenharmony_ci}
6506141cc406Sopenharmony_ci
6507141cc406Sopenharmony_ci/* move at dev->model->min_ydpi dpi up to the scanning area. Which speeds
6508141cc406Sopenharmony_ci * up scanning
6509141cc406Sopenharmony_ci */
6510141cc406Sopenharmony_cistatic SANE_Status
6511141cc406Sopenharmony_cimove_to_scan_area (struct Rts8891_Session *session)
6512141cc406Sopenharmony_ci{
6513141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
6514141cc406Sopenharmony_ci  SANE_Byte control;
6515141cc406Sopenharmony_ci  SANE_Byte regs[RTS8891_MAX_REGISTERS];
6516141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
6517141cc406Sopenharmony_ci  SANE_Int distance;
6518141cc406Sopenharmony_ci
6519141cc406Sopenharmony_ci  DBG (DBG_proc, "move_to_scan_area: start\n");
6520141cc406Sopenharmony_ci
6521141cc406Sopenharmony_ci  /* compute line number to move and fix scan values */
6522141cc406Sopenharmony_ci  distance = ((dev->ystart - 1) * MOVE_DPI) / dev->ydpi;
6523141cc406Sopenharmony_ci  dev->ystart = dev->ystart - (distance * dev->ydpi) / MOVE_DPI;
6524141cc406Sopenharmony_ci  /* extra lines to let head stop */
6525141cc406Sopenharmony_ci  distance -= 30;
6526141cc406Sopenharmony_ci
6527141cc406Sopenharmony_ci  DBG (DBG_proc, "move_to_scan_area: distance=%d, ystart=%d\n", distance,
6528141cc406Sopenharmony_ci       dev->ystart);
6529141cc406Sopenharmony_ci
6530141cc406Sopenharmony_ci  /* then send move command */
6531141cc406Sopenharmony_ci  rts8891_move (dev, regs, distance, SANE_TRUE);
6532141cc406Sopenharmony_ci
6533141cc406Sopenharmony_ci  /* wait for completion */
6534141cc406Sopenharmony_ci  do
6535141cc406Sopenharmony_ci    {
6536141cc406Sopenharmony_ci      sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
6537141cc406Sopenharmony_ci    }
6538141cc406Sopenharmony_ci  while ((control & 0x08) == 0x08);
6539141cc406Sopenharmony_ci
6540141cc406Sopenharmony_ci  DBG (DBG_proc, "move_to_scan_area: exit\n");
6541141cc406Sopenharmony_ci  return status;
6542141cc406Sopenharmony_ci}
6543141cc406Sopenharmony_ci
6544141cc406Sopenharmony_ci/* set up the shadow registers for scan, depending on scan parameters    */
6545141cc406Sopenharmony_ci/* the ultimate goal is to have no direct access to registers, but to    */
6546141cc406Sopenharmony_ci/* set them through helper functions                                     */
6547141cc406Sopenharmony_ci/* NOTE : I couldn't manage to get scans that really uses gray settings. */
6548141cc406Sopenharmony_ci/* The windows driver is always scanning in color, so we do the same.   */
6549141cc406Sopenharmony_ci/* For now, the only mode that could be done would be 300 dpi gray scan, */
6550141cc406Sopenharmony_ci/* based on the register settings of find_origin()                       */
6551141cc406Sopenharmony_cistatic SANE_Status
6552141cc406Sopenharmony_cisetup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_Byte *status2, SANE_Byte *regs)
6553141cc406Sopenharmony_ci{
6554141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
6555141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
6556141cc406Sopenharmony_ci  int exposure=0;
6557141cc406Sopenharmony_ci  int timing=0;
6558141cc406Sopenharmony_ci
6559141cc406Sopenharmony_ci  /* only software gray modes for now */
6560141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_GRAY
6561141cc406Sopenharmony_ci      && (session->dev->model->flags & RTS8891_FLAG_EMULATED_GRAY_MODE) == 0)
6562141cc406Sopenharmony_ci    {
6563141cc406Sopenharmony_ci      DBG (DBG_warn,
6564141cc406Sopenharmony_ci	   "setup_scan_registers: native gray modes not implemented for this model, failure expected\n");
6565141cc406Sopenharmony_ci    }
6566141cc406Sopenharmony_ci  sanei_rts88xx_set_scan_area (regs, dev->ystart, dev->ystart + dev->lines, dev->xstart, dev->xstart + dev->pixels);
6567141cc406Sopenharmony_ci  DBG (DBG_info, "setup_scan_registers: xstart=%d, pixels=%d\n", dev->xstart, dev->pixels);
6568141cc406Sopenharmony_ci  DBG (DBG_info, "setup_scan_registers: ystart=%d, lines =%d\n", dev->ystart, dev->lines);
6569141cc406Sopenharmony_ci
6570141cc406Sopenharmony_ci  /* this is full register set from a color preview */
6571141cc406Sopenharmony_ci  regs[0x00] = regs[0x00] & 0xef;
6572141cc406Sopenharmony_ci  regs[0x01] = 0x41;
6573141cc406Sopenharmony_ci
6574141cc406Sopenharmony_ci  sanei_rts88xx_set_offset (regs, dev->red_offset, dev->green_offset, dev->blue_offset);
6575141cc406Sopenharmony_ci  sanei_rts88xx_set_gain (regs, dev->red_gain, dev->green_gain, dev->blue_gain);
6576141cc406Sopenharmony_ci
6577141cc406Sopenharmony_ci  switch (dev->sensor)
6578141cc406Sopenharmony_ci    {
6579141cc406Sopenharmony_ci    case SENSOR_TYPE_4400:
6580141cc406Sopenharmony_ci    case SENSOR_TYPE_4400_BARE:
6581141cc406Sopenharmony_ci      *status1 = 0x10;
6582141cc406Sopenharmony_ci      *status2 = 0x2a;
6583141cc406Sopenharmony_ci      break;
6584141cc406Sopenharmony_ci    case SENSOR_TYPE_XPA:
6585141cc406Sopenharmony_ci      *status1 = 0x20;
6586141cc406Sopenharmony_ci      *status2 = 0x3f;
6587141cc406Sopenharmony_ci      break;
6588141cc406Sopenharmony_ci    default:
6589141cc406Sopenharmony_ci      *status1 = 0x20;
6590141cc406Sopenharmony_ci      *status2 = 0x3b;
6591141cc406Sopenharmony_ci    }
6592141cc406Sopenharmony_ci
6593141cc406Sopenharmony_ci  /* default to 75 dpi color scan */
6594141cc406Sopenharmony_ci  regs[0x0b] = 0x70;
6595141cc406Sopenharmony_ci  regs[0x0c] = 0x00;
6596141cc406Sopenharmony_ci  regs[0x0d] = 0x00;
6597141cc406Sopenharmony_ci  regs[0x0e] = 0x00;
6598141cc406Sopenharmony_ci  regs[0x0f] = 0x00;
6599141cc406Sopenharmony_ci
6600141cc406Sopenharmony_ci  regs[0x12] = 0xff;
6601141cc406Sopenharmony_ci  regs[0x13] = 0x20;
6602141cc406Sopenharmony_ci  regs[0x14] = 0xf8;
6603141cc406Sopenharmony_ci  regs[0x15] = 0x28;
6604141cc406Sopenharmony_ci  regs[0x16] = 0x01;
6605141cc406Sopenharmony_ci  regs[0x17] = 0x00;
6606141cc406Sopenharmony_ci  regs[0x18] = 0xff;
6607141cc406Sopenharmony_ci  regs[0x19] = 0x00;
6608141cc406Sopenharmony_ci  regs[0x1a] = 0x00;
6609141cc406Sopenharmony_ci  regs[0x1b] = 0x00;
6610141cc406Sopenharmony_ci  regs[0x1c] = 0x00;
6611141cc406Sopenharmony_ci  regs[0x1d] = 0x20;
6612141cc406Sopenharmony_ci  regs[0x1e] = 0x00;
6613141cc406Sopenharmony_ci  regs[0x1f] = 0x00;
6614141cc406Sopenharmony_ci
6615141cc406Sopenharmony_ci  /* LCD display */
6616141cc406Sopenharmony_ci  regs[0x20] = 0x3a;
6617141cc406Sopenharmony_ci  regs[0x21] = 0xf2;
6618141cc406Sopenharmony_ci  regs[0x22] = 0x00;
6619141cc406Sopenharmony_ci
6620141cc406Sopenharmony_ci  regs[0x23] = 0x80;
6621141cc406Sopenharmony_ci  regs[0x24] = 0xff;
6622141cc406Sopenharmony_ci  regs[0x25] = 0x00;
6623141cc406Sopenharmony_ci  regs[0x26] = 0x00;
6624141cc406Sopenharmony_ci  regs[0x27] = 0x00;
6625141cc406Sopenharmony_ci  regs[0x28] = 0x00;
6626141cc406Sopenharmony_ci  regs[0x29] = 0x00;
6627141cc406Sopenharmony_ci  regs[0x2a] = 0x00;
6628141cc406Sopenharmony_ci  regs[0x2b] = 0x00;
6629141cc406Sopenharmony_ci  regs[0x2c] = 0x00;
6630141cc406Sopenharmony_ci  regs[0x2d] = 0x00;
6631141cc406Sopenharmony_ci  regs[0x2e] = 0x00;
6632141cc406Sopenharmony_ci  regs[0x2f] = 0x00;
6633141cc406Sopenharmony_ci  regs[0x30] = 0x00;
6634141cc406Sopenharmony_ci  regs[0x31] = 0x00;
6635141cc406Sopenharmony_ci  regs[0x32] = 0x20;
6636141cc406Sopenharmony_ci  regs[0x33] = 0x83;
6637141cc406Sopenharmony_ci  regs[0x34] = 0x10;
6638141cc406Sopenharmony_ci  regs[0x35] = 0x47;
6639141cc406Sopenharmony_ci  regs[0x36] = 0x2c;
6640141cc406Sopenharmony_ci  regs[0x37] = 0x00;
6641141cc406Sopenharmony_ci  regs[0x38] = 0x00;
6642141cc406Sopenharmony_ci  regs[0x39] = 0x02;
6643141cc406Sopenharmony_ci  regs[0x3a] = 0x43;
6644141cc406Sopenharmony_ci  regs[0x3b] = 0x00;
6645141cc406Sopenharmony_ci  regs[0x3c] = 0x00;
6646141cc406Sopenharmony_ci  regs[0x3d] = 0x00;
6647141cc406Sopenharmony_ci  regs[0x3e] = 0x00;
6648141cc406Sopenharmony_ci  regs[0x3f] = 0x00;
6649141cc406Sopenharmony_ci  regs[0x40] = 0x2c;	/* 0x0c -> use shading data */
6650141cc406Sopenharmony_ci  regs[0x41] = 0x00;
6651141cc406Sopenharmony_ci  regs[0x42] = 0x00;
6652141cc406Sopenharmony_ci  regs[0x43] = 0x00;
6653141cc406Sopenharmony_ci  regs[0x44] = 0x8c;
6654141cc406Sopenharmony_ci  regs[0x45] = 0x76;
6655141cc406Sopenharmony_ci  regs[0x46] = 0x00;
6656141cc406Sopenharmony_ci  regs[0x47] = 0x00;
6657141cc406Sopenharmony_ci  regs[0x48] = 0x00;
6658141cc406Sopenharmony_ci  regs[0x49] = 0x00;
6659141cc406Sopenharmony_ci  regs[0x4a] = 0x00;
6660141cc406Sopenharmony_ci  regs[0x4b] = 0x00;
6661141cc406Sopenharmony_ci  regs[0x4c] = 0x00;
6662141cc406Sopenharmony_ci  regs[0x4d] = 0x00;
6663141cc406Sopenharmony_ci  regs[0x4e] = 0x00;
6664141cc406Sopenharmony_ci  regs[0x4f] = 0x00;
6665141cc406Sopenharmony_ci  regs[0x50] = 0x00;
6666141cc406Sopenharmony_ci  regs[0x51] = 0x00;
6667141cc406Sopenharmony_ci  regs[0x52] = 0x00;
6668141cc406Sopenharmony_ci  regs[0x53] = 0x00;
6669141cc406Sopenharmony_ci  regs[0x54] = 0x00;
6670141cc406Sopenharmony_ci  regs[0x55] = 0x00;
6671141cc406Sopenharmony_ci  regs[0x56] = 0x00;
6672141cc406Sopenharmony_ci  regs[0x57] = 0x00;
6673141cc406Sopenharmony_ci  regs[0x58] = 0x00;
6674141cc406Sopenharmony_ci  regs[0x59] = 0x00;
6675141cc406Sopenharmony_ci  regs[0x5a] = 0x00;
6676141cc406Sopenharmony_ci  regs[0x5b] = 0x00;
6677141cc406Sopenharmony_ci  regs[0x5c] = 0x00;
6678141cc406Sopenharmony_ci  regs[0x5d] = 0x00;
6679141cc406Sopenharmony_ci  regs[0x5e] = 0x00;
6680141cc406Sopenharmony_ci  regs[0x5f] = 0x00;
6681141cc406Sopenharmony_ci
6682141cc406Sopenharmony_ci  regs[0x64] = 0x01;
6683141cc406Sopenharmony_ci  regs[0x65] = 0x20;
6684141cc406Sopenharmony_ci
6685141cc406Sopenharmony_ci  regs[0x68] = 0x00;
6686141cc406Sopenharmony_ci  regs[0x69] = 0x00;
6687141cc406Sopenharmony_ci  regs[0x6a] = 0x00;
6688141cc406Sopenharmony_ci  regs[0x6b] = 0x00;
6689141cc406Sopenharmony_ci
6690141cc406Sopenharmony_ci  regs[0x6e] = 0x00;
6691141cc406Sopenharmony_ci  regs[0x6f] = 0x00;
6692141cc406Sopenharmony_ci  regs[0x70] = 0x00;
6693141cc406Sopenharmony_ci  regs[0x71] = 0x00;
6694141cc406Sopenharmony_ci
6695141cc406Sopenharmony_ci  regs[0x72] = 0xe1;
6696141cc406Sopenharmony_ci  regs[0x73] = 0x14;
6697141cc406Sopenharmony_ci  regs[0x74] = 0x18;
6698141cc406Sopenharmony_ci  regs[0x75] = 0x15;
6699141cc406Sopenharmony_ci
6700141cc406Sopenharmony_ci  regs[0x76] = 0x00;
6701141cc406Sopenharmony_ci  regs[0x77] = 0x00;
6702141cc406Sopenharmony_ci  regs[0x78] = 0x00;
6703141cc406Sopenharmony_ci  regs[0x79] = 0x20;
6704141cc406Sopenharmony_ci  regs[0x7a] = 0x01;
6705141cc406Sopenharmony_ci  regs[0x7b] = 0x00;
6706141cc406Sopenharmony_ci  regs[0x7c] = 0x00;
6707141cc406Sopenharmony_ci  regs[0x7d] = 0x00;
6708141cc406Sopenharmony_ci  regs[0x7e] = 0x00;
6709141cc406Sopenharmony_ci  regs[0x7f] = 0x00;
6710141cc406Sopenharmony_ci  timing=0x00af;
6711141cc406Sopenharmony_ci  regs[0x84] = 0x00;
6712141cc406Sopenharmony_ci  regs[0x85] = 0x46;
6713141cc406Sopenharmony_ci  regs[0x86] = 0x0b;
6714141cc406Sopenharmony_ci  regs[0x87] = 0x8c;
6715141cc406Sopenharmony_ci  regs[0x88] = 0x10;
6716141cc406Sopenharmony_ci  regs[0x8b] = 0xff;
6717141cc406Sopenharmony_ci  regs[0x8c] = 0x3f;
6718141cc406Sopenharmony_ci  regs[0x8d] = 0x3b;
6719141cc406Sopenharmony_ci
6720141cc406Sopenharmony_ci  regs[0x8e] = 0x60;
6721141cc406Sopenharmony_ci  regs[0x8f] = 0x00;
6722141cc406Sopenharmony_ci  regs[0x90] = 0x18;	/* 0x1c when shading calibration */
6723141cc406Sopenharmony_ci
6724141cc406Sopenharmony_ci  /* overwritten when calibration data is sent */
6725141cc406Sopenharmony_ci  regs[0x91] = 0x00;
6726141cc406Sopenharmony_ci  regs[0x92] = 0x00;
6727141cc406Sopenharmony_ci
6728141cc406Sopenharmony_ci  regs[0x93] = 0x01;
6729141cc406Sopenharmony_ci
6730141cc406Sopenharmony_ci  regs[0x94] = 0x0e;
6731141cc406Sopenharmony_ci  regs[0x95] = 0x00;
6732141cc406Sopenharmony_ci  regs[0x96] = 0x00;
6733141cc406Sopenharmony_ci  regs[0x97] = 0x00;
6734141cc406Sopenharmony_ci  regs[0x98] = 0x00;
6735141cc406Sopenharmony_ci  regs[0x99] = 0x00;
6736141cc406Sopenharmony_ci  regs[0x9a] = 0x00;
6737141cc406Sopenharmony_ci  regs[0x9b] = 0x00;
6738141cc406Sopenharmony_ci  regs[0x9c] = 0x00;
6739141cc406Sopenharmony_ci  regs[0x9d] = 0x00;
6740141cc406Sopenharmony_ci  regs[0x9e] = 0x00;
6741141cc406Sopenharmony_ci  regs[0x9f] = 0x00;
6742141cc406Sopenharmony_ci  regs[0xa0] = 0x00;
6743141cc406Sopenharmony_ci  regs[0xa1] = 0x00;
6744141cc406Sopenharmony_ci  regs[0xa2] = 0x00;
6745141cc406Sopenharmony_ci  regs[0xa3] = 0xcc;
6746141cc406Sopenharmony_ci  regs[0xa4] = 0x27;
6747141cc406Sopenharmony_ci  regs[0xa5] = 0x64;
6748141cc406Sopenharmony_ci  regs[0xa6] = 0x00;
6749141cc406Sopenharmony_ci  regs[0xa7] = 0x00;
6750141cc406Sopenharmony_ci  regs[0xa8] = 0x00;
6751141cc406Sopenharmony_ci  regs[0xa9] = 0x00;
6752141cc406Sopenharmony_ci  regs[0xaa] = 0x00;
6753141cc406Sopenharmony_ci  regs[0xab] = 0x00;
6754141cc406Sopenharmony_ci  regs[0xac] = 0x00;
6755141cc406Sopenharmony_ci  regs[0xad] = 0x00;
6756141cc406Sopenharmony_ci  regs[0xae] = 0x00;
6757141cc406Sopenharmony_ci  regs[0xaf] = 0x00;
6758141cc406Sopenharmony_ci  regs[0xb0] = 0x00;
6759141cc406Sopenharmony_ci  regs[0xb1] = 0x00;
6760141cc406Sopenharmony_ci  regs[0xb2] = 0x02;
6761141cc406Sopenharmony_ci
6762141cc406Sopenharmony_ci  regs[0xb4] = 0x00;
6763141cc406Sopenharmony_ci  regs[0xb5] = 0x00;
6764141cc406Sopenharmony_ci  regs[0xb6] = 0x00;
6765141cc406Sopenharmony_ci  regs[0xb7] = 0x00;
6766141cc406Sopenharmony_ci  regs[0xb8] = 0x00;
6767141cc406Sopenharmony_ci  regs[0xb9] = 0x00;
6768141cc406Sopenharmony_ci  regs[0xba] = 0x00;
6769141cc406Sopenharmony_ci  regs[0xbb] = 0x00;
6770141cc406Sopenharmony_ci  regs[0xbc] = 0x00;
6771141cc406Sopenharmony_ci  regs[0xbd] = 0x00;
6772141cc406Sopenharmony_ci  regs[0xbe] = 0x00;
6773141cc406Sopenharmony_ci  regs[0xbf] = 0x00;
6774141cc406Sopenharmony_ci  regs[0xc0] = 0x06;
6775141cc406Sopenharmony_ci  regs[0xc1] = 0xe6;
6776141cc406Sopenharmony_ci  regs[0xc2] = 0x67;
6777141cc406Sopenharmony_ci  regs[0xc3] = 0xff;
6778141cc406Sopenharmony_ci  regs[0xc4] = 0xff;
6779141cc406Sopenharmony_ci  regs[0xc5] = 0xff;
6780141cc406Sopenharmony_ci  regs[0xc6] = 0xff;
6781141cc406Sopenharmony_ci  regs[0xc7] = 0xff;
6782141cc406Sopenharmony_ci  regs[0xc8] = 0xff;
6783141cc406Sopenharmony_ci  regs[0xc9] = 0x07;
6784141cc406Sopenharmony_ci  regs[0xca] = 0x00;
6785141cc406Sopenharmony_ci  regs[0xcb] = 0xfe;
6786141cc406Sopenharmony_ci  regs[0xcc] = 0xf9;
6787141cc406Sopenharmony_ci  regs[0xcd] = 0x19;
6788141cc406Sopenharmony_ci  regs[0xce] = 0x98;
6789141cc406Sopenharmony_ci  regs[0xcf] = 0xe8;
6790141cc406Sopenharmony_ci  regs[0xd0] = 0xea;
6791141cc406Sopenharmony_ci
6792141cc406Sopenharmony_ci  regs[0xd1] = 0xf3;
6793141cc406Sopenharmony_ci  regs[0xd2] = 0x14;
6794141cc406Sopenharmony_ci
6795141cc406Sopenharmony_ci  regs[0xd3] = 0x02;
6796141cc406Sopenharmony_ci  regs[0xd4] = 0x04;
6797141cc406Sopenharmony_ci  regs[0xd5] = 0x86;
6798141cc406Sopenharmony_ci
6799141cc406Sopenharmony_ci  regs[0xd6] = 0x0f;
6800141cc406Sopenharmony_ci  regs[0xd7] = 0x30;	/* 12303 */
6801141cc406Sopenharmony_ci
6802141cc406Sopenharmony_ci  regs[0xd8] = 0x52;	/* 0x5230=21040 */
6803141cc406Sopenharmony_ci
6804141cc406Sopenharmony_ci  regs[0xd9] = 0xad;
6805141cc406Sopenharmony_ci  regs[0xda] = 0xa7;
6806141cc406Sopenharmony_ci  regs[0xdb] = 0x00;
6807141cc406Sopenharmony_ci  regs[0xdc] = 0x00;
6808141cc406Sopenharmony_ci  regs[0xdd] = 0x00;
6809141cc406Sopenharmony_ci  regs[0xde] = 0x00;
6810141cc406Sopenharmony_ci  regs[0xdf] = 0x00;
6811141cc406Sopenharmony_ci  regs[0xe0] = 0x00;
6812141cc406Sopenharmony_ci  regs[0xe1] = 0x00;
6813141cc406Sopenharmony_ci  regs[0xe2] = 0x0f;
6814141cc406Sopenharmony_ci  regs[0xe3] = 0x85;
6815141cc406Sopenharmony_ci  regs[0xe4] = 0x03;
6816141cc406Sopenharmony_ci
6817141cc406Sopenharmony_ci  /* regs[0xe5] = 0x52;
6818141cc406Sopenharmony_ci     regs[0xe6] = 0x00;     exposure time 0x0052=82 */
6819141cc406Sopenharmony_ci  exposure=82;
6820141cc406Sopenharmony_ci
6821141cc406Sopenharmony_ci  regs[0xe7] = 0x75;
6822141cc406Sopenharmony_ci  regs[0xe8] = 0x01;
6823141cc406Sopenharmony_ci  regs[0xe9] = 0x0b;
6824141cc406Sopenharmony_ci  regs[0xea] = 0x54;
6825141cc406Sopenharmony_ci  regs[0xeb] = 0x01;
6826141cc406Sopenharmony_ci  regs[0xec] = 0x04;
6827141cc406Sopenharmony_ci  regs[0xed] = 0xb8;
6828141cc406Sopenharmony_ci  regs[0xee] = 0x00;
6829141cc406Sopenharmony_ci  regs[0xef] = 0x03;
6830141cc406Sopenharmony_ci  regs[0xf0] = 0x70;
6831141cc406Sopenharmony_ci  regs[0xf1] = 0x00;
6832141cc406Sopenharmony_ci  regs[0xf2] = 0x01;
6833141cc406Sopenharmony_ci  regs[0xf3] = 0x00;
6834141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_XPA || dev->sensor == SENSOR_TYPE_4400)
6835141cc406Sopenharmony_ci    {
6836141cc406Sopenharmony_ci      regs[0xc0] = 0x67;
6837141cc406Sopenharmony_ci      regs[0xc1] = 0x06;
6838141cc406Sopenharmony_ci      regs[0xc2] = 0xe6;
6839141cc406Sopenharmony_ci      regs[0xc3] = 0x98;
6840141cc406Sopenharmony_ci      regs[0xc4] = 0xf9;
6841141cc406Sopenharmony_ci      regs[0xc5] = 0x19;
6842141cc406Sopenharmony_ci      regs[0xc6] = 0x67;
6843141cc406Sopenharmony_ci      regs[0xc7] = 0x06;
6844141cc406Sopenharmony_ci      regs[0xc8] = 0xe6;
6845141cc406Sopenharmony_ci      regs[0xc9] = 0x01;
6846141cc406Sopenharmony_ci      regs[0xca] = 0xf8;
6847141cc406Sopenharmony_ci      regs[0xcb] = 0xff;
6848141cc406Sopenharmony_ci      regs[0xcc] = 0x98;
6849141cc406Sopenharmony_ci      regs[0xcd] = 0xf9;
6850141cc406Sopenharmony_ci      regs[0xce] = 0x19;
6851141cc406Sopenharmony_ci      regs[0xcf] = 0xe0;
6852141cc406Sopenharmony_ci      regs[0xd0] = 0xe2;
6853141cc406Sopenharmony_ci
6854141cc406Sopenharmony_ci      regs[0xd1] = 0xeb;
6855141cc406Sopenharmony_ci      regs[0xd2] = 0x0c;
6856141cc406Sopenharmony_ci
6857141cc406Sopenharmony_ci      regs[0xd7] = 0x10;
6858141cc406Sopenharmony_ci    }
6859141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400)
6860141cc406Sopenharmony_ci    {
6861141cc406Sopenharmony_ci      regs[0x13] = 0x39;	/* 0x20 */
6862141cc406Sopenharmony_ci      regs[0x14] = 0xf0;	/* 0xf8 */
6863141cc406Sopenharmony_ci      regs[0x15] = 0x29;	/* 0x28 */
6864141cc406Sopenharmony_ci      regs[0x16] = 0x00;	/* 0x01 */
6865141cc406Sopenharmony_ci      regs[0x17] = 0x10;	/* 0x00 */
6866141cc406Sopenharmony_ci      regs[0x23] = 0x00;	/* 0x80 */
6867141cc406Sopenharmony_ci      regs[0x35] = 0x47;	/* 0x45 */
6868141cc406Sopenharmony_ci      regs[0x36] = 0x29;	/* 0x2c */
6869141cc406Sopenharmony_ci      regs[0x39] = 0x00;	/* 0x02 */
6870141cc406Sopenharmony_ci      timing=0x00af;
6871141cc406Sopenharmony_ci      regs[0x85] = 0x46;	/* 0x8c */
6872141cc406Sopenharmony_ci      regs[0x86] = 0x0b;	/* 0x10 */
6873141cc406Sopenharmony_ci      regs[0x87] = 0x8c;	/* 0x18 */
6874141cc406Sopenharmony_ci      regs[0x88] = 0x10;	/* 0x1b */
6875141cc406Sopenharmony_ci      regs[0x8d] = 0x3b;	/* 0x77 */
6876141cc406Sopenharmony_ci
6877141cc406Sopenharmony_ci      regs[0xd3] = 0x02;	/* 0x0e */
6878141cc406Sopenharmony_ci      regs[0xd4] = 0x04;	/* 0x10 */
6879141cc406Sopenharmony_ci      regs[0xe2] = 0x07;	/* 0x0f */
6880141cc406Sopenharmony_ci      regs[0xe3] = 0x84;	/* 0x87 */
6881141cc406Sopenharmony_ci      /*regs[0xe5] = 0xa5; 0x54 */
6882141cc406Sopenharmony_ci      exposure=165;
6883141cc406Sopenharmony_ci      regs[0xe7] = 0x0e;	/* 0xa8 */
6884141cc406Sopenharmony_ci      regs[0xe8] = 0x01;	/* 0x00 */
6885141cc406Sopenharmony_ci      regs[0xe9] = 0x0a;	/* 0x0b */
6886141cc406Sopenharmony_ci      regs[0xea] = 0xc2;	/* 0x56 */
6887141cc406Sopenharmony_ci      regs[0xed] = 0xf6;	/* 0xba */
6888141cc406Sopenharmony_ci      regs[0xef] = 0x02;	/* 0x03 */
6889141cc406Sopenharmony_ci      regs[0xf0] = 0xa8;	/* 0x72 */
6890141cc406Sopenharmony_ci    }
6891141cc406Sopenharmony_ci  if (dev->sensor == SENSOR_TYPE_4400_BARE)
6892141cc406Sopenharmony_ci    {
6893141cc406Sopenharmony_ci      regs[0x13] = 0x39;	/* 0x20 */
6894141cc406Sopenharmony_ci      regs[0x14] = 0xf0;	/* 0xf8 */
6895141cc406Sopenharmony_ci      regs[0x15] = 0x29;	/* 0x28 */
6896141cc406Sopenharmony_ci      regs[0x16] = 0x00;	/* 0x07 */
6897141cc406Sopenharmony_ci      regs[0x17] = 0x10;	/* 0x00 */
6898141cc406Sopenharmony_ci      regs[0x23] = 0x00;	/* 0xff */
6899141cc406Sopenharmony_ci      regs[0x35] = 0x47;	/* 0x0e */
6900141cc406Sopenharmony_ci      regs[0x36] = 0x29;	/* 0x2c */
6901141cc406Sopenharmony_ci      regs[0x39] = 0x00;	/* 0x02 */
6902141cc406Sopenharmony_ci      regs[0x3a] = 0x43;	/* 0x0e */
6903141cc406Sopenharmony_ci      regs[0x40] = 0x2c;	/* 0x20 */
6904141cc406Sopenharmony_ci      regs[0x85] = 0x46;	/* 0x00 */
6905141cc406Sopenharmony_ci      regs[0x86] = 0x0b;	/* 0x06 */
6906141cc406Sopenharmony_ci      regs[0x87] = 0x8c;	/* 0x00 */
6907141cc406Sopenharmony_ci      regs[0x88] = 0x10;	/* 0x06 */
6908141cc406Sopenharmony_ci      regs[0x8d] = 0x3b;	/* 0x00 */
6909141cc406Sopenharmony_ci      regs[0x90] = 0x18;	/* 0x1c */
6910141cc406Sopenharmony_ci      regs[0xe2] = 0x07;	/* 0x05 */
6911141cc406Sopenharmony_ci      regs[0xe3] = 0x84;	/* 0x00 */
6912141cc406Sopenharmony_ci      regs[0xe4] = 0x03;	/* 0x00 */
6913141cc406Sopenharmony_ci      timing=0x00af;
6914141cc406Sopenharmony_ci      exposure=165;
6915141cc406Sopenharmony_ci      regs[0xe7] = 0x0e;	/* 0x00 */
6916141cc406Sopenharmony_ci      regs[0xe8] = 0x01;	/* 0x00 */
6917141cc406Sopenharmony_ci      regs[0xe9] = 0x0a;	/* 0x00 */
6918141cc406Sopenharmony_ci      regs[0xea] = 0xc2;	/* 0x00 */
6919141cc406Sopenharmony_ci      regs[0xeb] = 0x01;	/* 0x00 */
6920141cc406Sopenharmony_ci      regs[0xec] = 0x04;	/* 0x00 */
6921141cc406Sopenharmony_ci      regs[0xed] = 0xf6;	/* 0x00 */
6922141cc406Sopenharmony_ci      regs[0xef] = 0x02;	/* 0x00 */
6923141cc406Sopenharmony_ci      regs[0xf0] = 0xa8;	/* 0x00 */
6924141cc406Sopenharmony_ci      regs[0xf2] = 0x01;	/* 0x00 */
6925141cc406Sopenharmony_ci    }
6926141cc406Sopenharmony_ci  switch (dev->xdpi)
6927141cc406Sopenharmony_ci    {
6928141cc406Sopenharmony_ci    case 75:
6929141cc406Sopenharmony_ci      break;
6930141cc406Sopenharmony_ci    case 150:
6931141cc406Sopenharmony_ci      regs[0x35] = 0x45;
6932141cc406Sopenharmony_ci
6933141cc406Sopenharmony_ci
6934141cc406Sopenharmony_ci      regs[0x85] = 0x8c;
6935141cc406Sopenharmony_ci      regs[0x86] = 0x10;
6936141cc406Sopenharmony_ci
6937141cc406Sopenharmony_ci      regs[0x87] = 0x18;
6938141cc406Sopenharmony_ci      regs[0x88] = 0x1b;
6939141cc406Sopenharmony_ci
6940141cc406Sopenharmony_ci      regs[0x8d] = 0x77;
6941141cc406Sopenharmony_ci
6942141cc406Sopenharmony_ci      regs[0xe3] = 0x87;
6943141cc406Sopenharmony_ci
6944141cc406Sopenharmony_ci      /* regs[0xe5] = 0x54;
6945141cc406Sopenharmony_ci         regs[0xe6] = 0x00;        exposure time 0x0054=84 */
6946141cc406Sopenharmony_ci      exposure=84;
6947141cc406Sopenharmony_ci      timing=0x012e;
6948141cc406Sopenharmony_ci
6949141cc406Sopenharmony_ci      regs[0xe7] = 0xa8;
6950141cc406Sopenharmony_ci      regs[0xe8] = 0x00;
6951141cc406Sopenharmony_ci      regs[0xea] = 0x56;
6952141cc406Sopenharmony_ci      regs[0xed] = 0xba;
6953141cc406Sopenharmony_ci
6954141cc406Sopenharmony_ci      regs[0xf0] = 0x72;
6955141cc406Sopenharmony_ci      switch (dev->sensor)
6956141cc406Sopenharmony_ci	{
6957141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
6958141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_XPA for 150 dpi\n");
6959141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
6960141cc406Sopenharmony_ci	  regs[0xc1] = 0x8e;
6961141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
6962141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
6963141cc406Sopenharmony_ci	  regs[0xc4] = 0x71;
6964141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
6965141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
6966141cc406Sopenharmony_ci	  regs[0xc7] = 0x8e;
6967141cc406Sopenharmony_ci	  regs[0xc8] = 0xff;
6968141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
6969141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
6970141cc406Sopenharmony_ci	  regs[0xcb] = 0x1f;
6971141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
6972141cc406Sopenharmony_ci	  regs[0xcd] = 0x71;
6973141cc406Sopenharmony_ci	  regs[0xce] = 0x00;
6974141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
6975141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
6976141cc406Sopenharmony_ci	  regs[0xd1] = 0xf6;
6977141cc406Sopenharmony_ci	  regs[0xd2] = 0x17;
6978141cc406Sopenharmony_ci	  regs[0xd3] = 0x0b;
6979141cc406Sopenharmony_ci	  regs[0xd4] = 0x0d;
6980141cc406Sopenharmony_ci	  break;
6981141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
6982141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_BARE for 150 dpi\n");
6983141cc406Sopenharmony_ci	  regs[0xc0] = 0x80;
6984141cc406Sopenharmony_ci	  regs[0xc1] = 0x87;
6985141cc406Sopenharmony_ci	  regs[0xc2] = 0x7f;
6986141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
6987141cc406Sopenharmony_ci	  regs[0xcb] = 0x78;
6988141cc406Sopenharmony_ci	  regs[0xcc] = 0x7f;
6989141cc406Sopenharmony_ci	  regs[0xcd] = 0x78;
6990141cc406Sopenharmony_ci	  regs[0xce] = 0x80;
6991141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
6992141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
6993141cc406Sopenharmony_ci
6994141cc406Sopenharmony_ci	  regs[0xd1] = 0xf7;
6995141cc406Sopenharmony_ci	  regs[0xd2] = 0x00;
6996141cc406Sopenharmony_ci
6997141cc406Sopenharmony_ci	  regs[0xd3] = 0x0e;
6998141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
6999141cc406Sopenharmony_ci	  break;
7000141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
7001141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400 for 150 dpi\n");
7002141cc406Sopenharmony_ci	  regs[0x35] = 0x47;
7003141cc406Sopenharmony_ci
7004141cc406Sopenharmony_ci          exposure=170;
7005141cc406Sopenharmony_ci          timing=0x012e;
7006141cc406Sopenharmony_ci	  regs[0x85] = 0x8c;
7007141cc406Sopenharmony_ci	  regs[0x86] = 0x10;
7008141cc406Sopenharmony_ci	  regs[0x87] = 0x18;
7009141cc406Sopenharmony_ci	  regs[0x88] = 0x1b;
7010141cc406Sopenharmony_ci	  regs[0x8d] = 0x77;
7011141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
7012141cc406Sopenharmony_ci	  regs[0xc1] = 0x8e;
7013141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
7014141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
7015141cc406Sopenharmony_ci	  regs[0xc4] = 0x71;
7016141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
7017141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
7018141cc406Sopenharmony_ci	  regs[0xc7] = 0x8e;
7019141cc406Sopenharmony_ci	  regs[0xc8] = 0xff;
7020141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
7021141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
7022141cc406Sopenharmony_ci	  regs[0xcb] = 0x1f;
7023141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
7024141cc406Sopenharmony_ci	  regs[0xcd] = 0x71;
7025141cc406Sopenharmony_ci	  regs[0xce] = 0x00;
7026141cc406Sopenharmony_ci	  regs[0xcf] = 0xe6;
7027141cc406Sopenharmony_ci	  regs[0xd0] = 0xe8;
7028141cc406Sopenharmony_ci	  regs[0xd1] = 0xf6;
7029141cc406Sopenharmony_ci	  regs[0xd2] = 0x17;
7030141cc406Sopenharmony_ci	  regs[0xd3] = 0x0b;
7031141cc406Sopenharmony_ci	  regs[0xd4] = 0x0d;
7032141cc406Sopenharmony_ci	  regs[0xe3] = 0x86;
7033141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7034141cc406Sopenharmony_ci	  regs[0xe8] = 0x1c;
7035141cc406Sopenharmony_ci	  regs[0xe9] = 0x01;
7036141cc406Sopenharmony_ci	  regs[0xea] = 0x0a;
7037141cc406Sopenharmony_ci	  regs[0xeb] = 0xc4;
7038141cc406Sopenharmony_ci	  regs[0xec] = 0x01;
7039141cc406Sopenharmony_ci	  regs[0xed] = 0x04;
7040141cc406Sopenharmony_ci	  regs[0xee] = 0xf8;
7041141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7042141cc406Sopenharmony_ci	  regs[0xf0] = 0x02;
7043141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7044141cc406Sopenharmony_ci	  break;
7045141cc406Sopenharmony_ci	}
7046141cc406Sopenharmony_ci      break;
7047141cc406Sopenharmony_ci
7048141cc406Sopenharmony_ci    case 300:
7049141cc406Sopenharmony_ci      switch (dev->sensor)
7050141cc406Sopenharmony_ci	{
7051141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
7052141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_XPA for 300 dpi\n");
7053141cc406Sopenharmony_ci	  regs[0x35] = 0x0e;	/* fast ? */
7054141cc406Sopenharmony_ci	  regs[0x3a] = 0x0e;
7055141cc406Sopenharmony_ci
7056141cc406Sopenharmony_ci
7057141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
7058141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
7059141cc406Sopenharmony_ci
7060141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
7061141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
7062141cc406Sopenharmony_ci
7063141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7064141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7065141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7066141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7067141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7068141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7069141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7070141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7071141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7072141cc406Sopenharmony_ci	  regs[0x8d] = 0xef;
7073141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
7074141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7075141cc406Sopenharmony_ci	  regs[0xc2] = 0x0f;
7076141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
7077141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
7078141cc406Sopenharmony_ci	  regs[0xc5] = 0xf0;
7079141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
7080141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
7081141cc406Sopenharmony_ci	  regs[0xc8] = 0x0f;
7082141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
7083141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
7084141cc406Sopenharmony_ci	  regs[0xcb] = 0xf1;
7085141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
7086141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
7087141cc406Sopenharmony_ci	  regs[0xce] = 0xf0;
7088141cc406Sopenharmony_ci	  regs[0xcf] = 0xed;
7089141cc406Sopenharmony_ci	  regs[0xd0] = 0xef;
7090141cc406Sopenharmony_ci	  regs[0xd1] = 0xe2;
7091141cc406Sopenharmony_ci	  regs[0xd2] = 0x03;
7092141cc406Sopenharmony_ci	  regs[0xd3] = 0x17;
7093141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
7094141cc406Sopenharmony_ci	  regs[0xe2] = 0x07;
7095141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7096141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7097141cc406Sopenharmony_ci          timing=0x022b;
7098141cc406Sopenharmony_ci          exposure=342;
7099141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7100141cc406Sopenharmony_ci	  break;
7101141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
7102141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_BARE for 300 dpi\n");
7103141cc406Sopenharmony_ci	  regs[0x35] = 0x0e;	/* fast ? */
7104141cc406Sopenharmony_ci	  regs[0x3a] = 0x0e;
7105141cc406Sopenharmony_ci
7106141cc406Sopenharmony_ci          timing=0x022b;
7107141cc406Sopenharmony_ci
7108141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
7109141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
7110141cc406Sopenharmony_ci
7111141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
7112141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
7113141cc406Sopenharmony_ci
7114141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7115141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7116141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7117141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7118141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7119141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7120141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7121141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7122141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7123141cc406Sopenharmony_ci	  regs[0x8d] = 0xf0;
7124141cc406Sopenharmony_ci	  regs[0x8e] = 0x60;	/* low nibble of 8e and 8d are proportional to
7125141cc406Sopenharmony_ci					   the scanned width 1de => 5100 wide scan */
7126141cc406Sopenharmony_ci
7127141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
7128141cc406Sopenharmony_ci	  regs[0xc1] = 0x0f;
7129141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
7130141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
7131141cc406Sopenharmony_ci	  regs[0xca] = 0x0e;
7132141cc406Sopenharmony_ci	  regs[0xcb] = 0x00;
7133141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
7134141cc406Sopenharmony_ci	  regs[0xcd] = 0xf0;
7135141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7136141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
7137141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
7138141cc406Sopenharmony_ci	  regs[0xd1] = 0xea;
7139141cc406Sopenharmony_ci	  regs[0xd2] = 0x0b;
7140141cc406Sopenharmony_ci
7141141cc406Sopenharmony_ci	  regs[0xd3] = 0x17;
7142141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
7143141cc406Sopenharmony_ci
7144141cc406Sopenharmony_ci	  regs[0xe2] = 0x07;
7145141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7146141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7147141cc406Sopenharmony_ci
7148141cc406Sopenharmony_ci          exposure=342;
7149141cc406Sopenharmony_ci	  break;
7150141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
7151141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400 for 300 dpi\n");
7152141cc406Sopenharmony_ci	  regs[0x11] = 0x22;
7153141cc406Sopenharmony_ci	  regs[0x35] = 0x0e;
7154141cc406Sopenharmony_ci	  regs[0x3a] = 0x0e;
7155141cc406Sopenharmony_ci	  regs[0x85] = 0x18;
7156141cc406Sopenharmony_ci	  regs[0x86] = 0x1b;
7157141cc406Sopenharmony_ci	  regs[0x87] = 0x30;
7158141cc406Sopenharmony_ci	  regs[0x88] = 0x30;
7159141cc406Sopenharmony_ci	  regs[0x8d] = 0xef;
7160141cc406Sopenharmony_ci	  regs[0xc0] = 0x00;
7161141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7162141cc406Sopenharmony_ci	  regs[0xc2] = 0x0f;
7163141cc406Sopenharmony_ci	  regs[0xc3] = 0xff;
7164141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
7165141cc406Sopenharmony_ci	  regs[0xc5] = 0xf0;
7166141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
7167141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
7168141cc406Sopenharmony_ci	  regs[0xc8] = 0x0f;
7169141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
7170141cc406Sopenharmony_ci	  regs[0xca] = 0xff;
7171141cc406Sopenharmony_ci	  regs[0xcb] = 0xf1;
7172141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
7173141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
7174141cc406Sopenharmony_ci	  regs[0xce] = 0xf0;
7175141cc406Sopenharmony_ci	  regs[0xcf] = 0xed;
7176141cc406Sopenharmony_ci	  regs[0xd0] = 0xef;
7177141cc406Sopenharmony_ci	  regs[0xd1] = 0xe2;
7178141cc406Sopenharmony_ci	  regs[0xd2] = 0x03;
7179141cc406Sopenharmony_ci	  regs[0xd3] = 0x17;
7180141cc406Sopenharmony_ci	  regs[0xd4] = 0x01;
7181141cc406Sopenharmony_ci	  regs[0xe2] = 0x03;
7182141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7183141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7184141cc406Sopenharmony_ci          timing=0x022b;
7185141cc406Sopenharmony_ci          exposure=686;
7186141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7187141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7188141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7189141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7190141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7191141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7192141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7193141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7194141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7195141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7196141cc406Sopenharmony_ci	  break;
7197141cc406Sopenharmony_ci	}
7198141cc406Sopenharmony_ci      break;
7199141cc406Sopenharmony_ci    case 600:
7200141cc406Sopenharmony_ci      *status1 = 0x28;
7201141cc406Sopenharmony_ci      switch (dev->sensor)
7202141cc406Sopenharmony_ci	{
7203141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
7204141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_BARE for 600 dpi\n");
7205141cc406Sopenharmony_ci
7206141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7207141cc406Sopenharmony_ci	  regs[0x35] = 0x1b;
7208141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
7209141cc406Sopenharmony_ci	  regs[0x3a] = 0x1b;
7210141cc406Sopenharmony_ci
7211141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
7212141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
7213141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
7214141cc406Sopenharmony_ci
7215141cc406Sopenharmony_ci          timing=0x0425;
7216141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
7217141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
7218141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
7219141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
7220141cc406Sopenharmony_ci
7221141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
7222141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;	/* low nibble of 8e and 8d are proportional to
7223141cc406Sopenharmony_ci					   the scanned width 1de => 5100 wide scan */
7224141cc406Sopenharmony_ci
7225141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
7226141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7227141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
7228141cc406Sopenharmony_ci	  regs[0xc3] = 0x00;
7229141cc406Sopenharmony_ci	  regs[0xc4] = 0xf0;
7230141cc406Sopenharmony_ci	  regs[0xc7] = 0x0f;
7231141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
7232141cc406Sopenharmony_ci	  regs[0xcb] = 0xe0;
7233141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
7234141cc406Sopenharmony_ci	  regs[0xcd] = 0xff;
7235141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7236141cc406Sopenharmony_ci	  regs[0xcf] = 0xe9;
7237141cc406Sopenharmony_ci	  regs[0xd0] = 0xeb;
7238141cc406Sopenharmony_ci
7239141cc406Sopenharmony_ci	  regs[0xd7] = 0x14;
7240141cc406Sopenharmony_ci
7241141cc406Sopenharmony_ci	  regs[0xe2] = 0x01;
7242141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7243141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7244141cc406Sopenharmony_ci	  /* regs[0xe5] = 0xbd;
7245141cc406Sopenharmony_ci	     regs[0xe6] = 0x0a;         exposure time = 0x0abd=2749 (5500/2-1) */
7246141cc406Sopenharmony_ci          exposure=2749;
7247141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7248141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7249141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7250141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7251141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7252141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7253141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7254141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7255141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7256141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7257141cc406Sopenharmony_ci	  break;
7258141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
7259141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_XPA for 600 dpi\n");
7260141cc406Sopenharmony_ci
7261141cc406Sopenharmony_ci          *status2 = 0x3b;
7262141cc406Sopenharmony_ci	  regs[0x33] = 0x83; /* 0x86 */
7263141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7264141cc406Sopenharmony_ci	  regs[0x35] = 0x1b;
7265141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
7266141cc406Sopenharmony_ci	  regs[0x3a] = 0x1b;
7267141cc406Sopenharmony_ci	  regs[0x40] = 0x2c; /* 0x24 */
7268141cc406Sopenharmony_ci	  regs[0x50] = 0x00; /* 0x18 */
7269141cc406Sopenharmony_ci
7270141cc406Sopenharmony_ci          regs[0x64] = 0x01; /* 0x02 */
7271141cc406Sopenharmony_ci	  regs[0x65] = 0x20; /* 0x10 */
7272141cc406Sopenharmony_ci
7273141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
7274141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
7275141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
7276141cc406Sopenharmony_ci
7277141cc406Sopenharmony_ci
7278141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
7279141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
7280141cc406Sopenharmony_ci
7281141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
7282141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
7283141cc406Sopenharmony_ci
7284141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
7285141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;	/* 25054 */
7286141cc406Sopenharmony_ci
7287141cc406Sopenharmony_ci	  regs[0xc0] = 0xf8;
7288141cc406Sopenharmony_ci	  regs[0xc1] = 0x7f;
7289141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
7290141cc406Sopenharmony_ci	  regs[0xc3] = 0xf8;
7291141cc406Sopenharmony_ci	  regs[0xc4] = 0x7f;
7292141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
7293141cc406Sopenharmony_ci	  regs[0xc6] = 0xf8;
7294141cc406Sopenharmony_ci	  regs[0xc7] = 0x7f;
7295141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
7296141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
7297141cc406Sopenharmony_ci	  regs[0xca] = 0x8f;
7298141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
7299141cc406Sopenharmony_ci	  regs[0xcc] = 0x07;
7300141cc406Sopenharmony_ci	  regs[0xcd] = 0x80;
7301141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7302141cc406Sopenharmony_ci	  regs[0xcf] = 0xf2;
7303141cc406Sopenharmony_ci	  regs[0xd0] = 0xf4;
7304141cc406Sopenharmony_ci	  regs[0xd1] = 0xe7;
7305141cc406Sopenharmony_ci	  regs[0xd2] = 0x08;
7306141cc406Sopenharmony_ci	  regs[0xd3] = 0x02;
7307141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
7308141cc406Sopenharmony_ci	  regs[0xd7] = 0x31;
7309141cc406Sopenharmony_ci	  regs[0xe2] = 0x01;
7310141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7311141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7312141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7313141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7314141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7315141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7316141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7317141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7318141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7319141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7320141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7321141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7322141cc406Sopenharmony_ci          exposure=2749;
7323141cc406Sopenharmony_ci          timing=0x0425;
7324141cc406Sopenharmony_ci	  break;
7325141cc406Sopenharmony_ci
7326141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
7327141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400 for 600 dpi\n");
7328141cc406Sopenharmony_ci	  *status1 = 0x10;
7329141cc406Sopenharmony_ci	  *status2 = 0x23;
7330141cc406Sopenharmony_ci
7331141cc406Sopenharmony_ci	  regs[0x13] = 0x39;
7332141cc406Sopenharmony_ci	  regs[0x14] = 0xf0;
7333141cc406Sopenharmony_ci	  regs[0x15] = 0x29;
7334141cc406Sopenharmony_ci	  regs[0x16] = 0x00;
7335141cc406Sopenharmony_ci	  regs[0x17] = 0x10;
7336141cc406Sopenharmony_ci	  regs[0x23] = 0x00;
7337141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7338141cc406Sopenharmony_ci	  regs[0x35] = 0x1b;
7339141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
7340141cc406Sopenharmony_ci	  regs[0x39] = 0x00;
7341141cc406Sopenharmony_ci	  regs[0x3a] = 0x1b;
7342141cc406Sopenharmony_ci	  regs[0x72] = 0x3a;
7343141cc406Sopenharmony_ci	  regs[0x73] = 0x15;
7344141cc406Sopenharmony_ci	  regs[0x74] = 0x62;
7345141cc406Sopenharmony_ci	  regs[0x85] = 0x30;
7346141cc406Sopenharmony_ci	  regs[0x86] = 0x30;
7347141cc406Sopenharmony_ci	  regs[0x87] = 0x60;
7348141cc406Sopenharmony_ci	  regs[0x88] = 0x5a;
7349141cc406Sopenharmony_ci	  regs[0x8d] = 0xde;
7350141cc406Sopenharmony_ci	  regs[0x8e] = 0x61;
7351141cc406Sopenharmony_ci	  regs[0xc0] = 0xf8;
7352141cc406Sopenharmony_ci	  regs[0xc1] = 0x7f;
7353141cc406Sopenharmony_ci	  regs[0xc2] = 0x00;
7354141cc406Sopenharmony_ci	  regs[0xc3] = 0xf8;
7355141cc406Sopenharmony_ci	  regs[0xc4] = 0x7f;
7356141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
7357141cc406Sopenharmony_ci	  regs[0xc6] = 0xf8;
7358141cc406Sopenharmony_ci	  regs[0xc7] = 0x7f;
7359141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
7360141cc406Sopenharmony_ci	  regs[0xc9] = 0xff;
7361141cc406Sopenharmony_ci	  regs[0xca] = 0x8f;
7362141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
7363141cc406Sopenharmony_ci	  regs[0xcc] = 0x07;
7364141cc406Sopenharmony_ci	  regs[0xcd] = 0x80;
7365141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7366141cc406Sopenharmony_ci	  regs[0xcf] = 0xf2;
7367141cc406Sopenharmony_ci	  regs[0xd0] = 0xf4;
7368141cc406Sopenharmony_ci	  regs[0xd1] = 0xe7;
7369141cc406Sopenharmony_ci	  regs[0xd2] = 0x08;
7370141cc406Sopenharmony_ci	  regs[0xd3] = 0x0e;
7371141cc406Sopenharmony_ci	  regs[0xd4] = 0x10;
7372141cc406Sopenharmony_ci	  regs[0xd7] = 0x31;
7373141cc406Sopenharmony_ci	  regs[0xe2] = 0x01;
7374141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7375141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7376141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7377141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7378141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7379141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7380141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7381141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7382141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7383141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7384141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7385141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7386141cc406Sopenharmony_ci          timing=0x0425;
7387141cc406Sopenharmony_ci          exposure=2749;
7388141cc406Sopenharmony_ci	  break;
7389141cc406Sopenharmony_ci
7390141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
7391141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400_BARE for 600 dpi\n");
7392141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
7393141cc406Sopenharmony_ci	  break;
7394141cc406Sopenharmony_ci	}
7395141cc406Sopenharmony_ci      break;
7396141cc406Sopenharmony_ci    case 1200:
7397141cc406Sopenharmony_ci      *status1 = 0x28;
7398141cc406Sopenharmony_ci      switch (dev->sensor)
7399141cc406Sopenharmony_ci	{
7400141cc406Sopenharmony_ci	case SENSOR_TYPE_BARE:
7401141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_BARE for 1200 dpi\n");
7402141cc406Sopenharmony_ci
7403141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7404141cc406Sopenharmony_ci	  regs[0x35] = 0x1b;
7405141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
7406141cc406Sopenharmony_ci	  regs[0x3a] = 0x1b;
7407141cc406Sopenharmony_ci	  regs[0x40] = 0xac;
7408141cc406Sopenharmony_ci          timing=0x081a;
7409141cc406Sopenharmony_ci	  regs[0x85] = 0x60;
7410141cc406Sopenharmony_ci	  regs[0x86] = 0x5a;
7411141cc406Sopenharmony_ci	  regs[0x87] = 0xc0;
7412141cc406Sopenharmony_ci	  regs[0x88] = 0xae;
7413141cc406Sopenharmony_ci
7414141cc406Sopenharmony_ci	  regs[0x8d] = 0xbd;	/* about twice the 600 dpi values */
7415141cc406Sopenharmony_ci	  regs[0x8e] = 0x63;	/* low nibble of 8e and 8d are proportional to
7416141cc406Sopenharmony_ci					   the scanned width 3b5 => 10124 wide scan */
7417141cc406Sopenharmony_ci	  regs[0xc0] = 0xff;
7418141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7419141cc406Sopenharmony_ci	  regs[0xc2] = 0xff;
7420141cc406Sopenharmony_ci	  regs[0xc4] = 0x0f;
7421141cc406Sopenharmony_ci	  regs[0xc5] = 0x00;
7422141cc406Sopenharmony_ci	  regs[0xc6] = 0x00;
7423141cc406Sopenharmony_ci	  regs[0xc7] = 0xf0;
7424141cc406Sopenharmony_ci	  regs[0xc9] = 0x00;
7425141cc406Sopenharmony_ci	  regs[0xca] = 0x0e;
7426141cc406Sopenharmony_ci	  regs[0xcb] = 0x00;
7427141cc406Sopenharmony_ci	  regs[0xcc] = 0xff;
7428141cc406Sopenharmony_ci	  regs[0xcd] = 0xff;
7429141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7430141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
7431141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
7432141cc406Sopenharmony_ci	  regs[0xd1] = 0xea;
7433141cc406Sopenharmony_ci	  regs[0xd2] = 0x0b;
7434141cc406Sopenharmony_ci	  regs[0xd3] = 0x17;
7435141cc406Sopenharmony_ci	  regs[0xd4] = 0xc1;
7436141cc406Sopenharmony_ci
7437141cc406Sopenharmony_ci	  regs[0xd7] = 0x14;
7438141cc406Sopenharmony_ci	  regs[0xd8] = 0xa4;
7439141cc406Sopenharmony_ci
7440141cc406Sopenharmony_ci	  regs[0xe2] = 0x01;
7441141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7442141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7443141cc406Sopenharmony_ci	  /* regs[0xe5] = 0x7b;
7444141cc406Sopenharmony_ci	     regs[0xe6] = 0x15;         exposure time = 0x157b=5499 */
7445141cc406Sopenharmony_ci          exposure=5499;
7446141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7447141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7448141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7449141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7450141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7451141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7452141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7453141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7454141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7455141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7456141cc406Sopenharmony_ci	  break;
7457141cc406Sopenharmony_ci	case SENSOR_TYPE_XPA:
7458141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_XPA for 1200 dpi\n");
7459141cc406Sopenharmony_ci	  *status2 = 0x3f;
7460141cc406Sopenharmony_ci
7461141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7462141cc406Sopenharmony_ci	  regs[0x35] = 0x1b;
7463141cc406Sopenharmony_ci	  regs[0x36] = 0x29;
7464141cc406Sopenharmony_ci	  regs[0x3a] = 0x1b;
7465141cc406Sopenharmony_ci	  regs[0x85] = 0x60;
7466141cc406Sopenharmony_ci	  regs[0x86] = 0x5a;
7467141cc406Sopenharmony_ci	  regs[0x87] = 0xc0;
7468141cc406Sopenharmony_ci	  regs[0x8a] = 0x08;	/* 81c=2076 */
7469141cc406Sopenharmony_ci
7470141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7471141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7472141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
7473141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
7474141cc406Sopenharmony_ci
7475141cc406Sopenharmony_ci	  regs[0xe2] = 0x01;
7476141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7477141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7478141cc406Sopenharmony_ci          timing=0x081a;
7479141cc406Sopenharmony_ci          exposure=5499;
7480141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7481141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7482141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7483141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7484141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7485141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7486141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7487141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7488141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7489141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7490141cc406Sopenharmony_ci	  regs[0x33] = 0x83;
7491141cc406Sopenharmony_ci	  regs[0x40] = 0xac;
7492141cc406Sopenharmony_ci	  regs[0x50] = 0x00;
7493141cc406Sopenharmony_ci	  regs[0x64] = 0x01;
7494141cc406Sopenharmony_ci	  regs[0x65] = 0x20;
7495141cc406Sopenharmony_ci	  regs[0x88] = 0xae;
7496141cc406Sopenharmony_ci	  regs[0x8d] = 0xbc;
7497141cc406Sopenharmony_ci	  regs[0x8e] = 0x63;
7498141cc406Sopenharmony_ci	  regs[0xc0] = 0xe0;
7499141cc406Sopenharmony_ci	  regs[0xc2] = 0x01;
7500141cc406Sopenharmony_ci	  regs[0xc3] = 0x1f;
7501141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
7502141cc406Sopenharmony_ci	  regs[0xc5] = 0xfe;
7503141cc406Sopenharmony_ci	  regs[0xc6] = 0xff;
7504141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
7505141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
7506141cc406Sopenharmony_ci	  regs[0xc9] = 0x3f;
7507141cc406Sopenharmony_ci	  regs[0xca] = 0xfe;
7508141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
7509141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
7510141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
7511141cc406Sopenharmony_ci	  regs[0xd1] = 0xec;
7512141cc406Sopenharmony_ci	  regs[0xd2] = 0x0d;
7513141cc406Sopenharmony_ci	  regs[0xd3] = 0x05;
7514141cc406Sopenharmony_ci	  regs[0xd4] = 0x67;
7515141cc406Sopenharmony_ci	  regs[0xd7] = 0x10;
7516141cc406Sopenharmony_ci	  regs[0xd8] = 0x52;
7517141cc406Sopenharmony_ci	  break;
7518141cc406Sopenharmony_ci
7519141cc406Sopenharmony_ci	case SENSOR_TYPE_4400:
7520141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400 for 1200 dpi\n");
7521141cc406Sopenharmony_ci	  regs[0x13] = 0x39;
7522141cc406Sopenharmony_ci	  regs[0x14] = 0xf0;
7523141cc406Sopenharmony_ci	  regs[0x15] = 0x29;
7524141cc406Sopenharmony_ci	  regs[0x16] = 0x00;
7525141cc406Sopenharmony_ci	  regs[0x17] = 0x10;
7526141cc406Sopenharmony_ci	  regs[0x23] = 0x00;
7527141cc406Sopenharmony_ci	  regs[0x33] = 0x86;
7528141cc406Sopenharmony_ci	  regs[0x34] = 0xf0;
7529141cc406Sopenharmony_ci	  regs[0x35] = 0x0e;
7530141cc406Sopenharmony_ci	  regs[0x39] = 0x00;
7531141cc406Sopenharmony_ci	  regs[0x3a] = 0x0e;
7532141cc406Sopenharmony_ci	  regs[0x40] = 0xac;
7533141cc406Sopenharmony_ci	  regs[0x64] = 0x02;
7534141cc406Sopenharmony_ci	  regs[0x65] = 0x10;
7535141cc406Sopenharmony_ci          timing=0x081a;
7536141cc406Sopenharmony_ci	  regs[0x85] = 0x60;
7537141cc406Sopenharmony_ci	  regs[0x86] = 0x5a;
7538141cc406Sopenharmony_ci	  regs[0x87] = 0xc0;
7539141cc406Sopenharmony_ci	  regs[0x88] = 0xae;
7540141cc406Sopenharmony_ci	  regs[0x8d] = 0xbc;
7541141cc406Sopenharmony_ci	  regs[0x8e] = 0x63;
7542141cc406Sopenharmony_ci	  regs[0xc0] = 0xe0;
7543141cc406Sopenharmony_ci	  regs[0xc1] = 0xff;
7544141cc406Sopenharmony_ci	  regs[0xc2] = 0x01;
7545141cc406Sopenharmony_ci	  regs[0xc3] = 0x1f;
7546141cc406Sopenharmony_ci	  regs[0xc4] = 0x00;
7547141cc406Sopenharmony_ci	  regs[0xc5] = 0xfe;
7548141cc406Sopenharmony_ci	  regs[0xc6] = 0xff;
7549141cc406Sopenharmony_ci	  regs[0xc7] = 0xff;
7550141cc406Sopenharmony_ci	  regs[0xc8] = 0x00;
7551141cc406Sopenharmony_ci	  regs[0xc9] = 0x3f;
7552141cc406Sopenharmony_ci	  regs[0xca] = 0xfe;
7553141cc406Sopenharmony_ci	  regs[0xcb] = 0xff;
7554141cc406Sopenharmony_ci	  regs[0xcc] = 0x00;
7555141cc406Sopenharmony_ci	  regs[0xcd] = 0x00;
7556141cc406Sopenharmony_ci	  regs[0xce] = 0xff;
7557141cc406Sopenharmony_ci	  regs[0xcf] = 0xf5;
7558141cc406Sopenharmony_ci	  regs[0xd0] = 0xf7;
7559141cc406Sopenharmony_ci	  regs[0xd1] = 0xec;
7560141cc406Sopenharmony_ci	  regs[0xd2] = 0x0d;
7561141cc406Sopenharmony_ci	  regs[0xd3] = 0x05;
7562141cc406Sopenharmony_ci	  regs[0xd4] = 0x67;
7563141cc406Sopenharmony_ci	  regs[0xd7] = 0x10;
7564141cc406Sopenharmony_ci	  regs[0xd8] = 0x52;
7565141cc406Sopenharmony_ci	  regs[0xe2] = 0x00;
7566141cc406Sopenharmony_ci	  regs[0xe3] = 0x00;
7567141cc406Sopenharmony_ci	  regs[0xe4] = 0x00;
7568141cc406Sopenharmony_ci	  regs[0xe7] = 0x00;
7569141cc406Sopenharmony_ci	  regs[0xe8] = 0x00;
7570141cc406Sopenharmony_ci	  regs[0xe9] = 0x00;
7571141cc406Sopenharmony_ci	  regs[0xea] = 0x00;
7572141cc406Sopenharmony_ci	  regs[0xeb] = 0x00;
7573141cc406Sopenharmony_ci	  regs[0xec] = 0x00;
7574141cc406Sopenharmony_ci	  regs[0xed] = 0x00;
7575141cc406Sopenharmony_ci	  regs[0xef] = 0x00;
7576141cc406Sopenharmony_ci	  regs[0xf0] = 0x00;
7577141cc406Sopenharmony_ci	  regs[0xf2] = 0x00;
7578141cc406Sopenharmony_ci          exposure=10999;
7579141cc406Sopenharmony_ci	  *status1 = 0x10;
7580141cc406Sopenharmony_ci	  *status2 = 0x23;
7581141cc406Sopenharmony_ci	  break;
7582141cc406Sopenharmony_ci
7583141cc406Sopenharmony_ci	case SENSOR_TYPE_4400_BARE:
7584141cc406Sopenharmony_ci          DBG (DBG_io, "setup_scan_registers: setting up SENSOR_TYPE_4400_BARE for 1200 dpi\n");
7585141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
7586141cc406Sopenharmony_ci	  break;
7587141cc406Sopenharmony_ci	}
7588141cc406Sopenharmony_ci      break;
7589141cc406Sopenharmony_ci    }
7590141cc406Sopenharmony_ci
7591141cc406Sopenharmony_ci  /* apply computed settings */
7592141cc406Sopenharmony_ci  SET_DOUBLE (regs, EXPOSURE_REG, exposure);
7593141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING_REG, timing);
7594141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING1_REG, timing+1);
7595141cc406Sopenharmony_ci  SET_DOUBLE (regs, TIMING2_REG, timing+2);
7596141cc406Sopenharmony_ci
7597141cc406Sopenharmony_ci  /* sets divisor */
7598141cc406Sopenharmony_ci  regs[0xd3] = rts8891_data_format (dev->xdpi, dev->sensor);
7599141cc406Sopenharmony_ci
7600141cc406Sopenharmony_ci  /* toggle front panel light to signal gray scan */
7601141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_GRAY)
7602141cc406Sopenharmony_ci    {
7603141cc406Sopenharmony_ci      *status1 = (*status1 & 0x0F) | 0x10;
7604141cc406Sopenharmony_ci    }
7605141cc406Sopenharmony_ci
7606141cc406Sopenharmony_ci  return status;
7607141cc406Sopenharmony_ci}
7608141cc406Sopenharmony_ci
7609141cc406Sopenharmony_ci/* set up the shadow registers for scan, depending on scan parameters    */
7610141cc406Sopenharmony_ci/* the ultimate goal is to have no direct access to registers, but to    */
7611141cc406Sopenharmony_ci/* set them through helper functions                                     */
7612141cc406Sopenharmony_ci/* NOTE : I couldn't manage to get scans that really uses gray settings. */
7613141cc406Sopenharmony_ci/* The windows driver is always scanning in color, so we do the same.   */
7614141cc406Sopenharmony_ci/* For now, the only mode that could be done would be 300 dpi gray scan, */
7615141cc406Sopenharmony_ci/* based on the register settings of find_origin()                       */
7616141cc406Sopenharmony_cistatic SANE_Status
7617141cc406Sopenharmony_ciwrite_scan_registers (struct Rts8891_Session *session)
7618141cc406Sopenharmony_ci{
7619141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
7620141cc406Sopenharmony_ci  SANE_Byte control;
7621141cc406Sopenharmony_ci  SANE_Byte status1, status2;
7622141cc406Sopenharmony_ci  struct Rts8891_Device *dev = session->dev;
7623141cc406Sopenharmony_ci
7624141cc406Sopenharmony_ci  /* setup registers for scan */
7625141cc406Sopenharmony_ci  status=setup_scan_registers (session, &status1, &status2, dev->regs);
7626141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
7627141cc406Sopenharmony_ci    {
7628141cc406Sopenharmony_ci      DBG (DBG_error0, "write_scan_registers: failed to setup registers\n");
7629141cc406Sopenharmony_ci      return status;
7630141cc406Sopenharmony_ci    }
7631141cc406Sopenharmony_ci
7632141cc406Sopenharmony_ci  /* check if session is idle */
7633141cc406Sopenharmony_ci  control = 0x00;
7634141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
7635141cc406Sopenharmony_ci  if (control != 0)
7636141cc406Sopenharmony_ci    {
7637141cc406Sopenharmony_ci      DBG (DBG_error0, "write_scan_registers: scanner is not idle!\n");
7638141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
7639141cc406Sopenharmony_ci    }
7640141cc406Sopenharmony_ci
7641141cc406Sopenharmony_ci  /* effective write of register set for scan */
7642141cc406Sopenharmony_ci  status = rts8891_write_all (dev->devnum, dev->regs, dev->reg_count);
7643141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
7644141cc406Sopenharmony_ci    {
7645141cc406Sopenharmony_ci      DBG (DBG_error0, "write_scan_registers: failed to write registers\n");
7646141cc406Sopenharmony_ci    }
7647141cc406Sopenharmony_ci  return status;
7648141cc406Sopenharmony_ci}
7649141cc406Sopenharmony_ci
7650141cc406Sopenharmony_ci/**
7651141cc406Sopenharmony_ci * This function parks head relying by moving head backward by a
7652141cc406Sopenharmony_ci * very large amount without scanning
7653141cc406Sopenharmony_ci */
7654141cc406Sopenharmony_cistatic SANE_Status
7655141cc406Sopenharmony_cipark_head (struct Rts8891_Device *dev, SANE_Bool wait)
7656141cc406Sopenharmony_ci{
7657141cc406Sopenharmony_ci  SANE_Status status;
7658141cc406Sopenharmony_ci  SANE_Byte reg, control;
7659141cc406Sopenharmony_ci  /* the hammer way : set all regs */
7660141cc406Sopenharmony_ci  SANE_Byte regs[244];
7661141cc406Sopenharmony_ci
7662141cc406Sopenharmony_ci  DBG (DBG_proc, "park_head: start\n");
7663141cc406Sopenharmony_ci
7664141cc406Sopenharmony_ci  reg = 0x8d;
7665141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
7666141cc406Sopenharmony_ci  reg = 0xad;
7667141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
7668141cc406Sopenharmony_ci
7669141cc406Sopenharmony_ci  status = sanei_rts88xx_read_reg (dev->devnum, CONTROL_REG, &control);
7670141cc406Sopenharmony_ci
7671141cc406Sopenharmony_ci  reg = 0xff;
7672141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, 0x23, &reg);
7673141cc406Sopenharmony_ci
7674141cc406Sopenharmony_ci  /* TODO create write_double_reg */
7675141cc406Sopenharmony_ci  if (dev->sensor != SENSOR_TYPE_4400)
7676141cc406Sopenharmony_ci    {
7677141cc406Sopenharmony_ci      dev->regs[0x16] = 0x07;
7678141cc406Sopenharmony_ci      dev->regs[0x17] = 0x00;
7679141cc406Sopenharmony_ci    }
7680141cc406Sopenharmony_ci  else
7681141cc406Sopenharmony_ci    {
7682141cc406Sopenharmony_ci      dev->regs[0x16] = 0x0f;
7683141cc406Sopenharmony_ci      dev->regs[0x17] = 0x10;
7684141cc406Sopenharmony_ci    }
7685141cc406Sopenharmony_ci  sanei_rts88xx_write_regs (dev->devnum, 0x16, dev->regs + 0x16, 2);
7686141cc406Sopenharmony_ci
7687141cc406Sopenharmony_ci  reg = 0x8d;
7688141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
7689141cc406Sopenharmony_ci  reg = 0xad;
7690141cc406Sopenharmony_ci  sanei_rts88xx_write_reg (dev->devnum, LAMP_REG, &reg);
7691141cc406Sopenharmony_ci
7692141cc406Sopenharmony_ci  /* 0x20 expected */
7693141cc406Sopenharmony_ci  sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, &reg);
7694141cc406Sopenharmony_ci  if (reg != 0x20)
7695141cc406Sopenharmony_ci    {
7696141cc406Sopenharmony_ci      DBG (DBG_warn, "park_head: unexpected controller value 0x%02x\n", reg);
7697141cc406Sopenharmony_ci    }
7698141cc406Sopenharmony_ci
7699141cc406Sopenharmony_ci  /* head parking */
7700141cc406Sopenharmony_ci  status = rts8891_park (dev, regs, wait);
7701141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
7702141cc406Sopenharmony_ci    {
7703141cc406Sopenharmony_ci      DBG (DBG_error, "park_head: failed to park head!\n");
7704141cc406Sopenharmony_ci    }
7705141cc406Sopenharmony_ci
7706141cc406Sopenharmony_ci  DBG (DBG_proc, "park_head: end\n");
7707141cc406Sopenharmony_ci  return status;
7708141cc406Sopenharmony_ci}
7709141cc406Sopenharmony_ci
7710141cc406Sopenharmony_ci/* update button status
7711141cc406Sopenharmony_ci * button access is allowed during scan, which is useful for 'cancel' button
7712141cc406Sopenharmony_ci */
7713141cc406Sopenharmony_cistatic SANE_Status
7714141cc406Sopenharmony_ciupdate_button_status (struct Rts8891_Session *session)
7715141cc406Sopenharmony_ci{
7716141cc406Sopenharmony_ci  SANE_Int mask = 0, i;
7717141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
7718141cc406Sopenharmony_ci  SANE_Bool lock = SANE_FALSE;
7719141cc406Sopenharmony_ci
7720141cc406Sopenharmony_ci  /* while scanning, interface is reserved, so don't claim/release it */
7721141cc406Sopenharmony_ci  if (session->scanning != SANE_TRUE)
7722141cc406Sopenharmony_ci    {
7723141cc406Sopenharmony_ci      lock = SANE_TRUE;
7724141cc406Sopenharmony_ci
7725141cc406Sopenharmony_ci      /* claim the interface to reserve device */
7726141cc406Sopenharmony_ci      if (session->dev->conf.allowsharing == SANE_TRUE)
7727141cc406Sopenharmony_ci	{
7728141cc406Sopenharmony_ci	  status = sanei_usb_claim_interface (session->dev->devnum, 0);
7729141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
7730141cc406Sopenharmony_ci	    {
7731141cc406Sopenharmony_ci	      DBG (DBG_warn,
7732141cc406Sopenharmony_ci		   "update_button_status: cannot claim usb interface\n");
7733141cc406Sopenharmony_ci	      return SANE_STATUS_DEVICE_BUSY;
7734141cc406Sopenharmony_ci	    }
7735141cc406Sopenharmony_ci	}
7736141cc406Sopenharmony_ci    }
7737141cc406Sopenharmony_ci
7738141cc406Sopenharmony_ci  /* effective button reading */
7739141cc406Sopenharmony_ci  status = rts8891_read_buttons (session->dev->devnum, &mask);
7740141cc406Sopenharmony_ci
7741141cc406Sopenharmony_ci  /* release interface if needed */
7742141cc406Sopenharmony_ci  if (lock == SANE_TRUE)
7743141cc406Sopenharmony_ci    {
7744141cc406Sopenharmony_ci      if (session->dev->conf.allowsharing == SANE_TRUE)
7745141cc406Sopenharmony_ci	{
7746141cc406Sopenharmony_ci	  sanei_usb_release_interface (session->dev->devnum, 0);
7747141cc406Sopenharmony_ci	}
7748141cc406Sopenharmony_ci    }
7749141cc406Sopenharmony_ci
7750141cc406Sopenharmony_ci  for (i = 0; i < session->dev->model->buttons; i++)
7751141cc406Sopenharmony_ci    {
7752141cc406Sopenharmony_ci      if (mask & (1 << i))
7753141cc406Sopenharmony_ci	{
7754141cc406Sopenharmony_ci	  session->val[OPT_BUTTON_1 + i].w = SANE_TRUE;
7755141cc406Sopenharmony_ci	  DBG (DBG_io2, "update_button_status: setting button %d to TRUE\n",
7756141cc406Sopenharmony_ci	       i + 1);
7757141cc406Sopenharmony_ci	}
7758141cc406Sopenharmony_ci    }
7759141cc406Sopenharmony_ci  return status;
7760141cc406Sopenharmony_ci}
7761141cc406Sopenharmony_ci
7762141cc406Sopenharmony_ci/* set lamp status, 0 for lamp off
7763141cc406Sopenharmony_ci * other values set lamp on */
7764141cc406Sopenharmony_cistatic SANE_Status
7765141cc406Sopenharmony_ciset_lamp_state (struct Rts8891_Session *session, int on)
7766141cc406Sopenharmony_ci{
7767141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
7768141cc406Sopenharmony_ci  SANE_Byte reg;
7769141cc406Sopenharmony_ci
7770141cc406Sopenharmony_ci  /* claim the interface reserve device */
7771141cc406Sopenharmony_ci  if (session->dev->conf.allowsharing == SANE_TRUE)
7772141cc406Sopenharmony_ci    {
7773141cc406Sopenharmony_ci      status = sanei_usb_claim_interface (session->dev->devnum, 0);
7774141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
7775141cc406Sopenharmony_ci	{
7776141cc406Sopenharmony_ci	  DBG (DBG_warn, "set_lamp_state: cannot claim usb interface\n");
7777141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
7778141cc406Sopenharmony_ci	}
7779141cc406Sopenharmony_ci    }
7780141cc406Sopenharmony_ci
7781141cc406Sopenharmony_ci  status = sanei_rts88xx_read_reg (session->dev->devnum, LAMP_REG, &reg);
7782141cc406Sopenharmony_ci  if (on)
7783141cc406Sopenharmony_ci    {
7784141cc406Sopenharmony_ci      DBG (DBG_info, "set_lamp_state: lamp on\n");
7785141cc406Sopenharmony_ci      reg = session->dev->regs[LAMP_REG] | 0x80;
7786141cc406Sopenharmony_ci    }
7787141cc406Sopenharmony_ci  else
7788141cc406Sopenharmony_ci    {
7789141cc406Sopenharmony_ci      DBG (DBG_info, "set_lamp_state: lamp off\n");
7790141cc406Sopenharmony_ci      reg = session->dev->regs[LAMP_REG] & 0x7F;
7791141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
7792141cc406Sopenharmony_ci      /* if lamp is switched off, warming up will be needed */
7793141cc406Sopenharmony_ci      session->dev->last_scan.tv_sec = 0;
7794141cc406Sopenharmony_ci#endif
7795141cc406Sopenharmony_ci    }
7796141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (session->dev->devnum, LAMP_REG, &reg);
7797141cc406Sopenharmony_ci
7798141cc406Sopenharmony_ci  /* release interface and return status from lamp setting */
7799141cc406Sopenharmony_ci  if (session->dev->conf.allowsharing == SANE_TRUE)
7800141cc406Sopenharmony_ci    {
7801141cc406Sopenharmony_ci      sanei_usb_release_interface (session->dev->devnum, 0);
7802141cc406Sopenharmony_ci    }
7803141cc406Sopenharmony_ci  return status;
7804141cc406Sopenharmony_ci}
7805141cc406Sopenharmony_ci
7806141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
7807