1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru>
4141cc406Sopenharmony_ci   AFE offset/gain setting by David Stevenson <david.stevenson@zoom.co.uk>
5141cc406Sopenharmony_ci   Copyright (C) 2002 - 2007 Henning Geinitz <sane@geinitz.org>
6141cc406Sopenharmony_ci   Copyright (C) 2009 Stéphane Voltz <stef.dev@free.fr> for sheetfed
7141cc406Sopenharmony_ci                      calibration code.
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This file is part of the SANE package.
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
12141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
13141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
14141cc406Sopenharmony_ci   License, or (at your option) any later version.
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
17141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
18141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19141cc406Sopenharmony_ci   General Public License for more details.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
22141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
25141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
28141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
29141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
30141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
31141cc406Sopenharmony_ci   account of linking the SANE library code into it.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
34141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
35141cc406Sopenharmony_ci   License.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
38141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
39141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
42141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
43141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
44141cc406Sopenharmony_ci*/
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include "gt68xx_high.h"
47141cc406Sopenharmony_ci#include "gt68xx_mid.c"
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#include <unistd.h>
50141cc406Sopenharmony_ci#include <math.h>
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_cistatic SANE_Status
53141cc406Sopenharmony_cigt68xx_afe_ccd_auto (GT68xx_Scanner * scanner, GT68xx_Scan_Request * request);
54141cc406Sopenharmony_cistatic SANE_Status gt68xx_afe_cis_auto (GT68xx_Scanner * scanner);
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ciSANE_Status
57141cc406Sopenharmony_cigt68xx_calibrator_new (SANE_Int width,
58141cc406Sopenharmony_ci		       SANE_Int white_level, GT68xx_Calibrator ** cal_return)
59141cc406Sopenharmony_ci{
60141cc406Sopenharmony_ci  GT68xx_Calibrator *cal;
61141cc406Sopenharmony_ci  SANE_Int i;
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci  DBG (4, "gt68xx_calibrator_new: enter: width=%d, white_level=%d\n",
64141cc406Sopenharmony_ci       width, white_level);
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci  *cal_return = 0;
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci  if (width <= 0)
69141cc406Sopenharmony_ci    {
70141cc406Sopenharmony_ci      DBG (5, "gt68xx_calibrator_new: invalid width=%d\n", width);
71141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
72141cc406Sopenharmony_ci    }
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci  cal = (GT68xx_Calibrator *) malloc (sizeof (GT68xx_Calibrator));
75141cc406Sopenharmony_ci  if (!cal)
76141cc406Sopenharmony_ci    {
77141cc406Sopenharmony_ci      DBG (5, "gt68xx_calibrator_new: no memory for GT68xx_Calibrator\n");
78141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
79141cc406Sopenharmony_ci    }
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci  cal->k_white = NULL;
82141cc406Sopenharmony_ci  cal->k_black = NULL;
83141cc406Sopenharmony_ci  cal->white_line = NULL;
84141cc406Sopenharmony_ci  cal->black_line = NULL;
85141cc406Sopenharmony_ci  cal->width = width;
86141cc406Sopenharmony_ci  cal->white_level = white_level;
87141cc406Sopenharmony_ci  cal->white_count = 0;
88141cc406Sopenharmony_ci  cal->black_count = 0;
89141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
90141cc406Sopenharmony_ci  cal->min_clip_count = cal->max_clip_count = 0;
91141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci  cal->k_white = (unsigned int *) malloc (width * sizeof (unsigned int));
94141cc406Sopenharmony_ci  cal->k_black = (unsigned int *) malloc (width * sizeof (unsigned int));
95141cc406Sopenharmony_ci  cal->white_line = (double *) malloc (width * sizeof (double));
96141cc406Sopenharmony_ci  cal->black_line = (double *) malloc (width * sizeof (double));
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci  if (!cal->k_white || !cal->k_black || !cal->white_line || !cal->black_line)
99141cc406Sopenharmony_ci    {
100141cc406Sopenharmony_ci      DBG (5, "gt68xx_calibrator_new: no memory for calibration data\n");
101141cc406Sopenharmony_ci      gt68xx_calibrator_free (cal);
102141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
103141cc406Sopenharmony_ci    }
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
106141cc406Sopenharmony_ci    {
107141cc406Sopenharmony_ci      cal->k_white[i] = 0;
108141cc406Sopenharmony_ci      cal->k_black[i] = 0;
109141cc406Sopenharmony_ci      cal->white_line[i] = 0.0;
110141cc406Sopenharmony_ci      cal->black_line[i] = 0.0;
111141cc406Sopenharmony_ci    }
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci  *cal_return = cal;
114141cc406Sopenharmony_ci  DBG (5, "gt68xx_calibrator_new: leave: ok\n");
115141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
116141cc406Sopenharmony_ci}
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ciSANE_Status
119141cc406Sopenharmony_cigt68xx_calibrator_free (GT68xx_Calibrator * cal)
120141cc406Sopenharmony_ci{
121141cc406Sopenharmony_ci  DBG (5, "gt68xx_calibrator_free: enter\n");
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci  if (!cal)
124141cc406Sopenharmony_ci    {
125141cc406Sopenharmony_ci      DBG (5, "gt68xx_calibrator_free: cal==NULL\n");
126141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
127141cc406Sopenharmony_ci    }
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
130141cc406Sopenharmony_ci  DBG (4, "gt68xx_calibrator_free: min_clip_count=%d, max_clip_count=%d\n",
131141cc406Sopenharmony_ci       cal->min_clip_count, cal->max_clip_count);
132141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci  if (cal->k_white)
135141cc406Sopenharmony_ci    {
136141cc406Sopenharmony_ci      free (cal->k_white);
137141cc406Sopenharmony_ci      cal->k_white = NULL;
138141cc406Sopenharmony_ci    }
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ci  if (cal->k_black)
141141cc406Sopenharmony_ci    {
142141cc406Sopenharmony_ci      free (cal->k_black);
143141cc406Sopenharmony_ci      cal->k_black = NULL;
144141cc406Sopenharmony_ci    }
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci  if (cal->white_line)
147141cc406Sopenharmony_ci    {
148141cc406Sopenharmony_ci      free (cal->white_line);
149141cc406Sopenharmony_ci      cal->white_line = NULL;
150141cc406Sopenharmony_ci    }
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci  if (cal->black_line)
153141cc406Sopenharmony_ci    {
154141cc406Sopenharmony_ci      free (cal->black_line);
155141cc406Sopenharmony_ci      cal->black_line = NULL;
156141cc406Sopenharmony_ci    }
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci  free (cal);
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci  DBG (5, "gt68xx_calibrator_free: leave: ok\n");
161141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
162141cc406Sopenharmony_ci}
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ciSANE_Status
165141cc406Sopenharmony_cigt68xx_calibrator_add_white_line (GT68xx_Calibrator * cal, unsigned int *line)
166141cc406Sopenharmony_ci{
167141cc406Sopenharmony_ci  SANE_Int i;
168141cc406Sopenharmony_ci  SANE_Int width = cal->width;
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci  SANE_Int sum = 0;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci  cal->white_count++;
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
175141cc406Sopenharmony_ci    {
176141cc406Sopenharmony_ci      cal->white_line[i] += line[i];
177141cc406Sopenharmony_ci      sum += line[i];
178141cc406Sopenharmony_ci#ifdef SAVE_WHITE_CALIBRATION
179141cc406Sopenharmony_ci      printf ("%c", line[i] >> 8);
180141cc406Sopenharmony_ci#endif
181141cc406Sopenharmony_ci    }
182141cc406Sopenharmony_ci  if (sum / width / 256 < 0x50)
183141cc406Sopenharmony_ci    DBG (1,
184141cc406Sopenharmony_ci	 "gt68xx_calibrator_add_white_line: WARNING: dark calibration line: "
185141cc406Sopenharmony_ci	 "%2d medium white: 0x%02x\n", cal->white_count - 1,
186141cc406Sopenharmony_ci	 sum / width / 256);
187141cc406Sopenharmony_ci  else
188141cc406Sopenharmony_ci    DBG (5,
189141cc406Sopenharmony_ci	 "gt68xx_calibrator_add_white_line: line: %2d medium white: 0x%02x\n",
190141cc406Sopenharmony_ci	 cal->white_count - 1, sum / width / 256);
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
193141cc406Sopenharmony_ci}
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ciSANE_Status
196141cc406Sopenharmony_cigt68xx_calibrator_eval_white (GT68xx_Calibrator * cal, double factor)
197141cc406Sopenharmony_ci{
198141cc406Sopenharmony_ci  SANE_Int i;
199141cc406Sopenharmony_ci  SANE_Int width = cal->width;
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
202141cc406Sopenharmony_ci    {
203141cc406Sopenharmony_ci      cal->white_line[i] = cal->white_line[i] / cal->white_count * factor;
204141cc406Sopenharmony_ci    }
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
207141cc406Sopenharmony_ci}
208141cc406Sopenharmony_ci
209141cc406Sopenharmony_ciSANE_Status
210141cc406Sopenharmony_cigt68xx_calibrator_add_black_line (GT68xx_Calibrator * cal, unsigned int *line)
211141cc406Sopenharmony_ci{
212141cc406Sopenharmony_ci  SANE_Int i;
213141cc406Sopenharmony_ci  SANE_Int width = cal->width;
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci  SANE_Int sum = 0;
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci  cal->black_count++;
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
220141cc406Sopenharmony_ci    {
221141cc406Sopenharmony_ci      cal->black_line[i] += line[i];
222141cc406Sopenharmony_ci      sum += line[i];
223141cc406Sopenharmony_ci#ifdef SAVE_BLACK_CALIBRATION
224141cc406Sopenharmony_ci      printf ("%c", line[i] >> 8);
225141cc406Sopenharmony_ci#endif
226141cc406Sopenharmony_ci    }
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci  DBG (5,
229141cc406Sopenharmony_ci       "gt68xx_calibrator_add_black_line: line: %2d medium black: 0x%02x\n",
230141cc406Sopenharmony_ci       cal->black_count - 1, sum / width / 256);
231141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
232141cc406Sopenharmony_ci}
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ciSANE_Status
235141cc406Sopenharmony_cigt68xx_calibrator_eval_black (GT68xx_Calibrator * cal, double factor)
236141cc406Sopenharmony_ci{
237141cc406Sopenharmony_ci  SANE_Int i;
238141cc406Sopenharmony_ci  SANE_Int width = cal->width;
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
241141cc406Sopenharmony_ci    {
242141cc406Sopenharmony_ci      cal->black_line[i] = cal->black_line[i] / cal->black_count - factor;
243141cc406Sopenharmony_ci    }
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
246141cc406Sopenharmony_ci}
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ciSANE_Status
249141cc406Sopenharmony_cigt68xx_calibrator_finish_setup (GT68xx_Calibrator * cal)
250141cc406Sopenharmony_ci{
251141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
252141cc406Sopenharmony_ci  double ave_black = 0.0;
253141cc406Sopenharmony_ci  double ave_diff = 0.0;
254141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
255141cc406Sopenharmony_ci  int i;
256141cc406Sopenharmony_ci  int width = cal->width;
257141cc406Sopenharmony_ci  unsigned int max_value = 65535;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
260141cc406Sopenharmony_ci    {
261141cc406Sopenharmony_ci      unsigned int white = cal->white_line[i];
262141cc406Sopenharmony_ci      unsigned int black = cal->black_line[i];
263141cc406Sopenharmony_ci      unsigned int diff = (white > black) ? white - black : 1;
264141cc406Sopenharmony_ci      if (diff > max_value)
265141cc406Sopenharmony_ci	diff = max_value;
266141cc406Sopenharmony_ci      cal->k_white[i] = diff;
267141cc406Sopenharmony_ci      cal->k_black[i] = black;
268141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
269141cc406Sopenharmony_ci      ave_black += black;
270141cc406Sopenharmony_ci      ave_diff += diff;
271141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
272141cc406Sopenharmony_ci    }
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
275141cc406Sopenharmony_ci  ave_black /= width;
276141cc406Sopenharmony_ci  ave_diff /= width;
277141cc406Sopenharmony_ci  DBG (4, "gt68xx_calibrator_finish_setup: ave_black=%f, ave_diff=%f\n",
278141cc406Sopenharmony_ci       ave_black, ave_diff);
279141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
282141cc406Sopenharmony_ci}
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ciSANE_Status
285141cc406Sopenharmony_cigt68xx_calibrator_process_line (GT68xx_Calibrator * cal, unsigned int *line)
286141cc406Sopenharmony_ci{
287141cc406Sopenharmony_ci  int i;
288141cc406Sopenharmony_ci  int width = cal->width;
289141cc406Sopenharmony_ci  unsigned int white_level = cal->white_level;
290141cc406Sopenharmony_ci
291141cc406Sopenharmony_ci  for (i = 0; i < width; ++i)
292141cc406Sopenharmony_ci    {
293141cc406Sopenharmony_ci      unsigned int src_value = line[i];
294141cc406Sopenharmony_ci      unsigned int black = cal->k_black[i];
295141cc406Sopenharmony_ci      unsigned int value;
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci      if (src_value > black)
298141cc406Sopenharmony_ci	{
299141cc406Sopenharmony_ci	  value = (src_value - black) * white_level / cal->k_white[i];
300141cc406Sopenharmony_ci	  if (value > 0xffff)
301141cc406Sopenharmony_ci	    {
302141cc406Sopenharmony_ci	      value = 0xffff;
303141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
304141cc406Sopenharmony_ci	      cal->max_clip_count++;
305141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
306141cc406Sopenharmony_ci	    }
307141cc406Sopenharmony_ci	}
308141cc406Sopenharmony_ci      else
309141cc406Sopenharmony_ci	{
310141cc406Sopenharmony_ci	  value = 0;
311141cc406Sopenharmony_ci#ifdef TUNE_CALIBRATOR
312141cc406Sopenharmony_ci	  if (src_value < black)
313141cc406Sopenharmony_ci	    cal->min_clip_count++;
314141cc406Sopenharmony_ci#endif /* TUNE_CALIBRATOR */
315141cc406Sopenharmony_ci	}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci      line[i] = value;
318141cc406Sopenharmony_ci    }
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
321141cc406Sopenharmony_ci}
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ciSANE_Status
324141cc406Sopenharmony_cigt68xx_scanner_new (GT68xx_Device * dev, GT68xx_Scanner ** scanner_return)
325141cc406Sopenharmony_ci{
326141cc406Sopenharmony_ci  GT68xx_Scanner *scanner;
327141cc406Sopenharmony_ci  int i;
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci  *scanner_return = NULL;
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_ci  scanner = (GT68xx_Scanner *) malloc (sizeof (GT68xx_Scanner));
332141cc406Sopenharmony_ci  if (!scanner)
333141cc406Sopenharmony_ci    {
334141cc406Sopenharmony_ci      DBG (5, "gt68xx_scanner_new: no memory for GT68xx_Scanner\n");
335141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
336141cc406Sopenharmony_ci    }
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci  scanner->dev = dev;
339141cc406Sopenharmony_ci  scanner->reader = NULL;
340141cc406Sopenharmony_ci  scanner->cal_gray = NULL;
341141cc406Sopenharmony_ci  scanner->cal_r = NULL;
342141cc406Sopenharmony_ci  scanner->cal_g = NULL;
343141cc406Sopenharmony_ci  scanner->cal_b = NULL;
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci  for(i=0;i<MAX_RESOLUTIONS;i++)
346141cc406Sopenharmony_ci    {
347141cc406Sopenharmony_ci      scanner->calibrations[i].dpi = 0;
348141cc406Sopenharmony_ci      scanner->calibrations[i].red = NULL;
349141cc406Sopenharmony_ci      scanner->calibrations[i].green = NULL;
350141cc406Sopenharmony_ci      scanner->calibrations[i].blue = NULL;
351141cc406Sopenharmony_ci      scanner->calibrations[i].gray = NULL;
352141cc406Sopenharmony_ci    }
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci  *scanner_return = scanner;
355141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
356141cc406Sopenharmony_ci}
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_cistatic void
359141cc406Sopenharmony_cigt68xx_scanner_free_calibrators (GT68xx_Scanner * scanner)
360141cc406Sopenharmony_ci{
361141cc406Sopenharmony_ci  if (scanner->cal_gray)
362141cc406Sopenharmony_ci    {
363141cc406Sopenharmony_ci      gt68xx_calibrator_free (scanner->cal_gray);
364141cc406Sopenharmony_ci      scanner->cal_gray = NULL;
365141cc406Sopenharmony_ci    }
366141cc406Sopenharmony_ci
367141cc406Sopenharmony_ci  if (scanner->cal_r)
368141cc406Sopenharmony_ci    {
369141cc406Sopenharmony_ci      gt68xx_calibrator_free (scanner->cal_r);
370141cc406Sopenharmony_ci      scanner->cal_r = NULL;
371141cc406Sopenharmony_ci    }
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci  if (scanner->cal_g)
374141cc406Sopenharmony_ci    {
375141cc406Sopenharmony_ci      gt68xx_calibrator_free (scanner->cal_g);
376141cc406Sopenharmony_ci      scanner->cal_g = NULL;
377141cc406Sopenharmony_ci    }
378141cc406Sopenharmony_ci
379141cc406Sopenharmony_ci  if (scanner->cal_b)
380141cc406Sopenharmony_ci    {
381141cc406Sopenharmony_ci      gt68xx_calibrator_free (scanner->cal_b);
382141cc406Sopenharmony_ci      scanner->cal_b = NULL;
383141cc406Sopenharmony_ci    }
384141cc406Sopenharmony_ci}
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ciSANE_Status
387141cc406Sopenharmony_cigt68xx_scanner_free (GT68xx_Scanner * scanner)
388141cc406Sopenharmony_ci{
389141cc406Sopenharmony_ci  int i;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci  if (!scanner)
392141cc406Sopenharmony_ci    {
393141cc406Sopenharmony_ci      DBG (5, "gt68xx_scanner_free: scanner==NULL\n");
394141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
395141cc406Sopenharmony_ci    }
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci  if (scanner->reader)
398141cc406Sopenharmony_ci    {
399141cc406Sopenharmony_ci      gt68xx_line_reader_free (scanner->reader);
400141cc406Sopenharmony_ci      scanner->reader = NULL;
401141cc406Sopenharmony_ci    }
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci  gt68xx_scanner_free_calibrators (scanner);
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci  /* free in memory calibration data */
406141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS; i++)
407141cc406Sopenharmony_ci    {
408141cc406Sopenharmony_ci      scanner->calibrations[i].dpi = 0;
409141cc406Sopenharmony_ci      if (scanner->calibrations[i].red != NULL)
410141cc406Sopenharmony_ci	{
411141cc406Sopenharmony_ci	  gt68xx_calibrator_free (scanner->calibrations[i].red);
412141cc406Sopenharmony_ci	}
413141cc406Sopenharmony_ci      if (scanner->calibrations[i].green != NULL)
414141cc406Sopenharmony_ci	{
415141cc406Sopenharmony_ci	  gt68xx_calibrator_free (scanner->calibrations[i].green);
416141cc406Sopenharmony_ci	}
417141cc406Sopenharmony_ci      if (scanner->calibrations[i].blue != NULL)
418141cc406Sopenharmony_ci	{
419141cc406Sopenharmony_ci	  gt68xx_calibrator_free (scanner->calibrations[i].blue);
420141cc406Sopenharmony_ci	}
421141cc406Sopenharmony_ci      if (scanner->calibrations[i].gray != NULL)
422141cc406Sopenharmony_ci	{
423141cc406Sopenharmony_ci	  gt68xx_calibrator_free (scanner->calibrations[i].gray);
424141cc406Sopenharmony_ci	}
425141cc406Sopenharmony_ci    }
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci  free (scanner);
428141cc406Sopenharmony_ci
429141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
430141cc406Sopenharmony_ci}
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_cistatic SANE_Status
433141cc406Sopenharmony_cigt68xx_scanner_wait_for_positioning (GT68xx_Scanner * scanner)
434141cc406Sopenharmony_ci{
435141cc406Sopenharmony_ci  SANE_Status status;
436141cc406Sopenharmony_ci  SANE_Bool moving;
437141cc406Sopenharmony_ci  SANE_Int status_count = 0;
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  usleep (100000);		/* needed by the BP 2400 CU Plus? */
440141cc406Sopenharmony_ci  while (SANE_TRUE)
441141cc406Sopenharmony_ci    {
442141cc406Sopenharmony_ci      status = gt68xx_device_is_moving (scanner->dev, &moving);
443141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
444141cc406Sopenharmony_ci	{
445141cc406Sopenharmony_ci	  if (!moving)
446141cc406Sopenharmony_ci	    break;
447141cc406Sopenharmony_ci	}
448141cc406Sopenharmony_ci      else
449141cc406Sopenharmony_ci	{
450141cc406Sopenharmony_ci	  if (status_count > 9)
451141cc406Sopenharmony_ci	    {
452141cc406Sopenharmony_ci	      DBG (1, "gt68xx_scanner_wait_for_positioning: error count too high!\n");
453141cc406Sopenharmony_ci	      return status;
454141cc406Sopenharmony_ci	    }
455141cc406Sopenharmony_ci	  status_count++;
456141cc406Sopenharmony_ci	  DBG(3, "gt68xx_scanner_wait_for_positioning: ignored error\n");
457141cc406Sopenharmony_ci	}
458141cc406Sopenharmony_ci      usleep (100000);
459141cc406Sopenharmony_ci    }
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
462141cc406Sopenharmony_ci}
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_cistatic SANE_Status
466141cc406Sopenharmony_cigt68xx_scanner_internal_start_scan (GT68xx_Scanner * scanner)
467141cc406Sopenharmony_ci{
468141cc406Sopenharmony_ci  SANE_Status status;
469141cc406Sopenharmony_ci  SANE_Bool ready;
470141cc406Sopenharmony_ci  SANE_Int repeat_count;
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  status = gt68xx_scanner_wait_for_positioning (scanner);
473141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
474141cc406Sopenharmony_ci    {
475141cc406Sopenharmony_ci      DBG (5,
476141cc406Sopenharmony_ci	   "gt68xx_scanner_internal_start_scan: gt68xx_scanner_wait_for_positioning error: %s\n",
477141cc406Sopenharmony_ci	   sane_strstatus (status));
478141cc406Sopenharmony_ci      return status;
479141cc406Sopenharmony_ci    }
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci  status = gt68xx_device_start_scan (scanner->dev);
482141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
483141cc406Sopenharmony_ci    {
484141cc406Sopenharmony_ci      DBG (5,
485141cc406Sopenharmony_ci	   "gt68xx_scanner_internal_start_scan: gt68xx_device_start_scan error: %s\n",
486141cc406Sopenharmony_ci	   sane_strstatus (status));
487141cc406Sopenharmony_ci      return status;
488141cc406Sopenharmony_ci    }
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci  for (repeat_count = 0; repeat_count < 30 * 100; ++repeat_count)
491141cc406Sopenharmony_ci    {
492141cc406Sopenharmony_ci      status = gt68xx_device_read_scanned_data (scanner->dev, &ready);
493141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
494141cc406Sopenharmony_ci	{
495141cc406Sopenharmony_ci	  DBG (5,
496141cc406Sopenharmony_ci	       "gt68xx_scanner_internal_start_scan: gt68xx_device_read_scanned_data error: %s\n",
497141cc406Sopenharmony_ci	       sane_strstatus (status));
498141cc406Sopenharmony_ci	  return status;
499141cc406Sopenharmony_ci	}
500141cc406Sopenharmony_ci      if (ready)
501141cc406Sopenharmony_ci	break;
502141cc406Sopenharmony_ci      usleep (10000);
503141cc406Sopenharmony_ci    }
504141cc406Sopenharmony_ci  if (!ready)
505141cc406Sopenharmony_ci    {
506141cc406Sopenharmony_ci      DBG (5,
507141cc406Sopenharmony_ci	   "gt68xx_scanner_internal_start_scan: scanner still not ready - giving up\n");
508141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
509141cc406Sopenharmony_ci    }
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci  status = gt68xx_device_read_start (scanner->dev);
512141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
513141cc406Sopenharmony_ci    {
514141cc406Sopenharmony_ci      DBG (5,
515141cc406Sopenharmony_ci	   "gt68xx_scanner_internal_start_scan: gt68xx_device_read_start error: %s\n",
516141cc406Sopenharmony_ci	   sane_strstatus (status));
517141cc406Sopenharmony_ci      return status;
518141cc406Sopenharmony_ci    }
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
521141cc406Sopenharmony_ci}
522141cc406Sopenharmony_ci
523141cc406Sopenharmony_cistatic SANE_Status
524141cc406Sopenharmony_cigt68xx_scanner_start_scan_extended (GT68xx_Scanner * scanner,
525141cc406Sopenharmony_ci				    GT68xx_Scan_Request * request,
526141cc406Sopenharmony_ci				    GT68xx_Scan_Action action,
527141cc406Sopenharmony_ci				    GT68xx_Scan_Parameters * params)
528141cc406Sopenharmony_ci{
529141cc406Sopenharmony_ci  SANE_Status status;
530141cc406Sopenharmony_ci  GT68xx_AFE_Parameters afe = *scanner->dev->afe;
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci  status = gt68xx_scanner_wait_for_positioning (scanner);
533141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
534141cc406Sopenharmony_ci    {
535141cc406Sopenharmony_ci      DBG (5,
536141cc406Sopenharmony_ci	   "gt68xx_scanner_start_scan_extended: gt68xx_scanner_wait_for_positioning error: %s\n",
537141cc406Sopenharmony_ci	   sane_strstatus (status));
538141cc406Sopenharmony_ci      return status;
539141cc406Sopenharmony_ci    }
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci  status = gt68xx_device_setup_scan (scanner->dev, request, action, params);
542141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
543141cc406Sopenharmony_ci    {
544141cc406Sopenharmony_ci      DBG (5,
545141cc406Sopenharmony_ci	   "gt68xx_scanner_start_scan_extended: gt68xx_device_setup_scan failed: %s\n",
546141cc406Sopenharmony_ci	   sane_strstatus (status));
547141cc406Sopenharmony_ci      return status;
548141cc406Sopenharmony_ci    }
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci  status = gt68xx_line_reader_new (scanner->dev, params,
551141cc406Sopenharmony_ci				   action == SA_SCAN ? SANE_TRUE : SANE_FALSE,
552141cc406Sopenharmony_ci				   &scanner->reader);
553141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
554141cc406Sopenharmony_ci    {
555141cc406Sopenharmony_ci      DBG (5,
556141cc406Sopenharmony_ci	   "gt68xx_scanner_start_scan_extended: gt68xx_line_reader_new failed: %s\n",
557141cc406Sopenharmony_ci	   sane_strstatus (status));
558141cc406Sopenharmony_ci      return status;
559141cc406Sopenharmony_ci    }
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci  if (scanner->dev->model->is_cis
562141cc406Sopenharmony_ci      && !((scanner->dev->model->flags & GT68XX_FLAG_SHEET_FED) && scanner->calibrated == SANE_FALSE))
563141cc406Sopenharmony_ci    {
564141cc406Sopenharmony_ci      status =
565141cc406Sopenharmony_ci	gt68xx_device_set_exposure_time (scanner->dev,
566141cc406Sopenharmony_ci					 scanner->dev->exposure);
567141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
568141cc406Sopenharmony_ci	{
569141cc406Sopenharmony_ci	  DBG (5,
570141cc406Sopenharmony_ci	       "gt68xx_scanner_start_scan_extended: gt68xx_device_set_exposure_time failed: %s\n",
571141cc406Sopenharmony_ci	       sane_strstatus (status));
572141cc406Sopenharmony_ci	  return status;
573141cc406Sopenharmony_ci	}
574141cc406Sopenharmony_ci    }
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_ci  status = gt68xx_device_set_afe (scanner->dev, &afe);
577141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
578141cc406Sopenharmony_ci    {
579141cc406Sopenharmony_ci      DBG (5,
580141cc406Sopenharmony_ci	   "gt68xx_scanner_start_scan_extended: gt68xx_device_set_afe failed: %s\n",
581141cc406Sopenharmony_ci	   sane_strstatus (status));
582141cc406Sopenharmony_ci      return status;
583141cc406Sopenharmony_ci    }
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci  status = gt68xx_scanner_internal_start_scan (scanner);
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
588141cc406Sopenharmony_ci    {
589141cc406Sopenharmony_ci      DBG (5,
590141cc406Sopenharmony_ci	   "gt68xx_scanner_start_scan_extended: gt68xx_scanner_internal_start_scan failed: %s\n",
591141cc406Sopenharmony_ci	   sane_strstatus (status));
592141cc406Sopenharmony_ci      return status;
593141cc406Sopenharmony_ci    }
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
596141cc406Sopenharmony_ci}
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_cistatic SANE_Status
599141cc406Sopenharmony_cigt68xx_scanner_create_calibrator (GT68xx_Scan_Parameters * params,
600141cc406Sopenharmony_ci				  GT68xx_Calibrator ** cal_return)
601141cc406Sopenharmony_ci{
602141cc406Sopenharmony_ci  return gt68xx_calibrator_new (params->pixel_xs, 65535, cal_return);
603141cc406Sopenharmony_ci}
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_cistatic SANE_Status
606141cc406Sopenharmony_cigt68xx_scanner_create_color_calibrators (GT68xx_Scanner * scanner,
607141cc406Sopenharmony_ci					 GT68xx_Scan_Parameters * params)
608141cc406Sopenharmony_ci{
609141cc406Sopenharmony_ci  SANE_Status status;
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  if (!scanner->cal_r)
612141cc406Sopenharmony_ci    {
613141cc406Sopenharmony_ci      status = gt68xx_scanner_create_calibrator (params, &scanner->cal_r);
614141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
615141cc406Sopenharmony_ci	return status;
616141cc406Sopenharmony_ci    }
617141cc406Sopenharmony_ci  if (!scanner->cal_g)
618141cc406Sopenharmony_ci    {
619141cc406Sopenharmony_ci      status = gt68xx_scanner_create_calibrator (params, &scanner->cal_g);
620141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
621141cc406Sopenharmony_ci	return status;
622141cc406Sopenharmony_ci    }
623141cc406Sopenharmony_ci  if (!scanner->cal_b)
624141cc406Sopenharmony_ci    {
625141cc406Sopenharmony_ci      status = gt68xx_scanner_create_calibrator (params, &scanner->cal_b);
626141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
627141cc406Sopenharmony_ci	return status;
628141cc406Sopenharmony_ci    }
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
631141cc406Sopenharmony_ci}
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_cistatic SANE_Status
634141cc406Sopenharmony_cigt68xx_scanner_create_gray_calibrators (GT68xx_Scanner * scanner,
635141cc406Sopenharmony_ci					GT68xx_Scan_Parameters * params)
636141cc406Sopenharmony_ci{
637141cc406Sopenharmony_ci  SANE_Status status;
638141cc406Sopenharmony_ci
639141cc406Sopenharmony_ci  if (!scanner->cal_gray)
640141cc406Sopenharmony_ci    {
641141cc406Sopenharmony_ci      status = gt68xx_scanner_create_calibrator (params, &scanner->cal_gray);
642141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
643141cc406Sopenharmony_ci	return status;
644141cc406Sopenharmony_ci    }
645141cc406Sopenharmony_ci
646141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
647141cc406Sopenharmony_ci}
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_cistatic SANE_Status
650141cc406Sopenharmony_cigt68xx_scanner_calibrate_color_white_line (GT68xx_Scanner * scanner,
651141cc406Sopenharmony_ci					   unsigned int **buffer_pointers)
652141cc406Sopenharmony_ci{
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  gt68xx_calibrator_add_white_line (scanner->cal_r, buffer_pointers[0]);
655141cc406Sopenharmony_ci  gt68xx_calibrator_add_white_line (scanner->cal_g, buffer_pointers[1]);
656141cc406Sopenharmony_ci  gt68xx_calibrator_add_white_line (scanner->cal_b, buffer_pointers[2]);
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
659141cc406Sopenharmony_ci}
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_cistatic SANE_Status
662141cc406Sopenharmony_cigt68xx_scanner_calibrate_gray_white_line (GT68xx_Scanner * scanner,
663141cc406Sopenharmony_ci					  unsigned int **buffer_pointers)
664141cc406Sopenharmony_ci{
665141cc406Sopenharmony_ci  gt68xx_calibrator_add_white_line (scanner->cal_gray, buffer_pointers[0]);
666141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
667141cc406Sopenharmony_ci}
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_cistatic SANE_Status
670141cc406Sopenharmony_cigt68xx_scanner_calibrate_color_black_line (GT68xx_Scanner * scanner,
671141cc406Sopenharmony_ci					   unsigned int **buffer_pointers)
672141cc406Sopenharmony_ci{
673141cc406Sopenharmony_ci  gt68xx_calibrator_add_black_line (scanner->cal_r, buffer_pointers[0]);
674141cc406Sopenharmony_ci  gt68xx_calibrator_add_black_line (scanner->cal_g, buffer_pointers[1]);
675141cc406Sopenharmony_ci  gt68xx_calibrator_add_black_line (scanner->cal_b, buffer_pointers[2]);
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
678141cc406Sopenharmony_ci}
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_cistatic SANE_Status
681141cc406Sopenharmony_cigt68xx_scanner_calibrate_gray_black_line (GT68xx_Scanner * scanner,
682141cc406Sopenharmony_ci					  unsigned int **buffer_pointers)
683141cc406Sopenharmony_ci{
684141cc406Sopenharmony_ci  gt68xx_calibrator_add_black_line (scanner->cal_gray, buffer_pointers[0]);
685141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
686141cc406Sopenharmony_ci}
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ciSANE_Status
689141cc406Sopenharmony_cigt68xx_scanner_calibrate (GT68xx_Scanner * scanner,
690141cc406Sopenharmony_ci			  GT68xx_Scan_Request * request)
691141cc406Sopenharmony_ci{
692141cc406Sopenharmony_ci  SANE_Status status;
693141cc406Sopenharmony_ci  GT68xx_Scan_Parameters params;
694141cc406Sopenharmony_ci  GT68xx_Scan_Request req;
695141cc406Sopenharmony_ci  SANE_Int i;
696141cc406Sopenharmony_ci  unsigned int *buffer_pointers[3];
697141cc406Sopenharmony_ci  GT68xx_AFE_Parameters *afe = scanner->dev->afe;
698141cc406Sopenharmony_ci  GT68xx_Exposure_Parameters *exposure = scanner->dev->exposure;
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci  memcpy (&req, request, sizeof (req));
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci  gt68xx_scanner_free_calibrators (scanner);
703141cc406Sopenharmony_ci
704141cc406Sopenharmony_ci  if (scanner->auto_afe)
705141cc406Sopenharmony_ci    {
706141cc406Sopenharmony_ci      if (scanner->dev->model->is_cis)
707141cc406Sopenharmony_ci	status = gt68xx_afe_cis_auto (scanner);
708141cc406Sopenharmony_ci      else
709141cc406Sopenharmony_ci	status = gt68xx_afe_ccd_auto (scanner, request);
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
712141cc406Sopenharmony_ci	{
713141cc406Sopenharmony_ci	  DBG (5, "gt68xx_scanner_calibrate: gt68xx_afe_*_auto failed: %s\n",
714141cc406Sopenharmony_ci	       sane_strstatus (status));
715141cc406Sopenharmony_ci	  return status;
716141cc406Sopenharmony_ci	}
717141cc406Sopenharmony_ci      req.mbs = SANE_FALSE;
718141cc406Sopenharmony_ci    }
719141cc406Sopenharmony_ci  else
720141cc406Sopenharmony_ci    req.mbs = SANE_TRUE;
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci  DBG (3, "afe 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", afe->r_offset,
723141cc406Sopenharmony_ci       afe->r_pga, afe->g_offset, afe->g_pga, afe->b_offset, afe->b_pga);
724141cc406Sopenharmony_ci  DBG (3, "exposure 0x%02x 0x%02x 0x%02x\n", exposure->r_time,
725141cc406Sopenharmony_ci       exposure->g_time, exposure->b_time);
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci  if (!scanner->calib)
728141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci  req.mds = SANE_TRUE;
731141cc406Sopenharmony_ci  req.mas = SANE_FALSE;
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci  if (scanner->dev->model->is_cis && !(scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
734141cc406Sopenharmony_ci    req.color = SANE_TRUE;
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci  if (req.use_ta)
737141cc406Sopenharmony_ci    {
738141cc406Sopenharmony_ci      req.lamp = SANE_FALSE;
739141cc406Sopenharmony_ci      status =
740141cc406Sopenharmony_ci	gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
741141cc406Sopenharmony_ci    }
742141cc406Sopenharmony_ci  else
743141cc406Sopenharmony_ci    {
744141cc406Sopenharmony_ci      req.lamp = SANE_TRUE;
745141cc406Sopenharmony_ci      status =
746141cc406Sopenharmony_ci	gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
747141cc406Sopenharmony_ci    }
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  status = gt68xx_scanner_start_scan_extended (scanner, &req, SA_CALIBRATE,
750141cc406Sopenharmony_ci					       &params);
751141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
752141cc406Sopenharmony_ci    {
753141cc406Sopenharmony_ci      DBG (5,
754141cc406Sopenharmony_ci	   "gt68xx_scanner_calibrate: gt68xx_scanner_start_scan_extended failed: %s\n",
755141cc406Sopenharmony_ci	   sane_strstatus (status));
756141cc406Sopenharmony_ci      return status;
757141cc406Sopenharmony_ci    }
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci  if (params.color)
760141cc406Sopenharmony_ci    {
761141cc406Sopenharmony_ci      status = gt68xx_scanner_create_color_calibrators (scanner, &params);
762141cc406Sopenharmony_ci    }
763141cc406Sopenharmony_ci  else
764141cc406Sopenharmony_ci    {
765141cc406Sopenharmony_ci      status = gt68xx_scanner_create_gray_calibrators (scanner, &params);
766141cc406Sopenharmony_ci    }
767141cc406Sopenharmony_ci
768141cc406Sopenharmony_ci#if defined(SAVE_WHITE_CALIBRATION) || defined(SAVE_BLACK_CALIBRATION)
769141cc406Sopenharmony_ci  printf ("P5\n%d %d\n255\n", params.pixel_xs, params.pixel_ys * 3);
770141cc406Sopenharmony_ci#endif
771141cc406Sopenharmony_ci  for (i = 0; i < params.pixel_ys; ++i)
772141cc406Sopenharmony_ci    {
773141cc406Sopenharmony_ci      status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
774141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
775141cc406Sopenharmony_ci	{
776141cc406Sopenharmony_ci	  DBG (5,
777141cc406Sopenharmony_ci	       "gt68xx_scanner_calibrate: gt68xx_line_reader_read failed: %s\n",
778141cc406Sopenharmony_ci	       sane_strstatus (status));
779141cc406Sopenharmony_ci	  return status;
780141cc406Sopenharmony_ci	}
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci      if (params.color)
783141cc406Sopenharmony_ci	status = gt68xx_scanner_calibrate_color_white_line (scanner,
784141cc406Sopenharmony_ci							    buffer_pointers);
785141cc406Sopenharmony_ci      else
786141cc406Sopenharmony_ci	status = gt68xx_scanner_calibrate_gray_white_line (scanner,
787141cc406Sopenharmony_ci							   buffer_pointers);
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
790141cc406Sopenharmony_ci	{
791141cc406Sopenharmony_ci	  DBG (5, "gt68xx_scanner_calibrate: calibration failed: %s\n",
792141cc406Sopenharmony_ci	       sane_strstatus (status));
793141cc406Sopenharmony_ci	  return status;
794141cc406Sopenharmony_ci	}
795141cc406Sopenharmony_ci    }
796141cc406Sopenharmony_ci  gt68xx_scanner_stop_scan (scanner);
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci  if (params.color)
799141cc406Sopenharmony_ci    {
800141cc406Sopenharmony_ci      gt68xx_calibrator_eval_white (scanner->cal_r, 1);
801141cc406Sopenharmony_ci      gt68xx_calibrator_eval_white (scanner->cal_g, 1);
802141cc406Sopenharmony_ci      gt68xx_calibrator_eval_white (scanner->cal_b, 1);
803141cc406Sopenharmony_ci    }
804141cc406Sopenharmony_ci  else
805141cc406Sopenharmony_ci    {
806141cc406Sopenharmony_ci      gt68xx_calibrator_eval_white (scanner->cal_gray, 1);
807141cc406Sopenharmony_ci    }
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci  req.mbs = SANE_FALSE;
810141cc406Sopenharmony_ci  req.mds = SANE_FALSE;
811141cc406Sopenharmony_ci  req.mas = SANE_FALSE;
812141cc406Sopenharmony_ci  req.lamp = SANE_FALSE;
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci  status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_FALSE);
815141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
816141cc406Sopenharmony_ci    {
817141cc406Sopenharmony_ci      DBG (5,
818141cc406Sopenharmony_ci	   "gt68xx_scanner_calibrate: gt68xx_device_lamp_control failed: %s\n",
819141cc406Sopenharmony_ci	   sane_strstatus (status));
820141cc406Sopenharmony_ci      return status;
821141cc406Sopenharmony_ci    }
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  if (!scanner->dev->model->is_cis
824141cc406Sopenharmony_ci      || (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
825141cc406Sopenharmony_ci    usleep (500000);
826141cc406Sopenharmony_ci  status = gt68xx_scanner_start_scan_extended (scanner, &req, SA_CALIBRATE,
827141cc406Sopenharmony_ci					       &params);
828141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
829141cc406Sopenharmony_ci    {
830141cc406Sopenharmony_ci      DBG (5,
831141cc406Sopenharmony_ci	   "gt68xx_scanner_calibrate: gt68xx_scanner_start_scan_extended failed: %s\n",
832141cc406Sopenharmony_ci	   sane_strstatus (status));
833141cc406Sopenharmony_ci      return status;
834141cc406Sopenharmony_ci    }
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  for (i = 0; i < params.pixel_ys; ++i)
837141cc406Sopenharmony_ci    {
838141cc406Sopenharmony_ci      status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
839141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
840141cc406Sopenharmony_ci	{
841141cc406Sopenharmony_ci	  DBG (5,
842141cc406Sopenharmony_ci	       "gt68xx_scanner_calibrate: gt68xx_line_reader_read failed: %s\n",
843141cc406Sopenharmony_ci	       sane_strstatus (status));
844141cc406Sopenharmony_ci	  return status;
845141cc406Sopenharmony_ci	}
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci      if (params.color)
848141cc406Sopenharmony_ci	status = gt68xx_scanner_calibrate_color_black_line (scanner,
849141cc406Sopenharmony_ci							    buffer_pointers);
850141cc406Sopenharmony_ci      else
851141cc406Sopenharmony_ci	status = gt68xx_scanner_calibrate_gray_black_line (scanner,
852141cc406Sopenharmony_ci							   buffer_pointers);
853141cc406Sopenharmony_ci
854141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
855141cc406Sopenharmony_ci	{
856141cc406Sopenharmony_ci	  DBG (5, "gt68xx_scanner_calibrate: calibration failed: %s\n",
857141cc406Sopenharmony_ci	       sane_strstatus (status));
858141cc406Sopenharmony_ci	  return status;
859141cc406Sopenharmony_ci	}
860141cc406Sopenharmony_ci    }
861141cc406Sopenharmony_ci  gt68xx_scanner_stop_scan (scanner);
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci  if (req.use_ta)
864141cc406Sopenharmony_ci    status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
865141cc406Sopenharmony_ci  else
866141cc406Sopenharmony_ci    status = gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
867141cc406Sopenharmony_ci
868141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
869141cc406Sopenharmony_ci    {
870141cc406Sopenharmony_ci      DBG (5,
871141cc406Sopenharmony_ci	   "gt68xx_scanner_calibrate: gt68xx_device_lamp_control failed: %s\n",
872141cc406Sopenharmony_ci	   sane_strstatus (status));
873141cc406Sopenharmony_ci      return status;
874141cc406Sopenharmony_ci    }
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci  if (!scanner->dev->model->is_cis)
877141cc406Sopenharmony_ci    usleep (500000);
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_ci  if (params.color)
880141cc406Sopenharmony_ci    {
881141cc406Sopenharmony_ci      gt68xx_calibrator_eval_black (scanner->cal_r, 0.0);
882141cc406Sopenharmony_ci      gt68xx_calibrator_eval_black (scanner->cal_g, 0.0);
883141cc406Sopenharmony_ci      gt68xx_calibrator_eval_black (scanner->cal_b, 0.0);
884141cc406Sopenharmony_ci
885141cc406Sopenharmony_ci      gt68xx_calibrator_finish_setup (scanner->cal_r);
886141cc406Sopenharmony_ci      gt68xx_calibrator_finish_setup (scanner->cal_g);
887141cc406Sopenharmony_ci      gt68xx_calibrator_finish_setup (scanner->cal_b);
888141cc406Sopenharmony_ci    }
889141cc406Sopenharmony_ci  else
890141cc406Sopenharmony_ci    {
891141cc406Sopenharmony_ci      gt68xx_calibrator_eval_black (scanner->cal_gray, 0.0);
892141cc406Sopenharmony_ci      gt68xx_calibrator_finish_setup (scanner->cal_gray);
893141cc406Sopenharmony_ci    }
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
896141cc406Sopenharmony_ci}
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ciSANE_Status
899141cc406Sopenharmony_cigt68xx_scanner_start_scan (GT68xx_Scanner * scanner,
900141cc406Sopenharmony_ci			   GT68xx_Scan_Request * request,
901141cc406Sopenharmony_ci			   GT68xx_Scan_Parameters * params)
902141cc406Sopenharmony_ci{
903141cc406Sopenharmony_ci  request->mbs = SANE_FALSE;	/* don't go home before real scan */
904141cc406Sopenharmony_ci  request->mds = SANE_TRUE;
905141cc406Sopenharmony_ci  request->mas = SANE_FALSE;
906141cc406Sopenharmony_ci  if (request->use_ta)
907141cc406Sopenharmony_ci    {
908141cc406Sopenharmony_ci      gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
909141cc406Sopenharmony_ci      request->lamp = SANE_FALSE;
910141cc406Sopenharmony_ci    }
911141cc406Sopenharmony_ci  else
912141cc406Sopenharmony_ci    {
913141cc406Sopenharmony_ci      gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
914141cc406Sopenharmony_ci      request->lamp = SANE_TRUE;
915141cc406Sopenharmony_ci    }
916141cc406Sopenharmony_ci  if (!scanner->dev->model->is_cis)
917141cc406Sopenharmony_ci    sleep (2);
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci  return gt68xx_scanner_start_scan_extended (scanner, request, SA_SCAN,
920141cc406Sopenharmony_ci					     params);
921141cc406Sopenharmony_ci}
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ciSANE_Status
924141cc406Sopenharmony_cigt68xx_scanner_read_line (GT68xx_Scanner * scanner,
925141cc406Sopenharmony_ci			  unsigned int **buffer_pointers)
926141cc406Sopenharmony_ci{
927141cc406Sopenharmony_ci  SANE_Status status;
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci  status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
932141cc406Sopenharmony_ci    {
933141cc406Sopenharmony_ci      DBG (5,
934141cc406Sopenharmony_ci	   "gt68xx_scanner_read_line: gt68xx_line_reader_read failed: %s\n",
935141cc406Sopenharmony_ci	   sane_strstatus (status));
936141cc406Sopenharmony_ci      return status;
937141cc406Sopenharmony_ci    }
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  if (scanner->calib)
940141cc406Sopenharmony_ci    {
941141cc406Sopenharmony_ci      if (scanner->reader->params.color)
942141cc406Sopenharmony_ci	{
943141cc406Sopenharmony_ci	  gt68xx_calibrator_process_line (scanner->cal_r, buffer_pointers[0]);
944141cc406Sopenharmony_ci	  gt68xx_calibrator_process_line (scanner->cal_g, buffer_pointers[1]);
945141cc406Sopenharmony_ci	  gt68xx_calibrator_process_line (scanner->cal_b, buffer_pointers[2]);
946141cc406Sopenharmony_ci	}
947141cc406Sopenharmony_ci      else
948141cc406Sopenharmony_ci	{
949141cc406Sopenharmony_ci	  if (scanner->dev->model->is_cis && !(scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
950141cc406Sopenharmony_ci	    {
951141cc406Sopenharmony_ci	      if (strcmp
952141cc406Sopenharmony_ci		  (scanner->val[OPT_GRAY_MODE_COLOR].s,
953141cc406Sopenharmony_ci		   GT68XX_COLOR_BLUE) == 0)
954141cc406Sopenharmony_ci		gt68xx_calibrator_process_line (scanner->cal_b,
955141cc406Sopenharmony_ci						buffer_pointers[0]);
956141cc406Sopenharmony_ci	      else
957141cc406Sopenharmony_ci		if (strcmp
958141cc406Sopenharmony_ci		    (scanner->val[OPT_GRAY_MODE_COLOR].s,
959141cc406Sopenharmony_ci		     GT68XX_COLOR_GREEN) == 0)
960141cc406Sopenharmony_ci		gt68xx_calibrator_process_line (scanner->cal_g,
961141cc406Sopenharmony_ci						buffer_pointers[0]);
962141cc406Sopenharmony_ci	      else
963141cc406Sopenharmony_ci		gt68xx_calibrator_process_line (scanner->cal_r,
964141cc406Sopenharmony_ci						buffer_pointers[0]);
965141cc406Sopenharmony_ci	    }
966141cc406Sopenharmony_ci	  else
967141cc406Sopenharmony_ci	    {
968141cc406Sopenharmony_ci	      gt68xx_calibrator_process_line (scanner->cal_gray,
969141cc406Sopenharmony_ci					      buffer_pointers[0]);
970141cc406Sopenharmony_ci	    }
971141cc406Sopenharmony_ci	}
972141cc406Sopenharmony_ci    }
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
975141cc406Sopenharmony_ci}
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ciSANE_Status
978141cc406Sopenharmony_cigt68xx_scanner_stop_scan (GT68xx_Scanner * scanner)
979141cc406Sopenharmony_ci{
980141cc406Sopenharmony_ci  if (scanner->reader)
981141cc406Sopenharmony_ci    {
982141cc406Sopenharmony_ci      gt68xx_line_reader_free (scanner->reader);
983141cc406Sopenharmony_ci      scanner->reader = NULL;
984141cc406Sopenharmony_ci    }
985141cc406Sopenharmony_ci  return gt68xx_device_stop_scan (scanner->dev);
986141cc406Sopenharmony_ci}
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci/************************************************************************/
989141cc406Sopenharmony_ci/*                                                                      */
990141cc406Sopenharmony_ci/* AFE offset/gain automatic configuration                              */
991141cc406Sopenharmony_ci/*                                                                      */
992141cc406Sopenharmony_ci/************************************************************************/
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_citypedef struct GT68xx_Afe_Values GT68xx_Afe_Values;
995141cc406Sopenharmony_ci
996141cc406Sopenharmony_cistruct GT68xx_Afe_Values
997141cc406Sopenharmony_ci{
998141cc406Sopenharmony_ci  SANE_Int black;		/* minimum black (0-255) */
999141cc406Sopenharmony_ci  SANE_Int white;		/* maximum white (0-255) */
1000141cc406Sopenharmony_ci  SANE_Int total_white;		/* average white of the complete line (0-65536) */
1001141cc406Sopenharmony_ci  SANE_Int calwidth;
1002141cc406Sopenharmony_ci  SANE_Int callines;
1003141cc406Sopenharmony_ci  SANE_Int max_width;
1004141cc406Sopenharmony_ci  SANE_Int scan_dpi;
1005141cc406Sopenharmony_ci  SANE_Fixed start_black;
1006141cc406Sopenharmony_ci  SANE_Int offset_direction;
1007141cc406Sopenharmony_ci  SANE_Int coarse_black;
1008141cc406Sopenharmony_ci  SANE_Int coarse_white;
1009141cc406Sopenharmony_ci};
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci/************************************************************************/
1013141cc406Sopenharmony_ci/* CCD scanners                                                         */
1014141cc406Sopenharmony_ci/************************************************************************/
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci/** Calculate average black and maximum white
1017141cc406Sopenharmony_ci *
1018141cc406Sopenharmony_ci * This function is used for CCD scanners. The black mark to the left is used
1019141cc406Sopenharmony_ci * for the calculation of average black. The remaining calibration strip
1020141cc406Sopenharmony_ci * is used for searching the segment whose white average is the highest.
1021141cc406Sopenharmony_ci *
1022141cc406Sopenharmony_ci * @param values AFE values
1023141cc406Sopenharmony_ci * @param buffer scanned line
1024141cc406Sopenharmony_ci */
1025141cc406Sopenharmony_cistatic void
1026141cc406Sopenharmony_cigt68xx_afe_ccd_calc (GT68xx_Afe_Values * values, unsigned int *buffer)
1027141cc406Sopenharmony_ci{
1028141cc406Sopenharmony_ci  SANE_Int start_black;
1029141cc406Sopenharmony_ci  SANE_Int end_black;
1030141cc406Sopenharmony_ci  SANE_Int start_white;
1031141cc406Sopenharmony_ci  SANE_Int end_white;
1032141cc406Sopenharmony_ci  SANE_Int i;
1033141cc406Sopenharmony_ci  SANE_Int max_black = 0;
1034141cc406Sopenharmony_ci  SANE_Int min_black = 255;
1035141cc406Sopenharmony_ci  SANE_Int max_white = 0;
1036141cc406Sopenharmony_ci  SANE_Int total_white = 0;
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci  /* set size of black mark and white segments */
1039141cc406Sopenharmony_ci  start_black =
1040141cc406Sopenharmony_ci    SANE_UNFIX (values->start_black) * values->scan_dpi / MM_PER_INCH;
1041141cc406Sopenharmony_ci  end_black = start_black + 1.0 * values->scan_dpi / MM_PER_INCH;	/* 1 mm */
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci  /* 5mm after mark */
1044141cc406Sopenharmony_ci  start_white = end_black + 5.0 * values->scan_dpi / MM_PER_INCH;
1045141cc406Sopenharmony_ci  end_white = values->calwidth;
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci  DBG (5,
1048141cc406Sopenharmony_ci       "gt68xx_afe_ccd_calc: dpi=%d, start_black=%d, end_black=%d, start_white=%d, end_white=%d\n",
1049141cc406Sopenharmony_ci       values->scan_dpi, start_black, end_black, start_white, end_white);
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci  /* calc min and max black value */
1052141cc406Sopenharmony_ci  for (i = start_black; i < end_black; i++)
1053141cc406Sopenharmony_ci    {
1054141cc406Sopenharmony_ci      if ((SANE_Int) (buffer[i] >> 8) < min_black)
1055141cc406Sopenharmony_ci	min_black = (buffer[i] >> 8);
1056141cc406Sopenharmony_ci      if ((SANE_Int) (buffer[i] >> 8) > max_black)
1057141cc406Sopenharmony_ci	max_black = (buffer[i] >> 8);
1058141cc406Sopenharmony_ci#ifdef DEBUG_BLACK
1059141cc406Sopenharmony_ci      if ((buffer[i] >> 8) > 15)
1060141cc406Sopenharmony_ci	fprintf (stderr, "+");
1061141cc406Sopenharmony_ci      else if ((buffer[i] >> 8) < 5)
1062141cc406Sopenharmony_ci	fprintf (stderr, "-");
1063141cc406Sopenharmony_ci      else
1064141cc406Sopenharmony_ci	fprintf (stderr, "_");
1065141cc406Sopenharmony_ci#endif
1066141cc406Sopenharmony_ci    }
1067141cc406Sopenharmony_ci#ifdef DEBUG_BLACK
1068141cc406Sopenharmony_ci  fprintf (stderr, "\n");
1069141cc406Sopenharmony_ci#endif
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci  for (i = start_white; i < end_white; ++i)
1072141cc406Sopenharmony_ci    {
1073141cc406Sopenharmony_ci      if ((SANE_Int) (buffer[i] >> 8) > max_white)
1074141cc406Sopenharmony_ci	max_white = (buffer[i] >> 8);
1075141cc406Sopenharmony_ci      total_white += buffer[i];
1076141cc406Sopenharmony_ci    }
1077141cc406Sopenharmony_ci  values->total_white = total_white / (end_white - start_white);
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci  values->black = min_black;
1080141cc406Sopenharmony_ci  values->white = max_white;
1081141cc406Sopenharmony_ci  if (values->white < 50 || values->black > 150
1082141cc406Sopenharmony_ci      || values->white - values->black < 30 || max_black - min_black > 15)
1083141cc406Sopenharmony_ci    DBG (1,
1084141cc406Sopenharmony_ci	 "gt68xx_afe_ccd_calc: WARNING: max_white %3d   min_black %3d  max_black %3d\n",
1085141cc406Sopenharmony_ci	 values->white, values->black, max_black);
1086141cc406Sopenharmony_ci  else
1087141cc406Sopenharmony_ci    DBG (5,
1088141cc406Sopenharmony_ci	 "gt68xx_afe_ccd_calc: max_white %3d   min_black %3d  max_black %3d\n",
1089141cc406Sopenharmony_ci	 values->white, values->black, max_black);
1090141cc406Sopenharmony_ci}
1091141cc406Sopenharmony_ci
1092141cc406Sopenharmony_cistatic SANE_Bool
1093141cc406Sopenharmony_cigt68xx_afe_ccd_adjust_offset_gain (SANE_String_Const color_name,
1094141cc406Sopenharmony_ci				   GT68xx_Afe_Values * values,
1095141cc406Sopenharmony_ci				   unsigned int *buffer, SANE_Byte * offset,
1096141cc406Sopenharmony_ci				   SANE_Byte * pga, SANE_Byte * old_offset,
1097141cc406Sopenharmony_ci				   SANE_Byte * old_pga)
1098141cc406Sopenharmony_ci{
1099141cc406Sopenharmony_ci  SANE_Int black_low = values->coarse_black, black_high = black_low + 10;
1100141cc406Sopenharmony_ci  SANE_Int white_high = values->coarse_white, white_low = white_high - 10;
1101141cc406Sopenharmony_ci  SANE_Bool done = SANE_TRUE;
1102141cc406Sopenharmony_ci  SANE_Byte local_pga = *pga;
1103141cc406Sopenharmony_ci  SANE_Byte local_offset = *offset;
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci  gt68xx_afe_ccd_calc (values, buffer);
1106141cc406Sopenharmony_ci
1107141cc406Sopenharmony_ci#if 0
1108141cc406Sopenharmony_ci  /* test all offset values */
1109141cc406Sopenharmony_ci  local_offset++;
1110141cc406Sopenharmony_ci  done = SANE_FALSE;
1111141cc406Sopenharmony_ci  goto finish;
1112141cc406Sopenharmony_ci#endif
1113141cc406Sopenharmony_ci
1114141cc406Sopenharmony_ci  if (values->white > white_high)
1115141cc406Sopenharmony_ci    {
1116141cc406Sopenharmony_ci      if (values->black > black_high)
1117141cc406Sopenharmony_ci	local_offset += values->offset_direction;
1118141cc406Sopenharmony_ci      else if (values->black < black_low)
1119141cc406Sopenharmony_ci	local_pga--;
1120141cc406Sopenharmony_ci      else
1121141cc406Sopenharmony_ci	{
1122141cc406Sopenharmony_ci	  local_offset += values->offset_direction;
1123141cc406Sopenharmony_ci	  local_pga--;
1124141cc406Sopenharmony_ci	}
1125141cc406Sopenharmony_ci      done = SANE_FALSE;
1126141cc406Sopenharmony_ci      goto finish;
1127141cc406Sopenharmony_ci    }
1128141cc406Sopenharmony_ci  else if (values->white < white_low)
1129141cc406Sopenharmony_ci    {
1130141cc406Sopenharmony_ci      if (values->black < black_low)
1131141cc406Sopenharmony_ci	local_offset -= values->offset_direction;
1132141cc406Sopenharmony_ci      else if (values->black > black_high)
1133141cc406Sopenharmony_ci	local_pga++;
1134141cc406Sopenharmony_ci      else
1135141cc406Sopenharmony_ci	{
1136141cc406Sopenharmony_ci	  local_offset -= values->offset_direction;
1137141cc406Sopenharmony_ci	  local_pga++;
1138141cc406Sopenharmony_ci	}
1139141cc406Sopenharmony_ci      done = SANE_FALSE;
1140141cc406Sopenharmony_ci      goto finish;
1141141cc406Sopenharmony_ci    }
1142141cc406Sopenharmony_ci  if (values->black > black_high)
1143141cc406Sopenharmony_ci    {
1144141cc406Sopenharmony_ci      if (values->white > white_high)
1145141cc406Sopenharmony_ci	local_offset += values->offset_direction;
1146141cc406Sopenharmony_ci      else if (values->white < white_low)
1147141cc406Sopenharmony_ci	local_pga++;
1148141cc406Sopenharmony_ci      else
1149141cc406Sopenharmony_ci	{
1150141cc406Sopenharmony_ci	  local_offset += values->offset_direction;
1151141cc406Sopenharmony_ci	  local_pga++;
1152141cc406Sopenharmony_ci	}
1153141cc406Sopenharmony_ci      done = SANE_FALSE;
1154141cc406Sopenharmony_ci      goto finish;
1155141cc406Sopenharmony_ci    }
1156141cc406Sopenharmony_ci  else if (values->black < black_low)
1157141cc406Sopenharmony_ci    {
1158141cc406Sopenharmony_ci      if (values->white < white_low)
1159141cc406Sopenharmony_ci	local_offset -= values->offset_direction;
1160141cc406Sopenharmony_ci      else if (values->white > white_high)
1161141cc406Sopenharmony_ci	local_pga--;
1162141cc406Sopenharmony_ci      else
1163141cc406Sopenharmony_ci	{
1164141cc406Sopenharmony_ci	  local_offset -= values->offset_direction;
1165141cc406Sopenharmony_ci	  local_pga--;
1166141cc406Sopenharmony_ci	}
1167141cc406Sopenharmony_ci      done = SANE_FALSE;
1168141cc406Sopenharmony_ci      goto finish;
1169141cc406Sopenharmony_ci    }
1170141cc406Sopenharmony_cifinish:
1171141cc406Sopenharmony_ci  if ((local_pga == *pga) && (local_offset == *offset))
1172141cc406Sopenharmony_ci    done = SANE_TRUE;
1173141cc406Sopenharmony_ci  if ((local_pga == *old_pga) && (local_offset == *old_offset))
1174141cc406Sopenharmony_ci    done = SANE_TRUE;
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci  *old_pga = *pga;
1177141cc406Sopenharmony_ci  *old_offset = *offset;
1178141cc406Sopenharmony_ci
1179141cc406Sopenharmony_ci  DBG (4, "%5s white=%3d, black=%3d, offset=%2d, gain=%2d, old offs=%2d, "
1180141cc406Sopenharmony_ci       "old gain=%2d, total_white=%5d %s\n", color_name, values->white,
1181141cc406Sopenharmony_ci       values->black, local_offset, local_pga, *offset, *pga,
1182141cc406Sopenharmony_ci       values->total_white, done ? "DONE " : "");
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci  *pga = local_pga;
1185141cc406Sopenharmony_ci  *offset = local_offset;
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci  return done;
1188141cc406Sopenharmony_ci}
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci/* Wait for lamp to give stable brightness */
1191141cc406Sopenharmony_cistatic SANE_Status
1192141cc406Sopenharmony_cigt68xx_wait_lamp_stable (GT68xx_Scanner * scanner,
1193141cc406Sopenharmony_ci			 GT68xx_Scan_Parameters * params,
1194141cc406Sopenharmony_ci			 GT68xx_Scan_Request *request,
1195141cc406Sopenharmony_ci			 unsigned int *buffer_pointers[3],
1196141cc406Sopenharmony_ci			 GT68xx_Afe_Values *values,
1197141cc406Sopenharmony_ci			 SANE_Bool dont_move)
1198141cc406Sopenharmony_ci{
1199141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
1200141cc406Sopenharmony_ci  SANE_Int last_white = 0;
1201141cc406Sopenharmony_ci  SANE_Bool first = SANE_TRUE;
1202141cc406Sopenharmony_ci  SANE_Bool message_printed = SANE_FALSE;
1203141cc406Sopenharmony_ci  struct timeval now, start_time;
1204141cc406Sopenharmony_ci  int secs_lamp_on, secs_start;
1205141cc406Sopenharmony_ci  int increase = -5;
1206141cc406Sopenharmony_ci
1207141cc406Sopenharmony_ci  gettimeofday (&start_time, 0);
1208141cc406Sopenharmony_ci  do
1209141cc406Sopenharmony_ci    {
1210141cc406Sopenharmony_ci      usleep (200000);
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci      if (!first && dont_move)
1213141cc406Sopenharmony_ci	{
1214141cc406Sopenharmony_ci	  request->mbs = SANE_FALSE;
1215141cc406Sopenharmony_ci	  request->mds = SANE_FALSE;
1216141cc406Sopenharmony_ci	}
1217141cc406Sopenharmony_ci      first = SANE_FALSE;
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci      /* read line */
1220141cc406Sopenharmony_ci      status = gt68xx_scanner_start_scan_extended (scanner, request,
1221141cc406Sopenharmony_ci						   SA_CALIBRATE_ONE_LINE,
1222141cc406Sopenharmony_ci						   params);
1223141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1224141cc406Sopenharmony_ci	{
1225141cc406Sopenharmony_ci	  DBG (3,
1226141cc406Sopenharmony_ci	       "gt68xx_wait_lamp_stable: gt68xx_scanner_start_scan_extended "
1227141cc406Sopenharmony_ci	       "failed: %s\n", sane_strstatus (status));
1228141cc406Sopenharmony_ci	  return status;
1229141cc406Sopenharmony_ci	}
1230141cc406Sopenharmony_ci      status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1231141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1232141cc406Sopenharmony_ci	{
1233141cc406Sopenharmony_ci	  DBG (3, "gt68xx_wait_lamp_stable: gt68xx_line_reader_read failed: %s\n",
1234141cc406Sopenharmony_ci	       sane_strstatus (status));
1235141cc406Sopenharmony_ci	  return status;
1236141cc406Sopenharmony_ci	}
1237141cc406Sopenharmony_ci      gt68xx_scanner_stop_scan (scanner);
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci      gt68xx_afe_ccd_calc (values, buffer_pointers[0]);
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci      DBG (4,
1242141cc406Sopenharmony_ci	   "gt68xx_wait_lamp_stable: this white = %d, last white = %d\n",
1243141cc406Sopenharmony_ci	   values->total_white, last_white);
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci      gettimeofday (&now, 0);
1246141cc406Sopenharmony_ci      secs_lamp_on = now.tv_sec - scanner->lamp_on_time.tv_sec;
1247141cc406Sopenharmony_ci      secs_start = now.tv_sec - start_time.tv_sec;
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci      if (!message_printed && secs_start > 5)
1250141cc406Sopenharmony_ci	{
1251141cc406Sopenharmony_ci	  DBG (0, "Please wait for lamp warm-up\n");
1252141cc406Sopenharmony_ci	  message_printed = SANE_TRUE;
1253141cc406Sopenharmony_ci	}
1254141cc406Sopenharmony_ci
1255141cc406Sopenharmony_ci      if (scanner->val[OPT_AUTO_WARMUP].w == SANE_TRUE)
1256141cc406Sopenharmony_ci	{
1257141cc406Sopenharmony_ci	  if (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP)
1258141cc406Sopenharmony_ci	    {
1259141cc406Sopenharmony_ci	      if (values->total_white <= (last_white - 20))
1260141cc406Sopenharmony_ci		  increase--;
1261141cc406Sopenharmony_ci	      if (values->total_white >= last_white)
1262141cc406Sopenharmony_ci		  increase++;
1263141cc406Sopenharmony_ci	      if (increase > 0 && (values->total_white <= (last_white + 20))
1264141cc406Sopenharmony_ci		  && values->total_white != 0)
1265141cc406Sopenharmony_ci		break;
1266141cc406Sopenharmony_ci	    }
1267141cc406Sopenharmony_ci	  else
1268141cc406Sopenharmony_ci	    {
1269141cc406Sopenharmony_ci	      if ((values->total_white <= (last_white + 20))
1270141cc406Sopenharmony_ci		  && values->total_white != 0)
1271141cc406Sopenharmony_ci		break;		/* lamp is warmed up */
1272141cc406Sopenharmony_ci	    }
1273141cc406Sopenharmony_ci	}
1274141cc406Sopenharmony_ci      last_white = values->total_white;
1275141cc406Sopenharmony_ci    }
1276141cc406Sopenharmony_ci  while (secs_lamp_on <= WARMUP_TIME);
1277141cc406Sopenharmony_ci
1278141cc406Sopenharmony_ci  DBG (3, "gt68xx_wait_lamp_stable: Lamp is stable after %d secs (%d secs total)\n",
1279141cc406Sopenharmony_ci       secs_start, secs_lamp_on);
1280141cc406Sopenharmony_ci  return status;
1281141cc406Sopenharmony_ci}
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci/** Select best AFE gain and offset parameters.
1284141cc406Sopenharmony_ci *
1285141cc406Sopenharmony_ci * This function must be called before the main scan to choose the best values
1286141cc406Sopenharmony_ci * for the AFE gains and offsets.  It performs several one-line scans of the
1287141cc406Sopenharmony_ci * calibration strip.
1288141cc406Sopenharmony_ci *
1289141cc406Sopenharmony_ci * @param scanner Scanner object.
1290141cc406Sopenharmony_ci * @param orig_request Scan parameters.
1291141cc406Sopenharmony_ci *
1292141cc406Sopenharmony_ci * @returns
1293141cc406Sopenharmony_ci * - #SANE_STATUS_GOOD - gain and offset setting completed successfully
1294141cc406Sopenharmony_ci * - other error value - failure of some internal function
1295141cc406Sopenharmony_ci */
1296141cc406Sopenharmony_cistatic SANE_Status
1297141cc406Sopenharmony_cigt68xx_afe_ccd_auto (GT68xx_Scanner * scanner,
1298141cc406Sopenharmony_ci		     GT68xx_Scan_Request * orig_request)
1299141cc406Sopenharmony_ci{
1300141cc406Sopenharmony_ci  SANE_Status status;
1301141cc406Sopenharmony_ci  GT68xx_Scan_Parameters params;
1302141cc406Sopenharmony_ci  GT68xx_Scan_Request request;
1303141cc406Sopenharmony_ci  int i;
1304141cc406Sopenharmony_ci  GT68xx_Afe_Values values;
1305141cc406Sopenharmony_ci  unsigned int *buffer_pointers[3];
1306141cc406Sopenharmony_ci  GT68xx_AFE_Parameters *afe = scanner->dev->afe, old_afe;
1307141cc406Sopenharmony_ci  SANE_Bool gray_done = SANE_FALSE;
1308141cc406Sopenharmony_ci  SANE_Bool red_done = SANE_FALSE, green_done = SANE_FALSE, blue_done =
1309141cc406Sopenharmony_ci    SANE_FALSE;
1310141cc406Sopenharmony_ci
1311141cc406Sopenharmony_ci  values.offset_direction = 1;
1312141cc406Sopenharmony_ci  if (scanner->dev->model->flags & GT68XX_FLAG_OFFSET_INV)
1313141cc406Sopenharmony_ci    values.offset_direction = -1;
1314141cc406Sopenharmony_ci
1315141cc406Sopenharmony_ci  memset (&old_afe, 255, sizeof (old_afe));
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_ci  request.x0 = SANE_FIX (0.0);
1318141cc406Sopenharmony_ci  request.xs = scanner->dev->model->x_size;
1319141cc406Sopenharmony_ci  request.xdpi = 300;
1320141cc406Sopenharmony_ci  request.ydpi = 300;
1321141cc406Sopenharmony_ci  request.depth = 8;
1322141cc406Sopenharmony_ci  request.color = orig_request->color;
1323141cc406Sopenharmony_ci  /*  request.color = SANE_TRUE; */
1324141cc406Sopenharmony_ci  request.mas = SANE_FALSE;
1325141cc406Sopenharmony_ci  request.mbs = SANE_FALSE;
1326141cc406Sopenharmony_ci  request.mds = SANE_TRUE;
1327141cc406Sopenharmony_ci  request.calculate = SANE_FALSE;
1328141cc406Sopenharmony_ci  request.use_ta = orig_request->use_ta;
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci  if (orig_request->use_ta)
1331141cc406Sopenharmony_ci    {
1332141cc406Sopenharmony_ci      gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
1333141cc406Sopenharmony_ci      request.lamp = SANE_FALSE;
1334141cc406Sopenharmony_ci    }
1335141cc406Sopenharmony_ci  else
1336141cc406Sopenharmony_ci    {
1337141cc406Sopenharmony_ci      gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
1338141cc406Sopenharmony_ci      request.lamp = SANE_TRUE;
1339141cc406Sopenharmony_ci    }
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci  /* read line */
1342141cc406Sopenharmony_ci  status = gt68xx_scanner_start_scan_extended (scanner, &request,
1343141cc406Sopenharmony_ci					       SA_CALIBRATE_ONE_LINE,
1344141cc406Sopenharmony_ci					       &params);
1345141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1346141cc406Sopenharmony_ci    {
1347141cc406Sopenharmony_ci      DBG (3,
1348141cc406Sopenharmony_ci	   "gt68xx_afe_ccd_auto: gt68xx_scanner_start_scan_extended failed: %s\n",
1349141cc406Sopenharmony_ci	   sane_strstatus (status));
1350141cc406Sopenharmony_ci      return status;
1351141cc406Sopenharmony_ci    }
1352141cc406Sopenharmony_ci  values.scan_dpi = params.xdpi;
1353141cc406Sopenharmony_ci  values.calwidth = params.pixel_xs;
1354141cc406Sopenharmony_ci  values.max_width =
1355141cc406Sopenharmony_ci    (params.pixel_xs * scanner->dev->model->optical_xdpi) / params.xdpi;
1356141cc406Sopenharmony_ci  if (orig_request->use_ta)
1357141cc406Sopenharmony_ci    values.start_black = SANE_FIX (20.0);
1358141cc406Sopenharmony_ci  else
1359141cc406Sopenharmony_ci    values.start_black = scanner->dev->model->x_offset_mark;
1360141cc406Sopenharmony_ci  values.coarse_black = 1;
1361141cc406Sopenharmony_ci  values.coarse_white = 254;
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci  request.mds = SANE_FALSE;
1364141cc406Sopenharmony_ci  DBG (5, "gt68xx_afe_ccd_auto: scan_dpi=%d, calwidth=%d, max_width=%d, "
1365141cc406Sopenharmony_ci       "start_black=%.1f mm\n", values.scan_dpi,
1366141cc406Sopenharmony_ci       values.calwidth, values.max_width, SANE_UNFIX (values.start_black));
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci  status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1369141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1370141cc406Sopenharmony_ci    {
1371141cc406Sopenharmony_ci      DBG (3, "gt68xx_afe_ccd_auto: gt68xx_line_reader_read failed: %s\n",
1372141cc406Sopenharmony_ci	   sane_strstatus (status));
1373141cc406Sopenharmony_ci      return status;
1374141cc406Sopenharmony_ci    }
1375141cc406Sopenharmony_ci  gt68xx_scanner_stop_scan (scanner);
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci  status = gt68xx_wait_lamp_stable (scanner, &params, &request, buffer_pointers,
1378141cc406Sopenharmony_ci				    &values, SANE_FALSE);
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1381141cc406Sopenharmony_ci    {
1382141cc406Sopenharmony_ci      DBG (1, "gt68xx_afe_ccd_auto: gt68xx_wait_lamp_stable failed %s\n",
1383141cc406Sopenharmony_ci	   sane_strstatus (status));
1384141cc406Sopenharmony_ci      return status;
1385141cc406Sopenharmony_ci    }
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci  i = 0;
1388141cc406Sopenharmony_ci  do
1389141cc406Sopenharmony_ci    {
1390141cc406Sopenharmony_ci      i++;
1391141cc406Sopenharmony_ci      /* read line */
1392141cc406Sopenharmony_ci      status = gt68xx_scanner_start_scan_extended (scanner, &request,
1393141cc406Sopenharmony_ci						   SA_CALIBRATE_ONE_LINE,
1394141cc406Sopenharmony_ci						   &params);
1395141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1396141cc406Sopenharmony_ci	{
1397141cc406Sopenharmony_ci	  DBG (3,
1398141cc406Sopenharmony_ci	       "gt68xx_afe_ccd_auto: gt68xx_scanner_start_scan_extended failed: %s\n",
1399141cc406Sopenharmony_ci	       sane_strstatus (status));
1400141cc406Sopenharmony_ci	  return status;
1401141cc406Sopenharmony_ci	}
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci      status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1404141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1405141cc406Sopenharmony_ci	{
1406141cc406Sopenharmony_ci	  DBG (3, "gt68xx_afe_ccd_auto: gt68xx_line_reader_read failed: %s\n",
1407141cc406Sopenharmony_ci	       sane_strstatus (status));
1408141cc406Sopenharmony_ci	  return status;
1409141cc406Sopenharmony_ci	}
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci      if (params.color)
1412141cc406Sopenharmony_ci	{
1413141cc406Sopenharmony_ci	  /* red */
1414141cc406Sopenharmony_ci	  if (!red_done)
1415141cc406Sopenharmony_ci	    red_done =
1416141cc406Sopenharmony_ci	      gt68xx_afe_ccd_adjust_offset_gain ("red", &values,
1417141cc406Sopenharmony_ci						 buffer_pointers[0],
1418141cc406Sopenharmony_ci						 &afe->r_offset, &afe->r_pga,
1419141cc406Sopenharmony_ci						 &old_afe.r_offset,
1420141cc406Sopenharmony_ci						 &old_afe.r_pga);
1421141cc406Sopenharmony_ci	  /* green */
1422141cc406Sopenharmony_ci	  if (!green_done)
1423141cc406Sopenharmony_ci	    green_done =
1424141cc406Sopenharmony_ci	      gt68xx_afe_ccd_adjust_offset_gain ("green", &values,
1425141cc406Sopenharmony_ci						 buffer_pointers[1],
1426141cc406Sopenharmony_ci						 &afe->g_offset, &afe->g_pga,
1427141cc406Sopenharmony_ci						 &old_afe.g_offset,
1428141cc406Sopenharmony_ci						 &old_afe.g_pga);
1429141cc406Sopenharmony_ci
1430141cc406Sopenharmony_ci	  /* blue */
1431141cc406Sopenharmony_ci	  if (!blue_done)
1432141cc406Sopenharmony_ci	    blue_done =
1433141cc406Sopenharmony_ci	      gt68xx_afe_ccd_adjust_offset_gain ("blue", &values,
1434141cc406Sopenharmony_ci						 buffer_pointers[2],
1435141cc406Sopenharmony_ci						 &afe->b_offset, &afe->b_pga,
1436141cc406Sopenharmony_ci						 &old_afe.b_offset,
1437141cc406Sopenharmony_ci						 &old_afe.b_pga);
1438141cc406Sopenharmony_ci	}
1439141cc406Sopenharmony_ci      else
1440141cc406Sopenharmony_ci	{
1441141cc406Sopenharmony_ci	  if (strcmp (scanner->val[OPT_GRAY_MODE_COLOR].s, GT68XX_COLOR_BLUE)
1442141cc406Sopenharmony_ci	      == 0)
1443141cc406Sopenharmony_ci	    {
1444141cc406Sopenharmony_ci	      gray_done =
1445141cc406Sopenharmony_ci		gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1446141cc406Sopenharmony_ci						   buffer_pointers[0],
1447141cc406Sopenharmony_ci						   &afe->b_offset,
1448141cc406Sopenharmony_ci						   &afe->b_pga,
1449141cc406Sopenharmony_ci						   &old_afe.b_offset,
1450141cc406Sopenharmony_ci						   &old_afe.b_pga);
1451141cc406Sopenharmony_ci	    }
1452141cc406Sopenharmony_ci	  else
1453141cc406Sopenharmony_ci	    if (strcmp
1454141cc406Sopenharmony_ci		(scanner->val[OPT_GRAY_MODE_COLOR].s,
1455141cc406Sopenharmony_ci		 GT68XX_COLOR_GREEN) == 0)
1456141cc406Sopenharmony_ci	    {
1457141cc406Sopenharmony_ci	      gray_done =
1458141cc406Sopenharmony_ci		gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1459141cc406Sopenharmony_ci						   buffer_pointers[0],
1460141cc406Sopenharmony_ci						   &afe->g_offset,
1461141cc406Sopenharmony_ci						   &afe->g_pga,
1462141cc406Sopenharmony_ci						   &old_afe.g_offset,
1463141cc406Sopenharmony_ci						   &old_afe.g_pga);
1464141cc406Sopenharmony_ci	      afe->r_offset = afe->b_offset = 0x20;
1465141cc406Sopenharmony_ci	      afe->r_pga = afe->b_pga = 0x18;
1466141cc406Sopenharmony_ci	    }
1467141cc406Sopenharmony_ci	  else
1468141cc406Sopenharmony_ci	    {
1469141cc406Sopenharmony_ci	      gray_done =
1470141cc406Sopenharmony_ci		gt68xx_afe_ccd_adjust_offset_gain ("gray", &values,
1471141cc406Sopenharmony_ci						   buffer_pointers[0],
1472141cc406Sopenharmony_ci						   &afe->r_offset,
1473141cc406Sopenharmony_ci						   &afe->r_pga,
1474141cc406Sopenharmony_ci						   &old_afe.r_offset,
1475141cc406Sopenharmony_ci						   &old_afe.r_pga);
1476141cc406Sopenharmony_ci	    }
1477141cc406Sopenharmony_ci	}
1478141cc406Sopenharmony_ci      gt68xx_scanner_stop_scan (scanner);
1479141cc406Sopenharmony_ci    }
1480141cc406Sopenharmony_ci  while (((params.color && (!red_done || !green_done || !blue_done))
1481141cc406Sopenharmony_ci	  || (!params.color && !gray_done)) && i < 100);
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  return status;
1484141cc406Sopenharmony_ci}
1485141cc406Sopenharmony_ci
1486141cc406Sopenharmony_ci/************************************************************************/
1487141cc406Sopenharmony_ci/* CIS scanners                                                         */
1488141cc406Sopenharmony_ci/************************************************************************/
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_cistatic void
1492141cc406Sopenharmony_cigt68xx_afe_cis_calc_black (GT68xx_Afe_Values * values,
1493141cc406Sopenharmony_ci			   unsigned int *black_buffer)
1494141cc406Sopenharmony_ci{
1495141cc406Sopenharmony_ci  SANE_Int start_black;
1496141cc406Sopenharmony_ci  SANE_Int end_black;
1497141cc406Sopenharmony_ci  SANE_Int i, j;
1498141cc406Sopenharmony_ci  SANE_Int min_black = 255;
1499141cc406Sopenharmony_ci  SANE_Int average = 0;
1500141cc406Sopenharmony_ci
1501141cc406Sopenharmony_ci  start_black = 0;
1502141cc406Sopenharmony_ci  end_black = values->calwidth;
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  /* find min average black value */
1505141cc406Sopenharmony_ci  for (i = start_black; i < end_black; ++i)
1506141cc406Sopenharmony_ci    {
1507141cc406Sopenharmony_ci      SANE_Int avg_black = 0;
1508141cc406Sopenharmony_ci      for (j = 0; j < values->callines; j++)
1509141cc406Sopenharmony_ci	avg_black += (*(black_buffer + i + j * values->calwidth) >> 8);
1510141cc406Sopenharmony_ci      avg_black /= values->callines;
1511141cc406Sopenharmony_ci      average += avg_black;
1512141cc406Sopenharmony_ci      if (avg_black < min_black)
1513141cc406Sopenharmony_ci	min_black = avg_black;
1514141cc406Sopenharmony_ci    }
1515141cc406Sopenharmony_ci  values->black = min_black;
1516141cc406Sopenharmony_ci  average /= (end_black - start_black);
1517141cc406Sopenharmony_ci  DBG (5,
1518141cc406Sopenharmony_ci       "gt68xx_afe_cis_calc_black: min_black=0x%02x, average_black=0x%02x\n",
1519141cc406Sopenharmony_ci       values->black, average);
1520141cc406Sopenharmony_ci}
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_cistatic void
1523141cc406Sopenharmony_cigt68xx_afe_cis_calc_white (GT68xx_Afe_Values * values,
1524141cc406Sopenharmony_ci			   unsigned int *white_buffer)
1525141cc406Sopenharmony_ci{
1526141cc406Sopenharmony_ci  SANE_Int start_white;
1527141cc406Sopenharmony_ci  SANE_Int end_white;
1528141cc406Sopenharmony_ci  SANE_Int i, j;
1529141cc406Sopenharmony_ci  SANE_Int max_white = 0;
1530141cc406Sopenharmony_ci
1531141cc406Sopenharmony_ci  start_white = 0;
1532141cc406Sopenharmony_ci  end_white = values->calwidth;
1533141cc406Sopenharmony_ci  values->total_white = 0;
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci  /* find max average white value */
1536141cc406Sopenharmony_ci  for (i = start_white; i < end_white; ++i)
1537141cc406Sopenharmony_ci    {
1538141cc406Sopenharmony_ci      SANE_Int avg_white = 0;
1539141cc406Sopenharmony_ci      for (j = 0; j < values->callines; j++)
1540141cc406Sopenharmony_ci	{
1541141cc406Sopenharmony_ci	  avg_white += (*(white_buffer + i + j * values->calwidth) >> 8);
1542141cc406Sopenharmony_ci	  values->total_white += (*(white_buffer + i + j * values->calwidth));
1543141cc406Sopenharmony_ci	}
1544141cc406Sopenharmony_ci      avg_white /= values->callines;
1545141cc406Sopenharmony_ci      if (avg_white > max_white)
1546141cc406Sopenharmony_ci	max_white = avg_white;
1547141cc406Sopenharmony_ci    }
1548141cc406Sopenharmony_ci  values->white = max_white;
1549141cc406Sopenharmony_ci  values->total_white /= (values->callines * (end_white - start_white));
1550141cc406Sopenharmony_ci  DBG (5,
1551141cc406Sopenharmony_ci       "gt68xx_afe_cis_calc_white: max_white=0x%02x, average_white=0x%02x\n",
1552141cc406Sopenharmony_ci       values->white, values->total_white >> 8);
1553141cc406Sopenharmony_ci}
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_cistatic SANE_Bool
1556141cc406Sopenharmony_cigt68xx_afe_cis_adjust_gain_offset (SANE_String_Const color_name,
1557141cc406Sopenharmony_ci				   GT68xx_Afe_Values * values,
1558141cc406Sopenharmony_ci				   unsigned int *black_buffer,
1559141cc406Sopenharmony_ci				   unsigned int *white_buffer,
1560141cc406Sopenharmony_ci				   GT68xx_AFE_Parameters * afe,
1561141cc406Sopenharmony_ci				   GT68xx_AFE_Parameters * old_afe)
1562141cc406Sopenharmony_ci{
1563141cc406Sopenharmony_ci  SANE_Byte *offset, *old_offset, *gain, *old_gain;
1564141cc406Sopenharmony_ci  SANE_Int o, g;
1565141cc406Sopenharmony_ci  SANE_Int black_low = values->coarse_black, black_high = black_low + 10;
1566141cc406Sopenharmony_ci  SANE_Int white_high = values->coarse_white, white_low = white_high - 10;
1567141cc406Sopenharmony_ci  SANE_Bool done = SANE_TRUE;
1568141cc406Sopenharmony_ci
1569141cc406Sopenharmony_ci  gt68xx_afe_cis_calc_black (values, black_buffer);
1570141cc406Sopenharmony_ci  gt68xx_afe_cis_calc_white (values, white_buffer);
1571141cc406Sopenharmony_ci
1572141cc406Sopenharmony_ci  if (strcmp (color_name, "red") == 0)
1573141cc406Sopenharmony_ci    {
1574141cc406Sopenharmony_ci      offset = &(afe->r_offset);
1575141cc406Sopenharmony_ci      old_offset = &old_afe->r_offset;
1576141cc406Sopenharmony_ci      gain = &afe->r_pga;
1577141cc406Sopenharmony_ci      old_gain = &old_afe->r_pga;
1578141cc406Sopenharmony_ci    }
1579141cc406Sopenharmony_ci  else if (strcmp (color_name, "green") == 0)
1580141cc406Sopenharmony_ci    {
1581141cc406Sopenharmony_ci      offset = &afe->g_offset;
1582141cc406Sopenharmony_ci      old_offset = &old_afe->g_offset;
1583141cc406Sopenharmony_ci      gain = &afe->g_pga;
1584141cc406Sopenharmony_ci      old_gain = &old_afe->g_pga;
1585141cc406Sopenharmony_ci    }
1586141cc406Sopenharmony_ci  else
1587141cc406Sopenharmony_ci    {
1588141cc406Sopenharmony_ci      offset = &afe->b_offset;
1589141cc406Sopenharmony_ci      old_offset = &old_afe->b_offset;
1590141cc406Sopenharmony_ci      gain = &afe->b_pga;
1591141cc406Sopenharmony_ci      old_gain = &old_afe->b_pga;
1592141cc406Sopenharmony_ci    }
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci  o = *offset;
1595141cc406Sopenharmony_ci  g = *gain;
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  if (values->white > white_high)
1598141cc406Sopenharmony_ci    {
1599141cc406Sopenharmony_ci      if (values->black > black_high)
1600141cc406Sopenharmony_ci	o -= values->offset_direction;
1601141cc406Sopenharmony_ci      else if (values->black < black_low)
1602141cc406Sopenharmony_ci	g--;
1603141cc406Sopenharmony_ci      else
1604141cc406Sopenharmony_ci	{
1605141cc406Sopenharmony_ci	  o -= values->offset_direction;
1606141cc406Sopenharmony_ci	  g--;
1607141cc406Sopenharmony_ci	}
1608141cc406Sopenharmony_ci      done = SANE_FALSE;
1609141cc406Sopenharmony_ci      goto finish;
1610141cc406Sopenharmony_ci    }
1611141cc406Sopenharmony_ci  else if (values->white < white_low)
1612141cc406Sopenharmony_ci    {
1613141cc406Sopenharmony_ci      if (values->black < black_low)
1614141cc406Sopenharmony_ci	o += values->offset_direction;
1615141cc406Sopenharmony_ci      else if (values->black > black_high)
1616141cc406Sopenharmony_ci	g++;
1617141cc406Sopenharmony_ci      else
1618141cc406Sopenharmony_ci	{
1619141cc406Sopenharmony_ci	  o += values->offset_direction;
1620141cc406Sopenharmony_ci	  g++;
1621141cc406Sopenharmony_ci	}
1622141cc406Sopenharmony_ci      done = SANE_FALSE;
1623141cc406Sopenharmony_ci      goto finish;
1624141cc406Sopenharmony_ci    }
1625141cc406Sopenharmony_ci  if (values->black > black_high)
1626141cc406Sopenharmony_ci    {
1627141cc406Sopenharmony_ci      if (values->white > white_high)
1628141cc406Sopenharmony_ci	o -= values->offset_direction;
1629141cc406Sopenharmony_ci      else if (values->white < white_low)
1630141cc406Sopenharmony_ci	g++;
1631141cc406Sopenharmony_ci      else
1632141cc406Sopenharmony_ci	{
1633141cc406Sopenharmony_ci	  o -= values->offset_direction;
1634141cc406Sopenharmony_ci	  g++;
1635141cc406Sopenharmony_ci	}
1636141cc406Sopenharmony_ci      done = SANE_FALSE;
1637141cc406Sopenharmony_ci      goto finish;
1638141cc406Sopenharmony_ci    }
1639141cc406Sopenharmony_ci  else if (values->black < black_low)
1640141cc406Sopenharmony_ci    {
1641141cc406Sopenharmony_ci      if (values->white < white_low)
1642141cc406Sopenharmony_ci	o += values->offset_direction;
1643141cc406Sopenharmony_ci      else if (values->white > white_high)
1644141cc406Sopenharmony_ci	g--;
1645141cc406Sopenharmony_ci      else
1646141cc406Sopenharmony_ci	{
1647141cc406Sopenharmony_ci	  o += values->offset_direction;
1648141cc406Sopenharmony_ci	  g--;
1649141cc406Sopenharmony_ci	}
1650141cc406Sopenharmony_ci      done = SANE_FALSE;
1651141cc406Sopenharmony_ci      goto finish;
1652141cc406Sopenharmony_ci    }
1653141cc406Sopenharmony_cifinish:
1654141cc406Sopenharmony_ci  if (g < 0)
1655141cc406Sopenharmony_ci    g = 0;
1656141cc406Sopenharmony_ci  if (g > 48)
1657141cc406Sopenharmony_ci    g = 48;
1658141cc406Sopenharmony_ci  if (o < 0)
1659141cc406Sopenharmony_ci    o = 0;
1660141cc406Sopenharmony_ci  if (o > 64)
1661141cc406Sopenharmony_ci    o = 64;
1662141cc406Sopenharmony_ci
1663141cc406Sopenharmony_ci  if ((g == *gain) && (o == *offset))
1664141cc406Sopenharmony_ci    done = SANE_TRUE;
1665141cc406Sopenharmony_ci  if ((g == *old_gain) && (o == *old_offset))
1666141cc406Sopenharmony_ci    done = SANE_TRUE;
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci  *old_gain = *gain;
1669141cc406Sopenharmony_ci  *old_offset = *offset;
1670141cc406Sopenharmony_ci
1671141cc406Sopenharmony_ci  DBG (4, "%5s white=%3d, black=%3d, offset=0x%02X, gain=0x%02X, old offs=0x%02X, "
1672141cc406Sopenharmony_ci       "old gain=0x%02X, total_white=%5d %s\n", color_name, values->white,
1673141cc406Sopenharmony_ci       values->black, o, g, *offset, *gain, values->total_white,
1674141cc406Sopenharmony_ci       done ? "DONE " : "");
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci  *gain = g;
1677141cc406Sopenharmony_ci  *offset = o;
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci  return done;
1680141cc406Sopenharmony_ci}
1681141cc406Sopenharmony_ci
1682141cc406Sopenharmony_ci
1683141cc406Sopenharmony_cistatic SANE_Bool
1684141cc406Sopenharmony_cigt68xx_afe_cis_adjust_exposure (SANE_String_Const color_name,
1685141cc406Sopenharmony_ci				GT68xx_Afe_Values * values,
1686141cc406Sopenharmony_ci				unsigned int *white_buffer, SANE_Int border,
1687141cc406Sopenharmony_ci				SANE_Int * exposure_time)
1688141cc406Sopenharmony_ci{
1689141cc406Sopenharmony_ci  SANE_Int exposure_change = 0;
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci  gt68xx_afe_cis_calc_white (values, white_buffer);
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci  if (values->white < border)
1694141cc406Sopenharmony_ci    {
1695141cc406Sopenharmony_ci      exposure_change = ((border - values->white) * 1);
1696141cc406Sopenharmony_ci      (*exposure_time) += exposure_change;
1697141cc406Sopenharmony_ci      DBG (4,
1698141cc406Sopenharmony_ci	   "%5s: white = %3d, total_white=%5d (exposure too low) --> exposure += %d (=0x%03x)\n",
1699141cc406Sopenharmony_ci	   color_name, values->white, values->total_white, exposure_change, *exposure_time);
1700141cc406Sopenharmony_ci      return SANE_FALSE;
1701141cc406Sopenharmony_ci    }
1702141cc406Sopenharmony_ci  else if (values->white > border + 5)
1703141cc406Sopenharmony_ci    {
1704141cc406Sopenharmony_ci      exposure_change = -((values->white - (border + 5)) * 1);
1705141cc406Sopenharmony_ci      (*exposure_time) += exposure_change;
1706141cc406Sopenharmony_ci      DBG (4,
1707141cc406Sopenharmony_ci	   "%5s: white = %3d, total_white=%5d (exposure too high) --> exposure -= %d (=0x%03x)\n",
1708141cc406Sopenharmony_ci	   color_name, values->white, values->total_white, exposure_change, *exposure_time);
1709141cc406Sopenharmony_ci      return SANE_FALSE;
1710141cc406Sopenharmony_ci    }
1711141cc406Sopenharmony_ci  else
1712141cc406Sopenharmony_ci    {
1713141cc406Sopenharmony_ci      DBG (4, "%5s: white = %3d, total_white=%5d (exposure ok=0x%03x)\n",
1714141cc406Sopenharmony_ci	   color_name, values->white, values->total_white, *exposure_time);
1715141cc406Sopenharmony_ci    }
1716141cc406Sopenharmony_ci  return SANE_TRUE;
1717141cc406Sopenharmony_ci}
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_cistatic SANE_Status
1720141cc406Sopenharmony_cigt68xx_afe_cis_read_lines (GT68xx_Afe_Values * values,
1721141cc406Sopenharmony_ci			   GT68xx_Scanner * scanner, SANE_Bool lamp,
1722141cc406Sopenharmony_ci			   SANE_Bool first, unsigned int *r_buffer,
1723141cc406Sopenharmony_ci			   unsigned int *g_buffer, unsigned int *b_buffer)
1724141cc406Sopenharmony_ci{
1725141cc406Sopenharmony_ci  SANE_Status status;
1726141cc406Sopenharmony_ci  int line;
1727141cc406Sopenharmony_ci  unsigned int *buffer_pointers[3];
1728141cc406Sopenharmony_ci  GT68xx_Scan_Request request;
1729141cc406Sopenharmony_ci  GT68xx_Scan_Parameters params;
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci  request.x0 = SANE_FIX (0.0);
1732141cc406Sopenharmony_ci  request.xs = scanner->dev->model->x_size;
1733141cc406Sopenharmony_ci  request.xdpi = 300;
1734141cc406Sopenharmony_ci  request.ydpi = 300;
1735141cc406Sopenharmony_ci  request.depth = 8;
1736141cc406Sopenharmony_ci  request.color = SANE_TRUE;
1737141cc406Sopenharmony_ci  request.mas = SANE_FALSE;
1738141cc406Sopenharmony_ci  request.calculate = SANE_FALSE;
1739141cc406Sopenharmony_ci  request.use_ta = SANE_FALSE;
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci  if (first)			/* go to start position */
1742141cc406Sopenharmony_ci    {
1743141cc406Sopenharmony_ci      request.mbs = SANE_TRUE;
1744141cc406Sopenharmony_ci      request.mds = SANE_TRUE;
1745141cc406Sopenharmony_ci    }
1746141cc406Sopenharmony_ci  else
1747141cc406Sopenharmony_ci    {
1748141cc406Sopenharmony_ci      request.mbs = SANE_FALSE;
1749141cc406Sopenharmony_ci      request.mds = SANE_FALSE;
1750141cc406Sopenharmony_ci    }
1751141cc406Sopenharmony_ci  request.lamp = lamp;
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_ci  if (!r_buffer)		/* First, set the size parameters */
1754141cc406Sopenharmony_ci    {
1755141cc406Sopenharmony_ci      request.calculate = SANE_TRUE;
1756141cc406Sopenharmony_ci      RIE (gt68xx_device_setup_scan
1757141cc406Sopenharmony_ci	   (scanner->dev, &request, SA_CALIBRATE_ONE_LINE, &params));
1758141cc406Sopenharmony_ci      values->scan_dpi = params.xdpi;
1759141cc406Sopenharmony_ci      values->calwidth = params.pixel_xs;
1760141cc406Sopenharmony_ci      values->callines = params.pixel_ys;
1761141cc406Sopenharmony_ci      values->start_black = scanner->dev->model->x_offset_mark;
1762141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1763141cc406Sopenharmony_ci    }
1764141cc406Sopenharmony_ci
1765141cc406Sopenharmony_ci  if (first && (scanner->dev->model->flags & GT68XX_FLAG_CIS_LAMP))
1766141cc406Sopenharmony_ci    {
1767141cc406Sopenharmony_ci      if (request.use_ta)
1768141cc406Sopenharmony_ci	{
1769141cc406Sopenharmony_ci	  gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
1770141cc406Sopenharmony_ci	  request.lamp = SANE_FALSE;
1771141cc406Sopenharmony_ci	}
1772141cc406Sopenharmony_ci      else
1773141cc406Sopenharmony_ci	{
1774141cc406Sopenharmony_ci	  gt68xx_device_lamp_control (scanner->dev, SANE_TRUE, SANE_FALSE);
1775141cc406Sopenharmony_ci	  request.lamp = SANE_TRUE;
1776141cc406Sopenharmony_ci	}
1777141cc406Sopenharmony_ci      status = gt68xx_wait_lamp_stable (scanner, &params, &request,
1778141cc406Sopenharmony_ci					buffer_pointers, values, SANE_TRUE);
1779141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1780141cc406Sopenharmony_ci	{
1781141cc406Sopenharmony_ci	  DBG (1, "gt68xx_afe_cis_read_lines: gt68xx_wait_lamp_stable failed %s\n",
1782141cc406Sopenharmony_ci	       sane_strstatus (status));
1783141cc406Sopenharmony_ci	  return status;
1784141cc406Sopenharmony_ci	}
1785141cc406Sopenharmony_ci      request.mbs = SANE_FALSE;
1786141cc406Sopenharmony_ci      request.mds = SANE_FALSE;
1787141cc406Sopenharmony_ci    }
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci  status =
1790141cc406Sopenharmony_ci    gt68xx_scanner_start_scan_extended (scanner, &request,
1791141cc406Sopenharmony_ci					SA_CALIBRATE_ONE_LINE, &params);
1792141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1793141cc406Sopenharmony_ci    {
1794141cc406Sopenharmony_ci      DBG (5,
1795141cc406Sopenharmony_ci	   "gt68xx_afe_cis_read_lines: gt68xx_scanner_start_scan_extended failed: %s\n",
1796141cc406Sopenharmony_ci	   sane_strstatus (status));
1797141cc406Sopenharmony_ci      return status;
1798141cc406Sopenharmony_ci    }
1799141cc406Sopenharmony_ci  values->scan_dpi = params.xdpi;
1800141cc406Sopenharmony_ci  values->calwidth = params.pixel_xs;
1801141cc406Sopenharmony_ci  values->callines = params.pixel_ys;
1802141cc406Sopenharmony_ci  values->coarse_black = 2;
1803141cc406Sopenharmony_ci  values->coarse_white = 253;
1804141cc406Sopenharmony_ci
1805141cc406Sopenharmony_ci  if (r_buffer && g_buffer && b_buffer)
1806141cc406Sopenharmony_ci    for (line = 0; line < values->callines; line++)
1807141cc406Sopenharmony_ci      {
1808141cc406Sopenharmony_ci	status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
1809141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
1810141cc406Sopenharmony_ci	  {
1811141cc406Sopenharmony_ci	    DBG (5,
1812141cc406Sopenharmony_ci		 "gt68xx_afe_cis_read_lines: gt68xx_line_reader_read failed: %s\n",
1813141cc406Sopenharmony_ci		 sane_strstatus (status));
1814141cc406Sopenharmony_ci	    return status;
1815141cc406Sopenharmony_ci	  }
1816141cc406Sopenharmony_ci	memcpy (r_buffer + values->calwidth * line, buffer_pointers[0],
1817141cc406Sopenharmony_ci		values->calwidth * sizeof (unsigned int));
1818141cc406Sopenharmony_ci	memcpy (g_buffer + values->calwidth * line, buffer_pointers[1],
1819141cc406Sopenharmony_ci		values->calwidth * sizeof (unsigned int));
1820141cc406Sopenharmony_ci	memcpy (b_buffer + values->calwidth * line, buffer_pointers[2],
1821141cc406Sopenharmony_ci		values->calwidth * sizeof (unsigned int));
1822141cc406Sopenharmony_ci      }
1823141cc406Sopenharmony_ci
1824141cc406Sopenharmony_ci  status = gt68xx_scanner_stop_scan (scanner);
1825141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1826141cc406Sopenharmony_ci    {
1827141cc406Sopenharmony_ci      DBG (5,
1828141cc406Sopenharmony_ci	   "gt68xx_afe_cis_read_lines: gt68xx_scanner_stop_scan failed: %s\n",
1829141cc406Sopenharmony_ci	   sane_strstatus (status));
1830141cc406Sopenharmony_ci      return status;
1831141cc406Sopenharmony_ci    }
1832141cc406Sopenharmony_ci
1833141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1834141cc406Sopenharmony_ci}
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_cistatic SANE_Status
1837141cc406Sopenharmony_cigt68xx_afe_cis_auto (GT68xx_Scanner * scanner)
1838141cc406Sopenharmony_ci{
1839141cc406Sopenharmony_ci  SANE_Status status;
1840141cc406Sopenharmony_ci  int total_count, exposure_count;
1841141cc406Sopenharmony_ci  GT68xx_Afe_Values values;
1842141cc406Sopenharmony_ci  GT68xx_AFE_Parameters *afe = scanner->dev->afe, old_afe;
1843141cc406Sopenharmony_ci  GT68xx_Exposure_Parameters *exposure = scanner->dev->exposure;
1844141cc406Sopenharmony_ci  SANE_Int red_done, green_done, blue_done;
1845141cc406Sopenharmony_ci  SANE_Bool first = SANE_TRUE;
1846141cc406Sopenharmony_ci  unsigned int *r_gbuffer = 0, *g_gbuffer = 0, *b_gbuffer = 0;
1847141cc406Sopenharmony_ci  unsigned int *r_obuffer = 0, *g_obuffer = 0, *b_obuffer = 0;
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_ci  DBG (5, "gt68xx_afe_cis_auto: start\n");
1850141cc406Sopenharmony_ci
1851141cc406Sopenharmony_ci  if (scanner->dev->model->flags & GT68XX_FLAG_NO_CALIBRATE)
1852141cc406Sopenharmony_ci  {
1853141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1854141cc406Sopenharmony_ci  }
1855141cc406Sopenharmony_ci
1856141cc406Sopenharmony_ci  memset (&old_afe, 255, sizeof (old_afe));
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci  /* Start with the preset exposure settings */
1859141cc406Sopenharmony_ci  memcpy (scanner->dev->exposure, &scanner->dev->model->exposure,
1860141cc406Sopenharmony_ci	  sizeof (*scanner->dev->exposure));
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_ci  RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_FALSE, SANE_FALSE,
1863141cc406Sopenharmony_ci				  r_gbuffer, g_gbuffer, b_gbuffer));
1864141cc406Sopenharmony_ci
1865141cc406Sopenharmony_ci  r_gbuffer =
1866141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1867141cc406Sopenharmony_ci  g_gbuffer =
1868141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1869141cc406Sopenharmony_ci  b_gbuffer =
1870141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1871141cc406Sopenharmony_ci  r_obuffer =
1872141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1873141cc406Sopenharmony_ci  g_obuffer =
1874141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1875141cc406Sopenharmony_ci  b_obuffer =
1876141cc406Sopenharmony_ci    malloc (values.calwidth * values.callines * sizeof (unsigned int));
1877141cc406Sopenharmony_ci  if (!r_gbuffer || !g_gbuffer || !b_gbuffer || !r_obuffer || !g_obuffer
1878141cc406Sopenharmony_ci      || !b_obuffer)
1879141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1880141cc406Sopenharmony_ci
1881141cc406Sopenharmony_ci  total_count = 0;
1882141cc406Sopenharmony_ci  red_done = green_done = blue_done = SANE_FALSE;
1883141cc406Sopenharmony_ci  old_afe.r_offset = old_afe.g_offset = old_afe.b_offset = 255;
1884141cc406Sopenharmony_ci  old_afe.r_pga = old_afe.g_pga = old_afe.b_pga = 255;
1885141cc406Sopenharmony_ci  do
1886141cc406Sopenharmony_ci    {
1887141cc406Sopenharmony_ci      values.offset_direction = 1;
1888141cc406Sopenharmony_ci      if (scanner->dev->model->flags & GT68XX_FLAG_OFFSET_INV)
1889141cc406Sopenharmony_ci	values.offset_direction = -1;
1890141cc406Sopenharmony_ci
1891141cc406Sopenharmony_ci      RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_FALSE, first,
1892141cc406Sopenharmony_ci				      r_obuffer, g_obuffer, b_obuffer));
1893141cc406Sopenharmony_ci      RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_TRUE, SANE_FALSE,
1894141cc406Sopenharmony_ci				      r_gbuffer, g_gbuffer, b_gbuffer));
1895141cc406Sopenharmony_ci
1896141cc406Sopenharmony_ci      if (!red_done)
1897141cc406Sopenharmony_ci	red_done =
1898141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_gain_offset ("red", &values, r_obuffer,
1899141cc406Sopenharmony_ci					     r_gbuffer, afe, &old_afe);
1900141cc406Sopenharmony_ci      if (!green_done)
1901141cc406Sopenharmony_ci	green_done =
1902141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_gain_offset ("green", &values, g_obuffer,
1903141cc406Sopenharmony_ci					     g_gbuffer, afe, &old_afe);
1904141cc406Sopenharmony_ci      if (!blue_done)
1905141cc406Sopenharmony_ci	blue_done =
1906141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_gain_offset ("blue", &values, b_obuffer,
1907141cc406Sopenharmony_ci					     b_gbuffer, afe, &old_afe);
1908141cc406Sopenharmony_ci      total_count++;
1909141cc406Sopenharmony_ci      first = SANE_FALSE;
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_ci    }
1912141cc406Sopenharmony_ci  while (total_count < 100 && (!red_done || !green_done || !blue_done));
1913141cc406Sopenharmony_ci
1914141cc406Sopenharmony_ci  if (!red_done || !green_done || !blue_done)
1915141cc406Sopenharmony_ci    DBG (0, "gt68xx_afe_cis_auto: setting AFE reached limit\n");
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci  /* Exposure time */
1918141cc406Sopenharmony_ci  exposure_count = 0;
1919141cc406Sopenharmony_ci  red_done = green_done = blue_done = SANE_FALSE;
1920141cc406Sopenharmony_ci  do
1921141cc406Sopenharmony_ci    {
1922141cc406Sopenharmony_ci      /* read white line */
1923141cc406Sopenharmony_ci      RIE (gt68xx_afe_cis_read_lines (&values, scanner, SANE_TRUE, SANE_FALSE,
1924141cc406Sopenharmony_ci				      r_gbuffer, g_gbuffer, b_gbuffer));
1925141cc406Sopenharmony_ci      if (!red_done)
1926141cc406Sopenharmony_ci	red_done =
1927141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_exposure ("red", &values, r_gbuffer, 245,
1928141cc406Sopenharmony_ci					  &exposure->r_time);
1929141cc406Sopenharmony_ci      if (!green_done)
1930141cc406Sopenharmony_ci	green_done =
1931141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_exposure ("green", &values, g_gbuffer, 245,
1932141cc406Sopenharmony_ci					  &exposure->g_time);
1933141cc406Sopenharmony_ci      if (!blue_done)
1934141cc406Sopenharmony_ci	blue_done =
1935141cc406Sopenharmony_ci	  gt68xx_afe_cis_adjust_exposure ("blue", &values, b_gbuffer, 245,
1936141cc406Sopenharmony_ci					  &exposure->b_time);
1937141cc406Sopenharmony_ci      exposure_count++;
1938141cc406Sopenharmony_ci      total_count++;
1939141cc406Sopenharmony_ci    }
1940141cc406Sopenharmony_ci  while ((!red_done || !green_done || !blue_done) && exposure_count < 50);
1941141cc406Sopenharmony_ci
1942141cc406Sopenharmony_ci  if (!red_done || !green_done || !blue_done)
1943141cc406Sopenharmony_ci    DBG (0, "gt68xx_afe_cis_auto: setting exposure reached limit\n");
1944141cc406Sopenharmony_ci
1945141cc406Sopenharmony_ci  /* store afe calibration when needed */
1946141cc406Sopenharmony_ci  if(scanner->dev->model->flags & GT68XX_FLAG_HAS_CALIBRATE)
1947141cc406Sopenharmony_ci    {
1948141cc406Sopenharmony_ci      memcpy(&(scanner->afe_params), afe, sizeof(GT68xx_AFE_Parameters));
1949141cc406Sopenharmony_ci      scanner->exposure_params.r_time=exposure->r_time;
1950141cc406Sopenharmony_ci      scanner->exposure_params.g_time=exposure->g_time;
1951141cc406Sopenharmony_ci      scanner->exposure_params.b_time=exposure->b_time;
1952141cc406Sopenharmony_ci    }
1953141cc406Sopenharmony_ci
1954141cc406Sopenharmony_ci  free (r_gbuffer);
1955141cc406Sopenharmony_ci  free (g_gbuffer);
1956141cc406Sopenharmony_ci  free (b_gbuffer);
1957141cc406Sopenharmony_ci  free (r_obuffer);
1958141cc406Sopenharmony_ci  free (g_obuffer);
1959141cc406Sopenharmony_ci  free (b_obuffer);
1960141cc406Sopenharmony_ci  DBG (4, "gt68xx_afe_cis_auto: total_count: %d\n", total_count);
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1963141cc406Sopenharmony_ci}
1964141cc406Sopenharmony_ci
1965141cc406Sopenharmony_ci/** @brief create and copy calibrator
1966141cc406Sopenharmony_ci * Creates a calibrator of the given width and copy data from reference
1967141cc406Sopenharmony_ci * to initialize it
1968141cc406Sopenharmony_ci * @param calibator pointer to the calibrator to create
1969141cc406Sopenharmony_ci * @param reference calibrator with reference data to copy
1970141cc406Sopenharmony_ci * @param width the width in pixels of the calibrator
1971141cc406Sopenharmony_ci * @param offset offset in pixels when copying data from reference
1972141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD and a filled calibrator if enough memory
1973141cc406Sopenharmony_ci */
1974141cc406Sopenharmony_cistatic SANE_Status
1975141cc406Sopenharmony_cigt68xx_calibrator_create_copy (GT68xx_Calibrator ** calibrator,
1976141cc406Sopenharmony_ci			       GT68xx_Calibrator * reference, int width,
1977141cc406Sopenharmony_ci			       int offset)
1978141cc406Sopenharmony_ci{
1979141cc406Sopenharmony_ci  SANE_Status status;
1980141cc406Sopenharmony_ci  int i;
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci  if (reference == NULL)
1983141cc406Sopenharmony_ci    {
1984141cc406Sopenharmony_ci      DBG (1, "gt68xx_calibrator_create_copy: NULL reference, skipping...\n");
1985141cc406Sopenharmony_ci      *calibrator = NULL;
1986141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1987141cc406Sopenharmony_ci    }
1988141cc406Sopenharmony_ci  /* check for reference overflow */
1989141cc406Sopenharmony_ci  if(width+offset>reference->width)
1990141cc406Sopenharmony_ci    {
1991141cc406Sopenharmony_ci      DBG (1, "gt68xx_calibrator_create_copy: required with and offset exceed reference width\n");
1992141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1993141cc406Sopenharmony_ci    }
1994141cc406Sopenharmony_ci
1995141cc406Sopenharmony_ci  status = gt68xx_calibrator_new (width, 65535, calibrator);
1996141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1997141cc406Sopenharmony_ci    {
1998141cc406Sopenharmony_ci      DBG (1,
1999141cc406Sopenharmony_ci	   "gt68xx_calibrator_create_copy: failed to create calibrator: %s\n",
2000141cc406Sopenharmony_ci	   sane_strstatus (status));
2001141cc406Sopenharmony_ci      return status;
2002141cc406Sopenharmony_ci    }
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_ci  for(i=0;i<width;i++)
2005141cc406Sopenharmony_ci    {
2006141cc406Sopenharmony_ci      (*calibrator)->k_white[i]=reference->k_white[i+offset];
2007141cc406Sopenharmony_ci      (*calibrator)->k_black[i]=reference->k_black[i+offset];
2008141cc406Sopenharmony_ci      (*calibrator)->white_line[i]=reference->white_line[i+offset];
2009141cc406Sopenharmony_ci      (*calibrator)->black_line[i]=reference->black_line[i+offset];
2010141cc406Sopenharmony_ci    }
2011141cc406Sopenharmony_ci
2012141cc406Sopenharmony_ci  return status;
2013141cc406Sopenharmony_ci}
2014141cc406Sopenharmony_ci
2015141cc406Sopenharmony_cistatic SANE_Status
2016141cc406Sopenharmony_cigt68xx_sheetfed_move_to_scan_area (GT68xx_Scanner * scanner,
2017141cc406Sopenharmony_ci				  GT68xx_Scan_Request * request)
2018141cc406Sopenharmony_ci{
2019141cc406Sopenharmony_ci  SANE_Status status;
2020141cc406Sopenharmony_ci
2021141cc406Sopenharmony_ci  if (!(scanner->dev->model->flags & GT68XX_FLAG_SHEET_FED)
2022141cc406Sopenharmony_ci      || scanner->dev->model->command_set->move_paper == NULL)
2023141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2024141cc406Sopenharmony_ci
2025141cc406Sopenharmony_ci  /* send move paper command */
2026141cc406Sopenharmony_ci  RIE (scanner->dev->model->command_set->move_paper (scanner->dev, request));
2027141cc406Sopenharmony_ci
2028141cc406Sopenharmony_ci  /* wait until paper is set to the desired position */
2029141cc406Sopenharmony_ci  return gt68xx_scanner_wait_for_positioning (scanner);
2030141cc406Sopenharmony_ci}
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci/**< number of consecutive white line to detect a white area */
2033141cc406Sopenharmony_ci#define WHITE_LINES 2
2034141cc406Sopenharmony_ci
2035141cc406Sopenharmony_ci/** @brief calibrate sheet fed scanner
2036141cc406Sopenharmony_ci * This function calibrates sheet fed scanner by scanning a calibration
2037141cc406Sopenharmony_ci * target (which may be a blank page). It first move to a white area then
2038141cc406Sopenharmony_ci * does afe and exposure calibration. Then it scans white lines to get data
2039141cc406Sopenharmony_ci * for shading correction.
2040141cc406Sopenharmony_ci * @param scanner structure describing the frontend session and the device
2041141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL
2042141cc406Sopenharmony_ci * otherwise.
2043141cc406Sopenharmony_ci */
2044141cc406Sopenharmony_cistatic SANE_Status
2045141cc406Sopenharmony_cigt68xx_sheetfed_scanner_calibrate (GT68xx_Scanner * scanner)
2046141cc406Sopenharmony_ci{
2047141cc406Sopenharmony_ci  SANE_Status status;
2048141cc406Sopenharmony_ci  GT68xx_Scan_Request request;
2049141cc406Sopenharmony_ci  GT68xx_Scan_Parameters params;
2050141cc406Sopenharmony_ci  int count, i, x, y, white;
2051141cc406Sopenharmony_ci  unsigned int *buffer_pointers[3];
2052141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
2053141cc406Sopenharmony_ci  FILE *fcal;
2054141cc406Sopenharmony_ci  char title[50];
2055141cc406Sopenharmony_ci#endif
2056141cc406Sopenharmony_ci
2057141cc406Sopenharmony_ci  DBG (3, "gt68xx_sheetfed_scanner_calibrate: start.\n");
2058141cc406Sopenharmony_ci
2059141cc406Sopenharmony_ci  /* clear calibration if needed */
2060141cc406Sopenharmony_ci  gt68xx_scanner_free_calibrators (scanner);
2061141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS; i++)
2062141cc406Sopenharmony_ci    {
2063141cc406Sopenharmony_ci      if(scanner->calibrations[i].red!=NULL)
2064141cc406Sopenharmony_ci        {
2065141cc406Sopenharmony_ci          gt68xx_calibrator_free (scanner->calibrations[i].red);
2066141cc406Sopenharmony_ci        }
2067141cc406Sopenharmony_ci      if(scanner->calibrations[i].green!=NULL)
2068141cc406Sopenharmony_ci        {
2069141cc406Sopenharmony_ci          gt68xx_calibrator_free (scanner->calibrations[i].green);
2070141cc406Sopenharmony_ci        }
2071141cc406Sopenharmony_ci      if(scanner->calibrations[i].blue!=NULL)
2072141cc406Sopenharmony_ci        {
2073141cc406Sopenharmony_ci          gt68xx_calibrator_free (scanner->calibrations[i].blue);
2074141cc406Sopenharmony_ci        }
2075141cc406Sopenharmony_ci      if(scanner->calibrations[i].gray!=NULL)
2076141cc406Sopenharmony_ci        {
2077141cc406Sopenharmony_ci          gt68xx_calibrator_free (scanner->calibrations[i].gray);
2078141cc406Sopenharmony_ci        }
2079141cc406Sopenharmony_ci    }
2080141cc406Sopenharmony_ci  scanner->calibrated = SANE_FALSE;
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci  /* find minimum horizontal resolution */
2083141cc406Sopenharmony_ci  request.xdpi = 9600;
2084141cc406Sopenharmony_ci  for (i = 0; scanner->dev->model->xdpi_values[i] != 0; i++)
2085141cc406Sopenharmony_ci    {
2086141cc406Sopenharmony_ci      if (scanner->dev->model->xdpi_values[i] < request.xdpi)
2087141cc406Sopenharmony_ci	{
2088141cc406Sopenharmony_ci	  request.xdpi = scanner->dev->model->xdpi_values[i];
2089141cc406Sopenharmony_ci	  request.ydpi = scanner->dev->model->xdpi_values[i];
2090141cc406Sopenharmony_ci	}
2091141cc406Sopenharmony_ci    }
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci  /* move to white area SA_CALIBRATE uses its own y0/ys fixed values */
2094141cc406Sopenharmony_ci  request.x0 = 0;
2095141cc406Sopenharmony_ci  request.y0 = scanner->dev->model->y_offset_calib;
2096141cc406Sopenharmony_ci  request.xs = scanner->dev->model->x_size;
2097141cc406Sopenharmony_ci  request.depth = 8;
2098141cc406Sopenharmony_ci
2099141cc406Sopenharmony_ci  request.color = SANE_FALSE;
2100141cc406Sopenharmony_ci  request.mbs = SANE_TRUE;
2101141cc406Sopenharmony_ci  request.mds = SANE_TRUE;
2102141cc406Sopenharmony_ci  request.mas = SANE_FALSE;
2103141cc406Sopenharmony_ci  request.lamp = SANE_TRUE;
2104141cc406Sopenharmony_ci  request.calculate = SANE_FALSE;
2105141cc406Sopenharmony_ci  request.use_ta = SANE_FALSE;
2106141cc406Sopenharmony_ci  request.backtrack = SANE_FALSE;
2107141cc406Sopenharmony_ci  request.backtrack_lines = 0;
2108141cc406Sopenharmony_ci
2109141cc406Sopenharmony_ci  /* skip start of calibration sheet */
2110141cc406Sopenharmony_ci  status = gt68xx_sheetfed_move_to_scan_area (scanner, &request);
2111141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2112141cc406Sopenharmony_ci    {
2113141cc406Sopenharmony_ci      DBG (1,
2114141cc406Sopenharmony_ci	   "gt68xx_sheetfed_scanner_calibrate: failed to skip start of calibration sheet %s\n",
2115141cc406Sopenharmony_ci	   sane_strstatus (status));
2116141cc406Sopenharmony_ci      return status;
2117141cc406Sopenharmony_ci    }
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_ci  status = gt68xx_device_lamp_control (scanner->dev, SANE_FALSE, SANE_TRUE);
2120141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
2121141cc406Sopenharmony_ci    {
2122141cc406Sopenharmony_ci      DBG (1,
2123141cc406Sopenharmony_ci	   "gt68xx_sheetfed_scanner_calibrate: gt68xx_device_lamp_control returned %s\n",
2124141cc406Sopenharmony_ci	   sane_strstatus (status));
2125141cc406Sopenharmony_ci      return status;
2126141cc406Sopenharmony_ci    }
2127141cc406Sopenharmony_ci
2128141cc406Sopenharmony_ci  /* loop until we find a white area to calibrate on */
2129141cc406Sopenharmony_ci  i = 0;
2130141cc406Sopenharmony_ci  request.y0 = 0;
2131141cc406Sopenharmony_ci  do
2132141cc406Sopenharmony_ci    {
2133141cc406Sopenharmony_ci      /* start scan */
2134141cc406Sopenharmony_ci      status =
2135141cc406Sopenharmony_ci	gt68xx_scanner_start_scan_extended (scanner, &request, SA_CALIBRATE,
2136141cc406Sopenharmony_ci					    &params);
2137141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2138141cc406Sopenharmony_ci	{
2139141cc406Sopenharmony_ci	  DBG (1,
2140141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_start_scan_extended returned %s\n",
2141141cc406Sopenharmony_ci	       sane_strstatus (status));
2142141cc406Sopenharmony_ci	  return status;
2143141cc406Sopenharmony_ci	}
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci      /* loop until we find WHITE_LINES consecutive white lines or we reach and of area */
2146141cc406Sopenharmony_ci      white = 0;
2147141cc406Sopenharmony_ci      y = 0;
2148141cc406Sopenharmony_ci      do
2149141cc406Sopenharmony_ci	{
2150141cc406Sopenharmony_ci	  status = gt68xx_line_reader_read (scanner->reader, buffer_pointers);
2151141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2152141cc406Sopenharmony_ci	    {
2153141cc406Sopenharmony_ci	      DBG (1,
2154141cc406Sopenharmony_ci		   "gt68xx_sheetfed_scanner_calibrate: gt68xx_line_reader_read returned %s\n",
2155141cc406Sopenharmony_ci		   sane_strstatus (status));
2156141cc406Sopenharmony_ci	      gt68xx_scanner_stop_scan (scanner);
2157141cc406Sopenharmony_ci	      return status;
2158141cc406Sopenharmony_ci	    }
2159141cc406Sopenharmony_ci
2160141cc406Sopenharmony_ci	  /* check for white line */
2161141cc406Sopenharmony_ci	  count = 0;
2162141cc406Sopenharmony_ci	  for (x = 0; x < params.pixel_xs; x++)
2163141cc406Sopenharmony_ci	    {
2164141cc406Sopenharmony_ci	      if (((buffer_pointers[0][x] >> 8) & 0xff) > 50)
2165141cc406Sopenharmony_ci		{
2166141cc406Sopenharmony_ci		  count++;
2167141cc406Sopenharmony_ci		}
2168141cc406Sopenharmony_ci	    }
2169141cc406Sopenharmony_ci
2170141cc406Sopenharmony_ci	  /* line is white if 93% is above black level */
2171141cc406Sopenharmony_ci	  if ((100 * count) / params.pixel_xs < 93)
2172141cc406Sopenharmony_ci	    {
2173141cc406Sopenharmony_ci	      white = 0;
2174141cc406Sopenharmony_ci	    }
2175141cc406Sopenharmony_ci	  else
2176141cc406Sopenharmony_ci	    {
2177141cc406Sopenharmony_ci	      white++;
2178141cc406Sopenharmony_ci	    }
2179141cc406Sopenharmony_ci	  y++;
2180141cc406Sopenharmony_ci	}
2181141cc406Sopenharmony_ci      while ((white < WHITE_LINES) && (y < params.pixel_ys));
2182141cc406Sopenharmony_ci
2183141cc406Sopenharmony_ci      /* end scan */
2184141cc406Sopenharmony_ci      gt68xx_scanner_stop_scan (scanner);
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci      i++;
2187141cc406Sopenharmony_ci    }
2188141cc406Sopenharmony_ci  while (i < 20 && white < WHITE_LINES);
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_ci  /* check if we found a white area */
2191141cc406Sopenharmony_ci  if (white != WHITE_LINES)
2192141cc406Sopenharmony_ci    {
2193141cc406Sopenharmony_ci      DBG (1,
2194141cc406Sopenharmony_ci	   "gt68xx_sheetfed_scanner_calibrate: didn't find a white area\n");
2195141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2196141cc406Sopenharmony_ci    }
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_ci  /* now do calibration */
2199141cc406Sopenharmony_ci  scanner->auto_afe = SANE_TRUE;
2200141cc406Sopenharmony_ci  scanner->calib = SANE_TRUE;
2201141cc406Sopenharmony_ci
2202141cc406Sopenharmony_ci  /* loop at each possible xdpi to create calibrators */
2203141cc406Sopenharmony_ci  i = 0;
2204141cc406Sopenharmony_ci  while (scanner->dev->model->xdpi_values[i] > 0)
2205141cc406Sopenharmony_ci    {
2206141cc406Sopenharmony_ci      request.xdpi = scanner->dev->model->xdpi_values[i];
2207141cc406Sopenharmony_ci      request.ydpi = scanner->dev->model->xdpi_values[i];
2208141cc406Sopenharmony_ci      request.x0 = 0;
2209141cc406Sopenharmony_ci      request.y0 = 0;
2210141cc406Sopenharmony_ci      request.xs = scanner->dev->model->x_size;
2211141cc406Sopenharmony_ci      request.color = SANE_FALSE;
2212141cc406Sopenharmony_ci      request.mbs = SANE_FALSE;
2213141cc406Sopenharmony_ci      request.mds = SANE_TRUE;
2214141cc406Sopenharmony_ci      request.mas = SANE_FALSE;
2215141cc406Sopenharmony_ci      request.lamp = SANE_TRUE;
2216141cc406Sopenharmony_ci      request.calculate = SANE_FALSE;
2217141cc406Sopenharmony_ci      request.use_ta = SANE_FALSE;
2218141cc406Sopenharmony_ci      request.backtrack = SANE_FALSE;
2219141cc406Sopenharmony_ci      request.backtrack_lines = 0;
2220141cc406Sopenharmony_ci
2221141cc406Sopenharmony_ci      /* calibrate in color */
2222141cc406Sopenharmony_ci      request.color = SANE_TRUE;
2223141cc406Sopenharmony_ci      status = gt68xx_scanner_calibrate (scanner, &request);
2224141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2225141cc406Sopenharmony_ci	{
2226141cc406Sopenharmony_ci	  DBG (1,
2227141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_calibrate returned %s\n",
2228141cc406Sopenharmony_ci	       sane_strstatus (status));
2229141cc406Sopenharmony_ci	  return status;
2230141cc406Sopenharmony_ci	}
2231141cc406Sopenharmony_ci
2232141cc406Sopenharmony_ci      /* since auto afe is done at a fixed resolution, we don't need to
2233141cc406Sopenharmony_ci       * do each each time, once is enough */
2234141cc406Sopenharmony_ci      scanner->auto_afe = SANE_FALSE;
2235141cc406Sopenharmony_ci
2236141cc406Sopenharmony_ci      /* allocate and save per dpi calibrators */
2237141cc406Sopenharmony_ci      scanner->calibrations[i].dpi = request.xdpi;
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_ci      /* recompute params */
2240141cc406Sopenharmony_ci      request.calculate = SANE_TRUE;
2241141cc406Sopenharmony_ci      gt68xx_device_setup_scan (scanner->dev, &request, SA_SCAN, &params);
2242141cc406Sopenharmony_ci
2243141cc406Sopenharmony_ci      scanner->calibrations[i].pixel_x0 = params.pixel_x0;
2244141cc406Sopenharmony_ci      status =
2245141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->calibrations[i].red),
2246141cc406Sopenharmony_ci				       scanner->cal_r, scanner->cal_r->width,
2247141cc406Sopenharmony_ci				       0);
2248141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2249141cc406Sopenharmony_ci	{
2250141cc406Sopenharmony_ci	  DBG (1,
2251141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: failed to create red calibrator: %s\n",
2252141cc406Sopenharmony_ci	       sane_strstatus (status));
2253141cc406Sopenharmony_ci	  return status;
2254141cc406Sopenharmony_ci	}
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci      status =
2257141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->calibrations[i].green),
2258141cc406Sopenharmony_ci				       scanner->cal_g, scanner->cal_g->width,
2259141cc406Sopenharmony_ci				       0);
2260141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2261141cc406Sopenharmony_ci	{
2262141cc406Sopenharmony_ci	  DBG (1,
2263141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: failed to create green calibrator: %s\n",
2264141cc406Sopenharmony_ci	       sane_strstatus (status));
2265141cc406Sopenharmony_ci	  return status;
2266141cc406Sopenharmony_ci	}
2267141cc406Sopenharmony_ci
2268141cc406Sopenharmony_ci      status =
2269141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->calibrations[i].blue),
2270141cc406Sopenharmony_ci				       scanner->cal_b, scanner->cal_b->width,
2271141cc406Sopenharmony_ci				       0);
2272141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2273141cc406Sopenharmony_ci	{
2274141cc406Sopenharmony_ci	  DBG (1,
2275141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: failed to create blue calibrator: %s\n",
2276141cc406Sopenharmony_ci	       sane_strstatus (status));
2277141cc406Sopenharmony_ci	  return status;
2278141cc406Sopenharmony_ci	}
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_ci      /* calibrate in gray */
2281141cc406Sopenharmony_ci      request.color = SANE_FALSE;
2282141cc406Sopenharmony_ci      status = gt68xx_scanner_calibrate (scanner, &request);
2283141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2284141cc406Sopenharmony_ci	{
2285141cc406Sopenharmony_ci	  DBG (1,
2286141cc406Sopenharmony_ci	       "gt68xx_sheetfed_scanner_calibrate: gt68xx_scanner_calibrate returned %s\n",
2287141cc406Sopenharmony_ci	       sane_strstatus (status));
2288141cc406Sopenharmony_ci	  return status;
2289141cc406Sopenharmony_ci	}
2290141cc406Sopenharmony_ci
2291141cc406Sopenharmony_ci      if (scanner->cal_gray)
2292141cc406Sopenharmony_ci	{
2293141cc406Sopenharmony_ci	  status =
2294141cc406Sopenharmony_ci	    gt68xx_calibrator_create_copy (&(scanner->calibrations[i].gray),
2295141cc406Sopenharmony_ci					   scanner->cal_gray,
2296141cc406Sopenharmony_ci					   scanner->cal_gray->width, 0);
2297141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2298141cc406Sopenharmony_ci	    {
2299141cc406Sopenharmony_ci	      DBG (1,
2300141cc406Sopenharmony_ci		   "gt68xx_sheetfed_scanner_calibrate: failed to create gray calibrator: %s\n",
2301141cc406Sopenharmony_ci		   sane_strstatus (status));
2302141cc406Sopenharmony_ci	      return status;
2303141cc406Sopenharmony_ci	    }
2304141cc406Sopenharmony_ci	}
2305141cc406Sopenharmony_ci
2306141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
2307141cc406Sopenharmony_ci      sprintf (title, "cal-%03d-red.pnm", scanner->calibrations[i].dpi);
2308141cc406Sopenharmony_ci      fcal = fopen (title, "wb");
2309141cc406Sopenharmony_ci      if (fcal != NULL)
2310141cc406Sopenharmony_ci	{
2311141cc406Sopenharmony_ci	  fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2312141cc406Sopenharmony_ci	  for (x = 0; x < params.pixel_xs; x++)
2313141cc406Sopenharmony_ci	    fputc ((scanner->calibrations[i].red->k_white[x] >> 8) & 0xff,
2314141cc406Sopenharmony_ci		   fcal);
2315141cc406Sopenharmony_ci	  fclose (fcal);
2316141cc406Sopenharmony_ci	}
2317141cc406Sopenharmony_ci      sprintf (title, "cal-%03d-green.pnm", scanner->calibrations[i].dpi);
2318141cc406Sopenharmony_ci      fcal = fopen (title, "wb");
2319141cc406Sopenharmony_ci      if (fcal != NULL)
2320141cc406Sopenharmony_ci	{
2321141cc406Sopenharmony_ci	  fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2322141cc406Sopenharmony_ci	  for (x = 0; x < params.pixel_xs; x++)
2323141cc406Sopenharmony_ci	    fputc ((scanner->calibrations[i].green->k_white[x] >> 8) & 0xff,
2324141cc406Sopenharmony_ci		   fcal);
2325141cc406Sopenharmony_ci	  fclose (fcal);
2326141cc406Sopenharmony_ci	}
2327141cc406Sopenharmony_ci      sprintf (title, "cal-%03d-blue.pnm", scanner->calibrations[i].dpi);
2328141cc406Sopenharmony_ci      fcal = fopen (title, "wb");
2329141cc406Sopenharmony_ci      if (fcal != NULL)
2330141cc406Sopenharmony_ci	{
2331141cc406Sopenharmony_ci	  fprintf (fcal, "P5\n%d 1\n255\n", params.pixel_xs);
2332141cc406Sopenharmony_ci	  for (x = 0; x < params.pixel_xs; x++)
2333141cc406Sopenharmony_ci	    fputc ((scanner->calibrations[i].blue->k_white[x] >> 8) & 0xff,
2334141cc406Sopenharmony_ci		   fcal);
2335141cc406Sopenharmony_ci	  fclose (fcal);
2336141cc406Sopenharmony_ci	}
2337141cc406Sopenharmony_ci#endif
2338141cc406Sopenharmony_ci
2339141cc406Sopenharmony_ci      /* next resolution */
2340141cc406Sopenharmony_ci      i++;
2341141cc406Sopenharmony_ci    }
2342141cc406Sopenharmony_ci
2343141cc406Sopenharmony_ci  scanner->calibrated = SANE_TRUE;
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci  /* eject calibration target from feeder */
2346141cc406Sopenharmony_ci  gt68xx_device_paperfeed (scanner->dev);
2347141cc406Sopenharmony_ci
2348141cc406Sopenharmony_ci  /* save calibration to file */
2349141cc406Sopenharmony_ci  gt68xx_write_calibration (scanner);
2350141cc406Sopenharmony_ci
2351141cc406Sopenharmony_ci  DBG (3, "gt68xx_sheetfed_scanner_calibrate: end.\n");
2352141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2353141cc406Sopenharmony_ci}
2354141cc406Sopenharmony_ci
2355141cc406Sopenharmony_ci/** @brief assign calibration for scan
2356141cc406Sopenharmony_ci * This function creates the calibrators and set up afe for the requested
2357141cc406Sopenharmony_ci * scan. It uses calibration data that has been created by
2358141cc406Sopenharmony_ci * gt68xx_sheetfed_scanner_calibrate.
2359141cc406Sopenharmony_ci * @param scanner structure describing the frontend session and the device
2360141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL
2361141cc406Sopenharmony_ci * otherwise.
2362141cc406Sopenharmony_ci */
2363141cc406Sopenharmony_cistatic SANE_Status
2364141cc406Sopenharmony_cigt68xx_assign_calibration (GT68xx_Scanner * scanner,
2365141cc406Sopenharmony_ci			   GT68xx_Scan_Parameters params)
2366141cc406Sopenharmony_ci{
2367141cc406Sopenharmony_ci  int i, dpi, offset;
2368141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
2369141cc406Sopenharmony_ci
2370141cc406Sopenharmony_ci  DBG (3, "gt68xx_assign_calibration: start.\n");
2371141cc406Sopenharmony_ci
2372141cc406Sopenharmony_ci  dpi = params.xdpi;
2373141cc406Sopenharmony_ci  DBG (4, "gt68xx_assign_calibration: searching calibration for %d dpi\n",
2374141cc406Sopenharmony_ci       dpi);
2375141cc406Sopenharmony_ci
2376141cc406Sopenharmony_ci  /* search matching dpi */
2377141cc406Sopenharmony_ci  i = 0;
2378141cc406Sopenharmony_ci  while (scanner->calibrations[i].dpi > 0
2379141cc406Sopenharmony_ci	 && scanner->calibrations[i].dpi != dpi)
2380141cc406Sopenharmony_ci    {
2381141cc406Sopenharmony_ci      i++;
2382141cc406Sopenharmony_ci    }
2383141cc406Sopenharmony_ci
2384141cc406Sopenharmony_ci  /* check if found a match */
2385141cc406Sopenharmony_ci  if (scanner->calibrations[i].dpi == 0)
2386141cc406Sopenharmony_ci    {
2387141cc406Sopenharmony_ci      DBG (4,
2388141cc406Sopenharmony_ci	   "gt68xx_assign_calibration: failed to find calibration for %d dpi\n",
2389141cc406Sopenharmony_ci	   dpi);
2390141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2391141cc406Sopenharmony_ci    }
2392141cc406Sopenharmony_ci  DBG (4, "gt68xx_assign_calibration: using entry %d for %d dpi\n", i, dpi);
2393141cc406Sopenharmony_ci
2394141cc406Sopenharmony_ci  DBG (5,
2395141cc406Sopenharmony_ci       "gt68xx_assign_calibration: using scan_parameters: pixel_x0=%d, pixel_xs=%d \n",
2396141cc406Sopenharmony_ci       params.pixel_x0, params.pixel_xs);
2397141cc406Sopenharmony_ci
2398141cc406Sopenharmony_ci  /* AFE/exposure data copy */
2399141cc406Sopenharmony_ci  memcpy (scanner->dev->afe, &(scanner->afe_params),
2400141cc406Sopenharmony_ci	  sizeof (GT68xx_AFE_Parameters));
2401141cc406Sopenharmony_ci  scanner->dev->exposure->r_time = scanner->exposure_params.r_time;
2402141cc406Sopenharmony_ci  scanner->dev->exposure->g_time = scanner->exposure_params.g_time;
2403141cc406Sopenharmony_ci  scanner->dev->exposure->b_time = scanner->exposure_params.b_time;
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci  /* free calibrators if needed */
2406141cc406Sopenharmony_ci  gt68xx_scanner_free_calibrators (scanner);
2407141cc406Sopenharmony_ci
2408141cc406Sopenharmony_ci  /* TODO compute offset based on the x0 value from scan_request */
2409141cc406Sopenharmony_ci  offset = params.pixel_x0 - scanner->calibrations[i].pixel_x0;
2410141cc406Sopenharmony_ci
2411141cc406Sopenharmony_ci  /* calibrator allocation and copy */
2412141cc406Sopenharmony_ci  if (scanner->calibrations[i].red!=NULL)
2413141cc406Sopenharmony_ci    {
2414141cc406Sopenharmony_ci      status =
2415141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->cal_r),
2416141cc406Sopenharmony_ci				       scanner->calibrations[i].red,
2417141cc406Sopenharmony_ci				       params.pixel_xs,
2418141cc406Sopenharmony_ci                                       offset);
2419141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2420141cc406Sopenharmony_ci	{
2421141cc406Sopenharmony_ci	  DBG (1,
2422141cc406Sopenharmony_ci	       "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2423141cc406Sopenharmony_ci	       sane_strstatus (status));
2424141cc406Sopenharmony_ci	  return status;
2425141cc406Sopenharmony_ci	}
2426141cc406Sopenharmony_ci    }
2427141cc406Sopenharmony_ci
2428141cc406Sopenharmony_ci  if (scanner->calibrations[i].green!=NULL)
2429141cc406Sopenharmony_ci    {
2430141cc406Sopenharmony_ci      status =
2431141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->cal_g),
2432141cc406Sopenharmony_ci				       scanner->calibrations[i].green,
2433141cc406Sopenharmony_ci				       params.pixel_xs,
2434141cc406Sopenharmony_ci				       offset);
2435141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2436141cc406Sopenharmony_ci	{
2437141cc406Sopenharmony_ci	  DBG (1,
2438141cc406Sopenharmony_ci	       "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2439141cc406Sopenharmony_ci	       sane_strstatus (status));
2440141cc406Sopenharmony_ci	  return status;
2441141cc406Sopenharmony_ci	}
2442141cc406Sopenharmony_ci    }
2443141cc406Sopenharmony_ci
2444141cc406Sopenharmony_ci  if (scanner->calibrations[i].blue!=NULL)
2445141cc406Sopenharmony_ci    {
2446141cc406Sopenharmony_ci      status =
2447141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->cal_b),
2448141cc406Sopenharmony_ci				       scanner->calibrations[i].blue,
2449141cc406Sopenharmony_ci				       params.pixel_xs,
2450141cc406Sopenharmony_ci				       offset);
2451141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2452141cc406Sopenharmony_ci	{
2453141cc406Sopenharmony_ci	  DBG (1,
2454141cc406Sopenharmony_ci	       "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2455141cc406Sopenharmony_ci	       sane_strstatus (status));
2456141cc406Sopenharmony_ci	  return status;
2457141cc406Sopenharmony_ci	}
2458141cc406Sopenharmony_ci    }
2459141cc406Sopenharmony_ci
2460141cc406Sopenharmony_ci  if (scanner->calibrations[i].gray!=NULL)
2461141cc406Sopenharmony_ci    {
2462141cc406Sopenharmony_ci      status =
2463141cc406Sopenharmony_ci	gt68xx_calibrator_create_copy (&(scanner->cal_gray),
2464141cc406Sopenharmony_ci				       scanner->calibrations[i].gray,
2465141cc406Sopenharmony_ci				       params.pixel_xs,
2466141cc406Sopenharmony_ci				       offset);
2467141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2468141cc406Sopenharmony_ci	{
2469141cc406Sopenharmony_ci	  DBG (1,
2470141cc406Sopenharmony_ci	       "gt68xx_assign_calibration: failed to create calibrator: %s\n",
2471141cc406Sopenharmony_ci	       sane_strstatus (status));
2472141cc406Sopenharmony_ci	  return status;
2473141cc406Sopenharmony_ci	}
2474141cc406Sopenharmony_ci    }
2475141cc406Sopenharmony_ci
2476141cc406Sopenharmony_ci  DBG (3, "gt68xx_assign_calibration: end.\n");
2477141cc406Sopenharmony_ci  return status;
2478141cc406Sopenharmony_ci}
2479141cc406Sopenharmony_ci
2480141cc406Sopenharmony_cistatic char *gt68xx_calibration_file(GT68xx_Scanner * scanner)
2481141cc406Sopenharmony_ci{
2482141cc406Sopenharmony_ci  char *ptr=NULL;
2483141cc406Sopenharmony_ci  char tmp_str[PATH_MAX];
2484141cc406Sopenharmony_ci
2485141cc406Sopenharmony_ci  ptr=getenv("HOME");
2486141cc406Sopenharmony_ci  if(ptr!=NULL)
2487141cc406Sopenharmony_ci    {
2488141cc406Sopenharmony_ci      sprintf (tmp_str, "%s/.sane/gt68xx-%s.cal", ptr, scanner->dev->model->name);
2489141cc406Sopenharmony_ci    }
2490141cc406Sopenharmony_ci  else
2491141cc406Sopenharmony_ci    {
2492141cc406Sopenharmony_ci      ptr=getenv("TMPDIR");
2493141cc406Sopenharmony_ci      if(ptr!=NULL)
2494141cc406Sopenharmony_ci        {
2495141cc406Sopenharmony_ci          sprintf (tmp_str, "%s/gt68xx-%s.cal", ptr, scanner->dev->model->name);
2496141cc406Sopenharmony_ci        }
2497141cc406Sopenharmony_ci      else
2498141cc406Sopenharmony_ci        {
2499141cc406Sopenharmony_ci          sprintf (tmp_str, "/tmp/gt68xx-%s.cal", scanner->dev->model->name);
2500141cc406Sopenharmony_ci        }
2501141cc406Sopenharmony_ci    }
2502141cc406Sopenharmony_ci  DBG(5,"gt68xx_calibration_file: using >%s< for calibration file name\n",tmp_str);
2503141cc406Sopenharmony_ci  return strdup(tmp_str);
2504141cc406Sopenharmony_ci}
2505141cc406Sopenharmony_ci
2506141cc406Sopenharmony_cistatic SANE_Status
2507141cc406Sopenharmony_cigt68xx_clear_calibration (GT68xx_Scanner * scanner)
2508141cc406Sopenharmony_ci{
2509141cc406Sopenharmony_ci  char *fname;
2510141cc406Sopenharmony_ci  int i;
2511141cc406Sopenharmony_ci
2512141cc406Sopenharmony_ci  if (scanner->calibrated == SANE_FALSE)
2513141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2514141cc406Sopenharmony_ci
2515141cc406Sopenharmony_ci  /* clear file */
2516141cc406Sopenharmony_ci  fname = gt68xx_calibration_file (scanner);
2517141cc406Sopenharmony_ci  unlink (fname);
2518141cc406Sopenharmony_ci  free (fname);
2519141cc406Sopenharmony_ci
2520141cc406Sopenharmony_ci  /* free calibrators */
2521141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS && scanner->calibrations[i].dpi > 0; i++)
2522141cc406Sopenharmony_ci    {
2523141cc406Sopenharmony_ci      scanner->calibrations[i].dpi = 0;
2524141cc406Sopenharmony_ci      if (scanner->calibrations[i].red)
2525141cc406Sopenharmony_ci	gt68xx_calibrator_free (scanner->calibrations[i].red);
2526141cc406Sopenharmony_ci      if (scanner->calibrations[i].green)
2527141cc406Sopenharmony_ci	gt68xx_calibrator_free (scanner->calibrations[i].green);
2528141cc406Sopenharmony_ci      if (scanner->calibrations[i].blue)
2529141cc406Sopenharmony_ci	gt68xx_calibrator_free (scanner->calibrations[i].blue);
2530141cc406Sopenharmony_ci      if (scanner->calibrations[i].gray)
2531141cc406Sopenharmony_ci	gt68xx_calibrator_free (scanner->calibrations[i].gray);
2532141cc406Sopenharmony_ci    }
2533141cc406Sopenharmony_ci
2534141cc406Sopenharmony_ci  /* reset flags */
2535141cc406Sopenharmony_ci  scanner->calibrated = SANE_FALSE;
2536141cc406Sopenharmony_ci  scanner->val[OPT_QUALITY_CAL].w = SANE_FALSE;
2537141cc406Sopenharmony_ci  scanner->val[OPT_NEED_CALIBRATION_SW].w = SANE_TRUE;
2538141cc406Sopenharmony_ci  DBG (5, "gt68xx_clear_calibration: done\n");
2539141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2540141cc406Sopenharmony_ci}
2541141cc406Sopenharmony_ci
2542141cc406Sopenharmony_cistatic SANE_Status
2543141cc406Sopenharmony_cigt68xx_write_calibration (GT68xx_Scanner * scanner)
2544141cc406Sopenharmony_ci{
2545141cc406Sopenharmony_ci  char *fname;
2546141cc406Sopenharmony_ci  FILE *fcal;
2547141cc406Sopenharmony_ci  int i;
2548141cc406Sopenharmony_ci  SANE_Int nullwidth = 0;
2549141cc406Sopenharmony_ci
2550141cc406Sopenharmony_ci  if (scanner->calibrated == SANE_FALSE)
2551141cc406Sopenharmony_ci    {
2552141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2553141cc406Sopenharmony_ci    }
2554141cc406Sopenharmony_ci
2555141cc406Sopenharmony_ci  /* open file */
2556141cc406Sopenharmony_ci  fname = gt68xx_calibration_file (scanner);
2557141cc406Sopenharmony_ci  fcal = fopen (fname, "wb");
2558141cc406Sopenharmony_ci  free (fname);
2559141cc406Sopenharmony_ci  if (fcal == NULL)
2560141cc406Sopenharmony_ci    {
2561141cc406Sopenharmony_ci      DBG (1,
2562141cc406Sopenharmony_ci	   "gt68xx_write_calibration: failed to open calibration file for writing %s\n",
2563141cc406Sopenharmony_ci	   strerror (errno));
2564141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2565141cc406Sopenharmony_ci    }
2566141cc406Sopenharmony_ci
2567141cc406Sopenharmony_ci  /* TODO we save check endianness and word alignment in case of a home
2568141cc406Sopenharmony_ci   * directory used trough different archs */
2569141cc406Sopenharmony_ci  fwrite (&(scanner->afe_params), sizeof (GT68xx_AFE_Parameters), 1, fcal);
2570141cc406Sopenharmony_ci  fwrite (&(scanner->exposure_params), sizeof (GT68xx_Exposure_Parameters), 1,
2571141cc406Sopenharmony_ci	  fcal);
2572141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS && scanner->calibrations[i].dpi > 0; i++)
2573141cc406Sopenharmony_ci    {
2574141cc406Sopenharmony_ci      DBG (1, "gt68xx_write_calibration: saving %d dpi calibration\n",
2575141cc406Sopenharmony_ci	   scanner->calibrations[i].dpi);
2576141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2577141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].pixel_x0), sizeof (SANE_Int), 1,
2578141cc406Sopenharmony_ci	      fcal);
2579141cc406Sopenharmony_ci
2580141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].red->width), sizeof (SANE_Int), 1,
2581141cc406Sopenharmony_ci	      fcal);
2582141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].red->white_level), sizeof (SANE_Int),
2583141cc406Sopenharmony_ci	      1, fcal);
2584141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].red->k_white, sizeof (unsigned int),
2585141cc406Sopenharmony_ci	      scanner->calibrations[i].red->width, fcal);
2586141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].red->k_black, sizeof (unsigned int),
2587141cc406Sopenharmony_ci	      scanner->calibrations[i].red->width, fcal);
2588141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].red->white_line, sizeof (double),
2589141cc406Sopenharmony_ci	      scanner->calibrations[i].red->width, fcal);
2590141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].red->black_line, sizeof (double),
2591141cc406Sopenharmony_ci	      scanner->calibrations[i].red->width, fcal);
2592141cc406Sopenharmony_ci
2593141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].green->width), sizeof (SANE_Int), 1,
2594141cc406Sopenharmony_ci	      fcal);
2595141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].green->white_level),
2596141cc406Sopenharmony_ci	      sizeof (SANE_Int), 1, fcal);
2597141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].green->k_white, sizeof (unsigned int),
2598141cc406Sopenharmony_ci	      scanner->calibrations[i].green->width, fcal);
2599141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].green->k_black, sizeof (unsigned int),
2600141cc406Sopenharmony_ci	      scanner->calibrations[i].green->width, fcal);
2601141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].green->white_line, sizeof (double),
2602141cc406Sopenharmony_ci	      scanner->calibrations[i].green->width, fcal);
2603141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].green->black_line, sizeof (double),
2604141cc406Sopenharmony_ci	      scanner->calibrations[i].green->width, fcal);
2605141cc406Sopenharmony_ci
2606141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].blue->width), sizeof (SANE_Int), 1,
2607141cc406Sopenharmony_ci	      fcal);
2608141cc406Sopenharmony_ci      fwrite (&(scanner->calibrations[i].blue->white_level),
2609141cc406Sopenharmony_ci	      sizeof (SANE_Int), 1, fcal);
2610141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].blue->k_white, sizeof (unsigned int),
2611141cc406Sopenharmony_ci	      scanner->calibrations[i].blue->width, fcal);
2612141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].blue->k_black, sizeof (unsigned int),
2613141cc406Sopenharmony_ci	      scanner->calibrations[i].blue->width, fcal);
2614141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].blue->white_line, sizeof (double),
2615141cc406Sopenharmony_ci	      scanner->calibrations[i].blue->width, fcal);
2616141cc406Sopenharmony_ci      fwrite (scanner->calibrations[i].blue->black_line, sizeof (double),
2617141cc406Sopenharmony_ci	      scanner->calibrations[i].blue->width, fcal);
2618141cc406Sopenharmony_ci
2619141cc406Sopenharmony_ci      if (scanner->calibrations[i].gray != NULL)
2620141cc406Sopenharmony_ci	{
2621141cc406Sopenharmony_ci	  fwrite (&(scanner->calibrations[i].gray->width), sizeof (SANE_Int),
2622141cc406Sopenharmony_ci		  1, fcal);
2623141cc406Sopenharmony_ci	  fwrite (&(scanner->calibrations[i].gray->white_level),
2624141cc406Sopenharmony_ci		  sizeof (SANE_Int), 1, fcal);
2625141cc406Sopenharmony_ci	  fwrite (scanner->calibrations[i].gray->k_white,
2626141cc406Sopenharmony_ci		  sizeof (unsigned int), scanner->calibrations[i].gray->width,
2627141cc406Sopenharmony_ci		  fcal);
2628141cc406Sopenharmony_ci	  fwrite (scanner->calibrations[i].gray->k_black,
2629141cc406Sopenharmony_ci		  sizeof (unsigned int), scanner->calibrations[i].gray->width,
2630141cc406Sopenharmony_ci		  fcal);
2631141cc406Sopenharmony_ci	  fwrite (scanner->calibrations[i].gray->white_line, sizeof (double),
2632141cc406Sopenharmony_ci		  scanner->calibrations[i].gray->width, fcal);
2633141cc406Sopenharmony_ci	  fwrite (scanner->calibrations[i].gray->black_line, sizeof (double),
2634141cc406Sopenharmony_ci		  scanner->calibrations[i].gray->width, fcal);
2635141cc406Sopenharmony_ci	}
2636141cc406Sopenharmony_ci      else
2637141cc406Sopenharmony_ci	{
2638141cc406Sopenharmony_ci	  fwrite (&nullwidth, sizeof (SANE_Int), 1, fcal);
2639141cc406Sopenharmony_ci	}
2640141cc406Sopenharmony_ci    }
2641141cc406Sopenharmony_ci  DBG (5, "gt68xx_write_calibration: wrote %d calibrations\n", i);
2642141cc406Sopenharmony_ci
2643141cc406Sopenharmony_ci  fclose (fcal);
2644141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2645141cc406Sopenharmony_ci}
2646141cc406Sopenharmony_ci
2647141cc406Sopenharmony_cistatic SANE_Status
2648141cc406Sopenharmony_cigt68xx_read_calibration (GT68xx_Scanner * scanner)
2649141cc406Sopenharmony_ci{
2650141cc406Sopenharmony_ci  char *fname;
2651141cc406Sopenharmony_ci  FILE *fcal;
2652141cc406Sopenharmony_ci  int i;
2653141cc406Sopenharmony_ci  SANE_Int width, level;
2654141cc406Sopenharmony_ci
2655141cc406Sopenharmony_ci  scanner->calibrated = SANE_FALSE;
2656141cc406Sopenharmony_ci  fname = gt68xx_calibration_file (scanner);
2657141cc406Sopenharmony_ci  fcal = fopen (fname, "rb");
2658141cc406Sopenharmony_ci  free (fname);
2659141cc406Sopenharmony_ci  if (fcal == NULL)
2660141cc406Sopenharmony_ci    {
2661141cc406Sopenharmony_ci      DBG (1,
2662141cc406Sopenharmony_ci	   "gt68xx_read_calibration: failed to open calibration file for reading %s\n",
2663141cc406Sopenharmony_ci	   strerror (errno));
2664141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2665141cc406Sopenharmony_ci    }
2666141cc406Sopenharmony_ci
2667141cc406Sopenharmony_ci  /* TODO we should check endianness and word alignment in case of a home
2668141cc406Sopenharmony_ci   * directory used trough different archs */
2669141cc406Sopenharmony_ci
2670141cc406Sopenharmony_ci  /* TODO check for errors */
2671141cc406Sopenharmony_ci  fread (&(scanner->afe_params), sizeof (GT68xx_AFE_Parameters), 1, fcal);
2672141cc406Sopenharmony_ci  fread (&(scanner->exposure_params), sizeof (GT68xx_Exposure_Parameters), 1,
2673141cc406Sopenharmony_ci	 fcal);
2674141cc406Sopenharmony_ci
2675141cc406Sopenharmony_ci  /* loop on calibrators */
2676141cc406Sopenharmony_ci  i = 0;
2677141cc406Sopenharmony_ci  fread (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2678141cc406Sopenharmony_ci  while (!feof (fcal) && scanner->calibrations[i].dpi > 0)
2679141cc406Sopenharmony_ci    {
2680141cc406Sopenharmony_ci      fread (&(scanner->calibrations[i].pixel_x0), sizeof (SANE_Int), 1,
2681141cc406Sopenharmony_ci	     fcal);
2682141cc406Sopenharmony_ci
2683141cc406Sopenharmony_ci      fread (&width, sizeof (SANE_Int), 1, fcal);
2684141cc406Sopenharmony_ci      fread (&level, sizeof (SANE_Int), 1, fcal);
2685141cc406Sopenharmony_ci      gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].red));
2686141cc406Sopenharmony_ci      fread (scanner->calibrations[i].red->k_white, sizeof (unsigned int),
2687141cc406Sopenharmony_ci	     width, fcal);
2688141cc406Sopenharmony_ci      fread (scanner->calibrations[i].red->k_black, sizeof (unsigned int),
2689141cc406Sopenharmony_ci	     width, fcal);
2690141cc406Sopenharmony_ci      fread (scanner->calibrations[i].red->white_line, sizeof (double), width,
2691141cc406Sopenharmony_ci	     fcal);
2692141cc406Sopenharmony_ci      fread (scanner->calibrations[i].red->black_line, sizeof (double), width,
2693141cc406Sopenharmony_ci	     fcal);
2694141cc406Sopenharmony_ci
2695141cc406Sopenharmony_ci      fread (&width, sizeof (SANE_Int), 1, fcal);
2696141cc406Sopenharmony_ci      fread (&level, sizeof (SANE_Int), 1, fcal);
2697141cc406Sopenharmony_ci      gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].green));
2698141cc406Sopenharmony_ci      fread (scanner->calibrations[i].green->k_white, sizeof (unsigned int),
2699141cc406Sopenharmony_ci	     width, fcal);
2700141cc406Sopenharmony_ci      fread (scanner->calibrations[i].green->k_black, sizeof (unsigned int),
2701141cc406Sopenharmony_ci	     width, fcal);
2702141cc406Sopenharmony_ci      fread (scanner->calibrations[i].green->white_line, sizeof (double),
2703141cc406Sopenharmony_ci	     width, fcal);
2704141cc406Sopenharmony_ci      fread (scanner->calibrations[i].green->black_line, sizeof (double),
2705141cc406Sopenharmony_ci	     width, fcal);
2706141cc406Sopenharmony_ci
2707141cc406Sopenharmony_ci      fread (&width, sizeof (SANE_Int), 1, fcal);
2708141cc406Sopenharmony_ci      fread (&level, sizeof (SANE_Int), 1, fcal);
2709141cc406Sopenharmony_ci      gt68xx_calibrator_new (width, level, &(scanner->calibrations[i].blue));
2710141cc406Sopenharmony_ci      fread (scanner->calibrations[i].blue->k_white, sizeof (unsigned int),
2711141cc406Sopenharmony_ci	     width, fcal);
2712141cc406Sopenharmony_ci      fread (scanner->calibrations[i].blue->k_black, sizeof (unsigned int),
2713141cc406Sopenharmony_ci	     width, fcal);
2714141cc406Sopenharmony_ci      fread (scanner->calibrations[i].blue->white_line, sizeof (double),
2715141cc406Sopenharmony_ci	     width, fcal);
2716141cc406Sopenharmony_ci      fread (scanner->calibrations[i].blue->black_line, sizeof (double),
2717141cc406Sopenharmony_ci	     width, fcal);
2718141cc406Sopenharmony_ci
2719141cc406Sopenharmony_ci      fread (&width, sizeof (SANE_Int), 1, fcal);
2720141cc406Sopenharmony_ci      if (width > 0)
2721141cc406Sopenharmony_ci	{
2722141cc406Sopenharmony_ci	  fread (&level, sizeof (SANE_Int), 1, fcal);
2723141cc406Sopenharmony_ci	  gt68xx_calibrator_new (width, level,
2724141cc406Sopenharmony_ci				 &(scanner->calibrations[i].gray));
2725141cc406Sopenharmony_ci	  fread (scanner->calibrations[i].gray->k_white,
2726141cc406Sopenharmony_ci		 sizeof (unsigned int), width, fcal);
2727141cc406Sopenharmony_ci	  fread (scanner->calibrations[i].gray->k_black,
2728141cc406Sopenharmony_ci		 sizeof (unsigned int), width, fcal);
2729141cc406Sopenharmony_ci	  fread (scanner->calibrations[i].gray->white_line, sizeof (double),
2730141cc406Sopenharmony_ci		 width, fcal);
2731141cc406Sopenharmony_ci	  fread (scanner->calibrations[i].gray->black_line, sizeof (double),
2732141cc406Sopenharmony_ci		 width, fcal);
2733141cc406Sopenharmony_ci	}
2734141cc406Sopenharmony_ci      /* prepare for nex resolution */
2735141cc406Sopenharmony_ci      i++;
2736141cc406Sopenharmony_ci      fread (&(scanner->calibrations[i].dpi), sizeof (SANE_Int), 1, fcal);
2737141cc406Sopenharmony_ci    }
2738141cc406Sopenharmony_ci
2739141cc406Sopenharmony_ci  DBG (5, "gt68xx_read_calibration: read %d calibrations\n", i);
2740141cc406Sopenharmony_ci  fclose (fcal);
2741141cc406Sopenharmony_ci
2742141cc406Sopenharmony_ci  scanner->val[OPT_QUALITY_CAL].w = SANE_TRUE;
2743141cc406Sopenharmony_ci  scanner->val[OPT_NEED_CALIBRATION_SW].w = SANE_FALSE;
2744141cc406Sopenharmony_ci  scanner->calibrated = SANE_TRUE;
2745141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2746141cc406Sopenharmony_ci}
2747141cc406Sopenharmony_ci
2748141cc406Sopenharmony_ci
2749141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
2750