From 0582b5448c1943ea73ba51f7c2e8a9b19c3f566c Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Sat, 26 Oct 2019 11:38:40 +0200 Subject: [PATCH] genesys: Move low-level protocol implementation to ScannerInterfaceUsb --- backend/genesys/low.cpp | 501 ---------------------- backend/genesys/low.h | 26 +- backend/genesys/scanner_interface_usb.cpp | 335 ++++++++++++++- 3 files changed, 323 insertions(+), 539 deletions(-) diff --git a/backend/genesys/low.cpp b/backend/genesys/low.cpp index 710df9dd4..6a90edeba 100644 --- a/backend/genesys/low.cpp +++ b/backend/genesys/low.cpp @@ -230,332 +230,6 @@ unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type) return 0xf000; } -void sanei_genesys_bulk_read_data_send_header(Genesys_Device* dev, size_t len) -{ - DBG_HELPER(dbg); - - uint8_t outdata[8]; - if (dev->model->asic_type == AsicType::GL124 || - dev->model->asic_type == AsicType::GL846 || - dev->model->asic_type == AsicType::GL847) - { - // hard coded 0x10000000 address - outdata[0] = 0; - outdata[1] = 0; - outdata[2] = 0; - outdata[3] = 0x10; - } else if (dev->model->asic_type == AsicType::GL841 || - dev->model->asic_type == AsicType::GL843) { - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = 0x82; // - outdata[3] = 0x00; - } else { - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - } - - /* data size to transfer */ - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, - sizeof(outdata), outdata); -} - -void sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len) -{ - DBG_HELPER(dbg); - - // currently supported: GL646, GL841, GL843, GL846, GL847, GL124 - size_t size, target; - - unsigned is_addr_used = 1; - unsigned has_header_before_each_chunk = 0; - if (dev->model->asic_type == AsicType::GL124 || - dev->model->asic_type == AsicType::GL846 || - dev->model->asic_type == AsicType::GL847) - { - is_addr_used = 0; - has_header_before_each_chunk = 1; - } - - if (is_addr_used) { - DBG(DBG_io, "%s: requesting %zu bytes from 0x%02x addr\n", __func__, len, addr); - } else { - DBG(DBG_io, "%s: requesting %zu bytes\n", __func__, len); - } - - if (len == 0) - return; - - if (is_addr_used) { - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00, - 1, &addr); - } - - target = len; - - size_t max_in_size = sanei_genesys_get_bulk_max_size(dev->model->asic_type); - - if (!has_header_before_each_chunk) { - sanei_genesys_bulk_read_data_send_header(dev, len); - } - - // loop until computed data size is read - while (target) { - if (target > max_in_size) { - size = max_in_size; - } else { - size = target; - } - - if (has_header_before_each_chunk) { - sanei_genesys_bulk_read_data_send_header(dev, size); - } - - DBG(DBG_io2, "%s: trying to read %zu bytes of data\n", __func__, size); - - dev->usb_dev.bulk_read(data, &size); - - DBG(DBG_io2, "%s: read %zu bytes, %zu remaining\n", __func__, size, target - size); - - target -= size; - data += size; - } -} - -void sanei_genesys_bulk_write_data(Genesys_Device* dev, uint8_t addr, uint8_t* data, size_t len) -{ - DBG_HELPER_ARGS(dbg, "writing %zu bytes", len); - - // supported: GL646, GL841, GL843 - size_t size; - uint8_t outdata[8]; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, &addr); - - size_t max_out_size = sanei_genesys_get_bulk_max_size(dev->model->asic_type); - - while (len) { - if (len > max_out_size) - size = max_out_size; - else - size = len; - - if (dev->model->asic_type == AsicType::GL841) { - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - // both 0x82 and 0x00 works on GL841. - outdata[2] = 0x82; - outdata[3] = 0x00; - } else { - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - // 8600F uses 0x82, but 0x00 works too. 8400F uses 0x02 for certain transactions. - outdata[2] = 0x00; - outdata[3] = 0x00; - } - - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, - sizeof(outdata), outdata); - - dev->usb_dev.bulk_write(data, &size); - - DBG(DBG_io2, "%s: wrote %zu bytes, %zu remaining\n", __func__, size, len - size); - - len -= size; - data += size; - } -} - -/** @brief write to one high (addr >= 0x100) register - * write to a register which address is higher than 0xff. - * @param dev opened device to write to - * @param reg LSB of register address - * @param val value to write - */ -static void sanei_genesys_write_hregister(Genesys_Device* dev, uint16_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - uint8_t buffer[2]; - - buffer[0]=reg & 0xff; - buffer[1]=val; - - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, 0x100 | VALUE_SET_REGISTER, INDEX, - 2, buffer); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); -} - -/** @brief read from one high (addr >= 0x100) register - * Read to a register which address is higher than 0xff. Second byte is check to detect - * physical link errors. - * @param dev opened device to read from - * @param reg LSB of register address - * @param val value to write - */ -static void sanei_genesys_read_hregister(Genesys_Device* dev, uint16_t reg, uint8_t* val) -{ - DBG_HELPER(dbg); - - SANE_Byte value[2]; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, 0x100 | VALUE_GET_REGISTER, - 0x22+((reg & 0xff)<<8), 2, value); - - *val=value[0]; - DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); - - /* check usb link status */ - if ((value[1] & 0xff) != 0x55) { - throw SaneException(SANE_STATUS_IO_ERROR, "invalid read, scanner unplugged"); - } -} - -/** - * Write to one GL847 ASIC register -URB 10 control 0x40 0x04 0x83 0x00 len 2 wrote 0xa6 0x04 - */ -static void sanei_genesys_write_gl847_register(Genesys_Device* dev, uint8_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - uint8_t buffer[2]; - - buffer[0]=reg; - buffer[1]=val; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, INDEX, - 2, buffer); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); -} - -/** - * Write to one ASIC register - */ -void sanei_genesys_write_register(Genesys_Device* dev, uint16_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - SANE_Byte reg8; - - // 16 bit register address space - if (reg > 255) { - sanei_genesys_write_hregister(dev, reg, val); - return; - } - - // route to gl847 function if needed - if (dev->model->asic_type == AsicType::GL847 || - dev->model->asic_type == AsicType::GL845 || - dev->model->asic_type == AsicType::GL846 || - dev->model->asic_type == AsicType::GL124) - { - sanei_genesys_write_gl847_register(dev, reg, val); - return; - } - - reg8=reg & 0xff; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, ®8); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX, - 1, &val); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); - return; -} - -/** - * @brief write command to 0x8c endpoint - * Write a value to 0x8c end point (end access), for USB firmware related operations - * Known values are 0x0f, 0x11 for USB 2.0 data transfer and 0x0f,0x14 for USB1.1 - * @param dev device to write to - * @param index index of the command - * @param val value to write - */ -void sanei_genesys_write_0x8c(Genesys_Device* dev, uint8_t index, uint8_t val) -{ - DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, val); - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, 1, - &val); -} - -/* read reg 0x41: - * URB 164 control 0xc0 0x04 0x8e 0x4122 len 2 read 0xfc 0x55 - */ -static void sanei_genesys_read_gl847_register(Genesys_Device* dev, uint16_t reg, uint8_t* val) -{ - DBG_HELPER(dbg); - SANE_Byte value[2]; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, VALUE_GET_REGISTER, 0x22+(reg<<8), - 2, value); - - *val=value[0]; - DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); - - /* check usb link status */ - if((value[1] & 0xff) != 0x55) - { - throw SaneException(SANE_STATUS_IO_ERROR, "invalid read, scanner unplugged?"); - } -} - -// Read from one register -void sanei_genesys_read_register(Genesys_Device* dev, uint16_t reg, uint8_t* val) -{ - DBG_HELPER(dbg); - - SANE_Byte reg8; - - // 16 bit register address space - if (reg > 255) { - sanei_genesys_read_hregister(dev, reg, val); - return; - } - - // route to gl847 function if needed - if (dev->model->asic_type == AsicType::GL847 || - dev->model->asic_type == AsicType::GL845 || - dev->model->asic_type == AsicType::GL846 || - dev->model->asic_type == AsicType::GL124) - { - sanei_genesys_read_gl847_register(dev, reg, val); - return; - } - - /* 8 bit register address space */ - reg8 = reg & 0Xff; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, ®8); - - *val = 0; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, - 1, val); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, *val); -} - // Set address for writing data void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr) { @@ -580,54 +254,6 @@ void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr) dev->write_register(0x2a, (addr & 0xff)); } -/**@brief read data from analog frontend (AFE) - * @param dev device owning the AFE - * @param addr register address to read - * @param data placeholder for the result - */ -void sanei_genesys_fe_read_data (Genesys_Device* dev, uint8_t addr, uint16_t* data) -{ - DBG_HELPER(dbg); - Genesys_Register_Set reg; - - reg.init_reg(0x50, addr); - - // set up read address - dev->write_registers(reg); - - // read data - uint8_t value = dev->read_register(0x46); - *data = 256 * value; - value = dev->read_register(0x47); - *data += value; - - DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, addr, *data); -} - -/*@brief write data to analog frontend - * writes data to analog frontend to set it up accordingly - * to the sensor settings (exposure, timings, color, bit depth, ...) - * @param dev devie owning the AFE to write to - * @param addr AFE rister address - * @param data value to write to AFE register - **/ -void sanei_genesys_fe_write_data(Genesys_Device* dev, uint8_t addr, uint16_t data) -{ - DBG_HELPER_ARGS(dbg, "0x%02x, 0x%04x", addr, data); - Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL); - - reg.init_reg(0x51, addr); - if (dev->model->asic_type == AsicType::GL124) { - reg.init_reg(0x5d, (data / 256) & 0xff); - reg.init_reg(0x5e, data & 0xff); - } else { - reg.init_reg(0x3a, (data / 256) & 0xff); - reg.init_reg(0x3b, data & 0xff); - } - - dev->write_registers(reg); -} - /* ------------------------------------------------------------------------ */ /* Medium level functions */ /* ------------------------------------------------------------------------ */ @@ -985,133 +611,6 @@ bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& senso return true; } -/** - * Write to many registers at once - * Note: sequential call to write register, no effective - * bulk write implemented. - * @param dev device to write to - * @param reg pointer to an array of registers - * @param elems size of the array - */ -void sanei_genesys_bulk_write_register(Genesys_Device* dev, const Genesys_Register_Set& reg) -{ - DBG_HELPER(dbg); - - if (dev->model->asic_type == AsicType::GL646 || - dev->model->asic_type == AsicType::GL841) - { - uint8_t outdata[8]; - std::vector buffer; - buffer.reserve(reg.size() * 2); - - /* copy registers and values in data buffer */ - for (const auto& r : reg) { - buffer.push_back(r.address); - buffer.push_back(r.value); - } - - DBG(DBG_io, "%s (elems= %zu, size = %zu)\n", __func__, reg.size(), buffer.size()); - - if (dev->model->asic_type == AsicType::GL646) { - outdata[0] = BULK_OUT; - outdata[1] = BULK_REGISTER; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (buffer.size() & 0xff); - outdata[5] = ((buffer.size() >> 8) & 0xff); - outdata[6] = ((buffer.size() >> 16) & 0xff); - outdata[7] = ((buffer.size() >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX, - sizeof(outdata), outdata); - - size_t write_size = buffer.size(); - - dev->usb_dev.bulk_write(buffer.data(), &write_size); - } else { - for (size_t i = 0; i < reg.size();) { - size_t c = reg.size() - i; - if (c > 32) /*32 is max on GL841. checked that.*/ - c = 32; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, - INDEX, c * 2, buffer.data() + i * 2); - - i += c; - } - } - } else { - for (const auto& r : reg) { - dev->write_register(r.address, r.value); - } - } - - DBG (DBG_io, "%s: wrote %zu registers\n", __func__, reg.size()); -} - - - -/** - * writes a block of data to AHB - * @param dn USB device index - * @param usb_mode usb mode : 1 usb 1.1, 2 usb 2.0 - * @param addr AHB address to write to - * @param size size of the chunk of data - * @param data pointer to the data to write - */ -void sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, uint8_t* data) -{ - DBG_HELPER(dbg); - - uint8_t outdata[8]; - size_t written,blksize; - int i; - char msg[100]="AHB="; - - outdata[0] = addr & 0xff; - outdata[1] = ((addr >> 8) & 0xff); - outdata[2] = ((addr >> 16) & 0xff); - outdata[3] = ((addr >> 24) & 0xff); - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - if (DBG_LEVEL >= DBG_io) - { - for (i = 0; i < 8; i++) - { - sprintf (msg+strlen(msg), " 0x%02x", outdata[i]); - } - DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __func__, addr,size); - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - // write addr and size for AHB - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata); - - size_t max_out_size = sanei_genesys_get_bulk_max_size(dev->model->asic_type); - - /* write actual data */ - written = 0; - do - { - if (size - written > max_out_size) - { - blksize = max_out_size; - } - else - { - blksize = size - written; - } - dev->usb_dev.bulk_write(data + written, &blksize); - - written += blksize; - } - while (written < size); -} - - std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, int color) { diff --git a/backend/genesys/low.h b/backend/genesys/low.h index 2f049ca93..24a3650b1 100644 --- a/backend/genesys/low.h +++ b/backend/genesys/low.h @@ -279,21 +279,6 @@ inline GenesysRegister* sanei_genesys_get_address(Genesys_Register_Set* regs, ui extern void sanei_genesys_init_cmd_set(Genesys_Device* dev); -extern void sanei_genesys_read_register(Genesys_Device* dev, uint16_t reg, uint8_t* val); - -extern void sanei_genesys_write_register(Genesys_Device* dev, uint16_t reg, uint8_t val); - -extern void sanei_genesys_bulk_write_register(Genesys_Device* dev, - const Genesys_Register_Set& regs); - -extern void sanei_genesys_write_0x8c(Genesys_Device* dev, uint8_t index, uint8_t val); - -extern void sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len); - -extern void sanei_genesys_bulk_write_data(Genesys_Device* dev, uint8_t addr, uint8_t* data, - size_t len); - std::uint8_t sanei_genesys_get_status(Genesys_Device* dev); extern void sanei_genesys_print_status (uint8_t val); @@ -355,16 +340,7 @@ void sanei_genesys_calculate_zmod(bool two_table, extern void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr); -/** @brief Reads data from frontend register. - * Reads data from the given frontend register. May be used to query - * analog frontend status by reading the right register. - */ -extern void sanei_genesys_fe_read_data(Genesys_Device* dev, uint8_t addr, uint16_t* data); -/** @brief Write data to frontend register. - * Writes data to analog frontend register at the given address. - * The use and address of registers change from model to model. - */ -extern void sanei_genesys_fe_write_data(Genesys_Device* dev, uint8_t addr, uint16_t data); +unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type); SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi, int step_type, int endpixel, int led_exposure); diff --git a/backend/genesys/scanner_interface_usb.cpp b/backend/genesys/scanner_interface_usb.cpp index 59a0897cb..079034d19 100644 --- a/backend/genesys/scanner_interface_usb.cpp +++ b/backend/genesys/scanner_interface_usb.cpp @@ -59,52 +59,361 @@ bool ScannerInterfaceUsb::is_mock() const std::uint8_t ScannerInterfaceUsb::read_register(std::uint16_t address) { - std::uint8_t value; - sanei_genesys_read_register(dev_, address, &value); + DBG_HELPER(dbg); + + std::uint8_t value = 0; + + if (dev_->model->asic_type == AsicType::GL847 || + dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL124) + { + std::uint8_t value2x8[2]; + std::uint16_t address16 = 0x22 + (address << 8); + + std::uint16_t usb_value = VALUE_GET_REGISTER; + if (address > 0xff) { + usb_value |= 0x100; + } + + dev_->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, usb_value, address16, + 2, value2x8); + + // check usb link status + if (value2x8[1] != 0x55) { + throw SaneException(SANE_STATUS_IO_ERROR, "invalid read, scanner unplugged?"); + } + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value2x8[0]); + + value = value2x8[0]; + + } else { + + if (address > 0xff) { + throw SaneException("Invalid register address 0x%04x", address); + } + + std::uint8_t address8 = address & 0xff; + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &address8); + dev_->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, + 1, &value); + } + + DBG(DBG_proc, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value); return value; } void ScannerInterfaceUsb::write_register(std::uint16_t address, std::uint8_t value) { - sanei_genesys_write_register(dev_, address, value); + DBG_HELPER_ARGS(dbg, "address: 0x%04x, value: 0x%02x", static_cast(address), + static_cast(value)); + + if (dev_->model->asic_type == AsicType::GL847 || + dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL124) + { + std::uint8_t buffer[2]; + + buffer[0] = address & 0xff; + buffer[1] = value; + + std::uint16_t usb_value = VALUE_SET_REGISTER; + if (address > 0xff) { + usb_value |= 0x100; + } + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, usb_value, INDEX, + 2, buffer); + + } else { + if (address > 0xff) { + throw SaneException("Invalid register address 0x%04x", address); + } + + std::uint8_t address8 = address & 0xff; + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &address8); + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX, + 1, &value); + + } + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value); } void ScannerInterfaceUsb::write_registers(const Genesys_Register_Set& regs) { - sanei_genesys_bulk_write_register(dev_, regs); + DBG_HELPER(dbg); + if (dev_->model->asic_type == AsicType::GL646 || + dev_->model->asic_type == AsicType::GL841) + { + uint8_t outdata[8]; + std::vector buffer; + buffer.reserve(regs.size() * 2); + + /* copy registers and values in data buffer */ + for (const auto& r : regs) { + buffer.push_back(r.address); + buffer.push_back(r.value); + } + + DBG(DBG_io, "%s (elems= %zu, size = %zu)\n", __func__, regs.size(), buffer.size()); + + if (dev_->model->asic_type == AsicType::GL646) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_REGISTER; + outdata[2] = 0x00; + outdata[3] = 0x00; + outdata[4] = (buffer.size() & 0xff); + outdata[5] = ((buffer.size() >> 8) & 0xff); + outdata[6] = ((buffer.size() >> 16) & 0xff); + outdata[7] = ((buffer.size() >> 24) & 0xff); + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX, + sizeof(outdata), outdata); + + size_t write_size = buffer.size(); + + dev_->usb_dev.bulk_write(buffer.data(), &write_size); + } else { + for (std::size_t i = 0; i < regs.size();) { + std::size_t c = regs.size() - i; + if (c > 32) /*32 is max on GL841. checked that.*/ + c = 32; + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, + INDEX, c * 2, buffer.data() + i * 2); + + i += c; + } + } + } else { + for (const auto& r : regs) { + dev_->write_register(r.address, r.value); + } + } + + DBG(DBG_io, "%s: wrote %zu registers\n", __func__, regs.size()); } void ScannerInterfaceUsb::write_0x8c(std::uint8_t index, std::uint8_t value) { - sanei_genesys_write_0x8c(dev_, index, value); + DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, value); + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, 1, + &value); +} + +static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, size_t size) +{ + DBG_HELPER(dbg); + + uint8_t outdata[8]; + if (asic_type == AsicType::GL124 || + asic_type == AsicType::GL846 || + asic_type == AsicType::GL847) + { + // hard coded 0x10000000 address + outdata[0] = 0; + outdata[1] = 0; + outdata[2] = 0; + outdata[3] = 0x10; + } else if (asic_type == AsicType::GL841 || + asic_type == AsicType::GL843) { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = 0x82; // + outdata[3] = 0x00; + } else { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + /* data size to transfer */ + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); } void ScannerInterfaceUsb::bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) { - sanei_genesys_bulk_read_data(dev_, addr, data, size); + // currently supported: GL646, GL841, GL843, GL846, GL847, GL124 + DBG_HELPER(dbg); + + unsigned is_addr_used = 1; + unsigned has_header_before_each_chunk = 0; + if (dev_->model->asic_type == AsicType::GL124 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL847) + { + is_addr_used = 0; + has_header_before_each_chunk = 1; + } + + if (is_addr_used) { + DBG(DBG_io, "%s: requesting %zu bytes from 0x%02x addr\n", __func__, size, addr); + } else { + DBG(DBG_io, "%s: requesting %zu bytes\n", __func__, size); + } + + if (size == 0) + return; + + if (is_addr_used) { + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00, + 1, &addr); + } + + std::size_t target_size = size; + + std::size_t max_in_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + if (!has_header_before_each_chunk) { + bulk_read_data_send_header(dev_->usb_dev, dev_->model->asic_type, size); + } + + // loop until computed data size is read + while (target_size > 0) { + std::size_t block_size = std::min(target_size, max_in_size); + + if (has_header_before_each_chunk) { + bulk_read_data_send_header(dev_->usb_dev, dev_->model->asic_type, block_size); + } + + DBG(DBG_io2, "%s: trying to read %zu bytes of data\n", __func__, block_size); + + dev_->usb_dev.bulk_read(data, &block_size); + + DBG(DBG_io2, "%s: read %zu bytes, %zu remaining\n", __func__, block_size, target_size - block_size); + + target_size -= block_size; + data += block_size; + } } -void ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) +void ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t len) { - sanei_genesys_bulk_write_data(dev_, addr, data, size); -} + DBG_HELPER_ARGS(dbg, "writing %zu bytes", len); + // supported: GL646, GL841, GL843 + std::size_t size; + std::uint8_t outdata[8]; + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &addr); + + std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + while (len) { + if (len > max_out_size) + size = max_out_size; + else + size = len; + + if (dev_->model->asic_type == AsicType::GL841) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + // both 0x82 and 0x00 works on GL841. + outdata[2] = 0x82; + outdata[3] = 0x00; + } else { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + // 8600F uses 0x82, but 0x00 works too. 8400F uses 0x02 for certain transactions. + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); + + dev_->usb_dev.bulk_write(data, &size); + + DBG(DBG_io2, "%s: wrote %zu bytes, %zu remaining\n", __func__, size, len - size); + + len -= size; + data += size; + } +} void ScannerInterfaceUsb::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) { - sanei_genesys_write_ahb(dev_, addr, size, data); + DBG_HELPER_ARGS(dbg, "size %d", static_cast(size)); + + std::uint8_t outdata[8]; + outdata[0] = addr & 0xff; + outdata[1] = ((addr >> 8) & 0xff); + outdata[2] = ((addr >> 16) & 0xff); + outdata[3] = ((addr >> 24) & 0xff); + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + // write addr and size for AHB + dev_->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata); + + std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + // write actual data + std::size_t written = 0; + do { + std::size_t block_size = std::min(size - written, max_out_size); + + dev_->usb_dev.bulk_write(data + written, &block_size); + + written += block_size; + } while (written < size); } std::uint16_t ScannerInterfaceUsb::read_fe_register(std::uint8_t address) { - std::uint16_t value; - sanei_genesys_fe_read_data(dev_, address, &value); + DBG_HELPER(dbg); + Genesys_Register_Set reg; + + reg.init_reg(0x50, address); + + // set up read address + dev_->write_registers(reg); + + // read data + std::uint16_t value = dev_->read_register(0x46) << 8; + value |= dev_->read_register(0x47); + + DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, address, value); return value; } void ScannerInterfaceUsb::write_fe_register(std::uint8_t address, std::uint16_t value) { - sanei_genesys_fe_write_data(dev_, address, value); + DBG_HELPER_ARGS(dbg, "0x%02x, 0x%04x", address, value); + Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL); + + reg.init_reg(0x51, address); + if (dev_->model->asic_type == AsicType::GL124) { + reg.init_reg(0x5d, (value / 256) & 0xff); + reg.init_reg(0x5e, value & 0xff); + } else { + reg.init_reg(0x3a, (value / 256) & 0xff); + reg.init_reg(0x3b, value & 0xff); + } + + dev_->write_registers(reg); } } // namespace genesys