1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   This file (C) 1997 Ingo Schneider
4141cc406Sopenharmony_ci             (C) 1998 Karl Anders Øygard
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   SANE is free software; you can redistribute it and/or modify it under
9141cc406Sopenharmony_ci   the terms of the GNU General Public License as published by the Free
10141cc406Sopenharmony_ci   Software Foundation; either version 2 of the License, or (at your
11141cc406Sopenharmony_ci   option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   SANE is distributed in the hope that it will be useful, but WITHOUT
14141cc406Sopenharmony_ci   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15141cc406Sopenharmony_ci   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16141cc406Sopenharmony_ci   for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with sane; see the file COPYING.
20141cc406Sopenharmony_ci   If not, see <https://www.gnu.org/licenses/>.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   This file implements a SANE backend for AGFA Focus flatbed scanners.  */
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci#include "../include/sane/config.h"
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_ci#include <signal.h>
27141cc406Sopenharmony_ci#include <errno.h>
28141cc406Sopenharmony_ci#include <fcntl.h>
29141cc406Sopenharmony_ci#include <stdlib.h>
30141cc406Sopenharmony_ci#include <unistd.h>
31141cc406Sopenharmony_ci#include <string.h>
32141cc406Sopenharmony_ci#include <sys/types.h>
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci#include "../include/sane/sane.h"
35141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
36141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
37141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
38141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
39141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci#define BACKEND_NAME	agfafocus
42141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci#include "agfafocus.h"
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#ifndef PATH_MAX
47141cc406Sopenharmony_ci# define PATH_MAX	1024
48141cc406Sopenharmony_ci#endif
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci#undef Byte
52141cc406Sopenharmony_ci#define Byte SANE_Byte
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
55141cc406Sopenharmony_cistatic int num_devices;
56141cc406Sopenharmony_cistatic AgfaFocus_Device *agfafocus_devices;
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_cistatic const SANE_String_Const focus_mode_list[] =
59141cc406Sopenharmony_ci{
60141cc406Sopenharmony_ci  "Lineart", "Gray (6 bit)",
61141cc406Sopenharmony_ci  0
62141cc406Sopenharmony_ci};
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_cistatic const SANE_String_Const focusii_mode_list[] =
65141cc406Sopenharmony_ci{
66141cc406Sopenharmony_ci  "Lineart", "Gray (6 bit)", "Gray (8 bit)",
67141cc406Sopenharmony_ci  0
68141cc406Sopenharmony_ci};
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_cistatic const SANE_String_Const focuscolor_mode_list[] =
71141cc406Sopenharmony_ci{
72141cc406Sopenharmony_ci  "Lineart", "Gray (6 bit)", "Gray (8 bit)", "Color (18 bit)", "Color (24 bit)",
73141cc406Sopenharmony_ci  0
74141cc406Sopenharmony_ci};
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list[] =
77141cc406Sopenharmony_ci{
78141cc406Sopenharmony_ci  "None", "Dispersed dot 4x4", "Round (Clustered dot 4x4)", "Diamond (Clustered dot 4x4)",
79141cc406Sopenharmony_ci  0
80141cc406Sopenharmony_ci};
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_cistatic const SANE_String_Const halftone_upload_list[] =
83141cc406Sopenharmony_ci{
84141cc406Sopenharmony_ci  "None", "Dispersed dot 4x4", "Round (Clustered dot 4x4)", "Diamond (Clustered dot 4x4)",
85141cc406Sopenharmony_ci  0
86141cc406Sopenharmony_ci};
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_cistatic const SANE_String_Const source_list[] =
89141cc406Sopenharmony_ci{
90141cc406Sopenharmony_ci  "Opaque/Normal", "Transparency",
91141cc406Sopenharmony_ci  0
92141cc406Sopenharmony_ci};
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic const SANE_String_Const quality_list[] =
95141cc406Sopenharmony_ci{
96141cc406Sopenharmony_ci  "Low", "Normal", "High",
97141cc406Sopenharmony_ci  0
98141cc406Sopenharmony_ci};
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_cistatic size_t
101141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
102141cc406Sopenharmony_ci{
103141cc406Sopenharmony_ci  size_t size, max_size = 0;
104141cc406Sopenharmony_ci  int i;
105141cc406Sopenharmony_ci  DBG (11, ">> max_string_size\n");
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
108141cc406Sopenharmony_ci    {
109141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
110141cc406Sopenharmony_ci      if (size > max_size)
111141cc406Sopenharmony_ci        max_size = size;
112141cc406Sopenharmony_ci    }
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci  DBG (11, "<< max_string_size\n");
115141cc406Sopenharmony_ci  return max_size;
116141cc406Sopenharmony_ci}
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci/* sets loc_s bytes long value at offset loc in scsi command to value size  */
119141cc406Sopenharmony_cistatic void
120141cc406Sopenharmony_ciset_size (Byte * loc, int loc_s, size_t size)
121141cc406Sopenharmony_ci{
122141cc406Sopenharmony_ci  int i;
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_ci  for (i = 0; i < loc_s; i++)
125141cc406Sopenharmony_ci    {
126141cc406Sopenharmony_ci      loc[loc_s - i - 1] = (size >> (i * 8)) & 0xff;
127141cc406Sopenharmony_ci    }
128141cc406Sopenharmony_ci}
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci/* gets loc_s bytes long value from loc in scsi command */
131141cc406Sopenharmony_cistatic int
132141cc406Sopenharmony_ciget_size (Byte * loc, int loc_s)
133141cc406Sopenharmony_ci{
134141cc406Sopenharmony_ci  int i;
135141cc406Sopenharmony_ci  int j = 0;
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci  for (i = 0; i < loc_s; i++)
138141cc406Sopenharmony_ci    {
139141cc406Sopenharmony_ci      j = (j << 8) + (loc[i] & 0xff);
140141cc406Sopenharmony_ci    }
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci  return j;
143141cc406Sopenharmony_ci}
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_cistatic long
146141cc406Sopenharmony_cireserve_unit (int fd)
147141cc406Sopenharmony_ci{
148141cc406Sopenharmony_ci  struct
149141cc406Sopenharmony_ci  {
150141cc406Sopenharmony_ci    /* Command */
151141cc406Sopenharmony_ci    Byte cmd;
152141cc406Sopenharmony_ci    Byte lun;
153141cc406Sopenharmony_ci    Byte res[2];
154141cc406Sopenharmony_ci    Byte tr_len;
155141cc406Sopenharmony_ci    Byte ctrl;
156141cc406Sopenharmony_ci  }
157141cc406Sopenharmony_ci  scsi_reserve;
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci  memset (&scsi_reserve, 0, sizeof (scsi_reserve));
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci  scsi_reserve.cmd = 0x16; /* RELEASE */
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci  DBG (3, "reserve_unit()\n");
164141cc406Sopenharmony_ci  return sanei_scsi_cmd (fd, &scsi_reserve, sizeof (scsi_reserve), 0, 0);
165141cc406Sopenharmony_ci}
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_cistatic long
168141cc406Sopenharmony_cirelease_unit (int fd)
169141cc406Sopenharmony_ci{
170141cc406Sopenharmony_ci  struct
171141cc406Sopenharmony_ci  {
172141cc406Sopenharmony_ci    /* Command */
173141cc406Sopenharmony_ci    Byte cmd;
174141cc406Sopenharmony_ci    Byte lun;
175141cc406Sopenharmony_ci    Byte res[2];
176141cc406Sopenharmony_ci    Byte tr_len;
177141cc406Sopenharmony_ci    Byte ctrl;
178141cc406Sopenharmony_ci  }
179141cc406Sopenharmony_ci  scsi_release;
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci  memset (&scsi_release, 0, sizeof (scsi_release));
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci  scsi_release.cmd = 0x17; /* RELEASE */
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci  DBG (3, "release_unit()\n");
186141cc406Sopenharmony_ci  return sanei_scsi_cmd (fd, &scsi_release, sizeof (scsi_release), 0, 0);
187141cc406Sopenharmony_ci}
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_cistatic SANE_Status
190141cc406Sopenharmony_citest_ready (int fd)
191141cc406Sopenharmony_ci{
192141cc406Sopenharmony_ci  SANE_Status status;
193141cc406Sopenharmony_ci  int try;
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci  struct
196141cc406Sopenharmony_ci  {
197141cc406Sopenharmony_ci    /* Command */
198141cc406Sopenharmony_ci    Byte cmd;
199141cc406Sopenharmony_ci    Byte lun;
200141cc406Sopenharmony_ci    Byte res[2];
201141cc406Sopenharmony_ci    Byte tr_len;
202141cc406Sopenharmony_ci    Byte ctrl;
203141cc406Sopenharmony_ci  }
204141cc406Sopenharmony_ci  scsi_test_ready;
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci  memset (&scsi_test_ready, 0, sizeof (scsi_test_ready));
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci  scsi_test_ready.cmd = 0x00; /* TEST UNIT READY */
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci  for (try = 0; try < 1000; ++try)
211141cc406Sopenharmony_ci    {
212141cc406Sopenharmony_ci      DBG (3, "test_ready: sending TEST_UNIT_READY\n");
213141cc406Sopenharmony_ci      status = sanei_scsi_cmd (fd, &scsi_test_ready, sizeof (scsi_test_ready),
214141cc406Sopenharmony_ci			       0, 0);
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci      switch (status)
217141cc406Sopenharmony_ci	{
218141cc406Sopenharmony_ci	case SANE_STATUS_DEVICE_BUSY:
219141cc406Sopenharmony_ci	  usleep (100000);	/* retry after 100ms */
220141cc406Sopenharmony_ci	  break;
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci	case SANE_STATUS_GOOD:
223141cc406Sopenharmony_ci	  return status;
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci	default:
226141cc406Sopenharmony_ci	  DBG (1, "test_ready: test unit ready failed (%s)\n",
227141cc406Sopenharmony_ci	       sane_strstatus (status));
228141cc406Sopenharmony_ci	  return status;
229141cc406Sopenharmony_ci	}
230141cc406Sopenharmony_ci    }
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci  DBG (1, "test_ready: timed out after %d attempts\n", try);
233141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
234141cc406Sopenharmony_ci}
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_cistatic SANE_Status
237141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char *result, void *arg)
238141cc406Sopenharmony_ci{
239141cc406Sopenharmony_ci  (void) scsi_fd;			/* silence gcc */
240141cc406Sopenharmony_ci  (void) arg;				/* silence gcc */
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci  if (result[0])
243141cc406Sopenharmony_ci    {
244141cc406Sopenharmony_ci      DBG (0, "sense_handler() : sense code = %02x\n", result[0]);
245141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
246141cc406Sopenharmony_ci    }
247141cc406Sopenharmony_ci  else
248141cc406Sopenharmony_ci    {
249141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
250141cc406Sopenharmony_ci    }
251141cc406Sopenharmony_ci}
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_cistatic SANE_Status
254141cc406Sopenharmony_cistop_scan (int fd)
255141cc406Sopenharmony_ci{
256141cc406Sopenharmony_ci  (void) fd;				/* silence gcc */
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci  /* XXX don't know how to stop the scanner. To be tested ! */
259141cc406Sopenharmony_ci#if 0
260141cc406Sopenharmony_ci  const Byte scsi_rewind[] =
261141cc406Sopenharmony_ci  {
262141cc406Sopenharmony_ci    0x01, 0x00, 0x00, 0x00, 0x00, 0x00
263141cc406Sopenharmony_ci  };
264141cc406Sopenharmony_ci  DBG (1, "Trying to stop scanner...\n");
265141cc406Sopenharmony_ci  return sanei_scsi_cmd (fd, scsi_rewind, sizeof (scsi_rewind), 0, 0);
266141cc406Sopenharmony_ci#else
267141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
268141cc406Sopenharmony_ci#endif
269141cc406Sopenharmony_ci}
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_cistatic SANE_Status
273141cc406Sopenharmony_cistart_scan (int fd, SANE_Bool cont)
274141cc406Sopenharmony_ci{
275141cc406Sopenharmony_ci  struct
276141cc406Sopenharmony_ci  {
277141cc406Sopenharmony_ci    /* Command */
278141cc406Sopenharmony_ci    Byte cmd;
279141cc406Sopenharmony_ci    Byte lun;
280141cc406Sopenharmony_ci    Byte res[2];
281141cc406Sopenharmony_ci    Byte tr_len;
282141cc406Sopenharmony_ci    Byte ctrl;
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci    /* Data */
285141cc406Sopenharmony_ci    Byte wid;
286141cc406Sopenharmony_ci  }
287141cc406Sopenharmony_ci  scsi_start_scan;
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci  memset (&scsi_start_scan, 0, sizeof (scsi_start_scan));
290141cc406Sopenharmony_ci
291141cc406Sopenharmony_ci  scsi_start_scan.cmd = 0x1b; /* SCAN */
292141cc406Sopenharmony_ci  scsi_start_scan.tr_len = 1;
293141cc406Sopenharmony_ci  scsi_start_scan.wid = 0;
294141cc406Sopenharmony_ci  scsi_start_scan.ctrl = (cont == SANE_TRUE) ? 0x80 : 0x00;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci  DBG (1, "Starting scanner ...\n");
297141cc406Sopenharmony_ci  return sanei_scsi_cmd (fd, &scsi_start_scan, sizeof (scsi_start_scan), 0, 0);
298141cc406Sopenharmony_ci}
299141cc406Sopenharmony_ci
300141cc406Sopenharmony_cistatic void
301141cc406Sopenharmony_ciwait_ready (int fd)
302141cc406Sopenharmony_ci{
303141cc406Sopenharmony_ci  struct
304141cc406Sopenharmony_ci  {
305141cc406Sopenharmony_ci    Byte bytes[2];		/* Total # of bytes */
306141cc406Sopenharmony_ci    Byte scan[2];		/* ms to complete - driver sleep time */
307141cc406Sopenharmony_ci  } result;
308141cc406Sopenharmony_ci
309141cc406Sopenharmony_ci  size_t size = sizeof (result);
310141cc406Sopenharmony_ci  SANE_Status status;
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  struct {
313141cc406Sopenharmony_ci    Byte cmd;
314141cc406Sopenharmony_ci    Byte lun;
315141cc406Sopenharmony_ci    Byte data_type;
316141cc406Sopenharmony_ci    Byte re1[3];
317141cc406Sopenharmony_ci    Byte tr_len[3];
318141cc406Sopenharmony_ci    Byte ctrl;
319141cc406Sopenharmony_ci  } cmd;
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci  cmd.cmd = 0x28;       /* READ */
324141cc406Sopenharmony_ci  cmd.data_type = 0x80; /* get scan time */
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci  set_size (cmd.tr_len, 3, sizeof (result));
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci  while (1)
329141cc406Sopenharmony_ci    {
330141cc406Sopenharmony_ci      status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd),
331141cc406Sopenharmony_ci			       &result, &size);
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD || size != sizeof (result))
334141cc406Sopenharmony_ci	{
335141cc406Sopenharmony_ci	  /*
336141cc406Sopenharmony_ci	     Command failed, the assembler code of the windows scan library
337141cc406Sopenharmony_ci	     ignores this condition, and so do I
338141cc406Sopenharmony_ci	   */
339141cc406Sopenharmony_ci	  break;
340141cc406Sopenharmony_ci	}
341141cc406Sopenharmony_ci      else
342141cc406Sopenharmony_ci	{
343141cc406Sopenharmony_ci	  /* left is the amount of seconds left till the scanner is
344141cc406Sopenharmony_ci             ready * 100 */
345141cc406Sopenharmony_ci	  int left = get_size (result.scan, 2);
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci	  DBG (1, "wait_ready() : %d left...\n", left);
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci	  if (!left)
350141cc406Sopenharmony_ci	    break;
351141cc406Sopenharmony_ci	  /* We delay only for half the given time */
352141cc406Sopenharmony_ci	  else if (left < 200)
353141cc406Sopenharmony_ci	    usleep (left * 5000);
354141cc406Sopenharmony_ci	  else
355141cc406Sopenharmony_ci	    sleep (left / 200);
356141cc406Sopenharmony_ci	}
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci  return;
360141cc406Sopenharmony_ci}
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_cistatic SANE_Status
363141cc406Sopenharmony_ciget_read_sizes (int fd, int *lines_available, int *bpl, int *total_lines)
364141cc406Sopenharmony_ci{
365141cc406Sopenharmony_ci  struct {
366141cc406Sopenharmony_ci    Byte reserved1[8];
367141cc406Sopenharmony_ci    Byte line_width[2];
368141cc406Sopenharmony_ci    Byte total_lines[2];
369141cc406Sopenharmony_ci    Byte cur_line[2];
370141cc406Sopenharmony_ci    Byte lines_this_block[2];
371141cc406Sopenharmony_ci    Byte reserved[8];
372141cc406Sopenharmony_ci  } read_sizes;
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci  const Byte scsi_read[] =
375141cc406Sopenharmony_ci  {
376141cc406Sopenharmony_ci    0x28, 0x00,				/* opcode, lun */
377141cc406Sopenharmony_ci    0x81,				/* data type 81 == read time left */
378141cc406Sopenharmony_ci    0x00, 0x00, 0x00,			/* reserved */
379141cc406Sopenharmony_ci    0x00, 0x00, sizeof (read_sizes),	/* transfer length */
380141cc406Sopenharmony_ci    0x00,				/* control byte */
381141cc406Sopenharmony_ci  };
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci  size_t size = sizeof (read_sizes);
384141cc406Sopenharmony_ci  SANE_Status status;
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, scsi_read, sizeof (scsi_read), &read_sizes, &size);
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size != sizeof (read_sizes))
389141cc406Sopenharmony_ci    {
390141cc406Sopenharmony_ci      /* Command failed */
391141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
392141cc406Sopenharmony_ci    }
393141cc406Sopenharmony_ci  else
394141cc406Sopenharmony_ci    {
395141cc406Sopenharmony_ci      *lines_available = get_size (read_sizes.lines_this_block, 2);
396141cc406Sopenharmony_ci      *bpl = get_size (read_sizes.cur_line, 2);
397141cc406Sopenharmony_ci      if (total_lines)
398141cc406Sopenharmony_ci	*total_lines = get_size (read_sizes.total_lines, 2);
399141cc406Sopenharmony_ci    }
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  DBG (1, "get_read_sizes() : %d of %d, %d\n",
402141cc406Sopenharmony_ci       *lines_available, total_lines ? *total_lines : -1, *bpl);
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
405141cc406Sopenharmony_ci}
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_cistatic SANE_Status
408141cc406Sopenharmony_ciset_window (AgfaFocus_Scanner * s)
409141cc406Sopenharmony_ci/* This function sets and sends the window for scanning */
410141cc406Sopenharmony_ci{
411141cc406Sopenharmony_ci  double pixels_per_mm = (double) s->val[OPT_RESOLUTION].w / MM_PER_INCH;
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci  SANE_Bool auto_bright = s->val[OPT_AUTO_BRIGHTNESS].b;
414141cc406Sopenharmony_ci  SANE_Bool auto_contr = s->val[OPT_AUTO_CONTRAST].b;
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  /* ranges down 255 (dark) down to 1(bright) */
417141cc406Sopenharmony_ci  int brightness = auto_bright ? 0 : (SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)
418141cc406Sopenharmony_ci				      * -1.27 + 128.5);
419141cc406Sopenharmony_ci  /* ranges from 1 (little contrast) up to 255 (much contrast) */
420141cc406Sopenharmony_ci  int contrast = auto_contr ? 0 : (SANE_UNFIX (s->val[OPT_CONTRAST].w)
421141cc406Sopenharmony_ci				   * 1.27 + 128.5);
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci  int width;
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci  /* ranges from 40 (dark) down to 0 (bright) */
426141cc406Sopenharmony_ci  int bright_adjust = (SANE_UNFIX (s->val[OPT_BRIGHTNESS].w) * -20.0) / 100.0 + 20.0;
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci  /* ranges from 20 (little contrast) down to -20 = 235 (much contrast) */
429141cc406Sopenharmony_ci  int contr_adjust = (SANE_UNFIX (s->val[OPT_CONTRAST].w) * -20.0) / 100.0;
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci  /* Warning ! The following structure SEEMS to be a valid SCSI-2 SET_WINDOW
432141cc406Sopenharmony_ci     command.  But e.g. the limits for the window are only 2 Bytes instead
433141cc406Sopenharmony_ci     of 4.  The scanner was built at about 1990, so SCSI-2 wasn't available
434141cc406Sopenharmony_ci     for development...  */
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci  struct
437141cc406Sopenharmony_ci    {
438141cc406Sopenharmony_ci      Byte cmd;
439141cc406Sopenharmony_ci      Byte lun;
440141cc406Sopenharmony_ci      Byte re1[4];
441141cc406Sopenharmony_ci      Byte tr_len[3];
442141cc406Sopenharmony_ci      Byte ctrl;
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci      Byte re2[6];
445141cc406Sopenharmony_ci      Byte wd_len[2];
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci      struct
448141cc406Sopenharmony_ci	{
449141cc406Sopenharmony_ci	  Byte wid;                      /* Window ID */
450141cc406Sopenharmony_ci	  Byte autobit;                  /* Window creation */
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci	  Byte x_axis_res[2];            /* X resolution */
453141cc406Sopenharmony_ci	  Byte y_axis_res[2];            /* X resolution */
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci	  Byte x_axis_ul[2];             /* X upper left */
456141cc406Sopenharmony_ci	  Byte y_axis_ul[2];             /* Y upper left */
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci	  Byte wwidth[2];                /* Width */
459141cc406Sopenharmony_ci	  Byte wlength[2];               /* Length */
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci	  Byte contrast;                 /* Contrast */
462141cc406Sopenharmony_ci	  Byte dummy1;
463141cc406Sopenharmony_ci	  Byte intensity;                /* Intensity */
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci	  Byte image_comp;               /* Image composition (0, 2, 5) */
466141cc406Sopenharmony_ci	  Byte bpp;                      /* Bits per pixel */
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci          Byte tonecurve;                /* Tone curve (0 - 8) */
469141cc406Sopenharmony_ci	  Byte ht_pattern;               /* Halftone pattern */
470141cc406Sopenharmony_ci	  Byte paddingtype;              /* Padding type */
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci          Byte bitordering[2];           /* Bit ordering (0 = left to right) */
473141cc406Sopenharmony_ci          Byte comprtype;                /* Compression type */
474141cc406Sopenharmony_ci          Byte comprarg;                 /* Compression argument */
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci	  Byte dummy2[6];
477141cc406Sopenharmony_ci	  Byte edge;                     /* Sharpening (0 - 7) */
478141cc406Sopenharmony_ci	  Byte dummy3;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci	  Byte bright_adjust;            /*  */
481141cc406Sopenharmony_ci	  Byte contr_adjust;             /*  */
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_ci	  Byte imagewidthtruncation;     /* */
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci	  Byte dummy4;
486141cc406Sopenharmony_ci          Byte quality_type;             /* 0 normal, 1 high, 255 low */
487141cc406Sopenharmony_ci          Byte red_att;
488141cc406Sopenharmony_ci          Byte green_att;
489141cc406Sopenharmony_ci          Byte blue_att;
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci	  Byte dummy5[5];
492141cc406Sopenharmony_ci	  Byte color_planes;
493141cc406Sopenharmony_ci	  Byte orig_type;
494141cc406Sopenharmony_ci	  Byte fixturetype;
495141cc406Sopenharmony_ci	  Byte exposure[2];
496141cc406Sopenharmony_ci	  Byte defocus[2];
497141cc406Sopenharmony_ci	  Byte dummy6[4];
498141cc406Sopenharmony_ci          Byte descreen_factor;
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci	  Byte packing_word_length;
501141cc406Sopenharmony_ci	  Byte packing_number_of_pixels;
502141cc406Sopenharmony_ci	  Byte packing_color_mode;
503141cc406Sopenharmony_ci	  Byte strokenab;
504141cc406Sopenharmony_ci	  Byte rotatenab;
505141cc406Sopenharmony_ci	  Byte autostrokenab;
506141cc406Sopenharmony_ci	  Byte dummy7;
507141cc406Sopenharmony_ci	}
508141cc406Sopenharmony_ci      wd;
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci    }
511141cc406Sopenharmony_ci  cmd;
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci  cmd.cmd = 0x24; /* SET WINDOW PARAMETERS */
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci  switch (s->hw->type)
518141cc406Sopenharmony_ci    {
519141cc406Sopenharmony_ci    case AGFAGRAY64:
520141cc406Sopenharmony_ci    case AGFALINEART:
521141cc406Sopenharmony_ci    case AGFAGRAY256:
522141cc406Sopenharmony_ci      set_size (cmd.tr_len, 3, 36 + 8);
523141cc406Sopenharmony_ci      set_size (cmd.wd_len, 2, 36);
524141cc406Sopenharmony_ci      break;
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_ci    case AGFACOLOR:
527141cc406Sopenharmony_ci      set_size (cmd.tr_len, 3, 65 + 8);
528141cc406Sopenharmony_ci      set_size (cmd.wd_len, 2, 65);
529141cc406Sopenharmony_ci      break;
530141cc406Sopenharmony_ci    }
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci  /* Resolution.  Original comment in German: Aufloesung */
533141cc406Sopenharmony_ci  set_size (cmd.wd.x_axis_res, 2, s->val[OPT_RESOLUTION].w);
534141cc406Sopenharmony_ci  set_size (cmd.wd.y_axis_res, 2, s->val[OPT_RESOLUTION].w);
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci  /* Scan window position/size.  Original comment in German:
537141cc406Sopenharmony_ci     Fensterposition / Groesse */
538141cc406Sopenharmony_ci  set_size (cmd.wd.x_axis_ul, 2,
539141cc406Sopenharmony_ci	    SANE_UNFIX (s->val[OPT_TL_X].w) * pixels_per_mm + 0.5);
540141cc406Sopenharmony_ci  set_size (cmd.wd.y_axis_ul, 2,
541141cc406Sopenharmony_ci	    SANE_UNFIX (s->val[OPT_TL_Y].w) * pixels_per_mm + 0.5);
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci  width = (SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) * pixels_per_mm) + 0.5;
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci  if (s->bpp == 1 && width % 8)
546141cc406Sopenharmony_ci    width += 8 - width % 8;
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  set_size (cmd.wd.wwidth, 2, width);
549141cc406Sopenharmony_ci  set_size (cmd.wd.wlength, 2, SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)
550141cc406Sopenharmony_ci	    * pixels_per_mm + 0.5);
551141cc406Sopenharmony_ci
552141cc406Sopenharmony_ci  cmd.wd.bpp = s->bpp;
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci  if (s->mode == COLOR18BIT ||
555141cc406Sopenharmony_ci      s->mode == COLOR24BIT)
556141cc406Sopenharmony_ci    {
557141cc406Sopenharmony_ci      cmd.wd.paddingtype = 3;
558141cc406Sopenharmony_ci      cmd.wd.ht_pattern = 3;
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci      cmd.wd.red_att = s->r_att;
561141cc406Sopenharmony_ci      cmd.wd.blue_att = s->g_att;
562141cc406Sopenharmony_ci      cmd.wd.green_att = s->b_att;
563141cc406Sopenharmony_ci      cmd.wd.color_planes = 0x0e;
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci      set_size (cmd.wd.exposure, 2, s->exposure);
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci      cmd.wd.packing_word_length = 1;
568141cc406Sopenharmony_ci      cmd.wd.packing_number_of_pixels = 1;
569141cc406Sopenharmony_ci      cmd.wd.packing_color_mode = 2;
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci      if (s->bpp == 6)
572141cc406Sopenharmony_ci	cmd.wd.edge = s->edge;
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci      DBG (3,
575141cc406Sopenharmony_ci	   "Setting parameters: imc %d, bpp %d, res %d, exp %d, attenuation [%d, %d, %d], edge %d\n",
576141cc406Sopenharmony_ci	   s->image_composition, s->bpp, s->val[OPT_RESOLUTION].w,
577141cc406Sopenharmony_ci	   s->exposure, cmd.wd.red_att, cmd.wd.blue_att, cmd.wd.green_att, s->edge);
578141cc406Sopenharmony_ci    }
579141cc406Sopenharmony_ci  else
580141cc406Sopenharmony_ci    {
581141cc406Sopenharmony_ci      if (s->bpp == 1)
582141cc406Sopenharmony_ci	cmd.wd.ht_pattern = s->halftone;
583141cc406Sopenharmony_ci      else
584141cc406Sopenharmony_ci	cmd.wd.ht_pattern = 3;
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_ci      cmd.wd.intensity = brightness;
587141cc406Sopenharmony_ci      cmd.wd.contrast = contrast;
588141cc406Sopenharmony_ci
589141cc406Sopenharmony_ci      cmd.wd.contr_adjust = contr_adjust;
590141cc406Sopenharmony_ci      cmd.wd.bright_adjust = bright_adjust;
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci      cmd.wd.tonecurve = s->tonecurve;
593141cc406Sopenharmony_ci      cmd.wd.paddingtype = 3;
594141cc406Sopenharmony_ci      cmd.wd.edge = s->edge;
595141cc406Sopenharmony_ci
596141cc406Sopenharmony_ci      if (s->lin_log)
597141cc406Sopenharmony_ci	cmd.wd.dummy3 = 0x02;
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci      DBG (3,
600141cc406Sopenharmony_ci	   "Setting parameters: imc %d, bpp %d, res %d, bri %d, con %d, bad %d, cad %d, ht %d, edge %d\n",
601141cc406Sopenharmony_ci	   s->image_composition, s->bpp, s->val[OPT_RESOLUTION].w,
602141cc406Sopenharmony_ci	   brightness, contrast, bright_adjust, contr_adjust, s->halftone, s->edge);
603141cc406Sopenharmony_ci    }
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci  cmd.wd.image_comp = s->image_composition;
606141cc406Sopenharmony_ci  cmd.wd.quality_type = s->quality;
607141cc406Sopenharmony_ci  cmd.wd.orig_type = s->original;
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci  return sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0);
610141cc406Sopenharmony_ci}
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci/* Tell scanner to scan more data. */
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_cistatic SANE_Status
615141cc406Sopenharmony_cirequest_more_data (AgfaFocus_Scanner * s)
616141cc406Sopenharmony_ci{
617141cc406Sopenharmony_ci  SANE_Status status;
618141cc406Sopenharmony_ci  int lines_available;
619141cc406Sopenharmony_ci  int bytes_per_line;
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci  status = start_scan (s->fd, SANE_TRUE);
622141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
623141cc406Sopenharmony_ci    return status;
624141cc406Sopenharmony_ci
625141cc406Sopenharmony_ci  if (!s->hw->disconnect)
626141cc406Sopenharmony_ci    wait_ready (s->fd);
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  status = get_read_sizes (s->fd, &lines_available, &bytes_per_line, 0);
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci  if (!lines_available)
631141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_ci  s->lines_available = lines_available;
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
636141cc406Sopenharmony_ci}
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_cistatic SANE_Status
639141cc406Sopenharmony_ciupload_dither_matrix (AgfaFocus_Scanner * s, int rows, int cols, int *dither_matrix)
640141cc406Sopenharmony_ci{
641141cc406Sopenharmony_ci  struct {
642141cc406Sopenharmony_ci    Byte cmd;
643141cc406Sopenharmony_ci    Byte lun;
644141cc406Sopenharmony_ci    Byte data_type;
645141cc406Sopenharmony_ci    Byte re1[3];
646141cc406Sopenharmony_ci    Byte tr_len[3];
647141cc406Sopenharmony_ci    Byte ctrl;
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci    struct {
650141cc406Sopenharmony_ci      Byte nrrows[2];
651141cc406Sopenharmony_ci      Byte nrcols[2];
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci      struct {
654141cc406Sopenharmony_ci	Byte data[2];
655141cc406Sopenharmony_ci      } element[256];
656141cc406Sopenharmony_ci    } wd;
657141cc406Sopenharmony_ci  } cmd;
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci  SANE_Status status;
660141cc406Sopenharmony_ci  int i;
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
663141cc406Sopenharmony_ci
664141cc406Sopenharmony_ci  cmd.cmd = 0x2a;       /* WRITE */
665141cc406Sopenharmony_ci  cmd.data_type = 0x81; /* upload dither matrix */
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci  set_size (cmd.tr_len, 3, 4 + (2 * rows * cols));
668141cc406Sopenharmony_ci  set_size (cmd.wd.nrrows, 2, rows);
669141cc406Sopenharmony_ci  set_size (cmd.wd.nrcols, 2, cols);
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci  for (i = 0; i < cols * rows; ++i)
672141cc406Sopenharmony_ci    set_size (cmd.wd.element[i].data, 2, dither_matrix[i]);
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0);
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
677141cc406Sopenharmony_ci    /* Command failed */
678141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci  DBG (1, "upload_dither_matrix(): uploaded dither matrix: %d, %d\n", rows, cols);
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
683141cc406Sopenharmony_ci}
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci#if 0
686141cc406Sopenharmony_cistatic SANE_Status
687141cc406Sopenharmony_ciupload_tonecurve (AgfaFocus_Scanner * s, int color_type, int input, int output, int dither_matrix[256])
688141cc406Sopenharmony_ci{
689141cc406Sopenharmony_ci  struct {
690141cc406Sopenharmony_ci   Byte cmd;
691141cc406Sopenharmony_ci   Byte lun;
692141cc406Sopenharmony_ci   Byte re1[4];
693141cc406Sopenharmony_ci   Byte tr_len[3];
694141cc406Sopenharmony_ci   Byte ctrl;
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci   Byte re2[6];
697141cc406Sopenharmony_ci   Byte wd_len[2];
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci    struct {
700141cc406Sopenharmony_ci      Byte color_type[2];
701141cc406Sopenharmony_ci      Byte nrinput[2];
702141cc406Sopenharmony_ci      Byte nroutput[2];
703141cc406Sopenharmony_ci
704141cc406Sopenharmony_ci      struct {
705141cc406Sopenharmony_ci	Byte data[2];
706141cc406Sopenharmony_ci      } outputval[256];
707141cc406Sopenharmony_ci    } wd;
708141cc406Sopenharmony_ci  } cmd;
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci  SANE_Status status;
711141cc406Sopenharmony_ci  int i, j;
712141cc406Sopenharmony_ci
713141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  cmd.cmd = 0x80;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  set_size (cmd.tr_len, 3, sizeof (cmd.wd));
718141cc406Sopenharmony_ci  set_size (cmd.wd.nrrows, 2, rows);
719141cc406Sopenharmony_ci  set_size (cmd.wd.nrrows, 2, cols);
720141cc406Sopenharmony_ci
721141cc406Sopenharmony_ci  for (i = 0; i < cols; ++i)
722141cc406Sopenharmony_ci    for (j = 0; j < rows; ++j)
723141cc406Sopenharmony_ci      set_size (cmd.wd.element[j + i * rows].data, 2, dither_matrix[j + i * rows]);
724141cc406Sopenharmony_ci
725141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0);
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
728141cc406Sopenharmony_ci  /*    * Command failed * */
729141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci  DBG (1, "upload_dither_matrix(): uploaded dither matrix\n");
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
734141cc406Sopenharmony_ci}
735141cc406Sopenharmony_ci#endif
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_ci/* May only be called when there is at least one row of data to
738141cc406Sopenharmony_ci   be read.
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci   Original comment in German: Darf nur aufgerufen werden, wenn
741141cc406Sopenharmony_ci   wirklich noch Zeilen zu scannen/lesen sind !  */
742141cc406Sopenharmony_cistatic SANE_Status
743141cc406Sopenharmony_ciread_data (AgfaFocus_Scanner * s, SANE_Byte *buf, int lines, int bpl)
744141cc406Sopenharmony_ci{
745141cc406Sopenharmony_ci  struct {
746141cc406Sopenharmony_ci   Byte cmd;
747141cc406Sopenharmony_ci   Byte lun;
748141cc406Sopenharmony_ci   Byte re1[4];
749141cc406Sopenharmony_ci   Byte tr_len[3];
750141cc406Sopenharmony_ci   Byte ctrl;
751141cc406Sopenharmony_ci  } cmd;
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci  SANE_Status status;
754141cc406Sopenharmony_ci  size_t size;
755141cc406Sopenharmony_ci  unsigned int i;
756141cc406Sopenharmony_ci
757141cc406Sopenharmony_ci  memset (&cmd, 0, sizeof (cmd));
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci  cmd.cmd = 0x28; /* READ */
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci  set_size (cmd.tr_len, 3, lines);
762141cc406Sopenharmony_ci  size = lines * bpl;
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci  status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, &size);
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
767141cc406Sopenharmony_ci    {
768141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd() = %d\n", status);
769141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
770141cc406Sopenharmony_ci    }
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci  if (size != ((unsigned int) lines * bpl))
773141cc406Sopenharmony_ci    {
774141cc406Sopenharmony_ci      DBG (1, "sanei_scsi_cmd(): got %lu bytes, expected %d\n",
775141cc406Sopenharmony_ci	   (u_long) size, lines * bpl);
776141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
777141cc406Sopenharmony_ci    }
778141cc406Sopenharmony_ci
779141cc406Sopenharmony_ci  DBG (1, "Got %lu bytes\n", (u_long) size);
780141cc406Sopenharmony_ci
781141cc406Sopenharmony_ci  /* Reverse: */
782141cc406Sopenharmony_ci  if (s->bpp != 1)
783141cc406Sopenharmony_ci    {
784141cc406Sopenharmony_ci      if (s->bpp != 6)
785141cc406Sopenharmony_ci	for (i = 0; i < size; i++)
786141cc406Sopenharmony_ci	  buf[i] = 255 - buf[i];
787141cc406Sopenharmony_ci      else
788141cc406Sopenharmony_ci	for (i = 0; i < size; i++)
789141cc406Sopenharmony_ci	  buf[i] = 255 - ((buf[i] * 256.0f) / 64.0f);
790141cc406Sopenharmony_ci    }
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci  s->lines_available -= lines;
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
795141cc406Sopenharmony_ci}
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_cistatic SANE_Status
799141cc406Sopenharmony_ciattach (const char *devname, AgfaFocus_Device ** devp)
800141cc406Sopenharmony_ci{
801141cc406Sopenharmony_ci#define ATTACH_SCSI_INQ_LEN 55
802141cc406Sopenharmony_ci  const Byte scsi_inquiry[] =
803141cc406Sopenharmony_ci  {
804141cc406Sopenharmony_ci    0x12, 0x00, 0x00, 0x00, ATTACH_SCSI_INQ_LEN, 0x00
805141cc406Sopenharmony_ci  };
806141cc406Sopenharmony_ci  Byte result[ATTACH_SCSI_INQ_LEN];
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci  int fd;
809141cc406Sopenharmony_ci  AgfaFocus_Device *dev;
810141cc406Sopenharmony_ci  SANE_Status status;
811141cc406Sopenharmony_ci  size_t size;
812141cc406Sopenharmony_ci  int i;
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci  for (dev = agfafocus_devices; dev; dev = dev->next)
815141cc406Sopenharmony_ci    if (strcmp (dev->sane.name, devname) == 0)
816141cc406Sopenharmony_ci      {
817141cc406Sopenharmony_ci	if (devp)
818141cc406Sopenharmony_ci	  *devp = dev;
819141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
820141cc406Sopenharmony_ci      }
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci  DBG (3, "attach: opening %s\n", devname);
823141cc406Sopenharmony_ci  status = sanei_scsi_open (devname, &fd, sense_handler, 0);
824141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
825141cc406Sopenharmony_ci    {
826141cc406Sopenharmony_ci      DBG (1, "attach: open failed (%s)\n", sane_strstatus (status));
827141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
828141cc406Sopenharmony_ci    }
829141cc406Sopenharmony_ci
830141cc406Sopenharmony_ci  DBG (4, "attach: sending INQUIRY\n");
831141cc406Sopenharmony_ci  size = sizeof (result);
832141cc406Sopenharmony_ci  status = sanei_scsi_cmd (fd, scsi_inquiry, sizeof (scsi_inquiry),
833141cc406Sopenharmony_ci			   result, &size);
834141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size != ATTACH_SCSI_INQ_LEN)
835141cc406Sopenharmony_ci    {
836141cc406Sopenharmony_ci      DBG (1, "attach: inquiry failed (%s)\n", sane_strstatus (status));
837141cc406Sopenharmony_ci      sanei_scsi_close (fd);
838141cc406Sopenharmony_ci      return status;
839141cc406Sopenharmony_ci    }
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci  status = test_ready (fd);
842141cc406Sopenharmony_ci  sanei_scsi_close (fd);
843141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
844141cc406Sopenharmony_ci    return status;
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci  /* The structure send by the scanner after inquiry is not SCSI-2
847141cc406Sopenharmony_ci     compatible.  The standard manufacturer/model fields are no ASCII
848141cc406Sopenharmony_ci     strings, but ?  At offset 36 my SIEMENS scanner identifies as an
849141cc406Sopenharmony_ci     AGFA one ?!   */
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_ci  if (result[0] != 6 || strncmp ((char *)result + 36, "AGFA0", 5))
852141cc406Sopenharmony_ci    {
853141cc406Sopenharmony_ci      DBG (1, "attach: device doesn't look like a Siemens 9036 scanner\n");
854141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
855141cc406Sopenharmony_ci    }
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci  DBG (4, "Inquiry data:\n");
858141cc406Sopenharmony_ci  DBG (4, "-----------\n");
859141cc406Sopenharmony_ci  for (i = 5; i < 55; i += 10)
860141cc406Sopenharmony_ci    DBG (4, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
861141cc406Sopenharmony_ci      result[i], result[i + 1], result[i + 2], result[i + 3], result[i + 4],
862141cc406Sopenharmony_ci	 result[i + 5], result[i + 6], result[i + 7], result[i + 8],
863141cc406Sopenharmony_ci	 result[i + 9]);
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_ci  if (!dev)
868141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
871141cc406Sopenharmony_ci
872141cc406Sopenharmony_ci  dev->sane.name = strdup (devname);
873141cc406Sopenharmony_ci  if (!strncmp ((char *)result + 36, "AGFA01", 6)) {
874141cc406Sopenharmony_ci    dev->sane.vendor = "AGFA";
875141cc406Sopenharmony_ci    dev->sane.model = "Focus GS Scanner (6 bit)";
876141cc406Sopenharmony_ci    dev->upload_user_defines = SANE_TRUE;
877141cc406Sopenharmony_ci    dev->type = AGFAGRAY64;
878141cc406Sopenharmony_ci  } else if (!strncmp ((char *)result + 36, "AGFA02", 6)) {
879141cc406Sopenharmony_ci    dev->sane.vendor = "AGFA";
880141cc406Sopenharmony_ci    dev->sane.model = "Focus Lineart Scanner";
881141cc406Sopenharmony_ci    dev->upload_user_defines = SANE_FALSE;
882141cc406Sopenharmony_ci    dev->type = AGFALINEART;
883141cc406Sopenharmony_ci  } else if (!strncmp ((char *)result + 36, "AGFA03", 6)) {
884141cc406Sopenharmony_ci    dev->sane.vendor = "AGFA";
885141cc406Sopenharmony_ci    dev->sane.model = "Focus II";
886141cc406Sopenharmony_ci    dev->upload_user_defines = SANE_TRUE;
887141cc406Sopenharmony_ci    dev->type = AGFAGRAY256;
888141cc406Sopenharmony_ci  } else if (!strncmp ((char *)result + 36, "AGFA04", 6)) {
889141cc406Sopenharmony_ci    dev->sane.vendor = "AGFA";
890141cc406Sopenharmony_ci    dev->sane.model = "Focus Color";
891141cc406Sopenharmony_ci    dev->upload_user_defines = SANE_TRUE;
892141cc406Sopenharmony_ci    dev->type = AGFACOLOR;
893141cc406Sopenharmony_ci  } else {
894141cc406Sopenharmony_ci    free (dev);
895141cc406Sopenharmony_ci    DBG (1, "attach: device looks like an AGFA scanner, but wasn't recognised\n");
896141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
897141cc406Sopenharmony_ci  }
898141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci  dev->transparent = result[45] & 0x80 ? SANE_TRUE : SANE_FALSE;
901141cc406Sopenharmony_ci  dev->analoglog =   result[46] & 0x80 ? SANE_TRUE : SANE_FALSE;
902141cc406Sopenharmony_ci  dev->tos5 =        result[46] & 0x05 ? SANE_TRUE : SANE_FALSE;
903141cc406Sopenharmony_ci  dev->quality =     result[47] & 0x40 ? SANE_TRUE : SANE_FALSE;
904141cc406Sopenharmony_ci  dev->disconnect =  result[47] & 0x80 ? SANE_TRUE : SANE_FALSE;
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci  DBG (4, "\n");
907141cc406Sopenharmony_ci  DBG (4, "scan modes:\n");
908141cc406Sopenharmony_ci  DBG (4, "-----------\n");
909141cc406Sopenharmony_ci  DBG (4, "three pass color mode: %s\n", dev->type >= AGFACOLOR ? "yes" : "no");
910141cc406Sopenharmony_ci  DBG (4, "8 bit gray mode: %s\n", dev->type >= AGFAGRAY64 ? "yes" : "no");
911141cc406Sopenharmony_ci  DBG (4, "uploadable matrices: %s\n", dev->upload_user_defines ? "yes" : "no");
912141cc406Sopenharmony_ci  DBG (4, "transparency: %s\n", dev->transparent ? "yes" : "no");
913141cc406Sopenharmony_ci  DBG (4, "disconnect: %s\n", dev->disconnect ? "yes" : "no");
914141cc406Sopenharmony_ci  DBG (4, "quality calibration: %s\n", dev->quality ? "yes" : "no");
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci  dev->handle = 0;
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci  DBG (3, "attach: found AgfaFocus scanner model\n");
919141cc406Sopenharmony_ci
920141cc406Sopenharmony_ci  ++num_devices;
921141cc406Sopenharmony_ci  dev->next = agfafocus_devices;
922141cc406Sopenharmony_ci  agfafocus_devices = dev;
923141cc406Sopenharmony_ci
924141cc406Sopenharmony_ci  if (devp)
925141cc406Sopenharmony_ci    *devp = dev;
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
928141cc406Sopenharmony_ci}
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_cistatic SANE_Status
931141cc406Sopenharmony_cido_eof (AgfaFocus_Scanner *s)
932141cc406Sopenharmony_ci{
933141cc406Sopenharmony_ci  if (s->pipe >= 0)
934141cc406Sopenharmony_ci    {
935141cc406Sopenharmony_ci      close (s->pipe);
936141cc406Sopenharmony_ci      s->pipe = -1;
937141cc406Sopenharmony_ci    }
938141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
939141cc406Sopenharmony_ci}
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_cistatic SANE_Status
943141cc406Sopenharmony_cido_cancel (AgfaFocus_Scanner * s)
944141cc406Sopenharmony_ci{
945141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
946141cc406Sopenharmony_ci  s->pass = 0;
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci  do_eof (s);
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci  if (sanei_thread_is_valid (s->reader_pid))
951141cc406Sopenharmony_ci    {
952141cc406Sopenharmony_ci      int exit_status;
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci      /* ensure child knows it's time to stop: */
955141cc406Sopenharmony_ci      sanei_thread_kill (s->reader_pid);
956141cc406Sopenharmony_ci      sanei_thread_waitpid (s->reader_pid, &exit_status);
957141cc406Sopenharmony_ci      sanei_thread_invalidate(s->reader_pid);
958141cc406Sopenharmony_ci    }
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci  if (s->fd >= 0)
961141cc406Sopenharmony_ci    {
962141cc406Sopenharmony_ci      stop_scan (s->fd);
963141cc406Sopenharmony_ci      release_unit (s->fd);
964141cc406Sopenharmony_ci      sanei_scsi_close (s->fd);
965141cc406Sopenharmony_ci      s->fd = -1;
966141cc406Sopenharmony_ci    }
967141cc406Sopenharmony_ci
968141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
969141cc406Sopenharmony_ci}
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_cistatic SANE_Status
973141cc406Sopenharmony_ciinit_options (AgfaFocus_Scanner * s)
974141cc406Sopenharmony_ci{
975141cc406Sopenharmony_ci  int i;
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci  /* Hardware Limitations: must be static ! */
978141cc406Sopenharmony_ci  static const SANE_Int dpi_list[] =
979141cc406Sopenharmony_ci  {8, 100, 200, 300, 400, 500, 600, 700, 800};
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  static const SANE_Range percentage_range =
982141cc406Sopenharmony_ci  {
983141cc406Sopenharmony_ci    SANE_FIX(-100),	/* minimum */
984141cc406Sopenharmony_ci    SANE_FIX(100),	/* maximum */
985141cc406Sopenharmony_ci    SANE_FIX(1)         /* quantization */
986141cc406Sopenharmony_ci  };
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci  static const SANE_Range sharpen_range =
989141cc406Sopenharmony_ci  {0, 7, 1};
990141cc406Sopenharmony_ci  static const SANE_Range exposure_range =
991141cc406Sopenharmony_ci  {0, 100, 0};
992141cc406Sopenharmony_ci  static const SANE_Range attenuation_range =
993141cc406Sopenharmony_ci  {
994141cc406Sopenharmony_ci    SANE_FIX(0),	/* minimum */
995141cc406Sopenharmony_ci    SANE_FIX(100),	/* maximum */
996141cc406Sopenharmony_ci    SANE_FIX(1)	        /* quantization */
997141cc406Sopenharmony_ci  };
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci  static const SANE_Range x_range =
1001141cc406Sopenharmony_ci  {0, SANE_FIX (8.27 * MM_PER_INCH), 0};
1002141cc406Sopenharmony_ci  static const SANE_Range y_range =
1003141cc406Sopenharmony_ci  {0, SANE_FIX (12.72 * MM_PER_INCH), 0};
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci  /* ------ */
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
1008141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
1011141cc406Sopenharmony_ci    {
1012141cc406Sopenharmony_ci      s->opt[i].size = sizeof (SANE_Word);
1013141cc406Sopenharmony_ci      s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1014141cc406Sopenharmony_ci    }
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1017141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1018141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1019141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1020141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci  /* "Mode" group: */
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = "Scan Mode";
1025141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
1026141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1027141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
1028141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  /* scan mode */
1031141cc406Sopenharmony_ci  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1032141cc406Sopenharmony_ci  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1033141cc406Sopenharmony_ci  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1034141cc406Sopenharmony_ci  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci  switch (s->hw->type)
1037141cc406Sopenharmony_ci    {
1038141cc406Sopenharmony_ci    case AGFACOLOR:
1039141cc406Sopenharmony_ci      s->opt[OPT_MODE].size = max_string_size (focuscolor_mode_list);
1040141cc406Sopenharmony_ci      s->opt[OPT_MODE].constraint.string_list = focuscolor_mode_list;
1041141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (focuscolor_mode_list[0]);
1042141cc406Sopenharmony_ci      break;
1043141cc406Sopenharmony_ci    case AGFAGRAY256:
1044141cc406Sopenharmony_ci      s->opt[OPT_MODE].size = max_string_size (focusii_mode_list);
1045141cc406Sopenharmony_ci      s->opt[OPT_MODE].constraint.string_list = focusii_mode_list;
1046141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (focusii_mode_list[0]);
1047141cc406Sopenharmony_ci      break;
1048141cc406Sopenharmony_ci    default:
1049141cc406Sopenharmony_ci      s->opt[OPT_MODE].size = max_string_size (focus_mode_list);
1050141cc406Sopenharmony_ci      s->opt[OPT_MODE].constraint.string_list = focus_mode_list;
1051141cc406Sopenharmony_ci      s->val[OPT_MODE].s = strdup (focus_mode_list[0]);
1052141cc406Sopenharmony_ci      break;
1053141cc406Sopenharmony_ci    }
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1056141cc406Sopenharmony_ci
1057141cc406Sopenharmony_ci  /* resolution */
1058141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1059141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1060141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1061141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1062141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1063141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1064141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list;
1065141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = 100;
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].name  = SANE_NAME_SCAN_SOURCE;
1068141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
1069141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].desc  = SANE_DESC_SCAN_SOURCE;
1070141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].type  = SANE_TYPE_STRING;
1071141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].unit  = SANE_UNIT_NONE;
1072141cc406Sopenharmony_ci  if (!s->hw->transparent)
1073141cc406Sopenharmony_ci    s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
1074141cc406Sopenharmony_ci  else
1075141cc406Sopenharmony_ci    s->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE;
1076141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1077141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].constraint.string_list = source_list;
1078141cc406Sopenharmony_ci  s->opt[OPT_SOURCE].size  = max_string_size (source_list);
1079141cc406Sopenharmony_ci  s->val[OPT_SOURCE].s     = strdup (source_list[0]);
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci  /* "Geometry" group: */
1082141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
1083141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
1084141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1085141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
1086141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  /* top-left x */
1089141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1090141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1091141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1092141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1093141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1094141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1095141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &x_range;
1096141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = 0;
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci  /* top-left y */
1099141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1100141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1101141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1102141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1103141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1104141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1105141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &y_range;
1106141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = 0;
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci  /* bottom-right x */
1109141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1110141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1111141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1112141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1113141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1114141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1115141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &x_range;
1116141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = x_range.max;
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_ci  /* bottom-right y */
1119141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1120141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1121141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1122141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1123141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1124141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1125141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &y_range;
1126141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = y_range.max;
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci  /* "Enhancement" group: */
1129141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1130141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
1131141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1132141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
1133141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci  /* exposure */
1136141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].name  = "exposure";
1137141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].title = "Exposure";
1138141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].desc  = "Analog exposure control.";
1139141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].type  = SANE_TYPE_INT;
1140141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
1141141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].unit  = SANE_UNIT_PERCENT;
1142141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
1143141cc406Sopenharmony_ci  s->opt[OPT_EXPOSURE].constraint.range = &exposure_range;
1144141cc406Sopenharmony_ci  s->val[OPT_EXPOSURE].w     = 23;
1145141cc406Sopenharmony_ci
1146141cc406Sopenharmony_ci  /* brightness automatic correct */
1147141cc406Sopenharmony_ci  s->opt[OPT_AUTO_BRIGHTNESS].name = "adjust-bright";
1148141cc406Sopenharmony_ci  s->opt[OPT_AUTO_BRIGHTNESS].title = "Automatic brightness correction";
1149141cc406Sopenharmony_ci  s->opt[OPT_AUTO_BRIGHTNESS].desc = "Turns on automatic brightness correction of "
1150141cc406Sopenharmony_ci    "the acquired image. This makes the scanner do a two pass scan to analyse the "
1151141cc406Sopenharmony_ci    "brightness of the image before it's scanned.";
1152141cc406Sopenharmony_ci  s->opt[OPT_AUTO_BRIGHTNESS].type = SANE_TYPE_BOOL;
1153141cc406Sopenharmony_ci  s->val[OPT_AUTO_BRIGHTNESS].b = SANE_FALSE;
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci  /* contrast automatic correct */
1156141cc406Sopenharmony_ci  s->opt[OPT_AUTO_CONTRAST].name = "adjust-contr";
1157141cc406Sopenharmony_ci  s->opt[OPT_AUTO_CONTRAST].title = "Automatic contrast correction";
1158141cc406Sopenharmony_ci  s->opt[OPT_AUTO_CONTRAST].desc = "Turns on automatic contrast correction of "
1159141cc406Sopenharmony_ci    "the acquired image. This makes the scanner do a two pass scan to analyse "
1160141cc406Sopenharmony_ci    "the contrast of the image to be scanned.";
1161141cc406Sopenharmony_ci  s->opt[OPT_AUTO_CONTRAST].type = SANE_TYPE_BOOL;
1162141cc406Sopenharmony_ci  s->val[OPT_AUTO_CONTRAST].b = SANE_FALSE;
1163141cc406Sopenharmony_ci
1164141cc406Sopenharmony_ci  /* brightness */
1165141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1166141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1167141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].desc = "Controls the brightness of the acquired image. "
1168141cc406Sopenharmony_ci    "When automatic brightness is enabled, this can be used to adjust the selected brightness.";
1169141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED;
1170141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
1171141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1172141cc406Sopenharmony_ci  s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
1173141cc406Sopenharmony_ci  s->val[OPT_BRIGHTNESS].w = 0;
1174141cc406Sopenharmony_ci
1175141cc406Sopenharmony_ci  /* contrast */
1176141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
1177141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
1178141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].desc = "Controls the contrast of the acquired image. "
1179141cc406Sopenharmony_ci    "When automatic contrast is enabled, this can be used to adjust the selected contrast.";
1180141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED;
1181141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
1182141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
1183141cc406Sopenharmony_ci  s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
1184141cc406Sopenharmony_ci  s->val[OPT_CONTRAST].w = 0;
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci  /* halftone patterns */
1187141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
1188141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
1189141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
1190141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
1191141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].size = 32;
1192141cc406Sopenharmony_ci  s->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1193141cc406Sopenharmony_ci  if (s->hw->upload_user_defines)
1194141cc406Sopenharmony_ci    {
1195141cc406Sopenharmony_ci      s->opt[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_upload_list;
1196141cc406Sopenharmony_ci      s->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_upload_list[0]);
1197141cc406Sopenharmony_ci    }
1198141cc406Sopenharmony_ci  else
1199141cc406Sopenharmony_ci    {
1200141cc406Sopenharmony_ci      s->opt[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_list;
1201141cc406Sopenharmony_ci      s->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_list[0]);
1202141cc406Sopenharmony_ci    }
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci  /* red-attenuation */
1205141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].name  = "red-attenuation";
1206141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].title = "Red attenuation";
1207141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].desc  = "Controls the red attenuation of the acquired image. "
1208141cc406Sopenharmony_ci    "Higher values mean less impact on scanned image.";
1209141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].type = SANE_TYPE_FIXED;
1210141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].cap |= SANE_CAP_INACTIVE;
1211141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].unit = SANE_UNIT_PERCENT;
1212141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].constraint_type = SANE_CONSTRAINT_RANGE;
1213141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_RED].constraint.range = &attenuation_range;
1214141cc406Sopenharmony_ci  s->val[OPT_ATTENUATION_RED].w = SANE_FIX (50.0);
1215141cc406Sopenharmony_ci
1216141cc406Sopenharmony_ci  /* green-attenuation */
1217141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].name  = "green-attenuation";
1218141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].title = "Green attenuation";
1219141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].desc  = "Controls the green attenuation of the acquired image. "
1220141cc406Sopenharmony_ci    "Higher values mean less impact on scanned image.";
1221141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].type = SANE_TYPE_FIXED;
1222141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].cap |= SANE_CAP_INACTIVE;
1223141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].unit = SANE_UNIT_PERCENT;
1224141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].constraint_type = SANE_CONSTRAINT_RANGE;
1225141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_GREEN].constraint.range = &attenuation_range;
1226141cc406Sopenharmony_ci  s->val[OPT_ATTENUATION_GREEN].w = SANE_FIX (50.0);
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci  /* blue-attenuation */
1229141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].name  = "blue-attenuation";
1230141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].title = "Blue attenuation";
1231141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].desc  = "Controls the blue attenuation of the acquired image. "
1232141cc406Sopenharmony_ci    "Higher values mean less impact on scanned image.";
1233141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].type = SANE_TYPE_FIXED;
1234141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].cap |= SANE_CAP_INACTIVE;
1235141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].unit = SANE_UNIT_PERCENT;
1236141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].constraint_type = SANE_CONSTRAINT_RANGE;
1237141cc406Sopenharmony_ci  s->opt[OPT_ATTENUATION_BLUE].constraint.range = &attenuation_range;
1238141cc406Sopenharmony_ci  s->val[OPT_ATTENUATION_BLUE].w = SANE_FIX (50.0);
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci  /* quality-calibration */
1241141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].name  = SANE_NAME_QUALITY_CAL;
1242141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].title = SANE_TITLE_QUALITY_CAL;
1243141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].desc  = "Controls the calibration that will be done in the "
1244141cc406Sopenharmony_ci        "scanner.  Less calibration result in faster scanner times.";
1245141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].type = SANE_TYPE_STRING;
1246141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].size = 32;
1247141cc406Sopenharmony_ci  if (!s->hw->quality)
1248141cc406Sopenharmony_ci    s->opt[OPT_QUALITY].cap |= SANE_CAP_INACTIVE;
1249141cc406Sopenharmony_ci  else
1250141cc406Sopenharmony_ci    s->opt[OPT_QUALITY].cap &= ~SANE_CAP_INACTIVE;
1251141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1252141cc406Sopenharmony_ci  s->opt[OPT_QUALITY].constraint.string_list = quality_list;
1253141cc406Sopenharmony_ci  s->val[OPT_QUALITY].s = strdup (quality_list[1]);
1254141cc406Sopenharmony_ci
1255141cc406Sopenharmony_ci  /* sharpening */
1256141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].name = "sharpen";
1257141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].title = "Sharpening";
1258141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].desc = "Controls the sharpening that will be "
1259141cc406Sopenharmony_ci    "done by the video processor in the scanner.";
1260141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].type = SANE_TYPE_INT;
1261141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].unit = SANE_UNIT_NONE;
1262141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].constraint_type = SANE_CONSTRAINT_RANGE;
1263141cc406Sopenharmony_ci  s->opt[OPT_SHARPEN].constraint.range = &sharpen_range;
1264141cc406Sopenharmony_ci  s->val[OPT_SHARPEN].w = 1;
1265141cc406Sopenharmony_ci
1266141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1267141cc406Sopenharmony_ci}
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_cistatic SANE_Status
1270141cc406Sopenharmony_ciattach_one (const char *dev)
1271141cc406Sopenharmony_ci{
1272141cc406Sopenharmony_ci  attach (dev, 0);
1273141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1274141cc406Sopenharmony_ci}
1275141cc406Sopenharmony_ci
1276141cc406Sopenharmony_ciSANE_Status
1277141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
1278141cc406Sopenharmony_ci{
1279141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
1280141cc406Sopenharmony_ci  size_t len;
1281141cc406Sopenharmony_ci  FILE *fp;
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci  (void) authorize;			/* silence gcc */
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_ci  DBG_INIT ();
1286141cc406Sopenharmony_ci
1287141cc406Sopenharmony_ci  sanei_thread_init ();
1288141cc406Sopenharmony_ci
1289141cc406Sopenharmony_ci  if (version_code)
1290141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  fp = sanei_config_open ("agfafocus.conf");
1293141cc406Sopenharmony_ci  if (!fp)
1294141cc406Sopenharmony_ci    {
1295141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
1296141cc406Sopenharmony_ci      attach ("/dev/scanner", 0);
1297141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1298141cc406Sopenharmony_ci    }
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
1301141cc406Sopenharmony_ci    {
1302141cc406Sopenharmony_ci      if (dev_name[0] == '#')	/* ignore line comments */
1303141cc406Sopenharmony_ci	continue;
1304141cc406Sopenharmony_ci      len = strlen (dev_name);
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci      if (!len)
1307141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
1308141cc406Sopenharmony_ci
1309141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
1310141cc406Sopenharmony_ci    }
1311141cc406Sopenharmony_ci  fclose (fp);
1312141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1313141cc406Sopenharmony_ci}
1314141cc406Sopenharmony_ci
1315141cc406Sopenharmony_civoid
1316141cc406Sopenharmony_cisane_exit (void)
1317141cc406Sopenharmony_ci{
1318141cc406Sopenharmony_ci  AgfaFocus_Device *dev, *next;
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci  for (dev = agfafocus_devices; dev; dev = next)
1321141cc406Sopenharmony_ci    {
1322141cc406Sopenharmony_ci      next = dev->next;
1323141cc406Sopenharmony_ci      if (dev->handle)
1324141cc406Sopenharmony_ci	sane_close (dev->handle);
1325141cc406Sopenharmony_ci      free (dev);
1326141cc406Sopenharmony_ci    }
1327141cc406Sopenharmony_ci
1328141cc406Sopenharmony_ci  if (devlist)
1329141cc406Sopenharmony_ci    free (devlist);
1330141cc406Sopenharmony_ci}
1331141cc406Sopenharmony_ci
1332141cc406Sopenharmony_ciSANE_Status
1333141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1334141cc406Sopenharmony_ci{
1335141cc406Sopenharmony_ci  AgfaFocus_Device *dev;
1336141cc406Sopenharmony_ci  int i;
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci  (void) local_only;			/* silence gcc */
1339141cc406Sopenharmony_ci
1340141cc406Sopenharmony_ci  if (devlist)
1341141cc406Sopenharmony_ci    free (devlist);
1342141cc406Sopenharmony_ci
1343141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
1344141cc406Sopenharmony_ci  if (!devlist)
1345141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci  for (dev = agfafocus_devices, i = 0; i < num_devices; dev = dev->next)
1348141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
1349141cc406Sopenharmony_ci  devlist[i++] = 0;
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci  *device_list = devlist;
1352141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1353141cc406Sopenharmony_ci}
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ciSANE_Status
1356141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
1357141cc406Sopenharmony_ci{
1358141cc406Sopenharmony_ci  AgfaFocus_Device *dev;
1359141cc406Sopenharmony_ci  SANE_Status status;
1360141cc406Sopenharmony_ci  AgfaFocus_Scanner *s;
1361141cc406Sopenharmony_ci
1362141cc406Sopenharmony_ci  if (devicename[0])
1363141cc406Sopenharmony_ci    {
1364141cc406Sopenharmony_ci      status = attach (devicename, &dev);
1365141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1366141cc406Sopenharmony_ci	return status;
1367141cc406Sopenharmony_ci    }
1368141cc406Sopenharmony_ci  else
1369141cc406Sopenharmony_ci    {
1370141cc406Sopenharmony_ci      /* empty devicname -> use first device */
1371141cc406Sopenharmony_ci      dev = agfafocus_devices;
1372141cc406Sopenharmony_ci    }
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci  if (!dev)
1375141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci  if (dev->handle)
1378141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci  s = malloc (sizeof (*s));
1381141cc406Sopenharmony_ci  if (!s)
1382141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1383141cc406Sopenharmony_ci
1384141cc406Sopenharmony_ci  memset (s, 0, sizeof (*s));
1385141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci  s->fd = -1;
1388141cc406Sopenharmony_ci  s->hw = dev;
1389141cc406Sopenharmony_ci  s->hw->handle = s;
1390141cc406Sopenharmony_ci
1391141cc406Sopenharmony_ci  init_options (s);
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci  *handle = s;
1394141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1395141cc406Sopenharmony_ci}
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_civoid
1398141cc406Sopenharmony_cisane_close (SANE_Handle handle)
1399141cc406Sopenharmony_ci{
1400141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
1401141cc406Sopenharmony_ci
1402141cc406Sopenharmony_ci  if (s->scanning)
1403141cc406Sopenharmony_ci    do_cancel (handle);
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci  s->hw->handle = 0;
1406141cc406Sopenharmony_ci
1407141cc406Sopenharmony_ci  free (handle);
1408141cc406Sopenharmony_ci}
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1411141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1412141cc406Sopenharmony_ci{
1413141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
1414141cc406Sopenharmony_ci
1415141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
1416141cc406Sopenharmony_ci    return 0;
1417141cc406Sopenharmony_ci  return s->opt + option;
1418141cc406Sopenharmony_ci}
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ciSANE_Status
1421141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1422141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1423141cc406Sopenharmony_ci{
1424141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
1425141cc406Sopenharmony_ci  SANE_Status status;
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci  if (info)
1428141cc406Sopenharmony_ci    *info = 0;
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ci  if (s->scanning)
1431141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
1432141cc406Sopenharmony_ci
1433141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS || !SANE_OPTION_IS_ACTIVE (s->opt[option].cap))
1434141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1437141cc406Sopenharmony_ci    {
1438141cc406Sopenharmony_ci      switch (option)
1439141cc406Sopenharmony_ci	{
1440141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1441141cc406Sopenharmony_ci	case OPT_TL_X:
1442141cc406Sopenharmony_ci	case OPT_TL_Y:
1443141cc406Sopenharmony_ci	case OPT_BR_X:
1444141cc406Sopenharmony_ci	case OPT_BR_Y:
1445141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1446141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1447141cc406Sopenharmony_ci	case OPT_CONTRAST:
1448141cc406Sopenharmony_ci	case OPT_SHARPEN:
1449141cc406Sopenharmony_ci	case OPT_EXPOSURE:
1450141cc406Sopenharmony_ci	case OPT_ATTENUATION_RED:
1451141cc406Sopenharmony_ci	case OPT_ATTENUATION_GREEN:
1452141cc406Sopenharmony_ci	case OPT_ATTENUATION_BLUE:
1453141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
1454141cc406Sopenharmony_ci	  break;
1455141cc406Sopenharmony_ci	case OPT_AUTO_BRIGHTNESS:
1456141cc406Sopenharmony_ci	case OPT_AUTO_CONTRAST:
1457141cc406Sopenharmony_ci	  *(SANE_Bool *) val = s->val[option].b;
1458141cc406Sopenharmony_ci	  break;
1459141cc406Sopenharmony_ci        case OPT_MODE:
1460141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
1461141cc406Sopenharmony_ci	case OPT_QUALITY:
1462141cc406Sopenharmony_ci	case OPT_SOURCE:
1463141cc406Sopenharmony_ci          strcpy (val, s->val[option].s);
1464141cc406Sopenharmony_ci          return (SANE_STATUS_GOOD);
1465141cc406Sopenharmony_ci	default:
1466141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
1467141cc406Sopenharmony_ci	}
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci    }
1470141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1471141cc406Sopenharmony_ci    {
1472141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap))
1473141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
1474141cc406Sopenharmony_ci
1475141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, info);
1476141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1477141cc406Sopenharmony_ci	return status;
1478141cc406Sopenharmony_ci
1479141cc406Sopenharmony_ci      switch (option)
1480141cc406Sopenharmony_ci	{
1481141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1482141cc406Sopenharmony_ci	case OPT_TL_X:
1483141cc406Sopenharmony_ci	case OPT_TL_Y:
1484141cc406Sopenharmony_ci	case OPT_BR_X:
1485141cc406Sopenharmony_ci	case OPT_BR_Y:
1486141cc406Sopenharmony_ci	  if (info)
1487141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
1488141cc406Sopenharmony_ci          // fall through
1489141cc406Sopenharmony_ci	case OPT_SHARPEN:
1490141cc406Sopenharmony_ci	case OPT_EXPOSURE:
1491141cc406Sopenharmony_ci	case OPT_ATTENUATION_RED:
1492141cc406Sopenharmony_ci	case OPT_ATTENUATION_GREEN:
1493141cc406Sopenharmony_ci	case OPT_ATTENUATION_BLUE:
1494141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1495141cc406Sopenharmony_ci	case OPT_CONTRAST:
1496141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
1497141cc406Sopenharmony_ci	  break;
1498141cc406Sopenharmony_ci	case OPT_AUTO_BRIGHTNESS:
1499141cc406Sopenharmony_ci	case OPT_AUTO_CONTRAST:
1500141cc406Sopenharmony_ci	  s->val[option].b = *(SANE_Bool *) val;
1501141cc406Sopenharmony_ci	  break;
1502141cc406Sopenharmony_ci        case OPT_MODE:
1503141cc406Sopenharmony_ci	  if (strcmp (s->val[option].s, (SANE_String) val))
1504141cc406Sopenharmony_ci	    {
1505141cc406Sopenharmony_ci	      if (info)
1506141cc406Sopenharmony_ci		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1507141cc406Sopenharmony_ci
1508141cc406Sopenharmony_ci	      if (s->val[option].s)
1509141cc406Sopenharmony_ci		free (s->val[option].s);
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci	      s->val[option].s = strdup (val);
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci	      if (strcmp (s->val[option].s, "Gray (6 bit)") == 0)
1514141cc406Sopenharmony_ci		s->mode = GRAY6BIT;
1515141cc406Sopenharmony_ci	      else if (strcmp (s->val[option].s, "Gray (8 bit)") == 0)
1516141cc406Sopenharmony_ci		s->mode = GRAY8BIT;
1517141cc406Sopenharmony_ci	      else if (strcmp (s->val[option].s, "Color (18 bit)") == 0)
1518141cc406Sopenharmony_ci		s->mode = COLOR18BIT;
1519141cc406Sopenharmony_ci	      else if (strcmp (s->val[option].s, "Color (24 bit)") == 0)
1520141cc406Sopenharmony_ci		s->mode = COLOR24BIT;
1521141cc406Sopenharmony_ci	      else
1522141cc406Sopenharmony_ci		s->mode = LINEART;
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci	      switch (s->mode)
1525141cc406Sopenharmony_ci		{
1526141cc406Sopenharmony_ci		case LINEART:
1527141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
1528141cc406Sopenharmony_ci		  s->opt[OPT_SHARPEN].cap &= ~SANE_CAP_INACTIVE;
1529141cc406Sopenharmony_ci		  s->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
1530141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_RED].cap |= SANE_CAP_INACTIVE;
1531141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_GREEN].cap |= SANE_CAP_INACTIVE;
1532141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_BLUE].cap |= SANE_CAP_INACTIVE;
1533141cc406Sopenharmony_ci		  s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1534141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1535141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1536141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1537141cc406Sopenharmony_ci		  break;
1538141cc406Sopenharmony_ci
1539141cc406Sopenharmony_ci		case GRAY6BIT:
1540141cc406Sopenharmony_ci		  s->opt[OPT_SHARPEN].cap &= ~SANE_CAP_INACTIVE;
1541141cc406Sopenharmony_ci		  s->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
1542141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_RED].cap |= SANE_CAP_INACTIVE;
1543141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_GREEN].cap |= SANE_CAP_INACTIVE;
1544141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_BLUE].cap |= SANE_CAP_INACTIVE;
1545141cc406Sopenharmony_ci		  s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1546141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1547141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1548141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1549141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1550141cc406Sopenharmony_ci		  break;
1551141cc406Sopenharmony_ci
1552141cc406Sopenharmony_ci		case GRAY8BIT:
1553141cc406Sopenharmony_ci		  s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1554141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1555141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1556141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1557141cc406Sopenharmony_ci		  s->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
1558141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_RED].cap |= SANE_CAP_INACTIVE;
1559141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_GREEN].cap |= SANE_CAP_INACTIVE;
1560141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_BLUE].cap |= SANE_CAP_INACTIVE;
1561141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1562141cc406Sopenharmony_ci		  s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
1563141cc406Sopenharmony_ci		  break;
1564141cc406Sopenharmony_ci
1565141cc406Sopenharmony_ci		case COLOR18BIT:
1566141cc406Sopenharmony_ci		  s->opt[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
1567141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_RED].cap &= ~SANE_CAP_INACTIVE;
1568141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_GREEN].cap &= ~SANE_CAP_INACTIVE;
1569141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_BLUE].cap &= ~SANE_CAP_INACTIVE;
1570141cc406Sopenharmony_ci		  s->opt[OPT_BRIGHTNESS].cap |=  SANE_CAP_INACTIVE;
1571141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap |=  SANE_CAP_INACTIVE;
1572141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1573141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_CONTRAST].cap |= SANE_CAP_INACTIVE;
1574141cc406Sopenharmony_ci		  s->opt[OPT_SHARPEN].cap &= ~SANE_CAP_INACTIVE;
1575141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1576141cc406Sopenharmony_ci		  break;
1577141cc406Sopenharmony_ci
1578141cc406Sopenharmony_ci		case COLOR24BIT:
1579141cc406Sopenharmony_ci		  s->opt[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
1580141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_RED].cap &= ~SANE_CAP_INACTIVE;
1581141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_GREEN].cap &= ~SANE_CAP_INACTIVE;
1582141cc406Sopenharmony_ci		  s->opt[OPT_ATTENUATION_BLUE].cap &= ~SANE_CAP_INACTIVE;
1583141cc406Sopenharmony_ci		  s->opt[OPT_BRIGHTNESS].cap |=  SANE_CAP_INACTIVE;
1584141cc406Sopenharmony_ci		  s->opt[OPT_CONTRAST].cap |=  SANE_CAP_INACTIVE;
1585141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1586141cc406Sopenharmony_ci		  s->opt[OPT_AUTO_CONTRAST].cap |= SANE_CAP_INACTIVE;
1587141cc406Sopenharmony_ci		  s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
1588141cc406Sopenharmony_ci		  s->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1589141cc406Sopenharmony_ci		  break;
1590141cc406Sopenharmony_ci		}
1591141cc406Sopenharmony_ci	    }
1592141cc406Sopenharmony_ci	  break;
1593141cc406Sopenharmony_ci	case OPT_SOURCE:
1594141cc406Sopenharmony_ci	case OPT_QUALITY:
1595141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
1596141cc406Sopenharmony_ci          if (info && strcmp (s->val[option].s, (SANE_String) val))
1597141cc406Sopenharmony_ci            *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1598141cc406Sopenharmony_ci          if (s->val[option].s)
1599141cc406Sopenharmony_ci            free (s->val[option].s);
1600141cc406Sopenharmony_ci          s->val[option].s = strdup (val);
1601141cc406Sopenharmony_ci	  break;
1602141cc406Sopenharmony_ci	default:
1603141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
1604141cc406Sopenharmony_ci	}
1605141cc406Sopenharmony_ci
1606141cc406Sopenharmony_ci    }
1607141cc406Sopenharmony_ci  else
1608141cc406Sopenharmony_ci    {
1609141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1610141cc406Sopenharmony_ci    }
1611141cc406Sopenharmony_ci
1612141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1613141cc406Sopenharmony_ci}
1614141cc406Sopenharmony_ci
1615141cc406Sopenharmony_ciSANE_Status
1616141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1617141cc406Sopenharmony_ci{
1618141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
1619141cc406Sopenharmony_ci
1620141cc406Sopenharmony_ci  if (!s->scanning)
1621141cc406Sopenharmony_ci    {
1622141cc406Sopenharmony_ci      double width, height, dpi;
1623141cc406Sopenharmony_ci      const char *quality;
1624141cc406Sopenharmony_ci      const char *original;
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci      memset (&s->params, 0, sizeof (s->params));
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ci      width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w);
1629141cc406Sopenharmony_ci      height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w);
1630141cc406Sopenharmony_ci      dpi = s->val[OPT_RESOLUTION].w;
1631141cc406Sopenharmony_ci
1632141cc406Sopenharmony_ci      /* make best-effort guess at what parameters will look like once
1633141cc406Sopenharmony_ci         scanning starts.  */
1634141cc406Sopenharmony_ci      if (dpi > 0.0 && width > 0.0 && height > 0.0)
1635141cc406Sopenharmony_ci	{
1636141cc406Sopenharmony_ci	  double dots_per_mm = dpi / MM_PER_INCH;
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci	  s->params.pixels_per_line = width * dots_per_mm + 0.5;
1639141cc406Sopenharmony_ci	  s->params.lines = height * dots_per_mm + 0.5;
1640141cc406Sopenharmony_ci	}
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_ci      /* Should we specify calibration quality? */
1643141cc406Sopenharmony_ci
1644141cc406Sopenharmony_ci      if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_QUALITY].cap))
1645141cc406Sopenharmony_ci        {
1646141cc406Sopenharmony_ci          DBG(3, " -------------- setting quality\n");
1647141cc406Sopenharmony_ci          quality = s->val[OPT_QUALITY].s;
1648141cc406Sopenharmony_ci          if (strcmp (quality, "Low") == 0 )
1649141cc406Sopenharmony_ci	    s->quality = 255;
1650141cc406Sopenharmony_ci          else if (strcmp (quality, "High") == 0)
1651141cc406Sopenharmony_ci	    s->quality = 1;
1652141cc406Sopenharmony_ci          else
1653141cc406Sopenharmony_ci	    s->quality = 0;
1654141cc406Sopenharmony_ci        }
1655141cc406Sopenharmony_ci      else
1656141cc406Sopenharmony_ci        s->quality = 0;
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci      /* Should we select source type? */
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci      if (SANE_OPTION_IS_ACTIVE (s->opt[OPT_SOURCE].cap))
1661141cc406Sopenharmony_ci        {
1662141cc406Sopenharmony_ci          DBG(3, " -------------- setting source\n");
1663141cc406Sopenharmony_ci          original = s->val[OPT_SOURCE].s;
1664141cc406Sopenharmony_ci          if (strcmp (original, "Transparency") == 0)
1665141cc406Sopenharmony_ci	    s->original = 0;
1666141cc406Sopenharmony_ci          else
1667141cc406Sopenharmony_ci	    s->original = 1;
1668141cc406Sopenharmony_ci        }
1669141cc406Sopenharmony_ci      else
1670141cc406Sopenharmony_ci        s->original = 0;
1671141cc406Sopenharmony_ci
1672141cc406Sopenharmony_ci      s->exposure = ((s->val[OPT_EXPOSURE].w * (255.0f - 80.0f)) / 100.0f) + 80.0f;
1673141cc406Sopenharmony_ci      s->r_att = (SANE_UNFIX (s->val[OPT_ATTENUATION_RED].w) * 20.0f) / 100.0f;
1674141cc406Sopenharmony_ci      s->g_att = (SANE_UNFIX (s->val[OPT_ATTENUATION_GREEN].w) * 20.0f) / 100.0f;
1675141cc406Sopenharmony_ci      s->b_att = (SANE_UNFIX (s->val[OPT_ATTENUATION_BLUE].w) * 20.0f) / 100.0f;
1676141cc406Sopenharmony_ci      s->tonecurve = 0;
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci      switch (s->mode)
1679141cc406Sopenharmony_ci	{
1680141cc406Sopenharmony_ci	case LINEART:
1681141cc406Sopenharmony_ci	  {
1682141cc406Sopenharmony_ci	    const char *halftone;
1683141cc406Sopenharmony_ci
1684141cc406Sopenharmony_ci	    s->image_composition = 0;
1685141cc406Sopenharmony_ci
1686141cc406Sopenharmony_ci	    /* in 1 bpp mode, lines need to be 8 pixel length */
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci	    if (s->params.pixels_per_line % 8)
1689141cc406Sopenharmony_ci	      s->params.pixels_per_line += 8 - (s->params.pixels_per_line % 8);
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci	    s->params.format = SANE_FRAME_GRAY;
1692141cc406Sopenharmony_ci	    s->params.bytes_per_line = s->params.pixels_per_line / 8;
1693141cc406Sopenharmony_ci	    s->bpp = s->params.depth = 1;
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci	    halftone = s->val[OPT_HALFTONE_PATTERN].s;
1696141cc406Sopenharmony_ci	    if (strcmp (halftone, "1") == 0 )
1697141cc406Sopenharmony_ci	      s->halftone = 1;
1698141cc406Sopenharmony_ci	    else if (strcmp (halftone, "Dispersed dot 4x4") == 0)
1699141cc406Sopenharmony_ci	      s->halftone = 2;
1700141cc406Sopenharmony_ci	    else if (strcmp (halftone, "Round (Clustered dot 4x4)") == 0)
1701141cc406Sopenharmony_ci	      s->halftone = 3;
1702141cc406Sopenharmony_ci	    else if (strcmp (halftone, "Diamond (Clustered dot 4x4)") == 0)
1703141cc406Sopenharmony_ci	      s->halftone = 4;
1704141cc406Sopenharmony_ci	    else if (strcmp (halftone, "User defined") == 0)
1705141cc406Sopenharmony_ci	      s->halftone = 5;
1706141cc406Sopenharmony_ci	    else
1707141cc406Sopenharmony_ci	      s->halftone = 0;
1708141cc406Sopenharmony_ci
1709141cc406Sopenharmony_ci	    s->edge = s->val[OPT_SHARPEN].w;
1710141cc406Sopenharmony_ci	  }
1711141cc406Sopenharmony_ci	  break;
1712141cc406Sopenharmony_ci
1713141cc406Sopenharmony_ci	case GRAY6BIT:
1714141cc406Sopenharmony_ci	  s->image_composition = 2;
1715141cc406Sopenharmony_ci
1716141cc406Sopenharmony_ci          s->params.format = SANE_FRAME_GRAY;
1717141cc406Sopenharmony_ci          s->params.bytes_per_line = s->params.pixels_per_line;
1718141cc406Sopenharmony_ci	  s->bpp = 6;
1719141cc406Sopenharmony_ci	  s->params.depth = 8;
1720141cc406Sopenharmony_ci	  s->edge = s->val[OPT_SHARPEN].w;
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci	  break;
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_ci	case GRAY8BIT:
1725141cc406Sopenharmony_ci	  s->image_composition = 2;
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci          s->params.format = SANE_FRAME_GRAY;
1728141cc406Sopenharmony_ci          s->params.bytes_per_line = s->params.pixels_per_line;
1729141cc406Sopenharmony_ci	  s->bpp = s->params.depth = 8;
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci	  break;
1732141cc406Sopenharmony_ci
1733141cc406Sopenharmony_ci	case COLOR18BIT:
1734141cc406Sopenharmony_ci	  s->image_composition = 5;
1735141cc406Sopenharmony_ci
1736141cc406Sopenharmony_ci          s->params.format = SANE_FRAME_RED;
1737141cc406Sopenharmony_ci          s->params.bytes_per_line = s->params.pixels_per_line;
1738141cc406Sopenharmony_ci	  s->bpp = 6;
1739141cc406Sopenharmony_ci	  s->params.depth = 8;
1740141cc406Sopenharmony_ci	  s->edge = s->val[OPT_SHARPEN].w;
1741141cc406Sopenharmony_ci
1742141cc406Sopenharmony_ci	  break;
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci	case COLOR24BIT:
1745141cc406Sopenharmony_ci	  s->image_composition = 5;
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci          s->params.format = SANE_FRAME_RED;
1748141cc406Sopenharmony_ci          s->params.bytes_per_line = s->params.pixels_per_line;
1749141cc406Sopenharmony_ci          s->bpp = s->params.depth = 8;
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci	  break;
1752141cc406Sopenharmony_ci        }
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci      s->pass = 0;
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci      /*s->params.bytes_per_line =
1757141cc406Sopenharmony_ci	(s->params.pixels_per_line + (8 - s->params.depth))
1758141cc406Sopenharmony_ci	/ (8 / s->params.depth);*/
1759141cc406Sopenharmony_ci    }
1760141cc406Sopenharmony_ci  else
1761141cc406Sopenharmony_ci    if (s->mode == COLOR18BIT ||
1762141cc406Sopenharmony_ci	s->mode == COLOR24BIT)
1763141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_RED + s->pass;
1764141cc406Sopenharmony_ci
1765141cc406Sopenharmony_ci  s->params.last_frame = (s->params.format != SANE_FRAME_RED && s->params.format != SANE_FRAME_GREEN);
1766141cc406Sopenharmony_ci
1767141cc406Sopenharmony_ci  if (params)
1768141cc406Sopenharmony_ci    *params = s->params;
1769141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1770141cc406Sopenharmony_ci}
1771141cc406Sopenharmony_ci
1772141cc406Sopenharmony_ci/* This function is executed as a child process.  The reason this is
1773141cc406Sopenharmony_ci   executed as a subprocess is because some (most?) generic SCSI
1774141cc406Sopenharmony_ci   interfaces block a SCSI request until it has completed.  With a
1775141cc406Sopenharmony_ci   subprocess, we can let it block waiting for the request to finish
1776141cc406Sopenharmony_ci   while the main process can go about to do more important things
1777141cc406Sopenharmony_ci   (such as recognizing when the user presses a cancel button).
1778141cc406Sopenharmony_ci
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci   WARNING: Since this is executed as a subprocess, it's NOT possible
1781141cc406Sopenharmony_ci   to update any of the variables in the main process (in particular
1782141cc406Sopenharmony_ci   the scanner state cannot be updated).  */
1783141cc406Sopenharmony_cistatic int
1784141cc406Sopenharmony_cireader_process (void *scanner)
1785141cc406Sopenharmony_ci{
1786141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = (AgfaFocus_Scanner *) scanner;
1787141cc406Sopenharmony_ci  int fd = s->reader_pipe;
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci  SANE_Status status;
1790141cc406Sopenharmony_ci  SANE_Byte *data;
1791141cc406Sopenharmony_ci  int lines_read = 0;
1792141cc406Sopenharmony_ci  int lines_per_buffer;
1793141cc406Sopenharmony_ci  int bytes_per_line = 0, total_lines = 0;
1794141cc406Sopenharmony_ci  int i;
1795141cc406Sopenharmony_ci  sigset_t sigterm_set;
1796141cc406Sopenharmony_ci  sigset_t ignore_set;
1797141cc406Sopenharmony_ci  struct SIGACTION act;
1798141cc406Sopenharmony_ci
1799141cc406Sopenharmony_ci  if (sanei_thread_is_forked()) close (s->pipe);
1800141cc406Sopenharmony_ci
1801141cc406Sopenharmony_ci  sigfillset (&ignore_set);
1802141cc406Sopenharmony_ci  sigdelset (&ignore_set, SIGTERM);
1803141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__)
1804141cc406Sopenharmony_ci  sigdelset (&ignore_set, SIGUSR2);
1805141cc406Sopenharmony_ci#endif
1806141cc406Sopenharmony_ci  sigprocmask (SIG_SETMASK, &ignore_set, 0);
1807141cc406Sopenharmony_ci
1808141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));
1809141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
1810141cc406Sopenharmony_ci
1811141cc406Sopenharmony_ci  sigemptyset (&sigterm_set);
1812141cc406Sopenharmony_ci  sigaddset (&sigterm_set, SIGTERM);
1813141cc406Sopenharmony_ci
1814141cc406Sopenharmony_ci  if (!s->hw->disconnect)
1815141cc406Sopenharmony_ci    wait_ready (s->fd);
1816141cc406Sopenharmony_ci
1817141cc406Sopenharmony_ci  status = get_read_sizes (s->fd, &s->lines_available, &bytes_per_line, &total_lines);
1818141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1819141cc406Sopenharmony_ci    {
1820141cc406Sopenharmony_ci      DBG (1, "open: get_read_sizes() failed: %s\n",
1821141cc406Sopenharmony_ci	   sane_strstatus (status));
1822141cc406Sopenharmony_ci      do_cancel (s);
1823141cc406Sopenharmony_ci      close (fd);
1824141cc406Sopenharmony_ci      return 1;
1825141cc406Sopenharmony_ci    }
1826141cc406Sopenharmony_ci
1827141cc406Sopenharmony_ci  if (!s->lines_available || !bytes_per_line || !total_lines || bytes_per_line < s->params.bytes_per_line)
1828141cc406Sopenharmony_ci    {
1829141cc406Sopenharmony_ci      DBG (1, "open: invalid sizes: %d, %d, %d\n",
1830141cc406Sopenharmony_ci	   s->lines_available, bytes_per_line, total_lines);
1831141cc406Sopenharmony_ci      do_cancel (s);
1832141cc406Sopenharmony_ci      close (fd);
1833141cc406Sopenharmony_ci      return 1;
1834141cc406Sopenharmony_ci    }
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  lines_per_buffer = sanei_scsi_max_request_size / bytes_per_line;
1837141cc406Sopenharmony_ci  if (!lines_per_buffer)
1838141cc406Sopenharmony_ci    {
1839141cc406Sopenharmony_ci      close (fd);
1840141cc406Sopenharmony_ci      return 2;			/* resolution is too high */
1841141cc406Sopenharmony_ci    }
1842141cc406Sopenharmony_ci
1843141cc406Sopenharmony_ci  data = malloc (lines_per_buffer * bytes_per_line);
1844141cc406Sopenharmony_ci  if (!data)
1845141cc406Sopenharmony_ci    {
1846141cc406Sopenharmony_ci      DBG (1, "open  malloc(%lu) failed.\n", (u_long) lines_per_buffer * bytes_per_line);
1847141cc406Sopenharmony_ci      do_cancel (s);
1848141cc406Sopenharmony_ci      close (fd);
1849141cc406Sopenharmony_ci      return 1;
1850141cc406Sopenharmony_ci    }
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci  while (lines_read < s->params.lines)
1853141cc406Sopenharmony_ci    {
1854141cc406Sopenharmony_ci      int lines = lines_per_buffer;
1855141cc406Sopenharmony_ci
1856141cc406Sopenharmony_ci      if (s->lines_available == 0)
1857141cc406Sopenharmony_ci	{
1858141cc406Sopenharmony_ci	  /* No lines in scanner?  Scan some more */
1859141cc406Sopenharmony_ci	  status = request_more_data (s);
1860141cc406Sopenharmony_ci
1861141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1862141cc406Sopenharmony_ci	    {
1863141cc406Sopenharmony_ci	      close (fd);
1864141cc406Sopenharmony_ci	      return 1;
1865141cc406Sopenharmony_ci	    }
1866141cc406Sopenharmony_ci	}
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci      /* We only request as many lines as there are already scanned */
1869141cc406Sopenharmony_ci      if (lines > s->lines_available)
1870141cc406Sopenharmony_ci	lines = s->lines_available;
1871141cc406Sopenharmony_ci
1872141cc406Sopenharmony_ci      DBG (1, "Requesting %d lines, in scanner: %d, total: %d\n", lines,
1873141cc406Sopenharmony_ci	   s->lines_available, s->params.lines);
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci      status = read_data (s, data, lines, bytes_per_line);
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1878141cc406Sopenharmony_ci	{
1879141cc406Sopenharmony_ci	  DBG (1, "sane_read: read_data() failed (%s)\n",
1880141cc406Sopenharmony_ci	       sane_strstatus (status));
1881141cc406Sopenharmony_ci	  do_cancel (s);
1882141cc406Sopenharmony_ci	  close (fd);
1883141cc406Sopenharmony_ci	  return 1;
1884141cc406Sopenharmony_ci	}
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci      /* Sometimes the scanner will return more bytes per line than
1887141cc406Sopenharmony_ci         requested, so we copy only what we wanted. */
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_ci      for (i = 0; i < lines; i++)
1890141cc406Sopenharmony_ci	if (write (fd, data + i * bytes_per_line, s->params.bytes_per_line) != s->params.bytes_per_line)
1891141cc406Sopenharmony_ci	  {
1892141cc406Sopenharmony_ci	    do_cancel (s);
1893141cc406Sopenharmony_ci	    close (fd);
1894141cc406Sopenharmony_ci	    return 1;
1895141cc406Sopenharmony_ci	  }
1896141cc406Sopenharmony_ci
1897141cc406Sopenharmony_ci      lines_read += lines;
1898141cc406Sopenharmony_ci    }
1899141cc406Sopenharmony_ci
1900141cc406Sopenharmony_ci  close (fd);
1901141cc406Sopenharmony_ci  return 0;
1902141cc406Sopenharmony_ci}
1903141cc406Sopenharmony_ci
1904141cc406Sopenharmony_ciSANE_Status
1905141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1906141cc406Sopenharmony_ci{
1907141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
1908141cc406Sopenharmony_ci  SANE_Status status;
1909141cc406Sopenharmony_ci  int fds[2];
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the
1912141cc406Sopenharmony_ci     parameters will be overwritten below, but that's OK.  */
1913141cc406Sopenharmony_ci
1914141cc406Sopenharmony_ci  status = sane_get_parameters (s, 0);
1915141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1916141cc406Sopenharmony_ci    return status;
1917141cc406Sopenharmony_ci
1918141cc406Sopenharmony_ci  /* don't initialise scanner if we're doing a three-pass scan */
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci  if (s->pass == 0)
1921141cc406Sopenharmony_ci    {
1922141cc406Sopenharmony_ci      if (s->fd < 0)
1923141cc406Sopenharmony_ci	{
1924141cc406Sopenharmony_ci	  status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0);
1925141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1926141cc406Sopenharmony_ci	    {
1927141cc406Sopenharmony_ci	      DBG (1, "open: open of %s failed: %s\n",
1928141cc406Sopenharmony_ci		   s->hw->sane.name, sane_strstatus (status));
1929141cc406Sopenharmony_ci	      s->fd = -1;
1930141cc406Sopenharmony_ci	      return status;
1931141cc406Sopenharmony_ci	    }
1932141cc406Sopenharmony_ci	}
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci      status = test_ready (s->fd);
1935141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1936141cc406Sopenharmony_ci	{
1937141cc406Sopenharmony_ci	  DBG (1, "open: test_ready() failed: %s\n", sane_strstatus (status));
1938141cc406Sopenharmony_ci	  sanei_scsi_close (s->fd);
1939141cc406Sopenharmony_ci	  s->fd = -1;
1940141cc406Sopenharmony_ci	  return status;
1941141cc406Sopenharmony_ci	}
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_ci      status = reserve_unit (s->fd);
1944141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1945141cc406Sopenharmony_ci	{
1946141cc406Sopenharmony_ci	  DBG (1, "open: reserve_unit() failed: %s\n", sane_strstatus (status));
1947141cc406Sopenharmony_ci	  sanei_scsi_close (s->fd);
1948141cc406Sopenharmony_ci	  s->fd = -1;
1949141cc406Sopenharmony_ci	  return status;
1950141cc406Sopenharmony_ci	}
1951141cc406Sopenharmony_ci
1952141cc406Sopenharmony_ci      status = set_window (s);
1953141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1954141cc406Sopenharmony_ci	{
1955141cc406Sopenharmony_ci	  DBG (1, "open: set_window() failed: %s\n", sane_strstatus (status));
1956141cc406Sopenharmony_ci	  release_unit (s->fd);
1957141cc406Sopenharmony_ci	  sanei_scsi_close (s->fd);
1958141cc406Sopenharmony_ci	  s->fd = -1;
1959141cc406Sopenharmony_ci	  return status;
1960141cc406Sopenharmony_ci	}
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci      {
1963141cc406Sopenharmony_ci	int matrix[256] = {
1964141cc406Sopenharmony_ci	   2, 60, 16, 56,  3, 57, 13, 53,
1965141cc406Sopenharmony_ci	  34, 18, 48, 32, 35, 19, 45, 29,
1966141cc406Sopenharmony_ci	  10, 50,  6, 63, 11, 51,  7, 61,
1967141cc406Sopenharmony_ci	  42, 26, 38, 22, 43, 27, 39, 23,
1968141cc406Sopenharmony_ci	   4, 58, 14, 54,  1, 59, 15, 55,
1969141cc406Sopenharmony_ci	  36, 20, 46, 30, 33, 17, 47, 31,
1970141cc406Sopenharmony_ci	  12, 52,  8, 62,  9, 49,  5, 63,
1971141cc406Sopenharmony_ci	  44, 28, 40, 24, 41, 25, 37, 21
1972141cc406Sopenharmony_ci	};
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci	status = upload_dither_matrix (s, 8, 8, matrix);
1975141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
1976141cc406Sopenharmony_ci	  {
1977141cc406Sopenharmony_ci	    DBG (1, "open: upload_dither_matrix() failed: %s\n", sane_strstatus (status));
1978141cc406Sopenharmony_ci	    release_unit (s->fd);
1979141cc406Sopenharmony_ci	    sanei_scsi_close (s->fd);
1980141cc406Sopenharmony_ci	    s->fd = -1;
1981141cc406Sopenharmony_ci	    return status;
1982141cc406Sopenharmony_ci	  }
1983141cc406Sopenharmony_ci      }
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci      s->scanning = SANE_TRUE;
1986141cc406Sopenharmony_ci
1987141cc406Sopenharmony_ci      status = start_scan (s->fd, SANE_FALSE);
1988141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1989141cc406Sopenharmony_ci	{
1990141cc406Sopenharmony_ci	  DBG (1, "open: start_scan() failed: %s\n", sane_strstatus (status));
1991141cc406Sopenharmony_ci	  do_cancel (s);
1992141cc406Sopenharmony_ci	  return status;
1993141cc406Sopenharmony_ci	}
1994141cc406Sopenharmony_ci    }
1995141cc406Sopenharmony_ci  else
1996141cc406Sopenharmony_ci    {
1997141cc406Sopenharmony_ci      /* continue three-pass scan */
1998141cc406Sopenharmony_ci
1999141cc406Sopenharmony_ci      status = start_scan (s->fd, SANE_TRUE);
2000141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2001141cc406Sopenharmony_ci	{
2002141cc406Sopenharmony_ci	  DBG (1, "open: start_scan() failed: %s\n", sane_strstatus (status));
2003141cc406Sopenharmony_ci	  do_cancel (s);
2004141cc406Sopenharmony_ci	  return status;
2005141cc406Sopenharmony_ci	}
2006141cc406Sopenharmony_ci    }
2007141cc406Sopenharmony_ci
2008141cc406Sopenharmony_ci  if (pipe (fds) < 0)
2009141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  s->pipe = fds[0];
2012141cc406Sopenharmony_ci  s->reader_pipe = fds[1];
2013141cc406Sopenharmony_ci  s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
2014141cc406Sopenharmony_ci
2015141cc406Sopenharmony_ci  if (sanei_thread_is_forked()) close (s->reader_pipe);
2016141cc406Sopenharmony_ci
2017141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2018141cc406Sopenharmony_ci}
2019141cc406Sopenharmony_ci
2020141cc406Sopenharmony_ciSANE_Status
2021141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
2022141cc406Sopenharmony_ci	   SANE_Int * len)
2023141cc406Sopenharmony_ci{
2024141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
2025141cc406Sopenharmony_ci  ssize_t nread;
2026141cc406Sopenharmony_ci
2027141cc406Sopenharmony_ci  *len = 0;
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci  nread = read (s->pipe, buf, max_len);
2030141cc406Sopenharmony_ci  DBG (3, "read %ld bytes\n", (long) nread);
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci  if (!s->scanning)
2033141cc406Sopenharmony_ci    return do_cancel (s);
2034141cc406Sopenharmony_ci
2035141cc406Sopenharmony_ci  if (nread < 0) {
2036141cc406Sopenharmony_ci    if (errno == EAGAIN) {
2037141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2038141cc406Sopenharmony_ci    } else {
2039141cc406Sopenharmony_ci      do_cancel (s);
2040141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2041141cc406Sopenharmony_ci    }
2042141cc406Sopenharmony_ci  }
2043141cc406Sopenharmony_ci
2044141cc406Sopenharmony_ci  *len = nread;
2045141cc406Sopenharmony_ci
2046141cc406Sopenharmony_ci  if (nread == 0) {
2047141cc406Sopenharmony_ci    s->pass++;
2048141cc406Sopenharmony_ci    return do_eof (s);
2049141cc406Sopenharmony_ci  }
2050141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2051141cc406Sopenharmony_ci}
2052141cc406Sopenharmony_ci
2053141cc406Sopenharmony_civoid
2054141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2055141cc406Sopenharmony_ci{
2056141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci  if (sanei_thread_is_valid (s->reader_pid))
2059141cc406Sopenharmony_ci    sanei_thread_kill (s->reader_pid);
2060141cc406Sopenharmony_ci  s->scanning = SANE_FALSE;
2061141cc406Sopenharmony_ci}
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_ciSANE_Status
2064141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2065141cc406Sopenharmony_ci{
2066141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci  if (!s->scanning)
2069141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2070141cc406Sopenharmony_ci
2071141cc406Sopenharmony_ci  if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
2072141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2075141cc406Sopenharmony_ci}
2076141cc406Sopenharmony_ci
2077141cc406Sopenharmony_ciSANE_Status
2078141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
2079141cc406Sopenharmony_ci{
2080141cc406Sopenharmony_ci  AgfaFocus_Scanner *s = handle;
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci  if (!s->scanning)
2083141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2084141cc406Sopenharmony_ci
2085141cc406Sopenharmony_ci  *fd = s->pipe;
2086141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2087141cc406Sopenharmony_ci}
2088