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