• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2001-2012 Stéphane Voltz <stef.dev@free.fr>
3    This file is part of the SANE package.
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 
18    As a special exception, the authors of SANE give permission for
19    additional uses of the libraries contained in this release of SANE.
20 
21    The exception is that, if you link a SANE library with other files
22    to produce an executable, this does not by itself cause the
23    resulting executable to be covered by the GNU General Public
24    License.  Your use of that executable is in no way restricted on
25    account of linking the SANE library code into it.
26 
27    This exception does not, however, invalidate any other reasons why
28    the executable file might be covered by the GNU General Public
29    License.
30 
31    If you submit changes to SANE to the maintainers to be included in
32    a subsequent release, you agree by submitting the changes that
33    those changes may be distributed with this exception intact.
34 
35    If you write modifications of your own for SANE, it is your choice
36    whether to permit this exception to apply to your modifications.
37    If you do not wish that, delete this exception notice.
38 
39    This file implements a SANE backend for Umax PP flatbed scanners.  */
40 
41 /* CREDITS:
42    Started by being a mere copy of mustek_pp
43    by Jochen Eisinger <jochen.eisinger@gmx.net>
44    then evolved in its own thing
45 
46    support for the 610P has been made possible thank to an hardware donation
47    from William Stuart
48    */
49 
50 
51 #include "../include/sane/config.h"
52 
53 #include <ctype.h>
54 #include <errno.h>
55 #include <limits.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #include <math.h>
63 
64 #ifdef HAVE_SYS_TIME_H
65 #include <sys/time.h>
66 #endif
67 #ifdef HAVE_SYS_TYPES_H
68 #include <sys/types.h>
69 #endif
70 
71 #define DEBUG_NOT_STATIC
72 
73 #include "../include/sane/sane.h"
74 #include "../include/sane/sanei.h"
75 #include "../include/sane/saneopts.h"
76 #include "../include/sane/sanei_config.h"
77 
78 #define BACKEND_NAME    umax_pp
79 #include "../include/sane/sanei_backend.h"
80 
81 #include "umax_pp_mid.h"
82 #include "umax_pp.h"
83 
84 #ifdef DMALLOC
85 #include "dmalloc.h"
86 #endif
87 
88 #define UMAX_PP_CONFIG_FILE "umax_pp.conf"
89 
90 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
91 
92 
93 /* DEBUG
94  *      for debug output, set SANE_DEBUG_UMAX_PP to
95  *              0       for nothing
96  *              1       for errors
97  *              2       for warnings
98  *              3       for additional information
99  *              4       for debug information
100  *              5       for code flow protocol (there isn't any)
101  *              129     if you want to know which parameters are unused
102  */
103 
104 #define UMAX_PP_BUILD   2301
105 #define UMAX_PP_STATE   "release"
106 
107 static int num_devices = 0;
108 static Umax_PP_Descriptor *devlist = NULL;
109 static const SANE_Device **devarray = NULL;
110 
111 static Umax_PP_Device *first_dev = NULL;
112 
113 
114 /* 2 Meg scan buffer */
115 static SANE_Word buf_size = 2048 * 1024;
116 
117 static SANE_Word red_gain = 0;
118 static SANE_Word green_gain = 0;
119 static SANE_Word blue_gain = 0;
120 
121 static SANE_Word red_offset = 0;
122 static SANE_Word green_offset = 0;
123 static SANE_Word blue_offset = 0;
124 static SANE_Char scanner_vendor[128]="";
125 static SANE_Char scanner_name[128]="";
126 static SANE_Char scanner_model[128]="";
127 static SANE_Char astra[128];
128 
129 
130 
131 static const SANE_String_Const mode_list[] = {
132   SANE_VALUE_SCAN_MODE_LINEART,
133   SANE_VALUE_SCAN_MODE_GRAY,
134   SANE_VALUE_SCAN_MODE_COLOR,
135   0
136 };
137 
138 static const SANE_Range u4_range = {
139   0,                            /* minimum */
140   15,                           /* maximum */
141   0                             /* quantization */
142 };
143 
144 static const SANE_Range u8_range = {
145   0,                            /* minimum */
146   255,                          /* maximum */
147   0                             /* quantization */
148 };
149 
150 /* range for int value in [0-15] */
151 static const SANE_Range value16_range = {
152   0,                            /* minimum */
153   15,                           /* maximum */
154   1                             /* quantization */
155 };
156 
157 /* range for buffer size */
158 static const SANE_Range buffer_range = {
159   2048,                         /* minimum */
160   4096 * 4096,                  /* maximum */
161   1                             /* quantization */
162 };
163 
164 /* list of astra models */
165 static const SANE_String_Const astra_models[] =
166   { "610", "1220", "1600", "2000", NULL };
167 
168 
169 #define UMAX_PP_CHANNEL_RED             0
170 #define UMAX_PP_CHANNEL_GREEN           1
171 #define UMAX_PP_CHANNEL_BLUE            2
172 #define UMAX_PP_CHANNEL_GRAY            1
173 
174 #define UMAX_PP_STATE_SCANNING          2
175 #define UMAX_PP_STATE_CANCELLED         1
176 #define UMAX_PP_STATE_IDLE              0
177 
178 #define UMAX_PP_MODE_LINEART            0
179 #define UMAX_PP_MODE_GRAYSCALE          1
180 #define UMAX_PP_MODE_COLOR              2
181 
182 #define MM_TO_PIXEL(mm, res)    (SANE_UNFIX(mm) * (float )res / MM_PER_INCH)
183 #define PIXEL_TO_MM(px, res)    (SANE_FIX((float )(px * MM_PER_INCH / (res / 10)) / 10.0))
184 
185 #define UMAX_PP_DEFAULT_PORT            "/dev/parport0"
186 
187 #define UMAX_PP_RESERVE                 259200
188 
189 /*
190  * devname may be either an hardware address for direct I/O (0x378 for instance)
191  * or the device name used by ppdev on linux systems        (/dev/parport0 )
192  */
193 
194 
195 static SANE_Status
umax_pp_attach(SANEI_Config * config,const char * devname)196 umax_pp_attach (SANEI_Config * config, const char *devname)
197 {
198   Umax_PP_Descriptor *dev;
199   int i;
200   SANE_Status status = SANE_STATUS_GOOD;
201   int ret, prt = 0, mdl;
202   char model[32];
203   const char *name = NULL;
204   const char *val;
205 
206   if (!devname || (strlen (devname) < 3))
207     return SANE_STATUS_INVAL;
208 
209   sanei_umax_pp_setastra (atoi((SANE_Char *) config->values[CFG_ASTRA]));
210 
211   /* if the name begins with a slash, it's a device, else it's an addr */
212   if ((devname[0] == '/'))
213     {
214       name = devname;
215     }
216   else
217     {
218       if ((devname[0] == '0')
219           && ((devname[1] == 'x') || (devname[1] == 'X')))
220         prt = strtol (devname + 2, NULL, 16);
221       else
222         prt = atoi (devname);
223     }
224 
225   for (i = 0; i < num_devices; i++)
226     {
227       if (devname[0] == '/')
228         {
229           if (strcmp (devlist[i].ppdevice, devname) == 0)
230             return SANE_STATUS_GOOD;
231         }
232       else
233         {
234           if (strcmp (devlist[i].port, devname) == 0)
235             return SANE_STATUS_GOOD;
236         }
237     }
238 
239   ret = sanei_umax_pp_attach (prt, name);
240   switch (ret)
241     {
242     case UMAX1220P_OK:
243       status = SANE_STATUS_GOOD;
244       break;
245     case UMAX1220P_BUSY:
246       status = SANE_STATUS_DEVICE_BUSY;
247       break;
248     case UMAX1220P_TRANSPORT_FAILED:
249       DBG (1, "umax_pp_attach: failed to init transport layer on %s\n",
250            devname);
251       status = SANE_STATUS_IO_ERROR;
252       break;
253     case UMAX1220P_PROBE_FAILED:
254       DBG (1, "umax_pp_attach: failed to probe scanner on %s\n", devname);
255       status = SANE_STATUS_IO_ERROR;
256       break;
257     }
258 
259   if (status != SANE_STATUS_GOOD)
260     {
261       DBG (2, "umax_pp_attach: couldn't attach to `%s' (%s)\n", devname,
262            sane_strstatus (status));
263       DEBUG ();
264       return status;
265     }
266 
267 
268   /* now look for the model */
269   do
270     {
271       ret = sanei_umax_pp_model (prt, &mdl);
272       if (ret != UMAX1220P_OK)
273         {
274           DBG (1, "umax_pp_attach: waiting for busy scanner on %s\n",
275                devname);
276         }
277     }
278   while (ret == UMAX1220P_BUSY);
279 
280   if (ret != UMAX1220P_OK)
281     {
282       DBG (1, "umax_pp_attach: failed to recognize scanner model on %s\n",
283            devname);
284       return SANE_STATUS_IO_ERROR;
285     }
286   snprintf (model, sizeof(model), "Astra %dP", mdl);
287 
288 
289   dev = malloc (sizeof (Umax_PP_Descriptor) * (num_devices + 1));
290 
291   if (dev == NULL)
292     {
293       DBG (2, "umax_pp_attach: not enough memory for device descriptor\n");
294       DEBUG ();
295       return SANE_STATUS_NO_MEM;
296     }
297 
298   memset (dev, 0, sizeof (Umax_PP_Descriptor) * (num_devices + 1));
299 
300   if (num_devices > 0)
301     {
302       memcpy (dev + 1, devlist, sizeof (Umax_PP_Descriptor) * (num_devices));
303       free (devlist);
304     }
305 
306   devlist = dev;
307   num_devices++;
308 
309   /* if there are user provided values, use them */
310   val=(const SANE_Char *) config->values[CFG_NAME];
311   if(strlen(val)==0)
312         dev->sane.name = strdup (devname);
313   else
314         dev->sane.name = strdup (val);
315   val=(const SANE_Char *) config->values[CFG_VENDOR];
316   if(strlen(val)==0)
317         dev->sane.vendor = strdup ("UMAX");
318   else
319         dev->sane.vendor = strdup (val);
320   dev->sane.type = "flatbed scanner";
321 
322   if (devname[0] == '/')
323     dev->ppdevice = strdup (devname);
324   else
325     dev->port = strdup (devname);
326   dev->buf_size = buf_size;
327 
328   if (mdl > 610)
329     {                           /* Astra 1220, 1600 and 2000 */
330       dev->max_res = 1200;
331       dev->ccd_res = 600;
332       dev->max_h_size = 5100;
333       dev->max_v_size = 7000 - 8;       /* -8: workaround 'y overflow bug at 600 dpi' */
334     }
335   else
336     {                           /* Astra 610 */
337       dev->max_res = 600;
338       dev->ccd_res = 300;
339       dev->max_h_size = 2550;
340       dev->max_v_size = 3500;
341     }
342   val=(const SANE_Char *) config->values[CFG_MODEL];
343   if(strlen(val)==0)
344     dev->sane.model = strdup (model);
345   else
346     dev->sane.model = strdup (val);
347 
348 
349   DBG (3, "umax_pp_attach: device %s attached\n", devname);
350 
351   return SANE_STATUS_GOOD;
352 }
353 
354 /*
355  * walk a port list and try to attach to them
356  *
357  */
358 static SANE_Int
umax_pp_try_ports(SANEI_Config * config,char ** ports)359 umax_pp_try_ports (SANEI_Config * config, char **ports)
360 {
361   int i;
362   int rc = SANE_STATUS_INVAL;
363 
364   if (ports != NULL)
365     {
366       i = 0;
367       rc = SANE_STATUS_INVAL;
368       while (ports[i] != NULL)
369         {
370           if (rc != SANE_STATUS_GOOD)
371             {
372               DBG (3, "umax_pp_try_ports: trying port `%s'\n", ports[i]);
373               rc = umax_pp_attach (config, ports[i]);
374               if (rc != SANE_STATUS_GOOD)
375                 DBG (3, "umax_pp_try_ports: couldn't attach to port `%s'\n",
376                      ports[i]);
377               else
378                 DBG (3,
379                      "umax_pp_try_ports: attach to port `%s' successful\n",
380                      ports[i]);
381             }
382           free (ports[i]);
383           i++;
384         }
385       free (ports);
386     }
387   return rc;
388 }
389 
390 /*
391  * attempt to auto detect right parallel port
392  * if safe set to SANE_TRUE, no direct hardware access
393  * is tried
394  */
395 static SANE_Int
umax_pp_auto_attach(SANEI_Config * config,SANE_Int safe)396 umax_pp_auto_attach (SANEI_Config * config, SANE_Int safe)
397 {
398   char **ports;
399   int rc = SANE_STATUS_INVAL;
400 
401   /* safe tests: user parallel port devices */
402   ports = sanei_parport_find_device ();
403   if (ports != NULL)
404     rc = umax_pp_try_ports (config, ports);
405 
406   /* try for direct hardware access */
407   if ((safe != SANE_TRUE) && (rc != SANE_STATUS_GOOD))
408     {
409       ports = sanei_parport_find_port ();
410       if (ports != NULL)
411         rc = umax_pp_try_ports (config, ports);
412     }
413   return rc;
414 }
415 
416 /** callback use by sanei_configure_attach, it is called with the
417  * device name to use for attach try.
418  */
419 static SANE_Status
umax_pp_configure_attach(SANEI_Config * config,const char * devname,void __sane_unused__ * data)420 umax_pp_configure_attach (SANEI_Config * config, const char *devname,
421                           void __sane_unused__ *data)
422 {
423   const char *lp;
424   SANE_Char *token;
425   SANE_Status status = SANE_STATUS_INVAL;
426 
427   /* check for mandatory 'port' token */
428   lp = sanei_config_get_string (devname, &token);
429   if (strncmp (token, "port", 4) != 0)
430     {
431       DBG (3, "umax_pp_configure_attach: invalid port line `%s'\n", devname);
432       free (token);
433       return SANE_STATUS_INVAL;
434     }
435   free (token);
436 
437   /* get argument */
438   lp = sanei_config_get_string (lp, &token);
439 
440   /* if "safe-auto" or "auto" devname, use umax_pp_attach_auto */
441   if (strncmp (token, "safe-auto", 9) == 0)
442     {
443       status = umax_pp_auto_attach (config, SANE_TRUE);
444     }
445   else if (strncmp (token, "auto", 4) == 0)
446     {
447       status = umax_pp_auto_attach (config, SANE_FALSE);
448     }
449   else
450     {
451       status = umax_pp_attach (config, token);
452     }
453   free (token);
454   return status;
455 }
456 
457 static SANE_Int
umax_pp_get_sync(SANE_Int dpi)458 umax_pp_get_sync (SANE_Int dpi)
459 {
460   /* delta between color frames */
461   if (sanei_umax_pp_getastra () > 610)
462     {
463       switch (dpi)
464         {
465         case 1200:
466           return 8;
467         case 600:
468           return 4;
469         case 300:
470           return 2;
471         case 150:
472           return 1;
473         default:
474           return 0;
475         }
476     }
477   else
478     {
479       switch (dpi)
480         {
481         case 600:
482           return 16;
483         case 300:
484           return 8;             /* 8 double-checked */
485         case 150:
486           /* wrong: 2, 3, 5
487            * double-checked : 4
488            */
489           return 4;
490         default:
491           return 2;             /* 2 double-checked */
492         }
493     }
494 }
495 
496 
497 static SANE_Status
init_options(Umax_PP_Device * dev)498 init_options (Umax_PP_Device * dev)
499 {
500   int i;
501 
502   /* sets initial option value to zero */
503   memset (dev->opt, 0, sizeof (dev->opt));
504   memset (dev->val, 0, sizeof (dev->val));
505 
506   for (i = 0; i < NUM_OPTIONS; ++i)
507     {
508       dev->opt[i].size = sizeof (SANE_Word);
509       dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
510     }
511 
512   dev->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
513   dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
514   dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
515   dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
516   dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
517   dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
518 
519   /* "Mode" group: */
520 
521   dev->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE;
522   dev->opt[OPT_MODE_GROUP].name = "";
523   dev->opt[OPT_MODE_GROUP].desc = "";
524   dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
525   dev->opt[OPT_MODE_GROUP].size = 0;
526   dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
527 
528   /* scan mode */
529   dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
530   dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
531   dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
532   dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
533   dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
534   dev->opt[OPT_MODE].size = 10;
535   dev->opt[OPT_MODE].constraint.string_list = mode_list;
536   dev->val[OPT_MODE].s = strdup (mode_list[1]);
537 
538   /* resolution */
539   dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
540   dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
541   dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
542   dev->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
543   dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
544   dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
545   dev->opt[OPT_RESOLUTION].constraint.range = &dev->dpi_range;
546   dev->val[OPT_RESOLUTION].w = dev->dpi_range.min;
547 
548 
549   /* preview */
550   dev->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
551   dev->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
552   dev->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
553   dev->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
554   dev->opt[OPT_PREVIEW].size = sizeof (SANE_Word);
555   dev->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE;
556   dev->val[OPT_PREVIEW].w = SANE_FALSE;
557 
558   /* gray preview */
559   dev->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
560   dev->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
561   dev->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
562   dev->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
563   dev->opt[OPT_GRAY_PREVIEW].size = sizeof (SANE_Word);
564   dev->opt[OPT_GRAY_PREVIEW].unit = SANE_UNIT_NONE;
565   dev->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
566 
567   /* "Geometry" group: */
568 
569   dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
570   dev->opt[OPT_GEOMETRY_GROUP].desc = "";
571   dev->opt[OPT_GEOMETRY_GROUP].name = "";
572   dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
573   dev->opt[OPT_GEOMETRY_GROUP].size = 0;
574   dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
575 
576   /* top-left x */
577   dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
578   dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
579   dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
580   dev->opt[OPT_TL_X].type = SANE_TYPE_INT;
581   dev->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
582   dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
583   dev->opt[OPT_TL_X].constraint.range = &dev->x_range;
584   dev->val[OPT_TL_X].w = 0;
585 
586   /* top-left y */
587   dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
588   dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
589   dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
590   dev->opt[OPT_TL_Y].type = SANE_TYPE_INT;
591   dev->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
592   dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
593   dev->opt[OPT_TL_Y].constraint.range = &dev->y_range;
594   dev->val[OPT_TL_Y].w = 0;
595 
596   /* bottom-right x */
597   dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
598   dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
599   dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
600   dev->opt[OPT_BR_X].type = SANE_TYPE_INT;
601   dev->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
602   dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
603   dev->opt[OPT_BR_X].constraint.range = &dev->x_range;
604   dev->val[OPT_BR_X].w = dev->x_range.max;
605 
606   /* bottom-right y */
607   dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
608   dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
609   dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
610   dev->opt[OPT_BR_Y].type = SANE_TYPE_INT;
611   dev->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
612   dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
613   dev->opt[OPT_BR_Y].constraint.range = &dev->y_range;
614   dev->val[OPT_BR_Y].w = dev->y_range.max;
615 
616   /* "Enhancement" group: */
617 
618   dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
619   dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";
620   dev->opt[OPT_ENHANCEMENT_GROUP].name = "";
621   dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
622   dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
623   dev->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_ADVANCED;
624   dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
625 
626   /* lamp control */
627   dev->opt[OPT_LAMP_CONTROL].name = "lamp-control";
628   dev->opt[OPT_LAMP_CONTROL].title = SANE_I18N ("Lamp on");
629   dev->opt[OPT_LAMP_CONTROL].desc = SANE_I18N ("Sets lamp on/off");
630   dev->opt[OPT_LAMP_CONTROL].type = SANE_TYPE_BOOL;
631   dev->opt[OPT_LAMP_CONTROL].size = sizeof (SANE_Word);
632   dev->opt[OPT_LAMP_CONTROL].unit = SANE_UNIT_NONE;
633   dev->val[OPT_LAMP_CONTROL].w = SANE_TRUE;
634   dev->opt[OPT_LAMP_CONTROL].cap |= SANE_CAP_ADVANCED;
635 
636   /* UTA control */
637   dev->opt[OPT_UTA_CONTROL].name = "UTA-control";
638   dev->opt[OPT_UTA_CONTROL].title = SANE_I18N ("UTA on");
639   dev->opt[OPT_UTA_CONTROL].desc = SANE_I18N ("Sets UTA on/off");
640   dev->opt[OPT_UTA_CONTROL].type = SANE_TYPE_BOOL;
641   dev->opt[OPT_UTA_CONTROL].size = sizeof (SANE_Word);
642   dev->opt[OPT_UTA_CONTROL].unit = SANE_UNIT_NONE;
643   dev->val[OPT_UTA_CONTROL].w = SANE_TRUE;
644   dev->opt[OPT_UTA_CONTROL].cap |= SANE_CAP_ADVANCED | SANE_CAP_INACTIVE;
645 
646   /* custom-gamma table */
647   dev->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
648   dev->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
649   dev->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
650   dev->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
651   dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED;
652   dev->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
653 
654   /* grayscale gamma vector */
655   dev->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
656   dev->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
657   dev->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
658   dev->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
659   dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
660   dev->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
661   dev->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
662   dev->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
663   dev->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
664   dev->val[OPT_GAMMA_VECTOR].wa = &dev->gamma_table[0][0];
665 
666   /* red gamma vector */
667   dev->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
668   dev->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
669   dev->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
670   dev->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
671   dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
672   dev->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
673   dev->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
674   dev->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
675   dev->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
676   dev->val[OPT_GAMMA_VECTOR_R].wa = &dev->gamma_table[1][0];
677 
678   /* green gamma vector */
679   dev->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
680   dev->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
681   dev->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
682   dev->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
683   dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
684   dev->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
685   dev->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
686   dev->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
687   dev->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
688   dev->val[OPT_GAMMA_VECTOR_G].wa = &dev->gamma_table[2][0];
689 
690   /* blue gamma vector */
691   dev->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
692   dev->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
693   dev->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
694   dev->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
695   dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
696   dev->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
697   dev->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
698   dev->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
699   dev->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
700   dev->val[OPT_GAMMA_VECTOR_B].wa = &dev->gamma_table[3][0];
701 
702   /*  gain group */
703   dev->opt[OPT_MANUAL_GAIN].name = "manual-channel-gain";
704   dev->opt[OPT_MANUAL_GAIN].title = SANE_I18N ("Gain");
705   dev->opt[OPT_MANUAL_GAIN].desc = SANE_I18N ("Color channels gain settings");
706   dev->opt[OPT_MANUAL_GAIN].type = SANE_TYPE_BOOL;
707   dev->opt[OPT_MANUAL_GAIN].cap |= SANE_CAP_ADVANCED;
708   dev->val[OPT_MANUAL_GAIN].w = SANE_FALSE;
709 
710   /* gray gain */
711   dev->opt[OPT_GRAY_GAIN].name = "gray-gain";
712   dev->opt[OPT_GRAY_GAIN].title = SANE_I18N ("Gray gain");
713   dev->opt[OPT_GRAY_GAIN].desc = SANE_I18N ("Sets gray channel gain");
714   dev->opt[OPT_GRAY_GAIN].type = SANE_TYPE_INT;
715   dev->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
716   dev->opt[OPT_GRAY_GAIN].unit = SANE_UNIT_NONE;
717   dev->opt[OPT_GRAY_GAIN].size = sizeof (SANE_Int);
718   dev->opt[OPT_GRAY_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
719   dev->opt[OPT_GRAY_GAIN].constraint.range = &u4_range;
720   dev->val[OPT_GRAY_GAIN].w = dev->gray_gain;
721 
722   /* red gain */
723   dev->opt[OPT_RED_GAIN].name = "red-gain";
724   dev->opt[OPT_RED_GAIN].title = SANE_I18N ("Red gain");
725   dev->opt[OPT_RED_GAIN].desc = SANE_I18N ("Sets red channel gain");
726   dev->opt[OPT_RED_GAIN].type = SANE_TYPE_INT;
727   dev->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
728   dev->opt[OPT_RED_GAIN].unit = SANE_UNIT_NONE;
729   dev->opt[OPT_RED_GAIN].size = sizeof (SANE_Int);
730   dev->opt[OPT_RED_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
731   dev->opt[OPT_RED_GAIN].constraint.range = &u4_range;
732   dev->val[OPT_RED_GAIN].w = dev->red_gain;
733 
734   /* green gain */
735   dev->opt[OPT_GREEN_GAIN].name = "green-gain";
736   dev->opt[OPT_GREEN_GAIN].title = SANE_I18N ("Green gain");
737   dev->opt[OPT_GREEN_GAIN].desc = SANE_I18N ("Sets green channel gain");
738   dev->opt[OPT_GREEN_GAIN].type = SANE_TYPE_INT;
739   dev->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
740   dev->opt[OPT_GREEN_GAIN].unit = SANE_UNIT_NONE;
741   dev->opt[OPT_GREEN_GAIN].size = sizeof (SANE_Int);
742   dev->opt[OPT_GREEN_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
743   dev->opt[OPT_GREEN_GAIN].constraint.range = &u4_range;
744   dev->val[OPT_GREEN_GAIN].w = dev->green_gain;
745 
746   /* blue gain */
747   dev->opt[OPT_BLUE_GAIN].name = "blue-gain";
748   dev->opt[OPT_BLUE_GAIN].title = SANE_I18N ("Blue gain");
749   dev->opt[OPT_BLUE_GAIN].desc = SANE_I18N ("Sets blue channel gain");
750   dev->opt[OPT_BLUE_GAIN].type = SANE_TYPE_INT;
751   dev->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
752   dev->opt[OPT_BLUE_GAIN].unit = SANE_UNIT_NONE;
753   dev->opt[OPT_BLUE_GAIN].size = sizeof (SANE_Int);
754   dev->opt[OPT_BLUE_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
755   dev->opt[OPT_BLUE_GAIN].constraint.range = &u4_range;
756   dev->val[OPT_BLUE_GAIN].w = dev->blue_gain;
757 
758   /*  offset group */
759   dev->opt[OPT_MANUAL_OFFSET].name = "manual-offset";
760   dev->opt[OPT_MANUAL_OFFSET].title = SANE_I18N ("Offset");
761   dev->opt[OPT_MANUAL_OFFSET].desc =
762     SANE_I18N ("Color channels offset settings");
763   dev->opt[OPT_MANUAL_OFFSET].type = SANE_TYPE_BOOL;
764   dev->opt[OPT_MANUAL_OFFSET].cap |= SANE_CAP_ADVANCED;
765   dev->val[OPT_MANUAL_OFFSET].w = SANE_FALSE;
766 
767   /* gray offset */
768   dev->opt[OPT_GRAY_OFFSET].name = "gray-offset";
769   dev->opt[OPT_GRAY_OFFSET].title = SANE_I18N ("Gray offset");
770   dev->opt[OPT_GRAY_OFFSET].desc = SANE_I18N ("Sets gray channel offset");
771   dev->opt[OPT_GRAY_OFFSET].type = SANE_TYPE_INT;
772   dev->opt[OPT_GRAY_OFFSET].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
773   dev->opt[OPT_GRAY_OFFSET].unit = SANE_UNIT_NONE;
774   dev->opt[OPT_GRAY_OFFSET].size = sizeof (SANE_Int);
775   dev->opt[OPT_GRAY_OFFSET].constraint_type = SANE_CONSTRAINT_RANGE;
776   dev->opt[OPT_GRAY_OFFSET].constraint.range = &u4_range;
777   dev->val[OPT_GRAY_OFFSET].w = dev->gray_offset;
778 
779   /* red offset */
780   dev->opt[OPT_RED_OFFSET].name = "red-offset";
781   dev->opt[OPT_RED_OFFSET].title = SANE_I18N ("Red offset");
782   dev->opt[OPT_RED_OFFSET].desc = SANE_I18N ("Sets red channel offset");
783   dev->opt[OPT_RED_OFFSET].type = SANE_TYPE_INT;
784   dev->opt[OPT_RED_OFFSET].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
785   dev->opt[OPT_RED_OFFSET].unit = SANE_UNIT_NONE;
786   dev->opt[OPT_RED_OFFSET].size = sizeof (SANE_Int);
787   dev->opt[OPT_RED_OFFSET].constraint_type = SANE_CONSTRAINT_RANGE;
788   dev->opt[OPT_RED_OFFSET].constraint.range = &u4_range;
789   dev->val[OPT_RED_OFFSET].w = dev->red_offset;
790 
791   /* green offset */
792   dev->opt[OPT_GREEN_OFFSET].name = "green-offset";
793   dev->opt[OPT_GREEN_OFFSET].title = SANE_I18N ("Green offset");
794   dev->opt[OPT_GREEN_OFFSET].desc = SANE_I18N ("Sets green channel offset");
795   dev->opt[OPT_GREEN_OFFSET].type = SANE_TYPE_INT;
796   dev->opt[OPT_GREEN_OFFSET].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
797   dev->opt[OPT_GREEN_OFFSET].unit = SANE_UNIT_NONE;
798   dev->opt[OPT_GREEN_OFFSET].size = sizeof (SANE_Int);
799   dev->opt[OPT_GREEN_OFFSET].constraint_type = SANE_CONSTRAINT_RANGE;
800   dev->opt[OPT_GREEN_OFFSET].constraint.range = &u4_range;
801   dev->val[OPT_GREEN_OFFSET].w = dev->green_offset;
802 
803   /* blue offset */
804   dev->opt[OPT_BLUE_OFFSET].name = "blue-offset";
805   dev->opt[OPT_BLUE_OFFSET].title = SANE_I18N ("Blue offset");
806   dev->opt[OPT_BLUE_OFFSET].desc = SANE_I18N ("Sets blue channel offset");
807   dev->opt[OPT_BLUE_OFFSET].type = SANE_TYPE_INT;
808   dev->opt[OPT_BLUE_OFFSET].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED;
809   dev->opt[OPT_BLUE_OFFSET].unit = SANE_UNIT_NONE;
810   dev->opt[OPT_BLUE_OFFSET].size = sizeof (SANE_Int);
811   dev->opt[OPT_BLUE_OFFSET].constraint_type = SANE_CONSTRAINT_RANGE;
812   dev->opt[OPT_BLUE_OFFSET].constraint.range = &u4_range;
813   dev->val[OPT_BLUE_OFFSET].w = dev->blue_offset;
814 
815   return SANE_STATUS_GOOD;
816 }
817 
818 
819 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)820 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
821 {
822   SANE_Status status;
823   SANEI_Config config;
824   SANE_Option_Descriptor *options[NUM_CFG_OPTIONS];
825   void *values[NUM_CFG_OPTIONS];
826   int i = 0;
827 
828   DBG_INIT ();
829 
830   if (authorize != NULL)
831     {
832       DBG (2, "init: SANE_Auth_Callback not supported ...\n");
833     }
834 
835   if (version_code != NULL)
836     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, UMAX_PP_BUILD);
837 
838   DBG (3, "init: SANE v%s, backend v%d.%d.%d-%s\n", VERSION, SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR,
839        UMAX_PP_BUILD, UMAX_PP_STATE);
840 
841   /* set up configuration options to parse */
842   options[CFG_BUFFER] =
843     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
844   options[CFG_BUFFER]->name = "buffer";
845   options[CFG_BUFFER]->type = SANE_TYPE_INT;
846   options[CFG_BUFFER]->unit = SANE_UNIT_NONE;
847   options[CFG_BUFFER]->size = sizeof (SANE_Word);
848   options[CFG_BUFFER]->cap = SANE_CAP_SOFT_SELECT;
849   options[CFG_BUFFER]->constraint_type = SANE_CONSTRAINT_RANGE;
850   options[CFG_BUFFER]->constraint.range = &buffer_range;
851   values[CFG_BUFFER] = &buf_size;
852 
853   options[CFG_RED_GAIN] =
854     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
855   options[CFG_RED_GAIN]->name = "red-gain";
856   options[CFG_RED_GAIN]->type = SANE_TYPE_INT;
857   options[CFG_RED_GAIN]->unit = SANE_UNIT_NONE;
858   options[CFG_RED_GAIN]->size = sizeof (SANE_Word);
859   options[CFG_RED_GAIN]->cap = SANE_CAP_SOFT_SELECT;
860   options[CFG_RED_GAIN]->constraint_type = SANE_CONSTRAINT_RANGE;
861   options[CFG_RED_GAIN]->constraint.range = &value16_range;
862   values[CFG_RED_GAIN] = &red_gain;
863 
864   options[CFG_GREEN_GAIN] =
865     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
866   options[CFG_GREEN_GAIN]->name = "green-gain";
867   options[CFG_GREEN_GAIN]->type = SANE_TYPE_INT;
868   options[CFG_GREEN_GAIN]->unit = SANE_UNIT_NONE;
869   options[CFG_GREEN_GAIN]->size = sizeof (SANE_Word);
870   options[CFG_GREEN_GAIN]->cap = SANE_CAP_SOFT_SELECT;
871   options[CFG_GREEN_GAIN]->constraint_type = SANE_CONSTRAINT_RANGE;
872   options[CFG_GREEN_GAIN]->constraint.range = &value16_range;
873   values[CFG_GREEN_GAIN] = &green_gain;
874 
875   options[CFG_BLUE_GAIN] =
876     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
877   options[CFG_BLUE_GAIN]->name = "blue-gain";
878   options[CFG_BLUE_GAIN]->type = SANE_TYPE_INT;
879   options[CFG_BLUE_GAIN]->unit = SANE_UNIT_NONE;
880   options[CFG_BLUE_GAIN]->size = sizeof (SANE_Word);
881   options[CFG_BLUE_GAIN]->cap = SANE_CAP_SOFT_SELECT;
882   options[CFG_BLUE_GAIN]->constraint_type = SANE_CONSTRAINT_RANGE;
883   options[CFG_BLUE_GAIN]->constraint.range = &value16_range;
884   values[CFG_BLUE_GAIN] = &blue_gain;
885 
886   options[CFG_RED_OFFSET] =
887     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
888   options[CFG_RED_OFFSET]->name = "red-offset";
889   options[CFG_RED_OFFSET]->type = SANE_TYPE_INT;
890   options[CFG_RED_OFFSET]->unit = SANE_UNIT_NONE;
891   options[CFG_RED_OFFSET]->size = sizeof (SANE_Word);
892   options[CFG_RED_OFFSET]->cap = SANE_CAP_SOFT_SELECT;
893   options[CFG_RED_OFFSET]->constraint_type = SANE_CONSTRAINT_RANGE;
894   options[CFG_RED_OFFSET]->constraint.range = &value16_range;
895   values[CFG_RED_OFFSET] = &red_offset;
896 
897   options[CFG_GREEN_OFFSET] =
898     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
899   options[CFG_GREEN_OFFSET]->name = "green-offset";
900   options[CFG_GREEN_OFFSET]->type = SANE_TYPE_INT;
901   options[CFG_GREEN_OFFSET]->unit = SANE_UNIT_NONE;
902   options[CFG_GREEN_OFFSET]->size = sizeof (SANE_Word);
903   options[CFG_GREEN_OFFSET]->cap = SANE_CAP_SOFT_SELECT;
904   options[CFG_GREEN_OFFSET]->constraint_type = SANE_CONSTRAINT_RANGE;
905   options[CFG_GREEN_OFFSET]->constraint.range = &value16_range;
906   values[CFG_GREEN_OFFSET] = &green_offset;
907 
908   options[CFG_BLUE_OFFSET] =
909     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
910   options[CFG_BLUE_OFFSET]->name = "blue-offset";
911   options[CFG_BLUE_OFFSET]->type = SANE_TYPE_INT;
912   options[CFG_BLUE_OFFSET]->unit = SANE_UNIT_NONE;
913   options[CFG_BLUE_OFFSET]->size = sizeof (SANE_Word);
914   options[CFG_BLUE_OFFSET]->cap = SANE_CAP_SOFT_SELECT;
915   options[CFG_BLUE_OFFSET]->constraint_type = SANE_CONSTRAINT_RANGE;
916   options[CFG_BLUE_OFFSET]->constraint.range = &value16_range;
917   values[CFG_BLUE_OFFSET] = &blue_offset;
918 
919   options[CFG_VENDOR] =
920     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
921   options[CFG_VENDOR]->name = "vendor";
922   options[CFG_VENDOR]->type = SANE_TYPE_STRING;
923   options[CFG_VENDOR]->unit = SANE_UNIT_NONE;
924   options[CFG_VENDOR]->size = 128;
925   options[CFG_VENDOR]->cap = SANE_CAP_SOFT_SELECT;
926   values[CFG_VENDOR] = scanner_vendor;
927 
928   options[CFG_NAME] =
929     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
930   options[CFG_NAME]->name = "name";
931   options[CFG_NAME]->type = SANE_TYPE_STRING;
932   options[CFG_NAME]->unit = SANE_UNIT_NONE;
933   options[CFG_NAME]->size = 128;
934   options[CFG_NAME]->cap = SANE_CAP_SOFT_SELECT;
935   values[CFG_NAME] = scanner_name;
936 
937   options[CFG_MODEL] =
938     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
939   options[CFG_MODEL]->name = "model";
940   options[CFG_MODEL]->type = SANE_TYPE_STRING;
941   options[CFG_MODEL]->unit = SANE_UNIT_NONE;
942   options[CFG_MODEL]->size = 128;
943   options[CFG_MODEL]->cap = SANE_CAP_SOFT_SELECT;
944   values[CFG_MODEL] = scanner_model;
945 
946   options[CFG_ASTRA] =
947     (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
948   options[CFG_ASTRA]->name = "astra";
949   options[CFG_ASTRA]->type = SANE_TYPE_STRING;
950   options[CFG_ASTRA]->unit = SANE_UNIT_NONE;
951   options[CFG_ASTRA]->size = 128;
952   options[CFG_ASTRA]->cap = SANE_CAP_SOFT_SELECT;
953   options[CFG_ASTRA]->constraint_type = SANE_CONSTRAINT_STRING_LIST;
954   options[CFG_ASTRA]->constraint.string_list = astra_models;
955   values[CFG_ASTRA] = astra;
956 
957   config.descriptors = options;
958   config.values = values;
959   config.count = NUM_CFG_OPTIONS;
960 
961   /* generic configure and attach function */
962   status = sanei_configure_attach (UMAX_PP_CONFIG_FILE, &config,
963                                    umax_pp_configure_attach, NULL);
964 
965   /* free option descriptors */
966   for (i = 0; i < NUM_CFG_OPTIONS; i++)
967     {
968       free (options[i]);
969     }
970 
971   return status;
972 }
973 
974 void
sane_exit(void)975 sane_exit (void)
976 {
977   int i;
978   Umax_PP_Device *dev;
979 
980   DBG (3, "sane_exit: (...)\n");
981   if (first_dev)
982     DBG (3, "exit: closing open devices\n");
983 
984   while (first_dev)
985     {
986       dev = first_dev;
987       sane_close (dev);
988     }
989 
990   for (i = 0; i < num_devices; i++)
991     {
992       free (devlist[i].port);
993       free ((void *) devlist[i].sane.name);
994       free ((void *) devlist[i].sane.model);
995       free ((void *) devlist[i].sane.vendor);
996     }
997 
998   if (devlist != NULL)
999     {
1000       free (devlist);
1001       devlist = NULL;
1002     }
1003 
1004   if (devarray != NULL)
1005     {
1006       free (devarray);
1007       devarray = NULL;
1008     }
1009 
1010   /* reset values */
1011   num_devices = 0;
1012   first_dev = NULL;
1013 
1014   red_gain = 0;
1015   green_gain = 0;
1016   blue_gain = 0;
1017 
1018   red_offset = 0;
1019   green_offset = 0;
1020   blue_offset = 0;
1021 
1022 }
1023 
1024 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)1025 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1026 {
1027   int i;
1028 
1029   DBG (3, "get_devices\n");
1030   DBG (129, "unused arg: local_only = %d\n", (int) local_only);
1031 
1032   if (devarray != NULL)
1033     {
1034       free (devarray);
1035       devarray = NULL;
1036     }
1037 
1038   devarray = malloc ((num_devices + 1) * sizeof (devarray[0]));
1039 
1040   if (devarray == NULL)
1041     {
1042       DBG (2, "get_devices: not enough memory for device list\n");
1043       DEBUG ();
1044       return SANE_STATUS_NO_MEM;
1045     }
1046 
1047   for (i = 0; i < num_devices; i++)
1048     devarray[i] = &devlist[i].sane;
1049 
1050   devarray[num_devices] = NULL;
1051   *device_list = devarray;
1052 
1053   return SANE_STATUS_GOOD;
1054 }
1055 
1056 SANE_Status
sane_open(SANE_String_Const devicename,SANE_Handle * handle)1057 sane_open (SANE_String_Const devicename, SANE_Handle * handle)
1058 {
1059   Umax_PP_Device *dev;
1060   Umax_PP_Descriptor *desc;
1061   int i, j;
1062   int rc, prt = 0;
1063   char *name = NULL;
1064 
1065   DBG (3, "open: device `%s'\n", devicename);
1066 
1067   /* if no device given or 'umax_pp' default value given */
1068   if (devicename == NULL || devicename[0] == 0
1069       || strncmp (devicename, "umax_pp", 7) == 0)
1070     {
1071 
1072       if (num_devices == 0)
1073         {
1074           DBG (1, "open: no devices present\n");
1075           return SANE_STATUS_INVAL;
1076         }
1077 
1078       DBG (3, "open: trying default device %s, port=%s,ppdev=%s\n",
1079            devlist[0].sane.name, devlist[0].port, devlist[0].ppdevice);
1080       if (devlist[0].port != NULL)
1081         {
1082           if ((devlist[0].port[0] == '0')
1083               && ((devlist[0].port[1] == 'x') || (devlist[0].port[1] == 'X')))
1084             prt = strtol (devlist[0].port + 2, NULL, 16);
1085           else
1086             prt = atoi (devlist[0].port);
1087           rc = sanei_umax_pp_open (prt, NULL);
1088         }
1089       else
1090         {
1091           rc = sanei_umax_pp_open (0, devlist[0].ppdevice);
1092         }
1093       desc = &devlist[0];
1094     }
1095   else                          /* specific value */
1096     {
1097       for (i = 0; i < num_devices; i++)
1098         if (strcmp (devlist[i].sane.name, devicename) == 0)
1099           break;
1100 
1101       if (i >= num_devices)
1102         for (i = 0; i < num_devices; i++)
1103           if (strcmp (devlist[i].port, devicename) == 0)
1104             break;
1105 
1106       if (i >= num_devices)
1107         {
1108           DBG (2, "open: device doesn't exist\n");
1109           DEBUG ();
1110           return SANE_STATUS_INVAL;
1111         }
1112 
1113       desc = &devlist[i];
1114 
1115       if (devlist[i].ppdevice != NULL)
1116         {
1117           if (devlist[i].ppdevice[0] == '/')
1118             {
1119               name = devlist[i].ppdevice;
1120             }
1121         }
1122       else
1123         {
1124           if ((devlist[i].port[0] == '0')
1125               && ((devlist[i].port[1] == 'x') || (devlist[i].port[1] == 'X')))
1126             prt = strtol (devlist[i].port + 2, NULL, 16);
1127           else
1128             prt = atoi (devlist[i].port);
1129           DBG (64, "open: devlist[i].port='%s' -> port=0x%X\n",
1130                devlist[i].port, prt);
1131         }
1132       rc = sanei_umax_pp_open (prt, name);
1133     }
1134 
1135   /* treat return code from open */
1136   switch (rc)
1137     {
1138     case UMAX1220P_TRANSPORT_FAILED:
1139       if (name == NULL)
1140         {
1141           DBG (1, "failed to init transport layer on port 0x%03X\n", prt);
1142         }
1143       else
1144         {
1145           DBG (1, "failed to init transport layer on device %s\n", name);
1146         }
1147       return SANE_STATUS_IO_ERROR;
1148 
1149     case UMAX1220P_SCANNER_FAILED:
1150       if (name == NULL)
1151         {
1152           DBG (1, "failed to initialize scanner on port 0x%03X\n", prt);
1153         }
1154       else
1155         {
1156           DBG (1, "failed to initialize scanner on device %s\n", name);
1157         }
1158       return SANE_STATUS_IO_ERROR;
1159     case UMAX1220P_BUSY:
1160       if (name == NULL)
1161         {
1162           DBG (1, "busy scanner on port 0x%03X\n", prt);
1163         }
1164       else
1165         {
1166           DBG (1, "busy scanner on device %s\n", name);
1167         }
1168       return SANE_STATUS_DEVICE_BUSY;
1169     }
1170 
1171 
1172   dev = (Umax_PP_Device *) malloc (sizeof (*dev));
1173 
1174   if (dev == NULL)
1175     {
1176       DBG (2, "open: not enough memory for device descriptor\n");
1177       DEBUG ();
1178       return SANE_STATUS_NO_MEM;
1179     }
1180 
1181   memset (dev, 0, sizeof (*dev));
1182 
1183   dev->desc = desc;
1184 
1185   for (i = 0; i < 4; ++i)
1186     for (j = 0; j < 256; ++j)
1187       dev->gamma_table[i][j] = j;
1188 
1189   /* the extra amount of UMAX_PP_RESERVE bytes is to handle */
1190   /* the data needed to resync the color frames     */
1191   dev->buf = malloc (dev->desc->buf_size + UMAX_PP_RESERVE);
1192   dev->bufsize = dev->desc->buf_size;
1193 
1194   dev->dpi_range.min = SANE_FIX (75);
1195   dev->dpi_range.max = SANE_FIX (dev->desc->max_res);
1196   dev->dpi_range.quant = 0;
1197 
1198   dev->x_range.min = 0;
1199   dev->x_range.max = dev->desc->max_h_size;
1200   dev->x_range.quant = 0;
1201 
1202   dev->y_range.min = 0;
1203   dev->y_range.max = dev->desc->max_v_size;
1204   dev->y_range.quant = 0;
1205 
1206   dev->gray_gain = 0;
1207 
1208   /* use pre defined settings read from umax_pp.conf */
1209   dev->red_gain = red_gain;
1210   dev->green_gain = green_gain;
1211   dev->blue_gain = blue_gain;
1212   dev->red_offset = red_offset;
1213   dev->green_offset = green_offset;
1214   dev->blue_offset = blue_offset;
1215 
1216 
1217   if (dev->buf == NULL)
1218     {
1219       DBG (2, "open: not enough memory for scan buffer (%lu bytes)\n",
1220            (long int) dev->desc->buf_size);
1221       DEBUG ();
1222       free (dev);
1223       return SANE_STATUS_NO_MEM;
1224     }
1225 
1226   init_options (dev);
1227 
1228   dev->next = first_dev;
1229   first_dev = dev;
1230 
1231 
1232   if (sanei_umax_pp_UTA () == 1)
1233     dev->opt[OPT_UTA_CONTROL].cap &= ~SANE_CAP_INACTIVE;
1234 
1235   *handle = dev;
1236 
1237   DBG (3, "open: success\n");
1238 
1239   return SANE_STATUS_GOOD;
1240 }
1241 
1242 void
sane_close(SANE_Handle handle)1243 sane_close (SANE_Handle handle)
1244 {
1245   Umax_PP_Device *prev, *dev;
1246   int rc;
1247 
1248   DBG (3, "sane_close: ...\n");
1249   /* remove handle from list of open handles: */
1250   prev = NULL;
1251 
1252   for (dev = first_dev; dev; dev = dev->next)
1253     {
1254       if (dev == handle)
1255         break;
1256       prev = dev;
1257     }
1258 
1259   if (dev == NULL)
1260     {
1261       DBG (2, "close: unknown device\n");
1262       DEBUG ();
1263       return;                   /* oops, not a handle we know about */
1264     }
1265 
1266   if (dev->state == UMAX_PP_STATE_SCANNING)
1267     sane_cancel (handle);       /* remember: sane_cancel is a macro and
1268                                    expands to sane_umax_pp_cancel ()... */
1269 
1270 
1271   /* if the scanner is parking head, we wait it to finish */
1272   while (dev->state == UMAX_PP_STATE_CANCELLED)
1273     {
1274       DBG (2, "close: waiting scanner to park head\n");
1275       rc = sanei_umax_pp_status ();
1276 
1277       /* check if scanner busy parking */
1278       if (rc != UMAX1220P_BUSY)
1279         {
1280           DBG (2, "close: scanner head parked\n");
1281           dev->state = UMAX_PP_STATE_IDLE;
1282         }
1283     }
1284 
1285   /* then we switch off gain if needed */
1286   if (dev->val[OPT_LAMP_CONTROL].w == SANE_TRUE)
1287     {
1288       rc = sanei_umax_pp_lamp (0);
1289       if (rc == UMAX1220P_TRANSPORT_FAILED)
1290         {
1291           DBG (1, "close: switch off gain failed (ignored....)\n");
1292         }
1293     }
1294 
1295   sanei_umax_pp_close ();
1296 
1297 
1298 
1299   if (prev != NULL)
1300     prev->next = dev->next;
1301   else
1302     first_dev = dev->next;
1303 
1304   free (dev->buf);
1305   DBG (3, "close: device closed\n");
1306 
1307   free (handle);
1308 
1309 }
1310 
1311 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)1312 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1313 {
1314   Umax_PP_Device *dev = handle;
1315 
1316   if ((unsigned) option >= NUM_OPTIONS)
1317     {
1318       DBG (2, "get_option_descriptor: option %d doesn't exist\n", option);
1319       DEBUG ();
1320       return NULL;
1321     }
1322 
1323   DBG (6, "get_option_descriptor: requested option %d (%s)\n",
1324        option, dev->opt[option].name);
1325 
1326   return dev->opt + option;
1327 }
1328 
1329 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)1330 sane_control_option (SANE_Handle handle, SANE_Int option,
1331                      SANE_Action action, void *val, SANE_Int * info)
1332 {
1333   Umax_PP_Device *dev = handle;
1334   SANE_Status status;
1335   SANE_Word w, cap, tmpw;
1336   int dpi, rc;
1337 
1338   DBG (6, "control_option: option %d, action %d\n", option, action);
1339 
1340   if (info)
1341     *info = 0;
1342 
1343   if (dev->state == UMAX_PP_STATE_SCANNING)
1344     {
1345       DBG (2, "control_option: device is scanning\n");
1346       return SANE_STATUS_DEVICE_BUSY;
1347     }
1348 
1349   if ((unsigned int) option >= NUM_OPTIONS)
1350     {
1351       DBG (2, "control_option: option doesn't exist\n");
1352       return SANE_STATUS_INVAL;
1353     }
1354 
1355 
1356   cap = dev->opt[option].cap;
1357 
1358   if (!SANE_OPTION_IS_ACTIVE (cap))
1359     {
1360       DBG (2, "control_option: option isn't active\n");
1361       return SANE_STATUS_INVAL;
1362     }
1363 
1364   DBG (6, "control_option: option <%s>, action ... %d\n",
1365        dev->opt[option].name, action);
1366 
1367   if (action == SANE_ACTION_GET_VALUE)
1368     {
1369       DBG (6, " get value\n");
1370       switch (option)
1371         {
1372           /* word options: */
1373         case OPT_PREVIEW:
1374         case OPT_GRAY_PREVIEW:
1375         case OPT_LAMP_CONTROL:
1376         case OPT_UTA_CONTROL:
1377         case OPT_RESOLUTION:
1378         case OPT_TL_X:
1379         case OPT_TL_Y:
1380         case OPT_BR_X:
1381         case OPT_BR_Y:
1382         case OPT_NUM_OPTS:
1383         case OPT_CUSTOM_GAMMA:
1384         case OPT_MANUAL_GAIN:
1385         case OPT_GRAY_GAIN:
1386         case OPT_GREEN_GAIN:
1387         case OPT_RED_GAIN:
1388         case OPT_BLUE_GAIN:
1389         case OPT_MANUAL_OFFSET:
1390         case OPT_GRAY_OFFSET:
1391         case OPT_GREEN_OFFSET:
1392         case OPT_RED_OFFSET:
1393         case OPT_BLUE_OFFSET:
1394 
1395           *(SANE_Word *) val = dev->val[option].w;
1396           return SANE_STATUS_GOOD;
1397 
1398           /* word-array options: */
1399         case OPT_GAMMA_VECTOR:
1400         case OPT_GAMMA_VECTOR_R:
1401         case OPT_GAMMA_VECTOR_G:
1402         case OPT_GAMMA_VECTOR_B:
1403           memcpy (val, dev->val[option].wa, dev->opt[option].size);
1404           return SANE_STATUS_GOOD;
1405 
1406           /* string options: */
1407         case OPT_MODE:
1408 
1409           strcpy (val, dev->val[option].s);
1410           return SANE_STATUS_GOOD;
1411         }
1412     }
1413   else if (action == SANE_ACTION_SET_VALUE)
1414     {
1415       DBG (6, " set value\n");
1416 
1417       if (!SANE_OPTION_IS_SETTABLE (cap))
1418         {
1419           DBG (2, "control_option: option can't be set\n");
1420           return SANE_STATUS_INVAL;
1421         }
1422 
1423       status = sanei_constrain_value (dev->opt + option, val, info);
1424 
1425       if (status != SANE_STATUS_GOOD)
1426         {
1427           DBG (2, "control_option: constrain_value failed (%s)\n",
1428                sane_strstatus (status));
1429           return status;
1430         }
1431 
1432       if (option == OPT_RESOLUTION)
1433         {
1434           DBG (16, "control_option: setting resolution to %d\n",
1435                *(SANE_Int *) val);
1436         }
1437       if (option == OPT_PREVIEW)
1438         {
1439           DBG (16, "control_option: setting preview to %d\n",
1440                *(SANE_Word *) val);
1441         }
1442 
1443       switch (option)
1444         {
1445           /* (mostly) side-effect-free word options: */
1446         case OPT_PREVIEW:
1447         case OPT_GRAY_PREVIEW:
1448         case OPT_TL_Y:
1449         case OPT_BR_Y:
1450 
1451           if (info)
1452             *info |= SANE_INFO_RELOAD_PARAMS;
1453 
1454           // fall through
1455         case OPT_GRAY_GAIN:
1456         case OPT_GREEN_GAIN:
1457         case OPT_RED_GAIN:
1458         case OPT_BLUE_GAIN:
1459         case OPT_GRAY_OFFSET:
1460         case OPT_GREEN_OFFSET:
1461         case OPT_RED_OFFSET:
1462         case OPT_BLUE_OFFSET:
1463 
1464           dev->val[option].w = *(SANE_Word *) val;
1465           /* sanity check */
1466           if (dev->val[OPT_BR_Y].w < dev->val[OPT_TL_Y].w)
1467             {
1468               tmpw = dev->val[OPT_BR_Y].w;
1469               dev->val[OPT_BR_Y].w = dev->val[OPT_TL_Y].w;
1470               dev->val[OPT_TL_Y].w = tmpw;
1471               if (info)
1472                 *info |= SANE_INFO_INEXACT;
1473               DBG (16, "control_option: swapping Y coordinates\n");
1474             }
1475           if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1476             {
1477               dpi = (int) (SANE_UNFIX (dev->val[OPT_RESOLUTION].w));
1478               if (dev->val[OPT_TL_Y].w < 2 * umax_pp_get_sync (dpi))
1479                 {
1480                   DBG (16, "control_option: correcting TL_Y coordinates\n");
1481                   dev->val[OPT_TL_Y].w = 2 * umax_pp_get_sync (dpi);
1482                   if (info)
1483                     *info |= SANE_INFO_INEXACT;
1484                 }
1485             }
1486           return SANE_STATUS_GOOD;
1487 
1488           /* side-effect-free word-array options: */
1489         case OPT_GAMMA_VECTOR:
1490         case OPT_GAMMA_VECTOR_R:
1491         case OPT_GAMMA_VECTOR_G:
1492         case OPT_GAMMA_VECTOR_B:
1493 
1494           memcpy (dev->val[option].wa, val, dev->opt[option].size);
1495           return SANE_STATUS_GOOD;
1496 
1497 
1498           /* options with side-effects: */
1499         case OPT_UTA_CONTROL:
1500           dev->val[option].w = *(SANE_Word *) val;
1501           return SANE_STATUS_GOOD;
1502 
1503         case OPT_LAMP_CONTROL:
1504           if (dev->state != UMAX_PP_STATE_IDLE)
1505             {
1506               rc = sanei_umax_pp_status ();
1507 
1508               /* check if scanner busy parking */
1509               if (rc == UMAX1220P_BUSY)
1510                 {
1511                   DBG (2, "control_option: scanner busy\n");
1512                   if (info)
1513                     *info |= SANE_INFO_RELOAD_PARAMS;
1514                   return SANE_STATUS_DEVICE_BUSY;
1515                 }
1516               dev->state = UMAX_PP_STATE_IDLE;
1517             }
1518           dev->val[option].w = *(SANE_Word *) val;
1519           if (dev->val[option].w == SANE_TRUE)
1520             rc = sanei_umax_pp_lamp (1);
1521           else
1522             rc = sanei_umax_pp_lamp (0);
1523           if (rc == UMAX1220P_TRANSPORT_FAILED)
1524             return SANE_STATUS_IO_ERROR;
1525           return SANE_STATUS_GOOD;
1526 
1527         case OPT_TL_X:
1528         case OPT_BR_X:
1529           if (info)
1530             *info |= SANE_INFO_RELOAD_PARAMS;
1531           dpi = (int) (SANE_UNFIX (dev->val[OPT_RESOLUTION].w));
1532           dev->val[option].w = *(SANE_Word *) val;
1533           /* coords rounded to allow 32 bit IO/transfer */
1534           /* at high resolution                         */
1535           if (dpi >= 600)
1536             {
1537               if (dev->val[option].w & 0x03)
1538                 {
1539                   if (info)
1540                     *info |= SANE_INFO_INEXACT;
1541                   dev->val[option].w = dev->val[option].w & 0xFFFC;
1542                   *(SANE_Word *) val = dev->val[option].w;
1543                   DBG (16, "control_option: rounding X to %d\n",
1544                        *(SANE_Word *) val);
1545                 }
1546             }
1547           /* sanity check */
1548           if (dev->val[OPT_BR_X].w < dev->val[OPT_TL_X].w)
1549             {
1550               tmpw = dev->val[OPT_BR_X].w;
1551               dev->val[OPT_BR_X].w = dev->val[OPT_TL_X].w;
1552               dev->val[OPT_TL_X].w = tmpw;
1553               if (info)
1554                 *info |= SANE_INFO_INEXACT;
1555               DBG (16, "control_option: swapping X coordinates\n");
1556             }
1557           return SANE_STATUS_GOOD;
1558 
1559 
1560 
1561         case OPT_RESOLUTION:
1562           if (info)
1563             *info |= SANE_INFO_RELOAD_PARAMS;
1564           /* resolution : only have 75, 150, 300, 600 and 1200 */
1565           dpi = (int) (SANE_UNFIX (*(SANE_Word *) val));
1566           if ((dpi != 75)
1567               && (dpi != 150)
1568               && (dpi != 300) && (dpi != 600) && (dpi != 1200))
1569             {
1570               if (dpi <= 75)
1571                 dpi = 75;
1572               else if (dpi <= 150)
1573                 dpi = 150;
1574               else if (dpi <= 300)
1575                 dpi = 300;
1576               else if (dpi <= 600)
1577                 dpi = 600;
1578               else
1579                 dpi = 1200;
1580               if (info)
1581                 *info |= SANE_INFO_INEXACT;
1582               *(SANE_Word *) val = SANE_FIX ((SANE_Word) dpi);
1583             }
1584           dev->val[option].w = *(SANE_Word *) val;
1585 
1586           /* correct top x and bottom x if needed */
1587           if (dpi >= 600)
1588             {
1589               dev->val[OPT_TL_X].w = dev->val[OPT_TL_X].w & 0xFFFC;
1590               dev->val[OPT_BR_X].w = dev->val[OPT_BR_X].w & 0xFFFC;
1591             }
1592           /* corrects top y for offset */
1593           if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1594             {
1595               if (dev->val[OPT_TL_Y].w < 2 * umax_pp_get_sync (dpi))
1596                 {
1597                   DBG (16, "control_option: correcting TL_Y coordinates\n");
1598                   dev->val[OPT_TL_Y].w = 2 * umax_pp_get_sync (dpi);
1599                   if (info)
1600                     *info |= SANE_INFO_INEXACT;
1601                 }
1602             }
1603           return SANE_STATUS_GOOD;
1604 
1605         case OPT_MANUAL_OFFSET:
1606           w = *(SANE_Word *) val;
1607 
1608           if (w == dev->val[OPT_MANUAL_OFFSET].w)
1609             return SANE_STATUS_GOOD;    /* no change */
1610 
1611           if (info)
1612             *info |= SANE_INFO_RELOAD_OPTIONS;
1613 
1614           dev->val[OPT_MANUAL_OFFSET].w = w;
1615 
1616           if (w == SANE_TRUE)
1617             {
1618               const char *mode = dev->val[OPT_MODE].s;
1619 
1620               if ((strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1621                   || (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1622                 dev->opt[OPT_GRAY_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1623               else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1624                 {
1625                   dev->opt[OPT_GRAY_OFFSET].cap |= SANE_CAP_INACTIVE;
1626                   dev->opt[OPT_RED_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1627                   dev->opt[OPT_GREEN_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1628                   dev->opt[OPT_BLUE_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1629                 }
1630             }
1631           else
1632             {
1633               dev->opt[OPT_GRAY_OFFSET].cap |= SANE_CAP_INACTIVE;
1634               dev->opt[OPT_RED_OFFSET].cap |= SANE_CAP_INACTIVE;
1635               dev->opt[OPT_GREEN_OFFSET].cap |= SANE_CAP_INACTIVE;
1636               dev->opt[OPT_BLUE_OFFSET].cap |= SANE_CAP_INACTIVE;
1637             }
1638           return SANE_STATUS_GOOD;
1639 
1640 
1641 
1642         case OPT_MANUAL_GAIN:
1643           w = *(SANE_Word *) val;
1644 
1645           if (w == dev->val[OPT_MANUAL_GAIN].w)
1646             return SANE_STATUS_GOOD;    /* no change */
1647 
1648           if (info)
1649             *info |= SANE_INFO_RELOAD_OPTIONS;
1650 
1651           dev->val[OPT_MANUAL_GAIN].w = w;
1652 
1653           if (w == SANE_TRUE)
1654             {
1655               const char *mode = dev->val[OPT_MODE].s;
1656 
1657               if ((strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1658                   || (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1659                 dev->opt[OPT_GRAY_GAIN].cap &= ~SANE_CAP_INACTIVE;
1660               else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1661                 {
1662                   dev->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE;
1663                   dev->opt[OPT_RED_GAIN].cap &= ~SANE_CAP_INACTIVE;
1664                   dev->opt[OPT_GREEN_GAIN].cap &= ~SANE_CAP_INACTIVE;
1665                   dev->opt[OPT_BLUE_GAIN].cap &= ~SANE_CAP_INACTIVE;
1666                 }
1667             }
1668           else
1669             {
1670               dev->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE;
1671               dev->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE;
1672               dev->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE;
1673               dev->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE;
1674             }
1675           return SANE_STATUS_GOOD;
1676 
1677 
1678 
1679 
1680         case OPT_CUSTOM_GAMMA:
1681           w = *(SANE_Word *) val;
1682 
1683           if (w == dev->val[OPT_CUSTOM_GAMMA].w)
1684             return SANE_STATUS_GOOD;    /* no change */
1685 
1686           if (info)
1687             *info |= SANE_INFO_RELOAD_OPTIONS;
1688 
1689           dev->val[OPT_CUSTOM_GAMMA].w = w;
1690 
1691           if (w == SANE_TRUE)
1692             {
1693               const char *mode = dev->val[OPT_MODE].s;
1694 
1695               if ((strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1696                   || (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1697                 {
1698                   dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1699                   sanei_umax_pp_gamma (NULL, dev->val[OPT_GAMMA_VECTOR].wa,
1700                                        NULL);
1701                 }
1702               else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1703                 {
1704                   dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1705                   dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1706                   dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1707                   dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1708                   sanei_umax_pp_gamma (dev->val[OPT_GAMMA_VECTOR_R].wa,
1709                                        dev->val[OPT_GAMMA_VECTOR_G].wa,
1710                                        dev->val[OPT_GAMMA_VECTOR_B].wa);
1711                 }
1712             }
1713           else
1714             {
1715               dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1716               dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1717               dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1718               dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1719               sanei_umax_pp_gamma (NULL, NULL, NULL);
1720             }
1721 
1722           return SANE_STATUS_GOOD;
1723 
1724         case OPT_MODE:
1725           {
1726             char *old_val = dev->val[option].s;
1727 
1728             if (old_val)
1729               {
1730                 if (strcmp (old_val, val) == 0)
1731                   return SANE_STATUS_GOOD;      /* no change */
1732 
1733                 free (old_val);
1734               }
1735 
1736             if (info)
1737               *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1738 
1739             dev->val[option].s = strdup (val);
1740 
1741             /* corrects top y for offset */
1742             if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1743               {
1744                 dpi = (int) (SANE_UNFIX (dev->val[OPT_RESOLUTION].w));
1745                 if (dev->val[OPT_TL_Y].w < 2 * umax_pp_get_sync (dpi))
1746                   {
1747                     dev->val[OPT_TL_Y].w = 2 * umax_pp_get_sync (dpi);
1748                     DBG (16, "control_option: correcting TL_Y coordinates\n");
1749                     if (info)
1750                       *info |= SANE_INFO_INEXACT;
1751                   }
1752               }
1753 
1754             dev->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1755             dev->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1756             dev->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1757             dev->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1758             dev->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1759             sanei_umax_pp_gamma (NULL, NULL, NULL);
1760 
1761 
1762             if (dev->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
1763               {
1764                 if ((strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1765                     || (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1766                   {
1767                     dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1768                     sanei_umax_pp_gamma (NULL, dev->val[OPT_GAMMA_VECTOR].wa,
1769                                          NULL);
1770                   }
1771                 else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1772                   {
1773                     dev->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1774                     dev->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1775                     dev->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1776                     dev->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1777                     sanei_umax_pp_gamma (dev->val[OPT_GAMMA_VECTOR_R].wa,
1778                                          dev->val[OPT_GAMMA_VECTOR_G].wa,
1779                                          dev->val[OPT_GAMMA_VECTOR_B].wa);
1780                   }
1781               }
1782 
1783             /* rebuild OPT OFFSET */
1784             dev->opt[OPT_GRAY_OFFSET].cap |= SANE_CAP_INACTIVE;
1785             dev->opt[OPT_RED_OFFSET].cap |= SANE_CAP_INACTIVE;
1786             dev->opt[OPT_GREEN_OFFSET].cap |= SANE_CAP_INACTIVE;
1787             dev->opt[OPT_BLUE_OFFSET].cap |= SANE_CAP_INACTIVE;
1788 
1789 
1790             if (dev->val[OPT_MANUAL_OFFSET].w == SANE_TRUE)
1791               {
1792                 if ((strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1793                     || (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1794                   dev->opt[OPT_GRAY_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1795                 else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1796                   {
1797                     dev->opt[OPT_RED_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1798                     dev->opt[OPT_GREEN_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1799                     dev->opt[OPT_BLUE_OFFSET].cap &= ~SANE_CAP_INACTIVE;
1800                   }
1801               }
1802 
1803             /* rebuild OPT GAIN */
1804             dev->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE;
1805             dev->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE;
1806             dev->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE;
1807             dev->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE;
1808 
1809 
1810             if (dev->val[OPT_MANUAL_GAIN].w == SANE_TRUE)
1811               {
1812                 if ((strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1813                     || (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0))
1814                   dev->opt[OPT_GRAY_GAIN].cap &= ~SANE_CAP_INACTIVE;
1815                 else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1816                   {
1817                     dev->opt[OPT_RED_GAIN].cap &= ~SANE_CAP_INACTIVE;
1818                     dev->opt[OPT_GREEN_GAIN].cap &= ~SANE_CAP_INACTIVE;
1819                     dev->opt[OPT_BLUE_GAIN].cap &= ~SANE_CAP_INACTIVE;
1820                   }
1821               }
1822 
1823             return SANE_STATUS_GOOD;
1824           }
1825         }
1826     }
1827 
1828 
1829   DBG (2, "control_option: unknown action %d \n", action);
1830   return SANE_STATUS_INVAL;
1831 }
1832 
1833 
1834 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)1835 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1836 {
1837   Umax_PP_Device *dev = handle;
1838   int dpi, remain;
1839 
1840   memset (&(dev->params), 0, sizeof (dev->params));
1841   DBG (64, "sane_get_parameters\n");
1842 
1843   /* color/gray */
1844   if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) != 0)
1845     {
1846       if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) != 0)
1847         dev->color = UMAX_PP_MODE_LINEART;
1848       else
1849         dev->color = UMAX_PP_MODE_GRAYSCALE;
1850     }
1851   else
1852     dev->color = UMAX_PP_MODE_COLOR;
1853 
1854   /* offset control */
1855   if (dev->val[OPT_MANUAL_OFFSET].w == SANE_TRUE)
1856     {
1857       if (dev->color != UMAX_PP_MODE_COLOR)
1858         {
1859           dev->red_offset = 0;
1860           dev->green_offset = (int) (dev->val[OPT_GRAY_OFFSET].w);
1861           dev->blue_offset = 0;
1862         }
1863       else
1864         {
1865           dev->red_offset = (int) (dev->val[OPT_RED_OFFSET].w);
1866           dev->green_offset = (int) (dev->val[OPT_GREEN_OFFSET].w);
1867           dev->blue_offset = (int) (dev->val[OPT_BLUE_OFFSET].w);
1868         }
1869     }
1870   else
1871     {
1872       dev->red_offset = 6;
1873       dev->green_offset = 6;
1874       dev->blue_offset = 6;
1875     }
1876 
1877   /* gain control */
1878   if (dev->val[OPT_MANUAL_GAIN].w == SANE_TRUE)
1879     {
1880       if (dev->color != UMAX_PP_MODE_COLOR)
1881         {
1882           dev->red_gain = 0;
1883           dev->green_gain = (int) (dev->val[OPT_GRAY_GAIN].w);
1884           dev->blue_gain = 0;
1885         }
1886       else
1887         {
1888           dev->red_gain = (int) (dev->val[OPT_RED_GAIN].w);
1889           dev->green_gain = (int) (dev->val[OPT_GREEN_GAIN].w);
1890           dev->blue_gain = (int) (dev->val[OPT_BLUE_GAIN].w);
1891         }
1892     }
1893   else
1894     {
1895       dev->red_gain = red_gain;
1896       dev->green_gain = green_gain;
1897       dev->blue_gain = blue_gain;
1898     }
1899 
1900   /* geometry */
1901   dev->TopX = dev->val[OPT_TL_X].w;
1902   dev->TopY = dev->val[OPT_TL_Y].w;
1903   dev->BottomX = dev->val[OPT_BR_X].w;
1904   dev->BottomY = dev->val[OPT_BR_Y].w;
1905 
1906   /* resolution : only have 75, 150, 300, 600 and 1200 */
1907   dpi = (int) (SANE_UNFIX (dev->val[OPT_RESOLUTION].w));
1908   if (dpi <= 75)
1909     dpi = 75;
1910   else if (dpi <= 150)
1911     dpi = 150;
1912   else if (dpi <= 300)
1913     dpi = 300;
1914   else if (dpi <= 600)
1915     dpi = 600;
1916   else
1917     dpi = 1200;
1918   dev->dpi = dpi;
1919 
1920   DBG (16, "sane_get_parameters: dpi set to %d\n", dpi);
1921 
1922   /* for highest resolutions , width must be aligned on 32 bit word */
1923   if (dpi >= 600)
1924     {
1925       remain = (dev->BottomX - dev->TopX) & 0x03;
1926       if (remain)
1927         {
1928           DBG (64, "sane_get_parameters: %d-%d -> remain is %d\n",
1929                dev->BottomX, dev->TopX, remain);
1930           if (dev->BottomX + remain < dev->desc->max_h_size)
1931             dev->BottomX += remain;
1932           else
1933             {
1934               remain -= (dev->desc->max_h_size - dev->BottomX);
1935               dev->BottomX = dev->desc->max_h_size;
1936               dev->TopX -= remain;
1937             }
1938         }
1939     }
1940 
1941   if (dev->val[OPT_PREVIEW].w == SANE_TRUE)
1942     {
1943 
1944       if (dev->val[OPT_GRAY_PREVIEW].w == SANE_TRUE)
1945         {
1946           DBG (16, "sane_get_parameters: gray preview\n");
1947           dev->color = UMAX_PP_MODE_GRAYSCALE;
1948           dev->params.format = SANE_FRAME_GRAY;
1949         }
1950       else
1951         {
1952           DBG (16, "sane_get_parameters: color preview\n");
1953           dev->color = UMAX_PP_MODE_COLOR;
1954           dev->params.format = SANE_FRAME_RGB;
1955         }
1956 
1957       dev->dpi = 75;
1958       dev->TopX = 0;
1959       dev->TopY = 0;
1960       dev->BottomX = dev->desc->max_h_size;
1961       dev->BottomY = dev->desc->max_v_size;
1962     }
1963 
1964 
1965   /* fill params */
1966   dev->params.last_frame = SANE_TRUE;
1967   dev->params.lines =
1968     ((dev->BottomY - dev->TopY) * dev->dpi) / dev->desc->ccd_res;
1969   if (dev->dpi >= dev->desc->ccd_res)
1970     dpi = dev->desc->ccd_res;
1971   else
1972     dpi = dev->dpi;
1973   dev->params.pixels_per_line =
1974     ((dev->BottomX - dev->TopX) * dpi) / dev->desc->ccd_res;
1975   if (dev->color == UMAX_PP_MODE_COLOR)
1976     {
1977       dev->params.bytes_per_line = dev->params.pixels_per_line * 3;
1978       dev->params.format = SANE_FRAME_RGB;
1979     }
1980   else
1981     {
1982       dev->params.bytes_per_line = dev->params.pixels_per_line;
1983       dev->params.format = SANE_FRAME_GRAY;
1984     }
1985   dev->params.depth = 8;
1986 
1987   /* success */
1988   if (params != NULL)
1989     memcpy (params, &(dev->params), sizeof (dev->params));
1990   return SANE_STATUS_GOOD;
1991 
1992 }
1993 
1994 SANE_Status
sane_start(SANE_Handle handle)1995 sane_start (SANE_Handle handle)
1996 {
1997   Umax_PP_Device *dev = handle;
1998   int rc, autoset;
1999   int delta = 0, points;
2000 
2001   /* sanity check */
2002   if (dev->state == UMAX_PP_STATE_SCANNING)
2003     {
2004       DBG (2, "sane_start: device is already scanning\n");
2005       DEBUG ();
2006 
2007       return SANE_STATUS_DEVICE_BUSY;
2008     }
2009 
2010   /* if cancelled, check if head is back home */
2011   if (dev->state == UMAX_PP_STATE_CANCELLED)
2012     {
2013       DBG (2, "sane_start: checking if scanner is parking head .... \n");
2014 
2015       rc = sanei_umax_pp_status ();
2016       points = 0;
2017 
2018       /* check if scanner busy parking  */
2019       /* if so, wait parking completion */
2020       DBG (2, "sane_start: scanner busy\n");
2021       while ((rc == UMAX1220P_BUSY) && (points < 30))
2022         {
2023           sleep (1);
2024           rc = sanei_umax_pp_status ();
2025           points++;
2026         }
2027       /* timeout waiting for scanner */
2028       if (rc == UMAX1220P_BUSY)
2029         {
2030           DBG (2, "sane_start: scanner still busy\n");
2031           return SANE_STATUS_DEVICE_BUSY;
2032         }
2033       dev->state = UMAX_PP_STATE_IDLE;
2034     }
2035 
2036 
2037   /* get values from options */
2038   sane_get_parameters (handle, NULL);
2039 
2040   /* sets lamp flag to TRUE */
2041   dev->val[OPT_LAMP_CONTROL].w = SANE_TRUE;
2042 
2043   /* tests if we do auto setting */
2044   if (dev->val[OPT_MANUAL_GAIN].w == SANE_TRUE)
2045     autoset = 0;
2046   else
2047     autoset = 1;
2048 
2049 
2050   /* call start scan */
2051   if (dev->color == UMAX_PP_MODE_COLOR)
2052     {
2053       delta = umax_pp_get_sync (dev->dpi);
2054       points = 2 * delta;
2055       /* first lines are 'garbage' for 610P */
2056       if (sanei_umax_pp_getastra () < 1210)
2057         points *= 2;
2058       DBG (64, "sane_start:umax_pp_start(%d,%d,%d,%d,%d,1,%X,%X)\n",
2059            dev->TopX,
2060            dev->TopY - points,
2061            dev->BottomX - dev->TopX,
2062            dev->BottomY - dev->TopY + points,
2063            dev->dpi,
2064            (dev->red_gain << 8) + (dev->green_gain << 4) +
2065            dev->blue_gain,
2066            (dev->red_offset << 8) + (dev->green_offset << 4) +
2067            dev->blue_offset);
2068 
2069       rc = sanei_umax_pp_start (dev->TopX,
2070                                 dev->TopY - points,
2071                                 dev->BottomX - dev->TopX,
2072                                 dev->BottomY - dev->TopY + points,
2073                                 dev->dpi,
2074                                 2,
2075                                 autoset,
2076                                 (dev->red_gain << 8) |
2077                                 (dev->green_gain << 4) |
2078                                 dev->blue_gain,
2079                                 (dev->red_offset << 8) |
2080                                 (dev->green_offset << 4) |
2081                                 dev->blue_offset, &(dev->bpp), &(dev->tw),
2082                                 &(dev->th));
2083       /* we enlarged the scanning zone   */
2084       /* to allow reordering, we must    */
2085       /* subtract it from real scanning */
2086       /* zone                            */
2087       dev->th -= points;
2088       DBG (64, "sane_start: bpp=%d,tw=%d,th=%d\n", dev->bpp, dev->tw,
2089            dev->th);
2090     }
2091   else
2092     {
2093       DBG (64, "sane_start:umax_pp_start(%d,%d,%d,%d,%d,0,%X,%X)\n",
2094            dev->TopX,
2095            dev->TopY,
2096            dev->BottomX - dev->TopX,
2097            dev->BottomY - dev->TopY, dev->dpi, dev->gray_gain << 4,
2098            dev->gray_offset << 4);
2099       rc = sanei_umax_pp_start (dev->TopX,
2100                                 dev->TopY,
2101                                 dev->BottomX - dev->TopX,
2102                                 dev->BottomY - dev->TopY,
2103                                 dev->dpi,
2104                                 1,
2105                                 autoset,
2106                                 dev->gray_gain << 4,
2107                                 dev->gray_offset << 4, &(dev->bpp),
2108                                 &(dev->tw), &(dev->th));
2109       DBG (64, "sane_start: bpp=%d,tw=%d,th=%d\n", dev->bpp, dev->tw,
2110            dev->th);
2111     }
2112 
2113   if (rc != UMAX1220P_OK)
2114     {
2115       DBG (2, "sane_start: failure\n");
2116       return SANE_STATUS_IO_ERROR;
2117     }
2118 
2119   /* scan started, no bytes read */
2120   dev->state = UMAX_PP_STATE_SCANNING;
2121   dev->buflen = 0;
2122   dev->bufread = 0;
2123   dev->read = 0;
2124 
2125   /* leading lines for 610P aren't complete in color mode */
2126   /* and should be discarded                              */
2127   if ((sanei_umax_pp_getastra () < 1210)
2128       && (dev->color == UMAX_PP_MODE_COLOR))
2129     {
2130       rc =
2131         sanei_umax_pp_read (2 * delta * dev->tw * dev->bpp, dev->tw, dev->dpi,
2132                             0,
2133                             dev->buf + UMAX_PP_RESERVE -
2134                             2 * delta * dev->tw * dev->bpp);
2135       if (rc != UMAX1220P_OK)
2136         {
2137           DBG (2, "sane_start: first lines discarding failed\n");
2138           return SANE_STATUS_IO_ERROR;
2139         }
2140     }
2141 
2142   /* in case of color, we have to preload blue and green */
2143   /* data to allow reordering while later read           */
2144   if ((dev->color == UMAX_PP_MODE_COLOR) && (delta > 0))
2145     {
2146       rc =
2147         sanei_umax_pp_read (2 * delta * dev->tw * dev->bpp, dev->tw, dev->dpi,
2148                             0,
2149                             dev->buf + UMAX_PP_RESERVE -
2150                             2 * delta * dev->tw * dev->bpp);
2151       if (rc != UMAX1220P_OK)
2152         {
2153           DBG (2, "sane_start: preload buffer failed\n");
2154           return SANE_STATUS_IO_ERROR;
2155         }
2156     }
2157 
2158   /* OK .... */
2159   return SANE_STATUS_GOOD;
2160 
2161 }
2162 
2163 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * buf,SANE_Int max_len,SANE_Int * len)2164 sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
2165            SANE_Int * len)
2166 {
2167   Umax_PP_Device *dev = handle;
2168   long int length;
2169   int last, rc;
2170   int x, y, nl, ll;
2171   SANE_Byte *lbuf;
2172   int max = 0;
2173   int min = 255;
2174   int delta = 0;
2175 
2176 
2177   /* no data until further notice */
2178   *len = 0;
2179   DBG (64, "sane_read(max_len=%d)\n", max_len);
2180   ll = dev->tw * dev->bpp;
2181 
2182   /* sanity check */
2183   if (dev->state == UMAX_PP_STATE_CANCELLED)
2184     {
2185       DBG (2, "sane_read: scan cancelled\n");
2186       DEBUG ();
2187 
2188       return SANE_STATUS_CANCELLED;
2189     }
2190 
2191   /* eof test */
2192   if (dev->read >= dev->th * ll)
2193     {
2194       DBG (2, "sane_read: end of scan reached\n");
2195       return SANE_STATUS_EOF;
2196     }
2197 
2198   /* read data from scanner if needed */
2199   if ((dev->buflen == 0) || (dev->bufread >= dev->buflen))
2200     {
2201       DBG (64, "sane_read: reading data from scanner\n");
2202       /* absolute number of bytes needed */
2203       length = ll * dev->th - dev->read;
2204 
2205       /* does all fit in a single last read ? */
2206       if (length <= dev->bufsize)
2207         {
2208           last = 1;
2209         }
2210       else
2211         {
2212           last = 0;
2213           /* round number of scan lines */
2214           length = (dev->bufsize / ll) * ll;
2215         }
2216 
2217 
2218       if (dev->color == UMAX_PP_MODE_COLOR)
2219         {
2220           delta = umax_pp_get_sync (dev->dpi);
2221           rc =
2222             sanei_umax_pp_read (length, dev->tw, dev->dpi, last,
2223                                 dev->buf + UMAX_PP_RESERVE);
2224         }
2225       else
2226         rc = sanei_umax_pp_read (length, dev->tw, dev->dpi, last, dev->buf);
2227       if (rc != UMAX1220P_OK)
2228         return SANE_STATUS_IO_ERROR;
2229       dev->buflen = length;
2230       DBG (64, "sane_read: got %ld bytes of data from scanner\n", length);
2231 
2232       /* we transform data for software lineart */
2233       if (dev->color == UMAX_PP_MODE_LINEART)
2234         {
2235           DBG (64, "sane_read: software lineart\n");
2236 
2237           for (y = 0; y < length; y++)
2238             {
2239               if (dev->buf[y] > max)
2240                 max = dev->buf[y];
2241               if (dev->buf[y] < min)
2242                 min = dev->buf[y];
2243             }
2244           max = (min + max) / 2;
2245           for (y = 0; y < length; y++)
2246             {
2247               if (dev->buf[y] > max)
2248                 dev->buf[y] = 255;
2249               else
2250                 dev->buf[y] = 0;
2251             }
2252         }
2253       else if (dev->color == UMAX_PP_MODE_COLOR)
2254         {
2255           /* number of lines */
2256           nl = dev->buflen / ll;
2257           DBG (64, "sane_read: reordering %ld bytes of data (lines=%d)\n",
2258                length, nl);
2259           lbuf = (SANE_Byte *) malloc (dev->bufsize + UMAX_PP_RESERVE);
2260           if (lbuf == NULL)
2261             {
2262               DBG (1, "sane_read: couldn't allocate %ld bytes\n",
2263                    dev->bufsize + UMAX_PP_RESERVE);
2264               return SANE_STATUS_NO_MEM;
2265             }
2266           /* reorder data in R,G,B values */
2267           for (y = 0; y < nl; y++)
2268             {
2269               for (x = 0; x < dev->tw; x++)
2270                 {
2271                   switch (sanei_umax_pp_getastra ())
2272                     {
2273                     case 610:
2274                       /* green value: sync'ed */
2275                       lbuf[x * dev->bpp + y * ll + 1 + UMAX_PP_RESERVE] =
2276                         dev->buf[x + y * ll + 2 * dev->tw + UMAX_PP_RESERVE];
2277 
2278                       /* blue value, +delta line ahead of sync */
2279                       lbuf[x * dev->bpp + y * ll + 2 + UMAX_PP_RESERVE] =
2280                         dev->buf[x + (y - delta) * ll + dev->tw +
2281                                  UMAX_PP_RESERVE];
2282 
2283                       /* red value, +2*delta line ahead of sync */
2284                       lbuf[x * dev->bpp + y * ll + UMAX_PP_RESERVE] =
2285                         dev->buf[x + (y - 2 * delta) * ll + UMAX_PP_RESERVE];
2286 
2287                       break;
2288                     default:
2289                       /* red value: sync'ed */
2290                       lbuf[x * dev->bpp + y * ll + UMAX_PP_RESERVE] =
2291                         dev->buf[x + y * ll + 2 * dev->tw + UMAX_PP_RESERVE];
2292 
2293                       /* green value, +delta line ahead of sync */
2294                       lbuf[x * dev->bpp + y * ll + 1 + UMAX_PP_RESERVE] =
2295                         dev->buf[x + (y - delta) * ll + dev->tw +
2296                                  UMAX_PP_RESERVE];
2297 
2298                       /* blue value, +2*delta line ahead of sync */
2299                       lbuf[x * dev->bpp + y * ll + 2 + UMAX_PP_RESERVE] =
2300                         dev->buf[x + (y - 2 * delta) * ll + UMAX_PP_RESERVE];
2301                     }
2302                 }
2303             }
2304           /* store last data lines for next reordering */
2305           if (!last)
2306             memcpy (lbuf + UMAX_PP_RESERVE - 2 * delta * ll,
2307                     dev->buf + UMAX_PP_RESERVE + dev->buflen - 2 * delta * ll,
2308                     2 * delta * ll);
2309           free (dev->buf);
2310           dev->buf = lbuf;
2311         }
2312       dev->bufread = 0;
2313     }
2314 
2315   /* how much get data we can get from memory buffer */
2316   length = dev->buflen - dev->bufread;
2317   DBG (64, "sane_read: %ld bytes of data available\n", length);
2318   if (length > max_len)
2319     length = max_len;
2320 
2321 
2322 
2323   if (dev->color == UMAX_PP_MODE_COLOR)
2324     memcpy (buf, dev->buf + dev->bufread + UMAX_PP_RESERVE, length);
2325   else
2326     memcpy (buf, dev->buf + dev->bufread, length);
2327   *len = length;
2328   dev->bufread += length;
2329   dev->read += length;
2330   DBG (64, "sane_read: %ld bytes read\n", length);
2331 
2332   return SANE_STATUS_GOOD;
2333 
2334 }
2335 
2336 void
sane_cancel(SANE_Handle handle)2337 sane_cancel (SANE_Handle handle)
2338 {
2339   Umax_PP_Device *dev = handle;
2340   int rc;
2341 
2342   DBG (64, "sane_cancel\n");
2343   if (dev->state == UMAX_PP_STATE_IDLE)
2344     {
2345       DBG (3, "cancel: cancelling idle \n");
2346       return;
2347     }
2348   if (dev->state == UMAX_PP_STATE_SCANNING)
2349     {
2350       DBG (3, "cancel: stopping current scan\n");
2351 
2352       dev->buflen = 0;
2353 
2354       dev->state = UMAX_PP_STATE_CANCELLED;
2355       sanei_umax_pp_cancel ();
2356     }
2357   else
2358     {
2359       /* STATE_CANCELLED */
2360       DBG (2, "cancel: checking if scanner is still parking head .... \n");
2361 
2362       rc = sanei_umax_pp_status ();
2363 
2364       /* check if scanner busy parking */
2365       if (rc == UMAX1220P_BUSY)
2366         {
2367           DBG (2, "cancel: scanner busy\n");
2368           return;
2369         }
2370       dev->state = UMAX_PP_STATE_IDLE;
2371     }
2372 }
2373 
2374 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)2375 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2376 {
2377   DBG (129, "unused arg: handle = %p, non_blocking = %d\n",
2378        handle, (int) non_blocking);
2379 
2380   DBG (2, "set_io_mode: not supported\n");
2381 
2382   return SANE_STATUS_UNSUPPORTED;
2383 }
2384 
2385 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)2386 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
2387 {
2388 
2389   DBG (129, "unused arg: handle = %p, fd = %p\n", handle, (void *) fd);
2390 
2391   DBG (2, "get_select_fd: not supported\n");
2392 
2393   return SANE_STATUS_UNSUPPORTED;
2394 }
2395