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