kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			4569 wiersze
		
	
	
		
			124 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			4569 wiersze
		
	
	
		
			124 KiB
		
	
	
	
		
			C
		
	
	
/* sane - Scanner Access Now Easy.
 | 
						|
   Copyright (C) 2002 Michael Herder <crapsite@gmx.net>
 | 
						|
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
This backend is based on the "gt68xxtest" program written by the following
 | 
						|
persons:
 | 
						|
  Sergey Vlasov <vsu@mivlgu.murom.ru>
 | 
						|
    - Main backend code.
 | 
						|
 | 
						|
  Andreas Nowack <nowack.andreas@gmx.de>
 | 
						|
    - Support for GT6801 (Mustek ScanExpress 1200 UB Plus).
 | 
						|
 | 
						|
  David Stevenson <david.stevenson@zoom.co.uk>
 | 
						|
    - Automatic AFE gain and offset setting.
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
Please note:
 | 
						|
The calibration code from the gt68xxtest program isn't used here, since I
 | 
						|
couldn't get it working. I'm using my own calibration code, which is based
 | 
						|
on wild assumptions based on the USB logs from the windoze driver.
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
It also contains code from the plustek backend
 | 
						|
 | 
						|
Copyright (C) 2000-2002 Gerhard Jaeger <g.jaeger@earthling.net>
 | 
						|
 | 
						|
and from the mustek_usb backend
 | 
						|
 | 
						|
Copyright (C) 2000 Mustek.
 | 
						|
Maintained by Tom Wang <tom.wang@mustek.com.tw>
 | 
						|
Updates (C) 2001 by Henning Meier-Geinitz.
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
						|
 | 
						|
   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.  */
 | 
						|
 | 
						|
#define BUILD 11
 | 
						|
 | 
						|
#include "../include/sane/config.h"
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <time.h>
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include <sys/time.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
 | 
						|
 | 
						|
#include "../include/sane/sane.h"
 | 
						|
#include "../include/sane/sanei.h"
 | 
						|
#include "../include/sane/saneopts.h"
 | 
						|
 | 
						|
#define BACKEND_NAME artec_eplus48u
 | 
						|
#include "sane/sanei_backend.h"
 | 
						|
#include "sane/sanei_config.h"
 | 
						|
 | 
						|
#include "artec_eplus48u.h"
 | 
						|
 | 
						|
#ifndef PATH_MAX
 | 
						|
# define PATH_MAX	1024
 | 
						|
#endif
 | 
						|
 | 
						|
#define _DEFAULT_DEVICE "/dev/usbscanner"
 | 
						|
#define ARTEC48U_CONFIG_FILE "artec_eplus48u.conf"
 | 
						|
 | 
						|
#define _SHADING_FILE_BLACK "artec48ushading_black"
 | 
						|
#define _SHADING_FILE_WHITE "artec48ushading_white"
 | 
						|
#define _EXPOSURE_FILE      "artec48uexposure"
 | 
						|
#define _OFFSET_FILE        "artec48uoffset"
 | 
						|
 | 
						|
#define _BYTE      3
 | 
						|
#define _STRING    2
 | 
						|
#define _FLOAT     1
 | 
						|
#define _INT       0
 | 
						|
 | 
						|
/*for calibration*/
 | 
						|
#define WHITE_MIN 243*257
 | 
						|
#define WHITE_MAX 253*257
 | 
						|
#define BLACK_MIN 8*257
 | 
						|
#define BLACK_MAX 18*257
 | 
						|
#define EXPOSURE_STEP 280
 | 
						|
 | 
						|
static Artec48U_Device *first_dev = 0;
 | 
						|
static Artec48U_Scanner *first_handle = 0;
 | 
						|
static SANE_Int num_devices = 0;
 | 
						|
static char devName[PATH_MAX];
 | 
						|
static char firmwarePath[PATH_MAX];
 | 
						|
static char vendor_string[PATH_MAX];
 | 
						|
static char model_string[PATH_MAX];
 | 
						|
 | 
						|
static SANE_Bool cancelRead;
 | 
						|
static int isEPro;
 | 
						|
static int eProMult;
 | 
						|
static SANE_Auth_Callback auth = NULL;
 | 
						|
static double gamma_master_default = 1.7;
 | 
						|
static double gamma_r_default = 1.0;
 | 
						|
static double gamma_g_default = 1.0;
 | 
						|
static double gamma_b_default = 1.0;
 | 
						|
 | 
						|
static SANE_Word memory_read_value = 0x200c;	/**< Memory read - wValue */
 | 
						|
static SANE_Word memory_write_value = 0x200b;	/**< Memory write - wValue */
 | 
						|
static SANE_Word send_cmd_value = 0x2010;	/**< Send normal command - wValue */
 | 
						|
static SANE_Word send_cmd_index = 0x3f40;	/**< Send normal command - wIndex */
 | 
						|
static SANE_Word recv_res_value = 0x2011;	/**< Receive normal result - wValue */
 | 
						|
static SANE_Word recv_res_index = 0x3f00;	/**< Receive normal result - wIndex */
 | 
						|
static SANE_Word send_small_cmd_value = 0x2012;	/**< Send small command - wValue */
 | 
						|
static SANE_Word send_small_cmd_index = 0x3f40;	/**< Send small command - wIndex */
 | 
						|
static SANE_Word recv_small_res_value = 0x2013;	/**< Receive small result - wValue */
 | 
						|
static SANE_Word recv_small_res_index = 0x3f00;	/**< Receive small result - wIndex */
 | 
						|
 | 
						|
