1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci*/
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci#include "scanner_interface_usb.h"
24141cc406Sopenharmony_ci#include "low.h"
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_cinamespace genesys {
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ciScannerInterfaceUsb::~ScannerInterfaceUsb() = default;
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ciScannerInterfaceUsb::ScannerInterfaceUsb(Genesys_Device* dev) : dev_{dev} {}
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_cibool ScannerInterfaceUsb::is_mock() const
33141cc406Sopenharmony_ci{
34141cc406Sopenharmony_ci    return false;
35141cc406Sopenharmony_ci}
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_cistd::uint8_t ScannerInterfaceUsb::read_register(std::uint16_t address)
38141cc406Sopenharmony_ci{
39141cc406Sopenharmony_ci    DBG_HELPER(dbg);
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci    std::uint8_t value = 0;
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL847 ||
44141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL845 ||
45141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL846 ||
46141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL124)
47141cc406Sopenharmony_ci    {
48141cc406Sopenharmony_ci        std::uint8_t value2x8[2];
49141cc406Sopenharmony_ci        std::uint16_t address16 = 0x22 + (address << 8);
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci        std::uint16_t usb_value = VALUE_GET_REGISTER;
52141cc406Sopenharmony_ci        if (address > 0xff) {
53141cc406Sopenharmony_ci            usb_value |= 0x100;
54141cc406Sopenharmony_ci        }
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, usb_value, address16, 2, value2x8);
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci        // check usb link status
59141cc406Sopenharmony_ci        if (value2x8[1] != 0x55) {
60141cc406Sopenharmony_ci            throw SaneException(SANE_STATUS_IO_ERROR, "invalid read, scanner unplugged?");
61141cc406Sopenharmony_ci        }
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci        DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value2x8[0]);
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci        value = value2x8[0];
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci    } else {
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci        if (address > 0xff) {
70141cc406Sopenharmony_ci            throw SaneException("Invalid register address 0x%04x", address);
71141cc406Sopenharmony_ci        }
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_ci        std::uint8_t address8 = address & 0xff;
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX,
76141cc406Sopenharmony_ci                             1, &address8);
77141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX,
78141cc406Sopenharmony_ci                             1, &value);
79141cc406Sopenharmony_ci    }
80141cc406Sopenharmony_ci    return value;
81141cc406Sopenharmony_ci}
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_register(std::uint16_t address, std::uint8_t value)
84141cc406Sopenharmony_ci{
85141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "address: 0x%04x, value: 0x%02x", static_cast<unsigned>(address),
86141cc406Sopenharmony_ci                    static_cast<unsigned>(value));
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL847 ||
89141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL845 ||
90141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL846 ||
91141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL124)
92141cc406Sopenharmony_ci    {
93141cc406Sopenharmony_ci        std::uint8_t buffer[2];
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci        buffer[0] = address & 0xff;
96141cc406Sopenharmony_ci        buffer[1] = value;
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci        std::uint16_t usb_value = VALUE_SET_REGISTER;
99141cc406Sopenharmony_ci        if (address > 0xff) {
100141cc406Sopenharmony_ci            usb_value |= 0x100;
101141cc406Sopenharmony_ci        }
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, usb_value, INDEX,
104141cc406Sopenharmony_ci                                  2, buffer);
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci    } else {
107141cc406Sopenharmony_ci        if (address > 0xff) {
108141cc406Sopenharmony_ci            throw SaneException("Invalid register address 0x%04x", address);
109141cc406Sopenharmony_ci        }
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci        std::uint8_t address8 = address & 0xff;
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX,
114141cc406Sopenharmony_ci                             1, &address8);
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX,
117141cc406Sopenharmony_ci                             1, &value);
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_ci    }
120141cc406Sopenharmony_ci    DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value);
121141cc406Sopenharmony_ci}
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_registers(const Genesys_Register_Set& regs)
124141cc406Sopenharmony_ci{
125141cc406Sopenharmony_ci    DBG_HELPER(dbg);
126141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL646 ||
127141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL841)
128141cc406Sopenharmony_ci    {
129141cc406Sopenharmony_ci        std::uint8_t outdata[8];
130141cc406Sopenharmony_ci        std::vector<std::uint8_t> buffer;
131141cc406Sopenharmony_ci        buffer.reserve(regs.size() * 2);
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci        /* copy registers and values in data buffer */
134141cc406Sopenharmony_ci        for (const auto& r : regs) {
135141cc406Sopenharmony_ci            buffer.push_back(r.address);
136141cc406Sopenharmony_ci            buffer.push_back(r.value);
137141cc406Sopenharmony_ci        }
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci        DBG(DBG_io, "%s (elems= %zu, size = %zu)\n", __func__, regs.size(), buffer.size());
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci        if (dev_->model->asic_type == AsicType::GL646) {
142141cc406Sopenharmony_ci            outdata[0] = BULK_OUT;
143141cc406Sopenharmony_ci            outdata[1] = BULK_REGISTER;
144141cc406Sopenharmony_ci            outdata[2] = 0x00;
145141cc406Sopenharmony_ci            outdata[3] = 0x00;
146141cc406Sopenharmony_ci            outdata[4] = (buffer.size() & 0xff);
147141cc406Sopenharmony_ci            outdata[5] = ((buffer.size() >> 8) & 0xff);
148141cc406Sopenharmony_ci            outdata[6] = ((buffer.size() >> 16) & 0xff);
149141cc406Sopenharmony_ci            outdata[7] = ((buffer.size() >> 24) & 0xff);
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci            usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX,
152141cc406Sopenharmony_ci                                 sizeof(outdata), outdata);
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci            size_t write_size = buffer.size();
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci            usb_dev_.bulk_write(buffer.data(), &write_size);
157141cc406Sopenharmony_ci        } else {
158141cc406Sopenharmony_ci            for (std::size_t i = 0; i < regs.size();) {
159141cc406Sopenharmony_ci                std::size_t c = regs.size() - i;
160141cc406Sopenharmony_ci                if (c > 32)  /*32 is max on GL841. checked that.*/
161141cc406Sopenharmony_ci                    c = 32;
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci                usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER,
164141cc406Sopenharmony_ci                                     INDEX, c * 2, buffer.data() + i * 2);
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci                i += c;
167141cc406Sopenharmony_ci            }
168141cc406Sopenharmony_ci        }
169141cc406Sopenharmony_ci    } else {
170141cc406Sopenharmony_ci        for (const auto& r : regs) {
171141cc406Sopenharmony_ci            write_register(r.address, r.value);
172141cc406Sopenharmony_ci        }
173141cc406Sopenharmony_ci    }
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci    DBG(DBG_io, "%s: wrote %zu registers\n", __func__, regs.size());
176141cc406Sopenharmony_ci}
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_0x8c(std::uint8_t index, std::uint8_t value)
179141cc406Sopenharmony_ci{
180141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, value);
181141cc406Sopenharmony_ci    usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, 1, &value);
182141cc406Sopenharmony_ci}
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_cistatic void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, size_t size)
185141cc406Sopenharmony_ci{
186141cc406Sopenharmony_ci    DBG_HELPER(dbg);
187141cc406Sopenharmony_ci
188141cc406Sopenharmony_ci    std::uint8_t outdata[8];
189141cc406Sopenharmony_ci    if (asic_type == AsicType::GL124 ||
190141cc406Sopenharmony_ci        asic_type == AsicType::GL845 ||
191141cc406Sopenharmony_ci        asic_type == AsicType::GL846 ||
192141cc406Sopenharmony_ci        asic_type == AsicType::GL847)
193141cc406Sopenharmony_ci    {
194141cc406Sopenharmony_ci        // hard coded 0x10000000 address
195141cc406Sopenharmony_ci        outdata[0] = 0;
196141cc406Sopenharmony_ci        outdata[1] = 0;
197141cc406Sopenharmony_ci        outdata[2] = 0;
198141cc406Sopenharmony_ci        outdata[3] = 0x10;
199141cc406Sopenharmony_ci    } else if (asic_type == AsicType::GL841 ||
200141cc406Sopenharmony_ci               asic_type == AsicType::GL842 ||
201141cc406Sopenharmony_ci               asic_type == AsicType::GL843)
202141cc406Sopenharmony_ci    {
203141cc406Sopenharmony_ci        outdata[0] = BULK_IN;
204141cc406Sopenharmony_ci        outdata[1] = BULK_RAM;
205141cc406Sopenharmony_ci        outdata[2] = 0x82; //
206141cc406Sopenharmony_ci        outdata[3] = 0x00;
207141cc406Sopenharmony_ci    } else {
208141cc406Sopenharmony_ci        outdata[0] = BULK_IN;
209141cc406Sopenharmony_ci        outdata[1] = BULK_RAM;
210141cc406Sopenharmony_ci        outdata[2] = 0x00;
211141cc406Sopenharmony_ci        outdata[3] = 0x00;
212141cc406Sopenharmony_ci    }
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci    /* data size to transfer */
215141cc406Sopenharmony_ci    outdata[4] = (size & 0xff);
216141cc406Sopenharmony_ci    outdata[5] = ((size >> 8) & 0xff);
217141cc406Sopenharmony_ci    outdata[6] = ((size >> 16) & 0xff);
218141cc406Sopenharmony_ci    outdata[7] = ((size >> 24) & 0xff);
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci   usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00,
221141cc406Sopenharmony_ci                       sizeof(outdata), outdata);
222141cc406Sopenharmony_ci}
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_civoid ScannerInterfaceUsb::bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size)
225141cc406Sopenharmony_ci{
226141cc406Sopenharmony_ci    // currently supported: GL646, GL841, GL843, GL845, GL846, GL847, GL124
227141cc406Sopenharmony_ci    DBG_HELPER(dbg);
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci    unsigned is_addr_used = 1;
230141cc406Sopenharmony_ci    unsigned has_header_before_each_chunk = 0;
231141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL124 ||
232141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL845 ||
233141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL846 ||
234141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL847)
235141cc406Sopenharmony_ci    {
236141cc406Sopenharmony_ci        is_addr_used = 0;
237141cc406Sopenharmony_ci        has_header_before_each_chunk = 1;
238141cc406Sopenharmony_ci    }
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci    if (is_addr_used) {
241141cc406Sopenharmony_ci        DBG(DBG_io, "%s: requesting %zu bytes from 0x%02x addr\n", __func__, size, addr);
242141cc406Sopenharmony_ci    } else {
243141cc406Sopenharmony_ci        DBG(DBG_io, "%s: requesting %zu bytes\n", __func__, size);
244141cc406Sopenharmony_ci    }
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci    if (size == 0)
247141cc406Sopenharmony_ci        return;
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_ci    if (is_addr_used) {
250141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00,
251141cc406Sopenharmony_ci                             1, &addr);
252141cc406Sopenharmony_ci    }
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_ci    std::size_t target_size = size;
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci    std::size_t max_in_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type);
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci    if (!has_header_before_each_chunk) {
259141cc406Sopenharmony_ci        bulk_read_data_send_header(usb_dev_, dev_->model->asic_type, size);
260141cc406Sopenharmony_ci    }
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci    // loop until computed data size is read
263141cc406Sopenharmony_ci    while (target_size > 0) {
264141cc406Sopenharmony_ci        std::size_t block_size = std::min(target_size, max_in_size);
265141cc406Sopenharmony_ci
266141cc406Sopenharmony_ci        if (has_header_before_each_chunk) {
267141cc406Sopenharmony_ci            bulk_read_data_send_header(usb_dev_, dev_->model->asic_type, block_size);
268141cc406Sopenharmony_ci        }
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci        DBG(DBG_io2, "%s: trying to read %zu bytes of data\n", __func__, block_size);
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci        usb_dev_.bulk_read(data, &block_size);
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci        DBG(DBG_io2, "%s: read %zu bytes, %zu remaining\n", __func__, block_size, target_size - block_size);
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_ci        target_size -= block_size;
277141cc406Sopenharmony_ci        data += block_size;
278141cc406Sopenharmony_ci    }
279141cc406Sopenharmony_ci}
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_civoid ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t len)
282141cc406Sopenharmony_ci{
283141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "writing %zu bytes", len);
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci    // supported: GL646, GL841, GL843
286141cc406Sopenharmony_ci    std::size_t size;
287141cc406Sopenharmony_ci    std::uint8_t outdata[8];
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci    usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX,
290141cc406Sopenharmony_ci                             1, &addr);
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci    std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type);
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci    while (len) {
295141cc406Sopenharmony_ci        if (len > max_out_size)
296141cc406Sopenharmony_ci            size = max_out_size;
297141cc406Sopenharmony_ci        else
298141cc406Sopenharmony_ci            size = len;
299141cc406Sopenharmony_ci
300141cc406Sopenharmony_ci        if (dev_->model->asic_type == AsicType::GL841) {
301141cc406Sopenharmony_ci            outdata[0] = BULK_OUT;
302141cc406Sopenharmony_ci            outdata[1] = BULK_RAM;
303141cc406Sopenharmony_ci            // both 0x82 and 0x00 works on GL841.
304141cc406Sopenharmony_ci            outdata[2] = 0x82;
305141cc406Sopenharmony_ci            outdata[3] = 0x00;
306141cc406Sopenharmony_ci        } else {
307141cc406Sopenharmony_ci            outdata[0] = BULK_OUT;
308141cc406Sopenharmony_ci            outdata[1] = BULK_RAM;
309141cc406Sopenharmony_ci            // 8600F uses 0x82, but 0x00 works too. 8400F uses 0x02 for certain transactions.
310141cc406Sopenharmony_ci            outdata[2] = 0x00;
311141cc406Sopenharmony_ci            outdata[3] = 0x00;
312141cc406Sopenharmony_ci        }
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci        outdata[4] = (size & 0xff);
315141cc406Sopenharmony_ci        outdata[5] = ((size >> 8) & 0xff);
316141cc406Sopenharmony_ci        outdata[6] = ((size >> 16) & 0xff);
317141cc406Sopenharmony_ci        outdata[7] = ((size >> 24) & 0xff);
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci        usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00,
320141cc406Sopenharmony_ci                             sizeof(outdata), outdata);
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci        usb_dev_.bulk_write(data, &size);
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci        DBG(DBG_io2, "%s: wrote %zu bytes, %zu remaining\n", __func__, size, len - size);
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci        len -= size;
327141cc406Sopenharmony_ci        data += size;
328141cc406Sopenharmony_ci    }
329141cc406Sopenharmony_ci}
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
332141cc406Sopenharmony_ci                                       std::size_t size)
333141cc406Sopenharmony_ci{
334141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
335141cc406Sopenharmony_ci    if (dev_->model->asic_type != AsicType::GL646 &&
336141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL841 &&
337141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL842 &&
338141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL843)
339141cc406Sopenharmony_ci    {
340141cc406Sopenharmony_ci        throw SaneException("Unsupported transfer mode");
341141cc406Sopenharmony_ci    }
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL843) {
344141cc406Sopenharmony_ci        write_register(0x2b, ((addr >> 4) & 0xff));
345141cc406Sopenharmony_ci        write_register(0x2a, ((addr >> 12) & 0xff));
346141cc406Sopenharmony_ci        write_register(0x29, ((addr >> 20) & 0xff));
347141cc406Sopenharmony_ci    } else {
348141cc406Sopenharmony_ci        write_register(0x2b, ((addr >> 4) & 0xff));
349141cc406Sopenharmony_ci        write_register(0x2a, ((addr >> 12) & 0xff));
350141cc406Sopenharmony_ci    }
351141cc406Sopenharmony_ci    bulk_write_data(type, data, size);
352141cc406Sopenharmony_ci}
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
355141cc406Sopenharmony_ci                                      std::size_t size)
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
358141cc406Sopenharmony_ci    if (dev_->model->asic_type != AsicType::GL841 &&
359141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL842 &&
360141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL843)
361141cc406Sopenharmony_ci    {
362141cc406Sopenharmony_ci        throw SaneException("Unsupported transfer mode");
363141cc406Sopenharmony_ci    }
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci    write_register(0x5b, ((addr >> 12) & 0xff));
366141cc406Sopenharmony_ci    write_register(0x5c, ((addr >> 4) & 0xff));
367141cc406Sopenharmony_ci    bulk_write_data(type, data, size);
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL842 ||
370141cc406Sopenharmony_ci        dev_->model->asic_type == AsicType::GL843)
371141cc406Sopenharmony_ci    {
372141cc406Sopenharmony_ci        // it looks like we need to reset the address so that subsequent buffer operations work.
373141cc406Sopenharmony_ci        // Most likely the MTRTBL register is to blame.
374141cc406Sopenharmony_ci        write_register(0x5b, 0);
375141cc406Sopenharmony_ci        write_register(0x5c, 0);
376141cc406Sopenharmony_ci    }
377141cc406Sopenharmony_ci}
378141cc406Sopenharmony_ci
379141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data)
380141cc406Sopenharmony_ci{
381141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "address: 0x%08x, size: %d", static_cast<unsigned>(addr),
382141cc406Sopenharmony_ci                    static_cast<unsigned>(size));
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci    if (dev_->model->asic_type != AsicType::GL845 &&
385141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL846 &&
386141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL847 &&
387141cc406Sopenharmony_ci        dev_->model->asic_type != AsicType::GL124)
388141cc406Sopenharmony_ci    {
389141cc406Sopenharmony_ci        throw SaneException("Unsupported transfer type");
390141cc406Sopenharmony_ci    }
391141cc406Sopenharmony_ci    std::uint8_t outdata[8];
392141cc406Sopenharmony_ci    outdata[0] = addr & 0xff;
393141cc406Sopenharmony_ci    outdata[1] = ((addr >> 8) & 0xff);
394141cc406Sopenharmony_ci    outdata[2] = ((addr >> 16) & 0xff);
395141cc406Sopenharmony_ci    outdata[3] = ((addr >> 24) & 0xff);
396141cc406Sopenharmony_ci    outdata[4] = (size & 0xff);
397141cc406Sopenharmony_ci    outdata[5] = ((size >> 8) & 0xff);
398141cc406Sopenharmony_ci    outdata[6] = ((size >> 16) & 0xff);
399141cc406Sopenharmony_ci    outdata[7] = ((size >> 24) & 0xff);
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci    // write addr and size for AHB
402141cc406Sopenharmony_ci    usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata);
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci    std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type);
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci    // write actual data
407141cc406Sopenharmony_ci    std::size_t written = 0;
408141cc406Sopenharmony_ci    do {
409141cc406Sopenharmony_ci        std::size_t block_size = std::min(size - written, max_out_size);
410141cc406Sopenharmony_ci
411141cc406Sopenharmony_ci        usb_dev_.bulk_write(data + written, &block_size);
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci        written += block_size;
414141cc406Sopenharmony_ci    } while (written < size);
415141cc406Sopenharmony_ci}
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_cistd::uint16_t ScannerInterfaceUsb::read_fe_register(std::uint8_t address)
418141cc406Sopenharmony_ci{
419141cc406Sopenharmony_ci    DBG_HELPER(dbg);
420141cc406Sopenharmony_ci    Genesys_Register_Set reg;
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ci    reg.init_reg(0x50, address);
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci    // set up read address
425141cc406Sopenharmony_ci    write_registers(reg);
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci    // read data
428141cc406Sopenharmony_ci    std::uint16_t value = read_register(0x46) << 8;
429141cc406Sopenharmony_ci    value |= read_register(0x47);
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci    DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, address, value);
432141cc406Sopenharmony_ci    return value;
433141cc406Sopenharmony_ci}
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_civoid ScannerInterfaceUsb::write_fe_register(std::uint8_t address, std::uint16_t value)
436141cc406Sopenharmony_ci{
437141cc406Sopenharmony_ci    DBG_HELPER_ARGS(dbg, "0x%02x, 0x%04x", address, value);
438141cc406Sopenharmony_ci    Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL);
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci    reg.init_reg(0x51, address);
441141cc406Sopenharmony_ci    if (dev_->model->asic_type == AsicType::GL124) {
442141cc406Sopenharmony_ci        reg.init_reg(0x5d, (value / 256) & 0xff);
443141cc406Sopenharmony_ci        reg.init_reg(0x5e, value & 0xff);
444141cc406Sopenharmony_ci    } else {
445141cc406Sopenharmony_ci        reg.init_reg(0x3a, (value / 256) & 0xff);
446141cc406Sopenharmony_ci        reg.init_reg(0x3b, value & 0xff);
447141cc406Sopenharmony_ci    }
448141cc406Sopenharmony_ci
449141cc406Sopenharmony_ci    write_registers(reg);
450141cc406Sopenharmony_ci}
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ciIUsbDevice& ScannerInterfaceUsb::get_usb_device()
453141cc406Sopenharmony_ci{
454141cc406Sopenharmony_ci    return usb_dev_;
455141cc406Sopenharmony_ci}
456141cc406Sopenharmony_ci
457141cc406Sopenharmony_civoid ScannerInterfaceUsb::sleep_us(unsigned microseconds)
458141cc406Sopenharmony_ci{
459141cc406Sopenharmony_ci    if (sanei_usb_is_replay_mode_enabled()) {
460141cc406Sopenharmony_ci        return;
461141cc406Sopenharmony_ci    }
462141cc406Sopenharmony_ci    usleep(microseconds);
463141cc406Sopenharmony_ci}
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_civoid ScannerInterfaceUsb::record_progress_message(const char* msg)
466141cc406Sopenharmony_ci{
467141cc406Sopenharmony_ci    sanei_usb_testing_record_message(msg);
468141cc406Sopenharmony_ci}
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_civoid ScannerInterfaceUsb::record_slope_table(unsigned table_nr,
471141cc406Sopenharmony_ci                                             const std::vector<std::uint16_t>& steps)
472141cc406Sopenharmony_ci{
473141cc406Sopenharmony_ci    (void) table_nr;
474141cc406Sopenharmony_ci    (void) steps;
475141cc406Sopenharmony_ci}
476141cc406Sopenharmony_ci
477141cc406Sopenharmony_civoid ScannerInterfaceUsb::record_key_value(const std::string& key, const std::string& value)
478141cc406Sopenharmony_ci{
479141cc406Sopenharmony_ci    (void) key;
480141cc406Sopenharmony_ci    (void) value;
481141cc406Sopenharmony_ci}
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_civoid ScannerInterfaceUsb::test_checkpoint(const std::string& name)
484141cc406Sopenharmony_ci{
485141cc406Sopenharmony_ci    (void) name;
486141cc406Sopenharmony_ci}
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci} // namespace genesys
489