1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2003 Oliver Rauch
4    Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de>
5    Copyright (C) 2004 Gerhard Jaeger <gerhard@gjaeger.de>
6    Copyright (C) 2004-2013 Stéphane Voltz <stef.dev@free.fr>
7    Copyright (C) 2005 Philipp Schmid <philipp8288@web.de>
8    Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
9    Copyright (C) 2006 Laurent Charpentier <laurent_pubs@yahoo.com>
10    Copyright (C) 2010 Chris Berry <s0457957@sms.ed.ac.uk> and Michael Rickmann <mrickma@gwdg.de>
11                  for Plustek Opticbook 3600 support
12 
13 
14    This file is part of the SANE package.
15 
16    This program is free software; you can redistribute it and/or
17    modify it under the terms of the GNU General Public License as
18    published by the Free Software Foundation; either version 2 of the
19    License, or (at your option) any later version.
20 
21    This program is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25 
26    You should have received a copy of the GNU General Public License
27    along with this program.  If not, see <https://www.gnu.org/licenses/>.
28 
29    As a special exception, the authors of SANE give permission for
30    additional uses of the libraries contained in this release of SANE.
31 
32    The exception is that, if you link a SANE library with other files
33    to produce an executable, this does not by itself cause the
34    resulting executable to be covered by the GNU General Public
35    License.  Your use of that executable is in no way restricted on
36    account of linking the SANE library code into it.
37 
38    This exception does not, however, invalidate any other reasons why
39    the executable file might be covered by the GNU General Public
40    License.
41 
42    If you submit changes to SANE to the maintainers to be included in
43    a subsequent release, you agree by submitting the changes that
44    those changes may be distributed with this exception intact.
45 
46    If you write modifications of your own for SANE, it is your choice
47    whether to permit this exception to apply to your modifications.
48    If you do not wish that, delete this exception notice.
49 */
50 
51 #define DEBUG_DECLARE_ONLY
52 
53 #include "gl841.h"
54 #include "gl841_registers.h"
55 #include "test_settings.h"
56 
57 #include <vector>
58 
59 namespace genesys {
60 namespace gl841 {
61 
62 
63 static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
64                                const MotorProfile& profile,
65                                float slope_dpi,
66                                int start,
67                                int used_pixels);
68 
69 /*
70  * Set all registers to default values
71  * (function called only once at the beginning)
72  */
73 static void
gl841_init_registers(Genesys_Device * dev)74 gl841_init_registers (Genesys_Device * dev)
75 {
76     DBG_HELPER(dbg);
77 
78     dev->reg.init_reg(0x01, 0x20);
79     if (dev->model->is_cis) {
80         dev->reg.find_reg(0x01).value |= REG_0x01_CISSET;
81     } else {
82         dev->reg.find_reg(0x01).value &= ~REG_0x01_CISSET;
83     }
84     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
85         dev->reg.init_reg(0x01, 0x82);
86     }
87 
88     dev->reg.init_reg(0x02, 0x38);
89     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
90         dev->reg.init_reg(0x02, 0x10);
91     }
92 
93     dev->reg.init_reg(0x03, 0x5f);
94     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
95         dev->reg.init_reg(0x03, 0x50);
96     }
97 
98     dev->reg.init_reg(0x04, 0x10);
99     if (dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) {
100         dev->reg.init_reg(0x04, 0x22);
101     } else if (dev->model->model_id == ModelId::CANON_LIDE_80) {
102         dev->reg.init_reg(0x04, 0x02);
103     }
104 
105     const auto& sensor = sanei_genesys_find_sensor_any(dev);
106 
107     dev->reg.init_reg(0x05, 0x00); // disable gamma, 24 clocks/pixel
108 
109     sanei_genesys_set_dpihw(dev->reg, sensor.register_dpihw);
110 
111     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
112         dev->reg.init_reg(0x05, 0x4c);
113     }
114 
115     dev->reg.init_reg(0x06, 0x18);
116     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
117         dev->reg.init_reg(0x06, 0x38);
118     }
119     if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
120         dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
121         dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
122         dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
123         dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
124     {
125         dev->reg.init_reg(0x06, 0xb8);
126     }
127 
128     dev->reg.init_reg(0x07, 0x00);
129     dev->reg.init_reg(0x08, 0x00);
130 
131     dev->reg.init_reg(0x09, 0x10);
132     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
133         dev->reg.init_reg(0x09, 0x11);
134     }
135     if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
136         dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
137         dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
138         dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
139         dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
140     {
141         dev->reg.init_reg(0x09, 0x00);
142     }
143     dev->reg.init_reg(0x0a, 0x00);
144 
145     // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings
146     dev->reg.init_reg(0x10, 0x00); // SENSOR_DEF
147     dev->reg.init_reg(0x11, 0x00); // SENSOR_DEF
148     dev->reg.init_reg(0x12, 0x00); // SENSOR_DEF
149     dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF
150     dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF
151     dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF
152     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
153         dev->reg.init_reg(0x10, 0x40);
154         dev->reg.init_reg(0x11, 0x00);
155         dev->reg.init_reg(0x12, 0x40);
156         dev->reg.init_reg(0x13, 0x00);
157         dev->reg.init_reg(0x14, 0x40);
158         dev->reg.init_reg(0x15, 0x00);
159     }
160 
161     dev->reg.init_reg(0x16, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
162     dev->reg.init_reg(0x17, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
163     dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
164     dev->reg.init_reg(0x19, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
165     dev->reg.init_reg(0x1a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
166     dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
167     dev->reg.init_reg(0x1c, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
168     dev->reg.init_reg(0x1d, 0x01); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
169     dev->reg.init_reg(0x1e, 0xf0);
170     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
171         dev->reg.init_reg(0x1e, 0x10);
172     }
173     dev->reg.init_reg(0x1f, 0x01);
174     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
175         dev->reg.init_reg(0x1f, 0x04);
176     }
177     dev->reg.init_reg(0x20, 0x20);
178     dev->reg.init_reg(0x21, 0x01);
179     dev->reg.init_reg(0x22, 0x01);
180     dev->reg.init_reg(0x23, 0x01);
181     dev->reg.init_reg(0x24, 0x01);
182     dev->reg.init_reg(0x25, 0x00);
183     dev->reg.init_reg(0x26, 0x00);
184     dev->reg.init_reg(0x27, 0x00);
185     dev->reg.init_reg(0x29, 0xff);
186 
187     dev->reg.init_reg(0x2c, 0x00);
188     dev->reg.init_reg(0x2d, 0x00);
189     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
190         dev->reg.init_reg(0x2c, sensor.full_resolution >> 8);
191         dev->reg.init_reg(0x2d, sensor.full_resolution & 0xff);
192     }
193     dev->reg.init_reg(0x2e, 0x80);
194     dev->reg.init_reg(0x2f, 0x80);
195 
196     dev->reg.init_reg(0x30, 0x00);
197     dev->reg.init_reg(0x31, 0x00);
198     dev->reg.init_reg(0x32, 0x00);
199     dev->reg.init_reg(0x33, 0x00);
200     dev->reg.init_reg(0x34, 0x00);
201     dev->reg.init_reg(0x35, 0x00);
202     dev->reg.init_reg(0x36, 0x00);
203     dev->reg.init_reg(0x37, 0x00);
204     dev->reg.init_reg(0x38, 0x4f);
205     dev->reg.init_reg(0x39, 0xc1);
206     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
207         dev->reg.init_reg(0x31, 0x10);
208         dev->reg.init_reg(0x32, 0x15);
209         dev->reg.init_reg(0x33, 0x0e);
210         dev->reg.init_reg(0x34, 0x40);
211         dev->reg.init_reg(0x35, 0x00);
212         dev->reg.init_reg(0x36, 0x2a);
213         dev->reg.init_reg(0x37, 0x30);
214         dev->reg.init_reg(0x38, 0x2a);
215         dev->reg.init_reg(0x39, 0xf8);
216     }
217 
218     dev->reg.init_reg(0x3d, 0x00);
219     dev->reg.init_reg(0x3e, 0x00);
220     dev->reg.init_reg(0x3f, 0x00);
221 
222     dev->reg.init_reg(0x52, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
223     dev->reg.init_reg(0x53, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
224     dev->reg.init_reg(0x54, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
225     dev->reg.init_reg(0x55, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
226     dev->reg.init_reg(0x56, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
227     dev->reg.init_reg(0x57, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
228     dev->reg.init_reg(0x58, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
229     dev->reg.init_reg(0x59, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
230     dev->reg.init_reg(0x5a, 0x00);  // SENSOR_DEF, overwritten in scanner_setup_sensor() below
231 
232     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
233         dev->reg.init_reg(0x5d, 0x20);
234         dev->reg.init_reg(0x5e, 0x41);
235         dev->reg.init_reg(0x5f, 0x40);
236         dev->reg.init_reg(0x60, 0x00);
237         dev->reg.init_reg(0x61, 0x00);
238         dev->reg.init_reg(0x62, 0x00);
239         dev->reg.init_reg(0x63, 0x00);
240         dev->reg.init_reg(0x64, 0x00);
241         dev->reg.init_reg(0x65, 0x00);
242         dev->reg.init_reg(0x66, 0x00);
243         dev->reg.init_reg(0x67, 0x40);
244         dev->reg.init_reg(0x68, 0x40);
245         dev->reg.init_reg(0x69, 0x20);
246         dev->reg.init_reg(0x6a, 0x20);
247         dev->reg.init_reg(0x6c, 0x00);
248         dev->reg.init_reg(0x6d, 0x00);
249         dev->reg.init_reg(0x6e, 0x00);
250         dev->reg.init_reg(0x6f, 0x00);
251     } else {
252         for (unsigned addr = 0x5d; addr <= 0x6f; addr++) {
253             dev->reg.init_reg(addr, 0);
254         }
255         dev->reg.init_reg(0x5e, 0x02);
256         if (dev->model->model_id == ModelId::CANON_LIDE_60) {
257             dev->reg.init_reg(0x66, 0xff);
258         }
259     }
260 
261     dev->reg.init_reg(0x70, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
262     dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
263     dev->reg.init_reg(0x72, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
264     dev->reg.init_reg(0x73, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
265 
266     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
267         dev->reg.init_reg(0x74, 0x00);
268         dev->reg.init_reg(0x75, 0x01);
269         dev->reg.init_reg(0x76, 0xff);
270         dev->reg.init_reg(0x77, 0x00);
271         dev->reg.init_reg(0x78, 0x0f);
272         dev->reg.init_reg(0x79, 0xf0);
273         dev->reg.init_reg(0x7a, 0xf0);
274         dev->reg.init_reg(0x7b, 0x00);
275         dev->reg.init_reg(0x7c, 0x1e);
276         dev->reg.init_reg(0x7d, 0x11);
277         dev->reg.init_reg(0x7e, 0x00);
278         dev->reg.init_reg(0x7f, 0x50);
279         dev->reg.init_reg(0x80, 0x00);
280         dev->reg.init_reg(0x81, 0x00);
281         dev->reg.init_reg(0x82, 0x0f);
282         dev->reg.init_reg(0x83, 0x00);
283         dev->reg.init_reg(0x84, 0x0e);
284         dev->reg.init_reg(0x85, 0x00);
285         dev->reg.init_reg(0x86, 0x0d);
286         dev->reg.init_reg(0x87, 0x02);
287         dev->reg.init_reg(0x88, 0x00);
288         dev->reg.init_reg(0x89, 0x00);
289     } else {
290         for (unsigned addr = 0x74; addr <= 0x87; addr++) {
291             dev->reg.init_reg(addr, 0);
292         }
293     }
294 
295     scanner_setup_sensor(*dev, sensor, dev->reg);
296 
297     // set up GPIO
298     for (const auto& reg : dev->gpo.regs) {
299         dev->reg.set8(reg.address, reg.value);
300     }
301 
302     if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
303         dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
304         dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
305     }
306 
307     if (dev->model->gpio_id == GpioId::XP300) {
308         dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
309     }
310 
311     if (dev->model->gpio_id == GpioId::DP685) {
312       /* REG_0x6B_GPO18 lights on green led */
313         dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17 | REG_0x6B_GPO18;
314     }
315 
316     if (dev->model->model_id == ModelId::CANON_LIDE_80) {
317         // specific scanner settings, clock and gpio first
318         dev->interface->write_register(REG_0x6B, 0x0c);
319         dev->interface->write_register(0x06, 0x10);
320         dev->interface->write_register(REG_0x6E, 0x6d);
321         dev->interface->write_register(REG_0x6F, 0x80);
322         dev->interface->write_register(REG_0x6B, 0x0e);
323         dev->interface->write_register(REG_0x6C, 0x00);
324         dev->interface->write_register(REG_0x6D, 0x8f);
325         dev->interface->write_register(REG_0x6B, 0x0e);
326         dev->interface->write_register(REG_0x6B, 0x0e);
327         dev->interface->write_register(REG_0x6B, 0x0a);
328         dev->interface->write_register(REG_0x6B, 0x02);
329         dev->interface->write_register(REG_0x6B, 0x06);
330 
331         dev->interface->write_0x8c(0x10, 0x94);
332         dev->interface->write_register(0x09, 0x10);
333 
334         // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was
335         // effectively changed. The current behavior matches the old code, but should probably be fixed.
336         dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18;
337         dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17;
338     }
339 }
340 
gl841_set_lide80_fe(Genesys_Device * dev,uint8_t set)341 static void gl841_set_lide80_fe(Genesys_Device* dev, uint8_t set)
342 {
343     DBG_HELPER(dbg);
344 
345     if (set == AFE_INIT) {
346         dev->frontend = dev->frontend_initial;
347 
348         // BUG: the following code does not make sense. The addresses are different than AFE_SET
349         // case
350         dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
351         dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x01));
352         dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x02));
353     }
354 
355   if (set == AFE_SET)
356     {
357         dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
358         dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x20));
359         dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x28));
360     }
361 }
362 
363 // Set values of Analog Device type frontend
gl841_set_ad_fe(Genesys_Device * dev,uint8_t set)364 static void gl841_set_ad_fe(Genesys_Device* dev, uint8_t set)
365 {
366     DBG_HELPER(dbg);
367   int i;
368 
369     if (dev->model->adc_id==AdcId::CANON_LIDE_80) {
370         gl841_set_lide80_fe(dev, set);
371         return;
372     }
373 
374     if (set == AFE_INIT) {
375       dev->frontend = dev->frontend_initial;
376 
377         // write them to analog frontend
378         dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
379 
380         dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
381 
382         for (i = 0; i < 6; i++) {
383             dev->interface->write_fe_register(0x02 + i, 0x00);
384         }
385     }
386   if (set == AFE_SET)
387     {
388         // write them to analog frontend
389         dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
390 
391         dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
392 
393         // Write fe 0x02 (red gain)
394         dev->interface->write_fe_register(0x02, dev->frontend.get_gain(0));
395 
396         // Write fe 0x03 (green gain)
397         dev->interface->write_fe_register(0x03, dev->frontend.get_gain(1));
398 
399         // Write fe 0x04 (blue gain)
400         dev->interface->write_fe_register(0x04, dev->frontend.get_gain(2));
401 
402         // Write fe 0x05 (red offset)
403         dev->interface->write_fe_register(0x05, dev->frontend.get_offset(0));
404 
405         // Write fe 0x06 (green offset)
406         dev->interface->write_fe_register(0x06, dev->frontend.get_offset(1));
407 
408         // Write fe 0x07 (blue offset)
409         dev->interface->write_fe_register(0x07, dev->frontend.get_offset(2));
410           }
411 }
412 
413 // Set values of analog frontend
set_fe(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t set) const414 void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
415 {
416     DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
417                                set == AFE_SET ? "set" :
418                                set == AFE_POWER_SAVE ? "powersave" : "huh?");
419     (void) sensor;
420 
421   /* Analog Device type frontend */
422     uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET;
423 
424     if (frontend_type == 0x02) {
425         gl841_set_ad_fe(dev, set);
426         return;
427     }
428 
429     if (frontend_type != 0x00) {
430         throw SaneException("unsupported frontend type %d", frontend_type);
431     }
432 
433     if (set == AFE_INIT) {
434         dev->frontend = dev->frontend_initial;
435 
436         // reset only done on init
437         dev->interface->write_fe_register(0x04, 0x80);
438     }
439 
440 
441   if (set == AFE_POWER_SAVE)
442     {
443         dev->interface->write_fe_register(0x01, 0x02);
444         return;
445     }
446 
447   /* todo :  base this test on cfg reg3 or a CCD family flag to be created */
448   /*if (dev->model->ccd_type!=SensorId::CCD_HP2300 && dev->model->ccd_type!=SensorId::CCD_HP2400) */
449   {
450         dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
451         dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02));
452   }
453 
454     dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
455     dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x03));
456     dev->interface->write_fe_register(0x06, dev->frontend.reg2[0]);
457     dev->interface->write_fe_register(0x08, dev->frontend.reg2[1]);
458     dev->interface->write_fe_register(0x09, dev->frontend.reg2[2]);
459 
460     for (unsigned i = 0; i < 3; i++) {
461         dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
462         dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
463         dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
464     }
465 }
466 
467 // @brief turn off motor
gl841_init_motor_regs_off(Genesys_Register_Set * reg,unsigned int scan_lines)468 static void gl841_init_motor_regs_off(Genesys_Register_Set* reg, unsigned int scan_lines)
469 {
470     DBG_HELPER_ARGS(dbg, "scan_lines=%d", scan_lines);
471     unsigned int feedl;
472 
473     feedl = 2;
474 
475     reg->set8(0x3d, (feedl >> 16) & 0xf);
476     reg->set8(0x3e, (feedl >> 8) & 0xff);
477     reg->set8(0x3f, feedl & 0xff);
478     reg->find_reg(0x5e).value &= ~0xe0;
479 
480     reg->set8(0x25, (scan_lines >> 16) & 0xf);
481     reg->set8(0x26, (scan_lines >> 8) & 0xff);
482     reg->set8(0x27, scan_lines & 0xff);
483 
484     reg->set8(0x02, 0x00);
485 
486     reg->set8(0x67, 0x3f);
487     reg->set8(0x68, 0x3f);
488 
489     reg->set8(REG_STEPNO, 1);
490     reg->set8(REG_FASTNO, 1);
491 
492     reg->set8(0x69, 1);
493     reg->set8(0x6a, 1);
494     reg->set8(0x5f, 1);
495 }
496 
497 /** @brief write motor table frequency
498  * Write motor frequency data table.
499  * @param dev device to set up motor
500  * @param ydpi motor target resolution
501  */
gl841_write_freq(Genesys_Device * dev,unsigned int ydpi)502 static void gl841_write_freq(Genesys_Device* dev, unsigned int ydpi)
503 {
504     DBG_HELPER(dbg);
505 /**< fast table */
506 uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76};
507 uint8_t t1200[]    = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20};
508 uint8_t t300[]     = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60};
509 uint8_t t150[]     = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60};
510 
511 uint8_t *table;
512 
513     if(dev->model->motor_id == MotorId::CANON_LIDE_80) {
514       switch(ydpi)
515         {
516           case 3600:
517           case 1200:
518             table=t1200;
519             break;
520           case 900:
521           case 300:
522             table=t300;
523             break;
524           case 450:
525           case 150:
526             table=t150;
527             break;
528           default:
529             table=tdefault;
530         }
531         dev->interface->write_register(0x66, 0x00);
532         dev->interface->write_gamma(0x28, 0xc000, table, 128);
533         dev->interface->write_register(0x5b, 0x00);
534         dev->interface->write_register(0x5c, 0x00);
535     }
536 }
537 
gl841_init_motor_regs_feed(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int feed_steps,ScanFlag flags)538 static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor& sensor,
539                                        Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/
540                                        ScanFlag flags)
541 {
542     DBG_HELPER_ARGS(dbg, "feed_steps=%d, flags=%x", feed_steps, static_cast<unsigned>(flags));
543     unsigned step_multiplier = 2;
544     int use_fast_fed = 0;
545     unsigned int feedl;
546 /*number of scan lines to add in a scan_lines line*/
547 
548     {
549         std::vector<uint16_t> table;
550         table.resize(256, 0xffff);
551 
552         scanner_send_slope_table(dev, sensor, 0, table);
553         scanner_send_slope_table(dev, sensor, 1, table);
554         scanner_send_slope_table(dev, sensor, 2, table);
555         scanner_send_slope_table(dev, sensor, 3, table);
556         scanner_send_slope_table(dev, sensor, 4, table);
557     }
558 
559     gl841_write_freq(dev, dev->motor.base_ydpi / 4);
560 
561     // FIXME: use proper scan session
562     ScanSession session;
563     session.params.yres = dev->motor.base_ydpi;
564     session.params.scan_method = dev->model->default_method;
565 
566     const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
567     if (fast_profile == nullptr) {
568         fast_profile = get_motor_profile_ptr(dev->motor.profiles, 0, session);
569     }
570     auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
571                                                  *fast_profile);
572 
573     // BUG: fast table is counted in base_ydpi / 4
574     feedl = feed_steps - fast_table.table.size() * 2;
575     use_fast_fed = 1;
576     if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
577         use_fast_fed = false;
578     }
579 
580     reg->set8(0x3d, (feedl >> 16) & 0xf);
581     reg->set8(0x3e, (feedl >> 8) & 0xff);
582     reg->set8(0x3f, feedl & 0xff);
583     reg->find_reg(0x5e).value &= ~0xe0;
584 
585     reg->set8(0x25, 0);
586     reg->set8(0x26, 0);
587     reg->set8(0x27, 0);
588 
589     reg->find_reg(0x02).value &= ~0x01; /*LONGCURV OFF*/
590     reg->find_reg(0x02).value &= ~0x80; /*NOT_HOME OFF*/
591 
592     reg->find_reg(0x02).value |= REG_0x02_MTRPWR;
593 
594     if (use_fast_fed)
595     reg->find_reg(0x02).value |= 0x08;
596     else
597     reg->find_reg(0x02).value &= ~0x08;
598 
599     if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
600         reg->find_reg(0x02).value |= 0x20;
601     } else {
602         reg->find_reg(0x02).value &= ~0x20;
603     }
604 
605     reg->find_reg(0x02).value &= ~0x40;
606 
607     if (has_flag(flags, ScanFlag::REVERSE)) {
608         reg->find_reg(0x02).value |= REG_0x02_MTRREV;
609     } else {
610         reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
611     }
612 
613     scanner_send_slope_table(dev, sensor, 3, fast_table.table);
614 
615     reg->set8(0x67, 0x3f);
616     reg->set8(0x68, 0x3f);
617     reg->set8(REG_STEPNO, 1);
618     reg->set8(REG_FASTNO, 1);
619     reg->set8(0x69, 1);
620     reg->set8(0x6a, fast_table.table.size() / step_multiplier);
621     reg->set8(0x5f, 1);
622 }
623 
gl841_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)624 static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
625                                        const ScanSession& session,
626                                        Genesys_Register_Set* reg, const MotorProfile& motor_profile,
627                                        unsigned int scan_exposure_time,/*pixel*/
628                                        unsigned scan_yres, // dpi, motor resolution
629                                        unsigned int scan_lines,/*lines, scan resolution*/
630                                        unsigned int scan_dummy,
631                                        // number of scan lines to add in a scan_lines line
632                                        unsigned int feed_steps,/*1/base_ydpi*/
633                                        // maybe float for half/quarter step resolution?
634                                        ScanFlag flags)
635 {
636     DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, scan_step_type=%d, scan_lines=%d,"
637                          " scan_dummy=%d, feed_steps=%d, flags=%x",
638                     scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
639                     scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
640 
641     unsigned step_multiplier = 2;
642 
643     int use_fast_fed = 0;
644     unsigned int fast_time;
645     unsigned int slow_time;
646     unsigned int feedl;
647     unsigned int min_restep = 0x20;
648 
649 /*
650   we calculate both tables for SCAN. the fast slope step count depends on
651   how many steps we need for slow acceleration and how much steps we are
652   allowed to use.
653  */
654 
655     // At least in LiDE 50, 60 the fast movement table is counted in full steps.
656     const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
657     if (fast_profile == nullptr) {
658         fast_profile = &motor_profile;
659     }
660 
661     auto slow_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
662                                          scan_exposure_time, step_multiplier, motor_profile);
663 
664     if (feed_steps < (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) {
665 	/*TODO: what should we do here?? go back to exposure calculation?*/
666         feed_steps = slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type);
667     }
668 
669     auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
670                                                  *fast_profile);
671 
672     unsigned max_fast_slope_steps_count = step_multiplier;
673     if (feed_steps > (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)) + 2) {
674         max_fast_slope_steps_count = (feed_steps -
675             (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) / 2;
676     }
677 
678     if (fast_table.table.size() > max_fast_slope_steps_count) {
679         fast_table.slice_steps(max_fast_slope_steps_count, step_multiplier);
680     }
681 
682     /* fast fed special cases handling */
683     if (dev->model->gpio_id == GpioId::XP300
684      || dev->model->gpio_id == GpioId::DP685)
685       {
686 	/* quirk: looks like at least this scanner is unable to use
687 	   2-feed mode */
688 	use_fast_fed = 0;
689       }
690     else if (feed_steps < fast_table.table.size() * 2 +
691              (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
692     {
693         use_fast_fed = 0;
694         DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__);
695     } else {
696 /* for deciding whether we should use fast mode we need to check how long we
697    need for (fast)accelerating, moving, decelerating, (TODO: stopping?)
698    (slow)accelerating again versus (slow)accelerating and moving. we need
699    fast and slow tables here.
700 */
701 /*NOTE: scan_exposure_time is per scan_yres*/
702 /*NOTE: fast_exposure is per base_ydpi/4*/
703 /*we use full steps as base unit here*/
704 	fast_time =
705         (fast_table.table.back() << static_cast<unsigned>(fast_profile->step_type)) / 4 *
706         (feed_steps - fast_table.table.size()*2 -
707          (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
708         + fast_table.pixeltime_sum() * 2 + slow_table.pixeltime_sum();
709 	slow_time =
710 	    (scan_exposure_time * scan_yres) / dev->motor.base_ydpi *
711         (feed_steps - (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
712         + slow_table.pixeltime_sum();
713 
714         use_fast_fed = fast_time < slow_time;
715     }
716 
717     if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
718         use_fast_fed = false;
719     }
720 
721     if (use_fast_fed) {
722         feedl = feed_steps - fast_table.table.size() * 2 -
723                 (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type));
724     } else if ((feed_steps << static_cast<unsigned>(motor_profile.step_type)) < slow_table.table.size()) {
725         feedl = 0;
726     } else {
727         feedl = (feed_steps << static_cast<unsigned>(motor_profile.step_type)) - slow_table.table.size();
728     }
729     DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed");
730 
731     reg->set8(0x3d, (feedl >> 16) & 0xf);
732     reg->set8(0x3e, (feedl >> 8) & 0xff);
733     reg->set8(0x3f, feedl & 0xff);
734     reg->find_reg(0x5e).value &= ~0xe0;
735     reg->set8(0x25, (scan_lines >> 16) & 0xf);
736     reg->set8(0x26, (scan_lines >> 8) & 0xff);
737     reg->set8(0x27, scan_lines & 0xff);
738     reg->find_reg(0x02).value = REG_0x02_MTRPWR;
739 
740     if (has_flag(flags, ScanFlag::REVERSE)) {
741         reg->find_reg(0x02).value |= REG_0x02_MTRREV;
742     } else {
743         reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
744     }
745 
746     if (use_fast_fed)
747     reg->find_reg(0x02).value |= 0x08;
748     else
749     reg->find_reg(0x02).value &= ~0x08;
750 
751     if (has_flag(flags, ScanFlag::AUTO_GO_HOME))
752     reg->find_reg(0x02).value |= 0x20;
753     else
754     reg->find_reg(0x02).value &= ~0x20;
755 
756     if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
757         reg->find_reg(0x02).value |= 0x40;
758     } else {
759         reg->find_reg(0x02).value &= ~0x40;
760     }
761 
762     scanner_send_slope_table(dev, sensor, 0, slow_table.table);
763     scanner_send_slope_table(dev, sensor, 1, slow_table.table);
764     scanner_send_slope_table(dev, sensor, 2, slow_table.table);
765     scanner_send_slope_table(dev, sensor, 3, fast_table.table);
766     scanner_send_slope_table(dev, sensor, 4, fast_table.table);
767 
768     gl841_write_freq(dev, scan_yres);
769 
770 /* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23,
771    reg 0x60-0x62 and reg 0x63-0x65
772    rule:
773    2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP
774 */
775 /* steps of table 0*/
776     if (min_restep < slow_table.table.size() * 2 + 2) {
777         min_restep = slow_table.table.size() * 2 + 2;
778     }
779 /* steps of table 1*/
780     if (min_restep < slow_table.table.size() * 2 + 2) {
781         min_restep = slow_table.table.size() * 2 + 2;
782     }
783 /* steps of table 0*/
784     reg->set8(REG_FWDSTEP, min_restep - slow_table.table.size()*2);
785 
786 /* steps of table 1*/
787     reg->set8(REG_BWDSTEP, min_restep - slow_table.table.size()*2);
788 
789 /*
790   for z1/z2:
791   in dokumentation mentioned variables a-d:
792   a = time needed for acceleration, table 1
793   b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time?
794   c = time needed for acceleration, table 1
795   d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time?
796   z1 = (c+d-1) % exposure_time
797   z2 = (a+b-1) % exposure_time
798 */
799 /* i don't see any effect of this. i can only guess that this will enhance
800    sub-pixel accuracy
801    z1 = (slope_0_time-1) % exposure_time;
802    z2 = (slope_0_time-1) % exposure_time;
803 */
804     reg->set24(REG_0x60, 0);
805     reg->set24(REG_0x63, 0);
806     reg->find_reg(REG_0x1E).value &= REG_0x1E_WDTIME;
807     reg->find_reg(REG_0x1E).value |= scan_dummy;
808     reg->set8(0x67, 0x3f | (static_cast<unsigned>(motor_profile.step_type) << 6));
809     reg->set8(0x68, 0x3f | (static_cast<unsigned>(fast_profile->step_type) << 6));
810     reg->set8(REG_STEPNO, slow_table.table.size() / step_multiplier);
811     reg->set8(REG_FASTNO, slow_table.table.size() / step_multiplier);
812     reg->set8(0x69, slow_table.table.size() / step_multiplier);
813     reg->set8(0x6a, fast_table.table.size() / step_multiplier);
814     reg->set8(0x5f, fast_table.table.size() / step_multiplier);
815 }
816 
gl841_init_optical_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int exposure_time,const ScanSession & session)817 static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
818                                          Genesys_Register_Set* reg, unsigned int exposure_time,
819                                          const ScanSession& session)
820 {
821     DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
822     uint16_t expavg, expr, expb, expg;
823 
824     dev->cmd_set->set_fe(dev, sensor, AFE_SET);
825 
826     /* gpio part.*/
827     if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
828         if (session.params.xres <= 600) {
829             reg->find_reg(REG_0x6C).value &= ~0x80;
830         } else {
831             reg->find_reg(REG_0x6C).value |= 0x80;
832         }
833       }
834     if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
835         if (session.params.xres <= 600) {
836             reg->find_reg(REG_0x6C).value &= ~0x40;
837             reg->find_reg(REG_0x6C).value |= 0x20;
838         } else {
839             reg->find_reg(REG_0x6C).value &= ~0x20;
840             reg->find_reg(REG_0x6C).value |= 0x40;
841         }
842     }
843 
844     /* enable shading */
845     reg->find_reg(0x01).value |= REG_0x01_SCAN;
846     if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
847         has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION)) {
848         reg->find_reg(0x01).value &= ~REG_0x01_DVDSET;
849     } else {
850         reg->find_reg(0x01).value |= REG_0x01_DVDSET;
851     }
852 
853     /* average looks better than deletion, and we are already set up to
854        use  one of the average enabled resolutions
855     */
856     reg->find_reg(0x03).value |= REG_0x03_AVEENB;
857     sanei_genesys_set_lamp_power(dev, sensor, *reg,
858                                  !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
859 
860     /* BW threshold */
861     reg->set8(0x2e, 0x7f);
862     reg->set8(0x2f, 0x7f);
863 
864 
865     /* monochrome / color scan */
866     switch (session.params.depth) {
867 	case 8:
868             reg->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
869 	    break;
870 	case 16:
871             reg->find_reg(0x04).value &= ~REG_0x04_LINEART;
872             reg->find_reg(0x04).value |= REG_0x04_BITSET;
873 	    break;
874     }
875 
876     /* AFEMOD should depend on FESET, and we should set these
877      * bits separately */
878     reg->find_reg(0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
879     if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
880         reg->find_reg(0x04).value |= 0x10;	/* no filter */
881     }
882     else if (session.params.channels == 1)
883       {
884     switch (session.params.color_filter)
885 	  {
886             case ColorFilter::RED:
887                 reg->find_reg(0x04).value |= 0x14;
888                 break;
889             case ColorFilter::GREEN:
890                 reg->find_reg(0x04).value |= 0x18;
891                 break;
892             case ColorFilter::BLUE:
893                 reg->find_reg(0x04).value |= 0x1c;
894                 break;
895             default:
896                 reg->find_reg(0x04).value |= 0x10;
897                 break;
898 	  }
899       }
900     else
901       {
902         if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
903             reg->find_reg(0x04).value |= 0x22;	/* slow color pixel by pixel */
904           }
905 	else
906           {
907         reg->find_reg(0x04).value |= 0x10;	/* color pixel by pixel */
908           }
909       }
910 
911     /* CIS scanners can do true gray by setting LEDADD */
912     reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
913     if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
914         reg->find_reg(0x87).value |= REG_0x87_LEDADD;
915         expr = reg->get16(REG_EXPR);
916         expg = reg->get16(REG_EXPG);
917         expb = reg->get16(REG_EXPB);
918 
919 	/* use minimal exposure for best image quality */
920 	expavg = expg;
921 	if (expr < expg)
922 	  expavg = expr;
923 	if (expb < expavg)
924 	  expavg = expb;
925 
926         dev->reg.set16(REG_EXPR, expavg);
927         dev->reg.set16(REG_EXPG, expavg);
928         dev->reg.set16(REG_EXPB, expavg);
929       }
930 
931     // enable gamma tables
932     if (should_enable_gamma(session, sensor)) {
933         reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
934     } else {
935         reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
936     }
937 
938     /* sensor parameters */
939     scanner_setup_sensor(*dev, sensor, dev->reg);
940     reg->set8(0x29, 255); /*<<<"magic" number, only suitable for cis*/
941     reg->set16(REG_DPISET, sensor.register_dpiset);
942     reg->set16(REG_STRPIXEL, session.pixel_startx);
943     reg->set16(REG_ENDPIXEL, session.pixel_endx);
944     reg->set24(REG_MAXWD, session.output_line_bytes);
945     reg->set16(REG_LPERIOD, exposure_time);
946     reg->set8(0x34, sensor.dummy_pixel);
947 }
948 
949 static int
gl841_get_led_exposure(Genesys_Device * dev,const Genesys_Sensor & sensor)950 gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor)
951 {
952     int d,r,g,b,m;
953     if (!dev->model->is_cis)
954 	return 0;
955     d = dev->reg.find_reg(0x19).value;
956 
957     r = sensor.exposure.red;
958     g = sensor.exposure.green;
959     b = sensor.exposure.blue;
960 
961     m = r;
962     if (m < g)
963 	m = g;
964     if (m < b)
965 	m = b;
966 
967     return m + d;
968 }
969 
970 /** @brief compute exposure time
971  * Compute exposure time for the device and the given scan resolution
972  */
gl841_exposure_time(Genesys_Device * dev,const Genesys_Sensor & sensor,const MotorProfile & profile,float slope_dpi,int start,int used_pixels)973 static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
974                                const MotorProfile& profile, float slope_dpi,
975                                int start,
976                                int used_pixels)
977 {
978 int led_exposure;
979 
980   led_exposure=gl841_get_led_exposure(dev, sensor);
981     return sanei_genesys_exposure_time2(dev, profile, slope_dpi,
982                                         start + used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
983                                         led_exposure);
984 }
985 
init_regs_for_scan_session(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,const ScanSession & session) const986 void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
987                                                  Genesys_Register_Set* reg,
988                                                  const ScanSession& session) const
989 {
990     DBG_HELPER(dbg);
991     session.assert_computed();
992 
993   int move;
994   int exposure_time;
995 
996   int slope_dpi = 0;
997   int dummy = 0;
998 
999 /* dummy */
1000   /* dummy lines: may not be useful, for instance 250 dpi works with 0 or 1
1001      dummy line. Maybe the dummy line adds correctness since the motor runs
1002      slower (higher dpi)
1003   */
1004 /* for cis this creates better aligned color lines:
1005 dummy \ scanned lines
1006    0: R           G           B           R ...
1007    1: R        G        B        -        R ...
1008    2: R      G      B       -      -      R ...
1009    3: R     G     B     -     -     -     R ...
1010    4: R    G    B     -   -     -    -    R ...
1011    5: R    G   B    -   -   -    -   -    R ...
1012    6: R   G   B   -   -   -   -   -   -   R ...
1013    7: R   G  B   -  -   -   -  -   -  -   R ...
1014    8: R  G  B   -  -  -   -  -  -   -  -  R ...
1015    9: R  G  B  -  -  -  -  -  -  -  -  -  R ...
1016   10: R  G B  -  -  -  - -  -  -  -  - -  R ...
1017   11: R  G B  - -  - -  -  - -  - -  - -  R ...
1018   12: R G  B - -  - -  - -  - -  - - -  - R ...
1019   13: R G B  - - - -  - - -  - - - -  - - R ...
1020   14: R G B - - -  - - - - - -  - - - - - R ...
1021   15: R G B - - - - - - - - - - - - - - - R ...
1022  -- pierre
1023  */
1024   dummy = 0;
1025 
1026 /* slope_dpi */
1027 /* cis color scan is effectively a gray scan with 3 gray lines per color
1028    line and a FILTER of 0 */
1029     if (dev->model->is_cis) {
1030         slope_dpi = session.params.yres* session.params.channels;
1031     } else {
1032         slope_dpi = session.params.yres;
1033     }
1034 
1035   slope_dpi = slope_dpi * (1 + dummy);
1036 
1037     const auto& motor_profile = get_motor_profile(dev->motor.profiles, 0, session);
1038 
1039     exposure_time = gl841_exposure_time(dev, sensor, motor_profile, slope_dpi,
1040                                         session.pixel_startx, session.optical_pixels);
1041 
1042     gl841_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
1043 
1044     move = session.params.starty;
1045 
1046   /* subtract current head position */
1047     move -= (dev->head_pos(ScanHeadId::PRIMARY) * session.params.yres) / dev->motor.base_ydpi;
1048 
1049   if (move < 0)
1050       move = 0;
1051 
1052   /* round it */
1053 /* the move is not affected by dummy -- pierre */
1054 /*  move = ((move + dummy) / (dummy + 1)) * (dummy + 1);*/
1055 
1056     if (has_flag(session.params.flags, ScanFlag::SINGLE_LINE)) {
1057         gl841_init_motor_regs_off(reg, session.optical_line_count);
1058     } else {
1059         gl841_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time,
1060                                    slope_dpi, session.optical_line_count, dummy, move,
1061                                    session.params.flags);
1062   }
1063 
1064     setup_image_pipeline(*dev, session);
1065 
1066     dev->read_active = true;
1067 
1068     dev->session = session;
1069 
1070     dev->total_bytes_read = 0;
1071     dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
1072 
1073     DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read);
1074 }
1075 
calculate_scan_session(const Genesys_Device * dev,const Genesys_Sensor & sensor,const Genesys_Settings & settings) const1076 ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev,
1077                                                     const Genesys_Sensor& sensor,
1078                                                     const Genesys_Settings& settings) const
1079 {
1080     DBG_HELPER(dbg);
1081     debug_dump(DBG_info, settings);
1082 
1083     /* steps to move to reach scanning area:
1084        - first we move to physical start of scanning
1085        either by a fixed steps amount from the black strip
1086        or by a fixed amount from parking position,
1087        minus the steps done during shading calibration
1088        - then we move by the needed offset whitin physical
1089        scanning area
1090 
1091        assumption: steps are expressed at maximum motor resolution
1092 
1093        we need:
1094        float y_offset;
1095        float y_size;
1096        float y_offset_calib;
1097        mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH
1098     */
1099     float move = dev->model->y_offset;
1100     move += dev->settings.tl_y;
1101 
1102     int move_dpi = dev->motor.base_ydpi;
1103     move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
1104 
1105     float start = dev->model->x_offset;
1106     start += dev->settings.tl_x;
1107     start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH);
1108 
1109     // we enable true gray for cis scanners only, and just when doing
1110     // scan since color calibration is OK for this mode
1111     ScanFlag flags = ScanFlag::NONE;
1112 
1113     // true gray (led add for cis scanners)
1114     if (dev->model->is_cis && dev->settings.true_gray &&
1115         dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS &&
1116         dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80)
1117     {
1118         // on Lide 80 the LEDADD bit results in only red LED array being lit
1119         flags |= ScanFlag::ENABLE_LEDADD;
1120     }
1121 
1122     ScanSession session;
1123     session.params.xres = dev->settings.xres;
1124     session.params.yres = dev->settings.yres;
1125     session.params.startx = static_cast<unsigned>(start);
1126     session.params.starty = static_cast<unsigned>(move);
1127     session.params.pixels = dev->settings.pixels;
1128     session.params.requested_pixels = dev->settings.requested_pixels;
1129     session.params.lines = dev->settings.lines;
1130     session.params.depth = dev->settings.depth;
1131     session.params.channels = dev->settings.get_channels();
1132     session.params.scan_method = dev->settings.scan_method;
1133     session.params.scan_mode = dev->settings.scan_mode;
1134     session.params.color_filter = dev->settings.color_filter;
1135     session.params.flags = flags;
1136     compute_session(dev, session, sensor);
1137 
1138     return session;
1139 }
1140 
1141 // for fast power saving methods only, like disabling certain amplifiers
save_power(Genesys_Device * dev,bool enable) const1142 void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const
1143 {
1144     DBG_HELPER_ARGS(dbg, "enable = %d", enable);
1145 
1146     const auto& sensor = sanei_genesys_find_sensor_any(dev);
1147 
1148     if (enable)
1149     {
1150     if (dev->model->gpio_id == GpioId::CANON_LIDE_35)
1151 	{
1152 /* expect GPIO17 to be enabled, and GPIO9 to be disabled,
1153    while GPIO8 is disabled*/
1154 /* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled,
1155    GPIO18 disabled*/
1156 
1157             uint8_t val = dev->interface->read_register(REG_0x6D);
1158             dev->interface->write_register(REG_0x6D, val | 0x80);
1159 
1160             dev->interface->sleep_ms(1);
1161 
1162 	    /*enable GPIO9*/
1163             val = dev->interface->read_register(REG_0x6C);
1164             dev->interface->write_register(REG_0x6C, val | 0x01);
1165 
1166 	    /*disable GPO17*/
1167             val = dev->interface->read_register(REG_0x6B);
1168             dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17);
1169 
1170 	    /*disable GPO18*/
1171             val = dev->interface->read_register(REG_0x6B);
1172             dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO18);
1173 
1174             dev->interface->sleep_ms(1);
1175 
1176             val = dev->interface->read_register(REG_0x6D);
1177             dev->interface->write_register(REG_0x6D, val & ~0x80);
1178 
1179 	}
1180     if (dev->model->gpio_id == GpioId::DP685)
1181 	  {
1182             uint8_t val = dev->interface->read_register(REG_0x6B);
1183             dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17);
1184             dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
1185             dev->initial_regs.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
1186 	  }
1187 
1188         set_fe(dev, sensor, AFE_POWER_SAVE);
1189 
1190     }
1191     else
1192     {
1193     if (dev->model->gpio_id == GpioId::CANON_LIDE_35)
1194 	{
1195 /* expect GPIO17 to be enabled, and GPIO9 to be disabled,
1196    while GPIO8 is disabled*/
1197 /* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled,
1198    GPIO18 enabled*/
1199 
1200             uint8_t val = dev->interface->read_register(REG_0x6D);
1201             dev->interface->write_register(REG_0x6D, val | 0x80);
1202 
1203             dev->interface->sleep_ms(10);
1204 
1205 	    /*disable GPIO9*/
1206             val = dev->interface->read_register(REG_0x6C);
1207             dev->interface->write_register(REG_0x6C, val & ~0x01);
1208 
1209 	    /*enable GPIO10*/
1210             val = dev->interface->read_register(REG_0x6C);
1211             dev->interface->write_register(REG_0x6C, val | 0x02);
1212 
1213 	    /*enable GPO17*/
1214             val = dev->interface->read_register(REG_0x6B);
1215             dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
1216             dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
1217             dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
1218 
1219 	    /*enable GPO18*/
1220             val = dev->interface->read_register(REG_0x6B);
1221             dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO18);
1222             dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
1223             dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO18;
1224 
1225 	}
1226     if (dev->model->gpio_id == GpioId::DP665
1227             || dev->model->gpio_id == GpioId::DP685)
1228 	  {
1229             uint8_t val = dev->interface->read_register(REG_0x6B);
1230             dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
1231             dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
1232             dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
1233 	  }
1234 
1235     }
1236 }
1237 
set_powersaving(Genesys_Device * dev,int delay) const1238 void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
1239 {
1240     DBG_HELPER_ARGS(dbg, "delay = %d", delay);
1241   // FIXME: SEQUENTIAL not really needed in this case
1242   Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
1243   int rate, exposure_time, tgtime, time;
1244 
1245     local_reg.init_reg(0x01, dev->reg.get8(0x01));	/* disable fastmode */
1246     local_reg.init_reg(0x03, dev->reg.get8(0x03));	/* Lamp power control */
1247     local_reg.init_reg(0x05, dev->reg.get8(0x05)); /*& ~REG_0x05_BASESEL*/;	/* 24 clocks/pixel */
1248     local_reg.init_reg(0x18, 0x00); // Set CCD type
1249     local_reg.init_reg(0x38, 0x00);
1250     local_reg.init_reg(0x39, 0x00);
1251 
1252     // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE
1253     local_reg.init_reg(0x1c, dev->reg.get8(0x05) & ~REG_0x1C_TGTIME);
1254 
1255     if (!delay) {
1256         local_reg.find_reg(0x03).value = local_reg.find_reg(0x03).value & 0xf0;	/* disable lampdog and set lamptime = 0 */
1257     } else if (delay < 20) {
1258         local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x09;	/* enable lampdog and set lamptime = 1 */
1259     } else {
1260         local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x0f;	/* enable lampdog and set lamptime = 7 */
1261     }
1262 
1263   time = delay * 1000 * 60;	/* -> msec */
1264   exposure_time = static_cast<std::uint32_t>(time * 32000.0 /
1265                  (24.0 * 64.0 * (local_reg.find_reg(0x03).value & REG_0x03_LAMPTIM) *
1266 		  1024.0) + 0.5);
1267   /* 32000 = system clock, 24 = clocks per pixel */
1268   rate = (exposure_time + 65536) / 65536;
1269   if (rate > 4)
1270     {
1271       rate = 8;
1272       tgtime = 3;
1273     }
1274   else if (rate > 2)
1275     {
1276       rate = 4;
1277       tgtime = 2;
1278     }
1279   else if (rate > 1)
1280     {
1281       rate = 2;
1282       tgtime = 1;
1283     }
1284   else
1285     {
1286       rate = 1;
1287       tgtime = 0;
1288     }
1289 
1290   local_reg.find_reg(0x1c).value |= tgtime;
1291   exposure_time /= rate;
1292 
1293   if (exposure_time > 65535)
1294     exposure_time = 65535;
1295 
1296   local_reg.set8(0x38, exposure_time >> 8);
1297   local_reg.set8(0x39, exposure_time & 255);	/* lowbyte */
1298 
1299     dev->interface->write_registers(local_reg);
1300 }
1301 
gl841_get_paper_sensor(Genesys_Device * dev)1302 static bool gl841_get_paper_sensor(Genesys_Device* dev)
1303 {
1304     DBG_HELPER(dbg);
1305 
1306     uint8_t val = dev->interface->read_register(REG_0x6D);
1307 
1308     return (val & 0x1) == 0;
1309 }
1310 
eject_document(Genesys_Device * dev) const1311 void CommandSetGl841::eject_document(Genesys_Device* dev) const
1312 {
1313     DBG_HELPER(dbg);
1314   Genesys_Register_Set local_reg;
1315   unsigned int init_steps;
1316   float feed_mm;
1317   int loop;
1318 
1319     if (!dev->model->is_sheetfed) {
1320       DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__);
1321       return;
1322     }
1323 
1324 
1325   local_reg.clear();
1326 
1327     // FIXME: unused result
1328     scanner_read_status(*dev);
1329     scanner_stop_action(*dev);
1330 
1331   local_reg = dev->reg;
1332 
1333     regs_set_optical_off(dev->model->asic_type, local_reg);
1334 
1335   const auto& sensor = sanei_genesys_find_sensor_any(dev);
1336     gl841_init_motor_regs_feed(dev, sensor, &local_reg, 65536, ScanFlag::NONE);
1337 
1338     dev->interface->write_registers(local_reg);
1339 
1340     try {
1341         scanner_start_action(*dev, true);
1342     } catch (...) {
1343         catch_all_exceptions(__func__, [&]() { scanner_stop_action(*dev); });
1344         // restore original registers
1345         catch_all_exceptions(__func__, [&]()
1346         {
1347             dev->interface->write_registers(dev->reg);
1348         });
1349         throw;
1350     }
1351 
1352     if (is_testing_mode()) {
1353         dev->interface->test_checkpoint("eject_document");
1354         scanner_stop_action(*dev);
1355         return;
1356     }
1357 
1358     if (gl841_get_paper_sensor(dev)) {
1359       DBG(DBG_info, "%s: paper still loaded\n", __func__);
1360       /* force document TRUE, because it is definitely present */
1361         dev->document = true;
1362         dev->set_head_pos_zero(ScanHeadId::PRIMARY);
1363 
1364       loop = 300;
1365       while (loop > 0)		/* do not wait longer then 30 seconds */
1366 	{
1367 
1368             if (!gl841_get_paper_sensor(dev)) {
1369                 DBG(DBG_info, "%s: reached home position\n", __func__);
1370                 break;
1371             }
1372           dev->interface->sleep_ms(100);
1373 	  --loop;
1374 	}
1375 
1376       if (loop == 0)
1377 	{
1378           // when we come here then the scanner needed too much time for this, so we better stop
1379           // the motor
1380           catch_all_exceptions(__func__, [&](){ scanner_stop_action(*dev); });
1381           throw SaneException(SANE_STATUS_IO_ERROR,
1382                               "timeout while waiting for scanhead to go home");
1383 	}
1384     }
1385 
1386     feed_mm = dev->model->eject_feed;
1387     if (dev->document) {
1388         feed_mm += dev->model->post_scan;
1389     }
1390 
1391         sanei_genesys_read_feed_steps(dev, &init_steps);
1392 
1393   /* now feed for extra <number> steps */
1394   loop = 0;
1395   while (loop < 300)		/* do not wait longer then 30 seconds */
1396     {
1397       unsigned int steps;
1398 
1399         sanei_genesys_read_feed_steps(dev, &steps);
1400 
1401       DBG(DBG_info, "%s: init_steps: %d, steps: %d\n", __func__, init_steps, steps);
1402 
1403       if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH)
1404 	{
1405 	  break;
1406 	}
1407 
1408         dev->interface->sleep_ms(100);
1409       ++loop;
1410     }
1411 
1412     scanner_stop_action(*dev);
1413 
1414     dev->document = false;
1415 }
1416 
update_home_sensor_gpio(Genesys_Device & dev) const1417 void CommandSetGl841::update_home_sensor_gpio(Genesys_Device& dev) const
1418 {
1419     if (dev.model->gpio_id == GpioId::CANON_LIDE_35) {
1420         dev.interface->read_register(REG_0x6C);
1421         dev.interface->write_register(REG_0x6C, dev.gpo.regs.get_value(0x6c));
1422     }
1423     if (dev.model->gpio_id == GpioId::CANON_LIDE_80) {
1424         dev.interface->read_register(REG_0x6B);
1425         dev.interface->write_register(REG_0x6B, REG_0x6B_GPO18 | REG_0x6B_GPO17);
1426     }
1427 }
1428 
load_document(Genesys_Device * dev) const1429 void CommandSetGl841::load_document(Genesys_Device* dev) const
1430 {
1431     DBG_HELPER(dbg);
1432   int loop = 300;
1433   while (loop > 0)		/* do not wait longer then 30 seconds */
1434     {
1435         if (gl841_get_paper_sensor(dev)) {
1436 	  DBG(DBG_info, "%s: document inserted\n", __func__);
1437 
1438 	  /* when loading OK, document is here */
1439         dev->document = true;
1440 
1441           // give user some time to place document correctly
1442           dev->interface->sleep_ms(1000);
1443 	  break;
1444 	}
1445         dev->interface->sleep_ms(100);
1446       --loop;
1447     }
1448 
1449   if (loop == 0)
1450     {
1451         // when we come here then the user needed to much time for this
1452         throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for document");
1453     }
1454 }
1455 
1456 /**
1457  * detects end of document and adjust current scan
1458  * to take it into account
1459  * used by sheetfed scanners
1460  */
detect_document_end(Genesys_Device * dev) const1461 void CommandSetGl841::detect_document_end(Genesys_Device* dev) const
1462 {
1463     DBG_HELPER(dbg);
1464     bool paper_loaded = gl841_get_paper_sensor(dev);
1465 
1466   /* sheetfed scanner uses home sensor as paper present */
1467     if (dev->document && !paper_loaded) {
1468       DBG(DBG_info, "%s: no more document\n", __func__);
1469         dev->document = false;
1470 
1471       /* we can't rely on total_bytes_to_read since the frontend
1472        * might have been slow to read data, so we re-evaluate the
1473        * amount of data to scan form the hardware settings
1474        */
1475         unsigned scanned_lines = 0;
1476         try {
1477             sanei_genesys_read_scancnt(dev, &scanned_lines);
1478         } catch (...) {
1479             dev->total_bytes_to_read = dev->total_bytes_read;
1480             throw;
1481         }
1482 
1483         if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS && dev->model->is_cis) {
1484             scanned_lines /= 3;
1485         }
1486 
1487         std::size_t output_lines = dev->session.output_line_count;
1488 
1489         std::size_t offset_lines = static_cast<std::size_t>(
1490                 (dev->model->post_scan / MM_PER_INCH) * dev->settings.yres);
1491 
1492         std::size_t scan_end_lines = scanned_lines + offset_lines;
1493 
1494         std::size_t remaining_lines = dev->get_pipeline_source().remaining_bytes() /
1495                 dev->session.output_line_bytes_raw;
1496 
1497         DBG(DBG_io, "%s: scanned_lines=%u\n", __func__, scanned_lines);
1498         DBG(DBG_io, "%s: scan_end_lines=%zu\n", __func__, scan_end_lines);
1499         DBG(DBG_io, "%s: output_lines=%zu\n", __func__, output_lines);
1500         DBG(DBG_io, "%s: remaining_lines=%zu\n", __func__, remaining_lines);
1501 
1502         if (scan_end_lines > output_lines) {
1503             auto skip_lines = scan_end_lines - output_lines;
1504 
1505             if (remaining_lines > skip_lines) {
1506                 remaining_lines -= skip_lines;
1507                 dev->get_pipeline_source().set_remaining_bytes(remaining_lines *
1508                                                                dev->session.output_line_bytes_raw);
1509                 dev->total_bytes_to_read -= skip_lines * dev->session.output_line_bytes_requested;
1510             }
1511         }
1512     }
1513 }
1514 
1515 // Send the low-level scan command
1516 // todo : is this that useful ?
begin_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,bool start_motor) const1517 void CommandSetGl841::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
1518                                  Genesys_Register_Set* reg, bool start_motor) const
1519 {
1520     DBG_HELPER(dbg);
1521     (void) sensor;
1522   // FIXME: SEQUENTIAL not really needed in this case
1523   Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
1524   uint8_t val;
1525 
1526     if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
1527         val = dev->interface->read_register(REG_0x6B);
1528         val = REG_0x6B_GPO18;
1529         dev->interface->write_register(REG_0x6B, val);
1530     }
1531 
1532     if (dev->model->model_id == ModelId::CANON_LIDE_50 ||
1533         dev->model->model_id == ModelId::CANON_LIDE_60)
1534     {
1535         if (dev->session.params.yres >= 1200) {
1536             dev->interface->write_register(REG_0x6C, 0x82);
1537         } else {
1538             dev->interface->write_register(REG_0x6C, 0x02);
1539         }
1540         if (dev->session.params.yres >= 600) {
1541             dev->interface->write_register(REG_0x6B, 0x01);
1542         } else {
1543             dev->interface->write_register(REG_0x6B, 0x03);
1544         }
1545     }
1546 
1547     if (dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
1548         local_reg.init_reg(0x03, reg->get8(0x03) | REG_0x03_LAMPPWR);
1549     } else {
1550         // TODO PLUSTEK_3600: why ??
1551         local_reg.init_reg(0x03, reg->get8(0x03));
1552     }
1553 
1554     local_reg.init_reg(0x01, reg->get8(0x01) | REG_0x01_SCAN);
1555     local_reg.init_reg(0x0d, 0x01);
1556 
1557     // scanner_start_action(dev, start_motor)
1558     if (start_motor) {
1559         local_reg.init_reg(0x0f, 0x01);
1560     } else {
1561         // do not start motor yet
1562         local_reg.init_reg(0x0f, 0x00);
1563     }
1564 
1565     dev->interface->write_registers(local_reg);
1566 
1567     dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
1568 }
1569 
1570 
1571 // Send the stop scan command
end_scan(Genesys_Device * dev,Genesys_Register_Set __sane_unused__ * reg,bool check_stop) const1572 void CommandSetGl841::end_scan(Genesys_Device* dev, Genesys_Register_Set __sane_unused__* reg,
1573                                bool check_stop) const
1574 {
1575     DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
1576 
1577     if (!dev->model->is_sheetfed) {
1578         scanner_stop_action(*dev);
1579     }
1580 }
1581 
1582 // Moves the slider to the home (top) position slowly
move_back_home(Genesys_Device * dev,bool wait_until_home) const1583 void CommandSetGl841::move_back_home(Genesys_Device* dev, bool wait_until_home) const
1584 {
1585     scanner_move_back_home(*dev, wait_until_home);
1586 }
1587 
1588 // init registers for shading calibration
init_regs_for_shading(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1589 void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
1590                                             Genesys_Register_Set& regs) const
1591 {
1592     DBG_HELPER(dbg);
1593 
1594     unsigned channels = 3;
1595 
1596     unsigned resolution = sensor.shading_resolution;
1597     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
1598                                                          dev->settings.scan_method);
1599 
1600     unsigned calib_lines =
1601             static_cast<unsigned>(dev->model->y_size_calib_dark_white_mm * resolution / MM_PER_INCH);
1602     unsigned starty =
1603             static_cast<unsigned>(dev->model->y_offset_calib_dark_white_mm * dev->motor.base_ydpi / MM_PER_INCH);
1604     ScanSession session;
1605     session.params.xres = resolution;
1606     session.params.yres = resolution;
1607     session.params.startx = 0;
1608     session.params.starty = starty;
1609     session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1610     session.params.lines = calib_lines;
1611     session.params.depth = 16;
1612     session.params.channels = channels;
1613     session.params.scan_method = dev->settings.scan_method;
1614     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1615     session.params.color_filter = dev->settings.color_filter;
1616     session.params.flags = ScanFlag::DISABLE_SHADING |
1617                            ScanFlag::DISABLE_GAMMA;
1618     compute_session(dev, session, calib_sensor);
1619 
1620     init_regs_for_scan_session(dev, calib_sensor, &regs, session);
1621 
1622     dev->calib_session = session;
1623 }
1624 
1625 // this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided
send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor) const1626 void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
1627 {
1628     DBG_HELPER(dbg);
1629   int size;
1630 
1631   size = 256;
1632 
1633   /* allocate temporary gamma tables: 16 bits words, 3 channels */
1634   std::vector<uint8_t> gamma(size * 2 * 3);
1635 
1636     sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data());
1637 
1638     dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
1639 }
1640 
1641 
1642 /* this function does the led calibration by scanning one line of the calibration
1643    area below scanner's top on white strip.
1644 
1645 -needs working coarse/gain
1646 */
led_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1647 SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1648                                                 Genesys_Register_Set& regs) const
1649 {
1650     return scanner_led_calibration(*dev, sensor, regs);
1651 }
1652 
1653 /** @brief calibration for AD frontend devices
1654  * offset calibration assumes that the scanning head is on a black area
1655  * For LiDE80 analog frontend
1656  * 0x0003 : is gain and belongs to [0..63]
1657  * 0x0006 : is offset
1658  * We scan a line with no gain until average offset reaches the target
1659  */
ad_fe_offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs)1660 static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1661                                      Genesys_Register_Set& regs)
1662 {
1663     DBG_HELPER(dbg);
1664   int average;
1665   int turn;
1666   int top;
1667   int bottom;
1668   int target;
1669 
1670   /* don't impact 3600 behavior since we can't test it */
1671     if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
1672       return;
1673     }
1674 
1675     unsigned resolution = sensor.shading_resolution;
1676 
1677     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3,
1678                                                               dev->settings.scan_method);
1679 
1680     unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1681     ScanSession session;
1682     session.params.xres = resolution;
1683     session.params.yres = dev->settings.yres;
1684     session.params.startx = 0;
1685     session.params.starty = 0;
1686     session.params.pixels = num_pixels;
1687     session.params.lines = 1;
1688     session.params.depth = 8;
1689     session.params.channels = 3;
1690     session.params.scan_method = dev->settings.scan_method;
1691     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1692     session.params.color_filter = dev->settings.color_filter;
1693     session.params.flags = ScanFlag::DISABLE_SHADING |
1694                            ScanFlag::DISABLE_GAMMA |
1695                            ScanFlag::SINGLE_LINE |
1696                            ScanFlag::IGNORE_STAGGER_OFFSET |
1697                            ScanFlag::IGNORE_COLOR_OFFSET;
1698     compute_session(dev, session, calib_sensor);
1699 
1700     dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &regs, session);
1701 
1702     // FIXME: we're reading twice as much data for no reason
1703     std::size_t total_size = session.output_line_bytes * 2;
1704     std::vector<uint8_t> line(total_size);
1705 
1706   dev->frontend.set_gain(0, 0);
1707   dev->frontend.set_gain(1, 0);
1708   dev->frontend.set_gain(2, 0);
1709 
1710   /* loop on scan until target offset is reached */
1711   turn=0;
1712   target=24;
1713   bottom=0;
1714   top=255;
1715   do {
1716       /* set up offset mid range */
1717       dev->frontend.set_offset(0, (top + bottom) / 2);
1718       dev->frontend.set_offset(1, (top + bottom) / 2);
1719       dev->frontend.set_offset(2, (top + bottom) / 2);
1720 
1721       /* scan line */
1722       DBG(DBG_info, "%s: starting line reading\n", __func__);
1723         dev->interface->write_registers(regs);
1724       dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1725         dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
1726 
1727         if (is_testing_mode()) {
1728             dev->interface->test_checkpoint("ad_fe_offset_calibration");
1729             scanner_stop_action(*dev);
1730             return;
1731         }
1732 
1733       sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
1734       scanner_stop_action(*dev);
1735       if (dbg_log_image_data()) {
1736           char fn[30];
1737           std::snprintf(fn, 30, "gl841_offset_%02d.tiff", turn);
1738           write_tiff_file(fn, line.data(), 8, 3, num_pixels, 1);
1739       }
1740 
1741       /* search for minimal value */
1742       average=0;
1743         for (std::size_t i = 0; i < total_size; i++)
1744         {
1745             average += line[i];
1746         }
1747       average/=total_size;
1748       DBG(DBG_data, "%s: average=%d\n", __func__, average);
1749 
1750       /* if min value is above target, the current value becomes the new top
1751        * else it is the new bottom */
1752       if(average>target)
1753         {
1754           top=(top+bottom)/2;
1755         }
1756       else
1757         {
1758           bottom=(top+bottom)/2;
1759         }
1760       turn++;
1761   } while ((top-bottom)>1 && turn < 100);
1762 
1763   // FIXME: don't overwrite the calibrated values
1764   dev->frontend.set_offset(0, 0);
1765   dev->frontend.set_offset(1, 0);
1766   dev->frontend.set_offset(2, 0);
1767   DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
1768       dev->frontend.get_offset(0),
1769       dev->frontend.get_offset(1),
1770       dev->frontend.get_offset(2));
1771 }
1772 
1773 /* this function does the offset calibration by scanning one line of the calibration
1774    area below scanner's top. There is a black margin and the remaining is white.
1775 
1776 this function expects the slider to be where?
1777 */
offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1778 void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1779                                          Genesys_Register_Set& regs) const
1780 {
1781     DBG_HELPER(dbg);
1782   int off[3],offh[3],offl[3],off1[3],off2[3];
1783   int min1[3],min2[3];
1784     unsigned cmin[3],cmax[3];
1785   int turn;
1786   int mintgt = 0x400;
1787 
1788   /* Analog Device fronted have a different calibration */
1789     if ((dev->reg.find_reg(0x04).value & REG_0x04_FESET) == 0x02) {
1790         ad_fe_offset_calibration(dev, sensor, regs);
1791         return;
1792     }
1793 
1794   /* offset calibration is always done in color mode */
1795     unsigned channels = 3;
1796 
1797     unsigned resolution = sensor.shading_resolution;
1798 
1799     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
1800                                                          dev->settings.scan_method);
1801 
1802     ScanSession session;
1803     session.params.xres = resolution;
1804     session.params.yres = dev->settings.yres;
1805     session.params.startx = 0;
1806     session.params.starty = 0;
1807     session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1808     session.params.lines = 1;
1809     session.params.depth = 16;
1810     session.params.channels = channels;
1811     session.params.scan_method = dev->settings.scan_method;
1812     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1813     session.params.color_filter = dev->settings.color_filter;
1814     session.params.flags = ScanFlag::DISABLE_SHADING |
1815                            ScanFlag::DISABLE_GAMMA |
1816                            ScanFlag::SINGLE_LINE |
1817                            ScanFlag::IGNORE_STAGGER_OFFSET |
1818                            ScanFlag::IGNORE_COLOR_OFFSET |
1819                            ScanFlag::DISABLE_LAMP;
1820     compute_session(dev, session, calib_sensor);
1821 
1822     init_regs_for_scan_session(dev, calib_sensor, &regs, session);
1823 
1824   /* scan first line of data with no offset nor gain */
1825 /*WM8199: gain=0.73; offset=-260mV*/
1826 /*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/
1827 /* we should probably do real calibration here:
1828  * -detect acceptable offset with binary search
1829  * -calculate offset from this last version
1830  *
1831  * acceptable offset means
1832  *   - few completely black pixels(<10%?)
1833  *   - few completely white pixels(<10%?)
1834  *
1835  * final offset should map the minimum not completely black
1836  * pixel to 0(16 bits)
1837  *
1838  * this does account for dummy pixels at the end of ccd
1839  * this assumes slider is at black strip(which is not quite as black as "no
1840  * signal").
1841  *
1842  */
1843   dev->frontend.set_gain(0, 0);
1844   dev->frontend.set_gain(1, 0);
1845   dev->frontend.set_gain(2, 0);
1846   offh[0] = 0xff;
1847   offh[1] = 0xff;
1848   offh[2] = 0xff;
1849   offl[0] = 0x00;
1850   offl[1] = 0x00;
1851   offl[2] = 0x00;
1852   turn = 0;
1853 
1854     Image first_line;
1855 
1856     bool acceptable = false;
1857   do {
1858 
1859         dev->interface->write_registers(regs);
1860 
1861         for (unsigned j = 0; j < channels; j++) {
1862 	  off[j] = (offh[j]+offl[j])/2;
1863           dev->frontend.set_offset(j, off[j]);
1864       }
1865 
1866         dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1867 
1868       DBG(DBG_info, "%s: starting first line reading\n", __func__);
1869         dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
1870 
1871         if (is_testing_mode()) {
1872             dev->interface->test_checkpoint("offset_calibration");
1873             return;
1874         }
1875 
1876         first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
1877 
1878         if (dbg_log_image_data()) {
1879             char fn[30];
1880             std::snprintf(fn, 30, "gl841_offset1_%02d.tiff", turn);
1881             write_tiff_file(fn, first_line);
1882         }
1883 
1884         acceptable = true;
1885 
1886         for (unsigned ch = 0; ch < channels; ch++) {
1887             cmin[ch] = 0;
1888             cmax[ch] = 0;
1889 
1890             for (std::size_t x = 0; x < first_line.get_width(); x++) {
1891                 auto value = first_line.get_raw_channel(x, 0, ch);
1892                 if (value < 10) {
1893                     cmin[ch]++;
1894                 }
1895                 if (value > 65525) {
1896                     cmax[ch]++;
1897                 }
1898             }
1899 
1900           /* TODO the DP685 has a black strip in the middle of the sensor
1901            * should be handled in a more elegant way , could be a bug */
1902             if (dev->model->sensor_id == SensorId::CCD_DP685) {
1903                 cmin[ch] -= 20;
1904             }
1905 
1906             if (cmin[ch] > first_line.get_width() / 100) {
1907           acceptable = false;
1908 	      if (dev->model->is_cis)
1909 		  offl[0] = off[0];
1910 	      else
1911           offl[ch] = off[ch];
1912             }
1913             if (cmax[ch] > first_line.get_width() / 100) {
1914           acceptable = false;
1915 	      if (dev->model->is_cis)
1916 		  offh[0] = off[0];
1917 	      else
1918           offh[ch] = off[ch];
1919             }
1920         }
1921 
1922       DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
1923           cmin[1], cmax[1], cmin[2], cmax[2]);
1924 
1925       if (dev->model->is_cis) {
1926 	  offh[2] = offh[1] = offh[0];
1927 	  offl[2] = offl[1] = offl[0];
1928       }
1929 
1930         scanner_stop_action(*dev);
1931 
1932       turn++;
1933   } while (!acceptable && turn < 100);
1934 
1935   DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
1936 
1937 
1938     for (unsigned ch = 0; ch < channels; ch++) {
1939         off1[ch] = off[ch];
1940 
1941         min1[ch] = 65536;
1942 
1943         for (std::size_t x = 0; x < first_line.get_width(); x++) {
1944             auto value = first_line.get_raw_channel(x, 0, ch);
1945 
1946             if (min1[ch] > value && value >= 10) {
1947                 min1[ch] = value;
1948             }
1949         }
1950     }
1951 
1952 
1953   offl[0] = off[0];
1954   offl[1] = off[0];
1955   offl[2] = off[0];
1956   turn = 0;
1957 
1958     Image second_line;
1959   do {
1960 
1961         for (unsigned j=0; j < channels; j++) {
1962 	  off[j] = (offh[j]+offl[j])/2;
1963           dev->frontend.set_offset(j, off[j]);
1964         }
1965 
1966         dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1967 
1968       DBG(DBG_info, "%s: starting second line reading\n", __func__);
1969         dev->interface->write_registers(regs);
1970         dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
1971         second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
1972 
1973         if (dbg_log_image_data()) {
1974             char fn[30];
1975             std::snprintf(fn, 30, "gl841_offset2_%02d.tiff", turn);
1976             write_tiff_file(fn, second_line);
1977         }
1978 
1979         acceptable = true;
1980 
1981         for (unsigned ch = 0; ch < channels; ch++) {
1982             cmin[ch] = 0;
1983             cmax[ch] = 0;
1984 
1985             for (std::size_t x = 0; x < second_line.get_width(); x++) {
1986                 auto value = second_line.get_raw_channel(x, 0, ch);
1987 
1988                 if (value < 10) {
1989                     cmin[ch]++;
1990                 }
1991                 if (value > 65525) {
1992                     cmax[ch]++;
1993                 }
1994             }
1995 
1996             if (cmin[ch] > second_line.get_width() / 100) {
1997             acceptable = false;
1998 	      if (dev->model->is_cis)
1999 		  offl[0] = off[0];
2000 	      else
2001                     offl[ch] = off[ch];
2002             }
2003             if (cmax[ch] > second_line.get_width() / 100) {
2004             acceptable = false;
2005 	      if (dev->model->is_cis)
2006 		  offh[0] = off[0];
2007 	      else
2008                 offh[ch] = off[ch];
2009             }
2010         }
2011 
2012       DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
2013           cmin[1], cmax[1], cmin[2], cmax[2]);
2014 
2015       if (dev->model->is_cis) {
2016 	  offh[2] = offh[1] = offh[0];
2017 	  offl[2] = offl[1] = offl[0];
2018       }
2019 
2020         scanner_stop_action(*dev);
2021 
2022       turn++;
2023 
2024   } while (!acceptable && turn < 100);
2025 
2026   DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
2027 
2028 
2029     for (unsigned ch = 0; ch < channels; ch++) {
2030         off2[ch] = off[ch];
2031 
2032         min2[ch] = 65536;
2033 
2034         for (std::size_t x = 0; x < second_line.get_width(); x++) {
2035             auto value = second_line.get_raw_channel(x, 0, ch);
2036 
2037             if (min2[ch] > value && value != 0) {
2038                 min2[ch] = value;
2039             }
2040         }
2041     }
2042 
2043   DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1],
2044       off1[2], min1[2]);
2045 
2046   DBG(DBG_info, "%s: second set: %d/%d,%d/%d,%d/%d\n", __func__, off2[0], min2[0], off2[1], min2[1],
2047       off2[2], min2[2]);
2048 
2049 /*
2050   calculate offset for each channel
2051   based on minimal pixel value min1 at offset off1 and minimal pixel value min2
2052   at offset off2
2053 
2054   to get min at off, values are linearly interpolated:
2055   min=real+off*fact
2056   min1=real+off1*fact
2057   min2=real+off2*fact
2058 
2059   fact=(min1-min2)/(off1-off2)
2060   real=min1-off1*(min1-min2)/(off1-off2)
2061 
2062   off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2))
2063 
2064   off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2)
2065 
2066  */
2067     for (unsigned ch = 0; ch < channels; ch++) {
2068         if (min2[ch] - min1[ch] == 0) {
2069 /*TODO: try to avoid this*/
2070 	  DBG(DBG_warn, "%s: difference too small\n", __func__);
2071             if (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch] >= 0) {
2072                 off[ch] = 0x0000;
2073             } else {
2074                 off[ch] = 0xffff;
2075             }
2076         } else {
2077             off[ch] = (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch])/(min1[ch]-min2[ch]);
2078         }
2079         if (off[ch] > 255) {
2080             off[ch] = 255;
2081         }
2082         if (off[ch] < 0) {
2083             off[ch] = 0;
2084         }
2085       dev->frontend.set_offset(ch, off[ch]);
2086   }
2087 
2088   DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
2089 
2090   if (dev->model->is_cis) {
2091       if (off[0] < off[1])
2092 	  off[0] = off[1];
2093       if (off[0] < off[2])
2094 	  off[0] = off[2];
2095       dev->frontend.set_offset(0, off[0]);
2096       dev->frontend.set_offset(1, off[0]);
2097       dev->frontend.set_offset(2, off[0]);
2098   }
2099 
2100   if (channels == 1)
2101     {
2102       dev->frontend.set_offset(1, dev->frontend.get_offset(0));
2103       dev->frontend.set_offset(2, dev->frontend.get_offset(0));
2104     }
2105 }
2106 
2107 
2108 /* alternative coarse gain calibration
2109    this on uses the settings from offset_calibration and
2110    uses only one scanline
2111  */
2112 /*
2113   with offset and coarse calibration we only want to get our input range into
2114   a reasonable shape. the fine calibration of the upper and lower bounds will
2115   be done with shading.
2116  */
coarse_gain_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,int dpi) const2117 void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
2118                                               Genesys_Register_Set& regs, int dpi) const
2119 {
2120     scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
2121 }
2122 
2123 // wait for lamp warmup by scanning the same line until difference
2124 // between 2 scans is below a threshold
init_regs_for_warmup(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * local_reg) const2125 void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
2126                                            Genesys_Register_Set* local_reg) const
2127 {
2128     DBG_HELPER(dbg);
2129     int num_pixels = 4 * 300;
2130   *local_reg = dev->reg;
2131 
2132 /* okay.. these should be defaults stored somewhere */
2133   dev->frontend.set_gain(0, 0);
2134   dev->frontend.set_gain(1, 0);
2135   dev->frontend.set_gain(2, 0);
2136   dev->frontend.set_offset(0, 0x80);
2137   dev->frontend.set_offset(1, 0x80);
2138   dev->frontend.set_offset(2, 0x80);
2139 
2140     auto flags = ScanFlag::DISABLE_SHADING |
2141                  ScanFlag::DISABLE_GAMMA |
2142                  ScanFlag::SINGLE_LINE |
2143                  ScanFlag::IGNORE_STAGGER_OFFSET |
2144                  ScanFlag::IGNORE_COLOR_OFFSET;
2145     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
2146         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
2147     {
2148         flags |= ScanFlag::USE_XPA;
2149     }
2150 
2151     ScanSession session;
2152     session.params.xres = sensor.full_resolution;
2153     session.params.yres = dev->settings.yres;
2154     session.params.startx = sensor.dummy_pixel;
2155     session.params.starty = 0;
2156     session.params.pixels = num_pixels;
2157     session.params.lines = 1;
2158     session.params.depth = dev->model->bpp_color_values.front();
2159     session.params.channels = 3;
2160     session.params.scan_method = dev->settings.scan_method;
2161     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
2162     session.params.color_filter = dev->settings.color_filter;
2163     session.params.flags = flags;
2164 
2165     compute_session(dev, session, sensor);
2166 
2167     init_regs_for_scan_session(dev, sensor, local_reg, session);
2168 }
2169 
2170 /*
2171  * initialize ASIC : registers, motor tables, and gamma tables
2172  * then ensure scanner's head is at home
2173  */
init(Genesys_Device * dev) const2174 void CommandSetGl841::init(Genesys_Device* dev) const
2175 {
2176     DBG_INIT();
2177     DBG_HELPER(dbg);
2178     sanei_genesys_asic_init(dev);
2179 }
2180 
update_hardware_sensors(Genesys_Scanner * s) const2181 void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const
2182 {
2183     DBG_HELPER(dbg);
2184   /* do what is needed to get a new set of events, but try to not lose
2185      any of them.
2186    */
2187   uint8_t val;
2188 
2189     if (s->dev->model->gpio_id == GpioId::CANON_LIDE_35
2190         || s->dev->model->gpio_id == GpioId::CANON_LIDE_80)
2191     {
2192         val = s->dev->interface->read_register(REG_0x6D);
2193         s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0);
2194         s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0);
2195         s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0);
2196         s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0);
2197     }
2198 
2199     if (s->dev->model->gpio_id == GpioId::XP300 ||
2200         s->dev->model->gpio_id == GpioId::DP665 ||
2201         s->dev->model->gpio_id == GpioId::DP685)
2202     {
2203         val = s->dev->interface->read_register(REG_0x6D);
2204 
2205         s->buttons[BUTTON_PAGE_LOADED_SW].write((val & 0x01) == 0);
2206         s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0);
2207     }
2208 }
2209 
2210 /**
2211  * Send shading calibration data. The buffer is considered to always hold values
2212  * for all the channels.
2213  */
send_shading_data(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t * data,int size) const2214 void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
2215                                         uint8_t* data, int size) const
2216 {
2217     DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
2218   uint32_t length, x, pixels, i;
2219   uint8_t *ptr,*src;
2220 
2221   /* old method if no SHDAREA */
2222     if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) == 0) {
2223         // Note that this requires the sensor pixel offset to be exactly the same as to start
2224         // reading from dummy_pixel + 1 position.
2225         dev->interface->write_buffer(0x3c, 0x0000, data, size);
2226         return;
2227     }
2228 
2229   /* data is whole line, we extract only the part for the scanned area */
2230     length = static_cast<std::uint32_t>(size / 3);
2231 
2232     // turn pixel value into bytes 2x16 bits words
2233     pixels = dev->session.pixel_endx - dev->session.pixel_startx;
2234     pixels *= 4;
2235 
2236     // shading pixel begin is start pixel minus start pixel during shading
2237     // calibration. Currently only cases handled are full and half ccd resolution.
2238     unsigned beginpixel = dev->session.params.startx * dev->session.optical_resolution /
2239             dev->session.params.xres;
2240     beginpixel *= 4;
2241     beginpixel /= sensor.shading_factor;
2242 
2243     dev->interface->record_key_value("shading_offset", std::to_string(beginpixel));
2244     dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
2245     dev->interface->record_key_value("shading_length", std::to_string(length));
2246 
2247   DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n", __func__, length,
2248       length/4);
2249   std::vector<uint8_t> buffer(pixels, 0);
2250 
2251   /* write actual shading data contigously
2252    * channel by channel, starting at addr 0x0000
2253    * */
2254   for(i=0;i<3;i++)
2255     {
2256       /* copy data to work buffer and process it */
2257           /* coefficient destination */
2258       ptr=buffer.data();
2259 
2260       /* iterate on both sensor segment, data has been averaged,
2261        * so is in the right order and we only have to copy it */
2262       for(x=0;x<pixels;x+=4)
2263         {
2264           /* coefficient source */
2265             src = data + x + beginpixel + i * length;
2266           ptr[0]=src[0];
2267           ptr[1]=src[1];
2268           ptr[2]=src[2];
2269           ptr[3]=src[3];
2270 
2271           /* next shading coefficient */
2272           ptr+=4;
2273         }
2274 
2275         // 0x5400 alignment for LIDE80 internal memory
2276         dev->interface->write_buffer(0x3c, 0x5400 * i, buffer.data(), pixels);
2277     }
2278 }
2279 
needs_home_before_init_regs_for_scan(Genesys_Device * dev) const2280 bool CommandSetGl841::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
2281 {
2282     (void) dev;
2283     return true;
2284 }
2285 
wait_for_motor_stop(Genesys_Device * dev) const2286 void CommandSetGl841::wait_for_motor_stop(Genesys_Device* dev) const
2287 {
2288     (void) dev;
2289 }
2290 
asic_boot(Genesys_Device * dev,bool cold) const2291 void CommandSetGl841::asic_boot(Genesys_Device *dev, bool cold) const
2292 {
2293     // reset ASIC in case of cold boot
2294     if (cold) {
2295         dev->interface->write_register(0x0e, 0x01);
2296         dev->interface->write_register(0x0e, 0x00);
2297     }
2298 
2299     gl841_init_registers(dev);
2300 
2301     // Write initial registers
2302     dev->interface->write_registers(dev->reg);
2303 
2304     // FIXME: 0x0b is not set, but on all other backends we do set it
2305     // dev->reg.remove_reg(0x0b);
2306 
2307     if (dev->model->model_id == ModelId::CANON_LIDE_60) {
2308         dev->interface->write_0x8c(0x10, 0xa4);
2309     }
2310 
2311     // FIXME: we probably don't need this
2312     const auto& sensor = sanei_genesys_find_sensor_any(dev);
2313     dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
2314 }
2315 
2316 } // namespace gl841
2317 } // namespace genesys
2318