diff options
Diffstat (limited to 'backend/genesys.c')
| -rw-r--r-- | backend/genesys.c | 8047 | 
1 files changed, 0 insertions, 8047 deletions
diff --git a/backend/genesys.c b/backend/genesys.c deleted file mode 100644 index db0a2b2..0000000 --- a/backend/genesys.c +++ /dev/null @@ -1,8047 +0,0 @@ -/* sane - Scanner Access Now Easy. - -   Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de> -   Copyright (C) 2004, 2005 Gerhard Jaeger <gerhard@gjaeger.de> -   Copyright (C) 2004-2016 Stéphane Voltz <stef.dev@free.fr> -   Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org> -   Copyright (C) 2006 Laurent Charpentier <laurent_pubs@yahoo.com> -   Copyright (C) 2007 Luke <iceyfor@gmail.com> -   Copyright (C) 2010 Chris Berry <s0457957@sms.ed.ac.uk> and Michael Rickmann <mrickma@gwdg.de> -                 for Plustek Opticbook 3600 support - -   Dynamic rasterization code was taken from the epjistsu backend by -   m. allan noah <kitno455 at gmail dot com> - -   Software processing for deskew, crop and dspeckle are inspired by allan's -   noah work in the fujitsu backend - -   This file is part of the SANE package. - -   This program is free software; you can redistribute it and/or -   modify it under the terms of the GNU General Public License as -   published by the Free Software Foundation; either version 2 of the -   License, or (at your option) any later version. - -   This program is distributed in the hope that it will be useful, but -   WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -   General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with this program; if not, write to the Free Software -   Foundation, Inc., 59 Temple Place - Suite 330, Boston, -   MA 02111-1307, USA. - -   As a special exception, the authors of SANE give permission for -   additional uses of the libraries contained in this release of SANE. - -   The exception is that, if you link a SANE library with other files -   to produce an executable, this does not by itself cause the -   resulting executable to be covered by the GNU General Public -   License.  Your use of that executable is in no way restricted on -   account of linking the SANE library code into it. - -   This exception does not, however, invalidate any other reasons why -   the executable file might be covered by the GNU General Public -   License. - -   If you submit changes to SANE to the maintainers to be included in -   a subsequent release, you agree by submitting the changes that -   those changes may be distributed with this exception intact. - -   If you write modifications of your own for SANE, it is your choice -   whether to permit this exception to apply to your modifications. -   If you do not wish that, delete this exception notice. -*/ - -/* - * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners - */ - -#define BUILD 2511 -#define BACKEND_NAME genesys - -#include "genesys.h" -#include "../include/sane/sanei_config.h" -#include "../include/sane/sanei_magic.h" -#include "genesys_devices.c" - -static SANE_Int num_devices = 0; -static Genesys_Device *first_dev = 0; -static Genesys_Scanner *first_handle = 0; -static const SANE_Device **devlist = 0; -/* Array of newly attached devices */ -static Genesys_Device **new_dev = 0; -/* Length of new_dev array */ -static SANE_Int new_dev_len = 0; -/* Number of entries alloced for new_dev */ -static SANE_Int new_dev_alloced = 0; - -static SANE_String_Const mode_list[] = { -  SANE_VALUE_SCAN_MODE_COLOR, -  SANE_VALUE_SCAN_MODE_GRAY, -  /* SANE_TITLE_HALFTONE,  currently unused */ -  SANE_VALUE_SCAN_MODE_LINEART, -  0 -}; - -static SANE_String_Const color_filter_list[] = { -  SANE_I18N ("Red"), -  SANE_I18N ("Green"), -  SANE_I18N ("Blue"), -  0 -}; - -static SANE_String_Const cis_color_filter_list[] = { -  SANE_I18N ("Red"), -  SANE_I18N ("Green"), -  SANE_I18N ("Blue"), -  SANE_I18N ("None"), -  0 -}; - -static SANE_String_Const source_list[] = { -  SANE_I18N (FLATBED), -  SANE_I18N (TRANSPARENCY_ADAPTER), -  0 -}; - -static SANE_Range swdespeck_range = { -  1, -  9, -  1 -}; - -static SANE_Range time_range = { -  0,				/* minimum */ -  60,				/* maximum */ -  0				/* quantization */ -}; - -static const SANE_Range u12_range = { -  0,				/* minimum */ -  4095,				/* maximum */ -  0				/* quantization */ -}; - -static const SANE_Range u14_range = { -  0,				/* minimum */ -  16383,			/* maximum */ -  0				/* quantization */ -}; - -static const SANE_Range u16_range = { -  0,				/* minimum */ -  65535,			/* maximum */ -  0				/* quantization */ -}; - -static const SANE_Range percentage_range = { -  SANE_FIX (0),			/* minimum */ -  SANE_FIX (100),		/* maximum */ -  SANE_FIX (1)			/* quantization */ -}; - -static const SANE_Range threshold_curve_range = { -  0,			/* minimum */ -  127,		        /* maximum */ -  1			/* quantization */ -}; - -/** - * range for brightness and contrast - */ -static const SANE_Range enhance_range = { -  -100,	/* minimum */ -  100,		/* maximum */ -  1		/* quantization */ -}; - -/** - * range for expiration time - */ -static const SANE_Range expiration_range = { -  -1,	        /* minimum */ -  30000,	/* maximum */ -  1		/* quantization */ -}; - -void -sanei_genesys_init_structs (Genesys_Device * dev) -{ -  unsigned int i, sensor_ok = 0, gpo_ok = 0, motor_ok = 0; - -  /* initialize the sensor data stuff */ -  for (i = 0; i < sizeof (Sensor) / sizeof (Genesys_Sensor); i++) -    { -      if (dev->model->ccd_type == Sensor[i].sensor_id) -	{ -	  memcpy (&dev->sensor, &Sensor[i], sizeof (Genesys_Sensor)); -	  sensor_ok = 1; -	} -    } - -  /* initialize the GPO data stuff */ -  for (i = 0; i < sizeof (Gpo) / sizeof (Genesys_Gpo); i++) -    { -      if (dev->model->gpo_type == Gpo[i].gpo_id) -	{ -	  memcpy (&dev->gpo, &Gpo[i], sizeof (Genesys_Gpo)); -	  gpo_ok = 1; -	} -    } - -  /* initialize the motor data stuff */ -  for (i = 0; i < sizeof (Motor) / sizeof (Genesys_Motor); i++) -    { -      if (dev->model->motor_type == Motor[i].motor_id) -	{ -	  memcpy (&dev->motor, &Motor[i], sizeof (Genesys_Motor)); -	  motor_ok = 1; -	} -    } - -  /* sanity check */ -  if (sensor_ok == 0 || motor_ok == 0 || gpo_ok == 0) -    { -      DBG (DBG_error0, -	   "sanei_genesys_init_structs: bad description(s) for ccd/gpo/motor=%d/%d/%d\n", -	   dev->model->ccd_type, dev->model->gpo_type, -	   dev->model->motor_type); -    } - -  /* set up initial line distance shift */ -  dev->ld_shift_r = dev->model->ld_shift_r; -  dev->ld_shift_g = dev->model->ld_shift_g; -  dev->ld_shift_b = dev->model->ld_shift_b; -} - -void -sanei_genesys_init_fe (Genesys_Device * dev) -{ -  unsigned int i; - -  DBGSTART; -  for (i = 0; i < sizeof (Wolfson) / sizeof (Genesys_Frontend); i++) -    { -      if (dev->model->dac_type == Wolfson[i].fe_id) -	{ -	  memcpy (&dev->frontend, &Wolfson[i], sizeof (Genesys_Frontend)); -	  return; -	} -    } -  DBG (DBG_error0, -       "sanei_genesys_init_fe: failed to find description for dac_type %d\n", -       dev->model->dac_type); -  DBG (DBG_info, "sanei_genesys_init_fe: dac_type %d set up\n", -       dev->model->dac_type); -  DBGCOMPLETED; -} - -/* main function for slope creation */ -/** - * This function generates a slope table using the given slope - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param slope_table    Table to write to - * @param max_steps      Size of slope_table in steps - * @param use_steps      Maximum number of steps to use for acceleration - * @param stop_at        Minimum step time to use - * @param vstart         Start step time of default slope - * @param vend           End step time of default slope - * @param steps          Step count of default slope - * @param g              Power for default slope - * @param used_steps     Final number of steps is stored here - * @param vfinal         Final step time is stored here - * @return               Time for acceleration - * @note  All times in pixel time. Correction for other motor timings is not - *        done. - */ -SANE_Int -sanei_genesys_generate_slope_table (uint16_t * slope_table, -				    unsigned int max_steps, -				    unsigned int use_steps, -                                    uint16_t stop_at, -				    uint16_t vstart, -                                    uint16_t vend, -				    unsigned int steps, -                                    double g, -				    unsigned int *used_steps, -				    unsigned int *vfinal) -{ -  double t; -  SANE_Int sum = 0; -  unsigned int i; -  unsigned int c = 0; -  uint16_t t2; -  unsigned int dummy; -  unsigned int _vfinal; -  if (!used_steps) -    used_steps = &dummy; -  if (!vfinal) -    vfinal = &_vfinal; - -  DBG (DBG_proc, "sanei_genesys_generate_slope_table: table size: %d\n", -       max_steps); - -  DBG (DBG_proc, -       "sanei_genesys_generate_slope_table: stop at time: %d, use %d steps max\n", -       stop_at, use_steps); - -  DBG (DBG_proc, -       "sanei_genesys_generate_slope_table: target slope: " -       "vstart: %d, vend: %d, steps: %d, g: %g\n", vstart, vend, steps, g); - -  sum = 0; -  c = 0; -  *used_steps = 0; - -  if (use_steps < 1) -    use_steps = 1; - -  if (stop_at < vstart) -    { -      t2 = vstart; -      for (i = 0; i < steps && i < use_steps - 1 && i < max_steps; i++, c++) -	{ -	  t = pow (((double) i) / ((double) (steps - 1)), g); -	  t2 = vstart * (1 - t) + t * vend; -	  if (t2 < stop_at) -	    break; -	  *slope_table++ = t2; -	  /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, t2); */ -	  sum += t2; -	} -      if (t2 > stop_at) -	{ -	  DBG (DBG_warn, "Can not reach target speed(%d) in %d steps.\n", -	       stop_at, use_steps); -	  DBG (DBG_warn, "Expect image to be distorted. " -	       "Ignore this if only feeding.\n"); -	} -      *vfinal = t2; -      *used_steps += i; -      max_steps -= i; -    } -  else -    *vfinal = stop_at; - -  for (i = 0; i < max_steps; i++, c++) -    { -      *slope_table++ = *vfinal; -      /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, *vfinal); */ -    } - -  (*used_steps)++; -  sum += *vfinal; - -  DBG (DBG_proc, -       "sanei_genesys_generate_slope_table: returns sum=%d, used %d steps, completed\n", -       sum, *used_steps); - -  return sum; -} - -/* Generate slope table for motor movement */ -/** - * This function generates a slope table using the slope from the motor struct - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param dev            Device struct - * @param slope_table    Table to write to - * @param max_step       Size of slope_table in steps - * @param use_steps      Maximum number of steps to use for acceleration - * @param step_type      Generate table for this step_type. 0=>full, 1=>half, - *                       2=>quarter - * @param exposure_time  Minimum exposure time of a scan line - * @param yres           Resolution of a scan line - * @param used_steps     Final number of steps is stored here - * @param final_exposure Final step time is stored here - * @param power_mode     Power mode (related to the Vref used) of the motor - * @return               Time for acceleration - * @note  all times in pixel time - */ -SANE_Int -sanei_genesys_create_slope_table3 (Genesys_Device * dev, -				   uint16_t * slope_table, -                                   int max_step, -				   unsigned int use_steps, -				   int step_type, -                                   int exposure_time, -				   double yres, -				   unsigned int *used_steps, -				   unsigned int *final_exposure, -				   int power_mode) -{ -  unsigned int sum_time = 0; -  unsigned int vtarget; -  unsigned int vend; -  unsigned int vstart; -  unsigned int vfinal; - -  DBG (DBG_proc, -       "%s: step_type = %d, " -       "exposure_time = %d, yres = %g, power_mode = %d\n", __func__, step_type, -       exposure_time, yres, power_mode); - -  /* final speed */ -  vtarget = (exposure_time * yres) / dev->motor.base_ydpi; - -  vstart = dev->motor.slopes[power_mode][step_type].maximum_start_speed; -  vend = dev->motor.slopes[power_mode][step_type].maximum_speed; - -  vtarget >>= step_type; -  if (vtarget > 65535) -    vtarget = 65535; - -  vstart >>= step_type; -  if (vstart > 65535) -    vstart = 65535; - -  vend >>= step_type; -  if (vend > 65535) -    vend = 65535; - -  sum_time = sanei_genesys_generate_slope_table (slope_table, -                                                 max_step, -						 use_steps, -						 vtarget, -						 vstart, -						 vend, -						 dev->motor.slopes[power_mode][step_type].minimum_steps << step_type, -						 dev->motor.slopes[power_mode][step_type].g, -                                                 used_steps, -						 &vfinal); - -  if (final_exposure) -    *final_exposure = (vfinal * dev->motor.base_ydpi) / yres; - -  DBG (DBG_proc, -       "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", -       sum_time); - -  return sum_time; -} - - -/* alternate slope table creation function        */ -/* the hardcoded values (g and vstart) will go in a motor struct */ -static SANE_Int -genesys_create_slope_table2 (Genesys_Device * dev, -			     uint16_t * slope_table, int steps, -			     int step_type, int exposure_time, -			     SANE_Bool same_speed, double yres, -			     int power_mode) -{ -  double t, g; -  SANE_Int sum = 0; -  int vstart, vend; -  int i; - -  DBG (DBG_proc, -       "sanei_genesys_create_slope_table2: %d steps, step_type = %d, " -       "exposure_time = %d, same_speed = %d, yres = %.2f, power_mode = %d\n", -       steps, step_type, exposure_time, same_speed, yres, power_mode); - -  /* start speed */ -  if (dev->model->motor_type == MOTOR_5345) -    { -      if (yres < dev->motor.base_ydpi / 6) -	vstart = 2500; -      else -	vstart = 2000; -    } -  else -    { -      if (steps == 2) -	vstart = exposure_time; -      else if (steps == 3) -	vstart = 2 * exposure_time; -      else if (steps == 4) -	vstart = 1.5 * exposure_time; -      else if (steps == 120) -	vstart = 1.81674 * exposure_time; -      else -	vstart = exposure_time; -    } - -  /* final speed */ -  vend = (exposure_time * yres) / (dev->motor.base_ydpi * (1 << step_type)); - -  /* -     type=1 : full -     type=2 : half -     type=4 : quarter -     vend * type * base_ydpi / exposure = yres -   */ - -  /* acceleration */ -  switch (steps) -    { -    case 255: -      /* test for special case: fast moving slope */ -      /* todo: a 'fast' boolean parameter should be better */ -      if (vstart == 2000) -	g = 0.2013; -      else -	g = 0.1677; -      break; -    case 120: -      g = 0.5; -      break; -    case 67: -      g = 0.5; -      break; -    case 64: -      g = 0.2555; -      break; -    case 44: -      g = 0.5; -      break; -    case 4: -      g = 0.5; -      break; -    case 3: -      g = 1; -      break; -    case 2: -      vstart = vend; -      g = 1; -      break; -    default: -      g = 0.2635; -    } - -  /* if same speed, no 'g' */ -  sum = 0; -  if (same_speed) -    { -      for (i = 0; i < 255; i++) -	{ -	  slope_table[i] = vend; -	  sum += slope_table[i]; -	  DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); -	} -    } -  else -    { -      for (i = 0; i < steps; i++) -	{ -	  t = pow (((double) i) / ((double) (steps - 1)), g); -	  slope_table[i] = vstart * (1 - t) + t * vend; -	  DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); -	  sum += slope_table[i]; -	} -      for (i = steps; i < 255; i++) -	{ -	  slope_table[i] = vend; -	  DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); -	  sum += slope_table[i]; -	} -    } - -  DBG (DBG_proc, -       "sanei_genesys_create_slope_table2: returns sum=%d, completed\n", sum); - -  return sum; -} - -/* Generate slope table for motor movement */ -/* todo: check details */ -SANE_Int -sanei_genesys_create_slope_table (Genesys_Device * dev, -				  uint16_t * slope_table, int steps, -				  int step_type, int exposure_time, -				  SANE_Bool same_speed, double yres, -				  int power_mode) -{ -  double t; -  double start_speed; -  double g; -  uint32_t time_period; -  int sum_time = 0; -  int i, divider; -  int same_step; - -  if (dev->model->motor_type == MOTOR_5345 -      || dev->model->motor_type == MOTOR_HP2300 -      || dev->model->motor_type == MOTOR_HP2400) -    return genesys_create_slope_table2 (dev, slope_table, steps, -					step_type, exposure_time, -					same_speed, yres, power_mode); - -  DBG (DBG_proc, -       "sanei_genesys_create_slope_table: %d steps, step_type = %d, " -       "exposure_time = %d, same_speed =%d\n", steps, step_type, -       exposure_time, same_speed); -  DBG (DBG_proc, "sanei_genesys_create_slope_table: yres = %.2f\n", yres); - -  g = 0.6; -  start_speed = 0.01; -  same_step = 4; -  divider = 1 << step_type; - -  time_period = -    (uint32_t) (yres * exposure_time / dev->motor.base_ydpi /*MOTOR_GEAR */ ); -  if ((time_period < 2000) && (same_speed)) -    same_speed = SANE_FALSE; - -  time_period = time_period / divider; - -  if (same_speed) -    { -      for (i = 0; i < steps; i++) -	{ -	  slope_table[i] = (uint16_t) time_period; -	  sum_time += time_period; - -	  DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); -	} -      DBG (DBG_info, -	   "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", -	   sum_time); -      return sum_time; -    } - -  if (time_period > MOTOR_SPEED_MAX * 5) -    { -      g = 1.0; -      start_speed = 0.05; -      same_step = 2; -    } -  else if (time_period > MOTOR_SPEED_MAX * 4) -    { -      g = 0.8; -      start_speed = 0.04; -      same_step = 2; -    } -  else if (time_period > MOTOR_SPEED_MAX * 3) -    { -      g = 0.7; -      start_speed = 0.03; -      same_step = 2; -    } -  else if (time_period > MOTOR_SPEED_MAX * 2) -    { -      g = 0.6; -      start_speed = 0.02; -      same_step = 3; -    } - -  if (dev->model->motor_type == MOTOR_ST24) -    { -      steps = 255; -      switch ((int) yres) -	{ -	case 2400: -	  g = 0.1672; -	  start_speed = 1.09; -	  break; -	case 1200: -	  g = 1; -	  start_speed = 6.4; -	  break; -	case 600: -	  g = 0.1672; -	  start_speed = 1.09; -	  break; -	case 400: -	  g = 0.2005; -	  start_speed = 20.0 / 3.0 /*7.5 */ ; -	  break; -	case 300: -	  g = 0.253; -	  start_speed = 2.182; -	  break; -	case 150: -	  g = 0.253; -	  start_speed = 4.367; -	  break; -	default: -	  g = 0.262; -	  start_speed = 7.29; -	} -      same_step = 1; -    } - -  if (steps <= same_step) -    { -      time_period = -	(uint32_t) (yres * exposure_time / -		    dev->motor.base_ydpi /*MOTOR_GEAR */ ); -      time_period = time_period / divider; - -      if (time_period > 65535) -	time_period = 65535; - -      for (i = 0; i < same_step; i++) -	{ -	  slope_table[i] = (uint16_t) time_period; -	  sum_time += time_period; - -	  DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); -	} - -      DBG (DBG_proc, -	   "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", -	   sum_time); -      return sum_time; -    } - -  for (i = 0; i < steps; i++) -    { -      double j = ((double) i) - same_step + 1;	/* start from 1/16 speed */ - -      if (j <= 0) -	t = 0; -      else -	t = pow (j / (steps - same_step), g); - -      time_period =		/* time required for full steps */ -	(uint32_t) (yres * exposure_time / -		    dev->motor.base_ydpi /*MOTOR_GEAR */  * -		    (start_speed + (1 - start_speed) * t)); - -      time_period = time_period / divider; -      if (time_period > 65535) -	time_period = 65535; - -      slope_table[i] = (uint16_t) time_period; -      sum_time += time_period; - -      DBG (DBG_io, "slope_table[%d] = %d\n", i, slope_table[i]); -    } - -  DBG (DBG_proc, -       "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", -       sum_time); - -  return sum_time; -} - -/** @brief computes gamma table - * Generates a gamma table of the given length within 0 and the given - * maximum value - * @param gamma_table gamma table to fill - * @param size size of the table - * @param maximum value allowed for gamma - * @param gamma_max maximum gamma value - * @param gamma gamma to compute values - * @return a gamma table filled with the computed values - * */ -void -sanei_genesys_create_gamma_table (uint16_t * gamma_table, int size, -				  float maximum, float gamma_max, float gamma) -{ -  int i; -  float value; - -  if(gamma_table==NULL) -    { -      DBG (DBG_proc, "sanei_genesys_create_gamma_table: gamma table is NULL\n"); -      return; -    } -  DBG (DBG_proc, -       "sanei_genesys_create_gamma_table: size = %d, " -       "maximum = %g, gamma_max = %g, gamma = %g\n", -       size, maximum, gamma_max, gamma); -  for (i = 0; i < size; i++) -    { -      value = gamma_max * pow ((float) i / size, 1.0 / gamma); -      if (value > maximum) -	value = maximum; -      gamma_table[i] = value; -    } -  DBG (DBG_proc, "sanei_genesys_create_gamma_table: completed\n"); -} - - -/* computes the exposure_time on the basis of the given vertical dpi, -   the number of pixels the ccd needs to send, -   the step_type and the corresponding maximum speed from the motor struct */ -/* -  Currently considers maximum motor speed at given step_type, minimum -  line exposure needed for conversion and led exposure time. - -  TODO: Should also consider maximum transfer rate: ~6.5MB/s. -    Note: The enhance option of the scanners does _not_ help. It only halves -          the amount of pixels transfered. - */ -SANE_Int -sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, -			      int step_type, int endpixel, -			      int exposure_by_led, int power_mode) -{ -  int exposure_by_ccd = endpixel + 32; -  int exposure_by_motor = -    (dev->motor.slopes[power_mode][step_type].maximum_speed -     * dev->motor.base_ydpi) / ydpi; - -  int exposure = exposure_by_ccd; - -  if (exposure < exposure_by_motor) -    exposure = exposure_by_motor; - -  if (exposure < exposure_by_led && dev->model->is_cis) -    exposure = exposure_by_led; - -  DBG (DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d, power=%d => exposure=%d\n", -       __func__, (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); -  return exposure; -} - -/* computes the exposure_time on the basis of the given horizontal dpi */ -/* we will clean/simplify it by using constants from a future motor struct */ -SANE_Int -sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, -			     int xdpi) -{ -  if (dev->model->motor_type == MOTOR_5345) -    { -      if (dev->model->cmd_set->get_filter_bit (reg)) -	{ -	  /* monochrome */ -	  switch (xdpi) -	    { -	    case 600: -	      return 8500; -	    case 500: -	    case 400: -	    case 300: -	    case 250: -	    case 200: -	    case 150: -	      return 5500; -	    case 100: -	      return 6500; -	    case 50: -	      return 12000; -	    default: -	      return 11000; -	    } -	} -      else -	{ -	  /* color scan */ -	  switch (xdpi) -	    { -	    case 300: -	    case 250: -	    case 200: -	      return 5500; -	    case 50: -	      return 12000; -	    default: -	      return 11000; -	    } -	} -    } -  else if (dev->model->motor_type == MOTOR_HP2400) -    { -      if (dev->model->cmd_set->get_filter_bit (reg)) -	{ -	  /* monochrome */ -	  switch (xdpi) -	    { -	    case 200: -	      return 7210; -	    default: -	      return 11111; -	    } -	} -      else -	{ -	  /* color scan */ -	  switch (xdpi) -	    { -	    case 600: -	      return 8751;	/*11902; 19200 */ -	    default: -	      return 11111; -	    } -	} -    } -  else if (dev->model->motor_type == MOTOR_HP2300) -    { -      if (dev->model->cmd_set->get_filter_bit (reg)) -	{ -	  /* monochrome */ -	  switch (xdpi) -	    { -	    case 600: -	      return 8699;	/* 3200; */ -	    case 300: -	      return 3200;	/*10000;, 3200 -> too dark */ -	    case 150: -	      return 4480;	/* 3200 ???, warmup needs 4480 */ -	    case 75: -	      return 5500; -	    default: -	      return 11111; -	    } -	} -      else -	{ -	  /* color scan */ -	  switch (xdpi) -	    { -	    case 600: -	      return 8699; -	    case 300: -	      return 4349; -	    case 150: -	    case 75: -	      return 4480; -	    default: -	      return 11111; -	    } -	} -    } -  return dev->settings.exposure_time; -} - - - -/* Sends a block of shading information to the scanner. -   The data is placed at address 0x0000 for color mode, gray mode and -   unconditionally for the following CCD chips: HP2300, HP2400 and HP5345 -   In the other cases (lineart, halftone on ccd chips not mentioned) the -   addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for -   dpihw==2. //Note: why this? - -   The data needs to be of size "size", and in little endian byte order. - */ -#ifndef UNIT_TESTING -static -#endif -  SANE_Status -genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data, -				 int size) -{ -  int dpihw; -  int start_address; -  SANE_Status status; - -  DBG (DBG_proc, "%s: (size = %d)\n", __func__, size); - -  /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to -   * a per ASIC shading data loading function if available. -   * It is also used for scanners using SHDAREA */ -  if(dev->model->cmd_set->send_shading_data!=NULL) -    { -        status=dev->model->cmd_set->send_shading_data(dev, data, size); -        DBGCOMPLETED; -        return status; -    } - -  /* gl646, gl84[123] case */ -  dpihw = sanei_genesys_read_reg_from_set (dev->reg, 0x05) >> 6; - -  /* TODO invert the test so only the 2 models behaving like that are -   * tested instead of adding all the others */ -  /* many scanners send coefficient for lineart/gray like in color mode */ -  if (dev->settings.scan_mode < 2 -      && dev->model->ccd_type != CCD_PLUSTEK3800 -      && dev->model->ccd_type != CCD_KVSS080 -      && dev->model->ccd_type != CCD_G4050 -      && dev->model->ccd_type != CCD_CS4400F -      && dev->model->ccd_type != CCD_CS8400F -      && dev->model->ccd_type != CCD_DSMOBILE600 -      && dev->model->ccd_type != CCD_XP300 -      && dev->model->ccd_type != CCD_DP665 -      && dev->model->ccd_type != CCD_DP685 -      && dev->model->ccd_type != CIS_CANONLIDE80 -      && dev->model->ccd_type != CCD_ROADWARRIOR -      && dev->model->ccd_type != CCD_HP2300 -      && dev->model->ccd_type != CCD_HP2400 -      && dev->model->ccd_type != CCD_HP3670 -      && dev->model->ccd_type != CCD_5345)	/* lineart, halftone */ -    { -      if (dpihw == 0)		/* 600 dpi */ -	start_address = 0x02a00; -      else if (dpihw == 1)	/* 1200 dpi */ -	start_address = 0x05500; -      else if (dpihw == 2)	/* 2400 dpi */ -	start_address = 0x0a800; -      else			/* reserved */ -	return SANE_STATUS_INVAL; -    } -  else				/* color */ -    start_address = 0x00; - -  status = sanei_genesys_set_buffer_address (dev, start_address); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, -           sane_strstatus (status)); -      return status; -    } - -  status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, -	   sane_strstatus (status)); -      return status; -    } - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -/* ? */ -SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, int pixels_per_line) -{ -  SANE_Status status; -  uint8_t *shading_data, *shading_data_ptr; -  int channels; -  int i; - -  /* these models don't need to init shading data due to the use of specific send shading data -     function */ -  if (dev->model->ccd_type==CCD_KVSS080 -   || dev->model->ccd_type==CCD_G4050 -   || dev->model->ccd_type==CCD_CS4400F -   || dev->model->ccd_type==CCD_CS8400F -   || dev->model->cmd_set->send_shading_data!=NULL) -    return SANE_STATUS_GOOD; - -  DBG (DBG_proc, "sanei_genesys_init_shading_data (pixels_per_line = %d)\n", -       pixels_per_line); - -  if (dev->settings.scan_mode >= 2)	/* 3 pass or single pass color */ -    channels = 3; -  else -    channels = 1; - -  shading_data = malloc (pixels_per_line * 4 * channels);	/* 16 bit black, 16 bit white */ -  if (!shading_data) -    { -      DBG (DBG_error, -	   "sanei_genesys_init_shading_data: failed to allocate memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  shading_data_ptr = shading_data; - -  for (i = 0; i < pixels_per_line * channels; i++) -    { -      *shading_data_ptr++ = 0x00;	/* dark lo */ -      *shading_data_ptr++ = 0x00;	/* dark hi */ -      *shading_data_ptr++ = 0x00;	/* white lo */ -      *shading_data_ptr++ = 0x40;	/* white hi -> 0x4000 */ -    } - -  status = genesys_send_offset_and_shading (dev, -                                            shading_data, -                                            pixels_per_line * 4 * channels); -  free (shading_data); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, -	  sane_strstatus (status)); -    } - -  DBGCOMPLETED; -  return status; -} - - -/* Find the position of the reference point: -   takes gray level 8 bits data and find -   first CCD usable pixel and top of scanning area */ -SANE_Status -sanei_genesys_search_reference_point (Genesys_Device * dev, uint8_t * data, -				      int start_pixel, int dpi, int width, -				      int height) -{ -  int x, y; -  int current, left, top = 0; -  uint8_t *image; -  int size, count; -  int level = 80;		/* edge threshold level */ - -  /*sanity check */ -  if ((width < 3) || (height < 3)) -    return SANE_STATUS_INVAL; - -  /* transformed image data */ -  size = width * height; -  image = malloc (size); -  if (!image) -    { -      DBG (DBG_error, -	   "sanei_genesys_search_reference_point: failed to allocate memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  /* laplace filter to denoise picture */ -  memcpy (image, data, size);	/* to initialize unprocessed part of the image buffer */ -  for (y = 1; y < height - 1; y++) -    for (x = 1; x < width - 1; x++) -      { -	image[y * width + x] = -	  (data[(y - 1) * width + x + 1] + 2 * data[(y - 1) * width + x] + -	   data[(y - 1) * width + x - 1] + 2 * data[y * width + x + 1] + -	   4 * data[y * width + x] + 2 * data[y * width + x - 1] + -	   data[(y + 1) * width + x + 1] + 2 * data[(y + 1) * width + x] + -	   data[(y + 1) * width + x - 1]) / 16; -      } - -  memcpy (data, image, size); -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("laplace.pnm", image, 8, 1, width, height); - -  /* apply X direction sobel filter -     -1  0  1 -     -2  0  2 -     -1  0  1 -     and finds threshold level -   */ -  level = 0; -  for (y = 2; y < height - 2; y++) -    for (x = 2; x < width - 2; x++) -      { -	current = -	  data[(y - 1) * width + x + 1] - data[(y - 1) * width + x - 1] + -	  2 * data[y * width + x + 1] - 2 * data[y * width + x - 1] + -	  data[(y + 1) * width + x + 1] - data[(y + 1) * width + x - 1]; -	if (current < 0) -	  current = -current; -	if (current > 255) -	  current = 255; -	image[y * width + x] = current; -	if (current > level) -	  level = current; -      } -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("xsobel.pnm", image, 8, 1, width, height); - -  /* set up detection level */ -  level = level / 3; - -  /* find left black margin first -     todo: search top before left -     we average the result of N searches */ -  left = 0; -  count = 0; -  for (y = 2; y < 11; y++) -    { -      x = 8; -      while ((x < width / 2) && (image[y * width + x] < level)) -	{ -	  image[y * width + x] = 255; -	  x++; -	} -      count++; -      left += x; -    } -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("detected-xsobel.pnm", image, 8, 1, width, -				  height); -  left = left / count; - -  /* turn it in CCD pixel at full sensor optical resolution */ -  dev->sensor.CCD_start_xoffset = -    start_pixel + (left * dev->sensor.optical_res) / dpi; - -  /* find top edge by detecting black strip */ -  /* apply Y direction sobel filter -     -1 -2 -1 -     0  0  0 -     1  2  1 -   */ -  level = 0; -  for (y = 2; y < height - 2; y++) -    for (x = 2; x < width - 2; x++) -      { -	current = -	  -data[(y - 1) * width + x + 1] - 2 * data[(y - 1) * width + x] - -	  data[(y - 1) * width + x - 1] + data[(y + 1) * width + x + 1] + -	  2 * data[(y + 1) * width + x] + data[(y + 1) * width + x - 1]; -	if (current < 0) -	  current = -current; -	if (current > 255) -	  current = 255; -	image[y * width + x] = current; -	if (current > level) -	  level = current; -      } -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("ysobel.pnm", image, 8, 1, width, height); - -  /* set up detection level */ -  level = level / 3; - -  /* search top of horizontal black stripe : TODO yet another flag */ -  if (dev->model->ccd_type == CCD_5345 -      && dev->model->motor_type == MOTOR_5345) -    { -      top = 0; -      count = 0; -      for (x = width / 2; x < width - 1; x++) -	{ -	  y = 2; -	  while ((y < height) && (image[x + y * width] < level)) -	    { -	      image[y * width + x] = 255; -	      y++; -	    } -	  count++; -	  top += y; -	} -      if (DBG_LEVEL >= DBG_data) -	sanei_genesys_write_pnm_file ("detected-ysobel.pnm", image, 8, 1, -				      width, height); -      top = top / count; - -      /* bottom of black stripe is of fixed witdh, this hardcoded value -       * will be moved into device struct if more such values are needed */ -      top += 10; -      dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); -      DBG (DBG_info, -	   "sanei_genesys_search_reference_point: black stripe y_offset = %f mm \n", -	   SANE_UNFIX (dev->model->y_offset_calib)); -    } - -  /* find white corner in dark area : TODO yet another flag */ -  if ((dev->model->ccd_type == CCD_HP2300 -       && dev->model->motor_type == MOTOR_HP2300) -      || (dev->model->ccd_type == CCD_HP2400 -	  && dev->model->motor_type == MOTOR_HP2400) -      || (dev->model->ccd_type == CCD_HP3670 -	  && dev->model->motor_type == MOTOR_HP3670)) -    { -      top = 0; -      count = 0; -      for (x = 10; x < 60; x++) -	{ -	  y = 2; -	  while ((y < height) && (image[x + y * width] < level)) -	    y++; -	  top += y; -	  count++; -	} -      top = top / count; -      dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); -      DBG (DBG_info, -	   "sanei_genesys_search_reference_point: white corner y_offset = %f mm\n", -	   SANE_UNFIX (dev->model->y_offset_calib)); -    } - -  free (image); -  DBG (DBG_proc, -       "sanei_genesys_search_reference_point: CCD_start_xoffset = %d, left = %d, top = %d\n", -       dev->sensor.CCD_start_xoffset, left, top); - -  return SANE_STATUS_GOOD; -} - - -void -sanei_genesys_calculate_zmode2 (SANE_Bool two_table, -				uint32_t exposure_time, -				uint16_t * slope_table, -				int reg21, -				int move, int reg22, uint32_t * z1, -				uint32_t * z2) -{ -  int i; -  int sum; -  DBG (DBG_info, "sanei_genesys_calculate_zmode2: two_table=%d\n", two_table); - -  /* acceleration total time */ -  sum = 0; -  for (i = 0; i < reg21; i++) -    sum += slope_table[i]; - -  /* compute Z1MOD */ -  /* c=sum(slope_table;reg21) -     d=reg22*cruising speed -     Z1MOD=(c+d) % exposure_time */ -  *z1 = (sum + reg22 * slope_table[reg21 - 1]) % exposure_time; - -  /* compute Z2MOD */ -  /* a=sum(slope_table;reg21), b=move or 1 if 2 tables */ -  /* Z2MOD=(a+b) % exposure_time */ -  if (!two_table) -    sum = sum + (move * slope_table[reg21 - 1]); -  else -    sum = sum + slope_table[reg21 - 1]; -  *z2 = sum % exposure_time; -} - - -/* huh? */ -/* todo: double check */ -/* Z1 and Z2 seem to be a time to synchronize with clock or a phase correction */ -/* steps_sum	is the result of create_slope_table 	*/ -/* last_speed	is the last entry of the slope_table 	*/ -/* feedl	is registers 3d,3e,3f 			 */ -/* fastfed	is register 02 bit 3		 	*/ -/* scanfed	is register 1f 				*/ -/* fwdstep	is register 22 				*/ -/* tgtime	is register 6c bit 6+7 >> 6 		*/ - -void -sanei_genesys_calculate_zmode (uint32_t exposure_time, -			       uint32_t steps_sum, uint16_t last_speed, -			       uint32_t feedl, uint8_t fastfed, -			       uint8_t scanfed, uint8_t fwdstep, -			       uint8_t tgtime, uint32_t * z1, uint32_t * z2) -{ -  uint8_t exposure_factor; - -  exposure_factor = pow (2, tgtime);	/* todo: originally, this is always 2^0 ! */ - -  /* Z1 is for buffer-full backward forward moving */ -  *z1 = -    exposure_factor * ((steps_sum + fwdstep * last_speed) % exposure_time); - -  /* Z2 is for acceleration before scan */ -  if (fastfed)			/* two curve mode */ -    { -      *z2 = -	exposure_factor * ((steps_sum + scanfed * last_speed) % -			   exposure_time); -    } -  else				/* one curve mode */ -    { -      *z2 = -	exposure_factor * ((steps_sum + feedl * last_speed) % exposure_time); -    } -} - - -static void -genesys_adjust_gain (double *applied_multi, -		     uint8_t * new_gain, double multi, uint8_t gain) -{ -  double voltage, original_voltage; - -  DBG (DBG_proc, "genesys_adjust_gain: multi=%f, gain=%d\n", multi, gain); - -  voltage = 0.5 + gain * 0.25; -  original_voltage = voltage; - -  voltage *= multi; - -  *new_gain = (uint8_t) ((voltage - 0.5) * 4); -  if (*new_gain > 0x0e) -    *new_gain = 0x0e; - -  voltage = 0.5 + (*new_gain) * 0.25; - -  *applied_multi = voltage / original_voltage; - -  DBG (DBG_proc, -       "genesys_adjust_gain: orig voltage=%.2f, new voltage=%.2f, " -       "*applied_multi=%f, *new_gain=%d\n", original_voltage, voltage, -       *applied_multi, *new_gain); -  return; -} - - -/* todo: is return status necessary (unchecked?) */ -static SANE_Status -genesys_average_white (Genesys_Device * dev, int channels, int channel, -		       uint8_t * data, int size, int *max_average) -{ -  int gain_white_ref, sum, range; -  int average; -  int i; - -  DBG (DBG_proc, -       "genesys_average_white: channels=%d, channel=%d, size=%d\n", -       channels, channel, size); - -  range = size / 50; - -  if (dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY)	/* transparency mode */ -    gain_white_ref = dev->sensor.fau_gain_white_ref * 256; -  else -    gain_white_ref = dev->sensor.gain_white_ref * 256; - -  if (range < 1) -    range = 1; - -  size = size / (2 * range * channels); - -  data += (channel * 2); - -  *max_average = 0; - -  while (size--) -    { -      sum = 0; -      for (i = 0; i < range; i++) -	{ -	  sum += (*data); -	  sum += *(data + 1) * 256; -	  data += (2 * channels);	/* byte based */ -	} - -      average = (sum / range); -      if (average > *max_average) -	*max_average = average; -    } - -  DBG (DBG_proc, -       "genesys_average_white: max_average=%d, gain_white_ref = %d, finished\n", -       *max_average, gain_white_ref); - -  if (*max_average >= gain_white_ref) -    return SANE_STATUS_INVAL; - -  return SANE_STATUS_GOOD; -} - -/* todo: understand, values are too high */ -static int -genesys_average_black (Genesys_Device * dev, int channel, -		       uint8_t * data, int pixels) -{ -  int i; -  int sum; -  int pixel_step; - -  DBG (DBG_proc, "genesys_average_black: channel=%d, pixels=%d\n", -       channel, pixels); - -  sum = 0; - -  if (dev->settings.scan_mode == SCAN_MODE_COLOR)	/* single pass color */ -    { -      data += (channel * 2); -      pixel_step = 3 * 2; -    } -  else -    { -      pixel_step = 2; -    } - -  for (i = 0; i < pixels; i++) -    { -      sum += *data; -      sum += *(data + 1) * 256; - -      data += pixel_step; -    } - -  DBG (DBG_proc, "genesys_average_black = %d\n", sum / pixels); - -  return (int) (sum / pixels); -} - - -/* todo: check; it works but the lines 1, 2, and 3 are too dark even with the -   same offset and gain settings? */ -static SANE_Status -genesys_coarse_calibration (Genesys_Device * dev) -{ -  int size; -  int black_pixels; -  int white_average; -  int channels; -  SANE_Status status; -  uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 };	/* first value isn't used */ -  uint16_t white[12], dark[12]; -  int i, j; -  uint8_t *calibration_data, *all_data; - -  DBG (DBG_info, "genesys_coarse_calibration (scan_mode = %d)\n", -       dev->settings.scan_mode); - -  black_pixels = dev->sensor.black_pixels -    * dev->settings.xres / dev->sensor.optical_res; - -  if (dev->settings.scan_mode == SCAN_MODE_COLOR)	/* single pass color */ -    channels = 3; -  else -    channels = 1; - -  DBG (DBG_info, "channels %d y_size %d xres %d\n", -       channels, dev->model->y_size, dev->settings.xres); -  size = -    channels * 2 * SANE_UNFIX (dev->model->y_size) * dev->settings.xres / -    25.4; -  /*       1        1               mm                      1/inch        inch/mm */ - -  calibration_data = malloc (size); -  if (!calibration_data) -    { -      DBG (DBG_error, -	   "genesys_coarse_calibration: failed to allocate memory(%d bytes)\n", -	   size); -      return SANE_STATUS_NO_MEM; -    } - -  all_data = calloc (1, size * 4); - -  status = dev->model->cmd_set->set_fe (dev, AFE_INIT); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, -	   sane_strstatus (status)); -      free(all_data); -      free(calibration_data); -      return status; -    } - -  dev->frontend.sign[0] = 0; -  dev->frontend.sign[1] = 0; -  dev->frontend.sign[2] = 0; -  dev->frontend.gain[0] = 2; -  dev->frontend.gain[1] = 2; -  dev->frontend.gain[2] = 2;	/* todo: ?  was 2 */ -  dev->frontend.offset[0] = offset[0]; -  dev->frontend.offset[1] = offset[0]; -  dev->frontend.offset[2] = offset[0]; - -  for (i = 0; i < 4; i++)	/* read 4 lines */ -    { -      if (i < 3)		/* first 3 lines */ -        { -	  dev->frontend.offset[0] = offset[i]; -          dev->frontend.offset[1] = offset[i]; -	  dev->frontend.offset[2] = offset[i]; -        } - -      if (i == 1)		/* second line */ -	{ -	  double applied_multi; -	  double gain_white_ref; - -	  if (dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY)	/* Transparency */ -	    gain_white_ref = dev->sensor.fau_gain_white_ref * 256; -	  else -	    gain_white_ref = dev->sensor.gain_white_ref * 256; -	  /* white and black are defined downwards */ - -	  genesys_adjust_gain (&applied_multi, -			       &dev->frontend.gain[0], -			       gain_white_ref / (white[0] - dark[0]), -			       dev->frontend.gain[0]); -	  genesys_adjust_gain (&applied_multi, -			       &dev->frontend.gain[1], -			       gain_white_ref / (white[1] - dark[1]), -			       dev->frontend.gain[1]); -	  genesys_adjust_gain (&applied_multi, -			       &dev->frontend.gain[2], -			       gain_white_ref / (white[2] - dark[2]), -			       dev->frontend.gain[2]); - -	  dev->frontend.gain[0] = dev->frontend.gain[1] = -	    dev->frontend.gain[2] = 2; - -	  status = -	    sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[0]); -	  if (status != SANE_STATUS_GOOD)	/* todo: this was 0x28 + 3 ? */ -	    { -	      DBG (DBG_error, -		   "genesys_coarse_calibration: Failed to write gain[0]: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -	  status = -	    sanei_genesys_fe_write_data (dev, 0x29, dev->frontend.gain[1]); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_coarse_calibration: Failed to write gain[1]: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -	  status = -	    sanei_genesys_fe_write_data (dev, 0x2a, dev->frontend.gain[2]); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_coarse_calibration: Failed to write gain[2]: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} - -      if (i == 3)		/* last line */ -	{ -	  double x, y, rate; - -	  for (j = 0; j < 3; j++) -	    { - -	      x = -		(double) (dark[(i - 2) * 3 + j] - -			  dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 - -							  offset[i - 2] / 2); -	      y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j]; -	      rate = (x - DARK_VALUE - y) * 254 / x + 0.5; - -	      dev->frontend.offset[j] = (uint8_t) (rate); - -	      if (dev->frontend.offset[j] > 0x7f) -		dev->frontend.offset[j] = 0x7f; -	      dev->frontend.offset[j] <<= 1; -	    } -	} -      status = -	sanei_genesys_fe_write_data (dev, 0x20, dev->frontend.offset[0]); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to write offset[0]: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = -	sanei_genesys_fe_write_data (dev, 0x21, dev->frontend.offset[1]); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to write offset[1]: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = -	sanei_genesys_fe_write_data (dev, 0x22, dev->frontend.offset[2]); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to write offset[2]: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      DBG (DBG_info, -	   "genesys_coarse_calibration: doing scan: sign: %d/%d/%d, gain: %d/%d/%d, offset: %d/%d/%d\n", -	   dev->frontend.sign[0], dev->frontend.sign[1], -	   dev->frontend.sign[2], dev->frontend.gain[0], -	   dev->frontend.gain[1], dev->frontend.gain[2], -	   dev->frontend.offset[0], dev->frontend.offset[1], -	   dev->frontend.offset[2]); - -      status = -	dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to begin scan: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = -	sanei_genesys_read_data_from_scanner (dev, calibration_data, size); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to read data: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      memcpy (all_data + i * size, calibration_data, size); -      if (i == 3)		/* last line */ -	{ -	  SANE_Byte *all_data_8 = malloc (size * 4 / 2); -	  unsigned int count; - -	  for (count = 0; count < (unsigned int) (size * 4 / 2); count++) -	    all_data_8[count] = all_data[count * 2 + 1]; -	  status = -	    sanei_genesys_write_pnm_file ("coarse.pnm", all_data_8, 8, -					  channels, size / 6, 4); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_coarse_calibration: sanei_genesys_write_pnm_file failed: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} - -      status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_coarse_calibration: Failed to end scan: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -      if (dev->settings.scan_mode == SCAN_MODE_COLOR)	/* single pass color */ -	{ -	  for (j = 0; j < 3; j++) -	    { -	      genesys_average_white (dev, 3, j, calibration_data, size, -				     &white_average); -	      white[i * 3 + j] = white_average; -	      dark[i * 3 + j] = -		genesys_average_black (dev, j, calibration_data, -				       black_pixels); -	      DBG (DBG_info, -		   "genesys_coarse_calibration: white[%d]=%d, black[%d]=%d\n", -		   i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]); -	    } -	} -      else			/* one color-component modes */ -	{ -	  genesys_average_white (dev, 1, 0, calibration_data, size, -				 &white_average); -	  white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] = -	    white_average; -	  dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] = -	    genesys_average_black (dev, 0, calibration_data, black_pixels); -	} - -      if (i == 3) -	{ -	  if (dev->settings.scan_mode == SCAN_MODE_COLOR)	/* single pass color */ -	    { -	      /* todo: huh? */ -	      dev->dark[0] = -		(uint16_t) (1.6925 * dark[i * 3 + 0] + 0.1895 * 256); -	      dev->dark[1] = -		(uint16_t) (1.4013 * dark[i * 3 + 1] + 0.3147 * 256); -	      dev->dark[2] = -		(uint16_t) (1.2931 * dark[i * 3 + 2] + 0.1558 * 256); -	    } -	  else			/* one color-component modes */ -	    { -	      switch (dev->settings.color_filter) -		{ -		case 0: -		default: -		  dev->dark[0] = -		    (uint16_t) (1.6925 * dark[i * 3 + 0] + -				(1.1895 - 1.0) * 256); -		  dev->dark[1] = dev->dark[2] = dev->dark[0]; -		  break; - -		case 1: -		  dev->dark[1] = -		    (uint16_t) (1.4013 * dark[i * 3 + 1] + -				(1.3147 - 1.0) * 256); -		  dev->dark[0] = dev->dark[2] = dev->dark[1]; -		  break; - -		case 2: -		  dev->dark[2] = -		    (uint16_t) (1.2931 * dark[i * 3 + 2] + -				(1.1558 - 1.0) * 256); -		  dev->dark[0] = dev->dark[1] = dev->dark[2]; -		  break; -		} -	    } -	} -    }				/* for (i = 0; i < 4; i++) */ - -  free(all_data); -  DBG (DBG_info, -       "genesys_coarse_calibration: final: sign: %d/%d/%d, gain: %d/%d/%d, offset: %d/%d/%d\n", -       dev->frontend.sign[0], dev->frontend.sign[1], dev->frontend.sign[2], -       dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2], -       dev->frontend.offset[0], dev->frontend.offset[1], -       dev->frontend.offset[2]); -  DBGCOMPLETED; - -  return status; -} - -/* Averages image data. -   average_data and calibration_data are little endian 16 bit words. - */ -#ifndef UNIT_TESTING -static -#endif -void -genesys_average_data (uint8_t * average_data, -		      uint8_t * calibration_data, -                      uint32_t lines, -		      uint32_t pixel_components_per_line) -{ -  uint32_t x, y; -  uint32_t sum; - -  for (x = 0; x < pixel_components_per_line; x++) -    { -      sum = 0; -      for (y = 0; y < lines; y++) -	{ -	  sum += calibration_data[(x + y * pixel_components_per_line) * 2]; -	  sum += -	    calibration_data[(x + y * pixel_components_per_line) * 2 + -			     1] * 256; -	} -      sum /= lines; -      *average_data++ = sum & 255; -      *average_data++ = sum / 256; -    } -} - -/** - * scans a white area with motor and lamp off to get the per CCD pixel offset - * that will be used to compute shading coefficient - * @param dev scanner's device - * @return SANE_STATUS_GOOD if OK, else an error - */ -static SANE_Status -genesys_dark_shading_calibration (Genesys_Device * dev) -{ -  SANE_Status status; -  size_t size; -  uint32_t pixels_per_line; -  uint8_t channels; -  uint8_t *calibration_data; -  SANE_Bool motor; - -  DBGSTART; - -  /* end pixel - start pixel */ -  pixels_per_line = dev->calib_pixels; -  channels = dev->calib_channels; - -  FREE_IFNOT_NULL (dev->dark_average_data); - -  dev->average_size = channels * 2 * pixels_per_line; - -  dev->dark_average_data = malloc (dev->average_size); -  if (!dev->dark_average_data) -    { -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: failed to allocate average memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  /* size is size in bytes for scanarea: bytes_per_line * lines */ -  size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - -  calibration_data = malloc (size); -  if (!calibration_data) -    { -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: failed to allocate calibration data memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  motor=SANE_TRUE; -  if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) -    { -      motor=SANE_FALSE; -    } - -  /* turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners -   * because they have a calibration sheet with a sufficient black strip                */ -  if (dev->model->is_sheetfed == SANE_FALSE) -    { -      dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_FALSE); -      dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); -    } -  else -    { -      dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); -      dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); -    } - -  status = -    dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, -					      dev->model-> -					      cmd_set->bulk_full_size ()); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: failed to bulk write registers: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  usleep (200 * 1000);		/* wait 200 ms: lamp needs some time to get dark */ - -  status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: Failed to begin scan: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: failed to read data: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_dark_shading_calibration: failed to end scan: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  genesys_average_data (dev->dark_average_data, calibration_data, -			dev->calib_lines, -			pixels_per_line * channels); - -  if (DBG_LEVEL >= DBG_data) -    { -      sanei_genesys_write_pnm_file ("black_shading.pnm", calibration_data, 16, -				    channels, pixels_per_line, -				    dev->calib_lines); -      sanei_genesys_write_pnm_file ("black_average.pnm", -				    dev->dark_average_data, 16, channels, -				    pixels_per_line, 1); -    } - -  free (calibration_data); - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -/* - * this function builds dummy dark calibration data so that we can - * compute shading coefficient in a clean way - *  todo: current values are hardcoded, we have to find if they - * can be computed from previous calibration data (when doing offset - * calibration ?) - */ -static SANE_Status -genesys_dummy_dark_shading (Genesys_Device * dev) -{ -  uint32_t pixels_per_line; -  uint8_t channels; -  uint32_t x, skip, xend; -  int dummy1, dummy2, dummy3;	/* dummy black average per channel */ - -  DBGSTART; - -  pixels_per_line = dev->calib_pixels; -  channels = dev->calib_channels; - -  FREE_IFNOT_NULL (dev->dark_average_data); - -  dev->average_size = channels * 2 * pixels_per_line; -  dev->dark_average_data = malloc (dev->average_size); -  if (!dev->dark_average_data) -    { -      DBG (DBG_error, -	   "genesys_dummy_dark_shading: failed to allocate average memory\n"); -      return SANE_STATUS_NO_MEM; -    } -  memset (dev->dark_average_data, 0x00, channels * 2 * pixels_per_line); - -  /* we average values on 'the left' where CCD pixels are under casing and -     give darkest values. We then use these as dummy dark calibration */ -  if (dev->settings.xres <= dev->sensor.optical_res / 2) -    { -      skip = 4; -      xend = 36; -    } -  else -    { -      skip = 4; -      xend = 68; -    } -  if (dev->model->ccd_type==CCD_G4050 -   || dev->model->ccd_type==CCD_CS4400F -   || dev->model->ccd_type==CCD_CS8400F -   || dev->model->ccd_type==CCD_KVSS080) -    { -      skip = 2; -      xend = dev->sensor.black_pixels; -    } - -  /* average each channels on half left margin */ -  dummy1 = 0; -  dummy2 = 0; -  dummy3 = 0; - -  for (x = skip + 1; x <= xend; x++) -    { -      dummy1 += -	dev->white_average_data[channels * 2 * x] + -	256 * dev->white_average_data[channels * 2 * x + 1]; -      if (channels > 1) -	{ -	  dummy2 += -	    (dev->white_average_data[channels * 2 * x + 2] + -	     256 * dev->white_average_data[channels * 2 * x + 3]); -	  dummy3 += -	    (dev->white_average_data[channels * 2 * x + 4] + -	     256 * dev->white_average_data[channels * 2 * x + 5]); -	} -    } - -  dummy1 /= (xend - skip); -  if (channels > 1) -    { -      dummy2 /= (xend - skip); -      dummy3 /= (xend - skip); -    } -  DBG (DBG_proc, -       "genesys_dummy_dark_shading: dummy1=%d, dummy2=%d, dummy3=%d \n", -       dummy1, dummy2, dummy3); - -  /* fill dark_average */ -  for (x = 0; x < pixels_per_line; x++) -    { -      dev->dark_average_data[channels * 2 * x] = dummy1 & 0xff; -      dev->dark_average_data[channels * 2 * x + 1] = dummy1 >> 8; -      if (channels > 1) -	{ -	  dev->dark_average_data[channels * 2 * x + 2] = dummy2 & 0xff; -	  dev->dark_average_data[channels * 2 * x + 3] = dummy2 >> 8; -	  dev->dark_average_data[channels * 2 * x + 4] = dummy3 & 0xff; -	  dev->dark_average_data[channels * 2 * x + 5] = dummy3 >> 8; -	} -    } - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - - -static SANE_Status -genesys_white_shading_calibration (Genesys_Device * dev) -{ -  SANE_Status status; -  size_t size; -  uint32_t pixels_per_line; -  uint8_t *calibration_data; -  uint8_t channels; -  SANE_Bool motor; - -  DBG (DBG_proc, "genesys_white_shading_calibration (lines = %d)\n", -       (unsigned int)dev->calib_lines); - -  pixels_per_line = dev->calib_pixels; -  channels = dev->calib_channels; - -  if (dev->white_average_data) -    free (dev->white_average_data); - -  dev->white_average_data = malloc (channels * 2 * pixels_per_line); -  if (!dev->white_average_data) -    { -      DBG (DBG_error, -	   "genesys_white_shading_calibration: failed to allocate average memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - -  calibration_data = malloc (size); -  if (!calibration_data) -    { -      DBG (DBG_error, -	   "genesys_white_shading_calibration: failed to allocate calibration memory\n"); -      return SANE_STATUS_NO_MEM; -    } - -  motor=SANE_TRUE; -  if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) -    { -      motor=SANE_FALSE; -    } - -  /* turn on motor and lamp power */ -  dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); -  dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - -  /* if needed, go back before doin next scan, by using rewind, registers and -   * slopes table are kept intact from previous scan */ -  if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK && dev->model->cmd_set->rewind) -    { -      status = dev->model->cmd_set->rewind (dev); -    } - -  status = -    dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, -					      dev->model-> -					      cmd_set->bulk_full_size ()); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_white_shading_calibration: failed to bulk write registers: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) -    usleep (500 * 1000);	/* wait 500ms to make sure lamp is bright again */ - -  status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_white_shading_calibration: Failed to begin scan: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_white_shading_calibration: failed to read data: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, -	   "genesys_white_shading_calibration: failed to end scan: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("white_shading.pnm", calibration_data, 16, -				  channels, pixels_per_line, -				  dev->calib_lines); - -  genesys_average_data (dev->white_average_data, calibration_data, -			dev->calib_lines, -			pixels_per_line * channels); - -  if (DBG_LEVEL >= DBG_data) -    sanei_genesys_write_pnm_file ("white_average.pnm", -				  dev->white_average_data, 16, channels, -				  pixels_per_line, 1); - -  free (calibration_data); - -  /* in case we haven't done dark calibration, build dummy data from white_average */ -  if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) -    { -      status = genesys_dummy_dark_shading (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_white_shading_calibration: failed to do dummy dark shading calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) -    { -	  status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); -    } - -  DBGCOMPLETED; - -  return status; -} - -/* This calibration uses a scan over the calibration target, comprising a - * black and a white strip. (So the motor must be on.) - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -genesys_dark_white_shading_calibration (Genesys_Device * dev) -{ -  SANE_Status status; -  size_t size; -  uint32_t pixels_per_line; -  uint8_t *calibration_data, *average_white, *average_dark; -  uint8_t channels; -  unsigned int x; -  int y; -  uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, -    dif; -  SANE_Bool motor; - - -  DBG (DBG_proc, "%s: (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); - -  pixels_per_line = dev->calib_pixels; -  channels = dev->calib_channels; - -  if (dev->white_average_data) -    free (dev->white_average_data); - -  dev->average_size = channels * 2 * pixels_per_line; - -  dev->white_average_data = malloc (dev->average_size); -  if (!dev->white_average_data) -    { -      DBG (DBG_error, "%s: failed to allocate white average memory\n", __func__); -      return SANE_STATUS_NO_MEM; -    } - -  if (dev->dark_average_data) -    free (dev->dark_average_data); - -  dev->dark_average_data = malloc (channels * 2 * pixels_per_line); -  if (!dev->dark_average_data) -    { -      DBG (DBG_error, "%s: failed to allocate dark average memory\n", __func__); -      return SANE_STATUS_NO_MEM; -    } - -  size = channels * 2 * pixels_per_line * dev->calib_lines; - -  calibration_data = malloc (size); -  if (!calibration_data) -    { -      DBG (DBG_error, "%s: failed to allocate calibration memory\n", __func__); -      return SANE_STATUS_NO_MEM; -    } - -  motor=SANE_TRUE; -  if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) -    { -      motor=SANE_FALSE; -    } - -  /* turn on motor and lamp power */ -  dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); -  dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - -  status = -    dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, -					      dev->model-> -					      cmd_set->bulk_full_size ()); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, -           sane_strstatus (status)); -      return status; -    } - -  status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); - -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, "%s: failed to begin scan: %s\n", __func__, -	   sane_strstatus (status)); -      return status; -    } - -  status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, "%s: failed to read data: %s\n", __func__, -	   sane_strstatus (status)); -      return status; -    } - -  status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      free (calibration_data); -      DBG (DBG_error, "%s: Failed to end scan: %s\n", __func__, -	   sane_strstatus (status)); -      return status; -    } - -  if (DBG_LEVEL >= DBG_data) -    { -      if (dev->model->is_cis) -        { -          sanei_genesys_write_pnm_file ("black_white_shading.pnm", calibration_data, -                                        16, 1, pixels_per_line*channels, -                                        dev->calib_lines); -        } -      else -        { -          sanei_genesys_write_pnm_file ("black_white_shading.pnm", calibration_data, -                                        16, channels, pixels_per_line, -                                        dev->calib_lines); -        } -    } - - -  average_white = dev->white_average_data; -  average_dark = dev->dark_average_data; - -  for (x = 0; x < pixels_per_line * channels; x++) -    { -      dark = 0xffff; -      white = 0; - -      for (y = 0; y < (int)dev->calib_lines; y++) -	{ -	  col = calibration_data[(x + y * pixels_per_line * channels) * 2]; -	  col |= -	    calibration_data[(x + y * pixels_per_line * channels) * 2 + -			     1] << 8; - -	  if (col > white) -	    white = col; -	  if (col < dark) -	    dark = col; -	} - -      dif = white - dark; - -      dark = dark + dif / 8; -      white = white - dif / 8; - -      dark_count = 0; -      dark_sum = 0; - -      white_count = 0; -      white_sum = 0; - -      for (y = 0; y < (int)dev->calib_lines; y++) -	{ -	  col = calibration_data[(x + y * pixels_per_line * channels) * 2]; -	  col |= -	    calibration_data[(x + y * pixels_per_line * channels) * 2 + -			     1] << 8; - -	  if (col >= white) -	    { -	      white_sum += col; -	      white_count++; -	    } -	  if (col <= dark) -	    { -	      dark_sum += col; -	      dark_count++; -	    } - -	} - -      dark_sum /= dark_count; -      white_sum /= white_count; - -      *average_dark++ = dark_sum & 255; -      *average_dark++ = dark_sum >> 8; - -      *average_white++ = white_sum & 255; -      *average_white++ = white_sum >> 8; -    } - -  if (DBG_LEVEL >= DBG_data) -    { -      sanei_genesys_write_pnm_file ("white_average.pnm", -				    dev->white_average_data, 16, channels, -				    pixels_per_line, 1); -      sanei_genesys_write_pnm_file ("dark_average.pnm", -				    dev->dark_average_data, 16, channels, -				    pixels_per_line, 1); -    } - -  free (calibration_data); - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -/* computes one coefficient given bright-dark value - * @param coeff factor giving 1.00 gain - * @param target desired target code - * @param value brght-dark value - * */ -static unsigned int -compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value) -{ -  int result; - -  if (value > 0) -    { -      result = (coeff * target) / value; -      if (result >= 65535) -	{ -	  result = 65535; -	} -    } -  else -    { -      result = coeff; -    } -  return result; -} - -/** @brief compute shading coefficients for LiDE scanners - * The dark/white shading is actually performed _after_ reducing - * resolution via averaging. only dark/white shading data for what would be - * first pixel at full resolution is used. - * - * scanner raw input to output value calculation: - *   o=(i-off)*(gain/coeff) - * - * from datasheet: - *   off=dark_average - *   gain=coeff*bright_target/(bright_average-dark_average) - * works for dark_target==0 - * - * what we want is these: - *   bright_target=(bright_average-off)*(gain/coeff) - *   dark_target=(dark_average-off)*(gain/coeff) - * leading to - *  off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) - *  gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - * - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param words_per_color memory words per color channel - * @param channels number of color channels (actually 1 or 3) - * @param o shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit) - * @param target_bright value of the white target code - * @param target_dark value of the black target code -*/ -#ifndef UNIT_TESTING -static -#endif -void -compute_averaged_planar (Genesys_Device * dev, -			 uint8_t * shading_data, -			 unsigned int pixels_per_line, -			 unsigned int words_per_color, -			 unsigned int channels, -			 unsigned int o, -			 unsigned int coeff, -			 unsigned int target_bright, -			 unsigned int target_dark) -{ -  unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; -  unsigned int fill,factor; - -  DBG (DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); - -  /* initialize result */ -  memset (shading_data, 0xff, words_per_color * 3 * 2); - -  /* -     strangely i can write 0x20000 bytes beginning at 0x00000 without overwriting -     slope tables - which begin at address 0x10000(for 1200dpi hw mode): -     memory is organized in words(2 bytes) instead of single bytes. explains -     quite some things -   */ -/* -  another one: the dark/white shading is actually performed _after_ reducing -  resolution via averaging. only dark/white shading data for what would be -  first pixel at full resolution is used. - */ -/* -  scanner raw input to output value calculation: -    o=(i-off)*(gain/coeff) - -  from datasheet: -    off=dark_average -    gain=coeff*bright_target/(bright_average-dark_average) -  works for dark_target==0 - -  what we want is these: -    bright_target=(bright_average-off)*(gain/coeff) -    dark_target=(dark_average-off)*(gain/coeff) -  leading to -    off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) -    gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - */ -  res = dev->settings.xres; - -  /* duplicate half-ccd logic */ -  if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) && -      dev->settings.xres <= dev->sensor.optical_res / 2) -    res *= 2; - -  /* this should be evenly dividable */ -  basepixels = dev->sensor.optical_res / res; - -  /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ -  if (basepixels < 1) -    avgpixels = 1; -  else if (basepixels < 6) -    avgpixels = basepixels; -  else if (basepixels < 8) -    avgpixels = 6; -  else if (basepixels < 10) -    avgpixels = 8; -  else if (basepixels < 12) -    avgpixels = 10; -  else if (basepixels < 15) -    avgpixels = 12; -  else -    avgpixels = 15; - -  /* LiDE80 packs shading data */ -  if(dev->model->ccd_type != CIS_CANONLIDE80) -    { -      factor=1; -      fill=avgpixels; -    } -  else -    { -      factor=avgpixels; -      fill=1; -    } - -  DBG (DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); -  DBG (DBG_info, "%s: packing factor is %d\n", __func__, factor); -  DBG (DBG_info, "%s: fill length is %d\n", __func__, fill); - -  for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) -    { -      if ((x + o) * 2 * 2 + 3 > words_per_color * 2) -	break; - -      for (j = 0; j < channels; j++) -	{ - -	  dk = 0; -	  br = 0; -	  for (i = 0; i < avgpixels; i++) -	    { -	      /* dark data */ -	      dk += -		(dev->dark_average_data[(x + i + -					 pixels_per_line * j) * -					2] | -		 (dev->dark_average_data -		  [(x + i + pixels_per_line * j) * 2 + 1] << 8)); - -	      /* white data */ -	      br += -		(dev->white_average_data[(x + i + -					  pixels_per_line * j) * -					 2] | -		 (dev->white_average_data -		  [(x + i + pixels_per_line * j) * 2 + 1] << 8)); -	    } - -	  br /= avgpixels; -	  dk /= avgpixels; - -	  if (br * target_dark > dk * target_bright) -	    val = 0; -	  else if (dk * target_bright - br * target_dark > -		   65535 * (target_bright - target_dark)) -	    val = 65535; -	  else -            { -	      val = (dk * target_bright - br * target_dark) / (target_bright - target_dark); -            } - -          /*fill all pixels, even if only the last one is relevant*/ -	  for (i = 0; i < fill; i++) -	    { -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff; -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8; -	    } - -	  val = br - dk; - -	  if (65535 * val > (target_bright - target_dark) * coeff) -            { -	      val = (coeff * (target_bright - target_dark)) / val; -            } -	  else -            { -	      val = 65535; -            } - -          /*fill all pixels, even if only the last one is relevant*/ -	  for (i = 0; i < fill; i++) -	    { -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff; -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8; -	    } -	} - -      /* fill remaining channels */ -      for (j = channels; j < 3; j++) -	{ -	  for (i = 0; i < fill; i++) -	    { -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j    ] = shading_data[(x/factor + o + i) * 2 * 2    ]; -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = shading_data[(x/factor + o + i) * 2 * 2 + 1]; -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = shading_data[(x/factor + o + i) * 2 * 2 + 2]; -	      shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = shading_data[(x/factor + o + i) * 2 * 2 + 3]; -	    } -	} -    } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. For now we assume deletion scanning type - * and that there is always 3 channels. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param channels number of color channels (actually 1 or 3) - * @param cmat color transposition matrix - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target value of the target code - */ -#ifndef UNIT_TESTING -static -#endif -void -compute_coefficients (Genesys_Device * dev, -		      uint8_t * shading_data, -		      unsigned int pixels_per_line, -		      unsigned int channels, -		      unsigned int cmat[3], -		      int offset, -		      unsigned int coeff, -		      unsigned int target) -{ -  uint8_t *ptr;			/* contain 16bit words in little endian */ -  unsigned int x, c; -  unsigned int val, br, dk; -  unsigned int start, end; - -  DBG (DBG_io, -       "compute_coefficients: pixels_per_line=%d,  coeff=0x%04x\n", pixels_per_line, coeff); - -  /* compute start & end values depending of the offset */ -  if (offset < 0) -   { -      start = -1 * offset; -      end = pixels_per_line; -   } -  else -   { -     start = 0; -     end = pixels_per_line - offset; -   } - -  for (c = 0; c < channels; c++) -    { -      for (x = start; x < end; x++) -	{ -	  /* TODO if channels=1 , use filter to know the base addr */ -	  ptr = shading_data + 4 * ((x + offset) * channels + cmat[c]); - -	  /* dark data */ -	  dk = dev->dark_average_data[x * 2 * channels + c * 2]; -	  dk += 256 * dev->dark_average_data[x * 2 * channels + c * 2 + 1]; - -	  /* white data */ -	  br = dev->white_average_data[x * 2 * channels + c * 2]; -	  br += 256 * dev->white_average_data[x * 2 * channels + c * 2 + 1]; - -	  /* compute coeff */ -	  val=compute_coefficient(coeff,target,br-dk); - -	  /* assign it */ -	  ptr[0] = dk & 255; -	  ptr[1] = dk / 256; -	  ptr[2] = val & 0xff; -	  ptr[3] = val / 256; - -	} -    } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. Data is in planar form, ie grouped by - * lines of the same color component. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param factor averaging factor when the calibration scan is done at a higher resolution - * than the final scan - * @param pixels_per_line number of pixels per line - * @param words_per_color total number of shading data words for one color element - * @param channels number of color channels (actually 1 or 3) - * @param cmat transcoding matrix for color channel order - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target white target value - */ -#ifndef UNIT_TESTING -static -#endif -void -compute_planar_coefficients (Genesys_Device * dev, -			     uint8_t * shading_data, -			     unsigned int factor, -			     unsigned int pixels_per_line, -			     unsigned int words_per_color, -			     unsigned int channels, -			     unsigned int cmat[3], -			     unsigned int offset, -			     unsigned int coeff, -			     unsigned int target) -{ -  uint8_t *ptr;			/* contains 16bit words in little endian */ -  uint32_t x, c, i; -  uint32_t val, dk, br; - -  DBG (DBG_io, -       "compute_planar_coefficients: factor=%d, pixels_per_line=%d, words=0x%X, coeff=0x%04x\n", factor, -       pixels_per_line, words_per_color, coeff); -  for (c = 0; c < channels; c++) -    { -      /* shading data is larger than pixels_per_line so offset can be neglected */ -      for (x = 0; x < pixels_per_line; x+=factor) -	{ -	  /* x2 because of 16 bit values, and x2 since one coeff for dark -	   * and another for white */ -	  ptr = shading_data + words_per_color * cmat[c] * 2 + (x + offset) * 4; - -	  dk = 0; -	  br = 0; - -	  /* average case */ -	  for(i=0;i<factor;i++) -	  { -	  dk += -	    256 * dev->dark_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; -	  dk += dev->dark_average_data[((x+i) + pixels_per_line * c) * 2]; -	  br += -	    256 * dev->white_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; -	  br += dev->white_average_data[((x+i) + pixels_per_line * c) * 2]; -	  } -	  dk /= factor; -	  br /= factor; - -	  val = compute_coefficient (coeff, target, br - dk); - -	  /* we duplicate the information to have calibration data at optical resolution */ -	  for (i = 0; i < factor; i++) -	    { -	      ptr[0 + 4 * i] = dk & 255; -	      ptr[1 + 4 * i] = dk / 256; -	      ptr[2 + 4 * i] = val & 0xff; -	      ptr[3 + 4 * i] = val / 256; -	    } -	} -    } -  /* in case of gray level scan, we duplicate shading information on all -   * three color channels */ -  if(channels==1) -  { -	  memcpy(shading_data+cmat[1]*2*words_per_color, -	         shading_data+cmat[0]*2*words_per_color, -		 words_per_color*2); -	  memcpy(shading_data+cmat[2]*2*words_per_color, -	         shading_data+cmat[0]*2*words_per_color, -		 words_per_color*2); -  } -} - -#ifndef UNIT_TESTING -static -#endif -void -compute_shifted_coefficients (Genesys_Device * dev, -			      uint8_t * shading_data, -			      unsigned int pixels_per_line, -			      unsigned int channels, -			      unsigned int cmat[3], -			      int offset, -			      unsigned int coeff, -			      unsigned int target_dark, -			      unsigned int target_bright, -			      unsigned int patch_size)		/* contigous extent */ -{ -  unsigned int x, avgpixels, basepixels, i, j, val1, val2; -  unsigned int br_tmp [3], dk_tmp [3]; -  uint8_t *ptr = shading_data + offset * 3 * 4;                 /* contain 16bit words in little endian */ -  unsigned int patch_cnt = offset * 3;                          /* at start, offset of first patch */ - -  x = dev->settings.xres; -  if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) && -      (dev->settings.xres <= dev->sensor.optical_res / 2)) -    x *= 2;							/* scanner is using half-ccd mode */ -  basepixels = dev->sensor.optical_res / x;			/*this should be evenly dividable */ - -      /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ -      if (basepixels < 1) -        avgpixels = 1; -      else if (basepixels < 6) -        avgpixels = basepixels; -      else if (basepixels < 8) -        avgpixels = 6; -      else if (basepixels < 10) -        avgpixels = 8; -      else if (basepixels < 12) -        avgpixels = 10; -      else if (basepixels < 15) -        avgpixels = 12; -      else -        avgpixels = 15; -  DBG (DBG_info, "compute_shifted_coefficients: pixels_per_line=%d,  coeff=0x%04x,  averaging over %d pixels\n", pixels_per_line, coeff, avgpixels); - -  for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { -    memset (&br_tmp, 0, sizeof(br_tmp)); -    memset (&dk_tmp, 0, sizeof(dk_tmp)); - -    for (i = 0; i < avgpixels; i++) { -      for (j = 0; j < channels; j++) { -        br_tmp[j]  += (dev->white_average_data[((x + i) * channels + j) * 2] | -                      (dev->white_average_data[((x + i) * channels + j) * 2 + 1] << 8)); -        dk_tmp[i] += (dev->dark_average_data[((x + i) * channels + j) * 2] | -                     (dev->dark_average_data[((x + i) * channels + j) * 2 + 1] << 8)); -      } -    } -    for (j = 0; j < channels; j++) { -      br_tmp[j] /= avgpixels; -      dk_tmp[j] /= avgpixels; - -      if (br_tmp[j] * target_dark > dk_tmp[j] * target_bright) -        val1 = 0; -      else if (dk_tmp[j] * target_bright - br_tmp[j] * target_dark > 65535 * (target_bright - target_dark)) -        val1 = 65535; -      else -        val1 = (dk_tmp[j] * target_bright - br_tmp[j] * target_dark) / (target_bright - target_dark); - -      val2 = br_tmp[j] - dk_tmp[j]; -      if (65535 * val2 > (target_bright - target_dark) * coeff) -        val2 = (coeff * (target_bright - target_dark)) / val2; -      else -        val2 = 65535; - -      br_tmp[j] = val1; -      dk_tmp[j] = val2; -    } -    for (i = 0; i < avgpixels; i++) { -      for (j = 0; j < channels; j++) { -        * ptr++ = br_tmp[ cmat[j] ] & 0xff; -        * ptr++ = br_tmp[ cmat[j] ] >> 8; -        * ptr++ = dk_tmp[ cmat[j] ] & 0xff; -        * ptr++ = dk_tmp[ cmat[j] ] >> 8; -        patch_cnt++; -        if (patch_cnt == patch_size) { -          patch_cnt = 0; -          val1 = cmat[2]; -          cmat[2] = cmat[1]; -          cmat[1] = cmat[0]; -          cmat[0] = val1; -        } -      } -    } -  } -} - -GENESYS_STATIC SANE_Status -genesys_send_shading_coefficient (Genesys_Device * dev) -{ -  SANE_Status status; -  uint32_t pixels_per_line; -  uint8_t *shading_data;	/**> contains 16bit words in little endian */ -  uint8_t channels; -  int o; -  unsigned int length;		/**> number of shading calibration data words */ -  unsigned int factor; -  unsigned int cmat[3];		/**> matrix of color channels */ -  unsigned int coeff, target_code, words_per_color = 0; - -  DBGSTART; - -  pixels_per_line = dev->calib_pixels; -  channels = dev->calib_channels; - -  /* we always build data for three channels, even for gray -   * we make the shading data such that each color channel data line is contiguous -   * to the next one, which allow to write the 3 channels in 1 write -   * during genesys_send_shading_coefficient, some values are words, other bytes -   * hence the x2 factor */ -  switch (sanei_genesys_read_reg_from_set (dev->reg, 0x05) >> 6) -    { -      /* 600 dpi */ -    case 0: -      words_per_color = 0x2a00; -      break; -      /* 1200 dpi */ -    case 1: -      words_per_color = 0x5500; -      break; -      /* 2400 dpi */ -    case 2: -      words_per_color = 0xa800; -      break; -      /* 4800 dpi */ -    case 3: -      words_per_color = 0x15000; -      break; -    } - -  /* special case, memory is aligned on 0x5400, this has yet to be explained */ -  /* could be 0xa800 because sensor is truly 2400 dpi, then halved because -   * we only set 1200 dpi */ -  if(dev->model->ccd_type==CIS_CANONLIDE80) -    { -      words_per_color = 0x5400; -    } - -  length = words_per_color * 3 * 2; - -  /* allocate computed size */ -  shading_data = malloc (length); -  if (!shading_data) -    { -      DBG (DBG_error, "%s: failed to allocate memory\n", __func__); -      return SANE_STATUS_NO_MEM; -    } -  memset (shading_data, 0, length); - -  /* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000 -     or 0x4000 to give an integer -     Wn = white average for column n -     Dn = dark average for column n -   */ -  if (dev->model->cmd_set->get_gain4_bit (dev->calib_reg)) -    coeff = 0x4000; -  else -    coeff = 0x2000; - -  /* compute avg factor */ -  if(dev->settings.xres>dev->sensor.optical_res) -    { -      factor=1; -    } -  else -    { -      factor=dev->sensor.optical_res/dev->settings.xres; -    } - -  /* for GL646, shading data is planar if REG01_FASTMOD is set and -   * chunky if not. For now we rely on the fact that we know that -   * each sensor is used only in one mode. Currently only the CIS_XP200 -   * sets REG01_FASTMOD. -   */ - -  /* TODO setup a struct in genesys_devices that -   * will handle these settings instead of having this switch growing up */ -  cmat[0] = 0; -  cmat[1] = 1; -  cmat[2] = 2; -  switch (dev->model->ccd_type) -    { -    case CCD_XP300: -    case CCD_ROADWARRIOR: -    case CCD_DP665: -    case CCD_DP685: -    case CCD_DSMOBILE600: -      target_code = 0xdc00; -      o = 4; -      compute_planar_coefficients (dev, -				   shading_data, -				   factor, -				   pixels_per_line, -				   words_per_color, -				   channels, -				   cmat, -				   o, -				   coeff, -				   target_code); -      break; -    case CIS_XP200: -      target_code = 0xdc00; -      o = 2; -      cmat[0] = 2;		/* red is last    */ -      cmat[1] = 0;		/* green is first */ -      cmat[2] = 1;		/* blue is second */ -      compute_planar_coefficients (dev, -				   shading_data, -				   1, -				   pixels_per_line, -				   words_per_color, -				   channels, -				   cmat, -				   o, -				   coeff, -				   target_code); -      break; -    case CCD_HP2300: -      target_code = 0xdc00; -      o = 2; -      if(dev->settings.xres<=dev->sensor.optical_res/2) -       { -      	  o = o - dev->sensor.dummy_pixel / 2; -       } -      compute_coefficients (dev, -			    shading_data, -			    pixels_per_line, -			    3, -                            cmat, -                            o, -                            coeff, -                            target_code); -      break; -    case CCD_5345: -      target_code = 0xe000; -      o = 4; -      if(dev->settings.xres<=dev->sensor.optical_res/2) -       { -      	  o = o - dev->sensor.dummy_pixel; -       } -      compute_coefficients (dev, -			    shading_data, -			    pixels_per_line, -			    3, -                            cmat, -                            o, -                            coeff, -                            target_code); -      break; -    case CCD_HP3670: -    case CCD_HP2400: -      target_code = 0xe000; -      /* offset is cksel dependent, but we can't use this in common code */ -      if(dev->settings.xres<=300) -        { -          o = -10; /* OK for <=300 */ -        } -      else if(dev->settings.xres<=600) -        { -          o = -6;  /* ok at 600 */ -        } -      else -        { -          o = +2; -        } -      compute_coefficients (dev, -			    shading_data, -			    pixels_per_line, -			    3, -                            cmat, -                            o, -                            coeff, -                            target_code); -      break; -    case CCD_KVSS080: -    case CCD_PLUSTEK3800: -    case CCD_G4050: -    case CCD_CS4400F: -    case CCD_CS8400F: -      target_code = 0xe000; -      o = 0; -      compute_coefficients (dev, -			    shading_data, -			    pixels_per_line, -			    3, -                            cmat, -                            o, -                            coeff, -                            target_code); -      break; -    case CIS_CANONLIDE700: -    case CIS_CANONLIDE100: -    case CIS_CANONLIDE200: -    case CIS_CANONLIDE110: -    case CIS_CANONLIDE120: -    case CIS_CANONLIDE210: -    case CIS_CANONLIDE220: -        /* TODO store this in a data struct so we avoid -         * growing this switch */ -        if(dev->model->ccd_type!=CIS_CANONLIDE110 -        && dev->model->ccd_type!=CIS_CANONLIDE210 -        && dev->model->ccd_type!=CIS_CANONLIDE120 -        && dev->model->ccd_type!=CIS_CANONLIDE220) -          target_code=0xdc00; -        else -          target_code=0xf000; -        words_per_color=pixels_per_line*2; -        length = words_per_color * 3 * 2; -        free(shading_data); -        shading_data = malloc (length); -        if (!shading_data) -          { -            DBG (DBG_error, "%s: failed to allocate memory\n", __func__); -            return SANE_STATUS_NO_MEM; -          } -        memset (shading_data, 0, length); -        compute_planar_coefficients (dev, -                                     shading_data, -                                     1, -                                     pixels_per_line, -                                     words_per_color, -                                     channels, -                                     cmat, -                                     0, -                                     coeff, -                                     target_code); -      break; -    case CCD_CANONLIDE35: -      compute_averaged_planar (dev, -			       shading_data, -                               pixels_per_line, -                               words_per_color, -                               channels, -                               4, -                               coeff, -                               0xe000, -                               0x0a00); -      break; -    case CIS_CANONLIDE80: -      compute_averaged_planar (dev, -			       shading_data, -                               pixels_per_line, -                               words_per_color, -                               channels, -                               0, -                               coeff, -                               0xd000, -                               0x0800); -      break; -    case CCD_PLUSTEK_3600: -      compute_shifted_coefficients (dev, -			            shading_data, -			            pixels_per_line, -			            channels, -			            cmat, -			            12,         /* offset */ -			            coeff, - 			            0x0001,      /* target_dark */ -			            0xf900,      /* target_bright */ -			            256);        /* patch_size: contigous extent */ -      break; -    default: -      DBG (DBG_error, "%s: sensor %d not supported\n", __func__, dev->model->ccd_type); -      return SANE_STATUS_UNSUPPORTED; -      break; -    } - -  /* do the actual write of shading calibration data to the scanner */ -  status = genesys_send_offset_and_shading (dev, shading_data, length); -  free (shading_data); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, -	  sane_strstatus (status)); -    } - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - - -/** - * search calibration cache list for an entry matching required scan. - * If one is found, set device calibration with it - * @param dev scanner's device - * @return SANE_STATUS_UNSUPPORTED if no matching cache entry has been - * found, SANE_STATUS_GOOD if one has been found and used. - */ -static SANE_Status -genesys_restore_calibration (Genesys_Device * dev) -{ -  SANE_Status status; -  Genesys_Calibration_Cache *cache; - -  DBGSTART; - -  /* if no cache or no function to evaluate cache entry ther can be no match */ -  if (!dev->model->cmd_set->is_compatible_calibration -      || dev->calibration_cache == NULL) -    return SANE_STATUS_UNSUPPORTED; - -  /* we walk the link list of calibration cache in search for a -   * matching one */ -  for (cache = dev->calibration_cache; cache; cache = cache->next) -    { -      status = dev->model->cmd_set->is_compatible_calibration (dev, cache, SANE_FALSE); -      /* SANE_STATUS_GOOD, a matching cache has been found -       * so we use it to populate calibration data -       */ -      if (status == SANE_STATUS_GOOD) -	{ -	  memcpy (&dev->frontend, &cache->frontend, sizeof (dev->frontend)); -          /* we don't restore the gamma fields */ -	  memcpy (dev->sensor.regs_0x10_0x1d, cache->sensor.regs_0x10_0x1d, 6); -	  free (dev->dark_average_data); -	  free (dev->white_average_data); - -	  dev->average_size = cache->average_size; -	  dev->calib_pixels = cache->calib_pixels; -	  dev->calib_channels = cache->calib_channels; - -	  dev->dark_average_data = (uint8_t *) malloc (cache->average_size); -	  dev->white_average_data = (uint8_t *) malloc (cache->average_size); - -	  if (!dev->dark_average_data || !dev->white_average_data) -	    return SANE_STATUS_NO_MEM; - -	  memcpy (dev->dark_average_data, -		  cache->dark_average_data, dev->average_size); -	  memcpy (dev->white_average_data, -		  cache->white_average_data, dev->average_size); - - -        if(dev->model->cmd_set->send_shading_data==NULL) -          { -            status = genesys_send_shading_coefficient (dev); -            if (status != SANE_STATUS_GOOD) -              { -                DBG (DBG_error, -                     "genesys_restore_calibration: failed to send shading calibration coefficients: %s\n", -                     sane_strstatus (status)); -                return status; -              } -          } - -	  DBG (DBG_proc, "genesys_restore_calibration: restored\n"); -	  return SANE_STATUS_GOOD; -	} - -      /* here status is either SANE_STATUS_UNSUPPORTED which mean tested cache -       * entry doesn't match, or an fatal error */ -      if (status != SANE_STATUS_UNSUPPORTED) -	{ -	  DBG (DBG_error, -	       "genesys_restore_calibration: fail while checking compatibility: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } -  DBG (DBG_proc, "genesys_restore_calibration: completed(nothing found)\n"); -  return SANE_STATUS_UNSUPPORTED; -} - - -static SANE_Status -genesys_save_calibration (Genesys_Device * dev) -{ -  SANE_Status status = SANE_STATUS_UNSUPPORTED; -  Genesys_Calibration_Cache *cache = NULL; -#ifdef HAVE_SYS_TIME_H -  struct timeval time; -#endif - -  DBGSTART; - -  if (!dev->model->cmd_set->is_compatible_calibration) -    return SANE_STATUS_UNSUPPORTED; - -  if (dev->calibration_cache != NULL) -    { -      for (cache = dev->calibration_cache; cache; cache = cache->next) -	{ -	  status = dev->model->cmd_set->is_compatible_calibration (dev, cache, SANE_TRUE); -	  if (status == SANE_STATUS_UNSUPPORTED) -	    { -	      continue; -	    } -	  else if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_save_calibration: fail while checking compatibility: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	  break; -	} -    } - -  /* if we found on overridable cache, we reuse it */ -  if (cache) -    { -          free(cache->dark_average_data); -          free(cache->white_average_data); -    } -  else -    { -      /* create a new cache entry and insert it in the linked list */ -      cache = malloc (sizeof (Genesys_Calibration_Cache)); -      if (!cache) -	return SANE_STATUS_NO_MEM; - -      memset (cache, 0, sizeof (Genesys_Calibration_Cache)); - -      cache->next = dev->calibration_cache; -      dev->calibration_cache = cache; -    } - -  cache->average_size = dev->average_size; - -  cache->dark_average_data = (uint8_t *) malloc (cache->average_size); -  if (!cache->dark_average_data) -    return SANE_STATUS_NO_MEM; -  cache->white_average_data = (uint8_t *) malloc (cache->average_size); -  if (!cache->white_average_data) -    return SANE_STATUS_NO_MEM; - -  memcpy (&cache->used_setup, &dev->current_setup, sizeof (cache->used_setup)); -  memcpy (&cache->frontend, &dev->frontend, sizeof (cache->frontend)); -  memcpy (&cache->sensor, &dev->sensor, sizeof (cache->sensor)); - -  cache->calib_pixels = dev->calib_pixels; -  cache->calib_channels = dev->calib_channels; -  memcpy (cache->dark_average_data, dev->dark_average_data, cache->average_size); -  memcpy (cache->white_average_data, dev->white_average_data, cache->average_size); -#ifdef HAVE_SYS_TIME_H -  gettimeofday(&time,NULL); -  cache->last_calibration = time.tv_sec; -#endif - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a flatbed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -GENESYS_STATIC SANE_Status -genesys_flatbed_calibration (Genesys_Device * dev) -{ -  SANE_Status status; -  uint32_t pixels_per_line; -  int yres; - -  DBG (DBG_info, "genesys_flatbed_calibration\n"); - -  yres = dev->sensor.optical_res; -  if (dev->settings.yres <= dev->sensor.optical_res / 2) -    yres /= 2; - -  /* do offset calibration if needed */ -  if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) -    { -      status = dev->model->cmd_set->offset_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: offset calibration failed: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      /* since all the registers are set up correctly, just use them */ -      status = dev->model->cmd_set->coarse_gain_calibration (dev, yres); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: coarse gain calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -    } -  else -    /* since we have 2 gain calibration proc, skip second if first one was -       used. */ -    { -      status = dev->model->cmd_set->init_regs_for_coarse_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: failed to send calibration registers: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = genesys_coarse_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: failed to do coarse gain calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -    } - -  if (dev->model->is_cis) -    { -      /* the afe now sends valid data for doing led calibration */ -      status = dev->model->cmd_set->led_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: led calibration failed: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      /* calibrate afe again to match new exposure */ -      if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) -	{ -	  status = dev->model->cmd_set->offset_calibration (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_flatbed_calibration: offset calibration failed: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -	  /* since all the registers are set up correctly, just use them */ - -	  status = dev->model->cmd_set->coarse_gain_calibration (dev, yres); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_flatbed_calibration: coarse gain calibration: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} -      else -	/* since we have 2 gain calibration proc, skip second if first one was -	   used. */ -	{ -	  status = -	    dev->model->cmd_set->init_regs_for_coarse_calibration (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_flatbed_calibration: failed to send calibration registers: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -	  status = genesys_coarse_calibration (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_flatbed_calibration: failed to do static calibration: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} -    } - -  /* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */ -  if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR)) -    { -      pixels_per_line = (SANE_UNFIX (dev->model->x_size) * dev->settings.xres) / MM_PER_INCH; -    } -  else -    { -      pixels_per_line = dev->sensor.sensor_pixels; -    } - -  /* send default shading data */ -  status = sanei_genesys_init_shading_data (dev, pixels_per_line); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_flatbed_calibration: failed to init shading process: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* shading calibration */ -  status = dev->model->cmd_set->init_regs_for_shading (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, "genesys_flatbed_calibration: failed to send shading " -	   "registers: %s\n", sane_strstatus (status)); -      return status; -    } - -  if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) -    { -      status = genesys_dark_white_shading_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: failed to do dark+white shading calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } -  else -    { -      if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) -	{ -	  status = genesys_dark_shading_calibration (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_flatbed_calibration: failed to do dark shading calibration: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} - -      status = genesys_white_shading_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_flatbed_calibration: failed to do white shading calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  if(dev->model->cmd_set->send_shading_data==NULL) -    { -      status = genesys_send_shading_coefficient (dev); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, -               "genesys_flatbed_calibration: failed to send shading calibration coefficients: %s\n", -               sane_strstatus (status)); -          return status; -        } -    } - -  DBG (DBG_info, "genesys_flatbed_calibration: completed\n"); - -  return SANE_STATUS_GOOD; -} - -/** - * Does the calibration process for a sheetfed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * During calibration a predefined calibration sheet with specific black and white - * areas is used. - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -static SANE_Status -genesys_sheetfed_calibration (Genesys_Device * dev) -{ -  SANE_Status status = SANE_STATUS_GOOD; -  SANE_Bool forward = SANE_TRUE; -  int xres; - -  DBGSTART; -  if (dev->model->cmd_set->search_strip == NULL) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: no strip searching function available\n"); -      return SANE_STATUS_UNSUPPORTED; -    } - -  /* first step, load document */ -  status = dev->model->cmd_set->load_document (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: failed to load document: %s\n", -	   sane_strstatus (status)); -      return status; -    } - - -  DBG (DBG_info, "genesys_sheetfed_calibration\n"); - -  /* led, offset and gain calibration are influenced by scan -   * settings. So we set it to sensor resolution */ -  xres = dev->sensor.optical_res; -  dev->settings.xres = dev->sensor.optical_res; -  /* XP200 needs to calibrate a full and half sensor's resolution */ -  if (dev->model->ccd_type == CIS_XP200 -   && dev->settings.xres <= dev->sensor.optical_res / 2) -    dev->settings.xres /= 2; - -  /* the afe needs to sends valid data even before calibration */ - -  /* go to a white area */ -  status = dev->model->cmd_set->search_strip (dev, forward, SANE_FALSE); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: failed to find white strip: %s\n", -	   sane_strstatus (status)); -      dev->model->cmd_set->eject_document (dev); -      return status; -    } - -  if (dev->model->is_cis) -    { -      status = dev->model->cmd_set->led_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: led calibration failed: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  /* calibrate afe */ -  if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) -    { -      status = dev->model->cmd_set->offset_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: offset calibration failed: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      /* since all the registers are set up correctly, just use them */ - -      status = dev->model->cmd_set->coarse_gain_calibration (dev, xres); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: coarse gain calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } -  else -    /* since we have 2 gain calibration proc, skip second if first one was -       used. */ -    { -      status = -	dev->model->cmd_set->init_regs_for_coarse_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: failed to send calibration registers: %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = genesys_coarse_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: failed to do static calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  /* search for a full width black strip and then do a 16 bit scan to -   * gather black shading data */ -  if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) -    { -      /* seek black/white reverse/forward */ -      status = dev->model->cmd_set->search_strip (dev, forward, SANE_TRUE); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: failed to find black strip: %s\n", -	       sane_strstatus (status)); -	  dev->model->cmd_set->eject_document (dev); -	  return status; -	} - -      status = dev->model->cmd_set->init_regs_for_shading (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: failed to do set up registers for shading calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -      status = genesys_dark_shading_calibration (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  dev->model->cmd_set->eject_document (dev); -	  DBG (DBG_error, -	       "genesys_sheetfed_calibration: failed to do dark shading calibration: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -      forward = SANE_FALSE; -    } - - -  /* go to a white area */ -  status = dev->model->cmd_set->search_strip (dev, forward, SANE_FALSE); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: failed to find white strip: %s\n", -	   sane_strstatus (status)); -      dev->model->cmd_set->eject_document (dev); -      return status; -    } - -  status = dev->model->cmd_set->init_regs_for_shading (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: failed to do set up registers for shading calibration: %s\n", -	   sane_strstatus (status)); -      return status; -    } -  status = genesys_white_shading_calibration (dev); -  if (status != SANE_STATUS_GOOD) -    { -      dev->model->cmd_set->eject_document (dev); -      DBG (DBG_error, "%s: failed eject target: %s\n", __func__, -	   sane_strstatus (status)); -      return status; -    } - -  /* in case we haven't black shading data, build it from black pixels -   * of white calibration */ -  if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) -    { -      FREE_IFNOT_NULL (dev->dark_average_data); -      dev->dark_average_data = malloc (dev->average_size); -      memset (dev->dark_average_data, 0x0f, dev->average_size); -      /* XXX STEF XXX -       * with black point in white shading, build an average black -       * pixel and use it to fill the dark_average -       * dev->calib_pixels -       (dev->sensor.sensor_pixels * dev->settings.xres) / dev->sensor.optical_res, -       dev->calib_lines, -       */ -    } - -  /* send the shading coefficient when doing whole line shading -   * but not when using SHDAREA like GL124 */ -  if(dev->model->cmd_set->send_shading_data==NULL) -    { -      status = genesys_send_shading_coefficient (dev); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, -               "genesys_sheetfed_calibration: failed to send shading calibration coefficients: %s\n", -               sane_strstatus (status)); -          return status; -        } -    } - -  /* save the calibration data */ -  genesys_save_calibration (dev); - -  /* and finally eject calibration sheet */ -  status = dev->model->cmd_set->eject_document (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_sheetfed_calibration: failed to eject document: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* resotre settings */ -  dev->settings.xres = xres; -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a device - * @param dev device to calibrate - */ -static SANE_Status -genesys_scanner_calibration (Genesys_Device * dev) -{ -  if (dev->model->is_sheetfed == SANE_FALSE) -    { -      return genesys_flatbed_calibration (dev); -    } -  return genesys_sheetfed_calibration (dev); -} - -/* unused function kept in case it may be usefull in the futur */ -#if 0 -static SANE_Status -genesys_wait_not_moving (Genesys_Device * dev, int mseconds) -{ -  uint8_t value; -  SANE_Status status; - -  DBG (DBG_proc, -       "genesys_wait_not_moving: waiting %d mseconds for motor to stop\n", -       mseconds); -  while (mseconds > 0) -    { -      RIE (sanei_genesys_get_status (dev, &value)); - -      if (dev->model->cmd_set->test_motor_flag_bit (value)) -	{ -	  usleep (100 * 1000); -	  mseconds -= 100; -	  DBG (DBG_io, -	       "genesys_wait_not_moving: motor is moving, %d mseconds to go\n", -	       mseconds); -	} -      else -	{ -	  DBG (DBG_info, -	       "genesys_wait_not_moving: motor is not moving, exiting\n"); -	  return SANE_STATUS_GOOD; -	} - -    } -  DBG (DBG_error, -       "genesys_wait_not_moving: motor is still moving, timeout exceeded\n"); -  return SANE_STATUS_DEVICE_BUSY; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/*                  High level (exported) functions                         */ -/* ------------------------------------------------------------------------ */ - -/* - * wait lamp to be warm enough by scanning the same line until - * differences between two scans are below a threshold - */ -static SANE_Status -genesys_warmup_lamp (Genesys_Device * dev) -{ -  uint8_t *first_line, *second_line; -  int seconds = 0; -  int pixel; -  int channels, total_size; -  double first_average = 0; -  double second_average = 0; -  int difference = 255; -  int empty, lines = 3; -  SANE_Status status = SANE_STATUS_IO_ERROR; - -  DBGSTART; - -  /* check if the current chipset implements warmup */ -  if(dev->model->cmd_set->init_regs_for_warmup==NULL) -    { -      DBG (DBG_error, "%s: init_regs_for_warmup not implemented\n", __func__); -      return status; -    } - -  dev->model->cmd_set->init_regs_for_warmup (dev, dev->reg, &channels, &total_size); -  first_line = malloc (total_size); -  if (!first_line) -    return SANE_STATUS_NO_MEM; - -  second_line = malloc (total_size); -  if (!second_line) -    { -      free(first_line); -      DBGCOMPLETED; -      return SANE_STATUS_NO_MEM; -    } - -  do -    { -      DBG (DBG_info, "genesys_warmup_lamp: one more loop\n"); -      RIEF2 (dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_FALSE), first_line, second_line); -      do -	{ -	  sanei_genesys_test_buffer_empty (dev, &empty); -	} -      while (empty); - -      status = sanei_genesys_read_data_from_scanner (dev, first_line, total_size); -      if (status != SANE_STATUS_GOOD) -	{ -	  RIEF2 (sanei_genesys_read_data_from_scanner -	       (dev, first_line, total_size), first_line, second_line); -	} - -      RIEF2 (dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE), first_line, second_line); - -      sleep (1);		/* sleep 1 s */ -      seconds++; - -      RIEF2 (dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_FALSE), first_line, second_line); -      do -	{ -	  sanei_genesys_test_buffer_empty (dev, &empty); -          usleep (100 * 1000); -	} -      while (empty); -      RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); -      RIEF2 (dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE), first_line, second_line); - -      /* compute difference between the two scans */ -      for (pixel = 0; pixel < total_size; pixel++) -	{ -          /* 16 bit data */ -	  if (dev->model->cmd_set->get_bitset_bit (dev->reg)) -	    { -	      first_average += (first_line[pixel] + first_line[pixel + 1] * 256); -	      second_average += (second_line[pixel] + second_line[pixel + 1] * 256); -	      pixel++; -	    } -	  else -	    { -	      first_average += first_line[pixel]; -	      second_average += second_line[pixel]; -	    } -	} -      if (dev->model->cmd_set->get_bitset_bit (dev->reg)) -	{ -	  first_average /= pixel; -	  second_average /= pixel; -	  difference = fabs (first_average - second_average); -	  DBG (DBG_info, -	       "genesys_warmup_lamp: average = %.2f, diff = %.3f\n", -	       100 * ((second_average) / (256 * 256)), -	       100 * (difference / second_average)); - -	  if (second_average > (100 * 256) -	      && (difference / second_average) < 0.002) -	    break; -	} -      else -	{ -	  first_average /= pixel; -	  second_average /= pixel; -	  if (DBG_LEVEL >= DBG_data) -	    { -	      sanei_genesys_write_pnm_file ("warmup1.pnm", first_line, 8, -					    channels, -					    total_size / (lines * channels), -					    lines); -	      sanei_genesys_write_pnm_file ("warmup2.pnm", second_line, 8, -					    channels, -					    total_size / (lines * channels), -					    lines); -	    } -	  DBG (DBG_info, "genesys_warmup_lamp: average 1 = %.2f, average 2 = %.2f\n", first_average, second_average); -          /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */ -	  if (fabs (first_average - second_average) < 15 -	      && second_average > 55) -	    break; -	} - -      /* sleep another second before next loop */ -      sleep (1); -      seconds++; -    } -  while (seconds < WARMUP_TIME); - -  if (seconds >= WARMUP_TIME) -    { -      DBG (DBG_error, -	   "genesys_warmup_lamp: warmup timed out after %d seconds. Lamp defective?\n", -	   seconds); -      status = SANE_STATUS_IO_ERROR; -    } -  else -    { -      DBG (DBG_info, -	   "genesys_warmup_lamp: warmup succeeded after %d seconds\n", -	   seconds); -    } - -  free (first_line); -  free (second_line); - -  DBGCOMPLETED; - -  return status; -} - - -/* High-level start of scanning */ -static SANE_Status -genesys_start_scan (Genesys_Device * dev, SANE_Bool lamp_off) -{ -  SANE_Status status; -  unsigned int steps, expected; -  SANE_Bool empty; - -  DBGSTART; - -  /* since not all scanners are set ot wait for head to park -   * we check we are not still parking before starting a new scan */ -  if (dev->parking == SANE_TRUE) -    { -      status = sanei_genesys_wait_for_home (dev); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, -               "genesys_start_scan: failed to wait for head to park: %s\n", -               sane_strstatus (status)); -          return status; -        } -    } - -  /* disable power saving*/ -  status = dev->model->cmd_set->save_power (dev, SANE_FALSE); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to disable power saving mode: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip -   * it when scanning from XPA. */ -  if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP) -    && (dev->settings.scan_method == SCAN_METHOD_FLATBED)) -    { -      RIE (genesys_warmup_lamp (dev)); -    } - -  /* set top left x and y values by scanning the internals if flatbed scanners */ -  if (dev->model->is_sheetfed == SANE_FALSE) -    { -      /* do the geometry detection only once */ -      if ((dev->model->flags & GENESYS_FLAG_SEARCH_START) -	  && (dev->model->y_offset_calib == 0)) -	{ -	  status = dev->model->cmd_set->search_start_position (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_start_scan: failed to search start position: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -          dev->parking = SANE_FALSE; -	  status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_start_scan: failed to move scanhead to " -		   "home position: %s\n", sane_strstatus (status)); -	      return status; -	    } -	  dev->scanhead_position_in_steps = 0; -	} -      else -	{ -	  /* Go home */ -	  /* TODO: check we can drop this since we cannot have the -	     scanner's head wandering here */ -          dev->parking = SANE_FALSE; -	  status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_start_scan: failed to move scanhead to " -		   "home position: %s\n", sane_strstatus (status)); -	      return status; -	    } -	  dev->scanhead_position_in_steps = 0; -	} -    } - -  /* move to calibration area for transparency adapter */ -  if ((dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY) -      && dev->model->cmd_set->move_to_ta != NULL) -    { -      status=dev->model->cmd_set->move_to_ta(dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_start_scan: failed to move to start of transparency adapter: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  /* load document if needed (for sheetfed scanner for instance) */ -  if (dev->model->is_sheetfed == SANE_TRUE -      && dev->model->cmd_set->load_document != NULL) -    { -      status = dev->model->cmd_set->load_document (dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_start_scan: failed to load document: %s\n", -	       sane_strstatus (status)); -	  return status; -	} -    } - -  /* send gamma tables. They have been set to device or user value -   * when setting option value */ -  status = dev->model->cmd_set->send_gamma_table (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to init gamma table: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* try to use cached calibration first */ -  status = genesys_restore_calibration (dev); -  if (status == SANE_STATUS_UNSUPPORTED) -    { -       /* calibration : sheetfed scanners can't calibrate before each scan */ -       /* and also those who have the NO_CALIBRATION flag                  */ -       if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) -           &&dev->model->is_sheetfed == SANE_FALSE) -	{ -	  status = genesys_scanner_calibration (dev); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_start_scan: failed to do scanner calibration: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } - -	  genesys_save_calibration (dev); -	} -      else -	{ -          DBG (DBG_warn, "genesys_start_scan: no calibration done\n"); -	} -    } -  else if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to restore calibration: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* build look up table for dynamic lineart */ -  if(dev->settings.dynamic_lineart==SANE_TRUE) -    { -      status = sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, -                        dev->settings.threshold_curve, -                        dev->settings.threshold-127); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, "genesys_start_scan: failed to build lut\n"); -          return status; -        } -    } - -  status = dev->model->cmd_set->init_regs_for_scan (dev); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to do init registers for scan: %s\n", -	   sane_strstatus (status)); -      return status; -    } - -  /* no lamp during scan */ -  if(lamp_off == SANE_TRUE) -    { -      dev->model->cmd_set->set_lamp_power (dev, dev->reg, SANE_FALSE); -    } - -  /* GL124 is using SHDAREA, so we have to wait for scan to be set up before -   * sending shading data */ -  if(  (dev->model->cmd_set->send_shading_data!=NULL) -   && !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) -    { -      status = genesys_send_shading_coefficient (dev); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, -               "genesys_start_scan: failed to send shading calibration coefficients: %s\n", -               sane_strstatus (status)); -          return status; -        } -    } - -  /* now send registers for scan */ -  status = -    dev->model->cmd_set->bulk_write_register (dev, dev->reg, -					      dev->model-> -					      cmd_set->bulk_full_size ()); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to bulk write registers, status = %d\n", -	   status); -      return status; -    } - -  /* start effective scan */ -  status = dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_start_scan: failed to begin scan: %s\n", -	   sane_strstatus (status)); -      return SANE_STATUS_IO_ERROR; -    } - -  /*do we really need this? the valid data check should be sufficent -- pierre*/ -  /* waits for head to reach scanning position */ -  expected = sanei_genesys_read_reg_from_set (dev->reg, 0x3d) * 65536 -           + sanei_genesys_read_reg_from_set (dev->reg, 0x3e) * 256 -           + sanei_genesys_read_reg_from_set (dev->reg, 0x3f); -  do -    { -      /* wait 1/10th of second between each test to avoid -         overloading USB and CPU */ -      usleep (100 * 1000); -      status = sanei_genesys_read_feed_steps (dev, &steps); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, -               "genesys_start_scan: Failed to read feed steps: %s\n", -               sane_strstatus (status)); -          return status; -        } -    } -  while (steps < expected); - -  /* wait for buffers to be filled */ -  do -    { -      RIE (sanei_genesys_test_buffer_empty (dev, &empty)); -    } -  while (empty); - -  /* when doing one or two-table movement, let the motor settle to scanning speed */ -  /* and scanning start before reading data                                        */ -/* the valid data check already waits until the scanner delivers data. this here leads to unnecessary buffer full conditions in the scanner. -  if (dev->model->cmd_set->get_fast_feed_bit (dev->reg)) -    usleep (1000 * 1000); -  else -    usleep (500 * 1000); -*/ -  /* then we wait for at least one word of valid scan data - -     this is also done in sanei_genesys_read_data_from_scanner -- pierre */ -  if (dev->model->is_sheetfed == SANE_FALSE) -    { -      do -	{ -	  usleep (100 * 1000); -	  status = sanei_genesys_read_valid_words (dev, &steps); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_start_scan: failed to read valid words: %s\n", -		   sane_strstatus (status)); -	      return status; -	    } -	} -      while (steps < 1); -    } - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -/* this is _not_ a ringbuffer. -   if we need a block which does not fit at the end of our available data, -   we move the available data to the beginning. - */ - -SANE_Status -sanei_genesys_buffer_alloc (Genesys_Buffer * buf, size_t size) -{ -  buf->buffer = (SANE_Byte *) malloc (size); -  if (!buf->buffer) -    return SANE_STATUS_NO_MEM; -  buf->avail = 0; -  buf->pos = 0; -  buf->size = size; -  return SANE_STATUS_GOOD; -} - -SANE_Status -sanei_genesys_buffer_free (Genesys_Buffer * buf) -{ -  SANE_Byte *tmp = buf->buffer; -  buf->avail = 0; -  buf->size = 0; -  buf->pos = 0; -  buf->buffer = NULL; -  if (tmp) -    free (tmp); -  return SANE_STATUS_GOOD; -} - -SANE_Byte * -sanei_genesys_buffer_get_write_pos (Genesys_Buffer * buf, size_t size) -{ -  if (buf->avail + size > buf->size) -    return NULL; -  if (buf->pos + buf->avail + size > buf->size) -    { -      memmove (buf->buffer, buf->buffer + buf->pos, buf->avail); -      buf->pos = 0; -    } -  return buf->buffer + buf->pos + buf->avail; -} - -SANE_Byte * -sanei_genesys_buffer_get_read_pos (Genesys_Buffer * buf) -{ -  return buf->buffer + buf->pos; -} - -SANE_Status -sanei_genesys_buffer_produce (Genesys_Buffer * buf, size_t size) -{ -  if (size > buf->size - buf->avail) -    return SANE_STATUS_INVAL; -  buf->avail += size; -  return SANE_STATUS_GOOD; -} - -SANE_Status -sanei_genesys_buffer_consume (Genesys_Buffer * buf, size_t size) -{ -  if (size > buf->avail) -    return SANE_STATUS_INVAL; -  buf->avail -= size; -  buf->pos += size; -  return SANE_STATUS_GOOD; -} - - -#include "genesys_conv.c" - -static SANE_Status accurate_line_read(Genesys_Device * dev, -                                      SANE_Byte *buffer, -                                      size_t size) -{ -  SANE_Status status; -  status = dev->model->cmd_set->bulk_read_data (dev, 0x45, buffer, size); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "accurate_line_read: failed to read %lu bytes (%s)\n", -	   (u_long) size, sane_strstatus (status)); -      return SANE_STATUS_IO_ERROR; -    } - -  /* done reading */ -  dev->oe_buffer.avail = size; -  dev->oe_buffer.pos = 0; -  return status; -} - -/** @brief fill buffer while reducing vertical resolution - * This function fills a read buffer with scanned data from a sensor - * which puts odd and even pixels in 2 different data segment. So a complete - * must be read and bytes interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ -  size_t count; -  SANE_Status status; - -      /* fill buffer if needed */ -      if (dev->oe_buffer.avail == 0) -	{ -	  status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "%s: failed to read %lu bytes (%s)\n", __func__, -		   (u_long) dev->oe_buffer.size, sane_strstatus (status)); -	      return SANE_STATUS_IO_ERROR; -	    } -	} - -      /* copy size bytes of data, copying from a line when line count matches */ -      count = 0; -      while (count < size) -	{ -          /* line counter */ -          /* dev->line_interp holds the number of lines scanned for one line of data sent */ -          if(((dev->line_count/dev->current_setup.channels) % dev->line_interp)==0) -            { -	      /* copy pixel when line matches */ -	      work_buffer_dst[count] = dev->oe_buffer.buffer[dev->cur + dev->oe_buffer.pos]; -              count++; -            } - -          /* always update pointer so we skip uncopied data */ -          dev->cur++; - -	  /* go to next line if needed */ -	  if (dev->cur == dev->len) -	    { -	      dev->oe_buffer.pos += dev->bpl; -	      dev->cur = 0; -              dev->line_count++; -	    } - -	  /* read a new buffer if needed */ -	  if (dev->oe_buffer.pos >= dev->oe_buffer.avail) -	    { -              status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); -              if (status != SANE_STATUS_GOOD) -                { -                  DBG (DBG_error, -                       "%s: failed to read %lu bytes (%s)\n", __func__, -                       (u_long) dev->oe_buffer.size, sane_strstatus (status)); -                  return SANE_STATUS_IO_ERROR; -                } -	    } -	} - -    return SANE_STATUS_GOOD; -} - -/** @brief fill buffer for segmented sensors - * This function fills a read buffer with scanned data from a sensor segmented - * in several parts (multi-lines sensors). Data of the same valid area is read - * back to back and must be interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ -  size_t count; -  SANE_Status status; -  int depth,i,n,k; - -  depth = dev->settings.depth; -  if (dev->settings.scan_mode == SCAN_MODE_LINEART && dev->settings.dynamic_lineart==SANE_FALSE) -    depth = 1; - -      /* fill buffer if needed */ -      if (dev->oe_buffer.avail == 0) -	{ -	  status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "%s: failed to read %lu bytes (%s)\n", __func__, -		   (u_long) dev->oe_buffer.size, sane_strstatus (status)); -	      return SANE_STATUS_IO_ERROR; -	    } -	} - -      /* copy size bytes of data, copying from a subwindow of each line -       * when last line of buffer is exhausted, read another one */ -      count = 0; -      while (count < size) -	{ -          if(dev->settings.double_xres==SANE_TRUE) -            { -	      /* copy only even pixel */ -	      work_buffer_dst[count] = dev->oe_buffer.buffer[dev->cur + dev->oe_buffer.pos]; -              /* update counter and pointer */ -              count++; -              dev->cur++; -            } -          else -            { -                  if(depth==1) -                    { -                      while (dev->cur < dev->len && count < size) -                        { -                          for(n=0;n<dev->segnb;n++) -                            { -                                  work_buffer_dst[count+n] = 0; -                            } -                          /* interleaving is at bit level */ -                          for(i=0;i<8;i++) -                            { -                              k=count+(i*dev->segnb)/8; -                              for(n=0;n<dev->segnb;n++) -                                { -                                      work_buffer_dst[k] = work_buffer_dst[k] << 1; -                                      if((dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos])&(128>>i)) -                                        { -                                          work_buffer_dst[k] |= 1; -                                        } -                                } -                            } - -                          /* update counter and pointer */ -                          count += dev->segnb; -                          dev->cur++; -                        } -                    } -                  if(depth==8) -                    { -                      while (dev->cur < dev->len && count < size) -                        { -                          for(n=0;n<dev->segnb;n++) -                            { -                                  work_buffer_dst[count+n] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos]; -                            } -                          /* update counter and pointer */ -                          count += dev->segnb; -                          dev->cur++; -                        } -                    } -                  if(depth==16) -                    { -                      while (dev->cur < dev->len && count < size) -                        { -                          for(n=0;n<dev->segnb;n++) -                            { -                                  work_buffer_dst[count+n*2] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos]; -                                  work_buffer_dst[count+n*2+1] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos+1]; -                            } -                          /* update counter and pointer */ -                          count += dev->segnb*2; -                          dev->cur+=2; -                        } -                    } -            } - -	  /* go to next line if needed */ -	  if (dev->cur == dev->len) -	    { -	      dev->oe_buffer.pos += dev->bpl; -	      dev->cur = 0; -	    } - -	  /* read a new buffer if needed */ -	  if (dev->oe_buffer.pos >= dev->oe_buffer.avail) -	    { -              status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); -              if (status != SANE_STATUS_GOOD) -                { -                  DBG (DBG_error, -                       "%s: failed to read %lu bytes (%s)\n", __func__, -                       (u_long) dev->oe_buffer.size, sane_strstatus (status)); -                  return SANE_STATUS_IO_ERROR; -                } -	    } -	} - -    return SANE_STATUS_GOOD; -} - -/** - * - */ -static SANE_Status -genesys_fill_read_buffer (Genesys_Device * dev) -{ -  size_t size; -  size_t space; -  SANE_Status status; -  uint8_t *work_buffer_dst; - -  DBGSTART; - -  /* for sheetfed scanner, we must check is document is shorter than -   * the requested scan */ -  if (dev->model->is_sheetfed == SANE_TRUE) -    { -      status = dev->model->cmd_set->detect_document_end (dev); -      if (status != SANE_STATUS_GOOD) -	return status; -    } - -  space = dev->read_buffer.size - dev->read_buffer.avail; - -  work_buffer_dst = sanei_genesys_buffer_get_write_pos (&(dev->read_buffer), -							space); - -  size = space; - -  /* never read an odd number. exception: last read -     the chip internal counter does not count half words. */ -  size &= ~1; -  /* Some setups need the reads to be multiples of 256 bytes */ -  size &= ~0xff; - -  if (dev->read_bytes_left < size) -    { -      size = dev->read_bytes_left; -      /*round up to a multiple of 256 bytes */ -      size += (size & 0xff) ? 0x100 : 0x00; -      size &= ~0xff; -    } - -  /* early out if our remaining buffer capacity is too low */ -  if (size == 0) -    return SANE_STATUS_GOOD; - -  DBG (DBG_io, "genesys_fill_read_buffer: reading %lu bytes\n", -       (u_long) size); - -  /* size is already maxed to our needs. for most models bulk_read_data -     will read as much data as requested. */ - -  /* due to sensors and motors, not all data can be directly used. It -   * may have to be read from another intermediate buffer and then processed. -   * There are currently 3 intermediate stages: -   * - handling of odd/even sensors -   * - handling of line interpolation for motors that can't have low -   *   enough dpi -   * - handling of multi-segments sensors -   * -   * This is also the place where full duplex data will be handled. -   */ -  if (dev->line_interp>0) -    { -      /* line interpolation */ -      status = genesys_fill_line_interp_buffer (dev, work_buffer_dst, size); -    } -  else if (dev->segnb>1) -    { -      /* multi-segment sensors processing */ -      status = genesys_fill_segmented_buffer (dev, work_buffer_dst, size); -    } -  else /* regular case with no extra copy */ -    { -      status = dev->model->cmd_set->bulk_read_data (dev, 0x45, work_buffer_dst, size); -    } -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -           "genesys_fill_read_buffer: failed to read %lu bytes (%s)\n", -           (u_long) size, sane_strstatus (status)); -      return SANE_STATUS_IO_ERROR; -    } - -  if (size > dev->read_bytes_left) -    size = dev->read_bytes_left; - -  dev->read_bytes_left -= size; - -  RIE (sanei_genesys_buffer_produce (&(dev->read_buffer), size)); - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -/* this function does the effective data read in a manner that suits -   the scanner. It does data reordering and resizing if need. -   It also manages EOF and I/O errors, and line distance correction. -   */ -static SANE_Status -genesys_read_ordered_data (Genesys_Device * dev, SANE_Byte * destination, -			   size_t * len) -{ -  SANE_Status status; -  size_t bytes, extra; -  unsigned int channels, depth, src_pixels; -  unsigned int ccd_shift[12], shift_count; -  uint8_t *work_buffer_src; -  uint8_t *work_buffer_dst; -  unsigned int dst_lines; -  unsigned int step_1_mode; -  unsigned int needs_reorder; -  unsigned int needs_ccd; -  unsigned int needs_shrink; -  unsigned int needs_reverse; -  Genesys_Buffer *src_buffer; -  Genesys_Buffer *dst_buffer; - -  DBGSTART; -  if (dev->read_active != SANE_TRUE) -    { -      DBG (DBG_error, "genesys_read_ordered_data: read not active!\n"); -      *len = 0; -      return SANE_STATUS_INVAL; -    } - - -  DBG (DBG_info, "genesys_read_ordered_data: dumping current_setup:\n" -       "\tpixels: %d\n" -       "\tlines: %d\n" -       "\tdepth: %d\n" -       "\tchannels: %d\n" -       "\texposure_time: %d\n" -       "\txres: %g\n" -       "\tyres: %g\n" -       "\thalf_ccd: %s\n" -       "\tstagger: %d\n" -       "\tmax_shift: %d\n", -       dev->current_setup.pixels, -       dev->current_setup.lines, -       dev->current_setup.depth, -       dev->current_setup.channels, -       dev->current_setup.exposure_time, -       dev->current_setup.xres, -       dev->current_setup.yres, -       dev->current_setup.half_ccd ? "yes" : "no", -       dev->current_setup.stagger, dev->current_setup.max_shift); - -  /* prepare conversion */ -  /* current settings */ -  channels = dev->current_setup.channels; -  depth = dev->current_setup.depth; - -  src_pixels = dev->current_setup.pixels; - -  needs_reorder = 1; -  if (channels != 3 && depth != 16) -    needs_reorder = 0; -#ifndef WORDS_BIGENDIAN -  if (channels != 3 && depth == 16) -    needs_reorder = 0; -  if (channels == 3 && depth == 16 && !dev->model->is_cis && -      dev->model->line_mode_color_order == COLOR_ORDER_RGB) -    needs_reorder = 0; -#endif -  if (channels == 3 && depth == 8 && !dev->model->is_cis && -      dev->model->line_mode_color_order == COLOR_ORDER_RGB) -    needs_reorder = 0; - -  needs_ccd = dev->current_setup.max_shift > 0; -  needs_shrink = dev->settings.pixels != src_pixels; -  needs_reverse = depth == 1; - -  DBG (DBG_info, -       "genesys_read_ordered_data: using filters:%s%s%s%s\n", -       needs_reorder ? " reorder" : "", -       needs_ccd ? " ccd" : "", -       needs_shrink ? " shrink" : "", -       needs_reverse ? " reverse" : ""); - -  DBG (DBG_info, -       "genesys_read_ordered_data: frontend requested %lu bytes\n", -       (u_long) * len); - -  DBG (DBG_info, -       "genesys_read_ordered_data: bytes_to_read=%lu, total_bytes_read=%lu\n", -       (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); -  /* is there data left to scan */ -  if (dev->total_bytes_read >= dev->total_bytes_to_read) -    { -      DBG (DBG_proc, -	   "genesys_read_ordered_data: nothing more to scan: EOF\n"); -      *len = 0; - -      /* issue park command immediatly in case scanner can handle it -       * so we save time */ -      if (dev->model->is_sheetfed == SANE_FALSE -       && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) -       && dev->parking == SANE_FALSE) -        { -          dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); -          dev->parking = SANE_TRUE; -        } -      return SANE_STATUS_EOF; -    } - -  DBG (DBG_info, "genesys_read_ordered_data: %lu lines left by output\n", -       ((dev->total_bytes_to_read - dev->total_bytes_read) * 8UL) / -       (dev->settings.pixels * channels * depth)); -  DBG (DBG_info, "genesys_read_ordered_data: %lu lines left by input\n", -       ((dev->read_bytes_left + dev->read_buffer.avail) * 8UL) / -       (src_pixels * channels * depth)); - -  if (channels == 1) -    { -      ccd_shift[0] = 0; -      ccd_shift[1] = dev->current_setup.stagger; -      shift_count = 2; -    } -  else -    { -      ccd_shift[0] = -	((dev->ld_shift_r * dev->settings.yres) / -	 dev->motor.base_ydpi); -      ccd_shift[1] = -	((dev->ld_shift_g * dev->settings.yres) / -	 dev->motor.base_ydpi); -      ccd_shift[2] = -	((dev->ld_shift_b * dev->settings.yres) / -	 dev->motor.base_ydpi); - -      ccd_shift[3] = ccd_shift[0] + dev->current_setup.stagger; -      ccd_shift[4] = ccd_shift[1] + dev->current_setup.stagger; -      ccd_shift[5] = ccd_shift[2] + dev->current_setup.stagger; - -      shift_count = 6; -    } - - -/* convert data */ -/* -  0. fill_read_buffer --------------- read_buffer ---------------------- -  1a). (opt)uncis                    (assumes color components to be laid out -                                    planar) -  1b). (opt)reverse_RGB              (assumes pixels to be BGR or BBGGRR)) --------------- lines_buffer ---------------------- -  2a). (opt)line_distance_correction (assumes RGB or RRGGBB) -  2b). (opt)unstagger                (assumes pixels to be depth*channels/8 -                                      bytes long, unshrinked) -------------- shrink_buffer --------------------- -  3. (opt)shrink_lines             (assumes component separation in pixels) --------------- out_buffer ----------------------- -  4. memcpy to destination (for lineart with bit reversal) -*/ -/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to -  bytes at 0. and back to bits at 4. -Problems with the first approach: -  - its not clear how to check if we need to output an incomplete byte -    because it is the last one. - */ -/*FIXME: add lineart support for gl646. in the meantime add logic to convert -  from gray to lineart at the end? would suffer the above problem, -  total_bytes_to_read and total_bytes_read help in that case. - */ - -  status = genesys_fill_read_buffer (dev); - -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "genesys_read_ordered_data: genesys_fill_read_buffer failed\n"); -      return status; -    } - -  src_buffer = &(dev->read_buffer); - -/* maybe reorder components/bytes */ -  if (needs_reorder) -    { -/*not implemented for depth == 1.*/ -      if (depth == 1) -	{ -	  DBG (DBG_error, "Can't reorder single bit data\n"); -	  return SANE_STATUS_INVAL; -	} - -      dst_buffer = &(dev->lines_buffer); - -      work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); -      bytes = src_buffer->avail; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ -      if (bytes > dst_buffer->size - dst_buffer->avail) -	bytes = dst_buffer->size - dst_buffer->avail; - -      dst_lines = (bytes * 8) / (src_pixels * channels * depth); -      bytes = (dst_lines * src_pixels * channels * depth) / 8; - -      work_buffer_dst = sanei_genesys_buffer_get_write_pos (dst_buffer, -							    bytes); - -      DBG (DBG_info, "genesys_read_ordered_data: reordering %d lines\n", -	   dst_lines); - -      if (dst_lines != 0) -	{ - -	  if (channels == 3) -	    { -	      step_1_mode = 0; - -	      if (depth == 16) -		step_1_mode |= 1; - -	      if (dev->model->is_cis) -		step_1_mode |= 2; - -	      if (dev->model->line_mode_color_order == COLOR_ORDER_BGR) -		step_1_mode |= 4; - -	      switch (step_1_mode) -		{ -		case 1:	/* RGB, chunky, 16 bit */ -#ifdef WORDS_BIGENDIAN -		  status = -		    genesys_reorder_components_endian_16 (work_buffer_src, -							  work_buffer_dst, -							  dst_lines, -							  src_pixels, 3); -		  break; -#endif /*WORDS_BIGENDIAN */ -		case 0:	/* RGB, chunky, 8 bit */ -		  status = SANE_STATUS_GOOD; -		  break; -		case 2:	/* RGB, cis, 8 bit */ -		  status = -		    genesys_reorder_components_cis_8 (work_buffer_src, -						      work_buffer_dst, -						      dst_lines, src_pixels); -		  break; -		case 3:	/* RGB, cis, 16 bit */ -		  status = -		    genesys_reorder_components_cis_16 (work_buffer_src, -						       work_buffer_dst, -						       dst_lines, src_pixels); -		  break; -		case 4:	/* BGR, chunky, 8 bit */ -		  status = -		    genesys_reorder_components_bgr_8 (work_buffer_src, -						      work_buffer_dst, -						      dst_lines, src_pixels); -		  break; -		case 5:	/* BGR, chunky, 16 bit */ -		  status = -		    genesys_reorder_components_bgr_16 (work_buffer_src, -						       work_buffer_dst, -						       dst_lines, src_pixels); -		  break; -		case 6:	/* BGR, cis, 8 bit */ -		  status = -		    genesys_reorder_components_cis_bgr_8 (work_buffer_src, -							  work_buffer_dst, -							  dst_lines, -							  src_pixels); -		  break; -		case 7:	/* BGR, cis, 16 bit */ -		  status = -		    genesys_reorder_components_cis_bgr_16 (work_buffer_src, -							   work_buffer_dst, -							   dst_lines, -							   src_pixels); -		  break; -		} -	    } -	  else -	    { -#ifdef WORDS_BIGENDIAN -	      if (depth == 16) -		{ -		  status = -		    genesys_reorder_components_endian_16 (work_buffer_src, -							  work_buffer_dst, -							  dst_lines, -							  src_pixels, 1); -		} -	      else -		{ -		  status = SANE_STATUS_GOOD; -		} -#else /*!WORDS_BIGENDIAN */ -	      status = SANE_STATUS_GOOD; -#endif /*WORDS_BIGENDIAN */ -	    } - -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_read_ordered_data: failed to convert byte ordering(%s)\n", -		   sane_strstatus (status)); -	      return SANE_STATUS_IO_ERROR; -	    } - -	  RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - -	  RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); -	} -      src_buffer = dst_buffer; -    } - -/* maybe reverse effects of ccd layout */ -  if (needs_ccd) -    { -/*should not happen with depth == 1.*/ -      if (depth == 1) -	{ -	  DBG (DBG_error, "Can't reverse ccd for single bit data\n"); -	  return SANE_STATUS_INVAL; -	} - -      dst_buffer = &(dev->shrink_buffer); - -      work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); -      bytes = src_buffer->avail; - -      extra = -	(dev->current_setup.max_shift * src_pixels * channels * depth) / 8; - -/*extra bytes are reserved, and should not be consumed*/ -      if (bytes < extra) -	bytes = 0; -      else -	bytes -= extra; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ -      if (bytes > dst_buffer->size - dst_buffer->avail) -	bytes = dst_buffer->size - dst_buffer->avail; - -      dst_lines = (bytes * 8) / (src_pixels * channels * depth); -      bytes = (dst_lines * src_pixels * channels * depth) / 8; - -      work_buffer_dst = -	sanei_genesys_buffer_get_write_pos (dst_buffer, bytes); - -      DBG (DBG_info, "genesys_read_ordered_data: un-ccd-ing %d lines\n", -	   dst_lines); - -      if (dst_lines != 0) -	{ - -	  if (depth == 8) -	    status = genesys_reverse_ccd_8 (work_buffer_src, work_buffer_dst, -					    dst_lines, -					    src_pixels * channels, -					    ccd_shift, shift_count); -	  else -	    status = genesys_reverse_ccd_16 (work_buffer_src, work_buffer_dst, -					     dst_lines, -					     src_pixels * channels, -					     ccd_shift, shift_count); - -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_read_ordered_data: failed to reverse ccd effects(%s)\n", -		   sane_strstatus (status)); -	      return SANE_STATUS_IO_ERROR; -	    } - -	  RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - -	  RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); -	} -      src_buffer = dst_buffer; -    } - -/* maybe shrink(or enlarge) lines */ -  if (needs_shrink) -    { - -      dst_buffer = &(dev->out_buffer); - -      work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); -      bytes = src_buffer->avail; - -/*lines in input*/ -      dst_lines = (bytes * 8) / (src_pixels * channels * depth); - -      /* how many lines can be processed here?      */ -      /* we are greedy. we work as much as possible */ -      bytes = dst_buffer->size - dst_buffer->avail; - -      if (dst_lines > (bytes * 8) / (dev->settings.pixels * channels * depth)) -	dst_lines = (bytes * 8) / (dev->settings.pixels * channels * depth); - -      bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; - -      work_buffer_dst = -	sanei_genesys_buffer_get_write_pos (dst_buffer, bytes); - -      DBG (DBG_info, "genesys_read_ordered_data: shrinking %d lines\n", -	   dst_lines); - -      if (dst_lines != 0) -	{ -	  if (depth == 1) -	    status = genesys_shrink_lines_1 (work_buffer_src, -					     work_buffer_dst, -					     dst_lines, -					     src_pixels, -					     dev->settings.pixels, -                                             channels); -	  else if (depth == 8) -	    status = genesys_shrink_lines_8 (work_buffer_src, -					     work_buffer_dst, -					     dst_lines, -					     src_pixels, -					     dev->settings.pixels, channels); -	  else -	    status = genesys_shrink_lines_16 (work_buffer_src, -					      work_buffer_dst, -					      dst_lines, -					      src_pixels, -					      dev->settings.pixels, channels); - -	  if (status != SANE_STATUS_GOOD) -	    { -	      DBG (DBG_error, -		   "genesys_read_ordered_data: failed to shrink lines(%s)\n", -		   sane_strstatus (status)); -	      return SANE_STATUS_IO_ERROR; -	    } - -          /* we just consumed this many bytes*/ -	  bytes = (dst_lines * src_pixels * channels * depth) / 8; -	  RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - -          /* we just created this many bytes*/ -	  bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; -	  RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - -	} -      src_buffer = dst_buffer; -    } - -  /* move data to destination */ -  bytes = src_buffer->avail; -  if (bytes > *len) -    bytes = *len; -  work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); - -  if (needs_reverse) -    { -      status = genesys_reverse_bits (work_buffer_src, destination, bytes); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "genesys_read_ordered_data: failed to reverse bits(%s)\n", -	       sane_strstatus (status)); -	  return SANE_STATUS_IO_ERROR; -	} -      *len = bytes; -    } -  else -    { -      memcpy (destination, work_buffer_src, bytes); -      *len = bytes; -    } - -  /* avoid signaling some extra data because we have treated a full block -   * on the last block */ -  if (dev->total_bytes_read + *len > dev->total_bytes_to_read) -    *len = dev->total_bytes_to_read - dev->total_bytes_read; - -  /* count bytes sent to frontend */ -  dev->total_bytes_read += *len; - -  RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - -  /* end scan if all needed data have been read */ -   if(dev->total_bytes_read >= dev->total_bytes_to_read) -    { -      dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE); -      if (dev->model->is_sheetfed == SANE_TRUE) -        { -          dev->model->cmd_set->eject_document (dev); -        } -    } - -  DBG (DBG_proc, "genesys_read_ordered_data: completed, %lu bytes read\n", -       (u_long) bytes); -  return SANE_STATUS_GOOD; -} - - - -/* ------------------------------------------------------------------------ */ -/*                  Start of higher level functions                         */ -/* ------------------------------------------------------------------------ */ - -static size_t -max_string_size (const SANE_String_Const strings[]) -{ -  size_t size, max_size = 0; -  SANE_Int i; - -  for (i = 0; strings[i]; ++i) -    { -      size = strlen (strings[i]) + 1; -      if (size > max_size) -	max_size = size; -    } -  return max_size; -} - -static SANE_Status -calc_parameters (Genesys_Scanner * s) -{ -  SANE_String mode, source, color_filter; -  SANE_Status status = SANE_STATUS_GOOD; -  SANE_Int depth = 0, resolution = 0; -  double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0; - -  mode = s->val[OPT_MODE].s; -  source = s->val[OPT_SOURCE].s; -  color_filter = s->val[OPT_COLOR_FILTER].s; -  depth = s->val[OPT_BIT_DEPTH].w; -  resolution = s->val[OPT_RESOLUTION].w; -  tl_x = SANE_UNFIX (s->val[OPT_TL_X].w); -  tl_y = SANE_UNFIX (s->val[OPT_TL_Y].w); -  br_x = SANE_UNFIX (s->val[OPT_BR_X].w); -  br_y = SANE_UNFIX (s->val[OPT_BR_Y].w); - -  s->params.last_frame = SANE_TRUE;	/* only single pass scanning supported */ - -  if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0 -      || strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) -    s->params.format = SANE_FRAME_GRAY; -  else				/* Color */ -    s->params.format = SANE_FRAME_RGB; - -  if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) -    s->params.depth = 1; -  else -    s->params.depth = depth; -  s->dev->settings.depth = depth; - -  /* interpolation */ -  s->dev->settings.disable_interpolation = -    s->val[OPT_DISABLE_INTERPOLATION].w == SANE_TRUE; - -  /* hardware settings */ -  if (resolution > s->dev->sensor.optical_res && -      s->dev->settings.disable_interpolation) -    s->dev->settings.xres = s->dev->sensor.optical_res; -  else -    s->dev->settings.xres = resolution; -  s->dev->settings.yres = resolution; - -  s->params.lines = ((br_y - tl_y) * s->dev->settings.yres) / MM_PER_INCH; -  s->params.pixels_per_line = -    ((br_x - tl_x) * resolution) / MM_PER_INCH; - -  /* we need an even pixels number -   * TODO invert test logic or generalize behaviour across all ASICs */ -  if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) -      || s->dev->model->asic_type == GENESYS_GL847 -      || s->dev->model->asic_type == GENESYS_GL124 -      || s->dev->model->asic_type == GENESYS_GL845 -      || s->dev->model->asic_type == GENESYS_GL846 -      || s->dev->model->asic_type == GENESYS_GL843) -    { -      if (s->dev->settings.xres <= 1200) -        s->params.pixels_per_line = (s->params.pixels_per_line/4)*4; -      else -        s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; -    } - -  /* corner case for true lineart for sensor with several segments -   * or when xres is doubled to match yres */ -  if (s->dev->settings.xres >= 1200 -      && (    s->dev->model->asic_type == GENESYS_GL124 -           || s->dev->model->asic_type == GENESYS_GL847 -           || s->dev->current_setup.xres < s->dev->current_setup.yres -         ) -     ) -    { -      s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; -    } - -  s->params.bytes_per_line = s->params.pixels_per_line; -  if (s->params.depth > 8) -    { -      s->params.depth = 16; -      s->params.bytes_per_line *= 2; -    } -  else if (s->params.depth == 1) -    { -      s->params.bytes_per_line /= 8; -      /* round down pixel number -         really? rounding down means loss of at most 7 pixels! -- pierre */ -      s->params.pixels_per_line = 8 * s->params.bytes_per_line; -    } - -  if (s->params.format == SANE_FRAME_RGB) -    s->params.bytes_per_line *= 3; - -  if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) -    s->dev->settings.scan_mode = SCAN_MODE_COLOR; -  else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) -    s->dev->settings.scan_mode = SCAN_MODE_GRAY; -  else if (strcmp (mode, SANE_TITLE_HALFTONE) == 0) -    s->dev->settings.scan_mode = SCAN_MODE_HALFTONE; -  else				/* Lineart */ -    s->dev->settings.scan_mode = SCAN_MODE_LINEART; - -  /* TODO: change and check */ -  if (strcmp (source, FLATBED) == 0) -    s->dev->settings.scan_method = SCAN_METHOD_FLATBED; -  else				/* transparency */ -    s->dev->settings.scan_method = SCAN_METHOD_TRANSPARENCY; - -  s->dev->settings.lines = s->params.lines; -  s->dev->settings.pixels = s->params.pixels_per_line; -  s->dev->settings.tl_x = tl_x; -  s->dev->settings.tl_y = tl_y; - -  /* threshold setting */ -  s->dev->settings.threshold = 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); - -  /* color filter */ -  if (strcmp (color_filter, "Red") == 0) -    s->dev->settings.color_filter = 0; -  else if (strcmp (color_filter, "Green") == 0) -    s->dev->settings.color_filter = 1; -  else if (strcmp (color_filter, "Blue") == 0) -    s->dev->settings.color_filter = 2; -  else -    s->dev->settings.color_filter = 3; - -  /* true gray */ -  if (strcmp (color_filter, "None") == 0) -    s->dev->settings.true_gray = 1; -  else -    s->dev->settings.true_gray = 0; - -  /* dynamic lineart */ -  s->dev->settings.dynamic_lineart = SANE_FALSE; -  s->dev->settings.threshold_curve=0; -  if(s->val[OPT_DISABLE_DYNAMIC_LINEART].w ==SANE_FALSE -   &&s->dev->settings.scan_mode == SCAN_MODE_LINEART) -   { -      s->dev->settings.dynamic_lineart = SANE_TRUE; -   } - -  /* hardware lineart works only when we don't have interleave data -   * for GL847 scanners, ie up to 600 DPI, then we have to rely on -   * dynamic_lineart */ -  if(s->dev->settings.xres > 600 -     && s->dev->model->asic_type==GENESYS_GL847 -     && s->dev->settings.scan_mode == SCAN_MODE_LINEART) -   { -      s->dev->settings.dynamic_lineart = SANE_TRUE; -   } - -  /* threshold curve for dynamic rasterization */ -  s->dev->settings.threshold_curve=s->val[OPT_THRESHOLD_CURVE].w; - -  /* some digital processing requires the whole picture to be buffered */ -  /* no digital processing takes place when doing preview, or when bit depth is -   * higher than 8 bits */ -  if ((s->val[OPT_SWDESPECK].b -    || s->val[OPT_SWCROP].b -    || s->val[OPT_SWDESKEW].b -    || s->val[OPT_SWDEROTATE].b -    ||(SANE_UNFIX(s->val[OPT_SWSKIP].w)>0)) -    && (!s->val[OPT_PREVIEW].b) -    && (s->val[OPT_BIT_DEPTH].w <= 8)) -    { -      s->dev->buffer_image=SANE_TRUE; -    } -  else -    { -      s->dev->buffer_image=SANE_FALSE; -    } - -  /* brigthness and contrast only for for 8 bit scans */ -  if(s->val[OPT_BIT_DEPTH].w <= 8) -    { -      s->dev->settings.contrast=(s->val[OPT_CONTRAST].w*127)/100; -      s->dev->settings.brightness=(s->val[OPT_BRIGHTNESS].w*127)/100; -    } -  else -    { -      s->dev->settings.contrast=0; -      s->dev->settings.brightness=0; -    } - -  /* cache expiration time */ -   s->dev->settings.expiration_time=s->val[OPT_EXPIRATION_TIME].w; - -  return status; -} - - -static SANE_Status -create_bpp_list (Genesys_Scanner * s, SANE_Int * bpp) -{ -  int count; - -  for (count = 0; bpp[count] != 0; count++) -    ; -  s->bpp_list[0] = count; -  for (count = 0; bpp[count] != 0; count++) -    { -      s->bpp_list[s->bpp_list[0] - count] = bpp[count]; -    } -  return SANE_STATUS_GOOD; -} - -/** @brief this function initialize a gamma vector based on the ASIC: - * Set up a default gamma table vector based on device description - * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA - * gl84x: 16 bits - * gl12x: 16 bits - * @param scanner pointer to scanner session to get options - * @param option option number of the gamma table to set - */ -static void -init_gamma_vector_option (Genesys_Scanner * scanner, int option) -{ -  /* the option is inactive until the custom gamma control -   * is enabled */ -  scanner->opt[option].type = SANE_TYPE_INT; -  scanner->opt[option].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; -  scanner->opt[option].unit = SANE_UNIT_NONE; -  scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE; -  if (scanner->dev->model->asic_type == GENESYS_GL646) -    { -      if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0) -	{ -	  scanner->opt[option].size = 16384 * sizeof (SANE_Word); -	  scanner->opt[option].constraint.range = &u14_range; -	} -      else -	{			/* 12 bits gamma tables */ -	  scanner->opt[option].size = 4096 * sizeof (SANE_Word); -	  scanner->opt[option].constraint.range = &u12_range; -	} -    } -  else -    {				/* other asics have 16 bits words gamma table */ -      scanner->opt[option].size = 256 * sizeof (SANE_Word); -      scanner->opt[option].constraint.range = &u16_range; -    } -  /* default value is NULL */ -  scanner->val[option].wa = NULL; -} - -/** - * allocate a geometry range - * @param size maximum size of the range - * @return a pointer to a valid range or NULL - */ -static SANE_Range *create_range(SANE_Fixed size) -{ -SANE_Range *range=NULL; - -  range=(SANE_Range *)malloc(sizeof(SANE_Range)); -  if(range!=NULL) -    { -      range->min = SANE_FIX (0.0); -      range->max = size; -      range->quant = SANE_FIX (0.0); -    } -  return range; -} - -/** @brief generate calibration cache file nam - * Generates the calibration cache file name to use. - * Tries to store the chache in $HOME/.sane or - * then fallbacks to $TMPDIR or TMP. The filename - * uses the model name if only one scanner is plugged - * else is uses the device name when several identical - * scanners are in use. - * @param currdev current scanner device - * @return an allocated string containing a file name - */ -GENESYS_STATIC char *calibration_filename(Genesys_Device *currdev) -{ -  char *tmpstr; -  char *ptr; -  char filename[80]; -  Genesys_Device *dev; -  unsigned int count; -  unsigned int i; - -  /* allocate space for result */ -  tmpstr=malloc(PATH_MAX); -  if(tmpstr==NULL) -    { -      return NULL; -    } - -  /* first compute the DIR where we can store cache: -   * 1 - home dir -   * 2 - $TMPDIR -   * 3 - $TMP -   * 4 - tmp dir -   * 5 - temp dir -   * 6 - then resort to current dir -   */ -  ptr = getenv ("HOME"); -  if(ptr==NULL) -    { -      ptr = getenv ("USERPROFILE"); -    } -  if(ptr==NULL) -    { -      ptr = getenv ("TMPDIR"); -    } -  if(ptr==NULL) -    { -      ptr = getenv ("TMP"); -    } - -  /* now choose filename: -   * 1 - if only one scanner, name of the model -   * 2 - if several scanners of the same model, use device name, -   *     replacing special chars -   */ -  count=0; -  /* count models of the same names if several scanners attached */ -  if(num_devices>1) -    { -      for (dev = first_dev; dev; dev = dev->next) -        { -          if(strcmp(dev->model->name,currdev->model->name)==0) -            { -              count++; -            } -        } -    } -  if(count>1) -    { -      snprintf(filename,sizeof(filename),"%s.cal",currdev->file_name); -      for(i=0;i<strlen(filename);i++) -        { -          if(filename[i]==':'||filename[i]==PATH_SEP) -            { -              filename[i]='_'; -            } -        } -    } -  else -    { -      snprintf(filename,sizeof(filename),"%s.cal",currdev->model->name); -    } - -  /* build final final name : store dir + filename */ -  if (NULL == ptr) -    { -      snprintf (tmpstr, PATH_MAX, "%s", filename); -    } -  else -    { -#ifdef HAVE_MKDIR -      /* make sure .sane directory exists in existing store dir */ -      snprintf (tmpstr, PATH_MAX, "%s%c.sane", ptr, PATH_SEP); -      mkdir(tmpstr,0700); -#endif -      snprintf (tmpstr, PATH_MAX, "%s%c.sane%c%s", ptr, PATH_SEP, PATH_SEP, filename); -    } - -  DBG (DBG_info, "%s: calibration filename >%s<\n", __func__, tmpstr); - -  return tmpstr; -} - - -static SANE_Status -init_options (Genesys_Scanner * s) -{ -  SANE_Int option, count, min_dpi; -  SANE_Status status; -  SANE_Word *dpi_list; -  Genesys_Model *model = s->dev->model; -  SANE_Range *x_range, *y_range; - -  DBGSTART; - -  memset (s->opt, 0, sizeof (s->opt)); -  memset (s->val, 0, sizeof (s->val)); - -  for (option = 0; option < NUM_OPTIONS; ++option) -    { -      s->opt[option].size = sizeof (SANE_Word); -      s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; -    } -  s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; -  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; -  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; -  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; -  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; -  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; - -  /* "Mode" group: */ -  s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); -  s->opt[OPT_MODE_GROUP].desc = ""; -  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_MODE_GROUP].size = 0; -  s->opt[OPT_MODE_GROUP].cap = 0; -  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  /* scan mode */ -  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; -  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; -  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; -  s->opt[OPT_MODE].type = SANE_TYPE_STRING; -  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; -  s->opt[OPT_MODE].size = max_string_size (mode_list); -  s->opt[OPT_MODE].constraint.string_list = mode_list; -  s->val[OPT_MODE].s = strdup (SANE_VALUE_SCAN_MODE_GRAY); - -  /* scan source */ -  s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; -  s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; -  s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; -  s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; -  s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; -  s->opt[OPT_SOURCE].size = max_string_size (source_list); -  s->opt[OPT_SOURCE].constraint.string_list = source_list; -  s->val[OPT_SOURCE].s = strdup (FLATBED); -  if (model->flags & GENESYS_FLAG_HAS_UTA) -    { -      ENABLE (OPT_SOURCE); -    } -  else -    { -      DISABLE (OPT_SOURCE); -    } - -  /* preview */ -  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; -  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; -  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; -  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; -  s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE; -  s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; -  s->val[OPT_PREVIEW].w = SANE_FALSE; - -  /* bit depth */ -  s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; -  s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; -  s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; -  s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; -  s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; -  s->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); -  s->opt[OPT_BIT_DEPTH].constraint.word_list = 0; -  s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; -  create_bpp_list (s, model->bpp_gray_values); -  s->val[OPT_BIT_DEPTH].w = 8; -  if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) -    DISABLE (OPT_BIT_DEPTH); - -  /* resolution */ -  min_dpi=200000; -  for (count = 0; model->xdpi_values[count] != 0; count++) -    { -      if(model->xdpi_values[count]<min_dpi) -        { -          min_dpi=model->xdpi_values[count]; -        } -    } -  dpi_list = malloc ((count + 1) * sizeof (SANE_Word)); -  if (!dpi_list) -    return SANE_STATUS_NO_MEM; -  dpi_list[0] = count; -  for (count = 0; model->xdpi_values[count] != 0; count++) -    dpi_list[count + 1] = model->xdpi_values[count]; -  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; -  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; -  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; -  s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; -  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; -  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; -  s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; -  s->val[OPT_RESOLUTION].w = min_dpi; - -  /* "Geometry" group: */ -  s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); -  s->opt[OPT_GEOMETRY_GROUP].desc = ""; -  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; -  s->opt[OPT_GEOMETRY_GROUP].size = 0; -  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  x_range=create_range(model->x_size); -  if(x_range==NULL) -    { -      return SANE_STATUS_NO_MEM; -    } - -  y_range=create_range(model->y_size); -  if(y_range==NULL) -    { -      return SANE_STATUS_NO_MEM; -    } - -  /* top-left x */ -  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; -  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; -  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; -  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; -  s->opt[OPT_TL_X].unit = SANE_UNIT_MM; -  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_TL_X].constraint.range = x_range; -  s->val[OPT_TL_X].w = 0; - -  /* top-left y */ -  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; -  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; -  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; -  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; -  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; -  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_TL_Y].constraint.range = y_range; -  s->val[OPT_TL_Y].w = 0; - -  /* bottom-right x */ -  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; -  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; -  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; -  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; -  s->opt[OPT_BR_X].unit = SANE_UNIT_MM; -  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_BR_X].constraint.range = x_range; -  s->val[OPT_BR_X].w = x_range->max; - -  /* bottom-right y */ -  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; -  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; -  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; -  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; -  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; -  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_BR_Y].constraint.range = y_range; -  s->val[OPT_BR_Y].w = y_range->max; - -  /* "Enhancement" group: */ -  s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); -  s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; -  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; -  s->opt[OPT_ENHANCEMENT_GROUP].size = 0; -  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  /* custom-gamma table */ -  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; -  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; -  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; -  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; -  s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED; -  s->val[OPT_CUSTOM_GAMMA].b = SANE_FALSE; - -  /* grayscale gamma vector */ -  s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; -  s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; -  s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; -  init_gamma_vector_option (s, OPT_GAMMA_VECTOR); - -  /* red gamma vector */ -  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; -  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; -  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; -  init_gamma_vector_option (s, OPT_GAMMA_VECTOR_R); - -  /* green gamma vector */ -  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; -  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; -  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; -  init_gamma_vector_option (s, OPT_GAMMA_VECTOR_G); - -  /* blue gamma vector */ -  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; -  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; -  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; -  init_gamma_vector_option (s, OPT_GAMMA_VECTOR_B); - -  /* currently, there are only gamma table options in this group, -   * so if the scanner doesn't support gamma table, disable the -   * whole group */ -  if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA)) -    { -      s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE; -      s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; -      DBG (DBG_info, "init_options: custom gamma disabled\n"); -    } - -  /* software base image enhancements, these are consuming as many -   * memory than used by the full scanned image and may fail at high -   * resolution -   */ -  /* software deskew */ -  s->opt[OPT_SWDESKEW].name = "swdeskew"; -  s->opt[OPT_SWDESKEW].title = "Software deskew"; -  s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally"; -  s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; -  s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; -  s->val[OPT_SWDESKEW].b = SANE_FALSE; - -  /* software deskew */ -  s->opt[OPT_SWDESPECK].name = "swdespeck"; -  s->opt[OPT_SWDESPECK].title = "Software despeck"; -  s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally"; -  s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL; -  s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; -  s->val[OPT_SWDESPECK].b = SANE_FALSE; - -  /* software despeckle radius */ -  s->opt[OPT_DESPECK].name = "despeck"; -  s->opt[OPT_DESPECK].title = "Software despeckle diameter"; -  s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan"; -  s->opt[OPT_DESPECK].type = SANE_TYPE_INT; -  s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE; -  s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_DESPECK].constraint.range = &swdespeck_range; -  s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE; -  s->val[OPT_DESPECK].w = 1; - -  /* crop by software */ -  s->opt[OPT_SWCROP].name = "swcrop"; -  s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop"); -  s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally"); -  s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; -  s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; -  s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; -  s->val[OPT_SWCROP].b = SANE_FALSE; - -  /* Software blank page skip */ -  s->opt[OPT_SWSKIP].name = "swskip"; -  s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); -  s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); -  s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; -  s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; -  s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_SWSKIP].constraint.range = &(percentage_range); -  s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; -  /* disable by default */ -  s->val[OPT_SWSKIP].w = 0; - -  /* Software Derotate */ -  s->opt[OPT_SWDEROTATE].name = "swderotate"; -  s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); -  s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); -  s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; -  s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; -  s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; -  s->val[OPT_SWDEROTATE].b = SANE_FALSE; - -  /* Software brightness */ -  s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; -  s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; -  s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; -  s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; -  s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; -  s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_BRIGHTNESS].constraint.range = &(enhance_range); -  s->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; -  /* disable by default */ -  s->val[OPT_BRIGHTNESS].w = 0; - -  /* Sowftware contrast */ -  s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; -  s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; -  s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; -  s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; -  s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; -  s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_CONTRAST].constraint.range = &(enhance_range); -  s->opt[OPT_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; -  /* disable by default */ -  s->val[OPT_CONTRAST].w = 0; - -  /* "Extras" group: */ -  s->opt[OPT_EXTRAS_GROUP].title = SANE_I18N ("Extras"); -  s->opt[OPT_EXTRAS_GROUP].desc = ""; -  s->opt[OPT_EXTRAS_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_EXTRAS_GROUP].cap = SANE_CAP_ADVANCED; -  s->opt[OPT_EXTRAS_GROUP].size = 0; -  s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  /* BW threshold */ -  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; -  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; -  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; -  s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; -  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; -  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_THRESHOLD].constraint.range = &percentage_range; -  s->val[OPT_THRESHOLD].w = SANE_FIX (50); - -  /* BW threshold curve */ -  s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve"; -  s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve"); -  s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65"); -  s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT; -  s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE; -  s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range; -  s->val[OPT_THRESHOLD_CURVE].w = 50; - -  /* dynamic linart */ -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].name = "disable-dynamic-lineart"; -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].title = SANE_I18N ("Disable dynamic lineart"); -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].desc = -    SANE_I18N ("Disable use of a software adaptive algorithm to generate lineart relying instead on hardware lineart."); -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].type = SANE_TYPE_BOOL; -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].unit = SANE_UNIT_NONE; -  s->opt[OPT_DISABLE_DYNAMIC_LINEART].constraint_type = SANE_CONSTRAINT_NONE; -  s->val[OPT_DISABLE_DYNAMIC_LINEART].w = SANE_FALSE; - -  /* fastmod is required for hw lineart to work */ -  if ((s->dev->model->asic_type == GENESYS_GL646) -    &&(s->dev->model->motor_type != MOTOR_XP200)) -    { -      s->opt[OPT_DISABLE_DYNAMIC_LINEART].cap = SANE_CAP_INACTIVE; -    } - -  /* disable_interpolation */ -  s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation"; -  s->opt[OPT_DISABLE_INTERPOLATION].title = -    SANE_I18N ("Disable interpolation"); -  s->opt[OPT_DISABLE_INTERPOLATION].desc = -    SANE_I18N -    ("When using high resolutions where the horizontal resolution is smaller " -     "than the vertical resolution this disables horizontal interpolation."); -  s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL; -  s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE; -  s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE; -  s->val[OPT_DISABLE_INTERPOLATION].w = SANE_FALSE; - -  /* color filter */ -  s->opt[OPT_COLOR_FILTER].name = "color-filter"; -  s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter"); -  s->opt[OPT_COLOR_FILTER].desc = -    SANE_I18N -    ("When using gray or lineart this option selects the used color."); -  s->opt[OPT_COLOR_FILTER].type = SANE_TYPE_STRING; -  s->opt[OPT_COLOR_FILTER].constraint_type = SANE_CONSTRAINT_STRING_LIST; -  /* true gray not yet supported for GL847 and GL124 scanners */ -  if(!model->is_cis || model->asic_type==GENESYS_GL847 || model->asic_type==GENESYS_GL124) -    { -      s->opt[OPT_COLOR_FILTER].size = max_string_size (color_filter_list); -      s->opt[OPT_COLOR_FILTER].constraint.string_list = color_filter_list; -      s->val[OPT_COLOR_FILTER].s = strdup (s->opt[OPT_COLOR_FILTER].constraint.string_list[1]); -    } -  else -    { -      s->opt[OPT_COLOR_FILTER].size = max_string_size (cis_color_filter_list); -      s->opt[OPT_COLOR_FILTER].constraint.string_list = cis_color_filter_list; -      /* default to "None" ie true gray */ -      s->val[OPT_COLOR_FILTER].s = strdup (s->opt[OPT_COLOR_FILTER].constraint.string_list[3]); -    } - -  /* no support for color filter for cis+gl646 scanners */ -  if (model->asic_type == GENESYS_GL646 && model->is_cis) -    { -      DISABLE (OPT_COLOR_FILTER); -    } - -  /* calibration store file name */ -  s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; -  s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); -  s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); -  s->opt[OPT_CALIBRATION_FILE].type = SANE_TYPE_STRING; -  s->opt[OPT_CALIBRATION_FILE].unit = SANE_UNIT_NONE; -  s->opt[OPT_CALIBRATION_FILE].size = PATH_MAX; -  s->opt[OPT_CALIBRATION_FILE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; -  s->opt[OPT_CALIBRATION_FILE].constraint_type = SANE_CONSTRAINT_NONE; -  s->val[OPT_CALIBRATION_FILE].s = NULL; -  /* disable option if ran as root */ -#ifdef HAVE_GETUID -  if(geteuid()==0) -    { -      DISABLE (OPT_CALIBRATION_FILE); -    } -#endif - -  /* expiration time for calibration cache entries */ -  s->opt[OPT_EXPIRATION_TIME].name = "expiration-time"; -  s->opt[OPT_EXPIRATION_TIME].title = SANE_I18N ("Calibration cache expiration time"); -  s->opt[OPT_EXPIRATION_TIME].desc = SANE_I18N ("Time (in minutes) before a cached calibration expires. " -     "A value of 0 means cache is not used. A negative value means cache never expires."); -  s->opt[OPT_EXPIRATION_TIME].type = SANE_TYPE_INT; -  s->opt[OPT_EXPIRATION_TIME].unit = SANE_UNIT_NONE; -  s->opt[OPT_EXPIRATION_TIME].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_EXPIRATION_TIME].constraint.range = &expiration_range; -  s->val[OPT_EXPIRATION_TIME].w = 60;	/* 60 minutes by default */ - -  /* Powersave time (turn lamp off) */ -  s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; -  s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time"); -  s->opt[OPT_LAMP_OFF_TIME].desc = -    SANE_I18N -    ("The lamp will be turned off after the given time (in minutes). " -     "A value of 0 means, that the lamp won't be turned off."); -  s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; -  s->opt[OPT_LAMP_OFF_TIME].unit = SANE_UNIT_NONE; -  s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; -  s->opt[OPT_LAMP_OFF_TIME].constraint.range = &time_range; -  s->val[OPT_LAMP_OFF_TIME].w = 15;	/* 15 minutes */ - -  /* turn lamp off during scan */ -  s->opt[OPT_LAMP_OFF].name = "lamp-off-scan"; -  s->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off during scan"); -  s->opt[OPT_LAMP_OFF].desc = SANE_I18N ("The lamp will be turned off during scan. "); -  s->opt[OPT_LAMP_OFF].type = SANE_TYPE_BOOL; -  s->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE; -  s->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE; -  s->val[OPT_LAMP_OFF].w = SANE_FALSE; - -  s->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS; -  s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; -  s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED; -  s->opt[OPT_SENSOR_GROUP].size = 0; -  s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  s->opt[OPT_SCAN_SW].name = SANE_NAME_SCAN; -  s->opt[OPT_SCAN_SW].title = SANE_TITLE_SCAN; -  s->opt[OPT_SCAN_SW].desc = SANE_DESC_SCAN; -  s->opt[OPT_SCAN_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_SCAN_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_SCAN_SW) -    s->opt[OPT_SCAN_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_SCAN_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_SCAN_SW].b = 0; -  s->last_val[OPT_SCAN_SW].b = 0; - -  /* SANE_NAME_FILE is not for buttons */ -  s->opt[OPT_FILE_SW].name = "file"; -  s->opt[OPT_FILE_SW].title = SANE_I18N ("File button"); -  s->opt[OPT_FILE_SW].desc = SANE_I18N ("File button"); -  s->opt[OPT_FILE_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_FILE_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_FILE_SW) -    s->opt[OPT_FILE_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_FILE_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_FILE_SW].b = 0; -  s->last_val[OPT_FILE_SW].b = 0; - -  s->opt[OPT_EMAIL_SW].name = SANE_NAME_EMAIL; -  s->opt[OPT_EMAIL_SW].title = SANE_TITLE_EMAIL; -  s->opt[OPT_EMAIL_SW].desc = SANE_DESC_EMAIL; -  s->opt[OPT_EMAIL_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_EMAIL_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_EMAIL_SW) -    s->opt[OPT_EMAIL_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_EMAIL_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_EMAIL_SW].b = 0; -  s->last_val[OPT_EMAIL_SW].b = 0; - -  s->opt[OPT_COPY_SW].name = SANE_NAME_COPY; -  s->opt[OPT_COPY_SW].title = SANE_TITLE_COPY; -  s->opt[OPT_COPY_SW].desc = SANE_DESC_COPY; -  s->opt[OPT_COPY_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_COPY_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_COPY_SW) -    s->opt[OPT_COPY_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_COPY_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_COPY_SW].b = 0; -  s->last_val[OPT_COPY_SW].b = 0; - -  s->opt[OPT_PAGE_LOADED_SW].name = SANE_NAME_PAGE_LOADED; -  s->opt[OPT_PAGE_LOADED_SW].title = SANE_TITLE_PAGE_LOADED; -  s->opt[OPT_PAGE_LOADED_SW].desc = SANE_DESC_PAGE_LOADED; -  s->opt[OPT_PAGE_LOADED_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_PAGE_LOADED_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_PAGE_LOADED_SW) -    s->opt[OPT_PAGE_LOADED_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_PAGE_LOADED_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_PAGE_LOADED_SW].b = 0; -  s->last_val[OPT_PAGE_LOADED_SW].b = 0; - -  /* OCR button */ -  s->opt[OPT_OCR_SW].name = "ocr"; -  s->opt[OPT_OCR_SW].title = SANE_I18N ("OCR button"); -  s->opt[OPT_OCR_SW].desc = SANE_I18N ("OCR button"); -  s->opt[OPT_OCR_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_OCR_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_OCR_SW) -    s->opt[OPT_OCR_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_OCR_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_OCR_SW].b = 0; -  s->last_val[OPT_OCR_SW].b = 0; - -  /* power button */ -  s->opt[OPT_POWER_SW].name = "power"; -  s->opt[OPT_POWER_SW].title = SANE_I18N ("Power button"); -  s->opt[OPT_POWER_SW].desc = SANE_I18N ("Power button"); -  s->opt[OPT_POWER_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_POWER_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_POWER_SW) -    s->opt[OPT_POWER_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_POWER_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_POWER_SW].b = 0; -  s->last_val[OPT_POWER_SW].b = 0; - -  /* extra button */ -  s->opt[OPT_EXTRA_SW].name = "extra"; -  s->opt[OPT_EXTRA_SW].title = SANE_I18N ("Extra button"); -  s->opt[OPT_EXTRA_SW].desc = SANE_I18N ("Extra button"); -  s->opt[OPT_EXTRA_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_EXTRA_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_EXTRA_SW) -    s->opt[OPT_EXTRA_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_EXTRA_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_EXTRA_SW].b = 0; -  s->last_val[OPT_EXTRA_SW].b = 0; - -  /* calibration needed */ -  s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; -  s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); -  s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); -  s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; -  s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_CALIBRATE) -    s->opt[OPT_NEED_CALIBRATION_SW].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; -  else -    s->opt[OPT_NEED_CALIBRATION_SW].cap = SANE_CAP_INACTIVE; -  s->val[OPT_NEED_CALIBRATION_SW].b = 0; -  s->last_val[OPT_NEED_CALIBRATION_SW].b = 0; - -  /* button group */ -  s->opt[OPT_BUTTON_GROUP].title = SANE_I18N ("Buttons"); -  s->opt[OPT_BUTTON_GROUP].desc = ""; -  s->opt[OPT_BUTTON_GROUP].type = SANE_TYPE_GROUP; -  s->opt[OPT_BUTTON_GROUP].cap = SANE_CAP_ADVANCED; -  s->opt[OPT_BUTTON_GROUP].size = 0; -  s->opt[OPT_BUTTON_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - -  /* calibrate button */ -  s->opt[OPT_CALIBRATE].name = "calibrate"; -  s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate"); -  s->opt[OPT_CALIBRATE].desc = -    SANE_I18N ("Start calibration using special sheet"); -  s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON; -  s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE; -  if (model->buttons & GENESYS_HAS_CALIBRATE) -    s->opt[OPT_CALIBRATE].cap = -      SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | -      SANE_CAP_AUTOMATIC; -  else -    s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE; -  s->val[OPT_CALIBRATE].b = 0; -  s->last_val[OPT_CALIBRATE].b = 0; - -  /* clear calibration cache button */ -  s->opt[OPT_CLEAR_CALIBRATION].name = "clear-calibration"; -  s->opt[OPT_CLEAR_CALIBRATION].title = SANE_I18N ("Clear calibration"); -  s->opt[OPT_CLEAR_CALIBRATION].desc = SANE_I18N ("Clear calibration cache"); -  s->opt[OPT_CLEAR_CALIBRATION].type = SANE_TYPE_BUTTON; -  s->opt[OPT_CLEAR_CALIBRATION].unit = SANE_UNIT_NONE; -  s->opt[OPT_CLEAR_CALIBRATION].size = 0; -  s->opt[OPT_CLEAR_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; -  s->opt[OPT_CLEAR_CALIBRATION].cap = -    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; -  s->val[OPT_CLEAR_CALIBRATION].b = 0; -  s->last_val[OPT_CLEAR_CALIBRATION].b = 0; - -  RIE (calc_parameters (s)); - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -static SANE_Bool present; -static SANE_Status -check_present (SANE_String_Const devname) -{ -  present=SANE_TRUE; -  DBG (DBG_io, "check_present: %s detected.\n",devname); -  return SANE_STATUS_GOOD; -} - -/** @brief add a scanner device - * Insert the given device into the backend list of devices. - * @param dev device to add - */ -GENESYS_STATIC void add_device(Genesys_Device *dev) -{ -  ++num_devices; -  dev->next = first_dev; -  first_dev = dev; -} - -static SANE_Status -attach (SANE_String_Const devname, Genesys_Device ** devp, SANE_Bool may_wait) -{ -  Genesys_Device *dev = 0; -  SANE_Int dn, vendor, product; -  SANE_Status status; -  unsigned int i; - - -  DBG (DBG_proc, "attach: start: devp %s NULL, may_wait = %d\n", -       devp ? "!=" : "==", may_wait); - -  if (devp) -    *devp = 0; - -  if (!devname) -    { -      DBG (DBG_error, "attach: devname == NULL\n"); -      return SANE_STATUS_INVAL; -    } - -  for (dev = first_dev; dev; dev = dev->next) -    { -      if (strcmp (dev->file_name, devname) == 0) -	{ -	  if (devp) -	    *devp = dev; -	  DBG (DBG_info, "attach: device `%s' was already in device list\n", -	       devname); -	  return SANE_STATUS_GOOD; -	} -    } - -  DBG (DBG_info, "attach: trying to open device `%s'\n", devname); - -  status = sanei_usb_open (devname, &dn); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_warn, "attach: couldn't open device `%s': %s\n", devname, -	   sane_strstatus (status)); -      return status; -    } -  else -    DBG (DBG_info, "attach: device `%s' successfully opened\n", devname); - -  status = sanei_usb_get_vendor_product (dn, &vendor, &product); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -	   "attach: couldn't get vendor and product ids of device `%s': %s\n", -	   devname, sane_strstatus (status)); -      return status; -    } - -  /* KV-SS080 is an auxiliary device which requires a master device to be here */ -  if(vendor == 0x04da && product == 0x100f) -    { -      present=SANE_FALSE; -      sanei_usb_find_devices (vendor, 0x1006, check_present); -      sanei_usb_find_devices (vendor, 0x1007, check_present); -      sanei_usb_find_devices (vendor, 0x1010, check_present); -      if(present==SANE_FALSE) -        { -          DBG (DBG_error,"attach: master device not present\n"); -          return SANE_STATUS_INVAL; -        } -    } - -  for (i = 0; i < MAX_SCANNERS && genesys_usb_device_list[i].model != 0; i++) -    { -      if (vendor == genesys_usb_device_list[i].vendor && -	  product == genesys_usb_device_list[i].product) -	{ -	  dev = malloc (sizeof (*dev)); -	  if (!dev) -	    return SANE_STATUS_NO_MEM; -	  break; -	} -    } - -  if (!dev) -    { -      DBG (DBG_error, -	   "attach: vendor %d product %d is not supported by this backend\n", -	   vendor, product); -      return SANE_STATUS_INVAL; -    } - -  dev->file_name = strdup (devname); -  if (!dev->file_name) -    { -      free(dev); -      return SANE_STATUS_NO_MEM; -    } - -  dev->model = genesys_usb_device_list[i].model; -  dev->vendorId = genesys_usb_device_list[i].vendor; -  dev->productId = genesys_usb_device_list[i].product; -  dev->already_initialized = SANE_FALSE; - -  DBG (DBG_info, "attach: found %s flatbed scanner %s at %s\n", -       dev->model->vendor, dev->model->model, dev->file_name); -  add_device(dev); - -  if (devp) -    *devp = dev; -  sanei_usb_close (dn); -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -static SANE_Status -attach_one_device (SANE_String_Const devname) -{ -  Genesys_Device *dev; -  SANE_Status status; -  Genesys_Device **tmp_dev; - -  RIE (attach (devname, &dev, SANE_FALSE)); - -  if (dev) -    { -      /* Keep track of newly attached devices so we can set options as -         necessary.  */ -      tmp_dev=NULL; -      /* increase device list capacity if needed */ -      if (new_dev_len >= new_dev_alloced) -	{ -	  new_dev_alloced += 4; -	  if (new_dev) -            { -              tmp_dev = new_dev; -	      new_dev = realloc (new_dev, new_dev_alloced * sizeof (new_dev[0])); -            } -	  else -            { -	      new_dev = malloc (new_dev_alloced * sizeof (new_dev[0])); -              tmp_dev = NULL; -            } -	  if (!new_dev) -	    { -              FREE_IFNOT_NULL(tmp_dev) -	      DBG (DBG_error, "attach_one_device: out of memory\n"); -	      return SANE_STATUS_NO_MEM; -	    } -	} -      new_dev[new_dev_len++] = dev; -    } -  return SANE_STATUS_GOOD; -} - -/* configuration framework functions */ -static SANE_Status -config_attach_genesys (SANEI_Config __sane_unused__ *config, const char *devname) -{ -  /* the devname has been processed and is ready to be used -   * directly. Since the backend is an USB only one, we can -   * call sanei_usb_attach_matching_devices straight */ -  sanei_usb_attach_matching_devices (devname, attach_one_device); - -  return SANE_STATUS_GOOD; -} - -/* probes for scanner to attach to the backend */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -probe_genesys_devices (void) -{ -  SANEI_Config config; -  SANE_Status status; - -  DBGSTART; - -  new_dev = 0; -  new_dev_len = 0; -  new_dev_alloced = 0; - -  /* set configuration options structure : no option for this backend */ -  config.descriptors = NULL; -  config.values = NULL; -  config.count = 0; - -  /* generic configure and attach function */ -  status = sanei_configure_attach (GENESYS_CONFIG_FILE, &config, -				   config_attach_genesys); - -  if (new_dev_alloced > 0) -    { -      new_dev_len = new_dev_alloced = 0; -      free (new_dev); -    } - -  DBG(DBG_info, "%s: %d devices currently attached\n", __func__, num_devices); - -  DBGCOMPLETED; - -  return status; -} - -/** - * This should be changed if one of the substructures of -   Genesys_Calibration_Cache change, but it must be changed if there are -   changes that don't change size -- at least for now, as we store most -   of Genesys_Calibration_Cache as is. -*/ -#define CALIBRATION_VERSION 1 - -/** - * reads previously cached calibration data - * from file define in dev->calib_file - */ -SANE_Status -sanei_genesys_read_calibration (Genesys_Device * dev) -{ -  FILE *fp; -  uint8_t vers = 0; -  uint32_t size = 0; -  struct Genesys_Calibration_Cache *cache; -  SANE_Status status=SANE_STATUS_GOOD; - -  DBGSTART; - -  /* open calibration cache file */ -  fp = fopen (dev->calib_file, "rb"); -  if (!fp) -    { -      DBG (DBG_info, "Calibration: Cannot open %s\n", dev->calib_file); -      DBGCOMPLETED; -      return SANE_STATUS_IO_ERROR; -    } - -  /* these two checks ensure that most bad things cannot happen */ -  fread (&vers, 1, 1, fp); -  if (vers != CALIBRATION_VERSION) -    { -      DBG (DBG_info, "Calibration: Bad version\n"); -      fclose (fp); -      DBGCOMPLETED; -      return SANE_STATUS_INVAL; -    } -  fread (&size, 4, 1, fp); -  if (size != sizeof (struct Genesys_Calibration_Cache)) -    { -      DBG (DBG_info, -	   "Calibration: Size of calibration cache struct differs\n"); -      fclose (fp); -      DBGCOMPLETED; -      return SANE_STATUS_INVAL; -    } - -  /* clear device calibration cache */ -  while(dev->calibration_cache!=NULL) -    { -      cache=dev->calibration_cache; -      dev->calibration_cache=dev->calibration_cache->next; -      free(cache); -    } - -  /* loop on cache records in file */ -  while (!feof (fp) && status==SANE_STATUS_GOOD) -    { -      DBG (DBG_info, "sanei_genesys_read_calibration: reading one record\n"); -      cache = (struct Genesys_Calibration_Cache *) malloc (sizeof (*cache)); - -      if (!cache) -	{ -	  DBG (DBG_error, -	       "sanei_genesys_read_calibration: could not allocate cache struct\n"); -	  break; -	} - -#define BILT1( x )							\ -      do								\ -	{								\ -	  if ((x) < 1)							\ -	    {								\ -	      free(cache);						\ -	      DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); \ -              status=SANE_STATUS_EOF;                                   \ -	      break;							\ -	    }								\ -	} while(0) - - -      if (fread (&cache->used_setup, sizeof (cache->used_setup), 1, fp) < 1) -	{			/* eof is only detected here */ -	  free (cache); -          status=SANE_STATUS_GOOD; -	  break; -	} -      BILT1 (fread (&cache->last_calibration, sizeof (cache->last_calibration), 1, fp)); -      BILT1 (fread (&cache->frontend, sizeof (cache->frontend), 1, fp)); -      /* the gamma (and later) fields are not stored */ -      BILT1 (fread (&cache->sensor, offsetof (Genesys_Sensor, gamma[0]), 1, fp)); -      BILT1 (fread (&cache->calib_pixels, sizeof (cache->calib_pixels), 1, fp)); -      BILT1 (fread (&cache->calib_channels, sizeof (cache->calib_channels), 1, fp)); -      BILT1 (fread (&cache->average_size, sizeof (cache->average_size), 1, fp)); - -      cache->white_average_data = (uint8_t *) malloc (cache->average_size); -      cache->dark_average_data = (uint8_t *) malloc (cache->average_size); - -      if (!cache->white_average_data || !cache->dark_average_data) -	{ -          status=SANE_STATUS_NO_MEM; -	  FREE_IFNOT_NULL (cache->white_average_data); -	  FREE_IFNOT_NULL (cache->dark_average_data); -	  free (cache); -	  DBG (DBG_error, -	       "sanei_genesys_read_calibration: could not allocate space for average data\n"); -	  break; -	} - -      if (fread (cache->white_average_data, cache->average_size, 1, fp) < 1) -	{ -          status=SANE_STATUS_EOF; -	  DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); -	  free (cache->white_average_data); -	  free (cache->dark_average_data); -	  free (cache); -	  break; -	} -      if (fread (cache->dark_average_data, cache->average_size, 1, fp) < 1) -	{ -	  DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); -	  free (cache->white_average_data); -	  free (cache->dark_average_data); -	  free (cache); -          status=SANE_STATUS_EOF; -	  break; -	} -#undef BILT1 -      DBG (DBG_info, "sanei_genesys_read_calibration: adding record to list\n"); -      cache->next = dev->calibration_cache; -      dev->calibration_cache = cache; -    } - -  fclose (fp); -  DBGCOMPLETED; -  return status; -} - -static void -write_calibration (Genesys_Device * dev) -{ -  FILE *fp; -  uint8_t vers = 0; -  uint32_t size = 0; -  struct Genesys_Calibration_Cache *cache; - -  DBGSTART; -  fp = fopen (dev->calib_file, "wb"); -  if (!fp) -    { -      DBG (DBG_info, "write_calibration: Cannot open %s for writing\n", dev->calib_file); -      return; -    } - -  vers = CALIBRATION_VERSION; -  fwrite (&vers, 1, 1, fp); -  size = sizeof (struct Genesys_Calibration_Cache); -  fwrite (&size, 4, 1, fp); - -  for (cache = dev->calibration_cache; cache; cache = cache->next) -    { -      fwrite (&cache->used_setup, sizeof (cache->used_setup), 1, fp); -      fwrite (&cache->last_calibration, sizeof (cache->last_calibration), 1, fp); -      fwrite (&cache->frontend, sizeof (cache->frontend), 1, fp); -      /* the gamma (and later) fields are not stored */ -      fwrite (&cache->sensor, offsetof (Genesys_Sensor, gamma[0]), 1, fp); - -      fwrite (&cache->calib_pixels, sizeof (cache->calib_pixels), 1, fp); -      fwrite (&cache->calib_channels, sizeof (cache->calib_channels), 1, fp); -      fwrite (&cache->average_size, sizeof (cache->average_size), 1, fp); -      fwrite (cache->white_average_data, cache->average_size, 1, fp); -      fwrite (cache->dark_average_data, cache->average_size, 1, fp); -    } -  DBGCOMPLETED; -  fclose (fp); -} - -/** @brief buffer scanned picture - * In order to allow digital processing, we must be able to put all the - * scanned picture in a buffer. - */ -static SANE_Status -genesys_buffer_image(Genesys_Scanner *s) -{ -  SANE_Status status = SANE_STATUS_GOOD; -  size_t maximum;     /**> maximum bytes size of the scan */ -  size_t len;	      /**> length of scanned data read */ -  size_t total;	      /**> total of butes read */ -  size_t size;	      /**> size of image buffer */ -  size_t read_size;   /**> size of reads */ -  int lines;	      /** number of lines of the scan */ -  Genesys_Device *dev = s->dev; -  SANE_Byte *lineart=NULL; - -  /* compute maximum number of lines for the scan */ -  if (s->params.lines > 0) -    { -      lines = s->params.lines; -    } -  else -    { -      lines = -	(SANE_UNFIX (dev->model->y_size) * dev->settings.yres) / MM_PER_INCH; -    } -  DBG (DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, -       s->params.bytes_per_line); - -  /* maximum bytes to read */ -  maximum = s->params.bytes_per_line * lines; -  if(s->dev->settings.dynamic_lineart==SANE_TRUE) -    { -      maximum *= 8; -    } - -  /* initial size of the read buffer */ -  size = -    ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line; - -  /* read size */ -  read_size = size / 2; - -  /* allocate memory */ -  dev->img_buffer = (SANE_Byte *) malloc (size); -  if (dev->img_buffer == NULL) -    { -      DBG (DBG_error, -	   "%s: digital processing requires too much memory.\nConsider disabling it\n", -	   __func__); -      return SANE_STATUS_NO_MEM; -    } - -  /* loop reading data until we reach maximum or EOF */ -  total = 0; -  while (total < maximum && status != SANE_STATUS_EOF) -    { -      len = size - maximum; -      if (len > read_size) -	{ -	  len = read_size; -	} -      status = genesys_read_ordered_data (dev, dev->img_buffer + total, &len); -      if (status != SANE_STATUS_EOF && status != SANE_STATUS_GOOD) -	{ -	  free (s->dev->img_buffer); -	  DBG (DBG_error, "%s: %s buffering failed\n", __func__, -	       sane_strstatus (status)); -	  return status; -	} -      total += len; - -      /* do we need to enlarge read buffer ? */ -      if (total + read_size > size && status != SANE_STATUS_EOF) -	{ -	  size += read_size; -	  dev->img_buffer = (SANE_Byte *) realloc (dev->img_buffer, size); -	  if (dev->img_buffer == NULL) -	    { -	      DBG (DBG_error0, -		   "%s: digital processing requires too much memory.\nConsider disabling it\n", -		   __func__); -	      return SANE_STATUS_NO_MEM; -	    } -	} -    } - -  /* since digital processing is going to take place, -   * issue head parking command so that the head move while -   * computing so we can save time -   */ -  if (dev->model->is_sheetfed == SANE_FALSE && -      dev->parking == SANE_FALSE) -    { -      dev->model->cmd_set->slow_back_home (dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT); -      dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); -    } - -  /* in case of dynamic lineart, we have buffered gray data which -   * must be converted to lineart first */ -  if(s->dev->settings.dynamic_lineart==SANE_TRUE) -    { -      total/=8; -      lineart=(SANE_Byte *)malloc(total); -      if (lineart == NULL) -        { -          DBG (DBG_error0, -               "%s: digital processing requires too much memory.\nConsider disabling it\n", -               __func__); -          return SANE_STATUS_NO_MEM; -        } -      genesys_gray_lineart (dev, -                            dev->img_buffer, -                            lineart, -                            dev->settings.pixels, -                            (total*8)/dev->settings.pixels, -                            dev->settings.threshold); -      free(dev->img_buffer); -      dev->img_buffer = lineart; -    } - -  /* update counters */ -  dev->total_bytes_to_read = total; -  dev->total_bytes_read = 0; - -  /* update params */ -  s->params.lines = total / s->params.bytes_per_line; -  if (DBG_LEVEL >= DBG_io2) -    { -      sanei_genesys_write_pnm_file ("unprocessed.pnm", -				    dev->img_buffer, -				    s->params.depth, -				    s->params.format==SANE_FRAME_RGB ? 3:1, -				    s->params.pixels_per_line, -				    s->params.lines); -    } - -  return SANE_STATUS_GOOD; -} - -/* -------------------------- SANE API functions ------------------------- */ - -SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) -{ -  SANE_Status status; - -  DBG_INIT (); -  DBG (DBG_init, "SANE Genesys backend version %d.%d build %d from %s\n", -       SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); -#ifdef HAVE_LIBUSB -  DBG (DBG_init, "SANE Genesys backend built with libusb-1.0\n"); -#endif -#ifdef HAVE_LIBUSB_LEGACY -  DBG (DBG_init, "SANE Genesys backend built with libusb\n"); -#endif - -  if (version_code) -    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD); - -  DBG (DBG_proc, "sane_init: authorize %s null\n", authorize ? "!=" : "=="); - -  /* init usb use */ -  sanei_usb_init (); - -  /* init sanei_magic */ -  sanei_magic_init(); - -  DBG (DBG_info, "sane_init: %s endian machine\n", -#ifdef WORDS_BIGENDIAN -       "big" -#else -       "little" -#endif -    ); - -  /* set up to no devices at first */ -  num_devices = 0; -  first_dev = 0; -  first_handle = 0; -  devlist = 0; - -  /* cold-plug case :detection of allready connected scanners */ -  status = probe_genesys_devices (); - -  DBGCOMPLETED; - -  return status; -} - -void -sane_exit (void) -{ -  Genesys_Device *dev, *next; - -  DBGSTART; -  for (dev = first_dev; dev; dev = next) -    { -      /* sane_close() free many fields, not much things left to -       * do here */ -      next = dev->next; -      free (dev->file_name); -      free (dev); -    } -  first_dev = 0; -  first_handle = 0; -  if (devlist) -    free (devlist); -  devlist = 0; - -  sanei_usb_exit(); - -  DBGCOMPLETED; -} - -SANE_Status -sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) -{ -  Genesys_Device *dev, *prev; -  SANE_Int index; -  SANE_Device *sane_device; - -  DBG (DBG_proc, "sane_get_devices: start: local_only = %s\n", -       local_only == SANE_TRUE ? "true" : "false"); - -  /* hot-plug case : detection of newly connected scanners */ -  sanei_usb_scan_devices (); -  probe_genesys_devices (); - -  if (devlist) -    free (devlist); - -  devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); -  if (!devlist) -    return SANE_STATUS_NO_MEM; - -  prev = NULL; -  index = 0; -  dev = first_dev; -  while (dev != NULL) -    { -      /* check if device removed */ -      present = SANE_FALSE; -      sanei_usb_find_devices (dev->vendorId, dev->productId, check_present); -      if (present) -	{ -	  sane_device = malloc (sizeof (*sane_device)); -	  if (!sane_device) -	    return SANE_STATUS_NO_MEM; -	  sane_device->name = dev->file_name; -	  sane_device->vendor = dev->model->vendor; -	  sane_device->model = dev->model->model; -	  sane_device->type = strdup ("flatbed scanner"); -	  devlist[index] = sane_device; -	  index++; -	  prev = dev; -	  dev = dev->next; -	} -      else -	{ -	  /* remove device from internal list */ -	  /* case 1 : removed device is first_dev */ -	  if (prev == NULL) -	    { -	      /* test for another dev */ -	      if (dev->next == NULL) -		{ -		  /* empty the whole list */ -		  free (dev); -		  first_dev = NULL; -		  num_devices = 0; -		  dev = NULL; -		} -	      else -		{ -		  /* assign new start */ -		  first_dev = dev->next; -		  num_devices--; -		  free (dev); -	          dev = first_dev; -		} -	    } -	  /* case 2 : removed device is not first_dev */ -	  else -	    { -	      /* link previous dev to next dev */ -	      prev->next = dev->next; -	      free (dev); -	      num_devices--; - -	      /* next loop */ -	      dev = prev->next; -	    } -	} -    } -  devlist[index] = 0; - -  *device_list = devlist; - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -SANE_Status -sane_open (SANE_String_Const devicename, SANE_Handle * handle) -{ -  Genesys_Device *dev; -  SANE_Status status; -  Genesys_Scanner *s; -  char *tmpstr; - -  DBG (DBG_proc, "sane_open: start (devicename = `%s')\n", devicename); - -  /* devicename="" or devicename="genesys" are default values that use -   * first available device -   */ -  if (devicename[0] && strcmp ("genesys", devicename) != 0) -    { -      /* search for the given devicename in the device list */ -      for (dev = first_dev; dev; dev = dev->next) -	if (strcmp (dev->file_name, devicename) == 0) -	  break; - -      if (!dev) -	{ -	  DBG (DBG_info, -	       "sane_open: couldn't find `%s' in devlist, trying attach\n", -	       devicename); -	  RIE (attach (devicename, &dev, SANE_TRUE)); -	} -      else -	DBG (DBG_info, "sane_open: found `%s' in devlist\n", -	     dev->model->name); -    } -  else -    { -      /* empty devicename or "genesys" -> use first device */ -      dev = first_dev; -      if (dev) -	{ -	  devicename = dev->file_name; -	  DBG (DBG_info, "sane_open: empty devicename, trying `%s'\n", -	       devicename); -	} -    } - -  if (!dev) -    return SANE_STATUS_INVAL; - -  if (dev->model->flags & GENESYS_FLAG_UNTESTED) -    { -      DBG (DBG_error0, -	   "WARNING: Your scanner is not fully supported or at least \n"); -      DBG (DBG_error0, -	   "         had only limited testing. Please be careful and \n"); -      DBG (DBG_error0, "         report any failure/success to \n"); -      DBG (DBG_error0, -	   "         sane-devel@lists.alioth.debian.org. Please provide as many\n"); -      DBG (DBG_error0, -	   "         details as possible, e.g. the exact name of your\n"); -      DBG (DBG_error0, "         scanner and what does (not) work.\n"); -    } - -  status = sanei_usb_open (dev->file_name, &dev->dn); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_warn, "sane_open: couldn't open device `%s': %s\n", -	   dev->file_name, sane_strstatus (status)); -      return status; -    } - - -  s = malloc (sizeof (*s)); -  if (!s) -    return SANE_STATUS_NO_MEM; - -  s->dev = dev; -  s->scanning = SANE_FALSE; -  s->dev->read_buffer.buffer = NULL; -  s->dev->lines_buffer.buffer = NULL; -  s->dev->shrink_buffer.buffer = NULL; -  s->dev->out_buffer.buffer = NULL; -  s->dev->binarize_buffer.buffer = NULL; -  s->dev->local_buffer.buffer = NULL; -  s->dev->parking = SANE_FALSE; -  s->dev->read_active = SANE_FALSE; -  s->dev->white_average_data = NULL; -  s->dev->dark_average_data = NULL; -  s->dev->calibration_cache = NULL; -  s->dev->calib_file = NULL; -  s->dev->img_buffer = NULL; -  s->dev->line_interp = 0; -  s->dev->line_count = 0; -  s->dev->segnb = 0; -  s->dev->oe_buffer.buffer=NULL; -  s->dev->binary=NULL; - -  /* insert newly opened handle into list of open handles: */ -  s->next = first_handle; -  first_handle = s; -  *handle = s; - -  if (!dev->already_initialized) -    sanei_genesys_init_structs (dev); - -  RIE (init_options (s)); - -  if (sanei_genesys_init_cmd_set (s->dev) != SANE_STATUS_GOOD) -    { -      DBG (DBG_error0, "This device doesn't have a valid command set!!\n"); -      return SANE_STATUS_IO_ERROR; -    } - -  RIE (dev->model->cmd_set->init (dev)); - -  /* some hardware capabilities are detected through sensors */ -  RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); - -  /* here is the place to fetch a stored calibration cache */ -  tmpstr=calibration_filename(s->dev); -  s->val[OPT_CALIBRATION_FILE].s = strdup (tmpstr); -  s->dev->calib_file = strdup (tmpstr); -  DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); -  DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); -  free(tmpstr); - -  /* now open file, fetch calibration records */ - -  sanei_genesys_read_calibration (s->dev); - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -void -sane_close (SANE_Handle handle) -{ -  Genesys_Scanner *prev, *s; -  Genesys_Calibration_Cache *cache, *next_cache; -  SANE_Status status; - -  DBGSTART; - -  /* remove handle from list of open handles: */ -  prev = 0; -  for (s = first_handle; s; s = s->next) -    { -      if (s == handle) -	break; -      prev = s; -    } -  if (!s) -    { -      DBG (DBG_error, "sane_close: invalid handle %p\n", handle); -      return;			/* oops, not a handle we know about */ -    } - -  /* eject document for sheetfed scanners */ -  if (s->dev->model->is_sheetfed == SANE_TRUE) -    { -      s->dev->model->cmd_set->eject_document (s->dev); -    } -  else -    { -      /* in case scanner is parking, wait for the head -       * to reach home position */ -      if(s->dev->parking==SANE_TRUE) -        { -          status = sanei_genesys_wait_for_home (s->dev); -          if (status != SANE_STATUS_GOOD) -            { -              DBG (DBG_error, -                   "sane_close: failed to wait for head to park: %s\n", -                   sane_strstatus (status)); -            } -        } -    } - -  /* enable power saving before leaving */ -  status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); -  if (status != SANE_STATUS_GOOD) -    { -      DBG (DBG_error, -           "sane_close: failed to enable power saving mode: %s\n", -           sane_strstatus (status)); -    } - -  /* here is the place to store calibration cache */ -  write_calibration (s->dev); - -  for (cache = s->dev->calibration_cache; cache; cache = next_cache) -    { -      next_cache = cache->next; -      free (cache->dark_average_data); -      free (cache->white_average_data); -      free (cache); -    } - -  sanei_genesys_buffer_free (&(s->dev->read_buffer)); -  sanei_genesys_buffer_free (&(s->dev->lines_buffer)); -  sanei_genesys_buffer_free (&(s->dev->shrink_buffer)); -  sanei_genesys_buffer_free (&(s->dev->out_buffer)); -  sanei_genesys_buffer_free (&(s->dev->binarize_buffer)); -  sanei_genesys_buffer_free (&(s->dev->local_buffer)); -  FREE_IFNOT_NULL (s->dev->white_average_data); -  FREE_IFNOT_NULL (s->dev->dark_average_data); -  FREE_IFNOT_NULL (s->dev->calib_file); - -  /* free allocated gamma tables */ -  FREE_IFNOT_NULL (s->dev->sensor.gamma_table[0]); -  FREE_IFNOT_NULL (s->dev->sensor.gamma_table[1]); -  FREE_IFNOT_NULL (s->dev->sensor.gamma_table[2]); - -  s->dev->already_initialized = SANE_FALSE; - -   /* for an handful of bytes .. */ -  free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); -  free (s->val[OPT_SOURCE].s); -  free (s->val[OPT_MODE].s); -  free (s->val[OPT_COLOR_FILTER].s); -  free ((void *)(size_t)s->opt[OPT_TL_X].constraint.range); -  free ((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); - -  if (prev) -    prev->next = s->next; -  else -    first_handle = s->next; - -  /* LAMP OFF : same register across all the ASICs */ -  sanei_genesys_write_register (s->dev, 0x03, 0x00); - -  /* clear before closing */ -  sanei_usb_clear_halt (s->dev->dn); - -  /* we need this to avoid these ASIC getting stuck -   * in bulk writes */ -  sanei_usb_reset (s->dev->dn); - -  sanei_usb_close (s->dev->dn); -  free (s); - -  DBGCOMPLETED; -} - -const SANE_Option_Descriptor * -sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) -{ -  Genesys_Scanner *s = handle; - -  if ((unsigned) option >= NUM_OPTIONS) -    return 0; -  DBG (DBG_io2, "sane_get_option_descriptor: option = %s (%d)\n", -       s->opt[option].name, option); -  return s->opt + option; -} - -/* gets an option , called by sane_control_option */ -static SANE_Status -get_option_value (Genesys_Scanner * s, int option, void *val) -{ -  unsigned int i; -  SANE_Word *table ,tmp; -  uint16_t *gamma; -  SANE_Status status = SANE_STATUS_GOOD; -  Genesys_Calibration_Cache *cache; - -  switch (option) -    { -      /* geometry */ -    case OPT_TL_X: -    case OPT_TL_Y: -    case OPT_BR_X: -    case OPT_BR_Y: -      *(SANE_Word *) val = s->val[option].w; -      /* switch coordinate to keep them coherent */ -      if (s->val[OPT_TL_X].w >= s->val[OPT_BR_X].w) -        { -          tmp=s->val[OPT_BR_X].w; -          s->val[OPT_BR_X].w=s->val[OPT_TL_X].w; -          s->val[OPT_TL_X].w=tmp; -        } -      if (s->val[OPT_TL_Y].w >= s->val[OPT_BR_Y].w) -        { -          tmp=s->val[OPT_BR_Y].w; -          s->val[OPT_BR_Y].w=s->val[OPT_TL_Y].w; -          s->val[OPT_TL_Y].w=tmp; -        } -      break; -      /* word options: */ -    case OPT_NUM_OPTS: -    case OPT_RESOLUTION: -    case OPT_BIT_DEPTH: -    case OPT_PREVIEW: -    case OPT_THRESHOLD: -    case OPT_THRESHOLD_CURVE: -    case OPT_DISABLE_DYNAMIC_LINEART: -    case OPT_DISABLE_INTERPOLATION: -    case OPT_LAMP_OFF: -    case OPT_LAMP_OFF_TIME: -    case OPT_SWDESKEW: -    case OPT_SWCROP: -    case OPT_SWDESPECK: -    case OPT_SWDEROTATE: -    case OPT_SWSKIP: -    case OPT_DESPECK: -    case OPT_CONTRAST: -    case OPT_BRIGHTNESS: -    case OPT_EXPIRATION_TIME: -      *(SANE_Word *) val = s->val[option].w; -      break; -    case OPT_CUSTOM_GAMMA: -      *(SANE_Word *) val = s->val[option].w; -      break; - -      /* string options: */ -    case OPT_MODE: -    case OPT_COLOR_FILTER: -    case OPT_CALIBRATION_FILE: -    case OPT_SOURCE: -      strcpy (val, s->val[option].s); -      break; - -      /* word array options */ -    case OPT_GAMMA_VECTOR: -      table = (SANE_Word *) val; -      if (strcmp (s->val[OPT_COLOR_FILTER].s, "Red") == 0) -	{ -	  gamma = s->dev->sensor.gamma_table[GENESYS_RED]; -	} -      else if (strcmp (s->val[OPT_COLOR_FILTER].s, "Blue") == 0) -	{ -	  gamma = s->dev->sensor.gamma_table[GENESYS_BLUE]; -	} -      else -	{ -	  gamma = s->dev->sensor.gamma_table[GENESYS_GREEN]; -	} -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  table[i] = gamma[i]; -	} -      break; -    case OPT_GAMMA_VECTOR_R: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  table[i] = s->dev->sensor.gamma_table[GENESYS_RED][i]; -	} -      break; -    case OPT_GAMMA_VECTOR_G: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  table[i] = s->dev->sensor.gamma_table[GENESYS_GREEN][i]; -	} -      break; -    case OPT_GAMMA_VECTOR_B: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  table[i] = s->dev->sensor.gamma_table[GENESYS_BLUE][i]; -	} -      break; -      /* sensors */ -    case OPT_SCAN_SW: -    case OPT_FILE_SW: -    case OPT_EMAIL_SW: -    case OPT_COPY_SW: -    case OPT_PAGE_LOADED_SW: -    case OPT_OCR_SW: -    case OPT_POWER_SW: -    case OPT_EXTRA_SW: -      RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); -      *(SANE_Bool *) val = s->val[option].b; -      s->last_val[option].b = *(SANE_Bool *) val; -      break; -    case OPT_NEED_CALIBRATION_SW: -      /* scanner needs calibration for current mode unless a matching -       * calibration cache is found */ -      *(SANE_Bool *) val = SANE_TRUE; -      for (cache = s->dev->calibration_cache; cache; cache = cache->next) -	{ -	  if (s->dev->model-> -	      cmd_set->is_compatible_calibration (s->dev, cache, SANE_FALSE) == SANE_STATUS_GOOD) -	    { -	      *(SANE_Bool *) val = SANE_FALSE; -	    } -	} -      break; -    default: -      DBG (DBG_warn, "get_option_value: can't get unknown option %d\n", -	   option); -    } -  return status; -} - -/** @brief set calibration file value - * Set calibration file value. Load new cache values from file if it exists, - * else creates the file*/ -static SANE_Status set_calibration_value (Genesys_Scanner * s, int option, void *val) -{ -  SANE_Status status=SANE_STATUS_GOOD; -  char *tmp; -  Genesys_Device *dev=s->dev; - -  DBGSTART; - -  /* try to load file */ -  tmp=dev->calib_file; -  dev->calib_file=val; -  status=sanei_genesys_read_calibration (dev); - -  /* file exists but is invalid, so fall back to previous cache file -   * an re-read it */ -  if (status!=SANE_STATUS_IO_ERROR && status!=SANE_STATUS_GOOD) -    { -      dev->calib_file=tmp; -      status=sanei_genesys_read_calibration (dev); -      return status; -    } - -  /* now we can set file name value */ -  if (s->val[option].s) -    free (s->val[option].s); -  s->val[option].s = strdup (val); -  if (tmp) -    free (tmp); -  dev->calib_file = strdup (val); -  DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); -  DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); - -  DBGCOMPLETED; -  return SANE_STATUS_GOOD; -} - -/* sets an option , called by sane_control_option */ -static SANE_Status -set_option_value (Genesys_Scanner * s, int option, void *val, -		  SANE_Int * myinfo) -{ -  SANE_Status status = SANE_STATUS_GOOD; -  SANE_Word *table; -  unsigned int i; -  SANE_Range *x_range, *y_range; -  Genesys_Calibration_Cache *cache, *next_cache; - -  switch (option) -    { -    case OPT_TL_X: -    case OPT_TL_Y: -    case OPT_BR_X: -    case OPT_BR_Y: -      s->val[option].w = *(SANE_Word *) val; -      RIE (calc_parameters (s)); -      *myinfo |= SANE_INFO_RELOAD_PARAMS; -      break; -    case OPT_RESOLUTION: -    case OPT_THRESHOLD: -    case OPT_THRESHOLD_CURVE: -    case OPT_DISABLE_DYNAMIC_LINEART: -    case OPT_SWCROP: -    case OPT_SWDESKEW: -    case OPT_DESPECK: -    case OPT_SWDEROTATE: -    case OPT_SWSKIP: -    case OPT_DISABLE_INTERPOLATION: -    case OPT_LAMP_OFF: -    case OPT_PREVIEW: -    case OPT_BRIGHTNESS: -    case OPT_CONTRAST: -      s->val[option].w = *(SANE_Word *) val; -      RIE (calc_parameters (s)); -      *myinfo |= SANE_INFO_RELOAD_PARAMS; -      break; -    case OPT_SWDESPECK: -      s->val[option].w = *(SANE_Word *) val; -      if (s->val[OPT_SWDESPECK].b == SANE_TRUE) -	{ -          ENABLE(OPT_DESPECK); -        } -      else -        { -          DISABLE(OPT_DESPECK); -        } -      RIE (calc_parameters (s)); -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      break; -    /* software enhancement functions only apply to 8 or 1 bits data */ -    case OPT_BIT_DEPTH: -      s->val[option].w = *(SANE_Word *) val; -      if(s->val[OPT_BIT_DEPTH].w>8) -        { -          DISABLE(OPT_SWDESKEW); -          DISABLE(OPT_SWDESPECK); -          DISABLE(OPT_SWCROP); -          DISABLE(OPT_DESPECK); -          DISABLE(OPT_SWDEROTATE); -          DISABLE(OPT_SWSKIP); -          DISABLE(OPT_CONTRAST); -          DISABLE(OPT_BRIGHTNESS); -        } -      else -        { -          ENABLE(OPT_SWDESKEW); -          ENABLE(OPT_SWDESPECK); -          ENABLE(OPT_SWCROP); -          ENABLE(OPT_DESPECK); -          ENABLE(OPT_SWDEROTATE); -          ENABLE(OPT_SWSKIP); -          ENABLE(OPT_CONTRAST); -          ENABLE(OPT_BRIGHTNESS); -        } -      RIE (calc_parameters (s)); -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      break; -    case OPT_SOURCE: -      if (strcmp (s->val[option].s, val) != 0) -	{			/* something changed */ -	  if (s->val[option].s) -	    free (s->val[option].s); -	  s->val[option].s = strdup (val); - -          /* change geometry constraint to the new source value */ -          if (strcmp (s->val[option].s, FLATBED) == 0) -            { -              x_range=create_range(s->dev->model->x_size); -              y_range=create_range(s->dev->model->y_size); -            } -          else -            { -              x_range=create_range(s->dev->model->x_size_ta); -              y_range=create_range(s->dev->model->y_size_ta); -            } -          if(x_range==NULL || y_range==NULL) -            { -              return SANE_STATUS_NO_MEM; -            } - -          /* assign new values */ -          free((void *)(size_t)s->opt[OPT_TL_X].constraint.range); -          free((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); -          s->opt[OPT_TL_X].constraint.range = x_range; -          s->val[OPT_TL_X].w = 0; -          s->opt[OPT_TL_Y].constraint.range = y_range; -          s->val[OPT_TL_Y].w = 0; -          s->opt[OPT_BR_X].constraint.range = x_range; -          s->val[OPT_BR_Y].w = y_range->max; -          s->opt[OPT_BR_Y].constraint.range = y_range; -          s->val[OPT_BR_X].w = x_range->max; - -          /* signals reload */ -	  *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -	} -      break; -    case OPT_MODE: -      if (s->val[option].s) -	free (s->val[option].s); -      s->val[option].s = strdup (val); - -      if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) == 0) -	{ -	  ENABLE (OPT_THRESHOLD); -	  ENABLE (OPT_THRESHOLD_CURVE); -	  DISABLE (OPT_BIT_DEPTH); -          if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) -            { -	      ENABLE (OPT_COLOR_FILTER); -            } -	  ENABLE (OPT_DISABLE_DYNAMIC_LINEART); -	} -      else -	{ -	  DISABLE (OPT_THRESHOLD); -	  DISABLE (OPT_THRESHOLD_CURVE); -	  DISABLE (OPT_DISABLE_DYNAMIC_LINEART); -	  if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) -	    { -              if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) -                { -	          ENABLE (OPT_COLOR_FILTER); -                } -	      create_bpp_list (s, s->dev->model->bpp_gray_values); -	    } -	  else -	    { -	      DISABLE (OPT_COLOR_FILTER); -	      create_bpp_list (s, s->dev->model->bpp_color_values); -	    } -	  if (s->bpp_list[0] < 2) -	    DISABLE (OPT_BIT_DEPTH); -	  else -	    ENABLE (OPT_BIT_DEPTH); -	} -      RIE (calc_parameters (s)); - -      /* if custom gamma, toggle gamma table options according to the mode */ -      if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE) -	{ -	  if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) -	    { -	      DISABLE (OPT_GAMMA_VECTOR); -	      ENABLE (OPT_GAMMA_VECTOR_R); -	      ENABLE (OPT_GAMMA_VECTOR_G); -	      ENABLE (OPT_GAMMA_VECTOR_B); -	    } -	  else -	    { -	      ENABLE (OPT_GAMMA_VECTOR); -	      DISABLE (OPT_GAMMA_VECTOR_R); -	      DISABLE (OPT_GAMMA_VECTOR_G); -	      DISABLE (OPT_GAMMA_VECTOR_B); -	    } -	} - -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      break; -    case OPT_COLOR_FILTER: -      if (s->val[option].s) -	free (s->val[option].s); -      s->val[option].s = strdup (val); -      RIE (calc_parameters (s)); -      break; -    case OPT_CALIBRATION_FILE: -      RIE(set_calibration_value (s, option, val)); -      break; -    case OPT_LAMP_OFF_TIME: -    case OPT_EXPIRATION_TIME: -      if (*(SANE_Word *) val != s->val[option].w) -	{ -	  s->val[option].w = *(SANE_Word *) val; -	  RIE (s->dev->model->cmd_set-> -	       set_powersaving (s->dev, s->val[option].w)); -	} -      break; - -    case OPT_CUSTOM_GAMMA: -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      s->val[OPT_CUSTOM_GAMMA].b = *(SANE_Bool *) val; - -      if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE) -	{ -	  if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) -	    { -	      DISABLE (OPT_GAMMA_VECTOR); -	      ENABLE (OPT_GAMMA_VECTOR_R); -	      ENABLE (OPT_GAMMA_VECTOR_G); -	      ENABLE (OPT_GAMMA_VECTOR_B); -	    } -	  else -	    { -	      ENABLE (OPT_GAMMA_VECTOR); -	      DISABLE (OPT_GAMMA_VECTOR_R); -	      DISABLE (OPT_GAMMA_VECTOR_G); -	      DISABLE (OPT_GAMMA_VECTOR_B); -	    } -	} -      else -	{ -	  DISABLE (OPT_GAMMA_VECTOR); -	  DISABLE (OPT_GAMMA_VECTOR_R); -	  DISABLE (OPT_GAMMA_VECTOR_G); -	  DISABLE (OPT_GAMMA_VECTOR_B); -	  /* restore default sensor gamma table */ -	  /* currently there is no sensor's specific gamma table, -	   * tables are built by sanei_genesys_create_gamma_table */ -	  sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_RED], -					    s->opt[OPT_GAMMA_VECTOR_R].size / sizeof (SANE_Word), -					    s->opt[OPT_GAMMA_VECTOR_R].constraint.range->max, -					    s->opt[OPT_GAMMA_VECTOR_R].constraint.range->max, -					    s->dev->sensor.gamma[GENESYS_RED]); -	  sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_GREEN], -					    s->opt[OPT_GAMMA_VECTOR_G].size / sizeof (SANE_Word), -					    s->opt[OPT_GAMMA_VECTOR_G].constraint.range->max, -					    s->opt[OPT_GAMMA_VECTOR_G].constraint.range->max, -					    s->dev->sensor.gamma[GENESYS_GREEN]); -	  sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_BLUE], -					    s->opt[OPT_GAMMA_VECTOR_B].size / sizeof (SANE_Word), -					    s->opt[OPT_GAMMA_VECTOR_B].constraint.range->max, -					    s->opt[OPT_GAMMA_VECTOR_B].constraint.range->max, -					    s->dev->sensor.gamma[GENESYS_BLUE]); -	} -      break; - -    case OPT_GAMMA_VECTOR: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  s->dev->sensor.gamma_table[GENESYS_RED][i] = table[i]; -	  s->dev->sensor.gamma_table[GENESYS_GREEN][i] = table[i]; -	  s->dev->sensor.gamma_table[GENESYS_BLUE][i] = table[i]; -	} -      break; -    case OPT_GAMMA_VECTOR_R: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  s->dev->sensor.gamma_table[GENESYS_RED][i] = table[i]; -	} -      break; -    case OPT_GAMMA_VECTOR_G: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  s->dev->sensor.gamma_table[GENESYS_GREEN][i] = table[i]; -	} -      break; -    case OPT_GAMMA_VECTOR_B: -      table = (SANE_Word *) val; -      for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) -	{ -	  s->dev->sensor.gamma_table[GENESYS_BLUE][i] = table[i]; -	} -      break; -    case OPT_CALIBRATE: -      status = s->dev->model->cmd_set->save_power (s->dev, SANE_FALSE); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, -	       "%s: failed to disable power saving mode: %s\n", -	       __func__, sane_strstatus (status)); -	} -      else -	status = genesys_scanner_calibration (s->dev); -      /* not critical if this fails*/ -      s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); -      /* signals that sensors will have to be read again */ -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      break; -    case OPT_CLEAR_CALIBRATION: -      /* clear calibration cache */ -      if (s->dev->calibration_cache != NULL) -	{ -	  for (cache = s->dev->calibration_cache; cache; cache = next_cache) -	    { -	      next_cache = cache->next; -	      free (cache->dark_average_data); -	      free (cache->white_average_data); -	      free (cache); -	    } -	} -      s->dev->calibration_cache = NULL; -      /* remove file */ -      unlink (s->dev->calib_file); -      /* signals that sensors will have to be read again */ -      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; -      break; - -    default: -      DBG (DBG_warn, "set_option_value: can't set unknown option %d\n", -	   option); -    } -  return status; -} - - -/* sets and gets scanner option values */ -SANE_Status -sane_control_option (SANE_Handle handle, SANE_Int option, -		     SANE_Action action, void *val, SANE_Int * info) -{ -  Genesys_Scanner *s = handle; -  SANE_Status status = SANE_STATUS_GOOD; -  SANE_Word cap; -  SANE_Int myinfo = 0; - -  DBG (DBG_io2, -       "sane_control_option: start: action = %s, option = %s (%d)\n", -       (action == SANE_ACTION_GET_VALUE) ? "get" : (action == -						    SANE_ACTION_SET_VALUE) ? -       "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown", -       s->opt[option].name, option); - -  if (info) -    *info = 0; - -  if (s->scanning) -    { -      DBG (DBG_warn, "sane_control_option: don't call this function while " -	   "scanning (option = %s (%d))\n", s->opt[option].name, option); - -      return SANE_STATUS_DEVICE_BUSY; -    } -  if (option >= NUM_OPTIONS || option < 0) -    { -      DBG (DBG_warn, -	   "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n", -	   option); -      return SANE_STATUS_INVAL; -    } - -  cap = s->opt[option].cap; - -  if (!SANE_OPTION_IS_ACTIVE (cap)) -    { -      DBG (DBG_warn, "sane_control_option: option %d is inactive\n", option); -      return SANE_STATUS_INVAL; -    } - -  switch (action) -    { -    case SANE_ACTION_GET_VALUE: -      status = get_option_value (s, option, val); -      break; - -    case SANE_ACTION_SET_VALUE: -      if (!SANE_OPTION_IS_SETTABLE (cap)) -	{ -	  DBG (DBG_warn, "sane_control_option: option %d is not settable\n", -	       option); -	  return SANE_STATUS_INVAL; -	} - -      status = sanei_constrain_value (s->opt + option, val, &myinfo); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_warn, -	       "sane_control_option: sanei_constrain_value returned %s\n", -	       sane_strstatus (status)); -	  return status; -	} - -      status = set_option_value (s, option, val, &myinfo); -      break; - -    case SANE_ACTION_SET_AUTO: -      DBG (DBG_error, -	   "sane_control_option: SANE_ACTION_SET_AUTO unsupported since no option has SANE_CAP_AUTOMATIC\n"); -      status = SANE_STATUS_INVAL; -      break; - -    default: -      DBG (DBG_warn, "sane_control_option: unknown action %d for option %d\n", -	   action, option); -      status = SANE_STATUS_INVAL; -      break; -    } - -  if (info) -    *info = myinfo; - -  DBG (DBG_io2, "sane_control_option: exit\n"); -  return status; -} - - - -SANE_Status -sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) -{ -  Genesys_Scanner *s = handle; -  SANE_Status status; - -  DBGSTART; - -  /* don't recompute parameters once data reading is active, ie during scan */ -  if(s->dev->read_active == SANE_FALSE) -    { -      RIE (calc_parameters (s)); -    } -  if (params) -    { -      *params = s->params; - -      /* in the case of a sheetfed scanner, when full height is specified -       * we override the computed line number with -1 to signal that we -       * don't know the real document height. -       * We don't do that doing buffering image for digital processing -       */ -      if (s->dev->model->is_sheetfed == SANE_TRUE -          && s->dev->buffer_image == SANE_FALSE -	  && s->val[OPT_BR_Y].w == s->opt[OPT_BR_Y].constraint.range->max) -	{ -	  params->lines = -1; -	} -    } - -  DBGCOMPLETED; - -  return SANE_STATUS_GOOD; -} - -SANE_Status -sane_start (SANE_Handle handle) -{ -  Genesys_Scanner *s = handle; -  SANE_Status status=SANE_STATUS_GOOD; - -  DBGSTART; - -  if (s->val[OPT_TL_X].w >= s->val[OPT_BR_X].w) -    { -      DBG (DBG_error0, -	   "sane_start: top left x >= bottom right x --- exiting\n"); -      return SANE_STATUS_INVAL; -    } -  if (s->val[OPT_TL_Y].w >= s->val[OPT_BR_Y].w) -    { -      DBG (DBG_error0, -	   "sane_start: top left y >= bottom right y --- exiting\n"); -      return SANE_STATUS_INVAL; -    } - -  /* First make sure we have a current parameter set.  Some of the -     parameters will be overwritten below, but that's OK.  */ - -  RIE (calc_parameters (s)); -  RIE (genesys_start_scan (s->dev, s->val[OPT_LAMP_OFF].w)); - -  s->scanning = SANE_TRUE; - -  /* allocate intermediate buffer when doing dynamic lineart */ -  if(s->dev->settings.dynamic_lineart==SANE_TRUE) -    { -      RIE (sanei_genesys_buffer_free (&(s->dev->binarize_buffer))); -      RIE (sanei_genesys_buffer_alloc (&(s->dev->binarize_buffer), s->dev->settings.pixels)); -      RIE (sanei_genesys_buffer_free (&(s->dev->local_buffer))); -      RIE (sanei_genesys_buffer_alloc (&(s->dev->local_buffer), s->dev->binarize_buffer.size * 8)); -    } - -  /* if one of the software enhancement option is selected, -   * we do the scan internally, process picture then put it an internal -   * buffer. Since cropping may change scan parameters, we recompute them -   * at the end */ -  if (s->dev->buffer_image) -    { -      RIE(genesys_buffer_image(s)); - -      /* check if we need to skip this page, sheetfed scanners -       * can go to next doc while flatbed ones can't */ -      if (s->val[OPT_SWSKIP].w && IS_ACTIVE(OPT_SWSKIP)) -        { -          status = sanei_magic_isBlank(&s->params, -				       s->dev->img_buffer, -                                       SANE_UNFIX(s->val[OPT_SWSKIP].w)); -          if(status == SANE_STATUS_NO_DOCS) -            { -              if (s->dev->model->is_sheetfed == SANE_TRUE) -                { -                  DBG (DBG_info, "sane_start: blank page, recurse\n"); -                  return sane_start(handle); -                } -              return status; -            } -        } - -      /* deskew image if required */ -      if(s->val[OPT_SWDESKEW].b == SANE_TRUE) -        { -          RIE(genesys_deskew(s)); -        } - -      /* despeck image if required */ -      if(s->val[OPT_SWDESPECK].b == SANE_TRUE) -        { -          RIE(genesys_despeck(s)); -        } - -      /* crop image if required */ -      if(s->val[OPT_SWCROP].b == SANE_TRUE) -        { -          RIE(genesys_crop(s)); -        } - -      /* de-rotate image if required */ -      if(s->val[OPT_SWDEROTATE].b == SANE_TRUE) -        { -          RIE(genesys_derotate(s)); -        } -    } - -  DBGCOMPLETED; -  return status; -} - -SANE_Status -sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, -	   SANE_Int * len) -{ -  Genesys_Scanner *s = handle; -  Genesys_Device *dev; -  SANE_Status status=SANE_STATUS_GOOD; -  size_t local_len; - -  if (!s) -    { -      DBG (DBG_error, "sane_read: handle is null!\n"); -      return SANE_STATUS_INVAL; -    } - -  dev=s->dev; -  if (!dev) -    { -      DBG (DBG_error, "sane_read: dev is null!\n"); -      return SANE_STATUS_INVAL; -    } - -  if (!buf) -    { -      DBG (DBG_error, "sane_read: buf is null!\n"); -      return SANE_STATUS_INVAL; -    } - -  if (!len) -    { -      DBG (DBG_error, "sane_read: len is null!\n"); -      return SANE_STATUS_INVAL; -    } - -  *len = 0; - -  if (!s->scanning) -    { -      DBG (DBG_warn, "sane_read: scan was cancelled, is over or has not been " -	   "initiated yet\n"); -      return SANE_STATUS_CANCELLED; -    } - -  DBG (DBG_proc, "sane_read: start, %d maximum bytes required\n", max_len); -  DBG (DBG_io2, "sane_read: bytes_to_read=%lu, total_bytes_read=%lu\n", -       (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); -  DBG (DBG_io2, "sane_read: physical bytes to read = %lu\n", (u_long) dev->read_bytes_left); - -  if(dev->total_bytes_read>=dev->total_bytes_to_read) -    { -      DBG (DBG_proc, "sane_read: nothing more to scan: EOF\n"); - -      /* issue park command immediatly in case scanner can handle it -       * so we save time */ -      if (dev->model->is_sheetfed == SANE_FALSE -       && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) -       && dev->parking == SANE_FALSE) -        { -          dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); -          dev->parking = SANE_TRUE; -        } -      return SANE_STATUS_EOF; -    } - -  local_len = max_len; - -  /* in case of image processing, all data has been stored in -   * buffer_image. So read data from it if it exists, else from scanner */ -  if(!dev->buffer_image) -    { -      /* dynamic lineart is another kind of digital processing that needs -       * another layer of buffering on top of genesys_read_ordered_data */ -      if(dev->settings.dynamic_lineart==SANE_TRUE) -        { -          /* if buffer is empty, fill it with genesys_read_ordered_data */ -          if(dev->binarize_buffer.avail==0) -            { -              /* store gray data */ -              local_len=dev->local_buffer.size; -              status = genesys_read_ordered_data (dev, dev->local_buffer.buffer, &local_len); - -              /* binarize data is read successful */ -              if(status==SANE_STATUS_GOOD) -                { -                  dev->local_buffer.avail=local_len; -                  dev->local_buffer.pos=0; -                  dev->binarize_buffer.avail=local_len/8; -                  dev->binarize_buffer.pos=0; -                  genesys_gray_lineart (dev, -                                        dev->local_buffer.buffer, -                                        dev->binarize_buffer.buffer, -                                        dev->settings.pixels, -                                        local_len/dev->settings.pixels, -                                        dev->settings.threshold); -                } - -            } - -          /* return data from lineart buffer if any, up to the available amount */ -          local_len = max_len; -          if((size_t)max_len>dev->binarize_buffer.avail) -            { -              local_len=dev->binarize_buffer.avail; -            } -          if(local_len) -            { -              memcpy(buf,sanei_genesys_buffer_get_read_pos (&(dev->binarize_buffer)),local_len); -	      RIE (sanei_genesys_buffer_consume (&(dev->binarize_buffer), local_len)); -            } -        } -      else -        { -          /* most usual case, direct read of data from scanner */ -          status = genesys_read_ordered_data (dev, buf, &local_len); -        } -    } -  else /* read data from buffer */ -    { -      if(dev->total_bytes_read+local_len>dev->total_bytes_to_read) -        { -          local_len=dev->total_bytes_to_read-dev->total_bytes_read; -        } -      memcpy(buf,dev->img_buffer+dev->total_bytes_read,local_len); -      dev->total_bytes_read+=local_len; -    } - -  *len = local_len; -  if(local_len>(size_t)max_len) -    { -      fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n"); -    } -  DBG (DBG_proc, "sane_read: %d bytes returned\n", *len); -  return status; -} - -void -sane_cancel (SANE_Handle handle) -{ -  Genesys_Scanner *s = handle; -  SANE_Status status = SANE_STATUS_GOOD; - -  DBGSTART; - -  /* end binary logging if needed */ -  if (s->dev->binary!=NULL) -    { -      fclose(s->dev->binary); -      s->dev->binary=NULL; -    } - -  s->scanning = SANE_FALSE; -  s->dev->read_active = SANE_FALSE; -  if(s->dev->img_buffer!=NULL) -    { -      free(s->dev->img_buffer); -      s->dev->img_buffer=NULL; -    } - -  /* no need to end scan if we are parking the head */ -  if(s->dev->parking==SANE_FALSE) -    { -      status = s->dev->model->cmd_set->end_scan (s->dev, s->dev->reg, SANE_TRUE); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, "sane_cancel: failed to end scan: %s\n", -               sane_strstatus (status)); -          return; -        } -    } - -  /* park head if flatbed scanner */ -  if (s->dev->model->is_sheetfed == SANE_FALSE) -    { -      if(s->dev->parking==SANE_FALSE) -        { -          status = s->dev->model->cmd_set->slow_back_home (s->dev, s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); -          if (status != SANE_STATUS_GOOD) -            { -              DBG (DBG_error, -                   "sane_cancel: failed to move scanhead to home position: %s\n", -                   sane_strstatus (status)); -              return; -            } -          s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); -        } -    } -  else -    {				/* in case of sheetfed scanners, we have to eject the document if still present */ -      status = s->dev->model->cmd_set->eject_document (s->dev); -      if (status != SANE_STATUS_GOOD) -	{ -	  DBG (DBG_error, "sane_cancel: failed to eject document: %s\n", -	       sane_strstatus (status)); -	  return; -	} -    } - -  /* enable power saving mode unless we are parking .... */ -  if(s->dev->parking==SANE_FALSE) -    { -      status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); -      if (status != SANE_STATUS_GOOD) -        { -          DBG (DBG_error, "sane_cancel: failed to enable power saving mode: %s\n", -               sane_strstatus (status)); -          return; -        } -    } - -  DBGCOMPLETED; -  return; -} - -SANE_Status -sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) -{ -  Genesys_Scanner *s = handle; - -  DBG (DBG_proc, "sane_set_io_mode: handle = %p, non_blocking = %s\n", -       handle, non_blocking == SANE_TRUE ? "true" : "false"); - -  if (!s->scanning) -    { -      DBG (DBG_error, "sane_set_io_mode: not scanning\n"); -      return SANE_STATUS_INVAL; -    } -  if (non_blocking) -    return SANE_STATUS_UNSUPPORTED; -  return SANE_STATUS_GOOD; -} - -SANE_Status -sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) -{ -  Genesys_Scanner *s = handle; - -  DBG (DBG_proc, "sane_get_select_fd: handle = %p, fd = %p\n", handle, -       (void *) fd); - -  if (!s->scanning) -    { -      DBG (DBG_error, "sane_get_select_fd: not scanning\n"); -      return SANE_STATUS_INVAL; -    } -  return SANE_STATUS_UNSUPPORTED; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */  | 
