diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-09-10 19:11:27 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-09-10 19:11:27 +0200 | 
| commit | 7e9455b3b15671ff99ed168638c405e2acedb6df (patch) | |
| tree | 444e59ece236e09dc153f665e42160aeb0208c24 /backend/genesys/gl847.cpp | |
| parent | bc8a517abd2e11e1435f4ef042cfcc8648b62ef7 (diff) | |
| parent | bce41b3c37c2a68e7dab234ce0247755a61ceb40 (diff) | |
Merge branch 'release/debian/1.0.31-1_experimental1' into masterdebian/1.0.31-1_experimental1
Diffstat (limited to 'backend/genesys/gl847.cpp')
| -rw-r--r-- | backend/genesys/gl847.cpp | 1883 | 
1 files changed, 484 insertions, 1399 deletions
| diff --git a/backend/genesys/gl847.cpp b/backend/genesys/gl847.cpp index cb0b527..f8f6b1c 100644 --- a/backend/genesys/gl847.cpp +++ b/backend/genesys/gl847.cpp @@ -56,39 +56,12 @@ namespace gl847 {  /**   * compute the step multiplier used   */ -static int -gl847_get_step_multiplier (Genesys_Register_Set * regs) +static unsigned gl847_get_step_multiplier (Genesys_Register_Set * regs)  { -    GenesysRegister *r = sanei_genesys_get_address(regs, 0x9d); -    int value = 1; -    if (r != nullptr) -    { -      value = (r->value & 0x0f)>>1; -      value = 1 << value; -    } -  DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); -  return value; +    unsigned value = (regs->get8(0x9d) & 0x0f) >> 1; +    return 1 << value;  } -/** @brief sensor specific settings -*/ -static void gl847_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, -                               Genesys_Register_Set* regs) -{ -    DBG_HELPER(dbg); - -    for (const auto& reg : sensor.custom_regs) { -        regs->set8(reg.address, reg.value); -    } - -    regs->set16(REG_EXPR, sensor.exposure.red); -    regs->set16(REG_EXPG, sensor.exposure.green); -    regs->set16(REG_EXPB, sensor.exposure.blue); - -    dev->segment_order = sensor.segment_order; -} - -  /** @brief set all registers to default values .   * This function is called only once at the beginning and   * fills register startup values for registers reused across scans. @@ -111,30 +84,49 @@ gl847_init_registers (Genesys_Device * dev)      dev->reg.clear();      dev->reg.init_reg(0x01, 0x82); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x01, 0x40); +    }      dev->reg.init_reg(0x02, 0x18);      dev->reg.init_reg(0x03, 0x50);      dev->reg.init_reg(0x04, 0x12); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x04, 0x20); +    }      dev->reg.init_reg(0x05, 0x80);      dev->reg.init_reg(0x06, 0x50); // FASTMODE + POWERBIT +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x06, 0xf8); +    }      dev->reg.init_reg(0x08, 0x10); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x08, 0x20); +    }      dev->reg.init_reg(0x09, 0x01); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x09, 0x00); +    }      dev->reg.init_reg(0x0a, 0x00);      dev->reg.init_reg(0x0b, 0x01); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x0b, 0x6b); +    }      dev->reg.init_reg(0x0c, 0x02); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x0c, 0x00); +    }      // LED exposures -    dev->reg.init_reg(0x10, 0x00); -    dev->reg.init_reg(0x11, 0x00); -    dev->reg.init_reg(0x12, 0x00); -    dev->reg.init_reg(0x13, 0x00); -    dev->reg.init_reg(0x14, 0x00); -    dev->reg.init_reg(0x15, 0x00); +    dev->reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below +    dev->reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below +    dev->reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below +    dev->reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below +    dev->reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below +    dev->reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below      dev->reg.init_reg(0x16, 0x10); // SENSOR_DEF      dev->reg.init_reg(0x17, 0x08); // SENSOR_DEF      dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF - -    // EXPDMY      dev->reg.init_reg(0x19, 0x50); // SENSOR_DEF      dev->reg.init_reg(0x1a, 0x34); // SENSOR_DEF @@ -142,32 +134,40 @@ gl847_init_registers (Genesys_Device * dev)      dev->reg.init_reg(0x1c, 0x02); // SENSOR_DEF      dev->reg.init_reg(0x1d, 0x04); // SENSOR_DEF      dev->reg.init_reg(0x1e, 0x10); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x1e, 0xf0); +    }      dev->reg.init_reg(0x1f, 0x04); -    dev->reg.init_reg(0x20, 0x02); -    dev->reg.init_reg(0x21, 0x10); -    dev->reg.init_reg(0x22, 0x7f); -    dev->reg.init_reg(0x23, 0x7f); -    dev->reg.init_reg(0x24, 0x10); -    dev->reg.init_reg(0x25, 0x00); -    dev->reg.init_reg(0x26, 0x00); -    dev->reg.init_reg(0x27, 0x00); -    dev->reg.init_reg(0x2c, 0x09); -    dev->reg.init_reg(0x2d, 0x60); -    dev->reg.init_reg(0x2e, 0x80); -    dev->reg.init_reg(0x2f, 0x80); -    dev->reg.init_reg(0x30, 0x00); -    dev->reg.init_reg(0x31, 0x10); -    dev->reg.init_reg(0x32, 0x15); -    dev->reg.init_reg(0x33, 0x0e); -    dev->reg.init_reg(0x34, 0x40); -    dev->reg.init_reg(0x35, 0x00); -    dev->reg.init_reg(0x36, 0x2a); -    dev->reg.init_reg(0x37, 0x30); -    dev->reg.init_reg(0x38, 0x2a); -    dev->reg.init_reg(0x39, 0xf8); -    dev->reg.init_reg(0x3d, 0x00); -    dev->reg.init_reg(0x3e, 0x00); -    dev->reg.init_reg(0x3f, 0x00); +    dev->reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition +    dev->reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup +    dev->reg.init_reg(0x22, 0x7f); // FWDSTEP: set during motor setup +    dev->reg.init_reg(0x23, 0x7f); // BWDSTEP: set during motor setup +    dev->reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup +    dev->reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup +    dev->reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup +    dev->reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup + +    dev->reg.init_reg(0x2c, 0x09); // DPISET: set during sensor setup +    dev->reg.init_reg(0x2d, 0x60); // DPISET: set during sensor setup + +    dev->reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold +    dev->reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold + +    dev->reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup +    dev->reg.init_reg(0x31, 0x10); // STRPIXEL: set during sensor setup +    dev->reg.init_reg(0x32, 0x15); // ENDPIXEL: set during sensor setup +    dev->reg.init_reg(0x33, 0x0e); // ENDPIXEL: set during sensor setup + +    dev->reg.init_reg(0x34, 0x40); // DUMMY: SENSOR_DEF +    dev->reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup +    dev->reg.init_reg(0x36, 0x2a); // MAXWD: set during scan setup +    dev->reg.init_reg(0x37, 0x30); // MAXWD: set during scan setup +    dev->reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF +    dev->reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF +    dev->reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup +    dev->reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup +    dev->reg.init_reg(0x3f, 0x00); // FEEDL: set during motor setup +      dev->reg.init_reg(0x52, 0x03); // SENSOR_DEF      dev->reg.init_reg(0x53, 0x07); // SENSOR_DEF      dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF @@ -177,30 +177,27 @@ gl847_init_registers (Genesys_Device * dev)      dev->reg.init_reg(0x58, 0x2a); // SENSOR_DEF      dev->reg.init_reg(0x59, 0xe1); // SENSOR_DEF      dev->reg.init_reg(0x5a, 0x55); // SENSOR_DEF -    dev->reg.init_reg(0x5e, 0x41); -    dev->reg.init_reg(0x5f, 0x40); -    dev->reg.init_reg(0x60, 0x00); -    dev->reg.init_reg(0x61, 0x21); -    dev->reg.init_reg(0x62, 0x40); -    dev->reg.init_reg(0x63, 0x00); -    dev->reg.init_reg(0x64, 0x21); -    dev->reg.init_reg(0x65, 0x40); -    dev->reg.init_reg(0x67, 0x80); -    dev->reg.init_reg(0x68, 0x80); -    dev->reg.init_reg(0x69, 0x20); -    dev->reg.init_reg(0x6a, 0x20); - -    // CK1MAP + +    dev->reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM +    dev->reg.init_reg(0x5f, 0x40); // FMOVDEC: set during motor setup + +    dev->reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup +    dev->reg.init_reg(0x61, 0x21); // Z1MOD: overwritten during motor setup +    dev->reg.init_reg(0x62, 0x40); // Z1MOD: overwritten during motor setup +    dev->reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup +    dev->reg.init_reg(0x64, 0x21); // Z2MOD: overwritten during motor setup +    dev->reg.init_reg(0x65, 0x40); // Z2MOD: overwritten during motor setup +    dev->reg.init_reg(0x67, 0x80); // STEPSEL, MTRPWM: overwritten during motor setup +    dev->reg.init_reg(0x68, 0x80); // FSTPSEL, FASTPWM: overwritten during motor setup +    dev->reg.init_reg(0x69, 0x20); // FSHDEC: overwritten during motor setup +    dev->reg.init_reg(0x6a, 0x20); // FMOVNO: overwritten during motor setup +      dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x76, 0x3c); // SENSOR_DEF - -    // CK3MAP      dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x79, 0x9f); // SENSOR_DEF - -    // CK4MAP      dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x7b, 0x00); // SENSOR_DEF      dev->reg.init_reg(0x7c, 0x55); // SENSOR_DEF @@ -208,11 +205,23 @@ gl847_init_registers (Genesys_Device * dev)      dev->reg.init_reg(0x7d, 0x00);      // NOTE: autoconf is a non working option -    dev->reg.init_reg(0x87, 0x02); -    dev->reg.init_reg(0x9d, 0x06); -    dev->reg.init_reg(0xa2, 0x0f); -    dev->reg.init_reg(0xbd, 0x18); -    dev->reg.init_reg(0xfe, 0x08); +    dev->reg.init_reg(0x87, 0x02); // TODO: move to SENSOR_DEF +    dev->reg.init_reg(0x9d, 0x06); // RAMDLY, MOTLAG, CMODE, STEPTIM, IFRS +    dev->reg.init_reg(0xa2, 0x0f); // misc + +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0xab, 0x31); +        dev->reg.init_reg(0xbb, 0x00); +        dev->reg.init_reg(0xbc, 0x0f); +    } +    dev->reg.init_reg(0xbd, 0x18); // misc +    dev->reg.init_reg(0xfe, 0x08); // misc +    if (dev->model->model_id == ModelId::CANON_5600F) { +        dev->reg.init_reg(0x9e, 0x00); // sensor reg, but not in SENSOR_DEF +        dev->reg.init_reg(0x9f, 0x00); // sensor reg, but not in SENSOR_DEF +        dev->reg.init_reg(0xaa, 0x00); // custom data +        dev->reg.init_reg(0xff, 0x00); +    }      // gamma[0] and gamma[256] values      dev->reg.init_reg(0xbe, 0x00); @@ -237,233 +246,180 @@ gl847_init_registers (Genesys_Device * dev)      }      const auto& sensor = sanei_genesys_find_sensor_any(dev); -    sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); +    const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution, +                                                         3, ScanMethod::FLATBED); +    sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw); -  /* initalize calibration reg */ -  dev->calib_reg = dev->reg; +    if (dev->model->model_id == ModelId::CANON_5600F) { +        scanner_setup_sensor(*dev, sensor, dev->reg); +    }  } -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elements in the slope table - */ -static void gl847_send_slope_table(Genesys_Device* dev, int table_nr, -                                   const std::vector<uint16_t>& slope_table, -                                   int steps) +// Set values of analog frontend +void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const  { -    DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); -  int i; -  char msg[10000]; - -  /* sanity check */ -  if(table_nr<0 || table_nr>4) -    { -        throw SaneException("invalid table number %d", table_nr); -    } - -  std::vector<uint8_t> table(steps * 2); -  for (i = 0; i < steps; i++) -    { -      table[i * 2] = slope_table[i] & 0xff; -      table[i * 2 + 1] = slope_table[i] >> 8; -    } +    DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : +                               set == AFE_SET ? "set" : +                               set == AFE_POWER_SAVE ? "powersave" : "huh?"); -  if (DBG_LEVEL >= DBG_io) -    { -        std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); -      for (i = 0; i < steps; i++) -	{ -            std::sprintf(msg + std::strlen(msg), "%d", slope_table[i]); -	} -      DBG (DBG_io, "%s: %s\n", __func__, msg); -    } +    (void) sensor; -    if (dev->interface->is_mock()) { -        dev->interface->record_slope_table(table_nr, slope_table); +    if (dev->model->model_id != ModelId::CANON_5600F) { +        // FIXME: remove the following read +        dev->interface->read_register(REG_0x04);      } -    // slope table addresses are fixed -    dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); -} - -/** - * Set register values of Analog Device type frontend - * */ -static void gl847_set_ad_fe(Genesys_Device* dev, uint8_t set) -{ -    DBG_HELPER(dbg); -  int i;      // wait for FE to be ready      auto status = scanner_read_status(*dev);      while (status.is_front_end_busy) {          dev->interface->sleep_ms(10);          status = scanner_read_status(*dev); -    }; - -  if (set == AFE_INIT) -    { -        DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, -            static_cast<unsigned>(dev->model->adc_id)); - -      dev->frontend = dev->frontend_initial;      } -    // reset DAC -    dev->interface->write_fe_register(0x00, 0x80); - -    // write them to analog frontend -    dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); - -    dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); +    if (set == AFE_INIT) { +        dev->frontend = dev->frontend_initial; +    } -    for (i = 0; i < 3; i++) { -        dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i)); +    if (dev->model->model_id != ModelId::CANON_5600F) { +        // reset DAC (BUG: this does completely different thing on Analog Devices ADCs) +        dev->interface->write_fe_register(0x00, 0x80); +    } else { +        if (dev->frontend.layout.type == FrontendType::WOLFSON) { +            // reset DAC +            dev->interface->write_fe_register(0x04, 0xff); +        }      } -    for (i = 0; i < 3; i++) { -        dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i)); + +    for (const auto& reg : dev->frontend.regs) { +        dev->interface->write_fe_register(reg.address, reg.value);      }  } -// Set values of analog frontend -void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +static void gl847_write_motor_phase_table(Genesys_Device& dev, unsigned ydpi)  { -    DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : -                               set == AFE_SET ? "set" : -                               set == AFE_POWER_SAVE ? "powersave" : "huh?"); - -    (void) sensor; - -    uint8_t val = dev->interface->read_register(REG_0x04); -    uint8_t frontend_type = val & REG_0x04_FESET; - -    // route to AD devices -    if (frontend_type == 0x02) { -        gl847_set_ad_fe(dev, set); -        return; +    (void) ydpi; +    if (dev.model->model_id == ModelId::CANON_5600F) { +        std::vector<std::uint8_t> phase_table = { +            0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, +            0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, +            0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, +            0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, +            0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, +            0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, +            0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, +            0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, +            0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, +            0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, +            0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, +            0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, +            0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, +            0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, +            0x25, 0x00, 0x25, 0x00, 0x25, 0x00, 0x25, 0x00, +            0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, +        }; +        dev.interface->write_ahb(0x01000a00, phase_table.size(), phase_table.data());      } - -    throw SaneException("unsupported frontend type %d", frontend_type);  } -  // @brief set up motor related register for scan  static void gl847_init_motor_regs_scan(Genesys_Device* dev,                                         const Genesys_Sensor& sensor,                                         Genesys_Register_Set* reg, -                                       const Motor_Profile& motor_profile, +                                       const MotorProfile& motor_profile,                                         unsigned int scan_exposure_time,                                         unsigned scan_yres,                                         unsigned int scan_lines,                                         unsigned int scan_dummy,                                         unsigned int feed_steps, -                                       MotorFlag flags) +                                       ScanFlag flags)  {      DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, can_yres=%d, step_type=%d, scan_lines=%d, "                           "scan_dummy=%d, feed_steps=%d, flags=%x",                      scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),                      scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags)); -  int use_fast_fed; -  unsigned int fast_dpi; -  unsigned int feedl, dist; -  GenesysRegister *r; -  uint32_t z1, z2; -  unsigned int min_restep = 0x20; -    uint8_t val; -  unsigned int ccdlmt,tgtime;      unsigned step_multiplier = gl847_get_step_multiplier (reg); -  use_fast_fed=0; -  /* no fast fed since feed works well */ -    if (dev->settings.yres==4444 && feed_steps > 100 && (!has_flag(flags, MotorFlag::FEED))) -    { -      use_fast_fed=1; +    bool use_fast_fed = false; +    if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) { +        use_fast_fed = true; +    } +    if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) { +        use_fast_fed = false;      } -  DBG(DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed);      reg->set24(REG_LINCNT, scan_lines); -  DBG(DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); -  /* compute register 02 value */ -    r = sanei_genesys_get_address(reg, REG_0x02); -  r->value = 0x00; -  sanei_genesys_set_motor_power(*reg, true); +    reg->set8(REG_0x02, 0); +    sanei_genesys_set_motor_power(*reg, true); +    std::uint8_t reg02 = reg->get8(REG_0x02);      if (use_fast_fed) { -        r->value |= REG_0x02_FASTFED; +        reg02 |= REG_0x02_FASTFED;      } else { -        r->value &= ~REG_0x02_FASTFED; +        reg02 &= ~REG_0x02_FASTFED;      } -    if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { -        r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; +    if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) { +        reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;      } -  if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) -      ||(scan_yres>=sensor.optical_res)) -    { -        r->value |= REG_0x02_ACDCDIS; +    if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || (scan_yres >= sensor.full_resolution)) { +        reg02 |= REG_0x02_ACDCDIS;      } - -    if (has_flag(flags, MotorFlag::REVERSE)) { -        r->value |= REG_0x02_MTRREV; +    if (has_flag(flags, ScanFlag::REVERSE)) { +        reg02 |= REG_0x02_MTRREV;      } else { -        r->value &= ~REG_0x02_MTRREV; +        reg02 &= ~REG_0x02_MTRREV;      } +    reg->set8(REG_0x02, reg02); -  /* scan and backtracking slope table */ -    auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, -                                                scan_exposure_time, dev->motor.base_ydpi, -                                                step_multiplier, motor_profile); -    gl847_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); -    gl847_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); +    // scan and backtracking slope table +    auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, +                                         scan_exposure_time, step_multiplier, motor_profile); +    scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table); +    scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table); -  /* fast table */ -  fast_dpi=sanei_genesys_get_lowest_ydpi(dev); +    // fast table +    unsigned fast_dpi = sanei_genesys_get_lowest_ydpi(dev); + +    // BUG: looks like for fast moves we use inconsistent step type      StepType fast_step_type = motor_profile.step_type;      if (static_cast<unsigned>(motor_profile.step_type) >= static_cast<unsigned>(StepType::QUARTER)) {          fast_step_type = StepType::QUARTER;      } -    Motor_Profile fast_motor_profile = motor_profile; +    MotorProfile fast_motor_profile = motor_profile;      fast_motor_profile.step_type = fast_step_type; -    auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi, -                                                scan_exposure_time, dev->motor.base_ydpi, -                                                step_multiplier, fast_motor_profile); +    auto fast_table = create_slope_table(dev->model->asic_type, dev->motor, fast_dpi, +                                         scan_exposure_time, step_multiplier, fast_motor_profile); + +    scanner_send_slope_table(dev, sensor, STOP_TABLE, fast_table.table); +    scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table); +    scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table); -    gl847_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); -    gl847_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); -    gl847_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); +    gl847_write_motor_phase_table(*dev, scan_yres); -  /* correct move distance by acceleration and deceleration amounts */ -  feedl=feed_steps; -  if (use_fast_fed) +    // correct move distance by acceleration and deceleration amounts +    unsigned feedl = feed_steps; +    unsigned dist = 0; +    if (use_fast_fed)      {          feedl <<= static_cast<unsigned>(fast_step_type); -        dist = (scan_table.steps_count + 2 * fast_table.steps_count); -        /* TODO read and decode REG_0xAB */ -        r = sanei_genesys_get_address (reg, 0x5e); -        dist += (r->value & 31); -        /* FEDCNT */ -        r = sanei_genesys_get_address (reg, REG_FEDCNT); -        dist += r->value; -    } -  else -    { +        dist = (scan_table.table.size() + 2 * fast_table.table.size()); +        // TODO read and decode REG_0xAB +        dist += (reg->get8(0x5e) & 31); +        dist += reg->get8(REG_FEDCNT); +    } else {          feedl <<= static_cast<unsigned>(motor_profile.step_type); -        dist = scan_table.steps_count; -        if (has_flag(flags, MotorFlag::FEED)) { +        dist = scan_table.table.size(); +        if (has_flag(flags, ScanFlag::FEEDING)) {              dist *= 2;          }      } -  DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); -  /* check for overflow */ +    // check for overflow      if (dist < feedl) {          feedl -= dist;      } else { @@ -471,25 +427,20 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,      }      reg->set24(REG_FEEDL, feedl); -  DBG(DBG_io ,"%s: feedl=%d\n", __func__, feedl); -    r = sanei_genesys_get_address(reg, REG_0x0C); -    ccdlmt = (r->value & REG_0x0C_CCDLMT) + 1; - -    r = sanei_genesys_get_address(reg, REG_0x1C); -    tgtime = 1<<(r->value & REG_0x1C_TGTIME); +    unsigned ccdlmt = (reg->get8(REG_0x0C) & REG_0x0C_CCDLMT) + 1; +    unsigned tgtime = 1 << (reg->get8(REG_0x1C) & REG_0x1C_TGTIME);      // hi res motor speed GPIO      uint8_t effective = dev->interface->read_register(REG_0x6C);      // if quarter step, bipolar Vref2 +    std::uint8_t val = effective;      if (motor_profile.step_type == StepType::QUARTER) {          val = effective & ~REG_0x6C_GPIO13;      } else if (static_cast<unsigned>(motor_profile.step_type) > static_cast<unsigned>(StepType::QUARTER)) {          val = effective | REG_0x6C_GPIO13; -    } else { -        val = effective;      }      dev->interface->write_register(REG_0x6C, val); @@ -498,45 +449,37 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,      val = effective | REG_0x6C_GPIO10;      dev->interface->write_register(REG_0x6C, val); -    min_restep = scan_table.steps_count / (2 * step_multiplier) - 1; +    unsigned min_restep = scan_table.table.size() / (2 * step_multiplier) - 1;      if (min_restep < 1) {          min_restep = 1;      } -    r = sanei_genesys_get_address(reg, REG_FWDSTEP); -  r->value = min_restep; -    r = sanei_genesys_get_address(reg, REG_BWDSTEP); -  r->value = min_restep; +    reg->set8(REG_FWDSTEP, min_restep); +    reg->set8(REG_BWDSTEP, min_restep); + +    std::uint32_t z1, z2;      sanei_genesys_calculate_zmod(use_fast_fed, -			         scan_exposure_time*ccdlmt*tgtime, +                                 scan_exposure_time * ccdlmt * tgtime,                                   scan_table.table, -                                 scan_table.steps_count, -				 feedl, +                                 scan_table.table.size(), +                                 feedl,                                   min_restep * step_multiplier,                                   &z1,                                   &z2); -  DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);      reg->set24(REG_0x60, z1 | (static_cast<unsigned>(motor_profile.step_type) << (16+REG_0x60S_STEPSEL))); - -  DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);      reg->set24(REG_0x63, z2 | (static_cast<unsigned>(motor_profile.step_type) << (16+REG_0x63S_FSTPSEL))); -  r = sanei_genesys_get_address (reg, 0x1e); -  r->value &= 0xf0;		/* 0 dummy lines */ -  r->value |= scan_dummy;	/* dummy lines */ +    reg->set8_mask(REG_0x1E, scan_dummy, 0x0f); -    r = sanei_genesys_get_address(reg, REG_0x67); -    r->value = REG_0x67_MTRPWM; +    reg->set8(REG_0x67, REG_0x67_MTRPWM); +    reg->set8(REG_0x68, REG_0x68_FASTPWM); -    r = sanei_genesys_get_address(reg, REG_0x68); -    r->value = REG_0x68_FASTPWM; - -    reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); -    reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); -    reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier); -    reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); -    reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); +    reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier); +    reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier); +    reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier); +    reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier); +    reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);  } @@ -563,84 +506,84 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens                                           const ScanSession& session)  {      DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); -    unsigned dpihw; -  GenesysRegister *r; - -    // resolution is divided according to ccd_pixels_per_system_pixel() -    unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); -    DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); - -    // to manage high resolution device while keeping good low resolution scanning speed, we make -    // hardware dpi vary -    dpihw = sensor.get_register_hwdpi(session.params.xres * ccd_pixels_per_system_pixel); -  DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); -    gl847_setup_sensor(dev, sensor, reg); +    scanner_setup_sensor(*dev, sensor, *reg);      dev->cmd_set->set_fe(dev, sensor, AFE_SET);    /* enable shading */      regs_set_optical_off(dev->model->asic_type, *reg); -    r = sanei_genesys_get_address(reg, REG_0x01); -    r->value |= REG_0x01_SHDAREA; +    reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;      if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || -        (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) +        has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) || +        session.use_host_side_calib)      { -        r->value &= ~REG_0x01_DVDSET; -    } -  else -    { -        r->value |= REG_0x01_DVDSET; +        reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET; +    } else { +        reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;      } +    reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB; -  r = sanei_genesys_get_address (reg, REG_0x03); -  r->value &= ~REG_0x03_AVEENB; - +    reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL; +    if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { +        reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL; +    }      sanei_genesys_set_lamp_power(dev, sensor, *reg,                                   !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); +    reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA); + +    if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { +        if (dev->model->model_id == ModelId::CANON_5600F) { +            regs_set_exposure(dev->model->asic_type, *reg, sanei_genesys_fixup_exposure({0, 0, 0})); +        } +    } -  /* BW threshold */ -    r = sanei_genesys_get_address (reg, 0x2e); -  r->value = dev->settings.threshold; -    r = sanei_genesys_get_address (reg, 0x2f); -  r->value = dev->settings.threshold; +    // BW threshold +    reg->set8(0x2e, 0x7f); +    reg->set8(0x2f, 0x7f);    /* monochrome / color scan */ -    r = sanei_genesys_get_address (reg, REG_0x04);      switch (session.params.depth) {      case 8: -            r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); +            reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);        break;      case 16: -            r->value &= ~REG_0x04_LINEART; -            r->value |= REG_0x04_BITSET; +            reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART; +            reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;        break;      } -    r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); +    reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);    if (session.params.channels == 1)      {        switch (session.params.color_filter)  	{             case ColorFilter::RED: -               r->value |= 0x14; +               reg->find_reg(REG_0x04).value |= 0x14;                 break;             case ColorFilter::BLUE: -               r->value |= 0x1c; +               reg->find_reg(REG_0x04).value |= 0x1c;                 break;             case ColorFilter::GREEN: -               r->value |= 0x18; +               reg->find_reg(REG_0x04).value |= 0x18;                 break;             default:                 break; // should not happen  	}      } else { -        r->value |= 0x10; // mono +        if (dev->model->model_id == ModelId::CANON_5600F) { +            reg->find_reg(REG_0x04).value |= 0x20; +        } else { +            reg->find_reg(REG_0x04).value |= 0x10; // mono +        }      } -    sanei_genesys_set_dpihw(*reg, sensor, dpihw); +    const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution, +                                                         session.params.channels, +                                                         session.params.scan_method); +    sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);      if (should_enable_gamma(session, sensor)) {          reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; @@ -651,38 +594,30 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens    /* CIS scanners can do true gray by setting LEDADD */    /* we set up LEDADD only when asked */      if (dev->model->is_cis) { -        r = sanei_genesys_get_address (reg, 0x87); -        r->value &= ~REG_0x87_LEDADD; +        reg->find_reg(0x87).value &= ~REG_0x87_LEDADD; +          if (session.enable_ledadd) { -            r->value |= REG_0x87_LEDADD; +            reg->find_reg(0x87).value |= REG_0x87_LEDADD;          }        /* RGB weighting -        r = sanei_genesys_get_address (reg, 0x01); -        r->value &= ~REG_0x01_TRUEGRAY; +        reg->find_reg(0x01).value &= ~REG_0x01_TRUEGRAY;          if (session.enable_ledadd) { -            r->value |= REG_0x01_TRUEGRAY; +            reg->find_reg(0x01).value |= REG_0x01_TRUEGRAY;          }          */      } -    unsigned dpiset = session.params.xres * ccd_pixels_per_system_pixel; -    reg->set16(REG_DPISET, dpiset); -    DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - +    reg->set16(REG_DPISET, sensor.register_dpiset);      reg->set16(REG_STRPIXEL, session.pixel_startx);      reg->set16(REG_ENDPIXEL, session.pixel_endx); -    build_image_pipeline(dev, session); +    setup_image_pipeline(*dev, session);    /* MAXWD is expressed in 4 words unit */      // BUG: we shouldn't multiply by channels here      reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2)); -      reg->set16(REG_LPERIOD, exposure_time); -  DBG(DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - -  r = sanei_genesys_get_address (reg, 0x34); -  r->value = sensor.dummy_pixel; +    reg->set8(0x34, sensor.dummy_pixel);  }  void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, @@ -692,13 +627,18 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene      DBG_HELPER(dbg);      session.assert_computed(); -  int move;    int exposure_time;    int slope_dpi = 0;    int dummy = 0; -    dummy = 3 - session.params.channels; +    if (dev->model->model_id == ModelId::CANON_LIDE_100 || +        dev->model->model_id == ModelId::CANON_LIDE_200 || +        dev->model->model_id == ModelId::CANON_LIDE_700F || +        dev->model->model_id == ModelId::HP_SCANJET_N6310) +    { +        dummy = 3 - session.params.channels; +    }  /* slope_dpi */  /* cis color scan is effectively a gray scan with 3 gray lines per color @@ -712,40 +652,15 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene    slope_dpi = slope_dpi * (1 + dummy);      exposure_time = sensor.exposure_lperiod; -    const auto& motor_profile = sanei_genesys_get_motor_profile(*gl847_motor_profiles, -                                                                dev->model->motor_id, -                                                                exposure_time); - -  DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); -    DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, -        static_cast<unsigned>(motor_profile.step_type)); +    const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);    /* we enable true gray for cis scanners only, and just when doing     * scan since color calibration is OK for this mode     */      gl847_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); - -    move = session.params.starty; -    DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - -    MotorFlag mflags = MotorFlag::NONE; -    if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { -        mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; -    } -    if (has_flag(session.params.flags, ScanFlag::FEEDING)) { -        mflags |= MotorFlag::FEED; -  } -    if (has_flag(session.params.flags, ScanFlag::REVERSE)) { -        mflags |= MotorFlag::REVERSE; -    } -      gl847_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi, -                               dev->model->is_cis ? session.output_line_count * session.params.channels -                                                  : session.output_line_count, -                               dummy, move, mflags); - -    dev->read_buffer.clear(); -    dev->read_buffer.alloc(session.buffer_size_read); +                               session.optical_line_count, dummy, session.params.starty, +                               session.params.flags);      dev->read_active = true; @@ -761,21 +676,59 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,                                                      const Genesys_Sensor& sensor,                                                      const Genesys_Settings& settings) const  { -  int start; -      DBG(DBG_info, "%s ", __func__);      debug_dump(DBG_info, settings); -  /* start */ -    start = static_cast<int>(dev->model->x_offset); -    start = static_cast<int>(start + settings.tl_x); -    start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH); +    // backtracking isn't handled well, so don't enable it +    ScanFlag flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE; + +    /*  Steps to move to reach scanning area: + +        - first we move to physical start of scanning either by a fixed steps amount from the +          black strip or by a fixed amount from parking position, minus the steps done during +          shading calibration. + +        - then we move by the needed offset whitin physical scanning area +    */ +    unsigned move_dpi = dev->motor.base_ydpi; + +    float move = dev->model->y_offset; +    if (settings.scan_method == ScanMethod::TRANSPARENCY || +        settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) +    { +        // note: scanner_move_to_ta() function has already been called and the sensor is at the +        // transparency adapter +        if (!dev->ignore_offsets) { +            move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta; +        } +        flags |= ScanFlag::USE_XPA; +    } else { +        if (!dev->ignore_offsets) { +            move = dev->model->y_offset; +        } +    } + +    move = move + settings.tl_y; +    move = static_cast<float>((move * move_dpi) / MM_PER_INCH); +    move -= dev->head_pos(ScanHeadId::PRIMARY); + +    float start = dev->model->x_offset; +    if (settings.scan_method == ScanMethod::TRANSPARENCY || +        settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) +    { +        start = dev->model->x_offset_ta; +    } else { +        start = dev->model->x_offset; +    } + +    start = start + dev->settings.tl_x; +    start = static_cast<float>((start * settings.xres) / MM_PER_INCH);      ScanSession session;      session.params.xres = settings.xres;      session.params.yres = settings.yres; -    session.params.startx = start; // not used -    session.params.starty = 0; // not used +    session.params.startx = static_cast<unsigned>(start); +    session.params.starty = static_cast<unsigned>(move);      session.params.pixels = settings.pixels;      session.params.requested_pixels = settings.requested_pixels;      session.params.lines = settings.lines; @@ -784,7 +737,7 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,      session.params.scan_method = settings.scan_method;      session.params.scan_mode = settings.scan_mode;      session.params.color_filter = settings.color_filter; -    session.params.flags = ScanFlag::NONE; +    session.params.flags = flags;      compute_session(dev, session, sensor); @@ -811,25 +764,61 @@ void CommandSetGl847::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens      DBG_HELPER(dbg);      (void) sensor;    uint8_t val; -  GenesysRegister *r; -    // clear GPIO 10 -    if (dev->model->gpio_id != GpioId::CANON_LIDE_700F) { +    if (reg->state.is_xpa_on && reg->state.is_lamp_on) { +        dev->cmd_set->set_xpa_lamp_power(*dev, true); +    } + +    if (dev->model->model_id == ModelId::HP_SCANJET_N6310 || +        dev->model->model_id == ModelId::CANON_LIDE_100 || +        dev->model->model_id == ModelId::CANON_LIDE_200) +    {          val = dev->interface->read_register(REG_0x6C);          val &= ~REG_0x6C_GPIO10;          dev->interface->write_register(REG_0x6C, val);      } -    val = REG_0x0D_CLRLNCNT; -    dev->interface->write_register(REG_0x0D, val); -    val = REG_0x0D_CLRMCNT; -    dev->interface->write_register(REG_0x0D, val); +    if (dev->model->model_id == ModelId::CANON_5600F) { +        switch (dev->session.params.xres) { +            case 75: +            case 150: +            case 300: +                scanner_register_rw_bits(*dev, REG_0xA6, 0x04, 0x1c); +                break; +            case 600: +                scanner_register_rw_bits(*dev, REG_0xA6, 0x18, 0x1c); +                break; +            case 1200: +                scanner_register_rw_bits(*dev, REG_0xA6, 0x08, 0x1c); +                break; +            case 2400: +                scanner_register_rw_bits(*dev, REG_0xA6, 0x10, 0x1c); +                break; +            case 4800: +                scanner_register_rw_bits(*dev, REG_0xA6, 0x00, 0x1c); +                break; +            default: +                throw SaneException("Unexpected xres"); +        } +        dev->interface->write_register(0x6c, 0xf0); +        dev->interface->write_register(0x6b, 0x87); +        dev->interface->write_register(0x6d, 0x5f); +    } + +    if (dev->model->model_id == ModelId::CANON_5600F) { +        scanner_clear_scan_and_feed_counts(*dev); +    } else { +        // FIXME: use scanner_clear_scan_and_feed_counts() +        val = REG_0x0D_CLRLNCNT; +        dev->interface->write_register(REG_0x0D, val); +        val = REG_0x0D_CLRMCNT; +        dev->interface->write_register(REG_0x0D, val); +    }      val = dev->interface->read_register(REG_0x01);      val |= REG_0x01_SCAN;      dev->interface->write_register(REG_0x01, val); -    r = sanei_genesys_get_address (reg, REG_0x01); -  r->value = val; +    reg->set8(REG_0x01, val);      scanner_start_action(*dev, start_motor); @@ -844,268 +833,86 @@ void CommandSetGl847::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,      (void) reg;      DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); +    if (reg->state.is_xpa_on) { +        dev->cmd_set->set_xpa_lamp_power(*dev, false); +    } +      if (!dev->model->is_sheetfed) {          scanner_stop_action(*dev);      }  } -/** Park head - * Moves the slider to the home (top) position slowly - * @param dev device to park - * @param wait_until_home true to make the function waiting for head - * to be home before returning, if fals returne immediately -*/  void CommandSetGl847::move_back_home(Genesys_Device* dev, bool wait_until_home) const  {      scanner_move_back_home(*dev, wait_until_home);  } -// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi -// from very top of scanner -void CommandSetGl847::search_start_position(Genesys_Device* dev) const -{ -    DBG_HELPER(dbg); -  int size; -  Genesys_Register_Set local_reg; - -  int pixels = 600; -  int dpi = 300; - -  local_reg = dev->reg; - -  /* sets for a 200 lines * 600 pixels */ -  /* normal scan with no shading */ - -    // FIXME: the current approach of doing search only for one resolution does not work on scanners -    // whith employ different sensors with potentially different settings. -    const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); - -    ScanSession session; -    session.params.xres = dpi; -    session.params.yres = dpi; -    session.params.startx =  0; -    session.params.starty =  0; /*we should give a small offset here~60 steps */ -    session.params.pixels = 600; -    session.params.lines = dev->model->search_lines; -    session.params.depth = 8; -    session.params.channels =  1; -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = ScanColorMode::GRAY; -    session.params.color_filter = ColorFilter::GREEN; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::IGNORE_LINE_DISTANCE; -    compute_session(dev, session, sensor); - -    init_regs_for_scan_session(dev, sensor, &local_reg, session); - -    // send to scanner -    dev->interface->write_registers(local_reg); - -  size = pixels * dev->model->search_lines; - -  std::vector<uint8_t> data(size); - -    begin_scan(dev, sensor, &local_reg, true); - -    if (is_testing_mode()) { -        dev->interface->test_checkpoint("search_start_position"); -        end_scan(dev, &local_reg, true); -        dev->reg = local_reg; -        return; -    } - -    wait_until_buffer_non_empty(dev); - -    // now we're on target, we can read data -    sanei_genesys_read_data_from_scanner(dev, data.data(), size); - -    if (DBG_LEVEL >= DBG_data) { -        sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels, -                                     dev->model->search_lines); -    } - -    end_scan(dev, &local_reg, true); - -  /* update regs to copy ASIC internal state */ -  dev->reg = local_reg; - -    // TODO: find out where sanei_genesys_search_reference_point stores information, -    // and use that correctly -    for (auto& sensor_update : -            sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) -    { -        sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, -                                             dev->model->search_lines); -    } -} - -// sets up register for coarse gain calibration -// todo: check it for scanners using it -void CommandSetGl847::init_regs_for_coarse_calibration(Genesys_Device* dev, -                                                       const Genesys_Sensor& sensor, -                                                       Genesys_Register_Set& regs) const -{ -    DBG_HELPER(dbg); - -    ScanSession session; -    session.params.xres = dev->settings.xres; -    session.params.yres = dev->settings.yres; -    session.params.startx = 0; -    session.params.starty = 0; -    session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); -    session.params.lines = 20; -    session.params.depth = 16; -    session.params.channels = dev->settings.get_channels(); -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = dev->settings.scan_mode; -    session.params.color_filter = dev->settings.color_filter; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::SINGLE_LINE | -                           ScanFlag::IGNORE_LINE_DISTANCE; -    compute_session(dev, session, sensor); - -    init_regs_for_scan_session(dev, sensor, ®s, session); - -  DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, -      sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); - -    dev->interface->write_registers(regs); -} -  // init registers for shading calibration  void CommandSetGl847::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,                                              Genesys_Register_Set& regs) const  {      DBG_HELPER(dbg); -  dev->calib_channels = 3; +    unsigned move_dpi = dev->motor.base_ydpi; -  /* initial calibration reg values */ -  regs = dev->reg; +    float calib_size_mm = 0; +    if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || +        dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) +    { +        calib_size_mm = dev->model->y_size_calib_ta_mm; +    } else { +        calib_size_mm = dev->model->y_size_calib_mm; +    } -    dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres); +    unsigned channels = 3; +    unsigned resolution = sensor.shading_resolution; -    const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution, -                                                         dev->calib_channels, +    const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,                                                           dev->settings.scan_method); -  dev->calib_total_bytes_to_read = 0; -  dev->calib_lines = dev->model->shading_lines; -    if (dev->calib_resolution == 4800) { -        dev->calib_lines *= 2; +    float move = 0; +    ScanFlag flags = ScanFlag::DISABLE_SHADING | +                     ScanFlag::DISABLE_GAMMA | +                     ScanFlag::DISABLE_BUFFER_FULL_MOVE; + +    if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || +        dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) +    { +        // note: scanner_move_to_ta() function has already been called and the sensor is at the +        // transparency adapter +        move = dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta; +        flags |= ScanFlag::USE_XPA; +    } else { +        move = dev->model->y_offset_calib_white;      } -    dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) / -                        calib_sensor.optical_res; -    DBG(DBG_io, "%s: calib_lines  = %zu\n", __func__, dev->calib_lines); -    DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels); +    move = static_cast<float>((move * move_dpi) / MM_PER_INCH); + +    unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);      ScanSession session; -    session.params.xres = dev->calib_resolution; -    session.params.yres = dev->motor.base_ydpi; +    session.params.xres = resolution; +    session.params.yres = resolution;      session.params.startx = 0; -    session.params.starty = 20; -    session.params.pixels = dev->calib_pixels; -    session.params.lines = dev->calib_lines; +    session.params.starty = static_cast<unsigned>(move); +    session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; +    session.params.lines = calib_lines;      session.params.depth = 16; -    session.params.channels = dev->calib_channels; +    session.params.channels = channels;      session.params.scan_method = dev->settings.scan_method;      session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;      session.params.color_filter = dev->settings.color_filter; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::DISABLE_BUFFER_FULL_MOVE | -                           ScanFlag::IGNORE_LINE_DISTANCE; +    session.params.flags = flags;      compute_session(dev, session, calib_sensor);      init_regs_for_scan_session(dev, calib_sensor, ®s, session); -    dev->interface->write_registers(regs); - -  /* we use GENESYS_FLAG_SHADING_REPARK */ +  /* we use ModelFlag::SHADING_REPARK */      dev->set_head_pos_zero(ScanHeadId::PRIMARY); -} - -/** @brief set up registers for the actual scan - */ -void CommandSetGl847::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const -{ -    DBG_HELPER(dbg); -  float move; -  int move_dpi; -  float start; -    debug_dump(DBG_info, dev->settings); - -  /* steps to move to reach scanning area: -     - first we move to physical start of scanning -     either by a fixed steps amount from the black strip -     or by a fixed amount from parking position, -     minus the steps done during shading calibration -     - then we move by the needed offset whitin physical -     scanning area - -     assumption: steps are expressed at maximum motor resolution - -     we need: -     float y_offset; -     float y_size; -     float y_offset_calib; -     mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - -  /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is -     relative from origin, else, it is from parking position */ - -  move_dpi = dev->motor.base_ydpi; - -    move = static_cast<float>(dev->model->y_offset); -    move = static_cast<float>(move + dev->settings.tl_y); -    move = static_cast<float>((move * move_dpi) / MM_PER_INCH); -    move -= dev->head_pos(ScanHeadId::PRIMARY); -  DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - -  /* fast move to scan area */ -  /* we don't move fast the whole distance since it would involve -   * computing acceleration/deceleration distance for scan -   * resolution. So leave a remainder for it so scan makes the final -   * move tuning */ -    if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) { -        scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500), -                     Direction::FORWARD); -      move=500; -    } - -  DBG(DBG_info, "%s: move=%f steps\n", __func__, move); -  DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - -  /* start */ -    start = static_cast<float>(dev->model->x_offset); -    start = static_cast<float>(start + dev->settings.tl_x); -    start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH); - -    ScanSession session; -    session.params.xres = dev->settings.xres; -    session.params.yres = dev->settings.yres; -    session.params.startx = static_cast<unsigned>(start); -    session.params.starty = static_cast<unsigned>(move); -    session.params.pixels = dev->settings.pixels; -    session.params.requested_pixels = dev->settings.requested_pixels; -    session.params.lines = dev->settings.lines; -    session.params.depth = dev->settings.depth; -    session.params.channels = dev->settings.get_channels(); -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = dev->settings.scan_mode; -    session.params.color_filter = dev->settings.color_filter; -    // backtracking isn't handled well, so don't enable it -    session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE; -    compute_session(dev, session, sensor); - -    init_regs_for_scan_session(dev, sensor, &dev->reg, session); +    dev->calib_session = session;  } -  /**   * Send shading calibration data. The buffer is considered to always hold values   * for all the channels. @@ -1114,39 +921,24 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso                                          uint8_t* data, int size) const  {      DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); -  uint32_t addr, length, i, x, factor, pixels; -    uint32_t dpiset, dpihw; +    std::uint32_t addr, i;    uint8_t val,*ptr,*src; -  /* shading data is plit in 3 (up to 5 with IR) areas -     write(0x10014000,0x00000dd8) -     URB 23429  bulk_out len  3544  wrote 0x33 0x10 0x.... -     write(0x1003e000,0x00000dd8) -     write(0x10068000,0x00000dd8) -   */ -    length = static_cast<std::uint32_t>(size / 3); -    std::uint32_t strpixel = dev->session.pixel_startx; -    std::uint32_t endpixel = dev->session.pixel_endx; +    unsigned length = static_cast<unsigned>(size / 3); -  /* compute deletion factor */ -    dpiset = dev->reg.get16(REG_DPISET); -    dpihw = sensor.get_register_hwdpi(dpiset); -  factor=dpihw/dpiset; -  DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); +    // we're using SHDAREA, thus we only need to upload part of the line +    unsigned offset = dev->session.pixel_count_ratio.apply( +                dev->session.params.startx * sensor.full_resolution / dev->session.params.xres); +    unsigned pixels = dev->session.pixel_count_ratio.apply(dev->session.optical_pixels_raw); -  pixels=endpixel-strpixel; +    // turn pixel value into bytes 2x16 bits words +    offset *= 2 * 2; +    pixels *= 2 * 2; -  /* since we're using SHDAREA, substract startx coordinate from shading */ -    strpixel -= (sensor.ccd_start_xoffset * 600) / sensor.optical_res; - -  /* turn pixel value into bytes 2x16 bits words */ -  strpixel*=2*2; -  pixels*=2*2; - -    dev->interface->record_key_value("shading_offset", std::to_string(strpixel)); +    dev->interface->record_key_value("shading_offset", std::to_string(offset));      dev->interface->record_key_value("shading_pixels", std::to_string(pixels));      dev->interface->record_key_value("shading_length", std::to_string(length)); -    dev->interface->record_key_value("shading_factor", std::to_string(factor)); +    dev->interface->record_key_value("shading_factor", std::to_string(sensor.shading_factor));    std::vector<uint8_t> buffer(pixels, 0); @@ -1155,6 +947,10 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso    /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address     * is 8192*reg value */ +    if (dev->model->model_id == ModelId::CANON_5600F) { +        return; +    } +    /* write actual color channel data */    for(i=0;i<3;i++)      { @@ -1162,11 +958,10 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso         * to the one corresponding to SHDAREA */        ptr = buffer.data(); -      /* iterate on both sensor segment */ -      for(x=0;x<pixels;x+=4*factor) -        { +        // iterate on both sensor segment +        for (unsigned x = 0; x < pixels; x += 4 * sensor.shading_factor) {            /* coefficient source */ -          src=(data+strpixel+i*length)+x; +            src = (data + offset + i * length) + x;            /* coefficient copy */            ptr[0]=src[0]; @@ -1192,160 +987,7 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso  SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,                                                  Genesys_Register_Set& regs) const  { -    DBG_HELPER(dbg); -  int num_pixels; -  int total_size; -  int used_res; -  int i, j; -  int val; -    int channels; -  int avg[3], top[3], bottom[3]; -  int turn; -  uint16_t exp[3]; -  float move; - -    move = static_cast<float>(dev->model->y_offset_calib_white); -    move = static_cast<float>((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH); -    if (move > 20) { -        scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move), -                     Direction::FORWARD); -    } -  DBG(DBG_io, "%s: move=%f steps\n", __func__, move); - -  /* offset calibration is always done in color mode */ -  channels = 3; -    used_res = sensor.get_register_hwdpi(dev->settings.xres); -    const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels, -                                                         dev->settings.scan_method); -    num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res; - -  /* initial calibration reg values */ -  regs = dev->reg; - -    ScanSession session; -    session.params.xres = used_res; -    session.params.yres = used_res; -    session.params.startx = 0; -    session.params.starty = 0; -    session.params.pixels = num_pixels; -    session.params.lines = 1; -    session.params.depth = 16; -    session.params.channels = channels; -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; -    session.params.color_filter = dev->settings.color_filter; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::SINGLE_LINE | -                           ScanFlag::IGNORE_LINE_DISTANCE; -    compute_session(dev, session, calib_sensor); - -    init_regs_for_scan_session(dev, calib_sensor, ®s, session); - -    total_size = num_pixels * channels * (session.params.depth/8) * 1; -  std::vector<uint8_t> line(total_size); - -    // initial loop values and boundaries -    exp[0] = calib_sensor.exposure.red; -    exp[1] = calib_sensor.exposure.green; -    exp[2] = calib_sensor.exposure.blue; - -    bottom[0] = 28000; -    bottom[1] = 28000; -    bottom[2] = 28000; - -    top[0] = 32000; -    top[1] = 32000; -    top[2] = 32000; - -  turn = 0; - -  /* no move during led calibration */ -    bool acceptable = false; -  sanei_genesys_set_motor_power(regs, false); -  do -    { -        // set up exposure -        regs.set16(REG_EXPR,exp[0]); -        regs.set16(REG_EXPG,exp[1]); -        regs.set16(REG_EXPB,exp[2]); - -        // write registers and scan data -        dev->interface->write_registers(regs); - -      DBG(DBG_info, "%s: starting line reading\n", __func__); -        begin_scan(dev, calib_sensor, ®s, true); - -        if (is_testing_mode()) { -            dev->interface->test_checkpoint("led_calibration"); -            scanner_stop_action(*dev); -            move_back_home(dev, true); -            return calib_sensor.exposure; -        } - -        sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - -        // stop scanning -        scanner_stop_action(*dev); - -      if (DBG_LEVEL >= DBG_data) -	{ -          char fn[30]; -            std::snprintf(fn, 30, "gl847_led_%02d.pnm", turn); -            sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, -                                         channels, num_pixels, 1); -	} - -      /* compute average */ -      for (j = 0; j < channels; j++) -	{ -	  avg[j] = 0; -	  for (i = 0; i < num_pixels; i++) -	    { -	      if (dev->model->is_cis) -		val = -		  line[i * 2 + j * 2 * num_pixels + 1] * 256 + -		  line[i * 2 + j * 2 * num_pixels]; -	      else -		val = -		  line[i * 2 * channels + 2 * j + 1] * 256 + -		  line[i * 2 * channels + 2 * j]; -	      avg[j] += val; -	    } - -	  avg[j] /= num_pixels; -	} - -      DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - -      /* check if exposure gives average within the boundaries */ -        acceptable = true; -      for(i=0;i<3;i++) -        { -            if (avg[i] < bottom[i] || avg[i] > top[i]) { -                auto target = (bottom[i] + top[i]) / 2; -                exp[i] = (exp[i] * target) / avg[i]; -                acceptable = false; -            } -        } - -      turn++; -    } -  while (!acceptable && turn < 100); - -  DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - -    // set these values as final ones for scan -    dev->reg.set16(REG_EXPR, exp[0]); -    dev->reg.set16(REG_EXPG, exp[1]); -    dev->reg.set16(REG_EXPB, exp[2]); - -    // go back home -    if (move>20) { -        move_back_home(dev, true); -    } - -    return { exp[0], exp[1], exp[2] }; +    return scanner_led_calibration(*dev, sensor, regs);  }  /** @@ -1354,31 +996,37 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes  static void gl847_init_gpio(Genesys_Device* dev)  {      DBG_HELPER(dbg); -  int idx=0; -  /* search GPIO profile */ -    while(gpios[idx].gpio_id != GpioId::UNKNOWN && dev->model->gpio_id != gpios[idx].gpio_id) { -      idx++; -    } -    if (gpios[idx].gpio_id == GpioId::UNKNOWN) { -        throw SaneException("failed to find GPIO profile for sensor_id=%d", -                            static_cast<unsigned>(dev->model->sensor_id)); -    } +    if (dev->model->model_id == ModelId::CANON_5600F) { +        apply_registers_ordered(dev->gpo.regs, {0xa6, 0xa7, 0x6f, 0x6e}, +                                [&](const GenesysRegisterSetting& reg) +        { +            dev->interface->write_register(reg.address, reg.value); +        }); +    } else { +        std::vector<std::uint16_t> order1 = { 0xa7, 0xa6, 0x6e }; +        std::vector<std::uint16_t> order2 = { 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0xa8, 0xa9 }; -    dev->interface->write_register(REG_0xA7, gpios[idx].ra7); -    dev->interface->write_register(REG_0xA6, gpios[idx].ra6); +        for (auto addr : order1) { +            dev->interface->write_register(addr, dev->gpo.regs.find_reg(addr).value); +        } -    dev->interface->write_register(REG_0x6E, gpios[idx].r6e); -    dev->interface->write_register(REG_0x6C, 0x00); +        dev->interface->write_register(REG_0x6C, 0x00); // FIXME: Likely not needed -    dev->interface->write_register(REG_0x6B, gpios[idx].r6b); -    dev->interface->write_register(REG_0x6C, gpios[idx].r6c); -    dev->interface->write_register(REG_0x6D, gpios[idx].r6d); -    dev->interface->write_register(REG_0x6E, gpios[idx].r6e); -    dev->interface->write_register(REG_0x6F, gpios[idx].r6f); +        for (auto addr : order2) { +            dev->interface->write_register(addr, dev->gpo.regs.find_reg(addr).value); +        } -    dev->interface->write_register(REG_0xA8, gpios[idx].ra8); -    dev->interface->write_register(REG_0xA9, gpios[idx].ra9); +        for (const auto& reg : dev->gpo.regs) { +            if (std::find(order1.begin(), order1.end(), reg.address) != order1.end()) { +                continue; +            } +            if (std::find(order2.begin(), order2.end(), reg.address) != order2.end()) { +                continue; +            } +            dev->interface->write_register(reg.address, reg.value); +        } +    }  }  /** @@ -1387,77 +1035,24 @@ static void gl847_init_gpio(Genesys_Device* dev)  static void gl847_init_memory_layout(Genesys_Device* dev)  {      DBG_HELPER(dbg); -  int idx = 0; -  uint8_t val; -  /* point to per model memory layout */ -  idx = 0; -    if (dev->model->model_id == ModelId::CANON_LIDE_100) { -      idx = 0; -    } -    if (dev->model->model_id == ModelId::CANON_LIDE_200) { -      idx = 1; -    } -    if (dev->model->model_id == ModelId::CANON_5600F) { -      idx = 2; -    } -    if (dev->model->model_id == ModelId::CANON_LIDE_700F) { -      idx = 3; +    // FIXME: move to initial register list +    switch (dev->model->model_id) { +        case ModelId::CANON_LIDE_100: +        case ModelId::CANON_LIDE_200: +            dev->interface->write_register(REG_0x0B, 0x29); +            break; +        case ModelId::CANON_LIDE_700F: +            dev->interface->write_register(REG_0x0B, 0x2a); +            break; +        default: +            break;      } -  /* CLKSET nd DRAMSEL */ -  val = layouts[idx].dramsel; -    dev->interface->write_register(REG_0x0B, val); -  dev->reg.find_reg(0x0b).value = val; - -  /* prevent further writings by bulk write register */ -  dev->reg.remove_reg(0x0b); - -  /* setup base address for shading data. */ -  /* values must be multiplied by 8192=0x4000 to give address on AHB */ -  /* R-Channel shading bank0 address setting for CIS */ -    dev->interface->write_register(0xd0, layouts[idx].rd0); -  /* G-Channel shading bank0 address setting for CIS */ -    dev->interface->write_register(0xd1, layouts[idx].rd1); -  /* B-Channel shading bank0 address setting for CIS */ -    dev->interface->write_register(0xd2, layouts[idx].rd2); - -  /* setup base address for scanned data. */ -  /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ -  /* R-Channel ODD image buffer 0x0124->0x92000 */ -  /* size for each buffer is 0x16d*1k word */ -    dev->interface->write_register(0xe0, layouts[idx].re0); -    dev->interface->write_register(0xe1, layouts[idx].re1); -  /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ -    dev->interface->write_register(0xe2, layouts[idx].re2); -    dev->interface->write_register(0xe3, layouts[idx].re3); - -  /* R-Channel EVEN image buffer 0x0292 */ -    dev->interface->write_register(0xe4, layouts[idx].re4); -    dev->interface->write_register(0xe5, layouts[idx].re5); -  /* R-Channel EVEN image buffer end-address 0x03ff*/ -    dev->interface->write_register(0xe6, layouts[idx].re6); -    dev->interface->write_register(0xe7, layouts[idx].re7); - -  /* same for green, since CIS, same addresses */ -    dev->interface->write_register(0xe8, layouts[idx].re0); -    dev->interface->write_register(0xe9, layouts[idx].re1); -    dev->interface->write_register(0xea, layouts[idx].re2); -    dev->interface->write_register(0xeb, layouts[idx].re3); -    dev->interface->write_register(0xec, layouts[idx].re4); -    dev->interface->write_register(0xed, layouts[idx].re5); -    dev->interface->write_register(0xee, layouts[idx].re6); -    dev->interface->write_register(0xef, layouts[idx].re7); - -/* same for blue, since CIS, same addresses */ -    dev->interface->write_register(0xf0, layouts[idx].re0); -    dev->interface->write_register(0xf1, layouts[idx].re1); -    dev->interface->write_register(0xf2, layouts[idx].re2); -    dev->interface->write_register(0xf3, layouts[idx].re3); -    dev->interface->write_register(0xf4, layouts[idx].re4); -    dev->interface->write_register(0xf5, layouts[idx].re5); -    dev->interface->write_register(0xf6, layouts[idx].re6); -    dev->interface->write_register(0xf7, layouts[idx].re7); +    // prevent further writings by bulk write register +    dev->reg.remove_reg(0x0b); + +    apply_reg_settings_to_device_write_only(*dev, dev->memory_layout.regs);  }  /* * @@ -1486,15 +1081,17 @@ void CommandSetGl847::asic_boot(Genesys_Device* dev, bool cold) const      // Write initial registers      dev->interface->write_registers(dev->reg); -  /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ -    val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; -    val = (val | REG_0x0B_ENBDRAM); -    dev->interface->write_register(REG_0x0B, val); -    dev->reg.find_reg(0x0b).value = val; +    if (dev->model->model_id != ModelId::CANON_5600F) { +        // Enable DRAM by setting a rising edge on bit 3 of reg 0x0b +        // The initial register write also powers on SDRAM +        val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; +        val = (val | REG_0x0B_ENBDRAM); +        dev->interface->write_register(REG_0x0B, val); +        dev->reg.find_reg(0x0b).value = val; -  /* CIS_LINE */ -    dev->reg.init_reg(0x08, REG_0x08_CIS_LINE); -    dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value); +        // TODO: remove this write +        dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value); +    }      // set up end access      dev->interface->write_0x8c(0x10, 0x0b); @@ -1506,8 +1103,11 @@ void CommandSetGl847::asic_boot(Genesys_Device* dev, bool cold) const      // setup internal memory layout      gl847_init_memory_layout (dev); -    dev->reg.init_reg(0xf8, 0x01); -    dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value); +    if (dev->model->model_id != ModelId::CANON_5600F) { +        // FIXME: move to memory layout +        dev->reg.init_reg(0xf8, 0x01); +        dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value); +    }  }  /** @@ -1519,7 +1119,7 @@ void CommandSetGl847::init(Genesys_Device* dev) const    DBG_INIT ();      DBG_HELPER(dbg); -    sanei_genesys_asic_init(dev, 0); +    sanei_genesys_asic_init(dev);  }  void CommandSetGl847::update_hardware_sensors(Genesys_Scanner* s) const @@ -1566,517 +1166,16 @@ void CommandSetGl847::update_home_sensor_gpio(Genesys_Device& dev) const      }  } -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward true if searching forward, false if searching backward - * @param black true if searching for a black strip, false for a white strip - */ -void CommandSetGl847::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, -                                   bool black) const -{ -    DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); -  unsigned int pixels, lines, channels; -  Genesys_Register_Set local_reg; -  size_t size; -  unsigned int pass, count, found, x, y; -  char title[80]; - -    set_fe(dev, sensor, AFE_SET); -    scanner_stop_action(*dev); - -    // set up for a gray scan at lowest dpi -    const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); -    unsigned dpi = resolution_settings.get_min_resolution_x(); -  channels = 1; -  /* 10 MM */ -  /* lines = (10 * dpi) / MM_PER_INCH; */ -  /* shading calibation is done with dev->motor.base_ydpi */ -  lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; -  pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; -    dev->set_head_pos_zero(ScanHeadId::PRIMARY); - -  local_reg = dev->reg; - -    ScanSession session; -    session.params.xres = dpi; -    session.params.yres = dpi; -    session.params.startx = 0; -    session.params.starty = 0; -    session.params.pixels = pixels; -    session.params.lines = lines; -    session.params.depth = 8; -    session.params.channels = channels; -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = ScanColorMode::GRAY; -    session.params.color_filter = ColorFilter::RED; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA; -    if (!forward) { -        session.params.flags |= ScanFlag::REVERSE; -    } -    compute_session(dev, session, sensor); - -    size = pixels * channels * lines * (session.params.depth / 8); -    std::vector<uint8_t> data(size); - -    init_regs_for_scan_session(dev, sensor, &local_reg, session); - -    dev->interface->write_registers(local_reg); - -    begin_scan(dev, sensor, &local_reg, true); - -    if (is_testing_mode()) { -        dev->interface->test_checkpoint("search_strip"); -        scanner_stop_action(*dev); -        return; -    } - -    wait_until_buffer_non_empty(dev); - -    // now we're on target, we can read data -    sanei_genesys_read_data_from_scanner(dev, data.data(), size); - -    scanner_stop_action(*dev); - -  pass = 0; -  if (DBG_LEVEL >= DBG_data) -    { -        std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", -                     black ? "black" : "white", forward ? "fwd" : "bwd", pass); -        sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, -                                     channels, pixels, lines); -    } - -  /* loop until strip is found or maximum pass number done */ -  found = 0; -  while (pass < 20 && !found) -    { -        dev->interface->write_registers(local_reg); - -        // now start scan -        begin_scan(dev, sensor, &local_reg, true); - -        wait_until_buffer_non_empty(dev); - -        // now we're on target, we can read data -        sanei_genesys_read_data_from_scanner(dev, data.data(), size); - -    scanner_stop_action(*dev); - -      if (DBG_LEVEL >= DBG_data) -	{ -            std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", -                         black ? "black" : "white", -                         forward ? "fwd" : "bwd", static_cast<int>(pass)); -            sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, -                                         channels, pixels, lines); -	} - -      /* search data to find black strip */ -      /* when searching forward, we only need one line of the searched color since we -       * will scan forward. But when doing backward search, we need all the area of the -       * same color */ -      if (forward) -	{ -	  for (y = 0; y < lines && !found; y++) -	    { -	      count = 0; -	      /* count of white/black pixels depending on the color searched */ -	      for (x = 0; x < pixels; x++) -		{ -		  /* when searching for black, detect white pixels */ -		  if (black && data[y * pixels + x] > 90) -		    { -		      count++; -		    } -		  /* when searching for white, detect black pixels */ -		  if (!black && data[y * pixels + x] < 60) -		    { -		      count++; -		    } -		} - -	      /* at end of line, if count >= 3%, line is not fully of the desired color -	       * so we must go to next line of the buffer */ -	      /* count*100/pixels < 3 */ -	      if ((count * 100) / pixels < 3) -		{ -		  found = 1; -		  DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, -		      pass, y); -		} -	      else -		{ -		  DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, -		      (100 * count) / pixels); -		} -	    } -	} -      else			/* since calibration scans are done forward, we need the whole area -				   to be of the required color when searching backward */ -	{ -	  count = 0; -	  for (y = 0; y < lines; y++) -	    { -	      /* count of white/black pixels depending on the color searched */ -	      for (x = 0; x < pixels; x++) -		{ -		  /* when searching for black, detect white pixels */ -		  if (black && data[y * pixels + x] > 90) -		    { -		      count++; -		    } -		  /* when searching for white, detect black pixels */ -		  if (!black && data[y * pixels + x] < 60) -		    { -		      count++; -		    } -		} -	    } - -	  /* at end of area, if count >= 3%, area is not fully of the desired color -	   * so we must go to next buffer */ -	  if ((count * 100) / (pixels * lines) < 3) -	    { -	      found = 1; -	      DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); -	    } -	  else -	    { -	      DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, -		  (100 * count) / pixels); -	    } -	} -      pass++; -    } - -  if (found) -    { -      DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); -    } -  else -    { -        throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); -    } -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, -	      unsigned int channels, unsigned int black) -{ -  unsigned int i, j, k, average, count; -  unsigned int avg[3]; -  uint8_t val; - -  /* computes average value on black margin */ -  for (k = 0; k < channels; k++) -    { -      avg[k] = 0; -      count = 0; -      for (i = 0; i < lines; i++) -	{ -	  for (j = 0; j < black; j++) -	    { -	      val = data[i * channels * pixels + j + k]; -	      avg[k] += val; -	      count++; -	    } -	} -      if (count) -	avg[k] /= count; -      DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); -    } -  average = 0; -  for (i = 0; i < channels; i++) -    average += avg[i]; -  average /= channels; -  DBG(DBG_info, "%s: average = %d\n", __func__, average); -  return average; -} -  void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,                                           Genesys_Register_Set& regs) const  { -    DBG_HELPER(dbg); -    unsigned channels; -  int pass = 0, avg, total_size; -    int topavg, bottomavg, lines; -  int top, bottom, black_pixels, pixels; - -    // no gain nor offset for AKM AFE -    uint8_t reg04 = dev->interface->read_register(REG_0x04); -    if ((reg04 & REG_0x04_FESET) == 0x02) { -      return; -    } - -  /* offset calibration is always done in color mode */ -  channels = 3; -  dev->calib_pixels = sensor.sensor_pixels; -  lines=1; -    pixels= (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res; -    black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res; -  DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - -    ScanSession session; -    session.params.xres = sensor.optical_res; -    session.params.yres = sensor.optical_res; -    session.params.startx = 0; -    session.params.starty = 0; -    session.params.pixels = pixels; -    session.params.lines = lines; -    session.params.depth = 8; -    session.params.channels = channels; -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; -    session.params.color_filter = dev->settings.color_filter; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::SINGLE_LINE | -                           ScanFlag::IGNORE_LINE_DISTANCE; -    compute_session(dev, session, sensor); - -    init_regs_for_scan_session(dev, sensor, ®s, session); - -  sanei_genesys_set_motor_power(regs, false); - -  /* allocate memory for scans */ -  total_size = pixels * channels * lines * (session.params.depth / 8);	/* colors * bytes_per_color * scan lines */ - -  std::vector<uint8_t> first_line(total_size); -  std::vector<uint8_t> second_line(total_size); - -  /* init gain */ -  dev->frontend.set_gain(0, 0); -  dev->frontend.set_gain(1, 0); -  dev->frontend.set_gain(2, 0); - -  /* scan with no move */ -  bottom = 10; -  dev->frontend.set_offset(0, bottom); -  dev->frontend.set_offset(1, bottom); -  dev->frontend.set_offset(2, bottom); - -    set_fe(dev, sensor, AFE_SET); -    dev->interface->write_registers(regs); -  DBG(DBG_info, "%s: starting first line reading\n", __func__); -    begin_scan(dev, sensor, ®s, true); - -    if (is_testing_mode()) { -        dev->interface->test_checkpoint("offset_calibration"); -        return; -    } - -    sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); -  if (DBG_LEVEL >= DBG_data) -   { -      char fn[30]; -        std::snprintf(fn, 30, "gl847_offset%03d.pnm", bottom); -        sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth, -                                     channels, pixels, lines); -   } - -  bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels); -  DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); - -  /* now top value */ -  top = 255; -  dev->frontend.set_offset(0, top); -  dev->frontend.set_offset(1, top); -  dev->frontend.set_offset(2, top); -    set_fe(dev, sensor, AFE_SET); -    dev->interface->write_registers(regs); -  DBG(DBG_info, "%s: starting second line reading\n", __func__); -    begin_scan(dev, sensor, ®s, true); -    sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); - -  topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); -  DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); - -  /* loop until acceptable level */ -  while ((pass < 32) && (top - bottom > 1)) -    { -      pass++; - -      /* settings for new scan */ -      dev->frontend.set_offset(0, (top + bottom) / 2); -      dev->frontend.set_offset(1, (top + bottom) / 2); -      dev->frontend.set_offset(2, (top + bottom) / 2); - -        // scan with no move -        set_fe(dev, sensor, AFE_SET); -        dev->interface->write_registers(regs); -      DBG(DBG_info, "%s: starting second line reading\n", __func__); -        begin_scan(dev, sensor, ®s, true); -        sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); - -      if (DBG_LEVEL >= DBG_data) -	{ -          char fn[30]; -          std::snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1)); -          sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth, -                                       channels, pixels, lines); -	} - -      avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); -      DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); - -      /* compute new boundaries */ -      if (topavg == avg) -	{ -	  topavg = avg; -          top = dev->frontend.get_offset(1); -	} -      else -	{ -	  bottomavg = avg; -          bottom = dev->frontend.get_offset(1); -	} -    } -  DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, -      dev->frontend.get_offset(0), -      dev->frontend.get_offset(1), -      dev->frontend.get_offset(2)); +    scanner_offset_calibration(*dev, sensor, regs);  }  void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,                                                Genesys_Register_Set& regs, int dpi) const  { -    DBG_HELPER_ARGS(dbg, "dpi = %d", dpi); -  int pixels; -  int total_size; -  int i, j, channels; -  int max[3]; -  float gain[3],coeff; -  int val, code, lines; - -    // no gain nor offset for AKM AFE -    uint8_t reg04 = dev->interface->read_register(REG_0x04); -    if ((reg04 & REG_0x04_FESET) == 0x02) { -      return; -    } - -  /* coarse gain calibration is always done in color mode */ -  channels = 3; - -  /* follow CKSEL */ -  if(dev->settings.xres<sensor.optical_res) -    { -        coeff = 0.9f; -    } -  else -    { -      coeff=1.0; -    } -  lines=10; -    pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res; - -    ScanSession session; -    session.params.xres = sensor.optical_res; -    session.params.yres = sensor.optical_res; -    session.params.startx = 0; -    session.params.starty = 0; -    session.params.pixels = pixels; -    session.params.lines = lines; -    session.params.depth = 8; -    session.params.channels = channels; -    session.params.scan_method = dev->settings.scan_method; -    session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; -    session.params.color_filter = dev->settings.color_filter; -    session.params.flags = ScanFlag::DISABLE_SHADING | -                           ScanFlag::DISABLE_GAMMA | -                           ScanFlag::SINGLE_LINE | -                           ScanFlag::IGNORE_LINE_DISTANCE; -    compute_session(dev, session, sensor); - -    try { -        init_regs_for_scan_session(dev, sensor, ®s, session); -    } catch (...) { -        catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); -        throw; -    } - -    sanei_genesys_set_motor_power(regs, false); - -    dev->interface->write_registers(regs); - -    total_size = pixels * channels * (16 / session.params.depth) * lines; - -  std::vector<uint8_t> line(total_size); - -    set_fe(dev, sensor, AFE_SET); -    begin_scan(dev, sensor, ®s, true); - -    if (is_testing_mode()) { -        dev->interface->test_checkpoint("coarse_gain_calibration"); -        scanner_stop_action(*dev); -        move_back_home(dev, true); -        return; -    } - -    sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - -    if (DBG_LEVEL >= DBG_data) { -        sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), session.params.depth, -                                     channels, pixels, lines); -    } - -  /* average value on each channel */ -  for (j = 0; j < channels; j++) -    { -      max[j] = 0; -      for (i = pixels/4; i < (pixels*3/4); i++) -	{ -            if (dev->model->is_cis) { -                val = line[i + j * pixels]; -            } else { -                val = line[i * channels + j]; -            } - -	    max[j] += val; -	} -      max[j] = max[j] / (pixels/2); - -      gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j]; - -      /* turn logical gain value into gain code, checking for overflow */ -        code = static_cast<int>(283 - 208 / gain[j]); -      if (code > 255) -	code = 255; -      else if (code < 0) -	code = 0; -      dev->frontend.set_gain(j, code); - -      DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], -          dev->frontend.get_gain(j)); -    } - -    if (dev->model->is_cis) { -        uint8_t gain0 = dev->frontend.get_gain(0); -        if (gain0 > dev->frontend.get_gain(1)) { -            gain0 = dev->frontend.get_gain(1); -        } -        if (gain0 > dev->frontend.get_gain(2)) { -            gain0 = dev->frontend.get_gain(2); -        } -        dev->frontend.set_gain(0, gain0); -        dev->frontend.set_gain(1, gain0); -        dev->frontend.set_gain(2, gain0); -    } - -    if (channels == 1) { -        dev->frontend.set_gain(0, dev->frontend.get_gain(1)); -        dev->frontend.set_gain(2, dev->frontend.get_gain(1)); -    } - -    scanner_stop_action(*dev); - -    move_back_home(dev, true); +    scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);  }  bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const @@ -2086,14 +1185,11 @@ bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev)  }  void CommandSetGl847::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, -                                           Genesys_Register_Set* regs, int* channels, -                                           int* total_size) const +                                           Genesys_Register_Set* regs) const  {      (void) dev;      (void) sensor;      (void) regs; -    (void) channels; -    (void) total_size;      throw SaneException("not implemented");  } @@ -2125,16 +1221,5 @@ void CommandSetGl847::eject_document(Genesys_Device* dev) const      throw SaneException("not implemented");  } -void CommandSetGl847::move_to_ta(Genesys_Device* dev) const -{ -    (void) dev; -    throw SaneException("not implemented"); -} - -std::unique_ptr<CommandSet> create_gl847_cmd_set() -{ -    return std::unique_ptr<CommandSet>(new CommandSetGl847{}); -} -  } // namespace gl847  } // namespace genesys | 
