kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			1894 wiersze
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			1894 wiersze
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
| /* sane - Scanner Access Now Easy.
 | |
|    Copyright (C) 1997 BYTEC GmbH Germany
 | |
|    Written by Helmut Koeberle, Email: helmut.koeberle@bytec.de
 | |
|    Modified by Manuel Panea <Manuel.Panea@rzg.mpg.de>
 | |
|    and Markus Mertinat <Markus.Mertinat@Physik.Uni-Augsburg.DE>
 | |
|    FB620 and FB1200 support by Mitsuru Okaniwa <m-okaniwa@bea.hi-ho.ne.jp>
 | |
|    FS2710 support by Ulrich Deiters <ukd@xenon.pc.uni-koeln.de>
 | |
| 
 | |
|    backend version: 1.12
 | |
| 
 | |
|    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. */
 | |
| 
 | |
| /* This file implements the sane-api */
 | |
| 
 | |
| /* SANE-FLOW-DIAGRAMM
 | |
| 
 | |
|    - sane_init() : initialize backend, attach scanners(devicename,0)
 | |
|    . - sane_get_devices() : query list of scanner-devices
 | |
|    . - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev)
 | |
|    . . - sane_set_io_mode : set blocking-mode
 | |
|    . . - sane_get_select_fd : get scanner-fd
 | |
|    . . - sane_get_option_descriptor() : get option informations
 | |
|    . . - sane_control_option() : change option values
 | |
|    . .
 | |
|    . . - sane_start() : start image aquisition
 | |
|    . .   - sane_get_parameters() : returns actual scan-parameters
 | |
|    . .   - sane_read() : read image-data (from pipe)
 | |
|    . . - sane_cancel() : cancel operation, kill reader_process
 | |
|    
 | |
|    . - sane_close() : close opened scanner-device, do_cancel, free buffer and handle
 | |
|    - sane_exit() : terminate use of backend, free devicename and device-struture
 | |
| */
 | |
| 
 | |
| /* This driver's flow:
 | |
| 
 | |
|  - sane_init
 | |
|  . - attach_one
 | |
|  . . - inquiry
 | |
|  . . - test_unit_ready
 | |
|  . . - medium_position
 | |
|  . . - extended inquiry
 | |
|  . . - mode sense
 | |
|  . . - get_density_curve
 | |
|  - sane_get_devices
 | |
|  - sane_open
 | |
|  . - init_options
 | |
|  - sane_set_io_mode : set blocking-mode
 | |
|  - sane_get_select_fd : get scanner-fd
 | |
|  - sane_get_option_descriptor() : get option informations
 | |
|  - sane_control_option() : change option values
 | |
|  - sane_start() : start image aquisition
 | |
|    - sane_get_parameters() : returns actual scan-parameters
 | |
|    - sane_read() : read image-data (from pipe)
 | |
|    - sane_cancel() : cancel operation, kill reader_process
 | |
|  - sane_close() : close opened scanner-device, do_cancel, free buffer and handle
 | |
|  - sane_exit() : terminate use of backend, free devicename and device-struture
 | |
| */
 | |
| 
 | |
| #include <sane/config.h>
 | |
| 
 | |
| #include <limits.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdarg.h>
 | |
| #include <string.h>
 | |
| #include <math.h>
 | |
| #include <unistd.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #include <fcntl.h> /* for FB1200S */
 | |
| #include <unistd.h> /* for FB1200S */
 | |
| #include <errno.h> /* for FB1200S */
 | |
| 
 | |
| #include <sane/sane.h>
 | |
| #include <sane/saneopts.h>
 | |
| #include <sane/sanei_scsi.h>
 | |
| 
 | |
| #define BACKEND_NAME canon
 | |
| 
 | |
| #include <sane/sanei_backend.h>
 | |
| 
 | |
| #ifndef PATH_MAX
 | |
| #define PATH_MAX	1024
 | |
| #endif
 | |
| 
 | |
| #include <sane/sanei_config.h>
 | |
| #define CANON_CONFIG_FILE "canon.conf"
 | |
| 
 | |
| #include <canon.h>
 | |
| 
 | |
| #define MM_PER_INCH	 25.4
 | |
| 
 | |
| static SANE_Byte primaryHigh[256], primaryLow[256], secondaryHigh[256],
 | |
| 		 secondaryLow[256];	/* modification for FB1200S */
 | |
| 
 | |
| static int num_devices = 0;
 | |
| static CANON_Device *first_dev = NULL;
 | |
| static CANON_Scanner *first_handle = NULL;
 | |
| 
 | |
| static const SANE_String_Const mode_list[] = {
 | |
|   "Lineart", "Halftone", "Gray", "Color", 0
 | |
| };
 | |
| 
 | |
| /* modification for FS2710 */
 | |
| static const SANE_String_Const mode_list_fs2710[] = {
 | |
|   "Color", "Raw", 0
 | |
| };
 | |
| 
 | |
| /* modification for FB620S */
 | |
| static const SANE_String_Const mode_list_fb620[] = {
 | |
|   "Lineart", "Gray", "Color", "Fine color", 0
 | |
| };
 | |
| 
 | |
| /* modification for FB1200S */
 | |
