kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
	
	
		
			2167 wiersze
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
		
		
			
		
	
	
			2167 wiersze
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
| 
								 | 
							
								/* SANE - Scanner Access Now Easy.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
							 | 
						||
| 
								 | 
							
								   Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
							 | 
						||
| 
								 | 
							
								   Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   This file is part of the SANE package.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   This program is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								   modify it under the terms of the GNU General Public License as
							 | 
						||
| 
								 | 
							
								   published by the Free Software Foundation; either version 2 of the
							 | 
						||
| 
								 | 
							
								   License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   This program is distributed in the hope that it will be useful, but
							 | 
						||
| 
								 | 
							
								   WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
							 | 
						||
| 
								 | 
							
								   General Public License for more details.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								   along with this program; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
							 | 
						||
| 
								 | 
							
								   MA 02111-1307, USA.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   As a special exception, the authors of SANE give permission for
							 | 
						||
| 
								 | 
							
								   additional uses of the libraries contained in this release of SANE.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The exception is that, if you link a SANE library with other files
							 | 
						||
| 
								 | 
							
								   to produce an executable, this does not by itself cause the
							 | 
						||
| 
								 | 
							
								   resulting executable to be covered by the GNU General Public
							 | 
						||
| 
								 | 
							
								   License.  Your use of that executable is in no way restricted on
							 | 
						||
| 
								 | 
							
								   account of linking the SANE library code into it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   This exception does not, however, invalidate any other reasons why
							 | 
						||
| 
								 | 
							
								   the executable file might be covered by the GNU General Public
							 | 
						||
| 
								 | 
							
								   License.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   If you submit changes to SANE to the maintainers to be included in
							 | 
						||
| 
								 | 
							
								   a subsequent release, you agree by submitting the changes that
							 | 
						||
| 
								 | 
							
								   those changes may be distributed with this exception intact.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   If you write modifications of your own for SANE, it is your choice
							 | 
						||
| 
								 | 
							
								   whether to permit this exception to apply to your modifications.
							 | 
						||
| 
								 | 
							
								   If you do not wish that, delete this exception notice.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								#include "../include/sane/config.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#ifdef USE_PTHREAD
							 | 
						||
| 
								 | 
							
								# include <pthread.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#include <signal.h>		/* sigaction(POSIX) */
							 | 
						||
| 
								 | 
							
								#include <unistd.h>		/* POSIX: write read close pipe */
							 | 
						||
| 
								 | 
							
								#ifdef HAVE_FCNTL_H
							 | 
						||
| 
								 | 
							
								# include <fcntl.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "pixma_rename.h"
							 | 
						||
| 
								 | 
							
								#include "pixma.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# define DEBUG_NOT_STATIC
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sane.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sanei.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/saneopts.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sanei_thread.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sanei_backend.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sanei_config.h"
							 | 
						||
| 
								 | 
							
								# include "../include/sane/sanei_jpeg.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef NDEBUG
							 | 
						||
| 
								 | 
							
								# define PDBG(x)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#  define PDBG(x) IF_DBG(x)
							 | 
						||
| 
								 | 
							
								#endif /* NDEBUG */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __GNUC__
							 | 
						||
| 
								 | 
							
								# define UNUSED(v) (void) v
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								# define UNUSED(v)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define DECL_CTX pixma_sane_t *ss = check_handle(h)
							 | 
						||
| 
								 | 
							
								#define OPT_IN_CTX ss->opt
							 | 
						||
| 
								 | 
							
								#define SOD(opt)  OPT_IN_CTX[opt].sod
							 | 
						||
| 
								 | 
							
								#define OVAL(opt) OPT_IN_CTX[opt].val
							 | 
						||
| 
								 | 
							
								#define AUTO_GAMMA 2.2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* pixma_sane_options.h generated by
							 | 
						||
| 
								 | 
							
								 * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								#include "pixma_sane_options.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define BUTTON_GROUP_SIZE ( opt_scan_resolution - opt_button_1 + 1 )
							 | 
						||
| 
								 | 
							
								#define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct pixma_sane_t
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  struct pixma_sane_t *next;
							 | 
						||
| 
								 | 
							
								  pixma_t *s;
							 | 
						||
| 
								 | 
							
								  pixma_scan_param_t sp;
							 | 
						||
| 
								 | 
							
								  SANE_Bool cancel;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* valid states: idle, !idle && scanning, !idle && !scanning */
							 | 
						||
| 
								 | 
							
								  SANE_Bool idle;
							 | 
						||
| 
								 | 
							
								  SANE_Bool scanning;
							 | 
						||
| 
								 | 
							
								  SANE_Status last_read_status;	/* valid if !idle && !scanning */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  option_descriptor_t opt[opt_last];
							 | 
						||
| 
								 | 
							
								  char button_option_is_cached[BUTTON_GROUP_SIZE];
							 | 
						||
| 
								 | 
							
								  SANE_Range xrange, yrange;
							 | 
						||
| 
								 | 
							
								  SANE_Word dpi_list[9];	/* up to 9600 dpi */
							 | 
						||
| 
								 | 
							
								  SANE_String_Const mode_list[6];
							 | 
						||
| 
								 | 
							
								  pixma_scan_mode_t mode_map[6];
							 | 
						||
| 
								 | 
							
								  uint8_t gamma_table[4096];
							 | 
						||
| 
								 | 
							
								  SANE_String_Const source_list[4];
							 | 
						||
| 
								 | 
							
								  pixma_paper_source_t source_map[4];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  unsigned byte_pos_in_line, output_line_size;
							 | 
						||
| 
								 | 
							
								  uint64_t image_bytes_read;
							 | 
						||
| 
								 | 
							
								  unsigned page_count;		/* valid for ADF */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SANE_Pid reader_taskid;
							 | 
						||
| 
								 | 
							
								  int wpipe, rpipe;
							 | 
						||
| 
								 | 
							
								  SANE_Bool reader_stop;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Valid for JPEG source */
							 | 
						||
| 
								 | 
							
								  djpeg_dest_ptr jdst;
							 | 
						||
| 
								 | 
							
								  struct jpeg_decompress_struct jpeg_cinfo;
							 | 
						||
| 
								 | 
							
								  struct jpeg_error_mgr jpeg_err;
							 | 
						||
| 
								 | 
							
								  SANE_Bool jpeg_header_seen;
							 | 
						||
| 
								 | 
							
								} pixma_sane_t;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  struct jpeg_source_mgr jpeg;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  pixma_sane_t *s;
							 | 
						||
| 
								 | 
							
								  JOCTET *buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SANE_Byte *linebuffer;
							 | 
						||
| 
								 | 
							
								  SANE_Int linebuffer_size;
							 | 
						||
| 
								 | 
							
								  SANE_Int linebuffer_index;
							 | 
						||
| 
								 | 
							
								} pixma_jpeg_src_mgr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const char vendor_str[] = "CANON";
							 | 
						||
| 
								 | 
							
								static const char type_str[] = "multi-function peripheral";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static pixma_sane_t *first_scanner = NULL;
							 | 
						||
| 
								 | 
							
								static const SANE_Device **dev_list = NULL;
							 | 
						||
| 
								 | 
							
								static const char* conf_devices[MAX_CONF_DEVICES];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void mark_all_button_options_cached ( struct pixma_sane_t * ss )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int i;
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < (opt__group_5 - opt_button_1); i++ )
							 | 
						||
| 
								 | 
							
								      ss -> button_option_is_cached[i] = 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status config_attach_pixma(SANEI_Config * config, const char *devname)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int i;
							 | 
						||
| 
								 | 
							
								  UNUSED(config);
							 | 
						||
| 
								 | 
							
								  for (i=0; i < (MAX_CONF_DEVICES -1); i++)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if(conf_devices[i] == NULL)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          conf_devices[i] = strdup(devname);
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								map_error (int error)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (error >= 0)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch (error)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case PIXMA_ENOMEM:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_NO_MEM;
							 | 
						||
| 
								 | 
							
								    case PIXMA_ECANCELED:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_CANCELLED;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EBUSY:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_DEVICE_BUSY;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EINVAL:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EACCES:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_ACCESS_DENIED;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EPAPER_JAMMED:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_JAMMED;
							 | 
						||
| 
								 | 
							
								    case PIXMA_ENO_PAPER:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_NO_DOCS;
							 | 
						||
| 
								 | 
							
								    case PIXMA_ECOVER_OPEN:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_COVER_OPEN;
							 | 
						||
| 
								 | 
							
								    case PIXMA_ENOTSUP:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EPROTO:
							 | 
						||
| 
								 | 
							
								    case PIXMA_ENODEV:
							 | 
						||
| 
								 | 
							
								    case PIXMA_EIO:
							 | 
						||
| 
								 | 
							
								    case PIXMA_ETIMEDOUT:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (1, "BUG: unmapped error %d\n", error));
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								getenv_atoi (const char *name, int def)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  const char *str = getenv (name);
							 | 
						||
