1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru>
4 AFE offset/gain setting by David Stevenson <david.stevenson@zoom.co.uk>
5 Copyright (C) 2002 - 2007 Henning Geinitz <sane@geinitz.org>
6 Copyright (C) 2009 Stéphane Voltz <stef.dev@free.fr> for sheetfed
7 calibration code.
8
9 This file is part of the SANE package.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>.
23
24 As a special exception, the authors of SANE give permission for
25 additional uses of the libraries contained in this release of SANE.
26
27 The exception is that, if you link a SANE library with other files
28 to produce an executable, this does not by itself cause the
29 resulting executable to be covered by the GNU General Public
30 License. Your use of that executable is in no way restricted on
31 account of linking the SANE library code into it.
32
33 This exception does not, however, invalidate any other reasons why
34 the executable file might be covered by the GNU General Public
35 License.
36
37 If you submit changes to SANE to the maintainers to be included in
38 a subsequent release, you agree by submitting the changes that
39 those changes may be distributed with this exception intact.
40
41 If you write modifications of your own for SANE, it is your choice
42 whether to permit this exception to apply to your modifications.
43 If you do not wish that, delete this exception notice.
44 */
45
46 #include "gt68xx_high.h"
47 #include "gt68xx_mid.c"
48
49 #include <unistd.h>
50 #include <math.h>
51
52 static SANE_Status
53 gt68xx_afe_ccd_auto (GT68xx_Scanner * scanner, GT68xx_Scan_Request * request);
54 static SANE_Status gt68xx_afe_cis_auto (GT68xx_Scanner * scanner);
55
56 SANE_Status
gt68xx_calibrator_new(SANE_Int width,SANE_Int white_level,GT68xx_Calibrator ** cal_return)57 gt68xx_calibrator_new (SANE_Int width,
58 SANE_Int white_level, GT68xx_Calibrator ** cal_return)
59 {
60 GT68xx_Calibrator *cal;
61 SANE_Int i;
62
63 DBG (4, "gt68xx_calibrator_new: enter: width=%d, white_level=%d\n",
64 width, white_level);
65
66 *cal_return = 0;
67
68 if (width <= 0)
69 {
70 DBG (5, "gt68xx_calibrator_new: invalid width=%d\n", width);
71 return SANE_STATUS_INVAL;
72 }
73
74 cal = (GT68xx_Calibrator *) malloc (sizeof (GT68xx_Calibrator));
75 if (!cal)
76 {
77 DBG (5, "gt68xx_calibrator_new: no memory for GT68xx_Calibrator\n");
78 return SANE_STATUS_NO_MEM;
79 }
80
81 cal->k_white = NULL;
82 cal->k_black = NULL;
83 cal->white_line = NULL;
84 cal->black_line = NULL;
85 cal->width = width;
86 cal->white_level = white_level;
87 cal->white_count = 0;
88 cal->black_count = 0;
89 #ifdef TUNE_CALIBRATOR
90 cal->min_clip_count = cal->max_clip_count = 0;
91 #endif /* TUNE_CALIBRATOR */
92
93 cal->k_white = (unsigned int *) malloc (width * sizeof (unsigned int));
94 cal->k_black = (unsigned int *) malloc (width * sizeof (unsigned int));
95 cal->white_line = (double *) malloc (width * sizeof (double));
96 cal->black_line = (double *) malloc (width * sizeof (double));
97
98 if (!cal->k_white || !cal->k_black || !cal->white_line || !cal->black_line)
99 {
100 DBG (5, "gt68xx_calibrator_new: no memory for calibration data\n");
101 gt68xx_calibrator_free (cal);
102 return SANE_STATUS_NO_MEM;
103 }
104
105 for (i = 0; i < width; ++i)
106 {
107 cal->k_white[i] = 0;
108 cal->k_black[i] = 0;
109 cal->white_line[i] = 0.0;
110 cal->black_line[i] = 0.0;
111 }
112
113 *cal_return = cal;
114 DBG (5, "gt68xx_calibrator_new: leave: ok\n");
115 return SANE_STATUS_GOOD;
116 }
117
118 SANE_Status
gt68xx_calibrator_free(GT68xx_Calibrator * cal)119 gt68xx_calibrator_free (GT68xx_Calibrator * cal)
120 {
121 DBG (5, "gt68xx_calibrator_free: enter\n");
122
123 if (!cal)
124 {
125 DBG (5, "gt68xx_calibrator_free: cal==NULL\n");
126 return SANE_STATUS_INVAL;
127 }
128
129 #ifdef TUNE_CALIBRATOR
130 DBG (4, "gt68xx_calibrator_free: min_clip_count=%d, max_clip_count=%d\n",
131 cal->min_clip_count, cal->max_clip_count);
132 #endif /* TUNE_CALIBRATOR */
133
134 if (cal->k_white)
135 {
136 free (cal->k_white);
137 cal->k_white = NULL;
138 }
139
140 if (cal->k_black)
141 {
142 free (cal->k_black);
143 cal->k_black = NULL;
144 }
145
146 if (cal->white_line)
147 {
148 free (cal->white_line);
149 cal->white_line = NULL;
150 }
151
152 if (cal->black_line)
153 {
154 free (cal->black_line);
155 cal->black_line = NULL;
156 }
157
158 free (cal);
159
160 DBG (5, "gt68xx_calibrator_free: leave: ok\n");
161 return SANE_STATUS_GOOD;
162 }
163
164 SANE_Status
gt68xx_calibrator_add_white_line(GT68xx_Calibrator * cal,unsigned int * line)165 gt68xx_calibrator_add_white_line (GT68xx_Calibrator * cal, unsigned int *line)
166 {
167 SANE_Int i;
168 SANE_Int width = cal->width;
169
170 SANE_Int sum = 0;
171
172 cal->white_count++;
173
174 for (i = 0; i < width; ++i)
175 {
176 cal->white_line[i] += line[i];
177 sum += line[i];
178 #ifdef SAVE_WHITE_CALIBRATION
179 printf ("%c", line[i] >> 8);
180 #endif
181 }
182 if (sum / width / 256 < 0x50)
183 DBG (1,
184 "gt68xx_calibrator_add_white_line: WARNING: dark calibration line: "
185 "%2d medium white: 0x%02x\n", cal->white_count - 1,
186 sum / width / 256);
187 else
188 DBG (5,
189 "gt68xx_calibrator_add_white_line: line: %2d medium white: 0x%02x\n",
190 cal->white_count - 1, sum / width / 256);
191
192 return SANE_STATUS_GOOD;
193 }
194
195 SANE_Status
gt68xx_calibrator_eval_white(GT68xx_Calibrator * cal,double factor)196 gt68xx_calibrator_eval_white (GT68xx_Calibrator * cal, double factor)
197 {
198 SANE_Int i;
199 SANE_Int width = cal->width;
200
201 for (i = 0; i < width; ++i)
202 {
203 cal->white_line[i] = cal->white_line[i] / cal->white_count * factor;
204 }
205
206 return SANE_STATUS_GOOD;
207 }
208
209 SANE_Status
gt68xx_calibrator_add_black_line(GT68xx_Calibrator * cal,unsigned int * line)210 gt68xx_calibrator_add_black_line (GT68xx_Calibrator * cal, unsigned int *line)
211 {
212 SANE_Int i;
213 SANE_Int width = cal->width;
214
215 SANE_Int sum = 0;
216
217 cal->black_count++;
218
219 for (i = 0; i < width; ++i)
220 {
221 cal->black_line[i] += line[i];
222 sum += line[i];
223 #ifdef SAVE_BLACK_CALIBRATION
224 printf ("%c", line[i] >> 8);
225 #endif
226 }
227
228 DBG (5,
229 "gt68xx_calibrator_add_black_line: line: %2d medium black: 0x%02x\n",
230 cal->black_count - 1, sum / width / 256);
231 return SANE_STATUS_GOOD;
232 }
233
234 SANE_Status
gt68xx_calibrator_eval_black(GT68xx_Calibrator * cal,double factor)235 gt68xx_calibrator_eval_black (GT68xx_Calibrator * cal, double factor)
236 {
237 SANE_Int i;
238 SANE_Int width = cal->width;
239
240 for (i = 0; i < width; ++i)
241 {
242 cal->black_line[i] = cal->black_line[i] / cal->black_count - factor;
243 }
244
245 return SANE_STATUS_GOOD;
246 }
247
248 SANE_Status
gt68xx_calibrator_finish_setup(GT68xx_Calibrator * cal)249 gt68xx_calibrator_finish_setup (GT68xx_Calibrator * cal)
250 {
251 #ifdef TUNE_CALIBRATOR
252 double ave_black = 0.0;
253 double ave_diff = 0.0;
254 #endif /* TUNE_CALIBRATOR */
255 int i;
256 int width = cal->width;
257 unsigned int max_value = 65535;
258
259 for (i = 0; i < width; ++i)
260 {
261 unsigned int white = cal->white_line[i];
262 unsigned int black = cal->black_line[i];
263 unsigned int diff = (white > black) ? white - black : 1;
264 if (diff > max_value)
265 diff = max_value;
266 cal->k_white[i] = diff;
267 cal->k_black[i] = black;
268 #ifdef TUNE_CALIBRATOR
269 ave_black += black;
270 ave_diff += diff;
271 #endif /* TUNE_CALIBRATOR */
272 }
273
274 #ifdef TUNE_CALIBRATOR
275 ave_black /= width;
276 ave_diff /= width;
277 DBG (4, "gt68xx_calibrator_finish_setup: ave_black=%f, ave_diff=%f\n",
278 ave_black, ave_diff);
279 #endif /* TUNE_CALIBRATOR */
280
281 return SANE_STATUS_GOOD;
282 }
283
284 SANE_Status
gt68xx_calibrator_process_line(GT68xx_Calibrator * cal,unsigned int * line)285 gt68xx_calibrator_process_line (GT68xx_Calibrator * cal, unsigned int *line)
286 {
287 int i;
288 int width = cal->width;
289 unsigned int white_level = cal->white_level;
290
291 for (i = 0; i < width; ++i)
292 {
293 unsigned int src_value = line[i];
294 unsigned int black = cal->k_black[i];
295 unsigned int value;
296
297 if (src_value > black)
298 {
299 value = (src_value - black) * white_level / cal->k_white[i];
300 if (value > 0xffff)
301 {
302 value = 0xffff;
303 #ifdef TUNE_CALIBRATOR
304 cal->max_clip_count++;
305 #endif /* TUNE_CALIBRATOR */
306 }
307 }
308 else
309 {
310 value = 0;
311 #ifdef TUNE_CALIBRATOR
312 if (src_value < black)
313 cal->min_clip_count++;
314 #endif /* TUNE_CALIBRATOR */
315 }
316
317 line[i] = value;
318 }
319
320 return SANE_STATUS_GOOD;
321 }
322
323 SANE_Status
gt68xx_scanner_new(GT68xx_Device * dev,GT68xx_Scanner ** scanner_return)324 gt68xx_scanner_new (GT68xx_Device * dev, GT68xx_Scanner ** scanner_return)
325 {
326 GT68xx_Scanner *scanner;
327 int i;
328
329 *scanner_return = NULL;
330
331 scanner = (GT68xx_Scanner *) malloc (sizeof (GT68xx_Scanner));
332 if (!scanner)
333 {
334 DBG (5, "gt68xx_scanner_new: no memory for GT68xx_Scanner\n");
335 return SANE_STATUS_NO_MEM;
336 }
337
338 scanner->dev = dev;
339 scanner->reader = NULL;
340 scanner->cal_gray = NULL;
341 scanner->cal_r = NULL;
342 scanner->cal_g = NULL;
343 scanner->cal_b = NULL;
344
345 for(i=0;i<MAX_RESOLUTIONS;i++)
346 {
347 scanner->calibrations[i].dpi = 0;
348 scanner->calibrations[i].red = NULL;
349 scanner->calibrations[i].green = NULL;
350 scanner->calibrations[i].blue = NULL;
351 scanner->calibrations[i].gray = NULL;
352 }
353
354 *scanner_return = scanner;
355 return SANE_STATUS_GOOD;
356 }
357
358 static void
gt68xx_scanner_free_calibrators(GT68xx_Scanner * scanner)359 gt68xx_scanner_free_calibrators (GT68xx_Scanner * scanner)
360 {
361 if (scanner->cal_gray)
362 {
363 gt68xx_calibrator_free (scanner->cal_gray);
364 scanner->cal_gray = NULL;
365 }
366
367 if (scanner->cal_r)
368 {
369 gt68xx_calibrator_free (scanner->cal_r);
370 scanner->cal_r = NULL;
371 }
372
373 if (scanner->cal_g)
374 {
375 gt68xx_calibrator_free (scanner->cal_g);
376 scanner->cal_g = NULL;
377 }
378
379 if (scanner->cal_b)
380 {
381 gt68xx_calibrator_free (scanner->cal_b);
382 scanner->cal_b = NULL;
383 }
384 }
385
386 SANE_Status
gt68xx_scanner_free(GT68xx_Scanner * scanner)387 gt68xx_scanner_free (GT68xx_Scanner * scanner)
388 {
389 int i;
390
391 if (!scanner)
392 {
393 DBG (5, "gt68xx_scanner_free: scanner==NULL\n");
394 return SANE_STATUS_INVAL;
395 }
396
397 if (scanner->reader)
398 {
399 gt68xx_line_reader_free (scanner->reader);
400 scanner->reader = NULL;
401 }
402
403 gt68xx_scanner_free_calibrators (scanner);
404
405 /* free in memory calibration data */
406 for (i = 0; i < MAX_RESOLUTIONS; i++)
407 {
408 scanner->calibrations[i].dpi = 0;
409 if (scanner->calibrations[i].red != NULL)
410 {
411 gt68xx_calibrator_free (scanner->calibrations[i].red);
412 }
413 if (scanner->calibrations[i].green != NULL)
414 {
415 gt68xx_calibrator_free (scanner->calibrations[i].green);
416 }
417 if (scanner->calibrations[i].blue != NULL)
418 {
419 gt68xx_calibrator_free (scanner->calibrations[i].blue);
420 }
421 if (scanner->calibrations[i].gray != NULL)
422 {
423 gt68xx_calibrator_free (scanner->calibrations[i].gray);
424 }
425 }
426
427 free (scanner);
428
429 return SANE_STATUS_GOOD;
430 }
431
432 static SANE_Status
gt68xx_scanner_wait_for_positioning(GT68xx_Scanner * scanner)433 gt68xx_scanner_wait_for_positioning (GT68xx_Scanner * scanner)
434 {
435 SANE_Status status;
436 SANE_Bool moving;
437 SANE_Int status_count = 0;
438
439 usleep (100000); /* needed by the BP 2400 CU Plus? */
440 while (SANE_TRUE)
441 {
442 status = gt68xx_device_is_moving (scanner->dev, &moving);
443 if (status == SANE_STATUS_GOOD)
444 {
445 if (!moving)
446 break;
447 }
448 else
449 {
450 if (status_count > 9)
451 {
452 DBG (1, "gt68xx_scanner_wait_for_positioning: error count too high!\n");
453 return status;
454 }
455 status_count++;
456 DBG(3, "gt68xx_scanner_wait_for_positioning: ignored error\n");
457 }
458 usleep (100000);
459 }
460
461 return SANE_STATUS_GOOD;
462 }
463
464
465 static SANE_Status
gt68xx_scanner_internal_start_scan(GT68xx_Scanner * scanner)466 gt68xx_scanner_internal_start_scan (GT68xx_Scanner * scanner)
467 {
468 SANE_Status status;
469 SANE_Bool ready;
470 SANE_Int repeat_count;
471
472 status = gt68xx_scanner_wait_for_positioning (scanner);
473 if (status != SANE_STATUS_GOOD)
474 {
475 DBG (5,
476 "gt68xx_scanner_internal_start_scan: gt68xx_scanner_wait_for_positioning error: %s\n",
477 sane_strstatus (status));
478 return status;
479 }
480
481 status = gt68xx_device_start_scan (scanner->dev);
482 if (status != SANE_STATUS_GOOD)
483 {
484 DBG (5,
485 "gt68xx_scanner_internal_start_scan: gt68xx_device_start_scan error: %s\n",
486 sane_strstatus (status));
487 return status;
488 }
489
490 for (repeat_count = 0; repeat_count < 30 * 100; ++repeat_count)
491 {
492 status = gt68xx_device_read_scanned_data (scanner->dev, &ready);
493 if (status != SANE_STATUS_GOOD)
494 {
495 DBG (5,
496 "gt68xx_scanner_internal_start_scan: gt68xx_device_read_scanned_data error: %s\n",
497 sane_strstatus (status));
498 return status;
499 }
500 if (ready)
501 break;
502 usleep (10000);
503 }
504 if (!ready)
505 {
506 DBG (5,
507 "gt68xx_scanner_internal_start_scan: scanner still not ready - giving up\n");
508 return SANE_STATUS_DEVICE_BUSY;
509 }
510
511 status = gt68xx_device_read_start (scanner->dev);
512 if (status != SANE_STATUS_GOOD)
513 {
514 DBG (5,
515 "gt68xx_scanner_internal_start_scan: gt68xx_device_read_start error: %s\n",
516 sane_strstatus (status));
517 return status;
518 }
519
520 return SANE_STATUS_GOOD;
521 }
522
523 static SANE_Status
gt68xx_scanner_start_scan_extended(GT68xx_Scanner * scanner,GT68xx_Scan_Request * request,GT68xx_Scan_Action action,GT68xx_Scan_Parameters * params)524 gt68xx_scanner_start_scan_extended (GT68xx_Scanner * scanner,
525 GT68xx_Scan_Request * request,
526 GT68xx_Scan_Action action,
527 GT68xx_Scan_Parameters * params)
528 {
529 SANE_Status status;
530 GT68xx_AFE_Parameters afe = *scanner->dev->afe;
531
532 status = gt68xx_scanner_wait_for_positioning (scanner);
533 if (status != SANE_STATUS_GOOD)
534 {
535 DBG (5,
536 "gt68xx_scanner_start_scan_extended: gt68xx_scanner_wait_for_positioning error: %s\n",
537 sane_strstatus (status));
538 return status;
539 }
540
541 status = gt68xx_device_setup_scan (scanner->dev, request, action, params);
542 if (status != SANE_STATUS_GOOD)
543 {
544 DBG (5,
545 "gt68xx_scanner_start_scan_extended: gt68xx_device_setup_scan failed: %s\n",
546 sane_strstatus (status));
547 return status;
548 }
549
550 status = gt68xx_line_reader_new (scanner->dev, params,
551 action == SA_SCAN ? SANE_TRUE : SANE_FALSE,
552 &scanner->reader);
553 if (status != SANE_STATUS_GOOD)
554 {
555 DBG (5,
556 "gt68xx_scanner_start_scan_extended: gt68xx_line_reader_new failed: %s\n",
557 sane_strstatus (status));
558 return status;
559 }
560
561 if (scanner->dev->model->is_cis
562 && !((scanner->dev->model->flags & GT68XX_FLAG_SHEET_FED) && scanner->calibrated == SANE_FALSE))
563 {
564 status =
565 gt68xx_device_set_exposure_time (scanner->dev,
566 scanner->dev->exposure);
567 if (status != SANE_STATUS_GOOD)
568 {
569 DBG (5,
570 "gt68xx_scanner_start_scan_extended: gt68xx_device_set_exposure_time failed: %s\n",
571 sane_strstatus (status));
572 return status;
573 }
574 }
575
576 status = gt68xx_device_set_afe (scanner->dev, &afe);
577 if (status != SANE_STATUS_GOOD)
578 {
579 DBG (5,
580 "gt68xx_scanner_start_scan_extended: gt68xx_device_set_afe failed: %s\n",
581 sane_strstatus (status));
582 return status;
583 }
584
585 status = gt68xx_scanner_internal_start_scan (scanner);
586
587 if (status != SANE_STATUS_GOOD)
588 {
589 DBG (5,
590 "gt68xx_scanner_start_scan_extended: gt68xx_scanner_internal_start_scan failed: %s\n",
591 sane_strstatus (status));
592 return status;
593 }
594
595 return SANE_STATUS_GOOD;
596 }
597
598 static SANE_Status
gt68xx_scanner_create_calibrator(GT68xx_Scan_Parameters * params,GT68xx_Calibrator ** cal_return)599 gt68xx_scanner_create_calibrator (GT68xx_Scan_Parameters * params,
600 GT68xx_Calibrator ** cal_return)
601 {
602 return gt68xx_calibrator_new (params->pixel_xs, 65535, cal_return);
603 }
604
605 static SANE_Status
gt68xx_scanner_create_color_calibrators(GT68xx_Scanner * scanner,GT68xx_Scan_Parameters * params)606 gt68xx_scanner_create_color_calibrators (GT68xx_Scanner * scanner,
607 GT68xx_Scan_Parameters * params)
608 {
609 SANE_Status status;
610
611 if (!scanner->cal_r)
612 {
613 status = gt68xx_scanner_create_calibrator (params, &scanner->cal_r);
614 if (status != SANE_STATUS_GOOD)
615 return status;
616 }
617 if (!scanner->cal_g)
618 {
619 status = gt68xx_scanner_create_calibrator (params, &scanner->cal_g);
620 if (status != SANE_STATUS_GOOD)
621 return status;
622 }
623 if (!scanner->cal_b)
624 {
625 status = gt68xx_scanner_create_calibrator (params, &scanner->cal_b);
626 if (status != SANE_STATUS_GOOD)
627 return status;
628 }
629
630 return SANE_STATUS_GOOD;
631 }
632
633 static SANE_Status
gt68xx_scanner_create_gray_calibrators(GT68xx_Scanner * scanner,GT68xx_Scan_Parameters * params)634 gt68xx_scanner_create_gray_calibrators (GT68xx_Scanner * scanner,
635 GT68xx_Scan_Parameters * params)
636 {
637 SANE_Status status;
638
639 if (!scanner->cal_gray)
640 {
641 status = gt68xx_scanner_create_calibrator (params, &scanner->cal_gray);
642 if (status != SANE_STATUS_GOOD)
643 return status;
644 }
645
646 return SANE_STATUS_GOOD;
647 }
648
649 static SANE_Status
gt68xx_scanner_calibrate_color_white_line(GT68xx_Scanner * scanner,unsigned int ** buffer_pointers)650 gt68xx_scanner_calibrate_color_white_line (GT68xx_Scanner * scanner,
651 unsigned int **buffer_pointers)
652 {
653
654 gt68xx_calibrator_add_white_line (scanner->cal_r, buffer_pointers[0]);
655 gt68xx_calibrator_add_white_line (scanner->cal_g, buffer_pointers[1]);
656 gt68xx_calibrator_add_white_line (scanner->cal_b, buffer_pointers[2]);
657
658 return SANE_STATUS_GOOD;
659 }
660
661 static SANE_Status
gt68xx_scanner_calibrate_gray_white_line(GT68xx_Scanner * scanner,unsigned int ** buffer_pointers)662 gt68xx_scanner_calibrate_gray_white_line (GT68xx_Scanner * scanner,
663 unsigned int **buffer_pointers)
664 {
665 gt68xx_calibrator_add_white_line (scanner->cal_gray, buffer_pointers[0]);
666 return SANE_STATUS_GOOD;
667 }
668
669 static SANE_Status
gt68xx_scanner_calibrate_color_black_line(GT68xx_Scanner * scanner,unsigned int ** buffer_pointers)670 gt68xx_scanner_calibrate_color_black_line (GT68xx_Scanner * scanner,
671 unsigned int **buffer_pointers)
672 {
673 gt68xx_calibrator_add_black_line (scanner->cal_r, buffer_pointers[0]);
674 gt68xx_calibrator_add_black_line (scanner->cal_g, buffer_pointers[1]);
675 gt68xx_calibrator_add_black_line (scanner->cal_b, buffer_pointers[2]);
676
677 return SANE_STATUS_GOOD;
678 }
679
680 static SANE_Status
gt68xx_scanner_calibrate_gray_black_line(GT68xx_Scanner * scanner,unsigned int ** buffer_pointers)681 gt68xx_scanner_calibrate_gray_black_line (GT68xx_Scanner * scanner,
682 unsigned int **buffer_pointers)
683 {
684 gt68xx_calibrator_add_black_line (scanner->cal_gray, buffer_pointers[0]);
685 return SANE_STATUS_GOOD;
686 }
687
688 SANE_Status
gt68xx_scanner_calibrate(GT68xx_Scanner * scanner,GT68xx_Scan_Request * request)689 gt68xx_scanner_calibrate (GT68xx_Scanner * scanner,
690 GT68xx_Scan_Request * request)
691 {
692 SANE_Status status;
693 GT68xx_Scan_Parameters params;
694 GT68xx_Scan_Request req;
695 SANE_Int i;
696 unsigned int *buffer_pointers[3];
697 GT68xx_AFE_Parameters *afe = scanner->dev->afe;
698 GT68xx_Exposure_Parameters *exposure = scanner->dev->exposure;
699
700 memcpy (&req, request, sizeof (req));
701
702 gt68xx_scanner_free_calibrators (scanner);
703
704 if (scanner->auto_afe)
705 {
706 if (scanner->dev->model->is_cis)
707 status = gt68xx_afe_cis_auto (scanner);
708 else
709 status = gt68xx_afe_ccd_auto (scanner, request);
710
711 if (status != SANE_STATUS_GOOD)
712 {
713 DBG (5, "gt68xx_scanner_calibrate: gt68xx_afe_*_auto failed: %s\n",
714 sane_strstatus (status));
715 return status;
716 }
717 req.mbs = SANE_FALSE;
718 }
719 else
720 req.mbs = SANE_TRUE;
721
722 DBG (3, "afe 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", afe->r_offset,
723 afe->r_pga, afe->g_offset, afe->g_pga, afe->b_offset, afe->b_pga);
724 DBG (3, "exposure 0x%02x 0x%02x 0x%02x\n", exposure->r_time,
725 exposure->g_time, exposure->b_time);
726
727 if (!scanner->calib)
728 return SANE_STATUS_GOOD;
729
730 req.mds = SANE_TRUE;
731 req.mas = SANE_FALSE;
732
733 if (scanner->dev->model->is_cis && !(scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
734 req.color = SANE_TRUE;
735
736 if (req.use_ta)
737 {
738 req.lamp = SANE_FALSE;
739 status =
740 gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
741 }
742 else
743 {
744 req.lamp = SANE_TRUE;
745 status =
746 gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
747 }
748
749 status = gt68xx_scanner_start_scan_extended (scanner, &req, SA_CALIBRATE,
750 ¶ms);
751 if (status != SANE_STATUS_GOOD)
752 {
753 DBG (5,
754 "gt68xx_scanner_calibrate: gt68xx_scanner_start_scan_extended failed: %s\n",
755 sane_strstatus (status));
756 return status;
757 }
758
759 if (params.color)
760 {
761 status = gt68xx_scanner_create_color_calibrators (scanner, ¶ms);
762 }
763 else
764 {
765 status = gt68xx_scanner_create_gray_calibrators (scanner, ¶ms);
766 }
767
768 #if defined(SAVE_WHITE_CALIBRATION) || defined(SAVE_BLACK_CALIBRATION)
769 printf ("P5\n%d %d\n255\n", params.pixel_xs, params.pixel_ys * 3);
770 #endif
771 for (i = 0; i < params.pixel_ys; ++i)
772 {
773 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
774 if (status != SANE_STATUS_GOOD)
775 {
776 DBG (5,
777 "gt68xx_scanner_calibrate: gt68xx_line_reader_read failed: %s\n",
778 sane_strstatus (status));
779 return status;
780 }
781
782 if (params.color)
783 status = gt68xx_scanner_calibrate_color_white_line (scanner,
784 buffer_pointers);
785 else
786 status = gt68xx_scanner_calibrate_gray_white_line (scanner,
787 buffer_pointers);
788
789 if (status != SANE_STATUS_GOOD)
790 {
791 DBG (5, "gt68xx_scanner_calibrate: calibration failed: %s\n",
792 sane_strstatus (status));
793 return status;
794 }
795 }
796 gt68xx_scanner_stop_scan (scanner);
797
798 if (params.color)
799 {
800 gt68xx_calibrator_eval_white (scanner->cal_r, 1);
801 gt68xx_calibrator_eval_white (scanner->cal_g, 1);
802 gt68xx_calibrator_eval_white (scanner->cal_b, 1);
803 }
804 else
805 {
806 gt68xx_calibrator_eval_white (scanner->cal_gray, 1);
807 }
808
809 req.mbs = SANE_FALSE;
810 req.mds = SANE_FALSE;
811 req.mas = SANE_FALSE;
812 req.lamp = SANE_FALSE;
813
814 status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_FALSE);
815 if (status != SANE_STATUS_GOOD)
816 {
817 DBG (5,
818 "gt68xx_scanner_calibrate: gt68xx_device_lamp_control failed: %s\n",
819 sane_strstatus (status));
820 return status;
821 }
822
823 if (!scanner->dev->model->is_cis
824 || (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
825 usleep (500000);
826 status = gt68xx_scanner_start_scan_extended (scanner, &req, SA_CALIBRATE,
827 ¶ms);
828 if (status != SANE_STATUS_GOOD)
829 {
830 DBG (5,
831 "gt68xx_scanner_calibrate: gt68xx_scanner_start_scan_extended failed: %s\n",
832 sane_strstatus (status));
833 return status;
834 }
835
836 for (i = 0; i < params.pixel_ys; ++i)
837 {
838 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
839 if (status != SANE_STATUS_GOOD)
840 {
841 DBG (5,
842 "gt68xx_scanner_calibrate: gt68xx_line_reader_read failed: %s\n",
843 sane_strstatus (status));
844 return status;
845 }
846
847 if (params.color)
848 status = gt68xx_scanner_calibrate_color_black_line (scanner,
849 buffer_pointers);
850 else
851 status = gt68xx_scanner_calibrate_gray_black_line (scanner,
852 buffer_pointers);
853
854 if (status != SANE_STATUS_GOOD)
855 {
856 DBG (5, "gt68xx_scanner_calibrate: calibration failed: %s\n",
857 sane_strstatus (status));
858 return status;
859 }
860 }
861 gt68xx_scanner_stop_scan (scanner);
862
863 if (req.use_ta)
864 status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
865 else
866 status = gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
867
868 if (status != SANE_STATUS_GOOD)
869 {
870 DBG (5,
871 "gt68xx_scanner_calibrate: gt68xx_device_lamp_control failed: %s\n",
872 sane_strstatus (status));
873 return status;
874 }
875
876 if (!scanner->dev->model->is_cis)
877 usleep (500000);
878
879 if (params.color)
880 {
881 gt68xx_calibrator_eval_black (scanner->cal_r, 0.0);
882 gt68xx_calibrator_eval_black (scanner->cal_g, 0.0);
883 gt68xx_calibrator_eval_black (scanner->cal_b, 0.0);
884
885 gt68xx_calibrator_finish_setup (scanner->cal_r);
886 gt68xx_calibrator_finish_setup (scanner->cal_g);
887 gt68xx_calibrator_finish_setup (scanner->cal_b);
888 }
889 else
890 {
891 gt68xx_calibrator_eval_black (scanner->cal_gray, 0.0);
892 gt68xx_calibrator_finish_setup (scanner->cal_gray);
893 }
894
895 return SANE_STATUS_GOOD;
896 }
897
898 SANE_Status
gt68xx_scanner_start_scan(GT68xx_Scanner * scanner,GT68xx_Scan_Request * request,GT68xx_Scan_Parameters * params)899 gt68xx_scanner_start_scan (GT68xx_Scanner * scanner,
900 GT68xx_Scan_Request * request,
901 GT68xx_Scan_Parameters * params)
902 {
903 request->mbs = SANE_FALSE; /* don't go home before real scan */
904 request->mds = SANE_TRUE;
905 request->mas = SANE_FALSE;
906 if (request->use_ta)
907 {
908 gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
909 request->lamp = SANE_FALSE;
910 }
911 else
912 {
913 gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
914 request->lamp = SANE_TRUE;
915 }
916 if (!scanner->dev->model->is_cis)
917 sleep (2);
918
919 return gt68xx_scanner_start_scan_extended (scanner, request, SA_SCAN,
920 params);
921 }
922
923 SANE_Status
gt68xx_scanner_read_line(GT68xx_Scanner * scanner,unsigned int ** buffer_pointers)924 gt68xx_scanner_read_line (GT68xx_Scanner * scanner,
925 unsigned int **buffer_pointers)
926 {
927 SANE_Status status;
928
929 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
930
931 if (status != SANE_STATUS_GOOD)
932 {
933 DBG (5,
934 "gt68xx_scanner_read_line: gt68xx_line_reader_read failed: %s\n",
935 sane_strstatus (status));
936 return status;
937 }
938
939 if (scanner->calib)
940 {
941 if (scanner->reader->params.color)
942 {
943 gt68xx_calibrator_process_line (scanner->cal_r, buffer_pointers[0]);
944 gt68xx_calibrator_process_line (scanner->cal_g, buffer_pointers[1]);
945 gt68xx_calibrator_process_line (scanner->cal_b, buffer_pointers[2]);
946 }
947 else
948 {
949 if (scanner->dev->model->is_cis && !(scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
950 {
951 if (strcmp
952 (scanner->val[OPT_GRAY_MODE_COLOR].s,
953 GT68XX_COLOR_BLUE) == 0)
954 gt68xx_calibrator_process_line (scanner->cal_b,
955 buffer_pointers[0]);
956 else
957 if (strcmp
958 (scanner->val[OPT_GRAY_MODE_COLOR].s,
959 GT68XX_COLOR_GREEN) == 0)
960 gt68xx_calibrator_process_line (scanner->cal_g,
961 buffer_pointers[0]);
962 else
963 gt68xx_calibrator_process_line (scanner->cal_r,
964 buffer_pointers[0]);
965 }
966 else
967 {
968 gt68xx_calibrator_process_line (scanner->cal_gray,
969 buffer_pointers[0]);
970 }
971 }
972 }
973
974 return SANE_STATUS_GOOD;
975 }
976
977 SANE_Status
gt68xx_scanner_stop_scan(GT68xx_Scanner * scanner)978 gt68xx_scanner_stop_scan (GT68xx_Scanner * scanner)
979 {
980 if (scanner->reader)
981 {
982 gt68xx_line_reader_free (scanner->reader);
983 scanner->reader = NULL;
984 }
985 return gt68xx_device_stop_scan (scanner->dev);
986 }
987
988 /************************************************************************/
989 /* */
990 /* AFE offset/gain automatic configuration */
991 /* */
992 /************************************************************************/
993
994 typedef struct GT68xx_Afe_Values GT68xx_Afe_Values;
995
996 struct GT68xx_Afe_Values
997 {
998 SANE_Int black; /* minimum black (0-255) */
999 SANE_Int white; /* maximum white (0-255) */
1000 SANE_Int total_white; /* average white of the complete line (0-65536) */
1001 SANE_Int calwidth;
1002 SANE_Int callines;
1003 SANE_Int max_width;
1004 SANE_Int scan_dpi;
1005 SANE_Fixed start_black;
1006 SANE_Int offset_direction;
1007 SANE_Int coarse_black;
1008 SANE_Int coarse_white;
1009 };
1010
1011
1012 /************************************************************************/
1013 /* CCD scanners */
1014 /************************************************************************/
1015
1016 /** Calculate average black and maximum white
1017 *
1018 * This function is used for CCD scanners. The black mark to the left is used
1019 * for the calculation of average black. The remaining calibration strip
1020 * is used for searching the segment whose white average is the highest.
1021 *
1022 * @param values AFE values
1023 * @param buffer scanned line
1024 */
1025 static void
gt68xx_afe_ccd_calc(GT68xx_Afe_Values * values,unsigned int * buffer)1026 gt68xx_afe_ccd_calc (GT68xx_Afe_Values * values, unsigned int *buffer)
1027 {
1028 SANE_Int start_black;
1029 SANE_Int end_black;
1030 SANE_Int start_white;
1031 SANE_Int end_white;
1032 SANE_Int i;
1033 SANE_Int max_black = 0;
1034 SANE_Int min_black = 255;
1035 SANE_Int max_white = 0;
1036 SANE_Int total_white = 0;
1037
1038 /* set size of black mark and white segments */
1039 start_black =
1040 SANE_UNFIX (values->start_black) * values->scan_dpi / MM_PER_INCH;
1041 end_black = start_black + 1.0 * values->scan_dpi / MM_PER_INCH; /* 1 mm */
1042
1043 /* 5mm after mark */
1044 start_white = end_black + 5.0 * values->scan_dpi / MM_PER_INCH;
1045 end_white = values->calwidth;
1046
1047 DBG (5,
1048 "gt68xx_afe_ccd_calc: dpi=%d, start_black=%d, end_black=%d, start_white=%d, end_white=%d\n",
1049 values->scan_dpi, start_black, end_black, start_white, end_white);
1050
1051 /* calc min and max black value */
1052 for (i = start_black; i < end_black; i++)
1053 {
1054 if ((SANE_Int) (buffer[i] >> 8) < min_black)
1055 min_black = (buffer[i] >> 8);
1056 if ((SANE_Int) (buffer[i] >> 8) > max_black)
1057 max_black = (buffer[i] >> 8);
1058 #ifdef DEBUG_BLACK
1059 if ((buffer[i] >> 8) > 15)
1060 fprintf (stderr, "+");
1061 else if ((buffer[i] >> 8) < 5)
1062 fprintf (stderr, "-");
1063 else
1064 fprintf (stderr, "_");
1065 #endif
1066 }
1067 #ifdef DEBUG_BLACK
1068 fprintf (stderr, "\n");
1069 #endif
1070
1071 for (i = start_white; i < end_white; ++i)
1072 {
1073 if ((SANE_Int) (buffer[i] >> 8) > max_white)
1074 max_white = (buffer[i] >> 8);
1075 total_white += buffer[i];
1076 }
1077 values->total_white = total_white / (end_white - start_white);
1078
1079 values->black = min_black;
1080 values->white = max_white;
1081 if (values->white < 50 || values->black > 150
1082 || values->white - values->black < 30 || max_black - min_black > 15)
1083 DBG (1,
1084 "gt68xx_afe_ccd_calc: WARNING: max_white %3d min_black %3d max_black %3d\n",
1085 values->white, values->black, max_black);
1086 else
1087 DBG (5,
1088 "gt68xx_afe_ccd_calc: max_white %3d min_black %3d max_black %3d\n",
1089 values->white, values->black, max_black);
1090 }
1091
1092 static SANE_Bool
gt68xx_afe_ccd_adjust_offset_gain(SANE_String_Const color_name,GT68xx_Afe_Values * values,unsigned int * buffer,SANE_Byte * offset,SANE_Byte * pga,SANE_Byte * old_offset,SANE_Byte * old_pga)1093 gt68xx_afe_ccd_adjust_offset_gain (SANE_String_Const color_name,
1094 GT68xx_Afe_Values * values,
1095 unsigned int *buffer, SANE_Byte * offset,
1096 SANE_Byte * pga, SANE_Byte * old_offset,
1097 SANE_Byte * old_pga)
1098 {
1099 SANE_Int black_low = values->coarse_black, black_high = black_low + 10;
1100 SANE_Int white_high = values->coarse_white, white_low = white_high - 10;
1101 SANE_Bool done = SANE_TRUE;
1102 SANE_Byte local_pga = *pga;
1103 SANE_Byte local_offset = *offset;
1104
1105 gt68xx_afe_ccd_calc (values, buffer);
1106
1107 #if 0
1108 /* test all offset values */
1109 local_offset++;
1110 done = SANE_FALSE;
1111 goto finish;
1112 #endif
1113
1114 if (values->white > white_high)
1115 {
1116 if (values->black > black_high)
1117 local_offset += values->offset_direction;
1118 else if (values->black < black_low)
1119 local_pga--;
1120 else
1121 {
1122 local_offset += values->offset_direction;
1123 local_pga--;
1124 }
1125 done = SANE_FALSE;
1126 goto finish;
1127 }
1128 else if (values->white < white_low)
1129 {
1130 if (values->black < black_low)
1131 local_offset -= values->offset_direction;
1132 else if (values->black > black_high)
1133 local_pga++;
1134 else
1135 {
1136 local_offset -= values->offset_direction;
1137 local_pga++;
1138 }
1139 done = SANE_FALSE;
1140 goto finish;
1141 }
1142 if (values->black > black_high)
1143 {
1144 if (values->white > white_high)
1145 local_offset += values->offset_direction;
1146 else if (values->white < white_low)
1147 local_pga++;
1148 else
1149 {
1150 local_offset += values->offset_direction;
1151 local_pga++;
1152 }
1153 done = SANE_FALSE;
1154 goto finish;
1155 }
1156 else if (values->black < black_low)
1157 {
1158 if (values->white < white_low)
1159 local_offset -= values->offset_direction;
1160 else if (values->white > white_high)
1161 local_pga--;
1162 else
1163 {
1164 local_offset -= values->offset_direction;
1165 local_pga--;
1166 }
1167 done = SANE_FALSE;
1168 goto finish;
1169 }
1170 finish:
1171 if ((local_pga == *pga) && (local_offset == *offset))
1172 done = SANE_TRUE;
1173 if ((local_pga == *old_pga) && (local_offset == *old_offset))
1174 done = SANE_TRUE;
1175
1176 *old_pga = *pga;
1177 *old_offset = *offset;
1178
1179 DBG (4, "%5s white=%3d, black=%3d, offset=%2d, gain=%2d, old offs=%2d, "
1180 "old gain=%2d, total_white=%5d %s\n", color_name, values->white,
1181 values->black, local_offset, local_pga, *offset, *pga,
1182 values->total_white, done ? "DONE " : "");
1183
1184 *pga = local_pga;
1185 *offset = local_offset;
1186
1187 return done;
1188 }
1189
1190 /* Wait for lamp to give stable brightness */
1191 static SANE_Status
gt68xx_wait_lamp_stable(GT68xx_Scanner * scanner,GT68xx_Scan_Parameters * params,GT68xx_Scan_Request * request,unsigned int * buffer_pointers[3],GT68xx_Afe_Values * values,SANE_Bool dont_move)1192 gt68xx_wait_lamp_stable (GT68xx_Scanner * scanner,
1193 GT68xx_Scan_Parameters * params,
1194 GT68xx_Scan_Request *request,
1195 unsigned int *buffer_pointers[3],
1196 GT68xx_Afe_Values *values,
1197 SANE_Bool dont_move)
1198 {
1199 SANE_Status status = SANE_STATUS_GOOD;
1200 SANE_Int last_white = 0;
1201 SANE_Bool first = SANE_TRUE;
1202 SANE_Bool message_printed = SANE_FALSE;
1203 struct timeval now, start_time;
1204 int secs_lamp_on, secs_start;
1205 int increase = -5;
1206
1207 gettimeofday (&start_time, 0);
1208 do
1209 {
1210 usleep (200000);
1211
1212 if (!first && dont_move)
1213 {
1214 request->mbs = SANE_FALSE;
1215 request->mds = SANE_FALSE;
1216 }
1217 first = SANE_FALSE;
1218
1219 /* read line */
1220 status = gt68xx_scanner_start_scan_extended (scanner, request,
1221 SA_CALIBRATE_ONE_LINE,
1222 params);
1223 if (status != SANE_STATUS_GOOD)
1224 {
1225 DBG (3,
1226 "gt68xx_wait_lamp_stable: gt68xx_scanner_start_scan_extended "
1227 "failed: %s\n", sane_strstatus (status));
1228 return status;
1229 }
1230 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1231 if (status != SANE_STATUS_GOOD)
1232 {
1233 DBG (3, "gt68xx_wait_lamp_stable: gt68xx_line_reader_read failed: %s\n",
1234 sane_strstatus (status));
1235 return status;
1236 }
1237 gt68xx_scanner_stop_scan (scanner);
1238
1239 gt68xx_afe_ccd_calc (values, buffer_pointers[0]);
1240
1241 DBG (4,
1242 "gt68xx_wait_lamp_stable: this white = %d, last white = %d\n",
1243 values->total_white, last_white);
1244
1245 gettimeofday (&now, 0);
1246 secs_lamp_on = now.tv_sec - scanner->lamp_on_time.tv_sec;
1247 secs_start = now.tv_sec - start_time.tv_sec;
1248
1249 if (!message_printed && secs_start > 5)
1250 {
1251 DBG (0, "Please wait for lamp warm-up\n");
1252 message_printed = SANE_TRUE;
1253 }
1254
1255 if (scanner->val[OPT_AUTO_WARMUP].w == SANE_TRUE)
1256 {
1257 if (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP)
1258 {
1259 if (values->total_white <= (last_white - 20))
1260 increase--;
1261 if (values->total_white >= last_white)
1262 increase++;
1263 if (increase > 0 && (values->total_white <= (last_white + 20))
1264 && values->total_white != 0)
1265 break;
1266 }
1267 else
1268 {
1269 if ((values->total_white <= (last_white + 20))
1270 && values->total_white != 0)
1271 break; /* lamp is warmed up */
1272 }
1273 }
1274 last_white = values->total_white;
1275 }
1276 while (secs_lamp_on <= WARMUP_TIME);
1277
1278 DBG (3, "gt68xx_wait_lamp_stable: Lamp is stable after %d secs (%d secs total)\n",
1279 secs_start, secs_lamp_on);
1280 return status;
1281 }
1282
1283 /** Select best AFE gain and offset parameters.
1284 *
1285 * This function must be called before the main scan to choose the best values
1286 * for the AFE gains and offsets. It performs several one-line scans of the
1287 * calibration strip.
1288 *
1289 * @param scanner Scanner object.
1290 * @param orig_request Scan parameters.
1291 *
1292 * @returns
1293 * - #SANE_STATUS_GOOD - gain and offset setting completed successfully
1294 * - other error value - failure of some internal function
1295 */
1296 static SANE_Status
gt68xx_afe_ccd_auto(GT68xx_Scanner * scanner,GT68xx_Scan_Request * orig_request)1297 gt68xx_afe_ccd_auto (GT68xx_Scanner * scanner,
1298 GT68xx_Scan_Request * orig_request)
1299 {
1300 SANE_Status status;
1301 GT68xx_Scan_Parameters params;
1302 GT68xx_Scan_Request request;
1303 int i;
1304 GT68xx_Afe_Values values;
1305 unsigned int *buffer_pointers[3];
1306 GT68xx_AFE_Parameters *afe = scanner->dev->afe, old_afe;
1307 SANE_Bool gray_done = SANE_FALSE;
1308 SANE_Bool red_done = SANE_FALSE, green_done = SANE_FALSE, blue_done =
1309 SANE_FALSE;
1310
1311 values.offset_direction = 1;
1312 if (scanner->dev->model->flags & GT68XX_FLAG_OFFSET_INV)
1313 values.offset_direction = -1;
1314
1315 memset (&old_afe, 255, sizeof (old_afe));
1316
1317 request.x0 = SANE_FIX (0.0);
1318 request.xs = scanner->dev->model->x_size;
1319 request.xdpi = 300;
1320 request.ydpi = 300;
1321 request.depth = 8;
1322 request.color = orig_request->color;
1323 /* request.color = SANE_TRUE; */
1324 request.mas = SANE_FALSE;
1325 request.mbs = SANE_FALSE;
1326 request.mds = SANE_TRUE;
1327 request.calculate = SANE_FALSE;
1328 request.use_ta = orig_request->use_ta;
1329
1330 if (orig_request->use_ta)
1331 {
1332 gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
1333 request.lamp = SANE_FALSE;
1334 }
1335 else
1336 {
1337 gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
1338 request.lamp = SANE_TRUE;
1339 }
1340
1341 /* read line */
1342 status = gt68xx_scanner_start_scan_extended (scanner, &request,
1343 SA_CALIBRATE_ONE_LINE,
1344 ¶ms);
1345 if (status != SANE_STATUS_GOOD)
1346 {
1347 DBG (3,
1348 "gt68xx_afe_ccd_auto: gt68xx_scanner_start_scan_extended failed: %s\n",
1349 sane_strstatus (status));
1350 return status;
1351 }
1352 values.scan_dpi = params.xdpi;
1353 values.calwidth = params.pixel_xs;
1354 values.max_width =
1355 (params.pixel_xs * scanner->dev->model->optical_xdpi) / params.xdpi;
1356 if (orig_request->use_ta)
1357 values.start_black = SANE_FIX (20.0);
1358 else
1359 values.start_black = scanner->dev->model->x_offset_mark;
1360 values.coarse_black = 1;
1361 values.coarse_white = 254;
1362
1363 request.mds = SANE_FALSE;
1364 DBG (5, "gt68xx_afe_ccd_auto: scan_dpi=%d, calwidth=%d, max_width=%d, "
1365 "start_black=%.1f mm\n", values.scan_dpi,
1366 values.calwidth, values.max_width, SANE_UNFIX (values.start_black));
1367
1368 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1369 if (status != SANE_STATUS_GOOD)
1370 {
1371 DBG (3, "gt68xx_afe_ccd_auto: gt68xx_line_reader_read failed: %s\n",
1372 sane_strstatus (status));
1373 return status;
1374 }
1375 gt68xx_scanner_stop_scan (scanner);
1376
1377 status = gt68xx_wait_lamp_stable (scanner, ¶ms, &request, buffer_pointers,
1378 &values, SANE_FALSE);
1379
1380 if (status != SANE_STATUS_GOOD)
1381 {
1382 DBG (1, "gt68xx_afe_ccd_auto: gt68xx_wait_lamp_stable failed %s\n",
1383 sane_strstatus (status));
1384 return status;
1385 }
1386
1387 i = 0;
1388 do
1389 {
1390 i++;
1391 /* read line */
1392 status = gt68xx_scanner_start_scan_extended (scanner, &request,
1393 SA_CALIBRATE_ONE_LINE,
1394 ¶ms);
1395 if (status != SANE_STATUS_GOOD)
1396 {
1397 DBG (3,
1398 "gt68xx_afe_ccd_auto: gt68xx_scanner_start_scan_extended failed: %s\n",
1399 sane_strstatus (status));
1400 return status;
1401 }
1402
1403 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1404 if (status != SANE_STATUS_GOOD)
1405 {
1406 DBG (3, "gt68xx_afe_ccd_auto: gt68xx_line_reader_read failed: %s\n",
1407 sane_strstatus (status));
1408 return status;
1409 }
1410
1411 if (params.color)
1412 {
1413 /* red */
1414 if (!red_done)
1415 red_done =
1416 gt68xx_afe_ccd_adjust_offset_gain ("red", &values,
1417 buffer_pointers[0],
1418 &afe->r_offset, &afe->r_pga,
1419 &old_afe.r_offset,
1420 &old_afe.r_pga);
1421 /* green */
1422 if (!green_done)
1423 green_done =
1424 gt68xx_afe_ccd_adjust_offset_gain ("green", &values,
1425 buffer_pointers[1],
1426 &afe->g_offset, &afe->g_pga,
1427 &old_afe.g_offset,
1428 &old_afe.g_pga);
1429
1430 /* blue */
1431 if (!blue_done)
1432 blue_done =
1433 gt68xx_afe_ccd_adjust_offset_gain ("blue", &values,
1434 buffer_pointers[2],
1435 &afe->b_offset, &afe->b_pga,
1436 &old_afe.b_offset,
1437 &old_afe.b_pga);
1438 }
1439 else
1440 {
1441 if (strcmp (scanner->val[OPT_GRAY_MODE_COLOR].s, GT68XX_COLOR_BLUE)
1442 == 0)
1443 {
1444 gray_done =
1445 gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1446 buffer_pointers[0],
1447 &afe->b_offset,
1448 &afe->b_pga,
1449 &old_afe.b_offset,
1450 &old_afe.b_pga);
1451 }
1452 else
1453 if (strcmp
1454 (scanner->val[OPT_GRAY_MODE_COLOR].s,
1455 GT68XX_COLOR_GREEN) == 0)
1456 {
1457 gray_done =
1458 gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1459 buffer_pointers[0],
1460 &afe->g_offset,
1461 &afe->g_pga,
1462 &old_afe.g_offset,
1463 &old_afe.g_pga);
1464 afe->r_offset = afe->b_offset = 0x20;
1465 afe->r_pga = afe->b_pga = 0x18;
1466 }
1467 else
1468 {
1469 gray_done =
1470 gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1471 buffer_pointers[0],
1472 &afe->r_offset,
1473 &afe->r_pga,
1474 &old_afe.r_offset,
1475 &old_afe.r_pga);
1476 }
1477 }
1478 gt68xx_scanner_stop_scan (scanner);
1479 }
1480 while (((params.color && (!red_done || !green_done || !blue_done))
1481 || (!params.color && !gray_done)) && i < 100);
1482
1483 return status;
1484 }
1485
1486 /************************************************************************/
1487 /* CIS scanners */
1488 /************************************************************************/
1489
1490
1491 static void
gt68xx_afe_cis_calc_black(GT68xx_Afe_Values * values,unsigned int * black_buffer)1492 gt68xx_afe_cis_calc_black (GT68xx_Afe_Values * values,
1493 unsigned int *black_buffer)
1494 {
1495 SANE_Int start_black;
1496 SANE_Int end_black;
1497 SANE_Int i, j;
1498 SANE_Int min_black = 255;
1499 SANE_Int average = 0;
1500
1501 start_black = 0;
1502 end_black = values->calwidth;
1503
1504 /* find min average black value */
1505 for (i = start_black; i < end_black; ++i)
1506 {
1507 SANE_Int avg_black = 0;
1508 for (j = 0; j < values->callines; j++)
1509 avg_black += (*(black_buffer + i + j * values->calwidth) >> 8);
1510 avg_black /= values->callines;
1511 average += avg_black;
1512 if (avg_black < min_black)
1513 min_black = avg_black;
1514 }
1515 values->black = min_black;
1516 average /= (end_black - start_black);
1517 DBG (5,
1518 "gt68xx_afe_cis_calc_black: min_black=0x%02x, average_black=0x%02x\n",
1519 values->black, average);
1520 }
1521
1522 static void
gt68xx_afe_cis_calc_white(GT68xx_Afe_Values * values,unsigned int * white_buffer)1523 gt68xx_afe_cis_calc_white (GT68xx_Afe_Values * values,
1524 unsigned int *white_buffer)
1525 {
1526 SANE_Int start_white;
1527 SANE_Int end_white;
1528 SANE_Int i, j;
1529 SANE_Int max_white = 0;
1530
1531 start_white = 0;
1532 end_white = values->calwidth;
1533 values->total_white = 0;
1534
1535 /* find max average white value */
1536 for (i = start_white; i < end_white; ++i)
1537 {
1538 SANE_Int avg_white = 0;
1539 for (j = 0; j < values->callines; j++)
1540 {
1541 avg_white += (*(white_buffer + i + j * values->calwidth) >> 8);
1542 values->total_white += (*(white_buffer + i + j * values->calwidth));
1543 }
1544 avg_white /= values->callines;
1545 if (avg_white > max_white)
1546 max_white = avg_white;
1547 }
1548 values->white = max_white;
1549 values->total_white /= (values->callines * (end_white - start_white));
1550 DBG (5,
1551 "gt68xx_afe_cis_calc_white: max_white=0x%02x, average_white=0x%02x\n",
1552 values->white, values->total_white >> 8);
1553 }
1554
1555 static SANE_Bool
gt68xx_afe_cis_adjust_gain_offset(SANE_String_Const color_name,GT68xx_Afe_Values * values,unsigned int * black_buffer,unsigned int * white_buffer,GT68xx_AFE_Parameters * afe,GT68xx_AFE_Parameters * old_afe)1556 gt68xx_afe_cis_adjust_gain_offset (SANE_String_Const color_name,
1557 GT68xx_Afe_Values * values,
1558 unsigned int *black_buffer,
1559 unsigned int *white_buffer,
1560 GT68xx_AFE_Parameters * afe,
1561 GT68xx_AFE_Parameters * old_afe)
1562 {
1563 SANE_Byte *offset, *old_offset, *gain, *old_gain;
1564 SANE_Int o, g;
1565 SANE_Int black_low = values->coarse_black, black_high = black_low + 10;
1566 SANE_Int white_high = values->coarse_white, white_low = white_high - 10;
1567 SANE_Bool done = SANE_TRUE;
1568
1569 gt68xx_afe_cis_calc_black (values, black_buffer);
1570 gt68xx_afe_cis_calc_white (values, white_buffer);
1571
1572 if (strcmp (color_name, "red") == 0)
1573 {
1574 offset = &(afe->r_offset);
1575 old_offset = &old_afe->r_offset;
1576 gain = &afe->r_pga;
1577 old_gain = &old_afe->r_pga;
1578 }
1579 else if (strcmp (color_name, "green") == 0)
1580 {
1581 offset = &afe->g_offset;
1582 old_offset = &old_afe->g_offset;
1583 gain = &afe->g_pga;
1584 old_gain = &old_afe->g_pga;
1585 }
1586 else
1587 {
1588 offset = &afe->b_offset;
1589 old_offset = &old_afe->b_offset;
1590 gain = &afe->b_pga;
1591 old_gain = &old_afe->b_pga;
1592 }
1593
1594 o = *offset;
1595 g = *gain;
1596
1597 if (values->white > white_high)
1598 {
1599 if (values->black > black_high)
1600 o -= values->offset_direction;
1601 else if (values->black < black_low)
1602 g--;
1603 else
1604 {
1605 o -= values->offset_direction;
1606 g--;
1607 }
1608 done = SANE_FALSE;
1609 goto finish;
1610 }
1611 else if (values->white < white_low)
1612 {
1613 if (values->black < black_low)
1614 o += values->offset_direction;
1615 else if (values->black > black_high)
1616 g++;
1617 else
1618 {
1619 o += values->offset_direction;
1620 g++;
1621 }
1622 done = SANE_FALSE;
1623 goto finish;
1624 }
1625 if (values->black > black_high)
1626 {
1627 if (values->white > white_high)
1628 o -= values->offset_direction;
1629 else if (values->white < white_low)
1630 g++;
1631 else
1632 {
1633 o -= values->offset_direction;
1634 g++;
1635 }
1636 done = SANE_FALSE;
1637 goto finish;
1638 }
1639 else if (values->black < black_low)
1640 {
1641 if (values->white < white_low)
1642 o += values->offset_direction;
1643 else if (values->white > white_high)
1644 g--;
1645 else
1646 {
1647 o += values->offset_direction;
1648 g--;
1649 }
1650 done = SANE_FALSE;
1651 goto finish;
1652 }
1653 finish:
1654 if (g < 0)
1655 g = 0;
1656 if (g > 48)
1657 g = 48;
1658 if (o < 0)
1659 o = 0;
1660 if (o > 64)
1661 o = 64;
1662
1663 if ((g == *gain) && (o == *offset))
1664 done = SANE_TRUE;
1665 if ((g == *old_gain) && (o == *old_offset))
1666 done = SANE_TRUE;
1667
1668 *old_gain = *gain;
1669 *old_offset = *offset;
1670
1671 DBG (4, "%5s white=%3d, black=%3d, offset=0x%02X, gain=0x%02X, old offs=0x%02X, "
1672 "old gain=0x%02X, total_white=%5d %s\n", color_name, values->white,
1673 values->black, o, g, *offset, *gain, values->total_white,
1674 done ? "DONE " : "");
1675
1676 *gain = g;
1677 *offset = o;
1678
1679 return done;
1680 }
1681
1682
1683 static SANE_Bool
gt68xx_afe_cis_adjust_exposure(SANE_String_Const color_name,GT68xx_Afe_Values * values,unsigned int * white_buffer,SANE_Int border,SANE_Int * exposure_time)1684 gt68xx_afe_cis_adjust_exposure (SANE_String_Const color_name,
1685 GT68xx_Afe_Values * values,
1686 unsigned int *white_buffer, SANE_Int border,
1687 SANE_Int * exposure_time)
1688 {
1689 SANE_Int exposure_change = 0;
1690
1691 gt68xx_afe_cis_calc_white (values, white_buffer);
1692
1693 if (values->white < border)
1694 {
1695 exposure_change = ((border - values->white) * 1);
1696 (*exposure_time) += exposure_change;
1697 DBG (4,
1698 "%5s: white = %3d, total_white=%5d (exposure too low) --> exposure += %d (=0x%03x)\n",
1699 color_name, values->white, values->total_white, exposure_change, *exposure_time);
1700 return SANE_FALSE;
1701 }
1702 else if (values->white > border + 5)
1703 {
1704 exposure_change = -((values->white - (border + 5)) * 1);
1705 (*exposure_time) += exposure_change;
1706 DBG (4,
1707 "%5s: white = %3d, total_white=%5d (exposure too high) --> exposure -= %d (=0x%03x)\n",
1708 color_name, values->white, values->total_white, exposure_change, *exposure_time);
1709 return SANE_FALSE;
1710 }
1711 else
1712 {
1713 DBG (4, "%5s: white = %3d, total_white=%5d (exposure ok=0x%03x)\n",
1714 color_name, values->white, values->total_white, *exposure_time);
1715 }
1716 return SANE_TRUE;
1717 }
1718
1719 static SANE_Status
gt68xx_afe_cis_read_lines(GT68xx_Afe_Values * values,GT68xx_Scanner * scanner,SANE_Bool lamp,SANE_Bool first,unsigned int * r_buffer,unsigned int * g_buffer,unsigned int * b_buffer)1720 gt68xx_afe_cis_read_lines (GT68xx_Afe_Values * values,
1721 GT68xx_Scanner * scanner, SANE_Bool lamp,
1722 SANE_Bool first, unsigned int *r_buffer,
1723 unsigned int *g_buffer, unsigned int *b_buffer)
1724 {
1725 SANE_Status status;
1726 int line;
1727 unsigned int *buffer_pointers[3];
1728 GT68xx_Scan_Request request;
1729 GT68xx_Scan_Parameters params;
1730
1731 request.x0 = SANE_FIX (0.0);
1732 request.xs = scanner->dev->model->x_size;
1733 request.xdpi = 300;
1734 request.ydpi = 300;
1735 request.depth = 8;
1736 request.color = SANE_TRUE;
1737 request.mas = SANE_FALSE;
1738 request.calculate = SANE_FALSE;
1739 request.use_ta = SANE_FALSE;
1740
1741 if (first) /* go to start position */
1742 {
1743 request.mbs = SANE_TRUE;
1744 request.mds = SANE_TRUE;
1745 }
1746 else
1747 {
1748 request.mbs = SANE_FALSE;
1749 request.mds = SANE_FALSE;
1750 }
1751 request.lamp = lamp;
1752
1753 if (!r_buffer) /* First, set the size parameters */
1754 {
1755 request.calculate = SANE_TRUE;
1756 RIE (gt68xx_device_setup_scan
1757 (scanner->dev, &request, SA_CALIBRATE_ONE_LINE, ¶ms));
1758 values->scan_dpi = params.xdpi;
1759 values->calwidth = params.pixel_xs;
1760 values->callines = params.pixel_ys;
1761 values->start_black = scanner->dev->model->x_offset_mark;
1762 return SANE_STATUS_GOOD;
1763 }
1764
1765 if (first && (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
1766 {
1767 if (request.use_ta)
1768 {
1769 gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
1770 request.lamp = SANE_FALSE;
1771 }
1772 else
1773 {
1774 gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
1775 request.lamp = SANE_TRUE;
1776 }
1777 status = gt68xx_wait_lamp_stable (scanner, ¶ms, &request,
1778 buffer_pointers, values, SANE_TRUE);
1779 if (status != SANE_STATUS_GOOD)
1780 {
1781 DBG (1, "gt68xx_afe_cis_read_lines: gt68xx_wait_lamp_stable failed %s\n",
1782 sane_strstatus (status));
1783 return status;
1784 }
1785 request.mbs = SANE_FALSE;
1786 request.mds = SANE_FALSE;
1787 }
1788
1789 status =
1790 gt68xx_scanner_start_scan_extended (scanner, &request,
1791 SA_CALIBRATE_ONE_LINE, ¶ms);
1792 if (status != SANE_STATUS_GOOD)
1793 {
1794 DBG (5,
1795 "gt68xx_afe_cis_read_lines: gt68xx_scanner_start_scan_extended failed: %s\n",
1796 sane_strstatus (status));
1797 return status;
1798 }
1799 values->scan_dpi = params.xdpi;
1800 values->calwidth = params.pixel_xs;
1801 values->callines = params.pixel_ys;
1802 values->coarse_black = 2;
1803 values->coarse_white = 253;
1804
1805 if (r_buffer && g_buffer && b_buffer)
1806 for (line = 0; line < values->callines; line++)
1807 {
1808 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1809 if (status != SANE_STATUS_GOOD)
1810 {
1811 DBG (5,
1812 "gt68xx_afe_cis_read_lines: gt68xx_line_reader_read failed: %s\n",
1813 sane_strstatus (status));
1814 return status;
1815 }
1816 memcpy (r_buffer + values->calwidth * line, buffer_pointers[0],
1817 values->calwidth * sizeof (unsigned int));
1818 memcpy (g_buffer + values->calwidth * line, buffer_pointers[1],
1819 values->calwidth * sizeof (unsigned int));
1820 memcpy (b_buffer + values->calwidth * line, buffer_pointers[2],
1821 values->calwidth * sizeof (unsigned int));
1822 }
1823
1824 status = gt68xx_scanner_stop_scan (scanner);
1825 if (status != SANE_STATUS_GOOD)
1826 {
1827 DBG (5,
1828 "gt68xx_afe_cis_read_lines: gt68xx_scanner_stop_scan failed: %s\n",
1829 sane_strstatus (status));
1830 return status;
1831 }
1832
1833 return SANE_STATUS_GOOD;
1834 }
1835
1836 static SANE_Status
gt68xx_afe_cis_auto(GT68xx_Scanner * scanner)1837 gt68xx_afe_cis_auto (GT68xx_Scanner * scanner)
1838 {
1839 SANE_Status status;
1840 int total_count, exposure_count;
1841 GT68xx_Afe_Values values;
1842 GT68xx_AFE_Parameters *afe = scanner->dev->afe, old_afe;
1843 GT68xx_Exposure_Parameters *exposure = scanner->dev->exposure;
1844 SANE_Int red_done, green_done, blue_done;
1845 SANE_Bool first = SANE_TRUE;
1846 unsigned int *r_gbuffer = 0, *g_gbuffer = 0, *b_gbuffer = 0;
1847 unsigned int *r_obuffer = 0, *g_obuffer = 0, *b_obuffer = 0;
1848
1849 DBG (5, "gt68xx_afe_cis_auto: start\n");
1850
1851 if (scanner->dev->model->flags & GT68XX_FLAG_NO_CALIBRATE)
1852 {
1853 return SANE_STATUS_GOOD;
1854 }
1855
1856 memset (&old_afe, 255, sizeof (old_afe));
1857
1858 /* Start with the preset exposure settings */
1859 memcpy (scanner->dev->exposure, &scanner->dev->model->exposure,
1860 sizeof (*scanner->dev->exposure));
1861
1862 RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_FALSE, SANE_FALSE,
1863 r_gbuffer, g_gbuffer, b_gbuffer));
1864
1865 r_gbuffer =
1866 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1867 g_gbuffer =
1868 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1869 b_gbuffer =
1870 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1871 r_obuffer =
1872 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1873 g_obuffer =
1874 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1875 b_obuffer =
1876 malloc (values.calwidth * values.callines * sizeof (unsigned int));
1877 if (!r_gbuffer || !g_gbuffer || !b_gbuffer || !r_obuffer || !g_obuffer
1878 || !b_obuffer)
1879 return SANE_STATUS_NO_MEM;
1880
1881 total_count = 0;
1882 red_done = green_done = blue_done = SANE_FALSE;
1883 old_afe.r_offset = old_afe.g_offset = old_afe.b_offset = 255;
1884 old_afe.r_pga = old_afe.g_pga = old_afe.b_pga = 255;
1885 do
1886 {
1887 values.offset_direction = 1;
1888 if (scanner->dev->model->flags & GT68XX_FLAG_OFFSET_INV)
1889 values.offset_direction = -1;
1890
1891 RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_FALSE, first,
1892 r_obuffer, g_obuffer, b_obuffer));
1893 RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_TRUE, SANE_FALSE,
1894 r_gbuffer, g_gbuffer, b_gbuffer));
1895
1896 if (!red_done)
1897 red_done =
1898 gt68xx_afe_cis_adjust_gain_offset ("red", &values, r_obuffer,
1899 r_gbuffer, afe, &old_afe);
1900 if (!green_done)
1901 green_done =
1902 gt68xx_afe_cis_adjust_gain_offset ("green", &values, g_obuffer,
1903 g_gbuffer, afe, &old_afe);
1904 if (!blue_done)
1905 blue_done =
1906 gt68xx_afe_cis_adjust_gain_offset ("blue", &values, b_obuffer,
1907 b_gbuffer, afe, &old_afe);
1908 total_count++;
1909 first = SANE_FALSE;
1910
1911 }
1912 while (total_count < 100 && (!red_done || !green_done || !blue_done));
1913
1914 if (!red_done || !green_done || !blue_done)
1915 DBG (0, "gt68xx_afe_cis_auto: setting AFE reached limit\n");
1916
1917 /* Exposure time */
1918 exposure_count = 0;
1919 red_done = green_done = blue_done = SANE_FALSE;
1920 do
1921 {
1922 /* read white line */
1923 RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_TRUE, SANE_FALSE,
1924 r_gbuffer, g_gbuffer, b_gbuffer));
1925 if (!red_done)
1926 red_done =
1927 gt68xx_afe_cis_adjust_exposure ("red", &values, r_gbuffer, 245,
1928 &exposure->r_time);
1929 if (!green_done)
1930 green_done =
1931 gt68xx_afe_cis_adjust_exposure ("green", &values, g_gbuffer, 245,
1932 &exposure->g_time);
1933 if (!blue_done)
1934 blue_done =
1935 gt68xx_afe_cis_adjust_exposure ("blue", &values, b_gbuffer, 245,
1936 &exposure->b_time);
1937 exposure_count++;
1938 total_count++;
1939 }
1940 while ((!red_done || !green_done || !blue_done) && exposure_count < 50);
1941
1942 if (!red_done || !green_done || !blue_done)
1943 DBG (0, "gt68xx_afe_cis_auto: setting exposure reached limit\n");
1944
1945 /* store afe calibration when needed */
1946 if(scanner->dev->model->flags & GT68XX_FLAG_HAS_CALIBRATE)
1947 {
1948 memcpy(&(scanner->afe_params), afe, sizeof(GT68xx_AFE_Parameters));
1949 scanner->exposure_params.r_time=exposure->r_time;
1950 scanner->exposure_params.g_time=exposure->g_time;
1951 scanner->exposure_params.b_time=exposure->b_time;
1952 }
1953
1954 free (r_gbuffer);
1955 free (g_gbuffer);
1956 free (b_gbuffer);
1957 free (r_obuffer);
1958 free (g_obuffer);
1959 free (b_obuffer);
1960 DBG (4, "gt68xx_afe_cis_auto: total_count: %d\n", total_count);
1961
1962 return SANE_STATUS_GOOD;
1963 }
1964
1965 /** @brief create and copy calibrator
1966 * Creates a calibrator of the given width and copy data from reference
1967 * to initialize it
1968 * @param calibator pointer to the calibrator to create
1969 * @param reference calibrator with reference data to copy
1970 * @param width the width in pixels of the calibrator
1971 * @param offset offset in pixels when copying data from reference
1972 * @return SANE_STATUS_GOOD and a filled calibrator if enough memory
1973 */
1974 static SANE_Status
gt68xx_calibrator_create_copy(GT68xx_Calibrator ** calibrator,GT68xx_Calibrator * reference,int width,int offset)1975 gt68xx_calibrator_create_copy (GT68xx_Calibrator ** calibrator,
1976 GT68xx_Calibrator * reference, int width,
1977 int offset)
1978 {
1979 SANE_Status status;
1980 int i;
1981
1982 if (reference == NULL)
1983 {
1984 DBG (1, "gt68xx_calibrator_create_copy: NULL reference, skipping...\n");
1985 *calibrator = NULL;
1986 return SANE_STATUS_GOOD;
1987 }
1988 /* check for reference overflow */
1989 if(width+offset>reference->width)
1990 {
1991 DBG (1, "gt68xx_calibrator_create_copy: required with and offset exceed reference width\n");
1992 return SANE_STATUS_INVAL;
1993 }
1994
1995 status = gt68xx_calibrator_new (width, 65535, calibrator);
1996 if (status != SANE_STATUS_GOOD)
1997 {
1998 DBG (1,
1999 "gt68xx_calibrator_create_copy: failed to create calibrator: %s\n",
2000 sane_strstatus (status));
2001 return status;
2002 }
2003
2004 for(i=0;i<width;i++)
2005 {
2006 (*calibrator)->k_white[i]=reference->k_white[i+offset];
2007 (*calibrator)->k_black[i]=reference->k_black[i+offset];
2008 (*calibrator)->white_line[i]=reference->white_line[i+offset];
2009 (*calibrator)->black_line[i]=reference->black_line[i+offset];
2010 }
2011
2012 return status;
2013 }
2014
2015 static SANE_Status
gt68xx_sheetfed_move_to_scan_area(GT68xx_Scanner * scanner,GT68xx_Scan_Request * request)2016 gt68xx_sheetfed_move_to_scan_area (GT68xx_Scanner * scanner,
2017 GT68xx_Scan_Request * request)
2018 {
2019 SANE_Status status;
2020
2021 if (!(scanner->dev->model->flags & GT68XX_FLAG_SHEET_FED)
2022 || scanner->dev->model->command_set->move_paper == NULL)
2023 return SANE_STATUS_GOOD;
2024
2025 /* send move paper command */
2026 RIE (scanner->dev->model->command_set->move_paper (scanner->dev, request));
2027
2028 /* wait until paper is set to the desired position */
2029 return gt68xx_scanner_wait_for_positioning (scanner);
2030 }
2031
2032 /**< number of consecutive white line to detect a white area */
2033 #define WHITE_LINES 2
2034
2035 /** @brief calibrate sheet fed scanner
2036 * This function calibrates sheet fed scanner by scanning a calibration
2037 * target (which may be a blank page). It first move to a white area then
2038 * does afe and exposure calibration. Then it scans white lines to get data
2039 * for shading correction.
2040 * @param scanner structure describing the frontend session and the device
2041 * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL
2042 * otherwise.
2043 */
2044 static SANE_Status
gt68xx_sheetfed_scanner_calibrate(GT68xx_Scanner * scanner)2045 gt68xx_sheetfed_scanner_calibrate (GT68xx_Scanner * scanner)
2046 {
2047 SANE_Status status;
2048 GT68xx_Scan_Request request;
2049 GT68xx_Scan_Parameters params;
2050 int count, i, x, y, white;
2051 unsigned int *buffer_pointers[3];
2052 #ifdef DEBUG_CALIBRATION
2053 FILE *fcal;
2054 char title[50];
2055 #endif
2056
2057 DBG (3, "gt68xx_sheetfed_scanner_calibrate: start.\n");
2058
2059 /* clear calibration if needed */
2060 gt68xx_scanner_free_calibrators (scanner);
2061 for (i = 0; i < MAX_RESOLUTIONS; i++)
2062 {
2063 if(scanner->calibrations[i].red!=NULL)
2064 {
2065 gt68xx_calibrator_free (scanner->calibrations[i].red);
2066 }
2067 if(scanner->calibrations[i].green!=NULL)
2068 {
2069 gt68xx_calibrator_free (scanner->calibrations[i].green);
2070 }
2071 if(scanner->calibrations[i].blue!=NULL)
2072 {
2073 gt68xx_calibrator_free (scanner->calibrations[i].blue);
2074 }
2075 if(scanner->calibrations[i].gray!=NULL)
2076 {
2077 gt68xx_calibrator_free (scanner->calibrations[i].gray);
2078 }
2079 }
2080 scanner->calibrated = SANE_FALSE;
2081
2082 /* find minimum horizontal resolution */
2083 request.xdpi = 9600;
2084 for (i = 0; scanner->dev->model->xdpi_values[i] != 0; i++)
2085 {
2086 if (scanner->dev->model->xdpi_values[i] < request.xdpi)
2087 {
2088 request.xdpi = scanner->dev->model->xdpi_values[i];
2089 request.ydpi = scanner->dev->model->xdpi_values[i];
2090 }
2091 }
2092
2093 /* move to white area SA_CALIBRATE uses its own y0/ys fixed values */
2094 request.x0 = 0;
2095 request.y0 = scanner->dev->model->y_offset_calib;
2096 request.xs = scanner->dev->model->x_size;
2097 request.depth = 8;
2098
2099 request.color = SANE_FALSE;
2100 request.mbs = SANE_TRUE;
2101 request.mds = SANE_TRUE;
2102 request.mas = SANE_FALSE;
2103 request.lamp = SANE_TRUE;
2104 request.calculate = SANE_FALSE;
2105 request.use_ta = SANE_FALSE;
2106 request.backtrack = SANE_FALSE;
2107 request.backtrack_lines = 0;
2108
2109 /* skip start of calibration sheet */
2110 status = gt68xx_sheetfed_move_to_scan_area (scanner, &request);
2111 if (status != SANE_STATUS_GOOD)
2112 {
2113 DBG (1,
2114 "gt68xx_sheetfed_scanner_calibrate: failed to skip start of calibration sheet %s\n",
2115 sane_strstatus (status));
2116 return status;
2117 }
2118
2119 status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
2120 if (status != SANE_STATUS_GOOD)
2121 {
2122 DBG (1,
2123 "gt68xx_sheetfed_scanner_calibrate: gt68xx_device_lamp_control returned %s\n",
2124 sane_strstatus (status));
2125 return status;
2126 }
2127
2128 /* loop until we find a white area to calibrate on */
2129 i = 0;
2130 request.y0 = 0;
2131 do
2132 {
2133 /* start scan */
2134 status =
2135 gt68xx_scanner_start_scan_extended (scanner, &request, SA_CALIBRATE,
2136 ¶ms);
2137 if (status != SANE_STATUS_GOOD)
2138 {
2139 DBG (1,
2140 "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_start_scan_extended returned %s\n",
2141 sane_strstatus (status));
2142 return status;
2143 }
2144
2145 /* loop until we find WHITE_LINES consecutive white lines or we reach and of area */
2146 white = 0;
2147 y = 0;
2148 do
2149 {
2150 status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
2151 if (status != SANE_STATUS_GOOD)
2152 {
2153 DBG (1,
2154 "gt68xx_sheetfed_scanner_calibrate: gt68xx_line_reader_read returned %s\n",
2155 sane_strstatus (status));
2156 gt68xx_scanner_stop_scan (scanner);
2157 return status;
2158 }
2159
2160 /* check for white line */
2161 count = 0;
2162 for (x = 0; x < params.pixel_xs; x++)
2163 {
2164 if (((buffer_pointers[0][x] >> 8) & 0xff) > 50)
2165 {
2166 count++;
2167 }
2168 }
2169
2170 /* line is white if 93% is above black level */
2171 if ((100 * count) / params.pixel_xs < 93)
2172 {
2173 white = 0;
2174 }
2175 else
2176 {
2177 white++;
2178 }
2179 y++;
2180 }
2181 while ((white < WHITE_LINES) && (y < params.pixel_ys));
2182
2183 /* end scan */
2184 gt68xx_scanner_stop_scan (scanner);
2185
2186 i++;
2187 }
2188 while (i < 20 && white < WHITE_LINES);
2189
2190 /* check if we found a white area */
2191 if (white != WHITE_LINES)
2192 {
2193 DBG (1,
2194 "gt68xx_sheetfed_scanner_calibrate: didn't find a white area\n");
2195 return SANE_STATUS_INVAL;
2196 }
2197
2198 /* now do calibration */
2199 scanner->auto_afe = SANE_TRUE;
2200 scanner->calib = SANE_TRUE;
2201
2202 /* loop at each possible xdpi to create calibrators */
2203 i = 0;
2204 while (scanner->dev->model->xdpi_values[i] > 0)
2205 {
2206 request.xdpi = scanner->dev->model->xdpi_values[i];
2207 request.ydpi = scanner->dev->model->xdpi_values[i];
2208 request.x0 = 0;
2209 request.y0 = 0;
2210 request.xs = scanner->dev->model->x_size;
2211 request.color = SANE_FALSE;
2212 request.mbs = SANE_FALSE;
2213 request.mds = SANE_TRUE;
2214 request.mas = SANE_FALSE;
2215 request.lamp = SANE_TRUE;
2216 request.calculate = SANE_FALSE;
2217 request.use_ta = SANE_FALSE;
2218 request.backtrack = SANE_FALSE;
2219 request.backtrack_lines = 0;
2220
2221 /* calibrate in color */
2222 request.color = SANE_TRUE;
2223 status = gt68xx_scanner_calibrate (scanner, &request);
2224 if (status != SANE_STATUS_GOOD)
2225 {
2226 DBG (1,
2227 "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_calibrate returned %s\n",
2228 sane_strstatus (status));
2229 return status;
2230 }
2231
2232 /* since auto afe is done at a fixed resolution, we don't need to
2233 * do each each time, once is enough */
2234 scanner->auto_afe = SANE_FALSE;
2235
2236 /* allocate and save per dpi calibrators */
2237 scanner->calibrations[i].dpi = request.xdpi;
2238
2239 /* recompute params */
2240 request.calculate = SANE_TRUE;
2241 gt68xx_device_setup_scan (scanner->dev, &request, SA_SCAN, ¶ms);
2242
2243 scanner->calibrations[i].pixel_x0 = params.pixel_x0;
2244 status =
2245 gt68xx_calibrator_create_copy (&(scanner->calibrations[i].red),
2246 scanner->cal_r, scanner->cal_r->width,
2247 0);
2248 if (status != SANE_STATUS_GOOD)
2249 {
2250 DBG (1,
2251 "gt68xx_sheetfed_scanner_calibrate: failed to create red calibrator: %s\n",
2252 sane_strstatus (status));
2253 return status;
2254 }
2255
2256 status =
2257 gt68xx_calibrator_create_copy (&(scanner->calibrations[i].green),
2258 scanner->cal_g, scanner->cal_g->width,
2259 0);
2260 if (status != SANE_STATUS_GOOD)
2261 {
2262 DBG (1,
2263 "gt68xx_sheetfed_scanner_calibrate: failed to create green calibrator: %s\n",
2264 sane_strstatus (status));
2265 return status;
2266 }
2267
2268 status =
2269 gt68xx_calibrator_create_copy (&(scanner->calibrations[i].blue),
2270 scanner->cal_b, scanner->cal_b->width,
2271 0);
2272 if (status != SANE_STATUS_GOOD)
2273 {
2274 DBG (1,
2275 "gt68xx_sheetfed_scanner_calibrate: failed to create blue calibrator: %s\n",
2276 sane_strstatus (status));
2277 return status;
2278 }
2279
2280 /* calibrate in gray */
2281 request.color = SANE_FALSE;
2282 status = gt68xx_scanner_calibrate (scanner, &request);
2283 if (status != SANE_STATUS_GOOD)
2284 {
2285 DBG (1,
2286 "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_calibrate returned %s\n",
2287 sane_strstatus (status));
2288 return status;
2289 }
2290
2291 if (scanner->cal_gray)
2292 {
2293 status =
2294 gt68xx_calibrator_create_copy (&(scanner->calibrations[i].gray),
2295 scanner->cal_gray,
2296 scanner->cal_gray->width, 0);
2297 if (status != SANE_STATUS_GOOD)
2298 {
2299 DBG (1,
2300 "gt68xx_sheetfed_scanner_calibrate: failed to create gray calibrator: %s\n",
2301 sane_strstatus (status));
2302 return status;
2303 }
2304 }
2305
2306 #ifdef DEBUG_CALIBRATION
2307 sprintf (title, "cal-%03d-red.pnm", scanner->calibrations[i].dpi);
2308 fcal = fopen (title, "wb");
2309 if (fcal != NULL)
2310 {
2311 fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2312 for (x = 0; x < params.pixel_xs; x++)
2313 fputc ((scanner->calibrations[i].red->k_white[x] >> 8) & 0xff,
2314 fcal);
2315 fclose (fcal);
2316 }
2317 sprintf (title, "cal-%03d-green.pnm", scanner->calibrations[i].dpi);
2318 fcal = fopen (title, "wb");
2319 if (fcal != NULL)
2320 {
2321 fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2322 for (x = 0; x < params.pixel_xs; x++)
2323 fputc ((scanner->calibrations[i].green->k_white[x] >> 8) & 0xff,
2324 fcal);
2325 fclose (fcal);
2326 }
2327 sprintf (title, "cal-%03d-blue.pnm", scanner->calibrations[i].dpi);
2328 fcal = fopen (title, "wb");
2329 if (fcal != NULL)
2330 {
2331 fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2332 for (x = 0; x < params.pixel_xs; x++)
2333 fputc ((scanner->calibrations[i].blue->k_white[x] >> 8) & 0xff,
2334 fcal);
2335 fclose (fcal);
2336 }
2337 #endif
2338
2339 /* next resolution */
2340 i++;
2341 }
2342
2343 scanner->calibrated = SANE_TRUE;
2344
2345 /* eject calibration target from feeder */
2346 gt68xx_device_paperfeed (scanner->dev);
2347
2348 /* save calibration to file */
2349 gt68xx_write_calibration (scanner);
2350
2351 DBG (3, "gt68xx_sheetfed_scanner_calibrate: end.\n");
2352 return SANE_STATUS_GOOD;
2353 }
2354
2355 /** @brief assign calibration for scan
2356 * This function creates the calibrators and set up afe for the requested
2357 * scan. It uses calibration data that has been created by
2358 * gt68xx_sheetfed_scanner_calibrate.
2359 * @param scanner structure describing the frontend session and the device
2360 * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL
2361 * otherwise.
2362 */
2363 static SANE_Status
gt68xx_assign_calibration(GT68xx_Scanner * scanner,GT68xx_Scan_Parameters params)2364 gt68xx_assign_calibration (GT68xx_Scanner * scanner,
2365 GT68xx_Scan_Parameters params)
2366 {
2367 int i, dpi, offset;
2368 SANE_Status status = SANE_STATUS_GOOD;
2369
2370 DBG (3, "gt68xx_assign_calibration: start.\n");
2371
2372 dpi = params.xdpi;
2373 DBG (4, "gt68xx_assign_calibration: searching calibration for %d dpi\n",
2374 dpi);
2375
2376 /* search matching dpi */
2377 i = 0;
2378 while (scanner->calibrations[i].dpi > 0
2379 && scanner->calibrations[i].dpi != dpi)
2380 {
2381 i++;
2382 }
2383
2384 /* check if found a match */
2385 if (scanner->calibrations[i].dpi == 0)
2386 {
2387 DBG (4,
2388 "gt68xx_assign_calibration: failed to find calibration for %d dpi\n",
2389 dpi);
2390 return SANE_STATUS_INVAL;
2391 }
2392 DBG (4, "gt68xx_assign_calibration: using entry %d for %d dpi\n", i, dpi);
2393
2394 DBG (5,
2395 "gt68xx_assign_calibration: using scan_parameters: pixel_x0=%d, pixel_xs=%d \n",
2396 params.pixel_x0, params.pixel_xs);
2397
2398 /* AFE/exposure data copy */
2399 memcpy (scanner->dev->afe, &(scanner->afe_params),
2400 sizeof (GT68xx_AFE_Parameters));
2401 scanner->dev->exposure->r_time = scanner->exposure_params.r_time;
2402 scanner->dev->exposure->g_time = scanner->exposure_params.g_time;
2403 scanner->dev->exposure->b_time = scanner->exposure_params.b_time;
2404
2405 /* free calibrators if needed */
2406 gt68xx_scanner_free_calibrators (scanner);
2407
2408 /* TODO compute offset based on the x0 value from scan_request */
2409 offset = params.pixel_x0 - scanner->calibrations[i].pixel_x0;
2410
2411 /* calibrator allocation and copy */
2412 if (scanner->calibrations[i].red!=NULL)
2413 {
2414 status =
2415 gt68xx_calibrator_create_copy (&(scanner->cal_r),
2416 scanner->calibrations[i].red,
2417 params.pixel_xs,
2418 offset);
2419 if (status != SANE_STATUS_GOOD)
2420 {
2421 DBG (1,
2422 "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2423 sane_strstatus (status));
2424 return status;
2425 }
2426 }
2427
2428 if (scanner->calibrations[i].green!=NULL)
2429 {
2430 status =
2431 gt68xx_calibrator_create_copy (&(scanner->cal_g),
2432 scanner->calibrations[i].green,
2433 params.pixel_xs,
2434 offset);
2435 if (status != SANE_STATUS_GOOD)
2436 {
2437 DBG (1,
2438 "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2439 sane_strstatus (status));
2440 return status;
2441 }
2442 }
2443
2444 if (scanner->calibrations[i].blue!=NULL)
2445 {
2446 status =
2447 gt68xx_calibrator_create_copy (&(scanner->cal_b),
2448 scanner->calibrations[i].blue,
2449 params.pixel_xs,
2450 offset);
2451 if (status != SANE_STATUS_GOOD)
2452 {
2453 DBG (1,
2454 "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2455 sane_strstatus (status));
2456 return status;
2457 }
2458 }
2459
2460 if (scanner->calibrations[i].gray!=NULL)
2461 {
2462 status =
2463 gt68xx_calibrator_create_copy (&(scanner->cal_gray),
2464 scanner->calibrations[i].gray,
2465 params.pixel_xs,
2466 offset);
2467 if (status != SANE_STATUS_GOOD)
2468 {
2469 DBG (1,
2470 "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2471 sane_strstatus (status));
2472 return status;
2473 }
2474 }
2475
2476 DBG (3, "gt68xx_assign_calibration: end.\n");
2477 return status;
2478 }
2479
gt68xx_calibration_file(GT68xx_Scanner * scanner)2480 static char *gt68xx_calibration_file(GT68xx_Scanner * scanner)
2481 {
2482 char *ptr=NULL;
2483 char tmp_str[PATH_MAX];
2484
2485 ptr=getenv("HOME");
2486 if(ptr!=NULL)
2487 {
2488 sprintf (tmp_str, "%s/.sane/gt68xx-%s.cal", ptr, scanner->dev->model->name);
2489 }
2490 else
2491 {
2492 ptr=getenv("TMPDIR");
2493 if(ptr!=NULL)
2494 {
2495 sprintf (tmp_str, "%s/gt68xx-%s.cal", ptr, scanner->dev->model->name);
2496 }
2497 else
2498 {
2499 sprintf (tmp_str, "/tmp/gt68xx-%s.cal", scanner->dev->model->name);
2500 }
2501 }
2502 DBG(5,"gt68xx_calibration_file: using >%s< for calibration file name\n",tmp_str);
2503 return strdup(tmp_str);
2504 }
2505
2506 static SANE_Status
gt68xx_clear_calibration(GT68xx_Scanner * scanner)2507 gt68xx_clear_calibration (GT68xx_Scanner * scanner)
2508 {
2509 char *fname;
2510 int i;
2511
2512 if (scanner->calibrated == SANE_FALSE)
2513 return SANE_STATUS_GOOD;
2514
2515 /* clear file */
2516 fname = gt68xx_calibration_file (scanner);
2517 unlink (fname);
2518 free (fname);
2519
2520 /* free calibrators */
2521 for (i = 0; i < MAX_RESOLUTIONS && scanner->calibrations[i].dpi > 0; i++)
2522 {
2523 scanner->calibrations[i].dpi = 0;
2524 if (scanner->calibrations[i].red)
2525 gt68xx_calibrator_free (scanner->calibrations[i].red);
2526 if (scanner->calibrations[i].green)
2527 gt68xx_calibrator_free (scanner->calibrations[i].green);
2528 if (scanner->calibrations[i].blue)
2529 gt68xx_calibrator_free (scanner->calibrations[i].blue);
2530 if (scanner->calibrations[i].gray)
2531 gt68xx_calibrator_free (scanner->calibrations[i].gray);
2532 }
2533
2534 /* reset flags */
2535 scanner->calibrated = SANE_FALSE;
2536 scanner->val[OPT_QUALITY_CAL].w = SANE_FALSE;
2537 scanner->val[OPT_NEED_CALIBRATION_SW].w = SANE_TRUE;
2538 DBG (5, "gt68xx_clear_calibration: done\n");
2539 return SANE_STATUS_GOOD;
2540 }
2541
2542 static SANE_Status
gt68xx_write_calibration(GT68xx_Scanner * scanner)2543 gt68xx_write_calibration (GT68xx_Scanner * scanner)
2544 {
2545 char *fname;
2546 FILE *fcal;
2547 int i;
2548 SANE_Int nullwidth = 0;
2549
2550 if (scanner->calibrated == SANE_FALSE)
2551 {
2552 return SANE_STATUS_GOOD;
2553 }
2554
2555 /* open file */
2556 fname = gt68xx_calibration_file (scanner);
2557 fcal = fopen (fname, "wb");
2558 free (fname);
2559 if (fcal == NULL)
2560 {
2561 DBG (1,
2562 "gt68xx_write_calibration: failed to open calibration file for writing %s\n",
2563 strerror (errno));
2564 return SANE_STATUS_IO_ERROR;
2565 }
2566
2567 /* TODO we save check endianness and word alignment in case of a home
2568 * directory used trough different archs */
2569 fwrite (&(scanner->afe_params), sizeof (GT68xx_AFE_Parameters), 1, fcal);
2570 fwrite (&(scanner->exposure_params), sizeof (GT68xx_Exposure_Parameters), 1,
2571 fcal);
2572 for (i = 0; i < MAX_RESOLUTIONS && scanner->calibrations[i].dpi > 0; i++)
2573 {
2574 DBG (1, "gt68xx_write_calibration: saving %d dpi calibration\n",
2575 scanner->calibrations[i].dpi);
2576 fwrite (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2577 fwrite (&(scanner->calibrations[i].pixel_x0), sizeof (SANE_Int), 1,
2578 fcal);
2579
2580 fwrite (&(scanner->calibrations[i].red->width), sizeof (SANE_Int), 1,
2581 fcal);
2582 fwrite (&(scanner->calibrations[i].red->white_level), sizeof (SANE_Int),
2583 1, fcal);
2584 fwrite (scanner->calibrations[i].red->k_white, sizeof (unsigned int),
2585 scanner->calibrations[i].red->width, fcal);
2586 fwrite (scanner->calibrations[i].red->k_black, sizeof (unsigned int),
2587 scanner->calibrations[i].red->width, fcal);
2588 fwrite (scanner->calibrations[i].red->white_line, sizeof (double),
2589 scanner->calibrations[i].red->width, fcal);
2590 fwrite (scanner->calibrations[i].red->black_line, sizeof (double),
2591 scanner->calibrations[i].red->width, fcal);
2592
2593 fwrite (&(scanner->calibrations[i].green->width), sizeof (SANE_Int), 1,
2594 fcal);
2595 fwrite (&(scanner->calibrations[i].green->white_level),
2596 sizeof (SANE_Int), 1, fcal);
2597 fwrite (scanner->calibrations[i].green->k_white, sizeof (unsigned int),
2598 scanner->calibrations[i].green->width, fcal);
2599 fwrite (scanner->calibrations[i].green->k_black, sizeof (unsigned int),
2600 scanner->calibrations[i].green->width, fcal);
2601 fwrite (scanner->calibrations[i].green->white_line, sizeof (double),
2602 scanner->calibrations[i].green->width, fcal);
2603 fwrite (scanner->calibrations[i].green->black_line, sizeof (double),
2604 scanner->calibrations[i].green->width, fcal);
2605
2606 fwrite (&(scanner->calibrations[i].blue->width), sizeof (SANE_Int), 1,
2607 fcal);
2608 fwrite (&(scanner->calibrations[i].blue->white_level),
2609 sizeof (SANE_Int), 1, fcal);
2610 fwrite (scanner->calibrations[i].blue->k_white, sizeof (unsigned int),
2611 scanner->calibrations[i].blue->width, fcal);
2612 fwrite (scanner->calibrations[i].blue->k_black, sizeof (unsigned int),
2613 scanner->calibrations[i].blue->width, fcal);
2614 fwrite (scanner->calibrations[i].blue->white_line, sizeof (double),
2615 scanner->calibrations[i].blue->width, fcal);
2616 fwrite (scanner->calibrations[i].blue->black_line, sizeof (double),
2617 scanner->calibrations[i].blue->width, fcal);
2618
2619 if (scanner->calibrations[i].gray != NULL)
2620 {
2621 fwrite (&(scanner->calibrations[i].gray->width), sizeof (SANE_Int),
2622 1, fcal);
2623 fwrite (&(scanner->calibrations[i].gray->white_level),
2624 sizeof (SANE_Int), 1, fcal);
2625 fwrite (scanner->calibrations[i].gray->k_white,
2626 sizeof (unsigned int), scanner->calibrations[i].gray->width,
2627 fcal);
2628 fwrite (scanner->calibrations[i].gray->k_black,
2629 sizeof (unsigned int), scanner->calibrations[i].gray->width,
2630 fcal);
2631 fwrite (scanner->calibrations[i].gray->white_line, sizeof (double),
2632 scanner->calibrations[i].gray->width, fcal);
2633 fwrite (scanner->calibrations[i].gray->black_line, sizeof (double),
2634 scanner->calibrations[i].gray->width, fcal);
2635 }
2636 else
2637 {
2638 fwrite (&nullwidth, sizeof (SANE_Int), 1, fcal);
2639 }
2640 }
2641 DBG (5, "gt68xx_write_calibration: wrote %d calibrations\n", i);
2642
2643 fclose (fcal);
2644 return SANE_STATUS_GOOD;
2645 }
2646
2647 static SANE_Status
gt68xx_read_calibration(GT68xx_Scanner * scanner)2648 gt68xx_read_calibration (GT68xx_Scanner * scanner)
2649 {
2650 char *fname;
2651 FILE *fcal;
2652 int i;
2653 SANE_Int width, level;
2654
2655 scanner->calibrated = SANE_FALSE;
2656 fname = gt68xx_calibration_file (scanner);
2657 fcal = fopen (fname, "rb");
2658 free (fname);
2659 if (fcal == NULL)
2660 {
2661 DBG (1,
2662 "gt68xx_read_calibration: failed to open calibration file for reading %s\n",
2663 strerror (errno));
2664 return SANE_STATUS_IO_ERROR;
2665 }
2666
2667 /* TODO we should check endianness and word alignment in case of a home
2668 * directory used trough different archs */
2669
2670 /* TODO check for errors */
2671 fread (&(scanner->afe_params), sizeof (GT68xx_AFE_Parameters), 1, fcal);
2672 fread (&(scanner->exposure_params), sizeof (GT68xx_Exposure_Parameters), 1,
2673 fcal);
2674
2675 /* loop on calibrators */
2676 i = 0;
2677 fread (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2678 while (!feof (fcal) && scanner->calibrations[i].dpi > 0)
2679 {
2680 fread (&(scanner->calibrations[i].pixel_x0), sizeof (SANE_Int), 1,
2681 fcal);
2682
2683 fread (&width, sizeof (SANE_Int), 1, fcal);
2684 fread (&level, sizeof (SANE_Int), 1, fcal);
2685 gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].red));
2686 fread (scanner->calibrations[i].red->k_white, sizeof (unsigned int),
2687 width, fcal);
2688 fread (scanner->calibrations[i].red->k_black, sizeof (unsigned int),
2689 width, fcal);
2690 fread (scanner->calibrations[i].red->white_line, sizeof (double), width,
2691 fcal);
2692 fread (scanner->calibrations[i].red->black_line, sizeof (double), width,
2693 fcal);
2694
2695 fread (&width, sizeof (SANE_Int), 1, fcal);
2696 fread (&level, sizeof (SANE_Int), 1, fcal);
2697 gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].green));
2698 fread (scanner->calibrations[i].green->k_white, sizeof (unsigned int),
2699 width, fcal);
2700 fread (scanner->calibrations[i].green->k_black, sizeof (unsigned int),
2701 width, fcal);
2702 fread (scanner->calibrations[i].green->white_line, sizeof (double),
2703 width, fcal);
2704 fread (scanner->calibrations[i].green->black_line, sizeof (double),
2705 width, fcal);
2706
2707 fread (&width, sizeof (SANE_Int), 1, fcal);
2708 fread (&level, sizeof (SANE_Int), 1, fcal);
2709 gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].blue));
2710 fread (scanner->calibrations[i].blue->k_white, sizeof (unsigned int),
2711 width, fcal);
2712 fread (scanner->calibrations[i].blue->k_black, sizeof (unsigned int),
2713 width, fcal);
2714 fread (scanner->calibrations[i].blue->white_line, sizeof (double),
2715 width, fcal);
2716 fread (scanner->calibrations[i].blue->black_line, sizeof (double),
2717 width, fcal);
2718
2719 fread (&width, sizeof (SANE_Int), 1, fcal);
2720 if (width > 0)
2721 {
2722 fread (&level, sizeof (SANE_Int), 1, fcal);
2723 gt68xx_calibrator_new (width, level,
2724 &(scanner->calibrations[i].gray));
2725 fread (scanner->calibrations[i].gray->k_white,
2726 sizeof (unsigned int), width, fcal);
2727 fread (scanner->calibrations[i].gray->k_black,
2728 sizeof (unsigned int), width, fcal);
2729 fread (scanner->calibrations[i].gray->white_line, sizeof (double),
2730 width, fcal);
2731 fread (scanner->calibrations[i].gray->black_line, sizeof (double),
2732 width, fcal);
2733 }
2734 /* prepare for nex resolution */
2735 i++;
2736 fread (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2737 }
2738
2739 DBG (5, "gt68xx_read_calibration: read %d calibrations\n", i);
2740 fclose (fcal);
2741
2742 scanner->val[OPT_QUALITY_CAL].w = SANE_TRUE;
2743 scanner->val[OPT_NEED_CALIBRATION_SW].w = SANE_FALSE;
2744 scanner->calibrated = SANE_TRUE;
2745 return SANE_STATUS_GOOD;
2746 }
2747
2748
2749 /* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
2750