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 ¶ms); 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, ¶ms); 762141cc406Sopenharmony_ci } 763141cc406Sopenharmony_ci else 764141cc406Sopenharmony_ci { 765141cc406Sopenharmony_ci status = gt68xx_scanner_create_gray_calibrators (scanner, ¶ms); 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 ¶ms); 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 ¶ms); 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, ¶ms, &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 ¶ms); 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, ¶ms)); 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, ¶ms, &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, ¶ms); 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 ¶ms); 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, ¶ms); 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