| static const SANE_String_Const mode_list_fb1200[] = {
 | |
|   "Lineart", "Gray", "Color", 0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const tpu_dc_mode_list[] = {
 | |
|   "No transparency correction",
 | |
|   "Correction according to Film type",
 | |
|   "Correction according to Transparency Ratio",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const page_list[] = {
 | |
|   "Show normal options",
 | |
|   "Show advanced options",
 | |
|   "Show all options",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const filmtype_list[] = {
 | |
|   "Negatives",
 | |
|   "Slides",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const negative_filmtype_list[] = {
 | |
|   "Film type 0", "Film type 1", "Film type 2", "Film type 3",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const scanning_speed_list[] = {
 | |
|   "Automatic", "Normal speed", "1/2 normal speed", "1/3 normal speed",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const tpu_filmtype_list[] = {
 | |
|   "Film 0", "Film 1", "Film 2", "Film 3",
 | |
|   0
 | |
| };
 | |
| 
 | |
| static const SANE_String_Const papersize_list[] = {
 | |
|   "A4", "Letter", "B5", "Maximal",
 | |
|   0
 | |
| };
 | |
| 
 | |
| /**************************************************/
 | |
| 
 | |
| static const SANE_Range u8_range = {
 | |
|   0,				/* minimum */
 | |
|   255,				/* maximum */
 | |
|   0				/* quantization */
 | |
| };
 | |
| 
 | |
| #include "canon-scsi.c"
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static size_t
 | |
| max_string_size (const SANE_String_Const strings[])
 | |
| {
 | |
|   size_t size, max_size = 0;
 | |
|   int i;
 | |
|   DBG (11, ">> max_string_size\n");
 | |
| 
 | |
|   for (i = 0; strings[i]; ++i)
 | |
|     {
 | |
|       size = strlen (strings[i]) + 1;
 | |
|       if (size > max_size)
 | |
| 	max_size = size;
 | |
|     }
 | |
| 
 | |
|   DBG (11, "<< max_string_size\n");
 | |
|   return max_size;
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static void
 | |
| get_tpu_stat (int fd, CANON_Device * dev)
 | |
| {
 | |
|   unsigned char tbuf[12 + 5];
 | |
|   size_t buf_size, i;
 | |
|   SANE_Status status;
 | |
| 
 | |
|   DBG (3, ">> get tpu stat\n");
 | |
| 
 | |
|   memset (tbuf, 0, sizeof (tbuf));
 | |
|   buf_size = sizeof (tbuf);
 | |
|   status = get_scan_mode (fd, TRANSPARENCY_UNIT, tbuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "get scan mode failed: %s\n", sane_strstatus (status));
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < buf_size; i++)
 | |
|     {
 | |
|       DBG (3, "scan mode control byte[%d] = %d\n", i, tbuf[i]);
 | |
|     }
 | |
|   dev->tpu.Status = (tbuf[2 + 4 + 5] >> 7) ?
 | |
|     TPU_STAT_INACTIVE : TPU_STAT_NONE;
 | |
|   if (dev->tpu.Status == SANE_TRUE)	/* TPU available */
 | |
|     {
 | |
|       dev->tpu.Status = (tbuf[2 + 4 + 5] && 0x04) ?
 | |
| 	TPU_STAT_INACTIVE : TPU_STAT_ACTIVE;
 | |
|     }
 | |
|   dev->tpu.ControlMode = tbuf[3 + 4 + 5] && 0x03;
 | |
|   dev->tpu.Transparency = tbuf[4 + 4 + 5] * 256 + tbuf[5 + 4 + 5];
 | |
|   dev->tpu.PosNeg = tbuf[6 + 4 + 5] && 0x01;
 | |
|   dev->tpu.FilmType = tbuf[7 + 4 + 5];
 | |
| 
 | |
|   DBG (11, "TPU Status: %d\n", dev->tpu.Status);
 | |
|   DBG (11, "TPU ControlMode: %d\n", dev->tpu.ControlMode);
 | |
|   DBG (11, "TPU Transparency: %d\n", dev->tpu.Transparency);
 | |
|   DBG (11, "TPU PosNeg: %d\n", dev->tpu.PosNeg);
 | |
|   DBG (11, "TPU FilmType: %d\n", dev->tpu.FilmType);
 | |
| 
 | |
|   DBG (3, "<< get tpu stat\n");
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static void
 | |
| get_adf_stat (int fd, CANON_Device * dev)
 | |
| {
 | |
|   size_t buf_size = 0x0C, i;
 | |
|   unsigned char abuf[0x0C];
 | |
|   SANE_Status status;
 | |
| 
 | |
|   DBG (3, ">> get adf stat\n");
 | |
| 
 | |
|   memset (abuf, 0, buf_size);
 | |
|   status = get_scan_mode (fd, AUTO_DOC_FEEDER_UNIT, abuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "get scan mode failed: %s\n", sane_strstatus (status));
 | |
|       perror ("get scan mode failed");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < buf_size; i++)
 | |
|     {
 | |
|       DBG (3, "scan mode control byte[%d] = %d\n", i, abuf[i]);
 | |
|     }
 | |
| 
 | |
|   dev->adf.Status = (abuf[ADF_Status] & ADF_NOT_PRESENT) ?
 | |
|     ADF_STAT_NONE : ADF_STAT_INACTIVE;
 | |
| 
 | |
|   if (dev->adf.Status == SANE_TRUE)	/* ADF available / INACTIVE */
 | |
|     {
 | |
|       dev->adf.Status = (abuf[ADF_Status] & ADF_PROBLEM) ?
 | |
| 	ADF_STAT_INACTIVE : ADF_STAT_ACTIVE;
 | |
|     }
 | |
|   dev->adf.Problem = (abuf[ADF_Status] & ADF_PROBLEM);
 | |
|   dev->adf.Priority = (abuf[ADF_Settings] & ADF_PRIORITY);
 | |
|   dev->adf.Feeder = (abuf[ADF_Settings] & ADF_FEEDER);
 | |
| 
 | |
|   DBG (11, "ADF Status: %d\n", dev->adf.Status);
 | |
|   DBG (11, "ADF Priority: %d\n", dev->adf.Priority);
 | |
|   DBG (11, "ADF Problem: %d\n", dev->adf.Problem);
 | |
|   DBG (11, "ADF Feeder: %d\n", dev->adf.Feeder);
 | |
| 
 | |
|   DBG (3, "<< get adf stat\n");
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| sense_handler (int scsi_fd, u_char * result, void *arg)
 | |
| {
 | |
|   static char me[] = "canon_sense_handler";
 | |
|   CANON_Device *dev = (CANON_Device *) arg;
 | |
|   u_char sense;
 | |
|   int asc;
 | |
|   char *sense_str = NULL;
 | |
|   SANE_Status status;
 | |
| 
 | |
|   DBG (1, ">> sense_handler\n");
 | |
|   DBG (11, "%s(%ld, %p, %p)\n", me, (long) scsi_fd,
 | |
|        (void *) result, (void *) arg);
 | |
|   DBG (11, "sense buffer: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \
 | |
| %02x %02x %02x %02x %02x %02x\n", result[0], result[1], result[2], result[3],
 | |
|   result[4], result[5], result[6], result[7], result[8], result[9], result[10],
 | |
|   result[11], result[12], result[13], result[14], result[15]);
 | |
| 
 | |
|   if (dev && dev->info.is_scsi2)
 | |
|     {
 | |
|       DBG(11, "sense data interpretation for SCSI-2 devices\n");
 | |
|       sense = result[2] & 0x0f;		/* extract the sense key */
 | |
|       if (result[7] > 3)		/* additional sense code available? */
 | |
| 	{
 | |
| 	  asc = (result[12] << 8) + result[13];	/* 12: additional sense code */
 | |
| 	}					/* 13: a.s.c. qualifier */
 | |
|       else
 | |
| 	asc = 0xffff;
 | |
| 
 | |
|       switch (sense)
 | |
| 	{
 | |
| 	case 0x00:
 | |
| 	  DBG(11, "sense category: no error\n");
 | |
| 	  status = SANE_STATUS_GOOD;
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x01:
 | |
| 	  DBG(11, "sense category: recovered error\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x3700:
 | |
| 	      sense_str = "rounded parameter";
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	    }
 | |
| 	  status = SANE_STATUS_GOOD;
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x03:
 | |
| 	  DBG(11, "sense category: medium error\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x8000:
 | |
| 	      sense_str = "ADF jam";
 | |
| 	      break;
 | |
| 	    case 0x8001:
 | |
| 	      sense_str = "ADF cover open";
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	    }
 | |
| 	  status = SANE_STATUS_IO_ERROR;
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x04:
 | |
| 	  DBG(11, "sense category: hardware error\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x6000:
 | |
| 	      sense_str = "lamp failure";
 | |
| 	      break;
 | |
| 	    case 0x6200:
 | |
| 	      sense_str = "scan head positioning error";
 | |
| 	      break;
 | |
| 	    case 0x8001:
 | |
| 	      sense_str = "CPU check error";
 | |
| 	      break;
 | |
| 	    case 0x8002:
 | |
| 	      sense_str = "RAM check error";
 | |
| 	      break;
 | |
| 	    case 0x8003:
 | |
| 	      sense_str = "ROM check error";
 | |
| 	      break;
 | |
| 	    case 0x8004:
 | |
| 	      sense_str = "hardware check error";
 | |
| 	      break;
 | |
| 	    case 0x8005:
 | |
| 	      sense_str = "transparency unit lamp failure";
 | |
| 	      break;
 | |
| 	    case 0x8006:
 | |
| 	      sense_str = "transparency unit scan head positioning failure";
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	    }
 | |
| 	  status = SANE_STATUS_IO_ERROR;
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x05:
 | |
| 	  DBG(11, "sense category: illegal request\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x1a00:
 | |
| 	      sense_str = "parameter list length error";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x2000:
 | |
| 	      sense_str = "invalid command operation code";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x2400:
 | |
| 	      sense_str = "invalid field in CDB";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x2500:
 | |
| 	      sense_str = "unsupported LUN";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x2600:
 | |
| 	      sense_str = "invalid field in parameter list";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x2c00:
 | |
| 	      sense_str = "command sequence error";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x2c01:
 | |
| 	      sense_str = "too many windows specified";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x3a00:
 | |
| 	      sense_str = "medium not present";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x3d00:
 | |
| 	      sense_str = "invalid bit IDENTIFY message";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x8002:
 | |
| 	      sense_str = "option not connect";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x06:
 | |
| 	  DBG(11, "sense category: unit attention\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x2900:
 | |
| 	      sense_str = "power on reset / bus device reset";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x2a00:
 | |
| 	      sense_str = "parameter changed by another initiator";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case 0x0b:
 | |
| 	  DBG(11, "sense category: non-standard\n");
 | |
| 	  switch (asc)
 | |
| 	    {
 | |
| 	    case 0x0000:
 | |
| 	      sense_str = "no additional sense information";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x4500:
 | |
| 	      sense_str = "reselect failure";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x4700:
 | |
| 	      sense_str = "SCSI parity error";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x4800:
 | |
| 	      sense_str = "initiator detected error message received";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x4900:
 | |
| 	      sense_str = "invalid message error";
 | |
| 	      status = SANE_STATUS_UNSUPPORTED;
 | |
| 	      break;
 | |
| 	    case 0x8000:
 | |
| 	      sense_str = "timeout error";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x8001:
 | |
| 	      sense_str = "trancparency unit shading error";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    case 0x8003:
 | |
| 	      sense_str = "lamp not stabilized";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      sense_str = "unknown";
 | |
| 	      status = SANE_STATUS_IO_ERROR;
 | |
| 	    }
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  DBG(11, "sense category: else\n");
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       sense_str = "problem not analyzed (unknown SCSI class)";
 | |
|       status = SANE_STATUS_IO_ERROR;
 | |
|     }
 | |
|   DBG (11, "sense message: %s\n", sense_str);
 | |
| #if 0					/* superfluous? [U.D.] */
 | |
|   s->sense_str = sense_str;
 | |
| #endif
 | |
|   DBG (1, "<< sense_handler\n");
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /***************************************************************/
 | |
| static SANE_Status
 | |
| do_gamma (CANON_Scanner * s)
 | |
| {
 | |
|   SANE_Status status;
 | |
|   u_char gbuf[256];
 | |
|   size_t buf_size;
 | |
|   int i, j, neg, transfer_data_type, from;
 | |
| 
 | |
| 
 | |
|   DBG (7, "sending SET_DENSITY_CURVE\n");
 | |
|   buf_size = 256 * sizeof (u_char);
 | |
|   transfer_data_type = 0x03;
 | |
| 
 | |
|   neg = (s->hw->info.is_filmscanner) ?
 | |
|     strcmp (filmtype_list[1], s->val[OPT_NEGATIVE].s)
 | |
|     : s->val[OPT_HNEGATIVE].w;
 | |
| 
 | |
|   if (!strcmp (s->val[OPT_MODE].s, "Gray"))
 | |
|     {
 | |
|       /* If scanning in gray mode, use the first curve for the
 | |
|          scanner's monochrome gamma component                    */
 | |
|       for (j = 0; j < 256; j++)
 | |
| 	{
 | |
| 	  if (neg == SANE_FALSE)
 | |
| 	    {
 | |
| 	      gbuf[j] = (u_char) s->gamma_table[0][j];
 | |
| 	      DBG (22, "set_density %d: gbuf[%d] = [%d]\n", 0, j, gbuf[j]);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      gbuf[255 - j] = (u_char) (255 - s->gamma_table[0][j]);
 | |
| 	      DBG (22, "set_density %d: gbuf[%d] = [%d]\n", 0, 255 - j,
 | |
| 		   gbuf[255 - j]);
 | |
| 	    }
 | |
| 	}
 | |
|       if ((status = set_density_curve (s->fd, 0, gbuf, &buf_size,
 | |
| 				       transfer_data_type)) !=
 | |
| 	  SANE_STATUS_GOOD)
 | |
| 	{
 | |
| 	  DBG (7, "SET_DENSITY_CURVE\n");
 | |
| 	  sanei_scsi_close (s->fd);
 | |
| 	  s->fd = -1;
 | |
| 	  return (SANE_STATUS_INVAL);
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {				/* colour mode */
 | |
|       /* If in RGB mode but with gamma bind, use the first curve
 | |
|          for all 3 colors red, green, blue */
 | |
|       for (i = 1; i < 4; i++)
 | |
| 	{
 | |
| 	  from = (s->val[OPT_CUSTOM_GAMMA_BIND].w == SANE_TRUE) ? 0 : i;
 | |
| 	  for (j = 0; j < 256; j++)
 | |
| 	    {
 | |
| 	      if (neg == SANE_FALSE)
 | |
| 		{
 | |
| 		  gbuf[j] = (u_char) s->gamma_table[from][j];
 | |
| 		  DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, j,
 | |
| 		       gbuf[j]);
 | |
| 		}
 | |
| 	      else
 | |
| 		{
 | |
| 		  gbuf[255 - j] = (u_char) (255 - s->gamma_table[from][j]);
 | |
| 		  DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, 255 - j,
 | |
| 		       gbuf[255 - j]);
 | |
| 		}
 | |
| 	    }
 | |
| 	  if (s->hw->info.model == FS2710)
 | |
| 	    status = set_density_curve_fs2710 (s, i, gbuf);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if ((status = set_density_curve (s->fd, i, gbuf, &buf_size,
 | |
| 					       transfer_data_type)) !=
 | |
| 		  SANE_STATUS_GOOD)
 | |
| 		{
 | |
| 		  DBG (7, "SET_DENSITY_CURVE\n");
 | |
| 		  sanei_scsi_close (s->fd);
 | |
| 		  s->fd = -1;
 | |
| 		  return (SANE_STATUS_INVAL);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return (SANE_STATUS_GOOD);
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| attach (const char *devnam, CANON_Device ** devp)
 | |
| {
 | |
|   SANE_Status status;
 | |
|   CANON_Device *dev;
 | |
| 
 | |
|   int fd;
 | |
|   u_char ibuf[36], ebuf[74], mbuf[12];
 | |
|   size_t buf_size, i;
 | |
|   char *str;
 | |
| 
 | |
|   DBG (1, ">> attach\n");
 | |
| 
 | |
|   for (dev = first_dev; dev; dev = dev->next)
 | |
|     {
 | |
|       if (strcmp (dev->sane.name, devnam) == 0)
 | |
| 	{
 | |
| 	  if (devp)
 | |
| 	    *devp = dev;
 | |
| 	  return (SANE_STATUS_GOOD);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   DBG (3, "attach: opening %s\n", devnam);
 | |
|   status = sanei_scsi_open (devnam, &fd, sense_handler, dev);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
 | |
|       return (status);
 | |
|     }
 | |
| 
 | |
|   DBG (3, "attach: sending (standard) INQUIRY\n");
 | |
|   memset (ibuf, 0, sizeof (ibuf));
 | |
|   buf_size = sizeof (ibuf);
 | |
|   status = inquiry (fd, 0, ibuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (status);
 | |
|     }
 | |
| 
 | |
|   if (ibuf[0] != 6
 | |
|       || strncmp ((char *) (ibuf + 8), "CANON", 5) != 0
 | |
|       || strncmp ((char *) (ibuf + 16), "IX-", 3) != 0)
 | |
|     {
 | |
|       DBG (1, "attach: device doesn't look like a Canon scanner\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| 
 | |
|   DBG (3, "attach: sending TEST_UNIT_READY\n");
 | |
|   status = test_unit_ready (fd);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: test unit ready failed (%s)\n",
 | |
| 	   sane_strstatus (status));
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (status);
 | |
|     }
 | |
| 
 | |
| #if 0
 | |
|   DBG (3, "attach: sending REQUEST SENSE\n");
 | |
|   memset (sbuf, 0, sizeof (sbuf));
 | |
|   buf_size = sizeof (sbuf);
 | |
|   status = request_sense (fd, sbuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: REQUEST_SENSE failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| 
 | |
|   DBG (3, "attach: sending MEDIUM POSITION\n");
 | |
|   status = medium_position (fd);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: MEDIUM POSITION failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| /*   s->val[OPT_AF_NOW].w == SANE_TRUE; */
 | |
| #endif
 | |
| 
 | |
|   DBG (3, "attach: sending RESERVE UNIT\n");
 | |
|   status = reserve_unit (fd);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: RESERVE UNIT failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| 
 | |
| #if 0
 | |
|   DBG (3, "attach: sending GET SCAN MODE for transparency unit\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = sizeof (ebuf);
 | |
|   buf_size = 12;
 | |
|   status = get_scan_mode (fd, TRANSPARENCY_UNIT, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: GET SCAN MODE for transparency unit failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
|   for (i=0; i<buf_size; i++)
 | |
|     {
 | |
|       DBG(3, "scan mode trans byte[%d] = %d\n", i, ebuf[i]);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   DBG (3, "attach: sending GET SCAN MODE for scan control conditions\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = sizeof (ebuf);
 | |
|   status = get_scan_mode (fd, SCAN_CONTROL_CONDITIONS, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
|   for (i = 0; i < buf_size; i++)
 | |
|     {
 | |
|       DBG (3, "scan mode byte[%d] = %d\n", i, ebuf[i]);
 | |
|     }
 | |
| 
 | |
|   DBG (3, "attach: sending (extended) INQUIRY\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = sizeof (ebuf);
 | |
|   status = inquiry (fd, 1, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: (extended) INQUIRY failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| 
 | |
| #if 0
 | |
|   DBG (3, "attach: sending GET SCAN MODE for transparency unit\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = 64;
 | |
|   status = get_scan_mode (fd, ALL_SCAN_MODE_PAGES,	/* transparency unit */
 | |
| 			  ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
|   for (i = 0; i < buf_size; i++)
 | |
|     {
 | |
|       DBG (3, "scan mode control byte[%d] = %d\n", i, ebuf[i]);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
|   DBG (3, "attach: sending GET SCAN MODE for all scan mode pages\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = 32;
 | |
|   status = get_scan_mode (fd, (u_char)ALL_SCAN_MODE_PAGES, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
|   for (i=0; i<buf_size; i++)
 | |
|     {
 | |
|     DBG(3, "scan mode control byte[%d] = %d\n", i, ebuf[i]);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| 
 | |
|   DBG (3, "attach: sending MODE SENSE\n");
 | |
|   memset (mbuf, 0, sizeof (mbuf));
 | |
|   buf_size = sizeof (mbuf);
 | |
|   status = mode_sense (fd, mbuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "attach: MODE_SENSE failed\n");
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_INVAL);
 | |
|     }
 | |
| 
 | |
|   dev = malloc (sizeof (*dev));
 | |
|   if (!dev)
 | |
|     {
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_NO_MEM);
 | |
|     }
 | |
|   memset (dev, 0, sizeof (*dev));
 | |
| 
 | |
|   dev->sane.name = strdup (devnam);
 | |
|   dev->sane.vendor = "CANON";
 | |
|   if ((str = calloc (16 + 1, 1)) == NULL)
 | |
|     {
 | |
|       sanei_scsi_close (fd);
 | |
|       fd = -1;
 | |
|       return (SANE_STATUS_NO_MEM);
 | |
|     }
 | |
|   strncpy (str, (char *) (ibuf + 16), 16);
 | |
|   dev->sane.model = str;
 | |
| 
 | |
|   /* Register the fixed properties of the scanner below:
 | |
|      - whether it is a film scanner or a flatbed scanner
 | |
|      - whether it can have an automatic document feeder (ADF)
 | |
|      - whether it can be equipped with a transparency unit (TPU)
 | |
|      - whether it has got focus control
 | |
|      - whether it can optimize image parameters (autoexposure)
 | |
|      - whether it can calibrate itself
 | |
|      - whether it can eject the media
 | |
|      - whether it can mirror the scanned data
 | |
|      - whether it is an SCSI-2 device (gives status information by "sense key")
 | |
|      - whether it is a film scanner (or can be used as one)
 | |
|      - whether it has fixed, hardware-set scan resolutions only
 | |
|   */
 | |
|   if (strncmp (str, "IX-27015", 8) == 0)	/* FS2700S */
 | |
|     {
 | |
|       dev->info.model = CS2700;
 | |
|       dev->sane.type = "film scanner";
 | |
|       dev->adf.Status = ADF_STAT_NONE;
 | |
|       dev->tpu.Status = TPU_STAT_NONE;
 | |
|       dev->info.can_focus = SANE_TRUE;
 | |
|       dev->info.can_autoexpose = SANE_FALSE;
 | |
|       dev->info.can_calibrate = SANE_FALSE;
 | |
|       dev->info.can_eject = SANE_TRUE;
 | |
|       dev->info.can_mirror = SANE_TRUE;
 | |
|       dev->info.is_scsi2 = SANE_TRUE;
 | |
|       dev->info.is_filmscanner = SANE_TRUE;
 | |
|       dev->info.has_fixed_resolutions = SANE_TRUE;
 | |
|     }
 | |
|   else if (strncmp (str, "IX-27025E", 9) == 0)	/* FS2710S */
 | |
|     {
 | |
|       dev->info.model = FS2710;
 | |
|       dev->sane.type = "film scanner";
 | |
|       dev->adf.Status = ADF_STAT_NONE;
 | |
|       dev->tpu.Status = TPU_STAT_NONE;
 | |
|       dev->info.can_focus = SANE_TRUE;
 | |
|       dev->info.can_autoexpose = SANE_FALSE;
 | |
|       dev->info.can_calibrate = SANE_FALSE;
 | |
|       dev->info.can_eject = SANE_TRUE;
 | |
|       dev->info.can_mirror = SANE_TRUE;
 | |
|       dev->info.is_scsi2 = SANE_TRUE;
 | |
|       dev->info.is_filmscanner = SANE_TRUE;
 | |
|       dev->info.has_fixed_resolutions = SANE_TRUE;
 | |
|     }
 | |
|   else if (strncmp (str, "IX-06035E", 9) == 0)	/* FB620S */
 | |
|     {
 | |
|       dev->info.model = FB620;
 | |
|       dev->sane.type = "flatbed scanner";
 | |
|       dev->adf.Status = ADF_STAT_NONE;
 | |
|       dev->tpu.Status = TPU_STAT_NONE;
 | |
|       dev->info.can_focus = SANE_FALSE;
 | |
|       dev->info.can_autoexpose = SANE_FALSE;
 | |
|       dev->info.can_calibrate = SANE_TRUE;
 | |
|       dev->info.can_eject = SANE_FALSE;
 | |
|       dev->info.can_mirror = SANE_FALSE;
 | |
|       dev->info.is_scsi2 = SANE_TRUE;
 | |
|       dev->info.is_filmscanner = SANE_FALSE;
 | |
|       dev->info.has_fixed_resolutions = SANE_TRUE;
 | |
|     }
 | |
|   else if (strncmp (str, "IX-12015E", 9) == 0)	/* FB1200S */
 | |
|     {
 | |
|       dev->info.model = FB1200;
 | |
|       dev->sane.type = "flatbed scanner";
 | |
|       dev->adf.Status = ADF_STAT_ACTIVE;
 | |
|       dev->tpu.Status = TPU_STAT_NONE;
 | |
|       dev->info.can_focus = SANE_FALSE;
 | |
|       dev->info.can_autoexpose = SANE_FALSE;
 | |
|       dev->info.can_calibrate = SANE_FALSE;
 | |
|       dev->info.can_eject = SANE_FALSE;
 | |
|       dev->info.can_mirror = SANE_FALSE;
 | |
|       dev->info.is_scsi2 = SANE_TRUE;
 | |
|       dev->info.is_filmscanner = SANE_FALSE;
 | |
|       dev->info.has_fixed_resolutions = SANE_TRUE;
 | |
|     }
 | |
|   else						/* CS300, CS600 */
 | |
|     {
 | |
|       dev->info.model = CS3_600;
 | |
|       dev->sane.type = "flatbed scanner";
 | |
|       dev->adf.Status = ADF_STAT_ACTIVE;
 | |
|       dev->tpu.Status = TPU_STAT_ACTIVE;
 | |
|       dev->info.can_focus = SANE_FALSE;
 | |
|       dev->info.can_autoexpose = SANE_FALSE;
 | |
|       dev->info.can_calibrate = SANE_FALSE;
 | |
|       dev->info.can_eject = SANE_FALSE;
 | |
|       dev->info.can_mirror = SANE_TRUE;
 | |
|       dev->info.is_scsi2 = SANE_TRUE;
 | |
|       dev->info.is_filmscanner = SANE_FALSE;
 | |
|       dev->info.has_fixed_resolutions = SANE_FALSE;
 | |
|     }
 | |
| 
 | |
|   DBG (5, "dev->sane.name = '%s'\n", dev->sane.name);
 | |
|   DBG (5, "dev->sane.vendor = '%s'\n", dev->sane.vendor);
 | |
|   DBG (5, "dev->sane.model = '%s'\n", dev->sane.model);
 | |
|   DBG (5, "dev->sane.type = '%s'\n", dev->sane.type);
 | |
| 
 | |
|   if (dev->tpu.Status != TPU_STAT_NONE)
 | |
|     get_tpu_stat (fd, dev);		/* Query TPU */
 | |
|   if (dev->adf.Status != ADF_STAT_NONE)
 | |
|     get_adf_stat (fd, dev);		/* Query ADF */
 | |
| 
 | |
|   dev->info.bmu = mbuf[6];
 | |
|   DBG (5, "bmu=%d\n", dev->info.bmu);
 | |
|   dev->info.mud = (mbuf[8] << 8) + mbuf[9];
 | |
|   DBG (5, "mud=%d\n", dev->info.mud);
 | |
| 
 | |
|   dev->info.xres_default = (ebuf[5] << 8) + ebuf[6];
 | |
|   DBG (5, "xres_default=%d\n", dev->info.xres_default);
 | |
|   dev->info.xres_range.max = (ebuf[10] << 8) + ebuf[11];
 | |
|   DBG (5, "xres_range.max=%d\n", dev->info.xres_range.max);
 | |
|   dev->info.xres_range.min = (ebuf[14] << 8) + ebuf[15];
 | |
|   DBG (5, "xres_range.min=%d\n", dev->info.xres_range.min);
 | |
|   dev->info.xres_range.quant = ebuf[9] >> 4;
 | |
|   DBG (5, "xres_range.quant=%d\n", dev->info.xres_range.quant);
 | |
| 
 | |
|   dev->info.yres_default = (ebuf[7] << 8) + ebuf[8];
 | |
|   DBG (5, "yres_default=%d\n", dev->info.yres_default);
 | |
|   dev->info.yres_range.max = (ebuf[12] << 8) + ebuf[13];
 | |
|   DBG (5, "yres_range.max=%d\n", dev->info.yres_range.max);
 | |
|   dev->info.yres_range.min = (ebuf[16] << 8) + ebuf[17];
 | |
|   DBG (5, "yres_range.min=%d\n", dev->info.yres_range.min);
 | |
|   dev->info.yres_range.quant = ebuf[9] & 0x0f;
 | |
|   DBG (5, "xres_range.quant=%d\n", dev->info.xres_range.quant);
 | |
| 
 | |
|   dev->info.x_range.min = SANE_FIX (0.0);
 | |
|   dev->info.x_range.max = (ebuf[20] << 24) + (ebuf[21] << 16)
 | |
|     + (ebuf[22] << 8) + ebuf[23] - 1;
 | |
|   dev->info.x_range.max =
 | |
|     SANE_FIX (dev->info.x_range.max * MM_PER_INCH / dev->info.mud);
 | |
|   DBG (5, "x_range.max=%d\n", dev->info.x_range.max);
 | |
|   dev->info.x_range.quant = 0;
 | |
| 
 | |
|   dev->info.y_range.min = SANE_FIX (0.0);
 | |
|   dev->info.y_range.max = (ebuf[24] << 24) + (ebuf[25] << 16)
 | |
|     + (ebuf[26] << 8) + ebuf[27] - 1;
 | |
|   dev->info.y_range.max =
 | |
|     SANE_FIX (dev->info.y_range.max * MM_PER_INCH / dev->info.mud);
 | |
|   DBG (5, "y_range.max=%d\n", dev->info.y_range.max);
 | |
|   dev->info.y_range.quant = 0;
 | |
| 
 | |
|   dev->info.x_adf_range.max = (ebuf[30] << 24) + (ebuf[31] << 16)
 | |
|     + (ebuf[32] << 8) + ebuf[33] - 1;
 | |
|   DBG (5, "x_adf_range.max=%d\n", dev->info.x_adf_range.max);
 | |
|   dev->info.y_adf_range.max = (ebuf[34] << 24) + (ebuf[35] << 16)
 | |
|     + (ebuf[36] << 8) + ebuf[37] - 1;
 | |
|   DBG (5, "y_adf_range.max=%d\n", dev->info.y_adf_range.max);
 | |
| 
 | |
|   dev->info.brightness_range.min = 0;
 | |
|   dev->info.brightness_range.max = 255;
 | |
|   dev->info.brightness_range.quant = 0;
 | |
| 
 | |
|   dev->info.contrast_range.min = 1;
 | |
|   dev->info.contrast_range.max = 255;
 | |
|   dev->info.contrast_range.quant = 0;
 | |
| 
 | |
|   dev->info.threshold_range.min = 1;
 | |
|   dev->info.threshold_range.max = 255;
 | |
|   dev->info.threshold_range.quant = 0;
 | |
| 
 | |
|   dev->info.HiliteR_range.min = 0;
 | |
|   dev->info.HiliteR_range.max = 255;
 | |
|   dev->info.HiliteR_range.quant = 0;
 | |
| 
 | |
|   dev->info.ShadowR_range.min = 0;
 | |
|   dev->info.ShadowR_range.max = 254;
 | |
|   dev->info.ShadowR_range.quant = 0;
 | |
| 
 | |
|   dev->info.HiliteG_range.min = 0;
 | |
|   dev->info.HiliteG_range.max = 255;
 | |
|   dev->info.HiliteG_range.quant = 0;
 | |
| 
 | |
|   dev->info.ShadowG_range.min = 0;
 | |
|   dev->info.ShadowG_range.max = 254;
 | |
|   dev->info.ShadowG_range.quant = 0;
 | |
| 
 | |
|   dev->info.HiliteB_range.min = 0;
 | |
|   dev->info.HiliteB_range.max = 255;
 | |
|   dev->info.HiliteB_range.quant = 0;
 | |
| 
 | |
|   dev->info.ShadowB_range.min = 0;
 | |
|   dev->info.ShadowB_range.max = 254;
 | |
|   dev->info.ShadowB_range.quant = 0;
 | |
| 
 | |
|   dev->info.focus_range.min = 0;
 | |
|   dev->info.focus_range.max = 255;
 | |
|   dev->info.focus_range.quant = 0;
 | |
| 
 | |
|   dev->info.TPU_Transparency_range.min = 0;
 | |
|   dev->info.TPU_Transparency_range.max = 10000;
 | |
|   dev->info.TPU_Transparency_range.quant = 100;
 | |
| 
 | |
|   sanei_scsi_close (fd);
 | |
|   fd = -1;
 | |
| 
 | |
|   ++num_devices;
 | |
|   dev->next = first_dev;
 | |
|   first_dev = dev;
 | |
| 
 | |
|   if (devp)
 | |
|     *devp = dev;
 | |
| 
 | |
|   DBG (1, "<< attach\n");
 | |
|   return (SANE_STATUS_GOOD);
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| do_cancel (CANON_Scanner * s)
 | |
| {
 | |
|   SANE_Status status;
 | |
| 
 | |
|   DBG (1, ">> do_cancel\n");
 | |
| 
 | |
|   s->scanning = SANE_FALSE;
 | |
| 
 | |
|   if (s->fd >= 0)
 | |
|     {
 | |
|       if (s->val[OPT_EJECT_AFTERSCAN].w && ! (s->val[OPT_PREVIEW].w
 | |
|       && s->hw->info.is_filmscanner))
 | |
| 	{
 | |
| 	  DBG (3, "do_cancel: sending MEDIUM POSITION\n");
 | |
| 	  status = medium_position (s->fd);
 | |
| 	  if (status != SANE_STATUS_GOOD)
 | |
| 	    {
 | |
| 	      DBG (1, "do_cancel: MEDIUM POSITION failed\n");
 | |
| 	      return (SANE_STATUS_INVAL);
 | |
| 	    }
 | |
| 	  s->AF_NOW = SANE_TRUE;
 | |
| 	  DBG (1, "do_cancel AF_NOW = '%d'\n", s->AF_NOW);
 | |
| 	}
 | |
| 
 | |
|       DBG (21, "do_cancel: reset_flag = %d\n", s->reset_flag);
 | |
|       if ((s->reset_flag == 1) && (s->hw->info.model == FB620))
 | |
| 	{
 | |
| 	  status = reset_scanner (s->fd);
 | |
| 	  if (status != SANE_STATUS_GOOD)
 | |
| 	    {
 | |
| 	      DBG (21, "RESET SCANNER failed\n");
 | |
| 	      sanei_scsi_close (s->fd);
 | |
| 	      s->fd = -1;
 | |
| 	      return (SANE_STATUS_INVAL);
 | |
| 	    }
 | |
| 	  DBG (21, "RESET SCANNER\n");
 | |
| 	  s->reset_flag = 0;
 | |
| 	  DBG (21, "do_cancel: reset_flag = %d\n", s->reset_flag);
 | |
| 	  s->time0 = -1;
 | |
| 	  DBG (21, "time0 = %ld\n", s->time0);
 | |
| 	}
 | |
| 
 | |
|       if (s->hw->info.model == FB1200)
 | |
| 	{
 | |
| 	  DBG (3, "CANCEL FB1200S\n");
 | |
| 	  status = cancel (s->fd);
 | |
| 	  if (status != SANE_STATUS_GOOD)
 | |
| 	    {
 | |
| 	      DBG (1, "CANCEL FB1200S failed\n");
 | |
| 	      return (SANE_STATUS_INVAL);
 | |
| 	    }
 | |
| 	  DBG (3, "CANCEL FB1200S OK\n");
 | |
| 	}
 | |
| 
 | |
|       sanei_scsi_close (s->fd);
 | |
|       s->fd = -1;
 | |
|     }
 | |
| 
 | |
|   DBG (1, "<< do_cancel\n");
 | |
|   return (SANE_STATUS_CANCELLED);
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| init_options (CANON_Scanner * s)
 | |
| {
 | |
|   int i;
 | |
|   DBG (1, ">> init_options\n");
 | |
| 
 | |
|   memset (s->opt, 0, sizeof (s->opt));
 | |
|   memset (s->val, 0, sizeof (s->val));
 | |
| 
 | |
|   s->AF_NOW = SANE_TRUE;
 | |
| 
 | |
|   for (i = 0; i < NUM_OPTIONS; ++i)
 | |
|     {
 | |
|       s->opt[i].size = sizeof (SANE_Word);
 | |
|       s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | |
|     }
 | |
| 
 | |
|   s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
 | |
|   s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
 | |
|   s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
 | |
|   s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
 | |
| 
 | |
|   /* "Mode" group: */
 | |
|   s->opt[OPT_MODE_GROUP].title = "Scan Mode";
 | |
|   s->opt[OPT_MODE_GROUP].desc = "";
 | |
|   s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_MODE_GROUP].cap = 0;
 | |
|   s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* scan mode */
 | |
|   s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
| 
 | |
|   switch (s->hw->info.model)
 | |
|     {
 | |
|     case FB620:
 | |
|       s->opt[OPT_MODE].size = max_string_size (mode_list_fb620);
 | |
|       s->opt[OPT_MODE].constraint.string_list = mode_list_fb620;
 | |
|       s->val[OPT_MODE].s = strdup (mode_list_fb620[3]);
 | |
|       break;
 | |
|     case FB1200:
 | |
|       s->opt[OPT_MODE].size = max_string_size (mode_list_fb1200);
 | |
|       s->opt[OPT_MODE].constraint.string_list = mode_list_fb1200;
 | |
|       s->val[OPT_MODE].s = strdup (mode_list_fb1200[2]);
 | |
|       break;
 | |
|     case FS2710:
 | |
|       s->opt[OPT_MODE].size = max_string_size (mode_list_fs2710);
 | |
|       s->opt[OPT_MODE].constraint.string_list = mode_list_fs2710;
 | |
|       s->val[OPT_MODE].s = strdup (mode_list_fs2710[0]);
 | |
|       break;
 | |
|     default:
 | |
|       s->opt[OPT_MODE].size = max_string_size (mode_list);
 | |
|       s->opt[OPT_MODE].constraint.string_list = mode_list;
 | |
|       s->val[OPT_MODE].s = strdup (mode_list[3]);
 | |
|     }
 | |
| 
 | |
|   /* Slides or negatives */
 | |
|   s->opt[OPT_NEGATIVE].name = "film-type";
 | |
|   s->opt[OPT_NEGATIVE].title = "Film type";
 | |
|   s->opt[OPT_NEGATIVE].desc =
 | |
|     "Selects the film type, i.e. negatives or slides";
 | |
|   s->opt[OPT_NEGATIVE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_NEGATIVE].size = max_string_size (filmtype_list);
 | |
|   s->opt[OPT_NEGATIVE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_NEGATIVE].constraint.string_list = filmtype_list;
 | |
|   s->opt[OPT_NEGATIVE].cap |=
 | |
|     (s->hw->info.is_filmscanner)? 0 : SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_NEGATIVE].s = strdup (filmtype_list[1]);
 | |
| 
 | |
|   /* Negative film type */
 | |
|   s->opt[OPT_NEGATIVE_TYPE].name = "negative-film-type";
 | |
|   s->opt[OPT_NEGATIVE_TYPE].title = "Negative film type";
 | |
|   s->opt[OPT_NEGATIVE_TYPE].desc = "Selects the negative film type";
 | |
|   s->opt[OPT_NEGATIVE_TYPE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_NEGATIVE_TYPE].size = max_string_size (negative_filmtype_list);
 | |
|   s->opt[OPT_NEGATIVE_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_NEGATIVE_TYPE].constraint.string_list = negative_filmtype_list;
 | |
|   s->opt[OPT_NEGATIVE_TYPE].cap |=
 | |
|     (s->hw->info.is_filmscanner) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_NEGATIVE_TYPE].s = strdup (negative_filmtype_list[0]);
 | |
| 
 | |
|   /* Scanning speed */
 | |
|   s->opt[OPT_SCANNING_SPEED].name = "scanning-speed";
 | |
|   s->opt[OPT_SCANNING_SPEED].title = "Scanning speed";
 | |
|   s->opt[OPT_SCANNING_SPEED].desc = "Selects the scanning speed";
 | |
|   s->opt[OPT_SCANNING_SPEED].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_SCANNING_SPEED].size = max_string_size (scanning_speed_list);
 | |
|   s->opt[OPT_SCANNING_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_SCANNING_SPEED].constraint.string_list = scanning_speed_list;
 | |
|   s->opt[OPT_SCANNING_SPEED].cap |=
 | |
|     (s->hw->info.model == CS2700) ? 0 : SANE_CAP_INACTIVE;
 | |
|   if (s->hw->info.model != CS2700)
 | |
|     s->opt[OPT_SCANNING_SPEED].cap &= ~SANE_CAP_SOFT_SELECT;
 | |
|   s->val[OPT_SCANNING_SPEED].s = strdup (scanning_speed_list[0]);
 | |
| 
 | |
|   /* "Resolution" group: */
 | |
|   s->opt[OPT_RESOLUTION_GROUP].title = "Scan Resolution";
 | |
|   s->opt[OPT_RESOLUTION_GROUP].desc = "";
 | |
|   s->opt[OPT_RESOLUTION_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_RESOLUTION_GROUP].cap = 0;
 | |
|   s->opt[OPT_RESOLUTION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* bind resolution */
 | |
|   s->opt[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
 | |
|   s->opt[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
 | |
|   s->opt[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
 | |
|   s->opt[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
 | |
| 
 | |
|   /* hardware resolutions only */
 | |
|   s->opt[OPT_HW_RESOLUTION_ONLY].name = "hw-resolution-only";
 | |
|   s->opt[OPT_HW_RESOLUTION_ONLY].title = "Hardware resolution";
 | |
|   s->opt[OPT_HW_RESOLUTION_ONLY].desc = "Use only hardware resolutions";
 | |
|   s->opt[OPT_HW_RESOLUTION_ONLY].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_HW_RESOLUTION_ONLY].w = SANE_TRUE;
 | |
|   s->opt[OPT_HW_RESOLUTION_ONLY].cap |=
 | |
|     (s->hw->info.has_fixed_resolutions)? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* x-resolution */
 | |
|   s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
 | |
|   s->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
 | |
|   s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
 | |
|   s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI;
 | |
|   if (s->hw->info.has_fixed_resolutions)
 | |
|     {
 | |
|       int iCnt;
 | |
|       float iRes;		/* modification for FB620S */
 | |
|       s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | |
|       iCnt = 0;
 | |
| 
 | |
|       iRes = s->hw->info.xres_range.max;
 | |
|       DBG (5, "hw->info.xres_range.max=%d\n", s->hw->info.xres_range.max);
 | |
|       s->opt[OPT_X_RESOLUTION].constraint.word_list = s->xres_word_list;
 | |
| 
 | |
|       /* go to minimum resolution by dividing by 2 */
 | |
|       while (iRes >= s->hw->info.xres_range.min)
 | |
| 	{
 | |
| 	  iRes /= 2;
 | |
| 	}
 | |
|       /* fill array upto maximum resolution */
 | |
|       while (iRes < s->hw->info.xres_range.max)
 | |
| 	{
 | |
| 	  iRes *= 2;
 | |
| 	  s->xres_word_list[++iCnt] = iRes;
 | |
| 	}
 | |
|       s->xres_word_list[0] = iCnt;
 | |
|       s->val[OPT_X_RESOLUTION].w = s->xres_word_list[2];
 | |
| 
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|       s->opt[OPT_X_RESOLUTION].constraint.range = &s->hw->info.xres_range;
 | |
|       s->val[OPT_X_RESOLUTION].w = 300;
 | |
|     }
 | |
| 
 | |
|   /* y-resolution */
 | |
|   s->opt[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
 | |
|   s->opt[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
 | |
|   s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
 | |
|   s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
 | |
|   s->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
 | |
|   if (s->hw->info.has_fixed_resolutions)
 | |
|     {
 | |
|       int iCnt;
 | |
|       float iRes;		/* modification for FB620S */
 | |
|       s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | |
|       iCnt = 0;
 | |
| 
 | |
|       iRes = s->hw->info.yres_range.max;
 | |
|       DBG (5, "hw->info.yres_range.max=%d\n", s->hw->info.yres_range.max);
 | |
|       s->opt[OPT_Y_RESOLUTION].constraint.word_list = s->yres_word_list;
 | |
| 
 | |
|       /* go to minimum resolution by dividing by 2 */
 | |
|       while (iRes >= s->hw->info.yres_range.min)
 | |
| 	{
 | |
| 	  iRes /= 2;
 | |
| 	}
 | |
|       /* fill array upto maximum resolution */
 | |
|       while (iRes < s->hw->info.yres_range.max)
 | |
| 	{
 | |
| 	  iRes *= 2;
 | |
| 	  s->yres_word_list[++iCnt] = iRes;
 | |
| 	}
 | |
|       s->yres_word_list[0] = iCnt;
 | |
|       s->val[OPT_Y_RESOLUTION].w = s->yres_word_list[2];
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|       s->opt[OPT_Y_RESOLUTION].constraint.range = &s->hw->info.yres_range;
 | |
|       s->val[OPT_Y_RESOLUTION].w = 300;
 | |
|     }
 | |
| 
 | |
|   /* Focus group: */
 | |
|   s->opt[OPT_FOCUS_GROUP].title = "Focus";
 | |
|   s->opt[OPT_FOCUS_GROUP].desc = "";
 | |
|   s->opt[OPT_FOCUS_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_FOCUS_GROUP].cap = SANE_CAP_ADVANCED;
 | |
|   s->opt[OPT_FOCUS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_FOCUS_GROUP].cap |=
 | |
|     (s->hw->info.can_focus) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* Auto-Focus switch */
 | |
|   s->opt[OPT_AF].name = "af";
 | |
|   s->opt[OPT_AF].title = "Auto Focus";
 | |
|   s->opt[OPT_AF].desc = "Enable/disable Auto Focus";
 | |
|   s->opt[OPT_AF].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_AF].cap |= (s->hw->info.can_focus) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_AF].w = s->hw->info.can_focus;
 | |
| 
 | |
|   /* Auto-Focus once switch */
 | |
|   s->opt[OPT_AF_ONCE].name = "afonce";
 | |
|   s->opt[OPT_AF_ONCE].title = "Auto Focus only once";
 | |
|   s->opt[OPT_AF_ONCE].desc = "Do Auto Focus only once between ejects";
 | |
|   s->opt[OPT_AF_ONCE].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_AF_ONCE].cap |= (s->hw->info.can_focus) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_AF_ONCE].w = s->hw->info.can_focus;
 | |
| 
 | |
|   /* Manual focus */
 | |
|   s->opt[OPT_FOCUS].name = "focus";
 | |
|   s->opt[OPT_FOCUS].title = "Manual focus position";
 | |
|   s->opt[OPT_FOCUS].desc =
 | |
|     "Set the optical system's focus position by hand. The default position is 128.";
 | |
|   s->opt[OPT_FOCUS].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_FOCUS].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_FOCUS].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_FOCUS].constraint.range = &s->hw->info.focus_range;
 | |
|   s->opt[OPT_FOCUS].cap |= (s->hw->info.can_focus) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_FOCUS].w = (s->hw->info.can_focus) ? 128 : 0;
 | |
| 
 | |
|   /* Margins group: */
 | |
|   s->opt[OPT_MARGINS_GROUP].title = "Scan margins";
 | |
|   s->opt[OPT_MARGINS_GROUP].desc = "";
 | |
|   s->opt[OPT_MARGINS_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_MARGINS_GROUP].cap = SANE_CAP_ADVANCED;
 | |
|   s->opt[OPT_MARGINS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* top-left x */
 | |
|   s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_TL_X].constraint.range = &s->hw->info.x_range;
 | |
|   s->val[OPT_TL_X].w = 0;
 | |
| 
 | |
|   /* top-left y */
 | |
|   s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_TL_Y].constraint.range = &s->hw->info.y_range;
 | |
|   s->val[OPT_TL_Y].w = 0;
 | |
| 
 | |
|   /* bottom-right x */
 | |
|   s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_BR_X].constraint.range = &s->hw->info.x_range;
 | |
|   s->val[OPT_BR_X].w = s->hw->info.x_range.max;
 | |
| 
 | |
|   /* bottom-right y */
 | |
|   s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_BR_Y].constraint.range = &s->hw->info.y_range;
 | |
|   s->val[OPT_BR_Y].w = s->hw->info.y_range.max;
 | |
| 
 | |
|   /* Colors group: */
 | |
|   s->opt[OPT_COLORS_GROUP].title = "Extra color adjustments";
 | |
|   s->opt[OPT_COLORS_GROUP].desc = "";
 | |
|   s->opt[OPT_COLORS_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_COLORS_GROUP].cap = SANE_CAP_ADVANCED;
 | |
|   s->opt[OPT_COLORS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* Positive/Negative switch for the CanoScan 300/600 models */
 | |
|   s->opt[OPT_HNEGATIVE].name = SANE_NAME_NEGATIVE;
 | |
|   s->opt[OPT_HNEGATIVE].title = SANE_TITLE_NEGATIVE;
 | |
|   s->opt[OPT_HNEGATIVE].desc = SANE_DESC_NEGATIVE;
 | |
|   s->opt[OPT_HNEGATIVE].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_HNEGATIVE].cap |=
 | |
|     (s->hw->info.model == CS2700 || s->hw->info.model == FS2710) ?
 | |
|     SANE_CAP_INACTIVE : 0;
 | |
|   s->val[OPT_HNEGATIVE].w = SANE_FALSE;
 | |
| 
 | |
|   /* Same values for highlight and shadow points for red, green, blue */
 | |
|   s->opt[OPT_BIND_HILO].name = "bind-highlight-shadow-points";
 | |
|   s->opt[OPT_BIND_HILO].title = SANE_TITLE_RGB_BIND;
 | |
|   s->opt[OPT_BIND_HILO].desc = SANE_DESC_RGB_BIND;
 | |
|   s->opt[OPT_BIND_HILO].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_BIND_HILO].cap |=
 | |
|     (s->hw->info.model == FB620) ? SANE_CAP_INACTIVE : 0;
 | |
|   s->val[OPT_BIND_HILO].w = SANE_TRUE;
 | |
| 
 | |
|   /* highlight point for red   */
 | |
|   s->opt[OPT_HILITE_R].name = SANE_NAME_HIGHLIGHT_R;
 | |
|   s->opt[OPT_HILITE_R].title = SANE_TITLE_HIGHLIGHT_R;
 | |
|   s->opt[OPT_HILITE_R].desc = SANE_DESC_HIGHLIGHT_R;
 | |
|   s->opt[OPT_HILITE_R].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_HILITE_R].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_HILITE_R].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_HILITE_R].constraint.range = &s->hw->info.HiliteR_range;
 | |
|   s->opt[OPT_HILITE_R].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_HILITE_R].w = 255;
 | |
| 
 | |
|   /* shadow    point for red   */
 | |
|   s->opt[OPT_SHADOW_R].name = SANE_NAME_SHADOW_R;
 | |
|   s->opt[OPT_SHADOW_R].title = SANE_TITLE_SHADOW_R;
 | |
|   s->opt[OPT_SHADOW_R].desc = SANE_DESC_SHADOW_R;
 | |
|   s->opt[OPT_SHADOW_R].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_SHADOW_R].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_SHADOW_R].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_SHADOW_R].constraint.range = &s->hw->info.ShadowR_range;
 | |
|   s->opt[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_SHADOW_R].w = 0;
 | |
| 
 | |
|   /* highlight point for green */
 | |
|   s->opt[OPT_HILITE_G].name = SANE_NAME_HIGHLIGHT;
 | |
|   s->opt[OPT_HILITE_G].title = SANE_TITLE_HIGHLIGHT;
 | |
|   s->opt[OPT_HILITE_G].desc = SANE_DESC_HIGHLIGHT;
 | |
|   s->opt[OPT_HILITE_G].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_HILITE_G].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_HILITE_G].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_HILITE_G].constraint.range = &s->hw->info.HiliteG_range;
 | |
|   s->val[OPT_HILITE_G].w = 255;
 | |
| 
 | |
|   /* shadow    point for green */
 | |
|   s->opt[OPT_SHADOW_G].name = SANE_NAME_SHADOW;
 | |
|   s->opt[OPT_SHADOW_G].title = SANE_TITLE_SHADOW;
 | |
|   s->opt[OPT_SHADOW_G].desc = SANE_DESC_SHADOW;
 | |
|   s->opt[OPT_SHADOW_G].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_SHADOW_G].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_SHADOW_G].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_SHADOW_G].constraint.range = &s->hw->info.ShadowG_range;
 | |
|   s->val[OPT_SHADOW_G].w = 0;
 | |
| 
 | |
|   /* highlight point for blue  */
 | |
|   s->opt[OPT_HILITE_B].name = SANE_NAME_HIGHLIGHT_B;
 | |
|   s->opt[OPT_HILITE_B].title = SANE_TITLE_HIGHLIGHT_B;
 | |
|   s->opt[OPT_HILITE_B].desc = SANE_DESC_HIGHLIGHT_B;
 | |
|   s->opt[OPT_HILITE_B].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_HILITE_B].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_HILITE_B].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_HILITE_B].constraint.range = &s->hw->info.HiliteB_range;
 | |
|   s->opt[OPT_HILITE_B].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_HILITE_B].w = 255;
 | |
| 
 | |
|   /* shadow    point for blue  */
 | |
|   s->opt[OPT_SHADOW_B].name = SANE_NAME_SHADOW_B;
 | |
|   s->opt[OPT_SHADOW_B].title = SANE_TITLE_SHADOW_B;
 | |
|   s->opt[OPT_SHADOW_B].desc = SANE_DESC_SHADOW_B;
 | |
|   s->opt[OPT_SHADOW_B].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_SHADOW_B].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_SHADOW_B].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_SHADOW_B].constraint.range = &s->hw->info.ShadowB_range;
 | |
