Merge branch 'genesys-lide-90' into 'master'

genesys: Add support for Canon CanoScan LiDE 90

See merge request sane-project/backends!488
merge-requests/244/head
Povilas Kanapickas 2020-06-26 22:04:27 +00:00
commit 37c597d8df
27 zmienionych plików z 405 dodań i 108 usunięć

Wyświetl plik

@ -39,6 +39,9 @@ usb 0x04a9 0x221c
# Canon LiDE 80
usb 0x04a9 0x2214
# Canon LiDE 90
usb 0x04a9 0x1900
# Canon 4400F
usb 0x04a9 0x2228

Wyświetl plik

@ -107,15 +107,10 @@ public:
// Updates hardware sensor information in Genesys_Scanner.val[].
virtual void update_hardware_sensors(struct Genesys_Scanner* s) const = 0;
/** Whether the scanner needs to call update_home_sensor_gpio before reading the status of the
home sensor. On some chipsets this is unreliable until update_home_sensor_gpio() is called.
/** Needed on some chipsets before reading the status of the home sensor as the sensor may be
controlled by additional GPIO registers.
*/
virtual bool needs_update_home_sensor_gpio() const { return false; }
/** Needed on some chipsets before reading the status of the home sensor to make this operation
reliable.
*/
virtual void update_home_sensor_gpio(Genesys_Device& dev) const { (void) dev; }
virtual void update_home_sensor_gpio(Genesys_Device& dev) const = 0;
// functions for sheetfed scanners

Wyświetl plik

