2006-05-26 07:49:24 +00:00
/* SANE - Scanner Access Now Easy.
2015-04-03 17:19:02 +00:00
Copyright ( C ) 2011 - 2015 Rolf Bensch < rolf at bensch hyphen online dot de >
2008-10-14 19:48:59 +00:00
Copyright ( C ) 2007 - 2008 Nicolas Martin , < nicols - guest at alioth dot debian dot org >
2007-04-09 20:41:25 +00:00
Copyright ( C ) 2006 - 2007 Wittawat Yamwong < wittawat @ web . de >
2006-05-26 07:49:24 +00:00
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 .
*/
2013-02-09 15:56:40 +00:00
# include "../include/sane/config.h"
2006-05-26 07:49:24 +00:00
# include <errno.h>
# include <string.h>
# include <stdlib.h>
2008-02-03 10:34:20 +00:00
# ifdef USE_PTHREAD
# include <pthread.h>
# endif
2006-05-26 07:49:24 +00:00
# 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"
2008-10-25 14:56:11 +00:00
# include ".. / include /sane/sanei_config.h"
2006-05-26 07:49:24 +00:00
# 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
2012-02-03 21:05:32 +00:00
/* pixma_sane_options.h generated by
* scripts / pixma_gen_options . py h < pixma . c > pixma_sane_options . h
2012-10-31 11:40:07 +00:00
*/
2012-02-03 21:05:32 +00:00
# include "pixma_sane_options.h"
2006-05-26 07:49:24 +00:00
2013-07-18 20:45:45 +00:00
# define BUTTON_GROUP_SIZE ( opt_scan_resolution - opt_button_1 + 1 )
2012-10-31 11:40:07 +00:00
# define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 )
2006-05-26 07:49:24 +00:00
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 ] ;
2012-10-31 11:40:07 +00:00
char button_option_is_cached [ BUTTON_GROUP_SIZE ] ;
2006-05-26 07:49:24 +00:00
SANE_Range xrange , yrange ;
SANE_Word dpi_list [ 9 ] ; /* up to 9600 dpi */
2012-06-27 08:49:09 +00:00
SANE_String_Const mode_list [ 6 ] ;
pixma_scan_mode_t mode_map [ 6 ] ;
2006-05-26 07:49:24 +00:00
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 ;
2011-01-04 21:19:52 +00:00
uint64_t image_bytes_read ;
2006-05-26 07:49:24 +00:00
unsigned page_count ; /* valid for ADF */
2008-05-15 12:50:25 +00:00
SANE_Pid reader_taskid ;
2006-05-26 07:49:24 +00:00
int wpipe , rpipe ;
SANE_Bool reader_stop ;
} pixma_sane_t ;
static const char vendor_str [ ] = " CANON " ;
2006-06-08 17:49:47 +00:00
static const char type_str [ ] = " multi-function peripheral " ;
2006-05-26 07:49:24 +00:00
static pixma_sane_t * first_scanner = NULL ;
static const SANE_Device * * dev_list = NULL ;
2008-10-25 14:56:11 +00:00
static const char * conf_devices [ MAX_CONF_DEVICES ] ;
2006-05-26 07:49:24 +00:00
2012-10-31 11:40:07 +00:00
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 ;
}
2008-10-25 14:56:11 +00:00
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 ;
}
2006-05-26 07:49:24 +00:00
static SANE_Status
map_error ( int error )
{
if ( error > = 0 )
return SANE_STATUS_GOOD ;
switch ( error )
{
2006-08-27 12:39:18 +00:00
case PIXMA_ENOMEM :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_NO_MEM ;
2006-08-27 12:39:18 +00:00
case PIXMA_ECANCELED :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_CANCELLED ;
2006-08-27 12:39:18 +00:00
case PIXMA_EBUSY :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_DEVICE_BUSY ;
2006-08-27 12:39:18 +00:00
case PIXMA_EINVAL :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_INVAL ;
2006-08-27 12:39:18 +00:00
case PIXMA_EACCES :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_ACCESS_DENIED ;
2006-08-27 12:39:18 +00:00
case PIXMA_EPAPER_JAMMED :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_JAMMED ;
2006-08-27 12:39:18 +00:00
case PIXMA_ENO_PAPER :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_NO_DOCS ;
2006-08-27 12:39:18 +00:00
case PIXMA_ECOVER_OPEN :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_COVER_OPEN ;
2006-08-27 12:39:18 +00:00
case PIXMA_ENOTSUP :
return SANE_STATUS_UNSUPPORTED ;
case PIXMA_EPROTO :
case PIXMA_ENODEV :
case PIXMA_EIO :
case PIXMA_ETIMEDOUT :
2006-05-26 07:49:24 +00:00
return SANE_STATUS_IO_ERROR ;
}
2006-08-27 12:39:18 +00:00
PDBG ( pixma_dbg ( 1 , " BUG: unmapped error %d \n " , error ) ) ;
return SANE_STATUS_IO_ERROR ;
2006-05-26 07:49:24 +00:00
}
static int
getenv_atoi ( const char * name , int def )
{
const char * str = getenv ( name ) ;
return ( str ) ? atoi ( str ) : def ;
}
2006-08-27 12:39:18 +00:00
# define CONST_CAST(t,x) (t)(x)
2009-12-26 13:40:39 +00:00
static void
free_block ( const void * ptr )
{
free ( CONST_CAST ( void * , ptr ) ) ;
}
2006-05-26 07:49:24 +00:00
static void
cleanup_device_list ( void )
{
if ( dev_list )
{
int i ;
for ( i = 0 ; dev_list [ i ] ; i + + )
2008-10-05 20:42:19 +00:00
{
2009-12-26 13:40:39 +00:00
free_block ( ( const void * ) dev_list [ i ] - > name ) ;
free_block ( ( const void * ) dev_list [ i ] - > model ) ;
free_block ( ( const void * ) dev_list [ i ] ) ;
2008-10-05 20:42:19 +00:00
}
2006-05-26 07:49:24 +00:00
}
free ( dev_list ) ;
dev_list = NULL ;
}
static void
find_scanners ( void )
{
unsigned i , nscanners ;
cleanup_device_list ( ) ;
2008-10-25 14:56:11 +00:00
nscanners = pixma_find_scanners ( conf_devices ) ;
2007-04-09 20:41:25 +00:00
PDBG ( pixma_dbg ( 3 , " pixma_find_scanners() found %u devices \n " , nscanners ) ) ;
2006-05-26 07:49:24 +00:00
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 )
2008-10-05 20:42:19 +00:00
goto nomem ;
2006-05-26 07:49:24 +00:00
name = strdup ( pixma_get_device_id ( i ) ) ;
model = strdup ( pixma_get_device_model ( i ) ) ;
if ( ! name | | ! model )
2008-10-05 20:42:19 +00:00
{
free ( name ) ;
free ( model ) ;
free ( sdev ) ;
goto nomem ;
}
2006-05-26 07:49:24 +00:00
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 :
2012-10-31 11:40:07 +00:00
b1 = 1 ;
2006-05-26 07:49:24 +00:00
break ;
case PIXMA_EV_BUTTON2 :
2012-10-31 11:40:07 +00:00
b2 = 1 ;
2006-05-26 07:49:24 +00:00
break ;
}
2012-10-31 11:40:07 +00:00
2006-05-26 07:49:24 +00:00
if ( b1 ! = OVAL ( opt_button_1 ) . w | | b2 ! = OVAL ( opt_button_2 ) . w )
2012-10-31 11:40:07 +00:00
{
2006-05-26 07:49:24 +00:00
* info | = SANE_INFO_RELOAD_OPTIONS ;
2012-10-31 11:40:07 +00:00
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 ) ;
2013-07-18 20:45:45 +00:00
OVAL ( opt_scan_resolution ) . w = GET_EV_DPI ( ev ) ;
2012-10-31 11:40:07 +00:00
}
mark_all_button_options_cached ( ss ) ;
2006-05-26 07:49:24 +00:00
}
2006-08-27 12:39:18 +00:00
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 ) ;
}
2006-05-26 07:49:24 +00:00
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 )
2008-10-05 20:42:19 +00:00
{
value = range - > min ;
}
2006-05-26 07:49:24 +00:00
else if ( value > range - > max )
2008-10-05 20:42:19 +00:00
{
value = range - > max ;
}
2006-05-26 07:49:24 +00:00
if ( range - > quant ! = 0 )
2008-10-05 20:42:19 +00:00
{
value = ( value - range - > min + range - > quant / 2 ) /
range - > quant * range - > quant ;
}
2006-05-26 07:49:24 +00:00
if ( value ! = va [ i ] )
2008-10-05 20:42:19 +00:00
{
va [ i ] = value ;
* info | = SANE_INFO_INEXACT ;
}
2006-05-26 07:49:24 +00:00
}
}
2012-02-03 21:05:32 +00:00
/* 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
2013-02-18 15:20:57 +00:00
create_mode_list ( pixma_sane_t * ss )
2012-02-03 21:05:32 +00:00
{
2013-02-18 15:20:57 +00:00
SANE_Bool tpu ;
2012-02-03 21:05:32 +00:00
const pixma_config_t * cfg ;
int i ;
cfg = pixma_get_config ( ss - > s ) ;
2013-02-18 15:20:57 +00:00
tpu = ( ss - > source_map [ OVAL ( opt_source ) . w ] = = PIXMA_SOURCE_TPU ) ;
2012-02-03 21:05:32 +00:00
2013-02-18 15:20:57 +00:00
/* setup available mode */
2012-02-03 21:05:32 +00:00
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 + + ;
}
2013-02-09 15:56:40 +00:00
if ( tpu & & ( cfg - > cap & PIXMA_CAP_NEGATIVE ) )
2012-04-04 13:15:18 +00:00
{
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 + + ;
}
}
2013-06-27 19:14:49 +00:00
if ( tpu & & ( cfg - > cap & PIXMA_CAP_TPUIR ) = = PIXMA_CAP_TPUIR )
2013-02-18 16:37:30 +00:00
{
ss - > mode_list [ i ] = SANE_I18N ( " Infrared " ) ;
ss - > mode_map [ i ] = PIXMA_SCAN_MODE_TPUIR ;
i + + ;
}
2013-02-09 15:56:40 +00:00
if ( ! tpu & & ( cfg - > cap & PIXMA_CAP_48BIT ) )
2012-06-27 08:49:09 +00:00
{
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 + + ;
}
}
2013-02-09 15:56:40 +00:00
if ( ! tpu & & ( cfg - > cap & PIXMA_CAP_LINEART ) )
2012-02-03 21:05:32 +00:00
{
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 ;
}
2012-06-27 08:49:09 +00:00
/* create dynamic dpi_list
2013-02-18 15:20:57 +00:00
* ss : scanner device */
2012-01-31 10:39:53 +00:00
static void
2013-02-18 15:20:57 +00:00
create_dpi_list ( pixma_sane_t * ss )
2012-01-31 10:39:53 +00:00
{
const pixma_config_t * cfg ;
int i , j ;
2013-02-18 15:20:57 +00:00
int min ;
unsigned min_dpi ;
unsigned max_dpi ;
2012-01-31 10:39:53 +00:00
cfg = pixma_get_config ( ss - > s ) ;
2013-02-18 15:20:57 +00:00
/* get min/max dpi */
max_dpi = cfg - > xdpi ;
min_dpi = 75 ;
if ( ss - > source_map [ OVAL ( opt_source ) . w ] = = PIXMA_SOURCE_TPU
2013-02-18 16:37:30 +00:00
& & 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 )
2013-02-18 15:20:57 +00:00
{ /* 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 ;
}
2012-01-31 10:39:53 +00:00
/* set j for min. dpi
* 75 dpi : j = 0
* 150 dpi : j = 1 \
2013-02-18 15:20:57 +00:00
* 300 dpi : j = 2 | - - > from cfg - > adftpu_min_dpi or cfg - > tpuir_min_dpi
* 600 dpi : j = 3 /
2012-04-04 13:15:18 +00:00
* */
2013-02-18 15:20:57 +00:00
j = - 1 ;
min = min_dpi / 75 ;
do
{
j + + ;
min > > = 1 ;
}
while ( min > 0 ) ;
2012-01-31 10:39:53 +00:00
/* create dpi_list
2013-02-18 15:20:57 +00:00
* use j for min . dpi */
2012-01-31 10:39:53 +00:00
i = 0 ;
do
{
i + + ; j + + ;
ss - > dpi_list [ i ] = 75 * ( 1 < < ( j - 1 ) ) ; /* 75 x 2^(j-1) */
}
2013-02-18 15:20:57 +00:00
while ( ( unsigned ) ss - > dpi_list [ i ] < max_dpi ) ;
2012-01-31 10:39:53 +00:00
ss - > dpi_list [ 0 ] = i ;
2013-02-18 15:20:57 +00:00
/*PDBG (pixma_dbg (4, "*create_dpi_list***** min_dpi = %d, max_dpi = %d\n", min_dpi, max_dpi));*/
2012-01-31 10:39:53 +00:00
}
2006-05-26 07:49:24 +00:00
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 + + )
2008-10-05 20:42:19 +00:00
{
SANE_Word delta = abs ( value - list [ j ] ) ;
if ( delta < mindelta )
{
mindelta = delta ;
nearest = list [ j ] ;
}
if ( mindelta = = 0 )
break ;
}
2006-05-26 07:49:24 +00:00
if ( va [ i ] ! = nearest )
2008-10-05 20:42:19 +00:00
{
va [ i ] = nearest ;
* info | = SANE_INFO_INEXACT ;
}
2006-05-26 07:49:24 +00:00
}
}
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 )
2008-10-05 20:42:19 +00:00
{
case SANE_TYPE_BOOL :
case SANE_TYPE_INT :
case SANE_TYPE_FIXED :
* ( SANE_Word * ) v = opt - > val . w ;
break ;
default :
return SANE_STATUS_UNSUPPORTED ;
}
2006-05-26 07:49:24 +00:00
return SANE_STATUS_GOOD ;
case SANE_ACTION_SET_VALUE :
switch ( opt - > sod . type )
2008-10-05 20:42:19 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
* info | = opt - > info ;
return SANE_STATUS_GOOD ;
case SANE_ACTION_SET_AUTO :
switch ( opt - > sod . type )
2008-10-05 20:42:19 +00:00
{
case SANE_TYPE_BOOL :
case SANE_TYPE_INT :
case SANE_TYPE_FIXED :
opt - > val . w = opt - > def . w ;
break ;
default :
return SANE_STATUS_UNSUPPORTED ;
}
2006-05-26 07:49:24 +00:00
* 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 )
2008-10-05 20:42:19 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
return SANE_STATUS_GOOD ;
}
else
{
2013-02-09 15:56:40 +00:00
int i ;
2006-05-26 07:49:24 +00:00
switch ( a )
2008-10-05 20:42:19 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
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 ;
2012-01-31 10:39:53 +00:00
const pixma_config_t * cfg ;
2012-10-31 11:40:07 +00:00
SANE_Int dummy ;
2012-01-31 10:39:53 +00:00
2012-10-31 11:40:07 +00:00
/* info may be null, better to set a dummy here then test everywhere */
if ( info = = NULL )
info = & dummy ;
2012-01-31 10:39:53 +00:00
cfg = pixma_get_config ( ss - > s ) ;
2006-05-26 07:49:24 +00:00
2012-02-03 21:05:32 +00:00
/* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */
2012-10-31 11:40:07 +00:00
/* first deal with options that require special treatment */
2006-05-26 07:49:24 +00:00
result = SANE_STATUS_UNSUPPORTED ;
switch ( n )
{
2008-10-05 20:42:19 +00:00
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 ;
2006-05-26 07:49:24 +00:00
2008-10-14 19:48:59 +00:00
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 ;
2012-10-31 11:40:07 +00:00
case opt_button_1 :
case opt_button_2 :
case opt_original :
case opt_target :
2013-07-18 20:45:45 +00:00
case opt_scan_resolution :
2012-10-31 11:40:07 +00:00
/* 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 */
2006-05-26 07:49:24 +00:00
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 ;
2012-10-31 11:40:07 +00:00
/* deal with dependencies between options */
2006-05-26 07:49:24 +00:00
switch ( n )
{
case opt_custom_gamma :
if ( a = = SANE_ACTION_SET_VALUE | | a = = SANE_ACTION_SET_AUTO )
2008-10-05 20:42:19 +00:00
{
if ( enable_option ( ss , opt_gamma_table , OVAL ( opt_custom_gamma ) . b ) )
* info | = SANE_INFO_RELOAD_OPTIONS ;
}
2006-05-26 07:49:24 +00:00
break ;
2012-02-16 18:58:23 +00:00
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 ;
2012-02-03 21:05:32 +00:00
case opt_mode :
2013-02-18 16:37:30 +00:00
if ( cfg - > cap & ( PIXMA_CAP_48BIT | PIXMA_CAP_LINEART | PIXMA_CAP_TPUIR )
2012-02-16 17:11:52 +00:00
& & ( a = = SANE_ACTION_SET_VALUE | | a = = SANE_ACTION_SET_AUTO ) )
2012-06-27 08:49:09 +00:00
{ /* new mode selected: Color, Gray, ... */
/* PDBG (pixma_dbg (4, "*control_option***** mode = %u *\n",
ss - > mode_map [ OVAL ( opt_mode ) . w ] ) ) ; */
2013-02-18 15:20:57 +00:00
/* recreate dynamic lists */
create_dpi_list ( ss ) ;
2012-02-03 21:05:32 +00:00
if ( ss - > mode_map [ OVAL ( opt_mode ) . w ] = = PIXMA_SCAN_MODE_LINEART )
2012-06-27 08:49:09 +00:00
{ /* lineart */
2012-02-03 21:05:32 +00:00
enable_option ( ss , opt_threshold , SANE_TRUE ) ;
2012-02-29 10:40:18 +00:00
enable_option ( ss , opt_threshold_curve , SANE_TRUE ) ;
2012-02-03 21:05:32 +00:00
}
else
2012-06-27 08:49:09 +00:00
{ /* all other modes */
2012-02-03 21:05:32 +00:00
enable_option ( ss , opt_threshold , SANE_FALSE ) ;
2012-02-29 10:40:18 +00:00
enable_option ( ss , opt_threshold_curve , SANE_FALSE ) ;
2012-02-03 21:05:32 +00:00
}
* info | = SANE_INFO_RELOAD_OPTIONS ;
}
break ;
2012-01-31 10:39:53 +00:00
case opt_source :
2013-02-09 15:56:40 +00:00
if ( ( cfg - > cap & ( PIXMA_CAP_ADF | PIXMA_CAP_ADFDUP | PIXMA_CAP_TPU ) )
2012-01-31 10:39:53 +00:00
& & ( a = = SANE_ACTION_SET_VALUE | | a = = SANE_ACTION_SET_AUTO ) )
2012-02-03 20:26:50 +00:00
{ /* new source selected: flatbed, ADF, TPU, ... */
2013-02-18 15:20:57 +00:00
/* to avoid fatal errors,
* select first entry of dynamic mode_list
* identifiers are unknown here */
OVAL ( opt_mode ) . w = ss - > mode_map [ 0 ] ;
2012-02-03 21:05:32 +00:00
/* recreate dynamic lists */
2013-02-18 15:20:57 +00:00
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 ] ;
2012-06-27 08:49:09 +00:00
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 ) ;
2012-01-31 10:39:53 +00:00
}
* info | = SANE_INFO_RELOAD_OPTIONS ;
}
break ;
2006-05-26 07:49:24 +00:00
}
return result ;
}
# ifndef NDEBUG
static void
print_scan_param ( int level , const pixma_scan_param_t * sp )
{
pixma_dbg ( level , " Scan parameters \n " ) ;
2012-01-15 02:48:19 +00:00
pixma_dbg ( level , " line_size=% " PRIu64 " image_size=% " PRIu64 " channels=%u depth=%u \n " ,
2006-05-26 07:49:24 +00:00
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 ) ;
}
# 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 ;
2010-07-25 19:38:07 +00:00
sp - > depth = ( OVAL ( opt_mode ) . w = = 2 ) ? 1 : 8 ;
2006-05-26 07:49:24 +00:00
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 ;
2012-01-15 02:48:19 +00:00
sp - > tpu_offset_added = 0 ;
2006-05-26 07:49:24 +00:00
sp - > gamma_table = ( OVAL ( opt_custom_gamma ) . b ) ? ss - > gamma_table : NULL ;
sp - > source = ss - > source_map [ OVAL ( opt_source ) . w ] ;
2012-02-03 21:05:32 +00:00
sp - > mode = ss - > mode_map [ OVAL ( opt_mode ) . w ] ;
2008-10-05 20:42:19 +00:00
sp - > adf_pageid = ss - > page_count ;
2012-02-29 10:40:18 +00:00
sp - > threshold = 2.55 * OVAL ( opt_threshold ) . w ;
sp - > threshold_curve = OVAL ( opt_threshold_curve ) . w ;
2006-05-26 07:49:24 +00:00
error = pixma_check_scan_param ( ss - > s , sp ) ;
if ( error < 0 )
{
2006-08-27 12:39:18 +00:00
PDBG ( pixma_dbg ( 1 , " BUG:calc_scan_param() failed %d \n " , error ) ) ;
2006-05-26 07:49:24 +00:00
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. */
2013-02-18 15:20:57 +00:00
create_mode_list ( ss ) ;
/* setup dpi up to the value supported by the scanner. */
create_dpi_list ( ss ) ;
2010-07-25 19:38:07 +00:00
2006-05-26 07:49:24 +00:00
/* 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 + + ;
}
2008-04-21 19:20:12 +00:00
if ( ( cfg - > cap & PIXMA_CAP_ADFDUP ) = = PIXMA_CAP_ADFDUP )
2006-08-27 12:39:18 +00:00
{
ss - > source_list [ i ] = SANE_I18N ( " ADF Duplex " ) ;
ss - > source_map [ i ] = PIXMA_SOURCE_ADFDUP ;
i + + ;
}
2008-06-15 20:05:14 +00:00
if ( cfg - > cap & PIXMA_CAP_TPU )
{
ss - > source_list [ i ] = SANE_I18N ( " Transparency Unit " ) ;
ss - > source_map [ i ] = PIXMA_SOURCE_TPU ;
i + + ;
}
2006-05-26 07:49:24 +00:00
build_option_descriptors ( ss ) ;
/* Enable options that are available only in some scanners. */
if ( cfg - > cap & PIXMA_CAP_GAMMA_TABLE )
{
2012-02-16 18:58:23 +00:00
enable_option ( ss , opt_gamma , SANE_TRUE ) ;
2006-08-27 12:39:18 +00:00
enable_option ( ss , opt_custom_gamma , SANE_TRUE ) ;
2006-05-26 07:49:24 +00:00
sane_control_option ( ss , opt_custom_gamma , SANE_ACTION_SET_AUTO ,
NULL , NULL ) ;
pixma_fill_gamma_table ( AUTO_GAMMA , ss - > gamma_table , 4096 ) ;
}
2006-08-27 12:39:18 +00:00
enable_option ( ss , opt_button_controlled ,
( ( cfg - > cap & PIXMA_CAP_EVENTS ) ! = 0 ) ) ;
2006-05-26 07:49:24 +00:00
}
/* Writing to reader_ss outside reader_process() is a BUG! */
static pixma_sane_t * reader_ss = NULL ;
static RETSIGTYPE
reader_signal_handler ( int sig )
{
if ( reader_ss )
{
reader_ss - > reader_stop = SANE_TRUE ;
2008-11-25 21:40:54 +00:00
/* reader process is ended by SIGTERM, so no cancel in this case */
if ( sig ! = SIGTERM )
pixma_cancel ( reader_ss - > s ) ;
2006-05-26 07:49:24 +00:00
}
}
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 " ) ) ;
2008-10-22 20:35:25 +00:00
/*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 */
2006-05-26 07:49:24 +00:00
buf = malloc ( bufsize ) ;
if ( ! buf )
{
2006-08-27 12:39:18 +00:00
count = PIXMA_ENOMEM ;
2006-05-26 07:49:24 +00:00
goto done ;
}
2008-11-05 20:53:30 +00:00
count = pixma_activate_connection ( ss - > s ) ;
if ( count < 0 )
goto done ;
2006-05-26 07:49:24 +00:00
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 " ) ;
2008-06-15 20:05:14 +00:00
pixma_dbg ( 1 , " ==== To proceed, press 'SCAN' or 'COLOR' button. "
2013-01-18 11:11:31 +00:00
" To cancel, press 'GRAY' or 'END' button. \n " ) ;
2006-05-26 07:49:24 +00:00
# endif
while ( pixma_wait_event ( ss - > s , 10 ) ! = 0 )
2008-10-05 20:42:19 +00:00
{
}
2006-05-26 07:49:24 +00:00
while ( ! start )
2008-10-05 20:42:19 +00:00
{
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 ;
}
}
2006-05-26 07:49:24 +00:00
}
count = pixma_scan ( ss - > s , & ss - > sp ) ;
if ( count > = 0 )
{
while ( ( count = pixma_read_image ( ss - > s , buf , bufsize ) ) > 0 )
2008-10-05 20:42:19 +00:00
{
if ( write_all ( ss , buf , count ) ! = count )
pixma_cancel ( ss - > s ) ;
}
2006-05-26 07:49:24 +00:00
}
done :
pixma_enable_background ( ss - > s , 0 ) ;
2008-11-05 20:53:30 +00:00
pixma_deactivate_connection ( ss - > s ) ;
2006-05-26 07:49:24 +00:00
free ( buf ) ;
close ( ss - > wpipe ) ;
ss - > wpipe = - 1 ;
if ( count > = 0 )
{
PDBG ( pixma_dbg ( 3 , " Reader task terminated \n " ) ) ;
}
else
{
2006-08-27 12:39:18 +00:00
PDBG ( pixma_dbg
( 2 , " Reader task terminated: %s \n " , pixma_strerror ( count ) ) ) ;
2006-05-26 07:49:24 +00:00
}
return map_error ( count ) ;
}
static int
reader_process ( void * arg )
{
pixma_sane_t * ss = ( pixma_sane_t * ) arg ;
2006-08-27 12:39:18 +00:00
struct SIGACTION sa ;
2006-05-26 07:49:24 +00:00
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 ) ;
2007-04-09 20:41:25 +00:00
# endif /* USE_PTHREAD */
2006-05-26 07:49:24 +00:00
return reader_loop ( ss ) ;
}
2008-05-15 12:50:25 +00:00
static SANE_Pid
2006-05-26 07:49:24 +00:00
terminate_reader_task ( pixma_sane_t * ss , int * exit_code )
{
2008-05-15 12:50:25 +00:00
SANE_Pid result , pid ;
2006-05-26 07:49:24 +00:00
int status = 0 ;
pid = ss - > reader_taskid ;
2015-11-13 13:06:30 +00:00
if ( ! sanei_thread_is_valid ( pid ) )
2006-05-26 07:49:24 +00:00
return - 1 ;
if ( sanei_thread_is_forked ( ) )
{
sanei_thread_kill ( pid ) ;
}
else
{
ss - > reader_stop = SANE_TRUE ;
2009-11-28 14:11:05 +00:00
/* pixma_cancel (ss->s); What is this for ? Makes end-of-scan buggy => removing */
2006-05-26 07:49:24 +00:00
}
result = sanei_thread_waitpid ( pid , & status ) ;
2007-11-18 10:59:18 +00:00
ss - > reader_taskid = - 1 ;
2008-02-17 15:49:43 +00:00
2008-07-05 12:42:53 +00:00
if ( ss - > sp . source ! = PIXMA_SOURCE_ADF & & ss - > sp . source ! = PIXMA_SOURCE_ADFDUP )
2008-02-17 15:49:43 +00:00
ss - > idle = SANE_TRUE ;
2006-05-26 07:49:24 +00:00
if ( result = = pid )
{
if ( exit_code )
2008-10-05 20:42:19 +00:00
* exit_code = status ;
2006-05-26 07:49:24 +00:00
return pid ;
}
else
{
2006-08-27 12:39:18 +00:00
PDBG ( pixma_dbg ( 1 , " WARNING:waitpid() failed %s \n " , strerror ( errno ) ) ) ;
2006-05-26 07:49:24 +00:00
return - 1 ;
}
}
static int
start_reader_task ( pixma_sane_t * ss )
{
int fds [ 2 ] ;
2008-05-15 12:50:25 +00:00
SANE_Pid pid ;
2006-05-26 07:49:24 +00:00
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 ;
}
2015-11-13 13:06:30 +00:00
if ( sanei_thread_is_valid ( ss - > reader_taskid ) )
2006-05-26 07:49:24 +00:00
{
2008-02-17 15:49:43 +00:00
PDBG ( pixma_dbg
2008-05-15 12:50:25 +00:00
( 1 , " BUG:reader_taskid(%ld) != -1 \n " , ( long ) ss - > reader_taskid ) ) ;
2006-05-26 07:49:24 +00:00
terminate_reader_task ( ss , NULL ) ;
}
if ( pipe ( fds ) = = - 1 )
{
PDBG ( pixma_dbg ( 1 , " ERROR:start_reader_task():pipe() failed %s \n " ,
strerror ( errno ) ) ) ;
2006-08-27 12:39:18 +00:00
return PIXMA_ENOMEM ;
2006-05-26 07:49:24 +00:00
}
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 ( pid > 0 )
2008-10-05 20:42:19 +00:00
{
close ( ss - > wpipe ) ;
ss - > wpipe = - 1 ;
}
2006-05-26 07:49:24 +00:00
}
else
{
pid = sanei_thread_begin ( reader_thread , ss ) ;
}
2015-11-13 13:06:30 +00:00
if ( ! sanei_thread_is_valid ( pid ) )
2006-05-26 07:49:24 +00:00
{
close ( ss - > wpipe ) ;
close ( ss - > rpipe ) ;
ss - > wpipe = - 1 ;
ss - > rpipe = - 1 ;
PDBG ( pixma_dbg ( 1 , " ERROR:unable to start reader task \n " ) ) ;
2006-08-27 12:39:18 +00:00
return PIXMA_ENOMEM ;
2006-05-26 07:49:24 +00:00
}
2008-05-15 12:50:25 +00:00
PDBG ( pixma_dbg ( 3 , " Reader task id=%ld (%s) \n " , ( long ) pid ,
2006-05-26 07:49:24 +00:00
( is_forked ) ? " forked " : " threaded " ) ) ;
ss - > reader_taskid = pid ;
2007-11-18 10:59:18 +00:00
return 0 ;
2006-05-26 07:49:24 +00:00
}
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 )
2008-10-05 20:42:19 +00:00
/* ss->rpipe has already been closed by sane_cancel(). */
return SANE_STATUS_CANCELLED ;
2006-05-26 07:49:24 +00:00
count = read ( ss - > rpipe , buf , size ) ;
}
while ( count = = - 1 & & errno = = EINTR ) ;
if ( count = = - 1 )
{
if ( errno = = EAGAIN )
2008-10-05 20:42:19 +00:00
return SANE_STATUS_GOOD ;
2006-05-26 07:49:24 +00:00
if ( ! ss - > cancel )
2008-10-05 20:42:19 +00:00
{
PDBG ( pixma_dbg ( 1 , " WARNING:read_image():read() failed %s \n " ,
strerror ( errno ) ) ) ;
}
2006-05-26 07:49:24 +00:00
close ( ss - > rpipe ) ;
ss - > rpipe = - 1 ;
terminate_reader_task ( ss , NULL ) ;
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 ) ;
}
else if ( count = = 0 )
{
2011-01-04 21:19:52 +00:00
PDBG ( pixma_dbg ( 3 , " read_image():reader task closed the pipe:% "
PRIu64 " bytes received, % " PRIu64 " bytes expected \n " ,
2006-05-26 07:49:24 +00:00
ss - > image_bytes_read , ss - > sp . image_size ) ) ;
close ( ss - > rpipe ) ;
ss - > rpipe = - 1 ;
2015-11-13 13:06:30 +00:00
if ( sanei_thread_is_valid ( terminate_reader_task ( ss , & status ) )
2008-10-05 20:42:19 +00:00
& & status ! = SANE_STATUS_GOOD )
{
return status ;
}
2007-07-19 22:17:21 +00:00
else
2008-10-05 20:42:19 +00:00
{
/* either terminate_reader_task failed or
rpipe was closed but we expect more data */
return SANE_STATUS_IO_ERROR ;
}
2006-05-26 07:49:24 +00:00
}
if ( readlen )
* readlen = count ;
return SANE_STATUS_GOOD ;
}
/*******************************************************************
* * SANE API
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
SANE_Status
sane_init ( SANE_Int * version_code , SANE_Auth_Callback authorize )
{
2008-10-25 14:56:11 +00:00
int status , myversion , i ;
SANEI_Config config ;
2006-05-26 07:49:24 +00:00
UNUSED ( authorize ) ;
if ( ! version_code )
return SANE_STATUS_INVAL ;
myversion = 100 * PIXMA_VERSION_MAJOR + PIXMA_VERSION_MINOR ;
2008-11-26 21:21:31 +00:00
* version_code = SANE_VERSION_CODE ( SANE_CURRENT_MAJOR , V_MINOR , myversion ) ;
2006-05-26 07:49:24 +00:00
DBG_INIT ( ) ;
sanei_thread_init ( ) ;
pixma_set_debug_level ( DBG_LEVEL ) ;
2009-12-06 14:40:58 +00:00
2009-12-06 14:33:10 +00:00
PDBG ( pixma_dbg ( 2 , " pixma is compiled %s pthread support. \n " ,
( sanei_thread_is_forked ( ) ? " without " : " with " ) ) ) ;
2006-05-26 07:49:24 +00:00
2008-10-25 14:56:11 +00:00
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 ) ) ;
2006-05-26 07:49:24 +00:00
status = pixma_init ( ) ;
if ( status < 0 )
{
2008-10-14 19:48:59 +00:00
PDBG ( pixma_dbg ( 2 , " pixma_init() failed %s \n " , pixma_strerror ( status ) ) ) ;
2006-05-26 07:49:24 +00:00
}
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 )
{
UNUSED ( local_only ) ;
if ( ! device_list )
return SANE_STATUS_INVAL ;
find_scanners ( ) ;
* 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 )
{
2012-10-31 11:40:07 +00:00
unsigned i , j , nscanners ;
2006-05-26 07:49:24 +00:00
int error = 0 ;
pixma_sane_t * ss = NULL ;
const pixma_config_t * cfg ;
if ( ! name | | ! h )
return SANE_STATUS_INVAL ;
* h = NULL ;
2008-10-25 14:56:11 +00:00
nscanners = pixma_find_scanners ( conf_devices ) ;
2006-05-26 07:49:24 +00:00
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 )
2008-10-05 20:42:19 +00:00
{
/* We have already opened it! */
return SANE_STATUS_DEVICE_BUSY ;
}
2006-05-26 07:49:24 +00:00
}
i = 0 ;
while ( strcmp ( pixma_get_device_id ( i ) , name ) ! = 0 )
{
if ( + + i > = nscanners )
2008-10-05 20:42:19 +00:00
return SANE_STATUS_INVAL ;
2006-05-26 07:49:24 +00:00
}
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 )
2008-10-05 20:42:19 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
# 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 ;
2008-01-30 07:52:23 +00:00
ss - > reader_taskid = - 1 ;
2006-05-26 07:49:24 +00:00
ss - > wpipe = - 1 ;
ss - > rpipe = - 1 ;
2006-06-03 00:37:11 +00:00
ss - > idle = SANE_TRUE ;
ss - > scanning = SANE_FALSE ;
2012-10-31 11:40:07 +00:00
for ( j = 0 ; j < BUTTON_GROUP_SIZE ; j + + )
ss - > button_option_is_cached [ j ] = 0 ;
2006-05-26 07:49:24 +00:00
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 )
2008-07-05 12:42:53 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
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 ) | |
2008-10-14 19:48:59 +00:00
! SANE_OPTION_IS_SETTABLE ( opt - > sod . cap ) )
return SANE_STATUS_INVAL ; /* or _UNSUPPORTED? */
break ;
2006-05-26 07:49:24 +00:00
case SANE_ACTION_SET_AUTO :
if ( ! ( opt - > sod . cap & SANE_CAP_AUTOMATIC ) | |
2008-10-14 19:48:59 +00:00
! SANE_OPTION_IS_SETTABLE ( opt - > sod . cap ) )
return SANE_STATUS_INVAL ; /* or _UNSUPPORTED? */
break ;
2006-05-26 07:49:24 +00:00
case SANE_ACTION_GET_VALUE :
if ( ! v | | ! ( opt - > sod . cap & SANE_CAP_SOFT_DETECT ) )
2008-10-14 19:48:59 +00:00
return SANE_STATUS_INVAL ; /* or _UNSUPPORTED? */
break ;
2006-05-26 07:49:24 +00:00
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. */
2010-09-01 19:18:14 +00:00
p - > bytes_per_line = ( sp - > w * sp - > channels * sp - > depth ) / 8 ;
2006-05-26 07:49:24 +00:00
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 )
2008-10-05 20:42:19 +00:00
{
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 ;
}
2006-05-26 07:49:24 +00:00
ss - > cancel = SANE_FALSE ;
2008-10-05 20:42:19 +00:00
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 + + ;
2006-05-26 07:49:24 +00:00
if ( calc_scan_param ( ss , & ss - > sp ) < 0 )
return SANE_STATUS_INVAL ;
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 )
{
2010-09-01 19:18:14 +00:00
ss - > output_line_size = ( ss - > sp . w * ss - > sp . channels * ss - > sp . depth ) / 8 ;
2006-05-26 07:49:24 +00:00
ss - > byte_pos_in_line = 0 ;
ss - > last_read_status = SANE_STATUS_GOOD ;
ss - > scanning = SANE_TRUE ;
ss - > idle = SANE_FALSE ;
}
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 ;
2010-07-03 19:27:44 +00:00
/* 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 ] ;
2006-05-26 07:49:24 +00:00
SANE_Status status ;
if ( len )
* len = 0 ;
if ( ! ss | | ! buf | | ! len )
return SANE_STATUS_INVAL ;
if ( ss - > cancel )
return SANE_STATUS_CANCELLED ;
2008-02-17 15:49:43 +00:00
if ( ( ss - > idle )
2008-07-05 12:42:53 +00:00
& & ( ss - > sp . source = = PIXMA_SOURCE_ADF | | ss - > sp . source = = PIXMA_SOURCE_ADFDUP ) )
2006-05-26 07:49:24 +00:00
return SANE_STATUS_INVAL ;
if ( ! ss - > scanning )
return ss - > last_read_status ;
status = SANE_STATUS_GOOD ;
2012-02-03 21:05:32 +00:00
/* CCD scanners use software lineart
2012-08-11 20:50:30 +00:00
* the scanner must scan 24 bit color or 8 bit grayscale for one bit lineart */
2012-02-03 21:05:32 +00:00
if ( ( ss - > sp . line_size - ( ( ss - > sp . software_lineart = = 1 ) ? ( ss - > output_line_size * 8 ) : ss - > output_line_size ) ) = = 0 )
2006-05-26 07:49:24 +00:00
{
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 ! */
2012-02-03 21:05:32 +00:00
PDBG ( pixma_dbg ( 1 , " *sane_read***** Warning: padding may cause incomplete scan results \n " ) ) ;
2006-05-26 07:49:24 +00:00
sum = 0 ;
while ( sum < maxlen )
2008-10-05 20:42:19 +00:00
{
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 ;
}
}
2006-05-26 07:49:24 +00:00
}
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 ;
if ( ss - > idle )
return ;
close ( ss - > rpipe ) ;
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 )
{
2006-08-27 12:39:18 +00:00
PDBG ( pixma_dbg
( 1 , " WARNING:fcntl(F_SETFL) failed %s \n " , strerror ( errno ) ) ) ;
2006-05-26 07:49:24 +00:00
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
2012-06-27 08:49:09 +00:00
type string mode [ 30 ]
2006-05-26 07:49:24 +00:00
constraint @ string_list = ss - > mode_list
2013-02-09 11:43:38 +00:00
default @ s = SANE_VALUE_SCAN_MODE_COLOR
2006-05-26 07:49:24 +00:00
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
2012-04-17 09:02:08 +00:00
desc Selects the scan source ( such as a document - feeder ) . Set source before mode and resolution . Resets mode and resolution to auto values .
2006-05-26 07:49:24 +00:00
default Flatbed
cap soft_select soft_detect
type bool button - controlled
2008-06-15 20:05:14 +00:00
title Button - controlled scan
2006-05-26 07:49:24 +00:00
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
2012-02-16 18:58:23 +00:00
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
2006-05-26 07:49:24 +00:00
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
2012-10-31 11:40:07 +00:00
cap soft_detect advanced
2006-05-26 07:49:24 +00:00
type int button - 2
default 0
title Button 2
2012-10-31 11:40:07 +00:00
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
2006-05-26 07:49:24 +00:00
2013-07-18 20:45:45 +00:00
type int scan - resolution
default 0
title Scan resolution
cap soft_detect advanced
2012-02-03 21:05:32 +00:00
rem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
type group
title Extras
type int threshold
unit PERCENT
default 50
2012-02-27 14:31:37 +00:00
constraint ( 0 , 100 , 1 )
2012-02-03 21:05:32 +00:00
title @ SANE_TITLE_THRESHOLD
desc @ SANE_DESC_THRESHOLD
cap soft_select soft_detect automatic inactive
2012-02-29 10:40:18 +00:00
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
2006-05-26 07:49:24 +00:00
rem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
END SANE_Option_Descriptor
*/
2012-02-03 21:05:32 +00:00
/* pixma_sane_options.c generated by
* scripts / pixma_gen_options . py < pixma . c > pixma_sane_options . c
2013-07-18 20:45:45 +00:00
*
* pixma_sane_options . h generated by
* scripts / pixma_gen_options . py h < pixma . c > pixma_sane_options . h
2012-10-31 11:40:07 +00:00
*/
2012-02-03 21:05:32 +00:00
# include "pixma_sane_options.c"