1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 1996, 1997 David Mosberger-Tang and Andreas Czechanowski,
3141cc406Sopenharmony_ci   1998 Andreas Bolsch for extension to ScanExpress models version 0.6,
4141cc406Sopenharmony_ci   2000-2005 Henning Meier-Geinitz,
5141cc406Sopenharmony_ci   2003 James Perry (600 EP).
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This file is part of the SANE package.
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
10141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
11141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
12141cc406Sopenharmony_ci   License, or (at your option) any later version.
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
15141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
16141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17141cc406Sopenharmony_ci   General Public License for more details.
18141cc406Sopenharmony_ci
19141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
20141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
23141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
24141cc406Sopenharmony_ci
25141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
26141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
27141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
28141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
29141cc406Sopenharmony_ci   account of linking the SANE library code into it.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
32141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
33141cc406Sopenharmony_ci   License.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
36141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
37141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
40141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
41141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci   This file implements a SANE backend for Mustek and some Trust flatbed
44141cc406Sopenharmony_ci   scanners with SCSI, parallel port (600 EP)  or proprietary interface.  */
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci/**************************************************************************/
48141cc406Sopenharmony_ci/* Mustek backend version                                                 */
49141cc406Sopenharmony_ci#define BUILD 138
50141cc406Sopenharmony_ci/**************************************************************************/
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci#include "../include/sane/config.h"
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci#include <ctype.h>
55141cc406Sopenharmony_ci#include <errno.h>
56141cc406Sopenharmony_ci#include <fcntl.h>
57141cc406Sopenharmony_ci#include <limits.h>
58141cc406Sopenharmony_ci#include <signal.h>
59141cc406Sopenharmony_ci#include <stdio.h>
60141cc406Sopenharmony_ci#include <stdlib.h>
61141cc406Sopenharmony_ci#include <string.h>
62141cc406Sopenharmony_ci#include <unistd.h>
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci#include <sys/time.h>
65141cc406Sopenharmony_ci#include <sys/types.h>
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci#include "../include/_stdint.h"
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#include "../include/sane/sane.h"
70141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
71141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei_ab306.h"
74141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#define BACKEND_NAME	mustek
77141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
78141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci#include "mustek.h"
81141cc406Sopenharmony_ci#include "mustek_scsi_pp.h"
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci#ifndef SANE_I18N
84141cc406Sopenharmony_ci#define SANE_I18N(text) text
85141cc406Sopenharmony_ci#endif
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci/* Debug level from sanei_init_debug */
88141cc406Sopenharmony_cistatic SANE_Int debug_level;
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci/* Maximum # of inches to scan in one swoop.  0 means "unlimited."
91141cc406Sopenharmony_ci   This is here to be nice on the SCSI bus---Mustek scanners don't
92141cc406Sopenharmony_ci   disconnect while scanning is in progress, which confuses some
93141cc406Sopenharmony_ci   drivers that expect no reasonable SCSI request would take more than
94141cc406Sopenharmony_ci   10 seconds.  That's not really true for Mustek scanners operating
95141cc406Sopenharmony_ci   in certain modes, hence this limit. Usually you don't need to set it. */
96141cc406Sopenharmony_cistatic double strip_height;
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci/* Should we wait for the scan slider to return after each scan? */
99141cc406Sopenharmony_cistatic SANE_Bool force_wait;
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci/* Should we disable double buffering when reading data from the scanner? */
102141cc406Sopenharmony_cistatic SANE_Bool disable_double_buffering;
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_cistatic SANE_Int num_devices;
105141cc406Sopenharmony_cistatic Mustek_Device *first_dev;
106141cc406Sopenharmony_cistatic Mustek_Scanner *first_handle;
107141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci/* Array of newly attached devices */
110141cc406Sopenharmony_cistatic Mustek_Device **new_dev;
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci/* Length of new_dev array */
113141cc406Sopenharmony_cistatic SANE_Int new_dev_len;
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci/* Number of entries allocated for new_dev */
116141cc406Sopenharmony_cistatic SANE_Int new_dev_alloced;
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_cistatic SANE_Int lamp_off_time = 60;
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci/* Used for line-distance correction: */
121141cc406Sopenharmony_cistatic const SANE_Int color_seq[] = {
122141cc406Sopenharmony_ci  1, 2, 0			/* green, blue, red */
123141cc406Sopenharmony_ci};
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci/* Which modes are supported? */
126141cc406Sopenharmony_cistatic SANE_String_Const mode_list_paragon[] = {
127141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
128141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_HALFTONE,
129141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
130141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
131141cc406Sopenharmony_ci  0
132141cc406Sopenharmony_ci};
133141cc406Sopenharmony_cistatic SANE_String_Const mode_list_se[] = {
134141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
135141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
136141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
137141cc406Sopenharmony_ci  0
138141cc406Sopenharmony_ci};
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_cistatic SANE_String_Const bit_depth_list_pro[] = {
141141cc406Sopenharmony_ci  "8", "12",
142141cc406Sopenharmony_ci  0
143141cc406Sopenharmony_ci};
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_ci/* Some scanners support setting speed manually */
146141cc406Sopenharmony_cistatic SANE_String_Const speed_list[] = {
147141cc406Sopenharmony_ci  SANE_I18N ("Slowest"), SANE_I18N ("Slower"), SANE_I18N ("Normal"),
148141cc406Sopenharmony_ci  SANE_I18N ("Faster"), SANE_I18N ("Fastest"),
149141cc406Sopenharmony_ci  0
150141cc406Sopenharmony_ci};
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci/* Which scan-sources are supported? */
153141cc406Sopenharmony_cistatic const SANE_String_Const source_list[] = {
154141cc406Sopenharmony_ci  SANE_I18N ("Flatbed"),
155141cc406Sopenharmony_ci  0
156141cc406Sopenharmony_ci};
157141cc406Sopenharmony_cistatic SANE_String_Const adf_source_list[] = {
158141cc406Sopenharmony_ci  SANE_I18N ("Flatbed"), SANE_I18N ("Automatic Document Feeder"),
159141cc406Sopenharmony_ci  0
160141cc406Sopenharmony_ci};
161141cc406Sopenharmony_cistatic SANE_String_Const ta_source_list[] = {
162141cc406Sopenharmony_ci  SANE_I18N ("Flatbed"), SANE_I18N ("Transparency Adapter"),
163141cc406Sopenharmony_ci  0
164141cc406Sopenharmony_ci};
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci/* Range used for gamma and halftone pattern */
167141cc406Sopenharmony_cistatic const SANE_Range u8_range = {
168141cc406Sopenharmony_ci  0,				/* minimum */
169141cc406Sopenharmony_ci  255,				/* maximum */
170141cc406Sopenharmony_ci  0				/* quantization */
171141cc406Sopenharmony_ci};
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci/* Which kind of halftone patterns are available? */
174141cc406Sopenharmony_cistatic SANE_String_Const halftone_list[] = {
175141cc406Sopenharmony_ci  SANE_I18N ("8x8 coarse"), SANE_I18N ("8x8 normal"), SANE_I18N ("8x8 fine"),
176141cc406Sopenharmony_ci  SANE_I18N ("8x8 very fine"), SANE_I18N ("6x6 normal"),
177141cc406Sopenharmony_ci  SANE_I18N ("5x5 coarse"), SANE_I18N ("5x5 fine"), SANE_I18N ("4x4 coarse"),
178141cc406Sopenharmony_ci  SANE_I18N ("4x4 normal"), SANE_I18N ("4x4 fine"), SANE_I18N ("3x3 normal"),
179141cc406Sopenharmony_ci  SANE_I18N ("2x2 normal"), SANE_I18N ("8x8 custom"),
180141cc406Sopenharmony_ci  SANE_I18N ("6x6 custom"),
181141cc406Sopenharmony_ci  SANE_I18N ("5x5 custom"), SANE_I18N ("4x4 custom"),
182141cc406Sopenharmony_ci  SANE_I18N ("3x3 custom"),
183141cc406Sopenharmony_ci  SANE_I18N ("2x2 custom"),
184141cc406Sopenharmony_ci  0
185141cc406Sopenharmony_ci};
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ci/* Range used for brightness and contrast */
188141cc406Sopenharmony_cistatic const SANE_Range percentage_range = {
189141cc406Sopenharmony_ci  SANE_FIX(-100),	/* minimum */
190141cc406Sopenharmony_ci  SANE_FIX(100),	/* maximum */
191141cc406Sopenharmony_ci  SANE_FIX(1)           /* quantization */
192141cc406Sopenharmony_ci};
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci/* SCSI command buffers used by the backend */
195141cc406Sopenharmony_cistatic const SANE_Byte scsi_inquiry[] = {
196141cc406Sopenharmony_ci  MUSTEK_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00
197141cc406Sopenharmony_ci};
198141cc406Sopenharmony_cistatic const SANE_Byte scsi_test_unit_ready[] = {
199141cc406Sopenharmony_ci  MUSTEK_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00
200141cc406Sopenharmony_ci};
201141cc406Sopenharmony_cistatic const SANE_Byte scsi_request_sense[] = {
202141cc406Sopenharmony_ci  MUSTEK_SCSI_REQUEST_SENSE, 0x00, 0x00, 0x00, 0x04, 0x00
203141cc406Sopenharmony_ci};
204141cc406Sopenharmony_cistatic const SANE_Byte scsi_start_stop[] = {
205141cc406Sopenharmony_ci  MUSTEK_SCSI_START_STOP, 0x00, 0x00, 0x00, 0x00, 0x00
206141cc406Sopenharmony_ci};
207141cc406Sopenharmony_cistatic const SANE_Byte scsi_ccd_distance[] = {
208141cc406Sopenharmony_ci  MUSTEK_SCSI_CCD_DISTANCE, 0x00, 0x00, 0x00, 0x05, 0x00
209141cc406Sopenharmony_ci};
210141cc406Sopenharmony_cistatic const SANE_Byte scsi_get_image_status[] = {
211141cc406Sopenharmony_ci  MUSTEK_SCSI_GET_IMAGE_STATUS, 0x00, 0x00, 0x00, 0x06, 0x00
212141cc406Sopenharmony_ci};
213141cc406Sopenharmony_cistatic const SANE_Byte scsi_get_window[] = {
214141cc406Sopenharmony_ci  MUSTEK_SCSI_GET_WINDOW, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00
215141cc406Sopenharmony_ci};
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci/* Sizes for fixed-length, non-vendor-specific CDB formats (others are 0) */
218141cc406Sopenharmony_ci#define CDB_SIZE(opcode)	((opcode) < 0x20 ? 6 : \
219141cc406Sopenharmony_ci				 (opcode) < 0x60 ? 10 : \
220141cc406Sopenharmony_ci				 (opcode) < 0x80 ? 0 : \
221141cc406Sopenharmony_ci				 (opcode) < 0xa0 ? 16 : \
222141cc406Sopenharmony_ci				 (opcode) < 0xc0 ? 12 : 0)
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci/* prototypes */
225141cc406Sopenharmony_cistatic SANE_Status area_and_windows (Mustek_Scanner * s);
226141cc406Sopenharmony_cistatic SANE_Status inquiry (Mustek_Scanner * s);
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci/* Test if this machine is little endian (from coolscan.c) */
229141cc406Sopenharmony_cistatic SANE_Bool
230141cc406Sopenharmony_cilittle_endian (void)
231141cc406Sopenharmony_ci{
232141cc406Sopenharmony_ci  SANE_Int testvalue = 255;
233141cc406Sopenharmony_ci  uint8_t *firstbyte = (uint8_t *) & testvalue;
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci  if (*firstbyte == 255)
236141cc406Sopenharmony_ci    return SANE_TRUE;
237141cc406Sopenharmony_ci  return SANE_FALSE;
238141cc406Sopenharmony_ci}
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci/* Used for Pro series. First value seems to be always 85, second one varies.
241141cc406Sopenharmony_ci   First bit of second value clear == device ready (?) */
242141cc406Sopenharmony_cistatic SANE_Status
243141cc406Sopenharmony_ciscsi_sense_wait_ready (Mustek_Scanner * s)
244141cc406Sopenharmony_ci{
245141cc406Sopenharmony_ci  struct timeval now, start;
246141cc406Sopenharmony_ci  SANE_Status status;
247141cc406Sopenharmony_ci  size_t len;
248141cc406Sopenharmony_ci  SANE_Byte sense_buffer[4];
249141cc406Sopenharmony_ci  SANE_Byte bytetxt[300], dbgtxt[300], *pp;
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci  gettimeofday (&start, 0);
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci  while (1)
254141cc406Sopenharmony_ci    {
255141cc406Sopenharmony_ci      len = sizeof (sense_buffer);
256141cc406Sopenharmony_ci
257141cc406Sopenharmony_ci      DBG (5, "scsi_sense_wait_ready: command size = %ld, sense size = %ld\n",
258141cc406Sopenharmony_ci	   (long int) sizeof (scsi_request_sense), (long int) len);
259141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, scsi_request_sense,
260141cc406Sopenharmony_ci			       sizeof (scsi_request_sense), sense_buffer,
261141cc406Sopenharmony_ci			       &len);
262141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
263141cc406Sopenharmony_ci	{
264141cc406Sopenharmony_ci	  DBG (1, "scsi_sense_wait_ready: failed: %s\n",
265141cc406Sopenharmony_ci	       sane_strstatus (status));
266141cc406Sopenharmony_ci	  return status;
267141cc406Sopenharmony_ci	}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci      dbgtxt[0] = '\0';
270141cc406Sopenharmony_ci      for (pp = sense_buffer; pp < (sense_buffer + 4); pp++)
271141cc406Sopenharmony_ci	{
272141cc406Sopenharmony_ci	  sprintf ((SANE_String) bytetxt, " %02x", *pp);
273141cc406Sopenharmony_ci	  strcat ((SANE_String) dbgtxt, (SANE_String) bytetxt);
274141cc406Sopenharmony_ci	}
275141cc406Sopenharmony_ci      DBG (5, "scsi_sense_wait_ready: sensebuffer: %s\n", dbgtxt);
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci      if (!(sense_buffer[1] & 0x01))
278141cc406Sopenharmony_ci	{
279141cc406Sopenharmony_ci	  DBG (4, "scsi_sense_wait_ready: ok\n");
280141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
281141cc406Sopenharmony_ci	}
282141cc406Sopenharmony_ci      else
283141cc406Sopenharmony_ci	{
284141cc406Sopenharmony_ci	  gettimeofday (&now, 0);
285141cc406Sopenharmony_ci	  if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
286141cc406Sopenharmony_ci	    {
287141cc406Sopenharmony_ci	      DBG (1, "scsi_sense_wait_ready: timed out after %lu seconds\n",
288141cc406Sopenharmony_ci		   (u_long) (now.tv_sec - start.tv_sec));
289141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
290141cc406Sopenharmony_ci	    }
291141cc406Sopenharmony_ci	  usleep (100000);	/* retry after 100ms */
292141cc406Sopenharmony_ci	}
293141cc406Sopenharmony_ci    }
294141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
295141cc406Sopenharmony_ci}
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci/* Used for 3pass series */
298141cc406Sopenharmony_cistatic SANE_Status
299141cc406Sopenharmony_ciscsi_area_wait_ready (Mustek_Scanner * s)
300141cc406Sopenharmony_ci{
301141cc406Sopenharmony_ci  struct timeval now, start;
302141cc406Sopenharmony_ci  SANE_Status status;
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci  gettimeofday (&start, 0);
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci  DBG (5, "scsi_area_wait_ready\n");
307141cc406Sopenharmony_ci  while (1)
308141cc406Sopenharmony_ci    {
309141cc406Sopenharmony_ci      status = area_and_windows (s);
310141cc406Sopenharmony_ci      switch (status)
311141cc406Sopenharmony_ci	{
312141cc406Sopenharmony_ci	default:
313141cc406Sopenharmony_ci	  /* Ignore errors while waiting for scanner to become ready.
314141cc406Sopenharmony_ci	     Some SCSI drivers return EIO while the scanner is
315141cc406Sopenharmony_ci	     returning to the home position.  */
316141cc406Sopenharmony_ci	  DBG (3, "scsi_area_wait_ready: failed (%s)\n",
317141cc406Sopenharmony_ci	       sane_strstatus (status));
318141cc406Sopenharmony_ci	  /* fall through */
319141cc406Sopenharmony_ci	case SANE_STATUS_DEVICE_BUSY:
320141cc406Sopenharmony_ci	  gettimeofday (&now, 0);
321141cc406Sopenharmony_ci	  if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
322141cc406Sopenharmony_ci	    {
323141cc406Sopenharmony_ci	      DBG (1, "scsi_area_wait_ready: timed out after %lu seconds\n",
324141cc406Sopenharmony_ci		   (u_long) (now.tv_sec - start.tv_sec));
325141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
326141cc406Sopenharmony_ci	    }
327141cc406Sopenharmony_ci	  usleep (100000);	/* retry after 100ms */
328141cc406Sopenharmony_ci	  break;
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci	case SANE_STATUS_GOOD:
331141cc406Sopenharmony_ci	  return status;
332141cc406Sopenharmony_ci	}
333141cc406Sopenharmony_ci    }
334141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
335141cc406Sopenharmony_ci}
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_cistatic SANE_Status
338141cc406Sopenharmony_ciscsi_unit_wait_ready (Mustek_Scanner * s)
339141cc406Sopenharmony_ci{
340141cc406Sopenharmony_ci  struct timeval now, start;
341141cc406Sopenharmony_ci  SANE_Status status;
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci  gettimeofday (&start, 0);
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci  while (1)
346141cc406Sopenharmony_ci    {
347141cc406Sopenharmony_ci      DBG (5, "scsi_unit_wait_ready: sending TEST_UNIT_READY\n");
348141cc406Sopenharmony_ci      status = sanei_scsi_cmd (s->fd, scsi_test_unit_ready,
349141cc406Sopenharmony_ci			       sizeof (scsi_test_unit_ready), 0, 0);
350141cc406Sopenharmony_ci      DBG (5, "scsi_unit_wait_ready: TEST_UNIT_READY finished\n");
351141cc406Sopenharmony_ci      switch (status)
352141cc406Sopenharmony_ci	{
353141cc406Sopenharmony_ci	default:
354141cc406Sopenharmony_ci	  /* Ignore errors while waiting for scanner to become ready.
355141cc406Sopenharmony_ci	     Some SCSI drivers return EIO while the scanner is
356141cc406Sopenharmony_ci	     returning to the home position.  */
357141cc406Sopenharmony_ci	  DBG (3, "scsi_unit_wait_ready: test unit ready failed (%s)\n",
358141cc406Sopenharmony_ci	       sane_strstatus (status));
359141cc406Sopenharmony_ci	  /* fall through */
360141cc406Sopenharmony_ci	case SANE_STATUS_DEVICE_BUSY:
361141cc406Sopenharmony_ci	  gettimeofday (&now, 0);
362141cc406Sopenharmony_ci	  if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
363141cc406Sopenharmony_ci	    {
364141cc406Sopenharmony_ci	      DBG (1, "scsi_unit_wait_ready: timed out after %lu seconds\n",
365141cc406Sopenharmony_ci		   (u_long) (now.tv_sec - start.tv_sec));
366141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
367141cc406Sopenharmony_ci	    }
368141cc406Sopenharmony_ci	  usleep (100000);	/* retry after 100ms */
369141cc406Sopenharmony_ci	  break;
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci	case SANE_STATUS_GOOD:
372141cc406Sopenharmony_ci	  return status;
373141cc406Sopenharmony_ci	}
374141cc406Sopenharmony_ci    }
375141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
376141cc406Sopenharmony_ci}
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_cistatic SANE_Status
379141cc406Sopenharmony_ciscsi_inquiry_wait_ready (Mustek_Scanner * s)
380141cc406Sopenharmony_ci{
381141cc406Sopenharmony_ci  struct timeval now, start;
382141cc406Sopenharmony_ci  SANE_Status status;
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  gettimeofday (&start, 0);
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  while (1)
387141cc406Sopenharmony_ci    {
388141cc406Sopenharmony_ci      DBG (5, "scsi_inquiry_wait_ready: sending INQUIRY\n");
389141cc406Sopenharmony_ci      status = inquiry (s);
390141cc406Sopenharmony_ci      DBG (5, "scsi_inquiry_wait_ready: INQUIRY finished\n");
391141cc406Sopenharmony_ci      switch (status)
392141cc406Sopenharmony_ci	{
393141cc406Sopenharmony_ci	default:
394141cc406Sopenharmony_ci	  /* Ignore errors while waiting for scanner to become ready.
395141cc406Sopenharmony_ci	     Some SCSI drivers return EIO while the scanner is
396141cc406Sopenharmony_ci	     returning to the home position.  */
397141cc406Sopenharmony_ci	  DBG (3, "scsi_unit_wait_ready: inquiry failed (%s)\n",
398141cc406Sopenharmony_ci	       sane_strstatus (status));
399141cc406Sopenharmony_ci	  /* fall through */
400141cc406Sopenharmony_ci	case SANE_STATUS_DEVICE_BUSY:
401141cc406Sopenharmony_ci	  gettimeofday (&now, 0);
402141cc406Sopenharmony_ci	  if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
403141cc406Sopenharmony_ci	    {
404141cc406Sopenharmony_ci	      DBG (1, "scsi_unit_wait_ready: timed out after %lu seconds\n",
405141cc406Sopenharmony_ci		   (u_long) (now.tv_sec - start.tv_sec));
406141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
407141cc406Sopenharmony_ci	    }
408141cc406Sopenharmony_ci	  usleep (500000);	/* retry after 500ms */
409141cc406Sopenharmony_ci	  break;
410141cc406Sopenharmony_ci
411141cc406Sopenharmony_ci	case SANE_STATUS_GOOD:
412141cc406Sopenharmony_ci	  return status;
413141cc406Sopenharmony_ci	}
414141cc406Sopenharmony_ci    }
415141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
416141cc406Sopenharmony_ci}
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_cistatic SANE_Status
419141cc406Sopenharmony_cin_wait_ready (Mustek_Scanner * s)
420141cc406Sopenharmony_ci{
421141cc406Sopenharmony_ci  struct timeval now, start;
422141cc406Sopenharmony_ci  SANE_Status status;
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci  gettimeofday (&start, 0);
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci  DBG (5, "n_wait_ready\n");
427141cc406Sopenharmony_ci  while (1)
428141cc406Sopenharmony_ci    {
429141cc406Sopenharmony_ci      status = sanei_ab306_test_ready (s->fd);
430141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
431141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci      gettimeofday (&now, 0);
434141cc406Sopenharmony_ci      if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
435141cc406Sopenharmony_ci	{
436141cc406Sopenharmony_ci	  DBG (1, "n_wait_ready: timed out after %lu seconds\n",
437141cc406Sopenharmony_ci	       (u_long) (now.tv_sec - start.tv_sec));
438141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
439141cc406Sopenharmony_ci	}
440141cc406Sopenharmony_ci      usleep (100000);		/* retry after 100ms */
441141cc406Sopenharmony_ci    }
442141cc406Sopenharmony_ci}
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_cistatic SANE_Status
445141cc406Sopenharmony_ciscsi_pp_wait_ready (Mustek_Scanner * s)
446141cc406Sopenharmony_ci{
447141cc406Sopenharmony_ci  struct timeval now, start;
448141cc406Sopenharmony_ci  SANE_Status status;
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci  gettimeofday (&start, 0);
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  DBG (5, "scsi_pp_wait_ready\n");
453141cc406Sopenharmony_ci  while (1)
454141cc406Sopenharmony_ci    {
455141cc406Sopenharmony_ci      status = mustek_scsi_pp_test_ready (s->fd);
456141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
457141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci      gettimeofday (&now, 0);
460141cc406Sopenharmony_ci      if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME)
461141cc406Sopenharmony_ci	{
462141cc406Sopenharmony_ci	  DBG (1, "scsi_pp_wait_ready: timed out after %lu seconds\n",
463141cc406Sopenharmony_ci	       (u_long) (now.tv_sec - start.tv_sec));
464141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
465141cc406Sopenharmony_ci	}
466141cc406Sopenharmony_ci      usleep (100000);		/* retry after 100ms */
467141cc406Sopenharmony_ci    }
468141cc406Sopenharmony_ci}
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_cistatic SANE_Status
471141cc406Sopenharmony_cidev_wait_ready (Mustek_Scanner * s)
472141cc406Sopenharmony_ci{
473141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
474141cc406Sopenharmony_ci    return n_wait_ready (s);
475141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP)
476141cc406Sopenharmony_ci    return scsi_pp_wait_ready (s);
477141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
478141cc406Sopenharmony_ci    {
479141cc406Sopenharmony_ci      SANE_Status status;
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci      /* some 3-pass scanners seem to need the inquiry wait, too */
482141cc406Sopenharmony_ci      status = scsi_area_wait_ready (s);
483141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
484141cc406Sopenharmony_ci	return status;
485141cc406Sopenharmony_ci      return scsi_inquiry_wait_ready (s);
486141cc406Sopenharmony_ci    }
487141cc406Sopenharmony_ci  else if ((s->hw->flags & MUSTEK_FLAG_PARAGON_1)
488141cc406Sopenharmony_ci	   || (s->hw->flags & MUSTEK_FLAG_PARAGON_2))
489141cc406Sopenharmony_ci    return scsi_inquiry_wait_ready (s);
490141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_PRO)
491141cc406Sopenharmony_ci    return scsi_sense_wait_ready (s);
492141cc406Sopenharmony_ci  else
493141cc406Sopenharmony_ci    return scsi_unit_wait_ready (s);
494141cc406Sopenharmony_ci}
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_cistatic SANE_Status
497141cc406Sopenharmony_cidev_open (SANE_String_Const devname, Mustek_Scanner * s,
498141cc406Sopenharmony_ci	  SANEI_SCSI_Sense_Handler handler)
499141cc406Sopenharmony_ci{
500141cc406Sopenharmony_ci  SANE_Status status;
501141cc406Sopenharmony_ci
502141cc406Sopenharmony_ci  DBG (5, "dev_open %s\n", devname);
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
505141cc406Sopenharmony_ci  s->hw->buffer_size = s->hw->max_buffer_size;
506141cc406Sopenharmony_ci  status = sanei_scsi_open_extended (devname, &s->fd, handler, 0,
507141cc406Sopenharmony_ci				     &s->hw->buffer_size);
508141cc406Sopenharmony_ci#else
509141cc406Sopenharmony_ci  s->hw->buffer_size = MIN (sanei_scsi_max_request_size,
510141cc406Sopenharmony_ci			    s->hw->max_buffer_size);
511141cc406Sopenharmony_ci  status = sanei_scsi_open (devname, &s->fd, handler, 0);
512141cc406Sopenharmony_ci#endif
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD)
515141cc406Sopenharmony_ci    {
516141cc406Sopenharmony_ci      DBG (3, "dev_open: %s is a SCSI device\n", devname);
517141cc406Sopenharmony_ci      DBG (4, "dev_open: wanted %d kbytes, got %d kbytes buffer\n",
518141cc406Sopenharmony_ci	   s->hw->max_buffer_size / 1024, s->hw->buffer_size / 1024);
519141cc406Sopenharmony_ci      if (s->hw->buffer_size < 4096)
520141cc406Sopenharmony_ci	{
521141cc406Sopenharmony_ci	  DBG (1, "dev_open: sanei_scsi_open buffer too small\n");
522141cc406Sopenharmony_ci	  sanei_scsi_close (s->fd);
523141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
524141cc406Sopenharmony_ci	}
525141cc406Sopenharmony_ci    }
526141cc406Sopenharmony_ci  else
527141cc406Sopenharmony_ci    {
528141cc406Sopenharmony_ci      DBG (3, "dev_open: %s: can't open %s as a SCSI device\n",
529141cc406Sopenharmony_ci	   sane_strstatus (status), devname);
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci      status = sanei_ab306_open (devname, &s->fd);
532141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
533141cc406Sopenharmony_ci	{
534141cc406Sopenharmony_ci	  s->hw->flags |= MUSTEK_FLAG_N;
535141cc406Sopenharmony_ci	  DBG (3, "dev_open: %s is an AB306N device\n", devname);
536141cc406Sopenharmony_ci	}
537141cc406Sopenharmony_ci      else
538141cc406Sopenharmony_ci	{
539141cc406Sopenharmony_ci	  DBG (3, "dev_open: %s: can't open %s as an AB306N device\n",
540141cc406Sopenharmony_ci	       sane_strstatus (status), devname);
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci	  status = mustek_scsi_pp_open (devname, &s->fd);
543141cc406Sopenharmony_ci	  if (status == SANE_STATUS_GOOD)
544141cc406Sopenharmony_ci	    {
545141cc406Sopenharmony_ci	      s->hw->flags |= MUSTEK_FLAG_SCSI_PP;
546141cc406Sopenharmony_ci	      DBG (3, "dev_open: %s is a SCSI-over-parallel device\n",
547141cc406Sopenharmony_ci		   devname);
548141cc406Sopenharmony_ci	    }
549141cc406Sopenharmony_ci	  else
550141cc406Sopenharmony_ci	    {
551141cc406Sopenharmony_ci	      DBG (3,
552141cc406Sopenharmony_ci		   "dev_open: %s: can't open %s as a SCSI-over-parallel device\n",
553141cc406Sopenharmony_ci		   sane_strstatus (status), devname);
554141cc406Sopenharmony_ci	      DBG (1, "dev_open: can't open %s\n", devname);
555141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
556141cc406Sopenharmony_ci	    }
557141cc406Sopenharmony_ci	}
558141cc406Sopenharmony_ci    }
559141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
560141cc406Sopenharmony_ci}
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_cistatic SANE_Status
563141cc406Sopenharmony_cidev_cmd (Mustek_Scanner * s, const void *src, size_t src_size,
564141cc406Sopenharmony_ci	 void *dst, size_t * dst_size)
565141cc406Sopenharmony_ci{
566141cc406Sopenharmony_ci  SANE_Status status;
567141cc406Sopenharmony_ci  SANE_Byte cmd_byte_list[50];
568141cc406Sopenharmony_ci  SANE_Byte cmd_byte[5];
569141cc406Sopenharmony_ci  const SANE_Byte *pp;
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci  DBG (5, "dev_cmd: fd=%d, src=%p, src_size=%ld, dst=%p, dst_size=%ld\n",
572141cc406Sopenharmony_ci       s->fd, src, (long int) src_size, dst,
573141cc406Sopenharmony_ci       (long int) (dst_size ? *dst_size : 0));
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ci  if (src && (debug_level >= 5))	/* output data sent to SCSI device */
576141cc406Sopenharmony_ci    {
577141cc406Sopenharmony_ci      cmd_byte_list[0] = '\0';
578141cc406Sopenharmony_ci      for (pp = (const SANE_Byte *) src;
579141cc406Sopenharmony_ci	   pp < (((const SANE_Byte *) src) + src_size); pp++)
580141cc406Sopenharmony_ci	{
581141cc406Sopenharmony_ci	  sprintf ((SANE_String) cmd_byte, " %02x", *pp);
582141cc406Sopenharmony_ci	  strcat ((SANE_String) cmd_byte_list, (SANE_String) cmd_byte);
583141cc406Sopenharmony_ci	  if (((pp - (const SANE_Byte *) src) % 0x10 == 0x0f)
584141cc406Sopenharmony_ci	      || (pp >= (((const SANE_Byte *) src) + src_size - 1)))
585141cc406Sopenharmony_ci	    {
586141cc406Sopenharmony_ci	      DBG (5, "dev_cmd: sending: %s\n", cmd_byte_list);
587141cc406Sopenharmony_ci	      cmd_byte_list[0] = '\0';
588141cc406Sopenharmony_ci	    }
589141cc406Sopenharmony_ci	}
590141cc406Sopenharmony_ci    }
591141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
592141cc406Sopenharmony_ci    status = sanei_ab306_cmd (s->fd, src, src_size, dst, dst_size);
593141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP)
594141cc406Sopenharmony_ci    status = mustek_scsi_pp_cmd (s->fd, src, src_size, dst, dst_size);
595141cc406Sopenharmony_ci  else
596141cc406Sopenharmony_ci    status = sanei_scsi_cmd (s->fd, src, src_size, dst, dst_size);
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci  if (dst && dst_size && (debug_level >= 5))
599141cc406Sopenharmony_ci    /* output data received from SCSI device */
600141cc406Sopenharmony_ci    {
601141cc406Sopenharmony_ci      cmd_byte_list[0] = '\0';
602141cc406Sopenharmony_ci      for (pp = (const SANE_Byte *) dst;
603141cc406Sopenharmony_ci	   pp < (((const SANE_Byte *) dst) + *dst_size); pp++)
604141cc406Sopenharmony_ci	{
605141cc406Sopenharmony_ci	  sprintf ((SANE_String) cmd_byte, " %02x", *pp);
606141cc406Sopenharmony_ci	  strcat ((SANE_String) cmd_byte_list, (SANE_String) cmd_byte);
607141cc406Sopenharmony_ci	  if (((pp - (const SANE_Byte *) dst) % 0x10 == 0x0f)
608141cc406Sopenharmony_ci	      || (pp >= (((const SANE_Byte *) dst) + *dst_size - 1)))
609141cc406Sopenharmony_ci	    {
610141cc406Sopenharmony_ci	      DBG (5, "dev_cmd: receiving: %s\n", cmd_byte_list);
611141cc406Sopenharmony_ci	      cmd_byte_list[0] = '\0';
612141cc406Sopenharmony_ci	    }
613141cc406Sopenharmony_ci	}
614141cc406Sopenharmony_ci    }
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci  DBG (5, "dev_cmd: finished: dst_size=%ld, status=%s\n",
617141cc406Sopenharmony_ci       (long int) (dst_size ? *dst_size : 0), sane_strstatus (status));
618141cc406Sopenharmony_ci  return status;
619141cc406Sopenharmony_ci}
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_cistatic SANE_Status
622141cc406Sopenharmony_cidev_req_wait (void *id)
623141cc406Sopenharmony_ci{
624141cc406Sopenharmony_ci  if (!id)
625141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
626141cc406Sopenharmony_ci  else
627141cc406Sopenharmony_ci    return sanei_scsi_req_wait (id);
628141cc406Sopenharmony_ci}
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_cistatic SANE_Status
631141cc406Sopenharmony_cidev_block_read_start (Mustek_Scanner * s, SANE_Int lines)
632141cc406Sopenharmony_ci{
633141cc406Sopenharmony_ci  DBG (4, "dev_block_read_start: entering block for %d lines\n", lines);
634141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
635141cc406Sopenharmony_ci    {
636141cc406Sopenharmony_ci      SANE_Byte readlines[6];
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci      memset (readlines, 0, sizeof (readlines));
639141cc406Sopenharmony_ci      readlines[0] = MUSTEK_SCSI_READ_SCANNED_DATA;
640141cc406Sopenharmony_ci      readlines[2] = (lines >> 16) & 0xff;
641141cc406Sopenharmony_ci      readlines[3] = (lines >> 8) & 0xff;
642141cc406Sopenharmony_ci      readlines[4] = (lines >> 0) & 0xff;
643141cc406Sopenharmony_ci      return sanei_ab306_cmd (s->fd, readlines, sizeof (readlines), 0, 0);
644141cc406Sopenharmony_ci    }
645141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP)
646141cc406Sopenharmony_ci    {
647141cc406Sopenharmony_ci      SANE_Byte readlines[6];
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci      memset (readlines, 0, sizeof (readlines));
650141cc406Sopenharmony_ci      readlines[0] = MUSTEK_SCSI_READ_SCANNED_DATA;
651141cc406Sopenharmony_ci      readlines[2] = (lines >> 16) & 0xff;
652141cc406Sopenharmony_ci      readlines[3] = (lines >> 8) & 0xff;
653141cc406Sopenharmony_ci      readlines[4] = (lines >> 0) & 0xff;
654141cc406Sopenharmony_ci      return mustek_scsi_pp_cmd (s->fd, readlines, sizeof (readlines), 0, 0);
655141cc406Sopenharmony_ci    }
656141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_PARAGON_2)
657141cc406Sopenharmony_ci    {
658141cc406Sopenharmony_ci      SANE_Byte buffer[6];
659141cc406Sopenharmony_ci      size_t len;
660141cc406Sopenharmony_ci      SANE_Int color;
661141cc406Sopenharmony_ci      SANE_Status status;
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci      /* reset line-distance values */
664141cc406Sopenharmony_ci      if (s->mode & MUSTEK_MODE_COLOR)
665141cc406Sopenharmony_ci	{
666141cc406Sopenharmony_ci	  for (color = 0; color < 3; ++color)
667141cc406Sopenharmony_ci	    {
668141cc406Sopenharmony_ci	      s->ld.index[color] = -s->ld.dist[color];
669141cc406Sopenharmony_ci	    }
670141cc406Sopenharmony_ci	  s->ld.lmod3 = -1;
671141cc406Sopenharmony_ci	  s->ld.ld_line = 0;
672141cc406Sopenharmony_ci	}
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci      /* Get image status (necessary to start new block) */
675141cc406Sopenharmony_ci      len = sizeof (buffer);
676141cc406Sopenharmony_ci      status = dev_cmd (s, scsi_get_image_status,
677141cc406Sopenharmony_ci			sizeof (scsi_get_image_status), buffer, &len);
678141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
679141cc406Sopenharmony_ci	return status;
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ci      /* tell scanner how many lines to scan in one block */
682141cc406Sopenharmony_ci      memset (buffer, 0, sizeof (buffer));
683141cc406Sopenharmony_ci      buffer[0] = MUSTEK_SCSI_READ_SCANNED_DATA;
684141cc406Sopenharmony_ci      buffer[2] = (lines >> 16) & 0xff;
685141cc406Sopenharmony_ci      buffer[3] = (lines >> 8) & 0xff;
686141cc406Sopenharmony_ci      buffer[4] = (lines >> 0) & 0xff;
687141cc406Sopenharmony_ci      buffer[5] = 0x04;
688141cc406Sopenharmony_ci      return sanei_scsi_cmd (s->fd, buffer, sizeof (buffer), 0, 0);
689141cc406Sopenharmony_ci    }
690141cc406Sopenharmony_ci  else
691141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
692141cc406Sopenharmony_ci}
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_cistatic SANE_Status
695141cc406Sopenharmony_cidev_read_req_enter (Mustek_Scanner * s, SANE_Byte * buf, SANE_Int lines,
696141cc406Sopenharmony_ci		    SANE_Int bpl, size_t * lenp, void **idp, SANE_Int bank,
697141cc406Sopenharmony_ci		    SANE_Byte * command)
698141cc406Sopenharmony_ci{
699141cc406Sopenharmony_ci  *lenp = lines * bpl;
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
702141cc406Sopenharmony_ci    {
703141cc406Sopenharmony_ci      SANE_Int planes;
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci      *idp = 0;
706141cc406Sopenharmony_ci      planes = (s->mode & MUSTEK_MODE_COLOR) ? 3 : 1;
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci      return sanei_ab306_rdata (s->fd, planes, buf, lines, bpl);
709141cc406Sopenharmony_ci    }
710141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP)
711141cc406Sopenharmony_ci    {
712141cc406Sopenharmony_ci      SANE_Int planes;
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci      *idp = 0;
715141cc406Sopenharmony_ci      planes = (s->mode & MUSTEK_MODE_COLOR) ? 3 : 1;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci      return mustek_scsi_pp_rdata (s->fd, planes, buf, lines, bpl);
718141cc406Sopenharmony_ci    }
719141cc406Sopenharmony_ci  else
720141cc406Sopenharmony_ci    {
721141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_SE)
722141cc406Sopenharmony_ci	{
723141cc406Sopenharmony_ci	  if (s->mode & MUSTEK_MODE_COLOR)
724141cc406Sopenharmony_ci	    lines *= 3;
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci	  memset (command, 0, 10);
727141cc406Sopenharmony_ci	  command[0] = MUSTEK_SCSI_READ_DATA;
728141cc406Sopenharmony_ci	  command[6] = bank;	/* buffer bank not used ??? */
729141cc406Sopenharmony_ci	  command[7] = (lines >> 8) & 0xff;
730141cc406Sopenharmony_ci	  command[8] = (lines >> 0) & 0xff;
731141cc406Sopenharmony_ci	  return sanei_scsi_req_enter (s->fd, command, 10, buf, lenp, idp);
732141cc406Sopenharmony_ci	}
733141cc406Sopenharmony_ci      else if (s->hw->flags & MUSTEK_FLAG_PRO)
734141cc406Sopenharmony_ci	{
735141cc406Sopenharmony_ci	  memset (command, 0, 6);
736141cc406Sopenharmony_ci	  command[0] = MUSTEK_SCSI_READ_SCANNED_DATA;
737141cc406Sopenharmony_ci	  command[2] = ((lines * bpl) >> 16) & 0xff;
738141cc406Sopenharmony_ci	  command[3] = ((lines * bpl) >> 8) & 0xff;
739141cc406Sopenharmony_ci	  command[4] = ((lines * bpl) >> 0) & 0xff;
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci	  return sanei_scsi_req_enter (s->fd, command, 6, buf, lenp, idp);
742141cc406Sopenharmony_ci	}
743141cc406Sopenharmony_ci      else			/* Paragon series */
744141cc406Sopenharmony_ci	{
745141cc406Sopenharmony_ci	  memset (command, 0, 6);
746141cc406Sopenharmony_ci	  command[0] = MUSTEK_SCSI_READ_SCANNED_DATA;
747141cc406Sopenharmony_ci	  command[2] = (lines >> 16) & 0xff;
748141cc406Sopenharmony_ci	  command[3] = (lines >> 8) & 0xff;
749141cc406Sopenharmony_ci	  command[4] = (lines >> 0) & 0xff;
750141cc406Sopenharmony_ci	  return sanei_scsi_req_enter (s->fd, command, 6, buf, lenp, idp);
751141cc406Sopenharmony_ci	}
752141cc406Sopenharmony_ci    }
753141cc406Sopenharmony_ci}
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_cistatic void
756141cc406Sopenharmony_cidev_close (Mustek_Scanner * s)
757141cc406Sopenharmony_ci{
758141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
759141cc406Sopenharmony_ci    sanei_ab306_close (s->fd);
760141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_SCSI_PP)
761141cc406Sopenharmony_ci    mustek_scsi_pp_close (s->fd);
762141cc406Sopenharmony_ci  else
763141cc406Sopenharmony_ci    sanei_scsi_close (s->fd);
764141cc406Sopenharmony_ci}
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_cistatic SANE_Status
767141cc406Sopenharmony_cisense_handler (SANE_Int scsi_fd, SANE_Byte * result, void *arg)
768141cc406Sopenharmony_ci{
769141cc406Sopenharmony_ci  if (!result)
770141cc406Sopenharmony_ci    {
771141cc406Sopenharmony_ci      DBG (5, "sense_handler: no sense buffer\n");
772141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
773141cc406Sopenharmony_ci    }
774141cc406Sopenharmony_ci  if (!arg)
775141cc406Sopenharmony_ci    DBG (5, "sense_handler: got sense code %02x for fd %d (arg = null)\n",
776141cc406Sopenharmony_ci	 result[0], scsi_fd);
777141cc406Sopenharmony_ci  else
778141cc406Sopenharmony_ci    DBG (5, "sense_handler: got sense code %02x for fd %d (arg = %uc)\n",
779141cc406Sopenharmony_ci	 result[0], scsi_fd, *(SANE_Byte *) arg);
780141cc406Sopenharmony_ci  switch (result[0])
781141cc406Sopenharmony_ci    {
782141cc406Sopenharmony_ci    case 0x00:
783141cc406Sopenharmony_ci      break;
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci    case 0x82:
786141cc406Sopenharmony_ci      if (result[1] & 0x80)
787141cc406Sopenharmony_ci	{
788141cc406Sopenharmony_ci	  DBG (3, "sense_handler: ADF is jammed\n");
789141cc406Sopenharmony_ci	  return SANE_STATUS_JAMMED;	/* ADF is jammed */
790141cc406Sopenharmony_ci	}
791141cc406Sopenharmony_ci      break;
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci    case 0x83:
794141cc406Sopenharmony_ci      if (result[2] & 0x02)
795141cc406Sopenharmony_ci	{
796141cc406Sopenharmony_ci	  DBG (3, "sense_handler: ADF is out of documents\n");
797141cc406Sopenharmony_ci	  return SANE_STATUS_NO_DOCS;	/* ADF out of documents */
798141cc406Sopenharmony_ci	}
799141cc406Sopenharmony_ci      break;
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ci    case 0x84:
802141cc406Sopenharmony_ci      if (result[1] & 0x10)
803141cc406Sopenharmony_ci	{
804141cc406Sopenharmony_ci	  DBG (3, "sense_handler: transparency adapter cover open\n");
805141cc406Sopenharmony_ci	  return SANE_STATUS_COVER_OPEN;	/* open transparency adapter cover */
806141cc406Sopenharmony_ci	}
807141cc406Sopenharmony_ci      break;
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci    default:
810141cc406Sopenharmony_ci      DBG (1, "sense_handler: got unknown sense code %02x for fd %d\n",
811141cc406Sopenharmony_ci	   result[0], scsi_fd);
812141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
813141cc406Sopenharmony_ci    }
814141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
815141cc406Sopenharmony_ci}
816141cc406Sopenharmony_ci
817141cc406Sopenharmony_cistatic SANE_Status
818141cc406Sopenharmony_ciinquiry (Mustek_Scanner * s)
819141cc406Sopenharmony_ci{
820141cc406Sopenharmony_ci  SANE_Byte result[INQ_LEN];
821141cc406Sopenharmony_ci  size_t size;
822141cc406Sopenharmony_ci  SANE_Status status;
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci  DBG (5, "inquiry: sending INQUIRY\n");
825141cc406Sopenharmony_ci  size = sizeof (result);
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci  memset (result, 0, size);
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  status = dev_cmd (s, scsi_inquiry, sizeof (scsi_inquiry), result, &size);
830141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
831141cc406Sopenharmony_ci    return status;
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  /* checking ADF status */
834141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_ADF)
835141cc406Sopenharmony_ci    {
836141cc406Sopenharmony_ci      if (result[63] & (1 << 3))
837141cc406Sopenharmony_ci	{
838141cc406Sopenharmony_ci	  s->hw->flags |= MUSTEK_FLAG_ADF_READY;
839141cc406Sopenharmony_ci	  DBG (4, "inquiry: ADF ready\n");
840141cc406Sopenharmony_ci	}
841141cc406Sopenharmony_ci      else
842141cc406Sopenharmony_ci	{
843141cc406Sopenharmony_ci	  s->hw->flags &= ~MUSTEK_FLAG_ADF_READY;
844141cc406Sopenharmony_ci	  DBG (4, "inquiry: ADF not ready (out of paper)\n");
845141cc406Sopenharmony_ci	}
846141cc406Sopenharmony_ci    }
847141cc406Sopenharmony_ci  if (!result[0])
848141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
849141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
850141cc406Sopenharmony_ci}
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_cistatic SANE_Status
853141cc406Sopenharmony_ciparagon_2_get_adf_status (Mustek_Scanner * s)
854141cc406Sopenharmony_ci{
855141cc406Sopenharmony_ci  SANE_Status status;
856141cc406Sopenharmony_ci  size_t len;
857141cc406Sopenharmony_ci  SANE_Byte sense_buffer[4];
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci  len = sizeof (sense_buffer);
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, scsi_request_sense,
862141cc406Sopenharmony_ci			   sizeof (scsi_request_sense), sense_buffer, &len);
863141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
864141cc406Sopenharmony_ci    {
865141cc406Sopenharmony_ci      DBG (1, "paragon_2_get_adf_status: %s\n", sane_strstatus (status));
866141cc406Sopenharmony_ci      return status;
867141cc406Sopenharmony_ci    }
868141cc406Sopenharmony_ci  DBG (5, "paragon_2_get_adf_status: sense_buffer: %x %x %x %x\n",
869141cc406Sopenharmony_ci       sense_buffer[0], sense_buffer[1], sense_buffer[3], sense_buffer[3]);
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci  if (sense_buffer[0] == 0x00 && sense_buffer[1] == 0x00)
872141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ci  return SANE_STATUS_NO_DOCS;
875141cc406Sopenharmony_ci}
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_cistatic SANE_Bool
878141cc406Sopenharmony_cita_available_pro (Mustek_Scanner * s)
879141cc406Sopenharmony_ci{
880141cc406Sopenharmony_ci  SANE_Status status;
881141cc406Sopenharmony_ci  size_t len;
882141cc406Sopenharmony_ci  SANE_Byte sense_buffer[4];
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci  len = sizeof (sense_buffer);
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, scsi_request_sense,
887141cc406Sopenharmony_ci			   sizeof (scsi_request_sense), sense_buffer, &len);
888141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
889141cc406Sopenharmony_ci    {
890141cc406Sopenharmony_ci      DBG (1, "ta_available_pro: failed: %s\n", sane_strstatus (status));
891141cc406Sopenharmony_ci      return status;
892141cc406Sopenharmony_ci    }
893141cc406Sopenharmony_ci  DBG (5, "ta_available_pro: sense_buffer[2] = %x\n", sense_buffer[2]);
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci  scsi_unit_wait_ready (s);
896141cc406Sopenharmony_ci  if (sense_buffer[2] == 0x40)
897141cc406Sopenharmony_ci    return SANE_TRUE;
898141cc406Sopenharmony_ci
899141cc406Sopenharmony_ci  return SANE_FALSE;
900141cc406Sopenharmony_ci}
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_cistatic SANE_Status
903141cc406Sopenharmony_ciattach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait)
904141cc406Sopenharmony_ci{
905141cc406Sopenharmony_ci  SANE_Int mustek_scanner, fw_revision;
906141cc406Sopenharmony_ci  SANE_Byte result[INQ_LEN];
907141cc406Sopenharmony_ci  SANE_Byte inquiry_byte_list[50], inquiry_text_list[17];
908141cc406Sopenharmony_ci  SANE_Byte inquiry_byte[5], inquiry_text[5];
909141cc406Sopenharmony_ci  SANE_Byte *model_name = result + 44;
910141cc406Sopenharmony_ci  Mustek_Scanner s;
911141cc406Sopenharmony_ci  Mustek_Device *dev, new_dev;
912141cc406Sopenharmony_ci  SANE_Status status;
913141cc406Sopenharmony_ci  size_t size;
914141cc406Sopenharmony_ci  SANE_String scsi_device_type[] = {
915141cc406Sopenharmony_ci    "Direct-Access", "Sequential-Access", "Printer", "Processor",
916141cc406Sopenharmony_ci    "Write-Once", "CD-ROM", "Scanner", "Optical Memory", "Medium Changer",
917141cc406Sopenharmony_ci    "Communications"
918141cc406Sopenharmony_ci  };
919141cc406Sopenharmony_ci  SANE_Byte scsi_vendor[9];
920141cc406Sopenharmony_ci  SANE_Byte scsi_product[17];
921141cc406Sopenharmony_ci  SANE_Byte scsi_revision[5];
922141cc406Sopenharmony_ci  SANE_Byte *pp;
923141cc406Sopenharmony_ci  SANE_Bool warning = SANE_FALSE;
924141cc406Sopenharmony_ci  SANE_Int firmware_format = 0;
925141cc406Sopenharmony_ci  SANE_Int firmware_revision_system = 0;
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci  if (devp)
928141cc406Sopenharmony_ci    *devp = 0;
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
931141cc406Sopenharmony_ci    if (strcmp (dev->sane.name, devname) == 0)
932141cc406Sopenharmony_ci      {
933141cc406Sopenharmony_ci	if (devp)
934141cc406Sopenharmony_ci	  *devp = dev;
935141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
936141cc406Sopenharmony_ci      }
937141cc406Sopenharmony_ci
938141cc406Sopenharmony_ci  memset (&new_dev, 0, sizeof (new_dev));
939141cc406Sopenharmony_ci  memset (&s, 0, sizeof (s));
940141cc406Sopenharmony_ci  s.hw = &new_dev;
941141cc406Sopenharmony_ci  s.hw->max_buffer_size = 8 * 1024;
942141cc406Sopenharmony_ci
943141cc406Sopenharmony_ci  DBG (3, "attach: trying device %s\n", devname);
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci  status = dev_open (devname, &s, sense_handler);
946141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
947141cc406Sopenharmony_ci    return status;
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_ci  if (may_wait || force_wait)
950141cc406Sopenharmony_ci    dev_wait_ready (&s);
951141cc406Sopenharmony_ci
952141cc406Sopenharmony_ci  DBG (5, "attach: sending INQUIRY\n");
953141cc406Sopenharmony_ci  size = sizeof (result);
954141cc406Sopenharmony_ci  memset (result, 0, sizeof (result));
955141cc406Sopenharmony_ci  status = dev_cmd (&s, scsi_inquiry, sizeof (scsi_inquiry), result, &size);
956141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size != INQ_LEN)
957141cc406Sopenharmony_ci    {
958141cc406Sopenharmony_ci      DBG (1, "attach: inquiry for device %s failed (%s)\n", devname,
959141cc406Sopenharmony_ci	   sane_strstatus (status));
960141cc406Sopenharmony_ci      dev_close (&s);
961141cc406Sopenharmony_ci      return status;
962141cc406Sopenharmony_ci    }
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci  status = dev_wait_ready (&s);
965141cc406Sopenharmony_ci  dev_close (&s);
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
968141cc406Sopenharmony_ci    return status;
969141cc406Sopenharmony_ci
970141cc406Sopenharmony_ci  if ((result[0] & 0x1f) != 0x06)
971141cc406Sopenharmony_ci    {
972141cc406Sopenharmony_ci      DBG (1, "attach: device %s doesn't look like a scanner at all (%d)\n",
973141cc406Sopenharmony_ci	   devname, result[0] & 0x1f);
974141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
975141cc406Sopenharmony_ci    }
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci  if (debug_level >= 3)
978141cc406Sopenharmony_ci    {
979141cc406Sopenharmony_ci      /* clear spaces and special chars */
980141cc406Sopenharmony_ci      strncpy ((SANE_String) scsi_vendor, (SANE_String) result + 8, 8);
981141cc406Sopenharmony_ci      scsi_vendor[8] = '\0';
982141cc406Sopenharmony_ci      pp = scsi_vendor + 7;
983141cc406Sopenharmony_ci      while (pp >= scsi_vendor && (*pp == ' ' || *pp >= 127))
984141cc406Sopenharmony_ci	*pp-- = '\0';
985141cc406Sopenharmony_ci      strncpy ((SANE_String) scsi_product, (SANE_String) result + 16, 16);
986141cc406Sopenharmony_ci      scsi_product[16] = '\0';
987141cc406Sopenharmony_ci      pp = scsi_product + 15;
988141cc406Sopenharmony_ci      while (pp >= scsi_product && (*pp == ' ' || *pp >= 127))
989141cc406Sopenharmony_ci	*pp-- = '\0';
990141cc406Sopenharmony_ci      strncpy ((SANE_String) scsi_revision, (SANE_String) result + 32, 4);
991141cc406Sopenharmony_ci      scsi_revision[4] = '\0';
992141cc406Sopenharmony_ci      pp = scsi_revision + 3;
993141cc406Sopenharmony_ci      while (pp >= scsi_revision && (*pp == ' ' || *pp >= 127))
994141cc406Sopenharmony_ci	*pp-- = '\0';
995141cc406Sopenharmony_ci      DBG (3, "attach: SCSI Vendor: `%-8s' Model: `%-16s' Rev.: `%-4s'\n",
996141cc406Sopenharmony_ci	   scsi_vendor, scsi_product, scsi_revision);
997141cc406Sopenharmony_ci      DBG (3, "attach: SCSI Type: %s; ANSI rev.: %d\n",
998141cc406Sopenharmony_ci	   ((result[0] & 0x1f) < 0x10) ?
999141cc406Sopenharmony_ci	   scsi_device_type[result[0] & 0x1f] : "Unknown", result[2] & 0x03);
1000141cc406Sopenharmony_ci      DBG (3, "attach: SCSI flags: %s%s%s%s%s%s%s\n",
1001141cc406Sopenharmony_ci	   (result[7] & 0x80) ? "RelAdr " : "",
1002141cc406Sopenharmony_ci	   (result[7] & 0x40) ? "WBus32 " : "",
1003141cc406Sopenharmony_ci	   (result[7] & 0x20) ? "WBus16 " : "",
1004141cc406Sopenharmony_ci	   (result[7] & 0x10) ? "Sync " : "",
1005141cc406Sopenharmony_ci	   (result[7] & 0x08) ? "Linked " : "",
1006141cc406Sopenharmony_ci	   (result[7] & 0x02) ? "CmdQue " : "",
1007141cc406Sopenharmony_ci	   (result[7] & 0x01) ? "SftRe " : "");
1008141cc406Sopenharmony_ci    }
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci  if (debug_level >= 4)
1011141cc406Sopenharmony_ci    {
1012141cc406Sopenharmony_ci      /* print out inquiry */
1013141cc406Sopenharmony_ci      DBG (4, "attach: inquiry output:\n");
1014141cc406Sopenharmony_ci      inquiry_byte_list[0] = '\0';
1015141cc406Sopenharmony_ci      inquiry_text_list[0] = '\0';
1016141cc406Sopenharmony_ci      for (pp = result; pp < (result + INQ_LEN); pp++)
1017141cc406Sopenharmony_ci	{
1018141cc406Sopenharmony_ci	  sprintf ((SANE_String) inquiry_text, "%c",
1019141cc406Sopenharmony_ci		   (*pp < 127) && (*pp > 31) ? *pp : '.');
1020141cc406Sopenharmony_ci	  strcat ((SANE_String) inquiry_text_list,
1021141cc406Sopenharmony_ci		  (SANE_String) inquiry_text);
1022141cc406Sopenharmony_ci	  sprintf ((SANE_String) inquiry_byte, " %02x", *pp);
1023141cc406Sopenharmony_ci	  strcat ((SANE_String) inquiry_byte_list,
1024141cc406Sopenharmony_ci		  (SANE_String) inquiry_byte);
1025141cc406Sopenharmony_ci	  if ((pp - result) % 0x10 == 0x0f)
1026141cc406Sopenharmony_ci	    {
1027141cc406Sopenharmony_ci	      DBG (4, "%s  %s\n", inquiry_byte_list, inquiry_text_list);
1028141cc406Sopenharmony_ci	      inquiry_byte_list[0] = '\0';
1029141cc406Sopenharmony_ci	      inquiry_text_list[0] = '\0';
1030141cc406Sopenharmony_ci	    }
1031141cc406Sopenharmony_ci	}
1032141cc406Sopenharmony_ci    }
1033141cc406Sopenharmony_ci
1034141cc406Sopenharmony_ci  /* first check for new firmware format: */
1035141cc406Sopenharmony_ci  mustek_scanner = (strncmp ((SANE_String) result + 36, "MUSTEK", 6) == 0);
1036141cc406Sopenharmony_ci  if (mustek_scanner)
1037141cc406Sopenharmony_ci    {
1038141cc406Sopenharmony_ci      if (result[43] == 'M')
1039141cc406Sopenharmony_ci	{
1040141cc406Sopenharmony_ci	  DBG (3, "attach: found Mustek scanner (pro series firmware "
1041141cc406Sopenharmony_ci	       "format)\n");
1042141cc406Sopenharmony_ci	  firmware_format = 2;
1043141cc406Sopenharmony_ci	  model_name = result + 43;
1044141cc406Sopenharmony_ci	}
1045141cc406Sopenharmony_ci      else
1046141cc406Sopenharmony_ci	{
1047141cc406Sopenharmony_ci	  DBG (3, "attach: found Mustek scanner (new firmware format)\n");
1048141cc406Sopenharmony_ci	  firmware_format = 1;
1049141cc406Sopenharmony_ci	}
1050141cc406Sopenharmony_ci    }
1051141cc406Sopenharmony_ci  else
1052141cc406Sopenharmony_ci    {
1053141cc406Sopenharmony_ci      /* check for old format: */
1054141cc406Sopenharmony_ci      mustek_scanner = (strncmp ((SANE_String) result + 8, "MUSTEK", 6) == 0);
1055141cc406Sopenharmony_ci      if (mustek_scanner)
1056141cc406Sopenharmony_ci	{
1057141cc406Sopenharmony_ci	  model_name = result + 16;
1058141cc406Sopenharmony_ci	  DBG (3, "attach: found Mustek scanner (old firmware format)\n");
1059141cc406Sopenharmony_ci	  firmware_format = 0;
1060141cc406Sopenharmony_ci	}
1061141cc406Sopenharmony_ci      else
1062141cc406Sopenharmony_ci	{
1063141cc406Sopenharmony_ci	  /* Check for some non-Mustek scanners an print warning */
1064141cc406Sopenharmony_ci	  if (strncmp ((SANE_String) result + 8, "Trust", 5) == 0)
1065141cc406Sopenharmony_ci	    DBG (1, "attach: this is a real Trust scanner. It is not "
1066141cc406Sopenharmony_ci		 " supported by this backend.\n");
1067141cc406Sopenharmony_ci	  if (strncmp ((SANE_String) result + 8, "Aashima", 7) == 0)
1068141cc406Sopenharmony_ci	    DBG (1, "attach: this is an Aashima/Teco scanner. It is not "
1069141cc406Sopenharmony_ci		 " supported by this backend.\n");
1070141cc406Sopenharmony_ci	  if (strncmp ((SANE_String) result + 16, "Flatbed Scanner", 15) == 0
1071141cc406Sopenharmony_ci	      && strncmp ((SANE_String) result + 42, "TECO", 4) == 0)
1072141cc406Sopenharmony_ci	    DBG (1, "attach: this is a Relysis/Teco scanner. It is not "
1073141cc406Sopenharmony_ci		 " supported by this backend.\n");
1074141cc406Sopenharmony_ci	  DBG (1, "attach: device %s doesn't look like a Mustek scanner\n",
1075141cc406Sopenharmony_ci	       devname);
1076141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1077141cc406Sopenharmony_ci	}
1078141cc406Sopenharmony_ci    }
1079141cc406Sopenharmony_ci
1080141cc406Sopenharmony_ci  /* get firmware revision as BCD number:             */
1081141cc406Sopenharmony_ci  /* General format: x.yz                             */
1082141cc406Sopenharmony_ci  /* Newer ScanExpress scanners (ID XC06): Vxyz       */
1083141cc406Sopenharmony_ci  if (result[33] == '.')
1084141cc406Sopenharmony_ci    {
1085141cc406Sopenharmony_ci      fw_revision =
1086141cc406Sopenharmony_ci	(result[32] - '0') << 8 | (result[34] - '0') << 4 | (result[35] -
1087141cc406Sopenharmony_ci							     '0');
1088141cc406Sopenharmony_ci      firmware_revision_system = 0;
1089141cc406Sopenharmony_ci      DBG (4, "attach: old firmware revision system\n");
1090141cc406Sopenharmony_ci    }
1091141cc406Sopenharmony_ci  else
1092141cc406Sopenharmony_ci    {
1093141cc406Sopenharmony_ci      fw_revision =
1094141cc406Sopenharmony_ci	(result[33] - '0') << 8 | (result[34] - '0') << 4 | (result[35] -
1095141cc406Sopenharmony_ci							     '0');
1096141cc406Sopenharmony_ci      firmware_revision_system = 1;
1097141cc406Sopenharmony_ci      DBG (4, "attach: new firmware revision system\n");
1098141cc406Sopenharmony_ci    }
1099141cc406Sopenharmony_ci  DBG (3, "attach: firmware revision %d.%02x\n",
1100141cc406Sopenharmony_ci       fw_revision >> 8, fw_revision & 0xff);
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
1103141cc406Sopenharmony_ci  if (!dev)
1104141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1105141cc406Sopenharmony_ci
1106141cc406Sopenharmony_ci  memcpy (dev, &new_dev, sizeof (*dev));
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci  dev->name = strdup (devname);
1109141cc406Sopenharmony_ci  if (!dev->name)
1110141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1111141cc406Sopenharmony_ci  dev->sane.name = (SANE_String_Const) dev->name;
1112141cc406Sopenharmony_ci  dev->sane.vendor = "Mustek";
1113141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  dev->x_range.min = 0;
1116141cc406Sopenharmony_ci  dev->y_range.min = 0;
1117141cc406Sopenharmony_ci  dev->x_range.quant = 0;
1118141cc406Sopenharmony_ci  dev->y_range.quant = 0;
1119141cc406Sopenharmony_ci  dev->x_trans_range.min = 0;
1120141cc406Sopenharmony_ci  dev->y_trans_range.min = 0;
1121141cc406Sopenharmony_ci  /* default to something really small to be on the safe side: */
1122141cc406Sopenharmony_ci  dev->x_trans_range.max = SANE_FIX (8.0 * MM_PER_INCH);
1123141cc406Sopenharmony_ci  dev->y_trans_range.max = SANE_FIX (5.0 * MM_PER_INCH);
1124141cc406Sopenharmony_ci  dev->x_trans_range.quant = 0;
1125141cc406Sopenharmony_ci  dev->y_trans_range.quant = 0;
1126141cc406Sopenharmony_ci  dev->dpi_range.min = SANE_FIX (72);	/* some scanners don't like low dpi */
1127141cc406Sopenharmony_ci  dev->dpi_range.quant = SANE_FIX (1);
1128141cc406Sopenharmony_ci  /* default to 128 kB */
1129141cc406Sopenharmony_ci  dev->max_buffer_size = 128 * 1024;	/* SCSI buffer -> use 64 k per buffer */
1130141cc406Sopenharmony_ci  dev->max_block_buffer_size = 1024 * 1024 * 1024;
1131141cc406Sopenharmony_ci  dev->firmware_format = firmware_format;
1132141cc406Sopenharmony_ci  dev->firmware_revision_system = firmware_revision_system;
1133141cc406Sopenharmony_ci
1134141cc406Sopenharmony_ci  DBG (3, "attach: scanner id: %.11s\n", model_name);
1135141cc406Sopenharmony_ci  if (strncmp ((SANE_String) model_name + 10, "PRO", 3) == 0)
1136141cc406Sopenharmony_ci    DBG (3, "attach: this is probably a Paragon Pro series scanner\n");
1137141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFC", 3) == 0)
1138141cc406Sopenharmony_ci    DBG (3, "attach: this is probably a Paragon series II scanner\n");
1139141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "M", 1) == 0)
1140141cc406Sopenharmony_ci    DBG (3,
1141141cc406Sopenharmony_ci	 "attach: this is probably a Paragon series I or 3-pass scanner\n");
1142141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, " C", 2) == 0)
1143141cc406Sopenharmony_ci    DBG (3, "attach: this is probably a ScanExpress series A4 scanner\n");
1144141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, " L", 2) == 0)
1145141cc406Sopenharmony_ci    DBG (3, "attach: this is probably a ScanExpress series A3 scanner\n");
1146141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "XC", 2) == 0)
1147141cc406Sopenharmony_ci    DBG (3,
1148141cc406Sopenharmony_ci	 "attach: this is probably a ScanExpress Plus series A4 scanner\n");
1149141cc406Sopenharmony_ci  else
1150141cc406Sopenharmony_ci    DBG (3, "attach: I am not sure what type of scanner this is\n");
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci  /* Paragon 3-pass series */
1153141cc406Sopenharmony_ci  if (strncmp ((SANE_String) model_name, "MFS-12000CX", 11) == 0)
1154141cc406Sopenharmony_ci    {
1155141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1156141cc406Sopenharmony_ci         driver. Tested with a Paragon MFS-12000CX v4.00 */
1157141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1158141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1159141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1160141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (14.00 * MM_PER_INCH);
1161141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1162141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1163141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1164141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1165141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1166141cc406Sopenharmony_ci      dev->sane.model = "MFS-12000CX";
1167141cc406Sopenharmony_ci    }
1168141cc406Sopenharmony_ci  /* There are two different versions of the MFS-6000CX, one has the model
1169141cc406Sopenharmony_ci     name "MFS-06000CX", the other one is "MSF-06000CZ"   */
1170141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-06000CX", 11) == 0)
1171141cc406Sopenharmony_ci    {
1172141cc406Sopenharmony_ci      /* These values were measured and tested with a Paragon MFS-6000CX
1173141cc406Sopenharmony_ci         v4.06 */
1174141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1175141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1176141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1177141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (13.86 * MM_PER_INCH);
1178141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1179141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (2.0);
1180141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (203.0);
1181141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1184141cc406Sopenharmony_ci      dev->sane.model = "MFS-6000CX";
1185141cc406Sopenharmony_ci    }
1186141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MSF-06000CZ", 11) == 0)
1187141cc406Sopenharmony_ci    {
1188141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1189141cc406Sopenharmony_ci         driver. Tested with a Paragon MFS-6000CX v4.00 */
1190141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1191141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1192141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1193141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (13.85 * MM_PER_INCH);
1194141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1195141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (2.0);
1196141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1197141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1200141cc406Sopenharmony_ci      dev->sane.model = "MFS-6000CX";
1201141cc406Sopenharmony_ci    }
1202141cc406Sopenharmony_ci
1203141cc406Sopenharmony_ci  /* Paragon 1-pass 14" series I */
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci  /* I haven't seen a single report for this, but it is mentioned in
1206141cc406Sopenharmony_ci     the old man page. All reported Paragon 1200SP had a model name
1207141cc406Sopenharmony_ci     "MFS-12000SP" */
1208141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MSF-12000SP", 11) == 0)
1209141cc406Sopenharmony_ci    {
1210141cc406Sopenharmony_ci      /* These values are not tested and mostly guessed. */
1211141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1212141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (13.85 * MM_PER_INCH);
1213141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1214141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1215141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (200.0);
1216141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (250.0);
1217141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1218141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_LD_NONE;
1219141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1220141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_USE_BLOCK;
1221141cc406Sopenharmony_ci      dev->sane.model = "MFS-12000SP";
1222141cc406Sopenharmony_ci      warning = SANE_TRUE;
1223141cc406Sopenharmony_ci    }
1224141cc406Sopenharmony_ci  /* MFS-8000 SP v 1.x */
1225141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MSF-08000SP", 11) == 0)
1226141cc406Sopenharmony_ci    {
1227141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1228141cc406Sopenharmony_ci         driver. Tested with a Paragon MFS-8000SP v1.20 */
1229141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1230141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1231141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0);
1232141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (355.6);
1233141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1234141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1235141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1236141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (800);
1239141cc406Sopenharmony_ci      /* At least scanners with firmware 1.20 need a gamma table upload
1240141cc406Sopenharmony_ci         in color mode, otherwise the image is red */
1241141cc406Sopenharmony_ci      if (fw_revision == 0x120)
1242141cc406Sopenharmony_ci	dev->flags |= MUSTEK_FLAG_FORCE_GAMMA;
1243141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1244141cc406Sopenharmony_ci      dev->sane.model = "MFS-8000SP";
1245141cc406Sopenharmony_ci    }
1246141cc406Sopenharmony_ci  /* This model name exists */
1247141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MSF-06000SP", 11) == 0)
1248141cc406Sopenharmony_ci    {
1249141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1250141cc406Sopenharmony_ci         driver. Tested with a Paragon MFS-6000SP v3.12 */
1251141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1252141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1253141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1254141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (355.6);
1255141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1256141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1257141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1258141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1259141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1260141cc406Sopenharmony_ci      /* Looks like at least some versions of this scanner produce black images
1261141cc406Sopenharmony_ci         in gray and color mode if MUSTEK_FORCE_GAMMA is not set. At least
1262141cc406Sopenharmony_ci         versions 2.01, 2.02 and 2.10 are reported as having this bug. 3.12
1263141cc406Sopenharmony_ci         doesn't need this workaround but it doesn't harm either. */
1264141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_FORCE_GAMMA;
1265141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1266141cc406Sopenharmony_ci      dev->sane.model = "MFS-6000SP";
1267141cc406Sopenharmony_ci    }
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci  /* This one was reported multiple times */
1270141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-12000SP", 11) == 0)
1271141cc406Sopenharmony_ci    {
1272141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1273141cc406Sopenharmony_ci         driver. Tested with a Paragon MFS-12000SP v1.02 and v1.00 */
1274141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1275141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (217.0);
1276141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (2.0);
1277141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (352.0);
1278141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0.0);
1279141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0.0);
1280141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1281141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (250.0);
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1284141cc406Sopenharmony_ci      /* Earlier versions of this source code used MUSTEK_FLAG_LD_MFS
1285141cc406Sopenharmony_ci         for firmware versions < 1.02 and LD_NONE for the rest. This
1286141cc406Sopenharmony_ci         didn't work for my scanners.  1.00 doesn't need any LD
1287141cc406Sopenharmony_ci         correction, 1.02, 1.07 and 1.11 do need normal LD
1288141cc406Sopenharmony_ci         corrections.  Maybe all != 1.00 need normal LD */
1289141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1290141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_LD_BLOCK;
1291141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_USE_BLOCK;
1292141cc406Sopenharmony_ci      dev->sane.model = "MFS-12000SP";
1293141cc406Sopenharmony_ci    }
1294141cc406Sopenharmony_ci  /* MFS-8000 SP v2.x */
1295141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-08000SP", 11) == 0)
1296141cc406Sopenharmony_ci    {
1297141cc406Sopenharmony_ci      /* These values are tested with a MFS-08000SP v 2.04 */
1298141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1299141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1300141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0);
1301141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (355.6);
1302141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1303141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1304141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1305141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1306141cc406Sopenharmony_ci
1307141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (800);
1308141cc406Sopenharmony_ci      /* At least scanners with firmware 1.20 need a gamma table upload
1309141cc406Sopenharmony_ci         in color mode, otherwise the image is red */
1310141cc406Sopenharmony_ci      if (fw_revision == 0x120)
1311141cc406Sopenharmony_ci	dev->flags |= MUSTEK_FLAG_FORCE_GAMMA;
1312141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1313141cc406Sopenharmony_ci      dev->sane.model = "MFS-8000SP";
1314141cc406Sopenharmony_ci    }
1315141cc406Sopenharmony_ci  /* I have never seen one of those */
1316141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-06000SP", 11) == 0)
1317141cc406Sopenharmony_ci    {
1318141cc406Sopenharmony_ci      /* These values are not tested. */
1319141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
1320141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (13.84 * MM_PER_INCH);
1321141cc406Sopenharmony_ci      /* copied from MSF-06000SP */
1322141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (1.0);
1323141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (1.0);
1324141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1325141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (255.0);
1326141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1327141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_1;
1328141cc406Sopenharmony_ci      dev->sane.model = "MFS-6000SP";
1329141cc406Sopenharmony_ci      warning = SANE_TRUE;
1330141cc406Sopenharmony_ci    }
1331141cc406Sopenharmony_ci
1332141cc406Sopenharmony_ci  /* Paragon 1-pass A4 series II */
1333141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFC-08000CZ", 11) == 0)
1334141cc406Sopenharmony_ci    {
1335141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1336141cc406Sopenharmony_ci         driver. Tested with a Paragon 800 II SP v1.06. */
1337141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (1.5);
1338141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (218.0);
1339141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1340141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (293.0);
1341141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0.0);
1342141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0.0);
1343141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (205.0);
1344141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (254.0);
1345141cc406Sopenharmony_ci
1346141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (800);
1347141cc406Sopenharmony_ci      dev->max_block_buffer_size = 2 * 1024 * 1024;
1348141cc406Sopenharmony_ci
1349141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_PARAGON_2;
1350141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_LD_BLOCK;
1351141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_USE_BLOCK;
1352141cc406Sopenharmony_ci      dev->sane.model = "800S/800 II SP";
1353141cc406Sopenharmony_ci    }
1354141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFC-06000CZ", 11) == 0)
1355141cc406Sopenharmony_ci    {
1356141cc406Sopenharmony_ci      /* These values were measured and compared to those from the
1357141cc406Sopenharmony_ci         Windows driver. Tested with a Paragon 600 II CD, a Paragon
1358141cc406Sopenharmony_ci         MFC-600S and a Paragon 600 II N. */
1359141cc406Sopenharmony_ci      dev->x_range.min = SANE_FIX (0.0);
1360141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (218.0);
1361141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0.0);
1362141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (293.0);
1363141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0.0);
1364141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0.0);
1365141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (201.0);
1366141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (257.0);
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1369141cc406Sopenharmony_ci      /* This model comes in a non-scsi version, too. It is supplied
1370141cc406Sopenharmony_ci         with its own parallel-port like adapter, an AB306N. Two
1371141cc406Sopenharmony_ci         firmware revisions are known: 1.01 and 2.00. Each needs its
1372141cc406Sopenharmony_ci         own line-distance correction code. */
1373141cc406Sopenharmony_ci      if (dev->flags & MUSTEK_FLAG_N)
1374141cc406Sopenharmony_ci	{
1375141cc406Sopenharmony_ci	  if (fw_revision < 0x200)
1376141cc406Sopenharmony_ci	    dev->flags |= MUSTEK_FLAG_LD_N1;
1377141cc406Sopenharmony_ci	  else
1378141cc406Sopenharmony_ci	    dev->flags |= MUSTEK_FLAG_LD_N2;
1379141cc406Sopenharmony_ci	  dev->x_trans_range.min = SANE_FIX (33.0);
1380141cc406Sopenharmony_ci	  dev->y_trans_range.min = SANE_FIX (62.0);
1381141cc406Sopenharmony_ci	  dev->x_trans_range.max = SANE_FIX (183.0);
1382141cc406Sopenharmony_ci	  dev->y_trans_range.max = SANE_FIX (238.0);
1383141cc406Sopenharmony_ci	  dev->max_block_buffer_size = 1024 * 1024 * 1024;
1384141cc406Sopenharmony_ci	  dev->sane.model = "600 II N";
1385141cc406Sopenharmony_ci	}
1386141cc406Sopenharmony_ci      else if (dev->flags & MUSTEK_FLAG_SCSI_PP)
1387141cc406Sopenharmony_ci	{
1388141cc406Sopenharmony_ci	  /* FIXME; experiment with different line distance codes later */
1389141cc406Sopenharmony_ci	  dev->dpi_range.min = SANE_FIX (75.0);
1390141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_LD_NONE;
1391141cc406Sopenharmony_ci	  dev->max_block_buffer_size = 2 * 1024 * 1024;
1392141cc406Sopenharmony_ci	  dev->sane.model = "600 II EP";
1393141cc406Sopenharmony_ci	}
1394141cc406Sopenharmony_ci      else
1395141cc406Sopenharmony_ci	{
1396141cc406Sopenharmony_ci	  dev->sane.model = "600S/600 II CD";
1397141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_PARAGON_2;
1398141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_LD_BLOCK;
1399141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_USE_BLOCK;
1400141cc406Sopenharmony_ci	  dev->max_block_buffer_size = 2 * 1024 * 1024;
1401141cc406Sopenharmony_ci	}
1402141cc406Sopenharmony_ci    }
1403141cc406Sopenharmony_ci
1404141cc406Sopenharmony_ci  /* ScanExpress and ScanMagic series */
1405141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, " C03", 4) == 0)
1406141cc406Sopenharmony_ci    {
1407141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1408141cc406Sopenharmony_ci         driver. Tested with a ScannExpress 6000SP 1.00 */
1409141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (215);
1410141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0);
1411141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (293);
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0);
1414141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0);
1415141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (150.0);
1416141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (175.0);
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1419141cc406Sopenharmony_ci      dev->dpi_range.min = SANE_FIX (60);
1420141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_SE;
1421141cc406Sopenharmony_ci      /* At least the SE 6000SP with firmware 1.00 limits its
1422141cc406Sopenharmony_ci         x-resolution to 300 dpi and does *no* interpolation at higher
1423141cc406Sopenharmony_ci         resolutions. So this has to be done in software. */
1424141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1425141cc406Sopenharmony_ci      dev->sane.model = "ScanExpress 6000SP";
1426141cc406Sopenharmony_ci    }
1427141cc406Sopenharmony_ci  /* There are two different versions of the ScanExpress 12000SP, one
1428141cc406Sopenharmony_ci     has the model name " C06", the other one is "XC06". The latter
1429141cc406Sopenharmony_ci     seems to be used in the newer "Plus" models.
1430141cc406Sopenharmony_ci     Also there is the Mustek ScanExpress 1200 FS, which looks similar to the
1431141cc406Sopenharmony_ci     ScanExpress 12000 SP but has an "F" instead of the "V" in the
1432141cc406Sopenharmony_ci     firmware version.
1433141cc406Sopenharmony_ci  */
1434141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, " C06", 4) == 0)
1435141cc406Sopenharmony_ci    {
1436141cc406Sopenharmony_ci      if (result[32] == 'F')
1437141cc406Sopenharmony_ci	{
1438141cc406Sopenharmony_ci	  /* Mustek ScanExpress 1200 FS. Completely untested. */
1439141cc406Sopenharmony_ci	  dev->x_range.min = SANE_FIX (0);
1440141cc406Sopenharmony_ci	  dev->y_range.min = SANE_FIX (0);
1441141cc406Sopenharmony_ci	  dev->x_range.max = SANE_FIX (215.9);
1442141cc406Sopenharmony_ci	  dev->y_range.max = SANE_FIX (291.2);
1443141cc406Sopenharmony_ci
1444141cc406Sopenharmony_ci	  dev->x_trans_range.min = SANE_FIX (0);
1445141cc406Sopenharmony_ci	  dev->y_trans_range.min = SANE_FIX (0);
1446141cc406Sopenharmony_ci	  dev->x_trans_range.max = SANE_FIX (150.0);
1447141cc406Sopenharmony_ci	  dev->y_trans_range.max = SANE_FIX (175.0);
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci	  dev->dpi_range.max = SANE_FIX (1200);
1450141cc406Sopenharmony_ci	  dev->dpi_range.min = SANE_FIX (60);
1451141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_SE;
1452141cc406Sopenharmony_ci	  /* The ScanExpress models limit their x-resolution to 600 dpi
1453141cc406Sopenharmony_ci	     and do *no* interpolation at higher resolutions. So this has
1454141cc406Sopenharmony_ci	     to be done in software. */
1455141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1456141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_COVER_SENSOR;
1457141cc406Sopenharmony_ci	  dev->sane.model = "ScanExpress 12000 FS (untested)";
1458141cc406Sopenharmony_ci	}
1459141cc406Sopenharmony_ci      else
1460141cc406Sopenharmony_ci	{
1461141cc406Sopenharmony_ci	  /* These values were measured and compared to those from the Windows
1462141cc406Sopenharmony_ci	     driver. Tested with a ScaneExpress 12000SP 2.02 and a ScanMagic
1463141cc406Sopenharmony_ci	     9636S v 1.01 */
1464141cc406Sopenharmony_ci	  dev->x_range.min = SANE_FIX (0);
1465141cc406Sopenharmony_ci	  dev->y_range.min = SANE_FIX (0);
1466141cc406Sopenharmony_ci	  dev->x_range.max = SANE_FIX (215.9);
1467141cc406Sopenharmony_ci	  dev->y_range.max = SANE_FIX (291.2);
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci	  dev->x_trans_range.min = SANE_FIX (0);
1470141cc406Sopenharmony_ci	  dev->y_trans_range.min = SANE_FIX (0);
1471141cc406Sopenharmony_ci	  dev->x_trans_range.max = SANE_FIX (150.0);
1472141cc406Sopenharmony_ci	  dev->y_trans_range.max = SANE_FIX (175.0);
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci	  dev->dpi_range.max = SANE_FIX (1200);
1475141cc406Sopenharmony_ci	  dev->dpi_range.min = SANE_FIX (60);
1476141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_SE;
1477141cc406Sopenharmony_ci	  /* The ScanExpress models limit their x-resolution to 600 dpi
1478141cc406Sopenharmony_ci	     and do *no* interpolation at higher resolutions. So this has
1479141cc406Sopenharmony_ci	     to be done in software. */
1480141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1481141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_COVER_SENSOR;
1482141cc406Sopenharmony_ci	  dev->sane.model = "ScanExpress 12000SP";
1483141cc406Sopenharmony_ci	}
1484141cc406Sopenharmony_ci    }
1485141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "XC06", 4) == 0)
1486141cc406Sopenharmony_ci    {
1487141cc406Sopenharmony_ci      /* These values are tested with a SE 12000 SP Plus v 1.01 */
1488141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (216);
1489141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0);
1490141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (294.5);
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0);
1493141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0);
1494141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (152.0);
1495141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (177.0);
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1498141cc406Sopenharmony_ci      dev->dpi_range.min = SANE_FIX (60);
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_SE;
1501141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_SE_PLUS;
1502141cc406Sopenharmony_ci      /* The ScanExpress models limit their x-resolution to 600 dpi
1503141cc406Sopenharmony_ci         and do *no* interpolation at higher resolutions. So this has
1504141cc406Sopenharmony_ci         to be done in software. */
1505141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1506141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_COVER_SENSOR;
1507141cc406Sopenharmony_ci      dev->sane.model = "ScanExpress 12000SP Plus";
1508141cc406Sopenharmony_ci    }
1509141cc406Sopenharmony_ci  /* ScanExpress A3 SP */
1510141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, " L03", 4) == 0)
1511141cc406Sopenharmony_ci    {
1512141cc406Sopenharmony_ci      /* These values were measured with a ScannExpress A3 SP 2.00 */
1513141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (297);
1514141cc406Sopenharmony_ci      dev->y_range.min = SANE_FIX (0);
1515141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (430);
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci      /* TA couldn't be tested due to lack of equipment. So At least
1518141cc406Sopenharmony_ci         the TA IV (A4 size) is supported */
1519141cc406Sopenharmony_ci      dev->x_trans_range.min = SANE_FIX (0);
1520141cc406Sopenharmony_ci      dev->y_trans_range.min = SANE_FIX (0);
1521141cc406Sopenharmony_ci      dev->x_trans_range.max = SANE_FIX (150.0);
1522141cc406Sopenharmony_ci      dev->y_trans_range.max = SANE_FIX (175.0);
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (600);
1525141cc406Sopenharmony_ci      dev->dpi_range.min = SANE_FIX (60);
1526141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_SE;
1527141cc406Sopenharmony_ci      /* The ScanExpress models limit their x-resolution to 300 dpi
1528141cc406Sopenharmony_ci         and do *no* interpolation at higher resolutions. So this has
1529141cc406Sopenharmony_ci         to be done in software. */
1530141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1531141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_COVER_SENSOR;
1532141cc406Sopenharmony_ci      dev->sane.model = "ScanExpress A3 SP";
1533141cc406Sopenharmony_ci    }
1534141cc406Sopenharmony_ci  /* Paragon 1200 SP Pro */
1535141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-1200SPPRO", 13) == 0)
1536141cc406Sopenharmony_ci    {
1537141cc406Sopenharmony_ci      /* These values were measured with a Paragon 1200 SP Pro v2.01 */
1538141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (8.6 * MM_PER_INCH);
1539141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (13.70 * MM_PER_INCH);
1540141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1541141cc406Sopenharmony_ci      dev->sane.model = "1200 SP PRO";
1542141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_LD_NONE;
1543141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1544141cc406Sopenharmony_ci    }
1545141cc406Sopenharmony_ci  /* No documentation, but it works: Paragon 1200 A3 PRO  */
1546141cc406Sopenharmony_ci  else if (strncmp ((SANE_String) model_name, "MFS-1200A3PRO", 13) == 0)
1547141cc406Sopenharmony_ci    {
1548141cc406Sopenharmony_ci      /* These values were measured and compared to those from the Windows
1549141cc406Sopenharmony_ci         driver. Tested with a Paragon 1200 A3 Pro v1.10 */
1550141cc406Sopenharmony_ci      dev->x_range.max = SANE_FIX (11.7 * MM_PER_INCH);
1551141cc406Sopenharmony_ci      dev->y_range.max = SANE_FIX (424);
1552141cc406Sopenharmony_ci      dev->dpi_range.max = SANE_FIX (1200);
1553141cc406Sopenharmony_ci      dev->sane.model = "1200 A3 PRO";
1554141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_LD_NONE;
1555141cc406Sopenharmony_ci      dev->flags |= MUSTEK_FLAG_ENLARGE_X;
1556141cc406Sopenharmony_ci    }
1557141cc406Sopenharmony_ci  else
1558141cc406Sopenharmony_ci    {
1559141cc406Sopenharmony_ci      DBG (0, "attach: this Mustek scanner (ID: %s) is not supported yet\n",
1560141cc406Sopenharmony_ci	   model_name);
1561141cc406Sopenharmony_ci      DBG (0, "attach: please set the debug level to 5 and send a debug "
1562141cc406Sopenharmony_ci	   "report\n");
1563141cc406Sopenharmony_ci      DBG (0, "attach: to henning@meier-geinitz.de (export "
1564141cc406Sopenharmony_ci	   "SANE_DEBUG_MUSTEK=5\n");
1565141cc406Sopenharmony_ci      DBG (0, "attach: scanimage -L 2>debug.txt). Thank you.\n");
1566141cc406Sopenharmony_ci      free (dev);
1567141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1568141cc406Sopenharmony_ci    }
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci  if (dev->flags & MUSTEK_FLAG_SE)
1571141cc406Sopenharmony_ci    {
1572141cc406Sopenharmony_ci      DBG (3, "attach: this is a single-pass scanner\n");
1573141cc406Sopenharmony_ci      if (result[63] & (1 << 6))
1574141cc406Sopenharmony_ci	{
1575141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_TA;
1576141cc406Sopenharmony_ci	  DBG (3, "attach: scanner supports transparency adapter (TA)\n");
1577141cc406Sopenharmony_ci	}
1578141cc406Sopenharmony_ci    }
1579141cc406Sopenharmony_ci  else
1580141cc406Sopenharmony_ci    {
1581141cc406Sopenharmony_ci      if (result[57] & (1 << 6))
1582141cc406Sopenharmony_ci	{
1583141cc406Sopenharmony_ci	  DBG (3, "attach: this is a single-pass scanner\n");
1584141cc406Sopenharmony_ci	  if (dev->flags & MUSTEK_FLAG_LD_NONE)
1585141cc406Sopenharmony_ci	    DBG (4,
1586141cc406Sopenharmony_ci		 "attach: scanner doesn't need line-distance correction\n");
1587141cc406Sopenharmony_ci	  else if (dev->flags & MUSTEK_FLAG_LD_N1)
1588141cc406Sopenharmony_ci	    DBG (4, "attach: scanner has N1 line-distance correction\n");
1589141cc406Sopenharmony_ci	  else if (dev->flags & MUSTEK_FLAG_LD_N2)
1590141cc406Sopenharmony_ci	    DBG (4, "attach: scanner has N2 line-distance correction\n");
1591141cc406Sopenharmony_ci	  else if (dev->flags & MUSTEK_FLAG_LD_BLOCK)
1592141cc406Sopenharmony_ci	    DBG (4, "attach: scanner has block line-distance correction\n");
1593141cc406Sopenharmony_ci	  else
1594141cc406Sopenharmony_ci	    DBG (4, "attach: scanner has normal line-distance correction\n");
1595141cc406Sopenharmony_ci	}
1596141cc406Sopenharmony_ci      else
1597141cc406Sopenharmony_ci	{
1598141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_THREE_PASS;
1599141cc406Sopenharmony_ci	  /* three-pass scanners quantize to 0.5% of the maximum resolution: */
1600141cc406Sopenharmony_ci	  dev->dpi_range.quant = dev->dpi_range.max / 200;
1601141cc406Sopenharmony_ci	  dev->dpi_range.min = dev->dpi_range.quant;
1602141cc406Sopenharmony_ci	  DBG (3, "attach: this is a three-pass scanner\n");
1603141cc406Sopenharmony_ci	}
1604141cc406Sopenharmony_ci      if (result[57] & (1 << 5))
1605141cc406Sopenharmony_ci	{
1606141cc406Sopenharmony_ci	  DBG (3, "attach: this is a professional series scanner\n");
1607141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_PRO;
1608141cc406Sopenharmony_ci	  status = dev_open (devname, &s, sense_handler);
1609141cc406Sopenharmony_ci	  if (status == SANE_STATUS_GOOD)
1610141cc406Sopenharmony_ci	    {
1611141cc406Sopenharmony_ci	      if (ta_available_pro (&s))
1612141cc406Sopenharmony_ci		{
1613141cc406Sopenharmony_ci		  dev->flags |= MUSTEK_FLAG_TA;
1614141cc406Sopenharmony_ci		  DBG (3, "attach: found transparency adapter (TA)\n");
1615141cc406Sopenharmony_ci		}
1616141cc406Sopenharmony_ci	      dev_close (&s);
1617141cc406Sopenharmony_ci	    }
1618141cc406Sopenharmony_ci	  else
1619141cc406Sopenharmony_ci	    {
1620141cc406Sopenharmony_ci	      DBG (1, "attach: couldn't open device: %s\n",
1621141cc406Sopenharmony_ci		   sane_strstatus (status));
1622141cc406Sopenharmony_ci	      return status;
1623141cc406Sopenharmony_ci	    }
1624141cc406Sopenharmony_ci	}
1625141cc406Sopenharmony_ci      if (result[63] & (1 << 2))
1626141cc406Sopenharmony_ci	{
1627141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_ADF;
1628141cc406Sopenharmony_ci	  DBG (3, "attach: found automatic document feeder (ADF)\n");
1629141cc406Sopenharmony_ci	  if (result[63] & (1 << 3))
1630141cc406Sopenharmony_ci	    {
1631141cc406Sopenharmony_ci	      dev->flags |= MUSTEK_FLAG_ADF_READY;
1632141cc406Sopenharmony_ci	      DBG (4, "attach: automatic document feeder is ready\n");
1633141cc406Sopenharmony_ci	    }
1634141cc406Sopenharmony_ci	  else
1635141cc406Sopenharmony_ci	    {
1636141cc406Sopenharmony_ci	      DBG (4, "attach: automatic document feeder is out of "
1637141cc406Sopenharmony_ci		   "documents\n");
1638141cc406Sopenharmony_ci	    }
1639141cc406Sopenharmony_ci	}
1640141cc406Sopenharmony_ci
1641141cc406Sopenharmony_ci      if (result[63] & (1 << 6))
1642141cc406Sopenharmony_ci	{
1643141cc406Sopenharmony_ci	  dev->flags |= MUSTEK_FLAG_TA;
1644141cc406Sopenharmony_ci	  DBG (3, "attach: found transparency adapter (TA)\n");
1645141cc406Sopenharmony_ci	}
1646141cc406Sopenharmony_ci    }
1647141cc406Sopenharmony_ci
1648141cc406Sopenharmony_ci  if (dev->flags & MUSTEK_FLAG_COVER_SENSOR)
1649141cc406Sopenharmony_ci    {
1650141cc406Sopenharmony_ci      if (result[62] & (1 << 0))
1651141cc406Sopenharmony_ci	DBG (4, "attach: scanner cover is closed\n");
1652141cc406Sopenharmony_ci      else
1653141cc406Sopenharmony_ci	DBG (4, "attach: scanner cover is open\n");
1654141cc406Sopenharmony_ci    }
1655141cc406Sopenharmony_ci
1656141cc406Sopenharmony_ci  if (warning == SANE_TRUE)
1657141cc406Sopenharmony_ci    {
1658141cc406Sopenharmony_ci      DBG (0,
1659141cc406Sopenharmony_ci	   "WARNING: Your scanner was detected by the SANE Mustek backend, "
1660141cc406Sopenharmony_ci	   "but\n  it is not fully tested. It may or may not work. Be "
1661141cc406Sopenharmony_ci	   "careful and read\n  the PROBLEMS file in the sane directory. "
1662141cc406Sopenharmony_ci	   "Please set the debug level of this\n  backend to maximum "
1663141cc406Sopenharmony_ci	   "(export SANE_DEBUG_MUSTEK=255) and send the output of\n  "
1664141cc406Sopenharmony_ci	   "scanimage -L to the SANE mailing list sane-devel@alioth-lists.debian.net. "
1665141cc406Sopenharmony_ci	   "Please include\n  the exact model name of your scanner and to "
1666141cc406Sopenharmony_ci	   "which extend it works.\n");
1667141cc406Sopenharmony_ci    }
1668141cc406Sopenharmony_ci
1669141cc406Sopenharmony_ci  DBG (2, "attach: found Mustek %s %s, %s%s%s%s\n",
1670141cc406Sopenharmony_ci       dev->sane.model, dev->sane.type,
1671141cc406Sopenharmony_ci       (dev->flags & MUSTEK_FLAG_THREE_PASS) ? "3-pass" : "1-pass",
1672141cc406Sopenharmony_ci       (dev->flags & MUSTEK_FLAG_ADF) ? ", ADF" : "",
1673141cc406Sopenharmony_ci       (dev->flags & MUSTEK_FLAG_TA) ? ", TA" : "",
1674141cc406Sopenharmony_ci       (dev->flags & MUSTEK_FLAG_SE) ? ", SE" : "");
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci  ++num_devices;
1677141cc406Sopenharmony_ci  dev->next = first_dev;
1678141cc406Sopenharmony_ci  first_dev = dev;
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_ci  if (devp)
1681141cc406Sopenharmony_ci    *devp = dev;
1682141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1683141cc406Sopenharmony_ci}
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_cistatic size_t
1686141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
1687141cc406Sopenharmony_ci{
1688141cc406Sopenharmony_ci  size_t size, max_size = 0;
1689141cc406Sopenharmony_ci  SANE_Int i;
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
1692141cc406Sopenharmony_ci    {
1693141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
1694141cc406Sopenharmony_ci      if (size > max_size)
1695141cc406Sopenharmony_ci	max_size = size;
1696141cc406Sopenharmony_ci    }
1697141cc406Sopenharmony_ci  return max_size;
1698141cc406Sopenharmony_ci}
1699141cc406Sopenharmony_ci
1700141cc406Sopenharmony_cistatic SANE_Status
1701141cc406Sopenharmony_ciconstrain_value (Mustek_Scanner * s, SANE_Int option, void *value,
1702141cc406Sopenharmony_ci		 SANE_Int * info)
1703141cc406Sopenharmony_ci{
1704141cc406Sopenharmony_ci  SANE_Fixed w, dpi;
1705141cc406Sopenharmony_ci  SANE_Status status;
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci  if (value)
1708141cc406Sopenharmony_ci    w = *(SANE_Fixed *) value;
1709141cc406Sopenharmony_ci  else
1710141cc406Sopenharmony_ci    w = 0;
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci  if (option == OPT_RESOLUTION)
1713141cc406Sopenharmony_ci    {
1714141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
1715141cc406Sopenharmony_ci	{
1716141cc406Sopenharmony_ci	  /* The three pass scanners use a 0.5% of the maximum resolution
1717141cc406Sopenharmony_ci	     increment for resolutions less than or equal to half of the
1718141cc406Sopenharmony_ci	     maximum resolution. The MFS-06000CX uses a 5% of the maximum
1719141cc406Sopenharmony_ci	     resolution increment for larger resolutions.  The models
1720141cc406Sopenharmony_ci	     MFS-12000CX and MSF-06000CZ use 1% of the maximum resolution.
1721141cc406Sopenharmony_ci	     We can't represent this easily in SANE, so the constraint is
1722141cc406Sopenharmony_ci	     simply for 0.5% and then we round to the 5% or 1% increments
1723141cc406Sopenharmony_ci	     if necessary.  */
1724141cc406Sopenharmony_ci	  SANE_Fixed max_dpi, quant, half_res;
1725141cc406Sopenharmony_ci
1726141cc406Sopenharmony_ci	  /*w = *(SANE_Word *) value; */
1727141cc406Sopenharmony_ci	  max_dpi = s->hw->dpi_range.max;
1728141cc406Sopenharmony_ci	  half_res = max_dpi / 2;
1729141cc406Sopenharmony_ci
1730141cc406Sopenharmony_ci	  if (w > half_res)
1731141cc406Sopenharmony_ci	    {
1732141cc406Sopenharmony_ci	      /* quantizize to 1% step */
1733141cc406Sopenharmony_ci	      quant = max_dpi / 100;
1734141cc406Sopenharmony_ci
1735141cc406Sopenharmony_ci	      dpi = (w + quant / 2) / quant;
1736141cc406Sopenharmony_ci	      dpi *= quant;
1737141cc406Sopenharmony_ci	      if (dpi != w)
1738141cc406Sopenharmony_ci		{
1739141cc406Sopenharmony_ci		  *(SANE_Word *) value = dpi;
1740141cc406Sopenharmony_ci		  if (info)
1741141cc406Sopenharmony_ci		    *info |= SANE_INFO_INEXACT;
1742141cc406Sopenharmony_ci		}
1743141cc406Sopenharmony_ci	    }
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci	}
1746141cc406Sopenharmony_ci    }
1747141cc406Sopenharmony_ci
1748141cc406Sopenharmony_ci  status = sanei_constrain_value (s->opt + option, value, info);
1749141cc406Sopenharmony_ci  if (s->opt[option].type == SANE_TYPE_FIXED)
1750141cc406Sopenharmony_ci    DBG (5, "constrain_value: %s = %.2f (was %.2f)\n", s->opt[option].name,
1751141cc406Sopenharmony_ci	 SANE_UNFIX (*(SANE_Word *) value), SANE_UNFIX (w));
1752141cc406Sopenharmony_ci  return status;
1753141cc406Sopenharmony_ci}
1754141cc406Sopenharmony_ci
1755141cc406Sopenharmony_ci/* Quantize s->val[OPT_RESOLUTION].w and return the resolution code for the
1756141cc406Sopenharmony_ci   quantized resolution.  Quantization depends on scanner type (single
1757141cc406Sopenharmony_ci   pass vs. three-pass) and resolution */
1758141cc406Sopenharmony_cistatic SANE_Int
1759141cc406Sopenharmony_ciencode_resolution (Mustek_Scanner * s)
1760141cc406Sopenharmony_ci{
1761141cc406Sopenharmony_ci  SANE_Fixed max_dpi, dpi;
1762141cc406Sopenharmony_ci  SANE_Int code, mode = 0;
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_ci  dpi = s->val[OPT_RESOLUTION].w;
1765141cc406Sopenharmony_ci
1766141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
1767141cc406Sopenharmony_ci    {
1768141cc406Sopenharmony_ci      code = dpi >> SANE_FIXED_SCALE_SHIFT;
1769141cc406Sopenharmony_ci    }
1770141cc406Sopenharmony_ci  else
1771141cc406Sopenharmony_ci    {
1772141cc406Sopenharmony_ci      SANE_Fixed quant, half_res;
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci      max_dpi = s->hw->dpi_range.max;
1775141cc406Sopenharmony_ci      half_res = max_dpi / 2;
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci      if (dpi <= half_res)
1778141cc406Sopenharmony_ci	{
1779141cc406Sopenharmony_ci	  /* quantizize to 0.5% step */
1780141cc406Sopenharmony_ci	  quant = max_dpi / 200;
1781141cc406Sopenharmony_ci	}
1782141cc406Sopenharmony_ci      else
1783141cc406Sopenharmony_ci	{
1784141cc406Sopenharmony_ci	  /* quantizize to 1% step */
1785141cc406Sopenharmony_ci	  quant = max_dpi / 100;
1786141cc406Sopenharmony_ci	  mode = 0x100;		/* indicate 5% or 1% quantization */
1787141cc406Sopenharmony_ci	}
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci      code = (dpi + quant / 2) / quant;
1790141cc406Sopenharmony_ci      if (code < 1)
1791141cc406Sopenharmony_ci	code = 1;
1792141cc406Sopenharmony_ci
1793141cc406Sopenharmony_ci    }
1794141cc406Sopenharmony_ci  DBG (5, "encode_resolution: code = 0x%x (%d); mode = %x\n", code, code,
1795141cc406Sopenharmony_ci       mode);
1796141cc406Sopenharmony_ci  return code | mode;
1797141cc406Sopenharmony_ci}
1798141cc406Sopenharmony_ci
1799141cc406Sopenharmony_cistatic SANE_Int
1800141cc406Sopenharmony_ciencode_percentage (Mustek_Scanner * s, double value)
1801141cc406Sopenharmony_ci{
1802141cc406Sopenharmony_ci  SANE_Int max, code, sign = 0;
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
1805141cc406Sopenharmony_ci    {
1806141cc406Sopenharmony_ci      code = (int) ((value / 100.0 * 12) + 12.5);
1807141cc406Sopenharmony_ci      max = 0x18;
1808141cc406Sopenharmony_ci    }
1809141cc406Sopenharmony_ci  else
1810141cc406Sopenharmony_ci    {
1811141cc406Sopenharmony_ci      if (value < 0.0)
1812141cc406Sopenharmony_ci	{
1813141cc406Sopenharmony_ci	  value = -value;
1814141cc406Sopenharmony_ci	  sign = 0x80;
1815141cc406Sopenharmony_ci	}
1816141cc406Sopenharmony_ci      code = (int) (value / 100.0 * 127 + 0.5);
1817141cc406Sopenharmony_ci      code |= sign;
1818141cc406Sopenharmony_ci      max = 0xff;
1819141cc406Sopenharmony_ci    }
1820141cc406Sopenharmony_ci  if (code > max)
1821141cc406Sopenharmony_ci    code = max;
1822141cc406Sopenharmony_ci  if (code < 0)
1823141cc406Sopenharmony_ci    code = 0x00;
1824141cc406Sopenharmony_ci  return code;
1825141cc406Sopenharmony_ci}
1826141cc406Sopenharmony_ci
1827141cc406Sopenharmony_ci/* encode halftone pattern type and size */
1828141cc406Sopenharmony_cistatic SANE_Status
1829141cc406Sopenharmony_ciencode_halftone (Mustek_Scanner * s)
1830141cc406Sopenharmony_ci{
1831141cc406Sopenharmony_ci  SANE_String selection = s->val[OPT_HALFTONE_DIMENSION].s;
1832141cc406Sopenharmony_ci  SANE_Int i = 0;
1833141cc406Sopenharmony_ci
1834141cc406Sopenharmony_ci  while ((halftone_list[i] != 0) && (strcmp (selection, halftone_list[i]) != 0))
1835141cc406Sopenharmony_ci    {
1836141cc406Sopenharmony_ci      i++;
1837141cc406Sopenharmony_ci    }
1838141cc406Sopenharmony_ci  if (halftone_list[i] == 0)
1839141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1840141cc406Sopenharmony_ci
1841141cc406Sopenharmony_ci  if (i < 0x0c)			/* standard pattern */
1842141cc406Sopenharmony_ci    {
1843141cc406Sopenharmony_ci      s->custom_halftone_pattern = SANE_FALSE;
1844141cc406Sopenharmony_ci      s->halftone_pattern_type = i;
1845141cc406Sopenharmony_ci    }
1846141cc406Sopenharmony_ci  else				/* custom pattern */
1847141cc406Sopenharmony_ci    {
1848141cc406Sopenharmony_ci      s->custom_halftone_pattern = SANE_TRUE;
1849141cc406Sopenharmony_ci      i -= 0x0c;
1850141cc406Sopenharmony_ci      i = 8 - i;
1851141cc406Sopenharmony_ci      if (i < 8)
1852141cc406Sopenharmony_ci	i--;
1853141cc406Sopenharmony_ci      i = i + (i << 4);
1854141cc406Sopenharmony_ci      s->halftone_pattern_type = i;
1855141cc406Sopenharmony_ci    }
1856141cc406Sopenharmony_ci
1857141cc406Sopenharmony_ci  DBG (5, "encode_halftone: %s pattern type %x\n",
1858141cc406Sopenharmony_ci       s->custom_halftone_pattern ? "custom" : "standard",
1859141cc406Sopenharmony_ci       s->halftone_pattern_type);
1860141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1861141cc406Sopenharmony_ci}
1862141cc406Sopenharmony_ci
1863141cc406Sopenharmony_ci/* Paragon series */
1864141cc406Sopenharmony_cistatic SANE_Status
1865141cc406Sopenharmony_ciarea_and_windows (Mustek_Scanner * s)
1866141cc406Sopenharmony_ci{
1867141cc406Sopenharmony_ci  SANE_Byte cmd[117], *cp;
1868141cc406Sopenharmony_ci  SANE_Int i, offset;
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci  /* setup SCSI command (except length): */
1871141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
1872141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_AREA_AND_WINDOWS;
1873141cc406Sopenharmony_ci
1874141cc406Sopenharmony_ci  cp = cmd + 6;
1875141cc406Sopenharmony_ci
1876141cc406Sopenharmony_ci  /* Some scanners need a larger scanarea for line-distance correction */
1877141cc406Sopenharmony_ci  offset = 0;
1878141cc406Sopenharmony_ci  if (((s->hw->flags & MUSTEK_FLAG_LD_N1)
1879141cc406Sopenharmony_ci       || ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK)
1880141cc406Sopenharmony_ci	   && (s->hw->flags & MUSTEK_FLAG_PARAGON_1)))
1881141cc406Sopenharmony_ci      && (s->mode & MUSTEK_MODE_COLOR))
1882141cc406Sopenharmony_ci    offset = MAX_LINE_DIST;
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci  /* fill in frame header: */
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_USE_EIGHTS)
1887141cc406Sopenharmony_ci    {
1888141cc406Sopenharmony_ci      double eights_per_mm = 8 / MM_PER_INCH;
1889141cc406Sopenharmony_ci      SANE_Int tlx, tly, brx, bry;
1890141cc406Sopenharmony_ci      /*
1891141cc406Sopenharmony_ci       * The MSF-06000CZ seems to lock-up if the pixel-unit is used.
1892141cc406Sopenharmony_ci       * Using 1/8" works.
1893141cc406Sopenharmony_ci       * This doesn't seem to be true with the current scheme.
1894141cc406Sopenharmony_ci       * This code isn't used at the moment.  <henning@meier-geinitz.de>
1895141cc406Sopenharmony_ci       */
1896141cc406Sopenharmony_ci      *cp++ = ((s->mode & MUSTEK_MODE_LINEART) ? 0x00 : 0x01);
1897141cc406Sopenharmony_ci
1898141cc406Sopenharmony_ci      tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * eights_per_mm + 0.5;
1899141cc406Sopenharmony_ci      tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * eights_per_mm + 0.5;
1900141cc406Sopenharmony_ci      brx = SANE_UNFIX (s->val[OPT_BR_X].w) * eights_per_mm + 0.5;
1901141cc406Sopenharmony_ci      bry = SANE_UNFIX (s->val[OPT_BR_Y].w) * eights_per_mm + 0.5;
1902141cc406Sopenharmony_ci      STORE16L (cp, tlx);
1903141cc406Sopenharmony_ci      STORE16L (cp, tly);
1904141cc406Sopenharmony_ci      STORE16L (cp, brx);
1905141cc406Sopenharmony_ci      STORE16L (cp, bry);
1906141cc406Sopenharmony_ci      DBG (5, "area_and_windows: tlx=%d (%d mm); tly=%d (%d mm); "
1907141cc406Sopenharmony_ci	   "brx=%d (%d mm); bry=%d (%d mm)\n", tlx,
1908141cc406Sopenharmony_ci	   (int) (tlx / eights_per_mm), tly, (int) (tly / eights_per_mm), brx,
1909141cc406Sopenharmony_ci	   (int) (brx / eights_per_mm), bry, (int) (bry / eights_per_mm));
1910141cc406Sopenharmony_ci    }
1911141cc406Sopenharmony_ci  else
1912141cc406Sopenharmony_ci    {
1913141cc406Sopenharmony_ci      double pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH;
1914141cc406Sopenharmony_ci      SANE_Int tlx, tly, brx, bry;
1915141cc406Sopenharmony_ci
1916141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
1917141cc406Sopenharmony_ci	/* 3pass scanners use 1/2 of the max resolution as base */
1918141cc406Sopenharmony_ci	pixels_per_mm /= 2;
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci      /* pixel unit and halftoning: */
1921141cc406Sopenharmony_ci      *cp++ = 0x8 | ((s->mode & MUSTEK_MODE_LINEART) ? 0x00 : 0x01);
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_ci      /* fill in scanning area: */
1924141cc406Sopenharmony_ci      if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0)
1925141cc406Sopenharmony_ci	{
1926141cc406Sopenharmony_ci	  /* must mirror the x coordinates */
1927141cc406Sopenharmony_ci	  brx = SANE_UNFIX (s->hw->x_range.max - s->val[OPT_TL_X].w)
1928141cc406Sopenharmony_ci	    * pixels_per_mm + 0.5;
1929141cc406Sopenharmony_ci	  tlx = SANE_UNFIX (s->hw->x_range.max - s->val[OPT_BR_X].w)
1930141cc406Sopenharmony_ci	    * pixels_per_mm + 0.5;
1931141cc406Sopenharmony_ci	}
1932141cc406Sopenharmony_ci      else
1933141cc406Sopenharmony_ci	{
1934141cc406Sopenharmony_ci	  tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5;
1935141cc406Sopenharmony_ci	  brx = SANE_UNFIX (s->val[OPT_BR_X].w) * pixels_per_mm + 0.5;
1936141cc406Sopenharmony_ci
1937141cc406Sopenharmony_ci	}
1938141cc406Sopenharmony_ci      tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5;
1939141cc406Sopenharmony_ci      bry = SANE_UNFIX (s->val[OPT_BR_Y].w) * pixels_per_mm + 0.5 + offset;
1940141cc406Sopenharmony_ci      STORE16L (cp, tlx);
1941141cc406Sopenharmony_ci      STORE16L (cp, tly);
1942141cc406Sopenharmony_ci      STORE16L (cp, brx);
1943141cc406Sopenharmony_ci      STORE16L (cp, bry);
1944141cc406Sopenharmony_ci      DBG (5, "area_and_windows: tlx=%d (%d mm); tly=%d (%d mm); "
1945141cc406Sopenharmony_ci	   "brx=%d (%d mm); bry=%d (%d mm)\n", tlx,
1946141cc406Sopenharmony_ci	   (int) (tlx / pixels_per_mm), tly, (int) (tly / pixels_per_mm), brx,
1947141cc406Sopenharmony_ci	   (int) (brx / pixels_per_mm), bry, (int) (bry / pixels_per_mm));
1948141cc406Sopenharmony_ci    }
1949141cc406Sopenharmony_ci
1950141cc406Sopenharmony_ci  if (s->custom_halftone_pattern)
1951141cc406Sopenharmony_ci    {
1952141cc406Sopenharmony_ci      *cp++ = 0x40;		/* mark presence of user pattern */
1953141cc406Sopenharmony_ci      *cp++ = s->halftone_pattern_type;	/* set pattern length */
1954141cc406Sopenharmony_ci      for (i = 0; i < (s->halftone_pattern_type & 0x0f) *
1955141cc406Sopenharmony_ci	   ((s->halftone_pattern_type >> 4) & 0x0f); ++i)
1956141cc406Sopenharmony_ci	*cp++ = s->val[OPT_HALFTONE_PATTERN].wa[i];
1957141cc406Sopenharmony_ci    }
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci  cmd[4] = (cp - cmd) - 6;
1960141cc406Sopenharmony_ci
1961141cc406Sopenharmony_ci  return dev_cmd (s, cmd, (cp - cmd), 0, 0);
1962141cc406Sopenharmony_ci}
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_ci/* ScanExpress */
1965141cc406Sopenharmony_cistatic SANE_Status
1966141cc406Sopenharmony_ciset_window_se (Mustek_Scanner * s, SANE_Int lamp)
1967141cc406Sopenharmony_ci{
1968141cc406Sopenharmony_ci  SANE_Byte cmd[58], *cp;
1969141cc406Sopenharmony_ci  double pixels_per_mm;
1970141cc406Sopenharmony_ci  SANE_Int offset;
1971141cc406Sopenharmony_ci  SANE_Int tlx, tly, width, height;
1972141cc406Sopenharmony_ci
1973141cc406Sopenharmony_ci  /* setup SCSI command (except length): */
1974141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
1975141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_SET_WINDOW;
1976141cc406Sopenharmony_ci  cp = cmd + CDB_SIZE (MUSTEK_SCSI_SET_WINDOW);	/* skip command block   */
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci  if (s->mode & MUSTEK_MODE_COLOR)
1979141cc406Sopenharmony_ci    {
1980141cc406Sopenharmony_ci      /* We have to increase the specified resolution to the next       */
1981141cc406Sopenharmony_ci      /* "standard" resolution due to a firmware bug(?) in color mode   */
1982141cc406Sopenharmony_ci      /* It's possible to scan in 36, 75, 100, 150, 200, 250, 300,      */
1983141cc406Sopenharmony_ci      /* 400, 500, 600, 900, 1200 dpi but the speed is only different   */
1984141cc406Sopenharmony_ci      /* with 36, 150, 300, 600, 1200 dpi.                              */
1985141cc406Sopenharmony_ci      /* Additionally we must increase the window length slightly to    */
1986141cc406Sopenharmony_ci      /* compensate for different line counts for r/g/b                 */
1987141cc406Sopenharmony_ci      const SANE_Int resolution_list[] = { 36, 150, 300, 600, 1200, 0 };
1988141cc406Sopenharmony_ci      SANE_Int entry = 0;
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_ci      while (resolution_list[entry] < s->resolution_code)
1991141cc406Sopenharmony_ci	entry++;
1992141cc406Sopenharmony_ci      s->ld.peak_res = resolution_list[entry];
1993141cc406Sopenharmony_ci
1994141cc406Sopenharmony_ci      offset = MAX_LINE_DIST;	/* distance r/b lines           */
1995141cc406Sopenharmony_ci    }
1996141cc406Sopenharmony_ci  else
1997141cc406Sopenharmony_ci    {
1998141cc406Sopenharmony_ci      /* In gray and lineart modes all resolutions are possible         */
1999141cc406Sopenharmony_ci      s->ld.peak_res = s->resolution_code;
2000141cc406Sopenharmony_ci      offset = 0;
2001141cc406Sopenharmony_ci    }
2002141cc406Sopenharmony_ci  DBG (5, "set_window_se: hardware resolution is %d dpi; offset is %d\n",
2003141cc406Sopenharmony_ci       s->ld.peak_res, offset);
2004141cc406Sopenharmony_ci
2005141cc406Sopenharmony_ci  STORE16B (cp, 0);		/* window identifier            */
2006141cc406Sopenharmony_ci  STORE16B (cp, s->ld.peak_res);
2007141cc406Sopenharmony_ci  /* x and y resolution           */
2008141cc406Sopenharmony_ci  STORE16B (cp, 0);		/* not used acc. to specs       */
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci  pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH;
2011141cc406Sopenharmony_ci
2012141cc406Sopenharmony_ci  /* fill in scanning area, begin and length(!) */
2013141cc406Sopenharmony_ci  if ((strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0) &&
2014141cc406Sopenharmony_ci      !(s->hw->flags & MUSTEK_FLAG_TA))
2015141cc406Sopenharmony_ci    {
2016141cc406Sopenharmony_ci      /* need to add the start values of the transparency adapter */
2017141cc406Sopenharmony_ci      tlx = (SANE_UNFIX (s->val[OPT_TL_X].w) + 33.0) * pixels_per_mm + 0.5;
2018141cc406Sopenharmony_ci      tly = (SANE_UNFIX (s->val[OPT_TL_Y].w) + 60.0) * pixels_per_mm + 0.5;
2019141cc406Sopenharmony_ci      DBG (5, "set_window_se: added offset for transparency adapter\n");
2020141cc406Sopenharmony_ci    }
2021141cc406Sopenharmony_ci  else
2022141cc406Sopenharmony_ci    {
2023141cc406Sopenharmony_ci      /* no transparency adapter selected or calculation done in firmware */
2024141cc406Sopenharmony_ci      tlx = SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5;
2025141cc406Sopenharmony_ci      tly = SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5;
2026141cc406Sopenharmony_ci    }
2027141cc406Sopenharmony_ci  width = (SANE_UNFIX (s->val[OPT_BR_X].w) - SANE_UNFIX (s->val[OPT_TL_X].w))
2028141cc406Sopenharmony_ci    * pixels_per_mm + 0.5;
2029141cc406Sopenharmony_ci  height = (SANE_UNFIX (s->val[OPT_BR_Y].w) - SANE_UNFIX (s->val[OPT_TL_Y].w))
2030141cc406Sopenharmony_ci    * pixels_per_mm + 0.5 + offset;
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci  DBG (5, "set_window_se: tlx=%d (%d mm); tly=%d (%d mm); width=%d (%d mm); "
2033141cc406Sopenharmony_ci       "height=%d (%d mm)\n", tlx, (int) (tlx / pixels_per_mm), tly,
2034141cc406Sopenharmony_ci       (int) (tly / pixels_per_mm), width, (int) (width / pixels_per_mm),
2035141cc406Sopenharmony_ci       height, (int) (height / pixels_per_mm));
2036141cc406Sopenharmony_ci
2037141cc406Sopenharmony_ci
2038141cc406Sopenharmony_ci  STORE32B (cp, tlx);
2039141cc406Sopenharmony_ci  STORE32B (cp, tly);
2040141cc406Sopenharmony_ci  STORE32B (cp, width);
2041141cc406Sopenharmony_ci  STORE32B (cp, height);
2042141cc406Sopenharmony_ci
2043141cc406Sopenharmony_ci  *cp++ = 0x00;			/* brightness, not impl.        */
2044141cc406Sopenharmony_ci  *cp++ = 0x80;			/* threshold, not impl.         */
2045141cc406Sopenharmony_ci  *cp++ = 0x00;			/* contrast, not impl.          */
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ci  /* Note that 'image composition' has no meaning for the SE series     */
2048141cc406Sopenharmony_ci  /* Mode selection is accomplished solely by bits/pixel (1, 8, 24)     */
2049141cc406Sopenharmony_ci  if (s->mode & MUSTEK_MODE_COLOR)
2050141cc406Sopenharmony_ci    {
2051141cc406Sopenharmony_ci      *cp++ = 0x05;		/* actually not used!           */
2052141cc406Sopenharmony_ci      *cp++ = 24;		/* 24 bits/pixel in color mode  */
2053141cc406Sopenharmony_ci    }
2054141cc406Sopenharmony_ci  else if (s->mode & MUSTEK_MODE_GRAY)
2055141cc406Sopenharmony_ci    {
2056141cc406Sopenharmony_ci      *cp++ = 0x02;		/* actually not used!           */
2057141cc406Sopenharmony_ci      *cp++ = 8;		/* 8 bits/pixel in gray mode    */
2058141cc406Sopenharmony_ci    }
2059141cc406Sopenharmony_ci  else
2060141cc406Sopenharmony_ci    {
2061141cc406Sopenharmony_ci      *cp++ = 0x00;		/* actually not used!           */
2062141cc406Sopenharmony_ci      *cp++ = 1;		/* 1 bit/pixel in lineart mode  */
2063141cc406Sopenharmony_ci    }
2064141cc406Sopenharmony_ci
2065141cc406Sopenharmony_ci  cp += 14;			/* skip reserved bytes          */
2066141cc406Sopenharmony_ci  *cp++ = lamp;			/* 0 = normal, 1 = on, 2 = off  */
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_TA)
2069141cc406Sopenharmony_ci      && (strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0))
2070141cc406Sopenharmony_ci    *cp++ = 1;
2071141cc406Sopenharmony_ci  else
2072141cc406Sopenharmony_ci    *cp++ = 0;
2073141cc406Sopenharmony_ci  cp += 5;			/* skip reserved bytes          */
2074141cc406Sopenharmony_ci
2075141cc406Sopenharmony_ci  cmd[8] = cp - cmd - CDB_SIZE (MUSTEK_SCSI_SET_WINDOW);
2076141cc406Sopenharmony_ci  return dev_cmd (s, cmd, (cp - cmd), 0, 0);
2077141cc406Sopenharmony_ci}
2078141cc406Sopenharmony_ci
2079141cc406Sopenharmony_ci/* Pro series */
2080141cc406Sopenharmony_cistatic SANE_Status
2081141cc406Sopenharmony_ciset_window_pro (Mustek_Scanner * s)
2082141cc406Sopenharmony_ci{
2083141cc406Sopenharmony_ci  SANE_Byte cmd[20], *cp;
2084141cc406Sopenharmony_ci  double pixels_per_mm;
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
2087141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_SET_WINDOW;
2088141cc406Sopenharmony_ci  if (strcmp (s->hw->sane.model, "1200 SP PRO") == 0)
2089141cc406Sopenharmony_ci    cmd[8] = 0x09;
2090141cc406Sopenharmony_ci  else
2091141cc406Sopenharmony_ci    cmd[8] = 0x0a;
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci  cp = cmd + CDB_SIZE (MUSTEK_SCSI_SET_WINDOW);	/* skip command block   */
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci  *cp++ = 0;			/* what's this? */
2096141cc406Sopenharmony_ci  pixels_per_mm = SANE_UNFIX (s->hw->dpi_range.max) / MM_PER_INCH;
2097141cc406Sopenharmony_ci
2098141cc406Sopenharmony_ci  /* The next for 16 bit values are x0, y0, x1, y1 in pixels at max res */
2099141cc406Sopenharmony_ci  STORE16L (cp, SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5);
2100141cc406Sopenharmony_ci  STORE16L (cp, SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5);
2101141cc406Sopenharmony_ci  STORE16L (cp, SANE_UNFIX (s->val[OPT_BR_X].w) * pixels_per_mm + 0.5);
2102141cc406Sopenharmony_ci  STORE16L (cp, SANE_UNFIX (s->val[OPT_BR_Y].w) * pixels_per_mm + 0.5);
2103141cc406Sopenharmony_ci
2104141cc406Sopenharmony_ci  if (strcmp (s->hw->sane.model, "1200 SP PRO") != 0)
2105141cc406Sopenharmony_ci    *cp++ = lamp_off_time;		/* Only needed for A3 Pro, default: 60 minutes until lamp-off */
2106141cc406Sopenharmony_ci  DBG (5, "set_window_pro\n");
2107141cc406Sopenharmony_ci
2108141cc406Sopenharmony_ci  return dev_cmd (s, cmd, (cp - cmd), 0, 0);
2109141cc406Sopenharmony_ci}
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci/* Pro series calibration */
2112141cc406Sopenharmony_cistatic SANE_Status
2113141cc406Sopenharmony_ciget_calibration_size_pro (Mustek_Scanner * s)
2114141cc406Sopenharmony_ci{
2115141cc406Sopenharmony_ci  SANE_Status status;
2116141cc406Sopenharmony_ci  SANE_Byte cmd[6];
2117141cc406Sopenharmony_ci  SANE_Byte result[6];
2118141cc406Sopenharmony_ci  size_t len;
2119141cc406Sopenharmony_ci
2120141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
2121141cc406Sopenharmony_ci  memset (result, 0, sizeof (result));
2122141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_GET_IMAGE_STATUS;
2123141cc406Sopenharmony_ci  cmd[4] = 0x06;		/* size of result */
2124141cc406Sopenharmony_ci  cmd[5] = 0x80;		/* get back buffer size and number of buffers */
2125141cc406Sopenharmony_ci  len = sizeof (result);
2126141cc406Sopenharmony_ci  status = dev_cmd (s, cmd, sizeof (cmd), result, &len);
2127141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2128141cc406Sopenharmony_ci    return status;
2129141cc406Sopenharmony_ci
2130141cc406Sopenharmony_ci  s->hw->cal.bytes = result[1] | (result[2] << 8);
2131141cc406Sopenharmony_ci  s->hw->cal.lines = result[3] | (result[4] << 8);
2132141cc406Sopenharmony_ci
2133141cc406Sopenharmony_ci  DBG (4, "get_calibration_size_pro: bytes=%d, lines=%d\n", s->hw->cal.bytes,
2134141cc406Sopenharmony_ci       s->hw->cal.lines);
2135141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2136141cc406Sopenharmony_ci}
2137141cc406Sopenharmony_ci
2138141cc406Sopenharmony_cistatic SANE_Status
2139141cc406Sopenharmony_ciget_calibration_lines_pro (Mustek_Scanner * s)
2140141cc406Sopenharmony_ci{
2141141cc406Sopenharmony_ci  SANE_Status status;
2142141cc406Sopenharmony_ci  SANE_Byte cmd[10];
2143141cc406Sopenharmony_ci  size_t len;
2144141cc406Sopenharmony_ci  SANE_Int line;
2145141cc406Sopenharmony_ci
2146141cc406Sopenharmony_ci  DBG (2, "get_calibration_lines_pro: please wait for warmup\n");
2147141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
2148141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_READ_DATA;
2149141cc406Sopenharmony_ci  len = s->hw->cal.bytes;
2150141cc406Sopenharmony_ci  cmd[6] = (len >> 16) & 0xff;
2151141cc406Sopenharmony_ci  cmd[7] = (len >> 8) & 0xff;
2152141cc406Sopenharmony_ci  cmd[8] = (len >> 0) & 0xff;
2153141cc406Sopenharmony_ci
2154141cc406Sopenharmony_ci  for (line = 0; line < s->hw->cal.lines; line++)
2155141cc406Sopenharmony_ci    {
2156141cc406Sopenharmony_ci      status = dev_cmd (s, cmd, CDB_SIZE (MUSTEK_SCSI_READ_DATA),
2157141cc406Sopenharmony_ci			s->hw->cal.buffer + line * len, &len);
2158141cc406Sopenharmony_ci
2159141cc406Sopenharmony_ci      if ((status != SANE_STATUS_GOOD)
2160141cc406Sopenharmony_ci	  || (len != (unsigned int) s->hw->cal.bytes))
2161141cc406Sopenharmony_ci	{
2162141cc406Sopenharmony_ci	  DBG (1, "get_calibration_lines_pro: read failed\n");
2163141cc406Sopenharmony_ci	  return status;
2164141cc406Sopenharmony_ci	}
2165141cc406Sopenharmony_ci    }
2166141cc406Sopenharmony_ci  DBG (5, "get_calibration_lines_pro finished. Assuming 12 bits per color\n");
2167141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2168141cc406Sopenharmony_ci}
2169141cc406Sopenharmony_ci
2170141cc406Sopenharmony_cistatic SANE_Status
2171141cc406Sopenharmony_cisend_calibration_lines_pro (Mustek_Scanner * s)
2172141cc406Sopenharmony_ci{
2173141cc406Sopenharmony_ci  SANE_Status status;
2174141cc406Sopenharmony_ci  SANE_Byte *cmd1, *cmd2;
2175141cc406Sopenharmony_ci  size_t buf_size;
2176141cc406Sopenharmony_ci  SANE_Word column, line, color;
2177141cc406Sopenharmony_ci
2178141cc406Sopenharmony_ci  DBG (5, "send_calibration_lines_pro\n");
2179141cc406Sopenharmony_ci
2180141cc406Sopenharmony_ci  buf_size = s->hw->cal.bytes / 2;
2181141cc406Sopenharmony_ci  cmd1 = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2182141cc406Sopenharmony_ci  cmd2 = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2183141cc406Sopenharmony_ci  if (!cmd1 || !cmd2)
2184141cc406Sopenharmony_ci    {
2185141cc406Sopenharmony_ci      DBG (1, "send_calibration_lines_pro: failed to malloc %zu bytes for "
2186141cc406Sopenharmony_ci	   "sending lines\n",
2187141cc406Sopenharmony_ci	   buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2188141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2189141cc406Sopenharmony_ci    }
2190141cc406Sopenharmony_ci  memset (cmd1, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2191141cc406Sopenharmony_ci  memset (cmd2, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2192141cc406Sopenharmony_ci
2193141cc406Sopenharmony_ci  cmd1[0] = cmd2[0] = MUSTEK_SCSI_SEND_DATA;
2194141cc406Sopenharmony_ci  cmd1[6] = cmd2[6] = (buf_size >> 16) & 0xff;
2195141cc406Sopenharmony_ci  cmd1[7] = cmd2[7] = (buf_size >> 8) & 0xff;
2196141cc406Sopenharmony_ci  cmd1[8] = cmd2[8] = (buf_size >> 0) & 0xff;
2197141cc406Sopenharmony_ci  cmd1[9] = 0;			/* Least significant 8 bits */
2198141cc406Sopenharmony_ci  cmd2[9] = 0x80;		/* Most significant 2 bits */
2199141cc406Sopenharmony_ci
2200141cc406Sopenharmony_ci  for (color = 0; color < 3; color++)
2201141cc406Sopenharmony_ci    {
2202141cc406Sopenharmony_ci      for (column = 0; column < s->hw->cal.bytes / 6; column++)
2203141cc406Sopenharmony_ci	{
2204141cc406Sopenharmony_ci	  SANE_Word calibration_word = 0;
2205141cc406Sopenharmony_ci	  for (line = 0; line < s->hw->cal.lines; line++)
2206141cc406Sopenharmony_ci	    {
2207141cc406Sopenharmony_ci	      calibration_word +=
2208141cc406Sopenharmony_ci		*(s->hw->cal.buffer + column * 6 + color_seq[color] * 2 + 0)
2209141cc406Sopenharmony_ci		+
2210141cc406Sopenharmony_ci		(*(s->hw->cal.buffer + column * 6 + color_seq[color] * 2 + 1)
2211141cc406Sopenharmony_ci		 << 8);
2212141cc406Sopenharmony_ci	    }
2213141cc406Sopenharmony_ci	  if (!calibration_word)
2214141cc406Sopenharmony_ci	    calibration_word = 1;
2215141cc406Sopenharmony_ci	  calibration_word = (1024 * 65536 / calibration_word) - 1024;
2216141cc406Sopenharmony_ci	  if (calibration_word > 1023)
2217141cc406Sopenharmony_ci	    calibration_word = 1023;
2218141cc406Sopenharmony_ci	  *(cmd1 + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + (buf_size / 3) * color
2219141cc406Sopenharmony_ci	    + column) = calibration_word & 0xff;
2220141cc406Sopenharmony_ci	  *(cmd2 + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + (buf_size / 3) * color
2221141cc406Sopenharmony_ci	    + column) = (calibration_word >> 8) & 0xff;
2222141cc406Sopenharmony_ci	}
2223141cc406Sopenharmony_ci    }
2224141cc406Sopenharmony_ci
2225141cc406Sopenharmony_ci  status = dev_cmd (s, cmd1, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0);
2226141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2227141cc406Sopenharmony_ci    {
2228141cc406Sopenharmony_ci      DBG (1, "send_calibration_lines_pro: send failed\n");
2229141cc406Sopenharmony_ci      return status;
2230141cc406Sopenharmony_ci    }
2231141cc406Sopenharmony_ci
2232141cc406Sopenharmony_ci  status = dev_cmd (s, cmd2, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0);
2233141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2234141cc406Sopenharmony_ci    {
2235141cc406Sopenharmony_ci      DBG (1, "send_calibration_lines_pro: send failed\n");
2236141cc406Sopenharmony_ci      return status;
2237141cc406Sopenharmony_ci    }
2238141cc406Sopenharmony_ci  free (cmd1);
2239141cc406Sopenharmony_ci  free (cmd2);
2240141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2241141cc406Sopenharmony_ci}
2242141cc406Sopenharmony_ci
2243141cc406Sopenharmony_cistatic SANE_Status
2244141cc406Sopenharmony_cicalibration_pro (Mustek_Scanner * s)
2245141cc406Sopenharmony_ci{
2246141cc406Sopenharmony_ci  SANE_Status status;
2247141cc406Sopenharmony_ci
2248141cc406Sopenharmony_ci  if (s->val[OPT_QUALITY_CAL].w)
2249141cc406Sopenharmony_ci    DBG (4, "calibration_pro: doing calibration\n");
2250141cc406Sopenharmony_ci  else
2251141cc406Sopenharmony_ci    {
2252141cc406Sopenharmony_ci      DBG (4, "calibration_pro: calibration not necessary\n");
2253141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2254141cc406Sopenharmony_ci    }
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci  status = get_calibration_size_pro (s);
2257141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2258141cc406Sopenharmony_ci    return status;
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci  s->hw->cal.buffer = (SANE_Byte *) malloc (s->hw->cal.bytes *
2261141cc406Sopenharmony_ci					    s->hw->cal.lines);
2262141cc406Sopenharmony_ci  if (!s->hw->cal.buffer)
2263141cc406Sopenharmony_ci    {
2264141cc406Sopenharmony_ci      DBG (1, "calibration_pro: failed to malloc %d bytes for buffer\n",
2265141cc406Sopenharmony_ci	   s->hw->cal.bytes * s->hw->cal.lines);
2266141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2267141cc406Sopenharmony_ci    }
2268141cc406Sopenharmony_ci
2269141cc406Sopenharmony_ci  status = get_calibration_lines_pro (s);
2270141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2271141cc406Sopenharmony_ci    return status;
2272141cc406Sopenharmony_ci
2273141cc406Sopenharmony_ci  status = send_calibration_lines_pro (s);
2274141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2275141cc406Sopenharmony_ci    return status;
2276141cc406Sopenharmony_ci
2277141cc406Sopenharmony_ci  free (s->hw->cal.buffer);
2278141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2279141cc406Sopenharmony_ci}
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_ci
2282141cc406Sopenharmony_ci/* ScanExpress series calibration */
2283141cc406Sopenharmony_cistatic SANE_Status
2284141cc406Sopenharmony_ciget_calibration_lines_se (Mustek_Scanner * s)
2285141cc406Sopenharmony_ci{
2286141cc406Sopenharmony_ci  SANE_Status status;
2287141cc406Sopenharmony_ci  SANE_Byte cmd[10];
2288141cc406Sopenharmony_ci  size_t len;
2289141cc406Sopenharmony_ci  SANE_Word lines, bytes_per_color;
2290141cc406Sopenharmony_ci
2291141cc406Sopenharmony_ci  if (s->mode == MUSTEK_MODE_COLOR)
2292141cc406Sopenharmony_ci    {
2293141cc406Sopenharmony_ci      lines = s->hw->cal.lines * 3;
2294141cc406Sopenharmony_ci      bytes_per_color = s->hw->cal.bytes / 3;
2295141cc406Sopenharmony_ci    }
2296141cc406Sopenharmony_ci  else
2297141cc406Sopenharmony_ci    {
2298141cc406Sopenharmony_ci      lines = s->hw->cal.lines;
2299141cc406Sopenharmony_ci      bytes_per_color = s->hw->cal.bytes;
2300141cc406Sopenharmony_ci    }
2301141cc406Sopenharmony_ci
2302141cc406Sopenharmony_ci  DBG (4, "get_calibration_lines_se: reading %d lines (%d bytes per color)\n",
2303141cc406Sopenharmony_ci       lines, bytes_per_color);
2304141cc406Sopenharmony_ci  memset (cmd, 0, sizeof (cmd));
2305141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_READ_DATA;
2306141cc406Sopenharmony_ci  cmd[2] = 1;
2307141cc406Sopenharmony_ci  cmd[7] = (lines >> 8) & 0xff;
2308141cc406Sopenharmony_ci  cmd[8] = (lines >> 0) & 0xff;
2309141cc406Sopenharmony_ci  len = lines * bytes_per_color;
2310141cc406Sopenharmony_ci  status = dev_cmd (s, cmd, CDB_SIZE (MUSTEK_SCSI_READ_DATA),
2311141cc406Sopenharmony_ci		    s->hw->cal.buffer, &len);
2312141cc406Sopenharmony_ci  if ((status != SANE_STATUS_GOOD)
2313141cc406Sopenharmony_ci      || (len != (unsigned int) (lines * bytes_per_color)))
2314141cc406Sopenharmony_ci    {
2315141cc406Sopenharmony_ci      DBG (1, "get_calibration_lines_se: read failed\n");
2316141cc406Sopenharmony_ci      return status;
2317141cc406Sopenharmony_ci    }
2318141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2319141cc406Sopenharmony_ci}
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_cistatic SANE_Status
2322141cc406Sopenharmony_cisend_calibration_lines_se (Mustek_Scanner * s, SANE_Word color)
2323141cc406Sopenharmony_ci{
2324141cc406Sopenharmony_ci  SANE_Status status;
2325141cc406Sopenharmony_ci  SANE_Byte *cmd;
2326141cc406Sopenharmony_ci  size_t buf_size;
2327141cc406Sopenharmony_ci  SANE_Word column;
2328141cc406Sopenharmony_ci  SANE_Word bytes_per_color;
2329141cc406Sopenharmony_ci
2330141cc406Sopenharmony_ci  if (s->mode == MUSTEK_MODE_COLOR)
2331141cc406Sopenharmony_ci    {
2332141cc406Sopenharmony_ci      bytes_per_color = s->hw->cal.bytes / 3;
2333141cc406Sopenharmony_ci    }
2334141cc406Sopenharmony_ci  else
2335141cc406Sopenharmony_ci    {
2336141cc406Sopenharmony_ci      bytes_per_color = s->hw->cal.bytes;
2337141cc406Sopenharmony_ci    }
2338141cc406Sopenharmony_ci
2339141cc406Sopenharmony_ci  buf_size = bytes_per_color;
2340141cc406Sopenharmony_ci
2341141cc406Sopenharmony_ci  DBG (5, "send_calibration_lines_se: %d bytes, color: %d\n",
2342141cc406Sopenharmony_ci       bytes_per_color, color + 1);
2343141cc406Sopenharmony_ci
2344141cc406Sopenharmony_ci  cmd = (SANE_Byte *) malloc (buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2345141cc406Sopenharmony_ci  if (!cmd)
2346141cc406Sopenharmony_ci    {
2347141cc406Sopenharmony_ci      DBG (1, "send_calibration_lines_se: failed to malloc %zu bytes for "
2348141cc406Sopenharmony_ci	   "sending lines\n",
2349141cc406Sopenharmony_ci	   buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2350141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2351141cc406Sopenharmony_ci    }
2352141cc406Sopenharmony_ci  memset (cmd, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2353141cc406Sopenharmony_ci
2354141cc406Sopenharmony_ci  for (column = 0; column < bytes_per_color; column++)
2355141cc406Sopenharmony_ci    {
2356141cc406Sopenharmony_ci      SANE_Word line;
2357141cc406Sopenharmony_ci      SANE_Word cali_word = 0;
2358141cc406Sopenharmony_ci      SANE_Int color_seq[] = { 2, 0, 1 };
2359141cc406Sopenharmony_ci
2360141cc406Sopenharmony_ci      for (line = 0; line < s->hw->cal.lines; line++)
2361141cc406Sopenharmony_ci	cali_word += *(s->hw->cal.buffer
2362141cc406Sopenharmony_ci		       + line * bytes_per_color
2363141cc406Sopenharmony_ci		       + bytes_per_color * color_seq[color] + column);
2364141cc406Sopenharmony_ci      if (!cali_word)
2365141cc406Sopenharmony_ci	cali_word = 1;
2366141cc406Sopenharmony_ci      cali_word = 256 * s->hw->cal.lines * 255 / cali_word - 256;
2367141cc406Sopenharmony_ci      if (cali_word > 255)
2368141cc406Sopenharmony_ci	cali_word = 255;
2369141cc406Sopenharmony_ci      *(cmd + CDB_SIZE (MUSTEK_SCSI_SEND_DATA) + column) = cali_word;
2370141cc406Sopenharmony_ci    }
2371141cc406Sopenharmony_ci
2372141cc406Sopenharmony_ci  cmd[0] = MUSTEK_SCSI_SEND_DATA;
2373141cc406Sopenharmony_ci  cmd[2] = 1;
2374141cc406Sopenharmony_ci  cmd[6] = color + 1;
2375141cc406Sopenharmony_ci  cmd[7] = (buf_size >> 8) & 0xff;
2376141cc406Sopenharmony_ci  cmd[8] = (buf_size >> 0) & 0xff;
2377141cc406Sopenharmony_ci
2378141cc406Sopenharmony_ci  status = dev_cmd (s, cmd, buf_size + CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0);
2379141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2380141cc406Sopenharmony_ci    {
2381141cc406Sopenharmony_ci      DBG (1, "send_calibration_lines_se: send failed\n");
2382141cc406Sopenharmony_ci      return status;
2383141cc406Sopenharmony_ci    }
2384141cc406Sopenharmony_ci  free (cmd);
2385141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2386141cc406Sopenharmony_ci}
2387141cc406Sopenharmony_ci
2388141cc406Sopenharmony_cistatic SANE_Status
2389141cc406Sopenharmony_cicalibration_se (Mustek_Scanner * s)
2390141cc406Sopenharmony_ci{
2391141cc406Sopenharmony_ci  SANE_Status status;
2392141cc406Sopenharmony_ci
2393141cc406Sopenharmony_ci  if (!s->val[OPT_QUALITY_CAL].w || s->val[OPT_PREVIEW].w
2394141cc406Sopenharmony_ci      || s->mode == MUSTEK_MODE_LINEART)
2395141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2396141cc406Sopenharmony_ci
2397141cc406Sopenharmony_ci  DBG (4, "calibration_se: doing calibration\n");
2398141cc406Sopenharmony_ci
2399141cc406Sopenharmony_ci  s->hw->cal.lines = MIN (s->hw->cal.lines,
2400141cc406Sopenharmony_ci			  s->hw->buffer_size / s->hw->cal.bytes);
2401141cc406Sopenharmony_ci
2402141cc406Sopenharmony_ci  s->hw->cal.buffer = (SANE_Byte *) malloc (s->hw->cal.bytes
2403141cc406Sopenharmony_ci					    * s->hw->cal.lines);
2404141cc406Sopenharmony_ci  if (!s->hw->cal.buffer)
2405141cc406Sopenharmony_ci    {
2406141cc406Sopenharmony_ci      DBG (1, "calibration_se: failed to malloc %d bytes for buffer\n",
2407141cc406Sopenharmony_ci	   s->hw->cal.bytes * s->hw->cal.lines);
2408141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2409141cc406Sopenharmony_ci    }
2410141cc406Sopenharmony_ci
2411141cc406Sopenharmony_ci  status = get_calibration_lines_se (s);
2412141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2413141cc406Sopenharmony_ci    return status;
2414141cc406Sopenharmony_ci
2415141cc406Sopenharmony_ci  if (s->mode == MUSTEK_MODE_GRAY)
2416141cc406Sopenharmony_ci    status = send_calibration_lines_se (s, 0);
2417141cc406Sopenharmony_ci  else
2418141cc406Sopenharmony_ci    {
2419141cc406Sopenharmony_ci      status = send_calibration_lines_se (s, 0);
2420141cc406Sopenharmony_ci      status = send_calibration_lines_se (s, 1);
2421141cc406Sopenharmony_ci      status = send_calibration_lines_se (s, 2);
2422141cc406Sopenharmony_ci    }
2423141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2424141cc406Sopenharmony_ci    return status;
2425141cc406Sopenharmony_ci
2426141cc406Sopenharmony_ci  free (s->hw->cal.buffer);
2427141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2428141cc406Sopenharmony_ci}
2429141cc406Sopenharmony_ci
2430141cc406Sopenharmony_ci/* ScanExpress series */
2431141cc406Sopenharmony_cistatic SANE_Status
2432141cc406Sopenharmony_cisend_gamma_table_se (Mustek_Scanner * s)
2433141cc406Sopenharmony_ci{
2434141cc406Sopenharmony_ci  SANE_Status status;
2435141cc406Sopenharmony_ci  SANE_Byte gamma[10 + 4096], *cp;
2436141cc406Sopenharmony_ci  SANE_Int color, factor, val_a, val_b;
2437141cc406Sopenharmony_ci  SANE_Int i, j;
2438141cc406Sopenharmony_ci# define CLIP(x)	((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)))
2439141cc406Sopenharmony_ci
2440141cc406Sopenharmony_ci  memset (gamma, 0, CDB_SIZE (MUSTEK_SCSI_SEND_DATA));
2441141cc406Sopenharmony_ci
2442141cc406Sopenharmony_ci  gamma[0] = MUSTEK_SCSI_SEND_DATA;
2443141cc406Sopenharmony_ci  gamma[2] = 0x03;		/* indicates gamma table */
2444141cc406Sopenharmony_ci
2445141cc406Sopenharmony_ci  if ((s->mode & MUSTEK_MODE_GRAY) || (s->mode & MUSTEK_MODE_COLOR))
2446141cc406Sopenharmony_ci    {
2447141cc406Sopenharmony_ci      if ((size_t) s->hw->gamma_length + CDB_SIZE (MUSTEK_SCSI_SEND_DATA)
2448141cc406Sopenharmony_ci	  > sizeof (gamma))
2449141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
2450141cc406Sopenharmony_ci      gamma[7] = (s->hw->gamma_length >> 8) & 0xff;
2451141cc406Sopenharmony_ci      gamma[8] = (s->hw->gamma_length >> 0) & 0xff;
2452141cc406Sopenharmony_ci
2453141cc406Sopenharmony_ci      factor = s->hw->gamma_length / 256;
2454141cc406Sopenharmony_ci      color = (s->mode & MUSTEK_MODE_COLOR) ? 1 : 0;
2455141cc406Sopenharmony_ci
2456141cc406Sopenharmony_ci      do
2457141cc406Sopenharmony_ci	{
2458141cc406Sopenharmony_ci	  gamma[6] = color;
2459141cc406Sopenharmony_ci
2460141cc406Sopenharmony_ci	  if (color == 0)
2461141cc406Sopenharmony_ci	    {
2462141cc406Sopenharmony_ci	      val_a = s->gamma_table[0][1];
2463141cc406Sopenharmony_ci	      val_b = s->gamma_table[0][0];
2464141cc406Sopenharmony_ci	    }
2465141cc406Sopenharmony_ci	  else
2466141cc406Sopenharmony_ci	    {
2467141cc406Sopenharmony_ci	      /* compose intensity gamma and color channel gamma: */
2468141cc406Sopenharmony_ci	      val_a = s->gamma_table[0][s->gamma_table[color][1]];
2469141cc406Sopenharmony_ci	      val_b = s->gamma_table[0][s->gamma_table[color][0]];
2470141cc406Sopenharmony_ci	    }
2471141cc406Sopenharmony_ci	  /* Now val_a is extrapolated from [0] and [1]      */
2472141cc406Sopenharmony_ci	  val_a = MAX (2 * val_b - val_a, 0);
2473141cc406Sopenharmony_ci
2474141cc406Sopenharmony_ci	  /* Interpolate first entries from 256 entry table  */
2475141cc406Sopenharmony_ci	  cp = gamma + CDB_SIZE (MUSTEK_SCSI_SEND_DATA);
2476141cc406Sopenharmony_ci	  for (j = 0; j < factor; j++)
2477141cc406Sopenharmony_ci	    *cp++ = CLIP (((factor - j) * val_a + j * val_b
2478141cc406Sopenharmony_ci			   + factor / 2) / factor);
2479141cc406Sopenharmony_ci
2480141cc406Sopenharmony_ci	  for (i = 1; i < 256; i++)
2481141cc406Sopenharmony_ci	    {
2482141cc406Sopenharmony_ci	      if (color == 0)
2483141cc406Sopenharmony_ci		{
2484141cc406Sopenharmony_ci		  val_a = s->gamma_table[0][i - 1];
2485141cc406Sopenharmony_ci		  val_b = s->gamma_table[0][i];
2486141cc406Sopenharmony_ci		}
2487141cc406Sopenharmony_ci	      else
2488141cc406Sopenharmony_ci		{
2489141cc406Sopenharmony_ci		  /* compose intensity gamma and color channel gamma: */
2490141cc406Sopenharmony_ci		  val_a = s->gamma_table[0][s->gamma_table[color][i - 1]];
2491141cc406Sopenharmony_ci		  val_b = s->gamma_table[0][s->gamma_table[color][i]];
2492141cc406Sopenharmony_ci		}
2493141cc406Sopenharmony_ci
2494141cc406Sopenharmony_ci	      /* Interpolate next entries from the 256 entry table */
2495141cc406Sopenharmony_ci	      for (j = 0; j < factor; j++)
2496141cc406Sopenharmony_ci		*cp++ = CLIP (((factor - j) * val_a + j * val_b
2497141cc406Sopenharmony_ci			       + factor / 2) / factor);
2498141cc406Sopenharmony_ci	    }
2499141cc406Sopenharmony_ci
2500141cc406Sopenharmony_ci	  DBG (5, "send_gamma_table_se: sending table for color %d\n",
2501141cc406Sopenharmony_ci	       gamma[6]);
2502141cc406Sopenharmony_ci	  status = dev_cmd (s, gamma, CDB_SIZE (MUSTEK_SCSI_SEND_DATA)
2503141cc406Sopenharmony_ci			    + s->hw->gamma_length, 0, 0);
2504141cc406Sopenharmony_ci	  ++color;
2505141cc406Sopenharmony_ci	}
2506141cc406Sopenharmony_ci      while ((color != 1) & (color < 4) & (status == SANE_STATUS_GOOD));
2507141cc406Sopenharmony_ci
2508141cc406Sopenharmony_ci      return status;
2509141cc406Sopenharmony_ci    }
2510141cc406Sopenharmony_ci  else
2511141cc406Sopenharmony_ci    {
2512141cc406Sopenharmony_ci      /* In lineart mode the threshold is encoded in byte 8 as follows */
2513141cc406Sopenharmony_ci      /* brightest -> 00 01 02 ... 7F 80 81 82 ... FF <- darkest image */
2514141cc406Sopenharmony_ci      gamma[6] = 0x04;
2515141cc406Sopenharmony_ci      gamma[8] = 128 - 127 * SANE_UNFIX (s->val[OPT_BRIGHTNESS].w) / 100.0;
2516141cc406Sopenharmony_ci
2517141cc406Sopenharmony_ci      DBG (5, "send_gamma_table_se: sending lineart threshold %2X\n",
2518141cc406Sopenharmony_ci	   gamma[8]);
2519141cc406Sopenharmony_ci      return dev_cmd (s, gamma, CDB_SIZE (MUSTEK_SCSI_SEND_DATA), 0, 0);
2520141cc406Sopenharmony_ci    }
2521141cc406Sopenharmony_ci}
2522141cc406Sopenharmony_ci
2523141cc406Sopenharmony_ci/* Paragon series */
2524141cc406Sopenharmony_cistatic SANE_Status
2525141cc406Sopenharmony_cimode_select_paragon (Mustek_Scanner * s, SANE_Int color_code)
2526141cc406Sopenharmony_ci{
2527141cc406Sopenharmony_ci  SANE_Int speed_code;
2528141cc406Sopenharmony_ci  SANE_Byte mode[19], *cp;
2529141cc406Sopenharmony_ci
2530141cc406Sopenharmony_ci  /* calculate funky speed code: */
2531141cc406Sopenharmony_ci  for (speed_code = 0; speed_list[speed_code]; ++speed_code)
2532141cc406Sopenharmony_ci    {
2533141cc406Sopenharmony_ci      if (strcmp (speed_list[speed_code], s->val[OPT_SPEED].s) == 0)
2534141cc406Sopenharmony_ci	break;
2535141cc406Sopenharmony_ci    }
2536141cc406Sopenharmony_ci  if (speed_code > 4)
2537141cc406Sopenharmony_ci    speed_code = 4;
2538141cc406Sopenharmony_ci  else if (speed_code < 0)
2539141cc406Sopenharmony_ci    speed_code = 0;
2540141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2541141cc406Sopenharmony_ci    {
2542141cc406Sopenharmony_ci      speed_code = 5 - speed_code;	/* 1 is fast, 5 is slow */
2543141cc406Sopenharmony_ci    }
2544141cc406Sopenharmony_ci  else
2545141cc406Sopenharmony_ci    {
2546141cc406Sopenharmony_ci      speed_code = 4 - speed_code;	/* 0 is fast, 4 is slow */
2547141cc406Sopenharmony_ci    }
2548141cc406Sopenharmony_ci  memset (mode, 0, sizeof (mode));
2549141cc406Sopenharmony_ci  mode[0] = MUSTEK_SCSI_MODE_SELECT;
2550141cc406Sopenharmony_ci
2551141cc406Sopenharmony_ci  /* set command length and resolution code: */
2552141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2553141cc406Sopenharmony_ci    {
2554141cc406Sopenharmony_ci      mode[4] = 0x0b;
2555141cc406Sopenharmony_ci      mode[7] = s->resolution_code;
2556141cc406Sopenharmony_ci    }
2557141cc406Sopenharmony_ci  else
2558141cc406Sopenharmony_ci    {
2559141cc406Sopenharmony_ci      mode[4] = 0x0d;
2560141cc406Sopenharmony_ci      cp = mode + 17;
2561141cc406Sopenharmony_ci      STORE16L (cp, s->resolution_code);
2562141cc406Sopenharmony_ci    }
2563141cc406Sopenharmony_ci  /* set mode byte: */
2564141cc406Sopenharmony_ci  mode[6] = 0x83 | (color_code << 5);
2565141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_USE_EIGHTS))
2566141cc406Sopenharmony_ci    mode[6] |= 0x08;
2567141cc406Sopenharmony_ci  if (s->custom_halftone_pattern)
2568141cc406Sopenharmony_ci    mode[6] |= 0x10;
2569141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_PARAGON_1)
2570141cc406Sopenharmony_ci    {
2571141cc406Sopenharmony_ci      if ((s->mode == MUSTEK_MODE_LINEART)
2572141cc406Sopenharmony_ci	  || (s->mode == MUSTEK_MODE_HALFTONE))
2573141cc406Sopenharmony_ci	{
2574141cc406Sopenharmony_ci	  mode[8] =
2575141cc406Sopenharmony_ci	    encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w));
2576141cc406Sopenharmony_ci	  mode[9] =
2577141cc406Sopenharmony_ci	    encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w));
2578141cc406Sopenharmony_ci	}
2579141cc406Sopenharmony_ci      else
2580141cc406Sopenharmony_ci	{
2581141cc406Sopenharmony_ci	  mode[8] = 0x0c;
2582141cc406Sopenharmony_ci	  mode[9] = 0x0c;
2583141cc406Sopenharmony_ci	}
2584141cc406Sopenharmony_ci      mode[10] = 2;		/* grain */
2585141cc406Sopenharmony_ci      if (s->val[OPT_PREVIEW].w && s->val[OPT_FAST_PREVIEW].w)
2586141cc406Sopenharmony_ci	mode[11] = 0x01;
2587141cc406Sopenharmony_ci      else if ((s->mode == MUSTEK_MODE_COLOR)
2588141cc406Sopenharmony_ci	       || (s->mode == MUSTEK_MODE_HALFTONE))
2589141cc406Sopenharmony_ci	mode[11] = 0x00;	/* speed */
2590141cc406Sopenharmony_ci      else
2591141cc406Sopenharmony_ci	mode[11] = 0x02;	/* speed */
2592141cc406Sopenharmony_ci      mode[12] = 0x00;		/* shadow param not used by Mustek */
2593141cc406Sopenharmony_ci      mode[13] = 0xff;		/* highlight only used by some scanners */
2594141cc406Sopenharmony_ci      mode[14] = 0x70;		/* paper- */
2595141cc406Sopenharmony_ci      mode[15] = 0x00;		/* length */
2596141cc406Sopenharmony_ci      mode[16] = 0x53;		/* midtone param not used by Mustek */
2597141cc406Sopenharmony_ci    }
2598141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_PARAGON_2)
2599141cc406Sopenharmony_ci    {
2600141cc406Sopenharmony_ci      mode[8] = encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w));
2601141cc406Sopenharmony_ci      mode[9] = encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w));
2602141cc406Sopenharmony_ci      mode[10] = 2;		/* grain */
2603141cc406Sopenharmony_ci      if ((s->mode == MUSTEK_MODE_COLOR) || (s->mode == MUSTEK_MODE_HALFTONE))
2604141cc406Sopenharmony_ci	mode[11] = 0x00;	/* speed */
2605141cc406Sopenharmony_ci      else
2606141cc406Sopenharmony_ci	mode[11] = 0x02;	/* speed */
2607141cc406Sopenharmony_ci      mode[12] = 0x00;		/* shadow param not used by Mustek */
2608141cc406Sopenharmony_ci      mode[13] = 0x00;		/* highlight param not used by Mustek */
2609141cc406Sopenharmony_ci      mode[14] = 0x5c;		/* paper- */
2610141cc406Sopenharmony_ci      mode[15] = 0x00;		/* length */
2611141cc406Sopenharmony_ci      mode[16] = 0x41;		/* midtone param not used by Mustek */
2612141cc406Sopenharmony_ci    }
2613141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2614141cc406Sopenharmony_ci    {
2615141cc406Sopenharmony_ci      if (s->mode & MUSTEK_MODE_COLOR)
2616141cc406Sopenharmony_ci	{
2617141cc406Sopenharmony_ci	  mode[8] = encode_percentage
2618141cc406Sopenharmony_ci	    (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS + s->pass + 1].w - 1));
2619141cc406Sopenharmony_ci	  mode[9] = encode_percentage
2620141cc406Sopenharmony_ci	    (s, SANE_UNFIX (s->val[OPT_CONTRAST + s->pass + 1].w - 1));
2621141cc406Sopenharmony_ci	}
2622141cc406Sopenharmony_ci      else
2623141cc406Sopenharmony_ci	{
2624141cc406Sopenharmony_ci	  mode[8] = encode_percentage
2625141cc406Sopenharmony_ci	    (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w - 1));
2626141cc406Sopenharmony_ci	  mode[9] = encode_percentage
2627141cc406Sopenharmony_ci	    (s, SANE_UNFIX (s->val[OPT_CONTRAST].w - 1));
2628141cc406Sopenharmony_ci	}
2629141cc406Sopenharmony_ci      mode[10] = s->halftone_pattern_type;
2630141cc406Sopenharmony_ci      mode[11] = speed_code;	/* lamp setting not supported yet */
2631141cc406Sopenharmony_ci      mode[12] = 0;		/* shadow param not used by Mustek */
2632141cc406Sopenharmony_ci      mode[13] = 0;		/* highlight param not used by Mustek */
2633141cc406Sopenharmony_ci      mode[14] = mode[15] = 0;	/* paperlength not used by Mustek */
2634141cc406Sopenharmony_ci      mode[16] = 0;		/* midtone param not used by Mustek */
2635141cc406Sopenharmony_ci    }
2636141cc406Sopenharmony_ci  else
2637141cc406Sopenharmony_ci    {
2638141cc406Sopenharmony_ci      mode[8] = encode_percentage (s, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w));
2639141cc406Sopenharmony_ci      mode[9] = encode_percentage (s, SANE_UNFIX (s->val[OPT_CONTRAST].w));
2640141cc406Sopenharmony_ci      mode[10] = s->halftone_pattern_type;
2641141cc406Sopenharmony_ci      mode[11] = speed_code;	/* lamp setting not supported yet */
2642141cc406Sopenharmony_ci      mode[12] = 0;		/* shadow param not used by Mustek */
2643141cc406Sopenharmony_ci      mode[13] = 0;		/* highlight param not used by Mustek */
2644141cc406Sopenharmony_ci      mode[14] = mode[15] = 0;	/* paperlength not used by Mustek */
2645141cc406Sopenharmony_ci      mode[16] = 0;		/* midtone param not used by Mustek */
2646141cc406Sopenharmony_ci    }
2647141cc406Sopenharmony_ci
2648141cc406Sopenharmony_ci  DBG (5, "mode_select: resolution_code=%d (0x%x)\n", s->resolution_code,
2649141cc406Sopenharmony_ci       s->resolution_code);
2650141cc406Sopenharmony_ci  return dev_cmd (s, mode, 6 + mode[4], 0, 0);
2651141cc406Sopenharmony_ci}
2652141cc406Sopenharmony_ci
2653141cc406Sopenharmony_ci/* Pro series */
2654141cc406Sopenharmony_cistatic SANE_Status
2655141cc406Sopenharmony_cimode_select_pro (Mustek_Scanner * s)
2656141cc406Sopenharmony_ci{
2657141cc406Sopenharmony_ci  SANE_Byte mode[19], *cp;
2658141cc406Sopenharmony_ci
2659141cc406Sopenharmony_ci  memset (mode, 0, sizeof (mode));
2660141cc406Sopenharmony_ci
2661141cc406Sopenharmony_ci  mode[0] = MUSTEK_SCSI_MODE_SELECT;
2662141cc406Sopenharmony_ci  mode[4] = 0x0d;
2663141cc406Sopenharmony_ci
2664141cc406Sopenharmony_ci  if (s->mode & MUSTEK_MODE_COLOR)
2665141cc406Sopenharmony_ci    {
2666141cc406Sopenharmony_ci      if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0)
2667141cc406Sopenharmony_ci	mode[6] = 0xE0;
2668141cc406Sopenharmony_ci      else
2669141cc406Sopenharmony_ci	mode[6] = 0x60;
2670141cc406Sopenharmony_ci    }
2671141cc406Sopenharmony_ci  else if (s->mode & MUSTEK_MODE_GRAY)
2672141cc406Sopenharmony_ci    {
2673141cc406Sopenharmony_ci      if (s->val[OPT_FAST_GRAY_MODE].w)
2674141cc406Sopenharmony_ci	mode[6] = 0x20;
2675141cc406Sopenharmony_ci      else
2676141cc406Sopenharmony_ci	mode[6] = 0x40;
2677141cc406Sopenharmony_ci    }
2678141cc406Sopenharmony_ci  else
2679141cc406Sopenharmony_ci    mode[6] = 0x00;		/* lineart */
2680141cc406Sopenharmony_ci
2681141cc406Sopenharmony_ci  mode[7] = 0;
2682141cc406Sopenharmony_ci  mode[8] = 0;
2683141cc406Sopenharmony_ci  mode[9] = 0;
2684141cc406Sopenharmony_ci  mode[10] = 0;
2685141cc406Sopenharmony_ci  mode[11] = 0x00;
2686141cc406Sopenharmony_ci  mode[12] = 0x27;
2687141cc406Sopenharmony_ci  mode[13] = 0xb0;
2688141cc406Sopenharmony_ci  mode[14] = 0x04;
2689141cc406Sopenharmony_ci  mode[15] = 0x43;
2690141cc406Sopenharmony_ci  mode[16] = 0x41;
2691141cc406Sopenharmony_ci
2692141cc406Sopenharmony_ci  cp = mode + 17;
2693141cc406Sopenharmony_ci  STORE16L (cp, s->resolution_code);
2694141cc406Sopenharmony_ci
2695141cc406Sopenharmony_ci  DBG (5, "mode_select_pro: resolution_code=%d (0x%x), mode=0x%x\n",
2696141cc406Sopenharmony_ci       s->resolution_code, s->resolution_code, mode[6]);
2697141cc406Sopenharmony_ci  return dev_cmd (s, mode, 6 + mode[4], 0, 0);
2698141cc406Sopenharmony_ci}
2699141cc406Sopenharmony_ci
2700141cc406Sopenharmony_ci/* Paragon and Pro series. According to Mustek, the only builtin gamma
2701141cc406Sopenharmony_ci   table is a linear table, so all we support here is user-defined
2702141cc406Sopenharmony_ci   gamma tables.  */
2703141cc406Sopenharmony_cistatic SANE_Status
2704141cc406Sopenharmony_cigamma_correction (Mustek_Scanner * s, SANE_Int color_code)
2705141cc406Sopenharmony_ci{
2706141cc406Sopenharmony_ci  SANE_Int i, j, table = 0, len = 0, bytes_per_channel, num_channels = 1;
2707141cc406Sopenharmony_ci  SANE_Byte gamma[4096 + 10], val, *cp;	/* for Paragon models 3 x 256 is the
2708141cc406Sopenharmony_ci					   maximum. Pro needs 4096 bytes */
2709141cc406Sopenharmony_ci
2710141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_N)
2711141cc406Sopenharmony_ci      && ((s->mode & MUSTEK_MODE_LINEART)
2712141cc406Sopenharmony_ci	  || (s->mode & MUSTEK_MODE_HALFTONE)))
2713141cc406Sopenharmony_ci    {
2714141cc406Sopenharmony_ci      /* sigh! - the 600 II N needs a (dummy) table download even for
2715141cc406Sopenharmony_ci         lineart and halftone mode, else it produces a completely
2716141cc406Sopenharmony_ci         white image. Thank Mustek for their buggy firmware !  */
2717141cc406Sopenharmony_ci      memset (gamma, 0, sizeof (gamma));
2718141cc406Sopenharmony_ci      gamma[0] = MUSTEK_SCSI_LOOKUP_TABLE;
2719141cc406Sopenharmony_ci      gamma[2] = 0x0;		/* indicate any preloaded gamma table */
2720141cc406Sopenharmony_ci      DBG (5, "gamma_correction: sending dummy gamma table\n");
2721141cc406Sopenharmony_ci      return dev_cmd (s, gamma, 6, 0, 0);
2722141cc406Sopenharmony_ci    }
2723141cc406Sopenharmony_ci
2724141cc406Sopenharmony_ci  if (((s->mode & MUSTEK_MODE_LINEART) || (s->mode & MUSTEK_MODE_HALFTONE))
2725141cc406Sopenharmony_ci      && !(s->hw->flags & MUSTEK_FLAG_PRO))
2726141cc406Sopenharmony_ci    {
2727141cc406Sopenharmony_ci      DBG (5, "gamma_correction: nothing to do in lineart mode -- exiting\n");
2728141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2729141cc406Sopenharmony_ci    }
2730141cc406Sopenharmony_ci
2731141cc406Sopenharmony_ci  if ((!s->val[OPT_CUSTOM_GAMMA].w) && (!(s->hw->flags & MUSTEK_FLAG_PRO)))
2732141cc406Sopenharmony_ci    {
2733141cc406Sopenharmony_ci      /* Do we need to upload a gamma table even if the user didn't select
2734141cc406Sopenharmony_ci         this option? Some scanners need this work around. */
2735141cc406Sopenharmony_ci      if (!(s->hw->flags & MUSTEK_FLAG_FORCE_GAMMA) ||
2736141cc406Sopenharmony_ci	  !((s->mode & MUSTEK_MODE_COLOR) || (s->mode & MUSTEK_MODE_GRAY)))
2737141cc406Sopenharmony_ci	{
2738141cc406Sopenharmony_ci	  DBG (5,
2739141cc406Sopenharmony_ci	       "gamma_correction: no custom table selected -- exititing\n");
2740141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2741141cc406Sopenharmony_ci	}
2742141cc406Sopenharmony_ci    }
2743141cc406Sopenharmony_ci
2744141cc406Sopenharmony_ci  if (s->mode & MUSTEK_MODE_COLOR)
2745141cc406Sopenharmony_ci    {
2746141cc406Sopenharmony_ci      table = 1;
2747141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2748141cc406Sopenharmony_ci	table += s->pass;
2749141cc406Sopenharmony_ci      else
2750141cc406Sopenharmony_ci	{
2751141cc406Sopenharmony_ci	  if ((color_code == MUSTEK_CODE_GRAY)
2752141cc406Sopenharmony_ci	      && !(s->hw->flags & MUSTEK_FLAG_PRO))
2753141cc406Sopenharmony_ci	    num_channels = 3;
2754141cc406Sopenharmony_ci	  else
2755141cc406Sopenharmony_ci	    table = color_code;
2756141cc406Sopenharmony_ci	}
2757141cc406Sopenharmony_ci    }
2758141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_N)
2759141cc406Sopenharmony_ci    {
2760141cc406Sopenharmony_ci      /* it seems 600 II N (firmware 1.x at least) wants 768 bytes in
2761141cc406Sopenharmony_ci       * gray mode too */
2762141cc406Sopenharmony_ci      num_channels = 3;
2763141cc406Sopenharmony_ci    }
2764141cc406Sopenharmony_ci
2765141cc406Sopenharmony_ci  memset (gamma, 0, sizeof (gamma));
2766141cc406Sopenharmony_ci  gamma[0] = MUSTEK_SCSI_LOOKUP_TABLE;
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_PRO)
2769141cc406Sopenharmony_ci    {
2770141cc406Sopenharmony_ci      bytes_per_channel = 4096;
2771141cc406Sopenharmony_ci      len = bytes_per_channel;
2772141cc406Sopenharmony_ci      if (s->mode == MUSTEK_MODE_COLOR)
2773141cc406Sopenharmony_ci	{
2774141cc406Sopenharmony_ci	  gamma[9] = (color_code << 6);	/* color */
2775141cc406Sopenharmony_ci	  if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0)
2776141cc406Sopenharmony_ci	    gamma[2] = 0x7f;	/* medium brightness */
2777141cc406Sopenharmony_ci	}
2778141cc406Sopenharmony_ci      else if (s->mode == MUSTEK_MODE_GRAY)
2779141cc406Sopenharmony_ci	{
2780141cc406Sopenharmony_ci	  gamma[9] = 0x80;	/* grayscale */
2781141cc406Sopenharmony_ci	  if (s->val[OPT_FAST_GRAY_MODE].w)
2782141cc406Sopenharmony_ci	    gamma[2] = 0x7f;	/* medium brightness */
2783141cc406Sopenharmony_ci	}
2784141cc406Sopenharmony_ci      else			/* lineart */
2785141cc406Sopenharmony_ci	{
2786141cc406Sopenharmony_ci	  gamma[2] =
2787141cc406Sopenharmony_ci	    128 - 127 * SANE_UNFIX (s->val[OPT_BRIGHTNESS].w) / 100.0;
2788141cc406Sopenharmony_ci	  gamma[9] = 0x80;	/* grayscale/lineart */
2789141cc406Sopenharmony_ci	  DBG (5, "gamma_correction: sending brightness information\n");
2790141cc406Sopenharmony_ci	}
2791141cc406Sopenharmony_ci      gamma[7] = (len >> 8) & 0xff;	/* big endian! */
2792141cc406Sopenharmony_ci      gamma[8] = (len >> 0) & 0xff;
2793141cc406Sopenharmony_ci    }
2794141cc406Sopenharmony_ci  else
2795141cc406Sopenharmony_ci    {
2796141cc406Sopenharmony_ci      bytes_per_channel = 256;
2797141cc406Sopenharmony_ci      len = num_channels * bytes_per_channel;
2798141cc406Sopenharmony_ci      gamma[2] = 0x27;		/* indicate user-selected gamma table */
2799141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_N)
2800141cc406Sopenharmony_ci	{
2801141cc406Sopenharmony_ci	  /* 600 II N always uses 6-byte cdb */
2802141cc406Sopenharmony_ci	  gamma[3] = (len >> 8) & 0xff;	/* big endian! */
2803141cc406Sopenharmony_ci	  gamma[4] = (len >> 0) & 0xff;
2804141cc406Sopenharmony_ci	  /* no way to pass color_code (?) */
2805141cc406Sopenharmony_ci	}
2806141cc406Sopenharmony_ci      else
2807141cc406Sopenharmony_ci	{
2808141cc406Sopenharmony_ci	  gamma[7] = (len >> 8) & 0xff;	/* big endian! */
2809141cc406Sopenharmony_ci	  gamma[8] = (len >> 0) & 0xff;
2810141cc406Sopenharmony_ci	  gamma[9] = (color_code << 6);
2811141cc406Sopenharmony_ci	}
2812141cc406Sopenharmony_ci    }
2813141cc406Sopenharmony_ci
2814141cc406Sopenharmony_ci  if (len > 0)
2815141cc406Sopenharmony_ci    {
2816141cc406Sopenharmony_ci      cp = gamma + 10;
2817141cc406Sopenharmony_ci      for (j = 0; j < num_channels; ++j)
2818141cc406Sopenharmony_ci	{
2819141cc406Sopenharmony_ci	  for (i = 0; i < bytes_per_channel; ++i)
2820141cc406Sopenharmony_ci	    {
2821141cc406Sopenharmony_ci	      if (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
2822141cc406Sopenharmony_ci		val = s->gamma_table[table][i * 256 / bytes_per_channel];
2823141cc406Sopenharmony_ci	      else
2824141cc406Sopenharmony_ci		val = i * 256 / bytes_per_channel;
2825141cc406Sopenharmony_ci	      if ((s->mode & MUSTEK_MODE_COLOR)
2826141cc406Sopenharmony_ci		  && (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE))
2827141cc406Sopenharmony_ci		/* compose intensity gamma and color channel gamma: */
2828141cc406Sopenharmony_ci		val = s->gamma_table[0][val];
2829141cc406Sopenharmony_ci	      *cp++ = val;
2830141cc406Sopenharmony_ci	    }
2831141cc406Sopenharmony_ci	  if (!(s->hw->flags & MUSTEK_FLAG_N)
2832141cc406Sopenharmony_ci	      || !(s->mode & MUSTEK_MODE_GRAY))
2833141cc406Sopenharmony_ci	    table++;
2834141cc406Sopenharmony_ci	}
2835141cc406Sopenharmony_ci    }
2836141cc406Sopenharmony_ci  DBG (5, "gamma_correction: sending gamma table of %d bytes\n", len);
2837141cc406Sopenharmony_ci  return dev_cmd (s, gamma, 10 + len, 0, 0);
2838141cc406Sopenharmony_ci}
2839141cc406Sopenharmony_ci
2840141cc406Sopenharmony_cistatic SANE_Status
2841141cc406Sopenharmony_cisend_gamma_table (Mustek_Scanner * s)
2842141cc406Sopenharmony_ci{
2843141cc406Sopenharmony_ci  SANE_Status status;
2844141cc406Sopenharmony_ci
2845141cc406Sopenharmony_ci  if (s->one_pass_color_scan)
2846141cc406Sopenharmony_ci    {
2847141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_N)
2848141cc406Sopenharmony_ci	/* This _should_ work for all one-pass scanners (not just
2849141cc406Sopenharmony_ci	   AB306N scanners), but it doesn't work for my Paragon
2850141cc406Sopenharmony_ci	   600 II SP with firmware rev 1.01.  Too bad, since it would
2851141cc406Sopenharmony_ci	   simplify the gamma correction code quite a bit.  */
2852141cc406Sopenharmony_ci	status = gamma_correction (s, MUSTEK_CODE_GRAY);
2853141cc406Sopenharmony_ci      else
2854141cc406Sopenharmony_ci	{
2855141cc406Sopenharmony_ci	  status = gamma_correction (s, MUSTEK_CODE_RED);
2856141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2857141cc406Sopenharmony_ci	    return status;
2858141cc406Sopenharmony_ci
2859141cc406Sopenharmony_ci	  status = gamma_correction (s, MUSTEK_CODE_GREEN);
2860141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2861141cc406Sopenharmony_ci	    return status;
2862141cc406Sopenharmony_ci
2863141cc406Sopenharmony_ci	  status = gamma_correction (s, MUSTEK_CODE_BLUE);
2864141cc406Sopenharmony_ci	}
2865141cc406Sopenharmony_ci    }
2866141cc406Sopenharmony_ci  else
2867141cc406Sopenharmony_ci    status = gamma_correction (s, MUSTEK_CODE_GRAY);
2868141cc406Sopenharmony_ci  return status;
2869141cc406Sopenharmony_ci}
2870141cc406Sopenharmony_ci
2871141cc406Sopenharmony_ci
2872141cc406Sopenharmony_ci/* ScanExpress and Paragon series */
2873141cc406Sopenharmony_cistatic SANE_Status
2874141cc406Sopenharmony_cistart_scan (Mustek_Scanner * s)
2875141cc406Sopenharmony_ci{
2876141cc406Sopenharmony_ci  SANE_Byte start[6];
2877141cc406Sopenharmony_ci  SANE_Status status;
2878141cc406Sopenharmony_ci
2879141cc406Sopenharmony_ci  memset (start, 0, sizeof (start));
2880141cc406Sopenharmony_ci  start[0] = MUSTEK_SCSI_START_STOP;
2881141cc406Sopenharmony_ci  start[4] = 0x01;
2882141cc406Sopenharmony_ci
2883141cc406Sopenharmony_ci  DBG (4, "start_scan\n");
2884141cc406Sopenharmony_ci  /* ScanExpress and Pro models don't have any variants */
2885141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_SE) && !(s->hw->flags & MUSTEK_FLAG_PRO))
2886141cc406Sopenharmony_ci    {
2887141cc406Sopenharmony_ci      if (s->mode & MUSTEK_MODE_COLOR)
2888141cc406Sopenharmony_ci	{
2889141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2890141cc406Sopenharmony_ci	    start[4] |= ((s->pass + 1) << 3);
2891141cc406Sopenharmony_ci	  else
2892141cc406Sopenharmony_ci	    start[4] |= 0x20;
2893141cc406Sopenharmony_ci	}
2894141cc406Sopenharmony_ci      /* or in single/multi bit: */
2895141cc406Sopenharmony_ci      start[4] |= ((s->mode & MUSTEK_MODE_LINEART)
2896141cc406Sopenharmony_ci		   || (s->mode & MUSTEK_MODE_HALFTONE)) ? 0 : (1 << 6);
2897141cc406Sopenharmony_ci
2898141cc406Sopenharmony_ci      /* or in expanded resolution bit: */
2899141cc406Sopenharmony_ci      if (s->val[OPT_RESOLUTION].w > (s->hw->dpi_range.max / 2)
2900141cc406Sopenharmony_ci	  && ((s->hw->flags & MUSTEK_FLAG_THREE_PASS)
2901141cc406Sopenharmony_ci	      || (s->hw->flags & MUSTEK_FLAG_PARAGON_1)
2902141cc406Sopenharmony_ci	      || (s->hw->flags & MUSTEK_FLAG_PARAGON_2)))
2903141cc406Sopenharmony_ci	start[4] |= 1 << 7;
2904141cc406Sopenharmony_ci
2905141cc406Sopenharmony_ci      /* block mode (or whatever) */
2906141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_USE_BLOCK)
2907141cc406Sopenharmony_ci	{
2908141cc406Sopenharmony_ci	  start[5] = 0x08;
2909141cc406Sopenharmony_ci	  DBG (4, "start_scan: using block mode\n");
2910141cc406Sopenharmony_ci	}
2911141cc406Sopenharmony_ci    }
2912141cc406Sopenharmony_ci
2913141cc406Sopenharmony_ci  status = dev_cmd (s, start, sizeof (start), 0, 0);
2914141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2915141cc406Sopenharmony_ci    DBG (1, "start_scan returned status %s\n", sane_strstatus (status));
2916141cc406Sopenharmony_ci  return status;
2917141cc406Sopenharmony_ci}
2918141cc406Sopenharmony_ci
2919141cc406Sopenharmony_cistatic SANE_Status
2920141cc406Sopenharmony_cido_eof (Mustek_Scanner * s)
2921141cc406Sopenharmony_ci{
2922141cc406Sopenharmony_ci  if (s->pipe >= 0)
2923141cc406Sopenharmony_ci    {
2924141cc406Sopenharmony_ci      close (s->pipe);
2925141cc406Sopenharmony_ci      s->pipe = -1;
2926141cc406Sopenharmony_ci      DBG (5, "do_eof: closing pipe\n");
2927141cc406Sopenharmony_ci    }
2928141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
2929141cc406Sopenharmony_ci}
2930141cc406Sopenharmony_ci
2931141cc406Sopenharmony_cistatic SANE_Status
2932141cc406Sopenharmony_cido_stop (Mustek_Scanner * s)
2933141cc406Sopenharmony_ci{
2934141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
2935141cc406Sopenharmony_ci
2936141cc406Sopenharmony_ci  DBG (5, "do_stop\n");
2937141cc406Sopenharmony_ci
2938141cc406Sopenharmony_ci  if (s->cancelled)
2939141cc406Sopenharmony_ci    status = SANE_STATUS_CANCELLED;
2940141cc406Sopenharmony_ci
2941141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
2942141cc406Sopenharmony_ci  s->pass = 0;
2943141cc406Sopenharmony_ci
2944141cc406Sopenharmony_ci  if (sanei_thread_is_valid (s->reader_pid))
2945141cc406Sopenharmony_ci    {
2946141cc406Sopenharmony_ci      SANE_Int exit_status;
2947141cc406Sopenharmony_ci      struct timeval now;
2948141cc406Sopenharmony_ci      long int scan_time;
2949141cc406Sopenharmony_ci      long int scan_size;
2950141cc406Sopenharmony_ci      SANE_Pid pid;
2951141cc406Sopenharmony_ci
2952141cc406Sopenharmony_ci      /* print scanning time */
2953141cc406Sopenharmony_ci      gettimeofday (&now, 0);
2954141cc406Sopenharmony_ci      scan_time = now.tv_sec - s->start_time;
2955141cc406Sopenharmony_ci      if (scan_time < 1)
2956141cc406Sopenharmony_ci	scan_time = 1;
2957141cc406Sopenharmony_ci      scan_size = s->hw->bpl * s->hw->lines / 1024;
2958141cc406Sopenharmony_ci      DBG (2, "Scanning time was %ld seconds, %ld kB/s\n", scan_time,
2959141cc406Sopenharmony_ci	   scan_size / scan_time);
2960141cc406Sopenharmony_ci
2961141cc406Sopenharmony_ci      if (s->total_bytes == s->params.lines * s->params.bytes_per_line)
2962141cc406Sopenharmony_ci	DBG (3, "Scanned %d bytes as expected\n", s->total_bytes);
2963141cc406Sopenharmony_ci      else if (s->total_bytes < s->params.lines * s->params.bytes_per_line)
2964141cc406Sopenharmony_ci	DBG (3, "Scanned %d bytes, expected %d bytes\n", s->total_bytes,
2965141cc406Sopenharmony_ci	     s->params.lines * s->params.bytes_per_line);
2966141cc406Sopenharmony_ci      else
2967141cc406Sopenharmony_ci	DBG (1, "Warning: Scanned %d bytes, but expected only %d bytes\n",
2968141cc406Sopenharmony_ci	     s->total_bytes, s->params.lines * s->params.bytes_per_line);
2969141cc406Sopenharmony_ci
2970141cc406Sopenharmony_ci      /* ensure child knows it's time to stop: */
2971141cc406Sopenharmony_ci      DBG (5, "do_stop: terminating reader process\n");
2972141cc406Sopenharmony_ci      sanei_thread_kill (s->reader_pid);
2973141cc406Sopenharmony_ci
2974141cc406Sopenharmony_ci      pid = sanei_thread_waitpid (s->reader_pid, &exit_status);
2975141cc406Sopenharmony_ci      if (!sanei_thread_is_valid (pid))
2976141cc406Sopenharmony_ci	{
2977141cc406Sopenharmony_ci	  DBG (1,
2978141cc406Sopenharmony_ci	       "do_stop: sanei_thread_waitpid failed, already terminated? (%s)\n",
2979141cc406Sopenharmony_ci	       strerror (errno));
2980141cc406Sopenharmony_ci	}
2981141cc406Sopenharmony_ci      else
2982141cc406Sopenharmony_ci	{
2983141cc406Sopenharmony_ci	  DBG (2, "do_stop: reader process terminated with status %s\n",
2984141cc406Sopenharmony_ci	       sane_strstatus (exit_status));
2985141cc406Sopenharmony_ci	  if (status != SANE_STATUS_CANCELLED
2986141cc406Sopenharmony_ci	      && exit_status != SANE_STATUS_GOOD)
2987141cc406Sopenharmony_ci	    status = exit_status;
2988141cc406Sopenharmony_ci	}
2989141cc406Sopenharmony_ci
2990141cc406Sopenharmony_ci      sanei_thread_invalidate (s->reader_pid);
2991141cc406Sopenharmony_ci    }
2992141cc406Sopenharmony_ci
2993141cc406Sopenharmony_ci  if (s->fd >= 0)
2994141cc406Sopenharmony_ci    {
2995141cc406Sopenharmony_ci      if (!sanei_thread_is_forked ())
2996141cc406Sopenharmony_ci	sanei_scsi_req_flush_all ();	/* flush SCSI queue */
2997141cc406Sopenharmony_ci
2998141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_PRO)
2999141cc406Sopenharmony_ci	{
3000141cc406Sopenharmony_ci	  if (s->total_bytes < s->params.lines * s->params.bytes_per_line)
3001141cc406Sopenharmony_ci	    status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop),
3002141cc406Sopenharmony_ci			      0, 0);
3003141cc406Sopenharmony_ci	  dev_wait_ready (s);
3004141cc406Sopenharmony_ci	}
3005141cc406Sopenharmony_ci      else if ((s->hw->flags & MUSTEK_FLAG_PARAGON_1)
3006141cc406Sopenharmony_ci	       || (s->hw->flags & MUSTEK_FLAG_PARAGON_2)
3007141cc406Sopenharmony_ci	       || (s->hw->flags & MUSTEK_FLAG_THREE_PASS))
3008141cc406Sopenharmony_ci	{
3009141cc406Sopenharmony_ci	  if (s->cancelled &&
3010141cc406Sopenharmony_ci	      (s->total_bytes < s->params.lines * s->params.bytes_per_line))
3011141cc406Sopenharmony_ci	    status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop),
3012141cc406Sopenharmony_ci			      0, 0);
3013141cc406Sopenharmony_ci	}
3014141cc406Sopenharmony_ci      else
3015141cc406Sopenharmony_ci	status = dev_cmd (s, scsi_start_stop, sizeof (scsi_start_stop), 0, 0);
3016141cc406Sopenharmony_ci
3017141cc406Sopenharmony_ci      if (force_wait)
3018141cc406Sopenharmony_ci	{
3019141cc406Sopenharmony_ci	  DBG (5, "do_stop: waiting for scanner to be ready\n");
3020141cc406Sopenharmony_ci	  dev_wait_ready (s);
3021141cc406Sopenharmony_ci	}
3022141cc406Sopenharmony_ci
3023141cc406Sopenharmony_ci      do_eof (s);
3024141cc406Sopenharmony_ci      DBG (5, "do_stop: closing scanner\n");
3025141cc406Sopenharmony_ci      dev_close (s);
3026141cc406Sopenharmony_ci      s->fd = -1;
3027141cc406Sopenharmony_ci    }
3028141cc406Sopenharmony_ci
3029141cc406Sopenharmony_ci  DBG (5, "do_stop: finished\n");
3030141cc406Sopenharmony_ci  return status;
3031141cc406Sopenharmony_ci}
3032141cc406Sopenharmony_ci
3033141cc406Sopenharmony_ci/* Paragon I + II: Determine the CCD's distance between the primary color
3034141cc406Sopenharmony_ci   lines.  */
3035141cc406Sopenharmony_cistatic SANE_Status
3036141cc406Sopenharmony_ciline_distance (Mustek_Scanner * s)
3037141cc406Sopenharmony_ci{
3038141cc406Sopenharmony_ci  SANE_Int factor, color, res, peak_res;
3039141cc406Sopenharmony_ci  SANE_Status status;
3040141cc406Sopenharmony_ci  SANE_Byte result[5];
3041141cc406Sopenharmony_ci  size_t len;
3042141cc406Sopenharmony_ci
3043141cc406Sopenharmony_ci  memset (result, 0, 5);
3044141cc406Sopenharmony_ci
3045141cc406Sopenharmony_ci  res = SANE_UNFIX (s->val[OPT_RESOLUTION].w) + 0.5;
3046141cc406Sopenharmony_ci  peak_res = SANE_UNFIX (s->hw->dpi_range.max) + 0.5;
3047141cc406Sopenharmony_ci
3048141cc406Sopenharmony_ci  s->ld.buf[0] = NULL;
3049141cc406Sopenharmony_ci
3050141cc406Sopenharmony_ci  len = sizeof (result);
3051141cc406Sopenharmony_ci  status = dev_cmd (s, scsi_ccd_distance, sizeof (scsi_ccd_distance),
3052141cc406Sopenharmony_ci		    result, &len);
3053141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3054141cc406Sopenharmony_ci    return status;
3055141cc406Sopenharmony_ci
3056141cc406Sopenharmony_ci  DBG (3, "line_distance: got factor=%d, (r/g/b)=(%d/%d/%d)\n",
3057141cc406Sopenharmony_ci       result[0] | (result[1] << 8), result[2], result[3], result[4]);
3058141cc406Sopenharmony_ci
3059141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_LD_FIX)
3060141cc406Sopenharmony_ci    {
3061141cc406Sopenharmony_ci      result[0] = 0xff;
3062141cc406Sopenharmony_ci      result[1] = 0xff;
3063141cc406Sopenharmony_ci      if (s->mode & MUSTEK_MODE_COLOR)
3064141cc406Sopenharmony_ci	{
3065141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_N)
3066141cc406Sopenharmony_ci	    {
3067141cc406Sopenharmony_ci	      /* According to Andreas Czechanowski, the line-distance values
3068141cc406Sopenharmony_ci		 returned for the AB306N scanners are garbage, so we have to
3069141cc406Sopenharmony_ci		 fix things up manually.  Not good.
3070141cc406Sopenharmony_ci		 This seems to be true only for firmware 2.00 which is
3071141cc406Sopenharmony_ci		 extremely seldom.. AB306N scanners with firmware 1.01 don't
3072141cc406Sopenharmony_ci		 need this fix. <henning@meier-geinitz.de> */
3073141cc406Sopenharmony_ci	      if (peak_res == 600)
3074141cc406Sopenharmony_ci		{
3075141cc406Sopenharmony_ci		  if (res < 51)
3076141cc406Sopenharmony_ci		    {
3077141cc406Sopenharmony_ci		      result[0] = 8;
3078141cc406Sopenharmony_ci		      result[1] = 0;
3079141cc406Sopenharmony_ci		      result[2] = 0;
3080141cc406Sopenharmony_ci		      result[3] = 2;
3081141cc406Sopenharmony_ci		      result[4] = 3;
3082141cc406Sopenharmony_ci		    }
3083141cc406Sopenharmony_ci		  else if (res < 75 || (res > 90 && res < 150))
3084141cc406Sopenharmony_ci		    {
3085141cc406Sopenharmony_ci		      /* 51-74 and 91-149 dpi: */
3086141cc406Sopenharmony_ci		      result[0] = 4;
3087141cc406Sopenharmony_ci		      result[1] = 0;
3088141cc406Sopenharmony_ci		      result[2] = 0;
3089141cc406Sopenharmony_ci		      result[3] = 3;
3090141cc406Sopenharmony_ci		      result[4] = 5;
3091141cc406Sopenharmony_ci		    }
3092141cc406Sopenharmony_ci		  else if (res <= 90 || (res >= 150 && res <= 300))
3093141cc406Sopenharmony_ci		    {
3094141cc406Sopenharmony_ci		      /* 75-90 and 150-300 dpi: */
3095141cc406Sopenharmony_ci		      result[0] = 2;
3096141cc406Sopenharmony_ci		      result[1] = 0;
3097141cc406Sopenharmony_ci		      result[2] = 0;
3098141cc406Sopenharmony_ci		      result[3] = 5;
3099141cc406Sopenharmony_ci		      result[4] = 9;
3100141cc406Sopenharmony_ci		    }
3101141cc406Sopenharmony_ci		  else
3102141cc406Sopenharmony_ci		    {
3103141cc406Sopenharmony_ci		      /* 301-600 dpi: */
3104141cc406Sopenharmony_ci		      result[0] = 1;
3105141cc406Sopenharmony_ci		      result[1] = 0;
3106141cc406Sopenharmony_ci		      result[2] = 0;
3107141cc406Sopenharmony_ci		      result[3] = 9;
3108141cc406Sopenharmony_ci		      result[4] = 23;
3109141cc406Sopenharmony_ci		    }
3110141cc406Sopenharmony_ci		}
3111141cc406Sopenharmony_ci	      else
3112141cc406Sopenharmony_ci		DBG (1, "don't know how to fix up line-distance for %d dpi\n",
3113141cc406Sopenharmony_ci		     peak_res);
3114141cc406Sopenharmony_ci	    }
3115141cc406Sopenharmony_ci	  else if (!(s->hw->flags & MUSTEK_FLAG_LD_NONE))
3116141cc406Sopenharmony_ci	    {
3117141cc406Sopenharmony_ci	      if (peak_res == 600)
3118141cc406Sopenharmony_ci		{
3119141cc406Sopenharmony_ci		  if (res < 51)
3120141cc406Sopenharmony_ci		    {
3121141cc406Sopenharmony_ci		      /* 1-50 dpi: */
3122141cc406Sopenharmony_ci		      result[0] = 4;
3123141cc406Sopenharmony_ci		      result[1] = 0;
3124141cc406Sopenharmony_ci		      result[2] = 0;
3125141cc406Sopenharmony_ci		      result[3] = 3;
3126141cc406Sopenharmony_ci		      result[4] = 5;
3127141cc406Sopenharmony_ci		    }
3128141cc406Sopenharmony_ci		  else if (res <= 300)
3129141cc406Sopenharmony_ci		    {
3130141cc406Sopenharmony_ci		      /* 51-300 dpi: */
3131141cc406Sopenharmony_ci		      result[0] = 2;
3132141cc406Sopenharmony_ci		      result[1] = 0;
3133141cc406Sopenharmony_ci		      result[2] = 0;
3134141cc406Sopenharmony_ci		      result[3] = 5;
3135141cc406Sopenharmony_ci		      result[4] = 9;
3136141cc406Sopenharmony_ci		    }
3137141cc406Sopenharmony_ci		  else
3138141cc406Sopenharmony_ci		    {
3139141cc406Sopenharmony_ci		      /*301-600 dpi: */
3140141cc406Sopenharmony_ci		      result[0] = 1;
3141141cc406Sopenharmony_ci		      result[1] = 0;
3142141cc406Sopenharmony_ci		      result[2] = 0;
3143141cc406Sopenharmony_ci		      result[3] = 9;
3144141cc406Sopenharmony_ci		      result[4] = 17;
3145141cc406Sopenharmony_ci		    }
3146141cc406Sopenharmony_ci		}
3147141cc406Sopenharmony_ci	      else if (peak_res == 800)
3148141cc406Sopenharmony_ci		{
3149141cc406Sopenharmony_ci		  if (res < 72)
3150141cc406Sopenharmony_ci		    {
3151141cc406Sopenharmony_ci		      /* 1-71 dpi: */
3152141cc406Sopenharmony_ci		      result[0] = 4;
3153141cc406Sopenharmony_ci		      result[1] = 0;
3154141cc406Sopenharmony_ci		      result[2] = 0;
3155141cc406Sopenharmony_ci		      result[3] = 3;
3156141cc406Sopenharmony_ci		      result[4] = 5;
3157141cc406Sopenharmony_ci		    }
3158141cc406Sopenharmony_ci		  else if (res <= 400)
3159141cc406Sopenharmony_ci		    {
3160141cc406Sopenharmony_ci		      /* 72-400 dpi: */
3161141cc406Sopenharmony_ci		      result[0] = 2;
3162141cc406Sopenharmony_ci		      result[1] = 0;
3163141cc406Sopenharmony_ci		      result[2] = 0;
3164141cc406Sopenharmony_ci		      result[3] = 9;
3165141cc406Sopenharmony_ci		      result[4] = 17;
3166141cc406Sopenharmony_ci		    }
3167141cc406Sopenharmony_ci		  else
3168141cc406Sopenharmony_ci		    {
3169141cc406Sopenharmony_ci		      /*401-800 dpi: */
3170141cc406Sopenharmony_ci		      result[0] = 1;
3171141cc406Sopenharmony_ci		      result[1] = 0;
3172141cc406Sopenharmony_ci		      result[2] = 0;
3173141cc406Sopenharmony_ci		      result[3] = 16;
3174141cc406Sopenharmony_ci		      result[4] = 32;
3175141cc406Sopenharmony_ci		    }
3176141cc406Sopenharmony_ci		}
3177141cc406Sopenharmony_ci	    }
3178141cc406Sopenharmony_ci	}
3179141cc406Sopenharmony_ci      DBG (4, "line_distance: fixed up to factor=%d, (r/g/b)=(%d/%d/%d)\n",
3180141cc406Sopenharmony_ci	   result[0] | (result[1] << 8), result[2], result[3], result[4]);
3181141cc406Sopenharmony_ci    }
3182141cc406Sopenharmony_ci
3183141cc406Sopenharmony_ci  factor = result[0] | (result[1] << 8);
3184141cc406Sopenharmony_ci  if (factor != 0xffff)
3185141cc406Sopenharmony_ci    {
3186141cc406Sopenharmony_ci      /* need to do line-distance adjustment ourselves... */
3187141cc406Sopenharmony_ci
3188141cc406Sopenharmony_ci      s->ld.max_value = peak_res;
3189141cc406Sopenharmony_ci
3190141cc406Sopenharmony_ci      if (factor == 0)
3191141cc406Sopenharmony_ci	{
3192141cc406Sopenharmony_ci	  if (res <= peak_res / 2)
3193141cc406Sopenharmony_ci	    res *= 2;
3194141cc406Sopenharmony_ci	}
3195141cc406Sopenharmony_ci      else
3196141cc406Sopenharmony_ci	res *= factor;
3197141cc406Sopenharmony_ci      s->ld.peak_res = res;
3198141cc406Sopenharmony_ci      for (color = 0; color < 3; ++color)
3199141cc406Sopenharmony_ci	{
3200141cc406Sopenharmony_ci	  s->ld.dist[color] = result[2 + color];
3201141cc406Sopenharmony_ci	  s->ld.quant[color] = s->ld.max_value;
3202141cc406Sopenharmony_ci	  s->ld.index[color] = -s->ld.dist[color];
3203141cc406Sopenharmony_ci	}
3204141cc406Sopenharmony_ci      s->ld.lmod3 = -1;
3205141cc406Sopenharmony_ci
3206141cc406Sopenharmony_ci      DBG (4, "line_distance: max_value = %d, peak_res = %d, ld.quant = "
3207141cc406Sopenharmony_ci	   "(%d, %d, %d)\n", s->ld.max_value, s->ld.peak_res, s->ld.quant[0],
3208141cc406Sopenharmony_ci	   s->ld.quant[1], s->ld.quant[2]);
3209141cc406Sopenharmony_ci    }
3210141cc406Sopenharmony_ci  else
3211141cc406Sopenharmony_ci    s->ld.max_value = 0;
3212141cc406Sopenharmony_ci
3213141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3214141cc406Sopenharmony_ci}
3215141cc406Sopenharmony_ci
3216141cc406Sopenharmony_ci/* Paragon + Pro series */
3217141cc406Sopenharmony_cistatic SANE_Status
3218141cc406Sopenharmony_ciget_image_status (Mustek_Scanner * s, SANE_Int * bpl, SANE_Int * lines)
3219141cc406Sopenharmony_ci{
3220141cc406Sopenharmony_ci  SANE_Byte result[6];
3221141cc406Sopenharmony_ci  SANE_Status status;
3222141cc406Sopenharmony_ci  size_t len;
3223141cc406Sopenharmony_ci  SANE_Int busy, offset;
3224141cc406Sopenharmony_ci  long res, half_res;
3225141cc406Sopenharmony_ci
3226141cc406Sopenharmony_ci  memset (result, 0, 6);
3227141cc406Sopenharmony_ci
3228141cc406Sopenharmony_ci  /* The 600 II N v1.01 and Paragon 12000SP need a larger scan-area for
3229141cc406Sopenharmony_ci     line-distance correction in color mode */
3230141cc406Sopenharmony_ci  offset = 0;
3231141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_LD_N1) && (s->mode & MUSTEK_MODE_COLOR))
3232141cc406Sopenharmony_ci    offset = s->ld.dist[1];
3233141cc406Sopenharmony_ci  else if ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK)
3234141cc406Sopenharmony_ci	   && (s->hw->flags & MUSTEK_FLAG_PARAGON_1)
3235141cc406Sopenharmony_ci	   && (s->mode & MUSTEK_MODE_COLOR))
3236141cc406Sopenharmony_ci    offset = MAX_LINE_DIST * SANE_UNFIX (s->val[OPT_RESOLUTION].w)
3237141cc406Sopenharmony_ci      / SANE_UNFIX (s->hw->dpi_range.max);
3238141cc406Sopenharmony_ci
3239141cc406Sopenharmony_ci  do
3240141cc406Sopenharmony_ci    {
3241141cc406Sopenharmony_ci      len = sizeof (result);
3242141cc406Sopenharmony_ci      status = dev_cmd (s, scsi_get_image_status,
3243141cc406Sopenharmony_ci			sizeof (scsi_get_image_status), result, &len);
3244141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3245141cc406Sopenharmony_ci	return status;
3246141cc406Sopenharmony_ci
3247141cc406Sopenharmony_ci      busy = result[0];
3248141cc406Sopenharmony_ci      if (busy)
3249141cc406Sopenharmony_ci	usleep (100000);
3250141cc406Sopenharmony_ci
3251141cc406Sopenharmony_ci      if (!s->scanning)		/* ? */
3252141cc406Sopenharmony_ci	if (!(s->hw->flags & MUSTEK_FLAG_PRO))
3253141cc406Sopenharmony_ci	  return do_stop (s);
3254141cc406Sopenharmony_ci    }
3255141cc406Sopenharmony_ci  while (busy);
3256141cc406Sopenharmony_ci
3257141cc406Sopenharmony_ci  s->hw->bpl = result[1] | (result[2] << 8);
3258141cc406Sopenharmony_ci  s->hw->lines = result[3] | (result[4] << 8) | (result[5] << 16);
3259141cc406Sopenharmony_ci
3260141cc406Sopenharmony_ci  res = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
3261141cc406Sopenharmony_ci  half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2;
3262141cc406Sopenharmony_ci  /* Need to interpolate resolutions > max x-resolution? */
3263141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3264141cc406Sopenharmony_ci    {
3265141cc406Sopenharmony_ci      *bpl = (s->hw->bpl * res) / half_res / 3;
3266141cc406Sopenharmony_ci      *bpl *= 3;
3267141cc406Sopenharmony_ci      DBG (4, "get_image_status: resolution > x-max; enlarge %d bpl to "
3268141cc406Sopenharmony_ci	   "%d bpl\n", s->hw->bpl, *bpl);
3269141cc406Sopenharmony_ci    }
3270141cc406Sopenharmony_ci  else
3271141cc406Sopenharmony_ci    *bpl = s->hw->bpl;
3272141cc406Sopenharmony_ci
3273141cc406Sopenharmony_ci  *lines = s->hw->lines - offset;
3274141cc406Sopenharmony_ci
3275141cc406Sopenharmony_ci  DBG (3, "get_image_status: bytes_per_line=%d, lines=%d (offset = %d)\n",
3276141cc406Sopenharmony_ci       *bpl, *lines, offset);
3277141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3278141cc406Sopenharmony_ci}
3279141cc406Sopenharmony_ci
3280141cc406Sopenharmony_ci/* ScanExpress models */
3281141cc406Sopenharmony_cistatic SANE_Status
3282141cc406Sopenharmony_ciget_window (Mustek_Scanner * s, SANE_Int * bpl, SANE_Int * lines,
3283141cc406Sopenharmony_ci	    SANE_Int * pixels)
3284141cc406Sopenharmony_ci{
3285141cc406Sopenharmony_ci  SANE_Byte result[48];
3286141cc406Sopenharmony_ci  SANE_Status status;
3287141cc406Sopenharmony_ci  size_t len;
3288141cc406Sopenharmony_ci  SANE_Int color;
3289141cc406Sopenharmony_ci  long res, half_res;
3290141cc406Sopenharmony_ci
3291141cc406Sopenharmony_ci  res = s->resolution_code;
3292141cc406Sopenharmony_ci  half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2;
3293141cc406Sopenharmony_ci
3294141cc406Sopenharmony_ci  DBG (5, "get_window: resolution: %ld dpi (hardware: %d dpi)\n",
3295141cc406Sopenharmony_ci       res, s->ld.peak_res);
3296141cc406Sopenharmony_ci
3297141cc406Sopenharmony_ci  len = sizeof (result);
3298141cc406Sopenharmony_ci  status = dev_cmd (s, scsi_get_window, sizeof (scsi_get_window), result,
3299141cc406Sopenharmony_ci		    &len);
3300141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
3301141cc406Sopenharmony_ci    return status;
3302141cc406Sopenharmony_ci
3303141cc406Sopenharmony_ci  if (!s->scanning)
3304141cc406Sopenharmony_ci    return do_stop (s);
3305141cc406Sopenharmony_ci
3306141cc406Sopenharmony_ci  s->hw->cal.bytes = (result[6] << 24) | (result[7] << 16) |
3307141cc406Sopenharmony_ci    (result[8] << 8) | (result[9] << 0);
3308141cc406Sopenharmony_ci  s->hw->cal.lines = (result[10] << 24) | (result[11] << 16) |
3309141cc406Sopenharmony_ci    (result[12] << 8) | (result[13] << 0);
3310141cc406Sopenharmony_ci
3311141cc406Sopenharmony_ci  DBG (4, "get_window: calibration bpl=%d, lines=%d\n",
3312141cc406Sopenharmony_ci       s->hw->cal.bytes, s->hw->cal.lines);
3313141cc406Sopenharmony_ci
3314141cc406Sopenharmony_ci  s->hw->bpl = (result[14] << 24) | (result[15] << 16) |
3315141cc406Sopenharmony_ci    (result[16] << 8) | result[17];
3316141cc406Sopenharmony_ci
3317141cc406Sopenharmony_ci  s->hw->lines = (result[18] << 24) | (result[19] << 16) |
3318141cc406Sopenharmony_ci    (result[20] << 8) | result[21];
3319141cc406Sopenharmony_ci
3320141cc406Sopenharmony_ci  DBG (4, "get_window: scan bpl=%d, lines=%d\n", s->hw->bpl, s->hw->lines);
3321141cc406Sopenharmony_ci
3322141cc406Sopenharmony_ci  if ((s->hw->cal.bytes == 0) || (s->hw->cal.lines == 0)
3323141cc406Sopenharmony_ci      || (s->hw->bpl == 0) || (s->hw->lines == 0))
3324141cc406Sopenharmony_ci    {
3325141cc406Sopenharmony_ci      DBG (1, "get_window: oops, none of these values should be 0 "
3326141cc406Sopenharmony_ci	   "-- exiting\n");
3327141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3328141cc406Sopenharmony_ci    }
3329141cc406Sopenharmony_ci
3330141cc406Sopenharmony_ci  s->hw->gamma_length = 1 << result[26];
3331141cc406Sopenharmony_ci  DBG (4, "get_window: gamma length=%d\n", s->hw->gamma_length);
3332141cc406Sopenharmony_ci
3333141cc406Sopenharmony_ci  if (s->mode & MUSTEK_MODE_COLOR)
3334141cc406Sopenharmony_ci    {
3335141cc406Sopenharmony_ci      s->ld.buf[0] = NULL;
3336141cc406Sopenharmony_ci      for (color = 0; color < 3; ++color)
3337141cc406Sopenharmony_ci	{
3338141cc406Sopenharmony_ci	  s->ld.dist[color] = result[42 + color];
3339141cc406Sopenharmony_ci	}
3340141cc406Sopenharmony_ci
3341141cc406Sopenharmony_ci      DBG (4, "get_window: LD res=%d, (r/g/b)=(%d/%d/%d)\n",
3342141cc406Sopenharmony_ci	   (result[40] << 8) | result[41], s->ld.dist[0],
3343141cc406Sopenharmony_ci	   s->ld.dist[1], s->ld.dist[2]);
3344141cc406Sopenharmony_ci      s->ld.max_value = (result[40] << 8) | result[41];
3345141cc406Sopenharmony_ci      if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3346141cc406Sopenharmony_ci	{
3347141cc406Sopenharmony_ci	  /* We must interpolate resolutions > max x-resolution */
3348141cc406Sopenharmony_ci	  *bpl = *pixels = (((s->hw->bpl / 3) * res) / half_res) * 3;
3349141cc406Sopenharmony_ci	}
3350141cc406Sopenharmony_ci      else
3351141cc406Sopenharmony_ci	{
3352141cc406Sopenharmony_ci	  /* Scale down the image according to desired resolution */
3353141cc406Sopenharmony_ci	  *bpl = *pixels = (((s->hw->bpl / 3) * res) / s->ld.peak_res) * 3;
3354141cc406Sopenharmony_ci	}
3355141cc406Sopenharmony_ci      *lines = (s->hw->lines - s->ld.dist[2]) * res / s->ld.peak_res;
3356141cc406Sopenharmony_ci    }
3357141cc406Sopenharmony_ci  else
3358141cc406Sopenharmony_ci    {
3359141cc406Sopenharmony_ci      if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3360141cc406Sopenharmony_ci	{
3361141cc406Sopenharmony_ci	  /* We must interpolate resolutions > max x-resolution */
3362141cc406Sopenharmony_ci	  *bpl = s->hw->bpl * res / half_res;
3363141cc406Sopenharmony_ci	}
3364141cc406Sopenharmony_ci      else
3365141cc406Sopenharmony_ci	{
3366141cc406Sopenharmony_ci	  *bpl = s->hw->bpl;
3367141cc406Sopenharmony_ci	}
3368141cc406Sopenharmony_ci      *lines = s->hw->lines;
3369141cc406Sopenharmony_ci    }
3370141cc406Sopenharmony_ci  DBG (4, "get_window: bpl = %d (hardware: %d), lines = %d (hardware: %d)\n",
3371141cc406Sopenharmony_ci       *bpl, s->hw->bpl, *lines, s->hw->lines);
3372141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3373141cc406Sopenharmony_ci}
3374141cc406Sopenharmony_ci
3375141cc406Sopenharmony_cistatic SANE_Status
3376141cc406Sopenharmony_ciadf_and_backtrack (Mustek_Scanner * s)
3377141cc406Sopenharmony_ci{
3378141cc406Sopenharmony_ci  SANE_Byte backtrack[6];
3379141cc406Sopenharmony_ci  SANE_Int code = 0x80;
3380141cc406Sopenharmony_ci
3381141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_NO_BACKTRACK))
3382141cc406Sopenharmony_ci    code |= 0x02;		/* enable backtracking */
3383141cc406Sopenharmony_ci
3384141cc406Sopenharmony_ci  if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0)
3385141cc406Sopenharmony_ci    code |= 0x01;
3386141cc406Sopenharmony_ci  else if (strcmp (s->val[OPT_SOURCE].s, "Transparency Adapter") == 0)
3387141cc406Sopenharmony_ci    code |= 0x04;
3388141cc406Sopenharmony_ci  memset (backtrack, 0, sizeof (backtrack));
3389141cc406Sopenharmony_ci  backtrack[0] = MUSTEK_SCSI_ADF_AND_BACKTRACK;
3390141cc406Sopenharmony_ci  backtrack[4] = code;
3391141cc406Sopenharmony_ci
3392141cc406Sopenharmony_ci  DBG (4, "adf_and_backtrack: backtrack: %s; ADF: %s; TA: %s\n",
3393141cc406Sopenharmony_ci       code & 0x02 ? "yes" : "no", code & 0x01 ? "yes" : "no",
3394141cc406Sopenharmony_ci       code & 0x04 ? "yes" : "no");
3395141cc406Sopenharmony_ci  return dev_cmd (s, backtrack, sizeof (backtrack), 0, 0);
3396141cc406Sopenharmony_ci}
3397141cc406Sopenharmony_ci
3398141cc406Sopenharmony_ci/* 600 II N firmware 2.x */
3399141cc406Sopenharmony_cistatic SANE_Int
3400141cc406Sopenharmony_cifix_line_distance_n_2 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
3401141cc406Sopenharmony_ci		       SANE_Byte * raw, SANE_Byte * out)
3402141cc406Sopenharmony_ci{
3403141cc406Sopenharmony_ci  SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl;
3404141cc406Sopenharmony_ci  SANE_Int c, num_saved_lines, line;
3405141cc406Sopenharmony_ci
3406141cc406Sopenharmony_ci  if (!s->ld.buf[0])
3407141cc406Sopenharmony_ci    {
3408141cc406Sopenharmony_ci      /* This buffer must be big enough to hold maximum line distance
3409141cc406Sopenharmony_ci         times max_bpl bytes.  The maximum line distance for the
3410141cc406Sopenharmony_ci         Paragon 600 II N scanner is 23, so 40 should be safe.  */
3411141cc406Sopenharmony_ci      DBG (5,
3412141cc406Sopenharmony_ci	   "fix_line_distance_n_2: allocating temp buffer of %d*%d bytes\n",
3413141cc406Sopenharmony_ci	   MAX_LINE_DIST, bpl);
3414141cc406Sopenharmony_ci      s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl);
3415141cc406Sopenharmony_ci      if (!s->ld.buf[0])
3416141cc406Sopenharmony_ci	{
3417141cc406Sopenharmony_ci	  DBG (1,
3418141cc406Sopenharmony_ci	       "fix_line_distance_n_2: failed to malloc temporary buffer\n");
3419141cc406Sopenharmony_ci	  return 0;
3420141cc406Sopenharmony_ci	}
3421141cc406Sopenharmony_ci    }
3422141cc406Sopenharmony_ci
3423141cc406Sopenharmony_ci  num_saved_lines = s->ld.index[0] - s->ld.index[2];
3424141cc406Sopenharmony_ci  if (num_saved_lines > 0)
3425141cc406Sopenharmony_ci    /* restore the previously saved lines: */
3426141cc406Sopenharmony_ci    memcpy (out, s->ld.buf[0], num_saved_lines * bpl);
3427141cc406Sopenharmony_ci
3428141cc406Sopenharmony_ci  while (1)
3429141cc406Sopenharmony_ci    {
3430141cc406Sopenharmony_ci      if (++s->ld.lmod3 >= 3)
3431141cc406Sopenharmony_ci	s->ld.lmod3 = 0;
3432141cc406Sopenharmony_ci
3433141cc406Sopenharmony_ci      c = color_seq[s->ld.lmod3];
3434141cc406Sopenharmony_ci      if (s->ld.index[c] < 0)
3435141cc406Sopenharmony_ci	++s->ld.index[c];
3436141cc406Sopenharmony_ci      else if (s->ld.index[c] < s->params.lines)
3437141cc406Sopenharmony_ci	{
3438141cc406Sopenharmony_ci	  s->ld.quant[c] += s->ld.peak_res;
3439141cc406Sopenharmony_ci	  if (s->ld.quant[c] > s->ld.max_value)
3440141cc406Sopenharmony_ci	    {
3441141cc406Sopenharmony_ci	      s->ld.quant[c] -= s->ld.max_value;
3442141cc406Sopenharmony_ci	      line = s->ld.index[c]++ - s->ld.ld_line;
3443141cc406Sopenharmony_ci	      out_ptr = out + line * bpl + c;
3444141cc406Sopenharmony_ci	      out_end = out_ptr + bpl;
3445141cc406Sopenharmony_ci	      while (out_ptr != out_end)
3446141cc406Sopenharmony_ci		{
3447141cc406Sopenharmony_ci		  *out_ptr = *raw++;
3448141cc406Sopenharmony_ci		  out_ptr += 3;
3449141cc406Sopenharmony_ci		}
3450141cc406Sopenharmony_ci
3451141cc406Sopenharmony_ci	      if (raw >= raw_end)
3452141cc406Sopenharmony_ci		{
3453141cc406Sopenharmony_ci		  DBG (3, "fix_line_distance_n_2: lmod3=%d, "
3454141cc406Sopenharmony_ci		       "index=(%d,%d,%d)\n", s->ld.lmod3,
3455141cc406Sopenharmony_ci		       s->ld.index[0], s->ld.index[1], s->ld.index[2]);
3456141cc406Sopenharmony_ci		  num_lines = s->ld.index[2] - s->ld.ld_line;
3457141cc406Sopenharmony_ci
3458141cc406Sopenharmony_ci		  /* copy away the lines with at least one missing
3459141cc406Sopenharmony_ci		     color component, so that we can interleave them
3460141cc406Sopenharmony_ci		     with new scan data on the next call */
3461141cc406Sopenharmony_ci		  num_saved_lines = s->ld.index[0] - s->ld.index[2];
3462141cc406Sopenharmony_ci		  memcpy (s->ld.buf[0], out + num_lines * bpl,
3463141cc406Sopenharmony_ci			  num_saved_lines * bpl);
3464141cc406Sopenharmony_ci
3465141cc406Sopenharmony_ci		  /* notice the number of lines we processed */
3466141cc406Sopenharmony_ci		  s->ld.ld_line = s->ld.index[2];
3467141cc406Sopenharmony_ci		  /* return number of complete (r+g+b) lines */
3468141cc406Sopenharmony_ci		  return num_lines;
3469141cc406Sopenharmony_ci		}
3470141cc406Sopenharmony_ci	    }
3471141cc406Sopenharmony_ci	}
3472141cc406Sopenharmony_ci    }
3473141cc406Sopenharmony_ci}
3474141cc406Sopenharmony_ci
3475141cc406Sopenharmony_ci/* 600 II N firmware 1.x */
3476141cc406Sopenharmony_cistatic SANE_Int
3477141cc406Sopenharmony_cifix_line_distance_n_1 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
3478141cc406Sopenharmony_ci		       SANE_Byte * raw, SANE_Byte * out)
3479141cc406Sopenharmony_ci{
3480141cc406Sopenharmony_ci  SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl;
3481141cc406Sopenharmony_ci  SANE_Int c, num_saved_lines, line;
3482141cc406Sopenharmony_ci
3483141cc406Sopenharmony_ci  /* For firmware 1.x the scanarea must be soemwhat bigger than needed
3484141cc406Sopenharmony_ci     because of the linedistance correction */
3485141cc406Sopenharmony_ci
3486141cc406Sopenharmony_ci  if (!s->ld.buf[0])
3487141cc406Sopenharmony_ci    {
3488141cc406Sopenharmony_ci      /* This buffer must be big enough to hold maximum line distance
3489141cc406Sopenharmony_ci         times max_bpl bytes.  The maximum line distance for the 600 II N
3490141cc406Sopenharmony_ci         is 23, so 40 is safe. */
3491141cc406Sopenharmony_ci      DBG (5,
3492141cc406Sopenharmony_ci	   "fix_line_distance_n_1: allocating temp buffer of %d*%d bytes\n",
3493141cc406Sopenharmony_ci	   MAX_LINE_DIST, bpl);
3494141cc406Sopenharmony_ci      s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl);
3495141cc406Sopenharmony_ci      if (!s->ld.buf[0])
3496141cc406Sopenharmony_ci	{
3497141cc406Sopenharmony_ci	  DBG (1,
3498141cc406Sopenharmony_ci	       "fix_line_distance_n_1: failed to malloc temporary buffer\n");
3499141cc406Sopenharmony_ci	  return 0;
3500141cc406Sopenharmony_ci	}
3501141cc406Sopenharmony_ci    }
3502141cc406Sopenharmony_ci  num_saved_lines = s->ld.index[0] - s->ld.index[1];
3503141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_n_1: got %d lines, %d bpl\n", num_lines, bpl);
3504141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_n_1: num_saved_lines = %d; peak_res = %d; "
3505141cc406Sopenharmony_ci       "max_value = %d\n", num_saved_lines, s->ld.peak_res, s->ld.max_value);
3506141cc406Sopenharmony_ci  if (num_saved_lines > 0)
3507141cc406Sopenharmony_ci    /* restore the previously saved lines: */
3508141cc406Sopenharmony_ci    memcpy (out, s->ld.buf[0], num_saved_lines * bpl);
3509141cc406Sopenharmony_ci
3510141cc406Sopenharmony_ci  while (1)
3511141cc406Sopenharmony_ci    {
3512141cc406Sopenharmony_ci      if (++s->ld.lmod3 >= 3)
3513141cc406Sopenharmony_ci	s->ld.lmod3 = 0;
3514141cc406Sopenharmony_ci      c = s->ld.lmod3;
3515141cc406Sopenharmony_ci      if (s->ld.index[c] < 0)
3516141cc406Sopenharmony_ci	++s->ld.index[c];
3517141cc406Sopenharmony_ci      else
3518141cc406Sopenharmony_ci	{
3519141cc406Sopenharmony_ci	  s->ld.quant[c] += s->ld.peak_res;
3520141cc406Sopenharmony_ci	  if (s->ld.quant[c] > s->ld.max_value)
3521141cc406Sopenharmony_ci	    {
3522141cc406Sopenharmony_ci	      s->ld.quant[c] -= s->ld.max_value;
3523141cc406Sopenharmony_ci	      line = s->ld.index[c]++ - s->ld.ld_line;
3524141cc406Sopenharmony_ci	      out_ptr = out + line * bpl + c;
3525141cc406Sopenharmony_ci	      out_end = out_ptr + bpl;
3526141cc406Sopenharmony_ci	      while (out_ptr != out_end)
3527141cc406Sopenharmony_ci		{
3528141cc406Sopenharmony_ci		  *out_ptr = *raw++;
3529141cc406Sopenharmony_ci		  out_ptr += 3;
3530141cc406Sopenharmony_ci		}
3531141cc406Sopenharmony_ci	      DBG (5, "fix_line_distance_n_1: copied line %d (color %d)\n",
3532141cc406Sopenharmony_ci		   line, c);
3533141cc406Sopenharmony_ci	    }
3534141cc406Sopenharmony_ci	}
3535141cc406Sopenharmony_ci      if ((raw >= raw_end) || ((s->ld.index[0] >= s->params.lines) &&
3536141cc406Sopenharmony_ci			       (s->ld.index[1] >= s->params.lines) &&
3537141cc406Sopenharmony_ci			       (s->ld.index[2] >= s->params.lines)))
3538141cc406Sopenharmony_ci	{
3539141cc406Sopenharmony_ci	  DBG (3, "fix_line_distance_n_1: lmod3=%d, index=(%d,%d,%d)%s\n",
3540141cc406Sopenharmony_ci	       s->ld.lmod3,
3541141cc406Sopenharmony_ci	       s->ld.index[0], s->ld.index[1], s->ld.index[2],
3542141cc406Sopenharmony_ci	       raw >= raw_end ? " raw >= raw_end" : "");
3543141cc406Sopenharmony_ci	  num_lines = s->ld.index[1] - s->ld.ld_line;
3544141cc406Sopenharmony_ci	  if (num_lines < 0)
3545141cc406Sopenharmony_ci	    num_lines = 0;
3546141cc406Sopenharmony_ci	  DBG (4, "fix_line_distance_n_1: lines ready: %d\n", num_lines);
3547141cc406Sopenharmony_ci
3548141cc406Sopenharmony_ci	  /* copy away the lines with at least one missing
3549141cc406Sopenharmony_ci	     color component, so that we can interleave them
3550141cc406Sopenharmony_ci	     with new scan data on the next call */
3551141cc406Sopenharmony_ci	  num_saved_lines = s->ld.index[0] - s->ld.index[1];
3552141cc406Sopenharmony_ci	  DBG (4, "fix_line_distance_n_1: copied %d lines to "
3553141cc406Sopenharmony_ci	       "ld.buf\n", num_saved_lines);
3554141cc406Sopenharmony_ci	  memcpy (s->ld.buf[0], out + num_lines * bpl, num_saved_lines * bpl);
3555141cc406Sopenharmony_ci	  /* notice the number of lines we processed */
3556141cc406Sopenharmony_ci	  s->ld.ld_line = s->ld.index[1];
3557141cc406Sopenharmony_ci	  if (s->ld.ld_line < 0)
3558141cc406Sopenharmony_ci	    s->ld.ld_line = 0;
3559141cc406Sopenharmony_ci	  /* return number of complete (r+g+b) lines */
3560141cc406Sopenharmony_ci	  return num_lines;
3561141cc406Sopenharmony_ci	}
3562141cc406Sopenharmony_ci
3563141cc406Sopenharmony_ci    }
3564141cc406Sopenharmony_ci}
3565141cc406Sopenharmony_ci
3566141cc406Sopenharmony_ci/* For ScanExpress models */
3567141cc406Sopenharmony_cistatic SANE_Int
3568141cc406Sopenharmony_cifix_line_distance_se (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
3569141cc406Sopenharmony_ci		      SANE_Byte * raw, SANE_Byte * out)
3570141cc406Sopenharmony_ci{
3571141cc406Sopenharmony_ci  SANE_Byte *raw_end = raw + num_lines * bpl;
3572141cc406Sopenharmony_ci  SANE_Byte *out_ptr[3], *ptr;
3573141cc406Sopenharmony_ci  SANE_Int index[3], lines[3], quant[3], dist[3];
3574141cc406Sopenharmony_ci  SANE_Int max_value;
3575141cc406Sopenharmony_ci  SANE_Int color, pixel, res, half_res, scale;
3576141cc406Sopenharmony_ci  SANE_Int bpc = bpl / 3;	/* bytes per color (per line) */
3577141cc406Sopenharmony_ci  SANE_Bool preview = SANE_FALSE;
3578141cc406Sopenharmony_ci
3579141cc406Sopenharmony_ci  res = s->resolution_code;
3580141cc406Sopenharmony_ci  half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2;
3581141cc406Sopenharmony_ci  max_value = s->ld.max_value;
3582141cc406Sopenharmony_ci  if ((s->val[OPT_PREVIEW].w == SANE_TRUE)
3583141cc406Sopenharmony_ci      && (s->val[OPT_FAST_PREVIEW].w == SANE_TRUE))
3584141cc406Sopenharmony_ci    {
3585141cc406Sopenharmony_ci      preview = SANE_TRUE;
3586141cc406Sopenharmony_ci      /*max_value = 75; */
3587141cc406Sopenharmony_ci      dist[0] = s->ld.dist[0];
3588141cc406Sopenharmony_ci      dist[1] = s->ld.dist[1];
3589141cc406Sopenharmony_ci      dist[2] = s->ld.dist[2];
3590141cc406Sopenharmony_ci    }
3591141cc406Sopenharmony_ci  else
3592141cc406Sopenharmony_ci    {
3593141cc406Sopenharmony_ci      dist[0] = s->ld.dist[0];
3594141cc406Sopenharmony_ci      dist[1] = s->ld.dist[1];
3595141cc406Sopenharmony_ci      dist[2] = s->ld.dist[2];
3596141cc406Sopenharmony_ci    }
3597141cc406Sopenharmony_ci
3598141cc406Sopenharmony_ci  if (!s->ld.buf[0])
3599141cc406Sopenharmony_ci    {
3600141cc406Sopenharmony_ci      /* This buffer must be big enough to hold maximum line distance times
3601141cc406Sopenharmony_ci         3*bpl bytes.  The maximum line distance for 1200 dpi is 32 */
3602141cc406Sopenharmony_ci      DBG (5, "fix_line_distance_se: allocating temp buffer of %d*%d bytes\n",
3603141cc406Sopenharmony_ci	   3 * MAX_LINE_DIST, bpc);
3604141cc406Sopenharmony_ci      s->ld.buf[0] = malloc (3 * MAX_LINE_DIST * (long) bpc);
3605141cc406Sopenharmony_ci
3606141cc406Sopenharmony_ci      if (!s->ld.buf[0])
3607141cc406Sopenharmony_ci	{
3608141cc406Sopenharmony_ci	  DBG (1,
3609141cc406Sopenharmony_ci	       "fix_line_distance_se: failed to malloc temporary buffer\n");
3610141cc406Sopenharmony_ci	  return 0;
3611141cc406Sopenharmony_ci	}
3612141cc406Sopenharmony_ci
3613141cc406Sopenharmony_ci      /* Note that either s->ld.buf[1] or  s->ld.buf[2] is never used. */
3614141cc406Sopenharmony_ci      s->ld.buf[1] = s->ld.buf[2] =
3615141cc406Sopenharmony_ci	s->ld.buf[0] + 2 * MAX_LINE_DIST * (long) bpc;
3616141cc406Sopenharmony_ci
3617141cc406Sopenharmony_ci      /* Since the blocks don't start necessarily with red note color. */
3618141cc406Sopenharmony_ci      s->ld.color = 0;
3619141cc406Sopenharmony_ci
3620141cc406Sopenharmony_ci      /* The scan area must be longer than desired because of the line
3621141cc406Sopenharmony_ci         distance. So me must count complete (r+g+b) lines already
3622141cc406Sopenharmony_ci         submitted to the fronted. */
3623141cc406Sopenharmony_ci      s->ld.ld_line = s->params.lines;
3624141cc406Sopenharmony_ci
3625141cc406Sopenharmony_ci      for (color = 0; color < 3; ++color)
3626141cc406Sopenharmony_ci	{
3627141cc406Sopenharmony_ci	  s->ld.index[color] = -dist[color];
3628141cc406Sopenharmony_ci	  s->ld.quant[color] = 0;
3629141cc406Sopenharmony_ci	  s->ld.saved[color] = 0;
3630141cc406Sopenharmony_ci	}
3631141cc406Sopenharmony_ci    }
3632141cc406Sopenharmony_ci
3633141cc406Sopenharmony_ci  num_lines *= 3;
3634141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_se: start color: %d; %d lines \n",
3635141cc406Sopenharmony_ci       s->ld.color, num_lines);
3636141cc406Sopenharmony_ci
3637141cc406Sopenharmony_ci  /* First scan the lines read and count red, green and blue ones.
3638141cc406Sopenharmony_ci     Since we will step through the lines a second time we must not
3639141cc406Sopenharmony_ci     alter any global variables here! */
3640141cc406Sopenharmony_ci  for (color = 0; color < 3; ++color)
3641141cc406Sopenharmony_ci    {
3642141cc406Sopenharmony_ci      index[color] = s->ld.index[color];
3643141cc406Sopenharmony_ci      lines[color] = s->ld.saved[color];
3644141cc406Sopenharmony_ci      quant[color] = s->ld.quant[color];
3645141cc406Sopenharmony_ci    }
3646141cc406Sopenharmony_ci
3647141cc406Sopenharmony_ci  color = s->ld.color;
3648141cc406Sopenharmony_ci  while (num_lines > 0)
3649141cc406Sopenharmony_ci    {
3650141cc406Sopenharmony_ci      if (index[color] < 0)
3651141cc406Sopenharmony_ci	++index[color];
3652141cc406Sopenharmony_ci      else
3653141cc406Sopenharmony_ci	{
3654141cc406Sopenharmony_ci	  quant[color] += res;
3655141cc406Sopenharmony_ci	  if (quant[color] >= max_value)
3656141cc406Sopenharmony_ci	    {
3657141cc406Sopenharmony_ci	      /* This line must be processed, not dropped. */
3658141cc406Sopenharmony_ci	      quant[color] -= max_value;
3659141cc406Sopenharmony_ci	      ++lines[color];
3660141cc406Sopenharmony_ci	      --num_lines;
3661141cc406Sopenharmony_ci	    }
3662141cc406Sopenharmony_ci	  else if (!preview)
3663141cc406Sopenharmony_ci	    --num_lines;
3664141cc406Sopenharmony_ci
3665141cc406Sopenharmony_ci	}
3666141cc406Sopenharmony_ci      if (++color > 2)
3667141cc406Sopenharmony_ci	color = 0;
3668141cc406Sopenharmony_ci    }
3669141cc406Sopenharmony_ci
3670141cc406Sopenharmony_ci  /* Calculate how many triples of color lines we can output now.
3671141cc406Sopenharmony_ci     Because the number of available red lines is always greater
3672141cc406Sopenharmony_ci     than for the other colors we may ignore the red ones here. */
3673141cc406Sopenharmony_ci  num_lines = MIN (lines[1], lines[2]);
3674141cc406Sopenharmony_ci
3675141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_se: saved lines: %d/%d/%d\n", s->ld.saved[0],
3676141cc406Sopenharmony_ci       s->ld.saved[1], s->ld.saved[2]);
3677141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_se: available:  %d/%d/%d --> triples: %d\n",
3678141cc406Sopenharmony_ci       lines[0], lines[1], lines[2], num_lines);
3679141cc406Sopenharmony_ci
3680141cc406Sopenharmony_ci  lines[0] = lines[1] = lines[2] = num_lines;
3681141cc406Sopenharmony_ci
3682141cc406Sopenharmony_ci  /* Output the color lines saved in previous call first.
3683141cc406Sopenharmony_ci     Note that data is converted in r/g/b interleave on the fly. */
3684141cc406Sopenharmony_ci  for (color = 0; color < 3; ++color)
3685141cc406Sopenharmony_ci    {
3686141cc406Sopenharmony_ci      out_ptr[color] = out + color;
3687141cc406Sopenharmony_ci      ptr = s->ld.buf[color];
3688141cc406Sopenharmony_ci      while ((s->ld.saved[color] > 0) && (lines[color] > 0))
3689141cc406Sopenharmony_ci	{
3690141cc406Sopenharmony_ci	  scale = 0;
3691141cc406Sopenharmony_ci	  if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3692141cc406Sopenharmony_ci	    {
3693141cc406Sopenharmony_ci	      /* Need to enlarge x-resolution */
3694141cc406Sopenharmony_ci	      SANE_Byte *ptr_start = ptr;
3695141cc406Sopenharmony_ci	      for (pixel = 0; pixel < s->params.pixels_per_line; ++pixel)
3696141cc406Sopenharmony_ci		{
3697141cc406Sopenharmony_ci		  *out_ptr[color] = *ptr;
3698141cc406Sopenharmony_ci		  out_ptr[color] += 3;
3699141cc406Sopenharmony_ci		  scale += half_res;
3700141cc406Sopenharmony_ci		  if (scale >= half_res)
3701141cc406Sopenharmony_ci		    {
3702141cc406Sopenharmony_ci		      scale -= res;
3703141cc406Sopenharmony_ci		      ++ptr;
3704141cc406Sopenharmony_ci		    }
3705141cc406Sopenharmony_ci		}
3706141cc406Sopenharmony_ci	      DBG (5, "fix_line_distance_se: got saved line: %d; line: %d; "
3707141cc406Sopenharmony_ci		   "color: %d; raw bytes: %lu; out bytes: %d\n",
3708141cc406Sopenharmony_ci		   s->ld.saved[color], lines[color], color, (u_long) (ptr - ptr_start),
3709141cc406Sopenharmony_ci		   s->params.pixels_per_line);
3710141cc406Sopenharmony_ci	      ptr = ptr_start + bpc;
3711141cc406Sopenharmony_ci	    }
3712141cc406Sopenharmony_ci	  else
3713141cc406Sopenharmony_ci	    {
3714141cc406Sopenharmony_ci	      if (preview)
3715141cc406Sopenharmony_ci		{
3716141cc406Sopenharmony_ci		  for (pixel = 0; pixel < bpc; ++pixel)
3717141cc406Sopenharmony_ci		    {
3718141cc406Sopenharmony_ci		      *out_ptr[color] = *ptr++;
3719141cc406Sopenharmony_ci		      out_ptr[color] += 3;
3720141cc406Sopenharmony_ci		    }
3721141cc406Sopenharmony_ci		}
3722141cc406Sopenharmony_ci	      else
3723141cc406Sopenharmony_ci		{
3724141cc406Sopenharmony_ci		  for (pixel = 0; pixel < bpc; ++pixel)
3725141cc406Sopenharmony_ci		    {
3726141cc406Sopenharmony_ci		      scale += res;
3727141cc406Sopenharmony_ci		      if (scale >= max_value)
3728141cc406Sopenharmony_ci			{
3729141cc406Sopenharmony_ci			  scale -= max_value;
3730141cc406Sopenharmony_ci			  *out_ptr[color] = *ptr;
3731141cc406Sopenharmony_ci			  out_ptr[color] += 3;
3732141cc406Sopenharmony_ci			}
3733141cc406Sopenharmony_ci		      ++ptr;
3734141cc406Sopenharmony_ci		    }
3735141cc406Sopenharmony_ci		}
3736141cc406Sopenharmony_ci	      DBG (5, "fix_line_distance_se: got saved line: %d; line: %d; "
3737141cc406Sopenharmony_ci		   "color: %d\n", s->ld.saved[color], lines[color], color);
3738141cc406Sopenharmony_ci	    }
3739141cc406Sopenharmony_ci	  --(s->ld.saved[color]);
3740141cc406Sopenharmony_ci	  --lines[color];
3741141cc406Sopenharmony_ci	}
3742141cc406Sopenharmony_ci      if (s->ld.saved[color] > 0)
3743141cc406Sopenharmony_ci	memmove (s->ld.buf[color], ptr, s->ld.saved[color] * bpc);
3744141cc406Sopenharmony_ci    }
3745141cc406Sopenharmony_ci
3746141cc406Sopenharmony_ci  while (1)
3747141cc406Sopenharmony_ci    {
3748141cc406Sopenharmony_ci      if (s->ld.index[s->ld.color] < 0)
3749141cc406Sopenharmony_ci	++(s->ld.index[s->ld.color]);
3750141cc406Sopenharmony_ci      else
3751141cc406Sopenharmony_ci	{
3752141cc406Sopenharmony_ci	  s->ld.quant[s->ld.color] += res;
3753141cc406Sopenharmony_ci	  if (s->ld.quant[s->ld.color] >= max_value)
3754141cc406Sopenharmony_ci	    {
3755141cc406Sopenharmony_ci	      /* This line must be processed, not dropped. */
3756141cc406Sopenharmony_ci	      s->ld.quant[s->ld.color] -= max_value;
3757141cc406Sopenharmony_ci
3758141cc406Sopenharmony_ci	      if (lines[s->ld.color] > 0)
3759141cc406Sopenharmony_ci		{
3760141cc406Sopenharmony_ci		  /* There's still a line to be output for current color.
3761141cc406Sopenharmony_ci		     Then shuffle current color line to output buffer. */
3762141cc406Sopenharmony_ci		  scale = 0;
3763141cc406Sopenharmony_ci		  /* need to enlarge x-resolution? */
3764141cc406Sopenharmony_ci		  if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X)
3765141cc406Sopenharmony_ci		      && (res > half_res))
3766141cc406Sopenharmony_ci		    {
3767141cc406Sopenharmony_ci		      SANE_Byte *raw_start = raw;
3768141cc406Sopenharmony_ci		      for (pixel = 0; pixel < s->params.pixels_per_line;
3769141cc406Sopenharmony_ci			   ++pixel)
3770141cc406Sopenharmony_ci			{
3771141cc406Sopenharmony_ci			  *out_ptr[s->ld.color] = *raw;
3772141cc406Sopenharmony_ci			  out_ptr[s->ld.color] += 3;
3773141cc406Sopenharmony_ci			  scale += half_res;
3774141cc406Sopenharmony_ci			  if (scale >= half_res)
3775141cc406Sopenharmony_ci			    {
3776141cc406Sopenharmony_ci			      scale -= res;
3777141cc406Sopenharmony_ci			      ++raw;
3778141cc406Sopenharmony_ci			    }
3779141cc406Sopenharmony_ci
3780141cc406Sopenharmony_ci			}
3781141cc406Sopenharmony_ci		      DBG (5,
3782141cc406Sopenharmony_ci			   "fix_line_distance_se: got line: %d; color: %d; "
3783141cc406Sopenharmony_ci			   "raw bytes: %lu; out bytes: %d\n",
3784141cc406Sopenharmony_ci			   lines[s->ld.color], s->ld.color, (u_long) (raw - raw_start),
3785141cc406Sopenharmony_ci			   s->params.pixels_per_line);
3786141cc406Sopenharmony_ci		      raw = raw_start + bpc;
3787141cc406Sopenharmony_ci		    }
3788141cc406Sopenharmony_ci		  else
3789141cc406Sopenharmony_ci		    {
3790141cc406Sopenharmony_ci		      if (preview)
3791141cc406Sopenharmony_ci			{
3792141cc406Sopenharmony_ci			  for (pixel = 0; pixel < bpc; ++pixel)
3793141cc406Sopenharmony_ci			    {
3794141cc406Sopenharmony_ci			      *out_ptr[s->ld.color] = *raw++;
3795141cc406Sopenharmony_ci			      out_ptr[s->ld.color] += 3;
3796141cc406Sopenharmony_ci			    }
3797141cc406Sopenharmony_ci			}
3798141cc406Sopenharmony_ci		      else
3799141cc406Sopenharmony_ci			{
3800141cc406Sopenharmony_ci			  for (pixel = 0; pixel < bpc; ++pixel)
3801141cc406Sopenharmony_ci			    {
3802141cc406Sopenharmony_ci			      scale += res;
3803141cc406Sopenharmony_ci			      if (scale >= max_value)
3804141cc406Sopenharmony_ci				{
3805141cc406Sopenharmony_ci				  scale -= max_value;
3806141cc406Sopenharmony_ci				  *out_ptr[s->ld.color] = *raw;
3807141cc406Sopenharmony_ci				  out_ptr[s->ld.color] += 3;
3808141cc406Sopenharmony_ci				}
3809141cc406Sopenharmony_ci			      ++raw;
3810141cc406Sopenharmony_ci			    }
3811141cc406Sopenharmony_ci			}
3812141cc406Sopenharmony_ci
3813141cc406Sopenharmony_ci		      DBG (5, "fix_line_distance_se: got line: %d; color: "
3814141cc406Sopenharmony_ci			   "%d\n", lines[s->ld.color], s->ld.color);
3815141cc406Sopenharmony_ci		    }
3816141cc406Sopenharmony_ci		  --lines[s->ld.color];
3817141cc406Sopenharmony_ci		}
3818141cc406Sopenharmony_ci	      else
3819141cc406Sopenharmony_ci		{
3820141cc406Sopenharmony_ci		  /* At least one component missing, so save this line. */
3821141cc406Sopenharmony_ci		  memcpy (s->ld.buf[s->ld.color] + s->ld.saved[s->ld.color]
3822141cc406Sopenharmony_ci			  * bpc, raw, bpc);
3823141cc406Sopenharmony_ci		  DBG (5, "fix_line_distance_se: saved line %d; color %d\n",
3824141cc406Sopenharmony_ci		       s->ld.saved[s->ld.color], s->ld.color);
3825141cc406Sopenharmony_ci		  ++(s->ld.saved[s->ld.color]);
3826141cc406Sopenharmony_ci		  raw += bpc;
3827141cc406Sopenharmony_ci		}
3828141cc406Sopenharmony_ci	    }
3829141cc406Sopenharmony_ci	  else
3830141cc406Sopenharmony_ci	    {
3831141cc406Sopenharmony_ci	      if (!preview)
3832141cc406Sopenharmony_ci		raw += bpc;
3833141cc406Sopenharmony_ci	      DBG (5, "fix_line_distance_se: ignored line; color: %d\n",
3834141cc406Sopenharmony_ci		   s->ld.color);
3835141cc406Sopenharmony_ci	    }
3836141cc406Sopenharmony_ci
3837141cc406Sopenharmony_ci	  if (raw >= raw_end)
3838141cc406Sopenharmony_ci	    {
3839141cc406Sopenharmony_ci	      /* Reduce num_lines if we encounter excess lines. */
3840141cc406Sopenharmony_ci	      if (num_lines > s->ld.ld_line)
3841141cc406Sopenharmony_ci		num_lines = s->ld.ld_line;
3842141cc406Sopenharmony_ci	      s->ld.ld_line -= num_lines;
3843141cc406Sopenharmony_ci
3844141cc406Sopenharmony_ci	      if (++s->ld.color > 2)
3845141cc406Sopenharmony_ci		s->ld.color = 0;
3846141cc406Sopenharmony_ci	      return num_lines;
3847141cc406Sopenharmony_ci	    }
3848141cc406Sopenharmony_ci	}
3849141cc406Sopenharmony_ci      if (++s->ld.color > 2)
3850141cc406Sopenharmony_ci	s->ld.color = 0;
3851141cc406Sopenharmony_ci    }
3852141cc406Sopenharmony_ci}
3853141cc406Sopenharmony_ci
3854141cc406Sopenharmony_ci
3855141cc406Sopenharmony_ci/* For Pro models. Not really a linedistance correction (they don't need one)
3856141cc406Sopenharmony_ci   only enlarging x-res here */
3857141cc406Sopenharmony_cistatic void
3858141cc406Sopenharmony_cifix_line_distance_pro (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
3859141cc406Sopenharmony_ci		       SANE_Byte * raw, SANE_Byte * out)
3860141cc406Sopenharmony_ci{
3861141cc406Sopenharmony_ci  SANE_Byte *out_addr, *in_addr;
3862141cc406Sopenharmony_ci  SANE_Int res, half_res, y, x_out, x_in;
3863141cc406Sopenharmony_ci
3864141cc406Sopenharmony_ci
3865141cc406Sopenharmony_ci  res = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
3866141cc406Sopenharmony_ci  half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2;
3867141cc406Sopenharmony_ci
3868141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_pro: res=%d; halfres=%d; num_lines=%d; bpl=%d\n",
3869141cc406Sopenharmony_ci       res, half_res, num_lines, bpl);
3870141cc406Sopenharmony_ci
3871141cc406Sopenharmony_ci  if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0)
3872141cc406Sopenharmony_ci    {
3873141cc406Sopenharmony_ci      if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3874141cc406Sopenharmony_ci	{
3875141cc406Sopenharmony_ci	  /*12 bit, need to enlarge x-resolution */
3876141cc406Sopenharmony_ci	  DBG (5, "fix_line_distance_pro: res > half_res --> need to "
3877141cc406Sopenharmony_ci	       "enlarge x\n");
3878141cc406Sopenharmony_ci	  if (little_endian ())
3879141cc406Sopenharmony_ci	    for (y = 0; y < num_lines; y++)
3880141cc406Sopenharmony_ci	      {
3881141cc406Sopenharmony_ci		for (x_out = 0; x_out < s->params.pixels_per_line; x_out++)
3882141cc406Sopenharmony_ci		  {
3883141cc406Sopenharmony_ci		    x_in = x_out * bpl / s->params.bytes_per_line / 2;
3884141cc406Sopenharmony_ci		    x_in *= 2;
3885141cc406Sopenharmony_ci		    out_addr = out + y * s->params.bytes_per_line + x_out * 6;
3886141cc406Sopenharmony_ci		    in_addr = raw + y * bpl + x_in * 6;
3887141cc406Sopenharmony_ci		    *(out_addr) = *(in_addr) << 4;
3888141cc406Sopenharmony_ci		    *(out_addr + 1) = (*(in_addr) >> 4) +
3889141cc406Sopenharmony_ci		      (*(in_addr + 1) << 4);
3890141cc406Sopenharmony_ci		    *(out_addr + 2) = *(in_addr + 2) << 4;
3891141cc406Sopenharmony_ci		    *(out_addr + 3) = (*(in_addr + 2) >> 4) +
3892141cc406Sopenharmony_ci		      (*(in_addr + 3) << 4);
3893141cc406Sopenharmony_ci		    *(out_addr + 4) = *(in_addr + 4) << 4;
3894141cc406Sopenharmony_ci		    *(out_addr + 5) = (*(in_addr + 4) >> 4) +
3895141cc406Sopenharmony_ci		      (*(in_addr + 5) << 4);
3896141cc406Sopenharmony_ci		  }
3897141cc406Sopenharmony_ci	      }
3898141cc406Sopenharmony_ci	  else			/* big endian */
3899141cc406Sopenharmony_ci	    for (y = 0; y < num_lines; y++)
3900141cc406Sopenharmony_ci	      {
3901141cc406Sopenharmony_ci		for (x_out = 0; x_out < s->params.pixels_per_line; x_out++)
3902141cc406Sopenharmony_ci		  {
3903141cc406Sopenharmony_ci		    x_in = x_out * bpl / s->params.bytes_per_line / 2;
3904141cc406Sopenharmony_ci		    out_addr = out + y * s->params.bytes_per_line + x_out * 6;
3905141cc406Sopenharmony_ci		    in_addr = raw + y * bpl + x_in * 6;
3906141cc406Sopenharmony_ci		    *(out_addr) = (*(in_addr) >> 4) + (*(in_addr + 1) << 4);
3907141cc406Sopenharmony_ci		    *(out_addr + 1) = *(in_addr) << 4;
3908141cc406Sopenharmony_ci		    *(out_addr + 2) = (*(in_addr + 2) >> 4) +
3909141cc406Sopenharmony_ci		      (*(in_addr + 3) << 4);
3910141cc406Sopenharmony_ci		    *(out_addr + 3) = *(in_addr + 2) << 4;
3911141cc406Sopenharmony_ci		    *(out_addr + 4) = (*(in_addr + 4) >> 4) +
3912141cc406Sopenharmony_ci		      (*(in_addr + 5) << 4);
3913141cc406Sopenharmony_ci		    *(out_addr + 5) = *(in_addr + 4) << 4;
3914141cc406Sopenharmony_ci		  }
3915141cc406Sopenharmony_ci	      }
3916141cc406Sopenharmony_ci	}
3917141cc406Sopenharmony_ci      else			/* 12 bit, no need to enlarge x */
3918141cc406Sopenharmony_ci	{
3919141cc406Sopenharmony_ci	  SANE_Word pixel;
3920141cc406Sopenharmony_ci
3921141cc406Sopenharmony_ci	  if (little_endian ())
3922141cc406Sopenharmony_ci	    for (pixel = 0; pixel < (num_lines * bpl / 2); pixel++)
3923141cc406Sopenharmony_ci	      {
3924141cc406Sopenharmony_ci		*(out + pixel * 2) = *(raw + pixel * 2) << 4;
3925141cc406Sopenharmony_ci		*(out + pixel * 2 + 1) = (*(raw + pixel * 2) >> 4) +
3926141cc406Sopenharmony_ci		  (*(raw + pixel * 2 + 1) << 4);
3927141cc406Sopenharmony_ci	      }
3928141cc406Sopenharmony_ci	  else			/* big endian */
3929141cc406Sopenharmony_ci	    for (pixel = 0; pixel < (num_lines * bpl / 2); pixel++)
3930141cc406Sopenharmony_ci	      {
3931141cc406Sopenharmony_ci		*(out + pixel * 2) = (*(raw + pixel * 2) >> 4) +
3932141cc406Sopenharmony_ci		  (*(raw + pixel * 2 + 1) << 4);
3933141cc406Sopenharmony_ci		*(out + pixel * 2 + 1) = *(raw + pixel * 2) << 4;
3934141cc406Sopenharmony_ci	      }
3935141cc406Sopenharmony_ci
3936141cc406Sopenharmony_ci	}
3937141cc406Sopenharmony_ci    }
3938141cc406Sopenharmony_ci  else				/* 8 bit */
3939141cc406Sopenharmony_ci    {
3940141cc406Sopenharmony_ci      /* need to enlarge x-resolution? */
3941141cc406Sopenharmony_ci      if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (res > half_res))
3942141cc406Sopenharmony_ci	{
3943141cc406Sopenharmony_ci	  DBG (5, "fix_line_distance_pro: res > half_res --> need to "
3944141cc406Sopenharmony_ci	       "enlarge x\n");
3945141cc406Sopenharmony_ci
3946141cc406Sopenharmony_ci	  for (y = 0; y < num_lines; y++)
3947141cc406Sopenharmony_ci	    {
3948141cc406Sopenharmony_ci	      for (x_out = 0; x_out < s->params.pixels_per_line; x_out++)
3949141cc406Sopenharmony_ci		{
3950141cc406Sopenharmony_ci		  x_in = x_out * bpl / s->params.bytes_per_line;
3951141cc406Sopenharmony_ci		  out_addr = out + y * s->params.bytes_per_line + x_out * 3;
3952141cc406Sopenharmony_ci		  in_addr = raw + y * bpl + x_in * 3;
3953141cc406Sopenharmony_ci		  *(out_addr) = *(in_addr);
3954141cc406Sopenharmony_ci		  *(out_addr + 1) = *(in_addr + 1);
3955141cc406Sopenharmony_ci		  *(out_addr + 2) = *(in_addr + 2);
3956141cc406Sopenharmony_ci		}
3957141cc406Sopenharmony_ci	    }
3958141cc406Sopenharmony_ci	}
3959141cc406Sopenharmony_ci      else
3960141cc406Sopenharmony_ci	memcpy (out, raw, num_lines * bpl);
3961141cc406Sopenharmony_ci    }
3962141cc406Sopenharmony_ci  return;
3963141cc406Sopenharmony_ci}
3964141cc406Sopenharmony_ci
3965141cc406Sopenharmony_ci/* For MFS-08000SP, MFS-06000SP. MFC-08000CZ, MFC-06000CZ */
3966141cc406Sopenharmony_cistatic void
3967141cc406Sopenharmony_cifix_line_distance_normal (Mustek_Scanner * s, SANE_Int num_lines,
3968141cc406Sopenharmony_ci			  SANE_Int bpl, SANE_Byte * raw, SANE_Byte * out)
3969141cc406Sopenharmony_ci{
3970141cc406Sopenharmony_ci  SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl;
3971141cc406Sopenharmony_ci  SANE_Int index[3];		/* index of the next output line for color C */
3972141cc406Sopenharmony_ci  SANE_Int i, color;
3973141cc406Sopenharmony_ci
3974141cc406Sopenharmony_ci  /* Initialize the indices with the line distances that were returned
3975141cc406Sopenharmony_ci     by the CCD linedistance command or set manually (option
3976141cc406Sopenharmony_ci     linedistance-fix).  We want to skip data for the first OFFSET
3977141cc406Sopenharmony_ci     rounds, so we initialize the indices to the negative of this
3978141cc406Sopenharmony_ci     offset.  */
3979141cc406Sopenharmony_ci
3980141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_normal: %d lines, %d bpl\n", num_lines, bpl);
3981141cc406Sopenharmony_ci
3982141cc406Sopenharmony_ci  for (color = 0; color < 3; ++color)
3983141cc406Sopenharmony_ci    index[color] = -s->ld.dist[color];
3984141cc406Sopenharmony_ci
3985141cc406Sopenharmony_ci  while (1)
3986141cc406Sopenharmony_ci    {
3987141cc406Sopenharmony_ci      for (i = 0; i < 3; ++i)
3988141cc406Sopenharmony_ci	{
3989141cc406Sopenharmony_ci	  color = color_seq[i];
3990141cc406Sopenharmony_ci	  if (index[color] < 0)
3991141cc406Sopenharmony_ci	    ++index[color];
3992141cc406Sopenharmony_ci	  else if (index[color] < num_lines)
3993141cc406Sopenharmony_ci	    {
3994141cc406Sopenharmony_ci	      s->ld.quant[color] += s->ld.peak_res;
3995141cc406Sopenharmony_ci	      if (s->ld.quant[color] > s->ld.max_value)
3996141cc406Sopenharmony_ci		{
3997141cc406Sopenharmony_ci		  s->ld.quant[color] -= s->ld.max_value;
3998141cc406Sopenharmony_ci		  out_ptr = out + index[color] * bpl + color;
3999141cc406Sopenharmony_ci		  out_end = out_ptr + bpl;
4000141cc406Sopenharmony_ci		  while (out_ptr != out_end)
4001141cc406Sopenharmony_ci		    {
4002141cc406Sopenharmony_ci		      *out_ptr = *raw++;
4003141cc406Sopenharmony_ci		      out_ptr += 3;
4004141cc406Sopenharmony_ci		    }
4005141cc406Sopenharmony_ci		  ++index[color];
4006141cc406Sopenharmony_ci		  if (raw >= raw_end)
4007141cc406Sopenharmony_ci		    return;
4008141cc406Sopenharmony_ci		}
4009141cc406Sopenharmony_ci	    }
4010141cc406Sopenharmony_ci	}
4011141cc406Sopenharmony_ci    }
4012141cc406Sopenharmony_ci}
4013141cc406Sopenharmony_ci
4014141cc406Sopenharmony_ci/* Paragon series I + II. */
4015141cc406Sopenharmony_cistatic SANE_Int
4016141cc406Sopenharmony_cifix_line_distance_block (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
4017141cc406Sopenharmony_ci			 SANE_Byte * raw, SANE_Byte * out,
4018141cc406Sopenharmony_ci			 SANE_Int num_lines_total)
4019141cc406Sopenharmony_ci{
4020141cc406Sopenharmony_ci  SANE_Byte *out_end, *out_ptr, *raw_end = raw + num_lines * bpl;
4021141cc406Sopenharmony_ci  SANE_Int c, num_saved_lines, line, max_index, min_index;
4022141cc406Sopenharmony_ci
4023141cc406Sopenharmony_ci  if (!s->ld.buf[0])
4024141cc406Sopenharmony_ci    {
4025141cc406Sopenharmony_ci      DBG (5, "fix_line_distance_block: allocating temp buffer of %d*%d "
4026141cc406Sopenharmony_ci	   "bytes\n", MAX_LINE_DIST, bpl);
4027141cc406Sopenharmony_ci      s->ld.buf[0] = malloc (MAX_LINE_DIST * (long) bpl);
4028141cc406Sopenharmony_ci      if (!s->ld.buf[0])
4029141cc406Sopenharmony_ci	{
4030141cc406Sopenharmony_ci	  DBG (1, "fix_line_distance_block: failed to malloc temporary "
4031141cc406Sopenharmony_ci	       "buffer\n");
4032141cc406Sopenharmony_ci	  return 0;
4033141cc406Sopenharmony_ci	}
4034141cc406Sopenharmony_ci    }
4035141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_block: s->ld.index = {%d, %d, %d}, "
4036141cc406Sopenharmony_ci       "s->ld.lmod3 = %d\n", s->ld.index[0], s->ld.index[1], s->ld.index[2],
4037141cc406Sopenharmony_ci       s->ld.lmod3);
4038141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_block: s->ld.quant = {%d, %d, %d}, "
4039141cc406Sopenharmony_ci       "s->ld.max_value = %d\n", s->ld.quant[0], s->ld.quant[1],
4040141cc406Sopenharmony_ci       s->ld.quant[2], s->ld.max_value);
4041141cc406Sopenharmony_ci  DBG (5,
4042141cc406Sopenharmony_ci       "fix_line_distance_block: s->ld.peak_res = %d, s->ld.ld_line = %d\n",
4043141cc406Sopenharmony_ci       s->ld.peak_res, s->ld.ld_line);
4044141cc406Sopenharmony_ci
4045141cc406Sopenharmony_ci  /* search maximum and minimum index */
4046141cc406Sopenharmony_ci  max_index = MAX (s->ld.index[0], MAX (s->ld.index[1], s->ld.index[2]));
4047141cc406Sopenharmony_ci  min_index = MIN (s->ld.index[0], MIN (s->ld.index[1], s->ld.index[2]));
4048141cc406Sopenharmony_ci  num_saved_lines = max_index - min_index;
4049141cc406Sopenharmony_ci  if (s->ld.index[0] == 0)
4050141cc406Sopenharmony_ci    num_saved_lines = 0;
4051141cc406Sopenharmony_ci  /* restore the previously saved lines: */
4052141cc406Sopenharmony_ci  memcpy (out, s->ld.buf[0], num_saved_lines * bpl);
4053141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_block: copied %d lines from "
4054141cc406Sopenharmony_ci       "ld.buf to buffer (max=%d, min=%d)\n", num_saved_lines, max_index,
4055141cc406Sopenharmony_ci       min_index);
4056141cc406Sopenharmony_ci  while (1)
4057141cc406Sopenharmony_ci    {
4058141cc406Sopenharmony_ci      if (++s->ld.lmod3 >= 3)
4059141cc406Sopenharmony_ci	s->ld.lmod3 = 0;
4060141cc406Sopenharmony_ci
4061141cc406Sopenharmony_ci      c = color_seq[s->ld.lmod3];
4062141cc406Sopenharmony_ci      if (s->ld.index[c] < 0)
4063141cc406Sopenharmony_ci	++s->ld.index[c];
4064141cc406Sopenharmony_ci      else if (s->ld.index[c] < num_lines_total)
4065141cc406Sopenharmony_ci	{
4066141cc406Sopenharmony_ci	  s->ld.quant[c] += s->ld.peak_res;
4067141cc406Sopenharmony_ci	  if (s->ld.quant[c] > s->ld.max_value)
4068141cc406Sopenharmony_ci	    {
4069141cc406Sopenharmony_ci	      s->ld.quant[c] -= s->ld.max_value;
4070141cc406Sopenharmony_ci	      line = s->ld.index[c]++ - s->ld.ld_line;
4071141cc406Sopenharmony_ci	      out_ptr = out + line * bpl + c;
4072141cc406Sopenharmony_ci	      out_end = out_ptr + bpl;
4073141cc406Sopenharmony_ci	      while (out_ptr != out_end)
4074141cc406Sopenharmony_ci		{
4075141cc406Sopenharmony_ci		  *out_ptr = *raw++;
4076141cc406Sopenharmony_ci		  out_ptr += 3;
4077141cc406Sopenharmony_ci		}
4078141cc406Sopenharmony_ci	      DBG (5, "fix_line_distance_block: copied line %d (color %d)\n",
4079141cc406Sopenharmony_ci		   line + s->ld.ld_line, c);
4080141cc406Sopenharmony_ci
4081141cc406Sopenharmony_ci	      max_index = MAX (s->ld.index[0],
4082141cc406Sopenharmony_ci			       MAX (s->ld.index[1], s->ld.index[2]));
4083141cc406Sopenharmony_ci	      min_index = MIN (s->ld.index[0],
4084141cc406Sopenharmony_ci			       MIN (s->ld.index[1], s->ld.index[2]));
4085141cc406Sopenharmony_ci	      if ((raw >= raw_end) || ((min_index >= num_lines_total)))
4086141cc406Sopenharmony_ci		{
4087141cc406Sopenharmony_ci		  DBG (5, "fix_line_distance_block: got num_lines: %d\n",
4088141cc406Sopenharmony_ci		       num_lines);
4089141cc406Sopenharmony_ci		  num_lines = min_index - s->ld.ld_line;
4090141cc406Sopenharmony_ci		  if (num_lines < 0)
4091141cc406Sopenharmony_ci		    num_lines = 0;
4092141cc406Sopenharmony_ci		  if ((s->total_lines + num_lines) > s->params.lines)
4093141cc406Sopenharmony_ci		    num_lines = s->params.lines - s->total_lines;
4094141cc406Sopenharmony_ci		  s->total_lines += num_lines;
4095141cc406Sopenharmony_ci
4096141cc406Sopenharmony_ci		  /* copy away the lines with at least one missing
4097141cc406Sopenharmony_ci		     color component, so that we can interleave them
4098141cc406Sopenharmony_ci		     with new scan data on the next call */
4099141cc406Sopenharmony_ci		  num_saved_lines = max_index - min_index;
4100141cc406Sopenharmony_ci
4101141cc406Sopenharmony_ci		  DBG (5, "fix_line_distance_block: num_saved_lines = %d; "
4102141cc406Sopenharmony_ci		       "num_lines = %d; bpl = %d\n", num_saved_lines,
4103141cc406Sopenharmony_ci		       num_lines, bpl);
4104141cc406Sopenharmony_ci
4105141cc406Sopenharmony_ci		  memcpy (s->ld.buf[0], out + num_lines * bpl,
4106141cc406Sopenharmony_ci			  num_saved_lines * bpl);
4107141cc406Sopenharmony_ci
4108141cc406Sopenharmony_ci		  DBG (5, "fix_line_distance_block: copied %d lines to "
4109141cc406Sopenharmony_ci		       "ld.buf\n", num_saved_lines);
4110141cc406Sopenharmony_ci
4111141cc406Sopenharmony_ci		  /* notice the number of lines we processed */
4112141cc406Sopenharmony_ci		  s->ld.ld_line = min_index;
4113141cc406Sopenharmony_ci		  if (s->ld.ld_line < 0)
4114141cc406Sopenharmony_ci		    s->ld.ld_line = 0;
4115141cc406Sopenharmony_ci
4116141cc406Sopenharmony_ci		  DBG (4, "fix_line_distance_block: lmod3=%d, "
4117141cc406Sopenharmony_ci		       "index=(%d,%d,%d), line = %d, lines = %d\n",
4118141cc406Sopenharmony_ci		       s->ld.lmod3,
4119141cc406Sopenharmony_ci		       s->ld.index[0], s->ld.index[1], s->ld.index[2],
4120141cc406Sopenharmony_ci		       s->ld.ld_line, num_lines);
4121141cc406Sopenharmony_ci		  /* return number of complete (r+g+b) lines */
4122141cc406Sopenharmony_ci		  return num_lines;
4123141cc406Sopenharmony_ci		}
4124141cc406Sopenharmony_ci	    }
4125141cc406Sopenharmony_ci	}
4126141cc406Sopenharmony_ci    }
4127141cc406Sopenharmony_ci}
4128141cc406Sopenharmony_ci
4129141cc406Sopenharmony_ci/* For MFS-1200SP 1.00 and others */
4130141cc406Sopenharmony_ci/* No LD correction necessary, just shuffle around data */
4131141cc406Sopenharmony_cistatic SANE_Int
4132141cc406Sopenharmony_cifix_line_distance_none (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl,
4133141cc406Sopenharmony_ci			SANE_Byte * raw, SANE_Byte * out)
4134141cc406Sopenharmony_ci{
4135141cc406Sopenharmony_ci  SANE_Byte *red_ptr, *grn_ptr, *blu_ptr, *ptr, *ptr_end;
4136141cc406Sopenharmony_ci  SANE_Word y;
4137141cc406Sopenharmony_ci
4138141cc406Sopenharmony_ci  ptr = out;
4139141cc406Sopenharmony_ci  red_ptr = raw;
4140141cc406Sopenharmony_ci
4141141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_none: no ld correction necessary (%d lines)\n",
4142141cc406Sopenharmony_ci       num_lines);
4143141cc406Sopenharmony_ci
4144141cc406Sopenharmony_ci  s->ld.ld_line += num_lines;
4145141cc406Sopenharmony_ci
4146141cc406Sopenharmony_ci  if (s->ld.ld_line > s->params.lines)
4147141cc406Sopenharmony_ci    num_lines -= (s->ld.ld_line - s->params.lines);
4148141cc406Sopenharmony_ci  if (num_lines < 0)
4149141cc406Sopenharmony_ci    num_lines = 0;
4150141cc406Sopenharmony_ci
4151141cc406Sopenharmony_ci  DBG (5, "fix_line_distance_none: using %d lines (ld_line = %d, "
4152141cc406Sopenharmony_ci       "s->params.lines = %d)\n", num_lines, s->ld.ld_line, s->params.lines);
4153141cc406Sopenharmony_ci
4154141cc406Sopenharmony_ci  for (y = 0; y < num_lines; ++y)
4155141cc406Sopenharmony_ci    {
4156141cc406Sopenharmony_ci      grn_ptr = red_ptr + bpl / 3;
4157141cc406Sopenharmony_ci      blu_ptr = grn_ptr + bpl / 3;
4158141cc406Sopenharmony_ci      ptr_end = red_ptr + bpl;
4159141cc406Sopenharmony_ci
4160141cc406Sopenharmony_ci      while (blu_ptr != ptr_end)
4161141cc406Sopenharmony_ci	{
4162141cc406Sopenharmony_ci	  *ptr++ = *red_ptr++;
4163141cc406Sopenharmony_ci	  *ptr++ = *grn_ptr++;
4164141cc406Sopenharmony_ci	  *ptr++ = *blu_ptr++;
4165141cc406Sopenharmony_ci	}
4166141cc406Sopenharmony_ci      red_ptr = ptr_end;
4167141cc406Sopenharmony_ci    }
4168141cc406Sopenharmony_ci  return num_lines;
4169141cc406Sopenharmony_ci}
4170141cc406Sopenharmony_ci
4171141cc406Sopenharmony_ci
4172141cc406Sopenharmony_cistatic SANE_Status
4173141cc406Sopenharmony_ciinit_options (Mustek_Scanner * s)
4174141cc406Sopenharmony_ci{
4175141cc406Sopenharmony_ci  SANE_Int i, j, gammasize;
4176141cc406Sopenharmony_ci
4177141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
4178141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
4179141cc406Sopenharmony_ci
4180141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
4181141cc406Sopenharmony_ci    {
4182141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
4183141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
4184141cc406Sopenharmony_ci    }
4185141cc406Sopenharmony_ci
4186141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].name = "";
4187141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
4188141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
4189141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
4190141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
4191141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
4192141cc406Sopenharmony_ci
4193141cc406Sopenharmony_ci  /* "Mode" group: */
4194141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
4195141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
4196141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
4197141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
4198141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].size = 0;
4199141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
4200141cc406Sopenharmony_ci
4201141cc406Sopenharmony_ci  /* scan mode */
4202141cc406Sopenharmony_ci  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
4203141cc406Sopenharmony_ci  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
4204141cc406Sopenharmony_ci  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
4205141cc406Sopenharmony_ci  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
4206141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4207141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_SE)
4208141cc406Sopenharmony_ci    {
4209141cc406Sopenharmony_ci      s->opt[OPT_MODE].size = max_string_size (mode_list_se);
4210141cc406Sopenharmony_ci      s->opt[OPT_MODE].constraint.string_list = mode_list_se;
4211141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (mode_list_se[1]);
4212141cc406Sopenharmony_ci      if (!s->val[OPT_MODE].s)
4213141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
4214141cc406Sopenharmony_ci    }
4215141cc406Sopenharmony_ci  else
4216141cc406Sopenharmony_ci    {
4217141cc406Sopenharmony_ci      s->opt[OPT_MODE].size = max_string_size (mode_list_paragon);
4218141cc406Sopenharmony_ci      s->opt[OPT_MODE].constraint.string_list = mode_list_paragon;
4219141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (mode_list_paragon[2]);
4220141cc406Sopenharmony_ci      if (!s->val[OPT_MODE].s)
4221141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
4222141cc406Sopenharmony_ci    }
4223141cc406Sopenharmony_ci
4224141cc406Sopenharmony_ci  /* fast gray mode (pro models) */
4225141cc406Sopenharmony_ci  s->opt[OPT_FAST_GRAY_MODE].name = "fast-gray-mode";
4226141cc406Sopenharmony_ci  s->opt[OPT_FAST_GRAY_MODE].title = SANE_I18N ("Fast gray mode");
4227141cc406Sopenharmony_ci  s->opt[OPT_FAST_GRAY_MODE].desc = SANE_I18N ("Scan in fast gray mode "
4228141cc406Sopenharmony_ci					       "(lower quality).");
4229141cc406Sopenharmony_ci  s->opt[OPT_FAST_GRAY_MODE].type = SANE_TYPE_BOOL;
4230141cc406Sopenharmony_ci  s->val[OPT_FAST_GRAY_MODE].w = SANE_FALSE;
4231141cc406Sopenharmony_ci  s->opt[OPT_FAST_GRAY_MODE].cap |= SANE_CAP_INACTIVE;
4232141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_PRO)
4233141cc406Sopenharmony_ci    {
4234141cc406Sopenharmony_ci      /* Only Pro models support fast gray mode */
4235141cc406Sopenharmony_ci      s->opt[OPT_FAST_GRAY_MODE].cap &= ~SANE_CAP_INACTIVE;
4236141cc406Sopenharmony_ci    }
4237141cc406Sopenharmony_ci
4238141cc406Sopenharmony_ci  /* resolution */
4239141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
4240141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
4241141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
4242141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
4243141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
4244141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
4245141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
4246141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = MAX (SANE_FIX (72), s->hw->dpi_range.min);
4247141cc406Sopenharmony_ci
4248141cc406Sopenharmony_ci  /* bit depth */
4249141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
4250141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
4251141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
4252141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_STRING;
4253141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4254141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
4255141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].size = max_string_size (bit_depth_list_pro);
4256141cc406Sopenharmony_ci  s->opt[OPT_BIT_DEPTH].constraint.string_list = bit_depth_list_pro;
4257141cc406Sopenharmony_ci  s->val[OPT_BIT_DEPTH].s = strdup (bit_depth_list_pro[0]);
4258141cc406Sopenharmony_ci  if (!s->val[OPT_BIT_DEPTH].s)
4259141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
4260141cc406Sopenharmony_ci
4261141cc406Sopenharmony_ci  /* speed */
4262141cc406Sopenharmony_ci  s->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED;
4263141cc406Sopenharmony_ci  s->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
4264141cc406Sopenharmony_ci  s->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED;
4265141cc406Sopenharmony_ci  s->opt[OPT_SPEED].type = SANE_TYPE_STRING;
4266141cc406Sopenharmony_ci  s->opt[OPT_SPEED].size = max_string_size (speed_list);
4267141cc406Sopenharmony_ci  s->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4268141cc406Sopenharmony_ci  s->opt[OPT_SPEED].constraint.string_list = speed_list;
4269141cc406Sopenharmony_ci  s->val[OPT_SPEED].s = strdup (speed_list[4]);
4270141cc406Sopenharmony_ci  if (!s->val[OPT_SPEED].s)
4271141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
4272141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
4273141cc406Sopenharmony_ci    {
4274141cc406Sopenharmony_ci      /* Speed only supported by 3-pass scanners */
4275141cc406Sopenharmony_ci      s->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE;
4276141cc406Sopenharmony_ci    }
4277141cc406Sopenharmony_ci
4278141cc406Sopenharmony_ci  /* source */
4279141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
4280141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
4281141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
4282141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
4283141cc406Sopenharmony_ci
4284141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_SE) || (s->hw->flags & MUSTEK_FLAG_N)
4285141cc406Sopenharmony_ci      || (s->hw->flags & MUSTEK_FLAG_TA))
4286141cc406Sopenharmony_ci    {
4287141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].size = max_string_size (ta_source_list);
4288141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4289141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint.string_list = ta_source_list;
4290141cc406Sopenharmony_ci      s->val[OPT_SOURCE].s = strdup (ta_source_list[0]);
4291141cc406Sopenharmony_ci      if (!s->val[OPT_SOURCE].s)
4292141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
4293141cc406Sopenharmony_ci    }
4294141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_ADF)
4295141cc406Sopenharmony_ci    {
4296141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].size = max_string_size (adf_source_list);
4297141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4298141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint.string_list = adf_source_list;
4299141cc406Sopenharmony_ci      s->val[OPT_SOURCE].s = strdup (adf_source_list[0]);
4300141cc406Sopenharmony_ci      if (!s->val[OPT_SOURCE].s)
4301141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
4302141cc406Sopenharmony_ci    }
4303141cc406Sopenharmony_ci  else
4304141cc406Sopenharmony_ci    {
4305141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].size = max_string_size (source_list);
4306141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
4307141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].constraint.string_list = source_list;
4308141cc406Sopenharmony_ci      s->val[OPT_SOURCE].s = strdup (source_list[0]);
4309141cc406Sopenharmony_ci      s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
4310141cc406Sopenharmony_ci      if (!s->val[OPT_SOURCE].s)
4311141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
4312141cc406Sopenharmony_ci    }
4313141cc406Sopenharmony_ci
4314141cc406Sopenharmony_ci  /* preview */
4315141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
4316141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
4317141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
4318141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
4319141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w = 0;
4320141cc406Sopenharmony_ci
4321141cc406Sopenharmony_ci  /* fast preview */
4322141cc406Sopenharmony_ci  s->opt[OPT_FAST_PREVIEW].name = "fast-preview";
4323141cc406Sopenharmony_ci  s->opt[OPT_FAST_PREVIEW].title = SANE_I18N ("Fast preview");
4324141cc406Sopenharmony_ci  s->opt[OPT_FAST_PREVIEW].desc = SANE_I18N ("Request that all previews are "
4325141cc406Sopenharmony_ci					     "done in the fastest (low-quality) mode. This may be a non-color "
4326141cc406Sopenharmony_ci					     "mode or a low resolution mode.");
4327141cc406Sopenharmony_ci  s->opt[OPT_FAST_PREVIEW].type = SANE_TYPE_BOOL;
4328141cc406Sopenharmony_ci  s->val[OPT_FAST_PREVIEW].w = SANE_FALSE;
4329141cc406Sopenharmony_ci
4330141cc406Sopenharmony_ci  /* lamp off time*/
4331141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time";
4332141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time (minutes)");
4333141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].desc = SANE_I18N ("Set the time (in minutes) after "
4334141cc406Sopenharmony_ci					      "which the lamp is shut off.");
4335141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT;
4336141cc406Sopenharmony_ci  if (strcmp (s->hw->sane.model, "1200 A3 PRO") != 0)
4337141cc406Sopenharmony_ci    s->opt[OPT_LAMP_OFF_TIME].cap |= SANE_CAP_INACTIVE;
4338141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE;
4339141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_TIME].constraint.range = &u8_range;
4340141cc406Sopenharmony_ci  s->val[OPT_LAMP_OFF_TIME].w = 60;
4341141cc406Sopenharmony_ci
4342141cc406Sopenharmony_ci  /* shut lamp off */
4343141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_BUTTON].name = "lamp-off";
4344141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_BUTTON].title = SANE_I18N ("Turn lamp off");
4345141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_BUTTON].desc = SANE_I18N ("Turns the lamp off immediately.");
4346141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_BUTTON].type = SANE_TYPE_BUTTON;
4347141cc406Sopenharmony_ci  s->opt[OPT_LAMP_OFF_BUTTON].cap = SANE_CAP_SOFT_SELECT;
4348141cc406Sopenharmony_ci  if (strcmp (s->hw->sane.model, "1200 A3 PRO") != 0)
4349141cc406Sopenharmony_ci    s->opt[OPT_LAMP_OFF_BUTTON].cap |= SANE_CAP_INACTIVE;
4350141cc406Sopenharmony_ci
4351141cc406Sopenharmony_ci  /* "Geometry" group: */
4352141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
4353141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
4354141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
4355141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
4356141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].size = 0;
4357141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
4358141cc406Sopenharmony_ci
4359141cc406Sopenharmony_ci  /* top-left x */
4360141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
4361141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
4362141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
4363141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
4364141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
4365141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
4366141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
4367141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = s->hw->x_range.min;
4368141cc406Sopenharmony_ci
4369141cc406Sopenharmony_ci  /* top-left y */
4370141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
4371141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
4372141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
4373141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
4374141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
4375141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
4376141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
4377141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = s->hw->y_range.min;
4378141cc406Sopenharmony_ci
4379141cc406Sopenharmony_ci  /* bottom-right x */
4380141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
4381141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
4382141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
4383141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
4384141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
4385141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
4386141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
4387141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = s->hw->x_range.max;
4388141cc406Sopenharmony_ci
4389141cc406Sopenharmony_ci  /* bottom-right y */
4390141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
4391141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
4392141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
4393141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
4394141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
4395141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
4396141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
4397141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = s->hw->y_range.max;
4398141cc406Sopenharmony_ci
4399141cc406Sopenharmony_ci  /* "Enhancement" group: */
4400141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
4401141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
4402141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
4403141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
4404141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
4405141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
4406141cc406Sopenharmony_ci
4407141cc406Sopenharmony_ci  /* brightness */
4408141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
4409141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
4410141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
4411141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED;
4412141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
4413141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
4414141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
4415141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
4416141cc406Sopenharmony_ci    /* 1-pass scanners don't support brightness in multibit mode */
4417141cc406Sopenharmony_ci    s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
4418141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS].w = 0;
4419141cc406Sopenharmony_ci
4420141cc406Sopenharmony_ci  /* brightness red */
4421141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].name = "brightness-r";
4422141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].title = SANE_I18N ("Red brightness");
4423141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].desc = SANE_I18N ("Controls the brightness of "
4424141cc406Sopenharmony_ci					     "the red channel of the "
4425141cc406Sopenharmony_ci					     "acquired image.");
4426141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].type = SANE_TYPE_FIXED;
4427141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].unit = SANE_UNIT_PERCENT;
4428141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].constraint_type = SANE_CONSTRAINT_RANGE;
4429141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].constraint.range = &percentage_range;
4430141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_R].cap |= SANE_CAP_INACTIVE;
4431141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS_R].w = 0;
4432141cc406Sopenharmony_ci
4433141cc406Sopenharmony_ci  /* brightness green */
4434141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].name = "brightness-g";
4435141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].title = SANE_I18N ("Green brightness");
4436141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].desc = SANE_I18N ("Controls the brightness of "
4437141cc406Sopenharmony_ci					     "the green channel of the "
4438141cc406Sopenharmony_ci					     "acquired image.");
4439141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].type = SANE_TYPE_FIXED;
4440141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].unit = SANE_UNIT_PERCENT;
4441141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].constraint_type = SANE_CONSTRAINT_RANGE;
4442141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].constraint.range = &percentage_range;
4443141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_G].cap |= SANE_CAP_INACTIVE;
4444141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS_G].w = 0;
4445141cc406Sopenharmony_ci
4446141cc406Sopenharmony_ci  /* brightness blue */
4447141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].name = "brightness-b";
4448141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].title = SANE_I18N ("Blue brightness");
4449141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].desc = SANE_I18N ("Controls the brightness of "
4450141cc406Sopenharmony_ci					     "the blue channel of the "
4451141cc406Sopenharmony_ci					     "acquired image.");
4452141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].type = SANE_TYPE_FIXED;
4453141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].unit = SANE_UNIT_PERCENT;
4454141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].constraint_type = SANE_CONSTRAINT_RANGE;
4455141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].constraint.range = &percentage_range;
4456141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS_B].cap |= SANE_CAP_INACTIVE;
4457141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS_B].w = 0;
4458141cc406Sopenharmony_ci
4459141cc406Sopenharmony_ci  /* contrast */
4460141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
4461141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
4462141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
4463141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED;
4464141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
4465141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
4466141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
4467141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
4468141cc406Sopenharmony_ci    /* 1-pass scanners don't support contrast in multibit mode */
4469141cc406Sopenharmony_ci    s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
4470141cc406Sopenharmony_ci  s->val[OPT_CONTRAST].w = 0;
4471141cc406Sopenharmony_ci
4472141cc406Sopenharmony_ci  /* contrast red */
4473141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].name = "contrast-r";
4474141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].title = SANE_I18N ("Contrast red channel");
4475141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].desc = SANE_I18N ("Controls the contrast of "
4476141cc406Sopenharmony_ci					   "the red channel of the "
4477141cc406Sopenharmony_ci					   "acquired image.");
4478141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].type = SANE_TYPE_FIXED;
4479141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].unit = SANE_UNIT_PERCENT;
4480141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].constraint_type = SANE_CONSTRAINT_RANGE;
4481141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].constraint.range = &percentage_range;
4482141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_R].cap |= SANE_CAP_INACTIVE;
4483141cc406Sopenharmony_ci  s->val[OPT_CONTRAST_R].w = 0;
4484141cc406Sopenharmony_ci
4485141cc406Sopenharmony_ci  /* contrast green */
4486141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].name = "contrast-g";
4487141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].title = SANE_I18N ("Contrast green channel");
4488141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].desc = SANE_I18N ("Controls the contrast of "
4489141cc406Sopenharmony_ci					   "the green channel of the "
4490141cc406Sopenharmony_ci					   "acquired image.");
4491141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].type = SANE_TYPE_FIXED;
4492141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].unit = SANE_UNIT_PERCENT;
4493141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].constraint_type = SANE_CONSTRAINT_RANGE;
4494141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].constraint.range = &percentage_range;
4495141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_G].cap |= SANE_CAP_INACTIVE;
4496141cc406Sopenharmony_ci  s->val[OPT_CONTRAST_G].w = 0;
4497141cc406Sopenharmony_ci
4498141cc406Sopenharmony_ci  /* contrast blue */
4499141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].name = "contrast-b";
4500141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].title = SANE_I18N ("Contrast blue channel");
4501141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].desc = SANE_I18N ("Controls the contrast of "
4502141cc406Sopenharmony_ci					   "the blue channel of the "
4503141cc406Sopenharmony_ci					   "acquired image.");
4504141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].type = SANE_TYPE_FIXED;
4505141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].unit = SANE_UNIT_PERCENT;
4506141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].constraint_type = SANE_CONSTRAINT_RANGE;
4507141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].constraint.range = &percentage_range;
4508141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST_B].cap |= SANE_CAP_INACTIVE;
4509141cc406Sopenharmony_ci  s->val[OPT_CONTRAST_B].w = 0;
4510141cc406Sopenharmony_ci
4511141cc406Sopenharmony_ci  /* gamma */
4512141cc406Sopenharmony_ci  gammasize = 256;
4513141cc406Sopenharmony_ci  for (i = 0; i < 4; ++i)
4514141cc406Sopenharmony_ci    for (j = 0; j < gammasize; ++j)
4515141cc406Sopenharmony_ci      s->gamma_table[i][j] = j;
4516141cc406Sopenharmony_ci
4517141cc406Sopenharmony_ci  /* custom-gamma table */
4518141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
4519141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
4520141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
4521141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
4522141cc406Sopenharmony_ci  s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
4523141cc406Sopenharmony_ci
4524141cc406Sopenharmony_ci  /* grayscale gamma vector */
4525141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
4526141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
4527141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
4528141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
4529141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
4530141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
4531141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
4532141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0];
4533141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
4534141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
4535141cc406Sopenharmony_ci
4536141cc406Sopenharmony_ci  /* red gamma vector */
4537141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
4538141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
4539141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
4540141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
4541141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
4542141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
4543141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
4544141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0];
4545141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
4546141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
4547141cc406Sopenharmony_ci
4548141cc406Sopenharmony_ci  /* green gamma vector */
4549141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
4550141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
4551141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
4552141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
4553141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
4554141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
4555141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
4556141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0];
4557141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
4558141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
4559141cc406Sopenharmony_ci
4560141cc406Sopenharmony_ci  /* blue gamma vector */
4561141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
4562141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
4563141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
4564141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
4565141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
4566141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
4567141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
4568141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0];
4569141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
4570141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
4571141cc406Sopenharmony_ci
4572141cc406Sopenharmony_ci  /* quality calibration */
4573141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].name = SANE_NAME_QUALITY_CAL;
4574141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].title = SANE_TITLE_QUALITY_CAL;
4575141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].desc = SANE_DESC_QUALITY_CAL;
4576141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].type = SANE_TYPE_BOOL;
4577141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_PRO)
4578141cc406Sopenharmony_ci    s->val[OPT_QUALITY_CAL].w = SANE_TRUE;
4579141cc406Sopenharmony_ci  else
4580141cc406Sopenharmony_ci    s->val[OPT_QUALITY_CAL].w = SANE_FALSE;
4581141cc406Sopenharmony_ci  s->opt[OPT_QUALITY_CAL].cap |= SANE_CAP_INACTIVE;
4582141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_PRO)
4583141cc406Sopenharmony_ci      || (s->hw->flags & MUSTEK_FLAG_SE_PLUS))
4584141cc406Sopenharmony_ci    {
4585141cc406Sopenharmony_ci      /* Only Pro and SE Plus models support calibration */
4586141cc406Sopenharmony_ci      s->opt[OPT_QUALITY_CAL].cap &= ~SANE_CAP_INACTIVE;
4587141cc406Sopenharmony_ci    }
4588141cc406Sopenharmony_ci
4589141cc406Sopenharmony_ci  /* halftone dimension */
4590141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].name = SANE_NAME_HALFTONE_DIMENSION;
4591141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].title = SANE_TITLE_HALFTONE_DIMENSION;
4592141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].desc = SANE_DESC_HALFTONE_DIMENSION;
4593141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].type = SANE_TYPE_STRING;
4594141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].size = max_string_size (halftone_list);
4595141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].constraint_type =
4596141cc406Sopenharmony_ci    SANE_CONSTRAINT_STRING_LIST;
4597141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].constraint.string_list = halftone_list;
4598141cc406Sopenharmony_ci  s->val[OPT_HALFTONE_DIMENSION].s = strdup (halftone_list[0]);
4599141cc406Sopenharmony_ci  if (!s->val[OPT_HALFTONE_DIMENSION].s)
4600141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
4601141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_DIMENSION].cap |= SANE_CAP_INACTIVE;
4602141cc406Sopenharmony_ci
4603141cc406Sopenharmony_ci  /* halftone pattern */
4604141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
4605141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
4606141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
4607141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_INT;
4608141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
4609141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_RANGE;
4610141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].constraint.range = &u8_range;
4611141cc406Sopenharmony_ci  s->val[OPT_HALFTONE_PATTERN].wa = s->halftone_pattern;
4612141cc406Sopenharmony_ci
4613141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4614141cc406Sopenharmony_ci}
4615141cc406Sopenharmony_ci
4616141cc406Sopenharmony_ci/* The following three functions execute as a child process.  The
4617141cc406Sopenharmony_ci   reason for using a subprocess is that some (most?) generic SCSI
4618141cc406Sopenharmony_ci   interfaces block a SCSI request until it has completed.  With a
4619141cc406Sopenharmony_ci   subprocess, we can let it block waiting for the request to finish
4620141cc406Sopenharmony_ci   while the main process can go about to do more important things
4621141cc406Sopenharmony_ci   (such as recognizing when the user presses a cancel button).
4622141cc406Sopenharmony_ci
4623141cc406Sopenharmony_ci   WARNING: Since this is executed as a subprocess, it's NOT possible
4624141cc406Sopenharmony_ci   to update any of the variables in the main process (in particular
4625141cc406Sopenharmony_ci   the scanner state cannot be updated).
4626141cc406Sopenharmony_ci
4627141cc406Sopenharmony_ci   NOTE: At least for Linux, it seems that we could get rid of the
4628141cc406Sopenharmony_ci   subprocess.  Linux v2.0 does seem to allow select() on SCSI
4629141cc406Sopenharmony_ci   descriptors.  */
4630141cc406Sopenharmony_ci
4631141cc406Sopenharmony_cistatic void
4632141cc406Sopenharmony_cioutput_data (Mustek_Scanner * s, FILE * fp,
4633141cc406Sopenharmony_ci	     SANE_Byte * data, SANE_Int lines_per_buffer, SANE_Int bpl,
4634141cc406Sopenharmony_ci	     SANE_Byte * extra)
4635141cc406Sopenharmony_ci{
4636141cc406Sopenharmony_ci  SANE_Byte *ptr, *ptr_end;
4637141cc406Sopenharmony_ci  SANE_Int y, num_lines;
4638141cc406Sopenharmony_ci
4639141cc406Sopenharmony_ci  DBG (5, "output_data: data=%p, lpb=%d, bpl=%d, extra=%p\n",
4640141cc406Sopenharmony_ci       (void *) data, lines_per_buffer, bpl, (void *) extra);
4641141cc406Sopenharmony_ci
4642141cc406Sopenharmony_ci  /* convert to pixel-interleaved format: */
4643141cc406Sopenharmony_ci  if ((s->mode & MUSTEK_MODE_COLOR)
4644141cc406Sopenharmony_ci      && !(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
4645141cc406Sopenharmony_ci    {
4646141cc406Sopenharmony_ci      num_lines = lines_per_buffer;
4647141cc406Sopenharmony_ci
4648141cc406Sopenharmony_ci      /* need to correct for distance between r/g/b sensors: */
4649141cc406Sopenharmony_ci      if (s->hw->flags & MUSTEK_FLAG_PRO)
4650141cc406Sopenharmony_ci	fix_line_distance_pro (s, num_lines, bpl, data, extra);
4651141cc406Sopenharmony_ci      else if (s->hw->flags & MUSTEK_FLAG_SE)
4652141cc406Sopenharmony_ci	{
4653141cc406Sopenharmony_ci	  num_lines = fix_line_distance_se (s, num_lines, bpl, data, extra);
4654141cc406Sopenharmony_ci	}
4655141cc406Sopenharmony_ci      else if (s->hw->flags & MUSTEK_FLAG_N)
4656141cc406Sopenharmony_ci	{
4657141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_LD_N2)
4658141cc406Sopenharmony_ci	    num_lines = fix_line_distance_n_2 (s, num_lines, bpl, data,
4659141cc406Sopenharmony_ci					       extra);
4660141cc406Sopenharmony_ci	  else
4661141cc406Sopenharmony_ci	    num_lines = fix_line_distance_n_1 (s, num_lines, bpl, data,
4662141cc406Sopenharmony_ci					       extra);
4663141cc406Sopenharmony_ci	}
4664141cc406Sopenharmony_ci      else if ((s->hw->flags & MUSTEK_FLAG_LD_BLOCK)
4665141cc406Sopenharmony_ci	       && (s->ld.max_value != 0))
4666141cc406Sopenharmony_ci	{
4667141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_PARAGON_1)
4668141cc406Sopenharmony_ci	    num_lines = fix_line_distance_block (s, num_lines, bpl, data,
4669141cc406Sopenharmony_ci						 extra, s->hw->lines);
4670141cc406Sopenharmony_ci	  else
4671141cc406Sopenharmony_ci	    num_lines = fix_line_distance_block (s, num_lines, bpl, data,
4672141cc406Sopenharmony_ci						 extra,
4673141cc406Sopenharmony_ci						 s->hw->lines_per_block);
4674141cc406Sopenharmony_ci	}
4675141cc406Sopenharmony_ci      else if (!(s->hw->flags & MUSTEK_FLAG_LD_NONE)
4676141cc406Sopenharmony_ci	       && (s->ld.max_value != 0))
4677141cc406Sopenharmony_ci	fix_line_distance_normal (s, num_lines, bpl, data, extra);
4678141cc406Sopenharmony_ci      else
4679141cc406Sopenharmony_ci	num_lines = fix_line_distance_none (s, num_lines, bpl, data, extra);
4680141cc406Sopenharmony_ci
4681141cc406Sopenharmony_ci      if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0)
4682141cc406Sopenharmony_ci	{
4683141cc406Sopenharmony_ci	  /* need to revert line direction */
4684141cc406Sopenharmony_ci	  SANE_Int line_number;
4685141cc406Sopenharmony_ci	  SANE_Int byte_number;
4686141cc406Sopenharmony_ci
4687141cc406Sopenharmony_ci	  DBG (5, "output_data: ADF found, mirroring lines\n");
4688141cc406Sopenharmony_ci	  for (line_number = 0; line_number < num_lines; line_number++)
4689141cc406Sopenharmony_ci	    {
4690141cc406Sopenharmony_ci	      for (byte_number = bpl - 3; byte_number >= 0; byte_number -= 3)
4691141cc406Sopenharmony_ci		{
4692141cc406Sopenharmony_ci		  fputc (*(extra + line_number * bpl + byte_number), fp);
4693141cc406Sopenharmony_ci		  fputc (*(extra + line_number * bpl + byte_number + 1), fp);
4694141cc406Sopenharmony_ci		  fputc (*(extra + line_number * bpl + byte_number + 2), fp);
4695141cc406Sopenharmony_ci		}
4696141cc406Sopenharmony_ci	    }
4697141cc406Sopenharmony_ci	}
4698141cc406Sopenharmony_ci      else
4699141cc406Sopenharmony_ci	fwrite (extra, num_lines, s->params.bytes_per_line, fp);
4700141cc406Sopenharmony_ci    }
4701141cc406Sopenharmony_ci  else
4702141cc406Sopenharmony_ci    {
4703141cc406Sopenharmony_ci      DBG (5, "output_data: write %d lpb; %d bpl\n", lines_per_buffer, bpl);
4704141cc406Sopenharmony_ci      /* Scale x-resolution above 1/2 of the maximum resolution for
4705141cc406Sopenharmony_ci         SE and Pro scanners */
4706141cc406Sopenharmony_ci      if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) &&
4707141cc406Sopenharmony_ci	  (s->val[OPT_RESOLUTION].w > (s->hw->dpi_range.max / 2)))
4708141cc406Sopenharmony_ci	{
4709141cc406Sopenharmony_ci	  SANE_Int x;
4710141cc406Sopenharmony_ci	  SANE_Int half_res = SANE_UNFIX (s->hw->dpi_range.max) / 2;
4711141cc406Sopenharmony_ci	  SANE_Int res = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
4712141cc406Sopenharmony_ci	  SANE_Int res_counter;
4713141cc406Sopenharmony_ci	  SANE_Int enlarged_x;
4714141cc406Sopenharmony_ci
4715141cc406Sopenharmony_ci	  DBG (5, "output_data: enlarge lines from %d bpl to %d bpl\n",
4716141cc406Sopenharmony_ci	       s->hw->bpl, s->params.bytes_per_line);
4717141cc406Sopenharmony_ci
4718141cc406Sopenharmony_ci	  for (y = 0; y < lines_per_buffer; y++)
4719141cc406Sopenharmony_ci	    {
4720141cc406Sopenharmony_ci	      SANE_Byte byte = 0;
4721141cc406Sopenharmony_ci
4722141cc406Sopenharmony_ci	      x = 0;
4723141cc406Sopenharmony_ci	      res_counter = 0;
4724141cc406Sopenharmony_ci	      enlarged_x = 0;
4725141cc406Sopenharmony_ci
4726141cc406Sopenharmony_ci	      while (enlarged_x < s->params.pixels_per_line)
4727141cc406Sopenharmony_ci		{
4728141cc406Sopenharmony_ci		  if (s->mode & MUSTEK_MODE_GRAY)
4729141cc406Sopenharmony_ci		    {
4730141cc406Sopenharmony_ci		      fputc (*(data + y * bpl + x), fp);
4731141cc406Sopenharmony_ci		      res_counter += half_res;
4732141cc406Sopenharmony_ci		      if (res_counter >= half_res)
4733141cc406Sopenharmony_ci			{
4734141cc406Sopenharmony_ci			  res_counter -= res;
4735141cc406Sopenharmony_ci			  x++;
4736141cc406Sopenharmony_ci			}
4737141cc406Sopenharmony_ci		      enlarged_x++;
4738141cc406Sopenharmony_ci		    }
4739141cc406Sopenharmony_ci		  else		/* lineart */
4740141cc406Sopenharmony_ci		    {
4741141cc406Sopenharmony_ci		      /* need to invert image because of funny SANE 1-bit image
4742141cc406Sopenharmony_ci			 polarity */
4743141cc406Sopenharmony_ci		      if (*(data + x / 8 + y * bpl) & (1 << (7 - (x % 8))))
4744141cc406Sopenharmony_ci			byte |= 1 << (7 - (enlarged_x % 8));
4745141cc406Sopenharmony_ci
4746141cc406Sopenharmony_ci		      if ((enlarged_x % 8) == 7)
4747141cc406Sopenharmony_ci			{
4748141cc406Sopenharmony_ci			  fputc (~byte, fp);	/* invert image */
4749141cc406Sopenharmony_ci			  byte = 0;
4750141cc406Sopenharmony_ci			}
4751141cc406Sopenharmony_ci		      res_counter += half_res;
4752141cc406Sopenharmony_ci		      if (res_counter >= half_res)
4753141cc406Sopenharmony_ci			{
4754141cc406Sopenharmony_ci			  res_counter -= res;
4755141cc406Sopenharmony_ci			  x++;
4756141cc406Sopenharmony_ci			}
4757141cc406Sopenharmony_ci		      enlarged_x++;
4758141cc406Sopenharmony_ci		    }
4759141cc406Sopenharmony_ci		}
4760141cc406Sopenharmony_ci	    }
4761141cc406Sopenharmony_ci	}
4762141cc406Sopenharmony_ci      else			/* lineart, gray or halftone (nothing to scale) */
4763141cc406Sopenharmony_ci	{
4764141cc406Sopenharmony_ci	  if ((s->mode & MUSTEK_MODE_LINEART)
4765141cc406Sopenharmony_ci	      || (s->mode & MUSTEK_MODE_HALFTONE))
4766141cc406Sopenharmony_ci	    {
4767141cc406Sopenharmony_ci	      /* need to invert image because of funny SANE 1-bit image
4768141cc406Sopenharmony_ci		 polarity */
4769141cc406Sopenharmony_ci	      ptr = data;
4770141cc406Sopenharmony_ci	      ptr_end = ptr + lines_per_buffer * bpl;
4771141cc406Sopenharmony_ci
4772141cc406Sopenharmony_ci	      if (strcmp (s->val[OPT_SOURCE].s,
4773141cc406Sopenharmony_ci			  "Automatic Document Feeder") == 0)
4774141cc406Sopenharmony_ci		{
4775141cc406Sopenharmony_ci		  while (ptr != ptr_end)
4776141cc406Sopenharmony_ci		    {
4777141cc406Sopenharmony_ci		      (*ptr) = ~(*ptr);
4778141cc406Sopenharmony_ci		      ptr++;
4779141cc406Sopenharmony_ci		      /* need to revert bit direction */
4780141cc406Sopenharmony_ci		      *ptr = ((*ptr & 0x80) >> 7) + ((*ptr & 0x40) >> 5)
4781141cc406Sopenharmony_ci			+ ((*ptr & 0x20) >> 3) + ((*ptr & 0x10) >> 1)
4782141cc406Sopenharmony_ci			+ ((*ptr & 0x08) << 1) + ((*ptr & 0x04) << 3)
4783141cc406Sopenharmony_ci			+ ((*ptr & 0x02) << 5) + ((*ptr & 0x01) << 7);
4784141cc406Sopenharmony_ci		    }
4785141cc406Sopenharmony_ci		}
4786141cc406Sopenharmony_ci	      else
4787141cc406Sopenharmony_ci		while (ptr != ptr_end)
4788141cc406Sopenharmony_ci		  {
4789141cc406Sopenharmony_ci		    (*ptr) = ~(*ptr);
4790141cc406Sopenharmony_ci		    ptr++;
4791141cc406Sopenharmony_ci		  }
4792141cc406Sopenharmony_ci	    }
4793141cc406Sopenharmony_ci	  if (strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0)
4794141cc406Sopenharmony_ci	    {
4795141cc406Sopenharmony_ci	      /* need to revert line direction */
4796141cc406Sopenharmony_ci	      SANE_Int line_number;
4797141cc406Sopenharmony_ci	      SANE_Int byte_number;
4798141cc406Sopenharmony_ci
4799141cc406Sopenharmony_ci	      DBG (5, "output_data: ADF found, mirroring lines\n");
4800141cc406Sopenharmony_ci	      for (line_number = 0; line_number < lines_per_buffer;
4801141cc406Sopenharmony_ci		   line_number++)
4802141cc406Sopenharmony_ci		{
4803141cc406Sopenharmony_ci		  for (byte_number = bpl - 1; byte_number >= 0; byte_number--)
4804141cc406Sopenharmony_ci		    {
4805141cc406Sopenharmony_ci		      fputc (*(data + line_number * bpl + byte_number), fp);
4806141cc406Sopenharmony_ci		    }
4807141cc406Sopenharmony_ci		}
4808141cc406Sopenharmony_ci	    }
4809141cc406Sopenharmony_ci	  else
4810141cc406Sopenharmony_ci	    {
4811141cc406Sopenharmony_ci	      fwrite (data, lines_per_buffer, bpl, fp);
4812141cc406Sopenharmony_ci	    }
4813141cc406Sopenharmony_ci	}
4814141cc406Sopenharmony_ci    }
4815141cc406Sopenharmony_ci  DBG (5, "output_data: end\n");
4816141cc406Sopenharmony_ci}
4817141cc406Sopenharmony_ci
4818141cc406Sopenharmony_cistatic void
4819141cc406Sopenharmony_cisigterm_handler (int signal)
4820141cc406Sopenharmony_ci{
4821141cc406Sopenharmony_ci  DBG (4,
4822141cc406Sopenharmony_ci       "sigterm_handler: started, signal is %d, starting sanei_scsi_req_flush_all()\n",
4823141cc406Sopenharmony_ci       signal);
4824141cc406Sopenharmony_ci  sanei_scsi_req_flush_all ();	/* flush SCSI queue */
4825141cc406Sopenharmony_ci  DBG (4,
4826141cc406Sopenharmony_ci       "sigterm_handler: sanei_scsi_req_flush_all() finisheshed, _exiting()\n");
4827141cc406Sopenharmony_ci  _exit (SANE_STATUS_GOOD);
4828141cc406Sopenharmony_ci}
4829141cc406Sopenharmony_ci
4830141cc406Sopenharmony_ci
4831141cc406Sopenharmony_cistatic SANE_Int
4832141cc406Sopenharmony_cireader_process (void *data)
4833141cc406Sopenharmony_ci{
4834141cc406Sopenharmony_ci  Mustek_Scanner *s = (Mustek_Scanner *) data;
4835141cc406Sopenharmony_ci  SANE_Int lines_per_buffer, bpl;
4836141cc406Sopenharmony_ci  SANE_Byte *extra = 0, *ptr;
4837141cc406Sopenharmony_ci  sigset_t sigterm_set;
4838141cc406Sopenharmony_ci  struct SIGACTION act;
4839141cc406Sopenharmony_ci  SANE_Status status;
4840141cc406Sopenharmony_ci  FILE *fp;
4841141cc406Sopenharmony_ci  int fd = s->reader_fds;
4842141cc406Sopenharmony_ci  SANE_Int buffernumber = 0;
4843141cc406Sopenharmony_ci  SANE_Int buffer_count, max_buffers;
4844141cc406Sopenharmony_ci  struct
4845141cc406Sopenharmony_ci  {
4846141cc406Sopenharmony_ci    void *id;			/* scsi queue id */
4847141cc406Sopenharmony_ci    SANE_Byte *data;		/* data buffer */
4848141cc406Sopenharmony_ci    SANE_Byte *command;		/* command buffer */
4849141cc406Sopenharmony_ci    SANE_Int lines;		/* # lines in buffer */
4850141cc406Sopenharmony_ci    size_t num_read;		/* # of bytes read (return value) */
4851141cc406Sopenharmony_ci    SANE_Int bank;		/* needed by SE models */
4852141cc406Sopenharmony_ci    SANE_Bool ready;		/* ready to send to application? */
4853141cc406Sopenharmony_ci    SANE_Bool finished;		/* block is finished */
4854141cc406Sopenharmony_ci  }
4855141cc406Sopenharmony_ci  bstat[2];
4856141cc406Sopenharmony_ci
4857141cc406Sopenharmony_ci  DBG (3, "reader_process: started\n");
4858141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
4859141cc406Sopenharmony_ci    {
4860141cc406Sopenharmony_ci      DBG (4, "reader_process: using fork ()\n");
4861141cc406Sopenharmony_ci      close (s->pipe);
4862141cc406Sopenharmony_ci      s->pipe = -1;
4863141cc406Sopenharmony_ci    }
4864141cc406Sopenharmony_ci  else
4865141cc406Sopenharmony_ci    {
4866141cc406Sopenharmony_ci      DBG (4, "reader_process: using threads\n");
4867141cc406Sopenharmony_ci    }
4868141cc406Sopenharmony_ci
4869141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
4870141cc406Sopenharmony_ci    {
4871141cc406Sopenharmony_ci      /* ignore SIGTERM while writing SCSI commands */
4872141cc406Sopenharmony_ci      sigemptyset (&sigterm_set);
4873141cc406Sopenharmony_ci      sigaddset (&sigterm_set, SIGTERM);
4874141cc406Sopenharmony_ci
4875141cc406Sopenharmony_ci      /* call our sigterm handler to clean up ongoing SCSI requests */
4876141cc406Sopenharmony_ci      memset (&act, 0, sizeof (act));
4877141cc406Sopenharmony_ci      act.sa_handler = sigterm_handler;
4878141cc406Sopenharmony_ci      sigaction (SIGTERM, &act, 0);
4879141cc406Sopenharmony_ci    }
4880141cc406Sopenharmony_ci
4881141cc406Sopenharmony_ci  if (disable_double_buffering)
4882141cc406Sopenharmony_ci    DBG (3, "reader_process: disable_double_buffering is set, this may be "
4883141cc406Sopenharmony_ci	 "slow\n");
4884141cc406Sopenharmony_ci
4885141cc406Sopenharmony_ci  fp = fdopen (fd, "w");
4886141cc406Sopenharmony_ci  if (!fp)
4887141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
4888141cc406Sopenharmony_ci
4889141cc406Sopenharmony_ci  s->total_lines = 0;
4890141cc406Sopenharmony_ci  bpl = s->hw->bpl;
4891141cc406Sopenharmony_ci
4892141cc406Sopenharmony_ci  /* buffer size is scanner dependent */
4893141cc406Sopenharmony_ci  lines_per_buffer = s->hw->buffer_size / bpl / 2;
4894141cc406Sopenharmony_ci
4895141cc406Sopenharmony_ci  if (strip_height > 0.0)
4896141cc406Sopenharmony_ci    {
4897141cc406Sopenharmony_ci      SANE_Int max_lines;
4898141cc406Sopenharmony_ci      double dpi;
4899141cc406Sopenharmony_ci
4900141cc406Sopenharmony_ci      dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
4901141cc406Sopenharmony_ci      max_lines = (int) (strip_height * dpi + 0.5);
4902141cc406Sopenharmony_ci
4903141cc406Sopenharmony_ci      if (lines_per_buffer > max_lines)
4904141cc406Sopenharmony_ci	{
4905141cc406Sopenharmony_ci	  DBG (2, "reader_process: limiting strip height to %g inches "
4906141cc406Sopenharmony_ci	       "(%d lines)\n", strip_height, max_lines);
4907141cc406Sopenharmony_ci	  lines_per_buffer = max_lines;
4908141cc406Sopenharmony_ci	}
4909141cc406Sopenharmony_ci    }
4910141cc406Sopenharmony_ci
4911141cc406Sopenharmony_ci  if (!lines_per_buffer)
4912141cc406Sopenharmony_ci    {
4913141cc406Sopenharmony_ci      DBG (1, "reader_process: bpl (%d) > SCSI buffer size / 2 (%d)\n",
4914141cc406Sopenharmony_ci	   bpl, s->hw->buffer_size / 2);
4915141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;	/* resolution is too high */
4916141cc406Sopenharmony_ci    }
4917141cc406Sopenharmony_ci
4918141cc406Sopenharmony_ci  DBG (4, "reader_process: %d lines per buffer, %d bytes per line, "
4919141cc406Sopenharmony_ci       "%d bytes per buffer\n", lines_per_buffer, bpl,
4920141cc406Sopenharmony_ci       lines_per_buffer * bpl);
4921141cc406Sopenharmony_ci
4922141cc406Sopenharmony_ci  bstat[0].data = malloc (2 * lines_per_buffer * (long) bpl);
4923141cc406Sopenharmony_ci  if (!bstat[0].data)
4924141cc406Sopenharmony_ci    {
4925141cc406Sopenharmony_ci      DBG (1, "reader_process: failed to malloc %ld bytes for data buffer\n",
4926141cc406Sopenharmony_ci	   lines_per_buffer * (long) bpl);
4927141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
4928141cc406Sopenharmony_ci    }
4929141cc406Sopenharmony_ci  bstat[1].data = bstat[0].data + lines_per_buffer * (long) bpl;
4930141cc406Sopenharmony_ci
4931141cc406Sopenharmony_ci  bstat[0].command = malloc (2 * 10);
4932141cc406Sopenharmony_ci  if (!bstat[0].command)
4933141cc406Sopenharmony_ci    {
4934141cc406Sopenharmony_ci      DBG (1,
4935141cc406Sopenharmony_ci	   "reader_process: failed to malloc %d bytes for command buffer\n",
4936141cc406Sopenharmony_ci	   2 * 10);
4937141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
4938141cc406Sopenharmony_ci    }
4939141cc406Sopenharmony_ci  bstat[1].command = bstat[0].command + 10;
4940141cc406Sopenharmony_ci
4941141cc406Sopenharmony_ci  /* Touch all pages of the buffer to fool the memory management. */
4942141cc406Sopenharmony_ci  ptr = bstat[0].data + 2 * lines_per_buffer * (long) bpl - 1;
4943141cc406Sopenharmony_ci  while (ptr >= bstat[0].data)
4944141cc406Sopenharmony_ci    {
4945141cc406Sopenharmony_ci      *ptr = 0x00;
4946141cc406Sopenharmony_ci      ptr -= 256;
4947141cc406Sopenharmony_ci    }
4948141cc406Sopenharmony_ci
4949141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
4950141cc406Sopenharmony_ci    {
4951141cc406Sopenharmony_ci      /* get temporary buffer for line-distance correction and/or bit
4952141cc406Sopenharmony_ci         expansion. For some scanners more space is needed because the
4953141cc406Sopenharmony_ci         data must be read in as single big block (cut up into pieces
4954141cc406Sopenharmony_ci         of lines_per_buffer). This requires that the line distance
4955141cc406Sopenharmony_ci         correction continues on every call exactly where it stopped
4956141cc406Sopenharmony_ci         if the image shall be reconstructed without any stripes. */
4957141cc406Sopenharmony_ci
4958141cc406Sopenharmony_ci      extra = malloc ((lines_per_buffer + MAX_LINE_DIST)
4959141cc406Sopenharmony_ci		      * (long) s->params.bytes_per_line);
4960141cc406Sopenharmony_ci      if (!extra)
4961141cc406Sopenharmony_ci	{
4962141cc406Sopenharmony_ci	  DBG (1, "reader_process: failed to malloc extra buffer\n");
4963141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
4964141cc406Sopenharmony_ci	}
4965141cc406Sopenharmony_ci    }
4966141cc406Sopenharmony_ci
4967141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_N)
4968141cc406Sopenharmony_ci    {
4969141cc406Sopenharmony_ci      /* reacquire port access rights (lost because of fork()): */
4970141cc406Sopenharmony_ci      sanei_ab306_get_io_privilege (s->fd);
4971141cc406Sopenharmony_ci    }
4972141cc406Sopenharmony_ci
4973141cc406Sopenharmony_ci  if ((s->hw->flags & MUSTEK_FLAG_N) || (s->hw->flags & MUSTEK_FLAG_LD_BLOCK))
4974141cc406Sopenharmony_ci    {
4975141cc406Sopenharmony_ci      /* reset counter of line number for line-dictance correction */
4976141cc406Sopenharmony_ci      s->ld.ld_line = 0;
4977141cc406Sopenharmony_ci    }
4978141cc406Sopenharmony_ci
4979141cc406Sopenharmony_ci  max_buffers = s->hw->max_block_buffer_size / (lines_per_buffer * bpl);
4980141cc406Sopenharmony_ci  if (max_buffers < 1)
4981141cc406Sopenharmony_ci    {
4982141cc406Sopenharmony_ci      DBG (1, "reader_process: buffersize > blocksize!\n");
4983141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
4984141cc406Sopenharmony_ci    }
4985141cc406Sopenharmony_ci  DBG (4, "reader_process: limiting block read to %d buffers (%d lines)\n",
4986141cc406Sopenharmony_ci       max_buffers, MIN (s->hw->lines, (max_buffers * lines_per_buffer)));
4987141cc406Sopenharmony_ci
4988141cc406Sopenharmony_ci  while (s->line < s->hw->lines)
4989141cc406Sopenharmony_ci    {
4990141cc406Sopenharmony_ci      s->hw->lines_per_block =
4991141cc406Sopenharmony_ci	MIN (s->hw->lines - s->line, (max_buffers * lines_per_buffer));
4992141cc406Sopenharmony_ci      status = dev_block_read_start (s, s->hw->lines_per_block);
4993141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
4994141cc406Sopenharmony_ci	return status;
4995141cc406Sopenharmony_ci
4996141cc406Sopenharmony_ci      for (buffernumber = 0; buffernumber < 2; buffernumber++)
4997141cc406Sopenharmony_ci	{
4998141cc406Sopenharmony_ci	  bstat[buffernumber].ready = SANE_FALSE;
4999141cc406Sopenharmony_ci	  bstat[buffernumber].finished = SANE_FALSE;
5000141cc406Sopenharmony_ci	}
5001141cc406Sopenharmony_ci      buffer_count = 0;
5002141cc406Sopenharmony_ci      buffernumber = 0;
5003141cc406Sopenharmony_ci
5004141cc406Sopenharmony_ci      while (1)
5005141cc406Sopenharmony_ci	{
5006141cc406Sopenharmony_ci	  /* omit reading first two buffers (not yet ready) */
5007141cc406Sopenharmony_ci	  if (bstat[buffernumber].ready == SANE_TRUE)
5008141cc406Sopenharmony_ci	    {
5009141cc406Sopenharmony_ci	      DBG (4, "reader_process: buffer %d: waiting for request to be "
5010141cc406Sopenharmony_ci		   "ready\n", buffernumber + 1);
5011141cc406Sopenharmony_ci	      status = dev_req_wait (bstat[buffernumber].id);
5012141cc406Sopenharmony_ci	      if (status == SANE_STATUS_GOOD)
5013141cc406Sopenharmony_ci		{
5014141cc406Sopenharmony_ci		  DBG (4, "reader_process: buffer %d is ready, wanted %d, "
5015141cc406Sopenharmony_ci		       "got %ld bytes\n", buffernumber + 1,
5016141cc406Sopenharmony_ci		       bstat[buffernumber].lines * bpl,
5017141cc406Sopenharmony_ci		       (long int) bstat[buffernumber].num_read);
5018141cc406Sopenharmony_ci		}
5019141cc406Sopenharmony_ci	      else
5020141cc406Sopenharmony_ci		{
5021141cc406Sopenharmony_ci		  DBG (1, "reader_process: failed to read data, status: %s, "
5022141cc406Sopenharmony_ci		       "buffer: %d\n", sane_strstatus (status),
5023141cc406Sopenharmony_ci		       buffernumber + 1);
5024141cc406Sopenharmony_ci		  if (status == SANE_STATUS_NO_MEM)
5025141cc406Sopenharmony_ci		    {
5026141cc406Sopenharmony_ci		      DBG (1,
5027141cc406Sopenharmony_ci			   "Probably the size of the kernel SCSI buffer is "
5028141cc406Sopenharmony_ci			   "too small for the\n         selected buffersize "
5029141cc406Sopenharmony_ci			   "in mustek.conf. Either decrease "
5030141cc406Sopenharmony_ci			   "buffersize in\n         mustek.conf to e.g. 32, "
5031141cc406Sopenharmony_ci			   "increase SG_BIG_BUF in kernel to 130560, "
5032141cc406Sopenharmony_ci			   "or\n         use SANE_SG_BUFFERSIZE variable. "
5033141cc406Sopenharmony_ci			   "See man sane-scsi and README for\n         "
5034141cc406Sopenharmony_ci			   "details.\n");
5035141cc406Sopenharmony_ci		    }
5036141cc406Sopenharmony_ci		  return status;
5037141cc406Sopenharmony_ci		}
5038141cc406Sopenharmony_ci
5039141cc406Sopenharmony_ci	      DBG (4, "reader_process: buffer %d: sending %ld bytes to "
5040141cc406Sopenharmony_ci		   "output_data\n", buffernumber + 1,
5041141cc406Sopenharmony_ci		   (long int) bstat[buffernumber].num_read);
5042141cc406Sopenharmony_ci	      output_data (s, fp, bstat[buffernumber].data,
5043141cc406Sopenharmony_ci			   bstat[buffernumber].lines, bpl, extra);
5044141cc406Sopenharmony_ci	      if (bstat[buffernumber].finished)
5045141cc406Sopenharmony_ci		break;		/* everything written; exit loop */
5046141cc406Sopenharmony_ci	    }
5047141cc406Sopenharmony_ci	  if (disable_double_buffering)
5048141cc406Sopenharmony_ci	    {
5049141cc406Sopenharmony_ci	      /* Enter only one buffer at once */
5050141cc406Sopenharmony_ci	      if (buffernumber == 1)
5051141cc406Sopenharmony_ci		buffernumber = 0;
5052141cc406Sopenharmony_ci	      else
5053141cc406Sopenharmony_ci		buffernumber = 1;
5054141cc406Sopenharmony_ci	    }
5055141cc406Sopenharmony_ci
5056141cc406Sopenharmony_ci	  /* enter read requests only if data left */
5057141cc406Sopenharmony_ci	  if ((s->line < s->hw->lines) && (buffer_count < max_buffers))
5058141cc406Sopenharmony_ci	    {
5059141cc406Sopenharmony_ci	      if (s->line + lines_per_buffer >= s->hw->lines)
5060141cc406Sopenharmony_ci		{
5061141cc406Sopenharmony_ci		  /* do the last few lines: */
5062141cc406Sopenharmony_ci		  bstat[buffernumber].lines = s->hw->lines - s->line;
5063141cc406Sopenharmony_ci		  bstat[buffernumber].bank = 0x01;
5064141cc406Sopenharmony_ci		  bstat[buffernumber].finished = SANE_TRUE;
5065141cc406Sopenharmony_ci		}
5066141cc406Sopenharmony_ci	      else
5067141cc406Sopenharmony_ci		{
5068141cc406Sopenharmony_ci		  bstat[buffernumber].lines = lines_per_buffer;
5069141cc406Sopenharmony_ci		  bstat[buffernumber].bank = 0x00;
5070141cc406Sopenharmony_ci		}
5071141cc406Sopenharmony_ci
5072141cc406Sopenharmony_ci	      if ((buffer_count + 1) >= max_buffers)
5073141cc406Sopenharmony_ci		bstat[buffernumber].finished = SANE_TRUE;
5074141cc406Sopenharmony_ci
5075141cc406Sopenharmony_ci	      s->line += bstat[buffernumber].lines;
5076141cc406Sopenharmony_ci	      bstat[buffernumber].ready = SANE_TRUE;
5077141cc406Sopenharmony_ci
5078141cc406Sopenharmony_ci	      buffer_count++;
5079141cc406Sopenharmony_ci
5080141cc406Sopenharmony_ci	      DBG (4,
5081141cc406Sopenharmony_ci		   "reader_process: buffer %d: entering read request for %d "
5082141cc406Sopenharmony_ci		   "bytes (buffer %d)\n", buffernumber + 1,
5083141cc406Sopenharmony_ci		   bstat[buffernumber].lines * bpl, buffer_count);
5084141cc406Sopenharmony_ci	      sigprocmask (SIG_BLOCK, &sigterm_set, 0);
5085141cc406Sopenharmony_ci	      status = dev_read_req_enter (s, bstat[buffernumber].data,
5086141cc406Sopenharmony_ci					   bstat[buffernumber].lines, bpl,
5087141cc406Sopenharmony_ci					   &bstat[buffernumber].num_read,
5088141cc406Sopenharmony_ci					   &bstat[buffernumber].id,
5089141cc406Sopenharmony_ci					   bstat[buffernumber].bank,
5090141cc406Sopenharmony_ci					   bstat[buffernumber].command);
5091141cc406Sopenharmony_ci	      sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
5092141cc406Sopenharmony_ci
5093141cc406Sopenharmony_ci
5094141cc406Sopenharmony_ci	      if (status == SANE_STATUS_GOOD)
5095141cc406Sopenharmony_ci		{
5096141cc406Sopenharmony_ci		  DBG (5, "reader_process: buffer %d: entered (line %d of %d,"
5097141cc406Sopenharmony_ci		       " buffer %d)\n", buffernumber + 1, s->line,
5098141cc406Sopenharmony_ci		       s->hw->lines, buffer_count);
5099141cc406Sopenharmony_ci		}
5100141cc406Sopenharmony_ci	      else
5101141cc406Sopenharmony_ci		{
5102141cc406Sopenharmony_ci		  DBG (1, "reader_process: buffer %d: failed to enter read "
5103141cc406Sopenharmony_ci		       "request, status: %s\n", buffernumber + 1,
5104141cc406Sopenharmony_ci		       sane_strstatus (status));
5105141cc406Sopenharmony_ci		  return status;
5106141cc406Sopenharmony_ci		}
5107141cc406Sopenharmony_ci	    }
5108141cc406Sopenharmony_ci	  if (!disable_double_buffering)
5109141cc406Sopenharmony_ci	    {
5110141cc406Sopenharmony_ci	      if (buffernumber == 1)
5111141cc406Sopenharmony_ci		buffernumber = 0;
5112141cc406Sopenharmony_ci	      else
5113141cc406Sopenharmony_ci		buffernumber = 1;
5114141cc406Sopenharmony_ci	    }
5115141cc406Sopenharmony_ci	  /* This is said to fix the scanner hangs that reportedly show on
5116141cc406Sopenharmony_ci	     some MFS-12000SP scanners.  */
5117141cc406Sopenharmony_ci	  if (s->mode == 0 && (s->hw->flags & MUSTEK_FLAG_LINEART_FIX))
5118141cc406Sopenharmony_ci	    usleep (200000);
5119141cc406Sopenharmony_ci	}
5120141cc406Sopenharmony_ci    }
5121141cc406Sopenharmony_ci
5122141cc406Sopenharmony_ci  fclose (fp);
5123141cc406Sopenharmony_ci  free (bstat[0].data);
5124141cc406Sopenharmony_ci  if (s->ld.buf[0])
5125141cc406Sopenharmony_ci    free (s->ld.buf[0]);
5126141cc406Sopenharmony_ci  s->ld.buf[0] = NULL;
5127141cc406Sopenharmony_ci  if (extra)
5128141cc406Sopenharmony_ci    free (extra);
5129141cc406Sopenharmony_ci  close (fd);
5130141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5131141cc406Sopenharmony_ci}
5132141cc406Sopenharmony_ci
5133141cc406Sopenharmony_cistatic SANE_Status
5134141cc406Sopenharmony_ciattach_one_device (SANE_String_Const devname)
5135141cc406Sopenharmony_ci{
5136141cc406Sopenharmony_ci  Mustek_Device *dev;
5137141cc406Sopenharmony_ci
5138141cc406Sopenharmony_ci  attach (devname, &dev, SANE_FALSE);
5139141cc406Sopenharmony_ci  if (dev)
5140141cc406Sopenharmony_ci    {
5141141cc406Sopenharmony_ci      /* Keep track of newly attached devices so we can set options as
5142141cc406Sopenharmony_ci         necessary.  */
5143141cc406Sopenharmony_ci      if (new_dev_len >= new_dev_alloced)
5144141cc406Sopenharmony_ci	{
5145141cc406Sopenharmony_ci	  new_dev_alloced += 4;
5146141cc406Sopenharmony_ci	  if (new_dev)
5147141cc406Sopenharmony_ci	    new_dev =
5148141cc406Sopenharmony_ci	      realloc (new_dev, new_dev_alloced * sizeof (new_dev[0]));
5149141cc406Sopenharmony_ci	  else
5150141cc406Sopenharmony_ci	    new_dev = malloc (new_dev_alloced * sizeof (new_dev[0]));
5151141cc406Sopenharmony_ci	  if (!new_dev)
5152141cc406Sopenharmony_ci	    {
5153141cc406Sopenharmony_ci	      DBG (1, "attach_one_device: out of memory\n");
5154141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
5155141cc406Sopenharmony_ci	    }
5156141cc406Sopenharmony_ci	}
5157141cc406Sopenharmony_ci      new_dev[new_dev_len++] = dev;
5158141cc406Sopenharmony_ci    }
5159141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5160141cc406Sopenharmony_ci}
5161141cc406Sopenharmony_ci
5162141cc406Sopenharmony_ci/**************************************************************************/
5163141cc406Sopenharmony_ci/*                            SANE API calls                              */
5164141cc406Sopenharmony_ci/**************************************************************************/
5165141cc406Sopenharmony_ci
5166141cc406Sopenharmony_ciSANE_Status
5167141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
5168141cc406Sopenharmony_ci{
5169141cc406Sopenharmony_ci  SANE_Char line[PATH_MAX], *word, *end;
5170141cc406Sopenharmony_ci  SANE_String_Const cp;
5171141cc406Sopenharmony_ci  SANE_Int linenumber;
5172141cc406Sopenharmony_ci  FILE *fp;
5173141cc406Sopenharmony_ci
5174141cc406Sopenharmony_ci  DBG_INIT ();
5175141cc406Sopenharmony_ci
5176141cc406Sopenharmony_ci  sanei_thread_init ();
5177141cc406Sopenharmony_ci
5178141cc406Sopenharmony_ci#ifdef DBG_LEVEL
5179141cc406Sopenharmony_ci  debug_level = DBG_LEVEL;
5180141cc406Sopenharmony_ci#else
5181141cc406Sopenharmony_ci  debug_level = 0;
5182141cc406Sopenharmony_ci#endif
5183141cc406Sopenharmony_ci
5184141cc406Sopenharmony_ci  DBG (2, "SANE mustek backend version %d.%d build %d from %s\n", SANE_CURRENT_MAJOR,
5185141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
5186141cc406Sopenharmony_ci
5187141cc406Sopenharmony_ci  if (version_code)
5188141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
5189141cc406Sopenharmony_ci
5190141cc406Sopenharmony_ci  DBG (5, "sane_init: authorize %s null\n", authorize ? "!=" : "==");
5191141cc406Sopenharmony_ci
5192141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
5193141cc406Sopenharmony_ci  DBG (5, "sane_init: using sanei_scsi_open_extended\n");
5194141cc406Sopenharmony_ci#else
5195141cc406Sopenharmony_ci  DBG (5, "sane_init: using sanei_scsi_open with buffer size = %d bytes\n",
5196141cc406Sopenharmony_ci       sanei_scsi_max_request_size);
5197141cc406Sopenharmony_ci#endif
5198141cc406Sopenharmony_ci
5199141cc406Sopenharmony_ci  num_devices = 0;
5200141cc406Sopenharmony_ci  force_wait = SANE_FALSE;
5201141cc406Sopenharmony_ci  disable_double_buffering = SANE_FALSE;
5202141cc406Sopenharmony_ci  first_dev = 0;
5203141cc406Sopenharmony_ci  first_handle = 0;
5204141cc406Sopenharmony_ci  devlist = 0;
5205141cc406Sopenharmony_ci  new_dev = 0;
5206141cc406Sopenharmony_ci  new_dev_len = 0;
5207141cc406Sopenharmony_ci  new_dev_alloced = 0;
5208141cc406Sopenharmony_ci
5209141cc406Sopenharmony_ci  fp = sanei_config_open (MUSTEK_CONFIG_FILE);
5210141cc406Sopenharmony_ci  if (!fp)
5211141cc406Sopenharmony_ci    {
5212141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
5213141cc406Sopenharmony_ci      DBG (3, "sane_init: couldn't find config file (%s), trying "
5214141cc406Sopenharmony_ci	   "/dev/scanner directly\n", MUSTEK_CONFIG_FILE);
5215141cc406Sopenharmony_ci      attach ("/dev/scanner", 0, SANE_FALSE);
5216141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
5217141cc406Sopenharmony_ci    }
5218141cc406Sopenharmony_ci  linenumber = 0;
5219141cc406Sopenharmony_ci  DBG (4, "sane_init: reading config file `%s'\n", MUSTEK_CONFIG_FILE);
5220141cc406Sopenharmony_ci  while (sanei_config_read (line, sizeof (line), fp))
5221141cc406Sopenharmony_ci    {
5222141cc406Sopenharmony_ci      word = 0;
5223141cc406Sopenharmony_ci      linenumber++;
5224141cc406Sopenharmony_ci
5225141cc406Sopenharmony_ci      cp = sanei_config_get_string (line, &word);
5226141cc406Sopenharmony_ci      if (!word || cp == line)
5227141cc406Sopenharmony_ci	{
5228141cc406Sopenharmony_ci	  DBG (5, "sane_init: config file line %d: ignoring empty line\n",
5229141cc406Sopenharmony_ci	       linenumber);
5230141cc406Sopenharmony_ci	  if (word)
5231141cc406Sopenharmony_ci	    free (word);
5232141cc406Sopenharmony_ci	  continue;
5233141cc406Sopenharmony_ci	}
5234141cc406Sopenharmony_ci      if (word[0] == '#')
5235141cc406Sopenharmony_ci	{
5236141cc406Sopenharmony_ci	  DBG (5, "sane_init: config file line %d: ignoring comment line\n",
5237141cc406Sopenharmony_ci	       linenumber);
5238141cc406Sopenharmony_ci	  free (word);
5239141cc406Sopenharmony_ci	  continue;
5240141cc406Sopenharmony_ci	}
5241141cc406Sopenharmony_ci
5242141cc406Sopenharmony_ci      if (strcmp (word, "option") == 0)
5243141cc406Sopenharmony_ci	{
5244141cc406Sopenharmony_ci	  free (word);
5245141cc406Sopenharmony_ci	  word = 0;
5246141cc406Sopenharmony_ci	  cp = sanei_config_get_string (cp, &word);
5247141cc406Sopenharmony_ci	  if (!word)
5248141cc406Sopenharmony_ci	    {
5249141cc406Sopenharmony_ci	      DBG (1,
5250141cc406Sopenharmony_ci		   "sane_init: config file line %d: missing quotation mark?\n",
5251141cc406Sopenharmony_ci		   linenumber);
5252141cc406Sopenharmony_ci	      continue;
5253141cc406Sopenharmony_ci	    }
5254141cc406Sopenharmony_ci
5255141cc406Sopenharmony_ci	  if (strcmp (word, "strip-height") == 0)
5256141cc406Sopenharmony_ci	    {
5257141cc406Sopenharmony_ci	      free (word);
5258141cc406Sopenharmony_ci	      word = 0;
5259141cc406Sopenharmony_ci	      cp = sanei_config_get_string (cp, &word);
5260141cc406Sopenharmony_ci	      if (!word)
5261141cc406Sopenharmony_ci		{
5262141cc406Sopenharmony_ci		  DBG (1,
5263141cc406Sopenharmony_ci		       "sane_init: config file line %d: missing quotation mark?\n",
5264141cc406Sopenharmony_ci		       linenumber);
5265141cc406Sopenharmony_ci		  continue;
5266141cc406Sopenharmony_ci		}
5267141cc406Sopenharmony_ci
5268141cc406Sopenharmony_ci	      errno = 0;
5269141cc406Sopenharmony_ci	      strip_height = strtod (word, &end);
5270141cc406Sopenharmony_ci	      if (end == word)
5271141cc406Sopenharmony_ci		{
5272141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: strip-height "
5273141cc406Sopenharmony_ci		       "must have a parameter; using 1 inch\n", linenumber);
5274141cc406Sopenharmony_ci		  strip_height = 1.0;
5275141cc406Sopenharmony_ci		}
5276141cc406Sopenharmony_ci	      if (errno)
5277141cc406Sopenharmony_ci		{
5278141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: strip-height `%s' "
5279141cc406Sopenharmony_ci		       "is invalid (%s); using 1 inch\n", linenumber,
5280141cc406Sopenharmony_ci		       word, strerror (errno));
5281141cc406Sopenharmony_ci		  strip_height = 1.0;
5282141cc406Sopenharmony_ci		}
5283141cc406Sopenharmony_ci	      else
5284141cc406Sopenharmony_ci		{
5285141cc406Sopenharmony_ci		  if (strip_height < 0.1)
5286141cc406Sopenharmony_ci		    strip_height = 0.1;
5287141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: strip-height set "
5288141cc406Sopenharmony_ci		       "to %g inches\n", linenumber, strip_height);
5289141cc406Sopenharmony_ci		}
5290141cc406Sopenharmony_ci	      if (word)
5291141cc406Sopenharmony_ci		free (word);
5292141cc406Sopenharmony_ci	      word = 0;
5293141cc406Sopenharmony_ci	    }
5294141cc406Sopenharmony_ci	  else if (strcmp (word, "force-wait") == 0)
5295141cc406Sopenharmony_ci	    {
5296141cc406Sopenharmony_ci	      DBG (3, "sane_init: config file line %d: enabling force-wait\n",
5297141cc406Sopenharmony_ci		   linenumber);
5298141cc406Sopenharmony_ci	      force_wait = SANE_TRUE;
5299141cc406Sopenharmony_ci	      if (word)
5300141cc406Sopenharmony_ci		free (word);
5301141cc406Sopenharmony_ci	      word = 0;
5302141cc406Sopenharmony_ci	    }
5303141cc406Sopenharmony_ci	  else if (strcmp (word, "disable-double-buffering") == 0)
5304141cc406Sopenharmony_ci	    {
5305141cc406Sopenharmony_ci	      DBG (3, "sane_init: config file line %d: disabling "
5306141cc406Sopenharmony_ci		   "double-buffering\n", linenumber);
5307141cc406Sopenharmony_ci	      disable_double_buffering = SANE_TRUE;
5308141cc406Sopenharmony_ci	      if (word)
5309141cc406Sopenharmony_ci		free (word);
5310141cc406Sopenharmony_ci	      word = 0;
5311141cc406Sopenharmony_ci	    }
5312141cc406Sopenharmony_ci	  else if (strcmp (word, "legal-size") == 0)
5313141cc406Sopenharmony_ci	    {
5314141cc406Sopenharmony_ci	      if (new_dev_len > 0)
5315141cc406Sopenharmony_ci		{
5316141cc406Sopenharmony_ci		  /* Check for 12000 LS, no way to find out automatically */
5317141cc406Sopenharmony_ci		  if (strcmp (new_dev[new_dev_len - 1]->sane.model,
5318141cc406Sopenharmony_ci			      "ScanExpress 12000SP") == 0)
5319141cc406Sopenharmony_ci		    {
5320141cc406Sopenharmony_ci		      new_dev[new_dev_len - 1]->x_range.max =
5321141cc406Sopenharmony_ci			SANE_FIX (220.0);
5322141cc406Sopenharmony_ci		      new_dev[new_dev_len - 1]->y_range.max =
5323141cc406Sopenharmony_ci			SANE_FIX (360.0);
5324141cc406Sopenharmony_ci		      new_dev[new_dev_len - 1]->sane.model =
5325141cc406Sopenharmony_ci			"Paragon 1200 LS";
5326141cc406Sopenharmony_ci		      DBG (3,
5327141cc406Sopenharmony_ci			   "sane_init: config file line %d: enabling "
5328141cc406Sopenharmony_ci			   "legal-size for %s\n", linenumber,
5329141cc406Sopenharmony_ci			   new_dev[new_dev_len - 1]->sane.name);
5330141cc406Sopenharmony_ci		    }
5331141cc406Sopenharmony_ci		  else
5332141cc406Sopenharmony_ci		    {
5333141cc406Sopenharmony_ci		      DBG (3, "sane_init: config file line %d: option "
5334141cc406Sopenharmony_ci			   "legal-size ignored, device %s is not a "
5335141cc406Sopenharmony_ci			   "Paragon 1200 LS\n", linenumber,
5336141cc406Sopenharmony_ci			   new_dev[new_dev_len - 1]->sane.name);
5337141cc406Sopenharmony_ci		    }
5338141cc406Sopenharmony_ci
5339141cc406Sopenharmony_ci		}
5340141cc406Sopenharmony_ci	      else
5341141cc406Sopenharmony_ci		{
5342141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
5343141cc406Sopenharmony_ci		       "legal-size ignored, was set before any device "
5344141cc406Sopenharmony_ci		       "name\n", linenumber);
5345141cc406Sopenharmony_ci		}
5346141cc406Sopenharmony_ci	      if (word)
5347141cc406Sopenharmony_ci		free (word);
5348141cc406Sopenharmony_ci	      word = 0;
5349141cc406Sopenharmony_ci	    }
5350141cc406Sopenharmony_ci	  else if (strcmp (word, "linedistance-fix") == 0)
5351141cc406Sopenharmony_ci	    {
5352141cc406Sopenharmony_ci	      if (new_dev_len > 0)
5353141cc406Sopenharmony_ci		{
5354141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_LD_FIX;
5355141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: enabling "
5356141cc406Sopenharmony_ci		       "linedistance-fix for %s\n", linenumber,
5357141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
5358141cc406Sopenharmony_ci		}
5359141cc406Sopenharmony_ci	      else
5360141cc406Sopenharmony_ci		{
5361141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
5362141cc406Sopenharmony_ci		       "linedistance-fix ignored, was set before any device "
5363141cc406Sopenharmony_ci		       "name\n", linenumber);
5364141cc406Sopenharmony_ci		}
5365141cc406Sopenharmony_ci	      if (word)
5366141cc406Sopenharmony_ci		free (word);
5367141cc406Sopenharmony_ci	      word = 0;
5368141cc406Sopenharmony_ci	    }
5369141cc406Sopenharmony_ci	  else if (strcmp (word, "disable-backtracking") == 0)
5370141cc406Sopenharmony_ci	    {
5371141cc406Sopenharmony_ci	      if (new_dev_len > 0)
5372141cc406Sopenharmony_ci		{
5373141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_NO_BACKTRACK;
5374141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: disabling "
5375141cc406Sopenharmony_ci		       "backtracking for %s\n", linenumber,
5376141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
5377141cc406Sopenharmony_ci		}
5378141cc406Sopenharmony_ci	      else
5379141cc406Sopenharmony_ci		{
5380141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
5381141cc406Sopenharmony_ci		       "disable-backtracking ignored, was set before any "
5382141cc406Sopenharmony_ci		       "device name\n", linenumber);
5383141cc406Sopenharmony_ci		}
5384141cc406Sopenharmony_ci	      if (word)
5385141cc406Sopenharmony_ci		free (word);
5386141cc406Sopenharmony_ci	      word = 0;
5387141cc406Sopenharmony_ci	    }
5388141cc406Sopenharmony_ci	  else if (strcmp (word, "lineart-fix") == 0)
5389141cc406Sopenharmony_ci	    {
5390141cc406Sopenharmony_ci	      if (new_dev_len > 0)
5391141cc406Sopenharmony_ci		{
5392141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->flags |= MUSTEK_FLAG_LINEART_FIX;
5393141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: enabling "
5394141cc406Sopenharmony_ci		       "lineart-fix for %s\n", linenumber,
5395141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
5396141cc406Sopenharmony_ci		}
5397141cc406Sopenharmony_ci	      else
5398141cc406Sopenharmony_ci		{
5399141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
5400141cc406Sopenharmony_ci		       "lineart-fix ignored, was set before any device name\n",
5401141cc406Sopenharmony_ci		       linenumber);
5402141cc406Sopenharmony_ci		}
5403141cc406Sopenharmony_ci	      if (word)
5404141cc406Sopenharmony_ci		free (word);
5405141cc406Sopenharmony_ci	      word = 0;
5406141cc406Sopenharmony_ci	    }
5407141cc406Sopenharmony_ci	  else if (strcmp (word, "buffersize") == 0)
5408141cc406Sopenharmony_ci	    {
5409141cc406Sopenharmony_ci	      long buffer_size;
5410141cc406Sopenharmony_ci
5411141cc406Sopenharmony_ci	      free (word);
5412141cc406Sopenharmony_ci	      word = 0;
5413141cc406Sopenharmony_ci	      cp = sanei_config_get_string (cp, &word);
5414141cc406Sopenharmony_ci	      if (!word)
5415141cc406Sopenharmony_ci		{
5416141cc406Sopenharmony_ci		  DBG (1,
5417141cc406Sopenharmony_ci		       "sane_init: config file line %d: missing quotation mark?\n",
5418141cc406Sopenharmony_ci		       linenumber);
5419141cc406Sopenharmony_ci		  continue;
5420141cc406Sopenharmony_ci		}
5421141cc406Sopenharmony_ci
5422141cc406Sopenharmony_ci	      errno = 0;
5423141cc406Sopenharmony_ci	      buffer_size = strtol (word, &end, 0);
5424141cc406Sopenharmony_ci
5425141cc406Sopenharmony_ci	      if (end == word)
5426141cc406Sopenharmony_ci		{
5427141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: buffersize must "
5428141cc406Sopenharmony_ci		       "have a parameter; using default (%d kb)\n",
5429141cc406Sopenharmony_ci		       linenumber, new_dev[new_dev_len - 1]->max_buffer_size);
5430141cc406Sopenharmony_ci		}
5431141cc406Sopenharmony_ci	      if (errno)
5432141cc406Sopenharmony_ci		{
5433141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: buffersize `%s' "
5434141cc406Sopenharmony_ci		       "is invalid (%s); using default (%d kb)\n", linenumber,
5435141cc406Sopenharmony_ci		       word, strerror (errno),
5436141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->max_buffer_size);
5437141cc406Sopenharmony_ci		}
5438141cc406Sopenharmony_ci	      else
5439141cc406Sopenharmony_ci		{
5440141cc406Sopenharmony_ci		  if (new_dev_len > 0)
5441141cc406Sopenharmony_ci		    {
5442141cc406Sopenharmony_ci		      if (buffer_size < 32.0)
5443141cc406Sopenharmony_ci			buffer_size = 32.0;
5444141cc406Sopenharmony_ci		      new_dev[new_dev_len - 1]->max_buffer_size =
5445141cc406Sopenharmony_ci			buffer_size * 1024;
5446141cc406Sopenharmony_ci		      DBG (3,
5447141cc406Sopenharmony_ci			   "sane_init: config file line %d: buffersize set "
5448141cc406Sopenharmony_ci			   "to %ld kb for %s\n", linenumber, buffer_size,
5449141cc406Sopenharmony_ci			   new_dev[new_dev_len - 1]->sane.name);
5450141cc406Sopenharmony_ci		    }
5451141cc406Sopenharmony_ci		  else
5452141cc406Sopenharmony_ci		    {
5453141cc406Sopenharmony_ci		      DBG (3, "sane_init: config file line %d: option "
5454141cc406Sopenharmony_ci			   "buffersize ignored, was set before any device "
5455141cc406Sopenharmony_ci			   "name\n", linenumber);
5456141cc406Sopenharmony_ci		    }
5457141cc406Sopenharmony_ci		}
5458141cc406Sopenharmony_ci	      if (word)
5459141cc406Sopenharmony_ci		free (word);
5460141cc406Sopenharmony_ci	      word = 0;
5461141cc406Sopenharmony_ci	    }
5462141cc406Sopenharmony_ci	  else if (strcmp (word, "blocksize") == 0)
5463141cc406Sopenharmony_ci	    {
5464141cc406Sopenharmony_ci	      long block_size;
5465141cc406Sopenharmony_ci
5466141cc406Sopenharmony_ci	      free (word);
5467141cc406Sopenharmony_ci	      word = 0;
5468141cc406Sopenharmony_ci	      cp = sanei_config_get_string (cp, &word);
5469141cc406Sopenharmony_ci	      if (!word)
5470141cc406Sopenharmony_ci		{
5471141cc406Sopenharmony_ci		  DBG (1,
5472141cc406Sopenharmony_ci		       "sane_init: config file line %d: missing quotation mark?\n",
5473141cc406Sopenharmony_ci		       linenumber);
5474141cc406Sopenharmony_ci		  continue;
5475141cc406Sopenharmony_ci		}
5476141cc406Sopenharmony_ci
5477141cc406Sopenharmony_ci	      errno = 0;
5478141cc406Sopenharmony_ci	      block_size = strtol (word, &end, 0);
5479141cc406Sopenharmony_ci
5480141cc406Sopenharmony_ci	      if (end == word)
5481141cc406Sopenharmony_ci		{
5482141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d:: blocksize must "
5483141cc406Sopenharmony_ci		       "have a parameter; using default (1 GB)\n",
5484141cc406Sopenharmony_ci		       linenumber);
5485141cc406Sopenharmony_ci		}
5486141cc406Sopenharmony_ci	      if (errno)
5487141cc406Sopenharmony_ci		{
5488141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: blocksize `%s' "
5489141cc406Sopenharmony_ci		       "is invalid (%s); using default (1 GB)\n", linenumber,
5490141cc406Sopenharmony_ci		       word, strerror (errno));
5491141cc406Sopenharmony_ci		}
5492141cc406Sopenharmony_ci	      else
5493141cc406Sopenharmony_ci		{
5494141cc406Sopenharmony_ci		  if (new_dev_len > 0)
5495141cc406Sopenharmony_ci		    {
5496141cc406Sopenharmony_ci		      if (block_size < 256.0)
5497141cc406Sopenharmony_ci			block_size = 256.0;
5498141cc406Sopenharmony_ci		      new_dev[new_dev_len - 1]->max_block_buffer_size =
5499141cc406Sopenharmony_ci			block_size * 1024;
5500141cc406Sopenharmony_ci		      DBG (3, "sane_init: config file line %d: blocksize set "
5501141cc406Sopenharmony_ci			   "to %ld kb for %s\n", linenumber, block_size,
5502141cc406Sopenharmony_ci			   new_dev[new_dev_len - 1]->sane.name);
5503141cc406Sopenharmony_ci		    }
5504141cc406Sopenharmony_ci		  else
5505141cc406Sopenharmony_ci		    {
5506141cc406Sopenharmony_ci		      DBG (3, "sane_init: config file line %d: option "
5507141cc406Sopenharmony_ci			   "blocksize ignored, was set before any device "
5508141cc406Sopenharmony_ci			   "name\n", linenumber);
5509141cc406Sopenharmony_ci		    }
5510141cc406Sopenharmony_ci		}
5511141cc406Sopenharmony_ci	      if (word)
5512141cc406Sopenharmony_ci		free (word);
5513141cc406Sopenharmony_ci	      word = 0;
5514141cc406Sopenharmony_ci	    }
5515141cc406Sopenharmony_ci	  else
5516141cc406Sopenharmony_ci	    {
5517141cc406Sopenharmony_ci	      DBG (3, "sane_init: config file line %d: ignoring unknown "
5518141cc406Sopenharmony_ci		   "option `%s'\n", linenumber, word);
5519141cc406Sopenharmony_ci	      if (word)
5520141cc406Sopenharmony_ci		free (word);
5521141cc406Sopenharmony_ci	      word = 0;
5522141cc406Sopenharmony_ci	    }
5523141cc406Sopenharmony_ci	}
5524141cc406Sopenharmony_ci      else
5525141cc406Sopenharmony_ci	{
5526141cc406Sopenharmony_ci	  new_dev_len = 0;
5527141cc406Sopenharmony_ci	  DBG (4, "sane_init: config file line %d: trying to attach `%s'\n",
5528141cc406Sopenharmony_ci	       linenumber, line);
5529141cc406Sopenharmony_ci	  sanei_config_attach_matching_devices (line, attach_one_device);
5530141cc406Sopenharmony_ci	  if (word)
5531141cc406Sopenharmony_ci	    free (word);
5532141cc406Sopenharmony_ci	  word = 0;
5533141cc406Sopenharmony_ci	}
5534141cc406Sopenharmony_ci    }
5535141cc406Sopenharmony_ci
5536141cc406Sopenharmony_ci  if (new_dev_alloced > 0)
5537141cc406Sopenharmony_ci    {
5538141cc406Sopenharmony_ci      new_dev_len = new_dev_alloced = 0;
5539141cc406Sopenharmony_ci      free (new_dev);
5540141cc406Sopenharmony_ci    }
5541141cc406Sopenharmony_ci  fclose (fp);
5542141cc406Sopenharmony_ci  DBG (5, "sane_init: end\n");
5543141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5544141cc406Sopenharmony_ci}
5545141cc406Sopenharmony_ci
5546141cc406Sopenharmony_civoid
5547141cc406Sopenharmony_cisane_exit (void)
5548141cc406Sopenharmony_ci{
5549141cc406Sopenharmony_ci  Mustek_Device *dev, *next;
5550141cc406Sopenharmony_ci
5551141cc406Sopenharmony_ci  DBG (4, "sane_exit\n");
5552141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
5553141cc406Sopenharmony_ci    {
5554141cc406Sopenharmony_ci      next = dev->next;
5555141cc406Sopenharmony_ci      free (dev->name);
5556141cc406Sopenharmony_ci      free (dev);
5557141cc406Sopenharmony_ci    }
5558141cc406Sopenharmony_ci  if (devlist)
5559141cc406Sopenharmony_ci    free (devlist);
5560141cc406Sopenharmony_ci  devlist = 0;
5561141cc406Sopenharmony_ci  first_dev = 0;
5562141cc406Sopenharmony_ci  sanei_ab306_exit ();		/* may have to do some cleanup */
5563141cc406Sopenharmony_ci  mustek_scsi_pp_exit ();
5564141cc406Sopenharmony_ci  DBG (5, "sane_exit: finished\n");
5565141cc406Sopenharmony_ci}
5566141cc406Sopenharmony_ci
5567141cc406Sopenharmony_ciSANE_Status
5568141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
5569141cc406Sopenharmony_ci{
5570141cc406Sopenharmony_ci  Mustek_Device *dev;
5571141cc406Sopenharmony_ci  SANE_Int i;
5572141cc406Sopenharmony_ci
5573141cc406Sopenharmony_ci  DBG (4, "sane_get_devices: %d devices %s\n", num_devices,
5574141cc406Sopenharmony_ci       local_only ? "(local only)" : "");
5575141cc406Sopenharmony_ci  if (devlist)
5576141cc406Sopenharmony_ci    free (devlist);
5577141cc406Sopenharmony_ci
5578141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
5579141cc406Sopenharmony_ci  if (!devlist)
5580141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
5581141cc406Sopenharmony_ci
5582141cc406Sopenharmony_ci  i = 0;
5583141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
5584141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
5585141cc406Sopenharmony_ci  devlist[i++] = 0;
5586141cc406Sopenharmony_ci
5587141cc406Sopenharmony_ci  *device_list = devlist;
5588141cc406Sopenharmony_ci  DBG (5, "sane_get_devices: end\n");
5589141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5590141cc406Sopenharmony_ci}
5591141cc406Sopenharmony_ci
5592141cc406Sopenharmony_ciSANE_Status
5593141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
5594141cc406Sopenharmony_ci{
5595141cc406Sopenharmony_ci  Mustek_Device *dev;
5596141cc406Sopenharmony_ci  SANE_Status status;
5597141cc406Sopenharmony_ci  Mustek_Scanner *s;
5598141cc406Sopenharmony_ci
5599141cc406Sopenharmony_ci  if (!devicename)
5600141cc406Sopenharmony_ci    {
5601141cc406Sopenharmony_ci      DBG (1, "sane_open: devicename is null!\n");
5602141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5603141cc406Sopenharmony_ci    }
5604141cc406Sopenharmony_ci  if (!handle)
5605141cc406Sopenharmony_ci    {
5606141cc406Sopenharmony_ci      DBG (1, "sane_open: handle is null!\n");
5607141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5608141cc406Sopenharmony_ci    }
5609141cc406Sopenharmony_ci  DBG (4, "sane_open: devicename=%s\n", devicename);
5610141cc406Sopenharmony_ci
5611141cc406Sopenharmony_ci  if (devicename[0])
5612141cc406Sopenharmony_ci    {
5613141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
5614141cc406Sopenharmony_ci	if (strcmp (dev->sane.name, devicename) == 0)
5615141cc406Sopenharmony_ci	  break;
5616141cc406Sopenharmony_ci
5617141cc406Sopenharmony_ci      if (!dev)
5618141cc406Sopenharmony_ci	{
5619141cc406Sopenharmony_ci	  status = attach (devicename, &dev, SANE_TRUE);
5620141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
5621141cc406Sopenharmony_ci	    return status;
5622141cc406Sopenharmony_ci	}
5623141cc406Sopenharmony_ci    }
5624141cc406Sopenharmony_ci  else
5625141cc406Sopenharmony_ci    /* empty devicname -> use first device */
5626141cc406Sopenharmony_ci    dev = first_dev;
5627141cc406Sopenharmony_ci
5628141cc406Sopenharmony_ci  if (!dev)
5629141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
5630141cc406Sopenharmony_ci
5631141cc406Sopenharmony_ci  s = malloc (sizeof (*s));
5632141cc406Sopenharmony_ci  if (!s)
5633141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
5634141cc406Sopenharmony_ci  memset (s, 0, sizeof (*s));
5635141cc406Sopenharmony_ci  s->fd = -1;
5636141cc406Sopenharmony_ci  s->pipe = -1;
5637141cc406Sopenharmony_ci  s->hw = dev;
5638141cc406Sopenharmony_ci  s->ld.ld_line = 0;
5639141cc406Sopenharmony_ci  s->halftone_pattern = malloc (8 * 8 * sizeof (SANE_Int));
5640141cc406Sopenharmony_ci  if (!s->halftone_pattern)
5641141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
5642141cc406Sopenharmony_ci  init_options (s);
5643141cc406Sopenharmony_ci
5644141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
5645141cc406Sopenharmony_ci  s->next = first_handle;
5646141cc406Sopenharmony_ci  first_handle = s;
5647141cc406Sopenharmony_ci
5648141cc406Sopenharmony_ci  *handle = s;
5649141cc406Sopenharmony_ci  DBG (4, "sane_open: finished (handle=%p)\n", (void *) s);
5650141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
5651141cc406Sopenharmony_ci}
5652141cc406Sopenharmony_ci
5653141cc406Sopenharmony_civoid
5654141cc406Sopenharmony_cisane_close (SANE_Handle handle)
5655141cc406Sopenharmony_ci{
5656141cc406Sopenharmony_ci  Mustek_Scanner *prev, *s;
5657141cc406Sopenharmony_ci
5658141cc406Sopenharmony_ci  DBG (4, "sane_close: handle=%p\n", handle);
5659141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
5660141cc406Sopenharmony_ci  prev = 0;
5661141cc406Sopenharmony_ci  for (s = first_handle; s; s = s->next)
5662141cc406Sopenharmony_ci    {
5663141cc406Sopenharmony_ci      if (s == handle)
5664141cc406Sopenharmony_ci	break;
5665141cc406Sopenharmony_ci      prev = s;
5666141cc406Sopenharmony_ci    }
5667141cc406Sopenharmony_ci  if (!s)
5668141cc406Sopenharmony_ci    {
5669141cc406Sopenharmony_ci      DBG (1, "sane_close: invalid handle %p\n", handle);
5670141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
5671141cc406Sopenharmony_ci    }
5672141cc406Sopenharmony_ci
5673141cc406Sopenharmony_ci  if (s->scanning)
5674141cc406Sopenharmony_ci    do_stop (handle);
5675141cc406Sopenharmony_ci
5676141cc406Sopenharmony_ci  if (s->ld.buf[0])
5677141cc406Sopenharmony_ci    free (s->ld.buf[0]);
5678141cc406Sopenharmony_ci  if (s->val[OPT_MODE].s)
5679141cc406Sopenharmony_ci    free (s->val[OPT_MODE].s);
5680141cc406Sopenharmony_ci  if (s->val[OPT_BIT_DEPTH].s)
5681141cc406Sopenharmony_ci    free (s->val[OPT_BIT_DEPTH].s);
5682141cc406Sopenharmony_ci  if (s->val[OPT_SPEED].s)
5683141cc406Sopenharmony_ci    free (s->val[OPT_SPEED].s);
5684141cc406Sopenharmony_ci  if (s->val[OPT_SOURCE].s)
5685141cc406Sopenharmony_ci    free (s->val[OPT_SOURCE].s);
5686141cc406Sopenharmony_ci  if (s->val[OPT_HALFTONE_DIMENSION].s)
5687141cc406Sopenharmony_ci    free (s->val[OPT_HALFTONE_DIMENSION].s);
5688141cc406Sopenharmony_ci  if (s->halftone_pattern)
5689141cc406Sopenharmony_ci    free (s->halftone_pattern);
5690141cc406Sopenharmony_ci  if (prev)
5691141cc406Sopenharmony_ci    prev->next = s->next;
5692141cc406Sopenharmony_ci  else
5693141cc406Sopenharmony_ci    first_handle = s->next;
5694141cc406Sopenharmony_ci  free (handle);
5695141cc406Sopenharmony_ci  handle = 0;
5696141cc406Sopenharmony_ci  DBG (5, "sane_close: finished\n");
5697141cc406Sopenharmony_ci}
5698141cc406Sopenharmony_ci
5699141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
5700141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
5701141cc406Sopenharmony_ci{
5702141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
5703141cc406Sopenharmony_ci
5704141cc406Sopenharmony_ci  if (((unsigned) option >= NUM_OPTIONS) || (option < 0))
5705141cc406Sopenharmony_ci    {
5706141cc406Sopenharmony_ci      DBG (4, "sane_get_option_descriptor: option %d >= NUM_OPTIONS or < 0\n",
5707141cc406Sopenharmony_ci	   option);
5708141cc406Sopenharmony_ci      return 0;
5709141cc406Sopenharmony_ci    }
5710141cc406Sopenharmony_ci  if (!s)
5711141cc406Sopenharmony_ci    {
5712141cc406Sopenharmony_ci      DBG (1, "sane_get_option_descriptor: handle is null!\n");
5713141cc406Sopenharmony_ci      return 0;
5714141cc406Sopenharmony_ci    }
5715141cc406Sopenharmony_ci  if (s->opt[option].name && s->opt[option].name[0] != 0)
5716141cc406Sopenharmony_ci    DBG (5, "sane_get_option_descriptor for option %s (%sactive%s)\n",
5717141cc406Sopenharmony_ci	 s->opt[option].name,
5718141cc406Sopenharmony_ci	 s->opt[option].cap & SANE_CAP_INACTIVE ? "in" : "",
5719141cc406Sopenharmony_ci	 s->opt[option].cap & SANE_CAP_ADVANCED ? ", advanced" : "");
5720141cc406Sopenharmony_ci  else
5721141cc406Sopenharmony_ci    DBG (5, "sane_get_option_descriptor for option \"%s\" (%sactive%s)\n",
5722141cc406Sopenharmony_ci	 s->opt[option].title,
5723141cc406Sopenharmony_ci	 s->opt[option].cap & SANE_CAP_INACTIVE ? "in" : "",
5724141cc406Sopenharmony_ci	 s->opt[option].cap & SANE_CAP_ADVANCED ? ", advanced" : "");
5725141cc406Sopenharmony_ci  return s->opt + option;
5726141cc406Sopenharmony_ci}
5727141cc406Sopenharmony_ci
5728141cc406Sopenharmony_ciSANE_Status
5729141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
5730141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
5731141cc406Sopenharmony_ci{
5732141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
5733141cc406Sopenharmony_ci  SANE_Status status;
5734141cc406Sopenharmony_ci  SANE_Word w, cap;
5735141cc406Sopenharmony_ci
5736141cc406Sopenharmony_ci  if (((unsigned) option >= NUM_OPTIONS) || (option < 0))
5737141cc406Sopenharmony_ci    {
5738141cc406Sopenharmony_ci      DBG (4, "sane_control_option: option %d < 0 or >= NUM_OPTIONS\n",
5739141cc406Sopenharmony_ci	   option);
5740141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5741141cc406Sopenharmony_ci    }
5742141cc406Sopenharmony_ci  if (!s)
5743141cc406Sopenharmony_ci    {
5744141cc406Sopenharmony_ci      DBG (1, "sane_control_option: handle is null!\n");
5745141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5746141cc406Sopenharmony_ci    }
5747141cc406Sopenharmony_ci
5748141cc406Sopenharmony_ci  if (s->opt[option].type != SANE_TYPE_BUTTON && !val)
5749141cc406Sopenharmony_ci    {
5750141cc406Sopenharmony_ci      DBG (1, "sane_control_option: val is null!\n");
5751141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5752141cc406Sopenharmony_ci    }
5753141cc406Sopenharmony_ci
5754141cc406Sopenharmony_ci  if (s->opt[option].name && s->opt[option].name[0] != 0)
5755141cc406Sopenharmony_ci    DBG (5, "sane_control_option (%s option %s)\n",
5756141cc406Sopenharmony_ci	 action == SANE_ACTION_GET_VALUE ? "get" :
5757141cc406Sopenharmony_ci	 (action == SANE_ACTION_SET_VALUE ? "set" : "unknown action with"),
5758141cc406Sopenharmony_ci	 s->opt[option].name);
5759141cc406Sopenharmony_ci  else
5760141cc406Sopenharmony_ci    DBG (5, "sane_control_option (%s option \"%s\")\n",
5761141cc406Sopenharmony_ci	 action == SANE_ACTION_GET_VALUE ? "get" :
5762141cc406Sopenharmony_ci	 (action == SANE_ACTION_SET_VALUE ? "set" : "unknown action with"),
5763141cc406Sopenharmony_ci	 s->opt[option].title);
5764141cc406Sopenharmony_ci
5765141cc406Sopenharmony_ci  if (info)
5766141cc406Sopenharmony_ci    *info = 0;
5767141cc406Sopenharmony_ci
5768141cc406Sopenharmony_ci  if (s->scanning)
5769141cc406Sopenharmony_ci    {
5770141cc406Sopenharmony_ci      DBG (4, "sane_control_option: don't use while scanning (option %s)\n",
5771141cc406Sopenharmony_ci	   s->opt[option].name);
5772141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
5773141cc406Sopenharmony_ci    }
5774141cc406Sopenharmony_ci
5775141cc406Sopenharmony_ci  cap = s->opt[option].cap;
5776141cc406Sopenharmony_ci
5777141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
5778141cc406Sopenharmony_ci    {
5779141cc406Sopenharmony_ci      DBG (4, "sane_control_option: option %s is inactive\n",
5780141cc406Sopenharmony_ci	   s->opt[option].name);
5781141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
5782141cc406Sopenharmony_ci    }
5783141cc406Sopenharmony_ci
5784141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
5785141cc406Sopenharmony_ci    {
5786141cc406Sopenharmony_ci      switch (option)
5787141cc406Sopenharmony_ci	{
5788141cc406Sopenharmony_ci	  /* word options: */
5789141cc406Sopenharmony_ci	case OPT_PREVIEW:
5790141cc406Sopenharmony_ci	case OPT_FAST_PREVIEW:
5791141cc406Sopenharmony_ci	case OPT_RESOLUTION:
5792141cc406Sopenharmony_ci	case OPT_FAST_GRAY_MODE:
5793141cc406Sopenharmony_ci	case OPT_TL_X:
5794141cc406Sopenharmony_ci	case OPT_TL_Y:
5795141cc406Sopenharmony_ci	case OPT_BR_X:
5796141cc406Sopenharmony_ci	case OPT_BR_Y:
5797141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
5798141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
5799141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_R:
5800141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_G:
5801141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_B:
5802141cc406Sopenharmony_ci	case OPT_CONTRAST:
5803141cc406Sopenharmony_ci	case OPT_CONTRAST_R:
5804141cc406Sopenharmony_ci	case OPT_CONTRAST_G:
5805141cc406Sopenharmony_ci	case OPT_CONTRAST_B:
5806141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
5807141cc406Sopenharmony_ci	case OPT_QUALITY_CAL:
5808141cc406Sopenharmony_ci	case OPT_LAMP_OFF_TIME:
5809141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
5810141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5811141cc406Sopenharmony_ci
5812141cc406Sopenharmony_ci	  /* word-array options: */
5813141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
5814141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
5815141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
5816141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
5817141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
5818141cc406Sopenharmony_ci	  memcpy (val, s->val[option].wa, s->opt[option].size);
5819141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5820141cc406Sopenharmony_ci
5821141cc406Sopenharmony_ci	  /* string options: */
5822141cc406Sopenharmony_ci	case OPT_SPEED:
5823141cc406Sopenharmony_ci	case OPT_SOURCE:
5824141cc406Sopenharmony_ci	case OPT_MODE:
5825141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
5826141cc406Sopenharmony_ci	case OPT_HALFTONE_DIMENSION:
5827141cc406Sopenharmony_ci	  strcpy (val, s->val[option].s);
5828141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5829141cc406Sopenharmony_ci	}
5830141cc406Sopenharmony_ci    }
5831141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
5832141cc406Sopenharmony_ci    {
5833141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
5834141cc406Sopenharmony_ci	{
5835141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: option %s is not setable\n",
5836141cc406Sopenharmony_ci	       s->opt[option].name);
5837141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
5838141cc406Sopenharmony_ci	}
5839141cc406Sopenharmony_ci
5840141cc406Sopenharmony_ci      status = constrain_value (s, option, val, info);
5841141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
5842141cc406Sopenharmony_ci	{
5843141cc406Sopenharmony_ci	  DBG (4, "sane_control_option: constrain_value error (option %s)\n",
5844141cc406Sopenharmony_ci	       s->opt[option].name);
5845141cc406Sopenharmony_ci	  return status;
5846141cc406Sopenharmony_ci	}
5847141cc406Sopenharmony_ci
5848141cc406Sopenharmony_ci      switch (option)
5849141cc406Sopenharmony_ci	{
5850141cc406Sopenharmony_ci	case OPT_LAMP_OFF_BUTTON:
5851141cc406Sopenharmony_ci	  {
5852141cc406Sopenharmony_ci	    SANE_Int old_time = lamp_off_time;
5853141cc406Sopenharmony_ci	    SANE_Status status;
5854141cc406Sopenharmony_ci
5855141cc406Sopenharmony_ci	    status = dev_open (s->hw->sane.name, s, sense_handler);
5856141cc406Sopenharmony_ci	    if (status != SANE_STATUS_GOOD)
5857141cc406Sopenharmony_ci	      return status;
5858141cc406Sopenharmony_ci	    lamp_off_time = 0;
5859141cc406Sopenharmony_ci	    set_window_pro (s);
5860141cc406Sopenharmony_ci	    lamp_off_time = old_time;
5861141cc406Sopenharmony_ci	    dev_close (s);
5862141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
5863141cc406Sopenharmony_ci	  }
5864141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
5865141cc406Sopenharmony_ci	case OPT_RESOLUTION:
5866141cc406Sopenharmony_ci	case OPT_TL_X:
5867141cc406Sopenharmony_ci	case OPT_BR_X:
5868141cc406Sopenharmony_ci	case OPT_TL_Y:
5869141cc406Sopenharmony_ci	case OPT_BR_Y:
5870141cc406Sopenharmony_ci	  if (info)
5871141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
5872141cc406Sopenharmony_ci	  /* fall through */
5873141cc406Sopenharmony_ci	case OPT_PREVIEW:
5874141cc406Sopenharmony_ci	case OPT_FAST_PREVIEW:
5875141cc406Sopenharmony_ci	case OPT_FAST_GRAY_MODE:
5876141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
5877141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_R:
5878141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_G:
5879141cc406Sopenharmony_ci	case OPT_BRIGHTNESS_B:
5880141cc406Sopenharmony_ci	case OPT_CONTRAST:
5881141cc406Sopenharmony_ci	case OPT_CONTRAST_R:
5882141cc406Sopenharmony_ci	case OPT_CONTRAST_G:
5883141cc406Sopenharmony_ci	case OPT_CONTRAST_B:
5884141cc406Sopenharmony_ci	case OPT_QUALITY_CAL:
5885141cc406Sopenharmony_ci	case OPT_LAMP_OFF_TIME:
5886141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
5887141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5888141cc406Sopenharmony_ci
5889141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
5890141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
5891141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
5892141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
5893141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
5894141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
5895141cc406Sopenharmony_ci	  memcpy (s->val[option].wa, val, s->opt[option].size);
5896141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5897141cc406Sopenharmony_ci
5898141cc406Sopenharmony_ci	  /* side-effect-free single-string options: */
5899141cc406Sopenharmony_ci	case OPT_SPEED:
5900141cc406Sopenharmony_ci	  if (s->val[option].s)
5901141cc406Sopenharmony_ci	    free (s->val[option].s);
5902141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
5903141cc406Sopenharmony_ci	  if (!s->val[option].s)
5904141cc406Sopenharmony_ci	    return SANE_STATUS_NO_MEM;
5905141cc406Sopenharmony_ci
5906141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5907141cc406Sopenharmony_ci
5908141cc406Sopenharmony_ci	  /* side-effect-free string list options: */
5909141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
5910141cc406Sopenharmony_ci	  {
5911141cc406Sopenharmony_ci	    SANE_Char *old_val = s->val[option].s;
5912141cc406Sopenharmony_ci
5913141cc406Sopenharmony_ci	    if (old_val)
5914141cc406Sopenharmony_ci	      {
5915141cc406Sopenharmony_ci		if (strcmp (old_val, val) == 0)
5916141cc406Sopenharmony_ci		  return SANE_STATUS_GOOD;	/* no change */
5917141cc406Sopenharmony_ci		free (old_val);
5918141cc406Sopenharmony_ci	      }
5919141cc406Sopenharmony_ci	    s->val[option].s = strdup (val);
5920141cc406Sopenharmony_ci	    if (!s->val[option].s)
5921141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
5922141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
5923141cc406Sopenharmony_ci	  }
5924141cc406Sopenharmony_ci
5925141cc406Sopenharmony_ci	  /* options with side-effects: */
5926141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
5927141cc406Sopenharmony_ci	  w = *(SANE_Word *) val;
5928141cc406Sopenharmony_ci
5929141cc406Sopenharmony_ci	  if (w == s->val[OPT_CUSTOM_GAMMA].w)
5930141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;	/* no change */
5931141cc406Sopenharmony_ci
5932141cc406Sopenharmony_ci	  if (info)
5933141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
5934141cc406Sopenharmony_ci
5935141cc406Sopenharmony_ci	  s->val[OPT_CUSTOM_GAMMA].w = w;
5936141cc406Sopenharmony_ci	  if (w)
5937141cc406Sopenharmony_ci	    {
5938141cc406Sopenharmony_ci	      SANE_String_Const mode = s->val[OPT_MODE].s;
5939141cc406Sopenharmony_ci
5940141cc406Sopenharmony_ci	      if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
5941141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
5942141cc406Sopenharmony_ci	      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
5943141cc406Sopenharmony_ci		{
5944141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
5945141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
5946141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
5947141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
5948141cc406Sopenharmony_ci		}
5949141cc406Sopenharmony_ci	      else if ((strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
5950141cc406Sopenharmony_ci		       && (s->hw->flags & MUSTEK_FLAG_PRO))
5951141cc406Sopenharmony_ci		{
5952141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
5953141cc406Sopenharmony_ci		}
5954141cc406Sopenharmony_ci	    }
5955141cc406Sopenharmony_ci	  else
5956141cc406Sopenharmony_ci	    {
5957141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
5958141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
5959141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
5960141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
5961141cc406Sopenharmony_ci	    }
5962141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
5963141cc406Sopenharmony_ci
5964141cc406Sopenharmony_ci	case OPT_MODE:
5965141cc406Sopenharmony_ci	  {
5966141cc406Sopenharmony_ci	    SANE_Char *old_val = s->val[option].s;
5967141cc406Sopenharmony_ci	    SANE_Int halftoning, binary;
5968141cc406Sopenharmony_ci
5969141cc406Sopenharmony_ci	    if (old_val)
5970141cc406Sopenharmony_ci	      {
5971141cc406Sopenharmony_ci		if (strcmp (old_val, val) == 0)
5972141cc406Sopenharmony_ci		  return SANE_STATUS_GOOD;	/* no change */
5973141cc406Sopenharmony_ci		free (old_val);
5974141cc406Sopenharmony_ci	      }
5975141cc406Sopenharmony_ci	    if (info)
5976141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
5977141cc406Sopenharmony_ci
5978141cc406Sopenharmony_ci	    s->val[option].s = strdup (val);
5979141cc406Sopenharmony_ci	    if (!s->val[option].s)
5980141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
5981141cc406Sopenharmony_ci
5982141cc406Sopenharmony_ci	    s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
5983141cc406Sopenharmony_ci	    s->opt[OPT_BRIGHTNESS_R].cap |= SANE_CAP_INACTIVE;
5984141cc406Sopenharmony_ci	    s->opt[OPT_BRIGHTNESS_G].cap |= SANE_CAP_INACTIVE;
5985141cc406Sopenharmony_ci	    s->opt[OPT_BRIGHTNESS_B].cap |= SANE_CAP_INACTIVE;
5986141cc406Sopenharmony_ci	    s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
5987141cc406Sopenharmony_ci	    s->opt[OPT_CONTRAST_R].cap |= SANE_CAP_INACTIVE;
5988141cc406Sopenharmony_ci	    s->opt[OPT_CONTRAST_G].cap |= SANE_CAP_INACTIVE;
5989141cc406Sopenharmony_ci	    s->opt[OPT_CONTRAST_B].cap |= SANE_CAP_INACTIVE;
5990141cc406Sopenharmony_ci	    s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
5991141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
5992141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
5993141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
5994141cc406Sopenharmony_ci	    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
5995141cc406Sopenharmony_ci	    s->opt[OPT_HALFTONE_DIMENSION].cap |= SANE_CAP_INACTIVE;
5996141cc406Sopenharmony_ci	    s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
5997141cc406Sopenharmony_ci
5998141cc406Sopenharmony_ci	    halftoning = strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE) == 0;
5999141cc406Sopenharmony_ci	    binary = (halftoning || strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0);
6000141cc406Sopenharmony_ci
6001141cc406Sopenharmony_ci	    if (binary)
6002141cc406Sopenharmony_ci	      {
6003141cc406Sopenharmony_ci		/* enable brightness/contrast for  when in a binary mode */
6004141cc406Sopenharmony_ci		s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
6005141cc406Sopenharmony_ci		/* The SE and paragon models support only threshold
6006141cc406Sopenharmony_ci		   in lineart */
6007141cc406Sopenharmony_ci		if (!(s->hw->flags & MUSTEK_FLAG_SE)
6008141cc406Sopenharmony_ci		    && !(s->hw->flags & MUSTEK_FLAG_PRO))
6009141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
6010141cc406Sopenharmony_ci
6011141cc406Sopenharmony_ci		if (halftoning)
6012141cc406Sopenharmony_ci		  {
6013141cc406Sopenharmony_ci		    s->opt[OPT_HALFTONE_DIMENSION].cap &= ~SANE_CAP_INACTIVE;
6014141cc406Sopenharmony_ci		    encode_halftone (s);
6015141cc406Sopenharmony_ci		    if (s->custom_halftone_pattern)
6016141cc406Sopenharmony_ci		      {
6017141cc406Sopenharmony_ci			s->opt[OPT_HALFTONE_PATTERN].cap
6018141cc406Sopenharmony_ci			  &= ~SANE_CAP_INACTIVE;
6019141cc406Sopenharmony_ci		      }
6020141cc406Sopenharmony_ci		    else
6021141cc406Sopenharmony_ci		      {
6022141cc406Sopenharmony_ci			s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
6023141cc406Sopenharmony_ci		      }
6024141cc406Sopenharmony_ci		  }
6025141cc406Sopenharmony_ci	      }
6026141cc406Sopenharmony_ci	    else
6027141cc406Sopenharmony_ci	      {
6028141cc406Sopenharmony_ci		s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
6029141cc406Sopenharmony_ci	      }
6030141cc406Sopenharmony_ci
6031141cc406Sopenharmony_ci	    if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
6032141cc406Sopenharmony_ci	      {
6033141cc406Sopenharmony_ci		if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
6034141cc406Sopenharmony_ci		  {
6035141cc406Sopenharmony_ci		    s->opt[OPT_BRIGHTNESS_R].cap &= ~SANE_CAP_INACTIVE;
6036141cc406Sopenharmony_ci		    s->opt[OPT_BRIGHTNESS_G].cap &= ~SANE_CAP_INACTIVE;
6037141cc406Sopenharmony_ci		    s->opt[OPT_BRIGHTNESS_B].cap &= ~SANE_CAP_INACTIVE;
6038141cc406Sopenharmony_ci		    s->opt[OPT_CONTRAST_R].cap &= ~SANE_CAP_INACTIVE;
6039141cc406Sopenharmony_ci		    s->opt[OPT_CONTRAST_G].cap &= ~SANE_CAP_INACTIVE;
6040141cc406Sopenharmony_ci		    s->opt[OPT_CONTRAST_B].cap &= ~SANE_CAP_INACTIVE;
6041141cc406Sopenharmony_ci		  }
6042141cc406Sopenharmony_ci		else
6043141cc406Sopenharmony_ci		  {
6044141cc406Sopenharmony_ci		    s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
6045141cc406Sopenharmony_ci		    s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
6046141cc406Sopenharmony_ci		  }
6047141cc406Sopenharmony_ci	      }
6048141cc406Sopenharmony_ci	    else if (s->hw->flags & MUSTEK_FLAG_PRO)
6049141cc406Sopenharmony_ci	      {
6050141cc406Sopenharmony_ci		if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
6051141cc406Sopenharmony_ci		  s->opt[OPT_FAST_GRAY_MODE].cap &= ~SANE_CAP_INACTIVE;
6052141cc406Sopenharmony_ci		else
6053141cc406Sopenharmony_ci		  s->opt[OPT_FAST_GRAY_MODE].cap |= SANE_CAP_INACTIVE;
6054141cc406Sopenharmony_ci		if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
6055141cc406Sopenharmony_ci		  s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
6056141cc406Sopenharmony_ci		else
6057141cc406Sopenharmony_ci		  s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
6058141cc406Sopenharmony_ci	      }
6059141cc406Sopenharmony_ci	    else if (s->hw->flags & MUSTEK_FLAG_SE_PLUS)
6060141cc406Sopenharmony_ci	      {
6061141cc406Sopenharmony_ci		if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
6062141cc406Sopenharmony_ci		  s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
6063141cc406Sopenharmony_ci		else
6064141cc406Sopenharmony_ci		  s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
6065141cc406Sopenharmony_ci	      }
6066141cc406Sopenharmony_ci
6067141cc406Sopenharmony_ci	    if (s->val[OPT_CUSTOM_GAMMA].w)
6068141cc406Sopenharmony_ci	      {
6069141cc406Sopenharmony_ci		if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
6070141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
6071141cc406Sopenharmony_ci		else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
6072141cc406Sopenharmony_ci		  {
6073141cc406Sopenharmony_ci		    s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
6074141cc406Sopenharmony_ci		    s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
6075141cc406Sopenharmony_ci		    s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
6076141cc406Sopenharmony_ci		    s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
6077141cc406Sopenharmony_ci		  }
6078141cc406Sopenharmony_ci	      }
6079141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
6080141cc406Sopenharmony_ci	  }
6081141cc406Sopenharmony_ci
6082141cc406Sopenharmony_ci	case OPT_HALFTONE_DIMENSION:
6083141cc406Sopenharmony_ci	  /* halftone pattern dimension affects halftone pattern option: */
6084141cc406Sopenharmony_ci	  {
6085141cc406Sopenharmony_ci	    if (strcmp (s->val[option].s, (SANE_String) val) == 0)
6086141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;	/* no change */
6087141cc406Sopenharmony_ci
6088141cc406Sopenharmony_ci	    if (info)
6089141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS;
6090141cc406Sopenharmony_ci
6091141cc406Sopenharmony_ci	    s->val[option].s = strdup (val);
6092141cc406Sopenharmony_ci	    if (!s->val[option].s)
6093141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
6094141cc406Sopenharmony_ci	    encode_halftone (s);
6095141cc406Sopenharmony_ci	    s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
6096141cc406Sopenharmony_ci	    if (s->custom_halftone_pattern)
6097141cc406Sopenharmony_ci	      {
6098141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
6099141cc406Sopenharmony_ci		/* BUG: The SANE standard does nor allow to change the option
6100141cc406Sopenharmony_ci		   size at run time */
6101141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE_PATTERN].size =
6102141cc406Sopenharmony_ci		  (s->halftone_pattern_type & 0x0f) * sizeof (SANE_Word);
6103141cc406Sopenharmony_ci	      }
6104141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
6105141cc406Sopenharmony_ci	  }
6106141cc406Sopenharmony_ci
6107141cc406Sopenharmony_ci	case OPT_SOURCE:
6108141cc406Sopenharmony_ci	  if (info)
6109141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
6110141cc406Sopenharmony_ci	  if (s->val[option].s)
6111141cc406Sopenharmony_ci	    free (s->val[option].s);
6112141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
6113141cc406Sopenharmony_ci	  if (!s->val[option].s)
6114141cc406Sopenharmony_ci	    return SANE_STATUS_NO_MEM;
6115141cc406Sopenharmony_ci
6116141cc406Sopenharmony_ci	  if (strcmp (val, "Transparency Adapter") == 0)
6117141cc406Sopenharmony_ci	    {
6118141cc406Sopenharmony_ci	      s->opt[OPT_TL_X].constraint.range = &s->hw->x_trans_range;
6119141cc406Sopenharmony_ci	      s->opt[OPT_TL_Y].constraint.range = &s->hw->y_trans_range;
6120141cc406Sopenharmony_ci	      s->opt[OPT_BR_X].constraint.range = &s->hw->x_trans_range;
6121141cc406Sopenharmony_ci	      s->opt[OPT_BR_Y].constraint.range = &s->hw->y_trans_range;
6122141cc406Sopenharmony_ci	    }
6123141cc406Sopenharmony_ci	  else
6124141cc406Sopenharmony_ci	    {
6125141cc406Sopenharmony_ci	      s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
6126141cc406Sopenharmony_ci	      s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
6127141cc406Sopenharmony_ci	      s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
6128141cc406Sopenharmony_ci	      s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
6129141cc406Sopenharmony_ci	    }
6130141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
6131141cc406Sopenharmony_ci	}
6132141cc406Sopenharmony_ci    }
6133141cc406Sopenharmony_ci  DBG (4, "sane_control_option: unknown action for option %s\n",
6134141cc406Sopenharmony_ci       s->opt[option].name);
6135141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
6136141cc406Sopenharmony_ci}
6137141cc406Sopenharmony_ci
6138141cc406Sopenharmony_ciSANE_Status
6139141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
6140141cc406Sopenharmony_ci{
6141141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6142141cc406Sopenharmony_ci  SANE_String_Const mode;
6143141cc406Sopenharmony_ci
6144141cc406Sopenharmony_ci  if (!s)
6145141cc406Sopenharmony_ci    {
6146141cc406Sopenharmony_ci      DBG (1, "sane_get_parameters: handle is null!\n");
6147141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6148141cc406Sopenharmony_ci    }
6149141cc406Sopenharmony_ci
6150141cc406Sopenharmony_ci  if (!s->scanning)
6151141cc406Sopenharmony_ci    {
6152141cc406Sopenharmony_ci      double width, height, dpi;
6153141cc406Sopenharmony_ci
6154141cc406Sopenharmony_ci      memset (&s->params, 0, sizeof (s->params));
6155141cc406Sopenharmony_ci
6156141cc406Sopenharmony_ci      width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w);
6157141cc406Sopenharmony_ci      height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w);
6158141cc406Sopenharmony_ci      dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
6159141cc406Sopenharmony_ci
6160141cc406Sopenharmony_ci      /* make best-effort guess at what parameters will look like once
6161141cc406Sopenharmony_ci         scanning starts.  */
6162141cc406Sopenharmony_ci      if (dpi > 0.0 && width > 0.0 && height > 0.0)
6163141cc406Sopenharmony_ci	{
6164141cc406Sopenharmony_ci	  double dots_per_mm = dpi / MM_PER_INCH;
6165141cc406Sopenharmony_ci
6166141cc406Sopenharmony_ci	  s->params.pixels_per_line = width * dots_per_mm;
6167141cc406Sopenharmony_ci	  s->params.lines = height * dots_per_mm;
6168141cc406Sopenharmony_ci	}
6169141cc406Sopenharmony_ci      encode_halftone (s);
6170141cc406Sopenharmony_ci      mode = s->val[OPT_MODE].s;
6171141cc406Sopenharmony_ci      if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0 || strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
6172141cc406Sopenharmony_ci	{
6173141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_GRAY;
6174141cc406Sopenharmony_ci	  s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
6175141cc406Sopenharmony_ci	  s->params.depth = 1;
6176141cc406Sopenharmony_ci	}
6177141cc406Sopenharmony_ci      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
6178141cc406Sopenharmony_ci	{
6179141cc406Sopenharmony_ci	  s->params.format = SANE_FRAME_GRAY;
6180141cc406Sopenharmony_ci	  s->params.bytes_per_line = s->params.pixels_per_line;
6181141cc406Sopenharmony_ci	  s->params.depth = 8;
6182141cc406Sopenharmony_ci	}
6183141cc406Sopenharmony_ci      else
6184141cc406Sopenharmony_ci	{
6185141cc406Sopenharmony_ci	  /* it's one of the color modes... */
6186141cc406Sopenharmony_ci
6187141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
6188141cc406Sopenharmony_ci	    {
6189141cc406Sopenharmony_ci	      s->params.format = SANE_FRAME_RED + s->pass;
6190141cc406Sopenharmony_ci	      s->params.bytes_per_line = s->params.pixels_per_line;
6191141cc406Sopenharmony_ci	      s->params.depth = 8;
6192141cc406Sopenharmony_ci	    }
6193141cc406Sopenharmony_ci	  else			/* 1-pass */
6194141cc406Sopenharmony_ci	    {
6195141cc406Sopenharmony_ci	      if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0)
6196141cc406Sopenharmony_ci		{
6197141cc406Sopenharmony_ci		  s->params.bytes_per_line = 6 * s->params.pixels_per_line;
6198141cc406Sopenharmony_ci		  s->params.depth = 16;
6199141cc406Sopenharmony_ci		}
6200141cc406Sopenharmony_ci	      else
6201141cc406Sopenharmony_ci		{
6202141cc406Sopenharmony_ci		  s->params.bytes_per_line = 3 * s->params.pixels_per_line;
6203141cc406Sopenharmony_ci		  s->params.depth = 8;
6204141cc406Sopenharmony_ci		}
6205141cc406Sopenharmony_ci	      s->params.format = SANE_FRAME_RGB;
6206141cc406Sopenharmony_ci	    }
6207141cc406Sopenharmony_ci	}
6208141cc406Sopenharmony_ci    }
6209141cc406Sopenharmony_ci  else if ((s->mode & MUSTEK_MODE_COLOR)
6210141cc406Sopenharmony_ci	   && (s->hw->flags & MUSTEK_FLAG_THREE_PASS))
6211141cc406Sopenharmony_ci    s->params.format = SANE_FRAME_RED + s->pass;
6212141cc406Sopenharmony_ci  s->params.last_frame = (s->params.format != SANE_FRAME_RED
6213141cc406Sopenharmony_ci			  && s->params.format != SANE_FRAME_GREEN);
6214141cc406Sopenharmony_ci  if (params)
6215141cc406Sopenharmony_ci    *params = s->params;
6216141cc406Sopenharmony_ci  DBG (4, "sane_get_parameters: frame = %d; last_frame = %s; depth = %d\n",
6217141cc406Sopenharmony_ci       s->params.format, s->params.last_frame ? "true" : "false",
6218141cc406Sopenharmony_ci       s->params.depth);
6219141cc406Sopenharmony_ci  DBG (4, "sane_get_parameters: lines = %d; ppl = %d; bpl = %d\n",
6220141cc406Sopenharmony_ci       s->params.lines, s->params.pixels_per_line, s->params.bytes_per_line);
6221141cc406Sopenharmony_ci
6222141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6223141cc406Sopenharmony_ci}
6224141cc406Sopenharmony_ci
6225141cc406Sopenharmony_ciSANE_Status
6226141cc406Sopenharmony_cisane_start (SANE_Handle handle)
6227141cc406Sopenharmony_ci{
6228141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6229141cc406Sopenharmony_ci  SANE_Status status;
6230141cc406Sopenharmony_ci  int fds[2];
6231141cc406Sopenharmony_ci  struct SIGACTION act;
6232141cc406Sopenharmony_ci
6233141cc406Sopenharmony_ci  if (!s)
6234141cc406Sopenharmony_ci    {
6235141cc406Sopenharmony_ci      DBG (1, "sane_start: handle is null!\n");
6236141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6237141cc406Sopenharmony_ci    }
6238141cc406Sopenharmony_ci
6239141cc406Sopenharmony_ci  DBG (4, "sane_start\n");
6240141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the
6241141cc406Sopenharmony_ci     parameters will be overwritten below, but that's OK.  */
6242141cc406Sopenharmony_ci  status = sane_get_parameters (s, 0);
6243141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
6244141cc406Sopenharmony_ci    return status;
6245141cc406Sopenharmony_ci
6246141cc406Sopenharmony_ci  /* Check for inconsistencies */
6247141cc406Sopenharmony_ci
6248141cc406Sopenharmony_ci  if (s->val[OPT_TL_X].w > s->val[OPT_BR_X].w)
6249141cc406Sopenharmony_ci    {
6250141cc406Sopenharmony_ci      DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) "
6251141cc406Sopenharmony_ci	   "-- aborting\n",
6252141cc406Sopenharmony_ci	   s->opt[OPT_TL_X].title, SANE_UNFIX (s->val[OPT_TL_X].w),
6253141cc406Sopenharmony_ci	   s->opt[OPT_BR_X].title, SANE_UNFIX (s->val[OPT_BR_X].w));
6254141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6255141cc406Sopenharmony_ci    }
6256141cc406Sopenharmony_ci  if (s->val[OPT_TL_Y].w > s->val[OPT_BR_Y].w)
6257141cc406Sopenharmony_ci    {
6258141cc406Sopenharmony_ci      DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) "
6259141cc406Sopenharmony_ci	   "-- aborting\n",
6260141cc406Sopenharmony_ci	   s->opt[OPT_TL_Y].title, SANE_UNFIX (s->val[OPT_TL_Y].w),
6261141cc406Sopenharmony_ci	   s->opt[OPT_BR_Y].title, SANE_UNFIX (s->val[OPT_BR_Y].w));
6262141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6263141cc406Sopenharmony_ci    }
6264141cc406Sopenharmony_ci
6265141cc406Sopenharmony_ci  s->total_bytes = 0;
6266141cc406Sopenharmony_ci
6267141cc406Sopenharmony_ci  if (s->fd < 0)
6268141cc406Sopenharmony_ci    {
6269141cc406Sopenharmony_ci      /* this is the first (and maybe only) pass... */
6270141cc406Sopenharmony_ci      SANE_String_Const mode;
6271141cc406Sopenharmony_ci      struct timeval start;
6272141cc406Sopenharmony_ci
6273141cc406Sopenharmony_ci      /* save start time */
6274141cc406Sopenharmony_ci      gettimeofday (&start, 0);
6275141cc406Sopenharmony_ci      s->start_time = start.tv_sec;
6276141cc406Sopenharmony_ci      /* translate options into s->mode for convenient access: */
6277141cc406Sopenharmony_ci      mode = s->val[OPT_MODE].s;
6278141cc406Sopenharmony_ci      if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
6279141cc406Sopenharmony_ci	s->mode = MUSTEK_MODE_LINEART;
6280141cc406Sopenharmony_ci      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
6281141cc406Sopenharmony_ci	s->mode = MUSTEK_MODE_HALFTONE;
6282141cc406Sopenharmony_ci      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
6283141cc406Sopenharmony_ci	s->mode = MUSTEK_MODE_GRAY;
6284141cc406Sopenharmony_ci      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
6285141cc406Sopenharmony_ci	s->mode = MUSTEK_MODE_COLOR;
6286141cc406Sopenharmony_ci
6287141cc406Sopenharmony_ci      /* scanner dependent specials */
6288141cc406Sopenharmony_ci      s->one_pass_color_scan = SANE_FALSE;
6289141cc406Sopenharmony_ci      if ((s->mode & MUSTEK_MODE_COLOR)
6290141cc406Sopenharmony_ci	  && !(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
6291141cc406Sopenharmony_ci	{
6292141cc406Sopenharmony_ci	  s->one_pass_color_scan = SANE_TRUE;
6293141cc406Sopenharmony_ci	}
6294141cc406Sopenharmony_ci
6295141cc406Sopenharmony_ci      s->resolution_code = encode_resolution (s);
6296141cc406Sopenharmony_ci
6297141cc406Sopenharmony_ci      if (s->val[OPT_PREVIEW].w && s->val[OPT_FAST_PREVIEW].w)
6298141cc406Sopenharmony_ci	{
6299141cc406Sopenharmony_ci	  if (s->hw->flags & MUSTEK_FLAG_THREE_PASS)
6300141cc406Sopenharmony_ci	    {
6301141cc406Sopenharmony_ci	      if (s->mode & MUSTEK_MODE_COLOR)
6302141cc406Sopenharmony_ci		{
6303141cc406Sopenharmony_ci		  /* Force gray-scale mode when previewing.  */
6304141cc406Sopenharmony_ci		  s->mode = MUSTEK_MODE_GRAY;
6305141cc406Sopenharmony_ci		  s->params.format = SANE_FRAME_GRAY;
6306141cc406Sopenharmony_ci		  s->params.bytes_per_line = s->params.pixels_per_line;
6307141cc406Sopenharmony_ci		  s->params.last_frame = SANE_TRUE;
6308141cc406Sopenharmony_ci		}
6309141cc406Sopenharmony_ci	    }
6310141cc406Sopenharmony_ci	  else if (s->hw->flags & MUSTEK_FLAG_SE)
6311141cc406Sopenharmony_ci	    {
6312141cc406Sopenharmony_ci	      /* use 36 dpi color in any case */
6313141cc406Sopenharmony_ci	      s->mode = MUSTEK_MODE_COLOR;
6314141cc406Sopenharmony_ci	      s->params.format = SANE_FRAME_RGB;
6315141cc406Sopenharmony_ci	      s->params.depth = 8;
6316141cc406Sopenharmony_ci	      s->one_pass_color_scan = SANE_TRUE;
6317141cc406Sopenharmony_ci	      s->resolution_code = 36;
6318141cc406Sopenharmony_ci	    }
6319141cc406Sopenharmony_ci	  else if (s->hw->flags & MUSTEK_FLAG_PARAGON_1)
6320141cc406Sopenharmony_ci	    {
6321141cc406Sopenharmony_ci	      /* use 36 dpi */
6322141cc406Sopenharmony_ci	      s->resolution_code = 36;
6323141cc406Sopenharmony_ci	    }
6324141cc406Sopenharmony_ci	  else if (s->hw->flags & MUSTEK_FLAG_PRO)
6325141cc406Sopenharmony_ci	    {
6326141cc406Sopenharmony_ci	      /* use 30 dpi color mode */
6327141cc406Sopenharmony_ci	      s->mode = MUSTEK_MODE_COLOR;
6328141cc406Sopenharmony_ci	      s->params.format = SANE_FRAME_RGB;
6329141cc406Sopenharmony_ci	      s->params.depth = 8;
6330141cc406Sopenharmony_ci	      s->one_pass_color_scan = SANE_TRUE;
6331141cc406Sopenharmony_ci	      s->resolution_code = 30;
6332141cc406Sopenharmony_ci	    }
6333141cc406Sopenharmony_ci	  DBG (4, "sane_start: use fast preview (res=%d dpi)\n",
6334141cc406Sopenharmony_ci	       s->resolution_code);
6335141cc406Sopenharmony_ci	}
6336141cc406Sopenharmony_ci
6337141cc406Sopenharmony_ci      status = dev_open (s->hw->sane.name, s, sense_handler);
6338141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6339141cc406Sopenharmony_ci	return status;
6340141cc406Sopenharmony_ci    }
6341141cc406Sopenharmony_ci
6342141cc406Sopenharmony_ci  status = dev_wait_ready (s);
6343141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
6344141cc406Sopenharmony_ci    {
6345141cc406Sopenharmony_ci      DBG (1, "sane_start: wait_ready() failed: %s\n",
6346141cc406Sopenharmony_ci	   sane_strstatus (status));
6347141cc406Sopenharmony_ci      goto stop_scanner_and_return;
6348141cc406Sopenharmony_ci    }
6349141cc406Sopenharmony_ci
6350141cc406Sopenharmony_ci  if (!(s->hw->flags & MUSTEK_FLAG_SCSI_PP))
6351141cc406Sopenharmony_ci    {
6352141cc406Sopenharmony_ci      /* SCSI-over-parallel port doesn't seem to like being inquired here */
6353141cc406Sopenharmony_ci      status = inquiry (s);
6354141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6355141cc406Sopenharmony_ci	{
6356141cc406Sopenharmony_ci	  DBG (1, "sane_start: inquiry command failed: %s\n",
6357141cc406Sopenharmony_ci	       sane_strstatus (status));
6358141cc406Sopenharmony_ci	  goto stop_scanner_and_return;
6359141cc406Sopenharmony_ci	}
6360141cc406Sopenharmony_ci    }
6361141cc406Sopenharmony_ci
6362141cc406Sopenharmony_ci  if ((strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0) &&
6363141cc406Sopenharmony_ci      !(s->hw->flags & MUSTEK_FLAG_ADF_READY))
6364141cc406Sopenharmony_ci    {
6365141cc406Sopenharmony_ci      DBG (2, "sane_start: automatic document feeder is out of documents\n");
6366141cc406Sopenharmony_ci      status = SANE_STATUS_NO_DOCS;
6367141cc406Sopenharmony_ci      goto stop_scanner_and_return;
6368141cc406Sopenharmony_ci    }
6369141cc406Sopenharmony_ci
6370141cc406Sopenharmony_ci  if (s->hw->flags & MUSTEK_FLAG_SE)
6371141cc406Sopenharmony_ci    {
6372141cc406Sopenharmony_ci      status = set_window_se (s, 0);
6373141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6374141cc406Sopenharmony_ci	{
6375141cc406Sopenharmony_ci	  DBG (1, "sane_start: set window command failed: %s\n",
6376141cc406Sopenharmony_ci	       sane_strstatus (status));
6377141cc406Sopenharmony_ci	  goto stop_scanner_and_return;
6378141cc406Sopenharmony_ci	}
6379141cc406Sopenharmony_ci
6380141cc406Sopenharmony_ci      s->scanning = SANE_TRUE;
6381141cc406Sopenharmony_ci      s->cancelled = SANE_FALSE;
6382141cc406Sopenharmony_ci
6383141cc406Sopenharmony_ci      dev_wait_ready (s);
6384141cc406Sopenharmony_ci
6385141cc406Sopenharmony_ci      status = get_window (s, &s->params.bytes_per_line,
6386141cc406Sopenharmony_ci			   &s->params.lines, &s->params.pixels_per_line);
6387141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6388141cc406Sopenharmony_ci	{
6389141cc406Sopenharmony_ci	  DBG (1, "sane_start: get window command failed: %s\n",
6390141cc406Sopenharmony_ci	       sane_strstatus (status));
6391141cc406Sopenharmony_ci	  goto stop_scanner_and_return;
6392141cc406Sopenharmony_ci	}
6393141cc406Sopenharmony_ci
6394141cc406Sopenharmony_ci      status = calibration_se (s);
6395141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6396141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6397141cc406Sopenharmony_ci
6398141cc406Sopenharmony_ci      status = start_scan (s);
6399141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6400141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6401141cc406Sopenharmony_ci
6402141cc406Sopenharmony_ci      status = send_gamma_table_se (s);
6403141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6404141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6405141cc406Sopenharmony_ci    }
6406141cc406Sopenharmony_ci
6407141cc406Sopenharmony_ci  else if (s->hw->flags & MUSTEK_FLAG_PRO)
6408141cc406Sopenharmony_ci    {
6409141cc406Sopenharmony_ci
6410141cc406Sopenharmony_ci      status = dev_wait_ready (s);
6411141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6412141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6413141cc406Sopenharmony_ci
6414141cc406Sopenharmony_ci      status = set_window_pro (s);
6415141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6416141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6417141cc406Sopenharmony_ci
6418141cc406Sopenharmony_ci      s->scanning = SANE_TRUE;
6419141cc406Sopenharmony_ci      s->cancelled = SANE_FALSE;
6420141cc406Sopenharmony_ci
6421141cc406Sopenharmony_ci      status = adf_and_backtrack (s);
6422141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6423141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6424141cc406Sopenharmony_ci
6425141cc406Sopenharmony_ci      status = mode_select_pro (s);
6426141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6427141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6428141cc406Sopenharmony_ci
6429141cc406Sopenharmony_ci      status = scsi_sense_wait_ready (s);
6430141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6431141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6432141cc406Sopenharmony_ci
6433141cc406Sopenharmony_ci      status = calibration_pro (s);
6434141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6435141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6436141cc406Sopenharmony_ci
6437141cc406Sopenharmony_ci      status = send_gamma_table (s);
6438141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6439141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6440141cc406Sopenharmony_ci
6441141cc406Sopenharmony_ci      status = start_scan (s);
6442141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6443141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6444141cc406Sopenharmony_ci
6445141cc406Sopenharmony_ci      status = get_image_status (s, &s->params.bytes_per_line,
6446141cc406Sopenharmony_ci				 &s->params.lines);
6447141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6448141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6449141cc406Sopenharmony_ci
6450141cc406Sopenharmony_ci      status = scsi_sense_wait_ready (s);
6451141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6452141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6453141cc406Sopenharmony_ci    }
6454141cc406Sopenharmony_ci
6455141cc406Sopenharmony_ci  else				/* Paragon series */
6456141cc406Sopenharmony_ci    {
6457141cc406Sopenharmony_ci      status = area_and_windows (s);
6458141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6459141cc406Sopenharmony_ci	{
6460141cc406Sopenharmony_ci	  DBG (1, "sane_start: set scan area command failed: %s\n",
6461141cc406Sopenharmony_ci	       sane_strstatus (status));
6462141cc406Sopenharmony_ci	  goto stop_scanner_and_return;
6463141cc406Sopenharmony_ci	}
6464141cc406Sopenharmony_ci
6465141cc406Sopenharmony_ci      status = adf_and_backtrack (s);
6466141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6467141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6468141cc406Sopenharmony_ci
6469141cc406Sopenharmony_ci      if (s->one_pass_color_scan)
6470141cc406Sopenharmony_ci	{
6471141cc406Sopenharmony_ci	  status = mode_select_paragon (s, MUSTEK_CODE_RED);
6472141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
6473141cc406Sopenharmony_ci	    goto stop_scanner_and_return;
6474141cc406Sopenharmony_ci
6475141cc406Sopenharmony_ci	  status = mode_select_paragon (s, MUSTEK_CODE_GREEN);
6476141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
6477141cc406Sopenharmony_ci	    goto stop_scanner_and_return;
6478141cc406Sopenharmony_ci
6479141cc406Sopenharmony_ci	  status = mode_select_paragon (s, MUSTEK_CODE_BLUE);
6480141cc406Sopenharmony_ci	}
6481141cc406Sopenharmony_ci      else
6482141cc406Sopenharmony_ci	status = mode_select_paragon (s, MUSTEK_CODE_GRAY);
6483141cc406Sopenharmony_ci
6484141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6485141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6486141cc406Sopenharmony_ci
6487141cc406Sopenharmony_ci      s->scanning = SANE_TRUE;
6488141cc406Sopenharmony_ci      s->cancelled = SANE_FALSE;
6489141cc406Sopenharmony_ci
6490141cc406Sopenharmony_ci      status = send_gamma_table (s);
6491141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6492141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6493141cc406Sopenharmony_ci
6494141cc406Sopenharmony_ci      status = start_scan (s);
6495141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6496141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6497141cc406Sopenharmony_ci
6498141cc406Sopenharmony_ci      if (!(s->hw->flags & MUSTEK_FLAG_SCSI_PP))
6499141cc406Sopenharmony_ci	{
6500141cc406Sopenharmony_ci	  /* This second gamma table download upsets the SCSI-over-parallel models */
6501141cc406Sopenharmony_ci	  status = send_gamma_table (s);
6502141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
6503141cc406Sopenharmony_ci	    goto stop_scanner_and_return;
6504141cc406Sopenharmony_ci	}
6505141cc406Sopenharmony_ci
6506141cc406Sopenharmony_ci      s->ld.max_value = 0;
6507141cc406Sopenharmony_ci      if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
6508141cc406Sopenharmony_ci	{
6509141cc406Sopenharmony_ci	  status = line_distance (s);
6510141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
6511141cc406Sopenharmony_ci	    goto stop_scanner_and_return;
6512141cc406Sopenharmony_ci	}
6513141cc406Sopenharmony_ci
6514141cc406Sopenharmony_ci      status = get_image_status (s, &s->params.bytes_per_line,
6515141cc406Sopenharmony_ci				 &s->params.lines);
6516141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
6517141cc406Sopenharmony_ci	goto stop_scanner_and_return;
6518141cc406Sopenharmony_ci
6519141cc406Sopenharmony_ci      if ((strcmp (s->val[OPT_SOURCE].s, "Automatic Document Feeder") == 0)
6520141cc406Sopenharmony_ci	  && (s->hw->flags & MUSTEK_FLAG_PARAGON_2))
6521141cc406Sopenharmony_ci	{
6522141cc406Sopenharmony_ci	  status = paragon_2_get_adf_status (s);
6523141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
6524141cc406Sopenharmony_ci	    goto stop_scanner_and_return;
6525141cc406Sopenharmony_ci	}
6526141cc406Sopenharmony_ci    }
6527141cc406Sopenharmony_ci
6528141cc406Sopenharmony_ci  s->params.pixels_per_line = s->params.bytes_per_line;
6529141cc406Sopenharmony_ci  if (s->one_pass_color_scan)
6530141cc406Sopenharmony_ci    {
6531141cc406Sopenharmony_ci      if (strcmp (s->val[OPT_BIT_DEPTH].s, "12") == 0)
6532141cc406Sopenharmony_ci	s->params.pixels_per_line /= 6;
6533141cc406Sopenharmony_ci      else
6534141cc406Sopenharmony_ci	s->params.pixels_per_line /= 3;
6535141cc406Sopenharmony_ci    }
6536141cc406Sopenharmony_ci  else if ((s->mode & MUSTEK_MODE_LINEART)
6537141cc406Sopenharmony_ci	   || (s->mode & MUSTEK_MODE_HALFTONE))
6538141cc406Sopenharmony_ci    s->params.pixels_per_line *= 8;
6539141cc406Sopenharmony_ci
6540141cc406Sopenharmony_ci  s->line = 0;
6541141cc406Sopenharmony_ci
6542141cc406Sopenharmony_ci  /* don't call any SIGTERM or SIGCHLD handlers
6543141cc406Sopenharmony_ci     this is to stop xsane and other frontends from calling
6544141cc406Sopenharmony_ci     its quit handlers */
6545141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));
6546141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
6547141cc406Sopenharmony_ci  sigaction (SIGCHLD, &act, 0);
6548141cc406Sopenharmony_ci
6549141cc406Sopenharmony_ci  if (pipe (fds) < 0)
6550141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
6551141cc406Sopenharmony_ci
6552141cc406Sopenharmony_ci  s->reader_fds = fds[1];
6553141cc406Sopenharmony_ci
6554141cc406Sopenharmony_ci  /* create reader routine as new process or thread */
6555141cc406Sopenharmony_ci  s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
6556141cc406Sopenharmony_ci
6557141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (s->reader_pid))
6558141cc406Sopenharmony_ci    {
6559141cc406Sopenharmony_ci      DBG (1, "sane_start: sanei_thread_begin failed (%s)\n",
6560141cc406Sopenharmony_ci	   strerror (errno));
6561141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
6562141cc406Sopenharmony_ci    }
6563141cc406Sopenharmony_ci
6564141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
6565141cc406Sopenharmony_ci    {
6566141cc406Sopenharmony_ci      close (s->reader_fds);
6567141cc406Sopenharmony_ci      s->reader_fds = -1;
6568141cc406Sopenharmony_ci    }
6569141cc406Sopenharmony_ci
6570141cc406Sopenharmony_ci  s->pipe = fds[0];
6571141cc406Sopenharmony_ci
6572141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6573141cc406Sopenharmony_ci
6574141cc406Sopenharmony_cistop_scanner_and_return:
6575141cc406Sopenharmony_ci  do_stop (s);
6576141cc406Sopenharmony_ci  return status;
6577141cc406Sopenharmony_ci}
6578141cc406Sopenharmony_ci
6579141cc406Sopenharmony_ciSANE_Status
6580141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
6581141cc406Sopenharmony_ci	   SANE_Int * len)
6582141cc406Sopenharmony_ci{
6583141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6584141cc406Sopenharmony_ci  SANE_Status status;
6585141cc406Sopenharmony_ci  ssize_t nread;
6586141cc406Sopenharmony_ci
6587141cc406Sopenharmony_ci
6588141cc406Sopenharmony_ci  if (!s)
6589141cc406Sopenharmony_ci    {
6590141cc406Sopenharmony_ci      DBG (1, "sane_read: handle is null!\n");
6591141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6592141cc406Sopenharmony_ci    }
6593141cc406Sopenharmony_ci
6594141cc406Sopenharmony_ci  if (!buf)
6595141cc406Sopenharmony_ci    {
6596141cc406Sopenharmony_ci      DBG (1, "sane_read: buf is null!\n");
6597141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6598141cc406Sopenharmony_ci    }
6599141cc406Sopenharmony_ci
6600141cc406Sopenharmony_ci  if (!len)
6601141cc406Sopenharmony_ci    {
6602141cc406Sopenharmony_ci      DBG (1, "sane_read: len is null!\n");
6603141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6604141cc406Sopenharmony_ci    }
6605141cc406Sopenharmony_ci
6606141cc406Sopenharmony_ci  DBG (5, "sane_read\n");
6607141cc406Sopenharmony_ci  *len = 0;
6608141cc406Sopenharmony_ci
6609141cc406Sopenharmony_ci  if (s->cancelled)
6610141cc406Sopenharmony_ci    {
6611141cc406Sopenharmony_ci      DBG (4, "sane_read: scan was cancelled\n");
6612141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
6613141cc406Sopenharmony_ci    }
6614141cc406Sopenharmony_ci
6615141cc406Sopenharmony_ci  if (!s->scanning)
6616141cc406Sopenharmony_ci    {
6617141cc406Sopenharmony_ci      DBG (3, "sane_read: must call sane_start before sane_read\n");
6618141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6619141cc406Sopenharmony_ci    }
6620141cc406Sopenharmony_ci
6621141cc406Sopenharmony_ci  while (*len < max_len)
6622141cc406Sopenharmony_ci    {
6623141cc406Sopenharmony_ci      nread = read (s->pipe, buf + *len, max_len - *len);
6624141cc406Sopenharmony_ci
6625141cc406Sopenharmony_ci      if (s->cancelled)
6626141cc406Sopenharmony_ci	{
6627141cc406Sopenharmony_ci	  DBG (4, "sane_read: scan was cancelled\n");
6628141cc406Sopenharmony_ci	  *len = 0;
6629141cc406Sopenharmony_ci	  return SANE_STATUS_CANCELLED;
6630141cc406Sopenharmony_ci	}
6631141cc406Sopenharmony_ci
6632141cc406Sopenharmony_ci      if (nread < 0)
6633141cc406Sopenharmony_ci	{
6634141cc406Sopenharmony_ci	  if (errno == EAGAIN)
6635141cc406Sopenharmony_ci	    {
6636141cc406Sopenharmony_ci	      if (*len == 0)
6637141cc406Sopenharmony_ci		DBG (5, "sane_read: no more data at the moment--try again\n");
6638141cc406Sopenharmony_ci	      else
6639141cc406Sopenharmony_ci		DBG (5, "sane_read: read buffer of %d bytes "
6640141cc406Sopenharmony_ci		     "(%d bytes total)\n", *len, s->total_bytes);
6641141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;
6642141cc406Sopenharmony_ci	    }
6643141cc406Sopenharmony_ci	  else
6644141cc406Sopenharmony_ci	    {
6645141cc406Sopenharmony_ci	      DBG (1, "sane_read: IO error\n");
6646141cc406Sopenharmony_ci	      do_stop (s);
6647141cc406Sopenharmony_ci	      *len = 0;
6648141cc406Sopenharmony_ci	      return SANE_STATUS_IO_ERROR;
6649141cc406Sopenharmony_ci	    }
6650141cc406Sopenharmony_ci	}
6651141cc406Sopenharmony_ci
6652141cc406Sopenharmony_ci      *len += nread;
6653141cc406Sopenharmony_ci      s->total_bytes += nread;
6654141cc406Sopenharmony_ci
6655141cc406Sopenharmony_ci      if (nread == 0)
6656141cc406Sopenharmony_ci	{
6657141cc406Sopenharmony_ci	  if (*len == 0)
6658141cc406Sopenharmony_ci	    {
6659141cc406Sopenharmony_ci	      if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS)
6660141cc406Sopenharmony_ci		  || !(s->mode & MUSTEK_MODE_COLOR) || ++s->pass >= 3)
6661141cc406Sopenharmony_ci		{
6662141cc406Sopenharmony_ci		  DBG (5, "sane_read: pipe was closed ... calling do_stop\n");
6663141cc406Sopenharmony_ci		  status = do_stop (s);
6664141cc406Sopenharmony_ci		  if (status != SANE_STATUS_CANCELLED
6665141cc406Sopenharmony_ci		      && status != SANE_STATUS_GOOD)
6666141cc406Sopenharmony_ci		    return status;	/* something went wrong */
6667141cc406Sopenharmony_ci		}
6668141cc406Sopenharmony_ci	      else		/* 3pass color first or second pass */
6669141cc406Sopenharmony_ci		{
6670141cc406Sopenharmony_ci		  DBG (5,
6671141cc406Sopenharmony_ci		       "sane_read: pipe was closed ... finishing pass %d\n",
6672141cc406Sopenharmony_ci		       s->pass);
6673141cc406Sopenharmony_ci		}
6674141cc406Sopenharmony_ci
6675141cc406Sopenharmony_ci	      return do_eof (s);
6676141cc406Sopenharmony_ci	    }
6677141cc406Sopenharmony_ci	  else
6678141cc406Sopenharmony_ci	    {
6679141cc406Sopenharmony_ci	      DBG (5, "sane_read: read last buffer of %d bytes "
6680141cc406Sopenharmony_ci		   "(%d bytes total)\n", *len, s->total_bytes);
6681141cc406Sopenharmony_ci	      return SANE_STATUS_GOOD;
6682141cc406Sopenharmony_ci	    }
6683141cc406Sopenharmony_ci	}
6684141cc406Sopenharmony_ci    }
6685141cc406Sopenharmony_ci  DBG (5, "sane_read: read full buffer of %d bytes (%d total bytes)\n",
6686141cc406Sopenharmony_ci       *len, s->total_bytes);
6687141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6688141cc406Sopenharmony_ci}
6689141cc406Sopenharmony_ci
6690141cc406Sopenharmony_civoid
6691141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
6692141cc406Sopenharmony_ci{
6693141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6694141cc406Sopenharmony_ci
6695141cc406Sopenharmony_ci  if (!s)
6696141cc406Sopenharmony_ci    {
6697141cc406Sopenharmony_ci      DBG (1, "sane_cancel: handle is null!\n");
6698141cc406Sopenharmony_ci      return;
6699141cc406Sopenharmony_ci    }
6700141cc406Sopenharmony_ci
6701141cc406Sopenharmony_ci  DBG (4, "sane_cancel\n");
6702141cc406Sopenharmony_ci  if (s->scanning)
6703141cc406Sopenharmony_ci    {
6704141cc406Sopenharmony_ci      s->cancelled = SANE_TRUE;
6705141cc406Sopenharmony_ci      do_stop (handle);
6706141cc406Sopenharmony_ci    }
6707141cc406Sopenharmony_ci  DBG (5, "sane_cancel: finished\n");
6708141cc406Sopenharmony_ci}
6709141cc406Sopenharmony_ci
6710141cc406Sopenharmony_ciSANE_Status
6711141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
6712141cc406Sopenharmony_ci{
6713141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6714141cc406Sopenharmony_ci
6715141cc406Sopenharmony_ci  if (!s)
6716141cc406Sopenharmony_ci    {
6717141cc406Sopenharmony_ci      DBG (1, "sane_set_io_mode: handle is null!\n");
6718141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6719141cc406Sopenharmony_ci    }
6720141cc406Sopenharmony_ci
6721141cc406Sopenharmony_ci  DBG (4, "sane_set_io_mode: %s\n",
6722141cc406Sopenharmony_ci       non_blocking ? "non-blocking" : "blocking");
6723141cc406Sopenharmony_ci
6724141cc406Sopenharmony_ci  if (!s->scanning)
6725141cc406Sopenharmony_ci    {
6726141cc406Sopenharmony_ci      DBG (1, "sane_set_io_mode: call sane_start before sane_set_io_mode");
6727141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6728141cc406Sopenharmony_ci    }
6729141cc406Sopenharmony_ci
6730141cc406Sopenharmony_ci  if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
6731141cc406Sopenharmony_ci    {
6732141cc406Sopenharmony_ci      DBG (1, "sane_set_io_mode: can't set io mode");
6733141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
6734141cc406Sopenharmony_ci    }
6735141cc406Sopenharmony_ci
6736141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6737141cc406Sopenharmony_ci}
6738141cc406Sopenharmony_ci
6739141cc406Sopenharmony_ciSANE_Status
6740141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
6741141cc406Sopenharmony_ci{
6742141cc406Sopenharmony_ci  Mustek_Scanner *s = handle;
6743141cc406Sopenharmony_ci
6744141cc406Sopenharmony_ci  if (!s)
6745141cc406Sopenharmony_ci    {
6746141cc406Sopenharmony_ci      DBG (1, "sane_get_select_fd: handle is null!\n");
6747141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6748141cc406Sopenharmony_ci    }
6749141cc406Sopenharmony_ci  if (!fd)
6750141cc406Sopenharmony_ci    {
6751141cc406Sopenharmony_ci      DBG (1, "sane_get_select_fd: fd is null!\n");
6752141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
6753141cc406Sopenharmony_ci    }
6754141cc406Sopenharmony_ci
6755141cc406Sopenharmony_ci  DBG (4, "sane_get_select_fd\n");
6756141cc406Sopenharmony_ci  if (!s->scanning)
6757141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
6758141cc406Sopenharmony_ci
6759141cc406Sopenharmony_ci  *fd = s->pipe;
6760141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
6761141cc406Sopenharmony_ci}
6762141cc406Sopenharmony_ci
6763141cc406Sopenharmony_ci#include "mustek_scsi_pp.c"
6764