@ -121,6 +121,7 @@ std::ostream& operator<<(std::ostream& out, ModelId id)
case ModelId::CANON_LIDE_50: out << "CANON_LIDE_50"; break;
case ModelId::CANON_LIDE_60: out << "CANON_LIDE_60"; break;
case ModelId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case ModelId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
case ModelId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
case ModelId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case ModelId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
@ -205,6 +206,7 @@ std::ostream& operator<<(std::ostream& out, SensorId id)
case SensorId::CIS_CANON_LIDE_35: out << "CIS_CANON_LIDE_35"; break;
case SensorId::CIS_CANON_LIDE_60: out << "CIS_CANON_LIDE_60"; break;
case SensorId::CIS_CANON_LIDE_80: out << "CIS_CANON_LIDE_80"; break;
case SensorId::CIS_CANON_LIDE_90: out << "CIS_CANON_LIDE_90"; break;
case SensorId::CIS_CANON_LIDE_100: out << "CIS_CANON_LIDE_100"; break;
case SensorId::CIS_CANON_LIDE_110: out << "CIS_CANON_LIDE_110"; break;
case SensorId::CIS_CANON_LIDE_120: out << "CIS_CANON_LIDE_120"; break;
@ -226,6 +228,7 @@ std::ostream& operator<<(std::ostream& out, AdcId id)
case AdcId::AD_XP200: out << "AD_XP200"; break;
case AdcId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
case AdcId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case AdcId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
case AdcId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case AdcId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case AdcId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
@ -266,6 +269,7 @@ std::ostream& operator<<(std::ostream& out, GpioId id)
case GpioId::UNKNOWN: out << "UNKNOWN"; break;
case GpioId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
case GpioId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case GpioId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
case GpioId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case GpioId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case GpioId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
@ -306,6 +310,7 @@ std::ostream& operator<<(std::ostream& out, MotorId id)
{
switch (id) {
case MotorId::UNKNOWN: out << "UNKNOWN"; break;
case MotorId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
case MotorId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
case MotorId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case MotorId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;

Wyświetl plik

@ -182,6 +182,7 @@ enum class ModelId : unsigned
CANON_LIDE_50,
CANON_LIDE_60,
CANON_LIDE_80,
CANON_LIDE_90,
CANON_LIDE_100,
CANON_LIDE_110,
CANON_LIDE_120,
@ -276,6 +277,7 @@ enum class SensorId : unsigned
CIS_CANON_LIDE_35,
CIS_CANON_LIDE_60,
CIS_CANON_LIDE_80,
CIS_CANON_LIDE_90,
CIS_CANON_LIDE_100,
CIS_CANON_LIDE_110,
CIS_CANON_LIDE_120,
@ -308,6 +310,7 @@ enum class AdcId : unsigned
AD_XP200,
CANON_LIDE_35,
CANON_LIDE_80,
CANON_LIDE_90,
CANON_LIDE_110,
CANON_LIDE_120,
CANON_LIDE_200,
@ -358,6 +361,7 @@ enum class GpioId : unsigned
UNKNOWN = 0,
CANON_LIDE_35,
CANON_LIDE_80,
CANON_LIDE_90,
CANON_LIDE_110,
CANON_LIDE_120,
CANON_LIDE_200,
@ -406,6 +410,7 @@ enum class MotorId : unsigned
CANON_LIDE_60,
CANON_LIDE_700,
CANON_LIDE_80,
CANON_LIDE_90,
CANON_4400F,
CANON_5600F,
CANON_8400F,
@ -510,12 +515,18 @@ enum class ModelFlag : unsigned
// whether scanner must wait for the head while parking
MUST_WAIT = 1 << 10,
// use zeroes for dark calibration
USE_CONSTANT_FOR_DARK_CALIBRATION = 1 << 11,
// do dark and white calibration in one run
DARK_WHITE_CALIBRATION = 1 << 12,
// allow custom gamma tables
CUSTOM_GAMMA = 1 << 13,
// disable fast feeding mode on this scanner
DISABLE_FAST_FEEDING = 1 << 14,
// the scanner uses multi-segment sensors that must be handled during calibration
SIS_SENSOR = 1 << 16,

Wyświetl plik

@ -544,9 +544,10 @@ void scanner_send_slope_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
table.push_back(slope_table[i] & 0xff);
table.push_back(slope_table[i] >> 8);
}
if (dev->model->asic_type == AsicType::GL841) {
// BUG: some motor setup setting is wrong on GL841 scanners, as they need full motor table
// to be written even though this is not observed in the official scanners.
if (dev->model->asic_type == AsicType::GL841 ||
dev->model->model_id == ModelId::CANON_LIDE_90)
{
// BUG: do this on all gl842 scanners
auto max_table_size = get_slope_table_max_size(dev->model->asic_type);
table.reserve(max_table_size * 2);
while (table.size() < max_table_size * 2) {
@ -576,7 +577,8 @@ void scanner_send_slope_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
table.size());
break;
}
case AsicType::GL841: {
case AsicType::GL841:
case AsicType::GL842: {
unsigned start_address = 0;
switch (sensor.register_dpihw) {
case 600: start_address = 0x08000; break;
@ -588,18 +590,6 @@ void scanner_send_slope_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
table.size());
break;
}
case AsicType::GL842: {
// slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000
// XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14);
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev->interface->write_buffer(0x3c, 0x010000 + 0x200 * table_nr, table.data(),
table.size());
} else {
dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(),
table.size());
}
break;
}
case AsicType::GL843: {
// slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000
// XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14);
@ -712,9 +702,7 @@ void scanner_stop_action(Genesys_Device& dev)
throw SaneException("Unsupported asic type");
}
if (dev.cmd_set->needs_update_home_sensor_gpio()) {
dev.cmd_set->update_home_sensor_gpio(dev);
}
dev.cmd_set->update_home_sensor_gpio(dev);
if (scanner_is_motor_stopped(dev)) {
DBG(DBG_info, "%s: already stopped\n", __func__);
@ -868,9 +856,7 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
// wait until feed count reaches the required value
if (dev.model->model_id == ModelId::CANON_LIDE_700F) {
if (dev.cmd_set->needs_update_home_sensor_gpio()) {
dev.cmd_set->update_home_sensor_gpio(dev);
}
dev.cmd_set->update_home_sensor_gpio(dev);
}
// FIXME: should porbably wait for some timeout
@ -948,9 +934,7 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
Direction::BACKWARD);
}
if (dev.cmd_set->needs_update_home_sensor_gpio()) {
dev.cmd_set->update_home_sensor_gpio(dev);
}
dev.cmd_set->update_home_sensor_gpio(dev);
auto status = scanner_read_reliable_status(dev);
@ -1012,9 +996,7 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
throw;
}
if (dev.cmd_set->needs_update_home_sensor_gpio()) {
dev.cmd_set->update_home_sensor_gpio(dev);
}
dev.cmd_set->update_home_sensor_gpio(dev);
if (is_testing_mode()) {
dev.interface->test_checkpoint("move_back_home");
@ -2464,7 +2446,7 @@ static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_
* can be computed from previous calibration data (when doing offset
* calibration ?)
*/
static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor& sensor)
static void genesys_dark_shading_by_dummy_pixel(Genesys_Device* dev, const Genesys_Sensor& sensor)
{
DBG_HELPER(dbg);
uint32_t pixels_per_line;
@ -2543,6 +2525,11 @@ static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor
}
}
static void genesys_dark_shading_by_constant(Genesys_Device& dev)
{
dev.dark_average_data.clear();
dev.dark_average_data.resize(dev.average_size, 0x0101);
}
static void genesys_repark_sensor_before_shading(Genesys_Device* dev)
{
@ -3554,6 +3541,7 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
break;
case SensorId::CIS_CANON_LIDE_35:
case SensorId::CIS_CANON_LIDE_60:
case SensorId::CIS_CANON_LIDE_90:
compute_averaged_planar (dev, sensor,
shading_data.data(),
pixels_per_line,
@ -3794,7 +3782,11 @@ static void genesys_flatbed_calibration(Genesys_Device* dev, Genesys_Sensor& sen
genesys_repark_sensor_after_white_shading(dev);
if (!has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
genesys_dummy_dark_shading(dev, sensor);
if (has_flag(dev->model->flags, ModelFlag::USE_CONSTANT_FOR_DARK_CALIBRATION)) {
genesys_dark_shading_by_constant(*dev);
} else {
genesys_dark_shading_by_dummy_pixel(dev, sensor);
}
}
}
}
@ -3902,17 +3894,9 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
}
// in case we haven't black shading data, build it from black pixels of white calibration
// FIXME: shouldn't we use genesys_dummy_dark_shading() ?
// FIXME: shouldn't we use genesys_dark_shading_by_dummy_pixel() ?
if (!has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
dev->dark_average_data.clear();
dev->dark_average_data.resize(dev->average_size, 0x0f0f);
/* XXX STEF XXX
* with black point in white shading, build an average black
* pixel and use it to fill the dark_average
* dev->calib_pixels
(sensor.x_size_calib_mm * dev->settings.xres) / MM_PER_INCH,
dev->calib_lines,
*/
genesys_dark_shading_by_constant(*dev);
}
/* send the shading coefficient when doing whole line shading

Wyświetl plik

@ -95,8 +95,6 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
bool needs_update_home_sensor_gpio() const override { return true; }
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;

Wyświetl plik

@ -2856,6 +2856,11 @@ void CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const
}
}
void CommandSetGl646::update_home_sensor_gpio(Genesys_Device& dev) const
{
DBG_HELPER(dbg);
(void) dev;
}
static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution)
{

Wyświetl plik

@ -99,6 +99,8 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;
void detect_document_end(Genesys_Device* dev) const override;

Wyświetl plik

@ -575,6 +575,9 @@ static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor
// BUG: fast table is counted in base_ydpi / 4
feedl = feed_steps - fast_table.table.size() * 2;
use_fast_fed = 1;
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set8(0x3d, (feedl >> 16) & 0xf);
reg->set8(0x3e, (feedl >> 8) & 0xff);
@ -713,6 +716,10 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
use_fast_fed = fast_time < slow_time;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
if (use_fast_fed) {
feedl = feed_steps - fast_table.table.size() * 2 -
(slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type));

Wyświetl plik

@ -95,8 +95,6 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
bool needs_update_home_sensor_gpio() const override { return true; }
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;

Wyświetl plik

@ -46,19 +46,35 @@ static void gl842_init_registers(Genesys_Device& dev)
dev.reg.clear();
dev.reg.init_reg(0x01, 0x00);
dev.reg.init_reg(0x02, 0x78);
dev.reg.init_reg(0x03, 0xbf);
dev.reg.init_reg(0x04, 0x22);
dev.reg.init_reg(0x05, 0x48);
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x01, 0x00);
dev.reg.init_reg(0x02, 0x78);
dev.reg.init_reg(0x03, 0xbf);
dev.reg.init_reg(0x04, 0x22);
dev.reg.init_reg(0x05, 0x48);
dev.reg.init_reg(0x06, 0xb8);
dev.reg.init_reg(0x06, 0xb8);
dev.reg.init_reg(0x07, 0x00);
dev.reg.init_reg(0x08, 0x00);
dev.reg.init_reg(0x09, 0x00);
dev.reg.init_reg(0x0a, 0x00);
dev.reg.init_reg(0x0d, 0x01);
dev.reg.init_reg(0x07, 0x00);
dev.reg.init_reg(0x08, 0x00);
dev.reg.init_reg(0x09, 0x00);
dev.reg.init_reg(0x0a, 0x00);
dev.reg.init_reg(0x0d, 0x01);
} else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
dev.reg.init_reg(0x01, 0x82);
dev.reg.init_reg(0x02, 0x10);
dev.reg.init_reg(0x03, 0x60);
dev.reg.init_reg(0x04, 0x10);
dev.reg.init_reg(0x05, 0x8c);
dev.reg.init_reg(0x06, 0x18);
//dev.reg.init_reg(0x07, 0x00);
dev.reg.init_reg(0x08, 0x00);
dev.reg.init_reg(0x09, 0x21);
dev.reg.init_reg(0x0a, 0x00);
dev.reg.init_reg(0x0d, 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
@ -77,14 +93,20 @@ static void gl842_init_registers(Genesys_Device& dev)
// Various CCD clock settings.
dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
}
dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
dev.reg.init_reg(0x1f, 0x01);
dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x1f, 0x01);
dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
} else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
dev.reg.init_reg(0x1f, 0x02);
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, 0x10); // FWDSTEP: set during motor setup
@ -127,7 +149,12 @@ static void gl842_init_registers(Genesys_Device& dev)
dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
} else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
dev.reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
dev.reg.init_reg(0x5d, 0x20);
}
dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
@ -137,8 +164,14 @@ static void gl842_init_registers(Genesys_Device& dev)
dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: overwritten during motor setup
dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: overwritten during motor setup
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: partially overwritten during motor setup
dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: partially overwritten during motor setup
} else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
dev.reg.init_reg(0x66, 0x00); // PHFREQ
dev.reg.init_reg(0x67, 0x40); // STEPSEL, MTRPWM: partially overwritten during motor setup
dev.reg.init_reg(0x68, 0x40); // FSTPSEL, FASTPWM: partially overwritten during motor setup
}
dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
@ -167,13 +200,26 @@ static void gl842_init_registers(Genesys_Device& dev)
// moving in various situations.
dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
dev.reg.init_reg(0x81, 0x00);
dev.reg.init_reg(0x82, 0x00);
dev.reg.init_reg(0x83, 0x00);
dev.reg.init_reg(0x84, 0x00);
dev.reg.init_reg(0x85, 0x00);
dev.reg.init_reg(0x86, 0x00);
dev.reg.init_reg(0x87, 0x00);
if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev.reg.init_reg(0x81, 0x00);
dev.reg.init_reg(0x82, 0x00);
dev.reg.init_reg(0x83, 0x00);
dev.reg.init_reg(0x84, 0x00);
dev.reg.init_reg(0x85, 0x00);
dev.reg.init_reg(0x86, 0x00);
dev.reg.init_reg(0x87, 0x00);
} else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
dev.reg.init_reg(0x7e, 0x00);
dev.reg.init_reg(0x81, 0x00);
dev.reg.init_reg(0x82, 0x0f);
dev.reg.init_reg(0x83, 0x00);
dev.reg.init_reg(0x84, 0x0e);
dev.reg.init_reg(0x85, 0x00);
dev.reg.init_reg(0x86, 0x0d);
dev.reg.init_reg(0x87, 0x00);
dev.reg.init_reg(0x88, 0x00);
dev.reg.init_reg(0x89, 0x00);
}
const auto& sensor = sanei_genesys_find_sensor_any(&dev);
sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
@ -181,13 +227,6 @@ static void gl842_init_registers(Genesys_Device& dev)
scanner_setup_sensor(dev, sensor, dev.reg);
}
static void gl842_set_ad_fe(Genesys_Device* dev)
{
for (const auto& reg : dev->frontend.regs) {
dev->interface->write_fe_register(reg.address, reg.value);
}
}
// Set values of analog frontend
void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
{
@ -203,8 +242,10 @@ void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
// check analog frontend type
// FIXME: looks like we write to that register with initial data
uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
if (fe_type == 2) {
gl842_set_ad_fe(dev);
if (fe_type == 2 || dev->model->model_id == ModelId::CANON_LIDE_90) {
for (const auto& reg : dev->frontend.regs) {
dev->interface->write_fe_register(reg.address, reg.value);
}
return;
}
if (fe_type != 0) {
@ -222,12 +263,6 @@ void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
}
if (dev->model->sensor_id == SensorId::CCD_KVSS080) {
for (unsigned i = 0; i < 3; i++) {
dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
}
}
for (unsigned i = 0; i < 3; i++) {
dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
}
@ -256,6 +291,9 @@ static void gl842_init_motor_regs_scan(Genesys_Device* dev,
if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
use_fast_fed = true;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set24(REG_LINCNT, scan_lines);
@ -479,7 +517,11 @@ static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
reg->set24(REG_MAXWD, session.output_line_bytes_raw);
if (dev->model->is_cis) {
reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels);
} else {
reg->set24(REG_MAXWD, session.output_line_bytes_raw);
}
unsigned tgtime = exposure / 65536 + 1;
reg->set16(REG_LPERIOD, exposure / tgtime);
@ -513,6 +555,9 @@ void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Gene
if (exposure < 0) {
throw std::runtime_error("Exposure not defined in sensor definition");
}
if (dev->model->model_id == ModelId::CANON_LIDE_90) {
exposure *= 2;
}
const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
// now _LOGICAL_ optical values used are known, setup registers
@ -640,6 +685,25 @@ void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
}
if (dev->model->model_id == ModelId::CANON_LIDE_90) {
if (has_flag(dev->session.params.flags, ScanFlag::REVERSE)) {
dev->interface->write_register(REG_0x6B, 0x01);
dev->interface->write_register(REG_0x6C, 0x02);
} else {
dev->interface->write_register(REG_0x6B, 0x03);
switch (dev->session.params.xres) {
case 150: dev->interface->write_register(REG_0x6C, 0x74); break;
case 300: dev->interface->write_register(REG_0x6C, 0x38); break;
case 600: dev->interface->write_register(REG_0x6C, 0x1c); break;
case 1200: dev->interface->write_register(REG_0x6C, 0x2c); break;
case 2400: dev->interface->write_register(REG_0x6C, 0x0c); break;
default:
break;
}
}
dev->interface->sleep_ms(100);
}
scanner_clear_scan_and_feed_counts(*dev);
// enable scan and motor
@ -899,6 +963,9 @@ void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev->interface->write_0x8c(0x10, 0x94);
}
if (dev->model->model_id == ModelId::CANON_LIDE_90) {
dev->interface->write_0x8c(0x10, 0xd4);
}
// set RAM read address
dev->interface->write_register(REG_0x2A, 0x00);
@ -923,6 +990,16 @@ void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
(void) s;
}
void CommandSetGl842::update_home_sensor_gpio(Genesys_Device& dev) const
{
DBG_HELPER(dbg);
if (dev.model->model_id == ModelId::CANON_LIDE_90) {
std::uint8_t val = dev.interface->read_register(REG_0x6C);
val |= 0x02;
dev.interface->write_register(REG_0x6C, val);
}
}
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.

Wyświetl plik

@ -95,6 +95,8 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;
void detect_document_end(Genesys_Device* dev) const override;

Wyświetl plik

@ -710,6 +710,9 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev,
if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
use_fast_fed = true;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set24(REG_LINCNT, scan_lines);
@ -1698,6 +1701,12 @@ void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const
}
}
void CommandSetGl843::update_home_sensor_gpio(Genesys_Device& dev) const
{
DBG_HELPER(dbg);
(void) dev;
}
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.

Wyświetl plik

@ -95,6 +95,8 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;
void detect_document_end(Genesys_Device* dev) const override;

Wyświetl plik

@ -380,6 +380,9 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
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;
}
reg->set24(REG_LINCNT, scan_lines);

Wyświetl plik

@ -95,8 +95,6 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
bool needs_update_home_sensor_gpio() const override { return true; }
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;

Wyświetl plik

@ -344,6 +344,9 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
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;
}
reg->set24(REG_LINCNT, scan_lines);

Wyświetl plik

@ -95,8 +95,6 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
bool needs_update_home_sensor_gpio() const override { return true; }
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;

Wyświetl plik

@ -791,7 +791,9 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
dev->model->asic_type == AsicType::GL847)
{
unsigned startx_xres = s.optical_resolution;
if (dev->model->model_id == ModelId::CANON_5600F) {
if (dev->model->model_id == ModelId::CANON_5600F ||
dev->model->model_id == ModelId::CANON_LIDE_90)
{
if (s.output_resolution == 1200) {
startx_xres /= 2;
}
@ -1044,7 +1046,9 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
}
}
if (dev->model->asic_type == AsicType::GL841) {
if (dev->model->asic_type == AsicType::GL841 ||
dev->model->asic_type == AsicType::GL842)
{
if (dev->model->is_cis) {
s.output_line_bytes_raw = s.output_channel_bytes;
}
@ -1060,7 +1064,13 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
if (dev->model->asic_type == AsicType::GL842 ||
dev->model->asic_type == AsicType::GL843)
{
s.conseq_pixel_dist = s.output_pixels / s.segment_count;
if (dev->model->is_cis) {
if (s.segment_count > 1) {
s.conseq_pixel_dist = sensor.segment_size;
}
} else {
s.conseq_pixel_dist = s.output_pixels / s.segment_count;
}
}
s.output_segment_pixel_group_count = 0;
@ -1071,6 +1081,11 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_segment_pixel_group_count = s.output_pixels /
(s.full_resolution / s.optical_resolution * s.segment_count);
}
if (dev->model->model_id == ModelId::CANON_LIDE_90) {
s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
}
if (dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846 ||
dev->model->asic_type == AsicType::GL847)
@ -1087,6 +1102,10 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count;
s.output_total_bytes = s.output_line_bytes * s.output_line_count;
if (dev->model->model_id == ModelId::CANON_LIDE_90) {
s.output_total_bytes_raw *= s.params.channels;
s.output_total_bytes *= s.params.channels;
}
s.buffer_size_read = s.output_line_bytes_raw * 64;
compute_session_pixel_offsets(dev, s, sensor);

Wyświetl plik

@ -141,6 +141,10 @@ MotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned t
dbg.log(DBG_warn, "failed to reach target speed");
}
if (target_speed_shifted_w >= std::numeric_limits<std::uint16_t>::max()) {
throw SaneException("Target motor speed is too low");
}
unsigned final_speed = std::max(target_speed_shifted_w, max_speed_shifted_w);
table.table.reserve(max_size);

Wyświetl plik

@ -219,6 +219,30 @@ void genesys_init_frontend_tables()
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_90;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON;
fe.regs = {
{ 0x01, 0x23 },
{ 0x02, 0x07 },
{ 0x03, 0x29 },
{ 0x06, 0x0d },
{ 0x08, 0x00 },
{ 0x09, 0x16 },
{ 0x20, 0x4d },
{ 0x21, 0x4d },
{ 0x22, 0x4d },
{ 0x23, 0x4d },
{ 0x28, 0x14 },
{ 0x29, 0x14 },
{ 0x2a, 0x14 },
{ 0x2b, 0x14 },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::AD_XP200;
fe.layout = wolfson_layout;

Wyświetl plik

@ -130,6 +130,18 @@ void genesys_init_gpo_tables()
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_LIDE_90;
gpo.regs = {
{ 0x6b, 0x03 },
{ 0x6c, 0x74 },
{ 0x6d, 0x80 },
{ 0x6e, 0x7f },
{ 0x6f, 0xe0 },
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::XP200;
gpo.regs = {

Wyświetl plik

@ -1177,6 +1177,65 @@ void genesys_init_usb_device_tables()
s_usb_devices->emplace_back(0x04a9, 0x2214, model);
model = Genesys_Model();
model.name = "canon-lide-90";
model.vendor = "Canon";
model.model = "LiDE 90";
model.model_id = ModelId::CANON_LIDE_90;
model.asic_type = AsicType::GL842;
model.resolutions = {
{
{ ScanMethod::FLATBED },
{ 2400, 1200, 600, 300 },
{ 2400, 1200, 600, 300 },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
model.x_offset = 3.50;
model.y_offset = 9.0;
model.x_size = 219.0;
model.y_size = 299.0;
model.y_offset_calib_white = 0.0;
model.y_size_calib_mm = 2.0;
model.y_offset_calib_dark_white_mm = 0.0;
model.y_size_calib_dark_white_mm = 0.0;
model.x_offset_calib_black = 0.0;
model.x_size_calib_mm = 221.5;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
model.ld_shift_g = 0;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
model.is_cis = true;
model.is_sheetfed = false;
model.sensor_id = SensorId::CIS_CANON_LIDE_90;
model.adc_id = AdcId::CANON_LIDE_90;
model.gpio_id = GpioId::CANON_LIDE_90;
model.motor_id = MotorId::CANON_LIDE_90;
model.flags = ModelFlag::DISABLE_ADC_CALIBRATION |
ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN |
ModelFlag::USE_CONSTANT_FOR_DARK_CALIBRATION |
ModelFlag::DISABLE_FAST_FEEDING |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_COPY_SW;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1900, model);
model = Genesys_Model();
model.name = "hewlett-packard-scanjet-2300c";
model.vendor = "Hewlett Packard";

Wyświetl plik

@ -144,6 +144,23 @@ void genesys_init_motor_tables()
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_90;
motor.base_ydpi = 1200;
profile = {MotorSlope::create_from_steps(8000, 3000, 200), StepType::FULL, 0};
profile.resolutions = { 150, 300 };
motor.profiles.push_back(profile);
profile = {MotorSlope::create_from_steps(7000, 3000, 200), StepType::HALF, 0};
profile.resolutions = { 600, 1200 };
motor.profiles.push_back(profile);
profile = {MotorSlope::create_from_steps(7000, 3000, 200), StepType::QUARTER, 0};
profile.resolutions = { 2400 };
motor.profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::XP200;
motor.base_ydpi = 600;

Wyświetl plik

@ -563,6 +563,69 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
sensor.sensor_id = SensorId::CIS_CANON_LIDE_90; // gl842
sensor.full_resolution = 2400;
sensor.black_pixels = 20;
sensor.dummy_pixel = 253;
sensor.fau_gain_white_ref = 150;
sensor.gain_white_ref = 150;
sensor.use_host_side_calib = true;
sensor.custom_regs = {
{ 0x16, 0x20 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x24 }, { 0x1c, 0x00 }, { 0x1d, 0x04 },
{ 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x02 }, { 0x55, 0x04 },
{ 0x56, 0x02 }, { 0x57, 0x04 }, { 0x58, 0x0a }, { 0x59, 0x71 }, { 0x5a, 0x55 },
{ 0x70, 0x00 }, { 0x71, 0x05 }, { 0x72, 0x07 }, { 0x73, 0x09 },
{ 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x3f },
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x1e }, { 0x7d, 0x11 }, { 0x7f, 0x50 }
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
{
struct CustomSensorSettings
{
ValueFilterAny<unsigned> resolutions;
unsigned optical_resolution;
unsigned register_dpihw;
unsigned register_dpiset;
unsigned shading_resolution;
unsigned shading_factor;
int output_pixel_offset;
SensorExposure exposure;
unsigned exposure_lperiod;
unsigned segment_size;
std::vector<unsigned> segment_order;
};
CustomSensorSettings custom_settings[] = {
{ { 300 }, 300, 600, 600, 300, 2, 280, { 955, 1235, 675 }, 6500, 5152,
std::vector<unsigned>{} },
{ { 600 }, 600, 600, 600, 600, 1, 250, { 1655, 2075, 1095 }, 6536, 5152,
std::vector<unsigned>{} },
{ { 1200 }, 1200, 1200, 1200, 1200, 1, 500, { 3055, 4175, 1935 }, 12688, 5152,
{0, 1} },
{ { 2400 }, 2400, 2400, 2400, 2400, 1, 1000, { 5855, 7535, 3615 }, 21500, 5152,
{0, 1, 2, 3} },
};
for (const CustomSensorSettings& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
sensor.optical_resolution = setting.optical_resolution;
sensor.register_dpihw = setting.register_dpihw;
sensor.register_dpiset = setting.register_dpiset;
sensor.shading_resolution = setting.shading_resolution;
sensor.shading_factor = setting.shading_factor;
sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.exposure = setting.exposure;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.segment_size = setting.segment_size;
sensor.segment_order = setting.segment_order;
s_sensors->push_back(sensor);
}
}
sensor = Genesys_Sensor();
sensor.sensor_id = SensorId::CIS_XP200; // gl646
sensor.full_resolution = 600;
@ -3803,7 +3866,7 @@ void verify_sensor_tables()
if (asic_type == AsicType::GL842) {
auto required_registers = {
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1c, 0x1d,
0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
0x7f

Wyświetl plik

@ -187,6 +187,12 @@
:status :basic
:comment "No 2400 dpi support, slow speed at lower resolution"
:model "CanoScan LiDE 90"
:interface "USB"
:usbid "0x04a9" "0x1900"
:status :good
:comment "resolutions from 300 to 2400 dpi are supported"
:model "CanoScan LiDE 100"
:interface "USB"
:usbid "0x04a9" "0x1904"

Wyświetl plik

@ -395,13 +395,6 @@
:status :unsupported
:comment "Not supported. However, a stand-alone program for FreeBSD is available."
:model "CanoScan LiDE 90"
:url "unsupported/canon-lide-90.html"
:interface "USB"
:usbid "0x04a9" "0x1900"
:status :unsupported
:comment "Unsupported. See link for details."
:model "CanoScan LiDE 500F"
:url "unsupported/canon-canoscan-lide-500f.html"
:interface "USB"