1 /*
2 Copyright (C) 2008, Panasonic Russia Ltd.
3 */
4 /* sane - Scanner Access Now Easy.
5 Panasonic KV-S1020C / KV-S1025C USB scanners.
6 */
7
8 #define DEBUG_DECLARE_ONLY
9
10 #include "../include/sane/config.h"
11
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22
23 #include "../include/sane/sane.h"
24 #include "../include/sane/saneopts.h"
25 #include "../include/sane/sanei.h"
26 #include "../include/sane/sanei_usb.h"
27 #include "../include/sane/sanei_backend.h"
28 #include "../include/sane/sanei_config.h"
29 #include "../include/lassert.h"
30
31 #include "kvs1025.h"
32 #include "kvs1025_low.h"
33
34 #include "../include/sane/sanei_debug.h"
35
36 /* Option lists */
37
38 static SANE_String_Const go_scan_mode_list[] = {
39 SANE_I18N ("bw"),
40 SANE_I18N ("halftone"),
41 SANE_I18N ("gray"),
42 SANE_I18N ("color"),
43 NULL
44 };
45
46 /*
47 static int go_scan_mode_val[] = {
48 0x00,
49 0x01,
50 0x02,
51 0x05
52 };*/
53
54 static const SANE_Word go_resolutions_list[] = {
55 11, /* list size */
56 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600
57 };
58
59 /* List of scan sources */
60 static SANE_String_Const go_scan_source_list[] = {
61 SANE_I18N ("adf"),
62 SANE_I18N ("fb"),
63 NULL
64 };
65 static const int go_scan_source_val[] = {
66 0,
67 0x1
68 };
69
70 /* List of feeder modes */
71 static SANE_String_Const go_feeder_mode_list[] = {
72 SANE_I18N ("single"),
73 SANE_I18N ("continuous"),
74 NULL
75 };
76 static const int go_feeder_mode_val[] = {
77 0x00,
78 0xff
79 };
80
81 /* List of manual feed mode */
82 static SANE_String_Const go_manual_feed_list[] = {
83 SANE_I18N ("off"),
84 SANE_I18N ("wait_doc"),
85 SANE_I18N ("wait_key"),
86 NULL
87 };
88 static const int go_manual_feed_val[] = {
89 0x00,
90 0x01,
91 0x02
92 };
93
94 /* List of paper sizes */
95 static SANE_String_Const go_paper_list[] = {
96 SANE_I18N ("user_def"),
97 SANE_I18N ("business_card"),
98 SANE_I18N ("Check"),
99 /*SANE_I18N ("A3"), */
100 SANE_I18N ("A4"),
101 SANE_I18N ("A5"),
102 SANE_I18N ("A6"),
103 SANE_I18N ("Letter"),
104 /*SANE_I18N ("Double letter 11x17 in"),
105 SANE_I18N ("B4"), */
106 SANE_I18N ("B5"),
107 SANE_I18N ("B6"),
108 SANE_I18N ("Legal"),
109 NULL
110 };
111 static const int go_paper_val[] = {
112 0x00,
113 0x01,
114 0x02,
115 /*0x03, *//* A3 : not supported */
116 0x04,
117 0x05,
118 0x06,
119 0x07,
120 /*0x09,
121 0x0C, *//* Dbl letter and B4 : not supported */
122 0x0D,
123 0x0E,
124 0x0F
125 };
126
127 static const KV_PAPER_SIZE go_paper_sizes[] = {
128 {210, 297}, /* User defined, default=A4 */
129 {54, 90}, /* Business card */
130 {80, 170}, /* Check (China business) */
131 /*{297, 420}, *//* A3 */
132 {210, 297}, /* A4 */
133 {148, 210}, /* A5 */
134 {105, 148}, /* A6 */
135 {216, 280}, /* US Letter 8.5 x 11 in */
136 /*{280, 432}, *//* Double Letter 11 x 17 in */
137 /*{250, 353}, *//* B4 */
138 {176, 250}, /* B5 */
139 {125, 176}, /* B6 */
140 {216, 356} /* US Legal */
141 };
142
143 static const int default_paper_size_idx = 3; /* A4 */
144
145 /* Lists of supported halftone. They are only valid with
146 * for the Black&White mode. */
147 static SANE_String_Const go_halftone_pattern_list[] = {
148 SANE_I18N ("bayer_64"),
149 SANE_I18N ("bayer_16"),
150 SANE_I18N ("halftone_32"),
151 SANE_I18N ("halftone_64"),
152 SANE_I18N ("diffusion"),
153 NULL
154 };
155 static const int go_halftone_pattern_val[] = {
156 0x00,
157 0x01,
158 0x02,
159 0x03,
160 0x04
161 };
162
163 /* List of automatic threshold options */
164 static SANE_String_Const go_automatic_threshold_list[] = {
165 SANE_I18N ("normal"),
166 SANE_I18N ("light"),
167 SANE_I18N ("dark"),
168 NULL
169 };
170 static const int go_automatic_threshold_val[] = {
171 0,
172 0x11,
173 0x1f
174 };
175
176 /* List of white level base. */
177 static SANE_String_Const go_white_level_list[] = {
178 SANE_I18N ("From scanner"),
179 SANE_I18N ("From paper"),
180 SANE_I18N ("Automatic"),
181 NULL
182 };
183 static const int go_white_level_val[] = {
184 0x00,
185 0x80,
186 0x81
187 };
188
189 /* List of noise reduction options. */
190 static SANE_String_Const go_noise_reduction_list[] = {
191 SANE_I18N ("default"),
192 "1x1",
193 "2x2",
194 "3x3",
195 "4x4",
196 "5x5",
197 NULL
198 };
199 static const int go_noise_reduction_val[] = {
200 0x00,
201 0x01,
202 0x02,
203 0x03,
204 0x04,
205 0x05
206 };
207
208 /* List of image emphasis options, 5 steps */
209 static SANE_String_Const go_image_emphasis_list[] = {
210 SANE_I18N ("smooth"),
211 SANE_I18N ("none"),
212 SANE_I18N ("low"),
213 SANE_I18N ("medium"), /* default */
214 SANE_I18N ("high"),
215 NULL
216 };
217 static const int go_image_emphasis_val[] = {
218 0x14,
219 0x00,
220 0x11,
221 0x12,
222 0x13
223 };
224
225 /* List of gamma */
226 static SANE_String_Const go_gamma_list[] = {
227 SANE_I18N ("normal"),
228 SANE_I18N ("crt"),
229 SANE_I18N ("linear"),
230 NULL
231 };
232 static const int go_gamma_val[] = {
233 0x00,
234 0x01,
235 0x02
236 };
237
238 /* List of lamp color dropout */
239 static SANE_String_Const go_lamp_list[] = {
240 SANE_I18N ("normal"),
241 SANE_I18N ("red"),
242 SANE_I18N ("green"),
243 SANE_I18N ("blue"),
244 NULL
245 };
246 static const int go_lamp_val[] = {
247 0x00,
248 0x01,
249 0x02,
250 0x03
251 };
252
253 static SANE_Range go_value_range = { 0, 255, 0 };
254
255 static SANE_Range go_jpeg_compression_range = { 0, 0x64, 0 };
256
257 static SANE_Range go_rotate_range = { 0, 270, 90 };
258
259 static SANE_Range go_swdespeck_range = { 0, 9, 1 };
260
261 static SANE_Range go_swskip_range = { SANE_FIX(0), SANE_FIX(100), 1 };
262
263 static const char *go_option_name[] = {
264 "OPT_NUM_OPTS",
265
266 /* General options */
267 "OPT_MODE_GROUP",
268 "OPT_MODE", /* scanner modes */
269 "OPT_RESOLUTION", /* X and Y resolution */
270 "OPT_DUPLEX", /* Duplex mode */
271 "OPT_SCAN_SOURCE", /* Scan source, fixed to ADF */
272 "OPT_FEEDER_MODE", /* Feeder mode, fixed to Continuous */
273 "OPT_LONGPAPER", /* Long paper mode */
274 "OPT_LENGTHCTL", /* Length control mode */
275 "OPT_MANUALFEED", /* Manual feed mode */
276 "OPT_FEED_TIMEOUT", /* Feed timeout */
277 "OPT_DBLFEED", /* Double feed detection mode */
278 "OPT_FIT_TO_PAGE", /* Scanner shrinks image to fit scanned page */
279
280 /* Geometry group */
281 "OPT_GEOMETRY_GROUP",
282 "OPT_PAPER_SIZE", /* Paper size */
283 "OPT_LANDSCAPE", /* true if landscape */
284 "OPT_TL_X", /* upper left X */
285 "OPT_TL_Y", /* upper left Y */
286 "OPT_BR_X", /* bottom right X */
287 "OPT_BR_Y", /* bottom right Y */
288
289 "OPT_ENHANCEMENT_GROUP",
290 "OPT_BRIGHTNESS", /* Brightness */
291 "OPT_CONTRAST", /* Contrast */
292 "OPT_AUTOMATIC_THRESHOLD", /* Binary threshold */
293 "OPT_HALFTONE_PATTERN", /* Halftone pattern */
294 "OPT_AUTOMATIC_SEPARATION", /* Automatic separation */
295 "OPT_WHITE_LEVEL", /* White level */
296 "OPT_NOISE_REDUCTION", /* Noise reduction */
297 "OPT_IMAGE_EMPHASIS", /* Image emphasis */
298 "OPT_GAMMA", /* Gamma */
299 "OPT_LAMP", /* Lamp -- color drop out */
300 "OPT_INVERSE", /* Inverse image */
301 "OPT_MIRROR", /* Mirror image */
302 "OPT_JPEG", /* JPEG Compression */
303 "OPT_ROTATE", /* Rotate image */
304
305 "OPT_SWDESKEW", /* Software deskew */
306 "OPT_SWDESPECK", /* Software despeckle */
307 "OPT_SWDEROTATE", /* Software detect/correct 90 deg. rotation */
308 "OPT_SWCROP", /* Software autocrop */
309 "OPT_SWSKIP", /* Software blank page skip */
310
311 /* must come last: */
312 "OPT_NUM_OPTIONS"
313 };
314
315
316 /* Round to boundry, return 1 if value modified */
317 static int
round_to_boundry(SANE_Word * pval,SANE_Word boundry,SANE_Word minv,SANE_Word maxv)318 round_to_boundry (SANE_Word * pval, SANE_Word boundry,
319 SANE_Word minv, SANE_Word maxv)
320 {
321 SANE_Word lower, upper, k, v;
322
323 v = *pval;
324 k = v / boundry;
325 lower = k * boundry;
326 upper = (k + 1) * boundry;
327
328 if (v - lower <= upper - v)
329 {
330 *pval = lower;
331 }
332 else
333 {
334 *pval = upper;
335 }
336
337 if ((*pval) < minv)
338 *pval = minv;
339 if ((*pval) > maxv)
340 *pval = maxv;
341
342 return ((*pval) != v);
343 }
344
345 /* Returns the length of the longest string, including the terminating
346 * character. */
347 static size_t
max_string_size(SANE_String_Const * strings)348 max_string_size (SANE_String_Const * strings)
349 {
350 size_t size, max_size = 0;
351 int i;
352
353 for (i = 0; strings[i]; ++i)
354 {
355 size = strlen (strings[i]) + 1;
356 if (size > max_size)
357 {
358 max_size = size;
359 }
360 }
361
362 return max_size;
363 }
364
365 /* Lookup a string list from one array and return its index. */
366 static int
get_string_list_index(const SANE_String_Const * list,SANE_String_Const name)367 get_string_list_index (const SANE_String_Const * list, SANE_String_Const name)
368 {
369 int index;
370
371 index = 0;
372 while (list[index] != NULL)
373 {
374 if (strcmp (list[index], name) == 0)
375 {
376 return (index);
377 }
378 index++;
379 }
380
381 DBG (DBG_error, "System bug: option %s not found in list\n", name);
382
383 return (-1); /* not found */
384 }
385
386
387 /* Lookup a string list from one array and return the correnpond value. */
388 int
get_optval_list(const PKV_DEV dev,int idx,const SANE_String_Const * str_list,const int * val_list)389 get_optval_list (const PKV_DEV dev, int idx,
390 const SANE_String_Const * str_list, const int *val_list)
391 {
392 int index;
393
394 index = get_string_list_index (str_list, dev->val[idx].s);
395
396 if (index < 0)
397 index = 0;
398
399 return val_list[index];
400 }
401
402
403 /* Get device mode from device options */
404 KV_SCAN_MODE
kv_get_mode(const PKV_DEV dev)405 kv_get_mode (const PKV_DEV dev)
406 {
407 int i;
408
409 i = get_string_list_index (go_scan_mode_list, dev->val[OPT_MODE].s);
410
411 switch (i)
412 {
413 case 0:
414 return SM_BINARY;
415 case 1:
416 return SM_DITHER;
417 case 2:
418 return SM_GRAYSCALE;
419 case 3:
420 return SM_COLOR;
421 default:
422 assert (0 == 1);
423 return 0;
424 }
425 }
426
427 void
kv_calc_paper_size(const PKV_DEV dev,int * w,int * h)428 kv_calc_paper_size (const PKV_DEV dev, int *w, int *h)
429 {
430 int i = get_string_list_index (go_paper_list,
431 dev->val[OPT_PAPER_SIZE].s);
432 if (i == 0)
433 { /* Non-standard document */
434 int x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w));
435 int y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w));
436 int x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w));
437 int y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w));
438 *w = x_br - x_tl;
439 *h = y_br - y_tl;
440 }
441 else
442 {
443 if (dev->val[OPT_LANDSCAPE].s)
444 {
445 *h = mmToIlu (go_paper_sizes[i].width);
446 *w = mmToIlu (go_paper_sizes[i].height);
447 }
448 else
449 {
450 *w = mmToIlu (go_paper_sizes[i].width);
451 *h = mmToIlu (go_paper_sizes[i].height);
452 }
453 }
454 }
455
456 /* Get bit depth from scan mode */
457 int
kv_get_depth(KV_SCAN_MODE mode)458 kv_get_depth (KV_SCAN_MODE mode)
459 {
460 switch (mode)
461 {
462 case SM_BINARY:
463 case SM_DITHER:
464 return 1;
465 case SM_GRAYSCALE:
466 return 8;
467 case SM_COLOR:
468 return 24;
469 default:
470 assert (0 == 1);
471 return 0;
472 }
473 }
474
475 const SANE_Option_Descriptor *
kv_get_option_descriptor(PKV_DEV dev,SANE_Int option)476 kv_get_option_descriptor (PKV_DEV dev, SANE_Int option)
477 {
478 DBG (DBG_proc, "sane_get_option_descriptor: enter, option %s\n",
479 go_option_name[option]);
480
481 if ((unsigned) option >= OPT_NUM_OPTIONS)
482 {
483 return NULL;
484 }
485
486 DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
487
488 return dev->opt + option;
489 }
490
491 /* Reset the options for that scanner. */
492 void
kv_init_options(PKV_DEV dev)493 kv_init_options (PKV_DEV dev)
494 {
495 int i;
496
497 if (dev->option_set)
498 return;
499
500 DBG (DBG_proc, "kv_init_options: enter\n");
501
502 /* Pre-initialize the options. */
503 memset (dev->opt, 0, sizeof (dev->opt));
504 memset (dev->val, 0, sizeof (dev->val));
505
506 for (i = 0; i < OPT_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 /* Number of options. */
513 dev->opt[OPT_NUM_OPTS].name = "";
514 dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
515 dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
516 dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
517 dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
518 dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS;
519
520 /* Mode group */
521 dev->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
522 dev->opt[OPT_MODE_GROUP].desc = ""; /* not valid for a group */
523 dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
524 dev->opt[OPT_MODE_GROUP].cap = 0;
525 dev->opt[OPT_MODE_GROUP].size = 0;
526 dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
527
528 /* Scanner supported modes */
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].size = max_string_size (go_scan_mode_list);
534 dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
535 dev->opt[OPT_MODE].constraint.string_list = go_scan_mode_list;
536 dev->val[OPT_MODE].s = strdup (""); /* will be set later */
537
538 /* X and Y 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_INT;
543 dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
544 dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
545 dev->opt[OPT_RESOLUTION].constraint.word_list = go_resolutions_list;
546 dev->val[OPT_RESOLUTION].w = go_resolutions_list[3];
547
548 /* Duplex */
549 dev->opt[OPT_DUPLEX].name = SANE_NAME_DUPLEX;
550 dev->opt[OPT_DUPLEX].title = SANE_TITLE_DUPLEX;
551 dev->opt[OPT_DUPLEX].desc = SANE_DESC_DUPLEX;
552 dev->opt[OPT_DUPLEX].type = SANE_TYPE_BOOL;
553 dev->opt[OPT_DUPLEX].unit = SANE_UNIT_NONE;
554 dev->val[OPT_DUPLEX].w = SANE_FALSE;
555 if (!dev->support_info.support_duplex)
556 dev->opt[OPT_DUPLEX].cap |= SANE_CAP_INACTIVE;
557
558 /* Scan source */
559 dev->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE;
560 dev->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
561 dev->opt[OPT_SCAN_SOURCE].desc = SANE_I18N ("Sets the scan source");
562 dev->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING;
563 dev->opt[OPT_SCAN_SOURCE].size = max_string_size (go_scan_source_list);
564 dev->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
565 dev->opt[OPT_SCAN_SOURCE].constraint.string_list = go_scan_source_list;
566 dev->val[OPT_SCAN_SOURCE].s = strdup (go_scan_source_list[0]);
567 dev->opt[OPT_SCAN_SOURCE].cap &= ~SANE_CAP_SOFT_SELECT;
568 /* for KV-S1020C / KV-S1025C, scan source is fixed to ADF */
569
570 /* Feeder mode */
571 dev->opt[OPT_FEEDER_MODE].name = "feeder-mode";
572 dev->opt[OPT_FEEDER_MODE].title = SANE_I18N ("Feeder mode");
573 dev->opt[OPT_FEEDER_MODE].desc = SANE_I18N ("Sets the feeding mode");
574 dev->opt[OPT_FEEDER_MODE].type = SANE_TYPE_STRING;
575 dev->opt[OPT_FEEDER_MODE].size = max_string_size (go_feeder_mode_list);
576 dev->opt[OPT_FEEDER_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
577 dev->opt[OPT_FEEDER_MODE].constraint.string_list = go_feeder_mode_list;
578 dev->val[OPT_FEEDER_MODE].s = strdup (go_feeder_mode_list[1]);
579
580 /* Long paper */
581 dev->opt[OPT_LONGPAPER].name = SANE_NAME_LONGPAPER;
582 dev->opt[OPT_LONGPAPER].title = SANE_TITLE_LONGPAPER;
583 dev->opt[OPT_LONGPAPER].desc = SANE_I18N ("Enable/Disable long paper mode");
584 dev->opt[OPT_LONGPAPER].type = SANE_TYPE_BOOL;
585 dev->opt[OPT_LONGPAPER].unit = SANE_UNIT_NONE;
586 dev->val[OPT_LONGPAPER].w = SANE_FALSE;
587
588 /* Length control */
589 dev->opt[OPT_LENGTHCTL].name = SANE_NAME_LENGTHCTL;
590 dev->opt[OPT_LENGTHCTL].title = SANE_TITLE_LENGTHCTL;
591 dev->opt[OPT_LENGTHCTL].desc =
592 SANE_I18N ("Enable/Disable length control mode");
593 dev->opt[OPT_LENGTHCTL].type = SANE_TYPE_BOOL;
594 dev->opt[OPT_LENGTHCTL].unit = SANE_UNIT_NONE;
595 dev->val[OPT_LENGTHCTL].w = SANE_TRUE;
596
597 /* Manual feed */
598 dev->opt[OPT_MANUALFEED].name = SANE_NAME_MANUALFEED;
599 dev->opt[OPT_MANUALFEED].title = SANE_TITLE_MANUALFEED;
600 dev->opt[OPT_MANUALFEED].desc = SANE_I18N ("Sets the manual feed mode");
601 dev->opt[OPT_MANUALFEED].type = SANE_TYPE_STRING;
602 dev->opt[OPT_MANUALFEED].size = max_string_size (go_manual_feed_list);
603 dev->opt[OPT_MANUALFEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
604 dev->opt[OPT_MANUALFEED].constraint.string_list = go_manual_feed_list;
605 dev->val[OPT_MANUALFEED].s = strdup (go_manual_feed_list[0]);
606
607 /*Manual feed timeout */
608 dev->opt[OPT_FEED_TIMEOUT].name = SANE_NAME_FEED_TIMEOUT;
609 dev->opt[OPT_FEED_TIMEOUT].title = SANE_TITLE_FEED_TIMEOUT;
610 dev->opt[OPT_FEED_TIMEOUT].desc =
611 SANE_I18N ("Sets the manual feed timeout in seconds");
612 dev->opt[OPT_FEED_TIMEOUT].type = SANE_TYPE_INT;
613 dev->opt[OPT_FEED_TIMEOUT].unit = SANE_UNIT_NONE;
614 dev->opt[OPT_FEED_TIMEOUT].size = sizeof (SANE_Int);
615 dev->opt[OPT_FEED_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE;
616 dev->opt[OPT_FEED_TIMEOUT].constraint.range = &(go_value_range);
617 dev->opt[OPT_FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE;
618 dev->val[OPT_FEED_TIMEOUT].w = 30;
619
620 /* Double feed */
621 dev->opt[OPT_DBLFEED].name = SANE_NAME_DBLFEED;
622 dev->opt[OPT_DBLFEED].title = SANE_TITLE_DBLFEED;
623 dev->opt[OPT_DBLFEED].desc =
624 SANE_I18N ("Enable/Disable double feed detection");
625 dev->opt[OPT_DBLFEED].type = SANE_TYPE_BOOL;
626 dev->opt[OPT_DBLFEED].unit = SANE_UNIT_NONE;
627 dev->val[OPT_DBLFEED].w = SANE_FALSE;
628
629 /* Fit to page */
630 dev->opt[OPT_FIT_TO_PAGE].name = SANE_I18N ("fit-to-page");
631 dev->opt[OPT_FIT_TO_PAGE].title = SANE_I18N ("Fit to page");
632 dev->opt[OPT_FIT_TO_PAGE].desc =
633 SANE_I18N ("Scanner shrinks image to fit scanned page");
634 dev->opt[OPT_FIT_TO_PAGE].type = SANE_TYPE_BOOL;
635 dev->opt[OPT_FIT_TO_PAGE].unit = SANE_UNIT_NONE;
636 dev->val[OPT_FIT_TO_PAGE].w = SANE_FALSE;
637
638 /* Geometry group */
639 dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
640 dev->opt[OPT_GEOMETRY_GROUP].desc = ""; /* not valid for a group */
641 dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
642 dev->opt[OPT_GEOMETRY_GROUP].cap = 0;
643 dev->opt[OPT_GEOMETRY_GROUP].size = 0;
644 dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
645
646 /* Paper sizes list */
647 dev->opt[OPT_PAPER_SIZE].name = SANE_NAME_PAPER_SIZE;
648 dev->opt[OPT_PAPER_SIZE].title = SANE_TITLE_PAPER_SIZE;
649 dev->opt[OPT_PAPER_SIZE].desc = SANE_DESC_PAPER_SIZE;
650 dev->opt[OPT_PAPER_SIZE].type = SANE_TYPE_STRING;
651 dev->opt[OPT_PAPER_SIZE].size = max_string_size (go_paper_list);
652 dev->opt[OPT_PAPER_SIZE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
653 dev->opt[OPT_PAPER_SIZE].constraint.string_list = go_paper_list;
654 dev->val[OPT_PAPER_SIZE].s = strdup (""); /* will be set later */
655
656 /* Landscape */
657 dev->opt[OPT_LANDSCAPE].name = SANE_NAME_LANDSCAPE;
658 dev->opt[OPT_LANDSCAPE].title = SANE_TITLE_LANDSCAPE;
659 dev->opt[OPT_LANDSCAPE].desc =
660 SANE_I18N ("Set paper position : "
661 "true for landscape, false for portrait");
662 dev->opt[OPT_LANDSCAPE].type = SANE_TYPE_BOOL;
663 dev->opt[OPT_LANDSCAPE].unit = SANE_UNIT_NONE;
664 dev->val[OPT_LANDSCAPE].w = SANE_FALSE;
665
666 /* Upper left X */
667 dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
668 dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
669 dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
670 dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
671 dev->opt[OPT_TL_X].unit = SANE_UNIT_MM;
672 dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
673 dev->opt[OPT_TL_X].constraint.range = &(dev->x_range);
674
675 /* Upper left Y */
676 dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
677 dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
678 dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
679 dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
680 dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
681 dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
682 dev->opt[OPT_TL_Y].constraint.range = &(dev->y_range);
683
684 /* Bottom-right x */
685 dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
686 dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
687 dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
688 dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
689 dev->opt[OPT_BR_X].unit = SANE_UNIT_MM;
690 dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
691 dev->opt[OPT_BR_X].constraint.range = &(dev->x_range);
692
693 /* Bottom-right y */
694 dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
695 dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
696 dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
697 dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
698 dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
699 dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
700 dev->opt[OPT_BR_Y].constraint.range = &(dev->y_range);
701
702 /* Enhancement group */
703 dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
704 dev->opt[OPT_ENHANCEMENT_GROUP].desc = ""; /* not valid for a group */
705 dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
706 dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
707 dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
708 dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
709
710 /* Brightness */
711 dev->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
712 dev->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
713 dev->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
714 dev->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
715 dev->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
716 dev->opt[OPT_BRIGHTNESS].size = sizeof (SANE_Int);
717 dev->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
718 dev->opt[OPT_BRIGHTNESS].constraint.range = &(go_value_range);
719 dev->val[OPT_BRIGHTNESS].w = 128;
720
721 /* Contrast */
722 dev->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
723 dev->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
724 dev->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
725 dev->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
726 dev->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
727 dev->opt[OPT_CONTRAST].size = sizeof (SANE_Int);
728 dev->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
729 dev->opt[OPT_CONTRAST].constraint.range = &(go_value_range);
730 dev->val[OPT_CONTRAST].w = 128;
731
732 /* Automatic threshold */
733 dev->opt[OPT_AUTOMATIC_THRESHOLD].name = "automatic-threshold";
734 dev->opt[OPT_AUTOMATIC_THRESHOLD].title = SANE_I18N ("Automatic threshold");
735 dev->opt[OPT_AUTOMATIC_THRESHOLD].desc =
736 SANE_I18N
737 ("Automatically sets brightness, contrast, white level, "
738 "gamma, noise reduction and image emphasis");
739 dev->opt[OPT_AUTOMATIC_THRESHOLD].type = SANE_TYPE_STRING;
740 dev->opt[OPT_AUTOMATIC_THRESHOLD].size =
741 max_string_size (go_automatic_threshold_list);
742 dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint_type =
743 SANE_CONSTRAINT_STRING_LIST;
744 dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint.string_list =
745 go_automatic_threshold_list;
746 dev->val[OPT_AUTOMATIC_THRESHOLD].s =
747 strdup (go_automatic_threshold_list[0]);
748
749 /* Halftone pattern */
750 dev->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
751 dev->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
752 dev->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
753 dev->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
754 dev->opt[OPT_HALFTONE_PATTERN].size =
755 max_string_size (go_halftone_pattern_list);
756 dev->opt[OPT_HALFTONE_PATTERN].constraint_type =
757 SANE_CONSTRAINT_STRING_LIST;
758 dev->opt[OPT_HALFTONE_PATTERN].constraint.string_list =
759 go_halftone_pattern_list;
760 dev->val[OPT_HALFTONE_PATTERN].s = strdup (go_halftone_pattern_list[0]);
761
762 /* Automatic separation */
763 dev->opt[OPT_AUTOMATIC_SEPARATION].name = SANE_NAME_AUTOSEP;
764 dev->opt[OPT_AUTOMATIC_SEPARATION].title = SANE_TITLE_AUTOSEP;
765 dev->opt[OPT_AUTOMATIC_SEPARATION].desc = SANE_DESC_AUTOSEP;
766 dev->opt[OPT_AUTOMATIC_SEPARATION].type = SANE_TYPE_BOOL;
767 dev->opt[OPT_AUTOMATIC_SEPARATION].unit = SANE_UNIT_NONE;
768 dev->val[OPT_AUTOMATIC_SEPARATION].w = SANE_FALSE;
769
770 /* White level base */
771 dev->opt[OPT_WHITE_LEVEL].name = SANE_NAME_WHITE_LEVEL;
772 dev->opt[OPT_WHITE_LEVEL].title = SANE_TITLE_WHITE_LEVEL;
773 dev->opt[OPT_WHITE_LEVEL].desc = SANE_DESC_WHITE_LEVEL;
774 dev->opt[OPT_WHITE_LEVEL].type = SANE_TYPE_STRING;
775 dev->opt[OPT_WHITE_LEVEL].size = max_string_size (go_white_level_list);
776 dev->opt[OPT_WHITE_LEVEL].constraint_type = SANE_CONSTRAINT_STRING_LIST;
777 dev->opt[OPT_WHITE_LEVEL].constraint.string_list = go_white_level_list;
778 dev->val[OPT_WHITE_LEVEL].s = strdup (go_white_level_list[0]);
779
780 /* Noise reduction */
781 dev->opt[OPT_NOISE_REDUCTION].name = "noise-reduction";
782 dev->opt[OPT_NOISE_REDUCTION].title = SANE_I18N ("Noise reduction");
783 dev->opt[OPT_NOISE_REDUCTION].desc =
784 SANE_I18N ("Reduce the isolated dot noise");
785 dev->opt[OPT_NOISE_REDUCTION].type = SANE_TYPE_STRING;
786 dev->opt[OPT_NOISE_REDUCTION].size =
787 max_string_size (go_noise_reduction_list);
788 dev->opt[OPT_NOISE_REDUCTION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
789 dev->opt[OPT_NOISE_REDUCTION].constraint.string_list =
790 go_noise_reduction_list;
791 dev->val[OPT_NOISE_REDUCTION].s = strdup (go_noise_reduction_list[0]);
792
793 /* Image emphasis */
794 dev->opt[OPT_IMAGE_EMPHASIS].name = "image-emphasis";
795 dev->opt[OPT_IMAGE_EMPHASIS].title = SANE_I18N ("Image emphasis");
796 dev->opt[OPT_IMAGE_EMPHASIS].desc = SANE_I18N ("Sets the image emphasis");
797 dev->opt[OPT_IMAGE_EMPHASIS].type = SANE_TYPE_STRING;
798 dev->opt[OPT_IMAGE_EMPHASIS].size =
799 max_string_size (go_image_emphasis_list);
800 dev->opt[OPT_IMAGE_EMPHASIS].constraint_type = SANE_CONSTRAINT_STRING_LIST;
801 dev->opt[OPT_IMAGE_EMPHASIS].constraint.string_list =
802 go_image_emphasis_list;
803 dev->val[OPT_IMAGE_EMPHASIS].s = strdup (SANE_I18N ("medium"));
804
805 /* Gamma */
806 dev->opt[OPT_GAMMA].name = "gamma";
807 dev->opt[OPT_GAMMA].title = SANE_I18N ("Gamma");
808 dev->opt[OPT_GAMMA].desc = SANE_I18N ("Gamma");
809 dev->opt[OPT_GAMMA].type = SANE_TYPE_STRING;
810 dev->opt[OPT_GAMMA].size = max_string_size (go_gamma_list);
811 dev->opt[OPT_GAMMA].constraint_type = SANE_CONSTRAINT_STRING_LIST;
812 dev->opt[OPT_GAMMA].constraint.string_list = go_gamma_list;
813 dev->val[OPT_GAMMA].s = strdup (go_gamma_list[0]);
814
815 /* Lamp color dropout */
816 dev->opt[OPT_LAMP].name = "lamp-color";
817 dev->opt[OPT_LAMP].title = SANE_I18N ("Lamp color");
818 dev->opt[OPT_LAMP].desc = SANE_I18N ("Sets the lamp color (color dropout)");
819 dev->opt[OPT_LAMP].type = SANE_TYPE_STRING;
820 dev->opt[OPT_LAMP].size = max_string_size (go_lamp_list);
821 dev->opt[OPT_LAMP].constraint_type = SANE_CONSTRAINT_STRING_LIST;
822 dev->opt[OPT_LAMP].constraint.string_list = go_lamp_list;
823 dev->val[OPT_LAMP].s = strdup (go_lamp_list[0]);
824 if (!dev->support_info.support_lamp)
825 dev->opt[OPT_LAMP].cap |= SANE_CAP_INACTIVE;
826
827 /* Inverse image */
828 dev->opt[OPT_INVERSE].name = SANE_NAME_INVERSE;
829 dev->opt[OPT_INVERSE].title = SANE_TITLE_INVERSE;
830 dev->opt[OPT_INVERSE].desc =
831 SANE_I18N ("Inverse image in B/W or halftone mode");
832 dev->opt[OPT_INVERSE].type = SANE_TYPE_BOOL;
833 dev->opt[OPT_INVERSE].unit = SANE_UNIT_NONE;
834 dev->val[OPT_INVERSE].w = SANE_FALSE;
835
836 /* Mirror image (left/right flip) */
837 dev->opt[OPT_MIRROR].name = SANE_NAME_MIRROR;
838 dev->opt[OPT_MIRROR].title = SANE_TITLE_MIRROR;
839 dev->opt[OPT_MIRROR].desc = SANE_I18N ("Mirror image (left/right flip)");
840 dev->opt[OPT_MIRROR].type = SANE_TYPE_BOOL;
841 dev->opt[OPT_MIRROR].unit = SANE_UNIT_NONE;
842 dev->val[OPT_MIRROR].w = SANE_FALSE;
843
844 /* JPEG Image Compression */
845 dev->opt[OPT_JPEG].name = "jpeg";
846 dev->opt[OPT_JPEG].title = SANE_I18N ("jpeg compression");
847 dev->opt[OPT_JPEG].desc =
848 SANE_I18N
849 ("JPEG Image Compression with Q parameter, '0' - no compression");
850 dev->opt[OPT_JPEG].type = SANE_TYPE_INT;
851 dev->opt[OPT_JPEG].unit = SANE_UNIT_NONE;
852 dev->opt[OPT_JPEG].size = sizeof (SANE_Int);
853 dev->opt[OPT_JPEG].constraint_type = SANE_CONSTRAINT_RANGE;
854 dev->opt[OPT_JPEG].constraint.range = &(go_jpeg_compression_range);
855 dev->val[OPT_JPEG].w = 0;
856
857 /* Image Rotation */
858 dev->opt[OPT_ROTATE].name = "rotate";
859 dev->opt[OPT_ROTATE].title = SANE_I18N ("Rotate image clockwise");
860 dev->opt[OPT_ROTATE].desc =
861 SANE_I18N("Request driver to rotate pages by a fixed amount");
862 dev->opt[OPT_ROTATE].type = SANE_TYPE_INT;
863 dev->opt[OPT_ROTATE].unit = SANE_UNIT_NONE;
864 dev->opt[OPT_ROTATE].size = sizeof (SANE_Int);
865 dev->opt[OPT_ROTATE].constraint_type = SANE_CONSTRAINT_RANGE;
866 dev->opt[OPT_ROTATE].constraint.range = &(go_rotate_range);
867 dev->val[OPT_ROTATE].w = 0;
868
869 /* Software Deskew */
870 dev->opt[OPT_SWDESKEW].name = "swdeskew";
871 dev->opt[OPT_SWDESKEW].title = SANE_I18N ("Software deskew");
872 dev->opt[OPT_SWDESKEW].desc =
873 SANE_I18N("Request driver to rotate skewed pages digitally");
874 dev->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL;
875 dev->opt[OPT_SWDESKEW].unit = SANE_UNIT_NONE;
876 dev->val[OPT_SWDESKEW].w = SANE_FALSE;
877
878 /* Software Despeckle */
879 dev->opt[OPT_SWDESPECK].name = "swdespeck";
880 dev->opt[OPT_SWDESPECK].title = SANE_I18N ("Software despeckle diameter");
881 dev->opt[OPT_SWDESPECK].desc =
882 SANE_I18N("Maximum diameter of lone dots to remove from scan");
883 dev->opt[OPT_SWDESPECK].type = SANE_TYPE_INT;
884 dev->opt[OPT_SWDESPECK].unit = SANE_UNIT_NONE;
885 dev->opt[OPT_SWDESPECK].size = sizeof (SANE_Int);
886 dev->opt[OPT_SWDESPECK].constraint_type = SANE_CONSTRAINT_RANGE;
887 dev->opt[OPT_SWDESPECK].constraint.range = &(go_swdespeck_range);
888 dev->val[OPT_SWDESPECK].w = 0;
889
890 /* Software Derotate */
891 dev->opt[OPT_SWDEROTATE].name = "swderotate";
892 dev->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate");
893 dev->opt[OPT_SWDEROTATE].desc =
894 SANE_I18N("Request driver to detect and correct 90 degree image rotation");
895 dev->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL;
896 dev->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE;
897 dev->val[OPT_SWDEROTATE].w = SANE_FALSE;
898
899 /* Software Autocrop*/
900 dev->opt[OPT_SWCROP].name = "swcrop";
901 dev->opt[OPT_SWCROP].title = SANE_I18N ("Software automatic cropping");
902 dev->opt[OPT_SWCROP].desc =
903 SANE_I18N("Request driver to remove border from pages digitally");
904 dev->opt[OPT_SWCROP].type = SANE_TYPE_BOOL;
905 dev->opt[OPT_SWCROP].unit = SANE_UNIT_NONE;
906 dev->val[OPT_SWCROP].w = SANE_FALSE;
907
908 /* Software blank page skip */
909 dev->opt[OPT_SWSKIP].name = "swskip";
910 dev->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage");
911 dev->opt[OPT_SWSKIP].desc
912 = SANE_I18N("Request driver to discard pages with low numbers of dark pixels");
913 dev->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED;
914 dev->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT;
915 dev->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE;
916 dev->opt[OPT_SWSKIP].constraint.range = &(go_swskip_range);
917
918 /* Lastly, set the default scan mode. This might change some
919 * values previously set here. */
920 sane_control_option (dev, OPT_PAPER_SIZE, SANE_ACTION_SET_VALUE,
921 (void *) go_paper_list[default_paper_size_idx], NULL);
922 sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE,
923 (void *) go_scan_mode_list[0], NULL);
924
925 DBG (DBG_proc, "kv_init_options: exit\n");
926
927 dev->option_set = 1;
928 }
929
930
931 SANE_Status
kv_control_option(PKV_DEV dev,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)932 kv_control_option (PKV_DEV dev, SANE_Int option,
933 SANE_Action action, void *val, SANE_Int * info)
934 {
935 SANE_Status status;
936 SANE_Word cap;
937 SANE_String_Const name;
938 int i;
939 SANE_Word value;
940
941 DBG (DBG_proc, "sane_control_option: enter, option %s, action %s\n",
942 go_option_name[option], action == SANE_ACTION_GET_VALUE ? "R" : "W");
943
944 if (info)
945 {
946 *info = 0;
947 }
948
949 if (dev->scanning)
950 {
951 return SANE_STATUS_DEVICE_BUSY;
952 }
953
954 if (option < 0 || option >= OPT_NUM_OPTIONS)
955 {
956 return SANE_STATUS_UNSUPPORTED;
957 }
958
959 cap = dev->opt[option].cap;
960 if (!SANE_OPTION_IS_ACTIVE (cap))
961 {
962 return SANE_STATUS_UNSUPPORTED;
963 }
964
965 name = dev->opt[option].name;
966 if (!name)
967 {
968 name = "(no name)";
969 }
970 if (action == SANE_ACTION_GET_VALUE)
971 {
972 switch (option)
973 {
974 /* word options */
975 case OPT_NUM_OPTS:
976 case OPT_LONGPAPER:
977 case OPT_LENGTHCTL:
978 case OPT_DBLFEED:
979 case OPT_RESOLUTION:
980 case OPT_TL_Y:
981 case OPT_BR_Y:
982 case OPT_TL_X:
983 case OPT_BR_X:
984 case OPT_BRIGHTNESS:
985 case OPT_CONTRAST:
986 case OPT_DUPLEX:
987 case OPT_LANDSCAPE:
988 case OPT_AUTOMATIC_SEPARATION:
989 case OPT_INVERSE:
990 case OPT_MIRROR:
991 case OPT_FEED_TIMEOUT:
992 case OPT_JPEG:
993 case OPT_ROTATE:
994 case OPT_SWDESKEW:
995 case OPT_SWDESPECK:
996 case OPT_SWDEROTATE:
997 case OPT_SWCROP:
998 case OPT_SWSKIP:
999 case OPT_FIT_TO_PAGE:
1000 *(SANE_Word *) val = dev->val[option].w;
1001 DBG (DBG_error, "opt value = %d\n", *(SANE_Word *) val);
1002 return SANE_STATUS_GOOD;
1003
1004 /* string options */
1005 case OPT_MODE:
1006 case OPT_FEEDER_MODE:
1007 case OPT_SCAN_SOURCE:
1008 case OPT_MANUALFEED:
1009 case OPT_HALFTONE_PATTERN:
1010 case OPT_PAPER_SIZE:
1011 case OPT_AUTOMATIC_THRESHOLD:
1012 case OPT_WHITE_LEVEL:
1013 case OPT_NOISE_REDUCTION:
1014 case OPT_IMAGE_EMPHASIS:
1015 case OPT_GAMMA:
1016 case OPT_LAMP:
1017
1018 strcpy (val, dev->val[option].s);
1019 DBG (DBG_error, "opt value = %s\n", (char *) val);
1020 return SANE_STATUS_GOOD;
1021
1022 default:
1023 return SANE_STATUS_UNSUPPORTED;
1024 }
1025 }
1026 else if (action == SANE_ACTION_SET_VALUE)
1027 {
1028 if (!SANE_OPTION_IS_SETTABLE (cap))
1029 {
1030 DBG (DBG_error,
1031 "could not set option %s, not settable\n",
1032 go_option_name[option]);
1033 return SANE_STATUS_INVAL;
1034 }
1035
1036 status = sanei_constrain_value (dev->opt + option, val, info);
1037 if (status != SANE_STATUS_GOOD)
1038 {
1039 DBG (DBG_error, "could not set option, invalid value\n");
1040 return status;
1041 }
1042
1043 switch (option)
1044 {
1045 /* Side-effect options */
1046 case OPT_TL_Y:
1047 case OPT_BR_Y:
1048 case OPT_RESOLUTION:
1049 if (info)
1050 {
1051 *info |= SANE_INFO_RELOAD_PARAMS;
1052 }
1053
1054 dev->val[option].w = *(SANE_Word *) val;
1055
1056 if (option == OPT_RESOLUTION)
1057 {
1058 if (round_to_boundry (&(dev->val[option].w),
1059 dev->support_info.
1060 step_resolution, 100, 600))
1061 {
1062 if (info)
1063 {
1064 *info |= SANE_INFO_INEXACT;
1065 }
1066 }
1067 }
1068 else if (option == OPT_TL_Y)
1069 {
1070 if (dev->val[option].w > dev->val[OPT_BR_Y].w)
1071 {
1072 dev->val[option].w = dev->val[OPT_BR_Y].w;
1073 if (info)
1074 {
1075 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1076 }
1077 }
1078 }
1079 else
1080 {
1081 if (dev->val[option].w < dev->val[OPT_TL_Y].w)
1082 {
1083 dev->val[option].w = dev->val[OPT_TL_Y].w;
1084 if (info)
1085 {
1086 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1087 }
1088 }
1089 }
1090
1091 DBG (DBG_error,
1092 "option %s, input = %d, value = %d\n",
1093 go_option_name[option], (*(SANE_Word *) val),
1094 dev->val[option].w);
1095
1096 return SANE_STATUS_GOOD;
1097
1098 /* The length of X must be rounded (up). */
1099 case OPT_TL_X:
1100 case OPT_BR_X:
1101 {
1102 SANE_Word xr = dev->val[OPT_RESOLUTION].w;
1103 SANE_Word tl_x = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w)) * xr;
1104 SANE_Word br_x = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w)) * xr;
1105 value = mmToIlu (SANE_UNFIX (*(SANE_Word *) val)) * xr; /* XR * W */
1106
1107 if (option == OPT_TL_X)
1108 {
1109 SANE_Word max = KV_PIXEL_MAX * xr - KV_PIXEL_ROUND;
1110 if (br_x < max)
1111 max = br_x;
1112 if (round_to_boundry (&value, KV_PIXEL_ROUND, 0, max))
1113 {
1114 if (info)
1115 {
1116 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1117 }
1118 }
1119 }
1120 else
1121 {
1122 if (round_to_boundry
1123 (&value, KV_PIXEL_ROUND, tl_x, KV_PIXEL_MAX * xr))
1124 {
1125 if (info)
1126 {
1127 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1128 }
1129 }
1130 }
1131
1132 dev->val[option].w = SANE_FIX (iluToMm ((double) value / xr));
1133
1134 if (info)
1135 {
1136 *info |= SANE_INFO_RELOAD_PARAMS;
1137 }
1138
1139 DBG (DBG_error,
1140 "option %s, input = %d, value = %d\n",
1141 go_option_name[option], (*(SANE_Word *) val),
1142 dev->val[option].w);
1143 return SANE_STATUS_GOOD;
1144 }
1145 case OPT_LANDSCAPE:
1146 dev->val[option].w = *(SANE_Word *) val;
1147 if (info)
1148 {
1149 *info |= SANE_INFO_RELOAD_PARAMS;
1150 }
1151 return SANE_STATUS_GOOD;
1152
1153 /* Side-effect free options */
1154 case OPT_CONTRAST:
1155 case OPT_BRIGHTNESS:
1156 case OPT_DUPLEX:
1157 case OPT_LONGPAPER:
1158 case OPT_LENGTHCTL:
1159 case OPT_DBLFEED:
1160 case OPT_INVERSE:
1161 case OPT_MIRROR:
1162 case OPT_AUTOMATIC_SEPARATION:
1163 case OPT_JPEG:
1164 case OPT_ROTATE:
1165 case OPT_SWDESKEW:
1166 case OPT_SWDESPECK:
1167 case OPT_SWDEROTATE:
1168 case OPT_SWCROP:
1169 case OPT_SWSKIP:
1170 case OPT_FIT_TO_PAGE:
1171 dev->val[option].w = *(SANE_Word *) val;
1172 return SANE_STATUS_GOOD;
1173
1174 case OPT_FEED_TIMEOUT:
1175 dev->val[option].w = *(SANE_Word *) val;
1176 return CMD_set_timeout (dev, *(SANE_Word *) val);
1177
1178 /* String mode */
1179 case OPT_SCAN_SOURCE:
1180 case OPT_WHITE_LEVEL:
1181 case OPT_NOISE_REDUCTION:
1182 case OPT_IMAGE_EMPHASIS:
1183 case OPT_GAMMA:
1184 case OPT_LAMP:
1185 case OPT_HALFTONE_PATTERN:
1186 case OPT_FEEDER_MODE:
1187 if (strcmp (dev->val[option].s, val) == 0)
1188 return SANE_STATUS_GOOD;
1189 free (dev->val[option].s);
1190 dev->val[option].s = (SANE_String) strdup (val);
1191
1192 if (option == OPT_FEEDER_MODE &&
1193 get_string_list_index (go_feeder_mode_list,
1194 dev->val[option].s) == 1)
1195 /* continuous mode */
1196 {
1197 free (dev->val[OPT_SCAN_SOURCE].s);
1198 dev->val[OPT_SCAN_SOURCE].s = strdup (go_scan_source_list[0]);
1199 dev->opt[OPT_LONGPAPER].cap &= ~SANE_CAP_INACTIVE;
1200 if (info)
1201 *info |= SANE_INFO_RELOAD_OPTIONS;
1202 }
1203 else
1204 {
1205 dev->opt[OPT_LONGPAPER].cap |= SANE_CAP_INACTIVE;
1206 if (info)
1207 *info |= SANE_INFO_RELOAD_OPTIONS;
1208 }
1209
1210 if (option == OPT_SCAN_SOURCE &&
1211 get_string_list_index (go_scan_source_list,
1212 dev->val[option].s) == 1)
1213 /* flatbed */
1214 {
1215 free (dev->val[OPT_FEEDER_MODE].s);
1216 dev->val[OPT_FEEDER_MODE].s = strdup (go_feeder_mode_list[0]);
1217 }
1218
1219 return SANE_STATUS_GOOD;
1220
1221 case OPT_MODE:
1222 if (strcmp (dev->val[option].s, val) == 0)
1223 return SANE_STATUS_GOOD;
1224 free (dev->val[OPT_MODE].s);
1225 dev->val[OPT_MODE].s = (SANE_String) strdup (val);
1226
1227 /* Set default options for the scan modes. */
1228 dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1229 dev->opt[OPT_AUTOMATIC_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1230 dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE;
1231 dev->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
1232 dev->opt[OPT_INVERSE].cap |= SANE_CAP_INACTIVE;
1233 dev->opt[OPT_JPEG].cap &= ~SANE_CAP_INACTIVE;
1234
1235 if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[0]) == 0)
1236 /* binary */
1237 {
1238 dev->opt[OPT_AUTOMATIC_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1239 dev->opt[OPT_INVERSE].cap &= ~SANE_CAP_INACTIVE;
1240 dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE;
1241 }
1242 else if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[1]) == 0)
1243 /* halftone */
1244 {
1245 dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
1246 dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE;
1247 dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1248 dev->opt[OPT_INVERSE].cap &= ~SANE_CAP_INACTIVE;
1249 dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE;
1250 }
1251 else if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[2]) == 0)
1252 /* grayscale */
1253 {
1254 dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1255 }
1256
1257 if (info)
1258 {
1259 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1260 }
1261
1262 return SANE_STATUS_GOOD;
1263
1264 case OPT_MANUALFEED:
1265 if (strcmp (dev->val[option].s, val) == 0)
1266 return SANE_STATUS_GOOD;
1267 free (dev->val[option].s);
1268 dev->val[option].s = (SANE_String) strdup (val);
1269
1270 if (strcmp (dev->val[option].s, go_manual_feed_list[0]) == 0) /* off */
1271 dev->opt[OPT_FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE;
1272 else
1273 dev->opt[OPT_FEED_TIMEOUT].cap &= ~SANE_CAP_INACTIVE;
1274 if (info)
1275 *info |= SANE_INFO_RELOAD_OPTIONS;
1276
1277 return SANE_STATUS_GOOD;
1278
1279 case OPT_PAPER_SIZE:
1280 if (strcmp (dev->val[option].s, val) == 0)
1281 return SANE_STATUS_GOOD;
1282
1283 free (dev->val[OPT_PAPER_SIZE].s);
1284 dev->val[OPT_PAPER_SIZE].s = (SANE_Char *) strdup (val);
1285
1286 i = get_string_list_index (go_paper_list,
1287 dev->val[OPT_PAPER_SIZE].s);
1288 if (i == 0)
1289 { /*user def */
1290 dev->opt[OPT_TL_X].cap &=
1291 dev->opt[OPT_TL_Y].cap &=
1292 dev->opt[OPT_BR_X].cap &=
1293 dev->opt[OPT_BR_Y].cap &= ~SANE_CAP_INACTIVE;
1294 dev->opt[OPT_LANDSCAPE].cap |= SANE_CAP_INACTIVE;
1295 dev->val[OPT_LANDSCAPE].w = 0;
1296 }
1297 else
1298 {
1299 dev->opt[OPT_TL_X].cap |=
1300 dev->opt[OPT_TL_Y].cap |=
1301 dev->opt[OPT_BR_X].cap |=
1302 dev->opt[OPT_BR_Y].cap |= SANE_CAP_INACTIVE;
1303 if (i == 4 || i == 5 || i == 7)
1304 { /*A5, A6 or B6 */
1305 dev->opt[OPT_LANDSCAPE].cap &= ~SANE_CAP_INACTIVE;
1306 }
1307 else
1308 {
1309 dev->opt[OPT_LANDSCAPE].cap |= SANE_CAP_INACTIVE;
1310 dev->val[OPT_LANDSCAPE].w = 0;
1311 }
1312 }
1313
1314 if (info)
1315 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1316
1317 return SANE_STATUS_GOOD;
1318
1319
1320 case OPT_AUTOMATIC_THRESHOLD:
1321 if (strcmp (dev->val[option].s, val) == 0)
1322 return SANE_STATUS_GOOD;
1323
1324 free (dev->val[option].s);
1325 dev->val[option].s = (SANE_Char *) strdup (val);
1326
1327 /* If the threshold is not set to none, some option must
1328 * disappear. */
1329
1330 dev->opt[OPT_WHITE_LEVEL].cap |= SANE_CAP_INACTIVE;
1331 dev->opt[OPT_NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE;
1332 dev->opt[OPT_IMAGE_EMPHASIS].cap |= SANE_CAP_INACTIVE;
1333 dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE;
1334 dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1335
1336 if (strcmp (val, go_automatic_threshold_list[0]) == 0)
1337 {
1338 dev->opt[OPT_WHITE_LEVEL].cap &= ~SANE_CAP_INACTIVE;
1339 dev->opt[OPT_NOISE_REDUCTION].cap &= ~SANE_CAP_INACTIVE;
1340 dev->opt[OPT_IMAGE_EMPHASIS].cap &= ~SANE_CAP_INACTIVE;
1341 dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE;
1342 if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[1]) == 0)
1343 {
1344 dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
1345 }
1346 }
1347
1348 if (info)
1349 {
1350 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1351 }
1352 return SANE_STATUS_GOOD;
1353
1354 default:
1355 return SANE_STATUS_INVAL;
1356 }
1357 }
1358
1359 DBG (DBG_proc, "sane_control_option: exit, bad\n");
1360
1361 return SANE_STATUS_UNSUPPORTED;
1362 }
1363
1364 /* Display a buffer in the log. */
1365 void
hexdump(int level,const char * comment,unsigned char * p,int l)1366 hexdump (int level, const char *comment, unsigned char *p, int l)
1367 {
1368 int i;
1369 char line[128];
1370 char *ptr;
1371
1372 DBG (level, "%s\n", comment);
1373 ptr = line;
1374 for (i = 0; i < l; i++, p++)
1375 {
1376 if ((i % 16) == 0)
1377 {
1378 if (ptr != line)
1379 {
1380 *ptr = '\0';
1381 DBG (level, "%s\n", line);
1382 ptr = line;
1383 }
1384 sprintf (ptr, "%3.3d:", i);
1385 ptr += 4;
1386 }
1387 sprintf (ptr, " %2.2x", *p);
1388 ptr += 3;
1389 }
1390 *ptr = '\0';
1391 DBG (level, "%s\n", line);
1392 }
1393
1394 /* Set window data */
1395 void
kv_set_window_data(PKV_DEV dev,KV_SCAN_MODE scan_mode,int side,unsigned char * windowdata)1396 kv_set_window_data (PKV_DEV dev,
1397 KV_SCAN_MODE scan_mode,
1398 int side, unsigned char *windowdata)
1399 {
1400 int paper = go_paper_val[get_string_list_index (go_paper_list,
1401 dev->val[OPT_PAPER_SIZE].
1402 s)];
1403
1404 /* Page side */
1405 windowdata[0] = side;
1406
1407 /* X and Y resolution */
1408 Ito16 (dev->val[OPT_RESOLUTION].w, &windowdata[2]);
1409 Ito16 (dev->val[OPT_RESOLUTION].w, &windowdata[4]);
1410
1411 /* Width and length */
1412 if (paper == 0)
1413 { /* Non-standard document */
1414 int x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w));
1415 int y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w));
1416 int x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w));
1417 int y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w));
1418 int width = x_br - x_tl;
1419 int length = y_br - y_tl;
1420 /* Upper Left (X,Y) */
1421 Ito32 (x_tl, &windowdata[6]);
1422 Ito32 (y_tl, &windowdata[10]);
1423
1424 Ito32 (width, &windowdata[14]);
1425 Ito32 (length, &windowdata[18]);
1426 Ito32 (width, &windowdata[48]); /* device specific */
1427 Ito32 (length, &windowdata[52]); /* device specific */
1428 }
1429
1430 /* Brightness */
1431 windowdata[22] = 255 - GET_OPT_VAL_W (dev, OPT_BRIGHTNESS);
1432 windowdata[23] = windowdata[22]; /* threshold, same as brightness. */
1433
1434 /* Contrast */
1435 windowdata[24] = GET_OPT_VAL_W (dev, OPT_CONTRAST);
1436
1437 /* Image Composition */
1438 windowdata[25] = (unsigned char) scan_mode;
1439
1440 /* Depth */
1441 windowdata[26] = kv_get_depth (scan_mode);
1442
1443 /* Halftone pattern. */
1444 if (scan_mode == SM_DITHER)
1445 {
1446 windowdata[28] = GET_OPT_VAL_L (dev, OPT_HALFTONE_PATTERN,
1447 halftone_pattern);
1448 }
1449
1450 /* Inverse */
1451 if (scan_mode == SM_BINARY || scan_mode == SM_DITHER)
1452 {
1453 windowdata[29] = GET_OPT_VAL_W (dev, OPT_INVERSE);
1454 }
1455
1456 /* Bit ordering */
1457 windowdata[31] = 1;
1458
1459 /*Compression Type */
1460 if (!(dev->opt[OPT_JPEG].cap & SANE_CAP_INACTIVE)
1461 && GET_OPT_VAL_W (dev, OPT_JPEG))
1462 {
1463 windowdata[32] = 0x81; /*jpeg */
1464 /*Compression Argument */
1465 windowdata[33] = GET_OPT_VAL_W (dev, OPT_JPEG);
1466 }
1467
1468 /* Gamma */
1469 if (scan_mode == SM_DITHER || scan_mode == SM_GRAYSCALE)
1470 {
1471 windowdata[44] = GET_OPT_VAL_L (dev, OPT_GAMMA, gamma);
1472 }
1473
1474 /* Feeder mode */
1475 windowdata[57] = GET_OPT_VAL_L (dev, OPT_FEEDER_MODE, feeder_mode);
1476
1477 /* Stop skew -- disabled */
1478 windowdata[41] = 0;
1479
1480 /* Scan source */
1481 if (GET_OPT_VAL_L (dev, OPT_SCAN_SOURCE, scan_source))
1482 { /* flatbed */
1483 windowdata[41] |= 0x80;
1484 }
1485 else
1486 {
1487 windowdata[41] &= 0x7f;
1488 }
1489
1490 /* Paper size */
1491 windowdata[47] = paper;
1492
1493 if (paper) /* Standard Document */
1494 windowdata[47] |= 1 << 7;
1495
1496 /* Long paper */
1497 if (GET_OPT_VAL_W (dev, OPT_LONGPAPER))
1498 {
1499 windowdata[47] |= 0x20;
1500 }
1501
1502 /* Length control */
1503 if (GET_OPT_VAL_W (dev, OPT_LENGTHCTL))
1504 {
1505 windowdata[47] |= 0x40;
1506 }
1507
1508 /* Landscape */
1509 if (GET_OPT_VAL_W (dev, OPT_LANDSCAPE))
1510 {
1511 windowdata[47] |= 1 << 4;
1512 }
1513 /* Double feed */
1514 if (GET_OPT_VAL_W (dev, OPT_DBLFEED))
1515 {
1516 windowdata[56] = 0x10;
1517 }
1518
1519 /* Fit to page */
1520 if (GET_OPT_VAL_W (dev, OPT_FIT_TO_PAGE))
1521 {
1522 windowdata[56] |= 1 << 2;
1523 }
1524
1525 /* Manual feed */
1526 windowdata[62] = GET_OPT_VAL_L (dev, OPT_MANUALFEED, manual_feed) << 6;
1527
1528 /* Mirror image */
1529 if (GET_OPT_VAL_W (dev, OPT_MIRROR))
1530 {
1531 windowdata[42] = 0x80;
1532 }
1533
1534 /* Image emphasis */
1535 windowdata[43] = GET_OPT_VAL_L (dev, OPT_IMAGE_EMPHASIS, image_emphasis);
1536
1537 /* White level */
1538 windowdata[60] = GET_OPT_VAL_L (dev, OPT_WHITE_LEVEL, white_level);
1539
1540 if (scan_mode == SM_BINARY || scan_mode == SM_DITHER)
1541 {
1542 /* Noise reduction */
1543 windowdata[61] = GET_OPT_VAL_L (dev, OPT_NOISE_REDUCTION,
1544 noise_reduction);
1545
1546 /* Automatic separation */
1547 if (scan_mode == SM_DITHER && GET_OPT_VAL_W (dev,
1548 OPT_AUTOMATIC_SEPARATION))
1549 {
1550 windowdata[59] = 0x80;
1551 }
1552 }
1553
1554 /* Automatic threshold. Must be last because it may override
1555 * some previous options. */
1556 if (scan_mode == SM_BINARY)
1557 {
1558 windowdata[58] =
1559 GET_OPT_VAL_L (dev, OPT_AUTOMATIC_THRESHOLD, automatic_threshold);
1560 }
1561
1562 if (windowdata[58] != 0)
1563 {
1564 /* Automatic threshold is enabled. */
1565 windowdata[22] = 0; /* brightness. */
1566 windowdata[23] = 0; /* threshold, same as brightness. */
1567 windowdata[24] = 0; /* contrast */
1568 windowdata[27] = windowdata[28] = 0; /* Halftone pattern. */
1569 windowdata[43] = 0; /* Image emphasis */
1570 windowdata[59] = 0; /* Automatic separation */
1571 windowdata[60] = 0; /* White level */
1572 windowdata[61] = 0; /* Noise reduction */
1573 }
1574
1575 /* lamp -- color dropout */
1576 windowdata[45] = GET_OPT_VAL_L (dev, OPT_LAMP, lamp) << 4;
1577
1578 /*Stop Mode: After 1 page */
1579 windowdata[63] = 1;
1580 }
1581