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