static SANE_String_Const mode_list[] = {
 | 
						|
  SANE_I18N ("Lineart"),
 | 
						|
  SANE_I18N ("Grayscale"),
 | 
						|
  SANE_I18N ("Color"),
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Word resbit_list[] = {
 | 
						|
  6,
 | 
						|
  50, 100, 200, 300, 600, 1200
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Range brightness_contrast_range = {
 | 
						|
  -127,
 | 
						|
  127,
 | 
						|
  0
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Range blacklevel_range = {
 | 
						|
  20,
 | 
						|
  240,
 | 
						|
  1
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Range gamma_range = {
 | 
						|
  0,				/* minimum */
 | 
						|
  SANE_FIX (4.0),		/* maximum */
 | 
						|
  0				/* quantization */
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Range scan_range_x = {
 | 
						|
  0,				/* minimum */
 | 
						|
  SANE_FIX (216.0),		/* maximum */
 | 
						|
  0				/* quantization */
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Range scan_range_y = {
 | 
						|
  0,				/* minimum */
 | 
						|
  SANE_FIX (297.0),		/* maximum */
 | 
						|
  0				/* quantization */
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static SANE_Word bitdepth_list[] = {
 | 
						|
  2, 8, 16
 | 
						|
};
 | 
						|
 | 
						|
static SANE_Word bitdepth_list2[] = {
 | 
						|
  1, 8
 | 
						|
};
 | 
						|
 | 
						|
static Artec48U_Exposure_Parameters exp_params;
 | 
						|
static Artec48U_Exposure_Parameters default_exp_params =
 | 
						|
  { 0x009f, 0x0109, 0x00cb };
 | 
						|
static Artec48U_AFE_Parameters afe_params;
 | 
						|
static Artec48U_AFE_Parameters default_afe_params =
 | 
						|
  { 0x28, 0x0a, 0x2e, 0x03, 0x2e, 0x03 };
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
download_firmware_file (Artec48U_Device * chip)
 | 
						|
{
 | 
						|
  SANE_Status status = SANE_STATUS_GOOD;
 | 
						|
  SANE_Byte *buf = NULL;
 | 
						|
  int size = -1;
 | 
						|
  FILE *f;
 | 
						|
 | 
						|
  XDBG ((2, "Try to open firmware file: \"%s\"\n", chip->firmware_path));
 | 
						|
  f = fopen (chip->firmware_path, "rb");
 | 
						|
  if (!f)
 | 
						|
    {
 | 
						|
      XDBG ((2, "Cannot open firmware file \"%s\"\n", firmwarePath));
 | 
						|
      status = SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (status == SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      fseek (f, 0, SEEK_END);
 | 
						|
      size = ftell (f);
 | 
						|
      fseek (f, 0, SEEK_SET);
 | 
						|
      if (size == -1)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "Error getting size of firmware file \"%s\"\n",
 | 
						|
	       chip->firmware_path));
 | 
						|
	  status = SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (status == SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "firmware size: %d\n", size));
 | 
						|
      buf = (SANE_Byte *) malloc (size);
 | 
						|
      if (!buf)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "Cannot allocate %d bytes for firmware\n", size));
 | 
						|
	  status = SANE_STATUS_NO_MEM;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (status == SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      int bytes_read = fread (buf, 1, size, f);
 | 
						|
      if (bytes_read != size)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "Problem reading firmware file \"%s\"\n",
 | 
						|
	       chip->firmware_path));
 | 
						|
	  status = SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (f)
 | 
						|
    fclose (f);
 | 
						|
 | 
						|
  if (status == SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      status = artec48u_download_firmware (chip, buf, size);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "Firmware download failed\n"));
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (buf)
 | 
						|
    free (buf);
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
init_calibrator (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  XDBG ((2, "Init calibrator size %d\n",30720 * s->dev->epro_mult));
 | 
						|
  s->shading_buffer_w = (unsigned char *) malloc (30720 * s->dev->epro_mult); /*epro*/
 | 
						|
  s->shading_buffer_b = (unsigned char *) malloc (30720 * s->dev->epro_mult); /*epro*/
 | 
						|
  s->shading_buffer_white[0] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult * sizeof(unsigned int));/*epro*/
 | 
						|
  s->shading_buffer_black[0] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult * sizeof (unsigned int));/*epro*/
 | 
						|
  s->shading_buffer_white[1] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult * sizeof (unsigned int));/*epro*/
 | 
						|
  s->shading_buffer_black[1] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult *  sizeof (unsigned int));/*epro*/
 | 
						|
  s->shading_buffer_white[2] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult *  sizeof (unsigned int));/*epro*/
 | 
						|
  s->shading_buffer_black[2] =
 | 
						|
    (unsigned int *) malloc (5120 * s->dev->epro_mult *  sizeof (unsigned int));/*epro*/
 | 
						|
 | 
						|
  if (!s->shading_buffer_w || !s->shading_buffer_b
 | 
						|
      || !s->shading_buffer_white[0] || !s->shading_buffer_black[0]
 | 
						|
      || !s->shading_buffer_white[1] || !s->shading_buffer_black[1]
 | 
						|
      || !s->shading_buffer_white[2] || !s->shading_buffer_black[2])
 | 
						|
    {
 | 
						|
      if (s->shading_buffer_w)
 | 
						|
	free (s->shading_buffer_w);
 | 
						|
      if (s->shading_buffer_b)
 | 
						|
	free (s->shading_buffer_b);
 | 
						|
      if (s->shading_buffer_white[0])
 | 
						|
	free (s->shading_buffer_white[0]);
 | 
						|
      if (s->shading_buffer_black[0])
 | 
						|
	free (s->shading_buffer_black[0]);
 | 
						|
      if (s->shading_buffer_white[1])
 | 
						|
	free (s->shading_buffer_white[1]);
 | 
						|
      if (s->shading_buffer_black[1])
 | 
						|
	free (s->shading_buffer_black[1]);
 | 
						|
      if (s->shading_buffer_white[2])
 | 
						|
	free (s->shading_buffer_white[2]);
 | 
						|
      if (s->shading_buffer_black[2])
 | 
						|
	free (s->shading_buffer_black[2]);
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
init_shading_buffer (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  unsigned int i, j;
 | 
						|
 | 
						|
  for (i = 0; i < 5120 * s->dev->epro_mult; i++) /*epro*/
 | 
						|
    {
 | 
						|
      for (j = 0; j < 3; j++)
 | 
						|
	{
 | 
						|
	  s->temp_shading_buffer[j][i] = 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
add_to_shading_buffer (Artec48U_Scanner * s, unsigned int **buffer_pointers)
 | 
						|
{
 | 
						|
  unsigned int i, j;
 | 
						|
 | 
						|
  for (i = 0; i < 5120 * s->dev->epro_mult; i++)  /*epro*/
 | 
						|
    {
 | 
						|
      for (j = 0; j < 3; j++)
 | 
						|
	{
 | 
						|
	  s->temp_shading_buffer[j][i] += buffer_pointers[j][i];
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
finish_shading_buffer (Artec48U_Scanner * s, SANE_Bool white)
 | 
						|
{
 | 
						|
  unsigned int i, j, cnt, c, div;
 | 
						|
  unsigned long max_r;
 | 
						|
  unsigned long max_g;
 | 
						|
  unsigned long max_b;
 | 
						|
  unsigned char *shading_buffer;
 | 
						|
  cnt = 0;
 | 
						|
 | 
						|
  if (white)
 | 
						|
    {
 | 
						|
      shading_buffer = s->shading_buffer_w;
 | 
						|
      div = s->dev->shading_lines_w;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      shading_buffer = s->shading_buffer_b;
 | 
						|
      div = s->dev->shading_lines_b;
 | 
						|
    }
 | 
						|
 | 
						|
  for (i = 0; i < 5120 * s->dev->epro_mult; i++) /*epro*/
 | 
						|
    {
 | 
						|
      for (j = 0; j < 3; j++)
 | 
						|
	{
 | 
						|
	  int value = s->temp_shading_buffer[j][i] / (div);
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) (value & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) ((value >> 8) & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  max_r = 0;
 | 
						|
  max_g = 0;
 | 
						|
  max_b = 0;
 | 
						|
 | 
						|
  for (c = 0; c < (30720 * s->dev->epro_mult) - 5; c += 6) /*epro*/
 | 
						|
    {
 | 
						|
      i = (int) shading_buffer[c] + ((int) shading_buffer[c + 1] << 8);
 | 
						|
      max_r += i;
 | 
						|
      i = (int) shading_buffer[c + 2] + ((int) shading_buffer[c + 3] << 8);
 | 
						|
      max_g += i;
 | 
						|
      i = (int) shading_buffer[c + 4] + ((int) shading_buffer[c + 5] << 8);
 | 
						|
      max_b += i;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
finish_exposure_buffer (Artec48U_Scanner * s, int *avg_r, int *avg_g,
 | 
						|
			int *avg_b)
 | 
						|
{
 | 
						|
  unsigned int i, j, cnt, c, div;
 | 
						|
  unsigned int max_r;
 | 
						|
  unsigned int max_g;
 | 
						|
  unsigned int max_b;
 | 
						|
  unsigned char *shading_buffer;
 | 
						|
  cnt = 0;
 | 
						|
 | 
						|
  shading_buffer = s->shading_buffer_w;
 | 
						|
  div = s->dev->shading_lines_w;
 | 
						|
 | 
						|
  for (i = 0; i < 5120 * s->dev->epro_mult; i++) /*epro*/
 | 
						|
    {
 | 
						|
      for (j = 0; j < 3; j++)
 | 
						|
	{
 | 
						|
	  int value = s->temp_shading_buffer[j][i] / (div);
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) (value & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) ((value >> 8) & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  max_r = 0;
 | 
						|
  max_g = 0;
 | 
						|
  max_b = 0;
 | 
						|
  for (c = 0; c < (30720 * s->dev->epro_mult) - 5; c += 6) /*epro*/
 | 
						|
    {
 | 
						|
      i = (int) shading_buffer[c] + ((int) shading_buffer[c + 1] << 8);
 | 
						|
      if (i > max_r)
 | 
						|
	max_r = i;
 | 
						|
      i = (int) shading_buffer[c + 2] + ((int) shading_buffer[c + 3] << 8);
 | 
						|
      if (i > max_g)
 | 
						|
	max_g = i;
 | 
						|
      i = (int) shading_buffer[c + 4] + ((int) shading_buffer[c + 5] << 8);
 | 
						|
      if (i > max_b)
 | 
						|
	max_b = i;
 | 
						|
    }
 | 
						|
  *avg_r = max_r;
 | 
						|
  *avg_g = max_g;
 | 
						|
  *avg_b = max_b;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
finish_offset_buffer (Artec48U_Scanner * s, int *avg_r, int *avg_g,
 | 
						|
		      int *avg_b)
 | 
						|
{
 | 
						|
  unsigned int i, j, cnt, c, div;
 | 
						|
  unsigned int min_r;
 | 
						|
  unsigned int min_g;
 | 
						|
  unsigned int min_b;
 | 
						|
  unsigned char *shading_buffer;
 | 
						|
  cnt = 0;
 | 
						|
 | 
						|
  shading_buffer = s->shading_buffer_b;
 | 
						|
  div = s->dev->shading_lines_b;
 | 
						|
 | 
						|
  for (i = 0; i < 5120 * s->dev->epro_mult; i++) /*epro*/
 | 
						|
    {
 | 
						|
      for (j = 0; j < 3; j++)
 | 
						|
	{
 | 
						|
	  int value = s->temp_shading_buffer[j][i] / (div);
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) (value & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	  shading_buffer[cnt] = (SANE_Byte) ((value >> 8) & 0xff);
 | 
						|
	  ++cnt;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  min_r = 65535;
 | 
						|
  min_g = 65535;
 | 
						|
  min_b = 65535;
 | 
						|
  for (c = 0; c < (30720 * s->dev->epro_mult) - 5; c += 6) /*epro*/
 | 
						|
    {
 | 
						|
      i = (int) shading_buffer[c] + ((int) shading_buffer[c + 1] << 8);
 | 
						|
      if (i < min_r)
 | 
						|
	min_r = i;
 | 
						|
      i = (int) shading_buffer[c + 2] + ((int) shading_buffer[c + 3] << 8);
 | 
						|
      if (i < min_g)
 | 
						|
	min_g = i;
 | 
						|
      i = (int) shading_buffer[c + 4] + ((int) shading_buffer[c + 5] << 8);
 | 
						|
      if (i < min_b)
 | 
						|
	min_b = i;
 | 
						|
    }
 | 
						|
  *avg_r = min_r;
 | 
						|
  *avg_g = min_g;
 | 
						|
  *avg_b = min_b;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_wait_for_positioning (Artec48U_Device * chip)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  SANE_Bool moving;
 | 
						|
 | 
						|
  while (SANE_TRUE)
 | 
						|
    {
 | 
						|
      status = artec48u_is_moving (chip, &moving);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
      if (!moving)
 | 
						|
	break;
 | 
						|
      usleep (100000);
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
copy_scan_line (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  /*For resolution of 1200 dpi we have to interpolate
 | 
						|
     horizontally, because the optical horizontal resolution is
 | 
						|
     limited to 600 dpi. We simply use the avarage value of two pixels. */
 | 
						|
  int cnt, i, j;
 | 
						|
  int xs = s->params.pixel_xs;
 | 
						|
  int interpolate = 0;
 | 
						|
  int value;
 | 
						|
  int value1;
 | 
						|
  int value2;
 | 
						|
  if ((s->reader->params.ydpi == 1200) && (s->dev->is_epro == 0)) /*epro*/
 | 
						|
    interpolate = 1;
 | 
						|
  cnt = 0;
 | 
						|
  if (s->params.color)
 | 
						|
    {
 | 
						|
      if (s->params.depth > 8)
 | 
						|
	{
 | 
						|
	  for (i = xs - 1; i >= 0; i--)
 | 
						|
	    {
 | 
						|
	      for (j = 0; j < 3; j++)
 | 
						|
		{
 | 
						|
		  value = s->buffer_pointers[j][i];
 | 
						|
		  s->line_buffer[cnt] = LOBYTE (value);
 | 
						|
		  ++cnt;
 | 
						|
		  s->line_buffer[cnt] = HIBYTE (value);
 | 
						|
		  ++cnt;
 | 
						|
		}
 | 
						|
	      if (interpolate == 1)	/*1200 dpi */
 | 
						|
		cnt += 6;
 | 
						|
	    }
 | 
						|
	  if (interpolate == 1)
 | 
						|
	    {
 | 
						|
	      for (i = 0; i < (xs * 12) - 12; i += 12)
 | 
						|
		{
 | 
						|
		  value1 = (int) s->line_buffer[i];
 | 
						|
		  value1 += (int) (s->line_buffer[i + 1] << 8);
 | 
						|
		  value2 = (int) s->line_buffer[i + 12];
 | 
						|
		  value2 += (int) (s->line_buffer[i + 13] << 8);
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 65535)
 | 
						|
		    value = 65535;
 | 
						|
		  s->line_buffer[i + 6] = LOBYTE (value);
 | 
						|
		  s->line_buffer[i + 7] = HIBYTE (value);
 | 
						|
 | 
						|
		  value1 = (int) s->line_buffer[i + 2];
 | 
						|
		  value1 += (int) (s->line_buffer[i + 3] << 8);
 | 
						|
		  value2 = (int) s->line_buffer[i + 14];
 | 
						|
		  value2 += (int) (s->line_buffer[i + 15] << 8);
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 65535)
 | 
						|
		    value = 65535;
 | 
						|
		  s->line_buffer[i + 8] = LOBYTE (value);
 | 
						|
		  s->line_buffer[i + 9] = HIBYTE (value);
 | 
						|
 | 
						|
		  value1 = (int) s->line_buffer[i + 4];
 | 
						|
		  value1 += (int) (s->line_buffer[i + 5] << 8);
 | 
						|
		  value2 = (int) s->line_buffer[i + 16];
 | 
						|
		  value2 += (int) (s->line_buffer[i + 17] << 8);
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 65535)
 | 
						|
		    value = 65535;
 | 
						|
		  s->line_buffer[i + 10] = LOBYTE (value);
 | 
						|
		  s->line_buffer[i + 11] = HIBYTE (value);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  for (i = xs - 1; i >= 0; i--)
 | 
						|
	    {
 | 
						|
	      for (j = 0; j < 3; j++)
 | 
						|
		{
 | 
						|
		  value = s->buffer_pointers[j][i];
 | 
						|
		  s->line_buffer[cnt] = (SANE_Byte) (value / 257);
 | 
						|
		  cnt += 1;
 | 
						|
		}
 | 
						|
	      if (interpolate == 1)	/*1200 dpi */
 | 
						|
		cnt += 3;
 | 
						|
	    }
 | 
						|
	  if (interpolate == 1)
 | 
						|
	    {
 | 
						|
	      for (i = 0; i < (xs * 6) - 6; i += 6)
 | 
						|
		{
 | 
						|
		  value1 = (int) s->line_buffer[i];
 | 
						|
		  value2 = (int) s->line_buffer[i + 6];
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 255)
 | 
						|
		    value = 255;
 | 
						|
		  s->line_buffer[i + 3] = (SANE_Byte) (value);
 | 
						|
 | 
						|
		  value1 = (int) s->line_buffer[i + 1];
 | 
						|
		  value2 = (int) s->line_buffer[i + 7];
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 255)
 | 
						|
		    value = 255;
 | 
						|
		  s->line_buffer[i + 4] = (SANE_Byte) (value);
 | 
						|
 | 
						|
		  value1 = (int) s->line_buffer[i + 2];
 | 
						|
		  value2 = (int) s->line_buffer[i + 8];
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 255)
 | 
						|
		    value = 255;
 | 
						|
		  s->line_buffer[i + 5] = (SANE_Byte) (value);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (s->params.depth > 8)
 | 
						|
	{
 | 
						|
	  for (i = xs - 1; i >= 0; --i)
 | 
						|
	    {
 | 
						|
	      value = s->buffer_pointers[0][i];
 | 
						|
	      s->line_buffer[cnt] = LOBYTE (value);
 | 
						|
	      ++cnt;
 | 
						|
	      s->line_buffer[cnt] = HIBYTE (value);
 | 
						|
	      ++cnt;
 | 
						|
	      if (interpolate == 1)	/*1200 dpi */
 | 
						|
		cnt += 2;
 | 
						|
	    }
 | 
						|
	  if (interpolate == 1)
 | 
						|
	    {
 | 
						|
	      for (i = 0; i < (xs * 4) - 4; i += 4)
 | 
						|
		{
 | 
						|
		  value1 = (int) s->line_buffer[i];
 | 
						|
		  value1 += (int) (s->line_buffer[i + 1] << 8);
 | 
						|
		  value2 = (int) s->line_buffer[i + 4];
 | 
						|
		  value2 += (int) (s->line_buffer[i + 5] << 8);
 | 
						|
		  value = (value1 + value2) / 2;
 | 
						|
		  if (value < 0)
 | 
						|
		    value = 0;
 | 
						|
		  if (value > 65535)
 | 
						|
		    value = 65535;
 | 
						|
		  s->line_buffer[i + 2] = LOBYTE (value);
 | 
						|
		  s->line_buffer[i + 3] = HIBYTE (value);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  if (s->params.lineart == SANE_FALSE)
 | 
						|
	    {
 | 
						|
	      for (i = xs - 1; i >= 0; --i)
 | 
						|
		{
 | 
						|
		  value = s->buffer_pointers[0][i];
 | 
						|
		  s->line_buffer[cnt] = (SANE_Byte) (value / 257);
 | 
						|
		  ++cnt;
 | 
						|
		  if (interpolate == 1)	/*1200 dpi */
 | 
						|
		    ++cnt;
 | 
						|
		}
 | 
						|
	      if (interpolate == 1)
 | 
						|
		{
 | 
						|
		  for (i = 0; i < (xs * 2) - 2; i += 2)
 | 
						|
		    {
 | 
						|
		      value1 = (int) s->line_buffer[i];
 | 
						|
		      value2 = (int) s->line_buffer[i + 2];
 | 
						|
		      value = (value1 + value2) / 2;
 | 
						|
		      if (value < 0)
 | 
						|
			value = 0;
 | 
						|
		      if (value > 255)
 | 
						|
			value = 255;
 | 
						|
		      s->line_buffer[i + 1] = (SANE_Byte) (value);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      int cnt2;
 | 
						|
	      int bit_cnt = 0;
 | 
						|
	      int black_level = s->val[OPT_BLACK_LEVEL].w;
 | 
						|
	      /*copy to lineart_buffer */
 | 
						|
	      for (i = xs - 1; i >= 0; --i)
 | 
						|
		{
 | 
						|
		  s->lineart_buffer[cnt] =
 | 
						|
		    (SANE_Byte) (s->buffer_pointers[0][i] / 257);
 | 
						|
		  ++cnt;
 | 
						|
		  if (interpolate == 1)	/*1200 dpi */
 | 
						|
		    ++cnt;
 | 
						|
		}
 | 
						|
	      cnt2 = cnt - 1;
 | 
						|
	      cnt = 0;
 | 
						|
	      if (interpolate == 1)
 | 
						|
		{
 | 
						|
		  for (i = 0; i < cnt2 - 2; i += 2)
 | 
						|
		    {
 | 
						|
		      value1 = (int) s->lineart_buffer[i];
 | 
						|
		      value2 = (int) s->lineart_buffer[i + 2];
 | 
						|
		      value = (value1 + value2) / 2;
 | 
						|
		      if (value < 0)
 | 
						|
			value = 0;
 | 
						|
		      if (value > 255)
 | 
						|
			value = 255;
 | 
						|
		      s->lineart_buffer[i + 1] = (SANE_Byte) (value);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      /* in this case, every value in buffer_pointers represents a bit */
 | 
						|
	      for (i = 0; i < cnt2; i++)
 | 
						|
		{
 | 
						|
		  SANE_Byte temp;
 | 
						|
		  if (bit_cnt == 0)
 | 
						|
		    s->line_buffer[cnt] = 0;	/*clear */
 | 
						|
		  temp = s->lineart_buffer[i];
 | 
						|
		  if (temp <= black_level)
 | 
						|
		    s->line_buffer[cnt] |= 1 << (7 - bit_cnt);
 | 
						|
		  ++bit_cnt;
 | 
						|
		  if (bit_cnt > 7)
 | 
						|
		    {
 | 
						|
		      bit_cnt = 0;
 | 
						|
		      ++cnt;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*.............................................................................
 | 
						|
 * attach a device to the backend
 | 
						|
 */
 | 
						|
static SANE_Status
 | 
						|
attach (const char *dev_name, Artec48U_Device ** devp)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  Artec48U_Device *dev;
 | 
						|
 | 
						|
  XDBG ((1, "attach (%s, %p)\n", dev_name, (void *) devp));
 | 
						|
 | 
						|
  if (!dev_name)
 | 
						|
    {
 | 
						|
      XDBG ((1, "attach: devname == NULL\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  /* already attached ? */
 | 
						|
  for (dev = first_dev; dev; dev = dev->next)
 | 
						|
    {
 | 
						|
      if (0 == strcmp (dev->name, dev_name))
 | 
						|
	{
 | 
						|
	  if (devp)
 | 
						|
	    *devp = dev;
 | 
						|
	  XDBG ((3, "attach: device %s already attached\n", dev_name));
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  XDBG ((3, "attach: device %s NOT attached\n", dev_name));
 | 
						|
  /* allocate some memory for the device */
 | 
						|
  artec48u_device_new (&dev);
 | 
						|
  if (NULL == dev)
 | 
						|
    return SANE_STATUS_NO_MEM;
 | 
						|
 | 
						|
  dev->fd = -1;
 | 
						|
  dev->name = strdup (dev_name);
 | 
						|
  dev->sane.name = strdup (dev_name);
 | 
						|
/*
 | 
						|
 * go ahead and open the scanner device
 | 
						|
 */
 | 
						|
  status = artec48u_device_open (dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "Could not open device!!\n"));
 | 
						|
      artec48u_device_free (dev);
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  /*limit the size of vendor and model string to 40 */
 | 
						|
  vendor_string[40] = 0;
 | 
						|
  model_string[40] = 0;
 | 
						|
 | 
						|
  /* assign all the stuff we need fo this device... */
 | 
						|
  dev->sane.vendor = strdup (vendor_string);
 | 
						|
  XDBG ((3, "attach: setting vendor string: %s\n", vendor_string));
 | 
						|
  dev->sane.model = strdup (model_string);
 | 
						|
  XDBG ((3, "attach: setting model string: %s\n", model_string));
 | 
						|
  dev->sane.type = "flatbed scanner";
 | 
						|
  dev->firmware_path = strdup (firmwarePath);
 | 
						|
 | 
						|
  dev->epro_mult = eProMult;
 | 
						|
  dev->is_epro = isEPro;
 | 
						|
  XDBG ((1, "attach eProMult %d\n", eProMult));
 | 
						|
  XDBG ((1, "attach isEPro %d\n", isEPro));
 | 
						|
  dev->optical_xdpi = 600 * dev->epro_mult; /*epro*/
 | 
						|
  dev->optical_ydpi = 1200 * dev->epro_mult; /*epro*/
 | 
						|
  dev->base_ydpi = 600 * dev->epro_mult; /*epro*/
 | 
						|
  dev->xdpi_offset = 0;		/* in optical_xdpi units */
 | 
						|
  dev->ydpi_offset = 280 * dev->epro_mult;	/* in optical_ydpi units */
 | 
						|
  dev->x_size = 5120 * dev->epro_mult; /*epro*/  /* in optical_xdpi units */
 | 
						|
  dev->y_size = 14100 * dev->epro_mult; /*epro*/  /* in optical_ydpi units */
 | 
						|
  dev->shading_offset = 10 * dev->epro_mult;
 | 
						|
  dev->shading_lines_b = 70 * dev->epro_mult;
 | 
						|
  dev->shading_lines_w = 70 * dev->epro_mult;
 | 
						|
 | 
						|
  dev->gamma_master = gamma_master_default;
 | 
						|
  dev->gamma_r = gamma_r_default;
 | 
						|
  dev->gamma_g = gamma_g_default;
 | 
						|
  dev->gamma_b = gamma_b_default;
 | 
						|
 | 
						|
  dev->afe_params.r_offset = afe_params.r_offset;
 | 
						|
  dev->afe_params.g_offset = afe_params.g_offset;
 | 
						|
  dev->afe_params.b_offset = afe_params.b_offset;
 | 
						|
 | 
						|
  dev->afe_params.r_pga = default_afe_params.r_pga;
 | 
						|
  dev->afe_params.g_pga = default_afe_params.g_pga;
 | 
						|
  dev->afe_params.b_pga = default_afe_params.b_pga;
 | 
						|
 | 
						|
  dev->exp_params.r_time = exp_params.r_time;
 | 
						|
  dev->exp_params.g_time = exp_params.g_time;
 | 
						|
  dev->exp_params.b_time = exp_params.b_time;
 | 
						|
 | 
						|
 | 
						|
  ++num_devices;
 | 
						|
  dev->next = first_dev;
 | 
						|
  first_dev = dev;
 | 
						|
 | 
						|
  if (devp)
 | 
						|
    *devp = first_dev;
 | 
						|
  status = artec48u_device_close (dev);
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
attach_one_device (SANE_String_Const devname)
 | 
						|
{
 | 
						|
  Artec48U_Device *dev;
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  status = attach (devname, &dev);
 | 
						|
  if (SANE_STATUS_GOOD != status)
 | 
						|
    return status;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * function to decode an value and give it back to the caller.
 | 
						|
 * @param src    -  pointer to the source string to check
 | 
						|
 * @param opt    -  string that keeps the option name to check src for
 | 
						|
 * @param what   - _FLOAT or _INT
 | 
						|
 * @param result -  pointer to the var that should receive our result
 | 
						|
 * @param def    - default value that result should be in case of any error
 | 
						|
 * @return The function returns SANE_TRUE if the option has been found,
 | 
						|
 *         if not, it returns SANE_FALSE
 | 
						|
 */
 | 
						|
static SANE_Bool
 | 
						|
decodeVal (char *src, char *opt, int what, void *result, void *def)
 | 
						|
{
 | 
						|
  char *tmp, *tmp2;
 | 
						|
  const char *name;
 | 
						|
 | 
						|
/* skip the option string */
 | 
						|
  name = (const char *) &src[strlen ("option")];
 | 
						|
 | 
						|
/* get the name of the option */
 | 
						|
  name = sanei_config_get_string (name, &tmp);
 | 
						|
 | 
						|
  if (tmp)
 | 
						|
    {
 | 
						|
      /* on success, compare wiht the given one */
 | 
						|
      if (0 == strcmp (tmp, opt))
 | 
						|
	{
 | 
						|
	  XDBG ((1, "Decoding option >%s<\n", opt));
 | 
						|
	  if (_INT == what)
 | 
						|
	    {
 | 
						|
	      /* assign the default value for this option... */
 | 
						|
	      *((int *) result) = *((int *) def);
 | 
						|
	      if (*name)
 | 
						|
		{
 | 
						|
		  /* get the configuration value and decode it */
 | 
						|
		  name = sanei_config_get_string (name, &tmp2);
 | 
						|
		  if (tmp2)
 | 
						|
		    {
 | 
						|
		      *((int *) result) = strtol (tmp2, 0, 0);
 | 
						|
		      free (tmp2);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      free (tmp);
 | 
						|
	      return SANE_TRUE;
 | 
						|
	    }
 | 
						|
	  else if (_FLOAT == what)
 | 
						|
	    {
 | 
						|
	      /* assign the default value for this option... */
 | 
						|
	      *((double *) result) = *((double *) def);
 | 
						|
	      if (*name)
 | 
						|
		{
 | 
						|
		  /* get the configuration value and decode it */
 | 
						|
		  name = sanei_config_get_string (name, &tmp2);
 | 
						|
		  if (tmp2)
 | 
						|
		    {
 | 
						|
		      *((double *) result) = strtod (tmp2, 0);
 | 
						|
		      free (tmp2);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      free (tmp);
 | 
						|
	      return SANE_TRUE;
 | 
						|
	    }
 | 
						|
	  else if (_BYTE == what)
 | 
						|
	    {
 | 
						|
	      /* assign the default value for this option... */
 | 
						|
	      *((SANE_Byte *) result) = *((SANE_Byte *) def);
 | 
						|
	      if (*name)
 | 
						|
		{
 | 
						|
		  /* get the configuration value and decode it */
 | 
						|
		  name = sanei_config_get_string (name, &tmp2);
 | 
						|
		  if (tmp2)
 | 
						|
		    {
 | 
						|
		      *((SANE_Byte *) result) =
 | 
						|
			(SANE_Byte) strtol (tmp2, 0, 0);
 | 
						|
		      free (tmp2);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      free (tmp);
 | 
						|
	      return SANE_TRUE;
 | 
						|
	    }
 | 
						|
	  else if (_STRING == what)
 | 
						|
	    {
 | 
						|
	      if (*name)
 | 
						|
		{
 | 
						|
		  /* get the configuration value and decode it */
 | 
						|
		  sanei_config_get_string (name, &tmp2);
 | 
						|
		  if (tmp2)
 | 
						|
		    {
 | 
						|
		      strcpy ((char *) result, (char *) tmp2);
 | 
						|
		      free (tmp2);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      free (tmp);
 | 
						|
	      return SANE_TRUE;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      free (tmp);
 | 
						|
    }
 | 
						|
  return SANE_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * function to retrive the device name of a given string
 | 
						|
 * @param src  -  string that keeps the option name to check src for
 | 
						|
 * @param dest -  pointer to the string, that should receive the detected
 | 
						|
 *                devicename
 | 
						|
 * @return The function returns SANE_TRUE if the devicename has been found,
 | 
						|
 *         if not, it returns SANE_FALSE
 | 
						|
 */
 | 
						|
static SANE_Bool
 | 
						|
decodeDevName (char *src, char *dest)
 | 
						|
{
 | 
						|
  char *tmp;
 | 
						|
  const char *name;
 | 
						|
 | 
						|
  if (0 == strncmp ("device", src, 6))
 | 
						|
    {
 | 
						|
      name = (const char *) &src[strlen ("device")];
 | 
						|
      name = sanei_config_skip_whitespace (name);
 | 
						|
 | 
						|
      XDBG ((1, "Decoding device name >%s<\n", name));
 | 
						|
 | 
						|
      if (*name)
 | 
						|
	{
 | 
						|
	  name = sanei_config_get_string (name, &tmp);
 | 
						|
	  if (tmp)
 | 
						|
	    {
 | 
						|
	      strcpy (dest, tmp);
 | 
						|
	      free (tmp);
 | 
						|
	      return SANE_TRUE;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  return SANE_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef ARTEC48U_USE_BUTTONS
 | 
						|
static SANE_Status
 | 
						|
artec48u_check_buttons (Artec48U_Device * dev, SANE_Int * value)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  Artec48U_Packet req;
 | 
						|
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x74;
 | 
						|
  req[1] = 0x01;
 | 
						|
 | 
						|
  status = artec48u_device_small_req (dev, req, req);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  *value = (SANE_Int) req[2];
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#define MAX_DOWNLOAD_BLOCK_SIZE 64
 | 
						|
static SANE_Status
 | 
						|
artec48u_generic_start_scan (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  Artec48U_Packet req;
 | 
						|
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x43;
 | 
						|
  req[1] = 0x01;
 | 
						|
 | 
						|
  return artec48u_device_req (dev, req, req);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_generic_read_scanned_data (Artec48U_Device * dev, SANE_Bool * ready)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  Artec48U_Packet req;
 | 
						|
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x35;
 | 
						|
  req[1] = 0x01;
 | 
						|
 | 
						|
  status = artec48u_device_req (dev, req, req);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  if (req[1] == 0x35)
 | 
						|
    {
 | 
						|
      if (req[0] == 0)
 | 
						|
	*ready = SANE_TRUE;
 | 
						|
      else
 | 
						|
	*ready = SANE_FALSE;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    return SANE_STATUS_IO_ERROR;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_download_firmware (Artec48U_Device * dev,
 | 
						|
			    SANE_Byte * data, SANE_Word size)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  SANE_Byte download_buf[MAX_DOWNLOAD_BLOCK_SIZE];
 | 
						|
  SANE_Byte check_buf[MAX_DOWNLOAD_BLOCK_SIZE];
 | 
						|
  SANE_Byte *block;
 | 
						|
  SANE_Word addr, bytes_left;
 | 
						|
  Artec48U_Packet boot_req;
 | 
						|
  SANE_Word block_size = MAX_DOWNLOAD_BLOCK_SIZE;
 | 
						|
 | 
						|
  CHECK_DEV_ACTIVE ((Artec48U_Device *) dev,
 | 
						|
		    (char *) "artec48u_device_download_firmware");
 | 
						|
 | 
						|
  for (addr = 0; addr < size; addr += block_size)
 | 
						|
    {
 | 
						|
      bytes_left = size - addr;
 | 
						|
      if (bytes_left > block_size)
 | 
						|
	block = data + addr;
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  memset (download_buf, 0, block_size);
 | 
						|
	  memcpy (download_buf, data + addr, bytes_left);
 | 
						|
	  block = download_buf;
 | 
						|
	}
 | 
						|
      status = artec48u_device_memory_write (dev, addr, block_size, block);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
      status = artec48u_device_memory_read (dev, addr, block_size, check_buf);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
      if (memcmp (block, check_buf, block_size) != 0)
 | 
						|
	{
 | 
						|
	  XDBG ((3,
 | 
						|
	       "artec48u_device_download_firmware: mismatch at block 0x%0x\n",
 | 
						|
	       addr));
 | 
						|
	  return SANE_STATUS_IO_ERROR;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  memset (boot_req, 0, sizeof (boot_req));
 | 
						|
  boot_req[0] = 0x69;
 | 
						|
  boot_req[1] = 0x01;
 | 
						|
  boot_req[2] = LOBYTE (addr);
 | 
						|
  boot_req[3] = HIBYTE (addr);
 | 
						|
  status = artec48u_device_req (dev, boot_req, boot_req);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_is_moving (Artec48U_Device * dev, SANE_Bool * moving)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  Artec48U_Packet req;
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x17;
 | 
						|
  req[1] = 0x01;
 | 
						|
 | 
						|
  status = artec48u_device_req (dev, req, req);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  if (req[0] == 0x00 && req[1] == 0x17)
 | 
						|
    {
 | 
						|
      if (req[2] == 0 && (req[3] == 0 || req[3] == 2))
 | 
						|
	*moving = SANE_FALSE;
 | 
						|
      else
 | 
						|
	*moving = SANE_TRUE;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    return SANE_STATUS_IO_ERROR;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_carriage_home (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  Artec48U_Packet req;
 | 
						|
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x24;
 | 
						|
  req[1] = 0x01;
 | 
						|
 | 
						|
  return artec48u_device_req (dev, req, req);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_stop_scan (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  Artec48U_Packet req;
 | 
						|
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x41;
 | 
						|
  req[1] = 0x01;
 | 
						|
  return artec48u_device_small_req (dev, req, req);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_setup_scan (Artec48U_Scanner * s,
 | 
						|
		     Artec48U_Scan_Request * request,
 | 
						|
		     Artec48U_Scan_Action action,
 | 
						|
		     SANE_Bool calculate_only,
 | 
						|
		     Artec48U_Scan_Parameters * params)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_setup_scan") SANE_Status status;
 | 
						|
  SANE_Int xdpi, ydpi;
 | 
						|
  SANE_Bool color;
 | 
						|
  SANE_Int depth;
 | 
						|
  SANE_Int pixel_x0, pixel_y0, pixel_xs, pixel_ys;
 | 
						|
  SANE_Int pixel_align;
 | 
						|
 | 
						|
  SANE_Int abs_x0, abs_y0, abs_xs, abs_ys, base_xdpi, base_ydpi;
 | 
						|
  SANE_Int scan_xs, scan_ys, scan_bpl;
 | 
						|
  SANE_Int bits_per_line;
 | 
						|
  SANE_Byte color_mode_code;
 | 
						|
 | 
						|
  /*If we scan a black line, we use these exposure values */
 | 
						|
  Artec48U_Exposure_Parameters exp_params_black = { 4, 4, 4 };
 | 
						|
 | 
						|
  XDBG ((6, "%s: enter\n", function_name));
 | 
						|
  XDBG ((1,"setup scan is_epro %d\n",s->dev->is_epro));
 | 
						|
  XDBG ((1,"setup scan epro_mult %d\n",s->dev->epro_mult));
 | 
						|
 | 
						|
  xdpi = request->xdpi;
 | 
						|
  ydpi = request->ydpi;
 | 
						|
  color = request->color;
 | 
						|
  depth = request->depth;
 | 
						|
 | 
						|
  switch (action)
 | 
						|
    {
 | 
						|
    case SA_CALIBRATE_SCAN_WHITE:
 | 
						|
      {
 | 
						|
	/*move a bit inside scan mark -
 | 
						|
	   the value for the offset was found by trial and error */
 | 
						|
	pixel_y0 = s->dev->shading_offset;
 | 
						|
	pixel_ys = s->dev->shading_lines_w;
 | 
						|
	pixel_x0 = 0;
 | 
						|
	pixel_xs = 5120 * s->dev->epro_mult; /*epro*/
 | 
						|
	xdpi = ydpi = 600 * s->dev->epro_mult; /*epro*/
 | 
						|
	color = SANE_TRUE;
 | 
						|
	depth = 8;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    case SA_CALIBRATE_SCAN_OFFSET_1:
 | 
						|
    case SA_CALIBRATE_SCAN_OFFSET_2:
 | 
						|
      {
 | 
						|
	pixel_y0 = s->dev->shading_offset;
 | 
						|
	pixel_ys = s->dev->shading_lines_b;
 | 
						|
	pixel_x0 = 0;
 | 
						|
	pixel_xs = 5120 * s->dev->epro_mult; /*epro*/
 | 
						|
	xdpi = ydpi = 600 * s->dev->epro_mult; /*epro*/
 | 
						|
	color = SANE_TRUE;
 | 
						|
	depth = 8;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    case SA_CALIBRATE_SCAN_EXPOSURE_1:
 | 
						|
    case SA_CALIBRATE_SCAN_EXPOSURE_2:
 | 
						|
      {
 | 
						|
	pixel_y0 = s->dev->shading_offset;
 | 
						|
	pixel_ys = s->dev->shading_lines_w;
 | 
						|
	pixel_x0 = 0;
 | 
						|
	pixel_xs = 5120 * s->dev->epro_mult; /*epro*/
 | 
						|
	xdpi = ydpi = 600 * s->dev->epro_mult; /*epro*/
 | 
						|
	color = SANE_TRUE;
 | 
						|
	depth = 8;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    case SA_CALIBRATE_SCAN_BLACK:
 | 
						|
      {
 | 
						|
	pixel_y0 = s->dev->shading_offset;
 | 
						|
	pixel_ys = s->dev->shading_lines_w;
 | 
						|
	pixel_x0 = 0;
 | 
						|
	pixel_xs = 5120 * s->dev->epro_mult; /*epro*/
 | 
						|
	xdpi = ydpi = 600 * s->dev->epro_mult; /*epro*/
 | 
						|
	color = SANE_TRUE;
 | 
						|
	depth = 8;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    case SA_SCAN:
 | 
						|
      {
 | 
						|
	SANE_Fixed x0 = request->x0 + s->dev->xdpi_offset;
 | 
						|
	SANE_Fixed y0;
 | 
						|
	/*epro*/
 | 
						|
	if ((ydpi == 1200) && (s->dev->is_epro == 0))
 | 
						|
	  xdpi = 600;
 | 
						|
	y0 = request->y0 + s->dev->ydpi_offset;
 | 
						|
	pixel_ys = SANE_UNFIX (request->ys) * ydpi / MM_PER_INCH + 0.5;
 | 
						|
	pixel_x0 = SANE_UNFIX (x0) * xdpi / MM_PER_INCH + 0.5;
 | 
						|
	pixel_y0 = SANE_UNFIX (y0) * ydpi / MM_PER_INCH + 0.5;
 | 
						|
	pixel_xs = SANE_UNFIX (request->xs) * xdpi / MM_PER_INCH + 0.5;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
 | 
						|
    default:
 | 
						|
      XDBG ((6, "%s: invalid action=%d\n", function_name, (int) action));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((6, "%s: xdpi=%d, ydpi=%d\n", function_name, xdpi, ydpi));
 | 
						|
  XDBG ((6, "%s: color=%s, depth=%d\n", function_name,
 | 
						|
       color ? "TRUE" : "FALSE", depth));
 | 
						|
  XDBG ((6, "%s: pixel_x0=%d, pixel_y0=%d\n", function_name,
 | 
						|
       pixel_x0, pixel_y0));
 | 
						|
  XDBG ((6, "%s: pixel_xs=%d, pixel_ys=%d\n", function_name,
 | 
						|
       pixel_xs, pixel_ys));
 | 
						|
 | 
						|
  switch (depth)
 | 
						|
    {
 | 
						|
    case 8:
 | 
						|
      color_mode_code = color ? 0x84 : 0x82;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 16:
 | 
						|
      color_mode_code = color ? 0xa4 : 0xa2;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      XDBG ((6, "%s: unsupported depth=%d\n", function_name, depth));
 | 
						|
      return SANE_STATUS_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
  base_xdpi = s->dev->optical_xdpi;
 | 
						|
  base_ydpi = s->dev->base_ydpi;
 | 
						|
 | 
						|
  XDBG ((6, "%s: base_xdpi=%d, base_ydpi=%d\n", function_name,
 | 
						|
       base_xdpi, base_ydpi));
 | 
						|
 | 
						|
  abs_x0 = pixel_x0 * base_xdpi / xdpi;
 | 
						|
  abs_y0 = pixel_y0 * base_ydpi / ydpi;
 | 
						|
 | 
						|
  /* Calculate minimum number of pixels which span an integral multiple of 64
 | 
						|
   * bytes. */
 | 
						|
  pixel_align = 32;		/* best case for depth = 16 */
 | 
						|
  while ((depth * pixel_align) % (64 * 8) != 0)
 | 
						|
    pixel_align *= 2;
 | 
						|
  XDBG ((6, "%s: pixel_align=%d\n", function_name, pixel_align));
 | 
						|
 | 
						|
  if (pixel_xs % pixel_align == 0)
 | 
						|
    scan_xs = pixel_xs;
 | 
						|
  else
 | 
						|
    scan_xs = (pixel_xs / pixel_align + 1) * pixel_align;
 | 
						|
  scan_ys = pixel_ys;
 | 
						|
  XDBG ((6, "%s: scan_xs=%d, scan_ys=%d\n", function_name, scan_xs, scan_ys));
 | 
						|
 | 
						|
  abs_xs = scan_xs * base_xdpi / xdpi;
 | 
						|
  abs_ys = scan_ys * base_ydpi / ydpi;
 | 
						|
  XDBG ((6, "%s: abs_xs=%d, abs_ys=%d\n", function_name, abs_xs, abs_ys));
 | 
						|
 | 
						|
  bits_per_line = depth * scan_xs;
 | 
						|
  if (bits_per_line % 8)	/* impossible */
 | 
						|
    {
 | 
						|
      XDBG ((1, "%s: BUG: unaligned bits_per_line=%d\n", function_name,
 | 
						|
	   bits_per_line));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  scan_bpl = bits_per_line / 8;
 | 
						|
 | 
						|
  if (scan_bpl % 64)		/* impossible */
 | 
						|
    {
 | 
						|
      XDBG ((1, "%s: BUG: unaligned scan_bpl=%d\n", function_name, scan_bpl));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (scan_bpl > 15600)
 | 
						|
    {
 | 
						|
      XDBG ((6, "%s: scan_bpl=%d, too large\n", function_name, scan_bpl));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((6, "%s: scan_bpl=%d\n", function_name, scan_bpl));
 | 
						|
 | 
						|
  if (!calculate_only)
 | 
						|
    {
 | 
						|
      Artec48U_Packet req;
 | 
						|
      char motor_mode_1, motor_mode_2;
 | 
						|
      switch (action)
 | 
						|
	{
 | 
						|
	case SA_CALIBRATE_SCAN_WHITE:
 | 
						|
	  motor_mode_1 = 0x01;
 | 
						|
	  motor_mode_2 = 0x00;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case SA_CALIBRATE_SCAN_BLACK:
 | 
						|
	  motor_mode_1 = 0x04;
 | 
						|
	  motor_mode_2 = 0x00;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case SA_SCAN:
 | 
						|
	  motor_mode_1 = 0x01;
 | 
						|
	  motor_mode_2 = 0x00;
 | 
						|
	  break;
 | 
						|
 | 
						|
	default:
 | 
						|
	  XDBG ((6, "%s: invalid action=%d\n", function_name, (int) action));
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Fill in the setup command */
 | 
						|
      memset (req, 0, sizeof (req));
 | 
						|
      req[0x00] = 0x20;
 | 
						|
      req[0x01] = 0x01;
 | 
						|
      req[0x02] = LOBYTE (abs_y0);
 | 
						|
      req[0x03] = HIBYTE (abs_y0);
 | 
						|
      req[0x04] = LOBYTE (abs_ys);
 | 
						|
      req[0x05] = HIBYTE (abs_ys);
 | 
						|
      req[0x06] = LOBYTE (abs_x0);
 | 
						|
      req[0x07] = HIBYTE (abs_x0);
 | 
						|
      req[0x08] = LOBYTE (abs_xs);
 | 
						|
      req[0x09] = HIBYTE (abs_xs);
 | 
						|
      req[0x0a] = color_mode_code;
 | 
						|
      req[0x0b] = 0x60;
 | 
						|
      req[0x0c] = LOBYTE (xdpi);
 | 
						|
      req[0x0d] = HIBYTE (xdpi);
 | 
						|
      req[0x0e] = 0x12;
 | 
						|
      req[0x0f] = 0x00;
 | 
						|
      req[0x10] = LOBYTE (scan_bpl);
 | 
						|
      req[0x11] = HIBYTE (scan_bpl);
 | 
						|
      req[0x12] = LOBYTE (scan_ys);
 | 
						|
      req[0x13] = HIBYTE (scan_ys);
 | 
						|
      req[0x14] = motor_mode_1;
 | 
						|
      req[0x15] = motor_mode_2;
 | 
						|
      req[0x16] = LOBYTE (ydpi);
 | 
						|
      req[0x17] = HIBYTE (ydpi);
 | 
						|
      req[0x18] = 0x00;
 | 
						|
 | 
						|
      status = artec48u_device_req (s->dev, req, req);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  XDBG ((3, "%s: setup request failed: %s\n", function_name,
 | 
						|
	       sane_strstatus (status)));
 | 
						|
	  return status;
 | 
						|
	}
 | 
						|
 | 
						|
      if (action == SA_SCAN)
 | 
						|
	{
 | 
						|
	  artec48u_calculate_shading_buffer (s, pixel_x0, pixel_xs + pixel_x0,
 | 
						|
					     xdpi, color);
 | 
						|
	  artec48u_generic_set_exposure_time (s->dev,
 | 
						|
					      &(s->dev->
 | 
						|
						artec_48u_exposure_params));
 | 
						|
	  artec48u_generic_set_afe (s->dev, &(s->dev->artec_48u_afe_params));
 | 
						|
	}
 | 
						|
      else if (action == SA_CALIBRATE_SCAN_BLACK)
 | 
						|
	{
 | 
						|
	  artec48u_generic_set_exposure_time (s->dev, &exp_params_black);
 | 
						|
	  artec48u_generic_set_afe (s->dev, &(s->dev->afe_params));
 | 
						|
	}
 | 
						|
      else if (action == SA_CALIBRATE_SCAN_WHITE)
 | 
						|
	{
 | 
						|
	  artec48u_generic_set_exposure_time (s->dev, &(s->dev->exp_params));
 | 
						|
	  artec48u_generic_set_afe (s->dev, &(s->dev->afe_params));
 | 
						|
	}
 | 
						|
    }
 | 
						|
  /* Fill in calculated values */
 | 
						|
  params->xdpi = xdpi;
 | 
						|
  params->ydpi = ydpi;
 | 
						|
  params->depth = depth;
 | 
						|
  params->color = color;
 | 
						|
  params->pixel_xs = pixel_xs;
 | 
						|
  params->pixel_ys = pixel_ys;
 | 
						|
  params->scan_xs = scan_xs;
 | 
						|
  params->scan_ys = scan_ys;
 | 
						|
  params->scan_bpl = scan_bpl;
 | 
						|
 | 
						|
  XDBG ((6, "%s: leave: ok\n", function_name));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_generic_set_afe (Artec48U_Device * dev,
 | 
						|
			  Artec48U_AFE_Parameters * params)
 | 
						|
{
 | 
						|
  Artec48U_Packet req;
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x22;
 | 
						|
  req[1] = 0x01;
 | 
						|
  req[2] = params->r_offset;
 | 
						|
  req[3] = params->r_pga;
 | 
						|
  req[4] = params->g_offset;
 | 
						|
  req[5] = params->g_pga;
 | 
						|
  req[6] = params->b_offset;
 | 
						|
  req[7] = params->b_pga;
 | 
						|
 | 
						|
  return artec48u_device_req (dev, req, req);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_generic_set_exposure_time (Artec48U_Device * dev,
 | 
						|
				    Artec48U_Exposure_Parameters * params)
 | 
						|
{
 | 
						|
  Artec48U_Packet req;
 | 
						|
  memset (req, 0, sizeof (req));
 | 
						|
  req[0] = 0x76;
 | 
						|
  req[1] = 0x01;
 | 
						|
  req[2] = req[6] = req[10] = 0x04;
 | 
						|
  req[4] = LOBYTE (params->r_time);
 | 
						|
  req[5] = HIBYTE (params->r_time);
 | 
						|
  req[8] = LOBYTE (params->g_time);
 | 
						|
  req[9] = HIBYTE (params->g_time);
 | 
						|
  req[12] = LOBYTE (params->b_time);
 | 
						|
  req[13] = HIBYTE (params->b_time);
 | 
						|
  return artec48u_device_req (dev, req, req);
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_new (Artec48U_Device ** dev_return)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_new") Artec48U_Device *dev;
 | 
						|
 | 
						|
  XDBG ((7, "%s: enter\n", function_name));
 | 
						|
  if (!dev_return)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  dev = (Artec48U_Device *) malloc (sizeof (Artec48U_Device));
 | 
						|
 | 
						|
  if (!dev)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: couldn't malloc %lu bytes for device\n",
 | 
						|
	     function_name, (u_long) sizeof (Artec48U_Device)));
 | 
						|
      *dev_return = 0;
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
  *dev_return = dev;
 | 
						|
 | 
						|
  memset (dev, 0, sizeof (Artec48U_Device));
 | 
						|
 | 
						|
  dev->fd = -1;
 | 
						|
  dev->active = SANE_FALSE;
 | 
						|
 | 
						|
  dev->read_buffer = NULL;
 | 
						|
  dev->requested_buffer_size = 32768;
 | 
						|
 | 
						|
  XDBG ((7, "%s: leave: ok\n", function_name));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_free (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_free")
 | 
						|
    XDBG ((7, "%s: enter: dev=%p\n", function_name, (void *) dev));
 | 
						|
  if (dev)
 | 
						|
    {
 | 
						|
      if (dev->active)
 | 
						|
	artec48u_device_deactivate (dev);
 | 
						|
 | 
						|
      if (dev->fd != -1)
 | 
						|
	artec48u_device_close (dev);
 | 
						|
 | 
						|
      XDBG ((7, "%s: freeing dev\n", function_name));
 | 
						|
      free (dev);
 | 
						|
    }
 | 
						|
  XDBG ((7, "%s: leave: ok\n", function_name));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_open (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_open")
 | 
						|
  SANE_Status status;
 | 
						|
  SANE_Int fd;
 | 
						|
 | 
						|
  XDBG ((7, "%s: enter: dev=%p\n", function_name, (void *) dev));
 | 
						|
 | 
						|
  CHECK_DEV_NOT_NULL (dev, function_name);
 | 
						|
 | 
						|
  if (dev->fd != -1)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: device already open\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  status = sanei_usb_open (dev->sane.name, &fd);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: sanei_usb_open failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  dev->fd = fd;
 | 
						|
 | 
						|
  XDBG ((7, "%s: leave: ok\n", function_name));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_close (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_close")
 | 
						|
    XDBG ((7, "%s: enter: dev=%p\n", function_name, (void *) dev));
 | 
						|
 | 
						|
  CHECK_DEV_OPEN (dev, function_name);
 | 
						|
 | 
						|
  if (dev->active)
 | 
						|
    artec48u_device_deactivate (dev);
 | 
						|
 | 
						|
  sanei_usb_close (dev->fd);
 | 
						|
  dev->fd = -1;
 | 
						|
 | 
						|
  XDBG ((7, "%s: leave: ok\n", function_name));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_activate (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_activate")
 | 
						|
    CHECK_DEV_OPEN (dev, function_name);
 | 
						|
 | 
						|
  if (dev->active)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: device already active\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((7, "%s: model \"%s\"\n", function_name, dev->sane.model));
 | 
						|
 | 
						|
  dev->xdpi_offset = SANE_FIX (dev->xdpi_offset *
 | 
						|
			       MM_PER_INCH / dev->optical_xdpi);
 | 
						|
  dev->ydpi_offset = SANE_FIX (dev->ydpi_offset *
 | 
						|
			       MM_PER_INCH / dev->optical_ydpi);
 | 
						|
 | 
						|
  dev->active = SANE_TRUE;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_deactivate (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_deactivate")
 | 
						|
    SANE_Status status = SANE_STATUS_GOOD;
 | 
						|
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  if (dev->read_active)
 | 
						|
    artec48u_device_read_finish (dev);
 | 
						|
 | 
						|
  dev->active = SANE_FALSE;
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_memory_write (Artec48U_Device * dev,
 | 
						|
			      SANE_Word addr,
 | 
						|
			      SANE_Word size, SANE_Byte * data)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_memory_write")
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  XDBG ((8, "%s: dev=%p, addr=0x%x, size=0x%x, data=%p\n",
 | 
						|
       function_name, (void *) dev, addr, size, (void *) data));
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  status = sanei_usb_control_msg (dev->fd, 0x40, 0x01,
 | 
						|
				  memory_write_value, addr, size, data);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: sanei_usb_control_msg failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
    }
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_memory_read (Artec48U_Device * dev,
 | 
						|
			     SANE_Word addr, SANE_Word size, SANE_Byte * data)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_memory_read")
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  XDBG ((8, "%s: dev=%p, addr=0x%x, size=0x%x, data=%p\n",
 | 
						|
       function_name, (void *) dev, addr, size, data));
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  status = sanei_usb_control_msg (dev->fd, 0xc0, 0x01,
 | 
						|
				  memory_read_value, addr, size, data);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: sanei_usb_control_msg failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
    }
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_generic_req (Artec48U_Device * dev,
 | 
						|
			     SANE_Word cmd_value, SANE_Word cmd_index,
 | 
						|
			     SANE_Word res_value, SANE_Word res_index,
 | 
						|
			     Artec48U_Packet cmd, Artec48U_Packet res)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_generic_req")
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  XDBG ((7, "%s: command=0x%02x\n", function_name, cmd[0]));
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  status = sanei_usb_control_msg (dev->fd,
 | 
						|
				  0x40, 0x01, cmd_value, cmd_index,
 | 
						|
				  ARTEC48U_PACKET_SIZE, cmd);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: writing command failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  memset (res, 0, sizeof (Artec48U_Packet));
 | 
						|
 | 
						|
  status = sanei_usb_control_msg (dev->fd,
 | 
						|
				  0xc0, 0x01, res_value, res_index,
 | 
						|
				  ARTEC48U_PACKET_SIZE, res);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: reading response failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_req (Artec48U_Device * dev, Artec48U_Packet cmd,
 | 
						|
		     Artec48U_Packet res)
 | 
						|
{
 | 
						|
  return artec48u_device_generic_req (dev,
 | 
						|
				      send_cmd_value,
 | 
						|
				      send_cmd_index,
 | 
						|
				      recv_res_value,
 | 
						|
				      recv_res_index, cmd, res);
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_small_req (Artec48U_Device * dev, Artec48U_Packet cmd,
 | 
						|
			   Artec48U_Packet res)
 | 
						|
{
 | 
						|
  Artec48U_Packet fixed_cmd;
 | 
						|
  int i;
 | 
						|
 | 
						|
  for (i = 0; i < 8; ++i)
 | 
						|
    memcpy (fixed_cmd + i * 8, cmd, 8);
 | 
						|
 | 
						|
  return artec48u_device_generic_req (dev,
 | 
						|
				      send_small_cmd_value,
 | 
						|
				      send_small_cmd_index,
 | 
						|
				      recv_small_res_value,
 | 
						|
				      recv_small_res_index, fixed_cmd, res);
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_read_raw (Artec48U_Device * dev, SANE_Byte * buffer,
 | 
						|
			  size_t * size)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_read_raw")
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  XDBG ((7, "%s: enter: size=0x%lx\n", function_name, (unsigned long) *size));
 | 
						|
 | 
						|
  status = sanei_usb_read_bulk (dev->fd, buffer, size);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: bulk read failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((7, "%s: leave: size=0x%lx\n", function_name, (unsigned long) *size));
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_set_read_buffer_size (Artec48U_Device * dev,
 | 
						|
				      size_t buffer_size)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("gt68xx_device_set_read_buffer_size")
 | 
						|
    CHECK_DEV_NOT_NULL (dev, function_name);
 | 
						|
 | 
						|
  if (dev->read_active)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: BUG: read already active\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  buffer_size = (buffer_size + 63UL) & ~63UL;
 | 
						|
  if (buffer_size > 0)
 | 
						|
    {
 | 
						|
      dev->requested_buffer_size = buffer_size;
 | 
						|
      return SANE_STATUS_GOOD;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((3, "%s: bad buffer size\n", function_name));
 | 
						|
  return SANE_STATUS_INVAL;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_read_prepare (Artec48U_Device * dev, size_t expected_count)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_read_prepare")
 | 
						|
    CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  if (dev->read_active)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: read already active\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  dev->read_buffer = (SANE_Byte *) malloc (dev->requested_buffer_size);
 | 
						|
  if (!dev->read_buffer)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: not enough memory for the read buffer (%lu bytes)\n",
 | 
						|
	   function_name, (unsigned long) dev->requested_buffer_size));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
 | 
						|
  dev->read_active = SANE_TRUE;
 | 
						|
  dev->read_pos = dev->read_bytes_in_buffer = 0;
 | 
						|
  dev->read_bytes_left = expected_count;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static RETSIGTYPE
 | 
						|
reader_process_sigterm_handler (int signal)
 | 
						|
{
 | 
						|
  XDBG ((1, "reader_process: terminated by signal %d\n", signal));
 | 
						|
  _exit (SANE_STATUS_GOOD);
 | 
						|
}
 | 
						|
 | 
						|
static RETSIGTYPE
 | 
						|
usb_reader_process_sigterm_handler (int signal)
 | 
						|
{
 | 
						|
  XDBG ((1, "reader_process (usb): terminated by signal %d\n", signal));
 | 
						|
  cancelRead = SANE_TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_read_start (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  CHECK_DEV_ACTIVE (dev, "artec48u_device_read_start");
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_read (Artec48U_Device * dev, SANE_Byte * buffer,
 | 
						|
		      size_t * size)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_read") SANE_Status status;
 | 
						|
  size_t byte_count = 0;
 | 
						|
  size_t left_to_read = *size;
 | 
						|
  size_t transfer_size, block_size, raw_block_size;
 | 
						|
 | 
						|
  CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  if (!dev->read_active)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: read not active\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  while (left_to_read > 0)
 | 
						|
    {
 | 
						|
      if (dev->read_bytes_in_buffer == 0)
 | 
						|
	{
 | 
						|
	  block_size = dev->requested_buffer_size;
 | 
						|
	  if (block_size > dev->read_bytes_left)
 | 
						|
	    block_size = dev->read_bytes_left;
 | 
						|
	  if (block_size == 0)
 | 
						|
	    break;
 | 
						|
	  raw_block_size = (block_size + 63UL) & ~63UL;
 | 
						|
	  status = artec48u_device_read_raw (dev, dev->read_buffer,
 | 
						|
					     &raw_block_size);
 | 
						|
	  if (status != SANE_STATUS_GOOD)
 | 
						|
	    {
 | 
						|
	      XDBG ((3, "%s: read failed\n", function_name));
 | 
						|
	      return status;
 | 
						|
	    }
 | 
						|
	  dev->read_pos = 0;
 | 
						|
	  dev->read_bytes_in_buffer = block_size;
 | 
						|
	  dev->read_bytes_left -= block_size;
 | 
						|
	}
 | 
						|
 | 
						|
      transfer_size = left_to_read;
 | 
						|
      if (transfer_size > dev->read_bytes_in_buffer)
 | 
						|
	transfer_size = dev->read_bytes_in_buffer;
 | 
						|
      if (transfer_size > 0)
 | 
						|
	{
 | 
						|
	  memcpy (buffer, dev->read_buffer + dev->read_pos, transfer_size);
 | 
						|
	  dev->read_pos += transfer_size;
 | 
						|
	  dev->read_bytes_in_buffer -= transfer_size;
 | 
						|
	  byte_count += transfer_size;
 | 
						|
	  left_to_read -= transfer_size;
 | 
						|
	  buffer += transfer_size;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  *size = byte_count;
 | 
						|
 | 
						|
  if (byte_count == 0)
 | 
						|
    return SANE_STATUS_EOF;
 | 
						|
  else
 | 
						|
    return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_device_read_finish (Artec48U_Device * dev)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_device_read_finish")
 | 
						|
    CHECK_DEV_ACTIVE (dev, function_name);
 | 
						|
 | 
						|
  if (!dev->read_active)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: read not active\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((7, "%s: read_bytes_left = %ld\n",
 | 
						|
       function_name, (long) dev->read_bytes_left));
 | 
						|
 | 
						|
  free (dev->read_buffer);
 | 
						|
  dev->read_buffer = NULL;
 | 
						|
 | 
						|
  dev->read_active = SANE_FALSE;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_delay_buffer_init (Artec48U_Delay_Buffer * delay,
 | 
						|
			    SANE_Int pixels_per_line)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_delay_buffer_init")
 | 
						|
    SANE_Int bytes_per_line;
 | 
						|
  SANE_Int line_count, i;
 | 
						|
 | 
						|
  if (pixels_per_line <= 0)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: BUG: pixels_per_line=%d\n",
 | 
						|
	   function_name, pixels_per_line));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  bytes_per_line = pixels_per_line * sizeof (unsigned int);
 | 
						|
 | 
						|
  delay->line_count = line_count = 1;
 | 
						|
  delay->read_index = 0;
 | 
						|
  delay->write_index = 0;
 | 
						|
 | 
						|
  delay->mem_block = (SANE_Byte *) malloc (bytes_per_line * line_count);
 | 
						|
  if (!delay->mem_block)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: no memory for delay block\n", function_name));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
 | 
						|
  delay->lines =
 | 
						|
    (unsigned int **) malloc (sizeof (unsigned int *) * line_count);
 | 
						|
  if (!delay->lines)
 | 
						|
    {
 | 
						|
      free (delay->mem_block);
 | 
						|
      XDBG ((3, "%s: no memory for delay line pointers\n", function_name));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
 | 
						|
  for (i = 0; i < line_count; ++i)
 | 
						|
    delay->lines[i] =
 | 
						|
      (unsigned int *) (delay->mem_block + i * bytes_per_line);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_delay_buffer_done (Artec48U_Delay_Buffer * delay)
 | 
						|
{
 | 
						|
  if (delay->lines)
 | 
						|
    {
 | 
						|
      free (delay->lines);
 | 
						|
      delay->lines = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (delay->mem_block)
 | 
						|
    {
 | 
						|
      free (delay->mem_block);
 | 
						|
      delay->mem_block = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
#define DELAY_BUFFER_WRITE_PTR(delay) ( (delay)->lines[(delay)->write_index] )
 | 
						|
 | 
						|
#define DELAY_BUFFER_READ_PTR(delay)  ( (delay)->lines[(delay)->read_index ] )
 | 
						|
 | 
						|
#define DELAY_BUFFER_STEP(delay)                                             \
 | 
						|
  do {                                                                       \
 | 
						|
    (delay)->read_index  = ((delay)->read_index  + 1) % (delay)->line_count; \
 | 
						|
    (delay)->write_index = ((delay)->write_index + 1) % (delay)->line_count; \
 | 
						|
  } while (SANE_FALSE)
 | 
						|
 | 
						|
 | 
						|
static inline void
 | 
						|
unpack_8_mono (SANE_Byte * src, unsigned int *dst, SANE_Int pixels_per_line)
 | 
						|
{
 | 
						|
  XDBG ((3, "unpack_8_mono\n"));
 | 
						|
  for (; pixels_per_line > 0; ++src, ++dst, --pixels_per_line)
 | 
						|
    {
 | 
						|
      *dst = (((unsigned int) *src) << 8) | *src;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
unpack_16_le_mono (SANE_Byte * src, unsigned int *dst,
 | 
						|
		   SANE_Int pixels_per_line)
 | 
						|
{
 | 
						|
  XDBG ((3, "unpack_16_le_mono\n"));
 | 
						|
  for (; pixels_per_line > 0; src += 2, dst++, --pixels_per_line)
 | 
						|
    {
 | 
						|
      *dst = (((unsigned int) src[1]) << 8) | src[0];
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
line_read_gray_8 (Artec48U_Line_Reader * reader,
 | 
						|
		  unsigned int **buffer_pointers_return)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  size_t size;
 | 
						|
  unsigned int *buffer;
 | 
						|
  XDBG ((3, "line_read_gray_8\n"));
 | 
						|
 | 
						|
  size = reader->params.scan_bpl;
 | 
						|
  status = artec48u_device_read (reader->dev, reader->pixel_buffer, &size);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  buffer = DELAY_BUFFER_READ_PTR (&reader->g_delay);
 | 
						|
  buffer_pointers_return[0] = buffer;
 | 
						|
  unpack_8_mono (reader->pixel_buffer, buffer, reader->pixels_per_line);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
line_read_gray_16 (Artec48U_Line_Reader * reader,
 | 
						|
		   unsigned int **buffer_pointers_return)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  size_t size;
 | 
						|
  unsigned int *buffer;
 | 
						|
 | 
						|
  XDBG ((3, "line_read_gray_16\n"));
 | 
						|
  size = reader->params.scan_bpl;
 | 
						|
  status = artec48u_device_read (reader->dev, reader->pixel_buffer, &size);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  buffer = DELAY_BUFFER_READ_PTR (&reader->g_delay);
 | 
						|
  buffer_pointers_return[0] = buffer;
 | 
						|
  unpack_16_le_mono (reader->pixel_buffer, buffer, reader->pixels_per_line);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
line_read_bgr_8_line_mode (Artec48U_Line_Reader * reader,
 | 
						|
			   unsigned int **buffer_pointers_return)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  size_t size;
 | 
						|
  SANE_Int pixels_per_line;
 | 
						|
  SANE_Byte *pixel_buffer = reader->pixel_buffer;
 | 
						|
  XDBG ((3, "line_read_bgr_8_line_mode\n"));
 | 
						|
 | 
						|
  size = reader->params.scan_bpl * 3;
 | 
						|
  status = artec48u_device_read (reader->dev, pixel_buffer, &size);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  pixels_per_line = reader->pixels_per_line;
 | 
						|
  unpack_8_mono (pixel_buffer,
 | 
						|
		 DELAY_BUFFER_WRITE_PTR (&reader->b_delay), pixels_per_line);
 | 
						|
  pixel_buffer += reader->params.scan_bpl;
 | 
						|
  unpack_8_mono (pixel_buffer,
 | 
						|
		 DELAY_BUFFER_WRITE_PTR (&reader->g_delay), pixels_per_line);
 | 
						|
  pixel_buffer += reader->params.scan_bpl;
 | 
						|
  unpack_8_mono (pixel_buffer,
 | 
						|
		 DELAY_BUFFER_WRITE_PTR (&reader->r_delay), pixels_per_line);
 | 
						|
 | 
						|
  buffer_pointers_return[0] = DELAY_BUFFER_READ_PTR (&reader->r_delay);
 | 
						|
  buffer_pointers_return[1] = DELAY_BUFFER_READ_PTR (&reader->g_delay);
 | 
						|
  buffer_pointers_return[2] = DELAY_BUFFER_READ_PTR (&reader->b_delay);
 | 
						|
 | 
						|
  DELAY_BUFFER_STEP (&reader->r_delay);
 | 
						|
  DELAY_BUFFER_STEP (&reader->g_delay);
 | 
						|
  DELAY_BUFFER_STEP (&reader->b_delay);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
line_read_bgr_16_line_mode (Artec48U_Line_Reader * reader,
 | 
						|
			    unsigned int **buffer_pointers_return)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  size_t size;
 | 
						|
  SANE_Int pixels_per_line;
 | 
						|
  SANE_Byte *pixel_buffer = reader->pixel_buffer;
 | 
						|
 | 
						|
  XDBG ((3, "line_read_bgr_16_line_mode\n"));
 | 
						|
  size = reader->params.scan_bpl * 3;
 | 
						|
  status = artec48u_device_read (reader->dev, pixel_buffer, &size);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
 | 
						|
  pixels_per_line = reader->pixels_per_line;
 | 
						|
  unpack_16_le_mono (pixel_buffer,
 | 
						|
		     DELAY_BUFFER_WRITE_PTR (&reader->b_delay),
 | 
						|
		     pixels_per_line);
 | 
						|
  pixel_buffer += reader->params.scan_bpl;
 | 
						|
  unpack_16_le_mono (pixel_buffer,
 | 
						|
		     DELAY_BUFFER_WRITE_PTR (&reader->g_delay),
 | 
						|
		     pixels_per_line);
 | 
						|
  pixel_buffer += reader->params.scan_bpl;
 | 
						|
  unpack_16_le_mono (pixel_buffer,
 | 
						|
		     DELAY_BUFFER_WRITE_PTR (&reader->r_delay),
 | 
						|
		     pixels_per_line);
 | 
						|
 | 
						|
  buffer_pointers_return[0] = DELAY_BUFFER_READ_PTR (&reader->r_delay);
 | 
						|
  buffer_pointers_return[1] = DELAY_BUFFER_READ_PTR (&reader->g_delay);
 | 
						|
  buffer_pointers_return[2] = DELAY_BUFFER_READ_PTR (&reader->b_delay);
 | 
						|
 | 
						|
  DELAY_BUFFER_STEP (&reader->r_delay);
 | 
						|
  DELAY_BUFFER_STEP (&reader->g_delay);
 | 
						|
  DELAY_BUFFER_STEP (&reader->b_delay);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_line_reader_init_delays (Artec48U_Line_Reader * reader)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  if (reader->params.color)
 | 
						|
    {
 | 
						|
      status = artec48u_delay_buffer_init (&reader->r_delay,
 | 
						|
					   reader->params.pixel_xs);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
 | 
						|
      status = artec48u_delay_buffer_init (&reader->g_delay,
 | 
						|
					   reader->params.pixel_xs);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  artec48u_delay_buffer_done (&reader->r_delay);
 | 
						|
	  return status;
 | 
						|
	}
 | 
						|
 | 
						|
      status = artec48u_delay_buffer_init (&reader->b_delay,
 | 
						|
					   reader->params.pixel_xs);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  artec48u_delay_buffer_done (&reader->g_delay);
 | 
						|
	  artec48u_delay_buffer_done (&reader->r_delay);
 | 
						|
	  return status;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      status = artec48u_delay_buffer_init (&reader->g_delay,
 | 
						|
					   reader->params.pixel_xs);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
    }
 | 
						|
 | 
						|
  reader->delays_initialized = SANE_TRUE;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
artec48u_line_reader_free_delays (Artec48U_Line_Reader * reader)
 | 
						|
{
 | 
						|
  if (!reader)
 | 
						|
    {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  if (reader->delays_initialized)
 | 
						|
    {
 | 
						|
      if (reader->params.color)
 | 
						|
	{
 | 
						|
	  artec48u_delay_buffer_done (&reader->b_delay);
 | 
						|
	  artec48u_delay_buffer_done (&reader->g_delay);
 | 
						|
	  artec48u_delay_buffer_done (&reader->r_delay);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  artec48u_delay_buffer_done (&reader->g_delay);
 | 
						|
	}
 | 
						|
      reader->delays_initialized = SANE_FALSE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_line_reader_new (Artec48U_Device * dev,
 | 
						|
			  Artec48U_Scan_Parameters * params,
 | 
						|
			  Artec48U_Line_Reader ** reader_return)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_line_reader_new") SANE_Status status;
 | 
						|
  Artec48U_Line_Reader *reader;
 | 
						|
  SANE_Int image_size;
 | 
						|
  SANE_Int scan_bpl_full;
 | 
						|
 | 
						|
  XDBG ((6, "%s: enter\n", function_name));
 | 
						|
  XDBG ((6, "%s: enter params xdpi: %i\n", function_name, params->xdpi));
 | 
						|
  XDBG ((6, "%s: enter params ydpi: %i\n", function_name, params->ydpi));
 | 
						|
  XDBG ((6, "%s: enter params depth: %i\n", function_name, params->depth));
 | 
						|
  XDBG ((6, "%s: enter params color: %i\n", function_name, params->color));
 | 
						|
  XDBG ((6, "%s: enter params pixel_xs: %i\n", function_name, params->pixel_xs));
 | 
						|
  XDBG ((6, "%s: enter params pixel_ys: %i\n", function_name, params->pixel_ys));
 | 
						|
  XDBG ((6, "%s: enter params scan_xs: %i\n", function_name, params->scan_xs));
 | 
						|
  XDBG ((6, "%s: enter params scan_ys: %i\n", function_name, params->scan_ys));
 | 
						|
  XDBG ((6, "%s: enter params scan_bpl: %i\n", function_name, params->scan_bpl));
 | 
						|
  *reader_return = NULL;
 | 
						|
 | 
						|
  reader = (Artec48U_Line_Reader *) malloc (sizeof (Artec48U_Line_Reader));
 | 
						|
  if (!reader)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: cannot allocate Artec48U_Line_Reader\n", function_name));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
  memset (reader, 0, sizeof (Artec48U_Line_Reader));
 | 
						|
 | 
						|
  reader->dev = dev;
 | 
						|
  memcpy (&reader->params, params, sizeof (Artec48U_Scan_Parameters));
 | 
						|
  reader->pixel_buffer = 0;
 | 
						|
  reader->delays_initialized = SANE_FALSE;
 | 
						|
 | 
						|
  reader->read = NULL;
 | 
						|
 | 
						|
  status = artec48u_line_reader_init_delays (reader);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: cannot allocate line buffers: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      free (reader);
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  reader->pixels_per_line = reader->params.pixel_xs;
 | 
						|
 | 
						|
  if (!reader->params.color)
 | 
						|
    {
 | 
						|
      XDBG ((2, "!reader->params.color\n"));
 | 
						|
      if (reader->params.depth == 8)
 | 
						|
	reader->read = line_read_gray_8;
 | 
						|
      else if (reader->params.depth == 16)
 | 
						|
	reader->read = line_read_gray_16;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      XDBG ((2, "reader line mode\n"));
 | 
						|
      if (reader->params.depth == 8)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "depth 8\n"));
 | 
						|
	  reader->read = line_read_bgr_8_line_mode;
 | 
						|
	}
 | 
						|
      else if (reader->params.depth == 16)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "depth 16\n"));
 | 
						|
	  reader->read = line_read_bgr_16_line_mode;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (reader->read == NULL)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: unsupported bit depth (%d)\n",
 | 
						|
	   function_name, reader->params.depth));
 | 
						|
      artec48u_line_reader_free_delays (reader);
 | 
						|
      free (reader);
 | 
						|
      return SANE_STATUS_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
  scan_bpl_full = reader->params.scan_bpl;
 | 
						|
  if (reader->params.color)
 | 
						|
    scan_bpl_full *= 3;
 | 
						|
 | 
						|
  reader->pixel_buffer = malloc (scan_bpl_full);
 | 
						|
  if (!reader->pixel_buffer)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: cannot allocate pixel buffer\n", function_name));
 | 
						|
      artec48u_line_reader_free_delays (reader);
 | 
						|
      free (reader);
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
 | 
						|
  artec48u_device_set_read_buffer_size (reader->dev,
 | 
						|
					scan_bpl_full /* 200 */ );
 | 
						|
 | 
						|
  image_size = scan_bpl_full * reader->params.scan_ys;
 | 
						|
  status = artec48u_device_read_prepare (reader->dev, image_size);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: artec48u_device_read_prepare failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      free (reader->pixel_buffer);
 | 
						|
      artec48u_line_reader_free_delays (reader);
 | 
						|
      free (reader);
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((6, "%s: leave: ok\n", function_name));
 | 
						|
  *reader_return = reader;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_line_reader_free (Artec48U_Line_Reader * reader)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_line_reader_free") SANE_Status status;
 | 
						|
 | 
						|
  XDBG ((6, "%s: enter\n", function_name));
 | 
						|
 | 
						|
  if (!reader)
 | 
						|
    {
 | 
						|
      return SANE_STATUS_GOOD;
 | 
						|
    }
 | 
						|
  artec48u_line_reader_free_delays (reader);
 | 
						|
 | 
						|
  if (reader->pixel_buffer)
 | 
						|
    {
 | 
						|
      free (reader->pixel_buffer);
 | 
						|
      reader->pixel_buffer = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  status = artec48u_device_read_finish (reader->dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "%s: artec48u_device_read_finish failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
    }
 | 
						|
 | 
						|
  if (reader)
 | 
						|
    free (reader);
 | 
						|
 | 
						|
  XDBG ((6, "%s: leave\n", function_name));
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_line_reader_read (Artec48U_Line_Reader * reader,
 | 
						|
			   unsigned int **buffer_pointers_return)
 | 
						|
{
 | 
						|
  return (*reader->read) (reader, buffer_pointers_return);
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_new (Artec48U_Device * dev,
 | 
						|
		      Artec48U_Scanner ** scanner_return)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_scanner_new") Artec48U_Scanner *s;
 | 
						|
 | 
						|
  *scanner_return = NULL;
 | 
						|
 | 
						|
  s = (Artec48U_Scanner *) malloc (sizeof (Artec48U_Scanner));
 | 
						|
  if (!s)
 | 
						|
    {
 | 
						|
      XDBG ((5, "%s: no memory for Artec48U_Scanner\n", function_name));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
  s->dev = dev;
 | 
						|
  s->reader = NULL;
 | 
						|
  s->scanning = SANE_FALSE;
 | 
						|
  s->line_buffer = NULL;
 | 
						|
  s->lineart_buffer = NULL;
 | 
						|
  s->next = NULL;
 | 
						|
  s->pipe_handle = NULL;
 | 
						|
  s->buffer_pointers[0] = NULL;
 | 
						|
  s->buffer_pointers[1] = NULL;
 | 
						|
  s->buffer_pointers[2] = NULL;
 | 
						|
  s->shading_buffer_w = NULL;
 | 
						|
  s->shading_buffer_b = NULL;
 | 
						|
  s->shading_buffer_white[0] = NULL;
 | 
						|
  s->shading_buffer_white[1] = NULL;
 | 
						|
  s->shading_buffer_white[2] = NULL;
 | 
						|
  s->shading_buffer_black[0] = NULL;
 | 
						|
  s->shading_buffer_black[1] = NULL;
 | 
						|
  s->shading_buffer_black[2] = NULL;
 | 
						|
  *scanner_return = s;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_read_line (Artec48U_Scanner * s,
 | 
						|
			    unsigned int **buffer_pointers, SANE_Bool shading)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_scanner_read_line") SANE_Status status;
 | 
						|
  int i, j, c;
 | 
						|
 | 
						|
  status = artec48u_line_reader_read (s->reader, buffer_pointers);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((5, "%s: artec48u_line_reader_read failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  if (shading != SANE_TRUE)
 | 
						|
    return status;
 | 
						|
 | 
						|
  c = s->reader->pixels_per_line;
 | 
						|
  if (s->reader->params.color == SANE_TRUE)
 | 
						|
    {
 | 
						|
      for (i = c - 1; i >= 0; i--)
 | 
						|
	{
 | 
						|
	  for (j = 0; j < 3; j++)
 | 
						|
	    {
 | 
						|
	      int new_value;
 | 
						|
	      unsigned int value = buffer_pointers[j][i];
 | 
						|
	      if (value < s->shading_buffer_black[j][i])
 | 
						|
		value = s->shading_buffer_black[j][i];
 | 
						|
	      if (value > s->shading_buffer_white[j][i])
 | 
						|
		value = s->shading_buffer_white[j][i];
 | 
						|
	      new_value =
 | 
						|
		(double) (value -
 | 
						|
			  s->shading_buffer_black[j][i]) * 65535.0 /
 | 
						|
		(double) (s->shading_buffer_white[j][i] -
 | 
						|
			  s->shading_buffer_black[j][i]);
 | 
						|
	      if (new_value < 0)
 | 
						|
		new_value = 0;
 | 
						|
	      if (new_value > 65535)
 | 
						|
		new_value = 65535;
 | 
						|
	      new_value =
 | 
						|
		s->gamma_array[j +
 | 
						|
			       1][s->contrast_array[s->
 | 
						|
						    brightness_array
 | 
						|
						    [new_value]]];
 | 
						|
	      new_value = s->gamma_array[0][new_value];
 | 
						|
	      buffer_pointers[j][i] = new_value;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      for (i = c - 1; i >= 0; i--)
 | 
						|
	{
 | 
						|
	  int new_value;
 | 
						|
	  unsigned int value = buffer_pointers[0][i];
 | 
						|
	  new_value =
 | 
						|
	    (double) (value -
 | 
						|
		      s->shading_buffer_black[1][i]) * 65535.0 /
 | 
						|
	    (double) (s->shading_buffer_white[1][i] -
 | 
						|
		      s->shading_buffer_black[1][i]);
 | 
						|
	  if (new_value < 0)
 | 
						|
	    new_value = 0;
 | 
						|
	  if (new_value > 65535)
 | 
						|
	    new_value = 65535;
 | 
						|
	  new_value =
 | 
						|
	    s->gamma_array[0][s->
 | 
						|
			      contrast_array[s->brightness_array[new_value]]];
 | 
						|
	  buffer_pointers[0][i] = new_value;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_free (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_scanner_free") if (!s)
 | 
						|
    {
 | 
						|
      XDBG ((5, "%s: scanner==NULL\n", function_name));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (s->reader)
 | 
						|
    {
 | 
						|
      artec48u_line_reader_free (s->reader);
 | 
						|
      s->reader = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  free (s->shading_buffer_w);
 | 
						|
  free (s->shading_buffer_b);
 | 
						|
  free (s->shading_buffer_white[0]);
 | 
						|
  free (s->shading_buffer_black[0]);
 | 
						|
  free (s->shading_buffer_white[1]);
 | 
						|
  free (s->shading_buffer_black[1]);
 | 
						|
  free (s->shading_buffer_white[2]);
 | 
						|
  free (s->shading_buffer_black[2]);
 | 
						|
 | 
						|
  if (s->line_buffer)
 | 
						|
    free (s->line_buffer);
 | 
						|
  if (s->lineart_buffer)
 | 
						|
    free (s->lineart_buffer);
 | 
						|
 | 
						|
  free (s);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_internal_start_scan (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_scanner_internal_start_scan")
 | 
						|
    SANE_Status status;
 | 
						|
  SANE_Bool ready;
 | 
						|
  SANE_Int repeat_count;
 | 
						|
 | 
						|
  status = artec48u_wait_for_positioning (s->dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_scanner_wait_for_positioning error: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  status = artec48u_generic_start_scan (s->dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_device_start_scan error: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  for (repeat_count = 0; repeat_count < 30 * 10; ++repeat_count)
 | 
						|
    {
 | 
						|
      status = artec48u_generic_read_scanned_data (s->dev, &ready);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "%s: artec48u_device_read_scanned_data error: %s\n",
 | 
						|
	       function_name, sane_strstatus (status)));
 | 
						|
	  return status;
 | 
						|
	}
 | 
						|
      if (ready)
 | 
						|
	break;
 | 
						|
      usleep (100000);
 | 
						|
    }
 | 
						|
 | 
						|
  if (!ready)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: scanner still not ready - giving up\n", function_name));
 | 
						|
      return SANE_STATUS_DEVICE_BUSY;
 | 
						|
    }
 | 
						|
 | 
						|
  status = artec48u_device_read_start (s->dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_device_read_start error: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_start_scan_extended (Artec48U_Scanner * s,
 | 
						|
				      Artec48U_Scan_Request * request,
 | 
						|
				      Artec48U_Scan_Action action,
 | 
						|
				      Artec48U_Scan_Parameters * params)
 | 
						|
{
 | 
						|
  DECLARE_FUNCTION_NAME ("artec48u_scanner_start_scan_extended")
 | 
						|
    SANE_Status status;
 | 
						|
 | 
						|
  status = artec48u_wait_for_positioning (s->dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_scanner_wait_for_positioning error: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  if (action == SA_SCAN)
 | 
						|
    status = artec48u_setup_scan (s, request, action, SANE_FALSE, params);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_device_setup_scan failed: %s\n", function_name,
 | 
						|
	   sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  status = artec48u_line_reader_new (s->dev, params, &s->reader);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_line_reader_new failed: %s\n", function_name,
 | 
						|
	   sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  status = artec48u_scanner_internal_start_scan (s);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "%s: artec48u_scanner_internal_start_scan failed: %s\n",
 | 
						|
	   function_name, sane_strstatus (status)));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_start_scan (Artec48U_Scanner * s,
 | 
						|
			     Artec48U_Scan_Request * request,
 | 
						|
			     Artec48U_Scan_Parameters * params)
 | 
						|
{
 | 
						|
  return artec48u_scanner_start_scan_extended (s, request, SA_SCAN, params);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_scanner_stop_scan (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  XDBG ((1, "artec48u_scanner_stop_scan begin: \n"));
 | 
						|
  artec48u_line_reader_free (s->reader);
 | 
						|
  s->reader = NULL;
 | 
						|
 | 
						|
  return artec48u_stop_scan (s->dev);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculateGamma (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  int gval;
 | 
						|
  unsigned int i;
 | 
						|
 | 
						|
  double gamma = SANE_UNFIX (s->val[OPT_GAMMA].w);
 | 
						|
 | 
						|
  d = 65536.0 / pow (65536.0, 1.0 / gamma);
 | 
						|
  for (i = 0; i < 65536; i++)
 | 
						|
    {
 | 
						|
      gval = (int) (pow ((double) i, 1.0 / gamma) * d);
 | 
						|
      s->gamma_array[0][i] = gval;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculateGammaRed (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  int gval;
 | 
						|
  unsigned int i;
 | 
						|
 | 
						|
  double gamma = SANE_UNFIX (s->val[OPT_GAMMA_R].w);
 | 
						|
 | 
						|
  d = 65536.0 / pow (65536.0, 1.0 / gamma);
 | 
						|
  for (i = 0; i < 65536; i++)
 | 
						|
    {
 | 
						|
      gval = (int) (pow ((double) i, 1.0 / gamma) * d);
 | 
						|
      s->gamma_array[1][i] = gval;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculateGammaGreen (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  int gval;
 | 
						|
  unsigned int i;
 | 
						|
 | 
						|
  double gamma = SANE_UNFIX (s->val[OPT_GAMMA_G].w);
 | 
						|
 | 
						|
  d = 65536.0 / pow (65536.0, 1.0 / gamma);
 | 
						|
  for (i = 0; i < 65536; i++)
 | 
						|
    {
 | 
						|
      gval = (int) (pow ((double) i, 1.0 / gamma) * d);
 | 
						|
      s->gamma_array[2][i] = gval;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculateGammaBlue (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  int gval;
 | 
						|
  unsigned int i;
 | 
						|
 | 
						|
  double gamma = SANE_UNFIX (s->val[OPT_GAMMA_B].w);
 | 
						|
 | 
						|
  d = 65536.0 / pow (65536.0, 1.0 / gamma);
 | 
						|
  for (i = 0; i < 65536; i++)
 | 
						|
    {
 | 
						|
      gval = (int) (pow ((double) i, 1.0 / gamma) * d);
 | 
						|
      s->gamma_array[3][i] = gval;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
artec48u_calculate_shading_buffer (Artec48U_Scanner * s, int start, int end,
 | 
						|
				   int resolution, SANE_Bool color)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  int c;
 | 
						|
  int bpp;
 | 
						|
  c = 0;
 | 
						|
  bpp = 6;
 | 
						|
  switch (resolution)
 | 
						|
    {
 | 
						|
    case 50:
 | 
						|
      bpp = 72;
 | 
						|
      break;
 | 
						|
    case 100:
 | 
						|
      bpp = 36;
 | 
						|
      break;
 | 
						|
    case 200:
 | 
						|
      bpp = 18;
 | 
						|
      break;
 | 
						|
    case 300:
 | 
						|
      bpp = 12;
 | 
						|
      break;
 | 
						|
    case 600:
 | 
						|
      bpp = 6;
 | 
						|
      break;
 | 
						|
    case 1200:
 | 
						|
      if(s->dev->is_epro == 0)
 | 
						|
        bpp = 6;
 | 
						|
      else
 | 
						|
        bpp = 3;
 | 
						|
    }
 | 
						|
 | 
						|
  for (i = start * bpp; i < end * bpp; i += bpp)
 | 
						|
    {
 | 
						|
      if (color)
 | 
						|
	{
 | 
						|
	  s->shading_buffer_white[0][c] =
 | 
						|
	    (unsigned int) s->shading_buffer_w[i] +
 | 
						|
	    ((((unsigned int) s->shading_buffer_w[i + 1]) << 8));
 | 
						|
	  s->shading_buffer_white[2][c] =
 | 
						|
	    (unsigned int) s->shading_buffer_w[i + 4] +
 | 
						|
	    ((((unsigned int) s->shading_buffer_w[i + 5]) << 8));
 | 
						|
	  s->shading_buffer_black[0][c] =
 | 
						|
	    (unsigned int) s->shading_buffer_b[i] +
 | 
						|
	    ((((unsigned int) s->shading_buffer_b[i + 1]) << 8));
 | 
						|
	  s->shading_buffer_black[2][c] =
 | 
						|
	    (unsigned int) s->shading_buffer_b[i + 4] +
 | 
						|
	    ((((unsigned int) s->shading_buffer_b[i + 5]) << 8));
 | 
						|
	}
 | 
						|
      s->shading_buffer_white[1][c] =
 | 
						|
	(unsigned int) s->shading_buffer_w[i + 2] +
 | 
						|
	((((unsigned int) s->shading_buffer_w[i + 3]) << 8));
 | 
						|
      s->shading_buffer_black[1][c] =
 | 
						|
	(unsigned int) s->shading_buffer_b[i + 2] +
 | 
						|
	((((unsigned int) s->shading_buffer_b[i + 3]) << 8));
 | 
						|
      ++c;
 | 
						|
    }
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
init_options (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  XDBG ((5, "init_options: scanner %p\n", (void *) s));
 | 
						|
  XDBG ((5, "init_options: start\n"));
 | 
						|
  XDBG ((5, "init_options: num options %i\n", NUM_OPTIONS));
 | 
						|
 | 
						|
  memset (s->val, 0, sizeof (s->val));
 | 
						|
  memset (s->opt, 0, sizeof (s->opt));
 | 
						|
 | 
						|
  for (i = 0; i < NUM_OPTIONS; ++i)
 | 
						|
    {
 | 
						|
      s->opt[i].size = sizeof (SANE_Word);
 | 
						|
      s->opt[i].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].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
 | 
						|
  s->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
 | 
						|
 | 
						|
  s->opt[OPT_MODE_GROUP].name = "scanmode-group";
 | 
						|
  s->opt[OPT_MODE_GROUP].title = SANE_TITLE_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].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->opt[OPT_MODE_GROUP].cap = 0;
 | 
						|
 | 
						|
  s->opt[OPT_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
 | 
						|
  s->opt[OPT_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
 | 
						|
  s->opt[OPT_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
 | 
						|
  s->opt[OPT_SCAN_MODE].type = SANE_TYPE_STRING;
 | 
						|
  s->opt[OPT_SCAN_MODE].size = max_string_size (mode_list);
 | 
						|
  s->opt[OPT_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | 
						|
  s->opt[OPT_SCAN_MODE].constraint.string_list = mode_list;
 | 
						|
  s->val[OPT_SCAN_MODE].s = strdup (mode_list[1]);
 | 
						|
 | 
						|
  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].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | 
						|
  s->opt[OPT_BIT_DEPTH].constraint.word_list = bitdepth_list;
 | 
						|
  s->val[OPT_BIT_DEPTH].w = bitdepth_list[1];
 | 
						|
 | 
						|
  /* black level (lineart only) */
 | 
						|
  s->opt[OPT_BLACK_LEVEL].name = SANE_NAME_BLACK_LEVEL;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].title = SANE_TITLE_BLACK_LEVEL;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].desc = SANE_DESC_BLACK_LEVEL;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].type = SANE_TYPE_INT;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].constraint.range = &blacklevel_range;
 | 
						|
  s->opt[OPT_BLACK_LEVEL].cap |= SANE_CAP_INACTIVE;
 | 
						|
  s->val[OPT_BLACK_LEVEL].w = 127;
 | 
						|
 | 
						|
  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 = resbit_list;
 | 
						|
  s->val[OPT_RESOLUTION].w = resbit_list[1];
 | 
						|
 | 
						|
  /* "Enhancement" group: */
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].name = "enhancement-group";
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
 | 
						|
 | 
						|
  /* 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 = &brightness_contrast_range;
 | 
						|
  s->val[OPT_BRIGHTNESS].w = 0;
 | 
						|
 | 
						|
  /* 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 = &brightness_contrast_range;
 | 
						|
  s->val[OPT_CONTRAST].w = 0;
 | 
						|
 | 
						|
  /* master analog gamma */
 | 
						|
  s->opt[OPT_GAMMA].name = SANE_NAME_ANALOG_GAMMA;
 | 
						|
  s->opt[OPT_GAMMA].title = SANE_TITLE_ANALOG_GAMMA;
 | 
						|
  s->opt[OPT_GAMMA].desc = SANE_DESC_ANALOG_GAMMA;
 | 
						|
  s->opt[OPT_GAMMA].type = SANE_TYPE_FIXED;
 | 
						|
  s->opt[OPT_GAMMA].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_GAMMA].constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
  s->opt[OPT_GAMMA].constraint.range = &gamma_range;
 | 
						|
  s->val[OPT_GAMMA].w = SANE_FIX (s->dev->gamma_master);
 | 
						|
  s->opt[OPT_GAMMA].size = sizeof (SANE_Word);
 | 
						|
 | 
						|
  /* red analog gamma */
 | 
						|
  s->opt[OPT_GAMMA_R].name = SANE_NAME_ANALOG_GAMMA_R;
 | 
						|
  s->opt[OPT_GAMMA_R].title = SANE_TITLE_ANALOG_GAMMA_R;
 | 
						|
  s->opt[OPT_GAMMA_R].desc = SANE_DESC_ANALOG_GAMMA_R;
 | 
						|
  s->opt[OPT_GAMMA_R].type = SANE_TYPE_FIXED;
 | 
						|
  s->opt[OPT_GAMMA_R].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_GAMMA_R].constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
  s->opt[OPT_GAMMA_R].constraint.range = &gamma_range;
 | 
						|
  s->val[OPT_GAMMA_R].w = SANE_FIX (s->dev->gamma_r);
 | 
						|
 | 
						|
  /* green analog gamma */
 | 
						|
  s->opt[OPT_GAMMA_G].name = SANE_NAME_ANALOG_GAMMA_G;
 | 
						|
  s->opt[OPT_GAMMA_G].title = SANE_TITLE_ANALOG_GAMMA_G;
 | 
						|
  s->opt[OPT_GAMMA_G].desc = SANE_DESC_ANALOG_GAMMA_G;
 | 
						|
  s->opt[OPT_GAMMA_G].type = SANE_TYPE_FIXED;
 | 
						|
  s->opt[OPT_GAMMA_G].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_GAMMA_G].constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
  s->opt[OPT_GAMMA_G].constraint.range = &gamma_range;
 | 
						|
  s->val[OPT_GAMMA_G].w = SANE_FIX (s->dev->gamma_g);
 | 
						|
 | 
						|
  /* blue analog gamma */
 | 
						|
  s->opt[OPT_GAMMA_B].name = SANE_NAME_ANALOG_GAMMA_B;
 | 
						|
  s->opt[OPT_GAMMA_B].title = SANE_TITLE_ANALOG_GAMMA_B;
 | 
						|
  s->opt[OPT_GAMMA_B].desc = SANE_DESC_ANALOG_GAMMA_B;
 | 
						|
  s->opt[OPT_GAMMA_B].type = SANE_TYPE_FIXED;
 | 
						|
  s->opt[OPT_GAMMA_B].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_GAMMA_B].constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
  s->opt[OPT_GAMMA_B].constraint.range = &gamma_range;
 | 
						|
  s->val[OPT_GAMMA_B].w = SANE_FIX (s->dev->gamma_b);
 | 
						|
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].name = "default-enhancements";
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].title = SANE_I18N ("Defaults");
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].desc =
 | 
						|
    SANE_I18N ("Set default values for enhancement controls.");
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].size = 0;
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].type = SANE_TYPE_BUTTON;
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_DEFAULT_ENHANCEMENTS].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
 | 
						|
  /* "Geometry" group: */
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].name = "geometry-group";
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].desc = "";
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].size = 0;
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
 | 
						|
  s->opt[OPT_GEOMETRY_GROUP].cap = 0;
 | 
						|
 | 
						|
  /* 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 = &scan_range_x;
 | 
						|
  s->val[OPT_TL_X].w = SANE_FIX (0.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 = &scan_range_y;
 | 
						|
  s->val[OPT_TL_Y].w = SANE_FIX (0.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 = &scan_range_x;
 | 
						|
  s->val[OPT_BR_X].w = SANE_FIX (50.0);
 | 
						|
 | 
						|
  /* 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 = &scan_range_y;
 | 
						|
  s->val[OPT_BR_Y].w = SANE_FIX (50.0);
 | 
						|
 | 
						|
  /* "Calibration" group: */
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].name = "calibration-group";
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].title = SANE_I18N ("Calibration");
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].desc = "";
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].size = 0;
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].type = SANE_TYPE_GROUP;
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->opt[OPT_CALIBRATION_GROUP].cap = 0;
 | 
						|
 | 
						|
  /* calibrate */
 | 
						|
  s->opt[OPT_CALIBRATE].name = "calibration";
 | 
						|
  s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate before next scan");
 | 
						|
  s->opt[OPT_CALIBRATE].desc =
 | 
						|
    SANE_I18N ("If enabled, the device will be calibrated before the "
 | 
						|
	       "next scan. Otherwise, calibration is performed "
 | 
						|
	       "only before the first start.");
 | 
						|
  s->opt[OPT_CALIBRATE].type = SANE_TYPE_BOOL;
 | 
						|
  s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_CALIBRATE].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->val[OPT_CALIBRATE].w = SANE_FALSE;
 | 
						|
 | 
						|
  /* calibrate */
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].name = "calibration-shading";
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].title =
 | 
						|
    SANE_I18N ("Only perform shading-correction");
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].desc =
 | 
						|
    SANE_I18N ("If enabled, only the shading correction is "
 | 
						|
	       "performed during calibration. The default values "
 | 
						|
	       "for gain, offset and exposure time, "
 | 
						|
	       "either build-in or from the configuration file, "
 | 
						|
	       "are used.");
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].type = SANE_TYPE_BOOL;
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_CALIBRATE_SHADING].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->val[OPT_CALIBRATE_SHADING].w = SANE_FALSE;
 | 
						|
#ifdef ARTEC48U_USE_BUTTONS
 | 
						|
  s->opt[OPT_BUTTON_STATE].name = "button-state";
 | 
						|
  s->opt[OPT_BUTTON_STATE].title = SANE_I18N ("Button state");
 | 
						|
  s->opt[OPT_BUTTON_STATE].type = SANE_TYPE_INT;
 | 
						|
  s->opt[OPT_BUTTON_STATE].unit = SANE_UNIT_NONE;
 | 
						|
  s->opt[OPT_BUTTON_STATE].constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
  s->opt[OPT_BUTTON_STATE].cap = SANE_CAP_SOFT_DETECT;
 | 
						|
  s->val[OPT_BUTTON_STATE].w = 0;
 | 
						|
#endif
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculate_brightness (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  long cnt;
 | 
						|
  double bright;
 | 
						|
 | 
						|
  bright = (double) s->val[OPT_BRIGHTNESS].w;
 | 
						|
 | 
						|
  bright *= 257.0;
 | 
						|
  for (cnt = 0; cnt < 65536; cnt++)
 | 
						|
    {
 | 
						|
      if (bright < 0.0)
 | 
						|
	s->brightness_array[cnt] =
 | 
						|
	  (int) (((double) cnt * (65535.0 + bright)) / 65535.0);
 | 
						|
      else
 | 
						|
	s->brightness_array[cnt] =
 | 
						|
	  (int) ((double) cnt +
 | 
						|
		 ((65535.0 - (double) cnt) * bright) / 65535.0);
 | 
						|
      if (s->brightness_array[cnt] > 65535)
 | 
						|
	s->brightness_array[cnt] = 65535;
 | 
						|
      if (s->brightness_array[cnt] < 0)
 | 
						|
	s->brightness_array[cnt] = 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calculate_contrast (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  int val;
 | 
						|
  double p;
 | 
						|
  int cnt;
 | 
						|
  double contr;
 | 
						|
 | 
						|
  contr = (double) s->val[OPT_CONTRAST].w;
 | 
						|
 | 
						|
  contr *= 257.0;
 | 
						|
 | 
						|
  for (cnt = 0; cnt < 65536; cnt++)
 | 
						|
    {
 | 
						|
      if (contr < 0.0)
 | 
						|
	{
 | 
						|
	  val = (int) (cnt > 32769) ? (65535 - cnt) : cnt;
 | 
						|
	  val = (int) (32769.0 * pow ((double) (val ? val : 1) / 32769.0,
 | 
						|
				      (32769.0 + contr) / 32769.0));
 | 
						|
	  s->contrast_array[cnt] = (cnt > 32769) ? (65535 - val) : val;
 | 
						|
	  if (s->contrast_array[cnt] > 65535)
 | 
						|
	    s->contrast_array[cnt] = 65535;
 | 
						|
	  if (s->contrast_array[cnt] < 0)
 | 
						|
	    s->contrast_array[cnt] = 0;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  val = (cnt > 32769) ? (65535 - cnt) : cnt;
 | 
						|
	  p = ((int) contr == 32769) ? 32769.0 : 32769.0 / (32769.0 - contr);
 | 
						|
	  val = (int) (32769.0 * pow ((double) val / 32769.0, p));
 | 
						|
	  s->contrast_array[cnt] = (cnt > 32639) ? (65535 - val) : val;
 | 
						|
	  if (s->contrast_array[cnt] > 65535)
 | 
						|
	    s->contrast_array[cnt] = 65535;
 | 
						|
	  if (s->contrast_array[cnt] < 0)
 | 
						|
	    s->contrast_array[cnt] = 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  The calibration function
 | 
						|
  Disclaimer: the following might be complete crap :-)
 | 
						|
  -Gain, offset, exposure time
 | 
						|
   It seems, that the gain values are actually constants. The windows driver always
 | 
						|
   uses the values 0x0a,0x03,0x03, during calibration as well as during a normal
 | 
						|
   scan. The exposure values are set to 0x04 for black calibration. It's not necessary to
 | 
						|
   move the scan head during this stage.
 | 
						|
   Calibration starts with default values for offset/exposure. These values are
 | 
						|
   increased/decreased until the white and black values are within a specific range, defined
 | 
						|
   by WHITE_MIN, WHITE_MAX, BLACK_MIN and BLACK_MAX.
 | 
						|
 | 
						|
  -White shading correction
 | 
						|
   The scanning head is moved some lines over the calibration strip. Some lines
 | 
						|
   are scanned at 600dpi/16bit over the full width. The average values are used for the
 | 
						|
   shading buffer. The normal exposure values are used.
 | 
						|
  -Black shading correction
 | 
						|
   Works like the white shading correction, with the difference, that the red-, green-
 | 
						|
   and blue exposure time is set to 0x04 (the value is taken from the windoze driver).
 | 
						|
  -Since we do this over the whole width of the image with the maximal optical resolution,
 | 
						|
   we can use the shading data for every scan, independend of the size, position or resolution,
 | 
						|
   because we have the shading values for every sensor/LED.
 | 
						|
 | 
						|
  Note:
 | 
						|
  For a CIS device, it's sufficient to determine those values once. It's not necessary, to
 | 
						|
  repeat the calibration sequence before every new scan. The windoze driver even saves the values
 | 
						|
  to various files to avoid the quite lengthy calibration sequence. This backend can also save
 | 
						|
  the values to files. For this purpose, the user has to create a hidden directory called
 | 
						|
  .artec-eplus48u in his/her home directory. If the user insists on calibration
 | 
						|
  before every new scan, he/she can enable a specific option in the backend.
 | 
						|
*/
 | 
						|
static SANE_Status
 | 
						|
calibrate_scanner (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
  unsigned int *buffer_pointers[3];
 | 
						|
  int avg_black[3];
 | 
						|
  int avg_white[3];
 | 
						|
  int exp_off;
 | 
						|
  int c;
 | 
						|
  int finish = 0;
 | 
						|
  int noloop = 0;
 | 
						|
 | 
						|
 | 
						|
  if ((s->val[OPT_CALIBRATE].w == SANE_TRUE) &&
 | 
						|
      (s->val[OPT_CALIBRATE_SHADING].w == SANE_FALSE))
 | 
						|
    {
 | 
						|
      while (finish == 0)
 | 
						|
	{
 | 
						|
	  finish = 1;
 | 
						|
	  /*get black values */
 | 
						|
	  artec48u_carriage_home (s->dev);
 | 
						|
 | 
						|
	  artec48u_wait_for_positioning (s->dev);
 | 
						|
	  s->reader = NULL;
 | 
						|
 | 
						|
	  s->scanning = SANE_TRUE;
 | 
						|
 | 
						|
	  init_shading_buffer (s);
 | 
						|
 | 
						|
	  artec48u_setup_scan (s, &(s->request), SA_CALIBRATE_SCAN_BLACK,
 | 
						|
			       SANE_FALSE, &(s->params));
 | 
						|
	  artec48u_scanner_start_scan_extended (s, &(s->request),
 | 
						|
						SA_CALIBRATE_SCAN_OFFSET_1,
 | 
						|
						&(s->params));
 | 
						|
 | 
						|
	  for (c = 0; c < s->dev->shading_lines_b; c++)
 | 
						|
	    {
 | 
						|
	      artec48u_scanner_read_line (s, buffer_pointers, SANE_FALSE);
 | 
						|
	      /* we abuse the shading buffer for the offset calculation */
 | 
						|
	      add_to_shading_buffer (s, buffer_pointers);
 | 
						|
	    }
 | 
						|
	  artec48u_scanner_stop_scan (s);
 | 
						|
	  finish_offset_buffer (s, &avg_black[0], &avg_black[1],
 | 
						|
				&avg_black[2]);
 | 
						|
	  s->scanning = SANE_FALSE;
 | 
						|
	  XDBG ((1, "avg_r: %i, avg_g: %i, avg_b: %i\n", avg_black[0],
 | 
						|
	       avg_black[1], avg_black[2]));
 | 
						|
	  /*adjust offset */
 | 
						|
	  for (c = 0; c < 3; c++)
 | 
						|
	    {
 | 
						|
	      if (c == 0)
 | 
						|
		{
 | 
						|
		  if (avg_black[c] < BLACK_MIN)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.r_offset -= 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset r: -1\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_black[c] > BLACK_MAX)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.r_offset += 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset r: +1\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      if (c == 1)
 | 
						|
		{
 | 
						|
		  if (avg_black[c] < BLACK_MIN)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.g_offset -= 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset g: -1\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_black[c] > BLACK_MAX)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.g_offset += 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset g: +1\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      if (c == 2)
 | 
						|
		{
 | 
						|
		  if (avg_black[c] < BLACK_MIN)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.b_offset -= 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset b: -1\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_black[c] > BLACK_MAX)
 | 
						|
		    {
 | 
						|
		      s->dev->afe_params.b_offset += 1;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust offset b: +1\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  /*adjust exposure */
 | 
						|
	  /*get white values */
 | 
						|
 | 
						|
	  artec48u_carriage_home (s->dev);
 | 
						|
 | 
						|
	  artec48u_wait_for_positioning (s->dev);
 | 
						|
	  s->reader = NULL;
 | 
						|
 | 
						|
	  s->scanning = SANE_TRUE;
 | 
						|
 | 
						|
	  init_shading_buffer (s);
 | 
						|
 | 
						|
	  artec48u_setup_scan (s, &(s->request), SA_CALIBRATE_SCAN_WHITE,
 | 
						|
			       SANE_FALSE, &(s->params));
 | 
						|
	  artec48u_scanner_start_scan_extended (s, &(s->request),
 | 
						|
						SA_CALIBRATE_SCAN_EXPOSURE_1,
 | 
						|
						&(s->params));
 | 
						|
 | 
						|
	  for (c = 0; c < s->dev->shading_lines_w; c++)
 | 
						|
	    {
 | 
						|
	      artec48u_scanner_read_line (s, buffer_pointers, SANE_FALSE);
 | 
						|
	      /* we abuse the shading buffer for the exposure calculation */
 | 
						|
	      add_to_shading_buffer (s, buffer_pointers);
 | 
						|
	    }
 | 
						|
	  artec48u_scanner_stop_scan (s);
 | 
						|
	  finish_exposure_buffer (s, &avg_white[0], &avg_white[1],
 | 
						|
				  &avg_white[2]);
 | 
						|
	  s->scanning = SANE_FALSE;
 | 
						|
	  XDBG ((1, "avg_r: %i, avg_g: %i, avg_b: %i\n", avg_white[0],
 | 
						|
	       avg_white[1], avg_white[2]));
 | 
						|
	  for (c = 0; c < 3; c++)
 | 
						|
	    {
 | 
						|
	      if (c == 0)
 | 
						|
		{
 | 
						|
		  if (avg_white[c] < WHITE_MIN)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			((WHITE_MAX + WHITE_MIN) / 2 -
 | 
						|
			 avg_white[c]) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.r_time += exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure r: ++\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_white[c] > WHITE_MAX)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			(avg_white[c] -
 | 
						|
			 (WHITE_MAX + WHITE_MIN) / 2) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.r_time -= exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure r: --\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      else if (c == 1)
 | 
						|
		{
 | 
						|
		  if (avg_white[c] < WHITE_MIN)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			((WHITE_MAX + WHITE_MIN) / 2 -
 | 
						|
			 avg_white[c]) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.g_time += exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure g: ++\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_white[c] > WHITE_MAX)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			(avg_white[c] -
 | 
						|
			 (WHITE_MAX + WHITE_MIN) / 2) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.g_time -= exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure g: --\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      else if (c == 2)
 | 
						|
		{
 | 
						|
		  if (avg_white[c] < WHITE_MIN)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			((WHITE_MAX + WHITE_MIN) / 2 -
 | 
						|
			 avg_white[c]) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.b_time += exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure b: ++\n"));
 | 
						|
		    }
 | 
						|
		  else if (avg_white[c] > WHITE_MAX)
 | 
						|
		    {
 | 
						|
		      exp_off =
 | 
						|
			(avg_white[c] -
 | 
						|
			 (WHITE_MAX + WHITE_MIN) / 2) / EXPOSURE_STEP;
 | 
						|
		      if (exp_off < 1)
 | 
						|
			exp_off = 1;
 | 
						|
		      s->dev->exp_params.b_time -= exp_off;
 | 
						|
		      finish = 0;
 | 
						|
		      XDBG ((1, "adjust exposure b: --\n"));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  XDBG ((1, "time_r: %x, time_g: %x, time_b: %x\n",
 | 
						|
	       s->dev->exp_params.r_time, s->dev->exp_params.g_time,
 | 
						|
	       s->dev->exp_params.b_time));
 | 
						|
	  XDBG ((1, "offset_r: %x, offset_g: %x, offset_b: %x\n",
 | 
						|
	       s->dev->afe_params.r_offset, s->dev->afe_params.g_offset,
 | 
						|
	       s->dev->afe_params.b_offset));
 | 
						|
	  ++noloop;
 | 
						|
	  if (noloop > 10)
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((1, "option redOffset 0x%x\n", s->dev->afe_params.r_offset));
 | 
						|
  XDBG ((1, "option greenOffset 0x%x\n", s->dev->afe_params.g_offset));
 | 
						|
  XDBG ((1, "option blueOffset 0x%x\n", s->dev->afe_params.b_offset));
 | 
						|
  XDBG ((1, "option redExposure 0x%x\n", s->dev->exp_params.r_time));
 | 
						|
  XDBG ((1, "option greenExposure 0x%x\n", s->dev->exp_params.g_time));
 | 
						|
  XDBG ((1, "option blueExposure 0x%x\n", s->dev->exp_params.b_time));
 | 
						|
 | 
						|
  s->dev->artec_48u_afe_params.r_offset = s->dev->afe_params.r_offset;
 | 
						|
  s->dev->artec_48u_afe_params.g_offset = s->dev->afe_params.g_offset;
 | 
						|
  s->dev->artec_48u_afe_params.b_offset = s->dev->afe_params.b_offset;
 | 
						|
  /*don't forget the gain */
 | 
						|
  s->dev->artec_48u_afe_params.r_pga = s->dev->afe_params.r_pga;
 | 
						|
  s->dev->artec_48u_afe_params.g_pga = s->dev->afe_params.g_pga;
 | 
						|
  s->dev->artec_48u_afe_params.b_pga = s->dev->afe_params.b_pga;
 | 
						|
 | 
						|
  s->dev->artec_48u_exposure_params.r_time = s->dev->exp_params.r_time;
 | 
						|
  s->dev->artec_48u_exposure_params.g_time = s->dev->exp_params.g_time;
 | 
						|
  s->dev->artec_48u_exposure_params.b_time = s->dev->exp_params.b_time;
 | 
						|
 | 
						|
  /*******************************
 | 
						|
   *get the black shading values *
 | 
						|
   *******************************/
 | 
						|
  artec48u_carriage_home (s->dev);
 | 
						|
 | 
						|
  artec48u_wait_for_positioning (s->dev);
 | 
						|
  s->reader = NULL;
 | 
						|
 | 
						|
  s->scanning = SANE_TRUE;
 | 
						|
 | 
						|
  init_shading_buffer (s);
 | 
						|
 | 
						|
  artec48u_setup_scan (s, &(s->request), SA_CALIBRATE_SCAN_BLACK, SANE_FALSE,
 | 
						|
		       &(s->params));
 | 
						|
  artec48u_scanner_start_scan_extended (s, &(s->request),
 | 
						|
					SA_CALIBRATE_SCAN_BLACK,
 | 
						|
					&(s->params));
 | 
						|
 | 
						|
  for (c = 0; c < s->dev->shading_lines_b; c++)
 | 
						|
    {
 | 
						|
      artec48u_scanner_read_line (s, buffer_pointers, SANE_FALSE);
 | 
						|
      add_to_shading_buffer (s, buffer_pointers);
 | 
						|
    }
 | 
						|
  artec48u_scanner_stop_scan (s);
 | 
						|
  finish_shading_buffer (s, SANE_FALSE);
 | 
						|
  s->scanning = SANE_FALSE;
 | 
						|
 | 
						|
  /*******************************
 | 
						|
   *get the white shading values *
 | 
						|
   *******************************/
 | 
						|
  artec48u_carriage_home (s->dev);
 | 
						|
 | 
						|
  artec48u_wait_for_positioning (s->dev);
 | 
						|
  s->reader = NULL;
 | 
						|
  s->scanning = SANE_TRUE;
 | 
						|
 | 
						|
  init_shading_buffer (s);
 | 
						|
 | 
						|
  artec48u_setup_scan (s, &(s->request), SA_CALIBRATE_SCAN_WHITE, SANE_FALSE,
 | 
						|
		       &(s->params));
 | 
						|
  artec48u_scanner_start_scan_extended (s, &(s->request),
 | 
						|
					SA_CALIBRATE_SCAN_WHITE,
 | 
						|
					&(s->params));
 | 
						|
  for (c = 0; c < s->dev->shading_lines_w; c++)
 | 
						|
    {
 | 
						|
      artec48u_scanner_read_line (s, buffer_pointers, SANE_FALSE);
 | 
						|
      add_to_shading_buffer (s, buffer_pointers);
 | 
						|
    }
 | 
						|
  artec48u_scanner_stop_scan (s);
 | 
						|
  finish_shading_buffer (s, SANE_TRUE);
 | 
						|
  s->scanning = SANE_FALSE;
 | 
						|
  save_calibration_data (s);
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
close_pipe (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  if (s->pipe >= 0)
 | 
						|
    {
 | 
						|
      XDBG ((1, "close_pipe\n"));
 | 
						|
      close (s->pipe);
 | 
						|
      s->pipe = -1;
 | 
						|
    }
 | 
						|
  return SANE_STATUS_EOF;
 | 
						|
}
 | 
						|
static RETSIGTYPE
 | 
						|
sigalarm_handler (int signal)
 | 
						|
{
 | 
						|
  int dummy;			/*Henning doesn't like warnings :-) */
 | 
						|
  XDBG ((1, "ALARM!!!\n"));
 | 
						|
  dummy = signal;
 | 
						|
  cancelRead = SANE_TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
sig_chldhandler (int signo)
 | 
						|
{
 | 
						|
  XDBG ((1, "Child is down (signal=%d)\n", signo));
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
reader_process (void * data)
 | 
						|
{
 | 
						|
  Artec48U_Scanner * s = (Artec48U_Scanner *) data;
 | 
						|
  int fd = s->reader_pipe;
 | 
						|
 | 
						|
  SANE_Status status;
 | 
						|
  struct SIGACTION act;
 | 
						|
  sigset_t ignore_set;
 | 
						|
  ssize_t bytes_written = 0;
 | 
						|
 | 
						|
  XDBG ((1, "reader process...\n"));
 | 
						|
 | 
						|
  if (sanei_thread_is_forked()) close (s->pipe);
 | 
						|
 | 
						|
  sigfillset (&ignore_set);
 | 
						|
  sigdelset (&ignore_set, SIGTERM);
 | 
						|
  sigdelset (&ignore_set, SIGUSR1);
 | 
						|
#if defined (__APPLE__) && defined (__MACH__)
 | 
						|
  sigdelset (&ignore_set, SIGUSR2);
 | 
						|
#endif
 | 
						|
  sigprocmask (SIG_SETMASK, &ignore_set, 0);
 | 
						|
 | 
						|
  memset (&act, 0, sizeof (act));
 | 
						|
  sigaction (SIGTERM, &act, 0);
 | 
						|
  sigaction (SIGUSR1, &act, 0);
 | 
						|
 | 
						|
  cancelRead = SANE_FALSE;
 | 
						|
  if (sigemptyset (&(act.sa_mask)) < 0)
 | 
						|
    XDBG ((2, "(child) reader_process: sigemptyset() failed\n"));
 | 
						|
  act.sa_flags = 0;
 | 
						|
 | 
						|
  act.sa_handler = reader_process_sigterm_handler;
 | 
						|
  if (sigaction (SIGTERM, &act, 0) < 0)
 | 
						|
    XDBG ((2, "(child) reader_process: sigaction(SIGTERM,...) failed\n"));
 | 
						|
 | 
						|
  act.sa_handler = usb_reader_process_sigterm_handler;
 | 
						|
  if (sigaction (SIGUSR1, &act, 0) < 0)
 | 
						|
    XDBG ((2, "(child) reader_process: sigaction(SIGUSR1,...) failed\n"));
 | 
						|
 | 
						|
 | 
						|
  XDBG ((2, "(child) reader_process: s=%p, fd=%d\n", (void *) s, fd));
 | 
						|
 | 
						|
  /*read line by line into buffer */
 | 
						|
  /*copy buffer pointers to line_buffer */
 | 
						|
  XDBG ((2, "(child) reader_process: byte_cnt %d\n", (int) s->byte_cnt));
 | 
						|
  s->eof = SANE_FALSE;
 | 
						|
  while (s->lines_to_read > 0)
 | 
						|
    {
 | 
						|
      if (cancelRead == SANE_TRUE)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "(child) reader_process: cancelRead == SANE_TRUE\n"));
 | 
						|
	  s->scanning = SANE_FALSE;
 | 
						|
	  s->eof = SANE_FALSE;
 | 
						|
	  return SANE_STATUS_CANCELLED;
 | 
						|
	}
 | 
						|
      if (s->scanning != SANE_TRUE)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "(child) reader_process: scanning != SANE_TRUE\n"));
 | 
						|
	  return SANE_STATUS_CANCELLED;
 | 
						|
	}
 | 
						|
      status = artec48u_scanner_read_line (s, s->buffer_pointers, SANE_TRUE);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "(child) reader_process: scanner_read_line failed\n"));
 | 
						|
	  return SANE_STATUS_IO_ERROR;
 | 
						|
	}
 | 
						|
      copy_scan_line (s);
 | 
						|
      s->lines_to_read -= 1;
 | 
						|
      bytes_written =
 | 
						|
	write (fd, s->line_buffer, s->sane_params.bytes_per_line);
 | 
						|
 | 
						|
      if (bytes_written < 0)
 | 
						|
	{
 | 
						|
	  XDBG ((2, "(child) reader_process: write returned %s\n",
 | 
						|
	       strerror (errno)));
 | 
						|
	  s->eof = SANE_FALSE;
 | 
						|
	  return SANE_STATUS_IO_ERROR;
 | 
						|
	}
 | 
						|
 | 
						|
      XDBG ((2, "(child) reader_process: lines to read %i\n", s->lines_to_read));
 | 
						|
    }
 | 
						|
  s->eof = SANE_TRUE;
 | 
						|
  close (fd);
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
do_cancel (Artec48U_Scanner * s, SANE_Bool closepipe)
 | 
						|
{
 | 
						|
  struct SIGACTION act;
 | 
						|
  pid_t res;
 | 
						|
  XDBG ((1, "do_cancel\n"));
 | 
						|
 | 
						|
  s->scanning = SANE_FALSE;
 | 
						|
 | 
						|
  if (s->reader_pid > 0)
 | 
						|
    {
 | 
						|
      /*parent */
 | 
						|
      XDBG ((1, "killing reader_process\n"));
 | 
						|
      /* tell the driver to stop scanning */
 | 
						|
      sigemptyset (&(act.sa_mask));
 | 
						|
      act.sa_flags = 0;
 | 
						|
 | 
						|
      act.sa_handler = sigalarm_handler;
 | 
						|
 | 
						|
      if (sigaction (SIGALRM, &act, 0) == -1)
 | 
						|
	XDBG ((1, "sigaction() failed !\n"));
 | 
						|
 | 
						|
      /* kill our child process and wait until done */
 | 
						|
      alarm (10);
 | 
						|
      if (sanei_thread_kill (s->reader_pid) < 0)
 | 
						|
	XDBG ((1, "sanei_thread_kill() failed !\n"));
 | 
						|
      res = sanei_thread_waitpid (s->reader_pid, 0);
 | 
						|
      alarm (0);
 | 
						|
 | 
						|
      if (res != s->reader_pid)
 | 
						|
	{
 | 
						|
	  XDBG ((1, "sanei_thread_waitpid() failed !\n"));
 | 
						|
	}
 | 
						|
      s->reader_pid = 0;
 | 
						|
      XDBG ((1, "reader_process killed\n"));
 | 
						|
    }
 | 
						|
  if (SANE_TRUE == closepipe)
 | 
						|
    {
 | 
						|
      close_pipe (s);
 | 
						|
      XDBG ((1, "pipe closed\n"));
 | 
						|
    }
 | 
						|
  artec48u_scanner_stop_scan (s);
 | 
						|
  artec48u_carriage_home (s->dev);
 | 
						|
  if (s->line_buffer)
 | 
						|
    {
 | 
						|
      XDBG ((2, "freeing line_buffer\n"));
 | 
						|
      free (s->line_buffer);
 | 
						|
      s->line_buffer = NULL;
 | 
						|
    }
 | 
						|
  if (s->lineart_buffer)
 | 
						|
    {
 | 
						|
      XDBG ((2, "freeing lineart_buffer\n"));
 | 
						|
      free (s->lineart_buffer);
 | 
						|
      s->lineart_buffer = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_CANCELLED;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
 | 
						|
{
 | 
						|
  static const SANE_Device **devlist = 0;
 | 
						|
  Artec48U_Device *dev;
 | 
						|
  SANE_Int dev_num;
 | 
						|
 | 
						|
  XDBG ((5, "sane_get_devices: start: local_only = %s\n",
 | 
						|
       local_only == SANE_TRUE ? "true" : "false"));
 | 
						|
 | 
						|
  if (devlist)
 | 
						|
    free (devlist);
 | 
						|
 | 
						|
  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
 | 
						|
  if (!devlist)
 | 
						|
    return SANE_STATUS_NO_MEM;
 | 
						|
 | 
						|
  dev_num = 0;
 | 
						|
  for (dev = first_dev; dev_num < num_devices; dev = dev->next)
 | 
						|
    {
 | 
						|
      devlist[dev_num] = &dev->sane;
 | 
						|
      XDBG ((3, "sane_get_devices: name %s\n", dev->sane.name));
 | 
						|
      XDBG ((3, "sane_get_devices: vendor %s\n", dev->sane.vendor));
 | 
						|
      XDBG ((3, "sane_get_devices: model %s\n", dev->sane.model));
 | 
						|
      ++dev_num;
 | 
						|
    }
 | 
						|
  devlist[dev_num] = 0;
 | 
						|
  ++dev_num;
 | 
						|
 | 
						|
  *device_list = devlist;
 | 
						|
 | 
						|
  XDBG ((5, "sane_get_devices: exit\n"));
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
load_calibration_data (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  SANE_Status status = SANE_STATUS_GOOD;
 | 
						|
  FILE *f = 0;
 | 
						|
  size_t cnt;
 | 
						|
  char path[PATH_MAX];
 | 
						|
  char filename[PATH_MAX];
 | 
						|
 | 
						|
  s->calibrated = SANE_FALSE;
 | 
						|
  path[0] = 0;
 | 
						|
  if (strlen (getenv ("HOME")) < (PATH_MAX - 1))
 | 
						|
    strcat (path, getenv ("HOME"));
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if (strlen (path) < (PATH_MAX - 1 - strlen ("/.artec_eplus48u/")))
 | 
						|
    strcat (path, "/.artec_eplus48u/");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  /*try to load black shading file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48ushading_black")))
 | 
						|
    strcat (filename, "artec48ushading_black");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to read black shading file: \"%s\"\n", filename));
 | 
						|
 | 
						|
  f = fopen (filename, "rb");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  /*read values */
 | 
						|
  cnt = fread (s->shading_buffer_b, sizeof (unsigned char), 30720*s->dev->epro_mult, f); /*epro*/
 | 
						|
  if (cnt != (30720*s->dev->epro_mult)) /*epro*/
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not load black shading file\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*try to load white shading file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48ushading_white")))
 | 
						|
    strcat (filename, "artec48ushading_white");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to read white shading file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "rb");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt = fread (s->shading_buffer_w, sizeof (unsigned char), 30720*s->dev->epro_mult, f);/*epro*/
 | 
						|
  if (cnt != (30720*s->dev->epro_mult)) /*epro*/
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not load white shading file\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*try to load offset file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48uoffset")))
 | 
						|
    strcat (filename, "artec48uoffset");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to read offset file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "rb");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt =
 | 
						|
    fread (&s->dev->artec_48u_afe_params, sizeof (Artec48U_AFE_Parameters), 1,
 | 
						|
	   f);
 | 
						|
  if (cnt != 1)
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not load offset file\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*load exposure file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48uexposure")))
 | 
						|
    strcat (filename, "artec48uexposure");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to read exposure file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "rb");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt =
 | 
						|
    fread (&s->dev->artec_48u_exposure_params,
 | 
						|
	   sizeof (Artec48U_Exposure_Parameters), 1, f);
 | 
						|
  if (cnt != 1)
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not load exposure file\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
  s->calibrated = SANE_TRUE;
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
save_calibration_data (Artec48U_Scanner * s)
 | 
						|
{
 | 
						|
  SANE_Status status = SANE_STATUS_GOOD;
 | 
						|
  FILE *f = 0;
 | 
						|
  size_t cnt;
 | 
						|
  char path[PATH_MAX];
 | 
						|
  char filename[PATH_MAX];
 | 
						|
  mode_t mode = S_IRUSR | S_IWUSR;
 | 
						|
 | 
						|
  path[0] = 0;
 | 
						|
  if (strlen (getenv ("HOME")) < (PATH_MAX - 1))
 | 
						|
    strcat (path, getenv ("HOME"));
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if (strlen (path) < (PATH_MAX - 1 - strlen ("/.artec_eplus48u/")))
 | 
						|
    strcat (path, "/.artec_eplus48u/");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  /*try to save black shading file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48ushading_black")))
 | 
						|
    strcat (filename, "artec48ushading_black");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to save black shading file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "w");
 | 
						|
  if (!f)
 | 
						|
    {
 | 
						|
      XDBG ((1, "Could not save artec48ushading_black\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  if (chmod (filename, mode) != 0)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  /*read values */
 | 
						|
  cnt = fwrite (s->shading_buffer_b, sizeof (unsigned char), 30720*s->dev->epro_mult, f); /*epro*/
 | 
						|
  XDBG ((1, "Wrote %li bytes to black shading buffer \n", (u_long) cnt));
 | 
						|
  if (cnt != (30720*s->dev->epro_mult))/*epro*/
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not write black shading buffer\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*try to save white shading file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48ushading_white")))
 | 
						|
    strcat (filename, "artec48ushading_white");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to save white shading file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "w");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  if (chmod (filename, mode) != 0)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt = fwrite (s->shading_buffer_w, sizeof (unsigned char), 30720*s->dev->epro_mult, f);/*epro*/
 | 
						|
  if (cnt != (30720*s->dev->epro_mult)) /*epro*/
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not write white shading buffer\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*try to save offset file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48uoffset")))
 | 
						|
    strcat (filename, "artec48uoffset");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to write offset file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "w");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  if (chmod (filename, mode) != 0)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt =
 | 
						|
    fwrite (&s->dev->artec_48u_afe_params, sizeof (Artec48U_AFE_Parameters),
 | 
						|
	    1, f);
 | 
						|
  if (cnt != 1)
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not write afe values\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
 | 
						|
  /*try to write exposure file */
 | 
						|
  strcpy (filename, path);
 | 
						|
  if (strlen (filename) < (PATH_MAX - 1 - strlen ("artec48uexposure")))
 | 
						|
    strcat (filename, "artec48uexposure");
 | 
						|
  else
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((1, "Try to write exposure file: \"%s\"\n", filename));
 | 
						|
  f = fopen (filename, "w");
 | 
						|
  if (!f)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  if (chmod (filename, mode) != 0)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  /*read values */
 | 
						|
  cnt =
 | 
						|
    fwrite (&s->dev->artec_48u_exposure_params,
 | 
						|
	    sizeof (Artec48U_Exposure_Parameters), 1, f);
 | 
						|
  if (cnt != 1)
 | 
						|
    {
 | 
						|
      fclose (f);
 | 
						|
      XDBG ((1, "Could not write exposure values\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  fclose (f);
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
 | 
						|
{
 | 
						|
  SANE_Status status = SANE_STATUS_INVAL;
 | 
						|
  Artec48U_Device *dev = 0;
 | 
						|
  Artec48U_Scanner *s = 0;
 | 
						|
 | 
						|
  if (!devicename)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
  XDBG ((2, "sane_open: devicename = \"%s\"\n", devicename));
 | 
						|
 | 
						|
 | 
						|
  if (devicename[0])
 | 
						|
    {
 | 
						|
      for (dev = first_dev; dev; dev = dev->next)
 | 
						|
	{
 | 
						|
	  if (strcmp (dev->sane.name, devicename) == 0)
 | 
						|
	    {
 | 
						|
	      XDBG ((2, "sane_open: found matching device %s\n",
 | 
						|
		   dev->sane.name));
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      if (!dev)
 | 
						|
	{
 | 
						|
	  status = attach (devicename, &dev);
 | 
						|
	  if (status != SANE_STATUS_GOOD)
 | 
						|
	    XDBG ((2, "sane_open: attach failed %s\n", devicename));
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* empty devicename -> use first device */
 | 
						|
      XDBG ((2, "sane_open: empty devicename\n"));
 | 
						|
      dev = first_dev;
 | 
						|
    }
 | 
						|
  if (!dev)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  status = artec48u_device_open (dev);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "could not open device\n"));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  XDBG ((2, "sane_open: opening device `%s', handle = %p\n", dev->sane.name,
 | 
						|
       (void *) dev));
 | 
						|
 | 
						|
  XDBG ((1, "sane_open - %s\n", dev->sane.name));
 | 
						|
  XDBG ((2, "sane_open: try to open %s\n", dev->sane.name));
 | 
						|
 | 
						|
  status = artec48u_device_activate (dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "could not activate device\n"));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  /* We do not check anymore, whether the firmware is already loaded */
 | 
						|
  /* because that caused problems after rebooting; furthermore, loading */
 | 
						|
  /* of the firmware is fast, therefore the test doesn't make much sense */
 | 
						|
  status = download_firmware_file (dev);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((3, "download_firmware_file failed\n"));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  /* If a scan is interrupted without sending stop_scan, bad things happen.
 | 
						|
   * Send the stop scan command now just in case. */
 | 
						|
  artec48u_stop_scan (dev);
 | 
						|
 | 
						|
  artec48u_wait_for_positioning (dev);
 | 
						|
 | 
						|
  artec48u_scanner_new (dev, &s);
 | 
						|
  init_calibrator (s);
 | 
						|
  s->next = first_handle;
 | 
						|
  first_handle = s;
 | 
						|
  *handle = s;
 | 
						|
 | 
						|
  status = init_options (s);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return status;
 | 
						|
  /*Try to load the calibration values */
 | 
						|
  status = load_calibration_data (s);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_close (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *prev, *s;
 | 
						|
 | 
						|
  XDBG ((5, "sane_close: start\n"));
 | 
						|
 | 
						|
  /* 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)
 | 
						|
    {
 | 
						|
      XDBG ((5, "close: invalid handle %p\n", handle));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  artec48u_device_close (s->dev);
 | 
						|
  artec48u_scanner_free (s);
 | 
						|
  XDBG ((5, "sane_close: exit\n"));
 | 
						|
}
 | 
						|
 | 
						|
const SANE_Option_Descriptor *
 | 
						|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
 | 
						|
  if ((unsigned) option >= NUM_OPTIONS)
 | 
						|
    return 0;
 | 
						|
  XDBG ((5, "sane_get_option_descriptor: option = %s (%d)\n",
 | 
						|
       s->opt[option].name, option));
 | 
						|
  return s->opt + option;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_control_option (SANE_Handle handle, SANE_Int option,
 | 
						|
		     SANE_Action action, void *value, SANE_Int * info)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
#ifdef ARTEC48U_USE_BUTTONS
 | 
						|
  SANE_Int button_state;
 | 
						|
#endif
 | 
						|
  SANE_Status status;
 | 
						|
  XDBG ((8, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
 | 
						|
       (void *) handle, option, action, (void *) value, (void *) info));
 | 
						|
 | 
						|
  if (info)
 | 
						|
    *info = 0;
 | 
						|
 | 
						|
  if (option < 0 || option >= NUM_OPTIONS)
 | 
						|
    return SANE_STATUS_INVAL;	/* Unknown option ... */
 | 
						|
 | 
						|
  if (!SANE_OPTION_IS_ACTIVE (s->opt[option].cap))
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  switch (action)
 | 
						|
    {
 | 
						|
    case SANE_ACTION_SET_VALUE:
 | 
						|
      if (s->scanning == SANE_TRUE)
 | 
						|
	return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
      if (!SANE_OPTION_IS_SETTABLE (s->opt[option].cap))
 | 
						|
	return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
      status = sanei_constrain_value (s->opt + option, value, info);
 | 
						|
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
 | 
						|
      switch (option)
 | 
						|
	{
 | 
						|
	case OPT_RESOLUTION:
 | 
						|
          if(s->dev->is_epro != 0)
 | 
						|
	  {
 | 
						|
            if((s->val[option].w == 1200) && (*(SANE_Word *) value < 1200))
 | 
						|
            {
 | 
						|
              s->opt[OPT_BIT_DEPTH].constraint.word_list = bitdepth_list;
 | 
						|
	      *info |= SANE_INFO_RELOAD_OPTIONS;
 | 
						|
            }
 | 
						|
            else if((s->val[option].w < 1200) && (*(SANE_Word *) value == 1200))
 | 
						|
            {
 | 
						|
              s->opt[OPT_BIT_DEPTH].constraint.word_list = bitdepth_list2;
 | 
						|
              if(s->val[OPT_BIT_DEPTH].w > 8)
 | 
						|
                s->val[OPT_BIT_DEPTH].w = 8;
 | 
						|
	      *info |= SANE_INFO_RELOAD_OPTIONS;
 | 
						|
            }
 | 
						|
	  }
 | 
						|
	  s->val[option].w = *(SANE_Word *) value;
 | 
						|
	  if (info)
 | 
						|
	  {
 | 
						|
            *info |= SANE_INFO_RELOAD_PARAMS;
 | 
						|
          }
 | 
						|
	  break;
 | 
						|
        /* fall through */
 | 
						|
	case OPT_BIT_DEPTH:
 | 
						|
	case OPT_TL_X:
 | 
						|
	case OPT_TL_Y:
 | 
						|
	case OPT_BR_X:
 | 
						|
	case OPT_BR_Y:
 | 
						|
	  s->val[option].w = *(SANE_Word *) value;
 | 
						|
	  if (info)
 | 
						|
	    *info |= SANE_INFO_RELOAD_PARAMS;
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	  /* fall through */
 | 
						|
	case OPT_BLACK_LEVEL:
 | 
						|
	case OPT_BRIGHTNESS:
 | 
						|
	case OPT_CONTRAST:
 | 
						|
	case OPT_GAMMA:
 | 
						|
	case OPT_GAMMA_R:
 | 
						|
	case OPT_GAMMA_G:
 | 
						|
	case OPT_GAMMA_B:
 | 
						|
	case OPT_CALIBRATE:
 | 
						|
	case OPT_CALIBRATE_SHADING:
 | 
						|
	  s->val[option].w = *(SANE_Word *) value;
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	case OPT_DEFAULT_ENHANCEMENTS:
 | 
						|
	  s->val[OPT_GAMMA].w = SANE_FIX (s->dev->gamma_master);
 | 
						|
	  if (strcmp (s->val[OPT_SCAN_MODE].s, mode_list[2]) == 0)
 | 
						|
	    {
 | 
						|
	      s->val[OPT_GAMMA_R].w = SANE_FIX (s->dev->gamma_r);
 | 
						|
	      s->val[OPT_GAMMA_G].w = SANE_FIX (s->dev->gamma_g);
 | 
						|
	      s->val[OPT_GAMMA_B].w = SANE_FIX (s->dev->gamma_b);
 | 
						|
	    }
 | 
						|
	  s->val[OPT_BRIGHTNESS].w = 0;
 | 
						|
	  s->val[OPT_CONTRAST].w = 0;
 | 
						|
	  if (info)
 | 
						|
	    *info |= SANE_INFO_RELOAD_OPTIONS;
 | 
						|
	  break;
 | 
						|
	case OPT_SCAN_MODE:
 | 
						|
	  if (s->val[option].s)
 | 
						|
	    free (s->val[option].s);
 | 
						|
	  s->val[option].s = strdup (value);
 | 
						|
	  if (strcmp (s->val[OPT_SCAN_MODE].s, mode_list[0]) == 0)
 | 
						|
	    {
 | 
						|
	      s->opt[OPT_GAMMA_R].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_G].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_B].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BLACK_LEVEL].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
 | 
						|
	    }
 | 
						|
	  else if (strcmp (s->val[OPT_SCAN_MODE].s, mode_list[1]) == 0)
 | 
						|
	    {
 | 
						|
	      s->opt[OPT_GAMMA_R].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_G].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_B].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BLACK_LEVEL].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      s->opt[OPT_GAMMA_R].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_G].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_GAMMA_B].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BLACK_LEVEL].cap |= SANE_CAP_INACTIVE;
 | 
						|
	      s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
 | 
						|
	    }
 | 
						|
	  if (info)
 | 
						|
	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    case SANE_ACTION_GET_VALUE:
 | 
						|
      switch (option)
 | 
						|
	{
 | 
						|
	  /* word options: */
 | 
						|
	case OPT_NUM_OPTS:
 | 
						|
	case OPT_RESOLUTION:
 | 
						|
	case OPT_BIT_DEPTH:
 | 
						|
	case OPT_BLACK_LEVEL:
 | 
						|
	case OPT_TL_X:
 | 
						|
	case OPT_TL_Y:
 | 
						|
	case OPT_BR_X:
 | 
						|
	case OPT_BR_Y:
 | 
						|
	case OPT_BRIGHTNESS:
 | 
						|
	case OPT_CONTRAST:
 | 
						|
	case OPT_GAMMA:
 | 
						|
	case OPT_GAMMA_R:
 | 
						|
	case OPT_GAMMA_G:
 | 
						|
	case OPT_GAMMA_B:
 | 
						|
	case OPT_CALIBRATE:
 | 
						|
	case OPT_CALIBRATE_SHADING:
 | 
						|
	  *(SANE_Word *) value = (SANE_Word) s->val[option].w;
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	  /* string options: */
 | 
						|
	case OPT_SCAN_MODE:
 | 
						|
	  strcpy (value, s->val[option].s);
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
#ifdef ARTEC48U_USE_BUTTONS
 | 
						|
	case OPT_BUTTON_STATE:
 | 
						|
	  status = artec48u_check_buttons (s->dev, &button_state);
 | 
						|
	  if (status == SANE_STATUS_GOOD)
 | 
						|
	    {
 | 
						|
	      s->val[option].w = button_state;
 | 
						|
	      *(SANE_Int *) value = (SANE_Int) s->val[option].w;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      s->val[option].w = 0;
 | 
						|
	      *(SANE_Int *) value = 0;
 | 
						|
	    }
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
  SANE_Status status;
 | 
						|
  SANE_Word resx;
 | 
						|
/*  int scan_mode;*/
 | 
						|
  SANE_String str = s->val[OPT_SCAN_MODE].s;
 | 
						|
  int tlx;
 | 
						|
  int tly;
 | 
						|
  int brx;
 | 
						|
  int bry;
 | 
						|
  int tmp;
 | 
						|
  XDBG ((2, "sane_get_params: string %s\n", str));
 | 
						|
  XDBG ((2, "sane_get_params: enter\n"));
 | 
						|
 | 
						|
  tlx = s->val[OPT_TL_X].w;
 | 
						|
  tly = s->val[OPT_TL_Y].w;
 | 
						|
  brx = s->val[OPT_BR_X].w;
 | 
						|
  bry = s->val[OPT_BR_Y].w;
 | 
						|
 | 
						|
  /*make sure, that tlx < brx and tly < bry
 | 
						|
     this will NOT change the options */
 | 
						|
  if (tlx > brx)
 | 
						|
    {
 | 
						|
      tmp = tlx;
 | 
						|
      tlx = brx;
 | 
						|
      brx = tmp;
 | 
						|
    }
 | 
						|
  if (tly > bry)
 | 
						|
    {
 | 
						|
      tmp = tly;
 | 
						|
      tly = bry;
 | 
						|
      bry = tmp;
 | 
						|
    }
 | 
						|
  resx = s->val[OPT_RESOLUTION].w;
 | 
						|
  str = s->val[OPT_SCAN_MODE].s;
 | 
						|
 | 
						|
  s->request.color = SANE_TRUE;
 | 
						|
  if ((strcmp (str, mode_list[0]) == 0) || (strcmp (str, mode_list[1]) == 0))
 | 
						|
    s->request.color = SANE_FALSE;
 | 
						|
  else
 | 
						|
    s->request.color = SANE_TRUE;
 | 
						|
  s->request.depth = s->val[OPT_BIT_DEPTH].w;
 | 
						|
  if (strcmp (str, mode_list[0]) == 0)
 | 
						|
    s->request.depth = 8;
 | 
						|
  s->request.y0 = tly;	      /**< Top boundary */
 | 
						|
  s->request.x0 = SANE_FIX (216.0) - brx;	/**< left boundary */
 | 
						|
  s->request.xs = brx - tlx;	    /**< Width */
 | 
						|
  s->request.ys = bry - tly;	    /**< Height */
 | 
						|
  s->request.xdpi = resx;      /**< Horizontal resolution */
 | 
						|
  s->request.ydpi = resx;      /**< Vertical resolution */
 | 
						|
  /*epro*/
 | 
						|
  if ((resx == 1200) && (s->dev->is_epro == 0))
 | 
						|
    s->request.xdpi = 600;/**< Vertical resolution */
 | 
						|
 | 
						|
  status = artec48u_setup_scan (s, &(s->request), SA_SCAN,
 | 
						|
				SANE_TRUE, &(s->params));
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
/*DBG(1, "sane_get_params: scan_mode %i\n",scan_mode);*/
 | 
						|
 | 
						|
  params->depth = s->params.depth;
 | 
						|
  s->params.lineart = SANE_FALSE;
 | 
						|
  if (s->params.color == SANE_TRUE)
 | 
						|
    {
 | 
						|
      params->format = SANE_FRAME_RGB;
 | 
						|
      params->bytes_per_line = s->params.pixel_xs * 3;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      params->format = SANE_FRAME_GRAY;
 | 
						|
      params->bytes_per_line = s->params.pixel_xs;
 | 
						|
      if (strcmp (str, mode_list[0]) == 0)
 | 
						|
	{
 | 
						|
	  params->depth = 1;
 | 
						|
	  params->bytes_per_line = (s->params.pixel_xs + 7) / 8;
 | 
						|
	  s->params.lineart = SANE_TRUE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  if ((resx == 1200) && (s->dev->is_epro == 0))
 | 
						|
    {
 | 
						|
      if (params->depth == 1)
 | 
						|
	params->bytes_per_line = (s->params.pixel_xs * 2 + 7) / 8;
 | 
						|
      else
 | 
						|
	params->bytes_per_line *= 2;
 | 
						|
    }
 | 
						|
  if (params->depth == 16)
 | 
						|
    params->bytes_per_line *= 2;
 | 
						|
  params->last_frame = SANE_TRUE;
 | 
						|
  params->pixels_per_line = s->params.pixel_xs;
 | 
						|
  if ((resx == 1200) && (s->dev->is_epro == 0))
 | 
						|
    params->pixels_per_line *= 2;
 | 
						|
  params->lines = s->params.pixel_ys;
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_start (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
  SANE_Status status;
 | 
						|
  int fds[2];
 | 
						|
 | 
						|
  if (s->scanning)
 | 
						|
    {
 | 
						|
      return SANE_STATUS_DEVICE_BUSY;
 | 
						|
    }
 | 
						|
 | 
						|
  if (sane_get_parameters (handle, &s->sane_params) != SANE_STATUS_GOOD)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if ((s->calibrated != SANE_TRUE) || (s->val[OPT_CALIBRATE].w == SANE_TRUE))
 | 
						|
    {
 | 
						|
      XDBG ((1, "Must calibrate scanner\n"));
 | 
						|
      status = calibrate_scanner (s);
 | 
						|
      if (status != SANE_STATUS_GOOD)
 | 
						|
	return status;
 | 
						|
      s->calibrated = SANE_TRUE;
 | 
						|
    }
 | 
						|
  if (sane_get_parameters (handle, &s->sane_params) != SANE_STATUS_GOOD)
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  calculate_brightness (s);
 | 
						|
  calculate_contrast (s);
 | 
						|
  calculateGamma (s);
 | 
						|
  calculateGammaRed (s);
 | 
						|
  calculateGammaGreen (s);
 | 
						|
  calculateGammaBlue (s);
 | 
						|
 | 
						|
  artec48u_carriage_home (s->dev);
 | 
						|
 | 
						|
  artec48u_wait_for_positioning (s->dev);
 | 
						|
  s->reader = NULL;
 | 
						|
 | 
						|
  s->scanning = SANE_TRUE;
 | 
						|
  s->byte_cnt = 0;
 | 
						|
  s->lines_to_read = s->params.pixel_ys;
 | 
						|
  /*allocate a buffer, that can hold a complete scan line */
 | 
						|
  /*If resolution is 1200 dpi and we are scanning in lineart mode,
 | 
						|
     then we also allocate a lineart_buffer, which can hold a complete scan line
 | 
						|
     in 8 bit/gray. This makes interpolation easier. */
 | 
						|
  if ((s->params.ydpi == 1200) && (s->dev->is_epro == 0))
 | 
						|
    {
 | 
						|
      if (s->request.color == SANE_TRUE)
 | 
						|
	{
 | 
						|
	  s->line_buffer = (SANE_Byte *) malloc (s->params.scan_bpl * 8);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  s->line_buffer = (SANE_Byte *) malloc (s->params.scan_bpl * 4);
 | 
						|
	  /*lineart ? */
 | 
						|
	  if (strcmp (s->val[OPT_SCAN_MODE].s, mode_list[0]) == 0)
 | 
						|
	    s->lineart_buffer = (SANE_Byte *) malloc (s->params.pixel_xs * 2);
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (s->request.color == SANE_TRUE)
 | 
						|
	s->line_buffer = (SANE_Byte *) malloc (s->params.scan_bpl * 4);
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  s->line_buffer = (SANE_Byte *) malloc (s->params.scan_bpl * 2);
 | 
						|
	  /*lineart ? */
 | 
						|
	  if (strcmp (s->val[OPT_SCAN_MODE].s, mode_list[0]) == 0)
 | 
						|
	    s->lineart_buffer = (SANE_Byte *) malloc (s->params.pixel_xs * 2);
 | 
						|
	}
 | 
						|
    }
 | 
						|
  if (pipe (fds) < 0)
 | 
						|
    {
 | 
						|
      s->scanning = SANE_FALSE;
 | 
						|
      XDBG ((2, "sane_start: pipe failed (%s)\n", strerror (errno)));
 | 
						|
      return SANE_STATUS_IO_ERROR;
 | 
						|
    }
 | 
						|
  status = artec48u_scanner_start_scan (s, &s->request, &s->params);
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      XDBG ((2, "sane_start: could not start scan\n"));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
  s->pipe = fds[0];
 | 
						|
  s->reader_pipe = fds[1];
 | 
						|
  s->reader_pid = sanei_thread_begin (reader_process, s);
 | 
						|
  cancelRead = SANE_FALSE;
 | 
						|
  if (s->reader_pid < 0)
 | 
						|
    {
 | 
						|
      s->scanning = SANE_FALSE;
 | 
						|
      XDBG ((2, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno)));
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
  signal (SIGCHLD, sig_chldhandler);
 | 
						|
 | 
						|
  if (sanei_thread_is_forked()) close (s->reader_pipe);
 | 
						|
 | 
						|
  XDBG ((1, "sane_start done\n"));
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;	/* parent */
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_read (SANE_Handle handle, SANE_Byte * data,
 | 
						|
	   SANE_Int max_length, SANE_Int * length)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
  ssize_t nread;
 | 
						|
 | 
						|
  *length = 0;
 | 
						|
 | 
						|
  /* here we read all data from the driver... */
 | 
						|
  nread = read (s->pipe, data, max_length);
 | 
						|
  XDBG ((3, "sane_read - read %ld bytes\n", (long) nread));
 | 
						|
  if (cancelRead == SANE_TRUE)
 | 
						|
    {
 | 
						|
      return do_cancel (s, SANE_TRUE);
 | 
						|
    }
 | 
						|
 | 
						|
  if (nread < 0)
 | 
						|
    {
 | 
						|
      if (EAGAIN == errno)
 | 
						|
	{
 | 
						|
	  /* if we already had read the picture, so it's okay and stop */
 | 
						|
	  if (s->eof == SANE_TRUE)
 | 
						|
	    {
 | 
						|
	      sanei_thread_waitpid (s->reader_pid, 0);
 | 
						|
	      s->reader_pid = -1;
 | 
						|
	      artec48u_scanner_stop_scan (s);
 | 
						|
	      artec48u_carriage_home (s->dev);
 | 
						|
	      return close_pipe (s);
 | 
						|
	    }
 | 
						|
	  /* else force the frontend to try again */
 | 
						|
	  return SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  XDBG ((4, "ERROR: errno=%d\n", errno));
 | 
						|
	  do_cancel (s, SANE_TRUE);
 | 
						|
	  return SANE_STATUS_IO_ERROR;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  *length = nread;
 | 
						|
  s->byte_cnt += nread;
 | 
						|
 | 
						|
  /* nothing read means that we're finished OR we had a problem... */
 | 
						|
  if (0 == nread)
 | 
						|
    {
 | 
						|
      if (0 == s->byte_cnt)
 | 
						|
	{
 | 
						|
	  s->exit_code = sanei_thread_get_status (s->reader_pid);
 | 
						|
 | 
						|
	  if (SANE_STATUS_GOOD != s->exit_code)
 | 
						|
	    {
 | 
						|
	      close_pipe (s);
 | 
						|
	      return s->exit_code;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      return close_pipe (s);
 | 
						|
    }
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_cancel (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = handle;
 | 
						|
  XDBG ((2, "sane_cancel: handle = %p\n", handle));
 | 
						|
  if (s->scanning)
 | 
						|
    do_cancel (s, SANE_FALSE);
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = (Artec48U_Scanner *) handle;
 | 
						|
 | 
						|
  XDBG ((1, "sane_set_io_mode: non_blocking=%d\n", non_blocking));
 | 
						|
 | 
						|
  if (!s->scanning)
 | 
						|
    {
 | 
						|
      XDBG ((4, "ERROR: not scanning !\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (-1 == s->pipe)
 | 
						|
    {
 | 
						|
      XDBG ((4, "ERROR: not supported !\n"));
 | 
						|
      return SANE_STATUS_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
  if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
 | 
						|
    {
 | 
						|
      XDBG ((4, "ERROR: can?t set to non-blocking mode !\n"));
 | 
						|
      return SANE_STATUS_IO_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
  XDBG ((1, "sane_set_io_mode done\n"));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
 | 
						|
{
 | 
						|
  Artec48U_Scanner *s = (Artec48U_Scanner *) handle;
 | 
						|
 | 
						|
  XDBG ((1, "sane_get_select_fd\n"));
 | 
						|
 | 
						|
  if (!s->scanning)
 | 
						|
    {
 | 
						|
      XDBG ((4, "ERROR: not scanning !\n"));
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  *fd = s->pipe;
 | 
						|
 | 
						|
  XDBG ((1, "sane_get_select_fd done\n"));
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
 | 
						|
{
 | 
						|
  Artec48U_Device *device = 0;
 | 
						|
  SANE_Status status;
 | 
						|
  char str[PATH_MAX] = _DEFAULT_DEVICE;
 | 
						|
  char temp[PATH_MAX];
 | 
						|
  size_t len;
 | 
						|
  FILE *fp;
 | 
						|
  double gamma_m = 1.9;
 | 
						|
  double gamma_r = 1.0;
 | 
						|
  double gamma_g = 1.0;
 | 
						|
  double gamma_b = 1.0;
 | 
						|
  int epro_default = 0;
 | 
						|
 | 
						|
  DBG_INIT ();
 | 
						|
  eProMult = 1;
 | 
						|
  isEPro = 0;
 | 
						|
  temp[0] = 0;
 | 
						|
  strcpy (vendor_string, "Artec");
 | 
						|
  strcpy (model_string, "E+ 48U");
 | 
						|
 | 
						|
  sanei_usb_init ();
 | 
						|
  sanei_thread_init ();
 | 
						|
 | 
						|
  /* do some presettings... */
 | 
						|
  auth = authorize;
 | 
						|
 | 
						|
  if (version_code != NULL)
 | 
						|
    *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
 | 
						|
 | 
						|
  fp = sanei_config_open (ARTEC48U_CONFIG_FILE);
 | 
						|
 | 
						|
  /* default to _DEFAULT_DEVICE instead of insisting on config file */
 | 
						|
  if (NULL == fp)
 | 
						|
    {
 | 
						|
      status = attach (_DEFAULT_DEVICE, &device);
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  while (sanei_config_read (str, sizeof (str), fp))
 | 
						|
    {
 | 
						|
      XDBG ((1, "sane_init, >%s<\n", str));
 | 
						|
      /* ignore line comments */
 | 
						|
      if (str[0] == '#')
 | 
						|
	continue;
 | 
						|
      len = strlen (str);
 | 
						|
      /* ignore empty lines */
 | 
						|
      if (0 == len)
 | 
						|
	continue;
 | 
						|
      /* check for options */
 | 
						|
      if (0 == strncmp (str, "option", 6))
 | 
						|
	{
 | 
						|
	  if(decodeVal (str,"ePlusPro",_INT, &isEPro,&epro_default) == SANE_TRUE)
 | 
						|
	  {
 | 
						|
            eProMult = 1;
 | 
						|
            if(isEPro != 0)
 | 
						|
            {
 | 
						|
              eProMult = 2;
 | 
						|
              XDBG ((3, "Is Artec E Pro\n"));
 | 
						|
            }
 | 
						|
            else
 | 
						|
              XDBG ((3, "Is Artec E+ 48U\n"));
 | 
						|
          }
 | 
						|
	  decodeVal (str, "masterGamma", _FLOAT, &gamma_master_default,
 | 
						|
		     &gamma_m);
 | 
						|
	  decodeVal (str, "redGamma", _FLOAT, &gamma_r_default, &gamma_r);
 | 
						|
	  decodeVal (str, "greenGamma", _FLOAT, &gamma_g_default, &gamma_g);
 | 
						|
	  decodeVal (str, "blueGamma", _FLOAT, &gamma_b_default, &gamma_b);
 | 
						|
	  decodeVal (str, "redOffset", _BYTE, &afe_params.r_offset,
 | 
						|
		     &default_afe_params.r_offset);
 | 
						|
	  decodeVal (str, "greenOffset", _BYTE, &afe_params.g_offset,
 | 
						|
		     &default_afe_params.g_offset);
 | 
						|
	  decodeVal (str, "blueOffset", _BYTE, &afe_params.b_offset,
 | 
						|
		     &default_afe_params.b_offset);
 | 
						|
 | 
						|
	  decodeVal (str, "redExposure", _INT, &exp_params.r_time,
 | 
						|
		     &default_exp_params.r_time);
 | 
						|
	  decodeVal (str, "greenExposure", _INT, &exp_params.g_time,
 | 
						|
		     &default_exp_params.g_time);
 | 
						|
	  decodeVal (str, "blueExposure", _INT, &exp_params.b_time,
 | 
						|
		     &default_exp_params.b_time);
 | 
						|
 | 
						|
	  decodeVal (str, "modelString", _STRING, model_string, model_string);
 | 
						|
	  decodeVal (str, "vendorString", _STRING, vendor_string,
 | 
						|
		     vendor_string);
 | 
						|
 | 
						|
	  decodeVal (str, "artecFirmwareFile", _STRING, firmwarePath,
 | 
						|
		     firmwarePath);
 | 
						|
	}
 | 
						|
      else if (0 == strncmp (str, "usb", 3))
 | 
						|
	{
 | 
						|
	  if (temp[0] != 0)
 | 
						|
	    {
 | 
						|
	      XDBG ((3, "trying to attach: %s\n", temp));
 | 
						|
	      XDBG ((3, "      vendor: %s\n", vendor_string));
 | 
						|
	      XDBG ((3, "      model: %s\n", model_string));
 | 
						|
	      sanei_usb_attach_matching_devices (temp, attach_one_device);
 | 
						|
	    }
 | 
						|
	  /*save config line in temp */
 | 
						|
	  strcpy (temp, str);
 | 
						|
	}
 | 
						|
      else if (0 == strncmp (str, "device", 6))
 | 
						|
	{
 | 
						|
	  if (SANE_TRUE == decodeDevName (str, devName))
 | 
						|
	    {
 | 
						|
	      if (devName[0] != 0)
 | 
						|
		sanei_usb_attach_matching_devices (devName,
 | 
						|
						   attach_one_device);
 | 
						|
	      temp[0] = 0;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  /* ignore other stuff... */
 | 
						|
	  XDBG ((1, "ignoring >%s<\n", str));
 | 
						|
	}
 | 
						|
    }
 | 
						|
  if (temp[0] != 0)
 | 
						|
    {
 | 
						|
      XDBG ((3, "trying to attach: %s\n", temp));
 | 
						|
      XDBG ((3, "      vendor: %s\n", vendor_string));
 | 
						|
      XDBG ((3, "      model: %s\n", model_string));
 | 
						|
      sanei_usb_attach_matching_devices (temp, attach_one_device);
 | 
						|
      temp[0] = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  fclose (fp);
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_exit (void)
 | 
						|
{
 | 
						|
  Artec48U_Device *dev, *next;
 | 
						|
 | 
						|
  XDBG ((5, "sane_exit: start\n"));
 | 
						|
  for (dev = first_dev; dev; dev = next)
 | 
						|
    {
 | 
						|
      next = dev->next;
 | 
						|
      /*function will check, whether device is really open */
 | 
						|
      artec48u_device_close (dev);
 | 
						|
      artec48u_device_free (dev);
 | 
						|
    }
 | 
						|
  XDBG ((5, "sane_exit: exit\n"));
 | 
						|
  return;
 | 
						|
}
 |