diff --git a/ChangeLog b/ChangeLog index 677610e6d..9986a670c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ + +2002-11-23 Rene Rebe + + * backend/avision.h backend/avision.c backend/avision.conf + doc/sane-avision.man: updated the Avisin backend to my todays + snapshot. It know handles more scanners as well as ADF and A3 + size devices. + 2002-11-23 Max Vorobiev * backend/hpsj5s.c: Removed default port probing. diff --git a/backend/avision.c b/backend/avision.c index c9fe74f43..72585ddfc 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -63,9 +63,77 @@ Very much thanks to: Oliver Neukum who sponsored a HP 5300 USB scanner !!! ;-) + Avision INC for sponsoring a AV 8000S with ADF !!! ;-) Avision INC for the documentation we got! ;-) ChangeLog: + 2002-11-23: René Rebe + * added ADF option, implemented line_pack + * option descriptions cleanup + * dynamic data_type_qualifier + * disabled c5_guard + + 2002-11-21/22: René Rebe + * cleanups and more correct set_window + * as well as many other cleanups + + 2002-11-04: René Rebe + * code and comment cleanups, made c5_guard the default + * readded old "Rene" calibration (for tests) + * added old-calibration and disaable-c5-guard config option + * updated avision.conf and avision.man + + 2002-10-30: René Rebe + * readded reject for film-scanner + * added sane-flow from umax.c + + 2002-10-29: René Rebe + * cleanup of reader_process + * fix in set_window + + 2002-10-28: René Rebe + * common debug prints + * simplyfied c5_guard and mofed the call to the right location + + 2002-10-25: René Rebe + * added AV820C Plus ID + * enabled preliminary c5_guard code + + 2002-09-24: René Rebe + * fixed gamma table for AV_ASIC_Cx devices (e.g. AV630C) + * rewrote window computation and review many places where the avdimen + are used + + 2002-09-23: René Rebe + * reenabled line-difference for hp5370c + + 2002-09-22: René Rebe + * cleanups + + 2002-09-21: René Rebe + * more debugging output + * channel by channel feature for normal_calib + + 2002-09-18: René Rebe + * finished first normal and c5 calibration integration + * factoring of the various _sort and read/send calib data helpers + + 2002-09-17: René Rebe + * overworked mojor parts of the code due to updated specs from + Avision + * replaced grey -> gray since the american form is used by SANE + * adapted normal calibration from avision example code + * common code factoring - c5 calibration adaption + + 2002-09-15: René Rebe + * added more inquiry info from new Spec + * improved debug_output_raw, fixed typos + * added calib2 auto-detection + * go_home only for film-scanners (not needed and hangs the AV8000S) + + 2002-09-10: René Rebe + * added "AV8000S" ID + 2002-08-25: René Rebe * added "AV620CS Plus" ID and fixed typo in the .conf file @@ -242,6 +310,31 @@ ********************************************************************************/ +/* SANE-FLOW-DIAGRAMM (from umax.c) + * + * - sane_init() : initialize backend, attach scanners(devicename,0) + * . - sane_get_devices() : query list of scanner-devices + * . - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev) + * . . - sane_set_io_mode : set blocking-mode + * . . - sane_get_select_fd : get scanner-fd + * . . - sane_get_option_descriptor() : get option information + * . . - sane_control_option() : change option values + * . . + * . . - sane_start() : start image aquisition + * . . - sane_get_parameters() : returns actual scan-parameters + * . . - sane_read() : read image-data (from pipe) + * + * in ADF mode this is done often: + * . . - sane_start() : start image aquisition + * . . - sane_get_parameters() : returns actual scan-parameters + * . . - sane_read() : read image-data (from pipe) + * + * . . - sane_cancel() : cancel operation, kill reader_process + * + * . - sane_close() : close opened scanner-device, do_cancel, free buffer and handle + * - sane_exit() : terminate use of backend, free devicename and device-struture + */ + #include #include @@ -273,11 +366,11 @@ #endif #define BACKEND_NAME avision -#define BACKEND_BUILD 37 /* avision backend BUILD version */ +#define BACKEND_BUILD 54 /* avision backend BUILD version */ -static Avision_HWEntry Avision_Device_List [] = +static Avision_HWEntry Avision_Device_List [] = { - /* All Avision except 630, 620 and 6240 untested ... */ + /* All Avision except 630*, 620*, 6240 and 8000 untested ... */ { "AVISION", "AV100CS", "Avision", "AV100CS", @@ -335,6 +428,10 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV6240", AV_SCSI, AV_FLATBED, 0}, + {"AVISION", "AV600U", + "Avision", "AV600U", + AV_USB, AV_FLATBED, 0}, /* c5 calib */ + { "AVISION", "AV660S", "Avision", "AV660S", AV_SCSI, AV_FLATBED, 0}, @@ -343,6 +440,10 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV680S", AV_SCSI, AV_FLATBED, 0}, + {"AVISION", "AV690U", + "Avision", "AV690U", + AV_USB, AV_FLATBED, 0}, /* c5 calib */ + { "AVISION", "AV800S", "Avision", "AV800S", AV_SCSI, AV_FLATBED, 0}, @@ -359,6 +460,18 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV820C", AV_SCSI, AV_FLATBED, 0}, + { "AVISION", "AV820C Plus", + "Avision", "AV820C Plus", + AV_SCSI, AV_FLATBED, 0}, + + {"AVISION", "AV830C", + "Avision", "AV830C", + AV_SCSI, AV_FLATBED, 0}, + + {"AVISION", "AV830C Plus", + "Avision", "AV830C Plus", + AV_SCSI, AV_FLATBED, 0}, + { "AVISION", "AV880", "Avision", "AV880", AV_SCSI, AV_FLATBED, 0}, @@ -367,6 +480,10 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV880C", AV_SCSI, AV_FLATBED, 0}, + { "AVISION", "AV8000S", + "Avision", "AV8000S", + AV_SCSI, AV_FLATBED, 0}, + { "AVISION", "AVA3", "Avision", "AVA3", AV_SCSI, AV_FLATBED, 0}, @@ -379,12 +496,12 @@ static Avision_HWEntry Avision_Device_List [] = { "HP", "ScanJet 5370C", "Hewlett-Packard", "ScanJet 5370C", - AV_USB, AV_FLATBED, AV_CALIB2 | AV_GAMMA3}, + AV_USB, AV_FLATBED, 0}, /* AV_NO_LINE_DIFFERENCE */ /* The HP 7450c seems to use the same ID */ { "hp", "scanjet 7400c", "Hewlett-Packard", "ScanJet 7400c", - AV_USB, AV_FLATBED, AV_CALIB2 | AV_GAMMA2}, + AV_USB, AV_FLATBED, AV_LIGHT_CHECK_BOGUS}, /* needs firmware and possibly more adaptions */ /*{"UMAX", "Astra 4500", AV_USB, AV_FLATBED, 0}, @@ -477,7 +594,8 @@ static Avision_HWEntry Avision_Device_List [] = #define AVISION_CONFIG_FILE "avision.conf" -#define MM_PER_INCH (25.4) +#define MM_PER_INCH 25.4 +#define AVISION_BASE_RES 300 static int num_devices; static Avision_Device* first_dev; @@ -486,13 +604,22 @@ static const SANE_Device** devlist = 0; /* disable the usage of a custom gamma-table */ static SANE_Bool disable_gamma_table = SANE_FALSE; + /* disable the calibration */ static SANE_Bool disable_calibration = SANE_FALSE; + +/* use old "Rene" calibration method (for tests) */ +static SANE_Bool old_calibration = SANE_FALSE; + /* do only one claibration per backend initialization */ static SANE_Bool one_calib_only = SANE_FALSE; + /* force scanable areas to ISO(DIN) A4 */ static SANE_Bool force_a4 = SANE_FALSE; +/* disable normally needed c5 guard */ +static SANE_Bool disable_c5_guard = SANE_FALSE; + static const SANE_String_Const mode_list[] = { "Line Art", "Dithered", "Gray", "Color", 0 @@ -543,11 +670,35 @@ static const u_int8_t get_status[] = 0x00, 0x00, 0x0c, 0x00 }; -static void debug_output_raw (int dbg_level, u_int8_t* data, size_t count) +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + int i; + + DBG (3, "max_string_size:\n"); + + for (i = 0; strings[i]; ++ i) { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + return max_size; +} + +static SANE_Status +constrain_value (Avision_Scanner *s, SANE_Int option, void *value, + SANE_Int *info) +{ + DBG (3, "constrain_value:\n"); + return sanei_constrain_value (s->opt + option, value, info); +} + +static void debug_print_raw (int dbg_level, char* info, u_int8_t* data, size_t count) { size_t i; - DBG (dbg_level, "RAW-Data:\n"); + DBG (dbg_level, info); for (i = 0; i < count; ++ i) { DBG (6, " [%d] %1d%1d%1d%1d%1d%1d%1d%1db %3oo %3dd %2xx\n", i, @@ -557,34 +708,227 @@ static void debug_output_raw (int dbg_level, u_int8_t* data, size_t count) } } -static int make_mode (char* mode) +static void debug_print_avdimen (int dbg_level, char* func, Avision_Dimensions* avdimen) { - DBG (3, "make_mode\n"); + DBG (dbg_level, "%s: tlx: %ld, tly: %ld, brx: %ld, bry: %ld\n", + func, avdimen->tlx, avdimen->tly, + avdimen->brx, avdimen->bry); + DBG (dbg_level, "%s: width: %ld, height: %ld\n", + func, avdimen->width, avdimen->height); + DBG (dbg_level, "%s: res: %d, line_difference: %d\n", + func, avdimen->res, avdimen->line_difference); +} + +static void debug_print_params (int dbg_level, char* func, SANE_Parameters* params) +{ + DBG (dbg_level, "%s: pixel_per_line: %d, lines: %d\n", + func, params->pixels_per_line, params->lines); + + DBG (dbg_level, "%s: depth: %d, bytes_per_line: %d\n", + func, params->depth, params->bytes_per_line); +} + +static void debug_print_calib_format (int dbg_level, char* func, + u_int8_t* result) +{ + debug_print_raw (dbg_level + 2, "debug_print_calib_format:", result, 32); + DBG (dbg_level, "%s: [0-1] pixels per line %d\n", + func, (result[0]<<8)+result[1]); + DBG (dbg_level, "%s: [2] bytes per channel %d\n", func, result[2]); + DBG (dbg_level, "%s: [3] line count %d\n", func, result[3]); + + DBG (dbg_level, "%s: [4] FLAG:%s%s%s\n", + func, + result[4] == 1?" MUST_DO_CALIBRATION":"", + result[4] == 2?" SCAN_IMAGE_DOES_CALIBRATION":"", + result[4] == 3?" NEEDS_NO_CALIBRATION":""); + + DBG (dbg_level, "%s: [5] Ability1:%s%s%s%s%s%s%s%s\n", + func, + BIT(result[5],7)?" NONE_PACKED":" PACKED", + BIT(result[5],6)?" INTERPOLATED":"", + BIT(result[5],5)?" SEND_REVERSED":"", + BIT(result[5],4)?" PACKED_DATA":"", + BIT(result[5],3)?" COLOR_CALIB":"", + BIT(result[5],2)?" DARK_CALIB":"", + BIT(result[5],1)?" NEEDS_WHITE_BLACK_SHADING_DATA":"", + BIT(result[5],0)?" NEEDS_CALIB_TABLE_CHANNEL_BY_CHANNEL":""); + + DBG (dbg_level, "%s: [6] R gain: %d\n", func, result[6]); + DBG (dbg_level, "%s: [7] G gain: %d\n", func, result[7]); + DBG (dbg_level, "%s: [8] B gain: %d\n", func, result[8]); +} + +static void debug_print_window_descriptor (int dbg_level, char* func, + command_set_window_window_descriptor* window) +{ + DBG (dbg_level, "%s: [0] window_id %d\n", func, window->winid); + DBG (dbg_level, "%s: [2-3] x-axis res %d\n", func, get_double (window->xres)); + DBG (dbg_level, "%s: [4-5] y-axis res %d\n", func, get_double (window->yres)); + DBG (dbg_level, "%s: [6-9] x-axis upper left %d\n", func, get_quad (window->ulx)); + DBG (dbg_level, "%s: [10-13] y-axis upper left %d\n", func, get_quad (window->uly)); + DBG (dbg_level, "%s: [14-17] window width %d\n", func, get_quad (window->width)); + DBG (dbg_level, "%s: [18-21] window length %d\n", func, get_quad (window->length)); + DBG (dbg_level, "%s: [22] brightness %d\n", func, window->brightness); + DBG (dbg_level, "%s: [23] threshold %d\n", func, window->threshold); + DBG (dbg_level, "%s: [24] contrast %d\n", func, window->contrast); + DBG (dbg_level, "%s: [25] image composition %x\n", func, window->image_comp); + DBG (dbg_level, "%s: [26] bits per channel %d\n", func, window->bpc); + DBG (dbg_level, "%s: [27-28] halftone pattern %x\n", func, get_double (window->halftone)); + DBG (dbg_level, "%s: [29] padding_and_bitset %x\n", func, window->padding_and_bitset); + DBG (dbg_level, "%s: [30-31] bit ordering %x\n", func, get_double (window->bitordering)); + DBG (dbg_level, "%s: [32] compression type %x\n", func, window->compr_type); + DBG (dbg_level, "%s: [33] compression argument %x\n", func, window->compr_arg); + DBG (dbg_level, "%s: [40] vendor id %x\n", func, window->vendor_specid); + DBG (dbg_level, "%s: [41] param lenght %d\n", func, window->paralen); + DBG (dbg_level, "%s: [42] bitset %x\n", func, window->bitset1); + DBG (dbg_level, "%s: [43] highlight %d\n", func, window->highlight); + DBG (dbg_level, "%s: [44] shadow %d\n", func, window->shadow); + DBG (dbg_level, "%s: [45-46] line-width %d\n", func, get_double (window->linewidth)); + DBG (dbg_level, "%s: [47-48] line-count %d\n", func, get_double (window->linecount)); + DBG (dbg_level, "%s: [49] bitset %x\n", func, window->bitset2); + DBG (dbg_level, "%s: [50] ir exposure time %d\n", func, window->ir_exposure_time); + + DBG (dbg_level, "%s: [51-52] r exposure %d\n", func, get_double (window->r_exposure_time)); + DBG (dbg_level, "%s: [53-54] g exposure %d\n", func, get_double (window->g_exposure_time)); + DBG (dbg_level, "%s: [55-56] b exposure %d\n", func, get_double (window->b_exposure_time)); + + DBG (dbg_level, "%s: [57] bitset %x\n", func, window->bitset3); + DBG (dbg_level, "%s: [58] auto focus %d\n", func, window->auto_focus); + DBG (dbg_level, "%s: [59] line-widht (MSB) %d\n", func, window->line_width_msb); + DBG (dbg_level, "%s: [60] line-count (MSB) %d\n", func, window->line_count_msb); + DBG (dbg_level, "%s: [61] edge threshold %d\n", func, window->edge_threshold); +} + +static +SANE_Status simple_read (Avision_Scanner *s, + u_int8_t data_type_code, u_int8_t read_type, + size_t* size, u_int8_t* result) +{ + SANE_Status status; + + struct command_read rcmd; + memset (&rcmd, 0, sizeof (rcmd)); + + rcmd.opc = AVISION_SCSI_READ; + rcmd.datatypecode = data_type_code; + rcmd.readtype = read_type; + set_double (rcmd.datatypequal, s->hw->data_dq); + set_triple (rcmd.transferlen, *size); + + DBG (3, "simple_read: size: %d\n", *size); + + status = sanei_scsi_cmd (s->fd, &rcmd, sizeof(rcmd), result, size); + return status; +} + +#ifdef IS_WRITTEN +static +SANE_Status simple_send (Avision_Scanner *s, + u_int8_t data_type_code, u_int8_t read_type, + u_int16_t data_type_qual, + size_t* size, u_int8_t* result) +{ +} +#endif + +/* a bubble sort for the calibration - which returns an average */ +static u_int16_t +bubble_sort (u_int16_t* sort_data, size_t count) +{ + size_t i, j, k, limit; + u_int64_t sum = 0; + u_int16_t temp; + + limit = count / 3; + + for (i = 0; i < limit; ++i) + for (j = (i + 1); j < count; ++j) + if (sort_data[i] > sort_data[j]) { + temp = sort_data[i]; + sort_data[i] = sort_data[j]; + sort_data[j] = temp; + } + + for (k = 0, i = limit; i < count; ++i) { + sum += sort_data[i]; + ++k; + } + + if (k > 0) /* if avg to compute */ + return (u_int16_t) (sum / k); + else + return (u_int16_t) (sum); +} + +/* a bubble sort for the calibration, + which writes an average into the first field */ +static void +bubble_sort2 (u_int16_t* sort_data, size_t count) +{ + sort_data[0] = bubble_sort (sort_data, count); +} + +static int +make_mode (char* mode) +{ + DBG (3, "make_mode:\n"); + if (strcmp (mode, "Line Art") == 0) return THRESHOLDED; if (strcmp (mode, "Dithered") == 0) return DITHERED; else if (strcmp (mode, "Gray") == 0) - return GREYSCALE; + return GRAYSCALE; else if (strcmp (mode, "Color") == 0) return TRUECOLOR; - + return -1; } +static int +get_pixel_boundary (Avision_Scanner* s) +{ + Avision_Device* dev = s->hw; + int boundary; + + switch (s->mode) { + case TRUECOLOR: + boundary = dev->inquiry_color_boundary; + break; + case GRAYSCALE: + boundary = dev->inquiry_gray_boundary; + break; + case DITHERED: + if (dev->inquiry_asic_type != AV_ASIC_C5) + boundary = 32; + else + boundary = dev->inquiry_dithered_boundary; + break; + case THRESHOLDED: + if (dev->inquiry_asic_type != AV_ASIC_C5) + boundary = 32; + else + boundary = dev->inquiry_thresholded_boundary; + break; + default: + boundary = 8; + } + + return boundary; +} + static SANE_Status sense_handler (int fd, u_char* sense, void* arg) { - int i; - SANE_Status status; SANE_Bool ASC_switch = SANE_FALSE; fd = fd; /* silence gcc */ arg = arg; /* silence gcc */ - DBG (3, "sense_handler\n"); + DBG (3, "sense_handler:\n"); switch (sense[0]) { @@ -596,10 +940,7 @@ sense_handler (int fd, u_char* sense, void* arg) status = SANE_STATUS_IO_ERROR; } - for (i = 0; i < 21; ++ i) - { - DBG (1, "%d:[%x]\n", i, sense[i]); - } + debug_print_raw (1, "sense_handler: data:\n", sense, 20); if (sense[VALID_BYTE] & VALID) { @@ -877,29 +1218,36 @@ wait_ready (int fd) static SANE_Status wait_4_light (Avision_Scanner *s) { + Avision_Device* dev = s->hw; + /* read stuff */ struct command_read rcmd; - char* light_status[] = { "off", "on", "warming up", "needs warm up test", - "light check error", "RESERVED" }; + char* light_status[] = + { "off", "on", "warming up", "needs warm up test", + "light check error", "RESERVED" }; SANE_Status status; u_int8_t result; int try; size_t size = 1; - DBG (3, "getting light status.\n"); + if (!dev->inquiry_light_control) { + DBG (3, "wait_4_light: scanner doesn't support light control.\n"); + return SANE_STATUS_GOOD; + } + + DBG (3, "wait_4_light: getting light status.\n"); memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0xa0; /* get light status */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - DBG (5, "read_data: bytes %d\n", size); - - for (try = 0; try < 10; ++ try) { + for (try = 0; try < 18; ++ try) { + + DBG (5, "wait_4_light: read bytes %d\n", size); status = sanei_scsi_cmd (s->fd, &rcmd, sizeof (rcmd), &result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { @@ -907,13 +1255,38 @@ wait_4_light (Avision_Scanner *s) return status; } - DBG (3, "Light status: command is %d. Result is %s\n", + DBG (3, "wait_4_light: command is %d. Result is %s\n", status, light_status[(result>4)?5:result]); if (result == 1) { return SANE_STATUS_GOOD; } - + else if (dev->hw->feature_type & AV_LIGHT_CHECK_BOGUS) { + DBG (3, "wait_4_light: scanner marked as returning bogus values in device-list!!\n"); + return SANE_STATUS_GOOD; + } + else { + struct command_send scmd; + u_int8_t light_on = 1; + + /*turn on the light */ + DBG (3, "wait_4_light: setting light status.\n"); + + memset (&scmd, 0, sizeof (scmd)); + + scmd.opc = AVISION_SCSI_SEND; + scmd.datatypecode = 0xa0; /* send light status */ + set_double (scmd.datatypequal, dev->data_dq); + set_triple (scmd.transferlen, size); + + status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), + &light_on, sizeof (light_on), 0, 0); + + if (status != SANE_STATUS_GOOD) { + DBG (1, "wait_4_light: send failed (%s)\n", sane_strstatus (status)); + return status; + } + } sleep (1); } @@ -922,29 +1295,56 @@ wait_4_light (Avision_Scanner *s) return SANE_STATUS_GOOD; } -static size_t -max_string_size (const SANE_String_Const strings[]) +/* C5 hardware scaling parameter. Code by Avision. + Scan width and length base dpi is not always 1200 dpi. + Be carefull! */ + +static void +c5_guard (Avision_Scanner* s) { - size_t size, max_size = 0; - int i; - - DBG (3, "max_string_size\n"); - - for (i = 0; strings[i]; ++ i) - { - size = strlen (strings[i]) + 1; - if (size > max_size) - max_size = size; - } - return max_size; -} - -static SANE_Status -constrain_value (Avision_Scanner *s, SANE_Int option, void *value, - SANE_Int *info) -{ - DBG (3, "constrain_value\n"); - return sanei_constrain_value (s->opt + option, value, info); + Avision_Device* dev = s->hw; + + int base_dpi = s->avdimen.res - s->avdimen.res % 300; + int weight, n_width, n_height; + + int gray_mode = (s->mode == TRUECOLOR) || (s->mode == GRAYSCALE); + int boundary = get_pixel_boundary (s); + + /* For fix C5 lineart bug. */ + if (!gray_mode) { + DBG (1, "c5_guard: not gray mode -> boundary = 1\n"); + boundary = 1; + } + + if (base_dpi > dev->inquiry_optical_res) + base_dpi = dev->inquiry_optical_res; + else if (s->avdimen.res <= 150) + base_dpi = 150; + DBG (1, "c5_guard: base_dpi = %d\n", base_dpi); + + weight = (double)base_dpi * 256 / s->avdimen.res; + DBG (1, "c5_guard: weight = %d\n", weight); + + n_width = (256 * (s->avdimen.width - 1) + (weight - 1) ) / weight; + DBG (1, "c5_guard: n_width = %d\n", n_width); + + n_height = (256 * (s->avdimen.height - 1) + (weight - 1) ) / weight; + DBG (1, "c5_guard: n_height = %d\n", n_height); + +#ifdef THIS_IS_NEEDED + if (!gray_mode) { /* single bit mode */ + s->avdimen.width = new_width; + s->avdimen.brx = s->avdimen.tlx + s->avdimen.width; + } +#endif + + /* overwrite with corrected values */ + s->params.lines = n_width; + s->params.pixels_per_line = n_height; + + DBG (1, "c5_guard: Parameters after C5 guard:\n"); + debug_print_avdimen (1, "c5_guard", &s->avdimen); + debug_print_params (1, "c5_guard", &s->params); } static SANE_Status @@ -964,8 +1364,7 @@ get_accessories_info (int fd, SANE_Bool *adf, SANE_Bool *light_box) rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x64; /* detect accessories */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + set_double (rcmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (rcmd.transferlen, size); status = sanei_scsi_cmd (fd, &rcmd, sizeof (rcmd), result, &size); @@ -975,11 +1374,15 @@ get_accessories_info (int fd, SANE_Bool *adf, SANE_Bool *light_box) return (status); } - debug_output_raw (6, result, size); + debug_print_raw (6, "get_accessories_info: raw data:\n", result, size); DBG (3, "get_accessories_info: [0] ADF: %x\n", result [0]); DBG (3, "get_accessories_info: [1] Light Box: %x\n", result [1]); + DBG (3, "get_accessories_info: [2] Bitfield1:%s%s\n", + BIT(result[39],0)?" Origami ADF":"", + BIT(result[39],1)?" Oodles ADF":""); + *adf = result [0]; *light_box = result [1]; @@ -998,7 +1401,7 @@ get_frame_info (int fd, int *number_of_frames, int *frame, int *holder_type) frame = frame; /* silence gcc */ - DBG (3, "get_frame_info\n"); + DBG (3, "get_frame_info:\n"); size = sizeof (result); @@ -1006,8 +1409,7 @@ get_frame_info (int fd, int *number_of_frames, int *frame, int *holder_type) rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x87; /* film holder sense */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + set_double (rcmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (rcmd.transferlen, size); status = sanei_scsi_cmd (fd, &rcmd, sizeof (rcmd), result, &size); @@ -1016,7 +1418,7 @@ get_frame_info (int fd, int *number_of_frames, int *frame, int *holder_type) return (status); } - debug_output_raw (6, result, size); + debug_print_raw (6, "get_frame_info: raw data\n", result, size); DBG (3, "get_frame_info: [0] Holder type: %s\n", (result[0]==1)?"APS": @@ -1070,7 +1472,7 @@ set_frame (Avision_Scanner* s, SANE_Word frame) } /* Better check the current status of the film holder, because it - can be changde between scans. */ + can be changed between scans. */ status = get_frame_info (s->fd, &dev->frame_range.max, &dev->current_frame, &dev->holder_type); @@ -1225,7 +1627,7 @@ attach (const char* devname, Avision_Device** devp) dev->is_calibrated = SANE_FALSE; - debug_output_raw (6, result, sizeof (result) ); + debug_print_raw (6, "attach: raw data:\n", result, sizeof (result) ); DBG (3, "attach: [8-15] Vendor id.: \"%8.8s\"\n", result+8); DBG (3, "attach: [16-31] Product id.: \"%16.16s\"\n", result+16); @@ -1239,7 +1641,7 @@ attach (const char* devname, Avision_Device** devp) BIT(i, 2)?" 1-pass color":"", BIT(i, 2) && BIT(i, 0) ?" 1-pass color (ScanPartner only)":"", BIT(result[36],3)?" IS_NOT_FLATBED:":"", - (result[36] & 0x7) == 0 ? " RGB_COLOR_PLANE":"RESERVED?"); + (result[36] & 0x7) == 0 ? " RGB_COLOR_PLANE":" RESERVED?"); DBG (3, "attach: [37] Optical res.: %d00 dpi\n", result[37]); DBG (3, "attach: [38] Maximum res.: %d00 dpi\n", result[38]); @@ -1258,8 +1660,8 @@ attach (const char* devname, Avision_Device** devp) DBG (3, "attach: [48-49] USB max read: %d\n", (result[48]<<8)+result[49]); DBG (3, "attach: [50] ESA1:%s%s%s%s%s%s%s%s\n", - BIT(result[50],7)?" LIGHT":"", - BIT(result[50],6)?" BUTTON":"", + BIT(result[50],7)?" LIGHT_CONTROL":"", + BIT(result[50],6)?" BUTTON_CONTROL":"", BIT(result[50],5)?" NEED_SW_COLORPACK":"", BIT(result[50],4)?" SW_CALIB":"", BIT(result[50],3)?" NEED_SW_GAMMA":"", @@ -1269,15 +1671,16 @@ attach (const char* devname, Avision_Device** devp) DBG (3, "attach: [51] ESA2:%s%s%s%s%s%s%s%s\n", BIT(result[51],7)?" EXPOSURE_CTRL":"", BIT(result[51],6)?" NEED_SW_TRIGGER_CAL":"", - BIT(result[51],5)?" NEED_WHITE_PAPER":"", - BIT(result[51],4)?" SUPP_QUALITY_SPEED_CAL":"", + BIT(result[51],5)?" NEED_WHITE_PAPER_CALIB":"", + BIT(result[51],4)?" SUPPORTS_QUALITY_SPEED_CAL":"", BIT(result[51],3)?" NEED_TRANSP_CAL":"", BIT(result[51],2)?" HAS_PUSH_BUTTON":"", - BIT(result[51],1)?" NEW_CAL_METHOD":"", - BIT(result[51],0)?" ADF_MIRRORS":""); - DBG (3, "attach: [52] ESA3:%s%s%s%s%s%s%s\n", + BIT(result[51],1)?" NEW_CAL_METHOD_3x3_MATRIX_(NO_GAMMA_TABLE)":"", + BIT(result[51],0)?" ADF_MIRRORS_IMAGE":""); + DBG (3, "attach: [52] ESA3:%s%s%s%s%s%s%s%s\n", BIT(result[52],7)?" GRAY_WHITE":"", - BIT(result[52],5)?" TET":"", /* huh ?!? */ + BIT(result[52],6)?" SUPPORTS_GAIN_CONTROL":"", + BIT(result[52],5)?" SUPPORTS_TET":"", /* huh ?!? */ BIT(result[52],4)?" 3x3COL_TABLE":"", BIT(result[52],3)?" 1x3FILTER":"", BIT(result[52],2)?" INDEX_COLOR":"", @@ -1287,8 +1690,8 @@ attach (const char* devname, Avision_Device** devp) /* print some more scanner features/params */ DBG (3, "attach: [53] line difference (software color pack): %d\n", result[53]); DBG (3, "attach: [54] color mode pixel boundary: %d\n", result[54]); - DBG (3, "attach: [55] grey mode pixel boundary: %d\n", result[55]); - DBG (3, "attach: [56] 4bit grey mode pixel boundary: %d\n", result[56]); + DBG (3, "attach: [55] gray mode pixel boundary: %d\n", result[55]); + DBG (3, "attach: [56] 4bit gray mode pixel boundary: %d\n", result[56]); DBG (3, "attach: [57] lineart mode pixel boundary: %d\n", result[57]); DBG (3, "attach: [58] halftone mode pixel boundary: %d\n", result[58]); DBG (3, "attach: [59] error-diffusion mode pixel boundary: %d\n", result[59]); @@ -1306,10 +1709,10 @@ attach (const char* devname, Avision_Device** devp) BIT(result[61],1)?" 16":""); DBG (3, "attach: [62] scanner type:%s%s%s%s%s\n", - BIT(result[62],7)?" Flatbed (w.o. ADF?)":"", /* not really in spec but resonable */ + BIT(result[62],7)?" Flatbed (w.o.? ADF)":"", BIT(result[62],6)?" Roller (ADF)":"", BIT(result[62],5)?" Flatbed (ADF)":"", - BIT(result[62],4)?" Roller scanner (w.o. ADF)":"", + BIT(result[62],4)?" Roller (w.o. ADF)":"", BIT(result[62],3)?" Film scanner":""); DBG (3, "attach: [77-78] Max X of transparency: %d FUBA\n", (result[77]<<8)+result[78]); @@ -1324,45 +1727,66 @@ attach (const char* devname, Avision_Device** devp) DBG (3, "attach: [89-90] Res. in Ex. mode: %d dpi\n", (result[89]<<8)+result[90]); + DBG (3, "attach: [91] ASIC: %d\n", result[91]); + DBG (3, "attach: [92] Buttons: %d\n", result[92]); DBG (3, "attach: [93] ESA4:%s%s%s%s%s%s%s%s\n", - BIT(result[93],7)?" SUPP_ACCESSORIES_DETECT":"", + BIT(result[93],7)?" SUPPORTS_ACCESSORIES_DETECT":"", BIT(result[93],6)?" ADF_IS_BGR_ORDERED":"", BIT(result[93],5)?" NO_SINGLE_CHANNEL_GRAY_MODE":"", - BIT(result[93],4)?" SUPP_FLASH_UPDATE":"", - BIT(result[93],3)?" SUPP_ASIC_UPDATE":"", - BIT(result[93],2)?" SUPP_LIGHT_DETECT":"", - BIT(result[93],1)?" SUPP_READ_PRNU_DATA":"", - BIT(result[93],0)?" SCAN_FLATBED_MIRRORED":""); + BIT(result[93],4)?" SUPPORTS_FLASH_UPDATE":"", + BIT(result[93],3)?" SUPPORTS_ASIC_UPDATE":"", + BIT(result[93],2)?" SUPPORTS_LIGHT_DETECT":"", + BIT(result[93],1)?" SUPPORTS_READ_PRNU_DATA":"", + BIT(result[93],0)?" FLATBED_MIRRORS_IMAGE":""); - /* if (BIT(result[62],3) ) { */ /* most scanners report film functionallity ... */ - switch(dev->hw->scanner_type) { + DBG (3, "attach: [94] ESA5:%s%s%s%s%s\n", + BIT(result[94],7)?" IGNORE_LINE_DIFFERENCE_FOR_ADF":"", + BIT(result[94],6)?" NEEDS_SW_LINE_COLOR_PACK":"", + BIT(result[94],5)?" SUPPORTS_DUPLEX_SCAN":"", + BIT(result[94],4)?" INTERLACE_DUPLEX_SCAN":"", + BIT(result[94],3)?" SUPPORTS_TWO_MODE_ADF_SCANS":""); + + /* if (BIT(result[62],3) ) */ + switch (dev->hw->scanner_type) { case AV_FLATBED: - dev->sane.type = "flatbed scanner"; + dev->sane.type = "flatbed scanner"; break; case AV_FILM: - dev->sane.type = "film scanner"; + dev->sane.type = "film scanner"; break; case AV_SHEETFEED: - dev->sane.type = "sheetfed scanner"; + dev->sane.type = "sheetfed scanner"; break; } + dev->inquiry_asic_type = (int) result[91]; + dev->inquiry_adf = (SANE_Bool) BIT (result[62], 5); + dev->inquiry_new_protocol = BIT (result[39],2); dev->inquiry_detect_accessories = BIT(result[93],7); dev->inquiry_needs_calibration = BIT (result[50],4); - dev->inquiry_needs_gamma = BIT (result[50],3); - dev->inquiry_needs_software_colorpack = BIT (result[50],5); + dev->inquiry_needs_gamma = BIT (result[50],3); + dev->inquiry_3x3_matrix = BIT (result[52], 4); + dev->inquiry_needs_software_colorpack = BIT (result[50],5); + dev->inquiry_needs_line_pack = BIT (result[94], 6); + dev->inquiry_adf_need_mirror = BIT (result[51], 0); + + dev->inquiry_light_detect = BIT (result[93], 2); + dev->inquiry_light_control = BIT (result[50], 7); + + dev->inquiry_max_shading_target = (result[75] << 8) + result[76]; + dev->inquiry_color_boundary = result[54]; if (dev->inquiry_color_boundary == 0) - dev->inquiry_color_boundary = 4; + dev->inquiry_color_boundary = 8; - dev->inquiry_grey_boundary = result[55]; - if (dev->inquiry_grey_boundary == 0) - dev->inquiry_grey_boundary = 4; + dev->inquiry_gray_boundary = result[55]; + if (dev->inquiry_gray_boundary == 0) + dev->inquiry_gray_boundary = 8; dev->inquiry_dithered_boundary = result[59]; if (dev->inquiry_dithered_boundary == 0) @@ -1374,11 +1798,17 @@ attach (const char* devname, Avision_Device** devp) dev->inquiry_line_difference = result[53]; - switch(dev->hw->scanner_type) { - case AV_FLATBED: - case AV_SHEETFEED: + if (dev->inquiry_new_protocol) { + dev->inquiry_optical_res = (result[89] << 8) + result[90]; + dev->inquiry_max_res = (result[44] << 8) + result[45]; + } + else { dev->inquiry_optical_res = result[37] * 100; - if (dev->inquiry_optical_res == 0) { + dev->inquiry_max_res = result[38] * 100; + } + + if (dev->inquiry_optical_res == 0) + { if (dev->hw->scanner_type == AV_SHEETFEED) { DBG (1, "Inquiry optical resolution is invalid, using 300 dpi (sf)!\n"); dev->inquiry_optical_res = 300; @@ -1388,28 +1818,20 @@ attach (const char* devname, Avision_Device** devp) dev->inquiry_optical_res = 600; } } - dev->inquiry_max_res = result[38] * 100; - if (dev->inquiry_max_res == 0) { - DBG (1, "Inquiry max resolution is invalid, using 1200 dpi!\n"); - dev->inquiry_max_res = 1200; - } - break; - case AV_FILM: - { - int opt_x = (result[44]<<8) + result[45]; - int opt_y = (result[46]<<8) + result[47]; - dev->inquiry_optical_res = (opt_x < opt_y) ? opt_x : opt_y; - dev->inquiry_max_res = dev->inquiry_optical_res; - DBG (1, "attach: optical resolution set to: %d dpi\n", dev->inquiry_optical_res); - } + if (dev->inquiry_max_res == 0) { + DBG (1, "Inquiry max resolution is invalid, using 1200 dpi!\n"); + dev->inquiry_max_res = 1200; } + DBG (1, "attach: optical resolution set to: %d dpi\n", dev->inquiry_optical_res); + DBG (1, "attach: max resolution set to: %d dpi\n", dev->inquiry_max_res); + /* Get max X and max Y ... */ dev->inquiry_x_range = ( ( (unsigned int)result[81] << 8) + (unsigned int)result[82] ) * MM_PER_INCH; dev->inquiry_y_range = ( ( (unsigned int)result[83] << 8) + (unsigned int)result[84] ) * MM_PER_INCH; - + dev->inquiry_adf_x_range = ( ( (unsigned int)result[85] << 8) + (unsigned int)result[86] ) * MM_PER_INCH; dev->inquiry_adf_y_range = ( ( (unsigned int)result[87] << 8) @@ -1421,12 +1843,12 @@ attach (const char* devname, Avision_Device** devp) + (unsigned int)result[80] ) * MM_PER_INCH; if (dev->hw->scanner_type != AV_FILM) { - dev->inquiry_x_range /= 300; - dev->inquiry_y_range /= 300; - dev->inquiry_adf_x_range /= 300; - dev->inquiry_adf_y_range /= 300; - dev->inquiry_transp_x_range /= 300; - dev->inquiry_transp_y_range /= 300; + dev->inquiry_x_range /= AVISION_BASE_RES; + dev->inquiry_y_range /= AVISION_BASE_RES; + dev->inquiry_adf_x_range /= AVISION_BASE_RES; + dev->inquiry_adf_y_range /= AVISION_BASE_RES; + dev->inquiry_transp_x_range /= AVISION_BASE_RES; + dev->inquiry_transp_y_range /= AVISION_BASE_RES; } else { /* ZP: The right number is 2820, wether it is 40-41, 42-43, 44-45, * 46-47 or 89-90 I don't know but I would bet for the last ! @@ -1443,13 +1865,15 @@ attach (const char* devname, Avision_Device** devp) /* check if x/y range is valid :-((( */ if (dev->inquiry_x_range == 0 || dev->inquiry_y_range == 0) { if (dev->hw->scanner_type == AV_SHEETFEED) { - DBG (1, "Inquiry x/y-range is invalid! Using defauld %fx%finch (sheetfeed).\n", + DBG (1, "attach: x/y-range is invalid! ...\n"); + DBG (1, "attach: Using defauld %fx%finch (sheetfeed).\n", A4_X_RANGE, SHEETFEED_Y_RANGE); + dev->inquiry_x_range = A4_X_RANGE * MM_PER_INCH; dev->inquiry_y_range = SHEETFEED_Y_RANGE * MM_PER_INCH; } else { - DBG (1, "Inquiry x/y-range is invalid! Using defauld %fx%finch (ISO A4).\n", + DBG (1, "attach: x/y-range is invalid! Using defauld %fx%finch (ISO A4).\n", A4_X_RANGE, A4_Y_RANGE); dev->inquiry_x_range = A4_X_RANGE * MM_PER_INCH; @@ -1457,9 +1881,9 @@ attach (const char* devname, Avision_Device** devp) } } else - DBG (3, "Inquiry x/y-range seems to be valid!\n"); + DBG (3, "attach: x/y-range seems to be valid!\n"); if (force_a4) { - DBG (1, "option: \"force_a4\" found! Using defauld %fx%finch (ISO A4).\n", + DBG (1, "attach: \"force_a4\" found! Using defauld %fx%finch (ISO A4).\n", A4_X_RANGE, A4_Y_RANGE); dev->inquiry_x_range = A4_X_RANGE * MM_PER_INCH; dev->inquiry_y_range = A4_Y_RANGE * MM_PER_INCH; @@ -1475,12 +1899,16 @@ attach (const char* devname, Avision_Device** devp) /* Try to retrieve additional accessories information */ if (dev->inquiry_detect_accessories) { status = get_accessories_info (fd, - &dev->inquiry_adf, - &dev->inquiry_light_box); + &dev->acc_adf, + &dev->acc_light_box); if (status != SANE_STATUS_GOOD) goto close_scanner_and_return; } + /* is an ADF unit connected? */ + if (dev->acc_adf) + dev->is_adf = SANE_TRUE; + /* For a film scanner try to retrieve additional frame information */ if (dev->hw->scanner_type == AV_FILM) { status = get_frame_info (fd, @@ -1494,6 +1922,8 @@ attach (const char* devname, Avision_Device** devp) goto close_scanner_and_return; } + dev->data_dq = 0; /* was 0x0a0d ... */ + status = wait_ready (fd); if (status != SANE_STATUS_GOOD) goto close_scanner_and_return; @@ -1514,11 +1944,378 @@ attach (const char* devname, Avision_Device** devp) } static SANE_Status -perform_calibration (Avision_Scanner* s) +get_calib_format (Avision_Scanner* s, struct calibration_format* format) { - Avision_Device* dev = s->hw; SANE_Status status; + struct command_read rcmd; + u_int8_t result [32]; + size_t size; + + DBG (3, "get_calib_format:\n"); + + size = sizeof (result); + + memset (&rcmd, 0, sizeof (rcmd)); + rcmd.opc = AVISION_SCSI_READ; + rcmd.datatypecode = 0x60; /* get calibration format */ + set_double (rcmd.datatypequal, s->hw->data_dq); + set_triple (rcmd.transferlen, size); + + DBG (3, "get_calib_format: read_data: %d bytes\n", size); + status = sanei_scsi_cmd (s->fd, &rcmd, sizeof (rcmd), result, &size); + if (status != SANE_STATUS_GOOD || size != sizeof (result) ) { + DBG (1, "get_calib_format: read calib. info failt (%s)\n", + sane_strstatus (status) ); + return status; + } + + debug_print_calib_format (3, "get_calib_format", result); + + format->pixel_per_line = (result[0] << 8) + result[1]; + format->bytes_per_channel = result[2]; + format->lines = result[3]; + format->flags = result[4]; + format->ability1 = result[5]; + format->r_gain = result[6]; + format->g_gain = result[7]; + format->b_gain = result[8]; + format->r_shading_target = (result[9] << 8) + result[10]; + format->g_shading_target = (result[11] << 8) + result[12]; + format->b_shading_target = (result[13] << 8) + result[14]; + format->r_dark_shading_target = (result[15] << 8) + result[16]; + format->g_dark_shading_target = (result[17] << 8) + result[18]; + format->b_dark_shading_target = (result[19] << 8) + result[20]; + + /* now translate to normal! */ + /* firmware return R--RG--GB--B with 3 line count */ + /* software format it as 1 line if true color scan */ + /* only line interleave format to be supported */ + + if ((s->mode == TRUECOLOR) || BIT(format->ability1, 3)) + { + format->lines /= 3; + format->channels = 3; + } + else + format->channels = 1; + + return SANE_STATUS_GOOD; +} + +static SANE_Status +get_calib_data (Avision_Scanner* s, u_int8_t data_type, + u_int8_t* calib_data, + size_t calib_size, size_t line_size) +{ + SANE_Status status; + u_int8_t *calib_ptr; + + size_t get_size, data_size; + + struct command_read rcmd; + + DBG (3, "get_calib_data: type %x, size %d, line_size: %d\n", + data_type, calib_size, line_size); + + memset (&rcmd, 0, sizeof (rcmd)); + + rcmd.opc = AVISION_SCSI_READ; + rcmd.datatypecode = data_type; + set_double (rcmd.datatypequal, s->hw->data_dq); + + calib_ptr = calib_data; + get_size = line_size; + data_size = calib_size; + + while (data_size) { + if (get_size > data_size) + get_size = data_size; + data_size -= get_size; + set_triple (rcmd.transferlen, get_size); + + status = sanei_scsi_cmd (s->fd, &rcmd, + sizeof (rcmd), calib_ptr, &get_size); + if (status != SANE_STATUS_GOOD) { + DBG (1, "get_calib_data: read data failed (%s)\n", + sane_strstatus (status)); + return status; + } + calib_ptr += get_size; + } + + return SANE_STATUS_GOOD; +} + +static SANE_Status +set_calib_data (Avision_Scanner* s, struct calibration_format* format, + u_int16_t* dark_data, u_int16_t* white_data) +{ + struct command_send scmd; + + SANE_Status status; + + u_int8_t dq; + u_int8_t dq1; + u_int8_t* out_data; + + int i, out_size; + int element_per_line = format->pixel_per_line * format->channels; + + DBG (3, "set_calib_data:\n"); + + memset (&scmd, 0x00, sizeof (scmd)); + scmd.opc = AVISION_SCSI_SEND; + scmd.datatypecode = 0x82; /* 0x82 for download calibration data */ + + /* dark calibration ? */ + if (BIT (format->ability1, 2) ) { + for (i = 0; i < element_per_line; ++i) + white_data[i] = (white_data[i] & 0xffc0) | ((dark_data[i] >> 10) & 0x3f); + } + + out_size = format->pixel_per_line * 2; + + for (dq1 = 0; dq1 < format->channels; ++dq1) + { + if (format->channels == 1) + dq = 0x11; /* send green channel */ + else + dq = dq1; + + set_double (scmd.datatypequal, dq); /* color: 0=red; 1=green; 2=blue */ + set_triple (scmd.transferlen, out_size); + + out_data = (u_int8_t *) & white_data[dq1 * format->pixel_per_line]; + + DBG (3, "set_calib_data: dq: %d, size: %d\n", + dq, out_size); + + status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), + out_data, out_size, 0, 0); + if (status != SANE_STATUS_GOOD) { + DBG (3, "set_calib_data: send failed (%s)\n", sane_strstatus (status)); + return status; + } + } /* end for each channel */ + + return SANE_STATUS_GOOD; +} + +/* Sort data pixel by pixel and average first 2/3 of the data. + The caller has to free return pointer. R,G,B pixels + interleave to R,G,B line interleave. */ + +static u_int16_t* +sort_and_average (struct calibration_format* format, u_int8_t* data) +{ + /* calibration data in 16 bits always */ + /* that is a = b[1] << 8 + b[0] in all system. */ + + int stride, i, line, limit; + int elements_per_line; + + u_int8_t *ptr1, *ptr2; + u_int16_t *sort_ptr, *avg_data, *avg_ptr[3]; + + DBG (1, "sort_and_average:\n"); + + if (!format || !data) + return NULL; + + sort_ptr = malloc (format->lines * 2); + if (!sort_ptr) + return NULL; + + /* maybe more accurance by first *2 ? */ + limit = 2 * (format->lines / 3); + + if (limit <= 0) + limit = 1; + + elements_per_line = format->pixel_per_line * format->channels; + + avg_data = malloc (elements_per_line * 2); + if (!avg_data) { + free (sort_ptr); + return NULL; + } + + for (i = 0; i < format->channels; ++i) + avg_ptr[i] = avg_data + i * format->pixel_per_line; + + stride = format->bytes_per_channel * elements_per_line; + + /* for each pixel */ + for (i = 0; i < format->pixel_per_line; ++i) + { + ptr1 = data + i * format->bytes_per_channel; + /* for each line of pixel "i" */ + for (line = 0; line < format->lines; ++line) { + ptr2 = ptr1 + line * stride; /* next line's pixel */ + + if (format->bytes_per_channel == 1) + sort_ptr[line] = (u_int16_t) (*ptr2 << 8); + + else + sort_ptr[line] = (u_int16_t) *ptr2; + } + + if (format->channels == 1) { + avg_data[i] = bubble_sort (sort_ptr, format->lines); + } + else { + *avg_ptr[i % 3]++ = bubble_sort (sort_ptr, format->lines); + } + } + + free ((void *) sort_ptr); + return avg_data; +} + +/*shading data is 16bits little endian format when send/read from firmware*/ +static void +get_dark_shading_data (Avision_Scanner* s, + struct calibration_format* format, u_int16_t* data) +{ +#define INVALID_DARK_SHADING 0xffff +#define DEFAULT_DARK_SHADING 0x0000 + + u_int16_t map_value = DEFAULT_DARK_SHADING; + u_int16_t rgb_map_value[3]; + + int elements_per_line, i; + + DBG (3, "get_dark_shading_data:\n"); + + if (s->hw->inquiry_max_shading_target != INVALID_DARK_SHADING) + map_value = s->hw->inquiry_max_shading_target; + + rgb_map_value[0] = format->r_dark_shading_target; + rgb_map_value[1] = format->g_dark_shading_target; + rgb_map_value[2] = format->b_dark_shading_target; + + for (i = 0; i < format->channels; ++i) { + if (rgb_map_value[i] == INVALID_DARK_SHADING) + rgb_map_value[i] = map_value; + } + + if (format->channels == 1) { + rgb_map_value[1] = rgb_map_value[2] = rgb_map_value[0]; + } + + elements_per_line = format->pixel_per_line * format->channels; + + /* Check line interleave or pixel interleave. */ + /* It seems no ASIC use line interleave right now. */ + /* Avision SCSI protocol document has bad description. */ + for (i = 0; i < elements_per_line; ++i) + { + if (data[i] > rgb_map_value[i & 0x3]) { + data[i] -= rgb_map_value[i & 0x3]; + } + else { + data[i] = 0; + } + } +} + +static void +get_white_shading_data (Avision_Scanner* s, + struct calibration_format* format, u_int16_t* data) +{ +#define INVALID_WHITE_SHADING 0x0000 +#define DEFAULT_WHITE_SHADING 0xfff0 +#define WHITE_MAP_RANGE 0x4000 +#define BYTE_MAX_WHITE_SHADING 0xff + + int i; + u_int16_t map_value = DEFAULT_WHITE_SHADING; + unsigned int rgb_map_value[3], result; + + u_int16_t white_map_value[] = { + WHITE_MAP_RANGE, WHITE_MAP_RANGE, WHITE_MAP_RANGE + }; + + int elements_per_line; + + DBG (3, "get_white_shading_data:\n"); + + if (s->hw->inquiry_max_shading_target != INVALID_WHITE_SHADING) + map_value = s->hw->inquiry_max_shading_target; + + rgb_map_value[0] = format->r_shading_target; + rgb_map_value[1] = format->g_shading_target; + rgb_map_value[2] = format->b_shading_target; + + for (i = 0; i < format->channels; ++i) { + if (rgb_map_value[i] == INVALID_WHITE_SHADING) + rgb_map_value[i] = map_value; + } + + if (format->channels == 1) { + rgb_map_value[1] = rgb_map_value[2] = rgb_map_value[0]; + } + + elements_per_line = format->pixel_per_line * format->channels; + + /* C5 use RGB pixels interleave */ + /* RR: was: if (info->firmware_ver >= 1.1) */ + if (s->hw->inquiry_asic_type == AV_ASIC_C5) + { + for (i = 0; i < 3; ++i) + rgb_map_value[i] = rgb_map_value[i] * 256; + + for (i = 0; i < elements_per_line; ++i) + { + if (data[i] < white_map_value[i % 3]) { + if (rgb_map_value[i % 3] >= 0xffff) + data[i] = 0xffff; + else + data[i] = (u_int16_t) rgb_map_value[i % 3]; + } + else { + result = (unsigned int) ((double) rgb_map_value[i % 3] * + white_map_value[i % 3] / data[i] + 0.5); + if (result > 0xffff) + data[i] = 0xffff; + else + data[i] = (u_int16_t) result; + } + } /* end for each element */ + } + else /* if not C5 ASIC */ + { + for (i = 0; i < 3; ++i) + { + if (rgb_map_value[i] <= BYTE_MAX_WHITE_SHADING) + { + /* C2 1 byte shading */ + rgb_map_value[i] = rgb_map_value[i] << 4; + white_map_value[i] = WHITE_MAP_RANGE >> 4; + } + } + for (i = 0; i < elements_per_line; ++i) + { + if (data[i] < white_map_value[i % 3]) { + data[i] = (u_int16_t) (rgb_map_value[i % 3]); + } + else { + data[i] = (u_int16_t) ((double) rgb_map_value[i % 3] * + white_map_value[i % 3] / data[i] + 0.5); + /* Will it overflow here? */ + } + } + } /* end not C5 ASIC */ +} + +static SANE_Status +old_r_calibration (Avision_Scanner* s) +{ + SANE_Status status; + + SANE_Bool send_single_channels; + size_t size; struct command_read rcmd; @@ -1534,26 +2331,24 @@ perform_calibration (Avision_Scanner* s) u_int8_t result [16]; - DBG (3, "perform_calibration: get calibration format\n"); + DBG (3, "old_r_calibration: get calibration format\n"); size = sizeof (result); memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x60; /* get calibration format */ - /* rcmd.calibchn = 0; */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + set_double (rcmd.datatypequal, s->hw->data_dq); set_triple (rcmd.transferlen, size); - DBG (3, "perform_calibration: read_data: %d bytes\n", size); + DBG (3, "old_r_calibration: read_data: %d bytes\n", size); status = sanei_scsi_cmd (s->fd, &rcmd, sizeof (rcmd), result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result) ) { - DBG (1, "perform_calibration: read calib. info failt (%s)\n", sane_strstatus (status) ); + DBG (1, "old_r_calibration: read calib. info failt (%s)\n", sane_strstatus (status) ); return status; } - debug_output_raw (5, result, size); + debug_print_raw (5, "calib_info: raw data:\n", result, size); DBG (3, "calib_info: [0-1] pixels per line %d\n", (result[0]<<8)+result[1]); DBG (3, "calib_info: [2] bytes per channel %d\n", result[2]); @@ -1572,12 +2367,14 @@ perform_calibration (Avision_Scanner* s) BIT(result[5],3)?" COLOR_CALIB":"", BIT(result[5],2)?" DARK_CALIB":"", BIT(result[5],1)?" NEEDS_WHITE_BLACK_SHADING_DATA":"", - BIT(result[5],0)?" NEEDS_2_CALIBS":""); + BIT(result[5],0)?" NEEDS_CALIB_TABLE_CHANNEL_BY_CHANNEL":""); DBG (3, "calib_info: [6] R gain: %d\n", result[6]); DBG (3, "calib_info: [7] G gain: %d\n", result[7]); DBG (3, "calib_info: [8] B gain: %d\n", result[8]); + send_single_channels = BIT(result[5],0); + /* (try) to get calibration data: * the read command 63 (read channel data hangs for HP 5300 ? */ @@ -1594,10 +2391,10 @@ perform_calibration (Avision_Scanner* s) unsigned int used_lines = calib_line_count; - DBG (3, "perform_calibration: using %d lines\n", used_lines); + DBG (3, "old_r_calibration: using %d lines\n", used_lines); calib_size = calib_pixels_per_line * calib_bytes_per_channel * used_lines; - DBG (3, "perform_calibration: read %d bytes\n", calib_size); + DBG (3, "old_r_calibration: read %d bytes\n", calib_size); calib_data = malloc (calib_size); if (!calib_data) @@ -1609,14 +2406,13 @@ perform_calibration (Avision_Scanner* s) rcmd.datatypecode = 0x62; /* only needed for single channel mode - which hangs the HP 5300 */ /* rcmd.calibchn = color; */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + set_double (rcmd.datatypequal, s->hw->data_dq); set_triple (rcmd.transferlen, calib_size); - DBG (1, "perform_calibration: %p %d\n", calib_data, calib_size); + DBG (1, "old_r_calibration: %p %d\n", calib_data, calib_size); status = sanei_scsi_cmd (s->fd, &rcmd, sizeof (rcmd), calib_data, &calib_size); if (status != SANE_STATUS_GOOD) { - DBG (1, "perform_calibration: calibration data read failed (%s)\n", sane_strstatus (status)); + DBG (1, "old_r_calibration: calibration data read failed (%s)\n", sane_strstatus (status)); return status; } @@ -1633,7 +2429,7 @@ perform_calibration (Avision_Scanner* s) if (!out_data) return SANE_STATUS_NO_MEM; - DBG (3, "perform_calibration: computing: %d bytes calibration data\n", out_size); + DBG (3, "old_r_calibration: computing: %d bytes calibration data\n", out_size); /* compute calibration data */ { @@ -1658,7 +2454,7 @@ perform_calibration (Avision_Scanner* s) for (line = 0; line < lines; ++ line) { if ( (line * offset) + i >= calib_size) - DBG (3, "perform_calibration: BUG: src out of range!!! %d\n", (line * offset) + i); + DBG (3, "old_r_calibration: BUG: src out of range!!! %d\n", (line * offset) + i); else avg += calib_data [ (line * offset) + i]; } @@ -1675,14 +2471,14 @@ perform_calibration (Avision_Scanner* s) out_data [(i * 2) + 1] = factor >> 8; } else { - DBG (3, "perform_calibration: BUG: dest out of range!!! %d\n", (i * 2) + 1); + DBG (3, "old_r_calibration: BUG: dest out of range!!! %d\n", (i * 2) + 1); } } } - if ( !(dev->hw->feature_type & AV_CALIB2) ) + if (!send_single_channels) { - DBG (3, "perform_calibration: all channels in one command\n"); + DBG (3, "old_r_calibration: all channels in one command\n"); memset (&scmd, 0, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; @@ -1691,17 +2487,20 @@ perform_calibration (Avision_Scanner* s) set_double (scmd.datatypequal, 0x12); set_triple (scmd.transferlen, out_size); - status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), out_data, out_size, 0, 0); + status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), + out_data, out_size, 0, 0); if (status != SANE_STATUS_GOOD) { - DBG (3, "perform_calibration: send_data failed (%s)\n", sane_strstatus (status)); + DBG (3, "old_r_calibration: send_data failed (%s)\n", + sane_strstatus (status)); /* not return immediately to free meme at the end */ } } - else /* send data in an alternative way (for HP 7400, and more?) */ + /* send data in an alternative way (for HP 7400, and more?) */ + else { u_int8_t* converted_out_data; - DBG (3, "perform_calibration: channels in single commands\n"); + DBG (3, "old_r_calibration: channels in single commands\n"); converted_out_data = malloc (out_size / 3); if (!out_data) { @@ -1712,7 +2511,7 @@ perform_calibration (Avision_Scanner* s) { int conv_out_size = calib_pixels_per_line * 2; - DBG (3, "perform_calibration: channel: %i\n", color); + DBG (3, "old_r_calibration: channel: %i\n", color); for (i = 0; i < calib_pixels_per_line; ++ i) { int conv_pixel = i * 2; @@ -1722,7 +2521,7 @@ perform_calibration (Avision_Scanner* s) converted_out_data [conv_pixel + 1] = out_data [out_pixel + 1]; } - DBG (3, "perform_calibration: sending now %i bytes \n", conv_out_size); + DBG (3, "old_r_calibration: sending now %i bytes \n", conv_out_size); memset (&scmd, 0, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; @@ -1735,8 +2534,8 @@ perform_calibration (Avision_Scanner* s) status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), converted_out_data, conv_out_size, 0, 0); if (status != SANE_STATUS_GOOD) { - DBG (3, "perform_calibration: send_data failed (%s)\n", sane_strstatus (status)); - /* not return immediately to free meme at the end */ + DBG (3, "old_r_calibration: send_data failed (%s)\n", sane_strstatus (status)); + /* not return immediately to free mem at the end */ } } free (converted_out_data); @@ -1747,7 +2546,331 @@ perform_calibration (Avision_Scanner* s) free (out_data); } /* end compute calibration data */ - DBG (3, "perform_calibration: returns\n"); + DBG (3, "old_r_calibration: returns\n"); + return status; +} + +static SANE_Status +normal_calibration (Avision_Scanner* s) +{ + SANE_Status status; + + struct calibration_format calib_format; + struct command_send scmd; + + u_int8_t *calib_data, *calib_ptr, *ptr; + u_int16_t *send_data, sort_data[50], mst[3]; /* mst : max shading target */ + u_int16_t map_range; + + u_int8_t read_type; + u_int8_t send_type; + u_int16_t send_type_q; + + size_t line_size, data_size, temp_size; + + int i, j, pos; + + DBG (1, "normal_calibration:\n"); + + /* get calibration format and data */ + status = get_calib_format (s, &calib_format); + if (status != SANE_STATUS_GOOD) + return status; + + /* cschiu: Always set 0x400, suggested by fransier. */ + map_range = 0x400; + + mst[0] = calib_format.r_shading_target; + if (!mst[0]) { + /* set to default, by cschiu */ + mst[0] = mst[1] = mst[2] = 0xfff; + } + else { + mst[1] = calib_format.g_shading_target; + mst[2] = calib_format.b_shading_target; + } + + send_type = 0x82; /* download calibration data */ + + if ((s->mode == TRUECOLOR) || BIT(calib_format.ability1, 3)) { /* color mode? */ + DBG (3, "normal_calibration: using color calibration\n"); + read_type = 0x62; /* read color calib data */ + send_type_q = 0x12; /* color calib data */ + } + else { + DBG (3, "normal_calibration: using gray calibration\n"); + read_type = 0x61; /* gray calib data */ + send_type_q = 0x11; /* gray/bw calib data */ + } + + line_size = calib_format.pixel_per_line * calib_format.bytes_per_channel + * calib_format.channels; + + data_size = line_size * calib_format.lines; + + temp_size = calib_format.pixel_per_line * 2 * calib_format.channels; + + DBG (3, "normal_calibration: line_size: %d, data_size: %d, temp_size: %d\n", + line_size, data_size, temp_size); + + send_data = (u_int16_t*) malloc (temp_size * sizeof(u_int16_t)); + if (!send_data) + return SANE_STATUS_NO_MEM; + + calib_data = (u_int8_t*) malloc (data_size); + if (!calib_data) { + free (send_data); + return SANE_STATUS_NO_MEM; + } + + get_calib_data (s, read_type, calib_data, data_size, data_size); /* line_size ? */ + + if (status != SANE_STATUS_GOOD) { + free (send_data); + free (calib_data); + return status; + } + + calib_ptr = calib_data; + for (i = 0; i < calib_format.pixel_per_line * calib_format.channels; ++i) + { + ptr = calib_ptr; + for (j = 0; j < (int) calib_format.lines; ++j) + { + if (calib_format.bytes_per_channel == 2) { + sort_data[j] = (u_int16_t) ((u_int16_t) (*(ptr + 1)) << 8); + sort_data[j] += *(ptr); + } + else { + sort_data[j] = (u_int16_t) (*ptr << 4); + } + + if (sort_data[j] > 0xFFF) + sort_data[j] = 0; + ptr += (u_int16_t) line_size; + } + + bubble_sort2 (sort_data, calib_format.lines / calib_format.channels); + + if (calib_format.channels == 3) + { + if (calib_format.ability1 & 0x10) /* send packed data ? */ + pos = i; + else + pos = (i % 3) * temp_size / 6 + i / 3; + + if (sort_data[0]) { + sort_data[0] = + (u_int16_t) ((double) mst[i % 3] * map_range / sort_data[0] + 0.5); + } + else + sort_data[0] = 0xFFF; + + if (sort_data[0] > 0xFFF) + sort_data[0] = 0xFFF; + + send_data[pos] = (u_int16_t) (sort_data[0]) << 4; + } + else + { + send_data[i] = (u_int16_t) (sort_data[0]) << 4; + + if (sort_data[0] != 0) { + sort_data[0] = + (u_int16_t) ((double) mst[i % 3] * map_range / sort_data[0] + 0.5); + } + else + sort_data[0] = 0xFFF; + + if (sort_data[0] > 0xFFF) + sort_data[0] = 0xFFF; + + send_data[i] = (u_int16_t) (sort_data[0]) << 4; + } + + if (calib_format.bytes_per_channel == 2) + calib_ptr += 2; + else + calib_ptr++; + } + + if (! BIT(calib_format.ability1, 0) ) /* send data in one command */ + { + DBG (3, "normal_calibration: all channels in one command\n"); + DBG (3, "normal_calibration: send_size: %d\n", + temp_size); + + memset (&scmd, 0, sizeof (scmd) ); + scmd.opc = AVISION_SCSI_SEND; + scmd.datatypecode = send_type; + set_double (scmd.datatypequal, send_type_q); + + set_triple (scmd.transferlen, temp_size); + status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), + (char *) send_data, temp_size, 0, 0); + /* not return immediately to free mem at the end */ + } + else /* send data channel by channel (for HP 7400, and other USB ones) */ + { + int conv_out_size = calib_format.pixel_per_line * 2; + u_int8_t* conv_out_data; + + DBG (3, "normal_calibration: channels in single commands\n"); + + conv_out_data = malloc (conv_out_size); + if (!conv_out_data) { + status = SANE_STATUS_NO_MEM; + } + else { + int channel; + for (channel = 0; channel < 3; ++ channel) + { + DBG (3, "normal_calibration: channel: %i\n", channel); + + for (i = 0; i < calib_format.pixel_per_line; ++ i) { + int conv_pixel = i * 2; + int out_pixel = ((i * 3) + channel) * 2; + + conv_out_data [conv_pixel] = send_data [out_pixel]; + conv_out_data [conv_pixel + 1] = send_data [out_pixel + 1]; + } + + DBG (3, "normal_calibration: sending %i bytes now\n", + conv_out_size); + + memset (&scmd, 0, sizeof (scmd)); + scmd.opc = AVISION_SCSI_SEND; + scmd.datatypecode = 0x82; /* send calibration data */ + + /* 0,1,2: color; 11: dark; 12 color calib data */ + set_double (scmd.datatypequal, channel); + set_triple (scmd.transferlen, conv_out_size); + + status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), + conv_out_data, conv_out_size, 0, 0); + if (status != SANE_STATUS_GOOD) { + DBG (3, "normal_calibration: send_data failed (%s)\n", + sane_strstatus (status)); + /* not return immediately to free mem at the end */ + } + } /* end for each channel */ + free (conv_out_data); + } /* end else send calib data*/ + } + + free ((void*)send_data); + free ((void*)calib_data); + + if (status != SANE_STATUS_GOOD) { + DBG (3, "normal_calibratoin: send data failed (%s)\n", + sane_strstatus (status)); + return status; + } + + return SANE_STATUS_GOOD; +} + +static SANE_Status +c5_calibration (Avision_Scanner* s) +{ + SANE_Status status; + + struct calibration_format calib_format; + + int calib_data_size, calib_bytes_per_line; + + u_int16_t *dark_avg_data, *white_avg_data; + u_int8_t *calib_tmp_data; + + DBG (1, "c5_calibration:\n"); + + /* get calibration format and data */ + status = get_calib_format (s, &calib_format); + if (status != SANE_STATUS_GOOD) + return status; + +#ifdef NEW_CODE + /* check if need do calibration */ + /* prescan always do calibration if need */ + if (calib_format.flags == 1) /* no calib neede */ + return SANE_STATUS_GOOD; +#endif + + /* calculate calibration data size for read from scanner */ + /* size = lines * bytes_per_channel * pixels_per_line * channel */ + calib_bytes_per_line = calib_format.bytes_per_channel * + calib_format.pixel_per_line * calib_format.channels; + + calib_data_size = calib_format.lines * calib_bytes_per_line; + + calib_tmp_data = (u_int8_t *) malloc (calib_data_size); + if (!calib_tmp_data) + return SANE_STATUS_NO_MEM; + + /*check if we need to do dark calibration */ + if (calib_format.ability1 & 0x04) /* needs dark shading ?*/ + { + /* read dark calib data */ + status = get_calib_data (s, 0x66, calib_tmp_data, calib_data_size, + calib_data_size /*calib_bytes_per_line */ ); + + if (status != SANE_STATUS_GOOD) { + free (calib_tmp_data); + return status; + } + + /* process dark data: sort and average. */ + dark_avg_data = sort_and_average (&calib_format, calib_tmp_data); + if (!dark_avg_data) { + free (calib_tmp_data); + return SANE_STATUS_NO_MEM; + } + get_dark_shading_data (s, &calib_format, dark_avg_data); + } + else + dark_avg_data = NULL; + + /* do white calibration: read grey or color or gray data */ + status = get_calib_data (s, (calib_format.channels == 3) ? 0x62 : 0x61, + calib_tmp_data, calib_data_size, + calib_data_size /*calib_bytes_per_line */ ); + + if (status != SANE_STATUS_GOOD) { + free (calib_tmp_data); + if (dark_avg_data) + free (dark_avg_data); + return status; + } + + white_avg_data = sort_and_average (&calib_format, calib_tmp_data); + + if (!white_avg_data) { + free (calib_tmp_data); + if (dark_avg_data) + free (dark_avg_data); + return SANE_STATUS_NO_MEM; + } + + /* decrease dark average data */ + if (calib_format.ability1 & 1) { + int elements_per_line = calib_format.pixel_per_line * + calib_format.channels; + int i; + + for (i = 0; i < elements_per_line; ++i) { + white_avg_data[i] -= dark_avg_data[i]; + } + } + + get_white_shading_data (s, &calib_format, white_avg_data); + + status = set_calib_data (s, &calib_format, dark_avg_data, white_avg_data); + + free (calib_tmp_data); + if (dark_avg_data) + free (dark_avg_data); + free (white_avg_data); + return status; } @@ -1805,6 +2928,8 @@ set_gamma (Avision_Scanner* s) Avision_Device* dev = s->hw; SANE_Status status; + int invert_table = 0; + size_t gamma_table_raw_size; size_t gamma_table_size; size_t gamma_values; @@ -1821,28 +2946,28 @@ set_gamma (Avision_Scanner* s) double brightness; double contrast; - /* calculate the gamma table sizes */ - if (!dev->inquiry_new_protocol) /* if 11bit (old protocol) table */ + if (dev->inquiry_asic_type != AV_ASIC_OA980) + invert_table = (s->mode == THRESHOLDED) || (s->mode == DITHERED); + + switch (dev->inquiry_asic_type) { + case AV_ASIC_C5: + gamma_table_raw_size = gamma_table_size = 256; + break; + case AV_ASIC_Cx: gamma_table_raw_size = 4096; gamma_table_size = 2048; - } - else /* new protocol */ - { - if (dev->hw->feature_type & AV_GAMMA2) - gamma_table_raw_size = 512; - else if (dev->hw->feature_type & AV_GAMMA3) - gamma_table_raw_size = 256; - else - gamma_table_raw_size = 4096; - - gamma_table_size = gamma_table_raw_size; + break; + default: + gamma_table_raw_size = gamma_table_size = 4096; } gamma_values = gamma_table_size / 256; - DBG (3, "set_gamma: table_raw_size: %d, table_size: %d, values: %d\n", - gamma_table_raw_size, gamma_table_size, gamma_values); + DBG (3, "set_gamma: table_raw_size: %d, table_size: %d\n", + gamma_table_raw_size, gamma_table_size); + DBG (3, "set_gamma: values: %d, invert_table: %d\n", + gamma_values, invert_table); /* prepare for emulating contrast, brightness ... via the gamma-table */ brightness = SANE_UNFIX (s->val[OPT_BRIGHTNESS].w); @@ -1911,6 +3036,15 @@ set_gamma (Avision_Scanner* s) v1 *= 255; v2 *= 255; + if (invert_table) { + v1 = 255 - v1; + v2 = 255 - v2; + if (v1 <= 0) + v1 = 0; + if (v2 <= 0) + v2 = 0; + } + for (k = 0; k < gamma_values; ++ k, ++ i) { gamma_data [i] = (u_int8_t) (((v1 * (gamma_values - k)) + (v2 * k) ) / (double) gamma_values); @@ -1920,12 +3054,14 @@ set_gamma (Avision_Scanner* s) { size_t t_i = i-1; if (i < gamma_table_raw_size) { - DBG (4, "set_gamma: (old protocol) - filling the rest\n"); + DBG (4, "set_gamma: (old protocol) - filling the table.\n"); for ( ; i < gamma_table_raw_size; ++ i) gamma_data [i] = gamma_data [t_i]; } } + DBG (4, "set_gamma: sending %d bytes gamma table.\n", + gamma_table_raw_size); status = sanei_scsi_cmd2 (s->fd, &scmd, sizeof (scmd), gamma_data, gamma_table_raw_size, 0, 0); } @@ -1936,7 +3072,8 @@ set_gamma (Avision_Scanner* s) static SANE_Status set_window (Avision_Scanner* s) { - /* Avision_Device* dev = s->hw; */ + Avision_Device* dev = s->hw; + SANE_Status status; struct { @@ -1961,22 +3098,22 @@ set_window (Avision_Scanner* s) set_double (cmd.window_descriptor.yres, s->avdimen.res); /* upper left corner coordinates in inch/1200 */ - set_quad (cmd.window_descriptor.ulx, s->avdimen.tlx); - set_quad (cmd.window_descriptor.uly, s->avdimen.tly); + set_quad (cmd.window_descriptor.ulx, s->avdimen.tlx * 1200 / s->avdimen.res); + set_quad (cmd.window_descriptor.uly, s->avdimen.tly * 1200 / s->avdimen.res); /* width and length in inch/1200 */ - set_quad (cmd.window_descriptor.width, s->avdimen.width); - set_quad (cmd.window_descriptor.length, s->avdimen.length); + set_quad (cmd.window_descriptor.width, s->avdimen.width * 1200 / s->avdimen.res); + set_quad (cmd.window_descriptor.length, s->avdimen.height * 1200 / s->avdimen.res); - /* width and length in bytes */ + /* width and length in _bytes_ */ set_double (cmd.window_descriptor.linewidth, s->params.bytes_per_line); - set_double (cmd.window_descriptor.linecount, - s->params.lines + s->avdimen.line_difference); + set_double (cmd.window_descriptor.linecount, s->params.lines + s->avdimen.line_difference); - cmd.window_descriptor.bitset1 = 0x60; - cmd.window_descriptor.bitset1 |= s->val[OPT_SPEED].w; - - cmd.window_descriptor.bitset2 = 0x00; + /* set speed */ + cmd.window_descriptor.bitset1 = s->val[OPT_SPEED].w & 0x07; /* only 3 bit */ + if (dev->inquiry_new_protocol) { + SET_BIT (cmd.window_descriptor.bitset1, 6); /* scanner should use our line-width / count */ + } /* quality scan option switch */ if (s->val[OPT_QSCAN].w == SANE_TRUE) { @@ -1993,20 +3130,21 @@ set_window (Avision_Scanner* s) cmd.window_descriptor.bitset2 |= AV_TRANS_ON; } + /* ADF scan */ + if (s->val[OPT_ADF].w) { + SET_BIT (cmd.window_descriptor.bitset1, 7); + } + /* fixed values */ - cmd.window_descriptor.pad_type = 3; + cmd.window_descriptor.padding_and_bitset = 3; cmd.window_descriptor.vendor_specid = 0xFF; - cmd.window_descriptor.paralen = 9; + cmd.window_descriptor.paralen = 14; /* modified by cschiu, from 9 to 14 */ - /* currently also fixed - * (and unsupported by all Avision scanner I know ...) */ + /* This is normaly unsupported by Avsion scanners, and we do this + via the gamma table - which works for all devices ... */ cmd.window_descriptor.highlight = 0xFF; cmd.window_descriptor.shadow = 0x00; - - /* this is normaly unsupported by Avsion scanners, too. - * I clear this only to be sure if another scanner knows about it ... - * we do this via the gamma table - which works for all ... */ - cmd.window_descriptor.thresh = 128; + cmd.window_descriptor.threshold = 128; cmd.window_descriptor.brightness = 128; cmd.window_descriptor.contrast = 128; @@ -2016,19 +3154,19 @@ set_window (Avision_Scanner* s) case THRESHOLDED: cmd.window_descriptor.bpc = 1; cmd.window_descriptor.image_comp = 0; - cmd.window_descriptor.bitset1 &= 0xC7; + cmd.window_descriptor.bitset1 &= 0xC7; /* no filter */ break; case DITHERED: cmd.window_descriptor.bpc = 1; cmd.window_descriptor.image_comp = 1; - cmd.window_descriptor.bitset1 &= 0xC7; + cmd.window_descriptor.bitset1 &= 0xC7; /* no filter */ break; - case GREYSCALE: + case GRAYSCALE: cmd.window_descriptor.bpc = 8; cmd.window_descriptor.image_comp = 2; - cmd.window_descriptor.bitset1 &= 0xC7; + cmd.window_descriptor.bitset1 &= 0xC7; /* no filter */ /* RR: what is it for Gunter ?? - doesn't work */ /* cmd.window_descriptor.bitset1 |= 0x30; */ break; @@ -2036,6 +3174,7 @@ set_window (Avision_Scanner* s) case TRUECOLOR: cmd.window_descriptor.bpc = 8; cmd.window_descriptor.image_comp = 5; + cmd.window_descriptor.bitset1 |= 0x20; /* rgb one-pass filter */ break; default: @@ -2043,6 +3182,8 @@ set_window (Avision_Scanner* s) return SANE_STATUS_INVAL; } + debug_print_window_descriptor (5, "set_window", &(cmd.window_descriptor)); + DBG (3, "set_window: sending command. Bytes: %d\n", sizeof (cmd)); status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0); @@ -2085,7 +3226,7 @@ check_paper (Avision_Scanner *s) buf, &size); if (status == SANE_STATUS_GOOD) { - if (buf[0] == 0) + if (!(buf[0] & 0x1)) status = SANE_STATUS_NO_DOCS; } @@ -2114,12 +3255,12 @@ start_scan (Avision_Scanner *s) { struct command_scan cmd; - DBG (3, "start_scan\n"); - + DBG (3, "start_scan:\n"); + memset (&cmd, 0, sizeof (cmd)); cmd.opc = AVISION_SCSI_SCAN; - cmd.transferlen = 1; - + cmd.transferlen = 0; /*RR: Was 0 */ + if (s->val[OPT_PREVIEW].w == SANE_TRUE) { cmd.bitset1 |= 0x01<<6; } @@ -2133,7 +3274,8 @@ start_scan (Avision_Scanner *s) else { cmd.bitset1 &= ~(0x01<<7); } - + + DBG (3, "start_scan: sending command:\n"); return sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0); } @@ -2142,7 +3284,7 @@ do_eof (Avision_Scanner *s) { int exit_status; - DBG (3, "do_eof\n"); + DBG (3, "do_eof:\n"); if (s->pipe >= 0) { @@ -2160,32 +3302,28 @@ do_eof (Avision_Scanner *s) static SANE_Status do_cancel (Avision_Scanner *s) { - DBG (3, "do_cancel\n"); + DBG (3, "do_cancel:\n"); s->scanning = SANE_FALSE; /* do_eof (s); needed? */ - if (s->reader_pid > 0) - { - int exit_status; - - /* ensure child knows it's time to stop: */ - kill (s->reader_pid, SIGTERM); - while (wait (&exit_status) != s->reader_pid); - s->reader_pid = 0; - } + if (s->reader_pid > 0) { + int exit_status; + + /* ensure child knows it's time to stop: */ + kill (s->reader_pid, SIGTERM); + while (wait (&exit_status) != s->reader_pid); + s->reader_pid = 0; + } - if (s->fd >= 0) - { - /* release the device */ - release_unit (s); - - /* object_position (s, AVISION_SCSI_OP_GO_HOME); go_home*/ - - sanei_scsi_close (s->fd); - s->fd = -1; - } + if (s->fd >= 0) { + /* release the device */ + release_unit (s); + + sanei_scsi_close (s->fd); + s->fd = -1; + } return SANE_STATUS_CANCELLED; } @@ -2196,14 +3334,17 @@ read_data (Avision_Scanner* s, SANE_Byte* buf, size_t count) struct command_read rcmd; SANE_Status status; - DBG (3, "read_data: %d\n", count); + DBG (9, "read_data: %d\n", count); memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x00; /* read image data */ - rcmd.datatypequal [0] = 0x0d; - rcmd.datatypequal [1] = 0x0a; + + /* Urghs!#*! I needed really long to figure out that the AV 800S + doesn't like another data_type_qualifier ... !!! */ + rcmd.datatypequal [0] = 0x0; + rcmd.datatypequal [1] = 0x0; set_triple (rcmd.transferlen, count); status = sanei_scsi_cmd (s->fd, &rcmd, sizeof (rcmd), buf, &count); @@ -2217,7 +3358,7 @@ init_options (Avision_Scanner* s) Avision_Device* dev = s->hw; int i; - DBG (3, "init_options\n"); + DBG (3, "init_options:\n"); memset (s->opt, 0, sizeof (s->opt)); memset (s->val, 0, sizeof (s->val)); @@ -2354,18 +3495,31 @@ init_options (Avision_Scanner* s) s->opt[OPT_ENHANCEMENT_GROUP].size = 0; s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - /* transparency adapter. */ + /* transparency adapter */ s->opt[OPT_TRANS].name = "transparency"; s->opt[OPT_TRANS].title = "Enable transparency adapter"; - s->opt[OPT_TRANS].desc = "Switch transparency mode on. Which mainly switches the scanner " \ - "lamp off. (Hint: This can also be used to switch the scanner lamp off when you don't " \ - "use the scanner in the next time. Simply enable this option and do a preview.)"; + s->opt[OPT_TRANS].desc = "Switch transparency mode on. Which mainly " \ + "switches the scanner lamp off. (Hint: This can also be used to switch " \ + "the scanner lamp off when you don't use the scanner in the next time. " \ + "Simply enable this option and perform a preview.)"; s->opt[OPT_TRANS].type = SANE_TYPE_BOOL; s->opt[OPT_TRANS].unit = SANE_UNIT_NONE; s->val[OPT_TRANS].w = SANE_FALSE; if (dev->hw->scanner_type == AV_SHEETFEED) s->opt[OPT_TRANS].cap |= SANE_CAP_INACTIVE; + /* ADF adapter */ + s->opt[OPT_ADF].name = "adf"; + s->opt[OPT_ADF].title = "Enable Automatic-Document-Feeder"; + s->opt[OPT_ADF].desc = "This option enables the " \ + "Automatic-Docuement-Feeder of the scanner. This allows you to " \ + "scan multiple pages manually or automatically."; + s->opt[OPT_ADF].type = SANE_TYPE_BOOL; + s->opt[OPT_ADF].unit = SANE_UNIT_NONE; + s->val[OPT_ADF].w = SANE_FALSE; + if (!dev->is_adf) + s->opt[OPT_ADF].cap |= SANE_CAP_INACTIVE; + /* brightness */ s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; @@ -2393,7 +3547,7 @@ init_options (Avision_Scanner* s) /* Quality Scan */ s->opt[OPT_QSCAN].name = "quality-scan"; s->opt[OPT_QSCAN].title = "Quality scan"; - s->opt[OPT_QSCAN].desc = "Turn on quality scanning (slower & better)"; + s->opt[OPT_QSCAN].desc = "Turn on quality scanning (slower but better)."; s->opt[OPT_QSCAN].type = SANE_TYPE_BOOL; s->opt[OPT_QSCAN].unit = SANE_UNIT_NONE; s->val[OPT_QSCAN].w = SANE_TRUE; @@ -2489,27 +3643,31 @@ reader_process (Avision_Scanner *s, int fd) { Avision_Device* dev = s->hw; + SANE_Status status; + sigset_t sigterm_set; + FILE* fp; + + /* the complex params */ + size_t bytes_per_line; + size_t lines_per_stripe; + size_t lines_per_output; + size_t max_bytes_per_read; + size_t half_inch_bytes; + + /* the simple params for the data reader */ + size_t stripe_size; + size_t stripe_fill; + size_t out_size; + + size_t total_size; + size_t processed_bytes; + /* the fat strip we currently puzzle together to perform software-colorpack and more */ u_int8_t* stripe_data; /* the corrected output data */ u_int8_t* out_data; - /* the glocal complex params */ - size_t bytes_per_line; - size_t lines_per_stripe; - size_t lines_per_output; - size_t max_bytes_per_read; - - /* the dumb params for the data reader */ - size_t needed_bytes; - size_t processed_bytes; - size_t bytes_in_stripe; - - SANE_Status status; - sigset_t sigterm_set; - FILE* fp; - - DBG (3, "reader_process\n"); + DBG (3, "reader_process:\n"); sigemptyset (&sigterm_set); sigaddset (&sigterm_set, SIGTERM); @@ -2521,114 +3679,149 @@ reader_process (Avision_Scanner *s, int fd) bytes_per_line = s->params.bytes_per_line; lines_per_stripe = s->avdimen.line_difference * 2; if (lines_per_stripe == 0) - lines_per_stripe = 8; /* TODO: perform some nice max 1/2 inch computation */ + lines_per_stripe = 8; lines_per_output = lines_per_stripe - s->avdimen.line_difference; /* the "/2" might makes scans faster - because it should leave some space - in the SCSI buffers (scanner, kernel, ...) empty to send _ahead_ ... */ + in the SCSI buffers (scanner, kernel, ...) empty to read/send _ahead_ ... */ max_bytes_per_read = sanei_scsi_max_request_size / 2; - DBG (3, "bytes_per_line=%d, lines_per_stripe=%d, lines_per_output=%d\n", + /* perform some nice max 1/2 inch computation to make scan-previews look nicer */ + half_inch_bytes = s->params.bytes_per_line * s->avdimen.res / 2; + if (max_bytes_per_read > half_inch_bytes) + max_bytes_per_read = half_inch_bytes; + + stripe_size = bytes_per_line * lines_per_stripe; + out_size = bytes_per_line * lines_per_output; + + DBG (3, "sanei_scsi_max_request_size / 2: %d, half_inch_bytes: %d\n", + sanei_scsi_max_request_size / 2, half_inch_bytes); + + DBG (3, "bytes_per_line: %d, lines_per_stripe: %d, lines_per_output: %d\n", bytes_per_line, lines_per_stripe, lines_per_output); - DBG (3, "max_bytes_per_read=%d, stripe_data size=%d\n", - max_bytes_per_read, bytes_per_line * lines_per_stripe); + DBG (3, "max_bytes_per_read: %d, stripe_size: %d, out_size: %d\n", + max_bytes_per_read, stripe_size, out_size); - stripe_data = malloc (bytes_per_line * lines_per_stripe); - out_data = malloc (bytes_per_line * lines_per_output); + stripe_data = malloc (stripe_size); + out_data = malloc (out_size); s->line = 0; /* calculate params for the simple reader */ - needed_bytes = bytes_per_line * s->params.lines; - if (s->mode == TRUECOLOR) - needed_bytes += bytes_per_line * s->avdimen.line_difference; + total_size = bytes_per_line * (s->params.lines + s->avdimen.line_difference); + DBG (3, "reader_process: total_size: %d\n", total_size); processed_bytes = 0; - bytes_in_stripe = 0; - - DBG (3, "total needed_bytes=%d\n", needed_bytes); + stripe_fill = 0; + /* data read loop until all lines are processed */ while (s->line < s->params.lines) { int usefull_bytes; - /* fille the stripe buffer */ - while (processed_bytes < needed_bytes && bytes_in_stripe < lines_per_stripe * bytes_per_line) + /* fill the stripe buffer */ + while (processed_bytes < total_size && stripe_fill < stripe_size) { - size_t this_read = (bytes_per_line * lines_per_stripe) - bytes_in_stripe; + size_t this_read = stripe_size - stripe_fill; /* limit reads to max_read and global data boundaries */ if (this_read > max_bytes_per_read) this_read = max_bytes_per_read; - if (processed_bytes + this_read > needed_bytes) - this_read = needed_bytes - processed_bytes; + if (processed_bytes + this_read > total_size) + this_read = total_size - processed_bytes; - DBG (7, "this read: %ld\n", (long)this_read); + DBG (5, "reader_process: processed_bytes: %d, total_size: %d\n", + processed_bytes, total_size); + + DBG (5, "reader_process: this_read: %d\n", + this_read); sigprocmask (SIG_BLOCK, &sigterm_set, 0); - status = read_data (s, stripe_data + bytes_in_stripe, this_read); + status = read_data (s, stripe_data + stripe_fill, this_read); sigprocmask (SIG_UNBLOCK, &sigterm_set, 0); if (status != SANE_STATUS_GOOD) { - DBG (1, "reader_process: read_data failed with status=%d\n", status); + DBG (1, "reader_process: read_data failed with status: %d\n", status); return 3; } - bytes_in_stripe += this_read; + stripe_fill += this_read; processed_bytes += this_read; } - DBG (6, "reader_process: buffer filled\n"); + DBG (5, "reader_process: stripe filled\n"); - /* perform output convertion */ + /* perform output convertions */ - usefull_bytes = bytes_in_stripe; + usefull_bytes = stripe_fill; if (s->mode == TRUECOLOR) usefull_bytes -= s->avdimen.line_difference * bytes_per_line; - DBG (7, "reader_process: usefull_bytes %i\n", usefull_bytes); - - if (s->mode == TRUECOLOR) { - if (s->avdimen.line_difference > 0) { - int c, i; - int pixels = usefull_bytes / 3; - int c_offset = (s->avdimen.line_difference / 3) * bytes_per_line; + DBG (5, "reader_process: usefull_bytes %i\n", usefull_bytes); + + /* perform needed data convertions (packing, ...) and/or copy the image data */ + if (s->mode == TRUECOLOR) + { + if (s->avdimen.line_difference > 0) /* color pack */ + { + int c, i; + int pixels = usefull_bytes / 3; + int c_offset = (s->avdimen.line_difference / 3) * bytes_per_line; + + for (c = 0; c < 3; ++ c) + for (i = 0; i < pixels; ++ i) + out_data [i * 3 + c] = stripe_data [i * 3 + (c * c_offset) + c]; + } /* end color pack */ + else if (dev->inquiry_needs_line_pack) { /* line pack */ + int i = 0; + int l, p; + int line_pixels = bytes_per_line / 3; + int lines = usefull_bytes / bytes_per_line; + + for (l = 0; l < lines; ++ l) + { + u_int8_t* r_ptr = stripe_data + (bytes_per_line * l); + u_int8_t* g_ptr = r_ptr + line_pixels; + u_int8_t* b_ptr = g_ptr + line_pixels; + + for (p = 0; p < line_pixels; ++ p) { + out_data [i++] = *(r_ptr++); + out_data [i++] = *(g_ptr++); + out_data [i++] = *(b_ptr++); + } + } + } /* end line pack */ - for (c = 0; c < 3; ++ c) - for (i = 0; i < pixels; ++ i) - out_data [i * 3 + c] = stripe_data [i * 3 + (c * c_offset) + c]; - } - else { + /* TODO: add mirror image support ... */ + + else { /* else simple copy */ memcpy (out_data, stripe_data, usefull_bytes); } } - else if (s->mode == GREYSCALE) { + else /*if (s->mode == GRAYSCALE) */ { memcpy (out_data, stripe_data, usefull_bytes); } - else { - /* in singlebit mode, the avision scanners return 1 for black. ;-( --EUR */ - int i; - for (i = 0; i < usefull_bytes; ++ i) - out_data[i] = ~ stripe_data [i]; - } - /* I know that this is broken if not a multiple of bytes_per_line is in the buffer. - Shouldn't happen */ + /* I know that the next lines are broken if not a multiple of + bytes_per_line are in the buffer. Shouldn't happen. */ fwrite (out_data, bytes_per_line, usefull_bytes / bytes_per_line, fp); - /* cleanup stripe buffer */ - bytes_in_stripe -= usefull_bytes; - if (bytes_in_stripe > 0) - memcpy (stripe_data, stripe_data + usefull_bytes, bytes_in_stripe); + /* save image date in stripe buffer for next next stripe */ + stripe_fill -= usefull_bytes; + if (stripe_fill > 0) + memcpy (stripe_data, stripe_data + usefull_bytes, stripe_fill); s->line += usefull_bytes / bytes_per_line; DBG (3, "reader_process: end loop\n"); } /* end while not all lines */ - if (dev->inquiry_new_protocol) { + /* Eject film-holder */ + if (dev->inquiry_new_protocol && + (dev->hw->scanner_type == AV_FILM || dev->hw->scanner_type == AV_SHEETFEED)) + { status = object_position (s, AVISION_SCSI_OP_GO_HOME); if (status != SANE_STATUS_GOOD) return status; @@ -2641,12 +3834,11 @@ reader_process (Avision_Scanner *s, int fd) status = release_unit (s); if (status != SANE_STATUS_GOOD) - DBG (1, "release_unit failed\n"); + DBG (1, "reader_process: release_unit failed\n"); return 0; } - static SANE_Status attach_one (const char *dev) { @@ -2654,34 +3846,32 @@ attach_one (const char *dev) return SANE_STATUS_GOOD; } - SANE_Status sane_init (SANE_Int* version_code, SANE_Auth_Callback authorize) { - /* char dev_name[PATH_MAX]; */ - FILE *fp; + FILE* fp; char line[PATH_MAX]; const char* cp = 0; char* word; int linenumber = 0; - + authorize = authorize; /* silence gcc */ - - DBG (3, "sane_init\n"); - + + DBG (3, "sane_init:\n"); + DBG_INIT(); - + if (version_code) *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BACKEND_BUILD); - + fp = sanei_config_open (AVISION_CONFIG_FILE); if (!fp) { /* default to /dev/scanner instead of insisting on config file */ attach ("/dev/scanner", 0); return SANE_STATUS_GOOD; } - + while (sanei_config_read (line, sizeof (line), fp)) { word = NULL; @@ -2727,6 +3917,12 @@ sane_init (SANE_Int* version_code, SANE_Auth_Callback authorize) linenumber); disable_calibration = SANE_TRUE; } + if (strcmp (word, "old-calibration") == 0) + { + DBG(3, "sane_init: config file line %d: old-calibration\n", + linenumber); + old_calibration = SANE_TRUE; + } if (strcmp (word, "one-calib-only") == 0) { DBG(3, "sane_init: config file line %d: one-calib-only\n", @@ -2739,6 +3935,12 @@ sane_init (SANE_Int* version_code, SANE_Auth_Callback authorize) linenumber); force_a4 = SANE_TRUE; } + if (strcmp (word, "disable-c5-guard") == 0) + { + DBG(3, "sane_init: config file line %d: disabling c5-guard\n", + linenumber); + disable_c5_guard = SANE_TRUE; + } } else { @@ -2750,19 +3952,20 @@ sane_init (SANE_Int* version_code, SANE_Auth_Callback authorize) word = NULL; } } + fclose (fp); if (word) free (word); + return SANE_STATUS_GOOD; } - void sane_exit (void) { Avision_Device *dev, *next; - DBG (3, "sane_exit\n"); + DBG (3, "sane_exit:\n"); for (dev = first_dev; dev; dev = next) { next = dev->next; @@ -2783,7 +3986,7 @@ sane_get_devices (const SANE_Device*** device_list, SANE_Bool local_only) local_only = local_only; /* silence gcc */ - DBG (3, "sane_get_devices\n"); + DBG (3, "sane_get_devices:\n"); if (devlist) free (devlist); @@ -2810,7 +4013,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) Avision_Scanner* s; int i, j; - DBG (3, "sane_open\n"); + DBG (3, "sane_open:\n"); if (devicename[0]) { for (dev = first_dev; dev; dev = dev->next) @@ -2857,16 +4060,14 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) return SANE_STATUS_GOOD; } - void sane_close (SANE_Handle handle) { Avision_Scanner *prev, *s; int i; - DBG (3, "sane_close\n"); - DBG (3, " \n"); - + DBG (3, "sane_close:\n\n"); + /* remove handle from list of open handles: */ prev = 0; for (s = first_handle; s; s = s->next) { @@ -2875,9 +4076,10 @@ sane_close (SANE_Handle handle) prev = s; } + /* a handle we know about ? */ if (!s) { - DBG (1, "close: invalid handle %p\n", handle); - return; /* oops, not a handle we know about */ + DBG (1, "sane_close: invalid handle %p\n", handle); + return; } if (s->scanning) @@ -2897,13 +4099,12 @@ sane_close (SANE_Handle handle) free (handle); } - const SANE_Option_Descriptor* sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) { Avision_Scanner* s = handle; - DBG (3, "sane_get_option_descriptor\n"); + DBG (3, "sane_get_option_descriptor:\n"); if ((unsigned) option >= NUM_OPTIONS) return 0; @@ -2918,7 +4119,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Status status; SANE_Word cap; - DBG (3, "sane_control_option\n"); + DBG (3, "sane_control_option:\n"); if (info) *info = 0; @@ -2954,6 +4155,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_QSCAN: case OPT_QCALIB: case OPT_TRANS: + case OPT_ADF: case OPT_FRAME: *(SANE_Word*) val = s->val[option].w; @@ -3000,6 +4202,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_QSCAN: case OPT_QCALIB: case OPT_TRANS: + case OPT_ADF: s->val[option].w = *(SANE_Word*) val; return SANE_STATUS_GOOD; @@ -3032,7 +4235,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; } - else /* grey or mono */ + else /* gray or mono */ { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; @@ -3066,83 +4269,107 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters* params) Avision_Scanner* s = handle; Avision_Device* dev = s->hw; - DBG (3, "sane_get_parameters\n"); - - if (!s->scanning) + DBG (3, "sane_get_parameters:\n"); + + /* during an acutal scan the parameters are used and thus are not alllowed + to change ... */ + if (!s->scanning) { + int boundary = get_pixel_boundary (s); + int gray_mode = ((s->mode == TRUECOLOR) || (s->mode == GRAYSCALE)); + + /* Official Avision fix C5 lineart bug. ?!? */ + if ((!gray_mode) && (dev->inquiry_asic_type == AV_ASIC_C5)) + boundary = 1; + + DBG (3, "sane_get_parameters: boundary %d, gray_mode: %d\n", + boundary, gray_mode); + s->avdimen.res = s->val[OPT_RESOLUTION].w; - DBG (1, "res: %i\n", s->avdimen.res); - /* the specs say they are specified in inch/1200 ... */ - s->avdimen.tlx = 1200.0 * SANE_UNFIX (s->val[OPT_TL_X].w) / MM_PER_INCH; - s->avdimen.tly = 1200.0 * SANE_UNFIX (s->val[OPT_TL_Y].w) / MM_PER_INCH; - s->avdimen.brx = 1200.0 * SANE_UNFIX (s->val[OPT_BR_X].w) / MM_PER_INCH; - s->avdimen.bry = 1200.0 * SANE_UNFIX (s->val[OPT_BR_Y].w) / MM_PER_INCH; + DBG (3, "sane_get_parameters: tlx: %f, tly: %f, brx: %f, bry: %f\n", + SANE_UNFIX (s->val[OPT_TL_X].w), SANE_UNFIX (s->val[OPT_TL_Y].w), + SANE_UNFIX (s->val[OPT_BR_X].w), SANE_UNFIX (s->val[OPT_BR_Y].w)); - DBG (1, "tlx: %ld, tly: %ld, brx %ld, bry %ld\n", s->avdimen.tlx, s->avdimen.tly, - s->avdimen.brx, s->avdimen.bry); + /* window parameter in pixel */ + s->avdimen.tlx = s->avdimen.res * SANE_UNFIX (s->val[OPT_TL_X].w) + / MM_PER_INCH; + s->avdimen.tly = s->avdimen.res * SANE_UNFIX (s->val[OPT_TL_Y].w) + / MM_PER_INCH; + s->avdimen.brx = s->avdimen.res * SANE_UNFIX (s->val[OPT_BR_X].w) + / MM_PER_INCH; + s->avdimen.bry = s->avdimen.res * SANE_UNFIX (s->val[OPT_BR_Y].w) + / MM_PER_INCH; + + /* line difference */ + if (s->mode == TRUECOLOR && dev->inquiry_needs_software_colorpack) + { + if (dev->hw->feature_type & AV_NO_LINE_DIFFERENCE) { + DBG (1, "sane_get_parameters: Line difference ignored due to device-list!!\n"); + } + else { + s->avdimen.line_difference + = (dev->inquiry_line_difference * s->avdimen.res) / + dev->inquiry_optical_res; + + s->avdimen.line_difference -= s->avdimen.line_difference % 3; + } + + s->avdimen.bry += s->avdimen.line_difference; + /* TODO: limit bry to max scan area */ + } /* end if needs software colorpack */ + else { + s->avdimen.line_difference = 0; + } s->avdimen.width = (s->avdimen.brx - s->avdimen.tlx); - s->avdimen.length = (s->avdimen.bry - s->avdimen.tly); + s->avdimen.width -= s->avdimen.width % boundary; + s->avdimen.height = (s->avdimen.bry - s->avdimen.tly); + + debug_print_avdimen (1, "sane_get_parameters", &s->avdimen); memset (&s->params, 0, sizeof (s->params)); - s->params.pixels_per_line = s->avdimen.width * s->avdimen.res / 1200; - s->params.lines = s->avdimen.length * s->avdimen.res / 1200; - s->avdimen.line_difference = 0; + + s->params.pixels_per_line = s->avdimen.width; + s->params.lines = s->avdimen.height - s->avdimen.line_difference; switch (s->mode) { case THRESHOLDED: - s->params.pixels_per_line -= - s->params.pixels_per_line % dev->inquiry_thresholded_boundary; s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line / 8; s->params.depth = 1; break; case DITHERED: - s->params.pixels_per_line -= - s->params.pixels_per_line % dev->inquiry_dithered_boundary; s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line / 8; s->params.depth = 1; break; - case GREYSCALE: - s->params.pixels_per_line -= - s->params.pixels_per_line % dev->inquiry_grey_boundary; + case GRAYSCALE: s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line; s->params.depth = 8; break; case TRUECOLOR: - /* bug check */ - if ( !dev->inquiry_needs_software_colorpack && s->avdimen.line_difference > 0) - DBG (1, "reader_process: HINT: no sofware-color-pack but line_def != 0\n"); - - if (dev->inquiry_needs_software_colorpack) - s->avdimen.line_difference = (dev->inquiry_line_difference - * s->avdimen.res) / dev->inquiry_optical_res; - s->params.pixels_per_line -= - s->params.pixels_per_line % dev->inquiry_color_boundary; - s->params.format = SANE_FRAME_RGB; - s->params.bytes_per_line = s->params.pixels_per_line * 3; + s->params.bytes_per_line = s->params.pixels_per_line * 3; s->params.depth = 8; break; } /* end switch */ - } /* end if scanning */ + + s->params.last_frame = SANE_TRUE; + + debug_print_params (1, "sane_get_parameters", &s->params); - /* compute the position coordinates we use now */ - s->avdimen.width = s->params.pixels_per_line * 1200 / s->avdimen.res; - s->avdimen.length = s->params.lines * 1200 / s->avdimen.res; - - DBG (1, "tlx: %ld, tly: %ld, brx %ld, bry %ld\n", - s->avdimen.tlx, s->avdimen.tly, - s->avdimen.width, s->avdimen.length); - - DBG (1, "pixel_per_line: %i, lines: %i, line_difference: %i\n", - s->params.pixels_per_line, s->params.lines, s->avdimen.line_difference); - - s->params.last_frame = SANE_TRUE; + /* C5 implements hardware scaling. + So modify s->params and s->avdimen. */ + + /* + if (!disable_c5_guard && dev->inquiry_asic_type == AV_ASIC_C5) { + c5_guard (s); + } + */ + } /* end if not scanning */ if (params) { *params = s->params; @@ -3160,7 +4387,7 @@ sane_start (SANE_Handle handle) SANE_Status status; int fds [2]; - DBG (3, "sane_start: page:\n", s->page); + DBG (3, "sane_start: page: %d\n", s->page); /* First make sure there is no scan running!!! */ @@ -3168,8 +4395,8 @@ sane_start (SANE_Handle handle) return SANE_STATUS_DEVICE_BUSY; /* Second make sure we have a current parameter set. Some of the - parameters will be overwritten below, but that's OK. */ - status = sane_get_parameters (s, 0); + parameters will be overwritten below, but that's OK. */ + status = sane_get_parameters (s, &s->params); if (status != SANE_STATUS_GOOD) { return status; @@ -3195,6 +4422,7 @@ sane_start (SANE_Handle handle) goto stop_scanner_and_return; } +#ifdef ADF_REVISITED_AND_NEEDED_FOR_OLDER_AVISIONS /* auto-feed next paper for ADF scanners */ if (dev->inquiry_adf && s->page > 0) { DBG (1, "sane_start: ADF next paper.\n"); @@ -3209,10 +4437,11 @@ sane_start (SANE_Handle handle) DBG(1, "sane_start: load paper failed: %s\n", sane_strstatus (status)); } +#endif /* Check for paper in sheetfeed scanners */ if (dev->hw->scanner_type == AV_SHEETFEED) { - status = check_paper(s); + status = check_paper (s); if (status != SANE_STATUS_GOOD) { DBG (1, "sane_start: check_paper() failed: %s\n", sane_strstatus (status)); goto stop_scanner_and_return; @@ -3230,17 +4459,50 @@ sane_start (SANE_Handle handle) goto stop_scanner_and_return; } +#ifdef DEBUG_TEST + /* debug window size test ... */ + if (dev->inquiry_new_protocol) + { + size_t size = 16; + u_int8_t result[16]; + + DBG (5, "sane_start: reading scanner window size\n"); + + status = simple_read (s, 0x80, 0, &size, result); + + if (status != SANE_STATUS_GOOD) { + DBG (1, "sane_start: get pixel size command failed: %s\n", + sane_strstatus (status)); + goto stop_scanner_and_return; + } + debug_print_raw (5, "sane_start: pixel_size:", result, size); + DBG (5, "sane_start: x-pixels: %d, y-pixels: %d\n", + get_quad (&(result[0])), get_quad (&(result[4]))); + } +#endif + /* Only perform the calibration for newer scanners - it is not needed for my Avision AV 630 - and also not even work ... */ + /* needs_calibration is not used for debugging purposes ... */ if (!dev->inquiry_new_protocol) { - DBG (1, "sane_start: old protocol - no calibration needed\n"); + DBG (1, "sane_start: old protocol no calibration needed!\n"); goto calib_end; } - /* check whether to do a claibration or not */ + if (!dev->inquiry_needs_calibration) { + DBG (1, "sane_start: due to inquiry no calibration needed!\n"); + goto calib_end; + } + /* calibration allowed for this scanner? */ + if (dev->hw->feature_type & AV_NO_CALIB) { + DBG (1, "sane_start: calibration disabled in device list!!\n"); + goto calib_end; + } + + /* check whether claibration is disabled by the user */ if (disable_calibration) { - DBG (1, "sane_start: calibration disabled - skipped\n"); + DBG (1, "sane_start: calibration disabled in config - skipped!\n"); goto calib_end; } @@ -3251,30 +4513,48 @@ sane_start (SANE_Handle handle) goto calib_end; } - status = perform_calibration (s); + if (old_calibration) + status = old_r_calibration (s); + else if (dev->inquiry_asic_type != AV_ASIC_C5 || disable_c5_guard) + status = normal_calibration (s); + else + status = c5_calibration (s); + if (status != SANE_STATUS_GOOD) { DBG (1, "sane_start: perform calibration failed: %s\n", sane_strstatus (status)); goto stop_scanner_and_return; } + dev->is_calibrated = SANE_TRUE; - calib_end: + calib_end: - if (!disable_gamma_table) { - status = set_gamma (s); - if (status != SANE_STATUS_GOOD) { - DBG (1, "sane_start: set gamma failed: %s\n", - sane_strstatus (status)); - goto stop_scanner_and_return; - } + /* check whether gamma-taable is disabled by the user? */ + if (disable_gamma_table) { + DBG (1, "sane_start: gamma-table disabled in config - skipped!\n"); + goto gamma_end; } - else - DBG (1, "sane_start: gamma-table disabled - skipped\n"); + + /* gamma-table allowed for this scanner? */ + if (dev->hw->feature_type & AV_NO_GAMMA) { + DBG (1, "sane_start: gamma-table disabled in device list!!\n"); + goto gamma_end; + } + + status = set_gamma (s); + if (status != SANE_STATUS_GOOD) { + DBG (1, "sane_start: set gamma failed: %s\n", + sane_strstatus (status)); + goto stop_scanner_and_return; + } + + gamma_end: /* check film holder */ if (dev->hw->scanner_type == AV_FILM && dev->holder_type == 0xff) { DBG (1, "sane_start: no film holder or APS cassette!\n"); + /* Normally "go_home" is executed from the reader process, but as it will not start we have to reset things here */ if (dev->inquiry_new_protocol) { @@ -3325,7 +4605,7 @@ sane_start (SANE_Handle handle) stop_scanner_and_return: - /* cancel the scan nicely and do a "go_home" for the new_protocol */ + /* cancel the scan nicely */ do_cancel (s); return status; @@ -3337,12 +4617,12 @@ sane_read (SANE_Handle handle, SANE_Byte* buf, SANE_Int max_len, SANE_Int* len) Avision_Scanner* s = handle; ssize_t nread; - DBG (3, "sane_read\n"); + DBG (3, "sane_read: max_len: %d\n", max_len); *len = 0; nread = read (s->pipe, buf, max_len); - DBG (3, "sane_read: read %d bytes\n", nread); + DBG (3, "sane_read: got %d bytes\n", nread); if (!s->scanning) return SANE_STATUS_CANCELLED; @@ -3383,7 +4663,7 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) { Avision_Scanner* s = handle; - DBG (3, "sane_set_io_mode\n"); + DBG (3, "sane_set_io_mode:\n"); if (!s->scanning) return SANE_STATUS_INVAL; @@ -3394,11 +4674,11 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) } SANE_Status -sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) +sane_get_select_fd (SANE_Handle handle, SANE_Int* fd) { Avision_Scanner* s = handle; - DBG (3, "sane_get_select_fd\n"); + DBG (3, "sane_get_select_fd:\n"); if (!s->scanning) return SANE_STATUS_INVAL; diff --git a/backend/avision.conf b/backend/avision.conf index 4c9c1a457..6738b23bc 100644 --- a/backend/avision.conf +++ b/backend/avision.conf @@ -1,3 +1,11 @@ + +#option disable-gamma-table +#option disable-calibration +#option old-calibration +#option one-calib-only +#option force-a4 +#option disable-c5-guard + scsi AVISION scsi FCPA scsi MINOLTA @@ -8,8 +16,3 @@ scsi hp /dev/scanner -#option disable-gamma-table -#option disable-calibration -#option one-calib-only -#option force-a4 - diff --git a/backend/avision.h b/backend/avision.h index fbf04a2ab..ed8ba389a 100644 --- a/backend/avision.h +++ b/backend/avision.h @@ -59,6 +59,7 @@ Very much thanks to: Oliver Neukum who sponsored a HP 5300 USB scanner !!! ;-) + Avision INC for sponsoring a AV 8000S with ADF !!! ;-) Avision INC for the documentation we got! ;-) Check the avision.c file for a ChangeLog ... @@ -87,17 +88,34 @@ typedef struct Avision_HWEntry { /* feature overwrites */ enum { - /* use single command calibraion send (i.e. all new scanners) */ - AV_CALIB2 = 1, - /* use 512 bytes gamma table (i.e. Minolta film-scanner) */ - AV_GAMMA2 = 2, - /* use 256 bytes gamma table (i.e. HP 5370C) */ - AV_GAMMA3 = 4 - /* more to come ... */ + /* force no calibration */ + AV_NO_CALIB = 1, + + /* force the special C5 calibration */ + AV_C5_CALIB = 2, + + /* no gamma table */ + AV_NO_GAMMA = 4, + + /* light check is bogus */ + AV_LIGHT_CHECK_BOGUS = 8, + + /* do not use line packing even if line_difference */ + AV_NO_LINE_DIFFERENCE = 16 + + /* maybe more ...*/ } feature_type; } Avision_HWEntry; +enum asic_type { + AV_ASIC_Cx = 0, + AV_ASIC_C1 = 1, + AV_ASIC_C2 = 3, + AV_ASIC_C5 = 5, + AV_ASIC_OA980 = 128 +}; + enum Avision_Option { OPT_NUM_OPTS = 0, /* must come first */ @@ -122,8 +140,9 @@ enum Avision_Option OPT_QSCAN, OPT_QCALIB, OPT_TRANS, /* Transparency Mode */ + OPT_ADF, /* Use ADF unit */ - OPT_GAMMA_VECTOR, /* first must be grey */ + OPT_GAMMA_VECTOR, /* first must be gray */ OPT_GAMMA_VECTOR_R, /* then r g b vector */ OPT_GAMMA_VECTOR_G, OPT_GAMMA_VECTOR_B, @@ -144,17 +163,18 @@ typedef struct Avision_Dimensions { /* in dpi */ int res; - int resx; - int rexy; - /* in 1200/dpi */ + /* int resx; + int rexy; */ + + /* in pixels */ long tlx; long tly; long brx; long bry; long width; - long length; + long height; /* in pixels */ int line_difference; @@ -173,14 +193,23 @@ typedef struct Avision_Device SANE_Range y_range; SANE_Range speed_range; + enum asic_type inquiry_asic_type; SANE_Bool inquiry_new_protocol; + SANE_Bool inquiry_adf; SANE_Bool inquiry_detect_accessories; SANE_Bool inquiry_needs_calibration; SANE_Bool inquiry_needs_gamma; + SANE_Bool inquiry_calibration; + SANE_Bool inquiry_3x3_matrix; SANE_Bool inquiry_needs_software_colorpack; + SANE_Bool inquiry_needs_line_pack; + SANE_Bool inquiry_adf_need_mirror; + SANE_Bool inquiry_light_detect; + SANE_Bool inquiry_light_control; + int inquiry_max_shading_target; - int inquiry_optical_res; /* in dpi */ - int inquiry_max_res; /* in dpi */ + int inquiry_optical_res; /* in dpi */ + int inquiry_max_res; /* in dpi */ double inquiry_x_range; /* in mm */ double inquiry_y_range; /* in mm */ @@ -192,7 +221,7 @@ typedef struct Avision_Device double inquiry_transp_y_range; /* in mm */ int inquiry_color_boundary; - int inquiry_grey_boundary; + int inquiry_gray_boundary; int inquiry_dithered_boundary; int inquiry_thresholded_boundary; int inquiry_line_difference; /* software color pack */ @@ -200,14 +229,19 @@ typedef struct Avision_Device /* int inquiry_bits_per_channel; */ /* accessories */ - SANE_Bool inquiry_adf; - SANE_Bool inquiry_light_box; + SANE_Bool acc_light_box; + SANE_Bool acc_adf; + + SANE_Bool is_adf; /* ADF scanner */ /* film scanner atributes - maybe these should be in the scanner struct? */ SANE_Range frame_range; SANE_Word current_frame; SANE_Word holder_type; + /* some versin corrections */ + u_int16_t data_dq; /* was ox0A0D - but hangs some new scanners */ + /* driver state */ SANE_Bool is_calibrated; @@ -243,6 +277,13 @@ typedef struct Avision_Scanner } Avision_Scanner; +/* modes */ +#define THRESHOLDED 0 +#define DITHERED 1 +#define GRAYSCALE 2 +#define TRUECOLOR 3 + +/* scsi command defines */ #define AV_ADF_ON 0x80 #define AV_QSCAN_ON 0x10 @@ -250,11 +291,6 @@ typedef struct Avision_Scanner #define AV_TRANS_ON 0x80 #define AV_INVERSE_ON 0x20 -#define THRESHOLDED 0 -#define DITHERED 1 -#define GREYSCALE 2 -#define TRUECOLOR 3 - /* request sense */ #define VALID (SANE_Byte) (0x01<<7) #define VALID_BYTE (SANE_Int ) (0x00) @@ -357,48 +393,49 @@ typedef struct Avision_Scanner #define AVISION_SCSI_OP_REJECT_PAPER 0x00 #define AVISION_SCSI_OP_LOAD_PAPER 0x01 #define AVISION_SCSI_OP_GO_HOME 0x02 -#define AVISION_SCSI_OP_TRANS_CALIB_GREY 0x04 +#define AVISION_SCSI_OP_TRANS_CALIB_GRAY 0x04 #define AVISION_SCSI_OP_TRANS_CALIB_COLOR 0x05 /* The structures that you have to send to an avision to get it to do various stuff... */ -struct command_header +typedef struct command_header { u_int8_t opc; u_int8_t pad0 [3]; u_int8_t len; u_int8_t pad1; -}; +} command_header; -struct command_set_window +typedef struct command_set_window { u_int8_t opc; u_int8_t reserved0 [5]; u_int8_t transferlen [3]; u_int8_t control; -}; +} command_set_window; -struct command_read +typedef struct command_read { u_int8_t opc; u_int8_t bitset1; u_int8_t datatypecode; - u_int8_t calibchn; + u_int8_t readtype; u_int8_t datatypequal [2]; u_int8_t transferlen [3]; u_int8_t control; -}; +} command_read; -struct command_scan +typedef struct command_scan { u_int8_t opc; - u_int8_t pad0 [3]; + u_int8_t bitset0; + u_int8_t reserved0 [2]; u_int8_t transferlen; u_int8_t bitset1; -}; +} command_scan; -struct command_send +typedef struct command_send { u_int8_t opc; u_int8_t bitset1; @@ -407,18 +444,18 @@ struct command_send u_int8_t datatypequal [2]; u_int8_t transferlen [3]; u_int8_t reserved1; -}; +} command_send; -struct command_set_window_window_header +typedef struct command_set_window_window_header { u_int8_t reserved0 [6]; u_int8_t desclen [2]; -}; +} command_set_window_window_header; -struct command_set_window_window_descriptor +typedef struct command_set_window_window_descriptor { u_int8_t winid; - u_int8_t pad0; + u_int8_t reserved0; u_int8_t xres [2]; u_int8_t yres [2]; u_int8_t ulx [4]; @@ -426,16 +463,16 @@ struct command_set_window_window_descriptor u_int8_t width [4]; u_int8_t length [4]; u_int8_t brightness; - u_int8_t thresh; + u_int8_t threshold; u_int8_t contrast; u_int8_t image_comp; u_int8_t bpc; u_int8_t halftone [2]; - u_int8_t pad_type; + u_int8_t padding_and_bitset; u_int8_t bitordering [2]; u_int8_t compr_type; u_int8_t compr_arg; - u_int8_t pad4 [6]; + u_int8_t reserved1 [6]; u_int8_t vendor_specid; u_int8_t paralen; u_int8_t bitset1; @@ -444,21 +481,27 @@ struct command_set_window_window_descriptor u_int8_t linewidth [2]; u_int8_t linecount [2]; u_int8_t bitset2; - u_int8_t pad5; + u_int8_t ir_exposure_time; u_int8_t r_exposure_time [2]; u_int8_t g_exposure_time [2]; u_int8_t b_exposure_time [2]; -}; + + u_int8_t bitset3; + u_int8_t auto_focus; + u_int8_t line_width_msb; + u_int8_t line_count_msb; + u_int8_t edge_threshold; +} command_set_window_window_descriptor; -struct page_header +typedef struct page_header { u_int8_t pad0 [4]; u_int8_t code; u_int8_t length; -}; +} page_header; -struct avision_page +typedef struct avision_page { u_int8_t gamma; u_int8_t thresh; @@ -466,24 +509,57 @@ struct avision_page u_int8_t delay; u_int8_t features; u_int8_t pad0; -}; +} avision_page; -/* set SCSI highended variables. Declare them as an array of chars */ +typedef struct calibration_format +{ + u_int16_t pixel_per_line; + u_int8_t bytes_per_channel; + u_int8_t lines; + u_int8_t flags; + u_int8_t ability1; + u_int8_t r_gain; + u_int8_t g_gain; + u_int8_t b_gain; + u_int16_t r_shading_target; + u_int16_t g_shading_target; + u_int16_t b_shading_target; + u_int16_t r_dark_shading_target; + u_int16_t g_dark_shading_target; + u_int16_t b_dark_shading_target; + + /* not returned but usefull in some places */ + u_int8_t channels; +} calibration_format; + + +/* set/get SCSI highended variables. Declare them as an array of chars */ /* endianness-safe, int-size safe... */ #define set_double(var,val) var[0] = ((val) >> 8) & 0xff; \ - var[1] = ((val) ) & 0xff; + var[1] = ((val) ) & 0xff #define set_triple(var,val) var[0] = ((val) >> 16) & 0xff; \ var[1] = ((val) >> 8 ) & 0xff; \ - var[2] = ((val) ) & 0xff; + var[2] = ((val) ) & 0xff #define set_quad(var,val) var[0] = ((val) >> 24) & 0xff; \ var[1] = ((val) >> 16) & 0xff; \ var[2] = ((val) >> 8 ) & 0xff; \ - var[3] = ((val) ) & 0xff; + var[3] = ((val) ) & 0xff + +#define get_double(var) (*var << 8) + *(var + 1) + +#define get_triple(var) (*var << 16) + \ + (*(var + 1) << 8) + * *var + +#define get_quad(var) (*var << 24) + \ + (*(var + 1) << 16) + \ + (*(var + 2) << 8) + *(var + 3) #define BIT(n, p) ((n & ( 1 << p))?1:0) +#define SET_BIT(n, p) (n |= 1 << p) + /* These should be in saneopts.h */ #define SANE_NAME_FRAME "frame" #define SANE_TITLE_FRAME SANE_I18N("Number of the frame to scan") diff --git a/doc/sane-avision.man b/doc/sane-avision.man index d9f7f3674..96b7a384b 100644 --- a/doc/sane-avision.man +++ b/doc/sane-avision.man @@ -1,4 +1,4 @@ -.TH sane-avision 5 "07 Julc 2002" +.TH sane-avision 5 "04 Nov 2002" .IX sane-avision .SH NAME @@ -22,23 +22,25 @@ The configuration file for this backend resides in @CONFIGDIR@/avision.conf. Its contents is a list of device names that correspond to Avision and Avision -compatible scanners. Empty lines and lines starting with a hash mark (#) are -ignored. A sample configuration file is shown below: +compatible scanners and backend-options. Empty lines and lines starting with +a hash mark (#) are ignored. A sample configuration file is shown below: .B I suggest you hold one hand on the power-button of the scanner while you try the first scans! - #scsi Vendor Model Type Bus Channel ID LUN - scsi AVISION - /dev/scanner - # this is a comment - # + option force-a4 option disable-gamma-table option disable-calibration - option disable-calibration option one-calib-only + option old-calibration + option disable-c5-guard + + #scsi Vendor Model Type Bus Channel ID LUN + scsi AVISION + scsi HP + /dev/scanner - force-a4: Forces the backend to overwrite the scanable area @@ -57,13 +59,29 @@ the first scans! might try this if your scans hang or only produces random garbage. - - one-calib-only + - one-calib-only: When this option is enabled, the backend will only perform a calibration when the backend is initialized and not before each scan. This might extend the life of the CCD, but does not work reliable with the newer USB scanners (they hang sometimes or return garbage image data). So this option should be used with care. + + - old-calibration: + This enables the use of the old calibration code for + testing purposes. + + - disable-c5-guard: + This disables the alpha-quality code normally needed + for newer USB scanners (e.g. HP 5370) to compute some + values for the hardware scaling. + + Note: Any option above modifies the default code-flow + for your scanner. The options should only be used + when you encounter problems with the default be- + haviour of the backend. Please report the need of + options to the backend-author so the backend can + be fixed as soon as possible. .SH "DEVICE NAMES" This backend expects device names of the form: @@ -117,11 +135,12 @@ to "/tmp/config:" would result in directories "tmp/config", ".", and .TP .B SANE_DEBUG_AVISION If the library was compiled with debug support enabled, this -environment variable controls the debug level for this backend. Higher -debug levels increase the verbosity of the output. +environment variable controls the debug level for this backend. +Higher debug levels increase the verbosity of the output. The debug +level 7 is the author's prefered value to debug backend problems. Example: -export SANE_DEBUG_AVISION=4 +export SANE_DEBUG_AVISION=7 .SH "SEE ALSO" sane(7), sane\-scsi(5)