|   s->opt[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_SHADOW_B].w = 0;
 | |
| 
 | |
| 
 | |
|   /* "Enhancement" group: */
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* brightness */
 | |
|   s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
 | |
|   s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
 | |
|   s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
 | |
|   s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->info.brightness_range;
 | |
|   s->opt[OPT_BRIGHTNESS].cap |= 0;
 | |
|   s->val[OPT_BRIGHTNESS].w = 128;
 | |
| 
 | |
|   /* contrast */
 | |
|   s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
 | |
|   s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
 | |
|   s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
 | |
|   s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_CONTRAST].constraint.range = &s->hw->info.contrast_range;
 | |
|   s->opt[OPT_CONTRAST].cap |= 0;
 | |
|   s->val[OPT_CONTRAST].w = 128;
 | |
| 
 | |
|   /* threshold */
 | |
|   s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_THRESHOLD].constraint.range = &s->hw->info.threshold_range;
 | |
|   s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_THRESHOLD].w = 128;
 | |
| 
 | |
|   s->opt[OPT_MIRROR].name = "mirror";
 | |
|   s->opt[OPT_MIRROR].title = "Mirror image";
 | |
|   s->opt[OPT_MIRROR].desc = "Mirror the image horizontally";
 | |
|   s->opt[OPT_MIRROR].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_MIRROR].cap |= (s->hw->info.can_mirror) ? 0: SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_MIRROR].w = SANE_FALSE;
 | |
