diff options
| author | Jörg Frings-Fürst <debian@jff.email> | 2023-02-16 10:20:08 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff.email> | 2023-02-16 10:20:08 +0100 | 
| commit | 778ebf8ee9cb22ea5727844333bcd5a6ee6bc0de (patch) | |
| tree | a754e785b286ed82b45fe4e50b980714ad80e0a7 /backend/canon_dr.c | |
| parent | 7d8aac1f3634dc58785bec7acf097dd6bac8c394 (diff) | |
| parent | 32cb765f681299af226ca0520993cbe47ba5ecd0 (diff) | |
Merge branch 'release/debian/1.2.1-1'debian/1.2.1-1
Diffstat (limited to 'backend/canon_dr.c')
| -rw-r--r-- | backend/canon_dr.c | 937 | 
1 files changed, 929 insertions, 8 deletions
| diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 95799e7..58299d7 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -3,7 +3,7 @@     This file is part of the SANE package, and implements a SANE backend     for various Canon DR-series scanners. -   Copyright (C) 2008-2021 m. allan noah +   Copyright (C) 2008-2022 m. allan noah     Yabarana Corp. www.yabarana.com provided significant funding     EvriChart, Inc. www.evrichart.com provided funding and loaned equipment @@ -355,6 +355,10 @@           - rewrite do_cmd() timeout handling           - remove long timeout TUR from v61 (did not help)           - allow config file to set initial tur timeout for DR-X10C (#142) +      v63 2022-11-18, CQ, MAN +         - add support for reading the total and roller counters +      v64 2022-11-18, CQ, MAN +         - add complete support for imprinters on X10C (#585)     SANE FLOW DIAGRAM @@ -393,6 +397,7 @@  #include <math.h> /*tan*/  #include <unistd.h> /*usleep*/  #include <sys/time.h> /*gettimeofday*/ +#include <time.h> /*localtime*/  #include <stdlib.h> /*strtol*/  #include "../include/sane/sanei_backend.h" @@ -406,7 +411,7 @@  #include "canon_dr.h"  #define DEBUG 1 -#define BUILD 62 +#define BUILD 64  /* values for SANE_DEBUG_CANON_DR env var:   - errors           5 @@ -449,6 +454,13 @@  #define STRING_NONE SANE_I18N("None")  #define STRING_JPEG SANE_I18N("JPEG") +#define STRING_IMPRINTER_8x12_FONT SANE_I18N("8x12") +#define STRING_IMPRINTER_12x12_FONT SANE_I18N("12x12") + +#define STRING_IMPRINTER_ADDON_BoW SANE_I18N("Black-on-White") +#define STRING_IMPRINTER_ADDON_BoI SANE_I18N("Black-on-Image") +#define STRING_IMPRINTER_ADDON_WoB SANE_I18N("White-on-Black") +  /* Also set via config file. */  static int global_buffer_size;  static int global_buffer_size_default = 2 * 1024 * 1024; @@ -494,7 +506,7 @@ static struct scanner *scanner_devList = NULL;  SANE_Status  sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)  { -  authorize = authorize;        /* get rid of compiler warning */ +  (void) authorize;             /* get rid of compiler warning */    DBG_INIT ();    DBG (10, "sane_init: start\n"); @@ -547,7 +559,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)    int num_devices=0;    int i=0; -  local_only = local_only;        /* get rid of compiler warning */ +  (void) local_only;            /* get rid of compiler warning */    DBG (10, "sane_get_devices: start\n"); @@ -992,6 +1004,12 @@ attach_one (const char *device_name, int connType)      return ret;    } +  /* this detects imprinters if they are available */ +  ret = init_imprinters (s); +  if (ret != SANE_STATUS_GOOD) { +    DBG (5, "attach_one: errors while trying to detect optional imprinters, continuing\n"); +  } +    /* enable/read the buttons */    ret = init_panel (s);    if (ret != SANE_STATUS_GOOD) { @@ -1001,6 +1019,13 @@ attach_one (const char *device_name, int connType)      return ret;    } +  /* enable/read the lifecycle counters */ +  ret = init_counters (s); +  if (ret != SANE_STATUS_GOOD) { +    DBG (5, "attach_one: unable to detect lifecycle counters, continuing\n"); +    return ret; +  } +    /* sets SANE option 'values' to good defaults */    ret = init_user (s);    if (ret != SANE_STATUS_GOOD) { @@ -1168,6 +1193,7 @@ init_inquire (struct scanner *s)    if (strncmp ("DR", s->model_name, 2)     && strncmp ("CR", s->model_name, 2)     && strncmp ("P-", s->model_name, 2) +   && strncmp ("R", s->model_name, 1)    ) {      DBG (5, "The device at '%s' is reported to be a '%s'\n",        s->device_name, s->model_name); @@ -1388,8 +1414,9 @@ init_model (struct scanner *s)    s->max_x_fb = s->max_x;    s->max_y_fb = s->max_y; -  /* missing from vpd- we will unset this for b&w machines below */ +  /* missing from vpd- we will unset these for some machines below */    s->can_color = 1; +  s->can_read_lifecycle_counters = 1;    /* specific settings missing from vpd */    if (strstr (s->model_name,"DR-9080")){ @@ -1491,6 +1518,34 @@ init_model (struct scanner *s)      s->can_monochrome=0;    } +  else if (strstr (s->model_name,"R40") +  ){ +	/* confirmed */ +    s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_C120; +    s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_C120; +    s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_C120; +    s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_C120; +    s->duplex_interlace = DUPLEX_INTERLACE_2510; +    /*s->duplex_offset = 320; now set in config file*/ +    s->fixed_width = 1; +    s->need_ccal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW; +    s->rgb_format = 1; +    s->sw_lut = 1; + +    /*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->ccal_version = 3; +    s->has_df_ultra = 1; +  } +    /* copied from 2510, possibly incorrect */    else if (strstr (s->model_name,"DR-3010")){      s->rgb_format = 1; @@ -1840,6 +1895,7 @@ init_model (struct scanner *s)    }    else if (strstr (s->model_name,"DR-X10C")){ +    int i = 0;      /* Required for USB coms */      s->has_ssm = 0; @@ -1862,6 +1918,61 @@ init_model (struct scanner *s)      s->std_res_y[DPI_600]=1;      s->has_hwcrop = 1; + +    /*valid horizontal offsets for post-imprinter*/ +    s->post_imprinter_h_offset_list[++i] = 21; +    s->post_imprinter_h_offset_list[++i] = 35; +    s->post_imprinter_h_offset_list[++i] = 47; +    s->post_imprinter_h_offset_list[++i] = 59; +    s->post_imprinter_h_offset_list[++i] = 72; +    s->post_imprinter_h_offset_list[++i] = 99; +    s->post_imprinter_h_offset_list[++i] = 114; +    s->post_imprinter_h_offset_list[++i] = 143; +    s->post_imprinter_h_offset_list[++i] = 155; +    s->post_imprinter_h_offset_list[++i] = 167; +    s->post_imprinter_h_offset_list[++i] = 196; +    s->post_imprinter_h_offset_list[++i] = 211; +    s->post_imprinter_h_offset_list[++i] = 239; +    s->post_imprinter_h_offset_list[++i] = 251; +    s->post_imprinter_h_offset_list[++i] = 263; +    s->post_imprinter_h_offset_list[++i] = 275; +    s->post_imprinter_h_offset_list[++i] = 289; +    s->post_imprinter_h_offset_list[0] = i; + +    i = 0; +    /*valid horizontal offsets for pre-imprinter*/ +    s->pre_imprinter_h_offset_list[++i] = 14; +    s->pre_imprinter_h_offset_list[++i] = 28; +    s->pre_imprinter_h_offset_list[++i] = 41; +    s->pre_imprinter_h_offset_list[++i] = 53; +    s->pre_imprinter_h_offset_list[++i] = 65; +    s->pre_imprinter_h_offset_list[++i] = 106; +    s->pre_imprinter_h_offset_list[0] = i; + +    /*valid vertical offsets for imprinters*/ +    s->imprinter_v_offset_range.min = 0; +    s->imprinter_v_offset_range.max = 500; +    s->imprinter_v_offset_range.quant = 1; + +    i = 0; +    /*valid font angles for imprinters*/ +    s->imprinter_font_angle_list[++i] = 0; +    s->imprinter_font_angle_list[++i] = 90; +    s->imprinter_font_angle_list[++i] = 180; +    s->imprinter_font_angle_list[++i] = 270; +    s->imprinter_font_angle_list[0] = i; + +    i = 0; +    s->imprint_font_size_list[i++] = STRING_IMPRINTER_8x12_FONT; +    s->imprint_font_size_list[i++] = STRING_IMPRINTER_12x12_FONT; +    s->imprint_font_size_list[i] = NULL; + +    i = 0; +    s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_BoI; +    s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_BoW; +    s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_WoB; +    s->imprint_addon_mode_list[i++] = STRING_NONE; +    s->imprint_addon_mode_list[i] = NULL;    }    DBG (10, "init_model: finish\n"); @@ -1870,6 +1981,30 @@ init_model (struct scanner *s)  }  /* + * try to detect imprinters. + */ +static SANE_Status +init_imprinters (struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  s->has_pre_imprinter = 0; +  s->has_post_imprinter = 0; + +  ret = detect_imprinter(s,R_PRE_IMPRINTER); +  if(ret != SANE_STATUS_GOOD){ +    return ret; +  } + +  ret = detect_imprinter(s,R_POST_IMPRINTER); +  if(ret != SANE_STATUS_GOOD){ +    return ret; +  } + +  return ret; +} + +/*   * This function enables the buttons and preloads the current panel values   */  static SANE_Status @@ -1901,6 +2036,28 @@ init_panel (struct scanner *s)  }  /* + * This function disables the lifecycle counters if not available + */ +static SANE_Status +init_counters (struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  DBG (10, "init_counters: start\n"); + +  ret = read_counters(s); +  if(ret){ +    DBG (5, "init_counters: disabling lifecycle counters\n"); +    s->can_read_lifecycle_counters = 0; +    return ret; +  } + +  DBG (10, "init_counters: finish\n"); + +  return ret; +} + +/*   * set good default user values.   * struct is already initialized to 0.   */ @@ -1953,6 +2110,10 @@ init_user (struct scanner *s)    s->threshold = 90;    s->compress_arg = 50; +  s->pre_imprint.h_offset = 65; +  s->post_imprint.h_offset = 155; +  s->post_imprint_addon_mode = ADDON_BoI; +    DBG (10, "init_user: finish\n");    return SANE_STATUS_GOOD; @@ -2737,6 +2898,197 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)       opt->cap = SANE_CAP_INACTIVE;    } +  /* "Imprinter" group --------------------------------------------------- */ +  if(option==OPT_IMPRINT_GROUP){ +    opt->name = "imprinter-options"; +    opt->title = SANE_I18N ("Imprinter Options"); +    opt->desc = SANE_I18N ("Controls for imprinter units"); +    opt->type = SANE_TYPE_GROUP; +    opt->constraint_type = SANE_CONSTRAINT_NONE; + +    /*flaming hack to get scanimage to hide group*/ +    if ( !(s->has_pre_imprinter || s->has_post_imprinter) ) +      opt->type = SANE_TYPE_BOOL; +  } + +  if(option==OPT_PRE_IMPRINT_SPECSTRING){ +    opt->name = "pre-imprint-string"; +    opt->title = "Pre-Imprinter string"; +    opt->desc = "String specifier for the pre-imprinter text"; +    opt->type = SANE_TYPE_STRING; +    opt->size = IMPRINT_SPECSTRING_LEN; +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_PRE_IMPRINT_H_OFFSET){ +    opt->name = "pre-imprint-h-offset"; +    opt->title = "Pre-Imprinter horizontal offset"; +    opt->desc = "Integer specifying the horizontal positioning of the pre-imprinter"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_MM; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; +    opt->constraint.word_list = s->pre_imprinter_h_offset_list; +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_PRE_IMPRINT_V_OFFSET){ +    opt->name = "pre-imprint-v-offset"; +    opt->title = "Pre-Imprinter vertical offset"; +    opt->desc = "Integer specifying the vertical positioning of the pre-imprinter"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_MM; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_RANGE; +    opt->constraint.range = &s->imprinter_v_offset_range; +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_PRE_IMPRINT_FONT_SIZE){ +    opt->name = "pre-imprint-font-size"; +    opt->title = "Pre-Imprinter font size"; +    opt->desc = "Integer specifying the pre-imprint font size"; +    opt->type = SANE_TYPE_STRING; +    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; +    opt->constraint.string_list = s->imprint_font_size_list; +    opt->size = maxStringSize (opt->constraint.string_list); +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_PRE_IMPRINT_FONT_ROT){ +    opt->name = "pre-imprint-font-rot"; +    opt->title = "Pre-Imprinter font rotation"; +    opt->desc = "Integer specifying the pre-imprint font rotation"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_NONE; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; +    opt->constraint.word_list = s->imprinter_font_angle_list; +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_PRE_IMPRINT_SPACING){ +    opt->name = "pre-imprint-spacing"; +    opt->title = "Pre-Imprinter spacing"; +    opt->desc = "Enables the pre-imprint extra spacing"; +    opt->type = SANE_TYPE_BOOL; +    if (s->has_pre_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_SPECSTRING){ +    opt->name = "post-imprint-string"; +    opt->title = "Post-Imprinter string"; +    opt->desc = "String specifier for the post-imprinter text"; +    opt->type = SANE_TYPE_STRING; +    opt->size = IMPRINT_SPECSTRING_LEN; +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_H_OFFSET){ +    opt->name = "post-imprint-h-offset"; +    opt->title = "Post-Imprinter horizontal offset"; +    opt->desc = "Integer specifying the horizontal positioning of the post-imprinter"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_MM; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; +    opt->constraint.word_list = s->post_imprinter_h_offset_list; +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_V_OFFSET){ +    opt->name = "post-imprint-v-offset"; +    opt->title = "Post-Imprinter vertical offset"; +    opt->desc = "Integer specifying the vertical positioning of the post-imprinter"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_MM; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_RANGE; +    opt->constraint.range = &s->imprinter_v_offset_range; +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_FONT_SIZE){ +    opt->name = "post-imprint-font-size"; +    opt->title = "Post-Imprinter font size"; +    opt->desc = "Integer specifying the post-imprint font size"; +    opt->type = SANE_TYPE_STRING; +    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; +    opt->constraint.string_list = s->imprint_font_size_list; +    opt->size = maxStringSize (opt->constraint.string_list); +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_FONT_ROT){ +    opt->name = "post-imprint-font-rot"; +    opt->title = "Post-Imprinter font rotation"; +    opt->desc = "Integer specifying the post-imprint font rotation"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_NONE; +    opt->size = sizeof(SANE_Word); +    opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; +    opt->constraint.word_list = s->imprinter_font_angle_list; +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_SPACING){ +    opt->name = "post-imprint-spacing"; +    opt->title = "Post-Imprinter spacing"; +    opt->desc = "Enables the post-imprint extra spacing"; +    opt->type = SANE_TYPE_BOOL; +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_POST_IMPRINT_ADDON_MODE){ +    opt->name = "post-imprint-addon-mode"; +    opt->title = "Post-Imprinter addon mode"; +    opt->desc = "Integer specifying the type of post-imprint addon rendered in the scanned image"; +    opt->type = SANE_TYPE_STRING; +    opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; +    opt->constraint.string_list = s->imprint_addon_mode_list; +    opt->size = maxStringSize (opt->constraint.string_list); +    if (s->has_post_imprinter) +     opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; +    else +     opt->cap = SANE_CAP_INACTIVE; +  } +    /* "Sensor" group ------------------------------------------------------ */    if(option==OPT_SENSOR_GROUP){      opt->name = SANE_NAME_SENSORS; @@ -2830,6 +3182,34 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)        opt->cap = SANE_CAP_INACTIVE;    } +  if(option==OPT_ROLLERCOUNTER){ +    opt->name = "roller-counter"; +    opt->title = "Roller Counter"; +    opt->desc = "Scans since last roller replacement"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_NONE; +    opt->constraint_type = SANE_CONSTRAINT_NONE; + +    if (s->can_read_lifecycle_counters) +      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; +    else +      opt->cap = SANE_CAP_INACTIVE; +  } + +  if(option==OPT_TOTALCOUNTER){ +    opt->name = "total-counter"; +    opt->title = "Total Counter"; +    opt->desc = "Total scan count of the device"; +    opt->type = SANE_TYPE_INT; +    opt->unit = SANE_UNIT_NONE; +    opt->constraint_type = SANE_CONSTRAINT_NONE; + +    if (s->can_read_lifecycle_counters) +      opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; +    else +      opt->cap = SANE_CAP_INACTIVE; +  } +    if(option==OPT_ADF_LOADED){      opt->name = "adf-loaded";      opt->title = "ADF Loaded"; @@ -3108,6 +3488,122 @@ sane_control_option (SANE_Handle handle, SANE_Int option,            *val_p = s->hwcrop;            return SANE_STATUS_GOOD; +        case OPT_PRE_IMPRINT_SPECSTRING: +          strcpy(val, s->pre_imprint.specstring); +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_H_OFFSET: +          *val_p = s->pre_imprint.h_offset; +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_V_OFFSET: +          *val_p = s->pre_imprint.v_offset; +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_FONT_SIZE: +          switch (s->pre_imprint.font_size){ +            case IMPRINTER_12x12_FONT: +              strcpy(val, STRING_IMPRINTER_12x12_FONT); +              break; + +            case IMPRINTER_8x12_FONT: +              strcpy(val, STRING_IMPRINTER_8x12_FONT); +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_FONT_ROT: +          switch (s->pre_imprint.font_rot){ +            case IMPRINTER_0_FONT_ROT: +              *val_p = 0; +              break; + +            case IMPRINTER_90_FONT_ROT: +              *val_p = 90; +              break; + +            case IMPRINTER_180_FONT_ROT: +              *val_p = 180; +              break; + +            case IMPRINTER_270_FONT_ROT: +              *val_p = 270; +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_SPACING: +          *val_p = s->pre_imprint.spacing; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_SPECSTRING: +          strcpy(val, s->post_imprint.specstring); +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_H_OFFSET: +          *val_p = s->post_imprint.h_offset; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_V_OFFSET: +          *val_p = s->post_imprint.v_offset; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_FONT_SIZE: +          switch (s->post_imprint.font_size){ +            case IMPRINTER_12x12_FONT: +              strcpy(val, STRING_IMPRINTER_12x12_FONT); +              break; + +            case IMPRINTER_8x12_FONT: +              strcpy(val, STRING_IMPRINTER_8x12_FONT); +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_FONT_ROT: +          switch (s->post_imprint.font_rot){ +            case IMPRINTER_0_FONT_ROT: +              *val_p = 0; +              break; + +            case IMPRINTER_90_FONT_ROT: +              *val_p = 90; +              break; + +            case IMPRINTER_180_FONT_ROT: +              *val_p = 180; +              break; + +            case IMPRINTER_270_FONT_ROT: +              *val_p = 270; +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_SPACING: +          *val_p = s->post_imprint.spacing; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_ADDON_MODE: +          switch (s->post_imprint_addon_mode){ +            case ADDON_BoW: +              strcpy(val, STRING_IMPRINTER_ADDON_BoW); +              break; + +            case ADDON_BoI: +              strcpy(val, STRING_IMPRINTER_ADDON_BoI); +              break; + +            case ADDON_WoB: +              strcpy(val, STRING_IMPRINTER_ADDON_WoB); +              break; + +            case ADDON_DISABLED: +              strcpy(val, STRING_NONE); +              break; +          } +          return SANE_STATUS_GOOD; +          /* Sensor Group */          case OPT_START:            ret = read_panel(s,OPT_START); @@ -3144,6 +3640,16 @@ sane_control_option (SANE_Handle handle, SANE_Int option,            *val_p = s->panel_counter;            return ret; +        case OPT_ROLLERCOUNTER: +          ret = read_counters(s); +          *val_p = s->roller_counter; +          return ret; + +        case OPT_TOTALCOUNTER: +          ret = read_counters(s); +          *val_p = s->total_counter; +          return ret; +          case OPT_ADF_LOADED:            ret = read_sensors(s,OPT_ADF_LOADED);            *val_p = s->sensor_adf_loaded; @@ -3431,6 +3937,119 @@ sane_control_option (SANE_Handle handle, SANE_Int option,            s->hwcrop = val_c;            return SANE_STATUS_GOOD; +        case OPT_PRE_IMPRINT_SPECSTRING: +          if (strlen(val) < IMPRINT_SPECSTRING_LEN){ +            strncpy(s->pre_imprint.specstring, val, IMPRINT_SPECSTRING_LEN); +            return SANE_STATUS_GOOD; +          } +          DBG (5, "sane_control_option: pre-imprint spec string '%s' exceed the limit of %d characters\n", (SANE_String)val, IMPRINT_SPECSTRING_LEN); +          return SANE_STATUS_INVAL; + +        case OPT_PRE_IMPRINT_H_OFFSET: +          s->pre_imprint.h_offset = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_V_OFFSET: +          s->pre_imprint.v_offset = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_FONT_SIZE: +          if (!strcmp (val, STRING_IMPRINTER_12x12_FONT)) { +            s->pre_imprint.font_size = IMPRINTER_12x12_FONT; +          } +          if (!strcmp (val, STRING_IMPRINTER_8x12_FONT)) { +            s->pre_imprint.font_size = IMPRINTER_8x12_FONT; +          } +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_FONT_ROT: +          switch (val_c){ +            case 0: +              s->pre_imprint.font_rot = IMPRINTER_0_FONT_ROT; +              break; + +            case 90: +              s->pre_imprint.font_rot = IMPRINTER_90_FONT_ROT; +              break; + +            case 180: +              s->pre_imprint.font_rot = IMPRINTER_180_FONT_ROT; +              break; + +            case 270: +              s->pre_imprint.font_rot = IMPRINTER_270_FONT_ROT; +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_PRE_IMPRINT_SPACING: +          s->pre_imprint.spacing = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_SPECSTRING: +          if (strlen(val) < IMPRINT_SPECSTRING_LEN){ +            strncpy(s->post_imprint.specstring, val, IMPRINT_SPECSTRING_LEN); +            return SANE_STATUS_GOOD; +          } +          DBG (5, "sane_control_option: post-imprint spec string '%s' exceed the limit of %d characters\n", (SANE_String)val, IMPRINT_SPECSTRING_LEN); +          return SANE_STATUS_INVAL; + +        case OPT_POST_IMPRINT_H_OFFSET: +          s->post_imprint.h_offset = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_V_OFFSET: +          s->post_imprint.v_offset = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_FONT_SIZE: +          if (!strcmp (val, STRING_IMPRINTER_12x12_FONT)) { +            s->post_imprint.font_size = IMPRINTER_12x12_FONT; +          } +          if (!strcmp (val, STRING_IMPRINTER_8x12_FONT)) { +            s->post_imprint.font_size = IMPRINTER_8x12_FONT; +          } +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_FONT_ROT: +          switch (val_c){ +            case 0: +              s->post_imprint.font_rot = IMPRINTER_0_FONT_ROT; +              break; + +            case 90: +              s->post_imprint.font_rot = IMPRINTER_90_FONT_ROT; +              break; + +            case 180: +              s->post_imprint.font_rot = IMPRINTER_180_FONT_ROT; +              break; + +            case 270: +              s->post_imprint.font_rot = IMPRINTER_270_FONT_ROT; +              break; +          } +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_SPACING: +          s->post_imprint.spacing = val_c; +          return SANE_STATUS_GOOD; + +        case OPT_POST_IMPRINT_ADDON_MODE: +          if (!strcmp (val, STRING_IMPRINTER_ADDON_BoW)) { +            s->post_imprint_addon_mode = ADDON_BoW; +          } +          if (!strcmp (val, STRING_IMPRINTER_ADDON_BoI)) { +            s->post_imprint_addon_mode = ADDON_BoI; +          } +          if (!strcmp (val, STRING_IMPRINTER_ADDON_WoB)) { +            s->post_imprint_addon_mode = ADDON_WoB; +          } +          if (!strcmp (val, STRING_NONE)) { +            s->post_imprint_addon_mode = ADDON_DISABLED; +          } +          return SANE_STATUS_GOOD; +        }    }                           /* else */ @@ -3636,6 +4255,14 @@ ssm_df (struct scanner *s)        set_SSM2_DF_staple(out, 1);      } +    int requires_postimprint = s->has_post_imprinter && (strlen(s->post_imprint.specstring) > 0); +    int requires_preimprint = s->has_pre_imprinter && (strlen(s->pre_imprint.specstring) > 0); +    if (s->has_post_imprinter) +      set_SSM2_DF_post_addon(out, requires_postimprint); +    if (requires_postimprint || requires_preimprint){ +      set_SSM2_DF_imprint(out, 1); +    } +      ret = do_cmd (          s, 1, 0,          cmd, cmdLen, @@ -3897,6 +4524,50 @@ ssm_do (struct scanner *s)  }  static SANE_Status +read_counters(struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  unsigned char cmd[READ_len]; +  size_t cmdLen = READ_len; + +  unsigned char in[R_COUNTERS_len]; +  size_t inLen = R_COUNTERS_len; + +  if (!s->can_read_lifecycle_counters){ +    DBG(10, "read_counters: unsupported\n"); +    return ret; +  } + +  DBG(10, "read_counters: start\n"); + +  memset(cmd,0,cmdLen); +  set_SCSI_opcode(cmd, READ_code); +  set_R_datatype_code(cmd, SR_datatype_counters); +  set_R_xfer_length(cmd, inLen); + +  ret = do_cmd( +    s, 1, 0, +    cmd, cmdLen, +    NULL, 0, +    in, &inLen +  ); + +  if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF){ + +    s->total_counter = get_R_COUNTERS_total(in); +    s->roller_counter = s->total_counter - get_R_COUNTERS_last_srv(in); + +    DBG(10, "read_counters: total counter: %d roller_counter %d \n",s->total_counter,s->roller_counter); +    ret = SANE_STATUS_GOOD; +  }else{ +    DBG(10, "read_counters: ERROR: %d\n",ret); +  } + +  return ret; +} + +static SANE_Status  read_sensors(struct scanner *s,SANE_Int option)  {    SANE_Status ret=SANE_STATUS_GOOD; @@ -4382,6 +5053,248 @@ update_params(struct scanner *s, int calib)      return ret;  } +/* simplify handling cmd SANE_STATUS_EOF as SANE_STATUS_GOOD */ +SANE_Status +send_cmd(struct scanner *s, unsigned char* cmd, size_t cmdLen, +                            unsigned char* out, size_t outLen, +                            unsigned char * inBuff, size_t * inLen) +{ +  SANE_Status ret=SANE_STATUS_GOOD; + +    ret = do_cmd ( +      s, 1, 0, +      cmd, cmdLen, +      out, outLen, +      inBuff, inLen +    ); + +    if (ret == SANE_STATUS_EOF) { +        ret = SANE_STATUS_GOOD; +    } + +    return ret; +} + +SANE_Status +send_imprint_positioning(struct scanner* s, int is_postimprint, int enabled) +{ +  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; + +  unsigned char out_prefix[5]={ 0x01, 0x00, 0x60, 0x00, 0x60 }; +  size_t outPrefixLen=5; + +  memset(cmd,0,cmdLen); +  set_SCSI_opcode(cmd,SET_SCAN_MODE2_code); +  set_SSM2_page_code(cmd,SM2_pc_imprinter_settings); +  if (is_postimprint) +    set_SSM2_postimprint_cmd(cmd); +  set_SSM2_pay_len(cmd,outLen); + +  memset(out,0,outLen); +  memcpy(out,out_prefix,outPrefixLen); + +  int h_offset; +  int v_offset; +  if (is_postimprint){ +    if (s->post_imprint_addon_mode != ADDON_DISABLED) +      set_SSM2_postimprint_addon(out); +    h_offset = s->post_imprint.h_offset; +    v_offset = s->post_imprint.v_offset; + +    if (enabled) +      DBG (10, "send_imprint_positioning: post-imprinter: h_offset: %d v_offset: %d\n",h_offset,v_offset); +  }else{ +    h_offset = s->pre_imprint.h_offset; +    v_offset = s->pre_imprint.v_offset; +    if (enabled) +      DBG (10, "send_imprint_positioning: pre-imprinter: h_offset: %d v_offset: %d\n",h_offset,v_offset); +  } +  if(!enabled) +    h_offset = v_offset = 0; +  set_SSM2_imprint_hoffset(out,h_offset); +  set_SSM2_imprint_voffset(out,v_offset); + +  return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +send_imprint_specstring(struct scanner* s, int is_postimprint) +{ +  unsigned char cmd[SET_SCAN_MODE2_len]; +  size_t cmdLen = SET_SCAN_MODE2_len; + +  unsigned char out[SSM2_IMPRINTER_STRING_PAY_len]; +  size_t outLen = SSM2_IMPRINTER_STRING_PAY_len; + +  memset(cmd,0,cmdLen); +  set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); +  set_SSM2_page_code(cmd, SM2_pc_imprinter_specstring); +  if (is_postimprint) +    set_SSM2_postimprint_cmd(cmd); +  set_SSM2_pay_len(cmd, outLen); + +  memset(out,0,outLen); +  /* most of these bytes have yet to be identified to specific functionalities, +     as they never seem to change under different imprinting mode */ +  unsigned char out_prefix[32] = { +      0x01, 0x00, +      0x60, 0x00, +      0x60, 0x00, +      0x00, 0x00, +      0x00, 0x00, +      0x00, 0x00, +      0x03, 0x00, +      0x00, 0x00, +      0x01, 0x00, +      0x00, 0x00, +      0x00, 0x00, +      0x00, 0x00, +      0x00, 0x00, +      0x00, 0x01, +      0x04, 0x00, +      0x00, 0x00 +    }; +  memcpy(out, out_prefix, 32); +  if (is_postimprint){ +    set_SSM2_imprint_fontsize(out, s->post_imprint.font_size); +    set_SSM2_imprint_fontrot(out, s->post_imprint.font_rot); +    set_SSM2_imprint_spacing(out, s->post_imprint.spacing); +    if (s->post_imprint_addon_mode != ADDON_DISABLED) +      set_SSM2_imprint_addonmode(out, s->post_imprint_addon_mode); +    strcpy((SANE_Char*)(out + 45), (SANE_String_Const) s->post_imprint.specstring); +    DBG (10, "send_imprint_specstring: post-imprinter: font size: %d rotation: %d spacing: %d text: '%s' imprint-addon-mode: %d\n",s->post_imprint.font_size,s->post_imprint.font_rot,s->post_imprint.spacing,s->post_imprint.specstring,s->post_imprint_addon_mode); +  }else{ +    set_SSM2_imprint_fontsize(out, s->pre_imprint.font_size); +    set_SSM2_imprint_fontrot(out, s->pre_imprint.font_rot); +    set_SSM2_imprint_spacing(out, s->pre_imprint.spacing); +    strcpy((SANE_Char*)(out + 45), (SANE_String_Const) s->pre_imprint.specstring); +    DBG (10, "send_imprint_specstring: pre-imprinter: font size: %d rotation: %d spacing: %d text: '%s'\n",s->pre_imprint.font_size,s->pre_imprint.font_rot,s->pre_imprint.spacing,s->pre_imprint.specstring); +  } + +  return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +send_imprint_date_and_time(struct scanner* s) +{ +  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_date_time); +  set_SSM2_pay_len(cmd, outLen); + +  memset(out,0,outLen); + +  time_t t = time(NULL); +  struct tm tM = *localtime(&t); + +  set_SSM2_imprint_year(out, tM.tm_year + 1900); +  set_SSM2_imprint_month(out, tM.tm_mon + 1); +  set_SSM2_imprint_day(out, tM.tm_mday); +  set_SSM2_imprint_hour(out, tM.tm_hour); +  set_SSM2_imprint_min(out, tM.tm_min); +  set_SSM2_imprint_sec(out, tM.tm_sec); + +  return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +load_imprinting_settings(struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  int requires_preimprint = (strlen(s->pre_imprint.specstring) > 0); +  int requires_postimprint = (strlen(s->post_imprint.specstring) > 0); +  int send_date_time = (s->has_pre_imprinter && requires_preimprint) || (s->has_post_imprinter && requires_postimprint); + +  if (s->has_pre_imprinter){ +    ret = send_imprint_positioning(s, 0, requires_preimprint); +    DBG(10, "load_imprinting_settings: send_pre_imprint_positioning = %d \n", ret); +    if (ret != SANE_STATUS_GOOD) +      return ret; +    if (requires_preimprint){ +      ret = send_imprint_specstring(s, 0); +      DBG(10, "load_imprinting_settings: send_pre_imprint_specstring = %d \n", ret); +      if (ret != SANE_STATUS_GOOD) +        return ret; +    } +  } + +  if (s->has_post_imprinter){ +    ret = send_imprint_positioning(s, 1, requires_postimprint); +    DBG(10, "load_imprinting_settings: send_post_imprint_positioning = %d \n", ret); +    if (ret != SANE_STATUS_GOOD) +      return ret; +    if (requires_postimprint){ +      ret = send_imprint_specstring(s, 1); +      DBG(10, "load_imprinting_settings: send_post_imprint_specstring = %d \n", ret); +      if (ret != SANE_STATUS_GOOD) +        return ret; +    } +  } + +  if (send_date_time){ +    ret = send_imprint_date_and_time(s); +    DBG(10, "load_imprinting_settings: send_imprint_date_and_time = %d \n", ret); +  } +  return ret; +} + +static SANE_Status +detect_imprinter(struct scanner *s,SANE_Int option) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  unsigned char cmd[READ_len]; +  size_t cmdLen = READ_len; + +  unsigned char in[R_IMPRINTER_len]; +  size_t inLen = R_IMPRINTER_len; + +  DBG (10, "detect_imprinter: start %d\n", option); + +  memset(cmd,0,cmdLen); +  set_SCSI_opcode(cmd, READ_code); +  set_R_datatype_code(cmd, SR_datatype_imprinters); +  set_R_xfer_uid(cmd, option); +  set_R_xfer_length(cmd, inLen); + +  ret = do_cmd( +    s, 1, 0, +    cmd, cmdLen, +    NULL, 0, +    in, &inLen +  ); + +  if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { +    ret = SANE_STATUS_GOOD; +  } + +  int imprinter_found = get_R_IMPRINTER_found(in); +  const char* imprinter_type = "unknown"; +  if (option == R_PRE_IMPRINTER){ +    s->has_pre_imprinter = imprinter_found; +    imprinter_type = "pre-imprinter"; +  } +  else if (option == R_POST_IMPRINTER){ +    s->has_post_imprinter = imprinter_found; +    imprinter_type = "post-imprinter"; +  } + +  DBG (10, "detect_imprinter:  type: %s. found status bit: %d \n",imprinter_type,imprinter_found); + +  return ret; +} +  /* reset image size parameters after buffer_xxx functions changed them */  SANE_Status  update_i_params(struct scanner *s) @@ -4471,6 +5384,14 @@ sane_start (SANE_Handle handle)        goto errors;      } +    if (s->has_pre_imprinter || s->has_post_imprinter){ +      ret = load_imprinting_settings(s); +      if (ret != SANE_STATUS_GOOD) { +        DBG (5, "sane_start: ERROR: invalid imprinting settings\n"); +        goto errors; +      } +    } +      /* reset the page counter after calibration */      s->panel_counter = 0;      s->prev_page = 0; @@ -7204,7 +8125,7 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg)    DBG (5, "sense_handler: start\n");    /* kill compiler warning */ -  fd = fd; +  (void) fd;    /* copy the rs return data into the scanner struct       so that the caller can use it if he wants @@ -7465,8 +8386,8 @@ do_scsi_cmd(struct scanner *s, int runRS, int timeout,    int ret;    /*shut up compiler*/ -  runRS=runRS; -  timeout=timeout; +  (void) runRS; +  (void) timeout;    DBG(10, "do_scsi_cmd: start\n"); | 
