1 /*
2    Copyright (C) 2009, Panasonic Russia Ltd.
3    Copyright (C) 2010,2011, m. allan noah
4 */
5 /*
6    Panasonic KV-S40xx USB-SCSI scanner driver.
7 */
8 
9 #include "../include/sane/config.h"
10 
11 #include <string.h>
12 #define DEBUG_DECLARE_ONLY
13 #define BACKEND_NAME kvs40xx
14 
15 #include "../include/sane/sanei_backend.h"
16 #include "../include/sane/saneopts.h"
17 #include "../include/sane/sanei.h"
18 #include "../include/sane/sanei_config.h"
19 #include "lassert.h"
20 
21 #include "kvs40xx.h"
22 
23 #include "../include/sane/sanei_debug.h"
24 
25 #include <stdlib.h>
26 
27 static inline unsigned
mm2scanner_units(unsigned mm)28 mm2scanner_units (unsigned mm)
29 {
30   return (mm * 12000 / 254.0 + .5);
31 }
32 static inline unsigned
scanner_units2mm(unsigned u)33 scanner_units2mm (unsigned u)
34 {
35   return (u * 254.0 / 12000 + .5);
36 }
37 struct restriction
38 {
39   unsigned ux, uy, ux_pix, uy_pix;
40 };
41 
42 static struct restriction flatbad = { 14064, 20400, 7031, 63999 };
43 static struct restriction cw = { 14268, 128000, 7133, 63999 };
44 static struct restriction cl = { 10724, 128000, 5361, 63999 };
45 
46 static inline int
check_area(struct scanner * s,unsigned ux,unsigned uy,unsigned bx,unsigned by)47 check_area (struct scanner *s, unsigned ux,
48 	    unsigned uy, unsigned bx, unsigned by)
49 {
50   int fb = !strcmp (s->val[SOURCE].s, SANE_I18N ("fb"));
51   struct restriction *r = fb ? &flatbad
52     : (s->id == KV_S4085CL || s->id == KV_S4065CL) ? &cl : &cw;
53   unsigned res = s->val[RESOLUTION].w;
54   unsigned w = bx - ux;
55   unsigned h = by - uy;
56   unsigned c1 = mm2scanner_units (ux + w);
57   unsigned c2 = mm2scanner_units (uy + h);
58   int c = c1 <= r->ux && c1 >= 16 && c2 >= 1 && c2 <= r->uy ? 0 : -1;
59   if (c)
60     return c;
61   if (mm2scanner_units (ux) > r->ux)
62     return -1;
63   if (res * mm2scanner_units (ux) / 1200 > r->ux_pix)
64     return -1;
65 
66   if (res * mm2scanner_units (uy) / 1200 > r->uy_pix)
67     return -1;
68   return 0;
69 }
70 
71 static size_t
max_string_size(const SANE_String_Const strings[])72 max_string_size (const SANE_String_Const strings[])
73 {
74   size_t size, max_size = 0;
75   SANE_Int i;
76 
77   for (i = 0; strings[i]; ++i)
78     {
79       size = strlen (strings[i]) + 1;
80       if (size > max_size)
81 	max_size = size;
82     }
83   return max_size;
84 }
85 
86 static SANE_String_Const mode_list[] = {
87   SANE_VALUE_SCAN_MODE_LINEART,
88   SANE_VALUE_SCAN_MODE_GRAY,
89   SANE_VALUE_SCAN_MODE_COLOR,
90   NULL
91 };
92 static const unsigned mode_val[] = { 0, 2, 5 };
93 static const unsigned bps_val[] = { 1, 8, 24 };
94 
95 static const SANE_Range resolutions_range = {
96   100,600,1
97 };
98 
99 /* List of feeder modes */
100 static SANE_String_Const feeder_mode_list[] = {
101   SANE_I18N ("single"),
102   SANE_I18N ("continuous"),
103   NULL
104 };
105 
106 /* List of scan sources */
107 static SANE_String_Const source_list[] = {
108   SANE_I18N ("adf"),
109   SANE_I18N ("fb"),
110   NULL
111 };
112 
113 /* List of manual feed mode */
114 static SANE_String_Const manual_feed_list[] = {
115   SANE_I18N ("off"),
116   SANE_I18N ("wait_doc"),
117   SANE_I18N ("wait_doc_hopper_up"),
118   SANE_I18N ("wait_key"),
119   NULL
120 };
121 
122 /* List of paper sizes */
123 static SANE_String_Const paper_list[] = {
124   SANE_I18N ("user_def"),
125   SANE_I18N ("business_card"),
126   SANE_I18N ("Check"),
127   SANE_I18N ("A3"),
128   SANE_I18N ("A4"),
129   SANE_I18N ("A5"),
130   SANE_I18N ("A6"),
131   SANE_I18N ("Letter"),
132   SANE_I18N ("Double letter 11x17 in"),
133   SANE_I18N ("B4"),
134   SANE_I18N ("B5"),
135   SANE_I18N ("B6"),
136   SANE_I18N ("Legal"),
137   NULL
138 };
139 
140 static SANE_String_Const paper_list_woA3[] = {
141   SANE_I18N ("user_def"),
142   SANE_I18N ("business_card"),
143   SANE_I18N ("Check"),
144   /*SANE_I18N ("A3"), */
145   SANE_I18N ("A4"),
146   SANE_I18N ("A5"),
147   SANE_I18N ("A6"),
148   SANE_I18N ("Letter"),
149   /*SANE_I18N ("Double letter 11x17 in"), */
150   /*SANE_I18N ("B4"), */
151   SANE_I18N ("B5"),
152   SANE_I18N ("B6"),
153   SANE_I18N ("Legal"),
154   NULL
155 };
156 
157 static const unsigned paper_val[] = { 0, 1, 2, 3, 4, 5, 6, 7,
158   9, 12, 13, 14, 15
159 };
160 
161 struct paper_size
162 {
163   int width;
164   int height;
165 };
166 static const struct paper_size paper_sizes[] = {
167   {210, 297},			/* User defined, default=A4 */
168   {54, 90},			/* Business card */
169   {80, 170},			/* Check (China business) */
170   {297, 420},			/* A3 */
171   {210, 297},			/* A4 */
172   {148, 210},			/* A5 */
173   {105, 148},			/* A6 */
174   {215, 280},			/* US Letter 8.5 x 11 in */
175   {280, 432},			/* Double Letter 11 x 17 in */
176   {250, 353},			/* B4 */
177   {176, 250},			/* B5 */
178   {125, 176},			/* B6 */
179   {215, 355}			/* US Legal */
180 };
181 
182 #define MIN_WIDTH	48
183 #define MIN_LENGTH	70
184 #define MAX_WIDTH	297
185 #define MAX_LENGTH	432
186 
187 #define MAX_WIDTH_A4	227
188 #define MAX_LENGTH_A4	432
189 
190 static SANE_Range tl_x_range = { 0, MAX_WIDTH - MIN_WIDTH, 0 };
191 static SANE_Range tl_y_range = { 0, MAX_LENGTH - MIN_LENGTH, 0 };
192 static SANE_Range br_x_range = { MIN_WIDTH, MAX_WIDTH, 0 };
193 static SANE_Range br_y_range = { MIN_LENGTH, MAX_LENGTH, 0 };
194 
195 static SANE_Range tl_x_range_A4 = { 0, MAX_WIDTH_A4 - MIN_WIDTH, 0 };
196 static SANE_Range tl_y_range_A4 = { 0, MAX_LENGTH_A4 - MIN_LENGTH, 0 };
197 static SANE_Range br_x_range_A4 = { MIN_WIDTH, MAX_WIDTH_A4, 0 };
198 static SANE_Range br_y_range_A4 = { MIN_LENGTH, MAX_LENGTH_A4, 0 };
199 
200 static SANE_Range byte_value_range = { 0, 255, 0 };
201 static SANE_Range compression_value_range = { 1, 0x64, 0 };
202 
203 /* List of image emphasis options, 5 steps */
204 static SANE_String_Const image_emphasis_list[] = {
205   SANE_I18N ("none"),
206   SANE_I18N ("low"),
207   SANE_I18N ("medium"),
208   SANE_I18N ("high"),
209   SANE_I18N ("smooth"),
210   NULL
211 };
212 
213 /* List of gamma */
214 static SANE_String_Const gamma_list[] = {
215   SANE_I18N ("normal"),
216   SANE_I18N ("crt"),
217   NULL
218 };
219 static unsigned gamma_val[] = { 0, 1 };
220 
221 /* List of lamp color dropout */
222 static SANE_String_Const lamp_list[] = {
223   SANE_I18N ("normal"),
224   SANE_I18N ("red"),
225   SANE_I18N ("green"),
226   SANE_I18N ("blue"),
227   NULL
228 };
229 static SANE_String_Const dfeed_sence_list[] = {
230   SANE_I18N ("Normal"),
231   SANE_I18N ("High sensitivity"),
232   SANE_I18N ("Low sensitivity"),
233   NULL
234 };
235 
236 /* Lists of supported halftone. They are only valid with
237  * for the Black&White mode. */
238 static SANE_String_Const halftone_pattern[] = {
239   SANE_I18N ("bayer_64"),
240   SANE_I18N ("bayer_16"),
241   SANE_I18N ("halftone_32"),
242   SANE_I18N ("halftone_64"),
243   SANE_I18N ("err_diffusion"),
244   NULL
245 };
246 
247 /*  Stapled document */
248 static SANE_String_Const stapeled_list[] = {
249   SANE_I18N ("No detection"),
250   SANE_I18N ("Normal mode"),
251   SANE_I18N ("Enhanced mode"),
252   NULL
253 };
254 
255 
256 /* List of automatic threshold options */
257 static SANE_String_Const automatic_threshold_list[] = {
258   SANE_I18N ("normal"),
259   SANE_I18N ("light"),
260   SANE_I18N ("dark"),
261   NULL
262 };
263 static const int automatic_threshold_val[] = {
264   0,
265   0x11,
266   0x1f
267 };
268 
269 /* List of white level base. */
270 static SANE_String_Const white_level_list[] = {
271   SANE_I18N ("From scanner"),
272   SANE_I18N ("From paper"),
273   SANE_I18N ("Automatic"),
274   NULL
275 };
276 static const int white_level_val[] = {
277   0x00,
278   0x80,
279   0x81
280 };
281 
282 /* List of noise reduction options. */
283 static SANE_String_Const noise_reduction_list[] = {
284   SANE_I18N ("default"),
285   "1x1",
286   "2x2",
287   "3x3",
288   "4x4",
289   "5x5",
290   NULL
291 };
292 
293 /* Reset the options for that scanner. */
294 void
kvs40xx_init_options(struct scanner * s)295 kvs40xx_init_options (struct scanner *s)
296 {
297   int i;
298   SANE_Option_Descriptor *o;
299   /* Pre-initialize the options. */
300   memset (s->opt, 0, sizeof (s->opt));
301   memset (s->val, 0, sizeof (s->val));
302 
303   for (i = 0; i < NUM_OPTIONS; i++)
304     {
305       s->opt[i].size = sizeof (SANE_Word);
306       s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
307     }
308 
309   /* Number of options. */
310   o = &s->opt[NUM_OPTS];
311   o->name = "";
312   o->title = SANE_TITLE_NUM_OPTIONS;
313   o->desc = SANE_DESC_NUM_OPTIONS;
314   o->type = SANE_TYPE_INT;
315   o->cap = SANE_CAP_SOFT_DETECT;
316   s->val[NUM_OPTS].w = NUM_OPTIONS;
317 
318   /* Mode group */
319   o = &s->opt[MODE_GROUP];
320   o->title = SANE_I18N ("Scan Mode");
321   o->desc = "";			/* not valid for a group */
322   o->type = SANE_TYPE_GROUP;
323   o->cap = 0;
324   o->size = 0;
325   o->constraint_type = SANE_CONSTRAINT_NONE;
326 
327   /* Scanner supported modes */
328   o = &s->opt[MODE];
329   o->name = SANE_NAME_SCAN_MODE;
330   o->title = SANE_TITLE_SCAN_MODE;
331   o->desc = SANE_DESC_SCAN_MODE;
332   o->type = SANE_TYPE_STRING;
333   o->size = max_string_size (mode_list);
334   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
335   o->constraint.string_list = mode_list;
336   s->val[MODE].s = malloc (o->size);
337   strcpy (s->val[MODE].s, mode_list[2]);
338 
339   /* X and Y resolution */
340   o = &s->opt[RESOLUTION];
341   o->name = SANE_NAME_SCAN_RESOLUTION;
342   o->title = SANE_TITLE_SCAN_RESOLUTION;
343   o->desc = SANE_DESC_SCAN_RESOLUTION;
344   o->type = SANE_TYPE_INT;
345   o->unit = SANE_UNIT_DPI;
346   o->constraint_type = SANE_CONSTRAINT_RANGE;
347   o->constraint.range = &resolutions_range;
348   s->val[RESOLUTION].w = 100;
349 
350   /* Duplex */
351   o = &s->opt[DUPLEX];
352   o->name = "duplex";
353   o->title = SANE_I18N ("Duplex");
354   o->desc = SANE_I18N ("Enable Duplex (Dual-Sided) Scanning");
355   o->type = SANE_TYPE_BOOL;
356   o->unit = SANE_UNIT_NONE;
357   s->val[DUPLEX].w = SANE_FALSE;
358 
359   /*FIXME
360      if (!s->support_info.support_duplex)
361      o->cap |= SANE_CAP_INACTIVE;
362    */
363 
364   /* Feeder mode */
365   o = &s->opt[FEEDER_MODE];
366   o->name = "feeder-mode";
367   o->title = SANE_I18N ("Feeder mode");
368   o->desc = SANE_I18N ("Sets the feeding mode");
369   o->type = SANE_TYPE_STRING;
370   o->size = max_string_size (feeder_mode_list);
371   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
372   o->constraint.string_list = feeder_mode_list;
373   s->val[FEEDER_MODE].s = malloc (o->size);
374   strcpy (s->val[FEEDER_MODE].s, feeder_mode_list[0]);
375 
376   /* Scan source */
377   o = &s->opt[SOURCE];
378   o->name = SANE_NAME_SCAN_SOURCE;
379   o->title = SANE_TITLE_SCAN_SOURCE;
380   o->desc = SANE_DESC_SCAN_SOURCE;
381   o->type = SANE_TYPE_STRING;
382   o->size = max_string_size (source_list);
383   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
384   o->constraint.string_list = source_list;
385   s->val[SOURCE].s = malloc (o->size);
386   strcpy (s->val[SOURCE].s, source_list[0]);
387   if (s->id != KV_S7075C)
388     o->cap |= SANE_CAP_INACTIVE;
389 
390   /* Length control */
391   o = &s->opt[LENGTHCTL];
392   o->name = "length-control";
393   o->title = SANE_I18N ("Length control mode");
394   o->desc =
395     SANE_I18N
396     ("Length Control Mode causes the scanner to read the shorter of either the length of the actual"
397      " paper or logical document length");
398   o->type = SANE_TYPE_BOOL;
399   o->unit = SANE_UNIT_NONE;
400   s->val[LENGTHCTL].w = SANE_FALSE;
401 
402   o = &s->opt[LONG_PAPER];
403   o->name = "long-paper";
404   o->title = SANE_I18N ("Long paper mode");
405   o->desc = SANE_I18N ("Long Paper Mode is a mode that the scanner "
406 		       "reads the image after it divides long paper "
407 		       "by the length which is set in Document Size option.");
408   o->type = SANE_TYPE_BOOL;
409   o->unit = SANE_UNIT_NONE;
410   s->val[LONG_PAPER].w = SANE_FALSE;
411   o->cap |= SANE_CAP_INACTIVE;
412 
413   /* Manual feed */
414   o = &s->opt[MANUALFEED];
415   o->name = "manual-feed";
416   o->title = SANE_I18N ("Manual feed mode");
417   o->desc = SANE_I18N ("Sets the manual feed mode");
418   o->type = SANE_TYPE_STRING;
419   o->size = max_string_size (manual_feed_list);
420   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
421   o->constraint.string_list = manual_feed_list;
422   s->val[MANUALFEED].s = malloc (o->size);
423   strcpy (s->val[MANUALFEED].s, manual_feed_list[0]);
424 
425   /*Manual feed timeout */
426   o = &s->opt[FEED_TIMEOUT];
427   o->name = "feed-timeout";
428   o->title = SANE_I18N ("Manual feed timeout");
429   o->desc = SANE_I18N ("Sets the manual feed timeout in seconds");
430   o->type = SANE_TYPE_INT;
431   o->unit = SANE_UNIT_NONE;
432   o->size = sizeof (SANE_Int);
433   o->constraint_type = SANE_CONSTRAINT_RANGE;
434   o->constraint.range = &(byte_value_range);
435   o->cap |= SANE_CAP_INACTIVE;
436   s->val[FEED_TIMEOUT].w = 30;
437 
438   /* Double feed */
439   o = &s->opt[DBLFEED];
440   o->name = "dfeed";
441   o->title = SANE_I18N ("Double feed detection");
442   o->desc = SANE_I18N ("Enable/Disable double feed detection");
443   o->type = SANE_TYPE_BOOL;
444   o->unit = SANE_UNIT_NONE;
445   s->val[DBLFEED].w = SANE_FALSE;
446 
447   o = &s->opt[DFEED_SENCE];
448   o->name = "dfeed-sense";
449   o->title = SANE_I18N ("Double feed detector sensitivity");
450   o->desc = SANE_I18N ("Set the double feed detector sensitivity");
451   o->type = SANE_TYPE_STRING;
452   o->size = max_string_size (dfeed_sence_list);
453   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
454   o->constraint.string_list = dfeed_sence_list;
455   s->val[DFEED_SENCE].s = malloc (o->size);
456   strcpy (s->val[DFEED_SENCE].s, dfeed_sence_list[0]);
457   o->cap |= SANE_CAP_INACTIVE;
458 
459   o = &s->opt[DFSTOP];
460   o->name = "dfstop";
461   o->title = SANE_I18N ("Do not stop after double feed detection");
462   o->desc = SANE_I18N ("Do not stop after double feed detection");
463   o->type = SANE_TYPE_BOOL;
464   o->unit = SANE_UNIT_NONE;
465   s->val[DFSTOP].w = SANE_FALSE;
466   o->cap |= SANE_CAP_INACTIVE;
467 
468   o = &s->opt[DFEED_L];
469   o->name = "dfeed_l";
470   o->title = SANE_I18N ("Ignore left double feed sensor");
471   o->desc = SANE_I18N ("Ignore left double feed sensor");
472   o->type = SANE_TYPE_BOOL;
473   o->unit = SANE_UNIT_NONE;
474   s->val[DFEED_L].w = SANE_FALSE;
475   o->cap |= SANE_CAP_INACTIVE;
476 
477   o = &s->opt[DFEED_C];
478   o->name = "dfeed_c";
479   o->title = SANE_I18N ("Ignore center double feed sensor");
480   o->desc = SANE_I18N ("Ignore center double feed sensor");
481   o->type = SANE_TYPE_BOOL;
482   o->unit = SANE_UNIT_NONE;
483   s->val[DFEED_C].w = SANE_FALSE;
484   o->cap |= SANE_CAP_INACTIVE;
485 
486   o = &s->opt[DFEED_R];
487   o->name = "dfeed_r";
488   o->title = SANE_I18N ("Ignore right double feed sensor");
489   o->desc = SANE_I18N ("Ignore right double feed sensor");
490   o->type = SANE_TYPE_BOOL;
491   o->unit = SANE_UNIT_NONE;
492   s->val[DFEED_R].w = SANE_FALSE;
493   o->cap |= SANE_CAP_INACTIVE;
494 
495   /* Fit to page */
496   o = &s->opt[FIT_TO_PAGE];
497   o->name = SANE_I18N ("fit-to-page");
498   o->title = SANE_I18N ("Fit to page");
499   o->desc = SANE_I18N ("Scanner shrinks image to fit scanned page");
500   o->type = SANE_TYPE_BOOL;
501   o->unit = SANE_UNIT_NONE;
502   s->val[FIT_TO_PAGE].w = SANE_FALSE;
503 
504   /* Geometry group */
505   o = &s->opt[GEOMETRY_GROUP];
506   o->title = SANE_I18N ("Geometry");
507   o->desc = "";			/* not valid for a group */
508   o->type = SANE_TYPE_GROUP;
509   o->cap = 0;
510   o->size = 0;
511   o->constraint_type = SANE_CONSTRAINT_NONE;
512 
513   /* Paper sizes list */
514   o = &s->opt[PAPER_SIZE];
515   o->name = "paper-size";
516   o->title = SANE_I18N ("Paper size");
517   o->desc = SANE_I18N ("Physical size of the paper in the ADF");
518   o->type = SANE_TYPE_STRING;
519   o->constraint.string_list =
520     s->id == KV_S4085CL || s->id == KV_S4065CL ? paper_list_woA3 : paper_list;
521 
522 
523   o->size = max_string_size (o->constraint.string_list);
524   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
525   s->val[PAPER_SIZE].s = malloc (o->size);
526   strcpy (s->val[PAPER_SIZE].s, SANE_I18N ("A4"));
527 
528   /* Landscape */
529   o = &s->opt[LANDSCAPE];
530   o->name = "landscape";
531   o->title = SANE_I18N ("Landscape");
532   o->desc =
533     SANE_I18N ("Set paper position : "
534 	       "true for landscape, false for portrait");
535   o->type = SANE_TYPE_BOOL;
536   o->unit = SANE_UNIT_NONE;
537   s->val[LANDSCAPE].w = SANE_FALSE;
538 
539   /* Upper left X */
540   o = &s->opt[TL_X];
541   o->name = SANE_NAME_SCAN_TL_X;
542   o->title = SANE_TITLE_SCAN_TL_X;
543   o->desc = SANE_DESC_SCAN_TL_X;
544   o->type = SANE_TYPE_INT;
545   o->unit = SANE_UNIT_MM;
546   o->constraint_type = SANE_CONSTRAINT_RANGE;
547   o->constraint.range =
548     (s->id == KV_S4085CL || s->id == KV_S4065CL)
549     ? &tl_x_range_A4 : &tl_x_range;
550   o->cap |= SANE_CAP_INACTIVE;
551   s->val[TL_X].w = 0;
552 
553   /* Upper left Y */
554   o = &s->opt[TL_Y];
555   o->name = SANE_NAME_SCAN_TL_Y;
556   o->title = SANE_TITLE_SCAN_TL_Y;
557   o->desc = SANE_DESC_SCAN_TL_Y;
558   o->type = SANE_TYPE_INT;
559   o->unit = SANE_UNIT_MM;
560   o->constraint_type = SANE_CONSTRAINT_RANGE;
561   o->constraint.range =
562     (s->id == KV_S4085CL || s->id == KV_S4065CL)
563     ? &tl_y_range_A4 : &tl_y_range;
564   o->cap |= SANE_CAP_INACTIVE;
565   s->val[TL_Y].w = 0;
566 
567   /* Bottom-right x */
568   o = &s->opt[BR_X];
569   o->name = SANE_NAME_SCAN_BR_X;
570   o->title = SANE_TITLE_SCAN_BR_X;
571   o->desc = SANE_DESC_SCAN_BR_X;
572   o->type = SANE_TYPE_INT;
573   o->unit = SANE_UNIT_MM;
574   o->constraint_type = SANE_CONSTRAINT_RANGE;
575   o->constraint.range =
576     (s->id == KV_S4085CL || s->id == KV_S4065CL)
577     ? &br_x_range_A4 : &br_x_range;
578   o->cap |= SANE_CAP_INACTIVE;
579   s->val[BR_X].w = 210;
580 
581   /* Bottom-right y */
582   o = &s->opt[BR_Y];
583   o->name = SANE_NAME_SCAN_BR_Y;
584   o->title = SANE_TITLE_SCAN_BR_Y;
585   o->desc = SANE_DESC_SCAN_BR_Y;
586   o->type = SANE_TYPE_INT;
587   o->unit = SANE_UNIT_MM;
588   o->constraint_type = SANE_CONSTRAINT_RANGE;
589   o->constraint.range =
590     (s->id == KV_S4085CL || s->id == KV_S4065CL)
591     ? &br_y_range_A4 : &br_y_range;
592   o->cap |= SANE_CAP_INACTIVE;
593   s->val[BR_Y].w = 297;
594 
595   /* Enhancement group */
596   o = &s->opt[ADVANCED_GROUP];
597   o->title = SANE_I18N ("Advanced");
598   o->desc = "";			/* not valid for a group */
599   o->type = SANE_TYPE_GROUP;
600   o->cap = SANE_CAP_ADVANCED;
601   o->size = 0;
602   o->constraint_type = SANE_CONSTRAINT_NONE;
603 
604   /* Brightness */
605   o = &s->opt[BRIGHTNESS];
606   o->name = SANE_NAME_BRIGHTNESS;
607   o->title = SANE_TITLE_BRIGHTNESS;
608   o->desc = SANE_DESC_BRIGHTNESS;
609   o->type = SANE_TYPE_INT;
610   o->unit = SANE_UNIT_NONE;
611   o->size = sizeof (SANE_Int);
612   o->constraint_type = SANE_CONSTRAINT_RANGE;
613   o->constraint.range = &(byte_value_range);
614   s->val[BRIGHTNESS].w = 128;
615 
616   /* Contrast */
617   o = &s->opt[CONTRAST];
618   o->name = SANE_NAME_CONTRAST;
619   o->title = SANE_TITLE_CONTRAST;
620   o->desc = SANE_DESC_CONTRAST;
621   o->type = SANE_TYPE_INT;
622   o->unit = SANE_UNIT_NONE;
623   o->size = sizeof (SANE_Int);
624   o->constraint_type = SANE_CONSTRAINT_RANGE;
625   o->constraint.range = &(byte_value_range);
626   s->val[CONTRAST].w = 128;
627 
628   /* threshold */
629   o = &s->opt[THRESHOLD];
630   o->name = SANE_NAME_THRESHOLD;
631   o->title = SANE_TITLE_THRESHOLD;
632   o->desc = SANE_DESC_THRESHOLD;
633   o->type = SANE_TYPE_INT;
634   o->size = sizeof (SANE_Int);
635   o->constraint_type = SANE_CONSTRAINT_RANGE;
636   o->constraint.range = &(byte_value_range);
637   s->val[THRESHOLD].w = 128;
638   o->cap |= SANE_CAP_INACTIVE;
639 
640   o = &s->opt[AUTOMATIC_THRESHOLD];
641   o->name = "athreshold";
642   o->title = SANE_I18N ("Automatic threshold mode");
643   o->desc = SANE_I18N ("Sets the automatic threshold mode");
644   o->type = SANE_TYPE_STRING;
645   o->size = max_string_size (automatic_threshold_list);
646   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
647   o->constraint.string_list = automatic_threshold_list;
648   s->val[AUTOMATIC_THRESHOLD].s = malloc (o->size);
649   strcpy (s->val[AUTOMATIC_THRESHOLD].s, automatic_threshold_list[0]);
650   o->cap |= SANE_CAP_INACTIVE;
651 
652   /* Image emphasis */
653   o = &s->opt[IMAGE_EMPHASIS];
654   o->name = "image-emphasis";
655   o->title = SANE_I18N ("Image emphasis");
656   o->desc = SANE_I18N ("Sets the image emphasis");
657   o->type = SANE_TYPE_STRING;
658   o->size = max_string_size (image_emphasis_list);
659   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
660   o->constraint.string_list = image_emphasis_list;
661   s->val[IMAGE_EMPHASIS].s = malloc (o->size);
662   strcpy (s->val[IMAGE_EMPHASIS].s, image_emphasis_list[0]);;
663   o->cap |= SANE_CAP_INACTIVE;
664 
665   /* Gamma */
666   o = &s->opt[GAMMA_CORRECTION];
667   o->name = "gamma-cor";
668   o->title = SANE_I18N ("Gamma correction");
669   o->desc = SANE_I18N ("Gamma correction");
670   o->type = SANE_TYPE_STRING;
671   o->size = max_string_size (gamma_list);
672   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
673   o->constraint.string_list = gamma_list;
674   s->val[GAMMA_CORRECTION].s = malloc (o->size);
675   strcpy (s->val[GAMMA_CORRECTION].s, gamma_list[0]);
676   o->cap |= SANE_CAP_INACTIVE;
677 
678   /* Lamp color dropout */
679   o = &s->opt[LAMP];
680   o->name = "lamp-color";
681   o->title = SANE_I18N ("Lamp color");
682   o->desc = SANE_I18N ("Sets the lamp color (color dropout)");
683   o->type = SANE_TYPE_STRING;
684   o->size = max_string_size (lamp_list);
685   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
686   o->constraint.string_list = lamp_list;
687   s->val[LAMP].s = malloc (o->size);
688   strcpy (s->val[LAMP].s, lamp_list[0]);
689 
690   /* Inverse image */
691   o = &s->opt[INVERSE];
692   o->name = "inverse";
693   o->title = SANE_I18N ("Inverse Image");
694   o->desc = SANE_I18N ("Inverse image in B/W mode");
695   o->type = SANE_TYPE_BOOL;
696   o->unit = SANE_UNIT_NONE;
697   o->cap |= SANE_CAP_INACTIVE;
698 
699   /* Halftone pattern */
700   o = &s->opt[HALFTONE_PATTERN];
701   o->name = SANE_NAME_HALFTONE_PATTERN;
702   o->title = SANE_TITLE_HALFTONE_PATTERN;
703   o->desc = SANE_DESC_HALFTONE_PATTERN;
704   o->type = SANE_TYPE_STRING;
705   o->size = max_string_size (halftone_pattern);
706   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
707   o->constraint.string_list = halftone_pattern;
708   s->val[HALFTONE_PATTERN].s = malloc (o->size);
709   strcpy (s->val[HALFTONE_PATTERN].s, halftone_pattern[0]);
710   o->cap |= SANE_CAP_INACTIVE;
711 
712   /* JPEG Compression */
713   o = &s->opt[COMPRESSION];
714   o->name = "jpeg";
715   o->title = SANE_I18N ("JPEG compression");
716   o->desc =
717     SANE_I18N
718     ("JPEG compression (your application must be able to uncompress)");
719   o->type = SANE_TYPE_BOOL;
720   o->unit = SANE_UNIT_NONE;
721 
722   /* Compression parameter */
723   o = &s->opt[COMPRESSION_PAR];
724   o->name = "comp_arg";
725   o->title = "Compression Argument";
726   o->desc = "Compression Argument (Q parameter for JPEG)";
727   o->type = SANE_TYPE_INT;
728   o->size = sizeof (SANE_Int);
729   o->constraint_type = SANE_CONSTRAINT_RANGE;
730   o->constraint.range = &(compression_value_range);
731   s->val[COMPRESSION_PAR].w = 0x4b;
732   o->cap |= SANE_CAP_INACTIVE;
733 
734   /*  Stapled document */
735   o = &s->opt[STAPELED_DOC];
736   o->name = "stapeled_doc";
737   o->title = SANE_I18N ("Detect stapled document");
738   o->desc = SANE_I18N ("Detect stapled document");
739   o->type = SANE_TYPE_STRING;
740   o->size = max_string_size (stapeled_list);
741   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
742   o->constraint.string_list = stapeled_list;
743   s->val[STAPELED_DOC].s = malloc (o->size);
744   strcpy (s->val[STAPELED_DOC].s, stapeled_list[0]);
745   if (s->id == KV_S7075C)
746     o->cap |= SANE_CAP_INACTIVE;
747 
748   /* White level base */
749   o = &s->opt[WHITE_LEVEL];
750   o->name = SANE_NAME_WHITE_LEVEL;
751   o->title = SANE_TITLE_WHITE_LEVEL;
752   o->desc = SANE_DESC_WHITE_LEVEL;
753   o->type = SANE_TYPE_STRING;
754   o->size = max_string_size (white_level_list);
755   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
756   o->constraint.string_list = white_level_list;
757   s->val[WHITE_LEVEL].s = malloc (o->size);
758   strcpy (s->val[WHITE_LEVEL].s, white_level_list[0]);
759   o->cap |= SANE_CAP_INACTIVE;
760 
761   /* Noise reduction */
762   o = &s->opt[NOISE_REDUCTION];
763   o->name = "noise-reduction";
764   o->title = SANE_I18N ("Noise reduction");
765   o->desc = SANE_I18N ("Reduce the isolated dot noise");
766   o->type = SANE_TYPE_STRING;
767   o->size = max_string_size (noise_reduction_list);
768   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
769   o->constraint.string_list = noise_reduction_list;
770   s->val[NOISE_REDUCTION].s = malloc (o->size);
771   strcpy (s->val[NOISE_REDUCTION].s, noise_reduction_list[0]);
772   o->cap |= SANE_CAP_INACTIVE;
773 
774   o = &s->opt[RED_CHROMA];
775   o->name = "red-chroma";
776   o->title = SANE_I18N ("chroma of red");
777   o->desc = SANE_I18N ("Set chroma of red");
778   o->type = SANE_TYPE_INT;
779   o->unit = SANE_UNIT_NONE;
780   o->size = sizeof (SANE_Int);
781   o->constraint_type = SANE_CONSTRAINT_RANGE;
782   o->constraint.range = &(byte_value_range);
783   s->val[RED_CHROMA].w = 0;
784 
785   o = &s->opt[BLUE_CHROMA];
786   o->name = "blue chroma";
787   o->title = SANE_I18N ("chroma of blue");
788   o->desc = SANE_I18N ("Set chroma of blue");
789   o->type = SANE_TYPE_INT;
790   o->unit = SANE_UNIT_NONE;
791   o->size = sizeof (SANE_Int);
792   o->constraint_type = SANE_CONSTRAINT_RANGE;
793   o->constraint.range = &(byte_value_range);
794   s->val[BLUE_CHROMA].w = 0;
795 
796   o = &s->opt[DESKEW];
797   o->name = "deskew";
798   o->title = SANE_I18N ("Skew adjustment");
799   o->desc = SANE_I18N ("Skew adjustment");
800   o->type = SANE_TYPE_BOOL;
801   o->unit = SANE_UNIT_NONE;
802   s->val[DESKEW].w = SANE_FALSE;
803   if (s->id != KV_S4085CL && s->id != KV_S4085CW)
804     o->cap |= SANE_CAP_INACTIVE;
805 
806   o = &s->opt[STOP_SKEW];
807   o->name = "stop-skew";
808   o->title = SANE_I18N ("Stop scanner if a sheet is skewed");
809   o->desc = SANE_I18N ("Scanner will stop if a sheet is skewed");
810   o->type = SANE_TYPE_BOOL;
811   o->unit = SANE_UNIT_NONE;
812   s->val[STOP_SKEW].w = SANE_FALSE;
813 
814   o = &s->opt[CROP];
815   o->name = "crop";
816   o->title = SANE_I18N ("Crop actual image area");
817   o->desc = SANE_I18N ("Scanner will automatically detect image area and crop to it");
818   o->type = SANE_TYPE_BOOL;
819   o->unit = SANE_UNIT_NONE;
820   s->val[CROP].w = SANE_FALSE;
821   if (s->id != KV_S4085CL && s->id != KV_S4085CW)
822     o->cap |= SANE_CAP_INACTIVE;
823 
824   o = &s->opt[MIRROR];
825   o->name = "mirror";
826   o->title = SANE_I18N ("Mirror image");
827   o->desc = SANE_I18N ("Left/right mirror image");
828   o->type = SANE_TYPE_BOOL;
829   o->unit = SANE_UNIT_NONE;
830   s->val[MIRROR].w = SANE_FALSE;
831 
832   o = &s->opt[TOPPOS];
833   o->name = "toppos";
834   o->title = SANE_I18N ("Addition of space in top position");
835   o->desc = SANE_I18N ("Addition of space in top position");
836   o->type = SANE_TYPE_BOOL;
837   o->unit = SANE_UNIT_NONE;
838   s->val[TOPPOS].w = SANE_FALSE;
839 
840   o = &s->opt[BTMPOS];
841   o->name = "btmpos";
842   o->title = SANE_I18N ("Addition of space in bottom position");
843   o->desc = SANE_I18N ("Addition of space in bottom position");
844   o->type = SANE_TYPE_BOOL;
845   o->unit = SANE_UNIT_NONE;
846   s->val[BTMPOS].w = SANE_FALSE;
847 }
848 
849 
850 /* Lookup a string list from one array and return its index. */
851 static int
str_index(const SANE_String_Const * list,SANE_String_Const name)852 str_index (const SANE_String_Const * list, SANE_String_Const name)
853 {
854   int index;
855   index = 0;
856   while (list[index])
857     {
858       if (!strcmp (list[index], name))
859 	return (index);
860       index++;
861     }
862   return (-1);			/* not found */
863 }
864 
865 /* Control option */
866 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)867 sane_control_option (SANE_Handle handle, SANE_Int option,
868 		     SANE_Action action, void *val, SANE_Int * info)
869 {
870   int i;
871   SANE_Status status;
872   SANE_Word cap;
873   struct scanner *s = (struct scanner *) handle;
874 
875   if (info)
876     *info = 0;
877 
878   if (option < 0 || option >= NUM_OPTIONS)
879     return SANE_STATUS_UNSUPPORTED;
880 
881   cap = s->opt[option].cap;
882   if (!SANE_OPTION_IS_ACTIVE (cap))
883     return SANE_STATUS_UNSUPPORTED;
884 
885   if (action == SANE_ACTION_GET_VALUE)
886     {
887       if (s->opt[option].type == SANE_TYPE_STRING)
888 	{
889 	  DBG (DBG_INFO,
890 	       "sane_control_option: reading opt[%d] =  %s\n",
891 	       option, s->val[option].s);
892 	  strcpy (val, s->val[option].s);
893 	}
894       else
895 	{
896 	  *(SANE_Word *) val = s->val[option].w;
897 	  DBG (DBG_INFO,
898 	       "sane_control_option: reading opt[%d] =  %d\n",
899 	       option, s->val[option].w);
900 	}
901       return SANE_STATUS_GOOD;
902 
903     }
904   else if (action == SANE_ACTION_SET_VALUE)
905     {
906       if (!SANE_OPTION_IS_SETTABLE (cap))
907 	return SANE_STATUS_INVAL;
908 
909       status = sanei_constrain_value (s->opt + option, val, info);
910       if (status != SANE_STATUS_GOOD)
911 	return status;
912 
913       if (s->opt[option].type == SANE_TYPE_STRING)
914 	{
915 	  if (!strcmp (val, s->val[option].s))
916 	    return SANE_STATUS_GOOD;
917 	  DBG (DBG_INFO,
918 	       "sane_control_option: writing opt[%d] =  %s\n",
919 	       option, (SANE_String_Const) val);
920 	}
921       else
922 	{
923 	  if (*(SANE_Word *) val == s->val[option].w)
924 	    return SANE_STATUS_GOOD;
925 	  DBG (DBG_INFO,
926 	       "sane_control_option: writing opt[%d] =  %d\n",
927 	       option, *(SANE_Word *) val);
928 	}
929 
930       switch (option)
931 	{
932 	  /* Side-effect options */
933 	case RESOLUTION:
934 	  s->val[option].w = *(SANE_Word *) val;
935 	  if (info)
936 	    *info |= SANE_INFO_RELOAD_PARAMS;
937 	  return SANE_STATUS_GOOD;
938 
939 	case TL_Y:
940 	  if ((*(SANE_Word *) val) + MIN_LENGTH <=
941 	      s->val[BR_Y].w &&
942 	      !check_area (s, s->val[TL_X].w, *(SANE_Word *) val,
943 			   s->val[BR_X].w, s->val[BR_Y].w))
944 	    {
945 	      s->val[option].w = *(SANE_Word *) val;
946 	      if (info)
947 		*info |= SANE_INFO_RELOAD_PARAMS;
948 	    }
949 	  else if (info)
950 	    *info |= SANE_INFO_INEXACT |
951 	      SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
952 	  return SANE_STATUS_GOOD;
953 	case BR_Y:
954 	  if ((*(SANE_Word *) val) >=
955 	      s->val[TL_Y].w + MIN_LENGTH
956 	      && !check_area (s, s->val[TL_X].w, s->val[TL_Y].w,
957 			      s->val[BR_X].w, *(SANE_Word *) val))
958 	    {
959 	      s->val[option].w = *(SANE_Word *) val;
960 	      if (info)
961 		*info |= SANE_INFO_RELOAD_PARAMS;
962 	    }
963 	  else if (info)
964 	    *info |= SANE_INFO_INEXACT |
965 	      SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
966 	  return SANE_STATUS_GOOD;
967 
968 	case TL_X:
969 	  if ((*(SANE_Word *) val) + MIN_WIDTH <=
970 	      s->val[BR_X].w &&
971 	      !check_area (s, *(SANE_Word *) val, s->val[TL_Y].w,
972 			   s->val[BR_X].w, s->val[BR_Y].w))
973 	    {
974 	      s->val[option].w = *(SANE_Word *) val;
975 	      if (info)
976 		*info |= SANE_INFO_RELOAD_PARAMS;
977 	    }
978 	  else if (info)
979 	    *info |= SANE_INFO_INEXACT |
980 	      SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
981 	  return SANE_STATUS_GOOD;
982 
983 	case BR_X:
984 	  if (*(SANE_Word *) val >=
985 	      s->val[TL_X].w + MIN_WIDTH
986 	      && !check_area (s, s->val[TL_X].w, s->val[TL_Y].w,
987 			      *(SANE_Word *) val, s->val[BR_Y].w))
988 	    {
989 	      s->val[option].w = *(SANE_Word *) val;
990 	      if (info)
991 		*info |= SANE_INFO_RELOAD_PARAMS;
992 	    }
993 	  else if (info)
994 	    *info |= SANE_INFO_INEXACT |
995 	      SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
996 	  return SANE_STATUS_GOOD;
997 
998 	case LANDSCAPE:
999 	  s->val[option].w = *(SANE_Word *) val;
1000 	  if (info)
1001 	    *info |= SANE_INFO_RELOAD_PARAMS;
1002 	  return SANE_STATUS_GOOD;
1003 
1004 	  /* Side-effect free options */
1005 	case CONTRAST:
1006 	case BRIGHTNESS:
1007 	case DUPLEX:
1008 	case LENGTHCTL:
1009 	case LONG_PAPER:
1010 	case FIT_TO_PAGE:
1011 	case THRESHOLD:
1012 	case INVERSE:
1013 	case COMPRESSION_PAR:
1014 	case DFSTOP:
1015 	case DFEED_L:
1016 	case DFEED_C:
1017 	case DFEED_R:
1018 	case STOP_SKEW:
1019 	case DESKEW:
1020 	case MIRROR:
1021 	case CROP:
1022 	case TOPPOS:
1023 	case BTMPOS:
1024 	case RED_CHROMA:
1025 	case BLUE_CHROMA:
1026 	  s->val[option].w = *(SANE_Word *) val;
1027 	  return SANE_STATUS_GOOD;
1028 
1029 	case FEED_TIMEOUT:
1030 	  s->val[option].w = *(SANE_Word *) val;
1031 	  return kvs40xx_set_timeout (s, s->val[option].w);
1032 
1033 	  /* String mode */
1034 	case IMAGE_EMPHASIS:
1035 	case GAMMA_CORRECTION:
1036 	case LAMP:
1037 	case HALFTONE_PATTERN:
1038 	case DFEED_SENCE:
1039 	case AUTOMATIC_THRESHOLD:
1040 	case WHITE_LEVEL:
1041 	case NOISE_REDUCTION:
1042 	  strcpy (s->val[option].s, val);
1043 	  return SANE_STATUS_GOOD;
1044 
1045 	case SOURCE:
1046 	  strcpy (s->val[option].s, val);
1047 	  if (strcmp (s->val[option].s, SANE_I18N ("adf")))
1048 	    {
1049 	      strcpy (s->val[FEEDER_MODE].s, feeder_mode_list[0]);
1050 	      strcpy (s->val[MANUALFEED].s, manual_feed_list[0]);
1051 	      s->val[DUPLEX].w = SANE_FALSE;
1052 	      s->val[DBLFEED].w = SANE_FALSE;
1053 	      s->val[BTMPOS].w = SANE_FALSE;
1054 	      s->val[TOPPOS].w = SANE_FALSE;
1055 	      s->val[STOP_SKEW].w = SANE_FALSE;
1056 	      s->val[LENGTHCTL].w = SANE_FALSE;
1057 	      s->val[LONG_PAPER].w = SANE_FALSE;
1058 	      s->opt[FEEDER_MODE].cap |= SANE_CAP_INACTIVE;
1059 	      s->opt[MANUALFEED].cap |= SANE_CAP_INACTIVE;
1060 	      s->opt[DUPLEX].cap |= SANE_CAP_INACTIVE;
1061 	      s->opt[DBLFEED].cap |= SANE_CAP_INACTIVE;
1062 	      s->opt[BTMPOS].cap |= SANE_CAP_INACTIVE;
1063 	      s->opt[TOPPOS].cap |= SANE_CAP_INACTIVE;
1064 	      s->opt[STOP_SKEW].cap |= SANE_CAP_INACTIVE;
1065 	      s->opt[LENGTHCTL].cap |= SANE_CAP_INACTIVE;
1066 	      s->opt[LONG_PAPER].cap |= SANE_CAP_INACTIVE;
1067 	    }
1068 	  else
1069 	    {
1070 	      s->opt[FEEDER_MODE].cap &= ~SANE_CAP_INACTIVE;
1071 	      s->opt[MANUALFEED].cap &= ~SANE_CAP_INACTIVE;
1072 	      s->opt[DUPLEX].cap &= ~SANE_CAP_INACTIVE;
1073 	      s->opt[DBLFEED].cap &= ~SANE_CAP_INACTIVE;
1074 	      s->opt[BTMPOS].cap &= ~SANE_CAP_INACTIVE;
1075 	      s->opt[TOPPOS].cap &= ~SANE_CAP_INACTIVE;
1076 	      s->opt[STOP_SKEW].cap &= ~SANE_CAP_INACTIVE;
1077 	      s->opt[LENGTHCTL].cap &= ~SANE_CAP_INACTIVE;
1078 	      s->opt[LONG_PAPER].cap &= ~SANE_CAP_INACTIVE;
1079 	    }
1080 	  if (info)
1081 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1082 
1083 	  return SANE_STATUS_GOOD;
1084 
1085 	case FEEDER_MODE:
1086 	  strcpy (s->val[option].s, val);
1087 	  if (strcmp (s->val[option].s, SANE_I18N ("continuous")))
1088 	    {
1089 	      s->opt[LONG_PAPER].cap |= SANE_CAP_INACTIVE;
1090 	    }
1091 	  else
1092 	    {
1093 	      s->opt[LONG_PAPER].cap &= ~SANE_CAP_INACTIVE;
1094 	    }
1095 	  if (info)
1096 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1097 
1098 	  return SANE_STATUS_GOOD;
1099 
1100 	case MODE:
1101 	  strcpy (s->val[option].s, val);
1102 	  if (!strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_LINEART))
1103 	    {
1104 	      s->opt[GAMMA_CORRECTION].cap |= SANE_CAP_INACTIVE;
1105 	      s->opt[COMPRESSION].cap |= SANE_CAP_INACTIVE;
1106 	      s->opt[COMPRESSION_PAR].cap |= SANE_CAP_INACTIVE;
1107 	      s->opt[THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1108 	      s->opt[HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
1109 
1110 	      s->opt[AUTOMATIC_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1111 	      s->opt[WHITE_LEVEL].cap &= ~SANE_CAP_INACTIVE;
1112 	      s->opt[NOISE_REDUCTION].cap &= ~SANE_CAP_INACTIVE;
1113 	      s->opt[INVERSE].cap &= ~SANE_CAP_INACTIVE;
1114 	      s->opt[RED_CHROMA].cap |= SANE_CAP_INACTIVE;
1115 	      s->opt[BLUE_CHROMA].cap |= SANE_CAP_INACTIVE;
1116 	    }
1117 	  else
1118 	    {
1119 	      s->opt[COMPRESSION].cap &= ~SANE_CAP_INACTIVE;
1120 	      s->opt[COMPRESSION_PAR].cap &= ~SANE_CAP_INACTIVE;
1121 
1122 	      s->opt[THRESHOLD].cap |= SANE_CAP_INACTIVE;
1123 	      s->opt[INVERSE].cap |= SANE_CAP_INACTIVE;
1124 	      s->opt[HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1125 
1126 	      s->opt[AUTOMATIC_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1127 	      s->opt[WHITE_LEVEL].cap |= SANE_CAP_INACTIVE;
1128 	      s->opt[NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE;
1129 	      s->opt[RED_CHROMA].cap &= ~SANE_CAP_INACTIVE;
1130 	      s->opt[BLUE_CHROMA].cap &= ~SANE_CAP_INACTIVE;
1131 	    }
1132 
1133 	  if (!strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_GRAY))
1134 	    {
1135 	      s->opt[INVERSE].cap &= ~SANE_CAP_INACTIVE;
1136 
1137 	      s->opt[GAMMA_CORRECTION].cap &= ~SANE_CAP_INACTIVE;
1138 	    }
1139 	  else
1140 	    {
1141 	      s->opt[GAMMA_CORRECTION].cap |= SANE_CAP_INACTIVE;
1142 	    }
1143 
1144 	  if (info)
1145 	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1146 
1147 	  return SANE_STATUS_GOOD;
1148 
1149 	case MANUALFEED:
1150 	  strcpy (s->val[option].s, val);
1151 	  if (strcmp (s->val[option].s, manual_feed_list[0]) == 0)	/* off */
1152 	    s->opt[FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE;
1153 	  else
1154 	    s->opt[FEED_TIMEOUT].cap &= ~SANE_CAP_INACTIVE;
1155 	  if (info)
1156 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1157 
1158 	  return SANE_STATUS_GOOD;
1159 
1160 	case STAPELED_DOC:
1161 	  strcpy (s->val[option].s, val);
1162 	  if (strcmp (s->val[option].s, stapeled_list[0]) == 0)
1163 	    {
1164 	      s->opt[DBLFEED].cap &= ~SANE_CAP_INACTIVE;
1165 	      s->opt[DFSTOP].cap &= ~SANE_CAP_INACTIVE;
1166 	      s->opt[DFEED_L].cap &= ~SANE_CAP_INACTIVE;
1167 	      s->opt[DFEED_C].cap &= ~SANE_CAP_INACTIVE;
1168 	      s->opt[DFEED_C].cap &= ~SANE_CAP_INACTIVE;
1169 	      s->opt[DFEED_R].cap &= ~SANE_CAP_INACTIVE;
1170 	      s->opt[DFEED_SENCE].cap &= ~SANE_CAP_INACTIVE;
1171 	    }
1172 	  else
1173 	    {
1174 	      s->opt[DBLFEED].cap |= SANE_CAP_INACTIVE;
1175 	      s->opt[DFSTOP].cap |= SANE_CAP_INACTIVE;
1176 	      s->opt[DFEED_L].cap |= SANE_CAP_INACTIVE;
1177 	      s->opt[DFEED_C].cap |= SANE_CAP_INACTIVE;
1178 	      s->opt[DFEED_R].cap |= SANE_CAP_INACTIVE;
1179 	      s->opt[DFEED_SENCE].cap |= SANE_CAP_INACTIVE;
1180 	    }
1181 	  if (info)
1182 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1183 
1184 	  return SANE_STATUS_GOOD;
1185 
1186 	case DBLFEED:
1187 	  s->val[option].w = *(SANE_Word *) val;
1188 	  if (!s->val[option].b)
1189 	    {
1190 	      s->opt[DFSTOP].cap |= SANE_CAP_INACTIVE;
1191 	      s->opt[DFEED_L].cap |= SANE_CAP_INACTIVE;
1192 	      s->opt[DFEED_C].cap |= SANE_CAP_INACTIVE;
1193 	      s->opt[DFEED_R].cap |= SANE_CAP_INACTIVE;
1194 	      s->opt[DFEED_SENCE].cap |= SANE_CAP_INACTIVE;
1195 	    }
1196 	  else
1197 	    {
1198 	      s->opt[DFSTOP].cap &= ~SANE_CAP_INACTIVE;
1199 	      s->opt[DFEED_L].cap &= ~SANE_CAP_INACTIVE;
1200 	      s->opt[DFEED_C].cap &= ~SANE_CAP_INACTIVE;
1201 	      s->opt[DFEED_C].cap &= ~SANE_CAP_INACTIVE;
1202 	      s->opt[DFEED_R].cap &= ~SANE_CAP_INACTIVE;
1203 	      s->opt[DFEED_SENCE].cap &= ~SANE_CAP_INACTIVE;
1204 	    }
1205 	  if (info)
1206 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1207 
1208 	  return SANE_STATUS_GOOD;
1209 
1210 	case PAPER_SIZE:
1211 	  strcpy (s->val[option].s, val);
1212 	  i = str_index (paper_list, s->val[option].s);
1213 	  if (i == 0)
1214 	    {			/*user def */
1215 	      s->opt[TL_X].cap &=
1216 		s->opt[TL_Y].cap &=
1217 		s->opt[BR_X].cap &= s->opt[BR_Y].cap &= ~SANE_CAP_INACTIVE;
1218 	      s->opt[LANDSCAPE].cap |= SANE_CAP_INACTIVE;
1219 	      s->val[LANDSCAPE].w = 0;
1220 	    }
1221 	  else
1222 	    {
1223 	      s->opt[TL_X].cap |=
1224 		s->opt[TL_Y].cap |=
1225 		s->opt[BR_X].cap |= s->opt[BR_Y].cap |= SANE_CAP_INACTIVE;
1226 	      if ( /*i == 4 || */ i == 5 || i == 6 /*XXX*/
1227 		  || i == 10 || i == 11)
1228 		{		/*A4, A5, A6, B5, B6 */
1229 		  if ((s->id == KV_S4085CL || s->id == KV_S4065CL)
1230 		      && i == 4 && i == 10)
1231 		    {		/*A4, B5 */
1232 		      s->opt[LANDSCAPE].cap |= SANE_CAP_INACTIVE;
1233 		      s->val[LANDSCAPE].w = 0;
1234 		    }
1235 		  else
1236 		    s->opt[LANDSCAPE].cap &= ~SANE_CAP_INACTIVE;
1237 		}
1238 	      else
1239 		{
1240 		  s->opt[LANDSCAPE].cap |= SANE_CAP_INACTIVE;
1241 		  s->val[LANDSCAPE].w = 0;
1242 		}
1243 	    }
1244 	  if (info)
1245 	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1246 
1247 	  return SANE_STATUS_GOOD;
1248 
1249 	case COMPRESSION:
1250 	  s->val[option].w = *(SANE_Word *) val;
1251 	  if (!s->val[option].b)
1252 	    {
1253 	      s->opt[COMPRESSION_PAR].cap |= SANE_CAP_INACTIVE;
1254 	    }
1255 	  else
1256 	    {
1257 	      s->opt[COMPRESSION_PAR].cap &= ~SANE_CAP_INACTIVE;
1258 	    }
1259 	  if (info)
1260 	    *info |= SANE_INFO_RELOAD_OPTIONS;
1261 
1262 	  return SANE_STATUS_GOOD;
1263 	}
1264     }
1265 
1266 
1267   return SANE_STATUS_UNSUPPORTED;
1268 }
1269 
1270 void
kvs40xx_init_window(struct scanner * s,struct window * wnd,int wnd_id)1271 kvs40xx_init_window (struct scanner *s, struct window *wnd, int wnd_id)
1272 {
1273   int paper = str_index (paper_list, s->val[PAPER_SIZE].s), i;
1274   memset (wnd, 0, sizeof (struct window));
1275   copy16 (wnd->window_descriptor_block_length, cpu2be16 (66));
1276 
1277   wnd->window_identifier = wnd_id;
1278   copy16 (wnd->x_resolution, cpu2be16 (s->val[RESOLUTION].w));
1279   copy16 (wnd->y_resolution, cpu2be16 (s->val[RESOLUTION].w));
1280   if (!paper)
1281     {
1282       copy32 (wnd->upper_left_x,
1283               cpu2be32 (mm2scanner_units (s->val[TL_X].w)));
1284       copy32 (wnd->upper_left_y,
1285               cpu2be32 (mm2scanner_units (s->val[TL_Y].w)));
1286       copy32 (wnd->document_width,
1287               cpu2be32 (mm2scanner_units (s->val[BR_X].w)));
1288       copy32 (wnd->width,
1289               cpu2be32 (mm2scanner_units (s->val[BR_X].w - s->val[TL_X].w)));
1290       copy32 (wnd->document_length, cpu2be32 (mm2scanner_units
1291                                               (s->val[BR_Y].w)));
1292       copy32 (wnd->length,
1293               cpu2be32 (mm2scanner_units (s->val[BR_Y].w - s->val[TL_Y].w)));
1294     }
1295   else
1296     {
1297       u32 w = cpu2be32 (mm2scanner_units (paper_sizes[paper].width));
1298       u32 h = cpu2be32 (mm2scanner_units (paper_sizes[paper].height));
1299       copy32 (wnd->upper_left_x, cpu2be32 (mm2scanner_units (0)));
1300       copy32 (wnd->upper_left_y, cpu2be32 (mm2scanner_units (0)));
1301       if (!s->val[LANDSCAPE].b)
1302 	{
1303 	  copy32 (wnd->width, w);
1304 	  copy32 (wnd->length, h);
1305 	  copy32 (wnd->document_width, w);
1306 	  copy32 (wnd->document_length, h);
1307 	}
1308       else
1309 	{
1310 	  copy32 (wnd->width, h);
1311 	  copy32 (wnd->length, w);
1312 	  copy32 (wnd->document_width, h);
1313 	  copy32 (wnd->document_length, w);
1314 	}
1315     }
1316   wnd->brightness = s->val[BRIGHTNESS].w;
1317   wnd->threshold = s->val[THRESHOLD].w;
1318   wnd->contrast = s->val[CONTRAST].w;
1319   wnd->image_composition = mode_val[str_index (mode_list, s->val[MODE].s)];
1320   wnd->bit_per_pixel = bps_val[str_index (mode_list, s->val[MODE].s)];
1321 
1322   copy16 (wnd->halftone_pattern,
1323           cpu2be16 (str_index (halftone_pattern, s->val[HALFTONE_PATTERN].s)));
1324 
1325   wnd->rif_padding = s->val[INVERSE].b << 7;
1326   copy16 (wnd->bit_ordering, cpu2be16 (BIT_ORDERING));
1327   wnd->compression_type = s->val[COMPRESSION].b ? 0x81 : 0;
1328   wnd->compression_argument = s->val[COMPRESSION_PAR].w;
1329 
1330   wnd->vendor_unique_identifier = 0;
1331   wnd->nobuf_fstspeed_dfstop = str_index (source_list,
1332 					  s->val[SOURCE].s) << 7 |
1333     str_index (stapeled_list,
1334 	       s->val[STAPELED_DOC].s) << 5 |
1335     s->val[STOP_SKEW].b << 4 | s->val[CROP].b << 3 | s->val[DFSTOP].b << 0;
1336 
1337   wnd->mirror_image = s->val[MIRROR].b << 7 |
1338     s->val[DFEED_L].b << 2 | s->val[DFEED_C].b << 1 | s->val[DFEED_R].b << 0;
1339   wnd->image_emphasis = str_index (image_emphasis_list,
1340 				   s->val[IMAGE_EMPHASIS].s);
1341   wnd->gamma_correction = gamma_val[str_index (gamma_list,
1342 					       s->val[GAMMA_CORRECTION].s)];
1343   wnd->mcd_lamp_dfeed_sens =
1344     str_index (lamp_list, s->val[LAMP].s) << 4 |
1345     str_index (dfeed_sence_list, s->val[DFEED_SENCE].s);
1346 
1347   wnd->document_size = ((paper != 0) << 7) | (s->val[LENGTHCTL].b << 6)
1348       | (s->val[LONG_PAPER].b << 5) | (s->val[LANDSCAPE].b << 4)
1349       | paper_val[paper];
1350 
1351   wnd->ahead_deskew_dfeed_scan_area_fspeed_rshad =
1352     (s->val[DESKEW].b || s->val[CROP].b ? 2 : 0) << 5 | /*XXX*/
1353     s->val[DBLFEED].b << 4 | s->val[FIT_TO_PAGE].b << 2;
1354   wnd->continuous_scanning_pages =
1355     str_index (feeder_mode_list, s->val[FEEDER_MODE].s) ? 0xff : 0;
1356   wnd->automatic_threshold_mode = automatic_threshold_val
1357     [str_index (automatic_threshold_list, s->val[AUTOMATIC_THRESHOLD].s)];
1358   wnd->automatic_separation_mode = 0;	/*Does not supported */
1359   wnd->standard_white_level_mode =
1360     white_level_val[str_index (white_level_list, s->val[WHITE_LEVEL].s)];
1361   wnd->b_wnr_noise_reduction =
1362     str_index (noise_reduction_list, s->val[NOISE_REDUCTION].s);
1363 
1364   i = str_index (manual_feed_list, s->val[MANUALFEED].s);
1365   wnd->mfeed_toppos_btmpos_dsepa_hsepa_dcont_rstkr = i << 6 |
1366     s->val[TOPPOS].b << 5 | s->val[BTMPOS].b << 4;
1367   wnd->stop_mode = 1;
1368   wnd->red_chroma = s->val[RED_CHROMA].w;
1369   wnd->blue_chroma = s->val[BLUE_CHROMA].w;
1370 }
1371 
1372 /* Get scan parameters */
1373 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)1374 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1375 {
1376   struct scanner *s = (struct scanner *) handle;
1377   SANE_Parameters *p = &s->params;
1378 
1379   if (!s->scanning)
1380     {
1381       unsigned w, h, res = s->val[RESOLUTION].w;
1382       unsigned i = str_index (paper_list,
1383 			      s->val[PAPER_SIZE].s);
1384       if (i)
1385 	{
1386 	  if (s->val[LANDSCAPE].b)
1387 	    {
1388 	      w = paper_sizes[i].height;
1389 	      h = paper_sizes[i].width;
1390 	    }
1391 	  else
1392 	    {
1393 	      w = paper_sizes[i].width;
1394 	      h = paper_sizes[i].height;
1395 	    }
1396 	}
1397       else
1398 	{
1399 	  w = s->val[BR_X].w - s->val[TL_X].w;
1400 	  h = s->val[BR_Y].w - s->val[TL_Y].w;
1401 	}
1402       p->pixels_per_line = w * res / 25.4 + .5;
1403       p->lines = h * res / 25.4 + .5;
1404     }
1405 
1406   p->format = !strcmp (s->val[MODE].s,
1407 		       SANE_VALUE_SCAN_MODE_COLOR) ? SANE_FRAME_RGB :
1408     SANE_FRAME_GRAY;
1409   p->last_frame = SANE_TRUE;
1410   p->depth = bps_val[str_index (mode_list, s->val[MODE].s)];
1411   p->bytes_per_line = p->depth * p->pixels_per_line / 8;
1412   if (p->depth > 8)
1413     p->depth = 8;
1414   if (params)
1415     memcpy (params, p, sizeof (SANE_Parameters));
1416   s->side_size = p->bytes_per_line * p->lines;
1417 
1418   return SANE_STATUS_GOOD;
1419 }
1420