From 8b9df6bcbf897d08616f21dd97ecad4d337d56ae Mon Sep 17 00:00:00 2001 From: "m. allan noah" Date: Sat, 15 Jul 2006 01:17:33 +0000 Subject: [PATCH] update to backend v1.0.37 --- ChangeLog | 9 + backend/fujitsu-scsi.h | 194 ++++++--------- backend/fujitsu.c | 456 +++++++++++++++++++++++++++++----- backend/fujitsu.h | 25 +- doc/descriptions/fujitsu.desc | 4 +- 5 files changed, 487 insertions(+), 201 deletions(-) diff --git a/ChangeLog b/ChangeLog index 715e40767..966082333 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-07-14 m. allan noah + + * backend/fujitsu.[ch] backend/fujitsu-scsi.h: backend v1.0.37, + add support for mode sense command, use it to detect various + page codes instead of hardcoding. add support for send cmd, + use it to enable 8 or 10 bit LUT for brightness/contrast. + minor global variable and option description cleanups. + * doc/descriptions/fujitsu.desc: version number/status update + 2006-07-06 m. allan noah * backend/fujitsu.[ch]: backend v1.0.36, less verbose debugging, diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h index c3d924809..8f2873684 100644 --- a/backend/fujitsu-scsi.h +++ b/backend/fujitsu-scsi.h @@ -219,6 +219,7 @@ static scsiblk inquiryB = { inquiryC, sizeof (inquiryC) }; #define get_IN_buffer_bytes(in) getnbyte(in + 0x22, 4) /* more stuff here (std supported commands) */ +#define get_IN_has_cmd_msen(in) getbitfield(in+0x29, 1, 7) #define get_IN_has_subwindow(in) getbitfield(in+0x2b, 1, 0) #define get_IN_has_endorser(in) getbitfield(in+0x2b, 1, 1) @@ -299,19 +300,17 @@ static scsiblk object_positionB = static unsigned char sendC[] = {SEND, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static scsiblk sendB = - {sendC, sizeof (sendC)}; +static scsiblk sendB = {sendC, sizeof (sendC)}; - -#define set_S_datatype_code(sb, val) sb[0x02] = (unsigned char)val -#define S_datatype_imagedatai 0x00 +#define set_S_xfer_datatype(sb, val) sb[0x02] = (unsigned char)val +/*#define S_datatype_imagedatai 0x00 #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_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 /* Experiment code */ -#define S_EX_datatype_shading_data 0xa0 /* Experiment code */ +#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 #define set_S_datatype_qual_upper(sb, val) sb[0x04] = (unsigned char)val @@ -321,8 +320,16 @@ static scsiblk sendB = #define S_DQ_Bcomp 0x08 #define S_DQ_Reg1 0x01 #define S_DQ_Reg2 0x02 -#define S_DQ_Reg3 0x03 -#define set_S_xfer_length(sb, val) putnbyte(sb + 0x06, val, 3) +#define S_DQ_Reg3 0x03*/ +#define set_S_xfer_id(sb, val) putnbyte(sb + 4, val, 2) +#define set_S_xfer_length(sb, val) putnbyte(sb + 6, val, 3) + +static unsigned char send_lutC[1034]; +#define set_S_lut_order(sb, val) putnbyte(sb + 2, val, 1) +#define S_lut_order_single 0x10 +#define set_S_lut_ssize(sb, val) putnbyte(sb + 4, val, 2) +#define set_S_lut_dsize(sb, val) putnbyte(sb + 6, val, 2) +#define S_lut_data_offset 0x0a /* static unsigned char send_imprinterC[] = @@ -331,44 +338,28 @@ static unsigned char send_imprinterC[] = 0x00, 0x00}; static scsiblk send_imprinterB = {send_imprinterC, sizeof(send_imprinterC)}; -*/ -/* imprinter counter - * 0 = increase counter - * 1 = decrease counter - */ #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 -/* counter value - * 1 = 24 bit - * 0 = 16 bit - */ #define set_imprinter_lap24(sb, val) setbitfield(sb + 0x01, 1, 4, val) #define S_im_ctr_24bit 1 #define S_im_ctr_16bit 0 -/* stepping of the imprinter counter - * 0..2 allowed - */ #define set_imprinter_cstep(sb, val) setbitfield(sb + 0x01, 0x03, 0, val) #define set_imprinter_uly(sb, val) putnbyte(sb + 0x06, val, 4) - -/* specifies the way of printing direction of the strings. - */ #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 +*/ /* - 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) - }; - */ +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) }; +*/ /* ==================================================================== */ /* @@ -416,76 +407,70 @@ static scsiblk readB = { readC, sizeof (readC) }; /* ==================================================================== */ +/* page codes used by mode_sense and mode_select */ +#define MS_pc_prepick 0x33 /* Prepick next adf page */ +#define MS_pc_sleep 0x34 /* Sleep mode */ +#define MS_pc_duplex 0x35 /* ADF duplex transfer mode */ +#define MS_pc_rand 0x36 /* All sorts of device controls */ +#define MS_pc_bg 0x37 /* Backing switch control */ +#define MS_pc_df 0x38 /* Double feed detection */ +#define MS_pc_dropout 0x39 /* Drop out color */ +#define MS_pc_buff 0x3a /* Scan buffer control */ +#define MS_pc_auto 0x3c /* Auto paper size detection */ +#define MS_pc_lamp 0x3d /* Lamp light timer set */ +#define MS_pc_jobsep 0x3e /* Detect job separation sheet */ +#define MS_pc_all 0x3f /* Only used with mode_sense */ + +/* ==================================================================== */ + +static unsigned char mode_senseC[] = + { MODE_SENSE, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static scsiblk mode_senseB = { mode_senseC, sizeof (mode_senseC) }; +#define set_MSEN_DBD(b, val) setbitfield(b, 0x01, 3, (val?1:0)) +#define set_MSEN_pc(sb, val) setbitfield(sb + 0x02, 0x3f, 0, val) +#define set_MSEN_xfer_length(sb, val) sb[0x04] = (unsigned char)val +#define get_MSEN_MUD(b) getnbyte(b+(0x04+((int)*(b+0x3)))+0x4,2) + +/* ==================================================================== */ + static unsigned char mode_selectC[] = { MODE_SELECT, 0x10, 0x00, 0x00, 0x00, 0x00 }; static scsiblk mode_selectB = { mode_selectC, sizeof (mode_selectC) }; #define set_MSEL_xfer_length(sb, val) sb[0x04] = (unsigned char)val -/* combined 4 byte header and 8 byte page - * PageCodes: (most scanners know a few of these) - * 0x34 = Sleep mode - * 0x35 = ADF duplex reading transfer mode - * 0x36 = All sorts of device controls switching - * 0x37 = Backing switch control - * 0x38 = Double feed detection - * 0x39 = Drop out color - * 0x3c = Auto paper size detection - * 0x3d = Lamp light timer set - * 0x3e = Detect job separation sheet - * there is also a 'descriptor block' - * and a 'vendor-specific block' - * but fujitsu seems not to use these - */ +/* following are combined 4 byte header and 8 or 10 byte page + * there is also 'descriptor block' & 'vendor-specific block' + * but fujitsu seems not to use these */ -static unsigned char mode_select_sleepC[] = { +/* 8 byte page only used by all pages except dropout? */ +static unsigned char mode_select_8byteC[] = { 0x00, 0x00, 0x00, 0x00, - 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static scsiblk mode_select_sleepB = { - mode_select_sleepC, sizeof (mode_select_sleepC) +static scsiblk mode_select_8byteB = { + mode_select_8byteC, sizeof (mode_select_8byteC) }; + +/* 10 byte page only used by dropout? */ +static unsigned char mode_select_10byteC[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static scsiblk mode_select_10byteB = { + mode_select_10byteC, sizeof (mode_select_10byteC) +}; + +#define set_MSEL_pc(sb, val) sb[0x04]=val + #define set_MSEL_sleep_mode(sb, val) sb[0x06]=val -/* -static unsigned char mode_select_duplexC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x35, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_duplexB = { - mode_select_duplexC, sizeof (mode_select_duplexC) -}; #define set_MSEL_transfer_mode(sb, val) setbitfield(sb + 0x02, 0x01, 0, val) -*/ -/* -static unsigned char mode_select_randC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x36, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_randB = { - mode_select_randC, sizeof (mode_select_randC) -}; -*/ - -static unsigned char mode_select_bgC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x37, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_bgB = { - mode_select_bgC, sizeof (mode_select_bgC) -}; #define set_MSEL_bg_enable(sb, val) setbitfield(sb + 6, 1, 7, val) #define set_MSEL_bg_front(sb, val) setbitfield(sb + 6, 1, 5, val) #define set_MSEL_bg_back(sb, val) setbitfield(sb + 6, 1, 4, val) #define set_MSEL_bg_fb(sb, val) setbitfield(sb + 6, 1, 3, val) -static unsigned char mode_select_dfC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_dfB = { - mode_select_dfC, sizeof (mode_select_dfC) -}; #define set_MSEL_df_enable(sb, val) setbitfield(sb + 6, 1, 7, val) #define set_MSEL_df_continue(sb, val) setbitfield(sb + 6, 1, 6, val) #define set_MSEL_df_thickness(sb, val) setbitfield(sb + 6, 1, 4, val) @@ -496,13 +481,6 @@ static scsiblk mode_select_dfB = { #define MSEL_df_diff_15MM 2 #define MSEL_df_diff_20MM 3 -static unsigned char mode_select_dropoutC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x39, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_dropoutB = { - mode_select_dropoutC, sizeof (mode_select_dropoutC) -}; #define set_MSEL_dropout_front(sb, val) setbitfield(sb + 0x06, 0x0f, 0, val) #define set_MSEL_dropout_back(sb, val) setbitfield(sb + 0x06, 0x0f, 4, val) #define MSEL_dropout_DEFAULT 0 @@ -511,38 +489,6 @@ static scsiblk mode_select_dropoutB = { #define MSEL_dropout_BLUE 11 #define MSEL_dropout_CUSTOM 12 -/* -static unsigned char mode_select_autoC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_autoB = { - mode_select_autoC, sizeof (mode_select_autoC) -}; -*/ - -/* -static unsigned char mode_select_lampC[] = { - 0x00, 0x00, 0x00, 0x00, - 0x3D, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static scsiblk mode_select_lampB= { - mode_select_lampC, sizeof (mode_select_lampC) -}; -*/ - -/* ==================================================================== */ -#if 0 -/* currently not used */ -static unsigned char mode_senseC[] = - { MODE_SENSE, 0x18, 0x03, 0x00, 0x00, 0x00, /* PF set, page type 03 */ }; -static scsiblk mode_senseB = { mode_senseC, sizeof (mode_senseC) }; - -#define set_MS_DBD(b, val) setbitfield(b, 0x01, 3, (val?1:0)) -#define set_MS_len(b, val) putnbyte(b+0x04, val, 1) -#define get_MS_MUD(b) getnbyte(b+(0x04+((int)*(b+0x3)))+0x4,2) -#endif - /* ==================================================================== */ static unsigned char scanC[] = { SCAN, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/backend/fujitsu.c b/backend/fujitsu.c index 295aabe22..9031bd769 100644 --- a/backend/fujitsu.c +++ b/backend/fujitsu.c @@ -208,6 +208,12 @@ V 1.0.36 2006-07-06, MAN - deal with fi-5900 even bytes problem - less verbose calculateDerivedValues() + V 1.0.37 2006-07-14, MAN + - mode sense command support + - detect mode page codes instead of hardcoding + - send command support + - brightness/contrast support via LUT + - merge global mode page buffers SANE FLOW DIAGRAM @@ -250,6 +256,7 @@ #include #include #include +#include #include #include @@ -267,7 +274,7 @@ #include "fujitsu.h" #define DEBUG 1 -#define BUILD 36 +#define BUILD 37 /* values for SANE_DEBUG_FUJITSU env var: - errors 5 @@ -622,6 +629,16 @@ attach_one (const char *device_name, int connType) return ret; } + /* see what mode pages device supports */ + ret = init_ms (s); + if (ret != SANE_STATUS_GOOD) { + disconnect_fd(s); + free (s->device_name); + free (s); + DBG (5, "attach_one: ms failed\n"); + return ret; + } + /* clean up the scanner struct based on model */ /* this is the only piece of model specific code */ /* sets SANE option 'values' to good defaults */ @@ -954,6 +971,10 @@ init_vpd (struct fujitsu *s) s->buffer_bytes = get_IN_buffer_bytes(buffer); DBG (15, " buffer bytes: %d\n",s->buffer_bytes); + /* std scsi command support */ + s->has_cmd_msen = get_IN_has_cmd_msen(buffer); + DBG (15, " mode_sense cmd: %d\n", s->has_cmd_msen); + /* vendor added scsi command support */ /* FIXME: there are more of these... */ s->has_cmd_subwindow = get_IN_has_subwindow(buffer); @@ -1077,6 +1098,180 @@ init_vpd (struct fujitsu *s) return ret; } +static SANE_Status +init_ms(struct fujitsu *s) +{ + int ret; + unsigned char buff[64]; + + DBG (10, "init_ms: start\n"); + + if(!s->has_cmd_msen){ + DBG (10, "init_ms: unsupported\n"); + return SANE_STATUS_GOOD; + } + + set_MSEN_xfer_length (mode_senseB.cmd, 64); + + /* prepick */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_prepick); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_prepick=1; + } + DBG (15, " prepick: %d\n", s->has_MS_prepick); + + /* sleep */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_sleep); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_sleep=1; + } + DBG (15, " sleep: %d\n", s->has_MS_sleep); + + /* duplex */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_duplex); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_duplex=1; + } + DBG (15, " duplex: %d\n", s->has_MS_duplex); + + /* rand */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_rand); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_rand=1; + } + DBG (15, " rand: %d\n", s->has_MS_rand); + + /* bg */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_bg); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_bg=1; + } + DBG (15, " bg: %d\n", s->has_MS_bg); + + /* df */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_df); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_df=1; + } + DBG (15, " df: %d\n", s->has_MS_df); + + /* dropout */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_dropout); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_dropout=1; + } + DBG (15, " dropout: %d\n", s->has_MS_dropout); + + /* buff */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_buff); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_buff=1; + } + DBG (15, " buff: %d\n", s->has_MS_buff); + + /* auto */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_auto); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_auto=1; + } + DBG (15, " auto: %d\n", s->has_MS_auto); + + /* lamp */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_lamp); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_lamp=1; + } + DBG (15, " lamp: %d\n", s->has_MS_lamp); + + /* jobsep */ + set_MSEN_pc(mode_senseB.cmd, MS_pc_jobsep); + memset(buff,0,64); + ret = do_cmd ( + s, 1, 0, + mode_senseB.cmd, mode_senseB.size, + NULL, 0, + buff, 64 + ); + if(ret == SANE_STATUS_GOOD){ + s->has_MS_jobsep=1; + } + DBG (15, " jobsep: %d\n", s->has_MS_jobsep); + + DBG (10, "init_ms: finish\n"); + + return SANE_STATUS_GOOD; +} + /* * set model specific info and good default user values * in scanner struct. struct is already initialized to 0, @@ -1153,11 +1348,10 @@ init_model (struct fujitsu *s) s->color_interlace = COLOR_INTERLACE_3091; s->duplex_interlace = DUPLEX_INTERLACE_3091; s->even_scan_line = 0; - s->has_MS_df = 0; - s->has_MS_dropout = 0; s->has_SW_dropout = 1; s->window_vid = 0xc0; s->ghs_in_rs = 1; + s->lut_bits = 8; s->reverse_by_mode[MODE_LINEART] = 1; s->reverse_by_mode[MODE_HALFTONE] = 1; @@ -1173,11 +1367,10 @@ init_model (struct fujitsu *s) s->color_interlace = COLOR_INTERLACE_NONE; s->duplex_interlace = DUPLEX_INTERLACE_NONE; s->even_scan_line = 0; - s->has_MS_df = 0; - s->has_MS_dropout = 0; s->has_SW_dropout = 0; s->window_vid = 0; s->ghs_in_rs = 0; + s->lut_bits = 0; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; @@ -1193,11 +1386,10 @@ init_model (struct fujitsu *s) s->color_interlace = COLOR_INTERLACE_RRGGBB; s->duplex_interlace = DUPLEX_INTERLACE_NONE; s->even_scan_line = 0; - s->has_MS_df = 1; - s->has_MS_dropout = 1; s->has_SW_dropout = 0; s->window_vid = 0; s->ghs_in_rs = 0; + s->lut_bits = 10; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; @@ -1214,11 +1406,10 @@ init_model (struct fujitsu *s) s->color_interlace = COLOR_INTERLACE_BGR; s->duplex_interlace = DUPLEX_INTERLACE_NONE; s->even_scan_line = 1; - s->has_MS_df = 1; - s->has_MS_dropout = 1; s->has_SW_dropout = 0; s->window_vid = 0; s->ghs_in_rs = 0; + s->lut_bits = 10; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; @@ -1233,11 +1424,10 @@ init_model (struct fujitsu *s) s->color_interlace = COLOR_INTERLACE_BGR; s->duplex_interlace = DUPLEX_INTERLACE_NONE; s->even_scan_line = 0; - s->has_MS_df = 1; - s->has_MS_dropout = 1; s->has_SW_dropout = 0; s->window_vid = 0; s->ghs_in_rs = 0; + s->lut_bits = 10; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; @@ -1729,10 +1919,20 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; opt->constraint.range = &s->brightness_range; - s->brightness_range.min=0; - s->brightness_range.max=s->brightness_steps; s->brightness_range.quant=1; + + /* scanner has brightness built-in */ + /* value ranges from 0-255 (usually) */ if (s->brightness_steps){ + s->brightness_range.min=0; + s->brightness_range.max=s->brightness_steps; + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + /* scanner has brightness via LUT */ + /* value ranges from -127 to +127 */ + else if (s->lut_bits){ + s->brightness_range.min=-127; + s->brightness_range.max=127; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } else{ @@ -1769,12 +1969,22 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; opt->constraint.range = &s->contrast_range; - s->contrast_range.min=0; - s->contrast_range.max=s->contrast_steps; s->contrast_range.quant=1; + + /* scanner has contrast built-in */ + /* value ranges from 0-255 (usually) */ if (s->contrast_steps) { + s->contrast_range.min=0; + s->contrast_range.max=s->contrast_steps; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } + /* scanner has contrast via LUT */ + /* value ranges from -127 to +127 */ + else if (s->lut_bits){ + s->contrast_range.min=-127; + s->contrast_range.max=127; + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } else { opt->cap = SANE_CAP_INACTIVE; } @@ -1898,7 +2108,10 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; opt->constraint.range=&s->sleep_time_range; - opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + if(s->has_MS_sleep) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; } /*duplex offset*/ @@ -1944,7 +2157,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->blue_offset_range.quant = 1; opt->name = "blueoffset"; - opt->title = "blue scan line offset from default"; + opt->title = "Blue offset"; opt->desc = "Adjust blue/red offset"; opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -2807,13 +3020,14 @@ set_sleep_mode(struct fujitsu *s) DBG (10, "set_sleep_mode: start\n"); - set_MSEL_xfer_length (mode_selectB.cmd, mode_select_sleepB.size); - set_MSEL_sleep_mode(mode_select_sleepB.cmd, s->sleep_time); + set_MSEL_xfer_length (mode_selectB.cmd, mode_select_8byteB.size); + set_MSEL_pc(mode_select_8byteB.cmd, MS_pc_sleep); + set_MSEL_sleep_mode(mode_select_8byteB.cmd, s->sleep_time); ret = do_cmd ( s, 1, 0, mode_selectB.cmd, mode_selectB.size, - mode_select_sleepB.cmd, mode_select_sleepB.size, + mode_select_8byteB.cmd, mode_select_8byteB.size, NULL, 0 ); @@ -2919,6 +3133,92 @@ get_hardware_status (struct fujitsu *s) 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. + brightness and contrast inputs are -127 to +127 + + contrast rotates slope of line around central input val + + high low + . x . + . x . xx + out . x . xxxxxxxx + . x xx + ....x....... ............ + input + + then brightness moves line vertically, and clamps to 8bit + + bright dark + . xxxxxxxx . + out . x . + x . x + . . x + ............ xxxxxxxx.... + input */ +static SANE_Status +send_lut (struct fujitsu *s) +{ + int i, j, ret, bytes = 1 << s->lut_bits; + unsigned char * p = send_lutC+S_lut_data_offset; + double b, cmax, coff; + + DBG (10, "send_lut: start\n"); + + /* contrast is converted to height in last col of table + * first from -127 to +127 to 0 to ~.996 + * then multiply by PI/2 to convert to radians + * then take the tangent and multiply by max input (255) */ + cmax = tan(((double)s->contrast+127)/255 * M_PI/2) * 255; + + /* contrast slope must stay centered, so figure + * out vertical offset at central input value (127.5)*/ + coff = 127.5-(cmax/2); + + /* convert the user brightness setting (-127 to +127) + * into a scale that covers the range required + * to slide the contrast curve entirely off the table */ + b = ((double)s->brightness/127) * (256 - coff); + + DBG (15, "send_lut: %d %f %d %f %f\n", s->brightness, b, s->contrast, cmax, coff); + + set_S_xfer_datatype (sendB.cmd, S_datatype_lut_data); + set_S_xfer_length (sendB.cmd, S_lut_data_offset+bytes); + + set_S_lut_order (send_lutC, S_lut_order_single); + set_S_lut_ssize (send_lutC, bytes); + set_S_lut_dsize (send_lutC, 256); + + for(i=0;i255){ + j=255; + } + + *p=j; + p++; + } + + hexdump(15,"LUT:",send_lutC+S_lut_data_offset,bytes); + + ret = do_cmd ( + s, 1, 0, + sendB.cmd, sendB.size, + send_lutC, S_lut_data_offset+bytes, + NULL, 0 + ); + + DBG (10, "send_lut: finish\n"); + + return ret; +} + static SANE_Status mode_select_df (struct fujitsu *s) { @@ -2926,53 +3226,54 @@ mode_select_df (struct fujitsu *s) DBG (10, "mode_select_df: start\n"); - set_MSEL_xfer_length (mode_selectB.cmd, mode_select_dfB.size); + set_MSEL_xfer_length (mode_selectB.cmd, mode_select_8byteB.size); + set_MSEL_pc(mode_select_8byteB.cmd, MS_pc_df); /* clear everything for defaults */ if(s->df_detect == DF_DEFAULT){ - set_MSEL_df_enable (mode_select_dfB.cmd, 0); - set_MSEL_df_continue (mode_select_dfB.cmd, 0); - set_MSEL_df_thickness (mode_select_dfB.cmd, 0); - set_MSEL_df_length (mode_select_dfB.cmd, 0); - set_MSEL_df_diff (mode_select_dfB.cmd, 0); + set_MSEL_df_enable (mode_select_8byteB.cmd, 0); + set_MSEL_df_continue (mode_select_8byteB.cmd, 0); + set_MSEL_df_thickness (mode_select_8byteB.cmd, 0); + set_MSEL_df_length (mode_select_8byteB.cmd, 0); + set_MSEL_df_diff (mode_select_8byteB.cmd, 0); } /* none, still have to enable */ else if(s->df_detect == DF_NONE){ - set_MSEL_df_enable (mode_select_dfB.cmd, 1); - set_MSEL_df_continue (mode_select_dfB.cmd, 1); - set_MSEL_df_thickness (mode_select_dfB.cmd, 0); - set_MSEL_df_length (mode_select_dfB.cmd, 0); - set_MSEL_df_diff (mode_select_dfB.cmd, 0); + set_MSEL_df_enable (mode_select_8byteB.cmd, 1); + set_MSEL_df_continue (mode_select_8byteB.cmd, 1); + set_MSEL_df_thickness (mode_select_8byteB.cmd, 0); + set_MSEL_df_length (mode_select_8byteB.cmd, 0); + set_MSEL_df_diff (mode_select_8byteB.cmd, 0); } /* thickness only */ else if(s->df_detect == DF_THICKNESS){ - set_MSEL_df_enable (mode_select_dfB.cmd, 1); - set_MSEL_df_continue (mode_select_dfB.cmd, 0); - set_MSEL_df_thickness (mode_select_dfB.cmd, 1); - set_MSEL_df_length (mode_select_dfB.cmd, 0); - set_MSEL_df_diff (mode_select_dfB.cmd, 0); + set_MSEL_df_enable (mode_select_8byteB.cmd, 1); + set_MSEL_df_continue (mode_select_8byteB.cmd, 0); + set_MSEL_df_thickness (mode_select_8byteB.cmd, 1); + set_MSEL_df_length (mode_select_8byteB.cmd, 0); + set_MSEL_df_diff (mode_select_8byteB.cmd, 0); } /* length only */ else if(s->df_detect == DF_LENGTH){ - set_MSEL_df_enable (mode_select_dfB.cmd, 1); - set_MSEL_df_continue (mode_select_dfB.cmd, 0); - set_MSEL_df_thickness (mode_select_dfB.cmd, 0); - set_MSEL_df_length (mode_select_dfB.cmd, 1); - set_MSEL_df_diff (mode_select_dfB.cmd, s->df_diff); + set_MSEL_df_enable (mode_select_8byteB.cmd, 1); + set_MSEL_df_continue (mode_select_8byteB.cmd, 0); + set_MSEL_df_thickness (mode_select_8byteB.cmd, 0); + set_MSEL_df_length (mode_select_8byteB.cmd, 1); + set_MSEL_df_diff (mode_select_8byteB.cmd, s->df_diff); } /* thickness and length */ else{ - set_MSEL_df_enable (mode_select_dfB.cmd, 1); - set_MSEL_df_continue (mode_select_dfB.cmd, 0); - set_MSEL_df_thickness (mode_select_dfB.cmd, 1); - set_MSEL_df_length (mode_select_dfB.cmd, 1); - set_MSEL_df_diff (mode_select_dfB.cmd, s->df_diff); + set_MSEL_df_enable (mode_select_8byteB.cmd, 1); + set_MSEL_df_continue (mode_select_8byteB.cmd, 0); + set_MSEL_df_thickness (mode_select_8byteB.cmd, 1); + set_MSEL_df_length (mode_select_8byteB.cmd, 1); + set_MSEL_df_diff (mode_select_8byteB.cmd, s->df_diff); } ret = do_cmd ( s, 1, 0, mode_selectB.cmd, mode_selectB.size, - mode_select_dfB.cmd, mode_select_dfB.size, + mode_select_8byteB.cmd, mode_select_8byteB.size, NULL, 0 ); @@ -2988,34 +3289,35 @@ mode_select_bg (struct fujitsu *s) DBG (10, "mode_select_bg: start\n"); - set_MSEL_xfer_length (mode_selectB.cmd, mode_select_bgB.size); + set_MSEL_xfer_length (mode_selectB.cmd, mode_select_8byteB.size); + set_MSEL_pc(mode_select_8byteB.cmd, MS_pc_bg); /* clear everything for defaults */ if(s->bg_color == COLOR_DEFAULT){ - set_MSEL_bg_enable (mode_select_bgB.cmd, 0); - set_MSEL_bg_front (mode_select_bgB.cmd, 0); - set_MSEL_bg_back (mode_select_bgB.cmd, 0); - set_MSEL_bg_fb (mode_select_bgB.cmd, 0); + set_MSEL_bg_enable (mode_select_8byteB.cmd, 0); + set_MSEL_bg_front (mode_select_8byteB.cmd, 0); + set_MSEL_bg_back (mode_select_8byteB.cmd, 0); + set_MSEL_bg_fb (mode_select_8byteB.cmd, 0); } else{ - set_MSEL_bg_enable (mode_select_bgB.cmd, 1); + set_MSEL_bg_enable (mode_select_8byteB.cmd, 1); if(s->bg_color == COLOR_BLACK){ - set_MSEL_bg_front (mode_select_bgB.cmd, 1); - set_MSEL_bg_back (mode_select_bgB.cmd, 1); - set_MSEL_bg_fb (mode_select_bgB.cmd, 1); + set_MSEL_bg_front (mode_select_8byteB.cmd, 1); + set_MSEL_bg_back (mode_select_8byteB.cmd, 1); + set_MSEL_bg_fb (mode_select_8byteB.cmd, 1); } else{ - set_MSEL_bg_front (mode_select_bgB.cmd, 0); - set_MSEL_bg_back (mode_select_bgB.cmd, 0); - set_MSEL_bg_fb (mode_select_bgB.cmd, 0); + set_MSEL_bg_front (mode_select_8byteB.cmd, 0); + set_MSEL_bg_back (mode_select_8byteB.cmd, 0); + set_MSEL_bg_fb (mode_select_8byteB.cmd, 0); } } ret = do_cmd ( s, 1, 0, mode_selectB.cmd, mode_selectB.size, - mode_select_bgB.cmd, mode_select_bgB.size, + mode_select_8byteB.cmd, mode_select_8byteB.size, NULL, 0 ); @@ -3031,14 +3333,15 @@ mode_select_dropout (struct fujitsu *s) DBG (10, "mode_select_dropout: start\n"); - set_MSEL_xfer_length (mode_selectB.cmd, mode_select_dropoutB.size); - set_MSEL_dropout_front (mode_select_dropoutB.cmd, s->dropout_color); - set_MSEL_dropout_back (mode_select_dropoutB.cmd, s->dropout_color); + set_MSEL_xfer_length (mode_selectB.cmd, mode_select_10byteB.size); + set_MSEL_pc(mode_select_10byteB.cmd, MS_pc_dropout); + set_MSEL_dropout_front (mode_select_10byteB.cmd, s->dropout_color); + set_MSEL_dropout_back (mode_select_10byteB.cmd, s->dropout_color); ret = do_cmd ( s, 1, 0, mode_selectB.cmd, mode_selectB.size, - mode_select_dropoutB.cmd, mode_select_dropoutB.size, + mode_select_10byteB.cmd, mode_select_10byteB.size, NULL, 0 ); @@ -3239,14 +3542,22 @@ sane_start (SANE_Handle handle) s->bytes_tx[1]=0; /* send batch setup commands */ - ret = scanner_control (s, SC_function_lamp_on); + ret = scanner_control(s, SC_function_lamp_on); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: cannot start lamp\n"); do_cancel(s); return ret; } - /*FIXME: send lut and dither ?*/ + /* send lut if scanner has no contrast option */ + if(!s->contrast_steps && s->lut_bits){ + ret = send_lut(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot send lut\n"); + do_cancel(s); + return ret; + } + } /* get the scan size, etc */ calculateDerivedValues(s); @@ -3534,9 +3845,18 @@ set_window (struct fujitsu *s) } set_WD_length (window_descriptor_blockB.cmd, length); - set_WD_brightness (window_descriptor_blockB.cmd, s->brightness); + set_WD_brightness (window_descriptor_blockB.cmd, 0); + if(s->brightness_steps){ + set_WD_brightness (window_descriptor_blockB.cmd, s->brightness); + } + set_WD_threshold (window_descriptor_blockB.cmd, s->threshold); - set_WD_contrast (window_descriptor_blockB.cmd, s->contrast); + + set_WD_contrast (window_descriptor_blockB.cmd, 0); + if(s->contrast_steps){ + set_WD_contrast (window_descriptor_blockB.cmd, s->contrast); + } + set_WD_composition (window_descriptor_blockB.cmd, s->mode); /* FIXME: is this something else on new scanners? */ diff --git a/backend/fujitsu.h b/backend/fujitsu.h index ba4351421..e8d8aa533 100644 --- a/backend/fujitsu.h +++ b/backend/fujitsu.h @@ -155,6 +155,7 @@ struct fujitsu int buffer_bytes; /*FIXME: do we need the std cmd list? */ + int has_cmd_msen; /*FIXME: there are more vendor cmds? */ int has_cmd_subwindow; @@ -199,6 +200,21 @@ struct fujitsu int os_x_basic; int os_y_basic; + /* --------------------------------------------------------------------- */ + /* immutable values which are gathered by mode_sense command */ + + int has_MS_prepick; + int has_MS_sleep; + int has_MS_duplex; + int has_MS_rand; + int has_MS_bg; + int has_MS_df; + int has_MS_dropout; /* dropout color specified in mode select data */ + int has_MS_buff; + int has_MS_auto; + int has_MS_lamp; + int has_MS_jobsep; + /* --------------------------------------------------------------------- */ /* immutable values which are hard coded because they are not in vpd */ /* this section replaces all the old 'switch (s->model)' code */ @@ -215,15 +231,9 @@ struct fujitsu int even_scan_line; /* need even number of bytes in a scanline (fi-5900) */ int window_vid; /* some models want different vendor ID in set window */ int ghs_in_rs; + int lut_bits; - /*int has_MS_prepick; - int has_MS_sleep; - int has_MS_background;*/ - int has_MS_df; - int has_MS_dropout; /* dropout color specified in mode select data */ int has_SW_dropout; /* dropout color specified in set window data */ - /*int has_MS_buffered; - int has_MS_paperlen;*/ int reverse_by_mode[6]; /* mode specific */ @@ -497,6 +507,7 @@ static SANE_Status sense_handler (int scsi_fd, u_char * result, void *arg); static SANE_Status init_inquire (struct fujitsu *s); static SANE_Status init_vpd (struct fujitsu *s); +static SANE_Status init_ms (struct fujitsu *s); static SANE_Status init_model (struct fujitsu *s); static SANE_Status init_options (struct fujitsu *scanner); diff --git a/doc/descriptions/fujitsu.desc b/doc/descriptions/fujitsu.desc index 3e0fdb188..2d466da74 100644 --- a/doc/descriptions/fujitsu.desc +++ b/doc/descriptions/fujitsu.desc @@ -11,7 +11,7 @@ :backend "fujitsu" ; name of backend :url "http://www2.pfeiffer.edu/~anoah/fujitsu/" -:version "1.0.36" ; version of backend +:version "1.0.37" ; 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.... @@ -303,6 +303,6 @@ :model "fi-5900C" :interface "SCSI USB" :usbid "0x04c5" "0x10e7" -:status :basic +:status :good :comment "production, current"