kopia lustrzana https://gitlab.com/sane-project/backends
450 wiersze
18 KiB
C++
450 wiersze
18 KiB
C++
/* sane - Scanner Access Now Easy.
|
|
|
|
Copyright (C) 2003 Oliver Rauch
|
|
Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de>
|
|
Copyright (C) 2004, 2005 Gerhard Jaeger <gerhard@gjaeger.de>
|
|
Copyright (C) 2004-2013 Stéphane Voltz <stef.dev@free.fr>
|
|
Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
|
|
Copyright (C) 2006 Laurent Charpentier <laurent_pubs@yahoo.com>
|
|
Parts of the structs have been taken from the gt68xx backend by
|
|
Sergey Vlasov <vsu@altlinux.ru> et al.
|
|
|
|
This file is part of the SANE package.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef GENESYS_LOW_H
|
|
#define GENESYS_LOW_H
|
|
|
|
|
|
#include "../include/sane/config.h"
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <stddef.h>
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
#ifdef HAVE_MKDIR
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/sanei.h"
|
|
#include "../include/sane/saneopts.h"
|
|
|
|
#include "../include/sane/sanei_backend.h"
|
|
#include "../include/sane/sanei_usb.h"
|
|
|
|
#include "../include/_stdint.h"
|
|
|
|
#include "device.h"
|
|
#include "enums.h"
|
|
#include "error.h"
|
|
#include "fwd.h"
|
|
#include "usb_device.h"
|
|
#include "sensor.h"
|
|
#include "serialize.h"
|
|
#include "settings.h"
|
|
#include "static_init.h"
|
|
#include "status.h"
|
|
#include "register.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#define GENESYS_RED 0
|
|
#define GENESYS_GREEN 1
|
|
#define GENESYS_BLUE 2
|
|
|
|
#define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */
|
|
#define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */
|
|
#define GENESYS_HAS_FILE_SW (1 << 1) /**< scanner has FILE button */
|
|
#define GENESYS_HAS_COPY_SW (1 << 2) /**< scanner has COPY button */
|
|
#define GENESYS_HAS_EMAIL_SW (1 << 3) /**< scanner has EMAIL button */
|
|
#define GENESYS_HAS_PAGE_LOADED_SW (1 << 4) /**< scanner has paper in detection */
|
|
#define GENESYS_HAS_OCR_SW (1 << 5) /**< scanner has OCR button */
|
|
#define GENESYS_HAS_POWER_SW (1 << 6) /**< scanner has power button */
|
|
#define GENESYS_HAS_CALIBRATE (1 << 7) /**< scanner has 'calibrate' software button to start calibration */
|
|
#define GENESYS_HAS_EXTRA_SW (1 << 8) /**< scanner has extra function button */
|
|
#define GENESYS_HAS_TRANSP_SW (1 << 9) /**< scanner has TRANSPARENCY/SCAN_FILM button */
|
|
#define GENESYS_HAS_PDF1_SW (1 << 10) /**< scanner has special PDF button 1 */
|
|
#define GENESYS_HAS_PDF2_SW (1 << 11) /**< scanner has special PDF button 2 */
|
|
#define GENESYS_HAS_PDF3_SW (1 << 12) /**< scanner has special PDF button 3 */
|
|
#define GENESYS_HAS_PDF4_SW (1 << 13) /**< scanner has special PDF button 4 */
|
|
|
|
/* USB control message values */
|
|
#define REQUEST_TYPE_IN (USB_TYPE_VENDOR | USB_DIR_IN)
|
|
#define REQUEST_TYPE_OUT (USB_TYPE_VENDOR | USB_DIR_OUT)
|
|
#define REQUEST_REGISTER 0x0c
|
|
#define REQUEST_BUFFER 0x04
|
|
#define VALUE_BUFFER 0x82
|
|
#define VALUE_SET_REGISTER 0x83
|
|
#define VALUE_READ_REGISTER 0x84
|
|
#define VALUE_WRITE_REGISTER 0x85
|
|
#define VALUE_INIT 0x87
|
|
#define GPIO_OUTPUT_ENABLE 0x89
|
|
#define GPIO_READ 0x8a
|
|
#define GPIO_WRITE 0x8b
|
|
#define VALUE_BUF_ENDACCESS 0x8c
|
|
#define VALUE_GET_REGISTER 0x8e
|
|
#define INDEX 0x00
|
|
|
|
/* todo: used?
|
|
#define VALUE_READ_STATUS 0x86
|
|
*/
|
|
|
|
/* Read/write bulk data/registers */
|
|
#define BULK_OUT 0x01
|
|
#define BULK_IN 0x00
|
|
#define BULK_RAM 0x00
|
|
#define BULK_REGISTER 0x11
|
|
|
|
#define BULKOUT_MAXSIZE 0xF000
|
|
|
|
/* AFE values */
|
|
#define AFE_INIT 1
|
|
#define AFE_SET 2
|
|
#define AFE_POWER_SAVE 4
|
|
|
|
namespace genesys {
|
|
|
|
class UsbDeviceEntry {
|
|
public:
|
|
static constexpr std::uint16_t BCD_DEVICE_NOT_SET = 0xffff;
|
|
|
|
UsbDeviceEntry(std::uint16_t vendor_id, std::uint16_t product_id,
|
|
const Genesys_Model& model) :
|
|
vendor_{vendor_id}, product_{product_id},
|
|
bcd_device_{BCD_DEVICE_NOT_SET}, model_{model}
|
|
{}
|
|
|
|
UsbDeviceEntry(std::uint16_t vendor_id, std::uint16_t product_id, std::uint16_t bcd_device,
|
|
const Genesys_Model& model) :
|
|
vendor_{vendor_id}, product_{product_id},
|
|
bcd_device_{bcd_device}, model_{model}
|
|
{}
|
|
|
|
std::uint16_t vendor_id() const { return vendor_; }
|
|
std::uint16_t product_id() const { return product_; }
|
|
std::uint16_t bcd_device() const { return bcd_device_; }
|
|
|
|
const Genesys_Model& model() const { return model_; }
|
|
|
|
bool matches(std::uint16_t vendor_id, std::uint16_t product_id, std::uint16_t bcd_device)
|
|
{
|
|
if (vendor_ != vendor_id)
|
|
return false;
|
|
if (product_ != product_id)
|
|
return false;
|
|
if (bcd_device_ != BCD_DEVICE_NOT_SET && bcd_device != BCD_DEVICE_NOT_SET &&
|
|
bcd_device_ != bcd_device)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
// USB vendor identifier
|
|
std::uint16_t vendor_;
|
|
// USB product identifier
|
|
std::uint16_t product_;
|
|
// USB bcdProduct identifier
|
|
std::uint16_t bcd_device_;
|
|
// Scanner model information
|
|
Genesys_Model model_;
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* common functions needed by low level specific functions */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
std::unique_ptr<CommandSet> create_cmd_set(AsicType asic_type);
|
|
|
|
// reads the status of the scanner
|
|
Status scanner_read_status(Genesys_Device& dev);
|
|
|
|
// reads the status of the scanner reliably. This is done by reading the status twice. The first
|
|
// read sometimes returns the home sensor as engaged when this is not true.
|
|
Status scanner_read_reliable_status(Genesys_Device& dev);
|
|
|
|
// reads and prints the scanner status
|
|
void scanner_read_print_status(Genesys_Device& dev);
|
|
|
|
void debug_print_status(DebugMessageHelper& dbg, Status status);
|
|
|
|
void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
|
|
void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
|
|
void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
|
|
std::uint8_t value, std::uint8_t mask);
|
|
|
|
void sanei_genesys_write_ahb(Genesys_Device* dev, std::uint32_t addr, std::uint32_t size,
|
|
std::uint8_t* data);
|
|
|
|
extern void sanei_genesys_init_structs (Genesys_Device * dev);
|
|
|
|
const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev);
|
|
const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
|
|
unsigned channels, ScanMethod scan_method);
|
|
bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
|
|
ScanMethod scan_method);
|
|
Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi,
|
|
unsigned channels, ScanMethod scan_method);
|
|
|
|
std::vector<std::reference_wrapper<const Genesys_Sensor>>
|
|
sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method);
|
|
std::vector<std::reference_wrapper<Genesys_Sensor>>
|
|
sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method);
|
|
|
|
extern void sanei_genesys_init_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
|
int pixels_per_line);
|
|
|
|
extern void sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* steps);
|
|
|
|
extern void sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* steps);
|
|
|
|
extern void sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps);
|
|
|
|
void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
|
Genesys_Register_Set& regs, bool set);
|
|
|
|
void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set);
|
|
|
|
bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor);
|
|
|
|
/** Calculates the values of the Z{1,2}MOD registers. They are a phase correction to synchronize
|
|
with the line clock during acceleration and deceleration.
|
|
|
|
two_table is true if moving is done by two tables, false otherwise.
|
|
|
|
acceleration_steps is the number of steps for acceleration, i.e. the number written to
|
|
REG_STEPNO.
|
|
|
|
move_steps number of steps to move, i.e. the number written to REG_FEEDL.
|
|
|
|
buffer_acceleration_steps, the number of steps for acceleration when buffer condition is met,
|
|
i.e. the number written to REG_FWDSTEP.
|
|
*/
|
|
void sanei_genesys_calculate_zmod(bool two_table,
|
|
std::uint32_t exposure_time,
|
|
const std::vector<std::uint16_t>& slope_table,
|
|
unsigned acceleration_steps,
|
|
unsigned move_steps,
|
|
unsigned buffer_acceleration_steps,
|
|
std::uint32_t* out_z1, std::uint32_t* out_z2);
|
|
|
|
extern void sanei_genesys_set_buffer_address(Genesys_Device* dev, std::uint32_t addr);
|
|
|
|
unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type);
|
|
|
|
SANE_Int sanei_genesys_exposure_time2(Genesys_Device* dev, const MotorProfile& profile, float ydpi,
|
|
int endpixel, int led_exposure);
|
|
|
|
void sanei_genesys_create_default_gamma_table(Genesys_Device* dev,
|
|
std::vector<std::uint16_t>& gamma_table, float gamma);
|
|
|
|
std::vector<std::uint16_t> get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
|
int color);
|
|
|
|
void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor);
|
|
|
|
extern void sanei_genesys_stop_motor(Genesys_Device* dev);
|
|
|
|
// moves the scan head by the specified steps at the motor base dpi
|
|
void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, Direction direction);
|
|
|
|
void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home);
|
|
void scanner_move_back_home_ta(Genesys_Device& dev);
|
|
|
|
/** 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 scanner_search_strip(Genesys_Device& dev, bool forward, bool black);
|
|
|
|
bool should_calibrate_only_active_area(const Genesys_Device& dev,
|
|
const Genesys_Settings& settings);
|
|
|
|
void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
|
Genesys_Register_Set& regs);
|
|
|
|
void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
|
Genesys_Register_Set& regs, unsigned dpi);
|
|
|
|
SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
|
Genesys_Register_Set& regs);
|
|
|
|
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev);
|
|
|
|
void scanner_send_slope_table(Genesys_Device* dev, const Genesys_Sensor& sensor, unsigned table_nr,
|
|
const std::vector<std::uint16_t>& slope_table);
|
|
|
|
extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
|
|
std::size_t length);
|
|
|
|
void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice = false);
|
|
|
|
void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, std::uint8_t* data, size_t size);
|
|
|
|
Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session,
|
|
std::size_t total_bytes);
|
|
|
|
void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs,
|
|
const SensorExposure& exposure);
|
|
|
|
void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs);
|
|
|
|
void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw);
|
|
|
|
inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure)
|
|
{
|
|
exposure.red = std::max<std::uint16_t>(1, exposure.red);
|
|
exposure.green = std::max<std::uint16_t>(1, exposure.green);
|
|
exposure.blue = std::max<std::uint16_t>(1, exposure.blue);
|
|
return exposure;
|
|
}
|
|
|
|
bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs);
|
|
|
|
extern void sanei_genesys_wait_for_home(Genesys_Device* dev);
|
|
|
|
extern void sanei_genesys_asic_init(Genesys_Device* dev);
|
|
|
|
void scanner_start_action(Genesys_Device& dev, bool start_motor);
|
|
void scanner_stop_action(Genesys_Device& dev);
|
|
void scanner_stop_action_no_move(Genesys_Device& dev, Genesys_Register_Set& regs);
|
|
|
|
bool scanner_is_motor_stopped(Genesys_Device& dev);
|
|
|
|
void scanner_setup_sensor(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
|
Genesys_Register_Set& regs);
|
|
|
|
const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
|
|
unsigned exposure,
|
|
const ScanSession& session);
|
|
|
|
const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
|
|
unsigned exposure,
|
|
const ScanSession& session);
|
|
|
|
MotorSlopeTable create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi,
|
|
unsigned exposure, unsigned step_multiplier,
|
|
const MotorProfile& motor_profile);
|
|
|
|
MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
|
|
const MotorProfile& motor_profile);
|
|
|
|
/** @brief find lowest motor resolution for the device.
|
|
* Parses the resolution list for motor and
|
|
* returns the lowest value.
|
|
* @param dev for which to find the lowest motor resolution
|
|
* @return the lowest available motor resolution for the device
|
|
*/
|
|
extern
|
|
int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev);
|
|
|
|
/** @brief find lowest resolution for the device.
|
|
* Parses the resolution list for motor and sensor and
|
|
* returns the lowest value.
|
|
* @param dev for which to find the lowest resolution
|
|
* @return the lowest available resolution for the device
|
|
*/
|
|
extern
|
|
int sanei_genesys_get_lowest_dpi(Genesys_Device *dev);
|
|
|
|
bool sanei_genesys_is_compatible_calibration(Genesys_Device* dev,
|
|
const ScanSession& session,
|
|
const Genesys_Calibration_Cache* cache,
|
|
bool for_overwrite);
|
|
|
|
extern void sanei_genesys_load_lut(unsigned char* lut,
|
|
int in_bits, int out_bits,
|
|
int out_min, int out_max,
|
|
int slope, int offset);
|
|
|
|
std::vector<std::uint8_t> generate_gamma_buffer(Genesys_Device* dev,
|
|
const Genesys_Sensor& sensor,
|
|
int bits, int max, int size);
|
|
|
|
unsigned session_adjust_output_pixels(unsigned output_pixels,
|
|
const Genesys_Device& dev, const Genesys_Sensor& sensor,
|
|
unsigned output_xresolution, unsigned output_yresolution,
|
|
bool adjust_output_pixels);
|
|
|
|
void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor);
|
|
|
|
ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
|
|
unsigned pipeline_index, bool log_image_data);
|
|
|
|
// sets up a image pipeline for device `dev`
|
|
void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session);
|
|
|
|
std::uint8_t compute_frontend_gain(float value, float target_value,
|
|
FrontendType frontend_type);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* ASIC specific functions declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
extern StaticInit<std::vector<Genesys_Sensor>> s_sensors;
|
|
extern StaticInit<std::vector<Genesys_Frontend>> s_frontends;
|
|
extern StaticInit<std::vector<Genesys_Gpo>> s_gpo;
|
|
extern StaticInit<std::vector<MemoryLayout>> s_memory_layout;
|
|
extern StaticInit<std::vector<Genesys_Motor>> s_motors;
|
|
extern StaticInit<std::vector<UsbDeviceEntry>> s_usb_devices;
|
|
|
|
void genesys_init_sensor_tables();
|
|
void genesys_init_frontend_tables();
|
|
void genesys_init_gpo_tables();
|
|
void genesys_init_memory_layout_tables();
|
|
void genesys_init_motor_tables();
|
|
void genesys_init_usb_device_tables();
|
|
void verify_sensor_tables();
|
|
void verify_usb_device_tables();
|
|
|
|
template<class T>
|
|
void debug_dump(unsigned level, const T& value)
|
|
{
|
|
std::stringstream out;
|
|
out << value;
|
|
DBG(level, "%s\n", out.str().c_str());
|
|
}
|
|
|
|
} // namespace genesys
|
|
|
|
#endif /* not GENESYS_LOW_H */
|