1 /* sane - Scanner Access Now Easy.
2 
3    ScanMaker 3840 Backend
4    Copyright (C) 2005-7 Earle F. Philhower, III
5    earle@ziplabel.com - http://www.ziplabel.com
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 
20    As a special exception, the authors of SANE give permission for
21    additional uses of the libraries contained in this release of SANE.
22 
23    The exception is that, if you link a SANE library with other files
24    to produce an executable, this does not by itself cause the
25    resulting executable to be covered by the GNU General Public
26    License.  Your use of that executable is in no way restricted on
27    account of linking the SANE library code into it.
28 
29    This exception does not, however, invalidate any other reasons why
30    the executable file might be covered by the GNU General Public
31    License.
32 
33    If you submit changes to SANE to the maintainers to be included in
34    a subsequent release, you agree by submitting the changes that
35    those changes may be distributed with this exception intact.
36 
37    If you write modifications of your own for SANE, it is your choice
38    whether to permit this exception to apply to your modifications.
39    If you do not wish that, delete this exception notice.
40 
41 */
42 
43 
44 
45 
46 #include "../include/sane/config.h"
47 #include <string.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <ctype.h>
52 #include <limits.h>
53 #include <stdarg.h>
54 #include <string.h>
55 #include <signal.h>
56 #include <sys/stat.h>
57 
58 #include "../include/sane/sane.h"
59 #include "../include/sane/saneopts.h"
60 
61 #define BACKENDNAME sm3840
62 #include "../include/sane/sanei_backend.h"
63 #include "../include/sane/sanei_usb.h"
64 #include "../include/sane/sanei_config.h"
65 
66 #include "sm3840.h"
67 
68 #include "sm3840_scan.c"
69 #include "sm3840_lib.c"
70 
71 static double sm3840_unit_convert (SANE_Int val);
72 
73 static int num_devices;
74 static SM3840_Device *first_dev;
75 static SM3840_Scan *first_handle;
76 static const SANE_Device **devlist = 0;
77 
78 static const SANE_String_Const mode_list[] = {
79   SANE_VALUE_SCAN_MODE_GRAY,
80   SANE_VALUE_SCAN_MODE_COLOR,
81   SANE_VALUE_SCAN_MODE_LINEART,
82   SANE_VALUE_SCAN_MODE_HALFTONE,
83   0
84 };
85 
86 static const SANE_Word resolution_list[] = {
87   4, 1200, 600, 300, 150
88 };
89 
90 static const SANE_Word bpp_list[] = {
91   2, 8, 16
92 };
93 
94 static const SANE_Range x_range = {
95   SANE_FIX (0),
96   SANE_FIX (215.91),		/* 8.5 inches */
97   SANE_FIX (0)
98 };
99 
100 static const SANE_Range y_range = {
101   SANE_FIX (0),
102   SANE_FIX (297.19),		/* 11.7 inches */
103   SANE_FIX (0)
104 };
105 
106 static const SANE_Range brightness_range = {
107   1,
108   4096,
109   1.0
110 };
111 
112 static const SANE_Range contrast_range = {
113   SANE_FIX (0.1),
114   SANE_FIX (9.9),
115   SANE_FIX (0.1)
116 };
117 
118 static const SANE_Range lamp_range = {
119   1,
120   15,
121   1
122 };
123 
124 static const SANE_Range threshold_range = {
125   0,
126   255,
127   1
128 };
129 
130 /*--------------------------------------------------------------------------*/
131 static int
min(int a, int b)132 min (int a, int b)
133 {
134   if (a < b)
135     return a;
136   else
137     return b;
138 }
139 
140 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len)141 sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
142 	   SANE_Int * len)
143 {
144   SM3840_Scan *s = handle;
145   unsigned char c, d;
146   int i;
147 
148   DBG (2, "+sane-read:%p %p %d %p\n", (void *) s, (void *) buf, max_len,
149        (void *) len);
150   DBG (2,
151        "+sane-read:remain:%lu offset:%lu linesleft:%d linebuff:%p linesread:%d\n",
152        (u_long) s->remaining, (u_long) s->offset, s->linesleft,
153        (void *) s->line_buffer, s->linesread);
154 
155   if (!s->scanning)
156     return SANE_STATUS_INVAL;
157 
158   if (!s->remaining)
159     {
160       if (!s->linesleft)
161 	{
162 	  *len = 0;
163 	  s->scanning = 0;
164 	  /* Move to home position */
165 	  reset_scanner ((p_usb_dev_handle)s->udev);
166 	  /* Send lamp timeout */
167 	  set_lamp_timer ((p_usb_dev_handle)s->udev, s->sm3840_params.lamp);
168 
169 	  /* Free memory */
170 	  if (s->save_scan_line)
171 	    free (s->save_scan_line);
172 	  s->save_scan_line = NULL;
173 	  if (s->save_dpi1200_remap)
174 	    free (s->save_dpi1200_remap);
175 	  s->save_dpi1200_remap = NULL;
176 	  if (s->save_color_remap)
177 	    free (s->save_color_remap);
178 	  s->save_color_remap = NULL;
179 
180 	  return SANE_STATUS_EOF;
181 	}
182 
183       record_line ((s->linesread == 0) ? 1 : 0,
184 		   (p_usb_dev_handle) s->udev,
185 		   s->line_buffer,
186 		   s->sm3840_params.dpi,
187 		   s->sm3840_params.scanpix,
188 		   s->sm3840_params.gray,
189 		   (s->sm3840_params.bpp == 16) ? 1 : 0,
190 		   &s->save_i,
191 		   &s->save_scan_line,
192 		   &s->save_dpi1200_remap, &s->save_color_remap);
193       s->remaining = s->sm3840_params.linelen;
194       s->offset = 0;
195       s->linesread++;
196       s->linesleft--;
197     }
198 
199   /* Need to software emulate 1-bpp modes, simple threshold and error */
200   /* diffusion dither implemented. */
201   if (s->sm3840_params.lineart || s->sm3840_params.halftone)
202     {
203       d = 0;
204       for (i = 0; i < min (max_len * 8, s->remaining); i++)
205 	{
206 	  d = d << 1;
207 	  if (s->sm3840_params.halftone)
208 	    {
209 	      c = (*(unsigned char *) (s->offset + s->line_buffer + i));
210 	      if (c + s->save_dither_err < 128)
211 		{
212 		  d |= 1;
213 		  s->save_dither_err += c;
214 		}
215 	      else
216 		{
217 		  s->save_dither_err += c - 255;
218 		}
219 	    }
220 	  else
221 	    {
222 	      if ((*(unsigned char *) (s->offset + s->line_buffer + i)) < s->threshold )
223 		d |= 1;
224 	    }
225 	  if (i % 8 == 7)
226 	    *(buf++) = d;
227 	}
228       *len = i / 8;
229       s->offset += i;
230       s->remaining -= i;
231     }
232   else
233     {
234       memcpy (buf, s->offset + s->line_buffer, min (max_len, s->remaining));
235       *len = min (max_len, s->remaining);
236       s->offset += min (max_len, s->remaining);
237       s->remaining -= min (max_len, s->remaining);
238     }
239 
240   DBG (2, "-sane_read\n");
241 
242   return SANE_STATUS_GOOD;
243 }
244 
245 /*--------------------------------------------------------------------------*/
246 void
sane_cancel(SANE_Handle h)247 sane_cancel (SANE_Handle h)
248 {
249   SM3840_Scan *s = h;
250 
251   DBG (2, "trying to cancel...\n");
252   if (s->scanning)
253     {
254       if (!s->cancelled)
255 	{
256 	  /* Move to home position */
257 	  reset_scanner ((p_usb_dev_handle) s->udev);
258 	  /* Send lamp timeout */
259 	  set_lamp_timer ((p_usb_dev_handle) s->udev, s->sm3840_params.lamp);
260 
261 	  /* Free memory */
262 	  if (s->save_scan_line)
263 	    free (s->save_scan_line);
264 	  s->save_scan_line = NULL;
265 	  if (s->save_dpi1200_remap)
266 	    free (s->save_dpi1200_remap);
267 	  s->save_dpi1200_remap = NULL;
268 	  if (s->save_color_remap)
269 	    free (s->save_color_remap);
270 	  s->save_color_remap = NULL;
271 
272 	  s->scanning = 0;
273 	  s->cancelled = SANE_TRUE;
274 	}
275     }
276 }
277 
278 /*--------------------------------------------------------------------------*/
279 SANE_Status
sane_start(SANE_Handle handle)280 sane_start (SANE_Handle handle)
281 {
282   SM3840_Scan *s = handle;
283   SANE_Status status;
284 
285   /* First make sure we have a current parameter set.  Some of the
286    * parameters will be overwritten below, but that's OK.  */
287   DBG (2, "sane_start\n");
288   status = sane_get_parameters (s, 0);
289   if (status != SANE_STATUS_GOOD)
290     return status;
291   DBG (1, "Got params again...\n");
292 
293   s->scanning = SANE_TRUE;
294   s->cancelled = 0;
295 
296   s->line_buffer = malloc (s->sm3840_params.linelen);
297   s->remaining = 0;
298   s->offset = 0;
299   s->linesleft = s->sm3840_params.scanlines;
300   s->linesread = 0;
301 
302   s->save_i = 0;
303   s->save_scan_line = NULL;
304   s->save_dpi1200_remap = NULL;
305   s->save_color_remap = NULL;
306 
307   s->save_dither_err = 0;
308   s->threshold = s->sm3840_params.threshold;
309 
310   setup_scan ((p_usb_dev_handle) s->udev, &(s->sm3840_params));
311 
312   return (SANE_STATUS_GOOD);
313 }
314 
315 static double
sm3840_unit_convert(SANE_Int val)316 sm3840_unit_convert (SANE_Int val)
317 {
318   double d;
319   d = SANE_UNFIX (val);
320   d /= MM_PER_INCH;
321   return d;
322 }
323 
324 /*--------------------------------------------------------------------------*/
325 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters * params)326 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
327 {
328   SM3840_Scan *s = handle;
329 
330   DBG (2, "sane_get_parameters\n");
331   if (!s->scanning)
332     {
333       memset (&s->sane_params, 0, sizeof (s->sane_params));
334       /* Copy from options to sm3840_params */
335       s->sm3840_params.gray =
336 	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) ? 1 : 0;
337       s->sm3840_params.halftone =
338 	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE)) ? 1 : 0;
339       s->sm3840_params.lineart =
340 	(!strcasecmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) ? 1 : 0;
341 
342       s->sm3840_params.dpi = s->value[OPT_RESOLUTION].w;
343       s->sm3840_params.bpp = s->value[OPT_BIT_DEPTH].w;
344       s->sm3840_params.gain = SANE_UNFIX (s->value[OPT_CONTRAST].w);
345       s->sm3840_params.offset = s->value[OPT_BRIGHTNESS].w;
346       s->sm3840_params.lamp = s->value[OPT_LAMP_TIMEOUT].w;
347       s->sm3840_params.threshold = s->value[OPT_THRESHOLD].w;
348 
349       if (s->sm3840_params.lineart || s->sm3840_params.halftone)
350 	{
351 	  s->sm3840_params.gray = 1;
352 	  s->sm3840_params.bpp = 8;
353 	}
354 
355       s->sm3840_params.top = sm3840_unit_convert (s->value[OPT_TL_Y].w);
356       s->sm3840_params.left = sm3840_unit_convert (s->value[OPT_TL_X].w);
357       s->sm3840_params.width =
358 	sm3840_unit_convert (s->value[OPT_BR_X].w) - s->sm3840_params.left;
359       s->sm3840_params.height =
360 	sm3840_unit_convert (s->value[OPT_BR_Y].w) - s->sm3840_params.top;
361 
362       /* Legalize and calculate pixel sizes */
363       prepare_params (&(s->sm3840_params));
364 
365       /* Copy into sane_params */
366       s->sane_params.pixels_per_line = s->sm3840_params.scanpix;
367       s->sane_params.lines = s->sm3840_params.scanlines;
368       s->sane_params.format =
369 	s->sm3840_params.gray ? SANE_FRAME_GRAY : SANE_FRAME_RGB;
370       s->sane_params.bytes_per_line = s->sm3840_params.linelen;
371       s->sane_params.depth = s->sm3840_params.bpp;
372 
373       if (s->sm3840_params.lineart || s->sm3840_params.halftone)
374 	{
375 	  s->sane_params.bytes_per_line += 7;
376 	  s->sane_params.bytes_per_line /= 8;
377 	  s->sane_params.depth = 1;
378 	  s->sane_params.pixels_per_line = s->sane_params.bytes_per_line * 8;
379 	}
380 
381       s->sane_params.last_frame = SANE_TRUE;
382     }				/*!scanning */
383 
384   if (params)
385     *params = s->sane_params;
386 
387   return (SANE_STATUS_GOOD);
388 }
389 
390 /*--------------------------------------------------------------------------*/
391 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int * info)392 sane_control_option (SANE_Handle handle, SANE_Int option,
393 		     SANE_Action action, void *val, SANE_Int * info)
394 {
395   SM3840_Scan *s = handle;
396   SANE_Status status = 0;
397   SANE_Word cap;
398   DBG (2, "sane_control_option\n");
399   if (info)
400     *info = 0;
401   if (s->scanning)
402     return SANE_STATUS_DEVICE_BUSY;
403   if (option >= NUM_OPTIONS)
404     return SANE_STATUS_INVAL;
405   cap = s->options_list[option].cap;
406   if (!SANE_OPTION_IS_ACTIVE (cap))
407     return SANE_STATUS_INVAL;
408   if (action == SANE_ACTION_GET_VALUE)
409     {
410       DBG (1, "sane_control_option %d, get value\n", option);
411       switch (option)
412 	{
413 	  /* word options: */
414 	case OPT_RESOLUTION:
415 	case OPT_BIT_DEPTH:
416 	case OPT_TL_X:
417 	case OPT_TL_Y:
418 	case OPT_BR_X:
419 	case OPT_BR_Y:
420 	case OPT_NUM_OPTS:
421 	case OPT_CONTRAST:
422 	case OPT_BRIGHTNESS:
423 	case OPT_LAMP_TIMEOUT:
424 	case OPT_THRESHOLD:
425 	  *(SANE_Word *) val = s->value[option].w;
426 	  return (SANE_STATUS_GOOD);
427 	  /* string options: */
428 	case OPT_MODE:
429 	  strcpy (val, s->value[option].s);
430 	  return (SANE_STATUS_GOOD);
431 	}
432     }
433   else if (action == SANE_ACTION_SET_VALUE)
434     {
435       DBG (1, "sane_control_option %d, set value\n", option);
436       if (!SANE_OPTION_IS_SETTABLE (cap))
437 	return (SANE_STATUS_INVAL);
438       if (status != SANE_STATUS_GOOD)
439 	return (status);
440       status = sanei_constrain_value (s->options_list + option, val, info);
441       switch (option)
442 	{
443 	  /* (mostly) side-effect-free word options: */
444 	case OPT_RESOLUTION:
445 	case OPT_BIT_DEPTH:
446 	case OPT_BR_X:
447 	case OPT_BR_Y:
448 	case OPT_TL_X:
449 	case OPT_TL_Y:
450 	  if (info)
451 	    *info |= SANE_INFO_RELOAD_PARAMS;
452 	  /* fall through */
453 	case OPT_NUM_OPTS:
454 	case OPT_CONTRAST:
455 	case OPT_BRIGHTNESS:
456 	case OPT_LAMP_TIMEOUT:
457 	case OPT_THRESHOLD:
458 	  s->value[option].w = *(SANE_Word *) val;
459 	  return (SANE_STATUS_GOOD);
460 	case OPT_MODE:
461 	  if (s->value[option].s)
462 	    free (s->value[option].s);
463 	  s->value[option].s = strdup (val);
464 
465 	  if (info)
466 	    *info |= SANE_INFO_RELOAD_PARAMS;
467 	  return (SANE_STATUS_GOOD);
468 	}
469     }
470   return (SANE_STATUS_INVAL);
471 }
472 
473 /*--------------------------------------------------------------------------*/
474 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)475 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
476 {
477   SM3840_Scan *s = handle;
478   DBG (2, "sane_get_option_descriptor\n");
479   if ((unsigned) option >= NUM_OPTIONS)
480     return (0);
481   return (&s->options_list[option]);
482 }
483 
484 /*--------------------------------------------------------------------------*/
485 
486 void
sane_close(SANE_Handle handle)487 sane_close (SANE_Handle handle)
488 {
489   SM3840_Scan *prev, *s;
490 
491   DBG (2, "sane_close\n");
492   /* remove handle from list of open handles: */
493   prev = 0;
494   for (s = first_handle; s; s = s->next)
495     {
496       if (s == handle)
497 	break;
498       prev = s;
499     }
500   if (!s)
501     {
502       DBG (1, "close: invalid handle %p\n", handle);
503       return;			/* oops, not a handle we know about */
504     }
505 
506   if (s->scanning)
507     {
508       sane_cancel (handle);
509     }
510 
511   sanei_usb_close (s->udev);
512 
513   if (s->line_buffer)
514     free (s->line_buffer);
515   if (s->save_scan_line)
516     free (s->save_scan_line);
517   if (s->save_dpi1200_remap)
518     free (s->save_dpi1200_remap);
519   if (s->save_color_remap)
520     free (s->save_color_remap);
521 
522   if (prev)
523     prev->next = s->next;
524   else
525     first_handle = s;
526   free (handle);
527 }
528 
529 /*--------------------------------------------------------------------------*/
530 void
sane_exit(void)531 sane_exit (void)
532 {
533   SM3840_Device *next;
534   DBG (2, "sane_exit\n");
535   while (first_dev != NULL)
536     {
537       next = first_dev->next;
538       free (first_dev);
539       first_dev = next;
540     }
541   if (devlist)
542     free (devlist);
543 }
544 
545 
546 
547 /*--------------------------------------------------------------------------*/
548 SANE_Status
sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize)549 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
550 {
551   DBG_INIT ();
552   if (version_code)
553     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
554   if (authorize)
555     DBG (2, "Unused authorize\n");
556 
557   sanei_usb_init ();
558 
559   return (SANE_STATUS_GOOD);
560 }
561 
562 /*--------------------------------------------------------------------------*/
563 
564 
565 static SANE_Status
add_sm_device(SANE_String_Const devname, SANE_String_Const modname)566 add_sm_device (SANE_String_Const devname, SANE_String_Const modname)
567 {
568   SM3840_Device *dev;
569 
570   dev = calloc (sizeof (*dev), 1);
571   if (!dev)
572     return (SANE_STATUS_NO_MEM);
573 
574   memset (dev, 0, sizeof (*dev));
575   dev->sane.name = strdup (devname);
576   dev->sane.model = modname;
577   dev->sane.vendor = "Microtek";
578   dev->sane.type = "flatbed scanner";
579   ++num_devices;
580   dev->next = first_dev;
581   first_dev = dev;
582 
583   return (SANE_STATUS_GOOD);
584 }
585 
586 static SANE_Status
add_sm3840_device(SANE_String_Const devname)587 add_sm3840_device (SANE_String_Const devname)
588 {
589   return add_sm_device (devname, "ScanMaker 3840");
590 }
591 
592 static SANE_Status
add_sm4800_device(SANE_String_Const devname)593 add_sm4800_device (SANE_String_Const devname)
594 {
595   return add_sm_device (devname, "ScanMaker 4800");
596 }
597 
598 
599 /*--------------------------------------------------------------------------*/
600 SANE_Status
sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only)601 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
602 {
603   static const SANE_Device **devlist = 0;
604   SM3840_Device *dev;
605   int i;
606 
607   DBG (3, "sane_get_devices (local_only = %d)\n", local_only);
608 
609   while (first_dev)
610     {
611       dev = first_dev->next;
612       free (first_dev);
613       first_dev = dev;
614     }
615   first_dev = NULL;
616   num_devices = 0;
617 
618   /* If we get enough scanners should use an array, but for now */
619   /* do it one-by-one... */
620   sanei_usb_find_devices (0x05da, 0x30d4, add_sm3840_device);
621   sanei_usb_find_devices (0x05da, 0x30cf, add_sm4800_device);
622 
623   if (devlist)
624     free (devlist);
625   devlist = calloc ((num_devices + 1) * sizeof (devlist[0]), 1);
626   if (!devlist)
627     return SANE_STATUS_NO_MEM;
628   i = 0;
629   for (dev = first_dev; i < num_devices; dev = dev->next)
630     devlist[i++] = &dev->sane;
631   devlist[i++] = 0;
632   if (device_list)
633     *device_list = devlist;
634   return (SANE_STATUS_GOOD);
635 }
636 
637 
638 /*--------------------------------------------------------------------------*/
639 
640 static size_t
max_string_size(const SANE_String_Const strings[])641 max_string_size (const SANE_String_Const strings[])
642 {
643   size_t size, max_size = 0;
644   int i;
645   for (i = 0; strings[i]; ++i)
646     {
647       size = strlen (strings[i]) + 1;
648       if (size > max_size)
649 	max_size = size;
650     }
651 
652   return (max_size);
653 }
654 
655 /*--------------------------------------------------------------------------*/
656 
657 static void
initialize_options_list(SM3840_Scan * s)658 initialize_options_list (SM3840_Scan * s)
659 {
660 
661   SANE_Int option;
662   DBG (2, "initialize_options_list\n");
663   for (option = 0; option < NUM_OPTIONS; ++option)
664     {
665       s->options_list[option].size = sizeof (SANE_Word);
666       s->options_list[option].cap =
667 	SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
668     }
669 
670   s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
671   s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
672   s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
673   s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT;
674   s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE;
675   s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word);
676   s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
677   s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
678   s->value[OPT_NUM_OPTS].w = NUM_OPTIONS;
679 
680   s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE;
681   s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
682   s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
683   s->options_list[OPT_MODE].type = SANE_TYPE_STRING;
684   s->options_list[OPT_MODE].size = max_string_size (mode_list);
685   s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
686   s->options_list[OPT_MODE].constraint.string_list = mode_list;
687   s->value[OPT_MODE].s = strdup (mode_list[1]);
688 
689   s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
690   s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
691   s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
692   s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT;
693   s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
694   s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
695   s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list;
696   s->value[OPT_RESOLUTION].w = 300;
697 
698   s->options_list[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
699   s->options_list[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
700   s->options_list[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
701   s->options_list[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
702   s->options_list[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE;
703   s->options_list[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
704   s->options_list[OPT_BIT_DEPTH].constraint.word_list = bpp_list;
705   s->value[OPT_BIT_DEPTH].w = 8;
706 
707   s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
708   s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
709   s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
710   s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED;
711   s->options_list[OPT_TL_X].unit = SANE_UNIT_MM;
712   s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
713   s->options_list[OPT_TL_X].constraint.range = &x_range;
714   s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min;
715   s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
716   s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
717   s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
718   s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED;
719   s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM;
720   s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
721   s->options_list[OPT_TL_Y].constraint.range = &y_range;
722   s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min;
723   s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
724   s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
725   s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
726   s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED;
727   s->options_list[OPT_BR_X].unit = SANE_UNIT_MM;
728   s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
729   s->options_list[OPT_BR_X].constraint.range = &x_range;
730   s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max;
731   s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
732   s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
733   s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
734   s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED;
735   s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM;
736   s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
737   s->options_list[OPT_BR_Y].constraint.range = &y_range;
738   s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max;
739 
740   s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
741   s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
742   s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
743   s->options_list[OPT_CONTRAST].type = SANE_TYPE_FIXED;
744   s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE;
745   s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
746   s->options_list[OPT_CONTRAST].constraint.range = &contrast_range;
747   s->value[OPT_CONTRAST].w = SANE_FIX (3.5);
748 
749   s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
750   s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
751   s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
752   s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
753   s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
754   s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
755   s->options_list[OPT_BRIGHTNESS].constraint.range = &brightness_range;
756   s->value[OPT_BRIGHTNESS].w = 1800;
757 
758   s->options_list[OPT_LAMP_TIMEOUT].name = "lamp-timeout";
759   s->options_list[OPT_LAMP_TIMEOUT].title = SANE_I18N ("Lamp timeout");
760   s->options_list[OPT_LAMP_TIMEOUT].desc =
761     SANE_I18N ("Minutes until lamp is turned off after scan");
762   s->options_list[OPT_LAMP_TIMEOUT].type = SANE_TYPE_INT;
763   s->options_list[OPT_LAMP_TIMEOUT].unit = SANE_UNIT_NONE;
764   s->options_list[OPT_LAMP_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE;
765   s->options_list[OPT_LAMP_TIMEOUT].constraint.range = &lamp_range;
766   s->value[OPT_LAMP_TIMEOUT].w = 15;
767 
768   s->options_list[OPT_THRESHOLD].name = "threshold";
769   s->options_list[OPT_THRESHOLD].title = SANE_I18N ("Threshold");
770   s->options_list[OPT_THRESHOLD].desc =
771     SANE_I18N ("Threshold value for lineart mode");
772   s->options_list[OPT_THRESHOLD].type = SANE_TYPE_INT;
773   s->options_list[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
774   s->options_list[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
775   s->options_list[OPT_THRESHOLD].constraint.range = &threshold_range;
776   s->value[OPT_THRESHOLD].w = 128;
777 
778 }
779 
780 /*--------------------------------------------------------------------------*/
781 SANE_Status
sane_open(SANE_String_Const devicename, SANE_Handle * handle)782 sane_open (SANE_String_Const devicename, SANE_Handle * handle)
783 {
784   SANE_Status status;
785   SM3840_Device *dev;
786   SM3840_Scan *s;
787   DBG (2, "sane_open\n");
788 
789   /* Make sure we have first_dev */
790   sane_get_devices (NULL, 0);
791   if (devicename[0])
792     {
793       for (dev = first_dev; dev; dev = dev->next)
794 	if (strcmp (dev->sane.name, devicename) == 0)
795 	  break;
796     }
797   else
798     {
799       /* empty devicename -> use first device */
800       dev = first_dev;
801     }
802   DBG (2, "using device: %s %p\n", dev->sane.name, (void *) dev);
803   if (!dev)
804     return SANE_STATUS_INVAL;
805   s = calloc (sizeof (*s), 1);
806   if (!s)
807     return SANE_STATUS_NO_MEM;
808 
809   status = sanei_usb_open (dev->sane.name, &(s->udev));
810   if (status != SANE_STATUS_GOOD)
811     return status;
812 
813   initialize_options_list (s);
814   s->scanning = 0;
815   /* insert newly opened handle into list of open handles: */
816   s->next = first_handle;
817   first_handle = s;
818   *handle = s;
819   return (SANE_STATUS_GOOD);
820 }
821 
822 /*--------------------------------------------------------------------------*/
823 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)824 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
825 {
826   SM3840_Scan *s = handle;
827   DBG (2, "sane_set_io_mode( %p, %d )\n", handle, non_blocking);
828   if (s->scanning)
829     {
830       if (non_blocking == SANE_FALSE)
831 	return SANE_STATUS_GOOD;
832       else
833 	return (SANE_STATUS_UNSUPPORTED);
834     }
835   else
836     return SANE_STATUS_INVAL;
837 }
838 
839 /*---------------------------------------------------------------------------*/
840 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int * fd)841 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
842 {
843   DBG (2, "sane_get_select_fd( %p, %p )\n", (void *) handle, (void *) fd);
844   return SANE_STATUS_UNSUPPORTED;
845 }
846