1141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
2141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
3141cc406Sopenharmony_ci   coolscan.c , version  0.4.4
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   This file implements a SANE backend for COOLSCAN flatbed scanners.  */
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci/* SANE-FLOW-DIAGRAMM
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci   - sane_init() : initialize backend, attach scanners
49141cc406Sopenharmony_ci   . - sane_get_devices() : query list of scanner-devices
50141cc406Sopenharmony_ci   . - sane_open() : open a particular scanner-device
51141cc406Sopenharmony_ci   . . - sane_set_io_mode : set blocking-mode
52141cc406Sopenharmony_ci   . . - sane_get_select_fd : get scanner-fd
53141cc406Sopenharmony_ci   . . - sane_get_option_descriptor() : get option information
54141cc406Sopenharmony_ci   . . - sane_control_option() : change option values
55141cc406Sopenharmony_ci   . .
56141cc406Sopenharmony_ci   . . - sane_start() : start image acquisition
57141cc406Sopenharmony_ci   . .   - sane_get_parameters() : returns actual scan-parameters
58141cc406Sopenharmony_ci   . .   - sane_read() : read image-data (from pipe)
59141cc406Sopenharmony_ci   . .
60141cc406Sopenharmony_ci   . . - sane_cancel() : cancel operation
61141cc406Sopenharmony_ci   . - sane_close() : close opened scanner-device
62141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend
63141cc406Sopenharmony_ci */
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#ifdef _AIX
66141cc406Sopenharmony_ci# include "lalloca.h"		/* MUST come first for AIX! */
67141cc406Sopenharmony_ci#endif
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#include "../include/sane/config.h"
70141cc406Sopenharmony_ci#include "lalloca.h"
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci#include <errno.h>
73141cc406Sopenharmony_ci#include <math.h>
74141cc406Sopenharmony_ci#include <fcntl.h>
75141cc406Sopenharmony_ci#include <limits.h>
76141cc406Sopenharmony_ci#include <signal.h>
77141cc406Sopenharmony_ci#include <stdio.h>
78141cc406Sopenharmony_ci#include <stdlib.h>
79141cc406Sopenharmony_ci#include <string.h>
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci#include <sys/types.h>
82141cc406Sopenharmony_ci#include <unistd.h>
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci#include "../include/sane/sane.h"
85141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
86141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
87141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
88141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
89141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
92141cc406Sopenharmony_ci#define COOLSCAN_CONFIG_FILE "coolscan.conf"
93141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci#include "coolscan.h"
96141cc406Sopenharmony_ci#include "coolscan-scsidef.h"
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci#ifndef PATH_MAX
100141cc406Sopenharmony_ci#define PATH_MAX       1024
101141cc406Sopenharmony_ci#endif
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
104141cc406Sopenharmony_cistatic const SANE_Int resolution_list[] =
105141cc406Sopenharmony_ci{
106141cc406Sopenharmony_ci  25,
107141cc406Sopenharmony_ci  2700, 1350, 900, 675, 540, 450, 385, 337, 300, 270, 245, 225, 207,
108141cc406Sopenharmony_ci  192, 180, 168, 158, 150, 142, 135, 128, 122, 117, 112, 108
109141cc406Sopenharmony_ci};
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci#define coolscan_do_scsi_open(dev, fd, handler) sanei_scsi_open(dev, fd, handler)
113141cc406Sopenharmony_ci#define coolscan_do_scsi_close(fd)              sanei_scsi_close(fd)
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci#define	COOLSCAN_MAX_RETRY	25
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_cistatic SANE_Status sense_handler (int scsi_fd, unsigned char * result, void *arg);
119141cc406Sopenharmony_cistatic int coolscan_check_values (Coolscan_t * s);
120141cc406Sopenharmony_cistatic int get_internal_info (Coolscan_t *);
121141cc406Sopenharmony_cistatic void coolscan_get_inquiry_values (Coolscan_t *);
122141cc406Sopenharmony_cistatic void hexdump (int level, char *comment, unsigned char *p, int l);
123141cc406Sopenharmony_cistatic int swap_res (Coolscan_t * s);
124141cc406Sopenharmony_ci/* --------------------------- COOLSCAN_DO_SCSI_CMD  ----------------------- */
125141cc406Sopenharmony_cistatic int
126141cc406Sopenharmony_cido_scsi_cmd (int fd, unsigned char *cmd, int cmd_len, unsigned char *out, size_t out_len)
127141cc406Sopenharmony_ci{
128141cc406Sopenharmony_ci  int ret;
129141cc406Sopenharmony_ci  size_t ol = out_len;
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci  hexdump (20, "", cmd, cmd_len);
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci  ret = sanei_scsi_cmd (fd, cmd, cmd_len, out, &ol);
134141cc406Sopenharmony_ci  if ((out_len != 0) && (out_len != ol))
135141cc406Sopenharmony_ci    {
136141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd: asked %lu bytes, got %lu\n",
137141cc406Sopenharmony_ci	   (u_long) out_len, (u_long) ol);
138141cc406Sopenharmony_ci    }
139141cc406Sopenharmony_ci  if (ret)
140141cc406Sopenharmony_ci    {
141141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd: returning 0x%08x\n", ret);
142141cc406Sopenharmony_ci    }
143141cc406Sopenharmony_ci  DBG (10, "sanei_scsi_cmd: returning %lu bytes:\n", (u_long) ol);
144141cc406Sopenharmony_ci  if (out != NULL && out_len != 0)
145141cc406Sopenharmony_ci    hexdump (15, "", out, (out_len > 0x60) ? 0x60 : out_len);
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci  return ret;
148141cc406Sopenharmony_ci}
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_cistatic int
152141cc406Sopenharmony_cirequest_sense_parse (unsigned char *sensed_data)
153141cc406Sopenharmony_ci{
154141cc406Sopenharmony_ci  int ret, sense, asc, ascq;
155141cc406Sopenharmony_ci  sense = get_RS_sense_key (sensed_data);
156141cc406Sopenharmony_ci  asc = get_RS_ASC (sensed_data);
157141cc406Sopenharmony_ci  ascq = get_RS_ASCQ (sensed_data);
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci  ret = SANE_STATUS_IO_ERROR;
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci  switch (sense)
162141cc406Sopenharmony_ci    {
163141cc406Sopenharmony_ci    case 0x0:
164141cc406Sopenharmony_ci      DBG (5, "\t%d/%d/%d: Scanner ready\n", sense, asc, ascq);
165141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_ci    case 0x1:
168141cc406Sopenharmony_ci      if ((0x37 == asc) && (0x00 == ascq)) {
169141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Rounded Parameter\n", sense, asc, ascq);
170141cc406Sopenharmony_ci        ret = SANE_STATUS_GOOD;
171141cc406Sopenharmony_ci      }
172141cc406Sopenharmony_ci      else if ((0x61 == asc) && (0x02 == ascq))
173141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Out Of Focus\n", sense, asc, ascq);
174141cc406Sopenharmony_ci      else
175141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
176141cc406Sopenharmony_ci      break;
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci    case 0x2:
179141cc406Sopenharmony_ci      if ((0x4 == asc) && (0x1 == ascq)) {
180141cc406Sopenharmony_ci	DBG (10, "\t%d/%d/%d: Logical unit is in process of becoming ready\n",
181141cc406Sopenharmony_ci	     sense, asc, ascq);
182141cc406Sopenharmony_ci	ret = SANE_STATUS_DEVICE_BUSY;
183141cc406Sopenharmony_ci      }
184141cc406Sopenharmony_ci      else if ((0x3A == asc) && (0x00 == ascq))
185141cc406Sopenharmony_ci	{
186141cc406Sopenharmony_ci	  DBG (1, "\t%d/%d/%d: No Diapo inserted\n", sense, asc, ascq);
187141cc406Sopenharmony_ci          ret = SANE_STATUS_GOOD;
188141cc406Sopenharmony_ci	}
189141cc406Sopenharmony_ci      else if ((0x60 == asc) && (0x00 == ascq))
190141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Lamp Failure\n", sense, asc, ascq);
191141cc406Sopenharmony_ci      else
192141cc406Sopenharmony_ci	{
193141cc406Sopenharmony_ci	  DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
194141cc406Sopenharmony_ci          ret = SANE_STATUS_GOOD;
195141cc406Sopenharmony_ci	}
196141cc406Sopenharmony_ci      break;
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci    case 0x3:
199141cc406Sopenharmony_ci      if ((0x3b == asc) && (0xe == ascq))
200141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Medium source element empty\n", sense, asc, ascq);
201141cc406Sopenharmony_ci      else if ((0x53 == asc) && (0x00 == ascq))
202141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Media Load of Eject Failed\n", sense, asc, ascq);
203141cc406Sopenharmony_ci      else
204141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
205141cc406Sopenharmony_ci      break;
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci    case 0x4:
208141cc406Sopenharmony_ci      if ((0x15 == asc) && (0x1 == ascq))
209141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Mechanical Positioning Error\n", sense, asc, ascq);
210141cc406Sopenharmony_ci      else
211141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
212141cc406Sopenharmony_ci      break;
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci    case 0x5:
215141cc406Sopenharmony_ci      if ((0x00 == asc) && (0x5 == ascq))
216141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: End-Of-Data Detected\n", sense, asc, ascq);
217141cc406Sopenharmony_ci      else if ((0x1a == asc) && (0x00 == ascq))
218141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Parameter List Length Error\n", sense, asc, ascq);
219141cc406Sopenharmony_ci      else if ((0x20 == asc) && (0x00 == ascq))
220141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Invalid Command Operation Code\n", sense, asc, ascq);
221141cc406Sopenharmony_ci      else if ((0x24 == asc) && (0x00 == ascq))
222141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Invalid Field In CDB\n", sense, asc, ascq);
223141cc406Sopenharmony_ci      else if ((0x25 == asc) && (0x00 == ascq))
224141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Logical Unit Not Supported\n", sense, asc, ascq);
225141cc406Sopenharmony_ci      else if ((0x26 == asc) && (0x00 == ascq))
226141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Invalid Field in Parameter List\n", sense, asc, ascq);
227141cc406Sopenharmony_ci      else if ((0x2c == asc) && (0x00 == ascq))
228141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Command Sequence Error\n", sense, asc, ascq);
229141cc406Sopenharmony_ci      else if ((0x39 == asc) && (0x00 == ascq))
230141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Saving Parameters Not Supported\n", sense, asc, ascq);
231141cc406Sopenharmony_ci      else if ((0x3d == asc) && (0x00 == ascq))
232141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Invalid Bits In Identify Message\n", sense, asc, ascq);
233141cc406Sopenharmony_ci      else
234141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
235141cc406Sopenharmony_ci      break;
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci    case 0x6:
238141cc406Sopenharmony_ci      if ((0x29 == asc) && (0x0 == ascq))
239141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Power On, Reset, or Bus Device Reset Occurred\n", sense, asc, ascq);
240141cc406Sopenharmony_ci      else if ((0x2a == asc) && (0x1 == ascq))
241141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Mode Parameters Changed\n", sense, asc, ascq);
242141cc406Sopenharmony_ci      else
243141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
244141cc406Sopenharmony_ci      break;
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci    case 0xb:
247141cc406Sopenharmony_ci      if ((0x43 == asc) && (0x0 == ascq))
248141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Message Error\n", sense, asc, ascq);
249141cc406Sopenharmony_ci      else if ((0x47 == asc) && (0x0 == ascq))
250141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: SCSI Parity Error\n", sense, asc, ascq);
251141cc406Sopenharmony_ci      else if ((0x48 == asc) && (0x0 == ascq))
252141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Initiator Detected Error Message Received\n", sense, asc, ascq);
253141cc406Sopenharmony_ci      else if ((0x49 == asc) && (0x0 == ascq))
254141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Invalid Message Error\n", sense, asc, ascq);
255141cc406Sopenharmony_ci      else if ((0x4e == asc) && (0x0 == ascq))
256141cc406Sopenharmony_ci	DBG (1, "\t%d/%d/%d: Overlapped Commands Attempted\n", sense, asc, ascq);
257141cc406Sopenharmony_ci      else
258141cc406Sopenharmony_ci	DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
259141cc406Sopenharmony_ci      break;
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci    default:
262141cc406Sopenharmony_ci      DBG (1, "\tUnknown - Sense=%d, ASC=%d, ASCQ=%d\n", sense, asc, ascq);
263141cc406Sopenharmony_ci      break;
264141cc406Sopenharmony_ci    }				/* switch */
265141cc406Sopenharmony_ci  return ret;
266141cc406Sopenharmony_ci}
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci/*
269141cc406Sopenharmony_ci *  wait_scanner should spin until TEST_UNIT_READY returns 0 (GOOD)
270141cc406Sopenharmony_ci *  returns 0 on success,
271141cc406Sopenharmony_ci *  returns -1 on error.
272141cc406Sopenharmony_ci */
273141cc406Sopenharmony_cistatic int
274141cc406Sopenharmony_ciwait_scanner (Coolscan_t * s)
275141cc406Sopenharmony_ci{
276141cc406Sopenharmony_ci  int ret = -1;
277141cc406Sopenharmony_ci  int cnt = 0;
278141cc406Sopenharmony_ci  DBG (10, "wait_scanner: Testing if scanner is ready\n");
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_ci  while (ret != 0)
281141cc406Sopenharmony_ci    {
282141cc406Sopenharmony_ci      ret = do_scsi_cmd (s->sfd, test_unit_ready.cmd,
283141cc406Sopenharmony_ci			 test_unit_ready.size, 0, 0);
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci      if (ret == SANE_STATUS_DEVICE_BUSY)
286141cc406Sopenharmony_ci	{
287141cc406Sopenharmony_ci	  usleep (500000);	/* wait 0.5 seconds */
288141cc406Sopenharmony_ci	  if (cnt++ > 40)
289141cc406Sopenharmony_ci	    {			/* 20 sec. max (prescan takes up to 15 sec. */
290141cc406Sopenharmony_ci	      DBG (1, "wait_scanner: scanner does NOT get ready\n");
291141cc406Sopenharmony_ci	      return -1;
292141cc406Sopenharmony_ci	    }
293141cc406Sopenharmony_ci	}
294141cc406Sopenharmony_ci      else if (ret == SANE_STATUS_GOOD)
295141cc406Sopenharmony_ci	{
296141cc406Sopenharmony_ci	  DBG (10, "wait_scanner: scanner is ready\n");
297141cc406Sopenharmony_ci	  return ret;
298141cc406Sopenharmony_ci	}
299141cc406Sopenharmony_ci      else
300141cc406Sopenharmony_ci	{
301141cc406Sopenharmony_ci	  DBG (1, "wait_scanner: test unit ready failed (%s)\n",
302141cc406Sopenharmony_ci	       sane_strstatus (ret));
303141cc406Sopenharmony_ci	}
304141cc406Sopenharmony_ci    }
305141cc406Sopenharmony_ci  return 0;
306141cc406Sopenharmony_ci}
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci/* ------------------------- COOLSCAN GRAB SCANNER ----------------------------- */
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci/* coolscan_grab_scanner should go through the following command sequence:
312141cc406Sopenharmony_ci * TEST UNIT READY
313141cc406Sopenharmony_ci *     CHECK CONDITION  \
314141cc406Sopenharmony_ci * REQUEST SENSE         > These should be handled automagically by
315141cc406Sopenharmony_ci *     UNIT ATTENTION   /  the kernel if they happen (powerup/reset)
316141cc406Sopenharmony_ci * TEST UNIT READY
317141cc406Sopenharmony_ci *     GOOD
318141cc406Sopenharmony_ci * RESERVE UNIT
319141cc406Sopenharmony_ci *     GOOD
320141cc406Sopenharmony_ci *
321141cc406Sopenharmony_ci * It is then responsible for installing appropriate signal handlers
322141cc406Sopenharmony_ci * to call emergency_give_scanner() if user aborts.
323141cc406Sopenharmony_ci */
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_cistatic int
326141cc406Sopenharmony_cicoolscan_grab_scanner (Coolscan_t * s)
327141cc406Sopenharmony_ci{
328141cc406Sopenharmony_ci  int ret;
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci  DBG (10, "grabbing scanner\n");
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci  wait_scanner (s);		/* wait for scanner ready, if not print
333141cc406Sopenharmony_ci				   sense and return 1 */
334141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, reserve_unit.cmd, reserve_unit.size, NULL, 0);
335141cc406Sopenharmony_ci  if (ret)
336141cc406Sopenharmony_ci    return ret;
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci  DBG (10, "scanner reserved\n");
339141cc406Sopenharmony_ci  return 0;
340141cc406Sopenharmony_ci}
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci/*
343141cc406Sopenharmony_ci * Convert a size in ilu to the units expected by the scanner
344141cc406Sopenharmony_ci */
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_cistatic int
347141cc406Sopenharmony_ciresDivToVal (int res_div)
348141cc406Sopenharmony_ci{
349141cc406Sopenharmony_ci  if (res_div < 1 || res_div > resolution_list[0])
350141cc406Sopenharmony_ci    {
351141cc406Sopenharmony_ci      DBG (1, "Invalid resolution divisor %d \n", res_div);
352141cc406Sopenharmony_ci      return 2700;
353141cc406Sopenharmony_ci    }
354141cc406Sopenharmony_ci  else
355141cc406Sopenharmony_ci    {
356141cc406Sopenharmony_ci      return resolution_list[res_div];
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci}
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_cistatic int
361141cc406Sopenharmony_ciresValToDiv (int res_val)
362141cc406Sopenharmony_ci{
363141cc406Sopenharmony_ci  int res_div;
364141cc406Sopenharmony_ci  int max_res = resolution_list[0];
365141cc406Sopenharmony_ci  for (res_div = 1; res_div <= max_res; res_div++)
366141cc406Sopenharmony_ci    {
367141cc406Sopenharmony_ci      if (resolution_list[res_div] == res_val)
368141cc406Sopenharmony_ci	break;
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci  if (res_div > max_res)
371141cc406Sopenharmony_ci    {
372141cc406Sopenharmony_ci      DBG (1, "Invalid resolution value\n");
373141cc406Sopenharmony_ci      return 1;
374141cc406Sopenharmony_ci    }
375141cc406Sopenharmony_ci  else
376141cc406Sopenharmony_ci    {
377141cc406Sopenharmony_ci      return res_div;
378141cc406Sopenharmony_ci    }
379141cc406Sopenharmony_ci}
380141cc406Sopenharmony_ci/*
381141cc406Sopenharmony_ci * use mode select to force a measurement divisor of 2700
382141cc406Sopenharmony_ci */
383141cc406Sopenharmony_cistatic unsigned char mode_select[] =
384141cc406Sopenharmony_ci{
385141cc406Sopenharmony_ci  MODE_SELECT, 0x10, 0, 0, 20, 0,
386141cc406Sopenharmony_ci  0, 0, 0, 8,
387141cc406Sopenharmony_ci  0, 0, 0, 0, 0, 0, 0, 1,
388141cc406Sopenharmony_ci  3, 6, 0, 0, 0xA, 0x8C, 0, 0};
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_cistatic int
391141cc406Sopenharmony_ciselect_MUD (Coolscan_t * s)
392141cc406Sopenharmony_ci{
393141cc406Sopenharmony_ci  return do_scsi_cmd (s->sfd, mode_select, 26, NULL, 0);
394141cc406Sopenharmony_ci}
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_cistatic int
397141cc406Sopenharmony_cicoolscan_autofocus_LS30 (Coolscan_t * s)
398141cc406Sopenharmony_ci{
399141cc406Sopenharmony_ci  int x, y;
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  wait_scanner(s);
402141cc406Sopenharmony_ci  memcpy(s->buffer, autofocusLS30.cmd, autofocusLS30.size);
403141cc406Sopenharmony_ci  memcpy(s->buffer+ autofocusLS30.size, autofocuspos, 9);
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci  x = s->xmaxpix - (s->brx + s->tlx) / 2;
406141cc406Sopenharmony_ci  y = (s->bry + s->tly) / 2;
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  DBG (10, "Attempting AutoFocus at x=%d, y=%d\n", x, y);
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, s->buffer,
411141cc406Sopenharmony_ci	       autofocusLS30.size  + 9, NULL, 0);
412141cc406Sopenharmony_ci  /* Trashes when used in combination with scsi-driver AM53C974.o  */
413141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, command_c1.cmd,
414141cc406Sopenharmony_ci	       command_c1.size, NULL, 0);
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  DBG (10, "\tWaiting end of Autofocus\n");
417141cc406Sopenharmony_ci  wait_scanner (s);
418141cc406Sopenharmony_ci  DBG (10, "AutoFocused.\n");
419141cc406Sopenharmony_ci  return 0;
420141cc406Sopenharmony_ci}
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_cistatic int
423141cc406Sopenharmony_cicoolscan_autofocus (Coolscan_t * s)
424141cc406Sopenharmony_ci{
425141cc406Sopenharmony_ci  int x, y;
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci  if(s->LS>=2)
428141cc406Sopenharmony_ci    { return coolscan_autofocus_LS30(s);
429141cc406Sopenharmony_ci    }
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci  wait_scanner(s);
432141cc406Sopenharmony_ci  memcpy(s->buffer, autofocus.cmd, autofocus.size);
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci  x = s->xmaxpix - (s->brx + s->tlx) / 2;
435141cc406Sopenharmony_ci  y = (s->bry + s->tly) / 2;
436141cc406Sopenharmony_ci
437141cc406Sopenharmony_ci  DBG (10, "Attempting AutoFocus at x=%d, y=%d\n", x, y);
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  set_AF_XPoint (s->buffer, x);
440141cc406Sopenharmony_ci  set_AF_YPoint (s->buffer, y);
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci  set_AF_transferlength (s->buffer, 0); /* should be 8 !*/
443141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, s->buffer,
444141cc406Sopenharmony_ci	       autofocus.size  + AF_Point_length, NULL, 0);
445141cc406Sopenharmony_ci
446141cc406Sopenharmony_ci  sleep(5);		 	/* autofocus takes a minimum of 5 sec. */
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci  DBG (10, "\tWaiting end of Autofocus\n");
449141cc406Sopenharmony_ci  wait_scanner (s);
450141cc406Sopenharmony_ci  DBG (10, "AutoFocused.\n");
451141cc406Sopenharmony_ci  return 0;
452141cc406Sopenharmony_ci}
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci/*
455141cc406Sopenharmony_ci   static int
456141cc406Sopenharmony_ci   coolscan_abort_scan (Coolscan_t * s)
457141cc406Sopenharmony_ci   {
458141cc406Sopenharmony_ci   int ret;
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci   DBG (5, "Aborting scan...\n");
461141cc406Sopenharmony_ci   ret = do_scsi_cmd (s->sfd, sabort.cmd, sabort.size, NULL, 0);
462141cc406Sopenharmony_ci   if (ret)
463141cc406Sopenharmony_ci   DBG (5, "Scan Aborted\n");
464141cc406Sopenharmony_ci   else
465141cc406Sopenharmony_ci   DBG (5, "Not scanning\n");
466141cc406Sopenharmony_ci   return 0;
467141cc406Sopenharmony_ci   }
468141cc406Sopenharmony_ci */
469141cc406Sopenharmony_cistatic int
470141cc406Sopenharmony_cicoolscan_mode_sense (Coolscan_t * s)
471141cc406Sopenharmony_ci{
472141cc406Sopenharmony_ci  int ret, len;
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci  DBG (10, "Mode Sense...\n");
475141cc406Sopenharmony_ci  len = 12;
476141cc406Sopenharmony_ci  set_MS_DBD (mode_sense.cmd, 1);
477141cc406Sopenharmony_ci  set_MS_len (mode_sense.cmd, len);
478141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, mode_sense.cmd, mode_sense.size,
479141cc406Sopenharmony_ci		     s->buffer, len);
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci  if (ret == 0)
482141cc406Sopenharmony_ci    {
483141cc406Sopenharmony_ci      s->MUD = get_MS_MUD (s->buffer);
484141cc406Sopenharmony_ci      DBG (10, "\tMode Sensed (MUD is %d)\n", s->MUD);
485141cc406Sopenharmony_ci    }
486141cc406Sopenharmony_ci  return ret;
487141cc406Sopenharmony_ci}
488141cc406Sopenharmony_ci
489141cc406Sopenharmony_cistatic int
490141cc406Sopenharmony_cicoolscan_object_discharge (Coolscan_t * s)
491141cc406Sopenharmony_ci{
492141cc406Sopenharmony_ci  int ret;
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci  DBG (10, "Trying to discharge object...\n");
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci  memcpy (s->buffer, object_position.cmd, object_position.size);
497141cc406Sopenharmony_ci  set_OP_autofeed (s->buffer, OP_Discharge);
498141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer,
499141cc406Sopenharmony_ci		     object_position.size, NULL, 0);
500141cc406Sopenharmony_ci  wait_scanner (s);
501141cc406Sopenharmony_ci  DBG (10, "Object discharged.\n");
502141cc406Sopenharmony_ci  return ret;
503141cc406Sopenharmony_ci}
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_cistatic int
506141cc406Sopenharmony_cicoolscan_object_feed (Coolscan_t * s)
507141cc406Sopenharmony_ci{
508141cc406Sopenharmony_ci  int ret;
509141cc406Sopenharmony_ci  DBG (10, "Trying to feed object...\n");
510141cc406Sopenharmony_ci  if (!s->asf)
511141cc406Sopenharmony_ci    {
512141cc406Sopenharmony_ci      DBG (10, "\tAutofeeder not present.\n");
513141cc406Sopenharmony_ci      return 0;
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci  memcpy (s->buffer, object_position.cmd, object_position.size);
516141cc406Sopenharmony_ci  set_OP_autofeed (s->buffer, OP_Feed);
517141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer,
518141cc406Sopenharmony_ci		     object_position.size, NULL, 0);
519141cc406Sopenharmony_ci  wait_scanner (s);
520141cc406Sopenharmony_ci  DBG (10, "Object fed.\n");
521141cc406Sopenharmony_ci  return ret;
522141cc406Sopenharmony_ci}
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci/* coolscan_give_scanner should go through the following sequence:
525141cc406Sopenharmony_ci * OBJECT POSITION DISCHARGE
526141cc406Sopenharmony_ci *     GOOD
527141cc406Sopenharmony_ci * RELEASE UNIT
528141cc406Sopenharmony_ci *     GOOD
529141cc406Sopenharmony_ci */
530141cc406Sopenharmony_cistatic int
531141cc406Sopenharmony_cicoolscan_give_scanner (Coolscan_t * s)
532141cc406Sopenharmony_ci{
533141cc406Sopenharmony_ci  DBG (10, "trying to release scanner ...\n");
534141cc406Sopenharmony_ci  coolscan_object_discharge (s);
535141cc406Sopenharmony_ci  wait_scanner (s);
536141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, release_unit.cmd, release_unit.size, NULL, 0);
537141cc406Sopenharmony_ci  DBG (10, "scanner released\n");
538141cc406Sopenharmony_ci  return 0;
539141cc406Sopenharmony_ci}
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_cistatic int
543141cc406Sopenharmony_cicoolscan_set_window_param_LS20 (Coolscan_t * s, int prescan)
544141cc406Sopenharmony_ci{
545141cc406Sopenharmony_ci  unsigned char buffer_r[max_WDB_size];
546141cc406Sopenharmony_ci  int ret;
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  wait_scanner (s);
549141cc406Sopenharmony_ci  memset (buffer_r, '\0', max_WDB_size);	/* clear buffer */
550141cc406Sopenharmony_ci  memcpy (buffer_r, window_descriptor_block.cmd,
551141cc406Sopenharmony_ci	  window_descriptor_block.size);	/* copy preset data */
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_ci  set_WD_wid (buffer_r, WD_wid_all);	/* window identifier */
554141cc406Sopenharmony_ci  set_WD_auto (buffer_r, s->set_auto);	/* 0 or 1: don't know what it is */
555141cc406Sopenharmony_ci
556141cc406Sopenharmony_ci  set_WD_negative (buffer_r, s->negative);	/* Negative/positive slide */
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci  if (prescan)
559141cc406Sopenharmony_ci    {
560141cc406Sopenharmony_ci      set_WD_scanmode (buffer_r, WD_Prescan);
561141cc406Sopenharmony_ci    }
562141cc406Sopenharmony_ci  else
563141cc406Sopenharmony_ci    {
564141cc406Sopenharmony_ci      set_WD_scanmode (buffer_r, WD_Scan);
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci      /* geometry */
567141cc406Sopenharmony_ci      set_WD_Xres (buffer_r, resDivToVal (s->x_nres));	/* x resolution in dpi */
568141cc406Sopenharmony_ci      set_WD_Yres (buffer_r, resDivToVal (s->y_nres));	/* y resolution in dpi */
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ci      /* the coolscan  uses the upper right corner as the origin of coordinates */
571141cc406Sopenharmony_ci      /* xmax and ymax are given in 1200 dpi */
572141cc406Sopenharmony_ci      set_WD_ULX (buffer_r, (s->xmaxpix - s->brx));
573141cc406Sopenharmony_ci      set_WD_ULY (buffer_r, s->tly);	/* upper_edge y */
574141cc406Sopenharmony_ci      set_WD_width (buffer_r, (s->brx - s->tlx + 1));
575141cc406Sopenharmony_ci      set_WD_length (buffer_r, (s->bry - s->tly + 1));
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci      /* BTC */
578141cc406Sopenharmony_ci      if (s->brightness == 128)
579141cc406Sopenharmony_ci	{
580141cc406Sopenharmony_ci	  set_WD_brightness (buffer_r, 0);
581141cc406Sopenharmony_ci	}
582141cc406Sopenharmony_ci      else
583141cc406Sopenharmony_ci	{
584141cc406Sopenharmony_ci	  set_WD_brightness (buffer_r, s->brightness);	/* brightness */
585141cc406Sopenharmony_ci	}
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci      if (s->contrast == 128)
588141cc406Sopenharmony_ci	{
589141cc406Sopenharmony_ci	  set_WD_contrast (buffer_r, 0);
590141cc406Sopenharmony_ci	}
591141cc406Sopenharmony_ci      else
592141cc406Sopenharmony_ci	{
593141cc406Sopenharmony_ci	  set_WD_contrast (buffer_r, s->contrast);	/* contrast */
594141cc406Sopenharmony_ci	}
595141cc406Sopenharmony_ci
596141cc406Sopenharmony_ci      /* scanmode */
597141cc406Sopenharmony_ci      if (s->colormode == GREYSCALE)
598141cc406Sopenharmony_ci	set_WD_composition (buffer_r, WD_comp_grey);	/* GRAY composition */
599141cc406Sopenharmony_ci      else
600141cc406Sopenharmony_ci	set_WD_composition (buffer_r, WD_comp_rgb_full);	/* RGB composition */
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci      set_WD_dropoutcolor (buffer_r, s->dropoutcolor);	/* Which color to scan with when grayscale scan */
603141cc406Sopenharmony_ci      set_WD_transfermode (buffer_r, WD_LineSequence);
604141cc406Sopenharmony_ci      set_WD_gammaselection (buffer_r, s->gammaselection);	/* monitor/linear */
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_ci      set_WD_shading (buffer_r, WD_Shading_ON);		/* default for non-manufacturing */
607141cc406Sopenharmony_ci
608141cc406Sopenharmony_ci      if (1 == s->LS)
609141cc406Sopenharmony_ci	{			/* Analog gamma reserved on LS-1000 */
610141cc406Sopenharmony_ci	  set_WD_analog_gamma_R (buffer_r, 0);
611141cc406Sopenharmony_ci	  set_WD_analog_gamma_G (buffer_r, 0);
612141cc406Sopenharmony_ci	  set_WD_analog_gamma_R (buffer_r, 0);
613141cc406Sopenharmony_ci	}
614141cc406Sopenharmony_ci      else
615141cc406Sopenharmony_ci	{
616141cc406Sopenharmony_ci	  /* Quote spec: "It is recommended that analog gamma bits 5, 4 and 3 be
617141cc406Sopenharmony_ci	   * set to 1 (OFF) when the object type of byte 48 is positive and the
618141cc406Sopenharmony_ci	   * gamma specification of byte 51 is linear, and to 0 (ON) in all
619141cc406Sopenharmony_ci	   * other cases." */
620141cc406Sopenharmony_ci	  /*
621141cc406Sopenharmony_ci	  int foo;
622141cc406Sopenharmony_ci	  if ((buffer_r[48] == WD_Positive) && (buffer_r[51] == WD_Linear))
623141cc406Sopenharmony_ci	    foo = WD_Analog_Gamma_OFF;
624141cc406Sopenharmony_ci	  else
625141cc406Sopenharmony_ci	    foo = WD_Analog_Gamma_ON;
626141cc406Sopenharmony_ci	  set_WD_analog_gamma_R (buffer_r, foo);
627141cc406Sopenharmony_ci	  set_WD_analog_gamma_G (buffer_r, foo);
628141cc406Sopenharmony_ci	  set_WD_analog_gamma_B (buffer_r, foo);
629141cc406Sopenharmony_ci	  */
630141cc406Sopenharmony_ci	  set_WD_analog_gamma_R (buffer_r, s->analog_gamma_r);
631141cc406Sopenharmony_ci	  set_WD_analog_gamma_G (buffer_r, s->analog_gamma_g);
632141cc406Sopenharmony_ci	  set_WD_analog_gamma_B (buffer_r, s->analog_gamma_b);
633141cc406Sopenharmony_ci	  if (s->gamma_bind)
634141cc406Sopenharmony_ci	    {
635141cc406Sopenharmony_ci	      set_WD_LUT_R (buffer_r, 1);
636141cc406Sopenharmony_ci	      set_WD_LUT_G (buffer_r, 1);
637141cc406Sopenharmony_ci	      set_WD_LUT_B (buffer_r, 1);
638141cc406Sopenharmony_ci	    }
639141cc406Sopenharmony_ci	  else
640141cc406Sopenharmony_ci	    {
641141cc406Sopenharmony_ci	      set_WD_LUT_R (buffer_r, 1);
642141cc406Sopenharmony_ci	      set_WD_LUT_G (buffer_r, 2);
643141cc406Sopenharmony_ci	      set_WD_LUT_B (buffer_r, 3);
644141cc406Sopenharmony_ci	    }
645141cc406Sopenharmony_ci	}
646141cc406Sopenharmony_ci      set_WD_averaging (buffer_r, s->averaging);
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci      set_WD_brightness_R (buffer_r, s->brightness_R);
649141cc406Sopenharmony_ci      set_WD_brightness_G (buffer_r, s->brightness_G);
650141cc406Sopenharmony_ci      set_WD_brightness_B (buffer_r, s->brightness_B);
651141cc406Sopenharmony_ci
652141cc406Sopenharmony_ci      set_WD_contrast_R (buffer_r, s->contrast_R);
653141cc406Sopenharmony_ci      set_WD_contrast_G (buffer_r, s->contrast_G);
654141cc406Sopenharmony_ci      set_WD_contrast_B (buffer_r, s->contrast_B);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci      set_WD_exposure_R (buffer_r, s->exposure_R);
657141cc406Sopenharmony_ci      set_WD_exposure_G (buffer_r, s->exposure_G);
658141cc406Sopenharmony_ci      set_WD_exposure_B (buffer_r, s->exposure_B);
659141cc406Sopenharmony_ci      set_WD_shift_R (buffer_r, s->shift_R);
660141cc406Sopenharmony_ci      set_WD_shift_G (buffer_r, s->shift_G);
661141cc406Sopenharmony_ci      set_WD_shift_B (buffer_r, s->shift_B);
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci
664141cc406Sopenharmony_ci      /* FIXME: LUT-[RGB] */
665141cc406Sopenharmony_ci      /* FIXME: stop on/off */
666141cc406Sopenharmony_ci    }
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_ci  DBG (10, "\tx_nres=%d, y_nres=%d, upper left-x=%d, upper left-y=%d\n",
669141cc406Sopenharmony_ci       s->x_nres, s->y_nres, s->tlx, s->tly);
670141cc406Sopenharmony_ci  DBG (10, "\twindow width=%d, MUD=%d, brx=%d\n",
671141cc406Sopenharmony_ci       s->brx - s->tlx, s->MUD, s->brx);
672141cc406Sopenharmony_ci  DBG (10, "\tcolormode=%d, bits per pixel=%d\n",
673141cc406Sopenharmony_ci       s->colormode, s->bits_per_color);
674141cc406Sopenharmony_ci  DBG (10, "\tnegative=%d, dropoutcolor=%d, preview=%d, transfermode=%d, gammasel=%d\n",
675141cc406Sopenharmony_ci       s->negative, s->dropoutcolor, s->preview, s->transfermode,
676141cc406Sopenharmony_ci       s->gammaselection);
677141cc406Sopenharmony_ci
678141cc406Sopenharmony_ci  /* prepare SCSI-BUFFER */
679141cc406Sopenharmony_ci  memcpy (s->buffer, set_window.cmd, set_window.size);	/* SET-WINDOW cmd */
680141cc406Sopenharmony_ci  memcpy ((s->buffer + set_window.size),	/* add WPDB */
681141cc406Sopenharmony_ci	  window_parameter_data_block.cmd,
682141cc406Sopenharmony_ci	  window_parameter_data_block.size);
683141cc406Sopenharmony_ci  set_WPDB_wdblen ((s->buffer + set_window.size), used_WDB_size);	/* set WD_len */
684141cc406Sopenharmony_ci  memcpy (s->buffer + set_window.size + window_parameter_data_block.size,
685141cc406Sopenharmony_ci	  buffer_r, window_descriptor_block.size);
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci  hexdump (15, "Window set", buffer_r, s->wdb_len);
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  set_SW_xferlen (s->buffer, (window_parameter_data_block.size +
690141cc406Sopenharmony_ci			      window_descriptor_block.size));
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer, set_window.size +
693141cc406Sopenharmony_ci		     window_parameter_data_block.size +
694141cc406Sopenharmony_ci		     window_descriptor_block.size,
695141cc406Sopenharmony_ci		     NULL, 0);
696141cc406Sopenharmony_ci  DBG (10, "window set.\n");
697141cc406Sopenharmony_ci  return ret;
698141cc406Sopenharmony_ci}
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_cistatic int
701141cc406Sopenharmony_cicoolscan_set_window_param_LS30 (Coolscan_t * s, int wid, int prescan)
702141cc406Sopenharmony_ci{
703141cc406Sopenharmony_ci  unsigned char buffer_r[max_WDB_size];
704141cc406Sopenharmony_ci  int ret;
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci  wait_scanner (s);
707141cc406Sopenharmony_ci  memset (buffer_r, '\0', max_WDB_size);	/* clear buffer */
708141cc406Sopenharmony_ci  memcpy (buffer_r, window_descriptor_block_LS30.cmd,
709141cc406Sopenharmony_ci	  window_descriptor_block_LS30.size);	/* copy preset data */
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci  set_WD_wid (buffer_r, wid);          	/* window identifier */
712141cc406Sopenharmony_ci  set_WD_auto (buffer_r, s->set_auto);	/* 0 or 1: don't know what it is */
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci  /* geometry */
715141cc406Sopenharmony_ci  set_WD_Xres (buffer_r, resDivToVal (s->x_nres));	/* x resolution in dpi */
716141cc406Sopenharmony_ci  set_WD_Yres (buffer_r, resDivToVal (s->y_nres));	/* y resolution in dpi */
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci  if (prescan)
719141cc406Sopenharmony_ci    {
720141cc406Sopenharmony_ci      set_WD_scanmode_LS30 (buffer_r, WD_Prescan);
721141cc406Sopenharmony_ci      set_WD_Xres (buffer_r, resDivToVal (1));	/* x res. in dpi */
722141cc406Sopenharmony_ci      set_WD_Yres (buffer_r, resDivToVal (1));	/* y res. in dpi */
723141cc406Sopenharmony_ci      buffer_r[0x29]=0x81;
724141cc406Sopenharmony_ci      buffer_r[0x2a]=0x04;
725141cc406Sopenharmony_ci      buffer_r[0x2b]=0x02;
726141cc406Sopenharmony_ci      buffer_r[0x2c]=0x01;
727141cc406Sopenharmony_ci      buffer_r[0x2d]=0xff;
728141cc406Sopenharmony_ci      buffer_r[0x30]=0x00;
729141cc406Sopenharmony_ci      buffer_r[0x31]=0x00;
730141cc406Sopenharmony_ci      buffer_r[0x32]=0x00;
731141cc406Sopenharmony_ci      buffer_r[0x33]=0x00;
732141cc406Sopenharmony_ci      set_WD_width (buffer_r,(2592));
733141cc406Sopenharmony_ci      set_WD_length (buffer_r,(3894));
734141cc406Sopenharmony_ci    }
735141cc406Sopenharmony_ci  else
736141cc406Sopenharmony_ci    {
737141cc406Sopenharmony_ci      set_WD_scanmode_LS30 (buffer_r, WD_Scan);
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci      /* the coolscan LS-30 uses the upper left corner
740141cc406Sopenharmony_ci	 as the origin of coordinates */
741141cc406Sopenharmony_ci      /* xmax and ymax are given in 1200 dpi */
742141cc406Sopenharmony_ci      set_WD_ULX (buffer_r, s->tlx);
743141cc406Sopenharmony_ci      set_WD_ULY (buffer_r, s->tly);	/* upper_edge y */
744141cc406Sopenharmony_ci      set_WD_width (buffer_r, (s->brx - s->tlx+1));
745141cc406Sopenharmony_ci      set_WD_length (buffer_r, (s->bry - s->tly+1));
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci      /* BTC */
748141cc406Sopenharmony_ci      if (s->brightness == 128)
749141cc406Sopenharmony_ci	{
750141cc406Sopenharmony_ci	  buffer_r[0x32]=0x00;
751141cc406Sopenharmony_ci	}
752141cc406Sopenharmony_ci      else
753141cc406Sopenharmony_ci	{
754141cc406Sopenharmony_ci	  buffer_r[0x32]=s->brightness;	/* brightness */
755141cc406Sopenharmony_ci	}
756141cc406Sopenharmony_ci
757141cc406Sopenharmony_ci      if (s->contrast == 128)
758141cc406Sopenharmony_ci	{
759141cc406Sopenharmony_ci	  buffer_r[0x33]=0x00;
760141cc406Sopenharmony_ci	}
761141cc406Sopenharmony_ci      else
762141cc406Sopenharmony_ci	{
763141cc406Sopenharmony_ci	  buffer_r[0x33]=s->contrast;	/* contrast */
764141cc406Sopenharmony_ci	}
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci      /* scanmode */
767141cc406Sopenharmony_ci      if (s->colormode == GREYSCALE)
768141cc406Sopenharmony_ci	set_WD_composition (buffer_r, WD_comp_grey);	/* GRAY composition */
769141cc406Sopenharmony_ci      else
770141cc406Sopenharmony_ci	set_WD_composition (buffer_r, WD_comp_rgb_full);	/* RGB composition */
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci      set_WD_composition (buffer_r, WD_comp_rgb_full);  /* always RGB composition */
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci      /* Bits per pixel */
775141cc406Sopenharmony_ci      set_WD_bitsperpixel(buffer_r, s->bits_per_color);
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci      buffer_r[0x29]=0x81;
778141cc406Sopenharmony_ci      buffer_r[0x2a]=0x01;
779141cc406Sopenharmony_ci      buffer_r[0x2b]=0x02;
780141cc406Sopenharmony_ci      buffer_r[0x2c]=0x01;
781141cc406Sopenharmony_ci      buffer_r[0x2d]=0xff;
782141cc406Sopenharmony_ci      buffer_r[0x30]=0x00;
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_ci    }
785141cc406Sopenharmony_ci    set_WD_negative_LS30(buffer_r, s->negative);	/* Negative/positive slide */
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci    switch(wid)
788141cc406Sopenharmony_ci    { case 1:  set_gain_LS30(buffer_r,(s->exposure_R*s->pretv_r)/50);
789141cc406Sopenharmony_ci                 break;
790141cc406Sopenharmony_ci      case 2:  set_gain_LS30(buffer_r,(s->exposure_G*s->pretv_g)/50);
791141cc406Sopenharmony_ci                 break;
792141cc406Sopenharmony_ci      case 3:  set_gain_LS30(buffer_r,(s->exposure_B*s->pretv_b)/50);
793141cc406Sopenharmony_ci                 break;
794141cc406Sopenharmony_ci    }
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci  DBG (10, "\texpo_r=%d, expo_g=%d, expob=%d\n",
797141cc406Sopenharmony_ci       s->exposure_R, s->exposure_G, s->exposure_B);
798141cc406Sopenharmony_ci  DBG (10, "\tpre_r=%d, pre_g=%d, preb=%d\n",
799141cc406Sopenharmony_ci       s->pretv_r, s->pretv_g, s->pretv_b);
800141cc406Sopenharmony_ci  DBG (10, "\tx_nres=%d, y_nres=%d, upper left-x=%d, upper left-y=%d\n",
801141cc406Sopenharmony_ci       s->x_nres, s->y_nres, s->tlx, s->tly);
802141cc406Sopenharmony_ci  DBG (10, "\twindow width=%d, MUD=%d, brx=%d\n",
803141cc406Sopenharmony_ci       s->brx - s->tlx, s->MUD, s->brx);
804141cc406Sopenharmony_ci  DBG (10, "\tcolormode=%d, bits per pixel=%d\n",
805141cc406Sopenharmony_ci       s->colormode, s->bits_per_color);
806141cc406Sopenharmony_ci  DBG (10, "\tnegative=%d, dropoutcolor=%d, preview=%d, transfermode=%d, gammasel=%d\n",
807141cc406Sopenharmony_ci       s->negative, s->dropoutcolor, s->preview, s->transfermode,
808141cc406Sopenharmony_ci       s->gammaselection);
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  /* prepare SCSI-BUFFER */
811141cc406Sopenharmony_ci  memcpy (s->buffer, set_window.cmd, set_window.size);	/* SET-WINDOW cmd */
812141cc406Sopenharmony_ci  memcpy ((s->buffer + set_window.size),	/* add WPDB */
813141cc406Sopenharmony_ci	  window_parameter_data_block.cmd,
814141cc406Sopenharmony_ci	  window_parameter_data_block.size);
815141cc406Sopenharmony_ci  set_WPDB_wdblen ((s->buffer + set_window.size), used_WDB_size_LS30);	/* set WD_len */
816141cc406Sopenharmony_ci  memcpy (s->buffer + set_window.size + window_parameter_data_block.size,
817141cc406Sopenharmony_ci	  buffer_r, window_descriptor_block_LS30.size);
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci  hexdump (15, "Window set", buffer_r, s->wdb_len);
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci  set_SW_xferlen (s->buffer, (window_parameter_data_block.size +
822141cc406Sopenharmony_ci			      window_descriptor_block_LS30.size));
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, s->buffer, set_window.size +
825141cc406Sopenharmony_ci		     window_parameter_data_block.size +
826141cc406Sopenharmony_ci		     window_descriptor_block_LS30.size,
827141cc406Sopenharmony_ci		     NULL, 0);
828141cc406Sopenharmony_ci  DBG (10, "window set.\n");
829141cc406Sopenharmony_ci  return ret;
830141cc406Sopenharmony_ci}
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_cistatic int
833141cc406Sopenharmony_cicoolscan_set_window_param (Coolscan_t * s, int prescan)
834141cc406Sopenharmony_ci{
835141cc406Sopenharmony_ci  int ret;
836141cc406Sopenharmony_ci  ret=0;
837141cc406Sopenharmony_ci  DBG (10, "set_window_param\n");
838141cc406Sopenharmony_ci
839141cc406Sopenharmony_ci  if(s->LS<2)                   /* distinguish between old and new scanners */
840141cc406Sopenharmony_ci  { ret=coolscan_set_window_param_LS20 (s,prescan);
841141cc406Sopenharmony_ci  }
842141cc406Sopenharmony_ci  else
843141cc406Sopenharmony_ci  {  do_scsi_cmd (s->sfd,commande1.cmd,commande1.size,s->buffer,0x0d);
844141cc406Sopenharmony_ci     wait_scanner (s);
845141cc406Sopenharmony_ci     wait_scanner (s);
846141cc406Sopenharmony_ci     coolscan_set_window_param_LS30(s,1,prescan);
847141cc406Sopenharmony_ci     ret=coolscan_set_window_param_LS30(s,2,prescan);
848141cc406Sopenharmony_ci     ret=coolscan_set_window_param_LS30(s,3,prescan);
849141cc406Sopenharmony_ci     if(s->colormode&0x08)
850141cc406Sopenharmony_ci     { ret=coolscan_set_window_param_LS30(s,9,prescan);
851141cc406Sopenharmony_ci     }
852141cc406Sopenharmony_ci  }
853141cc406Sopenharmony_ci  return ret;
854141cc406Sopenharmony_ci}
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci/*
858141cc406Sopenharmony_ci * The only purpose of get_window is debugging. None of the return parameters
859141cc406Sopenharmony_ci * is currently used.
860141cc406Sopenharmony_ci */
861141cc406Sopenharmony_cistatic int
862141cc406Sopenharmony_cicoolscan_get_window_param_LS30 (Coolscan_t * s, int wid,int prescanok)
863141cc406Sopenharmony_ci{
864141cc406Sopenharmony_ci  int translen;
865141cc406Sopenharmony_ci  unsigned char *buf;
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_ci  DBG (10, "GET_WINDOW_PARAM\n");
868141cc406Sopenharmony_ci  /*  wait_scanner (s); */
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci  translen = window_parameter_data_block.size + window_descriptor_block_LS30.size;
871141cc406Sopenharmony_ci
872141cc406Sopenharmony_ci  /* prepare SCSI-BUFFER */
873141cc406Sopenharmony_ci  memset (s->buffer, '\0', max_WDB_size);	/* clear buffer */
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci  set_SW_xferlen (get_window.cmd, translen);	/* Transfer length */
876141cc406Sopenharmony_ci  get_window.cmd[5]= wid;                     	/* window identifier */
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci  hexdump (15, "Get window cmd", get_window.cmd, get_window.size);
879141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, get_window.cmd, get_window.size,
880141cc406Sopenharmony_ci		     s->buffer, translen);
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci  buf = s->buffer + window_parameter_data_block.size;
883141cc406Sopenharmony_ci  hexdump (10, "Window get", buf, 117);
884141cc406Sopenharmony_ci
885141cc406Sopenharmony_ci  s->brightness = buf[0x32];	/* brightness */
886141cc406Sopenharmony_ci  s->contrast = buf[0x33];	/* contrast */
887141cc406Sopenharmony_ci  DBG (10, "\tbrightness=%d, contrast=%d\n", s->brightness, s->contrast);
888141cc406Sopenharmony_ci
889141cc406Sopenharmony_ci  /* Useful? */
890141cc406Sopenharmony_ci  s->bits_per_color = get_WD_bitsperpixel (buf);	/* bits/pixel (8) */
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci  DBG (10, "\tcolormode=%d, bits per pixel=%d\n",
893141cc406Sopenharmony_ci       s->colormode, s->bits_per_color);
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci  if(prescanok)
896141cc406Sopenharmony_ci  { switch(wid)
897141cc406Sopenharmony_ci    { case 1: s->pretv_r = get_gain_LS30(buf);
898141cc406Sopenharmony_ci              break;
899141cc406Sopenharmony_ci      case 2: s->pretv_g = get_gain_LS30(buf);
900141cc406Sopenharmony_ci              break;
901141cc406Sopenharmony_ci      case 3: s->pretv_b = get_gain_LS30(buf);
902141cc406Sopenharmony_ci            break;
903141cc406Sopenharmony_ci    }
904141cc406Sopenharmony_ci  }
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci  /* Should this one be set at all, here? */
907141cc406Sopenharmony_ci  s->transfermode = get_WD_transfermode (buf);
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci  s->gammaselection = get_WD_gammaselection (buf);	/* monitor/linear */
910141cc406Sopenharmony_ci  DBG (10, "\tpre_r=%d, pre_g=%d, preb=%d\n",
911141cc406Sopenharmony_ci       s->pretv_r, s->pretv_g, s->pretv_b);
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  DBG (5, "\tnegative=%d, dropoutcolor=%d, preview=%d, transfermode=%d, gammasel=%d\n",
914141cc406Sopenharmony_ci       s->negative, s->dropoutcolor, s->preview, s->transfermode,
915141cc406Sopenharmony_ci       s->gammaselection);
916141cc406Sopenharmony_ci
917141cc406Sopenharmony_ci  DBG (10, "get_window_param - return\n");
918141cc406Sopenharmony_ci  return 0;
919141cc406Sopenharmony_ci}
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci/*
922141cc406Sopenharmony_ci * The only purpose of get_window is debugging. None of the return parameters
923141cc406Sopenharmony_ci * is currently used.
924141cc406Sopenharmony_ci */
925141cc406Sopenharmony_cistatic int
926141cc406Sopenharmony_cicoolscan_get_window_param_LS20 (Coolscan_t * s)
927141cc406Sopenharmony_ci{
928141cc406Sopenharmony_ci  int translen;
929141cc406Sopenharmony_ci  unsigned char *buf;
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci  DBG (10, "GET_WINDOW_PARAM\n");
932141cc406Sopenharmony_ci  wait_scanner (s);
933141cc406Sopenharmony_ci
934141cc406Sopenharmony_ci  translen = window_parameter_data_block.size + window_descriptor_block.size;
935141cc406Sopenharmony_ci
936141cc406Sopenharmony_ci  /* prepare SCSI-BUFFER */
937141cc406Sopenharmony_ci  memset (s->buffer, '\0', max_WDB_size);	/* clear buffer */
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  set_SW_xferlen (get_window.cmd, translen);	/* Transfer length */
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci  hexdump (15, "Get window cmd", get_window.cmd, get_window.size);
942141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, get_window.cmd, get_window.size,
943141cc406Sopenharmony_ci		     s->buffer, translen);
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci  buf = s->buffer + window_parameter_data_block.size;
946141cc406Sopenharmony_ci  hexdump (10, "Window get", buf, 117);
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci  /* BTC */
949141cc406Sopenharmony_ci  s->brightness = get_WD_brightness (buf);	/* brightness */
950141cc406Sopenharmony_ci  s->contrast = get_WD_contrast (buf);	/* contrast */
951141cc406Sopenharmony_ci  DBG (10, "\tbrightness=%d, contrast=%d\n", s->brightness, s->contrast);
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci  if (WD_comp_gray == get_WD_composition (buf))
954141cc406Sopenharmony_ci    s->colormode = GREYSCALE;
955141cc406Sopenharmony_ci  else
956141cc406Sopenharmony_ci    s->colormode = RGB;
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  /* Useful? */
959141cc406Sopenharmony_ci  s->bits_per_color = get_WD_bitsperpixel (buf);	/* bits/pixel (8) */
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci  DBG (10, "\tcolormode=%d, bits per pixel=%d\n",
962141cc406Sopenharmony_ci       s->colormode, s->bits_per_color);
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci  s->dropoutcolor = get_WD_dropoutcolor (buf);	/* Which color to scan with when grayscale scan */
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci  /* Should this one be set at all, here? */
968141cc406Sopenharmony_ci  s->transfermode = get_WD_transfermode (buf);
969141cc406Sopenharmony_ci
970141cc406Sopenharmony_ci  s->gammaselection = get_WD_gammaselection (buf);	/* monitor/linear */
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci  DBG (5, "\tnegative=%d, dropoutcolor=%d, preview=%d, transfermode=%d, gammasel=%d\n",
973141cc406Sopenharmony_ci       s->negative, s->dropoutcolor, s->preview, s->transfermode,
974141cc406Sopenharmony_ci       s->gammaselection);
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci  /* Should this one be set at all? */
977141cc406Sopenharmony_ci  s->shading = get_WD_shading (buf);
978141cc406Sopenharmony_ci  s->averaging = get_WD_averaging (buf);
979141cc406Sopenharmony_ci  DBG (10, "get_window_param - return\n");
980141cc406Sopenharmony_ci  return 0;
981141cc406Sopenharmony_ci}
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci/*
984141cc406Sopenharmony_ci * The only purpose of get_window is debugging. None of the return parameters
985141cc406Sopenharmony_ci * is currently used.
986141cc406Sopenharmony_ci */
987141cc406Sopenharmony_cistatic int
988141cc406Sopenharmony_cicoolscan_get_window_param (Coolscan_t * s, int prescanok)
989141cc406Sopenharmony_ci{
990141cc406Sopenharmony_ci  int ret;
991141cc406Sopenharmony_ci  DBG (10, "get_window_param\n");
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci  ret=0;
994141cc406Sopenharmony_ci  if(s->LS<2)                   /* distinguish between old and new scanners */
995141cc406Sopenharmony_ci  { ret=coolscan_get_window_param_LS20 (s);
996141cc406Sopenharmony_ci  }
997141cc406Sopenharmony_ci  else
998141cc406Sopenharmony_ci  {
999141cc406Sopenharmony_ci     ret=coolscan_get_window_param_LS30(s,1,prescanok);
1000141cc406Sopenharmony_ci     ret=coolscan_get_window_param_LS30(s,2,prescanok);
1001141cc406Sopenharmony_ci     ret=coolscan_get_window_param_LS30(s,3,prescanok);
1002141cc406Sopenharmony_ci     if(s->colormode&0x08)
1003141cc406Sopenharmony_ci     { ret=coolscan_get_window_param_LS30(s,9,prescanok);
1004141cc406Sopenharmony_ci     }
1005141cc406Sopenharmony_ci  }
1006141cc406Sopenharmony_ci  return ret;
1007141cc406Sopenharmony_ci}
1008141cc406Sopenharmony_ci
1009141cc406Sopenharmony_cistatic int
1010141cc406Sopenharmony_cicoolscan_start_scanLS30 (Coolscan_t * s)
1011141cc406Sopenharmony_ci{ int channels;
1012141cc406Sopenharmony_ci  DBG (10, "starting scan\n");
1013141cc406Sopenharmony_ci
1014141cc406Sopenharmony_ci  channels=1;
1015141cc406Sopenharmony_ci  memcpy (s->buffer, scan.cmd, scan.size);
1016141cc406Sopenharmony_ci  switch(s->colormode)
1017141cc406Sopenharmony_ci    {  case RGB:
1018141cc406Sopenharmony_ci       case GREYSCALE:
1019141cc406Sopenharmony_ci	       channels=s->buffer[4]=0x03; /* window 1 */
1020141cc406Sopenharmony_ci               s->buffer[6]=0x01; /* window 1 */
1021141cc406Sopenharmony_ci	       s->buffer[7]=0x02; /* window 2 */
1022141cc406Sopenharmony_ci	       s->buffer[8]=0x03; /* window 3 */
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci              break;
1025141cc406Sopenharmony_ci       case RGBI:
1026141cc406Sopenharmony_ci	       channels=s->buffer[4]=0x04; /* window 1 */
1027141cc406Sopenharmony_ci               s->buffer[6]=0x01; /* window 1 */
1028141cc406Sopenharmony_ci	       s->buffer[7]=0x02; /* window 2 */
1029141cc406Sopenharmony_ci	       s->buffer[8]=0x03; /* window 3 */
1030141cc406Sopenharmony_ci	       s->buffer[9]=0x09; /* window 3 */
1031141cc406Sopenharmony_ci              break;
1032141cc406Sopenharmony_ci       case IRED:
1033141cc406Sopenharmony_ci	       channels=s->buffer[4]=0x01; /* window 1 */
1034141cc406Sopenharmony_ci	       s->buffer[8]=0x09; /* window 3 */
1035141cc406Sopenharmony_ci              break;
1036141cc406Sopenharmony_ci    }
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci  return do_scsi_cmd (s->sfd, s->buffer, scan.size+channels, NULL, 0);
1039141cc406Sopenharmony_ci}
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_cistatic int
1042141cc406Sopenharmony_cicoolscan_start_scan (Coolscan_t * s)
1043141cc406Sopenharmony_ci{
1044141cc406Sopenharmony_ci  DBG (10, "starting scan\n");
1045141cc406Sopenharmony_ci  if(s->LS>=2)
1046141cc406Sopenharmony_ci    { return coolscan_start_scanLS30(s);
1047141cc406Sopenharmony_ci    }
1048141cc406Sopenharmony_ci  return do_scsi_cmd (s->sfd, scan.cmd, scan.size, NULL, 0);
1049141cc406Sopenharmony_ci}
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_cistatic int
1053141cc406Sopenharmony_ciprescan (Coolscan_t * s)
1054141cc406Sopenharmony_ci{
1055141cc406Sopenharmony_ci  int ret;
1056141cc406Sopenharmony_ci
1057141cc406Sopenharmony_ci  DBG (10, "Starting prescan...\n");
1058141cc406Sopenharmony_ci  if(s->LS<2)
1059141cc406Sopenharmony_ci  {  coolscan_set_window_param (s, 1);
1060141cc406Sopenharmony_ci  }
1061141cc406Sopenharmony_ci  else
1062141cc406Sopenharmony_ci  {
1063141cc406Sopenharmony_ci     do_scsi_cmd (s->sfd,commande1.cmd,commande1.size,s->buffer,0x0d);
1064141cc406Sopenharmony_ci     wait_scanner (s);
1065141cc406Sopenharmony_ci     wait_scanner (s);
1066141cc406Sopenharmony_ci     coolscan_set_window_param_LS30 (s,1,1);
1067141cc406Sopenharmony_ci     coolscan_set_window_param_LS30 (s,2,1);
1068141cc406Sopenharmony_ci     coolscan_set_window_param_LS30 (s,3,1);
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci  }
1071141cc406Sopenharmony_ci  ret = coolscan_start_scan(s);
1072141cc406Sopenharmony_ci
1073141cc406Sopenharmony_ci  sleep(8);			/* prescan takes a minimum of 10 sec. */
1074141cc406Sopenharmony_ci  wait_scanner (s);
1075141cc406Sopenharmony_ci  DBG (10, "Prescan done\n");
1076141cc406Sopenharmony_ci  return ret;
1077141cc406Sopenharmony_ci}
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_cistatic SANE_Status
1080141cc406Sopenharmony_cido_prescan_now (Coolscan_t * scanner)
1081141cc406Sopenharmony_ci{
1082141cc406Sopenharmony_ci
1083141cc406Sopenharmony_ci  DBG (10, "do_prescan_now \n");
1084141cc406Sopenharmony_ci  if (scanner->scanning == SANE_TRUE)
1085141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
1086141cc406Sopenharmony_ci
1087141cc406Sopenharmony_ci  if (scanner->sfd < 0)
1088141cc406Sopenharmony_ci    {				/* first call */
1089141cc406Sopenharmony_ci      if (sanei_scsi_open (scanner->sane.name,
1090141cc406Sopenharmony_ci			   &(scanner->sfd),
1091141cc406Sopenharmony_ci			   sense_handler, 0) != SANE_STATUS_GOOD)
1092141cc406Sopenharmony_ci	{
1093141cc406Sopenharmony_ci	  DBG (1, "do_prescan_now: open of %s failed:\n",
1094141cc406Sopenharmony_ci	       scanner->sane.name);
1095141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1096141cc406Sopenharmony_ci	}
1097141cc406Sopenharmony_ci    }
1098141cc406Sopenharmony_ci  scanner->scanning = SANE_TRUE;
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci
1101141cc406Sopenharmony_ci  if (coolscan_check_values (scanner) != 0)
1102141cc406Sopenharmony_ci    {				/* Verify values */
1103141cc406Sopenharmony_ci      DBG (1, "ERROR: invalid scan-values\n");
1104141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
1105141cc406Sopenharmony_ci      coolscan_give_scanner (scanner);
1106141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
1107141cc406Sopenharmony_ci      scanner->sfd = -1;
1108141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1109141cc406Sopenharmony_ci    }
1110141cc406Sopenharmony_ci
1111141cc406Sopenharmony_ci  if (coolscan_grab_scanner (scanner))
1112141cc406Sopenharmony_ci    {
1113141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
1114141cc406Sopenharmony_ci      scanner->sfd = -1;
1115141cc406Sopenharmony_ci      DBG (5, "WARNING: unable to reserve scanner: device busy\n");
1116141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
1117141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1118141cc406Sopenharmony_ci    }
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci  prescan (scanner);
1121141cc406Sopenharmony_ci  if(scanner->LS<2)
1122141cc406Sopenharmony_ci    {	get_internal_info(scanner);
1123141cc406Sopenharmony_ci    }
1124141cc406Sopenharmony_ci  coolscan_get_window_param (scanner,1);
1125141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
1126141cc406Sopenharmony_ci  coolscan_give_scanner (scanner);
1127141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1128141cc406Sopenharmony_ci}
1129141cc406Sopenharmony_ci
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_cistatic int
1132141cc406Sopenharmony_cisend_one_LUT (Coolscan_t * s, SANE_Word * LUT, int reg)
1133141cc406Sopenharmony_ci{
1134141cc406Sopenharmony_ci  int i;
1135141cc406Sopenharmony_ci  short lutval;
1136141cc406Sopenharmony_ci  short bytesperval;
1137141cc406Sopenharmony_ci  unsigned char *gamma, *gamma_p;
1138141cc406Sopenharmony_ci  unsigned short *gamma_s;
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci  DBG (10, "send LUT\n");
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci  if(s->LS<2)
1143141cc406Sopenharmony_ci  { set_S_datatype_code (send.cmd, R_user_reg_gamma);
1144141cc406Sopenharmony_ci    bytesperval=1;
1145141cc406Sopenharmony_ci  }
1146141cc406Sopenharmony_ci  else
1147141cc406Sopenharmony_ci  {
1148141cc406Sopenharmony_ci    send.cmd[0x02]=3;
1149141cc406Sopenharmony_ci    send.cmd[0x05]=1;
1150141cc406Sopenharmony_ci    bytesperval=2;
1151141cc406Sopenharmony_ci  }
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci  set_S_xfer_length (send.cmd, s->lutlength*bytesperval);
1154141cc406Sopenharmony_ci  set_S_datatype_qual_upper (send.cmd, reg);
1155141cc406Sopenharmony_ci
1156141cc406Sopenharmony_ci  gamma = alloca (send.size + s->lutlength*2);
1157141cc406Sopenharmony_ci  memcpy (gamma, send.cmd, send.size);
1158141cc406Sopenharmony_ci  if(s->LS<2)
1159141cc406Sopenharmony_ci  { gamma_p = &gamma[send.size];
1160141cc406Sopenharmony_ci    for (i = 0; i < s->lutlength; i++)
1161141cc406Sopenharmony_ci    {
1162141cc406Sopenharmony_ci      if (LUT[i] > 255)
1163141cc406Sopenharmony_ci	LUT[i] = 255;		/* broken gtk */
1164141cc406Sopenharmony_ci      *gamma_p++ = (unsigned char) LUT[i];
1165141cc406Sopenharmony_ci    }
1166141cc406Sopenharmony_ci  }
1167141cc406Sopenharmony_ci  else if(s->LS==2)
1168141cc406Sopenharmony_ci  { gamma_s = (unsigned short*)( &gamma[send.size]);
1169141cc406Sopenharmony_ci    for (i = 0; i < s->lutlength; i++)
1170141cc406Sopenharmony_ci    {
1171141cc406Sopenharmony_ci       if(s->negative)
1172141cc406Sopenharmony_ci       {
1173141cc406Sopenharmony_ci         lutval=(unsigned short)(LUT[(s->lutlength-i)]);
1174141cc406Sopenharmony_ci       }
1175141cc406Sopenharmony_ci       else
1176141cc406Sopenharmony_ci       {
1177141cc406Sopenharmony_ci	 lutval=(unsigned short)(LUT[i]);
1178141cc406Sopenharmony_ci       }
1179141cc406Sopenharmony_ci       if (LUT[i] >= s->max_lut_val)
1180141cc406Sopenharmony_ci       LUT[i] = s->max_lut_val-1;	          	/* broken gtk */
1181141cc406Sopenharmony_ci       if(s->low_byte_first)                                /* if on little endian machine: */
1182141cc406Sopenharmony_ci       {
1183141cc406Sopenharmony_ci         lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */
1184141cc406Sopenharmony_ci       }
1185141cc406Sopenharmony_ci       *gamma_s++ = lutval;
1186141cc406Sopenharmony_ci    }
1187141cc406Sopenharmony_ci  }
1188141cc406Sopenharmony_ci  else if(s->LS==3)
1189141cc406Sopenharmony_ci  { gamma_s = (unsigned short*)( &gamma[send.size]);
1190141cc406Sopenharmony_ci    for (i = 0; i < s->lutlength; i++)
1191141cc406Sopenharmony_ci    {
1192141cc406Sopenharmony_ci       if(s->negative)
1193141cc406Sopenharmony_ci       {
1194141cc406Sopenharmony_ci         lutval=(unsigned short)(LUT[s->lutlength-i]);
1195141cc406Sopenharmony_ci       }
1196141cc406Sopenharmony_ci       else
1197141cc406Sopenharmony_ci       {
1198141cc406Sopenharmony_ci	 lutval=(unsigned short)(LUT[i]);
1199141cc406Sopenharmony_ci       }
1200141cc406Sopenharmony_ci       if (LUT[i] >= s->max_lut_val)
1201141cc406Sopenharmony_ci       LUT[i] = s->max_lut_val-1;	          	    /* broken gtk */
1202141cc406Sopenharmony_ci       if(s->low_byte_first)                                /* if on little endian machine: */
1203141cc406Sopenharmony_ci       {  lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */
1204141cc406Sopenharmony_ci       }
1205141cc406Sopenharmony_ci       *gamma_s++ = lutval;
1206141cc406Sopenharmony_ci    }
1207141cc406Sopenharmony_ci  }
1208141cc406Sopenharmony_ci  return do_scsi_cmd (s->sfd, gamma, send.size + s->lutlength*bytesperval, NULL, 0);
1209141cc406Sopenharmony_ci}
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_cistatic int
1213141cc406Sopenharmony_cisend_LUT (Coolscan_t * s)
1214141cc406Sopenharmony_ci{
1215141cc406Sopenharmony_ci  wait_scanner (s);
1216141cc406Sopenharmony_ci  if (s->gamma_bind)
1217141cc406Sopenharmony_ci    {
1218141cc406Sopenharmony_ci      send_one_LUT (s, s->gamma, S_DQ_Reg1);
1219141cc406Sopenharmony_ci      if(s->LS>=2)
1220141cc406Sopenharmony_ci	{      send_one_LUT (s, s->gamma, S_DQ_Reg2);
1221141cc406Sopenharmony_ci	       send_one_LUT (s, s->gamma, S_DQ_Reg3);
1222141cc406Sopenharmony_ci               if(s->colormode&0x08)
1223141cc406Sopenharmony_ci	       { send_one_LUT (s, s->gamma, S_DQ_Reg9);
1224141cc406Sopenharmony_ci	       }
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci	}
1227141cc406Sopenharmony_ci    }
1228141cc406Sopenharmony_ci  else
1229141cc406Sopenharmony_ci    {
1230141cc406Sopenharmony_ci      send_one_LUT (s, s->gamma_r, S_DQ_Reg1);
1231141cc406Sopenharmony_ci      send_one_LUT (s, s->gamma_g, S_DQ_Reg2);
1232141cc406Sopenharmony_ci      send_one_LUT (s, s->gamma_b, S_DQ_Reg3);
1233141cc406Sopenharmony_ci      if(s->colormode&0x08)
1234141cc406Sopenharmony_ci      { send_one_LUT (s, s->gamma_r, S_DQ_Reg9);
1235141cc406Sopenharmony_ci      }
1236141cc406Sopenharmony_ci    }
1237141cc406Sopenharmony_ci  return 0;
1238141cc406Sopenharmony_ci}
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_cistatic int
1242141cc406Sopenharmony_cicoolscan_read_data_block (Coolscan_t * s, unsigned int datatype, unsigned int length)
1243141cc406Sopenharmony_ci{
1244141cc406Sopenharmony_ci  int r;
1245141cc406Sopenharmony_ci
1246141cc406Sopenharmony_ci  DBG (10, "read_data_block (type= %x length = %d)\n",datatype,length);
1247141cc406Sopenharmony_ci  /*wait_scanner(s); */
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci  set_R_datatype_code (sread.cmd, datatype);
1250141cc406Sopenharmony_ci  sread.cmd[4]=00;
1251141cc406Sopenharmony_ci  sread.cmd[5]=00;
1252141cc406Sopenharmony_ci  set_R_xfer_length (sread.cmd, length);
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  r = do_scsi_cmd (s->sfd, sread.cmd, sread.size, s->buffer, length);
1255141cc406Sopenharmony_ci  return ((r != 0) ? -1 : (int) length);
1256141cc406Sopenharmony_ci}
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_cistatic void
1260141cc406Sopenharmony_cicoolscan_do_inquiry (Coolscan_t * s)
1261141cc406Sopenharmony_ci{
1262141cc406Sopenharmony_ci  int size;
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci  DBG (10, "do_inquiry\n");
1265141cc406Sopenharmony_ci  memset (s->buffer, '\0', 256);	/* clear buffer */
1266141cc406Sopenharmony_ci  size = 36;			/* Hardcoded, and as specified by Nikon */
1267141cc406Sopenharmony_ci  /* then get inquiry with actual size */
1268141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);
1269141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, s->buffer, size);
1270141cc406Sopenharmony_ci}
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_cistatic int
1273141cc406Sopenharmony_cicoolscan_identify_scanner (Coolscan_t * s)
1274141cc406Sopenharmony_ci{
1275141cc406Sopenharmony_ci  unsigned char vendor[9];
1276141cc406Sopenharmony_ci  unsigned char product[0x11];
1277141cc406Sopenharmony_ci  unsigned char version[5];
1278141cc406Sopenharmony_ci  unsigned char *pp;
1279141cc406Sopenharmony_ci  int i;
1280141cc406Sopenharmony_ci
1281141cc406Sopenharmony_ci  vendor[8] = product[0x10] = version[4] = 0;
1282141cc406Sopenharmony_ci  DBG (10, "identify_scanner\n");
1283141cc406Sopenharmony_ci  coolscan_do_inquiry (s);	/* get inquiry */
1284141cc406Sopenharmony_ci  if (get_inquiry_periph_devtype (s->buffer) != IN_periph_devtype_scanner)
1285141cc406Sopenharmony_ci    {
1286141cc406Sopenharmony_ci      DBG (5, "identify_scanner: not a scanner\n");
1287141cc406Sopenharmony_ci      return 1;
1288141cc406Sopenharmony_ci    }				/* no, continue searching */
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  coolscan_get_inquiry_values (s);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  get_inquiry_vendor ((char *)s->buffer, (char *)vendor);
1293141cc406Sopenharmony_ci  get_inquiry_product ((char *)s->buffer, (char *)product);
1294141cc406Sopenharmony_ci  get_inquiry_version ((char *)s->buffer, (char *)version);
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci  if (strncmp ("Nikon   ", (char *)vendor, 8))
1297141cc406Sopenharmony_ci    {
1298141cc406Sopenharmony_ci      DBG (5, "identify_scanner: \"%s\" isn't a Nikon product\n", vendor);
1299141cc406Sopenharmony_ci      return 1;
1300141cc406Sopenharmony_ci    }				/* Not a Nikon product */
1301141cc406Sopenharmony_ci
1302141cc406Sopenharmony_ci  pp = &vendor[8];
1303141cc406Sopenharmony_ci  vendor[8] = ' ';
1304141cc406Sopenharmony_ci  while (*pp == ' ')
1305141cc406Sopenharmony_ci    {
1306141cc406Sopenharmony_ci      *pp-- = '\0';
1307141cc406Sopenharmony_ci    }
1308141cc406Sopenharmony_ci
1309141cc406Sopenharmony_ci  pp = &product[0x10];
1310141cc406Sopenharmony_ci  product[0x10] = ' ';
1311141cc406Sopenharmony_ci  while (*(pp - 1) == ' ')
1312141cc406Sopenharmony_ci    {
1313141cc406Sopenharmony_ci      *pp-- = '\0';
1314141cc406Sopenharmony_ci    }				/* leave one blank at the end! */
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci  pp = &version[4];
1317141cc406Sopenharmony_ci  version[4] = ' ';
1318141cc406Sopenharmony_ci  while (*pp == ' ')
1319141cc406Sopenharmony_ci    {
1320141cc406Sopenharmony_ci      *pp-- = '\0';
1321141cc406Sopenharmony_ci    }
1322141cc406Sopenharmony_ci
1323141cc406Sopenharmony_ci  DBG (10, "Found Nikon scanner %sversion %s on device %s\n",
1324141cc406Sopenharmony_ci       product, version, s->devicename);
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  /* look for scanners that do not give all inquiry-informations */
1327141cc406Sopenharmony_ci  /* and if possible use driver-known inquiry-data  */
1328141cc406Sopenharmony_ci  if (get_inquiry_additional_length (s->buffer) >= 0x1f)
1329141cc406Sopenharmony_ci    {
1330141cc406Sopenharmony_ci      /* Now identify full supported scanners */
1331141cc406Sopenharmony_ci      for (i = 0; i < known_scanners; i++)
1332141cc406Sopenharmony_ci	{
1333141cc406Sopenharmony_ci	  if (!strncmp ((char *)product, scanner_str[i], strlen (scanner_str[i])))
1334141cc406Sopenharmony_ci	    {
1335141cc406Sopenharmony_ci	      s->LS = i;
1336141cc406Sopenharmony_ci	      return 0;
1337141cc406Sopenharmony_ci	    }
1338141cc406Sopenharmony_ci	}
1339141cc406Sopenharmony_ci      if (s->cont)
1340141cc406Sopenharmony_ci	return 0;
1341141cc406Sopenharmony_ci      else
1342141cc406Sopenharmony_ci	return 1;
1343141cc406Sopenharmony_ci    }
1344141cc406Sopenharmony_ci  else
1345141cc406Sopenharmony_ci    return 1;
1346141cc406Sopenharmony_ci}
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_cistatic int
1349141cc406Sopenharmony_cipixels_per_line (Coolscan_t * s)
1350141cc406Sopenharmony_ci{
1351141cc406Sopenharmony_ci  int pic_dot;
1352141cc406Sopenharmony_ci  if(s->LS<2)
1353141cc406Sopenharmony_ci  {  pic_dot = (s->brx - s->tlx + s->x_nres) / s->x_nres;
1354141cc406Sopenharmony_ci  }
1355141cc406Sopenharmony_ci  else
1356141cc406Sopenharmony_ci  { pic_dot = (s->brx - s->tlx + 1) / s->x_nres;
1357141cc406Sopenharmony_ci  }
1358141cc406Sopenharmony_ci  DBG (10, "pic_dot=%d\n", pic_dot);
1359141cc406Sopenharmony_ci  return pic_dot;
1360141cc406Sopenharmony_ci}
1361141cc406Sopenharmony_ci
1362141cc406Sopenharmony_cistatic int
1363141cc406Sopenharmony_cilines_per_scan (Coolscan_t * s)
1364141cc406Sopenharmony_ci{
1365141cc406Sopenharmony_ci  int pic_line;
1366141cc406Sopenharmony_ci  if(s->LS<2)
1367141cc406Sopenharmony_ci  { pic_line = (s->bry - s->tly + s->y_nres) / s->y_nres;
1368141cc406Sopenharmony_ci  }
1369141cc406Sopenharmony_ci  else
1370141cc406Sopenharmony_ci  { pic_line = (( s->bry - s->tly + 1.0 )  / s->y_nres);
1371141cc406Sopenharmony_ci  }
1372141cc406Sopenharmony_ci  DBG (10, "pic_line=%d\n", pic_line);
1373141cc406Sopenharmony_ci  return pic_line;
1374141cc406Sopenharmony_ci}
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_cistatic int
1377141cc406Sopenharmony_ciscan_bytes_per_line (Coolscan_t * s)
1378141cc406Sopenharmony_ci{ int bpl;
1379141cc406Sopenharmony_ci  switch(s->colormode)
1380141cc406Sopenharmony_ci    {  case RGB:
1381141cc406Sopenharmony_ci       case GREYSCALE:
1382141cc406Sopenharmony_ci              bpl=pixels_per_line (s) * 3;
1383141cc406Sopenharmony_ci              if(s->bits_per_color>8) bpl=bpl*2;
1384141cc406Sopenharmony_ci              return bpl;
1385141cc406Sopenharmony_ci              break;
1386141cc406Sopenharmony_ci       case RGBI:
1387141cc406Sopenharmony_ci       case IRED:
1388141cc406Sopenharmony_ci              bpl=pixels_per_line (s) * 4;
1389141cc406Sopenharmony_ci              if(s->bits_per_color>8) bpl=bpl*2;
1390141cc406Sopenharmony_ci              return bpl;
1391141cc406Sopenharmony_ci              break;
1392141cc406Sopenharmony_ci    }
1393141cc406Sopenharmony_ci    return 0;
1394141cc406Sopenharmony_ci}
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_cistatic int
1397141cc406Sopenharmony_ciwrite_bytes_per_line (Coolscan_t * s)
1398141cc406Sopenharmony_ci{ int bpl;
1399141cc406Sopenharmony_ci  switch(s->colormode)
1400141cc406Sopenharmony_ci    {  case RGB:
1401141cc406Sopenharmony_ci              bpl=pixels_per_line (s) * 3;
1402141cc406Sopenharmony_ci              if(s->bits_per_color>8) bpl=bpl*2;
1403141cc406Sopenharmony_ci              return bpl;
1404141cc406Sopenharmony_ci              break;
1405141cc406Sopenharmony_ci       case RGBI:
1406141cc406Sopenharmony_ci              bpl=pixels_per_line (s) * 4;
1407141cc406Sopenharmony_ci              if(s->bits_per_color>8) bpl=bpl*2;
1408141cc406Sopenharmony_ci              return bpl;
1409141cc406Sopenharmony_ci              break;
1410141cc406Sopenharmony_ci       case IRED:
1411141cc406Sopenharmony_ci       case GREYSCALE:
1412141cc406Sopenharmony_ci              bpl= pixels_per_line (s) ;
1413141cc406Sopenharmony_ci              if(s->bits_per_color>8) bpl=bpl*2;
1414141cc406Sopenharmony_ci              return bpl;
1415141cc406Sopenharmony_ci              break;
1416141cc406Sopenharmony_ci    }
1417141cc406Sopenharmony_ci    return 0;
1418141cc406Sopenharmony_ci}
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ci
1421141cc406Sopenharmony_cistatic void
1422141cc406Sopenharmony_cicoolscan_trim_rowbufsize (Coolscan_t * s)
1423141cc406Sopenharmony_ci{
1424141cc406Sopenharmony_ci  unsigned int row_len;
1425141cc406Sopenharmony_ci  row_len = scan_bytes_per_line (s);
1426141cc406Sopenharmony_ci  s->row_bufsize = (s->row_bufsize < row_len) ? s->row_bufsize
1427141cc406Sopenharmony_ci    : s->row_bufsize - (s->row_bufsize % row_len);
1428141cc406Sopenharmony_ci  DBG (10, "trim_bufsize to %d\n", s->row_bufsize);
1429141cc406Sopenharmony_ci}
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_cistatic int
1432141cc406Sopenharmony_cicoolscan_check_values (Coolscan_t * s)
1433141cc406Sopenharmony_ci{
1434141cc406Sopenharmony_ci  DBG (10, "check_values\n");
1435141cc406Sopenharmony_ci  /* -------------------------- asf --------------------------------- */
1436141cc406Sopenharmony_ci  if (s->asf != 0)
1437141cc406Sopenharmony_ci    {
1438141cc406Sopenharmony_ci      if (s->autofeeder == 0)
1439141cc406Sopenharmony_ci	{
1440141cc406Sopenharmony_ci	  DBG (1, "ERROR: ASF-MODE NOT SUPPORTED BY SCANNER, ABORTING\n");
1441141cc406Sopenharmony_ci	  return (1);
1442141cc406Sopenharmony_ci	}
1443141cc406Sopenharmony_ci    }
1444141cc406Sopenharmony_ci
1445141cc406Sopenharmony_ci  return (0);
1446141cc406Sopenharmony_ci}
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci/* test_little_endian */
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_cistatic SANE_Bool
1451141cc406Sopenharmony_cicoolscan_test_little_endian(void)
1452141cc406Sopenharmony_ci{
1453141cc406Sopenharmony_ci  SANE_Int testvalue = 255;
1454141cc406Sopenharmony_ci  unsigned char *firstbyte = (unsigned char *) &testvalue;
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci  if (*firstbyte == 255)
1457141cc406Sopenharmony_ci  { return SANE_TRUE;
1458141cc406Sopenharmony_ci  }
1459141cc406Sopenharmony_ci  return SANE_FALSE;
1460141cc406Sopenharmony_ci}
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_cistatic int
1463141cc406Sopenharmony_ciget_inquiery_part_LS30 (Coolscan_t * s, unsigned char part)
1464141cc406Sopenharmony_ci{
1465141cc406Sopenharmony_ci  int size;
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci  /* Get length of response */
1468141cc406Sopenharmony_ci  inquiry.cmd[1]=0x01;
1469141cc406Sopenharmony_ci  inquiry.cmd[2]=part;
1470141cc406Sopenharmony_ci  size=4;
1471141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);
1472141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size,
1473141cc406Sopenharmony_ci               s->buffer, size);
1474141cc406Sopenharmony_ci  size=get_inquiry_length(s->buffer);
1475141cc406Sopenharmony_ci  size+=4;
1476141cc406Sopenharmony_ci  /* then get inquiry with actual size */
1477141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);
1478141cc406Sopenharmony_ci  do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size,
1479141cc406Sopenharmony_ci               s->buffer, size);
1480141cc406Sopenharmony_ci  return size;
1481141cc406Sopenharmony_ci}
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_cistatic int
1484141cc406Sopenharmony_cicoolscan_read_var_data_block (Coolscan_t * s,int datatype)
1485141cc406Sopenharmony_ci{
1486141cc406Sopenharmony_ci  int r;
1487141cc406Sopenharmony_ci  int size;
1488141cc406Sopenharmony_ci
1489141cc406Sopenharmony_ci  DBG (10, "read_data_block (type= %x)\n",datatype);
1490141cc406Sopenharmony_ci  /*wait_scanner(s); */
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_ci  sread.cmd[2]=datatype;
1493141cc406Sopenharmony_ci  sread.cmd[4]=00;
1494141cc406Sopenharmony_ci  sread.cmd[5]=03;
1495141cc406Sopenharmony_ci  size=6;
1496141cc406Sopenharmony_ci  set_R_xfer_length (sread.cmd, size);
1497141cc406Sopenharmony_ci  r = do_scsi_cmd (s->sfd, sread.cmd, sread.size,
1498141cc406Sopenharmony_ci		     s->buffer, size);
1499141cc406Sopenharmony_ci  size=s->buffer[5];
1500141cc406Sopenharmony_ci  set_R_xfer_length (sread.cmd, size);
1501141cc406Sopenharmony_ci  r = do_scsi_cmd (s->sfd, sread.cmd, sread.size,
1502141cc406Sopenharmony_ci		     s->buffer, size);
1503141cc406Sopenharmony_ci  return ((r != 0) ? -1 : size);
1504141cc406Sopenharmony_ci}
1505141cc406Sopenharmony_ci
1506141cc406Sopenharmony_cistatic int
1507141cc406Sopenharmony_ciget_inquiery_LS30 (Coolscan_t * s)
1508141cc406Sopenharmony_ci{
1509141cc406Sopenharmony_ci  unsigned char part;
1510141cc406Sopenharmony_ci  unsigned char parts[5];
1511141cc406Sopenharmony_ci  int i;
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci  /* Get vector of inquiery parts */
1514141cc406Sopenharmony_ci  get_inquiery_part_LS30(s, (unsigned char) 0);
1515141cc406Sopenharmony_ci  /* Get the parts of inquiery */
1516141cc406Sopenharmony_ci  for(i=0;i<5;i++)
1517141cc406Sopenharmony_ci  { parts[i]=((unsigned char *)s->buffer)[4+11+i];
1518141cc406Sopenharmony_ci  }
1519141cc406Sopenharmony_ci  for(i=0;i<5;i++)
1520141cc406Sopenharmony_ci  { part=parts[i];
1521141cc406Sopenharmony_ci    get_inquiery_part_LS30 (s, part);
1522141cc406Sopenharmony_ci    switch(part)
1523141cc406Sopenharmony_ci    {  case 0x0c1:/* max size and resolution */
1524141cc406Sopenharmony_ci                    s->adbits = 8;
1525141cc406Sopenharmony_ci                    s->outputbits = 8;
1526141cc406Sopenharmony_ci		    s->maxres = getnbyte(s->buffer+0x12,2)-1;
1527141cc406Sopenharmony_ci		    s->xmaxpix = getnbyte(s->buffer+0x53,2)-1;
1528141cc406Sopenharmony_ci		    s->ymaxpix = getnbyte(s->buffer+0x3c,2)-1;
1529141cc406Sopenharmony_ci                  break;
1530141cc406Sopenharmony_ci       case 0x0d1:
1531141cc406Sopenharmony_ci                  break;
1532141cc406Sopenharmony_ci       case 0x0e1:
1533141cc406Sopenharmony_ci                  break;
1534141cc406Sopenharmony_ci       case 0x0f0:
1535141cc406Sopenharmony_ci                  break;
1536141cc406Sopenharmony_ci       case 0x0f8:
1537141cc406Sopenharmony_ci                  break;
1538141cc406Sopenharmony_ci    }
1539141cc406Sopenharmony_ci  }
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci  /* get windows */
1542141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,0,0);
1543141cc406Sopenharmony_ci   s->xmax = get_WD_width(s->buffer);
1544141cc406Sopenharmony_ci   s->ymax = get_WD_length(s->buffer);
1545141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,1,0);
1546141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,2,0);
1547141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,3,0);
1548141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,4,0);
1549141cc406Sopenharmony_ci  coolscan_get_window_param_LS30 (s,9,0);
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci  s->analoggamma = 0;
1552141cc406Sopenharmony_ci  return 1;
1553141cc406Sopenharmony_ci}
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_cistatic int
1556141cc406Sopenharmony_ciget_feeder_type_LS30 (Coolscan_t * s)
1557141cc406Sopenharmony_ci{
1558141cc406Sopenharmony_ci  int size;
1559141cc406Sopenharmony_ci  unsigned char *ptr;
1560141cc406Sopenharmony_ci  int ima;
1561141cc406Sopenharmony_ci
1562141cc406Sopenharmony_ci  /* find out about Film-strip-feeder or Mount-Feeder */
1563141cc406Sopenharmony_ci  size=get_inquiery_part_LS30(s, (unsigned char) 1);
1564141cc406Sopenharmony_ci  if(strncmp((char *)s->buffer+5,"Strip",5)==0)
1565141cc406Sopenharmony_ci  { s->feeder=STRIP_FEEDER;
1566141cc406Sopenharmony_ci    s->autofeeder = 1;
1567141cc406Sopenharmony_ci  }
1568141cc406Sopenharmony_ci  if(strncmp((char *)s->buffer+5,"Mount",5)==0)
1569141cc406Sopenharmony_ci  { s->feeder=MOUNT_FEEDER;
1570141cc406Sopenharmony_ci  }
1571141cc406Sopenharmony_ci  /* find out about Film-strip-feeder positions*/
1572141cc406Sopenharmony_ci  if(s->feeder==STRIP_FEEDER)
1573141cc406Sopenharmony_ci  { size=coolscan_read_var_data_block (s,(int)0x88);
1574141cc406Sopenharmony_ci    if(size>=4)
1575141cc406Sopenharmony_ci    { s->numima=s->buffer[3];
1576141cc406Sopenharmony_ci      if(s->numima>6) s->numima=6; /* limit to 6 images for now */
1577141cc406Sopenharmony_ci      if(s->numima>(size-4)/16) s->numima=(size-4)/16;
1578141cc406Sopenharmony_ci      ptr=s->buffer+4;
1579141cc406Sopenharmony_ci      for(ima=0;ima<s->numima;ima++)
1580141cc406Sopenharmony_ci      {  s->ipos[ima].start=getnbyte(ptr,4);
1581141cc406Sopenharmony_ci         s->ipos[ima].offset=getnbyte(ptr+4,4);
1582141cc406Sopenharmony_ci         s->ipos[ima].end=getnbyte(ptr+8,4);
1583141cc406Sopenharmony_ci         s->ipos[ima].height=getnbyte(ptr+12,4);
1584141cc406Sopenharmony_ci	 ptr+=16;
1585141cc406Sopenharmony_ci      }
1586141cc406Sopenharmony_ci    }
1587141cc406Sopenharmony_ci    s->posima=0;
1588141cc406Sopenharmony_ci  }
1589141cc406Sopenharmony_ci  return 1;
1590141cc406Sopenharmony_ci}
1591141cc406Sopenharmony_ci
1592141cc406Sopenharmony_ci
1593141cc406Sopenharmony_cistatic int
1594141cc406Sopenharmony_ciget_internal_info_LS20 (Coolscan_t * s)
1595141cc406Sopenharmony_ci{
1596141cc406Sopenharmony_ci  int ret;
1597141cc406Sopenharmony_ci
1598141cc406Sopenharmony_ci  DBG (10, "get_internal_info\n");
1599141cc406Sopenharmony_ci  wait_scanner (s);
1600141cc406Sopenharmony_ci  memset (s->buffer, '\0', DI_length);	/* clear buffer */
1601141cc406Sopenharmony_ci
1602141cc406Sopenharmony_ci  set_R_datatype_code (sread.cmd, R_device_internal_info);
1603141cc406Sopenharmony_ci  set_R_datatype_qual_upper (sread.cmd, R_DQ_none);
1604141cc406Sopenharmony_ci  set_R_xfer_length (sread.cmd, DI_length);
1605141cc406Sopenharmony_ci  /* then get inquiry with actual size */
1606141cc406Sopenharmony_ci  ret = do_scsi_cmd (s->sfd, sread.cmd, sread.size,
1607141cc406Sopenharmony_ci		     s->buffer, DI_length);
1608141cc406Sopenharmony_ci
1609141cc406Sopenharmony_ci  s->adbits = get_DI_ADbits (s->buffer);
1610141cc406Sopenharmony_ci  s->outputbits = get_DI_Outputbits (s->buffer);
1611141cc406Sopenharmony_ci  s->maxres = get_DI_MaxResolution (s->buffer);
1612141cc406Sopenharmony_ci  s->xmax = get_DI_Xmax (s->buffer);
1613141cc406Sopenharmony_ci  s->ymax = get_DI_Ymax (s->buffer);
1614141cc406Sopenharmony_ci  s->xmaxpix = get_DI_Xmaxpixel (s->buffer);
1615141cc406Sopenharmony_ci  s->ymaxpix = get_DI_Ymaxpixel (s->buffer);
1616141cc406Sopenharmony_ci  s->ycurrent = get_DI_currentY (s->buffer);
1617141cc406Sopenharmony_ci  s->currentfocus = get_DI_currentFocus (s->buffer);
1618141cc406Sopenharmony_ci  s->currentscanpitch = get_DI_currentscanpitch (s->buffer);
1619141cc406Sopenharmony_ci  s->autofeeder = get_DI_autofeeder (s->buffer);
1620141cc406Sopenharmony_ci  s->analoggamma = get_DI_analoggamma (s->buffer);
1621141cc406Sopenharmony_ci  s->derr[0] = get_DI_deviceerror0 (s->buffer);
1622141cc406Sopenharmony_ci  s->derr[1] = get_DI_deviceerror1 (s->buffer);
1623141cc406Sopenharmony_ci  s->derr[2] = get_DI_deviceerror2 (s->buffer);
1624141cc406Sopenharmony_ci  s->derr[3] = get_DI_deviceerror3 (s->buffer);
1625141cc406Sopenharmony_ci  s->derr[4] = get_DI_deviceerror4 (s->buffer);
1626141cc406Sopenharmony_ci  s->derr[5] = get_DI_deviceerror5 (s->buffer);
1627141cc406Sopenharmony_ci  s->derr[6] = get_DI_deviceerror6 (s->buffer);
1628141cc406Sopenharmony_ci  s->derr[7] = get_DI_deviceerror7 (s->buffer);
1629141cc406Sopenharmony_ci  s->wbetr_r = get_DI_WBETR_R (s->buffer);
1630141cc406Sopenharmony_ci  s->webtr_g = get_DI_WBETR_G (s->buffer);
1631141cc406Sopenharmony_ci  s->webtr_b = get_DI_WBETR_B (s->buffer);
1632141cc406Sopenharmony_ci  s->pretv_r = get_DI_PRETV_R (s->buffer);
1633141cc406Sopenharmony_ci  s->pretv_g = get_DI_PRETV_G (s->buffer);
1634141cc406Sopenharmony_ci  s->pretv_r = get_DI_PRETV_R (s->buffer);
1635141cc406Sopenharmony_ci  s->cetv_r = get_DI_CETV_R (s->buffer);
1636141cc406Sopenharmony_ci  s->cetv_g = get_DI_CETV_G (s->buffer);
1637141cc406Sopenharmony_ci  s->cetv_b = get_DI_CETV_B (s->buffer);
1638141cc406Sopenharmony_ci  s->ietu_r = get_DI_IETU_R (s->buffer);
1639141cc406Sopenharmony_ci  s->ietu_g = get_DI_IETU_G (s->buffer);
1640141cc406Sopenharmony_ci  s->ietu_b = get_DI_IETU_B (s->buffer);
1641141cc406Sopenharmony_ci  s->limitcondition = get_DI_limitcondition (s->buffer);
1642141cc406Sopenharmony_ci  s->offsetdata_r = get_DI_offsetdata_R (s->buffer);
1643141cc406Sopenharmony_ci  s->offsetdata_g = get_DI_offsetdata_G (s->buffer);
1644141cc406Sopenharmony_ci  s->offsetdata_b = get_DI_offsetdata_B (s->buffer);
1645141cc406Sopenharmony_ci  get_DI_poweron_errors (s->buffer, s->power_on_errors);
1646141cc406Sopenharmony_ci
1647141cc406Sopenharmony_ci  DBG (10,
1648141cc406Sopenharmony_ci       "\tadbits=%d\toutputbits=%d\tmaxres=%d\txmax=%d\tymax=%d\n"
1649141cc406Sopenharmony_ci       "\txmaxpix=%d\tymaxpix=%d\tycurrent=%d\tcurrentfocus=%d\n"
1650141cc406Sopenharmony_ci       "\tautofeeder=%s\tanaloggamma=%s\tcurrentscanpitch=%d\n",
1651141cc406Sopenharmony_ci       s->adbits, s->outputbits, s->maxres, s->xmax, s->ymax,
1652141cc406Sopenharmony_ci       s->xmaxpix, s->ymaxpix, s->ycurrent, s->currentfocus,
1653141cc406Sopenharmony_ci       s->autofeeder ? "Yes" : "No", s->analoggamma ? "Yes" : "No",
1654141cc406Sopenharmony_ci       s->currentscanpitch);
1655141cc406Sopenharmony_ci  DBG (10,
1656141cc406Sopenharmony_ci       "\tWhite balance exposure time var [RGB]=\t%d %d %d\n"
1657141cc406Sopenharmony_ci       "\tPrescan result exposure time var [RGB]=\t%d %d %d\n"
1658141cc406Sopenharmony_ci       "\tCurrent exposure time var.[RGB]=\t%d %d %d\n"
1659141cc406Sopenharmony_ci       "\tInternal exposure time unit[RGB]=\t%d %d %d\n",
1660141cc406Sopenharmony_ci       s->wbetr_r, s->webtr_g, s->webtr_b, s->pretv_r, s->pretv_g,
1661141cc406Sopenharmony_ci       s->pretv_r, s->cetv_r, s->cetv_g, s->cetv_b, s->ietu_r,
1662141cc406Sopenharmony_ci       s->ietu_g, s->ietu_b);
1663141cc406Sopenharmony_ci  DBG (10,
1664141cc406Sopenharmony_ci       "\toffsetdata_[rgb]=\t0x%x 0x%x 0x%x\n"
1665141cc406Sopenharmony_ci       "\tlimitcondition=0x%x\n"
1666141cc406Sopenharmony_ci       "\tdevice error code = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n"
1667141cc406Sopenharmony_ci       "\tpower-on errors = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1668141cc406Sopenharmony_ci       s->offsetdata_r, s->offsetdata_g, s->offsetdata_b,
1669141cc406Sopenharmony_ci       s->limitcondition,
1670141cc406Sopenharmony_ci       s->derr[0], s->derr[1], s->derr[2], s->derr[3], s->derr[4],
1671141cc406Sopenharmony_ci       s->derr[5], s->derr[6], s->derr[7],
1672141cc406Sopenharmony_ci       s->power_on_errors[0], s->power_on_errors[1],
1673141cc406Sopenharmony_ci       s->power_on_errors[2], s->power_on_errors[3],
1674141cc406Sopenharmony_ci       s->power_on_errors[4], s->power_on_errors[5],
1675141cc406Sopenharmony_ci       s->power_on_errors[6], s->power_on_errors[7]);
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci  return ret;
1678141cc406Sopenharmony_ci}
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_cistatic int
1681141cc406Sopenharmony_ciget_internal_info (Coolscan_t * s)
1682141cc406Sopenharmony_ci{
1683141cc406Sopenharmony_ci  int ret;
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_ci  DBG (10, "get_internal_info\n");
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci  if(s->LS<2)                   /* distinguish between old and new scanners */
1688141cc406Sopenharmony_ci  { ret=get_internal_info_LS20 (s);
1689141cc406Sopenharmony_ci  }
1690141cc406Sopenharmony_ci  else
1691141cc406Sopenharmony_ci  { ret=get_inquiery_LS30 (s);
1692141cc406Sopenharmony_ci  }
1693141cc406Sopenharmony_ci  return ret;
1694141cc406Sopenharmony_ci}
1695141cc406Sopenharmony_ci
1696141cc406Sopenharmony_cistatic void
1697141cc406Sopenharmony_cicoolscan_get_inquiry_values (Coolscan_t * s)
1698141cc406Sopenharmony_ci{
1699141cc406Sopenharmony_ci  unsigned char *inquiry_block;
1700141cc406Sopenharmony_ci
1701141cc406Sopenharmony_ci  DBG (10, "get_inquiry_values\n");
1702141cc406Sopenharmony_ci
1703141cc406Sopenharmony_ci  inquiry_block = (unsigned char *) s->buffer;
1704141cc406Sopenharmony_ci  s->inquiry_len = 36;
1705141cc406Sopenharmony_ci
1706141cc406Sopenharmony_ci  get_inquiry_vendor ((char *)inquiry_block, (char *)s->vendor);
1707141cc406Sopenharmony_ci  s->vendor[8] = '\0';
1708141cc406Sopenharmony_ci  get_inquiry_product ((char *)inquiry_block, (char *)s->product);
1709141cc406Sopenharmony_ci  s->product[16] = '\0';
1710141cc406Sopenharmony_ci  get_inquiry_version ((char *)inquiry_block, (char *)s->version);
1711141cc406Sopenharmony_ci  s->version[4] = '\0';
1712141cc406Sopenharmony_ci
1713141cc406Sopenharmony_ci  if (s->inquiry_len < 36)
1714141cc406Sopenharmony_ci    {
1715141cc406Sopenharmony_ci      DBG (1, "WARNING: inquiry return block is unexpected short (%d instead of 36).\n", s->inquiry_len);
1716141cc406Sopenharmony_ci    }
1717141cc406Sopenharmony_ci  s->inquiry_wdb_len = 117;
1718141cc406Sopenharmony_ci  return;
1719141cc406Sopenharmony_ci}
1720141cc406Sopenharmony_ci
1721141cc406Sopenharmony_cistatic void
1722141cc406Sopenharmony_cicoolscan_initialize_values (Coolscan_t * s)
1723141cc406Sopenharmony_ci{
1724141cc406Sopenharmony_ci  int i;
1725141cc406Sopenharmony_ci  DBG (10, "initialize_values\n");
1726141cc406Sopenharmony_ci  /* Initialize us structure */
1727141cc406Sopenharmony_ci  if(s->LS<2)                   /* LS-20 or LS-10000 */
1728141cc406Sopenharmony_ci  {  select_MUD (s);		/* must be before mode_sense - not for LS-30*/
1729141cc406Sopenharmony_ci     coolscan_mode_sense (s);	/* Obtain MUD (Measurement Unit Divisor) */
1730141cc406Sopenharmony_ci     get_internal_info (s);	/* MUST be called first. */
1731141cc406Sopenharmony_ci     s->wdb_len = 117;
1732141cc406Sopenharmony_ci  }
1733141cc406Sopenharmony_ci  if(s->LS>=2)                  /* LS-30 */
1734141cc406Sopenharmony_ci  {
1735141cc406Sopenharmony_ci    get_inquiery_LS30(s);	/* Info about scanner*/
1736141cc406Sopenharmony_ci    select_MUD (s);		/* must be before mode_sense */
1737141cc406Sopenharmony_ci    get_feeder_type_LS30(s);
1738141cc406Sopenharmony_ci    s->wdb_len = 117;
1739141cc406Sopenharmony_ci  }
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci  s->cont = 0;			/* do not continue if scanner is unknown */
1742141cc406Sopenharmony_ci  s->verbose = 2;		/* 1=verbose,2=very verbose */
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci  s->x_nres = s->y_nres = 2;	/* 2 => 1350 dpi */
1746141cc406Sopenharmony_ci  s->x_p_nres = s->y_p_nres = 9;	/* 9 => 300 dpi */
1747141cc406Sopenharmony_ci  s->tlx = 0;
1748141cc406Sopenharmony_ci  s->tly = 0;
1749141cc406Sopenharmony_ci  s->brx = s->xmaxpix;		/* 2700 / 1200; */
1750141cc406Sopenharmony_ci  s->bry = s->ymaxpix;		/* 2700 / 1200; */
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_ci  s->set_auto = 0;		/* Always 0 on Nikon LS-{100|2}0 */
1754141cc406Sopenharmony_ci  s->preview = 0;		/* 1 for preview */
1755141cc406Sopenharmony_ci  s->colormode = RGB;		/* GREYSCALE or RGB */
1756141cc406Sopenharmony_ci  s->colormode_p = RGB;		/* GREYSCALE or RGB for preview*/
1757141cc406Sopenharmony_ci  s->asf = 0;			/* 1 if asf shall be used */
1758141cc406Sopenharmony_ci  s->gammaselection = WD_Linear;
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci  s->brightness = 128;
1761141cc406Sopenharmony_ci  s->brightness_R = 128;
1762141cc406Sopenharmony_ci  s->brightness_G = 128;
1763141cc406Sopenharmony_ci  s->brightness_B = 128;
1764141cc406Sopenharmony_ci  s->contrast = 128;
1765141cc406Sopenharmony_ci  s->contrast_R = 128;
1766141cc406Sopenharmony_ci  s->contrast_G = 128;
1767141cc406Sopenharmony_ci  s->contrast_B = 128;
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci  s->exposure_R = 50;
1770141cc406Sopenharmony_ci  s->exposure_G = 50;
1771141cc406Sopenharmony_ci  s->exposure_B = 50;
1772141cc406Sopenharmony_ci
1773141cc406Sopenharmony_ci  s->pretv_r=40000;
1774141cc406Sopenharmony_ci  s->pretv_g=40000;
1775141cc406Sopenharmony_ci  s->pretv_b=40000;
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci  s->shift_R = 128;
1778141cc406Sopenharmony_ci  s->shift_G = 128;
1779141cc406Sopenharmony_ci  s->shift_B = 128;
1780141cc406Sopenharmony_ci
1781141cc406Sopenharmony_ci  s->ired_red=60;
1782141cc406Sopenharmony_ci  s->ired_green=1;
1783141cc406Sopenharmony_ci  s->ired_blue=1;
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  s->prescan = 1;
1786141cc406Sopenharmony_ci  s->bits_per_color = 8;
1787141cc406Sopenharmony_ci  s->rgb_control = 0;
1788141cc406Sopenharmony_ci  s->gamma_bind = 1;
1789141cc406Sopenharmony_ci  switch(s->LS)
1790141cc406Sopenharmony_ci  {  case 0:s->lutlength=2048;
1791141cc406Sopenharmony_ci            s->max_lut_val=256;
1792141cc406Sopenharmony_ci            break;
1793141cc406Sopenharmony_ci     case 1:s->lutlength=512;
1794141cc406Sopenharmony_ci            s->max_lut_val=512;
1795141cc406Sopenharmony_ci            break;
1796141cc406Sopenharmony_ci     case 2:s->lutlength=1024;
1797141cc406Sopenharmony_ci            s->max_lut_val=1024;
1798141cc406Sopenharmony_ci            break;
1799141cc406Sopenharmony_ci     case 3:s->lutlength=4096;
1800141cc406Sopenharmony_ci            s->max_lut_val=4096;
1801141cc406Sopenharmony_ci            break;
1802141cc406Sopenharmony_ci  }
1803141cc406Sopenharmony_ci  for (i = 0; i < s->lutlength; i++)
1804141cc406Sopenharmony_ci  {
1805141cc406Sopenharmony_ci     s->gamma[i] =((short)((((double)i)/s->lutlength)*s->max_lut_val));
1806141cc406Sopenharmony_ci     s->gamma_r[i] = s->gamma[i];
1807141cc406Sopenharmony_ci     s->gamma_g[i] = s->gamma[i];
1808141cc406Sopenharmony_ci     s->gamma_b[i] = s->gamma[i];
1809141cc406Sopenharmony_ci  }
1810141cc406Sopenharmony_ci
1811141cc406Sopenharmony_ci  if (coolscan_test_little_endian() == SANE_TRUE)
1812141cc406Sopenharmony_ci  {
1813141cc406Sopenharmony_ci    s->low_byte_first = 1;					        /* in 2 byte mode send lowbyte first */
1814141cc406Sopenharmony_ci    DBG(10,"backend runs on little endian machine\n");
1815141cc406Sopenharmony_ci  }
1816141cc406Sopenharmony_ci  else
1817141cc406Sopenharmony_ci  {
1818141cc406Sopenharmony_ci    s->low_byte_first = 0;					       /* in 2 byte mode send highbyte first */
1819141cc406Sopenharmony_ci    DBG(10,"backend runs on big endian machine\n");
1820141cc406Sopenharmony_ci  }
1821141cc406Sopenharmony_ci}
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_cistatic void
1824141cc406Sopenharmony_cihexdump (int level, char *comment, unsigned char *p, int l)
1825141cc406Sopenharmony_ci{
1826141cc406Sopenharmony_ci  int i;
1827141cc406Sopenharmony_ci  char line[128];
1828141cc406Sopenharmony_ci  char *ptr;
1829141cc406Sopenharmony_ci
1830141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
1831141cc406Sopenharmony_ci  ptr = line;
1832141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++)
1833141cc406Sopenharmony_ci    {
1834141cc406Sopenharmony_ci      if ((i % 16) == 0)
1835141cc406Sopenharmony_ci	{
1836141cc406Sopenharmony_ci	  if (ptr != line)
1837141cc406Sopenharmony_ci	    {
1838141cc406Sopenharmony_ci	      *ptr = '\0';
1839141cc406Sopenharmony_ci	      DBG (level, "%s\n", line);
1840141cc406Sopenharmony_ci	      ptr = line;
1841141cc406Sopenharmony_ci	    }
1842141cc406Sopenharmony_ci	  sprintf (ptr, "%3.3d:", i);
1843141cc406Sopenharmony_ci	  ptr += 4;
1844141cc406Sopenharmony_ci	}
1845141cc406Sopenharmony_ci      sprintf (ptr, " %2.2x", *p);
1846141cc406Sopenharmony_ci      ptr += 3;
1847141cc406Sopenharmony_ci    }
1848141cc406Sopenharmony_ci  *ptr = '\0';
1849141cc406Sopenharmony_ci  DBG (level, "%s\n", line);
1850141cc406Sopenharmony_ci}
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci
1853141cc406Sopenharmony_cistatic SANE_Status
1854141cc406Sopenharmony_cisense_handler (int scsi_fd, unsigned char * result, void *arg)
1855141cc406Sopenharmony_ci{
1856141cc406Sopenharmony_ci  (void) scsi_fd;
1857141cc406Sopenharmony_ci  (void) arg;
1858141cc406Sopenharmony_ci
1859141cc406Sopenharmony_ci  if (result[0] != 0x70)
1860141cc406Sopenharmony_ci    {
1861141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;	/* we only know about this one  */
1862141cc406Sopenharmony_ci    }
1863141cc406Sopenharmony_ci  return request_sense_parse(result);
1864141cc406Sopenharmony_ci
1865141cc406Sopenharmony_ci}
1866141cc406Sopenharmony_ci
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci
1871141cc406Sopenharmony_ci/* ilu per mm */
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci#define length_quant SANE_UNFIX(SANE_FIX(MM_PER_INCH / 2700.0))
1874141cc406Sopenharmony_ci#define mmToIlu(mm) ((mm) / length_quant)
1875141cc406Sopenharmony_ci#define iluToMm(ilu) ((ilu) * length_quant)
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci#define P_200_TO_255(per) SANE_UNFIX((per + 100) * 255/200 )
1878141cc406Sopenharmony_ci#define P_100_TO_255(per) SANE_UNFIX(per * 255/100 )
1879141cc406Sopenharmony_ci
1880141cc406Sopenharmony_cistatic const char negativeStr[] = "Negative";
1881141cc406Sopenharmony_cistatic const char positiveStr[] = "Positive";
1882141cc406Sopenharmony_cistatic SANE_String_Const type_list[] =
1883141cc406Sopenharmony_ci{
1884141cc406Sopenharmony_ci  positiveStr,
1885141cc406Sopenharmony_ci  negativeStr,
1886141cc406Sopenharmony_ci  0
1887141cc406Sopenharmony_ci};
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_cistatic const char colorStr[] = SANE_VALUE_SCAN_MODE_COLOR;
1890141cc406Sopenharmony_cistatic const char grayStr[] = SANE_VALUE_SCAN_MODE_GRAY;
1891141cc406Sopenharmony_cistatic const char rgbiStr[] = "RGBI";
1892141cc406Sopenharmony_cistatic const char iredStr[] = "Infrared";
1893141cc406Sopenharmony_ci
1894141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list_LS20[] =
1895141cc406Sopenharmony_ci{
1896141cc406Sopenharmony_ci  colorStr,
1897141cc406Sopenharmony_ci  grayStr,
1898141cc406Sopenharmony_ci  NULL
1899141cc406Sopenharmony_ci};
1900141cc406Sopenharmony_ci
1901141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list_LS30[] =
1902141cc406Sopenharmony_ci{
1903141cc406Sopenharmony_ci  colorStr,
1904141cc406Sopenharmony_ci  grayStr,
1905141cc406Sopenharmony_ci#ifdef HAS_IRED
1906141cc406Sopenharmony_ci  rgbiStr,
1907141cc406Sopenharmony_ci#endif /* HAS_IRED */
1908141cc406Sopenharmony_ci  NULL
1909141cc406Sopenharmony_ci};
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_cistatic SANE_Int bit_depth_list[9];
1912141cc406Sopenharmony_ci
1913141cc406Sopenharmony_cistatic const char neverStr[] = "never";
1914141cc406Sopenharmony_cistatic const char previewStr[] = "before preview";
1915141cc406Sopenharmony_cistatic const char scanStr[] = "before scan";
1916141cc406Sopenharmony_cistatic const char preandscanStr[] = "before preview and scan";
1917141cc406Sopenharmony_cistatic SANE_String_Const autofocus_mode_list[] =
1918141cc406Sopenharmony_ci{
1919141cc406Sopenharmony_ci  neverStr,
1920141cc406Sopenharmony_ci  previewStr,
1921141cc406Sopenharmony_ci  scanStr,
1922141cc406Sopenharmony_ci  preandscanStr,
1923141cc406Sopenharmony_ci  NULL
1924141cc406Sopenharmony_ci};
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_cistatic SANE_String_Const source_list[4] =
1927141cc406Sopenharmony_ci{NULL, NULL, NULL, NULL};
1928141cc406Sopenharmony_ci
1929141cc406Sopenharmony_cistatic const SANE_Range gamma_range_8 =
1930141cc406Sopenharmony_ci{
1931141cc406Sopenharmony_ci  0,				/* minimum */
1932141cc406Sopenharmony_ci  255,				/* maximum */
1933141cc406Sopenharmony_ci  1				/* quantization */
1934141cc406Sopenharmony_ci};
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci
1937141cc406Sopenharmony_cistatic const SANE_Range gamma_range_9 =
1938141cc406Sopenharmony_ci{
1939141cc406Sopenharmony_ci  0,				/* minimum */
1940141cc406Sopenharmony_ci  511,				/* maximum */
1941141cc406Sopenharmony_ci  1				/* quantization */
1942141cc406Sopenharmony_ci};
1943141cc406Sopenharmony_ci
1944141cc406Sopenharmony_cistatic const SANE_Range gamma_range_10 =
1945141cc406Sopenharmony_ci{
1946141cc406Sopenharmony_ci  0,				/* minimum */
1947141cc406Sopenharmony_ci  1023,				/* maximum */
1948141cc406Sopenharmony_ci  1				/* quantization */
1949141cc406Sopenharmony_ci};
1950141cc406Sopenharmony_ci
1951141cc406Sopenharmony_cistatic const SANE_Range gamma_range_12 =
1952141cc406Sopenharmony_ci{
1953141cc406Sopenharmony_ci  0,				/* minimum */
1954141cc406Sopenharmony_ci  4096,				/* maximum */
1955141cc406Sopenharmony_ci  1				/* quantization */
1956141cc406Sopenharmony_ci};
1957141cc406Sopenharmony_ci
1958141cc406Sopenharmony_cistatic const SANE_Range brightness_range =
1959141cc406Sopenharmony_ci{
1960141cc406Sopenharmony_ci  -5,
1961141cc406Sopenharmony_ci  +5,
1962141cc406Sopenharmony_ci  1
1963141cc406Sopenharmony_ci};
1964141cc406Sopenharmony_ci
1965141cc406Sopenharmony_cistatic const SANE_Range contrast_range =
1966141cc406Sopenharmony_ci{
1967141cc406Sopenharmony_ci  -5,
1968141cc406Sopenharmony_ci  +5,
1969141cc406Sopenharmony_ci  0
1970141cc406Sopenharmony_ci};
1971141cc406Sopenharmony_ci
1972141cc406Sopenharmony_cistatic const SANE_Range exposure_range =
1973141cc406Sopenharmony_ci{
1974141cc406Sopenharmony_ci  24,
1975141cc406Sopenharmony_ci  400,
1976141cc406Sopenharmony_ci  2
1977141cc406Sopenharmony_ci};
1978141cc406Sopenharmony_ci
1979141cc406Sopenharmony_cistatic const SANE_Range shift_range =
1980141cc406Sopenharmony_ci{
1981141cc406Sopenharmony_ci  -15,
1982141cc406Sopenharmony_ci  +15,
1983141cc406Sopenharmony_ci  0
1984141cc406Sopenharmony_ci};
1985141cc406Sopenharmony_ci
1986141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
1987141cc406Sopenharmony_cistatic int num_devices;
1988141cc406Sopenharmony_cistatic Coolscan_t *first_dev;
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_cistatic size_t
1992141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
1993141cc406Sopenharmony_ci{
1994141cc406Sopenharmony_ci  size_t size, max_size = 0;
1995141cc406Sopenharmony_ci  int i;
1996141cc406Sopenharmony_ci
1997141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
1998141cc406Sopenharmony_ci    {
1999141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
2000141cc406Sopenharmony_ci      if (size > max_size)
2001141cc406Sopenharmony_ci	max_size = size;
2002141cc406Sopenharmony_ci    }
2003141cc406Sopenharmony_ci  return max_size;
2004141cc406Sopenharmony_ci}
2005141cc406Sopenharmony_ci
2006141cc406Sopenharmony_cistatic SANE_Status
2007141cc406Sopenharmony_cido_eof (Coolscan_t * scanner)
2008141cc406Sopenharmony_ci{
2009141cc406Sopenharmony_ci  DBG (10, "do_eof\n");
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  if (scanner->pipe >= 0)
2012141cc406Sopenharmony_ci    {
2013141cc406Sopenharmony_ci      close (scanner->pipe);
2014141cc406Sopenharmony_ci      scanner->pipe = -1;
2015141cc406Sopenharmony_ci    }
2016141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
2017141cc406Sopenharmony_ci}
2018141cc406Sopenharmony_ci
2019141cc406Sopenharmony_cistatic SANE_Status
2020141cc406Sopenharmony_cido_cancel (Coolscan_t * scanner)
2021141cc406Sopenharmony_ci{
2022141cc406Sopenharmony_ci  DBG (10, "do_cancel\n");
2023141cc406Sopenharmony_ci  swap_res (scanner);
2024141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci  do_eof (scanner);		/* close pipe and reposition scanner */
2027141cc406Sopenharmony_ci
2028141cc406Sopenharmony_ci  if (sanei_thread_is_valid (scanner->reader_pid))
2029141cc406Sopenharmony_ci    {
2030141cc406Sopenharmony_ci      int exit_status;
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci      DBG (10, "do_cancel: kill reader_process\n");
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci      /* ensure child knows it's time to stop: */
2035141cc406Sopenharmony_ci      sanei_thread_kill (scanner->reader_pid);
2036141cc406Sopenharmony_ci      while (sanei_thread_waitpid(scanner->reader_pid, &exit_status) !=
2037141cc406Sopenharmony_ci                                                        scanner->reader_pid );
2038141cc406Sopenharmony_ci      sanei_thread_invalidate (scanner->reader_pid);
2039141cc406Sopenharmony_ci    }
2040141cc406Sopenharmony_ci
2041141cc406Sopenharmony_ci  if (scanner->sfd >= 0)
2042141cc406Sopenharmony_ci    {
2043141cc406Sopenharmony_ci      coolscan_give_scanner (scanner);
2044141cc406Sopenharmony_ci      DBG (10, "do_cancel: close filedescriptor\n");
2045141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
2046141cc406Sopenharmony_ci      scanner->sfd = -1;
2047141cc406Sopenharmony_ci    }
2048141cc406Sopenharmony_ci
2049141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
2050141cc406Sopenharmony_ci}
2051141cc406Sopenharmony_ci
2052141cc406Sopenharmony_cistatic SANE_Status
2053141cc406Sopenharmony_ciattach_scanner (const char *devicename, Coolscan_t ** devp)
2054141cc406Sopenharmony_ci{
2055141cc406Sopenharmony_ci  Coolscan_t *dev;
2056141cc406Sopenharmony_ci  int sfd;
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci  DBG (10, "attach_scanner: %s\n", devicename);
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
2061141cc406Sopenharmony_ci    {
2062141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
2063141cc406Sopenharmony_ci	{
2064141cc406Sopenharmony_ci	  if (devp)
2065141cc406Sopenharmony_ci	    {
2066141cc406Sopenharmony_ci	      *devp = dev;
2067141cc406Sopenharmony_ci	    }
2068141cc406Sopenharmony_ci	  DBG (5, "attach_scanner: scanner already attached (is ok)!\n");
2069141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2070141cc406Sopenharmony_ci	}
2071141cc406Sopenharmony_ci    }
2072141cc406Sopenharmony_ci
2073141cc406Sopenharmony_ci  DBG (10, "attach_scanner: opening %s\n", devicename);
2074141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, sense_handler, 0) != 0)
2075141cc406Sopenharmony_ci    {
2076141cc406Sopenharmony_ci      DBG (1, "attach_scanner: open failed\n");
2077141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2078141cc406Sopenharmony_ci    }
2079141cc406Sopenharmony_ci
2080141cc406Sopenharmony_ci  if (NULL == (dev = malloc (sizeof (*dev))))
2081141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2082141cc406Sopenharmony_ci
2083141cc406Sopenharmony_ci
2084141cc406Sopenharmony_ci  dev->row_bufsize = (sanei_scsi_max_request_size < (64 * 1024)) ?
2085141cc406Sopenharmony_ci  	sanei_scsi_max_request_size : 64 * 1024;
2086141cc406Sopenharmony_ci
2087141cc406Sopenharmony_ci  if ((dev->buffer = malloc (dev->row_bufsize)) == NULL)
2088141cc406Sopenharmony_ci/*  if ((dev->buffer = malloc (sanei_scsi_max_request_size)) == NULL)*/
2089141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_ci  if ((dev->obuffer = malloc (dev->row_bufsize)) == NULL)
2092141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2093141cc406Sopenharmony_ci
2094141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
2095141cc406Sopenharmony_ci  dev->sfd = sfd;
2096141cc406Sopenharmony_ci
2097141cc406Sopenharmony_ci  /* Nikon manual: Step 1 */
2098141cc406Sopenharmony_ci  if (coolscan_identify_scanner (dev) != 0)
2099141cc406Sopenharmony_ci    {
2100141cc406Sopenharmony_ci      DBG (1, "attach_scanner: scanner-identification failed\n");
2101141cc406Sopenharmony_ci      sanei_scsi_close (dev->sfd);
2102141cc406Sopenharmony_ci      free (dev->buffer);
2103141cc406Sopenharmony_ci      free (dev);
2104141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2105141cc406Sopenharmony_ci    }
2106141cc406Sopenharmony_ci
2107141cc406Sopenharmony_ci  /* Get MUD (via mode_sense), internal info (via get_internal_info), and
2108141cc406Sopenharmony_ci   * initialize values */
2109141cc406Sopenharmony_ci  coolscan_initialize_values (dev);
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci  /* Why? */
2112141cc406Sopenharmony_ci  sanei_scsi_close (dev->sfd);
2113141cc406Sopenharmony_ci  dev->sfd = -1;
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
2116141cc406Sopenharmony_ci  dev->sane.vendor = dev->vendor;
2117141cc406Sopenharmony_ci  dev->sane.model = dev->product;
2118141cc406Sopenharmony_ci  dev->sane.type = "slide scanner";
2119141cc406Sopenharmony_ci
2120141cc406Sopenharmony_ci  dev->x_range.min = SANE_FIX (0);
2121141cc406Sopenharmony_ci  dev->x_range.quant = SANE_FIX (length_quant);
2122141cc406Sopenharmony_ci  dev->x_range.max = SANE_FIX ((double) ((dev->xmaxpix) * length_quant));
2123141cc406Sopenharmony_ci
2124141cc406Sopenharmony_ci  dev->y_range.min = SANE_FIX (0.0);
2125141cc406Sopenharmony_ci  dev->y_range.quant = SANE_FIX (length_quant);
2126141cc406Sopenharmony_ci  dev->y_range.max = SANE_FIX ((double) ((dev->ymaxpix) * length_quant));
2127141cc406Sopenharmony_ci
2128141cc406Sopenharmony_ci  /* ...and this?? */
2129141cc406Sopenharmony_ci  dev->dpi_range.min = SANE_FIX (108);
2130141cc406Sopenharmony_ci  dev->dpi_range.quant = SANE_FIX (0);
2131141cc406Sopenharmony_ci  dev->dpi_range.max = SANE_FIX (dev->maxres);
2132141cc406Sopenharmony_ci  DBG (10, "attach: dev->dpi_range.max = %f\n",
2133141cc406Sopenharmony_ci       SANE_UNFIX (dev->dpi_range.max));
2134141cc406Sopenharmony_ci
2135141cc406Sopenharmony_ci  ++num_devices;
2136141cc406Sopenharmony_ci  dev->next = first_dev;
2137141cc406Sopenharmony_ci  first_dev = dev;
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_ci  if (devp)
2140141cc406Sopenharmony_ci    {
2141141cc406Sopenharmony_ci      *devp = dev;
2142141cc406Sopenharmony_ci    }
2143141cc406Sopenharmony_ci
2144141cc406Sopenharmony_ci  DBG (10, "attach_scanner done\n");
2145141cc406Sopenharmony_ci
2146141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2147141cc406Sopenharmony_ci}
2148141cc406Sopenharmony_ci
2149141cc406Sopenharmony_cistatic SANE_Status
2150141cc406Sopenharmony_ciattach_one (const char *devName)
2151141cc406Sopenharmony_ci{
2152141cc406Sopenharmony_ci  return attach_scanner(devName, 0);
2153141cc406Sopenharmony_ci}
2154141cc406Sopenharmony_ci
2155141cc406Sopenharmony_cistatic void
2156141cc406Sopenharmony_cisigterm_handler (int signal)
2157141cc406Sopenharmony_ci{
2158141cc406Sopenharmony_ci  (void) signal;
2159141cc406Sopenharmony_ci  sanei_scsi_req_flush_all ();	/* flush SCSI queue */
2160141cc406Sopenharmony_ci  _exit (SANE_STATUS_GOOD);
2161141cc406Sopenharmony_ci}
2162141cc406Sopenharmony_ci
2163141cc406Sopenharmony_ci
2164141cc406Sopenharmony_citypedef struct Color_correct_s
2165141cc406Sopenharmony_ci{ int sum;           /* number of pixels summed so far */
2166141cc406Sopenharmony_ci  double sumr;          /* sum of red pixel values*/
2167141cc406Sopenharmony_ci  double sumi;          /* sum of infrared pixel values*/
2168141cc406Sopenharmony_ci  double sumri;         /* sum of red*ired pixel values*/
2169141cc406Sopenharmony_ci  double sumii;         /* sum of ired*ired pixel values*/
2170141cc406Sopenharmony_ci  double sumrr;         /* sum of ired*ired pixel values*/
2171141cc406Sopenharmony_ci  int  mr;         /* factor between red and ired values (*256) */
2172141cc406Sopenharmony_ci  int  br;         /* offset of ired values */
2173141cc406Sopenharmony_ci} ColorCorrect;
2174141cc406Sopenharmony_ci
2175141cc406Sopenharmony_ci/* ---------------------------------------------------------------
2176141cc406Sopenharmony_ci
2177141cc406Sopenharmony_ci  function:   RGBIfix
2178141cc406Sopenharmony_ci
2179141cc406Sopenharmony_ci  task:       Correct the infrared channel
2180141cc406Sopenharmony_ci
2181141cc406Sopenharmony_ci  import:     unsigned char * rgbimat - RGBI - matrix from scanner
2182141cc406Sopenharmony_ci              int size - number of pixels to correct
2183141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2184141cc406Sopenharmony_ci	      int *lutg - lookup table for red correction
2185141cc406Sopenharmony_ci	      int *lutb - lookup table for red correction
2186141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2187141cc406Sopenharmony_ci
2188141cc406Sopenharmony_ci  export:     unsigned char * orgbimat - RGBI - corrected matrix
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_ci  written by: Andreas RICK   19.6.1999
2191141cc406Sopenharmony_ci
2192141cc406Sopenharmony_ci  ----------------------------------------------------------------*/
2193141cc406Sopenharmony_ci
2194141cc406Sopenharmony_cistatic int Calc_fix_LUT(Coolscan_t * s)
2195141cc406Sopenharmony_ci{ int uselutr,uselutg,uselutb,useluti;
2196141cc406Sopenharmony_ci/*  static int irmulr= -34*25; */
2197141cc406Sopenharmony_ci   int irmulr= -64*25;
2198141cc406Sopenharmony_ci   int irmulg= -1*25;
2199141cc406Sopenharmony_ci   int irmulb= -0*25;
2200141cc406Sopenharmony_ci   int irmuli= 256*25;
2201141cc406Sopenharmony_ci   int div;
2202141cc406Sopenharmony_ci   int i;
2203141cc406Sopenharmony_ci
2204141cc406Sopenharmony_ci    irmulr=s->ired_red*(25);
2205141cc406Sopenharmony_ci    irmulg=s->ired_green*(25);
2206141cc406Sopenharmony_ci    irmulb=s->ired_blue*(25);
2207141cc406Sopenharmony_ci    irmuli=25*256;
2208141cc406Sopenharmony_ci
2209141cc406Sopenharmony_ci  if(s->LS==2) /* TODO: right conversion factors for 10 and 12 bit */
2210141cc406Sopenharmony_ci    { div=4;
2211141cc406Sopenharmony_ci    }
2212141cc406Sopenharmony_ci  else  if(s->LS==3)
2213141cc406Sopenharmony_ci    { div=16;
2214141cc406Sopenharmony_ci    }
2215141cc406Sopenharmony_ci  else
2216141cc406Sopenharmony_ci    { return 0;
2217141cc406Sopenharmony_ci    }
2218141cc406Sopenharmony_ci
2219141cc406Sopenharmony_ci  memset(s->lutr, 0,256*4);
2220141cc406Sopenharmony_ci  memset(s->lutg, 0,256*4);
2221141cc406Sopenharmony_ci  memset(s->lutb, 0,256*4);
2222141cc406Sopenharmony_ci  memset(s->luti, 0,256*4);
2223141cc406Sopenharmony_ci
2224141cc406Sopenharmony_ci  for(i=0;i<s->lutlength;i++)
2225141cc406Sopenharmony_ci  {  if(s->gamma_bind)
2226141cc406Sopenharmony_ci     { uselutr=uselutg=uselutb=useluti=s->gamma[i]/div;
2227141cc406Sopenharmony_ci     }
2228141cc406Sopenharmony_ci     else
2229141cc406Sopenharmony_ci     { uselutr=s->gamma_r[i]/div;
2230141cc406Sopenharmony_ci       uselutg=s->gamma_g[i]/div;
2231141cc406Sopenharmony_ci       uselutb=s->gamma_b[i]/div;
2232141cc406Sopenharmony_ci       useluti=s->gamma_r[i]/div;
2233141cc406Sopenharmony_ci     }
2234141cc406Sopenharmony_ci     s->lutr[uselutr]=(int)(irmulr*pow((double)i,(double)0.333333));
2235141cc406Sopenharmony_ci     s->lutg[uselutg]=(int)(irmulg*pow((double)i,(double)0.333333));
2236141cc406Sopenharmony_ci     s->lutb[uselutb]=(int)(irmulb*pow((double)i,(double)0.333333));
2237141cc406Sopenharmony_ci     s->luti[useluti]=(int)(irmuli*pow((double)i,(double)0.333333));
2238141cc406Sopenharmony_ci     if(uselutr<255)
2239141cc406Sopenharmony_ci     { if(s->lutr[uselutr+1]==0) s->lutr[uselutr+1]=s->lutr[uselutr];
2240141cc406Sopenharmony_ci     }
2241141cc406Sopenharmony_ci     if(uselutg<255)
2242141cc406Sopenharmony_ci     { if(s->lutg[uselutg+1]==0) s->lutg[uselutg+1]=s->lutg[uselutg];
2243141cc406Sopenharmony_ci     }
2244141cc406Sopenharmony_ci     if(uselutb<255)
2245141cc406Sopenharmony_ci     { if(s->lutb[uselutb+1]==0) s->lutb[uselutb+1]=s->lutb[uselutb];
2246141cc406Sopenharmony_ci     }
2247141cc406Sopenharmony_ci     if(useluti<255)
2248141cc406Sopenharmony_ci     { if(s->luti[useluti+1]==0) s->luti[useluti+1]=s->luti[useluti];
2249141cc406Sopenharmony_ci     }
2250141cc406Sopenharmony_ci  }
2251141cc406Sopenharmony_ci  /* DEBUG
2252141cc406Sopenharmony_ci  for(i=0;i<255;i++)
2253141cc406Sopenharmony_ci  { fprintf(stderr,"%d %d %d %d\n"
2254141cc406Sopenharmony_ci	    ,s->lutr[i],s->lutg[i],s->lutb[i],s->luti[i]);
2255141cc406Sopenharmony_ci  }
2256141cc406Sopenharmony_ci  */
2257141cc406Sopenharmony_ci  return 1;
2258141cc406Sopenharmony_ci}
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci
2261141cc406Sopenharmony_ci
2262141cc406Sopenharmony_ci/* ---------------------------------------------------------------
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci  function:   RGBIfix
2265141cc406Sopenharmony_ci
2266141cc406Sopenharmony_ci  task:       Correct the infrared channel
2267141cc406Sopenharmony_ci
2268141cc406Sopenharmony_ci  import:     unsigned char * rgbimat - RGBI - matrix from scanner
2269141cc406Sopenharmony_ci              int size - number of pixels to correct
2270141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2271141cc406Sopenharmony_ci	      int *lutg - lookup table for red correction
2272141cc406Sopenharmony_ci	      int *lutb - lookup table for red correction
2273141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2274141cc406Sopenharmony_ci
2275141cc406Sopenharmony_ci  export:     unsigned char * orgbimat - RGBI - corrected matrix
2276141cc406Sopenharmony_ci
2277141cc406Sopenharmony_ci  written by: Andreas RICK   19.6.1999
2278141cc406Sopenharmony_ci
2279141cc406Sopenharmony_ci  ----------------------------------------------------------------*/
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_cistatic int RGBIfix(Coolscan_t * scanner,
2282141cc406Sopenharmony_ci	   unsigned char* rgbimat,
2283141cc406Sopenharmony_ci	   unsigned char* orgbimat,
2284141cc406Sopenharmony_ci	    int size,
2285141cc406Sopenharmony_ci	    int *lutr,
2286141cc406Sopenharmony_ci	    int *lutg,
2287141cc406Sopenharmony_ci	    int *lutb,
2288141cc406Sopenharmony_ci	    int *luti)
2289141cc406Sopenharmony_ci
2290141cc406Sopenharmony_ci{
2291141cc406Sopenharmony_ci  unsigned char *pr,*pg,*pb,*pi;
2292141cc406Sopenharmony_ci  unsigned char *opr,*opg,*opb,*opi;
2293141cc406Sopenharmony_ci
2294141cc406Sopenharmony_ci   int r,g,b,i;
2295141cc406Sopenharmony_ci   int ii;
2296141cc406Sopenharmony_ci   int x;
2297141cc406Sopenharmony_ci   for(x=0;x<size;x++)
2298141cc406Sopenharmony_ci   {
2299141cc406Sopenharmony_ci        pr=rgbimat+x*4;
2300141cc406Sopenharmony_ci	pg=pr+1;
2301141cc406Sopenharmony_ci	pb=pg+1;
2302141cc406Sopenharmony_ci	pi=pb+1;
2303141cc406Sopenharmony_ci        opr=orgbimat+x*4;
2304141cc406Sopenharmony_ci	opg=opr+1;
2305141cc406Sopenharmony_ci	opb=opg+1;
2306141cc406Sopenharmony_ci	opi=opb+1;
2307141cc406Sopenharmony_ci	r=lutr[(*pr)];
2308141cc406Sopenharmony_ci	g=lutg[(*pg)];
2309141cc406Sopenharmony_ci	b=lutb[(*pb)];
2310141cc406Sopenharmony_ci	i=luti[(*pi)];
2311141cc406Sopenharmony_ci	ii= i-r-g-b;
2312141cc406Sopenharmony_ci	(*opr)=(*pr);
2313141cc406Sopenharmony_ci	(*opg)=(*pg);
2314141cc406Sopenharmony_ci	(*opb)=(*pb);
2315141cc406Sopenharmony_ci	if(ii<0)ii=0;
2316141cc406Sopenharmony_ci	if(ii>255*256)ii=255*256;
2317141cc406Sopenharmony_ci	if(scanner->negative)
2318141cc406Sopenharmony_ci	{
2319141cc406Sopenharmony_ci	    (*opi)=(unsigned char)(255-(ii>>8));
2320141cc406Sopenharmony_ci	}
2321141cc406Sopenharmony_ci	else
2322141cc406Sopenharmony_ci	{
2323141cc406Sopenharmony_ci	  (*opi)=(unsigned char)(ii>>8);
2324141cc406Sopenharmony_ci	}
2325141cc406Sopenharmony_ci   }
2326141cc406Sopenharmony_ci   return 1;
2327141cc406Sopenharmony_ci}
2328141cc406Sopenharmony_ci
2329141cc406Sopenharmony_ci/* ---------------------------------------------------------------
2330141cc406Sopenharmony_ci
2331141cc406Sopenharmony_ci  function:   RGBIfix16
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci  task:       Correct the infrared channel for 16 bit images
2334141cc406Sopenharmony_ci              (doesn't do anything for now)
2335141cc406Sopenharmony_ci
2336141cc406Sopenharmony_ci  import:     unsigned char * rgbimat - RGBI - matrix from scanner
2337141cc406Sopenharmony_ci              int size - number of pixels to correct
2338141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2339141cc406Sopenharmony_ci	      int *lutg - lookup table for red correction
2340141cc406Sopenharmony_ci	      int *lutb - lookup table for red correction
2341141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2342141cc406Sopenharmony_ci
2343141cc406Sopenharmony_ci  export:     unsigned char * orgbimat - RGBI - corrected matrix
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci  written by: Andreas RICK   19.6.1999
2346141cc406Sopenharmony_ci
2347141cc406Sopenharmony_ci  ----------------------------------------------------------------*/
2348141cc406Sopenharmony_ci
2349141cc406Sopenharmony_cistatic int RGBIfix16(Coolscan_t * scanner,
2350141cc406Sopenharmony_ci	      unsigned short* rgbimat,
2351141cc406Sopenharmony_ci	      unsigned short* orgbimat,
2352141cc406Sopenharmony_ci	      int size,
2353141cc406Sopenharmony_ci	      int *lutr,
2354141cc406Sopenharmony_ci	      int *lutg,
2355141cc406Sopenharmony_ci	      int *lutb,
2356141cc406Sopenharmony_ci	      int *luti)
2357141cc406Sopenharmony_ci
2358141cc406Sopenharmony_ci{
2359141cc406Sopenharmony_ci  unsigned short *pr,*pg,*pb,*pi;
2360141cc406Sopenharmony_ci  unsigned short *opr,*opg,*opb,*opi;
2361141cc406Sopenharmony_ci  int x;
2362141cc406Sopenharmony_ci
2363141cc406Sopenharmony_ci  (void) scanner; (void) lutr; (void) lutg; (void) lutb; (void) luti;
2364141cc406Sopenharmony_ci
2365141cc406Sopenharmony_ci   for(x=0;x<size;x++)
2366141cc406Sopenharmony_ci   {
2367141cc406Sopenharmony_ci        pr=rgbimat+x*4;
2368141cc406Sopenharmony_ci	pg=pr+1;
2369141cc406Sopenharmony_ci	pb=pg+1;
2370141cc406Sopenharmony_ci	pi=pb+1;
2371141cc406Sopenharmony_ci        opr=orgbimat+x*4;
2372141cc406Sopenharmony_ci	opg=opr+1;
2373141cc406Sopenharmony_ci	opb=opg+1;
2374141cc406Sopenharmony_ci	opi=opb+1;
2375141cc406Sopenharmony_ci	(*opr)=(((*pr)&0x00ff)<<8)+(((*pr)&0xff00)>>8);
2376141cc406Sopenharmony_ci      	(*opg)=(((*pg)&0x00ff)<<8)+(((*pg)&0xff00)>>8);
2377141cc406Sopenharmony_ci	(*opb)=(((*pb)&0x00ff)<<8)+(((*pb)&0xff00)>>8);
2378141cc406Sopenharmony_ci	(*opi)=(((*pi)&0x00ff)<<8)+(((*pi)&0xff00)>>8);
2379141cc406Sopenharmony_ci   }
2380141cc406Sopenharmony_ci   return 1;
2381141cc406Sopenharmony_ci}
2382141cc406Sopenharmony_ci
2383141cc406Sopenharmony_ci
2384141cc406Sopenharmony_ci/* ---------------------------------------------------------------
2385141cc406Sopenharmony_ci
2386141cc406Sopenharmony_ci  function:   rgb2g
2387141cc406Sopenharmony_ci
2388141cc406Sopenharmony_ci  task:       Convert RGB data to grey
2389141cc406Sopenharmony_ci
2390141cc406Sopenharmony_ci  import:     unsigned char * rgbimat - RGB - matrix from scanner
2391141cc406Sopenharmony_ci              int size - size of input data (num pixel)
2392141cc406Sopenharmony_ci
2393141cc406Sopenharmony_ci  export:     unsigned char * gomat - Grey matrix
2394141cc406Sopenharmony_ci
2395141cc406Sopenharmony_ci  written by: Andreas RICK   13.7.1999
2396141cc406Sopenharmony_ci
2397141cc406Sopenharmony_ci  ----------------------------------------------------------------*/
2398141cc406Sopenharmony_ci#define RtoG ((int)(0.27*256))
2399141cc406Sopenharmony_ci#define GtoG ((int)(0.54*256))
2400141cc406Sopenharmony_ci#define BtoG ((int)(0.19*256))
2401141cc406Sopenharmony_ci
2402141cc406Sopenharmony_cistatic int rgb2g(unsigned char* rgbimat,unsigned char* gomat,
2403141cc406Sopenharmony_ci	  int size)
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci{  unsigned char *pr,*pg,*pb;
2406141cc406Sopenharmony_ci   unsigned char *opg;
2407141cc406Sopenharmony_ci
2408141cc406Sopenharmony_ci   int g;
2409141cc406Sopenharmony_ci   int x;
2410141cc406Sopenharmony_ci   for(x=0;x<size;x++)
2411141cc406Sopenharmony_ci   {
2412141cc406Sopenharmony_ci        pr=rgbimat+x*3;
2413141cc406Sopenharmony_ci	pg=pr+1;
2414141cc406Sopenharmony_ci	pb=pg+1;
2415141cc406Sopenharmony_ci        opg=gomat+x;
2416141cc406Sopenharmony_ci	g= RtoG*(*pr) + GtoG*(*pg) + BtoG*(*pb);
2417141cc406Sopenharmony_ci	(*opg)=(unsigned char)(g>>8);
2418141cc406Sopenharmony_ci   }
2419141cc406Sopenharmony_ci   return 1;
2420141cc406Sopenharmony_ci}
2421141cc406Sopenharmony_ci
2422141cc406Sopenharmony_ci
2423141cc406Sopenharmony_ci/* ---------------------------------------------------------------
2424141cc406Sopenharmony_ci
2425141cc406Sopenharmony_ci  function:   RGBIfix1
2426141cc406Sopenharmony_ci
2427141cc406Sopenharmony_ci  task:       Correct the infrared channel.
2428141cc406Sopenharmony_ci              The input image data is the output of scanning
2429141cc406Sopenharmony_ci	      with LUT. To calculate the original values
2430141cc406Sopenharmony_ci	      the lutr and luti is applied.
2431141cc406Sopenharmony_ci	      The infrared values is corrected by:
2432141cc406Sopenharmony_ci
2433141cc406Sopenharmony_ci	      Ir=mr*lutr(r)+luti(i)
2434141cc406Sopenharmony_ci
2435141cc406Sopenharmony_ci  import:     unsigned char * rgbimat - RGBI - matrix from scanner
2436141cc406Sopenharmony_ci              int size - number of pixels to correct
2437141cc406Sopenharmony_ci 	      ColorCorrect *cc,
2438141cc406Sopenharmony_ci	      int *lutr - lookup table for red correction
2439141cc406Sopenharmony_ci	      int *luti - lookup table for ired correction
2440141cc406Sopenharmony_ci
2441141cc406Sopenharmony_ci  export:     unsigned char * orgbimat - RGBI - corrected matrix
2442141cc406Sopenharmony_ci
2443141cc406Sopenharmony_ci  written by: Andreas RICK   3.7.1999
2444141cc406Sopenharmony_ci
2445141cc406Sopenharmony_ci  ----------------------------------------------------------------*/
2446141cc406Sopenharmony_ci#if 0
2447141cc406Sopenharmony_cistatic int RGBIfix1(unsigned char* rgbimat,unsigned char* orgbimat,
2448141cc406Sopenharmony_ci	    int size,
2449141cc406Sopenharmony_ci	    int *lutr,
2450141cc406Sopenharmony_ci	    int *lutg,
2451141cc406Sopenharmony_ci	    int *lutb,
2452141cc406Sopenharmony_ci	    int *luti)
2453141cc406Sopenharmony_ci
2454141cc406Sopenharmony_ci{  unsigned char *pr,*pg,*pb,*pi;
2455141cc406Sopenharmony_ci   unsigned char *opr,*opg,*opb,*opi;
2456141cc406Sopenharmony_ci   ColorCorrect cc;
2457141cc406Sopenharmony_ci   int r,i;
2458141cc406Sopenharmony_ci   static int thresi=100;
2459141cc406Sopenharmony_ci   int ii;
2460141cc406Sopenharmony_ci   int x;
2461141cc406Sopenharmony_ci
2462141cc406Sopenharmony_ci   (void) lutg; (void) lutb;
2463141cc406Sopenharmony_ci
2464141cc406Sopenharmony_ci   /* calculate regression between r and ir */
2465141cc406Sopenharmony_ci   cc.sum=0;
2466141cc406Sopenharmony_ci   cc.sumr=cc.sumii=cc.sumrr=cc.sumi=cc.sumri=0.0;
2467141cc406Sopenharmony_ci   for(x=0;x<size;x++)
2468141cc406Sopenharmony_ci   {    pr=rgbimat+x*4;
2469141cc406Sopenharmony_ci	pi=pr+3;
2470141cc406Sopenharmony_ci	r=lutr[(*pr)];
2471141cc406Sopenharmony_ci	i=luti[(*pi)];
2472141cc406Sopenharmony_ci	/*	r=(*pr);
2473141cc406Sopenharmony_ci		i=(*pi); */
2474141cc406Sopenharmony_ci	if((*pi)>thresi)
2475141cc406Sopenharmony_ci        { cc.sum++;
2476141cc406Sopenharmony_ci          cc.sumr+=r;
2477141cc406Sopenharmony_ci          cc.sumii+=(i*i);
2478141cc406Sopenharmony_ci          cc.sumrr+=(r*r);
2479141cc406Sopenharmony_ci          cc.sumi+=i;
2480141cc406Sopenharmony_ci          cc.sumri+=(i*r);
2481141cc406Sopenharmony_ci	}
2482141cc406Sopenharmony_ci   }
2483141cc406Sopenharmony_ci   if((cc.sumii!=0)&&(cc.sum!=0))
2484141cc406Sopenharmony_ci   { double dn,dz,dm;
2485141cc406Sopenharmony_ci     dz=(cc.sumri-cc.sumr*cc.sumi/cc.sum);
2486141cc406Sopenharmony_ci     dn=(cc.sumrr-cc.sumr*cc.sumr/cc.sum);
2487141cc406Sopenharmony_ci     DBG (2, "Reg:dz:%e dn:%e\n",dz,dn);
2488141cc406Sopenharmony_ci     if(dn!=0)
2489141cc406Sopenharmony_ci     {  dm=(dz/dn);
2490141cc406Sopenharmony_ci        cc.mr=(int)(dm*1024);
2491141cc406Sopenharmony_ci     }
2492141cc406Sopenharmony_ci     else
2493141cc406Sopenharmony_ci     { cc.mr=0;
2494141cc406Sopenharmony_ci       dm=0;
2495141cc406Sopenharmony_ci     }
2496141cc406Sopenharmony_ci     cc.br=(int)((cc.sumi-dm*cc.sumr)/cc.sum);
2497141cc406Sopenharmony_ci   }
2498141cc406Sopenharmony_ci   else
2499141cc406Sopenharmony_ci   { cc.mr=0;
2500141cc406Sopenharmony_ci   }
2501141cc406Sopenharmony_ci   DBG (2, "Regression: size:%d I=%d/1024*R b:%d s:%d sr:%e si:%e sii:%e sri:%e  srr:%e\n",
2502141cc406Sopenharmony_ci	size,cc.mr,cc.br,cc.sum,cc.sumr,cc.sumi,cc.sumii,cc.sumri,cc.sumrr);
2503141cc406Sopenharmony_ci   for(x=0;x<size;x++)
2504141cc406Sopenharmony_ci   {
2505141cc406Sopenharmony_ci
2506141cc406Sopenharmony_ci        pr=rgbimat+x*4;
2507141cc406Sopenharmony_ci	pg=pr+1;
2508141cc406Sopenharmony_ci	pb=pg+1;
2509141cc406Sopenharmony_ci	pi=pb+1;
2510141cc406Sopenharmony_ci        opr=orgbimat+x*4;
2511141cc406Sopenharmony_ci	opg=opr+1;
2512141cc406Sopenharmony_ci	opb=opg+1;
2513141cc406Sopenharmony_ci	opi=opb+1;
2514141cc406Sopenharmony_ci	r=lutr[(*pr)];
2515141cc406Sopenharmony_ci	i=luti[(*pi)];
2516141cc406Sopenharmony_ci	/*	r=(*pr);
2517141cc406Sopenharmony_ci		i=(*pi); */
2518141cc406Sopenharmony_ci	ii= ((i-((r*cc.mr)>>10)-cc.br)>>2) +128;
2519141cc406Sopenharmony_ci	(*opr)=(*pr);
2520141cc406Sopenharmony_ci	(*opg)=(*pg);
2521141cc406Sopenharmony_ci	(*opb)=(*pb);
2522141cc406Sopenharmony_ci	if(ii<0) ii=0;
2523141cc406Sopenharmony_ci	if(ii>255) ii=255;
2524141cc406Sopenharmony_ci	(*opi)=(unsigned char)(ii);
2525141cc406Sopenharmony_ci   }
2526141cc406Sopenharmony_ci   return 1;
2527141cc406Sopenharmony_ci}
2528141cc406Sopenharmony_ci
2529141cc406Sopenharmony_ci#endif
2530141cc406Sopenharmony_ci/* This function is executed as a child process. */
2531141cc406Sopenharmony_cistatic int
2532141cc406Sopenharmony_cireader_process (void *data )
2533141cc406Sopenharmony_ci{
2534141cc406Sopenharmony_ci  int status;
2535141cc406Sopenharmony_ci  unsigned int i;
2536141cc406Sopenharmony_ci  unsigned char h;
2537141cc406Sopenharmony_ci  unsigned int data_left;
2538141cc406Sopenharmony_ci  unsigned int data_to_read;
2539141cc406Sopenharmony_ci  unsigned int data_to_write;
2540141cc406Sopenharmony_ci  FILE *fp;
2541141cc406Sopenharmony_ci  sigset_t sigterm_set, ignore_set;
2542141cc406Sopenharmony_ci  struct SIGACTION act;
2543141cc406Sopenharmony_ci  unsigned int bpl, linesPerBuf, lineOffset;
2544141cc406Sopenharmony_ci  unsigned char r_data, g_data, b_data;
2545141cc406Sopenharmony_ci  unsigned int j, line;
2546141cc406Sopenharmony_ci  Coolscan_t * scanner = (Coolscan_t*)data;
2547141cc406Sopenharmony_ci
2548141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
2549141cc406Sopenharmony_ci    {
2550141cc406Sopenharmony_ci      DBG (10, "reader_process started (forked)\n");
2551141cc406Sopenharmony_ci      close (scanner->pipe);
2552141cc406Sopenharmony_ci      scanner->pipe = -1;
2553141cc406Sopenharmony_ci
2554141cc406Sopenharmony_ci      sigfillset ( &ignore_set );
2555141cc406Sopenharmony_ci      sigdelset  ( &ignore_set, SIGTERM );
2556141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__)
2557141cc406Sopenharmony_ci      sigdelset  ( &ignore_set, SIGUSR2 );
2558141cc406Sopenharmony_ci#endif
2559141cc406Sopenharmony_ci      sigprocmask( SIG_SETMASK, &ignore_set, 0 );
2560141cc406Sopenharmony_ci
2561141cc406Sopenharmony_ci      memset (&act, 0, sizeof (act));
2562141cc406Sopenharmony_ci      sigaction (SIGTERM, &act, 0);
2563141cc406Sopenharmony_ci    }
2564141cc406Sopenharmony_ci  else
2565141cc406Sopenharmony_ci    {
2566141cc406Sopenharmony_ci      DBG (10, "reader_process started (as thread)\n");
2567141cc406Sopenharmony_ci    }
2568141cc406Sopenharmony_ci
2569141cc406Sopenharmony_ci  sigemptyset (&sigterm_set);
2570141cc406Sopenharmony_ci  sigaddset (&sigterm_set, SIGTERM);
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci  fp = fdopen ( scanner->reader_fds, "w");
2573141cc406Sopenharmony_ci  if (!fp)
2574141cc406Sopenharmony_ci    {
2575141cc406Sopenharmony_ci      DBG (1, "reader_process: couldn't open pipe!\n");
2576141cc406Sopenharmony_ci      return 1;
2577141cc406Sopenharmony_ci    }
2578141cc406Sopenharmony_ci
2579141cc406Sopenharmony_ci  DBG (10, "reader_process: starting to READ data\n");
2580141cc406Sopenharmony_ci
2581141cc406Sopenharmony_ci  data_left = scan_bytes_per_line (scanner) *
2582141cc406Sopenharmony_ci    lines_per_scan (scanner);
2583141cc406Sopenharmony_ci
2584141cc406Sopenharmony_ci  /*scanner->row_bufsize = sanei_scsi_max_request_size;*/
2585141cc406Sopenharmony_ci  coolscan_trim_rowbufsize (scanner);	/* trim bufsize */
2586141cc406Sopenharmony_ci
2587141cc406Sopenharmony_ci  DBG (10, "reader_process: reading %u bytes in blocks of %u bytes\n",
2588141cc406Sopenharmony_ci       data_left, scanner->row_bufsize);
2589141cc406Sopenharmony_ci
2590141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));
2591141cc406Sopenharmony_ci  act.sa_handler = sigterm_handler;
2592141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
2593141cc406Sopenharmony_ci  /* wait_scanner(scanner); */
2594141cc406Sopenharmony_ci  do
2595141cc406Sopenharmony_ci    {
2596141cc406Sopenharmony_ci      data_to_read = (data_left < scanner->row_bufsize) ?
2597141cc406Sopenharmony_ci	data_left : scanner->row_bufsize;
2598141cc406Sopenharmony_ci
2599141cc406Sopenharmony_ci      data_to_write=data_to_read;
2600141cc406Sopenharmony_ci
2601141cc406Sopenharmony_ci      status = coolscan_read_data_block (scanner
2602141cc406Sopenharmony_ci					 ,R_datatype_imagedata,data_to_read);
2603141cc406Sopenharmony_ci      if (status == 0)
2604141cc406Sopenharmony_ci	{
2605141cc406Sopenharmony_ci	  continue;
2606141cc406Sopenharmony_ci	}
2607141cc406Sopenharmony_ci      if (status == -1)
2608141cc406Sopenharmony_ci	{
2609141cc406Sopenharmony_ci	  DBG (1, "reader_process: unable to get image data from scanner!\n");
2610141cc406Sopenharmony_ci	  fclose (fp);
2611141cc406Sopenharmony_ci	  return (-1);
2612141cc406Sopenharmony_ci	}
2613141cc406Sopenharmony_ci
2614141cc406Sopenharmony_ci      if (scanner->LS == 1) {	/* mirror image for LS-1000 */
2615141cc406Sopenharmony_ci	  bpl = scan_bytes_per_line(scanner);
2616141cc406Sopenharmony_ci	  linesPerBuf = data_to_read / bpl;
2617141cc406Sopenharmony_ci
2618141cc406Sopenharmony_ci	  for (line = 0, lineOffset = 0; line < linesPerBuf;
2619141cc406Sopenharmony_ci	       line++, lineOffset += bpl ) {
2620141cc406Sopenharmony_ci
2621141cc406Sopenharmony_ci	      if (scanner->colormode == RGB) {
2622141cc406Sopenharmony_ci		  for (j = 0; j < bpl/2 ; j += 3) {
2623141cc406Sopenharmony_ci		      r_data=scanner->buffer[lineOffset + j];
2624141cc406Sopenharmony_ci		      g_data=scanner->buffer[lineOffset + j + 1];
2625141cc406Sopenharmony_ci		      b_data=scanner->buffer[lineOffset + j + 2];
2626141cc406Sopenharmony_ci
2627141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + j] =
2628141cc406Sopenharmony_ci			  scanner->buffer[lineOffset + bpl -1 - j - 2 ];
2629141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + j + 1] =
2630141cc406Sopenharmony_ci			  scanner->buffer[lineOffset + bpl -1 - j - 1 ];
2631141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + j + 2] =
2632141cc406Sopenharmony_ci			  scanner->buffer[lineOffset + bpl -1 - j ];
2633141cc406Sopenharmony_ci
2634141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + bpl -1 - j - 2 ] = r_data;
2635141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + bpl -1 - j - 1] = g_data;
2636141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + bpl -1 - j] = b_data;
2637141cc406Sopenharmony_ci		  }
2638141cc406Sopenharmony_ci	      }
2639141cc406Sopenharmony_ci	      else {
2640141cc406Sopenharmony_ci		  for (j = 0; j < bpl/2; j++) {
2641141cc406Sopenharmony_ci		      r_data=scanner->buffer[lineOffset + j];
2642141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + j] =
2643141cc406Sopenharmony_ci			  scanner->buffer[lineOffset + bpl - 1 - j];
2644141cc406Sopenharmony_ci		      scanner->buffer[lineOffset + bpl - 1 - j] = r_data;
2645141cc406Sopenharmony_ci		  }
2646141cc406Sopenharmony_ci	      }
2647141cc406Sopenharmony_ci	  }
2648141cc406Sopenharmony_ci      }
2649141cc406Sopenharmony_ci      if(scanner->colormode==RGBI)
2650141cc406Sopenharmony_ci      {  /* Correct Infrared Channel */
2651141cc406Sopenharmony_ci	if(scanner->bits_per_color>8)
2652141cc406Sopenharmony_ci	{
2653141cc406Sopenharmony_ci	  RGBIfix16(scanner, (unsigned short * ) scanner->buffer,
2654141cc406Sopenharmony_ci		    (unsigned short * )scanner->obuffer,
2655141cc406Sopenharmony_ci		 data_to_read/8,scanner->lutr,
2656141cc406Sopenharmony_ci		 scanner->lutg,scanner->lutb,scanner->luti);
2657141cc406Sopenharmony_ci	}
2658141cc406Sopenharmony_ci	else
2659141cc406Sopenharmony_ci	{
2660141cc406Sopenharmony_ci	  RGBIfix(scanner,scanner->buffer,scanner->obuffer,
2661141cc406Sopenharmony_ci		 data_to_read/4,scanner->lutr,
2662141cc406Sopenharmony_ci		 scanner->lutg,scanner->lutb,scanner->luti);
2663141cc406Sopenharmony_ci	}
2664141cc406Sopenharmony_ci      }
2665141cc406Sopenharmony_ci      else if((scanner->colormode==GREYSCALE)&&(scanner->LS>=2))
2666141cc406Sopenharmony_ci      {  /* Convert to Grey */
2667141cc406Sopenharmony_ci	 data_to_write/=3;
2668141cc406Sopenharmony_ci	 rgb2g(scanner->buffer,scanner->obuffer,data_to_write);
2669141cc406Sopenharmony_ci      }
2670141cc406Sopenharmony_ci      else
2671141cc406Sopenharmony_ci      { /* or just copy */
2672141cc406Sopenharmony_ci	memcpy (scanner->obuffer, scanner->buffer,data_to_read);
2673141cc406Sopenharmony_ci      }
2674141cc406Sopenharmony_ci      if((!scanner->low_byte_first)&&(scanner->bits_per_color>8))
2675141cc406Sopenharmony_ci	{  for(i=0;i<data_to_write;i++) /* inverse byteorder */
2676141cc406Sopenharmony_ci           { h=scanner->obuffer[i];
2677141cc406Sopenharmony_ci             scanner->obuffer[i]=scanner->obuffer[i+1];
2678141cc406Sopenharmony_ci	     i++;
2679141cc406Sopenharmony_ci  	     scanner->obuffer[i]=h;
2680141cc406Sopenharmony_ci	   }
2681141cc406Sopenharmony_ci	}
2682141cc406Sopenharmony_ci      fwrite (scanner->obuffer, 1, data_to_write, fp);
2683141cc406Sopenharmony_ci      fflush (fp);
2684141cc406Sopenharmony_ci      data_left -= data_to_read;
2685141cc406Sopenharmony_ci      DBG (10, "reader_process: buffer of %d bytes read; %d bytes to go\n",
2686141cc406Sopenharmony_ci	   data_to_read, data_left);
2687141cc406Sopenharmony_ci    }
2688141cc406Sopenharmony_ci  while (data_left);
2689141cc406Sopenharmony_ci
2690141cc406Sopenharmony_ci  fclose (fp);
2691141cc406Sopenharmony_ci
2692141cc406Sopenharmony_ci  DBG (10, "reader_process: finished reading data\n");
2693141cc406Sopenharmony_ci
2694141cc406Sopenharmony_ci  return 0;
2695141cc406Sopenharmony_ci}
2696141cc406Sopenharmony_ci
2697141cc406Sopenharmony_cistatic SANE_Status
2698141cc406Sopenharmony_ciinit_options (Coolscan_t * scanner)
2699141cc406Sopenharmony_ci{
2700141cc406Sopenharmony_ci  int i;
2701141cc406Sopenharmony_ci  int bit_depths;
2702141cc406Sopenharmony_ci
2703141cc406Sopenharmony_ci  DBG (10, "init_options\n");
2704141cc406Sopenharmony_ci
2705141cc406Sopenharmony_ci  memset (scanner->opt, 0, sizeof (scanner->opt));
2706141cc406Sopenharmony_ci
2707141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
2708141cc406Sopenharmony_ci    {
2709141cc406Sopenharmony_ci      scanner->opt[i].size = sizeof (SANE_Word);
2710141cc406Sopenharmony_ci      scanner->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2711141cc406Sopenharmony_ci    }
2712141cc406Sopenharmony_ci
2713141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2714141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2715141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2716141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2717141cc406Sopenharmony_ci
2718141cc406Sopenharmony_ci  /* "Mode" group: */
2719141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].title = "Scan Mode";
2720141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].desc = "";
2721141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2722141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].cap = 0;
2723141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2724141cc406Sopenharmony_ci
2725141cc406Sopenharmony_ci  /* scan mode */
2726141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2727141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2728141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2729141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].type = SANE_TYPE_STRING;
2730141cc406Sopenharmony_ci  if(scanner->LS<2)
2731141cc406Sopenharmony_ci  { scanner->opt[OPT_MODE].size = max_string_size (scan_mode_list_LS20);
2732141cc406Sopenharmony_ci    scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2733141cc406Sopenharmony_ci    scanner->opt[OPT_MODE].constraint.string_list = scan_mode_list_LS20;
2734141cc406Sopenharmony_ci  }
2735141cc406Sopenharmony_ci  else
2736141cc406Sopenharmony_ci  { scanner->opt[OPT_MODE].size = max_string_size (scan_mode_list_LS30);
2737141cc406Sopenharmony_ci    scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2738141cc406Sopenharmony_ci    scanner->opt[OPT_MODE].constraint.string_list = scan_mode_list_LS30;
2739141cc406Sopenharmony_ci  }
2740141cc406Sopenharmony_ci
2741141cc406Sopenharmony_ci  /* source */
2742141cc406Sopenharmony_ci  source_list[0] = "Slide";
2743141cc406Sopenharmony_ci  source_list[1] = "Automatic Slide Feeder";
2744141cc406Sopenharmony_ci  source_list[2] = NULL;
2745141cc406Sopenharmony_ci  if (!scanner->autofeeder)
2746141cc406Sopenharmony_ci    {
2747141cc406Sopenharmony_ci      scanner->opt[OPT_SOURCE].cap = SANE_CAP_INACTIVE;
2748141cc406Sopenharmony_ci    }
2749141cc406Sopenharmony_ci
2750141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
2751141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
2752141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
2753141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
2754141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].size = max_string_size (source_list);
2755141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2756141cc406Sopenharmony_ci  scanner->opt[OPT_SOURCE].constraint.string_list = source_list;
2757141cc406Sopenharmony_ci
2758141cc406Sopenharmony_ci  /* negative */
2759141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].name = "type";
2760141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].title = "Film type";
2761141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].desc =
2762141cc406Sopenharmony_ci    "Select the film type (positive (slide) or negative)";
2763141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].type = SANE_TYPE_STRING;
2764141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].size = max_string_size (type_list);
2765141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2766141cc406Sopenharmony_ci  scanner->opt[OPT_TYPE].constraint.string_list = type_list;
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].name = "prescan";
2769141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].title = "Prescan";
2770141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].desc =
2771141cc406Sopenharmony_ci    "Perform a prescan during preview";
2772141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].type = SANE_TYPE_BOOL;
2773141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN].unit = SANE_UNIT_NONE;
2774141cc406Sopenharmony_ci
2775141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].name = "prescan now";
2776141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].title = "Prescan now";
2777141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].desc =
2778141cc406Sopenharmony_ci    "Perform a prescan now";
2779141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].type = SANE_TYPE_BUTTON;
2780141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].unit = SANE_UNIT_NONE;
2781141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].size = 0;
2782141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
2783141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].constraint_type = SANE_CONSTRAINT_NONE;
2784141cc406Sopenharmony_ci  scanner->opt[OPT_PRESCAN_NOW].constraint.string_list = 0;
2785141cc406Sopenharmony_ci
2786141cc406Sopenharmony_ci /* bit depth */
2787141cc406Sopenharmony_ci
2788141cc406Sopenharmony_ci  bit_depths=0;
2789141cc406Sopenharmony_ci  bit_depth_list[++bit_depths] = 8;
2790141cc406Sopenharmony_ci  if (scanner->LS==2)
2791141cc406Sopenharmony_ci  {
2792141cc406Sopenharmony_ci    bit_depth_list[++bit_depths] = 10;
2793141cc406Sopenharmony_ci  }
2794141cc406Sopenharmony_ci  if (scanner->LS==3)
2795141cc406Sopenharmony_ci  {
2796141cc406Sopenharmony_ci    bit_depth_list[++bit_depths] = 12;
2797141cc406Sopenharmony_ci  }
2798141cc406Sopenharmony_ci
2799141cc406Sopenharmony_ci  bit_depth_list[0] = bit_depths;
2800141cc406Sopenharmony_ci
2801141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].name  = SANE_NAME_BIT_DEPTH;
2802141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
2803141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].desc  = SANE_DESC_BIT_DEPTH;
2804141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].type  = SANE_TYPE_INT;
2805141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].unit  = SANE_UNIT_BIT;
2806141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2807141cc406Sopenharmony_ci  scanner->opt[OPT_BIT_DEPTH].constraint.word_list = bit_depth_list;
2808141cc406Sopenharmony_ci
2809141cc406Sopenharmony_ci  /* resolution */
2810141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2811141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
2812141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
2813141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
2814141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
2815141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2816141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].constraint.word_list = resolution_list;
2817141cc406Sopenharmony_ci
2818141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].name = "preview-resolution";
2819141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].title = "Preview resolution";
2820141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
2821141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].type = SANE_TYPE_INT;
2822141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].unit = SANE_UNIT_DPI;
2823141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2824141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW_RESOLUTION].constraint.word_list = resolution_list;
2825141cc406Sopenharmony_ci
2826141cc406Sopenharmony_ci  /* "Geometry" group: */
2827141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
2828141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].desc = "";
2829141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2830141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
2831141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2832141cc406Sopenharmony_ci
2833141cc406Sopenharmony_ci  /* top-left x */
2834141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2835141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2836141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2837141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
2838141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM;
2839141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
2840141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint.range = &(scanner->x_range);
2841141cc406Sopenharmony_ci
2842141cc406Sopenharmony_ci  /* top-left y */
2843141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2844141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2845141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2846141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
2847141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
2848141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2849141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint.range = &(scanner->y_range);
2850141cc406Sopenharmony_ci
2851141cc406Sopenharmony_ci  /* bottom-right x */
2852141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2853141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2854141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2855141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
2856141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM;
2857141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
2858141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint.range = &(scanner->x_range);
2859141cc406Sopenharmony_ci
2860141cc406Sopenharmony_ci  /* bottom-right y */
2861141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2862141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2863141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2864141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
2865141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
2866141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
2867141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint.range = &(scanner->y_range);
2868141cc406Sopenharmony_ci
2869141cc406Sopenharmony_ci
2870141cc406Sopenharmony_ci  /* ------------------------------ */
2871141cc406Sopenharmony_ci
2872141cc406Sopenharmony_ci  /* "Enhancement" group: */
2873141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
2874141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].desc = "";
2875141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2876141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
2877141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2878141cc406Sopenharmony_ci
2879141cc406Sopenharmony_ci
2880141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_BIND].name = "gamma-bind";
2881141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_BIND].title = "Gamma bind";
2882141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_BIND].desc =
2883141cc406Sopenharmony_ci    "Use same gamma correction for all colours";
2884141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_BIND].type = SANE_TYPE_BOOL;
2885141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_BIND].unit = SANE_UNIT_NONE;
2886141cc406Sopenharmony_ci
2887141cc406Sopenharmony_ci
2888141cc406Sopenharmony_ci  scanner->opt[OPT_ANALOG_GAMMA].name = "analog_gamma";
2889141cc406Sopenharmony_ci  scanner->opt[OPT_ANALOG_GAMMA].title = "Analog Gamma";
2890141cc406Sopenharmony_ci  scanner->opt[OPT_ANALOG_GAMMA].desc = "Analog Gamma";
2891141cc406Sopenharmony_ci  scanner->opt[OPT_ANALOG_GAMMA].type = SANE_TYPE_BOOL;
2892141cc406Sopenharmony_ci  scanner->opt[OPT_ANALOG_GAMMA].unit = SANE_UNIT_NONE;
2893141cc406Sopenharmony_ci  if (!scanner->analoggamma)
2894141cc406Sopenharmony_ci    {
2895141cc406Sopenharmony_ci      scanner->opt[OPT_ANALOG_GAMMA].cap = SANE_CAP_INACTIVE;
2896141cc406Sopenharmony_ci    }
2897141cc406Sopenharmony_ci
2898141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].name = "averaging";
2899141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].title = "Averaging";
2900141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].desc = "Averaging";
2901141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].type = SANE_TYPE_BOOL;
2902141cc406Sopenharmony_ci  scanner->opt[OPT_AVERAGING].unit = SANE_UNIT_NONE;
2903141cc406Sopenharmony_ci
2904141cc406Sopenharmony_ci
2905141cc406Sopenharmony_ci  scanner->opt[OPT_RGB_CONTROL].name = "rgb-control";
2906141cc406Sopenharmony_ci  scanner->opt[OPT_RGB_CONTROL].title = "RGB control";
2907141cc406Sopenharmony_ci  scanner->opt[OPT_RGB_CONTROL].desc =
2908141cc406Sopenharmony_ci    "toggles brightness/contrast control over individual colours";
2909141cc406Sopenharmony_ci  scanner->opt[OPT_RGB_CONTROL].type = SANE_TYPE_BOOL;
2910141cc406Sopenharmony_ci  scanner->opt[OPT_RGB_CONTROL].unit = SANE_UNIT_NONE;
2911141cc406Sopenharmony_ci  if(scanner->LS>=2)
2912141cc406Sopenharmony_ci  {  scanner->opt[OPT_RGB_CONTROL].cap |= SANE_CAP_INACTIVE;
2913141cc406Sopenharmony_ci  }
2914141cc406Sopenharmony_ci
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci
2917141cc406Sopenharmony_ci  /* brightness */
2918141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2919141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2920141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2921141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
2922141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
2923141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2924141cc406Sopenharmony_ci  scanner->opt[OPT_BRIGHTNESS].constraint.range = &brightness_range;
2925141cc406Sopenharmony_ci  if(scanner->LS>=2)
2926141cc406Sopenharmony_ci  {  scanner->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2927141cc406Sopenharmony_ci  }
2928141cc406Sopenharmony_ci
2929141cc406Sopenharmony_ci
2930141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].name = "red-brightness";
2931141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].title = "Red brightness";
2932141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2933141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].type = SANE_TYPE_INT;
2934141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].unit = SANE_UNIT_NONE;
2935141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2936141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].constraint.range = &brightness_range;
2937141cc406Sopenharmony_ci  scanner->opt[OPT_R_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2938141cc406Sopenharmony_ci
2939141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].name = "green-brightness";
2940141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].title = "Green brightness";
2941141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2942141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].type = SANE_TYPE_INT;
2943141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].unit = SANE_UNIT_NONE;
2944141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2945141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].constraint.range = &brightness_range;
2946141cc406Sopenharmony_ci  scanner->opt[OPT_G_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2947141cc406Sopenharmony_ci
2948141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].name = "blue-brightness";
2949141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].title = "Blue brightness";
2950141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2951141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].type = SANE_TYPE_INT;
2952141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].unit = SANE_UNIT_NONE;
2953141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
2954141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].constraint.range = &brightness_range;
2955141cc406Sopenharmony_ci  scanner->opt[OPT_B_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2956141cc406Sopenharmony_ci
2957141cc406Sopenharmony_ci  /* contrast */
2958141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
2959141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
2960141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
2961141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
2962141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
2963141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2964141cc406Sopenharmony_ci  scanner->opt[OPT_CONTRAST].constraint.range = &contrast_range;
2965141cc406Sopenharmony_ci  if(scanner->LS>=2)
2966141cc406Sopenharmony_ci  {  scanner->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2967141cc406Sopenharmony_ci  }
2968141cc406Sopenharmony_ci
2969141cc406Sopenharmony_ci
2970141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].name = "red-contrast";
2971141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].title = "Red contrast";
2972141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].desc = SANE_DESC_CONTRAST;
2973141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].type = SANE_TYPE_INT;
2974141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].unit = SANE_UNIT_NONE;
2975141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2976141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].constraint.range = &contrast_range;
2977141cc406Sopenharmony_ci  scanner->opt[OPT_R_CONTRAST].cap |= SANE_CAP_INACTIVE;
2978141cc406Sopenharmony_ci
2979141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].name = "green-contrast";
2980141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].title = "Green contrast";
2981141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].desc = SANE_DESC_CONTRAST;
2982141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].type = SANE_TYPE_INT;
2983141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].unit = SANE_UNIT_NONE;
2984141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2985141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].constraint.range = &contrast_range;
2986141cc406Sopenharmony_ci  scanner->opt[OPT_G_CONTRAST].cap |= SANE_CAP_INACTIVE;
2987141cc406Sopenharmony_ci
2988141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].name = "blue-contrast";
2989141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].title = "Blue contrast";
2990141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].desc = SANE_DESC_CONTRAST;
2991141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].type = SANE_TYPE_INT;
2992141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].unit = SANE_UNIT_NONE;
2993141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
2994141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].constraint.range = &contrast_range;
2995141cc406Sopenharmony_ci  scanner->opt[OPT_B_CONTRAST].cap |= SANE_CAP_INACTIVE;
2996141cc406Sopenharmony_ci
2997141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].name = "exposure";
2998141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].title = "Exposure";
2999141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].desc = "";
3000141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].type = SANE_TYPE_INT;
3001141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3002141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].unit = SANE_UNIT_PERCENT;
3003141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
3004141cc406Sopenharmony_ci  scanner->opt[OPT_EXPOSURE].constraint.range = &exposure_range;
3005141cc406Sopenharmony_ci
3006141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].name = "red-exposure";
3007141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].title = "Red exposure";
3008141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].desc = "";
3009141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].type = SANE_TYPE_INT;
3010141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3011141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].unit = SANE_UNIT_PERCENT;
3012141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
3013141cc406Sopenharmony_ci  scanner->opt[OPT_R_EXPOSURE].constraint.range = &exposure_range;
3014141cc406Sopenharmony_ci
3015141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].name = "green-exposure";
3016141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].title = "Green exposure";
3017141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].desc = "";
3018141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].type = SANE_TYPE_INT;
3019141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].unit = SANE_UNIT_PERCENT;
3020141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
3021141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].constraint.range = &exposure_range;
3022141cc406Sopenharmony_ci  scanner->opt[OPT_G_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3023141cc406Sopenharmony_ci
3024141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].name = "blue-exposure";
3025141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].title = "Blue exposre";
3026141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].desc = "";
3027141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].type = SANE_TYPE_INT;
3028141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].unit = SANE_UNIT_PERCENT;
3029141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
3030141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].constraint.range = &exposure_range;
3031141cc406Sopenharmony_ci  scanner->opt[OPT_B_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3032141cc406Sopenharmony_ci  if(scanner->LS>=2)
3033141cc406Sopenharmony_ci  {  scanner->opt[OPT_R_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3034141cc406Sopenharmony_ci     scanner->opt[OPT_G_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3035141cc406Sopenharmony_ci     scanner->opt[OPT_B_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3036141cc406Sopenharmony_ci     scanner->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3037141cc406Sopenharmony_ci  }
3038141cc406Sopenharmony_ci
3039141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].name = "red-shift";
3040141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].title = "Red shift";
3041141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].desc = "";
3042141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].type = SANE_TYPE_INT;
3043141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].unit = SANE_UNIT_NONE;
3044141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].constraint_type = SANE_CONSTRAINT_RANGE;
3045141cc406Sopenharmony_ci  scanner->opt[OPT_R_SHIFT].constraint.range = &shift_range;
3046141cc406Sopenharmony_ci  if(scanner->LS>=2)
3047141cc406Sopenharmony_ci  {  scanner->opt[OPT_R_SHIFT].cap |= SANE_CAP_INACTIVE;
3048141cc406Sopenharmony_ci  }
3049141cc406Sopenharmony_ci
3050141cc406Sopenharmony_ci
3051141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].name = "green-shift";
3052141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].title = "Green shift";
3053141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].desc = "";
3054141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].type = SANE_TYPE_INT;
3055141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].unit = SANE_UNIT_NONE;
3056141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].constraint_type = SANE_CONSTRAINT_RANGE;
3057141cc406Sopenharmony_ci  scanner->opt[OPT_G_SHIFT].constraint.range = &shift_range;
3058141cc406Sopenharmony_ci  if(scanner->LS>=2)
3059141cc406Sopenharmony_ci  {  scanner->opt[OPT_G_SHIFT].cap |= SANE_CAP_INACTIVE;
3060141cc406Sopenharmony_ci  }
3061141cc406Sopenharmony_ci
3062141cc406Sopenharmony_ci
3063141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].name = "blue-shift";
3064141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].title = "Blue shift";
3065141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].desc = "";
3066141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].type = SANE_TYPE_INT;
3067141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].unit = SANE_UNIT_NONE;
3068141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].constraint_type = SANE_CONSTRAINT_RANGE;
3069141cc406Sopenharmony_ci  scanner->opt[OPT_B_SHIFT].constraint.range = &shift_range;
3070141cc406Sopenharmony_ci  if(scanner->LS>=2)
3071141cc406Sopenharmony_ci  {  scanner->opt[OPT_B_SHIFT].cap |= SANE_CAP_INACTIVE;
3072141cc406Sopenharmony_ci  }
3073141cc406Sopenharmony_ci
3074141cc406Sopenharmony_ci  /* R+G+B gamma vector */
3075141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
3076141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
3077141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
3078141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
3079141cc406Sopenharmony_ci  if (scanner->LS == 1)
3080141cc406Sopenharmony_ci    {
3081141cc406Sopenharmony_ci      scanner->opt[OPT_GAMMA_VECTOR].cap = SANE_CAP_INACTIVE;
3082141cc406Sopenharmony_ci    }
3083141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
3084141cc406Sopenharmony_ci  switch(scanner->LS)
3085141cc406Sopenharmony_ci  {  case 0:
3086141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &gamma_range_8;
3087141cc406Sopenharmony_ci           scanner->lutlength=2048;
3088141cc406Sopenharmony_ci           break;
3089141cc406Sopenharmony_ci     case 1:
3090141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &gamma_range_9;
3091141cc406Sopenharmony_ci           scanner->lutlength=512;
3092141cc406Sopenharmony_ci           break;
3093141cc406Sopenharmony_ci     case 2:
3094141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &gamma_range_10;
3095141cc406Sopenharmony_ci           scanner->lutlength=1024;
3096141cc406Sopenharmony_ci           break;
3097141cc406Sopenharmony_ci     case 3:
3098141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &gamma_range_12;
3099141cc406Sopenharmony_ci           scanner->lutlength=4096;
3100141cc406Sopenharmony_ci           break;
3101141cc406Sopenharmony_ci  }
3102141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].size = scanner->lutlength * sizeof (SANE_Word);
3103141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
3104141cc406Sopenharmony_ci
3105141cc406Sopenharmony_ci  /* red gamma vector */
3106141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
3107141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
3108141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
3109141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
3110141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3111141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
3112141cc406Sopenharmony_ci  switch(scanner->LS)
3113141cc406Sopenharmony_ci  {  case 0:
3114141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range_8;
3115141cc406Sopenharmony_ci           scanner->lutlength=2048;
3116141cc406Sopenharmony_ci           break;
3117141cc406Sopenharmony_ci     case 1:
3118141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range_9;
3119141cc406Sopenharmony_ci           scanner->lutlength=512;
3120141cc406Sopenharmony_ci           break;
3121141cc406Sopenharmony_ci     case 2:
3122141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range_10;
3123141cc406Sopenharmony_ci           scanner->lutlength=1024;
3124141cc406Sopenharmony_ci           break;
3125141cc406Sopenharmony_ci     case 3:
3126141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range_12;
3127141cc406Sopenharmony_ci           scanner->lutlength=4096;
3128141cc406Sopenharmony_ci           break;
3129141cc406Sopenharmony_ci  }
3130141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].size = scanner->lutlength * sizeof (SANE_Word);
3131141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
3132141cc406Sopenharmony_ci
3133141cc406Sopenharmony_ci  /* green gamma vector */
3134141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
3135141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
3136141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
3137141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
3138141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3139141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
3140141cc406Sopenharmony_ci  switch(scanner->LS)
3141141cc406Sopenharmony_ci  {  case 0:
3142141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range_8;
3143141cc406Sopenharmony_ci           scanner->lutlength=2048;
3144141cc406Sopenharmony_ci           break;
3145141cc406Sopenharmony_ci     case 1:
3146141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range_9;
3147141cc406Sopenharmony_ci           scanner->lutlength=512;
3148141cc406Sopenharmony_ci           break;
3149141cc406Sopenharmony_ci     case 2:
3150141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range_10;
3151141cc406Sopenharmony_ci           scanner->lutlength=1024;
3152141cc406Sopenharmony_ci           break;
3153141cc406Sopenharmony_ci     case 3:
3154141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range_12;
3155141cc406Sopenharmony_ci           scanner->lutlength=4096;
3156141cc406Sopenharmony_ci           break;
3157141cc406Sopenharmony_ci  }
3158141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].size = scanner->lutlength * sizeof (SANE_Word);
3159141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
3160141cc406Sopenharmony_ci
3161141cc406Sopenharmony_ci  /* blue gamma vector */
3162141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
3163141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
3164141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
3165141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
3166141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3167141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
3168141cc406Sopenharmony_ci  switch(scanner->LS)
3169141cc406Sopenharmony_ci  {  case 0:
3170141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range_8;
3171141cc406Sopenharmony_ci           scanner->lutlength=2048;
3172141cc406Sopenharmony_ci           break;
3173141cc406Sopenharmony_ci     case 1:
3174141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range_9;
3175141cc406Sopenharmony_ci           scanner->lutlength=512;
3176141cc406Sopenharmony_ci           break;
3177141cc406Sopenharmony_ci     case 2:
3178141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range_10;
3179141cc406Sopenharmony_ci           scanner->lutlength=1024;
3180141cc406Sopenharmony_ci           break;
3181141cc406Sopenharmony_ci     case 3:
3182141cc406Sopenharmony_ci           scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range_12;
3183141cc406Sopenharmony_ci           scanner->lutlength=4096;
3184141cc406Sopenharmony_ci           break;
3185141cc406Sopenharmony_ci  }
3186141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].size = scanner->lutlength * sizeof (SANE_Word);
3187141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
3188141cc406Sopenharmony_ci
3189141cc406Sopenharmony_ci
3190141cc406Sopenharmony_ci  /* ------------------------------ */
3191141cc406Sopenharmony_ci
3192141cc406Sopenharmony_ci  /* "Advanced" group: */
3193141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced";
3194141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].desc = "";
3195141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
3196141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
3197141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
3198141cc406Sopenharmony_ci
3199141cc406Sopenharmony_ci  /* preview */
3200141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
3201141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
3202141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
3203141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
3204141cc406Sopenharmony_ci
3205141cc406Sopenharmony_ci  /* Autofocus */
3206141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].name = "Autofocus";
3207141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].title ="Autofocus";
3208141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].desc = "When to do autofocussing";
3209141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].type = SANE_TYPE_STRING;
3210141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].size = max_string_size (autofocus_mode_list);
3211141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].constraint_type = SANE_CONSTRAINT_STRING_LIST;
3212141cc406Sopenharmony_ci  scanner->opt[OPT_AUTOFOCUS].constraint.string_list = autofocus_mode_list;
3213141cc406Sopenharmony_ci
3214141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].name = "IRED cor. red";
3215141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].title ="IRED cor. red";
3216141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].desc = "Correction of infrared from red";
3217141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].type = SANE_TYPE_INT;
3218141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].unit = SANE_UNIT_NONE;
3219141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].constraint_type = SANE_CONSTRAINT_RANGE;
3220141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].constraint.range = &gamma_range_8;
3221141cc406Sopenharmony_ci  scanner->opt[OPT_IRED_RED].cap |= SANE_CAP_ADVANCED;
3222141cc406Sopenharmony_ci  if(scanner->LS<2)
3223141cc406Sopenharmony_ci  {  scanner->opt[OPT_IRED_RED].cap |= SANE_CAP_INACTIVE;
3224141cc406Sopenharmony_ci  }
3225141cc406Sopenharmony_ci
3226141cc406Sopenharmony_ci
3227141cc406Sopenharmony_ci
3228141cc406Sopenharmony_ci  /*  scanner->opt[OPT_PREVIEW].cap   = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; */
3229141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3230141cc406Sopenharmony_ci}
3231141cc406Sopenharmony_ci
3232141cc406Sopenharmony_ci
3233141cc406Sopenharmony_ciSANE_Status
3234141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
3235141cc406Sopenharmony_ci{
3236141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
3237141cc406Sopenharmony_ci  size_t len;
3238141cc406Sopenharmony_ci  FILE *fp;
3239141cc406Sopenharmony_ci
3240141cc406Sopenharmony_ci  (void) authorize;
3241141cc406Sopenharmony_ci
3242141cc406Sopenharmony_ci  DBG_INIT ();
3243141cc406Sopenharmony_ci  sanei_thread_init ();
3244141cc406Sopenharmony_ci
3245141cc406Sopenharmony_ci  DBG (10, "sane_init\n");
3246141cc406Sopenharmony_ci  if (version_code)
3247141cc406Sopenharmony_ci      *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
3248141cc406Sopenharmony_ci
3249141cc406Sopenharmony_ci  fp = sanei_config_open (COOLSCAN_CONFIG_FILE);
3250141cc406Sopenharmony_ci  if (!fp)
3251141cc406Sopenharmony_ci    {
3252141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0); /* no config-file: /dev/scanner */
3253141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3254141cc406Sopenharmony_ci    }
3255141cc406Sopenharmony_ci
3256141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
3257141cc406Sopenharmony_ci    {
3258141cc406Sopenharmony_ci      if (dev_name[0] == '#')
3259141cc406Sopenharmony_ci	continue;		/* ignore line comments */
3260141cc406Sopenharmony_ci      len = strlen (dev_name);
3261141cc406Sopenharmony_ci
3262141cc406Sopenharmony_ci      if (!len)
3263141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
3264141cc406Sopenharmony_ci
3265141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
3266141cc406Sopenharmony_ci      /*attach_scanner (dev_name, 0);*/
3267141cc406Sopenharmony_ci    }
3268141cc406Sopenharmony_ci  fclose (fp);
3269141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3270141cc406Sopenharmony_ci}
3271141cc406Sopenharmony_ci
3272141cc406Sopenharmony_civoid
3273141cc406Sopenharmony_cisane_exit (void)
3274141cc406Sopenharmony_ci{
3275141cc406Sopenharmony_ci  Coolscan_t *dev, *next;
3276141cc406Sopenharmony_ci
3277141cc406Sopenharmony_ci  DBG (10, "sane_exit\n");
3278141cc406Sopenharmony_ci
3279141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
3280141cc406Sopenharmony_ci    {
3281141cc406Sopenharmony_ci      next = dev->next;
3282141cc406Sopenharmony_ci      free (dev->devicename);
3283141cc406Sopenharmony_ci      free (dev->buffer);
3284141cc406Sopenharmony_ci      free (dev->obuffer);
3285141cc406Sopenharmony_ci      free (dev);
3286141cc406Sopenharmony_ci    }
3287141cc406Sopenharmony_ci
3288141cc406Sopenharmony_ci  if (devlist)
3289141cc406Sopenharmony_ci    free (devlist);
3290141cc406Sopenharmony_ci}
3291141cc406Sopenharmony_ci
3292141cc406Sopenharmony_ci/* ----------------------------- SANE GET DEVICES -------------------------- */
3293141cc406Sopenharmony_ciSANE_Status
3294141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list,
3295141cc406Sopenharmony_ci		  SANE_Bool local_only)
3296141cc406Sopenharmony_ci{
3297141cc406Sopenharmony_ci  Coolscan_t *dev;
3298141cc406Sopenharmony_ci  int i;
3299141cc406Sopenharmony_ci
3300141cc406Sopenharmony_ci  (void) local_only;
3301141cc406Sopenharmony_ci
3302141cc406Sopenharmony_ci  DBG (10, "sane_get_devices\n");
3303141cc406Sopenharmony_ci
3304141cc406Sopenharmony_ci  if (devlist)
3305141cc406Sopenharmony_ci    free (devlist);
3306141cc406Sopenharmony_ci
3307141cc406Sopenharmony_ci  devlist = calloc (num_devices + 1, sizeof (devlist[0]));
3308141cc406Sopenharmony_ci  if (!devlist)
3309141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
3310141cc406Sopenharmony_ci
3311141cc406Sopenharmony_ci  i = 0;
3312141cc406Sopenharmony_ci
3313141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
3314141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
3315141cc406Sopenharmony_ci
3316141cc406Sopenharmony_ci  devlist[i++] = 0;
3317141cc406Sopenharmony_ci
3318141cc406Sopenharmony_ci  *device_list = devlist;
3319141cc406Sopenharmony_ci
3320141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3321141cc406Sopenharmony_ci}
3322141cc406Sopenharmony_ci
3323141cc406Sopenharmony_ciSANE_Status
3324141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
3325141cc406Sopenharmony_ci{
3326141cc406Sopenharmony_ci  Coolscan_t *dev;
3327141cc406Sopenharmony_ci  SANE_Status status;
3328141cc406Sopenharmony_ci
3329141cc406Sopenharmony_ci  DBG (10, "sane_open\n");
3330141cc406Sopenharmony_ci
3331141cc406Sopenharmony_ci  if (devicename[0])
3332141cc406Sopenharmony_ci    {				/* search for devicename */
3333141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
3334141cc406Sopenharmony_ci	{
3335141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devicename) == 0)
3336141cc406Sopenharmony_ci	    {
3337141cc406Sopenharmony_ci	      break;
3338141cc406Sopenharmony_ci	    }
3339141cc406Sopenharmony_ci	}
3340141cc406Sopenharmony_ci
3341141cc406Sopenharmony_ci      if (!dev)
3342141cc406Sopenharmony_ci	{
3343141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
3344141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
3345141cc406Sopenharmony_ci	    {
3346141cc406Sopenharmony_ci	      return status;
3347141cc406Sopenharmony_ci	    }
3348141cc406Sopenharmony_ci	}
3349141cc406Sopenharmony_ci    }
3350141cc406Sopenharmony_ci  else
3351141cc406Sopenharmony_ci    {
3352141cc406Sopenharmony_ci      dev = first_dev;		/* empty devicname -> use first device */
3353141cc406Sopenharmony_ci    }
3354141cc406Sopenharmony_ci
3355141cc406Sopenharmony_ci  if (!dev)
3356141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3357141cc406Sopenharmony_ci
3358141cc406Sopenharmony_ci  dev->sfd = -1;
3359141cc406Sopenharmony_ci  dev->pipe = -1;
3360141cc406Sopenharmony_ci  dev->scanning = SANE_FALSE;
3361141cc406Sopenharmony_ci
3362141cc406Sopenharmony_ci  init_options (dev);
3363141cc406Sopenharmony_ci  *handle = dev;
3364141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3365141cc406Sopenharmony_ci}
3366141cc406Sopenharmony_ci
3367141cc406Sopenharmony_civoid
3368141cc406Sopenharmony_cisane_close (SANE_Handle handle)
3369141cc406Sopenharmony_ci{
3370141cc406Sopenharmony_ci  DBG (10, "sane_close\n");
3371141cc406Sopenharmony_ci  if (((Coolscan_t *) handle)->scanning)
3372141cc406Sopenharmony_ci    do_cancel (handle);
3373141cc406Sopenharmony_ci}
3374141cc406Sopenharmony_ci
3375141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3376141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
3377141cc406Sopenharmony_ci{
3378141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
3379141cc406Sopenharmony_ci
3380141cc406Sopenharmony_ci  DBG (10, "sane_get_option_descriptor %d\n", option);
3381141cc406Sopenharmony_ci
3382141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
3383141cc406Sopenharmony_ci    return 0;
3384141cc406Sopenharmony_ci  return &scanner->opt[option];
3385141cc406Sopenharmony_ci}
3386141cc406Sopenharmony_ci
3387141cc406Sopenharmony_ci/*
3388141cc406Sopenharmony_ci   static void
3389141cc406Sopenharmony_ci   worddump(char *comment, SANE_Word * p, int l)
3390141cc406Sopenharmony_ci   {
3391141cc406Sopenharmony_ci   int i;
3392141cc406Sopenharmony_ci   char line[128];
3393141cc406Sopenharmony_ci   char *ptr;
3394141cc406Sopenharmony_ci
3395141cc406Sopenharmony_ci   DBG (5, "%s\n", comment);
3396141cc406Sopenharmony_ci   ptr = line;
3397141cc406Sopenharmony_ci   for (i = 0; i < l; i++, p++)
3398141cc406Sopenharmony_ci   {
3399141cc406Sopenharmony_ci   if ((i % 8) == 0)
3400141cc406Sopenharmony_ci   {
3401141cc406Sopenharmony_ci   if (ptr != line)
3402141cc406Sopenharmony_ci   {
3403141cc406Sopenharmony_ci   *ptr = '\0';
3404141cc406Sopenharmony_ci   DBG (5, "%s\n", line);
3405141cc406Sopenharmony_ci   ptr = line;
3406141cc406Sopenharmony_ci   }
3407141cc406Sopenharmony_ci   sprintf (ptr, "%3.3d:", i);
3408141cc406Sopenharmony_ci   ptr += 4;
3409141cc406Sopenharmony_ci   }
3410141cc406Sopenharmony_ci   sprintf (ptr, " %4.4d", *p);
3411141cc406Sopenharmony_ci   ptr += 5;
3412141cc406Sopenharmony_ci   }
3413141cc406Sopenharmony_ci   *ptr = '\0';
3414141cc406Sopenharmony_ci   DBG (5, "%s\n", line);
3415141cc406Sopenharmony_ci   }
3416141cc406Sopenharmony_ci */
3417141cc406Sopenharmony_ciSANE_Status
3418141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
3419141cc406Sopenharmony_ci		     SANE_Action action, void *val,
3420141cc406Sopenharmony_ci		     SANE_Int * info)
3421141cc406Sopenharmony_ci{
3422141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
3423141cc406Sopenharmony_ci  SANE_Status status;
3424141cc406Sopenharmony_ci  SANE_Word cap;
3425141cc406Sopenharmony_ci
3426141cc406Sopenharmony_ci  if (info)
3427141cc406Sopenharmony_ci    *info = 0;
3428141cc406Sopenharmony_ci
3429141cc406Sopenharmony_ci  if (scanner->scanning)
3430141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
3431141cc406Sopenharmony_ci
3432141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
3433141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3434141cc406Sopenharmony_ci
3435141cc406Sopenharmony_ci  cap = scanner->opt[option].cap;
3436141cc406Sopenharmony_ci
3437141cc406Sopenharmony_ci
3438141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
3439141cc406Sopenharmony_ci    {
3440141cc406Sopenharmony_ci      DBG (10, "sane_control_option %d, get value\n", option);
3441141cc406Sopenharmony_ci      switch (option)
3442141cc406Sopenharmony_ci	{
3443141cc406Sopenharmony_ci	  /* word options: */
3444141cc406Sopenharmony_ci	case OPT_TL_X:
3445141cc406Sopenharmony_ci	  *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tlx));
3446141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3447141cc406Sopenharmony_ci
3448141cc406Sopenharmony_ci	case OPT_TL_Y:
3449141cc406Sopenharmony_ci	  *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->tly));
3450141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3451141cc406Sopenharmony_ci
3452141cc406Sopenharmony_ci	case OPT_BR_X:
3453141cc406Sopenharmony_ci	  *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->brx));
3454141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3455141cc406Sopenharmony_ci
3456141cc406Sopenharmony_ci	case OPT_BR_Y:
3457141cc406Sopenharmony_ci	  *(SANE_Word *) val = SANE_FIX (iluToMm (scanner->bry));
3458141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3459141cc406Sopenharmony_ci
3460141cc406Sopenharmony_ci	case OPT_PREVIEW:
3461141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->preview;
3462141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3463141cc406Sopenharmony_ci
3464141cc406Sopenharmony_ci	case OPT_AUTOFOCUS:
3465141cc406Sopenharmony_ci	  switch(scanner->autofocus)
3466141cc406Sopenharmony_ci	    {  case AF_NEVER: strcpy (val,neverStr);
3467141cc406Sopenharmony_ci  	                 break;
3468141cc406Sopenharmony_ci	       case AF_PREVIEW:strcpy (val,previewStr);
3469141cc406Sopenharmony_ci  	                 break;
3470141cc406Sopenharmony_ci               case AF_SCAN:if(scanner->LS>=2) strcpy (val,scanStr);
3471141cc406Sopenharmony_ci  	                 break;
3472141cc406Sopenharmony_ci	       case AF_PREANDSCAN:if(scanner->LS>=2) strcpy (val,preandscanStr);
3473141cc406Sopenharmony_ci  	                 break;
3474141cc406Sopenharmony_ci	    }
3475141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3476141cc406Sopenharmony_ci
3477141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3478141cc406Sopenharmony_ci	  *(SANE_Word *) val = NUM_OPTIONS;
3479141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3480141cc406Sopenharmony_ci
3481141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3482141cc406Sopenharmony_ci	  *(SANE_Word *) val = resDivToVal (scanner->x_nres);
3483141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3484141cc406Sopenharmony_ci
3485141cc406Sopenharmony_ci	case OPT_PREVIEW_RESOLUTION:
3486141cc406Sopenharmony_ci	  *(SANE_Word *) val = resDivToVal (scanner->x_p_nres);
3487141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3488141cc406Sopenharmony_ci
3489141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
3490141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->bits_per_color;
3491141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3492141cc406Sopenharmony_ci
3493141cc406Sopenharmony_ci	case OPT_CONTRAST:
3494141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->contrast - 128;
3495141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3496141cc406Sopenharmony_ci
3497141cc406Sopenharmony_ci	case OPT_R_CONTRAST:
3498141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->contrast_R - 128;
3499141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3500141cc406Sopenharmony_ci
3501141cc406Sopenharmony_ci	case OPT_G_CONTRAST:
3502141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->contrast_G - 128;
3503141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3504141cc406Sopenharmony_ci
3505141cc406Sopenharmony_ci	case OPT_B_CONTRAST:
3506141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->contrast_B - 128;
3507141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3508141cc406Sopenharmony_ci
3509141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
3510141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->brightness - 128;
3511141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3512141cc406Sopenharmony_ci
3513141cc406Sopenharmony_ci	case OPT_R_BRIGHTNESS:
3514141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->brightness_R - 128;
3515141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3516141cc406Sopenharmony_ci
3517141cc406Sopenharmony_ci	case OPT_G_BRIGHTNESS:
3518141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->brightness_G - 128;
3519141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3520141cc406Sopenharmony_ci
3521141cc406Sopenharmony_ci	case OPT_B_BRIGHTNESS:
3522141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->brightness_B - 128;
3523141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3524141cc406Sopenharmony_ci
3525141cc406Sopenharmony_ci	case OPT_EXPOSURE:
3526141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->exposure_R * 2;
3527141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3528141cc406Sopenharmony_ci
3529141cc406Sopenharmony_ci	case OPT_R_EXPOSURE:
3530141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->exposure_R * 2;
3531141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3532141cc406Sopenharmony_ci
3533141cc406Sopenharmony_ci	case OPT_G_EXPOSURE:
3534141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->exposure_G * 2;
3535141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3536141cc406Sopenharmony_ci
3537141cc406Sopenharmony_ci	case OPT_B_EXPOSURE:
3538141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->exposure_B * 2;
3539141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3540141cc406Sopenharmony_ci
3541141cc406Sopenharmony_ci	case OPT_R_SHIFT:
3542141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->shift_R - 128;
3543141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3544141cc406Sopenharmony_ci
3545141cc406Sopenharmony_ci	case OPT_G_SHIFT:
3546141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->shift_G - 128;
3547141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3548141cc406Sopenharmony_ci
3549141cc406Sopenharmony_ci	case OPT_B_SHIFT:
3550141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->shift_B - 128;
3551141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3552141cc406Sopenharmony_ci
3553141cc406Sopenharmony_ci
3554141cc406Sopenharmony_ci	case OPT_IRED_RED:
3555141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->ired_red;
3556141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3557141cc406Sopenharmony_ci
3558141cc406Sopenharmony_ci	  /* string options: */
3559141cc406Sopenharmony_ci	case OPT_TYPE:
3560141cc406Sopenharmony_ci	  strcpy (val, ((scanner->negative) ? negativeStr : positiveStr));
3561141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3562141cc406Sopenharmony_ci
3563141cc406Sopenharmony_ci	case OPT_MODE:
3564141cc406Sopenharmony_ci	  switch(scanner->colormode)
3565141cc406Sopenharmony_ci	    {  case RGB: strcpy (val,colorStr);
3566141cc406Sopenharmony_ci  	                 break;
3567141cc406Sopenharmony_ci	       case GREYSCALE:strcpy (val,grayStr);
3568141cc406Sopenharmony_ci  	                 break;
3569141cc406Sopenharmony_ci               case RGBI:if(scanner->LS>=2) strcpy (val,rgbiStr);
3570141cc406Sopenharmony_ci		         else strcpy (val,colorStr);
3571141cc406Sopenharmony_ci  	                 break;
3572141cc406Sopenharmony_ci	       case IRED:if(scanner->LS>=2) strcpy (val,iredStr);
3573141cc406Sopenharmony_ci	                 else strcpy (val,grayStr);
3574141cc406Sopenharmony_ci  	                 break;
3575141cc406Sopenharmony_ci	    }
3576141cc406Sopenharmony_ci 	    if (info)
3577141cc406Sopenharmony_ci	    {
3578141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
3579141cc406Sopenharmony_ci	    }
3580141cc406Sopenharmony_ci
3581141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3582141cc406Sopenharmony_ci
3583141cc406Sopenharmony_ci	case OPT_PRESCAN:
3584141cc406Sopenharmony_ci	  *(SANE_Word *) val = (scanner->prescan) ? SANE_TRUE : SANE_FALSE;
3585141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3586141cc406Sopenharmony_ci
3587141cc406Sopenharmony_ci	case OPT_PRESCAN_NOW:
3588141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3589141cc406Sopenharmony_ci
3590141cc406Sopenharmony_ci	case OPT_RGB_CONTROL:
3591141cc406Sopenharmony_ci	  *(SANE_Word *) val = (scanner->rgb_control) ? SANE_TRUE : SANE_FALSE;
3592141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3593141cc406Sopenharmony_ci
3594141cc406Sopenharmony_ci	case OPT_GAMMA_BIND:
3595141cc406Sopenharmony_ci	  *(SANE_Word *) val = (scanner->gamma_bind) ? SANE_TRUE : SANE_FALSE;
3596141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3597141cc406Sopenharmony_ci
3598141cc406Sopenharmony_ci	case OPT_ANALOG_GAMMA:
3599141cc406Sopenharmony_ci	  *(SANE_Word *) val =
3600141cc406Sopenharmony_ci	    (scanner->analog_gamma_r) ? SANE_TRUE : SANE_FALSE;
3601141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3602141cc406Sopenharmony_ci
3603141cc406Sopenharmony_ci	case OPT_AVERAGING:
3604141cc406Sopenharmony_ci	  *(SANE_Word *) val = (scanner->averaging) ? SANE_TRUE : SANE_FALSE;
3605141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3606141cc406Sopenharmony_ci
3607141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
3608141cc406Sopenharmony_ci	  memcpy (val, scanner->gamma, scanner->opt[option].size);
3609141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3610141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
3611141cc406Sopenharmony_ci	  memcpy (val, scanner->gamma_r, scanner->opt[option].size);
3612141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3613141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
3614141cc406Sopenharmony_ci	  memcpy (val, scanner->gamma_g, scanner->opt[option].size);
3615141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3616141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
3617141cc406Sopenharmony_ci	  memcpy (val, scanner->gamma_b, scanner->opt[option].size);
3618141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3619141cc406Sopenharmony_ci
3620141cc406Sopenharmony_ci	case OPT_SOURCE:
3621141cc406Sopenharmony_ci	  if (strcmp (val, "Automatic Slide Feeder") == 0)
3622141cc406Sopenharmony_ci	    {
3623141cc406Sopenharmony_ci	      /* Feed/Discharge/update filename/etc */
3624141cc406Sopenharmony_ci	    }
3625141cc406Sopenharmony_ci	  else
3626141cc406Sopenharmony_ci	    {
3627141cc406Sopenharmony_ci	      /* Reset above */
3628141cc406Sopenharmony_ci	    }
3629141cc406Sopenharmony_ci	  if (info)
3630141cc406Sopenharmony_ci	    {
3631141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
3632141cc406Sopenharmony_ci	    }
3633141cc406Sopenharmony_ci	}
3634141cc406Sopenharmony_ci
3635141cc406Sopenharmony_ci    }
3636141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
3637141cc406Sopenharmony_ci    {
3638141cc406Sopenharmony_ci      DBG (10, "sane_control_option %d, set value\n", option);
3639141cc406Sopenharmony_ci
3640141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_ACTIVE (cap))
3641141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
3642141cc406Sopenharmony_ci
3643141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
3644141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
3645141cc406Sopenharmony_ci
3646141cc406Sopenharmony_ci      status = sanei_constrain_value (scanner->opt + option, val, info);
3647141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3648141cc406Sopenharmony_ci	return status;
3649141cc406Sopenharmony_ci
3650141cc406Sopenharmony_ci      switch (option)
3651141cc406Sopenharmony_ci	{
3652141cc406Sopenharmony_ci	case OPT_GAMMA_BIND:
3653141cc406Sopenharmony_ci	  scanner->gamma_bind = (*(SANE_Word *) val == SANE_TRUE);
3654141cc406Sopenharmony_ci	  if (scanner->LS != 1)
3655141cc406Sopenharmony_ci	    {
3656141cc406Sopenharmony_ci	      if (scanner->gamma_bind)
3657141cc406Sopenharmony_ci		{
3658141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
3659141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3660141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3661141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3662141cc406Sopenharmony_ci
3663141cc406Sopenharmony_ci		}
3664141cc406Sopenharmony_ci	      else
3665141cc406Sopenharmony_ci		{
3666141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
3667141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
3668141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
3669141cc406Sopenharmony_ci		  scanner->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
3670141cc406Sopenharmony_ci
3671141cc406Sopenharmony_ci		}
3672141cc406Sopenharmony_ci	    }
3673141cc406Sopenharmony_ci	  if (info)
3674141cc406Sopenharmony_ci	    {
3675141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS;
3676141cc406Sopenharmony_ci	    }
3677141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3678141cc406Sopenharmony_ci
3679141cc406Sopenharmony_ci	case OPT_ANALOG_GAMMA:
3680141cc406Sopenharmony_ci	  scanner->analog_gamma_r = scanner->analog_gamma_g =
3681141cc406Sopenharmony_ci	    scanner->analog_gamma_b = (*(SANE_Word *) val == SANE_TRUE);
3682141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3683141cc406Sopenharmony_ci
3684141cc406Sopenharmony_ci	case OPT_AVERAGING:
3685141cc406Sopenharmony_ci	  scanner->averaging = (*(SANE_Word *) val == SANE_TRUE);
3686141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3687141cc406Sopenharmony_ci
3688141cc406Sopenharmony_ci	case OPT_PRESCAN:
3689141cc406Sopenharmony_ci	  scanner->prescan = (*(SANE_Word *) val == SANE_TRUE);
3690141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3691141cc406Sopenharmony_ci
3692141cc406Sopenharmony_ci	case OPT_PRESCAN_NOW:
3693141cc406Sopenharmony_ci	   do_prescan_now(scanner);
3694141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3695141cc406Sopenharmony_ci
3696141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
3697141cc406Sopenharmony_ci	   scanner->bits_per_color=(*(SANE_Word *)val);
3698141cc406Sopenharmony_ci 	  if (info)
3699141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3700141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3701141cc406Sopenharmony_ci
3702141cc406Sopenharmony_ci
3703141cc406Sopenharmony_ci	case OPT_RGB_CONTROL:
3704141cc406Sopenharmony_ci	  scanner->rgb_control = (*(SANE_Word *) val == SANE_TRUE);
3705141cc406Sopenharmony_ci	  if (scanner->rgb_control)
3706141cc406Sopenharmony_ci	    {
3707141cc406Sopenharmony_ci	      scanner->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
3708141cc406Sopenharmony_ci	      scanner->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
3709141cc406Sopenharmony_ci	      scanner->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3710141cc406Sopenharmony_ci
3711141cc406Sopenharmony_ci	      scanner->opt[OPT_R_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
3712141cc406Sopenharmony_ci	      scanner->opt[OPT_G_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
3713141cc406Sopenharmony_ci	      scanner->opt[OPT_B_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
3714141cc406Sopenharmony_ci
3715141cc406Sopenharmony_ci	      scanner->opt[OPT_R_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
3716141cc406Sopenharmony_ci	      scanner->opt[OPT_G_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
3717141cc406Sopenharmony_ci	      scanner->opt[OPT_B_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
3718141cc406Sopenharmony_ci
3719141cc406Sopenharmony_ci	      scanner->opt[OPT_R_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3720141cc406Sopenharmony_ci	      scanner->opt[OPT_G_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3721141cc406Sopenharmony_ci	      scanner->opt[OPT_B_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3722141cc406Sopenharmony_ci
3723141cc406Sopenharmony_ci	      scanner->contrast_R = 128;
3724141cc406Sopenharmony_ci	      scanner->contrast_G = 128;
3725141cc406Sopenharmony_ci	      scanner->contrast_B = 128;
3726141cc406Sopenharmony_ci	      scanner->brightness_R = 128;
3727141cc406Sopenharmony_ci	      scanner->brightness_G = 128;
3728141cc406Sopenharmony_ci	      scanner->brightness_B = 128;
3729141cc406Sopenharmony_ci	      scanner->exposure_R = 50;
3730141cc406Sopenharmony_ci	      scanner->exposure_G = 50;
3731141cc406Sopenharmony_ci	      scanner->exposure_B = 50;
3732141cc406Sopenharmony_ci	    }
3733141cc406Sopenharmony_ci	  else
3734141cc406Sopenharmony_ci	    {
3735141cc406Sopenharmony_ci	      scanner->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
3736141cc406Sopenharmony_ci	      scanner->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
3737141cc406Sopenharmony_ci	      scanner->opt[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3738141cc406Sopenharmony_ci
3739141cc406Sopenharmony_ci	      scanner->contrast = 128;
3740141cc406Sopenharmony_ci	      scanner->brightness = 128;
3741141cc406Sopenharmony_ci	      scanner->exposure_R = 50;
3742141cc406Sopenharmony_ci	      scanner->exposure_G = 50;
3743141cc406Sopenharmony_ci	      scanner->exposure_B = 50;
3744141cc406Sopenharmony_ci
3745141cc406Sopenharmony_ci	      scanner->opt[OPT_R_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
3746141cc406Sopenharmony_ci	      scanner->opt[OPT_G_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
3747141cc406Sopenharmony_ci	      scanner->opt[OPT_B_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
3748141cc406Sopenharmony_ci
3749141cc406Sopenharmony_ci	      scanner->opt[OPT_R_CONTRAST].cap |= SANE_CAP_INACTIVE;
3750141cc406Sopenharmony_ci	      scanner->opt[OPT_G_CONTRAST].cap |= SANE_CAP_INACTIVE;
3751141cc406Sopenharmony_ci	      scanner->opt[OPT_B_CONTRAST].cap |= SANE_CAP_INACTIVE;
3752141cc406Sopenharmony_ci
3753141cc406Sopenharmony_ci	      scanner->opt[OPT_R_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3754141cc406Sopenharmony_ci	      scanner->opt[OPT_G_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3755141cc406Sopenharmony_ci	      scanner->opt[OPT_B_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3756141cc406Sopenharmony_ci	    }
3757141cc406Sopenharmony_ci	  if (info)
3758141cc406Sopenharmony_ci	    {
3759141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS;
3760141cc406Sopenharmony_ci	    }
3761141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3762141cc406Sopenharmony_ci
3763141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3764141cc406Sopenharmony_ci	  scanner->y_nres = scanner->x_nres =
3765141cc406Sopenharmony_ci	    resValToDiv (*(SANE_Word *) val);
3766141cc406Sopenharmony_ci
3767141cc406Sopenharmony_ci	  if (info)
3768141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3769141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3770141cc406Sopenharmony_ci
3771141cc406Sopenharmony_ci	case OPT_PREVIEW_RESOLUTION:
3772141cc406Sopenharmony_ci	  scanner->y_p_nres = scanner->x_p_nres =
3773141cc406Sopenharmony_ci	    resValToDiv (*(SANE_Word *) val);
3774141cc406Sopenharmony_ci
3775141cc406Sopenharmony_ci	  if (info)
3776141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3777141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3778141cc406Sopenharmony_ci
3779141cc406Sopenharmony_ci	case OPT_TL_X:
3780141cc406Sopenharmony_ci	  scanner->tlx = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
3781141cc406Sopenharmony_ci	  if (info)
3782141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3783141cc406Sopenharmony_ci
3784141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3785141cc406Sopenharmony_ci
3786141cc406Sopenharmony_ci	case OPT_TL_Y:
3787141cc406Sopenharmony_ci	  scanner->tly = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
3788141cc406Sopenharmony_ci	  if (info)
3789141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3790141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3791141cc406Sopenharmony_ci
3792141cc406Sopenharmony_ci	case OPT_BR_X:
3793141cc406Sopenharmony_ci	  scanner->brx = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
3794141cc406Sopenharmony_ci	  if (info)
3795141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3796141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3797141cc406Sopenharmony_ci
3798141cc406Sopenharmony_ci	case OPT_BR_Y:
3799141cc406Sopenharmony_ci	  scanner->bry = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
3800141cc406Sopenharmony_ci	  if (info)
3801141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
3802141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3803141cc406Sopenharmony_ci
3804141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3805141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3806141cc406Sopenharmony_ci
3807141cc406Sopenharmony_ci	case OPT_PREVIEW:
3808141cc406Sopenharmony_ci	  scanner->preview = *(SANE_Word *) val;
3809141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3810141cc406Sopenharmony_ci
3811141cc406Sopenharmony_ci	case OPT_AUTOFOCUS:
3812141cc406Sopenharmony_ci	  if(strcmp(val,neverStr)==0)
3813141cc406Sopenharmony_ci	    {    scanner->autofocus=AF_NEVER;
3814141cc406Sopenharmony_ci	    }
3815141cc406Sopenharmony_ci	  if(strcmp(val,previewStr)==0)
3816141cc406Sopenharmony_ci	    {    scanner->autofocus=AF_PREVIEW;
3817141cc406Sopenharmony_ci	    }
3818141cc406Sopenharmony_ci	  if(strcmp(val,scanStr)==0)
3819141cc406Sopenharmony_ci	    {    scanner->autofocus=AF_SCAN;
3820141cc406Sopenharmony_ci	    }
3821141cc406Sopenharmony_ci	  if(strcmp(val,preandscanStr)==0)
3822141cc406Sopenharmony_ci	    {    scanner->autofocus=AF_PREANDSCAN;;
3823141cc406Sopenharmony_ci	    }
3824141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3825141cc406Sopenharmony_ci
3826141cc406Sopenharmony_ci	case OPT_CONTRAST:
3827141cc406Sopenharmony_ci	  scanner->contrast = *(SANE_Word *) val + 128;
3828141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3829141cc406Sopenharmony_ci	case OPT_R_CONTRAST:
3830141cc406Sopenharmony_ci	  scanner->contrast_R = *(SANE_Word *) val + 128;
3831141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3832141cc406Sopenharmony_ci	case OPT_G_CONTRAST:
3833141cc406Sopenharmony_ci	  scanner->contrast_G = *(SANE_Word *) val + 128;
3834141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3835141cc406Sopenharmony_ci	case OPT_B_CONTRAST:
3836141cc406Sopenharmony_ci	  scanner->contrast_B = *(SANE_Word *) val + 128;
3837141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3838141cc406Sopenharmony_ci
3839141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
3840141cc406Sopenharmony_ci	  scanner->brightness = *(SANE_Word *) val + 128;
3841141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3842141cc406Sopenharmony_ci	case OPT_R_BRIGHTNESS:
3843141cc406Sopenharmony_ci	  scanner->brightness_R = *(SANE_Word *) val + 128;
3844141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3845141cc406Sopenharmony_ci	case OPT_G_BRIGHTNESS:
3846141cc406Sopenharmony_ci	  scanner->brightness_G = *(SANE_Word *) val + 128;
3847141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3848141cc406Sopenharmony_ci	case OPT_B_BRIGHTNESS:
3849141cc406Sopenharmony_ci	  scanner->brightness_B = *(SANE_Word *) val + 128;
3850141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3851141cc406Sopenharmony_ci
3852141cc406Sopenharmony_ci	case OPT_EXPOSURE:
3853141cc406Sopenharmony_ci	  scanner->exposure_R = *(SANE_Word *) val / 2;
3854141cc406Sopenharmony_ci	  scanner->exposure_G = *(SANE_Word *) val / 2;
3855141cc406Sopenharmony_ci	  scanner->exposure_B = *(SANE_Word *) val / 2;
3856141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3857141cc406Sopenharmony_ci	case OPT_R_EXPOSURE:
3858141cc406Sopenharmony_ci	  scanner->exposure_R = *(SANE_Word *) val / 2;
3859141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3860141cc406Sopenharmony_ci	case OPT_G_EXPOSURE:
3861141cc406Sopenharmony_ci	  scanner->exposure_G = *(SANE_Word *) val / 2;
3862141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3863141cc406Sopenharmony_ci	case OPT_B_EXPOSURE:
3864141cc406Sopenharmony_ci	  scanner->exposure_B = *(SANE_Word *) val / 2;
3865141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3866141cc406Sopenharmony_ci
3867141cc406Sopenharmony_ci	case OPT_R_SHIFT:
3868141cc406Sopenharmony_ci	  scanner->shift_R = *(SANE_Word *) val + 128;
3869141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3870141cc406Sopenharmony_ci	case OPT_G_SHIFT:
3871141cc406Sopenharmony_ci	  scanner->shift_G = *(SANE_Word *) val + 128;
3872141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3873141cc406Sopenharmony_ci	case OPT_B_SHIFT:
3874141cc406Sopenharmony_ci	  scanner->shift_B = *(SANE_Word *) val + 128;
3875141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3876141cc406Sopenharmony_ci
3877141cc406Sopenharmony_ci	case OPT_IRED_RED:
3878141cc406Sopenharmony_ci	  scanner->ired_red= *(SANE_Word *) val;
3879141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3880141cc406Sopenharmony_ci
3881141cc406Sopenharmony_ci	case OPT_SOURCE:
3882141cc406Sopenharmony_ci	  scanner->asf = (strcmp (val, "Automatic...") == 0);
3883141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3884141cc406Sopenharmony_ci
3885141cc406Sopenharmony_ci	case OPT_TYPE:
3886141cc406Sopenharmony_ci	  scanner->negative = (strcmp (val, negativeStr) == 0);
3887141cc406Sopenharmony_ci	  if (info)
3888141cc406Sopenharmony_ci	    {
3889141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
3890141cc406Sopenharmony_ci	    }
3891141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3892141cc406Sopenharmony_ci	case OPT_MODE:
3893141cc406Sopenharmony_ci	  if(strcmp(val,colorStr)==0)
3894141cc406Sopenharmony_ci	    {    scanner->colormode=RGB;
3895141cc406Sopenharmony_ci	         scanner->colormode_p=RGB;
3896141cc406Sopenharmony_ci	    }
3897141cc406Sopenharmony_ci	  if(strcmp(val,grayStr)==0)
3898141cc406Sopenharmony_ci	    {    scanner->colormode=GREYSCALE;
3899141cc406Sopenharmony_ci	         scanner->colormode_p=GREYSCALE;
3900141cc406Sopenharmony_ci	    }
3901141cc406Sopenharmony_ci	  if(strcmp(val,rgbiStr)==0)
3902141cc406Sopenharmony_ci	    {    scanner->colormode=RGBI;
3903141cc406Sopenharmony_ci	         scanner->colormode_p=RGB;
3904141cc406Sopenharmony_ci	    }
3905141cc406Sopenharmony_ci	  if(strcmp(val,iredStr)==0)
3906141cc406Sopenharmony_ci	    {    scanner->colormode=IRED;
3907141cc406Sopenharmony_ci	         scanner->colormode_p=GREYSCALE;
3908141cc406Sopenharmony_ci	    }
3909141cc406Sopenharmony_ci	  if (info)
3910141cc406Sopenharmony_ci	    {
3911141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
3912141cc406Sopenharmony_ci	    }
3913141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3914141cc406Sopenharmony_ci
3915141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
3916141cc406Sopenharmony_ci	  memcpy (scanner->gamma, val, scanner->opt[option].size);
3917141cc406Sopenharmony_ci	  if(scanner->LS>2)  Calc_fix_LUT(scanner);
3918141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3919141cc406Sopenharmony_ci
3920141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
3921141cc406Sopenharmony_ci	  memcpy (scanner->gamma_r, val, scanner->opt[option].size);
3922141cc406Sopenharmony_ci	  if(scanner->LS>2)  Calc_fix_LUT(scanner);
3923141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3924141cc406Sopenharmony_ci
3925141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
3926141cc406Sopenharmony_ci	  memcpy (scanner->gamma_g, val, scanner->opt[option].size);
3927141cc406Sopenharmony_ci	  if(scanner->LS>2)  Calc_fix_LUT(scanner);
3928141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3929141cc406Sopenharmony_ci
3930141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
3931141cc406Sopenharmony_ci	  memcpy (scanner->gamma_b, val, scanner->opt[option].size);
3932141cc406Sopenharmony_ci	  if(scanner->LS>2)  Calc_fix_LUT(scanner);
3933141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3934141cc406Sopenharmony_ci
3935141cc406Sopenharmony_ci	}			/* switch */
3936141cc406Sopenharmony_ci    }				/* else */
3937141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
3938141cc406Sopenharmony_ci}
3939141cc406Sopenharmony_ci
3940141cc406Sopenharmony_ciSANE_Status
3941141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
3942141cc406Sopenharmony_ci{
3943141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
3944141cc406Sopenharmony_ci
3945141cc406Sopenharmony_ci  DBG (10, "sane_get_parameters");
3946141cc406Sopenharmony_ci  switch(scanner->colormode)
3947141cc406Sopenharmony_ci    {  case RGB:
3948141cc406Sopenharmony_ci              params->format =  SANE_FRAME_RGB;
3949141cc406Sopenharmony_ci              break;
3950141cc406Sopenharmony_ci#ifdef HAS_IRED
3951141cc406Sopenharmony_ci       case RGBI:
3952141cc406Sopenharmony_ci              params->format =  SANE_FRAME_RGBA;
3953141cc406Sopenharmony_ci              break;
3954141cc406Sopenharmony_ci#endif /* HAS_RGBI */
3955141cc406Sopenharmony_ci       case GREYSCALE:
3956141cc406Sopenharmony_ci              params->format =  SANE_FRAME_GRAY;
3957141cc406Sopenharmony_ci              break;
3958141cc406Sopenharmony_ci    }
3959141cc406Sopenharmony_ci
3960141cc406Sopenharmony_ci  params->depth = scanner->bits_per_color>8?16:8;
3961141cc406Sopenharmony_ci  params->pixels_per_line = pixels_per_line (scanner);
3962141cc406Sopenharmony_ci  params->lines = lines_per_scan (scanner);
3963141cc406Sopenharmony_ci  params->bytes_per_line = write_bytes_per_line (scanner);
3964141cc406Sopenharmony_ci  params->last_frame = 1;
3965141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3966141cc406Sopenharmony_ci}
3967141cc406Sopenharmony_cistatic int
3968141cc406Sopenharmony_ciswap_res (Coolscan_t * s)
3969141cc406Sopenharmony_ci{
3970141cc406Sopenharmony_ci  if (s->preview)
3971141cc406Sopenharmony_ci    {
3972141cc406Sopenharmony_ci      /* swap preview/scan resolutions */
3973141cc406Sopenharmony_ci      int xres, yres, cmode;
3974141cc406Sopenharmony_ci      xres = s->x_nres;
3975141cc406Sopenharmony_ci      yres = s->y_nres;
3976141cc406Sopenharmony_ci      s->x_nres = s->x_p_nres;
3977141cc406Sopenharmony_ci      s->y_nres = s->y_p_nres;
3978141cc406Sopenharmony_ci
3979141cc406Sopenharmony_ci      s->x_p_nres = xres;
3980141cc406Sopenharmony_ci      s->y_p_nres = yres;
3981141cc406Sopenharmony_ci      cmode=s->colormode;
3982141cc406Sopenharmony_ci      s->colormode=s->colormode_p;
3983141cc406Sopenharmony_ci      s->colormode_p=cmode;
3984141cc406Sopenharmony_ci    }
3985141cc406Sopenharmony_ci  return 0;
3986141cc406Sopenharmony_ci}
3987141cc406Sopenharmony_ciSANE_Status
3988141cc406Sopenharmony_cisane_start (SANE_Handle handle)
3989141cc406Sopenharmony_ci{
3990141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
3991141cc406Sopenharmony_ci  int fds[2];
3992141cc406Sopenharmony_ci
3993141cc406Sopenharmony_ci  DBG (10, "sane_start\n");
3994141cc406Sopenharmony_ci  if (scanner->scanning == SANE_TRUE)
3995141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
3996141cc406Sopenharmony_ci
3997141cc406Sopenharmony_ci  if (scanner->sfd < 0)
3998141cc406Sopenharmony_ci    {				/* first call */
3999141cc406Sopenharmony_ci      if (sanei_scsi_open (scanner->sane.name,
4000141cc406Sopenharmony_ci			   &(scanner->sfd),
4001141cc406Sopenharmony_ci			   sense_handler, 0) != SANE_STATUS_GOOD)
4002141cc406Sopenharmony_ci	{
4003141cc406Sopenharmony_ci	  DBG (1, "sane_start: open of %s failed:\n",
4004141cc406Sopenharmony_ci	       scanner->sane.name);
4005141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
4006141cc406Sopenharmony_ci	}
4007141cc406Sopenharmony_ci    }
4008141cc406Sopenharmony_ci  scanner->scanning = SANE_TRUE;
4009141cc406Sopenharmony_ci
4010141cc406Sopenharmony_ci
4011141cc406Sopenharmony_ci  if (coolscan_check_values (scanner) != 0)
4012141cc406Sopenharmony_ci    {				/* Verify values */
4013141cc406Sopenharmony_ci      DBG (1, "ERROR: invalid scan-values\n");
4014141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
4015141cc406Sopenharmony_ci      coolscan_give_scanner (scanner);
4016141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
4017141cc406Sopenharmony_ci      scanner->sfd = -1;
4018141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
4019141cc406Sopenharmony_ci    }
4020141cc406Sopenharmony_ci
4021141cc406Sopenharmony_ci  if (coolscan_grab_scanner (scanner))
4022141cc406Sopenharmony_ci    {
4023141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
4024141cc406Sopenharmony_ci      scanner->sfd = -1;
4025141cc406Sopenharmony_ci      DBG (5, "WARNING: unable to reserve scanner: device busy\n");
4026141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
4027141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
4028141cc406Sopenharmony_ci    }
4029141cc406Sopenharmony_ci
4030141cc406Sopenharmony_ci  /* hoho, step 2c, -perm */
4031141cc406Sopenharmony_ci  coolscan_object_feed (scanner);
4032141cc406Sopenharmony_ci
4033141cc406Sopenharmony_ci  swap_res (scanner);
4034141cc406Sopenharmony_ci  if (!scanner->preview)
4035141cc406Sopenharmony_ci  { if(scanner->autofocus & 0x02)
4036141cc406Sopenharmony_ci    {  coolscan_autofocus (scanner);
4037141cc406Sopenharmony_ci    }
4038141cc406Sopenharmony_ci  }
4039141cc406Sopenharmony_ci  else
4040141cc406Sopenharmony_ci    {
4041141cc406Sopenharmony_ci      if(scanner->autofocus & 0x01)
4042141cc406Sopenharmony_ci      {  coolscan_autofocus (scanner);
4043141cc406Sopenharmony_ci      }
4044141cc406Sopenharmony_ci      if (scanner->prescan) {
4045141cc406Sopenharmony_ci	prescan (scanner);
4046141cc406Sopenharmony_ci	if(scanner->LS<2)
4047141cc406Sopenharmony_ci        {	get_internal_info(scanner);
4048141cc406Sopenharmony_ci	}
4049141cc406Sopenharmony_ci        coolscan_get_window_param (scanner,1);
4050141cc406Sopenharmony_ci      }
4051141cc406Sopenharmony_ci    }
4052141cc406Sopenharmony_ci  /*read_LUT(scanner); */
4053141cc406Sopenharmony_ci  if(scanner->LS<2)
4054141cc406Sopenharmony_ci  {  send_LUT (scanner);
4055141cc406Sopenharmony_ci     coolscan_set_window_param (scanner, 0);
4056141cc406Sopenharmony_ci     coolscan_get_window_param (scanner,0);
4057141cc406Sopenharmony_ci     coolscan_start_scan (scanner);
4058141cc406Sopenharmony_ci  }
4059141cc406Sopenharmony_ci  else
4060141cc406Sopenharmony_ci  {  coolscan_set_window_param (scanner, 0);
4061141cc406Sopenharmony_ci     send_LUT (scanner);
4062141cc406Sopenharmony_ci     Calc_fix_LUT(scanner);
4063141cc406Sopenharmony_ci     coolscan_start_scan (scanner);
4064141cc406Sopenharmony_ci     wait_scanner (scanner);
4065141cc406Sopenharmony_ci     coolscan_get_window_param (scanner,0);
4066141cc406Sopenharmony_ci  }
4067141cc406Sopenharmony_ci
4068141cc406Sopenharmony_ci  DBG (10, "bytes per line        = %d\n", scan_bytes_per_line (scanner));
4069141cc406Sopenharmony_ci  DBG (10, "pixels_per_line       = %d\n", pixels_per_line (scanner));
4070141cc406Sopenharmony_ci  DBG (10, "lines                 = %d\n", lines_per_scan (scanner));
4071141cc406Sopenharmony_ci  DBG (10, "negative              = %d\n", scanner->negative);
4072141cc406Sopenharmony_ci  DBG (10, "brightness (halftone) = %d\n", scanner->brightness);
4073141cc406Sopenharmony_ci  DBG (10, "contrast   (halftone) = %d\n", scanner->contrast);
4074141cc406Sopenharmony_ci  DBG (10, "fast preview function = %d\n", scanner->preview);
4075141cc406Sopenharmony_ci
4076141cc406Sopenharmony_ci  /* create a pipe, fds[0]=read-fd, fds[1]=write-fd */
4077141cc406Sopenharmony_ci  if (pipe (fds) < 0)
4078141cc406Sopenharmony_ci    {
4079141cc406Sopenharmony_ci      DBG (1, "ERROR: could not create pipe\n");
4080141cc406Sopenharmony_ci
4081141cc406Sopenharmony_ci      swap_res (scanner);
4082141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
4083141cc406Sopenharmony_ci      coolscan_give_scanner (scanner);
4084141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
4085141cc406Sopenharmony_ci      scanner->sfd = -1;
4086141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
4087141cc406Sopenharmony_ci    }
4088141cc406Sopenharmony_ci
4089141cc406Sopenharmony_ci  scanner->pipe       = fds[0];
4090141cc406Sopenharmony_ci  scanner->reader_fds = fds[1];
4091141cc406Sopenharmony_ci  scanner->reader_pid = sanei_thread_begin( reader_process, (void*)scanner );
4092141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (scanner->reader_pid))
4093141cc406Sopenharmony_ci    {
4094141cc406Sopenharmony_ci      DBG (1, "sane_start: sanei_thread_begin failed (%s)\n",
4095141cc406Sopenharmony_ci             strerror (errno));
4096141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
4097141cc406Sopenharmony_ci    }
4098141cc406Sopenharmony_ci
4099141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
4100141cc406Sopenharmony_ci    {
4101141cc406Sopenharmony_ci      close (scanner->reader_fds);
4102141cc406Sopenharmony_ci      scanner->reader_fds = -1;
4103141cc406Sopenharmony_ci    }
4104141cc406Sopenharmony_ci
4105141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4106141cc406Sopenharmony_ci}
4107141cc406Sopenharmony_ci
4108141cc406Sopenharmony_ci
4109141cc406Sopenharmony_ciSANE_Status
4110141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
4111141cc406Sopenharmony_ci	   SANE_Int max_len, SANE_Int * len)
4112141cc406Sopenharmony_ci{
4113141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
4114141cc406Sopenharmony_ci  ssize_t nread;
4115141cc406Sopenharmony_ci
4116141cc406Sopenharmony_ci  *len = 0;
4117141cc406Sopenharmony_ci
4118141cc406Sopenharmony_ci  nread = read (scanner->pipe, buf, max_len);
4119141cc406Sopenharmony_ci  DBG (10, "sane_read: read %ld bytes\n", (long) nread);
4120141cc406Sopenharmony_ci
4121141cc406Sopenharmony_ci  if (!(scanner->scanning))
4122141cc406Sopenharmony_ci    {
4123141cc406Sopenharmony_ci      return do_cancel (scanner);
4124141cc406Sopenharmony_ci    }
4125141cc406Sopenharmony_ci
4126141cc406Sopenharmony_ci  if (nread < 0)
4127141cc406Sopenharmony_ci    {
4128141cc406Sopenharmony_ci      if (errno == EAGAIN)
4129141cc406Sopenharmony_ci	{
4130141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
4131141cc406Sopenharmony_ci	}
4132141cc406Sopenharmony_ci      else
4133141cc406Sopenharmony_ci	{
4134141cc406Sopenharmony_ci	  do_cancel (scanner);
4135141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
4136141cc406Sopenharmony_ci	}
4137141cc406Sopenharmony_ci    }
4138141cc406Sopenharmony_ci
4139141cc406Sopenharmony_ci  *len = nread;
4140141cc406Sopenharmony_ci
4141141cc406Sopenharmony_ci  if (nread == 0)
4142141cc406Sopenharmony_ci    return do_eof (scanner);	/* close pipe */
4143141cc406Sopenharmony_ci
4144141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4145141cc406Sopenharmony_ci}
4146141cc406Sopenharmony_ci
4147141cc406Sopenharmony_civoid
4148141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
4149141cc406Sopenharmony_ci{
4150141cc406Sopenharmony_ci  Coolscan_t *s = handle;
4151141cc406Sopenharmony_ci
4152141cc406Sopenharmony_ci  if (sanei_thread_is_valid (s->reader_pid))
4153141cc406Sopenharmony_ci    {
4154141cc406Sopenharmony_ci      sanei_thread_kill   ( s->reader_pid );
4155141cc406Sopenharmony_ci      sanei_thread_waitpid( s->reader_pid, NULL );
4156141cc406Sopenharmony_ci      sanei_thread_invalidate (s->reader_pid);
4157141cc406Sopenharmony_ci    }
4158141cc406Sopenharmony_ci  swap_res (s);
4159141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
4160141cc406Sopenharmony_ci}
4161141cc406Sopenharmony_ci
4162141cc406Sopenharmony_ci
4163141cc406Sopenharmony_ciSANE_Status
4164141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
4165141cc406Sopenharmony_ci{
4166141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
4167141cc406Sopenharmony_ci
4168141cc406Sopenharmony_ci  DBG (10, "sane_set_io_mode: non_blocking=%d\n", non_blocking);
4169141cc406Sopenharmony_ci
4170141cc406Sopenharmony_ci  if (!scanner->scanning)
4171141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
4172141cc406Sopenharmony_ci
4173141cc406Sopenharmony_ci  if (fcntl (scanner->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
4174141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
4175141cc406Sopenharmony_ci
4176141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4177141cc406Sopenharmony_ci}
4178141cc406Sopenharmony_ci
4179141cc406Sopenharmony_ciSANE_Status
4180141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
4181141cc406Sopenharmony_ci{
4182141cc406Sopenharmony_ci  Coolscan_t *scanner = handle;
4183141cc406Sopenharmony_ci
4184141cc406Sopenharmony_ci  DBG (10, "sane_get_select_fd\n");
4185141cc406Sopenharmony_ci
4186141cc406Sopenharmony_ci  if (!scanner->scanning)
4187141cc406Sopenharmony_ci    {
4188141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
4189141cc406Sopenharmony_ci    }
4190141cc406Sopenharmony_ci  *fd = scanner->pipe;
4191141cc406Sopenharmony_ci
4192141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4193141cc406Sopenharmony_ci}
4194