From 08b41c052e4652c66d0906948eacd8dc3cf4e25b Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Thu, 23 Apr 2020 21:17:03 +0300 Subject: [PATCH] genesys: Add support for Plustek OpticFilm 7200 --- backend/Makefile.am | 1 + backend/genesys.conf.in | 3 + backend/genesys/command_set_common.cpp | 2 + backend/genesys/enums.cpp | 1 + backend/genesys/enums.h | 11 +- backend/genesys/genesys.cpp | 95 +- backend/genesys/gl842.cpp | 1058 ++++++++++++++++++++ backend/genesys/gl842.h | 131 +++ backend/genesys/gl842_registers.h | 285 ++++++ backend/genesys/low.cpp | 48 +- backend/genesys/motor.cpp | 3 +- backend/genesys/scanner_interface_usb.cpp | 10 +- backend/genesys/tables_frontend.cpp | 17 + backend/genesys/tables_gpo.cpp | 13 + backend/genesys/tables_model.cpp | 66 ++ backend/genesys/tables_motor.cpp | 13 + backend/genesys/tables_sensor.cpp | 68 ++ backend/genesys/test_scanner_interface.cpp | 1 + doc/descriptions/genesys.desc | 6 + doc/descriptions/unsupported.desc | 7 - 20 files changed, 1801 insertions(+), 38 deletions(-) create mode 100644 backend/genesys/gl842.cpp create mode 100644 backend/genesys/gl842.h create mode 100644 backend/genesys/gl842_registers.h diff --git a/backend/Makefile.am b/backend/Makefile.am index 5455e7744..fceed172c 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -540,6 +540,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \ genesys/gl646.cpp genesys/gl646.h genesys/gl646_registers.h \ genesys/gl124.cpp genesys/gl124.h genesys/gl124_registers.h \ genesys/gl841.cpp genesys/gl841.h genesys/gl841_registers.h \ + genesys/gl842.cpp genesys/gl842.h genesys/gl842_registers.h \ genesys/gl843.cpp genesys/gl843.h genesys/gl843_registers.h \ genesys/gl846.cpp genesys/gl846.h genesys/gl846_registers.h \ genesys/gl847.cpp genesys/gl847.h genesys/gl847_registers.h \ diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in index 2f2107f13..b14a19f62 100644 --- a/backend/genesys.conf.in +++ b/backend/genesys.conf.in @@ -124,6 +124,9 @@ usb 0x03f0 0x4605 # Plustek OpticBook 3600 usb 0x07b3 0x0900 +# Plustek OpticFilm 7200 +usb 0x07b3 0x0807 + # Plustek OpticFilm 7200i usb 0x07b3 0x0c04 diff --git a/backend/genesys/command_set_common.cpp b/backend/genesys/command_set_common.cpp index 87834abed..5576f68b3 100644 --- a/backend/genesys/command_set_common.cpp +++ b/backend/genesys/command_set_common.cpp @@ -114,6 +114,7 @@ void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const { 0x6c, 0x00, 0x80 }, } }, + { ModelId::PLUSTEK_OPTICFILM_7200, ScanMethod::TRANSPARENCY, {}, {} }, { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY, {}, {} }, { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, { { 0xa8, 0x07, 0x07 }, @@ -209,6 +210,7 @@ void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& { 0xa9, 0x00, 0x10 }, // note that 0x20 bit is not reset }, {} }, + { ModelId::PLUSTEK_OPTICFILM_7200, VALUE_FILTER_ANY, {}, {}, {} }, { ModelId::PLUSTEK_OPTICFILM_7200I, VALUE_FILTER_ANY, {}, {}, {} }, { ModelId::PLUSTEK_OPTICFILM_7300, VALUE_FILTER_ANY, {}, {}, {} }, { ModelId::PLUSTEK_OPTICFILM_7400, VALUE_FILTER_ANY, {}, {}, {} }, diff --git a/backend/genesys/enums.cpp b/backend/genesys/enums.cpp index 8531dbdf3..d3076344d 100644 --- a/backend/genesys/enums.cpp +++ b/backend/genesys/enums.cpp @@ -140,6 +140,7 @@ std::ostream& operator<<(std::ostream& out, ModelId id) case ModelId::PANASONIC_KV_SS080: out << "PANASONIC_KV_SS080"; break; case ModelId::PENTAX_DSMOBILE_600: out << "PENTAX_DSMOBILE_600"; break; case ModelId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break; + case ModelId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break; case ModelId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break; case ModelId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break; case ModelId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break; diff --git a/backend/genesys/enums.h b/backend/genesys/enums.h index abb108fbb..0191b9223 100644 --- a/backend/genesys/enums.h +++ b/backend/genesys/enums.h @@ -201,6 +201,7 @@ enum class ModelId : unsigned PANASONIC_KV_SS080, PENTAX_DSMOBILE_600, PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200, PLUSTEK_OPTICFILM_7200I, PLUSTEK_OPTICFILM_7300, PLUSTEK_OPTICFILM_7400, @@ -259,6 +260,7 @@ enum class SensorId : unsigned CCD_IMG101, CCD_KVSS080, CCD_PLUSTEK_OPTICBOOK_3800, + CCD_PLUSTEK_OPTICFILM_7200, CCD_PLUSTEK_OPTICFILM_7200I, CCD_PLUSTEK_OPTICFILM_7300, CCD_PLUSTEK_OPTICFILM_7400, @@ -313,6 +315,7 @@ enum class AdcId : unsigned IMG101, KVSS080, PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200, PLUSTEK_OPTICFILM_7200I, PLUSTEK_OPTICFILM_7300, PLUSTEK_OPTICFILM_7400, @@ -369,6 +372,7 @@ enum class GpioId : unsigned KVSS080, MD_5345, PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200, PLUSTEK_OPTICFILM_7200I, PLUSTEK_OPTICFILM_7300, PLUSTEK_OPTICFILM_7400, @@ -408,6 +412,7 @@ enum class MotorId : unsigned KVSS080, MD_5345, PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200, PLUSTEK_OPTICFILM_7200I, PLUSTEK_OPTICFILM_7300, PLUSTEK_OPTICFILM_7400, @@ -455,6 +460,7 @@ enum class AsicType : unsigned UNKNOWN = 0, GL646, GL841, + GL842, GL843, GL845, GL846, @@ -505,7 +511,10 @@ enum class ModelFlag : unsigned INVERTED_16BIT_DATA = 1 << 20, // the scanner has transparency, but it's implemented using only one motor - UTA_NO_SECONDARY_MOTOR = 1 << 21 + UTA_NO_SECONDARY_MOTOR = 1 << 21, + + // the scanner has transparency, but it's implemented using only one lamp + TA_NO_SECONDARY_LAMP = 1 << 22, }; inline ModelFlag operator|(ModelFlag left, ModelFlag right) diff --git a/backend/genesys/genesys.cpp b/backend/genesys/genesys.cpp index e353dbc1e..adfd164d4 100644 --- a/backend/genesys/genesys.cpp +++ b/backend/genesys/genesys.cpp @@ -64,6 +64,7 @@ #include "conv.h" #include "gl124_registers.h" #include "gl841_registers.h" +#include "gl842_registers.h" #include "gl843_registers.h" #include "gl846_registers.h" #include "gl847_registers.h" @@ -560,6 +561,11 @@ void scanner_clear_scan_and_feed_counts(Genesys_Device& dev) gl841::REG_0x0D_CLRLNCNT); break; } + case AsicType::GL842: { + dev.interface->write_register(gl842::REG_0x0D, + gl842::REG_0x0D_CLRLNCNT); + break; + } case AsicType::GL843: { dev.interface->write_register(gl843::REG_0x0D, gl843::REG_0x0D_CLRLNCNT | gl843::REG_0x0D_CLRMCNT); @@ -600,6 +606,13 @@ bool scanner_is_motor_stopped(Genesys_Device& dev) return (!(reg & gl841::REG_0x40_DATAENB) && !(reg & gl841::REG_0x40_MOTMFLG) && !status.is_motor_enabled); } + case AsicType::GL842: { + auto status = scanner_read_status(dev); + auto reg = dev.interface->read_register(gl842::REG_0x40); + + return (!(reg & gl842::REG_0x40_DATAENB) && !(reg & gl842::REG_0x40_MOTMFLG) && + !status.is_motor_enabled); + } case AsicType::GL843: { auto status = scanner_read_status(dev); auto reg = dev.interface->read_register(gl843::REG_0x40); @@ -658,6 +671,7 @@ void scanner_stop_action(Genesys_Device& dev) switch (dev.model->asic_type) { case AsicType::GL841: + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: @@ -699,6 +713,7 @@ void scanner_stop_action_no_move(Genesys_Device& dev, genesys::Genesys_Register_ switch (dev.model->asic_type) { case AsicType::GL646: case AsicType::GL841: + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: @@ -860,6 +875,7 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home) switch (dev.model->asic_type) { case AsicType::GL841: + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: @@ -1028,6 +1044,7 @@ void scanner_move_back_home_ta(Genesys_Device& dev) DBG_HELPER(dbg); switch (dev.model->asic_type) { + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: break; @@ -1360,6 +1377,12 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso { DBG_HELPER(dbg); + if (dev.model->asic_type == AsicType::GL842 && + dev.frontend.layout.type != FrontendType::WOLFSON) + { + return; + } + if (dev.model->asic_type == AsicType::GL843 && dev.frontend.layout.type != FrontendType::WOLFSON) { @@ -1447,7 +1470,7 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso ScanSession session; session.params.xres = resolution; - session.params.yres = resolution;; + session.params.yres = resolution; session.params.startx = start_pixel; session.params.starty = 0; session.params.pixels = target_pixels; @@ -1487,14 +1510,18 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso if (is_testing_mode()) { dev.interface->test_checkpoint("offset_calibration"); - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { scanner_stop_action_no_move(dev, regs); } return; } Image first_line; - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { first_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw); scanner_stop_action_no_move(dev, regs); @@ -1528,7 +1555,9 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso dev.cmd_set->begin_scan(&dev, *calib_sensor, ®s, true); Image second_line; - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw); scanner_stop_action_no_move(dev, regs); @@ -1566,7 +1595,9 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso DBG(DBG_info, "%s: starting second line reading\n", __func__); dev.cmd_set->begin_scan(&dev, *calib_sensor, ®s, true); - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw); scanner_stop_action_no_move(dev, regs); @@ -1630,6 +1661,12 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& { DBG_HELPER_ARGS(dbg, "dpi = %d", dpi); + if (dev.model->asic_type == AsicType::GL842 && + dev.frontend.layout.type != FrontendType::WOLFSON) + { + return; + } + if (dev.model->asic_type == AsicType::GL843 && dev.frontend.layout.type != FrontendType::WOLFSON) { @@ -1680,7 +1717,10 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& dev.settings.scan_method); resolution = dpihw_sensor.shading_resolution; } - if (dev.model->asic_type == AsicType::GL843) { + + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { const auto& dpihw_sensor = sanei_genesys_find_sensor(&dev, dpi, channels, dev.settings.scan_method); resolution = dpihw_sensor.shading_resolution; @@ -1707,6 +1747,7 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& const Genesys_Sensor* calib_sensor = &sensor; if (dev.model->asic_type == AsicType::GL841 || + dev.model->asic_type == AsicType::GL842 || dev.model->asic_type == AsicType::GL843) { calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels, @@ -1770,7 +1811,9 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& } Image image; - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw); } else if (dev.model->asic_type == AsicType::GL124) { // BUG: we probably want to read whole image, not just first line @@ -1779,7 +1822,9 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes); } - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { scanner_stop_action_no_move(dev, regs); } @@ -1791,7 +1836,9 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& float curr_output = 0; float target_value = 0; - if (dev.model->asic_type == AsicType::GL843) { + if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { std::vector values; // FIXME: start from the second line because the first line often has artifacts. Probably // caused by unclean cleanup of previous scan @@ -1889,7 +1936,9 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor scanner_move(dev, dev.model->default_method, static_cast(move), Direction::FORWARD); } - } else if (dev.model->asic_type == AsicType::GL843) { + } else if (dev.model->asic_type == AsicType::GL842 || + dev.model->asic_type == AsicType::GL843) + { // do nothing } else if (dev.model->asic_type == AsicType::GL845 || dev.model->asic_type == AsicType::GL846 || @@ -2147,6 +2196,7 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor } if (dev.model->asic_type == AsicType::GL841 || + dev.model->asic_type == AsicType::GL842 || dev.model->asic_type == AsicType::GL843) { dev.cmd_set->move_back_home(&dev, true); @@ -2224,7 +2274,9 @@ static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_ size_t size; uint32_t pixels_per_line; - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { pixels_per_line = dev->calib_session.output_pixels; } else { pixels_per_line = dev->calib_session.params.pixels; @@ -2250,7 +2302,9 @@ static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_ // FIXME: the current calculation is likely incorrect on non-GL843 implementations, // but this needs checking. Note the extra line when computing size. - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { size = dev->calib_session.output_total_bytes_raw; } else { size = channels * 2 * pixels_per_line * (dev->calib_session.params.lines + 1); @@ -2343,7 +2397,9 @@ static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor uint32_t skip, xend; int dummy1, dummy2, dummy3; /* dummy black average per channel */ - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { pixels_per_line = dev->calib_session.output_pixels; } else { pixels_per_line = dev->calib_session.params.pixels; @@ -2468,7 +2524,9 @@ static void genesys_dark_white_shading_calibration(Genesys_Device* dev, uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, dif; - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { pixels_per_line = dev->calib_session.output_pixels; } else { pixels_per_line = dev->calib_session.params.pixels; @@ -2490,7 +2548,9 @@ static void genesys_dark_white_shading_calibration(Genesys_Device* dev, dev->dark_average_data.clear(); dev->dark_average_data.resize(dev->average_size); - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { size = dev->calib_session.output_total_bytes_raw; } else { // FIXME: on GL841 this is different than dev->calib_session.output_total_bytes_raw, @@ -3093,7 +3153,9 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_ unsigned start_offset = dev->calib_session.params.startx * sensor.optical_res / dev->calib_session.params.xres; - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { pixels_per_line = dev->calib_session.output_pixels + start_offset; } else { pixels_per_line = dev->calib_session.params.pixels + start_offset; @@ -3275,6 +3337,7 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_ case SensorId::CCD_CANON_4400F: case SensorId::CCD_CANON_8400F: case SensorId::CCD_CANON_8600F: + case SensorId::CCD_PLUSTEK_OPTICFILM_7200: case SensorId::CCD_PLUSTEK_OPTICFILM_7200I: case SensorId::CCD_PLUSTEK_OPTICFILM_7300: case SensorId::CCD_PLUSTEK_OPTICFILM_7400: diff --git a/backend/genesys/gl842.cpp b/backend/genesys/gl842.cpp new file mode 100644 index 000000000..d47ab395f --- /dev/null +++ b/backend/genesys/gl842.cpp @@ -0,0 +1,1058 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2020 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl842_registers.h" +#include "gl842.h" +#include "test_settings.h" + +#include +#include + +namespace genesys { +namespace gl842 { + +static void gl842_init_registers(Genesys_Device& dev) +{ + // Within this function SENSOR_DEF marker documents that a register is part + // of the sensors definition and the actual value is set in + // gl842_setup_sensor(). + + DBG_HELPER(dbg); + + dev.reg.clear(); + + dev.reg.init_reg(0x01, 0x00); + dev.reg.init_reg(0x02, 0x78); + dev.reg.init_reg(0x03, 0xbf); + dev.reg.init_reg(0x04, 0x22); + dev.reg.init_reg(0x05, 0x48); + + dev.reg.init_reg(0x06, 0xb8); + + dev.reg.init_reg(0x07, 0x00); + dev.reg.init_reg(0x08, 0x00); + dev.reg.init_reg(0x09, 0x00); + dev.reg.init_reg(0x0a, 0x00); + dev.reg.init_reg(0x0d, 0x01); + + dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below + dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below + dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below + dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below + dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below + dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below + + // CCD signal settings. + dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF + + // EXPDMY[0:7]: Exposure time of dummy lines. + dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF + + // Various CCD clock settings. + dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup + + dev.reg.init_reg(0x1f, 0x01); + + dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition + + dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup + dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup + dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup + dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup + dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup + dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup + dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup + + dev.reg.init_reg(0x29, 0xff); // LAMPPWM + + dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup + dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup + + dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold + dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold + + dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup + dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup + dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup + dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup + + dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF + dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup + dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup + dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup + dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF + dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF + dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup + dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup + dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup + + dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF + + dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM + dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup + + dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup + dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup + dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup + dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup + dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup + dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup + + dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: overwritten during motor setup + dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: overwritten during motor setup + dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup + dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup + + // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio. + + dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF + dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF + + // 0x7e - set according to gpio tables. See gl842_init_gpio. + + dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF + + // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for + // moving in various situations. + dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE + + dev.reg.init_reg(0x81, 0x00); + dev.reg.init_reg(0x82, 0x00); + dev.reg.init_reg(0x83, 0x00); + dev.reg.init_reg(0x84, 0x00); + dev.reg.init_reg(0x85, 0x00); + dev.reg.init_reg(0x86, 0x00); + dev.reg.init_reg(0x87, 0x00); + + const auto& sensor = sanei_genesys_find_sensor_any(&dev); + sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw); + + scanner_setup_sensor(dev, sensor, dev.reg); +} + +// Send slope table for motor movement slope_table in machine byte order +static void gl842_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + + int i; + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + + // slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000 + // XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) { + dev->interface->write_buffer(0x3c, 0x010000 + 0x200 * table_nr, table.data(), steps * 2); + } else { + dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(), steps * 2); + } +} + +static void gl842_set_ad_fe(Genesys_Device* dev) +{ + for (const auto& reg : dev->frontend.regs) { + dev->interface->write_fe_register(reg.address, reg.value); + } +} + +// Set values of analog frontend +void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + (void) sensor; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + } + + // check analog frontend type + // FIXME: looks like we write to that register with initial data + uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET; + if (fe_type == 2) { + gl842_set_ad_fe(dev); + return; + } + if (fe_type != 0) { + throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type); + } + + DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); + + for (unsigned i = 1; i <= 3; i++) { + dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i)); + } + for (const auto& reg : sensor.custom_fe_regs) { + dev->interface->write_fe_register(reg.address, reg.value); + } + + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); + } + + if (dev->model->sensor_id == SensorId::CCD_KVSS080) { + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + } + } + + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); + } +} + +static void gl842_init_motor_regs_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + const ScanSession& session, + Genesys_Register_Set* reg, + const MotorProfile& motor_profile, + unsigned int exposure, + unsigned scan_yres, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + ScanFlag flags) +{ + DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, " + "feed_steps=%d, flags=%x", + exposure, scan_yres, static_cast(motor_profile.step_type), + scan_lines, scan_dummy, feed_steps, static_cast(flags)); + + unsigned step_multiplier = 2; + bool use_fast_fed = false; + + if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) { + use_fast_fed = true; + } + + reg->set24(REG_LINCNT, scan_lines); + + reg->set8(REG_0x02, 0); + sanei_genesys_set_motor_power(*reg, true); + + std::uint8_t reg02 = reg->get8(REG_0x02); + if (use_fast_fed) { + reg02 |= REG_0x02_FASTFED; + } else { + reg02 &= ~REG_0x02_FASTFED; + } + + // in case of automatic go home, move until home sensor + if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) { + reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; + } + + // disable backtracking if needed + if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || + (scan_yres >= 2400) || + (scan_yres >= sensor.optical_res)) + { + reg02 |= REG_0x02_ACDCDIS; + } + + if (has_flag(flags, ScanFlag::REVERSE)) { + reg02 |= REG_0x02_MTRREV; + } else { + reg02 &= ~REG_0x02_MTRREV; + } + reg->set8(REG_0x02, reg02); + + // scan and backtracking slope table + auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, exposure, + dev->motor.base_ydpi, step_multiplier, + motor_profile); + + gl842_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); + gl842_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + gl842_send_slope_table(dev, STOP_TABLE, scan_table.table, scan_table.steps_count); + + reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier); + + // fast table + const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session); + if (fast_profile == nullptr) { + fast_profile = &motor_profile; + } + + auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier, + *fast_profile); + + gl842_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); + gl842_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); + + reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); + + if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) { + std::uint8_t vref = 0; + vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL; + vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK; + vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST; + vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME; + reg->set8(REG_0x80, vref); + } + + // substract acceleration distance from feedl + unsigned feedl = feed_steps; + feedl <<= static_cast(motor_profile.step_type); + + unsigned dist = scan_table.steps_count / step_multiplier; + + if (use_fast_fed) { + dist += (fast_table.steps_count / step_multiplier) * 2; + } + DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + // make sure when don't insane value : XXX STEF XXX in this case we should + // fall back to single table move + if (dist < feedl) { + feedl -= dist; + } else { + feedl = 1; + } + + reg->set24(REG_FEEDL, feedl); + + // doesn't seem to matter that much + std::uint32_t z1, z2; + sanei_genesys_calculate_zmod(use_fast_fed, + exposure, + scan_table.table, + scan_table.steps_count / step_multiplier, + feedl, + scan_table.steps_count / step_multiplier, + &z1, + &z2); + if (scan_yres > 600) { + z1 = 0; + z2 = 0; + } + + reg->set24(REG_Z1MOD, z1); + reg->set24(REG_Z2MOD, z2); + + reg->set8_mask(REG_0x1E, scan_dummy, 0x0f); + + reg->set8_mask(REG_0x67, static_cast(motor_profile.step_type) << REG_0x67S_STEPSEL, + REG_0x67_STEPSEL); + reg->set8_mask(REG_0x68, static_cast(fast_profile->step_type) << REG_0x68S_FSTPSEL, + REG_0x68_FSTPSEL); + + // steps for STOP table + reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); +} + +static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure, + const ScanSession& session) +{ + DBG_HELPER(dbg); + + scanner_setup_sensor(*dev, sensor, *reg); + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + // enable shading + regs_set_optical_off(dev->model->asic_type, *reg); + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION) || + session.use_host_side_calib) + { + reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET; + + } else { + reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET; + } + + bool use_shdarea = true; + + if (use_shdarea) { + reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA; + } else { + reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA; + } + + if (dev->model->model_id == ModelId::CANON_8600F) { + reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB; + } else { + reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB; + } + + // FIXME: we probably don't need to set exposure to registers at this point. It was this way + // before a refactor. + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + // select XPA + reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL; + if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { + reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL; + } + reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA); + + // BW threshold + reg->set8(REG_0x2E, dev->settings.threshold); + reg->set8(REG_0x2F, dev->settings.threshold); + + // monochrome / color scan parameters + std::uint8_t reg04 = reg->get8(REG_0x04); + reg04 = reg04 & REG_0x04_FESET; + + switch (session.params.depth) { + case 8: + break; + case 16: + reg04 |= REG_0x04_BITSET; + break; + } + + if (session.params.channels == 1) { + switch (session.params.color_filter) { + case ColorFilter::RED: reg04 |= 0x14; break; + case ColorFilter::BLUE: reg04 |= 0x1c; break; + case ColorFilter::GREEN: reg04 |= 0x18; break; + default: + break; // should not happen + } + } else { + switch (dev->frontend.layout.type) { + case FrontendType::WOLFSON: + // pixel by pixel + reg04 |= 0x10; + break; + case FrontendType::ANALOG_DEVICES: + // slow color pixel by pixel + reg04 |= 0x20; + break; + default: + throw SaneException("Invalid frontend type %d", + static_cast(dev->frontend.layout.type)); + } + } + + reg->set8(REG_0x04, reg04); + + const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution, + session.params.channels, + session.params.scan_method); + sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw); + + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + reg->set16(REG_DPISET, sensor.register_dpiset); + + reg->set16(REG_STRPIXEL, session.pixel_startx); + reg->set16(REG_ENDPIXEL, session.pixel_endx); + + reg->set24(REG_MAXWD, session.output_line_bytes_raw); + + unsigned tgtime = exposure / 65536 + 1; + reg->set16(REG_LPERIOD, exposure / tgtime); + + reg->set8(REG_DUMMY, sensor.dummy_pixel); +} + +void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + // we enable true gray for cis scanners only, and just when doing scan since color calibration + // is OK for this mode + + int dummy = 0; + + /* slope_dpi */ + /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ + int slope_dpi = 0; + if (dev->model->is_cis) { + slope_dpi = session.params.yres * session.params.channels; + } else { + slope_dpi = session.params.yres; + } + slope_dpi = slope_dpi * (1 + dummy); + + int exposure = sensor.exposure_lperiod; + if (exposure < 0) { + throw std::runtime_error("Exposure not defined in sensor definition"); + } + const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session); + + DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, + static_cast(motor_profile.step_type)); + + // now _LOGICAL_ optical values used are known, setup registers + gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session); + gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi, + session.optical_line_count, dummy, session.params.starty, + session.params.flags); + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + build_image_pipeline(dev, session); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; +} + +ScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + DBG_HELPER(dbg); + debug_dump(DBG_info, settings); + + ScanFlag flags = ScanFlag::NONE; + + float move = 0.0f; + if (settings.scan_method == ScanMethod::TRANSPARENCY || + settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + if (!dev->ignore_offsets) { + move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta; + } + flags |= ScanFlag::USE_XPA; + } else { + if (!dev->ignore_offsets) { + move = dev->model->y_offset; + } + } + + move += settings.tl_y; + + int move_dpi = dev->motor.base_ydpi; + move = static_cast((move * move_dpi) / MM_PER_INCH); + + float start = 0.0f; + if (settings.scan_method==ScanMethod::TRANSPARENCY || + settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + start = dev->model->x_offset_ta; + } else { + start = dev->model->x_offset; + } + start = start + settings.tl_x; + + start = static_cast((start * settings.xres) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, sensor); + + return session; +} + +void CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "enable = %d", enable); +} + +void CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "delay = %d", delay); +} + +void CommandSetGl842::eject_document(Genesys_Device* dev) const +{ + (void) dev; + DBG_HELPER(dbg); +} + + +void CommandSetGl842::load_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + (void) dev; +} + +void CommandSetGl842::detect_document_end(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + (void) dev; + throw SaneException(SANE_STATUS_UNSUPPORTED); +} + +// Send the low-level scan command +void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + + if (reg->state.is_xpa_on && reg->state.is_lamp_on && + !has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP)) + { + dev->cmd_set->set_xpa_lamp_power(*dev, true); + } + if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) { + dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY); + } + + scanner_clear_scan_and_feed_counts(*dev); + + // enable scan and motor + std::uint8_t val = dev->interface->read_register(REG_0x01); + val |= REG_0x01_SCAN; + dev->interface->write_register(REG_0x01, val); + + scanner_start_action(*dev, start_motor); + + switch (reg->state.motor_mode) { + case MotorMode::PRIMARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); + } + break; + } + case MotorMode::PRIMARY_AND_SECONDARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); + dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + } + break; + } + case MotorMode::SECONDARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + } + break; + } + } +} + +void CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + if (reg->state.is_xpa_on) { + dev->cmd_set->set_xpa_lamp_power(*dev, false); + } + + if (!dev->model->is_sheetfed) { + scanner_stop_action(*dev); + } +} + +void CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + scanner_move_back_home(*dev, wait_until_home); +} + +void CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int move; + + float calib_size_mm = 0; + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + calib_size_mm = dev->model->y_size_calib_ta_mm; + } else { + calib_size_mm = dev->model->y_size_calib_mm; + } + + unsigned resolution = sensor.shading_resolution; + + unsigned channels = 3; + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + unsigned calib_pixels = 0; + unsigned calib_pixels_offset = 0; + + if (should_calibrate_only_active_area(*dev, dev->settings)) { + float offset = dev->model->x_offset_ta; + // FIXME: we should use resolution here + offset = static_cast((offset * dev->settings.xres) / MM_PER_INCH); + + float size = dev->model->x_size_ta; + size = static_cast((size * dev->settings.xres) / MM_PER_INCH); + + calib_pixels_offset = static_cast(offset); + calib_pixels = static_cast(size); + } else { + calib_pixels_offset = 0; + calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; + } + + ScanFlag flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::DISABLE_BUFFER_FULL_MOVE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + move = static_cast(dev->model->y_offset_calib_white_ta - + dev->model->y_offset_sensor_to_ta); + flags |= ScanFlag::USE_XPA; + } else { + move = static_cast(dev->model->y_offset_calib_white); + } + + move = static_cast((move * resolution) / MM_PER_INCH); + unsigned calib_lines = static_cast(calib_size_mm * resolution / MM_PER_INCH); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = calib_pixels_offset; + session.params.starty = move; + session.params.pixels = calib_pixels; + session.params.lines = calib_lines; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->calib_session = session; +} + +void CommandSetGl842::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + ScanSession session = calculate_scan_session(dev, sensor, dev->settings); + + init_regs_for_scan_session(dev, sensor, ®s, session); +} + +void CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) + return; // No gamma on this model + + unsigned size = 256; + + std::vector gamma(size * 2 * 3); + + std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); + std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); + std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); + + // copy sensor specific's gamma tables + for (unsigned i = 0; i < size; i++) { + gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff; + gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff; + gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff; + gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff; + } + + dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3); +} + +SensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + return scanner_led_calibration(*dev, sensor, regs); +} + +void CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + scanner_offset_calibration(*dev, sensor, regs); +} + +void CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + scanner_coarse_gain_calibration(*dev, sensor, regs, dpi); +} + +void CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg) const +{ + DBG_HELPER(dbg); + (void) sensor; + + unsigned channels = 3; + unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method) + .get_nearest_resolution_x(600); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2; + + *reg = dev->reg; + + auto flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_STAGGER_OFFSET | + ScanFlag::IGNORE_COLOR_OFFSET; + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + flags |= ScanFlag::USE_XPA; + } + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = (num_pixels / 2) * resolution / calib_sensor.optical_res; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = dev->model->bpp_color_values.front(); + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, reg, session); + + sanei_genesys_set_motor_power(*reg, false); +} + +static void gl842_init_gpio(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg) + { + dev->interface->write_register(reg.address, reg.value); + }); +} + +void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const +{ + DBG_HELPER(dbg); + + if (cold) { + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } + + // setup initial register values + gl842_init_registers(*dev); + dev->interface->write_registers(dev->reg); + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) { + uint8_t data[32] = { + 0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00, + }; + + dev->interface->write_buffer(0x3c, 0x010a00, data, 32); + } + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) { + dev->interface->write_0x8c(0x10, 0x94); + } + + // set RAM read address + dev->interface->write_register(REG_0x2A, 0x00); + dev->interface->write_register(REG_0x2B, 0x00); + + // setup gpio + gl842_init_gpio(dev); + dev->interface->sleep_ms(100); +} + +void CommandSetGl842::init(Genesys_Device* dev) const +{ + DBG_INIT(); + DBG_HELPER(dbg); + + sanei_genesys_asic_init(dev); +} + +void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const +{ + DBG_HELPER(dbg); + (void) s; +} + +/** @brief move sensor to transparency adaptor + * Move sensor to the calibration of the transparency adapator (XPA). + * @param dev device to use + */ +void CommandSetGl842::move_to_ta(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + const auto& resolution_settings = dev->model->get_resolution_settings(dev->model->default_method); + float resolution = resolution_settings.get_min_resolution_y(); + + unsigned multiplier = 16; + unsigned feed = static_cast(multiplier * (dev->model->y_offset_sensor_to_ta * resolution) / + MM_PER_INCH); + scanner_move(*dev, dev->model->default_method, feed, Direction::FORWARD); +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) const +{ + DBG_HELPER(dbg); + + int offset = 0; + unsigned length = size; + + if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) { + offset = dev->session.params.startx * sensor.shading_resolution / + dev->session.params.xres; + + length = dev->session.output_pixels * sensor.shading_resolution / + dev->session.params.xres; + + offset += sensor.shading_pixel_offset; + + // 16 bit words, 2 words per color, 3 color channels + length *= 2 * 2 * 3; + offset *= 2 * 2 * 3; + } else { + offset += sensor.shading_pixel_offset * 2 * 2 * 3; + } + + dev->interface->record_key_value("shading_offset", std::to_string(offset)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + + std::vector final_data(length, 0); + + unsigned count = 0; + if (offset < 0) { + count += (-offset); + length -= (-offset); + offset = 0; + } + if (static_cast(length) + offset > static_cast(size)) { + length = size - offset; + } + + for (unsigned i = 0; i < length; i++) { + final_data[count++] = data[offset + i]; + count++; + } + + dev->interface->write_buffer(0x3c, 0, final_data.data(), count); +} + +bool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return true; +} + +void CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +} // namespace gl842 +} // namespace genesys diff --git a/backend/genesys/gl842.h b/backend/genesys/gl842.h new file mode 100644 index 000000000..c49d90f6e --- /dev/null +++ b/backend/genesys/gl842.h @@ -0,0 +1,131 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + 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. +*/ + +#include "genesys.h" +#include "command_set_common.h" + +#ifndef BACKEND_GENESYS_GL842_H +#define BACKEND_GENESYS_GL842_H + +namespace genesys { +namespace gl842 { + +class CommandSetGl842 : public CommandSetCommon +{ +public: + ~CommandSetGl842() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +enum SlopeTable +{ + SCAN_TABLE = 0, // table 1 at 0x4000 + BACKTRACK_TABLE = 1, // table 2 at 0x4800 + STOP_TABLE = 2, // table 3 at 0x5000 + FAST_TABLE = 3, // table 4 at 0x5800 + HOME_TABLE = 4, // table 5 at 0x6000 +}; + +} // namespace gl842 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL842_H diff --git a/backend/genesys/gl842_registers.h b/backend/genesys/gl842_registers.h new file mode 100644 index 000000000..b6934ceec --- /dev/null +++ b/backend/genesys/gl842_registers.h @@ -0,0 +1,285 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_gl842_REGISTERS_H +#define BACKEND_GENESYS_gl842_REGISTERS_H + +#include + +namespace genesys { +namespace gl842 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_M15DRAM = 0x08; +static constexpr RegMask REG_0x01_DRAMSEL = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegAddr REG_0x03 = 0x03; +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegAddr REG_0x04 = 0x04; +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_AFEMOD = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; + +static constexpr RegShift REG_0x04S_AFEMOD = 4; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegShift REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x08_DECFLAG = 0x40; +static constexpr RegMask REG_0x08_GMMFFR = 0x20; +static constexpr RegMask REG_0x08_GMMFFG = 0x10; +static constexpr RegMask REG_0x08_GMMFFB = 0x08; +static constexpr RegMask REG_0x08_GMMZR = 0x04; +static constexpr RegMask REG_0x08_GMMZG = 0x02; +static constexpr RegMask REG_0x08_GMMZB = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_CLKSET = 0x30; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_ENHANCE = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; +static constexpr RegMask REG_0x09_NWAIT = 0x01; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegAddr REG_0x0F = 0x0f; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; + +static constexpr RegAddr REG_0x18 = 0x18; +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegAddr REG_EXPDMY = 0x19; + +static constexpr RegAddr REG_0x1A = 0x1a; +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegAddr REG_0x1C = 0x1c; +static constexpr RegMask REG_0x1C_TGTIME = 0x07; + +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_TGSHLD = 0x1f; + +static constexpr RegAddr REG_0x1E = 0x1e; +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegShift REG_0x1ES_WDTIME = 4; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; +static constexpr RegShift REG_0x1ES_LINESEL = 0; + +static constexpr RegAddr REG_0x21 = 0x21; +static constexpr RegAddr REG_STEPNO = 0x21; +static constexpr RegAddr REG_FWDSTEP = 0x22; +static constexpr RegAddr REG_BWDSTEP = 0x23; +static constexpr RegAddr REG_FASTNO = 0x24; +static constexpr RegAddr REG_LINCNT = 0x25; + +static constexpr RegAddr REG_0x29 = 0x29; +static constexpr RegAddr REG_0x2A = 0x2a; +static constexpr RegAddr REG_0x2B = 0x2b; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_0x2E = 0x2e; +static constexpr RegAddr REG_0x2F = 0x2f; + +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_DUMMY = 0x34; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; +static constexpr RegAddr REG_FEEDL = 0x3d; + +static constexpr RegAddr REG_0x40 = 0x40; +static constexpr RegMask REG_0x40_HISPDFLG = 0x04; +static constexpr RegMask REG_0x40_MOTMFLG = 0x02; +static constexpr RegMask REG_0x40_DATAENB = 0x01; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTORENB = 0x01; + +static constexpr RegMask REG_0x5A_ADCLKINV = 0x80; +static constexpr RegMask REG_0x5A_RLCSEL = 0x40; +static constexpr RegMask REG_0x5A_CDSREF = 0x30; +static constexpr RegShift REG_0x5AS_CDSREF = 4; +static constexpr RegMask REG_0x5A_RLC = 0x0f; +static constexpr RegShift REG_0x5AS_RLC = 0; + +static constexpr RegAddr REG_0x5E = 0x5e; +static constexpr RegMask REG_0x5E_DECSEL = 0xe0; +static constexpr RegShift REG_0x5ES_DECSEL = 5; +static constexpr RegMask REG_0x5E_STOPTIM = 0x1f; +static constexpr RegShift REG_0x5ES_STOPTIM = 0; + +static constexpr RegAddr REG_FMOVDEC = 0x5f; + +static constexpr RegAddr REG_0x60 = 0x60; +static constexpr RegMask REG_0x60_Z1MOD = 0x1f; +static constexpr RegAddr REG_0x61 = 0x61; +static constexpr RegMask REG_0x61_Z1MOD = 0xff; +static constexpr RegAddr REG_0x62 = 0x62; +static constexpr RegMask REG_0x62_Z1MOD = 0xff; + +static constexpr RegAddr REG_0x63 = 0x63; +static constexpr RegMask REG_0x63_Z2MOD = 0x1f; +static constexpr RegAddr REG_0x64 = 0x64; +static constexpr RegMask REG_0x64_Z2MOD = 0xff; +static constexpr RegAddr REG_0x65 = 0x65; +static constexpr RegMask REG_0x65_Z2MOD = 0xff; + +static constexpr RegAddr REG_0x67 = 0x67; +static constexpr RegAddr REG_0x68 = 0x68; + +static constexpr RegShift REG_0x67S_STEPSEL = 6; +static constexpr RegMask REG_0x67_STEPSEL = 0xc0; + +static constexpr RegShift REG_0x68S_FSTPSEL = 6; +static constexpr RegMask REG_0x68_FSTPSEL = 0xc0; + +static constexpr RegAddr REG_FSHDEC = 0x69; +static constexpr RegAddr REG_FMOVNO = 0x6a; + +static constexpr RegAddr REG_0x6B = 0x6b; +static constexpr RegMask REG_0x6B_MULTFILM = 0x80; + +static constexpr RegAddr REG_Z1MOD = 0x60; +static constexpr RegAddr REG_Z2MOD = 0x63; + +static constexpr RegAddr REG_0x6C = 0x6c; +static constexpr RegAddr REG_0x6D = 0x6d; +static constexpr RegAddr REG_0x6E = 0x6e; +static constexpr RegAddr REG_0x6F = 0x6f; + +static constexpr RegAddr REG_CK1MAP = 0x74; +static constexpr RegAddr REG_CK3MAP = 0x77; +static constexpr RegAddr REG_CK4MAP = 0x7a; + +static constexpr RegAddr REG_0x7E = 0x7e; + +static constexpr RegAddr REG_0x80 = 0x80; +static constexpr RegMask REG_0x80_TABLE1_NORMAL = 0x03; +static constexpr RegShift REG_0x80S_TABLE1_NORMAL = 0; +static constexpr RegMask REG_0x80_TABLE2_BACK = 0x0c; +static constexpr RegShift REG_0x80S_TABLE2_BACK = 2; +static constexpr RegMask REG_0x80_TABLE4_FAST = 0x30; +static constexpr RegShift REG_0x80S_TABLE4_FAST = 4; +static constexpr RegMask REG_0x80_TABLE5_GO_HOME = 0xc0; +static constexpr RegShift REG_0x80S_TABLE5_GO_HOME = 6; + +static constexpr RegMask REG_0x87_LEDADD = 0x04; + +} // namespace gl842 +} // namespace genesys + +#endif // BACKEND_GENESYS_gl842_REGISTERS_H diff --git a/backend/genesys/low.cpp b/backend/genesys/low.cpp index 4d56fa690..66b0e58df 100644 --- a/backend/genesys/low.cpp +++ b/backend/genesys/low.cpp @@ -51,6 +51,7 @@ #include "gl124_registers.h" #include "gl646_registers.h" #include "gl841_registers.h" +#include "gl842_registers.h" #include "gl843_registers.h" #include "gl846_registers.h" #include "gl847_registers.h" @@ -59,6 +60,7 @@ #include "gl124.h" #include "gl646.h" #include "gl841.h" +#include "gl842.h" #include "gl843.h" #include "gl846.h" #include "gl847.h" @@ -79,6 +81,7 @@ std::unique_ptr create_cmd_set(AsicType asic_type) switch (asic_type) { case AsicType::GL646: return std::unique_ptr(new gl646::CommandSetGl646{}); case AsicType::GL841: return std::unique_ptr(new gl841::CommandSetGl841{}); + case AsicType::GL842: return std::unique_ptr(new gl842::CommandSetGl842{}); case AsicType::GL843: return std::unique_ptr(new gl843::CommandSetGl843{}); case AsicType::GL845: // since only a few reg bits differs we handle both together case AsicType::GL846: return std::unique_ptr(new gl846::CommandSetGl846{}); @@ -271,6 +274,7 @@ Status scanner_read_status(Genesys_Device& dev) case AsicType::GL124: address = 0x101; break; case AsicType::GL646: case AsicType::GL841: + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: @@ -827,7 +831,9 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s, s.pixel_endx = s.pixel_startx + s.optical_pixels * s.ccd_size_divisor; } else if (dev->model->asic_type == AsicType::GL841 || - dev->model->asic_type == AsicType::GL843) { + dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { s.pixel_startx = (s.output_startx * s.optical_resolution) / s.params.xres; s.pixel_endx = s.pixel_startx + s.optical_pixels; @@ -843,7 +849,8 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s, s.pixel_startx = sensor.pixel_count_ratio.apply(s.pixel_startx); s.pixel_endx = sensor.pixel_count_ratio.apply(s.pixel_endx); - if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) { @@ -858,12 +865,10 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s, s.pixel_startx++; s.pixel_endx++; } - } else if (dev->model->asic_type == AsicType::GL841) { - if (s.num_staggered_lines > 0 && (s.pixel_startx & 1) == 0) { - s.pixel_startx++; - s.pixel_endx++; - } - } else if (dev->model->asic_type == AsicType::GL843) { + } else if (dev->model->asic_type == AsicType::GL841 || + dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { // in case of stagger we have to start at an odd coordinate // FIXME: we should probably just configure the image pipeline accordingly bool stagger_starts_even = false; @@ -924,7 +929,9 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se // compute the number of optical pixels that will be acquired by the chip s.optical_pixels = (s.params.pixels * s.optical_resolution) / s.output_resolution; - if (dev->model->asic_type == AsicType::GL841) { + if (dev->model->asic_type == AsicType::GL841 || + dev->model->asic_type == AsicType::GL842) + { s.optical_pixels = align_int_up(s.optical_pixels, 2); } @@ -937,7 +944,8 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number s.optical_pixels = align_int_up(s.optical_pixels, 2 * s.ccd_size_divisor); - if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 || dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I || @@ -1033,12 +1041,15 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se s.conseq_pixel_dist = s.output_pixels / s.ccd_size_divisor / s.segment_count; } - if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->asic_type == AsicType::GL842 || + dev->model->asic_type == AsicType::GL843) + { s.conseq_pixel_dist = s.output_pixels / s.segment_count; } s.output_segment_pixel_group_count = 0; if (dev->model->asic_type == AsicType::GL124 || + dev->model->asic_type == AsicType::GL842 || dev->model->asic_type == AsicType::GL843) { s.output_segment_pixel_group_count = s.output_pixels / @@ -1071,6 +1082,7 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se s.use_host_side_calib = sensor.use_host_side_calib; if (dev->model->asic_type == AsicType::GL841 || + dev->model->asic_type == AsicType::GL842 || dev->model->asic_type == AsicType::GL843) { // no 16 bit gamma for this ASIC @@ -1102,6 +1114,7 @@ static std::size_t get_usb_buffer_read_size(AsicType asic, const ScanSession& se // BUG: we shouldn't multiply by channels here return session.output_line_bytes_raw * session.params.channels; + case AsicType::GL842: case AsicType::GL843: return session.output_line_bytes_raw * 2; @@ -1427,6 +1440,7 @@ void scanner_start_action(Genesys_Device& dev, bool start_motor) switch (dev.model->asic_type) { case AsicType::GL646: case AsicType::GL841: + case AsicType::GL842: case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: @@ -1495,6 +1509,12 @@ void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs, regs.set16(gl841::REG_EXPB, exposure.blue); break; } + case AsicType::GL842: { + regs.set16(gl842::REG_EXPR, exposure.red); + regs.set16(gl842::REG_EXPG, exposure.green); + regs.set16(gl842::REG_EXPB, exposure.blue); + break; + } case AsicType::GL843: { regs.set16(gl843::REG_EXPR, exposure.red); regs.set16(gl843::REG_EXPG, exposure.green); @@ -1531,6 +1551,10 @@ void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs) regs.find_reg(gl841::REG_0x01).value &= ~gl841::REG_0x01_SCAN; break; } + case AsicType::GL842: { + regs.find_reg(gl842::REG_0x01).value &= ~gl842::REG_0x01_SCAN; + break; + } case AsicType::GL843: { regs.find_reg(gl843::REG_0x01).value &= ~gl843::REG_0x01_SCAN; break; @@ -1560,6 +1584,8 @@ bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& reg return static_cast(regs.get8(gl646::REG_0x06) & gl646::REG_0x06_GAIN4); case AsicType::GL841: return static_cast(regs.get8(gl841::REG_0x06) & gl841::REG_0x06_GAIN4); + case AsicType::GL842: + return static_cast(regs.get8(gl842::REG_0x06) & gl842::REG_0x06_GAIN4); case AsicType::GL843: return static_cast(regs.get8(gl843::REG_0x06) & gl843::REG_0x06_GAIN4); case AsicType::GL845: diff --git a/backend/genesys/motor.cpp b/backend/genesys/motor.cpp index d0f3b527b..d1b5e3d37 100644 --- a/backend/genesys/motor.cpp +++ b/backend/genesys/motor.cpp @@ -92,7 +92,8 @@ unsigned get_slope_table_max_size(AsicType asic_type) { switch (asic_type) { case AsicType::GL646: - case AsicType::GL841: return 255; + case AsicType::GL841: + case AsicType::GL842: return 255; case AsicType::GL843: case AsicType::GL845: case AsicType::GL846: diff --git a/backend/genesys/scanner_interface_usb.cpp b/backend/genesys/scanner_interface_usb.cpp index 0866c3e43..a3ac7ee4a 100644 --- a/backend/genesys/scanner_interface_usb.cpp +++ b/backend/genesys/scanner_interface_usb.cpp @@ -223,7 +223,9 @@ static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, s outdata[2] = 0; outdata[3] = 0x10; } else if (asic_type == AsicType::GL841 || - asic_type == AsicType::GL843) { + asic_type == AsicType::GL842 || + asic_type == AsicType::GL843) + { outdata[0] = BULK_IN; outdata[1] = BULK_RAM; outdata[2] = 0x82; // @@ -358,6 +360,7 @@ void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, st DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size); if (dev_->model->asic_type != AsicType::GL646 && dev_->model->asic_type != AsicType::GL841 && + dev_->model->asic_type != AsicType::GL842 && dev_->model->asic_type != AsicType::GL843) { throw SaneException("Unsupported transfer mode"); @@ -379,6 +382,7 @@ void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std { DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size); if (dev_->model->asic_type != AsicType::GL841 && + dev_->model->asic_type != AsicType::GL842 && dev_->model->asic_type != AsicType::GL843) { throw SaneException("Unsupported transfer mode"); @@ -388,7 +392,9 @@ void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std write_register(0x5c, ((addr >> 4) & 0xff)); bulk_write_data(type, data, size); - if (dev_->model->asic_type == AsicType::GL843) { + if (dev_->model->asic_type == AsicType::GL842 || + dev_->model->asic_type == AsicType::GL843) + { // it looks like we need to reset the address so that subsequent buffer operations work. // Most likely the MTRTBL register is to blame. write_register(0x5b, 0); diff --git a/backend/genesys/tables_frontend.cpp b/backend/genesys/tables_frontend.cpp index d7c378859..cfd801d12 100644 --- a/backend/genesys/tables_frontend.cpp +++ b/backend/genesys/tables_frontend.cpp @@ -471,6 +471,23 @@ void genesys_init_frontend_tables() s_frontends->push_back(fe); + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICFILM_7200; + fe.layout = analog_devices; + fe.regs = { + { 0x00, 0xf8 }, + { 0x01, 0x80 }, + { 0x02, 0x2e }, + { 0x03, 0x17 }, + { 0x04, 0x20 }, + { 0x05, 0x0109 }, + { 0x06, 0x01 }, + { 0x07, 0x0104 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + fe = Genesys_Frontend(); fe.id = AdcId::PLUSTEK_OPTICFILM_7200I; fe.layout = analog_devices; diff --git a/backend/genesys/tables_gpo.cpp b/backend/genesys/tables_gpo.cpp index 774a1e907..26f5c4764 100644 --- a/backend/genesys/tables_gpo.cpp +++ b/backend/genesys/tables_gpo.cpp @@ -292,6 +292,19 @@ void genesys_init_gpo_tables() s_gpo->push_back(gpo); + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICFILM_7200; + gpo.regs = { + { 0x6b, 0x33 }, + { 0x6c, 0x00 }, + { 0x6d, 0x80 }, + { 0x6e, 0x0c }, + { 0x6f, 0x80 }, + { 0x7e, 0x00 } + }; + s_gpo->push_back(gpo); + + gpo = Genesys_Gpo(); gpo.id = GpioId::PLUSTEK_OPTICFILM_7200I; gpo.regs = { diff --git a/backend/genesys/tables_model.cpp b/backend/genesys/tables_model.cpp index 5df6f8989..5201d59a4 100644 --- a/backend/genesys/tables_model.cpp +++ b/backend/genesys/tables_model.cpp @@ -2250,6 +2250,72 @@ void genesys_init_usb_device_tables() s_usb_devices->emplace_back(0x07b3, 0x0900, model); + + model = Genesys_Model(); + model.name = "plustek-opticfilm-7200"; + model.vendor = "PLUSTEK"; + model.model = "OpticFilm 7200"; + model.model_id = ModelId::PLUSTEK_OPTICFILM_7200; + model.asic_type = AsicType::GL842; + + model.resolutions = { + { + { ScanMethod::TRANSPARENCY }, + { 7200, 3600, 1800, 900 }, + { 7200, 3600, 1800, 900 }, + } + }; + + model.bpp_gray_values = { 16 }; + model.bpp_color_values = { 16 }; + model.default_method = ScanMethod::TRANSPARENCY; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 36.0; + model.y_size = 44.0; + + model.y_offset_calib_white = 0.0; + model.y_size_calib_mm = 0.0; + model.x_offset_calib_black = 6.5; + model.x_size_calib_mm = 35.9834; + + model.x_offset_ta = 0.7f; + model.y_offset_ta = 28.0; + model.x_size_ta = 36.0; + model.y_size_ta = 25.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_black_ta = 6.5; + model.y_offset_calib_white_ta = 0.0; + model.y_size_calib_ta_mm = 2.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 12; + model.ld_shift_b = 24; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200; + model.adc_id = AdcId::PLUSTEK_OPTICFILM_7200; + model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200; + model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200; + + model.flags = ModelFlag::WARMUP | + ModelFlag::CUSTOM_GAMMA | + ModelFlag::DARK_CALIBRATION | + ModelFlag::SHADING_REPARK; + + model.search_lines = 200; + s_usb_devices->emplace_back(0x07b3, 0x0807, model); + + model = Genesys_Model(); model.name = "plustek-opticfilm-7200i"; model.vendor = "PLUSTEK"; diff --git a/backend/genesys/tables_motor.cpp b/backend/genesys/tables_motor.cpp index 5a6d26c8f..c90472cdc 100644 --- a/backend/genesys/tables_motor.cpp +++ b/backend/genesys/tables_motor.cpp @@ -390,6 +390,19 @@ void genesys_init_motor_tables() s_motors->push_back(std::move(motor)); + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICFILM_7200; + motor.base_ydpi = 3600; + + profile = MotorProfile(); + profile.slope = MotorSlope::create_from_steps(20000 * 2, 600 * 2, 200); + profile.step_type = StepType::HALF; + profile.motor_vref = 0; + motor.profiles.push_back(std::move(profile)); + + s_motors->push_back(std::move(motor)); + + motor = Genesys_Motor(); motor.id = MotorId::PLUSTEK_OPTICFILM_7200I; motor.base_ydpi = 3600; diff --git a/backend/genesys/tables_sensor.cpp b/backend/genesys/tables_sensor.cpp index c37c1ef61..8815eb018 100644 --- a/backend/genesys/tables_sensor.cpp +++ b/backend/genesys/tables_sensor.cpp @@ -3028,6 +3028,60 @@ void genesys_init_sensor_tables() } } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200; // gl842 + sensor.optical_res = 7200; + sensor.register_dpihw = 1200; + sensor.black_pixels = 88; // TODO + sensor.dummy_pixel = 19; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x2b00, 0x2b00, 0x2b00 }; + sensor.exposure_lperiod = 0x694e; + sensor.stagger_config = StaggerConfig{7200, 4}; + sensor.use_host_side_calib = true; + sensor.custom_regs = { + { 0x16, 0x3b }, { 0x17, 0x4b }, { 0x18, 0x10 }, { 0x19, 0x00 }, + { 0x1a, 0x24 }, { 0x1b, 0x00 }, { 0x1c, 0x40 }, { 0x1d, 0x84 }, + { 0x52, 0x09 }, { 0x53, 0x0c }, { 0x54, 0x0e }, { 0x55, 0x02 }, + { 0x56, 0x04 }, { 0x57, 0x07 }, { 0x58, 0x22 }, { 0x59, 0x69 }, { 0x5a, 0xc0 }, + { 0x70, 0x08 }, { 0x71, 0x09 }, { 0x72, 0x0b }, { 0x73, 0x0c }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x7f }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x00 }, { 0x7f, 0x01 } + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + { + struct CustomSensorSettings + { + ValueFilterAny resolutions; + ScanMethod method; + Ratio pixel_count_ratio; + int output_pixel_offset; + unsigned register_dpiset; + }; + + CustomSensorSettings custom_settings[] = { + { { 900 }, ScanMethod::TRANSPARENCY, Ratio{8, 8}, 2, 150, }, + { { 1800 }, ScanMethod::TRANSPARENCY, Ratio{4, 4}, 10, 300, }, + { { 3600 }, ScanMethod::TRANSPARENCY, Ratio{2, 2}, 10, 600, }, + { { 7200 }, ScanMethod::TRANSPARENCY, Ratio{1, 1}, 20, 1200, }, + }; + + for (const CustomSensorSettings& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.method = setting.method; + sensor.shading_resolution = setting.resolutions.values().front(); + sensor.pixel_count_ratio = setting.pixel_count_ratio; + sensor.output_pixel_offset = setting.output_pixel_offset; + sensor.register_dpiset = setting.register_dpiset; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200I; // gl843 sensor.optical_res = 7200; @@ -3576,6 +3630,20 @@ void verify_sensor_tables() } } } + + if (asic_type == AsicType::GL842) { + auto required_registers = { + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, + 0x7f + }; + for (auto address : required_registers) { + if (!sensor.custom_regs.has_reg(address)) { + throw SaneException("Required register is not present"); + } + } + } } } diff --git a/backend/genesys/test_scanner_interface.cpp b/backend/genesys/test_scanner_interface.cpp index 0c7b73809..e8af49410 100644 --- a/backend/genesys/test_scanner_interface.cpp +++ b/backend/genesys/test_scanner_interface.cpp @@ -61,6 +61,7 @@ TestScannerInterface::TestScannerInterface(Genesys_Device* dev, uint16_t vendor_ write_register(0x41, 0x00); } if (dev_->model->asic_type == AsicType::GL841 || + dev_->model->asic_type == AsicType::GL842 || dev_->model->asic_type == AsicType::GL843 || dev_->model->asic_type == AsicType::GL845 || dev_->model->asic_type == AsicType::GL846 || diff --git a/doc/descriptions/genesys.desc b/doc/descriptions/genesys.desc index 5f3e4a78f..366e280df 100644 --- a/doc/descriptions/genesys.desc +++ b/doc/descriptions/genesys.desc @@ -17,6 +17,12 @@ :status :basic :comment "Has a Primax USB ID" +:model "OpticFilm 7200" +:interface "USB" +:usbid "0x07b3" "0x0807" +:status :complete +:comment "900, 1800, 3600 and 7200 dpi resolutions are supported" + :model "OpticFilm 7200 (v2)" :interface "USB" :usbid "0x07b3" "0x0c07" diff --git a/doc/descriptions/unsupported.desc b/doc/descriptions/unsupported.desc index 5d769963f..aa392c54f 100644 --- a/doc/descriptions/unsupported.desc +++ b/doc/descriptions/unsupported.desc @@ -1738,13 +1738,6 @@ :url "http://www.plustek.de/" :url "http://www.plustek.com/" -:model "OpticFilm 7200" -:url "unsupported/plustek-opticfilm-7200.html" -:interface "USB" -:usbid "0x07b3" "0x0807" -:status :unsupported -:comment "GL842 based, maybe to be added to genesys backend" - :model "OpticPro A3U" :interface "USB" :status :unsupported