diff --git a/ChangeLog b/ChangeLog index 01705e01f..67b19c28b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-06-24 m. allan noah + * backend/fujitsu.[ch], backend/fujitsu-scsi.h, + doc/descriptions/fujitsu.desc, doc/sane-fujitsu.man: + backend version 65, add endorser support, add quirks for fi-4990 + 2008-06-24 Julien Blache * backend/net.c: do not reload options behind the frontend's back in sane_control_option; rather return SANE_STATUS_INVAL and warn diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h index 533403b26..5286f608e 100644 --- a/backend/fujitsu-scsi.h +++ b/backend/fujitsu-scsi.h @@ -84,6 +84,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* ==================================================================== */ /* SCSI commands */ +#define set_SCSI_opcode(out, val) out[0]=val + typedef struct { unsigned char *cmd; @@ -109,7 +111,7 @@ scsiblk; #define MODE_SELECT 0x15 #define MODE_SENSE 0x1a #define SCAN 0x1b -#define IMPRINTER 0xc1 +#define ENDORSER 0xc1 #define HW_STATUS 0xc2 #define SCANNER_CONTROL 0xf1 @@ -252,7 +254,7 @@ static scsiblk inquiryB = { inquiryC, sizeof (inquiryC) }; /* vendor unique section */ #define get_IN_operator_panel(in) getbitfield(in+0x20, 1, 1) #define get_IN_barcode(in) getbitfield(in+0x20, 1, 2) -#define get_IN_imprinter(in) getbitfield(in+0x20, 1, 3) +#define get_IN_endorser(in) getbitfield(in+0x20, 1, 3) #define get_IN_duplex(in) getbitfield(in+0x20, 1, 4) #define get_IN_transparency(in) getbitfield(in+0x20, 1, 5) #define get_IN_flatbed(in) getbitfield(in+0x20, 1, 6) @@ -293,10 +295,10 @@ static scsiblk inquiryB = { inquiryC, sizeof (inquiryC) }; #define get_IN_has_cmd_tur(in) getbitfield(in+0x29, 1, 0) /* more stuff here? (vendor commands) */ -#define get_IN_has_subwindow(in) getbitfield(in+0x2b, 1, 0) -#define get_IN_has_endorser(in) getbitfield(in+0x2b, 1, 1) -#define get_IN_has_hw_status(in) getbitfield(in+0x2b, 1, 2) -#define get_IN_has_scanner_ctl(in) getbitfield(in+0x31, 1, 1) +#define get_IN_has_cmd_subwindow(in) getbitfield(in+0x2b, 1, 0) +#define get_IN_has_cmd_endorser(in) getbitfield(in+0x2b, 1, 1) +#define get_IN_has_cmd_hw_status(in) getbitfield(in+0x2b, 1, 2) +#define get_IN_has_cmd_scanner_ctl(in) getbitfield(in+0x31, 1, 1) #define get_IN_brightness_steps(in) getnbyte(in+0x52, 1) #define get_IN_threshold_steps(in) getnbyte(in+0x53, 1) @@ -328,12 +330,12 @@ static scsiblk inquiryB = { inquiryC, sizeof (inquiryC) }; #define get_IN_compression_JPG_EXT(in) getbitfield(in+0x5a, 1, 2) #define get_IN_compression_JPG_INDEP(in) getbitfield(in+0x5a, 1, 1) -#define get_IN_imprinter_mechanical(in) getbitfield(in+0x5c, 1, 7) -#define get_IN_imprinter_stamp(in) getbitfield(in+0x5c, 1, 6) -#define get_IN_imprinter_electrical(in) getbitfield(in+0x5c, 1, 5) -#define get_IN_imprinter_max_id(in) getbitfield(in+0x5c, 0x0f, 0) +#define get_IN_endorser_mechanical(in) getbitfield(in+0x5c, 1, 7) +#define get_IN_endorser_stamp(in) getbitfield(in+0x5c, 1, 6) +#define get_IN_endorser_electrical(in) getbitfield(in+0x5c, 1, 5) +#define get_IN_endorser_max_id(in) getbitfield(in+0x5c, 0x0f, 0) -#define get_IN_imprinter_size(in) getbitfield(in+0x5d, 3, 0) +#define get_IN_endorser_type(in) getbitfield(in+0x5d, 3, 0) #define get_IN_connection(in) getbitfield(in+0x62, 3, 0) @@ -350,21 +352,15 @@ static scsiblk test_unit_readyB = { test_unit_readyC, sizeof (test_unit_readyC) }; /* ==================================================================== */ -#if 0 -static unsigned char get_windowC[] = - { GET_WINDOW, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -/* opcode, lun, _____4 X reserved____, transfer length, control byte */ -static scsiblk get_windowB = { get_windowC, sizeof (get_windowC) }; -#define set_GW_xferlen(sb, len) putnbyte(sb + 0x06, len, 3) -#endif -/* ==================================================================== */ -static unsigned char set_windowC[] = - { SET_WINDOW, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -/* opcode, lun, _____4 X reserved____, transfer length, control byte */ -static scsiblk set_windowB = { set_windowC, sizeof (set_windowC) }; +#define SET_WINDOW_code 0x24 +#define SET_WINDOW_len 10 + #define set_SW_xferlen(sb, len) putnbyte(sb + 0x06, len, 3) +#define SW_header_len 8 +#define SW_desc_len 64 + /* ==================================================================== */ static unsigned char object_positionC[] = @@ -388,9 +384,9 @@ static scsiblk sendB = {sendC, sizeof (sendC)}; #define S_datatype_halftone_mask 0x02 #define S_datatype_gamma_function 0x03*/ #define S_datatype_lut_data 0x83 -/*#define S_datatype_jpg_q_table 0x88 -#define S_datatype_imprinter_data 0x90 -#define S_EX_datatype_lut 0x01 +/*#define S_datatype_jpg_q_table 0x88*/ +#define S_datatype_endorser_data 0x90 +/*#define S_EX_datatype_lut 0x01 #define S_EX_datatype_shading_data 0xa0 #define S_user_reg_gamma 0xc0 #define S_device_internal_info 0x03 @@ -412,63 +408,82 @@ static unsigned char send_lutC[1034]; #define set_S_lut_dsize(sb, val) putnbyte(sb + 6, val, 2) #define S_lut_data_offset 0x0a -/* -static unsigned char send_imprinterC[] = - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}; -static scsiblk send_imprinterB = - {send_imprinterC, sizeof(send_imprinterC)}; -#define set_imprinter_cnt_dir(sb, val) setbitfield(sb + 0x01, 1, 5, val) -#define S_im_dir_inc 0 -#define S_im_dir_dec 1 -#define set_imprinter_lap24(sb, val) setbitfield(sb + 0x01, 1, 4, val) -#define S_im_ctr_24bit 1 -#define S_im_ctr_16bit 0 -#define set_imprinter_cstep(sb, val) setbitfield(sb + 0x01, 0x03, 0, val) -#define set_imprinter_uly(sb, val) putnbyte(sb + 0x06, val, 4) -#define set_imprinter_dirs(sb, val) setbitfield(sb + 0x0c, 0x03, 0, val) -#define S_im_dir_left_right 0 -#define S_im_dir_top_bottom 1 -#define S_im_dir_right_left 2 -#define S_im_dir_bottom_top 3 -#define set_imprinter_string_length(sb, len) putnbyte(sb + 0x11, len, 1) -#define max_imprinter_string_length 40 -*/ +/*new style cmd sending code*/ +#define SEND_code 0x2a +#define SEND_len 10 -/* -static unsigned char gamma_user_LUT_LS1K[512] = { 0x00 }; -static scsiblk gamma_user_LUT_LS1K_LS1K = - { gamma_user_LUT_LS1K, sizeof(gamma_user_LUT_LS1K) }; -*/ +#define S_e_data_min_len 18 /*minimum 18 bytes no string bytes*/ +#define S_e_data_max_len 98 /*maximum 18 bytes plus 80 string bytes*/ + +#define set_S_endorser_data_id(sb, val) sb[0] = val + +#define set_S_endorser_stamp(sb, val) setbitfield(sb + 0x01, 1, 7, val) +#define set_S_endorser_elec(sb, val) setbitfield(sb + 0x01, 1, 6, val) +#define set_S_endorser_decr(sb, val) setbitfield(sb + 0x01, 1, 5, val) +#define S_e_decr_inc 0 +#define S_e_decr_dec 1 +#define set_S_endorser_lap24(sb, val) setbitfield(sb + 0x01, 1, 4, val) +#define S_e_lap_24bit 1 +#define S_e_lap_16bit 0 +#define set_S_endorser_ctstep(sb, val) setbitfield(sb + 0x01, 0x03, 0, val) + +#define set_S_endorser_ulx(sb, val) putnbyte(sb + 0x02, val, 4) +#define set_S_endorser_uly(sb, val) putnbyte(sb + 0x06, val, 4) + +#define set_S_endorser_font(sb, val) sb[0xa] = val +#define S_e_font_horiz 0 +#define S_e_font_vert 1 +#define S_e_font_horiz_narrow 2 +#define set_S_endorser_size(sb, val) sb[0xb] = val + +#define set_S_endorser_revs(sb, val) setbitfield(sb + 0x0c, 0x01, 7, val) +#define S_e_revs_fwd 0 +#define S_e_revs_rev 1 +#define set_S_endorser_bold(sb, val) setbitfield(sb + 0x0c, 0x01, 2, val) +#define set_S_endorser_dirs(sb, val) setbitfield(sb + 0x0c, 0x03, 0, val) +#define S_e_dir_left_right 0 +#define S_e_dir_top_bottom 1 +#define S_e_dir_right_left 2 +#define S_e_dir_bottom_top 3 + +#define set_S_endorser_string_length(sb, len) sb[0x11] = len +#define set_S_endorser_string(sb,val,len) memcpy(sb+0x12,val,(size_t)len) /* ==================================================================== */ -/* -static unsigned char imprinterC[] = - { IMPRINTER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static scsiblk imprinterB = { imprinterC, sizeof (imprinterC) }; -#define set_IM_xfer_length(sb, val) putnbyte(sb + 0x7, val, 2) +static unsigned char endorserC[] = + { ENDORSER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static scsiblk endorserB = { endorserC, sizeof (endorserC) }; -static unsigned char imprinter_descC[] = +#define set_E_xfer_length(sb, val) putnbyte(sb + 0x7, val, 2) + +static unsigned char endorser_desc4C[] = + { 0x00, 0x00, 0x00, 0x00 }; +static scsiblk endorser_desc4B = {endorser_desc4C, sizeof(endorser_desc4C) }; + +static unsigned char endorser_desc6C[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static scsiblk imprinter_descB = {imprinter_descC, sizeof(imprinter_descC) }; -*/ -/* enable/disable imprinter printing*/ -#define set_IMD_enable(sb, val) setbitfield(sb + 0x01, 1, 7, val) -#define IMD_enable 0 -#define IMD_disable 1 +static scsiblk endorser_desc6B = {endorser_desc6C, sizeof(endorser_desc6C) }; + +#define set_ED_endorser_data_id(sb, val) sb[0] = val + +/* enable/disable endorser printing*/ +#define set_ED_stop(sb, val) setbitfield(sb + 0x01, 1, 7, val) +#define ED_start 0 +#define ED_stop 1 /* specifies thes side of a document to be printed */ -#define set_IMD_side(sb, val) setbitfield(sb + 0x01, 1, 6, val) -#define IMD_front 0 -#define IMD_back 1 +#define set_ED_side(sb, val) setbitfield(sb + 0x01, 1, 6, val) +#define ED_front 0 +#define ED_back 1 + /* format of the counter 16/24 bit*/ -#define set_IMD_format(sb, val) setbitfield(sb + 0x01, 1, 5, val) -#define IMD_16_bit 0 -#define IMD_24_bit 1 +#define set_ED_lap24(sb, val) setbitfield(sb + 0x01, 1, 5, val) +#define ED_lap_16bit 0 +#define ED_lap_24bit 1 + /* initial count */ -#define set_IMD_initial_count_16(sb, val) putnbyte(sb + 0x02, val, 2) -#define set_IMD_initial_count_24(sb, val) putnbyte(sb + 0x03, val, 3) +#define set_ED_initial_count_16(sb, val) putnbyte(sb + 0x02, val, 2) +#define set_ED_initial_count_24(sb, val) putnbyte(sb + 0x03, val, 3) /* ==================================================================== */ @@ -574,6 +589,7 @@ static scsiblk mode_select_10byteB = { #define MSEL_dropout_CUSTOM 12 #define set_MSEL_buff_mode(sb, val) setbitfield(sb + 0x06, 0x03, 6, val) +#define set_MSEL_buff_clear(sb, val) setbitfield(sb + 0x07, 0x03, 6, val) #define set_MSEL_prepick(sb, val) setbitfield(sb + 0x06, 0x03, 6, val) @@ -627,24 +643,14 @@ static scsiblk hw_statusB = { hw_statusC, sizeof (hw_statusC) }; /* ==================================================================== */ -/* We use the same structure for both SET WINDOW and GET WINDOW. */ -static unsigned char window_descriptor_headerC[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, /* reserved */ - 0x00, 0x00, /* Window Descriptor Length */ -}; -static scsiblk window_descriptor_headerB= - { window_descriptor_headerC, sizeof (window_descriptor_headerC) }; #define set_WPDB_wdblen(sb, len) putnbyte(sb + 0x06, len, 2) /* ==================================================================== */ -static unsigned char window_descriptor_blockC[] = { /* 0x00 - Window Identifier * 0x00 for 3096 * 0x00 (front) or 0x80 (back) for 3091 */ - 0x00, #define set_WD_wid(sb, val) sb[0] = val #define WD_wid_front 0x00 #define WD_wid_back 0x80 @@ -652,7 +658,6 @@ static unsigned char window_descriptor_blockC[] = { /* 0x01 - Reserved (bits 7-1), AUTO (bit 0) * Use 0x00 for 3091, 3096 */ - 0x00, #define set_WD_auto(sb, val) setbitfield(sb + 0x01, 1, 0, val) #define get_WD_auto(sb) getbitfield(sb + 0x01, 1, 0) @@ -661,7 +666,6 @@ static unsigned char window_descriptor_blockC[] = { * 3096 suppors 200,240,300,400; or 100-1600 in steps of 4 * if image processiong option installed */ - 0x00, 0x00, #define set_WD_Xres(sb, val) putnbyte(sb + 0x02, val, 2) #define get_WD_Xres(sb) getnbyte(sb + 0x02, 2) @@ -671,19 +675,16 @@ static unsigned char window_descriptor_blockC[] = { * 3096 suppors 200,240,300,400; or 100-1600 in steps of 4 * if image processiong option installed */ - 0x00, 0x00, #define set_WD_Yres(sb, val) putnbyte(sb + 0x04, val, 2) #define get_WD_Yres(sb) getnbyte(sb + 0x04, 2) /* 0x06-0x09 - Upper Left X in 1/1200 inch */ - 0x00, 0x00, 0x00, 0x00, #define set_WD_ULX(sb, val) putnbyte(sb + 0x06, val, 4) #define get_WD_ULX(sb) getnbyte(sb + 0x06, 4) /* 0x0a-0x0d - Upper Left Y in 1/1200 inch */ - 0x00, 0x00, 0x00, 0x00, #define set_WD_ULY(sb, val) putnbyte(sb + 0x0a, val, 4) #define get_WD_ULY(sb) getnbyte(sb + 0x0a, 4) @@ -692,7 +693,6 @@ static unsigned char window_descriptor_blockC[] = { * 3096 left+width max 14592 * also limited to page size, see bytes 0x35ff. */ - 0x00, 0x00, 0x00, 0x00, #define set_WD_width(sb, val) putnbyte(sb + 0x0e, val, 4) #define get_WD_width(sb) getnbyte(sb + 0x0e, 4) @@ -701,7 +701,6 @@ static unsigned char window_descriptor_blockC[] = { * 3096 top+height max 20736, also if left+width>13199, * top+height has to be less than 19843 */ - 0x00, 0x00, 0x00, 0x00, #define set_WD_length(sb, val) putnbyte(sb + 0x12, val, 4) #define get_WD_length(sb) getnbyte(sb + 0x12, 4) @@ -711,7 +710,6 @@ static unsigned char window_descriptor_blockC[] = { ..., E0-FF) * use 0x00 for user defined dither pattern */ - 0x00, #define set_WD_brightness(sb, val) sb[0x16] = val #define get_WD_brightness(sb) sb[0x16] @@ -722,7 +720,6 @@ static unsigned char window_descriptor_blockC[] = { * 3096 0x00 = use "simplified dynamic treshold", otherwise * same as above but resolution is only 64 steps. */ - 0x00, #define set_WD_threshold(sb, val) sb[0x17] = val #define get_WD_threshold(sb) sb[0x17] @@ -730,7 +727,6 @@ static unsigned char window_descriptor_blockC[] = { * 3091 - not supported, always use 0x00 * 3096 - the same */ - 0x00, #define set_WD_contrast(sb, val) sb[0x18] = val #define get_WD_contrast(sb) sb[0x18] @@ -739,7 +735,6 @@ static unsigned char window_descriptor_blockC[] = { * 0x02 for grayscale, 0x05 for color. * 3096 - same but minus color. */ - 0x00, #define set_WD_composition(sb, val) sb[0x19] = val #define get_WD_composition(sb) sb[0x19] #define WD_comp_LA 0 @@ -753,7 +748,6 @@ static unsigned char window_descriptor_blockC[] = { * 3091 - use 0x01 for b/w or 0x08 for gray/color * 3096 - use 0x01 for b/w or 0x08 for gray */ - 0x08, #define set_WD_bitsperpixel(sb, val) sb[0x1a] = val #define get_WD_bitsperpixel(sb) sb[0x1a] @@ -768,7 +762,6 @@ static unsigned char window_descriptor_blockC[] = { * pattern number, three builtin and five downloadable * supported; higher numbers = error. */ - 0x00, 0x00, #define set_WD_halftone(sb, val) putnbyte(sb + 0x1b, val, 2) #define get_WD_halftone(sb) getnbyte(sb + 0x1b, 2) @@ -778,7 +771,6 @@ static unsigned char window_descriptor_blockC[] = { * 3096: the same; bit 7 must be set for gray and not * set for b/w. */ - 0x00, #define set_WD_rif(sb, val) setbitfield(sb + 0x1d, 1, 7, val) #define get_WD_rif(sb) getbitfield(sb + 0x1d, 1, 7) @@ -786,14 +778,12 @@ static unsigned char window_descriptor_blockC[] = { * 3091 not supported, use 0x00 * 3096 not supported, use 0x00 */ - 0x00, 0x00, /* 0x1e *//* bit ordering */ #define set_WD_bitorder(sb, val) putnbyte(sb + 0x1e, val, 2) #define get_WD_bitorder(sb) getnbyte(sb + 0x1e, 2) /* 0x20 - compression type * not supported on smaller models, use 0x00 */ - 0x00, #define set_WD_compress_type(sb, val) sb[0x20] = val #define get_WD_compress_type(sb) sb[0x20] #define WD_cmp_NONE 0 @@ -810,19 +800,16 @@ static unsigned char window_descriptor_blockC[] = { * specify "k" parameter with MR compress, * or with JPEG- Q param, 0-7 */ - 0x00, #define set_WD_compress_arg(sb, val) sb[0x21] = val #define get_WD_compress_arg(sb) sb[0x21] /* 0x22-0x27 - reserved */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 - vendor unique id code, decides meaning of remaining bytes * 0xc1 = color mode (fi-series) * 0xc0 = weird mode (M3091 and M3092) * 0x00 = mono mode (other M-series and fi-series) */ - 0x00, #define set_WD_vendor_id_code(sb, val) sb[0x28] = val #define get_WD_vendor_id_code(sb) sb[0x28] #define WD_VUID_MONO 0x00 @@ -830,7 +817,6 @@ static unsigned char window_descriptor_blockC[] = { #define WD_VUID_COLOR 0xc1 /* 0x29 common gamma */ - 0x00, #define set_WD_gamma(sb, val) sb[0x29] = val #define get_WD_gamma(sb) sb[0x29] #define WD_gamma_DEFAULT 0 @@ -840,8 +826,6 @@ static unsigned char window_descriptor_blockC[] = { /*==================================================================*/ /* 0x2a-0x34 - vary based on vuid */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, /*==================================================================*/ /* vuid 0x00, mono params */ @@ -964,9 +948,6 @@ static unsigned char window_descriptor_blockC[] = { /*==================================================================*/ /* 0x35-0x3d - paper size common to all vuids */ - 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, #define set_WD_paper_selection(sb, val) setbitfield(sb + 0x35, 3, 6, val) #define WD_paper_SEL_UNDEFINED 0 @@ -980,7 +961,6 @@ static unsigned char window_descriptor_blockC[] = { /*==================================================================*/ /* 0x3e-end - vary based on vuid */ - 0x00, 0x00 /*==================================================================*/ /* vuid 0xc0, 3091/2 - lots more params after 3f */ @@ -1004,10 +984,6 @@ static unsigned char window_descriptor_blockC[] = { #define WD_dtc_selection_SIMPLIFIED 2 /*3f reserved*/ -}; -static scsiblk window_descriptor_blockB = - { window_descriptor_blockC, sizeof (window_descriptor_blockC) }; -#define max_WDB_size 0xc8 /* ==================================================================== */ diff --git a/backend/fujitsu.c b/backend/fujitsu.c index 670a02873..281ae8393 100644 --- a/backend/fujitsu.c +++ b/backend/fujitsu.c @@ -1,6 +1,17 @@ /* sane - Scanner Access Now Easy. - This file is part of the SANE package. + This file is part of the SANE package, and implements a SANE backend + for various Fujitsu scanners. + + Copyright (C) 2000 Randolph Bentson + Copyright (C) 2001 Frederik Ramm + Copyright (C) 2001-2004 Oliver Schirrmeister + Copyright (C) 2003-2008 M. Allan Noah + + JPEG output support funded by Archivista GmbH, www.archivista.ch + Endorser support funded by O A S Oilfield Accounting Service Ltd, www.oas.ca + + -------------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -40,12 +51,6 @@ -------------------------------------------------------------------------- - This file implements a SANE backend for various Fujitsu scanners. - Currently supported: - - M309x (Frederik Ramm, Randolph Bentson, Oliver Schirrmeister) - - M409x (Oliver Schirrmeister) - - fi-series (M. Allan Noah, Oliver Schirrmeister) - The source code is divided in sections which you can easily find by searching for the tag "@@". @@ -321,6 +326,15 @@ - improve handling of vendor unique section of set_window - add init_interlace to detect proper color mode without hardcoding - add ascii output to hexdump + v65 2008-06-24, MAN + - detect endorser type during init_inquiry() + - add endorser options + - add send_endorser() and call from sane_control_option() + - add endorser() and call from sane_start() + - convert set_window() to use local cmd and payload copies + - remove get_window() + - mode_select_buff() now clears the buffer, and called in sane_close() + - fi-4990 quirks added, including modified even_scan_line code SANE FLOW DIAGRAM @@ -381,7 +395,7 @@ #include "fujitsu.h" #define DEBUG 1 -#define BUILD 64 +#define BUILD 65 /* values for SANE_DEBUG_FUJITSU env var: - errors 5 @@ -425,6 +439,15 @@ static const char string_10mm[] = "10mm"; static const char string_15mm[] = "15mm"; static const char string_20mm[] = "20mm"; +static const char string_Horizontal[] = "Horizontal"; +static const char string_HorizontalBold[] = "Horizontal bold"; +static const char string_HorizontalNarrow[] = "Horizontal narrow"; +static const char string_Vertical[] = "Vertical"; +static const char string_VerticalBold[] = "Vertical bold"; + +static const char string_TopToBottom[] = "Top to bottom"; +static const char string_BottomToTop[] = "Bottom to top"; + /* Also set via config file. */ static int global_buffer_size = 64 * 1024; @@ -1116,8 +1139,8 @@ init_vpd (struct fujitsu *s) s->has_barcode = get_IN_barcode(buffer); DBG (15, " barcode: %d\n", s->has_barcode); - s->has_imprinter = get_IN_imprinter(buffer); - DBG (15, " imprinter: %d\n", s->has_imprinter); + s->has_endorser = get_IN_endorser(buffer); + DBG (15, " endorser: %d\n", s->has_endorser); s->has_duplex = get_IN_duplex(buffer); s->has_back = s->has_duplex; @@ -1222,16 +1245,16 @@ init_vpd (struct fujitsu *s) /* vendor added scsi command support */ /* FIXME: there are more of these... */ - s->has_cmd_subwindow = get_IN_has_subwindow(buffer); + s->has_cmd_subwindow = get_IN_has_cmd_subwindow(buffer); DBG (15, " subwindow cmd: %d\n", s->has_cmd_subwindow); - s->has_cmd_endorser = get_IN_has_endorser(buffer); + s->has_cmd_endorser = get_IN_has_cmd_endorser(buffer); DBG (15, " endorser cmd: %d\n", s->has_cmd_endorser); - s->has_cmd_hw_status = get_IN_has_hw_status (buffer); + s->has_cmd_hw_status = get_IN_has_cmd_hw_status (buffer); DBG (15, " hardware status cmd: %d\n", s->has_cmd_hw_status); - s->has_cmd_scanner_ctl = get_IN_has_scanner_ctl(buffer); + s->has_cmd_scanner_ctl = get_IN_has_cmd_scanner_ctl(buffer); DBG (15, " scanner control cmd: %d\n", s->has_cmd_scanner_ctl); /* get threshold, brightness and contrast ranges. */ @@ -1308,11 +1331,13 @@ init_vpd (struct fujitsu *s) DBG (15, " compression JPG3: %d\n", s->has_comp_JPG3); /* FIXME: we dont store these? */ - DBG (15, " imprinter mech: %d\n", get_IN_imprinter_mechanical(buffer)); - DBG (15, " imprinter stamp: %d\n", get_IN_imprinter_stamp(buffer)); - DBG (15, " imprinter elec: %d\n", get_IN_imprinter_electrical(buffer)); - DBG (15, " imprinter max id: %d\n", get_IN_imprinter_max_id(buffer)); - DBG (15, " imprinter size: %d\n", get_IN_imprinter_size(buffer)); + DBG (15, " endorser mech: %d\n", get_IN_endorser_mechanical(buffer)); + DBG (15, " endorser stamp: %d\n", get_IN_endorser_stamp(buffer)); + DBG (15, " endorser elec: %d\n", get_IN_endorser_electrical(buffer)); + DBG (15, " endorser max id: %d\n", get_IN_endorser_max_id(buffer)); + + s->endorser_type = get_IN_endorser_type(buffer); + DBG (15, " endorser type: %d\n", s->endorser_type); /*not all scanners go this far*/ if (get_IN_page_length (buffer) > 0x5f) { @@ -1342,6 +1367,20 @@ init_vpd (struct fujitsu *s) DBG (5, "init_vpd: with details of your scanner model.\n"); } + /* get EVPD for fb? + set_IN_return_size (inquiryB.cmd, inLen); + set_IN_evpd (inquiryB.cmd, 1); + set_IN_page_code (inquiryB.cmd, 0xf1); + + ret = do_cmd ( + s, 1, 0, + inquiryB.cmd, inquiryB.size, + NULL, 0, + buffer, &inLen + ); + if() + */ + DBG (10, "init_vpd: finish\n"); return ret; @@ -1589,6 +1628,20 @@ init_model (struct fujitsu *s) s->window_gamma = 0x80; } + /* endorser type tells string length (among other things) */ + /*old-style is 40 bytes*/ + if(s->endorser_type == ET_OLD){ + s->endorser_string_len = 40; + } + /*short new style is 60 bytes*/ + else if(s->endorser_type == ET_30){ + s->endorser_string_len = 60; + } + /*long new style is 80 bytes*/ + else if(s->endorser_type == ET_40){ + s->endorser_string_len = 80; + } + /* these two scanners lie about their capabilities, * and/or differ significantly from most other models */ if (strstr (s->model_name, "M3091") @@ -1637,6 +1690,17 @@ init_model (struct fujitsu *s) s->os_y_basic = 236; } + + /* some firmware versions use capital f? */ + else if (strstr (s->model_name, "Fi-4990") + || strstr (s->model_name, "fi-4990") ) { + + /* weirdness */ + s->even_scan_line = 1; + s->duplex_interlace = DUPLEX_INTERLACE_NONE; + s->color_interlace = COLOR_INTERLACE_RRGGBB; + } + /* some firmware versions use capital f? */ else if (strstr (s->model_name, "Fi-5900") || strstr (s->model_name, "fi-5900") ) { @@ -1706,6 +1770,12 @@ init_user (struct fujitsu *s) /* gamma ramp exponent */ s->gamma = 1; + /* safe endorser settings */ + s->u_endorser_bits=16; + s->u_endorser_step=1; + s->u_endorser_dir=DIR_TTB; + strcpy((char *)s->u_endorser_string,"%05ud"); + DBG (10, "init_user: finish\n"); return SANE_STATUS_GOOD; @@ -2698,6 +2768,185 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } + /* "Endorser" group ------------------------------------------------------ */ + if(option==OPT_ENDORSER_GROUP){ + opt->name = "endorser-options"; + opt->title = "Endorser Options"; + opt->desc = "Controls for endorser unit"; + opt->type = SANE_TYPE_GROUP; + opt->unit = SANE_UNIT_NONE; + opt->size = 0; + opt->cap = 0; + opt->constraint_type = SANE_CONSTRAINT_NONE; + } + + if(option==OPT_ENDORSER){ + opt->name = "endorser"; + opt->title = "Endorser"; + opt->desc = "Enable endorser unit"; + opt->type = SANE_TYPE_BOOL; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + + if (s->has_endorser) + opt->cap= SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_NONE; + } + + if(option==OPT_ENDORSER_BITS){ + opt->name = "endorser-bits"; + opt->title = "Endorser bits"; + opt->desc = "Determines maximum endorser counter value."; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + + /*old type cant do this?*/ + if (s->has_endorser && s->endorser_type != ET_OLD && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->endorser_bits_range; + + s->endorser_bits_range.min = 16; + s->endorser_bits_range.max = 24; + s->endorser_bits_range.quant = 8; + } + + if(option==OPT_ENDORSER_VAL){ + opt->name = "endorser-val"; + opt->title = "Endorser value"; + opt->desc = "Initial endorser counter value."; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + + if (s->has_endorser && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->endorser_val_range; + + s->endorser_val_range.min = 0; + s->endorser_val_range.max = (1 << s->u_endorser_bits)-1; + s->endorser_val_range.quant = 1; + } + + if(option==OPT_ENDORSER_STEP){ + opt->name = "endorser-step"; + opt->title = "Endorser step"; + opt->desc = "Change endorser counter value by this much for each page."; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + + if (s->has_endorser && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->endorser_step_range; + + s->endorser_step_range.min = -2; + s->endorser_step_range.max = 2; + s->endorser_step_range.quant = 1; + } + + if(option==OPT_ENDORSER_Y){ + opt->name = "endorser-y"; + opt->title = "Endorser Y"; + opt->desc = "Endorser print offset from top of paper."; + opt->type = SANE_TYPE_FIXED; + opt->unit = SANE_UNIT_MM; + opt->size = sizeof(SANE_Word); + + if (s->has_endorser && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &(s->endorser_y_range); + + /* values stored in 1200 dpi units */ + /* must be converted to MM for sane */ + s->endorser_y_range.min = SCANNER_UNIT_TO_FIXED_MM(0); + s->endorser_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); + s->endorser_y_range.quant = MM_PER_UNIT_FIX; + } + + if(option==OPT_ENDORSER_FONT){ + opt->name = "endorser-font"; + opt->title = "Endorser font"; + opt->desc = "Endorser printing font."; + opt->type = SANE_TYPE_STRING; + opt->unit = SANE_UNIT_NONE; + + /*only newest can do this?*/ + if (s->has_endorser && s->endorser_type == ET_40 && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; + opt->constraint.string_list = s->endorser_font_list; + + s->endorser_font_list[0] = string_Horizontal; + s->endorser_font_list[1] = string_HorizontalBold; + s->endorser_font_list[2] = string_HorizontalNarrow; + s->endorser_font_list[3] = string_Vertical; + s->endorser_font_list[4] = string_VerticalBold; + s->endorser_font_list[5] = NULL; + + opt->size = maxStringSize (opt->constraint.string_list); + } + + if(option==OPT_ENDORSER_DIR){ + opt->name = "endorser-dir"; + opt->title = "Endorser direction"; + opt->desc = "Endorser printing direction."; + opt->type = SANE_TYPE_STRING; + opt->unit = SANE_UNIT_NONE; + + if (s->has_endorser && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; + opt->constraint.string_list = s->endorser_dir_list; + + s->endorser_dir_list[0] = string_TopToBottom; + s->endorser_dir_list[1] = string_BottomToTop; + s->endorser_dir_list[2] = NULL; + + opt->size = maxStringSize (opt->constraint.string_list); + } + + if(option==OPT_ENDORSER_STRING){ + opt->name = "endorser-string"; + opt->title = "Endorser string"; + opt->desc = "Endorser alphanumeric print format. %05ud or %08ud at the end will be replaced by counter value."; + opt->type = SANE_TYPE_STRING; + opt->unit = SANE_UNIT_NONE; + opt->size = s->endorser_string_len + 1; + + if (s->has_endorser && s->u_endorser) + opt->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + + opt->constraint_type = SANE_CONSTRAINT_NONE; + } + /* "Sensor" group ------------------------------------------------------ */ if(option==OPT_SENSOR_GROUP){ opt->name = SANE_NAME_SENSORS; @@ -2869,7 +3118,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->desc = "Imprinter ink running low"; opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; - if (s->has_cmd_hw_status && s->has_imprinter) + if (s->has_cmd_hw_status && s->has_endorser) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; else opt->cap = SANE_CAP_INACTIVE; @@ -2917,7 +3166,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->desc = "Imprinter ink level"; opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; - if (s->has_cmd_hw_status && s->has_imprinter) + if (s->has_cmd_hw_status && s->has_endorser) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; else opt->cap = SANE_CAP_INACTIVE; @@ -3238,6 +3487,66 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->use_temp_file; return SANE_STATUS_GOOD; + /* Endorser Group */ + case OPT_ENDORSER: + *val_p = s->u_endorser; + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_BITS: + *val_p = s->u_endorser_bits; + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_VAL: + *val_p = s->u_endorser_val; + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_STEP: + *val_p = s->u_endorser_step; + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_Y: + *val_p = SCANNER_UNIT_TO_FIXED_MM(s->u_endorser_y); + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_FONT: + switch (s->u_endorser_font) { + case FONT_H: + strcpy (val, string_Horizontal); + break; + case FONT_HB: + strcpy (val, string_HorizontalBold); + break; + case FONT_HN: + strcpy (val, string_HorizontalNarrow); + break; + case FONT_V: + strcpy (val, string_Vertical); + break; + case FONT_VB: + strcpy (val, string_VerticalBold); + break; + } + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_DIR: + switch (s->u_endorser_dir) { + case DIR_TTB: + strcpy (val, string_TopToBottom); + break; + case DIR_BTT: + strcpy (val, string_BottomToTop); + break; + } + return SANE_STATUS_GOOD; + + case OPT_ENDORSER_STRING: + strncpy( + (SANE_String)val, + (SANE_String)s->u_endorser_string, + s->endorser_string_len+1 + ); + return SANE_STATUS_GOOD; + /* Sensor Group */ case OPT_TOP: get_hardware_status(s); @@ -3604,10 +3913,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->buff_mode= MSEL_ON; else if (!strcmp(val, string_Off)) s->buff_mode= MSEL_OFF; - if (s->has_MS_buff) - return mode_select_buff(s); - else - return SANE_STATUS_GOOD; + return mode_select_buff(s); case OPT_PREPICK: if (!strcmp(val, string_Default)) @@ -3655,6 +3961,63 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->use_temp_file = val_c; return SANE_STATUS_GOOD; + /* Endorser Group */ + case OPT_ENDORSER: + s->u_endorser = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; + return send_endorser(s); + + case OPT_ENDORSER_BITS: + s->u_endorser_bits = val_c; + return send_endorser(s); + + case OPT_ENDORSER_VAL: + s->u_endorser_val = val_c; + return send_endorser(s); + + case OPT_ENDORSER_STEP: + s->u_endorser_step = val_c; + return send_endorser(s); + + case OPT_ENDORSER_Y: + s->u_endorser_y = FIXED_MM_TO_SCANNER_UNIT(val_c); + return send_endorser(s); + + case OPT_ENDORSER_FONT: + + if (!strcmp (val, string_Horizontal)){ + s->u_endorser_font = FONT_H; + } + else if (!strcmp (val, string_HorizontalBold)){ + s->u_endorser_font = FONT_HB; + } + else if (!strcmp (val, string_HorizontalNarrow)){ + s->u_endorser_font = FONT_HN; + } + else if (!strcmp (val, string_Vertical)){ + s->u_endorser_font = FONT_V; + } + else if (!strcmp (val, string_VerticalBold)){ + s->u_endorser_font = FONT_VB; + } + return send_endorser(s); + + case OPT_ENDORSER_DIR: + if (!strcmp (val, string_TopToBottom)){ + s->u_endorser_dir = DIR_TTB; + } + else if (!strcmp (val, string_BottomToTop)){ + s->u_endorser_dir = DIR_BTT; + } + return send_endorser(s); + + case OPT_ENDORSER_STRING: + strncpy( + (SANE_String)s->u_endorser_string, + (SANE_String)val, + s->endorser_string_len+1 + ); + return send_endorser(s); } /* switch */ } /* else */ @@ -3784,6 +4147,100 @@ get_hardware_status (struct fujitsu *s) return ret; } +static SANE_Status +send_endorser(struct fujitsu *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + unsigned char cmd[SEND_len]; + size_t cmdLen = SEND_len; + + size_t strLen = strlen(s->u_endorser_string); + + unsigned char out[S_e_data_max_len]; /*we probably send less below*/ + size_t outLen = S_e_data_min_len + strLen; + + DBG (10, "send_endorser: start\n"); + + /*build the payload*/ + memset(out,0,outLen); + + set_S_endorser_data_id(out,0); + set_S_endorser_stamp(out,0); + set_S_endorser_elec(out,0); + + if(s->u_endorser_step < 0){ + set_S_endorser_decr(out,S_e_decr_dec); + } + else{ + set_S_endorser_decr(out,S_e_decr_inc); + } + + if(s->u_endorser_bits == 24){ + set_S_endorser_lap24(out,S_e_lap_24bit); + } + else{ + set_S_endorser_lap24(out,S_e_lap_16bit); + } + + set_S_endorser_ctstep(out,abs(s->u_endorser_step)); + set_S_endorser_ulx(out,0); + set_S_endorser_uly(out,s->u_endorser_y); + + switch (s->u_endorser_font) { + case FONT_H: + set_S_endorser_font(out,S_e_font_horiz); + set_S_endorser_bold(out,0); + break; + case FONT_HB: + set_S_endorser_font(out,S_e_font_horiz); + set_S_endorser_bold(out,1); + break; + case FONT_HN: + set_S_endorser_font(out,S_e_font_horiz_narrow); + set_S_endorser_bold(out,0); + break; + case FONT_V: + set_S_endorser_font(out,S_e_font_vert); + set_S_endorser_bold(out,0); + break; + case FONT_VB: + set_S_endorser_font(out,S_e_font_vert); + set_S_endorser_bold(out,1); + break; + } + + set_S_endorser_size(out,0); + set_S_endorser_revs(out,0); + + if(s->u_endorser_dir == DIR_BTT){ + set_S_endorser_dirs(out,S_e_dir_bottom_top); + } + else{ + set_S_endorser_dirs(out,S_e_dir_top_bottom); + } + + set_S_endorser_string_length(out, strLen); + set_S_endorser_string(out, s->u_endorser_string, strLen); + + /*build the command*/ + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SEND_code); + set_S_xfer_datatype (cmd, S_datatype_endorser_data); + set_S_xfer_length (cmd, outLen); + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); + + DBG (10, "send_endorser: finish %d\n", ret); + + return ret; +} + /* instead of internal brightness/contrast/gamma most scanners use a 256x256 or 1024x256 LUT default is linear table of slope 1 or 1/4 resp. @@ -3861,9 +4318,6 @@ send_lut (struct fujitsu *s) p++; } - hexdump(15,"LUT:",send_lutC+S_lut_data_offset,bytes); - - DBG (10,"send_lut: skipping\n"); ret = do_cmd ( s, 1, 0, sendB.cmd, sendB.size, @@ -4010,13 +4464,19 @@ mode_select_dropout (struct fujitsu *s) static SANE_Status mode_select_buff (struct fujitsu *s) { - int ret; + SANE_Status ret = SANE_STATUS_GOOD; DBG (10, "mode_select_buff: start\n"); + if (!s->has_MS_buff){ + DBG (10, "mode_select_buff: unsupported\n"); + return SANE_STATUS_GOOD; + } + set_MSEL_xfer_length (mode_selectB.cmd, mode_select_8byteB.size); set_MSEL_pc(mode_select_8byteB.cmd, MS_pc_buff); set_MSEL_buff_mode(mode_select_8byteB.cmd, s->buff_mode); + set_MSEL_buff_clear(mode_select_8byteB.cmd, 3); ret = do_cmd ( s, 1, 0, @@ -4234,7 +4694,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) if( ((s->params.depth == 1 || s->params.format == SANE_FRAME_JPEG) && s->params.pixels_per_line % 8) - || (s->even_scan_line && s->params.bytes_per_line % 2) + || (s->even_scan_line && s->params.bytes_per_line % 8) ){ /* dont round up larger than current max width */ @@ -4289,79 +4749,6 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) return ret; } -#if 0 -/* - * This routine issues a SCSI GET WINDOW command to the scanner - */ -static SANE_Status -get_window (struct fujitsu *s) -{ - unsigned char buffer[max_WDB_size]; - size_t bufferLen; - SANE_Status ret = SANE_STATUS_GOOD; - - DBG (10, "get_window: start\n"); - - /* The command specifies the number of bytes in the data phase - * the data phase has a header, followed by 1 or 2 window desc blocks - * the header specifies the number of bytes in 1 window desc block - */ - - bufferLen = max_WDB_size; - - /* cmd has data phase byte count */ - set_GW_xferlen(get_windowB.cmd,bufferLen); - - ret = do_cmd ( - s, 1, 0, - get_windowB.cmd, get_windowB.size, - NULL, 0, - buffer, &bufferLen - ); - - hexdump(10, "GW: <<", buffer, bufferLen); - - DBG (10, "get_window: finish\n"); - - return ret; -} - -static SANE_Status -get_pixelsize(struct fujitsu *s, int * x, int * y, int * px, int * py) -{ - SANE_Status ret; - unsigned char buf[0x18]; - size_t inLen = sizeof(buf); - - DBG (10, "get_pixelsize: start\n"); - - set_R_datatype_code (readB.cmd, R_datatype_pixelsize); - set_R_window_id (readB.cmd, WD_wid_front); - if(s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK){ - set_R_window_id (readB.cmd, WD_wid_back); - } - set_R_xfer_length (readB.cmd, inLen); - - ret = do_cmd ( - s, 1, 0, - readB.cmd, readB.size, - NULL, 0, - buf, &inLen - ); - - if(ret == SANE_STATUS_GOOD){ - *x = get_PSIZE_num_x(buf); - *y = get_PSIZE_num_y(buf); - *px = get_PSIZE_paper_w(buf); - *py = get_PSIZE_paper_l(buf); - DBG (15, "get_pixelsize: x=%d, y=%d, px=%d, py=%d\n", *x, *y, *px, *py); - } - - DBG (10, "get_pixelsize: finish\n"); - return ret; -} -#endif - /* * Called by SANE when a page acquisition operation is to be started. * commands: scanner control (lampon), send (lut), send (dither), @@ -4440,6 +4827,13 @@ sane_start (SANE_Handle handle) return ret; } + /* start/stop endorser */ + ret = endorser(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot start/stop endorser\n"); + return ret; + } + /* turn lamp on */ ret = scanner_control(s, SC_function_lamp_on); if (ret != SANE_STATUS_GOOD) { @@ -4503,6 +4897,65 @@ sane_start (SANE_Handle handle) return ret; } +static SANE_Status +endorser(struct fujitsu *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + DBG (10, "endorser: start\n"); + + if (s->has_endorser) { + + if(s->u_endorser_bits == 24){ + set_E_xfer_length(endorserB.cmd,6); + + set_ED_endorser_data_id(endorser_desc6B.cmd,0); + if(s->u_endorser){ + set_ED_stop(endorser_desc6B.cmd,ED_start); + } + else{ + set_ED_stop(endorser_desc6B.cmd,ED_stop); + } + set_ED_side(endorser_desc6B.cmd,ED_back); + set_ED_lap24(endorser_desc6B.cmd,ED_lap_24bit); + set_ED_initial_count_24(endorser_desc6B.cmd,s->u_endorser_val); + + ret = do_cmd ( + s, 1, 0, + endorserB.cmd, endorserB.size, + endorser_desc6B.cmd, endorser_desc6B.size, + NULL, NULL + ); + } + + else{ + set_E_xfer_length(endorserB.cmd,4); + + set_ED_endorser_data_id(endorser_desc4B.cmd,0); + if(s->u_endorser){ + set_ED_stop(endorser_desc4B.cmd,ED_start); + } + else{ + set_ED_stop(endorser_desc4B.cmd,ED_stop); + } + set_ED_side(endorser_desc4B.cmd,ED_back); + set_ED_lap24(endorser_desc4B.cmd,ED_lap_16bit); + set_ED_initial_count_16(endorser_desc4B.cmd,s->u_endorser_val); + + ret = do_cmd ( + s, 1, 0, + endorserB.cmd, endorserB.size, + endorser_desc4B.cmd, endorser_desc4B.size, + NULL, NULL + ); + } + } + + DBG (10, "endorser: finish %d\n", ret); + + return ret; +} + static SANE_Status scanner_control (struct fujitsu *s, int function) { @@ -4647,39 +5100,53 @@ setup_buffers (struct fujitsu *s) static SANE_Status set_window (struct fujitsu *s) { - unsigned char buffer[max_WDB_size]; - int bufferLen; - int length = s->br_y - s->tl_y; SANE_Status ret = SANE_STATUS_GOOD; - DBG (10, "set_window: start\n"); - /* The command specifies the number of bytes in the data phase * the data phase has a header, followed by 1 or 2 window desc blocks * the header specifies the number of bytes in 1 window desc block */ + unsigned char cmd[SET_WINDOW_len]; + size_t cmdLen = SET_WINDOW_len; + + /*this is max size, we might send less below*/ + unsigned char out[SW_header_len + SW_desc_len + SW_desc_len]; + size_t outLen = SW_header_len + SW_desc_len + SW_desc_len; + + unsigned char * header = out; /*header*/ + unsigned char * desc1 = out + SW_header_len; /*1st desc*/ + unsigned char * desc2 = out + SW_header_len + SW_desc_len; /*2nd desc*/ + + int length = s->br_y - s->tl_y; + + DBG (10, "set_window: start\n"); + + /* actual output length shorter if not using duplex */ + if (s->source != SOURCE_ADF_DUPLEX) { + outLen -= SW_desc_len; + } + + /*build the payload*/ + memset(out,0,outLen); + /* set window desc size in header */ - set_WPDB_wdblen(window_descriptor_headerB.cmd, window_descriptor_blockB.size); - - /* copy header into local buffer */ - memcpy(buffer, window_descriptor_headerB.cmd, window_descriptor_headerB.size); - bufferLen = window_descriptor_headerB.size; - - if (s->source == SOURCE_ADF_BACK) { - set_WD_wid (window_descriptor_blockB.cmd, WD_wid_back); - } - else{ - set_WD_wid (window_descriptor_blockB.cmd, WD_wid_front); - } + set_WPDB_wdblen(header, SW_desc_len); /* init the window block */ - set_WD_Xres (window_descriptor_blockB.cmd, s->resolution_x); - set_WD_Yres (window_descriptor_blockB.cmd, s->resolution_y); + if (s->source == SOURCE_ADF_BACK) { + set_WD_wid (desc1, WD_wid_back); + } + else{ + set_WD_wid (desc1, WD_wid_front); + } - set_WD_ULX (window_descriptor_blockB.cmd, s->tl_x); - set_WD_ULY (window_descriptor_blockB.cmd, s->tl_y); - set_WD_width (window_descriptor_blockB.cmd, s->br_x - s->tl_x); + set_WD_Xres (desc1, s->resolution_x); + set_WD_Yres (desc1, s->resolution_y); + + set_WD_ULX (desc1, s->tl_x); + set_WD_ULY (desc1, s->tl_y); + set_WD_width (desc1, s->br_x - s->tl_x); /* stupid trick. 3091/2 require reading extra lines, * because they have a gap between R G and B */ @@ -4687,39 +5154,36 @@ set_window (struct fujitsu *s) length += (s->color_raster_offset+s->green_offset) * 1200/300 * 2; DBG(5,"set_window: Increasing length to %d\n",length); } - set_WD_length (window_descriptor_blockB.cmd, length); + set_WD_length (desc1, length); - set_WD_brightness (window_descriptor_blockB.cmd, 0); + set_WD_brightness (desc1, 0); if(s->brightness_steps){ /*convert our common -127 to +127 range into HW's range *FIXME: this code assumes hardware range of 0-255 */ - - set_WD_brightness (window_descriptor_blockB.cmd, s->brightness+128); + set_WD_brightness (desc1, s->brightness+128); } - set_WD_threshold (window_descriptor_blockB.cmd, s->threshold); + set_WD_threshold (desc1, s->threshold); - set_WD_contrast (window_descriptor_blockB.cmd, 0); + set_WD_contrast (desc1, 0); if(s->contrast_steps){ /*convert our common -127 to +127 range into HW's range *FIXME: this code assumes hardware range of 0-255 */ - - set_WD_contrast (window_descriptor_blockB.cmd, s->contrast+128); + set_WD_contrast (desc1, s->contrast+128); } - set_WD_composition (window_descriptor_blockB.cmd, s->mode); + set_WD_composition (desc1, s->mode); - set_WD_bitsperpixel (window_descriptor_blockB.cmd, s->params.depth); + set_WD_bitsperpixel (desc1, s->params.depth); - set_WD_rif (window_descriptor_blockB.cmd, s->rif); - - set_WD_compress_type(window_descriptor_blockB.cmd, COMP_NONE); - set_WD_compress_arg(window_descriptor_blockB.cmd, 0); + set_WD_rif (desc1, s->rif); + set_WD_compress_type(desc1, COMP_NONE); + set_WD_compress_arg(desc1, 0); /* some scanners support jpeg image compression, for color/gs only */ if(s->params.format == SANE_FRAME_JPEG){ - set_WD_compress_type(window_descriptor_blockB.cmd, COMP_JPEG); - set_WD_compress_arg(window_descriptor_blockB.cmd, s->compress_arg); + set_WD_compress_type(desc1, COMP_JPEG); + set_WD_compress_arg(desc1, s->compress_arg); } /*the remainder of the block varies based on model and mode, @@ -4727,24 +5191,21 @@ set_window (struct fujitsu *s) /*vuid c0*/ if(s->has_vuid_3091){ - set_WD_vendor_id_code (window_descriptor_blockB.cmd, WD_VUID_3091); + set_WD_vendor_id_code (desc1, WD_VUID_3091); - if (s->mode == MODE_COLOR){ - set_WD_lamp_color (window_descriptor_blockB.cmd, 0); - } - else{ + if (s->mode != MODE_COLOR){ switch (s->dropout_color) { case COLOR_RED: - set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_RED); + set_WD_lamp_color (desc1, WD_LAMP_RED); break; case COLOR_GREEN: - set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_GREEN); + set_WD_lamp_color (desc1, WD_LAMP_GREEN); break; case COLOR_BLUE: - set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_BLUE); + set_WD_lamp_color (desc1, WD_LAMP_BLUE); break; default: - set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_DEFAULT); + set_WD_lamp_color (desc1, WD_LAMP_DEFAULT); break; } } @@ -4752,35 +5213,29 @@ set_window (struct fujitsu *s) /*vuid c1*/ else if(s->mode == MODE_COLOR && s->has_vuid_color){ - set_WD_vendor_id_code (window_descriptor_blockB.cmd, WD_VUID_COLOR); + set_WD_vendor_id_code (desc1, WD_VUID_COLOR); if(s->color_interlace == COLOR_INTERLACE_RGB){ - set_WD_scanning_order (window_descriptor_blockB.cmd, WD_SCAN_ORDER_DOT); - set_WD_scanning_order_arg (window_descriptor_blockB.cmd, WD_SCAN_ARG_RGB); + set_WD_scanning_order (desc1, WD_SCAN_ORDER_DOT); + set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_RGB); } else if(s->color_interlace == COLOR_INTERLACE_BGR){ - set_WD_scanning_order (window_descriptor_blockB.cmd, WD_SCAN_ORDER_DOT); - set_WD_scanning_order_arg (window_descriptor_blockB.cmd, WD_SCAN_ARG_BGR); + set_WD_scanning_order (desc1, WD_SCAN_ORDER_DOT); + set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_BGR); } else if(s->color_interlace == COLOR_INTERLACE_RRGGBB){ - set_WD_scanning_order (window_descriptor_blockB.cmd, WD_SCAN_ORDER_LINE); - set_WD_scanning_order_arg (window_descriptor_blockB.cmd, WD_SCAN_ARG_RGB); + set_WD_scanning_order (desc1, WD_SCAN_ORDER_LINE); + set_WD_scanning_order_arg (desc1, WD_SCAN_ARG_RGB); } else{ DBG (5,"set_window: unknown color interlacing\n"); return SANE_STATUS_INVAL; } - - /* just in case? */ - set_WD_lamp_color (window_descriptor_blockB.cmd, 0); } /*vuid 00*/ else if(s->has_vuid_mono){ - set_WD_vendor_id_code (window_descriptor_blockB.cmd, WD_VUID_MONO); - - /* just in case? */ - set_WD_lamp_color (window_descriptor_blockB.cmd, 0); + set_WD_vendor_id_code (desc1, WD_VUID_MONO); } else{ @@ -4788,47 +5243,42 @@ set_window (struct fujitsu *s) return SANE_STATUS_INVAL; } - set_WD_gamma (window_descriptor_blockB.cmd, s->window_gamma); + set_WD_gamma (desc1, s->window_gamma); if(s->source == SOURCE_FLATBED){ - set_WD_paper_selection(window_descriptor_blockB.cmd,WD_paper_SEL_UNDEFINED); + set_WD_paper_selection(desc1,WD_paper_SEL_UNDEFINED); } else{ - set_WD_paper_selection (window_descriptor_blockB.cmd, WD_paper_SEL_NON_STANDARD); + set_WD_paper_selection (desc1, WD_paper_SEL_NON_STANDARD); /* call helper function, scanner wants lies about paper width */ - set_WD_paper_width_X (window_descriptor_blockB.cmd, get_page_width(s)); + set_WD_paper_width_X (desc1, get_page_width(s)); /* dont call helper function, scanner wants actual length? */ - set_WD_paper_length_Y (window_descriptor_blockB.cmd, s->page_height); + set_WD_paper_length_Y (desc1, s->page_height); } - /* copy first desc block into local buffer */ - memcpy (buffer + bufferLen, window_descriptor_blockB.cmd, window_descriptor_blockB.size); - bufferLen += window_descriptor_blockB.size; - - /* when in duplex mode, add a second window */ + /* when in duplex mode, copy first desc block into second */ if (s->source == SOURCE_ADF_DUPLEX) { + memcpy (desc2, desc1, SW_desc_len); - set_WD_wid (window_descriptor_blockB.cmd, WD_wid_back); + set_WD_wid (desc2, WD_wid_back); /* FIXME: do we really need these on back of page? */ - set_WD_paper_selection (window_descriptor_blockB.cmd, WD_paper_SEL_UNDEFINED); - set_WD_paper_width_X (window_descriptor_blockB.cmd, 0); - set_WD_paper_length_Y (window_descriptor_blockB.cmd, 0); - - /* copy second desc block into local buffer */ - memcpy (buffer + bufferLen, window_descriptor_blockB.cmd, window_descriptor_blockB.size); - bufferLen += window_descriptor_blockB.size; + set_WD_paper_selection (desc2, WD_paper_SEL_UNDEFINED); + set_WD_paper_width_X (desc2, 0); + set_WD_paper_length_Y (desc2, 0); } - /* cmd has data phase byte count */ - set_SW_xferlen(set_windowB.cmd,bufferLen); + /*build the command*/ + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_WINDOW_code); + set_SW_xferlen(cmd, outLen); ret = do_cmd ( s, 1, 0, - set_windowB.cmd, set_windowB.size, - buffer, bufferLen, + cmd, cmdLen, + out, outLen, NULL, NULL ); @@ -5706,6 +6156,8 @@ sane_close (SANE_Handle handle) struct fujitsu * s = (struct fujitsu *) handle; DBG (10, "sane_close: start\n"); + /*clears any held scans*/ + mode_select_buff(s); disconnect_fd(s); DBG (10, "sane_close: finish\n"); } @@ -5870,7 +6322,7 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg) return SANE_STATUS_DEVICE_BUSY; } if (0x14 == ascq) { - DBG (5, "Medium error: imprinter error\n"); + DBG (5, "Medium error: endorser error\n"); return SANE_STATUS_IO_ERROR; } DBG (5, "Medium error: unknown ascq\n"); @@ -5915,7 +6367,7 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg) return SANE_STATUS_IO_ERROR; } if ((0x80 == asc) && (0x10 == ascq)) { - DBG (5, "Hardware error: imprinter error\n"); + DBG (5, "Hardware error: endorser error\n"); return SANE_STATUS_IO_ERROR; } DBG (5, "Hardware error: unknown asc/ascq\n"); diff --git a/backend/fujitsu.h b/backend/fujitsu.h index 899815707..00cd9fde6 100644 --- a/backend/fujitsu.h +++ b/backend/fujitsu.h @@ -52,6 +52,16 @@ enum fujitsu_Option OPT_BLUE_OFFSET, OPT_USE_SWAPFILE, + OPT_ENDORSER_GROUP, + OPT_ENDORSER, + OPT_ENDORSER_BITS, + OPT_ENDORSER_VAL, + OPT_ENDORSER_STEP, + OPT_ENDORSER_Y, + OPT_ENDORSER_FONT, + OPT_ENDORSER_DIR, + OPT_ENDORSER_STRING, + OPT_SENSOR_GROUP, OPT_TOP, OPT_A3, @@ -149,7 +159,7 @@ struct fujitsu /* members in order found in scsi data... */ int has_operator_panel; int has_barcode; - int has_imprinter; + int has_endorser; int has_duplex; int has_transparency; int has_flatbed; @@ -224,7 +234,8 @@ struct fujitsu int has_comp_JPG2; int has_comp_JPG3; - /*FIXME: endorser data? */ + /*FIXME: more endorser data? */ + int endorser_type; /*FIXME: barcode data? */ @@ -264,6 +275,7 @@ struct fujitsu int even_scan_line; /* need even number of bytes in a scanline (fi-5900) */ int ghs_in_rs; int window_gamma; + int endorser_string_len; int has_vuid_mono; /* mono set window data */ int has_vuid_3091; /* 3091/2 set window data */ @@ -329,6 +341,14 @@ struct fujitsu SANE_Range green_offset_range; SANE_Range blue_offset_range; + /*endorser group*/ + SANE_Range endorser_bits_range; + SANE_Range endorser_val_range; + SANE_Range endorser_step_range; + SANE_Range endorser_y_range; + SANE_String_Const endorser_font_list[6]; + SANE_String_Const endorser_dir_list[3]; + /* --------------------------------------------------------------------- */ /* changeable vars to hold user input. modified by SANE_Options above */ @@ -371,6 +391,16 @@ struct fujitsu int blue_offset; int use_temp_file; + /*endorser group*/ + int u_endorser; + int u_endorser_bits; + int u_endorser_val; + int u_endorser_step; + int u_endorser_y; + int u_endorser_font; + int u_endorser_dir; + char u_endorser_string[81]; /*max length, plus null byte*/ + /* --------------------------------------------------------------------- */ /* values which are derived from setting the options above */ /* the user never directly modifies these */ @@ -502,6 +532,20 @@ struct fujitsu #define DF_LENGTH 3 #define DF_BOTH 4 +#define FONT_H 0 +#define FONT_HB 1 +#define FONT_HN 2 +#define FONT_V 3 +#define FONT_VB 4 + +#define DIR_TTB 0 +#define DIR_BTT 1 + +/* endorser type, same as scsi inquiry data */ +#define ET_OLD 0 +#define ET_30 1 +#define ET_40 2 + /* ------------------------------------------------------------------------- */ #define MM_PER_INCH 25.4 @@ -624,6 +668,8 @@ int get_page_width (struct fujitsu *s); int get_page_height (struct fujitsu *s); static SANE_Status send_lut (struct fujitsu *s); +static SANE_Status send_endorser (struct fujitsu *s); +static SANE_Status endorser (struct fujitsu *s); static SANE_Status set_window (struct fujitsu *s); /* diff --git a/doc/descriptions/fujitsu.desc b/doc/descriptions/fujitsu.desc index 00566e4ea..905505cbd 100644 --- a/doc/descriptions/fujitsu.desc +++ b/doc/descriptions/fujitsu.desc @@ -11,7 +11,7 @@ :backend "fujitsu" ; name of backend :url "http://www.thebility.com/fujitsu/" -:version "64" ; version of backend +:version "65" ; version of backend :manpage "sane-fujitsu" ; name of manpage (if it exists) :comment "Backend re-written for SANE release 1.0.18, see sane-fujitsu manpage" :devicetype :scanner ; start of a list of devices.... diff --git a/doc/sane-fujitsu.man b/doc/sane-fujitsu.man index 6ba12ece5..e19ec284f 100644 --- a/doc/sane-fujitsu.man +++ b/doc/sane-fujitsu.man @@ -1,4 +1,4 @@ -.TH sane-fujitsu 5 "2007-07-14" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.TH sane-fujitsu 5 "2008-06-24" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" .IX sane-fujitsu .SH NAME @@ -10,7 +10,7 @@ The library implements a SANE (Scanner Access Now Easy) backend which provides access to most Fujitsu flatbed and ADF scanners. -This document describes the rewritten backend versions 1.0.21 and greater. +This document describes the rewritten backend, version 21 and greater. The backend supports lineart, halftone, grayscale, and color scanning for most USB and SCSI scanners, depending on hardware capabilities. @@ -261,6 +261,18 @@ fi-4220C and basic USB support: Ron Cemer fi-4120, fi-series color support, backend re-write, current maintainer: m. allan noah: +JPEG output support funded by: + Archivista GmbH + www.archivista.ch + +Endorser support funded by: + O A S Oilfield Accounting Service Ltd + 1500, 840 - 7th Avenue S.W. + Calgary, Alberta + T2P 3G2 Canada + 1-403-263-2600 + www.oas.ca + .SH "SEE ALSO" sane(7), sane-scsi(5),