From ad779e0865ab8552ce2d5cbacdad5655f09bfb19 Mon Sep 17 00:00:00 2001 From: "m. allan noah" Date: Fri, 30 May 2008 08:47:38 +0000 Subject: [PATCH] backend version 64, use model and serial to build sane.name (idea from Ryan Duryea), allow both serial_name and device_name to sane_open scanner, simulate missing VPD data for M3097G, probe scanner for color interlacing mode instead of hardcoding, other minor cleanups --- ChangeLog | 8 + backend/fujitsu-scsi.h | 283 +++++++-------- backend/fujitsu.c | 626 ++++++++++++++++++++++------------ backend/fujitsu.h | 35 +- doc/descriptions/fujitsu.desc | 2 +- 5 files changed, 590 insertions(+), 364 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6eb365fb3..7a193e51c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-05-30 m. allan noah + * backend/fujitsu.[ch], backend/fujitsu-scsi.h, + doc/descriptions/fujitsu.desc: backend version 64, + use model and serial to build sane.name (idea from Ryan Duryea), + allow both serial_name and device_name to sane_open scanner, + simulate missing VPD data for M3097G, probe scanner for color + interlacing mode instead of hardcoding, other minor cleanups + 2008-05-29 Nicolas Martin * doc/sane-pixma.man: man update. * backend/pixma_io_sanei.c: update status types, and take into diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h index 011baea83..533403b26 100644 --- a/backend/fujitsu-scsi.h +++ b/backend/fujitsu-scsi.h @@ -97,6 +97,7 @@ scsiblk; #define RELEASE_UNIT 0x17 #define INQUIRY 0x12 #define REQUEST_SENSE 0x03 +#define READ_DIAGNOSTIC 0x1c #define SEND_DIAGNOSTIC 0x1d #define TEST_UNIT_READY 0x00 #define SET_WINDOW 0x24 @@ -112,17 +113,55 @@ scsiblk; #define HW_STATUS 0xc2 #define SCANNER_CONTROL 0xf1 - /* ==================================================================== */ -/* + +#if 0 static unsigned char reserve_unitC[] = { RESERVE_UNIT, 0x00, 0x00, 0x00, 0x00, 0x00 }; static scsiblk reserve_unitB = { reserve_unitC, sizeof (reserve_unitC) }; +/* ==================================================================== */ + static unsigned char release_unitC[] = { RELEASE_UNIT, 0x00, 0x00, 0x00, 0x00, 0x00 }; static scsiblk release_unitB = { release_unitC, sizeof (release_unitC) }; -*/ +#endif + +/* ==================================================================== */ + +static unsigned char send_diagnosticC[] = + { SEND_DIAGNOSTIC, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static scsiblk send_diagnosticB = {send_diagnosticC, sizeof(send_diagnosticC)}; + +#define set_SD_slftst(in, val) setbitfield(in + 1, 1, 2, val) +#define set_SD_xferlen(in, len) putnbyte(in + 3, len, 2) + +/* for 'FIRST READ DATE \0YMD' */ +#define set_SD_date_year(in, b) putnbyte(in + 0x11, b, 1) +#define set_SD_date_month(in, b) putnbyte(in + 0x12, b, 1) +#define set_SD_date_date(in, b) putnbyte(in + 0x13, b, 1) + +/* ==================================================================== */ + +static unsigned char read_diagnosticC[] = + { READ_DIAGNOSTIC, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static scsiblk read_diagnosticB = {read_diagnosticC, sizeof(read_diagnosticC)}; + +#define set_RD_xferlen(in, len) putnbyte(in + 3, len, 2) + +/* for 'FIRST READ DATE \0YMD' */ +#define get_RD_date_status(in) in[0] +#define RD_date_stored 0 +#define RD_date_not_stored 0xff + +/* for 'GET FIRST DATE ' */ +#define get_RD_date_year(in) in[1] +#define get_RD_date_month(in) in[2] +#define get_RD_date_date(in) in[3] + +/* for 'GET DEVICE ID ' */ +#define get_RD_id_serial(in) getnbyte (in, 4) + /* ==================================================================== */ static unsigned char scanner_controlC[] = @@ -223,8 +262,8 @@ static scsiblk inquiryB = { inquiryC, sizeof (inquiryC) }; #define get_IN_buffer_bytes(in) getnbyte(in + 0x22, 4) /*supported scsi commands*/ -#define get_IN_has_cmd_msen(in) getbitfield(in+0x26, 1, 1) -#define get_IN_has_cmd_msel(in) getbitfield(in+0x26, 1, 0) +#define get_IN_has_cmd_msen10(in) getbitfield(in+0x26, 1, 1) +#define get_IN_has_cmd_msel10(in) getbitfield(in+0x26, 1, 0) #define get_IN_has_cmd_lsen(in) getbitfield(in+0x27, 1, 7) #define get_IN_has_cmd_lsel(in) getbitfield(in+0x27, 1, 6) @@ -311,13 +350,13 @@ 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[] = @@ -340,7 +379,6 @@ static scsiblk object_positionB = /* ==================================================================== */ - static unsigned char sendC[] = {SEND, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static scsiblk sendB = {sendC, sizeof (sendC)}; @@ -779,18 +817,19 @@ static unsigned char window_descriptor_blockC[] = { /* 0x22-0x27 - reserved */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x28 - vendor id code - * 3091 - use 0xc0 - * 3096 - use 0xc0 + /* 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 +#define WD_VUID_3091 0xc0 +#define WD_VUID_COLOR 0xc1 - /* 0x29 - pattern setting - * 3091 - use 0x00 - * 3096 - reserved, use 0x00 - */ + /* 0x29 common gamma */ 0x00, #define set_WD_gamma(sb, val) sb[0x29] = val #define get_WD_gamma(sb) sb[0x29] @@ -799,25 +838,17 @@ static unsigned char window_descriptor_blockC[] = { #define WD_gamma_SOFT 2 #define WD_gamma_SHARP 3 - /* 0x2a - outline/scanning order - * 3091 - scanning order. Only 0x00 (line order) supported - * 3096 - outlining. 0x00=off, 0x80=on. 0x80 only permitted - * when image processing option fitted. - */ - 0x00, +/*==================================================================*/ + /* 0x2a-0x34 - vary based on vuid */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + +/*==================================================================*/ +/* vuid 0x00, mono params */ + #define set_WD_outline(sb, val) sb[0x2a] = val #define get_WD_outline(sb) sb[0x2a] -#define set_WD_scanning_order(sb, val) sb[0x2a] = val -#define get_WD_scanning_order(sb) sb[0x2a] - /* 0x2b - emphasis/scanning order argument - * 3091 - scanning order argument. Only 0x00 (RGB) supported - * 3096 - emphasis. 0x00=off, others only permitted when - * image processing option fitted: - * 0x2F=low emphasis, 0x4F=medium emphasis, - * 0x7F=high emphasis, 0xFF=smoothing - */ - 0x00, #define set_WD_emphasis(sb, val) sb[0x2b] = val #define get_WD_emphasis(sb) sb[0x2b] #define WD_emphasis_NONE 0x00 @@ -826,41 +857,17 @@ static unsigned char window_descriptor_blockC[] = { #define WD_emphasis_HIGH 0x50 #define WD_emphasis_SMOOTH 0x80 - /* 0x2c - auto separation - * 3091 - reserved, use 0x00 - * 3096 - auto separation. 0x00=off, 0x80=on. 0x80 only - * permitted when image processing option fitted. - */ - 0x00, #define set_WD_auto_sep(sb, val) setbitfield(sb + 0x2c, 1, 7, val) #define get_WD_auto_sep(sb) getbitfield(sb + 0x2c, 1, 7) - /* 0x2d - mirroring/single color - * 3091 - determines which color is used in monochrome - * scans: 0x00/0x04=G,0x01=B,0x02=R - * 3096 - window mirroring. 0x00=off, 0x80=on. 0x80 only - * permitted when image processing option fitted. - */ - 0x00, #define set_WD_mirroring(sb, val) setbitfield(sb + 0x2d, 1, 7, val) #define get_WD_mirroring(sb) getbitfield(sb + 0x2d, 1, 7) -#define set_WD_lamp_color(sb, val) sb[0x2d] = val -#define get_WD_lamp_color(sb) sb[0x2d] -#define WD_LAMP_DEFAULT 0x00 -#define WD_LAMP_BLUE 0x01 -#define WD_LAMP_RED 0x02 -#define WD_LAMP_GREEN 0x04 - /* 0x2e - variance/bit padding - * 3091 - unsupported, use 0x00 - * 3096 - variance rate for dynamic treshold. 0x00=default, - * 0x1f, 0x3f, ... 0xff = small...large - */ - 0x00, +/*also called Auto-II mode?*/ #define set_WD_var_rate_dyn_thresh(sb, val) sb[0x2e] = val #define get_WD_var_rate_dyn_thresh(sb) sb[0x2e] - 0x00, /* 0x2f *//* DTC mode */ +/*also called Auto-I mode?*/ #define set_WD_dtc_threshold_curve(sb, val) setbitfield(sb + 0x2f, 7, 0, val) #define get_WD_dtc_threshold_curve(sb) getbitfield(sb + 0x2f, 7, 0) #define set_WD_gradation(sb, val) setbitfield(sb + 0x2f, 3, 3, val) @@ -876,7 +883,6 @@ static unsigned char window_descriptor_blockC[] = { #define WD_filtering_BALLPOINT 0 #define WD_filtering_ORDINARY 1 - 0x00, /* 0x30 *//* DTC mode 2 */ #define set_WD_background(sb, val) setbitfield(sb + 0x30, 1, 0, val) #define get_WD_background(sb) getbitfield(sb + 0x30, 1, 0) #define WD_background_WHITE 0 @@ -892,113 +898,112 @@ static unsigned char window_descriptor_blockC[] = { #define set_WD_noise_removal(sb, val) setbitfield(sb + 0x30, 1, 5, !val) #define get_WD_noise_removal(sb) !getbitfield(sb + 0x30, 1, 5) - 0x00, /* 0x31 *//* reserved */ +/*31 reserved*/ - - /* 0x32 - scanning mode/white level follower - * 3091 - scan mode 0x00=normal, 0x02=high quality - * 3096 - white level follower, 0x00=default, - * 0x80 enable (line mode), 0xc0 disable (photo mode) - */ - 0x00, #define set_WD_white_level_follow(sb, val) sb[0x32] = val #define get_WD_white_level_follow(sb) sb[0x32] -#define set_WD_quality(sb, val) sb[0x32] = val -#define get_WD_quality(sb) sb[0x32] #define WD_white_level_follow_DEFAULT 0x00 #define WD_white_level_follow_ENABLED 0x80 #define WD_white_level_follow_DISABLED 0xC0 - /* 0x33,0x34 - subwindow list - * 3091 reserved, use 0x00 - * 3096 bits 0-3 of byte 34 denote use of subwindows 1...4 - */ - 0x00, 0x00, #define set_WD_subwindow_list(sb, val) putnbyte(sb + 0x33, val, 2) #define get_WD_subwindow_list(sb) getnbyte(sb + 0x33, 2) - /* 0x35 - paper size - * 3091 unsupported, always use 0xc0 - * 3096 if bits 6-7 both set, custom paper size enabled, - * bytes 0x36-0x3d used. Otherwise, a number of - * valid fixed values denote common paper formats. - */ - 0xC0, +/*==================================================================*/ +/* vuid 0xc1, color params */ + +#define set_WD_scanning_order(sb, val) sb[0x2a] = val +#define get_WD_scanning_order(sb) sb[0x2a] +#define WD_SCAN_ORDER_LINE 0 +#define WD_SCAN_ORDER_DOT 1 +#define WD_SCAN_ORDER_FACE 2 + +#define set_WD_scanning_order_arg(sb, val) sb[0x2b] = val +#define get_WD_scanning_order_arg(sb) sb[0x2b] +#define WD_SCAN_ARG_RGB 0 +#define WD_SCAN_ARG_RBG 1 +#define WD_SCAN_ARG_GRB 2 +#define WD_SCAN_ARG_GBR 3 +#define WD_SCAN_ARG_BRG 4 +#define WD_SCAN_ARG_BGR 5 + +/*2c-2d reserved*/ + +/*like vuid 00, but in different location*/ +#define set_WD_c1_emphasis(sb, val) sb[0x2e] = val +#define get_WD_c1_emphasis(sb) sb[0x2e] +#define set_WD_c1_mirroring(sb, val) setbitfield(sb + 0x2f, 1, 7, val) +#define get_WD_c1_mirroring(sb) getbitfield(sb + 0x2f, 1, 7) + +/*30-31 reserved*/ + +/*32 reserved for wlf like vuid 00*/ + +/*33-34 reserved*/ + +/*==================================================================*/ +/* vuid 0xc0, 3091/2 params */ + +/*2a-2b same as vuid 0xc1*/ + +#define set_WD_lamp_color(sb, val) sb[0x2d] = val +#define get_WD_lamp_color(sb) sb[0x2d] +#define WD_LAMP_DEFAULT 0x00 +#define WD_LAMP_BLUE 0x01 +#define WD_LAMP_RED 0x02 +#define WD_LAMP_GREEN 0x04 + +/*2e-31 reserved*/ + +#define set_WD_quality(sb, val) sb[0x32] = val +#define get_WD_quality(sb) sb[0x32] +#define WD_QUAL_NORMAL 0x00 +#define WD_QUAL_HIGH 0x02 + +/*33-34 reserved*/ + +/*==================================================================*/ + /* 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 #define WD_paper_SEL_NON_STANDARD 3 -/* we no longer use these, custom size (0xc0) overrides, - and more recent scanners only use custom size anyway -#define get_WD_paper_selection(sb) getbitfield(sb + 0x35, 3, 6) -#define WD_paper_SEL_STANDARD 2 - -#define set_WD_paper_orientation(sb, val) setbitfield(sb + 0x35, 1, 4, val) -#define get_WD_paper_orientation(sb) getbitfield(sb + 0x35, 1, 4) -#define WD_paper_PORTRAIT 0 -#define WD_paper_LANDSCAPE 1 - -#define set_WD_paper_size(sb, val) setbitfield(sb + 0x35, 0x0f, 0, val) -#define get_WD_paper_size(sb) getbitfield(sb + 0x35, 0x0f, 0) -#define WD_paper_UNDEFINED 0 -#define WD_paper_A3 3 -#define WD_paper_A4 4 -#define WD_paper_A5 5 -#define WD_paper_DOUBLE 6 -#define WD_paper_LETTER 7 -#define WD_paper_B4 12 -#define WD_paper_B5 13 -#define WD_paper_LEGAL 15 -#define WD_paper_CUSTOM 14 -*/ - - /* 0x36-0x39 - custom paper width - * 3091 0next) { - if (strcmp (s->sane.name, device_name) == 0) { + if (strcmp (s->device_name, device_name) == 0){ DBG (10, "attach_one: already attached!\n"); return SANE_STATUS_GOOD; } @@ -697,11 +709,7 @@ attach_one (const char *device_name, int connType) s->buffer_size = global_buffer_size; /* copy the device name */ - s->device_name = strdup (device_name); - if (!s->device_name){ - free (s); - return SANE_STATUS_NO_MEM; - } + strcpy (s->device_name, device_name); /* connect the fd */ s->connection = connType; @@ -710,7 +718,6 @@ attach_one (const char *device_name, int connType) s->fds[1] = -1; ret = connect_fd(s); if(ret != SANE_STATUS_GOOD){ - free (s->device_name); free (s); return ret; } @@ -719,7 +726,6 @@ attach_one (const char *device_name, int connType) ret = init_inquire (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); - free (s->device_name); free (s); DBG (5, "attach_one: inquiry failed\n"); return ret; @@ -729,7 +735,6 @@ attach_one (const char *device_name, int connType) ret = init_vpd (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); - free (s->device_name); free (s); DBG (5, "attach_one: vpd failed\n"); return ret; @@ -739,7 +744,6 @@ attach_one (const char *device_name, int connType) 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; @@ -750,7 +754,6 @@ attach_one (const char *device_name, int connType) ret = init_model (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); - free (s->device_name); free (s); DBG (5, "attach_one: model failed\n"); return ret; @@ -760,7 +763,6 @@ attach_one (const char *device_name, int connType) ret = init_user (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); - free (s->device_name); free (s); DBG (5, "attach_one: user failed\n"); return ret; @@ -769,21 +771,38 @@ attach_one (const char *device_name, int connType) ret = init_options (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); - free (s->device_name); free (s); DBG (5, "attach_one: options failed\n"); return ret; } + ret = init_interlace (s); + if (ret != SANE_STATUS_GOOD) { + disconnect_fd(s); + free (s); + DBG (5, "attach_one: interlace failed\n"); + return ret; + } + + /* load strings into sane_device struct */ + s->sane.name = s->device_name; + s->sane.vendor = s->vendor_name; + s->sane.model = s->model_name; + s->sane.type = "scanner"; + + /* change name in sane_device struct if scanner has serial number */ + ret = init_serial (s); + if (ret == SANE_STATUS_GOOD) { + s->sane.name = s->serial_name; + } + else{ + DBG (5, "attach_one: serial number unsupported?\n"); + } + /* we close the connection, so that another backend can talk to scanner */ disconnect_fd(s); - /* load info into sane_device struct */ - s->sane.name = s->device_name; - s->sane.vendor = s->vendor_name; - s->sane.model = s->product_name; - s->sane.type = "scanner"; - + /* store this scanner in global vars */ s->next = fujitsu_devList; fujitsu_devList = s; @@ -876,18 +895,18 @@ init_inquire (struct fujitsu *s) } get_IN_vendor (buffer, s->vendor_name); - get_IN_product (buffer, s->product_name); + get_IN_product (buffer, s->model_name); get_IN_version (buffer, s->version_name); s->vendor_name[8] = 0; - s->product_name[16] = 0; + s->model_name[16] = 0; s->version_name[4] = 0; /* gobble trailing spaces */ for (i = 7; s->vendor_name[i] == ' ' && i >= 0; i--) s->vendor_name[i] = 0; - for (i = 15; s->product_name[i] == ' ' && i >= 0; i--) - s->product_name[i] = 0; + for (i = 15; s->model_name[i] == ' ' && i >= 0; i--) + s->model_name[i] = 0; for (i = 3; s->version_name[i] == ' ' && i >= 0; i--) s->version_name[i] = 0; @@ -898,7 +917,7 @@ init_inquire (struct fujitsu *s) } DBG (15, "init_inquire: Found %s scanner %s version %s at %s\n", - s->vendor_name, s->product_name, s->version_name, s->device_name); + s->vendor_name, s->model_name, s->version_name, s->device_name); /*some scanners list random data here*/ DBG (15, "inquiry options\n"); @@ -952,20 +971,30 @@ init_vpd (struct fujitsu *s) ); /* M3099 gives all data, but wrong length */ - if (strstr (s->product_name, "M3099") + if (strstr (s->model_name, "M3099") && (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) && get_IN_page_length (buffer) == 0x19){ - DBG (5, "init_vpd: 3099 repair\n"); + DBG (5, "init_vpd: M3099 repair\n"); set_IN_page_length(buffer,0x5f); } - /* some(all?) versions of 3097 dont have vpd? - else if (strstr (s->product_name, "M3097") + /* some versions of 3097 have short vpd, fill in missing part */ + /* FIXME: do we need another block for devices with IPC? */ + else if (strstr (s->model_name, "M3097G") && (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) && get_IN_page_length (buffer) == 0x19){ - DBG (5, "init_vpd: 3097 repair\n"); - memcpy(buffer+0x19,buff_VPD_M3097.cmd,buff_VPD_M3097.size); - }*/ + unsigned char vpd3097g[] = { +0, 0, +0xc2, 0x08, 0, 0, 0, 0, 0, 0, 0xed, 0xbf, 0, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0xff, 0xff, 0xff, 0, 0x45, 0x35, 0x40, 0xe0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0 + }; + DBG (5, "init_vpd: M3097G repair\n"); + set_IN_page_length(buffer,0x5f); + memcpy(buffer+0x19+5,vpd3097g,sizeof(vpd3097g)); + } DBG (15, "init_vpd: length=%0x\n",get_IN_page_length (buffer)); @@ -1110,11 +1139,11 @@ init_vpd (struct fujitsu *s) DBG (15, " buffer bytes: %d\n",s->buffer_bytes); /* std scsi command support byte 26*/ - s->has_cmd_msen = get_IN_has_cmd_msen(buffer); - DBG (15, " mode_sense cmd: %d\n", s->has_cmd_msen); + s->has_cmd_msen10 = get_IN_has_cmd_msen10(buffer); + DBG (15, " mode_sense_10 cmd: %d\n", s->has_cmd_msen10); - s->has_cmd_msel = get_IN_has_cmd_msel(buffer); - DBG (15, " mode_select cmd: %d\n", s->has_cmd_msel); + s->has_cmd_msel10 = get_IN_has_cmd_msel10(buffer); + DBG (15, " mode_select_10 cmd: %d\n", s->has_cmd_msel10); /* std scsi command support byte 27*/ s->has_cmd_lsen = get_IN_has_cmd_lsen(buffer); @@ -1328,7 +1357,7 @@ init_ms(struct fujitsu *s) DBG (10, "init_ms: start\n"); - if(!s->has_cmd_msen){ + if(!s->has_cmd_msen6){ DBG (10, "init_ms: unsupported\n"); return SANE_STATUS_GOOD; } @@ -1344,7 +1373,7 @@ init_ms(struct fujitsu *s) set_MSEN_xfer_length (mode_senseB.cmd, inLen); - DBG (35, "init_ms: 32 (unknown)\n"); + DBG (35, "init_ms: 32 unknown)\n"); set_MSEN_pc(mode_senseB.cmd, MS_pc_unknown); memset(buffer,0,inLen); ret = do_cmd ( @@ -1541,7 +1570,12 @@ init_model (struct fujitsu *s) DBG (10, "init_model: start\n"); /* for most scanners these are good defaults */ - s->color_interlace = COLOR_INTERLACE_BGR; + if(s->can_monochrome || s->can_halftone || s->can_grayscale){ + s->has_vuid_mono = 1; + } + if(s->can_color_grayscale){ + s->has_vuid_color = 1; + } s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; @@ -1557,8 +1591,8 @@ init_model (struct fujitsu *s) /* these two scanners lie about their capabilities, * and/or differ significantly from most other models */ - if (strstr (s->product_name, "M3091") - || strstr (s->product_name, "M3092")) { + if (strstr (s->model_name, "M3091") + || strstr (s->model_name, "M3092")) { /* lies */ s->has_rif = 1; @@ -1566,10 +1600,12 @@ init_model (struct fujitsu *s) s->adbits = 8; /* weirdness */ + s->has_vuid_3091 = 1; + s->has_vuid_color = 0; + s->has_vuid_mono = 0; + s->color_interlace = COLOR_INTERLACE_3091; s->duplex_interlace = DUPLEX_INTERLACE_3091; - s->has_SW_dropout = 1; - s->window_vid = 0xc0; s->ghs_in_rs = 1; s->window_gamma = 0; @@ -1578,7 +1614,7 @@ init_model (struct fujitsu *s) s->reverse_by_mode[MODE_GRAYSCALE] = 0; s->reverse_by_mode[MODE_COLOR] = 0; } - else if (strstr (s->product_name, "M3093")){ + else if (strstr (s->model_name, "M3093")){ /* lies */ s->has_back = 0; s->adbits = 8; @@ -1586,43 +1622,27 @@ init_model (struct fujitsu *s) /* weirdness */ s->duplex_interlace = DUPLEX_INTERLACE_NONE; } - else if ( strstr (s->product_name, "M309") - || strstr (s->product_name, "M409")){ + else if ( strstr (s->model_name, "M309") + || strstr (s->model_name, "M409")){ /* lies */ s->adbits = 8; } - else if (strstr (s->product_name, "fi-4120C2") - || strstr (s->product_name, "fi-4220C2") ) { - - /*s->max_x = 10488;*/ + else if (strstr (s->model_name, "fi-4120C2") + || strstr (s->model_name, "fi-4220C2") ) { /* missing from vpd */ s->os_x_basic = 376; s->os_y_basic = 236; - } - else if ( strstr (s->product_name, "fi-4340") - || strstr (s->product_name, "fi-4750") - || strstr (s->product_name, "fi-5650") - || strstr (s->product_name, "fi-5750") - || strstr (s->product_name, "fi-6140") - || strstr (s->product_name, "fi-6240") - ) { - - /* weirdness */ - s->color_interlace = COLOR_INTERLACE_RRGGBB; - } /* some firmware versions use capital f? */ - else if (strstr (s->product_name, "Fi-5900") - || strstr (s->product_name, "fi-5900") ) { + else if (strstr (s->model_name, "Fi-5900") + || strstr (s->model_name, "fi-5900") ) { /* weirdness */ s->even_scan_line = 1; - s->color_interlace = COLOR_INTERLACE_NONE; - } DBG (10, "init_model: finish\n"); @@ -1723,6 +1743,127 @@ init_options (struct fujitsu *s) return SANE_STATUS_GOOD; } +/* + * send set window repeatedly to color scanners, + * searching for valid color interlacing mode + */ +static SANE_Status +init_interlace (struct fujitsu *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + int curr_mode = s->mode; + + DBG (10, "init_interlace: start\n"); + + if(!s->has_vuid_color){ + DBG (10, "init_interlace: unneeded\n"); + return SANE_STATUS_GOOD; + } + + /* set to color mode first */ + s->mode=MODE_COLOR; + + /* load our own private copy of scan params */ + ret = sane_get_parameters ((SANE_Handle) s, &s->params); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "init_interlace: ERROR: cannot get params\n"); + return ret; + } + + /*loop thru all the formats we support*/ + for(s->color_interlace = COLOR_INTERLACE_RGB; + s->color_interlace <= COLOR_INTERLACE_RRGGBB; + s->color_interlace++){ + + ret = set_window(s); + if (ret == SANE_STATUS_GOOD){ + break; + } + else{ + DBG (5, "init_interlace: not %d\n", s->color_interlace); + } + } + + if (ret != SANE_STATUS_GOOD){ + DBG (5, "init_interlace: no valid interlacings\n"); + return SANE_STATUS_INVAL; + } + + DBG (15, "init_interlace: color_interlace: %d\n",s->color_interlace); + + /* restore mode */ + s->mode=curr_mode; + + DBG (10, "init_interlace: finish\n"); + + return SANE_STATUS_GOOD; +} + +/* + * send diag query for serial number, and read result back + * use it to build a unique name for scanner in s->serial_name + */ +static SANE_Status +init_serial (struct fujitsu *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + unsigned int sn = 0; + + unsigned char sd_payload[] = "GET DEVICE ID "; + size_t sd_payLen = sizeof(sd_payload) - 1; + + unsigned char rd_payload[0x0c]; + size_t rd_payLen = sizeof(rd_payload); + + DBG (10, "init_serial: start\n"); + + if (!s->has_cmd_sdiag || !s->has_cmd_rdiag){ + DBG (5, "init_serial: send/read diag not supported, returning\n"); + return SANE_STATUS_INVAL; + } + + set_SD_slftst(send_diagnosticB.cmd, 0); + set_SD_xferlen(send_diagnosticB.cmd, sd_payLen); + + ret = do_cmd ( + s, 1, 0, + send_diagnosticB.cmd, send_diagnosticB.size, + sd_payload, sd_payLen, + NULL, NULL + ); + + if (ret != SANE_STATUS_GOOD){ + DBG (5, "init_serial: send diag error: %d\n", ret); + return ret; + } + + set_RD_xferlen(read_diagnosticB.cmd, rd_payLen); + + ret = do_cmd ( + s, 1, 0, + read_diagnosticB.cmd, read_diagnosticB.size, + NULL, 0, + rd_payload, &rd_payLen + ); + + if (ret != SANE_STATUS_GOOD){ + DBG (5, "init_serial: read diag error: %d\n", ret); + return ret; + } + + sn = get_RD_id_serial(rd_payload); + + DBG (15, "init_serial: found sn %d\n",sn); + + sprintf(s->serial_name, "%s:%d", s->model_name, sn); + + DBG (15, "init_serial: serial_name: %s\n",s->serial_name); + + DBG (10, "init_serial: finish\n"); + + return SANE_STATUS_GOOD; +} + /* * From the SANE spec: * This function is used to establish a connection to a particular @@ -1761,7 +1902,8 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) DBG (15, "sane_open: device %s requested\n", name); for (dev = fujitsu_devList; dev; dev = dev->next) { - if (strcmp (dev->sane.name, name) == 0) { + if (strcmp (dev->sane.name, name) == 0 + || strcmp (dev->device_name, name) == 0) { /*always allow sanei devname*/ s = dev; break; } @@ -2403,7 +2545,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->do_color_list; opt->size = maxStringSize (opt->constraint.string_list); - if ((s->has_MS_dropout || s->has_SW_dropout) && s->mode != MODE_COLOR) + if ((s->has_MS_dropout || s->has_vuid_3091) && s->mode != MODE_COLOR) opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; else opt->cap = SANE_CAP_INACTIVE; @@ -4148,6 +4290,42 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) } #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) { @@ -4462,42 +4640,6 @@ setup_buffers (struct fujitsu *s) return ret; } -/* - * 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; -} - /* * This routine issues a SCSI SET WINDOW command to the scanner, using the * values currently in the scanner data structure. @@ -4518,12 +4660,19 @@ set_window (struct fujitsu *s) */ /* set window desc size in header */ - set_WPDB_wdblen (window_descriptor_headerB.cmd, window_descriptor_blockB.size); + 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); + 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); + } + /* init the window block */ set_WD_Xres (window_descriptor_blockB.cmd, s->resolution_x); set_WD_Yres (window_descriptor_blockB.cmd, s->resolution_y); @@ -4560,11 +4709,30 @@ set_window (struct fujitsu *s) set_WD_composition (window_descriptor_blockB.cmd, s->mode); - /* FIXME: is this something else on new scanners? */ - set_WD_lamp_color (window_descriptor_blockB.cmd, 0); + set_WD_bitsperpixel (window_descriptor_blockB.cmd, s->params.depth); - /* older scanners use set window to indicate dropout color */ - if (s->has_SW_dropout && s->mode != MODE_COLOR){ + 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); + + /* 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); + } + + /*the remainder of the block varies based on model and mode, + * except for gamma and paper size, those are in the same place */ + + /*vuid c0*/ + if(s->has_vuid_3091){ + set_WD_vendor_id_code (window_descriptor_blockB.cmd, WD_VUID_3091); + + if (s->mode == MODE_COLOR){ + set_WD_lamp_color (window_descriptor_blockB.cmd, 0); + } + else{ switch (s->dropout_color) { case COLOR_RED: set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_RED); @@ -4579,27 +4747,51 @@ set_window (struct fujitsu *s) set_WD_lamp_color (window_descriptor_blockB.cmd, WD_LAMP_DEFAULT); break; } + } } - set_WD_bitsperpixel (window_descriptor_blockB.cmd, s->params.depth); + /*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_rif (window_descriptor_blockB.cmd, s->rif); + 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); + } + 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); + } + 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); + } + else{ + DBG (5,"set_window: unknown color interlacing\n"); + return SANE_STATUS_INVAL; + } - set_WD_compress_type(window_descriptor_blockB.cmd, COMP_NONE); - set_WD_compress_arg(window_descriptor_blockB.cmd, 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); + /* just in case? */ + set_WD_lamp_color (window_descriptor_blockB.cmd, 0); } - set_WD_vendor_id_code (window_descriptor_blockB.cmd, s->window_vid); + /*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); + } + + else{ + DBG (5,"set_window: no vuid to send?\n"); + return SANE_STATUS_INVAL; + } set_WD_gamma (window_descriptor_blockB.cmd, s->window_gamma); if(s->source == SOURCE_FLATBED){ - set_WD_paper_selection (window_descriptor_blockB.cmd, WD_paper_SEL_UNDEFINED); + set_WD_paper_selection(window_descriptor_blockB.cmd,WD_paper_SEL_UNDEFINED); } else{ set_WD_paper_selection (window_descriptor_blockB.cmd, WD_paper_SEL_NON_STANDARD); @@ -4611,13 +4803,6 @@ set_window (struct fujitsu *s) set_WD_paper_length_Y (window_descriptor_blockB.cmd, s->page_height); } - 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); - } - /* copy first desc block into local buffer */ memcpy (buffer + bufferLen, window_descriptor_blockB.cmd, window_descriptor_blockB.size); bufferLen += window_descriptor_blockB.size; @@ -5571,7 +5756,6 @@ sane_exit (void) for (dev = fujitsu_devList; dev; dev = next) { disconnect_fd(dev); next = dev->next; - free (dev->device_name); free (dev); } @@ -6236,38 +6420,56 @@ maxStringSize (const SANE_String_Const strings[]) return max_size; } -/** +/* * Prints a hex dump of the given buffer onto the debug output stream. */ static void hexdump (int level, char *comment, unsigned char *p, int l) { int i; - char line[128]; - char *ptr; + char line[70]; /* 'xxx: xx xx ... xx xx abc */ + char *hex = line+4; + char *bin = line+53; if(DBG_LEVEL < level) return; DBG (level, "%s\n", comment); - ptr = line; - for (i = 0; i < l; i++, p++) - { - if ((i % 16) == 0) - { - if (ptr != line) - { - *ptr = '\0'; - DBG (level, "%s\n", line); - ptr = line; - } - sprintf (ptr, "%3.3x:", i); - ptr += 4; - } - sprintf (ptr, " %2.2x", *p); - ptr += 3; + + for (i = 0; i < l; i++, p++) { + + /* at start of line */ + if ((i % 16) == 0) { + + /* not at start of first line, print current, reset */ + if (i) { + DBG (level, "%s\n", line); + } + + memset(line,0x20,69); + line[69] = 0; + hex = line + 4; + bin = line + 53; + + sprintf (line, "%3.3x:", i); } - *ptr = '\0'; + + /* the hex section */ + sprintf (hex, " %2.2x", *p); + hex += 3; + *hex = ' '; + + /* the char section */ + if(*p >= 0x20 && *p <= 0x7e){ + *bin=*p; + } + else{ + *bin='.'; + } + bin++; + } + + /* print last (partial) line */ DBG (level, "%s\n", line); } diff --git a/backend/fujitsu.h b/backend/fujitsu.h index 0347b213a..899815707 100644 --- a/backend/fujitsu.h +++ b/backend/fujitsu.h @@ -83,7 +83,7 @@ struct fujitsu /* --------------------------------------------------------------------- */ /* immutable values which are set during init of scanner. */ struct fujitsu *next; - char *device_name; /* The name of the scanner device for sane */ + char device_name[1024]; /* The name of the device from sanei */ /* --------------------------------------------------------------------- */ /* immutable values which are set during reading of config file. */ @@ -93,10 +93,8 @@ struct fujitsu /* --------------------------------------------------------------------- */ /* immutable values which are set during inquiry probing of the scanner. */ /* members in order found in scsi data... */ - SANE_Device sane; - char vendor_name[9]; /* raw data as returned by SCSI inquiry. */ - char product_name[17]; /* raw data as returned by SCSI inquiry. */ + char model_name[17]; /* raw data as returned by SCSI inquiry. */ char version_name[5]; /* raw data as returned by SCSI inquiry. */ int color_raster_offset; /* offset between r and b scan line and */ @@ -161,8 +159,8 @@ struct fujitsu int buffer_bytes; /*supported scsi commands*/ - int has_cmd_msen; - int has_cmd_msel; + int has_cmd_msen10; + int has_cmd_msel10; int has_cmd_lsen; int has_cmd_lsel; @@ -264,14 +262,24 @@ struct fujitsu int color_interlace; /* different models interlace colors differently */ int duplex_interlace; /* different models interlace sides differently */ 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 window_gamma; - int has_SW_dropout; /* dropout color specified in set window data */ + int has_vuid_mono; /* mono set window data */ + int has_vuid_3091; /* 3091/2 set window data */ + int has_vuid_color; /* color set window data */ int reverse_by_mode[6]; /* mode specific */ + /* --------------------------------------------------------------------- */ + /* immutable values which are set during serial number probing scanner */ + char serial_name[28]; /* 16 char model, ':', 10 byte serial, null */ + + /* --------------------------------------------------------------------- */ + /* struct with pointers to device/vendor/model names, and a type value */ + /* used to inform sane frontend about the device */ + SANE_Device sane; + /* --------------------------------------------------------------------- */ /* changeable SANE_Option structs provide our interface to frontend. */ /* some options require lists of strings or numbers, we keep them here */ @@ -479,10 +487,10 @@ struct fujitsu #define COLOR_WHITE 1 #define COLOR_BLACK 2 -#define COLOR_INTERLACE_NONE 0 -#define COLOR_INTERLACE_3091 1 -#define COLOR_INTERLACE_BGR 2 -#define COLOR_INTERLACE_RRGGBB 3 +#define COLOR_INTERLACE_RGB 0 +#define COLOR_INTERLACE_BGR 1 +#define COLOR_INTERLACE_RRGGBB 2 +#define COLOR_INTERLACE_3091 3 #define DUPLEX_INTERLACE_ALT 0 #define DUPLEX_INTERLACE_NONE 1 @@ -568,6 +576,8 @@ static SANE_Status init_ms (struct fujitsu *s); static SANE_Status init_model (struct fujitsu *s); static SANE_Status init_user (struct fujitsu *s); static SANE_Status init_options (struct fujitsu *scanner); +static SANE_Status init_interlace (struct fujitsu *scanner); +static SANE_Status init_serial (struct fujitsu *scanner); static SANE_Status do_cmd(struct fujitsu *s, int runRS, int shortTime, @@ -617,6 +627,7 @@ static SANE_Status send_lut (struct fujitsu *s); static SANE_Status set_window (struct fujitsu *s); /* +static SANE_Status get_window (struct fujitsu *s); static SANE_Status get_pixelsize (struct fujitsu *s, int*, int*, int*, int*); */ diff --git a/doc/descriptions/fujitsu.desc b/doc/descriptions/fujitsu.desc index 911b9960e..00566e4ea 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 "1.0.62" ; version of backend +:version "64" ; 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....