1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002 Frank Zago (sane at zago dot net)
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci*/
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci/*
43141cc406Sopenharmony_ci   Some Relisys scanners AVEC and RELI series
44141cc406Sopenharmony_ci*/
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#define BUILD 10			/* 2004/02/08 */
49141cc406Sopenharmony_ci#define BACKEND_NAME teco1
50141cc406Sopenharmony_ci#define TECO_CONFIG_FILE "teco1.conf"
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci#include "../include/sane/config.h"
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#include <errno.h>
57141cc406Sopenharmony_ci#include <fcntl.h>
58141cc406Sopenharmony_ci#include <limits.h>
59141cc406Sopenharmony_ci#include <signal.h>
60141cc406Sopenharmony_ci#include <stdio.h>
61141cc406Sopenharmony_ci#include <stdlib.h>
62141cc406Sopenharmony_ci#include <string.h>
63141cc406Sopenharmony_ci#include <sys/types.h>
64141cc406Sopenharmony_ci#include <sys/wait.h>
65141cc406Sopenharmony_ci#include <unistd.h>
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci#include "../include/sane/sane.h"
68141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
69141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
70141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
71141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
74141cc406Sopenharmony_ci#include "../include/lassert.h"
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#include "teco1.h"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci#undef sim
79141cc406Sopenharmony_ci#ifdef sim
80141cc406Sopenharmony_ci#define sanei_scsi_cmd2(a, b, c, d, e, f, g) SANE_STATUS_GOOD
81141cc406Sopenharmony_ci#define sanei_scsi_open(a, b, c, d) 0
82141cc406Sopenharmony_ci#define sanei_scsi_cmd(a, b, c, d, e)  SANE_STATUS_GOOD
83141cc406Sopenharmony_ci#define sanei_scsi_close(a)   SANE_STATUS_GOOD
84141cc406Sopenharmony_ci#endif
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci/* Lists of possible scan modes. */
89141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list[] = {
90141cc406Sopenharmony_ci  BLACK_WHITE_STR,
91141cc406Sopenharmony_ci  GRAY_STR,
92141cc406Sopenharmony_ci  COLOR_STR,
93141cc406Sopenharmony_ci  NULL
94141cc406Sopenharmony_ci};
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci/* Minimum and maximum width and length supported. */
99141cc406Sopenharmony_cistatic SANE_Range x_range = { SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0 };
100141cc406Sopenharmony_cistatic SANE_Range y_range = { SANE_FIX (0), SANE_FIX (14 * MM_PER_INCH), 0 };
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci/* Gamma range */
105141cc406Sopenharmony_cistatic const SANE_Range gamma_range = {
106141cc406Sopenharmony_ci  0,				/* minimum */
107141cc406Sopenharmony_ci  255,				/* maximum */
108141cc406Sopenharmony_ci  0				/* quantization */
109141cc406Sopenharmony_ci};
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/* List of dithering options. */
114141cc406Sopenharmony_cistatic SANE_String_Const dither_list[] = {
115141cc406Sopenharmony_ci  "Line art",
116141cc406Sopenharmony_ci  "2x2",
117141cc406Sopenharmony_ci  "3x3",
118141cc406Sopenharmony_ci  "4x4 bayer",
119141cc406Sopenharmony_ci  "4x4 smooth",
120141cc406Sopenharmony_ci  "8x8 bayer",
121141cc406Sopenharmony_ci  "8x8 smooth",
122141cc406Sopenharmony_ci  "8x8 horizontal",
123141cc406Sopenharmony_ci  "8x8 vertical",
124141cc406Sopenharmony_ci  NULL
125141cc406Sopenharmony_ci};
126141cc406Sopenharmony_cistatic const int dither_val[] = {
127141cc406Sopenharmony_ci  0x00,
128141cc406Sopenharmony_ci  0x01,
129141cc406Sopenharmony_ci  0x02,
130141cc406Sopenharmony_ci  0x03,
131141cc406Sopenharmony_ci  0x04,
132141cc406Sopenharmony_ci  0x05,
133141cc406Sopenharmony_ci  0x06,
134141cc406Sopenharmony_ci  0x07,
135141cc406Sopenharmony_ci  0x08
136141cc406Sopenharmony_ci};
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_cistatic const SANE_Range threshold_range = {
141141cc406Sopenharmony_ci  0,				/* minimum */
142141cc406Sopenharmony_ci  255,				/* maximum */
143141cc406Sopenharmony_ci  0				/* quantization */
144141cc406Sopenharmony_ci};
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci/* Define the supported scanners and their characteristics. */
149141cc406Sopenharmony_cistatic const struct scanners_supported scanners[] = {
150141cc406Sopenharmony_ci  {6, "TECO VM3510",		/* *fake id*, see teco_identify_scanner */
151141cc406Sopenharmony_ci   TECO_VM3510,
152141cc406Sopenharmony_ci   "Dextra", "DF-600P",
153141cc406Sopenharmony_ci   {1, 600, 1},			/* resolution */
154141cc406Sopenharmony_ci   300, 600,			/* max x and Y res */
155141cc406Sopenharmony_ci   3,				/* color 3 pass */
156141cc406Sopenharmony_ci   256,				/* number of bytes per gamma color */
157141cc406Sopenharmony_ci   80				/* number of bytes in a window */
158141cc406Sopenharmony_ci   },
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci  {6, "TECO VM353A",
161141cc406Sopenharmony_ci   TECO_VM353A,
162141cc406Sopenharmony_ci   "Relisys", "RELI 2412",
163141cc406Sopenharmony_ci   {1, 1200, 1},		/* resolution */
164141cc406Sopenharmony_ci   300, 1200,			/* max x and Y resolution */
165141cc406Sopenharmony_ci   1,				/* color 1 pass */
166141cc406Sopenharmony_ci   256,				/* number of bytes per gamma color */
167141cc406Sopenharmony_ci   99				/* number of bytes in a window */
168141cc406Sopenharmony_ci   },
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci  {6, "TECO VM3520",
171141cc406Sopenharmony_ci   TECO_VM3520,
172141cc406Sopenharmony_ci   "Relisys", "AVEC Colour Office 2400",
173141cc406Sopenharmony_ci   {1, 600, 1},			/* resolution */
174141cc406Sopenharmony_ci   300, 600,			/* max x and Y resolution */
175141cc406Sopenharmony_ci   3,				/* color 3 pass */
176141cc406Sopenharmony_ci   256,				/* number of bytes per gamma color */
177141cc406Sopenharmony_ci   99				/* number of bytes in a window */
178141cc406Sopenharmony_ci   },
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci  {6, "TECO VM352A",
181141cc406Sopenharmony_ci   TECO_VM3520,					/* same as AVEC 2400 */
182141cc406Sopenharmony_ci   "Relisys", "AVEC Colour 2412",
183141cc406Sopenharmony_ci   {1, 600, 1},
184141cc406Sopenharmony_ci   300, 600,
185141cc406Sopenharmony_ci   3,
186141cc406Sopenharmony_ci   256,
187141cc406Sopenharmony_ci   99
188141cc406Sopenharmony_ci  },
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_ci  {6, "TECO VM4540",
191141cc406Sopenharmony_ci   TECO_VM4540,
192141cc406Sopenharmony_ci   "Relisys", "RELI 4816",
193141cc406Sopenharmony_ci   {1, 1600, 1},       /* resolution */
194141cc406Sopenharmony_ci   400, 1600,          /* max x and Y resolution */
195141cc406Sopenharmony_ci   1,                  /* color 1 pass */
196141cc406Sopenharmony_ci   256,                /* number of bytes per gamma color */
197141cc406Sopenharmony_ci   99                  /* number of bytes in a window */
198141cc406Sopenharmony_ci  },
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci  {6, "TECO VM4542",
201141cc406Sopenharmony_ci   TECO_VM4542,
202141cc406Sopenharmony_ci   "Relisys", "RELI 4830",
203141cc406Sopenharmony_ci   {1, 400, 1},			/* resolution */
204141cc406Sopenharmony_ci   400, 400,			/* max x and Y resolution */
205141cc406Sopenharmony_ci   1,				/* color 1 pass */
206141cc406Sopenharmony_ci   1024,			/* number of bytes per gamma color */
207141cc406Sopenharmony_ci   99				/* number of bytes in a window */
208141cc406Sopenharmony_ci   }
209141cc406Sopenharmony_ci};
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci/* List of scanner attached. */
214141cc406Sopenharmony_cistatic Teco_Scanner *first_dev = NULL;
215141cc406Sopenharmony_cistatic int num_devices = 0;
216141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci/* Local functions. */
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci/* Display a buffer in the log. */
222141cc406Sopenharmony_cistatic void
223141cc406Sopenharmony_cihexdump (int level, const char *comment, unsigned char *p, int l)
224141cc406Sopenharmony_ci{
225141cc406Sopenharmony_ci  int i;
226141cc406Sopenharmony_ci  char line[128];
227141cc406Sopenharmony_ci  char *ptr;
228141cc406Sopenharmony_ci  char asc_buf[17];
229141cc406Sopenharmony_ci  char *asc_ptr;
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  ptr = line;
234141cc406Sopenharmony_ci  *ptr = '\0';
235141cc406Sopenharmony_ci  asc_ptr = asc_buf;
236141cc406Sopenharmony_ci  *asc_ptr = '\0';
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++)
239141cc406Sopenharmony_ci    {
240141cc406Sopenharmony_ci      if ((i % 16) == 0)
241141cc406Sopenharmony_ci	{
242141cc406Sopenharmony_ci	  if (ptr != line)
243141cc406Sopenharmony_ci	    {
244141cc406Sopenharmony_ci	      DBG (level, "%s    %s\n", line, asc_buf);
245141cc406Sopenharmony_ci	      ptr = line;
246141cc406Sopenharmony_ci	      *ptr = '\0';
247141cc406Sopenharmony_ci	      asc_ptr = asc_buf;
248141cc406Sopenharmony_ci	      *asc_ptr = '\0';
249141cc406Sopenharmony_ci	    }
250141cc406Sopenharmony_ci	  sprintf (ptr, "%3.3d:", i);
251141cc406Sopenharmony_ci	  ptr += 4;
252141cc406Sopenharmony_ci	}
253141cc406Sopenharmony_ci      ptr += sprintf (ptr, " %2.2x", *p);
254141cc406Sopenharmony_ci      if (*p >= 32 && *p <= 127)
255141cc406Sopenharmony_ci	{
256141cc406Sopenharmony_ci	  asc_ptr += sprintf (asc_ptr, "%c", *p);
257141cc406Sopenharmony_ci	}
258141cc406Sopenharmony_ci      else
259141cc406Sopenharmony_ci	{
260141cc406Sopenharmony_ci	  asc_ptr += sprintf (asc_ptr, ".");
261141cc406Sopenharmony_ci	}
262141cc406Sopenharmony_ci    }
263141cc406Sopenharmony_ci  *ptr = '\0';
264141cc406Sopenharmony_ci  DBG (level, "%s    %s\n", line, asc_buf);
265141cc406Sopenharmony_ci}
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci/* Returns the length of the longest string, including the terminating
268141cc406Sopenharmony_ci * character. */
269141cc406Sopenharmony_cistatic size_t
270141cc406Sopenharmony_cimax_string_size (SANE_String_Const strings[])
271141cc406Sopenharmony_ci{
272141cc406Sopenharmony_ci  size_t size, max_size = 0;
273141cc406Sopenharmony_ci  int i;
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
276141cc406Sopenharmony_ci    {
277141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
278141cc406Sopenharmony_ci      if (size > max_size)
279141cc406Sopenharmony_ci	{
280141cc406Sopenharmony_ci	  max_size = size;
281141cc406Sopenharmony_ci	}
282141cc406Sopenharmony_ci    }
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci  return max_size;
285141cc406Sopenharmony_ci}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci/* Lookup a string list from one array and return its index. */
288141cc406Sopenharmony_cistatic int
289141cc406Sopenharmony_ciget_string_list_index (SANE_String_Const list[], SANE_String_Const name)
290141cc406Sopenharmony_ci{
291141cc406Sopenharmony_ci  int index;
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci  index = 0;
294141cc406Sopenharmony_ci  while (list[index] != NULL)
295141cc406Sopenharmony_ci    {
296141cc406Sopenharmony_ci      if (strcmp (list[index], name) == 0)
297141cc406Sopenharmony_ci	{
298141cc406Sopenharmony_ci	  return (index);
299141cc406Sopenharmony_ci	}
300141cc406Sopenharmony_ci      index++;
301141cc406Sopenharmony_ci    }
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci  DBG (DBG_error, "name %s not found in list\n", name);
304141cc406Sopenharmony_ci
305141cc406Sopenharmony_ci  assert (0 == 1);		/* bug in backend, core dump */
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  return (-1);
308141cc406Sopenharmony_ci}
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci/* Initialize a scanner entry. Return an allocated scanner with some
311141cc406Sopenharmony_ci * preset values. */
312141cc406Sopenharmony_cistatic Teco_Scanner *
313141cc406Sopenharmony_citeco_init (void)
314141cc406Sopenharmony_ci{
315141cc406Sopenharmony_ci  Teco_Scanner *dev;
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_init: enter\n");
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
320141cc406Sopenharmony_ci  dev = malloc (sizeof (Teco_Scanner));
321141cc406Sopenharmony_ci  if (dev == NULL)
322141cc406Sopenharmony_ci    {
323141cc406Sopenharmony_ci      return NULL;
324141cc406Sopenharmony_ci    }
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci  memset (dev, 0, sizeof (Teco_Scanner));
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci  /* Allocate the buffer used to transfer the SCSI data. */
329141cc406Sopenharmony_ci  dev->buffer_size = 64 * 1024;
330141cc406Sopenharmony_ci  dev->buffer = malloc (dev->buffer_size);
331141cc406Sopenharmony_ci  if (dev->buffer == NULL)
332141cc406Sopenharmony_ci    {
333141cc406Sopenharmony_ci      free (dev);
334141cc406Sopenharmony_ci      return NULL;
335141cc406Sopenharmony_ci    }
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci  /* Allocate a buffer to store the temporary image. */
338141cc406Sopenharmony_ci  dev->image_size = 64 * 1024;	/* enough for 1 line at max res */
339141cc406Sopenharmony_ci  dev->image = malloc (dev->image_size);
340141cc406Sopenharmony_ci  if (dev->image == NULL)
341141cc406Sopenharmony_ci    {
342141cc406Sopenharmony_ci      free (dev->buffer);
343141cc406Sopenharmony_ci      free (dev);
344141cc406Sopenharmony_ci      return NULL;
345141cc406Sopenharmony_ci    }
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci  dev->sfd = -1;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_init: exit\n");
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci  return (dev);
352141cc406Sopenharmony_ci}
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci/* Closes an open scanner. */
355141cc406Sopenharmony_cistatic void
356141cc406Sopenharmony_citeco_close (Teco_Scanner * dev)
357141cc406Sopenharmony_ci{
358141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_close: enter\n");
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_ci  if (dev->sfd != -1)
361141cc406Sopenharmony_ci    {
362141cc406Sopenharmony_ci      sanei_scsi_close (dev->sfd);
363141cc406Sopenharmony_ci      dev->sfd = -1;
364141cc406Sopenharmony_ci    }
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_close: exit\n");
367141cc406Sopenharmony_ci}
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci/* Frees the memory used by a scanner. */
370141cc406Sopenharmony_cistatic void
371141cc406Sopenharmony_citeco_free (Teco_Scanner * dev)
372141cc406Sopenharmony_ci{
373141cc406Sopenharmony_ci  int i;
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_free: enter\n");
376141cc406Sopenharmony_ci
377141cc406Sopenharmony_ci  if (dev == NULL)
378141cc406Sopenharmony_ci    return;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  teco_close (dev);
381141cc406Sopenharmony_ci  if (dev->devicename)
382141cc406Sopenharmony_ci    {
383141cc406Sopenharmony_ci      free (dev->devicename);
384141cc406Sopenharmony_ci    }
385141cc406Sopenharmony_ci  if (dev->buffer)
386141cc406Sopenharmony_ci    {
387141cc406Sopenharmony_ci      free (dev->buffer);
388141cc406Sopenharmony_ci    }
389141cc406Sopenharmony_ci  if (dev->image)
390141cc406Sopenharmony_ci    {
391141cc406Sopenharmony_ci      free (dev->image);
392141cc406Sopenharmony_ci    }
393141cc406Sopenharmony_ci  for (i = 1; i < OPT_NUM_OPTIONS; i++)
394141cc406Sopenharmony_ci    {
395141cc406Sopenharmony_ci      if (dev->opt[i].type == SANE_TYPE_STRING && dev->val[i].s)
396141cc406Sopenharmony_ci	{
397141cc406Sopenharmony_ci	  free (dev->val[i].s);
398141cc406Sopenharmony_ci	}
399141cc406Sopenharmony_ci    }
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  free (dev);
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_free: exit\n");
404141cc406Sopenharmony_ci}
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci/* Inquiry a device and returns TRUE if is supported. */
407141cc406Sopenharmony_cistatic int
408141cc406Sopenharmony_citeco_identify_scanner (Teco_Scanner * dev)
409141cc406Sopenharmony_ci{
410141cc406Sopenharmony_ci  CDB cdb;
411141cc406Sopenharmony_ci  SANE_Status status;
412141cc406Sopenharmony_ci  size_t size;
413141cc406Sopenharmony_ci  int i;
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_identify_scanner: enter\n");
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci  size = 5;
418141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
419141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
420141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ci  if (status)
423141cc406Sopenharmony_ci    {
424141cc406Sopenharmony_ci      DBG (DBG_error,
425141cc406Sopenharmony_ci	   "teco_identify_scanner: inquiry failed with status %s\n",
426141cc406Sopenharmony_ci	   sane_strstatus (status));
427141cc406Sopenharmony_ci      return (SANE_FALSE);
428141cc406Sopenharmony_ci    }
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci#ifdef sim
431141cc406Sopenharmony_ci  {
432141cc406Sopenharmony_ci#if 1
433141cc406Sopenharmony_ci    /* vm3510 / Dextra DF-600P */
434141cc406Sopenharmony_ci    unsigned char table[] = {
435141cc406Sopenharmony_ci      0x06, 0x00, 0x02, 0x02, 0x24, 0x00, 0x00, 0x10, 0x44, 0x46,
436141cc406Sopenharmony_ci      0x2D, 0x36, 0x30, 0x30, 0x4D, 0x20, 0x20, 0x20, 0x20, 0x20,
437141cc406Sopenharmony_ci      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
438141cc406Sopenharmony_ci      0x20, 0x20, 0x31, 0x2E, 0x31, 0x37, 0x31, 0x2E, 0x31, 0x37,
439141cc406Sopenharmony_ci      0x02
440141cc406Sopenharmony_ci    };
441141cc406Sopenharmony_ci#endif
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci#if 0
444141cc406Sopenharmony_ci    /* vm4542 */
445141cc406Sopenharmony_ci    unsigned char table[] = {
446141cc406Sopenharmony_ci      0x06, 0x00, 0x02, 0x02, 0x30, 0x00, 0x00, 0x10, 0x52, 0x45, 0x4c, 0x49,
447141cc406Sopenharmony_ci      0x53, 0x59, 0x53, 0x20, 0x52, 0x45, 0x4c, 0x49, 0x20, 0x34, 0x38,
448141cc406Sopenharmony_ci      0x33, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x2e,
449141cc406Sopenharmony_ci      0x30, 0x33, 0x31, 0x2e, 0x30, 0x33, 0x02, 0x00, 0x54, 0x45, 0x43,
450141cc406Sopenharmony_ci      0x4f, 0x20, 0x56, 0x4d, 0x34, 0x35, 0x34, 0x32
451141cc406Sopenharmony_ci    };
452141cc406Sopenharmony_ci#endif
453141cc406Sopenharmony_ci    memcpy (dev->buffer, table, sizeof (table));
454141cc406Sopenharmony_ci  }
455141cc406Sopenharmony_ci#endif
456141cc406Sopenharmony_ci
457141cc406Sopenharmony_ci  size = dev->buffer[4] + 5;	/* total length of the inquiry data */
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
460141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
461141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci  if (status)
464141cc406Sopenharmony_ci    {
465141cc406Sopenharmony_ci      DBG (DBG_error,
466141cc406Sopenharmony_ci	   "teco_identify_scanner: inquiry failed with status %s\n",
467141cc406Sopenharmony_ci	   sane_strstatus (status));
468141cc406Sopenharmony_ci      return (SANE_FALSE);
469141cc406Sopenharmony_ci    }
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci  /* Hack to recognize the dextra as a TECO scanner. */
472141cc406Sopenharmony_ci  if (memcmp (dev->buffer + 0x08, "DF-600M ", 8) == 0)
473141cc406Sopenharmony_ci    {
474141cc406Sopenharmony_ci      memcpy (dev->buffer + 0x29, "\0TECO VM3510", 12);
475141cc406Sopenharmony_ci      dev->buffer[4] = 0x30;	/* change length */
476141cc406Sopenharmony_ci      size = 0x35;
477141cc406Sopenharmony_ci    }
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_ci  if (size < 53)
480141cc406Sopenharmony_ci    {
481141cc406Sopenharmony_ci      DBG (DBG_error,
482141cc406Sopenharmony_ci	   "teco_identify_scanner: not enough data to identify device\n");
483141cc406Sopenharmony_ci      return (SANE_FALSE);
484141cc406Sopenharmony_ci    }
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci  hexdump (DBG_info2, "inquiry", dev->buffer, size);
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci  dev->scsi_type = dev->buffer[0] & 0x1f;
489141cc406Sopenharmony_ci  memcpy (dev->scsi_vendor, dev->buffer + 0x08, 0x08);
490141cc406Sopenharmony_ci  dev->scsi_vendor[0x08] = 0;
491141cc406Sopenharmony_ci  memcpy (dev->scsi_product, dev->buffer + 0x10, 0x010);
492141cc406Sopenharmony_ci  dev->scsi_product[0x10] = 0;
493141cc406Sopenharmony_ci  memcpy (dev->scsi_version, dev->buffer + 0x20, 0x04);
494141cc406Sopenharmony_ci  dev->scsi_version[0x04] = 0;
495141cc406Sopenharmony_ci  memcpy (dev->scsi_teco_name, dev->buffer + 0x2A, 0x0B);
496141cc406Sopenharmony_ci  dev->scsi_teco_name[0x0B] = 0;
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci  DBG (DBG_info, "device is \"%s\" \"%s\" \"%s\" \"%s\"\n",
499141cc406Sopenharmony_ci       dev->scsi_vendor, dev->scsi_product, dev->scsi_version,
500141cc406Sopenharmony_ci       dev->scsi_teco_name);
501141cc406Sopenharmony_ci
502141cc406Sopenharmony_ci  /* Lookup through the supported scanners table to find if this
503141cc406Sopenharmony_ci   * backend supports that one. */
504141cc406Sopenharmony_ci  for (i = 0; i < NELEMS (scanners); i++)
505141cc406Sopenharmony_ci    {
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci      if (dev->scsi_type == scanners[i].scsi_type &&
508141cc406Sopenharmony_ci	  strcmp (dev->scsi_teco_name, scanners[i].scsi_teco_name) == 0)
509141cc406Sopenharmony_ci	{
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci	  DBG (DBG_error, "teco_identify_scanner: scanner supported\n");
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci	  dev->def = &(scanners[i]);
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci	  return (SANE_TRUE);
516141cc406Sopenharmony_ci	}
517141cc406Sopenharmony_ci    }
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_identify_scanner: exit, device not supported\n");
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci  return (SANE_FALSE);
522141cc406Sopenharmony_ci}
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci/* Get the inquiry page 0x82. */
525141cc406Sopenharmony_cistatic int
526141cc406Sopenharmony_citeco_get_inquiry_82 (Teco_Scanner * dev)
527141cc406Sopenharmony_ci{
528141cc406Sopenharmony_ci  CDB cdb;
529141cc406Sopenharmony_ci  SANE_Status status;
530141cc406Sopenharmony_ci  size_t size;
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_get_inquiry_82: enter\n");
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci  size = 0x4;
535141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
536141cc406Sopenharmony_ci  cdb.data[1] = 1;		/* evpd */
537141cc406Sopenharmony_ci  cdb.data[2] = 0x82;		/* page code number */
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
540141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci  if (status)
543141cc406Sopenharmony_ci    {
544141cc406Sopenharmony_ci      DBG (DBG_error,
545141cc406Sopenharmony_ci	   "teco_get_inquiry_82: inquiry page 0x82 failed with status %s\n",
546141cc406Sopenharmony_ci	   sane_strstatus (status));
547141cc406Sopenharmony_ci      return (SANE_FALSE);
548141cc406Sopenharmony_ci    }
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci  size = dev->buffer[3] + 4;
551141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
552141cc406Sopenharmony_ci  cdb.data[1] = 1;		/* evpd */
553141cc406Sopenharmony_ci  cdb.data[2] = 0x82;		/* page code number */
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
556141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci  if (status)
559141cc406Sopenharmony_ci    {
560141cc406Sopenharmony_ci      DBG (DBG_error,
561141cc406Sopenharmony_ci	   "teco_get_inquiry_82: inquiry page 0x82 failed with status %s\n",
562141cc406Sopenharmony_ci	   sane_strstatus (status));
563141cc406Sopenharmony_ci      return (SANE_FALSE);
564141cc406Sopenharmony_ci    }
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci  hexdump (DBG_info2, "inquiry page 0x82", dev->buffer, size);
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_get_inquiry_82: leave\n");
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ci  return (status);
571141cc406Sopenharmony_ci}
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci/* SCSI sense handler. Callback for SANE.
574141cc406Sopenharmony_ci * These scanners never set asc or ascq. */
575141cc406Sopenharmony_cistatic SANE_Status
576141cc406Sopenharmony_citeco_sense_handler (int __sane_unused__ scsi_fd, unsigned char *result, void __sane_unused__ *arg)
577141cc406Sopenharmony_ci{
578141cc406Sopenharmony_ci  int sensekey;
579141cc406Sopenharmony_ci  int len;
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_sense_handler: enter\n");
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  sensekey = get_RS_sense_key (result);
584141cc406Sopenharmony_ci  len = 7 + get_RS_additional_length (result);
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_ci  hexdump (DBG_info2, "sense", result, len);
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_ci  if (get_RS_error_code (result) != 0x70)
589141cc406Sopenharmony_ci    {
590141cc406Sopenharmony_ci      DBG (DBG_error,
591141cc406Sopenharmony_ci	   "teco_sense_handler: invalid sense key error code (%d)\n",
592141cc406Sopenharmony_ci	   get_RS_error_code (result));
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
595141cc406Sopenharmony_ci    }
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci  if (len < 14)
598141cc406Sopenharmony_ci    {
599141cc406Sopenharmony_ci      DBG (DBG_error, "teco_sense_handler: sense too short, no ASC/ASCQ\n");
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
602141cc406Sopenharmony_ci    }
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci  DBG (DBG_sense, "teco_sense_handler: sense=%d\n", sensekey);
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_ci  if (sensekey == 0x00)
607141cc406Sopenharmony_ci    {
608141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
609141cc406Sopenharmony_ci    }
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
612141cc406Sopenharmony_ci}
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci/* Send the mode select to the scanner. */
615141cc406Sopenharmony_cistatic int
616141cc406Sopenharmony_citeco_mode_select (Teco_Scanner * dev)
617141cc406Sopenharmony_ci{
618141cc406Sopenharmony_ci  CDB cdb;
619141cc406Sopenharmony_ci  SANE_Status status;
620141cc406Sopenharmony_ci  size_t size;
621141cc406Sopenharmony_ci  unsigned char select[24] = {
622141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
623141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
624141cc406Sopenharmony_ci    0x03, 0x06, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00
625141cc406Sopenharmony_ci  };
626141cc406Sopenharmony_ci
627141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_mode_select: enter\n");
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci  size = 24;
630141cc406Sopenharmony_ci  MKSCSI_MODE_SELECT (cdb, 1, 0, size);
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
633141cc406Sopenharmony_ci			    select, size, NULL, NULL);
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_mode_select: exit\n");
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci  return (status);
638141cc406Sopenharmony_ci}
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci/* Set a window. */
641141cc406Sopenharmony_cistatic SANE_Status
642141cc406Sopenharmony_citeco_set_window (Teco_Scanner * dev)
643141cc406Sopenharmony_ci{
644141cc406Sopenharmony_ci  size_t size;			/* significant size of window */
645141cc406Sopenharmony_ci  CDB cdb;
646141cc406Sopenharmony_ci  unsigned char window[99];
647141cc406Sopenharmony_ci  SANE_Status status;
648141cc406Sopenharmony_ci  int i;
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_set_window: enter\n");
651141cc406Sopenharmony_ci
652141cc406Sopenharmony_ci  size = dev->def->window_size;
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  MKSCSI_SET_WINDOW (cdb, size);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  memset (window, 0, size);
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_ci  /* size of the windows descriptor block */
659141cc406Sopenharmony_ci  window[7] = size - 8;
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci  /* X and Y resolution */
662141cc406Sopenharmony_ci  Ito16 (dev->x_resolution, &window[10]);
663141cc406Sopenharmony_ci  Ito16 (dev->y_resolution, &window[12]);
664141cc406Sopenharmony_ci
665141cc406Sopenharmony_ci  /* Upper Left (X,Y) */
666141cc406Sopenharmony_ci  Ito32 (dev->x_tl, &window[14]);
667141cc406Sopenharmony_ci  Ito32 (dev->y_tl, &window[18]);
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci  /* Width and length */
670141cc406Sopenharmony_ci  Ito32 (dev->width, &window[22]);
671141cc406Sopenharmony_ci  Ito32 (dev->length, &window[26]);
672141cc406Sopenharmony_ci
673141cc406Sopenharmony_ci  /* Image Composition */
674141cc406Sopenharmony_ci  switch (dev->scan_mode)
675141cc406Sopenharmony_ci    {
676141cc406Sopenharmony_ci    case TECO_BW:
677141cc406Sopenharmony_ci      window[33] = 0x00;
678141cc406Sopenharmony_ci      i = get_string_list_index (dither_list, dev->val[OPT_DITHER].s);
679141cc406Sopenharmony_ci      window[36] = dither_val[i];
680141cc406Sopenharmony_ci      break;
681141cc406Sopenharmony_ci    case TECO_GRAYSCALE:
682141cc406Sopenharmony_ci      window[33] = 0x02;
683141cc406Sopenharmony_ci      break;
684141cc406Sopenharmony_ci    case TECO_COLOR:
685141cc406Sopenharmony_ci      window[33] = 0x05;
686141cc406Sopenharmony_ci      break;
687141cc406Sopenharmony_ci    }
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  /* Depth */
690141cc406Sopenharmony_ci  window[34] = dev->depth;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  /* Unknown - invariants */
693141cc406Sopenharmony_ci  window[31] = 0x80;
694141cc406Sopenharmony_ci  window[37] = 0x80;
695141cc406Sopenharmony_ci  window[55] = 0x80;
696141cc406Sopenharmony_ci  window[57] = 0x80;
697141cc406Sopenharmony_ci  window[59] = 0x80;
698141cc406Sopenharmony_ci  window[61] = 0x80;
699141cc406Sopenharmony_ci  window[65] = 0x80;
700141cc406Sopenharmony_ci  window[67] = 0x80;
701141cc406Sopenharmony_ci  window[69] = 0x80;
702141cc406Sopenharmony_ci  window[71] = 0x80;
703141cc406Sopenharmony_ci  window[73] = 0x80;
704141cc406Sopenharmony_ci  window[75] = 0x80;
705141cc406Sopenharmony_ci  window[77] = 0x80;
706141cc406Sopenharmony_ci  window[79] = 0x80;
707141cc406Sopenharmony_ci  window[85] = 0xff;
708141cc406Sopenharmony_ci  window[89] = 0xff;
709141cc406Sopenharmony_ci  window[93] = 0xff;
710141cc406Sopenharmony_ci  window[97] = 0xff;
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  hexdump (DBG_info2, "windows", window, size);
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
715141cc406Sopenharmony_ci			    window, size, NULL, NULL);
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_set_window: exit, status=%d\n", status);
718141cc406Sopenharmony_ci
719141cc406Sopenharmony_ci  return status;
720141cc406Sopenharmony_ci}
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci/* Return the number of byte that can be read. */
723141cc406Sopenharmony_cistatic SANE_Status
724141cc406Sopenharmony_ciget_filled_data_length (Teco_Scanner * dev, size_t * to_read)
725141cc406Sopenharmony_ci{
726141cc406Sopenharmony_ci  size_t size;
727141cc406Sopenharmony_ci  CDB cdb;
728141cc406Sopenharmony_ci  SANE_Status status;
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci  DBG (DBG_proc, "get_filled_data_length: enter\n");
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci  *to_read = 0;
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci  size = 0x12;
735141cc406Sopenharmony_ci  MKSCSI_GET_DATA_BUFFER_STATUS (cdb, 1, size);
736141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
737141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci  if (size < 0x10)
740141cc406Sopenharmony_ci    {
741141cc406Sopenharmony_ci      DBG (DBG_error,
742141cc406Sopenharmony_ci	   "get_filled_data_length: not enough data returned (%ld)\n",
743141cc406Sopenharmony_ci	   (long) size);
744141cc406Sopenharmony_ci    }
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  hexdump (DBG_info2, "get_filled_data_length return", dev->buffer, size);
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci  *to_read = B24TOI (&dev->buffer[9]);
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci  DBG (DBG_info, "%d %d  -  %d %d\n",
751141cc406Sopenharmony_ci       dev->params.lines, B16TOI (&dev->buffer[12]),
752141cc406Sopenharmony_ci       dev->params.bytes_per_line, B16TOI (&dev->buffer[14]));
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci  if (dev->real_bytes_left == 0)
755141cc406Sopenharmony_ci    {
756141cc406Sopenharmony_ci      /* Beginning of a scan. */
757141cc406Sopenharmony_ci      dev->params.lines = B16TOI (&dev->buffer[12]);
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci      switch (dev->scan_mode)
760141cc406Sopenharmony_ci	{
761141cc406Sopenharmony_ci	case TECO_BW:
762141cc406Sopenharmony_ci	  dev->params.bytes_per_line = B16TOI (&dev->buffer[14]);
763141cc406Sopenharmony_ci	  dev->params.pixels_per_line = dev->params.bytes_per_line * 8;
764141cc406Sopenharmony_ci	  break;
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci	case TECO_GRAYSCALE:
767141cc406Sopenharmony_ci	  dev->params.pixels_per_line = B16TOI (&dev->buffer[14]);
768141cc406Sopenharmony_ci	  dev->params.bytes_per_line = dev->params.pixels_per_line;
769141cc406Sopenharmony_ci	  break;
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci	case TECO_COLOR:
772141cc406Sopenharmony_ci	  dev->params.pixels_per_line = B16TOI (&dev->buffer[14]);
773141cc406Sopenharmony_ci	  if (dev->def->pass == 3)
774141cc406Sopenharmony_ci	    {
775141cc406Sopenharmony_ci	      dev->params.bytes_per_line = dev->params.pixels_per_line;
776141cc406Sopenharmony_ci	    }
777141cc406Sopenharmony_ci	  else
778141cc406Sopenharmony_ci	    {
779141cc406Sopenharmony_ci	      dev->params.bytes_per_line = dev->params.pixels_per_line * 3;
780141cc406Sopenharmony_ci	    }
781141cc406Sopenharmony_ci	  break;
782141cc406Sopenharmony_ci	}
783141cc406Sopenharmony_ci    }
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci  DBG (DBG_info, "get_filled_data_length: to read = %ld\n", (long) *to_read);
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci  DBG (DBG_proc, "get_filled_data_length: exit, status=%d\n", status);
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci  return (status);
790141cc406Sopenharmony_ci}
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci/* Start a scan. */
793141cc406Sopenharmony_cistatic SANE_Status
794141cc406Sopenharmony_citeco_scan (Teco_Scanner * dev)
795141cc406Sopenharmony_ci{
796141cc406Sopenharmony_ci  CDB cdb;
797141cc406Sopenharmony_ci  SANE_Status status;
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_scan: enter\n");
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ci  MKSCSI_SCAN (cdb);
802141cc406Sopenharmony_ci
803141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
804141cc406Sopenharmony_ci
805141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_scan: exit, status=%d\n", status);
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci  return status;
808141cc406Sopenharmony_ci}
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci#if 0
811141cc406Sopenharmony_ci/* Do some vendor specific stuff. */
812141cc406Sopenharmony_cistatic SANE_Status
813141cc406Sopenharmony_citeco_vendor_spec (Teco_Scanner * dev)
814141cc406Sopenharmony_ci{
815141cc406Sopenharmony_ci  CDB cdb;
816141cc406Sopenharmony_ci  SANE_Status status;
817141cc406Sopenharmony_ci  size_t size;
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_vendor_spec: enter\n");
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci  size = 0x7800;
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  cdb.data[0] = 0x09;
824141cc406Sopenharmony_ci  cdb.data[1] = 0;
825141cc406Sopenharmony_ci  cdb.data[2] = 0;
826141cc406Sopenharmony_ci  cdb.data[3] = (size >> 8) & 0xff;
827141cc406Sopenharmony_ci  cdb.data[4] = (size >> 0) & 0xff;
828141cc406Sopenharmony_ci  cdb.data[5] = 0;
829141cc406Sopenharmony_ci  cdb.len = 6;
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
832141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci  /*hexdump (DBG_info2, "calibration:", dev->buffer, size); */
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  cdb.data[0] = 0x0E;
837141cc406Sopenharmony_ci  cdb.data[1] = 0;
838141cc406Sopenharmony_ci  cdb.data[2] = 0;
839141cc406Sopenharmony_ci  cdb.data[3] = 0;
840141cc406Sopenharmony_ci  cdb.data[4] = 0;
841141cc406Sopenharmony_ci  cdb.data[5] = 0;
842141cc406Sopenharmony_ci  cdb.len = 6;
843141cc406Sopenharmony_ci
844141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci  return status;
847141cc406Sopenharmony_ci}
848141cc406Sopenharmony_ci#endif
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci/* Send the gamma
851141cc406Sopenharmony_ci * The order is RGB. The last color is unused.
852141cc406Sopenharmony_ci * G is also the gray gamma (if gray scan).
853141cc406Sopenharmony_ci *
854141cc406Sopenharmony_ci * Some scanner have 4 tables of 256 bytes, and some 4 tables of 1024 bytes.
855141cc406Sopenharmony_ci */
856141cc406Sopenharmony_cistatic SANE_Status
857141cc406Sopenharmony_citeco_send_gamma (Teco_Scanner * dev)
858141cc406Sopenharmony_ci{
859141cc406Sopenharmony_ci  CDB cdb;
860141cc406Sopenharmony_ci  SANE_Status status;
861141cc406Sopenharmony_ci  struct
862141cc406Sopenharmony_ci  {
863141cc406Sopenharmony_ci    unsigned char gamma[4 * MAX_GAMMA_LENGTH];
864141cc406Sopenharmony_ci  }
865141cc406Sopenharmony_ci  param;
866141cc406Sopenharmony_ci  size_t i;
867141cc406Sopenharmony_ci  size_t size;
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_send_gamma: enter\n");
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci  size = 4 * GAMMA_LENGTH;
872141cc406Sopenharmony_ci  MKSCSI_SEND_10 (cdb, 0x03, 0x02, size);
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ci  if (dev->val[OPT_CUSTOM_GAMMA].w)
875141cc406Sopenharmony_ci    {
876141cc406Sopenharmony_ci      /* Use the custom gamma. */
877141cc406Sopenharmony_ci      if (dev->scan_mode == TECO_GRAYSCALE)
878141cc406Sopenharmony_ci	{
879141cc406Sopenharmony_ci	  /* Gray */
880141cc406Sopenharmony_ci	  for (i = 0; i < GAMMA_LENGTH; i++)
881141cc406Sopenharmony_ci	    {
882141cc406Sopenharmony_ci	      param.gamma[0 * GAMMA_LENGTH + i] = 0;
883141cc406Sopenharmony_ci	      param.gamma[1 * GAMMA_LENGTH + i] = dev->gamma_GRAY[i];
884141cc406Sopenharmony_ci	      param.gamma[2 * GAMMA_LENGTH + i] = 0;
885141cc406Sopenharmony_ci	      param.gamma[3 * GAMMA_LENGTH + i] = 0;
886141cc406Sopenharmony_ci	    }
887141cc406Sopenharmony_ci	}
888141cc406Sopenharmony_ci      else
889141cc406Sopenharmony_ci	{
890141cc406Sopenharmony_ci	  /* Color */
891141cc406Sopenharmony_ci	  for (i = 0; i < GAMMA_LENGTH; i++)
892141cc406Sopenharmony_ci	    {
893141cc406Sopenharmony_ci	      param.gamma[0 * GAMMA_LENGTH + i] = dev->gamma_R[i];
894141cc406Sopenharmony_ci	      param.gamma[1 * GAMMA_LENGTH + i] = dev->gamma_G[i];
895141cc406Sopenharmony_ci	      param.gamma[2 * GAMMA_LENGTH + i] = dev->gamma_B[i];
896141cc406Sopenharmony_ci	      param.gamma[3 * GAMMA_LENGTH + i] = 0;
897141cc406Sopenharmony_ci	    }
898141cc406Sopenharmony_ci	}
899141cc406Sopenharmony_ci    }
900141cc406Sopenharmony_ci  else
901141cc406Sopenharmony_ci    {
902141cc406Sopenharmony_ci      if (dev->scan_mode == TECO_BW)
903141cc406Sopenharmony_ci	{
904141cc406Sopenharmony_ci	  /* Map threshold from a 0..255 scale to a
905141cc406Sopenharmony_ci	   * 0..GAMMA_LENGTH scale. */
906141cc406Sopenharmony_ci	  unsigned int threshold =
907141cc406Sopenharmony_ci	    dev->val[OPT_THRESHOLD].w * (GAMMA_LENGTH / 256);
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci	  for (i = 0; i < GAMMA_LENGTH; i++)
910141cc406Sopenharmony_ci	    {
911141cc406Sopenharmony_ci	      param.gamma[0 * GAMMA_LENGTH + i] = 0;
912141cc406Sopenharmony_ci	      if (i < threshold)
913141cc406Sopenharmony_ci		param.gamma[1 * GAMMA_LENGTH + i] = 0;
914141cc406Sopenharmony_ci	      else
915141cc406Sopenharmony_ci		param.gamma[1 * GAMMA_LENGTH + i] = 255;
916141cc406Sopenharmony_ci	      param.gamma[2 * GAMMA_LENGTH + i] = 0;
917141cc406Sopenharmony_ci	      param.gamma[3 * GAMMA_LENGTH + i] = 0;
918141cc406Sopenharmony_ci	    }
919141cc406Sopenharmony_ci	}
920141cc406Sopenharmony_ci      else
921141cc406Sopenharmony_ci	{
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ci	  /*
924141cc406Sopenharmony_ci	   * Shift is 1 for GAMMA_LENGTH == 256
925141cc406Sopenharmony_ci	   *  and 4 for GAMMA_LENGTH == 1024
926141cc406Sopenharmony_ci	   */
927141cc406Sopenharmony_ci	  int shift = GAMMA_LENGTH >> 8;
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci	  for (i = 0; i < GAMMA_LENGTH; i++)
930141cc406Sopenharmony_ci	    {
931141cc406Sopenharmony_ci	      param.gamma[0 * GAMMA_LENGTH + i] = i / shift;
932141cc406Sopenharmony_ci	      param.gamma[1 * GAMMA_LENGTH + i] = i / shift;
933141cc406Sopenharmony_ci	      param.gamma[2 * GAMMA_LENGTH + i] = i / shift;
934141cc406Sopenharmony_ci	      param.gamma[3 * GAMMA_LENGTH + i] = 0;
935141cc406Sopenharmony_ci	    }
936141cc406Sopenharmony_ci	}
937141cc406Sopenharmony_ci    }
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  hexdump (DBG_info2, "teco_send_gamma:", cdb.data, cdb.len);
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
942141cc406Sopenharmony_ci			    &param, size, NULL, NULL);
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_send_gamma: exit, status=%d\n", status);
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci  return (status);
947141cc406Sopenharmony_ci}
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_ci/* Attach a scanner to this backend. */
950141cc406Sopenharmony_cistatic SANE_Status
951141cc406Sopenharmony_ciattach_scanner (const char *devicename, Teco_Scanner ** devp)
952141cc406Sopenharmony_ci{
953141cc406Sopenharmony_ci  Teco_Scanner *dev;
954141cc406Sopenharmony_ci  int sfd;
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "attach_scanner: %s\n", devicename);
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  if (devp)
959141cc406Sopenharmony_ci    *devp = NULL;
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci  /* Check if we know this device name. */
962141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
963141cc406Sopenharmony_ci    {
964141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
965141cc406Sopenharmony_ci	{
966141cc406Sopenharmony_ci	  if (devp)
967141cc406Sopenharmony_ci	    {
968141cc406Sopenharmony_ci	      *devp = dev;
969141cc406Sopenharmony_ci	    }
970141cc406Sopenharmony_ci	  DBG (DBG_info, "device is already known\n");
971141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
972141cc406Sopenharmony_ci	}
973141cc406Sopenharmony_ci    }
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
976141cc406Sopenharmony_ci  dev = teco_init ();
977141cc406Sopenharmony_ci  if (dev == NULL)
978141cc406Sopenharmony_ci    {
979141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: not enough memory\n");
980141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
981141cc406Sopenharmony_ci    }
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci  DBG (DBG_info, "attach_scanner: opening %s\n", devicename);
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, teco_sense_handler, dev) != 0)
986141cc406Sopenharmony_ci    {
987141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: attach_scanner: open failed\n");
988141cc406Sopenharmony_ci      teco_free (dev);
989141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
990141cc406Sopenharmony_ci    }
991141cc406Sopenharmony_ci
992141cc406Sopenharmony_ci  /* Fill some scanner specific values. */
993141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
994141cc406Sopenharmony_ci  dev->sfd = sfd;
995141cc406Sopenharmony_ci
996141cc406Sopenharmony_ci  /* Now, check that it is a scanner we support. */
997141cc406Sopenharmony_ci  if (teco_identify_scanner (dev) == SANE_FALSE)
998141cc406Sopenharmony_ci    {
999141cc406Sopenharmony_ci      DBG (DBG_error,
1000141cc406Sopenharmony_ci	   "ERROR: attach_scanner: scanner-identification failed\n");
1001141cc406Sopenharmony_ci      teco_free (dev);
1002141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1003141cc406Sopenharmony_ci    }
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci  /* Get the page 0x82. It doesn't appear to be useful yet. */
1006141cc406Sopenharmony_ci  teco_get_inquiry_82 (dev);
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci  teco_close (dev);
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci  /* Set the default options for that scanner. */
1011141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
1012141cc406Sopenharmony_ci  dev->sane.vendor = dev->def->real_vendor;
1013141cc406Sopenharmony_ci  dev->sane.model = dev->def->real_product;
1014141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  /* Link the scanner with the others. */
1017141cc406Sopenharmony_ci  dev->next = first_dev;
1018141cc406Sopenharmony_ci  first_dev = dev;
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci  if (devp)
1021141cc406Sopenharmony_ci    {
1022141cc406Sopenharmony_ci      *devp = dev;
1023141cc406Sopenharmony_ci    }
1024141cc406Sopenharmony_ci
1025141cc406Sopenharmony_ci  num_devices++;
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  DBG (DBG_proc, "attach_scanner: exit\n");
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1030141cc406Sopenharmony_ci}
1031141cc406Sopenharmony_ci
1032141cc406Sopenharmony_cistatic SANE_Status
1033141cc406Sopenharmony_ciattach_one (const char *dev)
1034141cc406Sopenharmony_ci{
1035141cc406Sopenharmony_ci  attach_scanner (dev, NULL);
1036141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1037141cc406Sopenharmony_ci}
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci/* Reset the options for that scanner. */
1040141cc406Sopenharmony_cistatic void
1041141cc406Sopenharmony_citeco_init_options (Teco_Scanner * dev)
1042141cc406Sopenharmony_ci{
1043141cc406Sopenharmony_ci  int i;
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ci  /* Pre-initialize the options. */
1046141cc406Sopenharmony_ci  memset (dev->opt, 0, sizeof (dev->opt));
1047141cc406Sopenharmony_ci  memset (dev->val, 0, sizeof (dev->val));
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_ci  for (i = 0; i < OPT_NUM_OPTIONS; ++i)
1050141cc406Sopenharmony_ci    {
1051141cc406Sopenharmony_ci      dev->opt[i].size = sizeof (SANE_Word);
1052141cc406Sopenharmony_ci      dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1053141cc406Sopenharmony_ci    }
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  /* Number of options. */
1056141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].name = "";
1057141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1058141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1059141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1060141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1061141cc406Sopenharmony_ci  dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS;
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci  /* Mode group */
1064141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE;
1065141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].desc = "";	/* not valid for a group */
1066141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1067141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].cap = 0;
1068141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].size = 0;
1069141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  /* Scanner supported modes */
1072141cc406Sopenharmony_ci  dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1073141cc406Sopenharmony_ci  dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1074141cc406Sopenharmony_ci  dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1075141cc406Sopenharmony_ci  dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
1076141cc406Sopenharmony_ci  dev->opt[OPT_MODE].size = max_string_size (scan_mode_list);
1077141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1078141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint.string_list = scan_mode_list;
1079141cc406Sopenharmony_ci  dev->val[OPT_MODE].s = (SANE_Char *) strdup ("");	/* will be set later */
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci  /* X and Y resolution */
1082141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1083141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1084141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1085141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1086141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1087141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
1088141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint.range = &dev->def->res_range;
1089141cc406Sopenharmony_ci  dev->val[OPT_RESOLUTION].w = 100;
1090141cc406Sopenharmony_ci
1091141cc406Sopenharmony_ci  /* Geometry group */
1092141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
1093141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].desc = "";	/* not valid for a group */
1094141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1095141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].cap = 0;
1096141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].size = 0;
1097141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci  /* Upper left X */
1100141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1101141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1102141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1103141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1104141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1105141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1106141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint.range = &x_range;
1107141cc406Sopenharmony_ci  dev->val[OPT_TL_X].w = x_range.min;
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci  /* Upper left Y */
1110141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1111141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1112141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1113141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1114141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1115141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1116141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint.range = &y_range;
1117141cc406Sopenharmony_ci  dev->val[OPT_TL_Y].w = y_range.min;
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci  /* Bottom-right x */
1120141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1121141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1122141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1123141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1124141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1125141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1126141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint.range = &x_range;
1127141cc406Sopenharmony_ci  dev->val[OPT_BR_X].w = x_range.max;
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci  /* Bottom-right y */
1130141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1131141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1132141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1133141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1134141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1135141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1136141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint.range = &y_range;
1137141cc406Sopenharmony_ci  dev->val[OPT_BR_Y].w = y_range.max;
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci  /* Enhancement group */
1140141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
1141141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";	/* not valid for a group */
1142141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1143141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
1144141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
1145141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1146141cc406Sopenharmony_ci
1147141cc406Sopenharmony_ci  /* Halftone pattern */
1148141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].name = "dither";
1149141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].title = SANE_I18N ("Dither");
1150141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].desc = SANE_I18N ("Dither");
1151141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].type = SANE_TYPE_STRING;
1152141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].size = max_string_size (dither_list);
1153141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].cap |= SANE_CAP_INACTIVE;
1154141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1155141cc406Sopenharmony_ci  dev->opt[OPT_DITHER].constraint.string_list = dither_list;
1156141cc406Sopenharmony_ci  dev->val[OPT_DITHER].s = strdup (dither_list[0]);
1157141cc406Sopenharmony_ci
1158141cc406Sopenharmony_ci  /* custom-gamma table */
1159141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
1160141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
1161141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
1162141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
1163141cc406Sopenharmony_ci  dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1164141cc406Sopenharmony_ci  dev->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci  /* red gamma vector */
1167141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
1168141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1169141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
1170141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
1171141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1172141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
1173141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].size = GAMMA_LENGTH * sizeof (SANE_Word);
1174141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1175141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_R].constraint.range = &gamma_range;
1176141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_R].wa = dev->gamma_R;
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  /* green and gamma vector */
1179141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
1180141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1181141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
1182141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
1183141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1184141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
1185141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].size = GAMMA_LENGTH * sizeof (SANE_Word);
1186141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1187141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_G].constraint.range = &gamma_range;
1188141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_G].wa = dev->gamma_G;
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci  /* blue gamma vector */
1191141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
1192141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1193141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
1194141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
1195141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1196141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
1197141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].size = GAMMA_LENGTH * sizeof (SANE_Word);
1198141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1199141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_B].constraint.range = &gamma_range;
1200141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_B].wa = dev->gamma_B;
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci  /* grayscale gamma vector */
1203141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].name = SANE_NAME_GAMMA_VECTOR;
1204141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].title = SANE_TITLE_GAMMA_VECTOR;
1205141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].desc = SANE_DESC_GAMMA_VECTOR;
1206141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].type = SANE_TYPE_INT;
1207141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].cap |= SANE_CAP_INACTIVE;
1208141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].unit = SANE_UNIT_NONE;
1209141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].size = GAMMA_LENGTH * sizeof (SANE_Word);
1210141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].constraint_type = SANE_CONSTRAINT_RANGE;
1211141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA_VECTOR_GRAY].constraint.range = &gamma_range;
1212141cc406Sopenharmony_ci  dev->val[OPT_GAMMA_VECTOR_GRAY].wa = dev->gamma_GRAY;
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci  /* Threshold */
1215141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1216141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1217141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1218141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1219141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1220141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].size = sizeof (SANE_Int);
1221141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1222141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1223141cc406Sopenharmony_ci  dev->opt[OPT_THRESHOLD].constraint.range = &threshold_range;
1224141cc406Sopenharmony_ci  dev->val[OPT_THRESHOLD].w = 128;
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci  /* preview */
1227141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
1228141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1229141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
1230141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
1231141cc406Sopenharmony_ci  dev->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
1232141cc406Sopenharmony_ci  dev->val[OPT_PREVIEW].w = SANE_FALSE;
1233141cc406Sopenharmony_ci
1234141cc406Sopenharmony_ci  /* Lastly, set the default scan mode. This might change some
1235141cc406Sopenharmony_ci   * values previously set here. */
1236141cc406Sopenharmony_ci  sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE,
1237141cc406Sopenharmony_ci		       (SANE_String_Const *) scan_mode_list[0], NULL);
1238141cc406Sopenharmony_ci}
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci/*
1241141cc406Sopenharmony_ci * Wait until the scanner is ready.
1242141cc406Sopenharmony_ci */
1243141cc406Sopenharmony_cistatic SANE_Status
1244141cc406Sopenharmony_citeco_wait_scanner (Teco_Scanner * dev)
1245141cc406Sopenharmony_ci{
1246141cc406Sopenharmony_ci  SANE_Status status;
1247141cc406Sopenharmony_ci  int timeout;
1248141cc406Sopenharmony_ci  CDB cdb;
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_wait_scanner: enter\n");
1251141cc406Sopenharmony_ci
1252141cc406Sopenharmony_ci  MKSCSI_TEST_UNIT_READY (cdb);
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  /* Set the timeout to 60 seconds. */
1255141cc406Sopenharmony_ci  timeout = 60;
1256141cc406Sopenharmony_ci
1257141cc406Sopenharmony_ci  while (timeout > 0)
1258141cc406Sopenharmony_ci    {
1259141cc406Sopenharmony_ci
1260141cc406Sopenharmony_ci      /* test unit ready */
1261141cc406Sopenharmony_ci      status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1262141cc406Sopenharmony_ci				NULL, 0, NULL, NULL);
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
1265141cc406Sopenharmony_ci	{
1266141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1267141cc406Sopenharmony_ci	}
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci      sleep (1);
1270141cc406Sopenharmony_ci    };
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_wait_scanner: scanner not ready\n");
1273141cc406Sopenharmony_ci  return (SANE_STATUS_IO_ERROR);
1274141cc406Sopenharmony_ci}
1275141cc406Sopenharmony_ci
1276141cc406Sopenharmony_ci/* Read the image from the scanner and fill the temporary buffer with it. */
1277141cc406Sopenharmony_cistatic SANE_Status
1278141cc406Sopenharmony_citeco_fill_image (Teco_Scanner * dev)
1279141cc406Sopenharmony_ci{
1280141cc406Sopenharmony_ci  SANE_Status status;
1281141cc406Sopenharmony_ci  size_t size;
1282141cc406Sopenharmony_ci  CDB cdb;
1283141cc406Sopenharmony_ci  unsigned char *image;
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_ci  DBG (DBG_proc, "teco_fill_image: enter\n");
1286141cc406Sopenharmony_ci
1287141cc406Sopenharmony_ci  assert (dev->image_begin == dev->image_end);
1288141cc406Sopenharmony_ci  assert (dev->real_bytes_left > 0);
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  dev->image_begin = 0;
1291141cc406Sopenharmony_ci  dev->image_end = 0;
1292141cc406Sopenharmony_ci
1293141cc406Sopenharmony_ci  while (dev->real_bytes_left)
1294141cc406Sopenharmony_ci    {
1295141cc406Sopenharmony_ci      /*
1296141cc406Sopenharmony_ci       * Try to read the maximum number of bytes.
1297141cc406Sopenharmony_ci       */
1298141cc406Sopenharmony_ci      size = 0;
1299141cc406Sopenharmony_ci      while (size == 0)
1300141cc406Sopenharmony_ci	{
1301141cc406Sopenharmony_ci	  status = get_filled_data_length (dev, &size);
1302141cc406Sopenharmony_ci	  if (status)
1303141cc406Sopenharmony_ci	    return (status);
1304141cc406Sopenharmony_ci	  if (size == 0)
1305141cc406Sopenharmony_ci	    usleep (100000);	/* sleep 1/10th of second */
1306141cc406Sopenharmony_ci	}
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci      if (size > dev->real_bytes_left)
1309141cc406Sopenharmony_ci	size = dev->real_bytes_left;
1310141cc406Sopenharmony_ci      if (size > dev->image_size - dev->image_end)
1311141cc406Sopenharmony_ci	size = dev->image_size - dev->image_end;
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci      /* Always read a multiple of a line. */
1314141cc406Sopenharmony_ci      size = size - (size % dev->params.bytes_per_line);
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci      if (size == 0)
1317141cc406Sopenharmony_ci	{
1318141cc406Sopenharmony_ci	  /* Probably reached the end of the buffer.
1319141cc406Sopenharmony_ci	   * Check, just in case. */
1320141cc406Sopenharmony_ci	  assert (dev->image_end != 0);
1321141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
1322141cc406Sopenharmony_ci	}
1323141cc406Sopenharmony_ci
1324141cc406Sopenharmony_ci      DBG (DBG_info, "teco_fill_image: to read   = %ld bytes (bpl=%d)\n",
1325141cc406Sopenharmony_ci	   (long) size, dev->params.bytes_per_line);
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci      MKSCSI_READ_10 (cdb, 0, 0, size);
1328141cc406Sopenharmony_ci
1329141cc406Sopenharmony_ci      hexdump (DBG_info2, "teco_fill_image: READ_10 CDB", cdb.data, 10);
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci      image = dev->image + dev->image_end;
1332141cc406Sopenharmony_ci
1333141cc406Sopenharmony_ci      status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1334141cc406Sopenharmony_ci				NULL, 0, image, &size);
1335141cc406Sopenharmony_ci
1336141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1337141cc406Sopenharmony_ci	{
1338141cc406Sopenharmony_ci	  DBG (DBG_error, "teco_fill_image: cannot read from the scanner\n");
1339141cc406Sopenharmony_ci	  return status;
1340141cc406Sopenharmony_ci	}
1341141cc406Sopenharmony_ci
1342141cc406Sopenharmony_ci      /* The size this scanner returns is always a multiple of lines. */
1343141cc406Sopenharmony_ci      assert ((size % dev->params.bytes_per_line) == 0);
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci      DBG (DBG_info, "teco_fill_image: real bytes left = %ld\n",
1346141cc406Sopenharmony_ci	   (long) dev->real_bytes_left);
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci      if (dev->scan_mode == TECO_COLOR)
1349141cc406Sopenharmony_ci	{
1350141cc406Sopenharmony_ci	  if (dev->def->pass == 1)
1351141cc406Sopenharmony_ci	    {
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci	      /* Reorder the lines. The scanner gives color by color for
1354141cc406Sopenharmony_ci	       * each line. */
1355141cc406Sopenharmony_ci	      unsigned char *src = image;
1356141cc406Sopenharmony_ci	      int nb_lines = size / dev->params.bytes_per_line;
1357141cc406Sopenharmony_ci	      int i, j;
1358141cc406Sopenharmony_ci
1359141cc406Sopenharmony_ci	      for (i = 0; i < nb_lines; i++)
1360141cc406Sopenharmony_ci		{
1361141cc406Sopenharmony_ci
1362141cc406Sopenharmony_ci		  unsigned char *dest = dev->buffer;
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci		  for (j = 0; j < dev->params.pixels_per_line; j++)
1365141cc406Sopenharmony_ci		    {
1366141cc406Sopenharmony_ci		      *dest = src[j + 0 * dev->params.pixels_per_line];
1367141cc406Sopenharmony_ci		      dest++;
1368141cc406Sopenharmony_ci		      *dest = src[j + 1 * dev->params.pixels_per_line];
1369141cc406Sopenharmony_ci		      dest++;
1370141cc406Sopenharmony_ci		      *dest = src[j + 2 * dev->params.pixels_per_line];
1371141cc406Sopenharmony_ci		      dest++;
1372141cc406Sopenharmony_ci		    }
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci		  /* Copy the line back. */
1375141cc406Sopenharmony_ci		  memcpy (src, dev->buffer, dev->params.bytes_per_line);
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci		  src += dev->params.bytes_per_line;
1378141cc406Sopenharmony_ci		}
1379141cc406Sopenharmony_ci	    }
1380141cc406Sopenharmony_ci	}
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci      dev->image_end += size;
1383141cc406Sopenharmony_ci      dev->real_bytes_left -= size;
1384141cc406Sopenharmony_ci    }
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);	/* unreachable */
1387141cc406Sopenharmony_ci}
1388141cc406Sopenharmony_ci
1389141cc406Sopenharmony_ci/* Copy from the raw buffer to the buffer given by the backend.
1390141cc406Sopenharmony_ci *
1391141cc406Sopenharmony_ci * len in input is the maximum length available in buf, and, in
1392141cc406Sopenharmony_ci * output, is the length written into buf.
1393141cc406Sopenharmony_ci */
1394141cc406Sopenharmony_cistatic void
1395141cc406Sopenharmony_citeco_copy_raw_to_frontend (Teco_Scanner * dev, SANE_Byte * buf, size_t * len)
1396141cc406Sopenharmony_ci{
1397141cc406Sopenharmony_ci  size_t size;
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci  size = dev->image_end - dev->image_begin;
1400141cc406Sopenharmony_ci  if (size > *len)
1401141cc406Sopenharmony_ci    {
1402141cc406Sopenharmony_ci      size = *len;
1403141cc406Sopenharmony_ci    }
1404141cc406Sopenharmony_ci  *len = size;
1405141cc406Sopenharmony_ci
1406141cc406Sopenharmony_ci  switch (dev->scan_mode)
1407141cc406Sopenharmony_ci    {
1408141cc406Sopenharmony_ci    case TECO_BW:
1409141cc406Sopenharmony_ci      {
1410141cc406Sopenharmony_ci	/* Invert black and white. */
1411141cc406Sopenharmony_ci	unsigned char *src = dev->image + dev->image_begin;
1412141cc406Sopenharmony_ci	size_t i;
1413141cc406Sopenharmony_ci
1414141cc406Sopenharmony_ci	for (i = 0; i < size; i++)
1415141cc406Sopenharmony_ci	  {
1416141cc406Sopenharmony_ci	    *buf = *src ^ 0xff;
1417141cc406Sopenharmony_ci	    src++;
1418141cc406Sopenharmony_ci	    buf++;
1419141cc406Sopenharmony_ci	  }
1420141cc406Sopenharmony_ci      }
1421141cc406Sopenharmony_ci      break;
1422141cc406Sopenharmony_ci
1423141cc406Sopenharmony_ci    case TECO_GRAYSCALE:
1424141cc406Sopenharmony_ci    case TECO_COLOR:
1425141cc406Sopenharmony_ci      memcpy (buf, dev->image + dev->image_begin, size);
1426141cc406Sopenharmony_ci      break;
1427141cc406Sopenharmony_ci    }
1428141cc406Sopenharmony_ci
1429141cc406Sopenharmony_ci  dev->image_begin += size;
1430141cc406Sopenharmony_ci}
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci/* Stop a scan. */
1433141cc406Sopenharmony_cistatic SANE_Status
1434141cc406Sopenharmony_cido_cancel (Teco_Scanner * dev)
1435141cc406Sopenharmony_ci{
1436141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel enter\n");
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci  if (dev->scanning == SANE_TRUE)
1439141cc406Sopenharmony_ci    {
1440141cc406Sopenharmony_ci
1441141cc406Sopenharmony_ci      /* Reset the scanner */
1442141cc406Sopenharmony_ci      dev->x_resolution = 300;
1443141cc406Sopenharmony_ci      dev->y_resolution = 300;
1444141cc406Sopenharmony_ci      dev->x_tl = 0;
1445141cc406Sopenharmony_ci      dev->y_tl = 0;
1446141cc406Sopenharmony_ci      dev->width = 0;
1447141cc406Sopenharmony_ci      dev->length = 0;
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci      teco_set_window (dev);
1450141cc406Sopenharmony_ci
1451141cc406Sopenharmony_ci      teco_scan (dev);
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci      teco_close (dev);
1454141cc406Sopenharmony_ci    }
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci  dev->scanning = SANE_FALSE;
1457141cc406Sopenharmony_ci
1458141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel exit\n");
1459141cc406Sopenharmony_ci
1460141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
1461141cc406Sopenharmony_ci}
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci/* Sane entry points */
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ciSANE_Status
1468141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
1469141cc406Sopenharmony_ci{
1470141cc406Sopenharmony_ci  FILE *fp;
1471141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
1472141cc406Sopenharmony_ci  size_t len;
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci  DBG_INIT ();
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_init\n");
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci  DBG (DBG_error, "This is sane-teco1 version %d.%d-%d\n", SANE_CURRENT_MAJOR,
1479141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD);
1480141cc406Sopenharmony_ci  DBG (DBG_error, "(C) 2002 by Frank Zago\n");
1481141cc406Sopenharmony_ci
1482141cc406Sopenharmony_ci  if (version_code)
1483141cc406Sopenharmony_ci    {
1484141cc406Sopenharmony_ci      *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
1485141cc406Sopenharmony_ci    }
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  fp = sanei_config_open (TECO_CONFIG_FILE);
1488141cc406Sopenharmony_ci  if (!fp)
1489141cc406Sopenharmony_ci    {
1490141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
1491141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);
1492141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1493141cc406Sopenharmony_ci    }
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
1496141cc406Sopenharmony_ci    {
1497141cc406Sopenharmony_ci      if (dev_name[0] == '#')	/* ignore line comments */
1498141cc406Sopenharmony_ci	continue;
1499141cc406Sopenharmony_ci      len = strlen (dev_name);
1500141cc406Sopenharmony_ci
1501141cc406Sopenharmony_ci      if (!len)
1502141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
1505141cc406Sopenharmony_ci    }
1506141cc406Sopenharmony_ci
1507141cc406Sopenharmony_ci  fclose (fp);
1508141cc406Sopenharmony_ci
1509141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: leave\n");
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1512141cc406Sopenharmony_ci}
1513141cc406Sopenharmony_ci
1514141cc406Sopenharmony_ciSANE_Status
1515141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)
1516141cc406Sopenharmony_ci{
1517141cc406Sopenharmony_ci  Teco_Scanner *dev;
1518141cc406Sopenharmony_ci  int i;
1519141cc406Sopenharmony_ci
1520141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: enter\n");
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci  if (devlist)
1523141cc406Sopenharmony_ci    free (devlist);
1524141cc406Sopenharmony_ci
1525141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
1526141cc406Sopenharmony_ci  if (!devlist)
1527141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci  i = 0;
1530141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
1531141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
1532141cc406Sopenharmony_ci  devlist[i++] = 0;
1533141cc406Sopenharmony_ci
1534141cc406Sopenharmony_ci  *device_list = devlist;
1535141cc406Sopenharmony_ci
1536141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: exit\n");
1537141cc406Sopenharmony_ci
1538141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1539141cc406Sopenharmony_ci}
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ciSANE_Status
1542141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
1543141cc406Sopenharmony_ci{
1544141cc406Sopenharmony_ci  Teco_Scanner *dev;
1545141cc406Sopenharmony_ci  SANE_Status status;
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: enter\n");
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_ci  /* search for devicename */
1550141cc406Sopenharmony_ci  if (devicename[0])
1551141cc406Sopenharmony_ci    {
1552141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: devicename=%s\n", devicename);
1553141cc406Sopenharmony_ci
1554141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
1555141cc406Sopenharmony_ci	{
1556141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devicename) == 0)
1557141cc406Sopenharmony_ci	    {
1558141cc406Sopenharmony_ci	      break;
1559141cc406Sopenharmony_ci	    }
1560141cc406Sopenharmony_ci	}
1561141cc406Sopenharmony_ci
1562141cc406Sopenharmony_ci      if (!dev)
1563141cc406Sopenharmony_ci	{
1564141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
1565141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1566141cc406Sopenharmony_ci	    {
1567141cc406Sopenharmony_ci	      return status;
1568141cc406Sopenharmony_ci	    }
1569141cc406Sopenharmony_ci	}
1570141cc406Sopenharmony_ci    }
1571141cc406Sopenharmony_ci  else
1572141cc406Sopenharmony_ci    {
1573141cc406Sopenharmony_ci      DBG (DBG_sane_info, "sane_open: no devicename, opening first device\n");
1574141cc406Sopenharmony_ci      dev = first_dev;		/* empty devicename -> use first device */
1575141cc406Sopenharmony_ci    }
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci  if (!dev)
1578141cc406Sopenharmony_ci    {
1579141cc406Sopenharmony_ci      DBG (DBG_error, "No scanner found\n");
1580141cc406Sopenharmony_ci
1581141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1582141cc406Sopenharmony_ci    }
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci  teco_init_options (dev);
1585141cc406Sopenharmony_ci
1586141cc406Sopenharmony_ci  /* Initialize the gamma table. */
1587141cc406Sopenharmony_ci  {
1588141cc406Sopenharmony_ci    /*
1589141cc406Sopenharmony_ci     * Shift is 1 for GAMMA_LENGTH == 256
1590141cc406Sopenharmony_ci     *  and 4 for GAMMA_LENGTH == 1024
1591141cc406Sopenharmony_ci     */
1592141cc406Sopenharmony_ci    int shift = GAMMA_LENGTH >> 8;
1593141cc406Sopenharmony_ci    size_t i;
1594141cc406Sopenharmony_ci
1595141cc406Sopenharmony_ci    for (i = 0; i < GAMMA_LENGTH; i++)
1596141cc406Sopenharmony_ci      {
1597141cc406Sopenharmony_ci	dev->gamma_R[i] = i / shift;
1598141cc406Sopenharmony_ci	dev->gamma_G[i] = i / shift;
1599141cc406Sopenharmony_ci	dev->gamma_B[i] = i / shift;
1600141cc406Sopenharmony_ci	dev->gamma_GRAY[i] = i / shift;
1601141cc406Sopenharmony_ci      }
1602141cc406Sopenharmony_ci  }
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci  *handle = dev;
1605141cc406Sopenharmony_ci
1606141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: exit\n");
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1609141cc406Sopenharmony_ci}
1610141cc406Sopenharmony_ci
1611141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1612141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1613141cc406Sopenharmony_ci{
1614141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: enter, option %d\n", option);
1617141cc406Sopenharmony_ci
1618141cc406Sopenharmony_ci  if ((unsigned) option >= OPT_NUM_OPTIONS)
1619141cc406Sopenharmony_ci    {
1620141cc406Sopenharmony_ci      return NULL;
1621141cc406Sopenharmony_ci    }
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
1624141cc406Sopenharmony_ci
1625141cc406Sopenharmony_ci  return dev->opt + option;
1626141cc406Sopenharmony_ci}
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ciSANE_Status
1629141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1630141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1631141cc406Sopenharmony_ci{
1632141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
1633141cc406Sopenharmony_ci  SANE_Status status;
1634141cc406Sopenharmony_ci  SANE_Word cap;
1635141cc406Sopenharmony_ci  SANE_String_Const name;
1636141cc406Sopenharmony_ci
1637141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: enter, option %d, action %d\n",
1638141cc406Sopenharmony_ci       option, action);
1639141cc406Sopenharmony_ci
1640141cc406Sopenharmony_ci  if (info)
1641141cc406Sopenharmony_ci    {
1642141cc406Sopenharmony_ci      *info = 0;
1643141cc406Sopenharmony_ci    }
1644141cc406Sopenharmony_ci
1645141cc406Sopenharmony_ci  if (dev->scanning)
1646141cc406Sopenharmony_ci    {
1647141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1648141cc406Sopenharmony_ci    }
1649141cc406Sopenharmony_ci
1650141cc406Sopenharmony_ci  if (option < 0 || option >= OPT_NUM_OPTIONS)
1651141cc406Sopenharmony_ci    {
1652141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1653141cc406Sopenharmony_ci    }
1654141cc406Sopenharmony_ci
1655141cc406Sopenharmony_ci  cap = dev->opt[option].cap;
1656141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
1657141cc406Sopenharmony_ci    {
1658141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1659141cc406Sopenharmony_ci    }
1660141cc406Sopenharmony_ci
1661141cc406Sopenharmony_ci  name = dev->opt[option].name;
1662141cc406Sopenharmony_ci  if (!name)
1663141cc406Sopenharmony_ci    {
1664141cc406Sopenharmony_ci      name = "(no name)";
1665141cc406Sopenharmony_ci    }
1666141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1667141cc406Sopenharmony_ci    {
1668141cc406Sopenharmony_ci
1669141cc406Sopenharmony_ci      switch (option)
1670141cc406Sopenharmony_ci	{
1671141cc406Sopenharmony_ci	  /* word options */
1672141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1673141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1674141cc406Sopenharmony_ci	case OPT_TL_Y:
1675141cc406Sopenharmony_ci	case OPT_BR_Y:
1676141cc406Sopenharmony_ci	case OPT_TL_X:
1677141cc406Sopenharmony_ci	case OPT_BR_X:
1678141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1679141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1680141cc406Sopenharmony_ci	case OPT_PREVIEW:
1681141cc406Sopenharmony_ci	  *(SANE_Word *) val = dev->val[option].w;
1682141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1683141cc406Sopenharmony_ci
1684141cc406Sopenharmony_ci	  /* string options */
1685141cc406Sopenharmony_ci	case OPT_MODE:
1686141cc406Sopenharmony_ci	case OPT_DITHER:
1687141cc406Sopenharmony_ci	  strcpy (val, dev->val[option].s);
1688141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci	  /* Gamma */
1691141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1692141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1693141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1694141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_GRAY:
1695141cc406Sopenharmony_ci	  memcpy (val, dev->val[option].wa, dev->opt[option].size);
1696141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1697141cc406Sopenharmony_ci
1698141cc406Sopenharmony_ci	default:
1699141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1700141cc406Sopenharmony_ci	}
1701141cc406Sopenharmony_ci    }
1702141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1703141cc406Sopenharmony_ci    {
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
1706141cc406Sopenharmony_ci	{
1707141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, not settable\n");
1708141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1709141cc406Sopenharmony_ci	}
1710141cc406Sopenharmony_ci
1711141cc406Sopenharmony_ci      status = sanei_constrain_value (dev->opt + option, val, info);
1712141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1713141cc406Sopenharmony_ci	{
1714141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, invalid value\n");
1715141cc406Sopenharmony_ci	  return status;
1716141cc406Sopenharmony_ci	}
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_ci      switch (option)
1719141cc406Sopenharmony_ci	{
1720141cc406Sopenharmony_ci
1721141cc406Sopenharmony_ci	  /* Numeric side-effect options */
1722141cc406Sopenharmony_ci	case OPT_TL_Y:
1723141cc406Sopenharmony_ci	case OPT_BR_Y:
1724141cc406Sopenharmony_ci	case OPT_TL_X:
1725141cc406Sopenharmony_ci	case OPT_BR_X:
1726141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1727141cc406Sopenharmony_ci	  if (info)
1728141cc406Sopenharmony_ci	    {
1729141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
1730141cc406Sopenharmony_ci	    }
1731141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1732141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci	  /* Numeric side-effect free options */
1735141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1736141cc406Sopenharmony_ci	case OPT_PREVIEW:
1737141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1738141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci	  /* String side-effect free options */
1741141cc406Sopenharmony_ci	case OPT_DITHER:
1742141cc406Sopenharmony_ci	  free (dev->val[option].s);
1743141cc406Sopenharmony_ci	  dev->val[option].s = (SANE_String) strdup (val);
1744141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1745141cc406Sopenharmony_ci
1746141cc406Sopenharmony_ci	  /* String side-effect options */
1747141cc406Sopenharmony_ci	case OPT_MODE:
1748141cc406Sopenharmony_ci	  if (strcmp (dev->val[option].s, val) == 0)
1749141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci	  free (dev->val[OPT_MODE].s);
1752141cc406Sopenharmony_ci	  dev->val[OPT_MODE].s = (SANE_Char *) strdup (val);
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci	  dev->opt[OPT_DITHER].cap |= SANE_CAP_INACTIVE;
1755141cc406Sopenharmony_ci	  dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1756141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1757141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1758141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1759141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA_VECTOR_GRAY].cap |= SANE_CAP_INACTIVE;
1760141cc406Sopenharmony_ci	  dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1761141cc406Sopenharmony_ci
1762141cc406Sopenharmony_ci	  if (strcmp (dev->val[OPT_MODE].s, BLACK_WHITE_STR) == 0)
1763141cc406Sopenharmony_ci	    {
1764141cc406Sopenharmony_ci	      dev->depth = 8;
1765141cc406Sopenharmony_ci	      dev->scan_mode = TECO_BW;
1766141cc406Sopenharmony_ci	      dev->opt[OPT_DITHER].cap &= ~SANE_CAP_INACTIVE;
1767141cc406Sopenharmony_ci	      dev->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1768141cc406Sopenharmony_ci	    }
1769141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, GRAY_STR) == 0)
1770141cc406Sopenharmony_ci	    {
1771141cc406Sopenharmony_ci	      dev->scan_mode = TECO_GRAYSCALE;
1772141cc406Sopenharmony_ci	      dev->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1773141cc406Sopenharmony_ci	      if (dev->val[OPT_CUSTOM_GAMMA].w)
1774141cc406Sopenharmony_ci		{
1775141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_GRAY].cap &= ~SANE_CAP_INACTIVE;
1776141cc406Sopenharmony_ci		}
1777141cc406Sopenharmony_ci	      dev->depth = 8;
1778141cc406Sopenharmony_ci	    }
1779141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, COLOR_STR) == 0)
1780141cc406Sopenharmony_ci	    {
1781141cc406Sopenharmony_ci	      dev->scan_mode = TECO_COLOR;
1782141cc406Sopenharmony_ci	      dev->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1783141cc406Sopenharmony_ci	      if (dev->val[OPT_CUSTOM_GAMMA].w)
1784141cc406Sopenharmony_ci		{
1785141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1786141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1787141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1788141cc406Sopenharmony_ci		}
1789141cc406Sopenharmony_ci	      dev->depth = 8;
1790141cc406Sopenharmony_ci	    }
1791141cc406Sopenharmony_ci
1792141cc406Sopenharmony_ci	  if (info)
1793141cc406Sopenharmony_ci	    {
1794141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1795141cc406Sopenharmony_ci	    }
1796141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1799141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1800141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1801141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_GRAY:
1802141cc406Sopenharmony_ci	  memcpy (dev->val[option].wa, val, dev->opt[option].size);
1803141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1804141cc406Sopenharmony_ci
1805141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1806141cc406Sopenharmony_ci	  dev->val[OPT_CUSTOM_GAMMA].w = *(SANE_Word *) val;
1807141cc406Sopenharmony_ci	  if (dev->val[OPT_CUSTOM_GAMMA].w)
1808141cc406Sopenharmony_ci	    {
1809141cc406Sopenharmony_ci	      /* use custom_gamma_table */
1810141cc406Sopenharmony_ci	      if (dev->scan_mode == TECO_GRAYSCALE)
1811141cc406Sopenharmony_ci		{
1812141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_GRAY].cap &= ~SANE_CAP_INACTIVE;
1813141cc406Sopenharmony_ci		}
1814141cc406Sopenharmony_ci	      else
1815141cc406Sopenharmony_ci		{
1816141cc406Sopenharmony_ci		  /* color mode */
1817141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1818141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1819141cc406Sopenharmony_ci		  dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1820141cc406Sopenharmony_ci		}
1821141cc406Sopenharmony_ci	    }
1822141cc406Sopenharmony_ci	  else
1823141cc406Sopenharmony_ci	    {
1824141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1825141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1826141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1827141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA_VECTOR_GRAY].cap |= SANE_CAP_INACTIVE;
1828141cc406Sopenharmony_ci	    }
1829141cc406Sopenharmony_ci	  if (info)
1830141cc406Sopenharmony_ci	    {
1831141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS;
1832141cc406Sopenharmony_ci	    }
1833141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_ci	default:
1836141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1837141cc406Sopenharmony_ci	}
1838141cc406Sopenharmony_ci    }
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: exit, bad\n");
1841141cc406Sopenharmony_ci
1842141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1843141cc406Sopenharmony_ci}
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_ciSANE_Status
1846141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1847141cc406Sopenharmony_ci{
1848141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
1849141cc406Sopenharmony_ci
1850141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: enter\n");
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci  if (!(dev->scanning))
1853141cc406Sopenharmony_ci    {
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci      /* Setup the parameters for the scan. These values will be re-used
1856141cc406Sopenharmony_ci       * in the SET WINDOWS command. */
1857141cc406Sopenharmony_ci      if (dev->val[OPT_PREVIEW].w == SANE_TRUE)
1858141cc406Sopenharmony_ci	{
1859141cc406Sopenharmony_ci	  dev->x_resolution = 22;
1860141cc406Sopenharmony_ci	  dev->y_resolution = 22;
1861141cc406Sopenharmony_ci	  dev->x_tl = 0;
1862141cc406Sopenharmony_ci	  dev->y_tl = 0;
1863141cc406Sopenharmony_ci	  dev->x_br = mmToIlu (SANE_UNFIX (x_range.max));
1864141cc406Sopenharmony_ci	  dev->y_br = mmToIlu (SANE_UNFIX (y_range.max));
1865141cc406Sopenharmony_ci	}
1866141cc406Sopenharmony_ci      else
1867141cc406Sopenharmony_ci	{
1868141cc406Sopenharmony_ci	  dev->x_resolution = dev->val[OPT_RESOLUTION].w;
1869141cc406Sopenharmony_ci	  dev->y_resolution = dev->val[OPT_RESOLUTION].w;
1870141cc406Sopenharmony_ci	  if (dev->x_resolution > dev->def->x_resolution_max)
1871141cc406Sopenharmony_ci	    {
1872141cc406Sopenharmony_ci	      dev->x_resolution = dev->def->x_resolution_max;
1873141cc406Sopenharmony_ci	    }
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci	  dev->x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w));
1876141cc406Sopenharmony_ci	  dev->y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w));
1877141cc406Sopenharmony_ci	  dev->x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w));
1878141cc406Sopenharmony_ci	  dev->y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w));
1879141cc406Sopenharmony_ci	}
1880141cc406Sopenharmony_ci
1881141cc406Sopenharmony_ci      /* Check the corners are OK. */
1882141cc406Sopenharmony_ci      if (dev->x_tl > dev->x_br)
1883141cc406Sopenharmony_ci	{
1884141cc406Sopenharmony_ci	  int s;
1885141cc406Sopenharmony_ci	  s = dev->x_tl;
1886141cc406Sopenharmony_ci	  dev->x_tl = dev->x_br;
1887141cc406Sopenharmony_ci	  dev->x_br = s;
1888141cc406Sopenharmony_ci	}
1889141cc406Sopenharmony_ci      if (dev->y_tl > dev->y_br)
1890141cc406Sopenharmony_ci	{
1891141cc406Sopenharmony_ci	  int s;
1892141cc406Sopenharmony_ci	  s = dev->y_tl;
1893141cc406Sopenharmony_ci	  dev->y_tl = dev->y_br;
1894141cc406Sopenharmony_ci	  dev->y_br = s;
1895141cc406Sopenharmony_ci	}
1896141cc406Sopenharmony_ci
1897141cc406Sopenharmony_ci      dev->width = dev->x_br - dev->x_tl;
1898141cc406Sopenharmony_ci      dev->length = dev->y_br - dev->y_tl;
1899141cc406Sopenharmony_ci
1900141cc406Sopenharmony_ci      /* Prepare the parameters for the caller. */
1901141cc406Sopenharmony_ci      memset (&dev->params, 0, sizeof (SANE_Parameters));
1902141cc406Sopenharmony_ci
1903141cc406Sopenharmony_ci      dev->params.last_frame = SANE_TRUE;
1904141cc406Sopenharmony_ci
1905141cc406Sopenharmony_ci      switch (dev->scan_mode)
1906141cc406Sopenharmony_ci	{
1907141cc406Sopenharmony_ci	case TECO_BW:
1908141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_GRAY;
1909141cc406Sopenharmony_ci	  dev->params.pixels_per_line =
1910141cc406Sopenharmony_ci	    ((dev->width * dev->x_resolution) / 300) & ~0x7;
1911141cc406Sopenharmony_ci	  dev->params.bytes_per_line = dev->params.pixels_per_line / 8;
1912141cc406Sopenharmony_ci	  dev->params.depth = 1;
1913141cc406Sopenharmony_ci	  dev->pass = 1;
1914141cc406Sopenharmony_ci	  break;
1915141cc406Sopenharmony_ci	case TECO_GRAYSCALE:
1916141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_GRAY;
1917141cc406Sopenharmony_ci	  dev->params.pixels_per_line =
1918141cc406Sopenharmony_ci	    ((dev->width * dev->x_resolution) / 300);
1919141cc406Sopenharmony_ci	  dev->params.bytes_per_line = dev->params.pixels_per_line;
1920141cc406Sopenharmony_ci	  dev->params.depth = 8;
1921141cc406Sopenharmony_ci	  dev->pass = 1;
1922141cc406Sopenharmony_ci	  break;
1923141cc406Sopenharmony_ci	case TECO_COLOR:
1924141cc406Sopenharmony_ci	  dev->params.format = SANE_FRAME_RGB;
1925141cc406Sopenharmony_ci	  dev->params.pixels_per_line =
1926141cc406Sopenharmony_ci	    ((dev->width * dev->x_resolution) / 300);
1927141cc406Sopenharmony_ci	  dev->pass = dev->def->pass;
1928141cc406Sopenharmony_ci	  dev->params.bytes_per_line = dev->params.pixels_per_line * 3;
1929141cc406Sopenharmony_ci	  dev->params.depth = 8;
1930141cc406Sopenharmony_ci	  break;
1931141cc406Sopenharmony_ci	}
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci      dev->params.lines = (dev->length * dev->y_resolution) / 300;
1934141cc406Sopenharmony_ci    }
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci  /* Return the current values. */
1937141cc406Sopenharmony_ci  if (params)
1938141cc406Sopenharmony_ci    {
1939141cc406Sopenharmony_ci      *params = (dev->params);
1940141cc406Sopenharmony_ci    }
1941141cc406Sopenharmony_ci
1942141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
1943141cc406Sopenharmony_ci
1944141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1945141cc406Sopenharmony_ci}
1946141cc406Sopenharmony_ci
1947141cc406Sopenharmony_ciSANE_Status
1948141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1949141cc406Sopenharmony_ci{
1950141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
1951141cc406Sopenharmony_ci  SANE_Status status;
1952141cc406Sopenharmony_ci  size_t size;
1953141cc406Sopenharmony_ci
1954141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: enter\n");
1955141cc406Sopenharmony_ci
1956141cc406Sopenharmony_ci  if (!(dev->scanning))
1957141cc406Sopenharmony_ci    {
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci      /* Open again the scanner. */
1960141cc406Sopenharmony_ci      if (sanei_scsi_open
1961141cc406Sopenharmony_ci	  (dev->devicename, &(dev->sfd), teco_sense_handler, dev) != 0)
1962141cc406Sopenharmony_ci	{
1963141cc406Sopenharmony_ci	  DBG (DBG_error, "ERROR: sane_start: open failed\n");
1964141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1965141cc406Sopenharmony_ci	}
1966141cc406Sopenharmony_ci
1967141cc406Sopenharmony_ci      /* Set the correct parameters. */
1968141cc406Sopenharmony_ci      sane_get_parameters (dev, NULL);
1969141cc406Sopenharmony_ci
1970141cc406Sopenharmony_ci      /* The scanner must be ready. */
1971141cc406Sopenharmony_ci      status = teco_wait_scanner (dev);
1972141cc406Sopenharmony_ci      if (status)
1973141cc406Sopenharmony_ci	{
1974141cc406Sopenharmony_ci	  teco_close (dev);
1975141cc406Sopenharmony_ci	  return status;
1976141cc406Sopenharmony_ci	}
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci      status = teco_mode_select (dev);
1979141cc406Sopenharmony_ci      if (status)
1980141cc406Sopenharmony_ci	{
1981141cc406Sopenharmony_ci	  teco_close (dev);
1982141cc406Sopenharmony_ci	  return status;
1983141cc406Sopenharmony_ci	}
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci      if (dev->scan_mode == TECO_COLOR)
1986141cc406Sopenharmony_ci	{
1987141cc406Sopenharmony_ci	  dev->pass = dev->def->pass;
1988141cc406Sopenharmony_ci	}
1989141cc406Sopenharmony_ci      else
1990141cc406Sopenharmony_ci	{
1991141cc406Sopenharmony_ci	  dev->pass = 1;
1992141cc406Sopenharmony_ci	}
1993141cc406Sopenharmony_ci
1994141cc406Sopenharmony_ci      if (dev->def->tecoref != TECO_VM3510)
1995141cc406Sopenharmony_ci	{
1996141cc406Sopenharmony_ci	  status = teco_set_window (dev);
1997141cc406Sopenharmony_ci	  if (status)
1998141cc406Sopenharmony_ci	    {
1999141cc406Sopenharmony_ci	      teco_close (dev);
2000141cc406Sopenharmony_ci	      return status;
2001141cc406Sopenharmony_ci	    }
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci	  dev->real_bytes_left = 0;
2004141cc406Sopenharmony_ci	  status = get_filled_data_length (dev, &size);
2005141cc406Sopenharmony_ci	  if (status)
2006141cc406Sopenharmony_ci	    {
2007141cc406Sopenharmony_ci	      teco_close (dev);
2008141cc406Sopenharmony_ci	      return status;
2009141cc406Sopenharmony_ci	    }
2010141cc406Sopenharmony_ci	}
2011141cc406Sopenharmony_ci
2012141cc406Sopenharmony_ci#if 0
2013141cc406Sopenharmony_ci      /* The windows driver does that, but some scanners don't like it. */
2014141cc406Sopenharmony_ci      teco_vendor_spec (dev);
2015141cc406Sopenharmony_ci      if (status)
2016141cc406Sopenharmony_ci	{
2017141cc406Sopenharmony_ci	  teco_close (dev);
2018141cc406Sopenharmony_ci	  return status;
2019141cc406Sopenharmony_ci	}
2020141cc406Sopenharmony_ci#endif
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci      status = teco_send_gamma (dev);
2023141cc406Sopenharmony_ci      if (status)
2024141cc406Sopenharmony_ci	{
2025141cc406Sopenharmony_ci	  teco_close (dev);
2026141cc406Sopenharmony_ci	  return status;
2027141cc406Sopenharmony_ci	}
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci      status = teco_set_window (dev);
2030141cc406Sopenharmony_ci      if (status)
2031141cc406Sopenharmony_ci	{
2032141cc406Sopenharmony_ci	  teco_close (dev);
2033141cc406Sopenharmony_ci	  return status;
2034141cc406Sopenharmony_ci	}
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci      status = teco_scan (dev);
2037141cc406Sopenharmony_ci      if (status)
2038141cc406Sopenharmony_ci	{
2039141cc406Sopenharmony_ci	  teco_close (dev);
2040141cc406Sopenharmony_ci	  return status;
2041141cc406Sopenharmony_ci	}
2042141cc406Sopenharmony_ci
2043141cc406Sopenharmony_ci      if (dev->def->tecoref == TECO_VM3510)
2044141cc406Sopenharmony_ci	{
2045141cc406Sopenharmony_ci	  dev->real_bytes_left = 0;
2046141cc406Sopenharmony_ci	  status = get_filled_data_length (dev, &size);
2047141cc406Sopenharmony_ci	  if (status)
2048141cc406Sopenharmony_ci	    {
2049141cc406Sopenharmony_ci	      teco_close (dev);
2050141cc406Sopenharmony_ci	      return status;
2051141cc406Sopenharmony_ci	    }
2052141cc406Sopenharmony_ci	}
2053141cc406Sopenharmony_ci    }
2054141cc406Sopenharmony_ci  else
2055141cc406Sopenharmony_ci    {
2056141cc406Sopenharmony_ci      /* Scan has already started. */
2057141cc406Sopenharmony_ci      dev->pass--;
2058141cc406Sopenharmony_ci    }
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci  /* Set the frame parameter. */
2061141cc406Sopenharmony_ci  if (dev->scan_mode == TECO_COLOR && dev->def->pass > 1)
2062141cc406Sopenharmony_ci    {
2063141cc406Sopenharmony_ci      SANE_Frame frames[] = { 0, SANE_FRAME_BLUE,
2064141cc406Sopenharmony_ci	SANE_FRAME_GREEN, SANE_FRAME_RED
2065141cc406Sopenharmony_ci      };
2066141cc406Sopenharmony_ci      dev->params.format = frames[dev->pass];
2067141cc406Sopenharmony_ci    }
2068141cc406Sopenharmony_ci
2069141cc406Sopenharmony_ci  /* Is it the last frame? */
2070141cc406Sopenharmony_ci  if (dev->pass > 1)
2071141cc406Sopenharmony_ci    {
2072141cc406Sopenharmony_ci      dev->params.last_frame = SANE_FALSE;
2073141cc406Sopenharmony_ci    }
2074141cc406Sopenharmony_ci  else
2075141cc406Sopenharmony_ci    {
2076141cc406Sopenharmony_ci      dev->params.last_frame = SANE_TRUE;
2077141cc406Sopenharmony_ci    }
2078141cc406Sopenharmony_ci
2079141cc406Sopenharmony_ci  dev->image_end = 0;
2080141cc406Sopenharmony_ci  dev->image_begin = 0;
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci  dev->bytes_left = dev->params.bytes_per_line * dev->params.lines;
2083141cc406Sopenharmony_ci  dev->real_bytes_left = dev->params.bytes_per_line * dev->params.lines;
2084141cc406Sopenharmony_ci
2085141cc406Sopenharmony_ci  dev->scanning = SANE_TRUE;
2086141cc406Sopenharmony_ci
2087141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
2088141cc406Sopenharmony_ci
2089141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2090141cc406Sopenharmony_ci}
2091141cc406Sopenharmony_ci
2092141cc406Sopenharmony_ciSANE_Status
2093141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
2094141cc406Sopenharmony_ci	   SANE_Int * len)
2095141cc406Sopenharmony_ci{
2096141cc406Sopenharmony_ci  SANE_Status status;
2097141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
2098141cc406Sopenharmony_ci  size_t size;
2099141cc406Sopenharmony_ci  int buf_offset;		/* offset into buf */
2100141cc406Sopenharmony_ci
2101141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: enter\n");
2102141cc406Sopenharmony_ci
2103141cc406Sopenharmony_ci  *len = 0;
2104141cc406Sopenharmony_ci
2105141cc406Sopenharmony_ci  if (!(dev->scanning))
2106141cc406Sopenharmony_ci    {
2107141cc406Sopenharmony_ci      /* OOPS, not scanning */
2108141cc406Sopenharmony_ci      return do_cancel (dev);
2109141cc406Sopenharmony_ci    }
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci  if (dev->bytes_left <= 0)
2112141cc406Sopenharmony_ci    {
2113141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
2114141cc406Sopenharmony_ci    }
2115141cc406Sopenharmony_ci
2116141cc406Sopenharmony_ci  buf_offset = 0;
2117141cc406Sopenharmony_ci
2118141cc406Sopenharmony_ci  do
2119141cc406Sopenharmony_ci    {
2120141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
2121141cc406Sopenharmony_ci	{
2122141cc406Sopenharmony_ci	  /* Fill image */
2123141cc406Sopenharmony_ci	  status = teco_fill_image (dev);
2124141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2125141cc406Sopenharmony_ci	    {
2126141cc406Sopenharmony_ci	      return (status);
2127141cc406Sopenharmony_ci	    }
2128141cc406Sopenharmony_ci	}
2129141cc406Sopenharmony_ci
2130141cc406Sopenharmony_ci      /* Something must have been read */
2131141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
2132141cc406Sopenharmony_ci	{
2133141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_read: nothing read\n");
2134141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
2135141cc406Sopenharmony_ci	}
2136141cc406Sopenharmony_ci
2137141cc406Sopenharmony_ci      /* Copy the data to the frontend buffer. */
2138141cc406Sopenharmony_ci      size = max_len - buf_offset;
2139141cc406Sopenharmony_ci      if (size > dev->bytes_left)
2140141cc406Sopenharmony_ci	{
2141141cc406Sopenharmony_ci	  size = dev->bytes_left;
2142141cc406Sopenharmony_ci	}
2143141cc406Sopenharmony_ci      teco_copy_raw_to_frontend (dev, buf + buf_offset, &size);
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci      buf_offset += size;
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci      dev->bytes_left -= size;
2148141cc406Sopenharmony_ci      *len += size;
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci    }
2151141cc406Sopenharmony_ci  while ((buf_offset != max_len) && dev->bytes_left);
2152141cc406Sopenharmony_ci
2153141cc406Sopenharmony_ci  DBG (DBG_info, "sane_read: leave, bytes_left=%ld\n",
2154141cc406Sopenharmony_ci       (long) dev->bytes_left);
2155141cc406Sopenharmony_ci
2156141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2157141cc406Sopenharmony_ci}
2158141cc406Sopenharmony_ci
2159141cc406Sopenharmony_ciSANE_Status
2160141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking)
2161141cc406Sopenharmony_ci{
2162141cc406Sopenharmony_ci  SANE_Status status;
2163141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: enter\n");
2166141cc406Sopenharmony_ci
2167141cc406Sopenharmony_ci  if (dev->scanning == SANE_FALSE)
2168141cc406Sopenharmony_ci    {
2169141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2170141cc406Sopenharmony_ci    }
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_ci  if (non_blocking == SANE_FALSE)
2173141cc406Sopenharmony_ci    {
2174141cc406Sopenharmony_ci      status = SANE_STATUS_GOOD;
2175141cc406Sopenharmony_ci    }
2176141cc406Sopenharmony_ci  else
2177141cc406Sopenharmony_ci    {
2178141cc406Sopenharmony_ci      status = SANE_STATUS_UNSUPPORTED;
2179141cc406Sopenharmony_ci    }
2180141cc406Sopenharmony_ci
2181141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: exit\n");
2182141cc406Sopenharmony_ci
2183141cc406Sopenharmony_ci  return status;
2184141cc406Sopenharmony_ci}
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ciSANE_Status
2187141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ *fd)
2188141cc406Sopenharmony_ci{
2189141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: enter\n");
2190141cc406Sopenharmony_ci
2191141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: exit\n");
2192141cc406Sopenharmony_ci
2193141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2194141cc406Sopenharmony_ci}
2195141cc406Sopenharmony_ci
2196141cc406Sopenharmony_civoid
2197141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2198141cc406Sopenharmony_ci{
2199141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
2200141cc406Sopenharmony_ci
2201141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: enter\n");
2202141cc406Sopenharmony_ci
2203141cc406Sopenharmony_ci  do_cancel (dev);
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: exit\n");
2206141cc406Sopenharmony_ci}
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_civoid
2209141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2210141cc406Sopenharmony_ci{
2211141cc406Sopenharmony_ci  Teco_Scanner *dev = handle;
2212141cc406Sopenharmony_ci  Teco_Scanner *dev_tmp;
2213141cc406Sopenharmony_ci
2214141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: enter\n");
2215141cc406Sopenharmony_ci
2216141cc406Sopenharmony_ci  do_cancel (dev);
2217141cc406Sopenharmony_ci  teco_close (dev);
2218141cc406Sopenharmony_ci
2219141cc406Sopenharmony_ci  /* Unlink dev. */
2220141cc406Sopenharmony_ci  if (first_dev == dev)
2221141cc406Sopenharmony_ci    {
2222141cc406Sopenharmony_ci      first_dev = dev->next;
2223141cc406Sopenharmony_ci    }
2224141cc406Sopenharmony_ci  else
2225141cc406Sopenharmony_ci    {
2226141cc406Sopenharmony_ci      dev_tmp = first_dev;
2227141cc406Sopenharmony_ci      while (dev_tmp->next && dev_tmp->next != dev)
2228141cc406Sopenharmony_ci	{
2229141cc406Sopenharmony_ci	  dev_tmp = dev_tmp->next;
2230141cc406Sopenharmony_ci	}
2231141cc406Sopenharmony_ci      if (dev_tmp->next != NULL)
2232141cc406Sopenharmony_ci	{
2233141cc406Sopenharmony_ci	  dev_tmp->next = dev_tmp->next->next;
2234141cc406Sopenharmony_ci	}
2235141cc406Sopenharmony_ci    }
2236141cc406Sopenharmony_ci
2237141cc406Sopenharmony_ci  teco_free (dev);
2238141cc406Sopenharmony_ci  num_devices--;
2239141cc406Sopenharmony_ci
2240141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: exit\n");
2241141cc406Sopenharmony_ci}
2242141cc406Sopenharmony_ci
2243141cc406Sopenharmony_civoid
2244141cc406Sopenharmony_cisane_exit (void)
2245141cc406Sopenharmony_ci{
2246141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: enter\n");
2247141cc406Sopenharmony_ci
2248141cc406Sopenharmony_ci  while (first_dev)
2249141cc406Sopenharmony_ci    {
2250141cc406Sopenharmony_ci      sane_close (first_dev);
2251141cc406Sopenharmony_ci    }
2252141cc406Sopenharmony_ci
2253141cc406Sopenharmony_ci  if (devlist)
2254141cc406Sopenharmony_ci    {
2255141cc406Sopenharmony_ci      free (devlist);
2256141cc406Sopenharmony_ci      devlist = NULL;
2257141cc406Sopenharmony_ci    }
2258141cc406Sopenharmony_ci
2259141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
2260141cc406Sopenharmony_ci}
2261