1141cc406Sopenharmony_ci/*  sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci    Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
4141cc406Sopenharmony_ci    Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci    This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci    This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci    modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci    published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci    License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci    This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci    WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci    General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci    You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci    along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci*/
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci#include "gl842_registers.h"
25141cc406Sopenharmony_ci#include "gl842.h"
26141cc406Sopenharmony_ci#include "test_settings.h"
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ci#include <string>
29141cc406Sopenharmony_ci#include <vector>
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_cinamespace genesys {
32141cc406Sopenharmony_cinamespace gl842 {
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_cistatic void gl842_init_registers(Genesys_Device& dev)
35141cc406Sopenharmony_ci{
36141cc406Sopenharmony_ci    // Within this function SENSOR_DEF marker documents that a register is part
37141cc406Sopenharmony_ci    // of the sensors definition and the actual value is set in
38141cc406Sopenharmony_ci    // gl842_setup_sensor().
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci    DBG_HELPER(dbg);
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci    dev.reg.clear();
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
45141cc406Sopenharmony_ci        dev.reg.init_reg(0x01, 0x00);
46141cc406Sopenharmony_ci        dev.reg.init_reg(0x02, 0x78);
47141cc406Sopenharmony_ci        dev.reg.init_reg(0x03, 0xbf);
48141cc406Sopenharmony_ci        dev.reg.init_reg(0x04, 0x22);
49141cc406Sopenharmony_ci        dev.reg.init_reg(0x05, 0x48);
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci        dev.reg.init_reg(0x06, 0xb8);
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci        dev.reg.init_reg(0x07, 0x00);
54141cc406Sopenharmony_ci        dev.reg.init_reg(0x08, 0x00);
55141cc406Sopenharmony_ci        dev.reg.init_reg(0x09, 0x00);
56141cc406Sopenharmony_ci        dev.reg.init_reg(0x0a, 0x00);
57141cc406Sopenharmony_ci        dev.reg.init_reg(0x0d, 0x01);
58141cc406Sopenharmony_ci    } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
59141cc406Sopenharmony_ci        dev.reg.init_reg(0x01, 0x82);
60141cc406Sopenharmony_ci        dev.reg.init_reg(0x02, 0x10);
61141cc406Sopenharmony_ci        dev.reg.init_reg(0x03, 0x60);
62141cc406Sopenharmony_ci        dev.reg.init_reg(0x04, 0x10);
63141cc406Sopenharmony_ci        dev.reg.init_reg(0x05, 0x8c);
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci        dev.reg.init_reg(0x06, 0x18);
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci        //dev.reg.init_reg(0x07, 0x00);
68141cc406Sopenharmony_ci        dev.reg.init_reg(0x08, 0x00);
69141cc406Sopenharmony_ci        dev.reg.init_reg(0x09, 0x21);
70141cc406Sopenharmony_ci        dev.reg.init_reg(0x0a, 0x00);
71141cc406Sopenharmony_ci        dev.reg.init_reg(0x0d, 0x00);
72141cc406Sopenharmony_ci    }
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci    dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
75141cc406Sopenharmony_ci    dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
76141cc406Sopenharmony_ci    dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
77141cc406Sopenharmony_ci    dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
78141cc406Sopenharmony_ci    dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
79141cc406Sopenharmony_ci    dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci    // CCD signal settings.
82141cc406Sopenharmony_ci    dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF
83141cc406Sopenharmony_ci    dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF
84141cc406Sopenharmony_ci    dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci    // EXPDMY[0:7]: Exposure time of dummy lines.
87141cc406Sopenharmony_ci    dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci    // Various CCD clock settings.
90141cc406Sopenharmony_ci    dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
91141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
92141cc406Sopenharmony_ci        dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
93141cc406Sopenharmony_ci    }
94141cc406Sopenharmony_ci    dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
95141cc406Sopenharmony_ci    dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
96141cc406Sopenharmony_ci    dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
99141cc406Sopenharmony_ci        dev.reg.init_reg(0x1f, 0x01);
100141cc406Sopenharmony_ci        dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
101141cc406Sopenharmony_ci    } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
102141cc406Sopenharmony_ci        dev.reg.init_reg(0x1f, 0x02);
103141cc406Sopenharmony_ci        dev.reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition
104141cc406Sopenharmony_ci    }
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci    dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
107141cc406Sopenharmony_ci    dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup
108141cc406Sopenharmony_ci    dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup
109141cc406Sopenharmony_ci    dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
110141cc406Sopenharmony_ci    dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
111141cc406Sopenharmony_ci    dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
112141cc406Sopenharmony_ci    dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci    dev.reg.init_reg(0x29, 0xff); // LAMPPWM
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci    dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup
117141cc406Sopenharmony_ci    dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_ci    dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
120141cc406Sopenharmony_ci    dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci    dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
123141cc406Sopenharmony_ci    dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup
124141cc406Sopenharmony_ci    dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup
125141cc406Sopenharmony_ci    dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci    dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF
128141cc406Sopenharmony_ci    dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
129141cc406Sopenharmony_ci    dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
130141cc406Sopenharmony_ci    dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
131141cc406Sopenharmony_ci    dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
132141cc406Sopenharmony_ci    dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
133141cc406Sopenharmony_ci    dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
134141cc406Sopenharmony_ci    dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
135141cc406Sopenharmony_ci    dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci    dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF
138141cc406Sopenharmony_ci    dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF
139141cc406Sopenharmony_ci    dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF
140141cc406Sopenharmony_ci    dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF
141141cc406Sopenharmony_ci    dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF
142141cc406Sopenharmony_ci    dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF
143141cc406Sopenharmony_ci    dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF
144141cc406Sopenharmony_ci    dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
145141cc406Sopenharmony_ci    dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
148141cc406Sopenharmony_ci        dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
149141cc406Sopenharmony_ci    } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
150141cc406Sopenharmony_ci        dev.reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
151141cc406Sopenharmony_ci        dev.reg.init_reg(0x5d, 0x20);
152141cc406Sopenharmony_ci    }
153141cc406Sopenharmony_ci    dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci    dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
156141cc406Sopenharmony_ci    dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
157141cc406Sopenharmony_ci    dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
158141cc406Sopenharmony_ci    dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
159141cc406Sopenharmony_ci    dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
160141cc406Sopenharmony_ci    dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
163141cc406Sopenharmony_ci        dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: partially overwritten during motor setup
164141cc406Sopenharmony_ci        dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: partially overwritten during motor setup
165141cc406Sopenharmony_ci    } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
166141cc406Sopenharmony_ci        dev.reg.init_reg(0x66, 0x00); // PHFREQ
167141cc406Sopenharmony_ci        dev.reg.init_reg(0x67, 0x40); // STEPSEL, MTRPWM: partially overwritten during motor setup
168141cc406Sopenharmony_ci        dev.reg.init_reg(0x68, 0x40); // FSTPSEL, FASTPWM: partially overwritten during motor setup
169141cc406Sopenharmony_ci    }
170141cc406Sopenharmony_ci    dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
171141cc406Sopenharmony_ci    dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci    // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio.
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci    dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF
176141cc406Sopenharmony_ci    dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF
177141cc406Sopenharmony_ci    dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF
178141cc406Sopenharmony_ci    dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF
179141cc406Sopenharmony_ci    dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF
180141cc406Sopenharmony_ci    dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF
181141cc406Sopenharmony_ci    dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF
182141cc406Sopenharmony_ci    dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF
183141cc406Sopenharmony_ci    dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF
184141cc406Sopenharmony_ci    dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF
185141cc406Sopenharmony_ci    dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF
186141cc406Sopenharmony_ci    dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF
187141cc406Sopenharmony_ci    dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF
188141cc406Sopenharmony_ci    dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_ci    // 0x7e - set according to gpio tables. See gl842_init_gpio.
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci    dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci    // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
195141cc406Sopenharmony_ci    // moving in various situations.
196141cc406Sopenharmony_ci    dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
199141cc406Sopenharmony_ci        dev.reg.init_reg(0x81, 0x00);
200141cc406Sopenharmony_ci        dev.reg.init_reg(0x82, 0x00);
201141cc406Sopenharmony_ci        dev.reg.init_reg(0x83, 0x00);
202141cc406Sopenharmony_ci        dev.reg.init_reg(0x84, 0x00);
203141cc406Sopenharmony_ci        dev.reg.init_reg(0x85, 0x00);
204141cc406Sopenharmony_ci        dev.reg.init_reg(0x86, 0x00);
205141cc406Sopenharmony_ci        dev.reg.init_reg(0x87, 0x00);
206141cc406Sopenharmony_ci    } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
207141cc406Sopenharmony_ci        dev.reg.init_reg(0x7e, 0x00);
208141cc406Sopenharmony_ci        dev.reg.init_reg(0x81, 0x00);
209141cc406Sopenharmony_ci        dev.reg.init_reg(0x82, 0x0f);
210141cc406Sopenharmony_ci        dev.reg.init_reg(0x83, 0x00);
211141cc406Sopenharmony_ci        dev.reg.init_reg(0x84, 0x0e);
212141cc406Sopenharmony_ci        dev.reg.init_reg(0x85, 0x00);
213141cc406Sopenharmony_ci        dev.reg.init_reg(0x86, 0x0d);
214141cc406Sopenharmony_ci        dev.reg.init_reg(0x87, 0x00);
215141cc406Sopenharmony_ci        dev.reg.init_reg(0x88, 0x00);
216141cc406Sopenharmony_ci        dev.reg.init_reg(0x89, 0x00);
217141cc406Sopenharmony_ci    }
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci    const auto& sensor = sanei_genesys_find_sensor_any(&dev);
220141cc406Sopenharmony_ci    sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci    scanner_setup_sensor(dev, sensor, dev.reg);
223141cc406Sopenharmony_ci}
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci// Set values of analog frontend
226141cc406Sopenharmony_civoid CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
227141cc406Sopenharmony_ci                             std::uint8_t set) const
228141cc406Sopenharmony_ci{
229141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
230141cc406Sopenharmony_ci                               set == AFE_SET ? "set" :
231141cc406Sopenharmony_ci                               set == AFE_POWER_SAVE ? "powersave" : "huh?");
232141cc406Sopenharmony_ci    (void) sensor;
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci    if (set == AFE_INIT) {
235141cc406Sopenharmony_ci        dev->frontend = dev->frontend_initial;
236141cc406Sopenharmony_ci    }
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci    // check analog frontend type
239141cc406Sopenharmony_ci    // FIXME: looks like we write to that register with initial data
240141cc406Sopenharmony_ci    std::uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
241141cc406Sopenharmony_ci    if (fe_type == 2 || dev->model->model_id == ModelId::CANON_LIDE_90) {
242141cc406Sopenharmony_ci        for (const auto& reg : dev->frontend.regs) {
243141cc406Sopenharmony_ci            dev->interface->write_fe_register(reg.address, reg.value);
244141cc406Sopenharmony_ci        }
245141cc406Sopenharmony_ci        return;
246141cc406Sopenharmony_ci    }
247141cc406Sopenharmony_ci    if (fe_type != 0) {
248141cc406Sopenharmony_ci        throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
249141cc406Sopenharmony_ci    }
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci    for (unsigned i = 1; i <= 3; i++) {
252141cc406Sopenharmony_ci        dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
253141cc406Sopenharmony_ci    }
254141cc406Sopenharmony_ci    for (const auto& reg : sensor.custom_fe_regs) {
255141cc406Sopenharmony_ci        dev->interface->write_fe_register(reg.address, reg.value);
256141cc406Sopenharmony_ci    }
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci    for (unsigned i = 0; i < 3; i++) {
259141cc406Sopenharmony_ci        dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
260141cc406Sopenharmony_ci    }
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci    for (unsigned i = 0; i < 3; i++) {
263141cc406Sopenharmony_ci        dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
264141cc406Sopenharmony_ci    }
265141cc406Sopenharmony_ci}
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_cistatic void gl842_init_motor_regs_scan(Genesys_Device* dev,
268141cc406Sopenharmony_ci                                       const Genesys_Sensor& sensor,
269141cc406Sopenharmony_ci                                       const ScanSession& session,
270141cc406Sopenharmony_ci                                       Genesys_Register_Set* reg,
271141cc406Sopenharmony_ci                                       const MotorProfile& motor_profile,
272141cc406Sopenharmony_ci                                       unsigned int exposure,
273141cc406Sopenharmony_ci                                       unsigned scan_yres,
274141cc406Sopenharmony_ci                                       unsigned int scan_lines,
275141cc406Sopenharmony_ci                                       unsigned int scan_dummy,
276141cc406Sopenharmony_ci                                       unsigned int feed_steps,
277141cc406Sopenharmony_ci                                       ScanFlag flags)
278141cc406Sopenharmony_ci{
279141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
280141cc406Sopenharmony_ci                         "feed_steps=%d, flags=%x",
281141cc406Sopenharmony_ci                    exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
282141cc406Sopenharmony_ci                    scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci    unsigned step_multiplier = 2;
285141cc406Sopenharmony_ci    bool use_fast_fed = false;
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci    if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
288141cc406Sopenharmony_ci        use_fast_fed = true;
289141cc406Sopenharmony_ci    }
290141cc406Sopenharmony_ci    if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
291141cc406Sopenharmony_ci        use_fast_fed = false;
292141cc406Sopenharmony_ci    }
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci    reg->set24(REG_LINCNT, scan_lines);
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci    reg->set8(REG_0x02, 0);
297141cc406Sopenharmony_ci    sanei_genesys_set_motor_power(*reg, true);
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci    std::uint8_t reg02 = reg->get8(REG_0x02);
300141cc406Sopenharmony_ci    if (use_fast_fed) {
301141cc406Sopenharmony_ci        reg02 |= REG_0x02_FASTFED;
302141cc406Sopenharmony_ci    } else {
303141cc406Sopenharmony_ci        reg02 &= ~REG_0x02_FASTFED;
304141cc406Sopenharmony_ci    }
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci    // in case of automatic go home, move until home sensor
307141cc406Sopenharmony_ci    if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
308141cc406Sopenharmony_ci        reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
309141cc406Sopenharmony_ci    }
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci    // disable backtracking if needed
312141cc406Sopenharmony_ci    if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
313141cc406Sopenharmony_ci        (scan_yres >= 2400) ||
314141cc406Sopenharmony_ci        (scan_yres >= sensor.full_resolution))
315141cc406Sopenharmony_ci    {
316141cc406Sopenharmony_ci        reg02 |= REG_0x02_ACDCDIS;
317141cc406Sopenharmony_ci    }
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci    if (has_flag(flags, ScanFlag::REVERSE)) {
320141cc406Sopenharmony_ci        reg02 |= REG_0x02_MTRREV;
321141cc406Sopenharmony_ci    } else {
322141cc406Sopenharmony_ci        reg02 &= ~REG_0x02_MTRREV;
323141cc406Sopenharmony_ci    }
324141cc406Sopenharmony_ci    reg->set8(REG_0x02, reg02);
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci    // scan and backtracking slope table
327141cc406Sopenharmony_ci    auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
328141cc406Sopenharmony_ci                                         step_multiplier, motor_profile);
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci    scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
331141cc406Sopenharmony_ci    scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
332141cc406Sopenharmony_ci    scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ci    reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
335141cc406Sopenharmony_ci    reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
336141cc406Sopenharmony_ci    reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci    // fast table
339141cc406Sopenharmony_ci    const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
340141cc406Sopenharmony_ci    if (fast_profile == nullptr) {
341141cc406Sopenharmony_ci        fast_profile = &motor_profile;
342141cc406Sopenharmony_ci    }
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci    auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
345141cc406Sopenharmony_ci                                                 *fast_profile);
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci    scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
348141cc406Sopenharmony_ci    scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
349141cc406Sopenharmony_ci
350141cc406Sopenharmony_ci    reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
351141cc406Sopenharmony_ci
352141cc406Sopenharmony_ci    if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
353141cc406Sopenharmony_ci        std::uint8_t vref = 0;
354141cc406Sopenharmony_ci        vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
355141cc406Sopenharmony_ci        vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
356141cc406Sopenharmony_ci        vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
357141cc406Sopenharmony_ci        vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
358141cc406Sopenharmony_ci        reg->set8(REG_0x80, vref);
359141cc406Sopenharmony_ci    }
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci    // subtract acceleration distance from feedl
362141cc406Sopenharmony_ci    unsigned feedl = feed_steps;
363141cc406Sopenharmony_ci    feedl <<= static_cast<unsigned>(motor_profile.step_type);
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci    unsigned dist = scan_table.table.size() / step_multiplier;
366141cc406Sopenharmony_ci
367141cc406Sopenharmony_ci    if (use_fast_fed) {
368141cc406Sopenharmony_ci        dist += (fast_table.table.size() / step_multiplier) * 2;
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci    // make sure when don't insane value : XXX STEF XXX in this case we should
372141cc406Sopenharmony_ci    // fall back to single table move
373141cc406Sopenharmony_ci    if (dist < feedl) {
374141cc406Sopenharmony_ci        feedl -= dist;
375141cc406Sopenharmony_ci    } else {
376141cc406Sopenharmony_ci        feedl = 1;
377141cc406Sopenharmony_ci    }
378141cc406Sopenharmony_ci
379141cc406Sopenharmony_ci    reg->set24(REG_FEEDL, feedl);
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci    // doesn't seem to matter that much
382141cc406Sopenharmony_ci    std::uint32_t z1, z2;
383141cc406Sopenharmony_ci    sanei_genesys_calculate_zmod(use_fast_fed,
384141cc406Sopenharmony_ci                                 exposure,
385141cc406Sopenharmony_ci                                 scan_table.table,
386141cc406Sopenharmony_ci                                 scan_table.table.size() / step_multiplier,
387141cc406Sopenharmony_ci                                 feedl,
388141cc406Sopenharmony_ci                                 scan_table.table.size() / step_multiplier,
389141cc406Sopenharmony_ci                                 &z1,
390141cc406Sopenharmony_ci                                 &z2);
391141cc406Sopenharmony_ci    if (scan_yres > 600) {
392141cc406Sopenharmony_ci        z1 = 0;
393141cc406Sopenharmony_ci        z2 = 0;
394141cc406Sopenharmony_ci    }
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci    reg->set24(REG_Z1MOD, z1);
397141cc406Sopenharmony_ci    reg->set24(REG_Z2MOD, z2);
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci    reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci    reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL,
402141cc406Sopenharmony_ci                   REG_0x67_STEPSEL);
403141cc406Sopenharmony_ci    reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL,
404141cc406Sopenharmony_ci                   REG_0x68_FSTPSEL);
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci    // steps for STOP table
407141cc406Sopenharmony_ci    reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
408141cc406Sopenharmony_ci}
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_cistatic void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
411141cc406Sopenharmony_ci                                         Genesys_Register_Set* reg, unsigned int exposure,
412141cc406Sopenharmony_ci                                         const ScanSession& session)
413141cc406Sopenharmony_ci{
414141cc406Sopenharmony_ci    DBG_HELPER(dbg);
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci    scanner_setup_sensor(*dev, sensor, *reg);
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci    dev->cmd_set->set_fe(dev, sensor, AFE_SET);
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci    // enable shading
421141cc406Sopenharmony_ci    regs_set_optical_off(dev->model->asic_type, *reg);
422141cc406Sopenharmony_ci    if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
423141cc406Sopenharmony_ci        has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
424141cc406Sopenharmony_ci        session.use_host_side_calib)
425141cc406Sopenharmony_ci    {
426141cc406Sopenharmony_ci        reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci    } else {
429141cc406Sopenharmony_ci        reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
430141cc406Sopenharmony_ci    }
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci    bool use_shdarea = true;
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci    if (use_shdarea) {
435141cc406Sopenharmony_ci        reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
436141cc406Sopenharmony_ci    } else {
437141cc406Sopenharmony_ci        reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
438141cc406Sopenharmony_ci    }
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::CANON_8600F) {
441141cc406Sopenharmony_ci        reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
442141cc406Sopenharmony_ci    } else {
443141cc406Sopenharmony_ci        reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
444141cc406Sopenharmony_ci    }
445141cc406Sopenharmony_ci
446141cc406Sopenharmony_ci    // FIXME: we probably don't need to set exposure to registers at this point. It was this way
447141cc406Sopenharmony_ci    // before a refactor.
448141cc406Sopenharmony_ci    sanei_genesys_set_lamp_power(dev, sensor, *reg,
449141cc406Sopenharmony_ci                                 !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
450141cc406Sopenharmony_ci
451141cc406Sopenharmony_ci    // select XPA
452141cc406Sopenharmony_ci    reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
453141cc406Sopenharmony_ci    if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
454141cc406Sopenharmony_ci        reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
455141cc406Sopenharmony_ci    }
456141cc406Sopenharmony_ci    reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci    // BW threshold
459141cc406Sopenharmony_ci    reg->set8(REG_0x2E, 0x7f);
460141cc406Sopenharmony_ci    reg->set8(REG_0x2F, 0x7f);
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci    // monochrome / color scan parameters
463141cc406Sopenharmony_ci    std::uint8_t reg04 = reg->get8(REG_0x04);
464141cc406Sopenharmony_ci    reg04 = reg04 & REG_0x04_FESET;
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci    switch (session.params.depth) {
467141cc406Sopenharmony_ci        case 8:
468141cc406Sopenharmony_ci            break;
469141cc406Sopenharmony_ci        case 16:
470141cc406Sopenharmony_ci            reg04 |= REG_0x04_BITSET;
471141cc406Sopenharmony_ci            break;
472141cc406Sopenharmony_ci    }
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci    if (session.params.channels == 1) {
475141cc406Sopenharmony_ci        switch (session.params.color_filter) {
476141cc406Sopenharmony_ci            case ColorFilter::RED: reg04 |= 0x14; break;
477141cc406Sopenharmony_ci            case ColorFilter::BLUE: reg04 |= 0x1c; break;
478141cc406Sopenharmony_ci            case ColorFilter::GREEN: reg04 |= 0x18; break;
479141cc406Sopenharmony_ci            default:
480141cc406Sopenharmony_ci                break; // should not happen
481141cc406Sopenharmony_ci        }
482141cc406Sopenharmony_ci    } else {
483141cc406Sopenharmony_ci        switch (dev->frontend.layout.type) {
484141cc406Sopenharmony_ci            case FrontendType::WOLFSON:
485141cc406Sopenharmony_ci                // pixel by pixel
486141cc406Sopenharmony_ci                reg04 |= 0x10;
487141cc406Sopenharmony_ci                break;
488141cc406Sopenharmony_ci            case FrontendType::ANALOG_DEVICES:
489141cc406Sopenharmony_ci                // slow color pixel by pixel
490141cc406Sopenharmony_ci                reg04 |= 0x20;
491141cc406Sopenharmony_ci                break;
492141cc406Sopenharmony_ci            default:
493141cc406Sopenharmony_ci                throw SaneException("Invalid frontend type %d",
494141cc406Sopenharmony_ci                                    static_cast<unsigned>(dev->frontend.layout.type));
495141cc406Sopenharmony_ci        }
496141cc406Sopenharmony_ci    }
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci    reg->set8(REG_0x04, reg04);
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci    const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
501141cc406Sopenharmony_ci                                                         session.params.channels,
502141cc406Sopenharmony_ci                                                         session.params.scan_method);
503141cc406Sopenharmony_ci    sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci    if (should_enable_gamma(session, sensor)) {
506141cc406Sopenharmony_ci        reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
507141cc406Sopenharmony_ci    } else {
508141cc406Sopenharmony_ci        reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
509141cc406Sopenharmony_ci    }
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci    reg->set16(REG_DPISET, sensor.register_dpiset);
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci    reg->set16(REG_STRPIXEL, session.pixel_startx);
514141cc406Sopenharmony_ci    reg->set16(REG_ENDPIXEL, session.pixel_endx);
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci    if (dev->model->is_cis) {
517141cc406Sopenharmony_ci        reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels);
518141cc406Sopenharmony_ci    } else {
519141cc406Sopenharmony_ci        reg->set24(REG_MAXWD, session.output_line_bytes_raw);
520141cc406Sopenharmony_ci    }
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci    unsigned tgtime = exposure / 65536 + 1;
523141cc406Sopenharmony_ci    reg->set16(REG_LPERIOD, exposure / tgtime);
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci    reg->set8(REG_DUMMY, sensor.dummy_pixel);
526141cc406Sopenharmony_ci}
527141cc406Sopenharmony_ci
528141cc406Sopenharmony_civoid CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
529141cc406Sopenharmony_ci                                                 Genesys_Register_Set* reg,
530141cc406Sopenharmony_ci                                                 const ScanSession& session) const
531141cc406Sopenharmony_ci{
532141cc406Sopenharmony_ci    DBG_HELPER(dbg);
533141cc406Sopenharmony_ci    session.assert_computed();
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci    // we enable true gray for cis scanners only, and just when doing scan since color calibration
536141cc406Sopenharmony_ci    // is OK for this mode
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci    int dummy = 0;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci  /* slope_dpi */
541141cc406Sopenharmony_ci  /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */
542141cc406Sopenharmony_ci    int slope_dpi = 0;
543141cc406Sopenharmony_ci    if (dev->model->is_cis) {
544141cc406Sopenharmony_ci        slope_dpi = session.params.yres * session.params.channels;
545141cc406Sopenharmony_ci    } else {
546141cc406Sopenharmony_ci        slope_dpi = session.params.yres;
547141cc406Sopenharmony_ci    }
548141cc406Sopenharmony_ci    slope_dpi = slope_dpi * (1 + dummy);
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci    int exposure = sensor.exposure_lperiod;
551141cc406Sopenharmony_ci    if (exposure < 0) {
552141cc406Sopenharmony_ci        throw std::runtime_error("Exposure not defined in sensor definition");
553141cc406Sopenharmony_ci    }
554141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::CANON_LIDE_90) {
555141cc406Sopenharmony_ci        exposure *= 2;
556141cc406Sopenharmony_ci    }
557141cc406Sopenharmony_ci    const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci    // now _LOGICAL_ optical values used are known, setup registers
560141cc406Sopenharmony_ci    gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session);
561141cc406Sopenharmony_ci    gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
562141cc406Sopenharmony_ci                               session.optical_line_count, dummy, session.params.starty,
563141cc406Sopenharmony_ci                               session.params.flags);
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci    setup_image_pipeline(*dev, session);
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci    dev->read_active = true;
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci    dev->session = session;
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci    dev->total_bytes_read = 0;
572141cc406Sopenharmony_ci    dev->total_bytes_to_read = (size_t)session.output_line_bytes_requested * (size_t)session.params.lines;
573141cc406Sopenharmony_ci}
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ciScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev,
576141cc406Sopenharmony_ci                                                    const Genesys_Sensor& sensor,
577141cc406Sopenharmony_ci                                                    const Genesys_Settings& settings) const
578141cc406Sopenharmony_ci{
579141cc406Sopenharmony_ci    DBG_HELPER(dbg);
580141cc406Sopenharmony_ci    debug_dump(DBG_info, settings);
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci    ScanFlag flags = ScanFlag::NONE;
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_ci    float move = 0.0f;
585141cc406Sopenharmony_ci    if (settings.scan_method == ScanMethod::TRANSPARENCY ||
586141cc406Sopenharmony_ci        settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
587141cc406Sopenharmony_ci    {
588141cc406Sopenharmony_ci        // note: scanner_move_to_ta() function has already been called and the sensor is at the
589141cc406Sopenharmony_ci        // transparency adapter
590141cc406Sopenharmony_ci        if (!dev->ignore_offsets) {
591141cc406Sopenharmony_ci            move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
592141cc406Sopenharmony_ci        }
593141cc406Sopenharmony_ci        flags |= ScanFlag::USE_XPA;
594141cc406Sopenharmony_ci    } else {
595141cc406Sopenharmony_ci        if (!dev->ignore_offsets) {
596141cc406Sopenharmony_ci            move = dev->model->y_offset;
597141cc406Sopenharmony_ci        }
598141cc406Sopenharmony_ci    }
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci    move += settings.tl_y;
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci    int move_dpi = dev->motor.base_ydpi;
603141cc406Sopenharmony_ci    move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci    float start = 0.0f;
606141cc406Sopenharmony_ci    if (settings.scan_method==ScanMethod::TRANSPARENCY ||
607141cc406Sopenharmony_ci        settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
608141cc406Sopenharmony_ci    {
609141cc406Sopenharmony_ci        start = dev->model->x_offset_ta;
610141cc406Sopenharmony_ci    } else {
611141cc406Sopenharmony_ci        start = dev->model->x_offset;
612141cc406Sopenharmony_ci    }
613141cc406Sopenharmony_ci    start = start + settings.tl_x;
614141cc406Sopenharmony_ci
615141cc406Sopenharmony_ci    start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci    ScanSession session;
618141cc406Sopenharmony_ci    session.params.xres = settings.xres;
619141cc406Sopenharmony_ci    session.params.yres = settings.yres;
620141cc406Sopenharmony_ci    session.params.startx = static_cast<unsigned>(start);
621141cc406Sopenharmony_ci    session.params.starty = static_cast<unsigned>(move);
622141cc406Sopenharmony_ci    session.params.pixels = settings.pixels;
623141cc406Sopenharmony_ci    session.params.requested_pixels = settings.requested_pixels;
624141cc406Sopenharmony_ci    session.params.lines = settings.lines;
625141cc406Sopenharmony_ci    session.params.depth = settings.depth;
626141cc406Sopenharmony_ci    session.params.channels = settings.get_channels();
627141cc406Sopenharmony_ci    session.params.scan_method = settings.scan_method;
628141cc406Sopenharmony_ci    session.params.scan_mode = settings.scan_mode;
629141cc406Sopenharmony_ci    session.params.color_filter = settings.color_filter;
630141cc406Sopenharmony_ci    session.params.contrast_adjustment = settings.contrast;
631141cc406Sopenharmony_ci    session.params.brightness_adjustment = settings.brightness;
632141cc406Sopenharmony_ci    session.params.flags = flags;
633141cc406Sopenharmony_ci    compute_session(dev, session, sensor);
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci    return session;
636141cc406Sopenharmony_ci}
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_civoid CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const
639141cc406Sopenharmony_ci{
640141cc406Sopenharmony_ci    (void) dev;
641141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "enable = %d", enable);
642141cc406Sopenharmony_ci}
643141cc406Sopenharmony_ci
644141cc406Sopenharmony_civoid CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
645141cc406Sopenharmony_ci{
646141cc406Sopenharmony_ci    (void) dev;
647141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "delay = %d", delay);
648141cc406Sopenharmony_ci}
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_civoid CommandSetGl842::eject_document(Genesys_Device* dev) const
651141cc406Sopenharmony_ci{
652141cc406Sopenharmony_ci    (void) dev;
653141cc406Sopenharmony_ci    DBG_HELPER(dbg);
654141cc406Sopenharmony_ci}
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_civoid CommandSetGl842::load_document(Genesys_Device* dev) const
658141cc406Sopenharmony_ci{
659141cc406Sopenharmony_ci    DBG_HELPER(dbg);
660141cc406Sopenharmony_ci    (void) dev;
661141cc406Sopenharmony_ci}
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_civoid CommandSetGl842::detect_document_end(Genesys_Device* dev) const
664141cc406Sopenharmony_ci{
665141cc406Sopenharmony_ci    DBG_HELPER(dbg);
666141cc406Sopenharmony_ci    (void) dev;
667141cc406Sopenharmony_ci    throw SaneException(SANE_STATUS_UNSUPPORTED);
668141cc406Sopenharmony_ci}
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci// Send the low-level scan command
671141cc406Sopenharmony_civoid CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
672141cc406Sopenharmony_ci                                 Genesys_Register_Set* reg, bool start_motor) const
673141cc406Sopenharmony_ci{
674141cc406Sopenharmony_ci    DBG_HELPER(dbg);
675141cc406Sopenharmony_ci    (void) sensor;
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci    if (reg->state.is_xpa_on && reg->state.is_lamp_on &&
678141cc406Sopenharmony_ci        !has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP))
679141cc406Sopenharmony_ci    {
680141cc406Sopenharmony_ci        dev->cmd_set->set_xpa_lamp_power(*dev, true);
681141cc406Sopenharmony_ci    }
682141cc406Sopenharmony_ci    if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) {
683141cc406Sopenharmony_ci        dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
684141cc406Sopenharmony_ci    }
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::CANON_LIDE_90) {
687141cc406Sopenharmony_ci        if (has_flag(dev->session.params.flags, ScanFlag::REVERSE)) {
688141cc406Sopenharmony_ci            dev->interface->write_register(REG_0x6B, 0x01);
689141cc406Sopenharmony_ci            dev->interface->write_register(REG_0x6C, 0x02);
690141cc406Sopenharmony_ci        } else {
691141cc406Sopenharmony_ci            dev->interface->write_register(REG_0x6B, 0x03);
692141cc406Sopenharmony_ci            switch (dev->session.params.xres) {
693141cc406Sopenharmony_ci                case 150: dev->interface->write_register(REG_0x6C, 0x74); break;
694141cc406Sopenharmony_ci                case 300: dev->interface->write_register(REG_0x6C, 0x38); break;
695141cc406Sopenharmony_ci                case 600: dev->interface->write_register(REG_0x6C, 0x1c); break;
696141cc406Sopenharmony_ci                case 1200: dev->interface->write_register(REG_0x6C, 0x2c); break;
697141cc406Sopenharmony_ci                case 2400: dev->interface->write_register(REG_0x6C, 0x0c); break;
698141cc406Sopenharmony_ci                default:
699141cc406Sopenharmony_ci                    break;
700141cc406Sopenharmony_ci            }
701141cc406Sopenharmony_ci        }
702141cc406Sopenharmony_ci        dev->interface->sleep_ms(100);
703141cc406Sopenharmony_ci    }
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci    scanner_clear_scan_and_feed_counts(*dev);
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ci    // enable scan and motor
708141cc406Sopenharmony_ci    std::uint8_t val = dev->interface->read_register(REG_0x01);
709141cc406Sopenharmony_ci    val |= REG_0x01_SCAN;
710141cc406Sopenharmony_ci    dev->interface->write_register(REG_0x01, val);
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci    scanner_start_action(*dev, start_motor);
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci    switch (reg->state.motor_mode) {
715141cc406Sopenharmony_ci        case MotorMode::PRIMARY: {
716141cc406Sopenharmony_ci            if (reg->state.is_motor_on) {
717141cc406Sopenharmony_ci                dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
718141cc406Sopenharmony_ci            }
719141cc406Sopenharmony_ci            break;
720141cc406Sopenharmony_ci        }
721141cc406Sopenharmony_ci        case MotorMode::PRIMARY_AND_SECONDARY: {
722141cc406Sopenharmony_ci            if (reg->state.is_motor_on) {
723141cc406Sopenharmony_ci                dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
724141cc406Sopenharmony_ci                dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
725141cc406Sopenharmony_ci            }
726141cc406Sopenharmony_ci            break;
727141cc406Sopenharmony_ci        }
728141cc406Sopenharmony_ci        case MotorMode::SECONDARY: {
729141cc406Sopenharmony_ci            if (reg->state.is_motor_on) {
730141cc406Sopenharmony_ci                dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
731141cc406Sopenharmony_ci            }
732141cc406Sopenharmony_ci            break;
733141cc406Sopenharmony_ci        }
734141cc406Sopenharmony_ci    }
735141cc406Sopenharmony_ci}
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_civoid CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
738141cc406Sopenharmony_ci                               bool check_stop) const
739141cc406Sopenharmony_ci{
740141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
741141cc406Sopenharmony_ci
742141cc406Sopenharmony_ci    if (reg->state.is_xpa_on) {
743141cc406Sopenharmony_ci        dev->cmd_set->set_xpa_lamp_power(*dev, false);
744141cc406Sopenharmony_ci    }
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci    if (!dev->model->is_sheetfed) {
747141cc406Sopenharmony_ci        scanner_stop_action(*dev);
748141cc406Sopenharmony_ci    }
749141cc406Sopenharmony_ci}
750141cc406Sopenharmony_ci
751141cc406Sopenharmony_civoid CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const
752141cc406Sopenharmony_ci{
753141cc406Sopenharmony_ci    scanner_move_back_home(*dev, wait_until_home);
754141cc406Sopenharmony_ci}
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_civoid CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
757141cc406Sopenharmony_ci                                            Genesys_Register_Set& regs) const
758141cc406Sopenharmony_ci{
759141cc406Sopenharmony_ci    DBG_HELPER(dbg);
760141cc406Sopenharmony_ci    int move;
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci    float calib_size_mm = 0;
763141cc406Sopenharmony_ci    if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
764141cc406Sopenharmony_ci        dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
765141cc406Sopenharmony_ci    {
766141cc406Sopenharmony_ci        calib_size_mm = dev->model->y_size_calib_ta_mm;
767141cc406Sopenharmony_ci    } else {
768141cc406Sopenharmony_ci        calib_size_mm = dev->model->y_size_calib_mm;
769141cc406Sopenharmony_ci    }
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci    unsigned resolution = sensor.shading_resolution;
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci    unsigned channels = 3;
774141cc406Sopenharmony_ci    const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
775141cc406Sopenharmony_ci                                                         dev->settings.scan_method);
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci    unsigned calib_pixels = 0;
778141cc406Sopenharmony_ci    unsigned calib_pixels_offset = 0;
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci    if (should_calibrate_only_active_area(*dev, dev->settings)) {
781141cc406Sopenharmony_ci        float offset = dev->model->x_offset_ta;
782141cc406Sopenharmony_ci        // FIXME: we should use resolution here
783141cc406Sopenharmony_ci        offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci        float size = dev->model->x_size_ta;
786141cc406Sopenharmony_ci        size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci        calib_pixels_offset = static_cast<std::size_t>(offset);
789141cc406Sopenharmony_ci        calib_pixels = static_cast<std::size_t>(size);
790141cc406Sopenharmony_ci    } else {
791141cc406Sopenharmony_ci        calib_pixels_offset = 0;
792141cc406Sopenharmony_ci        calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
793141cc406Sopenharmony_ci    }
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci    ScanFlag flags = ScanFlag::DISABLE_SHADING |
796141cc406Sopenharmony_ci                     ScanFlag::DISABLE_GAMMA |
797141cc406Sopenharmony_ci                     ScanFlag::DISABLE_BUFFER_FULL_MOVE;
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci    if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
800141cc406Sopenharmony_ci        dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
801141cc406Sopenharmony_ci    {
802141cc406Sopenharmony_ci        // note: scanner_move_to_ta() function has already been called and the sensor is at the
803141cc406Sopenharmony_ci        // transparency adapter
804141cc406Sopenharmony_ci        move = static_cast<int>(dev->model->y_offset_calib_white_ta -
805141cc406Sopenharmony_ci                                dev->model->y_offset_sensor_to_ta);
806141cc406Sopenharmony_ci        flags |= ScanFlag::USE_XPA;
807141cc406Sopenharmony_ci    } else {
808141cc406Sopenharmony_ci        move = static_cast<int>(dev->model->y_offset_calib_white);
809141cc406Sopenharmony_ci    }
810141cc406Sopenharmony_ci
811141cc406Sopenharmony_ci    move = static_cast<int>((move * resolution) / MM_PER_INCH);
812141cc406Sopenharmony_ci    unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci    ScanSession session;
815141cc406Sopenharmony_ci    session.params.xres = resolution;
816141cc406Sopenharmony_ci    session.params.yres = resolution;
817141cc406Sopenharmony_ci    session.params.startx = calib_pixels_offset;
818141cc406Sopenharmony_ci    session.params.starty = move;
819141cc406Sopenharmony_ci    session.params.pixels = calib_pixels;
820141cc406Sopenharmony_ci    session.params.lines = calib_lines;
821141cc406Sopenharmony_ci    session.params.depth = 16;
822141cc406Sopenharmony_ci    session.params.channels = channels;
823141cc406Sopenharmony_ci    session.params.scan_method = dev->settings.scan_method;
824141cc406Sopenharmony_ci    session.params.scan_mode = dev->settings.scan_mode;
825141cc406Sopenharmony_ci    session.params.color_filter = dev->settings.color_filter;
826141cc406Sopenharmony_ci    session.params.contrast_adjustment = dev->settings.contrast;
827141cc406Sopenharmony_ci    session.params.brightness_adjustment = dev->settings.brightness;
828141cc406Sopenharmony_ci    session.params.flags = flags;
829141cc406Sopenharmony_ci    compute_session(dev, session, calib_sensor);
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci    init_regs_for_scan_session(dev, calib_sensor, &regs, session);
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci    dev->calib_session = session;
834141cc406Sopenharmony_ci}
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_civoid CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
837141cc406Sopenharmony_ci{
838141cc406Sopenharmony_ci    DBG_HELPER(dbg);
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200)
841141cc406Sopenharmony_ci        return; // No gamma on this model
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci    unsigned size = 256;
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci    std::vector<std::uint8_t> gamma(size * 2 * 3);
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci    std::vector<std::uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
848141cc406Sopenharmony_ci    std::vector<std::uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
849141cc406Sopenharmony_ci    std::vector<std::uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_ci    // copy sensor specific's gamma tables
852141cc406Sopenharmony_ci    for (unsigned i = 0; i < size; i++) {
853141cc406Sopenharmony_ci        gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff;
854141cc406Sopenharmony_ci        gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff;
855141cc406Sopenharmony_ci        gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff;
856141cc406Sopenharmony_ci        gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff;
857141cc406Sopenharmony_ci        gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff;
858141cc406Sopenharmony_ci        gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
859141cc406Sopenharmony_ci    }
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci    dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
862141cc406Sopenharmony_ci}
863141cc406Sopenharmony_ci
864141cc406Sopenharmony_ciSensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
865141cc406Sopenharmony_ci                                                Genesys_Register_Set& regs) const
866141cc406Sopenharmony_ci{
867141cc406Sopenharmony_ci    return scanner_led_calibration(*dev, sensor, regs);
868141cc406Sopenharmony_ci}
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_civoid CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
871141cc406Sopenharmony_ci                                         Genesys_Register_Set& regs) const
872141cc406Sopenharmony_ci{
873141cc406Sopenharmony_ci    scanner_offset_calibration(*dev, sensor, regs);
874141cc406Sopenharmony_ci}
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_civoid CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
877141cc406Sopenharmony_ci                                              Genesys_Register_Set& regs, int dpi) const
878141cc406Sopenharmony_ci{
879141cc406Sopenharmony_ci    scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
880141cc406Sopenharmony_ci}
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_civoid CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
883141cc406Sopenharmony_ci                                           Genesys_Register_Set* reg) const
884141cc406Sopenharmony_ci{
885141cc406Sopenharmony_ci    DBG_HELPER(dbg);
886141cc406Sopenharmony_ci    (void) sensor;
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci    unsigned channels = 3;
889141cc406Sopenharmony_ci    unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
890141cc406Sopenharmony_ci                                     .get_nearest_resolution_x(600);
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci    const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
893141cc406Sopenharmony_ci                                                         dev->settings.scan_method);
894141cc406Sopenharmony_ci    unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
895141cc406Sopenharmony_ci
896141cc406Sopenharmony_ci    *reg = dev->reg;
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci    auto flags = ScanFlag::DISABLE_SHADING |
899141cc406Sopenharmony_ci                 ScanFlag::DISABLE_GAMMA |
900141cc406Sopenharmony_ci                 ScanFlag::SINGLE_LINE |
901141cc406Sopenharmony_ci                 ScanFlag::IGNORE_STAGGER_OFFSET |
902141cc406Sopenharmony_ci                 ScanFlag::IGNORE_COLOR_OFFSET;
903141cc406Sopenharmony_ci    if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
904141cc406Sopenharmony_ci        dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
905141cc406Sopenharmony_ci    {
906141cc406Sopenharmony_ci        flags |= ScanFlag::USE_XPA;
907141cc406Sopenharmony_ci    }
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci    ScanSession session;
910141cc406Sopenharmony_ci    session.params.xres = resolution;
911141cc406Sopenharmony_ci    session.params.yres = resolution;
912141cc406Sopenharmony_ci    session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
913141cc406Sopenharmony_ci    session.params.starty = 0;
914141cc406Sopenharmony_ci    session.params.pixels = num_pixels;
915141cc406Sopenharmony_ci    session.params.lines = 1;
916141cc406Sopenharmony_ci    session.params.depth = dev->model->bpp_color_values.front();
917141cc406Sopenharmony_ci    session.params.channels = channels;
918141cc406Sopenharmony_ci    session.params.scan_method = dev->settings.scan_method;
919141cc406Sopenharmony_ci    session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
920141cc406Sopenharmony_ci    session.params.color_filter = dev->settings.color_filter;
921141cc406Sopenharmony_ci    session.params.contrast_adjustment = 0;
922141cc406Sopenharmony_ci    session.params.brightness_adjustment = 0;
923141cc406Sopenharmony_ci    session.params.flags = flags;
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci    compute_session(dev, session, calib_sensor);
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci    init_regs_for_scan_session(dev, calib_sensor, reg, session);
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci    sanei_genesys_set_motor_power(*reg, false);
930141cc406Sopenharmony_ci}
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_cistatic void gl842_init_gpio(Genesys_Device* dev)
933141cc406Sopenharmony_ci{
934141cc406Sopenharmony_ci    DBG_HELPER(dbg);
935141cc406Sopenharmony_ci    apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
936141cc406Sopenharmony_ci    {
937141cc406Sopenharmony_ci        dev->interface->write_register(reg.address, reg.value);
938141cc406Sopenharmony_ci    });
939141cc406Sopenharmony_ci}
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_civoid CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
942141cc406Sopenharmony_ci{
943141cc406Sopenharmony_ci    DBG_HELPER(dbg);
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci    if (cold) {
946141cc406Sopenharmony_ci        dev->interface->write_register(0x0e, 0x01);
947141cc406Sopenharmony_ci        dev->interface->write_register(0x0e, 0x00);
948141cc406Sopenharmony_ci    }
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci    // setup initial register values
951141cc406Sopenharmony_ci    gl842_init_registers(*dev);
952141cc406Sopenharmony_ci    dev->interface->write_registers(dev->reg);
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
955141cc406Sopenharmony_ci        std::uint8_t data[32] = {
956141cc406Sopenharmony_ci            0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
957141cc406Sopenharmony_ci            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
958141cc406Sopenharmony_ci            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
959141cc406Sopenharmony_ci            0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
960141cc406Sopenharmony_ci        };
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci        dev->interface->write_buffer(0x3c, 0x010a00, data, 32);
963141cc406Sopenharmony_ci    }
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
966141cc406Sopenharmony_ci        dev->interface->write_0x8c(0x10, 0x94);
967141cc406Sopenharmony_ci    }
968141cc406Sopenharmony_ci    if (dev->model->model_id == ModelId::CANON_LIDE_90) {
969141cc406Sopenharmony_ci        dev->interface->write_0x8c(0x10, 0xd4);
970141cc406Sopenharmony_ci    }
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci    // set RAM read address
973141cc406Sopenharmony_ci    dev->interface->write_register(REG_0x2A, 0x00);
974141cc406Sopenharmony_ci    dev->interface->write_register(REG_0x2B, 0x00);
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci    // setup gpio
977141cc406Sopenharmony_ci    gl842_init_gpio(dev);
978141cc406Sopenharmony_ci    dev->interface->sleep_ms(100);
979141cc406Sopenharmony_ci}
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_civoid CommandSetGl842::init(Genesys_Device* dev) const
982141cc406Sopenharmony_ci{
983141cc406Sopenharmony_ci    DBG_INIT();
984141cc406Sopenharmony_ci    DBG_HELPER(dbg);
985141cc406Sopenharmony_ci
986141cc406Sopenharmony_ci    sanei_genesys_asic_init(dev);
987141cc406Sopenharmony_ci}
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_civoid CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
990141cc406Sopenharmony_ci{
991141cc406Sopenharmony_ci    DBG_HELPER(dbg);
992141cc406Sopenharmony_ci    (void) s;
993141cc406Sopenharmony_ci}
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_civoid CommandSetGl842::update_home_sensor_gpio(Genesys_Device& dev) const
996141cc406Sopenharmony_ci{
997141cc406Sopenharmony_ci    DBG_HELPER(dbg);
998141cc406Sopenharmony_ci    if (dev.model->model_id == ModelId::CANON_LIDE_90) {
999141cc406Sopenharmony_ci        std::uint8_t val = dev.interface->read_register(REG_0x6C);
1000141cc406Sopenharmony_ci        val |= 0x02;
1001141cc406Sopenharmony_ci        dev.interface->write_register(REG_0x6C, val);
1002141cc406Sopenharmony_ci    }
1003141cc406Sopenharmony_ci}
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci/**
1006141cc406Sopenharmony_ci * Send shading calibration data. The buffer is considered to always hold values
1007141cc406Sopenharmony_ci * for all the channels.
1008141cc406Sopenharmony_ci */
1009141cc406Sopenharmony_civoid CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
1010141cc406Sopenharmony_ci                                        std::uint8_t* data, int size) const
1011141cc406Sopenharmony_ci{
1012141cc406Sopenharmony_ci    DBG_HELPER(dbg);
1013141cc406Sopenharmony_ci
1014141cc406Sopenharmony_ci    int offset = 0;
1015141cc406Sopenharmony_ci    unsigned length = size;
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ci    if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
1018141cc406Sopenharmony_ci        offset = dev->session.params.startx * sensor.shading_resolution /
1019141cc406Sopenharmony_ci                 dev->session.params.xres;
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci        length = dev->session.output_pixels * sensor.shading_resolution /
1022141cc406Sopenharmony_ci                 dev->session.params.xres;
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci        offset += sensor.shading_pixel_offset;
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci        // 16 bit words, 2 words per color, 3 color channels
1027141cc406Sopenharmony_ci        length *= 2 * 2 * 3;
1028141cc406Sopenharmony_ci        offset *= 2 * 2 * 3;
1029141cc406Sopenharmony_ci    } else {
1030141cc406Sopenharmony_ci        offset += sensor.shading_pixel_offset * 2 * 2 * 3;
1031141cc406Sopenharmony_ci    }
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci    dev->interface->record_key_value("shading_offset", std::to_string(offset));
1034141cc406Sopenharmony_ci    dev->interface->record_key_value("shading_length", std::to_string(length));
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci    std::vector<std::uint8_t> final_data(length, 0);
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci    unsigned count = 0;
1039141cc406Sopenharmony_ci    if (offset < 0) {
1040141cc406Sopenharmony_ci        count += (-offset);
1041141cc406Sopenharmony_ci        length -= (-offset);
1042141cc406Sopenharmony_ci        offset = 0;
1043141cc406Sopenharmony_ci    }
1044141cc406Sopenharmony_ci    if (static_cast<int>(length) + offset > static_cast<int>(size)) {
1045141cc406Sopenharmony_ci        length = size - offset;
1046141cc406Sopenharmony_ci    }
1047141cc406Sopenharmony_ci
1048141cc406Sopenharmony_ci    for (unsigned i = 0; i < length; i++) {
1049141cc406Sopenharmony_ci        final_data[count++] = data[offset + i];
1050141cc406Sopenharmony_ci        count++;
1051141cc406Sopenharmony_ci    }
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci    dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
1054141cc406Sopenharmony_ci}
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_cibool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
1057141cc406Sopenharmony_ci{
1058141cc406Sopenharmony_ci    (void) dev;
1059141cc406Sopenharmony_ci    return true;
1060141cc406Sopenharmony_ci}
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_civoid CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const
1063141cc406Sopenharmony_ci{
1064141cc406Sopenharmony_ci    (void) dev;
1065141cc406Sopenharmony_ci}
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci} // namespace gl842
1068141cc406Sopenharmony_ci} // namespace genesys
1069