kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			2735 wiersze
		
	
	
		
			70 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			2735 wiersze
		
	
	
		
			70 KiB
		
	
	
	
		
			C
		
	
	
/* HP Scanjet 3900 series - SANE Backend controller
 | 
						|
   Copyright (C) 2005-2009 Jonathan Bravo Lopez <jkdsoft@gmail.com>
 | 
						|
 | 
						|
   This file is part of the SANE package.
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or
 | 
						|
   modify it under the terms of the GNU General Public License
 | 
						|
   as published by the Free Software Foundation; either version 2
 | 
						|
   of the License, or (at your option) any later version.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
   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.
 | 
						|
*/
 | 
						|
 | 
						|
/* Backend Code for SANE*/
 | 
						|
#define HP3900_CONFIG_FILE "hp3900.conf"
 | 
						|
#define GAMMA_DEFAULT 1.0
 | 
						|
 | 
						|
#include "../include/sane/config.h"
 | 
						|
#include "../include/sane/sane.h"
 | 
						|
#include "../include/sane/sanei.h"
 | 
						|
#include "../include/sane/sanei_backend.h"
 | 
						|
#include "../include/sane/sanei_config.h"
 | 
						|
#include "../include/sane/saneopts.h"
 | 
						|
#include "../include/sane/sanei_usb.h"
 | 
						|
#include "../include/sane/sanei_debug.h"
 | 
						|
 | 
						|
#include "hp3900_rts8822.c"
 | 
						|
 | 
						|
struct st_convert
 | 
						|
{
 | 
						|
  SANE_Int colormode;
 | 
						|
  SANE_Int depth;
 | 
						|
  SANE_Int threshold;
 | 
						|
  SANE_Int negative;
 | 
						|
  SANE_Int real_depth;
 | 
						|
};
 | 
						|
 | 
						|
/* options enumerator */
 | 
						|
typedef enum
 | 
						|
{
 | 
						|
  opt_begin = 0,
 | 
						|
 | 
						|
  grp_geometry,
 | 
						|
  opt_tlx, opt_tly, opt_brx, opt_bry,
 | 
						|
  opt_resolution,
 | 
						|
 | 
						|
  /* gamma tables */
 | 
						|
  opt_gamma_red,
 | 
						|
  opt_gamma_green,
 | 
						|
  opt_gamma_blue,
 | 
						|
 | 
						|
  opt_scantype,
 | 
						|
  opt_colormode,
 | 
						|
  opt_depth,
 | 
						|
  opt_threshold,
 | 
						|
 | 
						|
  /* debugging options */
 | 
						|
  grp_debug,
 | 
						|
  opt_model,
 | 
						|
  opt_negative,
 | 
						|
  opt_nogamma,
 | 
						|
  opt_nowshading,
 | 
						|
  opt_realdepth,
 | 
						|
  opt_emulategray,
 | 
						|
  opt_nowarmup,
 | 
						|
  opt_dbgimages,
 | 
						|
  opt_reset,
 | 
						|
 | 
						|
  /* device information */
 | 
						|
  grp_info,
 | 
						|
  opt_chipname,
 | 
						|
  opt_chipid,
 | 
						|
  opt_scancount,
 | 
						|
  opt_infoupdate,
 | 
						|
 | 
						|
  /* supported buttons. RTS8822 supports up to 6 buttons */
 | 
						|
  grp_sensors,
 | 
						|
  opt_button_0,
 | 
						|
  opt_button_1,
 | 
						|
  opt_button_2,
 | 
						|
  opt_button_3,
 | 
						|
  opt_button_4,
 | 
						|
  opt_button_5,
 | 
						|
 | 
						|
  opt_count
 | 
						|
} EOptionIndex;
 | 
						|
 | 
						|
/* linked list of SANE_Device structures */
 | 
						|
typedef struct TDevListEntry
 | 
						|
{
 | 
						|
  struct TDevListEntry *pNext;
 | 
						|
  SANE_Device dev;
 | 
						|
  char *devname;
 | 
						|
} TDevListEntry;
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
  char *pszVendor;
 | 
						|
  char *pszName;
 | 
						|
} TScannerModel;
 | 
						|
 | 
						|
typedef union
 | 
						|
{
 | 
						|
  SANE_Word w;
 | 
						|
  SANE_Word *wa;		/* word array */
 | 
						|
  SANE_String s;
 | 
						|
} TOptionValue;
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
  SANE_Int model;
 | 
						|
  SANE_Option_Descriptor aOptions[opt_count];
 | 
						|
  TOptionValue aValues[opt_count];
 | 
						|
  struct params ScanParams;
 | 
						|
 | 
						|
  /* lists */
 | 
						|
  SANE_String_Const *list_colormodes;
 | 
						|
  SANE_Int *list_depths;
 | 
						|
  SANE_String_Const *list_models;
 | 
						|
  SANE_Int *list_resolutions;
 | 
						|
  SANE_String_Const *list_sources;
 | 
						|
 | 
						|
  SANE_Word *aGammaTable[3];	/* a 16-to-16 bit color lookup table */
 | 
						|
  SANE_Range rng_gamma;
 | 
						|
 | 
						|
  /* reading image */
 | 
						|
  SANE_Byte *image;
 | 
						|
  SANE_Byte *rest;
 | 
						|
  SANE_Int rest_amount;
 | 
						|
  SANE_Int mylin;
 | 
						|
 | 
						|
  /* conversion settings */
 | 
						|
  struct st_convert cnv;
 | 
						|
 | 
						|
  /* ranges */
 | 
						|
  SANE_Range rng_threshold;
 | 
						|
  SANE_Range rng_horizontal;
 | 
						|
  SANE_Range rng_vertical;
 | 
						|
 | 
						|
  SANE_Int scan_count;
 | 
						|
  SANE_Int fScanning;		/* TRUE if actively scanning */
 | 
						|
} TScanner;
 | 
						|
 | 
						|
/* functions to manage backend's options */
 | 
						|
static void options_init (TScanner * scanner);
 | 
						|
static void options_free (TScanner * scanner);
 | 
						|
 | 
						|
/* devices listing */
 | 
						|
static SANE_Int _ReportDevice (TScannerModel * pModel,
 | 
						|
			       const char *pszDeviceName);
 | 
						|
static SANE_Status attach_one_device (SANE_String_Const devname);
 | 
						|
 | 
						|
/* capabilities */
 | 
						|
static SANE_Status bknd_colormodes (TScanner * scanner, SANE_Int model);
 | 
						|
static void bknd_constrains (TScanner * scanner, SANE_Int source,
 | 
						|
			     SANE_Int type);
 | 
						|
static SANE_Status bknd_depths (TScanner * scanner, SANE_Int model);
 | 
						|
static SANE_Status bknd_info (TScanner * scanner);
 | 
						|
static SANE_Status bknd_models (TScanner * scanner);
 | 
						|
static SANE_Status bknd_resolutions (TScanner * scanner, SANE_Int model);
 | 
						|
static SANE_Status bknd_sources (TScanner * scanner, SANE_Int model);
 | 
						|
 | 
						|
/* conversions */
 | 
						|
static void Color_Negative (SANE_Byte * buffer, SANE_Int size,
 | 
						|
			    SANE_Int depth);
 | 
						|
static void Color_to_Gray (SANE_Byte * buffer, SANE_Int size, SANE_Int depth);
 | 
						|
static void Gray_to_Lineart (SANE_Byte * buffer, SANE_Int size,
 | 
						|
			     SANE_Int threshold);
 | 
						|
static void Depth_16_to_8 (SANE_Byte * from_buffer, SANE_Int size,
 | 
						|
			   SANE_Byte * to_buffer);
 | 
						|
 | 
						|
/* gamma functions */
 | 
						|
static void gamma_apply (TScanner * s, SANE_Byte * buffer, SANE_Int size,
 | 
						|
			 SANE_Int depth);
 | 
						|
static SANE_Int gamma_create (TScanner * s, double gamma);
 | 
						|
static void gamma_free (TScanner * s);
 | 
						|
 | 
						|
static SANE_Int Get_Colormode (SANE_String colormode);
 | 
						|
static SANE_Int Get_Model (SANE_String model);
 | 
						|
static SANE_Int Get_Source (SANE_String source);
 | 
						|
static SANE_Int GetUSB_device_model (SANE_String_Const name);
 | 
						|
static size_t max_string_size (const SANE_String_Const strings[]);
 | 
						|
 | 
						|
static SANE_Status get_button_status (TScanner * s);
 | 
						|
 | 
						|
/* reading buffers */
 | 
						|
static SANE_Status img_buffers_alloc (TScanner * scanner, SANE_Int size);
 | 
						|
static SANE_Status img_buffers_free (TScanner * scanner);
 | 
						|
 | 
						|
static SANE_Status option_get (TScanner * scanner, SANE_Int optid,
 | 
						|
			       void *result);
 | 
						|
static SANE_Status option_set (TScanner * scanner, SANE_Int optid,
 | 
						|
			       void *value, SANE_Int * pInfo);
 | 
						|
 | 
						|
static void Set_Coordinates (SANE_Int scantype, SANE_Int resolution,
 | 
						|
			     struct st_coords *coords);
 | 
						|
static SANE_Int set_ScannerModel (SANE_Int proposed, SANE_Int product,
 | 
						|
				  SANE_Int vendor);
 | 
						|
static void Silent_Compile (void);
 | 
						|
static SANE_Status Translate_coords (struct st_coords *coords);
 | 
						|
 | 
						|
/* SANE functions */
 | 
						|
void sane_cancel (SANE_Handle h);
 | 
						|
void sane_close (SANE_Handle h);
 | 
						|
SANE_Status sane_control_option (SANE_Handle h, SANE_Int n,
 | 
						|
				 SANE_Action Action, void *pVal,
 | 
						|
				 SANE_Int * pInfo);
 | 
						|
void sane_exit (void);
 | 
						|
SANE_Status sane_get_devices (const SANE_Device *** device_list,
 | 
						|
			      SANE_Bool local_only);
 | 
						|
const SANE_Option_Descriptor *sane_get_option_descriptor (SANE_Handle h,
 | 
						|
							  SANE_Int n);
 | 
						|
SANE_Status sane_get_parameters (SANE_Handle h, SANE_Parameters * p);
 | 
						|
SANE_Status sane_get_select_fd (SANE_Handle handle, SANE_Int * fd);
 | 
						|
SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize);
 | 
						|
SANE_Status sane_open (SANE_String_Const name, SANE_Handle * h);
 | 
						|
SANE_Status sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen,
 | 
						|
		       SANE_Int * len);
 | 
						|
SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking);
 | 
						|
SANE_Status sane_start (SANE_Handle h);
 | 
						|
 | 
						|
/* variables */
 | 
						|
static struct st_device *device = NULL;
 | 
						|
static TDevListEntry *_pFirstSaneDev = 0;
 | 
						|
static SANE_Int iNumSaneDev = 0;
 | 
						|
static const SANE_Device **_pSaneDevList = 0;
 | 
						|
 | 
						|