| 
 | |
|   /* analog-gamma curve */
 | |
|   s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
 | |
|   s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
 | |
|   s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
 | |
|   s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
 | |
| 
 | |
|   /* bind analog-gamma */
 | |
|   s->opt[OPT_CUSTOM_GAMMA_BIND].name = "bind-custom-gamma";
 | |
|   s->opt[OPT_CUSTOM_GAMMA_BIND].title = SANE_TITLE_RGB_BIND;
 | |
|   s->opt[OPT_CUSTOM_GAMMA_BIND].desc = SANE_DESC_RGB_BIND;
 | |
|   s->opt[OPT_CUSTOM_GAMMA_BIND].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_CUSTOM_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_CUSTOM_GAMMA_BIND].w = SANE_TRUE;
 | |
| 
 | |
|   /* grayscale gamma vector */
 | |
|   s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
 | |
|   s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
 | |
|   s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
 | |
|   s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
 | |
|   s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
 | |
|   s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0];
 | |
| 
 | |
|   /* red gamma vector */
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
 | |
|   s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0];
 | |
| 
 | |
|   /* green gamma vector */
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
 | |
|   s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0];
 | |
| 
 | |
|   /* blue gamma vector */
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
 | |
|   s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0];
 | |
| 
 | |
|   s->opt[OPT_AE].name = "ae";
 | |
