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