| 
								 | 
							
								  return (str) ? atoi (str) : def;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define CONST_CAST(t,x) (t)(x)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								free_block (const void * ptr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  free (CONST_CAST (void *, ptr));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								cleanup_device_list (void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (dev_list)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int i;
							 | 
						||
| 
								 | 
							
								      for (i = 0; dev_list[i]; i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          free_block ((const void *) dev_list[i]->name);
							 | 
						||
| 
								 | 
							
								          free_block ((const void *) dev_list[i]->model);
							 | 
						||
| 
								 | 
							
								          free_block ((const void *) dev_list[i]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  free (dev_list);
							 | 
						||
| 
								 | 
							
								  dev_list = NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								find_scanners (SANE_Bool local_only)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  unsigned i, nscanners;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cleanup_device_list ();
							 | 
						||
| 
								 | 
							
								  nscanners = pixma_find_scanners (conf_devices, local_only);
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (3, "pixma_find_scanners() found %u devices\n", nscanners));
							 | 
						||
| 
								 | 
							
								  dev_list =
							 | 
						||
| 
								 | 
							
								    (const SANE_Device **) calloc (nscanners + 1, sizeof (*dev_list));
							 | 
						||
| 
								 | 
							
								  if (!dev_list)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  for (i = 0; i != nscanners; i++)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      SANE_Device *sdev = (SANE_Device *) calloc (1, sizeof (*sdev));
							 | 
						||
| 
								 | 
							
								      char *name, *model;
							 | 
						||
| 
								 | 
							
								      if (!sdev)
							 | 
						||
| 
								 | 
							
								        goto nomem;
							 | 
						||
| 
								 | 
							
								      name = strdup (pixma_get_device_id (i));
							 | 
						||
| 
								 | 
							
								      model = strdup (pixma_get_device_model (i));
							 | 
						||
| 
								 | 
							
								      if (!name || !model)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          free (name);
							 | 
						||
| 
								 | 
							
								          free (model);
							 | 
						||
| 
								 | 
							
								          free (sdev);
							 | 
						||
| 
								 | 
							
								          goto nomem;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      sdev->name = name;
							 | 
						||
| 
								 | 
							
								      sdev->model = model;
							 | 
						||
| 
								 | 
							
								      sdev->vendor = vendor_str;
							 | 
						||
| 
								 | 
							
								      sdev->type = type_str;
							 | 
						||
| 
								 | 
							
								      dev_list[i] = sdev;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  /* dev_list is already NULL terminated by calloc(). */
							 | 
						||
| 
								 | 
							
								  return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								nomem:
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (1, "WARNING:not enough memory for device list\n"));
							 | 
						||
| 
								 | 
							
								  return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static pixma_sane_t *
							 | 
						||
| 
								 | 
							
								check_handle (SANE_Handle h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_sane_t *p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (p = first_scanner; p && (SANE_Handle) p != h; p = p->next)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return p;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								update_button_state (pixma_sane_t * ss, SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Int b1 = OVAL (opt_button_1).w;
							 | 
						||
| 
								 | 
							
								  SANE_Int b2 = OVAL (opt_button_2).w;
							 | 
						||
| 
								 | 
							
								  uint32_t ev = pixma_wait_event (ss->s, 300);
							 | 
						||
| 
								 | 
							
								  switch (ev & ~PIXMA_EV_ACTION_MASK)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case PIXMA_EV_BUTTON1:
							 | 
						||
| 
								 | 
							
								      b1 = 1;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case PIXMA_EV_BUTTON2:
							 | 
						||
| 
								 | 
							
								      b2 = 1;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (b1 != OVAL (opt_button_1).w || b2 != OVAL (opt_button_2).w)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    *info |= SANE_INFO_RELOAD_OPTIONS;
							 | 
						||
| 
								 | 
							
								    OVAL (opt_button_1).w = b1;
							 | 
						||
| 
								 | 
							
								    OVAL (opt_button_2).w = b2;
							 | 
						||
| 
								 | 
							
								    OVAL (opt_original).w = GET_EV_ORIGINAL(ev);
							 | 
						||
| 
								 | 
							
								    OVAL (opt_target).w = GET_EV_TARGET(ev);
							 | 
						||
| 
								 | 
							
								    OVAL (opt_scan_resolution).w = GET_EV_DPI(ev);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  mark_all_button_options_cached(ss);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Bool
							 | 
						||
| 
								 | 
							
								enable_option (pixma_sane_t * ss, SANE_Int o, SANE_Bool enable)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Word save = SOD (o).cap;
							 | 
						||
| 
								 | 
							
								  if (enable)
							 | 
						||
| 
								 | 
							
								    SOD (o).cap &= ~SANE_CAP_INACTIVE;
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    SOD (o).cap |= SANE_CAP_INACTIVE;
							 | 
						||
| 
								 | 
							
								  return (save != SOD (o).cap);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								clamp_value (pixma_sane_t * ss, SANE_Int n, void *v, SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Option_Descriptor *sod = &SOD (n);
							 | 
						||
| 
								 | 
							
								  SANE_Word *va = (SANE_Word *) v;
							 | 
						||
| 
								 | 
							
								  const SANE_Range *range = sod->constraint.range;
							 | 
						||
| 
								 | 
							
								  int i, nmemb;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  nmemb = sod->size / sizeof (SANE_Word);
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < nmemb; i++)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      SANE_Word value = va[i];
							 | 
						||
| 
								 | 
							
								      if (value < range->min)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          value = range->min;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if (value > range->max)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          value = range->max;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      if (range->quant != 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          value = (value - range->min + range->quant / 2) /
							 | 
						||
| 
								 | 
							
								            range->quant * range->quant;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      if (value != va[i])
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          va[i] = value;
							 | 
						||
| 
								 | 
							
								          *info |= SANE_INFO_INEXACT;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* create dynamic mode_list
							 | 
						||
| 
								 | 
							
								 * ss:      scanner device
							 | 
						||
| 
								 | 
							
								 * tpu = 0: flatbed or ADF mode
							 | 
						||
| 
								 | 
							
								 *          1 bit lineart, 8 bit grayscale and 24 bit color scans
							 | 
						||
| 
								 | 
							
								 * tpu = 1: TPU mode
							 | 
						||
| 
								 | 
							
								 *          16 bit grayscale and 48 bit color scans */
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								create_mode_list (pixma_sane_t * ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Bool tpu;
							 | 
						||
| 
								 | 
							
								  const pixma_config_t *cfg;
							 | 
						||
| 
								 | 
							
								  int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cfg = pixma_get_config (ss->s);
							 | 
						||
| 
								 | 
							
								  tpu = (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup available mode */
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								  ss->mode_list[i] = SANE_VALUE_SCAN_MODE_COLOR;
							 | 
						||
| 
								 | 
							
								  ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR;
							 | 
						||
| 
								 | 
							
								  i++;
							 | 
						||
| 
								 | 
							
								  if (cfg->cap & PIXMA_CAP_GRAY)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->mode_list[i] = SANE_VALUE_SCAN_MODE_GRAY;
							 | 
						||
| 
								 | 
							
								      ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (tpu && (cfg->cap & PIXMA_CAP_NEGATIVE))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->mode_list[i] = SANE_I18N ("Negative color");
							 | 
						||
| 
								 | 
							
								      ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_COLOR;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								      if (cfg->cap & PIXMA_CAP_GRAY)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          ss->mode_list[i] = SANE_I18N ("Negative gray");
							 | 
						||
| 
								 | 
							
								          ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_GRAY;
							 | 
						||
| 
								 | 
							
								          i++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (tpu && (cfg->cap & PIXMA_CAP_TPUIR) == PIXMA_CAP_TPUIR)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->mode_list[i] = SANE_I18N ("Infrared");
							 | 
						||
| 
								 | 
							
								      ss->mode_map[i] = PIXMA_SCAN_MODE_TPUIR;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (!tpu && (cfg->cap & PIXMA_CAP_48BIT))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->mode_list[i] = SANE_I18N ("48 bits color");
							 | 
						||
| 
								 | 
							
								      ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR_48;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								      if (cfg->cap & PIXMA_CAP_GRAY)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          ss->mode_list[i] = SANE_I18N ("16 bits gray");
							 | 
						||
| 
								 | 
							
								          ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY_16;
							 | 
						||
| 
								 | 
							
								          i++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (!tpu && (cfg->cap & PIXMA_CAP_LINEART))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->mode_list[i] = SANE_VALUE_SCAN_MODE_LINEART;
							 | 
						||
| 
								 | 
							
								      ss->mode_map[i] = PIXMA_SCAN_MODE_LINEART;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  /* terminate mode_list and mode_map */
							 | 
						||
| 
								 | 
							
								  ss->mode_list[i] = 0;
							 | 
						||
| 
								 | 
							
								  ss->mode_map[i] = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* create dynamic dpi_list
							 | 
						||
| 
								 | 
							
								 * ss: scanner device */
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								create_dpi_list (pixma_sane_t * ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  const pixma_config_t *cfg;
							 | 
						||
| 
								 | 
							
								  int i, j;
							 | 
						||
| 
								 | 
							
								  int min;
							 | 
						||
| 
								 | 
							
								  unsigned min_dpi;
							 | 
						||
| 
								 | 
							
								  unsigned max_dpi;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cfg = pixma_get_config (ss->s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* get min/max dpi */
							 | 
						||
| 
								 | 
							
								  max_dpi = cfg->xdpi;
							 | 
						||
| 
								 | 
							
								  min_dpi = 75;
							 | 
						||
| 
								 | 
							
								  if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU
							 | 
						||
| 
								 | 
							
								      && ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_TPUIR)
							 | 
						||
| 
								 | 
							
								  { /* IR mode */
							 | 
						||
| 
								 | 
							
								    /*PDBG (pixma_dbg (4, "*create_dpi_list***** TPUIR mode\n"));*/
							 | 
						||
| 
								 | 
							
								    min_dpi = (cfg->tpuir_min_dpi) ? cfg->tpuir_min_dpi : 75;
							 | 
						||
| 
								 | 
							
								    max_dpi = (cfg->tpuir_max_dpi) ? cfg->tpuir_max_dpi : cfg->xdpi;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU
							 | 
						||
| 
								 | 
							
								            || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADF
							 | 
						||
| 
								 | 
							
								            || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADFDUP)
							 | 
						||
| 
								 | 
							
								  { /* ADF / TPU mode */
							 | 
						||
| 
								 | 
							
								    /*PDBG (pixma_dbg (4, "*create_dpi_list***** ADF/TPU mode\n"));*/
							 | 
						||
| 
								 | 
							
								    min_dpi = (cfg->adftpu_min_dpi) ? cfg->adftpu_min_dpi : 75;
							 | 
						||
| 
								 | 
							
								    max_dpi = (cfg->adftpu_max_dpi) ? cfg->adftpu_max_dpi : cfg->xdpi;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED
							 | 
						||
| 
								 | 
							
								            && (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_COLOR_48
							 | 
						||
| 
								 | 
							
								                || ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_GRAY_16))
							 | 
						||
| 
								 | 
							
								  { /* 48 bits flatbed */
							 | 
						||
| 
								 | 
							
								    /*PDBG (pixma_dbg (4, "*create_dpi_list***** 48 bits flatbed mode\n"));*/
							 | 
						||
| 
								 | 
							
								    min_dpi = 150;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* set j for min. dpi
							 | 
						||
| 
								 | 
							
								   *  75 dpi: j = 0
							 | 
						||
| 
								 | 
							
								   * 150 dpi: j = 1 \
							 | 
						||
| 
								 | 
							
								   * 300 dpi: j = 2 |--> from cfg->adftpu_min_dpi or cfg->tpuir_min_dpi
							 | 
						||
| 
								 | 
							
								   * 600 dpi: j = 3 /
							 | 
						||
| 
								 | 
							
								   * */
							 | 
						||
| 
								 | 
							
								  j = -1;
							 | 
						||
| 
								 | 
							
								  min = min_dpi / 75;
							 | 
						||
| 
								 | 
							
								  do
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    j++;
							 | 
						||
| 
								 | 
							
								    min >>= 1;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  while (min > 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* create dpi_list
							 | 
						||
| 
								 | 
							
								   * use j for min. dpi */
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								  do
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      i++; j++;
							 | 
						||
| 
								 | 
							
								      ss->dpi_list[i] = 75 * (1 << (j - 1));    /* 75 x 2^(j-1) */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  while ((unsigned) ss->dpi_list[i] < max_dpi);
							 | 
						||
| 
								 | 
							
								  ss->dpi_list[0] = i;
							 | 
						||
| 
								 | 
							
								  /*PDBG (pixma_dbg (4, "*create_dpi_list***** min_dpi = %d, max_dpi = %d\n", min_dpi, max_dpi));*/
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								select_value_from_list (pixma_sane_t * ss, SANE_Int n, void *v,
							 | 
						||
| 
								 | 
							
											SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Option_Descriptor *sod = &SOD (n);
							 | 
						||
| 
								 | 
							
								  SANE_Word *va = (SANE_Word *) v;
							 | 
						||
| 
								 | 
							
								  const SANE_Word *list = sod->constraint.word_list;
							 | 
						||
| 
								 | 
							
								  int i, j, nmemb;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  nmemb = sod->size / sizeof (SANE_Word);
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < nmemb; i++)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      SANE_Word value = va[i];
							 | 
						||
| 
								 | 
							
								      SANE_Word mindelta = abs (value - list[1]);
							 | 
						||
| 
								 | 
							
								      SANE_Word nearest = list[1];
							 | 
						||
| 
								 | 
							
								      for (j = 2; j <= list[0]; j++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          SANE_Word delta = abs (value - list[j]);
							 | 
						||
| 
								 | 
							
								          if (delta < mindelta)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              mindelta = delta;
							 | 
						||
| 
								 | 
							
								              nearest = list[j];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          if (mindelta == 0)
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      if (va[i] != nearest)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          va[i] = nearest;
							 | 
						||
| 
								 | 
							
								          *info |= SANE_INFO_INEXACT;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								control_scalar_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
							 | 
						||
| 
								 | 
							
										       SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  option_descriptor_t *opt = &(OPT_IN_CTX[n]);
							 | 
						||
| 
								 | 
							
								  SANE_Word val;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch (a)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_GET_VALUE:
							 | 
						||
| 
								 | 
							
								      switch (opt->sod.type)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_BOOL:
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_INT:
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_FIXED:
							 | 
						||
| 
								 | 
							
								          *(SANE_Word *) v = opt->val.w;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_SET_VALUE:
							 | 
						||
| 
								 | 
							
								      switch (opt->sod.type)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_BOOL:
							 | 
						||
| 
								 | 
							
								          val = *(SANE_Word *) v;
							 | 
						||
| 
								 | 
							
								          if (val != SANE_TRUE && val != SANE_FALSE)
							 | 
						||
| 
								 | 
							
								            return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								          opt->val.w = val;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_INT:
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_FIXED:
							 | 
						||
| 
								 | 
							
								          if (opt->sod.constraint_type == SANE_CONSTRAINT_RANGE)
							 | 
						||
| 
								 | 
							
								            clamp_value (ss, n, v, info);
							 | 
						||
| 
								 | 
							
								          else if (opt->sod.constraint_type == SANE_CONSTRAINT_WORD_LIST)
							 | 
						||
| 
								 | 
							
								            select_value_from_list (ss, n, v, info);
							 | 
						||
| 
								 | 
							
								          opt->val.w = *(SANE_Word *) v;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      *info |= opt->info;
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_SET_AUTO:
							 | 
						||
| 
								 | 
							
								      switch (opt->sod.type)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_BOOL:
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_INT:
							 | 
						||
| 
								 | 
							
								        case SANE_TYPE_FIXED:
							 | 
						||
| 
								 | 
							
								          opt->val.w = opt->def.w;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      *info |= opt->info;
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								control_string_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
							 | 
						||
| 
								 | 
							
										       SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  option_descriptor_t *opt = &(OPT_IN_CTX[n]);
							 | 
						||
| 
								 | 
							
								  const SANE_String_Const *slist = opt->sod.constraint.string_list;
							 | 
						||
| 
								 | 
							
								  SANE_String str = (SANE_String) v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (opt->sod.constraint_type == SANE_CONSTRAINT_NONE)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      switch (a)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_GET_VALUE:
							 | 
						||
| 
								 | 
							
								          strcpy (str, opt->val.s);
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_SET_AUTO:
							 | 
						||
| 
								 | 
							
								          str = opt->def.s;
							 | 
						||
| 
								 | 
							
								          /* fall through */
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_SET_VALUE:
							 | 
						||
| 
								 | 
							
								          strncpy (opt->val.s, str, opt->sod.size - 1);
							 | 
						||
| 
								 | 
							
								          *info |= opt->info;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      switch (a)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_GET_VALUE:
							 | 
						||
| 
								 | 
							
								          strcpy (str, slist[opt->val.w]);
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_SET_AUTO:
							 | 
						||
| 
								 | 
							
								          str = opt->def.ptr;
							 | 
						||
| 
								 | 
							
								          /* fall through */
							 | 
						||
| 
								 | 
							
								        case SANE_ACTION_SET_VALUE:
							 | 
						||
| 
								 | 
							
								          i = 0;
							 | 
						||
| 
								 | 
							
								          while (slist[i] && strcasecmp (str, slist[i]) != 0)
							 | 
						||
| 
								 | 
							
								            i++;
							 | 
						||
| 
								 | 
							
								          if (!slist[i])
							 | 
						||
| 
								 | 
							
								            return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								          if (strcmp (slist[i], str) != 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              strcpy (str, slist[i]);
							 | 
						||
| 
								 | 
							
								              *info |= SANE_INFO_INEXACT;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          opt->val.w = i;
							 | 
						||
| 
								 | 
							
								          *info |= opt->info;
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								control_option (pixma_sane_t * ss, SANE_Int n,
							 | 
						||
| 
								 | 
							
										SANE_Action a, void *v, SANE_Int * info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int result, i;
							 | 
						||
| 
								 | 
							
								  const pixma_config_t *cfg;
							 | 
						||
| 
								 | 
							
								  SANE_Int dummy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* info may be null, better to set a dummy here then test everywhere */
							 | 
						||
| 
								 | 
							
								  if (info == NULL)
							 | 
						||
| 
								 | 
							
								    info = &dummy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cfg = pixma_get_config (ss->s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* first deal with options that require special treatment */
							 | 
						||
| 
								 | 
							
								  result = SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								  switch (n)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      case opt_gamma_table:
							 | 
						||
| 
								 | 
							
								        switch (a)
							 | 
						||
| 
								 | 
							
								          {
							 | 
						||
| 
								 | 
							
								          case SANE_ACTION_SET_VALUE:
							 | 
						||
| 
								 | 
							
								            clamp_value (ss, n, v, info);
							 | 
						||
| 
								 | 
							
								            for (i = 0; i != 4096; i++)
							 | 
						||
| 
								 | 
							
								              ss->gamma_table[i] = *((SANE_Int *) v + i);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          case SANE_ACTION_GET_VALUE:
							 | 
						||
| 
								 | 
							
								            for (i = 0; i != 4096; i++)
							 | 
						||
| 
								 | 
							
								              *((SANE_Int *) v + i) = ss->gamma_table[i];
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          case SANE_ACTION_SET_AUTO:
							 | 
						||
| 
								 | 
							
								            pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table,
							 | 
						||
| 
								 | 
							
								                  sizeof (ss->gamma_table));
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      case opt_button_update:
							 | 
						||
| 
								 | 
							
								        if (a == SANE_ACTION_SET_VALUE)
							 | 
						||
| 
								 | 
							
								          {
							 | 
						||
| 
								 | 
							
								            update_button_state (ss, info);
							 | 
						||
| 
								 | 
							
								            return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								          {
							 | 
						||
| 
								 | 
							
								            return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case opt_button_1:
							 | 
						||
| 
								 | 
							
								      case opt_button_2:
							 | 
						||
| 
								 | 
							
								      case opt_original:
							 | 
						||
| 
								 | 
							
								      case opt_target:
							 | 
						||
| 
								 | 
							
								      case opt_scan_resolution:
							 | 
						||
| 
								 | 
							
								        /* poll scanner if option is not cached */
							 | 
						||
| 
								 | 
							
								        if (! ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] )
							 | 
						||
| 
								 | 
							
								          update_button_state (ss, info);
							 | 
						||
| 
								 | 
							
								        /* mark this option as read */
							 | 
						||
| 
								 | 
							
								        ss->button_option_is_cached[  BUTTON_GROUP_INDEX(n) ] = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* now deal with getting and setting of options */
							 | 
						||
| 
								 | 
							
								  switch (SOD (n).type)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_BOOL:
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_INT:
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_FIXED:
							 | 
						||
| 
								 | 
							
								      result = control_scalar_option (ss, n, a, v, info);
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_STRING:
							 | 
						||
| 
								 | 
							
								      result = control_string_option (ss, n, a, v, info);
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_BUTTON:
							 | 
						||
| 
								 | 
							
								    case SANE_TYPE_GROUP:
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "BUG:control_option():Unhandled option\n"));
							 | 
						||
| 
								 | 
							
								      result = SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (result != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* deal with dependencies between options */
							 | 
						||
| 
								 | 
							
								  switch (n)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case opt_custom_gamma:
							 | 
						||
| 
								 | 
							
								      if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          if (enable_option (ss, opt_gamma_table, OVAL (opt_custom_gamma).b))
							 | 
						||
| 
								 | 
							
								            *info |= SANE_INFO_RELOAD_OPTIONS;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case opt_gamma:
							 | 
						||
| 
								 | 
							
								      if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          /* PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n",
							 | 
						||
| 
								 | 
							
								                           SANE_UNFIX (OVAL (opt_gamma).w))); */
							 | 
						||
| 
								 | 
							
								          pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w),
							 | 
						||
| 
								 | 
							
								                                  ss->gamma_table, sizeof (ss->gamma_table));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case opt_mode:
							 | 
						||
| 
								 | 
							
								      if (cfg->cap & (PIXMA_CAP_48BIT|PIXMA_CAP_LINEART|PIXMA_CAP_TPUIR)
							 | 
						||
| 
								 | 
							
								          && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO))
							 | 
						||
| 
								 | 
							
								        { /* new mode selected: Color, Gray, ... */
							 | 
						||
| 
								 | 
							
								          /* PDBG (pixma_dbg (4, "*control_option***** mode = %u *\n",
							 | 
						||
| 
								 | 
							
								                           ss->mode_map[OVAL (opt_mode).w])); */
							 | 
						||
| 
								 | 
							
								          /* recreate dynamic lists */
							 | 
						||
| 
								 | 
							
								          create_dpi_list (ss);
							 | 
						||
| 
								 | 
							
								          if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART)
							 | 
						||
| 
								 | 
							
								            { /* lineart */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold_curve, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            { /* all other modes */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold_curve, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          *info |= SANE_INFO_RELOAD_OPTIONS;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case opt_source:
							 | 
						||
| 
								 | 
							
								      if ((cfg->cap & (PIXMA_CAP_ADF|PIXMA_CAP_ADFDUP|PIXMA_CAP_TPU))
							 | 
						||
| 
								 | 
							
								          && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO))
							 | 
						||
| 
								 | 
							
								        { /* new source selected: flatbed, ADF, TPU, ... */
							 | 
						||
| 
								 | 
							
								          /* to avoid fatal errors,
							 | 
						||
| 
								 | 
							
								           * select first entry of dynamic mode_list
							 | 
						||
| 
								 | 
							
								           * identifiers are unknown here */
							 | 
						||
| 
								 | 
							
								          OVAL (opt_mode).w = ss->mode_map[0];
							 | 
						||
| 
								 | 
							
								          /* recreate dynamic lists */
							 | 
						||
| 
								 | 
							
								          create_mode_list (ss);
							 | 
						||
| 
								 | 
							
								          create_dpi_list (ss);
							 | 
						||
| 
								 | 
							
								          /* to avoid fatal errors,
							 | 
						||
| 
								 | 
							
								           * select first entry of dynamic dpi_list
							 | 
						||
| 
								 | 
							
								           * identifiers are unknown here */
							 | 
						||
| 
								 | 
							
								          OVAL (opt_resolution).w = ss->dpi_list[1];
							 | 
						||
| 
								 | 
							
								          if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART)
							 | 
						||
| 
								 | 
							
								            { /* lineart */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold_curve, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            { /* all other modes */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_threshold_curve, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          if (cfg->cap & (PIXMA_CAP_ADF_WAIT))
							 | 
						||
| 
								 | 
							
								            { /* adf-wait */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_adf_wait, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            { /* disable adf-wait */
							 | 
						||
| 
								 | 
							
								              enable_option (ss, opt_adf_wait, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          *info |= SANE_INFO_RELOAD_OPTIONS;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return result;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef NDEBUG
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								print_scan_param (int level, const pixma_scan_param_t * sp)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_dbg (level, "Scan parameters\n");
							 | 
						||
| 
								 | 
							
								  pixma_dbg (level, "  line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n",
							 | 
						||
| 
								 | 
							
									     sp->line_size, sp->image_size, sp->channels, sp->depth);
							 | 
						||
| 
								 | 
							
								  pixma_dbg (level, "  dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n",
							 | 
						||
| 
								 | 
							
									     sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h);
							 | 
						||
| 
								 | 
							
								  pixma_dbg (level, "  gamma_table=%p source=%d\n", sp->gamma_table,
							 | 
						||
| 
								 | 
							
									     sp->source);
							 | 
						||
| 
								 | 
							
								  pixma_dbg (level, "  adf-wait=%d\n", sp->adf_wait);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								calc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int x1, y1, x2, y2;
							 | 
						||
| 
								 | 
							
								  int error;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  memset (sp, 0, sizeof (*sp));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sp->channels = (OVAL (opt_mode).w == 0) ? 3 : 1;
							 | 
						||
| 
								 | 
							
								  sp->depth = (OVAL (opt_mode).w == 2) ? 1 : 8;
							 | 
						||
| 
								 | 
							
								  sp->xdpi = sp->ydpi = OVAL (opt_resolution).w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PIXEL(x,dpi) (int)((SANE_UNFIX(x) / 25.4 * (dpi)) + 0.5)
							 | 
						||
| 
								 | 
							
								  x1 = PIXEL (OVAL (opt_tl_x).w, sp->xdpi);
							 | 
						||
| 
								 | 
							
								  x2 = PIXEL (OVAL (opt_br_x).w, sp->xdpi);
							 | 
						||
| 
								 | 
							
								  if (x2 < x1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int temp = x1;
							 | 
						||
| 
								 | 
							
								      x1 = x2;
							 | 
						||
| 
								 | 
							
								      x2 = temp;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  y1 = PIXEL (OVAL (opt_tl_y).w, sp->ydpi);
							 | 
						||
| 
								 | 
							
								  y2 = PIXEL (OVAL (opt_br_y).w, sp->ydpi);
							 | 
						||
| 
								 | 
							
								  if (y2 < y1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int temp = y1;
							 | 
						||
| 
								 | 
							
								      y1 = y2;
							 | 
						||
| 
								 | 
							
								      y2 = temp;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#undef PIXEL
							 | 
						||
| 
								 | 
							
								  sp->x = x1;
							 | 
						||
| 
								 | 
							
								  sp->y = y1;
							 | 
						||
| 
								 | 
							
								  sp->w = x2 - x1;
							 | 
						||
| 
								 | 
							
								  sp->h = y2 - y1;
							 | 
						||
| 
								 | 
							
								  if (sp->w == 0)
							 | 
						||
| 
								 | 
							
								    sp->w = 1;
							 | 
						||
| 
								 | 
							
								  if (sp->h == 0)
							 | 
						||
| 
								 | 
							
								    sp->h = 1;
							 | 
						||
| 
								 | 
							
								  sp->tpu_offset_added = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sp->gamma_table = (OVAL (opt_custom_gamma).b) ? ss->gamma_table : NULL;
							 | 
						||
| 
								 | 
							
								  sp->source = ss->source_map[OVAL (opt_source).w];
							 | 
						||
| 
								 | 
							
								  sp->mode = ss->mode_map[OVAL (opt_mode).w];
							 | 
						||
| 
								 | 
							
								  sp->adf_pageid = ss->page_count;
							 | 
						||
| 
								 | 
							
								  sp->threshold = 2.55 * OVAL (opt_threshold).w;
							 | 
						||
| 
								 | 
							
								  sp->threshold_curve = OVAL (opt_threshold_curve).w;
							 | 
						||
| 
								 | 
							
								  sp->adf_wait = OVAL (opt_adf_wait).w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  error = pixma_check_scan_param (ss->s, sp);
							 | 
						||
| 
								 | 
							
								  if (error < 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "BUG:calc_scan_param() failed %d\n", error));
							 | 
						||
| 
								 | 
							
								      PDBG (print_scan_param (1, sp));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return error;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								init_option_descriptors (pixma_sane_t * ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  const pixma_config_t *cfg;
							 | 
						||
| 
								 | 
							
								  int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cfg = pixma_get_config (ss->s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup range for the scan area. */
							 | 
						||
| 
								 | 
							
								  ss->xrange.min = SANE_FIX (0);
							 | 
						||
| 
								 | 
							
								  ss->xrange.max = SANE_FIX (cfg->width / 75.0 * 25.4);
							 | 
						||
| 
								 | 
							
								  ss->xrange.quant = SANE_FIX (0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ss->yrange.min = SANE_FIX (0);
							 | 
						||
| 
								 | 
							
								  ss->yrange.max = SANE_FIX (cfg->height / 75.0 * 25.4);
							 | 
						||
| 
								 | 
							
								  ss->yrange.quant = SANE_FIX (0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* mode_list and source_list were already NULL-terminated,
							 | 
						||
| 
								 | 
							
								   * because the whole pixma_sane_t was cleared during allocation. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup available mode. */
							 | 
						||
| 
								 | 
							
								  create_mode_list (ss);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup dpi up to the value supported by the scanner. */
							 | 
						||
| 
								 | 
							
								  create_dpi_list (ss);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup paper source */
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								  ss->source_list[i] = SANE_I18N ("Flatbed");
							 | 
						||
| 
								 | 
							
								  ss->source_map[i] = PIXMA_SOURCE_FLATBED;
							 | 
						||
| 
								 | 
							
								  i++;
							 | 
						||
| 
								 | 
							
								  if (cfg->cap & PIXMA_CAP_ADF)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->source_list[i] = SANE_I18N ("Automatic Document Feeder");
							 | 
						||
| 
								 | 
							
								      ss->source_map[i] = PIXMA_SOURCE_ADF;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if ((cfg->cap & PIXMA_CAP_ADFDUP) == PIXMA_CAP_ADFDUP)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->source_list[i] = SANE_I18N ("ADF Duplex");
							 | 
						||
| 
								 | 
							
								      ss->source_map[i] = PIXMA_SOURCE_ADFDUP;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (cfg->cap & PIXMA_CAP_TPU)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->source_list[i] = SANE_I18N ("Transparency Unit");
							 | 
						||
| 
								 | 
							
								      ss->source_map[i] = PIXMA_SOURCE_TPU;
							 | 
						||
| 
								 | 
							
								      i++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  build_option_descriptors (ss);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Enable options that are available only in some scanners. */
							 | 
						||
| 
								 | 
							
								  if (cfg->cap & PIXMA_CAP_GAMMA_TABLE)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      enable_option (ss, opt_gamma, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								      enable_option (ss, opt_custom_gamma, SANE_TRUE);
							 | 
						||
| 
								 | 
							
								      sane_control_option (ss, opt_custom_gamma, SANE_ACTION_SET_AUTO,
							 | 
						||
| 
								 | 
							
											   NULL, NULL);
							 | 
						||
| 
								 | 
							
								      pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table, 4096);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  enable_option (ss, opt_button_controlled,
							 | 
						||
| 
								 | 
							
										 ((cfg->cap & PIXMA_CAP_EVENTS) != 0));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Writing to reader_ss outside reader_process() is a BUG! */
							 | 
						||
| 
								 | 
							
								static pixma_sane_t *reader_ss = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								reader_signal_handler (int sig)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (reader_ss)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      reader_ss->reader_stop = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								      /* reader process is ended by SIGTERM, so no cancel in this case */
							 | 
						||
| 
								 | 
							
								      if (sig != SIGTERM)
							 | 
						||
| 
								 | 
							
								        pixma_cancel (reader_ss->s);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								write_all (pixma_sane_t * ss, void *buf_, size_t size)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  uint8_t *buf = (uint8_t *) buf_;
							 | 
						||
| 
								 | 
							
								  int count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (size != 0 && !ss->reader_stop)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      count = write (ss->wpipe, buf, size);
							 | 
						||
| 
								 | 
							
								      if (count == -1 && errno != EINTR)
							 | 
						||
| 
								 | 
							
									break;
							 | 
						||
| 
								 | 
							
								      if (count == -1 && errno == EINTR)
							 | 
						||
| 
								 | 
							
									continue;
							 | 
						||
| 
								 | 
							
								      buf += count;
							 | 
						||
| 
								 | 
							
								      size -= count;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return buf - (uint8_t *) buf_;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* NOTE: reader_loop() runs either in a separate thread or process. */
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								reader_loop (pixma_sane_t * ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  void *buf;
							 | 
						||
| 
								 | 
							
								  unsigned bufsize;
							 | 
						||
| 
								 | 
							
								  int count = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (3, "Reader task started\n"));
							 | 
						||
| 
								 | 
							
								  /*bufsize = ss->sp.line_size + 1;*/	/* XXX: "odd" bufsize for testing pixma_read_image() */
							 | 
						||
| 
								 | 
							
								  bufsize = ss->sp.line_size;   /* bufsize EVEN needed by Xsane for 48 bits depth */
							 | 
						||
| 
								 | 
							
								  buf = malloc (bufsize);
							 | 
						||
| 
								 | 
							
								  if (!buf)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      count = PIXMA_ENOMEM;
							 | 
						||
| 
								 | 
							
								      goto done;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  count = pixma_activate_connection (ss->s);
							 | 
						||
| 
								 | 
							
								  if (count < 0)
							 | 
						||
| 
								 | 
							
								    goto done;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  pixma_enable_background (ss->s, 1);
							 | 
						||
| 
								 | 
							
								  if (OVAL (opt_button_controlled).b && ss->page_count == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int start = 0;
							 | 
						||
| 
								 | 
							
								#ifndef NDEBUG
							 | 
						||
| 
								 | 
							
								      pixma_dbg (1, "==== Button-controlled scan mode is enabled.\n");
							 | 
						||
| 
								 | 
							
								      pixma_dbg (1, "==== To proceed, press 'SCAN' or 'COLOR' button. "
							 | 
						||
| 
								 | 
							
										 "To cancel, press 'GRAY' or 'END' button.\n");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								      while (pixma_wait_event (ss->s, 10) != 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      while (!start)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          uint32_t events;
							 | 
						||
| 
								 | 
							
								          if (ss->reader_stop)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              count = PIXMA_ECANCELED;
							 | 
						||
| 
								 | 
							
								              goto done;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          events = pixma_wait_event (ss->s, 1000);
							 | 
						||
| 
								 | 
							
								          switch (events & ~PIXMA_EV_ACTION_MASK)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								            case PIXMA_EV_BUTTON1:
							 | 
						||
| 
								 | 
							
								              start = 1;
							 | 
						||
| 
								 | 
							
								              break;
							 | 
						||
| 
								 | 
							
								            case PIXMA_EV_BUTTON2:
							 | 
						||
| 
								 | 
							
								              count = PIXMA_ECANCELED;
							 | 
						||
| 
								 | 
							
								              goto done;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  count = pixma_scan (ss->s, &ss->sp);
							 | 
						||
| 
								 | 
							
								  if (count >= 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      while ((count = pixma_read_image (ss->s, buf, bufsize)) > 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          if (write_all (ss, buf, count) != count)
							 | 
						||
| 
								 | 
							
								            pixma_cancel (ss->s);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								done:
							 | 
						||
| 
								 | 
							
								  pixma_enable_background (ss->s, 0);
							 | 
						||
| 
								 | 
							
								  pixma_deactivate_connection (ss->s);
							 | 
						||
| 
								 | 
							
								  free (buf);
							 | 
						||
| 
								 | 
							
								  close (ss->wpipe);
							 | 
						||
| 
								 | 
							
								  ss->wpipe = -1;
							 | 
						||
| 
								 | 
							
								  if (count >= 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (3, "Reader task terminated\n"));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg
							 | 
						||
| 
								 | 
							
									    (2, "Reader task terminated: %s\n", pixma_strerror (count)));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return map_error (count);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								reader_process (void *arg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_sane_t *ss = (pixma_sane_t *) arg;
							 | 
						||
| 
								 | 
							
								  struct SIGACTION sa;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  reader_ss = ss;
							 | 
						||
| 
								 | 
							
								  memset (&sa, 0, sizeof (sa));
							 | 
						||
| 
								 | 
							
								  sigemptyset (&sa.sa_mask);
							 | 
						||
| 
								 | 
							
								  sa.sa_handler = reader_signal_handler;
							 | 
						||
| 
								 | 
							
								  /* FIXME: which signal else? */
							 | 
						||
| 
								 | 
							
								  sigaction (SIGHUP, &sa, NULL);
							 | 
						||
| 
								 | 
							
								  sigaction (SIGINT, &sa, NULL);
							 | 
						||
| 
								 | 
							
								  sigaction (SIGPIPE, &sa, NULL);
							 | 
						||
| 
								 | 
							
								  sigaction (SIGTERM, &sa, NULL);
							 | 
						||
| 
								 | 
							
								  close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								  ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								  return reader_loop (ss);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								reader_thread (void *arg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_sane_t *ss = (pixma_sane_t *) arg;
							 | 
						||
| 
								 | 
							
								#ifdef USE_PTHREAD
							 | 
						||
| 
								 | 
							
								  /* Block SIGPIPE. We will handle this in reader_loop() by checking
							 | 
						||
| 
								 | 
							
								     ss->reader_stop and the return value from write(). */
							 | 
						||
| 
								 | 
							
								  sigset_t sigs;
							 | 
						||
| 
								 | 
							
								  sigemptyset (&sigs);
							 | 
						||
| 
								 | 
							
								  sigaddset (&sigs, SIGPIPE);
							 | 
						||
| 
								 | 
							
								  pthread_sigmask (SIG_BLOCK, &sigs, NULL);
							 | 
						||
| 
								 | 
							
								#endif /* USE_PTHREAD */
							 | 
						||
| 
								 | 
							
								  return reader_loop (ss);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Pid
							 | 
						||
| 
								 | 
							
								terminate_reader_task (pixma_sane_t * ss, int *exit_code)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  SANE_Pid result, pid;
							 | 
						||
| 
								 | 
							
								  int status = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  pid = ss->reader_taskid;
							 | 
						||
| 
								 | 
							
								  if (!sanei_thread_is_valid (pid))
							 | 
						||
| 
								 | 
							
								    return pid;
							 | 
						||
| 
								 | 
							
								  if (sanei_thread_is_forked ())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      sanei_thread_kill (pid);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->reader_stop = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								/*      pixma_cancel (ss->s);   What is this for ? Makes end-of-scan buggy => removing */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  result = sanei_thread_waitpid (pid, &status);
							 | 
						||
| 
								 | 
							
								  sanei_thread_invalidate (ss->reader_taskid);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
							 | 
						||
| 
								 | 
							
								    ss->idle = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (result == pid)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (exit_code)
							 | 
						||
| 
								 | 
							
									      *exit_code = status;
							 | 
						||
| 
								 | 
							
								      return pid;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "WARNING:waitpid() failed %s\n", strerror (errno)));
							 | 
						||
| 
								 | 
							
								      sanei_thread_invalidate (pid);
							 | 
						||
| 
								 | 
							
								      return pid;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								start_reader_task (pixma_sane_t * ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int fds[2];
							 | 
						||
| 
								 | 
							
								  SANE_Pid pid;
							 | 
						||
| 
								 | 
							
								  int is_forked;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (ss->rpipe != -1 || ss->wpipe != -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg
							 | 
						||
| 
								 | 
							
									    (1, "BUG:rpipe = %d, wpipe = %d\n", ss->rpipe, ss->wpipe));
							 | 
						||
| 
								 | 
							
								      close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								      close (ss->wpipe);
							 | 
						||
| 
								 | 
							
								      ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								      ss->wpipe = -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (sanei_thread_is_valid (ss->reader_taskid))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg
							 | 
						||
| 
								 | 
							
									    (1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid));
							 | 
						||
| 
								 | 
							
								      terminate_reader_task (ss, NULL);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (pipe (fds) == -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "ERROR:start_reader_task():pipe() failed %s\n",
							 | 
						||
| 
								 | 
							
										       strerror (errno)));
							 | 
						||
| 
								 | 
							
								      return PIXMA_ENOMEM;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  ss->rpipe = fds[0];
							 | 
						||
| 
								 | 
							
								  ss->wpipe = fds[1];
							 | 
						||
| 
								 | 
							
								  ss->reader_stop = SANE_FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  is_forked = sanei_thread_is_forked ();
							 | 
						||
| 
								 | 
							
								  if (is_forked)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      pid = sanei_thread_begin (reader_process, ss);
							 | 
						||
| 
								 | 
							
								      if (sanei_thread_is_valid (pid))
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          close (ss->wpipe);
							 | 
						||
| 
								 | 
							
								          ss->wpipe = -1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      pid = sanei_thread_begin (reader_thread, ss);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (!sanei_thread_is_valid (pid))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      close (ss->wpipe);
							 | 
						||
| 
								 | 
							
								      close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								      ss->wpipe = -1;
							 | 
						||
| 
								 | 
							
								      ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n"));
							 | 
						||
| 
								 | 
							
								      return PIXMA_ENOMEM;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n", (long) pid,
							 | 
						||
| 
								 | 
							
										   (is_forked) ? "forked" : "threaded"));
							 | 
						||
| 
								 | 
							
								  ss->reader_taskid = pid;
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* libJPEG API callbacks */
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /* No-op */
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  /* No-op */
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static boolean
							 | 
						||
| 
								 | 
							
								jpeg_fill_input_buffer(j_decompress_ptr cinfo)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src;
							 | 
						||
| 
								 | 
							
								  int size;
							 | 
						||
| 
								 | 
							
								  int retry;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (retry = 0; retry < 30; retry ++ )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      size = read (mgr->s->rpipe, mgr->buffer, 1024);
							 | 
						||
| 
								 | 
							
								      if (size == 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          return FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if (size < 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          sleep (1);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          mgr->jpeg.next_input_byte = mgr->buffer;
							 | 
						||
| 
								 | 
							
								          mgr->jpeg.bytes_in_buffer = size;
							 | 
						||
| 
								 | 
							
								          return TRUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (num_bytes > 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      /* Read and throw away extra */
							 | 
						||
| 
								 | 
							
								      while (num_bytes > (long)mgr->jpeg.bytes_in_buffer)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								           num_bytes -= (long)mgr->jpeg.bytes_in_buffer;
							 | 
						||
| 
								 | 
							
								           jpeg_fill_input_buffer(cinfo);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      /* Update jpeg info structure with leftover */
							 | 
						||
| 
								 | 
							
								      mgr->jpeg.next_input_byte += (size_t) num_bytes;
							 | 
						||
| 
								 | 
							
								      mgr->jpeg.bytes_in_buffer -= (size_t) num_bytes;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Pixma JPEG reader helpers */
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								pixma_jpeg_start(pixma_sane_t *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_jpeg_src_mgr *mgr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  s->jpeg_cinfo.err = jpeg_std_error(&s->jpeg_err);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  jpeg_create_decompress(&s->jpeg_cinfo);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  s->jpeg_cinfo.src = (struct jpeg_source_mgr *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo,
							 | 
						||
| 
								 | 
							
								                              JPOOL_PERMANENT, sizeof(pixma_jpeg_src_mgr));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  memset(s->jpeg_cinfo.src, 0, sizeof(pixma_jpeg_src_mgr));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  mgr = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src;
							 | 
						||
| 
								 | 
							
								  mgr->s = s;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  mgr->buffer = (JOCTET *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo,
							 | 
						||
| 
								 | 
							
								                                                  JPOOL_PERMANENT,
							 | 
						||
| 
								 | 
							
								                                                  1024 * sizeof(JOCTET));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.init_source = jpeg_init_source;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.fill_input_buffer = jpeg_fill_input_buffer;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.skip_input_data = jpeg_skip_input_data;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.resync_to_restart = jpeg_resync_to_restart;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.term_source = jpeg_term_source;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.bytes_in_buffer = 0;
							 | 
						||
| 
								 | 
							
								  mgr->jpeg.next_input_byte = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  s->jpeg_header_seen = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								pixma_jpeg_read_header(pixma_sane_t *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (jpeg_read_header(&s->jpeg_cinfo, TRUE))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      s->jdst = sanei_jpeg_jinit_write_ppm(&s->jpeg_cinfo);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (jpeg_start_decompress(&s->jpeg_cinfo))
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          int size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          DBG(3, "%s: w: %d, h: %d, components: %d\n",
							 | 
						||
| 
								 | 
							
								                  __func__,
							 | 
						||
| 
								 | 
							
								                  s->jpeg_cinfo.output_width, s->jpeg_cinfo.output_height,
							 | 
						||
| 
								 | 
							
								                  s->jpeg_cinfo.output_components);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          size = s->jpeg_cinfo.output_width * s->jpeg_cinfo.output_components * 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          src->linebuffer = (*s->jpeg_cinfo.mem->alloc_large)((j_common_ptr)&s->jpeg_cinfo,
							 | 
						||
| 
								 | 
							
								                  JPOOL_PERMANENT, size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          src->linebuffer_size = 0;
							 | 
						||
| 
								 | 
							
								          src->linebuffer_index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          s->jpeg_header_seen = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          DBG(0, "%s: decompression failed\n", __func__);
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      DBG(0, "%s: cannot read JPEG header\n", __func__);
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								pixma_jpeg_finish(pixma_sane_t *ss)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  jpeg_destroy_decompress(&ss->jpeg_cinfo);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								pixma_jpeg_read(pixma_sane_t *ss, SANE_Byte *data,
							 | 
						||
| 
								 | 
							
								           SANE_Int max_length, SANE_Int *length)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  struct jpeg_decompress_struct cinfo = ss->jpeg_cinfo;
							 | 
						||
| 
								 | 
							
								  pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)ss->jpeg_cinfo.src;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  int l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  *length = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* copy from line buffer if available */
							 | 
						||
| 
								 | 
							
								  if (src->linebuffer_size && src->linebuffer_index < src->linebuffer_size)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      *length = src->linebuffer_size - src->linebuffer_index;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (*length > max_length)
							 | 
						||
| 
								 | 
							
								        *length = max_length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      memcpy(data, src->linebuffer + src->linebuffer_index, *length);
							 | 
						||
| 
								 | 
							
								             src->linebuffer_index += *length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (cinfo.output_scanline >= cinfo.output_height)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      *length = 0;
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* scanlines of decompressed data will be in ss->jdst->buffer
							 | 
						||
| 
								 | 
							
								   * only one line at time is supported
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  l = jpeg_read_scanlines(&cinfo, ss->jdst->buffer, 1);
							 | 
						||
| 
								 | 
							
								  if (l == 0)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* from ss->jdst->buffer to linebuffer
							 | 
						||
| 
								 | 
							
								   * linebuffer holds width * bytesperpixel
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  (*ss->jdst->put_pixel_rows)(&cinfo, ss->jdst, 1, (char *)src->linebuffer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  *length = ss->sp.w * ss->sp.channels;
							 | 
						||
| 
								 | 
							
								  /* Convert RGB into grayscale */
							 | 
						||
| 
								 | 
							
								  if (ss->sp.channels == 1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      unsigned int i;
							 | 
						||
| 
								 | 
							
								      unsigned char *d = (unsigned char *)src->linebuffer;
							 | 
						||
| 
								 | 
							
								      unsigned char *s = (unsigned char *)src->linebuffer;
							 | 
						||
| 
								 | 
							
								      for (i = 0; i < ss->sp.w; i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          /* Using BT.709 luma formula, fixed-point */
							 | 
						||
| 
								 | 
							
								          int sum = ( s[0]*2126 + s[1]*7152 + s[2]*722 );
							 | 
						||
| 
								 | 
							
								          *d = sum / 10000;
							 | 
						||
| 
								 | 
							
								          d ++;
							 | 
						||
| 
								 | 
							
								          s += 3;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Maybe pack into lineary binary image */
							 | 
						||
| 
								 | 
							
								  if (ss->sp.depth == 1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      *length /= 8;
							 | 
						||
| 
								 | 
							
								      unsigned int i;
							 | 
						||
| 
								 | 
							
								      unsigned char *d = (unsigned char *)src->linebuffer;
							 | 
						||
| 
								 | 
							
								      unsigned char *s = (unsigned char *)src->linebuffer;
							 | 
						||
| 
								 | 
							
								      unsigned char b = 0;
							 | 
						||
| 
								 | 
							
								      for (i = 1; i < ss->sp.w + 1; i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          if (*(s++) > 127)
							 | 
						||
| 
								 | 
							
								            b = (b << 1) | 0;
							 | 
						||
| 
								 | 
							
								         else
							 | 
						||
| 
								 | 
							
								            b = (b << 1) | 1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      if ((i % 8) == 0)
							 | 
						||
| 
								 | 
							
								        *(d++) = b;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  src->linebuffer_size = *length;
							 | 
						||
| 
								 | 
							
								  src->linebuffer_index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (*length > max_length)
							 | 
						||
| 
								 | 
							
								    *length = max_length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  memcpy(data, src->linebuffer + src->linebuffer_index, *length);
							 | 
						||
| 
								 | 
							
								        src->linebuffer_index += *length;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static SANE_Status
							 | 
						||
| 
								 | 
							
								read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int count, status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (readlen)
							 | 
						||
| 
								 | 
							
								    *readlen = 0;
							 | 
						||
| 
								 | 
							
								  if (ss->image_bytes_read >= ss->sp.image_size)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_EOF;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  do
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (ss->cancel)
							 | 
						||
| 
								 | 
							
								        /* ss->rpipe has already been closed by sane_cancel(). */
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_CANCELLED;
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg && !ss->jpeg_header_seen)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          status = pixma_jpeg_read_header(ss);
							 | 
						||
| 
								 | 
							
								          if (status != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								              pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								              ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								              if (sanei_thread_is_valid (terminate_reader_task (ss, &status))
							 | 
						||
| 
								 | 
							
								                && status != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  return status;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  /* either terminate_reader_task failed or
							 | 
						||
| 
								 | 
							
								                     rpipe was closed but we expect more data */
							 | 
						||
| 
								 | 
							
								                  return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          count = -1;
							 | 
						||
| 
								 | 
							
								          pixma_jpeg_read(ss, buf, size, &count);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        count = read (ss->rpipe, buf, size);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  while (count == -1 && errno == EINTR);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (count == -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (errno == EAGAIN)
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								      if (!ss->cancel)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          PDBG (pixma_dbg (1, "WARNING:read_image():read() failed %s\n",
							 | 
						||
| 
								 | 
							
								               strerror (errno)));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								      ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								      terminate_reader_task (ss, NULL);
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								        pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* here count >= 0 */
							 | 
						||
| 
								 | 
							
								  ss->image_bytes_read += count;
							 | 
						||
| 
								 | 
							
								  if (ss->image_bytes_read > ss->sp.image_size)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "BUG:ss->image_bytes_read > ss->sp.image_size\n"));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (ss->image_bytes_read >= ss->sp.image_size)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								      ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								      terminate_reader_task (ss, NULL);
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								        pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else if (count == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (3, "read_image():reader task closed the pipe:%"
							 | 
						||
| 
								 | 
							
										       PRIu64" bytes received, %"PRIu64" bytes expected\n",
							 | 
						||
| 
								 | 
							
										       ss->image_bytes_read, ss->sp.image_size));
							 | 
						||
| 
								 | 
							
								      close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								        pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								      ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								      if (sanei_thread_is_valid (terminate_reader_task (ss, &status))
							 | 
						||
| 
								 | 
							
								      	  && status != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          return status;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          /* either terminate_reader_task failed or
							 | 
						||
| 
								 | 
							
								             rpipe was closed but we expect more data */
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_IO_ERROR;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (readlen)
							 | 
						||
| 
								 | 
							
								    *readlen = count;
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*******************************************************************
							 | 
						||
| 
								 | 
							
								 ** SANE API
							 | 
						||
| 
								 | 
							
								 *******************************************************************/
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int status, myversion, i;
							 | 
						||
| 
								 | 
							
								  SANEI_Config config;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  UNUSED (authorize);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!version_code)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  myversion = 100 * PIXMA_VERSION_MAJOR + PIXMA_VERSION_MINOR;
							 | 
						||
| 
								 | 
							
								  *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, myversion);
							 | 
						||
| 
								 | 
							
								  DBG_INIT ();
							 | 
						||
| 
								 | 
							
								  sanei_thread_init ();
							 | 
						||
| 
								 | 
							
								  pixma_set_debug_level (DBG_LEVEL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  PDBG(pixma_dbg(2, "pixma is compiled %s pthread support.\n",
							 | 
						||
| 
								 | 
							
								                   (sanei_thread_is_forked () ? "without" : "with")));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < MAX_CONF_DEVICES; i++)
							 | 
						||
| 
								 | 
							
								    conf_devices[i] = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  config.count = 0;
							 | 
						||
| 
								 | 
							
								  config.descriptors = NULL;
							 | 
						||
| 
								 | 
							
								  config.values = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (sanei_configure_attach(PIXMA_CONFIG_FILE, &config, config_attach_pixma) !=
							 | 
						||
| 
								 | 
							
								       SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								    PDBG(pixma_dbg(2, "Could not read pixma configuration file: %s\n",
							 | 
						||
| 
								 | 
							
								                   PIXMA_CONFIG_FILE));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  status = pixma_init ();
							 | 
						||
| 
								 | 
							
								  if (status < 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (2, "pixma_init() failed %s\n", pixma_strerror (status)));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return map_error (status);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								sane_exit (void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  while (first_scanner)
							 | 
						||
| 
								 | 
							
								    sane_close (first_scanner);
							 | 
						||
| 
								 | 
							
								  cleanup_device_list ();
							 | 
						||
| 
								 | 
							
								  pixma_cleanup ();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (!device_list)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  find_scanners (local_only);
							 | 
						||
| 
								 | 
							
								  *device_list = dev_list;
							 | 
						||
| 
								 | 
							
								  return (dev_list) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_open (SANE_String_Const name, SANE_Handle * h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  unsigned i, j, nscanners;
							 | 
						||
| 
								 | 
							
								  int error = 0;
							 | 
						||
| 
								 | 
							
								  pixma_sane_t *ss = NULL;
							 | 
						||
| 
								 | 
							
								  const pixma_config_t *cfg;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!name || !h)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  *h = NULL;
							 | 
						||
| 
								 | 
							
								  nscanners = pixma_find_scanners (conf_devices, SANE_FALSE);
							 | 
						||
| 
								 | 
							
								  if (nscanners == 0)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  if (name[0] == '\0')
							 | 
						||
| 
								 | 
							
								    name = pixma_get_device_id (0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Have we already opened the scanner? */
							 | 
						||
| 
								 | 
							
								  for (ss = first_scanner; ss; ss = ss->next)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (strcmp (pixma_get_string (ss->s, PIXMA_STRING_ID), name) == 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          /* We have already opened it! */
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_DEVICE_BUSY;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								  while (strcmp (pixma_get_device_id (i), name) != 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (++i >= nscanners)
							 | 
						||
| 
								 | 
							
									      return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  cfg = pixma_get_device_config (i);
							 | 
						||
| 
								 | 
							
								  if ((cfg->cap & PIXMA_CAP_EXPERIMENT) != 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								#ifndef NDEBUG
							 | 
						||
| 
								 | 
							
								      pixma_dbg (1, "WARNING:"
							 | 
						||
| 
								 | 
							
										 "Experimental backend CAN DAMAGE your hardware!\n");
							 | 
						||
| 
								 | 
							
								      if (getenv_atoi ("PIXMA_EXPERIMENT", 0) == 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          pixma_dbg (1, "Experimental SANE backend for %s is disabled "
							 | 
						||
| 
								 | 
							
								               "by default.\n", pixma_get_device_model (i));
							 | 
						||
| 
								 | 
							
								          pixma_dbg (1, "To enable it, set the environment variable "
							 | 
						||
| 
								 | 
							
								               "PIXMA_EXPERIMENT to non-zero.\n");
							 | 
						||
| 
								 | 
							
								          return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ss = (pixma_sane_t *) calloc (1, sizeof (*ss));
							 | 
						||
| 
								 | 
							
								  if (!ss)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_NO_MEM;
							 | 
						||
| 
								 | 
							
								  ss->next = first_scanner;
							 | 
						||
| 
								 | 
							
								  first_scanner = ss;
							 | 
						||
| 
								 | 
							
								  sanei_thread_initialize (ss->reader_taskid);
							 | 
						||
| 
								 | 
							
								  ss->wpipe = -1;
							 | 
						||
| 
								 | 
							
								  ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								  ss->idle = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								  ss->scanning = SANE_FALSE;
							 | 
						||
| 
								 | 
							
								  ss->sp.frontend_cancel = SANE_FALSE;
							 | 
						||
| 
								 | 
							
								  for (j=0; j < BUTTON_GROUP_SIZE; j++)
							 | 
						||
| 
								 | 
							
								    ss->button_option_is_cached[j] = 0;
							 | 
						||
| 
								 | 
							
								  error = pixma_open (i, &ss->s);
							 | 
						||
| 
								 | 
							
								  if (error < 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      sane_close (ss);
							 | 
						||
| 
								 | 
							
								      return map_error (error);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  pixma_enable_background (ss->s, 0);
							 | 
						||
| 
								 | 
							
								  init_option_descriptors (ss);
							 | 
						||
| 
								 | 
							
								  *h = ss;
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								sane_close (SANE_Handle h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  pixma_sane_t **p, *ss;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (p = &first_scanner; *p && *p != (pixma_sane_t *) h; p = &((*p)->next))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (!(*p))
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  ss = *p;
							 | 
						||
| 
								 | 
							
								  sane_cancel (ss);
							 | 
						||
| 
								 | 
							
								  pixma_close (ss->s);
							 | 
						||
| 
								 | 
							
								  *p = ss->next;
							 | 
						||
| 
								 | 
							
								  free (ss);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const SANE_Option_Descriptor *
							 | 
						||
| 
								 | 
							
								sane_get_option_descriptor (SANE_Handle h, SANE_Int n)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (ss && 0 <= n && n < opt_last)
							 | 
						||
| 
								 | 
							
								    return &SOD (n);
							 | 
						||
| 
								 | 
							
								  return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_control_option (SANE_Handle h, SANE_Int n,
							 | 
						||
| 
								 | 
							
										     SANE_Action a, void *v, SANE_Int * i)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								  SANE_Int info = 0;
							 | 
						||
| 
								 | 
							
								  int error;
							 | 
						||
| 
								 | 
							
								  option_descriptor_t *opt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (i)
							 | 
						||
| 
								 | 
							
								    *i = 0;
							 | 
						||
| 
								 | 
							
								  if (!ss)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  if (n < 0 || n >= opt_last)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								  if (!ss->idle && a != SANE_ACTION_GET_VALUE)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (3, "Warning: !idle && !SANE_ACTION_GET_VALUE\n"));
							 | 
						||
| 
								 | 
							
								      if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  opt = &(OPT_IN_CTX[n]);
							 | 
						||
| 
								 | 
							
								  if (!SANE_OPTION_IS_ACTIVE (opt->sod.cap))
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  switch (a)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_SET_VALUE:
							 | 
						||
| 
								 | 
							
								      if ((opt->sod.type != SANE_TYPE_BUTTON && !v) ||
							 | 
						||
| 
								 | 
							
								          !SANE_OPTION_IS_SETTABLE (opt->sod.cap))
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_SET_AUTO:
							 | 
						||
| 
								 | 
							
								      if (!(opt->sod.cap & SANE_CAP_AUTOMATIC) ||
							 | 
						||
| 
								 | 
							
								          !SANE_OPTION_IS_SETTABLE (opt->sod.cap))
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case SANE_ACTION_GET_VALUE:
							 | 
						||
| 
								 | 
							
								      if (!v || !(opt->sod.cap & SANE_CAP_SOFT_DETECT))
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_INVAL;	/* or _UNSUPPORTED? */
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  error = control_option (ss, n, a, v, &info);
							 | 
						||
| 
								 | 
							
								  if (error == SANE_STATUS_GOOD && i)
							 | 
						||
| 
								 | 
							
								    *i = info;
							 | 
						||
| 
								 | 
							
								  return error;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								  pixma_scan_param_t temp, *sp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ss || !p)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ss->idle)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      sp = &ss->sp;		/* sp is calculated in sane_start() */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      calc_scan_param (ss, &temp);
							 | 
						||
| 
								 | 
							
								      sp = &temp;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  p->format = (sp->channels == 3) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
							 | 
						||
| 
								 | 
							
								  p->last_frame = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								  p->lines = sp->h;
							 | 
						||
| 
								 | 
							
								  p->depth = sp->depth;
							 | 
						||
| 
								 | 
							
								  p->pixels_per_line = sp->w;
							 | 
						||
| 
								 | 
							
								  /* p->bytes_per_line = sp->line_size; NOTE: It should work this way, but it doesn't. No SANE frontend can cope with this. */
							 | 
						||
| 
								 | 
							
								  p->bytes_per_line = (sp->w * sp->channels * sp->depth) / 8;
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_start (SANE_Handle h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								  int error = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ss)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  if (!ss->idle && ss->scanning)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (3, "Warning in Sane_start: !idle && scanning. idle=%d, ss->scanning=%d\n",
							 | 
						||
| 
								 | 
							
								                       ss->idle, ss->scanning));
							 | 
						||
| 
								 | 
							
								      if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
							 | 
						||
| 
								 | 
							
								        return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ss->cancel = SANE_FALSE;
							 | 
						||
| 
								 | 
							
								  if (ss->idle ||
							 | 
						||
| 
								 | 
							
								      ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED ||
							 | 
						||
| 
								 | 
							
								      ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU)
							 | 
						||
| 
								 | 
							
								    ss->page_count = 0;	/* start from idle state or scan from flatbed or TPU */
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    ss->page_count++;
							 | 
						||
| 
								 | 
							
								  if (calc_scan_param (ss, &ss->sp) < 0)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Prepare the JPEG decompressor, if needed */
							 | 
						||
| 
								 | 
							
								  if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      SANE_Status status;
							 | 
						||
| 
								 | 
							
								      status = pixma_jpeg_start(ss);
							 | 
						||
| 
								 | 
							
								      if (status != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          PDBG (pixma_dbg(1, "%s: pixma_jpeg_start: %s\n", __func__, sane_strstatus(status)) );
							 | 
						||
| 
								 | 
							
								          return status;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ss->image_bytes_read = 0;
							 | 
						||
| 
								 | 
							
								  /* TODO: Check paper here in sane_start(). A function like
							 | 
						||
| 
								 | 
							
								     pixma_get_status() is needed. */
							 | 
						||
| 
								 | 
							
								  error = start_reader_task (ss);
							 | 
						||
| 
								 | 
							
								  if (error >= 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      ss->output_line_size = (ss->sp.w * ss->sp.channels * ss->sp.depth) / 8;
							 | 
						||
| 
								 | 
							
								      ss->byte_pos_in_line = 0;
							 | 
						||
| 
								 | 
							
								      ss->last_read_status = SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								      ss->scanning = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								      ss->idle = SANE_FALSE;
							 | 
						||
| 
								 | 
							
								      if (ss->sp.mode_jpeg && !ss->jpeg_header_seen)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          SANE_Status status;
							 | 
						||
| 
								 | 
							
								          status = pixma_jpeg_read_header(ss);
							 | 
						||
| 
								 | 
							
								          if (status != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								              pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								              ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								              if (sanei_thread_is_valid (terminate_reader_task (ss, &error))
							 | 
						||
| 
								 | 
							
								                && error != SANE_STATUS_GOOD)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  return error;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return map_error (error);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								  int sum, n;
							 | 
						||
| 
								 | 
							
								  /* Due to 32 pixels alignment, sizeof(temp) is to be greater than:
							 | 
						||
| 
								 | 
							
								   * max(nchannels) * max (sp.line_size - output_line_size)
							 | 
						||
| 
								 | 
							
								   * so currently: 3 * 32 = 96  for better end line cropping efficiency */
							 | 
						||
| 
								 | 
							
								  SANE_Byte temp[100];
							 | 
						||
| 
								 | 
							
								  SANE_Status status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (len)
							 | 
						||
| 
								 | 
							
								    *len = 0;
							 | 
						||
| 
								 | 
							
								  if (!ss || !buf || !len)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  if (ss->cancel)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_CANCELLED;
							 | 
						||
| 
								 | 
							
								  if ((ss->idle)
							 | 
						||
| 
								 | 
							
								      && (ss->sp.source == PIXMA_SOURCE_ADF || ss->sp.source == PIXMA_SOURCE_ADFDUP))
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  if (!ss->scanning)
							 | 
						||
| 
								 | 
							
								    return ss->last_read_status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  status = SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								  /* CCD scanners use software lineart
							 | 
						||
| 
								 | 
							
								   * the scanner must scan 24 bit color or 8 bit grayscale for one bit lineart */
							 | 
						||
| 
								 | 
							
								  if ((ss->sp.line_size - ((ss->sp.software_lineart == 1) ? (ss->output_line_size * 8) : ss->output_line_size)) == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      status = read_image (ss, buf, maxlen, &sum);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      /* FIXME: Because there is no frontend that can cope with padding at
							 | 
						||
| 
								 | 
							
								         the end of line, we've to remove it here in the backend! */
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg (1, "*sane_read***** Warning: padding may cause incomplete scan results\n"));
							 | 
						||
| 
								 | 
							
								      sum = 0;
							 | 
						||
| 
								 | 
							
								      while (sum < maxlen)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          if (ss->byte_pos_in_line < ss->output_line_size)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              n = ss->output_line_size - ss->byte_pos_in_line;
							 | 
						||
| 
								 | 
							
								              if ((maxlen - sum) < n)
							 | 
						||
| 
								 | 
							
								                n = maxlen - sum;
							 | 
						||
| 
								 | 
							
								              status = read_image (ss, buf, n, &n);
							 | 
						||
| 
								 | 
							
								              if (n == 0)
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								              sum += n;
							 | 
						||
| 
								 | 
							
								              buf += n;
							 | 
						||
| 
								 | 
							
								              ss->byte_pos_in_line += n;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              /* skip padding */
							 | 
						||
| 
								 | 
							
								              n = ss->sp.line_size - ss->byte_pos_in_line;
							 | 
						||
| 
								 | 
							
								              if (n > (int) sizeof (temp))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n));
							 | 
						||
| 
								 | 
							
								                  n = sizeof (temp);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              status = read_image (ss, temp, n, &n);
							 | 
						||
| 
								 | 
							
								              if (n == 0)
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								              ss->byte_pos_in_line += n;
							 | 
						||
| 
								 | 
							
								              if (ss->byte_pos_in_line == ss->sp.line_size)
							 | 
						||
| 
								 | 
							
								                ss->byte_pos_in_line = 0;
							 | 
						||
| 
								 | 
							
								             }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  if (ss->cancel)
							 | 
						||
| 
								 | 
							
								    status = SANE_STATUS_CANCELLED;
							 | 
						||
| 
								 | 
							
								  else if ((status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF) &&
							 | 
						||
| 
								 | 
							
									   sum > 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      *len = sum;
							 | 
						||
| 
								 | 
							
								      status = SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  ss->scanning = (status == SANE_STATUS_GOOD);
							 | 
						||
| 
								 | 
							
								  ss->last_read_status = status;
							 | 
						||
| 
								 | 
							
								  return status;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								sane_cancel (SANE_Handle h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ss)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  ss->cancel = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								  ss->sp.frontend_cancel = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								  if (ss->idle)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  close (ss->rpipe);
							 | 
						||
| 
								 | 
							
								  if (ss->sp.mode_jpeg)
							 | 
						||
| 
								 | 
							
								    pixma_jpeg_finish(ss);
							 | 
						||
| 
								 | 
							
								  ss->rpipe = -1;
							 | 
						||
| 
								 | 
							
								  terminate_reader_task (ss, NULL);
							 | 
						||
| 
								 | 
							
								  ss->idle = SANE_TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_set_io_mode (SANE_Handle h, SANE_Bool m)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ss || ss->idle || ss->rpipe == -1)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								#ifdef HAVE_FCNTL_H
							 | 
						||
| 
								 | 
							
								  PDBG (pixma_dbg (2, "Setting %sblocking mode\n", (m) ? "non-" : ""));
							 | 
						||
| 
								 | 
							
								  if (fcntl (ss->rpipe, F_SETFL, (m) ? O_NONBLOCK : 0) == -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      PDBG (pixma_dbg
							 | 
						||
| 
								 | 
							
									    (1, "WARNING:fcntl(F_SETFL) failed %s\n", strerror (errno)));
							 | 
						||
| 
								 | 
							
								      return SANE_STATUS_UNSUPPORTED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								  return (m) ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SANE_Status
							 | 
						||
| 
								 | 
							
								sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  DECL_CTX;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  *fd = -1;
							 | 
						||
| 
								 | 
							
								  if (!ss || !fd || ss->idle || ss->rpipe == -1)
							 | 
						||
| 
								 | 
							
								    return SANE_STATUS_INVAL;
							 | 
						||
| 
								 | 
							
								  *fd = ss->rpipe;
							 | 
						||
| 
								 | 
							
								  return SANE_STATUS_GOOD;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								BEGIN SANE_Option_Descriptor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								type group
							 | 
						||
| 
								 | 
							
								  title Scan mode
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int resolution
							 | 
						||
| 
								 | 
							
								  unit dpi
							 | 
						||
| 
								 | 
							
								  constraint @word_list = ss->dpi_list
							 | 
						||
| 
								 | 
							
								  default 75
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_RESOLUTION
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_RESOLUTION
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type string mode[30]
							 | 
						||
| 
								 | 
							
								  constraint @string_list = ss->mode_list
							 | 
						||
| 
								 | 
							
								  default @s = SANE_VALUE_SCAN_MODE_COLOR
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_MODE
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_MODE
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type string source[30]
							 | 
						||
| 
								 | 
							
								  constraint @string_list = ss->source_list
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_SOURCE
							 | 
						||
| 
								 | 
							
								  desc  Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values.
							 | 
						||
| 
								 | 
							
								  default Flatbed
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type bool button-controlled
							 | 
						||
| 
								 | 
							
								  title Button-controlled scan
							 | 
						||
| 
								 | 
							
								  desc When enabled, scan process will not start immediately. To proceed, press \"SCAN\" button (for MP150) or \"COLOR\" button (for other models). To cancel, press \"GRAY\" button.
							 | 
						||
| 
								 | 
							
								  default SANE_FALSE
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								type group
							 | 
						||
| 
								 | 
							
								  title Gamma
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type bool custom-gamma
							 | 
						||
| 
								 | 
							
								  default SANE_TRUE
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_CUSTOM_GAMMA
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_CUSTOM_GAMMA
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int gamma-table[4096]
							 | 
						||
| 
								 | 
							
								  constraint (0,255,0)
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_GAMMA_VECTOR
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_GAMMA_VECTOR
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type fixed gamma
							 | 
						||
| 
								 | 
							
								  default AUTO_GAMMA
							 | 
						||
| 
								 | 
							
								  constraint (0.3,5,0)
							 | 
						||
| 
								 | 
							
								  title Gamma function exponent
							 | 
						||
| 
								 | 
							
								  desc  Changes intensity of midtones
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								type group
							 | 
						||
| 
								 | 
							
								  title Geometry
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type fixed tl-x
							 | 
						||
| 
								 | 
							
								  unit mm
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  constraint @range = &ss->xrange
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_TL_X
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_TL_X
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type fixed tl-y
							 | 
						||
| 
								 | 
							
								  unit mm
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  constraint @range = &ss->yrange
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_TL_Y
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_TL_Y
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type fixed br-x
							 | 
						||
| 
								 | 
							
								  unit mm
							 | 
						||
| 
								 | 
							
								  default _MAX
							 | 
						||
| 
								 | 
							
								  constraint @range = &ss->xrange
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_BR_X
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_BR_X
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type fixed br-y
							 | 
						||
| 
								 | 
							
								  unit mm
							 | 
						||
| 
								 | 
							
								  default _MAX
							 | 
						||
| 
								 | 
							
								  constraint @range = &ss->yrange
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_SCAN_BR_Y
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_SCAN_BR_Y
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic
							 | 
						||
| 
								 | 
							
								  info reload_params
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								type group
							 | 
						||
| 
								 | 
							
								  title Buttons
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type button button-update
							 | 
						||
| 
								 | 
							
								  title Update button state
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int button-1
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  title Button 1
							 | 
						||
| 
								 | 
							
								  cap soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int button-2
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  title Button 2
							 | 
						||
| 
								 | 
							
								  cap soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int original
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  title Type of original to scan
							 | 
						||
| 
								 | 
							
								  cap soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int target
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  title Target operation type
							 | 
						||
| 
								 | 
							
								  cap soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int scan-resolution
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  title Scan resolution
							 | 
						||
| 
								 | 
							
								  cap soft_detect advanced
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								type group
							 | 
						||
| 
								 | 
							
								  title Extras
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int threshold
							 | 
						||
| 
								 | 
							
								  unit PERCENT
							 | 
						||
| 
								 | 
							
								  default 50
							 | 
						||
| 
								 | 
							
								  constraint (0,100,1)
							 | 
						||
| 
								 | 
							
								  title @SANE_TITLE_THRESHOLD
							 | 
						||
| 
								 | 
							
								  desc  @SANE_DESC_THRESHOLD
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int threshold-curve
							 | 
						||
| 
								 | 
							
								  constraint (0,127,1)
							 | 
						||
| 
								 | 
							
								  title Threshold curve
							 | 
						||
| 
								 | 
							
								  desc  Dynamic threshold curve, from light to dark, normally 50-65
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type int adf-wait
							 | 
						||
| 
								 | 
							
								  default 0
							 | 
						||
| 
								 | 
							
								  constraint (0,3600,1)
							 | 
						||
| 
								 | 
							
								  title ADF Waiting Time
							 | 
						||
| 
								 | 
							
								  desc  When set, the scanner searches the waiting time in seconds for a new document inserted into the automatic document feeder.
							 | 
						||
| 
								 | 
							
								  cap soft_select soft_detect automatic inactive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rem -------------------------------------------
							 | 
						||
| 
								 | 
							
								END SANE_Option_Descriptor
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* pixma_sane_options.c generated by
							 | 
						||
| 
								 | 
							
								 * scripts/pixma_gen_options.py < pixma.c > pixma_sane_options.c
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * pixma_sane_options.h generated by
							 | 
						||
| 
								 | 
							
								 * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								#include "pixma_sane_options.c"
							 |