|   s->opt[OPT_AE].title = "Auto Exposure";
 | |
|   s->opt[OPT_AE].desc = "Enable/disable the Auto Exposure feature";
 | |
|   s->opt[OPT_AE].cap |= (s->hw->info.can_autoexpose) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_AE].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_AE].w = SANE_FALSE;
 | |
| 
 | |
| 
 | |
|   /* "Calibration" group */
 | |
|   s->opt[OPT_CALIBRATION_GROUP].title = "Calibration";
 | |
|   s->opt[OPT_CALIBRATION_GROUP].desc = "";
 | |
|   s->opt[OPT_CALIBRATION_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_CALIBRATION_GROUP].cap |=
 | |
|     (s->hw->info.can_calibrate) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_CALIBRATION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* calibration now */
 | |
|   s->opt[OPT_CALIBRATION_NOW].name = "calibration-now";
 | |
|   s->opt[OPT_CALIBRATION_NOW].title = "Calibration now";
 | |
|   s->opt[OPT_CALIBRATION_NOW].desc = "Execute calibration *now*";
 | |
|   s->opt[OPT_CALIBRATION_NOW].type = SANE_TYPE_BUTTON;
 | |
|   s->opt[OPT_CALIBRATION_NOW].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_CALIBRATION_NOW].cap |=
 | |
