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