summaryrefslogtreecommitdiff
path: root/backend/genesys_gl646.cc
diff options
context:
space:
mode:
Diffstat (limited to 'backend/genesys_gl646.cc')
-rw-r--r--backend/genesys_gl646.cc4911
1 files changed, 0 insertions, 4911 deletions
diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc
deleted file mode 100644
index b2b9f62..0000000
--- a/backend/genesys_gl646.cc
+++ /dev/null
@@ -1,4911 +0,0 @@
-/* sane - Scanner Access Now Easy.
-
- Copyright (C) 2003 Oliver Rauch
- Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de>
- Copyright (C) 2004 Gerhard Jaeger <gerhard@gjaeger.de>
- Copyright (C) 2004-2013 Stéphane Voltz <stef.dev@free.fr>
- Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
- Copyright (C) 2007 Luke <iceyfor@gmail.com>
- Copyright (C) 2011 Alexey Osipov <simba@lerlan.ru> for HP2400 description
- and tuning
-
- 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.
-*/
-
-#define DEBUG_DECLARE_ONLY
-
-#include "genesys_gl646.h"
-
-#include <vector>
-
-/**
- * reads value from gpio endpoint
- */
-static void gl646_gpio_read(UsbDevice& usb_dev, uint8_t* value)
-{
- DBG_HELPER(dbg);
- usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, GPIO_READ, INDEX, 1, value);
-}
-
-/**
- * writes the given value to gpio endpoint
- */
-static void gl646_gpio_write(UsbDevice& usb_dev, uint8_t value)
-{
- DBG_HELPER_ARGS(dbg, "(0x%02x)", value);
- usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_WRITE, INDEX, 1, &value);
-}
-
-/**
- * writes the given value to gpio output enable endpoint
- */
-static void gl646_gpio_output_enable(UsbDevice& usb_dev, uint8_t value)
-{
- DBG_HELPER_ARGS(dbg, "(0x%02x)", value);
- usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, INDEX, 1, &value);
-}
-
-/* Read bulk data (e.g. scanned data) */
-static SANE_Status
-gl646_bulk_read_data (Genesys_Device * dev, uint8_t addr,
- uint8_t * data, size_t len)
-{
- SANE_Status status = sanei_genesys_bulk_read_data(dev, addr, data, len);
- if (status != SANE_STATUS_GOOD) {
- return status;
- }
- if (dev->model->is_sheetfed == SANE_TRUE) {
- gl646_detect_document_end (dev);
- }
- return status;
-}
-
-static SANE_Bool
-gl646_get_fast_feed_bit (Genesys_Register_Set * regs)
-{
- GenesysRegister *r = NULL;
-
- r = sanei_genesys_get_address (regs, 0x02);
- if (r && (r->value & REG02_FASTFED))
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_get_filter_bit (Genesys_Register_Set * regs)
-{
- GenesysRegister *r = NULL;
-
- r = sanei_genesys_get_address (regs, 0x04);
- if (r && (r->value & REG04_FILTER))
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_get_lineart_bit (Genesys_Register_Set * regs)
-{
- GenesysRegister *r = NULL;
-
- r = sanei_genesys_get_address (regs, 0x04);
- if (r && (r->value & REG04_LINEART))
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_get_bitset_bit (Genesys_Register_Set * regs)
-{
- GenesysRegister *r = NULL;
-
- r = sanei_genesys_get_address (regs, 0x04);
- if (r && (r->value & REG04_BITSET))
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_get_gain4_bit (Genesys_Register_Set * regs)
-{
- GenesysRegister *r = NULL;
-
- r = sanei_genesys_get_address (regs, 0x06);
- if (r && (r->value & REG06_GAIN4))
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_test_buffer_empty_bit (SANE_Byte val)
-{
- if (val & REG41_BUFEMPTY)
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-static SANE_Bool
-gl646_test_motor_flag_bit (SANE_Byte val)
-{
- if (val & REG41_MOTMFLG)
- return SANE_TRUE;
- return SANE_FALSE;
-}
-
-/**
- * decodes and prints content of status (0x41) register
- * @param val value read from reg41
- */
-static void
-print_status (uint8_t val)
-{
- char msg[80];
-
- sprintf (msg, "%s%s%s%s%s%s%s%s",
- val & REG41_PWRBIT ? "PWRBIT " : "",
- val & REG41_BUFEMPTY ? "BUFEMPTY " : "",
- val & REG41_FEEDFSH ? "FEEDFSH " : "",
- val & REG41_SCANFSH ? "SCANFSH " : "",
- val & REG41_HOMESNR ? "HOMESNR " : "",
- val & REG41_LAMPSTS ? "LAMPSTS " : "",
- val & REG41_FEBUSY ? "FEBUSY " : "",
- val & REG41_MOTMFLG ? "MOTMFLG" : "");
- DBG(DBG_info, "status=%s\n", msg);
-}
-
-/**
- * start scanner's motor
- * @param dev scanner's device
- */
-static SANE_Status
-gl646_start_motor (Genesys_Device * dev)
-{
- return sanei_genesys_write_register (dev, 0x0f, 0x01);
-}
-
-
-/**
- * stop scanner's motor
- * @param dev scanner's device
- */
-static SANE_Status
-gl646_stop_motor (Genesys_Device * dev)
-{
- return sanei_genesys_write_register (dev, 0x0f, 0x00);
-}
-
-
-/**
- * find the lowest resolution for the sensor in the given mode.
- * @param sensor id of the sensor
- * @param color true is color mode
- * @return the closest resolution for the sensor and mode
- */
-static int
-get_lowest_resolution(int sensor_id, unsigned channels)
-{
- int i, nb;
- int dpi;
-
- i = 0;
- dpi = 9600;
- nb = sizeof (sensor_master) / sizeof (Sensor_Master);
- while (i < nb)
- {
- /* computes distance and keep mode if it is closer than previous */
- if (sensor_id == sensor_master[i].sensor
- && sensor_master[i].channels == channels)
- {
- if (sensor_master[i].dpi < dpi)
- {
- dpi = sensor_master[i].dpi;
- }
- }
- i++;
- }
- DBG(DBG_info, "%s: %d\n", __func__, dpi);
- return dpi;
-}
-
-/**
- * find the closest match in mode tables for the given resolution and scan mode.
- * @param sensor id of the sensor
- * @param required required resolution
- * @param color true is color mode
- * @return the closest resolution for the sensor and mode
- */
-static int
-get_closest_resolution(int sensor_id, int required, unsigned channels)
-{
- int i, nb;
- int dist, dpi;
-
- i = 0;
- dpi = 0;
- dist = 9600;
- nb = sizeof (sensor_master) / sizeof (Sensor_Master);
- while (i < nb)
- {
- /* exit on perfect match */
- if (sensor_id == sensor_master[i].sensor
- && sensor_master[i].dpi == required
- && sensor_master[i].channels == channels)
- {
- DBG(DBG_info, "%s: match found for %d\n", __func__, required);
- return required;
- }
- /* computes distance and keep mode if it is closer than previous */
- if (sensor_id == sensor_master[i].sensor
- && sensor_master[i].channels == channels)
- {
- if (abs (sensor_master[i].dpi - required) < dist)
- {
- dpi = sensor_master[i].dpi;
- dist = abs (sensor_master[i].dpi - required);
- }
- }
- i++;
- }
- DBG(DBG_info, "%s: closest match for %d is %d\n", __func__, required, dpi);
- return dpi;
-}
-
-/**
- * Computes if sensor will be set up for half ccd pixels for the given
- * scan mode.
- * @param sensor id of the sensor
- * @param required required resolution
- * @param color true is color mode
- * @return SANE_TRUE if half ccd is used
- */
-static SANE_Bool is_half_ccd(int sensor_id, int required, unsigned channels)
-{
- int i, nb;
-
- i = 0;
- nb = sizeof (sensor_master) / sizeof (Sensor_Master);
- while (i < nb)
- {
- /* exit on perfect match */
- if (sensor_id == sensor_master[i].sensor
- && sensor_master[i].dpi == required
- && sensor_master[i].channels == channels)
- {
- DBG(DBG_io, "%s: match found for %d (half_ccd=%d)\n", __func__, required,
- sensor_master[i].half_ccd);
- return sensor_master[i].half_ccd;
- }
- i++;
- }
- DBG(DBG_info, "%s: failed to find match for %d dpi\n", __func__, required);
- return SANE_FALSE;
-}
-
-/**
- * Returns the cksel values used by the required scan mode.
- * @param sensor id of the sensor
- * @param required required resolution
- * @param color true is color mode
- * @return cksel value for mode
- */
-static int get_cksel(int sensor_id, int required, unsigned channels)
-{
- int i, nb;
-
- i = 0;
- nb = sizeof (sensor_master) / sizeof (Sensor_Master);
- while (i < nb)
- {
- /* exit on perfect match */
- if (sensor_id == sensor_master[i].sensor
- && sensor_master[i].dpi == required
- && sensor_master[i].channels == channels)
- {
- DBG(DBG_io, "%s: match found for %d (cksel=%d)\n", __func__, required,
- sensor_master[i].cksel);
- return sensor_master[i].cksel;
- }
- i++;
- }
- DBG(DBG_error, "%s: failed to find match for %d dpi\n", __func__, required);
- /* fail safe fallback */
- return 1;
-}
-
-/**
- * Setup register and motor tables for a scan at the
- * given resolution and color mode. TODO try to not use any filed from
- * the device.
- * @param dev pointer to a struct describing the device
- * @param regs register set to fill
- * @param slope_table1 first motor table to fill
- * @param slope_table2 second motor table to fill
- * @return SANE_STATUS_GOOD if registers could be set, SANE_STATUS_INVAL if
- * conditions can't be met.
- * @note No harcoded SENSOR or MOTOR 'names' should be present and
- * registers are set from settings tables and flags related
- * to the hardware capabilities.
- * */
-static SANE_Status
-gl646_setup_registers (Genesys_Device * dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set * regs,
- SetupParams& params,
- uint16_t * slope_table1,
- uint16_t * slope_table2,
- bool xcorrection)
-{
- int resolution = params.xres;
- uint32_t move = params.starty;
- uint32_t linecnt = params.lines;
-
- uint32_t startx = 0;
- /* pixels are allways given at full CCD optical resolution */
- /* use detected left margin and fixed value */
- if (xcorrection == SANE_TRUE) {
- if (sensor.CCD_start_xoffset > 0) {
- startx = sensor.CCD_start_xoffset;
- } else {
- startx = sensor.dummy_pixel;
- }
- } else {
- // startx cannot be below dummy pixel value
- startx = sensor.dummy_pixel;
- }
-
- /* add x coordinates : expressed in sensor max dpi */
- startx += params.startx;
-
- /* stagger works with odd start cordinates */
- if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) {
- startx |= 1;
- }
-
- uint32_t pixels = (params.pixels * sensor.optical_res) / params.xres;
- /* special requirement for 400 dpi on 1200 dpi sensors */
- if (params.xres == 400)
- {
- pixels = (pixels / 6) * 6;
- }
- /* TODO check for pixel width overflow */
- uint32_t endx = startx + pixels;
-
- SANE_Status status = SANE_STATUS_GOOD;
- int i, nb;
- Sensor_Master *sensor_mst = NULL;
- Motor_Master *motor = NULL;
- Sensor_Settings *settings = NULL;
- GenesysRegister *r;
- unsigned int used1, used2, vfinal;
- unsigned int bpp; /**> bytes per pixel */
- uint32_t z1, z2;
- uint16_t ex, sx;
- int stagger, words_per_line, max_shift;
- size_t requested_buffer_size;
- size_t read_buffer_size;
- SANE_Bool half_ccd = SANE_FALSE;
- SANE_Int xresolution;
- int feedl;
-
- DBG(DBG_proc, "%s: start\n", __func__);
- DBG(DBG_info, "%s: startx=%d, endx=%d, linecnt=%d\n", __func__, startx, endx, linecnt);
-
- /* x resolution is capped by sensor's capability */
- if (resolution > sensor.optical_res)
- {
- xresolution = sensor.optical_res;
- }
- else
- {
- xresolution = resolution;
- }
-
- /* for the given resolution, search for master
- * sensor mode setting */
- i = 0;
- nb = sizeof (sensor_master) / sizeof (Sensor_Master);
- while (i < nb)
- {
- if (dev->model->ccd_type == sensor_master[i].sensor
- && sensor_master[i].dpi == xresolution
- && sensor_master[i].channels == params.channels)
- {
- sensor_mst = &sensor_master[i];
- }
- i++;
- }
- if (sensor_mst == NULL)
- {
- DBG(DBG_error, "%s: unable to find settings for sensor %d at %d dpi channels=%d\n", __func__,
- dev->model->ccd_type, xresolution, params.channels);
- return SANE_STATUS_INVAL;
- }
-
- /* for the given resolution, search for master
- * motor mode setting */
- i = 0;
- nb = sizeof (motor_master) / sizeof (Motor_Master);
- while (i < nb)
- {
- if (dev->model->motor_type == motor_master[i].motor
- && motor_master[i].dpi == resolution
- && motor_master[i].channels == params.channels)
- {
- motor = &motor_master[i];
- }
- i++;
- }
- if (motor == NULL)
- {
- DBG(DBG_error, "%s: unable to find settings for motor %d at %d dpi, color=%d\n", __func__,
- dev->model->motor_type, resolution, params.channels);
- return SANE_STATUS_INVAL;
- }
-
- /* now we can search for the specific sensor settings */
- i = 0;
- nb = sizeof (sensor_settings) / sizeof (Sensor_Settings);
- while (i < nb)
- {
- if (sensor_mst->sensor == sensor_settings[i].sensor
- && sensor_mst->cksel == sensor_settings[i].cksel)
- {
- settings = &sensor_settings[i];
- }
- i++;
- }
- if (settings == NULL)
- {
- DBG(DBG_error, "%s: unable to find settings for sensor %d with '%d' ccd timing\n", __func__,
- sensor_mst->sensor, sensor_mst->cksel);
- return SANE_STATUS_INVAL;
- }
-
- /* half_ccd if manual clock programming or dpi is half dpiset */
- half_ccd = sensor_mst->half_ccd;
-
- /* now apply values from settings to registers */
- if (sensor_mst->regs_0x10_0x15 != NULL)
- {
- for (i = 0; i < 6; i++)
- {
- r = sanei_genesys_get_address (regs, 0x10 + i);
- r->value = sensor_mst->regs_0x10_0x15[i];
- }
- }
- else
- {
- for (i = 0; i < 6; i++)
- {
- r = sanei_genesys_get_address (regs, 0x10 + i);
- r->value = 0;
- }
- }
-
- for (i = 0; i < 4; i++)
- {
- r = sanei_genesys_get_address (regs, 0x08 + i);
- if (half_ccd == SANE_TRUE)
- r->value = settings->manual_0x08_0x0b[i];
- else
- r->value = settings->regs_0x08_0x0b[i];
- }
-
- for (i = 0; i < 8; i++)
- {
- r = sanei_genesys_get_address (regs, 0x16 + i);
- r->value = settings->regs_0x16_0x1d[i];
- }
-
- for (i = 0; i < 13; i++)
- {
- r = sanei_genesys_get_address (regs, 0x52 + i);
- r->value = settings->regs_0x52_0x5e[i];
- }
- if (half_ccd == SANE_TRUE)
- {
- for (i = 0; i < 7; i++)
- {
- r = sanei_genesys_get_address (regs, 0x52 + i);
- r->value = settings->manual_0x52_0x58[i];
- }
- }
-
- /* now generate slope tables : we are not using generate_slope_table3 yet */
- sanei_genesys_generate_slope_table (slope_table1, motor->steps1,
- motor->steps1 + 1, motor->vend1,
- motor->vstart1, motor->vend1,
- motor->steps1, motor->g1, &used1,
- &vfinal);
- sanei_genesys_generate_slope_table (slope_table2, motor->steps2,
- motor->steps2 + 1, motor->vend2,
- motor->vstart2, motor->vend2,
- motor->steps2, motor->g2, &used2,
- &vfinal);
-
- /* R01 */
- /* now setup other registers for final scan (ie with shading enabled) */
- /* watch dog + shading + scan enable */
- regs->find_reg(0x01).value |= REG01_DOGENB | REG01_DVDSET | REG01_SCAN;
- if (dev->model->is_cis == SANE_TRUE)
- regs->find_reg(0x01).value |= REG01_CISSET;
- else
- regs->find_reg(0x01).value &= ~REG01_CISSET;
-
- /* if device has no calibration, don't enable shading correction */
- if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)
- {
- regs->find_reg(0x01).value &= ~REG01_DVDSET;
- }
-
- regs->find_reg(0x01).value &= ~REG01_FASTMOD;
- if (motor->fastmod)
- regs->find_reg(0x01).value |= REG01_FASTMOD;
-
- /* R02 */
- /* allow moving when buffer full by default */
- if (dev->model->is_sheetfed == SANE_FALSE)
- dev->reg.find_reg(0x02).value &= ~REG02_ACDCDIS;
- else
- dev->reg.find_reg(0x02).value |= REG02_ACDCDIS;
-
- /* setup motor power and direction */
- sanei_genesys_set_motor_power(*regs, true);
- regs->find_reg(0x02).value &= ~REG02_MTRREV;
-
- /* fastfed enabled (2 motor slope tables) */
- if (motor->fastfed)
- regs->find_reg(0x02).value |= REG02_FASTFED;
- else
- regs->find_reg(0x02).value &= ~REG02_FASTFED;
-
- /* step type */
- regs->find_reg(0x02).value &= ~REG02_STEPSEL;
- switch (motor->steptype)
- {
- case FULL_STEP:
- break;
- case HALF_STEP:
- regs->find_reg(0x02).value |= 1;
- break;
- case QUATER_STEP:
- regs->find_reg(0x02).value |= 2;
- break;
- default:
- regs->find_reg(0x02).value |= 3;
- break;
- }
-
- /* if sheetfed, no AGOHOME */
- if (dev->model->is_sheetfed == SANE_TRUE)
- {
- regs->find_reg(0x02).value &= ~REG02_AGOHOME;
- }
- else
- {
- regs->find_reg(0x02).value |= REG02_AGOHOME;
- }
-
- /* R03 */
- regs->find_reg(0x03).value &= ~REG03_AVEENB;
- /* regs->find_reg(0x03).value |= REG03_AVEENB; */
- regs->find_reg(0x03).value &= ~REG03_LAMPDOG;
-
- /* select XPA */
- regs->find_reg(0x03).value &= ~REG03_XPASEL;
- if (params.flags & SCAN_FLAG_USE_XPA) {
- regs->find_reg(0x03).value |= REG03_XPASEL;
- }
- regs->state.is_xpa_on = params.flags & SCAN_FLAG_USE_XPA;
-
- /* R04 */
- /* monochrome / color scan */
- switch (params.depth)
- {
- case 1:
- regs->find_reg(0x04).value &= ~REG04_BITSET;
- regs->find_reg(0x04).value |= REG04_LINEART;
- break;
- case 8:
- regs->find_reg(0x04).value &= ~(REG04_LINEART | REG04_BITSET);
- break;
- case 16:
- regs->find_reg(0x04).value &= ~REG04_LINEART;
- regs->find_reg(0x04).value |= REG04_BITSET;
- break;
- }
-
- /* R05 */
- regs->find_reg(0x05).value &= ~REG05_DPIHW;
- switch (sensor.optical_res)
- {
- case 600:
- regs->find_reg(0x05).value |= REG05_DPIHW_600;
- break;
- case 1200:
- regs->find_reg(0x05).value |= REG05_DPIHW_1200;
- break;
- case 2400:
- regs->find_reg(0x05).value |= REG05_DPIHW_2400;
- break;
- default:
- regs->find_reg(0x05).value |= REG05_DPIHW;
- }
-
- /* gamma enable for scans */
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA)
- regs->find_reg(0x05).value |= REG05_GMM14BIT;
-
- regs->find_reg(0x05).value &= ~REG05_GMMENB;
-
- /* true CIS gray if needed */
- if (dev->model->is_cis == SANE_TRUE && params.channels == 1
- && dev->settings.true_gray)
- {
- regs->find_reg(0x05).value |= REG05_LEDADD;
- }
- else
- {
- regs->find_reg(0x05).value &= ~REG05_LEDADD;
- }
-
- /* cktoggle, ckdelay and cksel at once, cktdelay=2 => half_ccd for md5345 */
- regs->find_reg(0x18).value = sensor_mst->r18;
-
- /* manual CCD/2 clock programming => half_ccd for hp2300 */
- regs->find_reg(0x1d).value = sensor_mst->r1d;
-
- /* HP2400 1200dpi mode tuning */
-
- if (dev->model->ccd_type == CCD_HP2400)
- {
- /* reset count of dummy lines to zero */
- regs->find_reg(0x1e).value &= ~REG1E_LINESEL;
- if (params.xres >= 1200)
- {
- /* there must be one dummy line */
- regs->find_reg(0x1e).value |= 1 & REG1E_LINESEL;
-
- /* GPO12 need to be set to zero */
- regs->find_reg(0x66).value &= ~0x20;
- }
- else
- {
- /* set GPO12 back to one */
- regs->find_reg(0x66).value |= 0x20;
- }
- }
-
- /* motor steps used */
- regs->find_reg(0x21).value = motor->steps1;
- regs->find_reg(0x22).value = motor->fwdbwd;
- regs->find_reg(0x23).value = motor->fwdbwd;
- regs->find_reg(0x24).value = motor->steps1;
-
- /* scanned area height must be enlarged by max color shift needed */
- max_shift=sanei_genesys_compute_max_shift(dev,params.channels, params.yres, 0);
-
- /* we adjust linecnt according to real motor dpi */
- linecnt = (linecnt * motor->ydpi) / params.yres + max_shift;
-
- /* at QUATER_STEP lines are 'staggered' and need correction */
- stagger = 0;
- if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE))
- {
- /* for HP3670, stagger happens only at >=1200 dpi */
- if ((dev->model->motor_type != MOTOR_HP3670 && dev->model->motor_type != MOTOR_HP2400)
- || params.yres >= (unsigned) sensor.optical_res)
- {
- stagger = (4 * params.yres) / dev->motor.base_ydpi;
- }
- }
- linecnt += stagger;
-
- DBG(DBG_info, "%s : max_shift=%d, stagger=%d lines\n", __func__, max_shift, stagger);
-
- /* CIS scanners read one line per color channel
- * since gray mode use 'add' we also read 3 channels even not in
- * color mode */
- if (dev->model->is_cis == SANE_TRUE)
- {
- sanei_genesys_set_triple(regs, REG_LINCNT, linecnt * 3);
- linecnt *= params.channels;
- }
- else
- {
- sanei_genesys_set_triple(regs, REG_LINCNT, linecnt);
- }
-
- /* scanner's x coordinates are expressed in physical DPI but they must be divided by cksel */
- sx = startx / sensor_mst->cksel;
- ex = endx / sensor_mst->cksel;
- if (half_ccd == SANE_TRUE)
- {
- sx /= 2;
- ex /= 2;
- }
- sanei_genesys_set_double(regs, REG_STRPIXEL, sx);
- sanei_genesys_set_double(regs, REG_ENDPIXEL, ex);
- DBG(DBG_info, "%s: startx=%d, endx=%d, half_ccd=%d\n", __func__, sx, ex, half_ccd);
-
- /* words_per_line must be computed according to the scan's resolution */
- /* in fact, words_per_line _gives_ the actual scan resolution */
- words_per_line = (((endx - startx) * sensor_mst->xdpi) / sensor.optical_res);
- bpp=params.depth/8;
- if (params.depth == 1)
- {
- words_per_line = (words_per_line+7)/8 ;
- bpp=1;
- }
- else
- {
- words_per_line *= bpp;
- }
- dev->bpl = words_per_line;
- words_per_line *= params.channels;
- dev->wpl = words_per_line;
-
- DBG(DBG_info, "%s: wpl=%d\n", __func__, words_per_line);
- sanei_genesys_set_triple(regs, REG_MAXWD, words_per_line);
-
- sanei_genesys_set_double(regs, REG_DPISET, sensor_mst->dpiset);
- sanei_genesys_set_double(regs, REG_LPERIOD, sensor_mst->exposure);
-
- /* move distance must be adjusted to take into account the extra lines
- * read to reorder data */
- feedl = move;
- if (stagger + max_shift > 0 && feedl != 0)
- {
- if (feedl >
- ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi)
- feedl =
- feedl -
- ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi;
- }
-
- /* we assume all scans are done with 2 tables */
- /*
- feedl = feed_steps - fast_slope_steps*2 -
- (slow_slope_steps >> scan_step_type); */
- /* but head has moved due to shading calibration => dev->scanhead_position_in_steps */
- if (feedl > 0)
- {
- /* take into account the distance moved during calibration */
- /* feedl -= dev->scanhead_position_in_steps; */
- DBG(DBG_info, "%s: initial move=%d\n", __func__, feedl);
- DBG(DBG_info, "%s: scanhead_position_in_steps=%d\n", __func__,
- dev->scanhead_position_in_steps);
-
- /* TODO clean up this when I'll fully understand.
- * for now, special casing each motor */
- switch (dev->model->motor_type)
- {
- case MOTOR_5345:
- switch (motor->ydpi)
- {
- case 200:
- feedl -= 70;
- break;
- case 300:
- feedl -= 70;
- break;
- case 400:
- feedl += 130;
- break;
- case 600:
- feedl += 160;
- break;
- case 1200:
- feedl += 160;
- break;
- case 2400:
- feedl += 180;
- break;
- default:
- break;
- }
- break;
- case MOTOR_HP2300:
- switch (motor->ydpi)
- {
- case 75:
- feedl -= 180;
- break;
- case 150:
- feedl += 0;
- break;
- case 300:
- feedl += 30;
- break;
- case 600:
- feedl += 35;
- break;
- case 1200:
- feedl += 45;
- break;
- default:
- break;
- }
- break;
- case MOTOR_HP2400:
- switch (motor->ydpi)
- {
- case 150:
- feedl += 150;
- break;
- case 300:
- feedl += 220;
- break;
- case 600:
- feedl += 260;
- break;
- case 1200:
- feedl += 280; /* 300 */
- break;
- case 50:
- feedl += 0;
- break;
- case 100:
- feedl += 100;
- break;
- default:
- break;
- }
- break;
-
- /* theorical value */
- default:
- if (motor->fastfed)
- {
- feedl =
- feedl - 2 * motor->steps2 -
- (motor->steps1 >> motor->steptype);
- }
- else
- {
- feedl = feedl - (motor->steps1 >> motor->steptype);
- }
- break;
- }
- /* security */
- if (feedl < 0)
- feedl = 0;
- }
-
- DBG(DBG_info, "%s: final move=%d\n", __func__, feedl);
- sanei_genesys_set_triple(regs, REG_FEEDL, feedl);
-
- regs->find_reg(0x65).value = motor->mtrpwm;
-
- sanei_genesys_calculate_zmode2 (regs->find_reg(0x02).value & REG02_FASTFED,
- sensor_mst->exposure,
- slope_table1,
- motor->steps1,
- move, motor->fwdbwd, &z1, &z2);
-
- /* no z1/z2 for sheetfed scanners */
- if (dev->model->is_sheetfed == SANE_TRUE)
- {
- z1 = 0;
- z2 = 0;
- }
- sanei_genesys_set_double(regs, REG_Z1MOD, z1);
- sanei_genesys_set_double(regs, REG_Z2MOD, z2);
- regs->find_reg(0x6b).value = motor->steps2;
- regs->find_reg(0x6c).value =
- (regs->find_reg(0x6c).value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16)
- & 0x07);
-
- RIE (write_control (dev, sensor, xresolution));
-
- /* setup analog frontend */
- RIE (gl646_set_fe(dev, sensor, AFE_SET, xresolution));
-
- /* now we're done with registers setup values used by data transfer */
- /* we setup values needed for the data transfer */
-
- /* we must use a round number of words_per_line */
- requested_buffer_size = 8 * words_per_line;
- read_buffer_size =
- 2 * requested_buffer_size +
- ((max_shift + stagger) * params.pixels * params.channels * params.depth) / 8;
-
- dev->read_buffer.clear();
- dev->read_buffer.alloc(read_buffer_size);
-
- dev->lines_buffer.clear();
- dev->lines_buffer.alloc(read_buffer_size);
-
- dev->shrink_buffer.clear();
- dev->shrink_buffer.alloc(requested_buffer_size);
-
- dev->out_buffer.clear();
- dev->out_buffer.alloc(8 * params.pixels * params.channels * bpp);
-
- /* scan bytes to read */
- dev->read_bytes_left = words_per_line * linecnt;
-
- DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left);
- dev->read_active = SANE_TRUE;
-
- dev->current_setup.params = params;
- dev->current_setup.pixels =
- ((endx - startx) * sensor_mst->xdpi) / sensor.optical_res;
- dev->current_setup.lines = linecnt;
- dev->current_setup.depth = params.depth;
- dev->current_setup.channels = params.channels;
- dev->current_setup.exposure_time = sensor_mst->exposure;
- dev->current_setup.xres = sensor_mst->xdpi;
- dev->current_setup.yres = motor->ydpi;
- dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1;
- dev->current_setup.stagger = stagger;
- dev->current_setup.max_shift = max_shift + stagger;
-
- /* total_bytes_to_read is the number of byte to send to frontend
- * total_bytes_read is the number of bytes sent to frontend
- * read_bytes_left is the number of bytes to read from the scanner
- */
- dev->total_bytes_read = 0;
- if (params.depth == 1) {
- dev->total_bytes_to_read = ((params.pixels * params.lines) / 8 +
- (((params.pixels * params.lines) % 8) ? 1 : 0)) * params.channels;
- } else {
- dev->total_bytes_to_read = params.pixels * params.lines * params.channels * bpp;
- }
-
- /* select color filter based on settings */
- regs->find_reg(0x04).value &= ~REG04_FILTER;
- if (params.channels == 1) {
- switch (params.color_filter) {
- case ColorFilter::RED:
- regs->find_reg(0x04).value |= 0x04;
- break;
- case ColorFilter::GREEN:
- regs->find_reg(0x04).value |= 0x08;
- break;
- case ColorFilter::BLUE:
- regs->find_reg(0x04).value |= 0x0c;
- break;
- default:
- break;
- }
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return SANE_STATUS_GOOD;
-}
-
-
-/** copy sensor specific settings */
-/* *dev : device infos
- *regs : regiters to be set
- extended : do extended set up
- half_ccd: set up for half ccd resolution
- all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't
- appear anywhere else but in register init
-*/
-static void
-gl646_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * regs)
-{
- (void) dev;
- DBG(DBG_proc, "%s: start\n", __func__);
-
- for (const auto& reg_setting : sensor.custom_regs) {
- regs->set8(reg_setting.address, reg_setting.value);
- }
- // FIXME: all other drivers don't set exposure here
- sanei_genesys_set_exposure(*regs, sensor.exposure);
-
- DBG(DBG_proc, "%s: end\n", __func__);
-}
-
-/** Test if the ASIC works
- */
-static SANE_Status
-gl646_asic_test (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- uint8_t val;
- size_t size, verify_size;
- unsigned int i;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* set and read exposure time, compare if it's the same */
- status = sanei_genesys_write_register (dev, 0x38, 0xde);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = sanei_genesys_write_register (dev, 0x39, 0xad);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = sanei_genesys_read_register (dev, 0x4e, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- if (val != 0xde) /* value of register 0x38 */
- {
- DBG(DBG_error, "%s: register contains invalid value\n", __func__);
- return SANE_STATUS_IO_ERROR;
- }
-
- status = sanei_genesys_read_register (dev, 0x4f, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- if (val != 0xad) /* value of register 0x39 */
- {
- DBG(DBG_error, "%s: register contains invalid value\n", __func__);
- return SANE_STATUS_IO_ERROR;
- }
-
- /* ram test: */
- size = 0x40000;
- verify_size = size + 0x80;
- /* todo: looks like the read size must be a multiple of 128?
- otherwise the read doesn't succeed the second time after the scanner has
- been plugged in. Very strange. */
-
- std::vector<uint8_t> data(size);
- std::vector<uint8_t> verify_data(verify_size);
-
- for (i = 0; i < (size - 1); i += 2)
- {
- data[i] = i / 512;
- data[i + 1] = (i / 2) % 256;
- }
-
- status = sanei_genesys_set_buffer_address (dev, 0x0000);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = sanei_genesys_bulk_write_data(dev, 0x3c, data.data(), size);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write data: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = sanei_genesys_set_buffer_address (dev, 0x0000);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status =
- gl646_bulk_read_data (dev, 0x45, verify_data.data(), verify_size);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk read data: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* i + 2 is needed as the changed address goes into effect only after one
- data word is sent. */
- for (i = 0; i < size; i++)
- {
- if (verify_data[i + 2] != data[i])
- {
- DBG(DBG_error, "%s: data verification error\n", __func__);
- return SANE_STATUS_IO_ERROR;
- }
- }
-
- DBG(DBG_info, "%s: end\n", __func__);
-
- return SANE_STATUS_GOOD;
-}
-
-/**
- * Set all registers to default values after init
- * @param dev scannerr's device to set
- */
-static void
-gl646_init_regs (Genesys_Device * dev)
-{
- int addr;
-
- DBG(DBG_proc, "%s\n", __func__);
-
- dev->reg.clear();
-
- for (addr = 1; addr <= 0x0b; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x10; addr <= 0x29; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x2c; addr <= 0x39; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x3d; addr <= 0x3f; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x52; addr <= 0x5e; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x60; addr <= 0x6d; addr++)
- dev->reg.init_reg(addr, 0);
-
- dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */
- dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */
- if (dev->model->motor_type == MOTOR_5345)
- dev->reg.find_reg(0x02).value |= 0x01; /* half-step */
- switch (dev->model->motor_type)
- {
- case MOTOR_5345:
- dev->reg.find_reg(0x02).value |= 0x01; /* half-step */
- break;
- case MOTOR_XP200:
- /* for this sheetfed scanner, no AGOHOME, nor backtracking */
- dev->reg.find_reg(0x02).value = 0x50;
- break;
- default:
- break;
- }
- dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */
- dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */
- switch (dev->model->dac_type)
- {
- case DAC_AD_XP200:
- dev->reg.find_reg(0x04).value = 0x12;
- break;
- default:
- /* Wolfson frontend */
- dev->reg.find_reg(0x04).value = 0x13;
- break;
- }
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */
- switch (sensor.optical_res)
- {
- case 600:
- dev->reg.find_reg(0x05).value |= REG05_DPIHW_600;
- break;
- case 1200:
- dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200;
- break;
- case 2400:
- dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400;
- break;
- default:
- dev->reg.find_reg(0x05).value |= REG05_DPIHW;
- break;
- }
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA)
- dev->reg.find_reg(0x05).value |= REG05_GMM14BIT;
- if (dev->model->dac_type == DAC_AD_XP200)
- dev->reg.find_reg(0x05).value |= 0x01; /* 12 clocks/pixel */
-
- if (dev->model->ccd_type == CCD_HP2300)
- dev->reg.find_reg(0x06).value = 0x00; /* PWRBIT off, shading gain=4, normal AFE image capture */
- else
- dev->reg.find_reg(0x06).value = 0x18; /* PWRBIT on, shading gain=8, normal AFE image capture */
-
-
- gl646_setup_sensor(dev, sensor, &dev->reg);
-
- dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */
-
- switch (dev->model->ccd_type)
- {
- case CCD_HP2300:
- dev->reg.find_reg(0x1e).value = 0xf0;
- dev->reg.find_reg(0x1f).value = 0x10;
- dev->reg.find_reg(0x20).value = 0x20;
- break;
- case CCD_HP2400:
- dev->reg.find_reg(0x1e).value = 0x80;
- dev->reg.find_reg(0x1f).value = 0x10;
- dev->reg.find_reg(0x20).value = 0x20;
- break;
- case CCD_HP3670:
- dev->reg.find_reg(0x19).value = 0x2a;
- dev->reg.find_reg(0x1e).value = 0x80;
- dev->reg.find_reg(0x1f).value = 0x10;
- dev->reg.find_reg(0x20).value = 0x20;
- break;
- case CIS_XP200:
- dev->reg.find_reg(0x1e).value = 0x10;
- dev->reg.find_reg(0x1f).value = 0x01;
- dev->reg.find_reg(0x20).value = 0x50;
- break;
- default:
- dev->reg.find_reg(0x1f).value = 0x01;
- dev->reg.find_reg(0x20).value = 0x50;
- break;
- }
-
- dev->reg.find_reg(0x21).value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */
- dev->reg.find_reg(0x22).value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */
- dev->reg.find_reg(0x23).value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */
- dev->reg.find_reg(0x24).value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */
- dev->reg.find_reg(0x25).value = 0x00; /* scan line numbers (7000) */
- dev->reg.find_reg(0x26).value = 0x00 /*0x1b */ ;
- dev->reg.find_reg(0x27).value = 0xd4 /*0x58 */ ;
- dev->reg.find_reg(0x28).value = 0x01; /* PWM duty for lamp control */
- dev->reg.find_reg(0x29).value = 0xff;
-
- dev->reg.find_reg(0x2c).value = 0x02; /* set resolution (600 DPI) */
- dev->reg.find_reg(0x2d).value = 0x58;
- dev->reg.find_reg(0x2e).value = 0x78; /* set black&white threshold high level */
- dev->reg.find_reg(0x2f).value = 0x7f; /* set black&white threshold low level */
-
- dev->reg.find_reg(0x30).value = 0x00; /* begin pixel position (16) */
- dev->reg.find_reg(0x31).value = sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */
- dev->reg.find_reg(0x32).value = 0x2a /*0x15 */ ; /* end pixel position (5390) */
- dev->reg.find_reg(0x33).value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */
- dev->reg.find_reg(0x34).value = sensor.dummy_pixel;
- dev->reg.find_reg(0x35).value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */
- dev->reg.find_reg(0x36).value = 0x00 /*0x2a */ ;
- dev->reg.find_reg(0x37).value = 0x00 /*0x30 */ ;
- dev->reg.find_reg(0x38).value = 0x2a; // line period (exposure time = 11000 pixels) */
- dev->reg.find_reg(0x39).value = 0xf8;
- dev->reg.find_reg(0x3d).value = 0x00; /* set feed steps number of motor move */
- dev->reg.find_reg(0x3e).value = 0x00;
- dev->reg.find_reg(0x3f).value = 0x01 /*0x00 */ ;
-
- dev->reg.find_reg(0x60).value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */
- dev->reg.find_reg(0x61).value = 0x00; /* (21h+22h)/LPeriod */
- dev->reg.find_reg(0x62).value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */
- dev->reg.find_reg(0x63).value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */
- dev->reg.find_reg(0x64).value = 0x00; /* motor PWM frequency */
- dev->reg.find_reg(0x65).value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */
- if (dev->model->motor_type == MOTOR_5345)
- dev->reg.find_reg(0x65).value = 0x02; /* PWM duty cycle for table one motor phase (63 = max) */
- dev->reg.find_reg(0x66).value = dev->gpo.value[0];
- dev->reg.find_reg(0x67).value = dev->gpo.value[1];
- dev->reg.find_reg(0x68).value = dev->gpo.enable[0];
- dev->reg.find_reg(0x69).value = dev->gpo.enable[1];
-
- switch (dev->model->motor_type)
- {
- case MOTOR_HP2300:
- case MOTOR_HP2400:
- dev->reg.find_reg(0x6a).value = 0x7f; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6b).value = 0x78; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6d).value = 0x7f;
- break;
- case MOTOR_5345:
- dev->reg.find_reg(0x6a).value = 0x42; /* table two fast moving step type, PWM duty for table two */
- dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6d).value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */
- break;
- case MOTOR_XP200:
- dev->reg.find_reg(0x6a).value = 0x7f; /* table two fast moving step type, PWM duty for table two */
- dev->reg.find_reg(0x6b).value = 0x08; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */
- break;
- case MOTOR_HP3670:
- dev->reg.find_reg(0x6a).value = 0x41; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6b).value = 0xc8; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6d).value = 0x7f;
- break;
- default:
- dev->reg.find_reg(0x6a).value = 0x40; /* table two fast moving step type, PWM duty for table two */
- dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */
- dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */
- break;
- }
- dev->reg.find_reg(0x6c).value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */
-}
-
-
-/* Send slope table for motor movement
- slope_table in machine byte order
-*/
-static SANE_Status
-gl646_send_slope_table (Genesys_Device * dev, int table_nr,
- uint16_t * slope_table, int steps)
-{
- int dpihw;
- int start_address;
- SANE_Status status = SANE_STATUS_GOOD;
-
- DBG(DBG_proc, "%s (table_nr = %d, steps = %d)=%d .. %d\n", __func__, table_nr, steps,
- slope_table[0], slope_table[steps - 1]);
-
- dpihw = dev->reg.find_reg(0x05).value >> 6;
-
- if (dpihw == 0) /* 600 dpi */
- start_address = 0x08000;
- else if (dpihw == 1) /* 1200 dpi */
- start_address = 0x10000;
- else if (dpihw == 2) /* 2400 dpi */
- start_address = 0x1f800;
- else /* reserved */
- return SANE_STATUS_INVAL;
-
- std::vector<uint8_t> table(steps * 2);
- for (int i = 0; i < steps; i++)
- {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
-
- status =
- sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x100);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = sanei_genesys_bulk_write_data(dev, 0x3c, table.data(), steps * 2);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send slope table: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-/* Set values of Analog Device type frontend */
-static SANE_Status
-gl646_set_ad_fe (Genesys_Device * dev, uint8_t set)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- int i;
-
- DBG(DBG_proc, "%s(): start\n", __func__);
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type);
-
- dev->frontend = dev->frontend_initial;
-
- /* write them to analog frontend */
- status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- }
- if (set == AFE_SET)
- {
- for (i = 0; i < 3; i++)
- {
- status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write gain %d: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
- }
- for (i = 0; i < 3; i++)
- {
- status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write offset %d: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
- }
- }
- /*
- if (set == AFE_POWER_SAVE)
- {
- status =
- sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0] | 0x04);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- } */
- DBG(DBG_proc, "%s(): end\n", __func__);
-
- return status;
-}
-
-/** set up analog frontend
- * set up analog frontend
- * @param dev device to set up
- * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE
- * @param dpi resolution of the scan since it affects settings
- * @return SANE_STATUS_GOOD if evrithing OK
- */
-static SANE_Status
-gl646_wm_hp3670(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- int i;
-
- DBGSTART;
- switch (set)
- {
- case AFE_INIT:
- status = sanei_genesys_fe_write_data (dev, 0x04, 0x80);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: reset failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- sanei_genesys_sleep_ms(200);
- RIE (sanei_genesys_write_register (dev, 0x50, 0x00));
- dev->frontend = dev->frontend_initial;
- status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- gl646_gpio_output_enable(dev->usb_dev, 0x07);
- break;
- case AFE_POWER_SAVE:
- status = sanei_genesys_fe_write_data (dev, 0x01, 0x06);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_fe_write_data (dev, 0x06, 0x0f);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg6 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- return status;
- break;
- default: /* AFE_SET */
- /* mode setup */
- i = dev->frontend.regs.get_value(0x03);
- if (dpi > sensor.optical_res / 2)
- {
- /* fe_reg_0x03 must be 0x12 for 1200 dpi in DAC_WOLFSON_HP3670.
- * DAC_WOLFSON_HP2400 in 1200 dpi mode works well with
- * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */
- i = 0x12;
- }
- status = sanei_genesys_fe_write_data (dev, 0x03, i);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- /* offset and sign (or msb/lsb ?) */
- for (i = 0; i < 3; i++)
- {
- status =
- sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing offset%d failed: %s\n", __func__, i,
- sane_strstatus (status));
- return status;
- }
- status = sanei_genesys_fe_write_data(dev, 0x24 + i,
- dev->frontend.regs.get_value(0x24 + i)); /* MSB/LSB ? */
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing sign%d failed: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
- }
-
- /* gain */
- for (i = 0; i < 3; i++)
- {
- status =
- sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing gain%d failed: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
- }
- }
-
- DBGCOMPLETED;
- return status;
-}
-
-/** Set values of analog frontend
- * @param dev device to set
- * @param set action to execute
- * @param dpi dpi to setup the AFE
- * @return error or SANE_STATUS_GOOD */
-static SANE_Status
-gl646_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- int i;
- uint8_t val;
-
- DBG(DBG_proc, "%s (%s,%d)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set ==
- AFE_POWER_SAVE ? "powersave" : "huh?", dpi);
-
- /* Analog Device type frontend */
- if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02)
- return gl646_set_ad_fe (dev, set);
-
- /* Wolfson type frontend */
- if ((dev->reg.find_reg(0x04).value & REG04_FESET) != 0x03)
- {
- DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__,
- dev->reg.find_reg(0x04).value & REG04_FESET);
- return SANE_STATUS_UNSUPPORTED;
- }
-
- /* per frontend function to keep code clean */
- switch (dev->model->dac_type)
- {
- case DAC_WOLFSON_HP3670:
- case DAC_WOLFSON_HP2400:
- return gl646_wm_hp3670(dev, sensor, set, dpi);
- break;
- default:
- DBG(DBG_proc, "%s(): using old method\n", __func__);
- break;
- }
-
- /* initialize analog frontend */
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type);
- dev->frontend = dev->frontend_initial;
-
- /* reset only done on init */
- status = sanei_genesys_fe_write_data (dev, 0x04, 0x80);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: init fe failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* enable GPIO for some models */
- if (dev->model->ccd_type == CCD_HP2300)
- {
- val = 0x07;
- gl646_gpio_output_enable(dev->usb_dev, val);
- }
- return status;
- }
-
- /* set fontend to power saving mode */
- if (set == AFE_POWER_SAVE)
- {
- status = sanei_genesys_fe_write_data (dev, 0x01, 0x02);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing data failed: %s\n", __func__, sane_strstatus(status));
- }
- return status;
- }
-
- /* here starts AFE_SET */
- /* TODO : base this test on cfg reg3 or a CCD family flag to be created */
- /* if (dev->model->ccd_type != CCD_HP2300
- && dev->model->ccd_type != CCD_HP3670
- && dev->model->ccd_type != CCD_HP2400) */
- {
- status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg0 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- }
-
- /* start with reg3 */
- status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x03));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- switch (dev->model->ccd_type)
- {
- default:
- for (i = 0; i < 3; i++)
- {
- status =
- sanei_genesys_fe_write_data(dev, 0x24 + i,
- dev->frontend.regs.get_value(0x24 + i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
-
- status =
- sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
-
- status =
- sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i,
- sane_strstatus(status));
- return status;
- }
- }
- break;
- /* just can't have it to work ....
- case CCD_HP2300:
- case CCD_HP2400:
- case CCD_HP3670:
-
- status =
- sanei_genesys_fe_write_data(dev, 0x23, dev->frontend.get_offset(1));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing offset[1] failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_fe_write_data(dev, 0x28, dev->frontend.get_gain(1));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing gain[1] failed: %s\n", __func__, sane_strstatus (status));
- return status;
- }
- break; */
- }
-
- /* end with reg1 */
- status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
-
- DBG(DBG_proc, "%s: end\n", __func__);
-
- return SANE_STATUS_GOOD;
-}
-
-/** Set values of analog frontend
- * this this the public interface, the gl646 as to use one more
- * parameter to work effectively, hence the redirection
- * @param dev device to set
- * @param set action to execute
- * @return error or SANE_STATUS_GOOD */
-static SANE_Status
-gl646_public_set_fe (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set)
-{
- return gl646_set_fe(dev, sensor, set, dev->settings.yres);
-}
-
-/**
- * enters or leaves power saving mode
- * limited to AFE for now.
- * @param dev scanner's device
- * @param enable SANE_TRUE to enable power saving, SANE_FALSE to leave it
- * @return allways SANE_STATUS_GOOD
- */
-static
-SANE_Status
-gl646_save_power (Genesys_Device * dev, SANE_Bool enable)
-{
-
- DBGSTART;
- DBG(DBG_info, "%s: enable = %d\n", __func__, enable);
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- if (enable)
- {
- /* gl646_set_fe(dev, sensor, AFE_POWER_SAVE); */
- }
- else
- {
- gl646_set_fe(dev, sensor, AFE_INIT, 0);
- }
-
- DBGCOMPLETED;
- return SANE_STATUS_GOOD;
-}
-
-static SANE_Status
-gl646_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ )
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
- int rate, exposure_time, tgtime, time;
-
- DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay);
-
- local_reg.init_reg(0x01, dev->reg.get8(0x01)); // disable fastmode
- local_reg.init_reg(0x03, dev->reg.get8(0x03)); // Lamp power control
- local_reg.init_reg(0x05, dev->reg.get8(0x05) & ~REG05_BASESEL); // 24 clocks/pixel
- local_reg.init_reg(0x38, 0x00); // line period low
- local_reg.init_reg(0x39, 0x00); //line period high
- local_reg.init_reg(0x6c, 0x00); // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE
-
- if (!delay)
- local_reg.find_reg(0x03).value &= 0xf0; /* disable lampdog and set lamptime = 0 */
- else if (delay < 20)
- local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */
- else
- local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */
-
- time = delay * 1000 * 60; /* -> msec */
- exposure_time =
- (uint32_t) (time * 32000.0 /
- (24.0 * 64.0 * (local_reg.get8(0x03) & REG03_LAMPTIM) *
- 1024.0) + 0.5);
- /* 32000 = system clock, 24 = clocks per pixel */
- rate = (exposure_time + 65536) / 65536;
- if (rate > 4)
- {
- rate = 8;
- tgtime = 3;
- }
- else if (rate > 2)
- {
- rate = 4;
- tgtime = 2;
- }
- else if (rate > 1)
- {
- rate = 2;
- tgtime = 1;
- }
- else
- {
- rate = 1;
- tgtime = 0;
- }
-
- local_reg.find_reg(0x6c).value |= tgtime << 6;
- exposure_time /= rate;
-
- if (exposure_time > 65535)
- exposure_time = 65535;
-
- local_reg.find_reg(0x38).value = exposure_time / 256;
- local_reg.find_reg(0x39).value = exposure_time & 255;
-
- status = sanei_genesys_bulk_write_register(dev, local_reg);
- if (status != SANE_STATUS_GOOD) {
- DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-
-/**
- * loads document into scanner
- * currently only used by XP200
- * bit2 (0x04) of gpio is paper event (document in/out) on XP200
- * HOMESNR is set if no document in front of sensor, the sequence of events is
- * paper event -> document is in the sheet feeder
- * HOMESNR becomes 0 -> document reach sensor
- * HOMESNR becomes 1 ->document left sensor
- * paper event -> document is out
- */
-static SANE_Status
-gl646_load_document (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
-
- // FIXME: sequential not really needed in this case
- Genesys_Register_Set regs(Genesys_Register_Set::SEQUENTIAL);
- unsigned int used, vfinal, count;
- uint16_t slope_table[255];
- uint8_t val;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* no need to load document is flatbed scanner */
- if (dev->model->is_sheetfed == SANE_FALSE)
- {
- DBG(DBG_proc, "%s: nothing to load\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
- return SANE_STATUS_GOOD;
- }
-
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* HOMSNR is set if a document is inserted */
- if ((val & REG41_HOMESNR))
- {
- /* if no document, waits for a paper event to start loading */
- /* with a 60 seconde minutes timeout */
- count = 0;
- do
- {
- gl646_gpio_read(dev->usb_dev, &val);
-
- DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, val);
- if ((val & 0x04) != 0x04)
- {
- DBG(DBG_warn, "%s: no paper detected\n", __func__);
- }
- sanei_genesys_sleep_ms(200);
- count++;
- }
- while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */
- if (count == 300)
- {
- DBG(DBG_error, "%s: timeout waiting for document\n", __func__);
- return SANE_STATUS_NO_DOCS;
- }
- }
-
- /* set up to fast move before scan then move until document is detected */
- regs.init_reg(0x01, 0x90);
-
- /* AGOME, 2 slopes motor moving */
- regs.init_reg(0x02, 0x79);
-
- /* motor feeding steps to 0 */
- regs.init_reg(0x3d, 0);
- regs.init_reg(0x3e, 0);
- regs.init_reg(0x3f, 0);
-
- /* 50 fast moving steps */
- regs.init_reg(0x6b, 50);
-
- /* set GPO */
- regs.init_reg(0x66, 0x30);
-
- /* stesp NO */
- regs.init_reg(0x21, 4);
- regs.init_reg(0x22, 1);
- regs.init_reg(0x23, 1);
- regs.init_reg(0x24, 4);
-
- /* generate slope table 2 */
- sanei_genesys_generate_slope_table (slope_table,
- 50,
- 51,
- 2400,
- 6000, 2400, 50, 0.25, &used, &vfinal);
-/* document loading:
- * send regs
- * start motor
- * wait e1 status to become e0
- */
- status = gl646_send_slope_table (dev, 1, slope_table, 50);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_bulk_write_register(dev, regs);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = gl646_start_motor (dev);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status));
- return SANE_STATUS_IO_ERROR;
- }
-
- count = 0;
- do
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- sanei_genesys_sleep_ms(200);
- count++;
- }
- while ((val & REG41_MOTMFLG) && (count < 300));
- if (count == 300)
- {
- DBG(DBG_error, "%s: can't load document\n", __func__);
- return SANE_STATUS_JAMMED;
- }
-
- /* when loading OK, document is here */
- dev->document = SANE_TRUE;
-
- /* set up to idle */
- regs.set8(0x02, 0x71);
- regs.set8(0x3f, 1);
- regs.set8(0x6b, 8);
- status = sanei_genesys_bulk_write_register(dev, regs);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write idle registers: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
-
- return status;
-}
-
-/**
- * detects end of document and adjust current scan
- * to take it into account
- * used by sheetfed scanners
- */
-static SANE_Status
-gl646_detect_document_end (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- uint8_t val, gpio;
- unsigned int bytes_left, lines;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* test for document presence */
- RIE (sanei_genesys_get_status (dev, &val));
- if (DBG_LEVEL > DBG_info)
- {
- print_status (val);
- }
- gl646_gpio_read(dev->usb_dev, &gpio);
- DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio);
-
- /* detect document event. There one event when the document go in,
- * then another when it leaves */
- if ((dev->document == SANE_TRUE) && (gpio & 0x04)
- && (dev->total_bytes_read > 0))
- {
- DBG(DBG_info, "%s: no more document\n", __func__);
- dev->document = SANE_FALSE;
-
- /* adjust number of bytes to read:
- * total_bytes_to_read is the number of byte to send to frontend
- * total_bytes_read is the number of bytes sent to frontend
- * read_bytes_left is the number of bytes to read from the scanner
- */
- DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read);
- DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read);
- DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left);
-
- /* amount of data available from scanner is what to scan */
- status = sanei_genesys_read_valid_words (dev, &bytes_left);
-
- /* we add the number of lines needed to read the last part of the document in */
- lines =
- (SANE_UNFIX (dev->model->y_offset) * dev->current_setup.yres) /
- MM_PER_INCH;
- DBG(DBG_io, "%s: adding %d line to flush\n", __func__, lines);
- bytes_left += lines * dev->wpl;
- if (dev->current_setup.depth > 8)
- {
- bytes_left = 2 * bytes_left;
- }
- if (dev->current_setup.channels > 1)
- {
- bytes_left = 3 * bytes_left;
- }
- if (bytes_left < dev->read_bytes_left)
- {
- dev->total_bytes_to_read = dev->total_bytes_read + bytes_left;
- dev->read_bytes_left = bytes_left;
- }
- DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read);
- DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read);
- DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left);
- }
- DBG(DBG_proc, "%s: end\n", __func__);
-
- return status;
-}
-
-/**
- * eject document from the feeder
- * currently only used by XP200
- * TODO we currently rely on AGOHOME not being set for sheetfed scanners,
- * maybe check this flag in eject to let the document being eject automaticaly
- */
-static SANE_Status
-gl646_eject_document (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
-
- // FIXME: SEQUENTIAL not really needed in this case
- Genesys_Register_Set regs((Genesys_Register_Set::SEQUENTIAL));
- unsigned int used, vfinal, count;
- uint16_t slope_table[255];
- uint8_t gpio, state;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* at the end there will be noe more document */
- dev->document = SANE_FALSE;
-
- // first check for document event
- gl646_gpio_read(dev->usb_dev, &gpio);
-
- DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio);
-
- /* test status : paper event + HOMESNR -> no more doc ? */
- status = sanei_genesys_get_status (dev, &state);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- DBG(DBG_info, "%s: state=0x%02x\n", __func__, state);
- if (DBG_LEVEL > DBG_info)
- {
- print_status (state);
- }
-
- /* HOMSNR=0 if no document inserted */
- if ((state & REG41_HOMESNR) != 0)
- {
- dev->document = SANE_FALSE;
- DBG(DBG_info, "%s: no more document to eject\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
- }
-
- /* there is a document inserted, eject it */
- status = sanei_genesys_write_register (dev, 0x01, 0xb0);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* wait for motor to stop */
- do
- {
- sanei_genesys_sleep_ms(200);
- status = sanei_genesys_get_status (dev, &state);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- }
- while (state & REG41_MOTMFLG);
-
- /* set up to fast move before scan then move until document is detected */
- regs.init_reg(0x01, 0xb0);
-
- /* AGOME, 2 slopes motor moving , eject 'backward' */
- regs.init_reg(0x02, 0x5d);
-
- /* motor feeding steps to 119880 */
- regs.init_reg(0x3d, 1);
- regs.init_reg(0x3e, 0xd4);
- regs.init_reg(0x3f, 0x48);
-
- /* 60 fast moving steps */
- regs.init_reg(0x6b, 60);
-
- /* set GPO */
- regs.init_reg(0x66, 0x30);
-
- /* stesp NO */
- regs.init_reg(0x21, 4);
- regs.init_reg(0x22, 1);
- regs.init_reg(0x23, 1);
- regs.init_reg(0x24, 4);
-
- /* generate slope table 2 */
- sanei_genesys_generate_slope_table (slope_table,
- 60,
- 61,
- 1600,
- 10000, 1600, 60, 0.25, &used, &vfinal);
-/* document eject:
- * send regs
- * start motor
- * wait c1 status to become c8 : HOMESNR and ~MOTFLAG
- */
- status = gl646_send_slope_table (dev, 1, slope_table, 60);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- status = sanei_genesys_bulk_write_register(dev, regs);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status = gl646_start_motor (dev);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status));
- return SANE_STATUS_IO_ERROR;
- }
-
- /* loop until paper sensor tells paper is out, and till motor is running */
- /* use a 30 timeout */
- count = 0;
- do
- {
- status = sanei_genesys_get_status (dev, &state);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- print_status (state);
- sanei_genesys_sleep_ms(200);
- count++;
- }
- while (((state & REG41_HOMESNR) == 0) && (count < 150));
-
- // read GPIO on exit
- gl646_gpio_read(dev->usb_dev, &gpio);
-
- DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio);
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-/* Send the low-level scan command */
-static SANE_Status
-gl646_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg,
- SANE_Bool start_motor)
-{
- (void) sensor;
- SANE_Status status = SANE_STATUS_GOOD;
- // FIXME: SEQUENTIAL not really needed in this case
- Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
-
- DBG(DBG_proc, "%s\n", __func__);
-
- local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03));
- local_reg.init_reg(0x01, sanei_genesys_read_reg_from_set(reg, 0x01) | REG01_SCAN); /* set scan bit */
-
- if (start_motor) {
- local_reg.init_reg(0x0f, 0x01);
- } else {
- local_reg.init_reg(0x0f, 0x00); // do not start motor yet
- }
-
- status = sanei_genesys_bulk_write_register(dev, local_reg);
-
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
-
- return status;
-}
-
-
-/* Send the stop scan command */
-static SANE_Status
-end_scan (Genesys_Device * dev, Genesys_Register_Set * reg,
- SANE_Bool check_stop, SANE_Bool eject)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- int i = 0;
- uint8_t val, scanfsh = 0;
-
- DBG(DBG_proc, "%s (check_stop = %d, eject = %d)\n", __func__, check_stop, eject);
-
- /* we need to compute scanfsh before cancelling scan */
- if (dev->model->is_sheetfed == SANE_TRUE)
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- if (val & REG41_SCANFSH)
- scanfsh = 1;
- if (DBG_LEVEL > DBG_io2)
- {
- print_status (val);
- }
- }
-
- /* ends scan */
- val = sanei_genesys_read_reg_from_set (reg, 0x01);
- val &= ~REG01_SCAN;
- sanei_genesys_set_reg_from_set (reg, 0x01, val);
- status = sanei_genesys_write_register (dev, 0x01, val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* for sheetfed scanners, we may have to eject document */
- if (dev->model->is_sheetfed == SANE_TRUE)
- {
- if (eject == SANE_TRUE && dev->document == SANE_TRUE)
- {
- status = gl646_eject_document (dev);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to eject document\n", __func__);
- return status;
- }
- }
- if (check_stop)
- {
- for (i = 0; i < 30; i++) /* do not wait longer than wait 3 seconds */
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read register: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
- if (val & REG41_SCANFSH)
- scanfsh = 1;
- if (DBG_LEVEL > DBG_io2)
- {
- print_status (val);
- }
-
- if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh)
- {
- DBG(DBG_proc, "%s: scanfeed finished\n", __func__);
- break; /* leave for loop */
- }
-
- sanei_genesys_sleep_ms(100);
- }
- }
- }
- else /* flat bed scanners */
- {
- if (check_stop)
- {
- for (i = 0; i < 300; i++) /* do not wait longer than wait 30 seconds */
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read register: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
- if (val & REG41_SCANFSH)
- scanfsh = 1;
- if (DBG_LEVEL > DBG_io)
- {
- print_status (val);
- }
-
- if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh)
- {
- DBG(DBG_proc, "%s: scanfeed finished\n", __func__);
- break; /* leave while loop */
- }
-
- if ((!(val & REG41_MOTMFLG)) && (val & REG41_HOMESNR))
- {
- DBG(DBG_proc, "%s: head at home\n", __func__);
- break; /* leave while loop */
- }
-
- sanei_genesys_sleep_ms(100);
- }
- }
- }
-
- DBG(DBG_proc, "%s: end (i=%u)\n", __func__, i);
-
- return status;
-}
-
-/* Send the stop scan command */
-static SANE_Status
-gl646_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg,
- SANE_Bool check_stop)
-{
- return end_scan (dev, reg, check_stop, SANE_FALSE);
-}
-
-/**
- * parks head
- * @param dev scanner's device
- * @param wait_until_home true if the function waits until head parked
- */
-static
-SANE_Status
-gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
- uint8_t val;
- int i;
- int loop = 0;
-
- DBG(DBG_proc, "%s: start , wait_until_home = %d\n", __func__, wait_until_home);
-
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- if (DBG_LEVEL > DBG_io)
- {
- print_status (val);
- }
-
- dev->scanhead_position_in_steps = 0;
-
- if (val & REG41_HOMESNR) /* is sensor at home? */
- {
- DBG(DBG_info, "%s: end since already at home\n", __func__);
- return SANE_STATUS_GOOD;
- }
-
- /* stop motor if needed */
- if (val & REG41_MOTMFLG)
- {
- status = gl646_stop_motor (dev);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status));
- return SANE_STATUS_IO_ERROR;
- }
- sanei_genesys_sleep_ms(200);
- }
-
- /* when scanhead is moving then wait until scanhead stops or timeout */
- DBG(DBG_info, "%s: ensuring that motor is off\n", __func__);
- val = REG41_MOTMFLG;
- for (i = 400; i > 0 && (val & REG41_MOTMFLG); i--) /* do not wait longer than 40 seconds, count down to get i = 0 when busy */
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: Failed to read home sensor & motor status: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
- if (((val & (REG41_MOTMFLG | REG41_HOMESNR)) == REG41_HOMESNR)) /* at home and motor is off */
- {
- DBG(DBG_info, "%s: already at home and not moving\n", __func__);
- return SANE_STATUS_GOOD;
- }
- sanei_genesys_sleep_ms(100);
- }
-
- if (!i) /* the loop counted down to 0, scanner still is busy */
- {
- DBG(DBG_error, "%s: motor is still on: device busy\n", __func__);
- return SANE_STATUS_DEVICE_BUSY;
- }
-
- /* setup for a backward scan of 65535 steps, with no actual data reading */
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = get_lowest_resolution(dev->model->ccd_type, 1);
- settings.yres = settings.xres;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = 600;
- settings.lines = 1;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres);
-
- status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_TRUE, SANE_TRUE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status));
- DBGCOMPLETED;
- return status;
- }
-
- /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */
- dev->reg.find_reg(0x02).value |= REG02_MTRREV;
- dev->reg.find_reg(0x01).value &= ~REG01_SCAN;
- sanei_genesys_set_triple(&dev->reg, REG_FEEDL, 65535);
-
- /* sets frontend */
- status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status));
- DBGCOMPLETED;
- return status;
- }
-
- /* write scan registers */
- try {
- status = sanei_genesys_bulk_write_register(dev, dev->reg);
- } catch (...) {
- DBG(DBG_error, "%s: failed to bulk write registers\n", __func__);
- }
- if (status != SANE_STATUS_GOOD)
- DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
-
- /* registers are restored to an iddl state, give up if no head to park */
- if (dev->model->is_sheetfed == SANE_TRUE)
- {
- DBG(DBG_proc, "%s: end \n", __func__);
- return SANE_STATUS_GOOD;
- }
-
- /* starts scan */
- status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to begin scan: \n", __func__);
- return status;
- }
-
- /* loop until head parked */
- if (wait_until_home)
- {
- while (loop < 300) /* do not wait longer then 30 seconds */
- {
- status = sanei_genesys_get_status (dev, &val);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: Failed to read home sensor: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
-
- if (val & 0x08) /* home sensor */
- {
- DBG(DBG_info, "%s: reached home position\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
- sanei_genesys_sleep_ms(500);
- return SANE_STATUS_GOOD;
- }
- sanei_genesys_sleep_ms(100);
- ++loop;
- }
-
- /* when we come here then the scanner needed too much time for this, so we better stop the motor */
- gl646_stop_motor (dev);
- end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE);
- DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__);
- return SANE_STATUS_IO_ERROR;
- }
-
-
- DBG(DBG_info, "%s: scanhead is still moving\n", __func__);
- DBGCOMPLETED;
- return SANE_STATUS_GOOD;
-}
-
-/**
- * Automatically set top-left edge of the scan area by scanning an
- * area at 300 dpi from very top of scanner
- * @param dev device stucture describing the scanner
- * @return SANE_STATUS_GOOD in cas of success, else failure code
- */
-static SANE_Status
-gl646_search_start_position (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
- unsigned int resolution, x, y;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* we scan at 300 dpi */
- resolution = get_closest_resolution(dev->model->ccd_type, 300, 1);
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- auto& sensor = sanei_genesys_find_sensor_for_write(dev, resolution);
-
- /* fill settings for a gray level scan */
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = 600;
- settings.lines = dev->model->search_lines;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* scan the desired area */
- std::vector<uint8_t> data;
- status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data);
-
- /* process data if scan is OK */
- if (status != SANE_STATUS_GOOD) {
- DBG(DBG_error, "%s: simple_scan failed\n", __func__);
- DBGCOMPLETED;
- return status;
- }
-
-
- /* handle stagger case : reorder gray data and thus loose some lines */
- if (dev->current_setup.stagger > 0)
- {
- DBG(DBG_proc, "%s: 'un-staggering'\n", __func__);
- for (y = 0; y < settings.lines - dev->current_setup.stagger; y++)
- {
- /* one point out of 2 is 'unaligned' */
- for (x = 0; x < settings.pixels; x += 2)
- {
- data[y * settings.pixels + x] =
- data[(y + dev->current_setup.stagger) * settings.pixels +
- x];
- }
- }
- /* correct line number */
- settings.lines -= dev->current_setup.stagger;
- }
- if (DBG_LEVEL >= DBG_data)
- {
- sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1,
- settings.pixels, settings.lines);
- }
-
- /* now search reference points on the data */
- status =
- sanei_genesys_search_reference_point (dev, sensor, data.data(),
- sensor.CCD_start_xoffset,
- resolution, settings.pixels,
- settings.lines);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__,
- sane_strstatus(status));
- }
-
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * internally overriden during effective calibration
- * sets up register for coarse gain calibration
- */
-static SANE_Status
-gl646_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs)
-{
- (void) sensor;
- (void) regs;
-
- DBG(DBG_proc, "%s\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
-
- /* to make compilers happy ... */
- if (!dev)
- {
- return SANE_STATUS_INVAL;
- }
-
- return SANE_STATUS_GOOD;
-}
-
-
-/**
- * init registers for shading calibration
- * we assume that scanner's head is on an area suiting shading calibration.
- * We scan a full scan width area by the shading line number for the device
- * at either at full sensor's resolution or half depending upon half_ccd
- * @param dev scanner's device
- * @return SANE_STATUS_GOOD if success, else error code
- */
-static SANE_Status
-gl646_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs)
-{
- (void) regs;
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
- /* 1: no half_ccd, 2: use half number of pixels */
- int half_ccd = 1;
- int cksel = 1;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* fill settings for scan : always a color scan */
- int channels = 3;
-
- if (sensor.ccd_size_divisor > 1)
- {
- // when shading all (full width) line, we must adapt to half_ccd case
- if (is_half_ccd(dev->model->ccd_type, dev->settings.xres, channels) == SANE_TRUE)
- {
- half_ccd = 2;
- }
- }
-
- settings.scan_method = dev->settings.scan_method;
- settings.scan_mode = dev->settings.scan_mode;
- if (dev->model->is_cis == SANE_FALSE)
- {
- // FIXME: always a color scan, but why don't we set scan_mode to COLOR_SINGLE_PASS always?
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- }
- settings.xres = sensor.optical_res / half_ccd;
- cksel = get_cksel(dev->model->ccd_type, dev->settings.xres, channels);
- settings.xres = settings.xres / cksel;
- settings.yres = settings.xres;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * settings.xres) / sensor.optical_res;
- dev->calib_lines = dev->model->shading_lines;
- settings.lines = dev->calib_lines * (3 - half_ccd);
- settings.depth = 16;
- settings.color_filter = dev->settings.color_filter;
-
- settings.disable_interpolation = dev->settings.disable_interpolation;
- settings.threshold = dev->settings.threshold;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* keep account of the movement for final scan move */
- dev->scanhead_position_in_steps += settings.lines;
-
- /* we don't want top offset, but we need right margin to be the same
- * than the one for the final scan */
- status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE);
-
- /* used when sending shading calibration data */
- dev->calib_pixels = settings.pixels;
- dev->calib_channels = dev->current_setup.channels;
- if (dev->model->is_cis == SANE_FALSE)
- {
- dev->calib_channels = 3;
- }
-
- /* no shading */
- dev->reg.find_reg(0x01).value &= ~REG01_DVDSET;
- dev->reg.find_reg(0x02).value |= REG02_ACDCDIS; /* ease backtracking */
- dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME);
- dev->reg.find_reg(0x05).value &= ~REG05_GMMENB;
- sanei_genesys_set_motor_power(dev->reg, false);
-
- /* TODO another flag to setup regs ? */
- /* enforce needed LINCNT, getting rid of extra lines for color reordering */
- if (dev->model->is_cis == SANE_FALSE)
- {
- sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines);
- }
- else
- {
- sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines * 3);
- }
-
- /* copy reg to calib_reg */
- dev->calib_reg = dev->reg;
-
- /* this is an hack to make calibration cache working .... */
- /* if we don't do this, cache will be identified at the shading calibration
- * dpi which is different from calibration one */
- dev->current_setup.xres = dev->settings.xres;
- DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__,
- dev->settings.xres, dev->settings.yres);
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-static bool gl646_needs_home_before_init_regs_for_scan(Genesys_Device* dev)
-{
- return (dev->scanhead_position_in_steps > 0 &&
- dev->settings.scan_method == ScanMethod::FLATBED);
-}
-
-/**
- * set up registers for the actual scan. The scan's parameters are given
- * through the device settings. It allocates the scan buffers.
- */
-static SANE_Status
-gl646_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor)
-{
- SANE_Status status = SANE_STATUS_GOOD;
-
- DBGSTART;
-
- RIE(setup_for_scan(dev, sensor, &dev->reg, dev->settings, SANE_FALSE, SANE_TRUE, SANE_TRUE));
-
- /* gamma is only enabled at final scan time */
- if (dev->settings.depth < 16)
- dev->reg.find_reg(0x05).value |= REG05_GMMENB;
-
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * set up registers for the actual scan. The scan's parameters are given
- * through the device settings. It allocates the scan buffers.
- * @param dev scanner's device
- * @param regs registers to set up
- * @param settings settings of scan
- * @param split SANE_TRUE if move to scan area is split from scan, SANE_FALSE is
- * scan first moves to area
- * @param xcorrection take x geometry correction into account (fixed and detected offsets)
- * @param ycorrection take y geometry correction into account
- */
-static SANE_Status
-setup_for_scan (Genesys_Device * dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set *regs,
- Genesys_Settings settings,
- SANE_Bool split,
- SANE_Bool xcorrection,
- SANE_Bool ycorrection)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- SANE_Int depth;
- int channels;
-
- DBG(DBG_info, "%s ", __func__);
- debug_dump(DBG_info, dev->settings);
-
- if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- channels = 3;
- }
- else
- {
- channels = 1;
- }
-
- depth=settings.depth;
- if (settings.scan_mode == ScanColorMode::LINEART)
- {
- if (settings.dynamic_lineart == SANE_TRUE)
- {
- depth = 8;
- }
- else
- {
- /* XXX STEF XXX : why does the common layer never send depth=1 ? */
- depth = 1;
- }
- }
-
- // compute distance to move
- float move = 0;
- // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */
- if (split == SANE_FALSE) {
- if (dev->model->is_sheetfed == SANE_FALSE) {
- if (ycorrection == SANE_TRUE) {
- move = SANE_UNFIX(dev->model->y_offset);
- }
-
- // add tl_y to base movement
- }
- move += settings.tl_y;
-
- if (move < 0) {
- DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move);
- move = 0;
- }
- }
- move = (move * dev->motor.optical_ydpi) / MM_PER_INCH;
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- float start = settings.tl_x;
- if (xcorrection) {
- if (settings.scan_method == ScanMethod::FLATBED) {
- start += SANE_UNFIX(dev->model->x_offset);
- } else {
- start += SANE_UNFIX(dev->model->x_offset_ta);
- }
- }
- start = (start * sensor.optical_res) / MM_PER_INCH;
-
- SetupParams params;
- params.xres = settings.xres;
- params.yres = settings.yres;
- params.startx = start;
- params.starty = move;
- params.pixels = settings.pixels;
- params.lines = settings.lines;
- params.depth = depth;
- params.channels = channels;
- params.scan_method = dev->settings.scan_method;
- params.scan_mode = settings.scan_mode;
- params.color_filter = settings.color_filter;
- params.flags = 0;
- if (settings.scan_method == ScanMethod::TRANSPARENCY) {
- params.flags |= SCAN_FLAG_USE_XPA;
- }
-
- uint16_t slope_table0[256] = {};
- uint16_t slope_table1[256] = {};
-
- /* set up correct values for scan (gamma and shading enabled) */
- status = gl646_setup_registers(dev, sensor, regs, params, slope_table0, slope_table1,
- xcorrection);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* send computed slope tables */
- status =
- gl646_send_slope_table (dev, 0, slope_table0,
- sanei_genesys_read_reg_from_set (regs, 0x21));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- status =
- gl646_send_slope_table (dev, 1, slope_table1,
- sanei_genesys_read_reg_from_set (regs, 0x6b));
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * this function sen gamm table to ASIC
- */
-static SANE_Status
-gl646_send_gamma_table (Genesys_Device * dev, const Genesys_Sensor& sensor)
-{
- int size;
- int address;
- SANE_Status status = SANE_STATUS_GOOD;
- int bits;
-
- DBGSTART;
-
- /* gamma table size */
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA)
- {
- size = 16384;
- bits = 14;
- }
- else
- {
- size = 4096;
- bits = 12;
- }
-
- /* allocate temporary gamma tables: 16 bits words, 3 channels */
- std::vector<uint8_t> gamma(size * 2 * 3);
-
- RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, bits, size-1, size, gamma.data()));
-
- /* table address */
- switch (dev->reg.find_reg(0x05).value >> 6)
- {
- case 0: /* 600 dpi */
- address = 0x09000;
- break;
- case 1: /* 1200 dpi */
- address = 0x11000;
- break;
- case 2: /* 2400 dpi */
- address = 0x20000;
- break;
- default:
- return SANE_STATUS_INVAL;
- }
-
- /* send address */
- status = sanei_genesys_set_buffer_address (dev, address);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* send data */
- status = sanei_genesys_bulk_write_data(dev, 0x3c, gamma.data(), size * 2 * 3);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBGCOMPLETED;
- return SANE_STATUS_GOOD;
-}
-
-/** @brief this function does the led calibration.
- * this function does the led calibration by scanning one line of the calibration
- * area below scanner's top on white strip. The scope of this function is
- * currently limited to the XP200
- */
-static SANE_Status
-gl646_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs)
-{
- (void) regs;
- int total_size;
- unsigned int i, j;
- SANE_Status status = SANE_STATUS_GOOD;
- int val;
- unsigned int channels;
- int avg[3], avga, avge;
- int turn;
- uint16_t expr, expg, expb;
- Genesys_Settings settings;
- SANE_Int resolution;
-
- SANE_Bool acceptable = SANE_FALSE;
-
- DBG(DBG_proc, "%s\n", __func__);
- if (!dev->model->is_cis)
- {
- DBG(DBG_proc, "%s: not a cis scanner, nothing to do...\n", __func__);
- return SANE_STATUS_GOOD;
- }
-
- /* get led calibration resolution */
- if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- channels = 3;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- }
- else
- {
- channels = 1;
- settings.scan_mode = ScanColorMode::GRAY;
- }
- resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels);
-
- /* offset calibration is always done in color mode */
- settings.scan_method = ScanMethod::FLATBED;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.lines = 1;
- settings.depth = 16;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* colors * bytes_per_color * scan lines */
- total_size = settings.pixels * channels * 2 * 1;
-
- std::vector<uint8_t> line(total_size);
-
-/*
- we try to get equal bright leds here:
-
- loop:
- average per color
- adjust exposure times
-
- Sensor_Master uint8_t regs_0x10_0x15[6];
- */
- expr = sensor.exposure.red;
- expg = sensor.exposure.green;
- expb = sensor.exposure.blue;
-
- turn = 0;
-
- do
- {
- sensor.exposure.red = expr;
- sensor.exposure.green = expg;
- sensor.exposure.blue = expb;
-
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
-
- status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- snprintf(fn, 30, "gl646_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, settings.pixels, 1);
- }
-
- acceptable = SANE_TRUE;
-
- for (j = 0; j < channels; j++)
- {
- avg[j] = 0;
- for (i = 0; i < settings.pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * settings.pixels + 1] * 256 +
- line[i * 2 + j * 2 * settings.pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
- }
-
- avg[j] /= settings.pixels;
- }
-
- DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- acceptable = SANE_TRUE;
-
- if (!acceptable)
- {
- avga = (avg[0] + avg[1] + avg[2]) / 3;
- expr = (expr * avga) / avg[0];
- expg = (expg * avga) / avg[1];
- expb = (expb * avga) / avg[2];
-
- /* keep exposure time in a working window */
- avge = (expr + expg + expb) / 3;
- if (avge > 0x2000)
- {
- expr = (expr * 0x2000) / avge;
- expg = (expg * 0x2000) / avge;
- expb = (expb * 0x2000) / avge;
- }
- if (avge < 0x400)
- {
- expr = (expr * 0x400) / avge;
- expg = (expg * 0x400) / avge;
- expb = (expb * 0x400) / avge;
- }
- }
-
- turn++;
-
- }
- while (!acceptable && turn < 100);
-
- DBG(DBG_info,"%s: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", __func__, expr, expg, expb);
-
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * average dark pixels of a scan
- */
-static int
-dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
- unsigned int channels, unsigned int black)
-{
- unsigned int i, j, k, average, count;
- unsigned int avg[3];
- uint8_t val;
-
- /* computes average value on black margin */
- for (k = 0; k < channels; k++)
- {
- avg[k] = 0;
- count = 0;
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < black; j++)
- {
- val = data[i * channels * pixels + j + k];
- avg[k] += val;
- count++;
- }
- }
- if (count)
- avg[k] /= count;
- DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
- }
- average = 0;
- for (i = 0; i < channels; i++)
- average += avg[i];
- average /= channels;
- DBG(DBG_info, "%s: average = %d\n", __func__, average);
- return average;
-}
-
-
-/** @brief calibration for AD frontend devices
- * we do simple scan until all black_pixels are higher than 0,
- * raising offset at each turn.
- */
-static SANE_Status
-ad_fe_offset_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- unsigned int channels;
- int pass = 0;
- SANE_Int resolution;
- Genesys_Settings settings;
- unsigned int x, y, adr, min;
- unsigned int bottom, black_pixels;
-
- DBG(DBG_proc, "%s: start\n", __func__);
- channels = 3;
- resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels);
- black_pixels =
- (sensor.black_pixels * resolution) / sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* scan first line of data with no gain */
- dev->frontend.set_gain(0, 0);
- dev->frontend.set_gain(1, 0);
- dev->frontend.set_gain(2, 0);
-
- std::vector<uint8_t> line;
-
- /* scan with no move */
- bottom = 1;
- do
- {
- pass++;
- dev->frontend.set_offset(0, bottom);
- dev->frontend.set_offset(1, bottom);
- dev->frontend.set_offset(2, bottom);
- status =
- simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- snprintf(title, 30, "gl646_offset%03d.pnm", (int)bottom);
- sanei_genesys_write_pnm_file (title, line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
-
- min = 0;
- for (y = 0; y < settings.lines; y++)
- {
- for (x = 0; x < black_pixels; x++)
- {
- adr = (x + y * settings.pixels) * channels;
- if (line[adr] > min)
- min = line[adr];
- if (line[adr + 1] > min)
- min = line[adr + 1];
- if (line[adr + 2] > min)
- min = line[adr + 2];
- }
- }
-
- DBG(DBG_io2, "%s: pass=%d, min=%d\n", __func__, pass, min);
- bottom++;
- }
- while (pass < 128 && min == 0);
- if (pass == 128)
- {
- DBG(DBG_error, "%s: failed to find correct offset\n", __func__);
- return SANE_STATUS_INVAL;
- }
-
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-#define DARK_TARGET 8
-/**
- * This function does the offset calibration by scanning one line of the calibration
- * area below scanner's top. There is a black margin and the remaining is white.
- * genesys_search_start() must have been called so that the offsets and margins
- * are already known.
- * @param dev scanner's device
- * @return SANE_STATUS_GOOD if success, else error code is failure
-*/
-static SANE_Status
-gl646_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs)
-{
- (void) regs;
- SANE_Status status = SANE_STATUS_GOOD;
- unsigned int channels;
- int pass = 0, avg;
- SANE_Int resolution;
- Genesys_Settings settings;
- int topavg, bottomavg;
- int top, bottom, black_pixels;
-
- /* Analog Device fronted have a different calibration */
- if (dev->model->dac_type == DAC_AD_XP200)
- {
- return ad_fe_offset_calibration (dev, sensor);
- }
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* setup for a RGB scan, one full sensor's width line */
- /* resolution is the one from the final scan */
- channels = 3;
- if (dev->settings.xres > sensor.optical_res) {
- resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels);
- } else {
- resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels);
- }
- black_pixels =
- (sensor.black_pixels * resolution) / sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* scan first line of data with no gain, but with offset from
- * last calibration */
- dev->frontend.set_gain(0, 0);
- dev->frontend.set_gain(1, 0);
- dev->frontend.set_gain(2, 0);
-
- /* scan with no move */
- bottom = 90;
- dev->frontend.set_offset(0, bottom);
- dev->frontend.set_offset(1, bottom);
- dev->frontend.set_offset(2, bottom);
-
- std::vector<uint8_t> first_line, second_line;
-
- status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, first_line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- snprintf(title, 30, "gl646_offset%03d.pnm", bottom);
- sanei_genesys_write_pnm_file(title, first_line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
- bottomavg = dark_average(first_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
- DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
-
- /* now top value */
- top = 231;
- dev->frontend.set_offset(0, top);
- dev->frontend.set_offset(1, top);
- dev->frontend.set_offset(2, top);
- status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- snprintf(title, 30, "gl646_offset%03d.pnm", top);
- sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
- topavg = dark_average(second_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
- DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
-
- /* loop until acceptable level */
- while ((pass < 32) && (top - bottom > 1))
- {
- pass++;
-
- /* settings for new scan */
- dev->frontend.set_offset(0, (top + bottom) / 2);
- dev->frontend.set_offset(1, (top + bottom) / 2);
- dev->frontend.set_offset(2, (top + bottom) / 2);
-
- /* scan with no move */
- status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- snprintf(title, 30, "gl646_offset%03d.pnm", dev->frontend.get_offset(1));
- sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
-
- avg =
- dark_average (second_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
- DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
-
- /* compute new boundaries */
- if (topavg == avg)
- {
- topavg = avg;
- top = dev->frontend.get_offset(1);
- }
- else
- {
- bottomavg = avg;
- bottom = dev->frontend.get_offset(1);
- }
- }
-
- /* in case of debug do a final scan to get result */
- if (DBG_LEVEL >= DBG_data)
- {
- status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan final line\n", __func__);
- return status;
- }
- sanei_genesys_write_pnm_file("gl646_offset-final.pnm", second_line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
-
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-/** @brief gain calibration for Analog Device frontends
- * Alternative coarse gain calibration
- */
-static SANE_Status
-ad_fe_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs, int dpi)
-{
- (void) regs;
- unsigned int i, channels, val;
- unsigned int size, count, resolution, pass;
- SANE_Status status = SANE_STATUS_GOOD;
- float average;
- Genesys_Settings settings;
- char title[32];
-
- DBGSTART;
-
- /* setup for a RGB scan, one full sensor's width line */
- /* resolution is the one from the final scan */
- channels = 3;
- resolution = get_closest_resolution(dev->model->ccd_type, dpi, channels);
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
-
- settings.scan_method = ScanMethod::FLATBED;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- size = channels * settings.pixels * settings.lines;
-
- /* start gain value */
- dev->frontend.set_gain(0, 1);
- dev->frontend.set_gain(1, 1);
- dev->frontend.set_gain(2, 1);
-
- average = 0;
- pass = 0;
-
- std::vector<uint8_t> line;
-
- /* loop until each channel raises to acceptable level */
- while ((average < sensor.gain_white_ref) && (pass < 30))
- {
- /* scan with no move */
- status =
- simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
-
- /* log scanning data */
- if (DBG_LEVEL >= DBG_data)
- {
- sprintf (title, "gl646_alternative_gain%02d.pnm", (int)pass);
- sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels,
- settings.lines);
- }
- pass++;
-
- /* computes white average */
- average = 0;
- count = 0;
- for (i = 0; i < size; i++)
- {
- val = line[i];
- average += val;
- count++;
- }
- average = average / count;
-
- uint8_t gain0 = dev->frontend.get_gain(0);
- // adjusts gain for the channel
- if (average < sensor.gain_white_ref) {
- gain0 += 1;
- }
-
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
-
- DBG(DBG_proc, "%s: average = %.2f, gain = %d\n", __func__, average, gain0);
- }
-
- DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2));
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * Alternative coarse gain calibration
- * this on uses the settings from offset_calibration. First scan moves so
- * we can go to calibration area for XPA.
- * @param dev device for scan
- * @param dpi resolutnio to calibrate at
- */
-static SANE_Status
-gl646_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs, int dpi)
-{
- unsigned int i, j, k, channels, val, maximum, idx;
- unsigned int count, resolution, pass;
- SANE_Status status = SANE_STATUS_GOOD;
- float average[3];
- Genesys_Settings settings;
- char title[32];
-
- if (dev->model->ccd_type == CIS_XP200)
- {
- return ad_fe_coarse_gain_calibration (dev, sensor, regs, sensor.optical_res);
- }
- DBGSTART;
-
- /* setup for a RGB scan, one full sensor's width line */
- /* resolution is the one from the final scan */
- channels = 3;
-
- /* we are searching a sensor resolution */
- if (dpi > sensor.optical_res) {
- resolution = sensor.optical_res;
- } else {
- resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels);
- }
-
- settings.scan_method = dev->settings.scan_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_y = 0;
- if (settings.scan_method == ScanMethod::FLATBED)
- {
- settings.tl_x = 0;
- settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res;
- }
- else
- {
- settings.tl_x = SANE_UNFIX (dev->model->x_offset_ta);
- settings.pixels = (SANE_UNFIX (dev->model->x_size_ta) * resolution) / MM_PER_INCH;
- }
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* start gain value */
- dev->frontend.set_gain(0, 1);
- dev->frontend.set_gain(1, 1);
- dev->frontend.set_gain(2, 1);
-
- if (channels > 1)
- {
- average[0] = 0;
- average[1] = 0;
- average[2] = 0;
- idx = 0;
- }
- else
- {
- average[0] = 255;
- average[1] = 255;
- average[2] = 255;
- switch (dev->settings.color_filter) {
- case ColorFilter::RED: idx = 0; break;
- case ColorFilter::GREEN: idx = 1; break;
- case ColorFilter::BLUE: idx = 2; break;
- default: idx = 0; break; // should not happen
- }
- average[idx] = 0;
- }
- pass = 0;
-
- std::vector<uint8_t> line;
-
- /* loop until each channel raises to acceptable level */
- while (((average[0] < sensor.gain_white_ref)
- || (average[1] < sensor.gain_white_ref)
- || (average[2] < sensor.gain_white_ref)) && (pass < 30))
- {
- /* scan with no move */
- status =
- simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to scan first line\n", __func__);
- return status;
- }
-
- /* log scanning data */
- if (DBG_LEVEL >= DBG_data)
- {
- sprintf (title, "gl646_gain%02d.pnm", (int)pass);
- sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels,
- settings.lines);
- }
- pass++;
-
- /* average high level for each channel and compute gain
- to reach the target code
- we only use the central half of the CCD data */
- for (k = idx; k < idx + channels; k++)
- {
- /* we find the maximum white value, so we can deduce a threshold
- to average white values */
- maximum = 0;
- for (i = 0; i < settings.lines; i++)
- {
- for (j = 0; j < settings.pixels; j++)
- {
- val = line[i * channels * settings.pixels + j + k];
- if (val > maximum)
- maximum = val;
- }
- }
-
- /* threshold */
- maximum *= 0.9;
-
- /* computes white average */
- average[k] = 0;
- count = 0;
- for (i = 0; i < settings.lines; i++)
- {
- for (j = 0; j < settings.pixels; j++)
- {
- /* averaging only white points allow us not to care about dark margins */
- val = line[i * channels * settings.pixels + j + k];
- if (val > maximum)
- {
- average[k] += val;
- count++;
- }
- }
- }
- average[k] = average[k] / count;
-
- /* adjusts gain for the channel */
- if (average[k] < sensor.gain_white_ref)
- dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1);
-
- DBG(DBG_proc, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k],
- dev->frontend.get_gain(k));
- }
- }
-
- if (channels < 3) {
- dev->frontend.set_gain(1, dev->frontend.get_gain(0));
- dev->frontend.set_gain(2, dev->frontend.get_gain(0));
- }
-
- DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2));
- DBGCOMPLETED;
- return status;
-}
-
-/**
- * sets up the scanner's register for warming up. We scan 2 lines without moving.
- *
- */
-static SANE_Status
-gl646_init_regs_for_warmup (Genesys_Device * dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set * local_reg,
- int *channels, int *total_size)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
- int resolution, lines;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- dev->frontend = dev->frontend_initial;
-
- resolution = get_closest_resolution(dev->model->ccd_type, 300, 1);
-
- /* set up for a half width 2 lines gray scan without moving */
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels =
- (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.lines = 2;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* setup for scan */
- status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* we are not going to move, so clear these bits */
- dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME);
-
- /* don't enable any correction for this scan */
- dev->reg.find_reg(0x01).value &= ~REG01_DVDSET;
-
- /* copy to local_reg */
- *local_reg = dev->reg;
-
- /* turn off motor during this scan */
- sanei_genesys_set_motor_power(*local_reg, false);
-
- /* returned value to higher level warmup function */
- *channels = 1;
- uint32_t value = 0;
- sanei_genesys_get_triple(local_reg, REG_LINCNT, &value);
- lines = value + 1;
- *total_size = lines * settings.pixels;
-
- /* now registers are ok, write them to scanner */
- RIE (gl646_set_fe(dev, sensor, AFE_SET, settings.xres));
- RIE(sanei_genesys_bulk_write_register(dev, *local_reg));
-
- DBGCOMPLETED;
- return status;
-}
-
-
-/*
- * this function moves head without scanning, forward, then backward
- * so that the head goes to park position.
- * as a by-product, also check for lock
- */
-static SANE_Status
-gl646_repark_head (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
- unsigned int expected, steps;
-
- DBG(DBG_proc, "%s: start\n", __func__);
-
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = get_closest_resolution(dev->model->ccd_type, 75, 1);
- settings.yres = settings.xres;
- settings.tl_x = 0;
- settings.tl_y = 5;
- settings.pixels = 600;
- settings.lines = 4;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres);
-
- status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_FALSE, SANE_FALSE, SANE_FALSE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* TODO seems wrong ... no effective scan */
- dev->reg.find_reg(0x01).value &= ~REG01_SCAN;
-
- status = sanei_genesys_bulk_write_register(dev, dev->reg);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* start scan */
- status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to begin scan: \n", __func__);
- return status;
- }
-
- uint32_t value32 = 0;
- sanei_genesys_get_triple(&dev->reg, REG_FEEDL, &value32);
- expected = value32;
- do
- {
- sanei_genesys_sleep_ms(100);
- status = sanei_genesys_read_feed_steps (dev, &steps);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status));
- return status;
- }
- }
- while (steps < expected);
-
- /* toggle motor flag, put an huge step number and redo move backward */
- status = gl646_slow_back_home (dev, 1);
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-/* *
- * initialize ASIC : registers, motor tables, and gamma tables
- * then ensure scanner's head is at home
- * @param dev device description of the scanner to initailize
- * @return SANE_STATUS_GOOD if success, error code if failure
- */
-static SANE_Status
-gl646_init (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- struct timeval tv;
- uint8_t cold = 0, val = 0;
- uint32_t addr = 0xdead;
- size_t len;
-
- DBG_INIT ();
- DBG(DBG_proc, "%s: start\n", __func__);
-
- /* to detect real power up condition, we write to REG41
- * with pwrbit set, then read it back. When scanner is cold (just replugged)
- * PWRBIT will be set in the returned value
- */
- RIE (sanei_genesys_get_status (dev, &cold));
- DBG(DBG_info, "%s: status=0x%02x\n", __func__, cold);
- cold = !(cold & REG41_PWRBIT);
- if (cold)
- {
- DBG(DBG_info, "%s: device is cold\n", __func__);
- }
- else
- {
- DBG(DBG_info, "%s: device is hot\n", __func__);
- }
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- /* if scanning session hasn't been initialized, set it up */
- if (!dev->already_initialized)
- {
- dev->dark_average_data.clear();
- dev->white_average_data.clear();
-
- dev->settings.color_filter = ColorFilter::GREEN;
- gettimeofday (&tv, NULL);
- dev->init_date = tv.tv_sec;
-
- /* Set default values for registers */
- gl646_init_regs (dev);
-
- /* Init shading data */
- RIE (sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels));
-
- /* initial calibration reg values */
- dev->calib_reg = dev->reg;
- }
-
- /* execute physical unit init only if cold */
- if (cold)
- {
- DBG(DBG_info, "%s: device is cold\n", __func__);
-
- val = 0x04;
- dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_INIT, INDEX, 1, &val);
-
- /* ASIC reset */
- RIE (sanei_genesys_write_register (dev, 0x0e, 0x00));
- sanei_genesys_sleep_ms(100);
-
- /* Write initial registers */
- RIE(sanei_genesys_bulk_write_register(dev, dev->reg));
-
- /* Test ASIC and RAM */
- if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT))
- {
- RIE (gl646_asic_test (dev));
- }
-
- /* send gamma tables if needed */
- status = gl646_send_gamma_table(dev, sensor);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to send generic gamma tables: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
-
- /* Set powersaving (default = 15 minutes) */
- RIE (gl646_set_powersaving (dev, 15));
- } /* end if cold */
-
- /* Set analog frontend */
- RIE (gl646_set_fe(dev, sensor, AFE_INIT, 0));
-
- /* GPO enabling for XP200 */
- if (dev->model->ccd_type == CIS_XP200)
- {
- sanei_genesys_write_register (dev, 0x68, dev->gpo.enable[0]);
- sanei_genesys_write_register (dev, 0x69, dev->gpo.enable[1]);
-
- // enable GPIO
- gl646_gpio_output_enable(dev->usb_dev, 6);
-
- // writes 0 to GPIO
- gl646_gpio_write(dev->usb_dev, 0);
-
- // clear GPIO enable
- gl646_gpio_output_enable(dev->usb_dev, 0);
-
- sanei_genesys_write_register (dev, 0x66, 0x10);
- sanei_genesys_write_register (dev, 0x66, 0x00);
- sanei_genesys_write_register (dev, 0x66, 0x10);
- }
-
- /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which
- * is after the second slope table */
- if (dev->model->gpo_type != GPO_HP3670
- && dev->model->gpo_type != GPO_HP2400)
- {
- switch (sensor.optical_res)
- {
- case 600:
- addr = 0x08200;
- break;
- case 1200:
- addr = 0x10200;
- break;
- case 2400:
- addr = 0x1fa00;
- break;
- }
- status = sanei_genesys_set_buffer_address (dev, addr);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set up control address\n", __func__);
- return SANE_STATUS_INVAL;
- }
- sanei_usb_set_timeout (2 * 1000);
- len = 6;
- status = gl646_bulk_read_data (dev, 0x45, dev->control, len);
- /* for some reason, read fails here for MD6471, HP2300 and XP200
- * one time out of 2 scanimage launches
- */
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_warn, "%s: failed to read control\n", __func__);
- status = gl646_bulk_read_data (dev, 0x45, dev->control, len);
- }
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_warn, "%s: failed to read control\n", __func__);
- return SANE_STATUS_INVAL;
- }
- else
- {
- DBG(DBG_info, "%s: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__,
- dev->control[0], dev->control[1], dev->control[2], dev->control[3], dev->control[4],
- dev->control[5]);
- }
- sanei_usb_set_timeout (30 * 1000);
- }
- else
- /* HP2400 and HP3670 case */
- {
- dev->control[0] = 0x00;
- dev->control[1] = 0x00;
- dev->control[2] = 0x01;
- dev->control[3] = 0x00;
- dev->control[4] = 0x00;
- dev->control[5] = 0x00;
- }
-
- /* ensure head is correctly parked, and check lock */
- if (dev->model->is_sheetfed == SANE_FALSE)
- {
- if (dev->model->flags & GENESYS_FLAG_REPARK)
- {
- status = gl646_repark_head (dev);
- if (status != SANE_STATUS_GOOD)
- {
- if (status == SANE_STATUS_INVAL)
- {
- DBG(DBG_error0, "Your scanner is locked. Please move the lock switch to the "
- "unlocked position\n");
- return SANE_STATUS_JAMMED;
- }
- else
- DBG(DBG_error, "%s: gl646_repark_head failed: %s\n", __func__,
- sane_strstatus(status));
- return status;
- }
- }
- else
- {
- RIE (gl646_slow_back_home (dev, SANE_TRUE));
- }
- }
-
- /* here session and device are initialized */
- dev->already_initialized = SANE_TRUE;
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return SANE_STATUS_GOOD;
-}
-
-static
-SANE_Status
-gl646_move_to_ta (Genesys_Device * dev)
-{
- SANE_Status status = SANE_STATUS_GOOD;
-
- DBGSTART;
- if (simple_move (dev, SANE_UNFIX (dev->model->y_offset_calib_ta)) !=
- SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to move to calibration area\n", __func__);
- return status;
- }
- DBGCOMPLETED;
- return status;
-}
-
-
-/**
- * Does a simple scan: ie no line reordering and avanced data buffering and
- * shading correction. Memory for data is allocated in this function
- * and must be freed by caller.
- * @param dev device of the scanner
- * @param settings parameters of the scan
- * @param move SANE_TRUE if moving during scan
- * @param forward SANE_TRUE if moving forward during scan
- * @param shading SANE_TRUE to enable shading correction
- * @param data pointer for the data
- */
-static SANE_Status
-simple_scan (Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Settings settings, SANE_Bool move,
- SANE_Bool forward, SANE_Bool shading, std::vector<uint8_t>& data)
-{
- SANE_Status status = SANE_STATUS_INVAL;
- unsigned int size, lines, x, y, bpp;
- SANE_Bool empty, split;
- int count;
- uint8_t val;
-
- DBG(DBG_proc, "%s: starting\n", __func__);
- DBG(DBG_io, "%s: move=%d, forward=%d, shading=%d\n", __func__, move, forward, shading);
-
- /* round up to multiple of 3 in case of CIS scanner */
- if (dev->model->is_cis == SANE_TRUE)
- {
- settings.lines = ((settings.lines + 2) / 3) * 3;
- }
-
- /* setup for move then scan */
- if (move == SANE_TRUE && settings.tl_y > 0)
- {
- split = SANE_FALSE;
- }
- else
- {
- split = SANE_TRUE;
- }
- status = setup_for_scan(dev, sensor, &dev->reg, settings, split, SANE_FALSE, SANE_FALSE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */
- if (dev->model->is_cis == SANE_TRUE)
- {
- uint32_t value = 0;
- sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value);
- lines = value / 3;
- }
- else
- {
- uint32_t value = 0;
- sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value);
- lines = value + 1;
- }
- size = lines * settings.pixels;
- if (settings.depth == 16)
- bpp = 2;
- else
- bpp = 1;
- size *= bpp;
- if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- size *= 3;
- data.clear();
- data.resize(size);
-
- DBG(DBG_io, "%s: allocated %d bytes of memory for %d lines\n", __func__, size, lines);
-
- /* put back real line number in settings */
- settings.lines = lines;
-
- /* initialize frontend */
- status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* no shading correction and not watch dog for simple scan */
- dev->reg.find_reg(0x01).value &= ~(REG01_DVDSET | REG01_DOGENB);
- if (shading == SANE_TRUE)
- {
- dev->reg.find_reg(0x01).value |= REG01_DVDSET;
- }
-
- /* enable gamma table for the scan */
- dev->reg.find_reg(0x05).value |= REG05_GMMENB;
-
- /* one table movement for simple scan */
- dev->reg.find_reg(0x02).value &= ~REG02_FASTFED;
-
- if (move == SANE_FALSE)
- {
- sanei_genesys_set_motor_power(dev->reg, false);
-
- /* no automatic go home if no movement */
- dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME;
- }
- if (forward == SANE_FALSE)
- {
- dev->reg.find_reg(0x02).value |= REG02_MTRREV;
- }
- else
- {
- dev->reg.find_reg(0x02).value &= ~REG02_MTRREV;
- }
-
- /* no automatic go home when using XPA */
- if (settings.scan_method == ScanMethod::TRANSPARENCY)
- {
- dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME;
- }
-
- /* write scan registers */
- status = sanei_genesys_bulk_write_register(dev, dev->reg);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* starts scan */
- status = gl646_begin_scan(dev, sensor, &dev->reg, move);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to begin scan: \n", __func__);
- return status;
- }
-
- /* wait for buffers to be filled */
- count = 0;
- do
- {
- sanei_genesys_sleep_ms(10);
- RIE (sanei_genesys_get_status (dev, &val));
- if (DBG_LEVEL > DBG_info)
- {
- print_status (val);
- }
- RIE (sanei_genesys_test_buffer_empty (dev, &empty));
- count++;
- }
- while (empty && count < 1000);
- if (count == 1000)
- {
- DBG(DBG_error, "%s: failed toread data\n", __func__);
- return SANE_STATUS_IO_ERROR;
- }
-
- /* now we're on target, we can read data */
- status = sanei_genesys_read_data_from_scanner (dev, data.data(), size);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- /* in case of CIS scanner, we must reorder data */
- if (dev->model->is_cis == SANE_TRUE
- && settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- /* alloc one line sized working buffer */
- std::vector<uint8_t> buffer(settings.pixels * 3 * bpp);
-
- /* reorder one line of data and put it back to buffer */
- if (bpp == 1)
- {
- for (y = 0; y < lines; y++)
- {
- /* reorder line */
- for (x = 0; x < settings.pixels; x++)
- {
- buffer[x * 3] = data[y * settings.pixels * 3 + x];
- buffer[x * 3 + 1] = data[y * settings.pixels * 3 + settings.pixels + x];
- buffer[x * 3 + 2] = data[y * settings.pixels * 3 + 2 * settings.pixels + x];
- }
- /* copy line back */
- memcpy (data.data() + settings.pixels * 3 * y, buffer.data(),
- settings.pixels * 3);
- }
- }
- else
- {
- for (y = 0; y < lines; y++)
- {
- /* reorder line */
- for (x = 0; x < settings.pixels; x++)
- {
- buffer[x * 6] = data[y * settings.pixels * 6 + x * 2];
- buffer[x * 6 + 1] = data[y * settings.pixels * 6 + x * 2 + 1];
- buffer[x * 6 + 2] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2];
- buffer[x * 6 + 3] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2 + 1];
- buffer[x * 6 + 4] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2];
- buffer[x * 6 + 5] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2 + 1];
- }
- /* copy line back */
- memcpy (data.data() + settings.pixels * 6 * y, buffer.data(),
- settings.pixels * 6);
- }
- }
- }
-
- /* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */
- status = end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status));
- return status;
- }
-
- DBG(DBG_proc, "%s: end\n", __func__);
- return status;
-}
-
-/**
- * Does a simple move of the given distance by doing a scan at lowest resolution
- * shading correction. Memory for data is allocated in this function
- * and must be freed by caller.
- * @param dev device of the scanner
- * @param distance distance to move in MM
- */
-static SANE_Status
-simple_move (Genesys_Device * dev, SANE_Int distance)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- Genesys_Settings settings;
-
- DBG(DBG_proc, "%s: %d mm\n", __func__, distance);
-
- int resolution = get_lowest_resolution(dev->model->ccd_type, 3);
-
- const auto& sensor = sanei_genesys_find_sensor(dev, resolution);
-
- /* TODO give a no AGOHOME flag */
- settings.scan_method = ScanMethod::TRANSPARENCY;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_y = 0;
- settings.tl_x = 0;
- settings.pixels =
- (sensor.sensor_pixels * settings.xres) / sensor.optical_res;
- settings.lines = (distance * settings.xres) / MM_PER_INCH;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- std::vector<uint8_t> data;
- status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: simple_scan failed\n", __func__);
- }
-
- DBGCOMPLETED
- return status;
-}
-
-/**
- * update the status of the required sensor in the scanner session
- * the button fileds are used to make events 'sticky'
- */
-static SANE_Status
-gl646_update_hardware_sensors (Genesys_Scanner * session)
-{
- Genesys_Device *dev = session->dev;
- uint8_t value;
-
- // do what is needed to get a new set of events, but try to not loose any of them.
- gl646_gpio_read(dev->usb_dev, &value);
- DBG(DBG_io, "%s: GPIO=0x%02x\n", __func__, value);
-
- // scan button
- if (dev->model->buttons & GENESYS_HAS_SCAN_SW) {
- switch (dev->model->gpo_type) {
- case GPO_XP200:
- session->buttons[BUTTON_SCAN_SW].write((value & 0x02) != 0);
- break;
- case GPO_5345:
- session->buttons[BUTTON_SCAN_SW].write(value == 0x16);
- break;
- case GPO_HP2300:
- session->buttons[BUTTON_SCAN_SW].write(value == 0x6c);
- break;
- case GPO_HP3670:
- case GPO_HP2400:
- session->buttons[BUTTON_SCAN_SW].write((value & 0x20) == 0);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- // email button
- if (dev->model->buttons & GENESYS_HAS_EMAIL_SW) {
- switch (dev->model->gpo_type) {
- case GPO_5345:
- session->buttons[BUTTON_EMAIL_SW].write(value == 0x12);
- break;
- case GPO_HP3670:
- case GPO_HP2400:
- session->buttons[BUTTON_EMAIL_SW].write((value & 0x08) == 0);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- // copy button
- if (dev->model->buttons & GENESYS_HAS_COPY_SW) {
- switch (dev->model->gpo_type) {
- case GPO_5345:
- session->buttons[BUTTON_COPY_SW].write(value == 0x11);
- break;
- case GPO_HP2300:
- session->buttons[BUTTON_COPY_SW].write(value == 0x5c);
- break;
- case GPO_HP3670:
- case GPO_HP2400:
- session->buttons[BUTTON_COPY_SW].write((value & 0x10) == 0);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- // power button
- if (dev->model->buttons & GENESYS_HAS_POWER_SW) {
- switch (dev->model->gpo_type) {
- case GPO_5345:
- session->buttons[BUTTON_POWER_SW].write(value == 0x14);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- // ocr button
- if (dev->model->buttons & GENESYS_HAS_OCR_SW) {
- switch (dev->model->gpo_type) {
- case GPO_5345:
- session->buttons[BUTTON_OCR_SW].write(value == 0x13);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- // document detection
- if (dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) {
- switch (dev->model->gpo_type) {
- case GPO_XP200:
- session->buttons[BUTTON_PAGE_LOADED_SW].write((value & 0x04) != 0);
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- /* XPA detection */
- if (dev->model->flags & GENESYS_FLAG_XPA)
- {
- switch (dev->model->gpo_type)
- {
- case GPO_HP3670:
- case GPO_HP2400:
- /* test if XPA is plugged-in */
- if ((value & 0x40) == 0)
- {
- DBG(DBG_io, "%s: enabling XPA\n", __func__);
- session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE;
- }
- else
- {
- DBG(DBG_io, "%s: disabling XPA\n", __func__);
- session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
- }
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- }
-
- return SANE_STATUS_GOOD;
-}
-
-
-static SANE_Status
-write_control (Genesys_Device * dev, const Genesys_Sensor& sensor, int resolution)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- uint8_t control[4];
- uint32_t addr = 0xdead;
-
- /* 2300 does not write to 'control' */
- if (dev->model->motor_type == MOTOR_HP2300)
- return SANE_STATUS_GOOD;
-
- /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which
- * is after the second slope table */
- switch (sensor.optical_res)
- {
- case 600:
- addr = 0x08200;
- break;
- case 1200:
- addr = 0x10200;
- break;
- case 2400:
- addr = 0x1fa00;
- break;
- default:
- DBG(DBG_error, "%s: failed to compute control address\n", __func__);
- return SANE_STATUS_INVAL;
- }
-
- /* XP200 sets dpi, what other scanner put is unknown yet */
- switch (dev->model->motor_type)
- {
- case MOTOR_XP200:
- /* we put scan's dpi, not motor one */
- control[0] = LOBYTE (resolution);
- control[1] = HIBYTE (resolution);
- control[2] = dev->control[4];
- control[3] = dev->control[5];
- break;
- case MOTOR_HP3670:
- case MOTOR_HP2400:
- case MOTOR_5345:
- default:
- control[0] = dev->control[2];
- control[1] = dev->control[3];
- control[2] = dev->control[4];
- control[3] = dev->control[5];
- break;
- }
-
- DBG(DBG_info, "%s: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, control[0], control[1],
- control[2], control[3]);
- status = sanei_genesys_set_buffer_address (dev, addr);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set up control address\n", __func__);
- return SANE_STATUS_INVAL;
- }
- status = sanei_genesys_bulk_write_data(dev, 0x3c, control, 4);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: failed to set up control\n", __func__);
- return SANE_STATUS_INVAL;
- }
- return status;
-}
-
-/**
- * check if a stored calibration is compatible with requested scan.
- * @return true if compatible, false if not.
- * Whenever an error is met, it is returned.
- * @param dev scanner device
- * @param cache cache entry to test
- * @param for_overwrite reserved for future use ...
- */
-static bool
-gl646_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Calibration_Cache * cache,
- int for_overwrite)
-{
- (void) sensor;
-#ifdef HAVE_SYS_TIME_H
- struct timeval time;
-#endif
- int compatible = 1;
-
- DBG(DBG_proc, "%s: start (for_overwrite=%d)\n", __func__, for_overwrite);
-
- if (cache == NULL)
- return false;
-
- /* build minimal current_setup for calibration cache use only, it will be better
- * computed when during setup for scan
- */
- if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- dev->current_setup.channels = 3;
- }
- else
- {
- dev->current_setup.channels = 1;
- }
- dev->current_setup.xres = dev->settings.xres;
-
- DBG(DBG_io, "%s: requested=(%d,%f), tested=(%d,%f)\n", __func__, dev->current_setup.channels,
- dev->current_setup.xres, cache->used_setup.channels, cache->used_setup.xres);
-
- /* a calibration cache is compatible if color mode and x dpi match the user
- * requested scan. In the case of CIS scanners, dpi isn't a criteria */
- if (dev->model->is_cis == SANE_FALSE)
- {
- compatible =
- ((dev->current_setup.channels == cache->used_setup.channels)
- && (((int) dev->current_setup.xres) ==
- ((int) cache->used_setup.xres)));
- }
- else
- {
- compatible =
- (dev->current_setup.channels == cache->used_setup.channels);
- }
- if (dev->current_setup.params.scan_method != cache->used_setup.params.scan_method)
- {
- DBG(DBG_io, "%s: current method=%d, used=%d\n", __func__,
- static_cast<unsigned>(dev->current_setup.params.scan_method),
- static_cast<unsigned>(cache->used_setup.params.scan_method));
- compatible = 0;
- }
- if (!compatible)
- {
- DBG(DBG_proc, "%s: completed, non compatible cache\n", __func__);
- return false;
- }
-
- /* a cache entry expires after 30 minutes for non sheetfed scanners */
- /* this is not taken into account when overwriting cache entries */
-#ifdef HAVE_SYS_TIME_H
- if(for_overwrite == SANE_FALSE)
- {
- gettimeofday (&time, NULL);
- if ((time.tv_sec - cache->last_calibration > 30 * 60)
- && (dev->model->is_sheetfed == SANE_FALSE))
- {
- DBG(DBG_proc, "%s: expired entry, non compatible cache\n", __func__);
- return false;
- }
- }
-#endif
-
- DBG(DBG_proc, "%s: completed, cache compatible\n", __func__);
- return true;
-}
-
-/**
- * search for a full width black or white strip.
- * @param dev scanner device
- * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward
- * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip
- * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not
- */
-static SANE_Status
-gl646_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, SANE_Bool forward, SANE_Bool black)
-{
- SANE_Status status = SANE_STATUS_GOOD;
- SANE_Bool half_ccd = SANE_FALSE;
- Genesys_Settings settings;
- int res = get_closest_resolution(dev->model->ccd_type, 75, 1);
- unsigned int pass, count, found, x, y;
- char title[80];
-
- DBG(DBG_proc, "%s: start\n", __func__);
- /* adapt to half_ccd case */
- if (sensor.ccd_size_divisor > 1)
- {
- /* walk the master mode list to find if half_ccd */
- // FIXME: possibly wrong channel count for is_half_ccd
- if (is_half_ccd (dev->model->ccd_type, res, 3) == SANE_TRUE)
- {
- half_ccd = SANE_TRUE;
- }
- }
-
- /* we set up for a lowest available resolution color grey scan, full width */
- settings.scan_method = ScanMethod::FLATBED;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = res;
- settings.yres = res;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (SANE_UNFIX (dev->model->x_size) * res) / MM_PER_INCH;
- if (half_ccd == SANE_TRUE)
- {
- settings.pixels /= 2;
- }
-
- /* 15 mm at at time */
- settings.lines = (15 * settings.yres) / MM_PER_INCH; /* may become a parameter from genesys_devices.c */
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
- settings.dynamic_lineart = SANE_FALSE;
-
- /* signals if a strip of the given color has been found */
- found = 0;
-
- /* detection pass done */
- pass = 0;
-
- std::vector<uint8_t> data;
-
- /* loop until strip is found or maximum pass number done */
- while (pass < 20 && !found)
- {
- /* scan a full width strip */
- status =
- simple_scan(dev, sensor, settings, SANE_TRUE, forward, SANE_FALSE, data);
- if (status != SANE_STATUS_GOOD)
- {
- DBG(DBG_error, "%s: simple_scan failed\n", __func__);
- return status;
- }
- if (DBG_LEVEL >= DBG_data)
- {
- sprintf (title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd",
- (int)pass);
- sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1,
- settings.pixels, settings.lines);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < settings.lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < settings.pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * settings.pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * settings.pixels + x] < 60)
- {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / settings.pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < settings.lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < settings.pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * settings.pixels + x] > 60)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * settings.pixels + x] < 60)
- {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (settings.pixels * settings.lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
- }
- }
- pass++;
- }
- if (found)
- {
- status = SANE_STATUS_GOOD;
- DBG(DBG_info, "%s: strip found\n", __func__);
- }
- else
- {
- status = SANE_STATUS_UNSUPPORTED;
- DBG(DBG_info, "%s: strip not found\n", __func__);
- }
- return status;
-}
-
-/** the gl646 command set */
-static Genesys_Command_Set gl646_cmd_set = {
- "gl646-generic", /* the name of this set */
-
- gl646_needs_home_before_init_regs_for_scan,
-
- gl646_init,
- gl646_init_regs_for_warmup,
- gl646_init_regs_for_coarse_calibration,
- gl646_init_regs_for_shading,
- gl646_init_regs_for_scan,
-
- gl646_get_filter_bit,
- gl646_get_lineart_bit,
- gl646_get_bitset_bit,
- gl646_get_gain4_bit,
- gl646_get_fast_feed_bit,
- gl646_test_buffer_empty_bit,
- gl646_test_motor_flag_bit,
-
- gl646_public_set_fe,
- gl646_set_powersaving,
- gl646_save_power,
-
- gl646_begin_scan,
- gl646_end_scan,
-
- gl646_send_gamma_table,
-
- gl646_search_start_position,
-
- gl646_offset_calibration,
- gl646_coarse_gain_calibration,
- gl646_led_calibration,
-
- NULL,
- gl646_slow_back_home,
- NULL,
-
- sanei_genesys_bulk_write_register,
- sanei_genesys_bulk_write_data,
- gl646_bulk_read_data,
-
- gl646_update_hardware_sensors,
-
- /* sheetfed related functions */
- gl646_load_document,
- gl646_detect_document_end,
- gl646_eject_document,
- gl646_search_strip,
-
- gl646_is_compatible_calibration,
- gl646_move_to_ta,
- NULL,
- NULL,
- NULL
-};
-
-SANE_Status
-sanei_gl646_init_cmd_set (Genesys_Device * dev)
-{
- dev->model->cmd_set = &gl646_cmd_set;
- return SANE_STATUS_GOOD;
-}