|     (s->hw->info.can_calibrate) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_CALIBRATION_NOW].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_CALIBRATION_NOW].constraint.range = NULL;
 | |
| 
 | |
|   /* scanner self diagnostic */
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].name = "self-diagnostic";
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].title = "Self diagnostic";
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].desc =
 | |
|     "Perform scanner self diagnostic";
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].type = SANE_TYPE_BUTTON;
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].cap |=
 | |
|     (s->hw->info.can_calibrate) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_SCANNER_SELF_DIAGNOSTIC].constraint.range = NULL;
 | |
| 
 | |
|   /* reset scanner for FB620S */
 | |
|   s->opt[OPT_RESET_SCANNER].name = "reset-scanner";
 | |
|   s->opt[OPT_RESET_SCANNER].title = "Reset scanner";
 | |
|   s->opt[OPT_RESET_SCANNER].desc = "Reset the scanner";
 | |
|   s->opt[OPT_RESET_SCANNER].type = SANE_TYPE_BUTTON;
 | |
|   s->opt[OPT_RESET_SCANNER].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_RESET_SCANNER].cap |=
 | |
|     (s->hw->info.model == FB620) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_RESET_SCANNER].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_RESET_SCANNER].constraint.range = NULL;
 | |
| 
 | |
| 
 | |
