From e90781105527158ae2c38d4be4193ab5de34630d Mon Sep 17 00:00:00 2001 From: Peter Kirchgessner Date: Sat, 9 Sep 2000 17:44:14 +0000 Subject: [PATCH] hp-backend V 0.91, 04-Sep-2000, David Paschal (paschal@rcsis.com): - Added support for flatbed HP OfficeJets - (PK) fix problem with cancel preview hp-backend V 0.91, V 0.90, 02-Sep-2000, PK: - fix timing problem between killing child and writing to pipe - change fprintf(stderr,...) to DBG - change include to "sane.." in hp.h - change handling of options that have global effects. i.e. if option scanmode is received (has global effect), all options that "may change" are send to the scanner again. This fixes a problem that --resolution specified infront of --mode on command line of scanimage was ignored. NOTE: This change does not allow to specify --depth 12 infront of --mode color, because --depth is only enabled with --mode color. - add depth greater 8 bits for mode grayscale - add option for 8 bit output but 10/12 bit scanning --- backend/hp-device.c | 54 ++++++--- backend/hp-device.h | 18 +-- backend/hp-handle.c | 130 +++++++++++++++++---- backend/hp-option.c | 273 +++++++++++++++++++++++++++++++++++++------- backend/hp-option.h | 15 +++ backend/hp-scl.c | 259 ++++++++++++++++++++++++++++++++++++----- backend/hp-scl.h | 3 + backend/hp-scsi.h | 2 +- backend/hp.c | 149 +++++++++++++++++++++--- backend/hp.h | 11 +- 10 files changed, 774 insertions(+), 140 deletions(-) diff --git a/backend/hp-device.c b/backend/hp-device.c index 2cd8a5b54..a16cb8008 100644 --- a/backend/hp-device.c +++ b/backend/hp-device.c @@ -157,6 +157,9 @@ sanei_hp_device_support_probe (HpScsi scsi) SCL_BW_DITHER, SCL_CONTRAST, SCL_BRIGHTNESS, +#ifdef SCL_SHARPENING + SCL_SHARPENING, +#endif SCL_MIRROR_IMAGE, SCL_X_RESOLUTION, SCL_Y_RESOLUTION, @@ -175,6 +178,7 @@ sanei_hp_device_support_probe (HpScsi scsi) SCL_CHANGE_DOC, SCL_ADF_BFEED }; + enum hp_device_compat_e compat; DBG(1, "hp_device_support_probe: Check supported commands for %s\n", sanei_hp_scsi_devicename (scsi) ); @@ -194,6 +198,14 @@ sanei_hp_device_support_probe (HpScsi scsi) sclsupport->is_supported = (status == SANE_STATUS_GOOD); sclsupport->checked = 1; + /* The OfficeJets seem to ignore brightness and contrast settings, + * so we'll pretend they're not supported at all. */ + if (((sclprobe[k]==SCL_BRIGHTNESS) || (sclprobe[k]==SCL_CONTRAST)) && + (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) && + (compat & HP_COMPAT_OJ_1150C)) { + sclsupport->is_supported=0; + } + if (sclsupport->is_supported) { DBG(1, "hp_device_support_probe: %d supported (%d..%d, %d)\n", @@ -217,18 +229,20 @@ sanei_hp_device_probe (enum hp_device_compat_e *compat, HpScsi scsi) const char * model; enum hp_device_compat_e flag; } probes[] = { - { SCL_HP_MODEL_1, "Plus", HP_COMPAT_PLUS }, - { SCL_HP_MODEL_2, "IIc", HP_COMPAT_2C }, - { SCL_HP_MODEL_3, "IIp", HP_COMPAT_2P }, - { SCL_HP_MODEL_4, "IIcx", HP_COMPAT_2CX }, - { SCL_HP_MODEL_5, "4c/3c", HP_COMPAT_4C }, - { SCL_HP_MODEL_6, "3p", HP_COMPAT_3P }, - { SCL_HP_MODEL_8, "4P", HP_COMPAT_4P }, - { SCL_HP_MODEL_9, "5P", HP_COMPAT_5P }, - { SCL_HP_MODEL_10, "Photo Scanner", HP_COMPAT_PS }, - { SCL_HP_MODEL_14, "6200C/6250C", HP_COMPAT_6200C }, - { SCL_HP_MODEL_16, "5200C",HP_COMPAT_5200C }, - { SCL_HP_MODEL_17, "6300C/6350C",HP_COMPAT_6300C } + { SCL_HP_MODEL_1, "ScanJet Plus", HP_COMPAT_PLUS }, + { SCL_HP_MODEL_2, "ScanJet IIc", HP_COMPAT_2C }, + { SCL_HP_MODEL_3, "ScanJet IIp", HP_COMPAT_2P }, + { SCL_HP_MODEL_4, "ScanJet IIcx", HP_COMPAT_2CX }, + { SCL_HP_MODEL_5, "ScanJet 3c/4c/6100C", HP_COMPAT_4C }, + { SCL_HP_MODEL_6, "ScanJet 3p", HP_COMPAT_3P }, + { SCL_HP_MODEL_8, "ScanJet 4p", HP_COMPAT_4P }, + { SCL_HP_MODEL_9, "ScanJet 5p/4100C/5100C", HP_COMPAT_5P }, + { SCL_HP_MODEL_10,"PhotoSmart Photo Scanner", HP_COMPAT_PS }, + { SCL_HP_MODEL_11,"OfficeJet 1150C", HP_COMPAT_OJ_1150C }, + { SCL_HP_MODEL_12,"OfficeJet 1170C or later", HP_COMPAT_OJ_1170C }, + { SCL_HP_MODEL_14,"ScanJet 6200C/6250C", HP_COMPAT_6200C }, + { SCL_HP_MODEL_16,"ScanJet 5200C", HP_COMPAT_5200C }, + { SCL_HP_MODEL_17,"ScanJet 6300C/6350C", HP_COMPAT_6300C } }; int i; char buf[8]; @@ -260,7 +274,7 @@ sanei_hp_device_probe (enum hp_device_compat_e *compat, HpScsi scsi) if (!FAILED( status = sanei_hp_scl_upload(scsi, probes[i].cmd, buf, sizeof(buf)) )) { - DBG(1, "probe_scanner: Scanjet %s compatible\n", probes[i].model); + DBG(1, "probe_scanner: %s compatible\n", probes[i].model); *compat |= probes[i].flag; } else if (!UNSUPPORTED( status )) @@ -298,7 +312,7 @@ hp_nonscsi_device_new (HpDevice * newp, const char * devname, HpConnect connect) || memcmp(sanei_hp_scsi_vendor(scsi), "HP ", 8) != 0) { DBG(1, "%s: does not seem to be an HP scanner\n", devname); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); return SANE_STATUS_INVAL; } #endif @@ -307,7 +321,7 @@ hp_nonscsi_device_new (HpDevice * newp, const char * devname, HpConnect connect) if (FAILED( sanei_hp_scl_reset(scsi) )) { DBG(1, "hp_nonscsi_device_new: SCL reset failed\n"); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); return SANE_STATUS_IO_ERROR; } @@ -334,7 +348,7 @@ hp_nonscsi_device_new (HpDevice * newp, const char * devname, HpConnect connect) sanei_hp_device_support_probe (scsi); status = sanei_hp_optset_new(&(this->options), scsi, this); } - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); if (FAILED(status)) { @@ -363,6 +377,8 @@ sanei_hp_device_new (HpDevice * newp, const char * devname) SANE_Status status; char * str; + DBG(3, "sanei_hp_device_new: %s\n", devname); + connect = sanei_hp_get_connect (devname); if ( connect != HP_CONNECT_SCSI ) return hp_nonscsi_device_new (newp, devname, connect); @@ -377,7 +393,7 @@ sanei_hp_device_new (HpDevice * newp, const char * devname) || memcmp(sanei_hp_scsi_vendor(scsi), "HP ", 8) != 0) { DBG(1, "%s: does not seem to be an HP scanner\n", devname); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); return SANE_STATUS_INVAL; } @@ -385,7 +401,7 @@ sanei_hp_device_new (HpDevice * newp, const char * devname) if (FAILED( sanei_hp_scl_reset(scsi) )) { DBG(1, "sanei_hp_device_new: SCL reset failed\n"); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); return SANE_STATUS_IO_ERROR; } @@ -412,7 +428,7 @@ sanei_hp_device_new (HpDevice * newp, const char * devname) sanei_hp_device_support_probe (scsi); status = sanei_hp_optset_new(&this->options, scsi, this); } - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,1); if (FAILED(status)) { diff --git a/backend/hp-device.h b/backend/hp-device.h index 20793d429..549dcbcdd 100644 --- a/backend/hp-device.h +++ b/backend/hp-device.h @@ -47,19 +47,21 @@ #include "hp.h" enum hp_device_compat_e { - HP_COMPAT_PLUS = 1 << 0, /* Hp ScanJet Plus */ + HP_COMPAT_PLUS = 1 << 0, /* HP ScanJet Plus */ HP_COMPAT_2C = 1 << 1, HP_COMPAT_2P = 1 << 2, HP_COMPAT_2CX = 1 << 3, - HP_COMPAT_4C = 1 << 4, /* also for 3C, 6100C */ + HP_COMPAT_4C = 1 << 4, /* also 3c, 6100C */ HP_COMPAT_3P = 1 << 5, HP_COMPAT_4P = 1 << 6, - HP_COMPAT_5P = 1 << 7, - HP_COMPAT_5100C = 1 << 8, /* also 4100 C */ - HP_COMPAT_PS = 1 << 9, /* Hp PhotoSmart Photo Scanner */ - HP_COMPAT_6200C = 1 << 10, - HP_COMPAT_5200C = 1 << 11, - HP_COMPAT_6300C = 1 << 12 + HP_COMPAT_5P = 1 << 7, /* also 4100C, 5100C */ + HP_COMPAT_5100C = 1 << 8, /* redundant with 5p */ + HP_COMPAT_PS = 1 << 9, /* HP PhotoSmart Photo Scanner */ + HP_COMPAT_OJ_1150C = 1 << 10, + HP_COMPAT_OJ_1170C = 1 << 11, /* also later OfficeJets */ + HP_COMPAT_6200C = 1 << 12, + HP_COMPAT_5200C = 1 << 13, + HP_COMPAT_6300C = 1 << 14 }; struct hp_device_s diff --git a/backend/hp-handle.c b/backend/hp-handle.c index 5a3c89fe6..0156a2a56 100644 --- a/backend/hp-handle.c +++ b/backend/hp-handle.c @@ -130,6 +130,7 @@ hp_handle_startReader (HpHandle this, HpScsi scsi, HpProcessData *procdata) /* not closing fds[1] gives an infinite loop on Digital UNIX */ status = sanei_hp_scsi_pipeout(scsi,fds[1],procdata); close (fds[1]); + DBG(3,"hp_handle_startReader: Exiting child (%s)\n",sane_strstatus(status)); _exit(status); } @@ -144,10 +145,10 @@ hp_handle_stopScan (HpHandle this) if (this->reader_pid) { int info; - DBG(3, "do_cancel: killing child (%d)\n", this->reader_pid); + DBG(3, "hp_handle_stopScan: killing child (%d)\n", this->reader_pid); kill(this->reader_pid, SIGTERM); waitpid(this->reader_pid, &info, 0); - DBG(1, "do_cancel: child %s = %d\n", + DBG(1, "hp_handle_stopScan: child %s = %d\n", WIFEXITED(info) ? "exited, status" : "signalled, signal", WIFEXITED(info) ? WEXITSTATUS(info) : WTERMSIG(info)); close(this->pipefd); @@ -161,15 +162,19 @@ hp_handle_stopScan (HpHandle this) sanei_hp_scl_errcheck(scsi); */ sanei_hp_scl_reset(scsi); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,0); } } + else + { + DBG(3, "hp_handle_stopScan: no pid for child\n"); + } return SANE_STATUS_GOOD; } static SANE_Status hp_handle_uploadParameters (HpHandle this, HpScsi scsi, int *scan_depth, - hp_bool_t *soft_invert) + hp_bool_t *soft_invert, hp_bool_t *out8) { SANE_Parameters * p = &this->scan_params; int data_width; @@ -178,6 +183,7 @@ hp_handle_uploadParameters (HpHandle this, HpScsi scsi, int *scan_depth, assert(scsi); *soft_invert = 0; + *out8 = 0; p->last_frame = SANE_TRUE; /* inquire resulting size of image after setting it up */ @@ -196,17 +202,48 @@ hp_handle_uploadParameters (HpHandle this, HpScsi scsi, int *scan_depth, p->format = SANE_FRAME_GRAY; p->depth = 1; *scan_depth = 1; + + /* The OfficeJets don't seem to handle SCL_INVERSE_IMAGE, so we'll + * have to invert in software. */ + if ((sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) + && (compat & HP_COMPAT_OJ_1150C)) { + *soft_invert=1; + } + break; case HP_SCANMODE_GRAYSCALE: /* Grayscale */ p->format = SANE_FRAME_GRAY; - p->depth = 8; - *scan_depth = 8; + p->depth = (data_width > 8) ? 16 : 8; + *scan_depth = data_width; + + /* 8 bit output forced ? */ + if ( *scan_depth > 8 ) + { + *out8 = sanei_hp_optset_output_8bit (this->dev->options, this->data); + DBG(1,"hp_handle_uploadParameters: out8=%d\n", (int)*out8); + if (*out8) + { + p->depth = 8; + p->bytes_per_line /= 2; + } + } break; case HP_SCANMODE_COLOR: /* RGB */ p->format = SANE_FRAME_RGB; p->depth = (data_width > 24) ? 16 : 8; *scan_depth = data_width / 3; + /* 8 bit output forced ? */ + if ( *scan_depth > 8 ) + { + *out8 = sanei_hp_optset_output_8bit (this->dev->options, this->data); + DBG(1,"hp_handle_uploadParameters: out8=%d\n", (int)*out8); + if (*out8) + { + p->depth = 8; + p->bytes_per_line /= 2; + } + } /* HP PhotoSmart does not invert when depth > 8. Lets do it by software */ if ( (*scan_depth > 8) && (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) @@ -245,7 +282,17 @@ sanei_hp_handle_new (HpDevice dev) void sanei_hp_handle_destroy (HpHandle this) { + HpScsi scsi=0; + + DBG(3,"sanei_hp_handle_destroy: stop scan\n"); + hp_handle_stopScan(this); + + if (sanei_hp_scsi_new(&scsi,this->dev->sanedev.name)==SANE_STATUS_GOOD && + scsi) { + sanei_hp_scsi_destroy(scsi,1); + } + sanei_hp_data_destroy(this->data); sanei_hp_free(this); } @@ -253,6 +300,11 @@ sanei_hp_handle_destroy (HpHandle this) const SANE_Option_Descriptor * sanei_hp_handle_saneoption (HpHandle this, SANE_Int optnum) { + if (this->cancelled) + { + DBG(1, "sanei_hp_handle_saneoption: cancelled. Stop scan\n"); + hp_handle_stopScan(this); + } return sanei_hp_optset_saneoption(this->dev->options, this->data, optnum); } @@ -264,10 +316,11 @@ sanei_hp_handle_control(HpHandle this, SANE_Int optnum, HpScsi scsi; hp_bool_t immediate; -#if 0 - if (hp_handle_isScanning(this)) - return SANE_STATUS_DEVICE_BUSY; -#endif + if (this->cancelled) + { + DBG(1, "sanei_hp_handle_control: cancelled. Stop scan\n"); + RETURN_IF_FAIL( hp_handle_stopScan(this) ); + } if (hp_handle_isScanning(this)) return SANE_STATUS_DEVICE_BUSY; @@ -279,7 +332,7 @@ sanei_hp_handle_control(HpHandle this, SANE_Int optnum, status = sanei_hp_optset_control(this->dev->options, this->data, optnum, action, valp, info, scsi, immediate); - sanei_hp_scsi_destroy ( scsi ); + sanei_hp_scsi_destroy ( scsi,0 ); return status; } @@ -292,6 +345,12 @@ sanei_hp_handle_getParameters (HpHandle this, SANE_Parameters *params) if (!params) return SANE_STATUS_GOOD; + if (this->cancelled) + { + DBG(1, "sanei_hp_handle_getParameters: cancelled. Stop scan\n"); + RETURN_IF_FAIL( hp_handle_stopScan(this) ); + } + if (hp_handle_isScanning(this)) { *params = this->scan_params; @@ -310,7 +369,7 @@ sanei_hp_handle_getParameters (HpHandle this, SANE_Parameters *params) if (!FAILED( sanei_hp_scsi_new(&scsi, this->dev->sanedev.name) )) { RETURN_IF_FAIL( sanei_hp_scl_inquire(scsi, SCL_NUMBER_OF_LINES, &p->lines,0,0)); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,0); *params = this->scan_params; } } @@ -330,7 +389,10 @@ sanei_hp_handle_startScan (HpHandle this) /* FIXME: setup preview mode stuff? */ if (hp_handle_isScanning(this)) + { + DBG(3,"sanei_hp_handle_startScan: Stop current scan\n"); RETURN_IF_FAIL( hp_handle_stopScan(this) ); + } RETURN_IF_FAIL( sanei_hp_scsi_new(&scsi, this->dev->sanedev.name) ); @@ -339,11 +401,12 @@ sanei_hp_handle_startScan (HpHandle this) if (!FAILED(status)) status = hp_handle_uploadParameters(this, scsi, &(procdata.bits_per_channel), - &(procdata.invert)); + &(procdata.invert), + &(procdata.out8)); if (FAILED(status)) { - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,0); return status; } @@ -394,10 +457,16 @@ sanei_hp_handle_startScan (HpHandle this) this->bytes_left = ( this->scan_params.bytes_per_line * this->scan_params.lines ); - DBG(1, "start: %d pixels per line, %d bytes, %d lines high\n", + DBG(1, "start: %d pixels per line, %d bytes per line, %d lines high\n", this->scan_params.pixels_per_line, this->scan_params.bytes_per_line, this->scan_params.lines); procdata.bytes_per_line = (int)this->scan_params.bytes_per_line; + if (procdata.out8) + { + procdata.bytes_per_line *= 2; + DBG(1,"(scanner will send %d bytes per line, 8 bit output forced)\n", + procdata.bytes_per_line); + } procdata.lines = this->scan_params.lines; /* Wait for front-panel button push ? */ @@ -419,7 +488,7 @@ sanei_hp_handle_startScan (HpHandle this) status = hp_handle_startReader(this, scsi, &procdata); } - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,0); return status; } @@ -431,17 +500,18 @@ sanei_hp_handle_read (HpHandle this, void * buf, size_t *lengthp) ssize_t nread; SANE_Status status; - DBG(3, "read: trying to read %lu bytes\n", (unsigned long) *lengthp); + DBG(3, "sanei_hp_handle_read: trying to read %lu bytes\n", + (unsigned long) *lengthp); if (!hp_handle_isScanning(this)) { - DBG(1, "read: not scanning\n"); + DBG(1, "sanei_hp_handle_read: not scanning\n"); return SANE_STATUS_INVAL; } if (this->cancelled) { - DBG(1, "read: cancelled\n"); + DBG(1, "sanei_hp_handle_read: cancelled. Stop scan\n"); RETURN_IF_FAIL( hp_handle_stopScan(this) ); return SANE_STATUS_CANCELLED; } @@ -457,7 +527,8 @@ sanei_hp_handle_read (HpHandle this, void * buf, size_t *lengthp) *lengthp = 0; if (errno == EAGAIN) return SANE_STATUS_GOOD; - DBG(1, "read: read from pipe: %s\n", strerror(errno)); + DBG(1, "sanei_hp_handle_read: read from pipe: %s. Stop scan\n", + strerror(errno)); hp_handle_stopScan(this); return SANE_STATUS_IO_ERROR; } @@ -466,11 +537,11 @@ sanei_hp_handle_read (HpHandle this, void * buf, size_t *lengthp) if (nread > 0) { - DBG(3, "read: read %lu bytes\n", (unsigned long) nread); + DBG(3, "sanei_hp_handle_read: read %lu bytes\n", (unsigned long) nread); return SANE_STATUS_GOOD; } - DBG(1, "read: EOF from pipe\n"); + DBG(1, "sanei_hp_handle_read: EOF from pipe. Stop scan\n"); status = this->bytes_left ? SANE_STATUS_IO_ERROR : SANE_STATUS_EOF; RETURN_IF_FAIL( hp_handle_stopScan(this) ); @@ -486,7 +557,7 @@ sanei_hp_handle_read (HpHandle this, void * buf, size_t *lengthp) == SANE_STATUS_GOOD ) { sanei_hp_scl_set(scsi, SCL_UNLOAD, 0); - sanei_hp_scsi_destroy(scsi); + sanei_hp_scsi_destroy(scsi,0); } } } @@ -497,6 +568,17 @@ void sanei_hp_handle_cancel (HpHandle this) { this->cancelled = 1; + /* Office-Jets (K series) may not deliver enough data. */ + /* Therefor the read might not return until it is interrupted. */ + DBG(3,"sanei_hp_handle_cancel: compat flags: 0x%04x\n", + (int)this->dev->compat); + if ( (this->reader_pid) + && (this->dev->compat & (HP_COMPAT_OJ_1150C | HP_COMPAT_OJ_1170C)) ) + { + DBG(3,"sanei_hp_handle_cancel: send SIGTERM to child (%d)\n", + this->reader_pid); + kill(this->reader_pid, SIGTERM); + } } SANE_Status @@ -507,6 +589,7 @@ sanei_hp_handle_setNonblocking (HpHandle this, hp_bool_t non_blocking) if (this->cancelled) { + DBG(3,"sanei_hp_handle_setNonblocking: cancelled. Stop scan\n"); RETURN_IF_FAIL( hp_handle_stopScan(this) ); return SANE_STATUS_CANCELLED; } @@ -525,6 +608,7 @@ sanei_hp_handle_getPipefd (HpHandle this, SANE_Int *fd) if (this->cancelled) { + DBG(3,"sanei_hp_handle_getPipefd: cancelled. Stop scan\n"); RETURN_IF_FAIL( hp_handle_stopScan(this) ); return SANE_STATUS_CANCELLED; } diff --git a/backend/hp-option.c b/backend/hp-option.c index 22715e75f..35e741412 100644 --- a/backend/hp-option.c +++ b/backend/hp-option.c @@ -147,7 +147,6 @@ struct hp_option_descriptor_s HpScl scl_command; int minval, maxval, startval; /* for simulation */ HpChoice choices; - /* unsigned nchan, chan */ }; struct hp_data_info_s @@ -163,7 +162,7 @@ static const struct hp_option_descriptor_s GAMMA_VECTOR_7x12[1], RGB_TONEMAP[1], GAMMA_VECTOR_R[1], GAMMA_VECTOR_G[1], GAMMA_VECTOR_B[1], #endif - HALFTONE_PATTERN[1], MEDIA[1], BIT_DEPTH[1], SCAN_SOURCE[1], + HALFTONE_PATTERN[1], MEDIA[1], OUT8[1], BIT_DEPTH[1], SCAN_SOURCE[1], #ifdef FAKE_COLORSEP_MATRIXES SEPMATRIX[1], #endif @@ -517,7 +516,7 @@ hp_option_imm_set (HpOptSet optset, HpOption this, HpData data, if (FAILED( status = sanei_constrain_value(optd, valp, info) )) { - DBG(1, "option_set: %s: constrain_value failed :%s\n", + DBG(1, "option_imm_set: %s: constrain_value failed :%s\n", this->descriptor->name, sane_strstatus(status)); return status; } @@ -526,7 +525,7 @@ hp_option_imm_set (HpOptSet optset, HpOption this, HpData data, if (_values_are_equal(this, data, old_val, valp)) { - DBG(3, "option_set: value unchanged\n"); + DBG(3, "option_imm_set: value unchanged\n"); return SANE_STATUS_GOOD; } @@ -557,6 +556,7 @@ hp_option_set (HpOption this, HpData data, void * valp, SANE_Int * info) HpSaneOption optd = hp_option_saneoption(this, data); hp_byte_t * old_val = alloca(optd->size); SANE_Status status; + char sval[64]; if (!SANE_OPTION_IS_SETTABLE(optd->cap) || !this->data_acsr) @@ -564,6 +564,12 @@ hp_option_set (HpOption this, HpData data, void * valp, SANE_Int * info) if (!old_val) return SANE_STATUS_NO_MEM; + sval[0] = '\0'; + if (this->descriptor->type == SANE_TYPE_INT) + sprintf (sval," value=%d", *(int*)valp); + + DBG(10,"hp_option_set: %s%s\n", this->descriptor->name, sval); + if (FAILED( status = sanei_constrain_value(optd, valp, info) )) { DBG(1, "option_set: %s: constrain_value failed :%s\n", @@ -575,7 +581,7 @@ hp_option_set (HpOption this, HpData data, void * valp, SANE_Int * info) if (_values_are_equal(this, data, old_val, valp)) { - DBG(3, "option_set: value unchanged\n"); + DBG(3, "option_set: %s: value unchanged\n",this->descriptor->name); return SANE_STATUS_GOOD; } @@ -592,6 +598,9 @@ hp_option_set (HpOption this, HpData data, void * valp, SANE_Int * info) *info |= SANE_INFO_RELOAD_OPTIONS; if (this->descriptor->affects_scan_params) *info |= SANE_INFO_RELOAD_PARAMS; + + DBG(3, "option_set: %s: info=0x%lx\n",this->descriptor->name, + (long)*info); } return SANE_STATUS_GOOD; @@ -644,11 +653,28 @@ hp_option_control (HpOption this, HpData data, } } + +static void +hp_option_reprogram (HpOption this, HpOptSet optset, HpData data, HpScsi scsi) +{ + if (this->descriptor->may_change) + { + DBG(5, "hp_option_reprogram: %s\n", this->descriptor->name); + + hp_option_program (this, scsi, optset, data); + } +} + + static void hp_option_reprobe (HpOption this, HpOptSet optset, HpData data, HpScsi scsi) { if (this->descriptor->may_change) + { + DBG(5, "hp_option_reprobe: %s\n", this->descriptor->name); + (*this->descriptor->probe)((_HpOption)this, scsi, optset, data); + } } static void @@ -701,7 +727,7 @@ _set_size (HpOption opt, HpData data, SANE_Int size) _hp_option_saneoption(opt, data)->size = size; } -#ifdef HP_EXPERIMENTAL +/* #ifdef HP_EXPERIMENTAL */ static SANE_Status _probe_int (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) { @@ -722,7 +748,7 @@ _probe_int (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) _set_size(this, data, sizeof(SANE_Int)); return _set_range(this, data, minval, 1, maxval); } -#endif +/* #endif */ static SANE_Status _probe_int_brightness (_HpOption this, HpScsi scsi, HpOptSet optset, @@ -787,6 +813,14 @@ _probe_resolution (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) sanei_hp_accessor_setint(this->data_acsr, data, val); _set_size(this, data, sizeof(SANE_Int)); + /* The HP OfficeJet Pro 1150C crashes the scan head when scanning at + * resolutions less than 42 dpi. Set a safe minimum resolution. + * Hopefully 50 dpi is safe enough. */ + if ((sanei_hp_device_probe(&compat,scsi)==SANE_STATUS_GOOD) && + ((compat&(HP_COMPAT_OJ_1150C|HP_COMPAT_OJ_1170C))==HP_COMPAT_OJ_1150C)) { + if (minval<50) minval=50; + } + /* HP Photosmart scanner does not allow scanning at arbitrary resolutions */ /* for slides/negatives. Must be multiple of 300 dpi. Set quantization. */ @@ -824,17 +858,6 @@ _probe_bool (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) return SANE_STATUS_GOOD; } -static SANE_Status -_probe_preview (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) -{ - int val = 0; - - if (!(this->data_acsr = sanei_hp_accessor_bool_new(data))) - return SANE_STATUS_NO_MEM; - sanei_hp_accessor_setint(this->data_acsr, data, val); - _set_size(this, data, sizeof(SANE_Bool)); - return SANE_STATUS_GOOD; -} static SANE_Status _probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) @@ -862,6 +885,36 @@ _probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) return SANE_STATUS_GOOD; } +/* The OfficeJets support SCL_UNLOAD even when no ADF is installed, so + * this function was added to check for SCL_ADF_CAPABILITY, similar to + * _probe_change_doc(), to hide the unnecessary "Unload" button on + * non-ADF OfficeJets. */ +static SANE_Status +_probe_unload (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) + +{SANE_Status status; + int cap = 0; + + DBG(2, "probe_unload: inquire ADF capability\n"); + + status = sanei_hp_scl_inquire(scsi, SCL_ADF_CAPABILITY, &cap, 0, 0); + if ( (status != SANE_STATUS_GOOD) || (cap == 0)) + return SANE_STATUS_UNSUPPORTED; + + DBG(2, "probe_unload: check if unload is supported\n"); + + status = sanei_hp_scl_inquire(scsi, SCL_UNLOAD, &cap, 0, 0); + if ( status != SANE_STATUS_GOOD ) + return SANE_STATUS_UNSUPPORTED; + + if (!(this->data_acsr = sanei_hp_accessor_bool_new(data))) + return SANE_STATUS_NO_MEM; + sanei_hp_accessor_setint(this->data_acsr, data, cap); + _set_size(this, data, sizeof(SANE_Bool)); + + return SANE_STATUS_GOOD; +} + static SANE_Status _probe_calibrate (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) { @@ -871,6 +924,13 @@ _probe_calibrate (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) int download_calib_file = 1; enum hp_device_compat_e compat; + /* The OfficeJets don't seem to support calibration, so we'll + * remove it from the option list to reduce frontend clutter. */ + if ((sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) && + (compat & HP_COMPAT_OJ_1150C)) { + return SANE_STATUS_UNSUPPORTED; + } + /* If we have a Photosmart scanner, we only download the calibration file */ /* when medium is set to prints */ media = -1; @@ -972,14 +1032,24 @@ _probe_choice (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) { enum hp_scanmode_e scanmode = sanei_hp_optset_scanmode (optset, data); - /* Some PhotoSmart scanner report support for only 24 bit. */ - /* But they also support 30 bit. Dont rely on the inquire in this case */ - if ( (maxval == 24) - && (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) + /* The data width inquiries seem not to work properly on PhotoSmart */ + /* Sometimes they report just 24 bits, but support 30 bits too. */ + /* Sometimes they report min/max to be 24/8. Assume they all support */ + /* at least 10 bits per channel for RGB. Grayscale is only supported */ + /* with 8 bits. */ + if ( (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) && (compat & HP_COMPAT_PS)) { - DBG(1, "choice_option_probe: set max. datawidth to 30 for photosmart"); - maxval = 30; + if (scanmode == HP_SCANMODE_GRAYSCALE) + { + minval = 8; if (maxval < 8) maxval = 8; + } + else if (scanmode == HP_SCANMODE_COLOR) + { + minval = 24; if (maxval < 30) maxval = 30; + } + DBG(1, "choice_option_probe: set max. datawidth to %d for photosmart\n", + maxval); } if ( scanmode == HP_SCANMODE_COLOR ) @@ -988,6 +1058,15 @@ _probe_choice (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) maxval /= 3; if ( maxval <= 0) maxval = 1; val /= 3; if (val <= 0) val = 1; } + +#if 0 + /* The OfficeJets claim to support >8 bits per color, but it may not + * work on some models. This code (if not commented out) disables it. */ + if ((sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) && + (compat & HP_COMPAT_OJ_1150C)) { + if (maxval>8) maxval=8; + } +#endif } choices = _make_choice_list(this->descriptor->choices, minval, maxval); @@ -1114,7 +1193,8 @@ _probe_scan_type (_HpOption this, HpScsi scsi, HpOptSet optset, /* Inquire XPA capability is supported only by IIcx and 6100c/4c/3c. */ /* But more devices support XPA scan window. So dont inquire XPA cap. */ if ( compat & ( HP_COMPAT_2CX | HP_COMPAT_4C | HP_COMPAT_4P - | HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_6200C) ) + | HP_COMPAT_5P | HP_COMPAT_5100C | HP_COMPAT_6200C) && + !(compat&HP_COMPAT_OJ_1150C) ) { scan_types[numchoices++] = this->descriptor->choices[2]; } @@ -1222,8 +1302,6 @@ static SANE_Status _probe_front_button(_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) { int val = 0; - const HpDeviceInfo *info = - sanei_hp_device_info_get(sanei_hp_scsi_devicename(scsi)); if ( sanei_hp_scl_inquire(scsi, SCL_FRONT_BUTTON, &val, 0, 0) != SANE_STATUS_GOOD ) @@ -2412,8 +2490,22 @@ _enable_halftonevec (HpOption this, HpOptSet optset, HpData data, static hp_bool_t _enable_data_width (HpOption this, HpOptSet optset, HpData data, const HpDeviceInfo *info) +{enum hp_scanmode_e mode; + + mode = sanei_hp_optset_scanmode (optset, data); + return ( (mode == HP_SCANMODE_GRAYSCALE) || (mode == HP_SCANMODE_COLOR) ); +} + +static hp_bool_t +_enable_out8 (HpOption this, HpOptSet optset, HpData data, + const HpDeviceInfo *info) { - return (sanei_hp_optset_scanmode (optset, data) == HP_SCANMODE_COLOR); + if (hp_optset_isEnabled (optset, data, SANE_NAME_BIT_DEPTH, info)) + { + int data_width = sanei_hp_optset_data_width (optset, data); + return (((data_width > 8) && (data_width <= 16)) || (data_width > 24)); + } + return 0; } static hp_bool_t @@ -2507,7 +2599,7 @@ static const struct hp_option_descriptor_s SCAN_MODE_GROUP[1] = {{ static const struct hp_option_descriptor_s PREVIEW_MODE[1] = {{ SCANNER_OPTION(PREVIEW, BOOL, NONE), NO_REQUIRES, - _probe_preview, + _probe_bool, 0,0,0,0,0,0,0,0,0,0,0,0 /* for gcc-s sake */ }}; @@ -2553,6 +2645,14 @@ static const struct hp_option_descriptor_s CONTRAST[1] = {{ _probe_int_brightness, _program_generic_simulate, _enable_brightness, 0, 0, 0, 0, 0, SCL_CONTRAST, -127, 127, 0, 0 }}; +#ifdef SCL_SHARPENING +static const struct hp_option_descriptor_s SHARPENING[1] = {{ + SCANNER_OPTION(SHARPENING, INT, NONE), + NO_REQUIRES, + _probe_int, _program_generic, 0, + 0, 0, 0, 0, 0, SCL_SHARPENING, -127, 127, 0, 0 +}}; +#endif static const struct hp_option_descriptor_s AUTO_THRESHOLD[1] = {{ SCANNER_OPTION(AUTO_THRESHOLD, BOOL, NONE), NO_REQUIRES, @@ -2779,6 +2879,27 @@ static const struct hp_option_descriptor_s BIT_DEPTH[1] = {{ 1, 1, 1, 0, 1, SCL_DATA_WIDTH, 0, 0, 0, _data_widths }}; +static const struct hp_option_descriptor_s OUT8[1] = +{ + { + SCANNER_OPTION(OUTPUT_8BIT, BOOL, NONE), + NO_REQUIRES, /* enum hp_device_compat_e requires */ + _probe_bool, /* SANE_Status (*probe)() */ + 0, /* SANE_Status (*program)() */ + _enable_out8, /* hp_bool_t (*enable)() */ + 0, /* hp_bool_t has_global_effect */ + 0, /* hp_bool_t affects_scan_params */ + 0, /* hp_bool_t program_immediate */ + 0, /* hp_bool_t suppress_for_scan */ + 0, /* hp_bool_t may_change */ + 0, /* HpScl scl_command */ + 0, /* int minval */ + 0, /* int maxval */ + 0, /* int startval */ + 0 /* HpChoice choices */ + } +}; + /* The 100% setting may cause problems within the scanner */ static const struct hp_choice_s _ps_exposure_times[] = { /* {0, "100%", 0, 0, 0}, */ @@ -2839,7 +2960,7 @@ static const struct hp_option_descriptor_s CHANGE_DOC[1] = {{ static const struct hp_option_descriptor_s UNLOAD[1] = {{ SCANNER_OPTION(UNLOAD, BUTTON, NONE), NO_REQUIRES, - _probe_bool, _program_unload, 0, + _probe_unload, _program_unload, 0, 0, 0, 1, 1, 0, SCL_UNLOAD, 0, 0, 0, 0 }}; @@ -2983,7 +3104,11 @@ static HpOptionDescriptor hp_options[] = { SCAN_MODE, SCAN_RESOLUTION, DEVPIX_RESOLUTION, ENHANCEMENT_GROUP, - BRIGHTNESS, CONTRAST, AUTO_THRESHOLD, + BRIGHTNESS, CONTRAST, +#ifdef SCL_SHARPENING + SHARPENING, +#endif + AUTO_THRESHOLD, ADVANCED_GROUP, CUSTOM_GAMMA, @@ -3008,7 +3133,7 @@ static HpOptionDescriptor hp_options[] = { #endif HALFTONE_PATTERN_8x8, HORIZONTAL_DITHER_8x8, - SCAN_SPEED, SMOOTHING, MEDIA, PS_EXPOSURE_TIME, BIT_DEPTH, + SCAN_SPEED, SMOOTHING, MEDIA, PS_EXPOSURE_TIME, BIT_DEPTH, OUT8, SCAN_SOURCE, BUTTON_WAIT, UNLOAD_AFTER_SCAN, CHANGE_DOC, UNLOAD, CALIBRATE, @@ -3099,6 +3224,25 @@ sanei_hp_optset_scanmode (HpOptSet this, HpData data) return hp_option_getint(mode, data); } + +hp_bool_t +sanei_hp_optset_output_8bit (HpOptSet this, HpData data) +{ + HpOption option_out8; + int out8; + + option_out8 = hp_optset_get(this, OUT8); + if (option_out8) + { + out8 = hp_option_getint(option_out8, data); + return out8; + } + return 0; +} + + +/* Returns the data width that is send to the scanner, depending */ +/* on the scanmode. (b/w: 1, gray: 8..12, color: 24..36 */ int sanei_hp_optset_data_width (HpOptSet this, HpData data) { @@ -3114,12 +3258,19 @@ sanei_hp_optset_data_width (HpOptSet this, HpData data) break; case HP_SCANMODE_GRAYSCALE: - datawidth = 8; + opt_dwidth = hp_optset_get(this, BIT_DEPTH); + if (opt_dwidth) + datawidth = hp_option_getint (opt_dwidth, data); + else + datawidth = 8; break; case HP_SCANMODE_COLOR: opt_dwidth = hp_optset_get(this, BIT_DEPTH); - datawidth = 3 * hp_option_getint (opt_dwidth, data); + if (opt_dwidth) + datawidth = 3 * hp_option_getint (opt_dwidth, data); + else + datawidth = 24; break; } return datawidth; @@ -3148,7 +3299,7 @@ sanei_hp_optset_mirror_vert (HpOptSet this, HpData data, HpScsi scsi) hp_bool_t sanei_hp_optset_start_wait(HpOptSet this, HpData data, HpScsi scsi) { HpOption mode; - int wait, sec_dir; + int wait; if ((mode = hp_optset_get(this, BUTTON_WAIT)) == 0) return(0); @@ -3254,6 +3405,20 @@ hp_optset_fix_geometry_options (HpOptSet this, HpDevice dev) return SANE_STATUS_GOOD; } +static void +hp_optset_reprogram (HpOptSet this, HpData data, HpScsi scsi) +{ + int i; + + DBG(5, "hp_optset_reprogram: %lu options\n", + (unsigned long) this->num_opts); + + for (i = 0; i < (int)this->num_opts; i++) + hp_option_reprogram(this->options[i], this, data, scsi); + + DBG(5, "hp_optset_reprogram: finished\n"); +} + static void hp_optset_reprobe (HpOptSet this, HpData data, HpScsi scsi) { @@ -3265,6 +3430,7 @@ hp_optset_reprobe (HpOptSet this, HpData data, HpScsi scsi) for (i = 0; i < (int)this->num_opts; i++) hp_option_reprobe(this->options[i], this, data, scsi); + DBG(5, "hp_optset_reprobe: finished\n"); } static void @@ -3344,6 +3510,8 @@ sanei_hp_optset_download (HpOptSet this, HpData data, HpScsi scsi) is_preview = hp_option_getint (option, data); if ( is_preview ) { + /* For preview we only use 8 bit per channel */ + DBG(3, "sanei_hp_optset_download: Set up preview options\n"); info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) ); @@ -3355,6 +3523,10 @@ sanei_hp_optset_download (HpOptSet this, HpData data, HpScsi scsi) { sanei_hp_scl_set(scsi, SCL_DATA_WIDTH, 24); } + else if ((data_width > 8) && (data_width <= 16)) + { + sanei_hp_scl_set(scsi, SCL_DATA_WIDTH, 8); + } } } } @@ -3441,6 +3613,8 @@ sanei_hp_optset_control (HpOptSet this, HpData data, HpOption opt = hp_optset_getByIndex(this, optnum); SANE_Int my_info = 0; + DBG(3,"sanei_hp_optset_control: %s\n", opt ? opt->descriptor->name : ""); + if (infop) *infop = 0; else @@ -3458,6 +3632,15 @@ sanei_hp_optset_control (HpOptSet this, HpData data, if ((*infop & SANE_INFO_RELOAD_OPTIONS) != 0) {const HpDeviceInfo *info; + DBG(3,"sanei_hp_optset_control: reprobe\n"); + + /* At first we try to reprogram the parameters that may have changed */ + /* by an option that had a global effect. This is necessary to */ + /* specify options in an arbitrary order. Example: */ + /* Changing scan mode resets scan resolution in the scanner. */ + /* If resolution is set from the API before scan mode, we must */ + /* reprogram the resolution afterwards. */ + hp_optset_reprogram(this, data, scsi); hp_optset_reprobe(this, data, scsi); info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) ); hp_optset_updateEnables(this, data, info); @@ -3492,16 +3675,28 @@ sanei_hp_optset_guessParameters (HpOptSet this, HpData data, p->format = SANE_FRAME_GRAY; p->depth = 8; p->bytes_per_line = p->pixels_per_line; + if ( !sanei_hp_optset_output_8bit (this, data) ) + { + data_width = sanei_hp_optset_data_width (this, data); + if ( data_width > 8 ) + { + p->depth *= 2; + p->bytes_per_line *= 2; + } + } break; case HP_SCANMODE_COLOR: /* RGB */ p->format = SANE_FRAME_RGB; p->depth = 8; p->bytes_per_line = 3 * p->pixels_per_line; - data_width = sanei_hp_optset_data_width (this, data); - if ( data_width > 24 ) + if ( !sanei_hp_optset_output_8bit (this, data) ) { - p->depth *= 2; - p->bytes_per_line *= 2; + data_width = sanei_hp_optset_data_width (this, data); + if ( data_width > 24 ) + { + p->depth *= 2; + p->bytes_per_line *= 2; + } } break; default: diff --git a/backend/hp-option.h b/backend/hp-option.h index 2467e3a99..622076749 100644 --- a/backend/hp-option.h +++ b/backend/hp-option.h @@ -51,6 +51,13 @@ * * FIXME: this should become standard */ + +#ifndef SANE_NAME_SHARPENING +# define SANE_NAME_SHARPENING "sharpening" +# define SANE_TITLE_SHARPENING "Sharpening" +# define SANE_DESC_SHARPENING "Set sharpening value." +#endif + #ifndef SANE_NAME_AUTO_THRESHOLD # define SANE_NAME_AUTO_THRESHOLD "auto-threshold" # define SANE_TITLE_AUTO_THRESHOLD "Auto Threshold" @@ -140,6 +147,13 @@ # define SANE_DESC_UPDATE "Update options." #endif +#ifndef SANE_NAME_OUTPUT_8BIT +# define SANE_NAME_OUTPUT_8BIT "output-8bit" +# define SANE_TITLE_OUTPUT_8BIT "8 bit output" +# define SANE_DESC_OUTPUT_8BIT "Use bit depth greater eight internally,\ + but output only eight bits" +#endif + #ifndef SANE_NAME_BUTTON_WAIT # define SANE_NAME_BUTTON_WAIT "button-wait" # define SANE_TITLE_BUTTON_WAIT "Front button wait" @@ -248,6 +262,7 @@ SANE_Status sanei_hp_optset_control (HpOptSet this, HpData data, SANE_Status sanei_hp_optset_guessParameters (HpOptSet this, HpData data, SANE_Parameters * p); enum hp_scanmode_e sanei_hp_optset_scanmode (HpOptSet this, HpData data); +hp_bool_t sanei_hp_optset_output_8bit (HpOptSet this, HpData data); int sanei_hp_optset_data_width (HpOptSet this, HpData data); hp_bool_t sanei_hp_optset_isImmediate (HpOptSet this, int optnum); hp_bool_t sanei_hp_optset_mirror_vert (HpOptSet this, HpData data, HpScsi scsi); diff --git a/backend/hp-scl.c b/backend/hp-scl.c index 47faa5426..1a12f2ce5 100644 --- a/backend/hp-scl.c +++ b/backend/hp-scl.c @@ -69,6 +69,10 @@ extern int sanei_debug_hp; #include "hp-scsi.h" #include "hp-scl.h" +#ifdef HAVE_PTAL +#include +#endif + #define HP_SCSI_INQ_LEN (36) #define HP_SCSI_CMD_LEN (6) #define HP_SCSI_BUFSIZ (HP_SCSI_MAX_WRITE + HP_SCSI_CMD_LEN) @@ -80,6 +84,10 @@ extern int sanei_debug_hp; */ struct hp_scsi_s { +#ifdef HAVE_PTAL + ptalDevice_t dev; + ptalChannel_t chan; +#endif int fd; char * devname; @@ -119,6 +127,10 @@ static SANE_Status hp_nonscsi_write (HpScsi this, hp_byte_t *data, size_t len, HpConnect connect) {int n = -1; +#ifdef HAVE_PTAL + int isReset; + struct timeval startTimeout,continueTimeout; +#endif if (len <= 0) return SANE_STATUS_GOOD; @@ -140,6 +152,45 @@ hp_nonscsi_write (HpScsi this, hp_byte_t *data, size_t len, HpConnect connect) n = -1; break; + case HP_CONNECT_PTAL: +#ifndef HAVE_PTAL + n = -1; +#else + /* Check to see if we need to re-open the scan channel in case + * JetDirect closed it due to an idle timeout. */ + if (ptalChannelOpenOrReopen(this->chan)==PTAL_ERROR) { + + break; + } + if (ptalChannelPrepareForSelect(this->chan,&this->fd,0,0,0,0)== + PTAL_ERROR) { + + break; + } + + /* If we're sending an SCL RESET command, then flush stale + * response data after sending the command. Otherwise, + * flush stale data before sending the command. This is + * necessary because data is buffered between us and the + * scanner, which will not be affected by the SCL RESET. */ + isReset=(len==2 && data[0]==27 && data[1]=='E'); + startTimeout.tv_sec=0; + startTimeout.tv_usec=0; + continueTimeout.tv_sec=2; + continueTimeout.tv_usec=0; + + if (!isReset) { + ptalChannelFlush(this->chan,&startTimeout,&continueTimeout); + } + + n=ptalChannelWrite(this->chan,data,len); + + if (isReset) { + ptalChannelFlush(this->chan,&startTimeout,&continueTimeout); + } +#endif + break; + default: n = -1; break; @@ -152,9 +203,13 @@ hp_nonscsi_write (HpScsi this, hp_byte_t *data, size_t len, HpConnect connect) } static SANE_Status -hp_nonscsi_read (HpScsi this, hp_byte_t *data, size_t *len, HpConnect connect) +hp_nonscsi_read (HpScsi this, hp_byte_t *data, size_t *len, HpConnect connect, + int isResponse) {int n = -1; +#ifdef HAVE_PTAL + struct timeval continueTimeout; +#endif if (*len <= 0) return SANE_STATUS_GOOD; @@ -176,6 +231,18 @@ hp_nonscsi_read (HpScsi this, hp_byte_t *data, size_t *len, HpConnect connect) n = -1; break; + case HP_CONNECT_PTAL: +#ifndef HAVE_PTAL + n = -1; +#else + continueTimeout.tv_sec=0; + if (isResponse) continueTimeout.tv_sec=1; + if (*len>1024) continueTimeout.tv_sec=2; + continueTimeout.tv_usec=10000; + n=ptalSclChannelRead(this->chan,data,*len,0,&continueTimeout,isResponse); +#endif + break; + default: n = -1; break; @@ -237,6 +304,12 @@ hp_nonscsi_open (const char *devname, int *fd, HpConnect connect) status = SANE_STATUS_INVAL; break; + case HP_CONNECT_PTAL: + /* This is handled in hp_nonscsi_write() + * because we need more than the file descriptor. */ + status = SANE_STATUS_INVAL; + break; + default: status = SANE_STATUS_INVAL; break; @@ -271,6 +344,11 @@ hp_nonscsi_close (int fd, HpConnect connect) case HP_CONNECT_RESERVE: break; + case HP_CONNECT_PTAL: + /* This is handled in hp_scsi_close() + * because we need more than the file descriptor. */ + break; + default: break; } @@ -286,6 +364,26 @@ sanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect) if (!new) return SANE_STATUS_NO_MEM; +#ifdef HAVE_PTAL + if (connect==HP_CONNECT_PTAL) { + /* The constant allocation and deallocation of the HpScsi object + * does not work well with OfficeJets, especially when connected + * to JetDirect. As a somewhat inefficient workaround, we + * allocate and set up the PTAL channel once, and look it up by + * device name and service type on successive HpScsi instantiations. */ + new->dev=ptalDeviceOpen((char *)devname); + if (!new->dev) { + sanei_hp_free(new); + return SANE_STATUS_NO_MEM; + } + new->chan=ptalChannelFindOrAllocate(new->dev,PTAL_STYPE_SCAN,0,0); + if (!new->chan) { + sanei_hp_free(new); + return SANE_STATUS_NO_MEM; + } + new->fd=PTAL_NO_FD; + } else { +#endif status = hp_nonscsi_open(devname, &new->fd, connect); if (FAILED(status)) { @@ -293,6 +391,9 @@ sanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect) sanei_hp_free(new); return SANE_STATUS_IO_ERROR; } +#ifdef HAVE_PTAL + } +#endif /* For SCSI-devices we would have the inquire command here */ strncpy (new->inq_data, "\003zzzzzzzHP MODELx R000", @@ -308,15 +409,28 @@ sanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect) static void hp_scsi_close (HpScsi this) - {HpConnect connect; + DBG(3, "scsi_close: closing fd %ld\n", (long)this->fd); + connect = sanei_hp_scsi_get_connect (this); +#ifdef HAVE_PTAL + if (connect==HP_CONNECT_PTAL) { + ptalChannelClose(this->chan); + } else { +#endif + + assert(this->fd >= 0); + if (connect != HP_CONNECT_SCSI) hp_nonscsi_close (this->fd, connect); else sanei_scsi_close (this->fd); + +#ifdef HAVE_PTAL + } +#endif } SANE_Status @@ -374,12 +488,29 @@ sanei_hp_scsi_new (HpScsi * newp, const char * devname) return SANE_STATUS_GOOD; } -void -sanei_hp_scsi_destroy (HpScsi this) -{ - assert(this->fd >= 0); - DBG(3, "scsi_close: closing fd %d\n", this->fd); + +/* The "completely" parameter was added for OfficeJet support. + * For JetDirect connections, closing and re-opening the scan + * channel is very time consuming. Also, the OfficeJet G85 + * unloads a loaded document in the ADF when the scan channel + * gets closed. The solution is to "completely" destroy the + * connection, including closing and deallocating the PTAL + * channel, when initially probing the device in hp-device.c, + * but leave it open while the frontend is actually using the + * device (from hp-handle.c), and "completely" destroy it when + * the frontend closes its handle. */ +void +sanei_hp_scsi_destroy (HpScsi this,int completely) +{ + /* Moved to hp_scsi_close(): + * assert(this->fd >= 0); + * DBG(3, "scsi_close: closing fd %d\n", this->fd); + */ + +#ifdef HAVE_PTAL + if (sanei_hp_scsi_get_connect(this)!=HP_CONNECT_PTAL || completely) +#endif hp_scsi_close (this); if ( this->devname ) sanei_hp_free (this->devname); sanei_hp_free(this); @@ -542,8 +673,13 @@ hp_scsi_scl(HpScsi this, HpScl scl, int val) } +/* The OfficeJets tend to return inquiry responses containing array + * data in two packets. The added "isResponse" parameter tells + * ptalSclChannelRead whether it should keep reading until it gets + * a well-formed response. Naturally, this parameter would be zero + * when reading scan data. */ static SANE_Status -hp_scsi_read (HpScsi this, void * dest, size_t *len) +hp_scsi_read (HpScsi this, void * dest, size_t *len, int isResponse) { HpConnect connect; static hp_byte_t read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 }; @@ -562,7 +698,7 @@ hp_scsi_read (HpScsi this, void * dest, size_t *len) } else { - RETURN_IF_FAIL( hp_nonscsi_read (this, dest, len, connect) ); + RETURN_IF_FAIL( hp_nonscsi_read (this, dest, len, connect, isResponse) ); } DBG(16, "scsi_read: %lu bytes:\n", (unsigned long) *len); DBGDUMP(16, dest, *len); @@ -575,6 +711,7 @@ static int signal_caught = 0; static RETSIGTYPE signal_catcher (int sig) { + DBG(1,"signal_catcher(sig=%d): old signal_caught=%d\n",sig,signal_caught); if (!signal_caught) signal_caught = sig; } @@ -688,6 +825,53 @@ hp_scale_to_16bit(int count, register unsigned char *data, int depth, } } + +static void +hp_scale_to_8bit(int count, register unsigned char *data, int depth, + hp_bool_t invert) +{ + register unsigned int tmp, mask; + register hp_bool_t lowbyte_first = is_lowbyte_first_byteorder (); + unsigned int shift1 = depth-8; + int k; + unsigned char *dataout = data; + + if ((count <= 0) || (shift1 <= 0)) return; + + mask = 1; + for (k = 1; k < depth; k++) mask |= (1 << k); + + if (lowbyte_first) + { + while (count--) { + tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask; + tmp >>= shift1; + if (invert) tmp = ~tmp; + *(dataout++) = tmp & 255U; + data += 2; + } + } + else /* Highbyte first */ + { + while (count--) { + tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask; + tmp >>= shift1; + if (invert) tmp = ~tmp; + *(dataout++) = tmp & 255U; + data += 2; + } + } +} + +static void +hp_soft_invert(int count, register unsigned char *data) { + while (count>0) { + *data = ~(*data); + data++; + count--; + } +} + static PROCDATA_HANDLE * process_data_init (HpProcessData *procdata, const unsigned char *map, int outfd, hp_bool_t use_imgbuf) @@ -717,6 +901,7 @@ process_data_init (HpProcessData *procdata, const unsigned char *map, if ( procdata->mirror_vertical || use_imgbuf) { tsz = procdata->lines*procdata->bytes_per_line; + if (procdata->out8) tsz /= 2; ph->image_ptr = ph->image_buf = sanei_hp_alloc (tsz); if ( !ph->image_buf ) { @@ -756,7 +941,9 @@ process_data_write (PROCDATA_HANDLE *ph, unsigned char *data, int nbytes) return SANE_STATUS_GOOD; DBG(12, "process_data_write: write %d bytes\n", ph->wr_buf_size); - if ( write (ph->outfd, ph->wr_buf, ph->wr_buf_size) != ph->wr_buf_size) + /* Don't write data if we got a signal in the meantime */ + if ( signal_caught + || (write (ph->outfd, ph->wr_buf, ph->wr_buf_size) != ph->wr_buf_size)) { DBG(1, "process_data_write: write failed: %s\n", signal_caught ? "signal caught" : strerror(errno)); @@ -768,7 +955,8 @@ process_data_write (PROCDATA_HANDLE *ph, unsigned char *data, int nbytes) /* For large amount of data write it from data-buffer */ while ( nbytes > ph->wr_buf_size ) { - if ( write (ph->outfd, data, ph->wr_buf_size) != ph->wr_buf_size) + if ( signal_caught + || (write (ph->outfd, data, ph->wr_buf_size) != ph->wr_buf_size)) { DBG(1, "process_data_write: write failed: %s\n", signal_caught ? "signal caught" : strerror(errno)); @@ -787,12 +975,11 @@ process_data_write (PROCDATA_HANDLE *ph, unsigned char *data, int nbytes) return SANE_STATUS_GOOD; } - static SANE_Status process_scanline (PROCDATA_HANDLE *ph, unsigned char *linebuf, int bytes_per_line) -{ +{int out_bytes_per_line = bytes_per_line; HpProcessData *procdata; if (ph == NULL) return SANE_STATUS_INVAL; @@ -802,18 +989,33 @@ process_scanline (PROCDATA_HANDLE *ph, unsigned char *linebuf, hp_data_map (ph->map, bytes_per_line, linebuf); if (procdata->bits_per_channel > 8) - hp_scale_to_16bit( bytes_per_line/2, linebuf, - procdata->bits_per_channel, - procdata->invert); + { + if (procdata->out8) + { + hp_scale_to_8bit( bytes_per_line/2, linebuf, + procdata->bits_per_channel, + procdata->invert); + out_bytes_per_line /= 2; + } + else + { + hp_scale_to_16bit( bytes_per_line/2, linebuf, + procdata->bits_per_channel, + procdata->invert); + } + } else if (procdata->invert) { + hp_soft_invert(bytes_per_line,linebuf); + } if ( ph->image_buf ) { DBG(5, "process_scanline: save in memory\n"); - if ( ph->image_ptr+bytes_per_line-1 <= ph->image_buf+ph->image_buf_size-1 ) + if ( ph->image_ptr+out_bytes_per_line-1 + <= ph->image_buf+ph->image_buf_size-1 ) { - memcpy(ph->image_ptr, linebuf, bytes_per_line); - ph->image_ptr += bytes_per_line; + memcpy(ph->image_ptr, linebuf, out_bytes_per_line); + ph->image_ptr += out_bytes_per_line; } else { @@ -823,7 +1025,7 @@ process_scanline (PROCDATA_HANDLE *ph, unsigned char *linebuf, else /* Save scanlines in a bigger buffer. */ { /* Otherwise we will get performance problems */ - RETURN_IF_FAIL ( process_data_write (ph, linebuf, bytes_per_line) ); + RETURN_IF_FAIL ( process_data_write (ph, linebuf, out_bytes_per_line) ); } return SANE_STATUS_GOOD; } @@ -892,7 +1094,7 @@ process_data_flush (PROCDATA_HANDLE *ph) if ( ph->wr_left != ph->wr_buf_size ) /* Something in write buffer ? */ { nbytes = ph->wr_buf_size - ph->wr_left; - if ( write (ph->outfd, ph->wr_buf, nbytes) != nbytes) + if ( signal_caught || (write (ph->outfd, ph->wr_buf, nbytes) != nbytes)) { DBG(1, "process_data_flush: write failed: %s\n", signal_caught ? "signal caught" : strerror(errno)); @@ -906,6 +1108,7 @@ process_data_flush (PROCDATA_HANDLE *ph) if ( ph->image_buf ) { bytes_per_line = procdata->bytes_per_line; + if (procdata->out8) bytes_per_line /= 2; image_len = (size_t) (ph->image_ptr - ph->image_buf); num_lines = ((int)(image_len + bytes_per_line-1)) / bytes_per_line; @@ -917,7 +1120,8 @@ process_data_flush (PROCDATA_HANDLE *ph) image_data = ph->image_buf + (num_lines-1) * bytes_per_line; while (num_lines > 0 ) { - if (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line) + if ( signal_caught + || (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line)) { DBG(1,"process_data_finish: write from memory failed: %s\n", signal_caught ? "signal caught" : strerror(errno)); @@ -933,7 +1137,8 @@ process_data_flush (PROCDATA_HANDLE *ph) image_data = ph->image_buf; while (num_lines > 0 ) { - if (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line) + if ( signal_caught + || (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line)) { DBG(1,"process_data_finish: write from memory failed: %s\n", signal_caught ? "signal caught" : strerror(errno)); @@ -1173,7 +1378,7 @@ sanei_hp_scsi_pipeout (HpScsi this, int outfd, HpProcessData *procdata) DBG(3, "do_read: try to read data (%lu bytes)\n", (unsigned long)nread); - status = hp_scsi_read (this, read_buf, &nread); + status = hp_scsi_read (this, read_buf, &nread, 0); if (status != SANE_STATUS_GOOD) { DBG(1, "do_read: Error from scsi_read: %s\n",sane_strstatus(status)); @@ -1258,7 +1463,7 @@ _hp_scl_inq (HpScsi scsi, HpScl scl, HpScl inq_cmnd, RETURN_IF_FAIL( hp_scsi_scl(scsi, inq_cmnd, SCL_INQ_ID(scl)) ); - status = hp_scsi_read(scsi, buf, &bufsize); + status = hp_scsi_read(scsi, buf, &bufsize, 1); if (FAILED(status)) { DBG(1, "scl_inq: read failed (%s)\n", sane_strstatus(status)); @@ -1341,7 +1546,7 @@ sanei_hp_scl_upload_binary (HpScsi scsi, HpScl scl, size_t *lengthhp, RETURN_IF_FAIL( hp_scsi_scl(scsi, SCL_UPLOAD_BINARY_DATA, SCL_INQ_ID(scl)) ); - status = hp_scsi_read(scsi, buf, &bufsize); + status = hp_scsi_read(scsi, buf, &bufsize, 0); if (FAILED(status)) { DBG(1, "scl_upload_binary: read failed (%s)\n", sane_strstatus(status)); @@ -1397,7 +1602,7 @@ sanei_hp_scl_upload_binary (HpScsi scsi, HpScl scl, size_t *lengthhp, if ( val > 0 ) { sv = val; - status = hp_scsi_read(scsi, hpdata, &sv); + status = hp_scsi_read(scsi, hpdata, &sv, 0); if (status != SANE_STATUS_GOOD) sanei_hp_free ( *bufhp ); } diff --git a/backend/hp-scl.h b/backend/hp-scl.h index 20654921b..8c430368e 100644 --- a/backend/hp-scl.h +++ b/backend/hp-scl.h @@ -72,6 +72,7 @@ #define SCL_CONTRAST HP_SCL_CONTROL(10316, 'a', 'K') #define SCL_BRIGHTNESS HP_SCL_CONTROL(10317, 'a', 'L') #define SCL_MIRROR_IMAGE HP_SCL_CONTROL(10318, 'a', 'M') +#define SCL_SHARPENING HP_SCL_CONTROL(10319, 'a', 'N') #define SCL_X_RESOLUTION HP_SCL_CONTROL(10323, 'a', 'R') #define SCL_Y_RESOLUTION HP_SCL_CONTROL(10324, 'a', 'S') #define SCL_OUTPUT_DATA_TYPE HP_SCL_CONTROL(10325, 'a', 'T') @@ -116,6 +117,8 @@ #define SCL_HP_MODEL_8 HP_SCL_PARAMETER(15) #define SCL_HP_MODEL_9 HP_SCL_PARAMETER(16) #define SCL_HP_MODEL_10 HP_SCL_PARAMETER(17) +#define SCL_HP_MODEL_11 HP_SCL_PARAMETER(18) +#define SCL_HP_MODEL_12 HP_SCL_PARAMETER(19) #define SCL_HP_MODEL_14 HP_SCL_PARAMETER(21) #define SCL_HP_MODEL_16 HP_SCL_PARAMETER(31) #define SCL_HP_MODEL_17 HP_SCL_PARAMETER(32) diff --git a/backend/hp-scsi.h b/backend/hp-scsi.h index 68942c659..0e12185de 100644 --- a/backend/hp-scsi.h +++ b/backend/hp-scsi.h @@ -49,7 +49,7 @@ SANE_Status sanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect); SANE_Status sanei_hp_scsi_new (HpScsi * newp, const char * devname); -void sanei_hp_scsi_destroy (HpScsi this); +void sanei_hp_scsi_destroy (HpScsi this,int completely); hp_byte_t * sanei_hp_scsi_inq (HpScsi this); const char *sanei_hp_scsi_model (HpScsi this); diff --git a/backend/hp.c b/backend/hp.c index 12bfcf98c..3628e04d4 100644 --- a/backend/hp.c +++ b/backend/hp.c @@ -43,9 +43,26 @@ HP Scanner Control Language (SCL). */ -static char *hp_backend_version = "0.88"; +static char *hp_backend_version = "0.91"; /* Changes: + V 0.91, 04-Sep-2000, David Paschal (paschal@rcsis.com): + - Added support for flatbed HP OfficeJets + - (PK) fix problem with cancel preview + + V 0.90, 02-Sep-2000, PK: + - fix timing problem between killing child and writing to pipe + - change fprintf(stderr,...) to DBG + - change include to "sane.." in hp.h + - change handling of options that have global effects. + i.e. if option scanmode is received (has global effect), + all options that "may change" are send to the scanner again. + This fixes a problem that --resolution specified infront of + --mode on command line of scanimage was ignored. + NOTE: This change does not allow to specify --depth 12 infront of + --mode color, because --depth is only enabled with --mode color. + - add depth greater 8 bits for mode grayscale + - add option for 8 bit output but 10/12 bit scanning V 0.88, 25-Jul-2000, PK: - remove inlines V 0.88, 20-Jul-2000, PK: @@ -162,6 +179,10 @@ static char *hp_backend_version = "0.88"; #include "hp-device.h" #include "hp-handle.h" +#ifdef HAVE_PTAL +#include +#endif + #ifndef PATH_MAX # define PATH_MAX 1024 #endif @@ -174,19 +195,25 @@ sanei_hp_dbgdump (const void * bufp, size_t len) const hp_byte_t *buf = bufp; int offset = 0; int i; - FILE * fp = stderr; + char line[128], pt[32]; for (offset = 0; offset < (int)len; offset += 16) { - fprintf(fp, " 0x%04X ", offset); + sprintf (line," 0x%04X ", offset); for (i = offset; i < offset + 16 && i < (int)len; i++) - fprintf(fp, " %02X", buf[i]); + { + sprintf (pt," %02X", buf[i]); + strcat (line, pt); + } while (i++ < offset + 16) - fputs(" ", fp); - fputs(" ", fp); + strcat (line, " "); + strcat (line, " "); for (i = offset; i < offset + 16 && i < (int)len; i++) - fprintf(fp, "%c", isprint(buf[i]) ? buf[i] : '.'); - fputs("\n", fp); + { + sprintf (pt, "%c", isprint(buf[i]) ? buf[i] : '.'); + strcat (line, pt); + } + DBG(16,"%s\n",line); } } @@ -480,6 +507,7 @@ hp_get_dev (const char *devname, HpDevice* devp) else if (hp_connect == HP_CONNECT_PIO) connect = "pio"; else if (hp_connect == HP_CONNECT_USB) connect = "usb"; else if (hp_connect == HP_CONNECT_RESERVE) connect = "reserve"; + else if (hp_connect == HP_CONNECT_PTAL) connect = "ptal"; else connect = "unknown"; DBG(3, "hp_get_dev: New device %s, connect-%s, scsi-request=%lu\n", @@ -581,6 +609,16 @@ hp_read_config (void) config->connect = HP_CONNECT_RESERVE; config->use_scsi_request = 0; } + else if (strcmp (arg2, "connect-ptal") == 0) + { +#ifdef HAVE_PTAL + config->connect = HP_CONNECT_PTAL; + config->use_scsi_request = 0; +#else + DBG(1,"hp_read_config: connect-ptal:\n"); + DBG(1," hp-backend not compiled with PTAL support.\n"); +#endif + } else if (strcmp (arg2, "disable-scsi-request") == 0) { config->use_scsi_request = 0; @@ -673,32 +711,42 @@ hp_update_devlist (void) SANE_Status sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) -{ +{SANE_Status status; + DBG_INIT(); - DBG(3, "init called\n"); + DBG(3, "sane_init called\n"); + +#ifdef HAVE_PTAL + ptalInit(); +#endif hp_destroy(); if (version_code) *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, VERSIO); - return hp_init(); + status = hp_init(); + DBG(3, "sane_init will finish with %s\n", sane_strstatus (status)); + return status; } void sane_exit (void) { - DBG(3, "exit called\n"); + DBG(3, "sane_exit called\n"); hp_destroy(); + DBG(3, "sane_exit will finish\n"); } SANE_Status sane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only) { - DBG(3, "get_devices called\n"); + DBG(3, "sane_get_devices called\n"); RETURN_IF_FAIL( hp_update_devlist() ); *device_list = global.devlist; + DBG(3, "sane_get_devices will finish with %s\n", + sane_strstatus (SANE_STATUS_GOOD)); return SANE_STATUS_GOOD; } @@ -708,6 +756,8 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) HpDevice dev = 0; HpHandle h; + DBG(3, "sane_open called\n"); + RETURN_IF_FAIL( hp_read_config() ); if (devicename[0]) @@ -727,6 +777,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) RETURN_IF_FAIL( hp_handle_list_add(&global.handle_list, h) ); *handle = h; + DBG(3, "sane_open will finish with %s\n", sane_strstatus (SANE_STATUS_GOOD)); return SANE_STATUS_GOOD; } @@ -735,15 +786,27 @@ sane_close (SANE_Handle handle) { HpHandle h = handle; + DBG(3, "sane_close called\n"); + if (!FAILED( hp_handle_list_remove(&global.handle_list, h) )) sanei_hp_handle_destroy(h); + + DBG(3, "sane_close will finish\n"); } const SANE_Option_Descriptor * sane_get_option_descriptor (SANE_Handle handle, SANE_Int optnum) { HpHandle h = handle; - return sanei_hp_handle_saneoption(h, optnum); + const SANE_Option_Descriptor *optd; + + DBG(10, "sane_get_option_descriptor called\n"); + + optd = sanei_hp_handle_saneoption(h, optnum); + + DBG(10, "sane_get_option_descriptor will finish\n"); + + return optd; } SANE_Status @@ -751,21 +814,44 @@ sane_control_option (SANE_Handle handle, SANE_Int optnum, SANE_Action action, void *valp, SANE_Int *info) { HpHandle h = handle; - return sanei_hp_handle_control(h, optnum, action, valp, info); + SANE_Status status; + + DBG(10, "sane_control_option called\n"); + + status = sanei_hp_handle_control(h, optnum, action, valp, info); + + DBG(10, "sane_control_option will finish with %s\n", + sane_strstatus (status)); + return status; } SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) { HpHandle h = handle; - return sanei_hp_handle_getParameters(h, params); + SANE_Status status; + + DBG(10, "sane_get_parameters called\n"); + + status = sanei_hp_handle_getParameters(h, params); + + DBG(10, "sane_get_parameters will finish with %s\n", + sane_strstatus (status)); + return status; } SANE_Status sane_start (SANE_Handle handle) { HpHandle h = handle; - return sanei_hp_handle_startScan(h); + SANE_Status status; + + DBG(3, "sane_start called\n"); + + status = sanei_hp_handle_startScan(h); + + DBG(3, "sane_start will finish with %s\n", sane_strstatus (status)); + return status; } SANE_Status @@ -775,8 +861,12 @@ sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) size_t length = max_len; SANE_Status status; + DBG(16, "sane_read called\n"); + status = sanei_hp_handle_read(h, buf, &length); *len = length; + + DBG(16, "sane_read will finish with %s\n", sane_strstatus (status)); return status; } @@ -784,19 +874,40 @@ void sane_cancel (SANE_Handle handle) { HpHandle h = handle; + + DBG(3, "sane_cancel called\n"); + sanei_hp_handle_cancel(h); + + DBG(3, "sane_cancel will finish\n"); } SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) { HpHandle h = handle; - return sanei_hp_handle_setNonblocking(h, non_blocking); + SANE_Status status; + + DBG(3, "sane_set_io_mode called\n"); + + status = sanei_hp_handle_setNonblocking(h, non_blocking); + + DBG(3, "sane_set_io_mode will finish with %s\n", + sane_strstatus (status)); + return status; } SANE_Status sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) { HpHandle h = handle; - return sanei_hp_handle_getPipefd(h, fd); + SANE_Status status; + + DBG(10, "sane_get_select_fd called\n"); + + status = sanei_hp_handle_getPipefd(h, fd); + + DBG(10, "sane_get_select_fd will finish with %s\n", + sane_strstatus (status)); + return status; } diff --git a/backend/hp.h b/backend/hp.h index 0f88b19ca..e0e3f85b8 100644 --- a/backend/hp.h +++ b/backend/hp.h @@ -46,11 +46,11 @@ #define HP_H_INCLUDED #include #include -#include +#include "sane/sane.h" #undef BACKEND_NAME #define BACKEND_NAME hp -#include +#include "sane/sanei_debug.h" /* FIXME: these should be options? */ #undef ENABLE_7x12_TONEMAPS @@ -102,7 +102,8 @@ typedef int hp_bool_t; typedef unsigned char hp_byte_t; typedef enum { HP_CONNECT_SCSI, HP_CONNECT_DEVICE, - HP_CONNECT_PIO, HP_CONNECT_USB, HP_CONNECT_RESERVE } HpConnect; + HP_CONNECT_PIO, HP_CONNECT_USB, HP_CONNECT_RESERVE, + HP_CONNECT_PTAL } HpConnect; typedef struct { @@ -156,8 +157,10 @@ typedef long int HpScl; typedef struct { int lines; - int bytes_per_line; + int bytes_per_line; /* as received from scanner */ int bits_per_channel; + hp_bool_t out8; /* This flag is set and only set, when data with */ + /* depths > 8 is to be mapped to 8 bit output. */ hp_bool_t mirror_vertical; hp_bool_t invert; HpScl startscan;