1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2001, Marcio Luis Teixeira
4 
5    Parts copyright (C) 1996, 1997 Andreas Beck
6    Parts copyright (C) 2000, 2001 Michael Herder <crapsite@gmx.net>
7    Parts copyright (C) 2001 Henning Meier-Geinitz <henning@meier-geinitz.de>
8    Parts copyright (C) 2006 Patrick Lessard
9 
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of the
13    License, or (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <https://www.gnu.org/licenses/>.
22 
23    As a special exception, the authors of SANE give permission for
24    additional uses of the libraries contained in this release of SANE.
25 
26    The exception is that, if you link a SANE library with other files
27    to produce an executable, this does not by itself cause the
28    resulting executable to be covered by the GNU General Public
29    License.  Your use of that executable is in no way restricted on
30    account of linking the SANE library code into it.
31 
32    This exception does not, however, invalidate any other reasons why
33    the executable file might be covered by the GNU General Public
34    License.
35 
36    If you submit changes to SANE to the maintainers to be included in
37    a subsequent release, you agree by submitting the changes that
38    those changes may be distributed with this exception intact.
39 
40    If you write modifications of your own for SANE, it is your choice
41    whether to permit this exception to apply to your modifications.
42    If you do not wish that, delete this exception notice.  */
43 
44 #define BUILD 2
45 #define MM_IN_INCH 25.4
46 
47 #include "../include/sane/config.h"
48 
49 #include <stdlib.h>
50 #include <string.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <sys/ioctl.h>
55 
56 #include "../include/sane/sane.h"
57 #include "../include/sane/sanei.h"
58 #include "../include/sane/saneopts.h"
59 #include "../include/sane/sanei_config.h"
60 #include "../include/sane/sanei_usb.h"
61 #include "../include/sane/sanei_pv8630.h"
62 
63 #define BACKEND_NAME        umax1220u
64 #define UMAX_CONFIG_FILE "umax1220u.conf"
65 
66 #include "../include/sane/sanei_backend.h"
67 
68 #include "umax1220u-common.c"
69 
70 typedef struct Umax_Device
71 {
72   struct Umax_Device *next;
73   SANE_String name;
74   SANE_Device sane;
75 }
76 Umax_Device;
77 
78 typedef struct Umax_Scanner
79 {
80   struct Umax_Scanner *next;
81   Umax_Device *device;
82   UMAX_Handle scan;
83 }
84 Umax_Scanner;
85 
86 static int num_devices             = 0;
87 static const SANE_Device **devlist = NULL;
88 static Umax_Device *first_dev      = NULL;
89 static Umax_Scanner *first_handle  = NULL;
90 
91 static SANE_Parameters parms = {
92   SANE_FRAME_RGB,
93   0,
94   0,                   /* Number of bytes returned per scan line: */
95   0,                   /* Number of pixels per scan line.  */
96   0,                   /* Number of lines for the current scan.  */
97   8                    /* Number of bits per sample. */
98 };
99 
100 struct _SANE_Option
101 {
102   SANE_Option_Descriptor *descriptor;
103   SANE_Status (*callback) (struct _SANE_Option * option, SANE_Handle handle,
104                            SANE_Action action, void *value,
105                            SANE_Int * info);
106 };
107 
108 typedef struct _SANE_Option SANE_Option;
109 
110 static SANE_Word getNumberOfOptions (void);  /* Forward declaration */
111 
112 /*
113 This read-only option returns the number of options available for
114 the device. It should be the first option in the options array
115 declared below.
116 */
117 
118 static SANE_Option_Descriptor optionNumOptionsDescriptor = {
119   SANE_NAME_NUM_OPTIONS,
120   SANE_TITLE_NUM_OPTIONS,
121   SANE_DESC_NUM_OPTIONS,
122   SANE_TYPE_INT,
123   SANE_UNIT_NONE,
124   sizeof (SANE_Word),
125   SANE_CAP_SOFT_DETECT,
126   SANE_CONSTRAINT_NONE,
127   {NULL}
128 };
129 
130 static SANE_Status
optionNumOptionsCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)131 optionNumOptionsCallback (SANE_Option * option, SANE_Handle handle,
132                           SANE_Action action, void *value, SANE_Int * info)
133 {
134   option = option;
135   handle = handle;
136   info = info;    /* Eliminate warning about unused parameters */
137 
138   if (action != SANE_ACTION_GET_VALUE)
139     return SANE_STATUS_INVAL;
140   *(SANE_Word *) value = getNumberOfOptions ();
141   return SANE_STATUS_GOOD;
142 }
143 
144 /*
145 This option lets the user select the scan resolution. The UMAX
146 scanner only supports the following resolutions: 75, 150, 300 and
147 600
148 */
149 
150 static const SANE_Word optionResolutionList[] = {
151   4,                       /* Number of elements */
152   75, 150, 300, 600        /* Resolution list */
153 };
154 
155 static SANE_Option_Descriptor optionResolutionDescriptor = {
156   SANE_NAME_SCAN_RESOLUTION,
157   SANE_TITLE_SCAN_RESOLUTION,
158   SANE_DESC_SCAN_RESOLUTION,
159   SANE_TYPE_INT,
160   SANE_UNIT_DPI,
161   sizeof (SANE_Word),
162   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_AUTOMATIC,
163   SANE_CONSTRAINT_WORD_LIST,
164   {(const SANE_String_Const *) optionResolutionList}
165 };
166 
167 static SANE_Word optionResolutionValue = 75;
168 
169 static SANE_Status
optionResolutionCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)170 optionResolutionCallback (SANE_Option * option, SANE_Handle handle,
171                           SANE_Action action, void *value, SANE_Int * info)
172 {
173   SANE_Status status;
174   SANE_Word autoValue = 75;
175 
176   handle = handle;     /* Eliminate warning about unused parameters */
177 
178   switch (action)
179     {
180     case SANE_ACTION_SET_AUTO:
181       status =
182         sanei_constrain_value (option->descriptor, (void *) &autoValue, info);
183       if (status != SANE_STATUS_GOOD)
184         return status;
185       optionResolutionValue = autoValue;
186       *info |= SANE_INFO_RELOAD_PARAMS;
187       break;
188     case SANE_ACTION_SET_VALUE:
189       *info |= SANE_INFO_RELOAD_PARAMS;
190       optionResolutionValue = *(SANE_Word *) value;
191       break;
192     case SANE_ACTION_GET_VALUE:
193       *(SANE_Word *) value = optionResolutionValue;
194       break;
195     }
196   return SANE_STATUS_GOOD;
197 }
198 
199 /*
200 This option lets the user select a gray scale scan
201 */
202 static SANE_Word optionGrayscaleValue = SANE_FALSE;
203 
204 static SANE_Option_Descriptor optionGrayscaleDescriptor = {
205   "gray",
206   SANE_I18N ("Grayscale scan"),
207   SANE_I18N ("Do a grayscale rather than color scan"),
208   SANE_TYPE_BOOL,
209   SANE_UNIT_NONE,
210   sizeof (SANE_Word),
211   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
212   SANE_CONSTRAINT_NONE,
213   {NULL}
214 };
215 
216 static SANE_Status
optionGrayscaleCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)217 optionGrayscaleCallback (SANE_Option * option, SANE_Handle handle,
218                          SANE_Action action, void *value, SANE_Int * info)
219 {
220   handle = handle;
221   option = option;     /* Eliminate warning about unused parameters */
222 
223   switch (action)
224     {
225     case SANE_ACTION_SET_AUTO:
226       return SANE_STATUS_INVAL;
227       break;
228     case SANE_ACTION_SET_VALUE:
229       *info |= SANE_INFO_RELOAD_PARAMS;
230       optionGrayscaleValue = *(SANE_Bool *) value;
231       break;
232     case SANE_ACTION_GET_VALUE:
233       *(SANE_Word *) value = optionGrayscaleValue;
234       break;
235     }
236   return SANE_STATUS_GOOD;
237 }
238 
239 /*
240 This option is a button that allows the user to turn off the
241 lamp in the UMAX scanner
242 */
243 
244 static SANE_Option_Descriptor optionLampOffDescriptor = {
245   "lamp-off",
246   SANE_I18N ("Lamp off"),
247   SANE_I18N ("Turn off scanner lamp"),
248   SANE_TYPE_BUTTON,
249   SANE_UNIT_NONE,
250   0,
251   SANE_CAP_SOFT_SELECT,
252   SANE_CONSTRAINT_NONE,
253   {NULL}
254 };
255 
256 static SANE_Status
optionLampOffCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)257 optionLampOffCallback (SANE_Option * option, SANE_Handle handle,
258                        SANE_Action action, void *value, SANE_Int * info)
259 {
260   Umax_Scanner *scanner = handle;
261   SANE_Status res = SANE_STATUS_GOOD;
262 
263   /* Eliminate warnings about unused parameters */
264   option = option;
265   handle = handle;
266   info   = info;
267   value  = value;
268 
269   if (action != SANE_ACTION_SET_VALUE)
270     return SANE_STATUS_INVAL;
271 
272   res = UMAX_set_lamp_state (&scanner->scan, UMAX_LAMP_OFF);
273 
274   return res;
275 }
276 
277 static const SANE_Range widthRange = {
278   0,                                              /* minimum */
279   SANE_FIX (UMAX_MAX_WIDTH * MM_IN_INCH / 600),   /* maximum */
280   0                                               /* quantization */
281 };
282 
283 static const SANE_Range heightRange = {
284   0,                                              /* minimum */
285   SANE_FIX (UMAX_MAX_HEIGHT * MM_IN_INCH / 600),  /* maximum */
286   0                                               /* quantization */
287 };
288 
289 /*
290 This option controls the top-left-x corner of the scan
291 */
292 
293 static SANE_Fixed optionTopLeftXValue = 0;
294 
295 static SANE_Option_Descriptor optionTopLeftXDescriptor = {
296   SANE_NAME_SCAN_TL_X,
297   SANE_TITLE_SCAN_TL_X,
298   SANE_DESC_SCAN_TL_X,
299   SANE_TYPE_FIXED,
300   SANE_UNIT_MM,
301   sizeof (SANE_Fixed),
302   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
303   SANE_CONSTRAINT_RANGE,
304   {(const SANE_String_Const *) & widthRange}
305 };
306 
307 static SANE_Status
optionTopLeftXCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)308 optionTopLeftXCallback (SANE_Option * option, SANE_Handle handle,
309                         SANE_Action action, void *value, SANE_Int * info)
310 {
311   option = option;
312   handle = handle;
313   value  = value;      /* Eliminate warning about unused parameters */
314 
315   switch (action)
316     {
317     case SANE_ACTION_SET_AUTO:
318       return SANE_STATUS_INVAL;
319       break;
320     case SANE_ACTION_SET_VALUE:
321       optionTopLeftXValue = *(SANE_Fixed *) value;
322       *info |= SANE_INFO_RELOAD_PARAMS;
323       break;
324     case SANE_ACTION_GET_VALUE:
325       *(SANE_Fixed *) value = optionTopLeftXValue;
326       break;
327     }
328   return SANE_STATUS_GOOD;
329 }
330 
331 /*
332 This option controls the top-left-y corner of the scan
333 */
334 
335 static SANE_Fixed optionTopLeftYValue = 0;
336 
337 static SANE_Option_Descriptor optionTopLeftYDescriptor = {
338   SANE_NAME_SCAN_TL_Y,
339   SANE_TITLE_SCAN_TL_Y,
340   SANE_DESC_SCAN_TL_Y,
341   SANE_TYPE_FIXED,
342   SANE_UNIT_MM,
343   sizeof (SANE_Fixed),
344   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
345   SANE_CONSTRAINT_RANGE,
346   {(const SANE_String_Const *) & heightRange}
347 };
348 
349 static SANE_Status
optionTopLeftYCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)350 optionTopLeftYCallback (SANE_Option * option, SANE_Handle handle,
351                         SANE_Action action, void *value, SANE_Int * info)
352 {
353   /* Eliminate warnings about unused parameters */
354   option = option;
355   handle = handle;
356 
357   switch (action)
358     {
359     case SANE_ACTION_SET_AUTO:
360       return SANE_STATUS_INVAL;
361       break;
362     case SANE_ACTION_SET_VALUE:
363       optionTopLeftYValue = *(SANE_Fixed *) value;
364       *info |= SANE_INFO_RELOAD_PARAMS;
365       break;
366     case SANE_ACTION_GET_VALUE:
367       *(SANE_Fixed *) value = optionTopLeftYValue;
368       break;
369     }
370   return SANE_STATUS_GOOD;
371 }
372 
373 /*
374 This option controls the bot-right-x corner of the scan
375 */
376 
377 static SANE_Fixed optionBotRightXValue
378   = SANE_FIX (UMAX_MAX_WIDTH * MM_IN_INCH / 600);
379 
380 static SANE_Option_Descriptor optionBotRightXDescriptor = {
381   SANE_NAME_SCAN_BR_X,
382   SANE_TITLE_SCAN_BR_X,
383   SANE_DESC_SCAN_BR_X,
384   SANE_TYPE_FIXED,
385   SANE_UNIT_MM,
386   sizeof (SANE_Fixed),
387   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
388   SANE_CONSTRAINT_RANGE,
389   {(const SANE_String_Const *) & widthRange}
390 };
391 
392 static SANE_Status
optionBotRightXCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)393 optionBotRightXCallback (SANE_Option * option, SANE_Handle handle,
394                          SANE_Action action, void *value, SANE_Int * info)
395 {
396   /* Eliminate warnings about unused parameters */
397   option = option;
398   handle = handle;
399 
400   switch (action)
401     {
402     case SANE_ACTION_SET_AUTO:
403       return SANE_STATUS_INVAL;
404       break;
405     case SANE_ACTION_SET_VALUE:
406       optionBotRightXValue = *(SANE_Fixed *) value;
407       *info |= SANE_INFO_RELOAD_PARAMS;
408       break;
409     case SANE_ACTION_GET_VALUE:
410       *(SANE_Fixed *) value = optionBotRightXValue;
411       break;
412     }
413   return SANE_STATUS_GOOD;
414 }
415 
416 /*
417 This option controls the bot-right-y corner of the scan
418 */
419 
420 static SANE_Fixed optionBotRightYValue
421   = SANE_FIX (UMAX_MAX_HEIGHT * MM_IN_INCH / 600);
422 
423 static SANE_Option_Descriptor optionBotRightYDescriptor = {
424   SANE_NAME_SCAN_BR_Y,
425   SANE_TITLE_SCAN_BR_Y,
426   SANE_DESC_SCAN_BR_Y,
427   SANE_TYPE_FIXED,
428   SANE_UNIT_MM,
429   sizeof (SANE_Fixed),
430   SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
431   SANE_CONSTRAINT_RANGE,
432   {(const SANE_String_Const *) & heightRange}
433 };
434 
435 static SANE_Status
optionBotRightYCallback(SANE_Option * option,SANE_Handle handle,SANE_Action action,void * value,SANE_Int * info)436 optionBotRightYCallback (SANE_Option * option, SANE_Handle handle,
437                          SANE_Action action, void *value, SANE_Int * info)
438 {
439   /* Eliminate warnings about unused parameters */
440   option = option;
441   handle = handle;
442 
443   switch (action)
444     {
445     case SANE_ACTION_SET_AUTO:
446       return SANE_STATUS_INVAL;
447       break;
448     case SANE_ACTION_SET_VALUE:
449       optionBotRightYValue = *(SANE_Fixed *) value;
450       *info |= SANE_INFO_RELOAD_PARAMS;
451       break;
452     case SANE_ACTION_GET_VALUE:
453       *(SANE_Fixed *) value = optionBotRightYValue;
454       break;
455     }
456   return SANE_STATUS_GOOD;
457 }
458 
459 /*
460 The following array binds the option descriptors to
461 their respective callback routines
462 */
463 
464 static SANE_Option so[] = {
465   {&optionNumOptionsDescriptor, optionNumOptionsCallback},
466   {&optionResolutionDescriptor, optionResolutionCallback},
467   {&optionGrayscaleDescriptor, optionGrayscaleCallback},
468   {&optionTopLeftXDescriptor, optionTopLeftXCallback},
469   {&optionTopLeftYDescriptor, optionTopLeftYCallback},
470   {&optionBotRightXDescriptor, optionBotRightXCallback},
471   {&optionBotRightYDescriptor, optionBotRightYCallback},
472   {&optionLampOffDescriptor, optionLampOffCallback}
473 };
474 
475 static SANE_Word
getNumberOfOptions(void)476 getNumberOfOptions (void)
477 {
478   return NELEMS (so);
479 }
480 
481 /*
482 This routine dispatches the control message to the appropriate
483 callback routine, it outght to be called by sane_control_option
484 after any driver specific validation.
485 */
486 static SANE_Status
dispatch_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * value,SANE_Int * info)487 dispatch_control_option (SANE_Handle handle, SANE_Int option,
488                          SANE_Action action, void *value, SANE_Int * info)
489 {
490   SANE_Option *op = so + option;
491   SANE_Int myinfo = 0;
492   SANE_Status status = SANE_STATUS_GOOD;
493 
494   if (option < 0 || option >= NELEMS (so))
495     return SANE_STATUS_INVAL;        /* Unknown option ... */
496 
497   if ((action == SANE_ACTION_SET_VALUE) &&
498       ((op->descriptor->cap & SANE_CAP_SOFT_SELECT) == 0))
499     return SANE_STATUS_INVAL;
500 
501   if ((action == SANE_ACTION_GET_VALUE) &&
502       ((op->descriptor->cap & SANE_CAP_SOFT_DETECT) == 0))
503     return SANE_STATUS_INVAL;
504 
505   if ((action == SANE_ACTION_SET_AUTO) &&
506       ((op->descriptor->cap & SANE_CAP_AUTOMATIC) == 0))
507     return SANE_STATUS_INVAL;
508 
509   if (action == SANE_ACTION_SET_VALUE)
510     {
511       status = sanei_constrain_value (op->descriptor, value, &myinfo);
512       if (status != SANE_STATUS_GOOD)
513         return status;
514     }
515 
516   status = (op->callback) (op, handle, action, value, &myinfo);
517 
518   if (info)
519     *info = myinfo;
520 
521   return status;
522 }
523 
524 static SANE_Status
attach_scanner(const char * devicename,Umax_Device ** devp)525 attach_scanner (const char *devicename, Umax_Device ** devp)
526 {
527   UMAX_Handle scan;
528   Umax_Device *dev;
529   SANE_Status status;
530 
531   DBG (3, "attach_scanner: %s\n", devicename);
532 
533   for (dev = first_dev; dev; dev = dev->next)
534     {
535       if (strcmp (dev->sane.name, devicename) == 0)
536         {
537           if (devp)
538             *devp = dev;
539           return SANE_STATUS_GOOD;
540         }
541     }
542 
543   dev = malloc (sizeof (*dev));
544   if (!dev)
545     return SANE_STATUS_NO_MEM;
546   memset (dev, '\0', sizeof (Umax_Device));        /* clear structure */
547 
548   DBG (4, "attach_scanner: opening %s\n", devicename);
549 
550   status = UMAX_open_device (&scan, devicename);
551   if (status != SANE_STATUS_GOOD)
552     {
553       DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename);
554       free (dev);
555       return status;
556     }
557   dev->name = strdup (devicename);
558   dev->sane.name = dev->name;
559   dev->sane.vendor = "UMAX";
560   dev->sane.model = UMAX_get_device_name (&scan);
561   dev->sane.type = "flatbed scanner";
562   UMAX_close_device (&scan);
563 
564   ++num_devices;
565   dev->next = first_dev;
566   first_dev = dev;
567 
568   if (devp)
569     *devp = dev;
570   return SANE_STATUS_GOOD;
571 }
572 
573 /* callback function for sanei_usb_attach_matching_devices
574 */
575 static SANE_Status
attach_one(const char * name)576 attach_one (const char *name)
577 {
578   attach_scanner (name, 0);
579   return SANE_STATUS_GOOD;
580 }
581 
582 /* This file implements a SANE backend for the UMAX Astra 1220U scanner.
583  */
584 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)585 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
586 {
587   char config_line[PATH_MAX];
588   size_t len;
589   FILE *fp;
590 
591   DBG_INIT ();
592 
593   DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
594        version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
595   DBG (1, "sane_init: SANE umax1220u backend version %d.%d.%d from %s\n",
596        SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING);
597 
598   if (version_code)
599     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
600 
601   sanei_usb_init ();
602   sanei_pv8630_init ();
603 
604   fp = sanei_config_open (UMAX_CONFIG_FILE);
605   if (!fp)
606     {
607       /* no config-file: try /dev/scanner and /dev/usbscanner. */
608       attach_scanner ("/dev/scanner", 0);
609       attach_scanner ("/dev/usbscanner", 0);
610       return SANE_STATUS_GOOD;
611     }
612 
613   DBG (3, "reading configure file %s\n", UMAX_CONFIG_FILE);
614 
615   while (sanei_config_read (config_line, sizeof (config_line), fp))
616     {
617       if (config_line[0] == '#')
618         continue;                /* ignore line comments */
619 
620       len = strlen (config_line);
621 
622       if (!len)
623         continue;                /* ignore empty lines */
624 
625       DBG (4, "attach_matching_devices(%s)\n", config_line);
626       sanei_usb_attach_matching_devices (config_line, attach_one);
627     }
628 
629   DBG (4, "finished reading configure file\n");
630 
631   fclose (fp);
632 
633   return SANE_STATUS_GOOD;
634 }
635 
636 void
sane_exit(void)637 sane_exit (void)
638 {
639   Umax_Device *dev, *next;
640 
641   DBG (3, "sane_exit\n");
642 
643   for (dev = first_dev; dev; dev = next)
644     {
645       next = dev->next;
646       free (dev->name);
647       free (dev);
648     }
649 
650   if (devlist)
651     free (devlist);
652   return;
653 }
654 
655 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)656 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
657 {
658   Umax_Device *dev;
659   int i;
660 
661   DBG (3, "sane_get_devices(local_only = %d)\n", local_only);
662 
663   if (devlist)
664     free (devlist);
665 
666   devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
667   if (!devlist)
668     return SANE_STATUS_NO_MEM;
669 
670   i = 0;
671 
672   for (dev = first_dev; i < num_devices; dev = dev->next)
673     devlist[i++] = &dev->sane;
674 
675   devlist[i++] = 0;
676 
677   *device_list = devlist;
678 
679   return SANE_STATUS_GOOD;
680 }
681 
682 SANE_Status
sane_open(SANE_String_Const devicename,SANE_Handle * handle)683 sane_open (SANE_String_Const devicename, SANE_Handle * handle)
684 {
685   Umax_Device *dev;
686   SANE_Status status;
687   Umax_Scanner *scanner;
688 
689   DBG (3, "sane_open\n");
690 
691   if (devicename[0])                /* search for devicename */
692     {
693       DBG (4, "sane_open: devicename=%s\n", devicename);
694 
695       for (dev = first_dev; dev; dev = dev->next)
696           if (strcmp (dev->sane.name, devicename) == 0)
697             break;
698 
699       if (!dev)
700         {
701           status = attach_scanner (devicename, &dev);
702           if (status != SANE_STATUS_GOOD)
703             return status;
704         }
705     }
706   else
707     {
708       DBG (2, "sane_open: no devicename, opening first device\n");
709       dev = first_dev;
710     }
711 
712   if (!dev)
713     return SANE_STATUS_INVAL;
714 
715   scanner = malloc (sizeof (*scanner));
716   if (!scanner)
717     return SANE_STATUS_NO_MEM;
718 
719   memset (scanner, 0, sizeof (*scanner));
720   scanner->device = dev;
721 
722   status = UMAX_open_device (&scanner->scan, dev->sane.name);
723   if (status != SANE_STATUS_GOOD)
724     {
725       free (scanner);
726       return status;
727     }
728 
729   *handle = scanner;
730 
731   /* insert newly opened handle into list of open handles: */
732   scanner->next = first_handle;
733 
734   first_handle = scanner;
735 
736   return SANE_STATUS_GOOD;
737 }
738 
739 void
sane_close(SANE_Handle handle)740 sane_close (SANE_Handle handle)
741 {
742   Umax_Scanner *prev, *scanner;
743 
744   DBG (3, "sane_close\n");
745 
746   if (!first_handle)
747     {
748       DBG (1, "ERROR: sane_close: no handles opened\n");
749       return;
750     }
751 
752   /* remove handle from list of open handles: */
753 
754   prev = NULL;
755 
756   for (scanner = first_handle; scanner; scanner = scanner->next)
757     {
758       if (scanner == handle)
759         break;
760 
761       prev = scanner;
762     }
763 
764   if (!scanner)
765     {
766       DBG (1, "ERROR: sane_close: invalid handle %p\n", handle);
767       return;                        /* oops, not a handle we know about */
768     }
769 
770   if (prev)
771     prev->next = scanner->next;
772   else
773     first_handle = scanner->next;
774 
775   UMAX_close_device (&scanner->scan);
776 
777   free (scanner);
778 }
779 
780 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)781 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
782 {
783   handle = handle;                /* Eliminate compiler warning */
784 
785   DBG (3, "sane_get_option_descriptor: option = %d\n", option);
786   if (option < 0 || option >= NELEMS (so))
787     return NULL;
788   return so[option].descriptor;
789 }
790 
791 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * value,SANE_Int * info)792 sane_control_option (SANE_Handle handle, SANE_Int option,
793                      SANE_Action action, void *value, SANE_Int * info)
794 {
795   handle = handle;                /* Eliminate compiler warning */
796 
797   DBG (3,
798        "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
799        handle, option, action, value, (void*) info);
800 
801   return dispatch_control_option (handle, option, action, value, info);
802 }
803 
804 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)805 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
806 {
807   int rc = SANE_STATUS_GOOD;
808   int w =
809     SANE_UNFIX (optionBotRightXValue -
810                 optionTopLeftXValue) / MM_IN_INCH * optionResolutionValue;
811   int h =
812     SANE_UNFIX (optionBotRightYValue -
813                 optionTopLeftYValue) / MM_IN_INCH * optionResolutionValue;
814 
815   handle = handle;                /* Eliminate compiler warning */
816 
817   DBG (3, "sane_get_parameters\n");
818   parms.depth = 8;
819   parms.last_frame = SANE_TRUE;
820   parms.pixels_per_line = w;
821   parms.lines = h;
822 
823   if (optionGrayscaleValue == SANE_TRUE)
824     {
825       parms.format = SANE_FRAME_GRAY;
826       parms.bytes_per_line = w;
827     }
828   else
829     {
830       parms.format = SANE_FRAME_RGB;
831       parms.bytes_per_line = w * 3;
832     }
833   *params = parms;
834   return rc;
835 }
836 
837 SANE_Status
sane_start(SANE_Handle handle)838 sane_start (SANE_Handle handle)
839 {
840   Umax_Scanner *scanner = handle;
841   SANE_Status res;
842 
843   DBG (3, "sane_start\n");
844 
845   res = UMAX_set_scan_parameters (&scanner->scan,
846                                   optionGrayscaleValue == SANE_FALSE,
847                                   SANE_UNFIX (optionTopLeftXValue) /
848                                   MM_IN_INCH * 600,
849                                   SANE_UNFIX (optionTopLeftYValue) /
850                                   MM_IN_INCH * 600,
851                                   SANE_UNFIX (optionBotRightXValue -
852                                               optionTopLeftXValue) /
853                                   MM_IN_INCH * optionResolutionValue,
854                                   SANE_UNFIX (optionBotRightYValue -
855                                               optionTopLeftYValue) /
856                                   MM_IN_INCH * optionResolutionValue,
857                                   optionResolutionValue,
858                                   optionResolutionValue);
859 
860   if (res != SANE_STATUS_GOOD)
861     return res;
862 
863   if (scanner->scan.model == ASTRA_1220U)
864      return UMAX_start_scan (&scanner->scan);
865   else
866      return UMAX_start_scan_2100U (&scanner->scan);
867 }
868 
869 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * data,SANE_Int max_length,SANE_Int * length)870 sane_read (SANE_Handle handle, SANE_Byte * data,
871            SANE_Int max_length, SANE_Int * length)
872 {
873   Umax_Scanner *scanner = handle;
874   SANE_Status res;
875   int len;
876   unsigned char rgb[3];
877 
878   len = *length = 0;
879 
880   if (!data || !length)
881     return SANE_STATUS_INVAL;
882 
883   if (scanner->scan.done)
884     {
885       res = UMAX_finish_scan (&scanner->scan);
886 
887       if (scanner->scan.model == ASTRA_1220U)
888         res = UMAX_park_head (&scanner->scan);
889       else
890         res = UMAX_park_head_2100U (&scanner->scan);
891 
892       return SANE_STATUS_EOF;
893     }
894 
895   DBG (3, "sane_read: max_length = %d\n", max_length);
896 
897   if (optionGrayscaleValue == SANE_FALSE)
898     {
899       while (!scanner->scan.done && (max_length >= 3))
900         {
901           res = UMAX_get_rgb (&scanner->scan, rgb);
902           if (res != SANE_STATUS_GOOD)
903             {
904               *length = 0;
905               return res;
906             }
907           *data++ = rgb[0];
908           *data++ = rgb[1];
909           *data++ = rgb[2];
910           max_length -= 3;
911           len += 3;
912         }
913     }
914   else
915     {
916       while (!scanner->scan.done && max_length)
917         {
918           res = UMAX_get_rgb (&scanner->scan, rgb);
919           if (res != SANE_STATUS_GOOD)
920             {
921               *length = 0;
922               return res;
923             }
924           *data++ = rgb[0];
925           max_length--;
926           len++;
927         }
928     }
929 
930   *length = len;
931   return SANE_STATUS_GOOD;
932 }
933 
934 void
sane_cancel(SANE_Handle handle)935 sane_cancel (SANE_Handle handle)
936 {
937   DBG (3, "sane_cancel: handle = %p\n", handle);
938   DBG (3, "sane_cancel: canceling is unsupported in this backend\n");
939 }
940 
941 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)942 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
943 {
944   DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
945        non_blocking);
946   if (non_blocking != SANE_FALSE)
947     return SANE_STATUS_UNSUPPORTED;
948   return SANE_STATUS_GOOD;
949 }
950 
951 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)952 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
953 {
954   DBG (3, "sane_get_select_fd: handle = %p, fd %s 0\n", handle,
955        fd ? "!=" : "=");
956   return SANE_STATUS_UNSUPPORTED;
957 }
958