1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   --------------------------------------------------------------------------
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   This file implements a SANE backend for HP ScanJet 3500 series scanners.
42141cc406Sopenharmony_ci   Currently supported:
43141cc406Sopenharmony_ci    - HP ScanJet 3500C
44141cc406Sopenharmony_ci    - HP ScanJet 3530C
45141cc406Sopenharmony_ci    - HP ScanJet 3570C
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci   SANE FLOW DIAGRAM
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci   - sane_init() : initialize backend, attach scanners
50141cc406Sopenharmony_ci   . - sane_get_devices() : query list of scanner devices
51141cc406Sopenharmony_ci   . - sane_open() : open a particular scanner device
52141cc406Sopenharmony_ci   . . - sane_set_io_mode : set blocking mode
53141cc406Sopenharmony_ci   . . - sane_get_select_fd : get scanner fd
54141cc406Sopenharmony_ci   . . - sane_get_option_descriptor() : get option information
55141cc406Sopenharmony_ci   . . - sane_control_option() : change option values
56141cc406Sopenharmony_ci   . .
57141cc406Sopenharmony_ci   . . - sane_start() : start image acquisition
58141cc406Sopenharmony_ci   . .   - sane_get_parameters() : returns actual scan parameters
59141cc406Sopenharmony_ci   . .   - sane_read() : read image data (from pipe)
60141cc406Sopenharmony_ci   . .
61141cc406Sopenharmony_ci   . . - sane_cancel() : cancel operation
62141cc406Sopenharmony_ci   . - sane_close() : close opened scanner device
63141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci   There are some device specific routines in this file that are in "#if 0"
67141cc406Sopenharmony_ci   sections - these are left in place for documentation purposes in case
68141cc406Sopenharmony_ci   somebody wants to implement features that use those routines.
69141cc406Sopenharmony_ci
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 <signal.h>
80141cc406Sopenharmony_ci#include <stdio.h>
81141cc406Sopenharmony_ci#include <stdlib.h>
82141cc406Sopenharmony_ci#include <string.h>
83141cc406Sopenharmony_ci#include <ctype.h>
84141cc406Sopenharmony_ci#include <time.h>
85141cc406Sopenharmony_ci#include <math.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>		/* NeXTStep/OpenStep */
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_thread.h"
98141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_ci#define RTCMD_GETREG		0x80
101141cc406Sopenharmony_ci#define	RTCMD_READSRAM		0x81
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci#define	RTCMD_SETREG		0x88
104141cc406Sopenharmony_ci#define	RTCMD_WRITESRAM		0x89
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci#define	RTCMD_NVRAMCONTROL	0x8a
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_ci#define	RTCMD_BYTESAVAIL	0x90
109141cc406Sopenharmony_ci#define	RTCMD_READBYTES		0x91
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci#define	RT_CHANNEL_ALL		0
112141cc406Sopenharmony_ci#define	RT_CHANNEL_RED		1
113141cc406Sopenharmony_ci#define	RT_CHANNEL_GREEN	2
114141cc406Sopenharmony_ci#define	RT_CHANNEL_BLUE		3
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_citypedef int (*rts8801_callback) (void *param, unsigned bytes, void *data);
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci#define DEBUG 1
119141cc406Sopenharmony_ci#define SCANNER_UNIT_TO_FIXED_MM(number) SANE_FIX(number * MM_PER_INCH / 1200)
120141cc406Sopenharmony_ci#define FIXED_MM_TO_SCANNER_UNIT(number) SANE_UNFIX(number) * 1200 / MM_PER_INCH
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci#define MSG_ERR         1
123141cc406Sopenharmony_ci#define MSG_USER        5
124141cc406Sopenharmony_ci#define MSG_INFO        6
125141cc406Sopenharmony_ci#define FLOW_CONTROL    10
126141cc406Sopenharmony_ci#define MSG_IO          15
127141cc406Sopenharmony_ci#define MSG_IO_READ     17
128141cc406Sopenharmony_ci#define IO_CMD          20
129141cc406Sopenharmony_ci#define IO_CMD_RES      20
130141cc406Sopenharmony_ci#define MSG_GET         25
131141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_cienum hp3500_option
134141cc406Sopenharmony_ci{
135141cc406Sopenharmony_ci  OPT_NUM_OPTS = 0,
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci  OPT_RESOLUTION,
138141cc406Sopenharmony_ci  OPT_GEOMETRY_GROUP,
139141cc406Sopenharmony_ci  OPT_TL_X,
140141cc406Sopenharmony_ci  OPT_TL_Y,
141141cc406Sopenharmony_ci  OPT_BR_X,
142141cc406Sopenharmony_ci  OPT_BR_Y,
143141cc406Sopenharmony_ci  OPT_MODE_GROUP,
144141cc406Sopenharmony_ci  OPT_MODE,
145141cc406Sopenharmony_ci  OPT_BRIGHTNESS,
146141cc406Sopenharmony_ci  OPT_CONTRAST,
147141cc406Sopenharmony_ci  OPT_GAMMA,
148141cc406Sopenharmony_ci
149141cc406Sopenharmony_ci  NUM_OPTIONS
150141cc406Sopenharmony_ci};
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_citypedef struct
153141cc406Sopenharmony_ci{
154141cc406Sopenharmony_ci  int left;
155141cc406Sopenharmony_ci  int top;
156141cc406Sopenharmony_ci  int right;
157141cc406Sopenharmony_ci  int bottom;
158141cc406Sopenharmony_ci} hp3500_rect;
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_cistruct hp3500_data
161141cc406Sopenharmony_ci{
162141cc406Sopenharmony_ci  struct hp3500_data *next;
163141cc406Sopenharmony_ci  char *devicename;
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_ci  int sfd;
166141cc406Sopenharmony_ci  int pipe_r;
167141cc406Sopenharmony_ci  int pipe_w;
168141cc406Sopenharmony_ci  SANE_Pid reader_pid;
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci  int resolution;
171141cc406Sopenharmony_ci  int mode;
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci  time_t last_scan;
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci  hp3500_rect request_mm;
176141cc406Sopenharmony_ci  hp3500_rect actual_mm;
177141cc406Sopenharmony_ci  hp3500_rect fullres_pixels;
178141cc406Sopenharmony_ci  hp3500_rect actres_pixels;
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci  int rounded_left;
181141cc406Sopenharmony_ci  int rounded_top;
182141cc406Sopenharmony_ci  int rounded_right;
183141cc406Sopenharmony_ci  int rounded_bottom;
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci  int bytes_per_scan_line;
186141cc406Sopenharmony_ci  int scan_width_pixels;
187141cc406Sopenharmony_ci  int scan_height_pixels;
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_ci  int brightness;
190141cc406Sopenharmony_ci  int contrast;
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  double gamma;
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci  SANE_Option_Descriptor opt[NUM_OPTIONS];
195141cc406Sopenharmony_ci  SANE_Device sane;
196141cc406Sopenharmony_ci};
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_cistruct hp3500_write_info
199141cc406Sopenharmony_ci{
200141cc406Sopenharmony_ci  struct hp3500_data *scanner;
201141cc406Sopenharmony_ci  int bytesleft;
202141cc406Sopenharmony_ci};
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_citypedef struct detailed_calibration_data
205141cc406Sopenharmony_ci{
206141cc406Sopenharmony_ci  unsigned char const *channeldata[3];
207141cc406Sopenharmony_ci  unsigned resolution_divisor;
208141cc406Sopenharmony_ci} detailed_calibration_data;
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_cistatic struct hp3500_data *first_dev = 0;
211141cc406Sopenharmony_cistatic struct hp3500_data **new_dev = &first_dev;
212141cc406Sopenharmony_cistatic int num_devices = 0;
213141cc406Sopenharmony_cistatic SANE_Int res_list[] =
214141cc406Sopenharmony_ci  { 9, 50, 75, 100, 150, 200, 300, 400, 600, 1200 };
215141cc406Sopenharmony_cistatic const SANE_Range range_x =
216141cc406Sopenharmony_ci  { 0, SANE_FIX (215.9), SANE_FIX (MM_PER_INCH / 1200) };
217141cc406Sopenharmony_cistatic const SANE_Range range_y =
218141cc406Sopenharmony_ci  { 0, SANE_FIX (298.7), SANE_FIX (MM_PER_INCH / 1200) };
219141cc406Sopenharmony_cistatic const SANE_Range range_brightness =
220141cc406Sopenharmony_ci  { 0, 255, 0 };
221141cc406Sopenharmony_cistatic const SANE_Range range_contrast =
222141cc406Sopenharmony_ci  { 0, 255, 0 };
223141cc406Sopenharmony_cistatic const SANE_Range range_gamma =
224141cc406Sopenharmony_ci  { SANE_FIX (0.2), SANE_FIX(4.0), SANE_FIX(0.01) };
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci#define HP3500_COLOR_SCAN 0
228141cc406Sopenharmony_ci#define HP3500_GRAY_SCAN 1
229141cc406Sopenharmony_ci#define	HP3500_LINEART_SCAN 2
230141cc406Sopenharmony_ci#define HP3500_TOTAL_SCANS 3
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_cistatic char const *scan_mode_list[HP3500_TOTAL_SCANS + 1] = { 0 };
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_cistatic SANE_Status attachScanner (const char *name);
235141cc406Sopenharmony_cistatic SANE_Status init_options (struct hp3500_data *scanner);
236141cc406Sopenharmony_cistatic int reader_process (void *);
237141cc406Sopenharmony_cistatic void calculateDerivedValues (struct hp3500_data *scanner);
238141cc406Sopenharmony_cistatic void do_reset (struct hp3500_data *scanner);
239141cc406Sopenharmony_cistatic void do_cancel (struct hp3500_data *scanner);
240141cc406Sopenharmony_cistatic size_t max_string_size(char const **);
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci/*
243141cc406Sopenharmony_ci * used by sane_get_devices
244141cc406Sopenharmony_ci */
245141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci/*
248141cc406Sopenharmony_ci * SANE Interface
249141cc406Sopenharmony_ci */
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci/**
253141cc406Sopenharmony_ci * Called by SANE initially.
254141cc406Sopenharmony_ci *
255141cc406Sopenharmony_ci * From the SANE spec:
256141cc406Sopenharmony_ci * This function must be called before any other SANE function can be
257141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this
258141cc406Sopenharmony_ci * function is not called first. The version code of the backend is
259141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer
260141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either
261141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires
262141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does
263141cc406Sopenharmony_ci * not support authentication.
264141cc406Sopenharmony_ci */
265141cc406Sopenharmony_ciSANE_Status
266141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
267141cc406Sopenharmony_ci{
268141cc406Sopenharmony_ci  (void) authorize;		/* get rid of compiler warning */
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci  DBG_INIT ();
271141cc406Sopenharmony_ci  DBG (10, "sane_init\n");
272141cc406Sopenharmony_ci
273141cc406Sopenharmony_ci  sanei_usb_init ();
274141cc406Sopenharmony_ci  sanei_thread_init ();
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_ci  if (version_code)
277141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci  sanei_usb_find_devices (0x03f0, 0x2205, attachScanner);
280141cc406Sopenharmony_ci  sanei_usb_find_devices (0x03f0, 0x2005, attachScanner);
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
283141cc406Sopenharmony_ci}
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci
286141cc406Sopenharmony_ci/**
287141cc406Sopenharmony_ci * Called by SANE to find out about supported devices.
288141cc406Sopenharmony_ci *
289141cc406Sopenharmony_ci * From the SANE spec:
290141cc406Sopenharmony_ci * This function can be used to query the list of devices that are
291141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a
292141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device
293141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to
294141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function
295141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This
296141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become
297141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are
298141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is
299141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote
300141cc406Sopenharmony_ci * devices that are accessible to the SANE library.
301141cc406Sopenharmony_ci *
302141cc406Sopenharmony_ci * SANE does not require that this function is called before a
303141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified
304141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and
305141cc406Sopenharmony_ci * undesirable to call this function first.
306141cc406Sopenharmony_ci */
307141cc406Sopenharmony_ciSANE_Status
308141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
309141cc406Sopenharmony_ci{
310141cc406Sopenharmony_ci  int i;
311141cc406Sopenharmony_ci  struct hp3500_data *dev;
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci  DBG (10, "sane_get_devices %d\n", local_only);
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  if (devlist)
316141cc406Sopenharmony_ci    free (devlist);
317141cc406Sopenharmony_ci  devlist = calloc (num_devices + 1, sizeof (SANE_Device *));
318141cc406Sopenharmony_ci  if (!devlist)
319141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  for (dev = first_dev, i = 0; i < num_devices; dev = dev->next)
322141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
323141cc406Sopenharmony_ci  devlist[i++] = 0;
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci  *device_list = devlist;
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
328141cc406Sopenharmony_ci}
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_ci/**
332141cc406Sopenharmony_ci * Called to establish connection with the scanner. This function will
333141cc406Sopenharmony_ci * also establish meaningful defaults and initialize the options.
334141cc406Sopenharmony_ci *
335141cc406Sopenharmony_ci * From the SANE spec:
336141cc406Sopenharmony_ci * This function is used to establish a connection to a particular
337141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument
338141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device
339141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length
340141cc406Sopenharmony_ci * string as the device requests opening the first available device
341141cc406Sopenharmony_ci * (if there is such a device).
342141cc406Sopenharmony_ci */
343141cc406Sopenharmony_ciSANE_Status
344141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle)
345141cc406Sopenharmony_ci{
346141cc406Sopenharmony_ci  struct hp3500_data *dev = NULL;
347141cc406Sopenharmony_ci  struct hp3500_data *scanner = NULL;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci  if (name[0] == 0)
350141cc406Sopenharmony_ci    {
351141cc406Sopenharmony_ci      DBG (10, "sane_open: no device requested, using default\n");
352141cc406Sopenharmony_ci      if (first_dev)
353141cc406Sopenharmony_ci	{
354141cc406Sopenharmony_ci	  scanner = (struct hp3500_data *) first_dev;
355141cc406Sopenharmony_ci	  DBG (10, "sane_open: device %s found\n", first_dev->sane.name);
356141cc406Sopenharmony_ci	}
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci  else
359141cc406Sopenharmony_ci    {
360141cc406Sopenharmony_ci      DBG (10, "sane_open: device %s requested\n", name);
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
363141cc406Sopenharmony_ci	{
364141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, name) == 0)
365141cc406Sopenharmony_ci	    {
366141cc406Sopenharmony_ci	      DBG (10, "sane_open: device %s found\n", name);
367141cc406Sopenharmony_ci	      scanner = (struct hp3500_data *) dev;
368141cc406Sopenharmony_ci	    }
369141cc406Sopenharmony_ci	}
370141cc406Sopenharmony_ci    }
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci  if (!scanner)
373141cc406Sopenharmony_ci    {
374141cc406Sopenharmony_ci      DBG (10, "sane_open: no device found\n");
375141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
376141cc406Sopenharmony_ci    }
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_ci  *handle = scanner;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  init_options (scanner);
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci  scanner->resolution = 200;
383141cc406Sopenharmony_ci  scanner->request_mm.left = 0;
384141cc406Sopenharmony_ci  scanner->request_mm.top = 0;
385141cc406Sopenharmony_ci  scanner->request_mm.right = SCANNER_UNIT_TO_FIXED_MM (10200);
386141cc406Sopenharmony_ci  scanner->request_mm.bottom = SCANNER_UNIT_TO_FIXED_MM (14100);
387141cc406Sopenharmony_ci  scanner->mode = 0;
388141cc406Sopenharmony_ci  scanner->brightness = 128;
389141cc406Sopenharmony_ci  scanner->contrast = 64;
390141cc406Sopenharmony_ci  scanner->gamma = 2.2;
391141cc406Sopenharmony_ci  calculateDerivedValues (scanner);
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci}
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci/**
399141cc406Sopenharmony_ci * An advanced method we don't support but have to define.
400141cc406Sopenharmony_ci */
401141cc406Sopenharmony_ciSANE_Status
402141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking)
403141cc406Sopenharmony_ci{
404141cc406Sopenharmony_ci  DBG (10, "sane_set_io_mode\n");
405141cc406Sopenharmony_ci  DBG (99, "%d %p\n", non_blocking, h);
406141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
407141cc406Sopenharmony_ci}
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci/**
411141cc406Sopenharmony_ci * An advanced method we don't support but have to define.
412141cc406Sopenharmony_ci */
413141cc406Sopenharmony_ciSANE_Status
414141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fdp)
415141cc406Sopenharmony_ci{
416141cc406Sopenharmony_ci  struct hp3500_data *scanner = (struct hp3500_data *) h;
417141cc406Sopenharmony_ci  DBG (10, "sane_get_select_fd\n");
418141cc406Sopenharmony_ci  *fdp = scanner->pipe_r;
419141cc406Sopenharmony_ci  DBG (99, "%p %d\n", h, *fdp);
420141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
421141cc406Sopenharmony_ci}
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci/**
425141cc406Sopenharmony_ci * Returns the options we know.
426141cc406Sopenharmony_ci *
427141cc406Sopenharmony_ci * From the SANE spec:
428141cc406Sopenharmony_ci * This function is used to access option descriptors. The function
429141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device
430141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a
431141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of
432141cc406Sopenharmony_ci * options that are available for device handle h (the count includes
433141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns
434141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid
435141cc406Sopenharmony_ci * (and at the returned address) until the device is closed.
436141cc406Sopenharmony_ci */
437141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
438141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
439141cc406Sopenharmony_ci{
440141cc406Sopenharmony_ci  struct hp3500_data *scanner = handle;
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci  DBG (MSG_GET,
443141cc406Sopenharmony_ci       "sane_get_option_descriptor: \"%s\"\n", scanner->opt[option].name);
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
446141cc406Sopenharmony_ci    return NULL;
447141cc406Sopenharmony_ci  return &scanner->opt[option];
448141cc406Sopenharmony_ci}
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci
451141cc406Sopenharmony_ci/**
452141cc406Sopenharmony_ci * Gets or sets an option value.
453141cc406Sopenharmony_ci *
454141cc406Sopenharmony_ci * From the SANE spec:
455141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option
456141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which
457141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The
458141cc406Sopenharmony_ci * possible values of this parameter are described in more detail
459141cc406Sopenharmony_ci * below.  The value of the option is passed through argument val. It
460141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory
461141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option
462141cc406Sopenharmony_ci * value (determined by member size in the corresponding option
463141cc406Sopenharmony_ci * descriptor).
464141cc406Sopenharmony_ci *
465141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a
466141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter
467141cc406Sopenharmony_ci * since the backend will stop reading the option value upon
468141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i
469141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how
470141cc406Sopenharmony_ci * well the request has been met.
471141cc406Sopenharmony_ci */
472141cc406Sopenharmony_ciSANE_Status
473141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
474141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
475141cc406Sopenharmony_ci{
476141cc406Sopenharmony_ci  struct hp3500_data *scanner = (struct hp3500_data *) handle;
477141cc406Sopenharmony_ci  SANE_Status status;
478141cc406Sopenharmony_ci  SANE_Word cap;
479141cc406Sopenharmony_ci  SANE_Int dummy;
480141cc406Sopenharmony_ci  int i;
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci  /* Make sure that all those statements involving *info cannot break (better
483141cc406Sopenharmony_ci   * than having to do "if (info) ..." everywhere!)
484141cc406Sopenharmony_ci   */
485141cc406Sopenharmony_ci  if (info == 0)
486141cc406Sopenharmony_ci    info = &dummy;
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci  *info = 0;
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
491141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
492141cc406Sopenharmony_ci
493141cc406Sopenharmony_ci  cap = scanner->opt[option].cap;
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci  /*
496141cc406Sopenharmony_ci   * SANE_ACTION_GET_VALUE: We have to find out the current setting and
497141cc406Sopenharmony_ci   * return it in a human-readable form (often, text).
498141cc406Sopenharmony_ci   */
499141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
500141cc406Sopenharmony_ci    {
501141cc406Sopenharmony_ci      DBG (MSG_GET, "sane_control_option: get value \"%s\"\n",
502141cc406Sopenharmony_ci	   scanner->opt[option].name);
503141cc406Sopenharmony_ci      DBG (11, "\tcap = %d\n", cap);
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_ACTIVE (cap))
506141cc406Sopenharmony_ci	{
507141cc406Sopenharmony_ci	  DBG (10, "\tinactive\n");
508141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
509141cc406Sopenharmony_ci	}
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci      switch (option)
512141cc406Sopenharmony_ci	{
513141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
514141cc406Sopenharmony_ci	  *(SANE_Word *) val = NUM_OPTIONS;
515141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci	case OPT_RESOLUTION:
518141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->resolution;
519141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci	case OPT_TL_X:
522141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->request_mm.left;
523141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci	case OPT_TL_Y:
526141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->request_mm.top;
527141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci	case OPT_BR_X:
530141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->request_mm.right;
531141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci	case OPT_BR_Y:
534141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->request_mm.bottom;
535141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci	case OPT_MODE:
538141cc406Sopenharmony_ci	  strcpy ((SANE_Char *) val, scan_mode_list[scanner->mode]);
539141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci	case OPT_CONTRAST:
542141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->contrast;
543141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci        case OPT_GAMMA:
546141cc406Sopenharmony_ci          *(SANE_Word *) val = SANE_FIX(scanner->gamma);
547141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
550141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->brightness;
551141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
552141cc406Sopenharmony_ci	}
553141cc406Sopenharmony_ci    }
554141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
555141cc406Sopenharmony_ci    {
556141cc406Sopenharmony_ci      DBG (10, "sane_control_option: set value \"%s\"\n",
557141cc406Sopenharmony_ci	   scanner->opt[option].name);
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_ACTIVE (cap))
560141cc406Sopenharmony_ci	{
561141cc406Sopenharmony_ci	  DBG (10, "\tinactive\n");
562141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
563141cc406Sopenharmony_ci	}
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
566141cc406Sopenharmony_ci	{
567141cc406Sopenharmony_ci	  DBG (10, "\tnot settable\n");
568141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
569141cc406Sopenharmony_ci	}
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci      status = sanei_constrain_value (scanner->opt + option, val, info);
572141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
573141cc406Sopenharmony_ci	{
574141cc406Sopenharmony_ci	  DBG (10, "\tbad value\n");
575141cc406Sopenharmony_ci	  return status;
576141cc406Sopenharmony_ci	}
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci      /*
579141cc406Sopenharmony_ci       * Note - for those options which can assume one of a list of
580141cc406Sopenharmony_ci       * valid values, we can safely assume that they will have
581141cc406Sopenharmony_ci       * exactly one of those values because that's what
582141cc406Sopenharmony_ci       * sanei_constrain_value does. Hence no "else: invalid" branches
583141cc406Sopenharmony_ci       * below.
584141cc406Sopenharmony_ci       */
585141cc406Sopenharmony_ci      switch (option)
586141cc406Sopenharmony_ci	{
587141cc406Sopenharmony_ci	case OPT_RESOLUTION:
588141cc406Sopenharmony_ci	  if (scanner->resolution == *(SANE_Word *) val)
589141cc406Sopenharmony_ci	    {
590141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;
591141cc406Sopenharmony_ci	    }
592141cc406Sopenharmony_ci	  scanner->resolution = (*(SANE_Word *) val);
593141cc406Sopenharmony_ci	  calculateDerivedValues (scanner);
594141cc406Sopenharmony_ci	  *info |= SANE_INFO_RELOAD_PARAMS;
595141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci	case OPT_TL_X:
598141cc406Sopenharmony_ci	  if (scanner->request_mm.left == *(SANE_Word *) val)
599141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
600141cc406Sopenharmony_ci	  scanner->request_mm.left = *(SANE_Word *) val;
601141cc406Sopenharmony_ci	  calculateDerivedValues (scanner);
602141cc406Sopenharmony_ci	  if (scanner->actual_mm.left != scanner->request_mm.left)
603141cc406Sopenharmony_ci	    *info |= SANE_INFO_INEXACT;
604141cc406Sopenharmony_ci	  *info |= SANE_INFO_RELOAD_PARAMS;
605141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci	case OPT_TL_Y:
608141cc406Sopenharmony_ci	  if (scanner->request_mm.top == *(SANE_Word *) val)
609141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
610141cc406Sopenharmony_ci	  scanner->request_mm.top = *(SANE_Word *) val;
611141cc406Sopenharmony_ci	  calculateDerivedValues (scanner);
612141cc406Sopenharmony_ci	  if (scanner->actual_mm.top != scanner->request_mm.top)
613141cc406Sopenharmony_ci	    *info |= SANE_INFO_INEXACT;
614141cc406Sopenharmony_ci	  *info |= SANE_INFO_RELOAD_PARAMS;
615141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci	case OPT_BR_X:
618141cc406Sopenharmony_ci	  if (scanner->request_mm.right == *(SANE_Word *) val)
619141cc406Sopenharmony_ci	    {
620141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;
621141cc406Sopenharmony_ci	    }
622141cc406Sopenharmony_ci	  scanner->request_mm.right = *(SANE_Word *) val;
623141cc406Sopenharmony_ci	  calculateDerivedValues (scanner);
624141cc406Sopenharmony_ci	  if (scanner->actual_mm.right != scanner->request_mm.right)
625141cc406Sopenharmony_ci	    *info |= SANE_INFO_INEXACT;
626141cc406Sopenharmony_ci	  *info |= SANE_INFO_RELOAD_PARAMS;
627141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci	case OPT_BR_Y:
630141cc406Sopenharmony_ci	  if (scanner->request_mm.bottom == *(SANE_Word *) val)
631141cc406Sopenharmony_ci	    {
632141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;
633141cc406Sopenharmony_ci	    }
634141cc406Sopenharmony_ci	  scanner->request_mm.bottom = *(SANE_Word *) val;
635141cc406Sopenharmony_ci	  calculateDerivedValues (scanner);
636141cc406Sopenharmony_ci	  if (scanner->actual_mm.bottom != scanner->request_mm.bottom)
637141cc406Sopenharmony_ci	    *info |= SANE_INFO_INEXACT;
638141cc406Sopenharmony_ci	  *info |= SANE_INFO_RELOAD_PARAMS;
639141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ci	case OPT_MODE:
642141cc406Sopenharmony_ci	  for (i = 0; scan_mode_list[i]; ++i)
643141cc406Sopenharmony_ci	    {
644141cc406Sopenharmony_ci	      if (!strcmp ((SANE_Char const *) val, scan_mode_list[i]))
645141cc406Sopenharmony_ci		{
646141cc406Sopenharmony_ci		  DBG (10, "Setting scan mode to %s (request: %s)\n",
647141cc406Sopenharmony_ci		       scan_mode_list[i], (SANE_Char const *) val);
648141cc406Sopenharmony_ci		  scanner->mode = i;
649141cc406Sopenharmony_ci		  return SANE_STATUS_GOOD;
650141cc406Sopenharmony_ci		}
651141cc406Sopenharmony_ci	    }
652141cc406Sopenharmony_ci	  /* Impossible */
653141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
656141cc406Sopenharmony_ci	  scanner->brightness = *(SANE_Word *) val;
657141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci	case OPT_CONTRAST:
660141cc406Sopenharmony_ci	  scanner->contrast = *(SANE_Word *) val;
661141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci        case OPT_GAMMA:
664141cc406Sopenharmony_ci          scanner->gamma = SANE_UNFIX(*(SANE_Word *) val);
665141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
666141cc406Sopenharmony_ci	}			/* switch */
667141cc406Sopenharmony_ci    }				/* else */
668141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
669141cc406Sopenharmony_ci}
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci/**
672141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started.
673141cc406Sopenharmony_ci *
674141cc406Sopenharmony_ci */
675141cc406Sopenharmony_ciSANE_Status
676141cc406Sopenharmony_cisane_start (SANE_Handle handle)
677141cc406Sopenharmony_ci{
678141cc406Sopenharmony_ci  struct hp3500_data *scanner = handle;
679141cc406Sopenharmony_ci  int defaultFds[2];
680141cc406Sopenharmony_ci  int ret;
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  DBG (10, "sane_start\n");
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci  if (scanner->sfd < 0)
685141cc406Sopenharmony_ci    {
686141cc406Sopenharmony_ci      /* first call */
687141cc406Sopenharmony_ci      DBG (10, "sane_start opening USB device\n");
688141cc406Sopenharmony_ci      if (sanei_usb_open (scanner->sane.name, &(scanner->sfd)) !=
689141cc406Sopenharmony_ci	  SANE_STATUS_GOOD)
690141cc406Sopenharmony_ci	{
691141cc406Sopenharmony_ci	  DBG (MSG_ERR,
692141cc406Sopenharmony_ci	       "sane_start: open of %s failed:\n", scanner->sane.name);
693141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
694141cc406Sopenharmony_ci	}
695141cc406Sopenharmony_ci    }
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci  calculateDerivedValues (scanner);
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci  DBG (10, "\tbytes per line = %d\n", scanner->bytes_per_scan_line);
700141cc406Sopenharmony_ci  DBG (10, "\tpixels_per_line = %d\n", scanner->scan_width_pixels);
701141cc406Sopenharmony_ci  DBG (10, "\tlines = %d\n", scanner->scan_height_pixels);
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci
704141cc406Sopenharmony_ci  /* create a pipe, fds[0]=read-fd, fds[1]=write-fd */
705141cc406Sopenharmony_ci  if (pipe (defaultFds) < 0)
706141cc406Sopenharmony_ci    {
707141cc406Sopenharmony_ci      DBG (MSG_ERR, "ERROR: could not create pipe\n");
708141cc406Sopenharmony_ci      do_cancel (scanner);
709141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
710141cc406Sopenharmony_ci    }
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  scanner->pipe_r = defaultFds[0];
713141cc406Sopenharmony_ci  scanner->pipe_w = defaultFds[1];
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  ret = SANE_STATUS_GOOD;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  scanner->reader_pid = sanei_thread_begin (reader_process, scanner);
718141cc406Sopenharmony_ci  time (&scanner->last_scan);
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (scanner->reader_pid))
721141cc406Sopenharmony_ci    {
722141cc406Sopenharmony_ci      DBG (MSG_ERR, "cannot fork reader process.\n");
723141cc406Sopenharmony_ci      DBG (MSG_ERR, "%s", strerror (errno));
724141cc406Sopenharmony_ci      ret = SANE_STATUS_IO_ERROR;
725141cc406Sopenharmony_ci    }
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
728141cc406Sopenharmony_ci    {
729141cc406Sopenharmony_ci      close (scanner->pipe_w);
730141cc406Sopenharmony_ci    }
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci  if (ret == SANE_STATUS_GOOD)
733141cc406Sopenharmony_ci    {
734141cc406Sopenharmony_ci      DBG (10, "sane_start: ok\n");
735141cc406Sopenharmony_ci    }
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_ci  return ret;
738141cc406Sopenharmony_ci}
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci/**
742141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data
743141cc406Sopenharmony_ci * that the current scan will return.
744141cc406Sopenharmony_ci *
745141cc406Sopenharmony_ci * From the SANE spec:
746141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The
747141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time
748141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the
749141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned
750141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be
751141cc406Sopenharmony_ci * when sane_start() gets invoked.
752141cc406Sopenharmony_ci *
753141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows,
754141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will
755141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle h of the
756141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer p
757141cc406Sopenharmony_ci * to a parameter structure.
758141cc406Sopenharmony_ci */
759141cc406Sopenharmony_ciSANE_Status
760141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
761141cc406Sopenharmony_ci{
762141cc406Sopenharmony_ci  struct hp3500_data *scanner = (struct hp3500_data *) handle;
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters\n");
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci  calculateDerivedValues (scanner);
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci  params->format =
770141cc406Sopenharmony_ci    (scanner->mode == HP3500_COLOR_SCAN) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
771141cc406Sopenharmony_ci  params->depth = (scanner->mode == HP3500_LINEART_SCAN) ? 1 : 8;
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci  params->pixels_per_line = scanner->scan_width_pixels;
774141cc406Sopenharmony_ci  params->lines = scanner->scan_height_pixels;
775141cc406Sopenharmony_ci
776141cc406Sopenharmony_ci  params->bytes_per_line = scanner->bytes_per_scan_line;
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci  params->last_frame = 1;
779141cc406Sopenharmony_ci  DBG (10, "\tdepth %d\n", params->depth);
780141cc406Sopenharmony_ci  DBG (10, "\tlines %d\n", params->lines);
781141cc406Sopenharmony_ci  DBG (10, "\tpixels_per_line %d\n", params->pixels_per_line);
782141cc406Sopenharmony_ci  DBG (10, "\tbytes_per_line %d\n", params->bytes_per_line);
783141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
784141cc406Sopenharmony_ci}
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci/**
788141cc406Sopenharmony_ci * Called by SANE to read data.
789141cc406Sopenharmony_ci *
790141cc406Sopenharmony_ci * In this implementation, sane_read does nothing much besides reading
791141cc406Sopenharmony_ci * data from a pipe and handing it back. On the other end of the pipe
792141cc406Sopenharmony_ci * there's the reader process which gets data from the scanner and
793141cc406Sopenharmony_ci * stuffs it into the pipe.
794141cc406Sopenharmony_ci *
795141cc406Sopenharmony_ci * From the SANE spec:
796141cc406Sopenharmony_ci * This function is used to read image data from the device
797141cc406Sopenharmony_ci * represented by handle h.  Argument buf is a pointer to a memory
798141cc406Sopenharmony_ci * area that is at least maxlen bytes long.  The number of bytes
799141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when
800141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is
801141cc406Sopenharmony_ci * returned).
802141cc406Sopenharmony_ci *
803141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be
804141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes.
805141cc406Sopenharmony_ci */
806141cc406Sopenharmony_ciSANE_Status
807141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
808141cc406Sopenharmony_ci	   SANE_Int max_len, SANE_Int * len)
809141cc406Sopenharmony_ci{
810141cc406Sopenharmony_ci  struct hp3500_data *scanner = (struct hp3500_data *) handle;
811141cc406Sopenharmony_ci  ssize_t nread;
812141cc406Sopenharmony_ci  int source = scanner->pipe_r;
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci  *len = 0;
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci  nread = read (source, buf, max_len);
817141cc406Sopenharmony_ci  DBG (30, "sane_read: read %ld bytes of %ld\n",
818141cc406Sopenharmony_ci       (long) nread, (long) max_len);
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_ci  if (nread < 0)
821141cc406Sopenharmony_ci    {
822141cc406Sopenharmony_ci      if (errno == EAGAIN)
823141cc406Sopenharmony_ci	{
824141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
825141cc406Sopenharmony_ci	}
826141cc406Sopenharmony_ci      else
827141cc406Sopenharmony_ci	{
828141cc406Sopenharmony_ci	  do_cancel (scanner);
829141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
830141cc406Sopenharmony_ci	}
831141cc406Sopenharmony_ci    }
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  *len = nread;
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_ci  if (nread == 0)
836141cc406Sopenharmony_ci    {
837141cc406Sopenharmony_ci      close (source);
838141cc406Sopenharmony_ci      DBG (10, "sane_read: pipe closed\n");
839141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
840141cc406Sopenharmony_ci    }
841141cc406Sopenharmony_ci
842141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
843141cc406Sopenharmony_ci}				/* sane_read */
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci/**
847141cc406Sopenharmony_ci * Cancels a scan.
848141cc406Sopenharmony_ci *
849141cc406Sopenharmony_ci * It has been said on the mailing list that sane_cancel is a bit of a
850141cc406Sopenharmony_ci * misnomer because it is routinely called to signal the end of a
851141cc406Sopenharmony_ci * batch - quoting David Mosberger-Tang:
852141cc406Sopenharmony_ci *
853141cc406Sopenharmony_ci * > In other words, the idea is to have sane_start() be called, and
854141cc406Sopenharmony_ci * > collect as many images as the frontend wants (which could in turn
855141cc406Sopenharmony_ci * > consist of multiple frames each as indicated by frame-type) and
856141cc406Sopenharmony_ci * > when the frontend is done, it should call sane_cancel().
857141cc406Sopenharmony_ci * > Sometimes it's better to think of sane_cancel() as "sane_stop()"
858141cc406Sopenharmony_ci * > but that name would have had some misleading connotations as
859141cc406Sopenharmony_ci * > well, that's why we stuck with "cancel".
860141cc406Sopenharmony_ci *
861141cc406Sopenharmony_ci * The current consensus regarding duplex and ADF scans seems to be
862141cc406Sopenharmony_ci * the following call sequence: sane_start; sane_read (repeat until
863141cc406Sopenharmony_ci * EOF); sane_start; sane_read...  and then call sane_cancel if the
864141cc406Sopenharmony_ci * batch is at an end. I.e. do not call sane_cancel during the run but
865141cc406Sopenharmony_ci * as soon as you get a SANE_STATUS_NO_DOCS.
866141cc406Sopenharmony_ci *
867141cc406Sopenharmony_ci * From the SANE spec:
868141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible
869141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by
870141cc406Sopenharmony_ci * handle h.  This function can be called at any time (as long as
871141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running
872141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call
873141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler).
874141cc406Sopenharmony_ci * It is important to note that completion of this operation does not
875141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It
876141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation
877141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a
878141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED).  Since the SANE API does
879141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies
880141cc406Sopenharmony_ci * that a frontend must not call any other operation until the
881141cc406Sopenharmony_ci * cancelled operation has returned.
882141cc406Sopenharmony_ci */
883141cc406Sopenharmony_civoid
884141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
885141cc406Sopenharmony_ci{
886141cc406Sopenharmony_ci  DBG (10, "sane_cancel\n");
887141cc406Sopenharmony_ci  do_cancel ((struct hp3500_data *) h);
888141cc406Sopenharmony_ci}
889141cc406Sopenharmony_ci
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci/**
892141cc406Sopenharmony_ci * Ends use of the scanner.
893141cc406Sopenharmony_ci *
894141cc406Sopenharmony_ci * From the SANE spec:
895141cc406Sopenharmony_ci * This function terminates the association between the device handle
896141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is
897141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After
898141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore.
899141cc406Sopenharmony_ci */
900141cc406Sopenharmony_civoid
901141cc406Sopenharmony_cisane_close (SANE_Handle handle)
902141cc406Sopenharmony_ci{
903141cc406Sopenharmony_ci  DBG (10, "sane_close\n");
904141cc406Sopenharmony_ci  do_reset (handle);
905141cc406Sopenharmony_ci  do_cancel (handle);
906141cc406Sopenharmony_ci}
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci/**
910141cc406Sopenharmony_ci * Terminates the backend.
911141cc406Sopenharmony_ci *
912141cc406Sopenharmony_ci * From the SANE spec:
913141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The
914141cc406Sopenharmony_ci * function will first close all device handles that still might be
915141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through
916141cc406Sopenharmony_ci * a call to sane_clo-se(), but backends are required to release all
917141cc406Sopenharmony_ci * resources upon a call to this function). After this function
918141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called
919141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting
920141cc406Sopenharmony_ci * to call this function may result in some resources not being
921141cc406Sopenharmony_ci * released properly.
922141cc406Sopenharmony_ci */
923141cc406Sopenharmony_civoid
924141cc406Sopenharmony_cisane_exit (void)
925141cc406Sopenharmony_ci{
926141cc406Sopenharmony_ci  struct hp3500_data *dev, *next;
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci  DBG (10, "sane_exit\n");
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
931141cc406Sopenharmony_ci    {
932141cc406Sopenharmony_ci      next = dev->next;
933141cc406Sopenharmony_ci      free (dev->devicename);
934141cc406Sopenharmony_ci      free (dev);
935141cc406Sopenharmony_ci    }
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci  if (devlist)
938141cc406Sopenharmony_ci    free (devlist);
939141cc406Sopenharmony_ci}
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci/*
942141cc406Sopenharmony_ci * The scanning code
943141cc406Sopenharmony_ci */
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_cistatic SANE_Status
946141cc406Sopenharmony_ciattachScanner (const char *devicename)
947141cc406Sopenharmony_ci{
948141cc406Sopenharmony_ci  struct hp3500_data *dev;
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci  DBG (15, "attach_scanner: %s\n", devicename);
951141cc406Sopenharmony_ci
952141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
953141cc406Sopenharmony_ci    {
954141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
955141cc406Sopenharmony_ci	{
956141cc406Sopenharmony_ci	  DBG (5, "attach_scanner: scanner already attached (is ok)!\n");
957141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
958141cc406Sopenharmony_ci	}
959141cc406Sopenharmony_ci    }
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci  if (NULL == (dev = malloc (sizeof (*dev))))
963141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
964141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
967141cc406Sopenharmony_ci  dev->sfd = -1;
968141cc406Sopenharmony_ci  dev->last_scan = 0;
969141cc406Sopenharmony_ci  dev->reader_pid = (SANE_Pid) -1;
970141cc406Sopenharmony_ci  dev->pipe_r = dev->pipe_w = -1;
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
973141cc406Sopenharmony_ci  dev->sane.vendor = "Hewlett-Packard";
974141cc406Sopenharmony_ci  dev->sane.model = "ScanJet 3500";
975141cc406Sopenharmony_ci  dev->sane.type = "scanner";
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci  ++num_devices;
978141cc406Sopenharmony_ci  *new_dev = dev;
979141cc406Sopenharmony_ci
980141cc406Sopenharmony_ci  DBG (15, "attach_scanner: done\n");
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
983141cc406Sopenharmony_ci}
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_cistatic SANE_Status
986141cc406Sopenharmony_ciinit_options (struct hp3500_data *scanner)
987141cc406Sopenharmony_ci{
988141cc406Sopenharmony_ci  int i;
989141cc406Sopenharmony_ci  SANE_Option_Descriptor *opt;
990141cc406Sopenharmony_ci
991141cc406Sopenharmony_ci  memset (scanner->opt, 0, sizeof (scanner->opt));
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
994141cc406Sopenharmony_ci    {
995141cc406Sopenharmony_ci      scanner->opt[i].name = "filler";
996141cc406Sopenharmony_ci      scanner->opt[i].size = sizeof (SANE_Word);
997141cc406Sopenharmony_ci      scanner->opt[i].cap = SANE_CAP_INACTIVE;
998141cc406Sopenharmony_ci    }
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci  opt = scanner->opt + OPT_NUM_OPTS;
1001141cc406Sopenharmony_ci  opt->title = SANE_TITLE_NUM_OPTIONS;
1002141cc406Sopenharmony_ci  opt->desc = SANE_DESC_NUM_OPTIONS;
1003141cc406Sopenharmony_ci  opt->type = SANE_TYPE_INT;
1004141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_DETECT;
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci  opt = scanner->opt + OPT_RESOLUTION;
1007141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_RESOLUTION;
1008141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_RESOLUTION;
1009141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_RESOLUTION;
1010141cc406Sopenharmony_ci  opt->type = SANE_TYPE_INT;
1011141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_WORD_LIST;
1012141cc406Sopenharmony_ci  opt->constraint.word_list = res_list;
1013141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_DPI;
1014141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  opt = scanner->opt + OPT_GEOMETRY_GROUP;
1017141cc406Sopenharmony_ci  opt->title = SANE_I18N ("Geometry");
1018141cc406Sopenharmony_ci  opt->desc = SANE_I18N ("Geometry Group");
1019141cc406Sopenharmony_ci  opt->type = SANE_TYPE_GROUP;
1020141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_NONE;
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci  opt = scanner->opt + OPT_TL_X;
1023141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_TL_X;
1024141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_TL_X;
1025141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_TL_X;
1026141cc406Sopenharmony_ci  opt->type = SANE_TYPE_FIXED;
1027141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_MM;
1028141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1029141cc406Sopenharmony_ci  opt->constraint.range = &range_x;
1030141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1031141cc406Sopenharmony_ci
1032141cc406Sopenharmony_ci  opt = scanner->opt + OPT_TL_Y;
1033141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_TL_Y;
1034141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_TL_Y;
1035141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_TL_Y;
1036141cc406Sopenharmony_ci  opt->type = SANE_TYPE_FIXED;
1037141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_MM;
1038141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1039141cc406Sopenharmony_ci  opt->constraint.range = &range_y;
1040141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1041141cc406Sopenharmony_ci
1042141cc406Sopenharmony_ci  opt = scanner->opt + OPT_BR_X;
1043141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_BR_X;
1044141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_BR_X;
1045141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_BR_X;
1046141cc406Sopenharmony_ci  opt->type = SANE_TYPE_FIXED;
1047141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_MM;
1048141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1049141cc406Sopenharmony_ci  opt->constraint.range = &range_x;
1050141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci  opt = scanner->opt + OPT_BR_Y;
1053141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_BR_Y;
1054141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_BR_Y;
1055141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_BR_Y;
1056141cc406Sopenharmony_ci  opt->type = SANE_TYPE_FIXED;
1057141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_MM;
1058141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1059141cc406Sopenharmony_ci  opt->constraint.range = &range_y;
1060141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci  if (!scan_mode_list[0])
1063141cc406Sopenharmony_ci    {
1064141cc406Sopenharmony_ci      scan_mode_list[HP3500_COLOR_SCAN] = SANE_VALUE_SCAN_MODE_COLOR;
1065141cc406Sopenharmony_ci      scan_mode_list[HP3500_GRAY_SCAN] = SANE_VALUE_SCAN_MODE_GRAY;
1066141cc406Sopenharmony_ci      scan_mode_list[HP3500_LINEART_SCAN] = SANE_VALUE_SCAN_MODE_LINEART;
1067141cc406Sopenharmony_ci      scan_mode_list[HP3500_TOTAL_SCANS] = 0;
1068141cc406Sopenharmony_ci    }
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci  opt = scanner->opt + OPT_MODE_GROUP;
1071141cc406Sopenharmony_ci  opt->title = SANE_I18N ("Scan Mode Group");
1072141cc406Sopenharmony_ci  opt->desc = SANE_I18N ("Scan Mode Group");
1073141cc406Sopenharmony_ci  opt->type = SANE_TYPE_GROUP;
1074141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_NONE;
1075141cc406Sopenharmony_ci
1076141cc406Sopenharmony_ci  opt = scanner->opt + OPT_MODE;
1077141cc406Sopenharmony_ci  opt->name = SANE_NAME_SCAN_MODE;
1078141cc406Sopenharmony_ci  opt->title = SANE_TITLE_SCAN_MODE;
1079141cc406Sopenharmony_ci  opt->desc = SANE_DESC_SCAN_MODE;
1080141cc406Sopenharmony_ci  opt->type = SANE_TYPE_STRING;
1081141cc406Sopenharmony_ci  opt->size = max_string_size(scan_mode_list);
1082141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_STRING_LIST;
1083141cc406Sopenharmony_ci  opt->constraint.string_list = (SANE_String_Const *) scan_mode_list;
1084141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci  opt = scanner->opt + OPT_BRIGHTNESS;
1087141cc406Sopenharmony_ci  opt->name = SANE_NAME_BRIGHTNESS;
1088141cc406Sopenharmony_ci  opt->title = SANE_TITLE_BRIGHTNESS;
1089141cc406Sopenharmony_ci  opt->desc = SANE_DESC_BRIGHTNESS;
1090141cc406Sopenharmony_ci  opt->type = SANE_TYPE_INT;
1091141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1092141cc406Sopenharmony_ci  opt->constraint.range = &range_brightness;
1093141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci  opt = scanner->opt + OPT_CONTRAST;
1096141cc406Sopenharmony_ci  opt->name = SANE_NAME_CONTRAST;
1097141cc406Sopenharmony_ci  opt->title = SANE_TITLE_CONTRAST;
1098141cc406Sopenharmony_ci  opt->desc = SANE_DESC_CONTRAST;
1099141cc406Sopenharmony_ci  opt->type = SANE_TYPE_INT;
1100141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1101141cc406Sopenharmony_ci  opt->constraint.range = &range_contrast;
1102141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1103141cc406Sopenharmony_ci
1104141cc406Sopenharmony_ci  opt = scanner->opt + OPT_GAMMA;
1105141cc406Sopenharmony_ci  opt->name = SANE_NAME_ANALOG_GAMMA;
1106141cc406Sopenharmony_ci  opt->title = SANE_TITLE_ANALOG_GAMMA;
1107141cc406Sopenharmony_ci  opt->desc = SANE_DESC_ANALOG_GAMMA;
1108141cc406Sopenharmony_ci  opt->type = SANE_TYPE_FIXED;
1109141cc406Sopenharmony_ci  opt->unit = SANE_UNIT_NONE;
1110141cc406Sopenharmony_ci  opt->constraint_type = SANE_CONSTRAINT_RANGE;
1111141cc406Sopenharmony_ci  opt->constraint.range = &range_gamma;
1112141cc406Sopenharmony_ci  opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1113141cc406Sopenharmony_ci
1114141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1115141cc406Sopenharmony_ci}
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_cistatic void
1118141cc406Sopenharmony_cido_reset (struct hp3500_data *scanner)
1119141cc406Sopenharmony_ci{
1120141cc406Sopenharmony_ci  (void) scanner;		/* kill warning */
1121141cc406Sopenharmony_ci}
1122141cc406Sopenharmony_ci
1123141cc406Sopenharmony_cistatic void
1124141cc406Sopenharmony_cido_cancel (struct hp3500_data *scanner)
1125141cc406Sopenharmony_ci{
1126141cc406Sopenharmony_ci  if (sanei_thread_is_valid (scanner->reader_pid))
1127141cc406Sopenharmony_ci    {
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci      if (sanei_thread_kill (scanner->reader_pid) == 0)
1130141cc406Sopenharmony_ci	{
1131141cc406Sopenharmony_ci	  int exit_status;
1132141cc406Sopenharmony_ci
1133141cc406Sopenharmony_ci	  sanei_thread_waitpid (scanner->reader_pid, &exit_status);
1134141cc406Sopenharmony_ci	}
1135141cc406Sopenharmony_ci      sanei_thread_invalidate (scanner->reader_pid);
1136141cc406Sopenharmony_ci    }
1137141cc406Sopenharmony_ci  if (scanner->pipe_r >= 0)
1138141cc406Sopenharmony_ci    {
1139141cc406Sopenharmony_ci      close (scanner->pipe_r);
1140141cc406Sopenharmony_ci      scanner->pipe_r = -1;
1141141cc406Sopenharmony_ci    }
1142141cc406Sopenharmony_ci}
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_cistatic void
1145141cc406Sopenharmony_cicalculateDerivedValues (struct hp3500_data *scanner)
1146141cc406Sopenharmony_ci{
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci  DBG (12, "calculateDerivedValues\n");
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_ci  /* Convert the SANE_FIXED values for the scan area into 1/1200 inch
1151141cc406Sopenharmony_ci   * scanner units */
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci  scanner->fullres_pixels.left =
1154141cc406Sopenharmony_ci    FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.left);
1155141cc406Sopenharmony_ci  scanner->fullres_pixels.top =
1156141cc406Sopenharmony_ci    FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.top);
1157141cc406Sopenharmony_ci  scanner->fullres_pixels.right =
1158141cc406Sopenharmony_ci    FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.right);
1159141cc406Sopenharmony_ci  scanner->fullres_pixels.bottom =
1160141cc406Sopenharmony_ci    FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.bottom);
1161141cc406Sopenharmony_ci
1162141cc406Sopenharmony_ci  DBG (12, "\tleft margin: %u\n", scanner->fullres_pixels.left);
1163141cc406Sopenharmony_ci  DBG (12, "\ttop margin: %u\n", scanner->fullres_pixels.top);
1164141cc406Sopenharmony_ci  DBG (12, "\tright margin: %u\n", scanner->fullres_pixels.right);
1165141cc406Sopenharmony_ci  DBG (12, "\tbottom margin: %u\n", scanner->fullres_pixels.bottom);
1166141cc406Sopenharmony_ci
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci  scanner->scan_width_pixels =
1169141cc406Sopenharmony_ci    scanner->resolution * (scanner->fullres_pixels.right -
1170141cc406Sopenharmony_ci			   scanner->fullres_pixels.left) / 1200;
1171141cc406Sopenharmony_ci  scanner->scan_height_pixels =
1172141cc406Sopenharmony_ci    scanner->resolution * (scanner->fullres_pixels.bottom -
1173141cc406Sopenharmony_ci			   scanner->fullres_pixels.top) / 1200;
1174141cc406Sopenharmony_ci  if (scanner->mode == HP3500_LINEART_SCAN)
1175141cc406Sopenharmony_ci    scanner->bytes_per_scan_line = (scanner->scan_width_pixels + 7) / 8;
1176141cc406Sopenharmony_ci  else if (scanner->mode == HP3500_GRAY_SCAN)
1177141cc406Sopenharmony_ci    scanner->bytes_per_scan_line = scanner->scan_width_pixels;
1178141cc406Sopenharmony_ci  else
1179141cc406Sopenharmony_ci    scanner->bytes_per_scan_line = scanner->scan_width_pixels * 3;
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci  if (scanner->scan_width_pixels < 1)
1182141cc406Sopenharmony_ci    scanner->scan_width_pixels = 1;
1183141cc406Sopenharmony_ci  if (scanner->scan_height_pixels < 1)
1184141cc406Sopenharmony_ci    scanner->scan_height_pixels = 1;
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci  scanner->actres_pixels.left =
1187141cc406Sopenharmony_ci    scanner->fullres_pixels.left * scanner->resolution / 1200;
1188141cc406Sopenharmony_ci  scanner->actres_pixels.top =
1189141cc406Sopenharmony_ci    scanner->fullres_pixels.top * scanner->resolution / 1200;
1190141cc406Sopenharmony_ci  scanner->actres_pixels.right =
1191141cc406Sopenharmony_ci    scanner->actres_pixels.left + scanner->scan_width_pixels;
1192141cc406Sopenharmony_ci  scanner->actres_pixels.bottom =
1193141cc406Sopenharmony_ci    scanner->actres_pixels.top + scanner->scan_height_pixels;
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci  scanner->actual_mm.left =
1196141cc406Sopenharmony_ci    SCANNER_UNIT_TO_FIXED_MM (scanner->fullres_pixels.left);
1197141cc406Sopenharmony_ci  scanner->actual_mm.top =
1198141cc406Sopenharmony_ci    SCANNER_UNIT_TO_FIXED_MM (scanner->fullres_pixels.top);
1199141cc406Sopenharmony_ci  scanner->actual_mm.bottom =
1200141cc406Sopenharmony_ci    SCANNER_UNIT_TO_FIXED_MM (scanner->scan_width_pixels * 1200 /
1201141cc406Sopenharmony_ci			      scanner->resolution);
1202141cc406Sopenharmony_ci  scanner->actual_mm.right =
1203141cc406Sopenharmony_ci    SCANNER_UNIT_TO_FIXED_MM (scanner->scan_height_pixels * 1200 /
1204141cc406Sopenharmony_ci			      scanner->resolution);
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci  DBG (12, "calculateDerivedValues: ok\n");
1207141cc406Sopenharmony_ci}
1208141cc406Sopenharmony_ci
1209141cc406Sopenharmony_ci/* From here on in we have the original code written for the scanner demo */
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci#define	MAX_COMMANDS_BYTES	131072
1212141cc406Sopenharmony_ci#define	MAX_READ_COMMANDS	1	/* Issuing more than one register
1213141cc406Sopenharmony_ci					 * read command in a single request
1214141cc406Sopenharmony_ci					 * seems to put the device in an
1215141cc406Sopenharmony_ci					 * unpredictable state.
1216141cc406Sopenharmony_ci					 */
1217141cc406Sopenharmony_ci#define	MAX_READ_BYTES		0xffc0
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci#define	REG_DESTINATION_POSITION 0x60
1220141cc406Sopenharmony_ci#define	REG_MOVE_CONTROL_TEST	0xb3
1221141cc406Sopenharmony_ci
1222141cc406Sopenharmony_cistatic int command_reads_outstanding = 0;
1223141cc406Sopenharmony_cistatic int command_bytes_outstanding = 0;
1224141cc406Sopenharmony_cistatic unsigned char command_buffer[MAX_COMMANDS_BYTES];
1225141cc406Sopenharmony_cistatic int receive_bytes_outstanding = 0;
1226141cc406Sopenharmony_cistatic char *command_readmem_outstanding[MAX_READ_COMMANDS];
1227141cc406Sopenharmony_cistatic int command_readbytes_outstanding[MAX_READ_COMMANDS];
1228141cc406Sopenharmony_cistatic unsigned char sram_access_method = 0;
1229141cc406Sopenharmony_cistatic unsigned sram_size = 0;
1230141cc406Sopenharmony_cistatic int udh;
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_cistatic int
1233141cc406Sopenharmony_cirt_execute_commands (void)
1234141cc406Sopenharmony_ci{
1235141cc406Sopenharmony_ci  SANE_Status result;
1236141cc406Sopenharmony_ci  size_t bytes;
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci  if (!command_bytes_outstanding)
1239141cc406Sopenharmony_ci    return 0;
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci  bytes = command_bytes_outstanding;
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci  result = sanei_usb_write_bulk (udh, /* 0x02, */ command_buffer, &bytes);
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci  if (result == SANE_STATUS_GOOD && receive_bytes_outstanding)
1246141cc406Sopenharmony_ci    {
1247141cc406Sopenharmony_ci      unsigned char readbuf[MAX_READ_BYTES];
1248141cc406Sopenharmony_ci      int total_read = 0;
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci      do
1251141cc406Sopenharmony_ci	{
1252141cc406Sopenharmony_ci	  bytes = receive_bytes_outstanding - total_read;
1253141cc406Sopenharmony_ci	  result = sanei_usb_read_bulk (udh,
1254141cc406Sopenharmony_ci					/* 0x81, */
1255141cc406Sopenharmony_ci					readbuf + total_read, &bytes);
1256141cc406Sopenharmony_ci	  if (result == SANE_STATUS_GOOD)
1257141cc406Sopenharmony_ci	    total_read += bytes;
1258141cc406Sopenharmony_ci	  else
1259141cc406Sopenharmony_ci	    break;
1260141cc406Sopenharmony_ci	}
1261141cc406Sopenharmony_ci      while (total_read < receive_bytes_outstanding);
1262141cc406Sopenharmony_ci      if (result == SANE_STATUS_GOOD)
1263141cc406Sopenharmony_ci	{
1264141cc406Sopenharmony_ci	  unsigned char *readptr;
1265141cc406Sopenharmony_ci	  int i;
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci	  for (i = 0, readptr = readbuf;
1268141cc406Sopenharmony_ci	       i < command_reads_outstanding;
1269141cc406Sopenharmony_ci	       readptr += command_readbytes_outstanding[i++])
1270141cc406Sopenharmony_ci	    {
1271141cc406Sopenharmony_ci	      memcpy (command_readmem_outstanding[i],
1272141cc406Sopenharmony_ci		      readptr, command_readbytes_outstanding[i]);
1273141cc406Sopenharmony_ci	    }
1274141cc406Sopenharmony_ci	}
1275141cc406Sopenharmony_ci    }
1276141cc406Sopenharmony_ci  receive_bytes_outstanding = command_reads_outstanding =
1277141cc406Sopenharmony_ci    command_bytes_outstanding = 0;
1278141cc406Sopenharmony_ci  return (result == SANE_STATUS_GOOD) ? 0 : -1;
1279141cc406Sopenharmony_ci}
1280141cc406Sopenharmony_ci
1281141cc406Sopenharmony_cistatic int
1282141cc406Sopenharmony_cirt_queue_command (int command,
1283141cc406Sopenharmony_ci		  int reg,
1284141cc406Sopenharmony_ci		  int count,
1285141cc406Sopenharmony_ci		  int bytes, void const *data_, int readbytes, void *readdata)
1286141cc406Sopenharmony_ci{
1287141cc406Sopenharmony_ci  int len = 4 + bytes;
1288141cc406Sopenharmony_ci  unsigned char *buffer;
1289141cc406Sopenharmony_ci  unsigned char const *data = data_;
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci  /* We add "bytes" here to account for the possibility that all of the
1292141cc406Sopenharmony_ci   * data bytes are 0xaa and hence require a following 0x00 byte.
1293141cc406Sopenharmony_ci   */
1294141cc406Sopenharmony_ci  if (command_bytes_outstanding + len + bytes > MAX_COMMANDS_BYTES ||
1295141cc406Sopenharmony_ci      (readbytes &&
1296141cc406Sopenharmony_ci       ((command_reads_outstanding >= MAX_READ_COMMANDS) ||
1297141cc406Sopenharmony_ci	(receive_bytes_outstanding >= MAX_READ_BYTES))))
1298141cc406Sopenharmony_ci    {
1299141cc406Sopenharmony_ci      if (rt_execute_commands () < 0)
1300141cc406Sopenharmony_ci	return -1;
1301141cc406Sopenharmony_ci    }
1302141cc406Sopenharmony_ci
1303141cc406Sopenharmony_ci  buffer = command_buffer + command_bytes_outstanding;
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci  *buffer++ = command;
1306141cc406Sopenharmony_ci  *buffer++ = reg;
1307141cc406Sopenharmony_ci  *buffer++ = count >> 8;
1308141cc406Sopenharmony_ci  *buffer++ = count;
1309141cc406Sopenharmony_ci  while (bytes--)
1310141cc406Sopenharmony_ci    {
1311141cc406Sopenharmony_ci      *buffer++ = *data;
1312141cc406Sopenharmony_ci      if (*data++ == 0xaa)
1313141cc406Sopenharmony_ci	{
1314141cc406Sopenharmony_ci	  *buffer++ = 0;
1315141cc406Sopenharmony_ci	  ++len;
1316141cc406Sopenharmony_ci	}
1317141cc406Sopenharmony_ci    }
1318141cc406Sopenharmony_ci  command_bytes_outstanding += len;
1319141cc406Sopenharmony_ci  if (readbytes)
1320141cc406Sopenharmony_ci    {
1321141cc406Sopenharmony_ci      command_readbytes_outstanding[command_reads_outstanding] = readbytes;
1322141cc406Sopenharmony_ci      command_readmem_outstanding[command_reads_outstanding] = readdata;
1323141cc406Sopenharmony_ci      receive_bytes_outstanding += readbytes;
1324141cc406Sopenharmony_ci      ++command_reads_outstanding;
1325141cc406Sopenharmony_ci    }
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci  return 0;
1328141cc406Sopenharmony_ci}
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_cistatic int
1331141cc406Sopenharmony_cirt_send_command_immediate (int command,
1332141cc406Sopenharmony_ci			   int reg,
1333141cc406Sopenharmony_ci			   int count,
1334141cc406Sopenharmony_ci			   int bytes,
1335141cc406Sopenharmony_ci			   void *data, int readbytes, void *readdata)
1336141cc406Sopenharmony_ci{
1337141cc406Sopenharmony_ci  rt_queue_command (command, reg, count, bytes, data, readbytes, readdata);
1338141cc406Sopenharmony_ci  return rt_execute_commands ();
1339141cc406Sopenharmony_ci}
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_cistatic int
1342141cc406Sopenharmony_cirt_queue_read_register (int reg, int bytes, void *data)
1343141cc406Sopenharmony_ci{
1344141cc406Sopenharmony_ci  return rt_queue_command (RTCMD_GETREG, reg, bytes, 0, 0, bytes, data);
1345141cc406Sopenharmony_ci}
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_cistatic int
1348141cc406Sopenharmony_cirt_read_register_immediate (int reg, int bytes, void *data)
1349141cc406Sopenharmony_ci{
1350141cc406Sopenharmony_ci  if (rt_queue_read_register (reg, bytes, data) < 0)
1351141cc406Sopenharmony_ci    return -1;
1352141cc406Sopenharmony_ci  return rt_execute_commands ();
1353141cc406Sopenharmony_ci}
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_cistatic int
1356141cc406Sopenharmony_cirt_queue_set_register (int reg, int bytes, void *data)
1357141cc406Sopenharmony_ci{
1358141cc406Sopenharmony_ci  return rt_queue_command (RTCMD_SETREG, reg, bytes, bytes, data, 0, 0);
1359141cc406Sopenharmony_ci}
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_cistatic int
1362141cc406Sopenharmony_cirt_set_register_immediate (int reg, int bytes, void *data)
1363141cc406Sopenharmony_ci{
1364141cc406Sopenharmony_ci  if (reg < 0xb3 && reg + bytes > 0xb3)
1365141cc406Sopenharmony_ci    {
1366141cc406Sopenharmony_ci      int bytes_in_first_block = 0xb3 - reg;
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci      if (rt_set_register_immediate (reg, bytes_in_first_block, data) < 0 ||
1369141cc406Sopenharmony_ci	  rt_set_register_immediate (0xb4, bytes - bytes_in_first_block - 1,
1370141cc406Sopenharmony_ci				     (char *) data + bytes_in_first_block +
1371141cc406Sopenharmony_ci				     1) < 0)
1372141cc406Sopenharmony_ci	return -1;
1373141cc406Sopenharmony_ci      return 0;
1374141cc406Sopenharmony_ci    }
1375141cc406Sopenharmony_ci  if (rt_queue_set_register (reg, bytes, data) < 0)
1376141cc406Sopenharmony_ci    return -1;
1377141cc406Sopenharmony_ci  return rt_execute_commands ();
1378141cc406Sopenharmony_ci}
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_cistatic int
1381141cc406Sopenharmony_cirt_set_one_register (int reg, int val)
1382141cc406Sopenharmony_ci{
1383141cc406Sopenharmony_ci  char r = val;
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci  return rt_set_register_immediate (reg, 1, &r);
1386141cc406Sopenharmony_ci}
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_cistatic int
1389141cc406Sopenharmony_cirt_write_sram (int bytes, void *data_)
1390141cc406Sopenharmony_ci{
1391141cc406Sopenharmony_ci  unsigned char *data = (unsigned char *) data_;
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci  /* The number of bytes passed in could be much larger than we can transmit
1394141cc406Sopenharmony_ci   * (0xffc0) bytes. With 0xaa escapes it could be even larger. Accordingly
1395141cc406Sopenharmony_ci   * we need to count the 0xaa escapes and write in chunks if the number of
1396141cc406Sopenharmony_ci   * bytes would otherwise exceed a limit (I have used 0xf000 as the limit).
1397141cc406Sopenharmony_ci   */
1398141cc406Sopenharmony_ci  while (bytes > 0)
1399141cc406Sopenharmony_ci    {
1400141cc406Sopenharmony_ci      int now = 0;
1401141cc406Sopenharmony_ci      int bufsize = 0;
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci      while (now < bytes && bufsize < 0xf000)
1404141cc406Sopenharmony_ci	{
1405141cc406Sopenharmony_ci	  int i;
1406141cc406Sopenharmony_ci
1407141cc406Sopenharmony_ci	  /* Try to avoid writing part pages */
1408141cc406Sopenharmony_ci	  for (i = 0; i < 32 && now < bytes; ++i)
1409141cc406Sopenharmony_ci	    {
1410141cc406Sopenharmony_ci	      ++bufsize;
1411141cc406Sopenharmony_ci	      if (data[now++] == 0xaa)
1412141cc406Sopenharmony_ci		++bufsize;
1413141cc406Sopenharmony_ci	    }
1414141cc406Sopenharmony_ci	}
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci      if (rt_send_command_immediate (RTCMD_WRITESRAM, 0, now, now, data, 0,
1417141cc406Sopenharmony_ci				     0) < 0)
1418141cc406Sopenharmony_ci	return -1;
1419141cc406Sopenharmony_ci      bytes -= now;
1420141cc406Sopenharmony_ci      data += now;
1421141cc406Sopenharmony_ci    }
1422141cc406Sopenharmony_ci  return 0;
1423141cc406Sopenharmony_ci}
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_cistatic int
1426141cc406Sopenharmony_cirt_read_sram (int bytes, void *data_)
1427141cc406Sopenharmony_ci{
1428141cc406Sopenharmony_ci  unsigned char *data = (unsigned char *) data_;
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ci  while (bytes > 0)
1431141cc406Sopenharmony_ci    {
1432141cc406Sopenharmony_ci      int now = (bytes > 0xf000) ? 0xf000 : bytes;
1433141cc406Sopenharmony_ci      if (rt_send_command_immediate (RTCMD_READSRAM, 0, bytes, 0, 0, bytes,
1434141cc406Sopenharmony_ci				     data) < 0)
1435141cc406Sopenharmony_ci	return -1;
1436141cc406Sopenharmony_ci      bytes -= now;
1437141cc406Sopenharmony_ci      data += now;
1438141cc406Sopenharmony_ci    }
1439141cc406Sopenharmony_ci  return 0;
1440141cc406Sopenharmony_ci}
1441141cc406Sopenharmony_ci
1442141cc406Sopenharmony_cistatic int
1443141cc406Sopenharmony_cirt_set_sram_page (int page)
1444141cc406Sopenharmony_ci{
1445141cc406Sopenharmony_ci  unsigned char regs[2];
1446141cc406Sopenharmony_ci
1447141cc406Sopenharmony_ci  regs[0] = page;
1448141cc406Sopenharmony_ci  regs[1] = page >> 8;
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci  return rt_set_register_immediate (0x91, 2, regs);
1451141cc406Sopenharmony_ci}
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_cistatic int
1454141cc406Sopenharmony_cirt_detect_sram (unsigned *totalbytes, unsigned char *r93setting)
1455141cc406Sopenharmony_ci{
1456141cc406Sopenharmony_ci  char data[0x818];
1457141cc406Sopenharmony_ci  char testbuf[0x818];
1458141cc406Sopenharmony_ci  unsigned i;
1459141cc406Sopenharmony_ci  int test_values[] = { 6, 2, 1, -1 };
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  for (i = 0; i < sizeof (data); ++i)
1462141cc406Sopenharmony_ci    data[i] = i % 0x61;
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  for (i = 0; test_values[i] != -1; ++i)
1466141cc406Sopenharmony_ci    {
1467141cc406Sopenharmony_ci      if (rt_set_one_register (0x93, test_values[i]) ||
1468141cc406Sopenharmony_ci	  rt_set_sram_page (0x81) ||
1469141cc406Sopenharmony_ci	  rt_write_sram (0x818, data) ||
1470141cc406Sopenharmony_ci	  rt_set_sram_page (0x81) || rt_read_sram (0x818, testbuf))
1471141cc406Sopenharmony_ci	return -1;
1472141cc406Sopenharmony_ci      if (!memcmp (testbuf, data, 0x818))
1473141cc406Sopenharmony_ci	{
1474141cc406Sopenharmony_ci	  sram_access_method = test_values[i];
1475141cc406Sopenharmony_ci	  if (r93setting)
1476141cc406Sopenharmony_ci	    *r93setting = sram_access_method;
1477141cc406Sopenharmony_ci	  break;
1478141cc406Sopenharmony_ci	}
1479141cc406Sopenharmony_ci    }
1480141cc406Sopenharmony_ci  if (!sram_access_method)
1481141cc406Sopenharmony_ci    return -1;
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  for (i = 0; i < 16; ++i)
1484141cc406Sopenharmony_ci    {
1485141cc406Sopenharmony_ci      int j;
1486141cc406Sopenharmony_ci      char write_data[32];
1487141cc406Sopenharmony_ci      char read_data[32];
1488141cc406Sopenharmony_ci      int pagesetting;
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci      for (j = 0; j < 16; j++)
1491141cc406Sopenharmony_ci	{
1492141cc406Sopenharmony_ci	  write_data[j * 2] = j * 2;
1493141cc406Sopenharmony_ci	  write_data[j * 2 + 1] = i;
1494141cc406Sopenharmony_ci	}
1495141cc406Sopenharmony_ci
1496141cc406Sopenharmony_ci      pagesetting = i * 4096;
1497141cc406Sopenharmony_ci
1498141cc406Sopenharmony_ci
1499141cc406Sopenharmony_ci      if (rt_set_sram_page (pagesetting) < 0 ||
1500141cc406Sopenharmony_ci	  rt_write_sram (32, write_data) < 0)
1501141cc406Sopenharmony_ci	return -1;
1502141cc406Sopenharmony_ci      if (i)
1503141cc406Sopenharmony_ci	{
1504141cc406Sopenharmony_ci	  if (rt_set_sram_page (0) < 0 || rt_read_sram (32, read_data) < 0)
1505141cc406Sopenharmony_ci	    return -1;
1506141cc406Sopenharmony_ci	  if (!memcmp (read_data, write_data, 32))
1507141cc406Sopenharmony_ci	    {
1508141cc406Sopenharmony_ci	      sram_size = i * 0x20000;
1509141cc406Sopenharmony_ci	      if (totalbytes)
1510141cc406Sopenharmony_ci		*totalbytes = sram_size;
1511141cc406Sopenharmony_ci	      return 0;
1512141cc406Sopenharmony_ci	    }
1513141cc406Sopenharmony_ci	}
1514141cc406Sopenharmony_ci    }
1515141cc406Sopenharmony_ci  return -1;
1516141cc406Sopenharmony_ci}
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_cistatic int
1519141cc406Sopenharmony_cirt_get_available_bytes (void)
1520141cc406Sopenharmony_ci{
1521141cc406Sopenharmony_ci  unsigned char data[3];
1522141cc406Sopenharmony_ci
1523141cc406Sopenharmony_ci  if (rt_queue_command (RTCMD_BYTESAVAIL, 0, 3, 0, 0, 3, data) < 0 ||
1524141cc406Sopenharmony_ci      rt_execute_commands () < 0)
1525141cc406Sopenharmony_ci    return -1;
1526141cc406Sopenharmony_ci  return ((unsigned) data[0]) |
1527141cc406Sopenharmony_ci    ((unsigned) data[1] << 8) | ((unsigned) data[2] << 16);
1528141cc406Sopenharmony_ci}
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_cistatic int
1531141cc406Sopenharmony_cirt_get_data (int bytes, void *data)
1532141cc406Sopenharmony_ci{
1533141cc406Sopenharmony_ci  while (bytes)
1534141cc406Sopenharmony_ci    {
1535141cc406Sopenharmony_ci      int bytesnow = bytes;
1536141cc406Sopenharmony_ci
1537141cc406Sopenharmony_ci      if (bytesnow > 0xffc0)
1538141cc406Sopenharmony_ci	bytesnow = 0xffc0;
1539141cc406Sopenharmony_ci      if (rt_queue_command
1540141cc406Sopenharmony_ci	  (RTCMD_READBYTES, 0, bytesnow, 0, 0, bytesnow, data) < 0
1541141cc406Sopenharmony_ci	  || rt_execute_commands () < 0)
1542141cc406Sopenharmony_ci	return -1;
1543141cc406Sopenharmony_ci      bytes -= bytesnow;
1544141cc406Sopenharmony_ci      data = (char *) data + bytesnow;
1545141cc406Sopenharmony_ci    }
1546141cc406Sopenharmony_ci  return 0;
1547141cc406Sopenharmony_ci}
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_cistatic int
1550141cc406Sopenharmony_cirt_is_moving (void)
1551141cc406Sopenharmony_ci{
1552141cc406Sopenharmony_ci  char r;
1553141cc406Sopenharmony_ci
1554141cc406Sopenharmony_ci  if (rt_read_register_immediate (REG_MOVE_CONTROL_TEST, 1, &r) < 0)
1555141cc406Sopenharmony_ci    return -1;
1556141cc406Sopenharmony_ci  if (r == 0x08)
1557141cc406Sopenharmony_ci    return 1;
1558141cc406Sopenharmony_ci  return 0;
1559141cc406Sopenharmony_ci}
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_cistatic int
1562141cc406Sopenharmony_cirt_is_rewound (void)
1563141cc406Sopenharmony_ci{
1564141cc406Sopenharmony_ci  char r;
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci  if (rt_read_register_immediate (0x1d, 1, &r) < 0)
1567141cc406Sopenharmony_ci    return -1;
1568141cc406Sopenharmony_ci  if (r & 0x02)
1569141cc406Sopenharmony_ci    return 1;
1570141cc406Sopenharmony_ci  return 0;
1571141cc406Sopenharmony_ci}
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_cistatic int
1574141cc406Sopenharmony_cirt_set_direction_forwards (unsigned char *regs)
1575141cc406Sopenharmony_ci{
1576141cc406Sopenharmony_ci  regs[0xc6] |= 0x08;
1577141cc406Sopenharmony_ci  return 0;
1578141cc406Sopenharmony_ci}
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_cistatic int
1581141cc406Sopenharmony_cirt_set_direction_rewind (unsigned char *regs)
1582141cc406Sopenharmony_ci{
1583141cc406Sopenharmony_ci  regs[0xc6] &= 0xf7;
1584141cc406Sopenharmony_ci  return 0;
1585141cc406Sopenharmony_ci}
1586141cc406Sopenharmony_ci
1587141cc406Sopenharmony_cistatic int
1588141cc406Sopenharmony_cirt_set_stop_when_rewound (unsigned char *regs, int stop)
1589141cc406Sopenharmony_ci{
1590141cc406Sopenharmony_ci  if (stop)
1591141cc406Sopenharmony_ci    regs[0xb2] |= 0x10;
1592141cc406Sopenharmony_ci  else
1593141cc406Sopenharmony_ci    regs[0xb2] &= 0xef;
1594141cc406Sopenharmony_ci  return 0;
1595141cc406Sopenharmony_ci}
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_cistatic int
1598141cc406Sopenharmony_cirt_start_moving (void)
1599141cc406Sopenharmony_ci{
1600141cc406Sopenharmony_ci  if (rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 ||
1601141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 ||
1602141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 ||
1603141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 ||
1604141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 8) < 0 ||
1605141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 8) < 0)
1606141cc406Sopenharmony_ci    return -1;
1607141cc406Sopenharmony_ci  return 0;
1608141cc406Sopenharmony_ci}
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_cistatic int
1611141cc406Sopenharmony_cirt_stop_moving (void)
1612141cc406Sopenharmony_ci{
1613141cc406Sopenharmony_ci  if (rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 ||
1614141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 ||
1615141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 ||
1616141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0)
1617141cc406Sopenharmony_ci    return -1;
1618141cc406Sopenharmony_ci  return 0;
1619141cc406Sopenharmony_ci}
1620141cc406Sopenharmony_ci
1621141cc406Sopenharmony_cistatic int
1622141cc406Sopenharmony_cirt_set_powersave_mode (int enable)
1623141cc406Sopenharmony_ci{
1624141cc406Sopenharmony_ci  unsigned char r;
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci  if (rt_read_register_immediate (REG_MOVE_CONTROL_TEST, 1, &r) < 0)
1627141cc406Sopenharmony_ci    return -1;
1628141cc406Sopenharmony_ci  if (r & 0x04)
1629141cc406Sopenharmony_ci    {
1630141cc406Sopenharmony_ci      if (enable == 1)
1631141cc406Sopenharmony_ci	return 0;
1632141cc406Sopenharmony_ci      r &= ~0x04;
1633141cc406Sopenharmony_ci    }
1634141cc406Sopenharmony_ci  else
1635141cc406Sopenharmony_ci    {
1636141cc406Sopenharmony_ci      if (enable == 0)
1637141cc406Sopenharmony_ci	return 0;
1638141cc406Sopenharmony_ci      r |= 0x04;
1639141cc406Sopenharmony_ci    }
1640141cc406Sopenharmony_ci  if (rt_set_one_register (REG_MOVE_CONTROL_TEST, r) < 0 ||
1641141cc406Sopenharmony_ci      rt_set_one_register (REG_MOVE_CONTROL_TEST, r) < 0)
1642141cc406Sopenharmony_ci    return -1;
1643141cc406Sopenharmony_ci  return 0;
1644141cc406Sopenharmony_ci}
1645141cc406Sopenharmony_ci
1646141cc406Sopenharmony_cistatic int
1647141cc406Sopenharmony_cirt_turn_off_lamp (void)
1648141cc406Sopenharmony_ci{
1649141cc406Sopenharmony_ci  return rt_set_one_register (0x3a, 0);
1650141cc406Sopenharmony_ci}
1651141cc406Sopenharmony_ci
1652141cc406Sopenharmony_cistatic int
1653141cc406Sopenharmony_cirt_turn_on_lamp (void)
1654141cc406Sopenharmony_ci{
1655141cc406Sopenharmony_ci  char r3ab[2];
1656141cc406Sopenharmony_ci  char r10;
1657141cc406Sopenharmony_ci  char r58;
1658141cc406Sopenharmony_ci
1659141cc406Sopenharmony_ci  if (rt_read_register_immediate (0x3a, 1, r3ab) < 0 ||
1660141cc406Sopenharmony_ci      rt_read_register_immediate (0x10, 1, &r10) < 0 ||
1661141cc406Sopenharmony_ci      rt_read_register_immediate (0x58, 1, &r58) < 0)
1662141cc406Sopenharmony_ci    return -1;
1663141cc406Sopenharmony_ci  r3ab[0] |= 0x80;
1664141cc406Sopenharmony_ci  r3ab[1] = 0x40;
1665141cc406Sopenharmony_ci  r10 |= 0x01;
1666141cc406Sopenharmony_ci  r58 &= 0x0f;
1667141cc406Sopenharmony_ci  if (rt_set_register_immediate (0x3a, 2, r3ab) < 0 ||
1668141cc406Sopenharmony_ci      rt_set_one_register (0x10, r10) < 0 ||
1669141cc406Sopenharmony_ci      rt_set_one_register (0x58, r58) < 0)
1670141cc406Sopenharmony_ci    return -1;
1671141cc406Sopenharmony_ci  return 0;
1672141cc406Sopenharmony_ci}
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_cistatic int
1675141cc406Sopenharmony_cirt_set_value_lsbfirst (unsigned char *regs,
1676141cc406Sopenharmony_ci		       int firstreg, int totalregs, unsigned value)
1677141cc406Sopenharmony_ci{
1678141cc406Sopenharmony_ci  while (totalregs--)
1679141cc406Sopenharmony_ci    {
1680141cc406Sopenharmony_ci      regs[firstreg++] = value & 0xff;
1681141cc406Sopenharmony_ci      value >>= 8;
1682141cc406Sopenharmony_ci    }
1683141cc406Sopenharmony_ci  return 0;
1684141cc406Sopenharmony_ci}
1685141cc406Sopenharmony_ci
1686141cc406Sopenharmony_ci#if 0
1687141cc406Sopenharmony_cistatic int
1688141cc406Sopenharmony_cirt_set_value_msbfirst (unsigned char *regs,
1689141cc406Sopenharmony_ci		       int firstreg, int totalregs, unsigned value)
1690141cc406Sopenharmony_ci{
1691141cc406Sopenharmony_ci  while (totalregs--)
1692141cc406Sopenharmony_ci    {
1693141cc406Sopenharmony_ci      regs[firstreg + totalregs] = value & 0xff;
1694141cc406Sopenharmony_ci      value >>= 8;
1695141cc406Sopenharmony_ci    }
1696141cc406Sopenharmony_ci  return 0;
1697141cc406Sopenharmony_ci}
1698141cc406Sopenharmony_ci#endif
1699141cc406Sopenharmony_ci
1700141cc406Sopenharmony_cistatic int
1701141cc406Sopenharmony_cirt_set_ccd_shift_clock_multiplier (unsigned char *regs, unsigned value)
1702141cc406Sopenharmony_ci{
1703141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0xf0, 3, value);
1704141cc406Sopenharmony_ci}
1705141cc406Sopenharmony_ci
1706141cc406Sopenharmony_cistatic int
1707141cc406Sopenharmony_cirt_set_ccd_clock_reset_interval (unsigned char *regs, unsigned value)
1708141cc406Sopenharmony_ci{
1709141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0xf9, 3, value);
1710141cc406Sopenharmony_ci}
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_cistatic int
1713141cc406Sopenharmony_cirt_set_ccd_clamp_clock_multiplier (unsigned char *regs, unsigned value)
1714141cc406Sopenharmony_ci{
1715141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0xfc, 3, value);
1716141cc406Sopenharmony_ci}
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_cistatic int
1719141cc406Sopenharmony_cirt_set_movement_pattern (unsigned char *regs, unsigned value)
1720141cc406Sopenharmony_ci{
1721141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0xc0, 3, value);
1722141cc406Sopenharmony_ci}
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_cistatic int
1725141cc406Sopenharmony_cirt_set_motor_movement_clock_multiplier (unsigned char *regs, unsigned value)
1726141cc406Sopenharmony_ci{
1727141cc406Sopenharmony_ci  regs[0x40] = (regs[0x40] & ~0xc0) | (value << 6);
1728141cc406Sopenharmony_ci  return 0;
1729141cc406Sopenharmony_ci}
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_cistatic int
1732141cc406Sopenharmony_cirt_set_motor_type (unsigned char *regs, unsigned value)
1733141cc406Sopenharmony_ci{
1734141cc406Sopenharmony_ci  regs[0xc9] = (regs[0xc9] & 0xf8) | (value & 0x7);
1735141cc406Sopenharmony_ci  return 0;
1736141cc406Sopenharmony_ci}
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_cistatic int
1739141cc406Sopenharmony_cirt_set_noscan_distance (unsigned char *regs, unsigned value)
1740141cc406Sopenharmony_ci{
1741141cc406Sopenharmony_ci  DBG (10, "Setting distance without scanning to %d\n", value);
1742141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0x60, 2, value);
1743141cc406Sopenharmony_ci}
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_cistatic int
1746141cc406Sopenharmony_cirt_set_total_distance (unsigned char *regs, unsigned value)
1747141cc406Sopenharmony_ci{
1748141cc406Sopenharmony_ci  DBG (10, "Setting total distance to %d\n", value);
1749141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0x62, 2, value);
1750141cc406Sopenharmony_ci}
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_cistatic int
1753141cc406Sopenharmony_cirt_set_scanline_start (unsigned char *regs, unsigned value)
1754141cc406Sopenharmony_ci{
1755141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0x66, 2, value);
1756141cc406Sopenharmony_ci}
1757141cc406Sopenharmony_ci
1758141cc406Sopenharmony_cistatic int
1759141cc406Sopenharmony_cirt_set_scanline_end (unsigned char *regs, unsigned value)
1760141cc406Sopenharmony_ci{
1761141cc406Sopenharmony_ci  return rt_set_value_lsbfirst (regs, 0x6c, 2, value);
1762141cc406Sopenharmony_ci}
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_cistatic int
1765141cc406Sopenharmony_cirt_set_basic_calibration (unsigned char *regs,
1766141cc406Sopenharmony_ci			  int redoffset1,
1767141cc406Sopenharmony_ci			  int redoffset2,
1768141cc406Sopenharmony_ci			  int redgain,
1769141cc406Sopenharmony_ci			  int greenoffset1,
1770141cc406Sopenharmony_ci			  int greenoffset2,
1771141cc406Sopenharmony_ci			  int greengain,
1772141cc406Sopenharmony_ci			  int blueoffset1, int blueoffset2, int bluegain)
1773141cc406Sopenharmony_ci{
1774141cc406Sopenharmony_ci  regs[0x02] = redoffset1;
1775141cc406Sopenharmony_ci  regs[0x05] = redoffset2;
1776141cc406Sopenharmony_ci  regs[0x08] = redgain;
1777141cc406Sopenharmony_ci  regs[0x03] = greenoffset1;
1778141cc406Sopenharmony_ci  regs[0x06] = greenoffset2;
1779141cc406Sopenharmony_ci  regs[0x09] = greengain;
1780141cc406Sopenharmony_ci  regs[0x04] = blueoffset1;
1781141cc406Sopenharmony_ci  regs[0x07] = blueoffset2;
1782141cc406Sopenharmony_ci  regs[0x0a] = bluegain;
1783141cc406Sopenharmony_ci  return 0;
1784141cc406Sopenharmony_ci}
1785141cc406Sopenharmony_ci
1786141cc406Sopenharmony_cistatic int
1787141cc406Sopenharmony_cirt_set_calibration_addresses (unsigned char *regs,
1788141cc406Sopenharmony_ci			      unsigned redaddr,
1789141cc406Sopenharmony_ci			      unsigned greenaddr,
1790141cc406Sopenharmony_ci			      unsigned blueaddr,
1791141cc406Sopenharmony_ci			      unsigned endaddr,
1792141cc406Sopenharmony_ci			      unsigned width)
1793141cc406Sopenharmony_ci{
1794141cc406Sopenharmony_ci  unsigned endpage = (endaddr + 31) / 32;
1795141cc406Sopenharmony_ci  unsigned scanline_pages = ((width + 1) * 3 + 31) / 32;
1796141cc406Sopenharmony_ci
1797141cc406Sopenharmony_ci  /* Red, green and blue detailed calibration addresses */
1798141cc406Sopenharmony_ci
1799141cc406Sopenharmony_ci  regs[0x84] = redaddr;
1800141cc406Sopenharmony_ci  regs[0x8e] = (regs[0x8e] & 0x0f) | ((redaddr >> 4) & 0xf0);
1801141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x85, 2, greenaddr);
1802141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x87, 2, blueaddr);
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci  /* I don't know what the next three are used for, but each buffer commencing
1805141cc406Sopenharmony_ci   * at 0x80 and 0x82 needs to hold a full scan line.
1806141cc406Sopenharmony_ci   */
1807141cc406Sopenharmony_ci
1808141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x80, 2, endpage);
1809141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x82, 2, endpage + scanline_pages);
1810141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x89, 2, endpage + scanline_pages * 2);
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci  /* I don't know what this is, but it seems to be a number of pages that can hold
1813141cc406Sopenharmony_ci   * 16 complete scan lines, but not calculated as an offset from any other page
1814141cc406Sopenharmony_ci   */
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x51, 2, (48 * (width + 1) + 31) / 32);
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci  /* I don't know what this is either, but this is what the Windows driver does */
1819141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x8f, 2, 0x1c00);
1820141cc406Sopenharmony_ci  return 0;
1821141cc406Sopenharmony_ci}
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_cistatic int
1824141cc406Sopenharmony_cirt_set_lamp_duty_cycle (unsigned char *regs,
1825141cc406Sopenharmony_ci			int enable, int frequency, int offduty)
1826141cc406Sopenharmony_ci{
1827141cc406Sopenharmony_ci  if (enable)
1828141cc406Sopenharmony_ci    regs[0x3b] |= 0x80;
1829141cc406Sopenharmony_ci  else
1830141cc406Sopenharmony_ci    regs[0x3b] &= 0x7f;
1831141cc406Sopenharmony_ci
1832141cc406Sopenharmony_ci  regs[0x3b] =
1833141cc406Sopenharmony_ci    (regs[0x3b] & 0x80) | ((frequency & 0x7) << 4) | (offduty & 0x0f);
1834141cc406Sopenharmony_ci  regs[0x3d] = (regs[0x3d] & 0x7f) | ((frequency & 0x8) << 4);
1835141cc406Sopenharmony_ci  return 0;
1836141cc406Sopenharmony_ci}
1837141cc406Sopenharmony_ci
1838141cc406Sopenharmony_cistatic int
1839141cc406Sopenharmony_cirt_set_data_feed_on (unsigned char *regs)
1840141cc406Sopenharmony_ci{
1841141cc406Sopenharmony_ci  regs[0xb2] &= ~0x04;
1842141cc406Sopenharmony_ci  return 0;
1843141cc406Sopenharmony_ci}
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_cistatic int
1846141cc406Sopenharmony_cirt_set_data_feed_off (unsigned char *regs)
1847141cc406Sopenharmony_ci{
1848141cc406Sopenharmony_ci  regs[0xb2] |= 0x04;
1849141cc406Sopenharmony_ci  return 0;
1850141cc406Sopenharmony_ci}
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_cistatic int
1853141cc406Sopenharmony_cirt_enable_ccd (unsigned char *regs, int enable)
1854141cc406Sopenharmony_ci{
1855141cc406Sopenharmony_ci  if (enable)
1856141cc406Sopenharmony_ci    regs[0x00] &= ~0x10;
1857141cc406Sopenharmony_ci  else
1858141cc406Sopenharmony_ci    regs[0x00] |= 0x10;
1859141cc406Sopenharmony_ci  return 0;
1860141cc406Sopenharmony_ci}
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_cistatic int
1863141cc406Sopenharmony_cirt_set_cdss (unsigned char *regs, int val1, int val2)
1864141cc406Sopenharmony_ci{
1865141cc406Sopenharmony_ci  regs[0x28] = (regs[0x28] & 0xe0) | (val1 & 0x1f);
1866141cc406Sopenharmony_ci  regs[0x2a] = (regs[0x2a] & 0xe0) | (val2 & 0x1f);
1867141cc406Sopenharmony_ci  return 0;
1868141cc406Sopenharmony_ci}
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_cistatic int
1871141cc406Sopenharmony_cirt_set_cdsc (unsigned char *regs, int val1, int val2)
1872141cc406Sopenharmony_ci{
1873141cc406Sopenharmony_ci  regs[0x29] = (regs[0x29] & 0xe0) | (val1 & 0x1f);
1874141cc406Sopenharmony_ci  regs[0x2b] = (regs[0x2b] & 0xe0) | (val2 & 0x1f);
1875141cc406Sopenharmony_ci  return 0;
1876141cc406Sopenharmony_ci}
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_cistatic int
1879141cc406Sopenharmony_cirt_update_after_setting_cdss2 (unsigned char *regs)
1880141cc406Sopenharmony_ci{
1881141cc406Sopenharmony_ci  int fullcolour = (!(regs[0x2f] & 0xc0) && (regs[0x2f] & 0x04));
1882141cc406Sopenharmony_ci  int value = regs[0x2a] & 0x1f;
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci  regs[0x2a] = (regs[0x2a] & 0xe0) | (value & 0x1f);
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci  if (fullcolour)
1887141cc406Sopenharmony_ci    value *= 3;
1888141cc406Sopenharmony_ci  if ((regs[0x40] & 0xc0) == 0x40)
1889141cc406Sopenharmony_ci    value += 17;
1890141cc406Sopenharmony_ci  else
1891141cc406Sopenharmony_ci    value += 16;
1892141cc406Sopenharmony_ci
1893141cc406Sopenharmony_ci  regs[0x2c] = (regs[0x2c] & 0xe0) | (value % 24);
1894141cc406Sopenharmony_ci  regs[0x2d] = (regs[0x2d] & 0xe0) | ((value + 2) % 24);
1895141cc406Sopenharmony_ci  return 0;
1896141cc406Sopenharmony_ci}
1897141cc406Sopenharmony_ci
1898141cc406Sopenharmony_cistatic int
1899141cc406Sopenharmony_cirt_set_cph0s (unsigned char *regs, int on)
1900141cc406Sopenharmony_ci{
1901141cc406Sopenharmony_ci  if (on)
1902141cc406Sopenharmony_ci    regs[0x2d] |= 0x20;		/* 1200dpi horizontal coordinate space */
1903141cc406Sopenharmony_ci  else
1904141cc406Sopenharmony_ci    regs[0x2d] &= ~0x20;	/* 600dpi horizontal coordinate space */
1905141cc406Sopenharmony_ci  return 0;
1906141cc406Sopenharmony_ci}
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_cistatic int
1909141cc406Sopenharmony_cirt_set_cvtr_lm (unsigned char *regs, int val1, int val2, int val3)
1910141cc406Sopenharmony_ci{
1911141cc406Sopenharmony_ci  regs[0x28] = (regs[0x28] & ~0xe0) | (val1 << 5);
1912141cc406Sopenharmony_ci  regs[0x29] = (regs[0x29] & ~0xe0) | (val2 << 5);
1913141cc406Sopenharmony_ci  regs[0x2a] = (regs[0x2a] & ~0xe0) | (val3 << 5);
1914141cc406Sopenharmony_ci  return 0;
1915141cc406Sopenharmony_ci}
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_cistatic int
1918141cc406Sopenharmony_cirt_set_cvtr_mpt (unsigned char *regs, int val1, int val2, int val3)
1919141cc406Sopenharmony_ci{
1920141cc406Sopenharmony_ci  regs[0x3c] = (val1 & 0x0f) | (val2 << 4);
1921141cc406Sopenharmony_ci  regs[0x3d] = (regs[0x3d] & 0xf0) | (val3 & 0x0f);
1922141cc406Sopenharmony_ci  return 0;
1923141cc406Sopenharmony_ci}
1924141cc406Sopenharmony_ci
1925141cc406Sopenharmony_cistatic int
1926141cc406Sopenharmony_cirt_set_cvtr_wparams (unsigned char *regs,
1927141cc406Sopenharmony_ci		     unsigned fpw, unsigned bpw, unsigned w)
1928141cc406Sopenharmony_ci{
1929141cc406Sopenharmony_ci  regs[0x31] = (w & 0x0f) | ((bpw << 4) & 0x30) | (fpw << 6);
1930141cc406Sopenharmony_ci  return 0;
1931141cc406Sopenharmony_ci}
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_cistatic int
1934141cc406Sopenharmony_cirt_enable_movement (unsigned char *regs, int enable)
1935141cc406Sopenharmony_ci{
1936141cc406Sopenharmony_ci  if (enable)
1937141cc406Sopenharmony_ci    regs[0xc3] |= 0x80;
1938141cc406Sopenharmony_ci  else
1939141cc406Sopenharmony_ci    regs[0xc3] &= ~0x80;
1940141cc406Sopenharmony_ci  return 0;
1941141cc406Sopenharmony_ci}
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_cistatic int
1944141cc406Sopenharmony_cirt_set_scan_frequency (unsigned char *regs, int frequency)
1945141cc406Sopenharmony_ci{
1946141cc406Sopenharmony_ci  regs[0x64] = (regs[0x64] & 0xf0) | (frequency & 0x0f);
1947141cc406Sopenharmony_ci  return 0;
1948141cc406Sopenharmony_ci}
1949141cc406Sopenharmony_ci
1950141cc406Sopenharmony_cistatic int
1951141cc406Sopenharmony_cirt_set_merge_channels (unsigned char *regs, int on)
1952141cc406Sopenharmony_ci{
1953141cc406Sopenharmony_ci  /* RGBRGB instead of RRRRR...GGGGG...BBBB */
1954141cc406Sopenharmony_ci  regs[0x2f] &= ~0x14;
1955141cc406Sopenharmony_ci  regs[0x2f] |= on ? 0x04 : 0x10;
1956141cc406Sopenharmony_ci  return 0;
1957141cc406Sopenharmony_ci}
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_cistatic int
1960141cc406Sopenharmony_cirt_set_channel (unsigned char *regs, int channel)
1961141cc406Sopenharmony_ci{
1962141cc406Sopenharmony_ci  regs[0x2f] = (regs[0x2f] & ~0xc0) | (channel << 6);
1963141cc406Sopenharmony_ci  return 0;
1964141cc406Sopenharmony_ci}
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_cistatic int
1967141cc406Sopenharmony_cirt_set_single_channel_scanning (unsigned char *regs, int on)
1968141cc406Sopenharmony_ci{
1969141cc406Sopenharmony_ci  if (on)
1970141cc406Sopenharmony_ci    regs[0x2f] |= 0x20;
1971141cc406Sopenharmony_ci  else
1972141cc406Sopenharmony_ci    regs[0x2f] &= ~0x20;
1973141cc406Sopenharmony_ci  return 0;
1974141cc406Sopenharmony_ci}
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_cistatic int
1977141cc406Sopenharmony_cirt_set_colour_mode (unsigned char *regs, int on)
1978141cc406Sopenharmony_ci{
1979141cc406Sopenharmony_ci  if (on)
1980141cc406Sopenharmony_ci    regs[0x2f] |= 0x02;
1981141cc406Sopenharmony_ci  else
1982141cc406Sopenharmony_ci    regs[0x2f] &= ~0x02;
1983141cc406Sopenharmony_ci  return 0;
1984141cc406Sopenharmony_ci}
1985141cc406Sopenharmony_ci
1986141cc406Sopenharmony_cistatic int
1987141cc406Sopenharmony_cirt_set_horizontal_resolution (unsigned char *regs, int resolution)
1988141cc406Sopenharmony_ci{
1989141cc406Sopenharmony_ci  int base_resolution = 300;
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_ci  if (regs[0x2d] & 0x20)
1992141cc406Sopenharmony_ci    base_resolution *= 2;
1993141cc406Sopenharmony_ci  if (regs[0xd3] & 0x08)
1994141cc406Sopenharmony_ci    base_resolution *= 2;
1995141cc406Sopenharmony_ci  regs[0x7a] = base_resolution / resolution;
1996141cc406Sopenharmony_ci  return 0;
1997141cc406Sopenharmony_ci}
1998141cc406Sopenharmony_ci
1999141cc406Sopenharmony_cistatic int
2000141cc406Sopenharmony_cirt_set_last_sram_page (unsigned char *regs, int pagenum)
2001141cc406Sopenharmony_ci{
2002141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0x8b, 2, pagenum);
2003141cc406Sopenharmony_ci  return 0;
2004141cc406Sopenharmony_ci}
2005141cc406Sopenharmony_ci
2006141cc406Sopenharmony_cistatic int
2007141cc406Sopenharmony_cirt_set_step_size (unsigned char *regs, int stepsize)
2008141cc406Sopenharmony_ci{
2009141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0xe2, 2, stepsize);
2010141cc406Sopenharmony_ci  rt_set_value_lsbfirst (regs, 0xe0, 2, 0);
2011141cc406Sopenharmony_ci  return 0;
2012141cc406Sopenharmony_ci}
2013141cc406Sopenharmony_ci
2014141cc406Sopenharmony_cistatic int
2015141cc406Sopenharmony_cirt_set_all_registers (void const *regs_)
2016141cc406Sopenharmony_ci{
2017141cc406Sopenharmony_ci  char regs[255];
2018141cc406Sopenharmony_ci
2019141cc406Sopenharmony_ci  memcpy (regs, regs_, 255);
2020141cc406Sopenharmony_ci  regs[0x32] &= ~0x40;
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci  if (rt_set_one_register (0x32, regs[0x32]) < 0 ||
2023141cc406Sopenharmony_ci      rt_set_register_immediate (0, 255, regs) < 0 ||
2024141cc406Sopenharmony_ci      rt_set_one_register (0x32, regs[0x32] | 0x40) < 0)
2025141cc406Sopenharmony_ci    return -1;
2026141cc406Sopenharmony_ci  return 0;
2027141cc406Sopenharmony_ci}
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_cistatic int
2030141cc406Sopenharmony_cirt_adjust_misc_registers (unsigned char *regs)
2031141cc406Sopenharmony_ci{
2032141cc406Sopenharmony_ci  /* Mostly unknown purposes - probably no need to adjust */
2033141cc406Sopenharmony_ci  regs[0xc6] = (regs[0xc6] & 0x0f) | 0x20;	/* Purpose unknown - appears to do nothing */
2034141cc406Sopenharmony_ci  regs[0x2e] = 0x86;		/* ???? - Always has this value */
2035141cc406Sopenharmony_ci  regs[0x30] = 2;		/* CCPL = 1 */
2036141cc406Sopenharmony_ci  regs[0xc9] |= 0x38;		/* Doesn't have any obvious effect, but the Windows driver does this */
2037141cc406Sopenharmony_ci  return 0;
2038141cc406Sopenharmony_ci}
2039141cc406Sopenharmony_ci
2040141cc406Sopenharmony_ci
2041141cc406Sopenharmony_ci#define NVR_MAX_ADDRESS_SIZE	11
2042141cc406Sopenharmony_ci#define NVR_MAX_OPCODE_SIZE	3
2043141cc406Sopenharmony_ci#define NVR_DATA_SIZE		8
2044141cc406Sopenharmony_ci#define	NVR_MAX_COMMAND_SIZE	((NVR_MAX_ADDRESS_SIZE + \
2045141cc406Sopenharmony_ci				  NVR_MAX_OPCODE_SIZE + \
2046141cc406Sopenharmony_ci				  NVR_DATA_SIZE) * 2 + 1)
2047141cc406Sopenharmony_ci
2048141cc406Sopenharmony_cistatic int
2049141cc406Sopenharmony_cirt_nvram_enable_controller (int enable)
2050141cc406Sopenharmony_ci{
2051141cc406Sopenharmony_ci  unsigned char r;
2052141cc406Sopenharmony_ci
2053141cc406Sopenharmony_ci  if (rt_read_register_immediate (0x1d, 1, &r) < 0)
2054141cc406Sopenharmony_ci    return -1;
2055141cc406Sopenharmony_ci  if (enable)
2056141cc406Sopenharmony_ci    r |= 1;
2057141cc406Sopenharmony_ci  else
2058141cc406Sopenharmony_ci    r &= ~1;
2059141cc406Sopenharmony_ci  return rt_set_one_register (0x1d, r);
2060141cc406Sopenharmony_ci
2061141cc406Sopenharmony_ci}
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_cistatic int
2064141cc406Sopenharmony_cirt_nvram_init_command (void)
2065141cc406Sopenharmony_ci{
2066141cc406Sopenharmony_ci  unsigned char regs[13];
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci  if (rt_read_register_immediate (0x10, 13, regs) < 0)
2069141cc406Sopenharmony_ci    return -1;
2070141cc406Sopenharmony_ci  regs[2] |= 0xf0;
2071141cc406Sopenharmony_ci  regs[4] = (regs[4] & 0x1f) | 0x60;
2072141cc406Sopenharmony_ci  return rt_set_register_immediate (0x10, 13, regs);
2073141cc406Sopenharmony_ci}
2074141cc406Sopenharmony_ci
2075141cc406Sopenharmony_cistatic int
2076141cc406Sopenharmony_cirt_nvram_init_stdvars (int block, int *addrbits, unsigned char *basereg)
2077141cc406Sopenharmony_ci{
2078141cc406Sopenharmony_ci  int bitsneeded;
2079141cc406Sopenharmony_ci  int capacity;
2080141cc406Sopenharmony_ci
2081141cc406Sopenharmony_ci  switch (block)
2082141cc406Sopenharmony_ci    {
2083141cc406Sopenharmony_ci    case 0:
2084141cc406Sopenharmony_ci      bitsneeded = 7;
2085141cc406Sopenharmony_ci      break;
2086141cc406Sopenharmony_ci
2087141cc406Sopenharmony_ci    case 1:
2088141cc406Sopenharmony_ci      bitsneeded = 9;
2089141cc406Sopenharmony_ci      break;
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_ci    case 2:
2092141cc406Sopenharmony_ci      bitsneeded = 11;
2093141cc406Sopenharmony_ci      break;
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci    default:
2096141cc406Sopenharmony_ci      bitsneeded = 0;
2097141cc406Sopenharmony_ci      capacity = 1;
2098141cc406Sopenharmony_ci      while (capacity < block)
2099141cc406Sopenharmony_ci	capacity <<= 1, ++bitsneeded;
2100141cc406Sopenharmony_ci      break;
2101141cc406Sopenharmony_ci    }
2102141cc406Sopenharmony_ci
2103141cc406Sopenharmony_ci  *addrbits = bitsneeded;
2104141cc406Sopenharmony_ci
2105141cc406Sopenharmony_ci  if (rt_read_register_immediate (0x10, 1, basereg) < 0)
2106141cc406Sopenharmony_ci    return -1;
2107141cc406Sopenharmony_ci
2108141cc406Sopenharmony_ci  *basereg &= ~0x60;
2109141cc406Sopenharmony_ci  return 0;
2110141cc406Sopenharmony_ci}
2111141cc406Sopenharmony_ci
2112141cc406Sopenharmony_cistatic void
2113141cc406Sopenharmony_cirt_nvram_set_half_bit (unsigned char *buffer,
2114141cc406Sopenharmony_ci		       int value, unsigned char stdbits, int whichhalf)
2115141cc406Sopenharmony_ci{
2116141cc406Sopenharmony_ci  *buffer = stdbits | (value ? 0x40 : 0) | (whichhalf ? 0x20 : 0);
2117141cc406Sopenharmony_ci}
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_cistatic void
2120141cc406Sopenharmony_cirt_nvram_set_command_bit (unsigned char *buffer,
2121141cc406Sopenharmony_ci			  int value, unsigned char stdbits)
2122141cc406Sopenharmony_ci{
2123141cc406Sopenharmony_ci  rt_nvram_set_half_bit (buffer, value, stdbits, 0);
2124141cc406Sopenharmony_ci  rt_nvram_set_half_bit (buffer + 1, value, stdbits, 1);
2125141cc406Sopenharmony_ci}
2126141cc406Sopenharmony_ci
2127141cc406Sopenharmony_cistatic void
2128141cc406Sopenharmony_cirt_nvram_set_addressing_bits (unsigned char *buffer,
2129141cc406Sopenharmony_ci			      int location,
2130141cc406Sopenharmony_ci			      int addressingbits, unsigned char stdbits)
2131141cc406Sopenharmony_ci{
2132141cc406Sopenharmony_ci  int currentbit = 1 << (addressingbits - 1);
2133141cc406Sopenharmony_ci
2134141cc406Sopenharmony_ci  while (addressingbits--)
2135141cc406Sopenharmony_ci    {
2136141cc406Sopenharmony_ci      rt_nvram_set_command_bit (buffer,
2137141cc406Sopenharmony_ci				(location & currentbit) ? 1 : 0, stdbits);
2138141cc406Sopenharmony_ci      buffer += 2;
2139141cc406Sopenharmony_ci      currentbit >>= 1;
2140141cc406Sopenharmony_ci    }
2141141cc406Sopenharmony_ci}
2142141cc406Sopenharmony_ci
2143141cc406Sopenharmony_ci#if 0
2144141cc406Sopenharmony_cistatic int
2145141cc406Sopenharmony_cirt_nvram_enable_write (int addressingbits, int enable, unsigned char stdbits)
2146141cc406Sopenharmony_ci{
2147141cc406Sopenharmony_ci  unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE];
2148141cc406Sopenharmony_ci  int cmdsize = 6 + addressingbits * 2;
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer, 1, stdbits);
2151141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 2, 0, stdbits);
2152141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 4, 0, stdbits);
2153141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 6, enable, stdbits);
2154141cc406Sopenharmony_ci  if (addressingbits > 1)
2155141cc406Sopenharmony_ci    rt_nvram_set_addressing_bits (cmdbuffer + 8, 0, addressingbits - 1,
2156141cc406Sopenharmony_ci				  stdbits);
2157141cc406Sopenharmony_ci
2158141cc406Sopenharmony_ci  if (rt_nvram_enable_controller (1) < 0 ||
2159141cc406Sopenharmony_ci      rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0, cmdsize, cmdsize,
2160141cc406Sopenharmony_ci				 cmdbuffer, 0, 0) < 0
2161141cc406Sopenharmony_ci      || rt_nvram_enable_controller (0) < 0)
2162141cc406Sopenharmony_ci    {
2163141cc406Sopenharmony_ci      return -1;
2164141cc406Sopenharmony_ci    }
2165141cc406Sopenharmony_ci  return 0;
2166141cc406Sopenharmony_ci}
2167141cc406Sopenharmony_ci
2168141cc406Sopenharmony_cistatic int
2169141cc406Sopenharmony_cirt_nvram_write (int block, int location, char const *data, int bytes)
2170141cc406Sopenharmony_ci{
2171141cc406Sopenharmony_ci  int addressingbits;
2172141cc406Sopenharmony_ci  unsigned char stdbits;
2173141cc406Sopenharmony_ci  unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE];
2174141cc406Sopenharmony_ci  unsigned char *address_bits;
2175141cc406Sopenharmony_ci  unsigned char *data_bits;
2176141cc406Sopenharmony_ci  int cmdsize;
2177141cc406Sopenharmony_ci
2178141cc406Sopenharmony_ci  /* This routine doesn't appear to work, but I can't see anything wrong with it */
2179141cc406Sopenharmony_ci  if (rt_nvram_init_stdvars (block, &addressingbits, &stdbits) < 0)
2180141cc406Sopenharmony_ci    return -1;
2181141cc406Sopenharmony_ci
2182141cc406Sopenharmony_ci  cmdsize = (addressingbits + 8) * 2 + 6;
2183141cc406Sopenharmony_ci  address_bits = cmdbuffer + 6;
2184141cc406Sopenharmony_ci  data_bits = address_bits + (addressingbits * 2);
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer, 1, stdbits);
2187141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 2, 0, stdbits);
2188141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 4, 1, stdbits);
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_ci  if (rt_nvram_init_command () < 0 ||
2191141cc406Sopenharmony_ci      rt_nvram_enable_write (addressingbits, 1, stdbits) < 0)
2192141cc406Sopenharmony_ci    return -1;
2193141cc406Sopenharmony_ci
2194141cc406Sopenharmony_ci  while (bytes--)
2195141cc406Sopenharmony_ci    {
2196141cc406Sopenharmony_ci      int i;
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_ci      rt_nvram_set_addressing_bits (address_bits, location, addressingbits,
2199141cc406Sopenharmony_ci				    stdbits);
2200141cc406Sopenharmony_ci      rt_nvram_set_addressing_bits (data_bits, *data++, 8, stdbits);
2201141cc406Sopenharmony_ci
2202141cc406Sopenharmony_ci      if (rt_nvram_enable_controller (1) < 0 ||
2203141cc406Sopenharmony_ci	  rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0, cmdsize, cmdsize,
2204141cc406Sopenharmony_ci				     cmdbuffer, 0, 0) < 0
2205141cc406Sopenharmony_ci	  || rt_nvram_enable_controller (0) < 0)
2206141cc406Sopenharmony_ci	return -1;
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_ci      if (rt_nvram_enable_controller (1) < 0)
2209141cc406Sopenharmony_ci	return -1;
2210141cc406Sopenharmony_ci      for (i = 0; i < cmdsize; ++i)
2211141cc406Sopenharmony_ci	{
2212141cc406Sopenharmony_ci	  unsigned char r;
2213141cc406Sopenharmony_ci	  unsigned char cmd;
2214141cc406Sopenharmony_ci
2215141cc406Sopenharmony_ci	  rt_nvram_set_half_bit (&cmd, 0, stdbits, i & 1);
2216141cc406Sopenharmony_ci	  if (rt_send_command_immediate
2217141cc406Sopenharmony_ci	      (RTCMD_NVRAMCONTROL, 0, 1, 1, &cmd, 0, 0) < 0
2218141cc406Sopenharmony_ci	      || rt_read_register_immediate (0x10, 1, &r) < 0)
2219141cc406Sopenharmony_ci	    {
2220141cc406Sopenharmony_ci	      return -1;
2221141cc406Sopenharmony_ci	    }
2222141cc406Sopenharmony_ci	  else if (r & 0x80)
2223141cc406Sopenharmony_ci	    {
2224141cc406Sopenharmony_ci	      break;
2225141cc406Sopenharmony_ci	    }
2226141cc406Sopenharmony_ci	}
2227141cc406Sopenharmony_ci      if (rt_nvram_enable_controller (0) < 0)
2228141cc406Sopenharmony_ci	return -1;
2229141cc406Sopenharmony_ci
2230141cc406Sopenharmony_ci      ++location;
2231141cc406Sopenharmony_ci    }
2232141cc406Sopenharmony_ci
2233141cc406Sopenharmony_ci  if (rt_nvram_enable_write (addressingbits, 0, stdbits) < 0)
2234141cc406Sopenharmony_ci    return -1;
2235141cc406Sopenharmony_ci  return 0;
2236141cc406Sopenharmony_ci}
2237141cc406Sopenharmony_ci#endif
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_cistatic int
2240141cc406Sopenharmony_cirt_nvram_read (int block, int location, unsigned char *data, int bytes)
2241141cc406Sopenharmony_ci{
2242141cc406Sopenharmony_ci  int addressingbits;
2243141cc406Sopenharmony_ci  unsigned char stdbits;
2244141cc406Sopenharmony_ci  unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE];
2245141cc406Sopenharmony_ci  unsigned char *address_bits;
2246141cc406Sopenharmony_ci  unsigned char readbit_command[2];
2247141cc406Sopenharmony_ci  int cmdsize;
2248141cc406Sopenharmony_ci
2249141cc406Sopenharmony_ci  if (rt_nvram_init_stdvars (block, &addressingbits, &stdbits) < 0)
2250141cc406Sopenharmony_ci    return -1;
2251141cc406Sopenharmony_ci
2252141cc406Sopenharmony_ci  cmdsize = addressingbits * 2 + 7;
2253141cc406Sopenharmony_ci  address_bits = cmdbuffer + 6;
2254141cc406Sopenharmony_ci
2255141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer, 1, stdbits);
2256141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 2, 1, stdbits);
2257141cc406Sopenharmony_ci  rt_nvram_set_command_bit (cmdbuffer + 4, 0, stdbits);
2258141cc406Sopenharmony_ci  rt_nvram_set_half_bit (cmdbuffer + cmdsize - 1, 0, stdbits, 0);
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci  rt_nvram_set_half_bit (readbit_command, 0, stdbits, 1);
2261141cc406Sopenharmony_ci  rt_nvram_set_half_bit (readbit_command + 1, 0, stdbits, 0);
2262141cc406Sopenharmony_ci
2263141cc406Sopenharmony_ci  if (rt_nvram_init_command () < 0)
2264141cc406Sopenharmony_ci    return -1;
2265141cc406Sopenharmony_ci
2266141cc406Sopenharmony_ci  while (bytes--)
2267141cc406Sopenharmony_ci    {
2268141cc406Sopenharmony_ci      char c = 0;
2269141cc406Sopenharmony_ci      unsigned char r;
2270141cc406Sopenharmony_ci      int i;
2271141cc406Sopenharmony_ci
2272141cc406Sopenharmony_ci      rt_nvram_set_addressing_bits (address_bits, location, addressingbits,
2273141cc406Sopenharmony_ci				    stdbits);
2274141cc406Sopenharmony_ci
2275141cc406Sopenharmony_ci      if (rt_nvram_enable_controller (1) < 0 ||
2276141cc406Sopenharmony_ci	  rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0x1d, cmdsize,
2277141cc406Sopenharmony_ci				     cmdsize, cmdbuffer, 0, 0) < 0)
2278141cc406Sopenharmony_ci	return -1;
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_ci      for (i = 0; i < 8; ++i)
2281141cc406Sopenharmony_ci	{
2282141cc406Sopenharmony_ci	  c <<= 1;
2283141cc406Sopenharmony_ci
2284141cc406Sopenharmony_ci	  if (rt_send_command_immediate
2285141cc406Sopenharmony_ci	      (RTCMD_NVRAMCONTROL, 0x1d, 2, 2, readbit_command, 0, 0) < 0
2286141cc406Sopenharmony_ci	      || rt_read_register_immediate (0x10, 1, &r) < 0)
2287141cc406Sopenharmony_ci	    return -1;
2288141cc406Sopenharmony_ci	  if (r & 0x80)
2289141cc406Sopenharmony_ci	    c |= 1;
2290141cc406Sopenharmony_ci	}
2291141cc406Sopenharmony_ci      if (rt_nvram_enable_controller (0) < 0)
2292141cc406Sopenharmony_ci	return -1;
2293141cc406Sopenharmony_ci
2294141cc406Sopenharmony_ci      *data++ = c;
2295141cc406Sopenharmony_ci      ++location;
2296141cc406Sopenharmony_ci    }
2297141cc406Sopenharmony_ci  return 0;
2298141cc406Sopenharmony_ci}
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci/* This is what we want as the initial registers, not what they
2301141cc406Sopenharmony_ci * are at power on time. In particular 13 bytes at 0x10 are
2302141cc406Sopenharmony_ci * different, and the byte at 0x94 is different.
2303141cc406Sopenharmony_ci */
2304141cc406Sopenharmony_cistatic unsigned char initial_regs[] = {
2305141cc406Sopenharmony_ci  /* 0x00 */ 0xf5, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2306141cc406Sopenharmony_ci  /* 0x08 */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00,
2307141cc406Sopenharmony_ci  /* 0x10 */ 0x81, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
2308141cc406Sopenharmony_ci  /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
2309141cc406Sopenharmony_ci  /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2310141cc406Sopenharmony_ci  /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x19,
2311141cc406Sopenharmony_ci  /* 0x30 */ 0xd0, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2312141cc406Sopenharmony_ci  /* 0x38 */ 0x00, 0x00, 0xa0, 0x37, 0xff, 0x0f, 0x00, 0x00,
2313141cc406Sopenharmony_ci  /* 0x40 */ 0x80, 0x00, 0x00, 0x00, 0x8c, 0x76, 0x00, 0x00,
2314141cc406Sopenharmony_ci  /* 0x48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2315141cc406Sopenharmony_ci  /* 0x50 */ 0x20, 0xbc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
2316141cc406Sopenharmony_ci  /* 0x58 */ 0x1d, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
2317141cc406Sopenharmony_ci  /* 0x60 */ 0x5e, 0xea, 0x5f, 0xea, 0x00, 0x80, 0x64, 0x00,
2318141cc406Sopenharmony_ci  /* 0x68 */ 0x00, 0x00, 0x00, 0x00, 0x84, 0x04, 0x00, 0x00,
2319141cc406Sopenharmony_ci  /* 0x70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2320141cc406Sopenharmony_ci  /* 0x78 */ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2321141cc406Sopenharmony_ci  /* 0x80 */ 0x0f, 0x02, 0x4b, 0x02, 0x00, 0xec, 0x19, 0xd8,
2322141cc406Sopenharmony_ci  /* 0x88 */ 0x2d, 0x87, 0x02, 0xff, 0x3f, 0x78, 0x60, 0x00,
2323141cc406Sopenharmony_ci  /* 0x90 */ 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
2324141cc406Sopenharmony_ci  /* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2325141cc406Sopenharmony_ci  /* 0xa0 */ 0x00, 0x00, 0x00, 0x0c, 0x27, 0x64, 0x00, 0x00,
2326141cc406Sopenharmony_ci  /* 0xa8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2327141cc406Sopenharmony_ci  /* 0xb0 */ 0x12, 0x08, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00,
2328141cc406Sopenharmony_ci  /* 0xb8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2329141cc406Sopenharmony_ci  /* 0xc0 */ 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00,
2330141cc406Sopenharmony_ci  /* 0xc8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2331141cc406Sopenharmony_ci  /* 0xd0 */ 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
2332141cc406Sopenharmony_ci  /* 0xd8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2333141cc406Sopenharmony_ci  /* 0xe0 */ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
2334141cc406Sopenharmony_ci  /* 0xe8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2335141cc406Sopenharmony_ci  /* 0xf0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2336141cc406Sopenharmony_ci  /* 0xf8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2337141cc406Sopenharmony_ci};
2338141cc406Sopenharmony_ci
2339141cc406Sopenharmony_ci#define RT_NORMAL_TG 0
2340141cc406Sopenharmony_ci#define RT_DOUBLE_TG 1
2341141cc406Sopenharmony_ci#define RT_TRIPLE_TG 2
2342141cc406Sopenharmony_ci#define RT_DDOUBLE_TG 3
2343141cc406Sopenharmony_ci#define RT_300_TG 4
2344141cc406Sopenharmony_ci#define RT_150_TG 5
2345141cc406Sopenharmony_ci#define RT_TEST_TG 6
2346141cc406Sopenharmony_cistatic struct tg_info__
2347141cc406Sopenharmony_ci{
2348141cc406Sopenharmony_ci  int tg_cph0p;
2349141cc406Sopenharmony_ci  int tg_crsp;
2350141cc406Sopenharmony_ci  int tg_cclpp;
2351141cc406Sopenharmony_ci  int tg_cph0s;
2352141cc406Sopenharmony_ci  int tg_cdss1;
2353141cc406Sopenharmony_ci  int tg_cdsc1;
2354141cc406Sopenharmony_ci  int tg_cdss2;
2355141cc406Sopenharmony_ci  int tg_cdsc2;
2356141cc406Sopenharmony_ci} tg_info[] =
2357141cc406Sopenharmony_ci{
2358141cc406Sopenharmony_ci  /* CPH              CCD Shifting Clock
2359141cc406Sopenharmony_ci   *    0P            ??? Perhaps CCD rising edge position
2360141cc406Sopenharmony_ci   *    0S            ???
2361141cc406Sopenharmony_ci   * CRS              Reset CCD Clock
2362141cc406Sopenharmony_ci   *    P             ??? Perhaps CCD falling edge position
2363141cc406Sopenharmony_ci   * CCLP             CCD Clamp Clock
2364141cc406Sopenharmony_ci   *     P            ???
2365141cc406Sopenharmony_ci   * CDS              ???
2366141cc406Sopenharmony_ci   *    S1            ???
2367141cc406Sopenharmony_ci   *    S2            ???
2368141cc406Sopenharmony_ci   *    C1            ???
2369141cc406Sopenharmony_ci   *    C2            ???
2370141cc406Sopenharmony_ci   */
2371141cc406Sopenharmony_ci  /*CPH0P     CRSP      CCLPP     CPH0S CDSS1 CDSC1 CDSS2 CDSC2 */
2372141cc406Sopenharmony_ci  {
2373141cc406Sopenharmony_ci  0x01FFE0, 0x3c0000, 0x003000, 1, 0xb, 0xd, 0x00, 0x01},	/* NORMAL */
2374141cc406Sopenharmony_ci  {
2375141cc406Sopenharmony_ci  0x7ff800, 0xf00000, 0x01c000, 0, 0xb, 0xc, 0x14, 0x15},	/* DOUBLE */
2376141cc406Sopenharmony_ci  {
2377141cc406Sopenharmony_ci  0x033fcc, 0x300000, 0x060000, 1, 0x8, 0xa, 0x00, 0x01},	/* TRIPLE */
2378141cc406Sopenharmony_ci  {
2379141cc406Sopenharmony_ci  0x028028, 0x300000, 0x060000, 1, 0x8, 0xa, 0x00, 0x01},	/* DDOUBLE */
2380141cc406Sopenharmony_ci  {
2381141cc406Sopenharmony_ci  0x7ff800, 0x030000, 0x060000, 0, 0xa, 0xc, 0x17, 0x01},	/* 300 */
2382141cc406Sopenharmony_ci  {
2383141cc406Sopenharmony_ci  0x7fc700, 0x030000, 0x060000, 0, 0x7, 0x9, 0x17, 0x01},	/* 150 */
2384141cc406Sopenharmony_ci  {
2385141cc406Sopenharmony_ci  0x7ff800, 0x300000, 0x060000, 0, 0xa, 0xc, 0x17, 0x01},	/* TEST */
2386141cc406Sopenharmony_ci};
2387141cc406Sopenharmony_ci
2388141cc406Sopenharmony_cistruct resolution_parameters
2389141cc406Sopenharmony_ci{
2390141cc406Sopenharmony_ci  unsigned resolution;
2391141cc406Sopenharmony_ci  int reg_39_value;
2392141cc406Sopenharmony_ci  int reg_c3_value;
2393141cc406Sopenharmony_ci  int reg_c6_value;
2394141cc406Sopenharmony_ci  int scan_frequency;
2395141cc406Sopenharmony_ci  int cph0s;
2396141cc406Sopenharmony_ci  int red_green_offset;
2397141cc406Sopenharmony_ci  int green_blue_offset;
2398141cc406Sopenharmony_ci  int intra_channel_offset;
2399141cc406Sopenharmony_ci  int motor_movement_clock_multiplier;
2400141cc406Sopenharmony_ci  int d3_bit_3_value;
2401141cc406Sopenharmony_ci  int tg;
2402141cc406Sopenharmony_ci  int step_size;
2403141cc406Sopenharmony_ci};
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci/* The TG value sets seem to affect the exposure time:
2406141cc406Sopenharmony_ci * At 200dpi:
2407141cc406Sopenharmony_ci * NORMAL gets higher values than DOUBLE
2408141cc406Sopenharmony_ci * DDOUBLE gives a crazy spike in the data
2409141cc406Sopenharmony_ci * TRIPLE gives a black result
2410141cc406Sopenharmony_ci * TEST gives a black result
2411141cc406Sopenharmony_ci * 300 gives a black result
2412141cc406Sopenharmony_ci * 150 gives a black result
2413141cc406Sopenharmony_ci */
2414141cc406Sopenharmony_ci
2415141cc406Sopenharmony_cistatic struct resolution_parameters resparms[] = {
2416141cc406Sopenharmony_ci  /* Acceptable values for stepsz are:
2417141cc406Sopenharmony_ci   * 0x157b 0xabd, 0x55e, 0x2af, 0x157, 0xab, 0x55
2418141cc406Sopenharmony_ci   */
2419141cc406Sopenharmony_ci  /* My values - all work */
2420141cc406Sopenharmony_ci  /*res   r39 rC3 rC6 freq cph0s rgo gbo intra mmcm d3 tg            stepsz */
2421141cc406Sopenharmony_ci  {1200, 3, 6, 4, 2, 1, 22, 22, 4, 2, 1, RT_NORMAL_TG, 0x157b},
2422141cc406Sopenharmony_ci  {600, 15, 6, 4, 1, 1, 9, 10, 0, 2, 1, RT_NORMAL_TG, 0x055e},
2423141cc406Sopenharmony_ci  {400, 3, 1, 4, 1, 1, 6, 6, 1, 2, 1, RT_NORMAL_TG, 0x157b},
2424141cc406Sopenharmony_ci  {300, 15, 3, 4, 1, 1, 5, 4, 0, 2, 1, RT_NORMAL_TG, 0x02af},
2425141cc406Sopenharmony_ci  {200, 7, 1, 4, 1, 1, 3, 3, 0, 2, 1, RT_NORMAL_TG, 0x055e},
2426141cc406Sopenharmony_ci  {150, 15, 3, 1, 1, 1, 2, 2, 0, 2, 1, RT_NORMAL_TG, 0x02af},
2427141cc406Sopenharmony_ci  {100, 3, 1, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x0abd},
2428141cc406Sopenharmony_ci  {75, 15, 3, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x02af},
2429141cc406Sopenharmony_ci  {50, 15, 1, 1, 1, 1, 0, 0, 0, 2, 1, RT_NORMAL_TG, 0x055e},
2430141cc406Sopenharmony_ci  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
2431141cc406Sopenharmony_ci};
2432141cc406Sopenharmony_ci
2433141cc406Sopenharmony_cistruct dcalibdata
2434141cc406Sopenharmony_ci{
2435141cc406Sopenharmony_ci  unsigned char *buffers[3];
2436141cc406Sopenharmony_ci  int pixelsperrow;
2437141cc406Sopenharmony_ci  int pixelnow;
2438141cc406Sopenharmony_ci  int channelnow;
2439141cc406Sopenharmony_ci  int firstrowdone;
2440141cc406Sopenharmony_ci};
2441141cc406Sopenharmony_ci
2442141cc406Sopenharmony_cistatic void dump_registers (unsigned char const *);
2443141cc406Sopenharmony_cistatic int
2444141cc406Sopenharmony_cirts8801_rewind (void)
2445141cc406Sopenharmony_ci{
2446141cc406Sopenharmony_ci  unsigned char regs[255];
2447141cc406Sopenharmony_ci  int n;
2448141cc406Sopenharmony_ci  int tg_setting = RT_DOUBLE_TG;
2449141cc406Sopenharmony_ci
2450141cc406Sopenharmony_ci  rt_read_register_immediate (0, 255, regs);
2451141cc406Sopenharmony_ci
2452141cc406Sopenharmony_ci  rt_set_noscan_distance (regs, 59998);
2453141cc406Sopenharmony_ci  rt_set_total_distance (regs, 59999);
2454141cc406Sopenharmony_ci
2455141cc406Sopenharmony_ci  rt_set_stop_when_rewound (regs, 0);
2456141cc406Sopenharmony_ci
2457141cc406Sopenharmony_ci  rt_set_one_register (0xc6, 0);
2458141cc406Sopenharmony_ci  rt_set_one_register (0xc6, 0);
2459141cc406Sopenharmony_ci
2460141cc406Sopenharmony_ci
2461141cc406Sopenharmony_ci  rt_set_direction_rewind (regs);
2462141cc406Sopenharmony_ci
2463141cc406Sopenharmony_ci  rt_set_step_size (regs, 0x55);
2464141cc406Sopenharmony_ci  regs[0x39] = 3;
2465141cc406Sopenharmony_ci  regs[0xc3] = (regs[0xc3] & 0xf8) | 0x86;
2466141cc406Sopenharmony_ci  regs[0xc6] = (regs[0xc6] & 0xf8) | 4;
2467141cc406Sopenharmony_ci
2468141cc406Sopenharmony_ci  rt_set_horizontal_resolution (regs, 25);
2469141cc406Sopenharmony_ci  rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p);
2470141cc406Sopenharmony_ci  rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp);
2471141cc406Sopenharmony_ci  rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp);
2472141cc406Sopenharmony_ci  rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1,
2473141cc406Sopenharmony_ci	       tg_info[tg_setting].tg_cdss2);
2474141cc406Sopenharmony_ci  rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1,
2475141cc406Sopenharmony_ci	       tg_info[tg_setting].tg_cdsc2);
2476141cc406Sopenharmony_ci  rt_update_after_setting_cdss2 (regs);
2477141cc406Sopenharmony_ci  rt_set_cvtr_wparams (regs, 3, 0, 6);
2478141cc406Sopenharmony_ci  rt_set_cvtr_mpt (regs, 15, 15, 15);
2479141cc406Sopenharmony_ci  rt_set_cvtr_lm (regs, 7, 7, 7);
2480141cc406Sopenharmony_ci  rt_set_motor_type (regs, 2);
2481141cc406Sopenharmony_ci
2482141cc406Sopenharmony_ci  if (DBG_LEVEL >= 5)
2483141cc406Sopenharmony_ci    dump_registers (regs);
2484141cc406Sopenharmony_ci
2485141cc406Sopenharmony_ci  rt_set_all_registers (regs);
2486141cc406Sopenharmony_ci  rt_set_one_register (0x2c, regs[0x2c]);
2487141cc406Sopenharmony_ci
2488141cc406Sopenharmony_ci  rt_start_moving ();
2489141cc406Sopenharmony_ci
2490141cc406Sopenharmony_ci  while (!rt_is_rewound () &&
2491141cc406Sopenharmony_ci	 ((n = rt_get_available_bytes ()) > 0 || rt_is_moving () > 0))
2492141cc406Sopenharmony_ci    {
2493141cc406Sopenharmony_ci      if (n)
2494141cc406Sopenharmony_ci	{
2495141cc406Sopenharmony_ci	  char buffer[0xffc0];
2496141cc406Sopenharmony_ci
2497141cc406Sopenharmony_ci	  if (n > (int) sizeof (buffer))
2498141cc406Sopenharmony_ci	    n = sizeof (buffer);
2499141cc406Sopenharmony_ci	  rt_get_data (n, buffer);
2500141cc406Sopenharmony_ci	}
2501141cc406Sopenharmony_ci      else
2502141cc406Sopenharmony_ci	{
2503141cc406Sopenharmony_ci	  usleep (10000);
2504141cc406Sopenharmony_ci	}
2505141cc406Sopenharmony_ci    }
2506141cc406Sopenharmony_ci
2507141cc406Sopenharmony_ci  rt_stop_moving ();
2508141cc406Sopenharmony_ci  return 0;
2509141cc406Sopenharmony_ci}
2510141cc406Sopenharmony_ci
2511141cc406Sopenharmony_cistatic int cancelled_scan = 0;
2512141cc406Sopenharmony_ci
2513141cc406Sopenharmony_cistatic unsigned
2514141cc406Sopenharmony_ciget_lsbfirst_int (unsigned char const *p, int n)
2515141cc406Sopenharmony_ci{
2516141cc406Sopenharmony_ci  unsigned value = *p++;
2517141cc406Sopenharmony_ci  int shift = 8;
2518141cc406Sopenharmony_ci
2519141cc406Sopenharmony_ci  while (--n)
2520141cc406Sopenharmony_ci    {
2521141cc406Sopenharmony_ci      unsigned now = *p++;
2522141cc406Sopenharmony_ci      value |= now << shift;
2523141cc406Sopenharmony_ci      shift += 8;
2524141cc406Sopenharmony_ci    }
2525141cc406Sopenharmony_ci  return value;
2526141cc406Sopenharmony_ci}
2527141cc406Sopenharmony_ci
2528141cc406Sopenharmony_cistatic int
2529141cc406Sopenharmony_ciconvert_c6 (int i)
2530141cc406Sopenharmony_ci{
2531141cc406Sopenharmony_ci  switch (i)
2532141cc406Sopenharmony_ci    {
2533141cc406Sopenharmony_ci    case 3:
2534141cc406Sopenharmony_ci      return 1;
2535141cc406Sopenharmony_ci
2536141cc406Sopenharmony_ci    case 1:
2537141cc406Sopenharmony_ci      return 2;
2538141cc406Sopenharmony_ci
2539141cc406Sopenharmony_ci    case 4:
2540141cc406Sopenharmony_ci      return 4;
2541141cc406Sopenharmony_ci    }
2542141cc406Sopenharmony_ci  return -1;
2543141cc406Sopenharmony_ci}
2544141cc406Sopenharmony_ci
2545141cc406Sopenharmony_cistatic void
2546141cc406Sopenharmony_cidump_registers (unsigned char const *regs)
2547141cc406Sopenharmony_ci{
2548141cc406Sopenharmony_ci  int i = 0;
2549141cc406Sopenharmony_ci  long pixels;
2550141cc406Sopenharmony_ci
2551141cc406Sopenharmony_ci  DBG (5, "Scan commencing with registers:\n");
2552141cc406Sopenharmony_ci  while (i < 255)
2553141cc406Sopenharmony_ci    {
2554141cc406Sopenharmony_ci      int j = 0;
2555141cc406Sopenharmony_ci      char buffer[80];
2556141cc406Sopenharmony_ci
2557141cc406Sopenharmony_ci      buffer[0] = 0;
2558141cc406Sopenharmony_ci
2559141cc406Sopenharmony_ci      sprintf (buffer + strlen (buffer), "%02x:", i);
2560141cc406Sopenharmony_ci      while (j < 8)
2561141cc406Sopenharmony_ci	{
2562141cc406Sopenharmony_ci	  sprintf (buffer + strlen (buffer), " %02x", regs[i++]);
2563141cc406Sopenharmony_ci	  j++;
2564141cc406Sopenharmony_ci	}
2565141cc406Sopenharmony_ci      sprintf (buffer + strlen (buffer), " -");
2566141cc406Sopenharmony_ci      while (j++ < 16 && i < 255)
2567141cc406Sopenharmony_ci	sprintf (buffer + strlen (buffer), " %02x", regs[i++]);
2568141cc406Sopenharmony_ci      DBG (5, "    %s\n", buffer);
2569141cc406Sopenharmony_ci    }
2570141cc406Sopenharmony_ci
2571141cc406Sopenharmony_ci  DBG (5, "  Position:\n");
2572141cc406Sopenharmony_ci  DBG (5, "    Distance without scanning:       %u\n",
2573141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0x60, 2));
2574141cc406Sopenharmony_ci  DBG (5, "    Total distance:                  %u\n",
2575141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0x62, 2));
2576141cc406Sopenharmony_ci  DBG (5, "    Scanning distance:               %u\n",
2577141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0x62, 2) - get_lsbfirst_int (regs + 0x60, 2));
2578141cc406Sopenharmony_ci  DBG (5, "    Direction:                       %s\n",
2579141cc406Sopenharmony_ci       (regs[0xc6] & 0x08) ? "forward" : "rewind");
2580141cc406Sopenharmony_ci  DBG (5, "    Motor:                           %s\n",
2581141cc406Sopenharmony_ci       (regs[0xc3] & 0x80) ? "enabled" : "disabled");
2582141cc406Sopenharmony_ci  if (regs[0x7a])
2583141cc406Sopenharmony_ci    DBG (5, "    X range:                         %u-%u\n",
2584141cc406Sopenharmony_ci	 get_lsbfirst_int (regs + 0x66, 2) / regs[0x7a],
2585141cc406Sopenharmony_ci	 get_lsbfirst_int (regs + 0x6c, 2) / regs[0x7a]);
2586141cc406Sopenharmony_ci  DBG (5, "  TG Info:\n");
2587141cc406Sopenharmony_ci  DBG (5, "    CPH0P:                           %06x\n",
2588141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0xf0, 3));
2589141cc406Sopenharmony_ci  DBG (5, "    CRSP:                            %06x\n",
2590141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0xf9, 3));
2591141cc406Sopenharmony_ci  DBG (5, "    CCLPP:                           %06x\n",
2592141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0xfc, 3));
2593141cc406Sopenharmony_ci  DBG (5, "    CPH0S:                           %d\n",
2594141cc406Sopenharmony_ci       (regs[0x2d] & 0x20) ? 1 : 0);
2595141cc406Sopenharmony_ci  DBG (5, "    CDSS1:                           %02x\n", regs[0x28] & 0x1f);
2596141cc406Sopenharmony_ci  DBG (5, "    CDSC1:                           %02x\n", regs[0x29] & 0x1f);
2597141cc406Sopenharmony_ci  DBG (5, "    CDSS2:                           %02x\n", regs[0x2a] & 0x1f);
2598141cc406Sopenharmony_ci  DBG (5, "    CDSC2:                           %02x\n", regs[0x2b] & 0x1f);
2599141cc406Sopenharmony_ci
2600141cc406Sopenharmony_ci  DBG (5, "  Resolution specific:\n");
2601141cc406Sopenharmony_ci  if (!regs[0x7a])
2602141cc406Sopenharmony_ci    DBG (5, "    Horizontal resolution:           Denominator is zero!\n");
2603141cc406Sopenharmony_ci  else
2604141cc406Sopenharmony_ci    DBG (5, "    Horizontal resolution:           %u\n", 300
2605141cc406Sopenharmony_ci	 * ((regs[0x2d] & 0x20) ? 2 : 1)
2606141cc406Sopenharmony_ci	 * ((regs[0xd3] & 0x08) ? 2 : 1) / regs[0x7a]);
2607141cc406Sopenharmony_ci  DBG (5, "    Derived vertical resolution:     %u\n",
2608141cc406Sopenharmony_ci       400 * (regs[0xc3] & 0x1f) * convert_c6 (regs[0xc6] & 0x7) /
2609141cc406Sopenharmony_ci       (regs[0x39] + 1));
2610141cc406Sopenharmony_ci  DBG (5, "    Register D3:3                    %u\n",
2611141cc406Sopenharmony_ci       (regs[0xd3] & 0x08) ? 1 : 0);
2612141cc406Sopenharmony_ci  DBG (5, "    Register 39:                     %u\n", regs[0x39]);
2613141cc406Sopenharmony_ci  DBG (5, "    Register C3:0-5:                 %u\n", regs[0xc3] & 0x1f);
2614141cc406Sopenharmony_ci  DBG (5, "    Register C6:0-2:                 %u\n", regs[0xc6] & 0x7);
2615141cc406Sopenharmony_ci  DBG (5, "    Motor movement clock multiplier: %u\n", regs[0x40] >> 6);
2616141cc406Sopenharmony_ci  DBG (5, "    Step Size:                       %04x\n",
2617141cc406Sopenharmony_ci       get_lsbfirst_int (regs + 0xe2, 2));
2618141cc406Sopenharmony_ci  DBG (5, "    Frequency:                       %u\n", regs[0x64] & 0xf);
2619141cc406Sopenharmony_ci  DBG (5, "  Colour registers\n");
2620141cc406Sopenharmony_ci  DBG (5, "    Register 2F:                     %02x\n", regs[0x2f]);
2621141cc406Sopenharmony_ci  DBG (5, "    Register 2C:                     %02x\n", regs[0x2c]);
2622141cc406Sopenharmony_ci  if (regs[0x7a])
2623141cc406Sopenharmony_ci    {
2624141cc406Sopenharmony_ci      DBG (5, "  Scan data estimates:\n");
2625141cc406Sopenharmony_ci      pixels =
2626141cc406Sopenharmony_ci	(long) (get_lsbfirst_int (regs + 0x62, 2) -
2627141cc406Sopenharmony_ci		get_lsbfirst_int (regs + 0x60,
2628141cc406Sopenharmony_ci				  2)) * (long) (get_lsbfirst_int (regs + 0x6c,
2629141cc406Sopenharmony_ci								  2) -
2630141cc406Sopenharmony_ci						get_lsbfirst_int (regs + 0x66,
2631141cc406Sopenharmony_ci								  2)) /
2632141cc406Sopenharmony_ci	regs[0x7a];
2633141cc406Sopenharmony_ci      DBG (5, "    Pixels:                          %ld\n", pixels);
2634141cc406Sopenharmony_ci      DBG (5, "    Bytes at 24BPP:                  %ld\n", pixels * 3);
2635141cc406Sopenharmony_ci      DBG (5, "    Bytes at 1BPP:                   %ld\n", pixels / 8);
2636141cc406Sopenharmony_ci    }
2637141cc406Sopenharmony_ci  DBG (5, "\n");
2638141cc406Sopenharmony_ci}
2639141cc406Sopenharmony_ci
2640141cc406Sopenharmony_cistatic int
2641141cc406Sopenharmony_ciconstrain (int val, int min, int max)
2642141cc406Sopenharmony_ci{
2643141cc406Sopenharmony_ci  if (val < min)
2644141cc406Sopenharmony_ci    {
2645141cc406Sopenharmony_ci      DBG (10, "Clipped %d to %d\n", val, min);
2646141cc406Sopenharmony_ci      val = min;
2647141cc406Sopenharmony_ci    }
2648141cc406Sopenharmony_ci  else if (val > max)
2649141cc406Sopenharmony_ci    {
2650141cc406Sopenharmony_ci      DBG (10, "Clipped %d to %d\n", val, max);
2651141cc406Sopenharmony_ci      val = max;
2652141cc406Sopenharmony_ci    }
2653141cc406Sopenharmony_ci  return val;
2654141cc406Sopenharmony_ci}
2655141cc406Sopenharmony_ci
2656141cc406Sopenharmony_ci#if 0
2657141cc406Sopenharmony_cistatic void
2658141cc406Sopenharmony_cisram_dump_byte(FILE *fp,
2659141cc406Sopenharmony_ci               unsigned char const *left,
2660141cc406Sopenharmony_ci               unsigned leftstart,
2661141cc406Sopenharmony_ci               unsigned leftlimit,
2662141cc406Sopenharmony_ci               unsigned char const *right,
2663141cc406Sopenharmony_ci               unsigned rightstart,
2664141cc406Sopenharmony_ci               unsigned rightlimit,
2665141cc406Sopenharmony_ci               unsigned idx)
2666141cc406Sopenharmony_ci{
2667141cc406Sopenharmony_ci  unsigned ridx = rightstart + idx;
2668141cc406Sopenharmony_ci  unsigned lidx = leftstart + idx;
2669141cc406Sopenharmony_ci
2670141cc406Sopenharmony_ci  putc(' ', fp);
2671141cc406Sopenharmony_ci  if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx])
2672141cc406Sopenharmony_ci    fputs("<b>", fp);
2673141cc406Sopenharmony_ci  if (leftstart < leftlimit)
2674141cc406Sopenharmony_ci    fprintf(fp, "%02x", left[lidx]);
2675141cc406Sopenharmony_ci  else
2676141cc406Sopenharmony_ci    fputs("  ", fp);
2677141cc406Sopenharmony_ci  if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx])
2678141cc406Sopenharmony_ci    fputs("</b>", fp);
2679141cc406Sopenharmony_ci}
2680141cc406Sopenharmony_ci
2681141cc406Sopenharmony_cistatic void
2682141cc406Sopenharmony_cidump_sram_to_file(char const *fname,
2683141cc406Sopenharmony_ci                  unsigned char const *expected,
2684141cc406Sopenharmony_ci                  unsigned end_calibration_offset)
2685141cc406Sopenharmony_ci{
2686141cc406Sopenharmony_ci  FILE *fp = fopen(fname, "w");
2687141cc406Sopenharmony_ci  rt_set_sram_page(0);
2688141cc406Sopenharmony_ci
2689141cc406Sopenharmony_ci  if (fp)
2690141cc406Sopenharmony_ci    {
2691141cc406Sopenharmony_ci      unsigned char buf[1024];
2692141cc406Sopenharmony_ci      unsigned loc = 0;
2693141cc406Sopenharmony_ci
2694141cc406Sopenharmony_ci      fprintf(fp, "<html><head></head><body><pre>\n");
2695141cc406Sopenharmony_ci      while (loc < end_calibration_offset)
2696141cc406Sopenharmony_ci        {
2697141cc406Sopenharmony_ci          unsigned byte = 0;
2698141cc406Sopenharmony_ci
2699141cc406Sopenharmony_ci          rt_read_sram(1024, buf);
2700141cc406Sopenharmony_ci
2701141cc406Sopenharmony_ci          while (byte < 1024)
2702141cc406Sopenharmony_ci            {
2703141cc406Sopenharmony_ci              unsigned idx = 0;
2704141cc406Sopenharmony_ci
2705141cc406Sopenharmony_ci              fprintf(fp, "%06x:", loc);
2706141cc406Sopenharmony_ci              do
2707141cc406Sopenharmony_ci                {
2708141cc406Sopenharmony_ci		  sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx);
2709141cc406Sopenharmony_ci                } while (++idx & 0x7);
2710141cc406Sopenharmony_ci              fprintf(fp, " -");
2711141cc406Sopenharmony_ci              do
2712141cc406Sopenharmony_ci                {
2713141cc406Sopenharmony_ci		  sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx);
2714141cc406Sopenharmony_ci                } while (++idx & 0x7);
2715141cc406Sopenharmony_ci
2716141cc406Sopenharmony_ci              idx = 0;
2717141cc406Sopenharmony_ci              fputs("     ", fp);
2718141cc406Sopenharmony_ci
2719141cc406Sopenharmony_ci              do
2720141cc406Sopenharmony_ci                {
2721141cc406Sopenharmony_ci                  sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx);
2722141cc406Sopenharmony_ci                } while (++idx & 0x7);
2723141cc406Sopenharmony_ci              fprintf(fp, " -");
2724141cc406Sopenharmony_ci              do
2725141cc406Sopenharmony_ci                {
2726141cc406Sopenharmony_ci                  sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx);
2727141cc406Sopenharmony_ci                } while (++idx & 0x7);
2728141cc406Sopenharmony_ci
2729141cc406Sopenharmony_ci
2730141cc406Sopenharmony_ci              fputs("\n", fp);
2731141cc406Sopenharmony_ci              byte += 16;
2732141cc406Sopenharmony_ci              loc += 16;
2733141cc406Sopenharmony_ci            }
2734141cc406Sopenharmony_ci        }
2735141cc406Sopenharmony_ci      fprintf(fp, "</pre></body></html>");
2736141cc406Sopenharmony_ci      fclose(fp);
2737141cc406Sopenharmony_ci    }
2738141cc406Sopenharmony_ci}
2739141cc406Sopenharmony_ci#endif
2740141cc406Sopenharmony_ci
2741141cc406Sopenharmony_cistatic int
2742141cc406Sopenharmony_cirts8801_doscan (unsigned width,
2743141cc406Sopenharmony_ci		unsigned height,
2744141cc406Sopenharmony_ci		unsigned colour,
2745141cc406Sopenharmony_ci		unsigned red_green_offset,
2746141cc406Sopenharmony_ci		unsigned green_blue_offset,
2747141cc406Sopenharmony_ci		unsigned intra_channel_offset,
2748141cc406Sopenharmony_ci		rts8801_callback cbfunc,
2749141cc406Sopenharmony_ci		void *params,
2750141cc406Sopenharmony_ci		int oddfirst,
2751141cc406Sopenharmony_ci		unsigned char const *calib_info,
2752141cc406Sopenharmony_ci		int merged_channels,
2753141cc406Sopenharmony_ci		double *postprocess_offsets,
2754141cc406Sopenharmony_ci		double *postprocess_gains)
2755141cc406Sopenharmony_ci{
2756141cc406Sopenharmony_ci  unsigned rowbytes = 0;
2757141cc406Sopenharmony_ci  unsigned output_rowbytes = 0;
2758141cc406Sopenharmony_ci  unsigned channels = 0;
2759141cc406Sopenharmony_ci  unsigned total_rows = 0;
2760141cc406Sopenharmony_ci  unsigned char *row_buffer;
2761141cc406Sopenharmony_ci  unsigned char *output_buffer;
2762141cc406Sopenharmony_ci  unsigned buffered_rows;
2763141cc406Sopenharmony_ci  int rows_to_begin;
2764141cc406Sopenharmony_ci  int rowbuffer_bytes;
2765141cc406Sopenharmony_ci  int n;
2766141cc406Sopenharmony_ci  unsigned rownow = 0;
2767141cc406Sopenharmony_ci  unsigned bytenow = 0;
2768141cc406Sopenharmony_ci  unsigned char *channel_data[3][2];
2769141cc406Sopenharmony_ci  unsigned i;
2770141cc406Sopenharmony_ci  unsigned j;
2771141cc406Sopenharmony_ci  int result = 0;
2772141cc406Sopenharmony_ci  unsigned rows_supplied = 0;
2773141cc406Sopenharmony_ci
2774141cc406Sopenharmony_ci  (void) calib_info;		/* Kill warning */
2775141cc406Sopenharmony_ci  if (cancelled_scan)
2776141cc406Sopenharmony_ci    return -1;
2777141cc406Sopenharmony_ci  rt_start_moving ();
2778141cc406Sopenharmony_ci
2779141cc406Sopenharmony_ci  channels = 3;
2780141cc406Sopenharmony_ci  rowbytes = width * 3;
2781141cc406Sopenharmony_ci
2782141cc406Sopenharmony_ci  switch (colour)
2783141cc406Sopenharmony_ci    {
2784141cc406Sopenharmony_ci    case HP3500_GRAY_SCAN:
2785141cc406Sopenharmony_ci      output_rowbytes = width;
2786141cc406Sopenharmony_ci      break;
2787141cc406Sopenharmony_ci
2788141cc406Sopenharmony_ci    case HP3500_COLOR_SCAN:
2789141cc406Sopenharmony_ci      output_rowbytes = rowbytes;
2790141cc406Sopenharmony_ci      break;
2791141cc406Sopenharmony_ci
2792141cc406Sopenharmony_ci    case HP3500_LINEART_SCAN:
2793141cc406Sopenharmony_ci      output_rowbytes = (width + 7) / 8;
2794141cc406Sopenharmony_ci      break;
2795141cc406Sopenharmony_ci    }
2796141cc406Sopenharmony_ci
2797141cc406Sopenharmony_ci  buffered_rows =
2798141cc406Sopenharmony_ci    red_green_offset + green_blue_offset + intra_channel_offset + 1;
2799141cc406Sopenharmony_ci  rows_to_begin = buffered_rows;
2800141cc406Sopenharmony_ci  rowbuffer_bytes = buffered_rows * rowbytes;
2801141cc406Sopenharmony_ci  row_buffer = (unsigned char *) malloc (rowbuffer_bytes);
2802141cc406Sopenharmony_ci  output_buffer = (unsigned char *) malloc (rowbytes);
2803141cc406Sopenharmony_ci
2804141cc406Sopenharmony_ci  for (i = j = 0; i < channels; ++i)
2805141cc406Sopenharmony_ci    {
2806141cc406Sopenharmony_ci      if (i == 1)
2807141cc406Sopenharmony_ci	j += red_green_offset;
2808141cc406Sopenharmony_ci      else if (i == 2)
2809141cc406Sopenharmony_ci	j += green_blue_offset;
2810141cc406Sopenharmony_ci      if (merged_channels)
2811141cc406Sopenharmony_ci	channel_data[i][1 - oddfirst] = row_buffer + rowbytes * j + i;
2812141cc406Sopenharmony_ci      else
2813141cc406Sopenharmony_ci	channel_data[i][1 - oddfirst] = row_buffer + rowbytes * j + width * i;
2814141cc406Sopenharmony_ci      channel_data[i][oddfirst] =
2815141cc406Sopenharmony_ci	channel_data[i][1 - oddfirst] + rowbytes * intra_channel_offset;
2816141cc406Sopenharmony_ci    }
2817141cc406Sopenharmony_ci
2818141cc406Sopenharmony_ci  while (((n = rt_get_available_bytes ()) > 0 || rt_is_moving () > 0)
2819141cc406Sopenharmony_ci	 && !cancelled_scan)
2820141cc406Sopenharmony_ci    {
2821141cc406Sopenharmony_ci      if (n == 1 && (rt_is_moving () || rt_get_available_bytes () != 1))
2822141cc406Sopenharmony_ci	n = 0;
2823141cc406Sopenharmony_ci      if (n > 0)
2824141cc406Sopenharmony_ci	{
2825141cc406Sopenharmony_ci	 unsigned char buffer[0xffc0];
2826141cc406Sopenharmony_ci
2827141cc406Sopenharmony_ci	  if (n > 0xffc0)
2828141cc406Sopenharmony_ci	    n = 0xffc0;
2829141cc406Sopenharmony_ci	  else if ((n > 1) && (n & 1))
2830141cc406Sopenharmony_ci	    --n;
2831141cc406Sopenharmony_ci	  if (rt_get_data (n, buffer) >= 0)
2832141cc406Sopenharmony_ci	    {
2833141cc406Sopenharmony_ci	      unsigned char *bufnow = buffer;
2834141cc406Sopenharmony_ci
2835141cc406Sopenharmony_ci	      while (n)
2836141cc406Sopenharmony_ci		{
2837141cc406Sopenharmony_ci		  int numcopy = rowbytes - bytenow;
2838141cc406Sopenharmony_ci
2839141cc406Sopenharmony_ci		  if (numcopy > n)
2840141cc406Sopenharmony_ci		    numcopy = n;
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_ci		  memcpy (row_buffer + rownow * rowbytes + bytenow,
2843141cc406Sopenharmony_ci		  	  bufnow, numcopy);
2844141cc406Sopenharmony_ci		  bytenow += numcopy;
2845141cc406Sopenharmony_ci		  bufnow += numcopy;
2846141cc406Sopenharmony_ci		  n -= numcopy;
2847141cc406Sopenharmony_ci
2848141cc406Sopenharmony_ci		  if (bytenow == rowbytes)
2849141cc406Sopenharmony_ci		    {
2850141cc406Sopenharmony_ci		      if (!rows_to_begin || !--rows_to_begin)
2851141cc406Sopenharmony_ci			{
2852141cc406Sopenharmony_ci			  unsigned char *outnow = output_buffer;
2853141cc406Sopenharmony_ci                          unsigned x;
2854141cc406Sopenharmony_ci
2855141cc406Sopenharmony_ci			  for (i = x = 0;
2856141cc406Sopenharmony_ci			       x < width;
2857141cc406Sopenharmony_ci			       ++x, i += merged_channels ? channels : 1)
2858141cc406Sopenharmony_ci			    {
2859141cc406Sopenharmony_ci			      for (j = 0; j < channels; ++j)
2860141cc406Sopenharmony_ci				{
2861141cc406Sopenharmony_ci				  unsigned pix =
2862141cc406Sopenharmony_ci				    (unsigned char) channel_data[j][i & 1][i];
2863141cc406Sopenharmony_ci
2864141cc406Sopenharmony_ci                                  if (postprocess_gains && postprocess_offsets)
2865141cc406Sopenharmony_ci                                  {
2866141cc406Sopenharmony_ci                                    int ppidx = j * width + x;
2867141cc406Sopenharmony_ci
2868141cc406Sopenharmony_ci                                    pix = constrain ( pix
2869141cc406Sopenharmony_ci                                                       * postprocess_gains[ppidx]
2870141cc406Sopenharmony_ci                                                       - postprocess_offsets[ppidx],
2871141cc406Sopenharmony_ci                                                      0,
2872141cc406Sopenharmony_ci                                                      255);
2873141cc406Sopenharmony_ci                                  }
2874141cc406Sopenharmony_ci				  *outnow++ = pix;
2875141cc406Sopenharmony_ci				}
2876141cc406Sopenharmony_ci			    }
2877141cc406Sopenharmony_ci
2878141cc406Sopenharmony_ci			  if (colour == HP3500_GRAY_SCAN || colour == HP3500_LINEART_SCAN)
2879141cc406Sopenharmony_ci			    {
2880141cc406Sopenharmony_ci			      unsigned char const *in_now = output_buffer;
2881141cc406Sopenharmony_ci			      int	bit = 7;
2882141cc406Sopenharmony_ci
2883141cc406Sopenharmony_ci			      outnow = output_buffer;
2884141cc406Sopenharmony_ci			      for (i = 0; i < width; ++i)
2885141cc406Sopenharmony_ci				{
2886141cc406Sopenharmony_ci
2887141cc406Sopenharmony_ci				  if (colour == HP3500_GRAY_SCAN)
2888141cc406Sopenharmony_ci				    {
2889141cc406Sopenharmony_ci				      *outnow++ = ((unsigned) in_now[0] * 2989 +
2890141cc406Sopenharmony_ci						   (unsigned) in_now[1] * 5870 +
2891141cc406Sopenharmony_ci						   (unsigned) in_now[2] * 1140) / 10000;
2892141cc406Sopenharmony_ci				    }
2893141cc406Sopenharmony_ci				  else
2894141cc406Sopenharmony_ci				    {
2895141cc406Sopenharmony_ci				      if (bit == 7)
2896141cc406Sopenharmony_ci					*outnow = ((in_now[1] < 0x80) ? 0x80 : 0);
2897141cc406Sopenharmony_ci				      else if (in_now[1] < 0x80)
2898141cc406Sopenharmony_ci					*outnow |= (1 << bit);
2899141cc406Sopenharmony_ci				      if (bit == 0)
2900141cc406Sopenharmony_ci					{
2901141cc406Sopenharmony_ci					  ++outnow;
2902141cc406Sopenharmony_ci					  bit = 7;
2903141cc406Sopenharmony_ci					}
2904141cc406Sopenharmony_ci				      else
2905141cc406Sopenharmony_ci					{
2906141cc406Sopenharmony_ci					  --bit;
2907141cc406Sopenharmony_ci					}
2908141cc406Sopenharmony_ci				    }
2909141cc406Sopenharmony_ci				  in_now += 3;
2910141cc406Sopenharmony_ci				}
2911141cc406Sopenharmony_ci			    }
2912141cc406Sopenharmony_ci			  if (rows_supplied++ < height &&
2913141cc406Sopenharmony_ci			      !((*cbfunc) (params, output_rowbytes, output_buffer)))
2914141cc406Sopenharmony_ci			    break;
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci			  for (i = 0; i < channels; ++i)
2917141cc406Sopenharmony_ci			    {
2918141cc406Sopenharmony_ci			      for (j = 0; j < 2; ++j)
2919141cc406Sopenharmony_ci				{
2920141cc406Sopenharmony_ci				  channel_data[i][j] += rowbytes;
2921141cc406Sopenharmony_ci				  if (channel_data[i][j] - row_buffer >=
2922141cc406Sopenharmony_ci				      rowbuffer_bytes)
2923141cc406Sopenharmony_ci				    channel_data[i][j] -= rowbuffer_bytes;
2924141cc406Sopenharmony_ci				}
2925141cc406Sopenharmony_ci			    }
2926141cc406Sopenharmony_ci			}
2927141cc406Sopenharmony_ci		      ++total_rows;
2928141cc406Sopenharmony_ci		      if (++rownow == buffered_rows)
2929141cc406Sopenharmony_ci			rownow = 0;
2930141cc406Sopenharmony_ci		      bytenow = 0;
2931141cc406Sopenharmony_ci		    }
2932141cc406Sopenharmony_ci		}
2933141cc406Sopenharmony_ci	    }
2934141cc406Sopenharmony_ci	  DBG (30, "total_rows = %d\r", total_rows);
2935141cc406Sopenharmony_ci	}
2936141cc406Sopenharmony_ci      else
2937141cc406Sopenharmony_ci	{
2938141cc406Sopenharmony_ci	  usleep (10000);
2939141cc406Sopenharmony_ci	}
2940141cc406Sopenharmony_ci    }
2941141cc406Sopenharmony_ci  DBG (10, "\n");
2942141cc406Sopenharmony_ci  if (n < 0)
2943141cc406Sopenharmony_ci    result = -1;
2944141cc406Sopenharmony_ci
2945141cc406Sopenharmony_ci  free (output_buffer);
2946141cc406Sopenharmony_ci  free (row_buffer);
2947141cc406Sopenharmony_ci
2948141cc406Sopenharmony_ci  rt_stop_moving ();
2949141cc406Sopenharmony_ci  return result;
2950141cc406Sopenharmony_ci}
2951141cc406Sopenharmony_ci
2952141cc406Sopenharmony_cistatic unsigned local_sram_size;
2953141cc406Sopenharmony_cistatic unsigned char r93setting;
2954141cc406Sopenharmony_ci
2955141cc406Sopenharmony_ci#define RTS8801_F_SUPPRESS_MOVEMENT	1
2956141cc406Sopenharmony_ci#define	RTS8801_F_LAMP_OFF		2
2957141cc406Sopenharmony_ci#define RTS8801_F_NO_DISPLACEMENTS	4
2958141cc406Sopenharmony_ci#define RTS8801_F_ODDX			8
2959141cc406Sopenharmony_ci
2960141cc406Sopenharmony_cistatic int
2961141cc406Sopenharmony_cifind_resolution_index (unsigned resolution)
2962141cc406Sopenharmony_ci{
2963141cc406Sopenharmony_ci  int res = 0;
2964141cc406Sopenharmony_ci
2965141cc406Sopenharmony_ci  for (res = 0; resparms[res].resolution != resolution; ++res)
2966141cc406Sopenharmony_ci    {
2967141cc406Sopenharmony_ci      if (!resparms[res].resolution)
2968141cc406Sopenharmony_ci	return -1;
2969141cc406Sopenharmony_ci    }
2970141cc406Sopenharmony_ci  return res;
2971141cc406Sopenharmony_ci}
2972141cc406Sopenharmony_ci
2973141cc406Sopenharmony_cistatic int
2974141cc406Sopenharmony_cirts8801_fullscan (unsigned x,
2975141cc406Sopenharmony_ci		  unsigned y,
2976141cc406Sopenharmony_ci		  unsigned w,
2977141cc406Sopenharmony_ci		  unsigned h,
2978141cc406Sopenharmony_ci		  unsigned xresolution,
2979141cc406Sopenharmony_ci		  unsigned yresolution,
2980141cc406Sopenharmony_ci		  unsigned colour,
2981141cc406Sopenharmony_ci		  rts8801_callback cbfunc,
2982141cc406Sopenharmony_ci		  void *param,
2983141cc406Sopenharmony_ci		  unsigned char *calib_info,
2984141cc406Sopenharmony_ci		  int flags,
2985141cc406Sopenharmony_ci		  int red_calib_offset,
2986141cc406Sopenharmony_ci		  int green_calib_offset,
2987141cc406Sopenharmony_ci		  int blue_calib_offset,
2988141cc406Sopenharmony_ci		  int end_calib_offset,
2989141cc406Sopenharmony_ci                  double *postprocess_offsets,
2990141cc406Sopenharmony_ci                  double *postprocess_gains)
2991141cc406Sopenharmony_ci{
2992141cc406Sopenharmony_ci  int ires, jres;
2993141cc406Sopenharmony_ci  int tg_setting;
2994141cc406Sopenharmony_ci  unsigned char regs[256];
2995141cc406Sopenharmony_ci  unsigned char offdutytime;
2996141cc406Sopenharmony_ci  int result;
2997141cc406Sopenharmony_ci  int scan_frequency;
2998141cc406Sopenharmony_ci  unsigned intra_channel_offset;
2999141cc406Sopenharmony_ci  unsigned red_green_offset;
3000141cc406Sopenharmony_ci  unsigned green_blue_offset;
3001141cc406Sopenharmony_ci  unsigned total_offsets;
3002141cc406Sopenharmony_ci
3003141cc406Sopenharmony_ci  ires = find_resolution_index (xresolution);
3004141cc406Sopenharmony_ci  jres = find_resolution_index (yresolution);
3005141cc406Sopenharmony_ci
3006141cc406Sopenharmony_ci  if (ires < 0 || jres < 0)
3007141cc406Sopenharmony_ci    return -1;
3008141cc406Sopenharmony_ci
3009141cc406Sopenharmony_ci  /* Set scan parameters */
3010141cc406Sopenharmony_ci
3011141cc406Sopenharmony_ci  rt_read_register_immediate (0, 255, regs);
3012141cc406Sopenharmony_ci  regs[255] = 0;
3013141cc406Sopenharmony_ci
3014141cc406Sopenharmony_ci  rt_enable_ccd (regs, 1);
3015141cc406Sopenharmony_ci  rt_enable_movement (regs, 1);
3016141cc406Sopenharmony_ci  rt_set_scan_frequency (regs, 1);
3017141cc406Sopenharmony_ci
3018141cc406Sopenharmony_ci  rt_adjust_misc_registers (regs);
3019141cc406Sopenharmony_ci
3020141cc406Sopenharmony_ci  rt_set_cvtr_wparams (regs, 3, 0, 6);
3021141cc406Sopenharmony_ci  rt_set_cvtr_mpt (regs, 15, 15, 15);
3022141cc406Sopenharmony_ci  rt_set_cvtr_lm (regs, 7, 7, 7);
3023141cc406Sopenharmony_ci  rt_set_motor_type (regs, 2);
3024141cc406Sopenharmony_ci
3025141cc406Sopenharmony_ci  if (rt_nvram_read (0, 0x7b, &offdutytime, 1) < 0 || offdutytime >= 15)
3026141cc406Sopenharmony_ci    {
3027141cc406Sopenharmony_ci      offdutytime = 6;
3028141cc406Sopenharmony_ci    }
3029141cc406Sopenharmony_ci  rt_set_lamp_duty_cycle (regs, 1,	/* On */
3030141cc406Sopenharmony_ci			  10,	/* Frequency */
3031141cc406Sopenharmony_ci			  offdutytime);	/* Off duty time */
3032141cc406Sopenharmony_ci
3033141cc406Sopenharmony_ci  rt_set_movement_pattern (regs, 0x800000);
3034141cc406Sopenharmony_ci
3035141cc406Sopenharmony_ci  rt_set_direction_forwards (regs);
3036141cc406Sopenharmony_ci  rt_set_stop_when_rewound (regs, 0);
3037141cc406Sopenharmony_ci
3038141cc406Sopenharmony_ci  rt_set_calibration_addresses (regs, 0, 0, 0, 0, 0);
3039141cc406Sopenharmony_ci
3040141cc406Sopenharmony_ci  rt_set_basic_calibration (regs,
3041141cc406Sopenharmony_ci			    calib_info[0], calib_info[1], calib_info[2],
3042141cc406Sopenharmony_ci			    calib_info[3], calib_info[4], calib_info[5],
3043141cc406Sopenharmony_ci			    calib_info[6], calib_info[7], calib_info[8]);
3044141cc406Sopenharmony_ci  regs[0x0b] = 0x70;		/* If set to 0x71, the alternative, all values are low */
3045141cc406Sopenharmony_ci  regs[0x40] &= 0xc0;
3046141cc406Sopenharmony_ci
3047141cc406Sopenharmony_ci  if (red_calib_offset >= 0
3048141cc406Sopenharmony_ci      && green_calib_offset >= 0
3049141cc406Sopenharmony_ci      && blue_calib_offset >= 0)
3050141cc406Sopenharmony_ci    {
3051141cc406Sopenharmony_ci      rt_set_calibration_addresses (regs, red_calib_offset,
3052141cc406Sopenharmony_ci				    green_calib_offset, blue_calib_offset,
3053141cc406Sopenharmony_ci				    end_calib_offset,
3054141cc406Sopenharmony_ci				    w);
3055141cc406Sopenharmony_ci      regs[0x40] |= 0x2f;
3056141cc406Sopenharmony_ci    }
3057141cc406Sopenharmony_ci  else if (end_calib_offset >= 0)
3058141cc406Sopenharmony_ci    {
3059141cc406Sopenharmony_ci      rt_set_calibration_addresses (regs, 0x600, 0x600, 0x600,
3060141cc406Sopenharmony_ci				    end_calib_offset, w);
3061141cc406Sopenharmony_ci    }
3062141cc406Sopenharmony_ci
3063141cc406Sopenharmony_ci  rt_set_channel (regs, RT_CHANNEL_ALL);
3064141cc406Sopenharmony_ci  rt_set_single_channel_scanning (regs, 0);
3065141cc406Sopenharmony_ci  rt_set_merge_channels (regs, 1);
3066141cc406Sopenharmony_ci  rt_set_colour_mode (regs, 1);
3067141cc406Sopenharmony_ci
3068141cc406Sopenharmony_ci  rt_set_last_sram_page (regs, (local_sram_size - 1) >> 5);
3069141cc406Sopenharmony_ci
3070141cc406Sopenharmony_ci  scan_frequency = resparms[jres].scan_frequency;
3071141cc406Sopenharmony_ci  rt_set_cph0s (regs, resparms[ires].cph0s);
3072141cc406Sopenharmony_ci  if (resparms[ires].d3_bit_3_value)
3073141cc406Sopenharmony_ci    regs[0xd3] |= 0x08;
3074141cc406Sopenharmony_ci  else
3075141cc406Sopenharmony_ci    regs[0xd3] &= 0xf7;
3076141cc406Sopenharmony_ci
3077141cc406Sopenharmony_ci  if (flags & RTS8801_F_SUPPRESS_MOVEMENT)
3078141cc406Sopenharmony_ci    regs[0xc3] &= 0x7f;
3079141cc406Sopenharmony_ci
3080141cc406Sopenharmony_ci  regs[0xb2] &= 0xf7;
3081141cc406Sopenharmony_ci
3082141cc406Sopenharmony_ci  rt_set_horizontal_resolution (regs, xresolution);
3083141cc406Sopenharmony_ci
3084141cc406Sopenharmony_ci  rt_set_scanline_start (regs,
3085141cc406Sopenharmony_ci			 x * (1200 / xresolution) /
3086141cc406Sopenharmony_ci			 (resparms[ires].cph0s ? 1 : 2) /
3087141cc406Sopenharmony_ci			 (resparms[ires].d3_bit_3_value ? 1 : 2));
3088141cc406Sopenharmony_ci  rt_set_scanline_end (regs,
3089141cc406Sopenharmony_ci		       (x +
3090141cc406Sopenharmony_ci			w) * (1200 / xresolution) /
3091141cc406Sopenharmony_ci		       (resparms[ires].cph0s ? 1 : 2) /
3092141cc406Sopenharmony_ci		       (resparms[ires].d3_bit_3_value ? 1 : 2));
3093141cc406Sopenharmony_ci
3094141cc406Sopenharmony_ci  if (flags & RTS8801_F_NO_DISPLACEMENTS)
3095141cc406Sopenharmony_ci    {
3096141cc406Sopenharmony_ci      red_green_offset = green_blue_offset = intra_channel_offset = 0;
3097141cc406Sopenharmony_ci    }
3098141cc406Sopenharmony_ci  else
3099141cc406Sopenharmony_ci    {
3100141cc406Sopenharmony_ci      red_green_offset = resparms[jres].red_green_offset;
3101141cc406Sopenharmony_ci      green_blue_offset = resparms[jres].green_blue_offset;
3102141cc406Sopenharmony_ci      intra_channel_offset = resparms[jres].intra_channel_offset;
3103141cc406Sopenharmony_ci    }
3104141cc406Sopenharmony_ci  total_offsets = red_green_offset + green_blue_offset + intra_channel_offset;
3105141cc406Sopenharmony_ci  if (y > total_offsets + 2)
3106141cc406Sopenharmony_ci    y -= total_offsets;
3107141cc406Sopenharmony_ci  h += total_offsets;
3108141cc406Sopenharmony_ci
3109141cc406Sopenharmony_ci  if (yresolution > 75 && !(flags & RTS8801_F_SUPPRESS_MOVEMENT))
3110141cc406Sopenharmony_ci    {
3111141cc406Sopenharmony_ci      int rmres = find_resolution_index (50);
3112141cc406Sopenharmony_ci
3113141cc406Sopenharmony_ci      if (rmres >= 0)
3114141cc406Sopenharmony_ci	{
3115141cc406Sopenharmony_ci	  int factor = yresolution / 50;
3116141cc406Sopenharmony_ci	  int fastres = y / factor;
3117141cc406Sopenharmony_ci	  int remainder = y % factor;
3118141cc406Sopenharmony_ci
3119141cc406Sopenharmony_ci	  while (remainder < 2)
3120141cc406Sopenharmony_ci	    {
3121141cc406Sopenharmony_ci		--fastres;
3122141cc406Sopenharmony_ci		remainder += factor;
3123141cc406Sopenharmony_ci	    }
3124141cc406Sopenharmony_ci
3125141cc406Sopenharmony_ci	  if (fastres >= 3)
3126141cc406Sopenharmony_ci	    {
3127141cc406Sopenharmony_ci	      y = remainder;
3128141cc406Sopenharmony_ci
3129141cc406Sopenharmony_ci	      rt_set_noscan_distance(regs, fastres * resparms[rmres].scan_frequency - 2);
3130141cc406Sopenharmony_ci	      rt_set_total_distance(regs, fastres * resparms[rmres].scan_frequency - 1);
3131141cc406Sopenharmony_ci
3132141cc406Sopenharmony_ci	      rt_set_scan_frequency(regs, 1);
3133141cc406Sopenharmony_ci
3134141cc406Sopenharmony_ci	      tg_setting = resparms[rmres].tg;
3135141cc406Sopenharmony_ci	      rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p);
3136141cc406Sopenharmony_ci	      rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp);
3137141cc406Sopenharmony_ci	      rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp);
3138141cc406Sopenharmony_ci
3139141cc406Sopenharmony_ci	      rt_set_one_register (0xc6, 0);
3140141cc406Sopenharmony_ci	      rt_set_one_register (0xc6, 0);
3141141cc406Sopenharmony_ci
3142141cc406Sopenharmony_ci	      rt_set_step_size (regs, resparms[rmres].step_size);
3143141cc406Sopenharmony_ci
3144141cc406Sopenharmony_ci	      rt_set_motor_movement_clock_multiplier (regs,
3145141cc406Sopenharmony_ci						      resparms[rmres].
3146141cc406Sopenharmony_ci							  motor_movement_clock_multiplier);
3147141cc406Sopenharmony_ci
3148141cc406Sopenharmony_ci	      rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1,
3149141cc406Sopenharmony_ci			   tg_info[tg_setting].tg_cdss2);
3150141cc406Sopenharmony_ci	      rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1,
3151141cc406Sopenharmony_ci			   tg_info[tg_setting].tg_cdsc2);
3152141cc406Sopenharmony_ci	      rt_update_after_setting_cdss2 (regs);
3153141cc406Sopenharmony_ci
3154141cc406Sopenharmony_ci	      regs[0x39] = resparms[rmres].reg_39_value;
3155141cc406Sopenharmony_ci	      regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[rmres].reg_c3_value;
3156141cc406Sopenharmony_ci	      regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[rmres].reg_c6_value;
3157141cc406Sopenharmony_ci
3158141cc406Sopenharmony_ci	      rt_set_data_feed_off (regs);
3159141cc406Sopenharmony_ci
3160141cc406Sopenharmony_ci	      rt_set_all_registers (regs);
3161141cc406Sopenharmony_ci
3162141cc406Sopenharmony_ci  	      rt_set_one_register (0x2c, regs[0x2c]);
3163141cc406Sopenharmony_ci
3164141cc406Sopenharmony_ci	      if (DBG_LEVEL >= 5)
3165141cc406Sopenharmony_ci	        dump_registers (regs);
3166141cc406Sopenharmony_ci
3167141cc406Sopenharmony_ci	      rt_start_moving ();
3168141cc406Sopenharmony_ci	      while (rt_is_moving ());
3169141cc406Sopenharmony_ci	    }
3170141cc406Sopenharmony_ci	}
3171141cc406Sopenharmony_ci    }
3172141cc406Sopenharmony_ci
3173141cc406Sopenharmony_ci
3174141cc406Sopenharmony_ci  rt_set_noscan_distance (regs, y * scan_frequency - 1);
3175141cc406Sopenharmony_ci  rt_set_total_distance (regs, scan_frequency * (y + h) - 1);
3176141cc406Sopenharmony_ci
3177141cc406Sopenharmony_ci  rt_set_scan_frequency (regs, scan_frequency);
3178141cc406Sopenharmony_ci
3179141cc406Sopenharmony_ci  tg_setting = resparms[jres].tg;
3180141cc406Sopenharmony_ci
3181141cc406Sopenharmony_ci  rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p);
3182141cc406Sopenharmony_ci  rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp);
3183141cc406Sopenharmony_ci  rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp);
3184141cc406Sopenharmony_ci
3185141cc406Sopenharmony_ci  rt_set_one_register (0xc6, 0);
3186141cc406Sopenharmony_ci  rt_set_one_register (0xc6, 0);
3187141cc406Sopenharmony_ci
3188141cc406Sopenharmony_ci  rt_set_step_size (regs, resparms[jres].step_size);
3189141cc406Sopenharmony_ci
3190141cc406Sopenharmony_ci  rt_set_motor_movement_clock_multiplier (regs,
3191141cc406Sopenharmony_ci					  resparms[jres].
3192141cc406Sopenharmony_ci					  motor_movement_clock_multiplier);
3193141cc406Sopenharmony_ci
3194141cc406Sopenharmony_ci  rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1,
3195141cc406Sopenharmony_ci	       tg_info[tg_setting].tg_cdss2);
3196141cc406Sopenharmony_ci  rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1,
3197141cc406Sopenharmony_ci	       tg_info[tg_setting].tg_cdsc2);
3198141cc406Sopenharmony_ci  rt_update_after_setting_cdss2 (regs);
3199141cc406Sopenharmony_ci
3200141cc406Sopenharmony_ci  regs[0x39] = resparms[jres].reg_39_value;
3201141cc406Sopenharmony_ci  regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[jres].reg_c3_value;
3202141cc406Sopenharmony_ci  regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[jres].reg_c6_value;
3203141cc406Sopenharmony_ci
3204141cc406Sopenharmony_ci  rt_set_data_feed_on (regs);
3205141cc406Sopenharmony_ci
3206141cc406Sopenharmony_ci  rt_set_all_registers (regs);
3207141cc406Sopenharmony_ci
3208141cc406Sopenharmony_ci  rt_set_one_register (0x2c, regs[0x2c]);
3209141cc406Sopenharmony_ci
3210141cc406Sopenharmony_ci  if (DBG_LEVEL >= 5)
3211141cc406Sopenharmony_ci    dump_registers (regs);
3212141cc406Sopenharmony_ci
3213141cc406Sopenharmony_ci  result = rts8801_doscan (w,
3214141cc406Sopenharmony_ci			   h,
3215141cc406Sopenharmony_ci			   colour,
3216141cc406Sopenharmony_ci			   red_green_offset,
3217141cc406Sopenharmony_ci			   green_blue_offset,
3218141cc406Sopenharmony_ci			   intra_channel_offset,
3219141cc406Sopenharmony_ci			   cbfunc, param, (x & 1), calib_info,
3220141cc406Sopenharmony_ci			   (regs[0x2f] & 0x04) != 0,
3221141cc406Sopenharmony_ci                           postprocess_offsets,
3222141cc406Sopenharmony_ci                           postprocess_gains);
3223141cc406Sopenharmony_ci  return result;
3224141cc406Sopenharmony_ci}
3225141cc406Sopenharmony_ci
3226141cc406Sopenharmony_cistatic int
3227141cc406Sopenharmony_ciaccumfunc (struct dcalibdata *dcd, int bytes, char *data)
3228141cc406Sopenharmony_ci{
3229141cc406Sopenharmony_ci  unsigned char *c = (unsigned char *) data;
3230141cc406Sopenharmony_ci
3231141cc406Sopenharmony_ci  while (bytes > 0)
3232141cc406Sopenharmony_ci    {
3233141cc406Sopenharmony_ci      if (dcd->firstrowdone)
3234141cc406Sopenharmony_ci	dcd->buffers[dcd->channelnow][dcd->pixelnow - dcd->pixelsperrow] = *c;
3235141cc406Sopenharmony_ci      if (++dcd->channelnow >= 3)
3236141cc406Sopenharmony_ci	{
3237141cc406Sopenharmony_ci	  dcd->channelnow = 0;
3238141cc406Sopenharmony_ci	  if (++dcd->pixelnow == dcd->pixelsperrow)
3239141cc406Sopenharmony_ci	    ++dcd->firstrowdone;
3240141cc406Sopenharmony_ci	}
3241141cc406Sopenharmony_ci      c++;
3242141cc406Sopenharmony_ci      bytes--;
3243141cc406Sopenharmony_ci    }
3244141cc406Sopenharmony_ci  return 1;
3245141cc406Sopenharmony_ci}
3246141cc406Sopenharmony_ci
3247141cc406Sopenharmony_cistatic int
3248141cc406Sopenharmony_cicalcmedian (unsigned char const *data,
3249141cc406Sopenharmony_ci	    int pixel, int pixels_per_row, int elements)
3250141cc406Sopenharmony_ci{
3251141cc406Sopenharmony_ci  int tallies[256];
3252141cc406Sopenharmony_ci  int i;
3253141cc406Sopenharmony_ci  int elemstogo = elements / 2;
3254141cc406Sopenharmony_ci
3255141cc406Sopenharmony_ci  memset (tallies, 0, sizeof (tallies));
3256141cc406Sopenharmony_ci  data += pixel;
3257141cc406Sopenharmony_ci  for (i = 0; i < elements; ++i)
3258141cc406Sopenharmony_ci    {
3259141cc406Sopenharmony_ci      ++tallies[*data];
3260141cc406Sopenharmony_ci      data += pixels_per_row;
3261141cc406Sopenharmony_ci    }
3262141cc406Sopenharmony_ci  i = 0;
3263141cc406Sopenharmony_ci  while (elemstogo - tallies[i] > 0)
3264141cc406Sopenharmony_ci    elemstogo -= tallies[i++];
3265141cc406Sopenharmony_ci  return i;
3266141cc406Sopenharmony_ci}
3267141cc406Sopenharmony_ci
3268141cc406Sopenharmony_cistruct calibdata
3269141cc406Sopenharmony_ci{
3270141cc406Sopenharmony_ci  unsigned char *buffer;
3271141cc406Sopenharmony_ci  int space;
3272141cc406Sopenharmony_ci};
3273141cc406Sopenharmony_ci
3274141cc406Sopenharmony_cistatic int
3275141cc406Sopenharmony_cistorefunc (struct calibdata *cd, int bytes, char *data)
3276141cc406Sopenharmony_ci{
3277141cc406Sopenharmony_ci  if (cd->space > 0)
3278141cc406Sopenharmony_ci    {
3279141cc406Sopenharmony_ci      if (bytes > cd->space)
3280141cc406Sopenharmony_ci	bytes = cd->space;
3281141cc406Sopenharmony_ci      memcpy (cd->buffer, data, bytes);
3282141cc406Sopenharmony_ci      cd->buffer += bytes;
3283141cc406Sopenharmony_ci      cd->space -= bytes;
3284141cc406Sopenharmony_ci    }
3285141cc406Sopenharmony_ci  return 1;
3286141cc406Sopenharmony_ci}
3287141cc406Sopenharmony_ci
3288141cc406Sopenharmony_cistatic unsigned
3289141cc406Sopenharmony_cisum_channel (unsigned char *p, int n, int bytwo)
3290141cc406Sopenharmony_ci{
3291141cc406Sopenharmony_ci  unsigned v = 0;
3292141cc406Sopenharmony_ci
3293141cc406Sopenharmony_ci  while (n-- > 0)
3294141cc406Sopenharmony_ci    {
3295141cc406Sopenharmony_ci      v += *p;
3296141cc406Sopenharmony_ci      p += 3;
3297141cc406Sopenharmony_ci      if (bytwo)
3298141cc406Sopenharmony_ci	p += 3;
3299141cc406Sopenharmony_ci    }
3300141cc406Sopenharmony_ci  return v;
3301141cc406Sopenharmony_ci}
3302141cc406Sopenharmony_ci
3303141cc406Sopenharmony_cistatic int do_warmup = 1;
3304141cc406Sopenharmony_ci
3305141cc406Sopenharmony_ci#define DETAILED_PASS_COUNT		3
3306141cc406Sopenharmony_ci#define DETAILED_PASS_OFFSETS		0
3307141cc406Sopenharmony_ci#define	DETAILED_PASS_GAINS_FIRSTPASS	1
3308141cc406Sopenharmony_ci#define	DETAILED_PASS_GAINS_SECONDPASS	2
3309141cc406Sopenharmony_ci
3310141cc406Sopenharmony_cistatic int
3311141cc406Sopenharmony_cirts8801_scan (unsigned x,
3312141cc406Sopenharmony_ci	      unsigned y,
3313141cc406Sopenharmony_ci	      unsigned w,
3314141cc406Sopenharmony_ci	      unsigned h,
3315141cc406Sopenharmony_ci	      unsigned resolution,
3316141cc406Sopenharmony_ci	      unsigned colour,
3317141cc406Sopenharmony_ci	      unsigned brightness,
3318141cc406Sopenharmony_ci	      unsigned contrast,
3319141cc406Sopenharmony_ci	      rts8801_callback cbfunc,
3320141cc406Sopenharmony_ci	      void *param,
3321141cc406Sopenharmony_ci	      double gamma)
3322141cc406Sopenharmony_ci{
3323141cc406Sopenharmony_ci  unsigned char calib_info[9];
3324141cc406Sopenharmony_ci  unsigned char calibbuf[2400];
3325141cc406Sopenharmony_ci  struct dcalibdata dcd;
3326141cc406Sopenharmony_ci  struct calibdata cd;
3327141cc406Sopenharmony_ci  unsigned char *detail_buffer = 0;
3328141cc406Sopenharmony_ci  int iCalibY;
3329141cc406Sopenharmony_ci  int iCalibTarget;
3330141cc406Sopenharmony_ci  int iMoveFlags = 0;
3331141cc406Sopenharmony_ci  unsigned aiBestOffset[6];
3332141cc406Sopenharmony_ci  int aiPassed[6];
3333141cc406Sopenharmony_ci  int i;
3334141cc406Sopenharmony_ci  unsigned j;
3335141cc406Sopenharmony_ci  int k;
3336141cc406Sopenharmony_ci  int calibration_size;
3337141cc406Sopenharmony_ci  unsigned char *pDetailedCalib;
3338141cc406Sopenharmony_ci  int red_calibration_offset;
3339141cc406Sopenharmony_ci  int green_calibration_offset;
3340141cc406Sopenharmony_ci  int blue_calibration_offset;
3341141cc406Sopenharmony_ci  int end_calibration_offset;
3342141cc406Sopenharmony_ci  int base_resolution;
3343141cc406Sopenharmony_ci  int resolution_divisor;
3344141cc406Sopenharmony_ci  int resolution_index;
3345141cc406Sopenharmony_ci  int detailed_calibration_rows = 50;
3346141cc406Sopenharmony_ci  unsigned char *tdetail_buffer;
3347141cc406Sopenharmony_ci  int pass;
3348141cc406Sopenharmony_ci  int onechanged;
3349141cc406Sopenharmony_ci  double *postprocess_gains;
3350141cc406Sopenharmony_ci  double *postprocess_offsets;
3351141cc406Sopenharmony_ci  int needs_postprocessed_calibration = 0;
3352141cc406Sopenharmony_ci  double contrast_adjust = (double) contrast / 64;
3353141cc406Sopenharmony_ci  int brightness_adjust = brightness - 0x80;
3354141cc406Sopenharmony_ci
3355141cc406Sopenharmony_ci  /* Initialise and power up */
3356141cc406Sopenharmony_ci
3357141cc406Sopenharmony_ci  rt_set_all_registers (initial_regs);
3358141cc406Sopenharmony_ci  rt_set_powersave_mode (0);
3359141cc406Sopenharmony_ci
3360141cc406Sopenharmony_ci  /* Initial rewind in case scanner is stuck away from home position */
3361141cc406Sopenharmony_ci
3362141cc406Sopenharmony_ci  rts8801_rewind ();
3363141cc406Sopenharmony_ci
3364141cc406Sopenharmony_ci  /* Detect SRAM */
3365141cc406Sopenharmony_ci
3366141cc406Sopenharmony_ci  rt_detect_sram (&local_sram_size, &r93setting);
3367141cc406Sopenharmony_ci
3368141cc406Sopenharmony_ci  /* Warm up the lamp */
3369141cc406Sopenharmony_ci
3370141cc406Sopenharmony_ci  DBG (10, "Warming up the lamp\n");
3371141cc406Sopenharmony_ci
3372141cc406Sopenharmony_ci  rt_turn_on_lamp ();
3373141cc406Sopenharmony_ci  if (do_warmup)
3374141cc406Sopenharmony_ci    sleep (25);
3375141cc406Sopenharmony_ci
3376141cc406Sopenharmony_ci  /* Basic calibration */
3377141cc406Sopenharmony_ci
3378141cc406Sopenharmony_ci  DBG (10, "Calibrating (stage 1)\n");
3379141cc406Sopenharmony_ci
3380141cc406Sopenharmony_ci  calib_info[2] = calib_info[5] = calib_info[8] = 1;
3381141cc406Sopenharmony_ci
3382141cc406Sopenharmony_ci  iCalibY = (resolution == 25) ? 1 : 2;
3383141cc406Sopenharmony_ci  iCalibTarget = 550;
3384141cc406Sopenharmony_ci
3385141cc406Sopenharmony_ci  rt_turn_off_lamp();
3386141cc406Sopenharmony_ci
3387141cc406Sopenharmony_ci  for (i = 0; i < 6; ++i)
3388141cc406Sopenharmony_ci    {
3389141cc406Sopenharmony_ci      aiBestOffset[i] = 0xbf;
3390141cc406Sopenharmony_ci      aiPassed[i] = 0;
3391141cc406Sopenharmony_ci    }
3392141cc406Sopenharmony_ci
3393141cc406Sopenharmony_ci  do
3394141cc406Sopenharmony_ci    {
3395141cc406Sopenharmony_ci      DBG (30, "Initial calibration pass commences\n");
3396141cc406Sopenharmony_ci
3397141cc406Sopenharmony_ci      onechanged = 0;
3398141cc406Sopenharmony_ci      for (i = 0; i < 3; ++i)
3399141cc406Sopenharmony_ci        {
3400141cc406Sopenharmony_ci	  calib_info[i * 3] = aiBestOffset[i];
3401141cc406Sopenharmony_ci	  calib_info[i * 3 + 1] = aiBestOffset[i + 3];
3402141cc406Sopenharmony_ci        }
3403141cc406Sopenharmony_ci
3404141cc406Sopenharmony_ci      cd.buffer = calibbuf;
3405141cc406Sopenharmony_ci      cd.space = sizeof (calibbuf);
3406141cc406Sopenharmony_ci      DBG (30, "Commencing scan for initial calibration pass\n");
3407141cc406Sopenharmony_ci      rts8801_fullscan (1401, iCalibY, 100, 2, 400, resolution,
3408141cc406Sopenharmony_ci			HP3500_COLOR_SCAN, (rts8801_callback) storefunc, &cd,
3409141cc406Sopenharmony_ci			calib_info, iMoveFlags, -1, -1, -1, -1, 0, 0);
3410141cc406Sopenharmony_ci      DBG (30, "Completed scan for initial calibration pass\n");
3411141cc406Sopenharmony_ci      iMoveFlags = RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS;
3412141cc406Sopenharmony_ci      iCalibY = 2;
3413141cc406Sopenharmony_ci
3414141cc406Sopenharmony_ci      for (i = 0; i < 6; ++i)
3415141cc406Sopenharmony_ci	{
3416141cc406Sopenharmony_ci	  int sum;
3417141cc406Sopenharmony_ci
3418141cc406Sopenharmony_ci	  if (aiBestOffset[i] >= 255 || aiPassed[i] > 2)
3419141cc406Sopenharmony_ci	    continue;
3420141cc406Sopenharmony_ci	  sum = sum_channel (calibbuf + i, 50, 1);
3421141cc406Sopenharmony_ci	  DBG (20, "channel[%d] sum = %d (target %d)\n", i, sum,
3422141cc406Sopenharmony_ci	       iCalibTarget);
3423141cc406Sopenharmony_ci
3424141cc406Sopenharmony_ci	  if (sum < iCalibTarget)
3425141cc406Sopenharmony_ci            {
3426141cc406Sopenharmony_ci              onechanged = 1;
3427141cc406Sopenharmony_ci              ++aiBestOffset[i];
3428141cc406Sopenharmony_ci            }
3429141cc406Sopenharmony_ci          else
3430141cc406Sopenharmony_ci            {
3431141cc406Sopenharmony_ci              ++aiPassed[i];
3432141cc406Sopenharmony_ci            }
3433141cc406Sopenharmony_ci	}
3434141cc406Sopenharmony_ci      DBG (30, "Initial calibration pass completed\n");
3435141cc406Sopenharmony_ci    }
3436141cc406Sopenharmony_ci  while (onechanged);
3437141cc406Sopenharmony_ci
3438141cc406Sopenharmony_ci  DBG (20, "Offsets calculated\n");
3439141cc406Sopenharmony_ci
3440141cc406Sopenharmony_ci  rt_turn_on_lamp();
3441141cc406Sopenharmony_ci  usleep(500000);
3442141cc406Sopenharmony_ci
3443141cc406Sopenharmony_ci  tdetail_buffer =
3444141cc406Sopenharmony_ci    (unsigned char *) malloc (w * 3 * detailed_calibration_rows);
3445141cc406Sopenharmony_ci
3446141cc406Sopenharmony_ci  for (i = 0; i < 3; ++i)
3447141cc406Sopenharmony_ci    {
3448141cc406Sopenharmony_ci      calib_info[i * 3 + 2] = 1;
3449141cc406Sopenharmony_ci      aiPassed[i] = 0;
3450141cc406Sopenharmony_ci    }
3451141cc406Sopenharmony_ci
3452141cc406Sopenharmony_ci  do
3453141cc406Sopenharmony_ci    {
3454141cc406Sopenharmony_ci      struct dcalibdata dcdt;
3455141cc406Sopenharmony_ci
3456141cc406Sopenharmony_ci      dcdt.buffers[0] = tdetail_buffer;
3457141cc406Sopenharmony_ci      dcdt.buffers[1] = (tdetail_buffer + w * detailed_calibration_rows);
3458141cc406Sopenharmony_ci      dcdt.buffers[2] = (dcdt.buffers[1] + w * detailed_calibration_rows);
3459141cc406Sopenharmony_ci      dcdt.pixelsperrow = w;
3460141cc406Sopenharmony_ci      dcdt.pixelnow = dcdt.channelnow = dcdt.firstrowdone = 0;
3461141cc406Sopenharmony_ci      DBG (20, "Scanning for part 2 of initial calibration\n");
3462141cc406Sopenharmony_ci      rts8801_fullscan (x, 4, w, detailed_calibration_rows + 1, resolution,
3463141cc406Sopenharmony_ci			resolution, HP3500_COLOR_SCAN,
3464141cc406Sopenharmony_ci			(rts8801_callback) accumfunc, &dcdt, calib_info,
3465141cc406Sopenharmony_ci			RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS, -1, -1, -1, -1, 0, 0);
3466141cc406Sopenharmony_ci      DBG (20, "Scan for part 2 of initial calibration completed\n");
3467141cc406Sopenharmony_ci
3468141cc406Sopenharmony_ci      onechanged = 0;
3469141cc406Sopenharmony_ci      for (i = 0; i < 3; ++i)
3470141cc406Sopenharmony_ci	{
3471141cc406Sopenharmony_ci	  int largest = 1;
3472141cc406Sopenharmony_ci
3473141cc406Sopenharmony_ci          if (aiPassed[i] > 2 || calib_info[i * 3 + 2] >= 63)
3474141cc406Sopenharmony_ci            continue;
3475141cc406Sopenharmony_ci
3476141cc406Sopenharmony_ci 	  for (j = 0; j < w; ++j)
3477141cc406Sopenharmony_ci	    {
3478141cc406Sopenharmony_ci	      int val =
3479141cc406Sopenharmony_ci		calcmedian (dcdt.buffers[i], j, w, detailed_calibration_rows);
3480141cc406Sopenharmony_ci
3481141cc406Sopenharmony_ci	      if (val > largest)
3482141cc406Sopenharmony_ci		largest = val;
3483141cc406Sopenharmony_ci	    }
3484141cc406Sopenharmony_ci
3485141cc406Sopenharmony_ci	  if (largest < 0xe0)
3486141cc406Sopenharmony_ci            {
3487141cc406Sopenharmony_ci              ++calib_info[i * 3 + 2];
3488141cc406Sopenharmony_ci              onechanged = 1;
3489141cc406Sopenharmony_ci            }
3490141cc406Sopenharmony_ci          else
3491141cc406Sopenharmony_ci            {
3492141cc406Sopenharmony_ci              ++aiPassed[i];
3493141cc406Sopenharmony_ci            }
3494141cc406Sopenharmony_ci	}
3495141cc406Sopenharmony_ci    }
3496141cc406Sopenharmony_ci  while (onechanged);
3497141cc406Sopenharmony_ci
3498141cc406Sopenharmony_ci  for (i = 0; i < 3; ++i)
3499141cc406Sopenharmony_ci    {
3500141cc406Sopenharmony_ci      DBG (10, "Channel [%d] gain=%02x  offset=%02x\n",
3501141cc406Sopenharmony_ci	   i, calib_info[i * 3] + 2, calib_info[i * 3]);
3502141cc406Sopenharmony_ci    }
3503141cc406Sopenharmony_ci
3504141cc406Sopenharmony_ci  DBG (20, "Gain factors calculated\n");
3505141cc406Sopenharmony_ci
3506141cc406Sopenharmony_ci  /* Stage 2 calibration */
3507141cc406Sopenharmony_ci
3508141cc406Sopenharmony_ci  DBG (10, "Calibrating (stage 2)\n");
3509141cc406Sopenharmony_ci
3510141cc406Sopenharmony_ci  detail_buffer =
3511141cc406Sopenharmony_ci    (unsigned char *) malloc (w * 3 * detailed_calibration_rows);
3512141cc406Sopenharmony_ci
3513141cc406Sopenharmony_ci  dcd.buffers[0] = detail_buffer;
3514141cc406Sopenharmony_ci  dcd.buffers[1] = (detail_buffer + w * detailed_calibration_rows);
3515141cc406Sopenharmony_ci  dcd.buffers[2] = (dcd.buffers[1] + w * detailed_calibration_rows);
3516141cc406Sopenharmony_ci  dcd.pixelsperrow = w;
3517141cc406Sopenharmony_ci
3518141cc406Sopenharmony_ci
3519141cc406Sopenharmony_ci  /* And now for the detailed calibration */
3520141cc406Sopenharmony_ci  resolution_index = find_resolution_index (resolution);
3521141cc406Sopenharmony_ci  base_resolution = 300;
3522141cc406Sopenharmony_ci  if (resparms[resolution_index].cph0s)
3523141cc406Sopenharmony_ci    base_resolution *= 2;
3524141cc406Sopenharmony_ci  if (resparms[resolution_index].d3_bit_3_value)
3525141cc406Sopenharmony_ci    base_resolution *= 2;
3526141cc406Sopenharmony_ci  resolution_divisor = base_resolution / resolution;
3527141cc406Sopenharmony_ci
3528141cc406Sopenharmony_ci  calibration_size = w * resolution_divisor * 6 + 1568 + 96;
3529141cc406Sopenharmony_ci  red_calibration_offset = 0x600;
3530141cc406Sopenharmony_ci  green_calibration_offset =
3531141cc406Sopenharmony_ci    red_calibration_offset + w * resolution_divisor * 2;
3532141cc406Sopenharmony_ci  blue_calibration_offset =
3533141cc406Sopenharmony_ci    green_calibration_offset + w * resolution_divisor * 2;
3534141cc406Sopenharmony_ci  end_calibration_offset =
3535141cc406Sopenharmony_ci    blue_calibration_offset + w * resolution_divisor * 2;
3536141cc406Sopenharmony_ci  pDetailedCalib = (unsigned char *) malloc (calibration_size);
3537141cc406Sopenharmony_ci
3538141cc406Sopenharmony_ci  memset (pDetailedCalib, 0, calibration_size);
3539141cc406Sopenharmony_ci
3540141cc406Sopenharmony_ci  for (i = 0; i < 3; ++i)
3541141cc406Sopenharmony_ci    {
3542141cc406Sopenharmony_ci      int idx =
3543141cc406Sopenharmony_ci        (i == 0) ? red_calibration_offset :
3544141cc406Sopenharmony_ci        (i == 1) ? green_calibration_offset :
3545141cc406Sopenharmony_ci                       blue_calibration_offset;
3546141cc406Sopenharmony_ci
3547141cc406Sopenharmony_ci      for (j = 0; j < 256; j++)
3548141cc406Sopenharmony_ci        {
3549141cc406Sopenharmony_ci          /* Gamma table - appears to be 256 byte pairs for each input
3550141cc406Sopenharmony_ci           * range (so the first entry cover inputs in the range 0 to 1,
3551141cc406Sopenharmony_ci           * the second 1 to 2, and so on), mapping that input range
3552141cc406Sopenharmony_ci           * (including the fractional parts within it) to an output
3553141cc406Sopenharmony_ci           * range.
3554141cc406Sopenharmony_ci           */
3555141cc406Sopenharmony_ci          pDetailedCalib[i * 512 + j * 2] = j;
3556141cc406Sopenharmony_ci          pDetailedCalib[i * 512 + j * 2 + 1] = j;
3557141cc406Sopenharmony_ci        }
3558141cc406Sopenharmony_ci
3559141cc406Sopenharmony_ci      for (j = 0; j < w; ++j)
3560141cc406Sopenharmony_ci        {
3561141cc406Sopenharmony_ci          for (k = 0; k < resolution_divisor; ++k)
3562141cc406Sopenharmony_ci            {
3563141cc406Sopenharmony_ci              pDetailedCalib[idx++] = 0;
3564141cc406Sopenharmony_ci              pDetailedCalib[idx++] = 0x80;
3565141cc406Sopenharmony_ci            }
3566141cc406Sopenharmony_ci        }
3567141cc406Sopenharmony_ci    }
3568141cc406Sopenharmony_ci
3569141cc406Sopenharmony_ci  rt_set_sram_page (0);
3570141cc406Sopenharmony_ci  rt_set_one_register (0x93, r93setting);
3571141cc406Sopenharmony_ci  rt_write_sram (calibration_size, pDetailedCalib);
3572141cc406Sopenharmony_ci
3573141cc406Sopenharmony_ci  postprocess_gains = (double *) malloc(sizeof(double) * 3 * w);
3574141cc406Sopenharmony_ci  postprocess_offsets = (double *) malloc(sizeof(double) * 3 * w);
3575141cc406Sopenharmony_ci
3576141cc406Sopenharmony_ci  for (pass = 0; pass < DETAILED_PASS_COUNT; ++pass)
3577141cc406Sopenharmony_ci    {
3578141cc406Sopenharmony_ci      int ppidx = 0;
3579141cc406Sopenharmony_ci
3580141cc406Sopenharmony_ci      DBG (10, "Performing detailed calibration scan %d\n", pass);
3581141cc406Sopenharmony_ci
3582141cc406Sopenharmony_ci      switch (pass)
3583141cc406Sopenharmony_ci      {
3584141cc406Sopenharmony_ci      case DETAILED_PASS_OFFSETS:
3585141cc406Sopenharmony_ci        rt_turn_off_lamp();
3586141cc406Sopenharmony_ci	usleep(500000); /* To be sure it has gone off */
3587141cc406Sopenharmony_ci        break;
3588141cc406Sopenharmony_ci
3589141cc406Sopenharmony_ci      case DETAILED_PASS_GAINS_FIRSTPASS:
3590141cc406Sopenharmony_ci        rt_turn_on_lamp();
3591141cc406Sopenharmony_ci	usleep(500000); /* Give the lamp time to settle */
3592141cc406Sopenharmony_ci        break;
3593141cc406Sopenharmony_ci      }
3594141cc406Sopenharmony_ci
3595141cc406Sopenharmony_ci      dcd.pixelnow = dcd.channelnow = dcd.firstrowdone = 0;
3596141cc406Sopenharmony_ci      rts8801_fullscan (x, iCalibY, w, detailed_calibration_rows + 1,
3597141cc406Sopenharmony_ci                        resolution, resolution, HP3500_COLOR_SCAN,
3598141cc406Sopenharmony_ci                        (rts8801_callback) accumfunc, &dcd,
3599141cc406Sopenharmony_ci			calib_info,
3600141cc406Sopenharmony_ci                        RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS,
3601141cc406Sopenharmony_ci			red_calibration_offset,
3602141cc406Sopenharmony_ci			green_calibration_offset,
3603141cc406Sopenharmony_ci			blue_calibration_offset,
3604141cc406Sopenharmony_ci			end_calibration_offset,
3605141cc406Sopenharmony_ci			0, 0);
3606141cc406Sopenharmony_ci
3607141cc406Sopenharmony_ci      DBG (10, " Detailed calibration scan %d completed\n", pass);
3608141cc406Sopenharmony_ci
3609141cc406Sopenharmony_ci      for (i = 0; i < 3; ++i)
3610141cc406Sopenharmony_ci        {
3611141cc406Sopenharmony_ci          int idx =
3612141cc406Sopenharmony_ci            (i == 0) ? red_calibration_offset :
3613141cc406Sopenharmony_ci	    (i == 1) ? green_calibration_offset :
3614141cc406Sopenharmony_ci                       blue_calibration_offset;
3615141cc406Sopenharmony_ci
3616141cc406Sopenharmony_ci          for (j = 0; j < w; ++j)
3617141cc406Sopenharmony_ci            {
3618141cc406Sopenharmony_ci              double multnow = 0x80;
3619141cc406Sopenharmony_ci              int offnow = 0;
3620141cc406Sopenharmony_ci
3621141cc406Sopenharmony_ci              /* This seems to be the approach for reg 0x40 & 0x3f == 0x27, which allows detailed
3622141cc406Sopenharmony_ci               * calibration to return either higher or lower values.
3623141cc406Sopenharmony_ci               */
3624141cc406Sopenharmony_ci
3625141cc406Sopenharmony_ci              {
3626141cc406Sopenharmony_ci                double denom1 =
3627141cc406Sopenharmony_ci                  calcmedian (dcd.buffers[i], j, w, detailed_calibration_rows);
3628141cc406Sopenharmony_ci
3629141cc406Sopenharmony_ci		switch (pass)
3630141cc406Sopenharmony_ci                  {
3631141cc406Sopenharmony_ci                  case DETAILED_PASS_OFFSETS:
3632141cc406Sopenharmony_ci                    /* The offset is the number needed to be subtracted from "black" at detailed gain = 0x80,
3633141cc406Sopenharmony_ci                     * which is the value we started with. For the next round, pull the gain down to 0x20. Our
3634141cc406Sopenharmony_ci                     * next scan is a test scan to confirm the offset works.
3635141cc406Sopenharmony_ci                     */
3636141cc406Sopenharmony_ci                    multnow = 0x20;
3637141cc406Sopenharmony_ci                    offnow = denom1;
3638141cc406Sopenharmony_ci                    break;
3639141cc406Sopenharmony_ci
3640141cc406Sopenharmony_ci                  case DETAILED_PASS_GAINS_FIRSTPASS:
3641141cc406Sopenharmony_ci                    multnow = 128.0 / denom1 * 0x20; /* Then bring it up to whatever we need to hit 192 */
3642141cc406Sopenharmony_ci                    if (multnow > 255)
3643141cc406Sopenharmony_ci                      multnow = 255;
3644141cc406Sopenharmony_ci                    offnow = pDetailedCalib[idx];
3645141cc406Sopenharmony_ci                    break;
3646141cc406Sopenharmony_ci
3647141cc406Sopenharmony_ci                  case DETAILED_PASS_GAINS_SECONDPASS:
3648141cc406Sopenharmony_ci                    multnow = 255.0 / denom1 * contrast_adjust * pDetailedCalib[idx+1]; /* And finally to 255 */
3649141cc406Sopenharmony_ci                    offnow = pDetailedCalib[idx] - brightness_adjust * 0x80 / multnow;
3650141cc406Sopenharmony_ci
3651141cc406Sopenharmony_ci                    if (offnow < 0)
3652141cc406Sopenharmony_ci                      {
3653141cc406Sopenharmony_ci                        postprocess_offsets[ppidx] = multnow * offnow / 0x80;
3654141cc406Sopenharmony_ci                        offnow = 0;
3655141cc406Sopenharmony_ci                        needs_postprocessed_calibration = 1;
3656141cc406Sopenharmony_ci                      }
3657141cc406Sopenharmony_ci                    else if (offnow > 255)
3658141cc406Sopenharmony_ci                      {
3659141cc406Sopenharmony_ci                        postprocess_offsets[ppidx] = multnow * (offnow - 255) / 0x80;
3660141cc406Sopenharmony_ci                        offnow = 255;
3661141cc406Sopenharmony_ci                        needs_postprocessed_calibration = 1;
3662141cc406Sopenharmony_ci                      }
3663141cc406Sopenharmony_ci                    else
3664141cc406Sopenharmony_ci                      {
3665141cc406Sopenharmony_ci                        postprocess_offsets[ppidx] = 0;
3666141cc406Sopenharmony_ci                      }
3667141cc406Sopenharmony_ci                    if (multnow > 255)
3668141cc406Sopenharmony_ci                      {
3669141cc406Sopenharmony_ci                        postprocess_gains[ppidx] = multnow / 255;
3670141cc406Sopenharmony_ci                        multnow = 255;
3671141cc406Sopenharmony_ci                        needs_postprocessed_calibration = 1;
3672141cc406Sopenharmony_ci                      }
3673141cc406Sopenharmony_ci                    else
3674141cc406Sopenharmony_ci                      {
3675141cc406Sopenharmony_ci                        postprocess_gains[ppidx] = 1.0;
3676141cc406Sopenharmony_ci                      }
3677141cc406Sopenharmony_ci                    break;
3678141cc406Sopenharmony_ci                  }
3679141cc406Sopenharmony_ci              }
3680141cc406Sopenharmony_ci              if (offnow > 255)
3681141cc406Sopenharmony_ci                offnow = 255;
3682141cc406Sopenharmony_ci
3683141cc406Sopenharmony_ci              for (k = 0; k < resolution_divisor; ++k)
3684141cc406Sopenharmony_ci                {
3685141cc406Sopenharmony_ci                  pDetailedCalib[idx++] = offnow;         /* Subtract this value from the result  at gains = 0x80*/
3686141cc406Sopenharmony_ci                  pDetailedCalib[idx++] = multnow;        /* Then multiply by this value divided by 0x80	*/
3687141cc406Sopenharmony_ci                }
3688141cc406Sopenharmony_ci              ++ppidx;
3689141cc406Sopenharmony_ci            }
3690141cc406Sopenharmony_ci        }
3691141cc406Sopenharmony_ci
3692141cc406Sopenharmony_ci      if (pass == DETAILED_PASS_GAINS_SECONDPASS)
3693141cc406Sopenharmony_ci        {
3694141cc406Sopenharmony_ci           /* Build gamma table */
3695141cc406Sopenharmony_ci           unsigned char *redgamma = pDetailedCalib;
3696141cc406Sopenharmony_ci           unsigned char *greengamma = redgamma + 512;
3697141cc406Sopenharmony_ci           unsigned char *bluegamma = greengamma + 512;
3698141cc406Sopenharmony_ci           double val;
3699141cc406Sopenharmony_ci	   double invgamma = 1.0l / gamma;
3700141cc406Sopenharmony_ci
3701141cc406Sopenharmony_ci           *redgamma++ = *bluegamma++ = *greengamma++ = 0;
3702141cc406Sopenharmony_ci
3703141cc406Sopenharmony_ci           /* The windows driver does a linear interpolation for the next 19 boundaries */
3704141cc406Sopenharmony_ci           val = pow (20.0l / 255, invgamma) * 255;
3705141cc406Sopenharmony_ci
3706141cc406Sopenharmony_ci	   for (j = 1; j <= 20; ++j)
3707141cc406Sopenharmony_ci             {
3708141cc406Sopenharmony_ci               *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5;
3709141cc406Sopenharmony_ci               *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5;
3710141cc406Sopenharmony_ci             }
3711141cc406Sopenharmony_ci
3712141cc406Sopenharmony_ci           for (; j <= 255; ++j)
3713141cc406Sopenharmony_ci             {
3714141cc406Sopenharmony_ci               val = pow((double) j / 255, invgamma) * 255;
3715141cc406Sopenharmony_ci
3716141cc406Sopenharmony_ci               *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5;
3717141cc406Sopenharmony_ci               *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5;
3718141cc406Sopenharmony_ci             }
3719141cc406Sopenharmony_ci           *redgamma++ = *bluegamma++ = *greengamma++ = 255;
3720141cc406Sopenharmony_ci        }
3721141cc406Sopenharmony_ci
3722141cc406Sopenharmony_ci      DBG (10, "\n");
3723141cc406Sopenharmony_ci
3724141cc406Sopenharmony_ci      rt_set_sram_page (0);
3725141cc406Sopenharmony_ci      rt_set_one_register (0x93, r93setting);
3726141cc406Sopenharmony_ci      rt_write_sram (calibration_size, pDetailedCalib);
3727141cc406Sopenharmony_ci    }
3728141cc406Sopenharmony_ci
3729141cc406Sopenharmony_ci  /* And finally, perform the scan */
3730141cc406Sopenharmony_ci  DBG (10, "Scanning\n");
3731141cc406Sopenharmony_ci
3732141cc406Sopenharmony_ci  rts8801_rewind ();
3733141cc406Sopenharmony_ci
3734141cc406Sopenharmony_ci  rts8801_fullscan (x, y, w, h, resolution, resolution, colour, cbfunc, param,
3735141cc406Sopenharmony_ci		    calib_info, 0,
3736141cc406Sopenharmony_ci		    red_calibration_offset, green_calibration_offset,
3737141cc406Sopenharmony_ci		    blue_calibration_offset, end_calibration_offset,
3738141cc406Sopenharmony_ci                    needs_postprocessed_calibration ? postprocess_offsets : 0,
3739141cc406Sopenharmony_ci                    needs_postprocessed_calibration ? postprocess_gains : 0);
3740141cc406Sopenharmony_ci
3741141cc406Sopenharmony_ci  rt_turn_off_lamp ();
3742141cc406Sopenharmony_ci
3743141cc406Sopenharmony_ci  rts8801_rewind ();
3744141cc406Sopenharmony_ci  rt_set_powersave_mode (1);
3745141cc406Sopenharmony_ci
3746141cc406Sopenharmony_ci  if (pDetailedCalib)
3747141cc406Sopenharmony_ci    free (pDetailedCalib);
3748141cc406Sopenharmony_ci  if (detail_buffer)
3749141cc406Sopenharmony_ci    free (detail_buffer);
3750141cc406Sopenharmony_ci  if (tdetail_buffer)
3751141cc406Sopenharmony_ci    free(tdetail_buffer);
3752141cc406Sopenharmony_ci  if (postprocess_gains)
3753141cc406Sopenharmony_ci    free(postprocess_gains);
3754141cc406Sopenharmony_ci  if (postprocess_offsets)
3755141cc406Sopenharmony_ci    free(postprocess_offsets);
3756141cc406Sopenharmony_ci  return 0;
3757141cc406Sopenharmony_ci}
3758141cc406Sopenharmony_ci
3759141cc406Sopenharmony_cistatic int
3760141cc406Sopenharmony_ciwritefunc (struct hp3500_write_info *winfo, int bytes, char *data)
3761141cc406Sopenharmony_ci{
3762141cc406Sopenharmony_ci  static int warned = 0;
3763141cc406Sopenharmony_ci
3764141cc406Sopenharmony_ci  if (bytes > winfo->bytesleft)
3765141cc406Sopenharmony_ci    {
3766141cc406Sopenharmony_ci      if (!warned)
3767141cc406Sopenharmony_ci	{
3768141cc406Sopenharmony_ci	  warned = 1;
3769141cc406Sopenharmony_ci	  DBG (1, "Overflow protection triggered\n");
3770141cc406Sopenharmony_ci	  rt_stop_moving ();
3771141cc406Sopenharmony_ci	}
3772141cc406Sopenharmony_ci      bytes = winfo->bytesleft;
3773141cc406Sopenharmony_ci      if (!bytes)
3774141cc406Sopenharmony_ci	return 0;
3775141cc406Sopenharmony_ci    }
3776141cc406Sopenharmony_ci  winfo->bytesleft -= bytes;
3777141cc406Sopenharmony_ci  return write (winfo->scanner->pipe_w, data, bytes) == bytes;
3778141cc406Sopenharmony_ci}
3779141cc406Sopenharmony_ci
3780141cc406Sopenharmony_ci#ifdef _POSIX_SOURCE
3781141cc406Sopenharmony_cistatic void
3782141cc406Sopenharmony_cisigtermHandler (int signal)
3783141cc406Sopenharmony_ci{
3784141cc406Sopenharmony_ci  (void) signal;		/* get rid of compiler warning */
3785141cc406Sopenharmony_ci  cancelled_scan = 1;
3786141cc406Sopenharmony_ci}
3787141cc406Sopenharmony_ci#endif
3788141cc406Sopenharmony_ci
3789141cc406Sopenharmony_cistatic int
3790141cc406Sopenharmony_cireader_process (void *pv)
3791141cc406Sopenharmony_ci{
3792141cc406Sopenharmony_ci  struct hp3500_data *scanner = pv;
3793141cc406Sopenharmony_ci  time_t t;
3794141cc406Sopenharmony_ci  sigset_t ignore_set;
3795141cc406Sopenharmony_ci  sigset_t sigterm_set;
3796141cc406Sopenharmony_ci  struct SIGACTION act;
3797141cc406Sopenharmony_ci  struct hp3500_write_info winfo;
3798141cc406Sopenharmony_ci  int status;
3799141cc406Sopenharmony_ci
3800141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
3801141cc406Sopenharmony_ci    {
3802141cc406Sopenharmony_ci      close (scanner->pipe_r);
3803141cc406Sopenharmony_ci
3804141cc406Sopenharmony_ci      sigfillset (&ignore_set);
3805141cc406Sopenharmony_ci      sigdelset (&ignore_set, SIGTERM);
3806141cc406Sopenharmony_ci#if     defined (__APPLE__) && defined (__MACH__)
3807141cc406Sopenharmony_ci      sigdelset (&ignore_set, SIGUSR2);
3808141cc406Sopenharmony_ci#endif
3809141cc406Sopenharmony_ci      sigprocmask (SIG_SETMASK, &ignore_set, 0);
3810141cc406Sopenharmony_ci
3811141cc406Sopenharmony_ci      sigemptyset (&sigterm_set);
3812141cc406Sopenharmony_ci      sigaddset (&sigterm_set, SIGTERM);
3813141cc406Sopenharmony_ci
3814141cc406Sopenharmony_ci      memset (&act, 0, sizeof (act));
3815141cc406Sopenharmony_ci#ifdef     _POSIX_SOURCE
3816141cc406Sopenharmony_ci      act.sa_handler = sigtermHandler;
3817141cc406Sopenharmony_ci#endif
3818141cc406Sopenharmony_ci      sigaction (SIGTERM, &act, 0);
3819141cc406Sopenharmony_ci    }
3820141cc406Sopenharmony_ci
3821141cc406Sopenharmony_ci  /* Warm up the lamp again if our last scan ended more than 5 minutes ago. */
3822141cc406Sopenharmony_ci  time (&t);
3823141cc406Sopenharmony_ci  do_warmup = (t - scanner->last_scan) > 300;
3824141cc406Sopenharmony_ci
3825141cc406Sopenharmony_ci  if (getenv ("HP3500_NOWARMUP") && atoi (getenv ("HP3500_NOWARMUP")) > 0)
3826141cc406Sopenharmony_ci    do_warmup = 0;
3827141cc406Sopenharmony_ci
3828141cc406Sopenharmony_ci  udh = scanner->sfd;
3829141cc406Sopenharmony_ci
3830141cc406Sopenharmony_ci  cancelled_scan = 0;
3831141cc406Sopenharmony_ci
3832141cc406Sopenharmony_ci  winfo.scanner = scanner;
3833141cc406Sopenharmony_ci  winfo.bytesleft =
3834141cc406Sopenharmony_ci    scanner->bytes_per_scan_line * scanner->scan_height_pixels;
3835141cc406Sopenharmony_ci
3836141cc406Sopenharmony_ci  if (getenv ("HP3500_SLEEP"))
3837141cc406Sopenharmony_ci    {
3838141cc406Sopenharmony_ci      int seconds = atoi (getenv ("HP3500_SLEEP"));
3839141cc406Sopenharmony_ci
3840141cc406Sopenharmony_ci      DBG (1, "Backend process %d sleeping for %d seconds\n", getpid (),
3841141cc406Sopenharmony_ci	   seconds);
3842141cc406Sopenharmony_ci      sleep (seconds);
3843141cc406Sopenharmony_ci    }
3844141cc406Sopenharmony_ci  DBG (10, "Scanning at %ddpi, mode=%s\n", scanner->resolution,
3845141cc406Sopenharmony_ci       scan_mode_list[scanner->mode]);
3846141cc406Sopenharmony_ci  if (rts8801_scan
3847141cc406Sopenharmony_ci      (scanner->actres_pixels.left + 250 * scanner->resolution / 1200,
3848141cc406Sopenharmony_ci       scanner->actres_pixels.top + 599 * scanner->resolution / 1200,
3849141cc406Sopenharmony_ci       scanner->actres_pixels.right - scanner->actres_pixels.left,
3850141cc406Sopenharmony_ci       scanner->actres_pixels.bottom - scanner->actres_pixels.top,
3851141cc406Sopenharmony_ci       scanner->resolution, scanner->mode, scanner->brightness,
3852141cc406Sopenharmony_ci       scanner->contrast, (rts8801_callback) writefunc, &winfo,
3853141cc406Sopenharmony_ci       scanner->gamma) >= 0)
3854141cc406Sopenharmony_ci    status = SANE_STATUS_GOOD;
3855141cc406Sopenharmony_ci  status = SANE_STATUS_IO_ERROR;
3856141cc406Sopenharmony_ci  close (scanner->pipe_w);
3857141cc406Sopenharmony_ci  return status;
3858141cc406Sopenharmony_ci}
3859141cc406Sopenharmony_ci
3860141cc406Sopenharmony_cistatic size_t
3861141cc406Sopenharmony_cimax_string_size (char const **strings)
3862141cc406Sopenharmony_ci{
3863141cc406Sopenharmony_ci  size_t size, max_size = 0;
3864141cc406Sopenharmony_ci  SANE_Int i;
3865141cc406Sopenharmony_ci
3866141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
3867141cc406Sopenharmony_ci    {
3868141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
3869141cc406Sopenharmony_ci      if (size > max_size)
3870141cc406Sopenharmony_ci	max_size = size;
3871141cc406Sopenharmony_ci    }
3872141cc406Sopenharmony_ci  return max_size;
3873141cc406Sopenharmony_ci}
3874