summaryrefslogtreecommitdiff
path: root/backend/canon_dr.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/canon_dr.c')
-rw-r--r--backend/canon_dr.c432
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;
}