1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002 Frank Zago (sane at zago dot net)
4141cc406Sopenharmony_ci   Copyright (C) 2002 Other SANE contributors
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/*
44141cc406Sopenharmony_ci   Sceptre S1200 SCSI scanner (sometimes also called S120)
45141cc406Sopenharmony_ci*/
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#define BUILD 10		/* 2002-03-21 */
50141cc406Sopenharmony_ci#define BACKEND_NAME sceptre
51141cc406Sopenharmony_ci#define SCEPTRE_CONFIG_FILE "sceptre.conf"
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#include "../include/sane/config.h"
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#include <errno.h>
59141cc406Sopenharmony_ci#include <fcntl.h>
60141cc406Sopenharmony_ci#include <limits.h>
61141cc406Sopenharmony_ci#include <signal.h>
62141cc406Sopenharmony_ci#include <stdio.h>
63141cc406Sopenharmony_ci#include <stdlib.h>
64141cc406Sopenharmony_ci#include <string.h>
65141cc406Sopenharmony_ci#include <sys/types.h>
66141cc406Sopenharmony_ci#include <sys/wait.h>
67141cc406Sopenharmony_ci#include <unistd.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_debug.h"
74141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
75141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
76141cc406Sopenharmony_ci#include "../include/lassert.h"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci#include "sceptre.h"
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_cistatic const SANE_String scan_mode_list[] = { LINEART_STR, HALFTONE_STR,
83141cc406Sopenharmony_ci  GRAY_STR, COLOR_STR, NULL
84141cc406Sopenharmony_ci};
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_cistatic const SANE_Range gamma_range = {
87141cc406Sopenharmony_ci  0,				/* minimum */
88141cc406Sopenharmony_ci  255,				/* maximum */
89141cc406Sopenharmony_ci  0				/* quantization */
90141cc406Sopenharmony_ci};
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_cistatic const SANE_Range threshold_range = {
93141cc406Sopenharmony_ci  0,				/* minimum */
94141cc406Sopenharmony_ci  255,				/* maximum */
95141cc406Sopenharmony_ci  0				/* quantization */
96141cc406Sopenharmony_ci};
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_cistatic const SANE_Range halftone_range = {
99141cc406Sopenharmony_ci  1,				/* minimum */
100141cc406Sopenharmony_ci  4,				/* maximum */
101141cc406Sopenharmony_ci  0				/* quantization */
102141cc406Sopenharmony_ci};
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci#define NUM_OF_RES 15
107141cc406Sopenharmony_ci/* Table of supported resolution and number of lines of color shifting. */
108141cc406Sopenharmony_cistatic const SANE_Word resolutions_list[NUM_OF_RES + 1] = {
109141cc406Sopenharmony_ci  NUM_OF_RES, 10, 25, 30, 45, 75, 90, 150, 300, 450, 600, 750, 900, 1050,
110141cc406Sopenharmony_ci  1125, 1200
111141cc406Sopenharmony_ci};
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_cistatic const SANE_Word color_shift_list[NUM_OF_RES + 1] = {
114141cc406Sopenharmony_ci  NUM_OF_RES, 0, 0, 0, 0, 1, 1, 2, 4, 6, 8, 10, 12, 14, 15, 16
115141cc406Sopenharmony_ci};
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_ci/* Define the supported scanners and their characteristics. */
120141cc406Sopenharmony_cistatic const struct scanners_supported scanners[] = {
121141cc406Sopenharmony_ci  /*      { 6, "KINPO   ", "Vividscan S600  ", "KINPO",   "S600" }, */
122141cc406Sopenharmony_ci  {6, "KINPO   ", "Vividscan S120  ", "Sceptre", "S1200"}
123141cc406Sopenharmony_ci};
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci/* List of scanner attached. */
128141cc406Sopenharmony_cistatic Sceptre_Scanner *first_dev = NULL;
129141cc406Sopenharmony_cistatic int num_devices = 0;
130141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci/* Local functions. */
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci/* Display a buffer in the log. */
136141cc406Sopenharmony_cistatic void
137141cc406Sopenharmony_cihexdump (int level, const char *comment, unsigned char *p, int l)
138141cc406Sopenharmony_ci{
139141cc406Sopenharmony_ci  int i;
140141cc406Sopenharmony_ci  char line[128];
141141cc406Sopenharmony_ci  char *ptr;
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
144141cc406Sopenharmony_ci  ptr = line;
145141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++)
146141cc406Sopenharmony_ci    {
147141cc406Sopenharmony_ci      if ((i % 16) == 0)
148141cc406Sopenharmony_ci	{
149141cc406Sopenharmony_ci	  if (ptr != line)
150141cc406Sopenharmony_ci	    {
151141cc406Sopenharmony_ci	      *ptr = '\0';
152141cc406Sopenharmony_ci	      DBG (level, "%s\n", line);
153141cc406Sopenharmony_ci	      ptr = line;
154141cc406Sopenharmony_ci	    }
155141cc406Sopenharmony_ci	  sprintf (ptr, "%3.3d:", i);
156141cc406Sopenharmony_ci	  ptr += 4;
157141cc406Sopenharmony_ci	}
158141cc406Sopenharmony_ci      sprintf (ptr, " %2.2x", *p);
159141cc406Sopenharmony_ci      ptr += 3;
160141cc406Sopenharmony_ci    }
161141cc406Sopenharmony_ci  *ptr = '\0';
162141cc406Sopenharmony_ci  DBG (level, "%s\n", line);
163141cc406Sopenharmony_ci}
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_ci/* Initialize a scanner entry. Return an allocated scanner with some
166141cc406Sopenharmony_ci * preset values. */
167141cc406Sopenharmony_cistatic Sceptre_Scanner *
168141cc406Sopenharmony_cisceptre_init (void)
169141cc406Sopenharmony_ci{
170141cc406Sopenharmony_ci  Sceptre_Scanner *dev;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_init: enter\n");
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
175141cc406Sopenharmony_ci  dev = malloc (sizeof (Sceptre_Scanner));
176141cc406Sopenharmony_ci  if (dev == NULL)
177141cc406Sopenharmony_ci    {
178141cc406Sopenharmony_ci      return NULL;
179141cc406Sopenharmony_ci    }
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci  memset (dev, 0, sizeof (Sceptre_Scanner));
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci  /* Allocate the buffer used to transfer the SCSI data. */
184141cc406Sopenharmony_ci  dev->buffer_size = 64 * 1024;
185141cc406Sopenharmony_ci  dev->buffer = malloc (dev->buffer_size);
186141cc406Sopenharmony_ci  if (dev->buffer == NULL)
187141cc406Sopenharmony_ci    {
188141cc406Sopenharmony_ci      free (dev);
189141cc406Sopenharmony_ci      return NULL;
190141cc406Sopenharmony_ci    }
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  dev->sfd = -1;
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_init: exit\n");
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci  return (dev);
197141cc406Sopenharmony_ci}
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci/* Closes an open scanner. */
200141cc406Sopenharmony_cistatic void
201141cc406Sopenharmony_cisceptre_close (Sceptre_Scanner * dev)
202141cc406Sopenharmony_ci{
203141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_close: enter\n");
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci  if (dev->sfd != -1)
206141cc406Sopenharmony_ci    {
207141cc406Sopenharmony_ci      sanei_scsi_close (dev->sfd);
208141cc406Sopenharmony_ci      dev->sfd = -1;
209141cc406Sopenharmony_ci    }
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_close: exit\n");
212141cc406Sopenharmony_ci}
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci/* Frees the memory used by a scanner. */
215141cc406Sopenharmony_cistatic void
216141cc406Sopenharmony_cisceptre_free (Sceptre_Scanner * dev)
217141cc406Sopenharmony_ci{
218141cc406Sopenharmony_ci  int i;
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_free: enter\n");
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci  if (dev == NULL)
223141cc406Sopenharmony_ci    return;
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci  sceptre_close (dev);
226141cc406Sopenharmony_ci  if (dev->devicename)
227141cc406Sopenharmony_ci    {
228141cc406Sopenharmony_ci      free (dev->devicename);
229141cc406Sopenharmony_ci    }
230141cc406Sopenharmony_ci  if (dev->buffer)
231141cc406Sopenharmony_ci    {
232141cc406Sopenharmony_ci      free (dev->buffer);
233141cc406Sopenharmony_ci    }
234141cc406Sopenharmony_ci  if (dev->image)
235141cc406Sopenharmony_ci    {
236141cc406Sopenharmony_ci      free (dev->image);
237141cc406Sopenharmony_ci    }
238141cc406Sopenharmony_ci  for (i = 1; i < OPT_NUM_OPTIONS; i++)
239141cc406Sopenharmony_ci    {
240141cc406Sopenharmony_ci      if (dev->opt[i].type == SANE_TYPE_STRING && dev->val[i].s)
241141cc406Sopenharmony_ci	{
242141cc406Sopenharmony_ci	  free (dev->val[i].s);
243141cc406Sopenharmony_ci	}
244141cc406Sopenharmony_ci    }
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci  free (dev);
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_free: exit\n");
249141cc406Sopenharmony_ci}
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci/* Inquiry a device and returns TRUE if is supported. */
252141cc406Sopenharmony_cistatic int
253141cc406Sopenharmony_cisceptre_identify_scanner (Sceptre_Scanner * dev)
254141cc406Sopenharmony_ci{
255141cc406Sopenharmony_ci  CDB cdb;
256141cc406Sopenharmony_ci  SANE_Status status;
257141cc406Sopenharmony_ci  size_t size;
258141cc406Sopenharmony_ci  int i;
259141cc406Sopenharmony_ci
260141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_identify_scanner: enter\n");
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci  size = 36;
263141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
264141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
265141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci  if (status)
268141cc406Sopenharmony_ci    {
269141cc406Sopenharmony_ci      DBG (DBG_error,
270141cc406Sopenharmony_ci	   "sceptre_identify_scanner: inquiry failed with status %s\n",
271141cc406Sopenharmony_ci	   sane_strstatus (status));
272141cc406Sopenharmony_ci      return (SANE_FALSE);
273141cc406Sopenharmony_ci    }
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci  if (size < 36)
276141cc406Sopenharmony_ci    {
277141cc406Sopenharmony_ci      DBG (DBG_error,
278141cc406Sopenharmony_ci	   "sceptre_identify_scanner: not enough data to identify device\n");
279141cc406Sopenharmony_ci      return (SANE_FALSE);
280141cc406Sopenharmony_ci    }
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci  dev->scsi_type = dev->buffer[0] & 0x1f;
283141cc406Sopenharmony_ci  memcpy (dev->scsi_vendor, dev->buffer + 0x08, 0x08);
284141cc406Sopenharmony_ci  dev->scsi_vendor[0x08] = 0;
285141cc406Sopenharmony_ci  memcpy (dev->scsi_product, dev->buffer + 0x10, 0x010);
286141cc406Sopenharmony_ci  dev->scsi_product[0x10] = 0;
287141cc406Sopenharmony_ci  memcpy (dev->scsi_version, dev->buffer + 0x20, 0x04);
288141cc406Sopenharmony_ci  dev->scsi_version[0x04] = 0;
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci  DBG (DBG_info, "device is \"%s\" \"%s\" \"%s\"\n",
291141cc406Sopenharmony_ci       dev->scsi_vendor, dev->scsi_product, dev->scsi_version);
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci  /* Lookup through the supported scanners table to find if this
294141cc406Sopenharmony_ci   * backend supports that one. */
295141cc406Sopenharmony_ci  for (i = 0; i < NELEMS (scanners); i++)
296141cc406Sopenharmony_ci    {
297141cc406Sopenharmony_ci      if (dev->scsi_type == scanners[i].scsi_type &&
298141cc406Sopenharmony_ci	  strcmp (dev->scsi_vendor, scanners[i].scsi_vendor) == 0 &&
299141cc406Sopenharmony_ci	  strcmp (dev->scsi_product, scanners[i].scsi_product) == 0)
300141cc406Sopenharmony_ci	{
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci	  DBG (DBG_error, "sceptre_identify_scanner: scanner supported\n");
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci	  dev->scnum = i;
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci	  return (SANE_TRUE);
307141cc406Sopenharmony_ci	}
308141cc406Sopenharmony_ci    }
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_identify_scanner: exit\n");
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  return (SANE_FALSE);
313141cc406Sopenharmony_ci}
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci/* Return the number of bytes left to read. */
316141cc406Sopenharmony_cistatic SANE_Status
317141cc406Sopenharmony_cisceptre_get_status (Sceptre_Scanner * dev, size_t * data_left)
318141cc406Sopenharmony_ci{
319141cc406Sopenharmony_ci  size_t size;
320141cc406Sopenharmony_ci  CDB cdb;
321141cc406Sopenharmony_ci  SANE_Status status;
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_get_status: enter\n");
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci  /* Get status. */
326141cc406Sopenharmony_ci  size = 0x10;
327141cc406Sopenharmony_ci  MKSCSI_GET_DATA_BUFFER_STATUS (cdb, 1, size);
328141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
329141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
332141cc406Sopenharmony_ci    {
333141cc406Sopenharmony_ci      DBG (DBG_error, "sceptre_get_status: cannot get buffer status\n");
334141cc406Sopenharmony_ci      *data_left = 0;
335141cc406Sopenharmony_ci      return (SANE_STATUS_IO_ERROR);
336141cc406Sopenharmony_ci    }
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci  if (size != 16)
339141cc406Sopenharmony_ci    {
340141cc406Sopenharmony_ci      DBG (DBG_error,
341141cc406Sopenharmony_ci	   "sceptre_get_status: invalid data size returned (%ld)\n",
342141cc406Sopenharmony_ci	   (long) size);
343141cc406Sopenharmony_ci      return (SANE_STATUS_IO_ERROR);
344141cc406Sopenharmony_ci    }
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  hexdump (DBG_info2, "GET BUFFER STATUS result", dev->buffer, 16);
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  /* Read the size left. The scanner returns the rest of the
349141cc406Sopenharmony_ci   * bytes to read, not just what's in its buffers. */
350141cc406Sopenharmony_ci  *data_left = B32TOI (&dev->buffer[8]);
351141cc406Sopenharmony_ci
352141cc406Sopenharmony_ci  if (dev->raster_real == 0)
353141cc406Sopenharmony_ci    {
354141cc406Sopenharmony_ci      /* First call. Set the correct parameters. */
355141cc406Sopenharmony_ci      dev->raster_real = B16TOI (&dev->buffer[12]) * 3;
356141cc406Sopenharmony_ci      dev->params.lines = B16TOI (&dev->buffer[12]);
357141cc406Sopenharmony_ci      dev->params.pixels_per_line = B16TOI (&dev->buffer[14]);
358141cc406Sopenharmony_ci    }
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_get_status: exit, data_left=%ld\n",
361141cc406Sopenharmony_ci       (long) *data_left);
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
364141cc406Sopenharmony_ci}
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci/*
367141cc406Sopenharmony_ci * Adjust the rasters. This function is used during a color scan,
368141cc406Sopenharmony_ci * because the scanner does not present a format sane can interpret
369141cc406Sopenharmony_ci * directly.
370141cc406Sopenharmony_ci *
371141cc406Sopenharmony_ci * The scanner sends the colors by rasters (R then G then B), whereas
372141cc406Sopenharmony_ci * sane is waiting for a group of 3 bytes per color. To make things
373141cc406Sopenharmony_ci * funnier, the rasters are shifted. This shift factor depends on the
374141cc406Sopenharmony_ci * resolution used. The format of those raster is:
375141cc406Sopenharmony_ci *   R...R RG...RG RGB...RGB BG...GB B...B
376141cc406Sopenharmony_ci *
377141cc406Sopenharmony_ci * So this function reorders all that mess. It gets the input from
378141cc406Sopenharmony_ci * dev->buffer and write the output in dev->image. size_in the the
379141cc406Sopenharmony_ci * length of the valid data in dev->buffer.
380141cc406Sopenharmony_ci */
381141cc406Sopenharmony_cistatic void
382141cc406Sopenharmony_cisceptre_adjust_raster (Sceptre_Scanner * dev, size_t size_in)
383141cc406Sopenharmony_ci{
384141cc406Sopenharmony_ci  int nb_rasters;		/* number of rasters in dev->buffer */
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  int raster;			/* current raster number in buffer */
387141cc406Sopenharmony_ci  int line;			/* line number for that raster */
388141cc406Sopenharmony_ci  int colour;			/* colour for that raster */
389141cc406Sopenharmony_ci  size_t offset;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_adjust_raster: enter\n");
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci  assert (dev->scan_mode == SCEPTRE_COLOR);
394141cc406Sopenharmony_ci  assert ((size_in % dev->params.bytes_per_line) == 0);
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci  if (size_in == 0)
397141cc406Sopenharmony_ci    {
398141cc406Sopenharmony_ci      return;
399141cc406Sopenharmony_ci    }
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  /*
402141cc406Sopenharmony_ci   * The color coding is one line for each color (in the RGB order).
403141cc406Sopenharmony_ci   * Recombine that stuff to create a RGB value for each pixel.
404141cc406Sopenharmony_ci   */
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci  nb_rasters = size_in / dev->raster_size;
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  for (raster = 0; raster < nb_rasters; raster++)
409141cc406Sopenharmony_ci    {
410141cc406Sopenharmony_ci
411141cc406Sopenharmony_ci      /*
412141cc406Sopenharmony_ci       * Find the color to which this raster belongs to.
413141cc406Sopenharmony_ci       *   0 = red
414141cc406Sopenharmony_ci       *   1 = green
415141cc406Sopenharmony_ci       *   2 = blue
416141cc406Sopenharmony_ci       *
417141cc406Sopenharmony_ci       * When blue comes, it always finishes the current line;
418141cc406Sopenharmony_ci       */
419141cc406Sopenharmony_ci      line = 0;
420141cc406Sopenharmony_ci      if (dev->raster_num < dev->color_shift)
421141cc406Sopenharmony_ci	{
422141cc406Sopenharmony_ci	  colour = 0;		/* Red */
423141cc406Sopenharmony_ci	  line = dev->raster_num;
424141cc406Sopenharmony_ci	}
425141cc406Sopenharmony_ci      else if (dev->raster_num < (3 * dev->color_shift))
426141cc406Sopenharmony_ci	{
427141cc406Sopenharmony_ci	  /* even = red, odd = green */
428141cc406Sopenharmony_ci	  colour = (dev->raster_num - dev->color_shift) % 2;
429141cc406Sopenharmony_ci	  if (colour)
430141cc406Sopenharmony_ci	    {
431141cc406Sopenharmony_ci	      /* Green */
432141cc406Sopenharmony_ci	      line = (dev->raster_num - dev->color_shift) / 2;
433141cc406Sopenharmony_ci	    }
434141cc406Sopenharmony_ci	  else
435141cc406Sopenharmony_ci	    {
436141cc406Sopenharmony_ci	      /* Red */
437141cc406Sopenharmony_ci	      line = (dev->raster_num + dev->color_shift) / 2;
438141cc406Sopenharmony_ci	    }
439141cc406Sopenharmony_ci	}
440141cc406Sopenharmony_ci      else if (dev->raster_num >= dev->raster_real - dev->color_shift)
441141cc406Sopenharmony_ci	{
442141cc406Sopenharmony_ci	  /* Blue */
443141cc406Sopenharmony_ci	  colour = 2;
444141cc406Sopenharmony_ci	  line = dev->line;
445141cc406Sopenharmony_ci	}
446141cc406Sopenharmony_ci      else if (dev->raster_num >= dev->raster_real - 3 * dev->color_shift)
447141cc406Sopenharmony_ci	{
448141cc406Sopenharmony_ci	  /* Green or Blue */
449141cc406Sopenharmony_ci	  colour =
450141cc406Sopenharmony_ci	    (dev->raster_real - dev->raster_num - dev->color_shift) % 2 + 1;
451141cc406Sopenharmony_ci	  if (colour == 1)
452141cc406Sopenharmony_ci	    {
453141cc406Sopenharmony_ci	      /* Green */
454141cc406Sopenharmony_ci	      line = dev->line + dev->color_shift;
455141cc406Sopenharmony_ci	    }
456141cc406Sopenharmony_ci	  else
457141cc406Sopenharmony_ci	    {
458141cc406Sopenharmony_ci	      /* Blue */
459141cc406Sopenharmony_ci	      line = dev->line;
460141cc406Sopenharmony_ci	    }
461141cc406Sopenharmony_ci	}
462141cc406Sopenharmony_ci      else
463141cc406Sopenharmony_ci	{
464141cc406Sopenharmony_ci	  colour = (dev->raster_num - 3 * dev->color_shift) % 3;
465141cc406Sopenharmony_ci	  switch (colour)
466141cc406Sopenharmony_ci	    {
467141cc406Sopenharmony_ci	    case 0:
468141cc406Sopenharmony_ci	      /* Red */
469141cc406Sopenharmony_ci	      line = (dev->raster_num + 3 * dev->color_shift) / 3;
470141cc406Sopenharmony_ci	      break;
471141cc406Sopenharmony_ci	    case 1:
472141cc406Sopenharmony_ci	      /* Green */
473141cc406Sopenharmony_ci	      line = dev->raster_num / 3;
474141cc406Sopenharmony_ci	      break;
475141cc406Sopenharmony_ci	    case 2:
476141cc406Sopenharmony_ci	      /* Blue */
477141cc406Sopenharmony_ci	      line = (dev->raster_num - 3 * dev->color_shift) / 3;
478141cc406Sopenharmony_ci	      break;
479141cc406Sopenharmony_ci	    }
480141cc406Sopenharmony_ci	}
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci      /* Adjust the line number relative to the image. */
483141cc406Sopenharmony_ci      line -= dev->line;
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci      offset = dev->image_end + line * dev->params.bytes_per_line;
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci      assert (offset <= (dev->image_size - dev->raster_size));
488141cc406Sopenharmony_ci
489141cc406Sopenharmony_ci      /* Copy the raster to the temporary image. */
490141cc406Sopenharmony_ci      {
491141cc406Sopenharmony_ci	int i;
492141cc406Sopenharmony_ci	unsigned char *src = dev->buffer + raster * dev->raster_size;
493141cc406Sopenharmony_ci	unsigned char *dest = dev->image + offset + colour;
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci	for (i = 0; i < dev->raster_size; i++)
496141cc406Sopenharmony_ci	  {
497141cc406Sopenharmony_ci	    *dest = *src;
498141cc406Sopenharmony_ci	    src++;
499141cc406Sopenharmony_ci	    dest += 3;
500141cc406Sopenharmony_ci	  }
501141cc406Sopenharmony_ci      }
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci      if (colour == 2)
504141cc406Sopenharmony_ci	{
505141cc406Sopenharmony_ci	  /* This blue raster completes a new line */
506141cc406Sopenharmony_ci	  dev->line++;
507141cc406Sopenharmony_ci	  dev->image_end += dev->params.bytes_per_line;
508141cc406Sopenharmony_ci	}
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci      dev->raster_num++;
511141cc406Sopenharmony_ci    }
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_adjust_raster: exit\n");
514141cc406Sopenharmony_ci}
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci/* SCSI sense handler. Callback for SANE.
517141cc406Sopenharmony_ci *
518141cc406Sopenharmony_ci * Since this scanner does not have REQUEST SENSE, it is always an
519141cc406Sopenharmony_ci * error if this function is called.*/
520141cc406Sopenharmony_cistatic SANE_Status
521141cc406Sopenharmony_cisceptre_sense_handler (int scsi_fd, unsigned char __sane_unused__ *result, void __sane_unused__ *arg)
522141cc406Sopenharmony_ci{
523141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_sense_handler (scsi_fd = %d)\n", scsi_fd);
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
526141cc406Sopenharmony_ci}
527141cc406Sopenharmony_ci
528141cc406Sopenharmony_ci/* Attach a scanner to this backend. */
529141cc406Sopenharmony_cistatic SANE_Status
530141cc406Sopenharmony_ciattach_scanner (const char *devicename, Sceptre_Scanner ** devp)
531141cc406Sopenharmony_ci{
532141cc406Sopenharmony_ci  Sceptre_Scanner *dev;
533141cc406Sopenharmony_ci  int sfd;
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "attach_scanner: %s\n", devicename);
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci  if (devp)
538141cc406Sopenharmony_ci    *devp = NULL;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci  /* Check if we know this device name. */
541141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
542141cc406Sopenharmony_ci    {
543141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
544141cc406Sopenharmony_ci	{
545141cc406Sopenharmony_ci	  if (devp)
546141cc406Sopenharmony_ci	    {
547141cc406Sopenharmony_ci	      *devp = dev;
548141cc406Sopenharmony_ci	    }
549141cc406Sopenharmony_ci	  DBG (DBG_info, "device is already known\n");
550141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
551141cc406Sopenharmony_ci	}
552141cc406Sopenharmony_ci    }
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
555141cc406Sopenharmony_ci  dev = sceptre_init ();
556141cc406Sopenharmony_ci  if (dev == NULL)
557141cc406Sopenharmony_ci    {
558141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: not enough memory\n");
559141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
560141cc406Sopenharmony_ci    }
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci  DBG (DBG_info, "attach_scanner: opening %s\n", devicename);
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, sceptre_sense_handler, dev) != 0)
565141cc406Sopenharmony_ci    {
566141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: attach_scanner: open failed\n");
567141cc406Sopenharmony_ci      sceptre_free (dev);
568141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
569141cc406Sopenharmony_ci    }
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci  /* Fill some scanner specific values. */
572141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
573141cc406Sopenharmony_ci  dev->sfd = sfd;
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ci  /* Now, check that it is a scanner we support. */
576141cc406Sopenharmony_ci  if (sceptre_identify_scanner (dev) == SANE_FALSE)
577141cc406Sopenharmony_ci    {
578141cc406Sopenharmony_ci      DBG (DBG_error,
579141cc406Sopenharmony_ci	   "ERROR: attach_scanner: scanner-identification failed\n");
580141cc406Sopenharmony_ci      sceptre_free (dev);
581141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
582141cc406Sopenharmony_ci    }
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_ci  sceptre_close (dev);
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_ci  /* Set the default options for that scanner. */
587141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
588141cc406Sopenharmony_ci  dev->sane.vendor = scanners[dev->scnum].real_vendor;
589141cc406Sopenharmony_ci  dev->sane.model = scanners[dev->scnum].real_product;
590141cc406Sopenharmony_ci  dev->sane.type = SANE_I18N ("flatbed scanner");
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci  dev->resolution_range.min = SANE_FIX (50);
593141cc406Sopenharmony_ci  dev->resolution_range.max = SANE_FIX (1200);
594141cc406Sopenharmony_ci  dev->resolution_range.quant = SANE_FIX (1);
595141cc406Sopenharmony_ci
596141cc406Sopenharmony_ci  /*
597141cc406Sopenharmony_ci   * The S1200 has an area of 8.5 inches / 11.7 inches. (A4 like)
598141cc406Sopenharmony_ci   * That's roughly 215*297 mm
599141cc406Sopenharmony_ci   * The values are coded by
600141cc406Sopenharmony_ci   *    size in inch * 600 dpi.
601141cc406Sopenharmony_ci   * The maximums are:
602141cc406Sopenharmony_ci   *   X:  8.5 inches * 600 = 5100 dots
603141cc406Sopenharmony_ci   *   Y: 11.7 inches * 600 = 7020
604141cc406Sopenharmony_ci   *                (although the windows driver stops at 7019)
605141cc406Sopenharmony_ci   *
606141cc406Sopenharmony_ci   * The values are stored in mm. Inches sucks anyway.
607141cc406Sopenharmony_ci   *   X: 5078 dots (22 dots lost)
608141cc406Sopenharmony_ci   *   Y: 7015 dots (5 dots lost)
609141cc406Sopenharmony_ci   *
610141cc406Sopenharmony_ci   * There seems to be a minimum area, but yet to be determined.
611141cc406Sopenharmony_ci   */
612141cc406Sopenharmony_ci  dev->x_range.min = SANE_FIX (0);
613141cc406Sopenharmony_ci  dev->x_range.max = SANE_FIX (215.90);	/* in mm */
614141cc406Sopenharmony_ci  dev->x_range.quant = 0;
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci  dev->y_range.min = SANE_FIX (0);
617141cc406Sopenharmony_ci  dev->y_range.max = SANE_FIX (297.14);	/* in mm */
618141cc406Sopenharmony_ci  dev->y_range.quant = SANE_FIX (0);
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci  /* Link the scanner with the others. */
621141cc406Sopenharmony_ci  dev->next = first_dev;
622141cc406Sopenharmony_ci  first_dev = dev;
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci  if (devp)
625141cc406Sopenharmony_ci    {
626141cc406Sopenharmony_ci      *devp = dev;
627141cc406Sopenharmony_ci    }
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci  num_devices++;
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci  DBG (DBG_proc, "attach_scanner: exit\n");
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
634141cc406Sopenharmony_ci}
635141cc406Sopenharmony_ci
636141cc406Sopenharmony_cistatic SANE_Status
637141cc406Sopenharmony_ciattach_one (const char *dev)
638141cc406Sopenharmony_ci{
639141cc406Sopenharmony_ci  attach_scanner (dev, NULL);
640141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
641141cc406Sopenharmony_ci}
642141cc406Sopenharmony_ci
643141cc406Sopenharmony_ci/* Reset the options for that scanner. */
644141cc406Sopenharmony_cistatic void
645141cc406Sopenharmony_cisceptre_init_options (Sceptre_Scanner * dev)
646141cc406Sopenharmony_ci{
647141cc406Sopenharmony_ci  int i;
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_init_options: enter\n");
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci  /* Pre-initialize the options. */
652141cc406Sopenharmony_ci  memset (dev->opt, 0, sizeof (dev->opt));
653141cc406Sopenharmony_ci  memset (dev->val, 0, sizeof (dev->val));
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci  for (i = 0; i < OPT_NUM_OPTIONS; ++i)
656141cc406Sopenharmony_ci    {
657141cc406Sopenharmony_ci      dev->opt[i].size = sizeof (SANE_Word);
658141cc406Sopenharmony_ci      dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
659141cc406Sopenharmony_ci    }
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci  /* Number of options. */
662141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
663141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
664141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
665141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
666141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
667141cc406Sopenharmony_ci  dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS;
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci  /* Mode group */
670141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
671141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].desc = "";	/* not valid for a group */
672141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
673141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].cap = 0;
674141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].size = 0;
675141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci  /* Scanner supported modes */
678141cc406Sopenharmony_ci  dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
679141cc406Sopenharmony_ci  dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
680141cc406Sopenharmony_ci  dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
681141cc406Sopenharmony_ci  dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
682141cc406Sopenharmony_ci  dev->opt[OPT_MODE].size = 30;	/* should define yet another max_string_size() */
683141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
684141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint.string_list =
685141cc406Sopenharmony_ci    (SANE_String_Const *) scan_mode_list;
686141cc406Sopenharmony_ci  dev->val[OPT_MODE].s = (SANE_Char *) strdup (scan_mode_list[0]);
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci  /* Common resolution */
689141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
690141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
691141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
692141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
693141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
694141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
695141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint.word_list = resolutions_list;
696141cc406Sopenharmony_ci  dev->val[OPT_RESOLUTION].w = 150;
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci  /* Geometry group */
699141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
700141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].desc = "";	/* not valid for a group */
701141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
702141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
703141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].size = 0;
704141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci  /* Upper left X */
707141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
708141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
709141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
710141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
711141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].unit = SANE_UNIT_MM;
712141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
713141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint.range = &(dev->x_range);
714141cc406Sopenharmony_ci  dev->val[OPT_TL_X].w = dev->x_range.min;
715141cc406Sopenharmony_ci
716141cc406Sopenharmony_ci  /* Upper left Y */
717141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
718141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
719141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
720141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
721141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
722141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
723141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint.range = &(dev->y_range);
724141cc406Sopenharmony_ci  dev->val[OPT_TL_Y].w = dev->y_range.min;
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci  /* bottom-right x */
727141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
728141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
729141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
730141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
731141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].unit = SANE_UNIT_MM;
732141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
733141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint.range = &(dev->x_range);
734141cc406Sopenharmony_ci  dev->val[OPT_BR_X].w = dev->x_range.max;
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci  /* bottom-right y */
737141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
738141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
739141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
740141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
741141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
742141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
743141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint.range = &(dev->y_range);
744141cc406Sopenharmony_ci  dev->val[OPT_BR_Y].w = dev->y_range.max;
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  /* Enhancement group */
747141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
748141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";	/* not valid for a group */
749141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
750141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
751141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
752141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci  /* custom-gamma table */
755141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
756141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
757141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
758141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
759141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
760141cc406Sopenharmony_ci  dev->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci  /* red gamma vector */
763141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
764141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
765141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
766141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
767141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
768141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
769141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].size = GAMMA_LENGTH * sizeof (SANE_Word);
770141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
771141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range;
772141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_R].wa = dev->gamma_R;
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  /* green gamma vector */
775141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
776141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
777141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
778141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
779141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
780141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
781141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].size = GAMMA_LENGTH * sizeof (SANE_Word);
782141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
783141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range;
784141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_G].wa = dev->gamma_G;
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci  /* blue gamma vector */
787141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
788141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
789141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
790141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
791141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
792141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
793141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].size = GAMMA_LENGTH * sizeof (SANE_Word);
794141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
795141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range;
796141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_B].wa = dev->gamma_B;
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci  /* Threshold */
799141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
800141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
801141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
802141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
803141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
804141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].size = sizeof (SANE_Int);
805141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
806141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
807141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].constraint.range = &threshold_range;
808141cc406Sopenharmony_ci  dev->val[OPT_THRESHOLD].w = 128;
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  /* Halftone pattern */
811141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
812141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
813141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
814141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_INT;
815141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].size = sizeof (SANE_Int);
816141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
817141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_RANGE;
818141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].constraint.range = &halftone_range;
819141cc406Sopenharmony_ci  dev->val[OPT_HALFTONE_PATTERN].w = 1;
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci  /* preview */
822141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
823141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
824141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
825141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
826141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
827141cc406Sopenharmony_ci  dev->val[OPT_PREVIEW].w = SANE_FALSE;
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  /* Lastly, set the default mode. This might change some values
830141cc406Sopenharmony_ci   * previously set here. */
831141cc406Sopenharmony_ci  sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE,
832141cc406Sopenharmony_ci		       (SANE_String *) COLOR_STR, NULL);
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_init_options: leave\n");
835141cc406Sopenharmony_ci}
836141cc406Sopenharmony_ci
837141cc406Sopenharmony_ci/* Wait until the scanner is ready.
838141cc406Sopenharmony_ci *
839141cc406Sopenharmony_ci * The only reason I know the scanner is not ready is because it is
840141cc406Sopenharmony_ci * moving the CCD.
841141cc406Sopenharmony_ci */
842141cc406Sopenharmony_cistatic SANE_Status
843141cc406Sopenharmony_cisceptre_wait_scanner (Sceptre_Scanner * dev)
844141cc406Sopenharmony_ci{
845141cc406Sopenharmony_ci  SANE_Status status;
846141cc406Sopenharmony_ci  int timeout;
847141cc406Sopenharmony_ci  CDB cdb;
848141cc406Sopenharmony_ci  size_t size;
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_wait_scanner: enter\n");
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_ci  MKSCSI_TEST_UNIT_READY (cdb);
853141cc406Sopenharmony_ci  cdb.data[4] = 1;		/* returns one byte. Non standard SCSI. */
854141cc406Sopenharmony_ci
855141cc406Sopenharmony_ci  /* Set the timeout to 120 seconds. */
856141cc406Sopenharmony_ci  timeout = 120;
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci  while (timeout > 0)
859141cc406Sopenharmony_ci    {
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci      /* test unit ready */
862141cc406Sopenharmony_ci      size = 1;			/* read one info byte */
863141cc406Sopenharmony_ci      status =
864141cc406Sopenharmony_ci	sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
865141cc406Sopenharmony_ci			 NULL, 0, dev->buffer, &size);
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD || size != 1)
868141cc406Sopenharmony_ci	{
869141cc406Sopenharmony_ci	  DBG (DBG_error, "sceptre_wait_scanner: TUR failed\n");
870141cc406Sopenharmony_ci	  return (SANE_STATUS_IO_ERROR);
871141cc406Sopenharmony_ci	}
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci      /* Apparently the scanner returns only 2 values:
874141cc406Sopenharmony_ci       *   0x00 - ready
875141cc406Sopenharmony_ci       *   0xff - not ready
876141cc406Sopenharmony_ci       */
877141cc406Sopenharmony_ci      if (dev->buffer[0] != 0x00)
878141cc406Sopenharmony_ci	{
879141cc406Sopenharmony_ci	  sleep (1);		/* wait 1 seconds */
880141cc406Sopenharmony_ci	  timeout--;
881141cc406Sopenharmony_ci	}
882141cc406Sopenharmony_ci      else
883141cc406Sopenharmony_ci	{
884141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
885141cc406Sopenharmony_ci	}
886141cc406Sopenharmony_ci    };
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_wait_scanner: scanner not ready\n");
889141cc406Sopenharmony_ci  return (SANE_STATUS_IO_ERROR);
890141cc406Sopenharmony_ci}
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci/* Diagnostic the scanner. */
893141cc406Sopenharmony_cistatic SANE_Status
894141cc406Sopenharmony_cisceptre_do_diag (Sceptre_Scanner * dev)
895141cc406Sopenharmony_ci{
896141cc406Sopenharmony_ci  SANE_Status status;
897141cc406Sopenharmony_ci  CDB cdb;
898141cc406Sopenharmony_ci  size_t size;
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_receive_diag enter\n");
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_ci  /* SEND DIAGNOSTIC. */
903141cc406Sopenharmony_ci  MKSCSI_SEND_DIAG (cdb, 0);
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci  /* The windows driver sets that field. This is non standard. */
906141cc406Sopenharmony_ci  cdb.data[2] = 0x80;
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
909141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
910141cc406Sopenharmony_ci    {
911141cc406Sopenharmony_ci      DBG (DBG_error, "sceptre_do_diag: exit, status=%d\n", status);
912141cc406Sopenharmony_ci      return (status);
913141cc406Sopenharmony_ci    }
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ci  /* RECEIVE DIAGNOSTIC */
916141cc406Sopenharmony_ci
917141cc406Sopenharmony_ci  /* The windows driver ask for 3 byte. This is non standard
918141cc406Sopenharmony_ci   * SCSI. The page returned should be at least 4 bytes. */
919141cc406Sopenharmony_ci  size = 3;
920141cc406Sopenharmony_ci  MKSCSI_RECEIVE_DIAG (cdb, 0, size);
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
923141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
926141cc406Sopenharmony_ci    {
927141cc406Sopenharmony_ci      DBG (DBG_error, "sceptre_do_diag: exit, status=%d\n", status);
928141cc406Sopenharmony_ci      return (status);
929141cc406Sopenharmony_ci    }
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_receive_diag exit\n");
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci  return (status);
934141cc406Sopenharmony_ci}
935141cc406Sopenharmony_ci
936141cc406Sopenharmony_ci/* I'm not sure if the command sent is really set mode. The SCSI
937141cc406Sopenharmony_ci * command used is MODE SELECT, but no data is sent. Again, this is
938141cc406Sopenharmony_ci * not standard. */
939141cc406Sopenharmony_cistatic SANE_Status
940141cc406Sopenharmony_cisceptre_set_mode (Sceptre_Scanner * dev)
941141cc406Sopenharmony_ci{
942141cc406Sopenharmony_ci  SANE_Status status;
943141cc406Sopenharmony_ci  CDB cdb;
944141cc406Sopenharmony_ci  size_t size;
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_set_mode: enter\n");
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci  size = 0x18;
949141cc406Sopenharmony_ci  MKSCSI_MODE_SELECT (cdb, 1, 0, size);
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_set_mode: exit, status=%d\n", status);
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci  return (status);
956141cc406Sopenharmony_ci}
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci/* Start a scan. */
959141cc406Sopenharmony_cistatic SANE_Status
960141cc406Sopenharmony_cisceptre_scan (Sceptre_Scanner * dev)
961141cc406Sopenharmony_ci{
962141cc406Sopenharmony_ci  CDB cdb;
963141cc406Sopenharmony_ci  SANE_Status status;
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_scan: enter\n");
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci  MKSCSI_SCAN (cdb);
968141cc406Sopenharmony_ci
969141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_scan: exit, status=%d\n", status);
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci  return status;
974141cc406Sopenharmony_ci}
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci/* Set a window. */
977141cc406Sopenharmony_cistatic SANE_Status
978141cc406Sopenharmony_cisceptre_set_window (Sceptre_Scanner * dev)
979141cc406Sopenharmony_ci{
980141cc406Sopenharmony_ci  size_t size;
981141cc406Sopenharmony_ci  CDB cdb;
982141cc406Sopenharmony_ci  unsigned char window[82];
983141cc406Sopenharmony_ci  SANE_Status status;
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_set_window: enter\n");
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci  size = sizeof (window);
988141cc406Sopenharmony_ci  MKSCSI_SET_WINDOW (cdb, size);
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci  memset (window, 0, size);
991141cc406Sopenharmony_ci
992141cc406Sopenharmony_ci  /* size of the parameters (74 = 0x4a bytes) */
993141cc406Sopenharmony_ci  window[7] = sizeof (window) - 8;
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci  /* X and Y resolution */
996141cc406Sopenharmony_ci  Ito16 (dev->resolution, &window[10]);
997141cc406Sopenharmony_ci  Ito16 (dev->resolution, &window[12]);
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci  /* Upper Left (X,Y) */
1000141cc406Sopenharmony_ci  Ito32 (dev->x_tl, &window[14]);
1001141cc406Sopenharmony_ci  Ito32 (dev->y_tl, &window[18]);
1002141cc406Sopenharmony_ci
1003141cc406Sopenharmony_ci  /* Width and length */
1004141cc406Sopenharmony_ci  Ito32 (dev->width, &window[22]);
1005141cc406Sopenharmony_ci  Ito32 (dev->length, &window[26]);
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci  /* Image Composition, Halftone and Depth */
1008141cc406Sopenharmony_ci  switch (dev->scan_mode)
1009141cc406Sopenharmony_ci    {
1010141cc406Sopenharmony_ci    case SCEPTRE_LINEART:
1011141cc406Sopenharmony_ci      window[31] = dev->val[OPT_THRESHOLD].w;
1012141cc406Sopenharmony_ci      window[33] = 0;
1013141cc406Sopenharmony_ci      window[34] = 1;
1014141cc406Sopenharmony_ci      window[36] = 0;
1015141cc406Sopenharmony_ci      break;
1016141cc406Sopenharmony_ci    case SCEPTRE_HALFTONE:
1017141cc406Sopenharmony_ci      window[31] = 0x80;
1018141cc406Sopenharmony_ci      window[33] = 0;
1019141cc406Sopenharmony_ci      window[34] = 1;
1020141cc406Sopenharmony_ci      window[36] = dev->val[OPT_HALFTONE_PATTERN].w;
1021141cc406Sopenharmony_ci      break;
1022141cc406Sopenharmony_ci    case SCEPTRE_GRAYSCALE:
1023141cc406Sopenharmony_ci      window[31] = 0x80;
1024141cc406Sopenharmony_ci      window[33] = 2;
1025141cc406Sopenharmony_ci      window[34] = 8;
1026141cc406Sopenharmony_ci      window[36] = 0;
1027141cc406Sopenharmony_ci      break;
1028141cc406Sopenharmony_ci    case SCEPTRE_COLOR:
1029141cc406Sopenharmony_ci      window[31] = 0x80;
1030141cc406Sopenharmony_ci      window[33] = 5;
1031141cc406Sopenharmony_ci      window[34] = 24;
1032141cc406Sopenharmony_ci      window[36] = 0;
1033141cc406Sopenharmony_ci      break;
1034141cc406Sopenharmony_ci    }
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci  /* Unknown parameters. They look constant in the windows driver. */
1037141cc406Sopenharmony_ci  window[30] = 0x04;
1038141cc406Sopenharmony_ci  window[32] = 0x04;
1039141cc406Sopenharmony_ci  window[37] = 0x80;		/* RIF, although it looks unused. */
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci  hexdump (DBG_info2, "windows", window, sizeof (window));
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1044141cc406Sopenharmony_ci			    window, sizeof (window), NULL, NULL);
1045141cc406Sopenharmony_ci
1046141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_set_window: exit, status=%d\n", status);
1047141cc406Sopenharmony_ci
1048141cc406Sopenharmony_ci  return status;
1049141cc406Sopenharmony_ci}
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci/* Read the image from the scanner and fill the temporary buffer with it. */
1052141cc406Sopenharmony_cistatic SANE_Status
1053141cc406Sopenharmony_cisceptre_fill_image (Sceptre_Scanner * dev)
1054141cc406Sopenharmony_ci{
1055141cc406Sopenharmony_ci  SANE_Status status;
1056141cc406Sopenharmony_ci  size_t size;
1057141cc406Sopenharmony_ci  CDB cdb;
1058141cc406Sopenharmony_ci  size_t data_left;
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_fill_image: enter\n");
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci  assert (dev->image_begin == dev->image_end);
1063141cc406Sopenharmony_ci  assert (dev->real_bytes_left > 0);
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci  /* Copy the complete lines, plus the imcompletes
1066141cc406Sopenharmony_ci   * ones. We don't keep the real end of data used
1067141cc406Sopenharmony_ci   * in image, so we copy the biggest possible.
1068141cc406Sopenharmony_ci   *
1069141cc406Sopenharmony_ci   * This is a no-op for non color images.
1070141cc406Sopenharmony_ci   */
1071141cc406Sopenharmony_ci  memmove (dev->image, dev->image + dev->image_begin, dev->raster_ahead);
1072141cc406Sopenharmony_ci  dev->image_begin = 0;
1073141cc406Sopenharmony_ci  dev->image_end = 0;
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci  while (dev->real_bytes_left)
1076141cc406Sopenharmony_ci    {
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci      if ((status = sceptre_get_status (dev, &data_left)) != SANE_STATUS_GOOD)
1079141cc406Sopenharmony_ci	{
1080141cc406Sopenharmony_ci	  return (status);
1081141cc406Sopenharmony_ci	}
1082141cc406Sopenharmony_ci
1083141cc406Sopenharmony_ci      /*
1084141cc406Sopenharmony_ci       * Try to read the maximum number of bytes.
1085141cc406Sopenharmony_ci       */
1086141cc406Sopenharmony_ci      size = data_left;
1087141cc406Sopenharmony_ci      if (size > dev->real_bytes_left)
1088141cc406Sopenharmony_ci	{
1089141cc406Sopenharmony_ci	  size = dev->real_bytes_left;
1090141cc406Sopenharmony_ci	}
1091141cc406Sopenharmony_ci      if (size > dev->image_size - dev->raster_ahead - dev->image_end)
1092141cc406Sopenharmony_ci	{
1093141cc406Sopenharmony_ci	  size = dev->image_size - dev->raster_ahead - dev->image_end;
1094141cc406Sopenharmony_ci	}
1095141cc406Sopenharmony_ci      if (size > dev->buffer_size)
1096141cc406Sopenharmony_ci	{
1097141cc406Sopenharmony_ci	  size = dev->buffer_size;
1098141cc406Sopenharmony_ci	}
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci      /* Round down to a multiple of line size. */
1101141cc406Sopenharmony_ci      size = size - (size % dev->params.bytes_per_line);
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci      if (size == 0)
1104141cc406Sopenharmony_ci	{
1105141cc406Sopenharmony_ci	  /* Probably reached the end of the buffer.
1106141cc406Sopenharmony_ci	   * Check, just in case. */
1107141cc406Sopenharmony_ci	  assert (dev->image_end != 0);
1108141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
1109141cc406Sopenharmony_ci	}
1110141cc406Sopenharmony_ci
1111141cc406Sopenharmony_ci      DBG (DBG_info, "sceptre_fill_image: to read   = %ld bytes (bpl=%d)\n",
1112141cc406Sopenharmony_ci	   (long) size, dev->params.bytes_per_line);
1113141cc406Sopenharmony_ci
1114141cc406Sopenharmony_ci      MKSCSI_READ_10 (cdb, 0, 0, size);
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci      hexdump (DBG_info2, "sceptre_fill_image: READ_10 CDB", cdb.data, 10);
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_ci      status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1119141cc406Sopenharmony_ci				NULL, 0, dev->buffer, &size);
1120141cc406Sopenharmony_ci
1121141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1122141cc406Sopenharmony_ci	{
1123141cc406Sopenharmony_ci	  DBG (DBG_error,
1124141cc406Sopenharmony_ci	       "sceptre_fill_image: cannot read from the scanner\n");
1125141cc406Sopenharmony_ci	  return status;
1126141cc406Sopenharmony_ci	}
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci      DBG (DBG_info, "sceptre_fill_image: real bytes left = %ld\n",
1129141cc406Sopenharmony_ci	   (long)dev->real_bytes_left);
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_ci      switch (dev->scan_mode)
1132141cc406Sopenharmony_ci	{
1133141cc406Sopenharmony_ci	case SCEPTRE_COLOR:
1134141cc406Sopenharmony_ci	  sceptre_adjust_raster (dev, size);
1135141cc406Sopenharmony_ci	  break;
1136141cc406Sopenharmony_ci	case SCEPTRE_LINEART:
1137141cc406Sopenharmony_ci	case SCEPTRE_HALFTONE:
1138141cc406Sopenharmony_ci	  {
1139141cc406Sopenharmony_ci	    /* Invert black and white. */
1140141cc406Sopenharmony_ci	    unsigned char *src = dev->buffer;
1141141cc406Sopenharmony_ci	    unsigned char *dest = dev->image + dev->image_end;
1142141cc406Sopenharmony_ci	    size_t i;
1143141cc406Sopenharmony_ci	    for (i = 0; i < size; i++)
1144141cc406Sopenharmony_ci	      {
1145141cc406Sopenharmony_ci		*dest = *src ^ 0xff;
1146141cc406Sopenharmony_ci		dest++;
1147141cc406Sopenharmony_ci		src++;
1148141cc406Sopenharmony_ci	      }
1149141cc406Sopenharmony_ci	    dev->image_end += size;
1150141cc406Sopenharmony_ci	  }
1151141cc406Sopenharmony_ci	  break;
1152141cc406Sopenharmony_ci	default:
1153141cc406Sopenharmony_ci	  memcpy (dev->image + dev->image_end, dev->buffer, size);
1154141cc406Sopenharmony_ci	  dev->image_end += size;
1155141cc406Sopenharmony_ci	}
1156141cc406Sopenharmony_ci
1157141cc406Sopenharmony_ci      dev->real_bytes_left -= size;
1158141cc406Sopenharmony_ci    }
1159141cc406Sopenharmony_ci
1160141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);	/* unreachable */
1161141cc406Sopenharmony_ci}
1162141cc406Sopenharmony_ci
1163141cc406Sopenharmony_ci/* Copy from the raw buffer to the buffer given by the backend.
1164141cc406Sopenharmony_ci *
1165141cc406Sopenharmony_ci * len in input is the maximum length available in buf, and, in
1166141cc406Sopenharmony_ci * output, is the length written into buf.
1167141cc406Sopenharmony_ci */
1168141cc406Sopenharmony_cistatic void
1169141cc406Sopenharmony_cisceptre_copy_raw_to_frontend (Sceptre_Scanner * dev, SANE_Byte * buf,
1170141cc406Sopenharmony_ci			      size_t * len)
1171141cc406Sopenharmony_ci{
1172141cc406Sopenharmony_ci  size_t size;
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci  size = dev->image_end - dev->image_begin;
1175141cc406Sopenharmony_ci  if (size > *len)
1176141cc406Sopenharmony_ci    {
1177141cc406Sopenharmony_ci      size = *len;
1178141cc406Sopenharmony_ci    }
1179141cc406Sopenharmony_ci  *len = size;
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci  memcpy (buf, dev->image + dev->image_begin, size);
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci  dev->image_begin += size;
1184141cc406Sopenharmony_ci}
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci/* Stop a scan. */
1187141cc406Sopenharmony_cistatic SANE_Status
1188141cc406Sopenharmony_cido_cancel (Sceptre_Scanner * dev)
1189141cc406Sopenharmony_ci{
1190141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel enter\n");
1191141cc406Sopenharmony_ci
1192141cc406Sopenharmony_ci  if (dev->scanning == SANE_TRUE)
1193141cc406Sopenharmony_ci    {
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci      /* Reposition the CCD. */
1196141cc406Sopenharmony_ci      dev->x_tl = 0;
1197141cc406Sopenharmony_ci      dev->x_tl = 0;
1198141cc406Sopenharmony_ci      dev->width = 0;
1199141cc406Sopenharmony_ci      dev->length = 0;
1200141cc406Sopenharmony_ci      sceptre_set_window (dev);
1201141cc406Sopenharmony_ci      sceptre_scan (dev);
1202141cc406Sopenharmony_ci
1203141cc406Sopenharmony_ci      sceptre_close (dev);
1204141cc406Sopenharmony_ci    }
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci  dev->scanning = SANE_FALSE;
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel exit\n");
1209141cc406Sopenharmony_ci
1210141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
1211141cc406Sopenharmony_ci}
1212141cc406Sopenharmony_ci
1213141cc406Sopenharmony_ci/* Start a scan. */
1214141cc406Sopenharmony_cistatic const SANE_Word gamma_init[GAMMA_LENGTH] = {
1215141cc406Sopenharmony_ci  0x00, 0x06, 0x0A, 0x0D, 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,
1216141cc406Sopenharmony_ci  0x21, 0x23, 0x25, 0x27,
1217141cc406Sopenharmony_ci  0x28, 0x2A, 0x2C, 0x2D, 0x2F, 0x30, 0x32, 0x33, 0x35, 0x36, 0x38, 0x39,
1218141cc406Sopenharmony_ci  0x3A, 0x3C, 0x3D, 0x3F,
1219141cc406Sopenharmony_ci  0x40, 0x41, 0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B, 0x4D, 0x4E,
1220141cc406Sopenharmony_ci  0x4F, 0x50, 0x51, 0x53,
1221141cc406Sopenharmony_ci  0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60,
1222141cc406Sopenharmony_ci  0x61, 0x62, 0x63, 0x64,
1223141cc406Sopenharmony_ci  0x65, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
1224141cc406Sopenharmony_ci  0x72, 0x73, 0x74, 0x75,
1225141cc406Sopenharmony_ci  0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7D, 0x7E, 0x7F, 0x80,
1226141cc406Sopenharmony_ci  0x81, 0x82, 0x83, 0x84,
1227141cc406Sopenharmony_ci  0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
1228141cc406Sopenharmony_ci  0x90, 0x91, 0x92, 0x92,
1229141cc406Sopenharmony_ci  0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
1230141cc406Sopenharmony_ci  0x9E, 0x9F, 0x9F, 0xA0,
1231141cc406Sopenharmony_ci  0xA1, 0xA2, 0xA3, 0xA4, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xA9, 0xAA,
1232141cc406Sopenharmony_ci  0xAB, 0xAC, 0xAD, 0xAD,
1233141cc406Sopenharmony_ci  0xAE, 0xAF, 0xB0, 0xB1, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB5, 0xB6, 0xB7,
1234141cc406Sopenharmony_ci  0xB8, 0xB9, 0xB9, 0xBA,
1235141cc406Sopenharmony_ci  0xBB, 0xBC, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC0, 0xC1, 0xC2, 0xC3, 0xC3,
1236141cc406Sopenharmony_ci  0xC4, 0xC5, 0xC6, 0xC6,
1237141cc406Sopenharmony_ci  0xC7, 0xC8, 0xC9, 0xC9, 0xCA, 0xCB, 0xCC, 0xCC, 0xCD, 0xCE, 0xCF, 0xCF,
1238141cc406Sopenharmony_ci  0xD0, 0xD1, 0xD2, 0xD2,
1239141cc406Sopenharmony_ci  0xD3, 0xD4, 0xD5, 0xD5, 0xD6, 0xD7, 0xD7, 0xD8, 0xD9, 0xDA, 0xDA, 0xDB,
1240141cc406Sopenharmony_ci  0xDC, 0xDC, 0xDD, 0xDE,
1241141cc406Sopenharmony_ci  0xDF, 0xDF, 0xE0, 0xE1, 0xE1, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5, 0xE6, 0xE6,
1242141cc406Sopenharmony_ci  0xE7, 0xE8, 0xE8, 0xE9,
1243141cc406Sopenharmony_ci  0xEA, 0xEB, 0xEB, 0xEC, 0xED, 0xED, 0xEE, 0xEF, 0xEF, 0xF0, 0xF1, 0xF1,
1244141cc406Sopenharmony_ci  0xF2, 0xF3, 0xF4, 0xF4,
1245141cc406Sopenharmony_ci  0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF8, 0xF9, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC,
1246141cc406Sopenharmony_ci  0xFD, 0xFE, 0xFE, 0xFF
1247141cc406Sopenharmony_ci};
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_cistatic SANE_Status
1250141cc406Sopenharmony_cisceptre_send_gamma (Sceptre_Scanner * dev)
1251141cc406Sopenharmony_ci{
1252141cc406Sopenharmony_ci  CDB cdb;
1253141cc406Sopenharmony_ci  int i;
1254141cc406Sopenharmony_ci  struct
1255141cc406Sopenharmony_ci  {
1256141cc406Sopenharmony_ci    unsigned char gamma_R[GAMMA_LENGTH];
1257141cc406Sopenharmony_ci    unsigned char gamma_G[GAMMA_LENGTH];
1258141cc406Sopenharmony_ci    unsigned char gamma_B[GAMMA_LENGTH];
1259141cc406Sopenharmony_ci  }
1260141cc406Sopenharmony_ci  param;
1261141cc406Sopenharmony_ci  size_t size;
1262141cc406Sopenharmony_ci  SANE_Status status;
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_send_gamma: enter\n");
1265141cc406Sopenharmony_ci
1266141cc406Sopenharmony_ci  size = sizeof (param);
1267141cc406Sopenharmony_ci
1268141cc406Sopenharmony_ci  assert (size == 0x300);
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  MKSCSI_SEND_10 (cdb, 0x03, 0x02, size);
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_ci  if (dev->val[OPT_CUSTOM_GAMMA].w)
1273141cc406Sopenharmony_ci    {
1274141cc406Sopenharmony_ci      /* Use the custom gamma. */
1275141cc406Sopenharmony_ci      for (i = 0; i < GAMMA_LENGTH; i++)
1276141cc406Sopenharmony_ci	{
1277141cc406Sopenharmony_ci	  param.gamma_R[i] = dev->gamma_R[i];
1278141cc406Sopenharmony_ci	  param.gamma_G[i] = dev->gamma_G[i];
1279141cc406Sopenharmony_ci	  param.gamma_B[i] = dev->gamma_B[i];
1280141cc406Sopenharmony_ci	}
1281141cc406Sopenharmony_ci    }
1282141cc406Sopenharmony_ci  else
1283141cc406Sopenharmony_ci    {
1284141cc406Sopenharmony_ci      for (i = 0; i < GAMMA_LENGTH; i++)
1285141cc406Sopenharmony_ci	{
1286141cc406Sopenharmony_ci	  param.gamma_R[i] = gamma_init[i];
1287141cc406Sopenharmony_ci	  param.gamma_G[i] = gamma_init[i];
1288141cc406Sopenharmony_ci	  param.gamma_B[i] = gamma_init[i];
1289141cc406Sopenharmony_ci	}
1290141cc406Sopenharmony_ci    }
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  hexdump (DBG_info2, "gamma", param.gamma_R, 3 * GAMMA_LENGTH);
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1295141cc406Sopenharmony_ci			    &param, sizeof (param), NULL, NULL);
1296141cc406Sopenharmony_ci
1297141cc406Sopenharmony_ci  DBG (DBG_proc, "sceptre_send_gamma: exit, status=%d\n", status);
1298141cc406Sopenharmony_ci
1299141cc406Sopenharmony_ci  return (status);
1300141cc406Sopenharmony_ci}
1301141cc406Sopenharmony_ci
1302141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci/* Entry points */
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ciSANE_Status
1307141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
1308141cc406Sopenharmony_ci{
1309141cc406Sopenharmony_ci  FILE *fp;
1310141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
1311141cc406Sopenharmony_ci  size_t len;
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci  DBG_INIT ();
1314141cc406Sopenharmony_ci
1315141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: enter\n");
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_ci  DBG (DBG_error, "This is sane-sceptre version %d.%d-%d\n", SANE_CURRENT_MAJOR,
1318141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD);
1319141cc406Sopenharmony_ci  DBG (DBG_error, "(C) 2002 by Frank Zago\n");
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci  if (version_code)
1322141cc406Sopenharmony_ci    {
1323141cc406Sopenharmony_ci      *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
1324141cc406Sopenharmony_ci    }
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  fp = sanei_config_open (SCEPTRE_CONFIG_FILE);
1327141cc406Sopenharmony_ci  if (!fp)
1328141cc406Sopenharmony_ci    {
1329141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
1330141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);
1331141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1332141cc406Sopenharmony_ci    }
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
1335141cc406Sopenharmony_ci    {
1336141cc406Sopenharmony_ci      if (dev_name[0] == '#')	/* ignore line comments */
1337141cc406Sopenharmony_ci	continue;
1338141cc406Sopenharmony_ci      len = strlen (dev_name);
1339141cc406Sopenharmony_ci
1340141cc406Sopenharmony_ci      if (!len)
1341141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
1342141cc406Sopenharmony_ci
1343141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
1344141cc406Sopenharmony_ci    }
1345141cc406Sopenharmony_ci
1346141cc406Sopenharmony_ci  fclose (fp);
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: leave\n");
1349141cc406Sopenharmony_ci
1350141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1351141cc406Sopenharmony_ci}
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ciSANE_Status
1354141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)
1355141cc406Sopenharmony_ci{
1356141cc406Sopenharmony_ci  Sceptre_Scanner *dev;
1357141cc406Sopenharmony_ci  int i;
1358141cc406Sopenharmony_ci
1359141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: enter\n");
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci  if (devlist)
1362141cc406Sopenharmony_ci    free (devlist);
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
1365141cc406Sopenharmony_ci  if (!devlist)
1366141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci  i = 0;
1369141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
1370141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
1371141cc406Sopenharmony_ci  devlist[i++] = 0;
1372141cc406Sopenharmony_ci
1373141cc406Sopenharmony_ci  *device_list = devlist;
1374141cc406Sopenharmony_ci
1375141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: exit\n");
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1378141cc406Sopenharmony_ci}
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ciSANE_Status
1381141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
1382141cc406Sopenharmony_ci{
1383141cc406Sopenharmony_ci  Sceptre_Scanner *dev;
1384141cc406Sopenharmony_ci  SANE_Status status;
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: enter\n");
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci  /* search for devicename */
1389141cc406Sopenharmony_ci  if (devicename[0])
1390141cc406Sopenharmony_ci    {
1391141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: devicename=%s\n", devicename);
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
1394141cc406Sopenharmony_ci	{
1395141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devicename) == 0)
1396141cc406Sopenharmony_ci	    {
1397141cc406Sopenharmony_ci	      break;
1398141cc406Sopenharmony_ci	    }
1399141cc406Sopenharmony_ci	}
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ci      if (!dev)
1402141cc406Sopenharmony_ci	{
1403141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
1404141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1405141cc406Sopenharmony_ci	    {
1406141cc406Sopenharmony_ci	      return status;
1407141cc406Sopenharmony_ci	    }
1408141cc406Sopenharmony_ci	}
1409141cc406Sopenharmony_ci    }
1410141cc406Sopenharmony_ci  else
1411141cc406Sopenharmony_ci    {
1412141cc406Sopenharmony_ci      DBG (DBG_sane_info, "sane_open: no devicename, opening first device\n");
1413141cc406Sopenharmony_ci      dev = first_dev;		/* empty devicename -> use first device */
1414141cc406Sopenharmony_ci    }
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci  if (!dev)
1417141cc406Sopenharmony_ci    {
1418141cc406Sopenharmony_ci      DBG (DBG_error, "No scanner found\n");
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1421141cc406Sopenharmony_ci    }
1422141cc406Sopenharmony_ci
1423141cc406Sopenharmony_ci  sceptre_init_options (dev);
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci  /* Initialize the gamma table. */
1426141cc406Sopenharmony_ci  memcpy (dev->gamma_R, gamma_init, dev->opt[OPT_GAMMA_VECTOR_R].size);
1427141cc406Sopenharmony_ci  memcpy (dev->gamma_G, gamma_init, dev->opt[OPT_GAMMA_VECTOR_G].size);
1428141cc406Sopenharmony_ci  memcpy (dev->gamma_B, gamma_init, dev->opt[OPT_GAMMA_VECTOR_B].size);
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ci  *handle = dev;
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: exit\n");
1433141cc406Sopenharmony_ci
1434141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1435141cc406Sopenharmony_ci}
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1438141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1439141cc406Sopenharmony_ci{
1440141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1441141cc406Sopenharmony_ci
1442141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: enter, option %d\n", option);
1443141cc406Sopenharmony_ci
1444141cc406Sopenharmony_ci  if ((unsigned) option >= OPT_NUM_OPTIONS)
1445141cc406Sopenharmony_ci    {
1446141cc406Sopenharmony_ci      return NULL;
1447141cc406Sopenharmony_ci    }
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
1450141cc406Sopenharmony_ci
1451141cc406Sopenharmony_ci  return dev->opt + option;
1452141cc406Sopenharmony_ci}
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ciSANE_Status
1455141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1456141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1457141cc406Sopenharmony_ci{
1458141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1459141cc406Sopenharmony_ci  SANE_Status status;
1460141cc406Sopenharmony_ci  SANE_Word cap;
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: enter, option %d, action %d\n",
1463141cc406Sopenharmony_ci       option, action);
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  if (info)
1466141cc406Sopenharmony_ci    {
1467141cc406Sopenharmony_ci      *info = 0;
1468141cc406Sopenharmony_ci    }
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci  if (dev->scanning)
1471141cc406Sopenharmony_ci    {
1472141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1473141cc406Sopenharmony_ci    }
1474141cc406Sopenharmony_ci
1475141cc406Sopenharmony_ci  if (option < 0 || option >= OPT_NUM_OPTIONS)
1476141cc406Sopenharmony_ci    {
1477141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1478141cc406Sopenharmony_ci    }
1479141cc406Sopenharmony_ci
1480141cc406Sopenharmony_ci  cap = dev->opt[option].cap;
1481141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
1482141cc406Sopenharmony_ci    {
1483141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1484141cc406Sopenharmony_ci    }
1485141cc406Sopenharmony_ci
1486141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1487141cc406Sopenharmony_ci    {
1488141cc406Sopenharmony_ci
1489141cc406Sopenharmony_ci      switch (option)
1490141cc406Sopenharmony_ci	{
1491141cc406Sopenharmony_ci	  /* word options */
1492141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1493141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1494141cc406Sopenharmony_ci	case OPT_TL_X:
1495141cc406Sopenharmony_ci	case OPT_TL_Y:
1496141cc406Sopenharmony_ci	case OPT_BR_X:
1497141cc406Sopenharmony_ci	case OPT_BR_Y:
1498141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1499141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1500141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
1501141cc406Sopenharmony_ci	case OPT_PREVIEW:
1502141cc406Sopenharmony_ci
1503141cc406Sopenharmony_ci	  *(SANE_Word *) val = dev->val[option].w;
1504141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1505141cc406Sopenharmony_ci
1506141cc406Sopenharmony_ci	  /* string options */
1507141cc406Sopenharmony_ci	case OPT_MODE:
1508141cc406Sopenharmony_ci	  strcpy (val, dev->val[option].s);
1509141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1512141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1513141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1514141cc406Sopenharmony_ci	  memcpy (val, dev->val[option].wa, dev->opt[option].size);
1515141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci	default:
1518141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1519141cc406Sopenharmony_ci	}
1520141cc406Sopenharmony_ci    }
1521141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1522141cc406Sopenharmony_ci    {
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
1525141cc406Sopenharmony_ci	{
1526141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, not settable\n");
1527141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1528141cc406Sopenharmony_ci	}
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci      status = sanei_constrain_value (dev->opt + option, val, info);
1531141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1532141cc406Sopenharmony_ci	{
1533141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, invalid value\n");
1534141cc406Sopenharmony_ci	  return status;
1535141cc406Sopenharmony_ci	}
1536141cc406Sopenharmony_ci
1537141cc406Sopenharmony_ci      switch (option)
1538141cc406Sopenharmony_ci	{
1539141cc406Sopenharmony_ci
1540141cc406Sopenharmony_ci	  /* Side-effect options */
1541141cc406Sopenharmony_ci	case OPT_TL_X:
1542141cc406Sopenharmony_ci	case OPT_TL_Y:
1543141cc406Sopenharmony_ci	case OPT_BR_X:
1544141cc406Sopenharmony_ci	case OPT_BR_Y:
1545141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1546141cc406Sopenharmony_ci	  if (info)
1547141cc406Sopenharmony_ci	    {
1548141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
1549141cc406Sopenharmony_ci	    }
1550141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1551141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1552141cc406Sopenharmony_ci
1553141cc406Sopenharmony_ci	  /* Side-effect free options */
1554141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1555141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
1556141cc406Sopenharmony_ci	case OPT_PREVIEW:
1557141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1558141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1559141cc406Sopenharmony_ci
1560141cc406Sopenharmony_ci	case OPT_MODE:
1561141cc406Sopenharmony_ci	  free (dev->val[OPT_MODE].s);
1562141cc406Sopenharmony_ci	  dev->val[OPT_MODE].s = (SANE_Char *) strdup (val);
1563141cc406Sopenharmony_ci
1564141cc406Sopenharmony_ci	  /* Set default options for the scan modes. */
1565141cc406Sopenharmony_ci	  dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1566141cc406Sopenharmony_ci	  dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1567141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1568141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1569141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1570141cc406Sopenharmony_ci	  dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1571141cc406Sopenharmony_ci
1572141cc406Sopenharmony_ci	  if (strcmp (dev->val[OPT_MODE].s, LINEART_STR) == 0)
1573141cc406Sopenharmony_ci	    {
1574141cc406Sopenharmony_ci	      dev->scan_mode = SCEPTRE_LINEART;
1575141cc406Sopenharmony_ci	      dev->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1576141cc406Sopenharmony_ci	    }
1577141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, HALFTONE_STR) == 0)
1578141cc406Sopenharmony_ci	    {
1579141cc406Sopenharmony_ci	      dev->scan_mode = SCEPTRE_HALFTONE;
1580141cc406Sopenharmony_ci	      dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
1581141cc406Sopenharmony_ci	    }
1582141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, GRAY_STR) == 0)
1583141cc406Sopenharmony_ci	    {
1584141cc406Sopenharmony_ci	      dev->scan_mode = SCEPTRE_GRAYSCALE;
1585141cc406Sopenharmony_ci	    }
1586141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, COLOR_STR) == 0)
1587141cc406Sopenharmony_ci	    {
1588141cc406Sopenharmony_ci	      dev->scan_mode = SCEPTRE_COLOR;
1589141cc406Sopenharmony_ci	      dev->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1590141cc406Sopenharmony_ci	      if (dev->val[OPT_CUSTOM_GAMMA].w)
1591141cc406Sopenharmony_ci		{
1592141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1593141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1594141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1595141cc406Sopenharmony_ci		}
1596141cc406Sopenharmony_ci	    }
1597141cc406Sopenharmony_ci
1598141cc406Sopenharmony_ci	  if (info)
1599141cc406Sopenharmony_ci	    {
1600141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1601141cc406Sopenharmony_ci	    }
1602141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1605141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1606141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1607141cc406Sopenharmony_ci	  memcpy (dev->val[option].wa, val, dev->opt[option].size);
1608141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1611141cc406Sopenharmony_ci	  dev->val[OPT_CUSTOM_GAMMA].w = *(SANE_Word *) val;
1612141cc406Sopenharmony_ci	  if (dev->val[OPT_CUSTOM_GAMMA].w)
1613141cc406Sopenharmony_ci	    {
1614141cc406Sopenharmony_ci	      /* use custom_gamma_table */
1615141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1616141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1617141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1618141cc406Sopenharmony_ci	    }
1619141cc406Sopenharmony_ci	  else
1620141cc406Sopenharmony_ci	    {
1621141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1622141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1623141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1624141cc406Sopenharmony_ci	    }
1625141cc406Sopenharmony_ci	  if (info)
1626141cc406Sopenharmony_ci	    {
1627141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS;
1628141cc406Sopenharmony_ci	    }
1629141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1630141cc406Sopenharmony_ci
1631141cc406Sopenharmony_ci	default:
1632141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1633141cc406Sopenharmony_ci	}
1634141cc406Sopenharmony_ci    }
1635141cc406Sopenharmony_ci
1636141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: exit, bad\n");
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1639141cc406Sopenharmony_ci}
1640141cc406Sopenharmony_ci
1641141cc406Sopenharmony_ciSANE_Status
1642141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1643141cc406Sopenharmony_ci{
1644141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1645141cc406Sopenharmony_ci  int x_dpi;			/* X-Resolution */
1646141cc406Sopenharmony_ci
1647141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: enter\n");
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci  if (!(dev->scanning))
1650141cc406Sopenharmony_ci    {
1651141cc406Sopenharmony_ci      /* Prepare the parameters for the caller. */
1652141cc406Sopenharmony_ci      memset (&dev->params, 0, sizeof (SANE_Parameters));
1653141cc406Sopenharmony_ci
1654141cc406Sopenharmony_ci      if (dev->val[OPT_PREVIEW].w == SANE_TRUE)
1655141cc406Sopenharmony_ci	{
1656141cc406Sopenharmony_ci	  dev->resolution = 30;	/* Windows TWAIN does 32 */
1657141cc406Sopenharmony_ci	  dev->x_tl = 0;
1658141cc406Sopenharmony_ci	  dev->y_tl = 0;
1659141cc406Sopenharmony_ci	  dev->x_br = mmToIlu (SANE_UNFIX (dev->x_range.max));
1660141cc406Sopenharmony_ci	  dev->y_br = mmToIlu (SANE_UNFIX (dev->y_range.max));
1661141cc406Sopenharmony_ci	}
1662141cc406Sopenharmony_ci      else
1663141cc406Sopenharmony_ci	{
1664141cc406Sopenharmony_ci	  /* Setup the parameters for the scan. These values will be re-used
1665141cc406Sopenharmony_ci	   * in the SET WINDOWS command. */
1666141cc406Sopenharmony_ci	  dev->resolution = dev->val[OPT_RESOLUTION].w;
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci	  dev->x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w));
1669141cc406Sopenharmony_ci	  dev->y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w));
1670141cc406Sopenharmony_ci	  dev->x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w));
1671141cc406Sopenharmony_ci	  dev->y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w));
1672141cc406Sopenharmony_ci	}
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci      /* Check the corners are OK. */
1675141cc406Sopenharmony_ci      if (dev->x_tl > dev->x_br)
1676141cc406Sopenharmony_ci	{
1677141cc406Sopenharmony_ci	  int s;
1678141cc406Sopenharmony_ci	  s = dev->x_tl;
1679141cc406Sopenharmony_ci	  dev->x_tl = dev->x_br;
1680141cc406Sopenharmony_ci	  dev->x_br = s;
1681141cc406Sopenharmony_ci	}
1682141cc406Sopenharmony_ci      if (dev->y_tl > dev->y_br)
1683141cc406Sopenharmony_ci	{
1684141cc406Sopenharmony_ci	  int s;
1685141cc406Sopenharmony_ci	  s = dev->y_tl;
1686141cc406Sopenharmony_ci	  dev->y_tl = dev->y_br;
1687141cc406Sopenharmony_ci	  dev->y_br = s;
1688141cc406Sopenharmony_ci	}
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci      dev->width = dev->x_br - dev->x_tl;
1691141cc406Sopenharmony_ci      dev->length = dev->y_br - dev->y_tl;
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci      /*
1694141cc406Sopenharmony_ci       * Adjust the "X Resolution".  The sceptre S1200 ignores the
1695141cc406Sopenharmony_ci       * Y-Resolution parameter in the windows block. X-Resolution
1696141cc406Sopenharmony_ci       * is used instead. However the limits are not the same for X
1697141cc406Sopenharmony_ci       * (600 dpi) and Y (1200 dpi).
1698141cc406Sopenharmony_ci       */
1699141cc406Sopenharmony_ci      x_dpi = dev->resolution;
1700141cc406Sopenharmony_ci      if (x_dpi > 600)
1701141cc406Sopenharmony_ci	{
1702141cc406Sopenharmony_ci	  x_dpi = 600;
1703141cc406Sopenharmony_ci	}
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci      /* Set depth */
1706141cc406Sopenharmony_ci      switch (dev->scan_mode)
1707141cc406Sopenharmony_ci	{
1708141cc406Sopenharmony_ci	case SCEPTRE_LINEART:
1709141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_GRAY;
1710141cc406Sopenharmony_ci	  dev->depth = 1;
1711141cc406Sopenharmony_ci	  break;
1712141cc406Sopenharmony_ci	case SCEPTRE_HALFTONE:
1713141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_GRAY;
1714141cc406Sopenharmony_ci	  dev->depth = 1;
1715141cc406Sopenharmony_ci	  break;
1716141cc406Sopenharmony_ci	case SCEPTRE_GRAYSCALE:
1717141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_GRAY;
1718141cc406Sopenharmony_ci	  dev->depth = 8;
1719141cc406Sopenharmony_ci	  break;
1720141cc406Sopenharmony_ci	case SCEPTRE_COLOR:
1721141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_RGB;
1722141cc406Sopenharmony_ci	  dev->depth = 8;
1723141cc406Sopenharmony_ci	  break;
1724141cc406Sopenharmony_ci	}
1725141cc406Sopenharmony_ci
1726141cc406Sopenharmony_ci      /* this scanner does only one pass */
1727141cc406Sopenharmony_ci      dev->params.last_frame = SANE_TRUE;
1728141cc406Sopenharmony_ci      dev->params.depth = dev->depth;
1729141cc406Sopenharmony_ci
1730141cc406Sopenharmony_ci      /* Compute the number of pixels, bytes per lines and lines. */
1731141cc406Sopenharmony_ci      switch (dev->scan_mode)
1732141cc406Sopenharmony_ci	{
1733141cc406Sopenharmony_ci	case SCEPTRE_LINEART:
1734141cc406Sopenharmony_ci	case SCEPTRE_HALFTONE:
1735141cc406Sopenharmony_ci	  dev->params.pixels_per_line = (dev->width * x_dpi) / 600;
1736141cc406Sopenharmony_ci	  dev->params.pixels_per_line &= ~0x7;	/* round down to 8 */
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci	  dev->params.bytes_per_line = (dev->params.pixels_per_line) / 8;
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci	  dev->params.lines = ((dev->length * dev->resolution) / 600);
1741141cc406Sopenharmony_ci	  if ((dev->params.lines) * 600 != (dev->length * dev->resolution))
1742141cc406Sopenharmony_ci	    {
1743141cc406Sopenharmony_ci	      /* Round up lines to 2. */
1744141cc406Sopenharmony_ci	      dev->params.lines &= ~1;
1745141cc406Sopenharmony_ci	      dev->params.lines += 2;
1746141cc406Sopenharmony_ci	    }
1747141cc406Sopenharmony_ci
1748141cc406Sopenharmony_ci	  break;
1749141cc406Sopenharmony_ci
1750141cc406Sopenharmony_ci	case SCEPTRE_GRAYSCALE:
1751141cc406Sopenharmony_ci	case SCEPTRE_COLOR:
1752141cc406Sopenharmony_ci	  /* pixels_per_line rounding rules:
1753141cc406Sopenharmony_ci	   *  2n + [0.0 .. 1.0]  -> round to 2n
1754141cc406Sopenharmony_ci	   *  2n + ]1.0 .. 2.0]  -> round to 2n + 2
1755141cc406Sopenharmony_ci	   */
1756141cc406Sopenharmony_ci	  dev->params.pixels_per_line = (dev->width * x_dpi) / 600;
1757141cc406Sopenharmony_ci	  if (dev->params.pixels_per_line & 1)
1758141cc406Sopenharmony_ci	    {
1759141cc406Sopenharmony_ci	      if ((dev->params.pixels_per_line * 600) == (dev->width * x_dpi))
1760141cc406Sopenharmony_ci		{
1761141cc406Sopenharmony_ci		  /* 2n */
1762141cc406Sopenharmony_ci		  dev->params.pixels_per_line--;
1763141cc406Sopenharmony_ci		}
1764141cc406Sopenharmony_ci	      else
1765141cc406Sopenharmony_ci		{
1766141cc406Sopenharmony_ci		  /* 2n+2 */
1767141cc406Sopenharmony_ci		  dev->params.pixels_per_line++;
1768141cc406Sopenharmony_ci		}
1769141cc406Sopenharmony_ci	    }
1770141cc406Sopenharmony_ci
1771141cc406Sopenharmony_ci	  dev->params.bytes_per_line = dev->params.pixels_per_line;
1772141cc406Sopenharmony_ci	  if (dev->scan_mode == SCEPTRE_COLOR)
1773141cc406Sopenharmony_ci	    dev->params.bytes_per_line *= 3;
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci	  /* lines number rounding rules:
1776141cc406Sopenharmony_ci	   *   2n + [0.0 .. 2.0[  -> round to 2n
1777141cc406Sopenharmony_ci	   *
1778141cc406Sopenharmony_ci	   * Note: the rounding is often incorrect at high
1779141cc406Sopenharmony_ci	   * resolution (ag more than 300dpi)
1780141cc406Sopenharmony_ci	   */
1781141cc406Sopenharmony_ci	  dev->params.lines = (dev->length * dev->resolution) / 600;
1782141cc406Sopenharmony_ci	  dev->params.lines &= ~1;
1783141cc406Sopenharmony_ci
1784141cc406Sopenharmony_ci	  break;
1785141cc406Sopenharmony_ci	}
1786141cc406Sopenharmony_ci
1787141cc406Sopenharmony_ci      /* Find the proper color shifting parameter. */
1788141cc406Sopenharmony_ci      if (dev->scan_mode == SCEPTRE_COLOR)
1789141cc406Sopenharmony_ci	{
1790141cc406Sopenharmony_ci	  int i = 1;
1791141cc406Sopenharmony_ci	  while (resolutions_list[i] != dev->resolution)
1792141cc406Sopenharmony_ci	    {
1793141cc406Sopenharmony_ci	      i++;
1794141cc406Sopenharmony_ci	    }
1795141cc406Sopenharmony_ci	  dev->color_shift = color_shift_list[i];
1796141cc406Sopenharmony_ci	}
1797141cc406Sopenharmony_ci      else
1798141cc406Sopenharmony_ci	{
1799141cc406Sopenharmony_ci	  dev->color_shift = 0;
1800141cc406Sopenharmony_ci	}
1801141cc406Sopenharmony_ci
1802141cc406Sopenharmony_ci      DBG (DBG_proc, "color_shift = %d\n", dev->color_shift);
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci      dev->bytes_left = dev->params.lines * dev->params.bytes_per_line;
1805141cc406Sopenharmony_ci    }
1806141cc406Sopenharmony_ci
1807141cc406Sopenharmony_ci  /* Return the current values. */
1808141cc406Sopenharmony_ci  if (params)
1809141cc406Sopenharmony_ci    {
1810141cc406Sopenharmony_ci      *params = (dev->params);
1811141cc406Sopenharmony_ci    }
1812141cc406Sopenharmony_ci
1813141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1816141cc406Sopenharmony_ci}
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ciSANE_Status
1819141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1820141cc406Sopenharmony_ci{
1821141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1822141cc406Sopenharmony_ci  SANE_Status status;
1823141cc406Sopenharmony_ci
1824141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: enter\n");
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci  if (!(dev->scanning))
1827141cc406Sopenharmony_ci    {
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci      sane_get_parameters (dev, NULL);
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ci      if (dev->image)
1832141cc406Sopenharmony_ci	{
1833141cc406Sopenharmony_ci	  free (dev->image);
1834141cc406Sopenharmony_ci	}
1835141cc406Sopenharmony_ci      /* Compute the length necessary in image. The first part will store
1836141cc406Sopenharmony_ci       * the complete lines, and the rest is used to stored ahead
1837141cc406Sopenharmony_ci       * rasters.
1838141cc406Sopenharmony_ci       */
1839141cc406Sopenharmony_ci      dev->raster_ahead =
1840141cc406Sopenharmony_ci	(2 * dev->color_shift + 1) * dev->params.bytes_per_line;
1841141cc406Sopenharmony_ci      dev->image_size = dev->buffer_size + dev->raster_ahead;
1842141cc406Sopenharmony_ci      dev->image = malloc (dev->image_size);
1843141cc406Sopenharmony_ci      if (dev->image == NULL)
1844141cc406Sopenharmony_ci	{
1845141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
1846141cc406Sopenharmony_ci	}
1847141cc406Sopenharmony_ci      dev->image_begin = 0;
1848141cc406Sopenharmony_ci      dev->image_end = 0;
1849141cc406Sopenharmony_ci
1850141cc406Sopenharmony_ci      dev->raster_size = dev->params.bytes_per_line / 3;
1851141cc406Sopenharmony_ci      dev->raster_num = 0;
1852141cc406Sopenharmony_ci      dev->raster_real = 0;
1853141cc406Sopenharmony_ci      dev->line = 0;
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci      /* Open again the scanner. */
1856141cc406Sopenharmony_ci      if (sanei_scsi_open
1857141cc406Sopenharmony_ci	  (dev->devicename, &(dev->sfd), sceptre_sense_handler, dev) != 0)
1858141cc406Sopenharmony_ci	{
1859141cc406Sopenharmony_ci	  DBG (DBG_error, "ERROR: sane_start: open failed\n");
1860141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1861141cc406Sopenharmony_ci	}
1862141cc406Sopenharmony_ci
1863141cc406Sopenharmony_ci      /* The scanner must be ready. */
1864141cc406Sopenharmony_ci      status = sceptre_wait_scanner (dev);
1865141cc406Sopenharmony_ci      if (status)
1866141cc406Sopenharmony_ci	{
1867141cc406Sopenharmony_ci	  sceptre_close (dev);
1868141cc406Sopenharmony_ci	  return status;
1869141cc406Sopenharmony_ci	}
1870141cc406Sopenharmony_ci
1871141cc406Sopenharmony_ci      status = sceptre_do_diag (dev);
1872141cc406Sopenharmony_ci      if (status)
1873141cc406Sopenharmony_ci	{
1874141cc406Sopenharmony_ci	  sceptre_close (dev);
1875141cc406Sopenharmony_ci	  return status;
1876141cc406Sopenharmony_ci	}
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci      status = sceptre_set_mode (dev);
1879141cc406Sopenharmony_ci      if (status)
1880141cc406Sopenharmony_ci	{
1881141cc406Sopenharmony_ci	  sceptre_close (dev);
1882141cc406Sopenharmony_ci	  return status;
1883141cc406Sopenharmony_ci	}
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci      status = sceptre_set_window (dev);
1886141cc406Sopenharmony_ci      if (status)
1887141cc406Sopenharmony_ci	{
1888141cc406Sopenharmony_ci	  sceptre_close (dev);
1889141cc406Sopenharmony_ci	  return status;
1890141cc406Sopenharmony_ci	}
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci      status = sceptre_send_gamma (dev);
1893141cc406Sopenharmony_ci      if (status)
1894141cc406Sopenharmony_ci	{
1895141cc406Sopenharmony_ci	  sceptre_close (dev);
1896141cc406Sopenharmony_ci	  return status;
1897141cc406Sopenharmony_ci	}
1898141cc406Sopenharmony_ci
1899141cc406Sopenharmony_ci      status = sceptre_scan (dev);
1900141cc406Sopenharmony_ci      if (status)
1901141cc406Sopenharmony_ci	{
1902141cc406Sopenharmony_ci	  sceptre_close (dev);
1903141cc406Sopenharmony_ci	  return status;
1904141cc406Sopenharmony_ci	}
1905141cc406Sopenharmony_ci
1906141cc406Sopenharmony_ci      status = sceptre_get_status (dev, &dev->real_bytes_left);
1907141cc406Sopenharmony_ci      if (status)
1908141cc406Sopenharmony_ci	{
1909141cc406Sopenharmony_ci	  sceptre_close (dev);
1910141cc406Sopenharmony_ci	  return status;
1911141cc406Sopenharmony_ci	}
1912141cc406Sopenharmony_ci
1913141cc406Sopenharmony_ci    }
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci  dev->bytes_left = dev->params.bytes_per_line * dev->params.lines;
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci  dev->scanning = SANE_TRUE;
1918141cc406Sopenharmony_ci
1919141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
1920141cc406Sopenharmony_ci
1921141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1922141cc406Sopenharmony_ci}
1923141cc406Sopenharmony_ci
1924141cc406Sopenharmony_ciSANE_Status
1925141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
1926141cc406Sopenharmony_ci	   SANE_Int * len)
1927141cc406Sopenharmony_ci{
1928141cc406Sopenharmony_ci  SANE_Status status;
1929141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1930141cc406Sopenharmony_ci  size_t size;
1931141cc406Sopenharmony_ci  int buf_offset;		/* offset into buf */
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: enter\n");
1934141cc406Sopenharmony_ci
1935141cc406Sopenharmony_ci  *len = 0;
1936141cc406Sopenharmony_ci
1937141cc406Sopenharmony_ci  if (!(dev->scanning))
1938141cc406Sopenharmony_ci    {
1939141cc406Sopenharmony_ci      /* OOPS, not scanning */
1940141cc406Sopenharmony_ci      return do_cancel (dev);
1941141cc406Sopenharmony_ci    }
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_ci  if (dev->bytes_left <= 0)
1944141cc406Sopenharmony_ci    {
1945141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
1946141cc406Sopenharmony_ci    }
1947141cc406Sopenharmony_ci
1948141cc406Sopenharmony_ci  buf_offset = 0;
1949141cc406Sopenharmony_ci
1950141cc406Sopenharmony_ci  do
1951141cc406Sopenharmony_ci    {
1952141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
1953141cc406Sopenharmony_ci	{
1954141cc406Sopenharmony_ci	  /* Fill image */
1955141cc406Sopenharmony_ci	  status = sceptre_fill_image (dev);
1956141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1957141cc406Sopenharmony_ci	    {
1958141cc406Sopenharmony_ci	      return (status);
1959141cc406Sopenharmony_ci	    }
1960141cc406Sopenharmony_ci	}
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci      /* Something must have been read */
1963141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
1964141cc406Sopenharmony_ci	{
1965141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_read: nothing read\n");
1966141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
1967141cc406Sopenharmony_ci	}
1968141cc406Sopenharmony_ci
1969141cc406Sopenharmony_ci      /* Copy the data to the frontend buffer. */
1970141cc406Sopenharmony_ci      size = max_len - buf_offset;
1971141cc406Sopenharmony_ci      if (size > dev->bytes_left)
1972141cc406Sopenharmony_ci	{
1973141cc406Sopenharmony_ci	  size = dev->bytes_left;
1974141cc406Sopenharmony_ci	}
1975141cc406Sopenharmony_ci      sceptre_copy_raw_to_frontend (dev, buf + buf_offset, &size);
1976141cc406Sopenharmony_ci
1977141cc406Sopenharmony_ci      buf_offset += size;
1978141cc406Sopenharmony_ci
1979141cc406Sopenharmony_ci      dev->bytes_left -= size;
1980141cc406Sopenharmony_ci      *len += size;
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci    }
1983141cc406Sopenharmony_ci  while ((buf_offset != max_len) && dev->bytes_left);
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci  DBG (DBG_info, "sane_read: leave, bytes_left=%ld\n", (long)dev->bytes_left);
1986141cc406Sopenharmony_ci
1987141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1988141cc406Sopenharmony_ci}
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_ciSANE_Status
1991141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking)
1992141cc406Sopenharmony_ci{
1993141cc406Sopenharmony_ci  SANE_Status status;
1994141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
1995141cc406Sopenharmony_ci
1996141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: enter\n");
1997141cc406Sopenharmony_ci
1998141cc406Sopenharmony_ci  if (dev->scanning == SANE_FALSE)
1999141cc406Sopenharmony_ci    {
2000141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
2001141cc406Sopenharmony_ci    }
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci  if (non_blocking == SANE_FALSE)
2004141cc406Sopenharmony_ci    {
2005141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2006141cc406Sopenharmony_ci    }
2007141cc406Sopenharmony_ci  else
2008141cc406Sopenharmony_ci    {
2009141cc406Sopenharmony_ci      status = SANE_STATUS_UNSUPPORTED;
2010141cc406Sopenharmony_ci    }
2011141cc406Sopenharmony_ci
2012141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: exit\n");
2013141cc406Sopenharmony_ci
2014141cc406Sopenharmony_ci  return status;
2015141cc406Sopenharmony_ci}
2016141cc406Sopenharmony_ci
2017141cc406Sopenharmony_ciSANE_Status
2018141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd)
2019141cc406Sopenharmony_ci{
2020141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: enter\n");
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: exit\n");
2023141cc406Sopenharmony_ci
2024141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2025141cc406Sopenharmony_ci}
2026141cc406Sopenharmony_ci
2027141cc406Sopenharmony_civoid
2028141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2029141cc406Sopenharmony_ci{
2030141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: enter\n");
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci  do_cancel (dev);
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: exit\n");
2037141cc406Sopenharmony_ci}
2038141cc406Sopenharmony_ci
2039141cc406Sopenharmony_civoid
2040141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2041141cc406Sopenharmony_ci{
2042141cc406Sopenharmony_ci  Sceptre_Scanner *dev = handle;
2043141cc406Sopenharmony_ci  Sceptre_Scanner *dev_tmp;
2044141cc406Sopenharmony_ci
2045141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: enter\n");
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ci  do_cancel (dev);
2048141cc406Sopenharmony_ci  sceptre_close (dev);
2049141cc406Sopenharmony_ci
2050141cc406Sopenharmony_ci  /* Unlink dev. */
2051141cc406Sopenharmony_ci  if (first_dev == dev)
2052141cc406Sopenharmony_ci    {
2053141cc406Sopenharmony_ci      first_dev = dev->next;
2054141cc406Sopenharmony_ci    }
2055141cc406Sopenharmony_ci  else
2056141cc406Sopenharmony_ci    {
2057141cc406Sopenharmony_ci      dev_tmp = first_dev;
2058141cc406Sopenharmony_ci      while (dev_tmp->next && dev_tmp->next != dev)
2059141cc406Sopenharmony_ci	{
2060141cc406Sopenharmony_ci	  dev_tmp = dev_tmp->next;
2061141cc406Sopenharmony_ci	}
2062141cc406Sopenharmony_ci      if (dev_tmp->next != NULL)
2063141cc406Sopenharmony_ci	{
2064141cc406Sopenharmony_ci	  dev_tmp->next = dev_tmp->next->next;
2065141cc406Sopenharmony_ci	}
2066141cc406Sopenharmony_ci    }
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci  sceptre_free (dev);
2069141cc406Sopenharmony_ci  num_devices--;
2070141cc406Sopenharmony_ci
2071141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: exit\n");
2072141cc406Sopenharmony_ci}
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_civoid
2075141cc406Sopenharmony_cisane_exit (void)
2076141cc406Sopenharmony_ci{
2077141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: enter\n");
2078141cc406Sopenharmony_ci
2079141cc406Sopenharmony_ci  while (first_dev)
2080141cc406Sopenharmony_ci    {
2081141cc406Sopenharmony_ci      sane_close (first_dev);
2082141cc406Sopenharmony_ci    }
2083141cc406Sopenharmony_ci
2084141cc406Sopenharmony_ci  if (devlist)
2085141cc406Sopenharmony_ci    {
2086141cc406Sopenharmony_ci      free (devlist);
2087141cc406Sopenharmony_ci      devlist = NULL;
2088141cc406Sopenharmony_ci    }
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
2091141cc406Sopenharmony_ci}
2092