diff options
Diffstat (limited to 'backend/canon_dr.c')
| -rw-r--r-- | backend/canon_dr.c | 432 | 
1 files changed, 323 insertions, 109 deletions
| diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 17ee7b6..de7ed7e 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-2019 m. allan noah +   Copyright (C) 2008-2020 m. allan noah     Yabarana Corp. www.yabarana.com provided significant funding     EvriChart, Inc. www.evrichart.com provided funding and loaned equipment @@ -25,9 +25,7 @@     General Public License for more details.     You should have received a copy of the GNU General Public License -   along with this program; if not, write to the Free Software -   Foundation, Inc., 59 Temple Place - Suite 330, Boston, -   MA 02111-1307, USA. +   along with this program.  If not, see <https://www.gnu.org/licenses/>.     As a special exception, the authors of SANE give permission for     additional uses of the libraries contained in this release of SANE. @@ -126,9 +124,9 @@           - send_panel() can disable too           - add cancel() to send d8 command           - call cancel() only after final read from scanner -         - stop button reqests cancel +         - stop button requests cancel        v12 2009-01-21, MAN -         - dont export private symbols +         - don't export private symbols        v13 2009-03-06, MAN           - new vendor ID for recent machines           - add usb ids for several new machines @@ -149,7 +147,7 @@        v18 2009-03-21, MAN           - rewrite config file parsing to reset options after each scanner           - add config options for vendor, model, version -         - dont call inquiry if those 3 options are set +         - don't call inquiry if those 3 options are set           - remove default config file from code           - add initial gray deinterlacing code for DR-2510C           - rename do_usb_reset to do_usb_clear @@ -175,8 +173,8 @@        v24 2009-04-02, MAN           - fix DR-2510C duplex deinterlacing code           - rewrite sane_read helpers to read until EOF -         - update sane_start for scanners that dont use object_position -         - dont call sanei_usb_clear_halt() if device is not open +         - update sane_start for scanners that don't use object_position +         - don't call sanei_usb_clear_halt() if device is not open           - increase default buffer size to 4 megs           - set buffermode on by default           - hide modes and resolutions that DR-2510C lies about @@ -206,8 +204,8 @@           - merge x and y resolution options into single option           - move scan params into two new structs, s->u and s->s           - sane_get_parameters() just returns values from s->u -         - dont call wait_scanner() in object_position() -         - dont call ssm_*() from option handler +         - don't call wait_scanner() in object_position() +         - don't call ssm_*() from option handler           - refactor sane_start()           - read_from_buffer() can workaround missing res, modes and cropping           - set most DR-2xxx machines to use the read_from_buffer workarounds @@ -318,7 +316,7 @@        v51 2015-08-25, MAN (SANE 1.0.25)           - DR-C125 does not invert_tly, does need sw_lut        v52 2015-11-03, MAN -         - set can_color=1 by default (recent models dont have 'C' in name) +         - set can_color=1 by default (recent models don't have 'C' in name)           - enable jpeg for DR-6080           - add must_downsample and must_fully_buffer           - improve dropout option handling @@ -340,6 +338,14 @@           - complete support for X-10, including hardware cropping        v58 2019-11-10, MAN           - adjust wait_scanner to set runRS only as a last resort, bug #154 +      v59 2020-09-23, MAN +         - restructure fine calibration code +         - initial support for uploading fine calibration payloads +         - improve DR-C225 support +      v60 2020-11-28, MAN +         - add new gray and color interlacing options for DR-C120 +         - initial support for DR-C120 and C130 +         - enable fine calibration for P-208 (per @sashacmc in !546)     SANE FLOW DIAGRAM @@ -390,7 +396,7 @@  #include "canon_dr.h"  #define DEBUG 1 -#define BUILD 58 +#define BUILD 60  /* values for SANE_DEBUG_CANON_DR env var:   - errors           5 @@ -1348,7 +1354,8 @@ init_model (struct scanner *s)      s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG;      s->duplex_interlace = DUPLEX_INTERLACE_FBfb;      s->need_ccal = 1; -    s->need_fcal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW;      /*s->duplex_offset = 432; now set in config file*/      s->duplex_offset_side = SIDE_BACK; @@ -1372,7 +1379,8 @@ init_model (struct scanner *s)      s->duplex_interlace = DUPLEX_INTERLACE_2510;      /*s->duplex_offset = 400; now set in config file*/      s->need_ccal = 1; -    s->need_fcal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW;      s->sw_lut = 1;      /*s->invert_tly = 1;*/ @@ -1402,7 +1410,8 @@ init_model (struct scanner *s)      s->duplex_interlace = DUPLEX_INTERLACE_2510;      /*s->duplex_offset = 400; now set in config file*/      s->need_ccal = 1; -    s->need_fcal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW;      s->sw_lut = 1;      s->invert_tly = 1; @@ -1427,7 +1436,8 @@ init_model (struct scanner *s)      s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB;      s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB;      s->duplex_interlace = DUPLEX_INTERLACE_FBfb; -    s->need_fcal_buffer = 1; +    s->fcal_src = FCAL_SRC_HW; +    s->fcal_dest = FCAL_DEST_SW;      s->bg_color = 0x08;      /*s->duplex_offset = 840; now set in config file*/      s->sw_lut = 1; @@ -1487,6 +1497,8 @@ init_model (struct scanner *s)      s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG;      s->duplex_interlace = DUPLEX_INTERLACE_FBfb;      s->need_ccal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW;      s->invert_tly = 1;      s->unknown_byte2 = 0x88;      s->rgb_format = 1; @@ -1592,6 +1604,39 @@ init_model (struct scanner *s)      s->can_monochrome=0;    } +  else if (strstr (s->model_name,"DR-C120") +    || strstr (s->model_name,"DR-C130") +  ){ + +    /*confirmed settings*/ +    s->need_ccal = 1; +    s->ccal_version = 3; + +    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_side = SIDE_BACK; +    s->unknown_byte2 = 0x88; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW; +    s->sw_lut = 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-C125")){      /*confirmed settings*/ @@ -1604,7 +1649,8 @@ init_model (struct scanner *s)      s->unknown_byte2 = 0x88;      s->need_ccal = 1;      s->ccal_version = 3; -    s->need_fcal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_SW;      s->sw_lut = 1;      s->rgb_format = 1;      /*s->duplex_offset = 400; now set in config file*/ @@ -1625,14 +1671,15 @@ init_model (struct scanner *s)    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->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB;      s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG; -    s->duplex_interlace = DUPLEX_INTERLACE_FBfb; +    s->duplex_interlace = DUPLEX_INTERLACE_PER_CHANNEL;      s->unknown_byte2 = 0x88;      s->need_ccal = 1;      s->ccal_version = 3; -    s->need_fcal = 1; +    s->fcal_src = FCAL_SRC_SCAN; +    s->fcal_dest = FCAL_DEST_HW;      s->invert_tly = 1;      s->rgb_format = 1;      /*s->duplex_offset = 400; now set in config file*/ @@ -3019,7 +3066,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option,        DBG (20, "sane_control_option: set value for '%s' (%d)\n", s->opt[option].name,option);        if ( s->started ) { -        DBG (5, "sane_control_option: cant set, device busy\n"); +        DBG (5, "sane_control_option: can't set, device busy\n");          return SANE_STATUS_DEVICE_BUSY;        } @@ -3034,7 +3081,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option,          return status;        } -      /* may have been changed by constrain, so dont copy until now */ +      /* may have been changed by constrain, so don't copy until now */        val_c = *(SANE_Word *)val;        /* @@ -4259,7 +4306,7 @@ update_i_params(struct scanner *s)   *   * this will be called between sides of a duplex scan,   * and at the start of each page of an adf batch. - * hence, we spend alot of time playing with s->started, etc. + * hence, we spend a lot of time playing with s->started, etc.   */  SANE_Status  sane_start (SANE_Handle handle) @@ -4314,22 +4361,19 @@ sane_start (SANE_Handle handle)      }      /* AFE cal */ -    if((ret = calibrate_AFE(s))){ +    ret = calibrate_AFE(s); +    if (ret != SANE_STATUS_GOOD) {        DBG (5, "sane_start: ERROR: cannot cal afe\n");        goto errors;      }      /* fine cal */ -    if((ret = calibrate_fine(s))){ +    ret = calibrate_fine(s); +    if (ret != SANE_STATUS_GOOD) {        DBG (5, "sane_start: ERROR: cannot cal fine\n");        goto errors;      } -    if((ret = calibrate_fine_buffer(s))){ -      DBG (5, "sane_start: ERROR: cannot cal fine from buffer\n"); -      goto errors; -    } -      /* reset the page counter after calibration */      s->panel_counter = 0;      s->prev_page = 0; @@ -4458,10 +4502,10 @@ sane_start (SANE_Handle handle)      }      /* set clean defaults with new sheet of paper */ -    /* dont reset the transfer vars on backside of duplex page */ +    /* don't reset the transfer vars on backside of duplex page */      /* 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 */ +    /* don't call object pos or scan on back side of duplex scan */      if(s->side == SIDE_FRONT || s->s.source == SOURCE_ADF_BACK || s->s.source == SOURCE_CARD_BACK){        /* clean scan params for new scan */ @@ -5367,6 +5411,23 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side)              line[line_next++] = 0;            }            break; + +        case GRAY_INTERLACE_C120: +          DBG (17, "copy_simplex: gray, C120\n"); + +          /* first read head (third byte of every three) */ +          for(j=bwidth-1;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +          } +          /* second read head (first byte of every three) */ +          for(j=bwidth-3;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +          } +          /* third read head (second byte of every three) */ +          for(j=bwidth-2;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +          } +          break;        }      } @@ -5451,6 +5512,29 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side)              line[line_next++] = 0;            }            break; + +        case COLOR_INTERLACE_C120: +          DBG (17, "copy_simplex: color, C120\n"); + +          /* first read head (third byte of every three) */ +          for(j=t-1;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +            line[line_next++] = buf[i+t+j]; +            line[line_next++] = buf[i+2*t+j]; +          } +          /* second read head (first byte of every three) */ +          for(j=t-3;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +            line[line_next++] = buf[i+t+j]; +            line[line_next++] = buf[i+2*t+j]; +          } +          /* third read head (second byte of every three) */ +          for(j=t-2;j>=0;j-=3){ +            line[line_next++] = buf[i+j]; +            line[line_next++] = buf[i+t+j]; +            line[line_next++] = buf[i+2*t+j]; +          } +          break;        }      } @@ -5517,6 +5601,7 @@ copy_duplex(struct scanner *s, unsigned char * buf, int len)  {    SANE_Status ret=SANE_STATUS_GOOD;    int i,j; +  int pwidth = s->s.width;    int bwidth = s->s.Bpl;    int dbwidth = 2*bwidth;    unsigned char * front; @@ -5568,6 +5653,21 @@ copy_duplex(struct scanner *s, unsigned char * buf, int len)      }    } +  /* line is in 6 sections, front red, back red, front green, etc. */ +  else if(s->duplex_interlace == DUPLEX_INTERLACE_PER_CHANNEL){ + +    DBG (10, "copy_duplex: per channel\n"); + +    for(i=0; i<len; i+=dbwidth){ +      for(j=0;j<3;j++){ +        memcpy(front+flen,buf+i+j*pwidth*2,pwidth); +        flen+=pwidth; +        memcpy(back+blen,buf+i+j*pwidth*2+pwidth,pwidth); +        blen+=pwidth; +      } +    } +  } +    /* full line of front, then full line of back */    else if(s->duplex_interlace == DUPLEX_INTERLACE_FfBb || s->duplex_interlace == DUPLEX_INTERLACE_fFBb){      for(i=0; i<len; i+=dbwidth){ @@ -5944,7 +6044,7 @@ calibrate_AFE (struct scanner *s)      goto cleanup;    } -  /*blast the existing fine cal data so reading code wont apply it*/ +  /*blast the existing fine cal data so reading code won't apply it*/    ret = offset_buffers(s,0);    ret = gain_buffers(s,0); @@ -6119,10 +6219,68 @@ calibrate_AFE (struct scanner *s)    return ret;  } +/* + * fine calibration produces a per-cell offset and gain value, + * which is then used to adjust the output from the scanner. + * There is quite a bit of variation here, with different models + * needing different types/amounts of help from the software. + * + * This function is a common entry point for all variations. + */ +static SANE_Status +calibrate_fine (struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; + +  DBG (10, "calibrate_fine: start\n"); + +  if(s->fcal_src == FCAL_SRC_NONE || s->fcal_dest == FCAL_DEST_NONE){ +    DBG (10, "calibrate_fine: not required\n"); +    goto cleanup; +  } + +  /* don't recalibrate if we've already done it with these params */ +  if(s->f_res == s->s.dpi_x && s->f_mode == s->s.mode){ +    DBG (10, "calibrate_fine: already done\n"); +    goto cleanup; +  } + +  /* get calibration data from scanner memory */ +  if(s->fcal_src == FCAL_SRC_HW){ +    ret = calibrate_fine_src_hw(s); +    if (ret != SANE_STATUS_GOOD) +      goto cleanup; +  } + +  /* get calibration data by making scans */ +  if(s->fcal_src == FCAL_SRC_SCAN){ +    ret = calibrate_fine_src_scan(s); +    if (ret != SANE_STATUS_GOOD) +      goto cleanup; +  } + +  /* send calibration data to scanner */ +  if(s->fcal_dest == FCAL_DEST_HW){ +    ret = calibrate_fine_dest_hw(s); +    if (ret != SANE_STATUS_GOOD) +      goto cleanup; +  } + +  /* log current cal settings so we won't recalibrate on next scan with same params */ +  s->f_res = s->s.dpi_x; +  s->f_mode = s->s.mode; + +  cleanup: + +  DBG (10, "calibrate_fine: finish %d\n",ret); + +  return ret; +} + -/* alternative version- extracts data from scanner memory */ +/* extracts fine calibration data from scanner memory */  static SANE_Status -calibrate_fine_buffer (struct scanner *s) +calibrate_fine_src_hw (struct scanner *s)  {    SANE_Status ret = SANE_STATUS_GOOD;    int i, j, k; @@ -6138,12 +6296,7 @@ calibrate_fine_buffer (struct scanner *s)    int old_br_y = s->u.br_y;    int old_source = s->u.source; -  DBG (10, "calibrate_fine_buffer: start\n"); - -  if(!s->need_fcal_buffer){ -    DBG (10, "calibrate_fine_buffer: not required\n"); -    return ret; -  } +  DBG (10, "calibrate_fine_src_hw: start\n");    /* pretend we are doing a 1 line scan in duplex */    s->u.tl_y = 0; @@ -6153,19 +6306,14 @@ calibrate_fine_buffer (struct scanner *s)    /* load our own private copy of scan params */    ret = update_params(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine_buffer: ERROR: cannot update_params\n"); -    goto cleanup; -  } - -  if(s->f_res == s->s.dpi_x && s->f_mode == s->s.mode){ -    DBG (10, "calibrate_fine_buffer: already done\n"); +    DBG (5, "calibrate_fine_src_hw: ERROR: cannot update_params\n");      goto cleanup;    }    /* clean scan params for new scan */    ret = clean_params(s);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine_buffer: ERROR: cannot clean_params\n"); +    DBG (5, "calibrate_fine_src_hw: ERROR: cannot clean_params\n");      goto cleanup;    } @@ -6174,7 +6322,7 @@ calibrate_fine_buffer (struct scanner *s)    in = malloc(reqLen);    if (!in) { -    DBG (5, "calibrate_fine_buffer: ERROR: cannot malloc in\n"); +    DBG (5, "calibrate_fine_src_hw: ERROR: cannot malloc in\n");      ret = SANE_STATUS_NO_MEM;      goto cleanup;    } @@ -6182,11 +6330,11 @@ calibrate_fine_buffer (struct scanner *s)    /*fine offset*/    ret = offset_buffers(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine_buffer: ERROR: cannot load offset buffers\n"); +    DBG (5, "calibrate_fine_src_hw: ERROR: cannot load offset buffers\n");      goto cleanup;    } -  DBG (5, "calibrate_fine_buffer: %d %x\n", s->s.dpi_x/10, s->s.dpi_x/10); +  DBG (10, "calibrate_fine_src_hw: %d %x\n", s->s.dpi_x/10, s->s.dpi_x/10);    memset(cmd,0,cmdLen);    set_SCSI_opcode(cmd, READ_code); @@ -6196,8 +6344,6 @@ calibrate_fine_buffer (struct scanner *s)    inLen = reqLen; -  hexdump(15, "cmd:", cmd, cmdLen); -    ret = do_cmd (      s, 1, 0,      cmd, cmdLen, @@ -6232,14 +6378,12 @@ calibrate_fine_buffer (struct scanner *s)            s->f_offset[i][j] = 1;        }      } - -    hexdump(15, "off:", s->f_offset[i], s->s.valid_Bpl);    }    /*fine gain*/    ret = gain_buffers(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine_buffer: ERROR: cannot load gain buffers\n"); +    DBG (5, "calibrate_fine_src_hw: ERROR: cannot load gain buffers\n");      goto cleanup;    } @@ -6259,8 +6403,6 @@ calibrate_fine_buffer (struct scanner *s)        set_R_xfer_uid (cmd, codes[k]);        inLen = reqLen; -      hexdump(15, "cmd:", cmd, cmdLen); -        ret = do_cmd (          s, 1, 0,          cmd, cmdLen, @@ -6288,8 +6430,6 @@ calibrate_fine_buffer (struct scanner *s)      set_R_xfer_uid (cmd, R_FINE_uid_gray);      inLen = reqLen; -    hexdump(15, "cmd:", cmd, cmdLen); -      ret = do_cmd (        s, 1, 0,        cmd, cmdLen, @@ -6310,14 +6450,6 @@ calibrate_fine_buffer (struct scanner *s)      }    } -  for(i=0;i<2;i++){ -    hexdump(15, "gain:", s->f_gain[i], s->s.valid_Bpl); -  } - -  /* log current cal type */ -  s->f_res = s->s.dpi_x; -  s->f_mode = s->s.mode; -    cleanup:    if(in){ @@ -6329,16 +6461,16 @@ calibrate_fine_buffer (struct scanner *s)    s->u.br_y = old_br_y;    s->u.source = old_source; -  DBG (10, "calibrate_fine_buffer: finish %d\n",ret); +  DBG (10, "calibrate_fine_src_hw: finish %d\n",ret);    return ret;  }  /* - * makes several scans, adjusts fine calibration + * makes several scans, generates fine calibration data   */  static SANE_Status -calibrate_fine (struct scanner *s) +calibrate_fine_src_scan (struct scanner *s)  {    SANE_Status ret = SANE_STATUS_GOOD;    int i, j, k; @@ -6350,12 +6482,7 @@ calibrate_fine (struct scanner *s)    int old_br_y = s->u.br_y;    int old_source = s->u.source; -  DBG (10, "calibrate_fine: start\n"); - -  if(!s->need_fcal){ -    DBG (10, "calibrate_fine: not required\n"); -    return ret; -  } +  DBG (10, "calibrate_fine_src_scan: start\n");    /* always cal with a short scan in duplex */    s->u.tl_y = 0; @@ -6365,12 +6492,7 @@ calibrate_fine (struct scanner *s)    /* load our own private copy of scan params */    ret = update_params(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot update_params\n"); -    goto cleanup; -  } - -  if(s->f_res == s->s.dpi_x && s->f_mode == s->s.mode){ -    DBG (10, "calibrate_fine: already done\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot update_params\n");      goto cleanup;    } @@ -6384,39 +6506,39 @@ calibrate_fine (struct scanner *s)    /* make buffers to hold the images */    ret = image_buffers(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot load buffers\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot load buffers\n");      goto cleanup;    } -  /*blast the existing fine cal data so reading code wont apply it*/ +  /*blast the existing fine cal data so reading code won't apply it*/    ret = offset_buffers(s,0);    ret = gain_buffers(s,0);    /* need to tell it we want duplex */    ret = ssm_buffer(s);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot ssm buffer\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot ssm buffer\n");      goto cleanup;    }    /* set window command */    ret = set_window(s);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot set window\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot set window\n");      goto cleanup;    } -  /*handle fifth pass (fine offset), lamp off*/ -  DBG (15, "calibrate_fine: offset\n"); +  /* first pass (fine offset), lamp off */ +  DBG (15, "calibrate_fine_src_scan: offset\n");    ret = calibration_scan(s,0xff);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot make offset cal scan\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot make offset cal scan\n");      goto cleanup;    }    ret = offset_buffers(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot load offset buffers\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot load offset buffers\n");      goto cleanup;    } @@ -6431,17 +6553,17 @@ calibrate_fine (struct scanner *s)      hexdump(15, "off:", s->f_offset[i], s->s.valid_Bpl);    } -  /*handle sixth pass (fine gain), lamp on*/ -  DBG (15, "calibrate_fine: gain\n"); +  /* second pass (fine gain), lamp on */ +  DBG (15, "calibrate_fine_src_scan: gain\n");    ret = calibration_scan(s,0xfe);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot make gain cal scan\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot make gain cal scan\n");      goto cleanup;    }    ret = gain_buffers(s,1);    if (ret != SANE_STATUS_GOOD) { -    DBG (5, "calibrate_fine: ERROR: cannot load gain buffers\n"); +    DBG (5, "calibrate_fine_src_scan: ERROR: cannot load gain buffers\n");      goto cleanup;    } @@ -6459,10 +6581,6 @@ calibrate_fine (struct scanner *s)      hexdump(15, "gain:", s->f_gain[i], s->s.valid_Bpl);    } -  /* log current cal type */ -  s->f_res = s->s.dpi_x; -  s->f_mode = s->s.mode; -    cleanup:    /* recover user settings */ @@ -6470,13 +6588,109 @@ calibrate_fine (struct scanner *s)    s->u.br_y = old_br_y;    s->u.source = old_source; -  DBG (10, "calibrate_fine: finish %d\n",ret); +  DBG (10, "calibrate_fine_src_scan: finish %d\n",ret); + +  return ret; +} + +/* write calibration data to scanner memory and delete from struct */ +static SANE_Status +calibrate_fine_dest_hw (struct scanner *s) +{ +  SANE_Status ret = SANE_STATUS_GOOD; +  int i, j, k; + +  unsigned char cmd[SEND_len]; +  size_t cmdLen = SEND_len; + +  unsigned char * out = NULL; +  size_t outLen = 0; + +  DBG (10, "calibrate_fine_dest_hw: start\n"); + +  /* calibration buffers in scanner are single color channel, but 16 bit, plus 4 byte header */ +  outLen = s->s.width*2 + 4; + +  out = calloc(outLen,1); +  if (!out) { +    DBG (5, "calibrate_fine_dest_hw: ERROR: cannot calloc out\n"); +    ret = SANE_STATUS_NO_MEM; +    goto cleanup; +  } + +  // sides +  for(i=0;i<2;i++){ + +    // colors +    for(j=0;j<3;j++){ + +      int codes[] = { +        S_FCAL_id_f_red, S_FCAL_id_f_green, S_FCAL_id_f_blue, +        S_FCAL_id_b_red, S_FCAL_id_b_green, S_FCAL_id_b_blue}; + +      // offset +      memset(cmd,0,cmdLen); +      set_SCSI_opcode(cmd, SEND_code); +      set_S_xfer_datatype (cmd, SR_datatype_fineoffset); +      set_S_xfer_length (cmd, outLen); + +      set_S_FCAL_datatype (out, codes[i*3+j]); + +      for(k=0; k<s->s.valid_width; k++){ +        out[4+k*2] = 0; + +        // TODO: calculate this instead of hardcode +        out[4+k*2+1] = 140; +      } + +      ret = do_cmd ( +        s, 1, 0, +        cmd, cmdLen, +        out, outLen, +        NULL, 0 +      ); +      if (ret != SANE_STATUS_GOOD) +        goto cleanup; + +      // gain +      set_S_FCAL_datatype (out, codes[i*3+j] | 0x40); + +      for(k=0; k<s->s.valid_width; k++){ +        out[4+k*2] = 0; + +        // TODO: calculate this instead of hardcode +        out[4+k*2+1] = 40; +      } + +      ret = do_cmd ( +        s, 1, 0, +        cmd, cmdLen, +        out, outLen, +        NULL, 0 +      ); +      if (ret != SANE_STATUS_GOOD) +        goto cleanup; + +    } +  } + +  cleanup: + +  /*blast the fine cal data we generated above, so reading code wont apply it*/ +  offset_buffers(s,0); +  gain_buffers(s,0); + +  if(out){ +    free(out); +  } + +  DBG (10, "calibrate_fine_dest_hw: finish %d\n",ret);    return ret;  }  /* - * sends AFE params, and ingests entire duplex image into buffers + * does a simple scan, ingests entire duplex image into buffers   */  static SANE_Status  calibration_scan (struct scanner *s, int scan) @@ -6701,7 +6915,7 @@ gain_buffers (struct scanner *s, int setup)   * handle h is a valid handle) but usually affects long-running   * operations only (such as image acquisition). It is safe to call   * this function asynchronously (e.g., from within a signal handler). - * It is important to note that completion of this operaton does not + * It is important to note that completion of this operation does not   * imply that the currently pending operation has been cancelled. It   * only guarantees that cancellation has been initiated. Cancellation   * completes only when the cancelled call returns (typically with a @@ -6727,7 +6941,7 @@ sane_cancel (SANE_Handle handle)  /* checks started and cancelled flags in scanner struct,   * sends cancel command to scanner if required. don't call - * this function asyncronously, wait for pending operation */ + * this function asynchronously, wait for pending operation */  static SANE_Status  check_for_cancel(struct scanner *s)  { @@ -7245,7 +7459,7 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,        }        /* build a USB packet around the SCSI command */ -      cmdBuffer[3] = cmdLength-4; +      set_USB_CMD_xfer_length(cmdBuffer,cmdLength-4);        cmdBuffer[5] = 1;        cmdBuffer[6] = 0x90;        memcpy(cmdBuffer+cmdOffset,cmdBuff,cmdLen); @@ -7305,7 +7519,7 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,        }        /* build a USB packet around the SCSI command */ -      outBuffer[3] = outLength-4; +      set_USB_OUT_xfer_length(outBuffer,outLength-4);        outBuffer[5] = 2;        outBuffer[6] = 0xb0;        memcpy(outBuffer+outOffset,outBuff,outLen); @@ -7520,7 +7734,7 @@ do_usb_clear(struct scanner *s, int clear, int runRS)        DBG (15, "do_usb_clear: clear halt\n");        ret = sanei_usb_clear_halt(s->fd);        if(ret != SANE_STATUS_GOOD){ -        DBG(5,"do_usb_clear: cant clear halt, returning %d\n", ret); +        DBG(5,"do_usb_clear: can't clear halt, returning %d\n", ret);          return ret;        }      } @@ -7680,7 +7894,7 @@ get_page_width(struct scanner *s)        return s->max_x_fb;    } -  /* cant overscan larger than scanner max */ +  /* can't overscan larger than scanner max */    if(width > s->valid_x){        return s->valid_x;    } @@ -7704,7 +7918,7 @@ get_page_height(struct scanner *s)        return s->max_y_fb;    } -  /* cant overscan larger than scanner max */ +  /* can't overscan larger than scanner max */    if(height > s->max_y){        return s->max_y;    } | 