/* Own functions */
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_resolutions (TScanner * scanner, SANE_Int model)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_resolutions(*scanner, model=%i)\n", model);
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int *res = NULL;
 | 
						|
 | 
						|
      switch (model)
 | 
						|
	{
 | 
						|
	case BQ5550:
 | 
						|
	case UA4900:
 | 
						|
	  {
 | 
						|
	    SANE_Int myres[] = { 8, 50, 75, 100, 150, 200, 300, 600, 1200 };
 | 
						|
 | 
						|
	    res = (SANE_Int *) malloc (sizeof (myres));
 | 
						|
	    if (res != NULL)
 | 
						|
	      memcpy (res, &myres, sizeof (myres));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case HPG2710:
 | 
						|
	case HP3800:
 | 
						|
	  {
 | 
						|
	    /* 1200 and 2400 dpi are disabled until problems are solved */
 | 
						|
	    SANE_Int myres[] = { 7, 50, 75, 100, 150, 200, 300, 600 };
 | 
						|
 | 
						|
	    res = (SANE_Int *) malloc (sizeof (myres));
 | 
						|
	    if (res != NULL)
 | 
						|
	      memcpy (res, &myres, sizeof (myres));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case HP4370:
 | 
						|
	case HPG3010:
 | 
						|
	case HPG3110:
 | 
						|
	  {
 | 
						|
	    SANE_Int myres[] =
 | 
						|
	      { 10, 50, 75, 100, 150, 200, 300, 600, 1200, 2400, 4800 };
 | 
						|
 | 
						|
	    res = (SANE_Int *) malloc (sizeof (myres));
 | 
						|
	    if (res != NULL)
 | 
						|
	      memcpy (res, &myres, sizeof (myres));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	default:		/* HP3970 & HP4070 & UA4900 */
 | 
						|
	  {
 | 
						|
	    SANE_Int myres[] =
 | 
						|
	      { 9, 50, 75, 100, 150, 200, 300, 600, 1200, 2400 };
 | 
						|
 | 
						|
	    res = (SANE_Int *) malloc (sizeof (myres));
 | 
						|
	    if (res != NULL)
 | 
						|
	      memcpy (res, &myres, sizeof (myres));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      if (res != NULL)
 | 
						|
	{
 | 
						|
	  if (scanner->list_resolutions != NULL)
 | 
						|
	    free (scanner->list_resolutions);
 | 
						|
 | 
						|
	  scanner->list_resolutions = res;
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_models (TScanner * scanner)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_models:\n");
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_String_Const *model = NULL;
 | 
						|
 | 
						|
      /* at this moment all devices use the same list */
 | 
						|
      SANE_String_Const mymodel[] =
 | 
						|
	{ "HP3800", "HP3970", "HP4070", "HP4370", "UA4900", "HPG3010",
 | 
						|
"BQ5550", "HPG2710", "HPG3110", 0 };
 | 
						|
 | 
						|
      /* allocate space to save list */
 | 
						|
      model = (SANE_String_Const *) malloc (sizeof (mymodel));
 | 
						|
      if (model != NULL)
 | 
						|
	memcpy (model, &mymodel, sizeof (mymodel));
 | 
						|
 | 
						|
      if (model != NULL)
 | 
						|
	{
 | 
						|
	  /* free previous list */
 | 
						|
	  if (scanner->list_models != NULL)
 | 
						|
	    free (scanner->list_models);
 | 
						|
 | 
						|
	  /* set new list */
 | 
						|
	  scanner->list_models = model;
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_colormodes (TScanner * scanner, SANE_Int model)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_colormodes(*scanner, model=%i)\n", model);
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_String_Const *colormode = NULL;
 | 
						|
 | 
						|
      /* at this moment all devices use the same list */
 | 
						|
      SANE_String_Const mycolormode[] =
 | 
						|
	{ SANE_VALUE_SCAN_MODE_COLOR, SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_LINEART, 0 };
 | 
						|
 | 
						|
      /* silence gcc */
 | 
						|
      model = model;
 | 
						|
 | 
						|
      colormode = (SANE_String_Const *) malloc (sizeof (mycolormode));
 | 
						|
      if (colormode != NULL)
 | 
						|
	memcpy (colormode, &mycolormode, sizeof (mycolormode));
 | 
						|
 | 
						|
      if (colormode != NULL)
 | 
						|
	{
 | 
						|
	  if (scanner->list_colormodes != NULL)
 | 
						|
	    free (scanner->list_colormodes);
 | 
						|
 | 
						|
	  scanner->list_colormodes = colormode;
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_sources (TScanner * scanner, SANE_Int model)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_sources(*scanner, model=%i)\n", model);
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_String_Const *source = NULL;
 | 
						|
 | 
						|
      switch (model)
 | 
						|
	{
 | 
						|
	case UA4900:
 | 
						|
	  {
 | 
						|
	    SANE_String_Const mysource[] = { SANE_I18N ("Flatbed"), 0 };
 | 
						|
	    source = (SANE_String_Const *) malloc (sizeof (mysource));
 | 
						|
	    if (source != NULL)
 | 
						|
	      memcpy (source, &mysource, sizeof (mysource));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	default:		/* hp3970, hp4070, hp4370 and others */
 | 
						|
	  {
 | 
						|
	    SANE_String_Const mysource[] =
 | 
						|
	      { SANE_I18N ("Flatbed"), SANE_I18N ("Slide"),
 | 
						|
SANE_I18N ("Negative"), 0 };
 | 
						|
	    source = (SANE_String_Const *) malloc (sizeof (mysource));
 | 
						|
	    if (source != NULL)
 | 
						|
	      memcpy (source, &mysource, sizeof (mysource));
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      if (source != NULL)
 | 
						|
	{
 | 
						|
	  if (scanner->list_sources != NULL)
 | 
						|
	    free (scanner->list_sources);
 | 
						|
 | 
						|
	  scanner->list_sources = source;
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_depths (TScanner * scanner, SANE_Int model)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_depths(*scanner, model=%i\n", model);
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int *depth = NULL;
 | 
						|
 | 
						|
      /* at this moment all devices use the same list */
 | 
						|
      SANE_Int mydepth[] = { 2, 8, 16 };	/*{3, 8, 12, 16}; */
 | 
						|
 | 
						|
      /* silence gcc */
 | 
						|
      model = model;
 | 
						|
 | 
						|
      depth = (SANE_Int *) malloc (sizeof (mydepth));
 | 
						|
      if (depth != NULL)
 | 
						|
	memcpy (depth, &mydepth, sizeof (mydepth));
 | 
						|
 | 
						|
      if (depth != NULL)
 | 
						|
	{
 | 
						|
	  if (scanner->list_depths != NULL)
 | 
						|
	    free (scanner->list_depths);
 | 
						|
 | 
						|
	  scanner->list_depths = depth;
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
bknd_info (TScanner * scanner)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> bknd_info(*scanner)");
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      char data[256];
 | 
						|
 | 
						|
      /* update chipset name */
 | 
						|
      Chipset_Name (device, data, 255);
 | 
						|
      if (scanner->aValues[opt_chipname].s != NULL)
 | 
						|
	{
 | 
						|
	  free (scanner->aValues[opt_chipname].s);
 | 
						|
	  scanner->aValues[opt_chipname].s = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
      scanner->aValues[opt_chipname].s = strdup (data);
 | 
						|
      scanner->aOptions[opt_chipname].size = strlen (data) + 1;
 | 
						|
 | 
						|
      /* update chipset id */
 | 
						|
      scanner->aValues[opt_chipid].w = Chipset_ID (device);
 | 
						|
 | 
						|
      /* update scans counter */
 | 
						|
      scanner->aValues[opt_scancount].w = RTS_ScanCounter_Get (device);
 | 
						|
 | 
						|
      rst = SANE_STATUS_GOOD;
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
GetUSB_device_model (SANE_String_Const name)
 | 
						|
{
 | 
						|
  SANE_Int usbid, model;
 | 
						|
 | 
						|
  /* default model is unknown */
 | 
						|
  model = -1;
 | 
						|
 | 
						|
  /* open usb device */
 | 
						|
  if (sanei_usb_open (name, &usbid) == SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      SANE_Int vendor, product;
 | 
						|
 | 
						|
      if (sanei_usb_get_vendor_product (usbid, &vendor, &product) ==
 | 
						|
	  SANE_STATUS_GOOD)
 | 
						|
	model = Device_get (product, vendor);
 | 
						|
 | 
						|
      sanei_usb_close (usbid);
 | 
						|
    }
 | 
						|
 | 
						|
  return model;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Silent_Compile (void)
 | 
						|
{
 | 
						|
  /*
 | 
						|
     There are some functions in hp3900_rts8822.c that aren't used yet.
 | 
						|
     To avoid compilation warnings we will use them here
 | 
						|
   */
 | 
						|
 | 
						|
  SANE_Byte a = 1;
 | 
						|
 | 
						|
  if (a == 0)
 | 
						|
    {
 | 
						|
      Buttons_Status (device);
 | 
						|
      Calib_WriteTable (device, NULL, 0, 0);
 | 
						|
      Gamma_GetTables (device, NULL);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
bknd_constrains (TScanner * scanner, SANE_Int source, SANE_Int type)
 | 
						|
{
 | 
						|
  struct st_coords *coords = Constrains_Get (device, source);
 | 
						|
 | 
						|
  if ((coords != NULL) && (scanner != NULL))
 | 
						|
    {
 | 
						|
      switch (type)
 | 
						|
	{
 | 
						|
	case 1:		/* Y */
 | 
						|
	  scanner->rng_vertical.max = coords->height;
 | 
						|
	  break;
 | 
						|
	default:		/* X */
 | 
						|
	  scanner->rng_horizontal.max = coords->width;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
img_buffers_free (TScanner * scanner)
 | 
						|
{
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      if (scanner->image != NULL)
 | 
						|
	{
 | 
						|
	  free (scanner->image);
 | 
						|
	  scanner->image = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
      if (scanner->rest != NULL)
 | 
						|
	{
 | 
						|
	  free (scanner->rest);
 | 
						|
	  scanner->rest = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
      scanner->rest_amount = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
img_buffers_alloc (TScanner * scanner, SANE_Int size)
 | 
						|
{
 | 
						|
  SANE_Status rst;
 | 
						|
 | 
						|
  /* default result at this point */
 | 
						|
  rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      /* default result at this point */
 | 
						|
      rst = SANE_STATUS_NO_MEM;
 | 
						|
 | 
						|
      /* free previous allocs */
 | 
						|
      img_buffers_free (scanner);
 | 
						|
 | 
						|
      scanner->image = (SANE_Byte *) malloc (size * sizeof (SANE_Byte));
 | 
						|
      if (scanner->image != NULL)
 | 
						|
	{
 | 
						|
	  scanner->rest = (SANE_Byte *) malloc (size * sizeof (SANE_Byte));
 | 
						|
	  if (scanner->rest != NULL)
 | 
						|
	    rst = SANE_STATUS_GOOD;	/* ok !! */
 | 
						|
	}
 | 
						|
 | 
						|
      if (rst != SANE_STATUS_GOOD)
 | 
						|
	img_buffers_free (scanner);
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
set_ScannerModel (SANE_Int proposed, SANE_Int product, SANE_Int vendor)
 | 
						|
{
 | 
						|
  /* This function will set the device behaviour */
 | 
						|
 | 
						|
  SANE_Int current = Device_get (product, vendor);
 | 
						|
  char *sdevname[10] =
 | 
						|
    { "Unknown", "HP3970", "HP4070", "HP4370", "UA4900", "HP3800", "HPG3010",
 | 
						|
"BQ5550", "HPG2710", "HPG3110" };
 | 
						|
 | 
						|
  DBG (DBG_FNC,
 | 
						|
       "> set_ScannerModel(proposed=%i, product=%04x, vendor=%04x)\n",
 | 
						|
       proposed, product, vendor);
 | 
						|
 | 
						|
  if (proposed < 0)
 | 
						|
    {
 | 
						|
      if ((current < 0) || (current >= DEVSCOUNT))
 | 
						|
	{
 | 
						|
	  DBG (DBG_VRB, " -> Unknown device. Defaulting to HP3970...\n");
 | 
						|
	  RTS_Debug->dev_model = HP3970;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  RTS_Debug->dev_model = current;
 | 
						|
	  DBG (DBG_VRB, " -> Device model is %s\n", sdevname[current + 1]);
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (proposed < DEVSCOUNT)
 | 
						|
	{
 | 
						|
	  RTS_Debug->dev_model = proposed;
 | 
						|
	  DBG (DBG_VRB, " -> Device %s ,  treating as %s ...\n",
 | 
						|
	       sdevname[current + 1], sdevname[proposed + 1]);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  if ((current >= 0) && (current < DEVSCOUNT))
 | 
						|
	    {
 | 
						|
	      RTS_Debug->dev_model = current;
 | 
						|
	      DBG (DBG_VRB,
 | 
						|
		   " -> Device not supported. Defaulting to %s ...\n",
 | 
						|
		   sdevname[current + 1]);
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      RTS_Debug->dev_model = HP3970;
 | 
						|
	      DBG (DBG_VRB,
 | 
						|
		   "-> Device not supported. Defaulting to HP3970...\n");
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Set_Coordinates (SANE_Int scantype, SANE_Int resolution,
 | 
						|
		 struct st_coords *coords)
 | 
						|
{
 | 
						|
  struct st_coords *limits = Constrains_Get (device, scantype);
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> Set_Coordinates(res=%i, *coords):\n", resolution);
 | 
						|
 | 
						|
  if (coords->left == -1)
 | 
						|
    coords->left = 0;
 | 
						|
 | 
						|
  if (coords->width == -1)
 | 
						|
    coords->width = limits->width;
 | 
						|
 | 
						|
  if (coords->top == -1)
 | 
						|
    coords->top = 0;
 | 
						|
 | 
						|
  if (coords->height == -1)
 | 
						|
    coords->height = limits->height;
 | 
						|
 | 
						|
  DBG (DBG_FNC, " -> Coords [MM] : xy(%i, %i) wh(%i, %i)\n", coords->left,
 | 
						|
       coords->top, coords->width, coords->height);
 | 
						|
 | 
						|
  coords->left = MM_TO_PIXEL (coords->left, resolution);
 | 
						|
  coords->width = MM_TO_PIXEL (coords->width, resolution);
 | 
						|
  coords->top = MM_TO_PIXEL (coords->top, resolution);
 | 
						|
  coords->height = MM_TO_PIXEL (coords->height, resolution);
 | 
						|
 | 
						|
  DBG (DBG_FNC, " -> Coords [px] : xy(%i, %i) wh(%i, %i)\n", coords->left,
 | 
						|
       coords->top, coords->width, coords->height);
 | 
						|
 | 
						|
  Constrains_Check (device, resolution, scantype, coords);
 | 
						|
 | 
						|
  DBG (DBG_FNC, " -> Coords [check]: xy(%i, %i) wh(%i, %i)\n", coords->left,
 | 
						|
       coords->top, coords->width, coords->height);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Color_Negative (SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
 | 
						|
{
 | 
						|
  if (buffer != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int a;
 | 
						|
      SANE_Int max_value = (1 << depth) - 1;
 | 
						|
 | 
						|
      if (depth > 8)
 | 
						|
	{
 | 
						|
	  USHORT *sColor = (void *) buffer;
 | 
						|
	  for (a = 0; a < size / 2; a++)
 | 
						|
	    {
 | 
						|
	      *sColor = max_value - *sColor;
 | 
						|
	      sColor++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  for (a = 0; a < size; a++)
 | 
						|
	    *(buffer + a) = max_value - *(buffer + a);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
get_button_status (TScanner * s)
 | 
						|
{
 | 
						|
  if (s != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int a, b, status, btn;
 | 
						|
 | 
						|
      b = 1;
 | 
						|
      status = Buttons_Released (device) & 63;
 | 
						|
      for (a = 0; a < 6; a++)
 | 
						|
	{
 | 
						|
	  if ((status & b) != 0)
 | 
						|
	    {
 | 
						|
	      btn = Buttons_Order (device, b);
 | 
						|
	      if (btn != -1)
 | 
						|
		s->aValues[opt_button_0 + btn].w = SANE_TRUE;
 | 
						|
	    }
 | 
						|
 | 
						|
	  b <<= 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Depth_16_to_8 (SANE_Byte * from_buffer, SANE_Int size, SANE_Byte * to_buffer)
 | 
						|
{
 | 
						|
  if ((from_buffer != NULL) && (to_buffer != NULL))
 | 
						|
    {
 | 
						|
      SANE_Int a, b;
 | 
						|
 | 
						|
      a = 1;
 | 
						|
      b = 0;
 | 
						|
 | 
						|
      while (a < size)
 | 
						|
	{
 | 
						|
	  *(to_buffer + b) = *(from_buffer + a);
 | 
						|
	  a += 2;
 | 
						|
	  b++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Gray_to_Lineart (SANE_Byte * buffer, SANE_Int size, SANE_Int threshold)
 | 
						|
{
 | 
						|
  /* code provided by tobias leutwein */
 | 
						|
 | 
						|
  if (buffer != NULL)
 | 
						|
    {
 | 
						|
      SANE_Byte toBufferByte;
 | 
						|
      SANE_Int fromBufferPos_i = 0;
 | 
						|
      SANE_Int toBufferPos_i = 0;
 | 
						|
      SANE_Int bitPos_i;
 | 
						|
 | 
						|
      while (fromBufferPos_i < size)
 | 
						|
	{
 | 
						|
	  toBufferByte = 0;
 | 
						|
 | 
						|
	  for (bitPos_i = 7; bitPos_i != (-1); bitPos_i--)
 | 
						|
	    {
 | 
						|
	      if ((fromBufferPos_i < size)
 | 
						|
		  && (buffer[fromBufferPos_i] < threshold))
 | 
						|
		toBufferByte |= (1u << bitPos_i);
 | 
						|
 | 
						|
	      fromBufferPos_i++;
 | 
						|
	    }
 | 
						|
 | 
						|
	  buffer[toBufferPos_i] = toBufferByte;
 | 
						|
	  toBufferPos_i++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
Color_to_Gray (SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
 | 
						|
{
 | 
						|
  /* converts 3 color channel into 1 gray channel of specified bit depth */
 | 
						|
 | 
						|
  if (buffer != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int c, chn, chn_size;
 | 
						|
      SANE_Byte *ptr_src = NULL;
 | 
						|
      SANE_Byte *ptr_dst = NULL;
 | 
						|
      float data, chn_data;
 | 
						|
      float coef[3] = { 0.299, 0.587, 0.114 };	/* coefficients per channel */
 | 
						|
 | 
						|
      chn_size = (depth > 8) ? 2 : 1;
 | 
						|
      ptr_src = (void *) buffer;
 | 
						|
      ptr_dst = (void *) buffer;
 | 
						|
 | 
						|
      for (c = 0; c < size / (3 * chn_size); c++)
 | 
						|
	{
 | 
						|
	  data = 0.;
 | 
						|
 | 
						|
	  /* get, apply coeffs and sum channels */
 | 
						|
	  for (chn = 0; chn < 3; chn++)
 | 
						|
	    {
 | 
						|
	      chn_data = data_lsb_get (ptr_src + (chn * chn_size), chn_size);
 | 
						|
	      data += (chn_data * coef[chn]);
 | 
						|
	    }
 | 
						|
 | 
						|
	  /* save result */
 | 
						|
	  data_lsb_set (ptr_dst, (SANE_Int) data, chn_size);
 | 
						|
 | 
						|
	  ptr_src += 3 * chn_size;	/* next triplet */
 | 
						|
	  ptr_dst += chn_size;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gamma_free (TScanner * s)
 | 
						|
{
 | 
						|
  DBG (DBG_FNC, "> gamma_free()\n");
 | 
						|
 | 
						|
  if (s != NULL)
 | 
						|
    {
 | 
						|
      /* Destroy gamma tables */
 | 
						|
      SANE_Int a;
 | 
						|
 | 
						|
      for (a = CL_RED; a <= CL_BLUE; a++)
 | 
						|
	{
 | 
						|
	  if (s->aGammaTable[a] != NULL)
 | 
						|
	    {
 | 
						|
	      free (s->aGammaTable[a]);
 | 
						|
	      s->aGammaTable[a] = NULL;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
gamma_create (TScanner * s, double gamma)
 | 
						|
{
 | 
						|
  SANE_Int rst = ERROR;		/* by default */
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> gamma_create(*s)\n");
 | 
						|
 | 
						|
  if (s != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int a;
 | 
						|
      double value, c;
 | 
						|
 | 
						|
      /* default result */
 | 
						|
      rst = OK;
 | 
						|
 | 
						|
      /* destroy previous gamma tables */
 | 
						|
      gamma_free (s);
 | 
						|
 | 
						|
      /* check gamma value */
 | 
						|
      if (gamma < 0)
 | 
						|
	gamma = GAMMA_DEFAULT;
 | 
						|
 | 
						|
      /* allocate space for 16 bit gamma tables */
 | 
						|
      for (a = CL_RED; a <= CL_BLUE; a++)
 | 
						|
	{
 | 
						|
	  s->aGammaTable[a] = malloc (65536 * sizeof (SANE_Word));
 | 
						|
	  if (s->aGammaTable[a] == NULL)
 | 
						|
	    {
 | 
						|
	      rst = ERROR;
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
      if (rst == OK)
 | 
						|
	{
 | 
						|
	  /* fill tables */
 | 
						|
	  for (a = 0; a < 65536; a++)
 | 
						|
	    {
 | 
						|
	      value = (a / (65536. - 1));
 | 
						|
	      value = pow (value, (1. / gamma));
 | 
						|
	      value = value * (65536. - 1);
 | 
						|
 | 
						|
	      c = (SANE_Int) value;
 | 
						|
	      if (c > (65536. - 1))
 | 
						|
		c = (65536. - 1);
 | 
						|
	      else if (c < 0)
 | 
						|
		c = 0;
 | 
						|
 | 
						|
	      s->aGammaTable[CL_RED][a] = c;
 | 
						|
	      s->aGammaTable[CL_GREEN][a] = c;
 | 
						|
	      s->aGammaTable[CL_BLUE][a] = c;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	gamma_free (s);
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gamma_apply (TScanner * s, SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
 | 
						|
{
 | 
						|
  if ((s != NULL) && (buffer != NULL))
 | 
						|
    {
 | 
						|
      SANE_Int c;
 | 
						|
      SANE_Int dot_size = 3 * ((depth > 8) ? 2 : 1);
 | 
						|
      SANE_Byte *pColor = buffer;
 | 
						|
      USHORT *sColor = (void *) buffer;
 | 
						|
 | 
						|
      if ((s->aGammaTable[CL_RED] != NULL)
 | 
						|
	  && (s->aGammaTable[CL_GREEN] != NULL)
 | 
						|
	  && (s->aGammaTable[CL_BLUE] != NULL))
 | 
						|
	{
 | 
						|
	  for (c = 0; c < size / dot_size; c++)
 | 
						|
	    {
 | 
						|
	      if (depth > 8)
 | 
						|
		{
 | 
						|
		  *sColor = s->aGammaTable[CL_RED][*sColor];
 | 
						|
		  *(sColor + 1) = s->aGammaTable[CL_GREEN][*(sColor + 1)];
 | 
						|
		  *(sColor + 2) = s->aGammaTable[CL_BLUE][*(sColor + 2)];
 | 
						|
		  sColor += 3;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  /* 8 bits gamma */
 | 
						|
		  *pColor =
 | 
						|
		    (s->aGammaTable[CL_RED][*pColor * 256] >> 8) & 0xff;
 | 
						|
		  *(pColor + 1) =
 | 
						|
		    (s->
 | 
						|
		     aGammaTable[CL_GREEN][*(pColor + 1) * 256] >> 8) & 0xff;
 | 
						|
		  *(pColor + 2) =
 | 
						|
		    (s->
 | 
						|
		     aGammaTable[CL_BLUE][*(pColor + 2) * 256] >> 8) & 0xff;
 | 
						|
		  pColor += 3;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
Get_Model (SANE_String model)
 | 
						|
{
 | 
						|
  SANE_Int rst;
 | 
						|
 | 
						|
  if (strcmp (model, "HP3800") == 0)
 | 
						|
    rst = HP3800;
 | 
						|
  else if (strcmp (model, "HPG2710") == 0)
 | 
						|
    rst = HPG2710;
 | 
						|
  else if (strcmp (model, "HP3970") == 0)
 | 
						|
    rst = HP3970;
 | 
						|
  else if (strcmp (model, "HP4070") == 0)
 | 
						|
    rst = HP4070;
 | 
						|
  else if (strcmp (model, "HP4370") == 0)
 | 
						|
    rst = HP4370;
 | 
						|
  else if (strcmp (model, "HPG3010") == 0)
 | 
						|
    rst = HPG3010;
 | 
						|
  else if (strcmp (model, "HPG3110") == 0)
 | 
						|
    rst = HPG3110;
 | 
						|
  else if (strcmp (model, "UA4900") == 0)
 | 
						|
    rst = UA4900;
 | 
						|
  else if (strcmp (model, "BQ5550") == 0)
 | 
						|
    rst = BQ5550;
 | 
						|
  else
 | 
						|
    rst = HP3970;		/* default */
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
Get_Source (SANE_String source)
 | 
						|
{
 | 
						|
  SANE_Int rst;
 | 
						|
 | 
						|
  if (strcmp (source, SANE_I18N ("Flatbed")) == 0)
 | 
						|
    rst = ST_NORMAL;
 | 
						|
  else if (strcmp (source, SANE_I18N ("Slide")) == 0)
 | 
						|
    rst = ST_TA;
 | 
						|
  else if (strcmp (source, SANE_I18N ("Negative")) == 0)
 | 
						|
    rst = ST_NEG;
 | 
						|
  else
 | 
						|
    rst = ST_NORMAL;		/* default */
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
Get_Colormode (SANE_String colormode)
 | 
						|
{
 | 
						|
  SANE_Int rst;
 | 
						|
 | 
						|
  if (strcmp (colormode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
 | 
						|
    rst = CM_COLOR;
 | 
						|
  else if (strcmp (colormode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
 | 
						|
    rst = CM_GRAY;
 | 
						|
  else if (strcmp (colormode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
 | 
						|
    rst = CM_LINEART;
 | 
						|
  else
 | 
						|
    rst = CM_COLOR;		/* default */
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
Translate_coords (struct st_coords *coords)
 | 
						|
{
 | 
						|
  SANE_Int data;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> Translate_coords(*coords)\n");
 | 
						|
 | 
						|
  if ((coords->left < 0) || (coords->top < 0) ||
 | 
						|
      (coords->width < 0) || (coords->height < 0))
 | 
						|
    return SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if (coords->width < coords->left)
 | 
						|
    {
 | 
						|
      data = coords->left;
 | 
						|
      coords->left = coords->width;
 | 
						|
      coords->width = data;
 | 
						|
    }
 | 
						|
 | 
						|
  if (coords->height < coords->top)
 | 
						|
    {
 | 
						|
      data = coords->top;
 | 
						|
      coords->top = coords->height;
 | 
						|
      coords->height = data;
 | 
						|
    }
 | 
						|
 | 
						|
  coords->width -= coords->left;
 | 
						|
  coords->height -= coords->top;
 | 
						|
 | 
						|
  if (coords->width == 0)
 | 
						|
    coords->width++;
 | 
						|
 | 
						|
  if (coords->height == 0)
 | 
						|
    coords->height++;
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static size_t
 | 
						|
max_string_size (const SANE_String_Const strings[])
 | 
						|
{
 | 
						|
  size_t size, max_size = 0;
 | 
						|
  SANE_Int i;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> max_string_size:\n");
 | 
						|
 | 
						|
  for (i = 0; strings[i]; ++i)
 | 
						|
    {
 | 
						|
      size = strlen (strings[i]) + 1;
 | 
						|
      if (size > max_size)
 | 
						|
	max_size = size;
 | 
						|
    }
 | 
						|
 | 
						|
  return max_size;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
options_free (TScanner * scanner)
 | 
						|
{
 | 
						|
  /* frees all information contained in controls */
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> options_free\n");
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int i;
 | 
						|
      SANE_Option_Descriptor *pDesc;
 | 
						|
      TOptionValue *pVal;
 | 
						|
 | 
						|
      /* free gamma tables */
 | 
						|
      gamma_free (scanner);
 | 
						|
 | 
						|
      /* free lists */
 | 
						|
      if (scanner->list_resolutions != NULL)
 | 
						|
	free (scanner->list_resolutions);
 | 
						|
 | 
						|
      if (scanner->list_depths != NULL)
 | 
						|
	free (scanner->list_depths);
 | 
						|
 | 
						|
      if (scanner->list_sources != NULL)
 | 
						|
	free (scanner->list_sources);
 | 
						|
 | 
						|
      if (scanner->list_colormodes != NULL)
 | 
						|
	free (scanner->list_colormodes);
 | 
						|
 | 
						|
      if (scanner->list_models != NULL)
 | 
						|
	free (scanner->list_models);
 | 
						|
 | 
						|
      /* free values in certain controls */
 | 
						|
      for (i = opt_begin; i < opt_count; i++)
 | 
						|
	{
 | 
						|
	  pDesc = &scanner->aOptions[i];
 | 
						|
	  pVal = &scanner->aValues[i];
 | 
						|
 | 
						|
	  if (pDesc->type == SANE_TYPE_STRING)
 | 
						|
	    {
 | 
						|
	      if (pVal->s != NULL)
 | 
						|
		free (pVal->s);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
options_init (TScanner * scanner)
 | 
						|
{
 | 
						|
  /* initializes all controls */
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> options_init\n");
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      SANE_Int i;
 | 
						|
      SANE_Option_Descriptor *pDesc;
 | 
						|
      TOptionValue *pVal;
 | 
						|
 | 
						|
      /* set gamma */
 | 
						|
      gamma_create (scanner, 1.0);
 | 
						|
 | 
						|
      /* color conversion */
 | 
						|
      scanner->cnv.colormode = -1;
 | 
						|
      scanner->cnv.negative = FALSE;
 | 
						|
      scanner->cnv.threshold = 40;
 | 
						|
      scanner->cnv.real_depth = FALSE;
 | 
						|
      scanner->cnv.depth = -1;
 | 
						|
 | 
						|
      /* setting threshold */
 | 
						|
      scanner->rng_threshold.min = 0;
 | 
						|
      scanner->rng_threshold.max = 255;
 | 
						|
      scanner->rng_threshold.quant = 0;
 | 
						|
 | 
						|
      /* setting gamma range (16 bits depth) */
 | 
						|
      scanner->rng_gamma.min = 0;
 | 
						|
      scanner->rng_gamma.max = 65535;
 | 
						|
      scanner->rng_gamma.quant = 0;
 | 
						|
 | 
						|
      /* setting default horizontal constraint in millimeters */
 | 
						|
      scanner->rng_horizontal.min = 0;
 | 
						|
      scanner->rng_horizontal.max = 220;
 | 
						|
      scanner->rng_horizontal.quant = 1;
 | 
						|
 | 
						|
      /* setting default vertical constraint in millimeters */
 | 
						|
      scanner->rng_vertical.min = 0;
 | 
						|
      scanner->rng_vertical.max = 300;
 | 
						|
      scanner->rng_vertical.quant = 1;
 | 
						|
 | 
						|
      /* allocate option lists */
 | 
						|
      bknd_info (scanner);
 | 
						|
      bknd_colormodes (scanner, RTS_Debug->dev_model);
 | 
						|
      bknd_depths (scanner, RTS_Debug->dev_model);
 | 
						|
      bknd_models (scanner);
 | 
						|
      bknd_resolutions (scanner, RTS_Debug->dev_model);
 | 
						|
      bknd_sources (scanner, RTS_Debug->dev_model);
 | 
						|
 | 
						|
      /* By default preview scan */
 | 
						|
      scanner->ScanParams.scantype = ST_NORMAL;
 | 
						|
      scanner->ScanParams.colormode = CM_COLOR;
 | 
						|
      scanner->ScanParams.resolution_x = 75;
 | 
						|
      scanner->ScanParams.resolution_y = 75;
 | 
						|
      scanner->ScanParams.coords.left = 0;
 | 
						|
      scanner->ScanParams.coords.top = 0;
 | 
						|
      scanner->ScanParams.coords.width = 220;
 | 
						|
      scanner->ScanParams.coords.height = 300;
 | 
						|
      scanner->ScanParams.depth = 8;
 | 
						|
      scanner->ScanParams.channel = 0;
 | 
						|
 | 
						|
      for (i = opt_begin; i < opt_count; i++)
 | 
						|
	{
 | 
						|
	  pDesc = &scanner->aOptions[i];
 | 
						|
	  pVal = &scanner->aValues[i];
 | 
						|
 | 
						|
	  /* defaults */
 | 
						|
	  pDesc->name = "";
 | 
						|
	  pDesc->title = "";
 | 
						|
	  pDesc->desc = "";
 | 
						|
	  pDesc->type = SANE_TYPE_INT;
 | 
						|
	  pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	  pDesc->size = sizeof (SANE_Word);
 | 
						|
	  pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	  pDesc->cap = 0;
 | 
						|
 | 
						|
	  switch (i)
 | 
						|
	    {
 | 
						|
	    case opt_begin:
 | 
						|
	      pDesc->title = SANE_TITLE_NUM_OPTIONS;
 | 
						|
	      pDesc->desc = SANE_DESC_NUM_OPTIONS;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = (SANE_Word) opt_count;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case grp_geometry:
 | 
						|
	      pDesc->name = SANE_NAME_GEOMETRY;
 | 
						|
	      pDesc->title = SANE_TITLE_GEOMETRY;
 | 
						|
	      pDesc->desc = SANE_DESC_GEOMETRY;
 | 
						|
	      pDesc->type = SANE_TYPE_GROUP;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->cap = 0;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_tlx:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_TL_X;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_TL_X;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_TL_X;
 | 
						|
	      pDesc->unit = SANE_UNIT_MM;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_horizontal;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_tly:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_TL_Y;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_TL_Y;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_TL_Y;
 | 
						|
	      pDesc->unit = SANE_UNIT_MM;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_vertical;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_brx:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_BR_X;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_BR_X;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_BR_X;
 | 
						|
	      pDesc->unit = SANE_UNIT_MM;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_horizontal;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = scanner->rng_horizontal.max;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_bry:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_BR_Y;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_BR_Y;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_BR_Y;
 | 
						|
	      pDesc->unit = SANE_UNIT_MM;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_vertical;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = scanner->rng_vertical.max;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_resolution:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_RESOLUTION;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
 | 
						|
	      pDesc->unit = SANE_UNIT_DPI;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | 
						|
	      pDesc->constraint.word_list = scanner->list_resolutions;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = scanner->list_resolutions[1];
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_gamma_red:
 | 
						|
	      pDesc->name = SANE_NAME_GAMMA_VECTOR_R;
 | 
						|
	      pDesc->title = SANE_TITLE_GAMMA_VECTOR_R;
 | 
						|
	      pDesc->desc = SANE_DESC_GAMMA_VECTOR_R;
 | 
						|
	      pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_gamma;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->wa = scanner->aGammaTable[CL_RED];
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_gamma_green:
 | 
						|
	      pDesc->name = SANE_NAME_GAMMA_VECTOR_G;
 | 
						|
	      pDesc->title = SANE_TITLE_GAMMA_VECTOR_G;
 | 
						|
	      pDesc->desc = SANE_DESC_GAMMA_VECTOR_G;
 | 
						|
	      pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_gamma;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->wa = scanner->aGammaTable[CL_GREEN];
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_gamma_blue:
 | 
						|
	      pDesc->name = SANE_NAME_GAMMA_VECTOR_B;
 | 
						|
	      pDesc->title = SANE_TITLE_GAMMA_VECTOR_B;
 | 
						|
	      pDesc->desc = SANE_DESC_GAMMA_VECTOR_B;
 | 
						|
	      pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_gamma;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->wa = scanner->aGammaTable[CL_BLUE];
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_scantype:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_SOURCE;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_SOURCE;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_SOURCE;
 | 
						|
	      pDesc->type = SANE_TYPE_STRING;
 | 
						|
	      pDesc->size = max_string_size (scanner->list_sources);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | 
						|
	      pDesc->constraint.string_list = scanner->list_sources;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->s = strdup (scanner->list_sources[0]);
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_colormode:
 | 
						|
	      pDesc->name = SANE_NAME_SCAN_MODE;
 | 
						|
	      pDesc->title = SANE_TITLE_SCAN_MODE;
 | 
						|
	      pDesc->desc = SANE_DESC_SCAN_MODE;
 | 
						|
	      pDesc->type = SANE_TYPE_STRING;
 | 
						|
	      pDesc->size = max_string_size (scanner->list_colormodes);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | 
						|
	      pDesc->constraint.string_list = scanner->list_colormodes;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->s = strdup (scanner->list_colormodes[0]);
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_depth:
 | 
						|
	      pDesc->name = SANE_NAME_BIT_DEPTH;
 | 
						|
	      pDesc->title = SANE_TITLE_BIT_DEPTH;
 | 
						|
	      pDesc->desc = SANE_DESC_BIT_DEPTH;
 | 
						|
	      pDesc->type = SANE_TYPE_INT;
 | 
						|
	      pDesc->unit = SANE_UNIT_BIT;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | 
						|
	      pDesc->constraint.word_list = scanner->list_depths;
 | 
						|
	      pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = scanner->list_depths[1];
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_threshold:
 | 
						|
	      pDesc->name = SANE_NAME_THRESHOLD;
 | 
						|
	      pDesc->title = SANE_TITLE_THRESHOLD;
 | 
						|
	      pDesc->desc = SANE_DESC_THRESHOLD;
 | 
						|
	      pDesc->type = SANE_TYPE_INT;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
 | 
						|
	      pDesc->constraint.range = &scanner->rng_threshold;
 | 
						|
	      pDesc->cap |=
 | 
						|
		SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_INACTIVE;
 | 
						|
	      pVal->w = 0x80;
 | 
						|
	      break;
 | 
						|
 | 
						|
	      /* debugging options */
 | 
						|
	    case grp_debug:
 | 
						|
	      pDesc->name = "grp_debug";
 | 
						|
	      pDesc->title = SANE_I18N ("Debugging Options");
 | 
						|
	      pDesc->desc = "";
 | 
						|
	      pDesc->type = SANE_TYPE_GROUP;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_model:
 | 
						|
	      pDesc->name = "opt_model";
 | 
						|
	      pDesc->title = SANE_I18N ("Scanner model");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N
 | 
						|
		("Allows one to test device behavior with other supported models");
 | 
						|
	      pDesc->type = SANE_TYPE_STRING;
 | 
						|
	      pDesc->size = max_string_size (scanner->list_models);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | 
						|
	      pDesc->constraint.string_list = scanner->list_models;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT |
 | 
						|
		SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->s = strdup (scanner->list_models[0]);
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_negative:
 | 
						|
	      pDesc->name = "opt_negative";
 | 
						|
	      pDesc->title = SANE_I18N ("Negative");
 | 
						|
	      pDesc->desc = SANE_I18N ("Image colors will be inverted");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_nogamma:
 | 
						|
	      pDesc->name = "opt_nogamma";
 | 
						|
	      pDesc->title = SANE_I18N ("Disable gamma correction");
 | 
						|
	      pDesc->desc = SANE_I18N ("Gamma correction will be disabled");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_nowshading:
 | 
						|
	      pDesc->name = "opt_nowshading";
 | 
						|
	      pDesc->title = SANE_I18N ("Disable white shading correction");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N ("White shading correction will be disabled");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_nowarmup:
 | 
						|
	      pDesc->name = "opt_nowarmup";
 | 
						|
	      pDesc->title = SANE_I18N ("Skip warmup process");
 | 
						|
	      pDesc->desc = SANE_I18N ("Warmup process will be disabled");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_realdepth:
 | 
						|
	      pDesc->name = "opt_realdepth";
 | 
						|
	      pDesc->title = SANE_I18N ("Force real depth");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N
 | 
						|
		("If gamma is enabled, scans are always made in 16 bits depth to improve image quality and then converted to the selected depth. This option avoids depth emulation.");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_emulategray:
 | 
						|
	      pDesc->name = "opt_emulategray";
 | 
						|
	      pDesc->title = SANE_I18N ("Emulate Grayscale");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N
 | 
						|
		("If enabled, image will be scanned in color mode and then converted to grayscale by software. This may improve image quality in some circumstances.");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_dbgimages:
 | 
						|
	      pDesc->name = "opt_dbgimages";
 | 
						|
	      pDesc->title = SANE_I18N ("Save debugging images");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N
 | 
						|
		("If enabled, some images involved in scanner processing are saved to analyze them.");
 | 
						|
	      pDesc->type = SANE_TYPE_BOOL;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = sizeof (SANE_Word);
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pDesc->cap =
 | 
						|
		SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
 | 
						|
		SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_reset:
 | 
						|
	      pDesc->name = "opt_reset";
 | 
						|
	      pDesc->title = SANE_I18N ("Reset chipset");
 | 
						|
	      pDesc->desc = SANE_I18N ("Resets chipset data");
 | 
						|
	      pDesc->type = SANE_TYPE_BUTTON;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.string_list = 0;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	      /* device information */
 | 
						|
	    case grp_info:
 | 
						|
	      pDesc->name = "grp_info";
 | 
						|
	      pDesc->title = SANE_I18N ("Information");
 | 
						|
	      pDesc->desc = "";
 | 
						|
	      pDesc->type = SANE_TYPE_GROUP;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->cap = 0;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_chipname:
 | 
						|
	      pDesc->name = "opt_chipname";
 | 
						|
	      pDesc->title = SANE_I18N ("Chipset name");
 | 
						|
	      pDesc->desc = SANE_I18N ("Shows chipset name used in device.");
 | 
						|
	      pDesc->type = SANE_TYPE_STRING;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->s = strdup (SANE_I18N ("Unknown"));
 | 
						|
	      pDesc->size = strlen(pVal->s) + 1;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_chipid:
 | 
						|
	      pDesc->name = "opt_chipid";
 | 
						|
	      pDesc->title = SANE_I18N ("Chipset ID");
 | 
						|
	      pDesc->desc = SANE_I18N ("Shows the chipset ID");
 | 
						|
	      pDesc->type = SANE_TYPE_INT;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = -1;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_scancount:
 | 
						|
	      pDesc->name = "opt_scancount";
 | 
						|
	      pDesc->title = SANE_I18N ("Scan counter");
 | 
						|
	      pDesc->desc =
 | 
						|
		SANE_I18N ("Shows the number of scans made by scanner");
 | 
						|
	      pDesc->type = SANE_TYPE_INT;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
 | 
						|
	      pVal->w = -1;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_infoupdate:
 | 
						|
	      pDesc->name = "opt_infoupdate";
 | 
						|
	      pDesc->title = SANE_I18N ("Update information");
 | 
						|
	      pDesc->desc = SANE_I18N ("Updates information about device");
 | 
						|
	      pDesc->type = SANE_TYPE_BUTTON;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.string_list = 0;
 | 
						|
	      pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	      /* buttons support */
 | 
						|
	    case grp_sensors:
 | 
						|
	      pDesc->name = SANE_NAME_SENSORS;
 | 
						|
	      pDesc->title = SANE_TITLE_SENSORS;
 | 
						|
	      pDesc->desc = SANE_DESC_SENSORS;
 | 
						|
	      pDesc->type = SANE_TYPE_GROUP;
 | 
						|
	      pDesc->unit = SANE_UNIT_NONE;
 | 
						|
	      pDesc->size = 0;
 | 
						|
	      pDesc->cap = 0;
 | 
						|
	      pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
	      pDesc->constraint.range = 0;
 | 
						|
	      pVal->w = 0;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_button_0:
 | 
						|
	    case opt_button_1:
 | 
						|
	    case opt_button_2:
 | 
						|
	    case opt_button_3:
 | 
						|
	    case opt_button_4:
 | 
						|
	    case opt_button_5:
 | 
						|
	      {
 | 
						|
		char name[12];
 | 
						|
		char title[128];
 | 
						|
 | 
						|
		sprintf (name, "button %d", i - opt_button_0);
 | 
						|
		sprintf (title, "Scanner button %d", i - opt_button_0);
 | 
						|
		pDesc->name = strdup (name);
 | 
						|
		pDesc->title = strdup (title);
 | 
						|
		pDesc->desc =
 | 
						|
		  SANE_I18N
 | 
						|
		  ("This option reflects a front panel scanner button");
 | 
						|
		pDesc->type = SANE_TYPE_BOOL;
 | 
						|
		pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 | 
						|
 | 
						|
		if (i - opt_button_0 >= Buttons_Count (device))
 | 
						|
		  pDesc->cap |= SANE_CAP_INACTIVE;
 | 
						|
 | 
						|
		pDesc->unit = SANE_UNIT_NONE;
 | 
						|
		pDesc->size = sizeof (SANE_Word);
 | 
						|
		pDesc->constraint_type = SANE_CONSTRAINT_NONE;
 | 
						|
		pVal->w = SANE_FALSE;
 | 
						|
	      }
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Int
 | 
						|
_ReportDevice (TScannerModel * pModel, const char *pszDeviceName)
 | 
						|
{
 | 
						|
  SANE_Int rst = ERROR;
 | 
						|
  TDevListEntry *pNew, *pDev;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> _ReportDevice:\n");
 | 
						|
 | 
						|
  pNew = malloc (sizeof (TDevListEntry));
 | 
						|
  if (pNew != NULL)
 | 
						|
    {
 | 
						|
      rst = OK;
 | 
						|
 | 
						|
      /* add new element to the end of the list */
 | 
						|
      if (_pFirstSaneDev != NULL)
 | 
						|
	{
 | 
						|
	  /* Add at the end of existing list */
 | 
						|
	  for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext);
 | 
						|
 | 
						|
	  pDev->pNext = pNew;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	_pFirstSaneDev = pNew;
 | 
						|
 | 
						|
      /* fill in new element */
 | 
						|
      pNew->pNext = NULL;
 | 
						|
      pNew->devname = (char *) strdup (pszDeviceName);
 | 
						|
      pNew->dev.name = pNew->devname;
 | 
						|
      pNew->dev.vendor = pModel->pszVendor;
 | 
						|
      pNew->dev.model = pModel->pszName;
 | 
						|
      pNew->dev.type = SANE_I18N ("flatbed scanner");
 | 
						|
 | 
						|
      iNumSaneDev++;
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
attach_one_device (SANE_String_Const devname)
 | 
						|
{
 | 
						|
  static TScannerModel sModel;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> attach_one_device(devname=%s)\n", devname);
 | 
						|
 | 
						|
  switch (GetUSB_device_model (devname))
 | 
						|
    {
 | 
						|
    case HP3800:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet 3800");
 | 
						|
      break;
 | 
						|
    case HPG2710:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet G2710");
 | 
						|
      break;
 | 
						|
    case HP3970:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet 3970");
 | 
						|
      break;
 | 
						|
    case HP4070:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet 4070 Photosmart");
 | 
						|
      break;
 | 
						|
    case HP4370:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet 4370");
 | 
						|
      break;
 | 
						|
    case HPG3010:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet G3010");
 | 
						|
      break;
 | 
						|
    case HPG3110:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
 | 
						|
      sModel.pszName = (char *) strdup ("Scanjet G3110");
 | 
						|
      break;
 | 
						|
    case UA4900:
 | 
						|
      sModel.pszVendor = (char *) strdup ("UMAX");
 | 
						|
      sModel.pszName = (char *) strdup ("Astra 4900");
 | 
						|
      break;
 | 
						|
    case BQ5550:
 | 
						|
      sModel.pszVendor = (char *) strdup ("BenQ");
 | 
						|
      sModel.pszName = (char *) strdup ("5550");
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      sModel.pszVendor = (char *) strdup ("Unknown");
 | 
						|
      sModel.pszName = (char *) strdup ("RTS8822 chipset based");
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  _ReportDevice (&sModel, devname);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
/* Sane default functions */
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
 | 
						|
{
 | 
						|
  FILE *conf_fp;		/* Config file stream  */
 | 
						|
  SANE_Char line[PATH_MAX];
 | 
						|
  SANE_Char *str = NULL;
 | 
						|
  SANE_String_Const proper_str;
 | 
						|
  SANE_Int nline = 0;
 | 
						|
 | 
						|
  /* Initialize debug */
 | 
						|
  DBG_INIT ();
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> sane_init\n");
 | 
						|
 | 
						|
  /* silence gcc */
 | 
						|
  authorize = authorize;
 | 
						|
 | 
						|
  /* Initialize usb */
 | 
						|
  sanei_usb_init ();
 | 
						|
 | 
						|
  /* Parse config file */
 | 
						|
  conf_fp = sanei_config_open (HP3900_CONFIG_FILE);
 | 
						|
  if (conf_fp)
 | 
						|
    {
 | 
						|
      while (sanei_config_read (line, sizeof (line), conf_fp))
 | 
						|
	{
 | 
						|
	  nline++;
 | 
						|
	  if (str)
 | 
						|
	    free (str);
 | 
						|
 | 
						|
	  proper_str = sanei_config_get_string (line, &str);
 | 
						|
 | 
						|
	  /* Discards white lines and comments */
 | 
						|
	  if ((str != NULL) && (proper_str != line) && (str[0] != '#'))
 | 
						|
	    {
 | 
						|
	      /* If line's not blank or a comment, then it's the device
 | 
						|
	       * filename or a usb directive. */
 | 
						|
	      sanei_usb_attach_matching_devices (line, attach_one_device);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      fclose (conf_fp);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* default */
 | 
						|
      DBG (DBG_VRB, "- %s not found. Looking for hardcoded usb ids ...\n",
 | 
						|
	   HP3900_CONFIG_FILE);
 | 
						|
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x2605", attach_one_device);	/* HP3800  */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x2805", attach_one_device);	/* HPG2710 */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x2305", attach_one_device);	/* HP3970  */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x2405", attach_one_device);	/* HP4070  */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x4105", attach_one_device);	/* HP4370  */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x4205", attach_one_device);	/* HPG3010 */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x03f0 0x4305", attach_one_device);	/* HPG3110 */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x06dc 0x0020", attach_one_device);	/* UA4900  */
 | 
						|
      sanei_usb_attach_matching_devices ("usb 0x04a5 0x2211", attach_one_device);	/* BQ5550  */
 | 
						|
    }
 | 
						|
 | 
						|
  /* Return backend version */
 | 
						|
  if (version_code != NULL)
 | 
						|
    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0);
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_GOOD;
 | 
						|
 | 
						|
  local_only = local_only;
 | 
						|
 | 
						|
  if (_pSaneDevList)
 | 
						|
    free (_pSaneDevList);
 | 
						|
 | 
						|
  _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1));
 | 
						|
  if (_pSaneDevList != NULL)
 | 
						|
    {
 | 
						|
      TDevListEntry *pDev;
 | 
						|
      SANE_Int i = 0;
 | 
						|
 | 
						|
      for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext)
 | 
						|
	_pSaneDevList[i++] = &pDev->dev;
 | 
						|
 | 
						|
      _pSaneDevList[i++] = 0;	/* last entry is 0 */
 | 
						|
      *device_list = _pSaneDevList;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    rst = SANE_STATUS_NO_MEM;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> sane_get_devices: %i\n", rst);
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_open (SANE_String_Const name, SANE_Handle * h)
 | 
						|
{
 | 
						|
  TScanner *s;
 | 
						|
  SANE_Status rst;
 | 
						|
 | 
						|
  /* check the name */
 | 
						|
  if (strlen (name) == 0)
 | 
						|
    /* default to first available device */
 | 
						|
    name = _pFirstSaneDev->dev.name;
 | 
						|
 | 
						|
  /* allocate space for RTS environment */
 | 
						|
  device = RTS_Alloc ();
 | 
						|
  if (device != NULL)
 | 
						|
    {
 | 
						|
      /* Open device */
 | 
						|
      rst = sanei_usb_open (name, &device->usb_handle);
 | 
						|
      if (rst == SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  /* Allocating memory for device */
 | 
						|
	  s = malloc (sizeof (TScanner));
 | 
						|
	  if (s != NULL)
 | 
						|
	    {
 | 
						|
	      memset (s, 0, sizeof (TScanner));
 | 
						|
 | 
						|
	      /* Initializing RTS */
 | 
						|
	      if (Init_Vars () == OK)
 | 
						|
		{
 | 
						|
		  SANE_Int vendor, product;
 | 
						|
 | 
						|
		  /* Setting device model */
 | 
						|
		  if (sanei_usb_get_vendor_product
 | 
						|
		      (device->usb_handle, &vendor,
 | 
						|
		       &product) == SANE_STATUS_GOOD)
 | 
						|
		    s->model = Device_get (product, vendor);
 | 
						|
		  else
 | 
						|
		    s->model = HP3970;
 | 
						|
 | 
						|
		  set_ScannerModel (s->model, product, vendor);
 | 
						|
 | 
						|
		  /* Initialize device */
 | 
						|
		  if (RTS_Scanner_Init (device) == OK)
 | 
						|
		    {
 | 
						|
		      /* silencing unused functions */
 | 
						|
		      Silent_Compile ();
 | 
						|
 | 
						|
		      /* initialize backend options */
 | 
						|
		      options_init (s);
 | 
						|
		      *h = s;
 | 
						|
 | 
						|
		      /* everything went ok */
 | 
						|
		      rst = SANE_STATUS_GOOD;
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    {
 | 
						|
		      free ((void *) s);
 | 
						|
		      rst = SANE_STATUS_INVAL;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		rst = SANE_STATUS_NO_MEM;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    rst = SANE_STATUS_NO_MEM;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    rst = SANE_STATUS_NO_MEM;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> sane_open(name=%s): %i\n", name, rst);
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
const SANE_Option_Descriptor *
 | 
						|
sane_get_option_descriptor (SANE_Handle h, SANE_Int n)
 | 
						|
{
 | 
						|
  SANE_Option_Descriptor *rst = NULL;
 | 
						|
 | 
						|
  if ((n >= opt_begin) && (n < opt_count))
 | 
						|
    {
 | 
						|
      TScanner *s = (TScanner *) h;
 | 
						|
      rst = &s->aOptions[n];
 | 
						|
    }
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> SANE_Option_Descriptor(handle, n=%i): %i\n", n,
 | 
						|
       (rst == NULL) ? -1 : 0);
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
option_get (TScanner * scanner, SANE_Int optid, void *result)
 | 
						|
{
 | 
						|
  /* This function returns value contained in selected option */
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> option_get(optid=%i)\n", optid);
 | 
						|
 | 
						|
  if ((scanner != NULL) && (result != NULL))
 | 
						|
    {
 | 
						|
      switch (optid)
 | 
						|
	{
 | 
						|
	  /* SANE_Word */
 | 
						|
	case opt_begin:	/* null */
 | 
						|
	case opt_reset:	/* null */
 | 
						|
	case opt_negative:
 | 
						|
	case opt_nogamma:
 | 
						|
	case opt_nowshading:
 | 
						|
	case opt_emulategray:
 | 
						|
	case opt_dbgimages:
 | 
						|
	case opt_nowarmup:
 | 
						|
	case opt_realdepth:
 | 
						|
	case opt_depth:
 | 
						|
	case opt_resolution:
 | 
						|
	case opt_threshold:
 | 
						|
	case opt_brx:
 | 
						|
	case opt_tlx:
 | 
						|
	case opt_bry:
 | 
						|
	case opt_tly:
 | 
						|
	  *(SANE_Word *) result = scanner->aValues[optid].w;
 | 
						|
	  break;
 | 
						|
 | 
						|
	  /* SANE_Int */
 | 
						|
	case opt_chipid:
 | 
						|
	case opt_scancount:
 | 
						|
	  *(SANE_Int *) result = scanner->aValues[optid].w;
 | 
						|
	  break;
 | 
						|
 | 
						|
	  /* SANE_Word array */
 | 
						|
	case opt_gamma_red:
 | 
						|
	case opt_gamma_green:
 | 
						|
	case opt_gamma_blue:
 | 
						|
	  memcpy (result, scanner->aValues[optid].wa,
 | 
						|
		  scanner->aOptions[optid].size);
 | 
						|
	  break;
 | 
						|
 | 
						|
	  /* String */
 | 
						|
	case opt_colormode:
 | 
						|
	case opt_scantype:
 | 
						|
	case opt_model:
 | 
						|
	case opt_chipname:
 | 
						|
	  strncpy (result, scanner->aValues[optid].s, scanner->aOptions[optid].size);
 | 
						|
	  ((char*)result)[scanner->aOptions[optid].size-1] = '\0';
 | 
						|
 | 
						|
	  break;
 | 
						|
 | 
						|
	  /* scanner buttons */
 | 
						|
	case opt_button_0:
 | 
						|
	  get_button_status (scanner);
 | 
						|
          // fall through
 | 
						|
	case opt_button_1:
 | 
						|
	case opt_button_2:
 | 
						|
	case opt_button_3:
 | 
						|
	case opt_button_4:
 | 
						|
	case opt_button_5:
 | 
						|
	  /* copy the button state */
 | 
						|
	  *(SANE_Word *) result = scanner->aValues[optid].w;
 | 
						|
	  /* clear the button state */
 | 
						|
	  scanner->aValues[optid].w = SANE_FALSE;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
option_set (TScanner * scanner, SANE_Int optid, void *value, SANE_Int * pInfo)
 | 
						|
{
 | 
						|
  SANE_Status rst;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> option_set(optid=%i)\n", optid);
 | 
						|
 | 
						|
  rst = SANE_STATUS_INVAL;
 | 
						|
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      if (scanner->fScanning == FALSE)
 | 
						|
	{
 | 
						|
	  SANE_Int info = 0;
 | 
						|
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
 | 
						|
	  switch (optid)
 | 
						|
	    {
 | 
						|
	    case opt_brx:
 | 
						|
	    case opt_tlx:
 | 
						|
	    case opt_bry:
 | 
						|
	    case opt_tly:
 | 
						|
	    case opt_depth:
 | 
						|
	    case opt_nogamma:
 | 
						|
	    case opt_nowshading:
 | 
						|
	    case opt_nowarmup:
 | 
						|
	    case opt_negative:
 | 
						|
	    case opt_emulategray:
 | 
						|
	    case opt_dbgimages:
 | 
						|
	    case opt_threshold:
 | 
						|
	    case opt_resolution:
 | 
						|
	      info |= SANE_INFO_RELOAD_PARAMS;
 | 
						|
	      scanner->aValues[optid].w = *(SANE_Word *) value;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_gamma_red:
 | 
						|
	    case opt_gamma_green:
 | 
						|
	    case opt_gamma_blue:
 | 
						|
	      memcpy (scanner->aValues[optid].wa, value,
 | 
						|
		      scanner->aOptions[optid].size);
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_scantype:
 | 
						|
	      if (strcmp (scanner->aValues[optid].s, value) != 0)
 | 
						|
		{
 | 
						|
		  struct st_coords *coords;
 | 
						|
		  SANE_Int source;
 | 
						|
 | 
						|
		  if (scanner->aValues[optid].s)
 | 
						|
		    free (scanner->aValues[optid].s);
 | 
						|
 | 
						|
		  scanner->aValues[optid].s = strdup (value);
 | 
						|
 | 
						|
		  source = Get_Source (scanner->aValues[opt_scantype].s);
 | 
						|
		  coords = Constrains_Get (device, source);
 | 
						|
		  if (coords != NULL)
 | 
						|
		    {
 | 
						|
		      bknd_constrains (scanner, source, 0);
 | 
						|
		      bknd_constrains (scanner, source, 1);
 | 
						|
		      scanner->aValues[opt_tlx].w = 0;
 | 
						|
		      scanner->aValues[opt_tly].w = 0;
 | 
						|
		      scanner->aValues[opt_brx].w = coords->width;
 | 
						|
		      scanner->aValues[opt_bry].w = coords->height;
 | 
						|
		    }
 | 
						|
 | 
						|
		  info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 | 
						|
		}
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_colormode:
 | 
						|
	      if (strcmp (scanner->aValues[optid].s, value) != 0)
 | 
						|
		{
 | 
						|
		  if (scanner->aValues[optid].s)
 | 
						|
		    free (scanner->aValues[optid].s);
 | 
						|
		  scanner->aValues[optid].s = strdup (value);
 | 
						|
		  if (Get_Colormode (scanner->aValues[optid].s) == CM_LINEART)
 | 
						|
		    scanner->aOptions[opt_threshold].cap &=
 | 
						|
		      ~SANE_CAP_INACTIVE;
 | 
						|
		  else
 | 
						|
		    scanner->aOptions[opt_threshold].cap |= SANE_CAP_INACTIVE;
 | 
						|
		  info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 | 
						|
		}
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_model:
 | 
						|
	      if (strcmp (scanner->aValues[optid].s, value) != 0)
 | 
						|
		{
 | 
						|
		  SANE_Int model;
 | 
						|
 | 
						|
		  if (scanner->aValues[optid].s)
 | 
						|
		    free (scanner->aValues[optid].s);
 | 
						|
		  scanner->aValues[optid].s = strdup (value);
 | 
						|
 | 
						|
		  model = Get_Model (scanner->aValues[optid].s);
 | 
						|
		  if (model != RTS_Debug->dev_model)
 | 
						|
		    {
 | 
						|
		      SANE_Int source;
 | 
						|
		      struct st_coords *coords;
 | 
						|
 | 
						|
		      /* free configuration of last model */
 | 
						|
		      Free_Config (device);
 | 
						|
 | 
						|
		      /* set new model */
 | 
						|
		      RTS_Debug->dev_model = model;
 | 
						|
 | 
						|
		      /* and load configuration of current model */
 | 
						|
		      Load_Config (device);
 | 
						|
 | 
						|
		      /* update options according to selected device */
 | 
						|
		      bknd_info (scanner);
 | 
						|
		      bknd_colormodes (scanner, model);
 | 
						|
		      bknd_depths (scanner, model);
 | 
						|
		      bknd_resolutions (scanner, model);
 | 
						|
		      bknd_sources (scanner, model);
 | 
						|
 | 
						|
		      /* updating lists */
 | 
						|
		      scanner->aOptions[opt_colormode].size =
 | 
						|
			max_string_size (scanner->list_colormodes);
 | 
						|
		      scanner->aOptions[opt_colormode].constraint.
 | 
						|
			string_list = scanner->list_colormodes;
 | 
						|
		      scanner->aOptions[opt_depth].constraint.word_list =
 | 
						|
			scanner->list_depths;
 | 
						|
		      scanner->aOptions[opt_resolution].constraint.word_list =
 | 
						|
			scanner->list_resolutions;
 | 
						|
		      scanner->aOptions[opt_scantype].size =
 | 
						|
			max_string_size (scanner->list_sources);
 | 
						|
		      scanner->aOptions[opt_scantype].constraint.string_list =
 | 
						|
			scanner->list_sources;
 | 
						|
 | 
						|
		      /* default values */
 | 
						|
		      if (scanner->aValues[opt_colormode].s != NULL)
 | 
						|
			free (scanner->aValues[opt_colormode].s);
 | 
						|
 | 
						|
		      if (scanner->aValues[opt_scantype].s != NULL)
 | 
						|
			free (scanner->aValues[opt_scantype].s);
 | 
						|
 | 
						|
		      scanner->aValues[opt_colormode].s =
 | 
						|
			strdup (scanner->list_colormodes[0]);
 | 
						|
		      scanner->aValues[opt_scantype].s =
 | 
						|
			strdup (scanner->list_sources[0]);
 | 
						|
		      scanner->aValues[opt_resolution].w =
 | 
						|
			scanner->list_resolutions[1];
 | 
						|
		      scanner->aValues[opt_depth].w = scanner->list_depths[1];
 | 
						|
 | 
						|
		      source = Get_Source (scanner->aValues[opt_scantype].s);
 | 
						|
		      coords = Constrains_Get (device, source);
 | 
						|
		      if (coords != NULL)
 | 
						|
			{
 | 
						|
			  bknd_constrains (scanner, source, 0);
 | 
						|
			  bknd_constrains (scanner, source, 1);
 | 
						|
			  scanner->aValues[opt_tlx].w = 0;
 | 
						|
			  scanner->aValues[opt_tly].w = 0;
 | 
						|
			  scanner->aValues[opt_brx].w = coords->width;
 | 
						|
			  scanner->aValues[opt_bry].w = coords->height;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 | 
						|
		}
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_reset:
 | 
						|
	      Chipset_Reset (device);
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_realdepth:
 | 
						|
	      scanner->aValues[optid].w =
 | 
						|
		(scanner->cnv.real_depth == TRUE) ? SANE_TRUE : SANE_FALSE;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case opt_infoupdate:
 | 
						|
	      if (bknd_info (scanner) == SANE_STATUS_GOOD)
 | 
						|
		info |= SANE_INFO_RELOAD_OPTIONS;
 | 
						|
	      break;
 | 
						|
 | 
						|
	    default:
 | 
						|
	      rst = SANE_STATUS_INVAL;
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (pInfo != NULL)
 | 
						|
	    *pInfo = info;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
 | 
						|
		     void *pVal, SANE_Int * pInfo)
 | 
						|
{
 | 
						|
  TScanner *scanner;
 | 
						|
  SANE_Status rst;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "> sane_control_option\n");
 | 
						|
 | 
						|
  scanner = (TScanner *) h;
 | 
						|
 | 
						|
  switch (Action)
 | 
						|
    {
 | 
						|
    case SANE_ACTION_GET_VALUE:
 | 
						|
      rst = option_get (scanner, n, pVal);
 | 
						|
      break;
 | 
						|
 | 
						|
    case SANE_ACTION_SET_VALUE:
 | 
						|
      rst = option_set (scanner, n, pVal, pInfo);
 | 
						|
      break;
 | 
						|
 | 
						|
    case SANE_ACTION_SET_AUTO:
 | 
						|
      rst = SANE_STATUS_UNSUPPORTED;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      rst = SANE_STATUS_INVAL;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
  TScanner *s = (TScanner *) h;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "+ sane_get_parameters:");
 | 
						|
 | 
						|
  if (s != NULL)
 | 
						|
    {
 | 
						|
      struct st_coords coords;
 | 
						|
      SANE_Int res, source, depth, colormode, frameformat, bpl;
 | 
						|
 | 
						|
      /* first do some checks */
 | 
						|
 | 
						|
      /* colormode */
 | 
						|
      colormode = Get_Colormode (s->aValues[opt_colormode].s);
 | 
						|
 | 
						|
      /* frameformat */
 | 
						|
      frameformat =
 | 
						|
	(colormode == CM_COLOR) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
 | 
						|
 | 
						|
      /* depth */
 | 
						|
      depth = (colormode == CM_LINEART) ? 1 : s->aValues[opt_depth].w;
 | 
						|
 | 
						|
      /* scan type */
 | 
						|
      source = Get_Source (s->aValues[opt_scantype].s);
 | 
						|
 | 
						|
      /* resolution */
 | 
						|
      res = s->aValues[opt_resolution].w;
 | 
						|
 | 
						|
      /* image coordinates in millimeters */
 | 
						|
      coords.left = s->aValues[opt_tlx].w;
 | 
						|
      coords.top = s->aValues[opt_tly].w;
 | 
						|
      coords.width = s->aValues[opt_brx].w;
 | 
						|
      coords.height = s->aValues[opt_bry].w;
 | 
						|
 | 
						|
      /* validate coords */
 | 
						|
      if (Translate_coords (&coords) == SANE_STATUS_GOOD)
 | 
						|
	{
 | 
						|
	  Set_Coordinates (source, res, &coords);
 | 
						|
 | 
						|
	  if (colormode != CM_LINEART)
 | 
						|
	    {
 | 
						|
	      bpl = coords.width * ((depth > 8) ? 2 : 1);
 | 
						|
	      if (colormode == CM_COLOR)
 | 
						|
		bpl *= 3;	/* three channels */
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    bpl = (coords.width + 7) / 8;
 | 
						|
 | 
						|
	  /* return the data */
 | 
						|
	  p->format = frameformat;
 | 
						|
	  p->last_frame = SANE_TRUE;
 | 
						|
	  p->depth = depth;
 | 
						|
	  p->lines = coords.height;
 | 
						|
	  p->pixels_per_line = coords.width;
 | 
						|
	  p->bytes_per_line = bpl;
 | 
						|
 | 
						|
	  DBG (DBG_FNC, " -> Depth : %i\n", depth);
 | 
						|
	  DBG (DBG_FNC, " -> Height: %i\n", coords.height);
 | 
						|
	  DBG (DBG_FNC, " -> Width : %i\n", coords.width);
 | 
						|
	  DBG (DBG_FNC, " -> BPL   : %i\n", bpl);
 | 
						|
 | 
						|
	  rst = SANE_STATUS_GOOD;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  DBG (DBG_FNC, "- sane_get_parameters: %i\n", rst);
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_start (SANE_Handle h)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_INVAL;
 | 
						|
  TScanner *s;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "+ sane_start\n");
 | 
						|
 | 
						|
  s = (TScanner *) h;
 | 
						|
  if (s != NULL)
 | 
						|
    {
 | 
						|
      struct st_coords coords;
 | 
						|
      SANE_Int res, source, colormode, depth, channel;
 | 
						|
 | 
						|
      /* first do some checks */
 | 
						|
      /* Get Scan type */
 | 
						|
      source = Get_Source (s->aValues[opt_scantype].s);
 | 
						|
 | 
						|
      /* Check if scanner supports slides and negatives in case selected source is tma */
 | 
						|
      if (!((source != ST_NORMAL) && (RTS_isTmaAttached (device) == FALSE)))
 | 
						|
	{
 | 
						|
	  /* Get depth */
 | 
						|
	  depth = s->aValues[opt_depth].w;
 | 
						|
 | 
						|
	  /* Get color mode */
 | 
						|
	  colormode = Get_Colormode (s->aValues[opt_colormode].s);
 | 
						|
 | 
						|
	  /* Emulating certain color modes */
 | 
						|
	  if (colormode == CM_LINEART)
 | 
						|
	    {
 | 
						|
	      /* emulate lineart */
 | 
						|
	      s->cnv.colormode = CM_LINEART;
 | 
						|
	      colormode = CM_GRAY;
 | 
						|
	      depth = 8;
 | 
						|
	    }
 | 
						|
	  else if ((colormode == CM_GRAY)
 | 
						|
		   && (s->aValues[opt_emulategray].w == SANE_TRUE))
 | 
						|
	    {
 | 
						|
	      /* emulate grayscale */
 | 
						|
	      s->cnv.colormode = CM_GRAY;
 | 
						|
	      colormode = CM_COLOR;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    s->cnv.colormode = -1;
 | 
						|
 | 
						|
	  /* setting channel for colormodes different than CM_COLOR */
 | 
						|
	  channel = (colormode != CM_COLOR) ? 1 : 0;
 | 
						|
 | 
						|
	  /* negative colors */
 | 
						|
	  s->cnv.negative =
 | 
						|
	    (s->aValues[opt_negative].w == SANE_TRUE) ? TRUE : FALSE;
 | 
						|
 | 
						|
	  /* Get threshold */
 | 
						|
	  s->cnv.threshold = s->aValues[opt_threshold].w;
 | 
						|
 | 
						|
	  /* Get resolution */
 | 
						|
	  res = s->aValues[opt_resolution].w;
 | 
						|
 | 
						|
	  /* set depth emulation */
 | 
						|
	  if (s->cnv.colormode == CM_LINEART)
 | 
						|
	    s->cnv.real_depth = TRUE;
 | 
						|
	  else
 | 
						|
	    s->cnv.real_depth =
 | 
						|
	      (s->aValues[opt_realdepth].w == SANE_TRUE) ? TRUE : FALSE;
 | 
						|
 | 
						|
	  /* use gamma? */
 | 
						|
	  RTS_Debug->EnableGamma =
 | 
						|
	    (s->aValues[opt_nogamma].w == SANE_TRUE) ? FALSE : TRUE;
 | 
						|
 | 
						|
	  /* disable white shading correction? */
 | 
						|
	  RTS_Debug->wshading =
 | 
						|
	    (s->aValues[opt_nowshading].w == SANE_TRUE) ? FALSE : TRUE;
 | 
						|
 | 
						|
	  /* skip warmup process? */
 | 
						|
	  RTS_Debug->warmup =
 | 
						|
	    (s->aValues[opt_nowarmup].w == SANE_TRUE) ? FALSE : TRUE;
 | 
						|
 | 
						|
	  /* save debugging images? */
 | 
						|
	  RTS_Debug->SaveCalibFile =
 | 
						|
	    (s->aValues[opt_dbgimages].w == SANE_TRUE) ? TRUE : FALSE;
 | 
						|
 | 
						|
	  /* Get image coordinates in millimeters */
 | 
						|
	  coords.left = s->aValues[opt_tlx].w;
 | 
						|
	  coords.top = s->aValues[opt_tly].w;
 | 
						|
	  coords.width = s->aValues[opt_brx].w;
 | 
						|
	  coords.height = s->aValues[opt_bry].w;
 | 
						|
 | 
						|
	  /* Validate coords */
 | 
						|
	  if (Translate_coords (&coords) == SANE_STATUS_GOOD)
 | 
						|
	    {
 | 
						|
 | 
						|
	      /* Stop previusly started scan */
 | 
						|
	      RTS_Scanner_StopScan (device, TRUE);
 | 
						|
 | 
						|
	      s->ScanParams.scantype = source;
 | 
						|
	      s->ScanParams.colormode = colormode;
 | 
						|
	      s->ScanParams.resolution_x = res;
 | 
						|
	      s->ScanParams.resolution_y = res;
 | 
						|
	      s->ScanParams.channel = channel;
 | 
						|
 | 
						|
	      memcpy (&s->ScanParams.coords, &coords,
 | 
						|
		      sizeof (struct st_coords));
 | 
						|
	      Set_Coordinates (source, res, &s->ScanParams.coords);
 | 
						|
 | 
						|
	      /* emulating depth? */
 | 
						|
	      if ((s->cnv.real_depth == FALSE) && (depth < 16)
 | 
						|
		  && (RTS_Debug->EnableGamma == TRUE))
 | 
						|
		{
 | 
						|
		  /* In order to improve image quality, we will scan at 16bits if
 | 
						|
		     we are using gamma correction */
 | 
						|
		  s->cnv.depth = depth;
 | 
						|
		  s->ScanParams.depth = 16;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  s->ScanParams.depth = depth;
 | 
						|
		  s->cnv.depth = -1;
 | 
						|
		}
 | 
						|
 | 
						|
	      /* set scanning parameters */
 | 
						|
	      if (RTS_Scanner_SetParams (device, &s->ScanParams) == OK)
 | 
						|
		{
 | 
						|
		  /* Start scanning process */
 | 
						|
		  if (RTS_Scanner_StartScan (device) == OK)
 | 
						|
		    {
 | 
						|
		      /* Allocate buffer to read one line */
 | 
						|
		      s->mylin = 0;
 | 
						|
		      rst = img_buffers_alloc (s, bytesperline);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	rst = SANE_STATUS_COVER_OPEN;
 | 
						|
    }
 | 
						|
 | 
						|
  DBG (DBG_FNC, "- sane_start: %i\n", rst);
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
 | 
						|
{
 | 
						|
  SANE_Status rst = SANE_STATUS_GOOD;
 | 
						|
  TScanner *s = (TScanner *) h;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "+ sane_read\n");
 | 
						|
 | 
						|
  if ((s != NULL) && (buf != NULL) && (len != NULL))
 | 
						|
    {
 | 
						|
      /* nothing has been read at the moment */
 | 
						|
      *len = 0;
 | 
						|
 | 
						|
      /* if we read all the lines return EOF */
 | 
						|
      if ((s->mylin == s->ScanParams.coords.height)
 | 
						|
	  || (device->status->cancel == TRUE))
 | 
						|
	{
 | 
						|
	  rst =
 | 
						|
	    (device->status->cancel ==
 | 
						|
	     TRUE) ? SANE_STATUS_CANCELLED : SANE_STATUS_EOF;
 | 
						|
 | 
						|
	  RTS_Scanner_StopScan (device, FALSE);
 | 
						|
	  img_buffers_free (s);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  SANE_Int emul_len, emul_maxlen;
 | 
						|
	  SANE_Int thwidth, transferred, bufflength;
 | 
						|
	  SANE_Byte *buffer, *pbuffer;
 | 
						|
 | 
						|
	  emul_len = 0;
 | 
						|
	  if (s->cnv.depth != -1)
 | 
						|
	    emul_maxlen = maxlen * (s->ScanParams.depth / s->cnv.depth);
 | 
						|
	  else
 | 
						|
	    emul_maxlen = maxlen;
 | 
						|
 | 
						|
	  /* if grayscale emulation is enabled check that retrieved data is multiple of three */
 | 
						|
	  if (s->cnv.colormode == CM_GRAY)
 | 
						|
	    {
 | 
						|
	      SANE_Int chn_size, rest;
 | 
						|
 | 
						|
	      chn_size = (s->ScanParams.depth > 8) ? 2 : 1;
 | 
						|
	      rest = emul_maxlen % (3 * chn_size);
 | 
						|
 | 
						|
	      if (rest != 0)
 | 
						|
		emul_maxlen -= rest;
 | 
						|
	    }
 | 
						|
 | 
						|
	  /* this is important to keep lines alignment in lineart mode */
 | 
						|
	  if (s->cnv.colormode == CM_LINEART)
 | 
						|
	    emul_maxlen = s->ScanParams.coords.width;
 | 
						|
 | 
						|
	  /* if we are emulating depth, we scan at 16bit when frontend waits
 | 
						|
	     for 8bit data. Next buffer will be used to retrieve data from
 | 
						|
	     scanner prior to convert to 8 bits depth */
 | 
						|
	  buffer = (SANE_Byte *) malloc (emul_maxlen * sizeof (SANE_Byte));
 | 
						|
 | 
						|
	  if (buffer != NULL)
 | 
						|
	    {
 | 
						|
	      pbuffer = buffer;
 | 
						|
 | 
						|
	      /* get bytes per line */
 | 
						|
	      if (s->ScanParams.colormode != CM_LINEART)
 | 
						|
		{
 | 
						|
		  thwidth =
 | 
						|
		    s->ScanParams.coords.width *
 | 
						|
		    ((s->ScanParams.depth > 8) ? 2 : 1);
 | 
						|
 | 
						|
		  if (s->ScanParams.colormode == CM_COLOR)
 | 
						|
		    thwidth *= 3;	/* three channels */
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		thwidth = (s->ScanParams.coords.width + 7) / 8;
 | 
						|
 | 
						|
	      /* read as many lines the buffer may contain and while there are lines to be read */
 | 
						|
	      while ((emul_len < emul_maxlen)
 | 
						|
		     && (s->mylin < s->ScanParams.coords.height))
 | 
						|
		{
 | 
						|
		  /* Is there any data waiting for being passed ? */
 | 
						|
		  if (s->rest_amount != 0)
 | 
						|
		    {
 | 
						|
		      /* copy to buffer as many bytes as we can */
 | 
						|
		      bufflength =
 | 
						|
			min (emul_maxlen - emul_len, s->rest_amount);
 | 
						|
		      memcpy (pbuffer, s->rest, bufflength);
 | 
						|
		      emul_len += bufflength;
 | 
						|
		      pbuffer += bufflength;
 | 
						|
		      s->rest_amount -= bufflength;
 | 
						|
		      if (s->rest_amount == 0)
 | 
						|
			s->mylin++;
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    {
 | 
						|
		      /* read from scanner up to one line */
 | 
						|
		      if (Read_Image
 | 
						|
			  (device, bytesperline, s->image,
 | 
						|
			   &transferred) != OK)
 | 
						|
			{
 | 
						|
			  /* error, exit function */
 | 
						|
			  rst = SANE_STATUS_EOF;
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
 | 
						|
		      /* is there any data? */
 | 
						|
		      if (transferred != 0)
 | 
						|
			{
 | 
						|
			  /* copy to buffer as many bytes as we can */
 | 
						|
			  bufflength = min (emul_maxlen - emul_len, thwidth);
 | 
						|
 | 
						|
			  memcpy (pbuffer, s->image, bufflength);
 | 
						|
			  emul_len += bufflength;
 | 
						|
			  pbuffer += bufflength;
 | 
						|
 | 
						|
			  /* the rest will be copied to s->rest buffer */
 | 
						|
			  if (bufflength < thwidth)
 | 
						|
			    {
 | 
						|
			      s->rest_amount = thwidth - bufflength;
 | 
						|
			      memcpy (s->rest, s->image + bufflength,
 | 
						|
				      s->rest_amount);
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    s->mylin++;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		}		/* while */
 | 
						|
 | 
						|
	      /* process buffer before sending to frontend */
 | 
						|
	      if ((emul_len > 0) && (rst != SANE_STATUS_EOF))
 | 
						|
		{
 | 
						|
		  /* at this point ...
 | 
						|
		     buffer  : contains retrieved image
 | 
						|
		     emul_len: contains size in bytes of retrieved image
 | 
						|
 | 
						|
		     after this code ...
 | 
						|
		     buf : will contain postprocessed image
 | 
						|
		     len : will contain size in bytes of postprocessed image */
 | 
						|
 | 
						|
		  /* apply gamma if necessary */
 | 
						|
		  if (RTS_Debug->EnableGamma == TRUE)
 | 
						|
		    gamma_apply (s, buffer, emul_len, s->ScanParams.depth);
 | 
						|
 | 
						|
		  /* if we are scanning negatives, let's invert colors */
 | 
						|
		  if (s->ScanParams.scantype == ST_NEG)
 | 
						|
		    {
 | 
						|
		      if (s->cnv.negative == FALSE)
 | 
						|
			Color_Negative (buffer, emul_len,
 | 
						|
					s->ScanParams.depth);
 | 
						|
		    }
 | 
						|
		  else if (s->cnv.negative != FALSE)
 | 
						|
		    Color_Negative (buffer, emul_len, s->ScanParams.depth);
 | 
						|
 | 
						|
		  /* emulating grayscale ? */
 | 
						|
		  if (s->cnv.colormode == CM_GRAY)
 | 
						|
		    {
 | 
						|
		      Color_to_Gray (buffer, emul_len, s->ScanParams.depth);
 | 
						|
		      emul_len /= 3;
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* emulating depth */
 | 
						|
		  if (s->cnv.depth != -1)
 | 
						|
		    {
 | 
						|
		      switch (s->cnv.depth)
 | 
						|
			{
 | 
						|
			  /* case 1: treated separately as lineart */
 | 
						|
			  /*case 12: in the future */
 | 
						|
			case 8:
 | 
						|
			  Depth_16_to_8 (buffer, emul_len, buffer);
 | 
						|
			  emul_len /= 2;
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* lineart mode ? */
 | 
						|
		  if (s->cnv.colormode == CM_LINEART)
 | 
						|
		    {
 | 
						|
		      /* I didn't see any scanner supporting lineart mode.
 | 
						|
		         Windows drivers scan in grayscale and then convert image to lineart
 | 
						|
		         so let's perform conversion */
 | 
						|
		      SANE_Int rest = emul_len % 8;
 | 
						|
 | 
						|
		      Gray_to_Lineart (buffer, emul_len, s->cnv.threshold);
 | 
						|
		      emul_len /= 8;
 | 
						|
		      if (rest > 0)
 | 
						|
			emul_len++;
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* copy postprocessed image */
 | 
						|
		  *len = emul_len;
 | 
						|
		  memcpy (buf, buffer, *len);
 | 
						|
		}
 | 
						|
 | 
						|
	      free (buffer);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    rst = SANE_STATUS_EOF;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "- sane_read: %s\n", sane_strstatus (rst));
 | 
						|
 | 
						|
  return rst;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_cancel (SANE_Handle h)
 | 
						|
{
 | 
						|
  DBG (DBG_FNC, "> sane_cancel\n");
 | 
						|
 | 
						|
  /* silence gcc */
 | 
						|
  h = h;
 | 
						|
 | 
						|
  device->status->cancel = TRUE;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
 | 
						|
{
 | 
						|
  DBG (DBG_FNC, "> sane_set_io_mode\n");
 | 
						|
 | 
						|
  /* silence gcc */
 | 
						|
  handle = handle;
 | 
						|
  non_blocking = non_blocking;
 | 
						|
 | 
						|
  return SANE_STATUS_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
SANE_Status
 | 
						|
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
 | 
						|
{
 | 
						|
  DBG (DBG_FNC, "> sane_get_select_fd\n");
 | 
						|
 | 
						|
  /* silence gcc */
 | 
						|
  handle = handle;
 | 
						|
  fd = fd;
 | 
						|
 | 
						|
  return SANE_STATUS_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_close (SANE_Handle h)
 | 
						|
{
 | 
						|
  TScanner *scanner = (TScanner *) h;
 | 
						|
 | 
						|
  DBG (DBG_FNC, "- sane_close...\n");
 | 
						|
 | 
						|
  /* stop previous scans */
 | 
						|
  RTS_Scanner_StopScan (device, TRUE);
 | 
						|
 | 
						|
  /* close usb */
 | 
						|
  sanei_usb_close (device->usb_handle);
 | 
						|
 | 
						|
  /* free scanner internal variables */
 | 
						|
  RTS_Scanner_End (device);
 | 
						|
 | 
						|
  /* free RTS environment */
 | 
						|
  RTS_Free (device);
 | 
						|
 | 
						|
  /* free backend variables */
 | 
						|
  if (scanner != NULL)
 | 
						|
    {
 | 
						|
      options_free (scanner);
 | 
						|
 | 
						|
      img_buffers_free (scanner);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
sane_exit (void)
 | 
						|
{
 | 
						|
  /* free device list memory */
 | 
						|
  if (_pSaneDevList)
 | 
						|
    {
 | 
						|
      TDevListEntry *pDev, *pNext;
 | 
						|
 | 
						|
      for (pDev = _pFirstSaneDev; pDev; pDev = pNext)
 | 
						|
	{
 | 
						|
	  pNext = pDev->pNext;
 | 
						|
	  /* pDev->dev.name is the same pointer that pDev->devname */
 | 
						|
	  free (pDev->devname);
 | 
						|
	  free (pDev);
 | 
						|
	}
 | 
						|
 | 
						|
      _pFirstSaneDev = NULL;
 | 
						|
      free (_pSaneDevList);
 | 
						|
      _pSaneDevList = NULL;
 | 
						|
    }
 | 
						|
}
 |