diff options
Diffstat (limited to 'backend/genesys_gl646.c')
-rw-r--r-- | backend/genesys_gl646.c | 5799 |
1 files changed, 0 insertions, 5799 deletions
diff --git a/backend/genesys_gl646.c b/backend/genesys_gl646.c deleted file mode 100644 index 58952fb..0000000 --- a/backend/genesys_gl646.c +++ /dev/null @@ -1,5799 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de> - Copyright (C) 2004 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) 2007 Luke <iceyfor@gmail.com> - Copyright (C) 2011 Alexey Osipov <simba@lerlan.ru> for HP2400 description - and tuning - - 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, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - - As a special exception, the authors of SANE give permission for - additional uses of the libraries contained in this release of SANE. - - The exception is that, if you link a SANE library with other files - to produce an executable, this does not by itself cause the - resulting executable to be covered by the GNU General Public - License. Your use of that executable is in no way restricted on - account of linking the SANE library code into it. - - This exception does not, however, invalidate any other reasons why - the executable file might be covered by the GNU General Public - License. - - If you submit changes to SANE to the maintainers to be included in - a subsequent release, you agree by submitting the changes that - those changes may be distributed with this exception intact. - - If you write modifications of your own for SANE, it is your choice - whether to permit this exception to apply to your modifications. - If you do not wish that, delete this exception notice. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl646 - -#include "genesys_gl646.h" - -/** - * returns the value hold by a 3 word register - * @param regs register set from which reading the value - * @param regnum number of the register to read - * @return 24 bit value of the register - */ -static uint32_t -gl646_get_triple_reg (Genesys_Register_Set * regs, int regnum) -{ - Genesys_Register_Set *r = NULL; - uint32_t ret = 0; - - r = sanei_genesys_get_address (regs, regnum); - ret = r->value; - r = sanei_genesys_get_address (regs, regnum + 1); - ret = (ret << 8) + r->value; - r = sanei_genesys_get_address (regs, regnum + 2); - ret = (ret << 8) + r->value; - - return ret; -} - -/** - * returns the value hold by a 2 word register - * @param regs register set from which reading the value - * @param regnum number of the register to read - * @return 16 bit value of the register - */ -static uint32_t -gl646_get_double_reg (Genesys_Register_Set * regs, int regnum) -{ - Genesys_Register_Set *r = NULL; - uint32_t ret = 0; - - r = sanei_genesys_get_address (regs, regnum); - ret = r->value; - r = sanei_genesys_get_address (regs, regnum + 1); - ret = (ret << 8) + r->value; - - return ret; -} - -/* Write to many registers */ -static SANE_Status -gl646_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, size_t elems) -{ - SANE_Status status; - uint8_t outdata[8]; - uint8_t buffer[GENESYS_MAX_REGS * 2]; - size_t size; - unsigned int i; - - /* handle differently sized register sets, reg[0x00] may be the last one */ - i = 0; - while ((i < elems) && (reg[i].address != 0)) - i++; - elems = i; - size = i * 2; - - DBG (DBG_io, "gl646_bulk_write_register (elems= %lu, size = %lu)\n", - (u_long) elems, (u_long) size); - - - outdata[0] = BULK_OUT; - outdata[1] = BULK_REGISTER; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_register: failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - /* copy registers and values in data buffer */ - for (i = 0; i < size; i += 2) - { - buffer[i] = reg[i / 2].address; - buffer[i + 1] = reg[i / 2].value; - } - - status = sanei_usb_write_bulk (dev->dn, buffer, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_register: failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_io2) - { - for (i = 0; i < size; i += 2) - { - DBG (DBG_io2, "reg[0x%02x] = 0x%02x\n", buffer[i], buffer[i + 1]); - } - /* when full size, decode register content */ - if (elems > 60) - { - DBG (DBG_io2, "DPISET =%d\n", - gl646_get_double_reg (reg, REG_DPISET)); - DBG (DBG_io2, "DUMMY =%d\n", - sanei_genesys_get_address (reg, REG_DUMMY)->value); - DBG (DBG_io2, "STRPIXEL =%d\n", - gl646_get_double_reg (reg, REG_STRPIXEL)); - DBG (DBG_io2, "ENDPIXEL =%d\n", - gl646_get_double_reg (reg, REG_ENDPIXEL)); - DBG (DBG_io2, "LINCNT =%d\n", - gl646_get_triple_reg (reg, REG_LINCNT)); - DBG (DBG_io2, "MAXWD =%d\n", - gl646_get_triple_reg (reg, REG_MAXWD)); - DBG (DBG_io2, "LPERIOD =%d\n", - gl646_get_double_reg (reg, REG_LPERIOD)); - DBG (DBG_io2, "FEEDL =%d\n", - gl646_get_triple_reg (reg, REG_FEEDL)); - } - } - - DBG (DBG_io, "gl646_bulk_write_register: wrote %lu bytes, %lu registers\n", - (u_long) size, (u_long) elems); - return status; -} - -/* Write bulk data (e.g. shading, gamma) */ -static SANE_Status -gl646_bulk_write_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl646_bulk_write_data writing %lu bytes\n", (u_long) len); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > BULKOUT_MAXSIZE) - size = BULKOUT_MAXSIZE; - else - size = len; - - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_usb_write_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl646_bulk_write_data wrote %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBG (DBG_io, "gl646_bulk_write_data: end\n"); - - return status; -} - -/** - * reads value from gpio endpoint - */ -static SANE_Status -gl646_gpio_read (SANE_Int dn, uint8_t * value) -{ - return sanei_usb_control_msg (dn, REQUEST_TYPE_IN, - REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); -} - -/** - * writes the given value to gpio endpoint - */ -static SANE_Status -gl646_gpio_write (SANE_Int dn, uint8_t value) -{ - DBG (DBG_proc, "gl646_gpio_write(0x%02x)\n", value); - return sanei_usb_control_msg (dn, REQUEST_TYPE_OUT, - REQUEST_REGISTER, GPIO_WRITE, - INDEX, 1, &value); -} - -/** - * writes the given value to gpio output enable endpoint - */ -static SANE_Status -gl646_gpio_output_enable (SANE_Int dn, uint8_t value) -{ - DBG (DBG_proc, "gl646_gpio_output_enable(0x%02x)\n", value); - return sanei_usb_control_msg (dn, REQUEST_TYPE_OUT, - REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, - INDEX, 1, &value); -} - -/* Read bulk data (e.g. scanned data) */ -static SANE_Status -gl646_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl646_bulk_read_data: requesting %lu bytes\n", (u_long) len); - - /* write requested size */ - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > GL646_BULKIN_MAXSIZE) - size = GL646_BULKIN_MAXSIZE; - else - size = len; - - DBG (DBG_io2, - "gl646_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) size); - status = sanei_usb_read_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl646_bulk_read_data read %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - if (dev->model->is_sheetfed == SANE_TRUE) - { - gl646_detect_document_end (dev); - } - - DBG (DBG_io, "gl646_bulk_read_data: end\n"); - - return status; -} - -#if 0 -static SANE_Status -read_triple_reg (Genesys_Device * dev, int index, unsigned int *words) -{ - SANE_Status status; - uint8_t value; - - DBG (DBG_proc, "read_triple_reg\n"); - - RIE (sanei_genesys_read_register (dev, index + 2, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, index + 1, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, index, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - - DBG (DBG_proc, "read_triple_reg: value=%d\n", *words); - return status; -} -#endif - - -static SANE_Bool -gl646_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTMFLG) - return SANE_TRUE; - return SANE_FALSE; -} - -static void -gl646_set_triple_reg (Genesys_Register_Set * regs, int regnum, uint32_t value) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, regnum); - r->value = LOBYTE (HIWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 1); - r->value = HIBYTE (LOWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 2); - r->value = LOBYTE (LOWORD (value)); -} - -static void -gl646_set_double_reg (Genesys_Register_Set * regs, int regnum, uint16_t value) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, regnum); - r->value = HIBYTE (LOWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 1); - r->value = LOBYTE (LOWORD (value)); -} - -/** - * decodes and prints content of status (0x41) register - * @param val value read from reg41 - */ -static void -print_status (uint8_t val) -{ - char msg[80]; - - sprintf (msg, "%s%s%s%s%s%s%s%s", - val & REG41_PWRBIT ? "PWRBIT " : "", - val & REG41_BUFEMPTY ? "BUFEMPTY " : "", - val & REG41_FEEDFSH ? "FEEDFSH " : "", - val & REG41_SCANFSH ? "SCANFSH " : "", - val & REG41_HOMESNR ? "HOMESNR " : "", - val & REG41_LAMPSTS ? "LAMPSTS " : "", - val & REG41_FEBUSY ? "FEBUSY " : "", - val & REG41_MOTMFLG ? "MOTMFLG" : ""); - DBG (DBG_info, "status=%s\n", msg); -} - -/** - * start scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_start_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - - -/** - * stop scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_stop_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x00); -} - - -/** - * find the lowest resolution for the sensor in the given mode. - * @param sensor id of the sensor - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_lowest_resolution (int sensor, SANE_Bool color) -{ - int i, nb; - int dpi; - - i = 0; - dpi = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* computes distance and keep mode if it is closer than previous */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].color == color) - { - if (sensor_master[i].dpi < dpi) - { - dpi = sensor_master[i].dpi; - } - } - i++; - } - DBG (DBG_info, "get_lowest_resolution: %d\n", dpi); - return dpi; -} - -/** - * find the closest match in mode tables for the given resolution and scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_closest_resolution (int sensor, int required, SANE_Bool color) -{ - int i, nb; - int dist, dpi; - - i = 0; - dpi = 0; - dist = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_info, "get_closest_resolution: match found for %d\n", - required); - return required; - } - /* computes distance and keep mode if it is closer than previous */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].color == color) - { - if (abs (sensor_master[i].dpi - required) < dist) - { - dpi = sensor_master[i].dpi; - dist = abs (sensor_master[i].dpi - required); - } - } - i++; - } - DBG (DBG_info, "get_closest_resolution: closest match for %d is %d\n", - required, dpi); - return dpi; -} - -/** - * Computes if sensor will be set up for half ccd pixels for the given - * scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return SANE_TRUE if half ccd is used - */ -static SANE_Bool -is_half_ccd (int sensor, int required, SANE_Bool color) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_io, "is_half_ccd: match found for %d (half_ccd=%d)\n", - required, sensor_master[i].half_ccd); - return sensor_master[i].half_ccd; - } - i++; - } - DBG (DBG_info, "is_half_ccd: failed to find match for %d dpi\n", required); - return SANE_FALSE; -} - -/** - * Returns the cksel values used by the required scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return cksel value for mode - */ -static int -get_cksel (int sensor, int required, SANE_Bool color) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_io, "get_cksel: match found for %d (cksel=%d)\n", - required, sensor_master[i].cksel); - return sensor_master[i].cksel; - } - i++; - } - DBG (DBG_error, "get_cksel: failed to find match for %d dpi\n", required); - /* fail safe fallback */ - return 1; -} - -/** - * Setup register and motor tables for a scan at the - * given resolution and color mode. TODO try to not use any filed from - * the device. - * @param dev pointer to a struct describing the device - * @param regs register set to fill - * @param scan_settings scan's settings - * @param slope_table1 first motor table to fill - * @param slope_table2 second motor table to fill - * @param resolution dpi of the scan - * @param move distance to move (at scan's dpi) before scan - * @param linecnt number of lines to scan at scan's dpi - * @param startx start of scan area on CCD at CCD's optical resolution - * @param endx end of scan area on CCD at CCD's optical resolution - * @param color SANE_TRUE is color scan - * @param depth 1, 8 or 16 bits data sample - * @return SANE_STATUS_GOOD if registers could be set, SANE_STATUS_INVAL if - * conditions can't be met. - * @note No harcoded SENSOR or MOTOR 'names' should be present and - * registers are set from settings tables and flags related - * to the hardware capabilities. - * */ -static SANE_Status -gl646_setup_registers (Genesys_Device * dev, - Genesys_Register_Set * regs, - Genesys_Settings scan_settings, - uint16_t * slope_table1, - uint16_t * slope_table2, - SANE_Int resolution, - uint32_t move, - uint32_t linecnt, - uint16_t startx, - uint16_t endx, SANE_Bool color, - SANE_Int depth) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i, nb; - Sensor_Master *sensor = NULL; - Motor_Master *motor = NULL; - Sensor_Settings *settings = NULL; - Genesys_Register_Set *r; - unsigned int used1, used2, vfinal; - unsigned int bpp; /**> bytes per pixel */ - uint32_t z1, z2; - uint16_t ex, sx; - int channels = 1, stagger, words_per_line, max_shift; - size_t requested_buffer_size; - size_t read_buffer_size; - SANE_Bool half_ccd = SANE_FALSE; - SANE_Int xresolution; - int feedl; - - DBG (DBG_proc, "gl646_setup_registers: start\n"); - DBG (DBG_info, "gl646_setup_registers: startx=%d, endx=%d, linecnt=%d\n", - startx, endx, linecnt); - - /* x resolution is capped by sensor's capability */ - if (resolution > dev->sensor.optical_res) - { - xresolution = dev->sensor.optical_res; - } - else - { - xresolution = resolution; - } - - /* for the given resolution, search for master - * sensor mode setting */ - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - if (dev->model->ccd_type == sensor_master[i].sensor - && sensor_master[i].dpi == xresolution - && sensor_master[i].color == color) - { - sensor = &sensor_master[i]; - } - i++; - } - if (sensor == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for sensor %d at %d dpi color=%d\n", - dev->model->ccd_type, xresolution, color); - return SANE_STATUS_INVAL; - } - - /* for the given resolution, search for master - * motor mode setting */ - i = 0; - nb = sizeof (motor_master) / sizeof (Motor_Master); - while (i < nb) - { - if (dev->model->motor_type == motor_master[i].motor - && motor_master[i].dpi == resolution - && motor_master[i].color == color) - { - motor = &motor_master[i]; - } - i++; - } - if (motor == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for motor %d at %d dpi, color=%d\n", - dev->model->motor_type, resolution, color); - return SANE_STATUS_INVAL; - } - - /* now we can search for the specific sensor settings */ - i = 0; - nb = sizeof (sensor_settings) / sizeof (Sensor_Settings); - while (i < nb) - { - if (sensor->sensor == sensor_settings[i].sensor - && sensor->cksel == sensor_settings[i].cksel) - { - settings = &sensor_settings[i]; - } - i++; - } - if (settings == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for sensor %d with '%d' ccd timing\n", - sensor->sensor, sensor->cksel); - return SANE_STATUS_INVAL; - } - - /* half_ccd if manual clock programming or dpi is half dpiset */ - half_ccd = sensor->half_ccd; - - /* now apply values from settings to registers */ - if (sensor->regs_0x10_0x15 != NULL) - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = sensor->regs_0x10_0x15[i]; - } - } - else - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = 0; - } - } - - for (i = 0; i < 4; i++) - { - r = sanei_genesys_get_address (regs, 0x08 + i); - if (half_ccd == SANE_TRUE) - r->value = settings->manual_0x08_0x0b[i]; - else - r->value = settings->regs_0x08_0x0b[i]; - } - - for (i = 0; i < 8; i++) - { - r = sanei_genesys_get_address (regs, 0x16 + i); - r->value = settings->regs_0x16_0x1d[i]; - } - - for (i = 0; i < 13; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->regs_0x52_0x5e[i]; - } - if (half_ccd == SANE_TRUE) - { - for (i = 0; i < 7; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->manual_0x52_0x58[i]; - } - } - - /* now generate slope tables : we are not using generate_slope_table3 yet */ - sanei_genesys_generate_slope_table (slope_table1, motor->steps1, - motor->steps1 + 1, motor->vend1, - motor->vstart1, motor->vend1, - motor->steps1, motor->g1, &used1, - &vfinal); - sanei_genesys_generate_slope_table (slope_table2, motor->steps2, - motor->steps2 + 1, motor->vend2, - motor->vstart2, motor->vend2, - motor->steps2, motor->g2, &used2, - &vfinal); - - if (color == SANE_TRUE) - channels = 3; - else - channels = 1; - - /* R01 */ - /* now setup other registers for final scan (ie with shading enabled) */ - /* watch dog + shading + scan enable */ - regs[reg_0x01].value |= REG01_DOGENB | REG01_DVDSET | REG01_SCAN; - if (dev->model->is_cis == SANE_TRUE) - regs[reg_0x01].value |= REG01_CISSET; - else - regs[reg_0x01].value &= ~REG01_CISSET; - - /* if device has no calibration, don't enable shading correction */ - if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) - { - regs[reg_0x01].value &= ~REG01_DVDSET; - } - - regs[reg_0x01].value &= ~REG01_FASTMOD; - if (motor->fastmod) - regs[reg_0x01].value |= REG01_FASTMOD; - - /* R02 */ - /* allow moving when buffer full by default */ - if (dev->model->is_sheetfed == SANE_FALSE) - dev->reg[reg_0x02].value &= ~REG02_ACDCDIS; - else - dev->reg[reg_0x02].value |= REG02_ACDCDIS; - - /* setup motor power and direction */ - regs[reg_0x02].value |= REG02_MTRPWR; - regs[reg_0x02].value &= ~REG02_MTRREV; - - /* fastfed enabled (2 motor slope tables) */ - if (motor->fastfed) - regs[reg_0x02].value |= REG02_FASTFED; - else - regs[reg_0x02].value &= ~REG02_FASTFED; - - /* step type */ - regs[reg_0x02].value &= ~REG02_STEPSEL; - switch (motor->steptype) - { - case FULL_STEP: - break; - case HALF_STEP: - regs[reg_0x02].value |= 1; - break; - case QUATER_STEP: - regs[reg_0x02].value |= 2; - break; - default: - regs[reg_0x02].value |= 3; - break; - } - - /* if sheetfed, no AGOHOME */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - regs[reg_0x02].value &= ~REG02_AGOHOME; - } - else - { - regs[reg_0x02].value |= REG02_AGOHOME; - } - - /* R03 */ - regs[reg_0x03].value &= ~REG03_AVEENB; - /* regs[reg_0x03].value |= REG03_AVEENB; */ - regs[reg_0x03].value &= ~REG03_LAMPDOG; - - /* select XPA */ - regs[reg_0x03].value &= ~REG03_XPASEL; - if (scan_settings.scan_method == SCAN_METHOD_TRANSPARENCY) - { - regs[reg_0x03].value |= REG03_XPASEL; - } - - /* R04 */ - /* monochrome / color scan */ - switch (depth) - { - case 1: - regs[reg_0x04].value &= ~REG04_BITSET; - regs[reg_0x04].value |= REG04_LINEART; - break; - case 8: - regs[reg_0x04].value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - regs[reg_0x04].value &= ~REG04_LINEART; - regs[reg_0x04].value |= REG04_BITSET; - break; - } - - /* R05 */ - regs[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - regs[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - regs[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - regs[reg_0x05].value |= REG05_DPIHW_2400; - break; - default: - regs[reg_0x05].value |= REG05_DPIHW; - } - - /* gamma enable for scans */ - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - regs[reg_0x05].value |= REG05_GMM14BIT; - - regs[reg_0x05].value &= ~REG05_GMMENB; - - /* true CIS gray if needed */ - if (dev->model->is_cis == SANE_TRUE && color == SANE_FALSE - && dev->settings.true_gray) - { - regs[reg_0x05].value |= REG05_LEDADD; - } - else - { - regs[reg_0x05].value &= ~REG05_LEDADD; - } - - /* cktoggle, ckdelay and cksel at once, cktdelay=2 => half_ccd for md5345 */ - regs[reg_0x18].value = sensor->r18; - - /* manual CCD/2 clock programming => half_ccd for hp2300 */ - regs[reg_0x1d].value = sensor->r1d; - - /* HP2400 1200dpi mode tuning */ - - if (dev->model->ccd_type == CCD_HP2400) - { - /* reset count of dummy lines to zero */ - regs[reg_0x1e].value &= ~REG1E_LINESEL; - if (scan_settings.xres >= 1200) - { - /* there must be one dummy line */ - regs[reg_0x1e].value |= 1 & REG1E_LINESEL; - - /* GPO12 need to be set to zero */ - regs[reg_0x66].value &= ~0x20; - } - else - { - /* set GPO12 back to one */ - regs[reg_0x66].value |= 0x20; - } - } - - /* motor steps used */ - regs[reg_0x21].value = motor->steps1; - regs[reg_0x22].value = motor->fwdbwd; - regs[reg_0x23].value = motor->fwdbwd; - regs[reg_0x24].value = motor->steps1; - - /* scanned area height must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,scan_settings.yres,0); - - /* we adjust linecnt according to real motor dpi */ - linecnt = (linecnt * motor->ydpi) / scan_settings.yres + max_shift; - - /* at QUATER_STEP lines are 'staggered' and need correction */ - stagger = 0; - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - { - /* for HP3670, stagger happens only at >=1200 dpi */ - if ((dev->model->motor_type != MOTOR_HP3670 - && dev->model->motor_type != MOTOR_HP2400) - || scan_settings.yres >= dev->sensor.optical_res) - { - stagger = (4 * scan_settings.yres) / dev->motor.base_ydpi; - } - } - linecnt += stagger; - - DBG (DBG_info, "gl646_setup_registers : max_shift=%d, stagger=%d lines\n", - max_shift, stagger); - - /* CIS scanners read one line per color channel - * since gray mode use 'add' we also read 3 channels even not in - * color mode */ - if (dev->model->is_cis == SANE_TRUE) - { - gl646_set_triple_reg (regs, REG_LINCNT, linecnt * 3); - linecnt *= channels; - } - else - { - gl646_set_triple_reg (regs, REG_LINCNT, linecnt); - } - - /* scanner's x coordinates are expressed in physical DPI but they must be divided by cksel */ - sx = startx / sensor->cksel; - ex = endx / sensor->cksel; - if (half_ccd == SANE_TRUE) - { - sx /= 2; - ex /= 2; - } - gl646_set_double_reg (regs, REG_STRPIXEL, sx); - gl646_set_double_reg (regs, REG_ENDPIXEL, ex); - DBG (DBG_info, "gl646_setup_registers: startx=%d, endx=%d, half_ccd=%d\n", - sx, ex, half_ccd); - - /* words_per_line must be computed according to the scan's resolution */ - /* in fact, words_per_line _gives_ the actual scan resolution */ - words_per_line = (((endx - startx) * sensor->xdpi) / dev->sensor.optical_res); - bpp=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - bpp=1; - } - else - { - words_per_line *= bpp; - } - dev->bpl = words_per_line; - words_per_line *= channels; - dev->wpl = words_per_line; - - DBG (DBG_info, "gl646_setup_registers: wpl=%d\n", words_per_line); - gl646_set_triple_reg (regs, REG_MAXWD, words_per_line); - - gl646_set_double_reg (regs, REG_DPISET, sensor->dpiset); - gl646_set_double_reg (regs, REG_LPERIOD, sensor->exposure); - - /* move distance must be adjusted to take into account the extra lines - * read to reorder data */ - feedl = move; - if (stagger + max_shift > 0 && feedl != 0) - { - if (feedl > - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi) - feedl = - feedl - - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi; - } - - /* we assume all scans are done with 2 tables */ - /* - feedl = feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type); */ - /* but head has moved due to shading calibration => dev->scanhead_position_in_steps */ - if (feedl > 0) - { - /* take into account the distance moved during calibration */ - /* feedl -= dev->scanhead_position_in_steps; */ - DBG (DBG_info, "gl646_setup_registers: initial move=%d\n", feedl); - DBG (DBG_info, "gl646_setup_registers: scanhead_position_in_steps=%d\n", - dev->scanhead_position_in_steps); - - /* TODO clean up this when I'll fully understand. - * for now, special casing each motor */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - switch (motor->ydpi) - { - case 200: - feedl -= 70; - break; - case 300: - feedl -= 70; - break; - case 400: - feedl += 130; - break; - case 600: - feedl += 160; - break; - case 1200: - feedl += 160; - break; - case 2400: - feedl += 180; - break; - default: - break; - } - break; - case MOTOR_HP2300: - switch (motor->ydpi) - { - case 75: - feedl -= 180; - break; - case 150: - feedl += 0; - break; - case 300: - feedl += 30; - break; - case 600: - feedl += 35; - break; - case 1200: - feedl += 45; - break; - default: - break; - } - break; - case MOTOR_HP2400: - switch (motor->ydpi) - { - case 150: - feedl += 150; - break; - case 300: - feedl += 220; - break; - case 600: - feedl += 260; - break; - case 1200: - feedl += 280; /* 300 */ - break; - case 50: - feedl += 0; - break; - case 100: - feedl += 100; - break; - default: - break; - } - break; - - /* theorical value */ - default: - if (motor->fastfed) - { - feedl = - feedl - 2 * motor->steps2 - - (motor->steps1 >> motor->steptype); - } - else - { - feedl = feedl - (motor->steps1 >> motor->steptype); - } - break; - } - /* security */ - if (feedl < 0) - feedl = 0; - } - - DBG (DBG_info, "gl646_setup_registers: final move=%d\n", feedl); - gl646_set_triple_reg (regs, REG_FEEDL, feedl); - - regs[reg_0x65].value = motor->mtrpwm; - - sanei_genesys_calculate_zmode2 (regs[reg_0x02].value & REG02_FASTFED, - sensor->exposure, - slope_table1, - motor->steps1, - move, motor->fwdbwd, &z1, &z2); - - /* no z1/z2 for sheetfed scanners */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - z1 = 0; - z2 = 0; - } - gl646_set_double_reg (regs, REG_Z1MOD, z1); - gl646_set_double_reg (regs, REG_Z2MOD, z2); - regs[reg_0x6b].value = motor->steps2; - regs[reg_0x6c].value = - (regs[reg_0x6c].value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) - & 0x07); - - RIE (write_control (dev, xresolution)); - - /* setup analog frontend */ - RIE (gl646_set_fe (dev, AFE_SET, xresolution)); - - /* now we're done with registers setup values used by data transfer */ - /* we setup values needed for the data transfer */ - - /* we must use a round number of words_per_line */ - requested_buffer_size = 8 * words_per_line; - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * scan_settings.pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - 8 * scan_settings.pixels * channels * bpp)); - - /* scan bytes to read */ - dev->read_bytes_left = words_per_line * linecnt; - - DBG (DBG_info, - "gl646_setup_registers: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.pixels = - ((endx - startx) * sensor->xdpi) / dev->sensor.optical_res; - dev->current_setup.lines = linecnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = sensor->exposure; - dev->current_setup.xres = sensor->xdpi; - dev->current_setup.yres = motor->ydpi; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - /* total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((scan_settings.pixels * scan_settings.lines) / 8 + - (((scan_settings.pixels * scan_settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - scan_settings.pixels * scan_settings.lines * channels * bpp; - - DBG (DBG_proc, "gl646_setup_registers: end\n"); - return SANE_STATUS_GOOD; -} - - -/** copy sensor specific settings */ -/* *dev : device infos - *regs : regiters to be set - extended : do extended set up - half_ccd: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't - appear anywhere else but in register init -*/ -static void -gl646_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r; - int i; - - DBG (DBG_proc, "gl646_setup_sensor: start\n"); - for (i = 0; i < 4; i++) - { - r = sanei_genesys_get_address (regs, 0x08 + i); - r->value = dev->sensor.regs_0x08_0x0b[i]; - } - - for (i = 0; i < 14; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - - for (i = 0; i < 13; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = dev->sensor.regs_0x52_0x5e[i]; - } - DBG (DBG_proc, "gl646_setup_sensor: end\n"); - -} - -/** Test if the ASIC works - */ -static SANE_Status -gl646_asic_test (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val; - uint8_t *data; - uint8_t *verify_data; - size_t size, verify_size; - unsigned int i; - - DBG (DBG_proc, "gl646_asic_test: start\n"); - - /* set and read exposure time, compare if it's the same */ - status = sanei_genesys_write_register (dev, 0x38, 0xde); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x39, 0xad); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_register (dev, 0x4e, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xde) /* value of register 0x38 */ - { - DBG (DBG_error, "gl646_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - status = sanei_genesys_read_register (dev, 0x4f, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xad) /* value of register 0x39 */ - { - DBG (DBG_error, "gl646_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - /* ram test: */ - size = 0x40000; - verify_size = size + 0x80; - /* todo: looks like the read size must be a multiple of 128? - otherwise the read doesn't succeed the second time after the scanner has - been plugged in. Very strange. */ - - data = (uint8_t *) malloc (size); - if (!data) - { - DBG (DBG_error, "gl646_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - verify_data = (uint8_t *) malloc (verify_size); - if (!verify_data) - { - free (data); - DBG (DBG_error, "gl646_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - for (i = 0; i < (size - 1); i += 2) - { - data[i] = i / 512; - data[i + 1] = (i / 2) % 256; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = gl646_bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to bulk write data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = - gl646_bulk_read_data (dev, 0x45, (uint8_t *) verify_data, verify_size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to bulk read data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - /* i + 2 is needed as the changed address goes into effect only after one - data word is sent. */ - for (i = 0; i < size; i++) - { - if (verify_data[i + 2] != data[i]) - { - DBG (DBG_error, "gl646_asic_test: data verification error\n"); - free (data); - free (verify_data); - return SANE_STATUS_IO_ERROR; - } - } - - free (data); - free (verify_data); - - DBG (DBG_info, "gl646_asic_test: end\n"); - - return SANE_STATUS_GOOD; -} - -/* returns the max register bulk size */ -static int -gl646_bulk_full_size (void) -{ - return GENESYS_GL646_MAX_REGS; -} - -/** - * Set all registers to default values after init - * @param dev scannerr's device to set - */ -static void -gl646_init_regs (Genesys_Device * dev) -{ - int nr, addr; - - DBG (DBG_proc, "gl646_init_regs\n"); - - nr = 0; - memset (dev->reg, 0, GENESYS_MAX_REGS * sizeof (Genesys_Register_Set)); - - for (addr = 1; addr <= 0x0b; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x10; addr <= 0x29; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x52; addr <= 0x5e; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x60; addr <= 0x6d; addr++) - dev->reg[nr++].address = addr; - - dev->reg[reg_0x01].value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ - dev->reg[reg_0x02].value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg[reg_0x02].value |= 0x01; /* half-step */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - dev->reg[reg_0x02].value |= 0x01; /* half-step */ - break; - case MOTOR_XP200: - /* for this sheetfed scanner, no AGOHOME, nor backtracking */ - dev->reg[reg_0x02].value = 0x50; - break; - default: - break; - } - dev->reg[reg_0x03].value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg[reg_0x04].value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ - switch (dev->model->dac_type) - { - case DAC_AD_XP200: - dev->reg[reg_0x04].value = 0x12; - break; - default: - /* Wolfson frontend */ - dev->reg[reg_0x04].value = 0x13; - break; - } - - dev->reg[reg_0x05].value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - default: - dev->reg[reg_0x05].value |= REG05_DPIHW; - break; - } - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - dev->reg[reg_0x05].value |= REG05_GMM14BIT; - if (dev->model->dac_type == DAC_AD_XP200) - dev->reg[reg_0x05].value |= 0x01; /* 12 clocks/pixel */ - - if (dev->model->ccd_type == CCD_HP2300) - dev->reg[reg_0x06].value = 0x00; /* PWRBIT off, shading gain=4, normal AFE image capture */ - else - dev->reg[reg_0x06].value = 0x18; /* PWRBIT on, shading gain=8, normal AFE image capture */ - - - gl646_setup_sensor (dev, dev->reg); - - dev->reg[reg_0x1e].value = 0xf0; /* watch-dog time */ - - switch (dev->model->ccd_type) - { - case CCD_HP2300: - dev->reg[reg_0x1e].value = 0xf0; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CCD_HP2400: - dev->reg[reg_0x1e].value = 0x80; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CCD_HP3670: - dev->reg[reg_0x19].value = 0x2a; - dev->reg[reg_0x1e].value = 0x80; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CIS_XP200: - dev->reg[reg_0x1e].value = 0x10; - dev->reg[reg_0x1f].value = 0x01; - dev->reg[reg_0x20].value = 0x50; - break; - default: - dev->reg[reg_0x1f].value = 0x01; - dev->reg[reg_0x20].value = 0x50; - break; - } - - dev->reg[reg_0x21].value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ - dev->reg[reg_0x22].value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ - dev->reg[reg_0x23].value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ - dev->reg[reg_0x24].value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ - dev->reg[reg_0x25].value = 0x00; /* scan line numbers (7000) */ - dev->reg[reg_0x26].value = 0x00 /*0x1b */ ; - dev->reg[reg_0x27].value = 0xd4 /*0x58 */ ; - dev->reg[reg_0x28].value = 0x01; /* PWM duty for lamp control */ - dev->reg[reg_0x29].value = 0xff; - - dev->reg[reg_0x2c].value = 0x02; /* set resolution (600 DPI) */ - dev->reg[reg_0x2d].value = 0x58; - dev->reg[reg_0x2e].value = 0x78; /* set black&white threshold high level */ - dev->reg[reg_0x2f].value = 0x7f; /* set black&white threshold low level */ - - dev->reg[reg_0x30].value = 0x00; /* begin pixel position (16) */ - dev->reg[reg_0x31].value = dev->sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ - dev->reg[reg_0x32].value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ - dev->reg[reg_0x33].value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ - dev->reg[reg_0x34].value = dev->sensor.dummy_pixel; - dev->reg[reg_0x35].value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ - dev->reg[reg_0x36].value = 0x00 /*0x2a */ ; - dev->reg[reg_0x37].value = 0x00 /*0x30 */ ; - dev->reg[reg_0x38].value = HIBYTE (dev->settings.exposure_time) /*0x2a */ ; /* line period (exposure time = 11000 pixels) */ - dev->reg[reg_0x39].value = LOBYTE (dev->settings.exposure_time) /*0xf8 */ ; - dev->reg[reg_0x3d].value = 0x00; /* set feed steps number of motor move */ - dev->reg[reg_0x3e].value = 0x00; - dev->reg[reg_0x3f].value = 0x01 /*0x00 */ ; - - dev->reg[reg_0x60].value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ - dev->reg[reg_0x61].value = 0x00; /* (21h+22h)/LPeriod */ - dev->reg[reg_0x62].value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ - dev->reg[reg_0x63].value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ - dev->reg[reg_0x64].value = 0x00; /* motor PWM frequency */ - dev->reg[reg_0x65].value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg[reg_0x65].value = 0x02; /* PWM duty cycle for table one motor phase (63 = max) */ - dev->reg[reg_0x66].value = dev->gpo.value[0]; - dev->reg[reg_0x67].value = dev->gpo.value[1]; - dev->reg[reg_0x68].value = dev->gpo.enable[0]; - dev->reg[reg_0x69].value = dev->gpo.enable[1]; - - switch (dev->model->motor_type) - { - case MOTOR_HP2300: - case MOTOR_HP2400: - dev->reg[reg_0x6a].value = 0x7f; /* table two steps number for acc/dec */ - dev->reg[reg_0x6b].value = 0x78; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x7f; - break; - case MOTOR_5345: - dev->reg[reg_0x6a].value = 0x42; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0xff; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_XP200: - dev->reg[reg_0x6a].value = 0x7f; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0x08; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_HP3670: - dev->reg[reg_0x6a].value = 0x41; /* table two steps number for acc/dec */ - dev->reg[reg_0x6b].value = 0xc8; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x7f; - break; - default: - dev->reg[reg_0x6a].value = 0x40; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0xff; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - } - dev->reg[reg_0x6c].value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ -} - - -/* Send slope table for motor movement - slope_table in machine byte order -*/ -static SANE_Status -gl646_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - int dpihw; - int start_address; - SANE_Status status; - uint8_t *table; -#ifdef WORDS_BIGENDIAN - int i; -#endif - - DBG (DBG_proc, - "gl646_send_slope_table (table_nr = %d, steps = %d)=%d .. %d\n", - table_nr, steps, slope_table[0], slope_table[steps - 1]); - - dpihw = dev->reg[reg_0x05].value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x1f800; - else /* reserved */ - return SANE_STATUS_INVAL; - -#ifdef WORDS_BIGENDIAN - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } -#else - table = (uint8_t *) slope_table; -#endif - - status = - sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x100); - if (status != SANE_STATUS_GOOD) - { -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_error, - "gl646_send_slope_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_bulk_write_data (dev, 0x3c, (uint8_t *) table, steps * 2); - if (status != SANE_STATUS_GOOD) - { -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_error, - "gl646_send_slope_table: failed to send slope table: %s\n", - sane_strstatus (status)); - return status; - } - -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_proc, "gl646_send_slope_table: end\n"); - return status; -} - -/* Set values of Analog Device type frontend */ -static SANE_Status -gl646_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint16_t val; - - DBG (DBG_proc, "gl646_set_ad_fe(): start\n"); - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl646_set_ad_fe(): setting DAC %u\n", - dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - - /* write them to analog frontend */ - val = dev->frontend.reg[0]; - status = sanei_genesys_fe_write_data (dev, 0x00, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - val = dev->frontend.reg[1]; - status = sanei_genesys_fe_write_data (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg1: %s\n", - sane_strstatus (status)); - return status; - } - } - if (set == AFE_SET) - { - for (i = 0; i < 3; i++) - { - val = dev->frontend.gain[i]; - status = sanei_genesys_fe_write_data (dev, 0x02 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_ad_fe: failed to write gain %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - val = dev->frontend.offset[i]; - status = sanei_genesys_fe_write_data (dev, 0x05 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_ad_fe: failed to write offset %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - } - /* - if (set == AFE_POWER_SAVE) - { - status = - sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0] | 0x04); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - } */ - DBG (DBG_proc, "gl646_set_ad_fe(): end\n"); - - return status; -} - -/** set up analog frontend - * set up analog frontend - * @param dev device to set up - * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE - * @param dpi resolution of the scan since it affects settings - * @return SANE_STATUS_GOOD if evrithing OK - */ -static SANE_Status -gl646_wm_hp3670 (Genesys_Device * dev, uint8_t set, int dpi) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBGSTART; - switch (set) - { - case AFE_INIT: - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: reset failed: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); - RIE (sanei_genesys_write_register (dev, 0x50, 0x00)); - sanei_genesys_init_fe (dev); - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg2 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = gl646_gpio_output_enable (dev->dn, 0x07); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: failed to enable GPIO: %s\n", - sane_strstatus (status)); - return status; - } - break; - case AFE_POWER_SAVE: - status = sanei_genesys_fe_write_data (dev, 0x01, 0x06); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x06, 0x0f); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg6 failed: %s\n", - sane_strstatus (status)); - return status; - } - return status; - break; - default: /* AFE_SET */ - /* mode setup */ - i = dev->frontend.reg[3]; - if (dpi > dev->sensor.optical_res / 2) - { - /* fe_reg_0x03 must be 0x12 for 1200 dpi in DAC_WOLFSON_HP3670. - * DAC_WOLFSON_HP2400 in 1200 dpi mode works well with - * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ - i = 0x12; - } - status = sanei_genesys_fe_write_data (dev, 0x03, i); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg3 failed: %s\n", - sane_strstatus (status)); - return status; - } - /* offset and sign (or msb/lsb ?) */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, - dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_wm_hp3670: writing offset%d failed: %s\n", i, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x24 + i, dev->frontend.sign[i]); /* MSB/LSB ? */ - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing sign%d failed: %s\n", - i, sane_strstatus (status)); - return status; - } - } - - /* gain */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, - dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing gain%d failed: %s\n", - i, sane_strstatus (status)); - return status; - } - } - } - - DBGCOMPLETED; - return status; -} - -/** Set values of analog frontend - * @param dev device to set - * @param set action to execute - * @param dpi dpi to setup the AFE - * @return error or SANE_STATUS_GOOD */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_set_fe (Genesys_Device * dev, uint8_t set, int dpi) -{ - SANE_Status status; - int i; - uint8_t val; - - DBG (DBG_proc, "gl646_set_fe (%s,%d)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?", dpi); - - /* Analog Device type frontend */ - if ((dev->reg[reg_0x04].value & REG04_FESET) == 0x02) - return gl646_set_ad_fe (dev, set); - - /* Wolfson type frontend */ - if ((dev->reg[reg_0x04].value & REG04_FESET) != 0x03) - { - DBG (DBG_proc, "gl646_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - /* per frontend function to keep code clean */ - switch (dev->model->dac_type) - { - case DAC_WOLFSON_HP3670: - case DAC_WOLFSON_HP2400: - return gl646_wm_hp3670 (dev, set, dpi); - break; - default: - DBG (DBG_proc, "gl646_set_fe(): using old method\n"); - break; - } - - /* initialize analog frontend */ - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl646_set_fe(): setting DAC %u\n", - dev->model->dac_type); - sanei_genesys_init_fe (dev); - - /* reset only done on init */ - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: init fe failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* enable GPIO for some models */ - if (dev->model->ccd_type == CCD_HP2300) - { - val = 0x07; - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: failed to enable GPIO: %s\n", - sane_strstatus (status)); - return status; - } - } - return status; - } - - /* set fontend to power saving mode */ - if (set == AFE_POWER_SAVE) - { - status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing data failed: %s\n", - sane_strstatus (status)); - } - return status; - } - - /* here starts AFE_SET */ - /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ - /* if (dev->model->ccd_type != CCD_HP2300 - && dev->model->ccd_type != CCD_HP3670 - && dev->model->ccd_type != CCD_HP2400) */ - { - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg0 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg2 failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* start with reg3 */ - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[3]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg3 failed: %s\n", - sane_strstatus (status)); - return status; - } - - switch (dev->model->ccd_type) - { - default: - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x24 + i, - dev->frontend.sign[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing sign[%d] failed: %s\n", - i, sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, - dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing gain[%d] failed: %s\n", - i, sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, - dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: writing offset[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - break; - /* just can't have it to work .... - case CCD_HP2300: - case CCD_HP2400: - case CCD_HP3670: - - status = - sanei_genesys_fe_write_data (dev, 0x23, dev->frontend.offset[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: writing offset[1] failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing gain[1] failed: %s\n", - sane_strstatus (status)); - return status; - } - break; */ - } - - /* end with reg1 */ - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - - - DBG (DBG_proc, "gl646_set_fe: end\n"); - - return SANE_STATUS_GOOD; -} - -/** Set values of analog frontend - * this this the public interface, the gl646 as to use one more - * parameter to work effectively, hence the redirection - * @param dev device to set - * @param set action to execute - * @return error or SANE_STATUS_GOOD */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_public_set_fe (Genesys_Device * dev, uint8_t set) -{ - return gl646_set_fe (dev, set, dev->settings.yres); -} - -static void -gl646_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) | - REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) & - ~REG02_MTRPWR); - } -} - -static void -gl646_set_lamp_power (Genesys_Device * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - if (dev) - { - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set - (regs, 0x03) | REG03_LAMPPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set - (regs, 0x03) & ~REG03_LAMPPWR); - } - } -} - -/** - * enters or leaves power saving mode - * limited to AFE for now. - * @param dev scanner's device - * @param enable SANE_TRUE to enable power saving, SANE_FALSE to leave it - * @return allways SANE_STATUS_GOOD - */ -GENESYS_STATIC -SANE_Status -gl646_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - - DBGSTART; - DBG (DBG_info, "gl646_save_power: enable = %d\n", enable); - - if (enable) - { - /* gl646_set_fe (dev, AFE_POWER_SAVE); */ - } - else - { - gl646_set_fe (dev, AFE_INIT, 0); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl646_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg[6]; - int rate, exposure_time, tgtime, time; - - DBG (DBG_proc, "gl646_set_powersaving (delay = %d)\n", delay); - - local_reg[0].address = 0x01; - local_reg[0].value = sanei_genesys_read_reg_from_set (dev->reg, 0x01); /* disable fastmode */ - - local_reg[1].address = 0x03; - local_reg[1].value = sanei_genesys_read_reg_from_set (dev->reg, 0x03); /* Lamp power control */ - - local_reg[2].address = 0x05; - local_reg[2].value = sanei_genesys_read_reg_from_set (dev->reg, 0x05) & ~REG05_BASESEL; /* 24 clocks/pixel */ - - local_reg[3].address = 0x38; /* line period low */ - local_reg[3].value = 0x00; - - local_reg[4].address = 0x39; /* line period high */ - local_reg[4].value = 0x00; - - local_reg[5].address = 0x6c; /* period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE */ - local_reg[5].value = 0x00; - - if (!delay) - local_reg[1].value = local_reg[1].value & 0xf0; /* disable lampdog and set lamptime = 0 */ - else if (delay < 20) - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ - else - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ - - time = delay * 1000 * 60; /* -> msec */ - exposure_time = - (uint32_t) (time * 32000.0 / - (24.0 * 64.0 * (local_reg[1].value & REG03_LAMPTIM) * - 1024.0) + 0.5); - /* 32000 = system clock, 24 = clocks per pixel */ - rate = (exposure_time + 65536) / 65536; - if (rate > 4) - { - rate = 8; - tgtime = 3; - } - else if (rate > 2) - { - rate = 4; - tgtime = 2; - } - else if (rate > 1) - { - rate = 2; - tgtime = 1; - } - else - { - rate = 1; - tgtime = 0; - } - - local_reg[5].value |= tgtime << 6; - exposure_time /= rate; - - if (exposure_time > 65535) - exposure_time = 65535; - - local_reg[3].value = exposure_time / 256; /* highbyte */ - local_reg[4].value = exposure_time & 255; /* lowbyte */ - - status = gl646_bulk_write_register (dev, local_reg, - sizeof (local_reg) / - sizeof (local_reg[0])); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, - "gl646_set_powersaving: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - - DBG (DBG_proc, "gl646_set_powersaving: end\n"); - return status; -} - - -/** - * loads document into scanner - * currently only used by XP200 - * bit2 (0x04) of gpio is paper event (document in/out) on XP200 - * HOMESNR is set if no document in front of sensor, the sequence of events is - * paper event -> document is in the sheet feeder - * HOMESNR becomes 0 -> document reach sensor - * HOMESNR becomes 1 ->document left sensor - * paper event -> document is out - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_load_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set regs[11]; - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t val; - - DBG (DBG_proc, "gl646_load_document: start\n"); - - /* no need to load document is flatbed scanner */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - DBG (DBG_proc, "gl646_load_document: nothing to load\n"); - DBG (DBG_proc, "gl646_load_document: end\n"); - return SANE_STATUS_GOOD; - } - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - - /* HOMSNR is set if a document is inserted */ - if ((val & REG41_HOMESNR)) - { - /* if no document, waits for a paper event to start loading */ - /* with a 60 seconde minutes timeout */ - count = 0; - do - { - status = gl646_gpio_read (dev->dn, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_load_document: GPIO=0x%02x\n", val); - if ((val & 0x04) != 0x04) - { - DBG (DBG_warn, "gl646_load_document: no paper detected\n"); - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ - if (count == 300) - { - DBG (DBG_error, - "gl646_load_document: timeout waiting for document\n"); - return SANE_STATUS_NO_DOCS; - } - } - - /* set up to fast move before scan then move until document is detected */ - regs[0].address = 0x01; - regs[0].value = 0x90; - - /* AGOME, 2 slopes motor moving */ - regs[1].address = 0x02; - regs[1].value = 0x79; - - /* motor feeding steps to 0 */ - regs[2].address = 0x3d; - regs[2].value = 0; - regs[3].address = 0x3e; - regs[3].value = 0; - regs[4].address = 0x3f; - regs[4].value = 0; - - /* 50 fast moving steps */ - regs[5].address = 0x6b; - regs[5].value = 50; - - /* set GPO */ - regs[6].address = 0x66; - regs[6].value = 0x30; - - /* stesp NO */ - regs[7].address = 0x21; - regs[7].value = 4; - regs[8].address = 0x22; - regs[8].value = 1; - regs[9].address = 0x23; - regs[9].value = 1; - regs[10].address = 0x24; - regs[10].value = 4; - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 50, - 51, - 2400, - 6000, 2400, 50, 0.25, &used, &vfinal); -/* document loading: - * send regs - * start motor - * wait e1 status to become e0 - */ - status = gl646_send_slope_table (dev, 1, slope_table, 50); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to send slope table 1: %s\n", - sane_strstatus (status)); - return status; - } - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to start motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - count = 0; - do - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while ((val & REG41_MOTMFLG) && (count < 300)); - if (count == 300) - { - DBG (DBG_error, "gl646_load_document: can't load document\n"); - return SANE_STATUS_JAMMED; - } - - /* when loading OK, document is here */ - dev->document = SANE_TRUE; - - /* set up to idle */ - regs[1].value = 0x71; - regs[4].value = 1; - regs[5].value = 8; - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to bulk write idle registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl646_load_document: end\n"); - - return status; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl646_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val, gpio; - unsigned int bytes_left, lines; - - DBG (DBG_proc, "gl646_detect_document_end: start\n"); - - /* test for document presence */ - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - status = gl646_gpio_read (dev->dn, &gpio); - DBG (DBG_info, "gl646_detect_document_end: GPIO=0x%02x\n", gpio); - - /* detect document event. There one event when the document go in, - * then another when it leaves */ - if ((dev->document == SANE_TRUE) && (gpio & 0x04) - && (dev->total_bytes_read > 0)) - { - DBG (DBG_info, "gl646_detect_document_end: no more document\n"); - dev->document = SANE_FALSE; - - /* adjust number of bytes to read: - * total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - DBG (DBG_io, "gl646_detect_document_end: total_bytes_to_read=%lu\n", - (u_long) dev->total_bytes_to_read); - DBG (DBG_io, "gl646_detect_document_end: total_bytes_read =%lu\n", - (u_long) dev->total_bytes_read); - DBG (DBG_io, "gl646_detect_document_end: read_bytes_left =%lu\n", - (u_long) dev->read_bytes_left); - - /* amount of data available from scanner is what to scan */ - status = sanei_genesys_read_valid_words (dev, &bytes_left); - - /* we add the number of lines needed to read the last part of the document in */ - lines = - (SANE_UNFIX (dev->model->y_offset) * dev->current_setup.yres) / - MM_PER_INCH; - DBG (DBG_io, "gl646_detect_document_end: adding %d line to flush\n", - lines); - bytes_left += lines * dev->wpl; - if (dev->current_setup.depth > 8) - { - bytes_left = 2 * bytes_left; - } - if (dev->current_setup.channels > 1) - { - bytes_left = 3 * bytes_left; - } - if (bytes_left < dev->read_bytes_left) - { - dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; - dev->read_bytes_left = bytes_left; - } - DBG (DBG_io, "gl646_detect_document_end: total_bytes_to_read=%lu\n", - (u_long) dev->total_bytes_to_read); - DBG (DBG_io, "gl646_detect_document_end: total_bytes_read =%lu\n", - (u_long) dev->total_bytes_read); - DBG (DBG_io, "gl646_detect_document_end: read_bytes_left =%lu\n", - (u_long) dev->read_bytes_left); - } - DBG (DBG_proc, "gl646_detect_document_end: end\n"); - - return status; -} - -/** - * eject document from the feeder - * currently only used by XP200 - * TODO we currently rely on AGOHOME not being set for sheetfed scanners, - * maybe check this flag in eject to let the document being eject automaticaly - */ -static SANE_Status -gl646_eject_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set regs[11]; - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t gpio, state; - - DBG (DBG_proc, "gl646_eject_document: start\n"); - - /* at the end there will be noe more document */ - dev->document = SANE_FALSE; - - /* first check for document event */ - status = gl646_gpio_read (dev->dn, &gpio); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: GPIO=0x%02x\n", gpio); - - /* test status : paper event + HOMESNR -> no more doc ? */ - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: state=0x%02x\n", state); - if (DBG_LEVEL > DBG_info) - { - print_status (state); - } - - /* HOMSNR=0 if no document inserted */ - if ((state & REG41_HOMESNR) != 0) - { - dev->document = SANE_FALSE; - DBG (DBG_info, "gl646_eject_document: no more document to eject\n"); - DBG (DBG_proc, "gl646_eject_document: end\n"); - return status; - } - - /* there is a document inserted, eject it */ - status = sanei_genesys_write_register (dev, 0x01, 0xb0); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - /* wait for motor to stop */ - do - { - usleep (200000UL); - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - } - while (state & REG41_MOTMFLG); - - /* set up to fast move before scan then move until document is detected */ - regs[0].address = 0x01; - regs[0].value = 0xb0; - - /* AGOME, 2 slopes motor moving , eject 'backward' */ - regs[1].address = 0x02; - regs[1].value = 0x5d; - - /* motor feeding steps to 119880 */ - regs[2].address = 0x3d; - regs[2].value = 1; - regs[3].address = 0x3e; - regs[3].value = 0xd4; - regs[4].address = 0x3f; - regs[4].value = 0x48; - - /* 60 fast moving steps */ - regs[5].address = 0x6b; - regs[5].value = 60; - - /* set GPO */ - regs[6].address = 0x66; - regs[6].value = 0x30; - - /* stesp NO */ - regs[7].address = 0x21; - regs[7].value = 4; - regs[8].address = 0x22; - regs[8].value = 1; - regs[9].address = 0x23; - regs[9].value = 1; - regs[10].address = 0x24; - regs[10].value = 4; - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 60, - 61, - 1600, - 10000, 1600, 60, 0.25, &used, &vfinal); -/* document eject: - * send regs - * start motor - * wait c1 status to become c8 : HOMESNR and ~MOTFLAG - */ - status = gl646_send_slope_table (dev, 1, slope_table, 60); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to send slope table 1: %s\n", - sane_strstatus (status)); - return status; - } - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to start motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /* loop until paper sensor tells paper is out, and till motor is running */ - /* use a 30 timeout */ - count = 0; - do - { - status = sanei_genesys_get_status (dev, &state); - print_status (state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while (((state & REG41_HOMESNR) == 0) && (count < 150)); - - /* read GPIO on exit */ - status = gl646_gpio_read (dev->dn, &gpio); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: GPIO=0x%02x\n", gpio); - - DBG (DBG_proc, "gl646_eject_document: end\n"); - return status; -} - -/* Send the low-level scan command */ -static SANE_Status -gl646_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - Genesys_Register_Set local_reg[3]; - - DBG (DBG_proc, "gl646_begin_scan\n"); - - local_reg[0].address = 0x03; - local_reg[0].value = sanei_genesys_read_reg_from_set (reg, 0x03); - - local_reg[1].address = 0x01; - local_reg[1].value = sanei_genesys_read_reg_from_set (reg, 0x01) | REG01_SCAN; /* set scan bit */ - - local_reg[2].address = 0x0f; - if (start_motor) - local_reg[2].value = 0x01; - else - local_reg[2].value = 0x00; /* do not start motor yet */ - - status = gl646_bulk_write_register (dev, local_reg, - sizeof (local_reg) / - sizeof (local_reg[0])); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_begin_scan: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl646_begin_scan: end\n"); - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop, SANE_Bool eject) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i = 0; - uint8_t val, scanfsh = 0; - - DBG (DBG_proc, "end_scan (check_stop = %d, eject = %d)\n", check_stop, - eject); - - /* we need to compute scanfsh before cancelling scan */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (reg, 0x01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (reg, 0x01, val); - status = sanei_genesys_write_register (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to write register 01: %s\n", - sane_strstatus (status)); - return status; - } - - /* for sheetfed scanners, we may have to eject document */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - if (eject == SANE_TRUE && dev->document == SANE_TRUE) - { - status = gl646_eject_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "end_scan: failed to eject document\n"); - return status; - } - } - if (check_stop) - { - for (i = 0; i < 30; i++) /* do not wait longer than wait 3 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG (DBG_proc, "end_scan: scanfeed finished\n"); - break; /* leave for loop */ - } - - usleep (10000UL); /* sleep 100 ms */ - } - } - } - else /* flat bed scanners */ - { - if (check_stop) - { - for (i = 0; i < 300; i++) /* do not wait longer than wait 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG (DBG_proc, "end_scan: scanfeed finished\n"); - break; /* leave while loop */ - } - - if ((!(val & REG41_MOTMFLG)) && (val & REG41_HOMESNR)) - { - DBG (DBG_proc, "end_scan: head at home\n"); - break; /* leave while loop */ - } - - usleep (10000UL); /* sleep 100 ms */ - } - } - } - - DBG (DBG_proc, "end_scan: end (i=%u)\n", i); - - return status; -} - -/* Send the stop scan command */ -static SANE_Status -gl646_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - return end_scan (dev, reg, check_stop, SANE_FALSE); -} - -/** - * parks head - * @param dev scanner's device - * @param wait_until_home true if the function waits until head parked - */ -GENESYS_STATIC -SANE_Status -gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - SANE_Status status; - Genesys_Settings settings; - uint8_t val; - int i; - int loop = 0; - - DBG (DBG_proc, "gl646_slow_back_home: start , wait_until_home = %d\n", - wait_until_home); - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - dev->scanhead_position_in_steps = 0; - - if (val & REG41_HOMESNR) /* is sensor at home? */ - { - DBG (DBG_info, "gl646_slow_back_home: end since already at home\n"); - return SANE_STATUS_GOOD; - } - - /* stop motor if needed */ - if (val & REG41_MOTMFLG) - { - status = gl646_stop_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: failed to stop motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - usleep (200000UL); - } - - /* when scanhead is moving then wait until scanhead stops or timeout */ - DBG (DBG_info, "gl646_slow_back_home: ensuring that motor is off\n"); - val = REG41_MOTMFLG; - for (i = 400; i > 0 && (val & REG41_MOTMFLG); i--) /* do not wait longer than 40 seconds, count down to get i = 0 when busy */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: Failed to read home sensor & motor status: %s\n", - sane_strstatus (status)); - return status; - } - if (((val & (REG41_MOTMFLG | REG41_HOMESNR)) == REG41_HOMESNR)) /* at home and motor is off */ - { - DBG (DBG_info, - "gl646_slow_back_home: already at home and not moving\n"); - return SANE_STATUS_GOOD; - } - usleep (100 * 1000); /* sleep 100 ms (todo: fixed to really sleep 100 ms) */ - } - - if (!i) /* the loop counted down to 0, scanner still is busy */ - { - DBG (DBG_error, - "gl646_slow_back_home: motor is still on: device busy\n"); - return SANE_STATUS_DEVICE_BUSY; - } - - /* setup for a backward scan of 65535 steps, with no actual data reading */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = get_lowest_resolution (dev->model->ccd_type, SANE_FALSE); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = 1; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_TRUE, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to setup for scan: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ - dev->reg[reg_0x02].value |= REG02_MTRREV; - dev->reg[reg_0x01].value &= ~REG01_SCAN; - gl646_set_triple_reg (dev->reg, REG_FEEDL, 65535); - - /* sets frontend */ - status = gl646_set_fe (dev, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* write scan registers */ - status = gl646_bulk_write_register (dev, dev->reg, - sizeof (dev->reg) / - sizeof (dev->reg[0])); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, - "gl646_slow_back_home: failed to bulk write registers: %s\n", - sane_strstatus (status)); - - /* registers are restored to an iddl state, give up if no head to park */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - DBG (DBG_proc, "gl646_slow_back_home: end \n"); - return SANE_STATUS_GOOD; - } - - /* starts scan */ - status = gl646_begin_scan (dev, dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_slow_back_home: failed to begin scan: \n"); - return status; - } - - /* loop until head parked */ - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: Failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & 0x08) /* home sensor */ - { - DBG (DBG_info, "gl646_slow_back_home: reached home position\n"); - DBG (DBG_proc, "gl646_slow_back_home: end\n"); - usleep (500000); /* sleep 500 ms before returning */ - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl646_stop_motor (dev); - end_scan (dev, dev->reg, SANE_TRUE, SANE_FALSE); - DBG (DBG_error, - "gl646_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - - DBG (DBG_info, "gl646_slow_back_home: scanhead is still moving\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * Automatically set top-left edge of the scan area by scanning an - * area at 300 dpi from very top of scanner - * @param dev device stucture describing the scanner - * @return SANE_STATUS_GOOD in cas of success, else failure code - */ -static SANE_Status -gl646_search_start_position (Genesys_Device * dev) -{ - SANE_Status status; - unsigned char *data = NULL; - Genesys_Settings settings; - unsigned int resolution, x, y; - - DBG (DBG_proc, "gl646_search_start_position: start\n"); - - /* we scan at 300 dpi */ - resolution = get_closest_resolution (dev->model->ccd_type, 300, SANE_FALSE); - - /* fill settings for a gray level scan */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = dev->model->search_lines; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan the desired area */ - status = - simple_scan (dev, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, &data); - - /* process data if scan is OK */ - if (status == SANE_STATUS_GOOD) - { - /* handle stagger case : reorder gray data and thus loose some lines */ - if (dev->current_setup.stagger > 0) - { - DBG (DBG_proc, "gl646_search_start_position: 'un-staggering'\n"); - for (y = 0; y < settings.lines - dev->current_setup.stagger; y++) - { - /* one point out of 2 is 'unaligned' */ - for (x = 0; x < settings.pixels; x += 2) - { - data[y * settings.pixels + x] = - data[(y + dev->current_setup.stagger) * settings.pixels + - x]; - } - } - /* correct line number */ - settings.lines -= dev->current_setup.stagger; - } - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("search_position.pnm", - data, - settings.depth, - 1, settings.pixels, settings.lines); - } - } - else - { - DBG (DBG_error, "gl646_search_start_position: simple_scan failed\n"); - free (data); - DBGCOMPLETED; - return status; - } - - /* now search reference points on the data */ - status = - sanei_genesys_search_reference_point (dev, data, - dev->sensor.CCD_start_xoffset, - resolution, settings.pixels, - settings.lines); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - } - - free (data); - DBGCOMPLETED; - return status; -} - -/** - * internally overriden during effective calibration - * sets up register for coarse gain calibration - */ -static SANE_Status -gl646_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - DBG (DBG_proc, "gl646_init_regs_for_coarse_calibration\n"); - DBG (DBG_proc, "gl646_init_register_for_coarse_calibration: end\n"); - - /* to make compilers happy ... */ - if (!dev) - { - return SANE_STATUS_INVAL; - } - - return SANE_STATUS_GOOD; -} - - -/** - * init registers for shading calibration - * we assume that scanner's head is on an area suiting shading calibration. - * We scan a full scan width area by the shading line number for the device - * at either at full sensor's resolution or half depending upon half_ccd - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code - */ -static SANE_Status -gl646_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - /* 1: no half_ccd, 2: use half number of pixels */ - int half_ccd = 1; - int cksel = 1; - - DBG (DBG_proc, "gl646_init_register_for_shading: start\n"); - - /* when shading all (full width) line, we must adapt to half_ccd case */ - if (dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) - { - /* walk the master mode list to find if half_ccd */ - if (is_half_ccd (dev->model->ccd_type, dev->settings.xres, SANE_TRUE) == - SANE_TRUE) - { - half_ccd = 2; - } - } - - /* fill settings for scan : always a color scan */ - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = dev->settings.scan_mode; - if (dev->model->is_cis == SANE_FALSE) - { - settings.scan_mode = SCAN_MODE_COLOR; - } - settings.xres = dev->sensor.optical_res / half_ccd; - cksel = get_cksel (dev->model->ccd_type, dev->settings.xres, SANE_TRUE); - settings.xres = settings.xres / cksel; - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * settings.xres) / dev->sensor.optical_res; - dev->calib_lines = dev->model->shading_lines; - settings.lines = dev->calib_lines * (3 - half_ccd); - settings.depth = 16; - settings.color_filter = dev->settings.color_filter; - - settings.disable_interpolation = dev->settings.disable_interpolation; - settings.threshold = dev->settings.threshold; - settings.exposure_time = dev->settings.exposure_time; - settings.dynamic_lineart = SANE_FALSE; - - /* keep account of the movement for final scan move */ - dev->scanhead_position_in_steps += settings.lines; - - /* we don't want top offset, but we need right margin to be the same - * than the one for the final scan */ - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - - /* used when sending shading calibration data */ - dev->calib_pixels = settings.pixels; - dev->calib_channels = dev->current_setup.channels; - if (dev->model->is_cis == SANE_FALSE) - { - dev->calib_channels = 3; - } - - /* no shading */ - dev->reg[reg_0x01].value &= ~REG01_DVDSET; - dev->reg[reg_0x02].value |= REG02_ACDCDIS; /* ease backtracking */ - dev->reg[reg_0x02].value &= ~(REG02_FASTFED | REG02_AGOHOME); - dev->reg[reg_0x05].value &= ~REG05_GMMENB; - gl646_set_motor_power (dev->reg, SANE_FALSE); - - /* TODO another flag to setup regs ? */ - /* enforce needed LINCNT, getting rid of extra lines for color reordering */ - if (dev->model->is_cis == SANE_FALSE) - { - gl646_set_triple_reg (dev->reg, REG_LINCNT, dev->calib_lines); - } - else - { - gl646_set_triple_reg (dev->reg, REG_LINCNT, dev->calib_lines * 3); - } - - /* copy reg to calib_reg */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL646_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* this is an hack to make calibration cache working .... */ - /* if we don't do this, cache will be identified at the shading calibration - * dpi which is different from calibration one */ - dev->current_setup.xres = dev->settings.xres; - DBG (DBG_info, - "gl646_init_register_for_shading:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", - dev->settings.xres, dev->settings.yres); - - DBG (DBG_proc, "gl646_init_register_for_shading: end\n"); - return status; -} - - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - */ -static SANE_Status -gl646_init_regs_for_scan (Genesys_Device * dev) -{ - SANE_Status status; - - DBGSTART; - - /* park head after calibration if needed */ - if (dev->scanhead_position_in_steps > 0 - && dev->settings.scan_method == SCAN_METHOD_FLATBED) - { - RIE(gl646_slow_back_home (dev, SANE_TRUE)); - dev->scanhead_position_in_steps = 0; - } - - RIE(setup_for_scan (dev, dev->reg, dev->settings, SANE_FALSE, SANE_TRUE, SANE_TRUE)); - - /* gamma is only enabled at final scan time */ - if (dev->settings.depth < 16) - dev->reg[reg_0x05].value |= REG05_GMMENB; - - DBGCOMPLETED; - return status; -} - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - * @param dev scanner's device - * @param regs registers to set up - * @param settings settings of scan - * @param split SANE_TRUE if move to scan area is split from scan, SANE_FALSE is - * scan first moves to area - * @param xcorrection take x geometry correction into account (fixed and detected offsets) - * @param ycorrection take y geometry correction into account - */ -GENESYS_STATIC SANE_Status -setup_for_scan (Genesys_Device * dev, - Genesys_Register_Set *regs, - Genesys_Settings settings, - SANE_Bool split, - SANE_Bool xcorrection, - SANE_Bool ycorrection) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool color; - SANE_Int depth; - int channels; - uint16_t startx = 0, endx, pixels; - int move = 0; - - DBGSTART; - DBG (DBG_info, - "%s settings:\nResolution: %ux%uDPI\n" - "Lines : %u\nPixels : %u\nStartpos : %.3f/%.3f\nScan mode : %d\nScan method: %s\n\n", - __func__, - settings.xres, settings.yres, settings.lines, settings.pixels, - settings.tl_x, settings.tl_y, settings.scan_mode, - settings.scan_method == SCAN_METHOD_FLATBED ? "flatbed" : "XPA"); - - if (settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - { - channels = 3; - color = SANE_TRUE; - } - else - { - channels = 1; - color = SANE_FALSE; - } - - depth=settings.depth; - if (settings.scan_mode == SCAN_MODE_LINEART) - { - if (settings.dynamic_lineart == SANE_TRUE) - { - depth = 8; - } - else - { - /* XXX STEF XXX : why does the common layer never send depth=1 ? */ - depth = 1; - } - } - - /* compute distance to move */ - move = 0; - /* XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ - if (split == SANE_FALSE) - { - if (dev->model->is_sheetfed == SANE_FALSE) - { - if (ycorrection == SANE_TRUE) - { - move = - (SANE_UNFIX (dev->model->y_offset) * - dev->motor.optical_ydpi) / MM_PER_INCH; - } - - /* add tl_y to base movement */ - move += (settings.tl_y * dev->motor.optical_ydpi) / MM_PER_INCH; - - } - else - { - move += (settings.tl_y * dev->motor.optical_ydpi) / MM_PER_INCH; - } - - DBG (DBG_info, "%s: move=%d steps\n", __func__, move); - - /* security check */ - if (move < 0) - { - DBG (DBG_error, "%s: overriding negative move value %d\n", __func__, move); - move = 0; - } - } - DBG (DBG_info, "%s: move=%d steps\n", __func__, move); - - /* pixels are allways given at full CCD optical resolution */ - /* use detected left margin and fixed value */ - if (xcorrection == SANE_TRUE) - { - if (dev->sensor.CCD_start_xoffset > 0) - startx = dev->sensor.CCD_start_xoffset; - else - startx = dev->sensor.dummy_pixel; - if (settings.scan_method == SCAN_METHOD_FLATBED) - { - startx += - ((SANE_UNFIX (dev->model->x_offset) * dev->sensor.optical_res) / - MM_PER_INCH); - } - else - { - startx += - ((SANE_UNFIX (dev->model->x_offset_ta) * - dev->sensor.optical_res) / MM_PER_INCH); - } - } - else - { - /* startx cannot be below dummy pixel value */ - startx = dev->sensor.dummy_pixel; - } - - /* add x coordinates : expressed in sensor max dpi */ - startx += (settings.tl_x * dev->sensor.optical_res) / MM_PER_INCH; - - /* stagger works with odd start cordinates */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - startx |= 1; - - pixels = (settings.pixels * dev->sensor.optical_res) / settings.xres; - /* special requirement for 400 dpi on 1200 dpi sensors */ - if (settings.xres == 400) - { - pixels = (pixels / 6) * 6; - } - endx = startx + pixels; - - /* TODO check for pixel width overflow */ - - /* set up correct values for scan (gamma and shading enabled) */ - status = gl646_setup_registers (dev, - regs, - settings, - dev->slope_table0, - dev->slope_table1, - settings.xres, - move, - settings.lines, - startx, endx, color, - depth); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus (status)); - return status; - } - - /* now post-process values for register and options fine tuning */ - - /* select color filter based on settings */ - regs[reg_0x04].value &= ~REG04_FILTER; - if (channels == 1) - { - switch (settings.color_filter) - { - /* red */ - case 0: - regs[reg_0x04].value |= 0x04; - break; - /* green */ - case 1: - regs[reg_0x04].value |= 0x08; - break; - /* blue */ - case 2: - regs[reg_0x04].value |= 0x0c; - break; - default: - break; - } - } - - /* send computed slope tables */ - status = - gl646_send_slope_table (dev, 0, dev->slope_table0, - sanei_genesys_read_reg_from_set (regs, 0x21)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus (status)); - return status; - } - - status = - gl646_send_slope_table (dev, 1, dev->slope_table1, - sanei_genesys_read_reg_from_set (regs, 0x6b)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return status; -} - -/** - * this function sen gamm table to ASIC - */ -static SANE_Status -gl646_send_gamma_table (Genesys_Device * dev) -{ - int size; - int address; - SANE_Status status; - uint8_t *gamma; - int bits; - - DBGSTART; - - /* gamma table size */ - if (dev->reg[reg_0x05].value & REG05_GMMTYPE) - { - size = 16384; - bits = 14; - } - else - { - size = 4096; - bits = 12; - } - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - gamma = (uint8_t *) malloc (size * 2 * 3); - if (gamma==NULL) - { - return SANE_STATUS_NO_MEM; - } - - RIE(sanei_genesys_generate_gamma_buffer(dev, bits, size-1, size, gamma)); - - /* table address */ - switch (dev->reg[reg_0x05].value >> 6) - { - case 0: /* 600 dpi */ - address = 0x09000; - break; - case 1: /* 1200 dpi */ - address = 0x11000; - break; - case 2: /* 2400 dpi */ - address = 0x20000; - break; - default: - free (gamma); - return SANE_STATUS_INVAL; - } - - /* send address */ - status = sanei_genesys_set_buffer_address (dev, address); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl646_send_gamma_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - /* send data */ - status = gl646_bulk_write_data (dev, 0x3c, (uint8_t *) gamma, size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl646_send_gamma_table: failed to send gamma table: %s\n", - sane_strstatus (status)); - return status; - } - free (gamma); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief this function does the led calibration. - * this function does the led calibration by scanning one line of the calibration - * area below scanner's top on white strip. The scope of this function is - * currently limited to the XP200 - */ -static SANE_Status -gl646_led_calibration (Genesys_Device * dev) -{ - int total_size; - uint8_t *line; - unsigned int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - unsigned int channels; - int avg[3], avga, avge; - int turn; - char fn[20]; - uint16_t expr, expg, expb; - Genesys_Settings settings; - SANE_Int resolution; - - SANE_Bool acceptable = SANE_FALSE; - - DBG (DBG_proc, "gl646_led_calibration\n"); - if (!dev->model->is_cis) - { - DBG (DBG_proc, - "gl646_led_calibration: not a cis scanner, nothing to do...\n"); - return SANE_STATUS_GOOD; - } - - /* get led calibration resolution */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - settings.scan_mode = SCAN_MODE_COLOR; - channels = 3; - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_FALSE); - settings.scan_mode = SCAN_MODE_GRAY; - channels = 1; - } - - /* offset calibration is always done in color mode */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = 1; - settings.depth = 16; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* colors * bytes_per_color * scan lines */ - total_size = settings.pixels * channels * 2 * 1; - - line = malloc (total_size); - if (!line) - { - DBG (DBG_error, "gl646_led_calibration: failed to allocate %d bytes\n", - total_size); - return SANE_STATUS_NO_MEM; - } - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - - Sensor_Master uint8_t regs_0x10_0x15[6]; - */ - - expr = (dev->sensor.regs_0x10_0x1d[0] << 8) | dev->sensor.regs_0x10_0x1d[1]; - expg = (dev->sensor.regs_0x10_0x1d[2] << 8) | dev->sensor.regs_0x10_0x1d[3]; - expb = (dev->sensor.regs_0x10_0x1d[4] << 8) | dev->sensor.regs_0x10_0x1d[5]; - - turn = 0; - - do - { - - dev->sensor.regs_0x10_0x1d[0] = (expr >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = expr & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (expg >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = expg & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (expb >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = expb & 0xff; - - DBG (DBG_info, "gl646_led_calibration: starting first line reading\n"); - - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "gl646_led_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, - line, - 16, channels, settings.pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < settings.pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * settings.pixels + 1] * 256 + - line[i * 2 + j * 2 * settings.pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= settings.pixels; - } - - DBG (DBG_info, "gl646_led_calibration: average: " - "%d,%d,%d\n", avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * avga) / avg[2]; - - /* keep exposure time in a working window */ - avge = (expr + expg + expb) / 3; - if (avge > 0x2000) - { - expr = (expr * 0x2000) / avge; - expg = (expg * 0x2000) / avge; - expb = (expb * 0x2000) / avge; - } - if (avge < 0x400) - { - expr = (expr * 0x400) / avge; - expg = (expg * 0x400) / avge; - expb = (expb * 0x400) / avge; - } - } - - turn++; - - } - while (!acceptable && turn < 100); - - DBG (DBG_info, - "gl646_led_calibration: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", - expr, expg, expb); - - /* cleanup before return */ - free (line); - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 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, "dark_average: avg[%d] = %d\n", k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG (DBG_info, "dark_average: average = %d\n", average); - return average; -} - - -/** @brief calibration for AD frontend devices - * we do simple scan until all black_pixels are higher than 0, - * raising offset at each turn. - */ -static SANE_Status -ad_fe_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *line; - unsigned int channels; - char title[32]; - int pass = 0; - SANE_Int resolution; - Genesys_Settings settings; - unsigned int x, y, adr, min; - unsigned int bottom, black_pixels; - - DBG (DBG_proc, "ad_fe_offset_calibration: start\n"); - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - channels = 3; - black_pixels = - (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "ad_fe_offset_calibration: black_pixels=%d\n", black_pixels); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 1; - do - { - pass++; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "ad_fe_offset_calibration: failed to scan first line\n"); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", (int)bottom); - sanei_genesys_write_pnm_file (title, line, 8, channels, - settings.pixels, settings.lines); - } - - min = 0; - for (y = 0; y < settings.lines; y++) - { - for (x = 0; x < black_pixels; x++) - { - adr = (x + y * settings.pixels) * channels; - if (line[adr] > min) - min = line[adr]; - if (line[adr + 1] > min) - min = line[adr + 1]; - if (line[adr + 2] > min) - min = line[adr + 2]; - } - } - - free (line); - DBG (DBG_io2, "ad_fe_offset_calibration: pass=%d, min=%d\n", pass, min); - bottom++; - } - while (pass < 128 && min == 0); - if (pass == 128) - { - DBG (DBG_error, - "ad_fe_offset_calibration: failed to find correct offset\n"); - return SANE_STATUS_INVAL; - } - - DBG (DBG_info, "ad_fe_offset_calibration: offset=(%d,%d,%d)\n", - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - DBG (DBG_proc, "ad_fe_offset_calibration: end\n"); - return status; -} - -#define DARK_TARGET 8 -/** - * This function does the offset calibration by scanning one line of the calibration - * area below scanner's top. There is a black margin and the remaining is white. - * genesys_search_start() must have been called so that the offsets and margins - * are already known. - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code is failure -*/ -static SANE_Status -gl646_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line; - unsigned int channels; - char title[32]; - int pass = 0, avg; - SANE_Int resolution; - Genesys_Settings settings; - int topavg, bottomavg; - int top, bottom, black_pixels; - - /* Analog Device fronted have a different calibration */ - if (dev->model->dac_type == DAC_AD_XP200) - { - return ad_fe_offset_calibration (dev); - } - - DBG (DBG_proc, "gl646_offset_calibration: start\n"); - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - if (dev->settings.xres > dev->sensor.optical_res) - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->settings.xres, - SANE_TRUE); - } - channels = 3; - black_pixels = - (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "gl646_offset_calibration: black_pixels=%d\n", black_pixels); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain, but with offset from - * last calibration */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 90; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &first_line); - if (status != SANE_STATUS_GOOD) - { - free(first_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file (title, first_line, 8, channels, - settings.pixels, settings.lines); - } - bottomavg = - dark_average (first_line, settings.pixels, settings.lines, channels, - black_pixels); - free (first_line); - DBG (DBG_io2, "gl646_offset_calibration: bottom avg=%d\n", bottomavg); - - /* now top value */ - top = 231; - dev->frontend.offset[0] = top; - dev->frontend.offset[1] = top; - dev->frontend.offset[2] = top; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", top); - sanei_genesys_write_pnm_file (title, second_line, 8, channels, - settings.pixels, settings.lines); - } - topavg = - dark_average (second_line, settings.pixels, settings.lines, channels, - black_pixels); - free (second_line); - DBG (DBG_io2, "gl646_offset_calibration: top avg=%d\n", topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.offset[0] = (top + bottom) / 2; - dev->frontend.offset[1] = (top + bottom) / 2; - dev->frontend.offset[2] = (top + bottom) / 2; - - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", dev->frontend.offset[1]); - sanei_genesys_write_pnm_file (title, second_line, 8, channels, - settings.pixels, settings.lines); - } - - avg = - dark_average (second_line, settings.pixels, settings.lines, channels, - black_pixels); - DBG (DBG_info, "gl646_offset_calibration: avg=%d offset=%d\n", avg, - dev->frontend.offset[1]); - free (second_line); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.offset[1]; - } - else - { - bottomavg = avg; - bottom = dev->frontend.offset[1]; - } - } - - /* in case of debug do a final scan to get result */ - if (DBG_LEVEL >= DBG_data) - { - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan final line\n"); - return status; - } - sanei_genesys_write_pnm_file ("offset-final.pnm", second_line, 8, - channels, settings.pixels, - settings.lines); - free (second_line); - } - - DBG (DBG_info, "gl646_offset_calibration: offset=(%d,%d,%d)\n", - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - DBG (DBG_proc, "gl646_offset_calibration: end\n"); - return status; -} - -/** @brief gain calibration for Analog Device frontends - * Alternative coarse gain calibration - */ -static SANE_Status -ad_fe_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - uint8_t *line; - unsigned int i, channels, val; - unsigned int size, count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average; - Genesys_Settings settings; - char title[32]; - - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - resolution = get_closest_resolution (dev->model->ccd_type, dpi, SANE_TRUE); - channels = 3; - settings.scan_mode = SCAN_MODE_COLOR; - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - size = channels * settings.pixels * settings.lines; - - /* start gain value */ - dev->frontend.gain[0] = 1; - dev->frontend.gain[1] = 1; - dev->frontend.gain[2] = 1; - - average = 0; - pass = 0; - - /* loop until each channel raises to acceptable level */ - while ((average < dev->sensor.gain_white_ref) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "ad_fe_coarse_gain_calibration: failed to scan first line\n"); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "alternative_coarse%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file (title, line, 8, - channels, settings.pixels, - settings.lines); - } - pass++; - - /* computes white average */ - average = 0; - count = 0; - for (i = 0; i < size; i++) - { - val = line[i]; - average += val; - count++; - } - average = average / count; - - /* adjusts gain for the channel */ - if (average < dev->sensor.gain_white_ref) - dev->frontend.gain[0]++; - dev->frontend.gain[1] = dev->frontend.gain[0]; - dev->frontend.gain[2] = dev->frontend.gain[0]; - - DBG (DBG_proc, - "ad_fe_coarse_gain_calibration: average = %.2f, gain = %d\n", - average, dev->frontend.gain[0]); - free (line); - } - - DBG (DBG_info, "ad_fe_coarse_gain_calibration: gains=(%d,%d,%d)\n", - dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); - DBGCOMPLETED; - return status; -} - -/** - * Alternative coarse gain calibration - * this on uses the settings from offset_calibration. First scan moves so - * we can go to calibration area for XPA. - * @param dev device for scan - * @param dpi resolutnio to calibrate at - */ -static SANE_Status -gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - uint8_t *line; - unsigned int i, j, k, channels, val, maximum, idx; - unsigned int count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average[3]; - Genesys_Settings settings; - char title[32]; - - if (dev->model->ccd_type == CIS_XP200) - { - return ad_fe_coarse_gain_calibration (dev, dev->sensor.optical_res); - } - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - channels = 3; - - /* we are searching a sensor resolution */ - if (dpi > dev->sensor.optical_res) - { - resolution = dev->sensor.optical_res; - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->settings.xres, - SANE_TRUE); - } - - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_y = 0; - if (settings.scan_method == SCAN_METHOD_FLATBED) - { - settings.tl_x = 0; - settings.pixels = (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - } - else - { - settings.tl_x = SANE_UNFIX (dev->model->x_offset_ta); - settings.pixels = (SANE_UNFIX (dev->model->x_size_ta) * resolution) / MM_PER_INCH; - } - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* start gain value */ - dev->frontend.gain[0] = 1; - dev->frontend.gain[1] = 1; - dev->frontend.gain[2] = 1; - - if (channels > 1) - { - average[0] = 0; - average[1] = 0; - average[2] = 0; - idx = 0; - } - else - { - average[0] = 255; - average[1] = 255; - average[2] = 255; - idx = dev->settings.color_filter; - average[idx] = 0; - } - pass = 0; - - /* loop until each channel raises to acceptable level */ - while (((average[0] < dev->sensor.gain_white_ref) - || (average[1] < dev->sensor.gain_white_ref) - || (average[2] < dev->sensor.gain_white_ref)) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "coarse_gain%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file (title, line, 8, - channels, settings.pixels, - settings.lines); - } - pass++; - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (k = idx; k < idx + channels; k++) - { - /* we find the maximum white value, so we can deduce a threshold - to average white values */ - maximum = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - maximum = val; - } - } - - /* threshold */ - maximum *= 0.9; - - /* computes white average */ - average[k] = 0; - count = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - /* averaging only white points allow us not to care about dark margins */ - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - { - average[k] += val; - count++; - } - } - } - average[k] = average[k] / count; - - /* adjusts gain for the channel */ - if (average[k] < dev->sensor.gain_white_ref) - dev->frontend.gain[k]++; - - DBG (DBG_proc, - "%s: channel %d, average = %.2f, gain = %d\n", __func__, - k, average[k], dev->frontend.gain[k]); - } - free (line); - } - - if (channels < 3) - { - dev->frontend.gain[1] = dev->frontend.gain[0]; - dev->frontend.gain[2] = dev->frontend.gain[0]; - } - - DBG (DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, - dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); - DBGCOMPLETED; - return status; -} - -/** - * sets up the scanner's register for warming up. We scan 2 lines without moving. - * - */ -static SANE_Status -gl646_init_regs_for_warmup (Genesys_Device * dev, - Genesys_Register_Set * local_reg, - int *channels, int *total_size) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - int resolution, lines; - - DBG (DBG_proc, "gl646_init_regs_for_warmup: start\n"); - - sanei_genesys_init_fe (dev); - - resolution = get_closest_resolution (dev->model->ccd_type, 300, SANE_FALSE); - - /* set up for a half width 2 lines gray scan without moving */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = 2; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* setup for scan */ - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_init_regs_for_warmup: setup_for_scan failed (%s)\n", - sane_strstatus (status)); - return status; - } - - /* we are not going to move, so clear these bits */ - dev->reg[reg_0x02].value &= ~(REG02_FASTFED | REG02_AGOHOME); - - /* don't enable any correction for this scan */ - dev->reg[reg_0x01].value &= ~REG01_DVDSET; - - /* copy to local_reg */ - memcpy (local_reg, dev->reg, (GENESYS_GL646_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - - /* turn off motor during this scan */ - gl646_set_motor_power (local_reg, SANE_FALSE); - - /* returned value to higher level warmup function */ - *channels = 1; - lines = gl646_get_triple_reg (local_reg, REG_LINCNT) + 1; - *total_size = lines * settings.pixels; - - /* now registers are ok, write them to scanner */ - RIE (gl646_set_fe (dev, AFE_SET, settings.xres)); - RIE (gl646_bulk_write_register (dev, local_reg, GENESYS_GL646_MAX_REGS)); - - DBGCOMPLETED; - return status; -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -static SANE_Status -gl646_repark_head (Genesys_Device * dev) -{ - SANE_Status status; - Genesys_Settings settings; - unsigned int expected, steps; - - DBG (DBG_proc, "gl646_repark_head: start\n"); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = - get_closest_resolution (dev->model->ccd_type, 75, SANE_FALSE); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 5; - settings.pixels = 600; - settings.lines = 4; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = setup_for_scan (dev, dev->reg, settings, SANE_FALSE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to setup for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* TODO seems wrong ... no effective scan */ - dev->reg[reg_0x01].value &= ~REG01_SCAN; - - status = gl646_bulk_write_register (dev, dev->reg, GENESYS_GL646_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to send registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* start scan */ - status = gl646_begin_scan (dev, dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_repark_head: failed to begin scan: \n"); - return status; - } - - expected = gl646_get_triple_reg (dev->reg, REG_FEEDL); - do - { - usleep (100 * 1000); - status = sanei_genesys_read_feed_steps (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to read feed steps: %s\n", - sane_strstatus (status)); - return status; - } - } - while (steps < expected); - - /* toggle motor flag, put an huge step number and redo move backward */ - status = gl646_slow_back_home (dev, 1); - DBG (DBG_proc, "gl646_repark_head: end\n"); - return status; -} - -/* * - * initialize ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - * @param dev device description of the scanner to initailize - * @return SANE_STATUS_GOOD if success, error code if failure - */ -static SANE_Status -gl646_init (Genesys_Device * dev) -{ - SANE_Status status; - struct timeval tv; - uint8_t cold = 0, val = 0; - uint32_t addr = 0xdead; - int size, i; - size_t len; - - DBG_INIT (); - DBG (DBG_proc, "gl646_init: start\n"); - - /* to detect real power up condition, we write to REG41 - * with pwrbit set, then read it back. When scanner is cold (just replugged) - * PWRBIT will be set in the returned value - */ - RIE (sanei_genesys_get_status (dev, &cold)); - DBG (DBG_info, "gl646_init: status=0x%02x\n", cold); - cold = !(cold & REG41_PWRBIT); - if (cold) - { - DBG (DBG_info, "gl646_init: device is cold\n"); - } - else - { - DBG (DBG_info, "gl646_init: device is hot\n"); - } - - /* if scanning session hasn't been initialized, set it up */ - if (!dev->already_initialized) - { - dev->dark_average_data = NULL; - dev->white_average_data = NULL; - - dev->settings.color_filter = 1; /* green filter by default */ - gettimeofday (&tv, NULL); - dev->init_date = tv.tv_sec; - - switch (dev->model->motor_type) - { - /* set to 11111 to spot bugs, sanei_genesys_exposure_time should - have obsoleted this field */ - case MOTOR_5345: - dev->settings.exposure_time = 11111; - break; - - case MOTOR_ST24: - dev->settings.exposure_time = 11000; - break; - default: - dev->settings.exposure_time = 11000; - break; - } - - /* Set default values for registers */ - gl646_init_regs (dev); - - /* build default gamma tables */ - if (dev->reg[reg_0x05].value & REG05_GMMTYPE) - size = 16384; - else - size = 4096; - - for(i=0;i<3;i++) - { - if (dev->sensor.gamma_table[i] == NULL) - { - dev->sensor.gamma_table[i] = (uint16_t *) malloc (2 * size); - if (dev->sensor.gamma_table[i] == NULL) - { - DBG (DBG_error, "gl646_init: could not allocate memory for gamma table %d\n",i); - return SANE_STATUS_NO_MEM; - } - sanei_genesys_create_gamma_table (dev->sensor.gamma_table[i], - size, - size - 1, - size - 1, - dev->sensor.gamma[i]); - } - } - - /* Init shading data */ - RIE (sanei_genesys_init_shading_data (dev, dev->sensor.sensor_pixels)); - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, - (GENESYS_GL646_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - } - - /* execute physical unit init only if cold */ - if (cold) - { - DBG (DBG_info, "gl646_init: device is cold\n"); - val = 0x04; - RIE (sanei_usb_control_msg - (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_INIT, - INDEX, 1, &val)); - - /* ASIC reset */ - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - usleep (100000UL); /* sleep 100 ms */ - - /* Write initial registers */ - RIE (gl646_bulk_write_register (dev, dev->reg, GENESYS_GL646_MAX_REGS)); - - /* Test ASIC and RAM */ - if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) - { - RIE (gl646_asic_test (dev)); - } - - /* send gamma tables if needed */ - status = gl646_send_gamma_table (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_init: failed to send generic gamma tables: %s\n", - sane_strstatus (status)); - return status; - } - - /* Set powersaving (default = 15 minutes) */ - RIE (gl646_set_powersaving (dev, 15)); - } /* end if cold */ - - /* Set analog frontend */ - RIE (gl646_set_fe (dev, AFE_INIT, 0)); - - /* GPO enabling for XP200 */ - if (dev->model->ccd_type == CIS_XP200) - { - sanei_genesys_write_register (dev, 0x68, dev->gpo.enable[0]); - sanei_genesys_write_register (dev, 0x69, dev->gpo.enable[1]); - - /* enable GPIO */ - val = 6; - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO enable failed ... %s\n", - sane_strstatus (status)); - } - val = 0; - - /* writes 0 to GPIO */ - status = gl646_gpio_write (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO write failed ... %s\n", - sane_strstatus (status)); - } - - /* clear GPIO enable */ - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO disable failed ... %s\n", - sane_strstatus (status)); - } - sanei_genesys_write_register (dev, 0x66, 0x10); - sanei_genesys_write_register (dev, 0x66, 0x00); - sanei_genesys_write_register (dev, 0x66, 0x10); - } - - /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - if (dev->model->gpo_type != GPO_HP3670 - && dev->model->gpo_type != GPO_HP2400) - { - switch (dev->sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - } - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: failed to set up control address\n"); - return SANE_STATUS_INVAL; - } - sanei_usb_set_timeout (2 * 1000); - len = 6; - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - /* for some reason, read fails here for MD6471, HP2300 and XP200 - * one time out of 2 scanimage launches - */ - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "gl646_init: failed to read control\n"); - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "gl646_init: failed to read control\n"); - return SANE_STATUS_INVAL; - } - else - { - DBG (DBG_info, - "gl646_init: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - dev->control[0], dev->control[1], dev->control[2], - dev->control[3], dev->control[4], dev->control[5]); - } - sanei_usb_set_timeout (30 * 1000); - } - else - /* HP2400 and HP3670 case */ - { - dev->control[0] = 0x00; - dev->control[1] = 0x00; - dev->control[2] = 0x01; - dev->control[3] = 0x00; - dev->control[4] = 0x00; - dev->control[5] = 0x00; - } - - /* ensure head is correctly parked, and check lock */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - status = gl646_repark_head (dev); - if (status != SANE_STATUS_GOOD) - { - if (status == SANE_STATUS_INVAL) - { - DBG (DBG_error0, - "Your scanner is locked. Please move the lock switch " - "to the unlocked position\n"); -#ifdef SANE_STATUS_HW_LOCKED - return SANE_STATUS_HW_LOCKED; -#else - return SANE_STATUS_JAMMED; -#endif - } - else - DBG (DBG_error, - "gl646_init: gl646_repark_head failed: %s\n", - sane_strstatus (status)); - return status; - } - } - else - { - RIE (gl646_slow_back_home (dev, SANE_TRUE)); - } - } - - /* here session and device are initialized */ - dev->already_initialized = SANE_TRUE; - - DBG (DBG_proc, "gl646_init: end\n"); - return SANE_STATUS_GOOD; -} - -GENESYS_STATIC -SANE_Status -gl646_move_to_ta (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - if (simple_move (dev, SANE_UNFIX (dev->model->y_offset_calib_ta)) != - SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_move_to_ta: failed to move to calibration area\n"); - return status; - } - DBGCOMPLETED; - return status; -} - - -/** - * Does a simple scan: ie no line reordering and avanced data buffering and - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param settings parameters of the scan - * @param move SANE_TRUE if moving during scan - * @param forward SANE_TRUE if moving forward during scan - * @param shading SANE_TRUE to enable shading correction - * @param data pointer for the data - */ -GENESYS_STATIC SANE_Status -simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move, - SANE_Bool forward, SANE_Bool shading, unsigned char **data) -{ - SANE_Status status = SANE_STATUS_INVAL; - unsigned int size, lines, x, y, bpp; - SANE_Bool empty, split; - unsigned char *buffer; - int count; - uint8_t val; - - DBG (DBG_proc, "simple_scan: starting\n"); - DBG (DBG_io, "simple_scan: move=%d, forward=%d, shading=%d\n", move, - forward, shading); - - /* round up to multiple of 3 in case of CIS scanner */ - if (dev->model->is_cis == SANE_TRUE) - { - settings.lines = ((settings.lines + 2) / 3) * 3; - } - - /* setup for move then scan */ - if (move == SANE_TRUE && settings.tl_y > 0) - { - split = SANE_FALSE; - } - else - { - split = SANE_TRUE; - } - status = setup_for_scan (dev, dev->reg, settings, split, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "simple_scan: setup_for_scan failed (%s)\n", - sane_strstatus (status)); - return status; - } - - /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */ - if (dev->model->is_cis == SANE_TRUE) - { - lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) / 3; - } - else - { - lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) + 1; - } - size = lines * settings.pixels; - if (settings.depth == 16) - bpp = 2; - else - bpp = 1; - size *= bpp; - if (settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - size *= 3; - *data = malloc (size); - if (!*data) - { - DBG (DBG_error, - "simple_scan: failed to allocate %d bytes of memory\n", size); - return SANE_STATUS_NO_MEM; - } - DBG (DBG_io, "simple_scan: allocated %d bytes of memory for %d lines\n", - size, lines); - - /* put back real line number in settings */ - settings.lines = lines; - - /* initialize frontend */ - status = gl646_set_fe (dev, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to set frontend: %s\n", - sane_strstatus (status)); - return status; - } - - /* no shading correction and not watch dog for simple scan */ - dev->reg[reg_0x01].value &= ~(REG01_DVDSET | REG01_DOGENB); - if (shading == SANE_TRUE) - { - dev->reg[reg_0x01].value |= REG01_DVDSET; - } - - /* enable gamma table for the scan */ - dev->reg[reg_0x05].value |= REG05_GMMENB; - - /* one table movement for simple scan */ - dev->reg[reg_0x02].value &= ~REG02_FASTFED; - - if (move == SANE_FALSE) - { - /* clear motor power flag if no move */ - dev->reg[reg_0x02].value &= ~REG02_MTRPWR; - - /* no automatic go home if no movement */ - dev->reg[reg_0x02].value &= ~REG02_AGOHOME; - } - if (forward == SANE_FALSE) - { - dev->reg[reg_0x02].value |= REG02_MTRREV; - } - else - { - dev->reg[reg_0x02].value &= ~REG02_MTRREV; - } - - /* no automatic go home when using XPA */ - if (settings.scan_method == SCAN_METHOD_TRANSPARENCY) - { - dev->reg[reg_0x02].value &= ~REG02_AGOHOME; - } - - /* write scan registers */ - status = gl646_bulk_write_register (dev, dev->reg, - sizeof (dev->reg) / - sizeof (dev->reg[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "simple_scan: failed to bulk write registers: %s\n", - sane_strstatus (status)); - free (*data); - return status; - } - - /* starts scan */ - status = gl646_begin_scan (dev, dev->reg, move); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, "simple_scan: failed to begin scan: \n"); - return status; - } - - /* wait for buffers to be filled */ - count = 0; - do - { - usleep (10000UL); - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - RIE (sanei_genesys_test_buffer_empty (dev, &empty)); - count++; - } - while (empty && count < 1000); - if (count == 1000) - { - free (*data); - DBG (DBG_error, "simple_scan: failed toread data\n"); - return SANE_STATUS_IO_ERROR; - } - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, *data, size); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to read data: %s\n", sane_strstatus (status)); - return status; - } - - /* in case of CIS scanner, we must reorder data */ - if (dev->model->is_cis == SANE_TRUE - && settings.scan_mode == SCAN_MODE_COLOR) - { - /* alloc one line sized working buffer */ - buffer = (unsigned char *) malloc (settings.pixels * 3 * bpp); - if (buffer == NULL) - { - DBG (DBG_error, - "simple_scan: failed to allocate %d bytes of memory\n", - settings.pixels * 3); - return SANE_STATUS_NO_MEM; - } - - /* reorder one line of data and put it back to buffer */ - if (bpp == 1) - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 3] = (*data)[y * settings.pixels * 3 + x]; - buffer[x * 3 + 1] = - (*data)[y * settings.pixels * 3 + settings.pixels + x]; - buffer[x * 3 + 2] = - (*data)[y * settings.pixels * 3 + 2 * settings.pixels + - x]; - } - /* copy line back */ - memcpy ((*data) + settings.pixels * 3 * y, buffer, - settings.pixels * 3); - } - } - else - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 6] = (*data)[y * settings.pixels * 6 + x * 2]; - buffer[x * 6 + 1] = - (*data)[y * settings.pixels * 6 + x * 2 + 1]; - buffer[x * 6 + 2] = - (*data)[y * settings.pixels * 6 + 2 * settings.pixels + - x * 2]; - buffer[x * 6 + 3] = - (*data)[y * settings.pixels * 6 + 2 * settings.pixels + - x * 2 + 1]; - buffer[x * 6 + 4] = - (*data)[y * settings.pixels * 6 + 4 * settings.pixels + - x * 2]; - buffer[x * 6 + 5] = - (*data)[y * settings.pixels * 6 + 4 * settings.pixels + - x * 2 + 1]; - } - /* copy line back */ - memcpy ((*data) + settings.pixels * 6 * y, buffer, - settings.pixels * 6); - } - } - free (buffer); - } - - /* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */ - status = end_scan (dev, dev->reg, SANE_TRUE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to end scan: %s\n", sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "simple_scan: end\n"); - return status; -} - -/** - * Does a simple move of the given distance by doing a scan at lowest resolution - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param distance distance to move in MM - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -simple_move (Genesys_Device * dev, SANE_Int distance) -{ - SANE_Status status; - unsigned char *data = NULL; - Genesys_Settings settings; - - DBG (DBG_proc, "simple_move: %d mm\n", distance); - - /* TODO give a no AGOHOME flag */ - settings.scan_method = SCAN_METHOD_TRANSPARENCY; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = get_lowest_resolution (dev->model->ccd_type, SANE_TRUE); - settings.yres = settings.xres; - settings.tl_y = 0; - settings.tl_x = 0; - settings.pixels = - (dev->sensor.sensor_pixels * settings.xres) / dev->sensor.optical_res; - settings.lines = (distance * settings.xres) / MM_PER_INCH; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = simple_scan (dev, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, &data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "simple_move: simple_scan failed\n"); - } - - free (data); - DBGCOMPLETED - return status; -} - -/** - * update the status of the required sensor in the scanner session - * the last_val fileds are used to make events 'sticky' - */ -static SANE_Status -gl646_update_hardware_sensors (Genesys_Scanner * session) -{ - Genesys_Device *dev = session->dev; - uint8_t value; - SANE_Status status; - - /* do what is needed to get a new set of events, but try to not loose - any of them. - */ - status = gl646_gpio_read (dev->dn, &value); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_update_hardware_sensors: failed to read GPIO %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_io, "gl646_update_hardware_sensors: GPIO=0x%02x\n", value); - - /* scan button */ - if ((dev->model->buttons & GENESYS_HAS_SCAN_SW) - && session->val[OPT_SCAN_SW].b == session->last_val[OPT_SCAN_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_XP200: - session->val[OPT_SCAN_SW].b = ((value & 0x02) != 0); - break; - case GPO_5345: - session->val[OPT_SCAN_SW].b = (value == 0x16); - break; - case GPO_HP2300: - session->val[OPT_SCAN_SW].b = (value == 0x6c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_SCAN_SW].b = ((value & 0x20) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* email button */ - if ((dev->model->buttons & GENESYS_HAS_EMAIL_SW) - && session->val[OPT_EMAIL_SW].b == session->last_val[OPT_EMAIL_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_EMAIL_SW].b = (value == 0x12); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_EMAIL_SW].b = ((value & 0x08) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* copy button */ - if ((dev->model->buttons & GENESYS_HAS_COPY_SW) - && session->val[OPT_COPY_SW].b == session->last_val[OPT_COPY_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_COPY_SW].b = (value == 0x11); - break; - case GPO_HP2300: - session->val[OPT_COPY_SW].b = (value == 0x5c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_COPY_SW].b = ((value & 0x10) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* power button */ - if ((dev->model->buttons & GENESYS_HAS_POWER_SW) - && session->val[OPT_POWER_SW].b == session->last_val[OPT_POWER_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_POWER_SW].b = (value == 0x14); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* ocr button */ - if ((dev->model->buttons & GENESYS_HAS_OCR_SW) - && session->val[OPT_OCR_SW].b == session->last_val[OPT_OCR_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_OCR_SW].b = (value == 0x13); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* document detection */ - if ((dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) - && session->val[OPT_PAGE_LOADED_SW].b == - session->last_val[OPT_PAGE_LOADED_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_XP200: - session->val[OPT_PAGE_LOADED_SW].b = ((value & 0x04) != 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* XPA detection */ - if (dev->model->flags & GENESYS_FLAG_XPA) - { - switch (dev->model->gpo_type) - { - case GPO_HP3670: - case GPO_HP2400: - /* test if XPA is plugged-in */ - if ((value & 0x40) == 0) - { - DBG (DBG_io, "gl646_update_hardware_sensors: enabling XPA\n"); - session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; - } - else - { - DBG (DBG_io, "gl646_update_hardware_sensors: disabling XPA\n"); - session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; - } - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - return status; -} - - -static SANE_Status -write_control (Genesys_Device * dev, int resolution) -{ - SANE_Status status; - uint8_t control[4]; - uint32_t addr = 0xdead; - - /* 2300 does not write to 'control' */ - if (dev->model->motor_type == MOTOR_HP2300) - return SANE_STATUS_GOOD; - - /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - switch (dev->sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - default: - DBG (DBG_error, "write_control: failed to compute control address\n"); - return SANE_STATUS_INVAL; - } - - /* XP200 sets dpi, what other scanner put is unknown yet */ - switch (dev->model->motor_type) - { - case MOTOR_XP200: - /* we put scan's dpi, not motor one */ - control[0] = LOBYTE (resolution); - control[1] = HIBYTE (resolution); - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - case MOTOR_HP3670: - case MOTOR_HP2400: - case MOTOR_5345: - default: - control[0] = dev->control[2]; - control[1] = dev->control[3]; - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - } - - DBG (DBG_info, - "write_control: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", - control[0], control[1], control[2], control[3]); - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "write_control: failed to set up control address\n"); - return SANE_STATUS_INVAL; - } - status = gl646_bulk_write_data (dev, 0x3c, control, 4); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "write_control: failed to set up control\n"); - return SANE_STATUS_INVAL; - } - return status; -} - -/** - * check if a stored calibration is compatible with requested scan. - * @return SANE_STATUS_GOOD if compatible, SANE_STATUS_UNSUPPORTED if not. - * Whenever an error is met, it is returned. - * @param dev scanner device - * @param cache cache entry to test - * @param for_overwrite reserved for future use ... - */ -static SANE_Status -gl646_is_compatible_calibration (Genesys_Device * dev, - Genesys_Calibration_Cache * cache, - int for_overwrite) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - int compatible = 1; - - DBG (DBG_proc, - "gl646_is_compatible_calibration: start (for_overwrite=%d)\n", - for_overwrite); - - if (cache == NULL) - return SANE_STATUS_UNSUPPORTED; - - /* build minimal current_setup for calibration cache use only, it will be better - * computed when during setup for scan - */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - { - dev->current_setup.channels = 3; - } - else - { - dev->current_setup.channels = 1; - } - dev->current_setup.xres = dev->settings.xres; - dev->current_setup.scan_method = dev->settings.scan_method; - - DBG (DBG_io, - "gl646_is_compatible_calibration: requested=(%d,%f), tested=(%d,%f)\n", - dev->current_setup.channels, dev->current_setup.xres, - cache->used_setup.channels, cache->used_setup.xres); - - /* a calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria */ - if (dev->model->is_cis == SANE_FALSE) - { - compatible = - ((dev->current_setup.channels == cache->used_setup.channels) - && (((int) dev->current_setup.xres) == - ((int) cache->used_setup.xres))); - } - else - { - compatible = - (dev->current_setup.channels == cache->used_setup.channels); - } - if (dev->current_setup.scan_method != cache->used_setup.scan_method) - { - DBG (DBG_io, - "gl646_is_compatible_calibration: current method=%d, used=%d\n", - dev->current_setup.scan_method, cache->used_setup.scan_method); - compatible = 0; - } - if (!compatible) - { - DBG (DBG_proc, - "gl646_is_compatible_calibration: completed, non compatible cache\n"); - return SANE_STATUS_UNSUPPORTED; - } - - /* a cache entry expires after 30 minutes for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > 30 * 60) - && (dev->model->is_sheetfed == SANE_FALSE)) - { - DBG (DBG_proc, - "gl646_is_compatible_calibration: expired entry, non compatible cache\n"); - return SANE_STATUS_UNSUPPORTED; - } - } -#endif - - DBG (DBG_proc, - "gl646_is_compatible_calibration: completed, cache compatible\n"); - return SANE_STATUS_GOOD; -} - -/** - * search for a full width black or white strip. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl646_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool half_ccd = SANE_FALSE; - Genesys_Settings settings; - int res = get_closest_resolution (dev->model->ccd_type, 75, SANE_FALSE); - unsigned char *data = NULL; - unsigned int pass, count, found, x, y; - char title[80]; - - DBG (DBG_proc, "gl646_search_strip: start\n"); - /* adapt to half_ccd case */ - if (dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) - { - /* walk the master mode list to find if half_ccd */ - if (is_half_ccd (dev->model->ccd_type, res, SANE_TRUE) == SANE_TRUE) - { - half_ccd = SANE_TRUE; - } - } - - /* we set up for a lowest available resolution color grey scan, full width */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = res; - settings.yres = res; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = (SANE_UNFIX (dev->model->x_size) * res) / MM_PER_INCH; - if (half_ccd == SANE_TRUE) - { - settings.pixels /= 2; - } - - /* 15 mm at at time */ - settings.lines = (15 * settings.yres) / MM_PER_INCH; /* may become a parameter from genesys_devices.c */ - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* signals if a strip of the given color has been found */ - found = 0; - - /* detection pass done */ - pass = 0; - - /* loop until strip is found or maximum pass number done */ - while (pass < 20 && !found) - { - /* scan a full width strip */ - status = - simple_scan (dev, settings, SANE_TRUE, forward, SANE_FALSE, &data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_search_strip: simple_scan failed\n"); - free (data); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", - (int)pass); - sanei_genesys_write_pnm_file (title, data, settings.depth, 1, - settings.pixels, settings.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 < settings.lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.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) / settings.pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl646_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, "gl646_search_strip: pixels=%d, count=%d\n", - settings.pixels, count); - } - } - } - 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 < settings.lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 60) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.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) / (settings.pixels * settings.lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl646_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, "gl646_search_strip: pixels=%d, count=%d\n", - settings.pixels, count); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl646_search_strip: strip found\n"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl646_search_strip: strip not found\n"); - } - return status; -} - -/** the gl646 command set */ -static Genesys_Command_Set gl646_cmd_set = { - "gl646-generic", /* the name of this set */ - - gl646_init, - gl646_init_regs_for_warmup, - gl646_init_regs_for_coarse_calibration, - gl646_init_regs_for_shading, - gl646_init_regs_for_scan, - - gl646_get_filter_bit, - gl646_get_lineart_bit, - gl646_get_bitset_bit, - gl646_get_gain4_bit, - gl646_get_fast_feed_bit, - gl646_test_buffer_empty_bit, - gl646_test_motor_flag_bit, - - gl646_bulk_full_size, - - gl646_public_set_fe, - gl646_set_powersaving, - gl646_save_power, - gl646_set_motor_power, - gl646_set_lamp_power, - - gl646_begin_scan, - gl646_end_scan, - - gl646_send_gamma_table, - - gl646_search_start_position, - - gl646_offset_calibration, - gl646_coarse_gain_calibration, - gl646_led_calibration, - - gl646_slow_back_home, - NULL, - - gl646_bulk_write_register, - gl646_bulk_write_data, - gl646_bulk_read_data, - - gl646_update_hardware_sensors, - - /* sheetfed related functions */ - gl646_load_document, - gl646_detect_document_end, - gl646_eject_document, - gl646_search_strip, - - gl646_is_compatible_calibration, - gl646_move_to_ta, - NULL, - NULL, - NULL, - NULL -}; - -SANE_Status -sanei_gl646_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl646_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ |