diff options
Diffstat (limited to 'backend/canon_dr.c')
-rw-r--r-- | backend/canon_dr.c | 1258 |
1 files changed, 891 insertions, 367 deletions
diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 594aab2..381cfd6 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -276,10 +276,46 @@ - DR-2580C pads the backside of duplex scans v40 2012-11-01, MAN - initial DR-9050C, DR-7550C, DR-6050C and DR-3010C support - v41 2013-07-31, MAN + v41 2013-07-31, MAN (SANE 1.0.24) - initial P-208 and P-215 support - bug fix for calibration of scanners with duplex_offset - allow duplex_offset to be controlled from config file + v42 2013-12-09, MAN + - initial DR-G1100 support + - add support for paper sensors (P-215 & P-208) + - add initial support for card reader (P-215) + - removed unused var from do_scsi_cmd() + v43 2014-03-13, MAN + - initial DR-M140 support + - add extra_status config and code + - split status code into do_usb_status + - fix copy_line margin offset + - add new color interlacing modes and code + - comment out ssm2 + - add timestamp to do_usb_cmd + v44 2014-03-26, MAN + - buffermode support for machines with ssm2 command + - DR-M140 needs always_op=0 + v45 2014-03-29, MAN + - dropout support for machines with ssm2 command + - doublefeed support for machines with ssm2 command + v46 2014-04-09, MAN + - split debug level 30 into two levels + - simplify jpeg ifdefs + - add support for DR-M160 + v47 2014-07-07, MAN + - initial DR-G1130 support + v48 2014-08-06, MAN + - set another unknown byte in buffermode for ssm2 + - add another gettimeofday call at end of do_usb_cmd + - don't print 0 length line in hexdump + v49 2015-03-18, MAN + - initial support for DR-C125 + v50 2015-08-23, MAN + - DR-C125 adds duplex padding on back side + - initial support for DR-C225 + v51 2015-08-25, MAN + - DR-C125 does not invert_tly, does need sw_lut SANE FLOW DIAGRAM @@ -317,6 +353,7 @@ #include <ctype.h> /*isspace*/ #include <math.h> /*tan*/ #include <unistd.h> /*usleep*/ +#include <sys/time.h> /*gettimeofday*/ #include "../include/sane/sanei_backend.h" #include "../include/sane/sanei_scsi.h" @@ -328,7 +365,7 @@ #include "canon_dr.h" #define DEBUG 1 -#define BUILD 41 +#define BUILD 51 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 @@ -336,15 +373,25 @@ - function detail 15 - get/setopt cmds 20 - scsi/usb trace 25 - - scsi/usb detail 30 + - scsi/usb writes 30 + - scsi/usb reads 31 - useless noise 35 */ /* ------------------------------------------------------------------------- */ +/* if JPEG support is not enabled in sane.h, we setup our own defines */ +#ifndef SANE_FRAME_JPEG +#define SANE_FRAME_JPEG 0x0B +#define SANE_JPEG_DISABLED 1 +#endif +/* ------------------------------------------------------------------------- */ #define STRING_FLATBED SANE_I18N("Flatbed") #define STRING_ADFFRONT SANE_I18N("ADF Front") #define STRING_ADFBACK SANE_I18N("ADF Back") #define STRING_ADFDUPLEX SANE_I18N("ADF Duplex") +#define STRING_CARDFRONT SANE_I18N("Card Front") +#define STRING_CARDBACK SANE_I18N("Card Back") +#define STRING_CARDDUPLEX SANE_I18N("Card Duplex") #define STRING_LINEART SANE_VALUE_SCAN_MODE_LINEART #define STRING_HALFTONE SANE_VALUE_SCAN_MODE_HALFTONE @@ -366,6 +413,8 @@ static int global_buffer_size; static int global_buffer_size_default = 2 * 1024 * 1024; static int global_padded_read; static int global_padded_read_default = 0; +static int global_extra_status; +static int global_extra_status_default = 0; static int global_duplex_offset; static int global_duplex_offset_default = 0; static char global_vendor_name[9]; @@ -543,6 +592,32 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) global_padded_read = buf; } + /* EXTRA STATUS: we clamp to 0 or 1 */ + else if (!strncmp (lp, "extra-status", 12) && isspace (lp[12])) { + + int buf; + lp += 12; + lp = sanei_config_skip_whitespace (lp); + buf = atoi (lp); + + if (buf < 0) { + DBG (5, "sane_get_devices: config option \"extra-status\" " + "(%d) is < 0, ignoring!\n", buf); + continue; + } + + if (buf > 1) { + DBG (5, "sane_get_devices: config option \"extra-status\" " + "(%d) is > 1, ignoring!\n", buf); + continue; + } + + DBG (15, "sane_get_devices: setting \"extra-status\" to %d\n", + buf); + + global_extra_status = buf; + } + /* DUPLEXOFFSET: < 1200 */ else if (!strncmp (lp, "duplex-offset", 13) && isspace (lp[13])) { @@ -733,6 +808,7 @@ attach_one (const char *device_name, int connType) /* config file settings */ s->buffer_size = global_buffer_size; s->padded_read = global_padded_read; + s->extra_status = global_extra_status; s->duplex_offset = global_duplex_offset; /* copy the device name */ @@ -1160,6 +1236,9 @@ init_model (struct scanner *s) s->reverse_by_mode[MODE_GRAYSCALE] = 0; s->reverse_by_mode[MODE_COLOR] = 0; + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RGB; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RGB; + s->always_op = 1; s->has_df = 1; s->has_btc = 1; @@ -1191,9 +1270,7 @@ init_model (struct scanner *s) /* specific settings missing from vpd */ if (strstr (s->model_name,"DR-9080") || strstr (s->model_name,"DR-7580")){ -#ifdef SANE_FRAME_JPEG s->has_comp_JPEG = 1; -#endif s->rgb_format = 2; } @@ -1203,7 +1280,10 @@ init_model (struct scanner *s) else if (strstr (s->model_name,"DR-9050") || strstr (s->model_name,"DR-7550") - || strstr (s->model_name,"DR-6050")){ + || strstr (s->model_name,"DR-6050") + || strstr (s->model_name,"DR-G1100") + || strstr (s->model_name,"DR-G1130") + ){ /*missing*/ s->std_res_x[DPI_100]=1; @@ -1367,6 +1447,7 @@ init_model (struct scanner *s) s->has_ssm_pay_head_len = 1; s->ppl_mod = 8; s->ccal_version = 3; + s->can_read_sensors = 1; } else if (strstr (s->model_name, "P-215")) { @@ -1382,6 +1463,150 @@ init_model (struct scanner *s) s->has_ssm_pay_head_len = 1; s->ppl_mod = 8; s->ccal_version = 3; + s->can_read_sensors = 1; + s->has_card = 1; + } + + else if (strstr (s->model_name,"DR-M160")){ + + /*missing*/ + s->std_res_x[DPI_100]=1; + s->std_res_y[DPI_100]=1; + s->std_res_x[DPI_150]=1; + s->std_res_y[DPI_150]=1; + s->std_res_x[DPI_200]=1; + s->std_res_y[DPI_200]=1; + s->std_res_x[DPI_300]=1; + s->std_res_y[DPI_300]=1; + s->std_res_x[DPI_400]=1; + s->std_res_y[DPI_400]=1; + s->std_res_x[DPI_600]=1; + s->std_res_y[DPI_600]=1; + + s->has_comp_JPEG = 1; + s->rgb_format = 1; + s->can_color = 1; + s->has_df_ultra = 1; + + s->color_inter_by_res[DPI_100] = COLOR_INTERLACE_GBR; + s->color_inter_by_res[DPI_150] = COLOR_INTERLACE_GBR; + s->color_inter_by_res[DPI_200] = COLOR_INTERLACE_BRG; + s->color_inter_by_res[DPI_400] = COLOR_INTERLACE_GBR; + + /*weirdness*/ + s->always_op = 0; + s->fixed_width = 1; + s->invert_tly = 1; + s->can_write_panel = 0; + s->has_ssm = 0; + s->has_ssm2 = 1; + s->duplex_interlace = DUPLEX_INTERLACE_FFBB; + s->duplex_offset_side = SIDE_FRONT; + + /*lies*/ + s->can_halftone=0; + s->can_monochrome=0; + } + + else if (strstr (s->model_name,"DR-M140")){ + + /*missing*/ + s->std_res_x[DPI_100]=1; + s->std_res_y[DPI_100]=1; + s->std_res_x[DPI_150]=1; + s->std_res_y[DPI_150]=1; + s->std_res_x[DPI_200]=1; + s->std_res_y[DPI_200]=1; + s->std_res_x[DPI_300]=1; + s->std_res_y[DPI_300]=1; + s->std_res_x[DPI_400]=1; + s->std_res_y[DPI_400]=1; + s->std_res_x[DPI_600]=1; + s->std_res_y[DPI_600]=1; + + s->has_comp_JPEG = 1; + s->rgb_format = 1; + s->can_color = 1; + s->has_df_ultra = 1; + + s->color_inter_by_res[DPI_100] = COLOR_INTERLACE_GBR; + s->color_inter_by_res[DPI_150] = COLOR_INTERLACE_GBR; + s->color_inter_by_res[DPI_200] = COLOR_INTERLACE_BRG; + s->color_inter_by_res[DPI_400] = COLOR_INTERLACE_GBR; + + /*weirdness*/ + s->always_op = 0; + s->fixed_width = 1; + s->invert_tly = 1; + s->can_write_panel = 0; + s->has_ssm = 0; + s->has_ssm2 = 1; + s->duplex_interlace = DUPLEX_INTERLACE_FFBB; + s->duplex_offset_side = SIDE_BACK; + + /*lies*/ + s->can_halftone=0; + s->can_monochrome=0; + } + + else if (strstr (s->model_name,"DR-C125")){ + + /*confirmed settings*/ + s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_2510; + s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_2510; + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_2510; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_2510; + s->duplex_interlace = DUPLEX_INTERLACE_2510; + s->duplex_offset_side = SIDE_BACK; + s->unknown_byte2 = 0x88; + s->need_ccal = 1; + s->ccal_version = 3; + s->need_fcal = 1; + s->sw_lut = 1; + s->can_color = 1; + s->rgb_format = 1; + /*s->duplex_offset = 400; now set in config file*/ + + /*only in Y direction, so we trash them in X*/ + s->std_res_x[DPI_100]=0; + s->std_res_x[DPI_150]=0; + s->std_res_x[DPI_200]=0; + s->std_res_x[DPI_240]=0; + s->std_res_x[DPI_400]=0; + + /*suspected settings*/ + s->always_op = 0; + s->fixed_width = 1; + s->valid_x = 8.5 * 1200; + } + + else if (strstr (s->model_name,"DR-C225")){ + + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_rRgGbB; + s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG; + s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + + s->unknown_byte2 = 0x88; + s->need_ccal = 1; + s->ccal_version = 3; + s->need_fcal = 1; + s->invert_tly = 1; + s->can_color = 1; + s->rgb_format = 1; + /*s->duplex_offset = 400; now set in config file*/ + + /*only in Y direction, so we trash them in X*/ + s->std_res_x[DPI_100]=0; + s->std_res_x[DPI_150]=0; + s->std_res_x[DPI_200]=0; + s->std_res_x[DPI_240]=0; + s->std_res_x[DPI_400]=0; + + /*suspected settings*/ + s->always_op = 0; + s->fixed_width = 1; + s->valid_x = 8.5 * 1200; } DBG (10, "init_model: finish\n"); @@ -1435,6 +1660,8 @@ init_user (struct scanner *s) s->u.source = SOURCE_FLATBED; else if(s->has_adf) s->u.source = SOURCE_ADF_FRONT; + else if(s->has_card) + s->u.source = SOURCE_CARD_FRONT; /* scan mode */ if(s->can_monochrome) @@ -1628,6 +1855,16 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->source_list[i++]=STRING_ADFDUPLEX; } } + if(s->has_card){ + s->source_list[i++]=STRING_CARDFRONT; + + if(s->has_back){ + s->source_list[i++]=STRING_CARDBACK; + } + if(s->has_duplex){ + s->source_list[i++]=STRING_CARDDUPLEX; + } + } s->source_list[i]=NULL; opt->name = SANE_NAME_SCAN_SOURCE; @@ -1841,7 +2078,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->constraint_type = SANE_CONSTRAINT_RANGE; opt->constraint.range = &s->paper_x_range; - if(s->has_adf){ + if(s->has_adf || s->has_card){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; if(s->u.source == SOURCE_FLATBED){ opt->cap |= SANE_CAP_INACTIVE; @@ -1868,7 +2105,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->constraint_type = SANE_CONSTRAINT_RANGE; opt->constraint.range = &s->paper_y_range; - if(s->has_adf){ + if(s->has_adf || s->has_card){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; if(s->u.source == SOURCE_FLATBED){ opt->cap |= SANE_CAP_INACTIVE; @@ -1985,7 +2222,9 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->compress_list[i++]=STRING_NONE; if(s->has_comp_JPEG){ +#ifndef SANE_JPEG_DISABLED s->compress_list[i++]=STRING_JPEG; +#endif } s->compress_list[i]=NULL; @@ -2306,6 +2545,28 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } + if(option==OPT_ADF_LOADED){ + opt->name = "adf-loaded"; + opt->title = "ADF Loaded"; + opt->desc = "Paper available in ADF input hopper"; + opt->type = SANE_TYPE_BOOL; + opt->unit = SANE_UNIT_NONE; + opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + if(!s->can_read_sensors) + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_CARD_LOADED){ + opt->name = "card-loaded"; + opt->title = "Card Loaded"; + opt->desc = "Paper available in card reader"; + opt->type = SANE_TYPE_BOOL; + opt->unit = SANE_UNIT_NONE; + opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + if(!s->can_read_sensors || !s->has_card) + opt->cap = SANE_CAP_INACTIVE; + } + return opt; } @@ -2382,6 +2643,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option, else if(s->u.source == SOURCE_ADF_DUPLEX){ strcpy (val, STRING_ADFDUPLEX); } + else if(s->u.source == SOURCE_CARD_FRONT){ + strcpy (val, STRING_CARDFRONT); + } + else if(s->u.source == SOURCE_CARD_BACK){ + strcpy (val, STRING_CARDBACK); + } + else if(s->u.source == SOURCE_CARD_DUPLEX){ + strcpy (val, STRING_CARDDUPLEX); + } return SANE_STATUS_GOOD; case OPT_MODE: @@ -2581,6 +2851,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->panel_counter; return ret; + case OPT_ADF_LOADED: + ret = read_sensors(s,OPT_ADF_LOADED); + *val_p = s->sensor_adf_loaded; + return ret; + + case OPT_CARD_LOADED: + ret = read_sensors(s,OPT_CARD_LOADED); + *val_p = s->sensor_card_loaded; + return ret; } } else if (action == SANE_ACTION_SET_VALUE) { @@ -2629,6 +2908,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option, else if (!strcmp (val, STRING_ADFDUPLEX)) { tmp = SOURCE_ADF_DUPLEX; } + else if (!strcmp (val, STRING_CARDFRONT)) { + tmp = SOURCE_CARD_FRONT; + } + else if (!strcmp (val, STRING_CARDBACK)) { + tmp = SOURCE_CARD_BACK; + } + else if (!strcmp (val, STRING_CARDDUPLEX)) { + tmp = SOURCE_CARD_DUPLEX; + } else{ tmp = SOURCE_FLATBED; } @@ -2837,54 +3125,85 @@ ssm_buffer (struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; - unsigned char cmd[SET_SCAN_MODE_len]; - size_t cmdLen = SET_SCAN_MODE_len; - - unsigned char out[SSM_PAY_len]; - size_t outLen = SSM_PAY_len; - DBG (10, "ssm_buffer: start\n"); - if(!s->has_ssm){ - DBG (10, "ssm_buffer: unsupported\n"); - return ret; + if(s->has_ssm){ + + unsigned char cmd[SET_SCAN_MODE_len]; + size_t cmdLen = SET_SCAN_MODE_len; + + unsigned char out[SSM_PAY_len]; + size_t outLen = SSM_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE_code); + set_SSM_pf(cmd, 1); + set_SSM_pay_len(cmd, outLen); + + memset(out,0,outLen); + if(s->has_ssm_pay_head_len){ + set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); + } + set_SSM_page_code(out, SM_pc_buffer); + set_SSM_page_len(out, SSM_PAGE_len); + + if(s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX){ + set_SSM_BUFF_duplex(out, 1); + } + if(s->s.source == SOURCE_FLATBED){ + set_SSM_BUFF_fb(out, 1); + } + else if(s->s.source >= SOURCE_CARD_FRONT){ + set_SSM_BUFF_card(out, 1); + } + if(s->buffermode){ + set_SSM_BUFF_async(out, 1); + } + if(0){ + set_SSM_BUFF_ald(out, 1); + } + if(0){ + set_SSM_BUFF_unk(out,1); + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); } - memset(cmd,0,cmdLen); - set_SCSI_opcode(cmd, SET_SCAN_MODE_code); - set_SSM_pf(cmd, 1); - set_SSM_pay_len(cmd, outLen); + else if(s->has_ssm2){ - memset(out,0,outLen); - if(s->has_ssm_pay_head_len){ - set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; + + unsigned char out[SSM2_PAY_len]; + size_t outLen = SSM2_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_buffer); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + set_SSM2_BUFF_unk(out, !s->buffermode); + set_SSM2_BUFF_unk2(out, 0x40); + set_SSM2_BUFF_sync(out, !s->buffermode); + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); } - set_SSM_page_code(out, SM_pc_buffer); - set_SSM_page_len(out, SSM_PAGE_len); - if(s->s.source == SOURCE_ADF_DUPLEX){ - set_SSM_BUFF_duplex(out, 1); - } - else if(s->s.source == SOURCE_FLATBED){ - set_SSM_BUFF_fb(out, 1); - } - if(s->buffermode){ - set_SSM_BUFF_async(out, 1); - } - if(0){ - set_SSM_BUFF_ald(out, 1); - } - if(0){ - set_SSM_BUFF_unk(out,1); + else{ + DBG (10, "ssm_buffer: unsupported\n"); } - ret = do_cmd ( - s, 1, 0, - cmd, cmdLen, - out, outLen, - NULL, NULL - ); - DBG (10, "ssm_buffer: finish\n"); return ret; @@ -2895,57 +3214,118 @@ ssm_df (struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; - unsigned char cmd[SET_SCAN_MODE_len]; - size_t cmdLen = SET_SCAN_MODE_len; - - unsigned char out[SSM_PAY_len]; - size_t outLen = SSM_PAY_len; - DBG (10, "ssm_df: start\n"); - - if(!s->has_ssm || !s->has_df){ + + if(!s->has_df){ DBG (10, "ssm_df: unsupported, finishing\n"); return ret; } + + if(s->has_ssm){ - memset(cmd,0,cmdLen); - set_SCSI_opcode(cmd, SET_SCAN_MODE_code); - set_SSM_pf(cmd, 1); - set_SSM_pay_len(cmd, outLen); + unsigned char cmd[SET_SCAN_MODE_len]; + size_t cmdLen = SET_SCAN_MODE_len; + + unsigned char out[SSM_PAY_len]; + size_t outLen = SSM_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE_code); + set_SSM_pf(cmd, 1); + set_SSM_pay_len(cmd, outLen); + + memset(out,0,outLen); + if(s->has_ssm_pay_head_len){ + set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); + } + set_SSM_page_code(out, SM_pc_df); + set_SSM_page_len(out, SSM_PAGE_len); + + /* deskew by roller */ + if(s->rollerdeskew){ + set_SSM_DF_deskew_roll(out, 1); + } + + /* staple detection */ + if(s->stapledetect){ + set_SSM_DF_staple(out, 1); + } + + /* thickness */ + if(s->df_thickness){ + set_SSM_DF_thick(out, 1); + } + + /* length */ + if(s->df_length){ + set_SSM_DF_len(out, 1); + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); - memset(out,0,outLen); - if(s->has_ssm_pay_head_len){ - set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); } - set_SSM_page_code(out, SM_pc_df); - set_SSM_page_len(out, SSM_PAGE_len); - /* deskew by roller */ - if(s->rollerdeskew){ - set_SSM_DF_deskew_roll(out, 1); - } + else if(s->has_ssm2){ + + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; - /* staple detection */ - if(s->stapledetect){ - set_SSM_DF_staple(out, 1); - } + unsigned char out[SSM2_PAY_len]; + size_t outLen = SSM2_PAY_len; + + /* send ultrasonic offsets first */ + if(s->df_thickness && s->has_df_ultra){ + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_ultra); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + set_SSM2_ULTRA_top(out, 0); + set_SSM2_ULTRA_bot(out, 0); + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); + } - /* thickness */ - if(s->df_thickness){ - set_SSM_DF_thick(out, 1); - } + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_df); + set_SSM2_pay_len(cmd, outLen); - /* length */ - if(s->df_length){ - set_SSM_DF_len(out, 1); + memset(out,0,outLen); + + /* thickness */ + if(s->df_thickness){ + set_SSM2_DF_thick(out, 1); + } + + /* length */ + if(s->df_length){ + set_SSM2_DF_len(out, 1); + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); + } - ret = do_cmd ( - s, 1, 0, - cmd, cmdLen, - out, outLen, - NULL, NULL - ); + else{ + DBG (10, "ssm_df: unsupported\n"); + } DBG (10, "ssm_df: finish\n"); @@ -2957,140 +3337,203 @@ ssm_do (struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; - unsigned char cmd[SET_SCAN_MODE_len]; - size_t cmdLen = SET_SCAN_MODE_len; + DBG (10, "ssm_do: start\n"); - unsigned char out[SSM_PAY_len]; - size_t outLen = SSM_PAY_len; + if(!s->can_color){ + DBG (10, "ssm_do: unsupported, finishing\n"); + return ret; + } + + if(s->has_ssm){ - DBG (10, "ssm_do: start\n"); + unsigned char cmd[SET_SCAN_MODE_len]; + size_t cmdLen = SET_SCAN_MODE_len; + + unsigned char out[SSM_PAY_len]; + size_t outLen = SSM_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE_code); + set_SSM_pf(cmd, 1); + set_SSM_pay_len(cmd, outLen); + + memset(out,0,outLen); + if(s->has_ssm_pay_head_len){ + set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); + } + set_SSM_page_code(out, SM_pc_dropout); + set_SSM_page_len(out, SSM_PAGE_len); + + set_SSM_DO_unk1(out, 0x03); + + switch(s->dropout_color_f){ + case COLOR_RED: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_do(out,SSM_DO_red); + break; + case COLOR_GREEN: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_do(out,SSM_DO_green); + break; + case COLOR_BLUE: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_do(out,SSM_DO_blue); + break; + case COLOR_EN_RED: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_en(out,SSM_DO_red); + break; + case COLOR_EN_GREEN: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_en(out,SSM_DO_green); + break; + case COLOR_EN_BLUE: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_f_en(out,SSM_DO_blue); + break; + } + + switch(s->dropout_color_b){ + case COLOR_RED: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_do(out,SSM_DO_red); + break; + case COLOR_GREEN: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_do(out,SSM_DO_green); + break; + case COLOR_BLUE: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_do(out,SSM_DO_blue); + break; + case COLOR_EN_RED: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_en(out,SSM_DO_red); + break; + case COLOR_EN_GREEN: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_en(out,SSM_DO_green); + break; + case COLOR_EN_BLUE: + set_SSM_DO_unk2(out, 0x05); + set_SSM_DO_b_en(out,SSM_DO_blue); + break; + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); - if(!s->has_ssm || !s->can_color){ - DBG (10, "ssm_do: unsupported, finishing\n"); - return ret; } - memset(cmd,0,cmdLen); - set_SCSI_opcode(cmd, SET_SCAN_MODE_code); - set_SSM_pf(cmd, 1); - set_SSM_pay_len(cmd, outLen); + else if(s->has_ssm2){ - memset(out,0,outLen); - if(s->has_ssm_pay_head_len){ - set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); - } - set_SSM_page_code(out, SM_pc_dropout); - set_SSM_page_len(out, SSM_PAGE_len); - - set_SSM_DO_unk1(out, 0x03); + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; + + unsigned char out[SSM2_PAY_len]; + size_t outLen = SSM2_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_dropout); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + + switch(s->dropout_color_f){ + case COLOR_RED: + set_SSM2_DO_do(out,SSM_DO_red); + break; + case COLOR_GREEN: + set_SSM2_DO_do(out,SSM_DO_green); + break; + case COLOR_BLUE: + set_SSM2_DO_do(out,SSM_DO_blue); + break; + case COLOR_EN_RED: + set_SSM2_DO_en(out,SSM_DO_red); + break; + case COLOR_EN_GREEN: + set_SSM2_DO_en(out,SSM_DO_green); + break; + case COLOR_EN_BLUE: + set_SSM2_DO_en(out,SSM_DO_blue); + break; + } - switch(s->dropout_color_f){ - case COLOR_RED: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_do(out,SSM_DO_red); - break; - case COLOR_GREEN: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_do(out,SSM_DO_green); - break; - case COLOR_BLUE: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_do(out,SSM_DO_blue); - break; - case COLOR_EN_RED: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_en(out,SSM_DO_red); - break; - case COLOR_EN_GREEN: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_en(out,SSM_DO_green); - break; - case COLOR_EN_BLUE: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_f_en(out,SSM_DO_blue); - break; + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); } - switch(s->dropout_color_b){ - case COLOR_RED: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_do(out,SSM_DO_red); - break; - case COLOR_GREEN: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_do(out,SSM_DO_green); - break; - case COLOR_BLUE: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_do(out,SSM_DO_blue); - break; - case COLOR_EN_RED: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_en(out,SSM_DO_red); - break; - case COLOR_EN_GREEN: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_en(out,SSM_DO_green); - break; - case COLOR_EN_BLUE: - set_SSM_DO_unk2(out, 0x05); - set_SSM_DO_b_en(out,SSM_DO_blue); - break; + else{ + DBG (10, "ssm_do: unsupported\n"); } - ret = do_cmd ( - s, 1, 0, - cmd, cmdLen, - out, outLen, - NULL, NULL - ); - DBG (10, "ssm_do: finish\n"); return ret; } -/* used by recent scanners. meaning of payloads unknown */ static SANE_Status -ssm2 (struct scanner *s) +read_sensors(struct scanner *s,SANE_Int option) { - SANE_Status ret = SANE_STATUS_GOOD; - - unsigned char cmd[SET_SCAN_MODE2_len]; - size_t cmdLen = SET_SCAN_MODE2_len; + SANE_Status ret=SANE_STATUS_GOOD; - unsigned char out[SSM2_PAY_len]; - size_t outLen = SSM2_PAY_len; + unsigned char cmd[READ_len]; + size_t cmdLen = READ_len; - DBG (10, "ssm2:start\n"); + unsigned char in[R_SENSORS_len]; + size_t inLen = R_SENSORS_len; - if(!s->has_ssm2){ - DBG (10, "ssm2: unsupported, finishing\n"); + DBG (10, "read_sensors: start %d\n", option); + + if(!s->can_read_sensors){ + DBG (10, "read_sensors: unsupported, finishing\n"); return ret; } - memset(cmd,0,cmdLen); - set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); - /*FIXME: set this correctly */ - set_SSM2_page_code(cmd, 0); - set_SSM2_pay_len(cmd, outLen); + /* only run this if frontend has already read the last time we got it */ + /* or if we don't care for such bookkeeping (private use) */ + if (!option || !s->sensors_read[option-OPT_ADF_LOADED]) { - /*FIXME: set these correctly */ - memset(out,0,outLen); - set_SSM2_unk(out, 0); - set_SSM2_unk2(out, 0); - set_SSM2_unk3(out, 0); + DBG (15, "read_sensors: running\n"); - /* - ret = do_cmd ( + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, READ_code); + set_R_datatype_code (cmd, SR_datatype_sensors); + set_R_xfer_length (cmd, inLen); + + ret = do_cmd ( s, 1, 0, cmd, cmdLen, - out, outLen, - NULL, NULL - );*/ + NULL, 0, + in, &inLen + ); + + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { + /*set flags indicating there is data to read*/ + memset(s->sensors_read,1,sizeof(s->sensors_read)); - DBG (10, "ssm2: finish\n"); + s->sensor_adf_loaded = get_R_SENSORS_adf(in); + s->sensor_card_loaded = get_R_SENSORS_card(in); + ret = SANE_STATUS_GOOD; + } + } + + if(option) + s->sensors_read[option-OPT_ADF_LOADED] = 0; + + DBG (10, "read_sensors: finish\n"); + return ret; } @@ -3112,9 +3555,9 @@ read_panel(struct scanner *s,SANE_Int option) return ret; } - /* only run this if frontend has read previous value - * or if the caller does not want the data stored */ - if (!option || !s->hw_read[option-OPT_START]) { + /* only run this if frontend has already read the last time we got it */ + /* or if we don't care for such bookkeeping (private use) */ + if (!option || !s->panel_read[option-OPT_START]) { DBG (15, "read_panel: running\n"); @@ -3132,8 +3575,7 @@ read_panel(struct scanner *s,SANE_Int option) if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { /*set flags indicating there is data to read*/ - if(option) - memset(s->hw_read,1,sizeof(s->hw_read)); + memset(s->panel_read,1,sizeof(s->panel_read)); s->panel_start = get_R_PANEL_start(in); s->panel_stop = get_R_PANEL_stop(in); @@ -3143,12 +3585,13 @@ read_panel(struct scanner *s,SANE_Int option) s->panel_bypass_mode = get_R_PANEL_bypass_mode(in); s->panel_enable_led = get_R_PANEL_enable_led(in); s->panel_counter = get_R_PANEL_counter(in); + ret = SANE_STATUS_GOOD; } } if(option) - s->hw_read[option-OPT_START] = 0; + s->panel_read[option-OPT_START] = 0; DBG (10, "read_panel: finish %d\n",s->panel_counter); @@ -3294,14 +3737,12 @@ update_params(struct scanner *s, int calib) /* round down to pixel boundary for some scanners */ s->u.width -= s->u.width % s->ppl_mod; -#ifdef SANE_FRAME_JPEG /* jpeg requires 8x8 squares */ if(s->compress == COMP_JPEG && s->u.mode >= MODE_GRAYSCALE){ s->u.format = SANE_FRAME_JPEG; s->u.width -= s->u.width % 8; s->u.height -= s->u.height % 8; } -#endif s->u.Bpl = s->u.width * s->u.bpp / 8; s->u.valid_Bpl = s->u.Bpl; @@ -3396,7 +3837,8 @@ update_params(struct scanner *s, int calib) } /* some scanners need longer scans because front/back is offset */ - if(s->u.source == SOURCE_ADF_DUPLEX && s->duplex_offset && !calib) + if((s->u.source == SOURCE_ADF_DUPLEX || s->u.source == SOURCE_CARD_DUPLEX) + && s->duplex_offset && !calib) s->s.height = (s->u.br_y-s->u.tl_y+s->duplex_offset) * s->u.dpi_y / 1200; /* round lines up to even number */ @@ -3421,7 +3863,7 @@ update_params(struct scanner *s, int calib) else{ memcpy(&s->i,&s->u,sizeof(struct img_params)); /*dumb scanners pad the top of front page in duplex*/ - if(s->i.source == SOURCE_ADF_DUPLEX) + if(s->i.source == SOURCE_ADF_DUPLEX || s->i.source == SOURCE_CARD_DUPLEX) s->i.skip_lines[s->duplex_offset_side] = s->duplex_offset * s->i.dpi_y / 1200; } @@ -3485,7 +3927,7 @@ sane_start (SANE_Handle handle) if(!s->started){ /* load side marker */ - if(s->u.source == SOURCE_ADF_BACK){ + if(s->u.source == SOURCE_ADF_BACK || s->u.source == SOURCE_CARD_BACK){ s->side = SIDE_BACK; } else{ @@ -3549,7 +3991,7 @@ sane_start (SANE_Handle handle) goto errors; } - /* buffer/duplex/ald command */ + /* buffer/duplex/ald/fb/card command */ ret = ssm_buffer(s); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: cannot ssm buffer\n"); @@ -3591,18 +4033,21 @@ sane_start (SANE_Handle handle) goto errors; } - /* grab next page */ - ret = object_position (s, SANE_TRUE); - if (ret != SANE_STATUS_GOOD) { - DBG (5, "sane_start: ERROR: cannot load page\n"); - goto errors; - } - - /* wait for scanner to finish load */ - ret = wait_scanner (s); - if (ret != SANE_STATUS_GOOD) { - DBG (5, "sane_start: ERROR: cannot wait scanner\n"); - goto errors; + /* card reader dislikes op? */ + if(s->s.source < SOURCE_CARD_FRONT){ + /* grab next page */ + ret = object_position (s, SANE_TRUE); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot load page\n"); + goto errors; + } + + /* wait for scanner to finish load */ + ret = wait_scanner (s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot wait scanner\n"); + goto errors; + } } /* start scanning */ @@ -3619,7 +4064,7 @@ sane_start (SANE_Handle handle) else{ /* duplex needs to switch sides */ - if(s->s.source == SOURCE_ADF_DUPLEX){ + if(s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX){ s->side = !s->side; } @@ -3635,7 +4080,7 @@ sane_start (SANE_Handle handle) /* otherwise buffered back page will be lost */ /* ingest paper with adf (no-op for fb) */ /* dont call object pos or scan on back side of duplex scan */ - if(s->side == SIDE_FRONT || s->s.source == SOURCE_ADF_BACK){ + if(s->side == SIDE_FRONT || s->s.source == SOURCE_ADF_BACK || s->s.source == SOURCE_CARD_BACK){ /* clean scan params for new scan */ ret = clean_params(s); @@ -3694,9 +4139,7 @@ sane_start (SANE_Handle handle) * API has no way to inform the frontend of this, * so we block and buffer. yuck */ if( (s->swdeskew || s->swdespeck || s->swcrop) -#ifdef SANE_FRAME_JPEG && s->s.format != SANE_FRAME_JPEG -#endif ){ /* get image */ @@ -3772,23 +4215,26 @@ clean_params (struct scanner *s) s->s.bytes_tot[1]=0; /* store the number of front bytes */ - if ( s->u.source != SOURCE_ADF_BACK ) + if ( s->u.source != SOURCE_ADF_BACK && s->u.source != SOURCE_CARD_BACK ) s->u.bytes_tot[SIDE_FRONT] = s->u.Bpl * s->u.height; - if ( s->i.source != SOURCE_ADF_BACK ) + if ( s->i.source != SOURCE_ADF_BACK && s->i.source != SOURCE_CARD_BACK ) s->i.bytes_tot[SIDE_FRONT] = s->i.Bpl * s->i.height; - if ( s->s.source != SOURCE_ADF_BACK ) + if ( s->s.source != SOURCE_ADF_BACK && s->s.source != SOURCE_CARD_BACK ) s->s.bytes_tot[SIDE_FRONT] = s->s.Bpl * s->s.height; /* store the number of back bytes */ - if ( s->u.source == SOURCE_ADF_DUPLEX || s->u.source == SOURCE_ADF_BACK ) + if ( s->u.source == SOURCE_ADF_DUPLEX || s->u.source == SOURCE_ADF_BACK + || s->u.source == SOURCE_CARD_DUPLEX || s->u.source == SOURCE_CARD_BACK ) s->u.bytes_tot[SIDE_BACK] = s->u.Bpl * s->u.height; - if ( s->i.source == SOURCE_ADF_DUPLEX || s->i.source == SOURCE_ADF_BACK ) + if ( s->i.source == SOURCE_ADF_DUPLEX || s->i.source == SOURCE_ADF_BACK + || s->i.source == SOURCE_CARD_DUPLEX || s->i.source == SOURCE_CARD_BACK ) s->i.bytes_tot[SIDE_BACK] = s->i.Bpl * s->i.height; - if ( s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_ADF_BACK ) + if ( s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_ADF_BACK + || s->s.source == SOURCE_CARD_DUPLEX || s->s.source == SOURCE_CARD_BACK ) s->s.bytes_tot[SIDE_BACK] = s->s.Bpl * s->s.height; DBG (10, "clean_params: finish\n"); @@ -3863,7 +4309,7 @@ set_window (struct scanner *s) set_WPDB_wdblen(header, SW_desc_len); /* init the window block */ - if (s->s.source == SOURCE_ADF_BACK) { + if (s->s.source == SOURCE_ADF_BACK || s->s.source == SOURCE_CARD_BACK) { set_WD_wid (desc1, WD_wid_back); } else{ @@ -3933,13 +4379,11 @@ set_window (struct scanner *s) set_WD_compress_type(desc1, COMP_NONE); set_WD_compress_arg(desc1, 0); -#ifdef SANE_FRAME_JPEG /* some scanners support jpeg image compression, for color/gs only */ if(s->s.format == SANE_FRAME_JPEG){ set_WD_compress_type(desc1, COMP_JPEG); set_WD_compress_arg(desc1, s->compress_arg); } -#endif /*build the command*/ memset(cmd,0,cmdLen); @@ -3953,7 +4397,7 @@ set_window (struct scanner *s) NULL, NULL ); - if (!ret && s->s.source == SOURCE_ADF_DUPLEX) { + if (!ret && (s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX)) { set_WD_wid (desc1, WD_wid_back); ret = do_cmd ( s, 1, 0, @@ -4037,9 +4481,9 @@ start_scan (struct scanner *s, int type) out[1] = type; } - if (s->s.source != SOURCE_ADF_DUPLEX) { + if (s->s.source != SOURCE_ADF_DUPLEX && s->s.source != SOURCE_CARD_DUPLEX) { outLen--; - if(s->s.source == SOURCE_ADF_BACK) { + if(s->s.source == SOURCE_ADF_BACK || s->s.source == SOURCE_CARD_BACK) { out[0] = WD_wid_back; } } @@ -4100,7 +4544,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len s->reading = 1; /* double width pnm interlacing */ - if(s->s.source == SOURCE_ADF_DUPLEX + if((s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX) && s->s.format <= SANE_FRAME_RGB && s->duplex_interlace != DUPLEX_INTERLACE_NONE ){ @@ -4225,7 +4669,6 @@ read_from_scanner(struct scanner *s, int side, int exact) inLen = 0; } -#ifdef SANE_FRAME_JPEG /* this is jpeg data, we need to fix the missing image size */ if(s->s.format == SANE_FRAME_JPEG){ @@ -4275,7 +4718,6 @@ read_from_scanner(struct scanner *s, int side, int exact) } } } -#endif /*scanner may have sent more data than we asked for, chop it*/ if(inLen > remain){ @@ -4301,37 +4743,32 @@ read_from_scanner(struct scanner *s, int side, int exact) if(ret == SANE_STATUS_EOF){ - switch (s->s.format){ + /* this is jpeg data, we need to change the total size */ + if(s->s.format == SANE_FRAME_JPEG){ + s->s.bytes_tot[side] = s->s.bytes_sent[side]; + s->i.bytes_tot[side] = s->i.bytes_sent[side]; + s->u.bytes_tot[side] = s->i.bytes_sent[side]; + } -#ifdef SANE_FRAME_JPEG - /* this is jpeg data, we need to change the total size */ - case SANE_FRAME_JPEG: - s->s.bytes_tot[side] = s->s.bytes_sent[side]; - s->i.bytes_tot[side] = s->i.bytes_sent[side]; - s->u.bytes_tot[side] = s->i.bytes_sent[side]; - break; -#endif - - /* this is non-jpeg data, fill remainder, change rx'd size */ - default: + /* this is non-jpeg data, fill remainder, change rx'd size */ + else{ - DBG (15, "read_from_scanner: eof: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); + DBG (15, "read_from_scanner: eof: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[side] > s->i.bytes_sent[side]){ - memcpy( - s->buffers[side]+s->i.bytes_sent[side]-s->i.Bpl, - s->buffers[side]+s->i.bytes_sent[side], - s->i.Bpl - ); - s->i.bytes_sent[side] += s->i.Bpl; - } + /* clone the last line repeatedly until the end */ + while(s->i.bytes_tot[side] > s->i.bytes_sent[side]){ + memcpy( + s->buffers[side]+s->i.bytes_sent[side]-s->i.Bpl, + s->buffers[side]+s->i.bytes_sent[side], + s->i.Bpl + ); + s->i.bytes_sent[side] += s->i.Bpl; + } - DBG (15, "read_from_scanner: eof2: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); + DBG (15, "read_from_scanner: eof2: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); - /* pretend we got all the data from scanner */ - s->s.bytes_sent[side] = s->s.bytes_tot[side]; - break; + /* pretend we got all the data from scanner */ + s->s.bytes_sent[side] = s->s.bytes_tot[side]; } s->i.eof[side] = 1; @@ -4441,57 +4878,52 @@ read_from_scanner_duplex(struct scanner *s,int exact) if(ret == SANE_STATUS_EOF){ - switch (s->s.format){ - -#ifdef SANE_FRAME_JPEG - /* this is jpeg data, we need to change the total size */ - case SANE_FRAME_JPEG: - s->s.bytes_tot[SIDE_FRONT] = s->s.bytes_sent[SIDE_FRONT]; - s->s.bytes_tot[SIDE_BACK] = s->s.bytes_sent[SIDE_BACK]; - s->i.bytes_tot[SIDE_FRONT] = s->i.bytes_sent[SIDE_FRONT]; - s->i.bytes_tot[SIDE_BACK] = s->i.bytes_sent[SIDE_BACK]; - s->u.bytes_tot[SIDE_FRONT] = s->i.bytes_sent[SIDE_FRONT]; - s->u.bytes_tot[SIDE_BACK] = s->i.bytes_sent[SIDE_BACK]; - break; -#endif - - /* this is non-jpeg data, fill remainder, change rx'd size */ - default: + /* this is jpeg data, we need to change the total size */ + if(s->s.format == SANE_FRAME_JPEG){ + s->s.bytes_tot[SIDE_FRONT] = s->s.bytes_sent[SIDE_FRONT]; + s->s.bytes_tot[SIDE_BACK] = s->s.bytes_sent[SIDE_BACK]; + s->i.bytes_tot[SIDE_FRONT] = s->i.bytes_sent[SIDE_FRONT]; + s->i.bytes_tot[SIDE_BACK] = s->i.bytes_sent[SIDE_BACK]; + s->u.bytes_tot[SIDE_FRONT] = s->i.bytes_sent[SIDE_FRONT]; + s->u.bytes_tot[SIDE_BACK] = s->i.bytes_sent[SIDE_BACK]; + } - DBG (15, "read_from_scanner_duplex: eof: %d %d %d %d\n", - s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], - s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] - ); + /* this is non-jpeg data, fill remainder, change rx'd size */ + else{ - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[SIDE_FRONT] > s->i.bytes_sent[SIDE_FRONT]){ - memcpy( - s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT]-s->i.Bpl, - s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT], - s->i.Bpl - ); - s->i.bytes_sent[SIDE_FRONT] += s->i.Bpl; - } + DBG (15, "read_from_scanner_duplex: eof: %d %d %d %d\n", + s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], + s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] + ); - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[SIDE_BACK] > s->i.bytes_sent[SIDE_BACK]){ - memcpy( - s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK]-s->i.Bpl, - s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK], - s->i.Bpl - ); - s->i.bytes_sent[SIDE_BACK] += s->i.Bpl; - } + /* clone the last line repeatedly until the end */ + while(s->i.bytes_tot[SIDE_FRONT] > s->i.bytes_sent[SIDE_FRONT]){ + memcpy( + s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT]-s->i.Bpl, + s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT], + s->i.Bpl + ); + s->i.bytes_sent[SIDE_FRONT] += s->i.Bpl; + } - DBG (15, "read_from_scanner_duplex: eof2: %d %d %d %d\n", - s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], - s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] + /* clone the last line repeatedly until the end */ + while(s->i.bytes_tot[SIDE_BACK] > s->i.bytes_sent[SIDE_BACK]){ + memcpy( + s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK]-s->i.Bpl, + s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK], + s->i.Bpl ); + s->i.bytes_sent[SIDE_BACK] += s->i.Bpl; + } - /* pretend we got all the data from scanner */ - s->s.bytes_sent[SIDE_FRONT] = s->s.bytes_tot[SIDE_FRONT]; - s->s.bytes_sent[SIDE_BACK] = s->s.bytes_tot[SIDE_BACK]; - break; + DBG (15, "read_from_scanner_duplex: eof2: %d %d %d %d\n", + s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], + s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] + ); + + /* pretend we got all the data from scanner */ + s->s.bytes_sent[SIDE_FRONT] = s->s.bytes_tot[SIDE_FRONT]; + s->s.bytes_sent[SIDE_BACK] = s->s.bytes_tot[SIDE_BACK]; } s->i.eof[SIDE_FRONT] = 1; @@ -4522,6 +4954,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) unsigned char * line = NULL; int line_next = 0; + int inter = get_color_inter(s,side,s->s.dpi_x); /* jpeg data should not pass thru this function, so copy and bail out */ if(s->s.format > SANE_FRAME_RGB){ @@ -4592,7 +5025,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) else if (s->s.format == SANE_FRAME_RGB){ - switch (s->color_interlace[side]) { + switch (inter) { /* scanner returns color data as bgrbgr... */ case COLOR_INTERLACE_BGR: @@ -4604,6 +5037,26 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) } break; + /* scanner returns color data as gbrgbr... */ + case COLOR_INTERLACE_GBR: + DBG (17, "copy_simplex: color, GBR\n"); + for (j=0; j<pwidth; j++){ + line[line_next++] = buf[i+j*3+2]; + line[line_next++] = buf[i+j*3]; + line[line_next++] = buf[i+j*3+1]; + } + break; + + /* scanner returns color data as brgbrg... */ + case COLOR_INTERLACE_BRG: + DBG (17, "copy_simplex: color, BRG\n"); + for (j=0; j<pwidth; j++){ + line[line_next++] = buf[i+j*3+1]; + line[line_next++] = buf[i+j*3+2]; + line[line_next++] = buf[i+j*3]; + } + break; + /* one line has the following format: RRR...rrrGGG...gggBBB...bbb */ case COLOR_INTERLACE_RRGGBB: DBG (17, "copy_simplex: color, RRGGBB\n"); @@ -4768,7 +5221,7 @@ copy_duplex(struct scanner *s, unsigned char * buf, int len) } } - /* no scanners use this? */ + /* full line of front, then full line of back */ else if(s->duplex_interlace == DUPLEX_INTERLACE_FFBB){ for(i=0; i<len; i+=dbwidth){ memcpy(front+flen,buf+i,bwidth); @@ -4877,7 +5330,7 @@ copy_line(struct scanner *s, unsigned char * buff, int side) /* scan is wider than user wanted, skip some pixels on left side */ if(s->i.width != s->s.width){ - offset = ((s->valid_x-s->i.page_x) / 2 + s->i.tl_x) * s->i.dpi_x/1200*3; + offset = ((s->valid_x-s->i.page_x) / 2 + s->i.tl_x) * s->i.dpi_x/1200; } /* change mode, store line in buffer */ @@ -4905,7 +5358,7 @@ copy_line(struct scanner *s, unsigned char * buff, int side) /*loop over output bits*/ for(j=0;j<8;j++){ - int source = (offset+i)*24 + j*3; + int source = offset*3 + i*24 + j*3; if( (line[source] + line[source+1] + line[source+2]) < thresh ){ curr |= 1 << (7-j); } @@ -5967,6 +6420,7 @@ default_globals(void) { global_buffer_size = global_buffer_size_default; global_padded_read = global_padded_read_default; + global_extra_status = global_extra_status_default; global_duplex_offset = global_duplex_offset_default; global_vendor_name[0] = 0; global_model_name[0] = 0; @@ -6252,7 +6706,6 @@ do_scsi_cmd(struct scanner *s, int runRS, int shortTime, ) { int ret; - size_t actLen = 0; /*shut up compiler*/ runRS=runRS; @@ -6270,7 +6723,6 @@ do_scsi_cmd(struct scanner *s, int runRS, int shortTime, if (inBuff && inLen){ DBG(25, "in: reading %d bytes\n", (int)*inLen); memset(inBuff,0,*inLen); - actLen = *inLen; } ret = sanei_scsi_cmd2(s->fd, cmdBuff, cmdLen, outBuff, outLen, inBuff, inLen); @@ -6285,7 +6737,7 @@ do_scsi_cmd(struct scanner *s, int runRS, int shortTime, DBG(25, "in: short read, remainder %lu bytes\n", (u_long)s->rs_info); *inLen -= s->rs_info; } - hexdump(30, "in: <<", inBuff, *inLen); + hexdump(31, "in: <<", inBuff, *inLen); DBG(25, "in: read %d bytes\n", (int)*inLen); } @@ -6319,16 +6771,15 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, unsigned char * inBuffer = NULL; int inTimeout = 0; - size_t statOffset = 0; - size_t statLength = 0; - size_t statActual = 0; - unsigned char * statBuffer = NULL; - int statTimeout = 0; + size_t extraLength = 0; int ret = 0; int ret2 = 0; - DBG (10, "do_usb_cmd: start\n"); + struct timeval timer; + gettimeofday(&timer,NULL); + + DBG (10, "do_usb_cmd: start %lu %lu\n", (long unsigned int)timer.tv_sec, (long unsigned int)timer.tv_usec); /****************************************************************/ /* the command stage */ @@ -6376,6 +6827,20 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, } /****************************************************************/ + /* the extra status stage, used by few scanners */ + /* this is like the regular status block, with an additional */ + /* length component at the end */ + if(s->extra_status){ + ret2 = do_usb_status(s,runRS,shortTime,&extraLength); + + /* bail out on bad RS status */ + if(ret2){ + DBG(5,"extra: bad RS status, %d\n", ret2); + return ret2; + } + } + + /****************************************************************/ /* the output stage */ if(outBuff && outLen){ @@ -6432,6 +6897,12 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, inLength = inOffset+*inLen; inActual = inLength; + /* use the extra length to alter the amount of in we request */ + if(s->extra_status && extraLength && *inLen > extraLength){ + DBG(5,"in: adjust extra, %d %d\n", (int)*inLen, (int)extraLength); + inActual = inOffset+extraLength; + } + /*blast caller's copy in case we error out*/ *inLen = 0; @@ -6443,16 +6914,16 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, sanei_usb_set_timeout(inTimeout); /* build inBuffer */ - inBuffer = calloc(inLength,1); + inBuffer = calloc(inActual,1); if(!inBuffer){ DBG(5,"in: no mem\n"); return SANE_STATUS_NO_MEM; } - DBG(25, "in: reading %d bytes, timeout %d\n", (int)inLength, inTimeout); + DBG(25, "in: reading %d bytes, timeout %d\n", (int)inActual, inTimeout); ret = sanei_usb_read_bulk(s->fd, inBuffer, &inActual); DBG(25, "in: read %d bytes, retval %d\n", (int)inActual, ret); - hexdump(30, "in: <<", inBuffer, inActual); + hexdump(31, "in: <<", inBuffer, inActual); if(!inActual){ DBG(5,"in: got no data, clearing\n"); @@ -6474,49 +6945,8 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, } /****************************************************************/ - /* the status stage */ - statOffset = 0; - if(s->padded_read) - statOffset = USB_HEADER_LEN; - - statLength = statOffset+USB_STATUS_LEN; - statActual = statLength; - statTimeout = USB_STATUS_TIME; - - /* change timeout */ - if(shortTime) - statTimeout/=60; - sanei_usb_set_timeout(statTimeout); - - /* build statBuffer */ - statBuffer = calloc(statLength,1); - if(!statBuffer){ - DBG(5,"stat: no mem\n"); - if(inBuffer) free(inBuffer); - return SANE_STATUS_NO_MEM; - } - - DBG(25, "stat: reading %d bytes, timeout %d\n", (int)statLength, statTimeout); - ret2 = sanei_usb_read_bulk(s->fd, statBuffer, &statActual); - DBG(25, "stat: read %d bytes, retval %d\n", (int)statActual, ret2); - hexdump(30, "stat: <<", statBuffer, statActual); - - /*weird status*/ - if(ret2 != SANE_STATUS_GOOD){ - DBG(5,"stat: clearing error '%s'\n",sane_strstatus(ret2)); - ret2 = do_usb_clear(s,1,runRS); - } - /*short read*/ - else if(statLength != statActual){ - DBG(5,"stat: clearing short %d/%d\n",(int)statLength,(int)statActual); - ret2 = do_usb_clear(s,1,runRS); - } - /*inspect the last byte of the status response*/ - else if(statBuffer[statLength-1]){ - DBG(5,"stat: status %d\n",statBuffer[statLength-1]); - ret2 = do_usb_clear(s,0,runRS); - } - free(statBuffer); + /* the normal status stage */ + ret2 = do_usb_status(s,runRS,shortTime,&extraLength); /* if status said EOF, adjust input with remainder count */ if(ret2 == SANE_STATUS_EOF && inBuffer){ @@ -6524,11 +6954,11 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, /* EOF is ok */ ret2 = SANE_STATUS_GOOD; - if(inActual <= inLength - s->rs_info){ - DBG(5,"in: we read <= RS, ignoring RS: %d <= %d (%d-%d)\n", + if(inActual < inLength - s->rs_info){ + DBG(5,"in: we read < RS, ignoring RS: %d < %d (%d-%d)\n", (int)inActual,(int)(inLength-s->rs_info),(int)inLength,(int)s->rs_info); } - else if(s->rs_info){ + else if(inActual > inLength - s->rs_info){ DBG(5,"in: we read > RS, using RS: %d to %d (%d-%d)\n", (int)inActual,(int)(inLength-s->rs_info),(int)inLength,(int)s->rs_info); inActual = inLength - s->rs_info; @@ -6556,7 +6986,80 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, free(inBuffer); } - DBG (10, "do_usb_cmd: finish\n"); + gettimeofday(&timer,NULL); + + DBG (10, "do_usb_cmd: finish %lu %lu\n", (long unsigned int)timer.tv_sec, (long unsigned int)timer.tv_usec); + + return ret; +} + +static SANE_Status +do_usb_status(struct scanner *s, int runRS, int shortTime, size_t * extraLength) +{ + +#define EXTRA_READ_len 4 + + size_t statPadding = 0; + size_t statOffset = 0; + size_t statLength = 0; + size_t statActual = 0; + unsigned char * statBuffer = NULL; + int statTimeout = 0; + + int ret = 0; + + if(s->padded_read) + statPadding = USB_HEADER_LEN; + + statLength = statPadding+USB_STATUS_LEN; + statOffset = statLength-1; + + if(s->extra_status) + statLength += EXTRA_READ_len; + + statActual = statLength; + statTimeout = USB_STATUS_TIME; + + /* change timeout */ + if(shortTime) + statTimeout/=60; + sanei_usb_set_timeout(statTimeout); + + /* build statBuffer */ + statBuffer = calloc(statLength,1); + if(!statBuffer){ + DBG(5,"stat: no mem\n"); + return SANE_STATUS_NO_MEM; + } + + DBG(25, "stat: reading %d bytes, timeout %d\n", (int)statLength, statTimeout); + ret = sanei_usb_read_bulk(s->fd, statBuffer, &statActual); + DBG(25, "stat: read %d bytes, retval %d\n", (int)statActual, ret); + hexdump(30, "stat: <<", statBuffer, statActual); + + /*weird status*/ + if(ret != SANE_STATUS_GOOD){ + DBG(5,"stat: clearing error '%s'\n",sane_strstatus(ret)); + ret = do_usb_clear(s,1,runRS); + } + /*short read*/ + else if(statLength != statActual){ + DBG(5,"stat: clearing short %d/%d\n",(int)statLength,(int)statActual); + ret = do_usb_clear(s,1,runRS); + } + /*inspect the status byte of the response*/ + else if(statBuffer[statOffset]){ + DBG(5,"stat: status %d\n",statBuffer[statLength-1-4]); + ret = do_usb_clear(s,0,runRS); + } + + /*extract the extra length byte of the response*/ + if(s->extra_status){ + *extraLength = get_ES_length(statBuffer); + DBG(15,"stat: extra %d\n",(int)*extraLength); + } + + free(statBuffer); return ret; } @@ -6670,6 +7173,26 @@ wait_scanner(struct scanner *s) return ret; } +/* Some scanners have per-resolution + * color interlacing values, but most + * don't. This helper can tell the + * difference. + */ +static int +get_color_inter(struct scanner *s, int side, int res) +{ + int i; + for(i=0;i<DPI_1200;i++){ + if(res == dpi_list[i]) + break; + } + + if(s->color_inter_by_res[i]) + return s->color_inter_by_res[i]; + + return s->color_interlace[side]; +} + /* s->u.page_x stores the user setting * for the paper width in adf. sometimes, * we need a value that differs from this @@ -6789,7 +7312,8 @@ hexdump (int level, char *comment, unsigned char *p, int l) } /* print last (partial) line */ - DBG (level, "%s\n", line); + if (i) + DBG (level, "%s\n", line); } /** |