1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   ScanMaker 3840 Backend
4141cc406Sopenharmony_ci   Copyright (C) 2005-7 Earle F. Philhower, III
5141cc406Sopenharmony_ci   earle@ziplabel.com - http://www.ziplabel.com
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include "../include/sane/config.h"
47141cc406Sopenharmony_ci#include <string.h>
48141cc406Sopenharmony_ci#include <stdio.h>
49141cc406Sopenharmony_ci#include <stdlib.h>
50141cc406Sopenharmony_ci#include <unistd.h>
51141cc406Sopenharmony_ci#include <ctype.h>
52141cc406Sopenharmony_ci#include <limits.h>
53141cc406Sopenharmony_ci#include <stdarg.h>
54141cc406Sopenharmony_ci#include <string.h>
55141cc406Sopenharmony_ci#include <signal.h>
56141cc406Sopenharmony_ci#include <sys/stat.h>
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#include "../include/sane/sane.h"
59141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci#define BACKENDNAME sm3840
62141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
63141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
64141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci#include "sm3840.h"
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci#include "sm3840_scan.c"
69141cc406Sopenharmony_ci#include "sm3840_lib.c"
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_cistatic double sm3840_unit_convert (SANE_Int val);
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_cistatic int num_devices;
74141cc406Sopenharmony_cistatic SM3840_Device *first_dev;
75141cc406Sopenharmony_cistatic SM3840_Scan *first_handle;
76141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] = {
79141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
80141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
81141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
82141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_HALFTONE,
83141cc406Sopenharmony_ci  0
84141cc406Sopenharmony_ci};
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_cistatic const SANE_Word resolution_list[] = {
87141cc406Sopenharmony_ci  4, 1200, 600, 300, 150
88141cc406Sopenharmony_ci};
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_cistatic const SANE_Word bpp_list[] = {
91141cc406Sopenharmony_ci  2, 8, 16
92141cc406Sopenharmony_ci};
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic const SANE_Range x_range = {
95141cc406Sopenharmony_ci  SANE_FIX (0),
96141cc406Sopenharmony_ci  SANE_FIX (215.91),		/* 8.5 inches */
97141cc406Sopenharmony_ci  SANE_FIX (0)
98141cc406Sopenharmony_ci};
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_cistatic const SANE_Range y_range = {
101141cc406Sopenharmony_ci  SANE_FIX (0),
102141cc406Sopenharmony_ci  SANE_FIX (297.19),		/* 11.7 inches */
103141cc406Sopenharmony_ci  SANE_FIX (0)
104141cc406Sopenharmony_ci};
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_cistatic const SANE_Range brightness_range = {
107141cc406Sopenharmony_ci  1,
108141cc406Sopenharmony_ci  4096,
109141cc406Sopenharmony_ci  1.0
110141cc406Sopenharmony_ci};
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_cistatic const SANE_Range contrast_range = {
113141cc406Sopenharmony_ci  SANE_FIX (0.1),
114141cc406Sopenharmony_ci  SANE_FIX (9.9),
115141cc406Sopenharmony_ci  SANE_FIX (0.1)
116141cc406Sopenharmony_ci};
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_cistatic const SANE_Range lamp_range = {
119141cc406Sopenharmony_ci  1,
120141cc406Sopenharmony_ci  15,
121141cc406Sopenharmony_ci  1
122141cc406Sopenharmony_ci};
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_cistatic const SANE_Range threshold_range = {
125141cc406Sopenharmony_ci  0,
126141cc406Sopenharmony_ci  255,
127141cc406Sopenharmony_ci  1
128141cc406Sopenharmony_ci};
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
131141cc406Sopenharmony_cistatic int
132141cc406Sopenharmony_cimin (int a, int b)
133141cc406Sopenharmony_ci{
134141cc406Sopenharmony_ci  if (a < b)
135141cc406Sopenharmony_ci    return a;
136141cc406Sopenharmony_ci  else
137141cc406Sopenharmony_ci    return b;
138141cc406Sopenharmony_ci}
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ciSANE_Status
141141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
142141cc406Sopenharmony_ci	   SANE_Int * len)
143141cc406Sopenharmony_ci{
144141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
145141cc406Sopenharmony_ci  unsigned char c, d;
146141cc406Sopenharmony_ci  int i;
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci  DBG (2, "+sane-read:%p %p %d %p\n", (void *) s, (void *) buf, max_len,
149141cc406Sopenharmony_ci       (void *) len);
150141cc406Sopenharmony_ci  DBG (2,
151141cc406Sopenharmony_ci       "+sane-read:remain:%lu offset:%lu linesleft:%d linebuff:%p linesread:%d\n",
152141cc406Sopenharmony_ci       (u_long) s->remaining, (u_long) s->offset, s->linesleft,
153141cc406Sopenharmony_ci       (void *) s->line_buffer, s->linesread);
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci  if (!s->scanning)
156141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci  if (!s->remaining)
159141cc406Sopenharmony_ci    {
160141cc406Sopenharmony_ci      if (!s->linesleft)
161141cc406Sopenharmony_ci	{
162141cc406Sopenharmony_ci	  *len = 0;
163141cc406Sopenharmony_ci	  s->scanning = 0;
164141cc406Sopenharmony_ci	  /* Move to home position */
165141cc406Sopenharmony_ci	  reset_scanner ((p_usb_dev_handle)s->udev);
166141cc406Sopenharmony_ci	  /* Send lamp timeout */
167141cc406Sopenharmony_ci	  set_lamp_timer ((p_usb_dev_handle)s->udev, s->sm3840_params.lamp);
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci	  /* Free memory */
170141cc406Sopenharmony_ci	  if (s->save_scan_line)
171141cc406Sopenharmony_ci	    free (s->save_scan_line);
172141cc406Sopenharmony_ci	  s->save_scan_line = NULL;
173141cc406Sopenharmony_ci	  if (s->save_dpi1200_remap)
174141cc406Sopenharmony_ci	    free (s->save_dpi1200_remap);
175141cc406Sopenharmony_ci	  s->save_dpi1200_remap = NULL;
176141cc406Sopenharmony_ci	  if (s->save_color_remap)
177141cc406Sopenharmony_ci	    free (s->save_color_remap);
178141cc406Sopenharmony_ci	  s->save_color_remap = NULL;
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci	  return SANE_STATUS_EOF;
181141cc406Sopenharmony_ci	}
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci      record_line ((s->linesread == 0) ? 1 : 0,
184141cc406Sopenharmony_ci		   (p_usb_dev_handle) s->udev,
185141cc406Sopenharmony_ci		   s->line_buffer,
186141cc406Sopenharmony_ci		   s->sm3840_params.dpi,
187141cc406Sopenharmony_ci		   s->sm3840_params.scanpix,
188141cc406Sopenharmony_ci		   s->sm3840_params.gray,
189141cc406Sopenharmony_ci		   (s->sm3840_params.bpp == 16) ? 1 : 0,
190141cc406Sopenharmony_ci		   &s->save_i,
191141cc406Sopenharmony_ci		   &s->save_scan_line,
192141cc406Sopenharmony_ci		   &s->save_dpi1200_remap, &s->save_color_remap);
193141cc406Sopenharmony_ci      s->remaining = s->sm3840_params.linelen;
194141cc406Sopenharmony_ci      s->offset = 0;
195141cc406Sopenharmony_ci      s->linesread++;
196141cc406Sopenharmony_ci      s->linesleft--;
197141cc406Sopenharmony_ci    }
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci  /* Need to software emulate 1-bpp modes, simple threshold and error */
200141cc406Sopenharmony_ci  /* diffusion dither implemented. */
201141cc406Sopenharmony_ci  if (s->sm3840_params.lineart || s->sm3840_params.halftone)
202141cc406Sopenharmony_ci    {
203141cc406Sopenharmony_ci      d = 0;
204141cc406Sopenharmony_ci      for (i = 0; i < min (max_len * 8, s->remaining); i++)
205141cc406Sopenharmony_ci	{
206141cc406Sopenharmony_ci	  d = d << 1;
207141cc406Sopenharmony_ci	  if (s->sm3840_params.halftone)
208141cc406Sopenharmony_ci	    {
209141cc406Sopenharmony_ci	      c = (*(unsigned char *) (s->offset + s->line_buffer + i));
210141cc406Sopenharmony_ci	      if (c + s->save_dither_err < 128)
211141cc406Sopenharmony_ci		{
212141cc406Sopenharmony_ci		  d |= 1;
213141cc406Sopenharmony_ci		  s->save_dither_err += c;
214141cc406Sopenharmony_ci		}
215141cc406Sopenharmony_ci	      else
216141cc406Sopenharmony_ci		{
217141cc406Sopenharmony_ci		  s->save_dither_err += c - 255;
218141cc406Sopenharmony_ci		}
219141cc406Sopenharmony_ci	    }
220141cc406Sopenharmony_ci	  else
221141cc406Sopenharmony_ci	    {
222141cc406Sopenharmony_ci	      if ((*(unsigned char *) (s->offset + s->line_buffer + i)) < s->threshold )
223141cc406Sopenharmony_ci		d |= 1;
224141cc406Sopenharmony_ci	    }
225141cc406Sopenharmony_ci	  if (i % 8 == 7)
226141cc406Sopenharmony_ci	    *(buf++) = d;
227141cc406Sopenharmony_ci	}
228141cc406Sopenharmony_ci      *len = i / 8;
229141cc406Sopenharmony_ci      s->offset += i;
230141cc406Sopenharmony_ci      s->remaining -= i;
231141cc406Sopenharmony_ci    }
232141cc406Sopenharmony_ci  else
233141cc406Sopenharmony_ci    {
234141cc406Sopenharmony_ci      memcpy (buf, s->offset + s->line_buffer, min (max_len, s->remaining));
235141cc406Sopenharmony_ci      *len = min (max_len, s->remaining);
236141cc406Sopenharmony_ci      s->offset += min (max_len, s->remaining);
237141cc406Sopenharmony_ci      s->remaining -= min (max_len, s->remaining);
238141cc406Sopenharmony_ci    }
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci  DBG (2, "-sane_read\n");
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
243141cc406Sopenharmony_ci}
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
246141cc406Sopenharmony_civoid
247141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
248141cc406Sopenharmony_ci{
249141cc406Sopenharmony_ci  SM3840_Scan *s = h;
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci  DBG (2, "trying to cancel...\n");
252141cc406Sopenharmony_ci  if (s->scanning)
253141cc406Sopenharmony_ci    {
254141cc406Sopenharmony_ci      if (!s->cancelled)
255141cc406Sopenharmony_ci	{
256141cc406Sopenharmony_ci	  /* Move to home position */
257141cc406Sopenharmony_ci	  reset_scanner ((p_usb_dev_handle) s->udev);
258141cc406Sopenharmony_ci	  /* Send lamp timeout */
259141cc406Sopenharmony_ci	  set_lamp_timer ((p_usb_dev_handle) s->udev, s->sm3840_params.lamp);
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci	  /* Free memory */
262141cc406Sopenharmony_ci	  if (s->save_scan_line)
263141cc406Sopenharmony_ci	    free (s->save_scan_line);
264141cc406Sopenharmony_ci	  s->save_scan_line = NULL;
265141cc406Sopenharmony_ci	  if (s->save_dpi1200_remap)
266141cc406Sopenharmony_ci	    free (s->save_dpi1200_remap);
267141cc406Sopenharmony_ci	  s->save_dpi1200_remap = NULL;
268141cc406Sopenharmony_ci	  if (s->save_color_remap)
269141cc406Sopenharmony_ci	    free (s->save_color_remap);
270141cc406Sopenharmony_ci	  s->save_color_remap = NULL;
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci	  s->scanning = 0;
273141cc406Sopenharmony_ci	  s->cancelled = SANE_TRUE;
274141cc406Sopenharmony_ci	}
275141cc406Sopenharmony_ci    }
276141cc406Sopenharmony_ci}
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
279141cc406Sopenharmony_ciSANE_Status
280141cc406Sopenharmony_cisane_start (SANE_Handle handle)
281141cc406Sopenharmony_ci{
282141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
283141cc406Sopenharmony_ci  SANE_Status status;
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the
286141cc406Sopenharmony_ci   * parameters will be overwritten below, but that's OK.  */
287141cc406Sopenharmony_ci  DBG (2, "sane_start\n");
288141cc406Sopenharmony_ci  status = sane_get_parameters (s, 0);
289141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
290141cc406Sopenharmony_ci    return status;
291141cc406Sopenharmony_ci  DBG (1, "Got params again...\n");
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
294141cc406Sopenharmony_ci  s->cancelled = 0;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci  s->line_buffer = malloc (s->sm3840_params.linelen);
297141cc406Sopenharmony_ci  s->remaining = 0;
298141cc406Sopenharmony_ci  s->offset = 0;
299141cc406Sopenharmony_ci  s->linesleft = s->sm3840_params.scanlines;
300141cc406Sopenharmony_ci  s->linesread = 0;
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci  s->save_i = 0;
303141cc406Sopenharmony_ci  s->save_scan_line = NULL;
304141cc406Sopenharmony_ci  s->save_dpi1200_remap = NULL;
305141cc406Sopenharmony_ci  s->save_color_remap = NULL;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  s->save_dither_err = 0;
308141cc406Sopenharmony_ci  s->threshold = s->sm3840_params.threshold;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  setup_scan ((p_usb_dev_handle) s->udev, &(s->sm3840_params));
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
313141cc406Sopenharmony_ci}
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_cistatic double
316141cc406Sopenharmony_cism3840_unit_convert (SANE_Int val)
317141cc406Sopenharmony_ci{
318141cc406Sopenharmony_ci  double d;
319141cc406Sopenharmony_ci  d = SANE_UNFIX (val);
320141cc406Sopenharmony_ci  d /= MM_PER_INCH;
321141cc406Sopenharmony_ci  return d;
322141cc406Sopenharmony_ci}
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
325141cc406Sopenharmony_ciSANE_Status
326141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
327141cc406Sopenharmony_ci{
328141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci  DBG (2, "sane_get_parameters\n");
331141cc406Sopenharmony_ci  if (!s->scanning)
332141cc406Sopenharmony_ci    {
333141cc406Sopenharmony_ci      memset (&s->sane_params, 0, sizeof (s->sane_params));
334141cc406Sopenharmony_ci      /* Copy from options to sm3840_params */
335141cc406Sopenharmony_ci      s->sm3840_params.gray =
336141cc406Sopenharmony_ci	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) ? 1 : 0;
337141cc406Sopenharmony_ci      s->sm3840_params.halftone =
338141cc406Sopenharmony_ci	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE)) ? 1 : 0;
339141cc406Sopenharmony_ci      s->sm3840_params.lineart =
340141cc406Sopenharmony_ci	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) ? 1 : 0;
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci      s->sm3840_params.dpi = s->value[OPT_RESOLUTION].w;
343141cc406Sopenharmony_ci      s->sm3840_params.bpp = s->value[OPT_BIT_DEPTH].w;
344141cc406Sopenharmony_ci      s->sm3840_params.gain = SANE_UNFIX (s->value[OPT_CONTRAST].w);
345141cc406Sopenharmony_ci      s->sm3840_params.offset = s->value[OPT_BRIGHTNESS].w;
346141cc406Sopenharmony_ci      s->sm3840_params.lamp = s->value[OPT_LAMP_TIMEOUT].w;
347141cc406Sopenharmony_ci      s->sm3840_params.threshold = s->value[OPT_THRESHOLD].w;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci      if (s->sm3840_params.lineart || s->sm3840_params.halftone)
350141cc406Sopenharmony_ci	{
351141cc406Sopenharmony_ci	  s->sm3840_params.gray = 1;
352141cc406Sopenharmony_ci	  s->sm3840_params.bpp = 8;
353141cc406Sopenharmony_ci	}
354141cc406Sopenharmony_ci
355141cc406Sopenharmony_ci      s->sm3840_params.top = sm3840_unit_convert (s->value[OPT_TL_Y].w);
356141cc406Sopenharmony_ci      s->sm3840_params.left = sm3840_unit_convert (s->value[OPT_TL_X].w);
357141cc406Sopenharmony_ci      s->sm3840_params.width =
358141cc406Sopenharmony_ci	sm3840_unit_convert (s->value[OPT_BR_X].w) - s->sm3840_params.left;
359141cc406Sopenharmony_ci      s->sm3840_params.height =
360141cc406Sopenharmony_ci	sm3840_unit_convert (s->value[OPT_BR_Y].w) - s->sm3840_params.top;
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci      /* Legalize and calculate pixel sizes */
363141cc406Sopenharmony_ci      prepare_params (&(s->sm3840_params));
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci      /* Copy into sane_params */
366141cc406Sopenharmony_ci      s->sane_params.pixels_per_line = s->sm3840_params.scanpix;
367141cc406Sopenharmony_ci      s->sane_params.lines = s->sm3840_params.scanlines;
368141cc406Sopenharmony_ci      s->sane_params.format =
369141cc406Sopenharmony_ci	s->sm3840_params.gray ? SANE_FRAME_GRAY : SANE_FRAME_RGB;
370141cc406Sopenharmony_ci      s->sane_params.bytes_per_line = s->sm3840_params.linelen;
371141cc406Sopenharmony_ci      s->sane_params.depth = s->sm3840_params.bpp;
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci      if (s->sm3840_params.lineart || s->sm3840_params.halftone)
374141cc406Sopenharmony_ci	{
375141cc406Sopenharmony_ci	  s->sane_params.bytes_per_line += 7;
376141cc406Sopenharmony_ci	  s->sane_params.bytes_per_line /= 8;
377141cc406Sopenharmony_ci	  s->sane_params.depth = 1;
378141cc406Sopenharmony_ci	  s->sane_params.pixels_per_line = s->sane_params.bytes_per_line * 8;
379141cc406Sopenharmony_ci	}
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci      s->sane_params.last_frame = SANE_TRUE;
382141cc406Sopenharmony_ci    }				/*!scanning */
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  if (params)
385141cc406Sopenharmony_ci    *params = s->sane_params;
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
388141cc406Sopenharmony_ci}
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
391141cc406Sopenharmony_ciSANE_Status
392141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
393141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
394141cc406Sopenharmony_ci{
395141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
396141cc406Sopenharmony_ci  SANE_Status status = 0;
397141cc406Sopenharmony_ci  SANE_Word cap;
398141cc406Sopenharmony_ci  DBG (2, "sane_control_option\n");
399141cc406Sopenharmony_ci  if (info)
400141cc406Sopenharmony_ci    *info = 0;
401141cc406Sopenharmony_ci  if (s->scanning)
402141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
403141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS)
404141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
405141cc406Sopenharmony_ci  cap = s->options_list[option].cap;
406141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
407141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
408141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
409141cc406Sopenharmony_ci    {
410141cc406Sopenharmony_ci      DBG (1, "sane_control_option %d, get value\n", option);
411141cc406Sopenharmony_ci      switch (option)
412141cc406Sopenharmony_ci	{
413141cc406Sopenharmony_ci	  /* word options: */
414141cc406Sopenharmony_ci	case OPT_RESOLUTION:
415141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
416141cc406Sopenharmony_ci	case OPT_TL_X:
417141cc406Sopenharmony_ci	case OPT_TL_Y:
418141cc406Sopenharmony_ci	case OPT_BR_X:
419141cc406Sopenharmony_ci	case OPT_BR_Y:
420141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
421141cc406Sopenharmony_ci	case OPT_CONTRAST:
422141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
423141cc406Sopenharmony_ci	case OPT_LAMP_TIMEOUT:
424141cc406Sopenharmony_ci	case OPT_THRESHOLD:
425141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->value[option].w;
426141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
427141cc406Sopenharmony_ci	  /* string options: */
428141cc406Sopenharmony_ci	case OPT_MODE:
429141cc406Sopenharmony_ci	  strcpy (val, s->value[option].s);
430141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
431141cc406Sopenharmony_ci	}
432141cc406Sopenharmony_ci    }
433141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
434141cc406Sopenharmony_ci    {
435141cc406Sopenharmony_ci      DBG (1, "sane_control_option %d, set value\n", option);
436141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
437141cc406Sopenharmony_ci	return (SANE_STATUS_INVAL);
438141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
439141cc406Sopenharmony_ci	return (status);
440141cc406Sopenharmony_ci      status = sanei_constrain_value (s->options_list + option, val, info);
441141cc406Sopenharmony_ci      switch (option)
442141cc406Sopenharmony_ci	{
443141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
444141cc406Sopenharmony_ci	case OPT_RESOLUTION:
445141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
446141cc406Sopenharmony_ci	case OPT_BR_X:
447141cc406Sopenharmony_ci	case OPT_BR_Y:
448141cc406Sopenharmony_ci	case OPT_TL_X:
449141cc406Sopenharmony_ci	case OPT_TL_Y:
450141cc406Sopenharmony_ci	  if (info)
451141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
452141cc406Sopenharmony_ci	  /* fall through */
453141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
454141cc406Sopenharmony_ci	case OPT_CONTRAST:
455141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
456141cc406Sopenharmony_ci	case OPT_LAMP_TIMEOUT:
457141cc406Sopenharmony_ci	case OPT_THRESHOLD:
458141cc406Sopenharmony_ci	  s->value[option].w = *(SANE_Word *) val;
459141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
460141cc406Sopenharmony_ci	case OPT_MODE:
461141cc406Sopenharmony_ci	  if (s->value[option].s)
462141cc406Sopenharmony_ci	    free (s->value[option].s);
463141cc406Sopenharmony_ci	  s->value[option].s = strdup (val);
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci	  if (info)
466141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
467141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
468141cc406Sopenharmony_ci	}
469141cc406Sopenharmony_ci    }
470141cc406Sopenharmony_ci  return (SANE_STATUS_INVAL);
471141cc406Sopenharmony_ci}
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
474141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
475141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
476141cc406Sopenharmony_ci{
477141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
478141cc406Sopenharmony_ci  DBG (2, "sane_get_option_descriptor\n");
479141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
480141cc406Sopenharmony_ci    return (0);
481141cc406Sopenharmony_ci  return (&s->options_list[option]);
482141cc406Sopenharmony_ci}
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_civoid
487141cc406Sopenharmony_cisane_close (SANE_Handle handle)
488141cc406Sopenharmony_ci{
489141cc406Sopenharmony_ci  SM3840_Scan *prev, *s;
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci  DBG (2, "sane_close\n");
492141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
493141cc406Sopenharmony_ci  prev = 0;
494141cc406Sopenharmony_ci  for (s = first_handle; s; s = s->next)
495141cc406Sopenharmony_ci    {
496141cc406Sopenharmony_ci      if (s == handle)
497141cc406Sopenharmony_ci	break;
498141cc406Sopenharmony_ci      prev = s;
499141cc406Sopenharmony_ci    }
500141cc406Sopenharmony_ci  if (!s)
501141cc406Sopenharmony_ci    {
502141cc406Sopenharmony_ci      DBG (1, "close: invalid handle %p\n", handle);
503141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
504141cc406Sopenharmony_ci    }
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci  if (s->scanning)
507141cc406Sopenharmony_ci    {
508141cc406Sopenharmony_ci      sane_cancel (handle);
509141cc406Sopenharmony_ci    }
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci  sanei_usb_close (s->udev);
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci  if (s->line_buffer)
514141cc406Sopenharmony_ci    free (s->line_buffer);
515141cc406Sopenharmony_ci  if (s->save_scan_line)
516141cc406Sopenharmony_ci    free (s->save_scan_line);
517141cc406Sopenharmony_ci  if (s->save_dpi1200_remap)
518141cc406Sopenharmony_ci    free (s->save_dpi1200_remap);
519141cc406Sopenharmony_ci  if (s->save_color_remap)
520141cc406Sopenharmony_ci    free (s->save_color_remap);
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci  if (prev)
523141cc406Sopenharmony_ci    prev->next = s->next;
524141cc406Sopenharmony_ci  else
525141cc406Sopenharmony_ci    first_handle = s;
526141cc406Sopenharmony_ci  free (handle);
527141cc406Sopenharmony_ci}
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
530141cc406Sopenharmony_civoid
531141cc406Sopenharmony_cisane_exit (void)
532141cc406Sopenharmony_ci{
533141cc406Sopenharmony_ci  SM3840_Device *next;
534141cc406Sopenharmony_ci  DBG (2, "sane_exit\n");
535141cc406Sopenharmony_ci  while (first_dev != NULL)
536141cc406Sopenharmony_ci    {
537141cc406Sopenharmony_ci      next = first_dev->next;
538141cc406Sopenharmony_ci      free (first_dev);
539141cc406Sopenharmony_ci      first_dev = next;
540141cc406Sopenharmony_ci    }
541141cc406Sopenharmony_ci  if (devlist)
542141cc406Sopenharmony_ci    free (devlist);
543141cc406Sopenharmony_ci}
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci
546141cc406Sopenharmony_ci
547141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
548141cc406Sopenharmony_ciSANE_Status
549141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
550141cc406Sopenharmony_ci{
551141cc406Sopenharmony_ci  DBG_INIT ();
552141cc406Sopenharmony_ci  if (version_code)
553141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
554141cc406Sopenharmony_ci  if (authorize)
555141cc406Sopenharmony_ci    DBG (2, "Unused authorize\n");
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci  sanei_usb_init ();
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
560141cc406Sopenharmony_ci}
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_cistatic SANE_Status
566141cc406Sopenharmony_ciadd_sm_device (SANE_String_Const devname, SANE_String_Const modname)
567141cc406Sopenharmony_ci{
568141cc406Sopenharmony_ci  SM3840_Device *dev;
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ci  dev = calloc (sizeof (*dev), 1);
571141cc406Sopenharmony_ci  if (!dev)
572141cc406Sopenharmony_ci    return (SANE_STATUS_NO_MEM);
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
575141cc406Sopenharmony_ci  dev->sane.name = strdup (devname);
576141cc406Sopenharmony_ci  dev->sane.model = modname;
577141cc406Sopenharmony_ci  dev->sane.vendor = "Microtek";
578141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
579141cc406Sopenharmony_ci  ++num_devices;
580141cc406Sopenharmony_ci  dev->next = first_dev;
581141cc406Sopenharmony_ci  first_dev = dev;
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
584141cc406Sopenharmony_ci}
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_cistatic SANE_Status
587141cc406Sopenharmony_ciadd_sm3840_device (SANE_String_Const devname)
588141cc406Sopenharmony_ci{
589141cc406Sopenharmony_ci  return add_sm_device (devname, "ScanMaker 3840");
590141cc406Sopenharmony_ci}
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_cistatic SANE_Status
593141cc406Sopenharmony_ciadd_sm4800_device (SANE_String_Const devname)
594141cc406Sopenharmony_ci{
595141cc406Sopenharmony_ci  return add_sm_device (devname, "ScanMaker 4800");
596141cc406Sopenharmony_ci}
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
600141cc406Sopenharmony_ciSANE_Status
601141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
602141cc406Sopenharmony_ci{
603141cc406Sopenharmony_ci  static const SANE_Device **devlist = 0;
604141cc406Sopenharmony_ci  SM3840_Device *dev;
605141cc406Sopenharmony_ci  int i;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci  DBG (3, "sane_get_devices (local_only = %d)\n", local_only);
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci  while (first_dev)
610141cc406Sopenharmony_ci    {
611141cc406Sopenharmony_ci      dev = first_dev->next;
612141cc406Sopenharmony_ci      free (first_dev);
613141cc406Sopenharmony_ci      first_dev = dev;
614141cc406Sopenharmony_ci    }
615141cc406Sopenharmony_ci  first_dev = NULL;
616141cc406Sopenharmony_ci  num_devices = 0;
617141cc406Sopenharmony_ci
618141cc406Sopenharmony_ci  /* If we get enough scanners should use an array, but for now */
619141cc406Sopenharmony_ci  /* do it one-by-one... */
620141cc406Sopenharmony_ci  sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_device);
621141cc406Sopenharmony_ci  sanei_usb_find_devices (0x05da, 0x30cf, add_sm4800_device);
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci  if (devlist)
624141cc406Sopenharmony_ci    free (devlist);
625141cc406Sopenharmony_ci  devlist = calloc ((num_devices + 1) * sizeof (devlist[0]), 1);
626141cc406Sopenharmony_ci  if (!devlist)
627141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
628141cc406Sopenharmony_ci  i = 0;
629141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
630141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
631141cc406Sopenharmony_ci  devlist[i++] = 0;
632141cc406Sopenharmony_ci  if (device_list)
633141cc406Sopenharmony_ci    *device_list = devlist;
634141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
635141cc406Sopenharmony_ci}
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_cistatic size_t
641141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
642141cc406Sopenharmony_ci{
643141cc406Sopenharmony_ci  size_t size, max_size = 0;
644141cc406Sopenharmony_ci  int i;
645141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
646141cc406Sopenharmony_ci    {
647141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
648141cc406Sopenharmony_ci      if (size > max_size)
649141cc406Sopenharmony_ci	max_size = size;
650141cc406Sopenharmony_ci    }
651141cc406Sopenharmony_ci
652141cc406Sopenharmony_ci  return (max_size);
653141cc406Sopenharmony_ci}
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_cistatic void
658141cc406Sopenharmony_ciinitialize_options_list (SM3840_Scan * s)
659141cc406Sopenharmony_ci{
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci  SANE_Int option;
662141cc406Sopenharmony_ci  DBG (2, "initialize_options_list\n");
663141cc406Sopenharmony_ci  for (option = 0; option < NUM_OPTIONS; ++option)
664141cc406Sopenharmony_ci    {
665141cc406Sopenharmony_ci      s->options_list[option].size = sizeof (SANE_Word);
666141cc406Sopenharmony_ci      s->options_list[option].cap =
667141cc406Sopenharmony_ci	SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
668141cc406Sopenharmony_ci    }
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
671141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
672141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
673141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT;
674141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE;
675141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word);
676141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
677141cc406Sopenharmony_ci  s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
678141cc406Sopenharmony_ci  s->value[OPT_NUM_OPTS].w = NUM_OPTIONS;
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci  s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE;
681141cc406Sopenharmony_ci  s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
682141cc406Sopenharmony_ci  s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
683141cc406Sopenharmony_ci  s->options_list[OPT_MODE].type = SANE_TYPE_STRING;
684141cc406Sopenharmony_ci  s->options_list[OPT_MODE].size = max_string_size (mode_list);
685141cc406Sopenharmony_ci  s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
686141cc406Sopenharmony_ci  s->options_list[OPT_MODE].constraint.string_list = mode_list;
687141cc406Sopenharmony_ci  s->value[OPT_MODE].s = strdup (mode_list[1]);
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
690141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
691141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
692141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT;
693141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
694141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
695141cc406Sopenharmony_ci  s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list;
696141cc406Sopenharmony_ci  s->value[OPT_RESOLUTION].w = 300;
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
699141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
700141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
701141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
702141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE;
703141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
704141cc406Sopenharmony_ci  s->options_list[OPT_BIT_DEPTH].constraint.word_list = bpp_list;
705141cc406Sopenharmony_ci  s->value[OPT_BIT_DEPTH].w = 8;
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
708141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
709141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
710141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED;
711141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].unit = SANE_UNIT_MM;
712141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
713141cc406Sopenharmony_ci  s->options_list[OPT_TL_X].constraint.range = &x_range;
714141cc406Sopenharmony_ci  s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min;
715141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
716141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
717141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
718141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED;
719141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM;
720141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
721141cc406Sopenharmony_ci  s->options_list[OPT_TL_Y].constraint.range = &y_range;
722141cc406Sopenharmony_ci  s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min;
723141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
724141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
725141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
726141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED;
727141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].unit = SANE_UNIT_MM;
728141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
729141cc406Sopenharmony_ci  s->options_list[OPT_BR_X].constraint.range = &x_range;
730141cc406Sopenharmony_ci  s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max;
731141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
732141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
733141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
734141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED;
735141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM;
736141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
737141cc406Sopenharmony_ci  s->options_list[OPT_BR_Y].constraint.range = &y_range;
738141cc406Sopenharmony_ci  s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max;
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
741141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
742141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
743141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].type = SANE_TYPE_FIXED;
744141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE;
745141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
746141cc406Sopenharmony_ci  s->options_list[OPT_CONTRAST].constraint.range = &contrast_range;
747141cc406Sopenharmony_ci  s->value[OPT_CONTRAST].w = SANE_FIX (3.5);
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
750141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
751141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
752141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
753141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
754141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
755141cc406Sopenharmony_ci  s->options_list[OPT_BRIGHTNESS].constraint.range = &brightness_range;
756141cc406Sopenharmony_ci  s->value[OPT_BRIGHTNESS].w = 1800;
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].name = "lamp-timeout";
759141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].title = SANE_I18N ("Lamp timeout");
760141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].desc =
761141cc406Sopenharmony_ci    SANE_I18N ("Minutes until lamp is turned off after scan");
762141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].type = SANE_TYPE_INT;
763141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE;
764141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE;
765141cc406Sopenharmony_ci  s->options_list[OPT_LAMP_TIMEOUT].constraint.range = &lamp_range;
766141cc406Sopenharmony_ci  s->value[OPT_LAMP_TIMEOUT].w = 15;
767141cc406Sopenharmony_ci
768141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].name = "threshold";
769141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].title = SANE_I18N ("Threshold");
770141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].desc =
771141cc406Sopenharmony_ci    SANE_I18N ("Threshold value for lineart mode");
772141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].type = SANE_TYPE_INT;
773141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
774141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
775141cc406Sopenharmony_ci  s->options_list[OPT_THRESHOLD].constraint.range = &threshold_range;
776141cc406Sopenharmony_ci  s->value[OPT_THRESHOLD].w = 128;
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci}
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
781141cc406Sopenharmony_ciSANE_Status
782141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
783141cc406Sopenharmony_ci{
784141cc406Sopenharmony_ci  SANE_Status status;
785141cc406Sopenharmony_ci  SM3840_Device *dev;
786141cc406Sopenharmony_ci  SM3840_Scan *s;
787141cc406Sopenharmony_ci  DBG (2, "sane_open\n");
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci  /* Make sure we have first_dev */
790141cc406Sopenharmony_ci  sane_get_devices (NULL, 0);
791141cc406Sopenharmony_ci  if (devicename[0])
792141cc406Sopenharmony_ci    {
793141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
794141cc406Sopenharmony_ci	if (strcmp (dev->sane.name, devicename) == 0)
795141cc406Sopenharmony_ci	  break;
796141cc406Sopenharmony_ci    }
797141cc406Sopenharmony_ci  else
798141cc406Sopenharmony_ci    {
799141cc406Sopenharmony_ci      /* empty devicename -> use first device */
800141cc406Sopenharmony_ci      dev = first_dev;
801141cc406Sopenharmony_ci    }
802141cc406Sopenharmony_ci  DBG (2, "using device: %s %p\n", dev->sane.name, (void *) dev);
803141cc406Sopenharmony_ci  if (!dev)
804141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
805141cc406Sopenharmony_ci  s = calloc (sizeof (*s), 1);
806141cc406Sopenharmony_ci  if (!s)
807141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci  status = sanei_usb_open (dev->sane.name, &(s->udev));
810141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
811141cc406Sopenharmony_ci    return status;
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  initialize_options_list (s);
814141cc406Sopenharmony_ci  s->scanning = 0;
815141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
816141cc406Sopenharmony_ci  s->next = first_handle;
817141cc406Sopenharmony_ci  first_handle = s;
818141cc406Sopenharmony_ci  *handle = s;
819141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
820141cc406Sopenharmony_ci}
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
823141cc406Sopenharmony_ciSANE_Status
824141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
825141cc406Sopenharmony_ci{
826141cc406Sopenharmony_ci  SM3840_Scan *s = handle;
827141cc406Sopenharmony_ci  DBG (2, "sane_set_io_mode( %p, %d )\n", handle, non_blocking);
828141cc406Sopenharmony_ci  if (s->scanning)
829141cc406Sopenharmony_ci    {
830141cc406Sopenharmony_ci      if (non_blocking == SANE_FALSE)
831141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
832141cc406Sopenharmony_ci      else
833141cc406Sopenharmony_ci	return (SANE_STATUS_UNSUPPORTED);
834141cc406Sopenharmony_ci    }
835141cc406Sopenharmony_ci  else
836141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
837141cc406Sopenharmony_ci}
838141cc406Sopenharmony_ci
839141cc406Sopenharmony_ci/*---------------------------------------------------------------------------*/
840141cc406Sopenharmony_ciSANE_Status
841141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
842141cc406Sopenharmony_ci{
843141cc406Sopenharmony_ci  DBG (2, "sane_get_select_fd( %p, %p )\n", (void *) handle, (void *) fd);
844141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
845141cc406Sopenharmony_ci}
846