From 808dfaeef76626ae645dc3d2464c504c3d01ffab Mon Sep 17 00:00:00 2001 From: Henning Geinitz Date: Sat, 19 Jan 2002 20:58:42 +0000 Subject: [PATCH] Update to backend 0.95-20020112 (from karsten.festag@t-online.de (Karsten Festag)). Henning Meier-Geinitz --- backend/microtek2.c | 1003 +++++++++++++++++++++++-------------- backend/microtek2.h | 1139 ++++++++++++++++++++++++++++--------------- 2 files changed, 1387 insertions(+), 755 deletions(-) diff --git a/backend/microtek2.c b/backend/microtek2.c index ec30cd6e7..9021e8d7d 100644 --- a/backend/microtek2.c +++ b/backend/microtek2.c @@ -84,7 +84,16 @@ #include "../include/sane/sanei_scsi.h" #include "../include/sane/saneopts.h" +#ifdef HAVE_OS2_H +#include "../include/sane/sanei_thread.h" +#endif + +#ifndef TESTBACKEND #define BACKEND_NAME microtek2 +#else +#define BACKEND_NAME microtek2_test +#endif + #include "../include/sane/sanei_backend.h" #include "microtek2.h" @@ -879,8 +888,16 @@ cancel_scan(Microtek2_Scanner *ms) status = SANE_STATUS_CANCELLED; close(ms->fd[1]); - kill(ms->pid, SIGTERM); - waitpid(ms->pid, NULL, 0); + + /* if we are aborting a scan because, for example, we run out + of material on a feeder, then pid may be already -1 and + kill(-1, SIGTERM), i.e. killing all our processes, is not + likely what we really want - --mj, 2001/Nov/19 */ + if (ms->pid > 1) + { + kill(ms->pid, SIGTERM); + waitpid(ms->pid, NULL, 0); + } return status; } @@ -1142,7 +1159,9 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) *model_string = "ScanMaker V300"; /* The ScanMaker V300 returns some values for the */ /* "read image info" command in only two bytes */ - md->model_flags |= MD_RII_TWO_BYTES; + /* and doesn't understand read_image_status */ + md->model_flags |= MD_RII_TWO_BYTES + | MD_NO_RIS_COMMAND; break; case 0x87: *model_string = "ScanMaker 5"; @@ -1183,10 +1202,13 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) /* These models do not accept gamma tables. Apparently they */ /* read the control bits and do not accept shading tables */ /* They also don't support enhancements (contrast, brightness...)*/ - md->model_flags |= MD_NO_GAMMA - | MD_PHANTOM336CX_TYPE_SHADING - | MD_READ_CONTROL_BIT - | MD_NO_ENHANCEMENTS; + md->model_flags |= MD_NO_SLIDE_MODE + | MD_NO_GAMMA + | MD_PHANTOM336CX_TYPE_SHADING + | MD_READ_CONTROL_BIT + | MD_NO_ENHANCEMENTS; + md->opt_backend_calib_default = SANE_TRUE; + md->opt_no_backtrack_default = SANE_TRUE; md->n_control_bytes = 320; md->shading_length = 18; md->shading_depth = 10; @@ -1216,11 +1238,13 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) /* fail. Also it does not accept gamma tables. Apparently */ /* it reads the control bits and does not accept shading tables */ md->model_flags |= MD_NO_SLIDE_MODE - | MD_READ_CONTROL_BIT - | MD_NO_GAMMA - | MD_PHANTOM_C6; + | MD_READ_CONTROL_BIT + | MD_NO_GAMMA + | MD_PHANTOM_C6; + md->opt_backend_calib_default = SANE_TRUE; + md->opt_no_backtrack_default = SANE_TRUE; md->n_control_bytes = 647; - md->shading_length = 18; + /* md->shading_length = 18; firmware values seem to work better */ md->shading_depth = 12; md->controlbit_offset = 18; break; @@ -1241,8 +1265,9 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) md->model_flags |= MD_NO_GAMMA; break; case 0xb0: - *model_string = "ScanMaker X12USL"; - break; + *model_string = "ScanMaker X12USL"; + md->opt_backend_calib_default = SANE_TRUE; + break; case 0xb3: *model_string = "ScanMaker 3600"; break; @@ -1678,8 +1703,8 @@ dump_attributes(Microtek2_Info *mi) " ", mi->option_device & MI_OPTDEV_STRIPE ? "Yes" : "No"); DBG(1, "%30sSlides: %s\n", " ", mi->option_device & MI_OPTDEV_SLIDE ? "Yes" : "No"); - DBG(1, " Scan button%15s: %s\n", " ", mi->scnbuttn ? "Yes" : "No"); - + DBG(1, " Scan button%15s: %s\n", " ", mi->scnbuttn ? "Yes" : "No"); + DBG(1, "\n"); DBG(1, " Imaging Capabilities...\n"); DBG(1, " ~~~~~~~~~~~~~~~~~~~~~~~\n"); @@ -1690,7 +1715,7 @@ dump_attributes(Microtek2_Info *mi) DBG(1, " Resolution%9s: X-max: %5d dpi\n%35sY-max: %5d dpi\n", " ", mi->max_xresolution, " ",mi->max_yresolution); DBG(1, " Geometry%11s: Geometric width: %5d pts (%2.2f'')\n", " ", - mi->geo_width, (float) mi->geo_width / (float) mi->opt_resolution); + mi->geo_width, (float) mi->geo_width / (float) mi->opt_resolution); DBG(1, "%23sGeometric height:%5d pts (%2.2f'')\n", " ", mi->geo_height, (float) mi->geo_height / (float) mi->opt_resolution); DBG(1, " Optical resolution%1s: %d\n", " ", mi->opt_resolution); @@ -1709,14 +1734,18 @@ dump_attributes(Microtek2_Info *mi) " ", (mi->depth & MI_HASDEPTH_10) ? "Yes" : "No"); DBG(1, "%23s12-bit-color: %s\n", " ", (mi->depth & MI_HASDEPTH_12) ? "Yes" : "No"); + DBG(1, "%23s14-bit-color: %s\n", " ", + (mi->depth & MI_HASDEPTH_14) ? "Yes" : "No"); + DBG(1, "%23s16-bit-color: %s\n", " ", + (mi->depth & MI_HASDEPTH_16) ? "Yes" : "No"); DBG(1, " d/l of HT pattern%2s: %s\n", " ", (mi->has_dnldptrn) ? "Yes" : "No"); DBG(1, " Builtin HT pattern%1s: %d\n", " ", mi->grain_slct); - if ( MI_LUTCAP_NONE(mi->lut_cap) ) - DBG(1, " LUT capabilities : None\n"); + if ( MI_LUTCAP_NONE(mi->lut_cap) ) + DBG(1, " LUT capabilities : None\n"); if ( mi->lut_cap & MI_LUTCAP_256B ) - DBG(1, " LUT capabilities : 256 bytes\n"); + DBG(1, " LUT capabilities : 256 bytes\n"); if ( mi->lut_cap & MI_LUTCAP_1024B ) DBG(1, " LUT capabilities : 1024 bytes\n"); if ( mi->lut_cap & MI_LUTCAP_1024W ) @@ -1725,6 +1754,10 @@ dump_attributes(Microtek2_Info *mi) DBG(1, " LUT capabilities : 4096 bytes\n"); if ( mi->lut_cap & MI_LUTCAP_4096W ) DBG(1, " LUT capabilities : 4096 words\n"); + if ( mi->lut_cap & MI_LUTCAP_64k_W ) + DBG(1, " LUT capabilities : 64k words\n"); + if ( mi->lut_cap & MI_LUTCAP_16k_W ) + DBG(1, " LUT capabilities : 16k words\n"); DBG(1, "\n"); DBG(1, " Miscellaneous capabilities...\n"); DBG(1, " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); @@ -1780,9 +1813,10 @@ dump_attributes(Microtek2_Info *mi) DBG(1, " Calib white stripe location%4s: %d\n", " ", mi->calib_white); DBG(1, " Max calib space%16s: %d\n", " ", mi->calib_space); + DBG(1, " Calib Divisor%18s: %d\n", " ", mi->calib_divisor); DBG(1, " Number of lens%17s: %d\n", " ", mi->nlens); DBG(1, " Max number of windows%10s: %d\n", " ", mi->nwindows); - DBG(1, " Shading transfer function%6s: %d\n", " ",mi->shtrnsferequ); + DBG(1, " Shading transfer function%6s: 0x%02x\n", " ",mi->shtrnsferequ); DBG(1, " Red balance%20s: %d\n", " ", mi->balance[0]); DBG(1, " Green balance%18s: %d\n", " ", mi->balance[1]); DBG(1, " Blue balance%19s: %d\n", " " , mi->balance[2]); @@ -2044,6 +2078,11 @@ init_options(Microtek2_Scanner *ms, u_int8_t current_scan_source) md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_10; if ( mi->depth & MI_HASDEPTH_12 ) md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_12; + if ( mi->depth & MI_HASDEPTH_14 ) + md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_14; + if ( mi->depth & MI_HASDEPTH_16 ) + md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_16; + md->bitdepth_list[0] = i; if ( md->bitdepth_list[1] == (SANE_Int) MD_DEPTHVAL_8 ) val[OPT_BITDEPTH].w = md->bitdepth_list[1]; @@ -2207,10 +2246,10 @@ init_options(Microtek2_Scanner *ms, u_int8_t current_scan_source) val[OPT_RESOLUTION_BIND].w = SANE_TRUE; /* enable/disable option for backtracking */ - val[OPT_DISABLE_BACKTRACK].w = SANE_TRUE; + val[OPT_DISABLE_BACKTRACK].w = md->opt_no_backtrack_default; /* enable/disable calibration by backend */ - val[OPT_CALIB_BACKEND].w = SANE_FALSE; + val[OPT_CALIB_BACKEND].w = md->opt_backend_calib_default; /* turn off the lamp during a scan */ val[OPT_LIGHTLID35].w = SANE_FALSE; @@ -2779,7 +2818,10 @@ set_option_dependencies(Microtek2_Scanner *ms, SANE_Option_Descriptor *sod, sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE; sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE; sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; - sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE; + if ( md->bitdepth_list[0] != 1 ) + sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE; + else + sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE; sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE; if ( ! ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 ) ) { @@ -2803,7 +2845,10 @@ set_option_dependencies(Microtek2_Scanner *ms, SANE_Option_Descriptor *sod, sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE; sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE; sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; - sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE; + if ( md->bitdepth_list[0] != 1 ) + sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE; + else + sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE; sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE; sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE; sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE; @@ -3663,9 +3708,8 @@ get_calib_params(Microtek2_Scanner *ms) md = ms->dev; mi = &md->info[0]; /* must be changed */ - ms->x_resolution_dpi = mi->opt_resolution; - /* this is somehow arbitrary */ - ms->y_resolution_dpi = mi->opt_resolution; + ms->x_resolution_dpi = mi->opt_resolution / mi->calib_divisor; + ms->y_resolution_dpi = mi->opt_resolution / 5; /* ignore dust particles */ ms->x1_dots = 0; ms->y1_dots = mi->calib_white; ms->width_dots = mi->geo_width; @@ -3675,12 +3719,18 @@ get_calib_params(Microtek2_Scanner *ms) ms->height_dots = mi->calib_space; ms->mode = MS_MODE_COLOR; - if ( mi->depth & MI_HASDEPTH_12 ) + + if ( mi->depth & MI_HASDEPTH_16 ) + ms->depth = 16; + else if ( mi->depth & MI_HASDEPTH_14 ) + ms->depth = 14; + else if ( mi->depth & MI_HASDEPTH_12 ) ms->depth = 12; else if ( mi->depth & MI_HASDEPTH_10 ) ms->depth = 10; else ms->depth = 8; + ms->stay = 0; if ( mi->calib_space < 10 ) ms->stay = 1; @@ -3782,16 +3832,17 @@ get_scan_parameters(Microtek2_Scanner *ms) ms->y1_dots = (SANE_Int) ( SANE_UNFIX(ms->val[OPT_TL_Y].w) * dpm + 0.5 ); x2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_X].w) * dpm + 0.5 ); y2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_Y].w) * dpm + 0.5 ); - - /* special case, xscanimage sometimes tries to set OPT_BR_Y */ - /* to a too big value; bug in xscanimage ? */ - ms->width_dots = MIN(abs(x2_dots - ms->x1_dots), mi->geo_width); + ms->width_dots = abs(x2_dots - ms->x1_dots); ms->height_dots = abs(y2_dots - ms->y1_dots); - /* ensure a minimum scan area */ + /* ensure minimum and maximum scan area */ if ( ms->height_dots < 10 ) ms->height_dots = 10; + if ( ms->height_dots > mi->geo_height ) + ms->height_dots = mi->geo_height; if ( ms->width_dots < 10 ) ms->width_dots = 10; + if ( ms->width_dots > mi->geo_width ) + ms->width_dots = mi->geo_width; /* (KF) take scanning direction into account */ if ((mi->direction & MI_DATSEQ_RTOL) == 1) @@ -4035,7 +4086,7 @@ scsi_read_gamma(Microtek2_Scanner *ms, int color) SANE_Status status; RG_CMD(readgamma); - ENDIAN_TYPE(endiantype); + ENDIAN_TYPE(endiantype); RG_PCORMAC(readgamma, endiantype); RG_COLOR(readgamma, color); RG_WORD(readgamma, ( ms->dev->lut_entry_size == 1 ) ? 0 : 1); @@ -4044,7 +4095,7 @@ scsi_read_gamma(Microtek2_Scanner *ms, int color) dump_area(readgamma, 10, "ReadGamma"); size = sizeof(result); - status = sanei_scsi_cmd(ms->sfd, readgamma, sizeof(readgamma), + status = sanei_scsi_cmd(ms->sfd, readgamma, sizeof(readgamma), result, &size); if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_gamma: (L,R) read_gamma failed: status '%s'\n", @@ -4062,41 +4113,75 @@ scsi_read_gamma(Microtek2_Scanner *ms, int color) /*---------- scsi_send_gamma() -----------------------------------------------*/ static SANE_Status -scsi_send_gamma(Microtek2_Scanner *ms, u_int16_t length) +scsi_send_gamma(Microtek2_Scanner *ms) { SANE_Bool endiantype; SANE_Status status; size_t size; - u_int8_t *cmd; + u_int8_t *cmd, color; - DBG(30, "scsi_send_gamma: pos=%p, size=%d, word=%d, color=%d\n", + DBG(30, "scsi_send_gamma: pos=%p, size=%d, word=%d, color=%d\n", ms->gamma_table, ms->lut_size_bytes, ms->word, ms->current_color); - cmd = (u_int8_t *) alloca(SG_CMD_L + length); - if ( cmd == NULL ) + if ( ( 3 * ms->lut_size_bytes ) <= 0xffff ) /*send Gamma with one command*/ { - DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n"); - return SANE_STATUS_IO_ERROR; + cmd = (u_int8_t *) alloca(SG_CMD_L + 3 * ms->lut_size_bytes); + if ( cmd == NULL ) + { + DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n"); + return SANE_STATUS_IO_ERROR; + } + + SG_SET_CMD(cmd); + ENDIAN_TYPE(endiantype) + SG_SET_PCORMAC(cmd, endiantype); + SG_SET_COLOR(cmd, ms->current_color); + SG_SET_WORD(cmd, ms->word); + SG_SET_TRANSFERLENGTH(cmd, 3 * ms->lut_size_bytes); + memcpy(cmd + SG_CMD_L, ms->gamma_table, 3 * ms->lut_size_bytes); + size = 3 * ms->lut_size_bytes; + if ( md_dump >= 2 ) + dump_area2(cmd, SG_CMD_L, "sendgammacmd"); + if ( md_dump >= 3 ) + dump_area2(cmd + SG_CMD_L, size, "sendgammadata"); + + status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0); + if ( status != SANE_STATUS_GOOD ) + DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status)); } - - SG_SET_CMD(cmd); - ENDIAN_TYPE(endiantype) - SG_SET_PCORMAC(cmd, endiantype); - SG_SET_COLOR(cmd, ms->current_color); - SG_SET_WORD(cmd, ms->word); - SG_SET_TRANSFERLENGTH(cmd, length); - memcpy(cmd + SG_CMD_L, ms->gamma_table, length); - size = length; - if ( md_dump >= 2 ) - dump_area2(cmd, SG_CMD_L, "sendgammacmd"); - if ( md_dump >= 3 ) - dump_area2(cmd + SG_CMD_L, size, "sendgammadata"); + else /* send gamma with 3 commands, one for each color */ + { + for ( color = 0; color < 3; color++ ) + { + cmd = (u_int8_t *) alloca(SG_CMD_L + ms->lut_size_bytes); + if ( cmd == NULL ) + { + DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n"); + return SANE_STATUS_IO_ERROR; + } + SG_SET_CMD(cmd); + ENDIAN_TYPE(endiantype) + SG_SET_PCORMAC(cmd, endiantype); + SG_SET_COLOR(cmd, color); + SG_SET_WORD(cmd, ms->word); + SG_SET_TRANSFERLENGTH(cmd, ms->lut_size_bytes); + memcpy(cmd + SG_CMD_L, + ms->gamma_table + color * ms->lut_size_bytes, + ms->lut_size_bytes); + size = ms->lut_size_bytes; + if ( md_dump >= 2 ) + dump_area2(cmd, SG_CMD_L, "sendgammacmd"); + if ( md_dump >= 3 ) + dump_area2(cmd + SG_CMD_L, size, "sendgammadata"); - status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0); - if ( status != SANE_STATUS_GOOD ) - DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status)); + status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0); + if ( status != SANE_STATUS_GOOD ) + DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status)); + } + + } return status; } @@ -4116,7 +4201,7 @@ scsi_inquiry(Microtek2_Info *mi, char *device) DBG(30, "scsi_inquiry: mi=%p, device='%s'\n", mi, device); - + status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0); if ( status != SANE_STATUS_GOOD ) { @@ -4146,7 +4231,7 @@ scsi_inquiry(Microtek2_Info *mi, char *device) INQ_GET_INQLEN(inqlen, result); INQ_SET_ALLOC(cmd, inqlen + INQ_ALLOC_L); result = alloca(inqlen + INQ_ALLOC_L); - if ( result == NULL ) + if ( result == NULL ) { DBG(1, "scsi_inquiry: malloc failed\n"); sanei_scsi_close(sfd); @@ -4196,17 +4281,17 @@ scsi_read_attributes(Microtek2_Info *pmi, char *device, u_int8_t scan_source) u_int8_t result[RSA_TRANSFERLENGTH]; size_t size; int sfd; - + mi = &pmi[scan_source]; DBG(30, "scsi_read_attributes: mi=%p, device='%s', source=%d\n", mi, device, scan_source); - RSA_CMD(readattributes); + RSA_CMD(readattributes); RSA_SETMEDIA(readattributes, scan_source); status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_attributes: open '%s'\n", sane_strstatus(status)); return status; @@ -4214,22 +4299,24 @@ scsi_read_attributes(Microtek2_Info *pmi, char *device, u_int8_t scan_source) if (md_dump >= 2 ) dump_area2(readattributes, sizeof(readattributes), "scannerattributes"); - - size = sizeof(result); + + size = sizeof(result); status = sanei_scsi_cmd(sfd, readattributes, sizeof(readattributes), result, &size); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_attributes: cmd '%s'\n", sane_strstatus(status)); sanei_scsi_close(sfd); return status; } - sanei_scsi_close(sfd); + sanei_scsi_close(sfd); /* The X6 appears to lie about the data format for a TMA */ if ( (&pmi[0])->model_code == 0x91 ) result[0] &= 0xfd; + /* calib_divisor is bit49 which isn't read yet */ + mi->calib_divisor = 1; #if 0 result[13] &= 0xfe; /* simulate no lineart */ @@ -4251,6 +4338,12 @@ scsi_read_attributes(Microtek2_Info *pmi, char *device, u_int8_t scan_source) RSA_GEOHEIGHT(mi->geo_height, result); RSA_OPTRESOLUTION(mi->opt_resolution, result); RSA_DEPTH(mi->depth, result); + /* The X12USL doesn't say that it has 14bit and uses a calib divisor */ + if ( mi->model_code == 0xb0 ) + { + mi->depth |= MI_HASDEPTH_14; + mi->calib_divisor = 2; + } RSA_SCANMODE(mi->scanmode, result); RSA_CCDPIXELS(mi->ccd_pixels, result); RSA_LUTCAP(mi->lut_cap, result); @@ -4270,11 +4363,11 @@ scsi_read_attributes(Microtek2_Info *pmi, char *device, u_int8_t scan_source) RSA_APSMAXFRAMES(mi->aps_maxframes, result); if (md_dump >= 2 ) - dump_area2((u_int8_t *) result, sizeof(result), + dump_area2((u_int8_t *) result, sizeof(result), "scannerattributesresults"); if ( md_dump >= 1 && md_dump_clear ) dump_attributes(mi); - + return SANE_STATUS_GOOD; } @@ -4301,14 +4394,14 @@ scsi_read_control_bits(Microtek2_Scanner *ms) if ( md_dump >= 2) dump_area2(cmd, RCB_CMD_L, "readcontrolbits"); - + status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), ms->control_bytes, &ms->n_control_bytes); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_control_bits: cmd '%s'\n", sane_strstatus(status)); return status; @@ -4348,13 +4441,15 @@ scsi_set_window(Microtek2_Scanner *ms, int n) { /* n windows, not yet */ size = SW_CMD_L + SW_HEADER_L + n * SW_BODY_L; setwindow = (u_int8_t *) malloc(size); + DBG(100, "scsi_set_window: setwindow= %p, malloc'd %d Bytes\n", + setwindow, size); if ( setwindow == NULL ) { DBG(1, "scsi_set_window: malloc for setwindow failed\n"); return SANE_STATUS_NO_MEM; } memset(setwindow, 0, size); - + SW_CMD(setwindow); SW_PARAM_LENGTH(setwindow, SW_HEADER_L + n * SW_BODY_L); SW_WNDDESCLEN(setwindow + SW_HEADER_P, SW_WNDDESCVAL); @@ -4373,7 +4468,7 @@ scsi_set_window(Microtek2_Scanner *ms, int n) { /* n windows, not yet */ SW_BITSPERPIXEL(POS, ms->depth); SW_EXTHT(POS, ms->use_external_ht); SW_INTHTINDEX(POS, ms->internal_ht_index); - SW_RIF(POS, 1); + SW_RIF(POS, 1); SW_LENS(POS, 0); /* ???? */ SW_INFINITE(POS, 0); SW_STAY(POS, ms->stay); @@ -4416,9 +4511,10 @@ scsi_set_window(Microtek2_Scanner *ms, int n) { /* n windows, not yet */ } status = sanei_scsi_cmd(ms->sfd, setwindow, size, NULL, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_set_window: '%s'\n", sane_strstatus(status)); - + + DBG(100, "scsi_set_window: free setwindow at %p\n", setwindow); free((void *) setwindow); return status; } @@ -4509,10 +4605,10 @@ scsi_read_image(Microtek2_Scanner *ms, u_int8_t *buffer) if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_read_image: '%s'\n", sane_strstatus(status)); - - if ( md_dump > 3 ) + + if ( md_dump > 3 ) dump_area2(buffer, ms->transfer_length, "readimageresult"); - + return status; } @@ -4598,7 +4694,7 @@ scsi_read_shading(Microtek2_Scanner *ms, u_int8_t *buffer, u_int32_t length) SANE_Status status = SANE_STATUS_GOOD; size_t size; - DBG(30, "scsi_read_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n", + DBG(30, "scsi_read_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n", buffer, length, ms->word, ms->current_color, ms->dark); md = ms->dev; @@ -4621,9 +4717,9 @@ scsi_read_shading(Microtek2_Scanner *ms, u_int8_t *buffer, u_int32_t length) ms->sfd, cmd, sizeof(cmd), buffer, size); status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), buffer, &size); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_read_shading: '%s'\n", sane_strstatus(status)); - + if ( md_dump > 3) dump_area2(buffer, size, @@ -4637,7 +4733,7 @@ scsi_read_shading(Microtek2_Scanner *ms, u_int8_t *buffer, u_int32_t length) static SANE_Status scsi_send_shading(Microtek2_Scanner *ms, - u_int8_t * shading_data, + u_int8_t *shading_data, u_int32_t length, u_int8_t dark) { @@ -4647,17 +4743,19 @@ scsi_send_shading(Microtek2_Scanner *ms, u_int8_t *cmd; - DBG(30, "scsi_send_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n", - ms->dev->shading_table_w, length, ms->word, ms->current_color, + DBG(30, "scsi_send_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n", + shading_data, length, ms->word, ms->current_color, dark); cmd = (u_int8_t *) malloc(SSI_CMD_L + length); + DBG(100, "scsi_send_shading: cmd=%p, malloc'd %d bytes\n", + cmd, SSI_CMD_L + length); if ( cmd == NULL ) { DBG(1, "scsi_send_shading: Couldn't get buffer for shading table\n"); - return SANE_STATUS_IO_ERROR; + return SANE_STATUS_NO_MEM; } - + SSI_SET_CMD(cmd); ENDIAN_TYPE(endiantype) SSI_SET_PCORMAC(cmd, endiantype); @@ -4671,11 +4769,13 @@ scsi_send_shading(Microtek2_Scanner *ms, if ( md_dump >= 2 ) dump_area2(cmd, SSI_CMD_L, "sendshading"); if ( md_dump >= 3 ) - dump_area2(cmd + SSI_CMD_L, size, "sendshading"); + dump_area2(cmd + SSI_CMD_L, size, "sendshadingdata"); status = sanei_scsi_cmd(ms->sfd, cmd, size + SSI_CMD_L, NULL, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_send_shading: '%s'\n", sane_strstatus(status)); + + DBG(100, "free cmd at %p\n", cmd); free((void *) cmd); return status; @@ -4695,11 +4795,11 @@ scsi_read_system_status(Microtek2_Device *md, int fd) SANE_Status status; DBG(30, "scsi_read_system_status: md=%p, fd=%d\n", md, fd); - + if ( fd == -1 ) - { + { status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_system_status: open '%s'\n", sane_strstatus(status)); @@ -4713,11 +4813,11 @@ scsi_read_system_status(Microtek2_Device *md, int fd) if ( md_dump >= 2) dump_area2(cmd, RSS_CMD_L, "readsystemstatus"); - + size = sizeof(result); status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_read_system_status: cmd '%s'\n", sane_strstatus(status)); sanei_scsi_close(sfd); @@ -4749,7 +4849,7 @@ scsi_read_system_status(Microtek2_Device *md, int fd) md->status.adfcnt = RSS_ADFCNT(result); md->status.currentmode = RSS_CURRENTMODE(result); md->status.buttoncount = RSS_BUTTONCOUNT(result); - + return SANE_STATUS_GOOD; } @@ -4771,20 +4871,20 @@ scsi_request_sense(Microtek2_Scanner *ms) int as_info_length; DBG(30, "scsi_request_sense: ms=%p\n", ms); - + RQS_CMD(requestsense); RQS_ALLOCLENGTH(requestsense, 100); size = sizeof(buffer); - status = sanei_scsi_cmd(ms->sfd, requestsense, sizeof(requestsense), + status = sanei_scsi_cmd(ms->sfd, requestsense, sizeof(requestsense), buffer, &size); - - if ( status != SANE_STATUS_GOOD ) + + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_request_sense: '%s'\n", sane_strstatus(status)); return status; } - + if ( md_dump >= 2 ) dump_area2(buffer, size, "requestsenseresult"); @@ -4793,7 +4893,7 @@ scsi_request_sense(Microtek2_Scanner *ms) if ( (as_info_length = RQS_ASINFOLENGTH(buffer)) > 0 ) DBG(25, "scsi_request_sense: info '%.*s'\n", as_info_length, RQS_ASINFO(buffer)); - + return SANE_STATUS_GOOD; } #endif @@ -4816,7 +4916,7 @@ scsi_send_system_status(Microtek2_Device *md, int fd) if ( fd == -1 ) { status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) { DBG(1, "scsi_send_system_status: open '%s'\n", sane_strstatus(status)); @@ -4825,7 +4925,7 @@ scsi_send_system_status(Microtek2_Device *md, int fd) } else sfd = fd; - + SSS_CMD(cmd); pos = cmd + SSS_CMD_L; SSS_STICK(pos, md->status.stick); @@ -4850,19 +4950,21 @@ scsi_send_system_status(Microtek2_Device *md, int fd) SSS_BUTTONCOUNT(pos, md->status.buttoncount); if ( md_dump >= 2) - dump_area2(cmd, SSS_CMD_L + SSS_DATA_L, "sendsystemstatus"); - + dump_area2(cmd, SSS_CMD_L, "sendsystemstatus"); + dump_area2(cmd + SSS_CMD_L, SSS_DATA_L, "sendsystemstatusdata"); + status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), NULL, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_send_system_status: '%s'\n", sane_strstatus(status)); if ( fd == -1 ) - sanei_scsi_close(sfd); + sanei_scsi_close(sfd); return status; } /*---------- scsi_sense_handler() --------------------------------------------*/ +/* rewritten 19.12.2001 for better SANE_STATUS return codes */ static SANE_Status scsi_sense_handler (int fd, u_char *sense, void *arg) @@ -4872,8 +4974,8 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) u_int8_t asl; u_int8_t asc; u_int8_t ascq; - - + + DBG(30, "scsi_sense_handler: fd=%d, sense=%p arg=%p\n",fd, sense, arg); dump_area(sense, RQS_LENGTH(sense), "SenseBuffer"); @@ -4882,24 +4984,32 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) asl = RQS_ASL(sense); asc = RQS_ASC(sense); ascq = RQS_ASCQ(sense); - + + DBG(5, "scsi_sense_handler: SENSE KEY (0x%02x), " + "ASC (0x%02x), ASCQ (0x%02x)\n", sense_key, asc, ascq); + if ( (as_info_length = RQS_ASINFOLENGTH(sense)) > 0 ) - DBG(30,"scsi_sense_handler: info: '%*s'\n", + DBG(5,"scsi_sense_handler: info: '%*s'\n", as_info_length, RQS_ASINFO(sense)); - - switch ( sense_key ) + + switch ( sense_key ) { case RQS_SENSEKEY_NOSENSE: return SANE_STATUS_GOOD; case RQS_SENSEKEY_HWERR: + case RQS_SENSEKEY_ILLEGAL: + case RQS_SENSEKEY_VENDOR: if ( asc == 0x4a && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Command phase error\n"); + else if ( asc == 0x2c && ascq == 0x00 ) + DBG(5, "scsi_sense_handler: Command sequence error\n"); else if ( asc == 0x4b && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Data phase error\n"); - else if ( asc == 0x40 ) + else if ( asc == 0x40 ) { - switch ( ascq ) + DBG(5, "scsi_sense_handler: Hardware diagnostic failure:\n"); + switch ( ascq ) { case RQS_ASCQ_CPUERR: DBG(5, "scsi_sense_handler: CPU error\n"); @@ -4917,83 +5027,92 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) DBG(5, "scsi_sense_handler: Gain error\n"); break; case RQS_ASCQ_POS: - DBG(5, "scsi_sense_handler: Pos. error\n"); + DBG(5, "scsi_sense_handler: Positoning error\n"); break; default: DBG(5, "scsi_sense_handler: Unknown combination of ASC" " (0x%02x) and ASCQ (0x%02x)\n", asc, ascq); break; } - } - else if ( asc == 0x00 && ascq == 0x05) - DBG(5, "scsi_sense_handler: End of data detected\n"); - else if ( asc == 0x60 && ascq == 0x00 ) - DBG(5, "scsi_sense_handler: Lamp failure\n"); - else if ( asc == 0x53 && ascq == 0x00 ) - { - DBG(5, "scsi_sense_handler: ADF paper jam or no paper\n"); - return SANE_STATUS_NO_DOCS; /* not STATUS_INVAL */ } - else if ( asc == 0x3a && ascq == 0x00 ) - DBG(5, "scsi_sense_handler: Media (ADF or TMA) not available\n"); - else if ( asc == 0x03 && ascq == 0x00 ) - DBG(5, "scsi_sense_handler: Peripheral device write fault\n"); - else if ( asc == 0x80 && ascq == 0x00 ) - DBG(5, "scsi_sense_handler: Target abort scan\n"); - else - DBG(5, "scsi_sense_handler: Unknown combination of SENSE KEY " - "(0x%02x), ASC (0x%02x) and ASCQ (0x%02x)\n", - sense_key, asc, ascq); - - return SANE_STATUS_IO_ERROR; - - case RQS_SENSEKEY_ILLEGAL: - if ( asc == 0x2c && ascq == 0x00 ) - DBG(5, "scsi_sense_handler: Command sequence error\n"); - else if ( asc == 0x3d && ascq == 0x00) + else if ( asc == 0x00 && ascq == 0x05) + { + DBG(5, "scsi_sense_handler: End of data detected\n"); + return SANE_STATUS_EOF; + } + else if ( asc == 0x3d && ascq == 0x00) DBG(5, "scsi_sense_handler: Invalid bit in IDENTIFY\n"); - else if ( asc == 0x2c && ascq == 0x02 ) + else if ( asc == 0x2c && ascq == 0x02 ) /* Ok */ DBG(5, "scsi_sense_handler: Invalid comb. of windows specfied\n"); - else if ( asc == 0x20 && ascq == 0x00 ) + else if ( asc == 0x20 && ascq == 0x00 ) /* Ok */ DBG(5, "scsi_sense_handler: Invalid command opcode\n"); - else if ( asc == 0x24 && ascq == 0x00 ) + else if ( asc == 0x24 && ascq == 0x00 ) /* Ok */ DBG(5, "scsi_sense_handler: Invalid field in CDB\n"); else if ( asc == 0x26 && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Invalid field in the param list\n"); - else if ( asc == 0x49 && ascq == 0x00 ) + else if ( asc == 0x49 && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Invalid message error\n"); - else if ( asc == 0x25 && ascq == 0x00 ) + else if ( asc == 0x60 && ascq == 0x00 ) + DBG(5, "scsi_sense_handler: Lamp failure\n"); + else if ( asc == 0x25 && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Unsupported logic. unit\n"); - else if ( asc == 0x00 && ascq == 0x00 ) + else if ( asc == 0x53 && ascq == 0x00 ) + { + DBG(5, "scsi_sense_handler: ADF paper jam or no paper\n"); + return SANE_STATUS_NO_DOCS; + } + else if ( asc == 0x54 && ascq == 0x00 ) + { + DBG(5, "scsi_sense_handler: Media bumping\n"); + return SANE_STATUS_JAMMED; /* Don't know if this is right! */ + } + else if ( asc == 0x55 && ascq == 0x00 ) + { + DBG(5, "scsi_sense_handler: Scan Job stopped or cancelled\n"); + return SANE_STATUS_CANCELLED; + } + else if ( asc == 0x3a && ascq == 0x00 ) + { + DBG(5, "scsi_sense_handler: Media (ADF or TMA) not available\n"); + return SANE_STATUS_NO_DOCS; + } + else if ( asc == 0x3a && ascq == 0x01 ) + { + DBG(5, "scsi_sense_handler: Door is not closed\n"); + return SANE_STATUS_COVER_OPEN; + } + else if ( asc == 0x3a && ascq == 0x02 ) + DBG(5, "scsi_sense_handler: Door is not opened\n"); + else if ( asc == 0x00 && ascq == 0x00 ) DBG(5, "scsi_sense_handler: No additional sense information\n"); -/* Ok */ else if ( asc == 0x1a && ascq == 0x00 ) +/* Ok */ else if ( asc == 0x1a && ascq == 0x00 ) DBG(5, "scsi_sense_handler: Parameter list length error\n"); - else if ( asc == 0x26 && ascq == 0x02 ) + else if ( asc == 0x26 && ascq == 0x02 ) DBG(5, "scsi_sense_handler: Parameter value invalid\n"); - else if ( asc == 0x2c && ascq == 0x01 ) - DBG(5, "scsi_sense_handler: Too many windows\n"); + else if ( asc == 0x03 && ascq == 0x00 ) + DBG(5, "scsi_sense_handler: Peripheral device write fault - " + "Firmware Download Error\n"); + else if ( asc == 0x2c && ascq == 0x01 ) + DBG(5, "scsi_sense_handler: Too many windows specified\n"); + else if ( asc == 0x80 && ascq == 0x00 ) + DBG(5, "scsi_sense_handler: Target abort scan\n"); + else if ( asc == 0x96 && ascq == 0x08 ) + { + DBG(5, "scsi_sense_handler: Firewire Device busy\n"); + return SANE_STATUS_DEVICE_BUSY; + } else DBG(5, "scsi_sense_handler: Unknown combination of SENSE KEY " - "(0x%02x), ASC (0x%02x) and ASCQ (0x%02x)\n", + "(0x%02x), ASC (0x%02x) and ASCQ (0x%02x)\n", sense_key, asc, ascq); - - return SANE_STATUS_IO_ERROR; - case RQS_SENSEKEY_VENDOR: - DBG(5, "scsi_sense_handler: Vendor specific SENSE KEY (0x%02x), " - "ASC (0x%02x) and ASCQ (0x%02x)\n", sense_key, asc, ascq); - - return SANE_STATUS_IO_ERROR; + return SANE_STATUS_IO_ERROR; default: DBG(5, "scsi_sense_handler: Unknown sense key (0x%02x)\n", sense_key); return SANE_STATUS_IO_ERROR; } - -#if 0 - return SANE_STATUS_GOOD; -#endif } @@ -5008,8 +5127,8 @@ scsi_test_unit_ready(Microtek2_Device *md) DBG(30, "scsi_test_unit_ready: md=%s\n", md->name); - - TUR_CMD(tur); + + TUR_CMD(tur); status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0); if ( status != SANE_STATUS_GOOD ) { @@ -5051,7 +5170,7 @@ sane_start(SANE_Handle handle) { if (ms->control_bytes) free((void *)ms->control_bytes); ms->control_bytes = (u_int8_t *) malloc(ms->n_control_bytes); - DBG(30, "sane_start: ms->control_bytes=%p, malloc'd %d bytes\n", + DBG(100, "sane_start: ms->control_bytes=%p, malloc'd %d bytes\n", ms->control_bytes, ms->n_control_bytes); if ( ms->control_bytes == NULL ) { @@ -5062,11 +5181,11 @@ sane_start(SANE_Handle handle) } if (ms->sfd < 0) /* first or only pass of this scan */ - { + { /* open device */ - status = sanei_scsi_open (md->sane.name, &ms->sfd, + status = sanei_scsi_open (md->sane.name, &ms->sfd, scsi_sense_handler, 0); - if (status != SANE_STATUS_GOOD) + if (status != SANE_STATUS_GOOD) { DBG(1, "sane_start: scsi_open: '%s'\n", sane_strstatus(status)); goto cleanup; @@ -5124,11 +5243,11 @@ sane_start(SANE_Handle handle) md->status.ntrack |= MD_NTRACK_ON; else md->status.ntrack &= ~MD_NTRACK_ON; - + status = scsi_send_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) goto cleanup; - + /* calculate gamma: we assume, that the gamma values are transferred */ /* with one send gamma command, even if it is a 3 pass scanner */ if ( md->model_flags & MD_NO_GAMMA ) @@ -5167,7 +5286,7 @@ sane_start(SANE_Handle handle) if ( ! (md->model_flags & MD_NO_GAMMA) ) { - status = scsi_send_gamma(ms, 3 * ms->lut_size_bytes); + status = scsi_send_gamma(ms); if ( status != SANE_STATUS_GOOD ) goto cleanup; } @@ -5176,18 +5295,6 @@ sane_start(SANE_Handle handle) if ( status != SANE_STATUS_GOOD ) goto cleanup; -#if 0 - if ( ms->calib_backend - && ! (md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) - && ! (md->model_flags & MD_READ_CONTROL_BIT) ) - { - status = scsi_send_shading(ms, - 3 * ms->lut_entry_size * mi->geo_width, - 0); - if ( status != SANE_STATUS_GOOD ) - goto cleanup; - } -#endif ms->scanning = SANE_TRUE; ms->cancelled = SANE_FALSE; } @@ -5206,14 +5313,17 @@ sane_start(SANE_Handle handle) if ( status != SANE_STATUS_GOOD ) goto cleanup; - /* !!FIXME!! - hack for C6USB because RIS over USB doesn't wait until */ - /* scanner ready */ - if (mi->model_code == 0x9a) - sleep(2); + if ( !( md->model_flags & MD_NO_RIS_COMMAND ) ) + { + /* !!FIXME!! - hack for C6USB because RIS over USB doesn't wait until */ + /* scanner ready */ + if (mi->model_code == 0x9a) + sleep(2); - status = scsi_wait_for_image(ms); - if ( status != SANE_STATUS_GOOD ) - goto cleanup; + status = scsi_wait_for_image(ms); + if ( status != SANE_STATUS_GOOD ) + goto cleanup; + } if ( ms->calib_backend && ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) @@ -5246,7 +5356,13 @@ sane_start(SANE_Handle handle) goto cleanup; } + /* create reader routine as new thread or process */ +#ifdef HAVE_OS2_H + ms->pid = sanei_thread_begin( reader_process,(void*) ms); +#else ms->pid = fork(); +#endif + if ( ms->pid == -1 ) { DBG(1, "sane_start: fork failed\n"); @@ -5256,7 +5372,9 @@ sane_start(SANE_Handle handle) else if ( ms->pid == 0 ) /* child process */ _exit(reader_process(ms)); +#ifndef HAVE_OS2_H close(ms->fd[1]); +#endif return SANE_STATUS_GOOD; cleanup: @@ -5287,7 +5405,11 @@ prepare_buffers(Microtek2_Scanner *ms) strip_lines = 1; /* calculate number of lines that fit into the source buffer */ +#ifdef TESTBACKEND + ms->src_max_lines = MIN( 5000000 / ms->bpl, strip_lines); +#else ms->src_max_lines = MIN( sanei_scsi_max_request_size / ms->bpl, strip_lines); +#endif if ( ms->src_max_lines == 0 ) { DBG(1, "sane_start: Scan buffer too small\n"); @@ -5391,30 +5513,58 @@ static void write_shading_buf_pnm(Microtek2_Scanner *ms) { FILE *outfile; - unsigned int pixel, color, line; + u_int16_t pixel, color, line, factor; unsigned char img_val_out; - float img_val; - int colseq[3]={2, 1, 0}; + float img_val = 0; Microtek2_Device *md; Microtek2_Info *mi; md = ms->dev; mi = &md->info[md->scan_source]; + if ( mi->depth & MI_HASDEPTH_16 ) + factor = 256; + else if ( mi->depth & MI_HASDEPTH_14 ) + factor = 64; + else if ( mi->depth & MI_HASDEPTH_12 ) + factor = 16; + else if ( mi->depth & MI_HASDEPTH_10 ) + factor = 4; + else + factor = 1; + outfile = fopen("shading_buf_w.pnm", "w"); fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n", - mi->geo_width, md->shading_length); + mi->geo_width / mi->calib_divisor, md->shading_length); for ( line=0; line < md->shading_length; ++line ) { - for ( pixel=0; pixel < (unsigned int) mi->geo_width; ++pixel) + for ( pixel=0; + pixel < (u_int16_t) (mi->geo_width / mi->calib_divisor); + ++pixel) { for ( color=0; color < 3; ++color ) { - img_val = *((u_int16_t *) ms->shading_image - + line * ( ms->bpl / ms->lut_entry_size ) - + colseq[color] * ( ms->bpl / ms->lut_entry_size / 3 ) - + pixel); - img_val /= 16.0; + switch( mi->data_format ) + { + case MI_DATAFMT_LPLCONCAT: + img_val = *((u_int16_t *) ms->shading_image + + line * ( ms->bpl / ms->lut_entry_size ) + + mi->color_sequence[color] + * ( ms->bpl / ms->lut_entry_size / 3 ) + + pixel); + break; + case MI_DATAFMT_CHUNKY: + img_val = *((u_int16_t *) ms->shading_image + + line * 3 * mi->geo_width / mi->calib_divisor + + 3 * pixel + + mi->color_sequence[color]); + break; + case MI_DATAFMT_LPLSEGREG: + DBG(1, "Output of shading buffer unsupported for" + "Segreg Data format\n"); + break; + } + img_val /= factor; img_val_out = (unsigned char)img_val; fputc(img_val_out, outfile); } @@ -5429,63 +5579,110 @@ static void write_shading_pnm(Microtek2_Scanner *ms) { FILE *outfile_w = NULL, *outfile_d = NULL; - int pixel, color, line, offset; - float img_val; + int pixel, color, line, offset, num_shading_pixels, output_height; + u_int16_t img_val, factor; Microtek2_Device *md; Microtek2_Info *mi; + output_height = 180; md = ms->dev; mi = &md->info[md->scan_source]; - outfile_w = fopen(".microtek2_shading_w.pnm", "w"); - fprintf(outfile_w, "P6\n#imagedata\n%d %d\n255\n", - mi->geo_width, md->shading_length); - if ( md->shading_table_d != NULL ) - outfile_d = fopen(".microtek2_shading_d.pnm", "w"); - fprintf(outfile_d, "P6\n#imagedata\n%d %d\n255\n", - mi->geo_width, md->shading_length); - for ( line=0; line < 180; ++line ) + DBG(30, "write_shading_pnm: ms=%p\n", ms); + + if ( mi->depth & MI_HASDEPTH_16 ) + factor = 256; + else if ( mi->depth & MI_HASDEPTH_14 ) + factor = 64; + else if ( mi->depth & MI_HASDEPTH_12 ) + factor = 16; + else if ( mi->depth & MI_HASDEPTH_10 ) + factor = 4; + else + factor = 1; + + if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) + num_shading_pixels = ms->n_control_bytes * 8; + else + num_shading_pixels = mi->geo_width / mi->calib_divisor; + if ( md->shading_table_w != NULL ) { - for ( pixel=0; pixel < mi->geo_width; ++pixel) + outfile_w = fopen("microtek2_shading_w.pnm", "w"); + fprintf(outfile_w, "P6\n#imagedata\n%d %d\n255\n", + num_shading_pixels, output_height); + } + if ( md->shading_table_d != NULL ) + { + outfile_d = fopen("microtek2_shading_d.pnm", "w"); + fprintf(outfile_d, "P6\n#imagedata\n%d %d\n255\n", + num_shading_pixels, output_height); + } + for ( line=0; line < output_height; ++line ) + { + for ( pixel=0; pixel < num_shading_pixels ; ++pixel) { for ( color=0; color < 3; ++color ) { - offset = mi->color_sequence[color] * mi->geo_width - + pixel; - img_val = *(md->shading_table_w + offset * 2 ); - img_val += *(md->shading_table_w + offset * 2 + 1)* 256.0; - img_val /= 16.0; - fputc((unsigned char)img_val, outfile_w); + offset = mi->color_sequence[color] + * num_shading_pixels + + pixel; + if ( md->shading_table_w != NULL ) + { + if ( ms->lut_entry_size == 2 ) + { + img_val = *((u_int16_t *) md->shading_table_w + offset ); + img_val /= factor; + } + else + img_val = *((u_int8_t *) md->shading_table_w + offset ); + fputc((unsigned char)img_val, outfile_w); + } + if ( md->shading_table_d != NULL ) { - img_val = *(md->shading_table_d + offset * 2 ); - img_val += *(md->shading_table_d + offset * 2 + 1)* 256.0; - img_val /= 16.0; + if ( ms->lut_entry_size == 2 ) + { + img_val = *((u_int16_t *) md->shading_table_d + offset ); + img_val /= factor; + } + else + img_val = *((u_int8_t *) md->shading_table_d + offset ); fputc((unsigned char)img_val, outfile_d); } } } } - fclose(outfile_w); + if ( md->shading_table_w != NULL ) + fclose(outfile_w); if ( md->shading_table_d != NULL ) fclose(outfile_d); return; } - static void write_cshading_pnm(Microtek2_Scanner *ms) { FILE *outfile; Microtek2_Device *md; Microtek2_Info *mi; - int pixel, color, line, offset, img_val, img_height=30; + int pixel, color, line, offset, img_val, img_height=30, factor; md = ms->dev; mi = &md->info[md->scan_source]; + if ( mi->depth & MI_HASDEPTH_16 ) + factor = 256; + else if ( mi->depth & MI_HASDEPTH_14 ) + factor = 64; + else if ( mi->depth & MI_HASDEPTH_12 ) + factor = 16; + else if ( mi->depth & MI_HASDEPTH_10 ) + factor = 4; + else + factor = 1; + outfile = fopen("microtek2_cshading_w.pnm", "w"); if ( ms->mode == MS_MODE_COLOR ) fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n", ms->ppl, img_height); @@ -5499,13 +5696,13 @@ write_cshading_pnm(Microtek2_Scanner *ms) for ( color=0; color < 3; ++color ) { offset = color * (int)ms->ppl + pixel; - if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) + if ( ms->lut_entry_size == 1 ) img_val = (int) *((u_int8_t *)ms->condensed_shading_w + offset); else { img_val = (int) *((u_int16_t *)ms->condensed_shading_w + offset); - img_val /= 16; + img_val /= factor; } fputc((unsigned char)img_val, outfile); if ( ms->mode == MS_MODE_GRAY ) @@ -5566,7 +5763,11 @@ condense_shading(Microtek2_Scanner *ms) shad_bplc = shad_pixels * ms->lut_entry_size; if ( md_dump >= 3 ) + { dump_area2(md->shading_table_w, shad_bplc * 3, "shading_table_w"); + if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) + write_shading_pnm(ms); + } cond_length = ms->bpl * ms->lut_entry_size; @@ -5705,16 +5906,17 @@ read_shading_image(Microtek2_Scanner *ms) md = ms->dev; mi = &md->info[0]; - md->status.ntrack |= MD_NTRACK_ON; if ( ! MI_WHITE_SHADING_ONLY(mi->shtrnsferequ) || ( md->model_flags & MD_PHANTOM_C6 ) ) + + /* Dark shading correction */ + /* ~~~~~~~~~~~~~~~~~~~~~~~ */ { DBG(30, "read_shading_image: reading black data\n"); - + md->status.ntrack |= MD_NTRACK_ON; md->status.ncalib &= ~MD_NCALIB_ON; md->status.flamp |= MD_FLAMP_ON; - if ( md->model_flags & MD_PHANTOM_C6 ) { md->status.stick |= MD_STICK_ON; @@ -5722,27 +5924,26 @@ read_shading_image(Microtek2_Scanner *ms) } get_calib_params(ms); + if ( md->model_flags & MD_PHANTOM_C6 ) + ms->stay = 1; status = scsi_send_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) - { - DBG(1, "read_shading_image: send_system_status failed: '%s'\n", - sane_strstatus(status)); return status; - } - - if ( md->model_flags & MD_PHANTOM_C6 ) - ms->stay = 1; status = scsi_set_window(ms, 1); if ( status != SANE_STATUS_GOOD ) return status; - + status = scsi_wait_for_image(ms); if ( status != SANE_STATUS_GOOD ) return status; +#ifdef TESTBACKEND + status = scsi_read_sh_image_info(ms); +#else status = scsi_read_image_info(ms); +#endif if ( status != SANE_STATUS_GOOD ) return status; @@ -5768,27 +5969,34 @@ read_shading_image(Microtek2_Scanner *ms) buf = ms->shading_image; +#ifdef TESTBACKEND + max_lines = 5000000 / ms->bpl; +#else max_lines = sanei_scsi_max_request_size / ms->bpl; +#endif if ( max_lines == 0 ) { DBG(1, "read_shading_image: buffer too small\n"); return SANE_STATUS_IO_ERROR; - } + } lines = ms->src_remaining_lines; while ( ms->src_remaining_lines > 0 ) { lines_to_read = MIN(max_lines, ms->src_remaining_lines); - ms->src_buffer_size = lines_to_read * ms->bpl; + ms->src_buffer_size = lines_to_read * ms->bpl; ms->transfer_length = ms->src_buffer_size; - +#ifdef TESTBACKEND + status = scsi_read_sh_d_image(ms, buf); +#else status = scsi_read_image(ms, buf); +#endif if ( status != SANE_STATUS_GOOD ) { DBG(1, "read_shading_image: read image failed: '%s'\n", sane_strstatus(status)); return status; } - + ms->src_remaining_lines -= lines_to_read; buf += ms->src_buffer_size; } @@ -5805,12 +6013,13 @@ read_shading_image(Microtek2_Scanner *ms) status = shading_function(ms, md->shading_table_d); if ( status != SANE_STATUS_GOOD ) return status; - + ms->word = ms->lut_entry_size == 2 ? 1 : 0; ms->current_color = MS_COLOR_ALL; status = scsi_send_shading(ms, md->shading_table_d, - 3 * ms->lut_entry_size * mi->geo_width, + 3 * ms->lut_entry_size + * mi->geo_width / mi->calib_divisor, 1); if ( status != SANE_STATUS_GOOD ) return status; @@ -5823,6 +6032,7 @@ read_shading_image(Microtek2_Scanner *ms) } /* white shading correction */ + /* ~~~~~~~~~~~~~~~~~~~~~~~~ */ DBG(30, "read_shading_image: reading white data\n"); /* According to the doc NCalib must be set for white shading data */ @@ -5836,35 +6046,36 @@ read_shading_image(Microtek2_Scanner *ms) md->status.stick &= ~MD_STICK_ON; md->status.reserved17 |= MD_RESERVED17_ON; } + get_calib_params(ms); status = scsi_send_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) - { - DBG(1, "read_shading_image: send_system_status failed: '%s'\n", - sane_strstatus(status)); - return status; - } + return status; status = scsi_set_window(ms, 1); if ( status != SANE_STATUS_GOOD ) - return status; + return status; status = scsi_wait_for_image(ms); if ( status != SANE_STATUS_GOOD ) - return status; + return status; +#ifdef TESTBACKEND + status = scsi_read_sh_image_info(ms); +#else status = scsi_read_image_info(ms); +#endif if ( status != SANE_STATUS_GOOD ) return status; status = scsi_read_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) - return status; + return status; ms->shading_image = malloc(ms->bpl * ms->src_remaining_lines); DBG(100, "read shading image: ms->shading_image=%p, malloc'd %d bytes\n", - ms->shading_image, ms->bpl * ms->src_remaining_lines); + ms->shading_image, ms->bpl * ms->src_remaining_lines); if ( ms->shading_image == NULL ) { DBG(1, "read_shading_image: malloc for buffer failed\n"); @@ -5872,7 +6083,11 @@ read_shading_image(Microtek2_Scanner *ms) } buf = ms->shading_image; +#ifdef TESTBACKEND + max_lines = 5000000 / ms->bpl; +#else max_lines = sanei_scsi_max_request_size / ms->bpl; +#endif if ( max_lines == 0 ) { DBG(1, "read_shading_image: buffer too small\n"); @@ -5885,7 +6100,11 @@ read_shading_image(Microtek2_Scanner *ms) ms->src_buffer_size = lines_to_read * ms->bpl; ms->transfer_length = ms->src_buffer_size; +#ifdef TESTBACKEND + status = scsi_read_sh_w_image(ms, buf); +#else status = scsi_read_image(ms, buf); +#endif if ( status != SANE_STATUS_GOOD ) return status; @@ -5916,7 +6135,8 @@ read_shading_image(Microtek2_Scanner *ms) ms->current_color = MS_COLOR_ALL; status = scsi_send_shading(ms, md->shading_table_w, - 3 * ms->lut_entry_size * mi->geo_width, + 3 * ms->lut_entry_size + * mi->geo_width / mi->calib_divisor, 0); if ( status != SANE_STATUS_GOOD ) return status; @@ -5934,17 +6154,13 @@ read_shading_image(Microtek2_Scanner *ms) status = scsi_send_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) - { - DBG(1, "read_shading_image: send_system_status failed: %s\n", - sane_strstatus(status)); return status; - } + DBG(100, "free memory for ms->shading_image at %p\n", ms->shading_image); free((void *) ms->shading_image); ms->shading_image = NULL; - return SANE_STATUS_GOOD; } @@ -5958,19 +6174,34 @@ prepare_shading_data(Microtek2_Scanner *ms, u_int32_t lines, u_int8_t **data) /* from the shading image. At the end we have one line. The */ /* color sequence is unchanged. */ +#define MICROTEK2_CALIB_USE_MEDIAN + Microtek2_Device *md; Microtek2_Info *mi; - u_int32_t length, value, line; + u_int32_t length,line; int color, i; + SANE_Status status; + +#ifdef MICROTEK2_CALIB_USE_MEDIAN + u_int16_t *sortbuf, value; +#else + u_int32_t value; +#endif DBG(30, "prepare_shading_data: ms=%p, lines=%d, *data=%p\n", ms, lines, *data); md = ms->dev; mi = &md->info[0]; + status = SANE_STATUS_GOOD; get_lut_size(mi, &ms->lut_size, &ms->lut_entry_size); - length = 3 * ms->lut_entry_size * mi->geo_width; + if ( ms->lut_entry_size == 1 ) + { + DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n"); + return SANE_STATUS_UNSUPPORTED; + } + length = 3 * ms->lut_entry_size * mi->geo_width / mi->calib_divisor; if ( *data == NULL ) { @@ -5983,105 +6214,116 @@ prepare_shading_data(Microtek2_Scanner *ms, u_int32_t lines, u_int8_t **data) } } +#ifdef MICROTEK2_CALIB_USE_MEDIAN + sortbuf = malloc( lines * ms->lut_entry_size ); + DBG(100, "prepare_shading_data: sortbuf= %p, malloc'd %d Bytes\n", + sortbuf, lines * ms->lut_entry_size); + if ( sortbuf == NULL ) + { + DBG(1, "prepare_shading_data: malloc for sort buffer failed\n"); + return SANE_STATUS_NO_MEM; + } +#endif + switch( mi->data_format ) { case MI_DATAFMT_LPLCONCAT: - if ( ms->lut_entry_size == 1 ) - { - DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n"); - return SANE_STATUS_UNSUPPORTED; - } for ( color = 0; color < 3; color++ ) { - for ( i = 0; i < mi->geo_width; i++ ) + for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ ) { value = 0; for ( line = 0; line < lines; line++ ) - value += *((u_int16_t *) ms->shading_image +#ifndef MICROTEK2_CALIB_USE_MEDIAN +/* average the shading lines to get the shading data */ + value += *((u_int16_t *) ms->shading_image + line * ( ms->bpl / ms->lut_entry_size ) + color * ( ms->bpl / ms->lut_entry_size / 3 ) + i); - value /= lines; - *((u_int16_t *) *data + color * mi->geo_width + i) = - MIN(0xffff, (u_int16_t) value); +#else +/* use a median filter to get the shading data -- should be better */ + *(sortbuf + line ) = + *((u_int16_t *) ms->shading_image + + line * ( ms->bpl / ms->lut_entry_size ) + + color * ( ms->bpl / ms->lut_entry_size / 3 ) + + i); + qsort(sortbuf, lines, sizeof(u_int16_t), + (qsortfunc)compare_func_16); + value = *(sortbuf + ( lines - 1 ) / 2 ); +#endif + *((u_int16_t *) *data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = + MIN(0xffff, (u_int16_t) value); } } break; case MI_DATAFMT_CHUNKY: - if ( ms->lut_entry_size == 1 ) - { - DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n"); - return SANE_STATUS_UNSUPPORTED; - } for ( color = 0; color < 3; color++ ) { - for ( i = 0; i < mi->geo_width; i++ ) + for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ ) { value = 0; for ( line = 0; line < lines; line++ ) +#ifndef MICROTEK2_CALIB_USE_MEDIAN +/* average the shading lines to get the shading data */ value += *((u_int16_t *) ms->shading_image - + line * 3 * mi->geo_width + + line * 3 * mi->geo_width / mi->calib_divisor + 3 * i + color); value /= lines; - *((u_int16_t *) *data + color * mi->geo_width + i) = +#else +/* use a median filter to get the shading data -- should be better */ + *(sortbuf + line ) = + *((u_int16_t *) ms->shading_image + + line * 3 * mi->geo_width / mi->calib_divisor + + 3 * i + + color); + qsort(sortbuf, lines, sizeof(u_int16_t), + (qsortfunc)compare_func_16); + value = *(sortbuf + ( lines - 1 ) / 2 ); +#endif + *((u_int16_t *) *data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = MIN(0xffff, (u_int16_t) value); } } - break; case MI_DATAFMT_LPLSEGREG: - DBG(1, "prepare_shading_data: wordsize==1 incorrect supported\n"); - if ( ms->lut_entry_size == 1 ) + for ( color = 0; color < 3; color++ ) { - for ( color = 0; color < 3; color++ ) + for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ ) { - for ( i = 0; i < mi->geo_width; i++ ) - { - value = 0; - for ( line = 0; line < lines; line++ ) - value += *((u_int8_t *) ms->shading_image - + line * 3 * mi->geo_width - + 3 * i - + color); + value = 0; + for ( line = 0; line < lines; line++ ) + value += *((u_int16_t *) ms->shading_image + + line * 3 * mi->geo_width / mi->calib_divisor + + 3 * i + + color); - value /= lines; - *((u_int8_t *) *data + color * mi->geo_width + i) = - MIN(0xff, (u_int8_t) value); - } + value /= lines; + *((u_int16_t *) *data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = + MIN(0xffff, (u_int16_t) value); } } - else - for ( color = 0; color < 3; color++ ) - { - for ( i = 0; i < mi->geo_width; i++ ) - { - value = 0; - for ( line = 0; line < lines; line++ ) - value += *((u_int16_t *) ms->shading_image - + line * 3 * mi->geo_width - + 3 * i - + color); - - value /= lines; - *((u_int16_t *) *data + color * mi->geo_width + i) = - MIN(0xffff, (u_int16_t) value); - } - } - break; default: DBG(1, "prepare_shading_data: Unsupported data format 0x%02x\n", mi->data_format); - return SANE_STATUS_UNSUPPORTED; + status = SANE_STATUS_UNSUPPORTED; } - return SANE_STATUS_GOOD; +#ifdef MICROTEK2_CALIB_USE_MEDIAN + DBG(100, "prepare_shading_data: free sortbuf at %p\n", sortbuf); + free(sortbuf); + sortbuf = NULL; +#endif + return status; } @@ -6104,7 +6346,7 @@ read_cx_shading(Microtek2_Scanner *ms) ms->current_color = MS_COLOR_GREEN; /* for grayscale */ ms->word = 1; - ms->dark = 0; + ms->dark = 0; status = read_cx_shading_image(ms); if ( status != SANE_STATUS_GOOD ) @@ -6120,7 +6362,7 @@ read_cx_shading(Microtek2_Scanner *ms) cleanup: cleanup_scanner(ms); - return status; + return status; } @@ -6136,7 +6378,7 @@ read_cx_shading_image(Microtek2_Scanner *ms) int max_lines, lines_to_read, remaining_lines; md = ms->dev; - + shading_bytes = ms->n_control_bytes * 8 * md->shading_length; if ( ms->current_color == MS_COLOR_ALL ) shading_bytes *= 3; @@ -6158,20 +6400,23 @@ read_cx_shading_image(Microtek2_Scanner *ms) } buf = ms->shading_image; - + DBG(30, "read_cx_shading_image: ms=%p, shading_bytes=%d\n", ms, shading_bytes); linesize = shading_bytes / md->shading_length; +#ifdef TESTBACKEND + max_lines = 5000000 / linesize; +#else max_lines = sanei_scsi_max_request_size / linesize; - - /* the following part is like in "read_shading_image" */ +#endif + /* the following part is like in "read_shading_image" */ remaining_lines = md->shading_length; while ( remaining_lines > 0 ) { lines_to_read = MIN(max_lines, remaining_lines); - buffer_size = lines_to_read * linesize; - + buffer_size = lines_to_read * linesize; + status = scsi_read_shading(ms, buf, buffer_size); if ( status != SANE_STATUS_GOOD ) { @@ -6181,7 +6426,7 @@ read_cx_shading_image(Microtek2_Scanner *ms) remaining_lines -= lines_to_read; buf += buffer_size; } - + status = calc_cx_shading_line(ms); if ( status != SANE_STATUS_GOOD ) { @@ -6197,7 +6442,7 @@ read_cx_shading_image(Microtek2_Scanner *ms) ms->shading_image = NULL; } - return status; + return status; } /*---------- calc_cx_shading_line() ------------------------------------------*/ @@ -6210,25 +6455,32 @@ calc_cx_shading_line(Microtek2_Scanner *ms) { Microtek2_Device *md; SANE_Status status; - u_int8_t *current_byte, *buf; + u_int8_t *current_byte, *buf, *shading_table_pointer; u_int8_t color, factor; - u_int8_t *shading_table_pointer; u_int32_t shading_line_pixels, shading_line_bytes, shading_data_bytes, line, i, accu, color_offset; - float sum; - - status = SANE_STATUS_GOOD; - buf = ms->shading_image; + u_int16_t *sortbuf, value; + md = ms->dev; + status = SANE_STATUS_GOOD; + + sortbuf = malloc( md->shading_length * sizeof(float) ); + DBG(100, "calc_cx_shading: sortbuf= %p, malloc'd %d Bytes\n", + sortbuf, md->shading_length * sizeof(float)); + if ( sortbuf == NULL ) + { + DBG(1, "calc_cx_shading: malloc for sort buffer failed\n"); + return SANE_STATUS_NO_MEM; + } + + buf = ms->shading_image; shading_line_pixels = ms->n_control_bytes * 8; /* = 2560 for 330CX */ shading_line_bytes = shading_line_pixels; /* grayscale */ if ( ms->mode == MS_MODE_COLOR ) /* color */ shading_line_bytes *= 3; - shading_data_bytes = shading_line_bytes; /* 8-bit color depth */ if (ms->word == 1) /* > 8-bit color depth */ shading_data_bytes *= 2; - factor = 4; /* shading bit depth = 10bit; shading line bit depth = 8bit */ if (ms->dark == 0) /* white shading data */ @@ -6275,17 +6527,17 @@ calc_cx_shading_line(Microtek2_Scanner *ms) ms, md->shading_table_w, md->shading_table_d, shading_line_bytes, shading_line_pixels, shading_table_pointer); - /* calculating the mean pixel values over the shading lines */ + /* calculating the median pixel values over the shading lines */ /* and write them to the shading table */ for (color = 0; color < 3; color++) { - color_offset = color * shading_line_pixels; + color_offset = color * shading_line_pixels; if ( ms->word == 1 ) color_offset *=2; for (i = 0; i < shading_line_pixels; i++) { - sum = 0.0; + value = 0; for (line = 0; line < md->shading_length; line++) { current_byte = buf + ( line * shading_data_bytes ) @@ -6303,18 +6555,18 @@ calc_cx_shading_line(Microtek2_Scanner *ms) + color_offset + shading_line_pixels + i; accu += ( *current_byte * 256 ); } - - sum += accu; + *( sortbuf + line ) = accu; } - *shading_table_pointer = (u_int8_t) (sum - / (float) md->shading_length - / (float) factor); - +/* this is the Median filter: sort the values ascending and take the middlest */ + qsort(sortbuf, md->shading_length, sizeof(float), + (qsortfunc)compare_func_16); + value = *( sortbuf + ( md->shading_length - 1 ) / 2 ); + *shading_table_pointer = (u_int8_t) (value / factor); shading_table_pointer++; } - if ( ms->mode != MS_MODE_COLOR ) - break; - } + if ( ms->mode != MS_MODE_COLOR ) + break; + } return status; } @@ -6339,7 +6591,7 @@ get_lut_size(Microtek2_Info *mi, int *max_lut_size, int *lut_entry_size) /* bitdepth of 12, and these values are only used to determine the */ /* size of the shading table */ if ( MI_LUTCAP_NONE(mi->lut_cap) ) - { + { *max_lut_size = 4096; *lut_entry_size = 2; } @@ -6369,6 +6621,16 @@ get_lut_size(Microtek2_Info *mi, int *max_lut_size, int *lut_entry_size) *max_lut_size = 4096; *lut_entry_size = 2; } + if ( mi->lut_cap & MI_LUTCAP_64k_W ) + { + *max_lut_size = 65536; + *lut_entry_size = 2; + } + if ( mi->lut_cap & MI_LUTCAP_16k_W ) + { + *max_lut_size = 16384; + *lut_entry_size = 2; + } DBG(30, "get_lut_size: mi=%p, lut_size=%d, lut_entry_size=%d\n", mi, *max_lut_size, *lut_entry_size); return SANE_STATUS_GOOD; @@ -6408,7 +6670,17 @@ calculate_gamma(Microtek2_Scanner *ms, u_int8_t *pos, int color, char *mode) } else { - if ( mi->depth & MI_HASDEPTH_12 ) + if ( mi->depth & MI_HASDEPTH_16 ) + { + factor = ms->lut_size / 65536; + mult = 65535.0; + } + else if ( mi->depth & MI_HASDEPTH_14 ) + { + factor = ms->lut_size / 16384; + mult = 16383.0; + } + else if ( mi->depth & MI_HASDEPTH_12 ) { factor = ms->lut_size / 4096; mult = 4095.0; @@ -6508,7 +6780,7 @@ shading_function(Microtek2_Scanner *ms, u_int8_t *data) md = ms->dev; mi = &md->info[md->scan_source]; - + if ( ms->lut_entry_size == 1 ) { DBG(1, "shading_function: wordsize = 1 unsupported\n"); @@ -6517,9 +6789,10 @@ shading_function(Microtek2_Scanner *ms, u_int8_t *data) for ( color = 0; color < 3; color++ ) { - for ( i = 0; i < mi->geo_width; i++) + for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++) { - value = *((u_int16_t *) data + color * mi->geo_width + i); + value = *((u_int16_t *) data + + color * ( mi->geo_width / mi->calib_divisor ) + i); switch ( mi->shtrnsferequ ) { case 0x00: @@ -6528,18 +6801,29 @@ shading_function(Microtek2_Scanner *ms, u_int8_t *data) case 0x01: value = (ms->lut_size * ms->lut_size) / value; - *((u_int16_t *) data + color * mi->geo_width + i) = + *((u_int16_t *) data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = MIN(0xffff, (u_int16_t) value); break; case 0x11: - value = (ms->lut_size * ms->lut_size) + value = (ms->lut_size * ms->lut_size) / (u_int32_t) ( (double) value * ((double) mi->balance[color] / 255.0)); - *((u_int16_t *) data + color * mi->geo_width + i) = + *((u_int16_t *) data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = MIN(0xffff, (u_int16_t) value); break; + case 0x15: + value = (u_int32_t) ( ( 1073741824 / (double) value ) + * ( (double) mi->balance[color] + / 256.0) ); + *((u_int16_t *) data + + color * ( mi->geo_width / mi->calib_divisor ) + i) = + MIN(0xffff, (u_int16_t) value); + break; + default: DBG(1, "Unsupported shading transfer function 0x%02x\n", mi->shtrnsferequ ); @@ -6587,7 +6871,11 @@ set_exposure(Microtek2_Scanner *ms) return; } - if ( mi->depth & MI_HASDEPTH_12 ) + if ( mi->depth & MI_HASDEPTH_16 ) + depth = 16; + else if ( mi->depth & MI_HASDEPTH_14 ) + depth = 14; + else if ( mi->depth & MI_HASDEPTH_12 ) depth = 12; else if ( mi->depth & MI_HASDEPTH_10 ) depth = 10; @@ -6606,11 +6894,11 @@ set_exposure(Microtek2_Scanner *ms) for ( color = 0; color < 3; color++) { val32 = (u_int32_t) *((u_int16_t *) from + color * size + byte); - val32 = MIN(val32 + val32 + val32 = MIN(val32 + val32 * (2 * (u_int32_t) exposure / 100), (u_int32_t) maxval); *((u_int16_t *) from + color * size + byte) = (u_int16_t) val32; } - } + } /* and now apply transformation to each channel */ @@ -6649,8 +6937,9 @@ reader_process(Microtek2_Scanner *ms) md = ms->dev; mi = &md->info[md->scan_source]; - close(ms->fd[0]); - +#ifndef HAVE_OS2_H + close(ms->fd[0]); +#endif sigemptyset (&sigterm_set); sigaddset (&sigterm_set, SIGTERM); memset (&act, 0, sizeof (act)); diff --git a/backend/microtek2.h b/backend/microtek2.h index ef3c89ce6..ed48cb071 100644 --- a/backend/microtek2.h +++ b/backend/microtek2.h @@ -4,6 +4,7 @@ microtek2.h This file (C) 1998, 1999 Bernd Schroeder + 2000, 2001 Karsten Festag This file is part of the SANE package. @@ -19,7 +20,7 @@ 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, + fOUNDATIOn, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, the authors of SANE give permission for @@ -58,27 +59,43 @@ /******************************************************************************/ #ifndef PATH_MAX -# define PATH_MAX 1024 +# define PATH_MAX 1024 #endif -#define MM_PER_INCH 25.4 +#ifdef HAVE_AUTHORIZATION +#ifndef PATH_SEP +#if defined(HAVE_OS2_H) +# define PATH_SEP "\\" +#else +# define PATH_SEP "/" +#endif +#endif + +#define MAX_LINE_LEN 512 /* max length of entry in password file */ +#define PASSWD_FILE STRINGIFY(PATH_SANE_CONFIG_DIR) PATH_SEP "auth" +#define SEPARATOR ':' /* separator in that file */ +#define SALT "ab" /* used by crypt() */ + +#endif /* HAVE_AUTHORIZATION */ + +#define MM_PER_INCH 25.4 #define ENDIAN_TYPE(d) { unsigned i, test = 0; \ for (i=0; i < sizeof(int); i++ ) \ test += i << (8 * i); \ d = ((char *) &test)[0] == 0 ? 0 : 1; } - #define MIN(a,b) ((a) < (b)) ? (a) : (b) #define MAX(a,b) ((a) > (b)) ? (a) : (b) #define MICROTEK2_MAJOR 0 -#define MICROTEK2_MINOR 6 +#define MICROTEK2_MINOR 95 +#define MICROTEK2_BUILD "20020112" #define MICROTEK2_CONFIG_FILE "microtek2.conf" /******************************************************************************/ -/* defines that ar common to all devices */ +/* defines that are common to all devices */ /******************************************************************************/ #define MD_RESOLUTION_DEFAULT 72 << SANE_FIXED_SCALE_SHIFT @@ -160,12 +177,23 @@ #define SG_DATA_P SG_CMD_L +/* READ CONTROL BITS */ +#define RCB_SET_CMD(d) (d)[0] = 0x28; (d)[1] = 0x00; (d)[2] = 0x90; \ + (d)[3] = 0x00; (d)[4] = 0x00; (d)[5] = 0x00; \ + (d)[6] = 0x00; (d)[7] = 0x00; (d)[8] = 0x00; \ + (d)[9] = 0x00 +#define RCB_CMD_L 10 +#define RCB_SET_LENGTH(d,s) (d)[6] = (((s) >> 16) & 0xff); \ + (d)[7] = (((s) >> 8) & 0xff); \ + (d)[8] = ((s) & 0xff); + + /* READ_SCANNER_ATTRIBUTES */ #define RSA_CMD(d) d[0]=0x28; d[1]=0x00; d[2]=0x82; d[3]=0x00; \ d[4]=0x00; d[5]=0x00; d[6]=0x00; d[7]=0x00; \ d[8]=0x28; d[9]=0x00 #define RSA_CMD_L 10 -#define RSA_SETMEDIA(d,p) d[5] |= ((p) & 0x77) +#define RSA_SETMEDIA(d,p) d[5] |= ((p) & 0x77) #define RSA_TRANSFERLENGTH 40 #define RSA_COLOR(d,s) d = (((s)[0] >> 7) & 0x01) @@ -179,29 +207,34 @@ d[1] = (((s)[1] >> 4) & 0x03); \ d[2] = (((s)[1] >> 2) & 0x03); \ } +#define RSA_NIS(d,s) d = ((s)[1] & 0x02) #define RSA_DATSEQ(d,s) d = ((s)[1] & 0x01) -#define RSA_CCDGAP(d,s) d = (s)[2] +#define RSA_CCDGAP(d,s) d = (s)[2] #define RSA_MAX_XRESOLUTION(d,s) d = ((s)[3] << 8) + (s)[4] #define RSA_MAX_YRESOLUTION(d,s) d = ((s)[5] << 8) + (s)[6] #define RSA_GEOWIDTH(d,s) d = ((s)[7] << 8) + (s)[8] #define RSA_GEOHEIGHT(d,s) d = ((s)[9] << 8) + (s)[10] #define RSA_OPTRESOLUTION(d,s) d = ((s)[11] << 8) + (s)[12] -#define RSA_DEPTH(d,s) d = (((s)[13] >> 4) & 0x07) +#define RSA_DEPTH(d,s) d = (((s)[13] >> 4) & 0x0f) #define RSA_SCANMODE(d,s) d = (s)[13] & 0x0f #define RSA_CCDPIXELS(d,s) d = ((s)[14] << 8) + (s)[15] -#define RSA_LUTCAP(d,s) d = (s)[16] & 0x1f -#define RSA_DNLDPTRN(d,s) d = (((s)[17] >> 7) & 0x01) -#define RSA_GRAINSLCT(d,s) d = (s)[17] & 0x7f -#define RSA_SUPPOPT(d,s) d = (s)[18] & 0xf3 +#define RSA_LUTCAP(d,s) d = (s)[16] +#define RSA_DNLDPTRN(d,s) d = (((s)[17] >> 7) & 0x01) +#define RSA_GRAINSLCT(d,s) d = (s)[17] & 0x7f +#define RSA_SUPPOPT(d,s) d = (s)[18] & 0xf3 #define RSA_CALIBWHITE(d,s) d = ((s)[19] << 24) + ((s)[20] << 16) \ + ((s)[21] << 8) + (s)[22] #define RSA_CALIBSPACE(d,s) d = ((s)[23] << 24) + ((s)[24] << 16) \ + ((s)[25] << 8) + (s)[26] #define RSA_NLENS(d,s) d = (s)[27] #define RSA_NWINDOWS(d,s) d = (s)[28] -#define RSA_SHTRNSFEREQU(d,s) d = (((s)[29] >> 2) & 0x01) +#define RSA_SHTRNSFEREQU(d,s) d = (((s)[29] >> 2) & 0x3f) #define RSA_SCNBTTN(d,s) d = (((s)[29] >> 1) & 0x01) #define RSA_BUFTYPE(d,s) d = (s)[29] & 0x01 +#define RSA_REDBALANCE(d,s) d = ((s)[30] << 8) | (s)[31] +#define RSA_GREENBALANCE(d,s) d = ((s)[32] << 8) | (s)[33] +#define RSA_BLUEBALANCE(d,s) d = ((s)[34] << 8) | (s)[35] +#define RSA_APSMAXFRAMES(d,s) d = (s)[36] /* READ IMAGE INFORMATION */ @@ -228,6 +261,37 @@ #define RII_GET_V300_REMAINBYTES(d,s) d = ((s)[6] << 24) + ((s)[7] << 16) \ + ((s)[8] << 8) + (s)[9] +/* READ SHADING INFORMATION */ +#define RSI_SET_CMD(d) (d)[0] = 0x28; (d)[1] = 0x00; (d)[2] = 0x01; \ + (d)[3] = 0x00; (d)[4] = 0x00; (d)[5] = 0x00; \ + (d)[6] = 0x00; (d)[7] = 0x00; (d)[8] = 0x10; \ + (d)[9] = 0x00 +#define RSI_CMD_L 10 +#define RSI_SET_PCORMAC(d,s) (d)[5] |= (((s) << 7) & 0x80) +#define RSI_SET_COLOR(d,s) (d)[5] |= (((s) << 5) & 0x60) +#define RSI_SET_DARK(d,s) (d)[5] |= (((s) << 1) & 0x02) /*(KF)*/ + /* RSI_SET_DARK was missing*/ +#define RSI_SET_WORD(d,s) (d)[5] |= ((s) & 0x01) +#define RSI_SET_TRANSFERLENGTH(d,s) (d)[6] = (((s) >> 16) & 0xff); \ + (d)[7] = (((s) >> 8) & 0xff); \ + (d)[8] = ((s) & 0xff); + +/* SEND SHADING INFORMATION */ +#define SSI_SET_CMD(d) (d)[0] = 0x2a; (d)[1] = 0x00; (d)[2] = 0x01; \ + (d)[3] = 0x00; (d)[4] = 0x00; (d)[5] = 0x00; \ + (d)[6] = 0x00; (d)[7] = 0x00; (d)[8] = 0x00; \ + (d)[9] = 0x00 +#define SSI_CMD_L 10 +#define SSI_SET_PCORMAC(d,s) (d)[5] |= (((s) << 7) & 0x80) +#define SSI_SET_COLOR(d,s) (d)[5] |= (((s) << 5) & 0x60) +#define SSI_SET_DARK(d,s) (d)[5] |= (((s) << 1) & 0x02) +#define SSI_SET_WORD(d,s) (d)[5] |= ((s) & 0x01) +#define SSI_SET_TRANSFERLENGTH(d,s) (d)[6] = (((s) >> 16) & 0xff); \ + (d)[7] = (((s) >> 8) & 0xff); \ + (d)[8] = ((s) & 0xff); + + +/* READ IMAGE */ /* READ IMAGE */ #define RI_SET_CMD(d) (d)[0] = 0x28; (d)[1] = 0x00; (d)[2] = 0x00; \ @@ -243,7 +307,7 @@ (d)[7] = (((s) >> 8) & 0xff); \ (d)[8] = ((s) & 0xff); - + /* READ SYSTEM_STATUS */ #define RSS_CMD(d) (d)[0] = 0x28; (d)[1] = 0x00; (d)[2] = 0x81; \ (d)[3] = 0x00; (d)[4] = 0x00; (d)[5] = 0x00; \ @@ -252,10 +316,17 @@ #define RSS_CMD_L 10 #define RSS_RESULT_L 9 +#define RSS_FIRSTSCAN(s) (s)[0] & 0x80 +#define RSS_AFOCUS(s) (s)[0] & 0x40 +#define RSS_SSKIP(s) (s)[0] & 0x20 +#define RSS_STICK(s) (s)[0] & 0x10 #define RSS_NTRACK(s) (s)[0] & 0x08 #define RSS_NCALIB(s) (s)[0] & 0x04 #define RSS_TLAMP(s) (s)[0] & 0x02 #define RSS_FLAMP(s) (s)[0] & 0x01 +#define RSS_FSH(s) (s)[1] & 0x20 +#define RSS_TEFLAG(s) (s)[1] & 0x10 +#define RSS_WHITESTRIE(s) (s)[1] & 0x08 #define RSS_RDYMAN(s) (s)[1] & 0x04 #define RSS_TRDY(s) (s)[1] & 0x02 #define RSS_FRDY(s) (s)[1] & 0x01 @@ -265,12 +336,21 @@ #define RSS_LENSSTATUS(s) (s)[3] #define RSS_ALOFF(s) (s)[4] & 0x80 #define RSS_TIMEREMAIN(s) (s)[4] & 0x7f +#define RSS_MTMACNT(s) (s)[5] & 0x40 +#define RSS_MOVE(s) (s)[5] & 0x20 +#define RSS_LAMP(s) (s)[5] & 0x10 +#define RSS_EJECT(s) (s)[5] & 0x08 #define RSS_TMACNT(s) (s)[5] & 0x04 #define RSS_PAPER(s) (s)[5] & 0x02 #define RSS_ADFCNT(s) (s)[5] & 0x01 -#define RSS_CURRENTMODE(s) (s)[6] & 0x03 +#define RSS_CANCELBTN(s) (s)[6] & 0x80 +#define RSS_COPYBTN(s) (s)[6] & 0x40 +#define RSS_EMAILBTN(s) (s)[6] & 0x20 +#define RSS_GOBTN(s) (s)[6] & 0x10 +#define RSS_TURBOBTN(s) (s)[6] & 0x08 +#define RSS_CURRENTMODE(s) (s)[6] & 0x07 #define RSS_BUTTONCOUNT(s) (s)[7] - +#define RSS_MFOCUS(s) (s)[9] /* SEND SYSTEM STATUS */ #define SSS_CMD(d) (d)[0] = 0x2a; (d)[1] = 0x00; (d)[2] = 0x81; \ @@ -280,10 +360,14 @@ #define SSS_CMD_L 10 #define SSS_DATA_L 9 +#define SSS_AFOCUS(d,p) d[0] |= (p) & 0x40 +#define SSS_STICK(d,p) d[0] |= (p) & 0x10 #define SSS_NTRACK(d,p) d[0] |= (p) & 0x08 #define SSS_NCALIB(d,p) d[0] |= (p) & 0x04 #define SSS_TLAMP(d,p) d[0] |= (p) & 0x02 #define SSS_FLAMP(d,p) d[0] |= (p) & 0x01 +#define SSS_RESERVED17(d,p) d[1] |= (p) & 0x80 +#define SSS_FSH(d,p) d[1] |= (p) & 0x40 #define SSS_RDYMAN(d,p) d[1] |= (p) & 0x04 #define SSS_TRDY(d,p) d[1] |= (p) & 0x02 #define SSS_FRDY(d,p) d[1] |= (p) & 0x01 @@ -298,6 +382,7 @@ #define SSS_ADFCNT(d,p) d[5] |= (p) & 0x01 #define SSS_CURRENTMODE(d,p) d[6] |= (p) & 0x07 #define SSS_BUTTONCOUNT(d,p) d[6] |= (p) +#define SSS_MFOCUS(s) d[9] |= (p) /* SET WINDOW */ @@ -343,12 +428,15 @@ #define SW_BRIGHTNESS_M(d,p) (d)[22] = (p) #define SW_THRESHOLD(d,p) (d)[23] = (p) #define SW_CONTRAST_M(d,p) (d)[24] = (p) -#define SW_IMGCOMP(d,p) (d)[25] = (p) +#define SW_IMGCOMP(d,p) (d)[25] = (p) & 0x0f /* take lineartfake */ + /* into account */ #define SW_BITSPERPIXEL(d,p) (d)[26] = (p) #define SW_EXPOSURE_M(d,p) (d)[27] = (p) #define SW_EXTHT(d,p) (d)[28] |= (((p) << 7) & 0x80) #define SW_INTHTINDEX(d,p) (d)[28] |= ((p) & 0x7f) #define SW_RIF(d,p) (d)[29] |= (((p) << 7) & 0x80) +#define SW_NOGAMMA(d,p) (d)[29] |= (((p) << 6) & 0x40) +#define SW_SLOWSCAN(d,p) (d)[29] |= (((p) << 5) & 0x20) #define SW_LENS(d,p) (d)[30] = (p) #define SW_INFINITE(d,p) (d)[31] |= (((p) << 7) & 0x80) #define SW_STAY(d,p) (d)[31] |= (((p) << 6) & 0x40) @@ -356,6 +444,9 @@ #define SW_QUALITY(d,p) (d)[31] |= (((p) << 4) & 0x10) #define SW_FASTSCAN(d,p) (d)[31] |= (((p) << 3) & 0x08) #define SW_MEDIA(d,p) (d)[31] |= ((p) & 0x07) +#define SW_JPEGENABLE(d,p) (d)[34] |= (((p) << 7) & 0x80) +#define SW_JPEGALGOR(d,p) (d)[34] |= (((p) << 5) & 0x60) +#define SW_JPEGMODE(d,p) (d)[34] |= (((p) << 3) & 0x18) #define SW_SHADOW_M(d,p) (d)[40] = (p) #define SW_MIDTONE_M(d,p) (d)[41] = (p) #define SW_HIGHLIGHT_M(d,p) (d)[42] = (p) @@ -384,7 +475,7 @@ (d)[3] = 0x00; (d)[4] = 0x00; (d)[5] = 0x00; \ (d)[6] = 0x00; (d)[7] = 0x00; (d)[8] = 0x00; \ (d)[9] = 0x00 -#define RIS_CMD_L 10 +#define RIS_CMD_L 10 #define RIS_SET_PCORMAC(d,p) (d)[4] |= (((p) << 7) & 0x80) #define RIS_SET_COLOR(d,p) (d)[4] |= (((p) << 5) & 0x60) @@ -429,34 +520,34 @@ enum Microtek2_Option { /*0*/ OPT_NUM_OPTS = 0, - + /*1*/OPT_MODE_GROUP, OPT_SOURCE, - OPT_MODE, - OPT_RESOLUTION, + OPT_MODE, + OPT_BITDEPTH, + OPT_RESOLUTION, OPT_X_RESOLUTION, OPT_Y_RESOLUTION, - OPT_RESOLUTION_BIND, - OPT_DISABLE_BACKTRACK, OPT_PREVIEW, - - /*10*/ OPT_GEOMETRY_GROUP, + + /*9*/ OPT_GEOMETRY_GROUP, OPT_TL_X, /* top-left x */ OPT_TL_Y, /* top-left y */ OPT_BR_X, /* bottom-right x */ - OPT_BR_Y, /* bottom-right y */ - - /*15*/ OPT_ENHANCEMENT_GROUP, - OPT_BRIGHTNESS, - OPT_CONTRAST, + OPT_BR_Y, /* bottom-right y */ + + /*14*/ OPT_ENHANCEMENT_GROUP, + OPT_BRIGHTNESS, + OPT_CONTRAST, OPT_THRESHOLD, OPT_HALFTONE, + OPT_AUTOADJUST, /*20*/ OPT_GAMMA_GROUP, - OPT_GAMMA_MODE, + OPT_GAMMA_MODE, OPT_GAMMA_SCALAR, OPT_GAMMA_SCALAR_R, - OPT_GAMMA_SCALAR_G, + OPT_GAMMA_SCALAR_G, OPT_GAMMA_SCALAR_B, OPT_GAMMA_CUSTOM, OPT_GAMMA_CUSTOM_R, @@ -468,26 +559,38 @@ enum Microtek2_Option /* these options must appear in exactly this order, */ /* sane_control_option relies on it */ OPT_CHANNEL, - OPT_SHADOW, - OPT_MIDTONE, - OPT_HIGHLIGHT, - OPT_SHADOW_R, + OPT_SHADOW, + OPT_MIDTONE, + OPT_HIGHLIGHT, + OPT_SHADOW_R, OPT_MIDTONE_R, - OPT_HIGHLIGHT_R, - OPT_SHADOW_G, - OPT_MIDTONE_G, - OPT_HIGHLIGHT_G, - OPT_SHADOW_B, - OPT_MIDTONE_B, - OPT_HIGHLIGHT_B, + OPT_HIGHLIGHT_R, + OPT_SHADOW_G, + OPT_MIDTONE_G, + OPT_HIGHLIGHT_G, + OPT_SHADOW_B, + OPT_MIDTONE_B, + OPT_HIGHLIGHT_B, OPT_EXPOSURE, OPT_EXPOSURE_R, OPT_EXPOSURE_G, OPT_EXPOSURE_B, - /*49*/ NUM_OPTIONS -}; + /*49*/ OPT_SPECIAL, + OPT_RESOLUTION_BIND, + OPT_DISABLE_BACKTRACK, + OPT_CALIB_BACKEND, + OPT_LIGHTLID35, + OPT_TOGGLELAMP, + /*55*/ OPT_COLORBALANCE, + OPT_BALANCE_R, + OPT_BALANCE_G, + OPT_BALANCE_B, + OPT_BALANCE_FW, + + /*60*/ NUM_OPTIONS +}; /******************************************************************************/ /* value structure for scanner options */ @@ -499,350 +602,50 @@ typedef union { SANE_String s; } Microtek2_Option_Value; - - -/******************************************************************************/ -/* scanner hardware info (as discovered by INQUIRY and READ ATTRIBUTES) */ -/******************************************************************************/ - -typedef struct Microtek2_Info { - /* from inquiry */ - SANE_Byte device_qualifier; -#define MI_DEVTYPE_SCANNER 0x06 - SANE_Byte device_type; -#define MI_SCSI_II_VERSION 0x02 - SANE_Byte scsi_version; - SANE_Char vendor[INQ_VENDOR_L + 1]; - SANE_Char model[INQ_MODEL_L + 1]; - SANE_Char revision[INQ_REV_L + 1]; - SANE_Byte model_code; - /* from read scanner attributes */ - /* #define MI_HAS_COLOR SANE_TRUE */ - SANE_Bool color; -#define MI_HAS_ONEPASS SANE_TRUE - SANE_Bool onepass; - /* the following 3 defines must correspond to byte 31 of SET WINDOW cmd */ -#define MI_TYPE_FLATBED 0x01 -#define MI_TYPE_SHEEDFEED 0x02 -#define MI_TYPE_TRANSPARENCY 0x03 - SANE_Byte scanner_type; -#define MI_HAS_FEPROM SANE_TRUE - SANE_Bool feprom; - /* MI_DATA_FORMAT_X must correspond to Byte 0 in READ SCANNER ATTRIBUTE */ -#define MI_DATAFMT_CHUNKY 1 -#define MI_DATAFMT_LPLCONCAT 2 -#define MI_DATAFMT_LPLSEGREG 3 -#define MI_DATAFMT_WORDCHUNKY 5 - SANE_Byte data_format; -#define MI_COLSEQ_RED 0 -#define MI_COLSEQ_GREEN 1 -#define MI_COLSEQ_BLUE 2 -#define MI_COLSEQ_ILLEGAL 3 - SANE_Byte color_sequence[RSA_COLORSEQUENCE_L]; - SANE_Byte ccd_gap; - SANE_Int max_xresolution; - SANE_Int max_yresolution; - SANE_Int geo_width; - SANE_Int geo_height; - SANE_Int opt_resolution; -#define MI_HASDEPTH_NIBBLE 1 -#define MI_HASDEPTH_10 2 -#define MI_HASDEPTH_12 4 - SANE_Byte depth; -#define MI_HASMODE_LINEART 1 -#define MI_HASMODE_HALFTONE 2 -#define MI_HASMODE_GRAY 4 -#define MI_HASMODE_COLOR 8 - SANE_Byte scanmode; - SANE_Int ccd_pixels; -#define MI_LUTCAP_NONE(d) (((d) & 0x1f) == 0) -#define MI_LUTCAP_256B 1 -#define MI_LUTCAP_1024B 2 -#define MI_LUTCAP_1024W 4 -#define MI_LUTCAP_4096B 8 -#define MI_LUTCAP_4096W 16 - SANE_Byte lut_cap; -#define MI_HAS_DNLDPTRN SANE_TRUE - SANE_Bool has_dnldptrn; - SANE_Byte grain_slct; -#define MI_OPTDEV_ADF 0x01 -#define MI_OPTDEV_TMA 0x02 -#define MI_OPTDEV_ADP 0x10 -#define MI_OPTDEV_APS 0x20 -#define MI_OPTDEV_STRIPE 0x40 -#define MI_OPTDEV_SLIDE 0x80 - SANE_Byte option_device; - SANE_Int calib_white; - SANE_Int calib_space; - SANE_Byte nlens; - SANE_Byte nwindows; -#define MI_SH_TRNSFEREQU_0 0x00 -#define MI_SH_TRNSFEREQU_1 0x01 -#define MI_SH_TRNSFEREQU_2 0x02 -#define MI_SH_TRNSFEREQU_3 0x03 -#define MI_SH_TRNSFEREQU_4 0x04 - SANE_Byte shtrnsferequ; -#define MI_HAS_SCNBTTN SANE_TRUE - SANE_Bool scnbuttn; -#define MI_HAS_PIPOBUF SANE_TRUE - SANE_Bool buftype; -} Microtek2_Info; - - - - - - -/******************************************************************************/ -/* device structure (one for each device in config file) */ -/******************************************************************************/ - -typedef struct Microtek2_Device { - struct Microtek2_Device *next; /* next, for linked list */ - -#define MD_SOURCE_FLATBED 0 -#define MD_SOURCE_ADF 1 -#define MD_SOURCE_TMA 2 -#define MD_SOURCE_SLIDE 3 -#define MD_SOURCE_STRIPE 4 - Microtek2_Info info[5]; /* detailed scanner spec */ - SANE_Device sane; /* SANE generic device block */ - char name[PATH_MAX]; /* name from config file */ - - SANE_Int *custom_gamma_table[4]; /* used for the custom gamma */ - /* values before a scan starts */ - /* the following two are derived from lut_cap */ - int max_lut_size; /* in bytes */ - int lut_entry_size; /* word or byte transfer in LUT */ - u_int8_t scan_source; - double revision; - - /* the following structure describes the device status */ -#define MD_TLAMP_ON 2 -#define MD_FLAMP_ON 1 -#define MD_NCALIB_ON 4 -#define MD_NTRACK_ON 8 -#define MD_CURRENT_MODE_FLATBED 0 - struct { - u_int8_t ntrack; - u_int8_t ncalib; - u_int8_t tlamp; - u_int8_t flamp; - u_int8_t rdyman; - u_int8_t trdy; - u_int8_t frdy; - u_int8_t adp; - u_int8_t detect; - u_int8_t adptime; - u_int8_t lensstatus; - u_int8_t aloff; - u_int8_t timeremain; - u_int8_t tmacnt; - u_int8_t paper; - u_int8_t adfcnt; - u_int8_t currentmode; - u_int8_t buttoncount; - } status; - - -#define MD_MODESTRING_NUMS 9 -#define MD_MODESTRING_COLOR36 "36-bit Color" -#define MD_MODESTRING_COLOR30 "30-bit Color" -#define MD_MODESTRING_COLOR24 "24-bit Color" -#define MD_MODESTRING_GRAY12 "12-bit Gray" -#define MD_MODESTRING_GRAY10 "10-bit Gray" -#define MD_MODESTRING_GRAY8 "8-bit Gray" -#define MD_MODESTRING_GRAY2 "2-bit Gray" -#define MD_MODESTRING_HALFTONE "Halftone" -#define MD_MODESTRING_LINEART "LineArt" - SANE_String_Const scanmode_list[MD_MODESTRING_NUMS + 1]; - -#define MD_SOURCESTRING_NUMS 5 -#define MD_SOURCESTRING_FLATBED "Flatbed " -#define MD_SOURCESTRING_ADF "ADF" -#define MD_SOURCESTRING_TMA "TMA" -#define MD_SOURCESTRING_STRIPE "Filmstrip" -#define MD_SOURCESTRING_SLIDE "Slide" - SANE_String_Const scansource_list[MD_SOURCESTRING_NUMS + 1]; - -#define MD_HALFTONE_NUMS 12 -#define MD_HALFTONE0 "53-dot screen (53 gray levels)" -#define MD_HALFTONE1 "Horiz. screen (65 gray levels)" -#define MD_HALFTONE2 "Vert. screen (65 gray levels)" -#define MD_HALFTONE3 "Mixed page (33 gray levels)" -#define MD_HALFTONE4 "71-dot screen (29 gray levels)" -#define MD_HALFTONE5 "60-dot #1 (26 gray levels)" -#define MD_HALFTONE6 "60-dot #2 (26 gray levels)" -#define MD_HALFTONE7 "Fine detail #1 (17 gray levels)" -#define MD_HALFTONE8 "Fine detail #2 (17 gray levels)" -#define MD_HALFTONE9 "Slant line (17 gray levels)" -#define MD_HALFTONE10 "Posterizing (10 gray levels)" -#define MD_HALFTONE11 "High Contrast (5 gray levels)" - SANE_String_Const halftone_mode_list[MD_HALFTONE_NUMS + 1]; - -#define MD_CHANNEL_NUMS 4 -#define MD_CHANNEL_MASTER "Master" -#define MD_CHANNEL_RED "Red" -#define MD_CHANNEL_GREEN "Green" -#define MD_CHANNEL_BLUE "Blue" - SANE_String_Const channel_list[MD_CHANNEL_NUMS + 1]; - -#define MD_GAMMAMODE_NUMS 3 -#define MD_GAMMAMODE_LINEAR "None" -#define MD_GAMMAMODE_SCALAR "Scalar" -#define MD_GAMMAMODE_CUSTOM "Custom" - SANE_String_Const gammamode_list[MD_GAMMAMODE_NUMS + 1]; - - SANE_Range x_res_range_dpi; /* X resolution in dpi */ - SANE_Range y_res_range_dpi; /* Y resolution in dpi */ - SANE_Range x_range_mm; /* scan width in mm */ - SANE_Range y_range_mm; /* scan height in mm */ - SANE_Range percentage_range; /* for brightness, shadow, ... */ - SANE_Range custom_gamma_range; /* for custom gamma values */ - SANE_Range scalar_gamma_range; /* for scalar gamma values */ - SANE_Range shadow_range; /* shadow of blue channel */ - SANE_Range midtone_range; /* midtone shadow of blue channel */ - SANE_Range exposure_range; /* for lengthening exposure time */ - SANE_Range highlight_range; /* highlight of master channel */ - SANE_Range threshold_range; /* 1 - 255 */ -} Microtek2_Device; - - - -/******************************************************************************/ -/* scanner structure (one for each device in use) */ -/* ....all the state needed to define a scan request */ -/******************************************************************************/ - -typedef struct Microtek2_Scanner { - struct Microtek2_Scanner *next; /* for linked list */ - Microtek2_Device *dev; /* raw device info */ - Microtek2_Option_Value val[NUM_OPTIONS + 1]; /* option values for session */ - SANE_Parameters params; /* format, lastframe, lines, depth, ppl, bpl */ - SANE_Option_Descriptor sod[NUM_OPTIONS + 1]; /* option list for session */ - - u_int8_t *gamma_table; - -/* the following defines must correspond to byte 25 of SET WINDOW body */ -#define MS_MODE_LINEART 0x00 -#define MS_MODE_HALFTONE 0x01 -#define MS_MODE_GRAY 0x02 -#define MS_MODE_COLOR 0x05 - -/* the following defines must correspond to byte 31 of SET WINDOW body */ -#define MS_SOURCE_FLATBED 0x00 -#define MS_SOURCE_ADF 0x01 -#define MS_SOURCE_TMA 0x02 -#define MS_SOURCE_STRIPE 0x05 -#define MS_SOURCE_SLIDE 0x06 - - SANE_Int mode; - SANE_Int depth; - SANE_Int x_resolution_dpi; - SANE_Int y_resolution_dpi; - SANE_Int x1_dots; /* x-position in units of optical resolution */ - SANE_Int y1_dots; /* same for y-position */ - SANE_Int width_dots; /* scan width in units of optical resolution */ - SANE_Int height_dots; /* same for height */ - u_int8_t brightness_m; - u_int8_t contrast_m; - u_int8_t exposure_m; - u_int8_t shadow_m; - u_int8_t midtone_m; - u_int8_t highlight_m; - u_int8_t brightness_r; - u_int8_t contrast_r; - u_int8_t exposure_r; - u_int8_t shadow_r; - u_int8_t midtone_r; - u_int8_t highlight_r; - u_int8_t brightness_g; - u_int8_t contrast_g; - u_int8_t exposure_g; - u_int8_t shadow_g; - u_int8_t midtone_g; - u_int8_t highlight_g; - u_int8_t brightness_b; - u_int8_t contrast_b; - u_int8_t exposure_b; - u_int8_t shadow_b; - u_int8_t midtone_b; - u_int8_t highlight_b; - u_int8_t threshold; - SANE_Bool use_external_ht; - SANE_Byte internal_ht_index; - u_int8_t rawdat; - SANE_Bool quality; - SANE_Bool fastscan; - SANE_Byte scan_source; - int no_backtracking; - int current_pass; /* current pass if 3-pass scan */ - int lut_size; /* size of gamma lookup table */ - int lut_entry_size; /* size of one entry in lookup table */ - u_int16_t lut_size_bytes; /* size of LUT in bytes */ - u_int8_t word; /* word transfer, used in some read cmds */ - /* MS _COLOR_X must correspond to color field in READ IMAGE STATUS */ -#define MS_COLOR_RED 0 -#define MS_COLOR_GREEN 1 -#define MS_COLOR_BLUE 2 -#define MS_COLOR_ALL 3 - u_int8_t current_color; /* for gamma clac. and 3-pass scanners */ - u_int32_t ppl; /* pixels per line as returned by RII */ - u_int32_t bpl; /* bytes per line as returned by RII */ - u_int32_t remaining_bytes; /* remaining bytes as returned by RII */ - u_int32_t real_remaining_bytes;/* bytes to transfer to the frontend */ - u_int32_t real_bpl; /* bytes to transfer to the frontend */ - SANE_Int src_remaining_lines; /* remaining lines to read */ - SANE_Int src_lines_to_read; /* actual number of lines read */ - SANE_Int src_max_lines; /* maximum number of lines that fit */ - /* into the scsi buffer */ - /* sent to the frontend */ - int bits_per_pixel_in; /* bits per pixel transferred from scanner */ - int bits_per_pixel_out; /* bits per pixel transf. to frontend */ - unsigned long src_buffer_size; /* size of this buffer */ - int transfer_length; /* transfer length for RI command */ - struct { - u_int8_t *src_buffer[2]; /* two buffers because of CCD gap */ - u_int8_t *src_buf; - int current_src; - unsigned int free_lines; - unsigned int free_max_lines; - u_int8_t *current_pos[3]; /* actual position in the source buffer */ - int planes[2][3]; /* # of red, green, blue planes in the */ - /* current source buffer and leftover */ - /* planes from previous "read image" */ - } buf; - - SANE_Bool onepass; - - int scanning; /* true == between sane_start & sane_read=EOF */ - int cancelled; - int sfd; /* SCSI filedescriptor */ - int fd[2]; /* file descriptors for pipe */ - pid_t pid; /* pid of child process */ - FILE *fp; - -} Microtek2_Scanner; - /******************************************************************************/ /* Description of options not included in saneopts.h */ /******************************************************************************/ -#define M_NAME_SCANSOURCE "scan-source" -#define M_TITLE_SCANSOURCE "Scan source" -#define M_DESC_SCANSOURCE "Selects the scan source, i.e. flatbed," \ - " transparency media adapter (TMA) or" \ - " automatic document feeder (ADF)." - #define M_NAME_NOBACKTRACK "no-backtracking" #define M_TITLE_NOBACKTRACK "Disable backtracking" #define M_DESC_NOBACKTRACK "If checked the scanner does not perform" \ " backtracking." - + +#define M_NAME_TOGGLELAMP "toggle-lamp" +#define M_TITLE_TOGGLELAMP "Toggle lamp of flatbed" +#define M_DESC_TOGGLELAMP "Toggles the lamp of the flatbed" + +#define M_NAME_CALIBBACKEND "backend-calibration" +#define M_TITLE_CALIBBACKEND "Calibration by backend" +#define M_DESC_CALIBBACKEND "If checked the color calibration before" \ + " a scan is done by the backend. Uncheck" \ + " this option if you experience any problem." + +#define M_NAME_LIGHTLID35 "lightlid35" +#define M_TITLE_LIGHTLID35 "Use the lightlid-35mm adapter" +#define M_DESC_LIGHTLID35 "This option turns off the lamp of the" \ + " flatbed during a scan. Do not expect" \ + " excellent results. Maybe this option will" \ + " be removed in the future." + +#define M_NAME_QUALITY_SCAN "quality_scan" +#define M_TITLE_QUALITY_SCAN "Quality scan" +#define M_DESC_QUALITY_SCAN "Highest quality but lower speed" + +#define M_NAME_FAST_SCAN "fast_scan" +#define M_TITLE_FAST_SCAN "Fast scan" +#define M_DESC_FAST_SCAN "Highest speed but lower quality" + +#define M_NAME_AUTOADJUST "lineart-auto-adjust" +#define M_TITLE_AUTOADJUST "Automatic adjustment of threshold value" +#define M_DESC_AUTOADJUST "If checked the backend automatically tries" \ + " to determine an optimal value for the" \ + " threshold." + #define M_NAME_GAMMA_MODE "gamma-correction" #define M_TITLE_GAMMA_MODE "Gamma correction" #define M_DESC_GAMMA_MODE "Selects the gamma correction mode." - + #define M_NAME_GAMMA_BIND "bind-gamma" #define M_TITLE_GAMMA_BIND "Bind gamma" #define M_DESC_GAMMA_BIND "Use same gamma values for all colour channels." @@ -891,6 +694,459 @@ typedef struct Microtek2_Scanner { #define M_DESC_MIDTONE_B "Selects which radiance level should be" \ " considered \"50 % blue\"." +#define M_NAME_BALANCE_R "balance-r" +#define M_TITLE_BALANCE_R "Red balance" +#define M_DESC_BALANCE_R "Balance factor for red. A value of 100% means " \ + "no correction." + +#define M_NAME_BALANCE_G "balance-g" +#define M_TITLE_BALANCE_G "Green balance" +#define M_DESC_BALANCE_G "Balance factor for green. A value of 100% "\ + "means no correction." + +#define M_NAME_BALANCE_B "balance-b" +#define M_TITLE_BALANCE_B "Blue balance" +#define M_DESC_BALANCE_B "Balance factor for blue. A value of 100% means " \ + "no correction. " + +#define M_NAME_BALANCE_FW "balance-fw" +#define M_TITLE_BALANCE_FW "Firmware balance" +#define M_DESC_BALANCE_FW "Sets the color balance values to the "\ + "firmware provided values. "\ + +/******************************************************************************/ +/* Structure that contains global options */ +/******************************************************************************/ + +typedef struct Config_Options +{ + double strip_height; /* inch */ + char *no_backtracking; /* enable/disable option for */ + /* backtracking */ + char *lightlid35; /* enable/disable lightlid35 option */ + char *toggle_lamp; /* enable/disable lightlid35 option */ + char *backend_calibration; /* calibration by backend */ + char *auto_adjust; /* automatically choose threshold */ + char *colorbalance_adjust; /* color balance can be modified */ +} Config_Options; + + + +/******************************************************************************/ +/* Structure that is temporarily used, when the config file is parsed */ +/******************************************************************************/ + +typedef struct Config_Temp +{ + struct Config_Temp *next; + char *device; /* possible device name */ + Config_Options opts; /* options belonging to this device name */ + +} Config_Temp; + + +/******************************************************************************/ +/* scanner hardware info (as discovered by INQUIRY and READ ATTRIBUTES) */ +/******************************************************************************/ + +typedef struct Microtek2_Info { + /* from inquiry */ + SANE_Byte device_qualifier; +#define MI_DEVTYPE_SCANNER 0x06 + SANE_Byte device_type; +#define MI_SCSI_II_VERSION 0x02 + SANE_Byte scsi_version; + SANE_Char vendor[INQ_VENDOR_L + 1]; + SANE_Char model[INQ_MODEL_L + 1]; + SANE_Char revision[INQ_REV_L + 1]; + SANE_Byte model_code; + /* from read scanner attributes */ + SANE_Bool color; +#define MI_HAS_ONEPASS SANE_TRUE + SANE_Bool onepass; + /* the following 3 defines must correspond to byte 31 of SET WINDOW cmd */ +#define MI_TYPE_FLATBED 0x01 +#define MI_TYPE_SHEEDFEED 0x02 +#define MI_TYPE_TRANSPARENCY 0x03 + SANE_Byte scanner_type; +#define MI_HAS_FEPROM SANE_TRUE + SANE_Bool feprom; + /* MI_DATAFMT_X must correspond to Byte 0 in READ SCANNER ATTRIBUTE */ +#define MI_DATAFMT_CHUNKY 1 +#define MI_DATAFMT_LPLCONCAT 2 +#define MI_DATAFMT_LPLSEGREG 3 +#define MI_DATAFMT_WORDCHUNKY 5 + SANE_Byte data_format; +#define MI_COLSEQ_RED 0 +#define MI_COLSEQ_GREEN 1 +#define MI_COLSEQ_BLUE 2 +#define MI_COLSEQ_ILLEGAL 3 + u_int8_t color_sequence[RSA_COLORSEQUENCE_L]; + SANE_Bool new_image_status; +#define MI_DATSEQ_RTOL 1 + u_int8_t direction; + SANE_Byte ccd_gap; + SANE_Int max_xresolution; + SANE_Int max_yresolution; + SANE_Int geo_width; + SANE_Int geo_height; + SANE_Int opt_resolution; +#define MI_HASDEPTH_NIBBLE 1 +#define MI_HASDEPTH_10 2 +#define MI_HASDEPTH_12 4 +#define MI_HASDEPTH_16 8 +#define MI_HASDEPTH_14 16 /*This is not in Byte 13 of + scanner attributes but in + byte 48-bit0*/ + + SANE_Byte depth; +#define MI_LINEART_NONE(d) (((d) & 0x01) == 0) +#define MI_HASMODE_LINEART 1 +#define MI_HASMODE_HALFTONE 2 +#define MI_HASMODE_GRAY 4 +#define MI_HASMODE_COLOR 8 + SANE_Byte scanmode; + SANE_Int ccd_pixels; +#define MI_LUTCAP_NONE(d) ((d) == 0) +#define MI_LUTCAP_256B 1 +#define MI_LUTCAP_1024B 2 +#define MI_LUTCAP_1024W 4 +#define MI_LUTCAP_4096B 8 +#define MI_LUTCAP_4096W 16 +#define MI_LUTCAP_64k_W 32 +#define MI_LUTCAP_16k_W 64 +#define MI_LUTCAP_UNKNOWN 128 + SANE_Byte lut_cap; +#define MI_HAS_DNLDPTRN SANE_TRUE + SANE_Bool has_dnldptrn; + SANE_Byte grain_slct; +#define MI_OPTDEV_ADF 0x01 +#define MI_OPTDEV_TMA 0x02 +#define MI_OPTDEV_ADP 0x10 +#define MI_OPTDEV_APS 0x20 +#define MI_OPTDEV_STRIPE 0x40 +#define MI_OPTDEV_SLIDE 0x80 + SANE_Byte option_device; + SANE_Int calib_white; + SANE_Int calib_space; + SANE_Byte nlens; + SANE_Byte nwindows; + SANE_Byte shtrnsferequ; +#define MI_WHITE_SHADING_ONLY(x) ((x) & 0x20) == 0 +#define MI_HAS_SCNBTTN SANE_TRUE + SANE_Bool scnbuttn; +#define MI_HAS_PIPOBUF SANE_TRUE + SANE_Bool buftype; + u_int16_t balance[3]; /* balance factor for red, green */ + /* and blue data */ + u_int16_t aps_maxframes; + SANE_Int calib_divisor; /* e.g. the X12USL reads and sends */ + /* shading at 1/2 * opt_resolution */ +} Microtek2_Info; + +/******************************************************************************/ +/* device structure (one for each device in config file) */ +/******************************************************************************/ + +typedef struct Microtek2_Device { + struct Microtek2_Device *next; /* next, for linked list */ + +#define MD_SOURCE_FLATBED 0 +#define MD_SOURCE_ADF 1 +#define MD_SOURCE_TMA 2 +#define MD_SOURCE_SLIDE 3 +#define MD_SOURCE_STRIPE 4 + Microtek2_Info info[5]; /* detailed scanner spec */ + SANE_Device sane; /* SANE generic device block */ + char name[PATH_MAX]; /* name from config file */ + + SANE_Int *custom_gamma_table[4]; /* used for the custom gamma */ + /* values before a scan starts */ + /* the following two are derived from lut_cap */ + int max_lut_size; /* in bytes */ + int lut_entry_size; /* word or byte transfer in LUT */ + u_int8_t scan_source; + double revision; + + /* basically the following two variables should go into the */ + /* Microtek2_Scanner structure, but their values must be retained */ + /* over several scans, and would be lost, if the application issues */ + /* a sane_close. */ + u_int8_t *shading_table_w; /* shading table white */ + u_int8_t *shading_table_d; /* shading table dark */ + u_int8_t shading_table_contents; /* values like ms->mode */ + /* the following structure describes the device status */ +#define MD_TLAMP_ON 2 +#define MD_FLAMP_ON 1 +#define MD_NCALIB_ON 4 +#define MD_NTRACK_ON 8 +#define MD_STICK_ON 16 +#define MD_RESERVED17_ON 128 +#define MD_CURRENT_MODE_FLATBED 0 + struct { + u_int8_t sskip; + u_int8_t stick; + u_int8_t ntrack; + u_int8_t ncalib; + u_int8_t tlamp; + u_int8_t flamp; + u_int8_t reserved17; + u_int8_t rdyman; + u_int8_t trdy; + u_int8_t frdy; + u_int8_t adp; + u_int8_t detect; + u_int8_t adptime; + u_int8_t lensstatus; + u_int8_t aloff; + u_int8_t timeremain; + u_int8_t tmacnt; + u_int8_t paper; + u_int8_t adfcnt; + u_int8_t currentmode; + u_int8_t buttoncount; + } status; + + /* The following defines are related to the model. Some models have */ + /* more or less subtle deviations from the spec, which are indicated */ + /* by these defines */ + u_int32_t model_flags; +#define MD_NO_SLIDE_MODE 1 /* indicates that it has slide */ + /* mode, but it does not */ +#define MD_DATA_FORMAT_WRONG 2 /* X6 indicates wrong mode for TMA */ +#define MD_NO_ENHANCEMENTS 4 /* image enhancements do not work */ + /* (Brightness, contrast, .....) */ +#define MD_RII_TWO_BYTES 8 /* return some image information */ + /* in two byte */ +#define MD_NO_GAMMA 16 /* if device does not accept */ + /* gamma tables */ +#define MD_PHANTOM336CX_TYPE_SHADING 32 /* Phantom 336cx type shading */ +#define MD_READ_CONTROL_BIT 64 /* uses "read control bit" */ +#define MD_PHANTOM_C6 128 /* It is a Phantom C6 */ +#define MD_OFFSET_2 256 /* Image data starts 2 bytes */ + /* from the beginning of a */ + /* scanline */ +#define MD_X6_SHORT_TRANSFER 512 /* X6 USB crashes if you read + too much */ +#define MD_NO_RIS_COMMAND 1024 /* doesn't like read_image_status */ + + u_int32_t n_control_bytes; /* for read_control_bits; the */ + /* number is model dependent */ + /* and can not be inquired */ + u_int32_t shading_length; /* length of the shading image */ + /* Phantom 336cx, C6, ... */ + u_int8_t shading_depth; /* bit depth of shading image */ + u_int8_t controlbit_offset; /* first relevant control bit */ + + +#define MD_MODESTRING_NUMS 4 +#define MD_MODESTRING_COLOR "Color" +#define MD_MODESTRING_GRAY "Gray" +#define MD_MODESTRING_HALFTONE "Halftone" +#define MD_MODESTRING_LINEART "LineArt" + SANE_String_Const scanmode_list[MD_MODESTRING_NUMS + 1]; + +#define MD_DEPTHVAL_NUMS 6 +#define MD_DEPTHVAL_16 16 +#define MD_DEPTHVAL_14 14 +#define MD_DEPTHVAL_12 12 +#define MD_DEPTHVAL_10 10 +#define MD_DEPTHVAL_8 8 +#define MD_DEPTHVAL_4 4 + SANE_Int bitdepth_list[MD_DEPTHVAL_NUMS + 1]; + +#define MD_SOURCESTRING_NUMS 5 +#define MD_SOURCESTRING_FLATBED "Flatbed" +#define MD_SOURCESTRING_ADF "ADF" +#define MD_SOURCESTRING_TMA "TMA" +#define MD_SOURCESTRING_STRIPE "Filmstrip" +#define MD_SOURCESTRING_SLIDE "Slide" + SANE_String_Const scansource_list[MD_SOURCESTRING_NUMS + 1]; + +#define MD_HALFTONE_NUMS 12 +#define MD_HALFTONE0 "53-dot screen (53 gray levels)" +#define MD_HALFTONE1 "Horiz. screen (65 gray levels)" +#define MD_HALFTONE2 "Vert. screen (65 gray levels)" +#define MD_HALFTONE3 "Mixed page (33 gray levels)" +#define MD_HALFTONE4 "71-dot screen (29 gray levels)" +#define MD_HALFTONE5 "60-dot #1 (26 gray levels)" +#define MD_HALFTONE6 "60-dot #2 (26 gray levels)" +#define MD_HALFTONE7 "Fine detail #1 (17 gray levels)" +#define MD_HALFTONE8 "Fine detail #2 (17 gray levels)" +#define MD_HALFTONE9 "Slant line (17 gray levels)" +#define MD_HALFTONE10 "Posterizing (10 gray levels)" +#define MD_HALFTONE11 "High Contrast (5 gray levels)" + SANE_String_Const halftone_mode_list[MD_HALFTONE_NUMS + 1]; + +#define MD_CHANNEL_NUMS 4 +#define MD_CHANNEL_MASTER "Master" +#define MD_CHANNEL_RED "Red" +#define MD_CHANNEL_GREEN "Green" +#define MD_CHANNEL_BLUE "Blue" + SANE_String_Const channel_list[MD_CHANNEL_NUMS + 1]; + +#define MD_GAMMAMODE_NUMS 3 +#define MD_GAMMAMODE_LINEAR "None" +#define MD_GAMMAMODE_SCALAR "Scalar" +#define MD_GAMMAMODE_CUSTOM "Custom" + SANE_String_Const gammamode_list[MD_GAMMAMODE_NUMS + 1]; + + SANE_Range x_res_range_dpi; /* X resolution in dpi */ + SANE_Range y_res_range_dpi; /* Y resolution in dpi */ + SANE_Range x_range_mm; /* scan width in mm */ + SANE_Range y_range_mm; /* scan height in mm */ + SANE_Range percentage_range; /* for brightness, shadow, ... */ + SANE_Range custom_gamma_range; /* for custom gamma values */ + SANE_Range scalar_gamma_range; /* for scalar gamma values */ + SANE_Range shadow_range; /* shadow of blue channel */ + SANE_Range midtone_range; /* midtone shadow of blue channel */ + SANE_Range exposure_range; /* for lengthening exposure time */ + SANE_Range highlight_range; /* highlight of master channel */ + SANE_Range threshold_range; /* 1 - 255 */ + SANE_Range balance_range; /* for user provided color balance */ + Config_Options opts; /* options from the config file */ + SANE_Word opt_backend_calib_default; /* corresponds to scanner model */ + SANE_Word opt_no_backtrack_default; /* corresponds to scanner model */ +} Microtek2_Device; + + + +/******************************************************************************/ +/* scanner structure (one for each device in use) */ +/* ....all the state needed to define a scan request */ +/******************************************************************************/ + +typedef struct Microtek2_Scanner { + struct Microtek2_Scanner *next; /* for linked list */ + Microtek2_Device *dev; /* raw device info */ + Microtek2_Option_Value val[NUM_OPTIONS + 1]; /* option values for session */ + SANE_Parameters params; /* format, lastframe, lines, depth, ppl, bpl */ + SANE_Option_Descriptor sod[NUM_OPTIONS + 1]; /* option list for session */ + + u_int8_t *gamma_table; + u_int8_t *shading_image; /* used for shading image */ + u_int8_t *condensed_shading_w; /* used when a model uses "read */ + u_int8_t *condensed_shading_d; /* control bit", stores the relevant */ + /* shading pixels for each color */ + u_int8_t *temporary_buffer; /* used when automatic adjustment */ + /* is selected */ + char *gamma_mode; /* none, linear or custom */ + +/* the following defines must correspond to byte 25 of SET WINDOW body */ +#define MS_MODE_LINEART 0x00 +#define MS_MODE_HALFTONE 0x01 +#define MS_MODE_GRAY 0x02 +#define MS_MODE_LINEARTFAKE 0x12 /* no real mode */ +#define MS_MODE_COLOR 0x05 + +/* the following defines must correspond to byte 31 of SET WINDOW body */ +#define MS_SOURCE_FLATBED 0x00 +#define MS_SOURCE_ADF 0x01 +#define MS_SOURCE_TMA 0x02 +#define MS_SOURCE_STRIPE 0x05 +#define MS_SOURCE_SLIDE 0x06 + + SANE_Int mode; + SANE_Int depth; + SANE_Int x_resolution_dpi; + SANE_Int y_resolution_dpi; + SANE_Int x1_dots; /* x-position in units of optical resolution */ + SANE_Int y1_dots; /* same for y-position */ + SANE_Int width_dots; /* scan width in units of optical resolution */ + SANE_Int height_dots; /* same for height */ + u_int8_t brightness_m; + u_int8_t contrast_m; + u_int8_t exposure_m; + u_int8_t shadow_m; + u_int8_t midtone_m; + u_int8_t highlight_m; + u_int8_t brightness_r; + u_int8_t contrast_r; + u_int8_t exposure_r; + u_int8_t shadow_r; + u_int8_t midtone_r; + u_int8_t highlight_r; + u_int8_t brightness_g; + u_int8_t contrast_g; + u_int8_t exposure_g; + u_int8_t shadow_g; + u_int8_t midtone_g; + u_int8_t highlight_g; + u_int8_t brightness_b; + u_int8_t contrast_b; + u_int8_t exposure_b; + u_int8_t shadow_b; + u_int8_t midtone_b; + u_int8_t highlight_b; + u_int8_t threshold; + + SANE_Bool use_external_ht; + SANE_Byte internal_ht_index; + u_int8_t stay; + u_int8_t rawdat; + SANE_Bool quality; + SANE_Bool fastscan; + SANE_Byte scan_source; + u_int8_t no_backtracking; + u_int8_t lightlid35; + u_int8_t auto_adjust; + u_int8_t calib_backend; + u_int8_t colorbalance_adjust; + int current_pass; /* current pass if 3-pass scan */ + int lut_size; /* size of gamma lookup table */ + int lut_entry_size; /* size of one entry in lookup table */ + u_int16_t lut_size_bytes; /* size of LUT in bytes */ + u_int8_t word; /* word transfer, used in some read cmds */ + /* MS_COLOR_X must correspond to color field in READ IMAGE STATUS */ +#define MS_COLOR_RED 0 +#define MS_COLOR_GREEN 1 +#define MS_COLOR_BLUE 2 +#define MS_COLOR_ALL 3 + u_int8_t current_color; /* for gamma calc. and 3-pass scanners */ + u_int8_t current_read_color; /* dto, for RI and RIS */ + u_int8_t dark; /* is 1 for reading dark shading */ + u_int32_t ppl; /* pixels per line as returned by RII */ + u_int32_t bpl; /* bytes per line as returned by RII */ + u_int32_t remaining_bytes; /* remaining bytes as returned by RII */ + u_int32_t real_remaining_bytes;/* bytes to transfer to the frontend */ + u_int32_t real_bpl; /* bpl to transfer to the frontend */ + SANE_Int src_remaining_lines; /* remaining lines to read */ + SANE_Int src_lines_to_read; /* actual number of lines read */ + SANE_Int src_max_lines; /* maximum number of lines that fit */ + /* into the scsi buffer */ + /* sent to the frontend */ + int bits_per_pixel_in; /* bits per pixel transferred from scanner */ + int bits_per_pixel_out; /* bits per pixel transf. to frontend */ + u_int32_t src_buffer_size; /* size of the buffer */ + int transfer_length; /* transfer length for RI command */ + u_int8_t balance[3]; /* user provided balance factor for */ + /* red, green and blue data */ + struct { + u_int8_t *src_buffer[2]; /* two buffers because of CCD gap */ + u_int8_t *src_buf; + int current_src; + SANE_Int free_lines; + SANE_Int free_max_lines; + u_int8_t *current_pos[3]; /* actual position in the source buffer */ + int planes[2][3]; /* # of red, green, blue planes in the */ + /* current source buffer and leftover */ + /* planes from previous "read image" */ + } buf; + + SANE_Bool onepass; + + u_int32_t n_control_bytes; /* for READ CONTROL BITS */ + u_int8_t *control_bytes; /* pointer to the result */ + + int scanning; /* true == between sane_start & sane_read=EOF */ + int cancelled; + int sfd; /* SCSI filedescriptor */ + int fd[2]; /* file descriptors for pipe */ + pid_t pid; /* pid of child process */ + FILE *fp; + +} Microtek2_Scanner; + /******************************************************************************/ /* Function prototypes */ /******************************************************************************/ @@ -905,13 +1161,25 @@ static SANE_Status attach_one (const char *); static SANE_Status -calculate_gamma(Microtek2_Scanner *, u_int8_t *, int); +auto_adjust_proc_data (Microtek2_Scanner *, u_int8_t **); + +static SANE_Status +calc_cx_shading_line(Microtek2_Scanner *); /* (KF) new */ + +static SANE_Status +calculate_gamma(Microtek2_Scanner *, u_int8_t *, int, char *); + +static SANE_Status +calculate_sane_params(Microtek2_Scanner *); static SANE_Status cancel_scan(Microtek2_Scanner *); static SANE_Status -check_inquiry(Microtek2_Info *, SANE_String *); +check_inquiry(Microtek2_Device *, SANE_String *); + +static void +check_option(const char *, Config_Options *); static SANE_Status chunky_copy_pixels(u_int8_t *, u_int32_t, int, FILE *); @@ -919,23 +1187,46 @@ chunky_copy_pixels(u_int8_t *, u_int32_t, int, FILE *); static SANE_Status chunky_proc_data(Microtek2_Scanner *); +#if 0 +static void +chunky_set_exposure(u_int8_t *, u_int32_t, u_int8_t, u_int8_t, int); +#endif + static void cleanup_scanner(Microtek2_Scanner *); -#if 0 static SANE_Status -do_dummy_scan(Microtek2_Scanner *); +condense_shading(Microtek2_Scanner *); + +#ifdef HAVE_AUTHORIZATION +static SANE_Status +do_authorization(char *); #endif +static SANE_Status +read_shading_image(Microtek2_Scanner *); + static SANE_Status dump_area(u_int8_t *, int, char *); static SANE_Status dump_area2(u_int8_t *, int, char *); +/* currently not used */ +#if 0 +static SANE_Status +dump_to_file(u_int8_t *, int, char *, char *); +#endif + static SANE_Status dump_attributes(Microtek2_Info *); +static void +get_calib_params(Microtek2_Scanner *); + +static SANE_Status +get_cshading_values(Microtek2_Scanner *,u_int8_t, u_int32_t, float, int, + float *, float *); /* (KF) new */ static SANE_Status get_scan_mode_and_depth(Microtek2_Scanner *, int *, SANE_Int *, int *, int *); @@ -946,47 +1237,90 @@ static SANE_Status get_lut_size(Microtek2_Info *, int *, int *); static SANE_Status -init_options(Microtek2_Scanner *, u_int8_t); +gray_copy_pixels(Microtek2_Scanner *ms, u_int8_t *, int, int); static SANE_Status -lplconcat_copy_pixels(u_int8_t **, u_int32_t, int, FILE *); +gray_proc_data(Microtek2_Scanner *); + +#if 0 +static void +gray_set_exposure(u_int8_t *, u_int32_t, u_int8_t, u_int8_t); +#endif + +static SANE_Status +init_options(Microtek2_Scanner *, u_int8_t); static SANE_Status +lineartfake_copy_pixels(Microtek2_Scanner *, u_int8_t *, u_int32_t, u_int8_t, + int, FILE *); + +static SANE_Status +lineartfake_proc_data(Microtek2_Scanner *); + +static SANE_Status +lplconcat_copy_pixels(Microtek2_Scanner *, u_int8_t **, int, int); + +static SANE_Status lplconcat_proc_data(Microtek2_Scanner *ms); static size_t max_string_size (const SANE_String_Const * /* strings[] */); -static SANE_Status -gray_proc_data(Microtek2_Scanner *); +static void +parse_config_file(FILE *, Config_Temp **); -static SANE_Status +static SANE_Status +prepare_buffers(Microtek2_Scanner *); + +static SANE_Status +prepare_shading_data(Microtek2_Scanner *, u_int32_t, u_int8_t **); + +static SANE_Status proc_onebit_data(Microtek2_Scanner *); -static SANE_Status +static SANE_Status +read_cx_shading_image(Microtek2_Scanner *); + +static SANE_Status +read_cx_shading(Microtek2_Scanner *); + +static SANE_Status reader_process(Microtek2_Scanner *); -static SANE_Status +static SANE_Status restore_gamma_options(SANE_Option_Descriptor *, Microtek2_Option_Value *); static SANE_Status -segreg_copy_pixels(u_int8_t **, u_int32_t, int, FILE *); +segreg_copy_pixels(Microtek2_Scanner *); -static SANE_Status +static SANE_Status segreg_proc_data(Microtek2_Scanner *ms); -static SANE_Status -set_option_dependencies(SANE_Option_Descriptor *, Microtek2_Option_Value *); +static void +set_exposure(Microtek2_Scanner *); + +static SANE_Status +set_option_dependencies(Microtek2_Scanner *, + SANE_Option_Descriptor *, Microtek2_Option_Value *); + +static SANE_Status +shading_function(Microtek2_Scanner *, u_int8_t *); static RETSIGTYPE -sigterm_handler (int); +signal_handler (int); static SANE_Status wordchunky_copy_pixels(u_int8_t *, u_int32_t, int, FILE *); static SANE_Status wordchunky_proc_data(Microtek2_Scanner *); - + +typedef int (*qsortfunc)(const void *, const void *); + +static int compare_func_16(const u_int16_t *p1, u_int16_t *p2) + { + return ( *p1 - *p2 ); + } /******************************************************************************/ @@ -999,12 +1333,15 @@ scsi_inquiry(Microtek2_Info *, char *); static SANE_Status scsi_read_attributes(Microtek2_Info *, char *, u_int8_t); +static SANE_Status +scsi_read_control_bits(Microtek2_Scanner *); + /* currently not used */ /* static SANE_Status -scsi_read_gamma(Microtek2_Scanner *, int); */ +scsi_read_gamma(Microtek2_Scanner *); */ static SANE_Status -scsi_read_image(Microtek2_Scanner *); +scsi_read_image(Microtek2_Scanner *, u_int8_t *); static SANE_Status scsi_read_image_info(Microtek2_Scanner *); @@ -1022,6 +1359,12 @@ scsi_request_sense(Microtek2_Scanner *); */ static SANE_Status scsi_send_gamma(Microtek2_Scanner *); +static SANE_Status +scsi_send_shading(Microtek2_Scanner *, u_int8_t *, u_int32_t, u_int8_t); + +static SANE_Status +scsi_read_shading(Microtek2_Scanner *, u_int8_t *, u_int32_t); + static SANE_Status scsi_send_system_status(Microtek2_Device *, int);