1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
4 
5 
6    This file is part of the SANE package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 */
21 
22 #define DEBUG_DECLARE_ONLY
23 
24 #include "low.h"
25 #include "assert.h"
26 #include "test_settings.h"
27 
28 #include "gl124_registers.h"
29 #include "gl646_registers.h"
30 #include "gl841_registers.h"
31 #include "gl842_registers.h"
32 #include "gl843_registers.h"
33 #include "gl846_registers.h"
34 #include "gl847_registers.h"
35 #include "gl646_registers.h"
36 
37 #include "gl124.h"
38 #include "gl646.h"
39 #include "gl841.h"
40 #include "gl842.h"
41 #include "gl843.h"
42 #include "gl846.h"
43 #include "gl847.h"
44 #include "gl646.h"
45 
46 #include <cstdio>
47 #include <chrono>
48 #include <cmath>
49 #include <vector>
50 
51 /* ------------------------------------------------------------------------ */
52 /*                  functions calling ASIC specific functions               */
53 /* ------------------------------------------------------------------------ */
54 
55 namespace genesys {
56 
create_cmd_set(AsicType asic_type)57 std::unique_ptr<CommandSet> create_cmd_set(AsicType asic_type)
58 {
59     switch (asic_type) {
60         case AsicType::GL646: return std::unique_ptr<CommandSet>(new gl646::CommandSetGl646{});
61         case AsicType::GL841: return std::unique_ptr<CommandSet>(new gl841::CommandSetGl841{});
62         case AsicType::GL842: return std::unique_ptr<CommandSet>(new gl842::CommandSetGl842{});
63         case AsicType::GL843: return std::unique_ptr<CommandSet>(new gl843::CommandSetGl843{});
64         case AsicType::GL845: // since only a few reg bits differs we handle both together
65         case AsicType::GL846: return std::unique_ptr<CommandSet>(new gl846::CommandSetGl846{});
66         case AsicType::GL847: return std::unique_ptr<CommandSet>(new gl847::CommandSetGl847{});
67         case AsicType::GL124: return std::unique_ptr<CommandSet>(new gl124::CommandSetGl124{});
68         default: throw SaneException(SANE_STATUS_INVAL, "unknown ASIC type");
69     }
70 }
71 
72 /* ------------------------------------------------------------------------ */
73 /*                  General IO and debugging functions                      */
74 /* ------------------------------------------------------------------------ */
75 
sanei_genesys_write_file(const char* filename, const std::uint8_t* data, std::size_t length)76 void sanei_genesys_write_file(const char* filename, const std::uint8_t* data, std::size_t length)
77 {
78     DBG_HELPER(dbg);
79     std::FILE* out = std::fopen(filename, "w");
80     if (!out) {
81         throw SaneException("could not open %s for writing: %s", filename, strerror(errno));
82     }
83     std::fwrite(data, 1, length, out);
84     std::fclose(out);
85 }
86 
87 /* ------------------------------------------------------------------------ */
88 /*                  Read and write RAM, registers and AFE                   */
89 /* ------------------------------------------------------------------------ */
90 
sanei_genesys_get_bulk_max_size(AsicType asic_type)91 unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type)
92 {
93     /*  Genesys supports 0xFE00 maximum size in general, wheraus GL646 supports
94         0xFFC0. We use 0xF000 because that's the packet limit in the Linux usbmon
95         USB capture stack. By default it limits packet size to b_size / 5 where
96         b_size is the size of the ring buffer. By default it's 300*1024, so the
97         packet is limited 61440 without any visibility to acquiring software.
98     */
99     if (asic_type == AsicType::GL124 ||
100         asic_type == AsicType::GL846 ||
101         asic_type == AsicType::GL847)
102     {
103         return 0xeff0;
104     }
105     return 0xf000;
106 }
107 
108 // Set address for writing data
sanei_genesys_set_buffer_address(Genesys_Device* dev, std::uint32_t addr)109 void sanei_genesys_set_buffer_address(Genesys_Device* dev, std::uint32_t addr)
110 {
111     DBG_HELPER(dbg);
112 
113     if (dev->model->asic_type==AsicType::GL847 ||
114         dev->model->asic_type==AsicType::GL845 ||
115         dev->model->asic_type==AsicType::GL846 ||
116         dev->model->asic_type==AsicType::GL124)
117     {
118       DBG(DBG_warn, "%s: shouldn't be used for GL846+ ASICs\n", __func__);
119       return;
120     }
121 
122   DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0);
123 
124   addr = addr >> 4;
125 
126     dev->interface->write_register(0x2b, (addr & 0xff));
127 
128   addr = addr >> 8;
129     dev->interface->write_register(0x2a, (addr & 0xff));
130 }
131 
132 /* ------------------------------------------------------------------------ */
133 /*                       Medium level functions                             */
134 /* ------------------------------------------------------------------------ */
135 
scanner_read_status(Genesys_Device& dev)136 Status scanner_read_status(Genesys_Device& dev)
137 {
138     DBG_HELPER(dbg);
139     std::uint16_t address = 0;
140 
141     switch (dev.model->asic_type) {
142         case AsicType::GL124: address = 0x101; break;
143         case AsicType::GL646:
144         case AsicType::GL841:
145         case AsicType::GL842:
146         case AsicType::GL843:
147         case AsicType::GL845:
148         case AsicType::GL846:
149         case AsicType::GL847: address = 0x41; break;
150         default: throw SaneException("Unsupported asic type");
151     }
152 
153     // same for all chips
154     constexpr std::uint8_t PWRBIT = 0x80;
155     constexpr std::uint8_t BUFEMPTY	= 0x40;
156     constexpr std::uint8_t FEEDFSH = 0x20;
157     constexpr std::uint8_t SCANFSH = 0x10;
158     constexpr std::uint8_t HOMESNR = 0x08;
159     constexpr std::uint8_t LAMPSTS = 0x04;
160     constexpr std::uint8_t FEBUSY = 0x02;
161     constexpr std::uint8_t MOTORENB	= 0x01;
162 
163     auto value = dev.interface->read_register(address);
164     Status status;
165     status.is_replugged = !(value & PWRBIT);
166     status.is_buffer_empty = value & BUFEMPTY;
167     status.is_feeding_finished = value & FEEDFSH;
168     status.is_scanning_finished = value & SCANFSH;
169     status.is_at_home = value & HOMESNR;
170     status.is_lamp_on = value & LAMPSTS;
171     status.is_front_end_busy = value & FEBUSY;
172     status.is_motor_enabled = value & MOTORENB;
173 
174     if (DBG_LEVEL >= DBG_io) {
175         debug_print_status(dbg, status);
176     }
177 
178     return status;
179 }
180 
scanner_read_reliable_status(Genesys_Device& dev)181 Status scanner_read_reliable_status(Genesys_Device& dev)
182 {
183     DBG_HELPER(dbg);
184 
185     scanner_read_status(dev);
186     dev.interface->sleep_ms(100);
187     return scanner_read_status(dev);
188 }
189 
scanner_read_print_status(Genesys_Device& dev)190 void scanner_read_print_status(Genesys_Device& dev)
191 {
192     scanner_read_status(dev);
193 }
194 
195 /**
196  * decodes and prints content of status register
197  * @param val value read from status register
198  */
debug_print_status(DebugMessageHelper& dbg, Status val)199 void debug_print_status(DebugMessageHelper& dbg, Status val)
200 {
201     std::stringstream str;
202     str << val;
203     dbg.vlog(DBG_info, "status=%s\n", str.str().c_str());
204 }
205 
scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)206 void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
207 {
208     scanner_register_rw_bits(dev, address, 0x00, mask);
209 }
210 
scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)211 void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
212 {
213     scanner_register_rw_bits(dev, address, mask, mask);
214 }
215 
scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t value, std::uint8_t mask)216 void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
217                               std::uint8_t value, std::uint8_t mask)
218 {
219     auto reg_value = dev.interface->read_register(address);
220     reg_value = (reg_value & ~mask) | (value & mask);
221     dev.interface->write_register(address, reg_value);
222 }
223 
224 /** read the number of valid words in scanner's RAM
225  * ie registers 42-43-44
226  */
227 // candidate for moving into chip specific files?
sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* words)228 void sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* words)
229 {
230     DBG_HELPER(dbg);
231 
232   switch (dev->model->asic_type)
233     {
234     case AsicType::GL124:
235             *words = dev->interface->read_register(0x102) & 0x03;
236             *words = *words * 256 + dev->interface->read_register(0x103);
237             *words = *words * 256 + dev->interface->read_register(0x104);
238             *words = *words * 256 + dev->interface->read_register(0x105);
239             break;
240 
241     case AsicType::GL845:
242     case AsicType::GL846:
243             *words = dev->interface->read_register(0x42) & 0x02;
244             *words = *words * 256 + dev->interface->read_register(0x43);
245             *words = *words * 256 + dev->interface->read_register(0x44);
246             *words = *words * 256 + dev->interface->read_register(0x45);
247             break;
248 
249     case AsicType::GL847:
250             *words = dev->interface->read_register(0x42) & 0x03;
251             *words = *words * 256 + dev->interface->read_register(0x43);
252             *words = *words * 256 + dev->interface->read_register(0x44);
253             *words = *words * 256 + dev->interface->read_register(0x45);
254             break;
255 
256     default:
257             *words = dev->interface->read_register(0x44);
258             *words += dev->interface->read_register(0x43) * 256;
259             if (dev->model->asic_type == AsicType::GL646) {
260                 *words += ((dev->interface->read_register(0x42) & 0x03) * 256 * 256);
261             } else {
262                 *words += ((dev->interface->read_register(0x42) & 0x0f) * 256 * 256);
263             }
264     }
265 
266   DBG(DBG_proc, "%s: %d words\n", __func__, *words);
267 }
268 
269 /** read the number of lines scanned
270  * ie registers 4b-4c-4d
271  */
sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* words)272 void sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* words)
273 {
274     DBG_HELPER(dbg);
275 
276     if (dev->model->asic_type == AsicType::GL124) {
277         *words = (dev->interface->read_register(0x10b) & 0x0f) << 16;
278         *words += (dev->interface->read_register(0x10c) << 8);
279         *words += dev->interface->read_register(0x10d);
280     }
281   else
282     {
283         *words = dev->interface->read_register(0x4d);
284         *words += dev->interface->read_register(0x4c) * 256;
285         if (dev->model->asic_type == AsicType::GL646) {
286             *words += ((dev->interface->read_register(0x4b) & 0x03) * 256 * 256);
287         } else {
288             *words += ((dev->interface->read_register(0x4b) & 0x0f) * 256 * 256);
289         }
290     }
291 
292   DBG(DBG_proc, "%s: %d lines\n", __func__, *words);
293 }
294 
295 /** @brief Check if the scanner's internal data buffer is empty
296  * @param *dev device to test for data
297  * @param *empty return value
298  * @return empty will be set to true if there is no scanned data.
299  **/
sanei_genesys_is_buffer_empty(Genesys_Device* dev)300 bool sanei_genesys_is_buffer_empty(Genesys_Device* dev)
301 {
302     DBG_HELPER(dbg);
303 
304     dev->interface->sleep_ms(1);
305 
306     auto status = scanner_read_status(*dev);
307 
308     if (status.is_buffer_empty) {
309       /* fix timing issue on USB3 (or just may be too fast) hardware
310        * spotted by John S. Weber <jweber53@gmail.com>
311        */
312         dev->interface->sleep_ms(1);
313       DBG(DBG_io2, "%s: buffer is empty\n", __func__);
314         return true;
315     }
316 
317 
318   DBG(DBG_io, "%s: buffer is filled\n", __func__);
319     return false;
320 }
321 
wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice)322 void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice)
323 {
324     // FIXME: reduce MAX_RETRIES once tests are updated
325     const unsigned MAX_RETRIES = 100000;
326     for (unsigned i = 0; i < MAX_RETRIES; ++i) {
327 
328         if (check_status_twice) {
329             // FIXME: this only to preserve previous behavior, can be removed
330             scanner_read_status(*dev);
331         }
332 
333         bool empty = sanei_genesys_is_buffer_empty(dev);
334         dev->interface->sleep_ms(10);
335         if (!empty)
336             return;
337     }
338     throw SaneException(SANE_STATUS_IO_ERROR, "failed to read data");
339 }
340 
wait_until_has_valid_words(Genesys_Device* dev)341 void wait_until_has_valid_words(Genesys_Device* dev)
342 {
343     unsigned words = 0;
344     unsigned sleep_time_ms = 10;
345 
346     for (unsigned wait_ms = 0; wait_ms < 70000; wait_ms += sleep_time_ms) {
347         sanei_genesys_read_valid_words(dev, &words);
348         if (words != 0)
349             break;
350         dev->interface->sleep_ms(sleep_time_ms);
351     }
352 
353     if (words == 0) {
354         throw SaneException(SANE_STATUS_IO_ERROR, "timeout, buffer does not get filled");
355     }
356 }
357 
358 // Read data (e.g scanned image) from scan buffer
sanei_genesys_read_data_from_scanner(Genesys_Device* dev, std::uint8_t* data, size_t size)359 void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, std::uint8_t* data, size_t size)
360 {
361     DBG_HELPER_ARGS(dbg, "size = %zu bytes", size);
362 
363     if (size & 1)
364         DBG(DBG_info, "WARNING %s: odd number of bytes\n", __func__);
365 
366     wait_until_has_valid_words(dev);
367 
368     dev->interface->bulk_read_data(0x45, data, size);
369 }
370 
read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session, std::size_t total_bytes)371 Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session,
372                                          std::size_t total_bytes)
373 {
374     DBG_HELPER(dbg);
375 
376     auto format = create_pixel_format(session.params.depth,
377                                       dev->model->is_cis ? 1 : session.params.channels,
378                                       dev->model->line_mode_color_order);
379 
380     auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
381     auto height = session.optical_line_count;
382 
383     Image image(width, height, format);
384 
385     auto max_bytes = image.get_row_bytes() * height;
386     if (total_bytes > max_bytes) {
387         throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
388     }
389     if (total_bytes != max_bytes) {
390         DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
391             total_bytes, max_bytes);
392     }
393 
394     sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes);
395 
396     ImagePipelineStack pipeline;
397     pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
398 
399     if (session.segment_count > 1) {
400         auto output_width = session.output_segment_pixel_group_count * session.segment_count;
401         pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
402                                                        session.conseq_pixel_dist,
403                                                        1, 1);
404     }
405 
406     if (session.params.depth == 16) {
407         unsigned num_swaps = 0;
408         if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
409             num_swaps++;
410         }
411 #ifdef WORDS_BIGENDIAN
412         num_swaps++;
413 #endif
414         if (num_swaps % 2 != 0) {
415             dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
416         }
417     }
418 
419     if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
420         pipeline.push_node<ImagePipelineNodeInvert>();
421     }
422 
423     if (dev->model->is_cis && session.params.channels == 3) {
424         pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev->model->line_mode_color_order);
425     }
426 
427     if (session.use_host_side_gray) {
428         pipeline.push_node<ImagePipelineNodeMergeColorToGray>();
429     }
430 
431     if (pipeline.get_output_format() == PixelFormat::BGR888) {
432         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
433     }
434 
435     if (pipeline.get_output_format() == PixelFormat::BGR161616) {
436         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
437     }
438 
439     return pipeline.get_image();
440 }
441 
442 
read_shuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session)443 Image read_shuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session)
444 {
445     DBG_HELPER(dbg);
446 
447     std::size_t total_bytes = 0;
448     std::size_t pixels_per_line = 0;
449 
450     if (dev->model->asic_type == AsicType::GL842 ||
451         dev->model->asic_type == AsicType::GL843 ||
452         dev->model->model_id == ModelId::CANON_5600F)
453     {
454         pixels_per_line = session.output_pixels;
455     } else {
456         // BUG: this selects incorrect pixel number
457         pixels_per_line = session.params.pixels;
458     }
459 
460     // FIXME: the current calculation is likely incorrect on non-GL843 implementations,
461     // but this needs checking. Note the extra line when computing size.
462     if (dev->model->asic_type == AsicType::GL842 ||
463         dev->model->asic_type == AsicType::GL843 ||
464         dev->model->model_id == ModelId::CANON_5600F)
465     {
466         total_bytes = session.output_total_bytes_raw;
467     } else {
468         total_bytes = session.params.channels * 2 * pixels_per_line * (session.params.lines + 1);
469     }
470 
471     auto format = create_pixel_format(session.params.depth,
472                                       dev->model->is_cis ? 1 : session.params.channels,
473                                       dev->model->line_mode_color_order);
474 
475     // auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
476     auto width = pixels_per_line;
477     auto height = session.params.lines + 1; // BUG: incorrect
478     if (dev->model->asic_type == AsicType::GL842 ||
479         dev->model->asic_type == AsicType::GL843 ||
480         dev->model->model_id == ModelId::CANON_5600F)
481     {
482         height = session.optical_line_count;
483     }
484 
485     Image image(width, height, format);
486 
487     auto max_bytes = image.get_row_bytes() * height;
488     if (total_bytes > max_bytes) {
489         throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
490     }
491     if (total_bytes != max_bytes) {
492         DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
493             total_bytes, max_bytes);
494     }
495 
496     sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes);
497 
498     ImagePipelineStack pipeline;
499     pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
500 
501     if (session.segment_count > 1) {
502         auto output_width = session.output_segment_pixel_group_count * session.segment_count;
503         pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
504                                                        session.conseq_pixel_dist,
505                                                        1, 1);
506     }
507 
508     if (session.params.depth == 16) {
509         unsigned num_swaps = 0;
510         if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
511             num_swaps++;
512         }
513 #ifdef WORDS_BIGENDIAN
514         num_swaps++;
515 #endif
516         if (num_swaps % 2 != 0) {
517             dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
518         }
519     }
520 
521     if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
522         pipeline.push_node<ImagePipelineNodeInvert>();
523     }
524 
525     if (dev->model->is_cis && session.params.channels == 3) {
526         pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev->model->line_mode_color_order);
527     }
528 
529     if (pipeline.get_output_format() == PixelFormat::BGR888) {
530         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
531     }
532 
533     if (pipeline.get_output_format() == PixelFormat::BGR161616) {
534         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
535     }
536 
537     return pipeline.get_image();
538 }
539 
sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps)540 void sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps)
541 {
542     DBG_HELPER(dbg);
543 
544     if (dev->model->asic_type == AsicType::GL124) {
545         *steps = (dev->interface->read_register(0x108) & 0x1f) << 16;
546         *steps += (dev->interface->read_register(0x109) << 8);
547         *steps += dev->interface->read_register(0x10a);
548     }
549   else
550     {
551         *steps = dev->interface->read_register(0x4a);
552         *steps += dev->interface->read_register(0x49) * 256;
553         if (dev->model->asic_type == AsicType::GL646) {
554             *steps += ((dev->interface->read_register(0x48) & 0x03) * 256 * 256);
555         } else if (dev->model->asic_type == AsicType::GL841) {
556             *steps += ((dev->interface->read_register(0x48) & 0x0f) * 256 * 256);
557         } else {
558             *steps += ((dev->interface->read_register(0x48) & 0x1f) * 256 * 256);
559         }
560     }
561 
562   DBG(DBG_proc, "%s: %d steps\n", __func__, *steps);
563 }
564 
sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set& regs, bool set)565 void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor,
566                                   Genesys_Register_Set& regs, bool set)
567 {
568     static const std::uint8_t REG_0x03_LAMPPWR = 0x10;
569 
570     if (set) {
571         regs.find_reg(0x03).value |= REG_0x03_LAMPPWR;
572 
573         if (dev->model->asic_type == AsicType::GL841) {
574             regs_set_exposure(dev->model->asic_type, regs,
575                               sanei_genesys_fixup_exposure(sensor.exposure));
576             regs.set8(0x19, 0x50);
577         }
578 
579         if (dev->model->asic_type == AsicType::GL843) {
580             regs_set_exposure(dev->model->asic_type, regs, sensor.exposure);
581         }
582 
583         // we don't actually turn on lamp on infrared scan
584         if ((dev->model->model_id == ModelId::CANON_8400F ||
585              dev->model->model_id == ModelId::CANON_8600F ||
586              dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
587              dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
588              dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I) &&
589             dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
590         {
591             regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
592         }
593     } else {
594         regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
595 
596         if (dev->model->asic_type == AsicType::GL841) {
597             regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
598             regs.set8(0x19, 0xff);
599         }
600         if (dev->model->model_id == ModelId::CANON_5600F) {
601             regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
602         }
603     }
604     regs.state.is_lamp_on = set;
605 }
606 
sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set)607 void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set)
608 {
609     static const std::uint8_t REG_0x02_MTRPWR = 0x10;
610 
611     if (set) {
612         regs.find_reg(0x02).value |= REG_0x02_MTRPWR;
613     } else {
614         regs.find_reg(0x02).value &= ~REG_0x02_MTRPWR;
615     }
616     regs.state.is_motor_on = set;
617 }
618 
should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor)619 bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor)
620 {
621     if ((session.params.flags & ScanFlag::DISABLE_GAMMA) != ScanFlag::NONE) {
622         return false;
623     }
624     if (session.params.depth == 16) {
625         return false;
626     }
627     if (session.params.brightness_adjustment != 0 || session.params.contrast_adjustment != 0) {
628         return true;
629     }
630 
631     if (sensor.gamma[0] == 1.0f || sensor.gamma[1] == 1.0f || sensor.gamma[2] == 1.0f) {
632         return false;
633     }
634 
635     return true;
636 }
637 
get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, int color)638 std::vector<std::uint16_t> get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
639                                            int color)
640 {
641     if (!dev->gamma_override_tables[color].empty()) {
642         return dev->gamma_override_tables[color];
643     } else {
644         std::vector<std::uint16_t> ret;
645         sanei_genesys_create_default_gamma_table(dev, ret, sensor.gamma[color]);
646         return ret;
647     }
648 }
649 
650 /** @brief generates gamma buffer to transfer
651  * Generates gamma table buffer to send to ASIC. Applies
652  * contrast and brightness if set.
653  * @param dev device to set up
654  * @param bits number of bits used by gamma
655  * @param max value for gamma
656  * @param size of the gamma table
657  */
generate_gamma_buffer(Genesys_Device* dev, const Genesys_Sensor& sensor, int bits, int max, int size)658 std::vector<std::uint8_t> generate_gamma_buffer(Genesys_Device* dev,
659                                                 const Genesys_Sensor& sensor,
660                                                 int bits, int max, int size)
661 {
662     DBG_HELPER(dbg);
663 
664     // the gamma tables are 16 bits words and contain 3 channels
665     std::vector<std::uint8_t> gamma_buf(size * 2 * 3);
666 
667     std::vector<std::uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
668     std::vector<std::uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
669     std::vector<std::uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
670 
671     auto get_gamma_value = [](const std::vector<std::uint16_t>& array,
672                               std::size_t index) -> std::uint16_t
673     {
674         if (index < array.size())
675             return array[index];
676         return 0xffff;
677     };
678 
679     auto set_gamma_buf_value = [](std::vector<std::uint8_t>& array, std::size_t pos,
680                                   std::uint16_t value)
681     {
682         array[pos * 2 + 0] = value & 0xff;
683         array[pos * 2 + 1] = (value >> 8) & 0xff;
684     };
685 
686   if(dev->settings.contrast!=0 || dev->settings.brightness!=0)
687     {
688         std::vector<std::uint16_t> lut(65536);
689       sanei_genesys_load_lut(reinterpret_cast<unsigned char *>(lut.data()),
690                              bits,
691                              bits,
692                              0,
693                              max,
694                              dev->settings.contrast,
695                              dev->settings.brightness);
696       for (int i = 0; i < size; i++)
697         {
698             set_gamma_buf_value(gamma_buf, i + size * 0, lut[get_gamma_value(rgamma, i)]);
699             set_gamma_buf_value(gamma_buf, i + size * 1, lut[get_gamma_value(ggamma, i)]);
700             set_gamma_buf_value(gamma_buf, i + size * 2, lut[get_gamma_value(bgamma, i)]);
701         }
702     }
703   else
704     {
705       for (int i = 0; i < size; i++)
706         {
707             set_gamma_buf_value(gamma_buf, i + size * 0, get_gamma_value(rgamma, i));
708             set_gamma_buf_value(gamma_buf, i + size * 1, get_gamma_value(ggamma, i));
709             set_gamma_buf_value(gamma_buf, i + size * 2, get_gamma_value(bgamma, i));
710         }
711     }
712     return gamma_buf;
713 }
714 
715 
716 /** @brief send gamma table to scanner
717  * This function sends generic gamma table (ie ones built with
718  * provided gamma) or the user defined one if provided by
719  * fontend. Used by gl846+ ASICs
720  * @param dev device to write to
721  */
sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor)722 void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor)
723 {
724     DBG_HELPER(dbg);
725   int size;
726   int i;
727 
728   size = 256 + 1;
729 
730     auto gamma = generate_gamma_buffer(dev, sensor, 16, 65535, size);
731 
732     // loop sending gamma tables NOTE: 0x01000000 not 0x10000000
733     for (i = 0; i < 3; i++) {
734         // clear corresponding GMM_N bit
735         std::uint8_t val = dev->interface->read_register(0xbd);
736         val &= ~(0x01 << i);
737         dev->interface->write_register(0xbd, val);
738 
739         // clear corresponding GMM_F bit
740         val = dev->interface->read_register(0xbe);
741       val &= ~(0x01 << i);
742         dev->interface->write_register(0xbe, val);
743 
744       // FIXME: currently the last word of each gamma table is not initialized, so to work around
745       // unstable data, just set it to 0 which is the most likely value of uninitialized memory
746       // (proper value is probably 0xff)
747       gamma[size * 2 * i + size * 2 - 2] = 0;
748       gamma[size * 2 * i + size * 2 - 1] = 0;
749 
750       /* set GMM_Z */
751         dev->interface->write_register(0xc5+2*i, gamma[size*2*i+1]);
752         dev->interface->write_register(0xc6+2*i, gamma[size*2*i]);
753 
754         dev->interface->write_ahb(0x01000000 + 0x200 * i, (size-1) * 2,
755                                   gamma.data() + i * size * 2+2);
756     }
757 }
758 
compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor)759 void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
760                                    const Genesys_Sensor& sensor)
761 {
762     if (dev->model->asic_type == AsicType::GL646) {
763         s.pixel_startx += s.output_startx * sensor.full_resolution / s.params.xres;
764         s.pixel_endx = s.pixel_startx + s.optical_pixels * s.full_resolution / s.optical_resolution;
765 
766     } else if (dev->model->asic_type == AsicType::GL841 ||
767                dev->model->asic_type == AsicType::GL842 ||
768                dev->model->asic_type == AsicType::GL843 ||
769                dev->model->asic_type == AsicType::GL845 ||
770                dev->model->asic_type == AsicType::GL846 ||
771                dev->model->asic_type == AsicType::GL847)
772     {
773         unsigned startx_xres = s.optical_resolution;
774         if (dev->model->model_id == ModelId::CANON_5600F ||
775             dev->model->model_id == ModelId::CANON_LIDE_90)
776         {
777             if (s.output_resolution == 1200) {
778                 startx_xres /= 2;
779             }
780             if (s.output_resolution >= 2400) {
781                 startx_xres /= 4;
782             }
783         }
784         s.pixel_startx = (s.output_startx * startx_xres) / s.params.xres;
785         s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
786 
787     } else if (dev->model->asic_type == AsicType::GL124)
788     {
789         s.pixel_startx = s.output_startx * sensor.full_resolution / s.params.xres;
790         s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
791     }
792 
793     // align pixels to correct boundary for unstaggering
794     unsigned needed_x_alignment = std::max(s.stagger_x.size(), s.stagger_y.size());
795     unsigned aligned_pixel_startx = align_multiple_floor(s.pixel_startx, needed_x_alignment);
796     s.pixel_endx -= s.pixel_startx - aligned_pixel_startx;
797     s.pixel_startx = aligned_pixel_startx;
798 
799     s.pixel_startx = sensor.pixel_count_ratio.apply(s.pixel_startx);
800     s.pixel_endx = sensor.pixel_count_ratio.apply(s.pixel_endx);
801 
802     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
803         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
804         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
805         dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
806     {
807         s.pixel_startx = align_multiple_floor(s.pixel_startx, sensor.pixel_count_ratio.divisor());
808         s.pixel_endx = align_multiple_floor(s.pixel_endx, sensor.pixel_count_ratio.divisor());
809     }
810 }
811 
session_adjust_output_pixels(unsigned output_pixels, const Genesys_Device& dev, const Genesys_Sensor& sensor, unsigned output_xresolution, unsigned output_yresolution, bool adjust_output_pixels)812 unsigned session_adjust_output_pixels(unsigned output_pixels,
813                                       const Genesys_Device& dev, const Genesys_Sensor& sensor,
814                                       unsigned output_xresolution, unsigned output_yresolution,
815                                       bool adjust_output_pixels)
816 {
817     bool adjust_optical_pixels = !adjust_output_pixels;
818     if (dev.model->model_id == ModelId::CANON_5600F) {
819         adjust_optical_pixels = true;
820         adjust_output_pixels = true;
821     }
822     if (adjust_optical_pixels) {
823         auto optical_resolution = sensor.get_optical_resolution();
824 
825         // FIXME: better way would be to compute and return the required multiplier
826         unsigned optical_pixels = (output_pixels * optical_resolution) / output_xresolution;
827 
828         if (dev.model->asic_type == AsicType::GL841 ||
829             dev.model->asic_type == AsicType::GL842)
830         {
831             optical_pixels = align_multiple_ceil(optical_pixels, 2);
832         }
833 
834         if (dev.model->asic_type == AsicType::GL646 && output_xresolution == 400) {
835             optical_pixels = align_multiple_floor(optical_pixels, 6);
836         }
837 
838         if (dev.model->asic_type == AsicType::GL843) {
839             // ensure the number of optical pixels is divisible by 2.
840             // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number
841             optical_pixels = align_multiple_ceil(optical_pixels,
842                                                  2 * sensor.full_resolution / optical_resolution);
843             if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
844                 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
845                 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
846                 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
847                 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
848                 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
849             {
850                 optical_pixels = align_multiple_ceil(optical_pixels, 16);
851             }
852         }
853         output_pixels = (optical_pixels * output_xresolution) / optical_resolution;
854     }
855 
856     if (adjust_output_pixels) {
857         // TODO: the following may no longer be needed but were applied historically.
858 
859         // we need an even pixels number
860         // TODO invert test logic or generalize behaviour across all ASICs
861         if (has_flag(dev.model->flags, ModelFlag::SIS_SENSOR) ||
862             dev.model->asic_type == AsicType::GL847 ||
863             dev.model->asic_type == AsicType::GL124 ||
864             dev.model->asic_type == AsicType::GL845 ||
865             dev.model->asic_type == AsicType::GL846 ||
866             dev.model->asic_type == AsicType::GL843)
867         {
868             if (output_xresolution <= 1200) {
869                 output_pixels = align_multiple_floor(output_pixels, 4);
870             } else if (output_xresolution < output_yresolution) {
871                 // BUG: this is an artifact of the fact that the resolution was twice as large than
872                 // the actual resolution when scanning above the supported scanner X resolution
873                 output_pixels = align_multiple_floor(output_pixels, 8);
874             } else {
875                 output_pixels = align_multiple_floor(output_pixels, 16);
876             }
877         }
878 
879         // corner case for true lineart for sensor with several segments or when xres is doubled
880         // to match yres */
881         if (output_xresolution >= 1200 && (
882                     dev.model->asic_type == AsicType::GL124 ||
883                     dev.model->asic_type == AsicType::GL847 ||
884                     dev.session.params.xres < dev.session.params.yres))
885         {
886             if (output_xresolution < output_yresolution) {
887                 // FIXME: this is an artifact of the fact that the resolution was twice as large than
888                 // the actual resolution when scanning above the supported scanner X resolution
889                 output_pixels = align_multiple_floor(output_pixels, 8);
890             } else {
891                 output_pixels = align_multiple_floor(output_pixels, 16);
892             }
893         }
894     }
895 
896     return output_pixels;
897 }
898 
compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor)899 void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor)
900 {
901     DBG_HELPER(dbg);
902 
903     (void) dev;
904     s.params.assert_valid();
905 
906     if (s.params.depth != 8 && s.params.depth != 16) {
907         throw SaneException("Unsupported depth setting %d", s.params.depth);
908     }
909 
910     // compute optical and output resolutions
911     s.full_resolution = sensor.full_resolution;
912     s.optical_resolution = sensor.get_optical_resolution();
913     s.output_resolution = s.params.xres;
914 
915     s.pixel_count_ratio = sensor.pixel_count_ratio;
916 
917     if (s.output_resolution > s.optical_resolution) {
918         throw std::runtime_error("output resolution higher than optical resolution");
919     }
920 
921     s.output_pixels = session_adjust_output_pixels(s.params.pixels, *dev, sensor,
922                                                    s.params.xres, s.params.yres, false);
923 
924     // Compute the number of optical pixels that will be acquired by the chip.
925     // The necessary alignment requirements have already been computed by
926     // get_session_output_pixels_multiplier
927     s.optical_pixels = (s.output_pixels * s.optical_resolution) / s.output_resolution;
928 
929     if (static_cast<int>(s.params.startx) + sensor.output_pixel_offset < 0)
930         throw SaneException("Invalid sensor.output_pixel_offset");
931     s.output_startx = static_cast<unsigned>(
932                 static_cast<int>(s.params.startx) + sensor.output_pixel_offset);
933 
934     if (has_flag(dev->model->flags, ModelFlag::HOST_SIDE_GRAY) && s.params.channels == 1 &&
935         s.params.color_filter == ColorFilter::NONE)
936     {
937         s.use_host_side_gray = true;
938         s.params.channels = 3;
939         s.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
940     }
941 
942     s.stagger_x = sensor.stagger_x;
943     s.stagger_y = sensor.stagger_y;
944 
945     s.num_staggered_lines = 0;
946     if (!has_flag(s.params.flags, ScanFlag::IGNORE_STAGGER_OFFSET)) {
947         s.num_staggered_lines = s.stagger_y.max_shift() * s.params.yres / s.params.xres;
948     }
949 
950     s.color_shift_lines_r = dev->model->ld_shift_r;
951     s.color_shift_lines_g = dev->model->ld_shift_g;
952     s.color_shift_lines_b = dev->model->ld_shift_b;
953 
954     if (dev->model->motor_id == MotorId::G4050 && s.params.yres > 600) {
955         // it seems base_dpi of the G4050 motor is changed above 600 dpi
956         s.color_shift_lines_r = (s.color_shift_lines_r * 3800) / dev->motor.base_ydpi;
957         s.color_shift_lines_g = (s.color_shift_lines_g * 3800) / dev->motor.base_ydpi;
958         s.color_shift_lines_b = (s.color_shift_lines_b * 3800) / dev->motor.base_ydpi;
959     }
960 
961     s.color_shift_lines_r = (s.color_shift_lines_r * s.params.yres) / dev->motor.base_ydpi;
962     s.color_shift_lines_g = (s.color_shift_lines_g * s.params.yres) / dev->motor.base_ydpi;
963     s.color_shift_lines_b = (s.color_shift_lines_b * s.params.yres) / dev->motor.base_ydpi;
964 
965     s.max_color_shift_lines = 0;
966     if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_COLOR_OFFSET)) {
967         s.max_color_shift_lines = std::max(s.color_shift_lines_r, std::max(s.color_shift_lines_g,
968                                                                            s.color_shift_lines_b));
969     }
970 
971     s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines;
972     s.optical_line_count = dev->model->is_cis ? s.output_line_count * s.params.channels
973                                               : s.output_line_count;
974 
975     s.output_channel_bytes = multiply_by_depth_ceil(s.output_pixels, s.params.depth);
976     s.output_line_bytes = s.output_channel_bytes * s.params.channels;
977 
978     s.segment_count = sensor.get_segment_count();
979 
980     s.optical_pixels_raw = s.optical_pixels;
981     s.output_line_bytes_raw = s.output_line_bytes;
982     s.conseq_pixel_dist = 0;
983 
984     // FIXME: Use ModelFlag::SIS_SENSOR
985     if ((dev->model->asic_type == AsicType::GL845 ||
986          dev->model->asic_type == AsicType::GL846 ||
987          dev->model->asic_type == AsicType::GL847) &&
988         dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7400 &&
989         dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_8200I)
990     {
991         if (s.segment_count > 1) {
992             s.conseq_pixel_dist = sensor.segment_size;
993 
994             // in case of multi-segments sensor, we have expand the scan area to sensor boundary
995             if (dev->model->model_id == ModelId::CANON_5600F) {
996                 unsigned startx_xres = s.optical_resolution;
997                 if (dev->model->model_id == ModelId::CANON_5600F) {
998                     if (s.output_resolution == 1200) {
999                         startx_xres /= 2;
1000                     }
1001                     if (s.output_resolution >= 2400) {
1002                         startx_xres /= 4;
1003                     }
1004                 }
1005                 unsigned optical_startx = s.output_startx * startx_xres / s.params.xres;
1006                 unsigned optical_endx = optical_startx + s.optical_pixels;
1007 
1008                 unsigned multi_segment_size_output = s.segment_count * s.conseq_pixel_dist;
1009                 unsigned multi_segment_size_optical =
1010                         (multi_segment_size_output * s.optical_resolution) / s.output_resolution;
1011 
1012                 optical_endx = align_multiple_ceil(optical_endx, multi_segment_size_optical);
1013                 s.optical_pixels_raw = optical_endx - optical_startx;
1014                 s.optical_pixels_raw = align_multiple_floor(s.optical_pixels_raw,
1015                                                             4 * s.optical_resolution / s.output_resolution);
1016             } else {
1017                 // BUG: the following code will likely scan too much. Use the CANON_5600F approach
1018                 unsigned extra_segment_scan_area = align_multiple_ceil(s.conseq_pixel_dist, 2);
1019                 extra_segment_scan_area *= s.segment_count - 1;
1020                 extra_segment_scan_area = s.pixel_count_ratio.apply_inverse(extra_segment_scan_area);
1021 
1022                 s.optical_pixels_raw += extra_segment_scan_area;
1023             }
1024         }
1025 
1026         if (dev->model->model_id == ModelId::CANON_5600F) {
1027             auto output_pixels_raw = (s.optical_pixels_raw * s.output_resolution) / s.optical_resolution;
1028             auto output_channel_bytes_raw = multiply_by_depth_ceil(output_pixels_raw, s.params.depth);
1029             s.output_line_bytes_raw = output_channel_bytes_raw * s.params.channels;
1030         } else {
1031             s.output_line_bytes_raw = multiply_by_depth_ceil(
1032                         (s.optical_pixels_raw * s.output_resolution) / sensor.full_resolution / s.segment_count,
1033                         s.params.depth);
1034         }
1035     }
1036 
1037     if (dev->model->asic_type == AsicType::GL841 ||
1038         dev->model->asic_type == AsicType::GL842)
1039     {
1040         if (dev->model->is_cis) {
1041             s.output_line_bytes_raw = s.output_channel_bytes;
1042         }
1043     }
1044 
1045     if (dev->model->asic_type == AsicType::GL124) {
1046         if (dev->model->is_cis) {
1047             s.output_line_bytes_raw = s.output_channel_bytes;
1048         }
1049         s.conseq_pixel_dist = s.output_pixels / (s.full_resolution / s.optical_resolution) / s.segment_count;
1050     }
1051 
1052     if (dev->model->asic_type == AsicType::GL842 ||
1053         dev->model->asic_type == AsicType::GL843)
1054     {
1055         if (dev->model->is_cis) {
1056             if (s.segment_count > 1) {
1057                 s.conseq_pixel_dist = sensor.segment_size;
1058             }
1059         } else {
1060             s.conseq_pixel_dist = s.output_pixels / s.segment_count;
1061         }
1062     }
1063 
1064     s.output_segment_pixel_group_count = 0;
1065     if (dev->model->asic_type == AsicType::GL124 ||
1066         dev->model->asic_type == AsicType::GL842 ||
1067         dev->model->asic_type == AsicType::GL843)
1068     {
1069         s.output_segment_pixel_group_count = s.output_pixels /
1070                 (s.full_resolution / s.optical_resolution * s.segment_count);
1071     }
1072 
1073     if (dev->model->model_id == ModelId::CANON_LIDE_90) {
1074         s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
1075     }
1076 
1077     if (dev->model->asic_type == AsicType::GL845 ||
1078         dev->model->asic_type == AsicType::GL846 ||
1079         dev->model->asic_type == AsicType::GL847)
1080     {
1081         if (dev->model->model_id == ModelId::CANON_5600F) {
1082             s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
1083         } else {
1084             s.output_segment_pixel_group_count = s.pixel_count_ratio.apply(s.optical_pixels);
1085         }
1086     }
1087 
1088     s.output_line_bytes_requested = multiply_by_depth_ceil(
1089             s.params.get_requested_pixels() * s.params.channels, s.params.depth);
1090 
1091     s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count;
1092     s.output_total_bytes = s.output_line_bytes * s.output_line_count;
1093     if (dev->model->model_id == ModelId::CANON_LIDE_90) {
1094         s.output_total_bytes_raw *= s.params.channels;
1095         s.output_total_bytes *= s.params.channels;
1096     }
1097 
1098     s.buffer_size_read = s.output_line_bytes_raw * 64;
1099     compute_session_pixel_offsets(dev, s, sensor);
1100 
1101     s.shading_pixel_offset = sensor.shading_pixel_offset;
1102 
1103     if (dev->model->asic_type == AsicType::GL124 ||
1104         dev->model->asic_type == AsicType::GL845 ||
1105         dev->model->asic_type == AsicType::GL846)
1106     {
1107         s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis &&
1108                            s.params.color_filter == ColorFilter::NONE);
1109     }
1110 
1111     s.use_host_side_calib = sensor.use_host_side_calib;
1112 
1113     if (dev->model->asic_type == AsicType::GL841 ||
1114         dev->model->asic_type == AsicType::GL842 ||
1115         dev->model->asic_type == AsicType::GL843)
1116     {
1117         // no 16 bit gamma for this ASIC
1118         if (s.params.depth == 16) {
1119             s.params.flags |= ScanFlag::DISABLE_GAMMA;
1120         }
1121     }
1122 
1123     s.computed = true;
1124 
1125     DBG(DBG_info, "%s ", __func__);
1126     debug_dump(DBG_info, s);
1127 }
1128 
build_image_pipeline(const Genesys_Device& dev, const ScanSession& session, unsigned pipeline_index, bool log_image_data)1129 ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
1130                                         unsigned pipeline_index, bool log_image_data)
1131 {
1132     auto format = create_pixel_format(session.params.depth,
1133                                       dev.model->is_cis ? 1 : session.params.channels,
1134                                       dev.model->line_mode_color_order);
1135     auto depth = get_pixel_format_depth(format);
1136     auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
1137 
1138     auto read_data_from_usb = [&dev](std::size_t size, std::uint8_t* data)
1139     {
1140         DBG(DBG_info, "read_data_from_usb: reading %zu bytes\n", size);
1141         auto begin = std::chrono::high_resolution_clock::now();
1142         dev.interface->bulk_read_data(0x45, data, size);
1143         auto end = std::chrono::high_resolution_clock::now();
1144         float us = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
1145         float speed = size / us; // bytes/us == MB/s
1146         DBG(DBG_info, "read_data_from_usb: reading %zu bytes finished %f MB/s\n", size, speed);
1147         return true;
1148     };
1149 
1150     auto debug_prefix = "gl_pipeline_" + std::to_string(pipeline_index);
1151 
1152     ImagePipelineStack pipeline;
1153 
1154     auto lines = session.optical_line_count;
1155     auto buffer_size = session.buffer_size_read;
1156 
1157     // At least GL841 requires reads to be aligned to 2 bytes and will fail on some devices on
1158     // certain circumstances.
1159     buffer_size = align_multiple_ceil(buffer_size, 2);
1160 
1161     auto& src_node = pipeline.push_first_node<ImagePipelineNodeBufferedCallableSource>(
1162                           width, lines, format, buffer_size, read_data_from_usb);
1163     src_node.set_last_read_multiple(2);
1164 
1165     if (log_image_data) {
1166         pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_0_from_usb.tiff");
1167     }
1168 
1169     if (session.segment_count > 1) {
1170         auto output_width = session.output_segment_pixel_group_count * session.segment_count;
1171         pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev.segment_order,
1172                                                             session.conseq_pixel_dist,
1173                                                             1, 1);
1174 
1175         if (log_image_data) {
1176             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_1_after_desegment.tiff");
1177         }
1178     }
1179 
1180     if (depth == 16) {
1181         unsigned num_swaps = 0;
1182         if (has_flag(dev.model->flags, ModelFlag::SWAP_16BIT_DATA)) {
1183             num_swaps++;
1184         }
1185 #ifdef WORDS_BIGENDIAN
1186         num_swaps++;
1187 #endif
1188         if (num_swaps % 2 != 0) {
1189             pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
1190 
1191             if (log_image_data) {
1192                 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_2_after_swap.tiff");
1193             }
1194         }
1195     }
1196 
1197     if (has_flag(dev.model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
1198         pipeline.push_node<ImagePipelineNodeInvert>();
1199 
1200         if (log_image_data) {
1201             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_3_after_invert.tiff");
1202         }
1203     }
1204 
1205     if (dev.model->is_cis && session.params.channels == 3) {
1206         pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev.model->line_mode_color_order);
1207 
1208         if (log_image_data) {
1209             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_4_after_merge_mono.tiff");
1210         }
1211     }
1212 
1213     if (pipeline.get_output_format() == PixelFormat::BGR888) {
1214         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
1215     }
1216 
1217     if (pipeline.get_output_format() == PixelFormat::BGR161616) {
1218         pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
1219     }
1220 
1221     if (log_image_data) {
1222         pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_5_after_format.tiff");
1223     }
1224 
1225     if (session.max_color_shift_lines > 0 && session.params.channels == 3) {
1226         pipeline.push_node<ImagePipelineNodeComponentShiftLines>(
1227                     session.color_shift_lines_r,
1228                     session.color_shift_lines_g,
1229                     session.color_shift_lines_b);
1230 
1231         if (log_image_data) {
1232             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_6_after_color_unshift.tiff");
1233         }
1234     }
1235 
1236     if (!session.stagger_x.empty()) {
1237         // FIXME: the image will be scaled to requested pixel count without regard to the reduction
1238         // of image size in this step.
1239         pipeline.push_node<ImagePipelineNodePixelShiftColumns>(session.stagger_x.shifts());
1240 
1241         if (log_image_data) {
1242             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_7_after_x_unstagger.tiff");
1243         }
1244     }
1245 
1246     if (session.num_staggered_lines > 0) {
1247         pipeline.push_node<ImagePipelineNodePixelShiftLines>(session.stagger_y.shifts());
1248 
1249         if (log_image_data) {
1250             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_8_after_y_unstagger.tiff");
1251         }
1252     }
1253 
1254     if (session.use_host_side_calib &&
1255         !has_flag(dev.model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) &&
1256         !has_flag(session.params.flags, ScanFlag::DISABLE_SHADING))
1257     {
1258         unsigned offset_pixels = session.params.startx + dev.calib_session.shading_pixel_offset;
1259         unsigned offset_bytes = offset_pixels * dev.calib_session.params.channels;
1260         pipeline.push_node<ImagePipelineNodeCalibrate>(dev.dark_average_data,
1261                                                        dev.white_average_data, offset_bytes);
1262 
1263         if (log_image_data) {
1264             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_9_after_calibrate.tiff");
1265         }
1266     }
1267 
1268     if (session.use_host_side_gray) {
1269         pipeline.push_node<ImagePipelineNodeMergeColorToGray>();
1270 
1271         if (log_image_data) {
1272             pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_10_after_nogray.tiff");
1273         }
1274     }
1275 
1276     if (pipeline.get_output_width() != session.params.get_requested_pixels()) {
1277         pipeline.push_node<ImagePipelineNodeScaleRows>(session.params.get_requested_pixels());
1278     }
1279 
1280     return pipeline;
1281 }
1282 
setup_image_pipeline(Genesys_Device& dev, const ScanSession& session)1283 void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session)
1284 {
1285     static unsigned s_pipeline_index = 0;
1286 
1287     s_pipeline_index++;
1288 
1289     dev.pipeline = build_image_pipeline(dev, session, s_pipeline_index, dbg_log_image_data());
1290 
1291     auto read_from_pipeline = [&dev](std::size_t size, std::uint8_t* out_data)
1292     {
1293         (void) size; // will be always equal to dev.pipeline.get_output_row_bytes()
1294         return dev.pipeline.get_next_row_data(out_data);
1295     };
1296     dev.pipeline_buffer = ImageBuffer{dev.pipeline.get_output_row_bytes(),
1297                                        read_from_pipeline};
1298 }
1299 
compute_frontend_gain_wolfson(float value, float target_value)1300 std::uint8_t compute_frontend_gain_wolfson(float value, float target_value)
1301 {
1302     /*  the flow of data through the frontend ADC is as follows (see e.g. WM8192 datasheet)
1303         input
1304         -> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
1305         -> apply gain (o = i * 208/(283-PGA[7:0])
1306         -> ADC
1307 
1308         Here we have some input data that was acquired with zero gain (PGA==0).
1309         We want to compute gain such that the output would approach full ADC range (controlled by
1310         target_value).
1311 
1312         We want to solve the following for {PGA}:
1313 
1314         {value}         = {input} * 208 / (283 - 0)
1315         {target_value}  = {input} * 208 / (283 - {PGA})
1316 
1317         The solution is the following equation:
1318 
1319         {PGA} = 283 * (1 - {value} / {target_value})
1320     */
1321     float gain = value / target_value;
1322     int code = static_cast<int>(283 * (1 - gain));
1323     return clamp(code, 0, 255);
1324 }
1325 
compute_frontend_gain_lide_80(float value, float target_value)1326 std::uint8_t compute_frontend_gain_lide_80(float value, float target_value)
1327 {
1328     int code = static_cast<int>((target_value / value) * 12);
1329     return clamp(code, 0, 255);
1330 }
1331 
compute_frontend_gain_wolfson_gl841(float value, float target_value)1332 std::uint8_t compute_frontend_gain_wolfson_gl841(float value, float target_value)
1333 {
1334     // this code path is similar to what generic wolfson code path uses and uses similar constants,
1335     // but is likely incorrect.
1336     float inv_gain = target_value / value;
1337     inv_gain *= 0.69f;
1338     int code = static_cast<int>(283 - 208 / inv_gain);
1339     return clamp(code, 0, 255);
1340 }
1341 
compute_frontend_gain_wolfson_gl846_gl847_gl124(float value, float target_value)1342 std::uint8_t compute_frontend_gain_wolfson_gl846_gl847_gl124(float value, float target_value)
1343 {
1344     // this code path is similar to what generic wolfson code path uses and uses similar constants,
1345     // but is likely incorrect.
1346     float inv_gain = target_value / value;
1347     int code = static_cast<int>(283 - 208 / inv_gain);
1348     return clamp(code, 0, 255);
1349 }
1350 
1351 
compute_frontend_gain_analog_devices(float value, float target_value)1352 std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value)
1353 {
1354     /*  The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet)
1355         input
1356         -> apply offset (o = i + 300mV * (OFFSET[8] ? 1 : -1) * (OFFSET[7:0] / 127)
1357         -> apply gain (o = i * 6 / (1 + 5 * ( 63 - PGA[5:0] ) / 63 ) )
1358         -> ADC
1359 
1360         We want to solve the following for {PGA}:
1361 
1362         {value}         = {input} * 6 / (1 + 5 * ( 63 - 0) / 63 ) )
1363         {target_value}  = {input} * 6 / (1 + 5 * ( 63 - {PGA}) / 63 ) )
1364 
1365         The solution is the following equation:
1366 
1367         {PGA} = (378 / 5) * ({target_value} - {value} / {target_value})
1368     */
1369     int code = static_cast<int>((378.0f / 5.0f) * ((target_value - value) / target_value));
1370     return clamp(code, 0, 63);
1371 }
1372 
compute_frontend_gain(float value, float target_value, FrontendType frontend_type)1373 std::uint8_t compute_frontend_gain(float value, float target_value,
1374                                    FrontendType frontend_type)
1375 {
1376     switch (frontend_type) {
1377         case FrontendType::WOLFSON:
1378             return compute_frontend_gain_wolfson(value, target_value);
1379         case FrontendType::ANALOG_DEVICES:
1380             return compute_frontend_gain_analog_devices(value, target_value);
1381         case FrontendType::CANON_LIDE_80:
1382             return compute_frontend_gain_lide_80(value, target_value);
1383         case FrontendType::WOLFSON_GL841:
1384             return compute_frontend_gain_wolfson_gl841(value, target_value);
1385         case FrontendType::WOLFSON_GL846:
1386         case FrontendType::ANALOG_DEVICES_GL847:
1387         case FrontendType::WOLFSON_GL124:
1388             return compute_frontend_gain_wolfson_gl846_gl847_gl124(value, target_value);
1389         default:
1390             throw SaneException("Unknown frontend to compute gain for");
1391     }
1392 }
1393 
1394 /** @brief initialize device
1395  * Initialize backend and ASIC : registers, motor tables, and gamma tables
1396  * then ensure scanner's head is at home. Designed for gl846+ ASICs.
1397  * Detects cold boot (ie first boot since device plugged) in this case
1398  * an extensice setup up is done at hardware level.
1399  *
1400  * @param dev device to initialize
1401  * @param max_regs umber of maximum used registers
1402  */
sanei_genesys_asic_init(Genesys_Device* dev)1403 void sanei_genesys_asic_init(Genesys_Device* dev)
1404 {
1405     DBG_HELPER(dbg);
1406 
1407     std::uint8_t val;
1408     bool cold = true;
1409 
1410     // URB    16  control  0xc0 0x0c 0x8e 0x0b len     1 read  0x00 */
1411     dev->interface->get_usb_device().control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER,
1412                                                  VALUE_GET_REGISTER, 0x00, 1, &val);
1413 
1414   DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val);
1415   DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0");
1416   if (val & 0x08)
1417     {
1418       dev->usb_mode = 1;
1419     }
1420   else
1421     {
1422       dev->usb_mode = 2;
1423     }
1424 
1425     /*  Check if the device has already been initialized and powered up. We read register 0x06 and
1426         check PWRBIT, if reset scanner has been freshly powered up. This bit will be set to later
1427         so that following reads can detect power down/up cycle
1428     */
1429     if (!is_testing_mode()) {
1430         if (dev->interface->read_register(0x06) & 0x10) {
1431             cold = false;
1432         }
1433     }
1434   DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm");
1435 
1436   /* don't do anything if backend is initialized and hardware hasn't been
1437    * replug */
1438   if (dev->already_initialized && !cold)
1439     {
1440       DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__);
1441         return;
1442     }
1443 
1444     // set up hardware and registers
1445     dev->cmd_set->asic_boot(dev, cold);
1446 
1447   /* now hardware part is OK, set up device struct */
1448   dev->white_average_data.clear();
1449   dev->dark_average_data.clear();
1450 
1451   dev->settings.color_filter = ColorFilter::RED;
1452 
1453     dev->initial_regs = dev->reg;
1454 
1455   const auto& sensor = sanei_genesys_find_sensor_any(dev);
1456 
1457     // Set analog frontend
1458     dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
1459 
1460     dev->already_initialized = true;
1461 
1462     // Move to home if needed
1463     if (dev->model->model_id == ModelId::CANON_8600F) {
1464         if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::SECONDARY)) {
1465             dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
1466         }
1467         if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::PRIMARY)) {
1468             dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
1469         }
1470     }
1471     dev->cmd_set->move_back_home(dev, true);
1472 
1473     // Set powersaving (default = 15 minutes)
1474     dev->cmd_set->set_powersaving(dev, 15);
1475 }
1476 
scanner_start_action(Genesys_Device& dev, bool start_motor)1477 void scanner_start_action(Genesys_Device& dev, bool start_motor)
1478 {
1479     DBG_HELPER(dbg);
1480     switch (dev.model->asic_type) {
1481         case AsicType::GL646:
1482         case AsicType::GL841:
1483         case AsicType::GL842:
1484         case AsicType::GL843:
1485         case AsicType::GL845:
1486         case AsicType::GL846:
1487         case AsicType::GL847:
1488         case AsicType::GL124:
1489             break;
1490         default:
1491             throw SaneException("Unsupported chip");
1492     }
1493 
1494     if (start_motor) {
1495         dev.interface->write_register(0x0f, 0x01);
1496     } else {
1497         dev.interface->write_register(0x0f, 0);
1498     }
1499 }
1500 
sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw)1501 void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw)
1502 {
1503     // same across GL646, GL841, GL843, GL846, GL847, GL124
1504     const std::uint8_t REG_0x05_DPIHW_MASK = 0xc0;
1505     const std::uint8_t REG_0x05_DPIHW_600 = 0x00;
1506     const std::uint8_t REG_0x05_DPIHW_1200 = 0x40;
1507     const std::uint8_t REG_0x05_DPIHW_2400 = 0x80;
1508     const std::uint8_t REG_0x05_DPIHW_4800 = 0xc0;
1509 
1510     std::uint8_t dpihw_setting;
1511     switch (dpihw) {
1512         case 600:
1513             dpihw_setting = REG_0x05_DPIHW_600;
1514             break;
1515         case 1200:
1516             dpihw_setting = REG_0x05_DPIHW_1200;
1517             break;
1518         case 2400:
1519             dpihw_setting = REG_0x05_DPIHW_2400;
1520             break;
1521         case 4800:
1522             dpihw_setting = REG_0x05_DPIHW_4800;
1523             break;
1524         default:
1525             throw SaneException("Unknown dpihw value: %d", dpihw);
1526     }
1527     regs.set8_mask(0x05, dpihw_setting, REG_0x05_DPIHW_MASK);
1528 }
1529 
regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs, const SensorExposure& exposure)1530 void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs,
1531                        const SensorExposure& exposure)
1532 {
1533     switch (asic_type) {
1534         case AsicType::GL124: {
1535             regs.set24(gl124::REG_EXPR, exposure.red);
1536             regs.set24(gl124::REG_EXPG, exposure.green);
1537             regs.set24(gl124::REG_EXPB, exposure.blue);
1538             break;
1539         }
1540         case AsicType::GL646: {
1541             regs.set16(gl646::REG_EXPR, exposure.red);
1542             regs.set16(gl646::REG_EXPG, exposure.green);
1543             regs.set16(gl646::REG_EXPB, exposure.blue);
1544             break;
1545         }
1546         case AsicType::GL841: {
1547             regs.set16(gl841::REG_EXPR, exposure.red);
1548             regs.set16(gl841::REG_EXPG, exposure.green);
1549             regs.set16(gl841::REG_EXPB, exposure.blue);
1550             break;
1551         }
1552         case AsicType::GL842: {
1553             regs.set16(gl842::REG_EXPR, exposure.red);
1554             regs.set16(gl842::REG_EXPG, exposure.green);
1555             regs.set16(gl842::REG_EXPB, exposure.blue);
1556             break;
1557         }
1558         case AsicType::GL843: {
1559             regs.set16(gl843::REG_EXPR, exposure.red);
1560             regs.set16(gl843::REG_EXPG, exposure.green);
1561             regs.set16(gl843::REG_EXPB, exposure.blue);
1562             break;
1563         }
1564         case AsicType::GL845:
1565         case AsicType::GL846: {
1566             regs.set16(gl846::REG_EXPR, exposure.red);
1567             regs.set16(gl846::REG_EXPG, exposure.green);
1568             regs.set16(gl846::REG_EXPB, exposure.blue);
1569             break;
1570         }
1571         case AsicType::GL847: {
1572             regs.set16(gl847::REG_EXPR, exposure.red);
1573             regs.set16(gl847::REG_EXPG, exposure.green);
1574             regs.set16(gl847::REG_EXPB, exposure.blue);
1575             break;
1576         }
1577         default:
1578             throw SaneException("Unsupported asic");
1579     }
1580 }
1581 
regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs)1582 void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs)
1583 {
1584     DBG_HELPER(dbg);
1585     switch (asic_type) {
1586         case AsicType::GL646: {
1587             regs.find_reg(gl646::REG_0x01).value &= ~gl646::REG_0x01_SCAN;
1588             break;
1589         }
1590         case AsicType::GL841: {
1591             regs.find_reg(gl841::REG_0x01).value &= ~gl841::REG_0x01_SCAN;
1592             break;
1593         }
1594         case AsicType::GL842: {
1595             regs.find_reg(gl842::REG_0x01).value &= ~gl842::REG_0x01_SCAN;
1596             break;
1597         }
1598         case AsicType::GL843: {
1599             regs.find_reg(gl843::REG_0x01).value &= ~gl843::REG_0x01_SCAN;
1600             break;
1601         }
1602         case AsicType::GL845:
1603         case AsicType::GL846: {
1604             regs.find_reg(gl846::REG_0x01).value &= ~gl846::REG_0x01_SCAN;
1605             break;
1606         }
1607         case AsicType::GL847: {
1608             regs.find_reg(gl847::REG_0x01).value &= ~gl847::REG_0x01_SCAN;
1609             break;
1610         }
1611         case AsicType::GL124: {
1612             regs.find_reg(gl124::REG_0x01).value &= ~gl124::REG_0x01_SCAN;
1613             break;
1614         }
1615         default:
1616             throw SaneException("Unsupported asic");
1617     }
1618 }
1619 
get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs)1620 bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs)
1621 {
1622     switch (asic_type) {
1623         case AsicType::GL646:
1624             return static_cast<bool>(regs.get8(gl646::REG_0x06) & gl646::REG_0x06_GAIN4);
1625         case AsicType::GL841:
1626             return static_cast<bool>(regs.get8(gl841::REG_0x06) & gl841::REG_0x06_GAIN4);
1627         case AsicType::GL842:
1628             return static_cast<bool>(regs.get8(gl842::REG_0x06) & gl842::REG_0x06_GAIN4);
1629         case AsicType::GL843:
1630             return static_cast<bool>(regs.get8(gl843::REG_0x06) & gl843::REG_0x06_GAIN4);
1631         case AsicType::GL845:
1632         case AsicType::GL846:
1633             return static_cast<bool>(regs.get8(gl846::REG_0x06) & gl846::REG_0x06_GAIN4);
1634         case AsicType::GL847:
1635             return static_cast<bool>(regs.get8(gl847::REG_0x06) & gl847::REG_0x06_GAIN4);
1636         case AsicType::GL124:
1637             return static_cast<bool>(regs.get8(gl124::REG_0x06) & gl124::REG_0x06_GAIN4);
1638         default:
1639             throw SaneException("Unsupported chipset");
1640     }
1641 }
1642 
1643 /**
1644  * Wait for the scanning head to park
1645  */
sanei_genesys_wait_for_home(Genesys_Device* dev)1646 void sanei_genesys_wait_for_home(Genesys_Device* dev)
1647 {
1648     DBG_HELPER(dbg);
1649 
1650   /* clear the parking status whatever the outcome of the function */
1651     dev->parking = false;
1652 
1653     if (is_testing_mode()) {
1654         return;
1655     }
1656 
1657     // read initial status, if head isn't at home and motor is on we are parking, so we wait.
1658     // gl847/gl124 need 2 reads for reliable results
1659     auto status = scanner_read_status(*dev);
1660     dev->interface->sleep_ms(10);
1661     status = scanner_read_status(*dev);
1662 
1663     if (status.is_at_home) {
1664 	  DBG (DBG_info,
1665 	       "%s: already at home\n", __func__);
1666         return;
1667     }
1668 
1669     unsigned timeout_ms = 200000;
1670     unsigned elapsed_ms = 0;
1671   do
1672     {
1673       dev->interface->sleep_ms(100);
1674         elapsed_ms += 100;
1675 
1676         status = scanner_read_status(*dev);
1677     } while (elapsed_ms < timeout_ms && !status.is_at_home);
1678 
1679   /* if after the timeout, head is still not parked, error out */
1680     if (elapsed_ms >= timeout_ms && !status.is_at_home) {
1681         DBG (DBG_error, "%s: failed to reach park position in %dseconds\n", __func__,
1682              timeout_ms / 1000);
1683         throw SaneException(SANE_STATUS_IO_ERROR, "failed to reach park position");
1684     }
1685 }
1686 
get_motor_profile_ptr(const std::vector<MotorProfile>& profiles, unsigned exposure, const ScanSession& session)1687 const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
1688                                           unsigned exposure,
1689                                           const ScanSession& session)
1690 {
1691     int best_i = -1;
1692 
1693     for (unsigned i = 0; i < profiles.size(); ++i) {
1694         const auto& profile = profiles[i];
1695 
1696         if (!profile.resolutions.matches(session.params.yres)) {
1697             continue;
1698         }
1699         if (!profile.scan_methods.matches(session.params.scan_method)) {
1700             continue;
1701         }
1702 
1703         if (profile.max_exposure == exposure) {
1704             return &profile;
1705         }
1706 
1707         if (profile.max_exposure == 0 || profile.max_exposure >= exposure) {
1708             if (best_i < 0) {
1709                 // no match found yet
1710                 best_i = i;
1711             } else {
1712                 // test for better match
1713                 if (profiles[i].max_exposure < profiles[best_i].max_exposure) {
1714                     best_i = i;
1715                 }
1716             }
1717         }
1718     }
1719 
1720     if (best_i < 0) {
1721         return nullptr;
1722     }
1723 
1724     return &profiles[best_i];
1725 }
1726 
get_motor_profile(const std::vector<MotorProfile>& profiles, unsigned exposure, const ScanSession& session)1727 const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
1728                                       unsigned exposure,
1729                                       const ScanSession& session)
1730 {
1731     const auto* profile = get_motor_profile_ptr(profiles, exposure, session);
1732     if (profile == nullptr) {
1733         throw SaneException("Motor slope is not configured");
1734     }
1735 
1736     return *profile;
1737 }
1738 
create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi, unsigned exposure, unsigned step_multiplier, const MotorProfile& motor_profile)1739 MotorSlopeTable create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi,
1740                                    unsigned exposure, unsigned step_multiplier,
1741                                    const MotorProfile& motor_profile)
1742 {
1743     unsigned target_speed_w = ((exposure * ydpi) / motor.base_ydpi);
1744 
1745     auto table = create_slope_table_for_speed(motor_profile.slope, target_speed_w,
1746                                               motor_profile.step_type,
1747                                               step_multiplier, 2 * step_multiplier,
1748                                               get_slope_table_max_size(asic_type));
1749     return table;
1750 }
1751 
create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier, const MotorProfile& motor_profile)1752 MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
1753                                            const MotorProfile& motor_profile)
1754 {
1755     return create_slope_table_for_speed(motor_profile.slope, motor_profile.slope.max_speed_w,
1756                                         motor_profile.step_type,
1757                                         step_multiplier, 2 * step_multiplier,
1758                                         get_slope_table_max_size(asic_type));
1759 }
1760 
1761 /** @brief returns the lowest possible ydpi for the device
1762  * Parses device entry to find lowest motor dpi.
1763  * @param dev device description
1764  * @return lowest motor resolution
1765  */
sanei_genesys_get_lowest_ydpi(Genesys_Device *dev)1766 int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev)
1767 {
1768     const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
1769     return resolution_settings.get_min_resolution_y();
1770 }
1771 
1772 /** @brief returns the lowest possible dpi for the device
1773  * Parses device entry to find lowest motor or sensor dpi.
1774  * @param dev device description
1775  * @return lowest motor resolution
1776  */
sanei_genesys_get_lowest_dpi(Genesys_Device *dev)1777 int sanei_genesys_get_lowest_dpi(Genesys_Device *dev)
1778 {
1779     const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
1780     return std::min(resolution_settings.get_min_resolution_x(),
1781                     resolution_settings.get_min_resolution_y());
1782 }
1783 
1784 /** @brief check is a cache entry may be used
1785  * Compares current settings with the cache entry and return
1786  * true if they are compatible.
1787  * A calibration cache is compatible if color mode and x dpi match the user
1788  * requested scan. In the case of CIS scanners, dpi isn't a criteria.
1789  * flatbed cache entries are considered too old and then expires if they
1790  * are older than the expiration time option, forcing calibration at least once
1791  * then given time. */
sanei_genesys_is_compatible_calibration(Genesys_Device* dev, const ScanSession& session, const Genesys_Calibration_Cache* cache, bool for_overwrite)1792 bool sanei_genesys_is_compatible_calibration(Genesys_Device* dev,
1793                                              const ScanSession& session,
1794                                              const Genesys_Calibration_Cache* cache,
1795                                              bool for_overwrite)
1796 {
1797     DBG_HELPER(dbg);
1798 #ifdef HAVE_SYS_TIME_H
1799   struct timeval time;
1800 #endif
1801 
1802     bool compatible = true;
1803 
1804     const auto& dev_params = session.params;
1805 
1806     if (dev_params.scan_method != cache->params.scan_method) {
1807         dbg.vlog(DBG_io, "incompatible: scan_method %d vs. %d\n",
1808                  static_cast<unsigned>(dev_params.scan_method),
1809                  static_cast<unsigned>(cache->params.scan_method));
1810         compatible = false;
1811     }
1812 
1813     if (dev_params.xres != cache->params.xres) {
1814         dbg.vlog(DBG_io, "incompatible: params.xres %d vs. %d\n",
1815                  dev_params.xres, cache->params.xres);
1816         compatible = false;
1817     }
1818 
1819     if (dev_params.yres != cache->params.yres) {
1820         // exposure depends on selected sensor and we select the sensor according to yres
1821         dbg.vlog(DBG_io, "incompatible: params.yres %d vs. %d\n",
1822                  dev_params.yres, cache->params.yres);
1823         compatible = false;
1824     }
1825 
1826     if (dev_params.channels != cache->params.channels) {
1827         // exposure depends on total number of pixels at least on gl841
1828         dbg.vlog(DBG_io, "incompatible: params.channels %d vs. %d\n",
1829                  dev_params.channels, cache->params.channels);
1830         compatible = false;
1831     }
1832 
1833     if (dev_params.startx != cache->params.startx) {
1834         // exposure depends on total number of pixels at least on gl841
1835         dbg.vlog(DBG_io, "incompatible: params.startx %d vs. %d\n",
1836                  dev_params.startx, cache->params.startx);
1837         compatible = false;
1838     }
1839 
1840     if (dev_params.pixels != cache->params.pixels) {
1841         // exposure depends on total number of pixels at least on gl841
1842         dbg.vlog(DBG_io, "incompatible: params.pixels %d vs. %d\n",
1843                  dev_params.pixels, cache->params.pixels);
1844         compatible = false;
1845     }
1846 
1847   if (!compatible)
1848     {
1849       DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__);
1850       return false;
1851     }
1852 
1853   /* a cache entry expires after after expiration time for non sheetfed scanners */
1854   /* this is not taken into account when overwriting cache entries    */
1855 #ifdef HAVE_SYS_TIME_H
1856     if (!for_overwrite && dev->settings.expiration_time >=0)
1857     {
1858         gettimeofday(&time, nullptr);
1859       if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60)
1860           && !dev->model->is_sheetfed
1861           && (dev->settings.scan_method == ScanMethod::FLATBED))
1862         {
1863           DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__);
1864           return false;
1865         }
1866     }
1867 #endif
1868 
1869   return true;
1870 }
1871 
1872 /** @brief build lookup table for digital enhancements
1873  * Function to build a lookup table (LUT), often
1874    used by scanners to implement brightness/contrast/gamma
1875    or by backends to speed binarization/thresholding
1876 
1877    offset and slope inputs are -127 to +127
1878 
1879    slope rotates line around central input/output val,
1880    0 makes horizontal line
1881 
1882        pos           zero          neg
1883        .       x     .             .  x
1884        .      x      .             .   x
1885    out .     x       .xxxxxxxxxxx  .    x
1886        .    x        .             .     x
1887        ....x.......  ............  .......x....
1888             in            in            in
1889 
1890    offset moves line vertically, and clamps to output range
1891    0 keeps the line crossing the center of the table
1892 
1893        high           low
1894        .   xxxxxxxx   .
1895        . x            .
1896    out x              .          x
1897        .              .        x
1898        ............   xxxxxxxx....
1899             in             in
1900 
1901    out_min/max provide bounds on output values,
1902    useful when building thresholding lut.
1903    0 and 255 are good defaults otherwise.
1904   * @param lut pointer where to store the generated lut
1905   * @param in_bits number of bits for in values
1906   * @param out_bits number of bits of out values
1907   * @param out_min minimal out value
1908   * @param out_max maximal out value
1909   * @param slope slope of the generated data
1910   * @param offset offset of the generated data
1911   */
sanei_genesys_load_lut(unsigned char* lut, int in_bits, int out_bits, int out_min, int out_max, int slope, int offset)1912 void sanei_genesys_load_lut(unsigned char* lut,
1913                             int in_bits, int out_bits,
1914                             int out_min, int out_max,
1915                             int slope, int offset)
1916 {
1917     DBG_HELPER(dbg);
1918   int i, j;
1919   double shift, rise;
1920   int max_in_val = (1 << in_bits) - 1;
1921   int max_out_val = (1 << out_bits) - 1;
1922     std::uint8_t* lut_p8 = lut;
1923     std::uint16_t* lut_p16 = reinterpret_cast<std::uint16_t*>(lut);
1924 
1925   /* slope is converted to rise per unit run:
1926    * first [-127,127] to [-.999,.999]
1927    * then to [-PI/4,PI/4] then [0,PI/2]
1928    * then take the tangent (T.O.A)
1929    * then multiply by the normal linear slope
1930    * because the table may not be square, i.e. 1024x256*/
1931     auto pi_4 = M_PI / 4.0;
1932     rise = std::tan(static_cast<double>(slope) / 128 * pi_4 + pi_4) * max_out_val / max_in_val;
1933 
1934   /* line must stay vertically centered, so figure
1935    * out vertical offset at central input value */
1936     shift = static_cast<double>(max_out_val) / 2 - (rise * max_in_val / 2);
1937 
1938   /* convert the user offset setting to scale of output
1939    * first [-127,127] to [-1,1]
1940    * then to [-max_out_val/2,max_out_val/2]*/
1941     shift += static_cast<double>(offset) / 127 * max_out_val / 2;
1942 
1943   for (i = 0; i <= max_in_val; i++)
1944     {
1945         j = static_cast<int>(rise * i + shift);
1946 
1947       /* cap data to required range */
1948       if (j < out_min)
1949 	{
1950 	  j = out_min;
1951 	}
1952       else if (j > out_max)
1953 	{
1954 	  j = out_max;
1955 	}
1956 
1957       /* copy result according to bit depth */
1958       if (out_bits <= 8)
1959 	{
1960 	  *lut_p8 = j;
1961 	  lut_p8++;
1962 	}
1963       else
1964 	{
1965 	  *lut_p16 = j;
1966 	  lut_p16++;
1967 	}
1968     }
1969 }
1970 
1971 } // namespace genesys
1972