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, ¤t_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