1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 1997 Geoffrey T. Dairiki
3    This file is part of the SANE package.
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 
18    As a special exception, the authors of SANE give permission for
19    additional uses of the libraries contained in this release of SANE.
20 
21    The exception is that, if you link a SANE library with other files
22    to produce an executable, this does not by itself cause the
23    resulting executable to be covered by the GNU General Public
24    License.  Your use of that executable is in no way restricted on
25    account of linking the SANE library code into it.
26 
27    This exception does not, however, invalidate any other reasons why
28    the executable file might be covered by the GNU General Public
29    License.
30 
31    If you submit changes to SANE to the maintainers to be included in
32    a subsequent release, you agree by submitting the changes that
33    those changes may be distributed with this exception intact.
34 
35    If you write modifications of your own for SANE, it is your choice
36    whether to permit this exception to apply to your modifications.
37    If you do not wish that, delete this exception notice.
38 
39    This file is part of a SANE backend for HP Scanners supporting
40    HP Scanner Control Language (SCL).
41 */
42 
43 /*
44    Revision 1.13  2005/04/13 12:50:07  ellert-guest
45    Add missing SANE_I18N, Regenerate .po files accordingly, Update Swedish translations
46 
47    Revision 1.12  2003/10/09 19:32:50  kig-guest
48    Bug #300241: fix inverse image on 3c/4c/6100C at 10 bit depth
49 */
50 
51 /* pwd.h not available ? */
52 #if (defined(__IBMC__) || defined(__IBMCPP__))
53 #ifndef _AIX
54 #  define SANE_HOME_HP "SANE_HOME_HP"
55 #endif
56 #endif
57 
58 /* To be done: don't reallocate choice accessors */
59 /* #define HP_ALLOC_CHOICEACC_ONCE 1 */
60 /*
61 #define HP_EXPERIMENTAL
62 */ /*
63 #define STUBS
64 extern int sanei_debug_hp; */
65 #define DEBUG_DECLARE_ONLY
66 #include "../include/sane/config.h"
67 #include "../include/sane/sanei_backend.h"
68 #include "../include/lalloca.h"
69 
70 #include <stdio.h>
71 #include <string.h>
72 #include "../include/lassert.h"
73 #ifndef SANE_HOME_HP
74 #include <pwd.h>
75 #endif
76 #include <sys/types.h>
77 #include <stdlib.h>
78 #include <unistd.h>
79 #include <math.h>
80 #include "../include/sane/saneopts.h"
81 #include "../include/sane/sanei.h"
82 #include "hp.h"
83 #include "hp-option.h"
84 #include "hp-accessor.h"
85 #include "hp-scsi.h"
86 #include "hp-scl.h"
87 #include "hp-device.h"
88 
89 
90 /* FIXME: descriptors should be static? */
91 
92 typedef SANE_Option_Descriptor *	_HpSaneOption;
93 typedef struct hp_option_descriptor_s *	_HpOptionDescriptor;
94 typedef struct hp_option_s *		_HpOption;
95 
96 typedef struct hp_data_info_s *	HpDataInfo;
97 typedef struct hp_data_info_s *		_HpDataInfo;
98 
99 typedef HpAccessor		HpAccessorOptd;
100 
101 
102 static hp_bool_t hp_optset_isEnabled (HpOptSet this, HpData data,
103                      const char *name, const HpDeviceInfo *info);
104 static HpOption hp_optset_get	(HpOptSet this, HpOptionDescriptor optd);
105 static HpOption hp_optset_getByName (HpOptSet this, const char * name);
106 static SANE_Status hp_download_calib_file (HpScsi scsi);
107 static SANE_Status hp_probe_parameter_support_table (enum hp_device_compat_e
108                      compat, HpScl scl, int value);
109 
110 #define HP_EOL -9999
111 
112 /* Don't need requiries for commands that are probed */
113 #define HP_PROBE_SCL_COMMAND 1
114 
115 /* Scale factor for vectors (gtk seems not to like vectors/curves
116  * in y-range 0.0,...,1.0)
117  */
118 #define HP_VECTOR_SCALE (256.0)
119 /*
120  *
121  */
122 struct hp_option_s
123 {
124     HpOptionDescriptor  descriptor;
125     HpAccessorOptd	optd_acsr;
126     HpAccessor		data_acsr;
127     void *		extra;
128 };
129 
130 struct hp_option_descriptor_s
131 {
132     const char *	name;
133     const char *	title;
134     const char *	desc;
135     SANE_Value_Type	type;
136     SANE_Unit		unit;
137     SANE_Int		cap;
138 
139     enum hp_device_compat_e requires;   /* model dependent support flags */
140 
141     /* probe for option support */
142     SANE_Status	(*probe)    (_HpOption this, HpScsi scsi, HpOptSet optset,
143 			     HpData data);
144     SANE_Status (*program)  (HpOption this, HpScsi scsi, HpOptSet optset,
145 			     HpData data);
146     hp_bool_t	(*enable)   (HpOption this, HpOptSet optset, HpData data,
147                              const HpDeviceInfo *info);
148 
149     hp_bool_t		has_global_effect;
150     hp_bool_t		affects_scan_params;
151     hp_bool_t		program_immediate;
152     hp_bool_t           suppress_for_scan;
153     hp_bool_t		may_change;
154 
155 
156     /* This stuff should really be in a subclasses: */
157     HpScl		scl_command;
158     int                 minval, maxval, startval; /* for simulation */
159     HpChoice		choices;
160 };
161 
162 struct hp_data_info_s
163 {
164     HpScl		scl;
165 };
166 
167 static const struct hp_option_descriptor_s
168     NUM_OPTIONS[1], PREVIEW_MODE[1], SCAN_MODE[1], SCAN_RESOLUTION[1],
169 
170     CUSTOM_GAMMA[1], GAMMA_VECTOR_8x8[1],
171 #ifdef ENABLE_7x12_TONEMAPS
172     GAMMA_VECTOR_7x12[1],
173     RGB_TONEMAP[1], GAMMA_VECTOR_R[1], GAMMA_VECTOR_G[1], GAMMA_VECTOR_B[1],
174 #endif
175     HALFTONE_PATTERN[1], MEDIA[1], OUT8[1], BIT_DEPTH[1], SCAN_SOURCE[1],
176 #ifdef FAKE_COLORSEP_MATRIXES
177     SEPMATRIX[1],
178 #endif
179     MATRIX_TYPE[1];
180 
181 
182 /* Check if a certain scanner model supports a command with a given parameter
183  * value. The function returns SANE_STATUS_GOOD if the command and the
184  * value is found in the support table of that scanner.
185  * It returns SANE_STATUS_UNSUPPORTED if the command is found in the support
186  * table of that scanner, but the value is not included in the table.
187  * It returns SANE_STATUS_EOF if there is no information about that command
188  * and that scanner in the support table.
189  */
190 static SANE_Status
hp_probe_parameter_support_table(enum hp_device_compat_e compat,HpScl scl,int value)191 hp_probe_parameter_support_table (enum hp_device_compat_e compat,
192                                   HpScl scl, int value)
193 
194 {int k, j;
195  char *eptr;
196  static int photosmart_output_type[] =
197    /* HP Photosmart: only b/w, gray, color is supported */
198    { HP_COMPAT_PS, SCL_OUTPUT_DATA_TYPE, 0, 4, 5, HP_EOL };
199 
200  static int *support_table[] =
201  {
202    photosmart_output_type
203  };
204 
205  eptr = getenv ("SANE_HP_CHK_TABLE");
206  if ((eptr != NULL) && (*eptr == '0'))
207    return SANE_STATUS_EOF;
208 
209  for (k = 0; k < (int)(sizeof (support_table)/sizeof (support_table[0])); k++)
210  {
211    if ((scl == support_table[k][1]) && (support_table[k][0] & compat))
212    {
213       for (j = 2; support_table[k][j] != HP_EOL; j++)
214         if (support_table[k][j] == value) return SANE_STATUS_GOOD;
215       return SANE_STATUS_UNSUPPORTED;
216    }
217  }
218  return SANE_STATUS_EOF;
219 }
220 
221 
222 /*
223  * class HpChoice
224  */
225 typedef struct hp_choice_s * _HpChoice;
226 
227 static hp_bool_t
hp_choice_isSupported(HpChoice choice,int minval,int maxval)228 hp_choice_isSupported (HpChoice choice, int minval, int maxval)
229 {
230   return ( choice->is_emulated
231 	   || ( choice->val >= minval && choice->val <= maxval ) );
232 }
233 
234 static hp_bool_t
hp_probed_choice_isSupported(HpScsi scsi,HpScl scl,HpChoice choice,int minval,int maxval)235 hp_probed_choice_isSupported (HpScsi scsi, HpScl scl,
236                               HpChoice choice, int minval, int maxval)
237 {
238   hp_bool_t isSupported;
239   SANE_Status status;
240   enum hp_device_compat_e compat;
241 
242   if ( choice->is_emulated )
243   {
244      DBG(3, "probed_choice: value %d is emulated\n", choice->val);
245      return ( 1 );
246   }
247   if ( choice->val < minval || choice->val > maxval )
248   {
249      DBG(3, "probed_choice: value %d out of range (%d,%d)\n", choice->val,
250          minval, maxval);
251      return ( 0 );
252   }
253 
254   if (sanei_hp_device_probe (&compat, scsi) != SANE_STATUS_GOOD)
255   {
256      DBG(1, "probed_choice: Could not get compatibilities for scanner\n");
257      return ( 0 );
258   }
259 
260   status = hp_probe_parameter_support_table (compat, scl, choice->val);
261   if (status == SANE_STATUS_GOOD)
262   {
263     DBG(3, "probed_choice: command/value found in support table\n");
264     return ( 1 );
265   }
266   else if (status == SANE_STATUS_UNSUPPORTED)
267   {
268     DBG(3, "probed_choice: command found in support table, but value n.s.\n");
269     return ( 0 );
270   }
271 
272   /* Not in the support table. Try to inquire */
273   /* Fix me: It seems that the scanner does not raise a parameter error */
274   /* after specifying an unsupported command-value. */
275 
276   sanei_hp_scl_clearErrors (scsi);
277   sanei_hp_scl_set (scsi, scl, choice->val);
278 
279   isSupported = ( sanei_hp_scl_errcheck (scsi) == SANE_STATUS_GOOD );
280 
281   DBG(3, "probed_choice: value %d %s\n", choice->val,
282        isSupported ? "supported" : "not supported");
283   return isSupported;
284 }
285 
286 hp_bool_t
sanei_hp_choice_isEnabled(HpChoice this,HpOptSet optset,HpData data,const HpDeviceInfo * info)287 sanei_hp_choice_isEnabled (HpChoice this, HpOptSet optset, HpData data,
288                            const HpDeviceInfo *info)
289 {
290   if (!this->enable)
291       return 1;
292   return (*this->enable)(this, optset, data, info);
293 }
294 
295 static hp_bool_t
_cenable_incolor(HpChoice __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)296 _cenable_incolor (HpChoice __sane_unused__ this, HpOptSet optset, HpData data,
297                   const HpDeviceInfo __sane_unused__ *info)
298 {
299   return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_COLOR;
300 }
301 
302 static hp_bool_t
_cenable_notcolor(HpChoice __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)303 _cenable_notcolor (HpChoice __sane_unused__ this, HpOptSet optset, HpData data,
304                    const HpDeviceInfo __sane_unused__ *info)
305 {
306   return sanei_hp_optset_scanmode(optset, data) != HP_SCANMODE_COLOR;
307 }
308 
309 /*
310  * class HpAccessorOptd
311  */
312 static HpAccessorOptd
hp_accessor_optd_new(HpData data)313 hp_accessor_optd_new (HpData data)
314 {
315   return sanei_hp_accessor_new(data, sizeof(SANE_Option_Descriptor));
316 }
317 
318 static _HpSaneOption
hp_accessor_optd_data(HpAccessorOptd this,HpData data)319 hp_accessor_optd_data (HpAccessorOptd this, HpData data)
320 {
321   return sanei__hp_accessor_data(this, data);
322 }
323 
324 
325 
326 /*
327  * class OptionDescriptor
328  */
329 
330 static SANE_Status
hp_option_descriptor_probe(HpOptionDescriptor desc,HpScsi scsi,HpOptSet optset,HpData data,HpOption * newoptp)331 hp_option_descriptor_probe (HpOptionDescriptor desc, HpScsi scsi,
332 			    HpOptSet optset, HpData data, HpOption * newoptp)
333 {
334   _HpOption 	new;
335   SANE_Status	status;
336   _HpSaneOption	optd;
337 
338   new = sanei_hp_alloc(sizeof(*new));
339   new->descriptor  = desc;
340   if (!(new->optd_acsr = hp_accessor_optd_new(data)))
341       return SANE_STATUS_NO_MEM;
342   new->data_acsr = 0;
343   optd = hp_accessor_optd_data(new->optd_acsr, data);
344 
345   memset(optd, 0, sizeof(*optd));
346   optd->name  = desc->name;
347   optd->title = desc->title;
348   optd->desc  = desc->desc;
349   optd->type  = desc->type;
350   optd->unit  = desc->unit;
351   optd->cap   = desc->cap;
352 
353   /*
354    * Probe function will set optd->size, optd->constraint_type,
355    * and optd->constraint.
356    * and also new->accessor
357    * and possibly new->extra
358    */
359   if (desc->probe)
360     {
361       if (FAILED( status = (*desc->probe)(new, scsi, optset, data) ))
362 	{
363 	  /* hp_accessor_optd_destoy(new->optd_acsr) */
364 	  sanei_hp_free(new);
365 	  return status;
366 	}
367     }
368 
369   *newoptp = new;
370   return SANE_STATUS_GOOD;
371 }
372 
373 
374 /*
375  * class Option
376  */
377 static HpSaneOption
hp_option_saneoption(HpOption this,HpData data)378 hp_option_saneoption (HpOption this, HpData data)
379 {
380   return hp_accessor_optd_data(this->optd_acsr, data);
381 }
382 
383 static _HpSaneOption
_hp_option_saneoption(HpOption this,HpData data)384 _hp_option_saneoption (HpOption this, HpData data)
385 {
386   return hp_accessor_optd_data(this->optd_acsr, data);
387 }
388 
389 static SANE_Status
hp_option_download(HpOption this,HpData data,HpOptSet optset,HpScsi scsi)390 hp_option_download (HpOption this, HpData data, HpOptSet optset, HpScsi scsi)
391 {
392   HpScl scl = this->descriptor->scl_command;
393   int value;
394 
395   if (IS_SCL_CONTROL(scl))
396   {
397       value = sanei_hp_accessor_getint(this->data_acsr, data);
398       if (   (scl == SCL_DATA_WIDTH)
399           && (sanei_hp_optset_scanmode (optset, data) == HP_SCANMODE_COLOR) )
400       {
401         value *= 3;
402       }
403       return sanei_hp_scl_set(scsi, scl, value);
404   }
405   else if (IS_SCL_DATA_TYPE(scl))
406       return sanei_hp_scl_download(scsi, scl,
407 			     sanei_hp_accessor_data(this->data_acsr, data),
408 			     sanei_hp_accessor_size(this->data_acsr));
409   assert(!scl);
410   return SANE_STATUS_INVAL;
411 }
412 
413 static SANE_Status
hp_option_upload(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)414 hp_option_upload (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
415 {
416   HpScl scl = this->descriptor->scl_command;
417   int	val;
418 
419   if (IS_SCL_CONTROL(scl))
420     {
421       RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, 0, 0) );
422       if (   (scl == SCL_DATA_WIDTH)
423           && (sanei_hp_optset_scanmode (optset, data) == HP_SCANMODE_COLOR) )
424       {
425         val /= 3;
426       }
427       sanei_hp_accessor_setint(this->data_acsr, data, val);
428       return SANE_STATUS_GOOD;
429     }
430   else if (IS_SCL_DATA_TYPE(scl))
431       return sanei_hp_scl_upload(scsi, scl,
432 			   sanei__hp_accessor_data(this->data_acsr, data),
433 			   sanei_hp_accessor_size(this->data_acsr));
434   assert(!scl);
435   return SANE_STATUS_INVAL;
436 }
437 
438 static SANE_Status
hp_option_program(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)439 hp_option_program (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
440 {
441  const HpDeviceInfo *info;
442 
443   DBG(10, "hp_option_program: name=%s, enable=0x%08lx, program=0x%08lx\n",
444       this->descriptor->name, (long)this->descriptor->enable,
445       (long)this->descriptor->program);
446 
447   /* Replaced by flag suppress_for_scan
448    * if (this->descriptor->program_immediate)
449    * {
450    *    DBG(10, "hp_option_program: is program_immediate. Dont program now.\n");
451    *    return SANE_STATUS_GOOD;
452    * }
453    */
454 
455   if (!this->descriptor->program)
456       return SANE_STATUS_GOOD;
457 
458   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
459   if (this->descriptor->enable
460       && !(*this->descriptor->enable)(this, optset, data, info))
461       return SANE_STATUS_GOOD;
462 
463   return (*this->descriptor->program)(this, scsi, optset, data);
464 }
465 
466 static SANE_Status
hp_option_get(HpOption this,HpData data,void * valp)467 hp_option_get (HpOption this, HpData data, void * valp)
468 {
469   if (!this->data_acsr)
470       return SANE_STATUS_INVAL;
471   return sanei_hp_accessor_get(this->data_acsr, data, valp);
472 }
473 
474 static hp_bool_t
_values_are_equal(HpOption this,HpData data,const void * val1,const void * val2)475 _values_are_equal (HpOption this, HpData data,
476 		   const void * val1, const void * val2)
477 {
478   HpSaneOption optd = hp_option_saneoption(this, data);
479 
480   if (optd->type == SANE_TYPE_STRING)
481       return strncmp((const char *)val1, (const char *)val2, optd->size) == 0;
482   else
483       return memcmp(val1, val2, optd->size) == 0;
484 }
485 
486 static hp_bool_t
hp_option_isImmediate(HpOption this)487 hp_option_isImmediate (HpOption this)
488 {
489   return (   this->descriptor->program_immediate
490           && this->descriptor->program );
491 }
492 
493 static SANE_Status
hp_option_imm_set(HpOptSet optset,HpOption this,HpData data,void * valp,SANE_Int * info,HpScsi scsi)494 hp_option_imm_set (HpOptSet optset, HpOption this, HpData data,
495                    void * valp, SANE_Int * info, HpScsi scsi)
496 {
497   HpSaneOption	optd	= hp_option_saneoption(this, data);
498   hp_byte_t *	old_val	= alloca(optd->size);
499   SANE_Status	status;
500 
501   assert (this->descriptor->program_immediate && this->descriptor->program);
502 
503   if (!SANE_OPTION_IS_SETTABLE(optd->cap))
504       return SANE_STATUS_INVAL;
505 
506   DBG(10,"hp_option_imm_set: %s\n", this->descriptor->name);
507 
508   if ( this->descriptor->type == SANE_TYPE_BUTTON )
509     {
510       status = (*this->descriptor->program)(this, scsi, optset, data);
511       if ( !FAILED(status) && info )
512         {
513 	  if (this->descriptor->has_global_effect)
514 	    *info |= SANE_INFO_RELOAD_OPTIONS;
515 	  if (this->descriptor->affects_scan_params)
516 	    *info |= SANE_INFO_RELOAD_PARAMS;
517         }
518       return status;
519     }
520 
521   if ( !this->data_acsr )
522       return SANE_STATUS_INVAL;
523 
524   if (!old_val)
525       return SANE_STATUS_NO_MEM;
526 
527   if (FAILED( status = sanei_constrain_value(optd, valp, info) ))
528     {
529       DBG(1, "option_imm_set: %s: constrain_value failed :%s\n",
530 	  this->descriptor->name, sane_strstatus(status));
531       return status;
532     }
533 
534   RETURN_IF_FAIL( sanei_hp_accessor_get(this->data_acsr, data, old_val) );
535 
536   if (_values_are_equal(this, data, old_val, valp))
537     {
538       DBG(3, "option_imm_set: value unchanged\n");
539       return SANE_STATUS_GOOD;
540     }
541 
542   if (info)
543       memcpy(old_val, valp, optd->size); /* Save requested value */
544 
545   RETURN_IF_FAIL( sanei_hp_accessor_set(this->data_acsr, data, valp) );
546 
547   if ( this->descriptor->type == SANE_TYPE_STRING )
548      RETURN_IF_FAIL( (*this->descriptor->program)(this, scsi, optset, data) );
549 
550   if (info)
551     {
552       if (!_values_are_equal(this, data, old_val, valp))
553 	  *info |= SANE_INFO_INEXACT;
554       if (this->descriptor->has_global_effect)
555 	  *info |= SANE_INFO_RELOAD_OPTIONS;
556       if (this->descriptor->affects_scan_params)
557 	  *info |= SANE_INFO_RELOAD_PARAMS;
558     }
559 
560   return SANE_STATUS_GOOD;
561 }
562 
563 static SANE_Status
hp_option_set(HpOption this,HpData data,void * valp,SANE_Int * info)564 hp_option_set (HpOption this, HpData data, void * valp, SANE_Int * info)
565 {
566   HpSaneOption	optd	= hp_option_saneoption(this, data);
567   hp_byte_t *	old_val	= alloca(optd->size);
568   SANE_Status	status;
569   char sval[64];
570 
571 
572   if (!SANE_OPTION_IS_SETTABLE(optd->cap) || !this->data_acsr)
573       return SANE_STATUS_INVAL;
574   if (!old_val)
575       return SANE_STATUS_NO_MEM;
576 
577   sval[0] = '\0';
578   if (this->descriptor->type == SANE_TYPE_INT)
579     sprintf (sval," value=%d", *(int*)valp);
580 
581   DBG(10,"hp_option_set: %s%s\n", this->descriptor->name, sval);
582 
583   if (FAILED( status = sanei_constrain_value(optd, valp, info) ))
584     {
585       DBG(1, "option_set: %s: constrain_value failed :%s\n",
586 	  this->descriptor->name, sane_strstatus(status));
587       return status;
588     }
589 
590   RETURN_IF_FAIL( sanei_hp_accessor_get(this->data_acsr, data, old_val) );
591 
592   if (_values_are_equal(this, data, old_val, valp))
593     {
594       DBG(3, "option_set: %s: value unchanged\n",this->descriptor->name);
595       return SANE_STATUS_GOOD;
596     }
597 
598   if (info)
599       memcpy(old_val, valp, optd->size); /* Save requested value */
600 
601   RETURN_IF_FAIL( sanei_hp_accessor_set(this->data_acsr, data, valp) );
602 
603   if (info)
604     {
605       if (!_values_are_equal(this, data, old_val, valp))
606 	  *info |= SANE_INFO_INEXACT;
607       if (this->descriptor->has_global_effect)
608 	  *info |= SANE_INFO_RELOAD_OPTIONS;
609       if (this->descriptor->affects_scan_params)
610 	  *info |= SANE_INFO_RELOAD_PARAMS;
611 
612       DBG(3, "option_set: %s: info=0x%lx\n",this->descriptor->name,
613           (long)*info);
614     }
615 
616   return SANE_STATUS_GOOD;
617 }
618 
619 static int
hp_option_getint(HpOption this,HpData data)620 hp_option_getint (HpOption this, HpData data)
621 {
622   return sanei_hp_accessor_getint(this->data_acsr, data);
623 }
624 
625 static SANE_Status
hp_option_imm_control(HpOptSet optset,HpOption this,HpData data,SANE_Action action,void * valp,SANE_Int * infop,HpScsi scsi)626 hp_option_imm_control (HpOptSet optset, HpOption this, HpData data,
627 		   SANE_Action action, void * valp, SANE_Int *infop,
628 		   HpScsi scsi)
629 {
630   HpSaneOption	optd	= hp_option_saneoption(this, data);
631 
632   if (!SANE_OPTION_IS_ACTIVE(optd->cap))
633       return SANE_STATUS_INVAL;
634 
635   switch (action) {
636   case SANE_ACTION_GET_VALUE:
637       return hp_option_get(this, data, valp);
638   case SANE_ACTION_SET_VALUE:
639       return hp_option_imm_set(optset, this, data, valp, infop, scsi);
640   case SANE_ACTION_SET_AUTO:
641   default:
642       return SANE_STATUS_INVAL;
643   }
644 }
645 
646 static SANE_Status
hp_option_control(HpOption this,HpData data,SANE_Action action,void * valp,SANE_Int * infop)647 hp_option_control (HpOption this, HpData data,
648                    SANE_Action action, void * valp, SANE_Int *infop)
649 {
650   HpSaneOption  optd    = hp_option_saneoption(this, data);
651 
652   if (!SANE_OPTION_IS_ACTIVE(optd->cap))
653       return SANE_STATUS_INVAL;
654 
655   switch (action) {
656   case SANE_ACTION_GET_VALUE:
657       return hp_option_get(this, data, valp);
658   case SANE_ACTION_SET_VALUE:
659       return hp_option_set(this, data, valp, infop);
660   case SANE_ACTION_SET_AUTO:
661   default:
662       return SANE_STATUS_INVAL;
663   }
664 }
665 
666 
667 static void
hp_option_reprogram(HpOption this,HpOptSet optset,HpData data,HpScsi scsi)668 hp_option_reprogram (HpOption this, HpOptSet optset, HpData data, HpScsi scsi)
669 {
670   if (this->descriptor->may_change)
671   {
672     DBG(5, "hp_option_reprogram: %s\n", this->descriptor->name);
673 
674     hp_option_program (this, scsi, optset, data);
675   }
676 }
677 
678 
679 static void
hp_option_reprobe(HpOption this,HpOptSet optset,HpData data,HpScsi scsi)680 hp_option_reprobe (HpOption this, HpOptSet optset, HpData data, HpScsi scsi)
681 {
682   if (this->descriptor->may_change)
683   {
684     DBG(5, "hp_option_reprobe: %s\n", this->descriptor->name);
685 
686     (*this->descriptor->probe)((_HpOption)this, scsi, optset, data);
687   }
688 }
689 
690 static void
hp_option_updateEnable(HpOption this,HpOptSet optset,HpData data,const HpDeviceInfo * info)691 hp_option_updateEnable (HpOption this, HpOptSet optset, HpData data,
692                         const HpDeviceInfo *info)
693 {
694   hp_bool_t 	(*f)(HpOption, HpOptSet, HpData, const HpDeviceInfo *)
695                     = this->descriptor->enable;
696   _HpSaneOption	optd 	= _hp_option_saneoption(this, data);
697 
698   if (!f || (*f)(this, optset, data, info))
699       optd->cap &= ~SANE_CAP_INACTIVE;
700   else
701       optd->cap |= SANE_CAP_INACTIVE;
702 }
703 
704 static hp_bool_t
hp_option_isInternal(HpOption this)705 hp_option_isInternal (HpOption this)
706 {
707   return this->descriptor->name[0] == '_';
708 }
709 
710 
711 /*
712  * Option probe functions
713  */
714 
715 static SANE_Status
_set_range(HpOption opt,HpData data,SANE_Word min,SANE_Word quant,SANE_Word max)716 _set_range (HpOption opt, HpData data,
717 	    SANE_Word min, SANE_Word quant, SANE_Word max)
718 {
719   _HpSaneOption	optd	= _hp_option_saneoption(opt, data);
720   SANE_Range * range	= sanei_hp_alloc(sizeof(*range)); /* FIXME: leak? */
721 
722   if (! range)
723       return SANE_STATUS_NO_MEM;
724 
725   range->min = min;
726   range->max = max;
727   range->quant = quant;
728   optd->constraint.range = range;
729   optd->constraint_type = SANE_CONSTRAINT_RANGE;
730 
731   return SANE_STATUS_GOOD;
732 }
733 
734 static void
_set_size(HpOption opt,HpData data,SANE_Int size)735 _set_size (HpOption opt, HpData data, SANE_Int size)
736 {
737   _hp_option_saneoption(opt, data)->size = size;
738 }
739 
740 /* #ifdef HP_EXPERIMENTAL */
741 static SANE_Status
_probe_int(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)742 _probe_int (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data)
743 {
744   HpScl		scl	= this->descriptor->scl_command;
745   int		minval, maxval;
746   int		val	= 0;
747 
748   assert(scl);
749 
750   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val,  &minval, &maxval) );
751 
752   if (minval >= maxval)
753       return SANE_STATUS_UNSUPPORTED;
754 
755   /* If we don't have an accessor, get one */
756   if (!this->data_acsr)
757   {
758       if (!(this->data_acsr = sanei_hp_accessor_int_new(data)))
759           return SANE_STATUS_NO_MEM;
760   }
761   sanei_hp_accessor_setint(this->data_acsr, data, val);
762   _set_size(this, data, sizeof(SANE_Int));
763   return _set_range(this, data, minval, 1, maxval);
764 }
765 /* #endif */
766 
767 static SANE_Status
_probe_int_brightness(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)768 _probe_int_brightness (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
769                       HpData data)
770 {
771   HpScl		scl	= this->descriptor->scl_command;
772   int		minval, maxval;
773   int		val	= 0;
774   hp_bool_t     simulate;
775 
776   assert(scl);
777 
778   simulate = (   sanei_hp_device_support_get (
779                     sanei_hp_scsi_devicename  (scsi), scl, 0, 0)
780               != SANE_STATUS_GOOD );
781 
782   if ( simulate )
783   {
784     val = this->descriptor->startval;
785     minval = this->descriptor->minval;
786     maxval = this->descriptor->maxval;
787   }
788   else
789   {
790     RETURN_IF_FAIL ( sanei_hp_scl_inquire(scsi,scl,&val,&minval,&maxval) );
791   }
792 
793   if (minval >= maxval)
794       return SANE_STATUS_UNSUPPORTED;
795 
796   /* If we don't have an accessor, get one */
797   if (!this->data_acsr)
798   {
799       if (!(this->data_acsr = sanei_hp_accessor_int_new(data)))
800           return SANE_STATUS_NO_MEM;
801   }
802 
803   sanei_hp_accessor_setint(this->data_acsr, data, val);
804   _set_size(this, data, sizeof(SANE_Int));
805   return _set_range(this, data, minval, 1, maxval);
806 }
807 
808 static SANE_Status
_probe_resolution(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)809 _probe_resolution (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
810                    HpData data)
811 {
812   int		minval, maxval, min2, max2;
813   int		val	= 0, val2;
814   int           quant   = 1;
815   enum hp_device_compat_e compat;
816 
817   /* Check for supported resolutions in both directions */
818   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_X_RESOLUTION, &val,
819                                  &minval, &maxval) );
820   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_Y_RESOLUTION, &val2, &min2, &max2));
821   if ( min2 > minval ) minval = min2;
822   if ( max2 < maxval ) maxval = max2;
823 
824   if (minval >= maxval)
825       return SANE_STATUS_UNSUPPORTED;
826 
827   /* If we don't have an accessor, get one */
828   if (!this->data_acsr)
829   {
830     if (!(this->data_acsr = sanei_hp_accessor_int_new(data)))
831       return SANE_STATUS_NO_MEM;
832   }
833   sanei_hp_accessor_setint(this->data_acsr, data, val);
834   _set_size(this, data, sizeof(SANE_Int));
835 
836   /* The HP OfficeJet Pro 1150C crashes the scan head when scanning at
837    * resolutions less than 42 dpi.  Set a safe minimum resolution.
838    * Hopefully 50 dpi is safe enough. */
839   if ((sanei_hp_device_probe(&compat,scsi)==SANE_STATUS_GOOD) &&
840       ((compat&(HP_COMPAT_OJ_1150C|HP_COMPAT_OJ_1170C))==HP_COMPAT_OJ_1150C)) {
841 	if (minval<50) minval=50;
842   }
843 
844   /* HP Photosmart scanner does not allow scanning at arbitrary resolutions */
845   /* for slides/negatives. Must be multiple of 300 dpi. Set quantization. */
846 
847   if (   (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD)
848       && (compat & HP_COMPAT_PS) )
849   {
850       int val, mi, ma;
851 
852       if (   (sanei_hp_scl_inquire(scsi, SCL_MEDIA, &val, &mi, &ma)
853               == SANE_STATUS_GOOD)
854           && ((val == HP_MEDIA_SLIDE) || (val == HP_MEDIA_NEGATIVE)) )
855       {
856           quant = 300;
857           minval = (minval+quant-1)/quant;
858           minval *= quant;
859           maxval = (maxval+quant-1)/quant;
860           maxval *= quant;
861       }
862   }
863   DBG(5, "_probe_resolution: set range %d..%d, quant=%d\n",minval,maxval,quant);
864 
865   return _set_range(this, data, minval, quant, maxval);
866 }
867 
868 static SANE_Status
_probe_bool(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)869 _probe_bool (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
870              HpData data)
871 {
872   HpScl		scl	= this->descriptor->scl_command;
873   int		val	= 0;
874 
875   if (scl)
876       RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, 0, 0) );
877 
878   /* If we don't have an accessor, get one */
879   if (!this->data_acsr)
880   {
881       if (!(this->data_acsr = sanei_hp_accessor_bool_new(data)))
882            return SANE_STATUS_NO_MEM;
883   }
884 
885   sanei_hp_accessor_setint(this->data_acsr, data, val);
886   _set_size(this, data, sizeof(SANE_Bool));
887   return SANE_STATUS_GOOD;
888 }
889 
890 
891 static SANE_Status
_probe_change_doc(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)892 _probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
893                    HpData data)
894 
895 {SANE_Status status;
896  int cap = 0;
897 
898   DBG(2, "probe_change_doc: inquire ADF capability\n");
899 
900   status = sanei_hp_scl_inquire(scsi, SCL_ADF_CAPABILITY, &cap, 0, 0);
901   if ( (status != SANE_STATUS_GOOD) || (cap == 0))
902     return SANE_STATUS_UNSUPPORTED;
903 
904   DBG(2, "probe_change_doc: check if change document is supported\n");
905 
906   status = sanei_hp_scl_inquire(scsi, SCL_CHANGE_DOC, &cap, 0, 0);
907   if ( status != SANE_STATUS_GOOD )
908     return SANE_STATUS_UNSUPPORTED;
909 
910   /* If we don't have an accessor, get one */
911   if (!this->data_acsr)
912   {
913       if (!(this->data_acsr = sanei_hp_accessor_bool_new(data)))
914           return SANE_STATUS_NO_MEM;
915   }
916 
917   sanei_hp_accessor_setint(this->data_acsr, data, cap);
918   _set_size(this, data, sizeof(SANE_Bool));
919 
920   return SANE_STATUS_GOOD;
921 }
922 
923 /* The OfficeJets support SCL_UNLOAD even when no ADF is installed, so
924  * this function was added to check for SCL_ADF_CAPABILITY, similar to
925  * _probe_change_doc(), to hide the unnecessary "Unload" button on
926  * non-ADF OfficeJets. */
927 static SANE_Status
_probe_unload(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)928 _probe_unload (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
929                HpData data)
930 
931 {SANE_Status status;
932  int cap = 0;
933 
934   DBG(2, "probe_unload: inquire ADF capability\n");
935 
936   status = sanei_hp_scl_inquire(scsi, SCL_ADF_CAPABILITY, &cap, 0, 0);
937   if ( (status != SANE_STATUS_GOOD) || (cap == 0))
938     return SANE_STATUS_UNSUPPORTED;
939 
940   DBG(2, "probe_unload: check if unload is supported\n");
941 
942   status = sanei_hp_scl_inquire(scsi, SCL_UNLOAD, &cap, 0, 0);
943   if ( status != SANE_STATUS_GOOD )
944     return SANE_STATUS_UNSUPPORTED;
945 
946   /* If we don't have an accessor, get one */
947   if (!this->data_acsr)
948   {
949       if (!(this->data_acsr = sanei_hp_accessor_bool_new(data)))
950           return SANE_STATUS_NO_MEM;
951   }
952 
953   sanei_hp_accessor_setint(this->data_acsr, data, cap);
954   _set_size(this, data, sizeof(SANE_Bool));
955 
956   return SANE_STATUS_GOOD;
957 }
958 
959 static SANE_Status
_probe_calibrate(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)960 _probe_calibrate (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
961                   HpData data)
962 {
963   int val = 0;  /* Always false */
964   int minval, maxval;
965   int media;
966   int download_calib_file = 1;
967   enum hp_device_compat_e compat;
968 
969   /* The OfficeJets don't seem to support calibration, so we'll
970    * remove it from the option list to reduce frontend clutter. */
971   if ((sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) &&
972       (compat & HP_COMPAT_OJ_1150C)) {
973 	return SANE_STATUS_UNSUPPORTED;
974   }
975 
976   /* If we have a Photosmart scanner, we only download the calibration file */
977   /* when medium is set to prints */
978   media = -1;
979   if (sanei_hp_scl_inquire(scsi, SCL_MEDIA, &val, &minval, &maxval)
980       == SANE_STATUS_GOOD)
981     media = val; /* 3: prints, 2: slides, 1: negatives */
982 
983   if (   (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD)
984       && (compat & HP_COMPAT_PS)
985       && (media != HP_MEDIA_PRINT))
986     download_calib_file = 0;
987 
988   /* Recalibrate can not be probed, because it has no inquire ID. */
989   /* And the desired ID of 10963 does not work. So we have to trust */
990   /* the evaluated HP model number. */
991 
992   /* If we don't have an accessor, get one */
993   if (!this->data_acsr)
994   {
995       if (!(this->data_acsr = sanei_hp_accessor_bool_new(data)))
996           return SANE_STATUS_NO_MEM;
997   }
998 
999   sanei_hp_accessor_setint(this->data_acsr, data, val);
1000   _set_size(this, data, sizeof(SANE_Bool));
1001 
1002   /* Try to download calibration map */
1003   if (download_calib_file)
1004     hp_download_calib_file ( scsi );
1005 
1006   return SANE_STATUS_GOOD;
1007 }
1008 
1009 
1010 static HpChoice
_make_choice_list(HpChoice choice,int minval,int maxval)1011 _make_choice_list (HpChoice choice, int minval, int maxval)
1012 {
1013   static struct hp_choice_s bad = { 0, 0, 0, 0, 0 }; /* FIXME: hack */
1014 
1015   /* FIXME: Another memory leak */
1016 
1017   if (!choice->name)
1018       return 0;
1019   else if (hp_choice_isSupported(choice, minval, maxval))
1020     {
1021       _HpChoice new = sanei_hp_memdup(choice, sizeof(*new));
1022       if (!new)
1023 	  return &bad;
1024       new->next = _make_choice_list(choice + 1, minval, maxval);
1025       return new;
1026     }
1027   else
1028       return _make_choice_list(choice + 1, minval, maxval);
1029 }
1030 
1031 static HpChoice
_make_probed_choice_list(HpScsi scsi,HpScl scl,HpChoice choice,int minval,int maxval)1032 _make_probed_choice_list (HpScsi scsi, HpScl scl, HpChoice choice,
1033                           int minval, int maxval)
1034 {
1035   static struct hp_choice_s bad = { 0, 0, 0, 0, 0 }; /* FIXME: hack */
1036 
1037   /* FIXME: Another memory leak */
1038 
1039   if (!choice->name)
1040       return 0;
1041   else if (hp_probed_choice_isSupported(scsi, scl, choice, minval, maxval))
1042     {
1043       _HpChoice new = sanei_hp_memdup(choice, sizeof(*new));
1044       if (!new)
1045 	  return &bad;
1046       new->next = _make_probed_choice_list(scsi, scl, choice + 1, minval, maxval);
1047       return new;
1048     }
1049   else
1050       return _make_probed_choice_list(scsi, scl, choice + 1, minval, maxval);
1051 }
1052 
1053 static void
_set_stringlist(HpOption this,HpData data,SANE_String_Const * strlist)1054 _set_stringlist (HpOption this, HpData data,  SANE_String_Const * strlist)
1055 {
1056   _HpSaneOption optd = _hp_option_saneoption(this, data);
1057   optd->constraint.string_list = strlist;
1058   optd->constraint_type = SANE_CONSTRAINT_STRING_LIST;
1059 }
1060 
1061 static SANE_Status
_probe_choice(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1062 _probe_choice (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1063 {
1064   HpScl		scl	= this->descriptor->scl_command;
1065   int		minval, maxval, val;
1066   HpChoice	choices;
1067   const HpDeviceInfo *info;
1068   enum hp_device_compat_e compat;
1069 
1070   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, &minval, &maxval) );
1071   DBG(3, "choice_option_probe: '%s': val, min, max = %d, %d, %d\n",
1072       this->descriptor->name, val, minval, maxval);
1073 
1074   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1075 
1076   /* Datawidth needs a special handling. The choicelist consists of */
1077   /* values of bits per sample. But the minval/maxval uses bits per pixel */
1078   if ( scl == SCL_DATA_WIDTH )
1079   {
1080     enum hp_scanmode_e scanmode = sanei_hp_optset_scanmode (optset, data);
1081 
1082     /* The data width inquiries seem not to work properly on PhotoSmart */
1083     /* Sometimes they report just 24 bits, but support 30 bits too. */
1084     /* Sometimes they report min/max to be 24/8. Assume they all support */
1085     /* at least 10 bits per channel for RGB. Grayscale is only supported */
1086     /* with 8 bits. */
1087     if (   (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD)
1088         && (compat & HP_COMPAT_PS))
1089     {
1090       if (scanmode == HP_SCANMODE_GRAYSCALE)
1091       {
1092         minval = 8; if (maxval < 8) maxval = 8;
1093       }
1094       else if (scanmode == HP_SCANMODE_COLOR)
1095       {
1096         minval = 24; if (maxval < 30) maxval = 30;
1097       }
1098       DBG(1, "choice_option_probe: set max. datawidth to %d for photosmart\n",
1099           maxval);
1100     }
1101 
1102     if ( scanmode ==  HP_SCANMODE_COLOR )
1103     {
1104       minval /= 3; if ( minval <= 0) minval = 1;
1105       maxval /= 3; if ( maxval <= 0) maxval = 1;
1106       val /= 3; if (val <= 0) val = 1;
1107     }
1108 
1109 #if 0
1110     /* The OfficeJets claim to support >8 bits per color, but it may not
1111      * work on some models.  This code (if not commented out) disables it. */
1112     if ((sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) &&
1113         (compat & HP_COMPAT_OJ_1150C)) {
1114           if (maxval>8) maxval=8;
1115     }
1116 #endif
1117   }
1118 
1119   choices = _make_choice_list(this->descriptor->choices, minval, maxval);
1120   if (choices && !choices->name) /* FIXME: hack */
1121       return SANE_STATUS_NO_MEM;
1122   if (!choices)
1123       return SANE_STATUS_UNSUPPORTED;
1124 
1125   /* If no accessor, create one here. */
1126 #ifdef HP_ALLOC_CHOICEACC_ONCE
1127   if (!(this->data_acsr))
1128 #endif
1129       this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1130                           this->descriptor->may_change);
1131 
1132   if (!(this->data_acsr))
1133       return SANE_STATUS_NO_MEM;
1134   sanei_hp_accessor_setint(this->data_acsr, data, val);
1135 
1136   _set_stringlist(this, data,
1137        sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1138                   0, 0, info));
1139   _set_size(this, data,
1140       sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1141   return SANE_STATUS_GOOD;
1142 }
1143 
1144 static SANE_Status
_probe_each_choice(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1145 _probe_each_choice (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1146                     HpData data)
1147 {
1148   HpScl		scl	= this->descriptor->scl_command;
1149   int		minval, maxval, val;
1150   HpChoice	choices;
1151   const HpDeviceInfo *info;
1152 
1153   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, &minval, &maxval) );
1154   DBG(3, "choice_option_probe_each: '%s': val, min, max = %d, %d, %d\n",
1155       this->descriptor->name, val, minval, maxval);
1156   DBG(3, "choice_option_probe_each: test all values for '%s' separately\n",
1157       this->descriptor->name);
1158 
1159   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1160   choices = _make_probed_choice_list(scsi, scl, this->descriptor->choices,
1161                                      minval, maxval);
1162 
1163   DBG(3, "choice_option_probe_each: restore previous value %d for '%s'\n",
1164       val, this->descriptor->name);
1165                                     /* Restore current value */
1166   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, scl, val) );
1167 
1168   if (choices && !choices->name) /* FIXME: hack */
1169       return SANE_STATUS_NO_MEM;
1170   if (!choices)
1171       return SANE_STATUS_UNSUPPORTED;
1172 
1173   /* If we don't have an accessor, get one */
1174 #ifdef HP_ALLOC_CHOICEACC_ONCE
1175   if (!this->data_acsr)
1176 #endif
1177   {
1178       if (!(this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1179                                 this->descriptor->may_change )))
1180           return SANE_STATUS_NO_MEM;
1181   }
1182 
1183   sanei_hp_accessor_setint(this->data_acsr, data, val);
1184 
1185   _set_stringlist(this, data,
1186        sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1187                   0, 0, info));
1188   _set_size(this, data,
1189        sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1190   return SANE_STATUS_GOOD;
1191 }
1192 
1193 /* pseudo probe for exposure times in Photosmart */
1194 static SANE_Status
_probe_ps_exposure_time(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1195 _probe_ps_exposure_time (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1196                          HpData data)
1197 {
1198     int           minval = 0, maxval = 9, val = 0;
1199     HpChoice      choices;
1200     const HpDeviceInfo *info;
1201 
1202     choices = _make_choice_list(this->descriptor->choices, minval, maxval);
1203     if (choices && !choices->name) /* FIXME: hack */
1204        return SANE_STATUS_NO_MEM;
1205 
1206     info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1207 
1208     /* If we don't have an accessor, get one */
1209 #ifdef HP_ALLOC_CHOICEACC_ONCE
1210     if (!this->data_acsr)
1211 #endif
1212     {
1213       if (!(this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1214                                   this->descriptor->may_change )))
1215          return SANE_STATUS_NO_MEM;
1216     }
1217 
1218     sanei_hp_accessor_setint(this->data_acsr, data, val);
1219 
1220     _set_stringlist(this, data,
1221            sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1222                0, 0, info));
1223     _set_size(this, data,
1224            sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1225     return SANE_STATUS_GOOD;
1226 }
1227 
1228 /* probe scan type (normal, adf, xpa) */
1229 static SANE_Status
_probe_scan_type(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1230 _probe_scan_type (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1231                   HpData data)
1232 {
1233   int           val;
1234   int           numchoices = 0;
1235   HpChoice      choices;
1236   SANE_Status   status;
1237   const HpDeviceInfo *info;
1238   struct hp_choice_s scan_types[4];
1239   struct hp_choice_s nch = { 0, 0, 0, 0, 0 };
1240   enum hp_device_compat_e compat;
1241 
1242   /* We always have normal scan mode */
1243   scan_types[numchoices++] = this->descriptor->choices[0];
1244 
1245   if ( sanei_hp_device_probe (&compat, scsi) != SANE_STATUS_GOOD )
1246     compat = 0;
1247 
1248   /* Inquire ADF Capability. PhotoSmart scanner reports ADF capability, */
1249   /* but it makes no sense. */
1250   if ((compat & HP_COMPAT_PS) == 0)
1251   {
1252     status = sanei_hp_scl_inquire(scsi, SCL_ADF_CAPABILITY, &val, 0, 0);
1253     if ( (status == SANE_STATUS_GOOD) && (val == 1) )
1254     {
1255       scan_types[numchoices++] = this->descriptor->choices[1];
1256     }
1257   }
1258 
1259   /* Inquire XPA capability is supported only by IIcx and 6100c/4c/3c. */
1260   /* But more devices support XPA scan window. So don't inquire XPA cap. */
1261   if ( compat & (  HP_COMPAT_2CX | HP_COMPAT_4C | HP_COMPAT_4P
1262                  | HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_6200C) &&
1263        !(compat&HP_COMPAT_OJ_1150C) )
1264   {
1265     scan_types[numchoices++] = this->descriptor->choices[2];
1266   }
1267 
1268   /* Only normal scan type available ? No need to display choice */
1269   if (numchoices <= 1) return SANE_STATUS_UNSUPPORTED;
1270 
1271   scan_types[numchoices] = nch;
1272   val = 0;
1273 
1274   choices = _make_choice_list(scan_types, 0, numchoices);
1275   if (choices && !choices->name) /* FIXME: hack */
1276      return SANE_STATUS_NO_MEM;
1277 
1278   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1279 
1280   /* If we don't have an accessor, get one */
1281 #ifdef HP_ALLOC_CHOICEACC_ONCE
1282   if (!this->data_acsr)
1283 #endif
1284   {
1285       if (!(this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1286                                 this->descriptor->may_change )))
1287          return SANE_STATUS_NO_MEM;
1288   }
1289 
1290   sanei_hp_accessor_setint(this->data_acsr, data, val);
1291 
1292   _set_stringlist(this, data,
1293          sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1294              0, 0, info));
1295   _set_size(this, data,
1296          sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1297   return SANE_STATUS_GOOD;
1298 }
1299 
1300 static SANE_Status
_probe_mirror_horiz(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1301 _probe_mirror_horiz (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1302                      HpData data)
1303 {
1304   HpScl		scl	= this->descriptor->scl_command;
1305   int		minval, maxval, val, sec_dir;
1306   HpChoice	choices;
1307   const HpDeviceInfo *info;
1308 
1309   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, &minval, &maxval) );
1310   DBG(3, "probe_mirror_horiz: '%s': val, min, max = %d, %d, %d\n",
1311       this->descriptor->name, val, minval, maxval);
1312 
1313   /* Look if the device supports the (?) inquire secondary scan-direction */
1314   if ( sanei_hp_scl_inquire(scsi, SCL_SECONDARY_SCANDIR, &sec_dir, 0, 0)
1315          == SANE_STATUS_GOOD )
1316     minval = HP_MIRROR_HORIZ_CONDITIONAL;
1317 
1318   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1319   choices = _make_choice_list(this->descriptor->choices, minval, maxval);
1320   if (choices && !choices->name) /* FIXME: hack */
1321       return SANE_STATUS_NO_MEM;
1322   if (!choices)
1323       return SANE_STATUS_UNSUPPORTED;
1324 
1325   /* If we don't have an accessor, get one */
1326 #ifdef HP_ALLOC_CHOICEACC_ONCE
1327   if (!this->data_acsr)
1328 #endif
1329   {
1330       if (!(this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1331                                 this->descriptor->may_change )))
1332           return SANE_STATUS_NO_MEM;
1333   }
1334 
1335   sanei_hp_accessor_setint(this->data_acsr, data, val);
1336 
1337   _set_stringlist(this, data,
1338        sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1339                   0, 0, info));
1340   _set_size(this, data,
1341        sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1342   return SANE_STATUS_GOOD;
1343 }
1344 
1345 static SANE_Status
_probe_mirror_vert(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1346 _probe_mirror_vert (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1347                     HpData data)
1348 {
1349   int		minval = HP_MIRROR_VERT_OFF,
1350                 maxval = HP_MIRROR_VERT_ON,
1351                 val = HP_MIRROR_VERT_OFF;
1352   int           sec_dir;
1353   HpChoice	choices;
1354   const HpDeviceInfo *info;
1355 
1356   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
1357 
1358   /* Look if the device supports the (?) inquire secondary scan-direction */
1359   if ( sanei_hp_scl_inquire(scsi, SCL_SECONDARY_SCANDIR, &sec_dir, 0, 0)
1360          == SANE_STATUS_GOOD )
1361     maxval = HP_MIRROR_VERT_CONDITIONAL;
1362 
1363   choices = _make_choice_list(this->descriptor->choices, minval, maxval);
1364   if (choices && !choices->name) /* FIXME: hack */
1365       return SANE_STATUS_NO_MEM;
1366   if (!choices)
1367       return SANE_STATUS_UNSUPPORTED;
1368 
1369   /* If we don't have an accessor, get one */
1370 #ifdef HP_ALLOC_CHOICEACC_ONCE
1371   if (!this->data_acsr)
1372 #endif
1373   {
1374       if (!(this->data_acsr = sanei_hp_accessor_choice_new(data, choices,
1375                                 this->descriptor->may_change )))
1376           return SANE_STATUS_NO_MEM;
1377   }
1378 
1379   sanei_hp_accessor_setint(this->data_acsr, data, val);
1380 
1381   _set_stringlist(this, data,
1382        sanei_hp_accessor_choice_strlist((HpAccessorChoice)this->data_acsr,
1383                   0, 0, info));
1384   _set_size(this, data,
1385        sanei_hp_accessor_choice_maxsize((HpAccessorChoice)this->data_acsr));
1386   return SANE_STATUS_GOOD;
1387 }
1388 
1389 
_probe_front_button(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1390 static SANE_Status _probe_front_button(_HpOption this, HpScsi scsi,
1391                                       HpOptSet __sane_unused__ optset, HpData data)
1392 {
1393   int val = 0;
1394 
1395   if ( sanei_hp_scl_inquire(scsi, SCL_FRONT_BUTTON, &val, 0, 0)
1396         != SANE_STATUS_GOOD )
1397     return SANE_STATUS_UNSUPPORTED;
1398 
1399   _set_size(this, data, sizeof(SANE_Bool));
1400 
1401   /* If we don't have an accessor, get one */
1402   if (!this->data_acsr)
1403   {
1404       if ( !(this->data_acsr = sanei_hp_accessor_bool_new(data)) )
1405           return SANE_STATUS_NO_MEM;
1406   }
1407 
1408   sanei_hp_accessor_setint(this->data_acsr, data, 0);
1409 
1410   return SANE_STATUS_GOOD;
1411 }
1412 
1413 
1414 static SANE_Status
_probe_geometry(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1415 _probe_geometry (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1416 {
1417   HpScl		scl	= this->descriptor->scl_command;
1418   hp_bool_t	is_tl	= 0;
1419   hp_bool_t     active_xpa = sanei_hp_is_active_xpa ( scsi );
1420   int		minval, maxval;
1421   SANE_Fixed	fval;
1422 
1423   /* There might have been a reason for inquiring the extent */
1424   /* by using the maxval of the position. But this does not work */
1425   /* when scanning from ADF. The Y-pos is then inquired with -1..0. */
1426   /* First try to get the values with SCL_X/Y_POS. If this is not ok, */
1427   /* use SCL_X/Y_EXTENT */
1428   if (scl == SCL_X_EXTENT)
1429   {
1430     scl = SCL_X_POS;
1431   }
1432   else if (scl == SCL_Y_EXTENT)
1433   {
1434     scl = SCL_Y_POS;
1435   }
1436   else
1437       is_tl = 1;
1438 
1439   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, 0, &minval, &maxval) );
1440   if (minval >= maxval)
1441       return SANE_STATUS_INVAL;
1442 
1443   /* Bad maximum value for extent-inquiry ? */
1444   if ( (!is_tl) && (maxval <= 0) )
1445   {
1446     scl = (scl == SCL_X_POS) ? SCL_X_EXTENT : SCL_Y_EXTENT;
1447     RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, 0, &minval, &maxval) );
1448     if (minval >= maxval)
1449         return SANE_STATUS_INVAL;
1450   }
1451 
1452   if ((scl == SCL_X_EXTENT) || (scl == SCL_Y_EXTENT))
1453   {
1454      /* Max. extent is larger than max. position. Reduce extent */
1455      maxval--;
1456      DBG(3, "probe_geometry: Inquiry by extent. Reduced maxval to %lu\n",
1457          (unsigned long)maxval);
1458   }
1459 
1460   /* Need a new accessor ? */
1461   if (!this->data_acsr)
1462   {
1463     if (!(this->data_acsr = sanei_hp_accessor_fixed_new(data)))
1464         return SANE_STATUS_NO_MEM;
1465   }
1466 
1467   /* The active xpa is only 5x5 inches */
1468   if (   (!is_tl) && active_xpa
1469       && (sanei_hp_optset_scan_type (optset, data) == SCL_XPA_SCAN) )
1470   {
1471     DBG(3,"Set maxval to 1500 because of active XPA\n");
1472     maxval = 1500;
1473   }
1474 
1475   fval = is_tl ? SANE_FIX(0.0) : maxval * SANE_FIX(MM_PER_DEVPIX);
1476   RETURN_IF_FAIL( sanei_hp_accessor_set(this->data_acsr, data, &fval) );
1477 
1478   _set_size(this, data, sizeof(SANE_Fixed));
1479   return _set_range(this, data,
1480 		    minval * SANE_FIX(MM_PER_DEVPIX),
1481 		    1,
1482 		    maxval * SANE_FIX(MM_PER_DEVPIX));
1483 }
1484 
1485 static SANE_Status
_probe_download_type(HpScl scl,HpScsi scsi)1486 _probe_download_type (HpScl scl, HpScsi scsi)
1487 {
1488   SANE_Status status;
1489 
1490   sanei_hp_scl_clearErrors (scsi);
1491   sanei_hp_scl_set (scsi, SCL_DOWNLOAD_TYPE, SCL_INQ_ID(scl));
1492 
1493   status = sanei_hp_scl_errcheck (scsi);
1494 
1495   DBG(3, "probe_download_type: Download type %d %ssupported\n", SCL_INQ_ID(scl),
1496       (status == SANE_STATUS_GOOD) ? "" : "not ");
1497 
1498   return status;
1499 }
1500 
1501 static SANE_Status
_probe_custom_gamma(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1502 _probe_custom_gamma (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1503                      HpData data)
1504 {
1505  HpScl       scl = this->descriptor->scl_command;
1506  HpScl       scl_tonemap = SCL_8x8TONE_MAP;
1507  SANE_Status status;
1508  hp_bool_t   simulate;
1509  int         val = 0, minval, maxval;
1510  int         id = SCL_INQ_ID(scl_tonemap);
1511 
1512   /* Check if download type supported */
1513   status = sanei_hp_device_support_get ( sanei_hp_scsi_devicename  (scsi),
1514                 SCL_DOWNLOAD_TYPE, &minval, &maxval);
1515 
1516   simulate = (status != SANE_STATUS_GOOD) || (id < minval) || (id > maxval);
1517 
1518   if (simulate)
1519   {
1520     DBG(3, "probe_custom_gamma: Download type 2 not supported. Simulate\n");
1521   }
1522   else
1523   {
1524     RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &val, 0, 0) );
1525   }
1526 
1527   /* If we don't have an accessor, get one */
1528   if (!this->data_acsr)
1529   {
1530       if (!(this->data_acsr = sanei_hp_accessor_bool_new(data)))
1531           return SANE_STATUS_NO_MEM;
1532   }
1533 
1534   sanei_hp_accessor_setint(this->data_acsr, data, val);
1535   _set_size(this, data, sizeof(SANE_Bool));
1536   return SANE_STATUS_GOOD;
1537 }
1538 
1539 static SANE_Status
_probe_vector(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1540 _probe_vector (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1541 {
1542   static struct vector_type_s {
1543       HpScl	scl;
1544       unsigned	length, depth;
1545       HpAccessor (*creator)(HpData data, unsigned length, unsigned depth);
1546   }	types[] = {
1547       { SCL_8x8TONE_MAP,    256,      8, sanei_hp_accessor_gamma_vector_new },
1548 #ifdef ENABLE_7x12_TONEMAPS
1549       { SCL_BW7x12TONE_MAP, 129,     12, sanei_hp_accessor_gamma_vector_new },
1550       { SCL_7x12TONE_MAP,   3 * 129, 12, sanei_hp_accessor_gamma_vector_new },
1551 #endif
1552 #ifdef ENABLE_16x16_DITHERS
1553       { SCL_BW16x16DITHER,  256,      8, sanei_hp_accessor_vector_new },
1554 #endif
1555       { SCL_BW8x8DITHER,    64,       8, sanei_hp_accessor_vector_new },
1556 
1557       { SCL_8x9MATRIX_COEFF,  9,      8, sanei_hp_accessor_matrix_vector_new },
1558 #ifdef ENABLE_10BIT_MATRIXES
1559       { SCL_10x9MATRIX_COEFF, 9,     10, sanei_hp_accessor_matrix_vector_new },
1560       { SCL_10x3MATRIX_COEFF, 3,     10, sanei_hp_accessor_matrix_vector_new },
1561 #endif
1562       { 0, 0, 0, 0 }
1563   };
1564   static struct subvector_type_s {
1565       HpOptionDescriptor	desc;
1566       unsigned			nchan, chan;
1567       HpOptionDescriptor	super;
1568   }	subvec_types[] = {
1569 #ifdef ENABLE_7x12_TONEMAPS
1570       { GAMMA_VECTOR_R, 3, 0, RGB_TONEMAP },
1571       { GAMMA_VECTOR_G, 3, 1, RGB_TONEMAP },
1572       { GAMMA_VECTOR_B, 3, 2, RGB_TONEMAP },
1573 #endif
1574       { 0, 0, 0, 0 },
1575   };
1576 
1577   HpScl			scl	= this->descriptor->scl_command;
1578   HpAccessorVector	vec;
1579 
1580   if (scl)
1581     {
1582       struct vector_type_s *type;
1583       for (type = types; type->scl; type++)
1584 	  if (type->scl == scl)
1585 	      break;
1586       assert(type->scl);
1587 
1588       RETURN_IF_FAIL ( _probe_download_type (scl, scsi) );
1589       /* If we don't have an accessor, get one */
1590 #ifdef HP_ALLOC_CHOICEACC_ONCE
1591       if (!this->data_acsr)
1592 #endif
1593       {
1594           this->data_acsr = (*type->creator)(data, type->length, type->depth);
1595       }
1596     }
1597   else
1598     {
1599       struct subvector_type_s *type;
1600       HpOption	super;
1601 
1602       for (type = subvec_types; type->desc; type++)
1603 	  if (type->desc == this->descriptor)
1604 	      break;
1605       assert(type->desc);
1606 
1607       super = hp_optset_get(optset, type->super);
1608       assert(super);
1609 
1610       /* If we don't have an accessor, get one */
1611 #ifdef HP_ALLOC_CHOICEACC_ONCE
1612       if (!this->data_acsr)
1613 #endif
1614       {
1615           this->data_acsr = sanei_hp_accessor_subvector_new(
1616             (HpAccessorVector) super->data_acsr, type->nchan, type->chan);
1617       }
1618     }
1619 
1620   if (!this->data_acsr)
1621       return SANE_STATUS_NO_MEM;
1622 
1623   vec = (HpAccessorVector)this->data_acsr;
1624 
1625   _set_size(this, data, sizeof(SANE_Fixed)
1626             * sanei_hp_accessor_vector_length(vec));
1627 
1628   return _set_range(this, data,
1629 		    sanei_hp_accessor_vector_minval(vec),
1630 		    1,
1631 		    sanei_hp_accessor_vector_maxval(vec));
1632 }
1633 
1634 static SANE_Status
_probe_gamma_vector(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1635 _probe_gamma_vector (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1636 {
1637   SANE_Fixed *	buf;
1638   int		i;
1639   size_t	size, length;
1640 
1641   RETURN_IF_FAIL( _probe_vector(this, scsi, optset, data) );
1642 
1643   /* Initialize to linear map */
1644   size = hp_option_saneoption(this, data)->size;
1645   if (!(buf = alloca(size)))
1646       return SANE_STATUS_NO_MEM;
1647   length = size / sizeof(SANE_Fixed);
1648   for (i = 0; i < (int)length; i++)
1649       buf[i] = (SANE_FIX(HP_VECTOR_SCALE* 1.0) * i + (length-1) / 2) / length;
1650   return sanei_hp_accessor_set(this->data_acsr, data, buf);
1651 }
1652 
1653 
1654 static SANE_Status
_probe_horiz_dither(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1655 _probe_horiz_dither (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1656 {
1657   int		dim	= 8;
1658   size_t	size;
1659   int		i, j;
1660   SANE_Fixed *	buf;
1661 
1662   if (this->descriptor->scl_command == SCL_BW16x16DITHER)
1663       dim = 16;
1664 
1665   RETURN_IF_FAIL( _probe_vector(this, scsi, optset, data) );
1666 
1667   /* Select vertical dither pattern, and upload it */
1668   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_BW_DITHER, HP_DITHER_VERTICAL) );
1669   RETURN_IF_FAIL( hp_option_upload(this, scsi, optset, data) );
1670 
1671   /* Flip it to get a horizontal dither pattern */
1672   size = hp_option_saneoption(this, data)->size;
1673   assert(size == dim * dim * sizeof(SANE_Fixed));
1674   if (!(buf = alloca(size)))
1675       return SANE_STATUS_NO_MEM;
1676 
1677 #define SWAP_FIXED(x,y) do { SANE_Fixed tmp = x; x = y; y = tmp; } while(0)
1678   RETURN_IF_FAIL( sanei_hp_accessor_get(this->data_acsr, data, buf) );
1679   for (i = 0; i < dim; i++) for (j = i + 1; j < dim; j++)
1680       SWAP_FIXED(buf[i * dim + j], buf[j * dim + i]);
1681   return sanei_hp_accessor_set(this->data_acsr, data, buf);
1682 }
1683 
1684 static SANE_Status
_probe_matrix(_HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1685 _probe_matrix (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1686 {
1687   RETURN_IF_FAIL( _probe_vector(this, scsi, optset, data) );
1688 
1689   /* Initial value: select RGB matrix, and upload it. */
1690   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_MATRIX, HP_MATRIX_RGB) );
1691   return hp_option_upload(this, scsi, optset, data);
1692 }
1693 
1694 static SANE_Status
_probe_num_options(_HpOption this,HpScsi __sane_unused__ scsi,HpOptSet __sane_unused__ optset,HpData data)1695 _probe_num_options (_HpOption this, HpScsi __sane_unused__ scsi,
1696                     HpOptSet __sane_unused__ optset, HpData data)
1697 {
1698   /* If we don't have an accessor, get one */
1699   if (!this->data_acsr)
1700   {
1701       if (!(this->data_acsr = sanei_hp_accessor_int_new(data)))
1702           return SANE_STATUS_NO_MEM;
1703   }
1704   _set_size(this, data, sizeof(SANE_Int));
1705   return SANE_STATUS_GOOD;
1706 }
1707 
1708 static SANE_Status
_probe_devpix(_HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)1709 _probe_devpix (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
1710                HpData data)
1711 {
1712   HpScl	scl	= this->descriptor->scl_command;
1713   int	resolution;
1714 
1715   if (FAILED( sanei_hp_scl_inquire(scsi, scl, &resolution, 0, 0) ))
1716     {
1717       DBG(1, "probe_devpix: inquiry failed, assume 300 ppi\n");
1718       resolution = 300;
1719     }
1720 
1721   if (!this->data_acsr)
1722   {
1723     if (!(this->data_acsr = sanei_hp_accessor_int_new(data)))
1724         return SANE_STATUS_NO_MEM;
1725   }
1726 
1727   sanei_hp_accessor_setint(this->data_acsr, data, resolution);
1728   _set_size(this, data, sizeof(SANE_Int));
1729   return SANE_STATUS_GOOD;
1730 }
1731 
1732 
1733 /*
1734  * Simulate functions
1735  */
1736 static SANE_Status
_simulate_brightness(HpOption this,HpData data,HpScsi scsi)1737 _simulate_brightness (HpOption this, HpData data, HpScsi scsi)
1738 {
1739  int k, val, newval;
1740  unsigned char *brightness_map;
1741  HpDeviceInfo *info;
1742 
1743  info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) );
1744  assert (info);
1745 
1746  val = sanei_hp_accessor_getint(this->data_acsr, data);
1747 
1748  DBG(3, "simulate_brightness: value = %d\n", val);
1749 
1750  /* Update brightness map in info structure */
1751  brightness_map = &(info->simulate.brightness_map[0]);
1752  val *= 2;  /* A value of 127 should give a totally white image */
1753  for (k = 0; k < 256; k++)
1754  {
1755    newval = k + val;
1756    if (newval < 0) newval = 0; else if (newval > 255) newval = 255;
1757    brightness_map[k] = (unsigned char)newval;
1758  }
1759  return SANE_STATUS_GOOD;
1760 }
1761 
1762 static int
hp_contrast(int x,int g)1763 hp_contrast (int x, int g)
1764 
1765 {int y = 0;
1766 
1767  if (g < -127) g = -127; else if (g > 127) g = 127;
1768  if (x < 0) x = 0; else if (x > 255) x = 255;
1769 
1770  if (g == 0)
1771  {
1772    y = x;
1773  }
1774  else if (g < 0)
1775  {
1776    g = -g;
1777    y = x * (255 - 2*g);
1778    y = y/255 + g;
1779  }
1780  else
1781  {
1782    if (x <= g) y = 0;
1783    else if (x >= 255-g) y = 255;
1784    else
1785    {
1786      y = (x - g)*255;
1787      y /= (255 - 2*g);
1788    }
1789  }
1790 
1791  return y;
1792 }
1793 
1794 static SANE_Status
_simulate_contrast(HpOption this,HpData data,HpScsi scsi)1795 _simulate_contrast (HpOption this, HpData data, HpScsi scsi)
1796 {
1797  int k, val, newval;
1798  unsigned char *contrast_map;
1799  HpDeviceInfo *info;
1800 
1801  info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) );
1802  assert (info);
1803 
1804  val = sanei_hp_accessor_getint(this->data_acsr, data);
1805 
1806  DBG(3, "simulate_contrast: value = %d\n", val);
1807 
1808  /* Update contrast map in info structure */
1809  contrast_map = &(info->simulate.contrast_map[0]);
1810 
1811  for (k = 0; k < 256; k++)
1812  {
1813    newval = hp_contrast (k, val);
1814    if (newval < 0) newval = 0; else if (newval > 255) newval = 255;
1815    contrast_map[k] = (unsigned char)newval;
1816  }
1817  return SANE_STATUS_GOOD;
1818 }
1819 
1820 /*
1821  * Option download functions
1822  */
1823 static SANE_Status
_program_generic(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1824 _program_generic (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1825 {
1826   return hp_option_download(this, data, optset, scsi);
1827 }
1828 
1829 static SANE_Status
_program_geometry(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1830 _program_geometry (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1831 {
1832 /* #define HP_LIMIT_ADF_WINDOW */
1833 #ifndef HP_LIMIT_ADF_WINDOW
1834 
1835  return hp_option_download(this, data, optset, scsi);
1836 
1837 #else
1838 
1839  HpScl scl = this->descriptor->scl_command;
1840  int value;
1841  SANE_Status Status;
1842 
1843  if (sanei_hp_optset_scan_type (optset, data) != SCL_ADF_SCAN)
1844    return hp_option_download(this, data, optset, scsi);
1845 
1846  /* ADF may crash when scanning only a window ? */
1847  if ( (scl == SCL_X_POS) || (scl == SCL_Y_POS) )
1848  {
1849    value = 0;
1850    DBG(3,"program_geometry: set %c-pos to %d\n",
1851        (scl == SCL_X_POS) ? 'x' : 'y', value);
1852  }
1853  else if ( scl == SCL_X_EXTENT )
1854  {
1855    value = 2550;
1856    DBG(3,"program_geometry: set x-extent to %d\n", value);
1857  }
1858  else
1859  {
1860    value = 4200;
1861    DBG(3,"program_geometry: set y-extent to %d\n", value);
1862  }
1863 
1864  Status = sanei_hp_scl_set(scsi, scl, value);
1865  return Status;
1866 
1867 #endif
1868 }
1869 
1870 static SANE_Status
_program_data_width(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1871 _program_data_width (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1872 {
1873   HpScl scl = this->descriptor->scl_command;
1874   int value = sanei_hp_accessor_getint(this->data_acsr, data);
1875   SANE_Status status;
1876 
1877   if ( sanei_hp_optset_scanmode (optset, data) == HP_SCANMODE_COLOR )
1878   {
1879     value *= 3;
1880     if (value < 24)
1881     {
1882       DBG(3,"program_data_width: map datawith from %d to 24\n", (int)value);
1883       value = 24;
1884     }
1885   }
1886   status = sanei_hp_scl_set(scsi, scl, value);
1887   return status;
1888 }
1889 
1890 static SANE_Status
_program_generic_simulate(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1891 _program_generic_simulate (HpOption this, HpScsi scsi, HpOptSet optset,
1892                            HpData data)
1893 {
1894  HpScl scl = this->descriptor->scl_command;
1895  const char *devname = sanei_hp_scsi_devicename (scsi);
1896  int simulate;
1897 
1898   /* Check if command is supported */
1899   simulate = (   sanei_hp_device_support_get (devname, scl, 0, 0)
1900               != SANE_STATUS_GOOD );
1901 
1902   /* Save simulate flag */
1903   sanei_hp_device_simulate_set (devname, scl, simulate);
1904 
1905   if ( !simulate )  /* Let the device do it */
1906     return hp_option_download(this, data, optset, scsi);
1907 
1908   DBG(3, "program_generic: %lu not programmed. Will be simulated\n",
1909       (unsigned long)(SCL_INQ_ID(scl)));
1910 
1911   switch (scl)
1912   {
1913     case SCL_BRIGHTNESS:
1914       _simulate_brightness (this, data, scsi);
1915       break;
1916 
1917     case SCL_CONTRAST:
1918       _simulate_contrast (this, data,scsi);
1919       break;
1920 
1921     default:
1922       DBG(1, "program_generic: No simulation for %lu\n",
1923           (unsigned long)(SCL_INQ_ID(scl)));
1924       break;
1925   }
1926   return SANE_STATUS_GOOD;
1927 }
1928 
1929 static SANE_Status
_simulate_custom_gamma(HpOption gvector,HpScsi scsi,HpData data)1930 _simulate_custom_gamma (HpOption gvector, HpScsi scsi, HpData data)
1931 {
1932  size_t size = sanei_hp_accessor_size(gvector->data_acsr);
1933  const unsigned char *vector_data =
1934      (const unsigned char *)sanei_hp_accessor_data(gvector->data_acsr, data);
1935  HpDeviceInfo *info;
1936  int k, newval;
1937 
1938   DBG(3,"program_custom_gamma_simulate: save gamma map\n");
1939   if (size != 256)
1940   {
1941     DBG(1,"program_custom_gamma_simulate: size of vector is %d.\
1942  Should be 256.\n", (int)size);
1943     return SANE_STATUS_INVAL;
1944   }
1945 
1946   RETURN_IF_FAIL (sanei_hp_scl_set(scsi, SCL_TONE_MAP, 0));
1947 
1948   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) );
1949   info->simulate.gamma_simulate = 1;
1950 
1951   for (k = 0; k < 256; k++)
1952   {
1953     newval = 255 - vector_data[255-k];
1954     if (newval < 0) newval = 0; else if (newval > 255) newval = 255;
1955     info->simulate.gamma_map[k] = newval;
1956   }
1957 
1958   return SANE_STATUS_GOOD;
1959 }
1960 
1961 static SANE_Status
_program_tonemap(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)1962 _program_tonemap (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
1963 {
1964   hp_bool_t	use_custom_map	= hp_option_getint(this, data);
1965   HpOption	gvector = 0;
1966   int		type = 0;
1967 
1968   if (!use_custom_map)
1969       return sanei_hp_scl_set(scsi, SCL_TONE_MAP, 0);
1970 
1971 #ifdef ENABLE_7x12_TONEMAPS
1972   /* Try to find the appropriate 5P style tonemap. */
1973   if (sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_COLOR)
1974     {
1975       type = -1;
1976       gvector = hp_optset_get(optset, RGB_TONEMAP);
1977     }
1978   else
1979     {
1980       type = -2;
1981       gvector = hp_optset_get(optset, GAMMA_VECTOR_7x12);
1982     }
1983 #endif
1984 
1985   /* If that failed, just use 8x8 tonemap */
1986   if (!gvector)
1987   {
1988     HpScl       scl_tonemap = SCL_8x8TONE_MAP;
1989     hp_bool_t   simulate;
1990     int         id = SCL_INQ_ID(scl_tonemap);
1991     int         minval, maxval;
1992     SANE_Status status;
1993 
1994       type = -1;
1995       gvector = hp_optset_get(optset, GAMMA_VECTOR_8x8);
1996 
1997       /* Check if download type supported */
1998       status = sanei_hp_device_support_get ( sanei_hp_scsi_devicename  (scsi),
1999                     SCL_DOWNLOAD_TYPE, &minval, &maxval);
2000 
2001       simulate =    (status != SANE_STATUS_GOOD) || (id < minval)
2002                  || (id > maxval);
2003       if (simulate)
2004         return _simulate_custom_gamma (gvector, scsi, data);
2005   }
2006 
2007   assert(gvector != 0);
2008 
2009   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_TONE_MAP, type) );
2010   return hp_option_download(gvector, data, optset, scsi);
2011 }
2012 
2013 
2014 static SANE_Status
_program_dither(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2015 _program_dither (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2016 {
2017   enum hp_dither_type_e type	= hp_option_getint(this, data);
2018   HpOption	dither;
2019 
2020   switch (type) {
2021   case HP_DITHER_CUSTOM:
2022       dither = hp_optset_getByName(optset, SANE_NAME_HALFTONE_PATTERN);
2023       assert(dither != 0);
2024       break;
2025   case HP_DITHER_HORIZONTAL:
2026       dither = hp_optset_getByName(optset, HP_NAME_HORIZONTAL_DITHER);
2027       type = HP_DITHER_CUSTOM;
2028       assert(dither != 0);
2029       break;
2030   default:
2031       dither = 0;
2032       break;
2033   }
2034 
2035   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_BW_DITHER, type) );
2036   if (!dither)
2037       return SANE_STATUS_GOOD;
2038   return hp_option_download(dither, data, optset, scsi);
2039 }
2040 
2041 #ifdef FAKE_COLORSEP_MATRIXES
2042 static HpOption
_get_sepmatrix(HpOptSet optset,HpData data,enum hp_matrix_type_e type)2043 _get_sepmatrix (HpOptSet optset, HpData data, enum hp_matrix_type_e type)
2044 {
2045   SANE_Fixed	buf[9];
2046   HpOption	matrix	= hp_optset_get(optset, SEPMATRIX);
2047 
2048   memset(buf, 0, sizeof(buf));
2049   if (type == HP_MATRIX_RED)
2050       buf[1] = SANE_FIX(1.0);
2051   else if (type == HP_MATRIX_GREEN)
2052       buf[4] = SANE_FIX(1.0);
2053   else if (type == HP_MATRIX_BLUE)
2054       buf[7] = SANE_FIX(1.0);
2055   else
2056     {
2057       assert(!"Bad colorsep type");
2058       return 0;
2059     }
2060   sanei_hp_accessor_set(matrix->data_acsr, data, buf);
2061   return matrix;
2062 }
2063 #endif
2064 
2065 static SANE_Status
_program_matrix(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2066 _program_matrix (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2067 {
2068   enum hp_matrix_type_e type	= hp_option_getint(this, data);
2069   HpOption		matrix	= 0;
2070 
2071   if (type == HP_MATRIX_AUTO)
2072       return SANE_STATUS_GOOD;	/* Default to matrix set by mode */
2073 
2074   /* Download custom matrix, if we need it. */
2075   if (type == HP_MATRIX_CUSTOM)
2076     {
2077       matrix = hp_optset_getByName(optset, SANE_NAME_MATRIX_RGB);
2078       assert(matrix);
2079     }
2080 #ifdef FAKE_COLORSEP_MATRIXES
2081   else if (type == HP_MATRIX_RED
2082 	   || type == HP_MATRIX_BLUE
2083 	   || type == HP_MATRIX_GREEN)
2084     {
2085       matrix = _get_sepmatrix(optset, data, type);
2086       type = HP_MATRIX_CUSTOM;
2087       assert(matrix);
2088     }
2089 #else
2090   else if (type == HP_MATRIX_GREEN)
2091       type = HP_MATRIX_PASS;
2092 #endif
2093 
2094 
2095   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_MATRIX, type) );
2096   if (matrix)
2097       RETURN_IF_FAIL( hp_option_download(matrix, data, optset, scsi) );
2098 
2099   return SANE_STATUS_GOOD;
2100 }
2101 
2102 static SANE_Status
_program_resolution(HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)2103 _program_resolution (HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
2104                      HpData data)
2105 {
2106 
2107   int xresolution = hp_option_getint(this, data);
2108   int yresolution = xresolution;
2109   int xscale = 100, yscale = 100;
2110 
2111 #ifdef FIX_PHOTOSMART
2112   int minval, maxval, media;
2113   enum hp_device_compat_e compat;
2114 
2115   /* HP Photosmart scanner has problems with scanning slides/negatives */
2116   /* at arbitrary resolutions. The following tests did not work: */
2117   /* xres = yres = next lower multiple of 300, xscale = yscale > 100: */
2118   /* xres = yres = next higher multiple of 300, xscale = yscale < 100: */
2119   /* xres = next lower multiple of 300, xscale > 100 */
2120   /* xres = next higher multiple of 300, xscale < 100 */
2121   /* yres = next lower multiple of 300, yscale > 100 */
2122   /* yres = next higher multiple of 300, yscale < 100 */
2123   /* The image extent was ok, but the content was stretched in y-direction */
2124 
2125   if (xresolution > 300)
2126   {
2127     if (   (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD)
2128         && (compat & HP_COMPAT_PS)
2129         && (sanei_hp_scl_inquire(scsi, SCL_MEDIA, &media, &minval, &maxval)
2130               == SANE_STATUS_GOOD)
2131         && ((media == HP_MEDIA_SLIDE) || (media == HP_MEDIA_NEGATIVE)))
2132     {int next_resolution;
2133       next_resolution = (xresolution % 300) * 300;
2134       if (next_resolution < 300) next_resolution = 300;
2135       yresolution = next_resolution;
2136       yscale = (int)(100.0 * xresolution / yresolution);
2137     }
2138   }
2139 #endif
2140 
2141   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_X_SCALE, xscale) );
2142   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_Y_SCALE, yscale) );
2143   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_X_RESOLUTION, xresolution) );
2144   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_Y_RESOLUTION, yresolution) );
2145 
2146   return SANE_STATUS_GOOD;
2147 }
2148 
2149 static char *
get_home_dir(void)2150 get_home_dir (void)
2151 {
2152 #ifdef SANE_HOME_HP
2153 
2154  return getenv (SANE_HOME_HP);
2155 
2156 #else
2157 
2158   struct passwd *pw;
2159 
2160   pw = getpwuid (getuid ());  /* Look if we can find our home directory */
2161   return pw ? pw->pw_dir : NULL;
2162 
2163 #endif
2164 }
2165 
2166 static char *
get_calib_filename(HpScsi scsi)2167 get_calib_filename (HpScsi scsi)
2168 {
2169   char *homedir;
2170   char *calib_filename, *cf;
2171   const char *devname = sanei_hp_scsi_devicename (scsi);
2172   int name_len;
2173 
2174   homedir = get_home_dir (); /* Look if we can find our home directory */
2175   if (!homedir) return NULL;
2176 
2177   name_len = strlen (homedir) + 33;
2178   if ( devname ) name_len += strlen (devname);
2179   calib_filename = sanei_hp_allocz (name_len);
2180   if (!calib_filename) return NULL;
2181 
2182   strcpy (calib_filename, homedir);
2183   strcat (calib_filename, "/.sane/calib-hp");
2184   if ( devname && devname[0] ) /* Replace '/' by "+-" */
2185     {
2186       cf = calib_filename + strlen (calib_filename);
2187       *(cf++) = ':';
2188       while (*devname)
2189       {
2190         if (*devname == '/') *(cf++) = '+', *(cf++) = '-';
2191         else *(cf++) = *devname;
2192         devname++;
2193       }
2194     }
2195   strcat (calib_filename, ".dat");
2196 
2197   return calib_filename;
2198 }
2199 
2200 static SANE_Status
read_calib_file(int * nbytes,char ** calib_data,HpScsi scsi)2201 read_calib_file (int *nbytes, char **calib_data, HpScsi scsi)
2202 {
2203   SANE_Status status = SANE_STATUS_GOOD;
2204   char *calib_filename;
2205   FILE *calib_file;
2206   int err, c1, c2, c3, c4;
2207 
2208   *nbytes = 0;
2209   *calib_data = NULL;
2210 
2211   calib_filename = get_calib_filename ( scsi );
2212   if (!calib_filename) return SANE_STATUS_NO_MEM;
2213 
2214   calib_file = fopen (calib_filename, "rb");
2215   if ( calib_file )
2216     {
2217       err = ((c1 = getc (calib_file)) == EOF);
2218       err |= ((c2 = getc (calib_file)) == EOF);
2219       err |= ((c3 = getc (calib_file)) == EOF);
2220       err |= ((c4 = getc (calib_file)) == EOF);
2221       *nbytes = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
2222       if ( err )
2223         {
2224           DBG(1, "read_calib_file: Error reading calibration data size\n");
2225           status = SANE_STATUS_EOF;
2226         }
2227       else
2228         {
2229           *calib_data = sanei_hp_alloc ( *nbytes );
2230           if ( !*calib_data )
2231             {
2232               status = SANE_STATUS_NO_MEM;
2233             }
2234           else
2235             {
2236               err |= ((int)fread (*calib_data,1,*nbytes,calib_file) != *nbytes);
2237               if ( err )
2238                 {
2239                   DBG(1, "read_calib_file: Error reading calibration data\n");
2240                   sanei_hp_free ( *calib_data );
2241                   status = SANE_STATUS_EOF;
2242                 }
2243             }
2244         }
2245       fclose ( calib_file );
2246     }
2247   else
2248     {
2249       DBG(1, "read_calib_file: Error opening calibration file %s\
2250  for reading\n", calib_filename);
2251       status = SANE_STATUS_EOF;
2252     }
2253 
2254   sanei_hp_free (calib_filename);
2255 
2256   return ( status );
2257 }
2258 
2259 static SANE_Status
write_calib_file(int nbytes,char * data,HpScsi scsi)2260 write_calib_file (int nbytes, char *data, HpScsi scsi)
2261 {
2262   SANE_Status status = SANE_STATUS_GOOD;
2263   char *calib_filename;
2264   int err;
2265   FILE *calib_file;
2266 
2267   calib_filename = get_calib_filename ( scsi );
2268   if (!calib_filename) return SANE_STATUS_NO_MEM;
2269 
2270   calib_file = fopen (calib_filename, "wb");
2271   if ( calib_file )
2272     {
2273       err = (putc ((nbytes >> 24) & 0xff, calib_file) == EOF);
2274       err |= (putc ((nbytes >> 16) & 0xff, calib_file) == EOF);
2275       err |= (putc ((nbytes >> 8) & 0xff, calib_file) == EOF);
2276       err |= (putc (nbytes & 0xff, calib_file) == EOF);
2277       err |= ((int)fwrite (data, 1, nbytes, calib_file) != nbytes);
2278       fclose (calib_file);
2279       if ( err )
2280         {
2281           DBG(1, "write_calib_file: Error writing calibration data\n");
2282           unlink (calib_filename);
2283           status = SANE_STATUS_EOF;
2284         }
2285     }
2286   else
2287     {
2288       DBG(1, "write_calib_file: Error opening calibration file %s\
2289  for writing\n", calib_filename);
2290       status = SANE_STATUS_EOF;
2291     }
2292 
2293   sanei_hp_free (calib_filename);
2294   return (status);
2295 }
2296 
2297 static SANE_Status
_program_media(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2298 _program_media (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2299 {
2300   int      req_media, minval, maxval, current_media;
2301   HpScl scl = this->descriptor->scl_command;
2302 
2303   req_media = sanei_hp_accessor_getint(this->data_acsr, data);
2304 
2305   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, scl, &current_media,
2306                                        &minval, &maxval) );
2307   if (current_media == req_media)
2308     return SANE_STATUS_GOOD;
2309 
2310   /* Unload scanner */
2311   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_UNLOAD, 0) );
2312 
2313   /* Select new media */
2314   RETURN_IF_FAIL( hp_option_download(this, data, optset, scsi));
2315 
2316   /* Update support list */
2317   sanei_hp_device_support_probe (scsi);
2318 
2319   if (req_media == HP_MEDIA_PRINT)
2320     hp_download_calib_file (scsi);
2321 
2322   return SANE_STATUS_GOOD;
2323 }
2324 
2325 static SANE_Status
_program_unload_after_scan(HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)2326 _program_unload_after_scan (HpOption this, HpScsi scsi,
2327                             HpOptSet __sane_unused__ optset, HpData data)
2328 { HpDeviceInfo *info;
2329 
2330   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
2331   assert (info);
2332   info->unload_after_scan = sanei_hp_accessor_getint(this->data_acsr, data);
2333 
2334   DBG(3,"program_unload_after_scan: flag = %lu\n",
2335       (unsigned long)info->unload_after_scan);
2336 
2337   return SANE_STATUS_GOOD;
2338 }
2339 
2340 static SANE_Status
_program_lamp_off(HpOption __sane_unused__ this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData __sane_unused__ data)2341 _program_lamp_off (HpOption __sane_unused__ this, HpScsi scsi,
2342                    HpOptSet __sane_unused__ optset, HpData __sane_unused__ data)
2343 {
2344   DBG(3,"program_lamp_off: shut off lamp\n");
2345 
2346   return sanei_hp_scl_set(scsi, SCL_LAMPTEST, 0);
2347 }
2348 
2349 static SANE_Status
_program_scan_type(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2350 _program_scan_type (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2351 
2352 { int      req_scan_type;
2353 
2354   req_scan_type = sanei_hp_accessor_getint(this->data_acsr, data);
2355 
2356   if ( req_scan_type == HP_SCANTYPE_XPA )
2357   {
2358    enum hp_scanmode_e scan_mode = sanei_hp_optset_scanmode(optset, data);
2359    static unsigned char xpa_matrix_coeff[] = {
2360 0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
2361 0x00,0x80
2362    };
2363    static unsigned char xpa_tone_map[] = {
2364 0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xfe,0x0f,
2365 0xe1,0x0f,0xd3,0x0f,0xc4,0x0f,0xb5,0x0f,0xa6,0x0f,0x97,0x0f,0x88,0x0f,0x79,0x0f,
2366 0x6a,0x0f,0x5b,0x0f,0x4b,0x0f,0x3c,0x0f,0x2c,0x0f,0x1d,0x0f,0x0d,0x0e,0xfe,0x0e,
2367 0xee,0x0e,0xde,0x0e,0xce,0x0e,0xbe,0x0e,0xae,0x0e,0x9e,0x0e,0x8e,0x0e,0x7d,0x0e,
2368 0x6d,0x0e,0x5c,0x0e,0x4c,0x0e,0x3b,0x0e,0x2a,0x0e,0x19,0x0e,0x08,0x0d,0xf7,0x0d,
2369 0xe6,0x0d,0xd5,0x0d,0xc4,0x0d,0xb2,0x0d,0xa1,0x0d,0x8f,0x0d,0x7d,0x0d,0x6b,0x0d,
2370 0x59,0x0d,0x47,0x0d,0x35,0x0d,0x22,0x0d,0x10,0x0c,0xfd,0x0c,0xeb,0x0c,0xd8,0x0c,
2371 0xc5,0x0c,0xb2,0x0c,0x9e,0x0c,0x8b,0x0c,0x77,0x0c,0x64,0x0c,0x50,0x0c,0x3c,0x0c,
2372 0x28,0x0c,0x14,0x0b,0xff,0x0b,0xeb,0x0b,0xd6,0x0b,0xc1,0x0b,0xac,0x0b,0x96,0x0b,
2373 0x81,0x0b,0x6b,0x0b,0x55,0x0b,0x3f,0x0b,0x29,0x0b,0x12,0x0a,0xfc,0x0a,0xe5,0x0a,
2374 0xce,0x0a,0xb6,0x0a,0x9e,0x0a,0x87,0x0a,0x6e,0x0a,0x56,0x0a,0x3d,0x0a,0x24,0x0a,
2375 0x0b,0x09,0xf1,0x09,0xd8,0x09,0xbd,0x09,0xa3,0x09,0x88,0x09,0x6d,0x09,0x51,0x09,
2376 0x35,0x09,0x19,0x08,0xfc,0x08,0xdf,0x08,0xc1,0x08,0xa3,0x08,0x84,0x08,0x65,0x08,
2377 0x45,0x08,0x24,0x08,0x03,0x07,0xe1,0x07,0xbe,0x07,0x9b,0x07,0x78,0x07,0x53,0x07,
2378 0x2d,0x07,0x07,0x06,0xdf,0x06,0xb7,0x06,0x8d,0x06,0x62,0x06,0x36,0x06,0x07,0x05,
2379 0xd8,0x05,0xa6,0x05,0x72,0x05,0x3c,0x04,0xfc,0x04,0x7c,0x03,0xfc,0x03,0x7c,0x02,
2380 0xfc,0x02,0x7c,0x01,0xfc,0x01,0x7c,0x00,0xfc,0x00,0x7c,0x00,0x00,0x0f,0xfe,0x0f,
2381 0xe1,0x0f,0xd3,0x0f,0xc4,0x0f,0xb5,0x0f,0xa6,0x0f,0x97,0x0f,0x88,0x0f,0x79,0x0f,
2382 0x6a,0x0f,0x5b,0x0f,0x4b,0x0f,0x3c,0x0f,0x2c,0x0f,0x1d,0x0f,0x0d,0x0e,0xfe,0x0e,
2383 0xee,0x0e,0xde,0x0e,0xce,0x0e,0xbe,0x0e,0xae,0x0e,0x9e,0x0e,0x8e,0x0e,0x7d,0x0e,
2384 0x6d,0x0e,0x5c,0x0e,0x4c,0x0e,0x3b,0x0e,0x2a,0x0e,0x19,0x0e,0x08,0x0d,0xf7,0x0d,
2385 0xe6,0x0d,0xd5,0x0d,0xc4,0x0d,0xb2,0x0d,0xa1,0x0d,0x8f,0x0d,0x7d,0x0d,0x6b,0x0d,
2386 0x59,0x0d,0x47,0x0d,0x35,0x0d,0x22,0x0d,0x10,0x0c,0xfd,0x0c,0xeb,0x0c,0xd8,0x0c,
2387 0xc5,0x0c,0xb2,0x0c,0x9e,0x0c,0x8b,0x0c,0x77,0x0c,0x64,0x0c,0x50,0x0c,0x3c,0x0c,
2388 0x28,0x0c,0x14,0x0b,0xff,0x0b,0xeb,0x0b,0xd6,0x0b,0xc1,0x0b,0xac,0x0b,0x96,0x0b,
2389 0x81,0x0b,0x6b,0x0b,0x55,0x0b,0x3f,0x0b,0x29,0x0b,0x12,0x0a,0xfc,0x0a,0xe5,0x0a,
2390 0xce,0x0a,0xb6,0x0a,0x9e,0x0a,0x87,0x0a,0x6e,0x0a,0x56,0x0a,0x3d,0x0a,0x24,0x0a,
2391 0x0b,0x09,0xf1,0x09,0xd8,0x09,0xbd,0x09,0xa3,0x09,0x88,0x09,0x6d,0x09,0x51,0x09,
2392 0x35,0x09,0x19,0x08,0xfc,0x08,0xdf,0x08,0xc1,0x08,0xa3,0x08,0x84,0x08,0x65,0x08,
2393 0x45,0x08,0x24,0x08,0x03,0x07,0xe1,0x07,0xbe,0x07,0x9b,0x07,0x78,0x07,0x53,0x07,
2394 0x2d,0x07,0x07,0x06,0xdf,0x06,0xb7,0x06,0x8d,0x06,0x62,0x06,0x36,0x06,0x07,0x05,
2395 0xd8,0x05,0xa6,0x05,0x72,0x05,0x3c,0x04,0xfc,0x04,0x7c,0x03,0xfc,0x03,0x7c,0x02,
2396 0xfc,0x02,0x7c,0x01,0xfc,0x01,0x7c,0x00,0xfc,0x00,0x7c,0x00,0x00,0x0f,0xfe,0x0f,
2397 0xe1,0x0f,0xd3,0x0f,0xc4,0x0f,0xb5,0x0f,0xa6,0x0f,0x97,0x0f,0x88,0x0f,0x79,0x0f,
2398 0x6a,0x0f,0x5b,0x0f,0x4b,0x0f,0x3c,0x0f,0x2c,0x0f,0x1d,0x0f,0x0d,0x0e,0xfe,0x0e,
2399 0xee,0x0e,0xde,0x0e,0xce,0x0e,0xbe,0x0e,0xae,0x0e,0x9e,0x0e,0x8e,0x0e,0x7d,0x0e,
2400 0x6d,0x0e,0x5c,0x0e,0x4c,0x0e,0x3b,0x0e,0x2a,0x0e,0x19,0x0e,0x08,0x0d,0xf7,0x0d,
2401 0xe6,0x0d,0xd5,0x0d,0xc4,0x0d,0xb2,0x0d,0xa1,0x0d,0x8f,0x0d,0x7d,0x0d,0x6b,0x0d,
2402 0x59,0x0d,0x47,0x0d,0x35,0x0d,0x22,0x0d,0x10,0x0c,0xfd,0x0c,0xeb,0x0c,0xd8,0x0c,
2403 0xc5,0x0c,0xb2,0x0c,0x9e,0x0c,0x8b,0x0c,0x77,0x0c,0x64,0x0c,0x50,0x0c,0x3c,0x0c,
2404 0x28,0x0c,0x14,0x0b,0xff,0x0b,0xeb,0x0b,0xd6,0x0b,0xc1,0x0b,0xac,0x0b,0x96,0x0b,
2405 0x81,0x0b,0x6b,0x0b,0x55,0x0b,0x3f,0x0b,0x29,0x0b,0x12,0x0a,0xfc,0x0a,0xe5,0x0a,
2406 0xce,0x0a,0xb6,0x0a,0x9e,0x0a,0x87,0x0a,0x6e,0x0a,0x56,0x0a,0x3d,0x0a,0x24,0x0a,
2407 0x0b,0x09,0xf1,0x09,0xd8,0x09,0xbd,0x09,0xa3,0x09,0x88,0x09,0x6d,0x09,0x51,0x09,
2408 0x35,0x09,0x19,0x08,0xfc,0x08,0xdf,0x08,0xc1,0x08,0xa3,0x08,0x84,0x08,0x65,0x08,
2409 0x45,0x08,0x24,0x08,0x03,0x07,0xe1,0x07,0xbe,0x07,0x9b,0x07,0x78,0x07,0x53,0x07,
2410 0x2d,0x07,0x07,0x06,0xdf,0x06,0xb7,0x06,0x8d,0x06,0x62,0x06,0x36,0x06,0x07,0x05,
2411 0xd8,0x05,0xa6,0x05,0x72,0x05,0x3c,0x04,0xfc,0x04,0x7c,0x03,0xfc,0x03,0x7c,0x02,
2412 0xfc,0x02,0x7c,0x01,0xfc,0x01,0x7c,0x00,0xfc,0x00,0x7c,0x00,0x00
2413      };
2414 
2415     sanei_hp_scl_set(scsi, SCL_RESERVED1, 0); /* don't know */
2416     sanei_hp_scl_set(scsi, SCL_10952, 0);     /* Calibration mode */
2417 
2418     if (   sanei_hp_is_active_xpa (scsi)
2419         && (   (scan_mode==HP_SCANMODE_COLOR)
2420             || (scan_mode==HP_SCANMODE_GRAYSCALE)) )
2421     {
2422       DBG (3,"program_scan_type: set tone map for active XPA\n");
2423       sanei_hp_scl_download (scsi, SCL_10x9MATRIX_COEFF, xpa_matrix_coeff,
2424                              sizeof (xpa_matrix_coeff));
2425       sanei_hp_scl_set(scsi, SCL_MATRIX, -1);     /* Set matrix coefficient */
2426 
2427       sanei_hp_scl_download (scsi, SCL_7x12TONE_MAP, xpa_tone_map,
2428                              sizeof (xpa_tone_map));
2429       sanei_hp_scl_set(scsi, SCL_TONE_MAP, -1); /* Select tone map */
2430     }
2431   }
2432 
2433   return SANE_STATUS_GOOD;
2434 }
2435 
2436 static SANE_Status
_program_change_doc(HpOption __sane_unused__ this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData __sane_unused__ data)2437 _program_change_doc (HpOption __sane_unused__ this, HpScsi scsi,
2438                      HpOptSet __sane_unused__ optset, HpData __sane_unused__ data)
2439 {
2440   int istat;
2441 
2442   DBG(2, "program_change_doc: inquire ADF ready\n");
2443 
2444   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_ADF_READY, &istat, 0, 0) );
2445   if ( istat != 1 )    /* ADF not ready */
2446   {
2447     DBG(2, "program_change_doc: ADF not ready\n");
2448     return SANE_STATUS_INVAL;
2449   }
2450 
2451   DBG(2, "program_change_doc: inquire paper in ADF\n");
2452 
2453   RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_ADF_BIN, &istat, 0, 0) );
2454   if ( istat == 0 )    /* Nothing in ADF BIN */
2455   {
2456     DBG(2, "program_change_doc: nothing in ADF BIN. Just Unload.\n");
2457     return sanei_hp_scl_set(scsi, SCL_UNLOAD, 0);
2458   }
2459 
2460   DBG(2, "program_change_doc: Clear errors and change document.\n");
2461 
2462   RETURN_IF_FAIL( sanei_hp_scl_clearErrors (scsi) );
2463 
2464   RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_CHANGE_DOC, 0) );
2465 
2466   return sanei_hp_scl_errcheck (scsi);
2467 }
2468 
2469 static SANE_Status
_program_unload(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2470 _program_unload (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2471 {
2472   hp_bool_t  adfscan = ( sanei_hp_optset_scan_type (optset, data)
2473                            == SCL_ADF_SCAN );
2474 
2475   /* If we have an ADF, try to see if it is ready to unload */
2476   if (adfscan)
2477   {int val;
2478 
2479    if ( sanei_hp_scl_inquire(scsi, SCL_ADF_RDY_UNLOAD, &val, 0, 0)
2480        == SANE_STATUS_GOOD )
2481    {
2482      DBG(3, "program_unload: ADF is%sready to unload\n", val ? " " : " not ");
2483    }
2484    else
2485    {
2486      DBG(3, "program_unload: Command 'Ready to unload' not supported\n");
2487    }
2488   }
2489   return hp_option_download(this, data, optset, scsi);
2490 }
2491 
2492 static SANE_Status
_program_calibrate(HpOption __sane_unused__ this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData __sane_unused__ data)2493 _program_calibrate (HpOption __sane_unused__ this, HpScsi scsi,
2494                     HpOptSet __sane_unused__ optset, HpData __sane_unused__ data)
2495 {
2496   struct passwd *pw;
2497   SANE_Status status = SANE_STATUS_GOOD;
2498   size_t calib_size;
2499   char *calib_buf;
2500 
2501   RETURN_IF_FAIL ( sanei_hp_scl_calibrate(scsi) );   /* Start calibration */
2502 
2503   pw = getpwuid (getuid ());  /* Look if we can find our home directory */
2504   if (!pw) return SANE_STATUS_GOOD;
2505 
2506   DBG(3, "_program_calibrate: Read calibration data\n");
2507 
2508   RETURN_IF_FAIL ( sanei_hp_scl_upload_binary (scsi, SCL_CALIB_MAP,
2509                                                &calib_size, &calib_buf) );
2510 
2511   DBG(3, "_program_calibrate: Got %lu bytes of calibration data\n",
2512       (unsigned long) calib_size);
2513 
2514   write_calib_file (calib_size, calib_buf, scsi);
2515 
2516   sanei_hp_free (calib_buf);
2517 
2518   return (status);
2519 }
2520 
2521 /* The exposure time of the HP Photosmart can be changed by overwriting
2522  * some headers of the calibration data. The scanner uses a slower stepping
2523  * speed for higher exposure times */
2524 static SANE_Status
_program_ps_exposure_time(HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)2525 _program_ps_exposure_time (HpOption this, HpScsi scsi,
2526                            HpOptSet __sane_unused__ optset, HpData data)
2527 {
2528     SANE_Status status = SANE_STATUS_GOOD;
2529     size_t calib_size = 0;
2530     char *calib_buf = NULL;
2531     int i;
2532     int option =  hp_option_getint(this, data);
2533     static char *exposure[] =
2534                       {"\x00\x64\x00\x64\x00\x64",  /* 100% */
2535                        "\x00\x7d\x00\x7d\x00\x7d",  /* 125% */
2536                        "\x00\x96\x00\x96\x00\x96",  /* 150% */
2537                        "\x00\xaf\x00\xaf\x00\xaf",  /* 175% */
2538                        "\x00\xc0\x00\xc0\x00\xc0",  /* 200% */
2539                        "\x00\xe1\x00\xe1\x00\xe1",  /* 225% */
2540                        "\x00\xfa\x00\xfa\x00\xfa",  /* 250% */
2541                        "\x01\x13\x01\x13\x01\x13",  /* 275% */
2542                        "\x01\x24\x01\x24\x01\x24",  /* 300% */
2543                        "\x00\x64\x00\xc0\x01\x24"}; /* Negatives */
2544     /* Negatives get some extra blue to penetrate the orange mask and less
2545        red to not saturate the red channel; R:G:B = 100:200:300 */
2546 
2547     /* We don't use the 100% case. It may cause mechanical problems */
2548     if ((option < 1) || (option > 9)) return 0;
2549     RETURN_IF_FAIL ( sanei_hp_scl_upload_binary (scsi, SCL_CALIB_MAP,
2550                &calib_size, &calib_buf) );
2551 
2552     DBG(3, "_program_ps_exposure_time: Got %lu bytes of calibration data\n",
2553            (unsigned long) calib_size);
2554 
2555     for (i = 0; i < 6; i++)
2556        calib_buf[24 + i] = exposure[option][i];
2557 
2558     status = sanei_hp_scl_download ( scsi, SCL_CALIB_MAP, calib_buf,
2559            (size_t)calib_size);
2560 
2561     /* see what the scanner did to our alterations */
2562     /*
2563      * RETURN_IF_FAIL ( sanei_hp_scl_upload_binary (scsi, SCL_CALIB_MAP,
2564      *           &calib_size, &calib_buf) );
2565      *
2566      * for (i = 0; i < 9; i++)
2567      *    DBG(1, ">%x ", (unsigned char) calib_buf[24 + i]);
2568      */
2569 
2570     sanei_hp_free (calib_buf);
2571 
2572     return (status);
2573 }
2574 
2575 static SANE_Status
_program_scanmode(HpOption this,HpScsi scsi,HpOptSet optset,HpData data)2576 _program_scanmode (HpOption this, HpScsi scsi, HpOptSet optset, HpData data)
2577 {
2578   enum hp_scanmode_e	new_mode  = hp_option_getint(this, data);
2579   int	invert	 = 0;
2580   int   fw_invert = 0;  /* Flag: does firmware do inversion ? */
2581   int   is_model_4c = 0;
2582   enum hp_device_compat_e compat;
2583   hp_bool_t  disable_xpa = ( sanei_hp_optset_scan_type (optset, data)
2584                                != SCL_XPA_SCAN );
2585 
2586   /* Seems that models 3c/4c/6100C invert image data at 10 bit by themself. */
2587   /* So we must not invert it by the invert command. */
2588   if (   (sanei_hp_device_probe (&compat,scsi) == SANE_STATUS_GOOD)
2589       && (compat & HP_COMPAT_4C) )
2590   {
2591     is_model_4c = 1;
2592     DBG(3, "program_scanmode: model 3c/4c/6100C recognized\n");
2593   }
2594 
2595   if (is_model_4c)
2596   {
2597     const HpDeviceInfo *info;
2598     int data_width;
2599     HpOption option;
2600     int is_preview = 0;
2601 
2602     /* Preview uses maximum 8 bit. So we don't need to check data width */
2603     option = hp_optset_getByName (optset, SANE_NAME_PREVIEW);
2604     if ( option )
2605       is_preview = hp_option_getint (option, data);
2606 
2607     info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
2608 
2609     if (   (!is_preview)
2610         && hp_optset_isEnabled (optset, data, SANE_NAME_BIT_DEPTH, info))
2611     {
2612       data_width = sanei_hp_optset_data_width (optset, data);
2613       if ((data_width == 10) || (data_width == 30))
2614       {
2615         fw_invert = 1;
2616         DBG(3, "program_scanmode: firmware is doing inversion\n");
2617       }
2618     }
2619   }
2620 
2621   /* Disabling XPA resets some settings in the scanner. */
2622   /* Scanmode is the first we program. So set XPA prior to scanmode */
2623   DBG(3, "program_scanmode: disable XPA = %d\n", (int)disable_xpa);
2624   sanei_hp_scl_set(scsi, SCL_XPA_DISABLE, disable_xpa);
2625 
2626   RETURN_IF_FAIL( hp_option_download(this, data, optset, scsi) );
2627 
2628   switch (new_mode) {
2629   case HP_SCANMODE_GRAYSCALE:
2630       /* Make sure that it is not b/w. Correct data width will be set later */
2631       RETURN_IF_FAIL( sanei_hp_scl_set(scsi, SCL_DATA_WIDTH, 8) );
2632       invert = 1;
2633       if (fw_invert) invert = 0;
2634       /* For active XPA we use a tone map. Dont invert */
2635       if ( (!disable_xpa) && sanei_hp_is_active_xpa (scsi) ) invert = 0;
2636       break;
2637   case HP_SCANMODE_COLOR:
2638       invert = 1;
2639       if (fw_invert) invert = 0;
2640       /* For active XPA we use a tone map. Dont invert */
2641       if ( (!disable_xpa) && sanei_hp_is_active_xpa (scsi) ) invert = 0;
2642       break;
2643   default:
2644       break;
2645   }
2646 
2647   return sanei_hp_scl_set(scsi, SCL_INVERSE_IMAGE, invert);
2648 }
2649 
2650 static SANE_Status
_program_mirror_horiz(HpOption this,HpScsi scsi,HpOptSet __sane_unused__ optset,HpData data)2651 _program_mirror_horiz (HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset,
2652                        HpData data)
2653 {
2654   int sec_dir, mirror = hp_option_getint(this, data);
2655 
2656   if ( mirror == HP_MIRROR_HORIZ_CONDITIONAL )
2657   {
2658      RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_SECONDARY_SCANDIR,
2659                        &sec_dir, 0, 0) );
2660      mirror = (sec_dir == 1);
2661   }
2662 
2663   return sanei_hp_scl_set(scsi, SCL_MIRROR_IMAGE, mirror);
2664 }
2665 
2666 /*
2667  * Option enable predicates
2668  */
2669 static hp_bool_t
_enable_choice(HpOption this,HpOptSet optset,HpData data,const HpDeviceInfo * info)2670 _enable_choice (HpOption this, HpOptSet optset, HpData data,
2671                 const HpDeviceInfo *info)
2672 {
2673   SANE_String_Const * strlist
2674       = sanei_hp_accessor_choice_strlist((HpAccessorChoice) this->data_acsr,
2675 				   optset, data, info);
2676 
2677   _set_stringlist(this, data, strlist);
2678 
2679   assert(strlist[0]);
2680   return strlist[0] != 0;
2681 }
2682 
2683 #ifdef ENABLE_7x12_TONEMAPS
2684 static hp_bool_t
_enable_rgb_maps(HpOption this,HpOptSet optset,HpData data,const HpDeviceInfo * info)2685 _enable_rgb_maps (HpOption this, HpOptSet optset, HpData data,
2686                   const HpDeviceInfo *info)
2687 {
2688   HpOption 	cgam	= hp_optset_get(optset, CUSTOM_GAMMA);
2689 
2690   return (cgam && hp_option_getint(cgam, data)
2691 	  && sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_COLOR);
2692 }
2693 #endif
2694 
2695 static hp_bool_t
_enable_mono_map(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2696 _enable_mono_map (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2697                   const HpDeviceInfo __sane_unused__ *info)
2698 {
2699   HpOption 	cgam	= hp_optset_get(optset, CUSTOM_GAMMA);
2700 
2701   return (cgam && hp_option_getint(cgam, data)
2702 	  && ( sanei_hp_optset_scanmode(optset, data) != HP_SCANMODE_COLOR
2703 	       || ! hp_optset_getByName(optset, SANE_NAME_GAMMA_VECTOR_R) ));
2704 }
2705 
2706 static hp_bool_t
_enable_rgb_matrix(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2707 _enable_rgb_matrix (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2708                     const HpDeviceInfo __sane_unused__ *info)
2709 {
2710   HpOption 	type = hp_optset_get(optset, MATRIX_TYPE);
2711 
2712   return type && hp_option_getint(type, data) == HP_MATRIX_CUSTOM;
2713 }
2714 
2715 static hp_bool_t
_enable_brightness(HpOption this,HpOptSet optset,HpData data,const HpDeviceInfo * info)2716 _enable_brightness (HpOption this, HpOptSet optset, HpData data,
2717                     const HpDeviceInfo *info)
2718 {
2719   HpOption 	cgam = hp_optset_get(optset, CUSTOM_GAMMA);
2720   HpScl         scl = this->descriptor->scl_command;
2721   int           simulate;
2722 
2723   simulate = (   sanei_hp_device_support_get ( info->devname, scl, 0, 0 )
2724               != SANE_STATUS_GOOD );
2725   /* If brightness is simulated, we only do it for gray/color */
2726   if ( simulate )
2727   {HpOption  mode = hp_optset_get(optset, SCAN_MODE);
2728    int       val = hp_option_getint (mode, data);
2729    int       disable;
2730 
2731     disable = (val != HP_SCANMODE_GRAYSCALE) && (val != HP_SCANMODE_COLOR);
2732     if (disable)
2733     {
2734        if ( cgam )   /* Disable custom gamma. */
2735        {
2736          val = 0;
2737          hp_option_set (cgam, data, &val, 0);
2738        }
2739        return 0;
2740     }
2741   }
2742 
2743   return !cgam || !hp_option_getint(cgam, data);
2744 }
2745 
2746 static hp_bool_t
_enable_autoback(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2747 _enable_autoback (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2748                   const HpDeviceInfo __sane_unused__ *info)
2749 {
2750   return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_LINEART;
2751 }
2752 
2753 static hp_bool_t
_enable_custom_gamma(HpOption this,HpOptSet optset,HpData data,const HpDeviceInfo * info)2754 _enable_custom_gamma (HpOption this, HpOptSet optset, HpData data,
2755                       const HpDeviceInfo *info)
2756 {
2757   HpScl     scl_tonemap = SCL_8x8TONE_MAP;
2758   int       id = SCL_INQ_ID(scl_tonemap);
2759   int       simulate, minval, maxval;
2760   SANE_Status status;
2761 
2762   /* Check if download type supported */
2763   status = sanei_hp_device_support_get ( info->devname,
2764                 SCL_DOWNLOAD_TYPE, &minval, &maxval);
2765 
2766   simulate = (status != SANE_STATUS_GOOD) || (id < minval) || (id > maxval);
2767 
2768   /* If custom gamma is simulated, we only do it for gray/color */
2769   if ( simulate )
2770   {HpOption  mode = hp_optset_get(optset, SCAN_MODE);
2771    int       val;
2772 
2773     if ( mode )
2774     {
2775       val = hp_option_getint (mode, data);
2776       if ((val != HP_SCANMODE_GRAYSCALE) && (val != HP_SCANMODE_COLOR))
2777       {
2778         val = 0;
2779         hp_option_set (this, data, &val, 0);
2780         return 0;
2781       }
2782     }
2783   }
2784 
2785   return 1;
2786 }
2787 
2788 static hp_bool_t
_enable_halftone(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2789 _enable_halftone (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2790                   const HpDeviceInfo __sane_unused__ *info)
2791 {
2792   return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_HALFTONE;
2793 }
2794 
2795 static hp_bool_t
_enable_halftonevec(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2796 _enable_halftonevec (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2797                      const HpDeviceInfo __sane_unused__ *info)
2798 {
2799   if (sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_HALFTONE)
2800     {
2801       HpOption 		dither	= hp_optset_get(optset, HALFTONE_PATTERN);
2802 
2803       return dither && hp_option_getint(dither, data) == HP_DITHER_CUSTOM;
2804     }
2805   return 0;
2806 }
2807 
2808 static hp_bool_t
_enable_data_width(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2809 _enable_data_width (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2810                    const HpDeviceInfo __sane_unused__ *info)
2811 {enum hp_scanmode_e mode;
2812 
2813  mode = sanei_hp_optset_scanmode (optset, data);
2814  return ( (mode == HP_SCANMODE_GRAYSCALE) || (mode == HP_SCANMODE_COLOR) );
2815 }
2816 
2817 static hp_bool_t
_enable_out8(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo * info)2818 _enable_out8 (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2819               const HpDeviceInfo *info)
2820 {
2821   if (hp_optset_isEnabled (optset, data, SANE_NAME_BIT_DEPTH, info))
2822   {
2823     int data_width = sanei_hp_optset_data_width (optset, data);
2824     return (((data_width > 8) && (data_width <= 16)) || (data_width > 24));
2825   }
2826   return 0;
2827 }
2828 
2829 static hp_bool_t
_enable_calibrate(HpOption __sane_unused__ this,HpOptSet optset,HpData data,const HpDeviceInfo __sane_unused__ * info)2830 _enable_calibrate (HpOption __sane_unused__ this, HpOptSet optset, HpData data,
2831                    const HpDeviceInfo __sane_unused__ *info)
2832 {
2833   HpOption 	media	= hp_optset_get(optset, MEDIA);
2834 
2835   /* If we don't have the media button, we should have calibrate */
2836   if ( !media ) return 1;
2837 
2838   return hp_option_getint(media, data) == HP_MEDIA_PRINT;
2839 }
2840 
2841 static SANE_Status
hp_download_calib_file(HpScsi scsi)2842 hp_download_calib_file (HpScsi scsi)
2843 {
2844   int nbytes;
2845   char *calib_data;
2846   SANE_Status status;
2847 
2848   RETURN_IF_FAIL ( read_calib_file ( &nbytes, &calib_data, scsi ) );
2849 
2850   DBG(3, "hp_download_calib_file: Got %d bytes calibration data\n", nbytes);
2851 
2852   status = sanei_hp_scl_download ( scsi, SCL_CALIB_MAP, calib_data,
2853                                    (size_t) nbytes);
2854   sanei_hp_free ( calib_data );
2855 
2856   DBG(3, "hp_download_calib_file: download %s\n", (status == SANE_STATUS_GOOD) ?
2857       "successful" : "failed");
2858 
2859   return status;
2860 }
2861 
2862 
2863 /*
2864  * The actual option descriptors.
2865  */
2866 
2867 #if (defined(__IBMC__) || defined(__IBMCPP__))
2868 #ifndef _AIX
2869   #define INT INT
2870 #endif
2871 #endif
2872 
2873 #define SCANNER_OPTION(name,type,unit)					\
2874    PASTE(SANE_NAME_,name),						\
2875    PASTE(SANE_TITLE_,name),						\
2876    PASTE(SANE_DESC_,name),						\
2877    PASTE(SANE_TYPE_,type),						\
2878    PASTE(SANE_UNIT_,unit),						\
2879    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT
2880 
2881 #define CONSTANT_OPTION(name,type,unit)					\
2882    PASTE(SANE_NAME_,name),						\
2883    PASTE(SANE_TITLE_,name),						\
2884    PASTE(SANE_DESC_,name),						\
2885    PASTE(SANE_TYPE_,type),						\
2886    PASTE(SANE_UNIT_,unit),						\
2887    SANE_CAP_SOFT_DETECT
2888 
2889 #define INTERNAL_OPTION(name,type,unit)					\
2890    PASTE(HP_NAME_,name), "", "",					\
2891    PASTE(SANE_TYPE_,type),						\
2892    PASTE(SANE_UNIT_,unit),						\
2893    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT
2894 
2895 #define OPTION_GROUP(name)   "", name, "", SANE_TYPE_GROUP, SANE_UNIT_NONE, 0
2896 
2897 #define ADVANCED_GROUP(name)						\
2898    "", name, "",  SANE_TYPE_GROUP, SANE_UNIT_NONE, SANE_CAP_ADVANCED
2899 
2900 
2901 #define REQUIRES(req)  req
2902 #define NO_REQUIRES    REQUIRES(0)
2903 
2904 static const struct hp_option_descriptor_s NUM_OPTIONS[1] = {{
2905     CONSTANT_OPTION(NUM_OPTIONS, INT, NONE),
2906     NO_REQUIRES,
2907     _probe_num_options,
2908     0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
2909 }};
2910 
2911 static const struct hp_option_descriptor_s SCAN_MODE_GROUP[1] = {{
2912     OPTION_GROUP(SANE_I18N("Scan Mode")),
2913     0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
2914 }};
2915 
2916 /* Preview stuff */
2917 static const struct hp_option_descriptor_s PREVIEW_MODE[1] = {{
2918     SCANNER_OPTION(PREVIEW, BOOL, NONE),
2919     NO_REQUIRES,
2920     _probe_bool,
2921     0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
2922 }};
2923 
2924 static const struct hp_choice_s _scanmode_choices[] = {
2925     { HP_SCANMODE_LINEART, SANE_VALUE_SCAN_MODE_LINEART, 0, 0, 0 },
2926     { HP_SCANMODE_HALFTONE, SANE_VALUE_SCAN_MODE_HALFTONE, 0, 0, 0 },
2927     { HP_SCANMODE_GRAYSCALE, SANE_VALUE_SCAN_MODE_GRAY, 0, 0, 0 },
2928     { HP_SCANMODE_COLOR, SANE_VALUE_SCAN_MODE_COLOR, 0, 0, 0 },
2929     { 0, 0, 0, 0, 0 }
2930 };
2931 static const struct hp_option_descriptor_s SCAN_MODE[1] = {{
2932     SCANNER_OPTION(SCAN_MODE, STRING, NONE),
2933     NO_REQUIRES,
2934     _probe_each_choice, _program_scanmode, 0,
2935     1, 1, 1, 0, 0, SCL_OUTPUT_DATA_TYPE, 0, 0, 0, _scanmode_choices
2936 }};
2937 static const struct hp_option_descriptor_s SCAN_RESOLUTION[1] = {{
2938     SCANNER_OPTION(SCAN_RESOLUTION, INT, DPI),
2939     NO_REQUIRES,
2940     _probe_resolution, _program_resolution, 0,
2941     0, 1, 0, 0, 1, SCL_X_RESOLUTION, 0, 0, 0, 0
2942 }};
2943 static const struct hp_option_descriptor_s DEVPIX_RESOLUTION[1] = {{
2944     INTERNAL_OPTION(DEVPIX_RESOLUTION, INT, DPI),
2945     NO_REQUIRES,
2946     _probe_devpix, 0, 0,
2947     0, 0, 0, 0, 1, SCL_DEVPIX_RESOLUTION, 0, 0, 0, 0
2948 }};
2949 
2950 static const struct hp_option_descriptor_s ENHANCEMENT_GROUP[1] = {{
2951     OPTION_GROUP(SANE_I18N("Enhancement")),
2952     0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
2953 }};
2954 static const struct hp_option_descriptor_s BRIGHTNESS[1] = {{
2955     SCANNER_OPTION(BRIGHTNESS, INT, NONE),
2956     NO_REQUIRES,
2957     _probe_int_brightness, _program_generic_simulate, _enable_brightness,
2958     0, 0, 0, 0, 0, SCL_BRIGHTNESS, -127, 127, 0, 0
2959 }};
2960 static const struct hp_option_descriptor_s CONTRAST[1] = {{
2961     SCANNER_OPTION(CONTRAST, INT, NONE),
2962     NO_REQUIRES,
2963     _probe_int_brightness, _program_generic_simulate, _enable_brightness,
2964     0, 0, 0, 0, 0, SCL_CONTRAST, -127, 127, 0, 0
2965 }};
2966 #ifdef SCL_SHARPENING
2967 static const struct hp_option_descriptor_s SHARPENING[1] = {{
2968     SCANNER_OPTION(SHARPENING, INT, NONE),
2969     NO_REQUIRES,
2970     _probe_int, _program_generic, 0,
2971     0, 0, 0, 0, 0, SCL_SHARPENING, -127, 127, 0, 0
2972 }};
2973 #endif
2974 static const struct hp_option_descriptor_s AUTO_THRESHOLD[1] = {{
2975     SCANNER_OPTION(AUTO_THRESHOLD, BOOL, NONE),
2976     NO_REQUIRES,
2977     _probe_bool, _program_generic, _enable_autoback,
2978     0, 0, 0, 0, 0, SCL_AUTO_BKGRND, 0, 0, 0, 0
2979 }};
2980 
2981 static const struct hp_option_descriptor_s ADVANCED_GROUP[1] = {{
2982     ADVANCED_GROUP(SANE_I18N("Advanced Options")),
2983     0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
2984 }};
2985 /* FIXME: make this a choice? (BW or RGB custom) */
2986 static const struct hp_option_descriptor_s CUSTOM_GAMMA[1] = {{
2987     SCANNER_OPTION(CUSTOM_GAMMA, BOOL, NONE),
2988     NO_REQUIRES,
2989     _probe_custom_gamma, _program_tonemap, _enable_custom_gamma,
2990     1, 0, 0, 0, 0, SCL_TONE_MAP, 0, 0, 0, 0
2991 }};
2992 static const struct hp_option_descriptor_s GAMMA_VECTOR_8x8[1] = {{
2993     SCANNER_OPTION(GAMMA_VECTOR, FIXED, NONE),
2994     NO_REQUIRES,
2995     _probe_gamma_vector, 0, _enable_mono_map,
2996     0, 0, 0, 0, 0, SCL_8x8TONE_MAP, 0, 0, 0, 0
2997 }};
2998 
2999 #ifdef ENABLE_7x12_TONEMAPS
3000 static const struct hp_option_descriptor_s GAMMA_VECTOR_7x12[1] = {{
3001     SCANNER_OPTION(GAMMA_VECTOR, FIXED, NONE),
3002     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_PS | HP_COMPAT_6200C
3003              |HP_COMPAT_5200C|HP_COMPAT_6300C),
3004     _probe_gamma_vector, 0, _enable_mono_map,
3005     0, 0, 0, 0, 0, SCL_BW7x12TONE_MAP, 0, 0, 0, 0
3006 }};
3007 
3008 static const struct hp_option_descriptor_s RGB_TONEMAP[1] = {{
3009     INTERNAL_OPTION(RGB_TONEMAP, FIXED, NONE),
3010     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_PS | HP_COMPAT_6200C
3011              |HP_COMPAT_5200C|HP_COMPAT_6300C),
3012     _probe_gamma_vector, 0, 0,
3013     0, 0, 0, 0, 0, SCL_7x12TONE_MAP, 0, 0, 0, 0
3014 }};
3015 static const struct hp_option_descriptor_s GAMMA_VECTOR_R[1] = {{
3016     SCANNER_OPTION(GAMMA_VECTOR_R, FIXED, NONE),
3017     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_PS | HP_COMPAT_6200C
3018              |HP_COMPAT_5200C|HP_COMPAT_6300C),
3019     _probe_gamma_vector, 0, _enable_rgb_maps,
3020     0,0,0,0,0,0,0,0,0,0
3021 }};
3022 static const struct hp_option_descriptor_s GAMMA_VECTOR_G[1] = {{
3023     SCANNER_OPTION(GAMMA_VECTOR_G, FIXED, NONE),
3024     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_PS | HP_COMPAT_6200C
3025              |HP_COMPAT_5200C|HP_COMPAT_6300C),
3026     _probe_gamma_vector, 0, _enable_rgb_maps,
3027     0,0,0,0,0,0,0,0,0,0
3028 }};
3029 static const struct hp_option_descriptor_s GAMMA_VECTOR_B[1] = {{
3030     SCANNER_OPTION(GAMMA_VECTOR_B, FIXED, NONE),
3031     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_PS | HP_COMPAT_6200C
3032              |HP_COMPAT_5200C|HP_COMPAT_6300C),
3033     _probe_gamma_vector, 0, _enable_rgb_maps,
3034     0,0,0,0,0,0,0,0,0,0
3035 }};
3036 #endif
3037 
3038 static const struct hp_choice_s _halftone_choices[] = {
3039     { HP_DITHER_COARSE,		SANE_I18N("Coarse"), 0, 0, 0 },
3040     { HP_DITHER_FINE,		SANE_I18N("Fine"), 0, 0, 0 },
3041     { HP_DITHER_BAYER,		SANE_I18N("Bayer"), 0, 0, 0 },
3042     { HP_DITHER_VERTICAL,	SANE_I18N("Vertical"), 0, 0, 0 },
3043     { HP_DITHER_HORIZONTAL,	SANE_I18N("Horizontal"), 0, 1, 0 },
3044     { HP_DITHER_CUSTOM, 	SANE_I18N("Custom"), 0, 0, 0 },
3045     { 0, 0, 0, 0, 0 }
3046 };
3047 static const struct hp_option_descriptor_s HALFTONE_PATTERN[1] = {{
3048     SCANNER_OPTION(HALFTONE_PATTERN, STRING, NONE),
3049     NO_REQUIRES,
3050     _probe_each_choice, _program_dither, _enable_halftone,
3051     1, 0, 0, 0, 0, SCL_BW_DITHER, 0, 0, 0, _halftone_choices
3052 }};
3053 /* FIXME: Halftone dimension? */
3054 
3055 #ifdef ENABLE_16X16_DITHERS
3056 static const struct hp_option_descriptor_s HALFTONE_PATTERN_16x16[1] = {{
3057     SCANNER_OPTION(HALFTONE_PATTERN, FIXED, NONE),
3058     REQUIRES(HP_COMPAT_5P | HP_COMPAT_4P | HP_COMPAT_4C | HP_COMPAT_5100C
3059               | HP_COMPAT_6200C | HP_COMPAT_5200C | HP_COMPAT_6300C),
3060     _probe_horiz_dither, 0, _enable_halftonevec,
3061     0, 0, 0, 0, 0, SCL_BW16x16DITHER
3062 }};
3063 static const struct hp_option_descriptor_s HORIZONTAL_DITHER_16x16[1] = {{
3064     INTERNAL_OPTION(HORIZONTAL_DITHER, FIXED, NONE),
3065     REQUIRES(HP_COMPAT_5P | HP_COMPAT_4P | HP_COMPAT_4C | HP_COMPAT_5100C
3066               | HP_COMPAT_6200C | HP_COMPAT_5200C | HP_COMPAT_6300C),
3067     _probe_horiz_dither, 0, 0,
3068     0, 0, 0, 0, 0, SCL_BW16x16DITHER
3069 }};
3070 #endif
3071 static const struct hp_option_descriptor_s HALFTONE_PATTERN_8x8[1] = {{
3072     SCANNER_OPTION(HALFTONE_PATTERN, FIXED, NONE),
3073     NO_REQUIRES,
3074     _probe_horiz_dither, 0, _enable_halftonevec,
3075     0, 0, 0, 0, 0, SCL_BW8x8DITHER, 0, 0, 0, 0
3076 }};
3077 static const struct hp_option_descriptor_s HORIZONTAL_DITHER_8x8[1] = {{
3078     INTERNAL_OPTION(HORIZONTAL_DITHER, FIXED, NONE),
3079     NO_REQUIRES,
3080     _probe_horiz_dither, 0, 0,
3081     0, 0, 0, 0, 0, SCL_BW8x8DITHER, 0, 0, 0, 0
3082 }};
3083 
3084 static const struct hp_choice_s _matrix_choices[] = {
3085     { HP_MATRIX_AUTO, SANE_I18N("Auto"), 0, 1, 0 },
3086     { HP_MATRIX_RGB, SANE_I18N("NTSC RGB"), _cenable_incolor, 0, 0 },
3087     { HP_MATRIX_XPA_RGB, SANE_I18N("XPA RGB"), _cenable_incolor, 0, 0 },
3088     { HP_MATRIX_PASS, SANE_I18N("Pass-through"), _cenable_incolor, 0, 0 },
3089     { HP_MATRIX_BW, SANE_I18N("NTSC Gray"), _cenable_notcolor, 0, 0 },
3090     { HP_MATRIX_XPA_BW, SANE_I18N("XPA Gray"), _cenable_notcolor, 0, 0 },
3091     { HP_MATRIX_RED, SANE_I18N("Red"), _cenable_notcolor, 0, 0 },
3092     { HP_MATRIX_GREEN, SANE_I18N("Green"), _cenable_notcolor, 1, 0 },
3093     { HP_MATRIX_BLUE, SANE_I18N("Blue"), _cenable_notcolor, 0, 0 },
3094 #ifdef ENABLE_CUSTOM_MATRIX
3095     { HP_MATRIX_CUSTOM, SANE_I18N("Custom"), 0, 0, 0 },
3096 #endif
3097     { 0, 0, 0, 0, 0 }
3098 };
3099 
3100 static const struct hp_option_descriptor_s MATRIX_TYPE[1] = {{
3101     SCANNER_OPTION(MATRIX_TYPE, STRING, NONE),
3102     NO_REQUIRES,
3103     _probe_each_choice, _program_matrix, _enable_choice,
3104     1, 0, 0, 0, 0, SCL_MATRIX, 0, 0, 0, _matrix_choices
3105 }};
3106 
3107 static const struct hp_option_descriptor_s MATRIX_RGB[1] = {{
3108     SCANNER_OPTION(MATRIX_RGB, FIXED, NONE),
3109     NO_REQUIRES,
3110     _probe_matrix, 0, _enable_rgb_matrix,
3111     0, 0, 0, 0, 0, SCL_8x9MATRIX_COEFF, 0, 0, 0, 0
3112 }};
3113 #ifdef FAKE_COLORSEP_MATRIXES
3114 static const struct hp_option_descriptor_s SEPMATRIX[1] = {{
3115     INTERNAL_OPTION(SEPMATRIX, FIXED, NONE),
3116     NO_REQUIRES,
3117     _probe_vector, 0, 0,
3118     0, 0, 0, 0, 0, SCL_8x9MATRIX_COEFF, 0, 0, 0, 0
3119 }};
3120 #endif
3121 #ifdef ENABLE_10BIT_MATRIXES
3122 static const struct hp_option_descriptor_s MATRIX_RGB10[1] = {{
3123     SCANNER_OPTION(MATRIX_RGB, FIXED, NONE),
3124     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_6200C
3125              | HP_COMPAT_5200C | HP_COMPAT_6300C),
3126     _probe_matrix, 0, _enable_rgb_matrix,
3127     0, 0, 0, 0, 0, SCL_10x9MATRIX_COEFF, 0, 0, 0, 0
3128 }};
3129 #endif
3130 #ifdef NotYetSupported
3131 static const struct hp_option_descriptor_s BWMATRIX_GRAY10[1] = {{
3132     SCANNER_OPTION(MATRIX_GRAY, FIXED, NONE),
3133     REQUIRES(HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_6200C
3134              | HP_COMPAT_5200C | HP_COMPAT_6300C),
3135     _probe_matrix, 0, _enable_gray_matrix,
3136     0, 0, 0, 0, 0, SCL_10x3MATRIX_COEFF, 0, 0, 0, 0
3137 }};
3138 #endif
3139 
3140 static const struct hp_choice_s _scan_speed_choices[] = {
3141     { 0, SANE_I18N("Auto"), 0, 0, 0 },
3142     { 1, SANE_I18N("Slow"), 0, 0, 0 },
3143     { 2, SANE_I18N("Normal"), 0, 0, 0 },
3144     { 3, SANE_I18N("Fast"), 0, 0, 0 },
3145     { 4, SANE_I18N("Extra Fast"), 0, 0, 0 },
3146     { 0, 0, 0, 0, 0 }
3147 };
3148 static const struct hp_option_descriptor_s SCAN_SPEED[1] = {{
3149     SCANNER_OPTION(SCAN_SPEED, STRING, NONE),
3150     NO_REQUIRES,
3151     _probe_each_choice, _program_generic, 0,
3152     0, 0, 0, 0, 1, SCL_SPEED, 0, 0, 0, _scan_speed_choices
3153 }};
3154 
3155 static const struct hp_choice_s _smoothing_choices[] = {
3156     { 0, SANE_I18N("Auto"), 0, 0, 0 },
3157     { 3, SANE_I18N("Off"), 0, 0, 0 },
3158     { 1, SANE_I18N("2-pixel"), 0, 0, 0 },
3159     { 2, SANE_I18N("4-pixel"), 0, 0, 0 },
3160     { 4, SANE_I18N("8-pixel"), 0, 0, 0 },
3161     { 0, 0, 0, 0, 0 }
3162 };
3163 static const struct hp_option_descriptor_s SMOOTHING[1] = {{
3164     SCANNER_OPTION(SMOOTHING, STRING, NONE),
3165     NO_REQUIRES,
3166     _probe_each_choice, _program_generic, 0,
3167     0, 0, 0, 0, 0, SCL_FILTER, 0, 0, 0, _smoothing_choices
3168 }};
3169 
3170 static const struct hp_choice_s _media_choices[] = {
3171     { HP_MEDIA_PRINT, SANE_I18N("Print"), 0, 0, 0 },
3172     { HP_MEDIA_SLIDE, SANE_I18N("Slide"), 0, 0, 0 },
3173     { HP_MEDIA_NEGATIVE, SANE_I18N("Film-strip"), 0, 0, 0 },
3174     { 0, 0, 0, 0, 0 }
3175 };
3176 static const struct hp_option_descriptor_s MEDIA[1] = {{
3177     SCANNER_OPTION(MEDIA, STRING, NONE),
3178     NO_REQUIRES,
3179     _probe_choice, _program_media, 0,
3180     1, 1, 1, 1, 0, SCL_MEDIA, 0, 0, 0, _media_choices
3181 }};
3182 
3183 static const struct hp_choice_s _data_widths[] = {
3184     {1, "1", 0, 0, 0},
3185     {8, "8", 0, 0, 0},
3186     {10, "10", 0, 0, 0},
3187     {12, "12", 0, 0, 0},
3188     {14, "14", 0, 0, 0},
3189     {16, "16", 0, 0, 0},
3190     {0, 0, 0, 0, 0}
3191 };
3192 
3193 static const struct hp_option_descriptor_s BIT_DEPTH[1] = {{
3194     SCANNER_OPTION(BIT_DEPTH, STRING, NONE),
3195     NO_REQUIRES,
3196     _probe_choice, _program_data_width, _enable_data_width,
3197     1, 1, 1, 0, 1, SCL_DATA_WIDTH, 0, 0, 0, _data_widths
3198 }};
3199 
3200 static const struct hp_option_descriptor_s OUT8[1] =
3201 {
3202   {
3203     SCANNER_OPTION(OUTPUT_8BIT, BOOL, NONE),
3204     NO_REQUIRES,            /* enum hp_device_compat_e requires */
3205     _probe_bool,            /* SANE_Status (*probe)() */
3206     0,                      /* SANE_Status (*program)() */
3207     _enable_out8,           /* hp_bool_t (*enable)() */
3208     0,                      /* hp_bool_t has_global_effect */
3209     0,                      /* hp_bool_t affects_scan_params */
3210     0,                      /* hp_bool_t program_immediate */
3211     0,                      /* hp_bool_t suppress_for_scan */
3212     0,                      /* hp_bool_t may_change */
3213     0,                      /* HpScl scl_command */
3214     0,                      /* int minval */
3215     0,                      /* int maxval */
3216     0,                      /* int startval */
3217     0                       /* HpChoice choices */
3218   }
3219 };
3220 
3221 /* The 100% setting may cause problems within the scanner */
3222 static const struct hp_choice_s _ps_exposure_times[] = {
3223     /* {0, "100%", 0, 0, 0}, */
3224     { 0, SANE_I18N("Default"), 0, 0, 0 },
3225     {1, "125%", 0, 0, 0},
3226     {2, "150%", 0, 0, 0},
3227     {3, "175%", 0, 0, 0},
3228     {4, "200%", 0, 0, 0},
3229     {5, "225%", 0, 0, 0},
3230     {6, "250%", 0, 0, 0},
3231     {7, "275%", 0, 0, 0},
3232     {8, "300%", 0, 0, 0},
3233     {9, SANE_I18N("Negative"), 0, 0, 0},
3234     {0, 0, 0, 0, 0}
3235 };
3236 
3237 /* Photosmart exposure time */
3238 static const struct hp_option_descriptor_s PS_EXPOSURE_TIME[1] = {{
3239     SCANNER_OPTION(PS_EXPOSURE_TIME, STRING, NONE),
3240     REQUIRES( HP_COMPAT_PS ),
3241     _probe_ps_exposure_time, _program_ps_exposure_time, 0,
3242     0, 0, 0, 0, 0, 0, 0, 0, 0, _ps_exposure_times
3243 }};
3244 
3245 /* Normal, ADF or XPA scanning. Because scanning from ADF can change */
3246 /* the extent of the scanning area, this option is marked to change  */
3247 /* global settings. The user should switch to ADF scanning after     */
3248 /* placing paper in the ADF. */
3249 static const struct hp_choice_s _scan_types[] = {
3250     { HP_SCANTYPE_NORMAL, SANE_I18N("Normal"), 0, 0, 0 },
3251     { HP_SCANTYPE_ADF, SANE_I18N("ADF"), 0, 0, 0 },
3252     { HP_SCANTYPE_XPA, SANE_I18N("XPA"), 0, 0, 0 },
3253     {0, 0, 0, 0, 0 }
3254 };
3255 
3256 static const struct hp_option_descriptor_s SCAN_SOURCE[1] = {{
3257     SCANNER_OPTION(SCAN_SOURCE, STRING, NONE),
3258     NO_REQUIRES,
3259     _probe_scan_type, _program_scan_type, 0,
3260     1, 1, 1, 0, 0, SCL_START_SCAN, 0, 0, 0, _scan_types
3261 }};
3262 
3263 /* Unload after is only necessary for PhotoScanner */
3264 static const struct hp_option_descriptor_s UNLOAD_AFTER_SCAN[1] = {{
3265     SCANNER_OPTION(UNLOAD_AFTER_SCAN, BOOL, NONE),
3266     REQUIRES(HP_COMPAT_PS),
3267     _probe_bool, _program_unload_after_scan, 0,
3268     0, 0, 0, 1, 0, SCL_UNLOAD, 0, 0, 0, 0
3269 }};
3270 
3271 static const struct hp_option_descriptor_s CHANGE_DOC[1] = {{
3272     SCANNER_OPTION(CHANGE_DOC, BUTTON, NONE),
3273     NO_REQUIRES,
3274     _probe_change_doc, _program_change_doc, 0,
3275     1, 1, 1, 1, 0, SCL_CHANGE_DOC, 0, 0, 0, 0
3276 }};
3277 
3278 static const struct hp_option_descriptor_s UNLOAD[1] = {{
3279     SCANNER_OPTION(UNLOAD, BUTTON, NONE),
3280     NO_REQUIRES,
3281     _probe_unload, _program_unload, 0,
3282     0, 0, 1, 1, 0, SCL_UNLOAD, 0, 0, 0, 0
3283 }};
3284 
3285 /* There is no inquire ID-for the calibrate command. */
3286 /* So here we need the requiries. */
3287 static const struct hp_option_descriptor_s CALIBRATE[1] = {{
3288     SCANNER_OPTION(CALIBRATE, BUTTON, NONE),
3289     REQUIRES(HP_COMPAT_PS),
3290     _probe_calibrate, _program_calibrate, _enable_calibrate,
3291     0, 0, 1, 1, 0, SCL_CALIBRATE, 0, 0, 0, 0
3292 }};
3293 
3294 static const struct hp_option_descriptor_s GEOMETRY_GROUP[1] = {{
3295     ADVANCED_GROUP(SANE_I18N("Geometry")),
3296     0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
3297 }};
3298 static const struct hp_option_descriptor_s SCAN_TL_X[1] = {{
3299     SCANNER_OPTION(SCAN_TL_X, FIXED, MM),
3300     NO_REQUIRES,
3301     _probe_geometry, _program_geometry, 0,
3302     0, 1, 0, 0, 1, SCL_X_POS, 0, 0, 0, 0
3303 }};
3304 static const struct hp_option_descriptor_s SCAN_TL_Y[1] = {{
3305     SCANNER_OPTION(SCAN_TL_Y, FIXED, MM),
3306     NO_REQUIRES,
3307     _probe_geometry, _program_geometry, 0,
3308     0, 1, 0, 0, 1, SCL_Y_POS, 0, 0, 0, 0
3309 }};
3310 static const struct hp_option_descriptor_s SCAN_BR_X[1] = {{
3311     SCANNER_OPTION(SCAN_BR_X, FIXED, MM),
3312     NO_REQUIRES,
3313     _probe_geometry, _program_geometry, 0,
3314     0, 1, 0, 0, 1, SCL_X_EXTENT, 0, 0, 0, 0
3315 }};
3316 static const struct hp_option_descriptor_s SCAN_BR_Y[1] = {{
3317     SCANNER_OPTION(SCAN_BR_Y, FIXED, MM),
3318     NO_REQUIRES,
3319     _probe_geometry, _program_geometry, 0,
3320     0, 1, 0, 0, 1, SCL_Y_EXTENT, 0, 0, 0, 0
3321 }};
3322 
3323 static const struct hp_choice_s _mirror_horiz_choices[] = {
3324     { HP_MIRROR_HORIZ_OFF, SANE_I18N("Off"), 0, 0, 0 },
3325     { HP_MIRROR_HORIZ_ON, SANE_I18N("On"), 0, 0, 0 },
3326     { HP_MIRROR_HORIZ_CONDITIONAL, SANE_I18N("Conditional"), 0, 0, 0 },
3327     { 0, 0, 0, 0, 0 }
3328 };
3329 static const struct hp_option_descriptor_s MIRROR_HORIZ[1] = {{
3330     SCANNER_OPTION(MIRROR_HORIZ, STRING, NONE),
3331     NO_REQUIRES,
3332     _probe_mirror_horiz, _program_mirror_horiz, 0,
3333     0, 0, 0, 0, 0, SCL_MIRROR_IMAGE, 0, 0, 0, _mirror_horiz_choices
3334 }};
3335 
3336 static const struct hp_choice_s _mirror_vert_choices[] = {
3337     { HP_MIRROR_VERT_OFF, SANE_I18N("Off"), 0, 0, 0 },
3338     { HP_MIRROR_VERT_ON, SANE_I18N("On"), 0, 0, 0 },
3339     { HP_MIRROR_VERT_CONDITIONAL, SANE_I18N("Conditional"), 0, 0, 0 },
3340     { 0, 0, 0, 0, 0 }
3341 };
3342 static const struct hp_option_descriptor_s MIRROR_VERT[1] = {{
3343     SCANNER_OPTION(MIRROR_VERT, STRING, NONE),
3344     NO_REQUIRES,
3345     _probe_mirror_vert, 0, 0,
3346     0, 0, 0, 0, 0, 0, 0, 0, 0, _mirror_vert_choices
3347 }};
3348 
3349 static const struct hp_option_descriptor_s BUTTON_WAIT[1] =
3350 {
3351   {
3352     SCANNER_OPTION(BUTTON_WAIT, BOOL, NONE),
3353     NO_REQUIRES,            /* enum hp_device_compat_e requires */
3354     _probe_front_button,    /* SANE_Status (*probe)() */
3355     0,                      /* SANE_Status (*program)() */
3356     0,                      /* hp_bool_t (*enable)() */
3357     0,                      /* hp_bool_t has_global_effect */
3358     0,                      /* hp_bool_t affects_scan_params */
3359     0,                      /* hp_bool_t program_immediate */
3360     0,                      /* hp_bool_t suppress_for_scan */
3361     0,                      /* hp_bool_t may_change */
3362     0,                      /* HpScl scl_command */
3363     0,                      /* int minval */
3364     0,                      /* int maxval */
3365     0,                      /* int startval */
3366     0                       /* HpChoice choices */
3367   }
3368 };
3369 
3370 
3371 static const struct hp_option_descriptor_s LAMP_OFF[1] =
3372 {
3373   {
3374     SCANNER_OPTION(LAMP_OFF, BUTTON, NONE),
3375     /* Lamp off instruction not supported by Photosmart */
3376     REQUIRES(  HP_COMPAT_PLUS | HP_COMPAT_2C | HP_COMPAT_2P | HP_COMPAT_2CX
3377              | HP_COMPAT_4C |  HP_COMPAT_3P | HP_COMPAT_4P | HP_COMPAT_5P
3378              | HP_COMPAT_5100C | HP_COMPAT_6200C | HP_COMPAT_5200C
3379              | HP_COMPAT_6300C),   /* enum hp_device_compat_e requires */
3380     _probe_bool,            /* SANE_Status (*probe)() */
3381     _program_lamp_off,      /* SANE_Status (*program)() */
3382     0,                      /* hp_bool_t (*enable)() */
3383     0,                      /* hp_bool_t has_global_effect */
3384     0,                      /* hp_bool_t affects_scan_params */
3385     1,                      /* hp_bool_t program_immediate */
3386     1,                      /* hp_bool_t suppress_for_scan */
3387     0,                      /* hp_bool_t may_change */
3388     SCL_LAMPTEST,           /* HpScl scl_command */
3389     0,                      /* int minval */
3390     0,                      /* int maxval */
3391     0,                      /* int startval */
3392     0                       /* HpChoice choices */
3393   }
3394 };
3395 
3396 #ifdef HP_EXPERIMENTAL
3397 
3398 static const struct hp_choice_s _range_choices[] = {
3399     { 0, "0", 0, 0, 0 },
3400     { 1, "1", 0, 0, 0 },
3401     { 2, "2", 0, 0, 0 },
3402     { 3, "3", 0, 0, 0 },
3403     { 4, "4", 0, 0, 0 },
3404     { 5, "5", 0, 0, 0 },
3405     { 6, "6", 0, 0, 0 },
3406     { 7, "7", 0, 0, 0 },
3407     { 8, "8", 0, 0, 0 },
3408     { 9, "9", 0, 0, 0 },
3409     { 0, 0, 0, 0, 0 }
3410 };
3411 static const struct hp_option_descriptor_s EXPERIMENT_GROUP[1] = {{
3412     ADVANCED_GROUP(SANE_I18N("Experiment"))
3413     0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */
3414 }};
3415 static const struct hp_option_descriptor_s PROBE_10470[1] = {{
3416     SCANNER_OPTION(10470, STRING, NONE),
3417     NO_REQUIRES,
3418     _probe_each_choice, _program_generic, 0,
3419     0, 0, 0, 0, 0, SCL_10470, 0, 0, 0, _range_choices
3420 }};
3421 static const struct hp_option_descriptor_s PROBE_10485[1] = {{
3422     SCANNER_OPTION(10485, STRING, NONE),
3423     NO_REQUIRES,
3424     _probe_each_choice, _program_generic, 0,
3425     0, 0, 0, 0, 0, SCL_10485, 0, 0, 0, _range_choices
3426 }};
3427 static const struct hp_option_descriptor_s PROBE_10952[1] = {{
3428     SCANNER_OPTION(10952, STRING, NONE),
3429     NO_REQUIRES,
3430     _probe_each_choice, _program_generic, 0,
3431     0, 0, 0, 0, 0, SCL_10952, 0, 0, 0, _range_choices
3432 }};
3433 static const struct hp_option_descriptor_s PROBE_10967[1] = {{
3434     SCANNER_OPTION(10967, INT, NONE),
3435     NO_REQUIRES,
3436     _probe_int, _program_generic, 0,
3437     0, 0, 0, 0, 0, SCL_10967, 0, 0, 0, 0
3438 }};
3439 
3440 #endif
3441 
3442 static HpOptionDescriptor hp_options[] = {
3443     NUM_OPTIONS,
3444 
3445     SCAN_MODE_GROUP,
3446     PREVIEW_MODE,
3447     SCAN_MODE, SCAN_RESOLUTION, DEVPIX_RESOLUTION,
3448 
3449     ENHANCEMENT_GROUP,
3450     BRIGHTNESS, CONTRAST,
3451 #ifdef SCL_SHARPENING
3452     SHARPENING,
3453 #endif
3454     AUTO_THRESHOLD,
3455 
3456     ADVANCED_GROUP,
3457     CUSTOM_GAMMA,
3458 #ifdef ENABLE_7x12_TONEMAPS
3459     GAMMA_VECTOR_7x12,
3460     RGB_TONEMAP, GAMMA_VECTOR_R, GAMMA_VECTOR_G, GAMMA_VECTOR_B,
3461 #endif
3462     GAMMA_VECTOR_8x8,
3463 
3464     MATRIX_TYPE,
3465 #ifdef FAKE_COLORSEP_MATRIXES
3466     SEPMATRIX,
3467 #endif
3468 #ifdef ENABLE_10BIT_MATRIXES
3469     MATRIX_RGB10, /* FIXME: unsupported: MATRIX_GRAY10, */
3470 #endif
3471     MATRIX_RGB,
3472 
3473     HALFTONE_PATTERN,
3474 #ifdef ENABLE_16X16_DITHERS
3475     HALFTONE_PATTERN_16x16, HORIZONTAL_DITHER_16x16,
3476 #endif
3477     HALFTONE_PATTERN_8x8, HORIZONTAL_DITHER_8x8,
3478 
3479     SCAN_SPEED, SMOOTHING, MEDIA, PS_EXPOSURE_TIME, BIT_DEPTH, OUT8,
3480     SCAN_SOURCE, BUTTON_WAIT, LAMP_OFF, UNLOAD_AFTER_SCAN,
3481     CHANGE_DOC, UNLOAD, CALIBRATE,
3482 
3483     GEOMETRY_GROUP,
3484     SCAN_TL_X, SCAN_TL_Y, SCAN_BR_X, SCAN_BR_Y,
3485     MIRROR_HORIZ, MIRROR_VERT,
3486 
3487 #ifdef HP_EXPERIMENTAL
3488 
3489     EXPERIMENT_GROUP,
3490     PROBE_10470,
3491     PROBE_10485,
3492     PROBE_10952,
3493     PROBE_10967,
3494 
3495 #endif
3496 
3497     0
3498 };
3499 
3500 
3501 
3502 /*
3503  * class HpOptSet
3504  */
3505 
3506 struct hp_optset_s
3507 {
3508 #define OPTION_LIST_MAX	sizeof(hp_options)/sizeof(hp_options[0])
3509     HpOption	options[OPTION_LIST_MAX];
3510     size_t	num_sane_opts;
3511     size_t	num_opts;
3512 
3513     /* Magic accessors to get coord in actual scan pixels: */
3514     HpAccessor	tl_x, tl_y, br_x, br_y;
3515 };
3516 
3517 static HpOption
hp_optset_get(HpOptSet this,HpOptionDescriptor optd)3518 hp_optset_get (HpOptSet this, HpOptionDescriptor optd)
3519 {
3520   HpOption *	optp	= this->options;
3521   int		i	= this->num_opts;
3522 
3523   while (i--)
3524     {
3525       if ((*optp)->descriptor == optd)
3526 	  return *optp;
3527       optp++;
3528     }
3529   return 0;
3530 }
3531 
3532 static HpOption
hp_optset_getByIndex(HpOptSet this,int optnum)3533 hp_optset_getByIndex (HpOptSet this, int optnum)
3534 {
3535   if ((optnum < 0) || (optnum >= (int)this->num_sane_opts))
3536       return 0;
3537   return this->options[optnum];
3538 }
3539 
3540 static HpOption
hp_optset_getByName(HpOptSet this,const char * name)3541 hp_optset_getByName (HpOptSet this, const char * name)
3542 {
3543   HpOption *	optp	= this->options;
3544   int		i	= this->num_opts;
3545 
3546   while (i--)
3547     {
3548       if (strcmp((*optp)->descriptor->name, name) == 0)
3549 	  return *optp;
3550       optp++;
3551     }
3552   return 0;
3553 }
3554 
3555 static _HpOption
_hp_optset_get(HpOptSet this,HpOptionDescriptor opt)3556 _hp_optset_get (HpOptSet this, HpOptionDescriptor opt)
3557 {
3558   /* Cast away const-ness */
3559   return (_HpOption) hp_optset_get(this, opt);
3560 }
3561 
3562 enum hp_scanmode_e
sanei_hp_optset_scanmode(HpOptSet this,HpData data)3563 sanei_hp_optset_scanmode (HpOptSet this, HpData data)
3564 {
3565   HpOption mode = hp_optset_get(this, SCAN_MODE);
3566   assert(mode);
3567   return hp_option_getint(mode, data);
3568 }
3569 
3570 
3571 hp_bool_t
sanei_hp_optset_output_8bit(HpOptSet this,HpData data)3572 sanei_hp_optset_output_8bit (HpOptSet this, HpData data)
3573 {
3574   HpOption option_out8;
3575   int out8;
3576 
3577   option_out8 = hp_optset_get(this, OUT8);
3578   if (option_out8)
3579   {
3580     out8 = hp_option_getint(option_out8, data);
3581     return out8;
3582   }
3583   return 0;
3584 }
3585 
3586 
3587 /* Returns the data width that is send to the scanner, depending */
3588 /* on the scanmode. (b/w: 1, gray: 8..12, color: 24..36 */
3589 int
sanei_hp_optset_data_width(HpOptSet this,HpData data)3590 sanei_hp_optset_data_width (HpOptSet this, HpData data)
3591 {
3592  enum hp_scanmode_e mode = sanei_hp_optset_scanmode (this, data);
3593  int datawidth = 0;
3594  HpOption opt_dwidth;
3595 
3596  switch (mode)
3597  {
3598    case HP_SCANMODE_LINEART:
3599    case HP_SCANMODE_HALFTONE:
3600           datawidth = 1;
3601           break;
3602 
3603    case HP_SCANMODE_GRAYSCALE:
3604           opt_dwidth = hp_optset_get(this, BIT_DEPTH);
3605           if (opt_dwidth)
3606             datawidth = hp_option_getint (opt_dwidth, data);
3607           else
3608             datawidth = 8;
3609           break;
3610 
3611    case HP_SCANMODE_COLOR:
3612           opt_dwidth = hp_optset_get(this, BIT_DEPTH);
3613           if (opt_dwidth)
3614             datawidth = 3 * hp_option_getint (opt_dwidth, data);
3615           else
3616             datawidth = 24;
3617           break;
3618  }
3619  return datawidth;
3620 }
3621 
3622 hp_bool_t
sanei_hp_optset_mirror_vert(HpOptSet this,HpData data,HpScsi scsi)3623 sanei_hp_optset_mirror_vert (HpOptSet this, HpData data, HpScsi scsi)
3624 {
3625   HpOption mode;
3626   int      mirror, sec_dir;
3627 
3628   mode = hp_optset_get(this, MIRROR_VERT);
3629   assert(mode);
3630   mirror = hp_option_getint(mode, data);
3631 
3632   if (mirror == HP_MIRROR_VERT_CONDITIONAL)
3633   {
3634     mirror = HP_MIRROR_VERT_OFF;
3635     if ( ( sanei_hp_scl_inquire(scsi, SCL_SECONDARY_SCANDIR, &sec_dir, 0, 0)
3636            == SANE_STATUS_GOOD ) && ( sec_dir == 1 ) )
3637       mirror = HP_MIRROR_VERT_ON;
3638   }
3639   return mirror == HP_MIRROR_VERT_ON;
3640 }
3641 
sanei_hp_optset_start_wait(HpOptSet this,HpData data)3642 hp_bool_t sanei_hp_optset_start_wait(HpOptSet this, HpData data)
3643 {
3644   HpOption mode;
3645   int wait;
3646 
3647   if ((mode = hp_optset_get(this, BUTTON_WAIT)) == 0)
3648     return(0);
3649 
3650   wait = hp_option_getint(mode, data);
3651 
3652   return(wait);
3653 }
3654 
3655 HpScl
sanei_hp_optset_scan_type(HpOptSet this,HpData data)3656 sanei_hp_optset_scan_type (HpOptSet this, HpData data)
3657 {
3658   HpOption mode;
3659   HpScl    scl = SCL_START_SCAN;
3660   int      scantype;
3661 
3662   mode = hp_optset_get(this, SCAN_SOURCE);
3663   if (mode)
3664   {
3665     scantype = hp_option_getint(mode, data);
3666     DBG(5, "sanei_hp_optset_scan_type: scantype=%d\n", scantype);
3667 
3668     switch (scantype)
3669     {
3670       case 1: scl = SCL_ADF_SCAN; break;
3671       case 2: scl = SCL_XPA_SCAN; break;
3672       default: scl = SCL_START_SCAN; break;
3673     }
3674   }
3675   return scl;
3676 }
3677 
3678 static void
hp_optset_add(HpOptSet this,HpOption opt)3679 hp_optset_add (HpOptSet this, HpOption opt)
3680 {
3681   assert(this->num_opts < OPTION_LIST_MAX);
3682 
3683   /*
3684    * Keep internal options at the end of the list.
3685    */
3686   if (hp_option_isInternal(opt))
3687       this->options[this->num_opts] = opt;
3688   else
3689     {
3690       if (this->num_opts != this->num_sane_opts)
3691 	  memmove(&this->options[this->num_sane_opts + 1],
3692 		  &this->options[this->num_sane_opts],
3693 		  ( (this->num_opts - this->num_sane_opts)
3694 		    * sizeof(*this->options) ));
3695       this->options[this->num_sane_opts++] = opt;
3696     }
3697   this->num_opts++;
3698 }
3699 
3700 static SANE_Status
hp_optset_fix_geometry_options(HpOptSet this)3701 hp_optset_fix_geometry_options (HpOptSet this)
3702 {
3703   _HpOption	tl_x	= _hp_optset_get(this, SCAN_TL_X);
3704   _HpOption	tl_y	= _hp_optset_get(this, SCAN_TL_Y);
3705   _HpOption	br_x	= _hp_optset_get(this, SCAN_BR_X);
3706   _HpOption	br_y	= _hp_optset_get(this, SCAN_BR_Y);
3707   HpOption	scanres	= hp_optset_get(this, SCAN_RESOLUTION);
3708   HpOption	devpix	= hp_optset_get(this, DEVPIX_RESOLUTION);
3709 
3710   HpAccessor	tl_xa, tl_ya, br_xa, br_ya;
3711 
3712   assert(tl_x && tl_y && br_x && br_y); /* Geometry options missing */
3713 
3714   tl_xa = tl_x->data_acsr;
3715   tl_ya = tl_y->data_acsr;
3716   br_xa = br_x->data_acsr;
3717   br_ya = br_y->data_acsr;
3718 
3719   assert(tl_xa && tl_ya && br_xa && br_ya);
3720   assert(scanres->data_acsr && devpix->data_acsr);
3721 
3722   /* Magic accessors that will read out in device pixels */
3723   tl_x->data_acsr = sanei_hp_accessor_geometry_new(tl_xa, br_xa, 0,
3724 					     devpix->data_acsr);
3725   tl_y->data_acsr = sanei_hp_accessor_geometry_new(tl_ya, br_ya, 0,
3726 					     devpix->data_acsr);
3727   br_x->data_acsr = sanei_hp_accessor_geometry_new(br_xa, tl_xa, 1,
3728 					     devpix->data_acsr);
3729   br_y->data_acsr = sanei_hp_accessor_geometry_new(br_ya, tl_ya, 1,
3730 					     devpix->data_acsr);
3731 
3732   if (!tl_x->data_acsr || !tl_y->data_acsr
3733       || !br_x->data_acsr || !br_y->data_acsr)
3734       return SANE_STATUS_NO_MEM;
3735 
3736   /* Magic accessors that will read out in scan pixels */
3737   this->tl_x = sanei_hp_accessor_geometry_new(tl_xa, br_xa, 0,
3738                                               scanres->data_acsr);
3739   this->tl_y = sanei_hp_accessor_geometry_new(tl_ya, br_ya, 0,
3740                                               scanres->data_acsr);
3741   this->br_x = sanei_hp_accessor_geometry_new(br_xa, tl_xa, 1,
3742                                               scanres->data_acsr);
3743   this->br_y = sanei_hp_accessor_geometry_new(br_ya, tl_ya, 1,
3744                                               scanres->data_acsr);
3745   if (!this->tl_x || !this->tl_y || !this->br_x || !this->br_y)
3746       return SANE_STATUS_NO_MEM;
3747 
3748   return SANE_STATUS_GOOD;
3749 }
3750 
3751 static void
hp_optset_reprogram(HpOptSet this,HpData data,HpScsi scsi)3752 hp_optset_reprogram (HpOptSet this, HpData data, HpScsi scsi)
3753 {
3754   int i;
3755 
3756   DBG(5, "hp_optset_reprogram: %lu options\n",
3757       (unsigned long) this->num_opts);
3758 
3759   for (i = 0; i < (int)this->num_opts; i++)
3760       hp_option_reprogram(this->options[i], this, data, scsi);
3761 
3762   DBG(5, "hp_optset_reprogram: finished\n");
3763 }
3764 
3765 static void
hp_optset_reprobe(HpOptSet this,HpData data,HpScsi scsi)3766 hp_optset_reprobe (HpOptSet this, HpData data, HpScsi scsi)
3767 {
3768   int i;
3769 
3770   DBG(5, "hp_optset_reprobe: %lu options\n",
3771       (unsigned long) this->num_opts);
3772 
3773   for (i = 0; i < (int)this->num_opts; i++)
3774       hp_option_reprobe(this->options[i], this, data, scsi);
3775 
3776   DBG(5, "hp_optset_reprobe: finished\n");
3777 }
3778 
3779 static void
hp_optset_updateEnables(HpOptSet this,HpData data,const HpDeviceInfo * info)3780 hp_optset_updateEnables (HpOptSet this, HpData data, const HpDeviceInfo *info)
3781 {
3782   int i;
3783 
3784   DBG(5, "hp_optset_updateEnables: %lu options\n",
3785       (unsigned long) this->num_opts);
3786 
3787   for (i = 0; i < (int)this->num_opts; i++)
3788       hp_option_updateEnable(this->options[i], this, data, info);
3789 }
3790 
3791 static hp_bool_t
hp_optset_isEnabled(HpOptSet this,HpData data,const char * name,const HpDeviceInfo * info)3792 hp_optset_isEnabled (HpOptSet this, HpData data, const char *name,
3793                      const HpDeviceInfo *info)
3794 {
3795   HpOption optpt;
3796 
3797   optpt = hp_optset_getByName (this, name);
3798 
3799   if (!optpt)  /* Not found ? Not enabled */
3800     return 0;
3801 
3802   if (!(optpt->descriptor->enable)) /* No enable necessary ? Enabled */
3803     return 1;
3804 
3805   return (*optpt->descriptor->enable)(optpt, this, data, info);
3806 }
3807 
3808 /* This function is only called from sanei_hp_handle_startScan() */
3809 SANE_Status
sanei_hp_optset_download(HpOptSet this,HpData data,HpScsi scsi)3810 sanei_hp_optset_download (HpOptSet this, HpData data, HpScsi scsi)
3811 {
3812   int i, errcount = 0;
3813 
3814   DBG(3, "Start downloading parameters to scanner\n");
3815 
3816   /* Reset scanner to wake it up */
3817 
3818   /* Reset would switch off XPA lamp and switch on scanner lamp. */
3819   /* Only do a reset if not in active XPA mode */
3820   if (  (sanei_hp_optset_scan_type (this, data) != SCL_XPA_SCAN)
3821       || (!sanei_hp_is_active_xpa (scsi)) )
3822   {
3823     RETURN_IF_FAIL(sanei_hp_scl_reset (scsi));
3824   }
3825   RETURN_IF_FAIL(sanei_hp_scl_clearErrors (scsi));
3826 
3827   sanei_hp_device_simulate_clear ( sanei_hp_scsi_devicename (scsi) );
3828 
3829   for (i = 0; i < (int)this->num_opts; i++)
3830   {
3831       if ( (this->options[i])->descriptor->suppress_for_scan )
3832       {
3833         DBG(3,"sanei_hp_optset_download: %s suppressed for scan\n",
3834             (this->options[i])->descriptor->name);
3835       }
3836       else
3837       {
3838         RETURN_IF_FAIL( hp_option_program(this->options[i], scsi, this, data) );
3839 
3840         if ( sanei_hp_scl_errcheck (scsi) != SANE_STATUS_GOOD )
3841         {
3842           errcount++;
3843           DBG(3, "Option %s generated scanner error\n",
3844               this->options[i]->descriptor->name);
3845 
3846           RETURN_IF_FAIL(sanei_hp_scl_clearErrors (scsi));
3847         }
3848       }
3849   }
3850   DBG(3, "Downloading parameters finished.\n");
3851 
3852   /* Check preview */
3853   {HpOption option;
3854    int is_preview, data_width;
3855    const HpDeviceInfo *info;
3856 
3857    option = hp_optset_getByName (this, SANE_NAME_PREVIEW);
3858    if ( option )
3859    {
3860      is_preview = hp_option_getint (option, data);
3861      if ( is_preview )
3862      {
3863        /* For preview we only use 8 bit per channel */
3864 
3865        DBG(3, "sanei_hp_optset_download: Set up preview options\n");
3866 
3867        info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
3868 
3869        if (hp_optset_isEnabled (this, data, SANE_NAME_BIT_DEPTH, info))
3870        {
3871          data_width = sanei_hp_optset_data_width (this, data);
3872          if (data_width > 24)
3873          {
3874            sanei_hp_scl_set(scsi, SCL_DATA_WIDTH, 24);
3875          }
3876          else if ((data_width > 8) && (data_width <= 16))
3877          {
3878            sanei_hp_scl_set(scsi, SCL_DATA_WIDTH, 8);
3879          }
3880        }
3881      }
3882    }
3883   }
3884 
3885   return SANE_STATUS_GOOD;
3886 }
3887 
3888 SANE_Status
sanei_hp_optset_new(HpOptSet * newp,HpScsi scsi,HpDevice dev)3889 sanei_hp_optset_new(HpOptSet * newp, HpScsi scsi, HpDevice dev)
3890 {
3891   HpOptionDescriptor *	ptr;
3892   HpOptSet		this = sanei_hp_allocz(sizeof(*this));
3893   SANE_Status		status;
3894   HpOption 		option;
3895   const HpDeviceInfo   *info;
3896 
3897   if (!this)
3898       return SANE_STATUS_NO_MEM;
3899 
3900   /* FIXME: more DBG's */
3901   for (ptr = hp_options; *ptr; ptr++)
3902     {
3903       HpOptionDescriptor desc = *ptr;
3904 
3905       DBG(8, "sanei_hp_optset_new: %s\n", desc->name);
3906       if (desc->requires && !sanei_hp_device_compat(dev, desc->requires))
3907 	  continue;
3908       if (desc->type != SANE_TYPE_GROUP
3909 	  && hp_optset_getByName(this, desc->name))
3910 	  continue;
3911 
3912       status = hp_option_descriptor_probe(desc, scsi, this,
3913 					  dev->data, &option);
3914       if (UNSUPPORTED(status))
3915 	  continue;
3916       if (FAILED(status))
3917 	{
3918 	  DBG(1, "Option '%s': probe failed: %s\n", desc->name,
3919 	      sane_strstatus(status));
3920 	  sanei_hp_free(this);
3921 	  return status;
3922 	}
3923       hp_optset_add(this, option);
3924     }
3925 
3926   /* Set NUM_OPTIONS */
3927   assert(this->options[0]->descriptor == NUM_OPTIONS);
3928   sanei_hp_accessor_setint(this->options[0]->data_acsr, dev->data,
3929 		     this->num_sane_opts);
3930 
3931   /* Now for some kludges */
3932   status = hp_optset_fix_geometry_options(this);
3933   if (FAILED(status))
3934     {
3935       sanei_hp_free(this);
3936       return status;
3937     }
3938 
3939   info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
3940   hp_optset_updateEnables(this, dev->data, info);
3941 
3942   *newp = this;
3943   return SANE_STATUS_GOOD;
3944 }
3945 
3946 hp_bool_t
sanei_hp_optset_isImmediate(HpOptSet this,int optnum)3947 sanei_hp_optset_isImmediate (HpOptSet this, int optnum)
3948 {
3949   HpOption	opt  = hp_optset_getByIndex(this, optnum);
3950 
3951   if (!opt)
3952       return 0;
3953 
3954   return hp_option_isImmediate (opt);
3955 }
3956 
3957 SANE_Status
sanei_hp_optset_control(HpOptSet this,HpData data,int optnum,SANE_Action action,void * valp,SANE_Int * infop,HpScsi scsi,hp_bool_t immediate)3958 sanei_hp_optset_control (HpOptSet this, HpData data,
3959                          int optnum, SANE_Action action,
3960                          void * valp, SANE_Int *infop, HpScsi scsi,
3961                          hp_bool_t immediate)
3962 {
3963   HpOption	opt  = hp_optset_getByIndex(this, optnum);
3964   SANE_Int	my_info = 0, my_val = 0;
3965 
3966   DBG(3,"sanei_hp_optset_control: %s\n", opt ? opt->descriptor->name : "");
3967 
3968   if (infop)
3969       *infop = 0;
3970   else
3971       infop = &my_info;
3972 
3973   if (!opt)
3974       return SANE_STATUS_INVAL;
3975 
3976   /* There are problems with SANE_ACTION_GET_VALUE and valp == 0. */
3977   /* Check if we really need valp. */
3978   if ((action == SANE_ACTION_GET_VALUE) && (!valp))
3979   {
3980     /* Options without a value ? */
3981     if (   (opt->descriptor->type == SANE_TYPE_BUTTON)
3982         || (opt->descriptor->type == SANE_TYPE_GROUP))
3983     {
3984       valp = &my_val; /* Just simulate a return value locally. */
3985     }
3986     else /* Others must return a value. So this is invalid */
3987     {
3988       DBG(1, "sanei_hp_optset_control: get value, but valp == 0\n");
3989       return SANE_STATUS_INVAL;
3990     }
3991   }
3992 
3993   if (immediate)
3994     RETURN_IF_FAIL( hp_option_imm_control(this, opt, data, action, valp, infop,
3995                                           scsi) );
3996   else
3997     RETURN_IF_FAIL( hp_option_control(opt, data, action, valp, infop ) );
3998 
3999   if ((*infop & SANE_INFO_RELOAD_OPTIONS) != 0)
4000   {const HpDeviceInfo *info;
4001 
4002       DBG(3,"sanei_hp_optset_control: reprobe\n");
4003 
4004       /* At first we try to reprogram the parameters that may have changed */
4005       /* by an option that had a global effect.  This is necessary to */
4006       /* specify options in an arbitrary order. Example: */
4007       /* Changing scan mode resets scan resolution in the scanner. */
4008       /* If resolution is set from the API before scan mode, we must */
4009       /* reprogram the resolution afterwards. */
4010       hp_optset_reprogram(this, data, scsi);
4011       hp_optset_reprobe(this, data, scsi);
4012       info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
4013       hp_optset_updateEnables(this, data, info);
4014   }
4015 
4016   return SANE_STATUS_GOOD;
4017 }
4018 
4019 SANE_Status
sanei_hp_optset_guessParameters(HpOptSet this,HpData data,SANE_Parameters * p)4020 sanei_hp_optset_guessParameters (HpOptSet this, HpData data,
4021                                  SANE_Parameters * p)
4022 {
4023   /* These are magic accessors which actually get the extent, not the
4024    * absolute position... */
4025   int xextent = sanei_hp_accessor_getint(this->br_x, data);
4026   int yextent = sanei_hp_accessor_getint(this->br_y, data);
4027   int data_width;
4028 
4029   assert(xextent > 0 && yextent > 0);
4030   p->last_frame = SANE_TRUE;
4031   p->pixels_per_line = xextent;
4032   p->lines           = yextent;
4033 
4034   switch (sanei_hp_optset_scanmode(this, data)) {
4035   case HP_SCANMODE_LINEART: /* Lineart */
4036   case HP_SCANMODE_HALFTONE: /* Halftone */
4037       p->format = SANE_FRAME_GRAY;
4038       p->depth  = 1;
4039       p->bytes_per_line  = (p->pixels_per_line + 7) / 8;
4040       break;
4041   case HP_SCANMODE_GRAYSCALE: /* Grayscale */
4042       p->format = SANE_FRAME_GRAY;
4043       p->depth  = 8;
4044       p->bytes_per_line  = p->pixels_per_line;
4045       if ( !sanei_hp_optset_output_8bit (this, data) )
4046       {
4047         data_width = sanei_hp_optset_data_width (this, data);
4048         if ( data_width > 8 )
4049         {
4050           p->depth *= 2;
4051           p->bytes_per_line *= 2;
4052         }
4053       }
4054       break;
4055   case HP_SCANMODE_COLOR: /* RGB */
4056       p->format = SANE_FRAME_RGB;
4057       p->depth = 8;
4058       p->bytes_per_line  = 3 * p->pixels_per_line;
4059       if ( !sanei_hp_optset_output_8bit (this, data) )
4060       {
4061         data_width = sanei_hp_optset_data_width (this, data);
4062         if ( data_width > 24 )
4063         {
4064           p->depth *= 2;
4065           p->bytes_per_line *= 2;
4066         }
4067       }
4068       break;
4069   default:
4070       assert(!"Bad scan mode?");
4071       return SANE_STATUS_INVAL;
4072   }
4073 
4074   return SANE_STATUS_GOOD;
4075 }
4076 
4077 const SANE_Option_Descriptor *
sanei_hp_optset_saneoption(HpOptSet this,HpData data,int optnum)4078 sanei_hp_optset_saneoption (HpOptSet this, HpData data, int optnum)
4079 {
4080   HpOption opt = hp_optset_getByIndex(this, optnum);
4081 
4082   if (!opt)
4083       return 0;
4084   return hp_option_saneoption(opt, data);
4085 }
4086