1 /*
2    Copyright (C) 2008, Panasonic Russia Ltd.
3    Copyright (C) 2010, m. allan noah
4 */
5 /*
6    Panasonic KV-S20xx USB-SCSI scanners.
7 */
8 
9 #include "../include/sane/config.h"
10 
11 #include <string.h>
12 
13 #define DEBUG_DECLARE_ONLY
14 #define BACKEND_NAME kvs20xx
15 
16 #include "../include/sane/sane.h"
17 #include "../include/sane/saneopts.h"
18 #include "../include/sane/sanei.h"
19 #include "../include/sane/sanei_backend.h"
20 #include "../include/sane/sanei_config.h"
21 #include "../include/lassert.h"
22 
23 #include "kvs20xx.h"
24 #include "kvs20xx_cmd.h"
25 
26 #include <stdlib.h>
27 
28 static size_t
max_string_size(SANE_String_Const strings[])29 max_string_size (SANE_String_Const strings[])
30 {
31   size_t size, max_size = 0;
32   SANE_Int i;
33 
34   for (i = 0; strings[i]; ++i)
35     {
36       size = strlen (strings[i]) + 1;
37       if (size > max_size)
38 	max_size = size;
39     }
40   return max_size;
41 }
42 static SANE_String_Const mode_list[] = {
43   SANE_VALUE_SCAN_MODE_LINEART,
44   SANE_VALUE_SCAN_MODE_GRAY,
45   SANE_VALUE_SCAN_MODE_COLOR,
46   NULL
47 };
48 static const unsigned mode_val[] = { 0, 2, 5 };
49 static const unsigned bps_val[] = { 1, 8, 24 };
50 
51 static const SANE_Range resolutions_range = {100,600,10};
52 
53 /* List of feeder modes */
54 static SANE_String_Const feeder_mode_list[] = {
55   SANE_I18N ("single"),
56   SANE_I18N ("continuous"),
57   NULL
58 };
59 
60 /* List of manual feed mode */
61 static SANE_String_Const manual_feed_list[] = {
62   SANE_I18N ("off"),
63   SANE_I18N ("wait_doc"),
64   SANE_I18N ("wait_key"),
65   NULL
66 };
67 
68 /* List of paper sizes */
69 static SANE_String_Const paper_list[] = {
70   SANE_I18N ("user_def"),
71   SANE_I18N ("business_card"),
72   /*SANE_I18N("Check"), */
73   /*SANE_I18N ("A3"), */
74   SANE_I18N ("A4"),
75   SANE_I18N ("A5"),
76   SANE_I18N ("A6"),
77   SANE_I18N ("Letter"),
78   /*SANE_I18N ("Double letter 11x17 in"),
79      SANE_I18N ("B4"), */
80   SANE_I18N ("B5"),
81   SANE_I18N ("B6"),
82   SANE_I18N ("Legal"),
83   NULL
84 };
85 static const unsigned paper_val[] = { 0, 1, 4, 5, 6, 7, 13, 14, 15 };
86 struct paper_size
87 {
88   int width;
89   int height;
90 };
91 static const struct paper_size paper_sizes[] = {
92   {210, 297},			/* User defined, default=A4 */
93   {54, 90},			/* Business card */
94   /*{80, 170},            *//* Check (China business) */
95   /*{297, 420}, *//* A3 */
96   {210, 297},			/* A4 */
97   {148, 210},			/* A5 */
98   {105, 148},			/* A6 */
99   {215, 280},			/* US Letter 8.5 x 11 in */
100   /*{280, 432}, *//* Double Letter 11 x 17 in */
101   /*{250, 353}, *//* B4 */
102   {176, 250},			/* B5 */
103   {125, 176},			/* B6 */
104   {215, 355}			/* US Legal */
105 };
106 
107 #define MIN_WIDTH	51
108 #define MAX_WIDTH	215
109 #define MIN_LENGTH	70
110 #define MAX_LENGTH	355
111 static SANE_Range tl_x_range = { 0, MAX_WIDTH - MIN_WIDTH, 0 };
112 static SANE_Range tl_y_range = { 0, MAX_LENGTH - MIN_LENGTH, 0 };
113 static SANE_Range br_x_range = { MIN_WIDTH, MAX_WIDTH, 0 };
114 static SANE_Range br_y_range = { MIN_LENGTH, MAX_LENGTH, 0 };
115 static SANE_Range byte_value_range = { 0, 255, 0 };
116 
117 /* List of image emphasis options, 5 steps */
118 static SANE_String_Const image_emphasis_list[] = {
119   SANE_I18N ("none"),
120   SANE_I18N ("low"),
121   SANE_I18N ("medium"),
122   SANE_I18N ("high"),
123   SANE_I18N ("smooth"),
124   NULL
125 };
126 
127 /* List of gamma */
128 static SANE_String_Const gamma_list[] = {
129   SANE_I18N ("normal"),
130   SANE_I18N ("crt"),
131   NULL
132 };
133 static unsigned gamma_val[] = { 0, 1 };
134 
135 /* List of lamp color dropout */
136 static SANE_String_Const lamp_list[] = {
137   SANE_I18N ("normal"),
138   SANE_I18N ("red"),
139   SANE_I18N ("green"),
140   SANE_I18N ("blue"),
141   NULL
142 };
143 
144 /* Reset the options for that scanner. */
145 void
kvs20xx_init_options(struct scanner *s)146 kvs20xx_init_options (struct scanner *s)
147 {
148   int i;
149   SANE_Option_Descriptor *o;
150   /* Pre-initialize the options. */
151   memset (s->opt, 0, sizeof (s->opt));
152   memset (s->val, 0, sizeof (s->val));
153 
154   for (i = 0; i < NUM_OPTIONS; i++)
155     {
156       s->opt[i].size = sizeof (SANE_Word);
157       s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
158     }
159 
160   /* Number of options. */
161   o = &s->opt[NUM_OPTS];
162   o->name = "";
163   o->title = SANE_TITLE_NUM_OPTIONS;
164   o->desc = SANE_DESC_NUM_OPTIONS;
165   o->type = SANE_TYPE_INT;
166   o->cap = SANE_CAP_SOFT_DETECT;
167   s->val[NUM_OPTS].w = NUM_OPTIONS;
168 
169   /* Mode group */
170   o = &s->opt[MODE_GROUP];
171   o->title = SANE_I18N ("Scan Mode");
172   o->desc = "";			/* not valid for a group */
173   o->type = SANE_TYPE_GROUP;
174   o->cap = 0;
175   o->size = 0;
176   o->constraint_type = SANE_CONSTRAINT_NONE;
177 
178   /* Scanner supported modes */
179   o = &s->opt[MODE];
180   o->name = SANE_NAME_SCAN_MODE;
181   o->title = SANE_TITLE_SCAN_MODE;
182   o->desc = SANE_DESC_SCAN_MODE;
183   o->type = SANE_TYPE_STRING;
184   o->size = max_string_size (mode_list);
185   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
186   o->constraint.string_list = mode_list;
187   s->val[MODE].s = malloc (o->size);
188   strcpy (s->val[MODE].s, mode_list[0]);
189 
190   /* X and Y resolution */
191   o = &s->opt[RESOLUTION];
192   o->name = SANE_NAME_SCAN_RESOLUTION;
193   o->title = SANE_TITLE_SCAN_RESOLUTION;
194   o->desc = SANE_DESC_SCAN_RESOLUTION;
195   o->type = SANE_TYPE_INT;
196   o->unit = SANE_UNIT_DPI;
197   o->constraint_type = SANE_CONSTRAINT_RANGE;
198   o->constraint.range = &resolutions_range;
199   s->val[RESOLUTION].w = 100;
200 
201   /* Duplex */
202   o = &s->opt[DUPLEX];
203   o->name = "duplex";
204   o->title = SANE_I18N ("Duplex");
205   o->desc = SANE_I18N ("Enable Duplex (Dual-Sided) Scanning");
206   o->type = SANE_TYPE_BOOL;
207   o->unit = SANE_UNIT_NONE;
208   s->val[DUPLEX].w = SANE_FALSE;
209 
210   /*FIXME
211      if (!s->support_info.support_duplex)
212      o->cap |= SANE_CAP_INACTIVE;
213    */
214 
215   /* Feeder mode */
216   o = &s->opt[FEEDER_MODE];
217   o->name = "feeder-mode";
218   o->title = SANE_I18N ("Feeder mode");
219   o->desc = SANE_I18N ("Sets the feeding mode");
220   o->type = SANE_TYPE_STRING;
221   o->size = max_string_size (feeder_mode_list);
222   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
223   o->constraint.string_list = feeder_mode_list;
224   s->val[FEEDER_MODE].s = malloc (o->size);
225   strcpy (s->val[FEEDER_MODE].s, feeder_mode_list[0]);
226 
227   /* Length control */
228   o = &s->opt[LENGTHCTL];
229   o->name = "length-control";
230   o->title = SANE_I18N ("Length control mode");
231   o->desc =
232     SANE_I18N
233     ("Length Control Mode causes the scanner to read the shorter of either the length of the actual"
234      " paper or logical document length.");
235   o->type = SANE_TYPE_BOOL;
236   o->unit = SANE_UNIT_NONE;
237   s->val[LENGTHCTL].w = SANE_FALSE;
238 
239   /* Manual feed */
240   o = &s->opt[MANUALFEED];
241   o->name = "manual-feed";
242   o->title = SANE_I18N ("Manual feed mode");
243   o->desc = SANE_I18N ("Sets the manual feed mode");
244   o->type = SANE_TYPE_STRING;
245   o->size = max_string_size (manual_feed_list);
246   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
247   o->constraint.string_list = manual_feed_list;
248   s->val[MANUALFEED].s = malloc (o->size);
249   strcpy (s->val[MANUALFEED].s, manual_feed_list[0]);
250 
251   /*Manual feed timeout */
252   o = &s->opt[FEED_TIMEOUT];
253   o->name = "feed-timeout";
254   o->title = SANE_I18N ("Manual feed timeout");
255   o->desc = SANE_I18N ("Sets the manual feed timeout in seconds");
256   o->type = SANE_TYPE_INT;
257   o->unit = SANE_UNIT_NONE;
258   o->size = sizeof (SANE_Int);
259   o->constraint_type = SANE_CONSTRAINT_RANGE;
260   o->constraint.range = &(byte_value_range);
261   o->cap |= SANE_CAP_INACTIVE;
262   s->val[FEED_TIMEOUT].w = 30;
263 
264   /* Double feed */
265   o = &s->opt[DBLFEED];
266   o->name = "double-feed";
267   o->title = SANE_I18N ("Double feed detection");
268   o->desc = SANE_I18N ("Enable/Disable double feed detection");
269   o->type = SANE_TYPE_BOOL;
270   o->unit = SANE_UNIT_NONE;
271   s->val[DBLFEED].w = SANE_FALSE;
272 
273 
274   /* Fit to page */
275   o = &s->opt[FIT_TO_PAGE];
276   o->name = SANE_I18N ("fit-to-page");
277   o->title = SANE_I18N ("Fit to page");
278   o->desc = SANE_I18N ("Scanner shrinks image to fit scanned page");
279   o->type = SANE_TYPE_BOOL;
280   o->unit = SANE_UNIT_NONE;
281   s->val[FIT_TO_PAGE].w = SANE_FALSE;
282 
283   /* Geometry group */
284   o = &s->opt[GEOMETRY_GROUP];
285   o->title = SANE_I18N ("Geometry");
286   o->desc = "";			/* not valid for a group */
287   o->type = SANE_TYPE_GROUP;
288   o->cap = 0;
289   o->size = 0;
290   o->constraint_type = SANE_CONSTRAINT_NONE;
291 
292   /* Paper sizes list */
293   o = &s->opt[PAPER_SIZE];
294   o->name = "paper-size";
295   o->title = SANE_I18N ("Paper size");
296   o->desc = SANE_I18N ("Physical size of the paper in the ADF");
297   o->type = SANE_TYPE_STRING;
298   o->size = max_string_size (paper_list);
299   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
300   o->constraint.string_list = paper_list;
301   s->val[PAPER_SIZE].s = malloc (o->size);
302   strcpy (s->val[PAPER_SIZE].s, SANE_I18N ("A4"));
303 
304   /* Landscape */
305   o = &s->opt[LANDSCAPE];
306   o->name = "landscape";
307   o->title = SANE_I18N ("Landscape");
308   o->desc =
309     SANE_I18N ("Set paper position : "
310 	       "true for landscape, false for portrait");
311   o->type = SANE_TYPE_BOOL;
312   o->unit = SANE_UNIT_NONE;
313   s->val[LANDSCAPE].w = SANE_FALSE;
314   o->cap |= SANE_CAP_INACTIVE;
315 
316   /* Upper left X */
317   o = &s->opt[TL_X];
318   o->name = SANE_NAME_SCAN_TL_X;
319   o->title = SANE_TITLE_SCAN_TL_X;
320   o->desc = SANE_DESC_SCAN_TL_X;
321   o->type = SANE_TYPE_INT;
322   o->unit = SANE_UNIT_MM;
323   o->constraint_type = SANE_CONSTRAINT_RANGE;
324   o->constraint.range = &tl_x_range;
325   o->cap |= SANE_CAP_INACTIVE;
326   s->val[TL_X].w = 0;
327 
328   /* Upper left Y */
329   o = &s->opt[TL_Y];
330   o->name = SANE_NAME_SCAN_TL_Y;
331   o->title = SANE_TITLE_SCAN_TL_Y;
332   o->desc = SANE_DESC_SCAN_TL_Y;
333   o->type = SANE_TYPE_INT;
334   o->unit = SANE_UNIT_MM;
335   o->constraint_type = SANE_CONSTRAINT_RANGE;
336   o->constraint.range = &tl_y_range;
337   o->cap |= SANE_CAP_INACTIVE;
338   s->val[TL_Y].w = 0;
339 
340   /* Bottom-right x */
341   o = &s->opt[BR_X];
342   o->name = SANE_NAME_SCAN_BR_X;
343   o->title = SANE_TITLE_SCAN_BR_X;
344   o->desc = SANE_DESC_SCAN_BR_X;
345   o->type = SANE_TYPE_INT;
346   o->unit = SANE_UNIT_MM;
347   o->constraint_type = SANE_CONSTRAINT_RANGE;
348   o->constraint.range = &br_x_range;
349   o->cap |= SANE_CAP_INACTIVE;
350   s->val[BR_X].w = 210;
351 
352   /* Bottom-right y */
353   o = &s->opt[BR_Y];
354   o->name = SANE_NAME_SCAN_BR_Y;
355   o->title = SANE_TITLE_SCAN_BR_Y;
356   o->desc = SANE_DESC_SCAN_BR_Y;
357   o->type = SANE_TYPE_INT;
358   o->unit = SANE_UNIT_MM;
359   o->constraint_type = SANE_CONSTRAINT_RANGE;
360   o->constraint.range = &br_y_range;
361   o->cap |= SANE_CAP_INACTIVE;
362   s->val[BR_Y].w = 297;
363 
364   /* Enhancement group */
365   o = &s->opt[ADVANCED_GROUP];
366   o->title = SANE_I18N ("Advanced");
367   o->desc = "";			/* not valid for a group */
368   o->type = SANE_TYPE_GROUP;
369   o->cap = SANE_CAP_ADVANCED;
370   o->size = 0;
371   o->constraint_type = SANE_CONSTRAINT_NONE;
372 
373   /* Brightness */
374   o = &s->opt[BRIGHTNESS];
375   o->name = SANE_NAME_BRIGHTNESS;
376   o->title = SANE_TITLE_BRIGHTNESS;
377   o->desc = SANE_DESC_BRIGHTNESS;
378   o->type = SANE_TYPE_INT;
379   o->unit = SANE_UNIT_NONE;
380   o->size = sizeof (SANE_Int);
381   o->constraint_type = SANE_CONSTRAINT_RANGE;
382   o->constraint.range = &(byte_value_range);
383   s->val[BRIGHTNESS].w = 128;
384 
385   /* Contrast */
386   o = &s->opt[CONTRAST];
387   o->name = SANE_NAME_CONTRAST;
388   o->title = SANE_TITLE_CONTRAST;
389   o->desc = SANE_DESC_CONTRAST;
390   o->type = SANE_TYPE_INT;
391   o->unit = SANE_UNIT_NONE;
392   o->size = sizeof (SANE_Int);
393   o->constraint_type = SANE_CONSTRAINT_RANGE;
394   o->constraint.range = &(byte_value_range);
395   s->val[CONTRAST].w = 128;
396 
397   /* threshold */
398   o = &s->opt[THRESHOLD];
399   o->name = SANE_NAME_THRESHOLD;
400   o->title = SANE_TITLE_THRESHOLD;
401   o->desc = SANE_DESC_THRESHOLD;
402   o->type = SANE_TYPE_INT;
403   o->size = sizeof (SANE_Int);
404   o->constraint_type = SANE_CONSTRAINT_RANGE;
405   o->constraint.range = &(byte_value_range);
406   s->val[THRESHOLD].w = 128;
407 
408 
409   /* Image emphasis */
410   o = &s->opt[IMAGE_EMPHASIS];
411   o->name = "image-emphasis";
412   o->title = SANE_I18N ("Image emphasis");
413   o->desc = SANE_I18N ("Sets the image emphasis");
414   o->type = SANE_TYPE_STRING;
415   o->size = max_string_size (image_emphasis_list);
416   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
417   o->constraint.string_list = image_emphasis_list;
418   s->val[IMAGE_EMPHASIS].s = malloc (o->size);
419   strcpy (s->val[IMAGE_EMPHASIS].s, image_emphasis_list[0]);
420 
421   /* Gamma */
422   o = &s->opt[GAMMA_CORRECTION];
423   o->name = "gamma-cor";
424   o->title = SANE_I18N ("Gamma correction");
425   o->desc = SANE_I18N ("Gamma correction");
426   o->type = SANE_TYPE_STRING;
427   o->size = max_string_size (gamma_list);
428   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
429   o->constraint.string_list = gamma_list;
430   s->val[GAMMA_CORRECTION].s = malloc (o->size);
431   strcpy (s->val[GAMMA_CORRECTION].s, gamma_list[0]);
432 
433   /* Lamp color dropout */
434   o = &s->opt[LAMP];
435   o->name = "lamp-color";
436   o->title = SANE_I18N ("Lamp color");
437   o->desc = SANE_I18N ("Sets the lamp color (color dropout)");
438   o->type = SANE_TYPE_STRING;
439   o->size = max_string_size (lamp_list);
440   o->constraint_type = SANE_CONSTRAINT_STRING_LIST;
441   o->constraint.string_list = lamp_list;
442   s->val[LAMP].s = malloc (o->size);
443   strcpy (s->val[LAMP].s, lamp_list[0]);
444 
445 }
446 
447 /* Lookup a string list from one array and return its index. */
448 static int
str_index(const SANE_String_Const * list, SANE_String_Const name)449 str_index (const SANE_String_Const * list, SANE_String_Const name)
450 {
451   int index;
452   index = 0;
453   while (list[index])
454     {
455       if (!strcmp (list[index], name))
456 	return (index);
457       index++;
458     }
459   return (-1);			/* not found */
460 }
461 
462 /* Control option */
463 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int * info)464 sane_control_option (SANE_Handle handle, SANE_Int option,
465 		     SANE_Action action, void *val, SANE_Int * info)
466 {
467   int i;
468   SANE_Status status;
469   SANE_Word cap;
470   struct scanner *s = (struct scanner *) handle;
471 
472   if (info)
473     *info = 0;
474 
475   if (option < 0 || option >= NUM_OPTIONS)
476     return SANE_STATUS_UNSUPPORTED;
477 
478   cap = s->opt[option].cap;
479   if (!SANE_OPTION_IS_ACTIVE (cap))
480     return SANE_STATUS_UNSUPPORTED;
481 
482   if (action == SANE_ACTION_GET_VALUE)
483     {
484       if (s->opt[option].type == SANE_TYPE_STRING)
485 	{
486 	  DBG (DBG_INFO, "sane_control_option: reading opt[%d] =  %s\n",
487 	       option, s->val[option].s);
488 	  strcpy (val, s->val[option].s);
489 	}
490       else
491 	{
492 	  *(SANE_Word *) val = s->val[option].w;
493 	  DBG (DBG_INFO, "sane_control_option: reading opt[%d] =  %d\n",
494 	       option, s->val[option].w);
495 	}
496       return SANE_STATUS_GOOD;
497 
498     }
499   else if (action == SANE_ACTION_SET_VALUE)
500     {
501       if (!SANE_OPTION_IS_SETTABLE (cap))
502 	return SANE_STATUS_INVAL;
503 
504       status = sanei_constrain_value (s->opt + option, val, info);
505       if (status != SANE_STATUS_GOOD)
506 	return status;
507 
508       if (s->opt[option].type == SANE_TYPE_STRING)
509 	{
510 	  if (!strcmp (val, s->val[option].s))
511 	    return SANE_STATUS_GOOD;
512 	  DBG (DBG_INFO, "sane_control_option: writing opt[%d] =  %s\n",
513 	       option, (SANE_String_Const) val);
514 	}
515       else
516 	{
517 	  if (*(SANE_Word *) val == s->val[option].w)
518 	    return SANE_STATUS_GOOD;
519 	  DBG (DBG_INFO, "sane_control_option: writing opt[%d] =  %d\n",
520 	       option, *(SANE_Word *) val);
521 	}
522 
523       switch (option)
524 	{
525 	  /* Side-effect options */
526 	case RESOLUTION:
527 	  s->val[option].w = *(SANE_Word *) val;
528 	  if (info)
529 	    *info |= SANE_INFO_RELOAD_PARAMS;
530 	  return SANE_STATUS_GOOD;
531 
532 	case TL_Y:
533 	  if ((*(SANE_Word *) val) + MIN_LENGTH <= s->val[BR_Y].w)
534 	    {
535 	      s->val[option].w = *(SANE_Word *) val;
536 	      if (info)
537 		*info |= SANE_INFO_RELOAD_PARAMS;
538 	    }
539 	  else if (info)
540 	    *info |= SANE_INFO_INEXACT;
541 	  return SANE_STATUS_GOOD;
542 	case BR_Y:
543 	  if ((*(SANE_Word *) val) >= s->val[TL_Y].w + MIN_LENGTH)
544 	    {
545 	      s->val[option].w = *(SANE_Word *) val;
546 	      if (info)
547 		*info |= SANE_INFO_RELOAD_PARAMS;
548 	    }
549 	  else if (info)
550 	    *info |= SANE_INFO_INEXACT;
551 	  return SANE_STATUS_GOOD;
552 
553 	case TL_X:
554 	  if ((*(SANE_Word *) val) + MIN_WIDTH <= s->val[BR_X].w)
555 	    {
556 	      s->val[option].w = *(SANE_Word *) val;
557 	      if (info)
558 		*info |= SANE_INFO_RELOAD_PARAMS;
559 	    }
560 	  else if (info)
561 	    *info |= SANE_INFO_INEXACT;
562 	  return SANE_STATUS_GOOD;
563 
564 	case BR_X:
565 	  if (*(SANE_Word *) val >= s->val[TL_X].w + MIN_WIDTH)
566 	    {
567 	      s->val[option].w = *(SANE_Word *) val;
568 	      if (info)
569 		*info |= SANE_INFO_RELOAD_PARAMS;
570 	    }
571 	  else if (info)
572 	    *info |= SANE_INFO_INEXACT;
573 	  return SANE_STATUS_GOOD;
574 
575 	case LANDSCAPE:
576 	  s->val[option].w = *(SANE_Word *) val;
577 	  if (info)
578 	    *info |= SANE_INFO_RELOAD_PARAMS;
579 	  return SANE_STATUS_GOOD;
580 
581 	  /* Side-effect free options */
582 	case CONTRAST:
583 	case BRIGHTNESS:
584 	case DUPLEX:
585 	case LENGTHCTL:
586 	case DBLFEED:
587 	case FIT_TO_PAGE:
588 	case THRESHOLD:
589 	  s->val[option].w = *(SANE_Word *) val;
590 	  return SANE_STATUS_GOOD;
591 
592 	case FEED_TIMEOUT:
593 	  s->val[option].w = *(SANE_Word *) val;
594 	  return kvs20xx_set_timeout (s, s->val[option].w);
595 
596 	  /* String mode */
597 	case IMAGE_EMPHASIS:
598 	case GAMMA_CORRECTION:
599 	case LAMP:
600 	case FEEDER_MODE:
601 	  strcpy (s->val[option].s, val);
602 	  return SANE_STATUS_GOOD;
603 
604 	case MODE:
605 	  strcpy (s->val[MODE].s, val);
606 	  if (!strcmp (s->val[MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
607 	    {
608 	      s->opt[THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
609 	      s->opt[GAMMA_CORRECTION].cap |= SANE_CAP_INACTIVE;
610 	      s->opt[BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
611 	    }
612 	  else
613 	    {
614 	      s->opt[THRESHOLD].cap |= SANE_CAP_INACTIVE;
615 	      s->opt[GAMMA_CORRECTION].cap &= ~SANE_CAP_INACTIVE;
616 	      s->opt[BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
617 	    }
618 	  if (info)
619 	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
620 
621 	  return SANE_STATUS_GOOD;
622 
623 	case MANUALFEED:
624 	  strcpy (s->val[option].s, val);
625 	  if (strcmp (s->val[option].s, manual_feed_list[0]) == 0)	/* off */
626 	    s->opt[FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE;
627 	  else
628 	    s->opt[FEED_TIMEOUT].cap &= ~SANE_CAP_INACTIVE;
629 	  if (info)
630 	    *info |= SANE_INFO_RELOAD_OPTIONS;
631 
632 	  return SANE_STATUS_GOOD;
633 
634 	case PAPER_SIZE:
635 	  strcpy (s->val[PAPER_SIZE].s, val);
636 	  i = str_index (paper_list, s->val[PAPER_SIZE].s);
637 	  if (i == 0)
638 	    {			/*user def */
639 	      s->opt[TL_X].cap &=
640 		s->opt[TL_Y].cap &=
641 		s->opt[BR_X].cap &= s->opt[BR_Y].cap &= ~SANE_CAP_INACTIVE;
642 	      s->opt[LANDSCAPE].cap |= SANE_CAP_INACTIVE;
643 	      s->val[LANDSCAPE].w = 0;
644 	    }
645 	  else
646 	    {
647 	      s->opt[TL_X].cap |=
648 		s->opt[TL_Y].cap |=
649 		s->opt[BR_X].cap |= s->opt[BR_Y].cap |= SANE_CAP_INACTIVE;
650 	      if (i == 3 || i == 4 || i == 7)
651 		{		/*A5, A6 or B6 */
652 		  s->opt[LANDSCAPE].cap &= ~SANE_CAP_INACTIVE;
653 		}
654 	      else
655 		{
656 		  s->opt[LANDSCAPE].cap |= SANE_CAP_INACTIVE;
657 		  s->val[LANDSCAPE].w = 0;
658 		}
659 	    }
660 	  if (info)
661 	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
662 
663 	  return SANE_STATUS_GOOD;
664 	}
665     }
666 
667 
668   return SANE_STATUS_UNSUPPORTED;
669 }
670 
671 static inline unsigned
mm2scanner_units(unsigned mm)672 mm2scanner_units (unsigned mm)
673 {
674   return mm * 12000 / 254;
675 }
676 
677 void
kvs20xx_init_window(struct scanner *s, struct window *wnd, int wnd_id)678 kvs20xx_init_window (struct scanner *s, struct window *wnd, int wnd_id)
679 {
680   int paper = str_index (paper_list, s->val[PAPER_SIZE].s);
681   memset (wnd, 0, sizeof (struct window));
682   wnd->window_descriptor_block_length = cpu2be16 (64);
683 
684   wnd->window_identifier = wnd_id;
685   wnd->x_resolution = cpu2be16 (s->val[RESOLUTION].w);
686   wnd->y_resolution = cpu2be16 (s->val[RESOLUTION].w);
687   if (!paper)
688     {
689       wnd->upper_left_x =
690 	cpu2be32 (mm2scanner_units (s->val[TL_X].w));
691       wnd->upper_left_y =
692 	cpu2be32 (mm2scanner_units (s->val[TL_Y].w));
693       wnd->width =
694 	cpu2be32 (mm2scanner_units (s->val[BR_X].w - s->val[TL_X].w));
695       wnd->length =
696 	cpu2be32 (mm2scanner_units (s->val[BR_Y].w - s->val[TL_Y].w));
697     }
698   else
699     {
700       u32 w = cpu2be32 (mm2scanner_units (paper_sizes[paper].width));
701       u32 h = cpu2be32 (mm2scanner_units (paper_sizes[paper].height));
702       wnd->upper_left_x = cpu2be32 (mm2scanner_units (0));
703       wnd->upper_left_y = cpu2be32 (mm2scanner_units (0));
704       if (!s->val[LANDSCAPE].b)
705 	{
706 	  wnd->document_width = wnd->width = w;
707 	  wnd->document_length = wnd->length = h;
708 	}
709       else
710 	{
711 	  wnd->document_width = wnd->width = h;
712 	  wnd->document_length = wnd->length = w;
713 	}
714     }
715   wnd->brightness = s->val[BRIGHTNESS].w;
716   wnd->threshold = s->val[THRESHOLD].w;
717   wnd->contrast = s->val[CONTRAST].w;
718   wnd->image_composition = mode_val[str_index (mode_list, s->val[MODE].s)];
719   wnd->bit_per_pixel = bps_val[str_index (mode_list, s->val[MODE].s)];
720   wnd->halftone_pattern = 0;	/*Does not supported */
721   wnd->bit_ordering = cpu2be16 (BIT_ORDERING);
722   wnd->compression_type = 0;	/*Does not supported */
723   wnd->compression_argument = 0;	/*Does not supported */
724 
725   wnd->vendor_unique_identifier = 0;
726   wnd->nobuf_fstspeed_dfstop = 0;
727   wnd->mirror_image = 0;
728   wnd->image_emphasis = str_index (image_emphasis_list,
729 				   s->val[IMAGE_EMPHASIS].s);
730   wnd->gamma_correction = gamma_val[str_index (gamma_list,
731 					       s->val[GAMMA_CORRECTION].s)];
732   wnd->mcd_lamp_dfeed_sens = str_index (lamp_list, s->val[LAMP].s) << 4 | 2;
733 
734   wnd->document_size = ((paper != 0) << 7) | (s->val[LENGTHCTL].b << 6)
735       | (s->val[LANDSCAPE].b << 4) | paper_val[paper];
736 
737   wnd->ahead_deskew_dfeed_scan_area_fspeed_rshad = s->val[DBLFEED].b << 4
738     | s->val[FIT_TO_PAGE].b << 2;
739   wnd->continuous_scanning_pages = str_index (feeder_mode_list,
740 					      s->val[FEEDER_MODE].
741 					      s) ? 0xff : 0;
742   wnd->automatic_threshold_mode = 0;	/*Does not supported */
743   wnd->automatic_separation_mode = 0;	/*Does not supported */
744   wnd->standard_white_level_mode = 0;	/*Does not supported */
745   wnd->b_wnr_noise_reduction = 0;	/*Does not supported */
746   if (str_index (manual_feed_list, s->val[MANUALFEED].s) == 2)
747     wnd->mfeed_toppos_btmpos_dsepa_hsepa_dcont_rstkr = 2 << 6;
748 
749   wnd->stop_mode = 1;
750 }
751 
752 
753 /* Get scan parameters */
754 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters * params)755 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
756 {
757   struct scanner *s = (struct scanner *) handle;
758   SANE_Parameters *p = &s->params;
759 
760   if (!s->scanning)
761     {
762       unsigned w, h, res = s->val[RESOLUTION].w;
763       unsigned i = str_index (paper_list,
764 			      s->val[PAPER_SIZE].s);
765       if (i)
766 	{
767 	  if (s->val[LANDSCAPE].b)
768 	    {
769 	      w = paper_sizes[i].height;
770 	      h = paper_sizes[i].width;
771 	    }
772 	  else
773 	    {
774 	      w = paper_sizes[i].width;
775 	      h = paper_sizes[i].height;
776 	    }
777 	}
778       else
779 	{
780 	  w = s->val[BR_X].w - s->val[TL_X].w;
781 	  h = s->val[BR_Y].w - s->val[TL_Y].w;
782 	}
783       p->pixels_per_line = w * res / 25.4;
784       p->lines = h * res / 25.4;
785     }
786 
787   p->format = (!strcmp(s->val[MODE].s,SANE_VALUE_SCAN_MODE_COLOR)) ?
788     SANE_FRAME_RGB : SANE_FRAME_GRAY;
789   p->last_frame = SANE_TRUE;
790   p->depth = bps_val[str_index (mode_list, s->val[MODE].s)];
791   p->bytes_per_line = p->depth * p->pixels_per_line / 8;
792   if (p->depth > 8)
793     p->depth = 8;
794   if (params)
795     memcpy (params, p, sizeof (SANE_Parameters));
796   return SANE_STATUS_GOOD;
797 }
798