1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
4 Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
5
6 This file is part of the SANE package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 As a special exception, the authors of SANE give permission for
22 additional uses of the libraries contained in this release of SANE.
23 */
24
25 #define DEBUG_DECLARE_ONLY
26
27 #include "gl842_registers.h"
28 #include "gl842.h"
29 #include "test_settings.h"
30
31 #include <string>
32 #include <vector>
33
34 namespace genesys {
35 namespace gl842 {
36
gl842_init_registers(Genesys_Device & dev)37 static void gl842_init_registers(Genesys_Device& dev)
38 {
39 // Within this function SENSOR_DEF marker documents that a register is part
40 // of the sensors definition and the actual value is set in
41 // gl842_setup_sensor().
42
43 DBG_HELPER(dbg);
44
45 dev.reg.clear();
46
47 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
48 dev.reg.init_reg(0x01, 0x00);
49 dev.reg.init_reg(0x02, 0x78);
50 dev.reg.init_reg(0x03, 0xbf);
51 dev.reg.init_reg(0x04, 0x22);
52 dev.reg.init_reg(0x05, 0x48);
53
54 dev.reg.init_reg(0x06, 0xb8);
55
56 dev.reg.init_reg(0x07, 0x00);
57 dev.reg.init_reg(0x08, 0x00);
58 dev.reg.init_reg(0x09, 0x00);
59 dev.reg.init_reg(0x0a, 0x00);
60 dev.reg.init_reg(0x0d, 0x01);
61 } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
62 dev.reg.init_reg(0x01, 0x82);
63 dev.reg.init_reg(0x02, 0x10);
64 dev.reg.init_reg(0x03, 0x60);
65 dev.reg.init_reg(0x04, 0x10);
66 dev.reg.init_reg(0x05, 0x8c);
67
68 dev.reg.init_reg(0x06, 0x18);
69
70 //dev.reg.init_reg(0x07, 0x00);
71 dev.reg.init_reg(0x08, 0x00);
72 dev.reg.init_reg(0x09, 0x21);
73 dev.reg.init_reg(0x0a, 0x00);
74 dev.reg.init_reg(0x0d, 0x00);
75 }
76
77 dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
78 dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
79 dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
80 dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
81 dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
82 dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
83
84 // CCD signal settings.
85 dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF
86 dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF
87 dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF
88
89 // EXPDMY[0:7]: Exposure time of dummy lines.
90 dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF
91
92 // Various CCD clock settings.
93 dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
94 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
95 dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
96 }
97 dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
98 dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
99 dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
100
101 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
102 dev.reg.init_reg(0x1f, 0x01);
103 dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
104 } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
105 dev.reg.init_reg(0x1f, 0x02);
106 dev.reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition
107 }
108
109 dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
110 dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup
111 dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup
112 dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
113 dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
114 dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
115 dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
116
117 dev.reg.init_reg(0x29, 0xff); // LAMPPWM
118
119 dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup
120 dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup
121
122 dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
123 dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
124
125 dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
126 dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup
127 dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup
128 dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup
129
130 dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF
131 dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
132 dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
133 dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
134 dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
135 dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
136 dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
137 dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
138 dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
139
140 dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF
141 dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF
142 dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF
143 dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF
144 dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF
145 dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF
146 dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF
147 dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
148 dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
149
150 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
151 dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
152 } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
153 dev.reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
154 dev.reg.init_reg(0x5d, 0x20);
155 }
156 dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
157
158 dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
159 dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
160 dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
161 dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
162 dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
163 dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
164
165 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
166 dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: partially overwritten during motor setup
167 dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: partially overwritten during motor setup
168 } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
169 dev.reg.init_reg(0x66, 0x00); // PHFREQ
170 dev.reg.init_reg(0x67, 0x40); // STEPSEL, MTRPWM: partially overwritten during motor setup
171 dev.reg.init_reg(0x68, 0x40); // FSTPSEL, FASTPWM: partially overwritten during motor setup
172 }
173 dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
174 dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
175
176 // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio.
177
178 dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF
179 dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF
180 dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF
181 dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF
182 dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF
183 dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF
184 dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF
185 dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF
186 dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF
187 dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF
188 dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF
189 dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF
190 dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF
191 dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF
192
193 // 0x7e - set according to gpio tables. See gl842_init_gpio.
194
195 dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF
196
197 // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
198 // moving in various situations.
199 dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
200
201 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
202 dev.reg.init_reg(0x81, 0x00);
203 dev.reg.init_reg(0x82, 0x00);
204 dev.reg.init_reg(0x83, 0x00);
205 dev.reg.init_reg(0x84, 0x00);
206 dev.reg.init_reg(0x85, 0x00);
207 dev.reg.init_reg(0x86, 0x00);
208 dev.reg.init_reg(0x87, 0x00);
209 } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
210 dev.reg.init_reg(0x7e, 0x00);
211 dev.reg.init_reg(0x81, 0x00);
212 dev.reg.init_reg(0x82, 0x0f);
213 dev.reg.init_reg(0x83, 0x00);
214 dev.reg.init_reg(0x84, 0x0e);
215 dev.reg.init_reg(0x85, 0x00);
216 dev.reg.init_reg(0x86, 0x0d);
217 dev.reg.init_reg(0x87, 0x00);
218 dev.reg.init_reg(0x88, 0x00);
219 dev.reg.init_reg(0x89, 0x00);
220 }
221
222 const auto& sensor = sanei_genesys_find_sensor_any(&dev);
223 sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
224
225 scanner_setup_sensor(dev, sensor, dev.reg);
226 }
227
228 // Set values of analog frontend
set_fe(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t set) const229 void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
230 {
231 DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
232 set == AFE_SET ? "set" :
233 set == AFE_POWER_SAVE ? "powersave" : "huh?");
234 (void) sensor;
235
236 if (set == AFE_INIT) {
237 dev->frontend = dev->frontend_initial;
238 }
239
240 // check analog frontend type
241 // FIXME: looks like we write to that register with initial data
242 uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
243 if (fe_type == 2 || dev->model->model_id == ModelId::CANON_LIDE_90) {
244 for (const auto& reg : dev->frontend.regs) {
245 dev->interface->write_fe_register(reg.address, reg.value);
246 }
247 return;
248 }
249 if (fe_type != 0) {
250 throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
251 }
252
253 for (unsigned i = 1; i <= 3; i++) {
254 dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
255 }
256 for (const auto& reg : sensor.custom_fe_regs) {
257 dev->interface->write_fe_register(reg.address, reg.value);
258 }
259
260 for (unsigned i = 0; i < 3; i++) {
261 dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
262 }
263
264 for (unsigned i = 0; i < 3; i++) {
265 dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
266 }
267 }
268
gl842_init_motor_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,const ScanSession & session,Genesys_Register_Set * reg,const MotorProfile & motor_profile,unsigned int exposure,unsigned scan_yres,unsigned int scan_lines,unsigned int scan_dummy,unsigned int feed_steps,ScanFlag flags)269 static void gl842_init_motor_regs_scan(Genesys_Device* dev,
270 const Genesys_Sensor& sensor,
271 const ScanSession& session,
272 Genesys_Register_Set* reg,
273 const MotorProfile& motor_profile,
274 unsigned int exposure,
275 unsigned scan_yres,
276 unsigned int scan_lines,
277 unsigned int scan_dummy,
278 unsigned int feed_steps,
279 ScanFlag flags)
280 {
281 DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
282 "feed_steps=%d, flags=%x",
283 exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
284 scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
285
286 unsigned step_multiplier = 2;
287 bool use_fast_fed = false;
288
289 if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
290 use_fast_fed = true;
291 }
292 if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
293 use_fast_fed = false;
294 }
295
296 reg->set24(REG_LINCNT, scan_lines);
297
298 reg->set8(REG_0x02, 0);
299 sanei_genesys_set_motor_power(*reg, true);
300
301 std::uint8_t reg02 = reg->get8(REG_0x02);
302 if (use_fast_fed) {
303 reg02 |= REG_0x02_FASTFED;
304 } else {
305 reg02 &= ~REG_0x02_FASTFED;
306 }
307
308 // in case of automatic go home, move until home sensor
309 if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
310 reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
311 }
312
313 // disable backtracking if needed
314 if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
315 (scan_yres >= 2400) ||
316 (scan_yres >= sensor.full_resolution))
317 {
318 reg02 |= REG_0x02_ACDCDIS;
319 }
320
321 if (has_flag(flags, ScanFlag::REVERSE)) {
322 reg02 |= REG_0x02_MTRREV;
323 } else {
324 reg02 &= ~REG_0x02_MTRREV;
325 }
326 reg->set8(REG_0x02, reg02);
327
328 // scan and backtracking slope table
329 auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
330 step_multiplier, motor_profile);
331
332 scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
333 scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
334 scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
335
336 reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
337 reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
338 reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
339
340 // fast table
341 const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
342 if (fast_profile == nullptr) {
343 fast_profile = &motor_profile;
344 }
345
346 auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
347 *fast_profile);
348
349 scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
350 scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
351
352 reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
353
354 if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
355 std::uint8_t vref = 0;
356 vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
357 vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
358 vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
359 vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
360 reg->set8(REG_0x80, vref);
361 }
362
363 // subtract acceleration distance from feedl
364 unsigned feedl = feed_steps;
365 feedl <<= static_cast<unsigned>(motor_profile.step_type);
366
367 unsigned dist = scan_table.table.size() / step_multiplier;
368
369 if (use_fast_fed) {
370 dist += (fast_table.table.size() / step_multiplier) * 2;
371 }
372
373 // make sure when don't insane value : XXX STEF XXX in this case we should
374 // fall back to single table move
375 if (dist < feedl) {
376 feedl -= dist;
377 } else {
378 feedl = 1;
379 }
380
381 reg->set24(REG_FEEDL, feedl);
382
383 // doesn't seem to matter that much
384 std::uint32_t z1, z2;
385 sanei_genesys_calculate_zmod(use_fast_fed,
386 exposure,
387 scan_table.table,
388 scan_table.table.size() / step_multiplier,
389 feedl,
390 scan_table.table.size() / step_multiplier,
391 &z1,
392 &z2);
393 if (scan_yres > 600) {
394 z1 = 0;
395 z2 = 0;
396 }
397
398 reg->set24(REG_Z1MOD, z1);
399 reg->set24(REG_Z2MOD, z2);
400
401 reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
402
403 reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL,
404 REG_0x67_STEPSEL);
405 reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL,
406 REG_0x68_FSTPSEL);
407
408 // steps for STOP table
409 reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
410 }
411
gl842_init_optical_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int exposure,const ScanSession & session)412 static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
413 Genesys_Register_Set* reg, unsigned int exposure,
414 const ScanSession& session)
415 {
416 DBG_HELPER(dbg);
417
418 scanner_setup_sensor(*dev, sensor, *reg);
419
420 dev->cmd_set->set_fe(dev, sensor, AFE_SET);
421
422 // enable shading
423 regs_set_optical_off(dev->model->asic_type, *reg);
424 if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
425 has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
426 session.use_host_side_calib)
427 {
428 reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
429
430 } else {
431 reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
432 }
433
434 bool use_shdarea = true;
435
436 if (use_shdarea) {
437 reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
438 } else {
439 reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
440 }
441
442 if (dev->model->model_id == ModelId::CANON_8600F) {
443 reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
444 } else {
445 reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
446 }
447
448 // FIXME: we probably don't need to set exposure to registers at this point. It was this way
449 // before a refactor.
450 sanei_genesys_set_lamp_power(dev, sensor, *reg,
451 !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
452
453 // select XPA
454 reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
455 if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
456 reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
457 }
458 reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
459
460 // BW threshold
461 reg->set8(REG_0x2E, 0x7f);
462 reg->set8(REG_0x2F, 0x7f);
463
464 // monochrome / color scan parameters
465 std::uint8_t reg04 = reg->get8(REG_0x04);
466 reg04 = reg04 & REG_0x04_FESET;
467
468 switch (session.params.depth) {
469 case 8:
470 break;
471 case 16:
472 reg04 |= REG_0x04_BITSET;
473 break;
474 }
475
476 if (session.params.channels == 1) {
477 switch (session.params.color_filter) {
478 case ColorFilter::RED: reg04 |= 0x14; break;
479 case ColorFilter::BLUE: reg04 |= 0x1c; break;
480 case ColorFilter::GREEN: reg04 |= 0x18; break;
481 default:
482 break; // should not happen
483 }
484 } else {
485 switch (dev->frontend.layout.type) {
486 case FrontendType::WOLFSON:
487 // pixel by pixel
488 reg04 |= 0x10;
489 break;
490 case FrontendType::ANALOG_DEVICES:
491 // slow color pixel by pixel
492 reg04 |= 0x20;
493 break;
494 default:
495 throw SaneException("Invalid frontend type %d",
496 static_cast<unsigned>(dev->frontend.layout.type));
497 }
498 }
499
500 reg->set8(REG_0x04, reg04);
501
502 const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
503 session.params.channels,
504 session.params.scan_method);
505 sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
506
507 if (should_enable_gamma(session, sensor)) {
508 reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
509 } else {
510 reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
511 }
512
513 reg->set16(REG_DPISET, sensor.register_dpiset);
514
515 reg->set16(REG_STRPIXEL, session.pixel_startx);
516 reg->set16(REG_ENDPIXEL, session.pixel_endx);
517
518 if (dev->model->is_cis) {
519 reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels);
520 } else {
521 reg->set24(REG_MAXWD, session.output_line_bytes_raw);
522 }
523
524 unsigned tgtime = exposure / 65536 + 1;
525 reg->set16(REG_LPERIOD, exposure / tgtime);
526
527 reg->set8(REG_DUMMY, sensor.dummy_pixel);
528 }
529
init_regs_for_scan_session(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,const ScanSession & session) const530 void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
531 Genesys_Register_Set* reg,
532 const ScanSession& session) const
533 {
534 DBG_HELPER(dbg);
535 session.assert_computed();
536
537 // we enable true gray for cis scanners only, and just when doing scan since color calibration
538 // is OK for this mode
539
540 int dummy = 0;
541
542 /* slope_dpi */
543 /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */
544 int slope_dpi = 0;
545 if (dev->model->is_cis) {
546 slope_dpi = session.params.yres * session.params.channels;
547 } else {
548 slope_dpi = session.params.yres;
549 }
550 slope_dpi = slope_dpi * (1 + dummy);
551
552 int exposure = sensor.exposure_lperiod;
553 if (exposure < 0) {
554 throw std::runtime_error("Exposure not defined in sensor definition");
555 }
556 if (dev->model->model_id == ModelId::CANON_LIDE_90) {
557 exposure *= 2;
558 }
559 const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
560
561 // now _LOGICAL_ optical values used are known, setup registers
562 gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session);
563 gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
564 session.optical_line_count, dummy, session.params.starty,
565 session.params.flags);
566
567 setup_image_pipeline(*dev, session);
568
569 dev->read_active = true;
570
571 dev->session = session;
572
573 dev->total_bytes_read = 0;
574 dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
575 }
576
calculate_scan_session(const Genesys_Device * dev,const Genesys_Sensor & sensor,const Genesys_Settings & settings) const577 ScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev,
578 const Genesys_Sensor& sensor,
579 const Genesys_Settings& settings) const
580 {
581 DBG_HELPER(dbg);
582 debug_dump(DBG_info, settings);
583
584 ScanFlag flags = ScanFlag::NONE;
585
586 float move = 0.0f;
587 if (settings.scan_method == ScanMethod::TRANSPARENCY ||
588 settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
589 {
590 // note: scanner_move_to_ta() function has already been called and the sensor is at the
591 // transparency adapter
592 if (!dev->ignore_offsets) {
593 move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
594 }
595 flags |= ScanFlag::USE_XPA;
596 } else {
597 if (!dev->ignore_offsets) {
598 move = dev->model->y_offset;
599 }
600 }
601
602 move += settings.tl_y;
603
604 int move_dpi = dev->motor.base_ydpi;
605 move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
606
607 float start = 0.0f;
608 if (settings.scan_method==ScanMethod::TRANSPARENCY ||
609 settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
610 {
611 start = dev->model->x_offset_ta;
612 } else {
613 start = dev->model->x_offset;
614 }
615 start = start + settings.tl_x;
616
617 start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
618
619 ScanSession session;
620 session.params.xres = settings.xres;
621 session.params.yres = settings.yres;
622 session.params.startx = static_cast<unsigned>(start);
623 session.params.starty = static_cast<unsigned>(move);
624 session.params.pixels = settings.pixels;
625 session.params.requested_pixels = settings.requested_pixels;
626 session.params.lines = settings.lines;
627 session.params.depth = settings.depth;
628 session.params.channels = settings.get_channels();
629 session.params.scan_method = settings.scan_method;
630 session.params.scan_mode = settings.scan_mode;
631 session.params.color_filter = settings.color_filter;
632 session.params.flags = flags;
633 compute_session(dev, session, sensor);
634
635 return session;
636 }
637
save_power(Genesys_Device * dev,bool enable) const638 void CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const
639 {
640 (void) dev;
641 DBG_HELPER_ARGS(dbg, "enable = %d", enable);
642 }
643
set_powersaving(Genesys_Device * dev,int delay) const644 void CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
645 {
646 (void) dev;
647 DBG_HELPER_ARGS(dbg, "delay = %d", delay);
648 }
649
eject_document(Genesys_Device * dev) const650 void CommandSetGl842::eject_document(Genesys_Device* dev) const
651 {
652 (void) dev;
653 DBG_HELPER(dbg);
654 }
655
656
load_document(Genesys_Device * dev) const657 void CommandSetGl842::load_document(Genesys_Device* dev) const
658 {
659 DBG_HELPER(dbg);
660 (void) dev;
661 }
662
detect_document_end(Genesys_Device * dev) const663 void CommandSetGl842::detect_document_end(Genesys_Device* dev) const
664 {
665 DBG_HELPER(dbg);
666 (void) dev;
667 throw SaneException(SANE_STATUS_UNSUPPORTED);
668 }
669
670 // Send the low-level scan command
begin_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,bool start_motor) const671 void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
672 Genesys_Register_Set* reg, bool start_motor) const
673 {
674 DBG_HELPER(dbg);
675 (void) sensor;
676
677 if (reg->state.is_xpa_on && reg->state.is_lamp_on &&
678 !has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP))
679 {
680 dev->cmd_set->set_xpa_lamp_power(*dev, true);
681 }
682 if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) {
683 dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
684 }
685
686 if (dev->model->model_id == ModelId::CANON_LIDE_90) {
687 if (has_flag(dev->session.params.flags, ScanFlag::REVERSE)) {
688 dev->interface->write_register(REG_0x6B, 0x01);
689 dev->interface->write_register(REG_0x6C, 0x02);
690 } else {
691 dev->interface->write_register(REG_0x6B, 0x03);
692 switch (dev->session.params.xres) {
693 case 150: dev->interface->write_register(REG_0x6C, 0x74); break;
694 case 300: dev->interface->write_register(REG_0x6C, 0x38); break;
695 case 600: dev->interface->write_register(REG_0x6C, 0x1c); break;
696 case 1200: dev->interface->write_register(REG_0x6C, 0x2c); break;
697 case 2400: dev->interface->write_register(REG_0x6C, 0x0c); break;
698 default:
699 break;
700 }
701 }
702 dev->interface->sleep_ms(100);
703 }
704
705 scanner_clear_scan_and_feed_counts(*dev);
706
707 // enable scan and motor
708 std::uint8_t val = dev->interface->read_register(REG_0x01);
709 val |= REG_0x01_SCAN;
710 dev->interface->write_register(REG_0x01, val);
711
712 scanner_start_action(*dev, start_motor);
713
714 switch (reg->state.motor_mode) {
715 case MotorMode::PRIMARY: {
716 if (reg->state.is_motor_on) {
717 dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
718 }
719 break;
720 }
721 case MotorMode::PRIMARY_AND_SECONDARY: {
722 if (reg->state.is_motor_on) {
723 dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
724 dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
725 }
726 break;
727 }
728 case MotorMode::SECONDARY: {
729 if (reg->state.is_motor_on) {
730 dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
731 }
732 break;
733 }
734 }
735 }
736
end_scan(Genesys_Device * dev,Genesys_Register_Set * reg,bool check_stop) const737 void CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
738 bool check_stop) const
739 {
740 DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
741
742 if (reg->state.is_xpa_on) {
743 dev->cmd_set->set_xpa_lamp_power(*dev, false);
744 }
745
746 if (!dev->model->is_sheetfed) {
747 scanner_stop_action(*dev);
748 }
749 }
750
move_back_home(Genesys_Device * dev,bool wait_until_home) const751 void CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const
752 {
753 scanner_move_back_home(*dev, wait_until_home);
754 }
755
init_regs_for_shading(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const756 void CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
757 Genesys_Register_Set& regs) const
758 {
759 DBG_HELPER(dbg);
760 int move;
761
762 float calib_size_mm = 0;
763 if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
764 dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
765 {
766 calib_size_mm = dev->model->y_size_calib_ta_mm;
767 } else {
768 calib_size_mm = dev->model->y_size_calib_mm;
769 }
770
771 unsigned resolution = sensor.shading_resolution;
772
773 unsigned channels = 3;
774 const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
775 dev->settings.scan_method);
776
777 unsigned calib_pixels = 0;
778 unsigned calib_pixels_offset = 0;
779
780 if (should_calibrate_only_active_area(*dev, dev->settings)) {
781 float offset = dev->model->x_offset_ta;
782 // FIXME: we should use resolution here
783 offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
784
785 float size = dev->model->x_size_ta;
786 size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
787
788 calib_pixels_offset = static_cast<std::size_t>(offset);
789 calib_pixels = static_cast<std::size_t>(size);
790 } else {
791 calib_pixels_offset = 0;
792 calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
793 }
794
795 ScanFlag flags = ScanFlag::DISABLE_SHADING |
796 ScanFlag::DISABLE_GAMMA |
797 ScanFlag::DISABLE_BUFFER_FULL_MOVE;
798
799 if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
800 dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
801 {
802 // note: scanner_move_to_ta() function has already been called and the sensor is at the
803 // transparency adapter
804 move = static_cast<int>(dev->model->y_offset_calib_white_ta -
805 dev->model->y_offset_sensor_to_ta);
806 flags |= ScanFlag::USE_XPA;
807 } else {
808 move = static_cast<int>(dev->model->y_offset_calib_white);
809 }
810
811 move = static_cast<int>((move * resolution) / MM_PER_INCH);
812 unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
813
814 ScanSession session;
815 session.params.xres = resolution;
816 session.params.yres = resolution;
817 session.params.startx = calib_pixels_offset;
818 session.params.starty = move;
819 session.params.pixels = calib_pixels;
820 session.params.lines = calib_lines;
821 session.params.depth = 16;
822 session.params.channels = channels;
823 session.params.scan_method = dev->settings.scan_method;
824 session.params.scan_mode = dev->settings.scan_mode;
825 session.params.color_filter = dev->settings.color_filter;
826 session.params.flags = flags;
827 compute_session(dev, session, calib_sensor);
828
829 init_regs_for_scan_session(dev, calib_sensor, ®s, session);
830
831 dev->calib_session = session;
832 }
833
send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor) const834 void CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
835 {
836 DBG_HELPER(dbg);
837
838 if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200)
839 return; // No gamma on this model
840
841 unsigned size = 256;
842
843 std::vector<uint8_t> gamma(size * 2 * 3);
844
845 std::vector<uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
846 std::vector<uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
847 std::vector<uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
848
849 // copy sensor specific's gamma tables
850 for (unsigned i = 0; i < size; i++) {
851 gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff;
852 gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff;
853 gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff;
854 gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff;
855 gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff;
856 gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
857 }
858
859 dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
860 }
861
led_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const862 SensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
863 Genesys_Register_Set& regs) const
864 {
865 return scanner_led_calibration(*dev, sensor, regs);
866 }
867
offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const868 void CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
869 Genesys_Register_Set& regs) const
870 {
871 scanner_offset_calibration(*dev, sensor, regs);
872 }
873
coarse_gain_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,int dpi) const874 void CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
875 Genesys_Register_Set& regs, int dpi) const
876 {
877 scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
878 }
879
init_regs_for_warmup(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg) const880 void CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
881 Genesys_Register_Set* reg) const
882 {
883 DBG_HELPER(dbg);
884 (void) sensor;
885
886 unsigned channels = 3;
887 unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
888 .get_nearest_resolution_x(600);
889
890 const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
891 dev->settings.scan_method);
892 unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
893
894 *reg = dev->reg;
895
896 auto flags = ScanFlag::DISABLE_SHADING |
897 ScanFlag::DISABLE_GAMMA |
898 ScanFlag::SINGLE_LINE |
899 ScanFlag::IGNORE_STAGGER_OFFSET |
900 ScanFlag::IGNORE_COLOR_OFFSET;
901 if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
902 dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
903 {
904 flags |= ScanFlag::USE_XPA;
905 }
906
907 ScanSession session;
908 session.params.xres = resolution;
909 session.params.yres = resolution;
910 session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
911 session.params.starty = 0;
912 session.params.pixels = num_pixels;
913 session.params.lines = 1;
914 session.params.depth = dev->model->bpp_color_values.front();
915 session.params.channels = channels;
916 session.params.scan_method = dev->settings.scan_method;
917 session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
918 session.params.color_filter = dev->settings.color_filter;
919 session.params.flags = flags;
920
921 compute_session(dev, session, calib_sensor);
922
923 init_regs_for_scan_session(dev, calib_sensor, reg, session);
924
925 sanei_genesys_set_motor_power(*reg, false);
926 }
927
gl842_init_gpio(Genesys_Device * dev)928 static void gl842_init_gpio(Genesys_Device* dev)
929 {
930 DBG_HELPER(dbg);
931 apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
932 {
933 dev->interface->write_register(reg.address, reg.value);
934 });
935 }
936
asic_boot(Genesys_Device * dev,bool cold) const937 void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
938 {
939 DBG_HELPER(dbg);
940
941 if (cold) {
942 dev->interface->write_register(0x0e, 0x01);
943 dev->interface->write_register(0x0e, 0x00);
944 }
945
946 // setup initial register values
947 gl842_init_registers(*dev);
948 dev->interface->write_registers(dev->reg);
949
950 if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
951 uint8_t data[32] = {
952 0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
953 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
954 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
955 0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
956 };
957
958 dev->interface->write_buffer(0x3c, 0x010a00, data, 32);
959 }
960
961 if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
962 dev->interface->write_0x8c(0x10, 0x94);
963 }
964 if (dev->model->model_id == ModelId::CANON_LIDE_90) {
965 dev->interface->write_0x8c(0x10, 0xd4);
966 }
967
968 // set RAM read address
969 dev->interface->write_register(REG_0x2A, 0x00);
970 dev->interface->write_register(REG_0x2B, 0x00);
971
972 // setup gpio
973 gl842_init_gpio(dev);
974 dev->interface->sleep_ms(100);
975 }
976
init(Genesys_Device * dev) const977 void CommandSetGl842::init(Genesys_Device* dev) const
978 {
979 DBG_INIT();
980 DBG_HELPER(dbg);
981
982 sanei_genesys_asic_init(dev);
983 }
984
update_hardware_sensors(Genesys_Scanner * s) const985 void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
986 {
987 DBG_HELPER(dbg);
988 (void) s;
989 }
990
update_home_sensor_gpio(Genesys_Device & dev) const991 void CommandSetGl842::update_home_sensor_gpio(Genesys_Device& dev) const
992 {
993 DBG_HELPER(dbg);
994 if (dev.model->model_id == ModelId::CANON_LIDE_90) {
995 std::uint8_t val = dev.interface->read_register(REG_0x6C);
996 val |= 0x02;
997 dev.interface->write_register(REG_0x6C, val);
998 }
999 }
1000
1001 /**
1002 * Send shading calibration data. The buffer is considered to always hold values
1003 * for all the channels.
1004 */
send_shading_data(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t * data,int size) const1005 void CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
1006 uint8_t* data, int size) const
1007 {
1008 DBG_HELPER(dbg);
1009
1010 int offset = 0;
1011 unsigned length = size;
1012
1013 if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
1014 offset = dev->session.params.startx * sensor.shading_resolution /
1015 dev->session.params.xres;
1016
1017 length = dev->session.output_pixels * sensor.shading_resolution /
1018 dev->session.params.xres;
1019
1020 offset += sensor.shading_pixel_offset;
1021
1022 // 16 bit words, 2 words per color, 3 color channels
1023 length *= 2 * 2 * 3;
1024 offset *= 2 * 2 * 3;
1025 } else {
1026 offset += sensor.shading_pixel_offset * 2 * 2 * 3;
1027 }
1028
1029 dev->interface->record_key_value("shading_offset", std::to_string(offset));
1030 dev->interface->record_key_value("shading_length", std::to_string(length));
1031
1032 std::vector<uint8_t> final_data(length, 0);
1033
1034 unsigned count = 0;
1035 if (offset < 0) {
1036 count += (-offset);
1037 length -= (-offset);
1038 offset = 0;
1039 }
1040 if (static_cast<int>(length) + offset > static_cast<int>(size)) {
1041 length = size - offset;
1042 }
1043
1044 for (unsigned i = 0; i < length; i++) {
1045 final_data[count++] = data[offset + i];
1046 count++;
1047 }
1048
1049 dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
1050 }
1051
needs_home_before_init_regs_for_scan(Genesys_Device * dev) const1052 bool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
1053 {
1054 (void) dev;
1055 return true;
1056 }
1057
wait_for_motor_stop(Genesys_Device * dev) const1058 void CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const
1059 {
1060 (void) dev;
1061 }
1062
1063 } // namespace gl842
1064 } // namespace genesys
1065