1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2012-2013 Stéphane Voltz <stef.dev@free.fr>
4 
5 
6    This file is part of the SANE package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 
21    As a special exception, the authors of SANE give permission for
22    additional uses of the libraries contained in this release of SANE.
23 
24    The exception is that, if you link a SANE library with other files
25    to produce an executable, this does not by itself cause the
26    resulting executable to be covered by the GNU General Public
27    License.  Your use of that executable is in no way restricted on
28    account of linking the SANE library code into it.
29 
30    This exception does not, however, invalidate any other reasons why
31    the executable file might be covered by the GNU General Public
32    License.
33 
34    If you submit changes to SANE to the maintainers to be included in
35    a subsequent release, you agree by submitting the changes that
36    those changes may be distributed with this exception intact.
37 
38    If you write modifications of your own for SANE, it is your choice
39    whether to permit this exception to apply to your modifications.
40    If you do not wish that, delete this exception notice.
41 */
42 
43 /** @file
44  *
45  * This file handles GL846 and GL845 ASICs since they are really close to each other.
46  */
47 
48 #define DEBUG_DECLARE_ONLY
49 
50 #include "gl846.h"
51 #include "gl846_registers.h"
52 #include "test_settings.h"
53 
54 #include <vector>
55 
56 namespace genesys {
57 namespace gl846 {
58 
59 /**
60  * compute the step multiplier used
61  */
gl846_get_step_multiplier(Genesys_Register_Set * regs)62 static int gl846_get_step_multiplier (Genesys_Register_Set * regs)
63 {
64     unsigned value = (regs->get8(0x9d) & 0x0f) >> 1;
65     return 1 << value;
66 }
67 
68 /** @brief set all registers to default values .
69  * This function is called only once at the beginning and
70  * fills register startup values for registers reused across scans.
71  * Those that are rarely modified or not modified are written
72  * individually.
73  * @param dev device structure holding register set to initialize
74  */
75 static void
gl846_init_registers(Genesys_Device * dev)76 gl846_init_registers (Genesys_Device * dev)
77 {
78     DBG_HELPER(dbg);
79 
80     dev->reg.clear();
81 
82     dev->reg.init_reg(0x01, 0x60);
83     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
84         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
85     {
86         dev->reg.init_reg(0x01, 0x22);
87     }
88     dev->reg.init_reg(0x02, 0x38);
89     dev->reg.init_reg(0x03, 0x03);
90     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
91         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
92     {
93         dev->reg.init_reg(0x03, 0xbf);
94     }
95     dev->reg.init_reg(0x04, 0x22);
96     dev->reg.init_reg(0x05, 0x60);
97     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
98         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
99     {
100         dev->reg.init_reg(0x05, 0x48);
101     }
102     dev->reg.init_reg(0x06, 0x10);
103     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
104         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
105     {
106         dev->reg.init_reg(0x06, 0xf0);
107     }
108     dev->reg.init_reg(0x08, 0x60);
109     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
110         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
111     {
112         dev->reg.init_reg(0x08, 0x00);
113     }
114     dev->reg.init_reg(0x09, 0x00);
115     dev->reg.init_reg(0x0a, 0x00);
116     dev->reg.init_reg(0x0b, 0x8b);
117     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
118         dev->reg.init_reg(0x0b, 0x2a);
119     }
120     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
121         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
122     {
123         dev->reg.init_reg(0x0b, 0x4a);
124     }
125     dev->reg.init_reg(0x0c, 0x00);
126     dev->reg.init_reg(0x0d, 0x00);
127     dev->reg.init_reg(0x10, 0x00); // exposure, set during sensor setup
128     dev->reg.init_reg(0x11, 0x00); // exposure, set during sensor setup
129     dev->reg.init_reg(0x12, 0x00); // exposure, set during sensor setup
130     dev->reg.init_reg(0x13, 0x00); // exposure, set during sensor setup
131     dev->reg.init_reg(0x14, 0x00); // exposure, set during sensor setup
132     dev->reg.init_reg(0x15, 0x00); // exposure, set during sensor setup
133     dev->reg.init_reg(0x16, 0xbb); // SENSOR_DEF
134     dev->reg.init_reg(0x17, 0x13); // SENSOR_DEF
135     dev->reg.init_reg(0x18, 0x10); // SENSOR_DEF
136     dev->reg.init_reg(0x19, 0x2a); // SENSOR_DEF
137     dev->reg.init_reg(0x1a, 0x34); // SENSOR_DEF
138     dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF
139     dev->reg.init_reg(0x1c, 0x20); // SENSOR_DEF
140     dev->reg.init_reg(0x1d, 0x06); // SENSOR_DEF
141     dev->reg.init_reg(0x1e, 0xf0); // WDTIME, LINESEL: set during sensor and motor setup
142 
143      // SCANFED
144     dev->reg.init_reg(0x1f, 0x01);
145     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400) {
146         dev->reg.init_reg(0x1f, 0x00);
147     }
148 
149     dev->reg.init_reg(0x20, 0x03);
150     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
151         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
152     {
153         dev->reg.init_reg(0x20, 0x55);
154     }
155     dev->reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
156     dev->reg.init_reg(0x22, 0x60); // FWDSTEP: set during motor setup
157     dev->reg.init_reg(0x23, 0x60); // BWDSTEP: set during motor setup
158     dev->reg.init_reg(0x24, 0x60); // FASTNO: set during motor setup
159     dev->reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
160     dev->reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
161     dev->reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
162     dev->reg.init_reg(0x2c, 0x00); // DPISET: set during sensor setup
163     dev->reg.init_reg(0x2d, 0x00); // DPISET: set during sensor setup
164     dev->reg.init_reg(0x2e, 0x80); // BWHI: set during sensor setup
165     dev->reg.init_reg(0x2f, 0x80); // BWLOW: set during sensor setup
166     dev->reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
167     dev->reg.init_reg(0x31, 0x00); // STRPIXEL: set during sensor setup
168     dev->reg.init_reg(0x32, 0x00); // ENDPIXEL: set during sensor setup
169     dev->reg.init_reg(0x33, 0x00); // ENDPIXEL: set during sensor setup
170 
171     // DUMMY: the number of CCD dummy pixels
172     dev->reg.init_reg(0x34, 0x1f);
173     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
174         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
175     {
176         dev->reg.init_reg(0x34, 0x14);
177     }
178 
179     dev->reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
180     dev->reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
181     dev->reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
182     dev->reg.init_reg(0x38, 0x2a); // LPERIOD: set during sensor setup
183     dev->reg.init_reg(0x39, 0xf8); // LPERIOD: set during sensor setup
184     dev->reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
185     dev->reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
186     dev->reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
187     dev->reg.init_reg(0x52, 0x02); // SENSOR_DEF
188     dev->reg.init_reg(0x53, 0x04); // SENSOR_DEF
189     dev->reg.init_reg(0x54, 0x06); // SENSOR_DEF
190     dev->reg.init_reg(0x55, 0x08); // SENSOR_DEF
191     dev->reg.init_reg(0x56, 0x0a); // SENSOR_DEF
192     dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF
193     dev->reg.init_reg(0x58, 0x59); // SENSOR_DEF
194     dev->reg.init_reg(0x59, 0x31); // SENSOR_DEF
195     dev->reg.init_reg(0x5a, 0x40); // SENSOR_DEF
196 
197     // DECSEL, STEPTIM
198     dev->reg.init_reg(0x5e, 0x1f);
199     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
200         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
201     {
202         dev->reg.init_reg(0x5e, 0x01);
203     }
204     dev->reg.init_reg(0x5f, 0x01); // FMOVDEC: overwritten during motor setup
205     dev->reg.init_reg(0x60, 0x00); // STEPSEL, Z1MOD: overwritten during motor setup
206     dev->reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
207     dev->reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
208     dev->reg.init_reg(0x63, 0x00); // FSTPSEL, Z2MOD: overwritten during motor setup
209     dev->reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
210     dev->reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
211     dev->reg.init_reg(0x67, 0x7f); // MTRPWM: overwritten during motor setup
212     dev->reg.init_reg(0x68, 0x7f); // FASTPWM: overwritten during motor setup
213     dev->reg.init_reg(0x69, 0x01); // FSHDEC: overwritten during motor setup
214     dev->reg.init_reg(0x6a, 0x01); // FMOVNO: overwritten during motor setup
215     // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - gpio
216     dev->reg.init_reg(0x70, 0x01); // SENSOR_DEF
217     dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF
218     dev->reg.init_reg(0x72, 0x02); // SENSOR_DEF
219     dev->reg.init_reg(0x73, 0x01); // SENSOR_DEF
220     dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF
221     dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF
222     dev->reg.init_reg(0x76, 0x00); // SENSOR_DEF
223     dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF
224     dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF
225     dev->reg.init_reg(0x79, 0x3f); // SENSOR_DEF
226     dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF
227     dev->reg.init_reg(0x7b, 0x09); // SENSOR_DEF
228     dev->reg.init_reg(0x7c, 0x99); // SENSOR_DEF
229     dev->reg.init_reg(0x7d, 0x20); // SENSOR_DEF
230     dev->reg.init_reg(0x7f, 0x05);
231     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
232         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
233     {
234         dev->reg.init_reg(0x7f, 0x00);
235     }
236     dev->reg.init_reg(0x80, 0x4f); // overwritten during motor setup
237     dev->reg.init_reg(0x87, 0x02); // SENSOR_DEF
238 
239     // MTRPLS: pulse width of ADF motor trigger signal
240     dev->reg.init_reg(0x94, 0x00);
241     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
242         dev->reg.init_reg(0x94, 0xff);
243     }
244     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
245         dev->reg.init_reg(0x98, 0x20); // ONDUR
246         dev->reg.init_reg(0x99, 0x00); // ONDUR
247         dev->reg.init_reg(0x9a, 0x90); // OFFDUR
248         dev->reg.init_reg(0x9b, 0x00); // OFFDUR
249     }
250 
251     dev->reg.init_reg(0x9d, 0x00); // contains STEPTIM
252     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
253         dev->reg.init_reg(0x9d, 0x04);
254     }
255     dev->reg.init_reg(0x9e, 0x00);
256     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
257         dev->reg.init_reg(0xa1, 0xe0);
258     }
259 
260     // RFHSET (SDRAM refresh time)
261     dev->reg.init_reg(0xa2, 0x1f);
262     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
263         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
264     {
265         dev->reg.init_reg(0xa2, 0x0f);
266     }
267 
268     // 0xa6, 0xa7 0xa8, 0xa9 - gpio
269 
270     // Various important settings: GPOM9, MULSTOP, NODECEL, TB3TB1, TB5TB2, FIX16CLK
271     dev->reg.init_reg(0xab, 0xc0);
272     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
273         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
274     {
275         dev->reg.init_reg(0xab, 0x01);
276     }
277     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
278         dev->reg.init_reg(0xbb, 0x00); // FIXME: default is the same
279     }
280     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
281         dev->reg.init_reg(0xbc, 0x0f);
282         dev->reg.init_reg(0xdb, 0xff);
283     }
284     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400) {
285         dev->reg.init_reg(0xbe, 0x07);
286     }
287 
288     // 0xd0, 0xd1, 0xd2 - SH0DWN, SH1DWN, SH2DWN - shading bank[0..2] for CCD.
289     // Set during memory layout setup
290 
291     // [0xe0..0xf7] - image buffer addresses. Set during memory layout setup
292     dev->reg.init_reg(0xf8, 0x05); // MAXSEL, MINSEL
293 
294     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
295         dev->reg.init_reg(0xfe, 0x08); // MOTTGST, AUTO_O
296         dev->reg.init_reg(0xff, 0x02); // AUTO_S
297     }
298 
299     const auto& sensor = sanei_genesys_find_sensor_any(dev);
300     const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution,
301                                                          3, dev->model->default_method);
302     sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw);
303 }
304 
305 /**
306  * Set register values of Analog Device type frontend
307  * */
gl846_set_adi_fe(Genesys_Device * dev,uint8_t set)308 static void gl846_set_adi_fe(Genesys_Device* dev, uint8_t set)
309 {
310     DBG_HELPER(dbg);
311   int i;
312 
313     // wait for FE to be ready
314     auto status = scanner_read_status(*dev);
315     while (status.is_front_end_busy) {
316         dev->interface->sleep_ms(10);
317         status = scanner_read_status(*dev);
318     };
319 
320     if (set == AFE_INIT) {
321         dev->frontend = dev->frontend_initial;
322     }
323 
324     // write them to analog frontend
325     dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
326 
327     dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
328 
329     for (i = 0; i < 3; i++) {
330         dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i));
331     }
332     for (i = 0; i < 3; i++) {
333         dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i));
334     }
335 }
336 
337 // Set values of analog frontend
set_fe(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t set) const338 void CommandSetGl846::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
339 {
340     DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
341                                set == AFE_SET ? "set" :
342                                set == AFE_POWER_SAVE ? "powersave" : "huh?");
343     (void) sensor;
344 
345   /* route to specific analog frontend setup */
346     uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET;
347     switch (frontend_type) {
348       case 0x02: /* ADI FE */
349         gl846_set_adi_fe(dev, set);
350         break;
351       default:
352             throw SaneException("unsupported frontend type %d", frontend_type);
353     }
354 }
355 
356 
357 // @brief set up motor related register for scan
gl846_init_motor_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,const ScanSession & session,Genesys_Register_Set * reg,const MotorProfile & motor_profile,unsigned int scan_exposure_time,unsigned scan_yres,unsigned int scan_lines,unsigned int scan_dummy,unsigned int feed_steps,ScanFlag flags)358 static void gl846_init_motor_regs_scan(Genesys_Device* dev,
359                                        const Genesys_Sensor& sensor,
360                                        const ScanSession& session,
361                                        Genesys_Register_Set* reg,
362                                        const MotorProfile& motor_profile,
363                                        unsigned int scan_exposure_time,
364                                        unsigned scan_yres,
365                                        unsigned int scan_lines,
366                                        unsigned int scan_dummy,
367                                        unsigned int feed_steps,
368                                        ScanFlag flags)
369 {
370     DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, step_type=%d, scan_lines=%d, "
371                          "scan_dummy=%d, feed_steps=%d, flags=%x",
372                     scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
373                     scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
374 
375     unsigned step_multiplier = gl846_get_step_multiplier(reg);
376 
377     bool use_fast_fed = false;
378     if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) {
379         use_fast_fed = true;
380     }
381     if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
382         use_fast_fed = false;
383     }
384 
385     reg->set24(REG_LINCNT, scan_lines);
386 
387     reg->set8(REG_0x02, 0);
388     sanei_genesys_set_motor_power(*reg, true);
389 
390     std::uint8_t reg02 = reg->get8(REG_0x02);
391     if (use_fast_fed) {
392         reg02 |= REG_0x02_FASTFED;
393     } else {
394         reg02 &= ~REG_0x02_FASTFED;
395     }
396 
397     if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
398         reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
399     }
400 
401     if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || (scan_yres>=sensor.full_resolution)) {
402         reg02 |= REG_0x02_ACDCDIS;
403     }
404     if (has_flag(flags, ScanFlag::REVERSE)) {
405         reg02 |= REG_0x02_MTRREV;
406     } else {
407         reg02 &= ~REG_0x02_MTRREV;
408     }
409     reg->set8(REG_0x02, reg02);
410 
411     // scan and backtracking slope table
412     auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
413                                          scan_exposure_time, step_multiplier, motor_profile);
414 
415     scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
416     scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
417     scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
418 
419     reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
420     reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
421     reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
422 
423     // fast table
424     const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
425     if (fast_profile == nullptr) {
426         fast_profile = &motor_profile;
427     }
428 
429     auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
430                                                  *fast_profile);
431 
432     scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
433     scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
434 
435     reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
436     reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
437 
438     if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
439         std::uint8_t vref = 0;
440         vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
441         vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
442         vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
443         vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
444         reg->set8(REG_0x80, vref);
445     }
446 
447     unsigned feedl = feed_steps;
448     unsigned dist = 0;
449     if (use_fast_fed) {
450         feedl <<= static_cast<unsigned>(fast_profile->step_type);
451         dist = (scan_table.table.size() + 2 * fast_table.table.size());
452         // TODO read and decode REG_0xAB
453         dist += (reg->get8(0x5e) & 31);
454         dist += reg->get8(REG_FEDCNT);
455     } else {
456         feedl <<= static_cast<unsigned>(motor_profile.step_type);
457         dist = scan_table.table.size();
458         if (has_flag(flags, ScanFlag::FEEDING)) {
459             dist *= 2;
460         }
461     }
462 
463     // check for overflow
464     if (dist < feedl) {
465         feedl -= dist;
466     } else {
467         feedl = 0;
468     }
469 
470     reg->set24(REG_FEEDL, feedl);
471 
472     unsigned ccdlmt = (reg->get8(REG_0x0C) & REG_0x0C_CCDLMT) + 1;
473     unsigned tgtime = 1 << (reg->get8(REG_0x1C) & REG_0x1C_TGTIME);
474 
475   /* hi res motor speed GPIO */
476   /*
477     uint8_t effective = dev->interface->read_register(REG_0x6C);
478   */
479 
480   /* if quarter step, bipolar Vref2 */
481   /* XXX STEF XXX GPIO
482   if (motor_profile.step_type > 1)
483     {
484       if (motor_profile.step_type < 3)
485         {
486             val = effective & ~REG_0x6C_GPIO13;
487         }
488       else
489         {
490             val = effective | REG_0x6C_GPIO13;
491         }
492     }
493   else
494     {
495       val = effective;
496     }
497     dev->interface->write_register(REG_0x6C, val);
498     */
499 
500   /* effective scan */
501   /*
502     effective = dev->interface->read_register(REG_0x6C);
503     val = effective | REG_0x6C_GPIO10;
504     dev->interface->write_register(REG_0x6C, val);
505   */
506 
507     unsigned min_restep = (scan_table.table.size() / step_multiplier) / 2 - 1;
508     if (min_restep < 1) {
509         min_restep = 1;
510     }
511 
512     reg->set8(REG_FWDSTEP, min_restep);
513     reg->set8(REG_BWDSTEP, min_restep);
514 
515     std::uint32_t z1, z2;
516     sanei_genesys_calculate_zmod(use_fast_fed,
517                                  scan_exposure_time * ccdlmt * tgtime,
518                                  scan_table.table,
519                                  scan_table.table.size(),
520                                  feedl,
521                                  min_restep * step_multiplier,
522                                  &z1,
523                                  &z2);
524 
525     reg->set24(REG_0x60, z1 | (static_cast<unsigned>(motor_profile.step_type) << (16 + REG_0x60S_STEPSEL)));
526     reg->set24(REG_0x63, z2 | (static_cast<unsigned>(motor_profile.step_type) << (16 + REG_0x63S_FSTPSEL)));
527 
528     reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
529 
530     reg->set8(REG_0x67, 0x7f);
531     reg->set8(REG_0x68, 0x7f);
532 }
533 
534 
535 /** @brief set up registers related to sensor
536  * Set up the following registers
537    0x01
538    0x03
539    0x10-0x015     R/G/B exposures
540    0x19           EXPDMY
541    0x2e           BWHI
542    0x2f           BWLO
543    0x04
544    0x87
545    0x05
546    0x2c,0x2d      DPISET
547    0x30,0x31      STRPIXEL
548    0x32,0x33      ENDPIXEL
549    0x35,0x36,0x37 MAXWD [25:2] (>>2)
550    0x38,0x39      LPERIOD
551    0x34           DUMMY
552  */
gl846_init_optical_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int exposure_time,const ScanSession & session)553 static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
554                                          Genesys_Register_Set* reg, unsigned int exposure_time,
555                                          const ScanSession& session)
556 {
557     DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
558 
559     scanner_setup_sensor(*dev, sensor, *reg);
560 
561     dev->cmd_set->set_fe(dev, sensor, AFE_SET);
562 
563   /* enable shading */
564     regs_set_optical_off(dev->model->asic_type, *reg);
565     reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
566     if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
567         has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
568         session.use_host_side_calib)
569     {
570         reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
571     } else {
572         reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
573     }
574 
575     reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
576 
577     sanei_genesys_set_lamp_power(dev, sensor, *reg,
578                                  !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
579     reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
580 
581     // BW threshold
582     reg->set8(0x2e, 0x7f);
583     reg->set8(0x2f, 0x7f);
584 
585   /* monochrome / color scan */
586     switch (session.params.depth) {
587     case 8:
588             reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
589       break;
590     case 16:
591             reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART;
592             reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;
593       break;
594     }
595 
596     reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
597   if (session.params.channels == 1)
598     {
599       switch (session.params.color_filter)
600         {
601             case ColorFilter::RED:
602                 reg->find_reg(REG_0x04).value |= 0x24;
603                 break;
604             case ColorFilter::BLUE:
605                 reg->find_reg(REG_0x04).value |= 0x2c;
606                 break;
607             case ColorFilter::GREEN:
608                 reg->find_reg(REG_0x04).value |= 0x28;
609                 break;
610             default:
611                 break; // should not happen
612         }
613     } else {
614         reg->find_reg(REG_0x04).value |= 0x20; // mono
615     }
616 
617     const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
618                                                          session.params.channels,
619                                                          session.params.scan_method);
620     sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
621 
622     if (should_enable_gamma(session, sensor)) {
623         reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
624     } else {
625         reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
626     }
627 
628   /* CIS scanners can do true gray by setting LEDADD */
629   /* we set up LEDADD only when asked */
630     if (dev->model->is_cis) {
631         reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
632 
633         if (session.enable_ledadd) {
634             reg->find_reg(0x87).value |= REG_0x87_LEDADD;
635         }
636       /* RGB weighting
637         reg->find_reg(0x01).value &= ~REG_0x01_TRUEGRAY;
638 
639       if (session.enable_ledadd))
640         {
641             reg->find_reg(0x01).value |= REG_0x01_TRUEGRAY;
642         }*/
643     }
644 
645     reg->set16(REG_DPISET, sensor.register_dpiset);
646     reg->set16(REG_STRPIXEL, session.pixel_startx);
647     reg->set16(REG_ENDPIXEL, session.pixel_endx);
648 
649     setup_image_pipeline(*dev, session);
650 
651   /* MAXWD is expressed in 4 words unit */
652     // BUG: we shouldn't multiply by channels here
653     reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2));
654     reg->set16(REG_LPERIOD, exposure_time);
655     reg->set8(0x34, sensor.dummy_pixel);
656 }
657 
init_regs_for_scan_session(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,const ScanSession & session) const658 void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
659                                                  Genesys_Register_Set* reg,
660                                                  const ScanSession& session) const
661 {
662     DBG_HELPER(dbg);
663     session.assert_computed();
664 
665   int exposure_time;
666 
667   int slope_dpi = 0;
668 
669     // FIXME: on cis scanners we may want to scan at reduced resolution
670     int dummy = 0;
671 
672 /* slope_dpi */
673 /* cis color scan is effectively a gray scan with 3 gray lines per color
674    line and a FILTER of 0 */
675     if (dev->model->is_cis) {
676         slope_dpi = session.params.yres * session.params.channels;
677     } else {
678         slope_dpi = session.params.yres;
679     }
680 
681   slope_dpi = slope_dpi * (1 + dummy);
682 
683     exposure_time = sensor.exposure_lperiod;
684     const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
685 
686   /* we enable true gray for cis scanners only, and just when doing
687    * scan since color calibration is OK for this mode
688    */
689     gl846_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
690     gl846_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time, slope_dpi,
691                                session.optical_line_count, dummy, session.params.starty,
692                                session.params.flags);
693 
694   /*** prepares data reordering ***/
695 
696     dev->read_active = true;
697 
698     dev->session = session;
699 
700     dev->total_bytes_read = 0;
701     dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
702 
703     DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read);
704 }
705 
calculate_scan_session(const Genesys_Device * dev,const Genesys_Sensor & sensor,const Genesys_Settings & settings) const706 ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev,
707                                                     const Genesys_Sensor& sensor,
708                                                     const Genesys_Settings& settings) const
709 {
710     DBG(DBG_info, "%s ", __func__);
711     debug_dump(DBG_info, settings);
712 
713     ScanFlag flags = ScanFlag::NONE;
714 
715     unsigned move_dpi = dev->motor.base_ydpi;
716 
717     float move = dev->model->y_offset;
718     if (settings.scan_method == ScanMethod::TRANSPARENCY ||
719         settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
720     {
721         // note: scanner_move_to_ta() function has already been called and the sensor is at the
722         // transparency adapter
723         if (!dev->ignore_offsets) {
724             move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
725         }
726         flags |= ScanFlag::USE_XPA;
727     } else {
728         if (!dev->ignore_offsets) {
729             move = dev->model->y_offset;
730         }
731     }
732 
733     move = move + settings.tl_y;
734     move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
735     move -= dev->head_pos(ScanHeadId::PRIMARY);
736 
737     float start = dev->model->x_offset;
738     if (settings.scan_method == ScanMethod::TRANSPARENCY ||
739         settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
740     {
741         start = dev->model->x_offset_ta;
742     } else {
743         start = dev->model->x_offset;
744     }
745 
746     start = start + dev->settings.tl_x;
747     start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
748 
749     ScanSession session;
750     session.params.xres = settings.xres;
751     session.params.yres = settings.yres;
752     session.params.startx = static_cast<unsigned>(start);
753     session.params.starty = static_cast<unsigned>(move);
754     session.params.pixels = settings.pixels;
755     session.params.requested_pixels = settings.requested_pixels;
756     session.params.lines = settings.lines;
757     session.params.depth = settings.depth;
758     session.params.channels = settings.get_channels();
759     session.params.scan_method = settings.scan_method;
760     session.params.scan_mode = settings.scan_mode;
761     session.params.color_filter = settings.color_filter;
762     // backtracking isn't handled well, so don't enable it
763     session.params.flags = flags;
764 
765     compute_session(dev, session, sensor);
766 
767     return session;
768 }
769 
770 // for fast power saving methods only, like disabling certain amplifiers
save_power(Genesys_Device * dev,bool enable) const771 void CommandSetGl846::save_power(Genesys_Device* dev, bool enable) const
772 {
773     (void) dev;
774     DBG_HELPER_ARGS(dbg, "enable = %d", enable);
775 }
776 
set_powersaving(Genesys_Device * dev,int delay) const777 void CommandSetGl846::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
778 {
779     (void) dev;
780     DBG_HELPER_ARGS(dbg, "delay = %d", delay);
781 }
782 
783 // Send the low-level scan command
begin_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,bool start_motor) const784 void CommandSetGl846::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
785                                  Genesys_Register_Set* reg, bool start_motor) const
786 {
787     DBG_HELPER(dbg);
788     (void) sensor;
789   uint8_t val;
790 
791     if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
792         dev->cmd_set->set_xpa_lamp_power(*dev, true);
793     }
794 
795     scanner_clear_scan_and_feed_counts(*dev);
796 
797     val = dev->interface->read_register(REG_0x01);
798     val |= REG_0x01_SCAN;
799     dev->interface->write_register(REG_0x01, val);
800     reg->set8(REG_0x01, val);
801 
802     scanner_start_action(*dev, start_motor);
803 
804     dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
805 }
806 
807 
808 // Send the stop scan command
end_scan(Genesys_Device * dev,Genesys_Register_Set * reg,bool check_stop) const809 void CommandSetGl846::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
810                                bool check_stop) const
811 {
812     (void) reg;
813     DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
814 
815     if (reg->state.is_xpa_on) {
816         dev->cmd_set->set_xpa_lamp_power(*dev, false);
817     }
818 
819     if (!dev->model->is_sheetfed) {
820         scanner_stop_action(*dev);
821     }
822 }
823 
824 // Moves the slider to the home (top) position slowly
move_back_home(Genesys_Device * dev,bool wait_until_home) const825 void CommandSetGl846::move_back_home(Genesys_Device* dev, bool wait_until_home) const
826 {
827     scanner_move_back_home(*dev, wait_until_home);
828 }
829 
830 // init registers for shading calibration
init_regs_for_shading(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const831 void CommandSetGl846::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
832                                             Genesys_Register_Set& regs) const
833 {
834     DBG_HELPER(dbg);
835 
836     unsigned move_dpi = dev->motor.base_ydpi;
837 
838     float calib_size_mm = 0;
839     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
840         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
841     {
842         calib_size_mm = dev->model->y_size_calib_ta_mm;
843     } else {
844         calib_size_mm = dev->model->y_size_calib_mm;
845     }
846 
847     unsigned channels = 3;
848     unsigned resolution = sensor.shading_resolution;
849 
850     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
851                                                          dev->settings.scan_method);
852 
853     float move = 0;
854     ScanFlag flags = ScanFlag::DISABLE_SHADING |
855                      ScanFlag::DISABLE_GAMMA |
856                      ScanFlag::DISABLE_BUFFER_FULL_MOVE;
857 
858     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
859         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
860     {
861         // note: scanner_move_to_ta() function has already been called and the sensor is at the
862         // transparency adapter
863         move = static_cast<int>(dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta);
864         flags |= ScanFlag::USE_XPA;
865     } else {
866         move = static_cast<int>(dev->model->y_offset_calib_white);
867     }
868 
869     move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
870 
871     unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
872 
873     ScanSession session;
874     session.params.xres = resolution;
875     session.params.yres = resolution;
876     session.params.startx = 0;
877     session.params.starty = static_cast<unsigned>(move);
878     session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
879     session.params.lines = calib_lines;
880     session.params.depth = 16;
881     session.params.channels = channels;
882     session.params.scan_method = dev->settings.scan_method;
883     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
884     session.params.color_filter = dev->settings.color_filter;
885     session.params.flags = flags;
886     compute_session(dev, session, calib_sensor);
887 
888     init_regs_for_scan_session(dev, calib_sensor, &regs, session);
889 
890   /* we use ModelFlag::SHADING_REPARK */
891     dev->set_head_pos_zero(ScanHeadId::PRIMARY);
892 
893     dev->calib_session = session;
894 }
895 
896 /**
897  * Send shading calibration data. The buffer is considered to always hold values
898  * for all the channels.
899  */
send_shading_data(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t * data,int size) const900 void CommandSetGl846::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
901                                         uint8_t* data, int size) const
902 {
903     DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
904     std::uint32_t addr, i;
905   uint8_t val,*ptr,*src;
906 
907     unsigned length = static_cast<unsigned>(size / 3);
908 
909     // we're using SHDAREA, thus we only need to upload part of the line
910     unsigned offset = dev->session.pixel_count_ratio.apply(
911                 dev->session.params.startx * sensor.full_resolution / dev->session.params.xres);
912     unsigned pixels = dev->session.pixel_count_ratio.apply(dev->session.optical_pixels_raw);
913 
914     // turn pixel value into bytes 2x16 bits words
915     offset *= 2 * 2;
916     pixels *= 2 * 2;
917 
918     dev->interface->record_key_value("shading_offset", std::to_string(offset));
919     dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
920     dev->interface->record_key_value("shading_length", std::to_string(length));
921     dev->interface->record_key_value("shading_factor", std::to_string(sensor.shading_factor));
922 
923   std::vector<uint8_t> buffer(pixels, 0);
924 
925   DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels);
926 
927   /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address
928    * is 8192*reg value */
929 
930   /* write actual color channel data */
931   for(i=0;i<3;i++)
932     {
933       /* build up actual shading data by copying the part from the full width one
934        * to the one corresponding to SHDAREA */
935       ptr = buffer.data();
936 
937       /* iterate on both sensor segment */
938         for (unsigned x = 0; x < pixels; x += 4 * sensor.shading_factor) {
939           // coefficient source
940           src = (data + offset + i * length) + x;
941 
942           /* coefficient copy */
943           ptr[0]=src[0];
944           ptr[1]=src[1];
945           ptr[2]=src[2];
946           ptr[3]=src[3];
947 
948           /* next shading coefficient */
949           ptr+=4;
950         }
951 
952         val = dev->interface->read_register(0xd0+i);
953         addr = val * 8192 + 0x10000000;
954         dev->interface->write_ahb(addr, pixels, buffer.data());
955     }
956 }
957 
958 /** @brief calibrates led exposure
959  * Calibrate exposure by scanning a white area until the used exposure gives
960  * data white enough.
961  * @param dev device to calibrate
962  */
led_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const963 SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
964                                                 Genesys_Register_Set& regs) const
965 {
966     return scanner_led_calibration(*dev, sensor, regs);
967 }
968 
969 /**
970  * set up GPIO/GPOE for idle state
971  */
gl846_init_gpio(Genesys_Device * dev)972 static void gl846_init_gpio(Genesys_Device* dev)
973 {
974     DBG_HELPER(dbg);
975     apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
976     {
977         dev->interface->write_register(reg.address, reg.value);
978     });
979 }
980 
981 /**
982  * set memory layout by filling values in dedicated registers
983  */
gl846_init_memory_layout(Genesys_Device * dev)984 static void gl846_init_memory_layout(Genesys_Device* dev)
985 {
986     DBG_HELPER(dbg);
987 
988     // prevent further writings by bulk write register
989     dev->reg.remove_reg(0x0b);
990 
991     apply_reg_settings_to_device_write_only(*dev, dev->memory_layout.regs);
992 }
993 
994 /* *
995  * initialize ASIC from power on condition
996  */
asic_boot(Genesys_Device * dev,bool cold) const997 void CommandSetGl846::asic_boot(Genesys_Device* dev, bool cold) const
998 {
999     DBG_HELPER(dbg);
1000   uint8_t val;
1001 
1002     // reset ASIC if cold boot
1003     if (cold) {
1004         dev->interface->write_register(0x0e, 0x01);
1005         dev->interface->write_register(0x0e, 0x00);
1006     }
1007 
1008     if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
1009         if (dev->usb_mode == 1) {
1010             val = 0x14;
1011         } else {
1012             val = 0x11;
1013         }
1014         dev->interface->write_0x8c(0x0f, val);
1015     }
1016 
1017     // test CHKVER
1018     val = dev->interface->read_register(REG_0x40);
1019     if (val & REG_0x40_CHKVER) {
1020         val = dev->interface->read_register(0x00);
1021         DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val);
1022     }
1023 
1024     gl846_init_registers (dev);
1025 
1026     // Write initial registers
1027     dev->interface->write_registers(dev->reg);
1028 
1029   /* CIS_LINE */
1030   if (dev->model->is_cis)
1031     {
1032         dev->reg.init_reg(0x08, REG_0x08_CIS_LINE);
1033         dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value);
1034     }
1035 
1036     // set up clocks
1037     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
1038         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
1039     {
1040         dev->interface->write_0x8c(0x10, 0x0c);
1041         dev->interface->write_0x8c(0x13, 0x0c);
1042     } else {
1043         dev->interface->write_0x8c(0x10, 0x0e);
1044         dev->interface->write_0x8c(0x13, 0x0e);
1045     }
1046 
1047     // setup gpio
1048     gl846_init_gpio(dev);
1049 
1050     // setup internal memory layout
1051     gl846_init_memory_layout(dev);
1052 
1053   dev->reg.init_reg(0xf8, 0x05);
1054     dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value);
1055 }
1056 
1057 /**
1058  * initialize backend and ASIC : registers, motor tables, and gamma tables
1059  * then ensure scanner's head is at home
1060  */
init(Genesys_Device * dev) const1061 void CommandSetGl846::init(Genesys_Device* dev) const
1062 {
1063   DBG_INIT ();
1064     DBG_HELPER(dbg);
1065 
1066     sanei_genesys_asic_init(dev);
1067 }
1068 
update_hardware_sensors(Genesys_Scanner * s) const1069 void CommandSetGl846::update_hardware_sensors(Genesys_Scanner* s) const
1070 {
1071     DBG_HELPER(dbg);
1072   /* do what is needed to get a new set of events, but try to not lose
1073      any of them.
1074    */
1075   uint8_t val;
1076   uint8_t scan, file, email, copy;
1077   switch(s->dev->model->gpio_id)
1078     {
1079       default:
1080         scan=0x01;
1081         file=0x02;
1082         email=0x04;
1083         copy=0x08;
1084     }
1085     val = s->dev->interface->read_register(REG_0x6D);
1086 
1087     s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0);
1088     s->buttons[BUTTON_FILE_SW].write((val & file) == 0);
1089     s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0);
1090     s->buttons[BUTTON_COPY_SW].write((val & copy) == 0);
1091 }
1092 
1093 
update_home_sensor_gpio(Genesys_Device & dev) const1094 void CommandSetGl846::update_home_sensor_gpio(Genesys_Device& dev) const
1095 {
1096     DBG_HELPER(dbg);
1097 
1098     std::uint8_t val = dev.interface->read_register(REG_0x6C);
1099     val |= 0x41;
1100     dev.interface->write_register(REG_0x6C, val);
1101 }
1102 
offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1103 void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1104                                          Genesys_Register_Set& regs) const
1105 {
1106     scanner_offset_calibration(*dev, sensor, regs);
1107 }
1108 
coarse_gain_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,int dpi) const1109 void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1110                                               Genesys_Register_Set& regs, int dpi) const
1111 {
1112     scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
1113 }
1114 
needs_home_before_init_regs_for_scan(Genesys_Device * dev) const1115 bool CommandSetGl846::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
1116 {
1117     (void) dev;
1118     return false;
1119 }
1120 
init_regs_for_warmup(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * regs) const1121 void CommandSetGl846::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
1122                                            Genesys_Register_Set* regs) const
1123 {
1124     (void) dev;
1125     (void) sensor;
1126     (void) regs;
1127     throw SaneException("not implemented");
1128 }
1129 
send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor) const1130 void CommandSetGl846::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
1131 {
1132     sanei_genesys_send_gamma_table(dev, sensor);
1133 }
1134 
wait_for_motor_stop(Genesys_Device * dev) const1135 void CommandSetGl846::wait_for_motor_stop(Genesys_Device* dev) const
1136 {
1137     (void) dev;
1138 }
1139 
load_document(Genesys_Device * dev) const1140 void CommandSetGl846::load_document(Genesys_Device* dev) const
1141 {
1142     (void) dev;
1143     throw SaneException("not implemented");
1144 }
1145 
detect_document_end(Genesys_Device * dev) const1146 void CommandSetGl846::detect_document_end(Genesys_Device* dev) const
1147 {
1148     (void) dev;
1149     throw SaneException("not implemented");
1150 }
1151 
eject_document(Genesys_Device * dev) const1152 void CommandSetGl846::eject_document(Genesys_Device* dev) const
1153 {
1154     (void) dev;
1155     throw SaneException("not implemented");
1156 }
1157 
1158 } // namespace gl846
1159 } // namespace genesys
1160