summaryrefslogtreecommitdiff
path: root/backend/mustek_usb_high.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/mustek_usb_high.c')
-rw-r--r--backend/mustek_usb_high.c2751
1 files changed, 2751 insertions, 0 deletions
diff --git a/backend/mustek_usb_high.c b/backend/mustek_usb_high.c
new file mode 100644
index 0000000..f6a0125
--- /dev/null
+++ b/backend/mustek_usb_high.c
@@ -0,0 +1,2751 @@
+/* sane - Scanner Access Now Easy.
+
+ Copyright (C) 2000 Mustek.
+ Originally maintained by Tom Wang <tom.wang@mustek.com.tw>
+
+ Copyright (C) 2001, 2002 by Henning Meier-Geinitz.
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice.
+
+ This file implements a SANE backend for Mustek 1200UB and similar
+ USB flatbed scanners. */
+
+#include "mustek_usb_high.h"
+#include "mustek_usb_mid.c"
+
+/* ------------------------ calibration functions ------------------------- */
+
+static SANE_Byte gray_map[8] = {
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static inline double
+filter_lower_end (SANE_Int * buffer, SANE_Word total_count,
+ SANE_Word filter_count)
+{
+ SANE_Word bound = total_count - 1;
+ SANE_Word left_count = total_count - filter_count;
+ SANE_Int temp = 0;
+ SANE_Word i, j;
+ SANE_Int sum = 0;
+
+ for (i = 0; i < bound; i++)
+ {
+ for (j = 0; j < bound - i; j++)
+ {
+ if (buffer[j + 1] > buffer[j])
+ {
+ temp = buffer[j];
+ buffer[j] = buffer[j + 1];
+ buffer[j + 1] = temp;
+ }
+ }
+ }
+ for (i = 0; i < left_count; i++)
+ sum += buffer[i];
+ return (double) sum;
+}
+
+SANE_Status
+usb_high_cal_init (Calibrator * cal, SANE_Byte type, SANE_Word target_white,
+ SANE_Word target_dark)
+{
+ DBG (5, "usb_high_cal_init: start, cal=%p, type=%d, target_white=%d "
+ "target_dark=%d\n", (void *) cal, type, target_white, target_dark);
+ cal->is_prepared = SANE_FALSE;
+ cal->k_white = NULL;
+ cal->k_dark = NULL;
+ /* Working Buffer */
+ cal->white_line = NULL;
+ cal->dark_line = NULL;
+ cal->white_buffer = NULL;
+ /* Necessary Parameters */
+ cal->k_white_level = 240 << 8;
+ cal->k_dark_level = 0;
+ cal->threshold = 2048;
+ cal->major_average = 0;
+ cal->minor_average = 0;
+ cal->filter = 0;
+ cal->white_needed = 0;
+ cal->dark_needed = 0;
+ cal->max_width = 0;
+ cal->width = 100;
+ cal->gamma_table = 0;
+ cal->calibrator_type = type;
+ cal->k_white_level = target_white / 16;
+ cal->k_dark_level = 0;
+ DBG (5, "usb_high_cal_init: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_exit (Calibrator * cal)
+{
+ DBG (5, "usb_high_cal_exit: start\n");
+
+ if (!cal)
+ {
+ DBG (3, "usb_high_cal_exit: cal == NULL\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_exit: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ DBG (5, "usb_high_cal_exit: 1\n");
+
+ if (cal->k_dark)
+ {
+ free (cal->k_dark);
+ }
+ cal->k_dark = NULL;
+ DBG (5, "usb_high_cal_exit: 2\n");
+ if (cal->k_white)
+ {
+ free (cal->k_white);
+ }
+ cal->k_white = NULL;
+ DBG (5, "usb_high_cal_exit: 3\n");
+
+ cal->is_prepared = SANE_FALSE;
+ DBG (5, "usb_high_cal_exit: 4\n");
+ DBG (5, "usb_high_cal_exit: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_embed_gamma (Calibrator * cal, SANE_Word * gamma_table)
+{
+ DBG (5, "usb_high_cal_embed_gamma: start\n");
+ cal->gamma_table = gamma_table;
+ DBG (5, "usb_high_cal_embed_gamma: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_prepare (Calibrator * cal, SANE_Word max_width)
+{
+ DBG (5, "usb_high_cal_Parepare: start\n");
+
+ if (cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_Parepare: is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ if (cal->k_white)
+ {
+ free (cal->k_white);
+ }
+ cal->k_white = (SANE_Word *) malloc (max_width * sizeof (SANE_Word));
+ if (!cal->k_white)
+ return SANE_STATUS_NO_MEM;
+
+ if (cal->k_dark)
+ {
+ free (cal->k_dark);
+ }
+ cal->k_dark = (SANE_Word *) malloc (max_width * sizeof (SANE_Word));
+ if (!cal->k_dark)
+ return SANE_STATUS_NO_MEM;
+
+ cal->max_width = max_width;
+
+ cal->is_prepared = SANE_TRUE;
+
+ DBG (5, "usb_high_cal_Parepare: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+usb_high_cal_setup (Calibrator * cal, SANE_Word major_average,
+ SANE_Word minor_average, SANE_Word filter,
+ SANE_Word width, SANE_Word * white_needed,
+ SANE_Word * dark_needed)
+{
+ SANE_Int i;
+
+ DBG (5, "usb_high_cal_setup: start\n");
+
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_setup: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (major_average == 0)
+ {
+ DBG (3, "usb_high_cal_setup: major_average==0\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (minor_average == 0)
+ {
+ DBG (3, "usb_high_cal_setup: minor_average==0\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (width > cal->max_width)
+ {
+ DBG (3, "usb_high_cal_setup: width>max_width\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ cal->major_average = major_average;
+ cal->minor_average = minor_average;
+ cal->filter = filter;
+ cal->width = width;
+ cal->white_needed = major_average * 16 + filter;
+ cal->dark_needed = major_average * 16;
+ *white_needed = cal->white_needed;
+ *dark_needed = cal->dark_needed;
+
+ if (cal->white_line)
+ {
+ free (cal->white_line);
+ }
+ cal->white_line = (double *) malloc (cal->width * sizeof (double));
+ if (!cal->white_line)
+ return SANE_STATUS_NO_MEM;
+
+ if (cal->dark_line)
+ {
+ free (cal->dark_line);
+ }
+ cal->dark_line = (double *) malloc (cal->width * sizeof (double));
+ if (!cal->dark_line)
+ return SANE_STATUS_NO_MEM;
+
+ for (i = 0; i < cal->width; i++)
+ {
+ cal->white_line[i] = 0.0;
+ cal->dark_line[i] = 0.0;
+ }
+
+ if (cal->white_buffer)
+ {
+ free (cal->white_buffer);
+ }
+ cal->white_buffer =
+ (SANE_Int *) malloc (cal->white_needed * cal->width * sizeof (SANE_Int));
+ if (!cal->white_buffer)
+ return SANE_STATUS_NO_MEM;
+
+ for (i = 0; i < cal->white_needed * cal->width; i++)
+ {
+ *(cal->white_buffer + i) = 0;
+ }
+
+ return SANE_STATUS_GOOD;
+ DBG (5, "usb_high_cal_setup: start\n");
+}
+
+SANE_Status
+usb_high_cal_evaluate_white (Calibrator * cal, double factor)
+{
+ /* Caculate white_line */
+ double loop_division;
+ double average;
+ SANE_Int *buffer;
+ SANE_Word i, j;
+
+ DBG (5, "usb_high_cal_evaluate_white: start\n");
+ loop_division = (double) (cal->major_average * cal->minor_average);
+ buffer = (SANE_Int *) malloc (cal->white_needed * sizeof (SANE_Int));
+ if (!buffer)
+ return SANE_STATUS_NO_MEM;
+
+ if (cal->white_buffer == NULL)
+ {
+ DBG (3, "usb_high_cal_evaluate_white: white_buffer==NULL\n");
+ return SANE_STATUS_NO_MEM;
+ }
+
+ for (i = 0; i < cal->width; i++)
+ {
+ for (j = 0; j < cal->white_needed; j++)
+ {
+ *(buffer + j) = *(cal->white_buffer + j * cal->width + i);
+ }
+ average =
+ filter_lower_end (buffer, cal->white_needed,
+ cal->filter) * factor / loop_division;
+ if (average >= 4096.0)
+ cal->white_line[i] = 4095.9999;
+ else if (average < 0.0)
+ cal->white_line[i] = 0.0;
+ else
+ cal->white_line[i] = average;
+ }
+ free (buffer);
+ buffer = NULL;
+ free (cal->white_buffer);
+ cal->white_buffer = NULL;
+ DBG (5, "usb_high_cal_evaluate_white: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_evaluate_dark (Calibrator * cal, double factor)
+{
+ SANE_Word i;
+ double loop_division;
+
+ DBG (5, "usb_high_cal_evaluate_dark: start\n");
+ /* Caculate dark_line */
+ factor *= 16.0;
+ loop_division = (double) (cal->major_average * cal->minor_average);
+ for (i = 0; i < cal->width; i++)
+ {
+ cal->dark_line[i] /= loop_division;
+ cal->dark_line[i] -= factor;
+ if (cal->dark_line[i] < 0.0)
+ cal->dark_line[i] = 0.0;
+ }
+ DBG (5, "usb_high_cal_evaluate_dark: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_evaluate_calibrator (Calibrator * cal)
+{
+ SANE_Int average = 0;
+ SANE_Word i;
+
+ DBG (5, "usb_high_cal_evaluate_calibrator: start\n");
+ if (cal->white_line == NULL)
+ {
+ DBG (3, "usb_high_cal_evaluate_calibrator: white_line==NULL\n");
+ return SANE_FALSE;
+ }
+ if (cal->dark_line == NULL)
+ {
+ DBG (3, "usb_high_cal_evaluate_calibrator: dark_line==NULL\n");
+ return SANE_FALSE;
+ }
+
+ for (i = 0; i < cal->width; i++)
+ {
+ average = (SANE_Int) (cal->white_line[i])
+ - (SANE_Int) (cal->dark_line[i]);
+ if (average <= 0)
+ average = 1;
+ else if (average >= 4096)
+ average = 4095;
+ cal->k_white[i] = (SANE_Word) (average);
+ cal->k_dark[i] = (SANE_Word) (cal->dark_line[i]);
+ }
+ free (cal->dark_line);
+ cal->dark_line = NULL;
+ free (cal->white_line);
+ cal->white_line = NULL;
+
+ DBG (5, "usb_high_cal_evaluate_calibrator: start\n");
+ return SANE_STATUS_GOOD;
+}
+
+/* virtual function switcher */
+SANE_Status
+usb_high_cal_fill_in_white (Calibrator * cal, SANE_Word major,
+ SANE_Word minor, void *white_pattern)
+{
+ DBG (5, "usb_high_cal_fill_in_white: start\n");
+ switch (cal->calibrator_type)
+ {
+ case I8O8RGB:
+ case I8O8MONO:
+ return usb_high_cal_i8o8_fill_in_white (cal, major, minor,
+ white_pattern);
+ break;
+ case I4O1MONO:
+ return usb_high_cal_i4o1_fill_in_white (cal, major, minor,
+ white_pattern);
+ break;
+ }
+ DBG (5, "usb_high_cal_fill_in_white: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_fill_in_dark (Calibrator * cal, SANE_Word major, SANE_Word minor,
+ void *dark_pattern)
+{
+ DBG (5, "usb_high_cal_fill_in_dark: start\n");
+ switch (cal->calibrator_type)
+ {
+ case I8O8RGB:
+ case I8O8MONO:
+ return usb_high_cal_i8o8_fill_in_dark (cal, major, minor, dark_pattern);
+ break;
+ case I4O1MONO:
+ return usb_high_cal_i4o1_fill_in_dark (cal, major, minor, dark_pattern);
+ break;
+ }
+ DBG (5, "usb_high_cal_fill_in_dark: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_calibrate (Calibrator * cal, void *src, void *target)
+{
+ DBG (5, "usb_high_cal_calibrate: start\n");
+ switch (cal->calibrator_type)
+ {
+ case I8O8RGB:
+ return usb_high_cal_i8o8_rgb_calibrate (cal, src, target);
+ break;
+ case I8O8MONO:
+ return usb_high_cal_i8o8_mono_calibrate (cal, src, target);
+ break;
+ case I4O1MONO:
+ return usb_high_cal_i4o1_calibrate (cal, src, target);
+ break;
+ }
+ DBG (5, "usb_high_cal_calibrate: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i8o8_fill_in_white (Calibrator * cal, SANE_Word major,
+ SANE_Word minor, void *white_pattern)
+{
+ SANE_Byte *pattern;
+ SANE_Word j;
+
+ pattern = (SANE_Byte *) white_pattern;
+
+ DBG (5, "usb_high_cal_i8o8_fill_in_white: start, minor=%d\n", minor);
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_i8o8_fill_in_white: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (cal->white_needed == 0)
+ {
+ DBG (3, "usb_high_cal_i8o8_fill_in_white: white_needed==0\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ for (j = 0; j < cal->width; j++)
+ {
+ *(cal->white_buffer + major * cal->width + j) +=
+ (SANE_Int) (pattern[j]);
+ }
+ DBG (5, "usb_high_cal_i8o8_fill_in_white: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i8o8_fill_in_dark (Calibrator * cal, SANE_Word major,
+ SANE_Word minor, void *dark_pattern)
+{
+ SANE_Byte *pattern = (SANE_Byte *) dark_pattern;
+ SANE_Word j;
+
+ DBG (5, "usb_high_cal_i8o8_fill_in_dark: start, major=%d, minor=%d\n",
+ major, minor);
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_i8o8_fill_in_dark: !is_prepared\n");
+ return SANE_FALSE;
+ }
+ if (cal->dark_needed == 0)
+ {
+ DBG (3, "usb_high_cal_i8o8_fill_in_dark: dark_needed==0\n");
+ return SANE_FALSE;
+ }
+
+ for (j = 0; j < cal->width; j++)
+ {
+ cal->dark_line[j] += (double) (pattern[j]);
+ }
+ DBG (5, "usb_high_cal_i8o8_fill_in_dark: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i4o1_fill_in_white (Calibrator * cal, SANE_Word major,
+ SANE_Word minor, void *white_pattern)
+{
+ SANE_Byte *pattern;
+ SANE_Word j = 0;
+
+ pattern = (SANE_Byte *) white_pattern;
+
+ DBG (5, "usb_high_cal_i4o1_fill_in_white: minor=%d\n", minor);
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_i4o1_fill_in_white: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (cal->white_needed == 0)
+ {
+ DBG (3, "usb_high_cal_i4o1_fill_in_white: white_needed==0\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ while (j < cal->width)
+ {
+ *(cal->white_buffer + major * cal->width + j) +=
+ (SANE_Int) (*(pattern) & 0xf0);
+ j++;
+ if (j >= cal->width)
+ break;
+ *(cal->white_buffer + major * cal->width + j) +=
+ (SANE_Int) ((SANE_Byte) (*(pattern++) << 4));
+ j++;
+ }
+ DBG (5, "usb_high_cal_i8o8_fill_in_white: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i4o1_fill_in_dark (Calibrator * cal, SANE_Word major,
+ SANE_Word minor, void *dark_pattern)
+{
+ SANE_Byte *pattern;
+ SANE_Word j = 0;
+
+ pattern = (SANE_Byte *) dark_pattern;
+
+ DBG (5, "usb_high_cal_i4o1_fill_in_dark: start, major=%d, minor=%d\n",
+ major, minor);
+ if (!cal->is_prepared)
+ {
+ DBG (3, "usb_high_cal_i4o1_fill_in_dark: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (cal->dark_needed == 0)
+ {
+ DBG (5, "usb_high_cal_i4o1_fill_in_dark: dark_needed==0\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ while (j < cal->width)
+ {
+ cal->dark_line[j++] += (double) (*(pattern) & 0xf0);
+ if (j >= cal->width)
+ break;
+ cal->dark_line[j++] += (double) ((SANE_Byte) (*(pattern++) << 4));
+ }
+ DBG (5, "usb_high_cal_i4o1_fill_in_dark: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i8o8_mono_calibrate (Calibrator * cal, void *src, void *target)
+{
+ SANE_Byte *gray_src;
+ SANE_Byte *gray_target;
+ SANE_Int base = 0;
+ SANE_Word value = 0;
+ SANE_Word i;
+
+ DBG (5, "usb_high_cal_i8o8_mono_calibrate: start\n");
+
+ gray_src = (SANE_Byte *) src;
+ gray_target = (SANE_Byte *) target;
+
+ if (cal->gamma_table == NULL)
+ {
+ SANE_Word k_white_level = cal->k_white_level >> 4;
+ for (i = 0; i < cal->width; i++)
+ {
+ base = (SANE_Int) ((SANE_Word) (gray_src[i]) << 4)
+ - (SANE_Int) (cal->k_dark[i]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * k_white_level) / cal->k_white[i];
+ if (value > 0x00ff)
+ value = 0x00ff;
+ gray_target[i] = (SANE_Byte) (value);
+ }
+ }
+ else
+ {
+ for (i = 0; i < cal->width; i++)
+ {
+ base = (SANE_Int) ((SANE_Word) (gray_src[i]) << 4)
+ - (SANE_Int) (cal->k_dark[i]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * cal->k_white_level) / cal->k_white[i];
+ if (value > 0x0fff)
+ value = 0x0fff;
+ gray_target[i] = (SANE_Byte) (cal->gamma_table[value]);
+ }
+ }
+ DBG (5, "usb_high_cal_i8o8_mono_calibrate: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i8o8_rgb_calibrate (Calibrator * cal, void *src, void *target)
+{
+ SANE_Byte *gray_src;
+ SANE_Byte *rgb_target;
+ SANE_Int base = 0;
+ SANE_Word value = 0;
+ SANE_Word i;
+
+ DBG (5, "usb_high_cal_i8o8_rgb_calibrate: start\n");
+ gray_src = (SANE_Byte *) src;
+ rgb_target = (SANE_Byte *) target;
+
+ if (cal->gamma_table == NULL)
+ {
+ SANE_Word k_white_level = cal->k_white_level >> 4;
+ for (i = 0; i < cal->width; i++)
+ {
+ base = (SANE_Int) ((SANE_Word) (gray_src[i]) << 4)
+ - (SANE_Int) (cal->k_dark[i]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * k_white_level) / cal->k_white[i];
+ if (value > 0x00ff)
+ value = 0x00ff;
+ *rgb_target = (SANE_Byte) (value);
+ rgb_target += 3;
+ }
+ }
+ else
+ {
+ for (i = 0; i < cal->width; i++)
+ {
+ base = (SANE_Int) ((SANE_Word) (gray_src[i]) << 4)
+ - (SANE_Int) (cal->k_dark[i]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * cal->k_white_level) / cal->k_white[i];
+ if (value > 0x0fff)
+ value = 0x0fff;
+ *(rgb_target) = (SANE_Byte) (cal->gamma_table[value]);
+ rgb_target += 3;
+ }
+ }
+ DBG (5, "usb_high_cal_i8o8_rgb_calibrate: start\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_cal_i4o1_calibrate (Calibrator * cal, void *src, void *target)
+{
+ SANE_Byte *local_src;
+ SANE_Byte *local_target;
+ SANE_Int base = 0;
+ SANE_Word value = 0;
+ SANE_Word j = 0;
+ SANE_Int count = 0;
+
+ DBG (5, "usb_high_cal_i4o1_calibrate: start\n");
+ local_src = (SANE_Byte *) src;
+ local_target = (SANE_Byte *) target;
+
+ *local_target = 0;
+ while (j < cal->width)
+ {
+ base =
+ (SANE_Int) ((SANE_Word) (*local_src & 0xf0) << 4)
+ - (SANE_Int) (cal->k_dark[j]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * cal->k_white_level) / cal->k_white[j];
+ if (value > 0x0fff)
+ value = 0x0fff;
+ if (value >= cal->threshold)
+ *(local_target) |= gray_map[count];
+ count++;
+ j++;
+ if (j >= cal->width)
+ break;
+ base = (SANE_Int) ((SANE_Word) (*(local_src++) & 0x0f) << 8) -
+ (SANE_Int) (cal->k_dark[j]);
+ if (base < 0)
+ base = 0;
+ value = ((SANE_Word) (base) * cal->k_white_level) / cal->k_white[j];
+ if (value > 0x0fff)
+ value = 0x0fff;
+ if (value >= cal->threshold)
+ *(local_target) |= gray_map[count];
+ count++;
+ if (count >= 8)
+ {
+ local_target++;
+ *local_target = 0;
+ count = 0;
+ }
+ j++;
+ }
+ DBG (5, "usb_high_cal_i4o1_calibrate: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+
+/* --------------------------- scan functions ----------------------------- */
+
+
+SANE_Status
+usb_high_scan_init (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_init: start\n");
+
+ dev->init_bytes_per_strip = 8 * 1024;
+ dev->adjust_length_300 = 2560;
+ dev->adjust_length_600 = 5120;
+ dev->init_min_expose_time = 4992;
+ dev->init_skips_per_row_300 = 56; /* this value must be times of 6 */
+ dev->init_skips_per_row_600 = 72; /* this value must be times of 6 */
+ dev->init_j_lines = 154;
+ dev->init_k_lines = 16;
+ dev->init_k_filter = 8;
+ dev->init_k_loops = 2;
+ dev->init_pixel_rate_lines = 50;
+ dev->init_pixel_rate_filts = 37;
+ dev->init_powerdelay_lines = 2;
+ dev->init_home_lines = 160;
+ dev->init_dark_lines = 50;
+ dev->init_k_level = 245;
+ dev->init_max_power_delay = 240;
+ dev->init_min_power_delay = 136;
+ dev->init_adjust_way = 1;
+ dev->init_green_black_factor = 0.0;
+ dev->init_blue_black_factor = 0.0;
+ dev->init_red_black_factor = 0.0;
+ dev->init_gray_black_factor = 0.0;
+ dev->init_green_factor = 0.82004;
+ dev->init_blue_factor = 0.84954;
+ dev->init_red_factor = 0.826375;
+ dev->init_gray_factor = 0.833375;
+
+ dev->init_red_rgb_600_pga = 8;
+ dev->init_green_rgb_600_pga = 8;
+ dev->init_blue_rgb_600_pga = 8;
+ dev->init_mono_600_pga = 8;
+ dev->init_red_rgb_300_pga = 8;
+ dev->init_green_rgb_300_pga = 8;
+ dev->init_blue_rgb_300_pga = 8;
+ dev->init_mono_300_pga = 8;
+ dev->init_expose_time = 9024;
+ dev->init_red_rgb_600_power_delay = 80;
+ dev->init_green_rgb_600_power_delay = 80;
+ dev->init_blue_rgb_600_power_delay = 80;
+ dev->init_red_mono_600_power_delay = 80;
+ dev->init_green_mono_600_power_delay = 80;
+ dev->init_blue_mono_600_power_delay = 80;
+ dev->init_red_rgb_300_power_delay = 80;
+ dev->init_green_rgb_300_power_delay = 80;
+ dev->init_blue_rgb_300_power_delay = 80;
+ dev->init_red_mono_300_power_delay = 80;
+ dev->init_green_mono_300_power_delay = 80;
+ dev->init_blue_mono_300_power_delay = 80;
+ dev->init_threshold = 128;
+
+ dev->init_top_ref = 128;
+ dev->init_front_end = 16;
+ dev->init_red_offset = 0;
+ dev->init_green_offset = 0;
+ dev->init_blue_offset = 0;
+
+ dev->init_rgb_24_back_track = 80;
+ dev->init_mono_8_back_track = 80;
+
+ dev->is_open = SANE_FALSE;
+ dev->is_prepared = SANE_FALSE;
+ dev->expose_time = 4000;
+ dev->width = 2550;
+ dev->x_dpi = 300;
+ dev->y_dpi = 300;
+ dev->scan_mode = RGB24EXT;
+ dev->bytes_per_row = 2550 * 3;
+ dev->dummy = 0;
+ dev->bytes_per_strip = 2550;
+ dev->image_buffer = NULL;
+ dev->red = NULL;
+ dev->green = NULL;
+ dev->blue = NULL;
+ dev->get_line = NULL;
+ dev->backtrack = NULL;
+ dev->is_adjusted_rgb_600_power_delay = SANE_FALSE;
+ dev->is_adjusted_mono_600_power_delay = SANE_FALSE;
+ dev->is_adjusted_rgb_300_power_delay = SANE_FALSE;
+ dev->is_adjusted_mono_300_power_delay = SANE_FALSE;
+ dev->is_evaluate_pixel_rate = SANE_FALSE;
+ dev->red_rgb_600_pga = 0;
+ dev->green_rgb_600_pga = 0;
+ dev->blue_rgb_600_pga = 0;
+ dev->mono_600_pga = 0;
+ dev->red_rgb_600_power_delay = 0;
+ dev->green_rgb_600_power_delay = 0;
+ dev->blue_rgb_600_power_delay = 0;
+ dev->red_mono_600_power_delay = 0;
+ dev->green_mono_600_power_delay = 0;
+ dev->blue_mono_600_power_delay = 0;
+ dev->red_rgb_300_pga = 0;
+ dev->green_rgb_300_pga = 0;
+ dev->blue_rgb_300_pga = 0;
+ dev->mono_300_pga = 0;
+ dev->red_rgb_300_power_delay = 0;
+ dev->green_rgb_300_power_delay = 0;
+ dev->blue_rgb_300_power_delay = 0;
+ dev->red_mono_300_power_delay = 0;
+ dev->green_mono_300_power_delay = 0;
+ dev->blue_mono_300_power_delay = 0;
+ dev->pixel_rate = 2000;
+ dev->threshold = 128;
+ dev->gamma_table = 0;
+ dev->skips_per_row = 0;
+
+
+ dev->red_calibrator = NULL;
+ dev->green_calibrator = NULL;
+ dev->blue_calibrator = NULL;
+ dev->mono_calibrator = NULL;
+
+ dev->is_cis_detected = SANE_FALSE;
+ dev->is_sensor_detected = SANE_FALSE;
+
+ RIE (usb_low_init (&dev->chip));
+
+ DBG (5, "usb_high_scan_init: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_exit (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_exit: start\n");
+ if (!dev->chip)
+ {
+ DBG (5, "usb_high_scan_exit: already exited (`%s')\n", dev->name);
+ return SANE_STATUS_INVAL;
+ }
+
+ RIE (usb_low_exit (dev->chip));
+ dev->chip = 0;
+ DBG (5, "usb_high_scan_exit: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_prepare: start dev=%p\n", (void *) dev);
+ if (dev->is_prepared)
+ {
+ DBG (5, "usb_high_scan_prepare: is already prepared\n");
+ return SANE_STATUS_GOOD;
+ }
+ if (dev->image_buffer)
+ {
+ free (dev->image_buffer);
+ }
+ dev->image_buffer = (SANE_Byte *) malloc (dev->init_bytes_per_strip * 3);
+ if (!dev->image_buffer)
+ return SANE_STATUS_NO_MEM;
+
+ dev->red = dev->image_buffer;
+ dev->green = dev->image_buffer + dev->init_bytes_per_strip;
+ dev->blue = dev->image_buffer + dev->init_bytes_per_strip * 2;
+
+ dev->is_prepared = SANE_TRUE;
+ DBG (5, "usb_high_scan_prepare: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_clearup (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_clearup: start, dev=%p\n", (void *) dev);
+ if (!dev->is_prepared)
+ {
+ DBG (3, "usb_high_scan_clearup: is not prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (dev->image_buffer)
+ {
+ free (dev->image_buffer);
+ }
+ dev->image_buffer = NULL;
+ dev->red = NULL;
+ dev->green = NULL;
+ dev->blue = NULL;
+
+ dev->is_prepared = SANE_FALSE;
+ DBG (5, "usb_high_scan_clearup: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_turn_power (Mustek_Usb_Device * dev, SANE_Bool is_on)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_turn_power: start, turn %s power\n",
+ is_on ? "on" : "off");
+
+ if (is_on)
+ {
+ if (dev->is_open)
+ {
+ DBG (3, "usb_high_scan_turn_power: wanted to turn on power, "
+ "but scanner already open\n");
+ return SANE_STATUS_INVAL;
+ }
+ RIE (usb_low_open (dev->chip, dev->device_name));
+ dev->is_open = SANE_TRUE;
+ RIE (usb_low_turn_peripheral_power (dev->chip, SANE_TRUE));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ }
+ else
+ {
+ if (!dev->is_open)
+ {
+ DBG (3, "usb_high_scan_turn_power: wanted to turn off power, "
+ "but scanner already closed\n");
+ return SANE_STATUS_INVAL;
+ }
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_FALSE));
+ RIE (usb_low_close (dev->chip));
+ dev->is_open = SANE_FALSE;
+ }
+
+ DBG (5, "usb_high_scan_turn_power: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_back_home (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_back_home: start\n");
+
+ if (!dev->is_open)
+ {
+ DBG (3, "usb_high_scan_back_home: not open\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ RIE (usb_low_set_ccd_width (dev->chip, dev->init_min_expose_time));
+ RIE (usb_mid_motor_prepare_home (dev->chip));
+
+ DBG (5, "usb_high_scan_back_home: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_set_threshold (Mustek_Usb_Device * dev, SANE_Byte threshold)
+{
+ DBG (5, "usb_high_scan_set_threshold: start, dev=%p, threshold=%d\n",
+ (void *) dev, threshold);
+
+ dev->threshold = threshold;
+ DBG (5, "usb_high_scan_set_threshold: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_embed_gamma (Mustek_Usb_Device * dev, SANE_Word * gamma_table)
+{
+ DBG (5, "usb_high_scan_embed_gamma: start, dev=%p, gamma_table=%p\n",
+ (void *) dev, (void *) gamma_table);
+ if (!dev->is_prepared)
+ {
+ DBG (5, "usb_high_scan_embed_gamma !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ dev->gamma_table = gamma_table;
+ DBG (5, "usb_high_scan_embed_gamma: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_reset (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_reset: start\n");
+
+ if (!dev->is_open)
+ {
+ DBG (3, "usb_high_scan_reset: not open\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (!dev->is_prepared)
+ {
+ DBG (3, "usb_high_scan_reset: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ RIE (usb_high_scan_init_asic (dev, dev->chip->sensor));
+ RIE (usb_low_set_ccd_width (dev->chip, dev->init_min_expose_time));
+ RIE (usb_mid_motor_prepare_home (dev->chip));
+ RIE (usb_high_scan_set_threshold (dev, dev->init_threshold));
+ RIE (usb_high_scan_embed_gamma (dev, NULL));
+ dev->is_adjusted_rgb_600_power_delay = SANE_FALSE;
+ dev->is_adjusted_mono_600_power_delay = SANE_FALSE;
+ dev->is_adjusted_rgb_300_power_delay = SANE_FALSE;
+ dev->is_adjusted_mono_300_power_delay = SANE_FALSE;
+ dev->is_evaluate_pixel_rate = SANE_FALSE;
+ DBG (5, "usb_high_scan_reset: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_wait_carriage_home (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_wait_carriage_home: start\n");
+
+ status = usb_low_get_home_sensor (dev->chip);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ RIE (usb_low_set_ccd_width (dev->chip, dev->init_min_expose_time));
+ RIE (usb_mid_motor_prepare_home (dev->chip));
+ do
+ {
+ status = usb_low_get_home_sensor (dev->chip);
+ if (status != SANE_STATUS_GOOD)
+ usleep (18 * 1000);
+ }
+ while (status != SANE_STATUS_GOOD);
+ }
+
+ /* No Motor & Forward */
+ RIE (usb_low_move_motor_home (dev->chip, SANE_FALSE, SANE_FALSE));
+ DBG (5, "usb_high_scan_wait_carriage_home: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_hardware_calibration (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_hardware_calibration: start\n");
+
+ if (dev->is_cis_detected)
+ RIE (usb_high_scan_safe_forward (dev, dev->init_home_lines));
+
+ switch (dev->init_adjust_way)
+ {
+ case 1: /* CIS */
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ {
+ dev->expose_time = dev->init_expose_time;
+ dev->red_rgb_600_pga = dev->init_red_rgb_600_pga;
+ dev->green_rgb_600_pga = dev->init_green_rgb_600_pga;
+ dev->blue_rgb_600_pga = dev->init_blue_rgb_600_pga;
+ RIE (usb_high_scan_adjust_rgb_600_power_delay (dev));
+ }
+ else
+ {
+ dev->expose_time = dev->init_expose_time;
+ dev->red_rgb_300_pga = dev->init_red_rgb_300_pga;
+ dev->green_rgb_300_pga = dev->init_green_rgb_300_pga;
+ dev->blue_rgb_300_pga = dev->init_blue_rgb_300_pga;
+ RIE (usb_high_scan_adjust_rgb_300_power_delay (dev));
+ }
+ break;
+ case GRAY8EXT:
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ {
+ dev->expose_time = dev->init_expose_time;
+ dev->mono_600_pga = dev->init_mono_600_pga;
+ RIE (usb_high_scan_evaluate_pixel_rate (dev));
+ RIE (usb_high_scan_adjust_mono_600_power_delay (dev));
+ }
+ else
+ {
+ dev->expose_time = dev->init_expose_time;
+ dev->mono_300_pga = dev->init_mono_300_pga;
+ RIE (usb_high_scan_evaluate_pixel_rate (dev));
+ RIE (usb_high_scan_adjust_mono_300_power_delay (dev));
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* CCD */
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ dev->red_rgb_600_pga = dev->init_red_rgb_600_pga;
+ dev->green_rgb_600_pga = dev->init_green_rgb_600_pga;
+ dev->blue_rgb_600_pga = dev->init_blue_rgb_600_pga;
+ dev->skips_per_row = dev->init_skips_per_row_600;
+ /* RIE(usb_high_scan_adjust_rgb_600_exposure (dev); fixme */
+ /* RIE(usb_high_scan_adjust_rgb_600_offset (dev); fixme */
+ /* RIE(usb_high_scan_adjust_rgb_600_pga (dev); fixme */
+ /* m_isAdjustedRgb600Offset=FALSE; */
+ /* RIE(usb_high_scan_adjust_rgb_600_offset (dev); fixme */
+ /* RIE(usb_high_scan_adjust_rgb_600_skips_per_row (dev); fixme */
+ break;
+ case GRAY8EXT:
+ dev->mono_600_pga = dev->init_mono_600_pga;
+ dev->skips_per_row = dev->init_skips_per_row_600;
+ RIE (usb_high_scan_adjust_mono_600_exposure (dev));
+ /* RIE(usb_high_scan_adjust_mono_600_offset (dev); fixme */
+ /* RIE(usb_high_scan_adjust_mono_600_pga (dev); fixme */
+ dev->is_adjusted_mono_600_offset = SANE_FALSE;
+ /* RIE(usb_high_scan_adjust_mono_600_offset (dev); fixme */
+ /* RIE(usb_high_scan_adjust_mono_600_skips_per_row (dev); fixme */
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ dev->expose_time = dev->init_expose_time;
+ dev->red_rgb_600_power_delay = dev->init_red_rgb_600_power_delay;
+ dev->green_rgb_600_power_delay = dev->init_green_rgb_600_power_delay;
+ dev->blue_rgb_600_power_delay = dev->init_blue_rgb_600_power_delay;
+ dev->red_mono_600_power_delay = dev->init_red_mono_600_power_delay;
+ dev->green_mono_600_power_delay = dev->init_green_mono_600_power_delay;
+ dev->blue_mono_600_power_delay = dev->init_blue_mono_600_power_delay;
+ dev->red_rgb_600_pga = dev->init_red_rgb_600_pga;
+ dev->green_rgb_600_pga = dev->init_green_rgb_600_pga;
+ dev->blue_rgb_600_pga = dev->init_blue_rgb_600_pga;
+ dev->mono_600_pga = dev->init_mono_600_pga;
+ dev->red_rgb_300_power_delay = dev->init_red_rgb_300_power_delay;
+ dev->green_rgb_300_power_delay = dev->init_green_rgb_300_power_delay;
+ dev->blue_rgb_300_power_delay = dev->init_blue_rgb_300_power_delay;
+ dev->red_mono_300_power_delay = dev->init_red_mono_300_power_delay;
+ dev->green_mono_300_power_delay = dev->init_green_mono_300_power_delay;
+ dev->blue_mono_300_power_delay = dev->init_blue_mono_300_power_delay;
+ dev->red_rgb_300_pga = dev->init_red_rgb_300_pga;
+ dev->green_rgb_300_pga = dev->init_green_rgb_300_pga;
+ dev->blue_rgb_300_pga = dev->init_blue_rgb_300_pga;
+ dev->mono_300_pga = dev->init_mono_300_pga;
+ break;
+ }
+ DBG (5, "usb_high_scan_hardware_calibration: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_line_calibration (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_line_calibration: start\n");
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ RIE (usb_high_scan_prepare_rgb_24 (dev));
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ RIE (usb_high_scan_prepare_rgb_signal_600_dpi (dev));
+ else
+ RIE (usb_high_scan_prepare_rgb_signal_300_dpi (dev));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, dev->x_dpi));
+ RIE (usb_high_scan_calibration_rgb_24 (dev));
+ break;
+ case GRAY8EXT:
+ RIE (usb_high_scan_prepare_mono_8 (dev));
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ RIE (usb_high_scan_prepare_mono_signal_600_dpi (dev));
+ else
+ RIE (usb_high_scan_prepare_mono_signal_300_dpi (dev));
+ RIE (usb_mid_sensor_prepare_mono (dev->chip, dev->x_dpi));
+ RIE (usb_high_scan_calibration_mono_8 (dev));
+ break;
+ default:
+ DBG (3, "usb_high_scan_line_calibration: mode not matched\n");
+ return SANE_STATUS_INVAL;
+ break;
+ }
+ DBG (5, "usb_high_scan_line_calibration: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_scan (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_scan: start\n");
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ RIE (usb_high_scan_prepare_rgb_24 (dev));
+ dev->get_line = &usb_high_scan_get_rgb_24_bit_line;
+ dev->backtrack = &usb_high_scan_backtrack_rgb_24;
+
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ RIE (usb_high_scan_prepare_rgb_signal_600_dpi (dev));
+ else
+ RIE (usb_high_scan_prepare_rgb_signal_300_dpi (dev));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, dev->x_dpi));
+ RIE (usb_mid_motor_prepare_rgb (dev->chip, dev->y_dpi));
+ break;
+ case GRAY8EXT:
+ RIE (usb_high_scan_prepare_mono_8 (dev));
+ dev->get_line = &usb_high_scan_get_mono_8_bit_line;
+ dev->backtrack = &usb_high_scan_backtrack_mono_8;
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ RIE (usb_high_scan_prepare_mono_signal_600_dpi (dev));
+ else
+ RIE (usb_high_scan_prepare_mono_signal_300_dpi (dev));
+ RIE (usb_mid_sensor_prepare_mono (dev->chip, dev->x_dpi));
+ RIE (usb_mid_motor_prepare_mono (dev->chip, dev->y_dpi));
+ break;
+ default:
+ DBG (5, "usb_high_scan_prepare_scan: unmatched mode\n");
+ return SANE_STATUS_INVAL;
+ break;
+ }
+ DBG (5, "usb_high_scan_prepare_scan: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_suggest_parameters (Mustek_Usb_Device * dev, SANE_Word dpi,
+ SANE_Word x, SANE_Word y, SANE_Word width,
+ SANE_Word height, Colormode color_mode)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_suggest_parameters: start\n");
+
+ RIE (usb_high_scan_detect_sensor (dev));
+ /* Looking up Optical Y Resolution */
+ RIE (usb_mid_motor_get_dpi (dev->chip, dpi, &dev->y_dpi));
+ /* Looking up Optical X Resolution */
+ RIE (usb_mid_sensor_get_dpi (dev->chip, dpi, &dev->x_dpi));
+
+ dev->x = x * dev->x_dpi / dpi;
+ dev->y = y * dev->y_dpi / dpi;
+ dev->width = width * dev->x_dpi / dpi;
+ dev->height = height * dev->y_dpi / dpi;
+
+ switch (color_mode)
+ {
+ case RGB24:
+ dev->scan_mode = RGB24EXT;
+ dev->bytes_per_row = dev->width * 3;
+ dev->bpp = 24;
+ break;
+ case GRAY8:
+ dev->scan_mode = GRAY8EXT;
+ dev->bpp = 8;
+ dev->bytes_per_row = dev->width;
+ break;
+ default:
+ DBG (3, "usb_high_scan_suggest_parameters: unmatched mode\n");
+ return SANE_STATUS_INVAL;
+ break;
+ }
+ DBG (5, "usb_high_scan_suggest_parameters: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_detect_sensor (Mustek_Usb_Device * dev)
+{
+ if (dev->is_sensor_detected)
+ {
+ DBG (5, "usb_high_scan_detect_sensor: sensor already detected\n");
+ return SANE_STATUS_GOOD;
+ }
+ dev->is_sensor_detected = SANE_TRUE;
+
+ switch (dev->chip->scanner_type)
+ {
+ case MT_600CU:
+ dev->chip->sensor = ST_CANON300;
+ dev->chip->motor = MT_600;
+ dev->is_cis_detected = SANE_TRUE;
+ DBG (4, "usb_high_scan_detect_sensor: sensor=Canon 300 dpi, motor="
+ "600 dpi\n");
+ break;
+ case MT_1200USB:
+ dev->chip->sensor = ST_NEC600;
+ dev->chip->motor = MT_1200;
+ dev->init_min_expose_time = 2250;
+ dev->init_skips_per_row_600 = 0;
+ dev->init_home_lines = 32;
+ dev->init_dark_lines = 10;
+ dev->init_max_power_delay = 220;
+ dev->init_min_power_delay = 220;
+ dev->init_adjust_way = 3;
+ dev->init_red_rgb_600_pga = 30;
+ dev->init_green_rgb_600_pga = 30;
+ dev->init_blue_rgb_600_pga = 30;
+ dev->init_mono_600_pga = 30;
+ dev->init_expose_time = 16000;
+
+ dev->init_top_ref = 6;
+ dev->init_front_end = 12;
+ dev->init_red_offset = 128;
+ dev->init_green_offset = 128;
+ dev->init_blue_offset = 128;
+
+ dev->init_rgb_24_back_track = 0;
+ dev->init_mono_8_back_track = 40;
+
+ dev->is_cis_detected = SANE_FALSE;
+
+ DBG (4, "usb_high_scan_detect_sensor: sensor=Canon 600 dpi, motor="
+ "1200 dpi\n");
+ break;
+ case MT_1200UB:
+ case MT_1200CU_PLUS:
+ case MT_1200CU: /* need to check if it's a 300600 or 600 dpi sensor */
+ {
+ SANE_Byte *buffer;
+ static SANE_Word l_temp = 0, r_temp = 0;
+ SANE_Int i;
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ dev->chip->motor = MT_1200;
+ dev->is_cis_detected = SANE_TRUE;
+
+ buffer = NULL;
+ l_temp = 0;
+ r_temp = 0;
+
+ buffer = (SANE_Byte *) malloc (dev->init_bytes_per_strip);
+
+ if (!buffer)
+ return SANE_STATUS_NO_MEM;
+
+ for (i = 0; i < 5400; i++)
+ buffer[i] = 0xaa;
+
+ dev->scan_mode = GRAY8EXT;
+ dev->x_dpi = 600;
+ dev->y_dpi = 1200;
+ dev->width = 5400;
+
+ RIE (usb_high_scan_init_asic (dev, ST_CANON600));
+ RIE (usb_low_turn_peripheral_power (dev->chip, SANE_TRUE));
+ RIE (usb_low_enable_motor (dev->chip, SANE_TRUE)); /* Enable Motor */
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ RIE (usb_low_invert_image (dev->chip, SANE_FALSE));
+ RIE (usb_low_set_image_dpi (dev->chip, SANE_TRUE, SW_P6P6));
+ dev->bytes_per_strip = dev->adjust_length_600;
+ dev->bytes_per_row = 5400;
+ dev->dummy = 0;
+
+ RIE (usb_high_scan_wait_carriage_home (dev));
+ RIE (usb_high_scan_hardware_calibration (dev));
+ RIE (usb_high_scan_prepare_scan (dev));
+
+ /* Get Data */
+ RIE (usb_low_start_rowing (dev->chip));
+ RIE (usb_low_get_row (dev->chip, buffer, &lines_left));
+ RIE (usb_low_stop_rowing (dev->chip));
+ /* Calculate */
+ for (i = 0; i < 256; i++)
+ l_temp = l_temp + buffer[512 + i];
+ for (i = 0; i < 256; i++)
+ r_temp = r_temp + buffer[3500 + i];
+
+ l_temp = l_temp / 256;
+ r_temp = r_temp / 256;
+
+ /* 300/600 switch CIS or 600 CIS */
+ DBG (5, "usb_high_scan_detect_sensor: l_temp=%d, r_temp=%d\n",
+ l_temp, r_temp);
+ if (r_temp > 50)
+ {
+ dev->chip->sensor = ST_CANON600;
+ DBG (4,
+ "usb_high_scan_detect_sensor: sensor=Canon 600 dpi, motor="
+ "1200 dpi\n");
+ }
+ else
+ {
+ DBG (4, "usb_high_scan_detect_sensor: sensor=Canon 300/600 dpi, "
+ "motor=1200 dpi\n");
+ dev->chip->sensor = ST_CANON300600;
+ }
+
+ /* Release Resource */
+ free (buffer);
+ buffer = NULL;
+
+ break;
+ }
+ default:
+ DBG (5, "usb_high_scan_detect_sensor: I don't know this scanner type "
+ "(%d)\n", dev->chip->scanner_type);
+ return SANE_STATUS_INVAL;
+ }
+
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+usb_high_scan_setup_scan (Mustek_Usb_Device * dev, Colormode color_mode,
+ SANE_Word x_dpi, SANE_Word y_dpi,
+ SANE_Bool is_invert, SANE_Word x, SANE_Word y,
+ SANE_Word width)
+{
+ SANE_Status status;
+ SANE_Word upper_bound;
+ SANE_Word left_bound;
+
+ DBG (5, "usb_high_scan_setup_scan: start, is_invert=%d\n", is_invert);
+ if (!dev->is_open)
+ {
+ DBG (5, "usb_high_scan_setup_scan: not open\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (!dev->is_prepared)
+ {
+ DBG (5, "usb_high_scan_setup_scan: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ RIE (usb_high_scan_init_asic (dev, dev->chip->sensor));
+ RIE (usb_low_turn_peripheral_power (dev->chip, SANE_TRUE));
+ RIE (usb_low_enable_motor (dev->chip, SANE_TRUE)); /* Enable Motor */
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ RIE (usb_low_invert_image (dev->chip, SANE_FALSE));
+ if (!dev->is_cis_detected)
+ {
+ usb_mid_front_set_front_end_mode (dev->chip, 16);
+ usb_mid_front_enable (dev->chip, SANE_TRUE);
+ usb_mid_front_set_top_reference (dev->chip, 244);
+ usb_mid_front_set_rgb_signal (dev->chip);
+ }
+
+ /* Compute necessary variables */
+ dev->scan_mode = color_mode;
+ dev->x_dpi = x_dpi;
+ dev->y_dpi = y_dpi;
+ dev->width = width;
+
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ dev->bytes_per_row = 3 * dev->width;
+ upper_bound = ((y * 600) / dev->y_dpi) + dev->init_j_lines;
+ break;
+ case GRAY8EXT:
+ dev->bytes_per_row = dev->width;
+ upper_bound = ((y * 600) / dev->y_dpi) + dev->init_j_lines + 4;
+ /* fixme */
+ break;
+ default:
+ upper_bound = ((y * 600) / dev->y_dpi) + dev->init_j_lines + 4;
+ break;
+ }
+
+ if (usb_mid_sensor_is600_mode (dev->chip, dev->x_dpi))
+ {
+ /* in 600dpi */
+ left_bound = (x * 600 / dev->x_dpi) + dev->init_skips_per_row_600;
+ dev->skips_per_row = (((left_bound % 32) * dev->x_dpi + 300) / 600);
+ }
+ else
+ {
+ /* in 300dpi */
+ left_bound = (x * 300 / dev->x_dpi) + dev->init_skips_per_row_300;
+ dev->skips_per_row = (((left_bound % 32) * dev->x_dpi + 150) / 300);
+ }
+
+ dev->dummy = (left_bound / 32) * 32;
+
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ dev->bytes_per_strip = dev->skips_per_row + dev->width;
+ break;
+ case GRAY8EXT:
+ dev->bytes_per_strip = dev->skips_per_row + dev->width;
+ break;
+ default:
+ break;
+ }
+
+ dev->bytes_per_strip = ((dev->bytes_per_strip + 1) / 2) * 2;
+ /* make bytes_per_strip is as 2n to advoid 64n+1 */
+
+ RIE (usb_high_scan_wait_carriage_home (dev));
+ RIE (usb_high_scan_hardware_calibration (dev));
+ RIE (usb_high_scan_line_calibration (dev));
+ RIE (usb_high_scan_step_forward (dev, upper_bound));
+ RIE (usb_high_scan_prepare_scan (dev));
+ RIE (usb_low_start_rowing (dev->chip));
+ /* pat_chromator fixme (init for calibration?) */
+ DBG (5, "usb_high_scan_setup_scan: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_get_rows (Mustek_Usb_Device * dev, SANE_Byte * block,
+ SANE_Word rows, SANE_Bool is_order_invert)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_get_rows: start, %d rows\n", rows);
+ if (!dev->is_open)
+ {
+ DBG (3, "usb_high_scan_get_rows: not open\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (!dev->is_prepared)
+ {
+ DBG (3, "usb_high_scan_get_rows: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ while (rows > 0)
+ {
+ RIE ((*dev->get_line) (dev, block, is_order_invert));
+ block += dev->bytes_per_row;
+ rows--;
+ }
+ DBG (5, "usb_high_scan_get_rows: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_stop_scan (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_stop_scan: start\n");
+ if (!dev->is_open)
+ {
+ DBG (3, "usb_high_scan_stop_scan: not open\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (!dev->is_prepared)
+ {
+ DBG (3, "usb_high_scan_stop_scan: !is_prepared\n");
+ return SANE_STATUS_INVAL;
+ }
+ switch (dev->scan_mode)
+ {
+ case RGB24EXT:
+ RIE (usb_high_cal_exit (dev->blue_calibrator));
+ if (dev->blue_calibrator)
+ free (dev->blue_calibrator);
+ dev->blue_calibrator = NULL;
+ RIE (usb_high_cal_exit (dev->green_calibrator));
+ if (dev->green_calibrator)
+ free (dev->green_calibrator);
+ dev->green_calibrator = NULL;
+ RIE (usb_high_cal_exit (dev->red_calibrator));
+ if (dev->red_calibrator)
+ free (dev->red_calibrator);
+ dev->red_calibrator = NULL;
+ break;
+ case GRAY8EXT:
+ RIE (usb_high_cal_exit (dev->mono_calibrator));
+ if (dev->mono_calibrator)
+ free (dev->mono_calibrator);
+ dev->mono_calibrator = NULL;
+ break;
+ default:
+ break;
+ }
+
+ RIE (usb_low_stop_rowing (dev->chip));
+ if (!dev->is_cis_detected)
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_FALSE));
+
+ DBG (5, "usb_high_scan_stop_scan: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_init_asic (Mustek_Usb_Device * dev, Sensor_Type sensor)
+{
+ SANE_Byte ccd_dpi = 0;
+ SANE_Byte select = 0;
+ SANE_Byte adjust = 0;
+ SANE_Byte pin = 0;
+ SANE_Byte motor = 0;
+ SANE_Bool fix_pattern = SANE_FALSE;
+ SANE_Byte ad_timing = 0;
+ Banksize bank_size;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_init_asic: start\n");
+ switch (sensor)
+ {
+ case ST_TOSHIBA600:
+ ccd_dpi = 32;
+ select = 240;
+ adjust = 0;
+ pin = 18;
+ motor = 0;
+ fix_pattern = SANE_FALSE;
+ ad_timing = 0;
+ bank_size = BS_16K;
+ DBG (5, "usb_high_scan_init_asic: sensor is set to TOSHIBA600\n");
+ break;
+ case ST_CANON300:
+ ccd_dpi = 232;
+ select = 232;
+ adjust = 0;
+ pin = 18;
+ motor = 0;
+ fix_pattern = SANE_FALSE;
+ ad_timing = 1;
+ bank_size = BS_4K;
+ DBG (5, "usb_high_scan_init_asic: sensor is set to CANON300\n");
+ break;
+ case ST_CANON300600:
+ ccd_dpi = 232;
+ select = 232;
+ adjust = 64;
+ pin = 18;
+ motor = 0;
+ fix_pattern = SANE_FALSE;
+ ad_timing = 1;
+ bank_size = BS_16K;
+ DBG (5, "usb_high_scan_init_asic: sensor is set to CANON300600\n");
+ break;
+ case ST_CANON600:
+ ccd_dpi = 232;
+ select = 232;
+ adjust = 64;
+ pin = 18;
+ motor = 0;
+ fix_pattern = SANE_FALSE;
+ ad_timing = 1;
+ bank_size = BS_16K;
+ DBG (5, "usb_high_scan_init_asic: sensor is set to CANON600\n");
+ break;
+ case ST_NEC600: /* fixme */
+ ccd_dpi = 32;
+ select = 224;
+ adjust = 112;
+ pin = 18;
+ motor = 0;
+ fix_pattern = SANE_FALSE;
+ ad_timing = 0;
+ bank_size = BS_16K;
+ DBG (5, "usb_high_scan_init_asic: sensor is set to NEC600\n");
+ break;
+ default:
+ DBG (5, "usb_high_scan_init_asic: unknown sensor\n");
+ return SANE_STATUS_INVAL;
+ break;
+ }
+ RIE (usb_low_adjust_timing (dev->chip, adjust));
+ RIE (usb_low_select_timing (dev->chip, select));
+ RIE (usb_low_set_timing (dev->chip, ccd_dpi));
+ RIE (usb_low_set_sram_bank (dev->chip, bank_size));
+ RIE (usb_low_set_asic_io_pins (dev->chip, pin));
+ RIE (usb_low_set_rgb_sel_pins (dev->chip, pin));
+ RIE (usb_low_set_motor_signal (dev->chip, motor));
+ RIE (usb_low_set_test_sram_mode (dev->chip, SANE_FALSE));
+ RIE (usb_low_set_fix_pattern (dev->chip, fix_pattern));
+ RIE (usb_low_set_ad_timing (dev->chip, ad_timing));
+
+ DBG (5, "usb_high_scan_init_asic: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_evaluate_max_level (Mustek_Usb_Device * dev,
+ SANE_Word sample_lines,
+ SANE_Int sample_length,
+ SANE_Byte * ret_max_level)
+{
+ SANE_Byte max_level = 0;
+ SANE_Word i;
+ SANE_Int j;
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ DBG (5, "usb_high_scan_evaluate_max_level: start\n");
+
+ sample_length -= 20;
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < sample_lines; i++)
+ {
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ for (j = 20; j < sample_length; j++)
+ {
+ if (max_level < dev->green[j])
+ max_level = dev->green[j];
+ }
+ }
+ RIE (usb_low_stop_rowing (dev->chip));
+ if (ret_max_level)
+ *ret_max_level = max_level;
+ DBG (5, "usb_high_scan_evaluate_max_level: exit, max_level = %d\n",
+ max_level);
+ return SANE_STATUS_GOOD;
+}
+
+/* Binary Search for Single Channel Power Delay */
+SANE_Status
+usb_high_scan_bssc_power_delay (Mustek_Usb_Device * dev,
+ Powerdelay_Function set_power_delay,
+ Signal_State * signal_state,
+ SANE_Byte * target, SANE_Byte max,
+ SANE_Byte min, SANE_Byte threshold,
+ SANE_Int length)
+{
+ SANE_Byte max_level;
+ SANE_Byte max_max = max;
+ SANE_Byte min_min = min;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_bssc_power_delay: start\n");
+
+ *target = (max + min) / 2;
+ RIE ((*set_power_delay) (dev->chip, *target));
+ while (*target != min)
+ {
+ RIE (usb_high_scan_evaluate_max_level (dev, dev->init_powerdelay_lines,
+ length, &max_level));
+ if (max_level > threshold)
+ {
+ min = *target;
+ *target = (max + min) / 2;
+ *signal_state = SS_BRIGHTER;
+ }
+ else if (max_level < threshold)
+ {
+ max = *target;
+ *target = (max + min) / 2;
+ *signal_state = SS_DARKER;
+ }
+ else if (max_level == threshold)
+ { /* Found. */
+ *signal_state = SS_EQUAL;
+ return SANE_STATUS_GOOD;
+ }
+ RIE ((*set_power_delay) (dev->chip, *target));
+ }
+ /* Fail... */
+ if (max == max_max || min == min_min)
+ { /* Boundary check */
+ if (max == max_max) /*target on max side */
+ *target = max_max;
+ else
+ *target = min_min;
+ RIE ((*set_power_delay) (dev->chip, *target));
+ RIE (usb_high_scan_evaluate_max_level (dev, dev->init_powerdelay_lines,
+ length, &max_level));
+
+ if (max_level > threshold)
+ {
+ *signal_state = SS_BRIGHTER;
+ }
+ else if (max_level < threshold)
+ {
+ *signal_state = SS_DARKER;
+ }
+ else if (max_level == threshold)
+ {
+ *signal_state = SS_EQUAL;
+ }
+ }
+ else
+ { /* Fail... will always on mimnum side, make it darker */
+ target++;
+ *signal_state = SS_DARKER;
+ }
+ DBG (5, "usb_high_scan_bssc_power_delay: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_adjust_rgb_600_power_delay (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+ SANE_Byte max_power_delay;
+ Signal_State signal_state = SS_UNKNOWN;
+
+ DBG (5, "usb_high_scan_adjust_rgb_600_power_delay: start\n");
+ max_power_delay = (SANE_Byte) (dev->expose_time / 64);
+
+ if (dev->is_adjusted_rgb_600_power_delay)
+ return SANE_STATUS_GOOD;
+ /* Setup Initial State */
+ dev->red_rgb_600_power_delay = max_power_delay;
+ dev->green_rgb_600_power_delay = max_power_delay;
+ dev->blue_rgb_600_power_delay = max_power_delay;
+
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_dummy (dev->chip, dev->init_skips_per_row_600));
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->adjust_length_600));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+
+ /* adjust GreenPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_GREEN));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 600));
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->green_rgb_600_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_green_pd, &signal_state,
+ &dev->green_rgb_600_power_delay,
+ max_power_delay, 0, dev->init_max_power_delay,
+ dev->adjust_length_600));
+
+ /* adjust BluePD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_BLUE));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 600));
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->blue_rgb_600_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_blue_pd, &signal_state,
+ &dev->blue_rgb_600_power_delay,
+ max_power_delay, 0, dev->init_max_power_delay,
+ dev->adjust_length_600));
+
+ /* adjust RedPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_RED));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 600));
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->red_rgb_600_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_red_pd, &signal_state,
+ &dev->red_rgb_600_power_delay, max_power_delay, 0,
+ dev->init_max_power_delay, dev->adjust_length_600));
+
+ dev->is_adjusted_rgb_600_power_delay = SANE_TRUE;
+ DBG (5, "usb_high_scan_adjust_rgb_600_power_delay: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_adjust_mono_600_power_delay (Mustek_Usb_Device * dev)
+{
+ SANE_Byte max_power_delay;
+ Signal_State signal_state = SS_UNKNOWN;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_adjust_mono_600_power_delay: start\n");
+ max_power_delay = (SANE_Byte) (dev->expose_time / 64);
+ if (dev->is_adjusted_mono_600_power_delay)
+ return SANE_STATUS_GOOD;
+ /* Setup Initial State */
+ dev->red_mono_600_power_delay = max_power_delay;
+ dev->green_mono_600_power_delay = max_power_delay;
+ dev->blue_mono_600_power_delay = max_power_delay;
+
+ /* Compute Gray PD */
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_dummy (dev->chip, dev->init_skips_per_row_600));
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->adjust_length_600));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+
+ /* adjust GreenGrayPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_GREEN));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 600));
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_green_pd, &signal_state,
+ &dev->green_mono_600_power_delay,
+ max_power_delay, 0, dev->init_max_power_delay,
+ dev->adjust_length_600));
+
+ dev->is_adjusted_mono_600_power_delay = SANE_TRUE;
+ DBG (5, "usb_high_scan_adjust_mono_600_power_delay: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+/* CCD */
+SANE_Status
+usb_high_scan_adjust_mono_600_exposure (Mustek_Usb_Device * dev)
+{
+ SANE_Word transfer_time;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_adjust_mono_600_exposure: start\n");
+ if (dev->is_adjusted_mono_600_exposure)
+ return SANE_STATUS_GOOD;
+
+ RIE (usb_high_scan_evaluate_pixel_rate (dev));
+ transfer_time = dev->pixel_rate * dev->x_dpi / 600;
+ if (transfer_time > 16000)
+ transfer_time = 16000;
+
+ dev->mono_600_exposure =
+ MAX (5504, MAX (transfer_time,
+ usb_mid_motor_mono_capability (dev->chip, dev->y_dpi)));
+ dev->mono_600_exposure = ((dev->mono_600_exposure + 63) / 64) * 64;
+ dev->is_adjusted_mono_600_exposure = SANE_TRUE;
+ DBG (5, "usb_high_scan_adjust_mono_600_exposure: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+#if 0
+/* CCD */
+SANE_Status
+usb_high_scan_adjust_mono_600_offset (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_adjust_mono_600_offset: start\n");
+ if (dev->is_adjusted_mono_600_offset)
+ return SANE_STATUS_GOOD;
+
+ DBG (5, "usb_high_scan_adjust_mono_600_offset: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+/* CCD */
+SANE_Status
+usb_high_scan_adjust_mono_600_pga (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_adjust_mono_600_pga: start (dev = %p)\n", dev);
+ DBG (5, "usb_high_scan_adjust_mono_600_pga: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+/* CCD */
+SANE_Status
+usb_high_scan_adjust_mono_600_skips_per_row (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_adjust_mono_600_skips_per_row: start (dev = %p)\n",
+ dev);
+ DBG (5, "usb_high_scan_adjust_mono_600_skips_per_row: exit\n");
+ return SANE_STATUS_GOOD;
+}
+#endif
+
+SANE_Status
+usb_high_scan_adjust_rgb_300_power_delay (Mustek_Usb_Device * dev)
+{
+ /* Setup Initial State */
+ SANE_Byte max_power_delay;
+ Signal_State signal_state = SS_UNKNOWN;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_adjust_rgb_300_power_delay: start\n");
+ max_power_delay = (SANE_Byte) (dev->expose_time / 64);
+ if (dev->is_adjusted_rgb_300_power_delay)
+ return SANE_STATUS_GOOD;
+
+ dev->red_rgb_300_power_delay = max_power_delay;
+ dev->green_rgb_300_power_delay = max_power_delay;
+ dev->blue_rgb_300_power_delay = max_power_delay;
+
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_dummy (dev->chip, dev->init_skips_per_row_300));
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->adjust_length_300));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+
+ /* adjust GreenPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_GREEN));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 300));
+
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->green_rgb_300_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_green_pd, &signal_state,
+ &dev->green_rgb_300_power_delay,
+ max_power_delay, 0, dev->init_max_power_delay,
+ dev->adjust_length_300));
+
+ /* adjust BluePD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_BLUE));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 300));
+
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->blue_rgb_300_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_blue_pd, &signal_state,
+ &dev->blue_rgb_300_power_delay, max_power_delay, 0,
+ dev->init_max_power_delay, dev->adjust_length_300));
+
+ /* adjust RedPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_RED));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 300));
+
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->red_rgb_300_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_red_pd, &signal_state,
+ &dev->red_rgb_300_power_delay, max_power_delay, 0,
+ dev->init_max_power_delay, dev->adjust_length_300));
+ dev->is_adjusted_rgb_300_power_delay = SANE_TRUE;
+ DBG (5, "usb_high_scan_adjust_rgb_300_power_delay: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_adjust_mono_300_power_delay (Mustek_Usb_Device * dev)
+{
+ SANE_Byte max_power_delay;
+ Signal_State signal_state = SS_UNKNOWN;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_adjust_mono_300_power_delay: start\n");
+ max_power_delay = (SANE_Byte) (dev->expose_time / 64);
+ if (dev->is_adjusted_mono_300_power_delay)
+ return SANE_STATUS_GOOD;
+ /* Setup Initial State */
+ dev->red_mono_300_power_delay = max_power_delay;
+ dev->green_mono_300_power_delay = max_power_delay;
+ dev->blue_mono_300_power_delay = max_power_delay;
+
+ /* Compute Gray PD */
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_dummy (dev->chip, dev->init_skips_per_row_300));
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->adjust_length_300));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+
+ /* adjust GreenGrayPD */
+ RIE (usb_mid_motor_prepare_adjust (dev->chip, CH_GREEN));
+ RIE (usb_mid_sensor_prepare_rgb (dev->chip, 300));
+
+ signal_state = SS_UNKNOWN;
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_high_scan_bssc_power_delay
+ (dev, &usb_low_set_green_pd, &signal_state,
+ &dev->green_mono_300_power_delay,
+ max_power_delay, 0, dev->init_max_power_delay,
+ dev->adjust_length_300));
+
+ dev->is_adjusted_mono_300_power_delay = SANE_TRUE;
+ DBG (5, "usb_high_scan_adjust_mono_300_power_delay: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_evaluate_pixel_rate (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_evaluate_pixel_rate: start, dev=%p\n", (void *) dev);
+
+ /* fixme: new for CCD */
+ dev->pixel_rate = 2000;
+ dev->is_evaluate_pixel_rate = SANE_TRUE;
+ DBG (5, "usb_high_scan_evaluate_pixel_rate: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_calibration_rgb_24 (Mustek_Usb_Device * dev)
+{
+ SANE_Word white_need;
+ SANE_Word dark_need;
+ SANE_Word i;
+ SANE_Status status;
+ SANE_Word lines_left;
+ SANE_Word minor_average;
+
+ DBG (5, "usb_high_scan_calibration_rgb_24: start, dev=%p\n", (void *) dev);
+ if (dev->is_cis_detected)
+ {
+ RIE (usb_mid_motor_prepare_calibrate_rgb (dev->chip, dev->y_dpi));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ minor_average = 2;
+ }
+ else
+ {
+ minor_average = 1;
+ }
+
+ dev->red_calibrator = (Calibrator *) malloc (sizeof (Calibrator));
+ if (!dev->red_calibrator)
+ return SANE_STATUS_NO_MEM;
+
+ RIE (usb_high_cal_init (dev->red_calibrator, I8O8RGB,
+ dev->init_k_level << 8, 0));
+ RIE (usb_high_cal_prepare (dev->red_calibrator, dev->width));
+ RIE (usb_high_cal_embed_gamma (dev->red_calibrator, dev->gamma_table));
+ RIE (usb_high_cal_setup
+ (dev->red_calibrator, 1, minor_average, 8, dev->width, &white_need,
+ &dark_need));
+
+ dev->green_calibrator = (Calibrator *) malloc (sizeof (Calibrator));
+ if (!dev->green_calibrator)
+ return SANE_STATUS_NO_MEM;
+ RIE (usb_high_cal_init (dev->green_calibrator, I8O8RGB,
+ dev->init_k_level << 8, 0));
+ RIE (usb_high_cal_prepare (dev->green_calibrator, dev->width));
+ RIE (usb_high_cal_embed_gamma (dev->green_calibrator, dev->gamma_table));
+ RIE (usb_high_cal_setup (dev->green_calibrator, 1, minor_average, 8,
+ dev->width, &white_need, &dark_need));
+
+ dev->blue_calibrator = (Calibrator *) malloc (sizeof (Calibrator));
+ if (!dev->blue_calibrator)
+ return SANE_STATUS_NO_MEM;
+
+ RIE (usb_high_cal_init (dev->blue_calibrator, I8O8RGB,
+ dev->init_k_level << 8, 0));
+ RIE (usb_high_cal_prepare (dev->blue_calibrator, dev->width));
+ RIE (usb_high_cal_embed_gamma (dev->blue_calibrator, dev->gamma_table));
+ RIE (usb_high_cal_setup (dev->blue_calibrator, 1, minor_average, 8,
+ dev->width, &white_need, &dark_need));
+
+ /* K White */
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < white_need; i++)
+ {
+ /* Read Green Channel */
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->green_calibrator, i, 0,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->green_calibrator, i, 1,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ /* Read Blue Channel */
+ RIE (usb_low_get_row (dev->chip, dev->blue, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->blue_calibrator, i, 0,
+ (void *) (dev->blue +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->blue, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->blue_calibrator, i, 1,
+ (void *) (dev->blue +
+ dev->skips_per_row)));
+ /* Read Red Channel */
+ RIE (usb_low_get_row (dev->chip, dev->red, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->red_calibrator, i, 0,
+ (void *) (dev->red +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->red, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->red_calibrator, i, 1,
+ (void *) (dev->red +
+ dev->skips_per_row)));
+ }
+ RIE (usb_low_stop_rowing (dev->chip));
+ /* Caculate average */
+ RIE (usb_high_cal_evaluate_white (dev->green_calibrator,
+ dev->init_green_factor));
+ RIE (usb_high_cal_evaluate_white (dev->blue_calibrator,
+ dev->init_blue_factor));
+ RIE (usb_high_cal_evaluate_white (dev->red_calibrator,
+ dev->init_red_factor));
+
+ RIE (usb_mid_motor_prepare_calibrate_rgb (dev->chip, dev->y_dpi));
+ RIE (usb_low_enable_motor (dev->chip, SANE_FALSE));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_FALSE));
+
+ /* K Black */
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < dark_need; i++)
+ {
+ /* Read Green Channel */
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->green_calibrator, i, 0,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->green_calibrator, i, 1,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ /* Read Blue Channel */
+ RIE (usb_low_get_row (dev->chip, dev->blue, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->blue_calibrator, i, 0,
+ (void *) (dev->blue +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->blue, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->blue_calibrator, i, 1,
+ (void *) (dev->blue +
+ dev->skips_per_row)));
+ /* Read Red Channel */
+ RIE (usb_low_get_row (dev->chip, dev->red, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->red_calibrator, i, 0,
+ (void *) (dev->red +
+ dev->skips_per_row)));
+ RIE (usb_low_get_row (dev->chip, dev->red, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->red_calibrator, i, 1,
+ (void *) (dev->red +
+ dev->skips_per_row)));
+ }
+ RIE (usb_low_stop_rowing (dev->chip));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ /* Calculate average */
+ RIE (usb_high_cal_evaluate_dark (dev->green_calibrator,
+ dev->init_green_black_factor));
+ RIE (usb_high_cal_evaluate_dark (dev->blue_calibrator,
+ dev->init_blue_black_factor));
+ RIE (usb_high_cal_evaluate_dark (dev->red_calibrator,
+ dev->init_red_black_factor));
+ /* Calculate Mapping */
+ RIE (usb_high_cal_evaluate_calibrator (dev->green_calibrator));
+ RIE (usb_high_cal_evaluate_calibrator (dev->blue_calibrator));
+ RIE (usb_high_cal_evaluate_calibrator (dev->red_calibrator));
+ DBG (5, "usb_high_scan_calibration_rgb_24: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_calibration_mono_8 (Mustek_Usb_Device * dev)
+{
+ SANE_Word white_need;
+ SANE_Word dark_need;
+ SANE_Word i;
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ DBG (5, "usb_high_scan_calibration_mono_8: start\n");
+ RIE (usb_mid_motor_prepare_calibrate_mono (dev->chip, dev->y_dpi));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+
+ dev->mono_calibrator = (Calibrator *) malloc (sizeof (Calibrator));
+ if (!dev->mono_calibrator)
+ return SANE_STATUS_NO_MEM;
+
+ RIE (usb_high_cal_init (dev->mono_calibrator, I8O8MONO,
+ dev->init_k_level << 8, 0));
+ RIE (usb_high_cal_prepare (dev->mono_calibrator, dev->width));
+ RIE (usb_high_cal_embed_gamma (dev->mono_calibrator, dev->gamma_table));
+ RIE (usb_high_cal_setup (dev->mono_calibrator, 1, 1, 8,
+ dev->width, &white_need, &dark_need));
+
+ /* K White */
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < white_need; i++)
+ {
+ /* Read Green Channel */
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_white (dev->mono_calibrator, i, 0,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ }
+ RIE (usb_low_stop_rowing (dev->chip));
+ /* Caculate average */
+ RIE (usb_high_cal_evaluate_white (dev->mono_calibrator,
+ dev->init_gray_factor));
+
+ RIE (usb_mid_motor_prepare_calibrate_mono (dev->chip, dev->y_dpi));
+ RIE (usb_low_enable_motor (dev->chip, SANE_FALSE));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_FALSE));
+
+ /* K Black */
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < dark_need; i++)
+ {
+ /* Read Green Channel */
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_fill_in_dark (dev->mono_calibrator, i, 0,
+ (void *) (dev->green +
+ dev->skips_per_row)));
+ }
+ RIE (usb_low_stop_rowing (dev->chip));
+ RIE (usb_low_turn_lamp_power (dev->chip, SANE_TRUE));
+ /* Caculate Green Black */
+ RIE (usb_high_cal_evaluate_dark (dev->mono_calibrator,
+ dev->init_gray_black_factor));
+ /* Caculate Mapping */
+ RIE (usb_high_cal_evaluate_calibrator (dev->mono_calibrator));
+ DBG (5, "usb_high_scan_calibration_mono_8: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_step_forward (Mustek_Usb_Device * dev, SANE_Int step_count)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_step_forward: start\n");
+
+ if (step_count <= 0)
+ return SANE_STATUS_INVAL;
+ /* Initialize */
+ RIE (usb_low_set_ccd_width (dev->chip, dev->init_min_expose_time));
+ RIE (usb_low_set_motor_direction (dev->chip, SANE_FALSE));
+ RIE (usb_mid_motor_prepare_step (dev->chip, (SANE_Word) step_count));
+ /* Startup */
+ RIE (usb_low_start_rowing (dev->chip));
+ /* Wait for stop */
+ /* Linux USB seems buggy on timeout... sleep before really try */
+ /* to read the flag from scanner */
+ usleep (step_count * 2 * 1000);
+ RIE (usb_low_wait_rowing_stop (dev->chip));
+ if (!dev->is_cis_detected)
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+
+ DBG (5, "usb_high_scan_step_forward: start\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_safe_forward (Mustek_Usb_Device * dev, SANE_Int step_count)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_safe_forward: start\n");
+ if (step_count <= 0)
+ return SANE_STATUS_INVAL;
+ /* Initialize */
+ RIE (usb_low_set_ccd_width (dev->chip, 5400));
+ RIE (usb_low_set_motor_direction (dev->chip, SANE_FALSE));
+ RIE (usb_mid_motor_prepare_step (dev->chip, (SANE_Word) step_count));
+ /* Startup */
+ RIE (usb_low_start_rowing (dev->chip));
+ /* Wait to Stop */
+ RIE (usb_low_wait_rowing_stop (dev->chip));
+ RIE (usb_low_set_ccd_width (dev->chip, dev->expose_time));
+ DBG (5, "usb_high_scan_safe_forward: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Word
+usb_high_scan_calculate_max_rgb_600_expose (Mustek_Usb_Device * dev,
+ SANE_Byte * ideal_red_pd,
+ SANE_Byte * ideal_green_pd,
+ SANE_Byte * ideal_blue_pd)
+{
+ SANE_Word red_light_up;
+ SANE_Word green_light_up;
+ SANE_Word blue_light_up;
+ SANE_Word max_light_up;
+ SANE_Word ideal_expose_time;
+
+ DBG (5, "usb_high_scan_calculate_max_rgb_600_expose: dev=%p\n", (void *) dev);
+
+ red_light_up = dev->expose_time - dev->red_rgb_600_power_delay * 64;
+ green_light_up = dev->expose_time - dev->green_rgb_600_power_delay * 64;
+ blue_light_up = dev->expose_time - dev->blue_rgb_600_power_delay * 64;
+ max_light_up = MAX (red_light_up, MAX (green_light_up, blue_light_up));
+ if (dev->chip->sensor == ST_NEC600)
+ {
+ ideal_expose_time
+ = MAX (MAX (5504, max_light_up),
+ usb_mid_motor_rgb_capability (dev->chip, dev->y_dpi));
+ }
+ else
+ {
+ ideal_expose_time
+ = MAX (MAX (5376, max_light_up),
+ usb_mid_motor_rgb_capability (dev->chip, dev->y_dpi));
+ }
+ ideal_expose_time = (ideal_expose_time + 63) / 64 * 64;
+ *ideal_red_pd = (SANE_Byte) ((ideal_expose_time - red_light_up) / 64);
+ *ideal_green_pd = (SANE_Byte) ((ideal_expose_time - green_light_up) / 64);
+ *ideal_blue_pd = (SANE_Byte) ((ideal_expose_time - blue_light_up) / 64);
+ DBG (5, "usb_high_scan_calculate_max_rgb_600_expose: exit\n");
+ return ideal_expose_time;
+}
+
+SANE_Word
+usb_high_scan_calculate_max_mono_600_expose (Mustek_Usb_Device * dev,
+ SANE_Byte * ideal_red_pd,
+ SANE_Byte * ideal_green_pd,
+ SANE_Byte * ideal_blue_pd)
+{
+ SANE_Word max_light_up;
+ SANE_Word ideal_expose_time;
+ SANE_Word transfer_time;
+
+ DBG (5, "usb_high_scan_calculate_max_mono_600_expose: dev=%p\n", (void *) dev);
+
+ max_light_up = dev->expose_time - dev->green_mono_600_power_delay * 64;
+ transfer_time = (SANE_Word) ((SANE_Word) (dev->pixel_rate)
+ * (SANE_Word) (dev->x_dpi) / 600);
+ /* base on 600, but double it. */
+
+ if (transfer_time > 16000)
+ transfer_time = 16000;
+ if (dev->chip->sensor == ST_NEC600)
+ {
+ ideal_expose_time
+ = MAX (MAX (5504, max_light_up),
+ MAX (transfer_time, usb_mid_motor_mono_capability
+ (dev->chip, dev->y_dpi)));
+ }
+ else
+ {
+ ideal_expose_time
+ = MAX (MAX (5376, max_light_up),
+ MAX (transfer_time, usb_mid_motor_mono_capability
+ (dev->chip, dev->y_dpi)));
+ }
+ ideal_expose_time = (ideal_expose_time + 63) / 64 * 64;
+ *ideal_red_pd = (SANE_Byte) ((ideal_expose_time) / 64);
+ *ideal_green_pd = (SANE_Byte) ((ideal_expose_time - max_light_up) / 64);
+ *ideal_blue_pd = (SANE_Byte) ((ideal_expose_time) / 64);
+ DBG (5, "usb_high_scan_calculate_max_mono_600_expose: exit\n");
+ return ideal_expose_time;
+}
+
+SANE_Word
+usb_high_scan_calculate_max_rgb_300_expose (Mustek_Usb_Device * dev,
+ SANE_Byte * ideal_red_pd,
+ SANE_Byte * ideal_green_pd,
+ SANE_Byte * ideal_blue_pd)
+{
+ SANE_Word red_light_up;
+ SANE_Word green_light_up;
+ SANE_Word blue_light_up;
+ SANE_Word max_light_up;
+ SANE_Word ideal_expose_time;
+
+ DBG (5, "usb_high_scan_calculate_max_rgb_300_expose: start\n");
+ red_light_up = dev->expose_time - dev->red_rgb_300_power_delay * 64;
+ green_light_up = dev->expose_time - dev->green_rgb_300_power_delay * 64;
+ blue_light_up = dev->expose_time - dev->blue_rgb_300_power_delay * 64;
+ max_light_up = MAX (red_light_up, MAX (green_light_up, blue_light_up));
+
+ if (dev->chip->sensor == ST_CANON300600)
+ {
+ ideal_expose_time =
+ MAX (MAX (2624, max_light_up),
+ usb_mid_motor_rgb_capability (dev->chip, dev->y_dpi));
+ }
+ else if (dev->chip->sensor == ST_CANON300)
+ {
+ ideal_expose_time = MAX (MAX (2624, max_light_up), /* fixme? */
+ usb_mid_motor_rgb_capability (dev->chip,
+ dev->y_dpi));
+ }
+ else
+ {
+ ideal_expose_time =
+ MAX (MAX (5376, max_light_up),
+ usb_mid_motor_rgb_capability (dev->chip, dev->y_dpi));
+ }
+
+ ideal_expose_time = (ideal_expose_time + 63) / 64 * 64;
+ *ideal_red_pd = (SANE_Byte) ((ideal_expose_time - red_light_up) / 64);
+ *ideal_green_pd = (SANE_Byte) ((ideal_expose_time - green_light_up) / 64);
+ *ideal_blue_pd = (SANE_Byte) ((ideal_expose_time - blue_light_up) / 64);
+ DBG (5, "usb_high_scan_calculate_max_rgb_300_expose: exit\n");
+ return ideal_expose_time;
+}
+
+SANE_Word
+usb_high_scan_calculate_max_mono_300_expose (Mustek_Usb_Device * dev,
+ SANE_Byte * ideal_red_pd,
+ SANE_Byte * ideal_green_pd,
+ SANE_Byte * ideal_blue_pd)
+{
+ SANE_Word max_light_up;
+ SANE_Word transfer_time;
+ SANE_Word ideal_expose_time;
+
+ DBG (5, "usb_high_scan_calculate_max_mono_300_expose: start\n");
+ max_light_up = dev->expose_time - dev->green_mono_300_power_delay * 64;
+ transfer_time =
+ (SANE_Word) ((SANE_Word) (dev->pixel_rate) *
+ (SANE_Word) (dev->x_dpi) / 600);
+ /* base on 600, but double it. */
+
+ if (transfer_time > 16000)
+ transfer_time = 16000;
+ if (dev->chip->sensor == ST_CANON300600)
+ {
+ ideal_expose_time =
+ MAX (MAX (2688, max_light_up),
+ MAX (transfer_time,
+ usb_mid_motor_mono_capability (dev->chip, dev->y_dpi)));
+ }
+ else if (dev->chip->sensor == ST_CANON300)
+ {
+ ideal_expose_time = MAX (MAX (2688, max_light_up), /* fixme? */
+ MAX (transfer_time,
+ usb_mid_motor_mono_capability (dev->chip,
+ dev->
+ y_dpi)));
+ }
+ else
+ {
+ ideal_expose_time =
+ MAX (MAX (5376, max_light_up),
+ MAX (transfer_time,
+ usb_mid_motor_mono_capability (dev->chip, dev->y_dpi)));
+ }
+
+ ideal_expose_time = (ideal_expose_time + 63) / 64 * 64;
+ *ideal_red_pd = (SANE_Byte) ((ideal_expose_time) / 64);
+ *ideal_green_pd = (SANE_Byte) ((ideal_expose_time - max_light_up) / 64);
+ *ideal_blue_pd = (SANE_Byte) ((ideal_expose_time) / 64);
+ DBG (5, "usb_high_scan_calculate_max_mono_300_expose: exit\n");
+ return ideal_expose_time;
+}
+
+SANE_Status
+usb_high_scan_prepare_rgb_signal_600_dpi (Mustek_Usb_Device * dev)
+{
+ SANE_Byte ideal_red_pd, ideal_green_pd, ideal_blue_pd;
+ SANE_Word ideal_expose_time;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_rgb_signal_600_dpi: start\n");
+ ideal_expose_time = usb_high_scan_calculate_max_rgb_600_expose
+ (dev, &ideal_red_pd, &ideal_green_pd, &ideal_blue_pd);
+
+ RIE (usb_low_set_ccd_width (dev->chip, ideal_expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->red_rgb_600_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->green_rgb_600_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->blue_rgb_600_pga));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_red_pd (dev->chip, ideal_red_pd));
+ RIE (usb_low_set_green_pd (dev->chip, ideal_green_pd));
+ RIE (usb_low_set_blue_pd (dev->chip, ideal_blue_pd));
+ DBG (5, "usb_high_scan_prepare_rgb_signal_600_dpi: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_mono_signal_600_dpi (Mustek_Usb_Device * dev)
+{
+ SANE_Byte ideal_red_pd, ideal_green_pd, ideal_blue_pd;
+ SANE_Word ideal_expose_time;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_mono_signal_600_dpi: start\n");
+ ideal_expose_time = usb_high_scan_calculate_max_mono_600_expose
+ (dev, &ideal_red_pd, &ideal_green_pd, &ideal_blue_pd);
+
+ RIE (usb_low_set_ccd_width (dev->chip, ideal_expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->mono_600_pga));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_red_pd (dev->chip, ideal_red_pd));
+ RIE (usb_low_set_green_pd (dev->chip, ideal_green_pd));
+ RIE (usb_low_set_blue_pd (dev->chip, ideal_blue_pd));
+ DBG (5, "usb_high_scan_prepare_mono_signal_600_dpi: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_rgb_signal_300_dpi (Mustek_Usb_Device * dev)
+{
+ SANE_Byte ideal_red_pd, ideal_green_pd, ideal_blue_pd;
+ SANE_Word ideal_expose_time;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_rgb_signal_300_dpi: start\n");
+
+ ideal_expose_time = usb_high_scan_calculate_max_rgb_300_expose
+ (dev, &ideal_red_pd, &ideal_green_pd, &ideal_blue_pd);
+
+ RIE (usb_low_set_ccd_width (dev->chip, ideal_expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->red_rgb_300_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->green_rgb_300_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->blue_rgb_300_pga));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_red_pd (dev->chip, ideal_red_pd));
+ RIE (usb_low_set_green_pd (dev->chip, ideal_green_pd));
+ RIE (usb_low_set_blue_pd (dev->chip, ideal_blue_pd));
+ DBG (5, "usb_high_scan_prepare_rgb_signal_300_dpi: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_mono_signal_300_dpi (Mustek_Usb_Device * dev)
+{
+ /* Setup Scan Here */
+ SANE_Byte ideal_red_pd, ideal_green_pd, ideal_blue_pd;
+ SANE_Word ideal_expose_time;
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_mono_signal_300_dpi: start\n");
+ ideal_expose_time = usb_high_scan_calculate_max_mono_300_expose
+ (dev, &ideal_red_pd, &ideal_green_pd, &ideal_blue_pd);
+
+ RIE (usb_low_set_ccd_width (dev->chip, ideal_expose_time));
+ RIE (usb_mid_front_set_front_end_mode (dev->chip, dev->init_front_end));
+ RIE (usb_mid_front_set_top_reference (dev->chip, dev->init_top_ref));
+ RIE (usb_mid_front_set_red_offset (dev->chip, dev->init_red_offset));
+ RIE (usb_mid_front_set_green_offset (dev->chip, dev->init_green_offset));
+ RIE (usb_mid_front_set_blue_offset (dev->chip, dev->init_blue_offset));
+ RIE (usb_mid_front_set_red_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_mid_front_set_green_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_mid_front_set_blue_pga (dev->chip, dev->mono_300_pga));
+ RIE (usb_mid_front_set_rgb_signal (dev->chip));
+ RIE (usb_low_set_red_pd (dev->chip, ideal_red_pd));
+ RIE (usb_low_set_green_pd (dev->chip, ideal_green_pd));
+ RIE (usb_low_set_blue_pd (dev->chip, ideal_blue_pd));
+ DBG (5, "usb_high_scan_prepare_mono_signal_300_dpi: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_rgb_24 (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_rgb_24: start\n");
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->bytes_per_strip));
+ RIE (usb_low_set_dummy (dev->chip, dev->dummy));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+ DBG (5, "usb_high_scan_prepare_rgb_24: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_prepare_mono_8 (Mustek_Usb_Device * dev)
+{
+ SANE_Status status;
+
+ DBG (5, "usb_high_scan_prepare_mono_8: start\n");
+ RIE (usb_low_set_image_byte_width (dev->chip, dev->bytes_per_strip));
+ RIE (usb_low_set_dummy (dev->chip, dev->dummy));
+ RIE (usb_low_set_pixel_depth (dev->chip, PD_8BIT));
+ DBG (5, "usb_high_scan_prepare_mono_8: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_get_rgb_24_bit_line (Mustek_Usb_Device * dev, SANE_Byte * line,
+ SANE_Bool is_order_invert)
+{
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ DBG (5, "usb_high_scan_get_rgb_24_bit_line: start, dev=%p, line=%p, "
+ "is_order_invert=%d\n", (void *) dev, line, is_order_invert);
+
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+
+ RIE (usb_low_get_row (dev->chip, dev->blue, &lines_left));
+
+ RIE (usb_low_get_row (dev->chip, dev->red, &lines_left));
+ RIE (usb_high_cal_calibrate (dev->green_calibrator,
+ dev->green + dev->skips_per_row, line + 1));
+ RIE (usb_high_cal_calibrate (dev->blue_calibrator,
+ dev->blue + dev->skips_per_row,
+ line + ((is_order_invert) ? 0 : 2)));
+ RIE (usb_high_cal_calibrate (dev->red_calibrator,
+ dev->red + dev->skips_per_row,
+ line + ((is_order_invert) ? 2 : 0)));
+
+ DBG (5, "usb_high_scan_get_rgb_24_bit_line: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+usb_high_scan_get_mono_8_bit_line (Mustek_Usb_Device * dev, SANE_Byte * line,
+ SANE_Bool is_order_invert)
+{
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ DBG (5, "usb_high_scan_get_mono_8_bit_line: start, dev=%p, line=%p, "
+ "is_order_invert=%d\n", (void *) dev, line, is_order_invert);
+
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ RIE (usb_high_cal_calibrate (dev->mono_calibrator, dev->green +
+ dev->skips_per_row, line));
+ DBG (5, "usb_high_scan_get_mono_8_bit_line: exit\n");
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_backtrack_rgb_24 (Mustek_Usb_Device * dev)
+{
+ DBG (5, "usb_high_scan_backtrack_rgb_24: noop, dev=%p\n", (void *) dev);
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+usb_high_scan_backtrack_mono_8 (Mustek_Usb_Device * dev)
+{
+ SANE_Int i;
+ SANE_Status status;
+ SANE_Word lines_left;
+
+ DBG (5, "usb_high_scan_backtrack_mono_8: start, dev=%p\n", (void *) dev);
+
+ if (dev->y_dpi >= 300)
+ {
+ RIE (usb_low_stop_rowing (dev->chip));
+ RIE (usb_low_set_motor_direction (dev->chip, SANE_TRUE));
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < dev->init_mono_8_back_track; i++)
+ {
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ }
+ usleep (100 * 1000);
+ RIE (usb_low_stop_rowing (dev->chip));
+ RIE (usb_low_set_motor_direction (dev->chip, SANE_FALSE));
+ RIE (usb_low_start_rowing (dev->chip));
+ for (i = 0; i < dev->init_mono_8_back_track; i++)
+ {
+ RIE (usb_low_get_row (dev->chip, dev->green, &lines_left));
+ }
+ }
+ DBG (5, "usb_high_scan_backtrack_mono_8: exit\n");
+ return SANE_STATUS_GOOD;
+}