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