• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 					       &params);
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, &params);
762     }
763   else
764     {
765       status = gt68xx_scanner_create_gray_calibrators (scanner, &params);
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 					       &params);
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 					       &params);
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, &params, &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 						   &params);
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, &params));
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, &params, &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, &params);
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 					    &params);
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, &params);
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