diff options
Diffstat (limited to 'backend/canon_dr.c')
| -rw-r--r-- | backend/canon_dr.c | 1191 | 
1 files changed, 824 insertions, 367 deletions
| diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 594aab2..15dcc59 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -276,10 +276,39 @@           - 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     SANE FLOW DIAGRAM @@ -317,6 +346,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 +358,7 @@  #include "canon_dr.h"  #define DEBUG 1 -#define BUILD 41 +#define BUILD 48  /* values for SANE_DEBUG_CANON_DR env var:   - errors           5 @@ -336,15 +366,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 +406,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 +585,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 +801,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 +1229,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 +1263,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 +1273,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 +1440,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 +1456,90 @@ 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;    }    DBG (10, "init_model: finish\n"); @@ -1435,6 +1593,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 +1788,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 +2011,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 +2038,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 +2155,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 +2478,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 +2576,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 +2784,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 +2841,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 +3058,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 +3147,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); +   +    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); +    } -  /* length */ -  if(s->df_length){ -    set_SSM_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 +3270,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); - -  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); +  else if(s->has_ssm2){ -  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 +3488,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 +3508,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 +3518,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 +3670,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 +3770,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 +3796,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 +3860,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 +3924,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 +3966,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 +3997,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 +4013,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 +4072,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 +4148,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 +4242,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 +4312,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 +4330,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 +4414,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 +4477,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 +4602,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 +4651,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 +4676,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 +4811,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 +4887,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 +4958,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 +4970,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 +5154,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 +5263,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 +5291,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 +6353,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 +6639,6 @@ do_scsi_cmd(struct scanner *s, int runRS, int shortTime,  )  {    int ret; -  size_t actLen = 0;    /*shut up compiler*/    runRS=runRS; @@ -6270,7 +6656,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 +6670,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 +6704,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 +6760,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 +6830,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 +6847,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 +6878,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 +6887,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 +6919,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 +7106,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 +7245,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);  }  /** | 