|   /* "Eject" group (active only for film scanners) */
 | |
|   s->opt[OPT_EJECT_GROUP].title = "Medium handling";
 | |
|   s->opt[OPT_EJECT_GROUP].desc = "";
 | |
|   s->opt[OPT_EJECT_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_EJECT_GROUP].cap |=
 | |
|     (s->hw->info.can_eject) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_EJECT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* eject after scan */
 | |
|   s->opt[OPT_EJECT_AFTERSCAN].name = "eject-after-scan";
 | |
|   s->opt[OPT_EJECT_AFTERSCAN].title = "Eject film after each scan";
 | |
|   s->opt[OPT_EJECT_AFTERSCAN].desc =
 | |
|     "Automatically eject the film from the device after each scan";
 | |
|   s->opt[OPT_EJECT_AFTERSCAN].cap |=
 | |
|     (s->hw->info.can_eject) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_EJECT_AFTERSCAN].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_EJECT_AFTERSCAN].w = SANE_FALSE;
 | |
| 
 | |
|   /* eject before exit */
 | |
|   s->opt[OPT_EJECT_BEFOREEXIT].name = "eject-before-exit";
 | |
|   s->opt[OPT_EJECT_BEFOREEXIT].title = "Eject film before exit";
 | |
|   s->opt[OPT_EJECT_BEFOREEXIT].desc =
 | |
|     "Automatically eject the film from the device before exiting the program";
 | |
|   s->opt[OPT_EJECT_BEFOREEXIT].cap |=
 | |
|     (s->hw->info.can_eject) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_EJECT_BEFOREEXIT].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_EJECT_BEFOREEXIT].w = s->hw->info.can_eject;
 | |
| 
 | |
|   /* eject now */
 | |
|   s->opt[OPT_EJECT_NOW].name = "eject-now";
 | |
|   s->opt[OPT_EJECT_NOW].title = "Eject film now";
 | |
|   s->opt[OPT_EJECT_NOW].desc = "Eject the film from the device *now*";
 | |
|   s->opt[OPT_EJECT_NOW].type = SANE_TYPE_BUTTON;
 | |
|   s->opt[OPT_EJECT_NOW].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_EJECT_NOW].cap |=
 | |
|     (s->hw->info.can_eject) ? 0 : SANE_CAP_INACTIVE;
 | |
|   s->opt[OPT_EJECT_NOW].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_EJECT_NOW].constraint.range = NULL;
 | |
| 
 | |
|   /* "NO-ADF" option: */
 | |
|   s->opt[OPT_ADF_GROUP].title = "Document Feeder Extras";
 | |
|   s->opt[OPT_ADF_GROUP].desc = "";
 | |
|   s->opt[OPT_ADF_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_ADF_GROUP].cap = 0;
 | |
