• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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