|   s->opt[OPT_ADF_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   s->opt[OPT_FLATBED_ONLY].name = "noadf";
 | |
|   s->opt[OPT_FLATBED_ONLY].title = "Flatbed Only";
 | |
|   s->opt[OPT_FLATBED_ONLY].desc =
 | |
|     "Disable Auto Document Feeder and use Flatbed only";
 | |
|   s->opt[OPT_FLATBED_ONLY].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_FLATBED_ONLY].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_FLATBED_ONLY].size = sizeof (SANE_Word);
 | |
|   s->opt[OPT_FLATBED_ONLY].cap |=
 | |
|     (s->hw->adf.Status == ADF_STAT_NONE) ? SANE_CAP_INACTIVE : 0;
 | |
|   s->val[OPT_FLATBED_ONLY].w = SANE_FALSE;
 | |
| 
 | |
|   /* "TPU" group: */
 | |
|   s->opt[OPT_TPU_GROUP].title = "Transparency Unit";
 | |
|   s->opt[OPT_TPU_GROUP].desc = "";
 | |
|   s->opt[OPT_TPU_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_TPU_GROUP].cap = 0;
 | |
|   s->opt[OPT_TPU_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->opt[OPT_TPU_GROUP].cap |=
 | |
|     (s->hw->tpu.Status != TPU_STAT_NONE) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* Transparency Unit (FAU, Film Adapter Unit) */
 | |
|   s->opt[OPT_TPU_ON].name = "transparency-unit-on-off";
 | |
|   s->opt[OPT_TPU_ON].title =
 | |
|     (s->hw->tpu.Status == TPU_STAT_ACTIVE) ?
 | |
|     "Turn Off the Transparency Unit" : "Turn On the Transparency Unit";
 | |
|   s->opt[OPT_TPU_ON].desc =
 | |
|     "Switch on/off the Transparency Unit (FAU, Film Adapter Unit)";
 | |
|   s->opt[OPT_TPU_ON].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_TPU_ON].unit = SANE_UNIT_NONE;
 | |
|   s->val[OPT_TPU_ON].w = s->hw->tpu.Status;
 | |
|   s->opt[OPT_TPU_ON].cap |=
 | |
|     (s->hw->tpu.Status != TPU_STAT_NONE) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   s->opt[OPT_TPU_PN].name = "transparency-unit-negative-film";
 | |
|   s->opt[OPT_TPU_PN].title = "Negative Film";
 | |
|   s->opt[OPT_TPU_PN].desc = "Positive or Negative Film";
 | |
|   s->opt[OPT_TPU_PN].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_TPU_PN].unit = SANE_UNIT_NONE;
 | |
|   s->val[OPT_TPU_PN].w = s->hw->tpu.PosNeg;
 | |
|   s->opt[OPT_TPU_PN].cap |=
 | |
|     (s->hw->tpu.Status == TPU_STAT_ACTIVE) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* density control mode */
 | |
|   s->opt[OPT_TPU_DCM].name = "TPMDC";
 | |
|   s->opt[OPT_TPU_DCM].title = "Density Control";
 | |
|   s->opt[OPT_TPU_DCM].desc = "Set Density Control Mode";
 | |
|   s->opt[OPT_TPU_DCM].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_TPU_DCM].size = max_string_size (tpu_dc_mode_list);
 | |
|   s->opt[OPT_TPU_DCM].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_TPU_DCM].constraint.string_list = tpu_dc_mode_list;
 | |
|   s->val[OPT_TPU_DCM].s = strdup (tpu_dc_mode_list[s->hw->tpu.ControlMode]);
 | |
|   s->opt[OPT_TPU_DCM].cap |=
 | |
|     (s->hw->tpu.Status == TPU_STAT_ACTIVE) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* Transparency Ratio */
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].name = "Transparency-Ratio";
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].title = "Transparency Ratio";
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].desc = "";
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].constraint.range =
 | |
|     &s->hw->info.TPU_Transparency_range;
 | |
|   s->val[OPT_TPU_TRANSPARENCY].w = s->hw->tpu.Transparency;
 | |
|   s->opt[OPT_TPU_TRANSPARENCY].cap |=
 | |
|     (s->hw->tpu.Status == TPU_STAT_ACTIVE &&
 | |
|      s->hw->tpu.ControlMode == 3) ? 0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
|   /* Select Film type */
 | |
|   s->opt[OPT_TPU_FILMTYPE].name = "Filmtype";
 | |
|   s->opt[OPT_TPU_FILMTYPE].title = "Select Film type";
 | |
|   s->opt[OPT_TPU_FILMTYPE].desc = "Select the film type";
 | |
|   s->opt[OPT_TPU_FILMTYPE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_TPU_FILMTYPE].size = max_string_size (tpu_filmtype_list);
 | |
|   s->opt[OPT_TPU_FILMTYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_TPU_FILMTYPE].constraint.string_list = tpu_filmtype_list;
 | |
|   s->val[OPT_TPU_FILMTYPE].s =
 | |
|     strdup (tpu_filmtype_list[s->hw->tpu.FilmType]);
 | |
|   s->opt[OPT_TPU_FILMTYPE].cap |=
 | |
|     (s->hw->tpu.Status == TPU_STAT_ACTIVE && s->hw->tpu.ControlMode == 1) ?
 | |
|     0 : SANE_CAP_INACTIVE;
 | |
| 
 | |
| 
 | |
|   /* preview */
 | |
|   s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
 | |
|   s->val[OPT_PREVIEW].w = SANE_FALSE;
 | |
| 
 | |
|   DBG (1, "<< init_options\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| attach_one (const char *dev)
 | |
| {
 | |
|   DBG (1, ">> attach_one\n");
 | |
|   attach (dev, 0);
 | |
|   DBG (1, "<< attach_one\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| static SANE_Status
 | |
| do_focus (CANON_Scanner * s)
 | |
| {
 | |
|   SANE_Status status;
 | |
|   u_char ebuf[74];
 | |
|   size_t buf_size;
 | |
| 
 | |
|   DBG (3, "do_focus: sending GET FILM STATUS\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = 4;
 | |
|   status = get_film_status (s->fd, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "do_focus: GET FILM STATUS failed\n");
 | |
|       if (status == SANE_STATUS_UNSUPPORTED)
 | |
| 	return (SANE_STATUS_GOOD);
 | |
|       else
 | |
| 	{
 | |
| 	  DBG (1, "do_focus: ... for unknown reasons\n");
 | |
| 	  sanei_scsi_close (s->fd);
 | |
| 	  s->fd = -1;
 | |
| 	  return (SANE_STATUS_INVAL);
 | |
| 	}
 | |
|     }
 | |
|   DBG (3, "focus point before autofocus : %d\n", ebuf[3]);
 | |
| 
 | |
|   if (s->val[OPT_AF].w == SANE_TRUE)	/* autofocus */
 | |
|     {
 | |
|       if (s->hw->info.model == FS2710)
 | |
| 	status = execute_auto_focus_FS2710 (s->fd, AUTO_FOCUS,
 | |
| 		 NO_AUTO_EXPOSURE, 128);
 | |
|       else
 | |
| 	status = execute_auto_focus (s->fd, AUTO_FOCUS,
 | |
| 		 (s->scanning_speed == 0) ? AUTO_SCAN_SPEED
 | |
| 		 : NO_AUTO_SCAN_SPEED,
 | |
| 		 (s->AE == 0) ? NO_AUTO_EXPOSURE : AUTO_EXPOSURE, 0);
 | |
|     }
 | |
|   else					/* manual focus */
 | |
|     {
 | |
|       if (s->hw->info.model == FS2710)
 | |
| 	status = execute_auto_focus_FS2710 (s->fd, MANUAL_FOCUS,
 | |
| 		 NO_AUTO_EXPOSURE, s->val[OPT_FOCUS].w);
 | |
|       else
 | |
| 	status = execute_auto_focus (s->fd, MANUAL_FOCUS,
 | |
| 		 (s->scanning_speed == 0) ? AUTO_SCAN_SPEED
 | |
| 		 : NO_AUTO_SCAN_SPEED,
 | |
| 		 (s->AE == 0) ? NO_AUTO_EXPOSURE : AUTO_EXPOSURE,
 | |
| 		 s->val[OPT_FOCUS].w);
 | |
|     }
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (7, "execute_auto_focus failed\n");
 | |
|       if (status == SANE_STATUS_UNSUPPORTED)
 | |
| 	  return (SANE_STATUS_GOOD);
 | |
|       else
 | |
| 	{
 | |
| 	  DBG (1, "do_focus: ... for unknown reasons\n");
 | |
| 	  sanei_scsi_close (s->fd);
 | |
| 	  s->fd = -1;
 | |
| 	  return (SANE_STATUS_INVAL);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   DBG (3, "do_focus: sending GET FILM STATUS\n");
 | |
|   memset (ebuf, 0, sizeof (ebuf));
 | |
|   buf_size = 4;
 | |
|   status = get_film_status (s->fd, ebuf, &buf_size);
 | |
|   if (status != SANE_STATUS_GOOD)
 | |
|     {
 | |
|       DBG (1, "do_focus: GET FILM STATUS failed\n");
 | |
|       if (status == SANE_STATUS_UNSUPPORTED)
 | |
| 	  return (SANE_STATUS_GOOD);
 | |
|       else
 | |
| 	{
 | |
| 	  DBG (1, "do_focus: ... for unknown reasons\n");
 | |
| 	  sanei_scsi_close (s->fd);
 | |
| 	  s->fd = -1;
 | |
| 	  return (SANE_STATUS_INVAL);
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|       DBG (3, "focus point after autofocus : %d\n", ebuf[3]);
 | |
| 
 | |
|   return (SANE_STATUS_GOOD);
 | |
| }
 | |
| 
 | |
| /**************************************************************************/
 | |
| 
 | |
| #include "canon-sane.c"
 |