summaryrefslogtreecommitdiff
path: root/backend/hp3900_rts8822.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/hp3900_rts8822.c')
-rw-r--r--backend/hp3900_rts8822.c15123
1 files changed, 15123 insertions, 0 deletions
diff --git a/backend/hp3900_rts8822.c b/backend/hp3900_rts8822.c
new file mode 100644
index 0000000..9c8deaa
--- /dev/null
+++ b/backend/hp3900_rts8822.c
@@ -0,0 +1,15123 @@
+/* HP Scanjet 3900 series - RTS8822 Core
+
+ Copyright (C) 2005-2013 Jonathan Bravo Lopez <jkdsoft@gmail.com>
+
+ 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.
+*/
+
+
+/*
+ This code is still a bit ugly due to it's the result of applying
+ reverse engineering techniques to windows driver. So at this
+ moment what you see is exactly what windows driver does.
+ And so many global vars exist that will be erased when driver
+ is entirely debugged. There are some variables with unknown
+ purpose. So they have no meaning name in form v+address. I
+ hope to change their names when driver is debugged completely.
+*/
+
+#ifndef RTS8822_CORE
+
+#define RTS8822_CORE
+
+#define GetTickCount() (time(0) * 1000)
+#define min(A,B) (((A)<(B)) ? (A) : (B))
+#define max(A,B) (((A)>(B)) ? (A) : (B))
+#define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_))
+#define MM_TO_PIXEL(_mm_, _dpi_) ((_mm_) * (_dpi_) / 25.4)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* bzero() */
+#include <time.h> /* clock() */
+#include <math.h> /* truncf() */
+#include <ctype.h> /* tolower() */
+#include <unistd.h> /* usleep() */
+#include <sys/types.h>
+
+#include "hp3900_types.c"
+#include "hp3900_debug.c"
+#include "hp3900_config.c"
+#include "hp3900_usb.c"
+
+/*-------------------- Exported function headers --------------------*/
+
+#ifdef developing
+static SANE_Int hp4370_prueba (struct st_device *dev);
+static void prueba (SANE_Byte * a);
+void shadingtest1 (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib);
+static SANE_Int Calib_test (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ struct st_scanparams *scancfg);
+static SANE_Int Calib_BlackShading_jkd (struct st_device *dev,
+ SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ struct st_scanparams *scancfg);
+#endif
+
+/*static void show_diff(struct st_device *dev, SANE_Byte *original);*/
+
+/* functions to allocate and free space for a device */
+static struct st_device *RTS_Alloc (void);
+static void RTS_Free (struct st_device *dev);
+
+/* Scanner level commands */
+static SANE_Int RTS_Scanner_Init (struct st_device *dev);
+static SANE_Int RTS_Scanner_SetParams (struct st_device *dev,
+ struct params *param);
+static SANE_Int RTS_Scanner_StartScan (struct st_device *dev);
+static void RTS_Scanner_StopScan (struct st_device *dev, SANE_Int wait);
+static void RTS_Scanner_End (struct st_device *dev);
+
+/* loading configuration functions */
+static SANE_Int Load_Buttons (struct st_device *dev);
+static SANE_Int Load_Chipset (struct st_device *dev);
+static SANE_Int Load_Config (struct st_device *dev);
+static SANE_Int Load_Constrains (struct st_device *dev);
+static SANE_Int Load_Motor (struct st_device *dev);
+static SANE_Int Load_MotorCurves (struct st_device *dev);
+static SANE_Int Load_Motormoves (struct st_device *dev);
+static SANE_Int Load_Scanmodes (struct st_device *dev);
+static SANE_Int Load_Sensor (struct st_device *dev);
+static SANE_Int Load_Timings (struct st_device *dev);
+
+/* freeing configuration functions */
+static void Free_Buttons (struct st_device *dev);
+static void Free_Chipset (struct st_device *dev);
+static void Free_Config (struct st_device *dev);
+static void Free_Constrains (struct st_device *dev);
+static void Free_Motor (struct st_device *dev);
+static void Free_MotorCurves (struct st_device *dev);
+static void Free_Motormoves (struct st_device *dev);
+static void Free_Scanmodes (struct st_device *dev);
+static void Free_Sensor (struct st_device *dev);
+static void Free_Timings (struct st_device *dev);
+static void Free_Vars (void);
+
+/* Functions to manage data */
+static SANE_Byte data_bitget (SANE_Byte * address, SANE_Int mask);
+static void data_bitset (SANE_Byte * address, SANE_Int mask, SANE_Byte data);
+static SANE_Int data_lsb_get (SANE_Byte * address, SANE_Int size);
+static void data_lsb_set (SANE_Byte * address, SANE_Int data, SANE_Int size);
+static void data_msb_set (SANE_Byte * address, SANE_Int data, SANE_Int size);
+static void data_wide_bitset (SANE_Byte * address, SANE_Int mask,
+ SANE_Int data);
+static SANE_Int data_swap_endianess (SANE_Int address, SANE_Int size);
+
+static SANE_Int Device_get (SANE_Int product, SANE_Int vendor);
+
+/* Chipset related commands */
+static SANE_Int Chipset_ID (struct st_device *dev);
+static SANE_Int Chipset_Name (struct st_device *dev, char *name,
+ SANE_Int size);
+static SANE_Int Chipset_Reset (struct st_device *dev);
+
+/* Initializing functions */
+static SANE_Int Init_Registers (struct st_device *dev);
+static SANE_Int Init_USBData (struct st_device *dev);
+static SANE_Int Init_Vars (void);
+
+/* scanmode functions */
+static SANE_Int Scanmode_fitres (struct st_device *dev, SANE_Int scantype,
+ SANE_Int colormode, SANE_Int resolution);
+static SANE_Int Scanmode_maxres (struct st_device *dev, SANE_Int scantype,
+ SANE_Int colormode);
+static SANE_Int Scanmode_minres (struct st_device *dev, SANE_Int scantype,
+ SANE_Int colormode);
+
+/* Chipset management useful commands*/
+static SANE_Int RTS_USBType (struct st_device *dev);
+static SANE_Byte RTS_Sensor_Type (USB_Handle usb_handle);
+static void RTS_DebugInit (void);
+static SANE_Int RTS_Enable_CCD (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int channels);
+
+/* DMA management commands */
+static SANE_Int RTS_DMA_Cancel (struct st_device *dev);
+static SANE_Int RTS_DMA_CheckType (struct st_device *dev, SANE_Byte * Regs);
+static SANE_Int RTS_DMA_Enable_Read (struct st_device *dev, SANE_Int dmacs,
+ SANE_Int size, SANE_Int options);
+static SANE_Int RTS_DMA_Enable_Write (struct st_device *dev, SANE_Int dmacs,
+ SANE_Int size, SANE_Int options);
+static SANE_Int RTS_DMA_Read (struct st_device *dev, SANE_Int dmacs,
+ SANE_Int options, SANE_Int size,
+ SANE_Byte * buffer);
+static SANE_Int RTS_DMA_Reset (struct st_device *dev);
+static SANE_Int RTS_DMA_SetType (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Byte ramtype);
+static SANE_Int RTS_DMA_WaitReady (struct st_device *dev, SANE_Int msecs);
+static SANE_Int RTS_DMA_Write (struct st_device *dev, SANE_Int dmacs,
+ SANE_Int options, SANE_Int size,
+ SANE_Byte * buffer);
+
+/* EEPROM management commands */
+static SANE_Int RTS_EEPROM_ReadByte (USB_Handle usb_handle, SANE_Int address,
+ SANE_Byte * data);
+static SANE_Int RTS_EEPROM_ReadInteger (USB_Handle usb_handle,
+ SANE_Int address, SANE_Int * data);
+static SANE_Int RTS_EEPROM_ReadWord (USB_Handle usb_handle, SANE_Int address,
+ SANE_Int * data);
+static SANE_Int RTS_EEPROM_WriteBuffer (USB_Handle usb_handle,
+ SANE_Int address, SANE_Byte * data,
+ SANE_Int size);
+static SANE_Int RTS_EEPROM_WriteByte (USB_Handle usb_handle, SANE_Int address,
+ SANE_Byte data);
+static SANE_Int RTS_EEPROM_WriteInteger (USB_Handle usb_handle,
+ SANE_Int address, SANE_Int data);
+static SANE_Int RTS_EEPROM_WriteWord (USB_Handle usb_handle, SANE_Int address,
+ SANE_Int data);
+
+static SANE_Int RTS_Execute (struct st_device *dev);
+static SANE_Int RTS_Warm_Reset (struct st_device *dev);
+static SANE_Byte RTS_IsExecuting (struct st_device *dev, SANE_Byte * Regs);
+
+static SANE_Int RTS_GetScanmode (struct st_device *dev, SANE_Int scantype,
+ SANE_Int colormode, SANE_Int resolution);
+static SANE_Int RTS_GetImage (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_gain_offset *gain_offset,
+ SANE_Byte * buffer,
+ struct st_calibration *myCalib,
+ SANE_Int options, SANE_Int gainmode);
+static SANE_Int RTS_GetImage_GetBuffer (struct st_device *dev, double dSize,
+ SANE_Byte * buffer,
+ double *transferred);
+static SANE_Int RTS_GetImage_Read (struct st_device *dev, SANE_Byte * buffer,
+ struct st_scanparams *myvar,
+ struct st_hwdconfig *hwdcfg);
+
+static SANE_Int RTS_isTmaAttached (struct st_device *dev);
+
+/* functions to wait for a process tp finish */
+static SANE_Int RTS_WaitInitEnd (struct st_device *dev, SANE_Int msecs);
+static SANE_Int RTS_WaitScanEnd (struct st_device *dev, SANE_Int msecs);
+
+/* functions to read/write control registers */
+static SANE_Int RTS_ReadRegs (USB_Handle usb_handle, SANE_Byte * buffer);
+static SANE_Int RTS_WriteRegs (USB_Handle usb_handle, SANE_Byte * buffer);
+
+/* functions to manage the scan counter */
+static SANE_Int RTS_ScanCounter_Inc (struct st_device *dev);
+static SANE_Int RTS_ScanCounter_Get (struct st_device *dev);
+
+/* functions to setup control registers */
+static SANE_Int RTS_Setup (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *myvar,
+ struct st_hwdconfig *hwdcfg,
+ struct st_gain_offset *gain_offset);
+static void RTS_Setup_Arrangeline (struct st_device *dev,
+ struct st_hwdconfig *hwdcfg,
+ SANE_Int colormode);
+static void RTS_Setup_Channels (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ SANE_Int mycolormode);
+static void RTS_Setup_Coords (SANE_Byte * Regs, SANE_Int iLeft, SANE_Int iTop,
+ SANE_Int width, SANE_Int height);
+static SANE_Int RTS_Setup_Depth (SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ SANE_Int mycolormode);
+static void RTS_Setup_Exposure_Times (SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_scanmode *sm);
+static void RTS_Setup_GainOffset (SANE_Byte * Regs,
+ struct st_gain_offset *gain_offset);
+static void RTS_Setup_Gamma (SANE_Byte * Regs, struct st_hwdconfig *lowcfg);
+static SANE_Int RTS_Setup_Line_Distances (struct st_device *dev,
+ SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg,
+ SANE_Int mycolormode,
+ SANE_Int arrangeline);
+static SANE_Int RTS_Setup_Motor (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *myvar,
+ SANE_Int somevalue);
+static void RTS_Setup_RefVoltages (struct st_device *dev, SANE_Byte * Regs);
+static void RTS_Setup_SensorTiming (struct st_device *dev, SANE_Int mytiming,
+ SANE_Byte * Regs);
+static void RTS_Setup_Shading (SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg,
+ SANE_Int bytes_per_line);
+
+static SANE_Int Scan_Start (struct st_device *dev);
+
+static void SetLock (USB_Handle usb_handle, SANE_Byte * Regs,
+ SANE_Byte Enable);
+static SANE_Int fn3330 (struct st_device *dev, SANE_Byte * Regs,
+ struct st_cal2 *calbuffers,
+ SANE_Int sensorchannelcolor, SANE_Int * tablepos,
+ SANE_Int data);
+static SANE_Int fn3560 (USHORT * table, struct st_cal2 *calbuffers,
+ SANE_Int * tablepos);
+static SANE_Int fn3730 (struct st_device *dev, struct st_cal2 *calbuffers,
+ SANE_Byte * Regs, USHORT * table,
+ SANE_Int sensorchannelcolor, SANE_Int data);
+
+static SANE_Int Reading_CreateBuffers (struct st_device *dev);
+static SANE_Int Reading_DestroyBuffers (struct st_device *dev);
+static SANE_Int Reading_BufferSize_Get (struct st_device *dev,
+ SANE_Byte channels_per_dot,
+ SANE_Int channel_size);
+static SANE_Int Reading_BufferSize_Notify (struct st_device *dev,
+ SANE_Int data, SANE_Int size);
+static SANE_Int Reading_Wait (struct st_device *dev,
+ SANE_Byte Channels_per_dot,
+ SANE_Byte Channel_size, SANE_Int size,
+ SANE_Int * last_amount, SANE_Int seconds,
+ SANE_Byte op);
+
+static SANE_Int Read_Image (struct st_device *dev, SANE_Int buffer_size,
+ SANE_Byte * buffer, SANE_Int * transferred);
+static SANE_Int Read_ResizeBlock (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size,
+ SANE_Int * transferred);
+static SANE_Int Read_Block (struct st_device *dev, SANE_Int buffer_size,
+ SANE_Byte * buffer, SANE_Int * transferred);
+static SANE_Int Read_NonColor_Block (struct st_device *dev,
+ SANE_Byte * buffer, SANE_Int buffer_size,
+ SANE_Byte ColorMode,
+ SANE_Int * transferred);
+
+/* Ref functions */
+static SANE_Int Refs_Analyze_Pattern (struct st_scanparams *scancfg,
+ SANE_Byte * scanned_pattern,
+ SANE_Int * ler1, SANE_Int ler1order,
+ SANE_Int * ser1, SANE_Int ser1order);
+static SANE_Int Refs_Counter_Inc (struct st_device *dev);
+static SANE_Byte Refs_Counter_Load (struct st_device *dev);
+static SANE_Int Refs_Counter_Save (struct st_device *dev, SANE_Byte data);
+static SANE_Int Refs_Detect (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int resolution_x, SANE_Int resolution_y,
+ SANE_Int * x, SANE_Int * y);
+static SANE_Int Refs_Load (struct st_device *dev, SANE_Int * x, SANE_Int * y);
+static SANE_Int Refs_Save (struct st_device *dev, SANE_Int left_leading,
+ SANE_Int start_pos);
+static SANE_Int Refs_Set (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *myscan);
+
+/* Coordinates' constrains functions */
+static SANE_Int Constrains_Check (struct st_device *dev, SANE_Int Resolution,
+ SANE_Int scantype,
+ struct st_coords *mycoords);
+static struct st_coords *Constrains_Get (struct st_device *dev,
+ SANE_Byte scantype);
+
+/* Gain and offset functions */
+static SANE_Int GainOffset_Clear (struct st_device *dev);
+static SANE_Int GainOffset_Get (struct st_device *dev);
+static SANE_Int GainOffset_Save (struct st_device *dev, SANE_Int * offset,
+ SANE_Byte * gain);
+static SANE_Int GainOffset_Counter_Inc (struct st_device *dev,
+ SANE_Int * arg1);
+static SANE_Byte GainOffset_Counter_Load (struct st_device *dev);
+static SANE_Int GainOffset_Counter_Save (struct st_device *dev,
+ SANE_Byte data);
+
+/* Gamma functions*/
+static SANE_Int Gamma_AllocTable (SANE_Byte * table);
+static SANE_Int Gamma_Apply (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg,
+ struct st_gammatables *mygamma);
+static void Gamma_FreeTables (void);
+static SANE_Int Gamma_SendTables (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Byte * gammatable, SANE_Int size);
+static SANE_Int Gamma_GetTables (struct st_device *dev,
+ SANE_Byte * Gamma_buffer);
+
+/* Lamp functions */
+static SANE_Byte Lamp_GetGainMode (struct st_device *dev, SANE_Int resolution,
+ SANE_Byte scantype);
+static void Lamp_SetGainMode (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int resolution, SANE_Byte gainmode);
+static SANE_Int Lamp_PWM_DutyCycle_Get (struct st_device *dev,
+ SANE_Int * data);
+static SANE_Int Lamp_PWM_DutyCycle_Set (struct st_device *dev,
+ SANE_Int duty_cycle);
+static SANE_Int Lamp_PWM_Setup (struct st_device *dev, SANE_Int lamp);
+static SANE_Int Lamp_PWM_use (struct st_device *dev, SANE_Int enable);
+static SANE_Int Lamp_PWM_CheckStable (struct st_device *dev,
+ SANE_Int resolution, SANE_Int lamp);
+static SANE_Int Lamp_PWM_Save (struct st_device *dev, SANE_Int fixedpwm);
+static SANE_Int Lamp_PWM_SaveStatus (struct st_device *dev, SANE_Byte status);
+static SANE_Int Lamp_Status_Get (struct st_device *dev, SANE_Byte * flb_lamp,
+ SANE_Byte * tma_lamp);
+static SANE_Int Lamp_Status_Set (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int turn_on, SANE_Int lamp);
+static SANE_Int Lamp_Status_Timer_Set (struct st_device *dev,
+ SANE_Int minutes);
+static SANE_Int Lamp_Warmup (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int lamp, SANE_Int resolution);
+
+/* Head related functions */
+static SANE_Int Head_IsAtHome (struct st_device *dev, SANE_Byte * Regs);
+static SANE_Int Head_ParkHome (struct st_device *dev, SANE_Int bWait,
+ SANE_Int movement);
+static SANE_Int Head_Relocate (struct st_device *dev, SANE_Int speed,
+ SANE_Int direction, SANE_Int ypos);
+
+/* Motor functions */
+static SANE_Byte *Motor_AddStep (SANE_Byte * steps, SANE_Int * bwriten,
+ SANE_Int step);
+static SANE_Int Motor_Change (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Byte value);
+static SANE_Int Motor_GetFromResolution (SANE_Int resolution);
+static SANE_Int Motor_Move (struct st_device *dev, SANE_Byte * Regs,
+ struct st_motormove *mymotor,
+ struct st_motorpos *mtrpos);
+static void Motor_Release (struct st_device *dev);
+static SANE_Int Motor_Setup_Steps (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int mysetting);
+static SANE_Int Motor_Curve_Equal (struct st_device *dev,
+ SANE_Int motorsetting, SANE_Int direction,
+ SANE_Int curve1, SANE_Int curve2);
+static void Motor_Curve_Free (struct st_motorcurve **motorcurves,
+ SANE_Int * mtc_count);
+static struct st_curve *Motor_Curve_Get (struct st_device *dev,
+ SANE_Int motorcurve,
+ SANE_Int direction, SANE_Int itype);
+static struct st_motorcurve **Motor_Curve_Parse (SANE_Int * mtc_count,
+ SANE_Int * buffer);
+
+/* Functions to arrange scanned lines */
+static SANE_Int Arrange_Colour (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Int * transferred);
+static SANE_Int Arrange_Compose (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size,
+ SANE_Int * transferred);
+static SANE_Int Arrange_NonColour (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size,
+ SANE_Int * transferred);
+
+/* Composing RGB triplet functions */
+static void Triplet_Gray (SANE_Byte * pPointer1, SANE_Byte * pPointer2,
+ SANE_Byte * buffer, SANE_Int channels_count);
+static void Triplet_Lineart (SANE_Byte * pPointer1, SANE_Byte * pPointer2,
+ SANE_Byte * buffer, SANE_Int channels_count);
+static void Triplet_Compose_Order (struct st_device *dev, SANE_Byte * pRed,
+ SANE_Byte * pGreen, SANE_Byte * pBlue,
+ SANE_Byte * buffer, SANE_Int dots);
+static void Triplet_Compose_HRes (SANE_Byte * pPointer1,
+ SANE_Byte * pPointer2,
+ SANE_Byte * pPointer3,
+ SANE_Byte * pPointer4,
+ SANE_Byte * pPointer5,
+ SANE_Byte * pPointer6, SANE_Byte * buffer,
+ SANE_Int Width);
+static void Triplet_Compose_LRes (SANE_Byte * pRed, SANE_Byte * pGreen,
+ SANE_Byte * pBlue, SANE_Byte * buffer,
+ SANE_Int dots);
+static void Triplet_Colour_Order (struct st_device *dev, SANE_Byte * pRed,
+ SANE_Byte * pGreen, SANE_Byte * pBlue,
+ SANE_Byte * buffer, SANE_Int Width);
+static void Triplet_Colour_HRes (SANE_Byte * pRed1, SANE_Byte * pGreen1,
+ SANE_Byte * pBlue1, SANE_Byte * pRed2,
+ SANE_Byte * pGreen2, SANE_Byte * pBlue2,
+ SANE_Byte * buffer, SANE_Int Width);
+static void Triplet_Colour_LRes (SANE_Int Width, SANE_Byte * Buffer,
+ SANE_Byte * pChannel1, SANE_Byte * pChannel2,
+ SANE_Byte * pChannel3);
+
+/* Timing functions */
+static SANE_Int Timing_SetLinearImageSensorClock (SANE_Byte * Regs,
+ struct st_cph *cph);
+
+/* Functions used to resize retrieved image */
+static SANE_Int Resize_Start (struct st_device *dev, SANE_Int * transferred);
+static SANE_Int Resize_CreateBuffers (struct st_device *dev, SANE_Int size1,
+ SANE_Int size2, SANE_Int size3);
+static SANE_Int Resize_DestroyBuffers (struct st_device *dev);
+static SANE_Int Resize_Increase (SANE_Byte * to_buffer,
+ SANE_Int to_resolution, SANE_Int to_width,
+ SANE_Byte * from_buffer,
+ SANE_Int from_resolution,
+ SANE_Int from_width, SANE_Int myresize_mode);
+static SANE_Int Resize_Decrease (SANE_Byte * to_buffer,
+ SANE_Int to_resolution, SANE_Int to_width,
+ SANE_Byte * from_buffer,
+ SANE_Int from_resolution,
+ SANE_Int from_width, SANE_Int myresize_mode);
+
+/* Scanner buttons support */
+static SANE_Int Buttons_Count (struct st_device *dev);
+static SANE_Int Buttons_Enable (struct st_device *dev);
+static SANE_Int Buttons_Order (struct st_device *dev, SANE_Int mask);
+static SANE_Int Buttons_Status (struct st_device *dev);
+static SANE_Int Buttons_Released (struct st_device *dev);
+
+/* Calibration functions */
+static SANE_Int Calib_CreateBuffers (struct st_device *dev,
+ struct st_calibration *buffer,
+ SANE_Int my14b4);
+static SANE_Int Calib_CreateFixedBuffers (void);
+static void Calib_FreeBuffers (struct st_calibration *caltables);
+static void Calib_LoadCut (struct st_device *dev,
+ struct st_scanparams *scancfg, SANE_Int scantype,
+ struct st_calibration_config *calibcfg);
+static SANE_Int Calib_AdcGain (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ SANE_Int arg2, SANE_Int gainmode);
+static SANE_Int Calib_AdcOffsetRT (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ SANE_Int value);
+static SANE_Int Calib_BlackShading (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib,
+ SANE_Int gainmode);
+static SANE_Int Calib_BWShading (struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib,
+ SANE_Int gainmode);
+static SANE_Int Calib_WhiteShading_3 (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib,
+ SANE_Int gainmode);
+static void Calibrate_Free (struct st_cal2 *calbuffers);
+static SANE_Int Calibrate_Malloc (struct st_cal2 *calbuffers,
+ SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ SANE_Int somelength);
+static SANE_Int Calib_ReadTable (struct st_device *dev, SANE_Byte * table,
+ SANE_Int size, SANE_Int data);
+static SANE_Int Calib_WriteTable (struct st_device *dev, SANE_Byte * table,
+ SANE_Int size, SANE_Int data);
+static SANE_Int Calib_LoadConfig (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ SANE_Int scantype, SANE_Int resolution,
+ SANE_Int bitmode);
+static SANE_Int Calib_PAGain (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ SANE_Int gainmode);
+static SANE_Int Calibration (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_calibration *myCalib, SANE_Int value);
+
+/* function for white shading correction */
+static SANE_Int WShading_Calibrate (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ struct st_scanparams *scancfg);
+static void WShading_Emulate (SANE_Byte * buffer, SANE_Int * chnptr,
+ SANE_Int size, SANE_Int depth);
+
+/* functions for shading calibration */
+static SANE_Int Shading_apply (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *myvar,
+ struct st_calibration *myCalib);
+static SANE_Int Shading_black_apply (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int channels,
+ struct st_calibration *myCalib,
+ struct st_cal2 *calbuffers);
+static SANE_Int Shading_white_apply (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int channels,
+ struct st_calibration *myCalib,
+ struct st_cal2 *calbuffers);
+
+/* Spread-Spectrum Clock Generator functions */
+static SANE_Int SSCG_Enable (struct st_device *dev);
+
+static void Split_into_12bit_channels (SANE_Byte * destino,
+ SANE_Byte * fuente, SANE_Int size);
+static SANE_Int Scan_Read_BufferA (struct st_device *dev,
+ SANE_Int buffer_size, SANE_Int arg2,
+ SANE_Byte * pBuffer,
+ SANE_Int * bytes_transfered);
+
+static SANE_Int Bulk_Operation (struct st_device *dev, SANE_Byte op,
+ SANE_Int buffer_size, SANE_Byte * buffer,
+ SANE_Int * transfered);
+static SANE_Int Get_PAG_Value (SANE_Byte scantype, SANE_Byte color);
+static SANE_Int GetOneLineInfo (struct st_device *dev, SANE_Int resolution,
+ SANE_Int * maximus, SANE_Int * minimus,
+ double *average);
+
+static SANE_Int Load_StripCoords (SANE_Int scantype, SANE_Int * ypos,
+ SANE_Int * xpos);
+
+/*static SANE_Int Free_Fixed_CalBuffer(void);*/
+static SANE_Int SetMultiExposure (struct st_device *dev, SANE_Byte * Regs);
+
+static void Set_E950_Mode (struct st_device *dev, SANE_Byte mode);
+
+static SANE_Int LoadImagingParams (struct st_device *dev, SANE_Int inifile);
+
+static SANE_Int SetScanParams (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg);
+static SANE_Int IsScannerLinked (struct st_device *dev);
+
+static SANE_Int Read_FE3E (struct st_device *dev, SANE_Byte * destino);
+
+static double get_shrd (double value, SANE_Int desp);
+static char get_byte (double value);
+/*static SANE_Int RTS8822_GetRegisters(SANE_Byte *buffer);*/
+
+/* ----------------- Implementation ------------------*/
+
+static void
+RTS_Free (struct st_device *dev)
+{
+ /* this function frees space of devices's variable */
+
+ if (dev != NULL)
+ {
+ /* next function shouldn't be necessary but I can NOT assure that other
+ programmers will call Free_Config before this function */
+ Free_Config (dev);
+
+ if (dev->init_regs != NULL)
+ free (dev->init_regs);
+
+ if (dev->Resize != NULL)
+ free (dev->Resize);
+
+ if (dev->Reading != NULL)
+ free (dev->Reading);
+
+ if (dev->scanning != NULL)
+ free (dev->scanning);
+
+ if (dev->status != NULL)
+ free (dev->status);
+
+ free (dev);
+ }
+}
+
+static struct st_device *
+RTS_Alloc ()
+{
+ /* this function allocates space for device's variable */
+
+ struct st_device *dev = NULL;
+
+ dev = malloc (sizeof (struct st_device));
+ if (dev != NULL)
+ {
+ SANE_Int rst = OK;
+
+ bzero (dev, sizeof (struct st_device));
+
+ /* initial registers */
+ dev->init_regs = malloc (sizeof (SANE_Byte) * RT_BUFFER_LEN);
+ if (dev->init_regs != NULL)
+ bzero (dev->init_regs, sizeof (SANE_Byte) * RT_BUFFER_LEN);
+ else
+ rst = ERROR;
+
+ if (rst == OK)
+ {
+ dev->scanning = malloc (sizeof (struct st_scanning));
+ if (dev->scanning != NULL)
+ bzero (dev->scanning, sizeof (struct st_scanning));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ dev->Reading = malloc (sizeof (struct st_readimage));
+ if (dev->Reading != NULL)
+ bzero (dev->Reading, sizeof (struct st_readimage));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ dev->Resize = malloc (sizeof (struct st_resize));
+ if (dev->Resize != NULL)
+ bzero (dev->Resize, sizeof (struct st_resize));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ dev->status = malloc (sizeof (struct st_status));
+ if (dev->status != NULL)
+ bzero (dev->status, sizeof (struct st_status));
+ else
+ rst = ERROR;
+ }
+
+ /* if something fails, free space */
+ if (rst != OK)
+ {
+ RTS_Free (dev);
+ dev = NULL;
+ }
+ }
+
+ return dev;
+}
+
+static void
+RTS_Scanner_End (struct st_device *dev)
+{
+ Gamma_FreeTables ();
+ Free_Config (dev);
+ Free_Vars ();
+}
+
+static SANE_Int
+Device_get (SANE_Int product, SANE_Int vendor)
+{
+ return cfg_device_get (product, vendor);
+}
+
+static SANE_Int
+RTS_Scanner_Init (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "> RTS_Scanner_Init:\n");
+ DBG (DBG_FNC, "> Backend version: %s\n", BACKEND_VRSN);
+
+ rst = ERROR;
+
+ /* gets usb type of this scanner if it's not already set by user */
+ if (RTS_Debug->usbtype == -1)
+ RTS_Debug->usbtype = RTS_USBType (dev);
+
+ if (RTS_Debug->usbtype != ERROR)
+ {
+ DBG (DBG_FNC, " -> Chipset model ID: %i\n", Chipset_ID (dev));
+
+ Chipset_Reset (dev);
+
+ if (Load_Config (dev) == OK)
+ {
+ if (IsScannerLinked (dev) == OK)
+ {
+ Set_E950_Mode (dev, 0);
+ Gamma_AllocTable (NULL);
+ rst = OK;
+ }
+ else
+ Free_Config (dev);
+ }
+ }
+
+ return rst;
+}
+
+static SANE_Int
+RTS_WriteRegs (USB_Handle usb_handle, SANE_Byte * buffer)
+{
+ SANE_Int rst = ERROR;
+
+ if (buffer != NULL)
+ rst =
+ Write_Buffer (usb_handle, 0xe800, buffer,
+ RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ return rst;
+}
+
+static SANE_Int
+RTS_ReadRegs (USB_Handle usb_handle, SANE_Byte * buffer)
+{
+ SANE_Int rst = ERROR;
+
+ if (buffer != NULL)
+ rst =
+ Read_Buffer (usb_handle, 0xe800, buffer,
+ RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ return rst;
+}
+
+static void
+SetLock (USB_Handle usb_handle, SANE_Byte * Regs, SANE_Byte Enable)
+{
+ SANE_Byte lock;
+
+ DBG (DBG_FNC, "+ SetLock(*Regs, Enable=%i):\n", Enable);
+
+ if (Regs == NULL)
+ {
+ if (Read_Byte (usb_handle, 0xee00, &lock) != OK)
+ lock = 0;
+ }
+ else
+ lock = Regs[0x600];
+
+ if (Enable == FALSE)
+ lock &= 0xfb;
+ else
+ lock |= 4;
+
+ if (Regs != NULL)
+ Regs[0x600] = lock;
+
+ Write_Byte (usb_handle, 0xee00, lock);
+
+ DBG (DBG_FNC, "- SetLock\n");
+}
+
+static void
+Set_E950_Mode (struct st_device *dev, SANE_Byte mode)
+{
+ SANE_Int data;
+
+ DBG (DBG_FNC, "+ Set_E950_Mode(mode=%i):\n", mode);
+
+ if (Read_Word (dev->usb_handle, 0xe950, &data) == OK)
+ {
+ data = (mode == 0) ? data & 0xffbf : data | 0x40;
+ Write_Word (dev->usb_handle, 0xe950, data);
+ }
+
+ DBG (DBG_FNC, "- Set_E950_Mode\n");
+}
+
+static struct st_curve *
+Motor_Curve_Get (struct st_device *dev, SANE_Int motorcurve,
+ SANE_Int direction, SANE_Int itype)
+{
+ struct st_curve *rst = NULL;
+
+ if (dev != NULL)
+ {
+ if ((dev->mtrsetting != NULL) && (motorcurve < dev->mtrsetting_count))
+ {
+ struct st_motorcurve *mtc = dev->mtrsetting[motorcurve];
+
+ if (mtc != NULL)
+ {
+ if ((mtc->curve != NULL) && (mtc->curve_count > 0))
+ {
+ struct st_curve *crv;
+ SANE_Int a = 0;
+
+ while (a < mtc->curve_count)
+ {
+ /* get each curve */
+ crv = mtc->curve[a];
+ if (crv != NULL)
+ {
+ /* check direction and type */
+ if ((crv->crv_speed == direction)
+ && (crv->crv_type == itype))
+ {
+ /* found ! */
+ rst = crv;
+ break;
+ }
+ }
+ a++;
+ }
+ }
+ }
+ }
+ }
+
+ return rst;
+}
+
+static SANE_Int
+Motor_Curve_Equal (struct st_device *dev, SANE_Int motorsetting,
+ SANE_Int direction, SANE_Int curve1, SANE_Int curve2)
+{
+ /* compares two curves of the same direction
+ returns TRUE if both buffers are equal */
+
+ SANE_Int rst = FALSE;
+ struct st_curve *crv1 =
+ Motor_Curve_Get (dev, motorsetting, direction, curve1);
+ struct st_curve *crv2 =
+ Motor_Curve_Get (dev, motorsetting, direction, curve2);
+
+ if ((crv1 != NULL) && (crv2 != NULL))
+ {
+ if (crv1->step_count == crv2->step_count)
+ {
+ rst = TRUE;
+
+ if (crv1->step_count > 0)
+ {
+ SANE_Int a = 0;
+
+ while ((a < crv1->step_count) && (rst == TRUE))
+ {
+ rst = (crv1->step[a] == crv2->step[a]) ? TRUE : FALSE;
+ a++;
+ }
+ }
+ }
+ }
+
+ return rst;
+}
+
+static struct st_motorcurve **
+Motor_Curve_Parse (SANE_Int * mtc_count, SANE_Int * buffer)
+{
+ /* this function parses motorcurve buffer to get all motor settings */
+ struct st_motorcurve **rst = NULL;
+
+ *mtc_count = 0;
+
+ if (buffer != NULL)
+ {
+ /* phases:
+ -1 : null phase
+ 0 :
+ -3 : initial config
+ */
+ struct st_motorcurve *mtc = NULL;
+ SANE_Int phase;
+
+ phase = -1;
+ while (*buffer != -1)
+ {
+ if (*buffer == -2)
+ {
+ /* end of motorcurve */
+ /* complete any openned phase */
+ /* close phase */
+ phase = -1;
+ }
+ else
+ {
+ /* step */
+ if (phase == -1)
+ {
+ /* new motorcurve */
+ phase = 0;
+ mtc =
+ (struct st_motorcurve *)
+ malloc (sizeof (struct st_motorcurve));
+ if (mtc != NULL)
+ {
+ *mtc_count += 1;
+ rst =
+ realloc (rst,
+ sizeof (struct st_motorcurve **) *
+ *mtc_count);
+ if (rst != NULL)
+ {
+ rst[*mtc_count - 1] = mtc;
+ memset (mtc, 0, sizeof (struct st_motorcurve));
+ phase = -3; /* initial config */
+ }
+ else
+ {
+ /* memory error */
+ *mtc_count = 0;
+ break;
+ }
+ }
+ else
+ break; /* some error */
+ }
+
+ if (mtc != NULL)
+ {
+ switch (phase)
+ {
+ case -3: /* initial config */
+ mtc->mri = *(buffer);
+ mtc->msi = *(buffer + 1);
+ mtc->skiplinecount = *(buffer + 2);
+ mtc->motorbackstep = *(buffer + 3);
+ buffer += 3;
+
+ phase = -4;
+ break;
+
+ case -4:
+ /**/
+ {
+ /* create new step curve */
+ struct st_curve *curve =
+ malloc (sizeof (struct st_curve));
+ if (curve != NULL)
+ {
+ /* add to step curve list */
+ mtc->curve =
+ (struct st_curve **) realloc (mtc->curve,
+ sizeof (struct
+ st_curve
+ **) *
+ (mtc->
+ curve_count +
+ 1));
+ if (mtc->curve != NULL)
+ {
+ mtc->curve_count++;
+ mtc->curve[mtc->curve_count - 1] = curve;
+
+ memset (curve, 0, sizeof (struct st_curve));
+ /* read crv speed and type */
+ curve->crv_speed = *buffer;
+ curve->crv_type = *(buffer + 1);
+ buffer += 2;
+
+ /* get length of step buffer */
+ while (*(buffer + curve->step_count) != 0)
+ curve->step_count++;
+
+ if (curve->step_count > 0)
+ {
+ /* allocate step buffer */
+ curve->step =
+ (SANE_Int *) malloc (sizeof (SANE_Int) *
+ curve->step_count);
+ if (curve->step != NULL)
+ {
+ memcpy (curve->step, buffer,
+ sizeof (SANE_Int) *
+ curve->step_count);
+ buffer += curve->step_count;
+ }
+ else
+ curve->step_count = 0;
+ }
+ }
+ else
+ {
+ mtc->curve_count = 0;
+ free (curve);
+ }
+ }
+ else
+ break;
+ }
+ break;
+ }
+ }
+ }
+ buffer++;
+ }
+ }
+
+ return rst;
+}
+
+static void
+Motor_Curve_Free (struct st_motorcurve **motorcurves, SANE_Int * mtc_count)
+{
+ if ((motorcurves != NULL) && (mtc_count != NULL))
+ {
+ struct st_motorcurve *mtc;
+ struct st_curve *curve;
+
+ while (*mtc_count > 0)
+ {
+ mtc = motorcurves[*mtc_count - 1];
+ if (mtc != NULL)
+ {
+ if (mtc->curve != NULL)
+ {
+ while (mtc->curve_count > 0)
+ {
+ curve = mtc->curve[mtc->curve_count - 1];
+ if (curve != NULL)
+ {
+ if (curve->step != NULL)
+ free (curve->step);
+
+ free (curve);
+ }
+ mtc->curve_count--;
+ }
+ }
+ free (mtc);
+ }
+ *mtc_count -= 1;
+ }
+
+ free (motorcurves);
+ }
+}
+
+static SANE_Byte
+RTS_Sensor_Type (USB_Handle usb_handle)
+{
+ /*
+ Returns sensor type
+ 01 = CCD
+ 00 = CIS
+ */
+
+ SANE_Int a, b, c;
+ SANE_Byte rst;
+
+ DBG (DBG_FNC, "+ RTS_Sensor_Type:\n");
+
+ a = b = c = 0;
+
+ /* Save data first */
+ Read_Word (usb_handle, 0xe950, &a);
+ Read_Word (usb_handle, 0xe956, &b);
+
+ /* Enables GPIO 0xe950 writing directly 0x13ff */
+ Write_Word (usb_handle, 0xe950, 0x13ff);
+ /* Sets GPIO 0xe956 writing 0xfcf0 */
+ Write_Word (usb_handle, 0xe956, 0xfcf0);
+ /* Makes a sleep of 200 ms */
+ usleep (1000 * 200);
+ /* Get GPIO 0xe968 */
+ Read_Word (usb_handle, 0xe968, &c);
+ /* Restore data */
+ Write_Word (usb_handle, 0xe950, a);
+ Write_Word (usb_handle, 0xe956, b);
+
+ rst = ((_B1 (c) & 1) == 0) ? CCD_SENSOR : CIS_SENSOR;
+
+ DBG (DBG_FNC, "- RTS_Sensor_Type: %s\n",
+ (rst == CCD_SENSOR) ? "CCD" : "CIS");
+
+ return rst;
+}
+
+static void
+Free_Scanmodes (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Free_Scanmodes\n");
+
+ if (dev->scanmodes != NULL)
+ {
+ if (dev->scanmodes_count > 0)
+ {
+ SANE_Int a;
+ for (a = 0; a < dev->scanmodes_count; a++)
+ if (dev->scanmodes[a] != NULL)
+ free (dev->scanmodes[a]);
+ }
+
+ free (dev->scanmodes);
+ dev->scanmodes = NULL;
+ }
+
+ dev->scanmodes_count = 0;
+}
+
+static SANE_Int
+Load_Scanmodes (struct st_device *dev)
+{
+ SANE_Int rst = OK;
+ SANE_Int a, b;
+ struct st_scanmode reg, *mode;
+
+ DBG (DBG_FNC, "> Load_Scanmodes\n");
+
+ if ((dev->scanmodes != NULL) || (dev->scanmodes_count > 0))
+ Free_Scanmodes (dev);
+
+ a = 0;
+ while ((cfg_scanmode_get (dev->sensorcfg->type, a, &reg) == OK)
+ && (rst == OK))
+ {
+ mode = (struct st_scanmode *) malloc (sizeof (struct st_scanmode));
+ if (mode != NULL)
+ {
+ memcpy (mode, &reg, sizeof (struct st_scanmode));
+
+ for (b = 0; b < 3; b++)
+ {
+ if (mode->mexpt[b] == 0)
+ {
+ mode->mexpt[b] = mode->ctpc;
+ if (mode->multiexposure != 1)
+ mode->expt[b] = mode->ctpc;
+ }
+ }
+
+ mode->ctpc = ((mode->ctpc + 1) * mode->multiexposure) - 1;
+
+ dev->scanmodes =
+ (struct st_scanmode **) realloc (dev->scanmodes,
+ (dev->scanmodes_count +
+ 1) *
+ sizeof (struct st_scanmode **));
+ if (dev->scanmodes != NULL)
+ {
+ dev->scanmodes[dev->scanmodes_count] = mode;
+ dev->scanmodes_count++;
+ }
+ else
+ rst = ERROR;
+ }
+ else
+ rst = ERROR;
+
+ a++;
+ }
+
+ if (rst == ERROR)
+ Free_Scanmodes (dev);
+
+ DBG (DBG_FNC, " -> Found %i scanmodes\n", dev->scanmodes_count);
+ dbg_scanmodes (dev);
+
+ return rst;
+}
+
+static void
+Free_Config (struct st_device *dev)
+{
+ DBG (DBG_FNC, "+ Free_Config\n");
+
+ /* free buttons */
+ Free_Buttons (dev);
+
+ /* free motor general configuration */
+ Free_Motor (dev);
+
+ /* free sensor main configuration */
+ Free_Sensor (dev);
+
+ /* free ccd sensor timing tables */
+ Free_Timings (dev);
+
+ /* free motor curves */
+ Free_MotorCurves (dev);
+
+ /* free motor movements */
+ Free_Motormoves (dev);
+
+ /* free scan modes */
+ Free_Scanmodes (dev);
+
+ /* free constrains */
+ Free_Constrains (dev);
+
+ /* free chipset configuration */
+ Free_Chipset (dev);
+
+ DBG (DBG_FNC, "- Free_Config\n");
+}
+
+static void
+Free_Chipset (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Free_Chipset\n");
+
+ if (dev->chipset != NULL)
+ {
+ if (dev->chipset->name != NULL)
+ free (dev->chipset->name);
+
+ free (dev->chipset);
+ dev->chipset = NULL;
+ }
+}
+
+static SANE_Int
+Load_Chipset (struct st_device *dev)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "> Load_Chipset\n");
+
+ if (dev->chipset != NULL)
+ Free_Chipset (dev);
+
+ dev->chipset = malloc (sizeof (struct st_chip));
+ if (dev->chipset != NULL)
+ {
+ SANE_Int model;
+
+ bzero (dev->chipset, sizeof (struct st_chip));
+
+ /* get chipset model of selected scanner */
+ model = cfg_chipset_model_get (RTS_Debug->dev_model);
+
+ /* get configuration for selected chipset */
+ rst = cfg_chipset_get (model, dev->chipset);
+ }
+
+ /* if rst == ERROR may be related to allocating space for chipset name */
+
+ return rst;
+}
+
+static SANE_Int
+Load_Config (struct st_device *dev)
+{
+ DBG (DBG_FNC, "+ Load_Config\n");
+
+ /* load chipset configuration */
+ Load_Chipset (dev);
+
+ /* load scanner's buttons */
+ Load_Buttons (dev);
+
+ /* load scanner area constrains */
+ Load_Constrains (dev);
+
+ /* load motor general configuration */
+ Load_Motor (dev);
+
+ /* load sensor main configuration */
+ Load_Sensor (dev);
+
+ if (dev->sensorcfg->type == -1)
+ /* get sensor from gpio */
+ dev->sensorcfg->type = RTS_Sensor_Type (dev->usb_handle);
+
+ /* load ccd sensor timing tables */
+ Load_Timings (dev);
+
+ /* load motor curves */
+ Load_MotorCurves (dev);
+
+ /* load motor movements */
+ Load_Motormoves (dev);
+
+ /* load scan modes */
+ Load_Scanmodes (dev);
+
+ /* deprecated */
+ if (dev->sensorcfg->type == CCD_SENSOR)
+ /* ccd */ usbfile =
+ (RTS_Debug->usbtype == USB20) ? T_RTINIFILE : T_USB1INIFILE;
+ else /* cis */
+ usbfile = (RTS_Debug->usbtype == USB20) ? S_RTINIFILE : S_USB1INIFILE;
+
+ scantype = ST_NORMAL;
+
+ pwmlamplevel = get_value (SCAN_PARAM, PWMLAMPLEVEL, 1, usbfile);
+
+ arrangeline2 = get_value (SCAN_PARAM, ARRANGELINE, FIX_BY_HARD, usbfile);
+
+ shadingbase = get_value (TRUE_GRAY_PARAM, SHADINGBASE, 3, usbfile);
+ shadingfact[0] = get_value (TRUE_GRAY_PARAM, SHADINGFACT1, 1, usbfile);
+ shadingfact[1] = get_value (TRUE_GRAY_PARAM, SHADINGFACT2, 1, usbfile);
+ shadingfact[2] = get_value (TRUE_GRAY_PARAM, SHADINGFACT3, 1, usbfile);
+
+ LoadImagingParams (dev, usbfile);
+
+ DBG (DBG_FNC, "- Load_Config\n");
+
+ return OK;
+}
+
+static SANE_Int
+LoadImagingParams (struct st_device *dev, SANE_Int inifile)
+{
+ DBG (DBG_FNC, "> LoadImagingParams(inifile='%i'):\n", inifile);
+
+ scan.startpos = get_value (SCAN_PARAM, STARTPOS, 0, inifile);
+ scan.leftleading = get_value (SCAN_PARAM, LEFTLEADING, 0, inifile);
+ arrangeline = get_value (SCAN_PARAM, ARRANGELINE, FIX_BY_HARD, inifile);
+ compression = get_value (SCAN_PARAM, COMPRESSION, 0, inifile);
+
+ /* get default gain and offset values */
+ cfg_gainoffset_get (dev->sensorcfg->type, default_gain_offset);
+
+ linedarlampoff = get_value (CALI_PARAM, LINEDARLAMPOFF, 0, inifile);
+
+ pixeldarklevel = get_value (CALI_PARAM, PIXELDARKLEVEL, 0x00ffff, inifile);
+
+ binarythresholdh = get_value (PLATFORM, BINARYTHRESHOLDH, 0x80, inifile);
+ binarythresholdl = get_value (PLATFORM, BINARYTHRESHOLDL, 0x7f, inifile);
+
+ return OK;
+}
+
+static SANE_Int
+Arrange_Colour (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Int * transferred)
+{
+ /*
+ 05F0FA78 04EC00D8 /CALL to Assumed StdFunc2 from hpgt3970.04EC00D3
+ 05F0FA7C 05D10048 |Arg1 = 05D10048
+ 05F0FA80 0000F906 \Arg2 = 0000F906
+ */
+ SANE_Int mydistance;
+ SANE_Int Lines_Count;
+ SANE_Int space;
+ SANE_Int rst = OK;
+ SANE_Int c;
+ struct st_scanning *scn;
+
+ DBG (DBG_FNC, "> Arrange_Colour(*buffer, buffer_size=%i, *transferred)\n",
+ buffer_size);
+
+ /* this is just to make code more legible */
+ scn = dev->scanning;
+
+ if (scn->imagebuffer == NULL)
+ {
+ if (dev->sensorcfg->type == CCD_SENSOR)
+ mydistance =
+ (dev->sensorcfg->line_distance * scan2.resolution_y) /
+ dev->sensorcfg->resolution;
+ else
+ mydistance = 0;
+
+ /*aafa */
+ if (mydistance != 0)
+ {
+ scn->bfsize =
+ (scn->arrange_hres ==
+ TRUE) ? scn->arrange_sensor_evenodd_dist : 0;
+ scn->bfsize = (scn->bfsize + (mydistance * 2) + 1) * line_size;
+ }
+ else
+ scn->bfsize = line_size * 2;
+
+ /*ab3c */
+ space =
+ (((scn->bfsize / line_size) * bytesperline) >
+ scn->bfsize) ? (scn->bfsize / line_size) *
+ bytesperline : scn->bfsize;
+
+ scn->imagebuffer = (SANE_Byte *) malloc (space * sizeof (SANE_Byte));
+ if (scn->imagebuffer == NULL)
+ return ERROR;
+
+ scn->imagepointer = scn->imagebuffer;
+
+ if (Read_Block (dev, scn->bfsize, scn->imagebuffer, transferred) != OK)
+ return ERROR;
+
+ scn->arrange_orderchannel = FALSE;
+ scn->channel_size = (scan2.depth == 8) ? 1 : 2;
+
+ /* Calculate channel displacements */
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (mydistance == 0)
+ {
+ /*ab9b */
+ if (scn->arrange_hres == FALSE)
+ {
+ if ((((dev->sensorcfg->line_distance * scan2.resolution_y) *
+ 2) / dev->sensorcfg->resolution) == 1)
+ scn->arrange_orderchannel = TRUE;
+
+ if (scn->arrange_orderchannel == TRUE)
+ scn->desp[c] =
+ ((dev->sensorcfg->rgb_order[c] / 2) * line_size) +
+ (scn->channel_size * c);
+ else
+ scn->desp[c] = scn->channel_size * c;
+ }
+ }
+ else
+ {
+ /*ac32 */
+ scn->desp[c] =
+ (dev->sensorcfg->rgb_order[c] * (mydistance * line_size)) +
+ (scn->channel_size * c);
+
+ if (scn->arrange_hres == TRUE)
+ {
+ scn->desp1[c] = scn->desp[c];
+ scn->desp2[c] =
+ ((scn->channel_size * 3) + scn->desp[c]) +
+ (scn->arrange_sensor_evenodd_dist * line_size);
+ }
+ }
+ }
+
+ /*ace2 */
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (scn->arrange_hres == TRUE)
+ {
+ scn->pColour2[c] = scn->imagebuffer + scn->desp2[c];
+ scn->pColour1[c] = scn->imagebuffer + scn->desp1[c];
+ }
+ else
+ scn->pColour[c] = scn->imagebuffer + scn->desp[c];
+ }
+ }
+
+ /*ad91 */
+ Lines_Count = buffer_size / line_size;
+ while (Lines_Count > 0)
+ {
+ if (scn->arrange_orderchannel == FALSE)
+ {
+ if (scn->arrange_hres == TRUE)
+ Triplet_Colour_HRes (scn->pColour1[CL_RED],
+ scn->pColour1[CL_GREEN],
+ scn->pColour1[CL_BLUE],
+ scn->pColour2[CL_RED],
+ scn->pColour2[CL_GREEN],
+ scn->pColour2[CL_BLUE], buffer,
+ line_size / (scn->channel_size * 3));
+ else
+ Triplet_Colour_LRes (line_size / (scn->channel_size * 3), buffer,
+ scn->pColour[CL_RED], scn->pColour[CL_GREEN],
+ scn->pColour[CL_BLUE]);
+ }
+ else
+ Triplet_Colour_Order (dev, scn->pColour[CL_RED],
+ scn->pColour[CL_GREEN], scn->pColour[CL_BLUE],
+ buffer, line_size / (scn->channel_size * 3));
+
+ scn->arrange_size -= bytesperline;
+ if (scn->arrange_size < 0)
+ v15bc--;
+
+ buffer += line_size;
+
+ Lines_Count--;
+ if (Lines_Count == 0)
+ {
+ if ((scn->arrange_size | v15bc) == 0)
+ return OK;
+ }
+
+ if (Read_Block (dev, line_size, scn->imagepointer, transferred) ==
+ ERROR)
+ return ERROR;
+
+ /* Update displacements */
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (scn->arrange_hres == TRUE)
+ {
+ /*aeb7 */
+ scn->desp2[c] = (scn->desp2[c] + line_size) % scn->bfsize;
+ scn->desp1[c] = (scn->desp1[c] + line_size) % scn->bfsize;
+
+ scn->pColour2[c] = scn->imagebuffer + scn->desp2[c];
+ scn->pColour1[c] = scn->imagebuffer + scn->desp1[c];
+ }
+ else
+ {
+ /*af86 */
+ scn->desp[c] = (scn->desp[c] + line_size) % scn->bfsize;
+ scn->pColour[c] = scn->imagebuffer + scn->desp[c];
+ }
+ }
+
+ /*aff3 */
+ scn->imagepointer += line_size;
+ if (scn->imagepointer >= (scn->imagebuffer + scn->bfsize))
+ scn->imagepointer = scn->imagebuffer;
+ }
+
+ return rst;
+}
+
+static SANE_Int
+RTS_Scanner_SetParams (struct st_device *dev, struct params *param)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ RTS_Scanner_SetParams:\n");
+ DBG (DBG_FNC, "-> param->resolution_x=%i\n", param->resolution_x);
+ DBG (DBG_FNC, "-> param->resolution_y=%i\n", param->resolution_y);
+ DBG (DBG_FNC, "-> param->left =%i\n", param->coords.left);
+ DBG (DBG_FNC, "-> param->width =%i\n", param->coords.width);
+ DBG (DBG_FNC, "-> param->top =%i\n", param->coords.top);
+ DBG (DBG_FNC, "-> param->height =%i\n", param->coords.height);
+ DBG (DBG_FNC, "-> param->colormode =%s\n",
+ dbg_colour (param->colormode));
+ DBG (DBG_FNC, "-> param->scantype =%s\n",
+ dbg_scantype (param->scantype));
+ DBG (DBG_FNC, "-> param->depth =%i\n", param->depth);
+ DBG (DBG_FNC, "-> param->channel =%i\n", param->channel);
+
+ /* validate area size to scan */
+ if ((param->coords.width != 0) && (param->coords.height != 0))
+ {
+ SANE_Byte mybuffer[1];
+ struct st_hwdconfig hwdcfg;
+
+ /* setting coordinates */
+ memcpy (&scan.coord, &param->coords, sizeof (struct st_coords));
+
+ /* setting resolution */
+ scan.resolution_x = param->resolution_x;
+ scan.resolution_y = param->resolution_y;
+
+ /* setting colormode and depth */
+ scan.colormode = param->colormode;
+ scan.depth = (param->colormode == CM_LINEART) ? 8 : param->depth;
+
+ /* setting color channel for non color scans */
+ scan.channel = _B0 (param->channel);
+
+ arrangeline = FIX_BY_HARD;
+ if ((scan.resolution_x == 2400) || ((scan.resolution_x == 4800)))
+ {
+ if (scan.colormode != CM_COLOR)
+ {
+ if (scan.colormode == CM_GRAY)
+ {
+ if (scan.channel == 3)
+ arrangeline = FIX_BY_SOFT;
+ }
+ }
+ else
+ arrangeline = FIX_BY_SOFT;
+ }
+
+ /* setting scan type */
+ if ((param->scantype > 0) && (param->scantype < 4))
+ scan.scantype = param->scantype;
+ else
+ scan.scantype = ST_NORMAL;
+
+ /* setting scanner lamp */
+ data_bitset (&dev->init_regs[0x146], 0x40,
+ ((dev->sensorcfg->type == CIS_SENSOR) ? 0 : 1));
+
+ /* turn on appropiate lamp */
+ if (scan.scantype == ST_NORMAL)
+ Lamp_Status_Set (dev, NULL, TRUE, FLB_LAMP);
+ else
+ Lamp_Status_Set (dev, NULL, TRUE, TMA_LAMP);
+
+ mybuffer[0] = 0;
+ if (RTS_IsExecuting (dev, mybuffer) == FALSE)
+ RTS_WriteRegs (dev->usb_handle, dev->init_regs);
+
+ if (scan.depth == 16)
+ compression = FALSE;
+
+ /* resetting low level config */
+ bzero (&hwdcfg, sizeof (struct st_hwdconfig));
+
+ /* setting low level config */
+ hwdcfg.scantype = scan.scantype;
+ hwdcfg.calibrate = mybuffer[0];
+ hwdcfg.arrangeline = arrangeline; /*1 */
+ hwdcfg.highresolution = (scan.resolution_x > 1200) ? TRUE : FALSE;
+ hwdcfg.sensorevenodddistance = dev->sensorcfg->evenodd_distance;
+
+ SetScanParams (dev, dev->init_regs, &scan, &hwdcfg);
+
+ scan.shadinglength =
+ (((scan.sensorresolution * 17) / 2) + 3) & 0xfffffffc;
+
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- RTS_Scanner_SetParams: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+SetScanParams (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, struct st_hwdconfig *hwdcfg)
+{
+ struct st_coords mycoords;
+ SANE_Int mycolormode;
+ SANE_Int myvalue;
+ SANE_Int mymode;
+ SANE_Int channel_size;
+ SANE_Int channel_count;
+ SANE_Int dots_per_block;
+ SANE_Int aditional_dots;
+
+ DBG (DBG_FNC, "+ SetScanParams:\n");
+ dbg_ScanParams (scancfg);
+ dbg_hwdcfg (hwdcfg);
+
+ bzero (&mycoords, sizeof (struct st_coords));
+ /* Copy scancfg to scan2 */
+ memcpy (&scan2, scancfg, sizeof (struct st_scanparams));
+
+ mycolormode = scancfg->colormode;
+ myvalue = scancfg->colormode;
+ scantype = hwdcfg->scantype;
+
+ if (scancfg->colormode == CM_LINEART)
+ scan2.depth = 8;
+
+ if ((scancfg->colormode != CM_COLOR) && (scancfg->channel == 3)) /*channel = 0x00 */
+ {
+ if (scancfg->colormode == CM_GRAY)
+ {
+ mycolormode = (hwdcfg->arrangeline != FIX_BY_SOFT) ? 3 : CM_COLOR;
+ }
+ else
+ mycolormode = 3;
+ myvalue = mycolormode;
+ }
+
+ dev->Resize->resolution_x = scancfg->resolution_x;
+ dev->Resize->resolution_y = scancfg->resolution_y;
+
+ mymode = RTS_GetScanmode (dev, hwdcfg->scantype, myvalue, scancfg->resolution_x); /*0x0b */
+ if (mymode == -1)
+ {
+ /* Non supported resolution. We will resize image after scanning */
+ SANE_Int fitres;
+
+ fitres =
+ Scanmode_fitres (dev, hwdcfg->scantype, scancfg->colormode,
+ scancfg->resolution_x);
+ if (fitres != -1)
+ {
+ /* supported resolution found */
+ dev->Resize->type = RSZ_DECREASE;
+ }
+ else
+ {
+ dev->Resize->type = RSZ_INCREASE;
+ fitres =
+ Scanmode_maxres (dev, hwdcfg->scantype, scancfg->colormode);
+ }
+
+ scan2.resolution_x = fitres;
+ scan2.resolution_y = fitres;
+
+ mymode =
+ RTS_GetScanmode (dev, hwdcfg->scantype, myvalue, scan2.resolution_x);
+ if (mymode == -1)
+ return ERROR;
+
+ imageheight = scancfg->coord.height;
+ dev->Resize->towidth = scancfg->coord.width;
+
+ /* Calculate coords for new resolution */
+ mycoords.left =
+ (scan2.resolution_x * scancfg->coord.left) /
+ dev->Resize->resolution_x;
+ mycoords.width =
+ (scan2.resolution_x * scancfg->coord.width) /
+ dev->Resize->resolution_x;
+ mycoords.top =
+ (scan2.resolution_y * scancfg->coord.top) / dev->Resize->resolution_y;
+ mycoords.height =
+ ((scan2.resolution_y * scancfg->coord.height) /
+ dev->Resize->resolution_y) + 2;
+
+ switch (scan2.colormode)
+ {
+ case CM_GRAY:
+ if ((dev->scanmodes[mymode]->samplerate == PIXEL_RATE)
+ && (mycolormode != 3))
+ dev->Resize->towidth *= 2;
+
+ channel_size = (scan2.depth == 8) ? 1 : 2;
+ dev->Resize->mode = (scan2.depth == 8) ? RSZ_GRAYL : RSZ_GRAYH;
+ dev->Resize->bytesperline = dev->Resize->towidth * channel_size;
+ break;
+ case CM_LINEART:
+ if (dev->scanmodes[mymode]->samplerate == PIXEL_RATE)
+ dev->Resize->towidth *= 2;
+
+ dev->Resize->mode = RSZ_LINEART;
+ dev->Resize->bytesperline = (dev->Resize->towidth + 7) / 8;
+ break;
+ default: /*CM_COLOR */
+ channel_count = 3;
+ channel_size = (scan2.depth == 8) ? 1 : 2;
+ dev->Resize->mode = (scan2.depth == 8) ? RSZ_COLOURL : RSZ_COLOURH;
+ dev->Resize->bytesperline =
+ scancfg->coord.width * (channel_count * channel_size);
+ break;
+ }
+ }
+ else
+ {
+ /* Supported scanmode */
+ dev->Resize->type = RSZ_NONE;
+ scan2.resolution_x = scancfg->resolution_x;
+ scan2.resolution_y = scancfg->resolution_y;
+ mycoords.left = scancfg->coord.left;
+ mycoords.top = scancfg->coord.top;
+ mycoords.width = scancfg->coord.width;
+ mycoords.height = scancfg->coord.height;
+ }
+
+ scancfg->timing = dev->scanmodes[mymode]->timing;
+
+ scan2.sensorresolution = dev->timings[scancfg->timing]->sensorresolution;
+ if ((scantype > 0) && (scantype < 5))
+ scan2.shadinglength =
+ (((scan2.sensorresolution * 17) / 2) + 3) & 0xfffffffc;
+
+ scancfg->sensorresolution = scan2.sensorresolution;
+ scancfg->shadinglength = scan2.shadinglength;
+
+ dev->scanning->arrange_compression = ((mycolormode != CM_LINEART)
+ && (scan2.depth <=
+ 8)) ? hwdcfg->compression : FALSE;
+
+ if ((arrangeline2 == FIX_BY_HARD) || (mycolormode == CM_LINEART))
+ arrangeline2 = mycolormode; /*¿? */
+ else if ((mycolormode == CM_GRAY) && (hwdcfg->highresolution == FALSE))
+ arrangeline2 = 0;
+
+ if (hwdcfg->highresolution == FALSE)
+ {
+ /* resolution < 1200 dpi */
+ dev->scanning->arrange_hres = FALSE;
+ dev->scanning->arrange_sensor_evenodd_dist = 0;
+ }
+ else
+ {
+ /* resolution > 1200 dpi */
+ dev->scanning->arrange_hres = TRUE;
+ dev->scanning->arrange_sensor_evenodd_dist =
+ hwdcfg->sensorevenodddistance;
+ }
+
+ /* with must be adjusted to fit in the dots count per block */
+ aditional_dots = 0;
+ if (mycolormode != CM_LINEART)
+ {
+ dots_per_block = ((scan2.resolution_x > 2400)
+ && (scancfg->samplerate == PIXEL_RATE)) ? 8 : 4;
+
+ /* fit width */
+ if ((mycoords.width % dots_per_block) != 0)
+ {
+ aditional_dots = dots_per_block - (mycoords.width % dots_per_block);
+ mycoords.width += aditional_dots;
+ }
+ }
+ else
+ {
+ /* Lineart */
+ dots_per_block = 32 - (mycoords.width & 0x1f);
+ if (dots_per_block < 32)
+ {
+ mycoords.width += dots_per_block;
+ aditional_dots = (dots_per_block / 8);
+ }
+ }
+
+ DBG (DBG_FNC, " -> dots_per_block: %i\n", dots_per_block);
+ DBG (DBG_FNC, " -> aditional_dots: %i\n", aditional_dots);
+
+ if (mycolormode == CM_LINEART)
+ {
+ bytesperline =
+ (dev->scanmodes[mymode]->samplerate ==
+ PIXEL_RATE) ? mycoords.width / 4 : mycoords.width / 8;
+ imagewidth3 = bytesperline;
+ lineart_width = bytesperline * 8;
+ line_size = bytesperline - aditional_dots;
+ dev->Resize->fromwidth = line_size * 8;
+ }
+ else
+ {
+ /*4510 */
+ switch (mycolormode)
+ {
+ case CM_COLOR:
+ channel_count = 3;
+ break;
+ case 3:
+ channel_count = 1;
+ break;
+ case CM_GRAY:
+ channel_count = (dev->scanmodes[mymode]->samplerate == PIXEL_RATE) ? 2 : 1; /*1 */
+ break;
+ }
+
+ channel_size = (scan2.depth == 8) ? 1 : 2;
+ bytesperline = mycoords.width * (channel_count * channel_size);
+ imagewidth3 = bytesperline / channel_count;
+ lineart_width = imagewidth3 / channel_size;
+ line_size =
+ bytesperline - (aditional_dots * (channel_count * channel_size));
+ dev->Resize->fromwidth = line_size / (channel_count * channel_size);
+ }
+
+ imagesize = mycoords.height * bytesperline;
+ v15b4 = 0;
+ dev->scanning->arrange_size = imagesize;
+ v15bc = 0;
+
+ /* set resolution ratio */
+ data_bitset (&Regs[0xc0], 0x1f,
+ scancfg->sensorresolution / scancfg->resolution_x);
+
+ scancfg->coord.left = mycoords.left;
+ scancfg->coord.top = mycoords.top;
+ scancfg->coord.width = mycoords.width;
+ scancfg->coord.height = mycoords.height;
+ scancfg->resolution_x = scan2.resolution_x;
+ scancfg->resolution_y = scan2.resolution_y;
+
+ myvalue =
+ (dev->Resize->type == RSZ_NONE) ? line_size : dev->Resize->bytesperline;
+ scancfg->bytesperline = bytesperline;
+
+ scancfg->v157c = myvalue;
+
+ if (scan.colormode != CM_COLOR)
+ {
+ if (mycolormode == CM_COLOR)
+ scancfg->v157c = (scancfg->v157c / 3);
+ }
+
+ if (scan.colormode == CM_LINEART)
+ {
+ if (mycolormode == 3)
+ {
+ scancfg->v157c = (scancfg->v157c + 7) / 8;
+ scancfg->bytesperline = (scancfg->bytesperline + 7) / 8;
+ }
+ }
+
+ DBG (DBG_FNC, "- SetScanParams:\n");
+
+ return OK;
+}
+
+static SANE_Int
+GainOffset_Counter_Save (struct st_device *dev, SANE_Byte data)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "> GainOffset_Counter_Save(data=%i):\n", data);
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ data = min (data, 0x0f);
+ rst = RTS_EEPROM_WriteByte (dev->usb_handle, 0x0077, data);
+ }
+
+ return rst;
+}
+
+static SANE_Int
+GainOffset_Counter_Inc (struct st_device *dev, SANE_Int * arg1)
+{
+ SANE_Byte count;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ GainOffset_Counter_Inc:\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ count = GainOffset_Counter_Load (dev);
+ if ((count >= 0x0f) || (GainOffset_Get (dev) != OK))
+ {
+ offset[CL_BLUE] = offset[CL_GREEN] = offset[CL_RED] = 0;
+ gain[CL_BLUE] = gain[CL_GREEN] = gain[CL_RED] = 0;
+ count = 0;
+ }
+ else
+ {
+ count++;
+ if (arg1 != NULL)
+ *arg1 = 1;
+ }
+
+ rst = GainOffset_Counter_Save (dev, count);
+ }
+ else
+ rst = OK;
+
+ DBG (DBG_FNC, "- GainOffset_Counter_Inc: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+GainOffset_Get (struct st_device *dev)
+{
+ SANE_Int a, data, rst;
+ SANE_Byte checksum;
+
+ DBG (DBG_FNC, "+ GainOffset_Get:\n");
+
+ checksum = 0;
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ /* get current checksum */
+ if (RTS_EEPROM_ReadByte (dev->usb_handle, 0x76, &checksum) == OK)
+ {
+ rst = OK;
+
+ /* read gain and offset values from EEPROM */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ if (RTS_EEPROM_ReadWord (dev->usb_handle, 0x70 + (2 * a), &data)
+ == ERROR)
+ {
+ rst = ERROR;
+ break;
+ }
+ else
+ offset[a] = data;
+ }
+
+ /* check checksum */
+ checksum =
+ _B0 (checksum + offset[CL_GREEN] + offset[CL_BLUE] +
+ offset[CL_RED]);
+ }
+ else
+ rst = ERROR;
+ }
+ else
+ rst = ERROR;
+
+ /* extract gain and offset values */
+ if ((rst == OK) && (checksum == 0x5b))
+ {
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ gain[a] = (offset[a] >> 9) & 0x1f;
+ offset[a] &= 0x01ff;
+ }
+ }
+ else
+ {
+ /* null values, let's reset them */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ gain[a] = 0;
+ offset[a] = 0;
+ }
+
+ rst = ERROR;
+ }
+
+ DBG (DBG_FNC,
+ "-> Preview gainR=%i, gainG=%i, gainB=%i, offsetR=%i, offsetG=%i, offsetB=%i\n",
+ gain[CL_RED], gain[CL_GREEN], gain[CL_BLUE], offset[CL_RED],
+ offset[CL_GREEN], offset[CL_BLUE]);
+
+ DBG (DBG_FNC, "- GainOffset_Get: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Scanmode_maxres (struct st_device *dev, SANE_Int scantype, SANE_Int colormode)
+{
+ /* returns position in scanmodes table where data fits with given arguments */
+ SANE_Int rst = 0;
+ SANE_Int a;
+ struct st_scanmode *reg;
+
+ for (a = 0; a < dev->scanmodes_count; a++)
+ {
+ reg = dev->scanmodes[a];
+ if (reg != NULL)
+ {
+ if ((reg->scantype == scantype) && (reg->colormode == colormode))
+ rst = max (rst, reg->resolution); /* found ! */
+ }
+ }
+
+ if (rst == 0)
+ {
+ /* There isn't any mode for these arguments.
+ Most devices doesn't support specific setup to scan in lineart mode
+ so they use gray colormode. Lets check this case */
+ if (colormode == CM_LINEART)
+ rst = Scanmode_maxres (dev, scantype, CM_GRAY);
+ }
+
+ DBG (DBG_FNC, "> Scanmode_maxres(scantype=%s, colormode=%s): %i\n",
+ dbg_scantype (scantype), dbg_colour (colormode), rst);
+
+ return rst;
+}
+
+static SANE_Int
+Scanmode_minres (struct st_device *dev, SANE_Int scantype, SANE_Int colormode)
+{
+ /* returns position in scanmodes table where data fits with given arguments */
+ SANE_Int rst, a;
+ struct st_scanmode *reg;
+
+ rst = Scanmode_maxres (dev, scantype, colormode);
+
+ for (a = 0; a < dev->scanmodes_count; a++)
+ {
+ reg = dev->scanmodes[a];
+ if (reg != NULL)
+ {
+ if ((reg->scantype == scantype) && (reg->colormode == colormode))
+ rst = min (rst, reg->resolution); /* found ! */
+ }
+ }
+
+ if (rst == 0)
+ {
+ /* There isn't any mode for these arguments.
+ Most devices doesn't support specific setup to scan in lineart mode
+ so they use gray colormode. Lets check this case */
+ if (colormode == CM_LINEART)
+ rst = Scanmode_minres (dev, scantype, CM_GRAY);
+ }
+
+ DBG (DBG_FNC, "> Scanmode_minres(scantype=%s, colormode=%s): %i\n",
+ dbg_scantype (scantype), dbg_colour (colormode), rst);
+
+ return rst;
+}
+
+static SANE_Int
+Scanmode_fitres (struct st_device *dev, SANE_Int scantype, SANE_Int colormode,
+ SANE_Int resolution)
+{
+ /* returns a supported resolution */
+ SANE_Int rst;
+ SANE_Int a, nullres;
+ struct st_scanmode *reg;
+
+ nullres = Scanmode_maxres (dev, scantype, colormode) + 1;
+ rst = nullres;
+
+ for (a = 0; a < dev->scanmodes_count; a++)
+ {
+ reg = dev->scanmodes[a];
+ if (reg != NULL)
+ {
+ if ((reg->scantype == scantype) && (reg->colormode == colormode))
+ {
+ if ((reg->resolution < rst) && (resolution <= reg->resolution))
+ rst = reg->resolution;
+ }
+ }
+ }
+
+ if (rst == nullres)
+ {
+ /* There isn't any mode for these arguments.
+ Most devices doesn't support specific setup to scan in lineart mode
+ so they use gray colormode. Lets check this case */
+ if (colormode != CM_LINEART)
+ {
+ /* at this point, given resolution is bigger than maximum supported resolution */
+ rst = -1;
+ }
+ else
+ rst = Scanmode_minres (dev, scantype, CM_GRAY);
+ }
+
+ DBG (DBG_FNC,
+ "> Scanmode_fitres(scantype=%s, colormode=%s, resolution=%i): %i\n",
+ dbg_scantype (scantype), dbg_colour (colormode), resolution, rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_GetScanmode (struct st_device *dev, SANE_Int scantype, SANE_Int colormode,
+ SANE_Int resolution)
+{
+ /* returns position in scanmodes table where data fits with given arguments */
+ SANE_Int rst = -1;
+ SANE_Int a;
+ struct st_scanmode *reg;
+
+ for (a = 0; a < dev->scanmodes_count; a++)
+ {
+ reg = dev->scanmodes[a];
+ if (reg != NULL)
+ {
+ if ((reg->scantype == scantype) && (reg->colormode == colormode)
+ && (reg->resolution == resolution))
+ {
+ /* found ! */
+ rst = a;
+ break;
+ }
+ }
+ }
+
+ if (rst == -1)
+ {
+ /* There isn't any mode for these arguments.
+ May be given resolution isn't supported by chipset.
+ Most devices doesn't support specific setup to scan in lineart mode
+ so they use gray colormode. Lets check this case */
+ if ((colormode == CM_LINEART) || (colormode == 3))
+ rst = RTS_GetScanmode (dev, scantype, CM_GRAY, resolution);
+ }
+
+ DBG (DBG_FNC,
+ "> RTS_GetScanmode(scantype=%s, colormode=%s, resolution=%i): %i\n",
+ dbg_scantype (scantype), dbg_colour (colormode), resolution, rst);
+
+ return rst;
+}
+
+static void
+Free_Motor (struct st_device *dev)
+{
+ /* this function releases space for stepper motor */
+
+ DBG (DBG_FNC, "> Free_Motor\n");
+
+ if (dev->motorcfg != NULL)
+ {
+ free (dev->motorcfg);
+ dev->motorcfg = NULL;
+ }
+}
+
+static SANE_Int
+Load_Motor (struct st_device *dev)
+{
+ /* this function loads general configuration for motor */
+
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "> Load_Motor\n");
+
+ if (dev->motorcfg != NULL)
+ Free_Motor (dev);
+
+ dev->motorcfg = malloc (sizeof (struct st_motorcfg));
+ if (dev->motorcfg != NULL)
+ {
+ rst = cfg_motor_get (dev->motorcfg);
+ dbg_motorcfg (dev->motorcfg);
+ }
+
+ return rst;
+}
+
+static void
+Free_Sensor (struct st_device *dev)
+{
+ /* this function releases space for ccd sensor */
+
+ DBG (DBG_FNC, "> Free_Sensor\n");
+
+ if (dev->sensorcfg != NULL)
+ {
+ free (dev->sensorcfg);
+ dev->sensorcfg = NULL;
+ }
+}
+
+static void
+Free_Buttons (struct st_device *dev)
+{
+ /* this function releases space for buttons */
+
+ DBG (DBG_FNC, "> Free_Buttons\n");
+
+ if (dev->buttons != NULL)
+ {
+ free (dev->buttons);
+ dev->buttons = NULL;
+ }
+}
+
+static SANE_Int
+Load_Buttons (struct st_device *dev)
+{
+ /* this function loads configuration for ccd sensor */
+
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "> Load_Buttons\n");
+
+ if (dev->buttons != NULL)
+ Free_Buttons (dev);
+
+ dev->buttons = malloc (sizeof (struct st_buttons));
+ if (dev->buttons != NULL)
+ {
+ rst = cfg_buttons_get (dev->buttons);
+ dbg_buttons (dev->buttons);
+ }
+
+ return rst;
+}
+
+static SANE_Int
+Load_Sensor (struct st_device *dev)
+{
+ /* this function loads configuration for ccd sensor */
+
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "> Load_Sensor\n");
+
+ if (dev->sensorcfg != NULL)
+ Free_Sensor (dev);
+
+ dev->sensorcfg = malloc (sizeof (struct st_sensorcfg));
+ if (dev->sensorcfg != NULL)
+ {
+ rst = cfg_sensor_get (dev->sensorcfg);
+ dbg_sensor (dev->sensorcfg);
+ }
+
+ return rst;
+}
+
+static void
+Free_Timings (struct st_device *dev)
+{
+ /* this function frees all ccd sensor timing tables */
+ DBG (DBG_FNC, "> Free_Timings\n");
+
+ if (dev->timings != NULL)
+ {
+ if (dev->timings_count > 0)
+ {
+ SANE_Int a;
+ for (a = 0; a < dev->timings_count; a++)
+ if (dev->timings[a] != NULL)
+ free (dev->timings[a]);
+
+ dev->timings_count = 0;
+ }
+
+ free (dev->timings);
+ dev->timings = NULL;
+ }
+}
+
+static SANE_Int
+Load_Timings (struct st_device *dev)
+{
+ SANE_Int rst = OK;
+ SANE_Int a;
+ struct st_timing reg, *tmg;
+
+ DBG (DBG_FNC, "> Load_Timings\n");
+
+ if (dev->timings != NULL)
+ Free_Timings (dev);
+
+ a = 0;
+
+ while ((cfg_timing_get (dev->sensorcfg->type, a, &reg) == OK)
+ && (rst == OK))
+ {
+ tmg = (struct st_timing *) malloc (sizeof (struct st_timing));
+ if (tmg != NULL)
+ {
+ memcpy (tmg, &reg, sizeof (struct st_timing));
+
+ dev->timings_count++;
+ dev->timings =
+ (struct st_timing **) realloc (dev->timings,
+ sizeof (struct st_timing **) *
+ dev->timings_count);
+ if (dev->timings == NULL)
+ {
+ rst = ERROR;
+ dev->timings_count = 0;
+ }
+ else
+ dev->timings[dev->timings_count - 1] = tmg;
+ }
+ else
+ rst = ERROR;
+
+ a++;
+ }
+
+ if (rst == ERROR)
+ Free_Timings (dev);
+
+ DBG (DBG_FNC, " -> Found %i timing registers\n", dev->timings_count);
+
+ return rst;
+}
+
+static SANE_Int
+IsScannerLinked (struct st_device *dev)
+{
+ SANE_Int var2;
+ SANE_Byte lamp;
+
+ DBG (DBG_FNC, "+ IsScannerLinked:\n");
+
+ Read_FE3E (dev, &v1619);
+ Init_USBData (dev);
+ scan.scantype = ST_NORMAL;
+
+ RTS_WaitInitEnd (dev, 0x30000);
+
+ lamp = FLB_LAMP;
+
+ /* Comprobar si es la primera conexión con el escaner */
+ if (Read_Word (dev->usb_handle, 0xe829, &var2) == OK)
+ {
+ SANE_Int firstconnection;
+
+#ifdef STANDALONE
+ firstconnection = TRUE;
+#else
+ firstconnection = (var2 == 0) ? TRUE : FALSE;
+#endif
+
+ if (firstconnection == TRUE)
+ {
+ /* primera conexión */
+ SANE_Byte flb_lamp, tma_lamp;
+
+ flb_lamp = 0;
+ tma_lamp = 0;
+ Lamp_Status_Get (dev, &flb_lamp, &tma_lamp);
+
+ if ((flb_lamp == 0) && (tma_lamp != 0))
+ lamp = TMA_LAMP;
+
+ /*Clear GainOffset count */
+ GainOffset_Clear (dev);
+ GainOffset_Counter_Save (dev, 0);
+
+ /* Clear AutoRef count */
+ Refs_Counter_Save (dev, 0);
+
+ Buttons_Enable (dev);
+ Lamp_Status_Timer_Set (dev, 13);
+ }
+ else
+ lamp = (_B0 (var2) == 0) ? FLB_LAMP : TMA_LAMP;
+ }
+
+ if (RTS_Warm_Reset (dev) != OK)
+ return ERROR;
+
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+
+ Lamp_Status_Timer_Set (dev, 13);
+
+ /* Use fixed pwm? */
+ if (RTS_Debug->use_fixed_pwm != FALSE)
+ {
+ Lamp_PWM_Save (dev, cfg_fixedpwm_get (dev->sensorcfg->type, ST_NORMAL));
+ /* Lets enable using fixed pwm */
+ Lamp_PWM_SaveStatus (dev, TRUE);
+ }
+
+ Lamp_PWM_Setup (dev, lamp);
+
+ DBG (DBG_FNC, "- IsScannerLinked:\n");
+
+ return OK;
+}
+
+static SANE_Int
+Lamp_PWM_SaveStatus (struct st_device *dev, SANE_Byte status)
+{
+ SANE_Byte mypwm;
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_SaveStatus(status=%i):\n", status);
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ rst = ERROR;
+
+ if (RTS_EEPROM_ReadByte (dev->usb_handle, 0x007b, &mypwm) == OK)
+ {
+ mypwm = (status == FALSE) ? mypwm & 0x7f : mypwm | 0x80;
+
+ if (RTS_EEPROM_WriteByte (dev->usb_handle, 0x007b, mypwm) == OK)
+ rst = OK;
+ }
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_SaveStatus: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_PWM_Save (struct st_device *dev, SANE_Int fixedpwm)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_Save(fixedpwm=%i):\n", fixedpwm);
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ rst =
+ RTS_EEPROM_WriteByte (dev->usb_handle, 0x7b, ((fixedpwm << 2) | 0x80));
+ else
+ rst = OK;
+
+ DBG (DBG_FNC, "- Lamp_PWM_Save: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_PWM_Setup (struct st_device *dev, SANE_Int lamp)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_Setup(lamp=%s):\n",
+ (lamp == FLB_LAMP) ? "FLB_LAMP" : "TMA_LAMP");
+
+ if (Lamp_PWM_use (dev, 1) == OK)
+ {
+ SANE_Int fixedpwm, currentpwd;
+
+ currentpwd = 0;
+ fixedpwm =
+ cfg_fixedpwm_get (dev->sensorcfg->type,
+ (lamp == FLB_LAMP) ? ST_NORMAL : ST_TA);
+
+ if (Lamp_PWM_DutyCycle_Get (dev, &currentpwd) == OK)
+ {
+ /* set duty cycle if current one is different */
+ if (currentpwd != fixedpwm)
+ rst = Lamp_PWM_DutyCycle_Set (dev, fixedpwm);
+ }
+ else
+ rst = Lamp_PWM_DutyCycle_Set (dev, fixedpwm);
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_Setup: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_PWM_DutyCycle_Get (struct st_device *dev, SANE_Int * data)
+{
+ SANE_Byte a;
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_DutyCycle_Get:\n");
+
+ if (Read_Byte (dev->usb_handle, 0xe948, &a) == OK)
+ {
+ *data = a & 0x3f;
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_DutyCycle_Get = %i: %i\n", *data, rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_PWM_DutyCycle_Set (struct st_device *dev, SANE_Int duty_cycle)
+{
+ SANE_Byte *Regs;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_DutyCycle_Set(duty_cycle=%i):\n", duty_cycle);
+
+ rst = ERROR;
+
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (Regs != NULL)
+ {
+ if (RTS_ReadRegs (dev->usb_handle, Regs) == OK)
+ {
+ data_bitset (&Regs[0x148], 0x3f, duty_cycle);
+
+ if (pwmlamplevel == 0)
+ {
+ data_bitset (&Regs[0x148], 0x40, 0);
+ Regs[0x1e0] |= ((duty_cycle >> 1) & 0x40);
+ }
+
+ data_bitset (&dev->init_regs[0x148], 0x7f, Regs[0x148]);
+ data_bitset (&dev->init_regs[0x1e0], 0x3f, Regs[0x1e0]);
+
+ Write_Byte (dev->usb_handle, 0xe948, Regs[0x0148]);
+
+ rst = Write_Byte (dev->usb_handle, 0xe9e0, Regs[0x01e0]);
+ }
+
+ free (Regs);
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_DutyCycle_Set: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Head_ParkHome (struct st_device *dev, SANE_Int bWait, SANE_Int movement)
+{
+ SANE_Int rst = ERROR;
+ SANE_Byte *Regs;
+
+ DBG (DBG_FNC, "+ Head_ParkHome(bWait=%i, movement=%i):\n", bWait, movement);
+
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (Regs != NULL)
+ {
+ rst = OK;
+
+ memcpy (Regs, dev->init_regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ /* Lets wait if it's required when is already executing */
+ if (bWait != FALSE)
+ {
+ if (RTS_WaitScanEnd (dev, 0x3a98) != OK)
+ {
+ DBG (DBG_FNC, " -> Head_ParkHome: RTS_WaitScanEnd Timeout\n");
+ rst = ERROR; /* timeout */
+ }
+ }
+ else
+ {
+ if (RTS_IsExecuting (dev, Regs) == FALSE)
+ {
+ DBG (DBG_FNC,
+ " -> Head_ParkHome: RTS_IsExecuting = 0, exiting function\n");
+ rst = ERROR; /* if NOT executing */
+ }
+ }
+
+ /* Check if lamp is at home */
+ if ((rst == OK) && (Head_IsAtHome (dev, Regs) == FALSE))
+ {
+ struct st_motormove mymotor;
+ struct st_motorpos mtrpos;
+
+ DBG (DBG_FNC,
+ "-> Head_ParkHome: Lamp is not at home, lets move\n");
+
+ /* it isn't */
+ dev->status->parkhome = TRUE;
+
+ if ((movement != -1) && (movement < dev->motormove_count))
+ {
+ memcpy (&mymotor, dev->motormove[movement],
+ sizeof (struct st_motormove));
+ }
+ else
+ {
+ /* debug this code. Shouldn't have any relationship with offsets */
+ if (default_gain_offset->edcg2[CL_BLUE] < 4)
+ mymotor.scanmotorsteptype =
+ default_gain_offset->edcg2[CL_BLUE];
+
+ mymotor.ctpc = default_gain_offset->odcg2[1];
+ mymotor.systemclock = default_gain_offset->edcg2[1]; /*? */
+ }
+
+ mtrpos.options = MTR_ENABLED | MTR_BACKWARD;
+ mtrpos.v12e448 = 0x01;
+ mtrpos.v12e44c = 0x00;
+ mtrpos.coord_y = 0x4e20;
+
+ Motor_Move (dev, Regs, &mymotor, &mtrpos);
+
+ /* Should we wait? */
+ if (bWait != FALSE)
+ rst = RTS_WaitScanEnd (dev, 15000);
+
+ dev->status->parkhome = FALSE;
+ }
+
+ free (Regs);
+ }
+
+ DBG (DBG_FNC, "- Head_ParkHome: %i:\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Motor_Move (struct st_device *dev, SANE_Byte * Regs,
+ struct st_motormove *mymotor, struct st_motorpos *mtrpos)
+{
+ SANE_Byte *cpRegs;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Motor_Move:\n");
+
+ rst = ERROR;
+
+ cpRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (cpRegs != NULL)
+ {
+ SANE_Int data, v12dcf8, coord_y, step_type;
+
+ memcpy (cpRegs, Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ v12dcf8 = 0;
+
+ /* resolution = 1 dpi */
+ data_bitset (&cpRegs[0xc0], 0x1f, 1); /*---xxxxx*/
+
+ /* set motor step type */
+ data_bitset (&cpRegs[0xd9], 0x70, mymotor->scanmotorsteptype); /*-xxx----*/
+
+ /* set motor direction (polarity) */
+ data_bitset (&cpRegs[0xd9], 0x80, mtrpos->options >> 3); /*e------- */
+
+ /* next value doesn't seem to have any effect */
+ data_bitset (&cpRegs[0xd9], 0x0f, mtrpos->options); /*----efgh*/
+
+ /* 0 enable/1 disable motor */
+ data_bitset (&cpRegs[0xdd], 0x80, mtrpos->options >> 4); /*d------- */
+
+ /* next value doesn't seem to have any effect */
+ data_bitset (&cpRegs[0xdd], 0x40, mtrpos->options >> 4); /*-d------*/
+
+ switch (mymotor->scanmotorsteptype)
+ {
+ case STT_OCT:
+ step_type = 8;
+ break;
+ case STT_QUART:
+ step_type = 4;
+ break;
+ case STT_HALF:
+ step_type = 2;
+ break;
+ case STT_FULL:
+ step_type = 1;
+ break;
+ default:
+ step_type = 0;
+ break; /* shouldn't be used */
+ }
+
+ coord_y = (mtrpos->coord_y * step_type) & 0xffff;
+ if (coord_y < 2)
+ coord_y = 2;
+
+ /* Sets dummyline to 1 */
+ data_bitset (&cpRegs[0xd6], 0xf0, 1);
+
+ /* set step_size - 1 */
+ cpRegs[0xe0] = 0;
+
+ cpRegs[0x01] &= 0xf9;
+ cpRegs[0x01] |= (mtrpos->v12e448 & 1) << 2;
+
+ /* set dummy scan */
+ data_bitset (&cpRegs[0x01], 0x10, 1); /*---x----*/
+
+ /* set samplerate */
+ data_bitset (&cpRegs[0x1cf], 0x40, PIXEL_RATE); /*-x------*/
+
+ /* unknown data */
+ data_bitset (&cpRegs[0x1cf], 0x80, 1); /*x------- */
+
+ /* sets one chanel per color */
+ data_bitset (&cpRegs[0x12], 0x3f, 0); /* channel */
+ data_bitset (&cpRegs[0x12], 0xc0, 1); /* 1 channel */
+
+ /* timing cnpp */
+ data_bitset (&cpRegs[0x96], 0x3f, 0x0b); /*--001011*/
+
+ /* set systemclock */
+ data_bitset (&cpRegs[0x00], 0x0f, mymotor->systemclock); /*----xxxx*/
+
+ /* set last step of accurve.smearing table to 2 */
+ data_lsb_set (&cpRegs[0xe4], 2, 3);
+
+ /* set last step of deccurve.scanbufferfull table to 16 */
+ data_lsb_set (&Regs[0xea], 0x10, 3);
+
+ /* set last step of deccurve.normalscan table to 16 */
+ data_lsb_set (&Regs[0xed], 0x10, 3);
+
+ /* set last step of deccurve.smearing table to 16 */
+ data_lsb_set (&Regs[0xf0], 0x10, 3);
+
+ /* set last step of deccurve.parkhome table to 16 */
+ data_lsb_set (&Regs[0xf3], 0x10, 3);
+
+ /* set msi */
+ cpRegs[0xda] = 2;
+ cpRegs[0xdd] &= 0xfc;
+
+ /* set if motor has motorcurves */
+ data_bitset (&cpRegs[0xdf], 0x10,
+ ((mymotor->motorcurve != -1) ? 1 : 0));
+
+ if (mymotor->motorcurve != -1)
+ {
+ struct st_curve *crv;
+
+ /* set last step of accurve.normalscan table */
+ crv =
+ Motor_Curve_Get (dev, mymotor->motorcurve, ACC_CURVE,
+ CRV_NORMALSCAN);
+ if (crv != NULL)
+ data_lsb_set (&cpRegs[0xe1], crv->step[crv->step_count - 1], 3);
+
+ DBG (DBG_FNC, " -> Setting up stepper motor using motorcurve %i\n",
+ mymotor->motorcurve);
+ v12dcf8 = Motor_Setup_Steps (dev, cpRegs, mymotor->motorcurve);
+
+ /* set step_size - 1 */
+ cpRegs[0xe0] = 0;
+
+ crv =
+ Motor_Curve_Get (dev, mymotor->motorcurve, DEC_CURVE,
+ CRV_NORMALSCAN);
+ if (crv != NULL)
+ coord_y -= (v12dcf8 + crv->step_count);
+
+ /* set line exposure time */
+ data_lsb_set (&cpRegs[0x30], mymotor->ctpc, 3);
+
+ /* set last step of accurve.smearing table */
+ data_lsb_set (&cpRegs[0xe4], 0, 3);
+ }
+ else
+ {
+ /* Setting some motor step */
+ SANE_Int some_step;
+
+ switch (Regs[0x00] & 0x0f)
+ {
+ case 0x00:
+ some_step = 0x00895440;
+ break; /* 3 x 0x2DC6C0 */
+ case 0x08:
+ case 0x01:
+ some_step = 0x00b71b00;
+ break; /* 4 x 0x2DC6C0 */
+ case 0x02:
+ some_step = 0x0112a880;
+ break; /* 6 x 0x2DC6C0 */
+ case 0x0a:
+ case 0x03:
+ some_step = 0x016e3600;
+ break; /* 8 x 0x2DC6C0 */
+ case 0x04:
+ some_step = 0x02255100;
+ break; /* 12 x 0x2DC6C0 */
+ case 0x0c:
+ some_step = 0x02dc6c00;
+ break; /* 16 x 0x2DC6C0 */
+ case 0x05:
+ some_step = 0x044aa200;
+ break; /* 24 x 0x2DC6C0 */
+ case 0x0d:
+ some_step = 0x05b8d800;
+ break; /* 32 x 0x2DC6C0 */
+
+ case 0x09:
+ some_step = 0x00f42400;
+ break;
+ case 0x0b:
+ some_step = 0x01e84800;
+ break; /* = case 9 * 2 */
+ default:
+ some_step = 0x0478f7f8;
+ break;
+ }
+
+ /* divide by timing.cnpp */
+ some_step /= ((cpRegs[0x96] & 0x3f) + 1);
+ if (mymotor->ctpc > 0)
+ some_step /= mymotor->ctpc;
+
+ /* set line exposure time */
+ data_lsb_set (&cpRegs[0x30], some_step, 3);
+
+ /* set last step of accurve.normalscan table */
+ data_lsb_set (&cpRegs[0xe1], some_step, 3);
+ }
+
+ /* Setting coords */
+ RTS_Setup_Coords (cpRegs, 100, coord_y - 1, 800, 1);
+
+ /* enable head movement */
+ data_bitset (&cpRegs[0xd8], 0x80, 1);
+
+ /* release motor before executing */
+ Motor_Release (dev);
+
+ RTS_Warm_Reset (dev);
+
+ /* action! */
+ data = RTS_WriteRegs (dev->usb_handle, cpRegs);
+ if (data == OK)
+ RTS_Execute (dev);
+
+ /* wait 10 seconds */
+ RTS_WaitScanEnd (dev, 10000);
+
+ rst = (data != OK) ? v12dcf8 : RTS_WaitScanEnd (dev, 20000);
+
+ free (cpRegs);
+ }
+
+ DBG (DBG_FNC, "- Motor_Move: %i\n", rst);
+
+ return rst;
+}
+
+static void
+Free_Motormoves (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Free_Motormoves\n");
+
+ if (dev->motormove != NULL)
+ {
+ SANE_Int a;
+ struct st_motormove *ms;
+
+ for (a = 0; a < dev->motormove_count; a++)
+ {
+ ms = dev->motormove[a];
+ if (ms != NULL)
+ free (ms);
+ }
+
+ free (dev->motormove);
+ dev->motormove = NULL;
+ }
+
+ dev->motormove_count = 0;
+}
+
+static void
+Free_MotorCurves (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Free_MotorCurves\n");
+ if (dev->mtrsetting != NULL)
+ Motor_Curve_Free (dev->mtrsetting, &dev->mtrsetting_count);
+
+ dev->mtrsetting = NULL;
+ dev->mtrsetting_count = 0;
+}
+
+static SANE_Int
+Load_MotorCurves (struct st_device *dev)
+{
+ SANE_Int rst = ERROR;
+ SANE_Int *mtc = NULL;
+
+ if (dev->mtrsetting != NULL)
+ Free_MotorCurves (dev);
+
+ DBG (DBG_FNC, "> Load_MotorCurves\n");
+
+ /* get motor setttings buffer for this device */
+ mtc = cfg_motorcurve_get ();
+ if (mtc != NULL)
+ {
+ /* parse buffer to get all motorcurves */
+ dev->mtrsetting = Motor_Curve_Parse (&dev->mtrsetting_count, mtc);
+ if (dev->mtrsetting != NULL)
+ rst = OK;
+ }
+
+ if (rst != ERROR)
+ {
+ DBG (DBG_FNC, " -> Found %i motor settings\n", dev->mtrsetting_count);
+ dbg_motorcurves (dev);
+ }
+ else
+ DBG (DBG_ERR, "- Load_MotorCurves error!!\n");
+
+ return rst;
+}
+
+static SANE_Int
+Load_Motormoves (struct st_device *dev)
+{
+ SANE_Int rst = OK;
+ SANE_Int a;
+ struct st_motormove reg, *mm;
+
+ DBG (DBG_FNC, "> Load_Motormoves\n");
+
+ /* if there is already any movement loaded let's free it */
+ if (dev->motormove != NULL)
+ Free_Motormoves (dev);
+
+ a = 0;
+ while ((cfg_motormove_get (dev->sensorcfg->type, a, &reg) != ERROR)
+ && (rst == OK))
+ {
+ dev->motormove_count++;
+ dev->motormove =
+ (struct st_motormove **) realloc (dev->motormove,
+ sizeof (struct st_motormove **) *
+ dev->motormove_count);
+ if (dev->motormove != NULL)
+ {
+ mm = (struct st_motormove *) malloc (sizeof (struct st_motormove));
+ if (mm != NULL)
+ {
+ memcpy (mm, &reg, sizeof (struct st_motormove));
+ dev->motormove[dev->motormove_count - 1] = mm;
+ }
+ else
+ rst = ERROR;
+ }
+ else
+ rst = ERROR;
+
+ a++;
+ }
+
+ if (rst == ERROR)
+ Free_Motormoves (dev);
+
+ DBG (DBG_FNC, " -> Found %i motormoves\n", dev->motormove_count);
+ dbg_motormoves (dev);
+
+ return rst;
+}
+
+static SANE_Byte *
+Motor_AddStep (SANE_Byte * steps, SANE_Int * bwriten, SANE_Int step)
+{
+ steps = (SANE_Byte *) realloc (steps, sizeof (SANE_Byte) * (*bwriten + 3));
+ if (steps != NULL)
+ {
+ data_msb_set (&steps[*bwriten], step, 3);
+ *bwriten += 3;
+ }
+ else
+ *bwriten = 0;
+
+ return steps;
+}
+
+static SANE_Int
+Motor_Setup_Steps (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int mysetting)
+{
+ SANE_Int varx10, cont, last_acc_step, varx20, stepbuffer_size,
+ mystep, bwriten;
+ SANE_Int myvar, var1, myvalor, mybwriten;
+ struct st_curve *mycurve;
+ SANE_Byte *steps;
+
+ DBG (DBG_FNC, "+ Motor_Setup_Steps(*Regs, motorsetting=%i):\n", mysetting);
+
+ varx10 = 0;
+ cont = 0;
+ varx20 = 0;
+ stepbuffer_size = (v15f8 << 4) & 0xffff;
+ steps = NULL;
+ bwriten = 0;
+ deccurvecount = 0;
+ acccurvecount = 0;
+ last_acc_step = 0;
+
+ /* mycurve points to acc normalscan steps table */
+ mycurve = Motor_Curve_Get (dev, mysetting, ACC_CURVE, CRV_NORMALSCAN);
+
+ if (mycurve != NULL)
+ {
+ /* acccurvecount has the number of steps in acc normalscan table */
+ acccurvecount = mycurve->step_count;
+
+ /* get last acccurve step from acc.normalscan step table */
+ last_acc_step = data_lsb_get (&Regs[0xe1], 3);
+
+ /* sets pointer to acc.normalscan step table */
+ data_wide_bitset (&Regs[0xf6], 0x3fff, stepbuffer_size);
+
+ /* Separate each step in three bytes */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ {
+ mystep = mycurve->step[cont];
+ if (mystep <= last_acc_step)
+ {
+ acccurvecount = cont;
+ break;
+ }
+ varx20 += mystep + 1;
+ steps = Motor_AddStep (steps, &bwriten, mystep);
+ }
+ }
+
+ if (acccurvecount == 0)
+ {
+ /* Write one step (last_acc_step + 0x01) to buffer */
+ acccurvecount++;
+ varx20 += (last_acc_step + 1) + 1;
+ steps = Motor_AddStep (steps, &bwriten, last_acc_step + 1);
+ }
+
+ /* write another step (last_acc_step) */
+ acccurvecount++;
+ varx20 += last_acc_step + 1;
+ steps = Motor_AddStep (steps, &bwriten, last_acc_step);
+
+ /* get line exposure time */
+ myvar = data_lsb_get (&Regs[0x30], 3) + 1;
+
+ var1 = (varx20 + myvar - 1) / myvar;
+ var1 = ((var1 * myvar) + mycurve->step[0] - varx20) - 0x0d;
+ if (steps != NULL)
+ data_msb_set (&steps[0], var1, 3);
+
+ /* dec.scanbufferfull step table */
+ /* set pointer to next table */
+ stepbuffer_size += (acccurvecount * 3);
+ data_wide_bitset (&Regs[0xf8], 0x3fff, stepbuffer_size);
+
+ /* set last step of deccurve.scanbufferfull table */
+ mycurve = Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_BUFFERFULL);
+ deccurvecount = mycurve->step_count;
+ data_lsb_set (&Regs[0xea], mycurve->step[mycurve->step_count - 1], 3);
+
+ /* write another step mycurve->step_count,cont,last_acc_step */
+ deccurvecount++;
+ steps = Motor_AddStep (steps, &bwriten, last_acc_step);
+
+ /* Separate each step in three bytes */
+ if (mycurve->step_count > 1)
+ for (cont = 0; cont < (mycurve->step_count - 1); cont++)
+ {
+ mystep = mycurve->step[cont];
+ if (mystep > last_acc_step)
+ steps = Motor_AddStep (steps, &bwriten, mystep);
+ else
+ deccurvecount--;
+ }
+
+ myvalor = dev->mtrsetting[mysetting]->motorbackstep;
+ if (myvalor > 0)
+ {
+ SANE_Int step_size = _B0 (Regs[0xe0]) + 1;
+
+ myvalor = ((myvalor - deccurvecount) - acccurvecount) + 2;
+ varx10 = myvalor;
+ myvalor /= step_size;
+ myvalor *= step_size;
+ var1 = mycurve->step[mycurve->step_count - 1]; /* last deccurve step */
+ if (last_acc_step >= var1)
+ var1 = last_acc_step + 1;
+ deccurvecount += (varx10 - myvalor);
+ myvalor = varx10 - myvalor;
+ }
+ else
+ myvalor = varx10;
+
+ if (myvalor > 0)
+ for (cont = myvalor; cont > 0; cont--)
+ steps = Motor_AddStep (steps, &bwriten, var1 - 1);
+
+ /* write another step , bwriten tiene 4b */
+ steps = Motor_AddStep (steps, &bwriten, var1);
+
+ /* acc.smearing step table */
+ if (Motor_Curve_Get (dev, mysetting, ACC_CURVE, CRV_SMEARING) != NULL)
+ {
+ /* acc.smearing curve enabled */
+ if (Motor_Curve_Equal
+ (dev, mysetting, ACC_CURVE, CRV_SMEARING, CRV_NORMALSCAN) == TRUE)
+ {
+ /* acc.smearing pointer points to acc.normalscan table */
+ data_wide_bitset (&Regs[0xfa], 0x3fff,
+ data_lsb_get (&Regs[0xf6], 2));
+ /* last step of acc.smearing table is the same as acc.normalscan */
+ data_lsb_set (&Regs[0xe4], data_lsb_get (&Regs[0xe1], 3), 3);
+ }
+ else
+ {
+ /* set pointer to next step table */
+ stepbuffer_size += (deccurvecount * 3);
+ data_wide_bitset (&Regs[0xfa], 0x3fff, stepbuffer_size);
+
+ /* set last step of acc.smearing table */
+ mycurve = Motor_Curve_Get (dev, mysetting, ACC_CURVE, CRV_SMEARING);
+ if (mycurve != NULL)
+ {
+ smearacccurvecount = mycurve->step_count;
+ data_lsb_set (&Regs[0xe4],
+ mycurve->step[mycurve->step_count - 1], 3);
+
+ /* generate acc.smearing table */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ steps =
+ Motor_AddStep (steps, &bwriten, mycurve->step[cont]);
+ }
+ }
+ }
+ else
+ {
+ /* acc.smearing curve disabled */
+ data_wide_bitset (&Regs[0xfa], 0x3fff, 0);
+ }
+
+ /* dec.smearing */
+ if (Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_SMEARING) != NULL)
+ {
+ /* dec.smearing curve enabled */
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_SMEARING, CRV_BUFFERFULL) == TRUE)
+ {
+ /* dec.smearing pointer points to dec.scanbufferfull table */
+ data_wide_bitset (&Regs[0x00fc], 0x3fff,
+ data_lsb_get (&Regs[0x00f8], 2));
+ /* last step of dec.smearing table is the same as dec.scanbufferfull */
+ data_lsb_set (&Regs[0x00f0], data_lsb_get (&Regs[0x00ea], 3), 3);
+ }
+ else
+ {
+ /* set pointer to next step table */
+ if (mycurve != NULL)
+ stepbuffer_size += (mycurve->step_count * 3);
+ data_wide_bitset (&Regs[0xfc], 0x3fff, stepbuffer_size);
+
+ /* set last step of dec.smearing table */
+ mycurve = Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_SMEARING);
+ if (mycurve != NULL)
+ {
+ smeardeccurvecount = mycurve->step_count;
+ data_lsb_set (&Regs[0xf0],
+ mycurve->step[mycurve->step_count - 1], 3);
+
+ /* generate dec.smearing table */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ steps =
+ Motor_AddStep (steps, &bwriten, mycurve->step[cont]);
+ }
+ }
+ }
+ else
+ {
+ /* dec.smearing curve disabled */
+ data_wide_bitset (&Regs[0x00fc], 0x3fff, 0);
+ }
+
+ /* dec.normalscan */
+ if (Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_NORMALSCAN) != NULL)
+ {
+ /* dec.normalscan enabled */
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_NORMALSCAN, CRV_BUFFERFULL) == TRUE)
+ {
+ /* dec.normalscan pointer points to dec.scanbufferfull table */
+ data_wide_bitset (&Regs[0xfe], 0x3fff,
+ data_lsb_get (&Regs[0xf8], 2));
+ /* last step of dec.normalscan table is the same as dec.scanbufferfull */
+ data_lsb_set (&Regs[0xed], data_lsb_get (&Regs[0xea], 3), 3);
+ }
+ else
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_NORMALSCAN, CRV_SMEARING) == TRUE)
+ {
+ /* dec.normalscan pointer points to dec.smearing table */
+ data_wide_bitset (&Regs[0xfe], 0x3fff,
+ data_lsb_get (&Regs[0xfc], 2));
+ /* last step of dec.normalscan table is the same as dec.smearing */
+ data_lsb_set (&Regs[0xed], data_lsb_get (&Regs[0xf0], 3), 3);
+ }
+ else
+ {
+ /* set pointer to next step table */
+ if (mycurve != NULL)
+ stepbuffer_size += (mycurve->step_count * 3);
+ data_wide_bitset (&Regs[0xfe], 0x3fff, stepbuffer_size);
+
+ /* set last step of dec.normalscan table */
+ mycurve =
+ Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_NORMALSCAN);
+ if (mycurve != NULL)
+ {
+ data_lsb_set (&Regs[0xed],
+ mycurve->step[mycurve->step_count - 1], 3);
+
+ /* generate dec.normalscan table */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ steps =
+ Motor_AddStep (steps, &bwriten, mycurve->step[cont]);
+ }
+ }
+ }
+ else
+ {
+ /* dec.normalscan disabled */
+ data_wide_bitset (&Regs[0xfe], 0x3fff, 0);
+ }
+
+ /* acc.parkhome */
+ if (Motor_Curve_Get (dev, mysetting, ACC_CURVE, CRV_PARKHOME) != NULL)
+ {
+ /* parkhome curve enabled */
+
+ if (Motor_Curve_Equal
+ (dev, mysetting, ACC_CURVE, CRV_PARKHOME, CRV_NORMALSCAN) == TRUE)
+ {
+ /* acc.parkhome pointer points to acc.normalscan table */
+ data_wide_bitset (&Regs[0x100], 0x3fff,
+ data_lsb_get (&Regs[0xf6], 2));
+
+ /* last step of acc.parkhome table is the same as acc.normalscan */
+ data_lsb_set (&Regs[0xe7], data_lsb_get (&Regs[0xe1], 3), 3);
+ }
+ else
+ if (Motor_Curve_Equal
+ (dev, mysetting, ACC_CURVE, CRV_PARKHOME, CRV_SMEARING) == TRUE)
+ {
+ /* acc.parkhome pointer points to acc.smearing table */
+ data_wide_bitset (&Regs[0x100], 0x3fff,
+ data_lsb_get (&Regs[0xfa], 2));
+ /* last step of acc.parkhome table is the same as acc.smearing */
+ data_lsb_set (&Regs[0xe7], data_lsb_get (&Regs[0xe4], 3), 3);
+ }
+ else
+ {
+ /* set pointer to next step table */
+ if (mycurve != NULL)
+ stepbuffer_size += (mycurve->step_count * 3);
+ data_wide_bitset (&Regs[0x100], 0x3fff, stepbuffer_size);
+
+ /* set last step of acc.parkhome table */
+ mycurve = Motor_Curve_Get (dev, mysetting, ACC_CURVE, CRV_PARKHOME);
+ if (mycurve != NULL)
+ {
+ data_lsb_set (&Regs[0xe7],
+ mycurve->step[mycurve->step_count - 1], 3);
+
+ /* generate acc.parkhome table */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ steps =
+ Motor_AddStep (steps, &bwriten, mycurve->step[cont]);
+ }
+ }
+ }
+ else
+ {
+ /* parkhome curve is disabled */
+ /* acc.parkhome pointer points to 0 */
+ data_wide_bitset (&Regs[0x100], 0x3fff, 0);
+ data_lsb_set (&Regs[0xe7], 16, 3);
+ }
+
+ /* dec.parkhome */
+ if (Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_PARKHOME) != NULL)
+ {
+ /* parkhome curve enabled */
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_PARKHOME, CRV_BUFFERFULL) == TRUE)
+ {
+ /* dec.parkhome pointer points to dec.scanbufferfull table */
+ data_wide_bitset (&Regs[0x102], 0x3fff,
+ data_lsb_get (&Regs[0xf8], 2));
+ /* last step of dec.parkhome table is the same as dec.scanbufferfull */
+ data_lsb_set (&Regs[0xf3], data_lsb_get (&Regs[0xe4], 3), 3);
+ }
+ else
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_PARKHOME, CRV_SMEARING) == TRUE)
+ {
+ /* dec.parkhome pointer points to dec.smearing table */
+ data_wide_bitset (&Regs[0x102], 0x3fff,
+ data_lsb_get (&Regs[0xfe], 2));
+ /* last step of dec.parkhome table is the same as dec.smearing */
+ data_lsb_set (&Regs[0xf3], data_lsb_get (&Regs[0xf0], 3), 3);
+ }
+ else
+ if (Motor_Curve_Equal
+ (dev, mysetting, DEC_CURVE, CRV_PARKHOME, CRV_NORMALSCAN) == TRUE)
+ {
+ /* dec.parkhome pointer points to dec.normalscan table */
+ data_wide_bitset (&Regs[0x102], 0x3fff,
+ data_lsb_get (&Regs[0xfe], 2));
+ /* last step of dec.parkhome table is the same as dec.normalscan */
+ data_lsb_set (&Regs[0xf3], data_lsb_get (&Regs[0xed], 3), 3);
+ }
+ else
+ {
+ /* set pointer to next step table */
+ if (mycurve != NULL)
+ stepbuffer_size += (mycurve->step_count * 3);
+ data_wide_bitset (&Regs[0x102], 0x3fff, stepbuffer_size);
+
+ /* set last step of dec.parkhome table */
+ mycurve = Motor_Curve_Get (dev, mysetting, DEC_CURVE, CRV_PARKHOME);
+ if (mycurve != NULL)
+ {
+ data_lsb_set (&Regs[0xf3],
+ mycurve->step[mycurve->step_count - 1], 3);
+
+ /* generate dec.parkhome table */
+ if (mycurve->step_count > 0)
+ for (cont = 0; cont < mycurve->step_count; cont++)
+ steps =
+ Motor_AddStep (steps, &bwriten, mycurve->step[cont]);
+ }
+ }
+ }
+ else
+ {
+ /* parkhome curve is disabled */
+
+ /* dec.parkhome pointer points to 0 */
+ data_wide_bitset (&Regs[0x102], 0x3fff, 0);
+ data_lsb_set (&Regs[0xf3], 16, 3);
+ }
+
+ mybwriten = bwriten & 0x8000000f;
+ if (mybwriten < 0)
+ mybwriten = ((mybwriten - 1) | 0xfffffff0) + 1;
+
+ if (mybwriten != 0)
+ bwriten = (((bwriten & 0xffff) >> 0x04) + 1) << 0x04;
+ bwriten = bwriten & 0xffff;
+
+ /* display table */
+ DBG (DBG_FNC, " -> Direction Type Offset Last step\n");
+ DBG (DBG_FNC, " -> --------- -------------- ------ ---------\n");
+ DBG (DBG_FNC, " -> ACC_CURVE CRV_NORMALSCAN %6i %6i\n",
+ data_lsb_get (&Regs[0x0f6], 2) & 0x3fff, data_lsb_get (&Regs[0x0e1],
+ 3));
+ DBG (DBG_FNC, " -> ACC_CURVE CRV_SMEARING %6i %6i\n",
+ data_lsb_get (&Regs[0x0fa], 2) & 0x3fff, data_lsb_get (&Regs[0x0e4],
+ 3));
+ DBG (DBG_FNC, " -> ACC_CURVE CRV_PARKHOME %6i %6i\n",
+ data_lsb_get (&Regs[0x100], 2) & 0x3fff, data_lsb_get (&Regs[0x0e7],
+ 3));
+ DBG (DBG_FNC, " -> DEC_CURVE CRV_NORMALSCAN %6i %6i\n",
+ data_lsb_get (&Regs[0x0fe], 2) & 0x3fff, data_lsb_get (&Regs[0x0ed],
+ 3));
+ DBG (DBG_FNC, " -> DEC_CURVE CRV_SMEARING %6i %6i\n",
+ data_lsb_get (&Regs[0x0fc], 2) & 0x3fff, data_lsb_get (&Regs[0x0f0],
+ 3));
+ DBG (DBG_FNC, " -> DEC_CURVE CRV_PARKHOME %6i %6i\n",
+ data_lsb_get (&Regs[0x102], 2) & 0x3fff, data_lsb_get (&Regs[0x0f3],
+ 3));
+ DBG (DBG_FNC, " -> DEC_CURVE CRV_BUFFERFULL %6i %6i\n",
+ data_lsb_get (&Regs[0x0f8], 2) & 0x3fff, data_lsb_get (&Regs[0x0ea],
+ 3));
+
+ RTS_Warm_Reset (dev);
+
+ /* send motor steps */
+ if (steps != NULL)
+ {
+ if (bwriten > 0)
+ {
+ /* lock */
+ SetLock (dev->usb_handle, Regs, TRUE);
+
+ /* send steps */
+ RTS_DMA_Write (dev, 0x0000, v15f8, bwriten, steps);
+
+ /* unlock */
+ SetLock (dev->usb_handle, Regs, FALSE);
+ }
+
+ free (steps);
+ }
+
+ DBG (DBG_FNC, "- Motor_Setup_Steps: %i\n", acccurvecount);
+
+ return acccurvecount;
+}
+
+static SANE_Int
+Lamp_PWM_use (struct st_device *dev, SANE_Int enable)
+{
+ SANE_Byte a, b;
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_use(enable=%i):\n", enable);
+
+ if (Read_Byte (dev->usb_handle, 0xe948, &a) == OK)
+ {
+ if (Read_Byte (dev->usb_handle, 0xe9e0, &b) == OK)
+ {
+ if (enable != 0)
+ {
+ if (pwmlamplevel != 0x00)
+ {
+ b |= 0x80;
+ dev->init_regs[0x01e0] &= 0x3f;
+ dev->init_regs[0x01e0] |= 0x80;
+ }
+ else
+ {
+ a |= 0x40;
+ b &= 0x3f;
+ dev->init_regs[0x0148] |= 0x40;
+ dev->init_regs[0x01e0] &= 0x3f;
+ }
+ }
+ else
+ {
+ b &= 0x7f;
+ a &= 0xbf;
+ }
+
+ if (Write_Byte (dev->usb_handle, 0xe948, a) == OK)
+ rst = Write_Byte (dev->usb_handle, 0xe9e0, b);
+ }
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_use: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+SSCG_Enable (struct st_device *dev)
+{
+ SANE_Int rst;
+ SANE_Int sscg;
+ SANE_Byte data1, data2;
+ SANE_Int enable, mode, clock;
+
+ DBG (DBG_FNC, "+ SSCG_Enable:\n");
+
+ rst = cfg_sscg_get (&enable, &mode, &clock);
+
+ if (rst == OK)
+ {
+ if ((Read_Byte (dev->usb_handle, 0xfe3a, &data1) == OK)
+ && (Read_Byte (dev->usb_handle, 0xfe39, &data2) == OK))
+ {
+ if (enable != FALSE)
+ {
+ /* clock values: 0=0.25%; 1=0.50%; 2=0.75%; 3=1.00% */
+ data2 = (mode == 0) ? data2 & 0x7f : data2 | 0x80;
+
+ sscg = (data1 & 0xf3) | (((clock & 0x03) | 0x04) << 0x02);
+ sscg = (sscg << 8) | data2;
+ }
+ else
+ sscg = ((data1 & 0xef) << 8) | _B0 (data2);
+
+ rst = Write_Word (dev->usb_handle, 0xfe39, sscg);
+ }
+ else
+ rst = ERROR;
+ }
+
+ DBG (DBG_FNC, "- SSCG_Enable: %i\n", rst);
+
+ return rst;
+}
+
+static void
+RTS_Setup_RefVoltages (struct st_device *dev, SANE_Byte * Regs)
+{
+ /* this function sets top, midle and bottom reference voltages */
+
+ DBG (DBG_FNC, "> RTS_Setup_RefVoltages\n");
+
+ if (Regs != NULL)
+ {
+ SANE_Byte vrts, vrms, vrbs;
+
+ cfg_refvoltages_get (dev->sensorcfg->type, &vrts, &vrms, &vrbs);
+
+ /* Top Reference Voltage */
+ data_bitset (&Regs[0x14], 0xe0, vrts); /*xxx----- */
+
+ /* Middle Reference Voltage */
+ data_bitset (&Regs[0x15], 0xe0, vrms); /*xxx----- */
+
+ /* Bottom Reference Voltage */
+ data_bitset (&Regs[0x16], 0xe0, vrbs); /*xxx----- */
+ }
+}
+
+static SANE_Int
+Init_USBData (struct st_device *dev)
+{
+ SANE_Byte data;
+ SANE_Byte *resource;
+
+ DBG (DBG_FNC, "+ Init_USBData:\n");
+
+ if (Read_Byte (dev->usb_handle, 0xf8ff, &data) != OK)
+ return ERROR;
+
+ data = (data | 1);
+ if (Write_Byte (dev->usb_handle, 0xf8ff, data) != OK)
+ return ERROR;
+
+ if (SSCG_Enable (dev) != OK)
+ return ERROR;
+
+ Init_Registers (dev);
+
+ /* Gamma table size = 0x100 */
+ data_bitset (&dev->init_regs[0x1d0], 0x30, 0x00); /*--00----*/
+
+ /* Set 3 channels_per_dot */
+ data_bitset (&dev->init_regs[0x12], 0xc0, 0x03); /*xx------ */
+
+ /* systemclock */
+ data_bitset (&dev->init_regs[0x00], 0x0f, 0x05); /*----xxxx*/
+
+ /* timing cnpp */
+ data_bitset (&dev->init_regs[0x96], 0x3f, 0x17); /*--xxxxxx*/
+
+ /* set sensor_channel_color_order */
+ data_bitset (&dev->init_regs[0x60a], 0x7f, 0x24); /*-xxxxxxx*/
+
+ /* set crvs */
+ data_bitset (&dev->init_regs[0x10], 0x1f, get_value (SCAN_PARAM, CRVS, 7, usbfile)); /*---xxxxx*/
+
+ /* set reference voltages */
+ RTS_Setup_RefVoltages (dev, dev->init_regs);
+
+ dev->init_regs[0x11] |= 0x10;
+
+ data_bitset (&dev->init_regs[0x26], 0x70, 5); /*-101----*/
+
+ dev->init_regs[0x185] = 0x88;
+ dev->init_regs[0x186] = 0x88;
+
+ /* SDRAM clock */
+ data = get_value (SCAN_PARAM, MCLKIOC, 8, usbfile);
+ data_bitset (&dev->init_regs[0x187], 0x0f, 0x08); /*----xxxx*/
+ data_bitset (&dev->init_regs[0x187], 0xf0, data); /*xxxx---- */
+
+ data--;
+
+ if (data < 7)
+ {
+ switch (data)
+ {
+ case 0:
+ data |= 0xc0;
+ break;
+ case 1:
+ data |= 0xa0;
+ break;
+ case 2:
+ data |= 0xe0;
+ break;
+ case 3:
+ data |= 0x90;
+ break;
+ case 4:
+ data |= 0xd0;
+ break;
+ case 5:
+ data |= 0xb0;
+ break;
+ case 6:
+ data = (data & 0x0f);
+ break;
+ }
+ dev->init_regs[0x187] = _B0 (data);
+ }
+
+ data_bitset (&dev->init_regs[0x26], 0x0f, 0); /*----0000*/
+
+ dev->init_regs[0x27] &= 0x3f;
+ dev->init_regs[0x29] = 0x24;
+ dev->init_regs[0x2a] = 0x10;
+ dev->init_regs[0x150] = 0xff;
+ dev->init_regs[0x151] = 0x13;
+ dev->init_regs[0x156] = 0xf0;
+ dev->init_regs[0x157] = 0xfd;
+
+ if (dev->motorcfg->changemotorcurrent != FALSE)
+ Motor_Change (dev, dev->init_regs, 3);
+
+ dev->init_regs[0xde] = 0;
+ data_bitset (&dev->init_regs[0xdf], 0x0f, 0);
+
+ /* loads motor resource for this dev */
+ resource = cfg_motor_resource_get (&data);
+ if ((resource != NULL) && (data > 1))
+ memcpy (&dev->init_regs[0x104], resource, data);
+
+ /* this bit is set but I don't know its purpose */
+ dev->init_regs[0x01] |= 0x40; /*-1------*/
+
+ dev->init_regs[0x124] = 0x94;
+
+ /* release motor */
+ Motor_Release (dev);
+
+ DBG (DBG_FNC, "- Init_USBData:\n");
+
+ return OK;
+}
+
+static SANE_Int
+Init_Registers (struct st_device *dev)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Init_Registers:\n");
+
+ /* Lee dev->init_regs */
+ bzero (dev->init_regs, RT_BUFFER_LEN);
+ RTS_ReadRegs (dev->usb_handle, dev->init_regs);
+ Read_FE3E (dev, &v1619);
+
+ if (dev->sensorcfg->type == CCD_SENSOR)
+ {
+ /* CCD sensor */
+ data_bitset (&dev->init_regs[0x11], 0xc0, 0); /*xx------ */
+ data_bitset (&dev->init_regs[0x146], 0x80, 1); /*x------- */
+ data_bitset (&dev->init_regs[0x146], 0x40, 1); /*-x------*/
+
+ }
+ else
+ {
+ /* CIS sensor */
+ data_bitset (&dev->init_regs[0x146], 0x80, 0); /*0------- */
+ data_bitset (&dev->init_regs[0x146], 0x40, 0); /*-0------*/
+ data_bitset (&dev->init_regs[0x11], 0xc0, 2); /*xx------ */
+ data_bitset (&dev->init_regs[0xae], 0x3f, 0x14); /*--xxxxxx*/
+ data_bitset (&dev->init_regs[0xaf], 0x07, 1); /*-----xxx*/
+
+ dev->init_regs[0x9c] = dev->init_regs[0xa2] = dev->init_regs[0xa8] =
+ (RTS_Debug->dev_model != UA4900) ? 1 : 0;
+ dev->init_regs[0x9d] = dev->init_regs[0xa3] = dev->init_regs[0xa9] = 0;
+ dev->init_regs[0x9e] = dev->init_regs[0xa4] = dev->init_regs[0xaa] = 0;
+ dev->init_regs[0x9f] = dev->init_regs[0xa5] = dev->init_regs[0xab] = 0;
+ dev->init_regs[0xa0] = dev->init_regs[0xa6] = dev->init_regs[0xac] = 0;
+ dev->init_regs[0xa1] = dev->init_regs[0xa7] = dev->init_regs[0xad] =
+ (RTS_Debug->dev_model != UA4900) ? 0x80 : 0;
+ }
+
+ /* disable CCD channels */
+ data_bitset (&dev->init_regs[0x10], 0xe0, 0); /*xxx----- */
+ data_bitset (&dev->init_regs[0x13], 0x80, 0); /*x------- */
+
+ /* enable timer to switch off lamp */
+ data_bitset (&dev->init_regs[0x146], 0x10, 1); /*---x----*/
+
+ /* set time to switch off lamp */
+ dev->init_regs[0x147] = 0xff;
+
+ /* set last acccurve step */
+ data_lsb_set (&dev->init_regs[0xe1], 0x2af8, 3);
+
+ /* set msi 0x02 */
+ dev->init_regs[0xda] = 0x02;
+ data_bitset (&dev->init_regs[0xdd], 0x03, 0); /*------xx*/
+
+ /* set binary threshold high and low in little endian */
+ data_lsb_set (&dev->init_regs[0x19e], binarythresholdl, 2);
+ data_lsb_set (&dev->init_regs[0x1a0], binarythresholdh, 2);
+
+
+ data_bitset (&dev->init_regs[0x01], 0x08, 0); /*----x---*/
+ data_bitset (&dev->init_regs[0x16f], 0x40, 0); /*-x------*/
+ dev->init_regs[0x0bf] = (dev->init_regs[0x00bf] & 0xe0) | 0x20;
+ dev->init_regs[0x163] = (dev->init_regs[0x0163] & 0x3f) | 0x40;
+
+ data_bitset (&dev->init_regs[0xd6], 0x0f, 8); /*----xxxx*/
+ data_bitset (&dev->init_regs[0x164], 0x80, 1); /*x------- */
+
+ dev->init_regs[0x0bc] = 0x00;
+ dev->init_regs[0x0bd] = 0x00;
+
+ dev->init_regs[0x165] = (dev->init_regs[0x0165] & 0x3f) | 0x80;
+ dev->init_regs[0x0ed] = 0x10;
+ dev->init_regs[0x0be] = 0x00;
+ dev->init_regs[0x0d5] = 0x00;
+
+ dev->init_regs[0xee] = 0x00;
+ dev->init_regs[0xef] = 0x00;
+ dev->init_regs[0xde] = 0xff;
+
+ /* set bit[4] has_curves = 0 | bit[0..3] unknown = 0 */
+ data_bitset (&dev->init_regs[0xdf], 0x10, 0); /*---x----*/
+ data_bitset (&dev->init_regs[0xdf], 0x0f, 0); /*----xxxx*/
+
+ /* Set motor type */
+ data_bitset (&dev->init_regs[0xd7], 0x80, dev->motorcfg->type); /*x------- */
+
+ if (dev->motorcfg->type == MT_ONCHIP_PWM)
+ {
+ data_bitset (&dev->init_regs[0x14e], 0x10, 1); /*---x----*/
+
+ /* set motorpwmfrequency */
+ data_bitset (&dev->init_regs[0xd7], 0x3f, dev->motorcfg->pwmfrequency); /*--xxxxxx*/
+ }
+
+ dev->init_regs[0x600] &= 0xfb;
+ dev->init_regs[0x1d8] |= 0x08;
+
+ v160c_block_size = 0x04;
+ mem_total = 0x80000;
+
+ /* check and setup installed ram */
+ RTS_DMA_CheckType (dev, dev->init_regs);
+ rst = RTS_DMA_WaitReady (dev, 1500);
+
+ DBG (DBG_FNC, "- Init_Registers: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Read_FE3E (struct st_device *dev, SANE_Byte * destino)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Read_FE3E:\n");
+
+ rst = ERROR;
+ if (destino != NULL)
+ {
+ SANE_Byte data;
+ if (Read_Byte (dev->usb_handle, 0xfe3e, &data) == 0)
+ {
+ *destino = data;
+ rst = OK;
+ DBG (DBG_FNC, " -> %02x\n", _B0 (data));
+ }
+ }
+
+ DBG (DBG_FNC, "- Read_FE3E: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Head_IsAtHome (struct st_device *dev, SANE_Byte * Regs)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Head_IsAtHome:\n");
+
+ /* if returns TRUE, lamp is at home. Otherwise it returns FALSE */
+ rst = 0;
+
+ if (Regs != NULL)
+ {
+ SANE_Byte data;
+ if (Read_Byte (dev->usb_handle, 0xe96f, &data) == OK)
+ {
+ Regs[0x16f] = _B0 (data);
+ rst = (data >> 6) & 1;
+ }
+ }
+
+ rst = (rst == 1) ? TRUE : FALSE;
+
+ DBG (DBG_FNC, "- Head_IsAtHome: %s\n", (rst == TRUE) ? "Yes" : "No");
+
+ return rst;
+}
+
+static SANE_Byte
+RTS_IsExecuting (struct st_device *dev, SANE_Byte * Regs)
+{
+ SANE_Byte rst;
+
+ DBG (DBG_FNC, "+ RTS_IsExecuting:\n");
+
+ rst = 0;
+
+ if (Regs != NULL)
+ {
+ SANE_Byte data;
+ if (Read_Byte (dev->usb_handle, 0xe800, &data) == OK)
+ {
+ Regs[0x00] = data;
+ rst = (data >> 7) & 1;
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_IsExecuting: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_WaitScanEnd (struct st_device *dev, SANE_Int msecs)
+{
+ SANE_Byte data;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_WaitScanEnd(msecs=%i):\n", msecs);
+
+ /* returns 0 if ok or timeout
+ returns -1 if fails */
+
+ rst = ERROR;
+
+ if (Read_Byte (dev->usb_handle, 0xe800, &data) == OK)
+ {
+ long ticks = GetTickCount () + msecs;
+ rst = OK;
+ while (((data & 0x80) != 0) && (ticks > GetTickCount ()) && (rst == OK))
+ {
+ rst = Read_Byte (dev->usb_handle, 0xe800, &data);
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_WaitScanEnd: Ending with rst=%i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_Enable_CCD (struct st_device *dev, SANE_Byte * Regs, SANE_Int channels)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ RTS_Enable_CCD(*Regs, arg2=%i):\n", channels);
+
+ if (Read_Buffer (dev->usb_handle, 0xe810, &Regs[0x10], 4) == OK)
+ {
+ data_bitset (&Regs[0x10], 0xe0, channels); /*xxx----- */
+ data_bitset (&Regs[0x13], 0x80, channels >> 3); /*x------- */
+
+ Write_Buffer (dev->usb_handle, 0xe810, &Regs[0x10], 4);
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- RTS_Enable_CCD: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_Warm_Reset (struct st_device *dev)
+{
+ SANE_Byte data;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_Warm_Reset:\n");
+
+ rst = ERROR;
+ if (Read_Byte (dev->usb_handle, 0xe800, &data) == OK)
+ {
+ data = (data & 0x3f) | 0x40; /*01------ */
+ if (Write_Byte (dev->usb_handle, 0xe800, data) == OK)
+ {
+ data &= 0xbf; /*-0------*/
+ rst = Write_Byte (dev->usb_handle, 0xe800, data);
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_Warm_Reset: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_Status_Timer_Set (struct st_device *dev, SANE_Int minutes)
+{
+ SANE_Byte MyBuffer[2];
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Lamp_Status_Timer_Set(minutes=%i):\n", minutes);
+
+ MyBuffer[0] = dev->init_regs[0x0146] & 0xef;
+ MyBuffer[1] = dev->init_regs[0x0147];
+
+ if (minutes > 0)
+ {
+ double rst, op2;
+
+ minutes = _B0 (minutes);
+ op2 = 2.682163611980331;
+ MyBuffer[0x00] |= 0x10;
+ rst = (minutes * op2);
+ MyBuffer[0x01] = (SANE_Byte) floor (rst);
+ }
+
+ dev->init_regs[0x147] = MyBuffer[1];
+ dev->init_regs[0x146] =
+ (dev->init_regs[0x146] & 0xef) | (MyBuffer[0] & 0x10);
+
+ rst =
+ Write_Word (dev->usb_handle, 0xe946,
+ (SANE_Int) ((MyBuffer[1] << 8) + MyBuffer[0]));
+
+ DBG (DBG_FNC, "- Lamp_Status_Timer_Set: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Buttons_Enable (struct st_device *dev)
+{
+ SANE_Int data, rst;
+
+ DBG (DBG_FNC, "+ Buttons_Enable:\n");
+
+ if (Read_Word (dev->usb_handle, 0xe958, &data) == OK)
+ {
+ data |= 0x0f;
+ rst = Write_Word (dev->usb_handle, 0xe958, data);
+ }
+ else
+ rst = ERROR;
+
+ DBG (DBG_FNC, "- Buttons_Enable: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Buttons_Count (struct st_device *dev)
+{
+ SANE_Int rst = 0;
+
+ /* This chipset supports up to six buttons */
+
+ if (dev->buttons != NULL)
+ rst = dev->buttons->count;
+
+ DBG (DBG_FNC, "> Buttons_Count: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Buttons_Status (struct st_device *dev)
+{
+ SANE_Int rst = -1;
+ SANE_Byte data;
+
+ DBG (DBG_FNC, "+ Buttons_Status\n");
+
+ /* Each bit is 1 if button is not pressed, and 0 if it is pressed
+ This chipset supports up to six buttons */
+
+ if (Read_Byte (dev->usb_handle, 0xe968, &data) == OK)
+ rst = _B0 (data);
+
+ DBG (DBG_FNC, "- Buttons_Status: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Buttons_Released (struct st_device *dev)
+{
+ SANE_Int rst = -1;
+ SANE_Byte data;
+
+ DBG (DBG_FNC, "+ Buttons_Released\n");
+
+ /* Each bit is 1 if button is released, until reading this register. Then
+ entire register is cleared. This chipset supports up to six buttons */
+
+ if (Read_Byte (dev->usb_handle, 0xe96a, &data) == OK)
+ rst = _B0 (data);
+
+ DBG (DBG_FNC, "- Buttons_Released: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Buttons_Order (struct st_device *dev, SANE_Int mask)
+{
+ /* this is a way to order each button according to its bit in register 0xe968 */
+ SANE_Int rst = -1;
+
+ if (dev->buttons != NULL)
+ {
+ SANE_Int a;
+
+ for (a = 0; a < 6; a++)
+ {
+ if (dev->buttons->mask[a] == mask)
+ {
+ rst = a;
+ break;
+ }
+ }
+ }
+
+ return rst;
+}
+
+static SANE_Int
+GainOffset_Clear (struct st_device *dev)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ GainOffset_Clear:\n");
+
+ /* clear offsets */
+ offset[CL_RED] = offset[CL_GREEN] = offset[CL_BLUE] = 0;
+
+ /* save offsets */
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ SANE_Int a;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ RTS_EEPROM_WriteWord (dev->usb_handle, 0x70 + (2 * a), 0);
+
+ /* update checksum */
+ rst = RTS_EEPROM_WriteByte (dev->usb_handle, 0x76, 0);
+ }
+
+ DBG (DBG_FNC, "- GainOffset_Clear: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_Status_Get (struct st_device *dev, SANE_Byte * flb_lamp,
+ SANE_Byte * tma_lamp)
+{
+ /* The only reason that I think windows driver uses two variables to get
+ which lamp is switched on instead of one variable is that some chipset
+ model could have both lamps switched on, so I'm maintaining such var */
+
+ SANE_Int rst = ERROR; /* default */
+
+ DBG (DBG_FNC, "+ Lamp_Status_Get:\n");
+
+ if ((flb_lamp != NULL) && (tma_lamp != NULL))
+ {
+ SANE_Int data1;
+ SANE_Byte data2;
+
+ if (Read_Byte (dev->usb_handle, 0xe946, &data2) == OK)
+ {
+ if (Read_Word (dev->usb_handle, 0xe954, &data1) == OK)
+ {
+ rst = OK;
+
+ *flb_lamp = 0;
+ *tma_lamp = 0;
+
+ switch (dev->chipset->model)
+ {
+ case RTS8822BL_03A:
+ *flb_lamp = ((data2 & 0x40) != 0) ? 1 : 0;
+ *tma_lamp = (((data2 & 0x20) != 0)
+ && ((data1 & 0x10) == 1)) ? 1 : 0;
+ break;
+ default:
+ if ((_B1 (data1) & 0x10) == 0)
+ *flb_lamp = (data2 >> 6) & 1;
+ else
+ *tma_lamp = (data2 >> 6) & 1;
+ break;
+ }
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- Lamp_Status_Get: rst=%i flb=%i tma=%i\n", rst,
+ _B0 (*flb_lamp), _B0 (*tma_lamp));
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_WaitReady (struct st_device *dev, SANE_Int msecs)
+{
+ SANE_Byte data;
+ SANE_Int rst;
+ long mytime;
+
+ DBG (DBG_FNC, "+ RTS_DMA_WaitReady(msecs=%i):\n", msecs);
+
+ rst = OK;
+ mytime = GetTickCount () + msecs;
+
+ while ((mytime > GetTickCount ()) && (rst == OK))
+ {
+ if (Read_Byte (dev->usb_handle, 0xef09, &data) == OK)
+ {
+ if ((data & 1) == 0)
+ usleep (1000 * 100);
+ else
+ break;
+ }
+ else
+ rst = ERROR;
+ }
+
+ DBG (DBG_FNC, "- RTS_DMA_WaitReady: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_WaitInitEnd (struct st_device *dev, SANE_Int msecs)
+{
+ SANE_Byte data;
+ SANE_Int rst;
+ long mytime;
+
+ DBG (DBG_FNC, "+ RTS_WaitInitEnd(msecs=%i):\n", msecs);
+
+ rst = OK;
+ mytime = GetTickCount () + msecs;
+
+ while ((mytime > GetTickCount ()) && (rst == OK))
+ {
+ if (Read_Byte (dev->usb_handle, 0xf910, &data) == OK)
+ {
+ if ((data & 8) == 0)
+ usleep (1000 * 100);
+ else
+ break;
+ }
+ else
+ rst = ERROR;
+ }
+
+ DBG (DBG_FNC, "- RTS_WaitInitEnd: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Motor_Change (struct st_device *dev, SANE_Byte * buffer, SANE_Byte value)
+{
+ SANE_Int data, rst;
+
+ DBG (DBG_FNC, "+ Motor_Change(*buffer, value=%i):\n", value);
+
+ if (Read_Word (dev->usb_handle, 0xe954, &data) == OK)
+ {
+ data &= 0xcf; /*--00----*/
+ value--;
+ switch (value)
+ {
+ case 2:
+ data |= 0x30;
+ break; /*--11----*/
+ case 1:
+ data |= 0x20;
+ break; /*--10----*/
+ case 0:
+ data |= 0x10;
+ break; /*--01----*/
+ }
+
+ buffer[0x154] = _B0 (data);
+
+ rst = Write_Byte (dev->usb_handle, 0xe954, buffer[0x154]);
+ }
+ else
+ rst = ERROR;
+
+ DBG (DBG_FNC, "- Motor_Change: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Read (struct st_device *dev, SANE_Int dmacs, SANE_Int options,
+ SANE_Int size, SANE_Byte * buffer)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC,
+ "+ RTS_DMA_Read(dmacs=%04x, options=%04x, size=%i., *buffer):\n",
+ dmacs, options, size);
+
+ /* is there any buffer to send? */
+ if ((buffer != NULL) && (size > 0))
+ {
+ /* reset dma */
+ if (RTS_DMA_Reset (dev) == OK)
+ {
+ /* prepare dma to read */
+ if (RTS_DMA_Enable_Read (dev, dmacs, size, options) == OK)
+ {
+ SANE_Int transferred;
+
+ rst =
+ Bulk_Operation (dev, BLK_READ, size, buffer, &transferred);
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_DMA_Read(): %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Write (struct st_device *dev, SANE_Int dmacs, SANE_Int options,
+ SANE_Int size, SANE_Byte * buffer)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC,
+ "+ RTS_DMA_Write(dmacs=%04x, options=%04x, size=%i., *buffer):\n",
+ dmacs, options, size);
+
+ /* is there any buffer to send? */
+ if ((buffer != NULL) && (size > 0))
+ {
+ /* reset dma */
+ if (RTS_DMA_Reset (dev) == OK)
+ {
+ /* prepare dma to write */
+ if (RTS_DMA_Enable_Write (dev, dmacs, size, options) == OK)
+ {
+ SANE_Int transferred;
+ SANE_Byte *check_buffer;
+
+ check_buffer = (SANE_Byte *) malloc (size);
+ if (check_buffer != NULL)
+ {
+ /* if some transfer fails we try again until ten times */
+ SANE_Int a;
+ for (a = 10; a > 0; a--)
+ {
+ /* send buffer */
+ Bulk_Operation (dev, BLK_WRITE, size, buffer,
+ &transferred);
+
+ /* prepare dma to read */
+ if (RTS_DMA_Enable_Read (dev, dmacs, size, options) ==
+ OK)
+ {
+ SANE_Int b = 0, diff = FALSE;
+
+ /* read buffer */
+ Bulk_Operation (dev, BLK_READ, size, check_buffer,
+ &transferred);
+
+ /* check buffers */
+ while ((b < size) && (diff == FALSE))
+ {
+ if (buffer[b] == check_buffer[b])
+ b++;
+ else
+ diff = TRUE;
+ }
+
+ /* if buffers are equal we can break loop */
+ if (diff == TRUE)
+ {
+ /* cancel dma */
+ RTS_DMA_Cancel (dev);
+
+ /* prepare dma to write buffer again */
+ if (RTS_DMA_Enable_Write
+ (dev, dmacs, size, options) != OK)
+ break;
+ }
+ else
+ {
+ /* everything went ok */
+ rst = OK;
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ /* free check buffer */
+ free (check_buffer);
+ }
+ else
+ {
+ /* for some reason it's not posible to allocate space to check
+ sent buffer so we just write data */
+ Bulk_Operation (dev, BLK_WRITE, size, buffer, &transferred);
+ rst = OK;
+ }
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_DMA_Write(): %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_CheckType (struct st_device *dev, SANE_Byte * Regs)
+{
+ /* This function tries to detect what kind of RAM supports chipset */
+ /* Returns a value between 0 and 4. -1 means error */
+
+ SANE_Int rst = -1;
+
+ DBG (DBG_FNC, "+ RTS_DMA_CheckType(*Regs):\n");
+
+ if (Regs != NULL)
+ {
+ SANE_Byte *out_buffer;
+
+ /* define buffer to send */
+ out_buffer = (SANE_Byte *) malloc (sizeof (SANE_Byte) * 2072);
+ if (out_buffer != NULL)
+ {
+ SANE_Byte *in_buffer;
+
+ /* define incoming buffer */
+ in_buffer = (SANE_Byte *) malloc (sizeof (SANE_Byte) * 2072);
+ if (in_buffer != NULL)
+ {
+ SANE_Int a, b, diff;
+
+ /* fill outgoing buffer with a known pattern */
+ b = 0;
+ for (a = 0; a < 2072; a++)
+ {
+ out_buffer[a] = b;
+ b++;
+ if (b == 0x61)
+ b = 0;
+ }
+
+ /* let's send buffer with different ram types and compare
+ incoming buffer until getting the right type */
+
+ for (a = 4; a >= 0; a--)
+ {
+ /* set ram type */
+ if (RTS_DMA_SetType (dev, Regs, a) != OK)
+ break;
+
+ /* wait 1500 miliseconds */
+ if (RTS_DMA_WaitReady (dev, 1500) == OK)
+ {
+ /* reset dma */
+ RTS_DMA_Reset (dev);
+
+ /* write buffer */
+ RTS_DMA_Write (dev, 0x0004, 0x102, 2072, out_buffer);
+
+ /* now read buffer */
+ RTS_DMA_Read (dev, 0x0004, 0x102, 2072, in_buffer);
+
+ /* check buffers */
+ b = 0;
+ diff = FALSE;
+ while ((b < 2072) && (diff == FALSE))
+ {
+ if (out_buffer[b] == in_buffer[b])
+ b++;
+ else
+ diff = TRUE;
+ }
+
+ /* if buffers are equal */
+ if (diff == FALSE)
+ {
+ SANE_Int data = 0;
+
+ /* buffers are equal so we've found the right ram type */
+ memset (out_buffer, 0, 0x20);
+ for (b = 0; b < 0x20; b += 2)
+ out_buffer[b] = b;
+
+ /* write buffer */
+ if (RTS_DMA_Write
+ (dev, 0x0004, 0x0000, 0x20, out_buffer) == OK)
+ {
+ SANE_Int c = 0;
+ diff = TRUE;
+
+ do
+ {
+ c++;
+ for (b = 1; b < 0x20; b += 2)
+ out_buffer[b] = c;
+
+ if (RTS_DMA_Write
+ (dev, 0x0004, (_B0 (c) << 0x11) >> 0x04,
+ 0x20, out_buffer) == OK)
+ {
+ if (RTS_DMA_Read
+ (dev, 0x0004, 0x0000, 0x20,
+ in_buffer) == OK)
+ {
+ b = 0;
+ diff = FALSE;
+ while ((b < 0x20)
+ && (diff == FALSE))
+ {
+ if (out_buffer[b] ==
+ in_buffer[b])
+ b++;
+ else
+ diff = TRUE;
+ }
+
+ if (diff == FALSE)
+ data = c << 7;
+ }
+ }
+ }
+ while ((c < 0x80) && (diff == TRUE));
+ }
+
+ switch (data)
+ {
+ case 16384:
+ Regs[0x708] &= 0x1f;
+ Regs[0x708] |= 0x80;
+ break;
+ case 8192:
+ Regs[0x708] &= 0x1f;
+ Regs[0x708] |= 0x60;
+ break;
+ case 4096:
+ Regs[0x708] &= 0x1f;
+ Regs[0x708] |= 0x40;
+ break;
+ case 2048:
+ Regs[0x708] &= 0x1f;
+ Regs[0x708] |= 0x20;
+ break;
+ case 1024:
+ Regs[0x708] &= 0x1f;
+ data = 0x200;
+ break;
+ case 128:
+ Regs[0x708] &= 0x1f;
+ break;
+ }
+
+ DBG (DBG_FNC, " -> data1 = 0x%08x\n",
+ (data * 4) * 1024);
+ DBG (DBG_FNC, " -> data2 = 0x%08x\n", data * 1024);
+ DBG (DBG_FNC, " -> type = 0x%04x\n",
+ Regs[0x708] >> 5);
+
+ RTS_DMA_SetType (dev, Regs, Regs[0x708] >> 5);
+
+ rst = OK;
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ free (in_buffer);
+ }
+
+ free (out_buffer);
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_DMA_CheckType(): %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_SetType (struct st_device *dev, SANE_Byte * Regs, SANE_Byte ramtype)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ RTS_DMA_SetType(*Regs, ramtype=%i):\n", ramtype);
+
+ if (Regs != NULL)
+ {
+ data_bitset (&Regs[0x708], 0x08, 0); /*----0---*/
+
+ if (Write_Byte (dev->usb_handle, 0xef08, Regs[0x708]) == OK)
+ {
+ data_bitset (&Regs[0x708], 0xe0, ramtype);
+
+ if (Write_Byte (dev->usb_handle, 0xef08, Regs[0x708]) == OK)
+ {
+ data_bitset (&Regs[0x708], 0x08, 1); /*----1---*/
+ rst = Write_Byte (dev->usb_handle, 0xef08, Regs[0x708]);
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_DMA_SetType: %i\n", rst);
+
+ return rst;
+}
+
+static void
+Motor_Release (struct st_device *dev)
+{
+ SANE_Byte data = 0;
+
+ DBG (DBG_FNC, "+ Motor_Release:\n");
+
+ if (Read_Byte (dev->usb_handle, 0xe8d9, &data) == OK)
+ {
+ data |= 4;
+ Write_Byte (dev->usb_handle, 0xe8d9, data);
+ }
+
+ DBG (DBG_FNC, "- Motor_Release:\n");
+}
+
+static SANE_Byte
+GainOffset_Counter_Load (struct st_device *dev)
+{
+ SANE_Byte data = 0x0f;
+
+ DBG (DBG_FNC, "+ GainOffset_Counter_Load:\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ if (RTS_EEPROM_ReadByte (dev->usb_handle, 0x77, &data) != OK)
+ data = 0x0f;
+
+ DBG (DBG_FNC, "- GainOffset_Counter_Load: %i\n", _B0 (data));
+
+ return data;
+}
+
+static SANE_Int
+RTS_Execute (struct st_device *dev)
+{
+ SANE_Byte e813, e800;
+ SANE_Int ret;
+
+ DBG (DBG_FNC, "+ RTS_Execute:\n");
+
+ e813 = 0;
+ e800 = 0;
+ ret = ERROR;
+
+ if (Read_Byte (dev->usb_handle, 0xe800, &e800) == OK)
+ {
+ if (Read_Byte (dev->usb_handle, 0xe813, &e813) == OK)
+ {
+ e813 &= 0xbf;
+ if (Write_Byte (dev->usb_handle, 0xe813, e813) == OK)
+ {
+ e800 |= 0x40;
+ if (Write_Byte (dev->usb_handle, 0xe800, e800) == OK)
+ {
+ e813 |= 0x40;
+ if (Write_Byte (dev->usb_handle, 0xe813, e813) == OK)
+ {
+ e800 &= 0xbf;
+ if (Write_Byte (dev->usb_handle, 0xe800, e800) == OK)
+ {
+ usleep (1000 * 100);
+ e800 |= 0x80;
+ ret = Write_Byte (dev->usb_handle, 0xe800, e800);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_Execute: %i\n", ret);
+
+ return ret;
+}
+
+static SANE_Int
+RTS_isTmaAttached (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_isTmaAttached:\n");
+
+ /* returns 0 if Tma is attached. Otherwise 1 */
+ if (Read_Word (dev->usb_handle, 0xe968, &rst) == OK)
+ {
+ rst = ((_B1 (rst) & 2) != 0) ? FALSE : TRUE;
+ }
+ else
+ rst = TRUE;
+
+ DBG (DBG_FNC, "- RTS_isTmaAttached: %s\n", (rst == TRUE) ? "Yes" : "No");
+
+ return rst;
+}
+
+static SANE_Int
+Gamma_AllocTable (SANE_Byte * table)
+{
+ SANE_Int C;
+ SANE_Int rst = OK;
+
+ hp_gamma->depth = 8;
+
+ for (C = 0; C < 3; C++)
+ if (hp_gamma->table[C] == NULL)
+ hp_gamma->table[C] = malloc (sizeof (SANE_Byte) * 256);
+
+ if ((hp_gamma->table[CL_RED] != NULL) &&
+ (hp_gamma->table[CL_GREEN] != NULL) &&
+ (hp_gamma->table[CL_BLUE] != NULL))
+ {
+ /* All tables allocated */
+ for (C = 0; C < 256; C++)
+ {
+ if ((table != NULL) && (RTS_Debug->EnableGamma == TRUE))
+ {
+ /* fill gamma tables with user defined values */
+ hp_gamma->table[CL_RED][C] = table[C];
+ hp_gamma->table[CL_GREEN][C] = table[0x100 + C];
+ hp_gamma->table[CL_BLUE][C] = table[0x200 + C];
+ }
+ else
+ {
+ hp_gamma->table[CL_RED][C] = C;
+ hp_gamma->table[CL_GREEN][C] = C;
+ hp_gamma->table[CL_BLUE][C] = C;
+ }
+ }
+
+ /* Locate threshold of bw */
+ for (C = 0; C < 256; C++)
+ if (hp_gamma->table[CL_RED][C] != 0)
+ break;
+
+ bw_threshold = C - 1;
+ }
+ else
+ {
+ /* Some alloc failed */
+ rst = ERROR;
+
+ Gamma_FreeTables ();
+ }
+
+ DBG (DBG_FNC, "> Gamma_AllocTable: %i >> bw_threshold = %i\n", rst,
+ bw_threshold);
+
+ return rst;
+}
+
+static SANE_Int
+Gamma_Apply (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, struct st_hwdconfig *hwdcfg,
+ struct st_gammatables *mygamma)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Gamma_Apply(*Regs, *scancfg, *hwdcfg, *mygamma):\n");
+ dbg_ScanParams (scancfg);
+
+ if (hwdcfg->use_gamma_tables == FALSE)
+ {
+ DBG (DBG_FNC, "-> Gamma tables are not used\n");
+
+ v1600 = NULL;
+ v1604 = NULL;
+ v1608 = NULL;
+ }
+ else
+ {
+ /*390b */
+ SANE_Int table_size, buffersize, c;
+ SANE_Byte channels, *gammabuffer;
+
+ DBG (DBG_FNC, "-> Using gamma tables\n");
+
+ /* get channels count */
+ channels = 3; /* default */
+
+ if (scancfg->colormode != CM_COLOR)
+ {
+ if (scancfg->channel != 3)
+ {
+ if (scancfg->colormode != 3)
+ channels = (scancfg->samplerate == PIXEL_RATE) ? 2 : 1;
+ }
+ }
+
+ /* get size for gamma tables */
+ switch (mygamma->depth & 0x0c)
+ {
+ case 0:
+ table_size = 0x100 + (mygamma->depth & 1);
+ break;
+ case 4:
+ table_size = 0x400 + (mygamma->depth & 1);
+ break;
+ case 8:
+ table_size = 0x1000 + (mygamma->depth & 1);
+ break;
+ default:
+ table_size = 2;
+ break;
+ }
+
+ /* allocate space for gamma buffer */
+ buffersize = table_size * channels;
+ gammabuffer = (SANE_Byte *) malloc (buffersize * sizeof (SANE_Byte));
+ if (gammabuffer != NULL)
+ {
+ /* update gamma pointers for each channel */
+ v1600 = (SANE_Byte *) & mygamma->table[CL_RED];
+ v1604 = (SANE_Byte *) & mygamma->table[CL_GREEN];
+ v1608 = (SANE_Byte *) & mygamma->table[CL_BLUE];
+
+ /* include gamma tables into one buffer */
+ for (c = 0; c < channels; c++)
+ memcpy (gammabuffer + (c * table_size), mygamma->table[c],
+ table_size);
+
+ /* send gamma buffer to scanner */
+ Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b] & 0xaf);
+ rst = Gamma_SendTables (dev, Regs, gammabuffer, buffersize);
+ Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b]);
+
+ /* free gamma buffer */
+ free (gammabuffer);
+ }
+ else
+ rst = ERROR;
+ }
+
+ return rst;
+}
+
+static SANE_Int
+Refs_Analyze_Pattern (struct st_scanparams *scancfg,
+ SANE_Byte * scanned_pattern, SANE_Int * ler1,
+ SANE_Int ler1order, SANE_Int * ser1, SANE_Int ser1order)
+{
+ SANE_Int buffersize, xpos, ypos, coord, cnt, chn_size, dist, rst;
+ double *color_sum, *color_dif, diff_max;
+ SANE_Int vector[3];
+
+ DBG (DBG_FNC,
+ "+ Refs_Analyze_Pattern(depth=%i, width=%i, height=%i, *scanned_pattern, *ler1, ler1order=%i, *ser1, ser1order=%i)\n",
+ scancfg->depth, scancfg->coord.width, scancfg->coord.height, ler1order,
+ ser1order);
+
+ rst = ERROR; /* by default */
+ dist = 5; /* distance to compare */
+ chn_size = (scancfg->depth > 8) ? 2 : 1;
+ buffersize = max (scancfg->coord.width, scancfg->coord.height);
+
+ color_sum = (double *) malloc (sizeof (double) * buffersize);
+ if (color_sum != NULL)
+ {
+ color_dif = (double *) malloc (sizeof (double) * buffersize);
+ if (color_dif != NULL)
+ {
+ /*-------- 1st SER -------- */
+ coord = 1;
+
+ if ((scancfg->coord.width - dist) > 1)
+ {
+ /* clear buffers */
+ bzero (color_sum, sizeof (double) * buffersize);
+ bzero (color_dif, sizeof (double) * buffersize);
+
+ for (xpos = 0; xpos < scancfg->coord.width; xpos++)
+ {
+ for (ypos = 0; ypos < 20; ypos++)
+ color_sum[xpos] +=
+ data_lsb_get (scanned_pattern +
+ (scancfg->coord.width * ypos) + xpos,
+ chn_size);
+ }
+
+ diff_max =
+ (ser1order !=
+ 0) ? color_sum[0] - color_sum[1] : color_sum[1] -
+ color_sum[0];
+ color_dif[0] = diff_max;
+ cnt = 1;
+
+ do
+ {
+ color_dif[cnt] =
+ (ser1order !=
+ 0) ? color_sum[cnt] - color_sum[cnt +
+ dist] : color_sum[cnt +
+ dist] -
+ color_sum[cnt];
+
+ if ((color_dif[cnt] >= 0) && (color_dif[cnt] > diff_max))
+ {
+ /*d4df */
+ diff_max = color_dif[cnt];
+ if (abs (color_dif[cnt] - color_dif[cnt - 1]) >
+ abs (color_dif[coord] - color_dif[coord - 1]))
+ coord = cnt;
+ }
+
+ cnt++;
+ }
+ while (cnt < (scancfg->coord.width - dist));
+ }
+
+ vector[0] = coord + dist;
+
+ /*-------- 1st LER -------- */
+ coord = 1;
+
+ if ((scancfg->coord.height - dist) > 1)
+ {
+ /* clear buffers */
+ bzero (color_sum, sizeof (double) * buffersize);
+ bzero (color_dif, sizeof (double) * buffersize);
+
+ for (ypos = 0; ypos < scancfg->coord.height; ypos++)
+ {
+ for (xpos = vector[0]; xpos < scancfg->coord.width - dist;
+ xpos++)
+ color_sum[ypos] +=
+ data_lsb_get (scanned_pattern +
+ (scancfg->coord.width * ypos) + xpos,
+ chn_size);
+ }
+
+ diff_max =
+ (ler1order !=
+ 0) ? color_sum[0] - color_sum[1] : color_sum[1] -
+ color_sum[0];
+ color_dif[0] = diff_max;
+
+ cnt = 1;
+
+ do
+ {
+ color_dif[cnt] =
+ (ler1order !=
+ 0) ? color_sum[cnt] - color_sum[cnt +
+ dist] : color_sum[cnt +
+ dist] -
+ color_sum[cnt];
+
+ if ((color_dif[cnt] >= 0) && (color_dif[cnt] > diff_max))
+ {
+ diff_max = color_dif[cnt];
+ if (abs (color_dif[cnt] - color_dif[cnt - 1]) >
+ abs (color_dif[coord] - color_dif[coord - 1]))
+ coord = cnt;
+ }
+
+ cnt++;
+ }
+ while (cnt < (scancfg->coord.height - dist));
+ }
+
+ vector[1] = coord + dist;
+
+ /*-------- 1st LER -------- */
+ if ((scancfg->coord.width - dist) > 1)
+ {
+ /* clear buffers */
+ bzero (color_sum, sizeof (double) * buffersize);
+ bzero (color_dif, sizeof (double) * buffersize);
+
+ for (xpos = 0; xpos < scancfg->coord.width; xpos++)
+ {
+ for (ypos = coord + 4; ypos < scancfg->coord.height; ypos++)
+ color_sum[xpos] +=
+ data_lsb_get (scanned_pattern +
+ (scancfg->coord.width * ypos) + xpos,
+ chn_size);
+ }
+
+ diff_max =
+ (ser1order !=
+ 0) ? color_sum[0] - color_sum[1] : color_sum[1] -
+ color_sum[0];
+ color_dif[0] = diff_max;
+ cnt = 1;
+
+ do
+ {
+ color_dif[cnt] =
+ (ser1order !=
+ 0) ? color_sum[cnt] - color_sum[cnt +
+ dist] : color_sum[cnt +
+ dist] -
+ color_sum[cnt];
+
+ if ((color_dif[cnt] >= 0) && (color_dif[cnt] > diff_max))
+ {
+ diff_max = color_dif[cnt];
+ if (abs (color_dif[cnt] - color_dif[cnt - 1]) >
+ abs (color_dif[coord] - color_dif[coord - 1]))
+ coord = cnt;
+ }
+
+ cnt++;
+ }
+ while (cnt < (scancfg->coord.width - dist));
+ }
+
+ vector[2] = coord + dist;
+
+ /* save image */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ dbg_autoref (scancfg, scanned_pattern, vector[0], vector[2],
+ vector[1]);
+
+ /* assign values detected */
+ if (ser1 != NULL)
+ *ser1 = vector[2];
+
+ if (ler1 != NULL)
+ *ler1 = vector[1];
+
+ /* show values */
+ DBG (DBG_FNC, " -> Vectors found: x1=%i, x2=%i, y=%i\n", vector[0],
+ vector[2], vector[1]);
+
+ rst = OK;
+
+ free (color_dif);
+ }
+
+ free (color_sum);
+ }
+
+ DBG (DBG_FNC, "- Refs_Analyze_Pattern: %i\n", rst);
+
+ return rst;
+}
+
+static double
+get_shrd (double value, SANE_Int desp)
+{
+ if (desp <= 0x40)
+ return value / pow (2, desp);
+ else
+ return 0;
+}
+
+static char
+get_byte (double value)
+{
+ unsigned int data;
+ double temp;
+
+ if (value > 0xffffffff)
+ {
+ temp = floor (get_shrd (value, 0x20));
+ temp *= pow (2, 32);
+ value -= temp;
+ }
+
+ data = (unsigned int) value;
+
+ data = _B0 (data);
+
+ return data;
+}
+
+static SANE_Int
+Timing_SetLinearImageSensorClock (SANE_Byte * Regs, struct st_cph *cph)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC,
+ "+ Timing_SetLinearImageSensorClock(SANE_Byte *Regs, struct st_cph *cph)\n");
+
+ dbg_sensorclock (cph);
+
+ if ((Regs != NULL) && (cph != NULL))
+ {
+ Regs[0x00] = get_byte (cph->p1);
+ Regs[0x01] = get_byte (get_shrd (cph->p1, 0x08));
+ Regs[0x02] = get_byte (get_shrd (cph->p1, 0x10));
+ Regs[0x03] = get_byte (get_shrd (cph->p1, 0x18));
+
+ Regs[0x04] &= 0x80;
+ Regs[0x04] |= ((get_byte (get_shrd (cph->p1, 0x20))) & 0x0f);
+ Regs[0x04] |= ((cph->ps & 1) << 6);
+ Regs[0x04] |= ((cph->ge & 1) << 5);
+ Regs[0x04] |= ((cph->go & 1) << 4);
+
+ Regs[0x05] = get_byte (cph->p2);
+ Regs[0x06] = get_byte (get_shrd (cph->p2, 0x08));
+ Regs[0x07] = get_byte (get_shrd (cph->p2, 0x10));
+ Regs[0x08] = get_byte (get_shrd (cph->p2, 0x18));
+ Regs[0x09] &= 0xf0;
+ Regs[0x09] |= ((get_byte (get_shrd (cph->p2, 0x20))) & 0x0f);
+
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- Timing_SetLinearImageSensorClock: %i\n", rst);
+
+ return rst;
+}
+
+static void
+RTS_Setup_SensorTiming (struct st_device *dev, SANE_Int mytiming,
+ SANE_Byte * Regs)
+{
+ DBG (DBG_FNC, "+ RTS_Setup_SensorTiming(mytiming=%i, *Regs):\n", mytiming);
+
+ if ((Regs != NULL) && (mytiming < dev->timings_count))
+ {
+ struct st_timing *mt = dev->timings[mytiming];
+
+ if (mt != NULL)
+ {
+ dbg_timing (mt);
+
+ /* Correlated-Double-Sample 1 & 2 */
+ data_bitset (&Regs[0x92], 0x3f, mt->cdss[0]);
+ data_bitset (&Regs[0x93], 0x3f, mt->cdsc[0]);
+ data_bitset (&Regs[0x94], 0x3f, mt->cdss[1]);
+ data_bitset (&Regs[0x95], 0x3f, mt->cdsc[1]);
+
+ data_bitset (&Regs[0x96], 0x3f, mt->cnpp);
+
+ /* Linear image sensor transfer gates */
+ data_bitset (&Regs[0x45], 0x80, mt->cvtrp[0]);
+ data_bitset (&Regs[0x45], 0x40, mt->cvtrp[1]);
+ data_bitset (&Regs[0x45], 0x20, mt->cvtrp[2]);
+
+ data_bitset (&Regs[0x45], 0x1f, mt->cvtrfpw);
+ data_bitset (&Regs[0x46], 0x1f, mt->cvtrbpw);
+
+ data_lsb_set (&Regs[0x47], mt->cvtrw, 1);
+
+ data_lsb_set (&Regs[0x84], mt->cphbp2s, 3);
+ data_lsb_set (&Regs[0x87], mt->cphbp2e, 3);
+
+ data_lsb_set (&Regs[0x8a], mt->clamps, 3);
+ data_lsb_set (&Regs[0x8d], mt->clampe, 3);
+
+ if (dev->chipset->model == RTS8822L_02A)
+ {
+ if (mt->clampe == -1)
+ data_lsb_set (&Regs[0x8d], mt->cphbp2e, 3);
+ }
+
+ Regs[0x97] = get_byte (mt->adcclkp[0]);
+ Regs[0x98] = get_byte (get_shrd (mt->adcclkp[0], 0x08));
+ Regs[0x99] = get_byte (get_shrd (mt->adcclkp[0], 0x10));
+ Regs[0x9a] = get_byte (get_shrd (mt->adcclkp[0], 0x18));
+ Regs[0x9b] &= 0xf0;
+ Regs[0x9b] |= ((get_byte (get_shrd (mt->adcclkp[0], 0x20))) & 0x0f);
+
+ Regs[0xc1] = get_byte (mt->adcclkp[1]);
+ Regs[0xc2] = get_byte (get_shrd (mt->adcclkp[1], 0x08));
+ Regs[0xc3] = get_byte (get_shrd (mt->adcclkp[1], 0x10));
+ Regs[0xc4] = get_byte (get_shrd (mt->adcclkp[1], 0x18));
+ Regs[0xc5] &= 0xe0;
+ Regs[0xc5] |= ((get_byte (get_shrd (mt->adcclkp[1], 0x20))) & 0x0f);
+
+ /* bit(4) = bit(0) */
+ Regs[0xc5] |= ((mt->adcclkp2e & 1) << 4);
+
+ Timing_SetLinearImageSensorClock (&Regs[0x48], &mt->cph[0]);
+ Timing_SetLinearImageSensorClock (&Regs[0x52], &mt->cph[1]);
+ Timing_SetLinearImageSensorClock (&Regs[0x5c], &mt->cph[2]);
+ Timing_SetLinearImageSensorClock (&Regs[0x66], &mt->cph[3]);
+ Timing_SetLinearImageSensorClock (&Regs[0x70], &mt->cph[4]);
+ Timing_SetLinearImageSensorClock (&Regs[0x7a], &mt->cph[5]);
+ }
+ }
+}
+
+static SANE_Int
+Motor_GetFromResolution (SANE_Int resolution)
+{
+ SANE_Int ret;
+
+ ret = 3;
+ if (RTS_Debug->usbtype != USB11)
+ {
+ if (scan.scantype != ST_NORMAL)
+ {
+ /* scantype is ST_NEG or ST_TA */
+ if (resolution >= 600)
+ ret = 0;
+ }
+ else if (resolution >= 1200)
+ ret = 0;
+ }
+ else if (resolution >= 600)
+ ret = 0;
+
+ DBG (DBG_FNC, "> Motor_GetFromResolution(resolution=%i): %i\n", resolution,
+ ret);
+
+ return ret;
+}
+
+static SANE_Int
+SetMultiExposure (struct st_device *dev, SANE_Byte * Regs)
+{
+ SANE_Int iValue, myctpc;
+
+ DBG (DBG_FNC, "> SetMultiExposure:\n");
+
+ /* set motor has no curves */
+ data_bitset (&Regs[0xdf], 0x10, 0); /*---0----*/
+
+ /* select case systemclock */
+ switch (Regs[0x00] & 0x0f)
+ {
+ case 0x00:
+ iValue = 0x00895440;
+ break; /* 3 x 0x2DC6C0 */
+ case 0x08:
+ case 0x01:
+ iValue = 0x00b71b00;
+ break; /* 4 x 0x2DC6C0 */
+ case 0x02:
+ iValue = 0x0112a880;
+ break; /* 6 x 0x2DC6C0 */
+ case 0x0a:
+ case 0x03:
+ iValue = 0x016e3600;
+ break; /* 8 x 0x2DC6C0 */
+ case 0x04:
+ iValue = 0x02255100;
+ break; /* 12 x 0x2DC6C0 */
+ case 0x0c:
+ iValue = 0x02dc6c00;
+ break; /* 16 x 0x2DC6C0 */
+ case 0x05:
+ iValue = 0x044aa200;
+ break; /* 24 x 0x2DC6C0 */
+ case 0x0d:
+ iValue = 0x05b8d800;
+ break; /* 32 x 0x2DC6C0 */
+
+ case 0x09:
+ iValue = 0x00f42400;
+ break;
+ case 0x0b:
+ iValue = 0x01e84800;
+ break; /* = case 9 * 2 */
+ default:
+ iValue = 0x0478f7f8;
+ break;
+ }
+
+ /* divide by timing.cnpp */
+ iValue /= ((Regs[0x96] & 0x3f) + 1);
+ iValue /= dev->motorcfg->basespeedpps;
+
+ /* get line exposure time */
+ myctpc = data_lsb_get (&Regs[0x30], 3) + 1;
+
+ DBG (DBG_FNC, "CTPC -- SetMultiExposure -- 1 =%i\n", myctpc);
+
+ /* if last step of accurve.normalscan table is lower than iValue ... */
+ if (data_lsb_get (&Regs[0xe1], 3) < iValue)
+ {
+ SANE_Int traget;
+ SANE_Int step_size = _B0 (Regs[0xe0]) + 1;
+
+ /* set exposure time [RED] if zero */
+ if (data_lsb_get (&Regs[0x36], 3) == 0)
+ data_lsb_set (&Regs[0x36], myctpc - 1, 3);
+
+ /* set exposure time [GREEN] if zero */
+ if (data_lsb_get (&Regs[0x3c], 3) == 0)
+ data_lsb_set (&Regs[0x3c], myctpc - 1, 3);
+
+ /* set exposure time [BLUE] if zero */
+ if (data_lsb_get (&Regs[0x42], 3) == 0)
+ data_lsb_set (&Regs[0x42], myctpc - 1, 3);
+
+ iValue = (iValue + 1) * step_size;
+
+ /* update line exposure time */
+ traget = (((myctpc + iValue - 1) / myctpc) * myctpc);
+ data_lsb_set (&Regs[0x30], traget - 1, 3);
+
+ traget = (traget / step_size) - 1;
+ data_lsb_set (&Regs[0x00e1], traget, 3);
+ }
+
+ /* 8300 */
+ return OK;
+}
+
+static SANE_Int
+data_lsb_get (SANE_Byte * address, SANE_Int size)
+{
+ SANE_Int ret = 0;
+ if ((address != NULL) && (size > 0) && (size < 5))
+ {
+ SANE_Int a;
+ SANE_Byte b;
+ size--;
+ for (a = size; a >= 0; a--)
+ {
+ b = address[a];
+ ret = (ret << 8) + b;
+ }
+ }
+ return ret;
+}
+
+static SANE_Byte
+data_bitget (SANE_Byte * address, SANE_Int mask)
+{
+ SANE_Int desp = 0;
+
+ if (mask & 1);
+ else if (mask & 2)
+ desp = 1;
+ else if (mask & 4)
+ desp = 2;
+ else if (mask & 8)
+ desp = 3;
+ else if (mask & 16)
+ desp = 4;
+ else if (mask & 32)
+ desp = 5;
+ else if (mask & 64)
+ desp = 6;
+ else if (mask & 128)
+ desp = 7;
+
+ return (*address & mask) >> desp;
+}
+
+static void
+data_bitset (SANE_Byte * address, SANE_Int mask, SANE_Byte data)
+{
+ /* This function fills mask bits of just a byte with bits given in data */
+ if (mask & 1);
+ else if (mask & 2)
+ data <<= 1;
+ else if (mask & 4)
+ data <<= 2;
+ else if (mask & 8)
+ data <<= 3;
+ else if (mask & 16)
+ data <<= 4;
+ else if (mask & 32)
+ data <<= 5;
+ else if (mask & 64)
+ data <<= 6;
+ else if (mask & 128)
+ data <<= 7;
+
+ *address = (*address & (0xff - mask)) | (data & mask);
+}
+
+static void
+data_wide_bitset (SANE_Byte * address, SANE_Int mask, SANE_Int data)
+{
+ /* Setting bytes bit per bit
+ mask is 4 bytes size
+ Example:
+ data = 0111010111
+ mask = 00000000 11111111 11000000 00000000
+ rst = 00000000 01110101 11000000 00000000 */
+
+ SANE_Int mymask, started = FALSE;
+
+ if ((address != NULL) && (mask != 0))
+ {
+ while (mask != 0)
+ {
+ mymask = _B0 (mask);
+
+ if (started == FALSE)
+ {
+ if (mymask != 0)
+ {
+ SANE_Int a, myvalue;
+
+ for (a = 0; a < 8; a++)
+ if ((mymask & (1 << a)) != 0)
+ break;
+
+ myvalue = _B0 (data << a);
+ myvalue >>= a;
+ data_bitset (address, mymask, myvalue);
+ data >>= (8 - a);
+ started = TRUE;
+ }
+ }
+ else
+ {
+ data_bitset (address, mymask, _B0 (data));
+ data >>= 8;
+ }
+
+ address++;
+ mask >>= 8;
+ }
+ }
+}
+
+
+static void
+data_lsb_set (SANE_Byte * address, SANE_Int data, SANE_Int size)
+{
+ if ((address != NULL) && (size > 0) && (size < 5))
+ {
+ SANE_Int a;
+ for (a = 0; a < size; a++)
+ {
+ address[a] = _B0 (data);
+ data >>= 8;
+ }
+ }
+}
+
+static void
+data_msb_set (SANE_Byte * address, SANE_Int data, SANE_Int size)
+{
+ if ((address != NULL) && (size > 0) && (size < 5))
+ {
+ SANE_Int a;
+
+ for (a = size - 1; a >= 0; a--)
+ {
+ address[a] = _B0 (data);
+ data >>= 8;
+ }
+ }
+}
+
+static SANE_Int
+data_swap_endianess (SANE_Int address, SANE_Int size)
+{
+ SANE_Int rst = 0;
+
+ if ((size > 0) && (size < 5))
+ {
+ SANE_Int a;
+
+ for (a = 0; a < size; a++)
+ {
+ rst = (rst << 8) | _B0 (address);
+ address >>= 8;
+ }
+ }
+
+ return rst;
+}
+
+static void
+Lamp_SetGainMode (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int resolution, SANE_Byte gainmode)
+{
+ DBG (DBG_FNC, "> Lamp_SetGainMode(*Regs, resolution=%i, gainmode=%i):\n",
+ resolution, gainmode);
+
+ if (dev->chipset->model == RTS8822L_02A)
+ {
+ /* hp4370 */
+ SANE_Int data1, data2;
+
+ data1 = data_lsb_get (&Regs[0x154], 2) & 0xfe7f;
+ data2 = data_lsb_get (&Regs[0x156], 2);
+
+ switch (resolution)
+ {
+ case 4800:
+ data2 |= 0x40;
+ data1 &= 0xffbf;
+ break;
+ case 100:
+ case 150:
+ case 200:
+ case 300:
+ case 600:
+ case 1200:
+ case 2400:
+ data1 |= 0x40;
+ data2 &= 0xffbf;
+ break;
+ }
+
+ data_lsb_set (&Regs[0x154], data1, 2);
+ data_lsb_set (&Regs[0x156], data2, 2);
+ }
+ else
+ {
+ /* hp3970 hp4070 ua4900 */
+ SANE_Int data;
+
+ data = data_lsb_get (&Regs[0x154], 2) & 0xfe7f;
+ data = (gainmode == FALSE) ? data | 0x0040 : data & 0xffbf;
+
+ switch (resolution)
+ {
+ case 100:
+ case 200:
+ case 300:
+ case 600:
+ data |= 0x0100;
+ break;
+ case 2400:
+ data |= 0x0180;
+ break;
+ case 1200:
+ if (dev->sensorcfg->type == CIS_SENSOR)
+ data |= 0x80;
+ else if (dev->sensorcfg->type == CCD_SENSOR)
+ data |= 0x0180;
+ break;
+ }
+
+ data_lsb_set (&Regs[0x0154], data, 2);
+ }
+}
+
+static SANE_Int
+RTS_Scanner_StartScan (struct st_device *dev)
+{
+ SANE_Int rst = ERROR; /* default */
+ SANE_Int data;
+
+ DBG (DBG_FNC, "+ RTS_Scanner_StartScan():\n");
+
+ v14b4 = 1; /* TEMPORAL */
+ data = 0;
+ Lamp_PWM_DutyCycle_Get (dev, &data);
+ data = _B0 (data);
+
+ DBG (DBG_FNC, "-> Pwm used = %i\n", data);
+
+ /*
+ windows driver saves pwm used, in file usbfile
+ Section [SCAN_PARAM], field PwmUsed
+ */
+
+ dev->status->cancel = FALSE;
+
+ if (Scan_Start (dev) == OK)
+ {
+ SANE_Int transferred;
+
+ rst = OK;
+
+ if (dev->scanning->imagebuffer != NULL)
+ {
+ free (dev->scanning->imagebuffer);
+ dev->scanning->imagebuffer = NULL;
+ }
+
+ SetLock (dev->usb_handle, NULL, (scan2.depth == 16) ? FALSE : TRUE);
+
+ /* Reservamos los buffers necesarios para leer la imagen */
+ Reading_CreateBuffers (dev);
+
+ if (dev->Resize->type != RSZ_NONE)
+ Resize_Start (dev, &transferred); /* 6729 */
+
+ RTS_ScanCounter_Inc (dev);
+ }
+
+ DBG (DBG_FNC, "- RTS_Scanner_StartScan: %i\n", rst);
+
+ return rst;
+}
+
+static void
+Triplet_Gray (SANE_Byte * pPointer1, SANE_Byte * pPointer2,
+ SANE_Byte * buffer, SANE_Int channels_count)
+{
+ /*
+ pPointer1 = FAB8
+ pPointer2 = FABC
+ buffer = FAC0
+ channels_count = FAC4
+ */
+
+ SANE_Int value;
+ SANE_Int channel_size;
+
+ DBG (DBG_FNC,
+ "> Triplet_Gray(*pPointer1, *pPointer2, *buffer, channels_count=%i)\n",
+ channels_count);
+
+ channel_size = (scan2.depth > 8) ? 2 : 1;
+ channels_count = channels_count / 2;
+
+ while (channels_count > 0)
+ {
+ value = data_lsb_get (pPointer1, channel_size);
+ data_lsb_set (buffer, value, channel_size);
+
+ value = data_lsb_get (pPointer2, channel_size);
+ data_lsb_set (buffer + channel_size, value, channel_size);
+
+ pPointer1 += 2 * channel_size;
+ pPointer2 += 2 * channel_size;
+ buffer += 2 * channel_size;
+
+ channels_count--;
+ }
+}
+
+static void
+Triplet_Lineart (SANE_Byte * pPointer1, SANE_Byte * pPointer2,
+ SANE_Byte * buffer, SANE_Int channels_count)
+{
+ /* Composing colour in lineart mode */
+
+ SANE_Int dots_count = 0;
+ SANE_Int channel;
+ SANE_Byte mask;
+ SANE_Byte value;
+ SANE_Int C;
+
+ DBG (DBG_FNC,
+ "> Triplet_Lineart(*pPointer1, *pPointer2, *buffer, channels_count=%i)\n",
+ channels_count);
+
+ if (channels_count > 0)
+ {
+ dots_count = (channels_count + 1) / 2;
+ while (dots_count > 0)
+ {
+ mask = 0x80;
+ channel = 2;
+ do
+ {
+ value = 0;
+ for (C = 4; C > 0; C--)
+ {
+ value =
+ (value << 2) +
+ (((*pPointer2 & mask) << 1) | (*pPointer1 & mask));
+ mask = mask >> 1;
+ }
+ *buffer = value;
+ buffer++;
+ channel--;
+ }
+ while (channel > 0);
+ pPointer2 += 2;
+ pPointer1 += 2;
+ dots_count--;
+ }
+ }
+}
+
+static SANE_Int
+Arrange_NonColour (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Int * transferred)
+{
+ /*
+ buffer : fadc
+ buffer_size : fae0
+ */
+
+ SANE_Int lines_count = 0; /* ebp */
+ SANE_Int channels_count = 0; /* fadc pisa buffer */
+ SANE_Int rst = ERROR;
+ struct st_scanning *scn;
+
+ DBG (DBG_FNC,
+ "+ Arrange_NonColour(*buffer, buffer_size=%i, *transferred):\n",
+ buffer_size);
+
+ /* this is just to make code more legible */
+ scn = dev->scanning;
+
+ if (scn->imagebuffer == NULL)
+ {
+ if ((scn->arrange_hres == TRUE) || (scan2.colormode == CM_LINEART))
+ {
+ scn->bfsize = (scn->arrange_sensor_evenodd_dist + 1) * line_size;
+ scn->imagebuffer =
+ (SANE_Byte *) malloc (scn->bfsize * sizeof (SANE_Byte));
+ if (scn->imagebuffer != NULL)
+ {
+ if (Read_Block (dev, scn->bfsize, scn->imagebuffer, transferred)
+ == OK)
+ {
+ scn->channel_size = (scan2.depth == 8) ? 1 : 2;
+ scn->desp1[CL_RED] = 0;
+ scn->desp2[CL_RED] =
+ scn->channel_size +
+ (scn->arrange_sensor_evenodd_dist * line_size);
+ scn->pColour2[CL_RED] =
+ scn->imagebuffer + scn->desp2[CL_RED];
+ scn->pColour1[CL_RED] =
+ scn->imagebuffer + scn->desp1[CL_RED];
+ rst = OK;
+ }
+ }
+ }
+ }
+ else
+ rst = OK;
+
+ /* b0f4 */
+ if (rst == OK)
+ {
+ scn->imagepointer = scn->imagebuffer;
+ lines_count = buffer_size / line_size;
+ channels_count = line_size / scn->channel_size;
+ while (lines_count > 0)
+ {
+ if (scan2.colormode == CM_LINEART)
+ Triplet_Lineart (scn->pColour1[CL_RED], scn->pColour2[CL_RED],
+ buffer, channels_count);
+ else
+ Triplet_Gray (scn->pColour1[CL_RED], scn->pColour2[CL_RED],
+ buffer, channels_count);
+
+ buffer += line_size;
+ scn->arrange_size -= bytesperline;
+
+ lines_count--;
+ if (lines_count == 0)
+ {
+ if ((scn->arrange_size | v15bc) == 0)
+ break;
+ }
+
+ rst = Read_Block (dev, line_size, scn->imagepointer, transferred);
+ if (rst != OK)
+ break;
+
+ if (scn->arrange_hres == TRUE)
+ {
+ scn->desp2[CL_RED] =
+ (line_size + scn->desp2[CL_RED]) % scn->bfsize;
+ scn->desp1[CL_RED] =
+ (line_size + scn->desp1[CL_RED]) % scn->bfsize;
+
+ scn->pColour2[CL_RED] = scn->imagebuffer + scn->desp2[CL_RED];
+ scn->pColour1[CL_RED] = scn->imagebuffer + scn->desp1[CL_RED];
+ }
+
+ /* b21d */
+ scn->imagepointer += line_size;
+ if (scn->imagepointer >= (scn->imagebuffer + scn->bfsize))
+ scn->imagepointer = scn->imagebuffer;
+ }
+ }
+
+ /* 2246 */
+
+ DBG (DBG_FNC, "- Arrange_NonColour(*transferred=%i): %i\n", *transferred,
+ rst);
+
+ return rst;
+}
+
+static SANE_Int
+Resize_Decrease (SANE_Byte * to_buffer, SANE_Int to_resolution,
+ SANE_Int to_width, SANE_Byte * from_buffer,
+ SANE_Int from_resolution, SANE_Int from_width,
+ SANE_Int myresize_mode)
+{
+ /*
+ to_buffer = FAC8 = 0x236200
+ to_resolution = FACC = 0x4b
+ to_width = FAD0 = 0x352
+ from_buffer = FAD4 = 0x235460
+ from_resolution = FAD8 = 0x64
+ from_width = FADC = 0x46d
+ myresize_mode = FAE0 = 1
+ */
+
+ SANE_Int rst = ERROR;
+ SANE_Int channels = 0; /* fac8 */
+ SANE_Int depth = 0; /* fae0 */
+ SANE_Int color[3] = { 0, 0, 0 }; /* fab8 | fabc | fac0 */
+ SANE_Int to_pos = 0; /* fad4 */
+ SANE_Int rescont = 0;
+ SANE_Int from_pos = 0; /* fab4 */
+ SANE_Int C;
+ SANE_Int smres = 0; /* fab0 */
+ SANE_Int value;
+ SANE_Int channel_size;
+
+ to_resolution = to_resolution & 0xffff;
+ from_resolution = from_resolution & 0xffff;
+
+ DBG (DBG_FNC,
+ "+ Resize_Decrease(*to_buffer, to_resolution=%i, to_width=%i, *from_buffer, from_resolution=%i, from_width=%i, myresize_mode=%i):\n",
+ to_resolution, to_width, from_resolution, from_width, myresize_mode);
+
+ if (myresize_mode != RSZ_LINEART)
+ {
+ switch (myresize_mode)
+ {
+ case RSZ_GRAYL:
+ channels = 1;
+ depth = 8;
+ break;
+ case RSZ_COLOURL:
+ channels = 3;
+ depth = 8;
+ break;
+ case RSZ_COLOURH:
+ channels = 3;
+ depth = 16;
+ break;
+ case RSZ_GRAYH:
+ channels = 1;
+ depth = 16;
+ break;
+ }
+
+ channel_size = (depth > 8) ? 2 : 1;
+ to_pos = 0;
+ rescont = 0;
+
+ while (to_pos < to_width)
+ {
+ from_pos++;
+ if (from_pos > from_width)
+ from_buffer -= (((depth + 7) / 8) * channels);
+
+ rescont += to_resolution;
+ if (rescont < from_resolution)
+ {
+ /* Adds 3 color channel values */
+ for (C = 0; C < channels; C++)
+ {
+ color[C] +=
+ data_lsb_get (from_buffer, channel_size) * to_resolution;
+ from_buffer += channel_size;
+ }
+ }
+ else
+ {
+ /* fc3c */
+ to_pos++;
+ smres = to_resolution - (rescont - from_resolution);
+ for (C = 0; C < channels; C++)
+ {
+ value =
+ ((data_lsb_get (from_buffer, channel_size) * smres) +
+ color[C]) / from_resolution;
+ data_lsb_set (to_buffer, value, channel_size);
+ color[C] =
+ data_lsb_get (from_buffer,
+ channel_size) * (rescont - from_resolution);
+
+ to_buffer += channel_size;
+ from_buffer += channel_size;
+ }
+ rescont -= from_resolution;
+ }
+ }
+
+ rst = OK;
+ }
+ else
+ {
+ /* fd60 */
+ SANE_Int bit, pos, desp, rescont2;
+
+ *to_buffer = 0;
+ bit = 0;
+ pos = 0;
+ desp = 0;
+ rescont = 0;
+ rescont2 = 0;
+ if (to_width > 0)
+ {
+ do
+ {
+ if (bit == 8)
+ {
+ /* fda6 */
+ bit = 0;
+ to_buffer++;
+ *to_buffer = 0;
+ }
+
+ rescont += to_resolution;
+ if (rescont < from_resolution)
+ {
+ if ((*from_buffer & (0x80 >> desp)) != 0)
+ rescont2 += to_resolution;
+ }
+ else
+ {
+ /*fdd5 */
+ pos++;
+ rescont -= from_resolution;
+ if ((*from_buffer & (0x80 >> desp)) != 0)
+ /*fdee */
+ rescont2 += (to_resolution - rescont);
+ if (rescont2 > (to_resolution / 2))
+ /* fe00 */
+ *to_buffer = _B0 (*to_buffer | (0x80 >> bit));
+ rescont2 =
+ ((*from_buffer & (0x80 >> desp)) != 0) ? rescont : 0;
+ bit++;
+ }
+
+ /* fe2f */
+ desp++;
+ if (desp == 8)
+ {
+ desp = 0;
+ from_buffer++;
+ }
+ }
+ while (pos < to_width);
+ }
+ else
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- Resize_Decrease: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Resize_Increase (SANE_Byte * to_buffer, SANE_Int to_resolution,
+ SANE_Int to_width, SANE_Byte * from_buffer,
+ SANE_Int from_resolution, SANE_Int from_width,
+ SANE_Int myresize_mode)
+{
+ /*
+
+ to_buffer = FAC8 = 0x2353f0
+ to_resolution = FACC = 0x4b
+ to_width = FAD0 = 0x352
+ from_buffer = FAD4 = 0x234650
+ from_resolution = FAD8 = 0x64
+ from_width = FADC = 0x46d
+ myresize_mode = FAE0 = 1
+ */
+
+ SANE_Int rst = ERROR;
+ SANE_Int desp; /* fac0 */
+ SANE_Byte *myp2; /* faac */
+ SANE_Int mywidth; /* fab4 fab8 */
+ SANE_Int mychannels; /* fabc */
+ SANE_Int channels = 0; /* faa4 */
+ SANE_Int depth = 0; /* faa8 */
+ SANE_Int pos = 0; /* fae0 */
+ SANE_Int rescount;
+ SANE_Int val6 = 0;
+ SANE_Int val7 = 0;
+ SANE_Int value;
+ /**/
+ DBG (DBG_FNC,
+ "+ Resize_Increase(*to_buffer, to_resolution=%i, to_width=%i, *from_buffer, from_resolution=%i, from_width=%i, myresize_mode=%i):\n",
+ to_resolution, to_width, from_resolution, from_width, myresize_mode);
+
+ if (myresize_mode != RSZ_LINEART)
+ {
+ switch (myresize_mode)
+ {
+ case RSZ_GRAYL:
+ channels = 1;
+ depth = 8;
+ break;
+ case RSZ_COLOURL:
+ channels = 3;
+ depth = 8;
+ break;
+ case RSZ_COLOURH:
+ channels = 3;
+ depth = 16;
+ break;
+ case RSZ_GRAYH:
+ channels = 1;
+ depth = 16;
+ break;
+ }
+
+ if (channels > 0)
+ {
+ SANE_Byte channel_size;
+ SANE_Byte *p_dst; /* fac8 */
+ SANE_Byte *p_src; /* fad4 */
+
+ desp = to_buffer - from_buffer;
+ myp2 = from_buffer;
+ channel_size = (depth == 8) ? 1 : 2;
+
+ for (mychannels = 0; mychannels < channels; mychannels++)
+ {
+ pos = 0;
+ rescount = (from_resolution / 2) + to_resolution;
+
+ p_src = myp2;
+ p_dst = myp2 + desp;
+
+ /* f938 */
+ val7 = data_lsb_get (p_src, channel_size);
+
+ if (to_width > 0)
+ {
+ for (mywidth = 0; mywidth < to_width; mywidth++)
+ {
+ if (rescount >= to_resolution)
+ {
+ rescount -= to_resolution;
+ val6 = val7;
+ pos++;
+ if (pos < from_width)
+ {
+ p_src += (channels * channel_size);
+ val7 = data_lsb_get (p_src, channel_size);
+ }
+ }
+
+ /*f9a5 */
+ data_lsb_set (p_dst,
+ ((((to_resolution - rescount) * val6) +
+ (val7 * rescount)) / to_resolution),
+ channel_size);
+ rescount += from_resolution;
+ p_dst += (channels * channel_size);
+ }
+ }
+
+ myp2 += channel_size;
+ }
+
+ rst = OK;
+ }
+ else
+ rst = OK;
+ }
+ else
+ {
+ /* RSZ_LINEART mode */
+ /* fa02 */
+ /*
+ to_buffer = FAC8 = 0x2353f0
+ to_resolution = FACC = 0x4b
+ to_width = FAD0 = 0x352
+ from_buffer = FAD4 = 0x234650
+ from_resolution = FAD8 = 0x64
+ from_width = FADC = 0x46d
+ myresize_mode = FAE0 = 1
+ */
+ SANE_Int myres2; /* fac8 */
+ SANE_Int sres;
+ SANE_Int lfae0;
+ SANE_Int lfad8;
+ SANE_Int myres;
+ SANE_Int cont = 1;
+ SANE_Int someval;
+ SANE_Int bit; /*lfaa8 */
+
+ myres2 = from_resolution;
+ sres = (myres2 / 2) + to_resolution;
+ value = _B0 (*from_buffer);
+ bit = 0;
+ lfae0 = 0;
+ lfad8 = value >> 7;
+ someval = lfad8;
+ *to_buffer = 0;
+
+ if (to_width > 0)
+ {
+ myres = to_resolution;
+ to_resolution = myres / 2;
+ do
+ {
+ if (sres >= myres)
+ {
+ sres -= myres;
+ lfae0++;
+ cont++;
+ lfad8 = someval;
+ if (lfae0 < from_width)
+ {
+ if (cont == 8)
+ {
+ cont = 0;
+ from_buffer++;
+ }
+ bit = (((0x80 >> cont) & *from_buffer) != 0) ? 1 : 0;
+ }
+ }
+ /*faa6 */
+ if ((((myres - sres) * lfad8) + (bit * sres)) > to_resolution)
+ *to_buffer |= (0x80 >> bit);
+
+ bit++;
+ if (bit == 8)
+ {
+ bit = 0;
+ to_buffer++;
+ *to_buffer = 0;
+ }
+ to_width--;
+ sres += myres2;
+ }
+ while (to_width > 0);
+ rst = OK;
+ }
+ }
+
+ DBG (DBG_FNC, "- Resize_Increase: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Resize_Start (struct st_device *dev, SANE_Int * transferred)
+{
+ SANE_Int rst = ERROR;
+ struct st_resize *rz = dev->Resize;
+
+ DBG (DBG_FNC, "+ Resize_Start(*transferred):\n");
+
+ if (Resize_CreateBuffers
+ (dev, line_size, rz->bytesperline, rz->bytesperline) == ERROR)
+ return ERROR;
+
+ if (arrangeline2 == FIX_BY_SOFT)
+ {
+ /* fee0 */
+ if (scan2.colormode == CM_COLOR)
+ rst = Arrange_Colour (dev, rz->v3624, line_size, transferred);
+ else
+ rst = Arrange_NonColour (dev, rz->v3624, line_size, transferred);
+ }
+ else
+ rst = Read_Block (dev, line_size, rz->v3624, transferred); /* ff03 */
+
+ /* Redimensionado */
+ switch (rz->type)
+ {
+ case RSZ_DECREASE:
+ /* ff1b */
+ Resize_Decrease (rz->v3628, rz->resolution_x, rz->towidth, rz->v3624,
+ scan2.resolution_x, rz->fromwidth, rz->mode);
+ break;
+ case RSZ_INCREASE:
+ /* ff69 */
+ rz->rescount = 0;
+ Resize_Increase (rz->v3628, rz->resolution_x, rz->towidth, rz->v3624,
+ scan2.resolution_x, rz->fromwidth, rz->mode);
+ if (arrangeline2 == FIX_BY_SOFT)
+ {
+ /* ffb1 */
+ if (scan2.colormode == CM_COLOR)
+ rst = Arrange_Colour (dev, rz->v3624, line_size, transferred);
+ else
+ rst = Arrange_NonColour (dev, rz->v3624, line_size, transferred);
+ }
+ else
+ rst = Read_Block (dev, line_size, rz->v3624, transferred); /* ffe0 */
+
+ /* fff2 */
+ Resize_Increase (rz->v362c, rz->resolution_x, rz->towidth, rz->v3624,
+ scan2.resolution_x, rz->fromwidth, rz->mode);
+ break;
+ }
+
+ /* 002a */
+
+ DBG (DBG_FNC, "- Resize_Start(*transferred=%i): %i\n", *transferred, rst);
+
+ return rst;
+}
+
+static SANE_Int
+Resize_CreateBuffers (struct st_device *dev, SANE_Int size1, SANE_Int size2,
+ SANE_Int size3)
+{
+ SANE_Int rst = ERROR;
+ struct st_resize *rz = dev->Resize;
+
+ rz->v3624 = (SANE_Byte *) malloc ((size1 + 0x40) * sizeof (SANE_Byte));
+ rz->v3628 = (SANE_Byte *) malloc ((size2 + 0x40) * sizeof (SANE_Byte));
+ rz->v362c = (SANE_Byte *) malloc ((size3 + 0x40) * sizeof (SANE_Byte));
+
+ if ((rz->v3624 == NULL) || (rz->v3628 == NULL) || (rz->v362c == NULL))
+ Resize_DestroyBuffers (dev);
+ else
+ rst = OK;
+
+ DBG (DBG_FNC, "> Resize_CreateBuffers(size1=%i, size2=%i, size3=%i): %i\n",
+ size1, size2, size3, rst);
+
+ return rst;
+}
+
+static SANE_Int
+Resize_DestroyBuffers (struct st_device *dev)
+{
+ struct st_resize *rz = dev->Resize;
+
+ if (rz->v3624 != NULL)
+ free (rz->v3624);
+
+ if (rz->v3628 != NULL)
+ free (rz->v3628);
+
+ if (rz->v362c != NULL)
+ free (rz->v362c);
+
+ rz->v3624 = NULL;
+ rz->v3628 = NULL;
+ rz->v362c = NULL;
+
+ return OK;
+}
+
+static SANE_Int
+Reading_DestroyBuffers (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Reading_DestroyBuffers():\n");
+
+ if (dev->Reading->DMABuffer != NULL)
+ free (dev->Reading->DMABuffer);
+
+ if (dev->scanning->imagebuffer != NULL)
+ {
+ free (dev->scanning->imagebuffer);
+ dev->scanning->imagebuffer = NULL;
+ }
+
+ bzero (dev->Reading, sizeof (struct st_readimage));
+
+ return OK;
+}
+
+static SANE_Int
+Gamma_SendTables (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Byte * gammatable, SANE_Int size)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Gamma_SendTables(*Regs, *gammatable, size=%i):\n", size);
+
+ if ((gammatable != NULL) && (size > 0))
+ {
+ SANE_Int transferred;
+ SANE_Int first_table;
+ SANE_Int cont = 0;
+ SANE_Int retry = TRUE;
+ SANE_Byte *mybuffer;
+
+ /* lock */
+ SetLock (dev->usb_handle, Regs, TRUE);
+
+ first_table = (data_lsb_get (&Regs[0x1b4], 2) & 0x3fff) >> 4;
+
+ mybuffer = (SANE_Byte *) malloc (sizeof (SANE_Byte) * size);
+ if (mybuffer != NULL)
+ {
+ /* Try to send buffer during 10 seconds */
+ long tick = GetTickCount () + 10000;
+ while ((retry == TRUE) && (tick > GetTickCount ()))
+ {
+ retry = FALSE;
+
+ /* Operation type 0x14 */
+ if (IWrite_Word (dev->usb_handle, 0x0000, 0x0014, 0x0800) == OK)
+ {
+ /* Send size to write */
+ if (RTS_DMA_Enable_Write (dev, 0x0000, size, first_table) ==
+ OK)
+ {
+ /* Send data */
+ if (Bulk_Operation
+ (dev, BLK_WRITE, size, gammatable,
+ &transferred) == OK)
+ {
+ /* Send size to read */
+ if (RTS_DMA_Enable_Read
+ (dev, 0x0000, size, first_table) == OK)
+ {
+ /* Retrieve data */
+ if (Bulk_Operation
+ (dev, BLK_READ, size, mybuffer,
+ &transferred) == OK)
+ {
+ /* Check data */
+ while ((cont < size) && (retry == FALSE))
+ {
+ if (mybuffer[cont] != gammatable[cont])
+ retry = TRUE;
+ cont++;
+ }
+
+ if (retry == FALSE)
+ rst = OK;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ free (mybuffer);
+ }
+
+ /* unlock */
+ SetLock (dev->usb_handle, Regs, FALSE);
+ }
+
+ DBG (DBG_FNC, "- Gamma_SendTables: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Gamma_GetTables (struct st_device *dev, SANE_Byte * Gamma_buffer)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Gamma_GetTables(SANE_Byte *Gamma_buffer):\n");
+
+ if (Gamma_buffer == NULL)
+ return ERROR;
+
+ /* Operation type 0x14 */
+ if (IWrite_Word (dev->usb_handle, 0x0000, 0x0014, 0x0800) == 0x00)
+ {
+ SANE_Int size = 768;
+
+ if (RTS_DMA_Enable_Read (dev, 0x0000, size, 0) == OK)
+ {
+ SANE_Int transferred = 0;
+ usleep (1000 * 500);
+
+ /* Read buffer */
+ rst =
+ Bulk_Operation (dev, BLK_READ, size, Gamma_buffer, &transferred);
+ }
+ }
+
+ DBG (DBG_FNC, "- Gamma_GetTables: %i\n", rst);
+
+ return rst;
+}
+
+static void
+Gamma_FreeTables ()
+{
+ SANE_Int c;
+
+ DBG (DBG_FNC, "> Gamma_FreeTables()\n");
+
+ for (c = 0; c < 3; c++)
+ {
+ if (hp_gamma->table[c] != NULL)
+ {
+ free (hp_gamma->table[c]);
+ hp_gamma->table[c] = NULL;
+ }
+ }
+ use_gamma_tables = FALSE;
+}
+
+static void
+RTS_Scanner_StopScan (struct st_device *dev, SANE_Int wait)
+{
+ SANE_Byte data;
+
+ DBG (DBG_FNC, "+ RTS_Scanner_StopScan():\n");
+
+ data = 0;
+
+ Reading_DestroyBuffers (dev);
+ Resize_DestroyBuffers (dev);
+
+ RTS_DMA_Reset (dev);
+
+ data_bitset (&dev->init_regs[0x60b], 0x10, 0);
+ data_bitset (&dev->init_regs[0x60a], 0x40, 0);
+
+ if (Write_Buffer (dev->usb_handle, 0xee0a, &dev->init_regs[0x60a], 2) == OK)
+ Motor_Change (dev, dev->init_regs, 3);
+
+ usleep (1000 * 200);
+
+ if (wait == FALSE)
+ {
+ Read_Byte (dev->usb_handle, 0xe801, &data);
+ if ((data & 0x02) == 0)
+ {
+ if (Head_IsAtHome (dev, dev->init_regs) == FALSE)
+ {
+ /* clear execution bit */
+ data_bitset (&dev->init_regs[0x00], 0x80, 0);
+
+ Write_Byte (dev->usb_handle, 0x00, dev->init_regs[0x00]);
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+ }
+ }
+ }
+ else
+ {
+ /*66a1 */
+ /* clear execution bit */
+ data_bitset (&dev->init_regs[0x00], 0x80, 0);
+
+ Write_Byte (dev->usb_handle, 0x00, dev->init_regs[0x00]);
+ if (Head_IsAtHome (dev, dev->init_regs) == FALSE)
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+ }
+
+ /*66e0 */
+ RTS_Enable_CCD (dev, dev->init_regs, 0);
+
+ Lamp_Status_Timer_Set (dev, 13);
+
+ DBG (DBG_FNC, "- RTS_Scanner_StopScan()\n");
+}
+
+static SANE_Int
+Reading_CreateBuffers (struct st_device *dev)
+{
+ SANE_Byte data;
+ SANE_Int mybytesperline;
+ SANE_Int mybuffersize, a, b;
+
+ DBG (DBG_FNC, "+ Reading_CreateBuffers():\n");
+
+ data = 0;
+
+ /* Gets BinarythresholdH */
+ if (Read_Byte (dev->usb_handle, 0xe9a1, &data) == OK)
+ binarythresholdh = data;
+
+ mybytesperline =
+ (scan2.depth == 12) ? (bytesperline * 3) / 4 : bytesperline;
+
+ dev->Reading->Max_Size = 0xfc00;
+ dev->Reading->DMAAmount = 0;
+
+ a = (RTS_Debug->dmabuffersize / 63);
+ b = (((RTS_Debug->dmabuffersize - a) / 2) + a) >> 0x0f;
+ mybuffersize = ((b << 6) - b) << 10;
+ if (mybuffersize < 0x1f800)
+ mybuffersize = 0x1f800;
+
+ dev->Reading->DMABufferSize = mybuffersize; /*3FFC00 4193280 */
+
+ do
+ {
+ dev->Reading->DMABuffer =
+ (SANE_Byte *) malloc (dev->Reading->DMABufferSize *
+ sizeof (SANE_Byte));
+ if (dev->Reading->DMABuffer != NULL)
+ break;
+ dev->Reading->DMABufferSize -= dev->Reading->Max_Size;
+ }
+ while (dev->Reading->DMABufferSize >= dev->Reading->Max_Size);
+
+ /* 6003 */
+ dev->Reading->Starting = TRUE;
+
+ dev->Reading->Size4Lines = (mybytesperline > dev->Reading->Max_Size) ?
+ mybytesperline : (dev->Reading->Max_Size / mybytesperline) *
+ mybytesperline;
+
+ dev->Reading->ImageSize = imagesize;
+ read_v15b4 = v15b4;
+
+ DBG (DBG_FNC, "- Reading_CreateBuffers():\n");
+
+ return OK;
+}
+
+static SANE_Int
+RTS_ScanCounter_Inc (struct st_device *dev)
+{
+ /* Keep a count of the number of scans done by this scanner */
+
+ SANE_Int idata;
+
+ DBG (DBG_FNC, "+ RTS_ScanCounter_Inc():\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ SANE_Byte cdata = 0;
+ SANE_Byte somebuffer[26];
+
+ switch (dev->chipset->model)
+ {
+ case RTS8822L_02A:
+ case RTS8822BL_03A:
+ /* value is 4 bytes size starting from address 0x21 in msb format */
+ if (RTS_EEPROM_ReadInteger (dev->usb_handle, 0x21, &idata) == OK)
+ {
+ idata = data_swap_endianess (idata, 4) + 1;
+ idata = data_swap_endianess (idata, 4);
+ RTS_EEPROM_WriteInteger (dev->usb_handle, 0x21, idata);
+ }
+ break;
+ default:
+ /* value is 4 bytes size starting from address 0x21 in lsb format */
+ bzero (&somebuffer, sizeof (somebuffer));
+ somebuffer[4] = 0x0c;
+
+ RTS_EEPROM_ReadInteger (dev->usb_handle, 0x21, &idata);
+ data_lsb_set (&somebuffer[0], idata + 1, 4);
+
+ RTS_EEPROM_ReadByte (dev->usb_handle, 0x003a, &cdata);
+ somebuffer[25] = cdata;
+ RTS_EEPROM_WriteBuffer (dev->usb_handle, 0x21, somebuffer, 0x1a);
+ break;
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_ScanCounter_Inc()\n");
+
+ return OK;
+}
+
+static SANE_Int
+RTS_ScanCounter_Get (struct st_device *dev)
+{
+ /* Returns the number of scans done by this scanner */
+
+ SANE_Int idata = 0;
+
+ DBG (DBG_FNC, "+ RTS_ScanCounter_Get():\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ RTS_EEPROM_ReadInteger (dev->usb_handle, 0x21, &idata);
+
+ switch (dev->chipset->model)
+ {
+ case RTS8822L_02A:
+ case RTS8822BL_03A:
+ /* value is 4 bytes size starting from address 0x21 in msb format */
+ idata = data_swap_endianess (idata, 4);
+ break;
+ default: /* RTS8822L_01H */
+ /* value is 4 bytes size starting from address 0x21 in lsb format */
+ idata &= 0xffffffff;
+ break;
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_ScanCounter_Get(): %i\n", idata);
+
+ return idata;
+}
+
+static SANE_Int
+Read_Image (struct st_device *dev, SANE_Int buffer_size, SANE_Byte * buffer,
+ SANE_Int * transferred)
+{
+ SANE_Int rst;
+ SANE_Byte mycolormode;
+
+ DBG (DBG_FNC, "+ Read_Image(buffer_size=%i, *buffer, *transferred):\n",
+ buffer_size);
+
+ *transferred = 0;
+ mycolormode = scan2.colormode;
+ rst = ERROR;
+ if ((scan2.colormode != CM_COLOR) && (scan2.channel == 3))
+ mycolormode = 3;
+
+ if (dev->Resize->type == RSZ_NONE)
+ {
+ if (arrangeline == FIX_BY_SOFT)
+ {
+ switch (mycolormode)
+ {
+ case CM_COLOR:
+ rst = Arrange_Colour (dev, buffer, buffer_size, transferred);
+ break;
+ case 3:
+ rst = Arrange_Compose (dev, buffer, buffer_size, transferred);
+ break;
+ default:
+ rst = Arrange_NonColour (dev, buffer, buffer_size, transferred);
+ break;
+ }
+ }
+ else
+ rst = Read_Block (dev, buffer_size, buffer, transferred); /*00fe */
+ }
+ else
+ rst = Read_ResizeBlock (dev, buffer, buffer_size, transferred); /*010d */
+
+ DBG (DBG_FNC, "- Read_Image(*transferred=%i): %i\n", *transferred, rst);
+
+ return rst;
+}
+
+static SANE_Int
+Arrange_Compose (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Int * transferred)
+{
+ /*
+ fnb250
+
+ 0600FA7C 05E10048 buffer
+ 0600FA80 0000F906 buffer_size
+ */
+ SANE_Byte *mybuffer = buffer; /* fa7c */
+ SANE_Int mydistance; /*ebp */
+ SANE_Int mydots; /*fa74 */
+ SANE_Int channel_size;
+ SANE_Int c;
+ struct st_scanning *scn;
+
+ /*mywidth = fa70 */
+
+ DBG (DBG_FNC, "+ Arrange_Compose(*buffer, buffer_size=%i, *transferred):\n",
+ buffer_size);
+
+ channel_size = (scan2.depth == 8) ? 1 : 2;
+
+ /* this is just to make code more legible */
+ scn = dev->scanning;
+
+ if (scn->imagebuffer == NULL)
+ {
+ if (dev->sensorcfg->type == CCD_SENSOR)
+ mydistance =
+ (dev->sensorcfg->line_distance * scan2.resolution_y) /
+ dev->sensorcfg->resolution;
+ else
+ mydistance = 0;
+
+ if (mydistance != 0)
+ {
+ scn->bfsize =
+ (scn->arrange_hres ==
+ TRUE) ? scn->arrange_sensor_evenodd_dist : 0;
+ scn->bfsize = line_size * (scn->bfsize + (mydistance * 2) + 1);
+ }
+ else
+ scn->bfsize = line_size * 2;
+
+ /*b2f0 */
+ scn->imagebuffer =
+ (SANE_Byte *) malloc (scn->bfsize * sizeof (SANE_Byte));
+ if (scn->imagebuffer == NULL)
+ return ERROR;
+
+ scn->imagepointer = scn->imagebuffer;
+ if (Read_Block (dev, scn->bfsize, scn->imagebuffer, transferred) ==
+ ERROR)
+ return ERROR;
+
+ /* Calculate channel displacements */
+ scn->arrange_orderchannel = FALSE;
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (mydistance == 0)
+ {
+ /*b34e */
+ if (scn->arrange_hres == FALSE)
+ {
+ if ((((dev->sensorcfg->line_distance * scan2.resolution_y) *
+ 2) / dev->sensorcfg->resolution) == 1)
+ scn->arrange_orderchannel = TRUE;
+
+ if (scn->arrange_orderchannel == TRUE)
+ scn->desp[c] =
+ ((dev->sensorcfg->rgb_order[c] / 2) * line_size) +
+ (channel_size * c);
+ else
+ scn->desp[c] = channel_size * c;
+ }
+ }
+ else
+ {
+ /*b3e3 */
+ scn->desp[c] =
+ (dev->sensorcfg->rgb_order[c] * (mydistance * line_size)) +
+ (channel_size * c);
+
+ if (scn->arrange_hres == TRUE)
+ {
+ /*b43b */
+ scn->desp1[c] = scn->desp[c];
+ scn->desp2[c] =
+ ((channel_size * 3) + scn->desp1[c]) +
+ (scn->arrange_sensor_evenodd_dist * line_size);
+ };
+ }
+ }
+
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (scn->arrange_hres == TRUE)
+ {
+ scn->pColour2[c] = scn->imagebuffer + scn->desp2[c];
+ scn->pColour1[c] = scn->imagebuffer + scn->desp1[c];
+ }
+ else
+ scn->pColour[c] = scn->imagebuffer + scn->desp[c];
+ }
+ }
+
+ /*b545 */
+ buffer_size /= line_size;
+ mydots = line_size / (channel_size * 3);
+
+ while (buffer_size > 0)
+ {
+ if (scn->arrange_orderchannel == FALSE)
+ {
+ /*b5aa */
+ if (scn->arrange_hres == TRUE)
+ Triplet_Compose_HRes (scn->pColour1[CL_RED],
+ scn->pColour1[CL_GREEN],
+ scn->pColour1[CL_BLUE],
+ scn->pColour2[CL_RED],
+ scn->pColour2[CL_GREEN],
+ scn->pColour2[CL_BLUE], mybuffer, mydots);
+ else
+ Triplet_Compose_LRes (scn->pColour[CL_RED],
+ scn->pColour[CL_GREEN],
+ scn->pColour[CL_BLUE], mybuffer, mydots);
+ }
+ else
+ Triplet_Compose_Order (dev, scn->pColour[CL_RED],
+ scn->pColour[CL_GREEN], scn->pColour[CL_BLUE],
+ mybuffer, mydots);
+
+ /*b5f8 */
+ mybuffer += line_size;
+ scn->arrange_size -= bytesperline;
+ if (scn->arrange_size < 0)
+ v15bc--;
+
+ buffer_size--;
+ if (buffer_size == 0)
+ {
+ if ((scn->arrange_size | v15bc) == 0)
+ return OK;
+ }
+
+ /*b63f */
+ if (Read_Block (dev, line_size, scn->imagepointer, transferred) ==
+ ERROR)
+ return ERROR;
+
+ for (c = CL_RED; c <= CL_BLUE; c++)
+ {
+ if (scn->arrange_hres == TRUE)
+ {
+ /*b663 */
+ scn->desp2[c] = (scn->desp2[c] + line_size) % scn->bfsize;
+ scn->desp1[c] = (scn->desp1[c] + line_size) % scn->bfsize;
+
+ scn->pColour2[c] = scn->imagebuffer + scn->desp2[c];
+ scn->pColour1[c] = scn->imagebuffer + scn->desp1[c];
+ }
+ else
+ {
+ /*b74a */
+ scn->desp[c] = (scn->desp[c] + line_size) % scn->bfsize;
+ scn->pColour[c] = scn->imagebuffer + scn->desp[c];
+ }
+ }
+
+ /*b7be */
+ scn->imagepointer += line_size;
+ if (scn->imagepointer >= (scn->imagebuffer + scn->bfsize))
+ scn->imagepointer = scn->imagebuffer;
+ }
+
+ return OK;
+}
+
+static void
+Triplet_Compose_HRes (SANE_Byte * pRed1, SANE_Byte * pGreen1,
+ SANE_Byte * pBlue1, SANE_Byte * pRed2,
+ SANE_Byte * pGreen2, SANE_Byte * pBlue2,
+ SANE_Byte * buffer, SANE_Int Width)
+{
+ SANE_Int Value;
+ SANE_Int Channel_size;
+ SANE_Int max_value;
+
+ DBG (DBG_FNC,
+ "> Triplet_Compose_HRes(*pRed1, *pGreen1, *pBlue1, *pRed2 *pGreen2, *pBlue2, *buffer, Width=%i):\n",
+ Width);
+
+ Width /= 2;
+ Channel_size = (scan2.depth > 8) ? 2 : 1;
+ max_value = (1 << scan2.depth) - 1;
+
+ while (Width > 0)
+ {
+ Value =
+ data_lsb_get (pRed1, Channel_size) + data_lsb_get (pGreen1,
+ Channel_size) +
+ data_lsb_get (pBlue1, Channel_size);
+
+ Value = min (Value, max_value);
+
+ if (v1600 != NULL)
+ {
+ if (scan2.depth > 8)
+ Value = *(v1600 + (Value >> 8)) | _B0 (Value);
+ else
+ Value = *(v1600 + Value);
+ }
+
+ data_lsb_set (buffer, Value, Channel_size);
+ buffer += Channel_size;
+
+ Value =
+ data_lsb_get (pRed2, Channel_size) + data_lsb_get (pGreen2,
+ Channel_size) +
+ data_lsb_get (pBlue2, Channel_size);
+
+ Value = min (Value, max_value);
+
+ if (v1600 != NULL)
+ {
+ if (scan2.depth > 8)
+ Value = *(v1600 + (Value >> 8)) | _B0 (Value);
+ else
+ Value = *(v1600 + Value);
+ }
+
+ data_lsb_set (buffer, Value, Channel_size);
+ buffer += Channel_size;
+
+ pRed1 += 6 * Channel_size;
+ pGreen1 += 6 * Channel_size;
+ pBlue1 += 6 * Channel_size;
+
+ pRed2 += 6 * Channel_size;
+ pGreen2 += 6 * Channel_size;
+ pBlue2 += 6 * Channel_size;
+
+ Width--;
+ }
+}
+
+static void
+Triplet_Compose_Order (struct st_device *dev, SANE_Byte * pRed,
+ SANE_Byte * pGreen, SANE_Byte * pBlue,
+ SANE_Byte * buffer, SANE_Int dots)
+{
+ SANE_Int Value;
+
+ DBG (DBG_FNC,
+ "> Triplet_Compose_Order(*pRed, *pGreen, *pBlue, *buffer, dots=%i):\n",
+ dots);
+
+ if (scan2.depth > 8)
+ {
+ /* c0fe */
+ dots = dots / 2;
+ while (dots > 0)
+ {
+ Value =
+ min (data_lsb_get (pRed, 2) + data_lsb_get (pGreen, 2) +
+ data_lsb_get (pBlue, 2), 0xffff);
+
+ if (v1600 != NULL)
+ Value = (*(v1600 + (Value >> 8)) << 8) | _B0 (Value);
+
+ data_lsb_set (buffer, Value, 2);
+
+ buffer += 2;
+ pRed += 6;
+ pGreen += 6;
+ pBlue += 6;
+ dots--;
+ }
+ }
+ else
+ {
+ SANE_Byte *myp1, *myp2, *myp3;
+
+ if (dev->sensorcfg->rgb_order[CL_RED] == 1)
+ {
+ myp1 = pRed;
+ myp2 = pGreen;
+ myp3 = pBlue;
+ }
+ else if (dev->sensorcfg->rgb_order[CL_GREEN] == 1)
+ {
+ myp1 = pGreen;
+ myp2 = pRed;
+ myp3 = pBlue;
+ }
+ else
+ {
+ myp1 = pBlue;
+ myp2 = pRed;
+ myp3 = pGreen;
+ }
+
+ while (dots > 0)
+ {
+ Value =
+ min (((*myp1 + *(line_size + myp1)) / 2) + *myp2 + *myp3, 0xff);
+
+ *buffer = (v1600 == NULL) ? _B0 (Value) : *(v1600 + Value);
+
+ buffer++;
+ myp1 += 3;
+ myp2 += 3;
+ myp3 += 3;
+ dots--;
+ }
+ }
+}
+
+static void
+Triplet_Compose_LRes (SANE_Byte * pRed, SANE_Byte * pGreen, SANE_Byte * pBlue,
+ SANE_Byte * buffer, SANE_Int dots)
+{
+ SANE_Int Value;
+ SANE_Int Channel_size;
+ SANE_Int max_value;
+
+ DBG (DBG_FNC,
+ "> Triplet_Compose_LRes(*pRed, *pGreen, *pBlue, *buffer, dots=%i):\n",
+ dots);
+
+ Channel_size = (scan2.depth > 8) ? 2 : 1;
+ max_value = (1 << scan2.depth) - 1;
+
+ /*bf59 */
+ while (dots > 0)
+ {
+ Value =
+ data_lsb_get (pRed, Channel_size) + data_lsb_get (pGreen,
+ Channel_size) +
+ data_lsb_get (pBlue, Channel_size);
+
+ Value = min (Value, max_value);
+
+ if (v1600 != NULL)
+ {
+ if (scan2.depth > 8)
+ Value = (*(v1600 + (Value >> 8)) << 8) | _B0 (Value);
+ else
+ Value = _B0 (*(v1600 + Value));
+ }
+
+ data_lsb_set (buffer, Value, Channel_size);
+
+ buffer += Channel_size;
+ pRed += Channel_size * 3;
+ pGreen += Channel_size * 3;
+ pBlue += Channel_size * 3;
+ dots--;
+ }
+}
+
+static void
+Triplet_Colour_Order (struct st_device *dev, SANE_Byte * pRed,
+ SANE_Byte * pGreen, SANE_Byte * pBlue,
+ SANE_Byte * buffer, SANE_Int Width)
+{
+ SANE_Int Value;
+
+ DBG (DBG_FNC,
+ "> Triplet_Colour_Order(*pRed, *pGreen, *pBlue, *buffer, Width=%i):\n",
+ Width);
+
+ if (scan2.depth > 8)
+ {
+ Width = Width / 2;
+ while (Width > 0)
+ {
+ Value = data_lsb_get (pRed, 2);
+ data_lsb_set (buffer, Value, 2);
+
+ Value = data_lsb_get (pGreen, 2);
+ data_lsb_set (buffer + 2, Value, 2);
+
+ Value = data_lsb_get (pBlue, 2);
+ data_lsb_set (buffer + 4, Value, 2);
+
+ pRed += 6;
+ pGreen += 6;
+ pBlue += 6;
+ buffer += 6;
+ Width--;
+ }
+ }
+ else
+ {
+ SANE_Int Colour;
+
+ if (dev->sensorcfg->rgb_order[CL_RED] == 1)
+ Colour = CL_RED;
+ else if (dev->sensorcfg->rgb_order[CL_GREEN] == 1)
+ Colour = CL_GREEN;
+ else
+ Colour = CL_BLUE;
+
+ while (Width > 0)
+ {
+ switch (Colour)
+ {
+ case CL_RED:
+ *buffer = (*pRed + *(pRed + line_size)) / 2;
+ *(buffer + 1) = *pGreen;
+ *(buffer + 2) = *pBlue;
+ break;
+ case CL_GREEN:
+ *buffer = *pRed;
+ *(buffer + 1) = ((*pGreen + *(pGreen + line_size)) / 2);
+ *(buffer + 2) = *pBlue;
+ break;
+ case CL_BLUE:
+ *buffer = *pRed;
+ *(buffer + 1) = *pGreen;
+ *(buffer + 2) = ((*pBlue + *(pBlue + line_size)) / 2);
+ break;
+ }
+
+ pRed += 3;
+ pGreen += 3;
+ pBlue += 3;
+ buffer += 3;
+
+ Width--;
+ }
+ }
+}
+
+static void
+Triplet_Colour_HRes (SANE_Byte * pRed1, SANE_Byte * pGreen1,
+ SANE_Byte * pBlue1, SANE_Byte * pRed2,
+ SANE_Byte * pGreen2, SANE_Byte * pBlue2,
+ SANE_Byte * buffer, SANE_Int Width)
+{
+ SANE_Int Value;
+ SANE_Int channel_size;
+ SANE_Int c;
+ SANE_Byte *pPointers[6];
+
+ pPointers[0] = pRed1;
+ pPointers[1] = pGreen1;
+ pPointers[2] = pBlue1;
+
+ pPointers[3] = pRed2;
+ pPointers[4] = pGreen2;
+ pPointers[5] = pBlue2;
+
+ DBG (DBG_FNC,
+ "> Triplet_Colour_HRes(*pRed1, *pGreen1, *pBlue1, *pRed2, *pGreen2, *pBlue2, *buffer, Width=%i):\n",
+ Width);
+
+ channel_size = (scan2.depth > 8) ? 2 : 1;
+
+ Width = Width / 2;
+ while (Width > 0)
+ {
+ for (c = 0; c < 6; c++)
+ {
+ Value = data_lsb_get (pPointers[c], channel_size);
+ data_lsb_set (buffer, Value, channel_size);
+
+ pPointers[c] += (6 * channel_size);
+ buffer += (channel_size);
+ }
+ Width--;
+ }
+}
+
+static void
+Triplet_Colour_LRes (SANE_Int Width, SANE_Byte * Buffer,
+ SANE_Byte * pChannel1, SANE_Byte * pChannel2,
+ SANE_Byte * pChannel3)
+{
+ /*
+ 05F0FA4C 04EBAE4A /CALL to Assumed StdFunc6 from hpgt3970.04EBAE45
+ 05F0FA50 00234FF8 |Arg1 = 00234FF8 pChannel3
+ 05F0FA54 002359EF |Arg2 = 002359EF pChannel2
+ 05F0FA58 002363E6 |Arg3 = 002363E6 pChannel1
+ 05F0FA5C 05D10048 |Arg4 = 05D10048 Buffer
+ 05F0FA60 00000352 |Arg5 = 00000352 Width
+ */
+
+ /* Esta funcion une los tres canales de color en un triplete
+ Inicialmente cada color está separado en 3 buffers apuntados
+ por pChannel1 ,2 y 3
+ */
+ SANE_Int Value;
+ SANE_Int channel_size;
+ SANE_Int c;
+ SANE_Byte *pChannels[3];
+
+ pChannels[0] = pChannel3;
+ pChannels[1] = pChannel2;
+ pChannels[2] = pChannel1;
+
+ DBG (DBG_FNC, "> Triplet_Colour_LRes(Width=%i, *Buffer2, *p1, *p2, *p3):\n",
+ Width);
+
+ channel_size = (scan2.depth > 8) ? 2 : 1;
+ while (Width > 0)
+ {
+ /* ba74 */
+ for (c = 0; c < 3; c++)
+ {
+ Value = data_lsb_get (pChannels[c], channel_size);
+ data_lsb_set (Buffer, Value, channel_size);
+
+ pChannels[c] += channel_size;
+ Buffer += channel_size;
+ }
+ Width--;
+ }
+}
+
+static SANE_Int
+Read_ResizeBlock (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Int * transferred)
+{
+ /*The Beach
+ buffer = FA7C 05E30048
+ buffer_size = FA80 0000F906
+ */
+
+ SANE_Int rst = ERROR; /* fa68 */
+ SANE_Int lfa54;
+ SANE_Int lfa58;
+ SANE_Byte *pP1; /* fa5c */
+ SANE_Byte *pP2; /* fa60 */
+ SANE_Int bOk;
+ struct st_resize *rz = dev->Resize;
+
+ /* fa74 = Resize->resolution_y */
+ /* fa70 = Resize->resolution_x */
+ /* fa64 = scan2.resolution_y */
+ /* fa6c = scan2.resolution_x */
+
+ DBG (DBG_FNC,
+ "+ Read_ResizeBlock(*buffer, buffer_size=%i, *transferred):\n",
+ buffer_size);
+
+ if (rz->type == RSZ_DECREASE)
+ {
+ lfa58 = 0;
+ do
+ {
+ bOk = 1;
+ if (arrangeline2 == FIX_BY_SOFT)
+ {
+ if (scan2.colormode == CM_COLOR)
+ rst = Arrange_Colour (dev, rz->v3624, line_size, transferred);
+ else
+ rst =
+ Arrange_NonColour (dev, rz->v3624, line_size, transferred);
+ }
+ else
+ rst = Read_Block (dev, line_size, rz->v3624, transferred);
+
+ /*f2df */
+ Resize_Decrease (rz->v362c, rz->resolution_x, rz->towidth,
+ rz->v3624, scan2.resolution_x, rz->fromwidth,
+ rz->mode);
+ rz->rescount += rz->resolution_y;
+
+ if (rz->rescount > scan2.resolution_y)
+ {
+ /*f331 */
+ rz->rescount -= scan2.resolution_y;
+ if (scan2.depth == 8)
+ {
+ /* f345 */
+ pP1 = rz->v3628;
+ pP2 = rz->v362c;
+ if (rz->mode == RSZ_LINEART)
+ {
+ /* f36b */
+ SANE_Int bit = 0;
+ SANE_Byte *pP3 = rz->v362c;
+ SANE_Int value;
+
+ *buffer = 0;
+ lfa54 = 0;
+ while (lfa54 < rz->towidth)
+ {
+ if (bit == 8)
+ {
+ buffer++;
+ *buffer = 0;
+ pP1++;
+ bit = 0;
+ pP3++;
+ }
+
+ value =
+ ((*pP1 & (0x80 >> bit)) != 0) ? rz->rescount : 0;
+
+ if ((*pP3 & (0x80 >> bit)) != 0)
+ value += (scan2.resolution_y - rz->rescount);
+
+ if (value > rz->resolution_y)
+ *buffer |= (0x80 >> bit);
+
+ bit++;
+ lfa54++;
+ }
+ }
+ else
+ {
+ /* f414 */
+ lfa54 = 0;
+ while (lfa54 < rz->bytesperline)
+ {
+ *buffer =
+ _B0 ((((scan2.resolution_y -
+ rz->rescount) * *pP2) +
+ (*pP1 * rz->rescount)) /
+ scan2.resolution_y);
+ pP1++;
+ pP2++;
+ buffer++;
+ lfa54++;
+ }
+ }
+ }
+ else
+ {
+ /* f47d */
+ lfa54 = 0;
+ pP1 = rz->v3628;
+ pP2 = rz->v362c;
+
+ if ((rz->bytesperline & 0xfffffffe) > 0)
+ {
+ SANE_Int value;
+ do
+ {
+ value =
+ (((scan2.resolution_y -
+ rz->rescount) * data_lsb_get (pP2,
+ 2)) +
+ (data_lsb_get (pP1, 2) * rz->rescount)) /
+ scan2.resolution_y;
+ data_lsb_set (buffer, value, 2);
+
+ buffer += 2;
+ pP1 += 2;
+ pP2 += 2;
+ lfa54++;
+ }
+ while (lfa54 < (rz->bytesperline / 2));
+ }
+ }
+ }
+ else
+ bOk = 0;
+ /* f4fd f502 */
+ pP1 = rz->v3628;
+ /* swap pointers */
+ rz->v3628 = rz->v362c;
+ rz->v362c = pP1;
+ }
+ while (bOk == 0);
+ }
+ else
+ {
+ /*f530 */
+ SANE_Int lfa68;
+ SANE_Int transferred;
+ SANE_Int channel_size;
+
+ rz->rescount += scan2.resolution_y;
+ lfa58 = 0;
+ if (rz->rescount > rz->resolution_y)
+ {
+ lfa68 = 1;
+ rz->rescount -= rz->resolution_y;
+ }
+ else
+ lfa68 = 0;
+
+ pP1 = rz->v3628;
+ pP2 = rz->v362c;
+
+ if (rz->mode == RSZ_LINEART)
+ {
+ /*f592 */
+ *buffer = 0;
+
+ if (rz->towidth > 0)
+ {
+ SANE_Int mask, mres;
+ /* lfa60 = rz->resolution_y */
+ /* lfa7c = rz->resolution_y / 2 */
+
+ for (lfa54 = 0; lfa54 < rz->towidth; lfa54++)
+ {
+ mask = 0x80 >> lfa58;
+
+ mres = ((mask & *pP1) != 0) ? rz->rescount : 0;
+
+ if ((mask & *pP2) != 0)
+ mres += (rz->resolution_y - rz->rescount);
+
+ if (mres > (rz->resolution_y / 2))
+ *buffer = *buffer | mask;
+
+ lfa58++;
+ if (lfa58 == 8)
+ {
+ lfa58 = 0;
+ buffer++;
+ pP1++;
+ pP2++;
+ *buffer = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ /*f633 */
+ channel_size = (scan2.depth > 8) ? 2 : 1;
+
+ if (rz->rescount < scan2.resolution_y)
+ {
+ if (rz->bytesperline != 0)
+ {
+ SANE_Int value;
+
+ for (lfa54 = 0; lfa54 < rz->bytesperline; lfa54++)
+ {
+ value =
+ (((scan2.resolution_y -
+ rz->rescount) * data_lsb_get (pP2,
+ channel_size)) +
+ (rz->rescount * data_lsb_get (pP1, channel_size))) /
+ scan2.resolution_y;
+ data_lsb_set (buffer, value, channel_size);
+
+ pP1 += channel_size;
+ pP2 += channel_size;
+ buffer += channel_size;
+ }
+ }
+ }
+ else
+ memcpy (buffer, rz->v3628, rz->bytesperline); /*f6a8 */
+ }
+
+ /*f736 */
+ if (lfa68 != 0)
+ {
+ SANE_Byte *temp;
+
+ if (arrangeline2 == FIX_BY_SOFT)
+ {
+ /*f74b */
+ if (scan2.colormode == CM_COLOR)
+ rst =
+ Arrange_Colour (dev, rz->v3624, line_size, &transferred);
+ else
+ rst =
+ Arrange_NonColour (dev, rz->v3624, line_size, &transferred);
+ }
+ else
+ rst = Read_Block (dev, line_size, rz->v3624, &transferred); /*f77a */
+
+ /*f78c */
+ /* swap buffers */
+ temp = rz->v3628;
+ rz->v3628 = rz->v362c;
+ rz->v362c = temp;
+
+ Resize_Increase (temp, rz->resolution_x, rz->towidth, rz->v3624,
+ scan2.resolution_x, rz->fromwidth, rz->mode);
+ }
+ else
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- Read_ResizeBlock(*transferred=%i): %i\n", *transferred,
+ rst);
+
+ return rst;
+}
+
+static void
+Split_into_12bit_channels (SANE_Byte * destino, SANE_Byte * fuente,
+ SANE_Int size)
+{
+ /*
+ Each letter represents a bit
+ abcdefgh 12345678 lmnopqrs << before splitting
+ [efgh1234 0000abcd] [lmnopqrs 00005678] << after splitting, in memory
+ [0000abcd efgh1234] [00005678 lmnopqrs] << resulting channels
+ */
+
+ DBG (DBG_FNC, "> Split_into_12bit_channels(*destino, *fuente, size=%i\n",
+ size);
+
+ if ((destino != NULL) && (fuente != NULL))
+ {
+ if ((size - (size & 0x03)) != 0)
+ {
+ SANE_Int C;
+
+ C = (size - (size & 0x03) + 3) / 4;
+ do
+ {
+ *destino = _B0 ((*(fuente + 1) >> 4) + (*fuente << 4));
+ *(destino + 1) = _B0 (*fuente >> 4);
+ *(destino + 2) = _B0 (*(fuente + 2));
+ *(destino + 3) = *(fuente + 1) & 0x0f;
+ destino += 4;
+ fuente += 3;
+ C--;
+ }
+ while (C > 0);
+ }
+
+ /**/ if ((size & 0x03) != 0)
+ {
+ *destino = _B0 ((*(fuente + 1) >> 4) + (*fuente << 4));
+ *(destino + 1) = _B0 (*fuente >> 4);
+ }
+ }
+}
+
+static SANE_Int
+Read_NonColor_Block (struct st_device *dev, SANE_Byte * buffer,
+ SANE_Int buffer_size, SANE_Byte ColorMode,
+ SANE_Int * transferred)
+{
+ /* FA50 05DA0048 buffer
+ FA54 0000F906 buffer_size
+ FA58 00 ColorMode
+ */
+
+ SANE_Int rst = OK;
+ SANE_Int lfa38 = 0;
+ SANE_Byte *gamma = v1600;
+ SANE_Int block_bytes_per_line;
+ SANE_Int mysize;
+ SANE_Byte *mybuffer;
+
+ DBG (DBG_FNC,
+ "+ Read_NonColor_Block(*buffer, buffer_size=%i, ColorMode=%s):\n",
+ buffer_size, dbg_colour (ColorMode));
+
+ if (ColorMode != CM_GRAY)
+ {
+ /* Lineart mode */
+ if ((lineart_width & 7) != 0)
+ lfa38 = 8 - (lineart_width & 7);
+ block_bytes_per_line = (lineart_width + 7) / 8;
+ }
+ else
+ block_bytes_per_line = line_size;
+ /*61b2 */
+
+ mysize = (buffer_size / block_bytes_per_line) * bytesperline;
+ mybuffer = (SANE_Byte *) malloc (mysize * sizeof (SANE_Byte)); /*fa40 */
+
+ if (mybuffer != NULL)
+ {
+ SANE_Int LinesCount;
+ SANE_Int mysize4lines;
+ SANE_Byte *pBuffer = buffer;
+ SANE_Byte *pImage = NULL; /* fa30 */
+ SANE_Int puntero;
+ SANE_Int value;
+
+ do
+ {
+ mysize4lines =
+ (mysize <=
+ dev->Reading->Size4Lines) ? mysize : dev->Reading->Size4Lines;
+ LinesCount = mysize4lines / bytesperline;
+
+ if (ColorMode == CM_GRAY)
+ {
+ if (scan2.depth == 12)
+ {
+ /* 633b */
+ /*GRAY Bit mode 12 */
+ rst =
+ Scan_Read_BufferA (dev, (mysize4lines * 3) / 4, 0,
+ mybuffer, transferred);
+ if (rst == OK)
+ {
+ pImage = mybuffer;
+ pBuffer += LinesCount * block_bytes_per_line;
+ while (LinesCount > 0)
+ {
+ Split_into_12bit_channels (mybuffer, pImage,
+ line_size);
+ pImage += (bytesperline * 3) / 4;
+ LinesCount--;
+ }
+ }
+ else
+ break;
+ }
+ else
+ {
+ /* grayscale 8 and 16 bits */
+
+ SANE_Int channel_size;
+
+ rst =
+ Scan_Read_BufferA (dev, mysize4lines, 0, mybuffer,
+ transferred);
+
+ if (rst == OK)
+ {
+ channel_size = (scan2.depth > 8) ? 2 : 1;
+
+ pImage = mybuffer;
+
+ /* No gamma tables */
+ while (LinesCount > 0)
+ {
+ if (line_size > 0)
+ {
+ puntero = 0;
+ do
+ {
+ value =
+ data_lsb_get (pImage + puntero,
+ channel_size);
+
+ if (gamma != NULL)
+ value +=
+ *gamma << (8 * (channel_size - 1));
+
+ data_lsb_set (pBuffer, value, channel_size);
+
+ pBuffer += channel_size;
+ puntero += channel_size;
+ }
+ while (puntero < line_size);
+ }
+ pImage += bytesperline;
+ LinesCount--;
+ }
+ }
+ else
+ break;
+ }
+ }
+ else
+ {
+ /*6429 */
+ /* LINEART */
+ SANE_Int desp;
+ rst =
+ Scan_Read_BufferA (dev, mysize4lines, 0, mybuffer,
+ transferred);
+ if (rst == OK)
+ {
+ pImage = mybuffer;
+ while (LinesCount > 0)
+ {
+ if (lineart_width > 0)
+ {
+ desp = 0;
+ do
+ {
+ if ((desp % 7) == 0)
+ *pBuffer = 0;
+
+ /* making a byte bit per bit */
+ *pBuffer = *pBuffer << 1;
+
+ /* bit 1 if data is under thresholdh value */
+ if (*(pImage + desp) >= binarythresholdh) /* binarythresholdh = 0x0c */
+ *pBuffer = *pBuffer | 1;
+
+ desp++;
+ if ((desp % 7) == 0)
+ pBuffer++;
+
+ }
+ while (desp < lineart_width);
+ }
+
+ if (lfa38 != 0)
+ {
+ *pBuffer = (*pBuffer << lfa38);
+ pBuffer++;
+ }
+ /* 64b0 */
+ pImage += bytesperline;
+ LinesCount--;
+ }
+ }
+ else
+ break;
+ }
+ /* 64c0 */
+ mysize -= mysize4lines;
+ }
+ while ((mysize > 0) && (dev->status->cancel == FALSE));
+
+ free (mybuffer);
+ }
+ else
+ rst = ERROR;
+
+ DBG (DBG_FNC, "- Read_NonColor_Block(*transferred=%i): %i\n", *transferred,
+ rst);
+
+ return rst;
+}
+
+static SANE_Int
+Read_Block (struct st_device *dev, SANE_Int buffer_size, SANE_Byte * buffer,
+ SANE_Int * transferred)
+{
+ /*
+ SANE_Int buffer_size fa80
+ SANE_Byte *buffer fa7c
+ */
+/*
+scan2:
+04F0155C 01 08 00 02 03 00 58 02 ..X
+04F01564 58 02 58 02 C5 00 00 00 XXÅ...
+04F0156C B4 07 00 00 8B 01 00 00 ´..‹..
+04F01574 10 06 00 00 EC 13 00 00 ..ì..
+04F0157C B2 07 00 00 B4 07 00 00 ²..´..
+04F01584 CF 08 00 00 Ï..
+
+arrangeline2 = 1
+*/
+ SANE_Int rst, LinesCount;
+ SANE_Int mysize;
+ SANE_Byte *readbuffer = NULL;
+ SANE_Byte *pImage = NULL;
+
+ DBG (DBG_FNC, "+ Read_Block(buffer_size=%i, *buffer):\n", buffer_size);
+
+ rst = ERROR;
+ *transferred = 0;
+
+ if ((scan2.colormode != CM_COLOR) && (scan2.channel == 3)
+ && (arrangeline2 != FIX_BY_SOFT))
+ {
+ /*6510 */
+ return Read_NonColor_Block (dev, buffer, buffer_size, scan2.colormode,
+ transferred);
+ }
+
+ /*6544 */
+ mysize = (buffer_size / line_size) * bytesperline;
+ readbuffer = (SANE_Byte *) malloc (mysize * sizeof (SANE_Byte));
+ pImage = buffer;
+
+ if (readbuffer != NULL)
+ {
+ do
+ {
+ buffer_size =
+ (dev->Reading->Size4Lines <
+ mysize) ? dev->Reading->Size4Lines : mysize;
+ LinesCount = buffer_size / bytesperline;
+
+ if (scan2.depth == 12)
+ {
+ rst =
+ Scan_Read_BufferA (dev, buffer_size, 0, readbuffer,
+ transferred);
+ if (rst == OK)
+ {
+ if (LinesCount > 0)
+ {
+ SANE_Byte *destino, *fuente;
+ destino = buffer;
+ fuente = readbuffer;
+ do
+ {
+ Split_into_12bit_channels (destino, fuente,
+ line_size);
+ destino += line_size;
+ fuente += (bytesperline * 3) / 4;
+ LinesCount--;
+ }
+ while (LinesCount > 0);
+ }
+ }
+ else
+ break;
+ }
+ else
+ {
+ /*65d9 */
+ rst =
+ Scan_Read_BufferA (dev, buffer_size, 0, readbuffer,
+ transferred);
+ if (rst == OK)
+ {
+ memcpy (pImage, readbuffer, *transferred);
+
+ /* apply white shading correction */
+ if ((RTS_Debug->wshading == TRUE)
+ && (scan2.scantype == ST_NORMAL))
+ WShading_Emulate (pImage, &wshading->ptr, *transferred,
+ scan2.depth);
+
+ pImage += *transferred;
+ }
+ else
+ break;
+ }
+ /*6629 */
+ mysize -= buffer_size;
+ }
+ while ((mysize > 0) && (dev->status->cancel == FALSE));
+
+ free (readbuffer);
+ }
+
+ DBG (DBG_FNC, "- Read_Block(*transferred=%i): %i\n", *transferred, rst);
+
+ return rst;
+}
+
+static SANE_Int
+Scan_Read_BufferA (struct st_device *dev, SANE_Int buffer_size, SANE_Int arg2,
+ SANE_Byte * pBuffer, SANE_Int * bytes_transfered)
+{
+ SANE_Int rst = OK;
+ SANE_Byte *ptBuffer = NULL;
+ SANE_Byte *ptImg = NULL;
+ struct st_readimage *rd = dev->Reading;
+
+ DBG (DBG_FNC,
+ "+ Scan_Read_BufferA(buffer_size=%i, arg2, *pBuffer, *bytes_transfered):\n",
+ buffer_size);
+
+ arg2 = arg2; /* silence gcc */
+ *bytes_transfered = 0;
+
+ if (pBuffer != NULL)
+ {
+ ptBuffer = pBuffer;
+
+ while ((buffer_size > 0) && (rst == OK)
+ && (dev->status->cancel == FALSE))
+ {
+ /* Check if we've already started */
+ if (rd->Starting == TRUE)
+ {
+ /* Get channels per dot and channel's size in bytes */
+ SANE_Byte data;
+
+ rd->Channels_per_dot = 1;
+ if (Read_Byte (dev->usb_handle, 0xe812, &data) == OK)
+ {
+ data = data >> 6;
+ if (data != 0)
+ rd->Channels_per_dot = data;
+ }
+
+ rd->Channel_size = 1;
+ if (Read_Byte (dev->usb_handle, 0xee0b, &data) == OK)
+ if (((data & 0x40) != 0) && ((data & 0x08) == 0))
+ rd->Channel_size = 2;
+
+ rd->RDStart = rd->DMABuffer;
+ rd->RDSize = 0;
+ rd->DMAAmount = 0;
+ rd->Starting = FALSE;
+ }
+
+ /* Is there any data to read from scanner? */
+ if ((rd->ImageSize > 0) && (rd->RDSize == 0))
+ {
+ /* Try to read from scanner all possible data to fill DMABuffer */
+ if (rd->RDSize < rd->DMABufferSize)
+ {
+ SANE_Int iAmount, dofree;
+
+ /* Check if we have already notify buffer size */
+ if (rd->DMAAmount <= 0)
+ {
+ /* Initially I suppose that I can read all image */
+ iAmount = min (rd->ImageSize, rd->Max_Size);
+ rd->DMAAmount =
+ ((RTS_Debug->dmasetlength * 2) / iAmount) * iAmount;
+ rd->DMAAmount = min (rd->DMAAmount, rd->ImageSize);
+ Reading_BufferSize_Notify (dev, 0, rd->DMAAmount);
+ iAmount = min (iAmount, rd->DMABufferSize - rd->RDSize);
+ }
+ else
+ {
+ iAmount = min (rd->DMAAmount, rd->ImageSize);
+ iAmount = min (iAmount, rd->Max_Size);
+ }
+
+ /* Allocate buffer to read image if it's necessary */
+ if ((rd->RDSize == 0) && (iAmount <= buffer_size))
+ {
+ ptImg = ptBuffer;
+ dofree = FALSE;
+ }
+ else
+ {
+ ptImg =
+ (SANE_Byte *) malloc (iAmount * sizeof (SANE_Byte));
+ dofree = TRUE;
+ }
+
+ if (ptImg != NULL)
+ {
+ /* We must wait for scanner to get data */
+ SANE_Int opStatus, sc;
+
+ sc = (iAmount < rd->Max_Size) ? TRUE : FALSE;
+ opStatus = Reading_Wait (dev, rd->Channels_per_dot,
+ rd->Channel_size,
+ iAmount,
+ &rd->Bytes_Available, 10, sc);
+
+ /* If something fails, perhaps we can read some bytes... */
+ if (opStatus != OK)
+ {
+ if (rd->Bytes_Available > 0)
+ iAmount = rd->Bytes_Available;
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ /* Try to read from scanner */
+ SANE_Int transferred = 0;
+ opStatus =
+ Bulk_Operation (dev, BLK_READ, iAmount, ptImg,
+ &transferred);
+
+ DBG (DBG_FNC,
+ "> Scan_Read_BufferA: Bulk read %i bytes\n",
+ transferred);
+
+ /*if something fails may be we can read some bytes */
+ iAmount = (SANE_Int) transferred;
+ if (iAmount != 0)
+ {
+ /* Lets copy data into DMABuffer if it's necessary */
+ if (ptImg != ptBuffer)
+ {
+ SANE_Byte *ptDMABuffer;
+
+ ptDMABuffer = rd->RDStart + rd->RDSize;
+ if ((ptDMABuffer - rd->DMABuffer) >=
+ rd->DMABufferSize)
+ ptDMABuffer -= rd->DMABufferSize;
+
+ if ((ptDMABuffer + iAmount) >=
+ (rd->DMABuffer + rd->DMABufferSize))
+ {
+ SANE_Int rest =
+ iAmount - (rd->DMABufferSize -
+ (ptDMABuffer -
+ rd->DMABuffer));
+ memcpy (ptDMABuffer, ptImg,
+ iAmount - rest);
+ memcpy (rd->DMABuffer,
+ ptImg + (iAmount - rest), rest);
+ }
+ else
+ memcpy (ptDMABuffer, ptImg, iAmount);
+ rd->RDSize += iAmount;
+ }
+ else
+ {
+ *bytes_transfered += iAmount;
+ buffer_size -= iAmount;
+ }
+
+ rd->DMAAmount -= iAmount;
+ rd->ImageSize -= iAmount;
+ }
+ else
+ rst = ERROR;
+ }
+
+ /* Lets free buffer */
+ if (dofree == TRUE)
+ {
+ free (ptImg);
+ ptImg = NULL;
+ }
+ }
+ else
+ rst = ERROR;
+ }
+ }
+
+ /* is there any data read from scanner? */
+ if (rd->RDSize > 0)
+ {
+ /* Add to the given buffer so many bytes as posible */
+ SANE_Int iAmount;
+
+ iAmount = min (buffer_size, rd->RDSize);
+ if ((rd->RDStart + iAmount) >=
+ (rd->DMABuffer + rd->DMABufferSize))
+ {
+ SANE_Int rest =
+ rd->DMABufferSize - (rd->RDStart - rd->DMABuffer);
+ memcpy (ptBuffer, rd->RDStart, rest);
+ memcpy (ptBuffer + rest, rd->DMABuffer, iAmount - rest);
+ rd->RDStart = rd->DMABuffer + (iAmount - rest);
+ }
+ else
+ {
+ memcpy (ptBuffer, rd->RDStart, iAmount);
+ rd->RDStart += iAmount;
+ }
+
+ ptBuffer += iAmount;
+ rd->RDSize -= iAmount;
+ buffer_size -= iAmount;
+ *bytes_transfered += iAmount;
+
+ /* if there isn't any data in DMABuffer we can point RDStart
+ to the begining of DMABuffer */
+ if (rd->RDSize == 0)
+ rd->RDStart = rd->DMABuffer;
+ }
+
+ /* in case of all data is read we return OK with bytes_transfered = 0 */
+ if ((*bytes_transfered == 0)
+ || ((rd->RDSize == 0) && (rd->ImageSize == 0)))
+ break;
+ }
+
+ if (rst == ERROR)
+ RTS_DMA_Cancel (dev);
+ }
+
+ DBG (DBG_FNC, "-> *bytes_transfered=%i\n", *bytes_transfered);
+ DBG (DBG_FNC, "-> Reading->ImageSize=%i\n", rd->ImageSize);
+ DBG (DBG_FNC, "-> Reading->DMAAmount=%i\n", rd->DMAAmount);
+ DBG (DBG_FNC, "-> Reading->RDSize =%i\n", rd->RDSize);
+
+ DBG (DBG_FNC, "- Scan_Read_BufferA: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Reading_BufferSize_Get (struct st_device *dev, SANE_Byte channels_per_dot,
+ SANE_Int channel_size)
+{
+ /* returns the ammount of bytes in scanner's buffer ready to be read */
+
+ SANE_Int rst;
+
+ DBG (DBG_FNC,
+ "+ Reading_BufferSize_Get(channels_per_dot=%i, channel_size=%i):\n",
+ channels_per_dot, channel_size);
+
+ rst = 0;
+
+ if (channel_size > 0)
+ {
+ SANE_Int myAmount;
+
+ if (channels_per_dot < 1)
+ {
+ /* read channels per dot from registers */
+ if (Read_Byte (dev->usb_handle, 0xe812, &channels_per_dot) == OK)
+ channels_per_dot = _B0 (channels_per_dot >> 6);
+
+ if (channels_per_dot == 0)
+ channels_per_dot++;
+ }
+
+ if (Read_Integer (dev->usb_handle, 0xef16, &myAmount) == OK)
+ rst = ((channels_per_dot * 32) / channel_size) * myAmount;
+ }
+
+ DBG (DBG_FNC, "- Reading_BufferSize_Get: %i bytes\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_Warmup (struct st_device *dev, SANE_Byte * Regs, SANE_Int lamp,
+ SANE_Int resolution)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Lamp_Warmup(*Regs, lamp=%i, resolution=%i)\n", lamp,
+ resolution);
+
+ if (Regs != NULL)
+ {
+ SANE_Byte flb_lamp, tma_lamp;
+ SANE_Int overdrivetime;
+
+ Lamp_Status_Get (dev, &flb_lamp, &tma_lamp);
+
+ /* ensure that selected lamp is switched on */
+ if (lamp == FLB_LAMP)
+ {
+ overdrivetime = RTS_Debug->overdrive_flb;
+
+ if (flb_lamp == 0)
+ {
+ /* FLB-Lamp is turned off, lets turn on */
+ Lamp_Status_Set (dev, Regs, TRUE, FLB_LAMP);
+ waitforpwm = TRUE;
+ }
+ }
+ else
+ {
+ /* is tma device attached to scanner ? */
+ if (RTS_isTmaAttached (dev) == TRUE)
+ {
+ overdrivetime = RTS_Debug->overdrive_ta;
+
+ if (tma_lamp == 0)
+ {
+ /* tma lamp is turned off */
+ Lamp_Status_Set (dev, Regs, FALSE, TMA_LAMP);
+ waitforpwm = TRUE;
+ }
+ }
+ else
+ rst = ERROR;
+ }
+
+ /* perform warmup process */
+ if (rst == OK)
+ {
+ Lamp_PWM_Setup (dev, lamp);
+
+ if (waitforpwm == TRUE)
+ {
+ /*Lamp_PWM_DutyCycle_Set(dev, (lamp == TMA_LAMP)? 0x0e : 0x00); */
+
+ if (RTS_Debug->warmup == TRUE)
+ {
+ long ticks = GetTickCount () + overdrivetime;
+
+ DBG (DBG_VRB, "- Lamp Warmup process. Please wait...\n");
+
+ dev->status->warmup = TRUE;
+
+ while (GetTickCount () <= ticks)
+ usleep (1000 * 200);
+
+ Lamp_PWM_CheckStable (dev, resolution, lamp);
+
+ }
+ else
+ DBG (DBG_VRB, "- Lamp Warmup process disabled.\n");
+ }
+
+ /*Lamp_PWM_Setup(dev, lamp);
+
+ if (waitforpwm == TRUE)
+ {
+ if (RTS_Debug->warmup == TRUE)
+ Lamp_PWM_CheckStable(dev, resolution, lamp);
+
+ waitforpwm = FALSE;
+ } */
+ }
+
+ }
+ else
+ rst = ERROR;
+
+ dev->status->warmup = FALSE;
+
+ DBG (DBG_FNC, "- Lamp_Warmup: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Scan_Start (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Scan_Start:\n");
+
+ rst = ERROR;
+ if (RTS_Enable_CCD (dev, dev->init_regs, 0x0f) == OK)
+ {
+ SANE_Byte Regs[RT_BUFFER_LEN], mlock;
+ SANE_Int ypos, xpos, runb1;
+ struct st_scanparams scancfg;
+ struct st_hwdconfig hwdcfg;
+ struct st_calibration myCalib;
+ long tick;
+
+ memcpy (&Regs, dev->init_regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (&scancfg, &scan, sizeof (struct st_scanparams));
+
+ dbg_ScanParams (&scancfg);
+
+ /* reserva buffer 6 dwords en fa84-fa9f */
+ bzero (&hwdcfg, sizeof (struct st_hwdconfig));
+
+ /* wait till lamp is at home (should use timeout
+ windows driver doesn't use it)
+ */
+ tick = GetTickCount () + 10000;
+ while ((Head_IsAtHome (dev, Regs) == FALSE)
+ && (tick > GetTickCount ()));
+
+ if (v14b4 != 0)
+ {
+ SANE_Int lfaa0 = 0;
+
+ if (GainOffset_Counter_Inc (dev, &lfaa0) != OK)
+ return 0x02;
+ }
+
+ tick = GetTickCount ();
+
+ /* set margin references */
+ Refs_Set (dev, Regs, &scancfg);
+
+ /* locate head to right position */
+ Load_StripCoords (scantype, &ypos, &xpos);
+ if (ypos != 0)
+ Head_Relocate (dev, dev->motorcfg->parkhomemotormove, MTR_FORWARD,
+ ypos);
+
+ /* perform lamp warmup */
+ if (Lamp_Warmup
+ (dev, Regs, (scancfg.scantype == ST_NORMAL) ? FLB_LAMP : TMA_LAMP,
+ scan.resolution_x) == ERROR)
+ return ERROR;
+
+ /* Calibration process */
+
+ /*592c */
+ if (Calib_CreateBuffers (dev, &myCalib, v14b4) != OK)
+ return ERROR;
+
+ /*5947 */
+
+/*
+if (Calib_BlackShading_jkd(dev, Regs, &myCalib, &scancfg) == OK)
+ Head_ParkHome(dev, TRUE, dev->motorcfg->parkhomemotormove);
+*/
+
+/*
+if (Calib_test(dev, Regs, &myCalib, &scancfg) == OK )
+ Head_ParkHome(dev, TRUE, dev->motorcfg->parkhomemotormove);
+*/
+
+/* Calibrate White shading correction */
+ if ((RTS_Debug->wshading == TRUE) && (scan.scantype == ST_NORMAL))
+ if (WShading_Calibrate (dev, Regs, &myCalib, &scancfg) == OK)
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+
+ hwdcfg.calibrate = RTS_Debug->calibrate;
+
+ if (RTS_Debug->calibrate != 0)
+ {
+ /* Let's calibrate */
+ if ((scancfg.colormode != CM_COLOR) && (scancfg.channel == 3))
+ scancfg.colormode = CM_COLOR;
+
+ hwdcfg.arrangeline = 0;
+
+ if (scan.scantype == ST_NORMAL)
+ {
+ /* Calibration for reflective type */
+
+ /*59e3 */
+ memcpy (&Regs, dev->init_regs,
+ RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ if (Calibration (dev, Regs, &scancfg, &myCalib, 0) != OK)
+ {
+ if (v14b4 == 0)
+ Calib_FreeBuffers (&myCalib);
+ return ERROR;
+ }
+ }
+ else
+ {
+ /*59ed */
+ /* Calibration for negative/slide type */
+
+ }
+
+ /*5af1 */
+ if (RTS_Debug->ScanWhiteBoard != FALSE)
+ {
+ Head_ParkHome (dev, TRUE, dev->motorcfg->basespeedmotormove);
+ scan.ler = 1;
+ }
+
+ scancfg.colormode = scan.colormode;
+ }
+ else
+ {
+ /*5b1e */
+ /*Don't calibrate */
+ if (scan.scantype == ST_NORMAL)
+ {
+ Lamp_Status_Set (dev, NULL, TRUE, FLB_LAMP);
+ }
+ else
+ {
+ if ((scan.scantype == ST_TA) || (scan.scantype == ST_NEG))
+ {
+ /*SANE_Int ta_y_start; */
+ Lamp_Status_Set (dev, NULL, FALSE, TMA_LAMP);
+ /*ta_y_start =
+ get_value(SCAN_PARAM, TA_Y_START, 0x2508, usbfile);
+ ta_y_start += (((((scan.coord.top * 3) * 5) * 5) * 32) / scancfg.resolution_x);
+ if (ta_y_start >= 500)
+ {
+ Head_Relocate(dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD, ta_y_start);
+ scancfg.coord.top = 1;
+ scan.ler = 1;
+ } else
+ {
+ / *5ba9* /
+ if (ta_y_start > 0)
+ {
+ Head_Relocate(dev, dev->motorcfg->basespeedmotormove, MTR_FORWARD, ta_y_start);
+ scancfg.coord.top = 1;
+ scan.ler = 1;
+ }
+ } */
+ }
+ }
+ }
+
+ /*5bd0 */
+ usleep (1000 * 200);
+
+ hwdcfg.scantype = scan.scantype;
+ hwdcfg.motor_direction = MTR_FORWARD;
+
+ /* Set Origin */
+ if ((scan.scantype >= ST_NORMAL) || (scan.scantype <= ST_NEG))
+ {
+ scancfg.coord.left += scan.ser;
+ scancfg.coord.top += scan.ler;
+ }
+
+ hwdcfg.sensorevenodddistance = dev->sensorcfg->evenodd_distance;
+ hwdcfg.highresolution = (scancfg.resolution_x <= 1200) ? FALSE : TRUE;
+
+ /*5c55 */
+ /*
+ if (RTS_Debug->calibrate == FALSE)
+ {
+ SANE_Int mytop = (((scancfg.coord.top * 5) * 5) * 16) / scancfg.resolution_y;
+ if ((scancfg.resolution_y <= 150)&&(mytop < 300))
+ {
+ scancfg.coord.top = scancfg.resolution_y / 4;
+ } else
+ {
+ if (mytop < 100)
+ scancfg.coord.top = scancfg.resolution_y / 12;
+ }
+ }
+ */
+
+ /*5cd9 */
+ if (compression != FALSE)
+ hwdcfg.compression = TRUE;
+
+ /* setting arrangeline option */
+ hwdcfg.arrangeline = arrangeline;
+ if (scancfg.resolution_x == 2400)
+ {
+ /* 5cfa */
+ if (scancfg.colormode != CM_COLOR)
+ {
+ if ((scancfg.colormode == CM_GRAY) && (scancfg.channel == 3))
+ hwdcfg.arrangeline = FIX_BY_SOFT;
+ }
+ else
+ hwdcfg.arrangeline = FIX_BY_SOFT;
+ }
+
+ /*5d12 */
+ if (dev->sensorcfg->type == CCD_SENSOR)
+ {
+ /*5d3a */
+ scancfg.coord.left += 24;
+ switch (scancfg.resolution_x)
+ {
+ case 1200:
+ scancfg.coord.left -= 63;
+ break;
+ case 2400:
+ scancfg.coord.left -= 127;
+ break;
+ }
+ }
+ else
+ {
+ /*5d5a */
+ /* CIS sensor */
+ /*5d6d */
+ scancfg.coord.left += 50;
+ switch (scancfg.resolution_x)
+ {
+ case 1200:
+ scancfg.coord.left -= 63;
+ break;
+ case 2400:
+ scancfg.coord.left -= 127;
+ break;
+ }
+ }
+
+ /* 5d92 */
+ DBG (DBG_FNC, " ->Scan_Start xStart=%i, xExtent=%i\n",
+ scancfg.coord.left, scancfg.coord.width);
+
+ runb1 = 1;
+ if (scan.scantype == ST_NORMAL)
+ {
+ /*5db7 */
+ if ((scancfg.resolution_x == 1200)
+ || (scancfg.resolution_x == 2400))
+ {
+ /*5e41 */
+ if ((scancfg.resolution_y / 10) > scancfg.coord.top)
+ runb1 = 0;
+ }
+ else
+ {
+ if ((scancfg.resolution_x == 600)
+ && (RTS_Debug->usbtype == USB11)
+ && (scancfg.colormode == CM_COLOR))
+ {
+ /*5ded */
+ if ((scancfg.resolution_y / 10) > scancfg.coord.top)
+ runb1 = 0;
+ }
+ else
+ {
+ if ((scancfg.resolution_x == 600)
+ || (scancfg.resolution_x == 300))
+ {
+ /*5e11 */
+ if (scancfg.resolution_y > scancfg.coord.top)
+ runb1 = 0;
+ }
+ else
+ runb1 = 0;
+ }
+ }
+ }
+ else
+ {
+ /*5e7c *//* entra aquí */
+ if ((scancfg.resolution_y / 10) > scancfg.coord.top)
+ runb1 = 0;
+ }
+ /*5eb1 */
+ if (runb1 == 1) /*entra */
+ {
+ SANE_Int val1 = scancfg.coord.top - (scancfg.resolution_y / 10);
+ scancfg.coord.top -= val1;
+ Head_Relocate (dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD, (dev->motorcfg->resolution / scancfg.resolution_y) * val1); /*x168 */
+ }
+
+ /*5efe */
+ if (RTS_Debug->calibrate != FALSE)
+ {
+ if (use_gamma_tables != FALSE)
+ {
+ hwdcfg.use_gamma_tables = TRUE;
+ hp_gamma->depth = 0;
+ }
+
+ /*5f24 */
+ hwdcfg.white_shading = TRUE;
+ hwdcfg.black_shading = TRUE;
+ hwdcfg.unk3 = 0;
+ RTS_Setup (dev, Regs, &scancfg, &hwdcfg, &calibdata->gain_offset);
+
+ myCalib.shading_type = 0;
+ myCalib.shadinglength =
+ min (myCalib.shadinglength, scan.shadinglength);
+
+ if (scancfg.colormode != CM_COLOR)
+ {
+ if ((scancfg.channel > 0) && (scancfg.channel < 3))
+ myCalib.WRef[0] = myCalib.WRef[scancfg.channel];
+ }
+
+ RTS_WriteRegs (dev->usb_handle, Regs);
+
+ /* apply gamma if required */
+ Gamma_Apply (dev, Regs, &scancfg, &hwdcfg, hp_gamma);
+
+ Shading_apply (dev, Regs, &scancfg, &myCalib);
+
+ /* Save to file? */
+ if (RTS_Debug->DumpShadingData != FALSE)
+ dump_shading (&myCalib); /*5ff9 */
+ }
+ else
+ RTS_Setup (dev, Regs, &scancfg, &hwdcfg, default_gain_offset);
+
+ /*602a */
+ RTS_Debug->calibrate = hwdcfg.calibrate;
+ binarythresholdh = bw_threshold;
+ binarythresholdl = bw_threshold;
+ DBG (DBG_FNC, "> bw threshold -- hi=%i, lo=%i\n", binarythresholdh,
+ binarythresholdl);
+
+ /* set threshold high */
+ data_lsb_set (&Regs[0x1a0], binarythresholdh, 2);
+
+ /* set threshold low */
+ data_lsb_set (&Regs[0x19e], binarythresholdl, 2);
+
+ /* if has motorcurves... */
+ if ((Regs[0xdf] & 0x10) != 0)
+ data_bitset (&Regs[0x01], 0x02, 1);
+
+ /* Set MLOCK */
+ mlock = get_value (SCAN_PARAM, MLOCK, 0, usbfile) & 1;
+ data_bitset (&Regs[0x00], 0x10, mlock); /*---x----*/
+
+ if (dev->motorcfg->changemotorcurrent != FALSE)
+ Motor_Change (dev, Regs,
+ Motor_GetFromResolution (scancfg.resolution_x));
+
+ /* set gain control mode */
+ Lamp_SetGainMode (dev, Regs, scancfg.resolution_x,
+ Lamp_GetGainMode (dev, scancfg.resolution_x,
+ scan.scantype));
+
+ RTS_WaitScanEnd (dev, 15000);
+ if (v14b4 == 0)
+ Calib_FreeBuffers (&myCalib);
+
+ /* release motor */
+ Motor_Release (dev);
+
+
+#ifdef developing
+/* prueba(Regs);
+ dbg_registers(Regs);*/
+ /*WShading_Calibrate(dev, Regs, &myCalib, &scancfg); */
+ /*shadingtest1(dev, Regs, &myCalib); */
+#endif
+
+ if (RTS_Warm_Reset (dev) == OK)
+ {
+ RTS_WriteRegs (dev->usb_handle, Regs);
+ usleep (1000 * 500);
+
+ if (RTS_Execute (dev) == OK)
+ {
+ Lamp_Status_Timer_Set (dev, 0);
+
+ /* Let scanner some time to store some data */
+ if ((dev->chipset->model == RTS8822L_02A)
+ && (scancfg.resolution_x > 2400))
+ usleep (1000 * 5000);
+
+ rst = OK;
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- Scan_Start: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_Setup_Motor (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, SANE_Int somevalue)
+{
+ SANE_Int rst = ERROR; /* default */
+
+ DBG (DBG_FNC, "+ RTS_Setup_Motor(*Regs, *scancfg, somevalue=%i):\n",
+ somevalue);
+ dbg_ScanParams (scancfg);
+
+ if ((Regs != NULL) && (scancfg != NULL))
+ {
+ SANE_Int colormode, mymode;
+
+ colormode = ((scancfg->colormode != CM_COLOR)
+ && (scancfg->channel == 3)) ? 3 : scancfg->colormode;
+ mymode =
+ RTS_GetScanmode (dev, scantype, colormode, scancfg->resolution_x);
+
+ if (mymode != -1)
+ {
+ SANE_Int mbs[2] = { 0 }; /* motor back steps */
+ SANE_Int step_size, step_type, dummyline, myvalue, lf02c;
+ struct st_scanmode *sm;
+
+ sm = dev->scanmodes[mymode];
+
+ /* set motor step type */
+ data_bitset (&Regs[0xd9], 0x70, sm->scanmotorsteptype); /*-xxx----*/
+
+ /* set motor direction (polarity) */
+ data_bitset (&Regs[0xd9], 0x80, somevalue >> 3); /*e------- */
+
+ /* next value doesn't seem to have any effect */
+ data_bitset (&Regs[0xd9], 0x0f, somevalue); /*----efgh*/
+
+ /* 0 enable/1 disable motor */
+ data_bitset (&Regs[0xdd], 0x80, somevalue >> 4); /*d------- */
+
+ /* next value doesn't seem to have any effect */
+ data_bitset (&Regs[0xdd], 0x40, somevalue >> 4); /*-d------*/
+
+ switch (sm->scanmotorsteptype)
+ {
+ case STT_OCT:
+ step_type = 8;
+ break;
+ case STT_QUART:
+ step_type = 4;
+ break;
+ case STT_HALF:
+ step_type = 2;
+ break;
+ default:
+ step_type = 1;
+ break; /* STT_FULL */
+ }
+
+ /* set dummy lines */
+ dummyline = sm->dummyline;
+ if (dummyline == 0)
+ dummyline++;
+
+ data_bitset (&Regs[0xd6], 0xf0, dummyline); /*xxxx---- */
+
+ /* Set if motor has curves */
+ data_bitset (&Regs[0xdf], 0x10, ((sm->motorcurve != -1) ? 1 : 0)); /*---x----*/
+
+ /* set last step of deccurve.scanbufferfull table to 16 */
+ data_lsb_set (&Regs[0xea], 0x10, 3);
+
+ /* set last step of deccurve.normalscan table to 16 */
+ data_lsb_set (&Regs[0xed], 0x10, 3);
+
+ /* set last step of deccurve.smearing table to 16 */
+ data_lsb_set (&Regs[0xf0], 0x10, 3);
+
+ /* set last step of deccurve.parkhome table to 16 */
+ data_lsb_set (&Regs[0xf3], 0x10, 3);
+
+ /* set step size */
+ step_size =
+ _B0 ((dev->motorcfg->resolution * step_type) /
+ (dummyline * scancfg->resolution_y));
+ data_lsb_set (&Regs[0xe0], step_size - 1, 1);
+
+ /* set line exposure time */
+ myvalue = data_lsb_get (&Regs[0x30], 3);
+ myvalue += ((myvalue + 1) % step_size);
+ data_lsb_set (&Regs[0x30], myvalue, 3);
+
+ /* set last step of accurve.normalscan table */
+ myvalue = ((myvalue + 1) / step_size) - 1;
+ data_lsb_set (&Regs[0xe1], myvalue, 3);
+
+ /* 42b30eb */
+ lf02c = 0;
+ if (sm->motorcurve != -1)
+ {
+ if (sm->motorcurve < dev->mtrsetting_count)
+ {
+ struct st_motorcurve *ms = dev->mtrsetting[sm->motorcurve];
+ ms->motorbackstep = sm->motorbackstep;
+ }
+
+ DBG (DBG_FNC, " -> Setting up step motor using motorcurve %i\n",
+ sm->motorcurve);
+ lf02c = Motor_Setup_Steps (dev, Regs, sm->motorcurve);
+
+ /* set motor back steps */
+ mbs[1] = sm->motorbackstep;
+ if (mbs[1] >= (smeardeccurvecount + smearacccurvecount))
+ mbs[0] =
+ mbs[1] - (smeardeccurvecount + smearacccurvecount) + 2;
+ else
+ mbs[0] = 0;
+
+ if (mbs[1] >= (deccurvecount + acccurvecount))
+ mbs[1] -= (deccurvecount + acccurvecount) + 2;
+ else
+ mbs[1] = 0;
+ }
+ else
+ {
+ /* this scanner hasn't got any motorcurve */
+
+ /* set last step of accurve.smearing table (same as accurve.normalscan) */
+ data_lsb_set (&Regs[0xe4], myvalue, 3);
+
+ /* set last step of accurve.parkhome table (same as accurve.normalscan) */
+ data_lsb_set (&Regs[0xe7], myvalue, 3);
+
+ /* both motorbacksteps are equal */
+ mbs[0] = sm->motorbackstep;
+ mbs[1] = sm->motorbackstep;
+ }
+
+ /* show msi and motorbacksteps */
+ DBG (DBG_FNC, " -> msi = %i\n", sm->msi);
+ DBG (DBG_FNC, " -> motorbackstep1 = %i\n", mbs[0]);
+ DBG (DBG_FNC, " -> motorbackstep2 = %i\n", mbs[1]);
+
+ /* set msi */
+ data_bitset (&Regs[0xda], 0xff, _B0 (sm->msi)); /*xxxxxxxx */
+ data_bitset (&Regs[0xdd], 0x03, _B1 (sm->msi)); /*------xx*/
+
+ /* set motorbackstep (a) */
+ data_bitset (&Regs[0xdb], 0xff, _B0 (mbs[0])); /*xxxxxxxx */
+ data_bitset (&Regs[0xdd], 0x0c, _B1 (mbs[0])); /*----xx--*/
+
+ /* set motorbackstep (b) */
+ data_bitset (&Regs[0xdc], 0xff, _B0 (mbs[1])); /*xxxxxxxx */
+ data_bitset (&Regs[0xdd], 0x30, _B1 (mbs[1])); /*--xx----*/
+
+ /* 328b */
+
+ /* get dummy lines count */
+ dummyline = data_bitget (&Regs[0xd6], 0xf0);
+
+ myvalue = scancfg->coord.top * (dummyline * step_size);
+
+ if (lf02c >= myvalue)
+ scancfg->coord.top = 1;
+ else
+ scancfg->coord.top -= (lf02c / (dummyline * step_size)) - 1;
+
+ rst = lf02c; /* Result from Motor_Setup_Steps */
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_Setup_Motor: %i\n", rst);
+
+ return rst;
+}
+
+static void
+RTS_Setup_Exposure_Times (SANE_Byte * Regs, struct st_scanparams *scancfg,
+ struct st_scanmode *sm)
+{
+ DBG (DBG_FNC, "> RTS_Setup_Exposure_Times\n");
+
+ if ((sm != NULL) && (Regs != NULL) && (scancfg != NULL))
+ {
+ SANE_Int myexpt[3], linexpt, a;
+
+ /* calculate line exposure time */
+ linexpt = sm->ctpc + 1;
+ if (RTS_Debug->usbtype == USB11)
+ linexpt *= sm->multiexposureforfullspeed;
+
+ if (scancfg->depth > 8)
+ linexpt *= sm->multiexposurefor16bitmode;
+
+ linexpt--;
+
+ /* generate exposure times for each channel color */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ if ((linexpt > sm->mexpt[a]) && (sm->expt[a] == 0))
+ sm->expt[a] = sm->mexpt[a];
+
+ myexpt[a] = (sm->expt[a] == 0) ? sm->mexpt[a] : sm->expt[a];
+ }
+
+ /* save exposure times */
+ DBG (DBG_FNC, "-> Exposure times : %04x, %04x, %04x\n", sm->expt[0],
+ sm->expt[1], sm->expt[2]);
+ data_lsb_set (&Regs[0x36], sm->expt[CL_RED], 3);
+ data_lsb_set (&Regs[0x3c], sm->expt[CL_GREEN], 3);
+ data_lsb_set (&Regs[0x42], sm->expt[CL_BLUE], 3);
+
+ /* save maximum exposure times */
+ DBG (DBG_FNC, "-> Maximum exposure times: %04x, %04x, %04x\n",
+ sm->mexpt[0], sm->mexpt[1], sm->mexpt[2]);
+ data_lsb_set (&Regs[0x33], sm->mexpt[CL_RED], 3);
+ data_lsb_set (&Regs[0x39], sm->mexpt[CL_GREEN], 3);
+ data_lsb_set (&Regs[0x3f], sm->mexpt[CL_BLUE], 3);
+
+ /* save line exposure time */
+ data_lsb_set (&Regs[0x30], linexpt, 3);
+
+ /* scancfg->expt = lowest value */
+ scancfg->expt = min (min (myexpt[1], myexpt[2]), myexpt[0]);
+ }
+}
+
+static SANE_Int
+RTS_Setup_Line_Distances (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg, SANE_Int mycolormode,
+ SANE_Int arrangeline)
+{
+ SANE_Int iLineDistance = 0;
+
+ if (arrangeline == FIX_BY_HARD)
+ {
+ /* we don't need to arrange retrieved line */
+ SANE_Int mylinedistance, myevenodddist;
+
+ mylinedistance =
+ (dev->sensorcfg->line_distance * scancfg->resolution_y) /
+ dev->sensorcfg->resolution;
+
+ if (hwdcfg->highresolution == TRUE)
+ myevenodddist =
+ (hwdcfg->sensorevenodddistance * scancfg->resolution_y) /
+ dev->sensorcfg->resolution;
+ else
+ myevenodddist = 0;
+
+ data_bitset (&Regs[0x149], 0x3f, myevenodddist);
+ data_bitset (&Regs[0x14a], 0x3f, mylinedistance);
+ data_bitset (&Regs[0x14b], 0x3f, mylinedistance + myevenodddist);
+ data_bitset (&Regs[0x14c], 0x3f, mylinedistance * 2);
+ data_bitset (&Regs[0x14d], 0x3f, (mylinedistance * 2) + myevenodddist);
+ }
+ else
+ {
+ /* arrange retrieved line */
+ data_bitset (&Regs[0x149], 0x3f, 0);
+ data_bitset (&Regs[0x14a], 0x3f, 0);
+ data_bitset (&Regs[0x14b], 0x3f, 0);
+ data_bitset (&Regs[0x14c], 0x3f, 0);
+ data_bitset (&Regs[0x14d], 0x3f, 0);
+
+ if (arrangeline == FIX_BY_SOFT)
+ {
+ if (hwdcfg->highresolution == FALSE)
+ {
+ if (mycolormode == CM_COLOR)
+ {
+ iLineDistance =
+ (dev->sensorcfg->line_distance * scan2.resolution_y) * 2;
+ iLineDistance =
+ (iLineDistance / dev->sensorcfg->resolution) + 1;
+ if (iLineDistance < 2)
+ iLineDistance = 2;
+ }
+ }
+ else
+ {
+ /* bcc */
+ if (mycolormode == CM_COLOR)
+ iLineDistance =
+ ((dev->sensorcfg->line_distance * 2) +
+ hwdcfg->sensorevenodddistance) * scan2.resolution_y;
+ else
+ iLineDistance =
+ dev->sensorcfg->line_distance * scan2.resolution_y;
+
+ iLineDistance =
+ (iLineDistance / dev->sensorcfg->resolution) + 1;
+ if (iLineDistance < 2)
+ iLineDistance = 2;
+ }
+
+ /* c25 */
+ iLineDistance &= 0xffff;
+ v15b4 = (iLineDistance > 0) ? 1 : 0;
+ imagesize += iLineDistance * bytesperline;
+ }
+ }
+
+ DBG (DBG_FNC,
+ "> RTS_Setup_Line_Distances(*Regs, *scancfg, *hwdcfg, mycolormode=%i, arrangeline=%i): %i\n",
+ mycolormode, arrangeline, iLineDistance);
+
+ return iLineDistance;
+}
+
+static SANE_Int
+RTS_Setup_Depth (SANE_Byte * Regs, struct st_scanparams *scancfg,
+ SANE_Int mycolormode)
+{
+ /* channels_per_line = channels_per_dot * scan.width
+ bytes_per_line = channels_per_line * bits_per_channel
+ */
+
+ SANE_Int bytes_per_line = 0;
+
+ if ((scancfg != NULL) && (Regs != NULL))
+ {
+ SANE_Int channels_per_line =
+ data_bitget (&Regs[0x12], 0xc0) * scancfg->coord.width;
+
+ bytes_per_line = channels_per_line;
+
+ /* set bits per channel in shading correction's register (0x1cf) */
+ if (mycolormode == CM_LINEART)
+ {
+ /* lineart mode */
+ bytes_per_line = (bytes_per_line + 7) / 8;
+ data_bitset (&Regs[0x1cf], 0x30, 3); /*--11----*/
+ }
+ else
+ {
+ /*f0c */
+ switch (scancfg->depth)
+ {
+ case 16:
+ /* 16 bits per channel */
+ bytes_per_line *= 2;
+ data_bitset (&Regs[0x1cf], 0x30, 2); /*--10----*/
+ break;
+ case 12:
+ /* 12 bits per channel */
+ bytes_per_line *= 2;
+ data_bitset (&Regs[0x1cf], 0x30, 1); /*--01----*/
+ break;
+ default:
+ /* 8 bits per channel */
+ data_bitset (&Regs[0x1cf], 0x30, 0); /*--00----*/
+ break;
+ }
+ }
+ }
+
+ return bytes_per_line;
+}
+
+static void
+RTS_Setup_Shading (SANE_Byte * Regs, struct st_scanparams *scancfg,
+ struct st_hwdconfig *hwdcfg, SANE_Int bytes_per_line)
+{
+ DBG (DBG_FNC,
+ "> RTS_Setup_Shading(*Regs, *scancfg, *hwdcfg, bytes_per_line=%i)\n",
+ bytes_per_line);
+
+ if ((Regs != NULL) && (hwdcfg != NULL))
+ {
+ SANE_Int dots_count, myvalue, myvalue2, mem_available, resolution_ratio,
+ sensor_line_distance;
+ SANE_Int channels, table_size;
+
+ resolution_ratio = Regs[0x0c0] & 0x1f;
+
+ /* 50de */
+ data_bitset (&Regs[0x1bf], 0x18, hwdcfg->unk3); /*---xx---*/
+
+ /* Enable black shading correction ? */
+ data_bitset (&Regs[0x1cf], 0x08, hwdcfg->black_shading); /*----x---*/
+
+ /* Enable white shading correction ? */
+ data_bitset (&Regs[0x1cf], 0x04, hwdcfg->white_shading); /*-----x--*/
+
+ if ((hwdcfg->white_shading != FALSE) && (hwdcfg->black_shading != FALSE)
+ && (hwdcfg->unk3 != 0))
+ data_bitset (&Regs[0x1cf], 0x04, 0); /*-----x--*/
+
+ table_size = 0;
+
+ /* if hwdcfg->black_shading */
+ if ((Regs[0x1cf] & 8) != 0)
+ table_size = (resolution_ratio * scancfg->coord.width) * 2; /* black shading buffer size? */
+
+ /* if hwdcfg->white_shading */
+ if ((Regs[0x1cf] & 4) != 0)
+ table_size += (resolution_ratio * scancfg->coord.width) * 2; /* white shading buffer size? */
+
+ /* Regs 0x1ba, 0x1bb, 0x1bd, 0x1c0 seem to be 4 pointers
+ to some buffer related to shading correction */
+
+ Regs[0x1ba] = 0x00;
+ table_size = (table_size + v160c_block_size - 1) / v160c_block_size;
+ table_size = ((table_size + 15) / 16) + 16;
+
+ Regs[0x1bf] &= 0xfe;
+ Regs[0x1bb] = _B0 (table_size);
+ Regs[0x1bc] = _B1 (table_size);
+ Regs[0x1bf] |= _B2 (table_size) & 1; /*-------x*/
+
+ Regs[0x1bf] &= 0xf9;
+ Regs[0x1bd] = _B0 (table_size * 2);
+ Regs[0x1be] = _B1 (table_size * 2);
+ Regs[0x1bf] |= (_B2 (table_size * 2) & 3) << 1; /*-----xx-*/
+
+ data_wide_bitset (&Regs[0x1c0], 0xfffff, table_size * 3);
+
+ mem_available = mem_total - ((table_size * 3) * 16);
+ sensor_line_distance = Regs[0x14a] & 0x3f;
+
+ /* select case channels_per_dot */
+ channels = data_lsb_get (&Regs[0x12], 1) >> 6;
+
+ switch (channels)
+ {
+ case 3: /* 3 channels per dot */
+ /* 528d */
+ dots_count = bytes_per_line / 3; /* 882 */
+ myvalue =
+ (((sensor_line_distance + 1) * dots_count) + v160c_block_size -
+ 1) / v160c_block_size;
+ myvalue2 = myvalue;
+ mem_available = (mem_available - (myvalue * 3) + 2) / 3;
+
+ myvalue += (table_size * 3) * 8;
+ myvalue = ((myvalue * 2) + mem_available);
+
+ data_bitset (&Regs[0x1c2], 0xf0, _B2 ((myvalue / 16) + 1)); /* 4 higher bits xxxx---- */
+ data_wide_bitset (&Regs[0x1c3], 0xffff, (myvalue / 16) + 1); /* 16 lower bits */
+
+ myvalue = myvalue + myvalue2 + mem_available;
+ data_wide_bitset (&Regs[0x1c5], 0xfffff, (myvalue / 16) + 1);
+ break;
+ case 2: /* 2 channels per dot */
+ dots_count = bytes_per_line / 2;
+ myvalue =
+ (((sensor_line_distance + 1) * dots_count) + v160c_block_size -
+ 1) / v160c_block_size;
+ mem_available = ((mem_available - myvalue) + 1) / 2;
+ myvalue += (((table_size * 3) + mem_available) / 16) + 1;
+
+ data_bitset (&Regs[0x1c2], 0xf0, _B2 (myvalue)); /* 4 higher bits xxxx---- */
+ data_wide_bitset (&Regs[0x1c3], 0xffff, myvalue); /* 16 lower bits */
+ break;
+ default:
+ dots_count = bytes_per_line;
+ break;
+ }
+
+ Regs[0x01c7] &= 0x0f;
+ Regs[0x01c8] = _B0 ((mem_total - 1) / 16);
+ Regs[0x01c9] = _B1 ((mem_total - 1) / 16);
+ Regs[0x01c7] |= (_B2 ((mem_total - 1) / 16) & 0x0f) << 4;
+
+ mem_available -= (dots_count + v160c_block_size - 1) / v160c_block_size;
+ mem_available /= 16;
+ Regs[0x0712] &= 0x0f;
+ Regs[0x0710] = _B0 (mem_available);
+ Regs[0x0711] = _B1 (mem_available);
+ Regs[0x0712] |= _B0 (_B2 (mem_available) << 4); /*xxxx---- */
+
+ Regs[0x0713] = 0x00;
+ Regs[0x0714] = 0x10;
+ Regs[0x0715] &= 0xf0;
+ }
+}
+
+static void
+RTS_Setup_Arrangeline (struct st_device *dev, struct st_hwdconfig *hwdcfg,
+ SANE_Int colormode)
+{
+ dev->scanning->arrange_compression =
+ (colormode == CM_LINEART) ? FALSE : hwdcfg->compression;
+
+ if ((colormode == CM_LINEART)
+ || ((colormode == CM_GRAY) && (hwdcfg->highresolution == FALSE)))
+ arrangeline2 = 0;
+ else
+ arrangeline2 = hwdcfg->arrangeline;
+
+ dev->scanning->arrange_hres = hwdcfg->highresolution;
+ dev->scanning->arrange_sensor_evenodd_dist =
+ (hwdcfg->highresolution == FALSE) ? 0 : hwdcfg->sensorevenodddistance;
+}
+
+static void
+RTS_Setup_Channels (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, SANE_Int mycolormode)
+{
+ DBG (DBG_FNC, "> RTS_Setup_Channels(colormode=%i)\n", mycolormode);
+
+ if ((scancfg != NULL) && (Regs != NULL))
+ {
+ if ((mycolormode != CM_COLOR) && (mycolormode != 3))
+ {
+ /* CM_GRAY || CM_LINEART */
+ if (scancfg->samplerate == LINE_RATE)
+ {
+ /* Setting channels_per_dot to 1 */
+ data_bitset (&Regs[0x12], 0xc0, 1); /*01------ */
+
+ /* setting one rgb_channel_order */
+ data_bitset (&Regs[0x12], 0x03, dev->sensorcfg->rgb_order[scancfg->channel]); /*------xx*/
+
+ /* set sensor_channel_color_order */
+ data_bitset (&Regs[0x60a], 0x3f, 6); /*--xxxxxx*/
+
+ /* set samplerate */
+ data_bitset (&Regs[0x1cf], 0x40, PIXEL_RATE); /*-x------*/
+
+ /* set unknown data */
+ data_bitset (&Regs[0x1cf], 0x80, 1); /*x------- */
+
+ if (scancfg->channel == dev->sensorcfg->rgb_order[1])
+ {
+ /* mexpts[CL_RED] = mexpts[CL_GREEN] */
+ data_lsb_set (&Regs[0x33], data_lsb_get (&Regs[0x39], 3),
+ 3);
+
+ /* expts[CL_RED] = expts[CL_GREEN] */
+ data_lsb_set (&Regs[0x36], data_lsb_get (&Regs[0x3c], 3),
+ 3);
+ }
+ else if (scancfg->channel == dev->sensorcfg->rgb_order[2])
+ {
+ /* mexpts[CL_RED] = mexpts[CL_BLUE] */
+ data_lsb_set (&Regs[0x33], data_lsb_get (&Regs[0x3f], 3),
+ 3);
+
+ /* expts[CL_RED] = expts[CL_BLUE] */
+ data_lsb_set (&Regs[0x36], data_lsb_get (&Regs[0x42], 3),
+ 3);
+ }
+ }
+ else
+ {
+ /* e01 */
+ /* setting channels_per_dot to 2 */
+ data_bitset (&Regs[0x12], 0xc0, 2);
+
+ /* set two channel color order */
+ data_bitset (&Regs[0x12], 0x03, dev->sensorcfg->channel_gray[0]); /*------xx*/
+ data_bitset (&Regs[0x12], 0x0c, dev->sensorcfg->channel_gray[1]); /*----xx--*/
+
+ /* set samplerate */
+ data_bitset (&Regs[0x1cf], 0x40, LINE_RATE);
+
+ /* set unknown data */
+ data_bitset (&Regs[0x1cf], 0x80, 1);
+ }
+ }
+ else
+ {
+ /* CM_COLOR || 3 */
+ /* e42 */
+
+ /* setting channels_per_dot to 3 */
+ data_bitset (&Regs[0x12], 0xc0, 3);
+
+ /* setting samplerate */
+ data_bitset (&Regs[0x1cf], 0x40, scancfg->samplerate);
+
+ /* set unknown data */
+ data_bitset (&Regs[0x1cf], 0x80, 0);
+
+ /* set sensor chanel_color_order */
+ data_bitset (&Regs[0x60a], 0x03, dev->sensorcfg->channel_color[2]); /*------xx*/
+ data_bitset (&Regs[0x60a], 0x0c, dev->sensorcfg->channel_color[1]); /*----xx--*/
+ data_bitset (&Regs[0x60a], 0x30, dev->sensorcfg->channel_color[0]); /*--xx----*/
+
+ /* set rgb_channel_order */
+ data_bitset (&Regs[0x12], 0x03, dev->sensorcfg->rgb_order[0]); /*------xx*/
+ data_bitset (&Regs[0x12], 0x0c, dev->sensorcfg->rgb_order[1]); /*----xx--*/
+ data_bitset (&Regs[0x12], 0x30, dev->sensorcfg->rgb_order[2]); /*--xx----*/
+ }
+ }
+}
+
+static SANE_Int
+RTS_Setup (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, struct st_hwdconfig *hwdcfg,
+ struct st_gain_offset *gain_offset)
+{
+ SANE_Int rst = ERROR; /* default */
+ SANE_Int lSMode;
+ SANE_Byte mycolormode;
+
+ DBG (DBG_FNC, "+ RTS_Setup:\n");
+ dbg_ScanParams (scancfg);
+ dbg_hwdcfg (hwdcfg);
+
+ mycolormode = scancfg->colormode;
+ if (scancfg->colormode != CM_COLOR)
+ {
+ if (scancfg->colormode == CM_LINEART)
+ scancfg->depth = 8;
+
+ if (scancfg->channel == 3)
+ {
+ if (scancfg->colormode == CM_GRAY)
+ mycolormode = (hwdcfg->arrangeline != FIX_BY_SOFT) ? 3 : CM_COLOR;
+ else
+ mycolormode = 3;
+ }
+ }
+
+ /* 42b47d6 */
+ memcpy (&scan2, scancfg, sizeof (struct st_scanparams));
+
+ scantype = hwdcfg->scantype;
+ lSMode =
+ RTS_GetScanmode (dev, scantype, mycolormode, scancfg->resolution_x);
+ if (lSMode >= 0)
+ {
+ struct st_scanmode *sm = dev->scanmodes[lSMode];
+
+ if (sm != NULL)
+ {
+ SANE_Int dummyline, iLineDistance, resolution_ratio, bytes_per_line;
+ struct st_coords rts_coords;
+
+ iLineDistance = 0;
+
+ scancfg->timing = sm->timing;
+ scancfg->sensorresolution =
+ dev->timings[scancfg->timing]->sensorresolution;
+ scancfg->shadinglength =
+ (((scancfg->sensorresolution * 17) / 2) + 3) & 0xfffffffc;
+ scancfg->samplerate = sm->samplerate;
+
+ hwdcfg->motorplus = sm->motorplus;
+
+ /* set systemclock */
+ data_bitset (&Regs[0x00], 0x0f, sm->systemclock);
+
+ /* setting exposure times */
+ RTS_Setup_Exposure_Times (Regs, scancfg, sm);
+
+ /* setting arranges */
+ RTS_Setup_Arrangeline (dev, hwdcfg, mycolormode);
+
+ /* set up line distances */
+ iLineDistance =
+ RTS_Setup_Line_Distances (dev, Regs, scancfg, hwdcfg, mycolormode,
+ arrangeline);
+
+ /* 4c67 */
+
+ /* setup channel colors */
+ RTS_Setup_Channels (dev, Regs, scancfg, mycolormode);
+
+ /* setup depth */
+ bytes_per_line = RTS_Setup_Depth (Regs, scancfg, mycolormode);
+
+ /* f61 */
+
+ /* Set resolution ratio */
+ resolution_ratio =
+ (scancfg->sensorresolution / scancfg->resolution_x) & 0x1f;
+ data_bitset (&Regs[0xc0], 0x1f, resolution_ratio);
+
+ /* set sensor timing values */
+ RTS_Setup_SensorTiming (dev, scancfg->timing, Regs);
+
+ data_bitset (&Regs[0xd8], 0x40, ((scantype == ST_NORMAL) ? 0 : 1)); /*-x------*/
+
+ /* Use static head ? */
+ data_bitset (&Regs[0xd8], 0x80, ((hwdcfg->static_head == FALSE) ? 1 : 0)); /*x------- */
+
+ /* Setting up gamma */
+ RTS_Setup_Gamma (Regs, hwdcfg);
+
+ /* setup shading correction */
+ RTS_Setup_Shading (Regs, scancfg, hwdcfg, bytes_per_line);
+
+ /* setup stepper motor */
+ hwdcfg->startpos =
+ RTS_Setup_Motor (dev, Regs, scancfg,
+ hwdcfg->motor_direction | MTR_ENABLED);
+
+ /* set coordinates */
+ dummyline = data_bitget (&Regs[0xd6], 0xf0);
+
+ if (scancfg->coord.left == 0)
+ scancfg->coord.left++;
+ if (scancfg->coord.top == 0)
+ scancfg->coord.top++;
+
+ rts_coords.left = scancfg->coord.left * resolution_ratio;
+ rts_coords.width = scancfg->coord.width * resolution_ratio;
+ rts_coords.top = scancfg->coord.top * dummyline;
+ rts_coords.height =
+ ((Regs[0x14d] & 0x3f) + scancfg->coord.height +
+ iLineDistance) * dummyline;
+
+ if ((rts_coords.left & 1) == 0)
+ rts_coords.left++;
+
+ RTS_Setup_Coords (Regs, rts_coords.left, rts_coords.top,
+ rts_coords.width, rts_coords.height);
+
+ data_bitset (&Regs[0x01], 0x06, 0); /*-----xx-*/
+
+ /* dummy_scan? */
+ data_bitset (&Regs[0x01], 0x10, hwdcfg->dummy_scan); /*---x----*/
+
+ data_bitset (&Regs[0x163], 0xc0, 1); /*xx------ */
+
+ if (dev->scanning->arrange_compression != FALSE)
+ {
+ Regs[0x60b] &= 0x8f;
+ data_bitset (&Regs[0x60b], 0x10, 1); /*-001----*/
+ }
+ else
+ data_bitset (&Regs[0x60b], 0x7f, 0); /*-0000000*/
+
+ if (mycolormode == 3)
+ {
+ SANE_Int channels_per_line;
+
+ /* Set channels_per_line = channels_per_dot * scan_width */
+ channels_per_line =
+ data_bitget (&Regs[0x12], 0xc0) * scancfg->coord.width;
+ data_wide_bitset (&Regs[0x060c], 0x3ffff, channels_per_line);
+
+ /* Sets 16 bits per channel */
+ data_bitset (&Regs[0x1cf], 0x30, 2); /*--10----*/
+
+ Regs[0x60b] |= 0x40;
+ if (v1619 == 0x21)
+ {
+ dev->scanning->arrange_compression = FALSE;
+ data_bitset (&Regs[0x60b], 0x10, 0); /*---0----*/
+ }
+
+ switch (scancfg->depth)
+ {
+ case 8:
+ case 16:
+ Regs[0x060b] &= 0xf3;
+ break;
+ case 12:
+ Regs[0x060b] = (Regs[0x060b] & 0xfb) | 0x08;
+ break;
+ }
+
+ if (scancfg->colormode == CM_LINEART)
+ data_bitset (&Regs[0x60b], 0x0c, 0);
+
+ /* disable gamma correction ¿? */
+ data_bitset (&Regs[0x1d0], 0x40, 0);
+ }
+
+ /* 5683 */
+ /* Set calibration table */
+ RTS_Setup_GainOffset (Regs, gain_offset);
+
+ rst = OK;
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_Setup: %i\n", rst);
+
+ return rst;
+}
+
+static void
+RTS_Setup_Coords (SANE_Byte * Regs, SANE_Int iLeft, SANE_Int iTop,
+ SANE_Int width, SANE_Int height)
+{
+ DBG (DBG_FNC,
+ "> RTS_Setup_Coords(*Regs, iLeft=%i, iTop=%i, width=%i, height=%i)\n",
+ iLeft, iTop, width, height);
+
+ if (Regs != NULL)
+ {
+ /* Set Left coord */
+ data_lsb_set (&Regs[0xb0], iLeft, 2);
+
+ /* Set Right coord */
+ data_lsb_set (&Regs[0xb2], iLeft + width, 2);
+
+ /* Set Top coord */
+ data_lsb_set (&Regs[0xd0], iTop, 2);
+ data_bitset (&Regs[0xd4], 0x0f, _B2 (iTop));
+
+ /* Set Down coord */
+ data_lsb_set (&Regs[0xd2], iTop + height, 2);
+ data_bitset (&Regs[0xd4], 0xf0, _B2 (iTop + height));
+ }
+}
+
+static void
+RTS_Setup_GainOffset (SANE_Byte * Regs, struct st_gain_offset *gain_offset)
+{
+ SANE_Byte fake[] =
+ { 0x19, 0x15, 0x19, 0x64, 0x64, 0x64, 0x74, 0xc0, 0x74, 0xc0, 0x6d,
+ 0xc0, 0x6d, 0xc0, 0x5f, 0xc0, 0x5f, 0xc0
+ };
+
+ DBG (DBG_FNC, "> RTS_Setup_GainOffset(*Regs, *gain_offset)\n");
+ dbg_calibtable (gain_offset);
+
+ if ((Regs != NULL) && (gain_offset != NULL))
+ {
+ if (RTS_Debug->calibrate == FALSE)
+ {
+ data_bitset (&Regs[0x13], 0x03, gain_offset->pag[CL_RED]); /*------xx*/
+ data_bitset (&Regs[0x13], 0x0c, gain_offset->pag[CL_GREEN]); /*----xx--*/
+ data_bitset (&Regs[0x13], 0x30, gain_offset->pag[CL_BLUE]); /*--xx----*/
+
+ memcpy (&Regs[0x14], &fake, 18);
+ }
+ else
+ {
+ SANE_Int a;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ /* Offsets */
+ Regs[0x1a + (a * 4)] = _B0 (gain_offset->edcg1[a]);
+ Regs[0x1b + (a * 4)] =
+ ((gain_offset->edcg1[a] >> 1) & 0x80) | (gain_offset->
+ edcg2[a] & 0x7f);
+ Regs[0x1c + (a * 4)] = _B0 (gain_offset->odcg1[a]);
+ Regs[0x1d + (a * 4)] =
+ ((gain_offset->odcg1[a] >> 1) & 0x80) | (gain_offset->
+ odcg2[a] & 0x7f);
+
+ /* Variable Gain Amplifier */
+ data_bitset (&Regs[0x14 + a], 0x1f, gain_offset->vgag1[a]);
+ data_bitset (&Regs[0x17 + a], 0x1f, gain_offset->vgag2[a]);
+ }
+
+ data_bitset (&Regs[0x13], 0x03, gain_offset->pag[CL_RED]); /*------xx*/
+ data_bitset (&Regs[0x13], 0x0c, gain_offset->pag[CL_GREEN]); /*----xx--*/
+ data_bitset (&Regs[0x13], 0x30, gain_offset->pag[CL_BLUE]); /*--xx----*/
+ }
+ }
+}
+
+static void
+Calibrate_Free (struct st_cal2 *calbuffers)
+{
+ DBG (DBG_FNC, "> Calibrate_Free(*calbuffers)\n");
+
+ if (calbuffers != NULL)
+ {
+ SANE_Int c;
+
+ if (calbuffers->table2 != NULL)
+ {
+ free (calbuffers->table2);
+ calbuffers->table2 = NULL;
+ }
+
+ for (c = 0; c < 4; c++)
+ {
+ if (calbuffers->tables[c] != NULL)
+ {
+ free (calbuffers->tables[c]);
+ calbuffers->tables[c] = NULL;
+ }
+ }
+
+ calbuffers->shadinglength1 = 0;
+ calbuffers->tables_size = 0;
+ calbuffers->shadinglength3 = 0;
+ }
+}
+
+static SANE_Int
+Calibrate_Malloc (struct st_cal2 *calbuffers, SANE_Byte * Regs,
+ struct st_calibration *myCalib, SANE_Int somelength)
+{
+ SANE_Int myshadinglength, pos;
+ SANE_Int rst;
+
+ if ((calbuffers != NULL) && (Regs != NULL) && (myCalib != NULL))
+ {
+ if ((Regs[0x1bf] & 0x18) == 0)
+ {
+ if ((((Regs[0x1cf] >> 1) & Regs[0x1cf]) & 0x04) != 0)
+ calbuffers->table_count = 2;
+ else
+ calbuffers->table_count = 4;
+ }
+ else
+ calbuffers->table_count = 4;
+
+ /*365d */
+ myshadinglength = myCalib->shadinglength * 2;
+ calbuffers->shadinglength1 = min (myshadinglength, somelength);
+
+ if ((myshadinglength % somelength) != 0)
+ calbuffers->tables_size =
+ (myshadinglength >= somelength) ? somelength * 2 : somelength;
+ else
+ calbuffers->tables_size = somelength;
+
+ if (myshadinglength >= somelength)
+ {
+ calbuffers->shadinglength1 =
+ (myshadinglength % calbuffers->shadinglength1) +
+ calbuffers->shadinglength1;
+ calbuffers->shadinglength3 =
+ ((myCalib->shadinglength * 2) / somelength) - 1;
+ }
+ else
+ calbuffers->shadinglength3 = 0;
+
+ calbuffers->shadinglength3 =
+ (somelength / 16) * calbuffers->shadinglength3;
+
+ rst = OK;
+ for (pos = 0; pos < calbuffers->table_count; pos++)
+ {
+ calbuffers->tables[pos] =
+ (USHORT *) malloc (calbuffers->tables_size * sizeof (USHORT));
+ if (calbuffers->tables[pos] == NULL)
+ {
+ rst = ERROR;
+ break;
+ }
+ }
+
+ if (rst == OK)
+ {
+ calbuffers->table2 =
+ (USHORT *) malloc (calbuffers->tables_size * sizeof (USHORT));
+ if (calbuffers->table2 == NULL)
+ rst = ERROR;
+ }
+
+ if (rst != OK)
+ Calibrate_Free (calbuffers);
+ }
+ else
+ rst = ERROR;
+
+ DBG (DBG_FNC,
+ "> Calibrate_Malloc(*calbuffers, *Regs, *myCalib, somelength=%i): %i\n",
+ somelength, rst);
+
+ return rst;
+}
+
+static SANE_Int
+fn3560 (USHORT * table, struct st_cal2 *calbuffers, SANE_Int * tablepos)
+{
+ /*05FEF974 001F99B0 |table = 001F99B0
+ 05FEF978 05FEFA08 |calbuffers->tables[0] = 05FEFA08
+ 05FEF97C 000000A0 |calbuffers->shadinglength3 = 000000A0
+ 05FEF980 00000348 |calbuffers->shadinglength1 = 00000348
+ 05FEF984 04F01502 |calbuffers->table_count = 04F01502
+ 05FEF988 05FEF998 \Arg6 = 05FEF998
+ */
+
+ if (table != NULL)
+ {
+ SANE_Int pos[4] = { 0, 0, 0, 0 }; /*f960 f964 f968 f96c */
+ SANE_Int usetable = 0;
+ SANE_Int a;
+
+ SANE_Int mylength3 = calbuffers->shadinglength1; /*f97c */
+ SANE_Byte *pPointer =
+ (SANE_Byte *) (table + (calbuffers->shadinglength3 * 16));
+
+ DBG (DBG_FNC, "> fn3560(*table, *calbuffers, *tablepos)\n");
+
+ if (mylength3 > 0)
+ {
+ do
+ {
+ if (calbuffers->tables[usetable] != NULL)
+ {
+ if (mylength3 <= 16)
+ {
+ if (mylength3 > 0)
+ {
+ do
+ {
+ *(calbuffers->tables[usetable] +
+ pos[usetable]) = _B0 (*pPointer);
+ pPointer++;
+ pos[usetable]++;
+ mylength3--;
+ }
+ while (mylength3 > 0);
+ }
+ break;
+ }
+
+ for (a = 0; a < 16; a++)
+ {
+ *(calbuffers->tables[usetable] + pos[usetable]) =
+ _B0 (*pPointer);
+ pPointer++;
+ pos[usetable]++;
+ }
+ }
+
+ mylength3 -= 16;
+ usetable++;
+ if (usetable == calbuffers->table_count)
+ usetable = 0;
+ }
+ while (mylength3 > 0);
+ }
+
+ /*35f8 */
+ if (calbuffers->table_count > 0)
+ {
+ /* Return position of each table */
+ memcpy (tablepos, pos, sizeof (SANE_Int) * 4);
+ }
+ }
+
+ return OK;
+}
+
+static SANE_Int
+Calib_WriteTable (struct st_device *dev, SANE_Byte * table, SANE_Int size,
+ SANE_Int data)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Calib_WriteTable(*table, size=%i):\n", size);
+
+ if ((table != NULL) && (size > 0))
+ {
+ SANE_Int transferred;
+
+ if (RTS_DMA_Reset (dev) == OK)
+ {
+ /* Send size to write */
+ if (RTS_DMA_Enable_Write (dev, 0x0004, size, data) == OK)
+ /* Send data */
+ rst = Bulk_Operation (dev, BLK_WRITE, size, table, &transferred);
+ }
+ }
+
+ DBG (DBG_FNC, "- Calib_WriteTable: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Calib_ReadTable (struct st_device *dev, SANE_Byte * table, SANE_Int size,
+ SANE_Int data)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ Calib_ReadTable(*table, size=%i):\n", size);
+
+ if ((table != NULL) && (size > 0))
+ {
+ SANE_Int transferred;
+
+ if (RTS_DMA_Reset (dev) == OK)
+ {
+ /* Send size to read */
+ if (RTS_DMA_Enable_Read (dev, 0x0004, size, data) == OK)
+ /* Retrieve data */
+ rst = Bulk_Operation (dev, BLK_READ, size, table, &transferred);
+ }
+ }
+
+ DBG (DBG_FNC, "- Calib_ReadTable: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+fn3330 (struct st_device *dev, SANE_Byte * Regs, struct st_cal2 *calbuffers,
+ SANE_Int sensorchannelcolor, SANE_Int * tablepos, SANE_Int data)
+{
+ /*05EEF968 04F0F7F8 |Regs = 04F0F7F8
+ 05EEF96C 02DEC838 |calbuffers->table2 = 02DEC838
+ 05EEF970 05EEFA08 |calbuffers->tables[] = 05EEFA08
+ 05EEF974 00000000 |sensorchannelcolor = 00000000
+ 05EEF978 000000A0 |calbuffers->shadinglength3 = 000000A0
+ 05EEF97C 00000400 |calbuffers->tables_size = 00000400
+ 05EEF980 05EEF998 |&pos = 05EEF998
+ 05EEF984 00221502 |calbuffers->table_count = 00221502
+ 05EEF988 00000000 \data = 00000000
+ */
+
+ SANE_Int table_count = calbuffers->table_count; /*f960 */
+ SANE_Int schcolor = _B0 (sensorchannelcolor);
+ SANE_Int a = 0;
+ SANE_Int tablelength = calbuffers->shadinglength3 / table_count; /*f954 */
+ SANE_Int val_color = 0; /*f974 */
+ SANE_Int val_lineart = 0; /*f978 */
+ SANE_Int val_gray = 0; /*ebx */
+ SANE_Int value4 = 0; /*ebp */
+ SANE_Int size;
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC,
+ "+ fn3330(*Regs, *calbuffers, sensorchannelcolor=%i, *tablepos, data=%i):\n",
+ sensorchannelcolor, data);
+
+ if (calbuffers->table_count > 0)
+ {
+ do
+ {
+ if (calbuffers->table_count == 2)
+ {
+ /*338c */
+ if (a != 0)
+ {
+ /*3394 */
+ if (_B0 (data) == 0)
+ {
+ val_color = 0x100000;
+ val_lineart = 0x100000;
+ val_gray = 0x200000;
+ }
+ else
+ {
+ /*343a */
+ val_color = 0x300000;
+ val_lineart = 0x300000;
+ val_gray = 0;
+ }
+ }
+ else
+ {
+ /*33be */
+ if (_B0 (data) == 0)
+ {
+ val_color = 0;
+ val_lineart = 0;
+ val_gray = 0x300000;
+ }
+ else
+ {
+ /*342a */
+ val_color = 0x200000;
+ val_lineart = 0x200000;
+ val_gray = 0x100000;
+ }
+ }
+ }
+ else
+ {
+ /*33d5 */
+ switch (a)
+ {
+ case 0:
+ val_color = 0;
+ val_lineart = 0;
+ val_gray = 0x300000;
+ break;
+ case 1:
+ val_color = 0x200000;
+ val_lineart = 0x200000;
+ val_gray = 0x100000;
+ break;
+ case 2:
+ val_color = 0x100000;
+ val_lineart = 0x100000;
+ val_gray = 0x200000;
+ break;
+ case 3:
+ val_color = 0x300000;
+ val_lineart = 0x300000;
+ val_gray = 0;
+ break;
+ }
+ }
+
+ /*3449 */
+ switch (schcolor)
+ {
+ case CM_LINEART:
+ size =
+ (((Regs[0x1bf] >> 1) & 3) << 0x10) | (Regs[0x1be] << 0x08) |
+ Regs[0x1bd];
+ value4 = (tablelength + size) | val_lineart;
+ break;
+ case CM_GRAY:
+ size =
+ ((Regs[0x1bf] & 1) << 0x10) | (Regs[0x1bc] << 0x08) |
+ Regs[0x1bb];
+ value4 = (tablelength + size) | val_gray;
+ break;
+ default:
+ size = _B0 (Regs[0x1ba]);
+ value4 = (tablelength + size) | val_color;
+ break;
+ }
+
+ if (Calib_ReadTable
+ (dev, (SANE_Byte *) calbuffers->table2, calbuffers->tables_size,
+ value4) != OK)
+ {
+ rst = ERROR;
+ break;
+ }
+
+ memcpy (calbuffers->tables[a], calbuffers->table2, tablepos[a]);
+
+ if (tablepos[a + 1] == 0)
+ break;
+
+ a++;
+ }
+ while (a < calbuffers->table_count);
+ }
+
+ DBG (DBG_FNC, "- fn3330: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+fn3730 (struct st_device *dev, struct st_cal2 *calbuffers, SANE_Byte * Regs,
+ USHORT * table, SANE_Int sensorchannelcolor, SANE_Int data)
+{
+ /*05FEF9AC |calbuffers = 05FEF9F8
+ 05FEF9B0 |Regs = 04EFF7F8
+ 05FEF9B4 |table = 001F99B0
+ 05FEF9B8 |sensorchannelcolor = 00000000
+ 05FEF9BC |data = 00000000
+ */
+
+ SANE_Int pos[4] = { 0, 0, 0, 0 }; /*f998 f99c f9a0 f9a4 */
+ SANE_Int rst;
+
+ DBG (DBG_FNC,
+ "+ fn3730(*calbuffers, *Regs, *table, sensorchannelcolor=%i, data=%i):\n",
+ sensorchannelcolor, data);
+
+ fn3560 (table, calbuffers, pos);
+ rst = fn3330 (dev, Regs, calbuffers, sensorchannelcolor, pos, data);
+
+ DBG (DBG_FNC, "- fn3730: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Shading_white_apply (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int channels, struct st_calibration *myCalib,
+ struct st_cal2 *calbuffers)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Shading_white_apply(channels=%i)\n", channels);
+
+ /*3e7f */
+ Calibrate_Malloc (calbuffers, Regs, myCalib,
+ (RTS_Debug->usbtype == USB20) ? 0x200 : 0x40);
+
+ if (channels > 0)
+ {
+ /*int a; */
+ SANE_Int chnl;
+ SANE_Int pos; /*fa2c */
+ SANE_Int transferred;
+
+ rst = ERROR;
+
+ for (chnl = 0; chnl < channels; chnl++)
+ {
+ /*for (a = 0; a < myCalib->shadinglength; a++)
+ myCalib->black_shading[chnl][a] = 0x2000; */
+ /* 11 tries */
+ for (pos = 0; pos <= 10; pos++)
+ {
+ /* Send size to write */
+ if (RTS_DMA_Enable_Write
+ (dev, dev->sensorcfg->channel_color[chnl] | 0x14,
+ myCalib->shadinglength, 0) == OK)
+ /* Send data */
+ Bulk_Operation (dev, BLK_WRITE,
+ myCalib->shadinglength * sizeof (USHORT),
+ (SANE_Byte *) & myCalib->
+ white_shading[chnl][myCalib->first_position -
+ 1], &transferred);
+
+ /*3df7 */
+ if (fn3730
+ (dev, calbuffers, Regs,
+ &myCalib->white_shading[chnl][myCalib->first_position - 1],
+ dev->sensorcfg->channel_color[chnl], 1) == OK)
+ {
+ rst = OK;
+ break;
+ }
+
+ RTS_DMA_Cancel (dev);
+ }
+ }
+ }
+
+ Calibrate_Free (calbuffers);
+
+ DBG (DBG_FNC, "- Shading_white_apply: %i\n", rst);
+
+ return OK;
+}
+
+static SANE_Int
+Shading_black_apply (struct st_device *dev, SANE_Byte * Regs,
+ SANE_Int channels, struct st_calibration *myCalib,
+ struct st_cal2 *calbuffers)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Shading_black_apply(channels=%i)\n", channels);
+
+ /* 3d79 */
+ Calibrate_Malloc (calbuffers, Regs, myCalib,
+ (RTS_Debug->usbtype == USB20) ? 0x200 : 0x40);
+
+ if (channels > 0)
+ {
+ /*int a; */
+ SANE_Int chnl;
+ SANE_Int pos; /*fa2c */
+ SANE_Int transferred;
+
+ rst = ERROR;
+
+ for (chnl = 0; chnl < channels; chnl++)
+ {
+ /* 11 tries */
+ /*for (a = 0; a < myCalib->shadinglength; a++)
+ myCalib->black_shading[chnl][a] = 0x2000; */
+
+ for (pos = 0; pos <= 10; pos++)
+ {
+ /* Send size to write */
+ if (RTS_DMA_Enable_Write
+ (dev, dev->sensorcfg->channel_color[chnl] | 0x10,
+ myCalib->shadinglength, 0) == OK)
+ /* Send data */
+ Bulk_Operation (dev, BLK_WRITE,
+ myCalib->shadinglength * sizeof (USHORT),
+ (SANE_Byte *) & myCalib->
+ black_shading[chnl][myCalib->first_position -
+ 1], &transferred);
+
+ /*3df7 */
+ if (fn3730
+ (dev, calbuffers, Regs,
+ &myCalib->black_shading[chnl][myCalib->first_position - 1],
+ dev->sensorcfg->channel_color[chnl], 0) == OK)
+ {
+ rst = OK;
+ break;
+ }
+
+ RTS_DMA_Cancel (dev);
+ }
+ }
+ }
+
+ /*3e62 */
+ Calibrate_Free (calbuffers);
+
+ DBG (DBG_FNC, "- Shading_black_apply: %i\n", rst);
+
+ return OK;
+}
+
+static SANE_Int
+Shading_apply (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *myvar, struct st_calibration *myCalib)
+{
+ /*
+ Regs f1bc
+ myvar f020
+ hwdcfg e838
+ arg4 e81c
+ myCalib e820
+ */
+
+ SANE_Int rst; /* lf9e0 */
+ SANE_Int myfact; /* e820 */
+ SANE_Int shadata;
+ SANE_Byte channels; /* f9d4 */
+ SANE_Int myShadingBase; /* e818 */
+
+ char lf9d1;
+ char lf9d0;
+
+ DBG (DBG_FNC, "+ Shading_apply(*Regs, *myvar, *mygamma, *myCalib):\n");
+ dbg_ScanParams (myvar);
+
+ lf9d0 = (Regs[0x60b] >> 6) & 1;
+ lf9d1 = (Regs[0x60b] >> 4) & 1;
+ Regs[0x060b] &= 0xaf;
+ rst = Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b]);
+ if (rst == OK)
+ {
+ SANE_Byte colormode = myvar->colormode; /*fa24 */
+ SANE_Int le7cc, le7d8;
+ struct st_cal2 calbuffers; /* f9f8 */
+
+ if (colormode != CM_COLOR)
+ {
+ if (myvar->channel != 3)
+ {
+ if (colormode != 3)
+ channels = (myvar->samplerate == PIXEL_RATE) ? 2 : 1;
+ else
+ channels = 3;
+ }
+ else
+ {
+ colormode = 3;
+ channels = 3;
+ }
+ }
+ else
+ channels = 3;
+
+ /*
+ White shading formula : 2000H x Target / (Wn-Dn) = White Gain data ----- for 8 times system
+ White shading formula : 4000H x Target / (Wn-Dn) = White Gain data ----- for 4 times system
+ For example : Target = 3FFFH Wn = 2FFFH Dn = 0040H and 8 times system operation
+ then White Gain = 2000H x 3FFFH / (2FFFH-0040H) = 2AE4H (1.34033 times)
+ */
+ /* 3aad */
+ if (colormode == 3)
+ {
+ /*
+ SANE_Int pos;
+ SANE_Int colour;
+
+ myShadingBase = shadingbase;
+
+ for (colour = 0; colour < channels; colour++)
+ {
+ if (myCalib->white_shading[colour] != NULL)
+ {
+ myfact = shadingfact[colour];
+ if (myCalib->shadinglength > 0)
+ {
+ for (pos = myCalib->first_position - 1; pos < myCalib->shadinglength; pos++)
+ myCalib->white_shading[colour][pos] = (myCalib->white_shading[colour][pos] * myfact) / myShadingBase;
+ }
+ } else break;
+ }
+ */
+ }
+
+ /* 3b3b */
+ if (myCalib->shading_enabled != FALSE)
+ {
+ /* 3b46 */
+ SANE_Int colour, pos;
+ le7cc = shadingbase;
+ le7d8 = shadingbase;
+
+ DBG (DBG_FNC, "-> Shading type: %i\n", myCalib->shading_type);
+
+ for (colour = 0; colour < channels; colour++)
+ {
+ if (colormode == 3)
+ le7cc = shadingfact[colour];
+
+ myShadingBase = ((Regs[0x1cf] & 2) != 0) ? 0x2000 : 0x4000;
+
+ myfact = myCalib->WRef[colour] * myShadingBase;
+
+ if (myCalib->shading_type == 2)
+ {
+ /*3bd8 */
+ if ((myCalib->black_shading[colour] != NULL)
+ && (myCalib->white_shading[colour] != NULL))
+ {
+ for (pos = myCalib->first_position - 1;
+ pos < myCalib->shadinglength; pos++)
+ {
+ if (myCalib->white_shading[colour][pos] == 0)
+ shadata = myShadingBase;
+ else
+ shadata =
+ myfact / myCalib->white_shading[colour][pos];
+
+ shadata = min ((shadata * le7cc) / le7d8, 0xff00);
+ myCalib->black_shading[colour][pos] &= 0xff;
+ myCalib->black_shading[colour][pos] |=
+ shadata & 0xff00;
+ }
+ }
+ else
+ break;
+ }
+ else
+ {
+ /*3c63 */
+ if (myCalib->shading_type == 3)
+ {
+ /*3c68 */
+ if (myCalib->black_shading[colour] != NULL)
+ {
+ for (pos = myCalib->first_position - 1;
+ pos < myCalib->shadinglength; pos++)
+ {
+ if (myCalib->black_shading[colour][pos] == 0)
+ shadata = myShadingBase;
+ else
+ shadata =
+ myfact /
+ myCalib->black_shading[colour][pos];
+
+ shadata =
+ min ((shadata * le7cc) / le7d8, 0xffc0);
+ myCalib->black_shading[colour][pos] &= 0x3f;
+ myCalib->black_shading[colour][pos] |=
+ shadata & 0xffc0;
+ }
+ }
+ else
+ break;
+ }
+ else
+ {
+ /*3ce3 */
+ if (myCalib->white_shading[colour] != NULL)
+ {
+ for (pos = 0; pos < myCalib->shadinglength; pos++)
+ {
+ if (myCalib->white_shading[colour][pos] == 0)
+ shadata = myShadingBase;
+ else
+ shadata =
+ myfact /
+ myCalib->white_shading[colour][pos];
+
+ shadata =
+ min ((shadata * le7cc) / le7d8, 0xffff);
+ myCalib->white_shading[colour][pos] = shadata;
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ /*3d4c */
+ bzero (&calbuffers, sizeof (struct st_cal2));
+
+ /* If black shading correction is enabled ... */
+ if ((Regs[0x1cf] & 8) != 0)
+ Shading_black_apply (dev, Regs, channels, myCalib, &calbuffers);
+
+ /*3e6e */
+
+ /* If white shading correction is enabled ... */
+ if ((Regs[0x1cf] & 4) != 0)
+ Shading_white_apply (dev, Regs, channels, myCalib, &calbuffers);
+
+ /* 3f74 */
+ if (rst == 0)
+ {
+ data_bitset (&Regs[0x60b], 0x40, lf9d0); /*-x------*/
+ data_bitset (&Regs[0x60b], 0x10, lf9d1); /*---x----*/
+
+ rst = Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b]);
+ }
+ }
+ /*3fb5 */
+
+ DBG (DBG_FNC, "- Shading_apply: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Bulk_Operation (struct st_device *dev, SANE_Byte op, SANE_Int buffer_size,
+ SANE_Byte * buffer, SANE_Int * transfered)
+{
+ SANE_Int iTransferSize, iBytesToTransfer, iPos, rst, iBytesTransfered;
+
+ DBG (DBG_FNC, "+ Bulk_Operation(op=%s, buffer_size=%i, buffer):\n",
+ ((op & 0x01) != 0) ? "READ" : "WRITE", buffer_size);
+
+ iBytesToTransfer = buffer_size;
+ iPos = 0;
+ rst = OK;
+ iBytesTransfered = 0;
+
+ if (transfered != NULL)
+ *transfered = 0;
+
+ iTransferSize = min (buffer_size, RTS_Debug->dmatransfersize);
+
+ if (op != 0)
+ {
+ /* Lectura */
+ do
+ {
+ iTransferSize = min (iTransferSize, iBytesToTransfer);
+
+ iBytesTransfered =
+ Read_Bulk (dev->usb_handle, &buffer[iPos], iTransferSize);
+ if (iBytesTransfered < 0)
+ {
+ rst = ERROR;
+ break;
+ }
+ else
+ {
+ if (transfered != NULL)
+ *transfered += iBytesTransfered;
+ }
+ iPos += iTransferSize;
+ iBytesToTransfer -= iTransferSize;
+ }
+ while (iBytesToTransfer > 0);
+ }
+ else
+ {
+ /* Escritura */
+ do
+ {
+ iTransferSize = min (iTransferSize, iBytesToTransfer);
+
+ if (Write_Bulk (dev->usb_handle, &buffer[iPos], iTransferSize) !=
+ OK)
+ {
+ rst = ERROR;
+ break;
+ }
+ else
+ {
+ if (transfered != NULL)
+ *transfered += iTransferSize;
+ }
+ iPos += iTransferSize;
+ iBytesToTransfer -= iTransferSize;
+ }
+ while (iBytesToTransfer > 0);
+ }
+
+ DBG (DBG_FNC, "- Bulk_Operation: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Reading_BufferSize_Notify (struct st_device *dev, SANE_Int data,
+ SANE_Int size)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Reading_BufferSize_Notify(data=%i, size=%i):\n", data,
+ size);
+
+ rst = RTS_DMA_Enable_Read (dev, 0x0008, size, data);
+
+ DBG (DBG_FNC, "- Reading_BufferSize_Notify: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Reading_Wait (struct st_device *dev, SANE_Byte Channels_per_dot,
+ SANE_Byte Channel_size, SANE_Int size, SANE_Int * last_amount,
+ SANE_Int seconds, SANE_Byte op)
+{
+ SANE_Int rst;
+ SANE_Byte cTimeout, executing;
+ SANE_Int lastAmount, myAmount;
+ long tick;
+
+ DBG (DBG_FNC,
+ "+ Reading_Wait(Channels_per_dot=%i, Channel_size=%i, size=%i, *last_amount, seconds=%i, op=%i):\n",
+ Channels_per_dot, Channel_size, size, seconds, op);
+
+ rst = OK;
+ cTimeout = FALSE;
+ lastAmount = 0;
+
+ myAmount = Reading_BufferSize_Get (dev, Channels_per_dot, Channel_size);
+ if (myAmount < size)
+ {
+ /* Wait until scanner fills its buffer */
+ if (seconds == 0)
+ seconds = 10;
+ tick = GetTickCount () + (seconds * 1000);
+
+ while (cTimeout == FALSE)
+ {
+ myAmount =
+ Reading_BufferSize_Get (dev, Channels_per_dot, Channel_size);
+
+ /* check special case */
+ if (op == TRUE)
+ {
+ if (((myAmount + 0x450) > size)
+ || (RTS_IsExecuting (dev, &executing) == FALSE))
+ break;
+ }
+
+ if (myAmount < size)
+ {
+ /* Check timeout */
+ if (myAmount == lastAmount)
+ {
+ /* we are in timeout? */
+ if (tick < GetTickCount ())
+ {
+ /* TIMEOUT */
+ rst = ERROR;
+ cTimeout = TRUE;
+ }
+ else
+ usleep (100 * 1000);
+ }
+ else
+ {
+ /* Amount increased, update tick */
+ lastAmount = myAmount;
+ tick = GetTickCount () + (seconds * 1000);
+ }
+ }
+ else
+ {
+ lastAmount = myAmount;
+ break; /* buffer full */
+ }
+ }
+ }
+
+ if (last_amount != NULL)
+ *last_amount = myAmount;
+
+ DBG (DBG_FNC, "- Reading_Wait: %i , last_amount=%i\n", rst, myAmount);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_GetImage_GetBuffer (struct st_device *dev, double dSize,
+ char unsigned *buffer, double *transferred)
+{
+ SANE_Int rst = ERROR;
+ SANE_Int itransferred;
+ double dtransferred = 0;
+
+ DBG (DBG_FNC, "+ RTS_GetImage_GetBuffer(dSize=%f, buffer, transferred):\n",
+ dSize);
+
+ rst = OK;
+ dSize /= 2;
+
+ if (dSize > 0)
+ {
+ SANE_Int myLength;
+ SANE_Int iPos = 0;
+
+ do
+ {
+ itransferred = 0;
+ myLength =
+ (dSize <=
+ RTS_Debug->dmasetlength) ? dSize : RTS_Debug->dmasetlength;
+
+ if (myLength > 0x1ffe0)
+ myLength = 0x1ffe0;
+
+ rst = ERROR;
+ if (Reading_Wait (dev, 0, 1, myLength * 2, NULL, 5, FALSE) == OK)
+ {
+ if (Reading_BufferSize_Notify (dev, 0, myLength * 2) == OK)
+ rst =
+ Bulk_Operation (dev, BLK_READ, myLength * 2, &buffer[iPos],
+ &itransferred);
+ }
+
+ if (rst != OK)
+ break;
+
+ iPos += itransferred;
+ dSize -= itransferred;
+ dtransferred += itransferred * 2;
+ }
+ while (dSize > 0);
+ }
+
+ /* Return bytes transferred */
+ if (transferred != NULL)
+ *transferred = dtransferred;
+
+ if (rst != OK)
+ RTS_DMA_Cancel (dev);
+
+ DBG (DBG_FNC, "- RTS_GetImage_GetBuffer: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_GetImage_Read (struct st_device *dev, SANE_Byte * buffer,
+ struct st_scanparams *scancfg, struct st_hwdconfig *hwdcfg)
+{
+ /*buffer f80c = esp+14
+ scancfg f850 = esp+18
+ hwdcfg faac = */
+
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC, "+ RTS_GetImage_Read(buffer, scancfg, hwdcfg):\n");
+
+ if (buffer != NULL)
+ {
+ double dSize = scancfg->bytesperline * scancfg->coord.height;
+ SANE_Byte exfn;
+
+ if (scancfg->depth == 12)
+ dSize = (dSize * 3) / 4;
+
+ /*3ff6 */
+ exfn = 1;
+ if (hwdcfg != NULL)
+ if (hwdcfg->compression != FALSE)
+ exfn = 0;
+
+ if (exfn != 0)
+ {
+ double transferred;
+ rst = RTS_GetImage_GetBuffer (dev, dSize, buffer, &transferred);
+ }
+
+ if (rst == OK)
+ RTS_WaitScanEnd (dev, 1500);
+ }
+
+ DBG (DBG_FNC, "- RTS_GetImage_Read: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_GetImage (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg,
+ struct st_gain_offset *gain_offset, SANE_Byte * buffer,
+ struct st_calibration *myCalib, SANE_Int options,
+ SANE_Int gaincontrol)
+{
+ /* 42b8e10 */
+
+ SANE_Int rst = ERROR; /* default */
+
+ DBG (DBG_FNC,
+ "+ RTS_GetImage(*Regs, *scancfg, *gain_offset, *buffer, myCalib, options=0x%08x, gaincontrol=%i):\n",
+ options, gaincontrol);
+ dbg_ScanParams (scancfg);
+
+ /* validate arguments */
+ if ((Regs != NULL) && (scancfg != NULL))
+ {
+ if ((scancfg->coord.width != 0) && (scancfg->coord.height != 0))
+ {
+ struct st_scanparams *myscancfg;
+
+ /* let's make a copy of scan config */
+ myscancfg =
+ (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ if (myscancfg != NULL)
+ {
+ struct st_hwdconfig *hwdcfg;
+
+ memcpy (myscancfg, scancfg, sizeof (struct st_scanparams));
+
+ /* Allocate space for low level config */
+ hwdcfg =
+ (struct st_hwdconfig *) malloc (sizeof (struct st_hwdconfig));
+ if (hwdcfg != NULL)
+ {
+ bzero (hwdcfg, sizeof (struct st_hwdconfig));
+
+ if (((options & 2) != 0) || ((_B1 (options) & 1) != 0))
+ {
+ /* switch off lamp */
+ data_bitset (&Regs[0x146], 0x40, 0);
+
+ Write_Byte (dev->usb_handle, 0xe946, Regs[0x146]);
+ usleep (1000 * ((v14b4 == 0) ? 500 : 300));
+ }
+
+ hwdcfg->scantype = scan.scantype;
+ hwdcfg->use_gamma_tables =
+ ((options & OP_USE_GAMMA) != 0) ? 1 : 0;
+ hwdcfg->white_shading =
+ ((options & OP_WHITE_SHAD) != 0) ? 1 : 0;
+ hwdcfg->black_shading =
+ ((options & OP_BLACK_SHAD) != 0) ? 1 : 0;
+ hwdcfg->motor_direction =
+ ((options & OP_BACKWARD) !=
+ 0) ? MTR_BACKWARD : MTR_FORWARD;
+ hwdcfg->compression =
+ ((options & OP_COMPRESSION) != 0) ? 1 : 0;
+ hwdcfg->static_head =
+ ((options & OP_STATIC_HEAD) != 0) ? 1 : 0;
+ hwdcfg->dummy_scan = (buffer == NULL) ? TRUE : FALSE;
+ hwdcfg->arrangeline = 0;
+ hwdcfg->highresolution =
+ (myscancfg->resolution_x > 1200) ? TRUE : FALSE;
+ hwdcfg->unk3 = 0;
+
+ /* Set Left coord */
+ myscancfg->coord.left +=
+ ((dev->sensorcfg->type == CCD_SENSOR) ? 24 : 50);
+
+ switch (myscancfg->resolution_x)
+ {
+ case 1200:
+ myscancfg->coord.left -= 63;
+ break;
+ case 2400:
+ myscancfg->coord.left -= 126;
+ break;
+ }
+
+ if (myscancfg->coord.left < 0)
+ myscancfg->coord.left = 0;
+
+ RTS_Setup (dev, Regs, myscancfg, hwdcfg, gain_offset);
+
+ /* Setting exposure time */
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ if (scan.resolution_x == 100)
+ {
+ SANE_Int iValue;
+ SANE_Byte *myRegs;
+
+ myRegs =
+ (SANE_Byte *) malloc (RT_BUFFER_LEN *
+ sizeof (SANE_Byte));
+ if (myRegs != NULL)
+ {
+ bzero (myRegs,
+ RT_BUFFER_LEN * sizeof (SANE_Byte));
+ RTS_Setup (dev, myRegs, &scan, hwdcfg,
+ gain_offset);
+
+ iValue = data_lsb_get (&myRegs[0x30], 3);
+ data_lsb_set (&Regs[0x30], iValue, 3);
+
+ /*Copy myregisters mexpts to Regs mexpts */
+ iValue = data_lsb_get (&myRegs[0x33], 3);
+ data_lsb_set (&Regs[0x33], iValue, 3);
+
+ iValue = data_lsb_get (&myRegs[0x39], 3);
+ data_lsb_set (&Regs[0x39], iValue, 3);
+
+ iValue = data_lsb_get (&myRegs[0x3f], 3);
+ data_lsb_set (&Regs[0x3f], iValue, 3);
+
+ free (myRegs);
+ }
+ }
+ break;
+ case ST_NEG:
+ {
+ SANE_Int myvalue;
+
+ /* Setting exposure times for Negative scans */
+ data_lsb_set (&Regs[0x30], myscancfg->expt, 3);
+ data_lsb_set (&Regs[0x33], myscancfg->expt, 3);
+ data_lsb_set (&Regs[0x39], myscancfg->expt, 3);
+ data_lsb_set (&Regs[0x3f], myscancfg->expt, 3);
+
+ data_lsb_set (&Regs[0x36], 0, 3);
+ data_lsb_set (&Regs[0x3c], 0, 3);
+ data_lsb_set (&Regs[0x42], 0, 3);
+
+ myvalue =
+ ((myscancfg->expt +
+ 1) / (data_lsb_get (&Regs[0xe0], 1) + 1)) - 1;
+ data_lsb_set (&Regs[0xe1], myvalue, 3);
+ }
+ break;
+ }
+
+ /* 91a0 */
+ if (myscancfg->resolution_y > 600)
+ {
+ options |= 0x20000000;
+ if (options != 0) /* Always true ... */
+ SetMultiExposure (dev, Regs);
+ else
+ myscancfg->coord.top += hwdcfg->startpos;
+ }
+ else
+ SetMultiExposure (dev, Regs);
+
+ /* 91e2 */
+ RTS_WriteRegs (dev->usb_handle, Regs);
+ if (myCalib != NULL)
+ Shading_apply (dev, Regs, myscancfg, myCalib);
+
+ if (dev->motorcfg->changemotorcurrent != FALSE)
+ Motor_Change (dev, Regs,
+ Motor_GetFromResolution (myscancfg->
+ resolution_x));
+
+ /* mlock = 0 */
+ data_bitset (&Regs[0x00], 0x10, 0);
+
+ data_wide_bitset (&Regs[0xde], 0xfff, 0);
+
+ /* release motor */
+ Motor_Release (dev);
+
+ if (RTS_Warm_Reset (dev) == OK)
+ {
+ rst = OK;
+
+ SetLock (dev->usb_handle, Regs,
+ (myscancfg->depth == 16) ? FALSE : TRUE);
+
+ /* set gain control */
+ Lamp_SetGainMode (dev, Regs, myscancfg->resolution_x,
+ gaincontrol);
+
+ /* send registers to scanner */
+ if (RTS_WriteRegs (dev->usb_handle, Regs) == OK)
+ {
+ /* execute! */
+ if (RTS_Execute (dev) == OK)
+ RTS_GetImage_Read (dev, buffer, myscancfg, hwdcfg); /*92e7 */
+ }
+
+ /*92fc */
+ SetLock (dev->usb_handle, Regs, FALSE);
+
+ if ((options & 0x200) != 0)
+ {
+ /* switch on lamp */
+ data_bitset (&Regs[0x146], 0x40, 1);
+
+ Write_Byte (dev->usb_handle, 0xe946, Regs[0x146]);
+ /* Wait 3 seconds */
+ usleep (1000 * 3000);
+ }
+
+ /*9351 */
+ if (dev->motorcfg->changemotorcurrent == TRUE)
+ Motor_Change (dev, dev->init_regs, 3);
+ }
+
+ /* free low level configuration */
+ free (hwdcfg);
+ }
+
+ /* free scanning configuration */
+ free (myscancfg);
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- RTS_GetImage: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Refs_Detect (struct st_device *dev, SANE_Byte * Regs, SANE_Int resolution_x,
+ SANE_Int resolution_y, SANE_Int * x, SANE_Int * y)
+{
+ SANE_Int rst = ERROR; /* default */
+
+ DBG (DBG_FNC, "+ Refs_Detect(*Regs, resolution_x=%i, resolution_y=%i):\n",
+ resolution_x, resolution_y);
+
+ if ((x != NULL) && (y != NULL))
+ {
+ SANE_Byte *image;
+ struct st_scanparams scancfg;
+
+ *x = *y = 0; /* default */
+
+ /* set configuration to scan a little area at the top-left corner */
+ bzero (&scancfg, sizeof (struct st_scanparams));
+ scancfg.depth = 8;
+ scancfg.colormode = CM_GRAY;
+ scancfg.channel = CL_RED;
+ scancfg.resolution_x = resolution_x;
+ scancfg.resolution_y = resolution_y;
+ scancfg.coord.left = 4;
+ scancfg.coord.width = (resolution_x * 3) / 10;
+ scancfg.coord.top = 1;
+ scancfg.coord.height = (resolution_y * 4) / 10;
+ scancfg.shadinglength = (resolution_x * 17) / 2;
+ scancfg.bytesperline = scancfg.coord.width;
+
+ /* allocate space to store image */
+ image =
+ (SANE_Byte *) malloc ((scancfg.coord.height * scancfg.coord.width) *
+ sizeof (SANE_Byte));
+ if (image != NULL)
+ {
+ struct st_gain_offset gain_offset;
+ SANE_Int gaincontrol, pwmlamplevel_backup, C;
+
+ gaincontrol = 0;
+ if (RTS_Debug->use_fixed_pwm == FALSE)
+ {
+ /* 3877 */
+ gaincontrol = Lamp_GetGainMode (dev, resolution_x, ST_NORMAL); /* scan.scantype */
+ pwmlamplevel = 0;
+ Lamp_PWM_use (dev, 1);
+ Lamp_PWM_DutyCycle_Set (dev, (gaincontrol == 0) ? 0x12 : 0x26);
+
+ /* Enciende flb lamp */
+ Lamp_Status_Set (dev, NULL, TRUE, FLB_LAMP);
+ usleep (1000 * 2000);
+ }
+
+ /* 38d6 */
+ pwmlamplevel_backup = pwmlamplevel;
+ pwmlamplevel = 0;
+ Lamp_PWM_use (dev, 1);
+
+ bzero (&gain_offset, sizeof (struct st_gain_offset));
+ for (C = CL_RED; C <= CL_BLUE; C++)
+ {
+ gain_offset.pag[C] = 3;
+ gain_offset.vgag1[C] = 4;
+ gain_offset.vgag2[C] = 4;
+ }
+
+ /* perform lamp warmup */
+ Lamp_Warmup (dev, Regs, FLB_LAMP, resolution_x);
+
+ /* retrieve image from scanner */
+ if (RTS_GetImage
+ (dev, Regs, &scancfg, &gain_offset, image, 0, 0x20000000,
+ gaincontrol) == OK)
+ {
+ SANE_Int ser1, ler1;
+
+ /* same image to disk if required by user */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ dbg_tiff_save ("pre-autoref.tiff",
+ scancfg.coord.width,
+ scancfg.coord.height,
+ scancfg.depth,
+ CM_GRAY,
+ scancfg.resolution_x,
+ scancfg.resolution_y,
+ image,
+ scancfg.coord.height * scancfg.coord.width);
+ }
+
+ /* calculate reference position */
+ if (Refs_Analyze_Pattern (&scancfg, image, &ler1, 1, &ser1, 0)
+ == OK)
+ {
+ *y = scancfg.coord.top + ler1;
+ *x = scancfg.coord.left + ser1;
+
+ rst = OK;
+ }
+ }
+
+ free (image);
+
+ pwmlamplevel = pwmlamplevel_backup;
+ }
+
+ DBG (DBG_FNC, " -> Detected refs: x=%i , y=%i\n", *x, *y);
+ }
+
+ DBG (DBG_FNC, "- Refs_Detect: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Refs_Set (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg)
+{
+ SANE_Int rst;
+ SANE_Int y, x;
+ struct st_autoref refcfg;
+
+ DBG (DBG_FNC, "+ Refs_Set(*Regs, *scancfg):\n");
+ dbg_ScanParams (scancfg);
+
+ rst = OK;
+
+ /* get fixed references for given resolution */
+ cfg_vrefs_get (dev->sensorcfg->type, scancfg->resolution_x, &scan.ler,
+ &scan.ser);
+ scan.leftleading = scan.ser;
+ scan.startpos = scan.ler;
+
+ /* get auto reference configuration */
+ cfg_autoref_get (&refcfg);
+
+ if (refcfg.type != REF_NONE)
+ {
+ /* if reference counter is == 0 perform auto detection */
+ if (Refs_Counter_Load (dev) == 0)
+ {
+ DBG (DBG_FNC,
+ " -> Refs_Set - Autodetection mandatory (counter == 0)\n");
+
+ refcfg.type = REF_AUTODETECT;
+ }
+
+ switch (refcfg.type)
+ {
+ case REF_AUTODETECT:
+ /* try to autodetect references scanning a little area */
+ if (Refs_Detect
+ (dev, Regs, refcfg.resolution, refcfg.resolution, &x, &y) == OK)
+ Refs_Save (dev, x, y);
+ else
+ rst = ERROR;
+
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+ break;
+
+ case REF_TAKEFROMSCANNER:
+ /* Try to get values from scanner */
+ if (Refs_Load (dev, &x, &y) == ERROR)
+ {
+ if (Refs_Detect
+ (dev, Regs, refcfg.resolution, refcfg.resolution, &x,
+ &y) == OK)
+ Refs_Save (dev, x, y);
+ else
+ rst = ERROR;
+
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+ }
+ break;
+ }
+
+ if (rst == OK)
+ {
+ /* values are based on resolution given by refcfg.resolution.
+
+ offset_x and y are based on 2400 dpi so convert values to that dpi
+ before adding offsets and then return to resolution given by user */
+
+ x *= (2400 / refcfg.resolution);
+ y *= (2400 / refcfg.resolution);
+
+ scan.leftleading = x;
+ scan.startpos = y;
+ scan.ser = ((x + refcfg.offset_x) * scancfg->resolution_x) / 2400;
+ scan.ler = ((y + refcfg.offset_y) * scancfg->resolution_y) / 2400;
+
+ DBG (DBG_FNC,
+ " -> After SEROffset and LEROffset, xoffset = %i, yoffset =%i\n",
+ scan.ser, scan.ler);
+ }
+
+ /* increase refs counter */
+ Refs_Counter_Inc (dev);
+ }
+
+ DBG (DBG_FNC, "- Refs_Set: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Lamp_Status_Set (struct st_device *dev, SANE_Byte * Regs, SANE_Int turn_on,
+ SANE_Int lamp)
+{
+ SANE_Int rst = ERROR; /* default */
+ SANE_Byte freevar = FALSE;
+
+ DBG (DBG_FNC, "+ Lamp_Status_Set(*Regs, turn_on=%i->%s, lamp=%s)\n",
+ turn_on,
+ ((((lamp - 1) | turn_on) & 1) == 1) ? "Yes" : "No",
+ (lamp == FLB_LAMP) ? "FLB_LAMP" : "TMA_LAMP");
+
+ if (Regs == NULL)
+ {
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ if (Regs != NULL)
+ freevar = TRUE;
+ }
+
+ if (Regs != NULL)
+ {
+ RTS_ReadRegs (dev->usb_handle, Regs);
+
+ /* next op depends on chipset */
+ switch (dev->chipset->model)
+ {
+ case RTS8822BL_03A:
+ /* register 0xe946 has 2 bits and each one referres one lamp
+ 0x40: FLB_LAMP | 0x20 : TMA_LAMP
+ if both were enabled both lamps would be switched on */
+ data_bitset (&Regs[0x146], 0x20, ((lamp == TMA_LAMP) && (turn_on == TRUE)) ? 1 : 0); /* TMA */
+ data_bitset (&Regs[0x146], 0x40, ((lamp == FLB_LAMP) && (turn_on == TRUE)) ? 1 : 0); /* FLB */
+
+ data_bitset (&Regs[0x155], 0x10, (lamp != FLB_LAMP) ? 1 : 0);
+ break;
+ default:
+ /* the other chipsets only use one bit to indicate when a lamp is
+ switched on or not being bit 0x10 in 0xe955 who decides which lamp
+ is affected */
+ /* switch on lamp? yes if TMA_LAMP, else whatever turn_on says */
+ data_bitset (&Regs[0x146], 0x40, ((lamp - 1) | turn_on));
+ /* what lamp must be switched on? */
+ if ((Regs[0x146] & 0x40) != 0)
+ data_bitset (&Regs[0x155], 0x10, (lamp != FLB_LAMP) ? 1 : 0);
+ break;
+ }
+
+ /*42b8cd1 */
+ /* switch on/off lamp */
+ /*dev->init_regs[0x0146] = (dev->init_regs[0x146] & 0xbf) | (Regs[0x146] & 0x40); */
+ dev->init_regs[0x0146] = (dev->init_regs[0x146] & 0x9f) | (Regs[0x146] & 0x60); /*-xx-----*/
+
+ /* Which lamp */
+ dev->init_regs[0x0155] = Regs[0x0155];
+ Write_Byte (dev->usb_handle, 0xe946, Regs[0x0146]);
+ usleep (1000 * 200);
+ Write_Buffer (dev->usb_handle, 0xe954, &Regs[0x0154], 2);
+ }
+
+ if (freevar != FALSE)
+ {
+ free (Regs);
+ Regs = NULL;
+ }
+
+ DBG (DBG_FNC, "- Lamp_Status_Set: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Get_PAG_Value (SANE_Byte scantype, SANE_Byte color)
+{
+ SANE_Int rst, iType, iColor;
+
+ switch (scantype)
+ {
+ case ST_NEG:
+ iType = CALIBNEGATIVEFILM;
+ break;
+ case ST_TA:
+ iType = CALIBTRANSPARENT;
+ break;
+ case ST_NORMAL:
+ iType = CALIBREFLECTIVE;
+ break;
+ default:
+ iType = CALIBREFLECTIVE;
+ break;
+ }
+
+ switch (color)
+ {
+ case CL_BLUE:
+ iColor = PAGB;
+ break;
+ case CL_GREEN:
+ iColor = PAGG;
+ break;
+ case CL_RED:
+ iColor = PAGR;
+ break;
+ default:
+ iColor = PAGR;
+ break;
+ }
+
+ rst = get_value (iType, iColor, 1, FITCALIBRATE);
+
+ DBG (DBG_FNC, "> Get_PAG_Value(scantype=%s, color=%i): %i\n",
+ dbg_scantype (scantype), color, rst);
+
+ return rst;
+}
+
+static SANE_Byte
+Lamp_GetGainMode (struct st_device *dev, SANE_Int resolution,
+ SANE_Byte scantype)
+{
+ SANE_Byte ret;
+ SANE_Int mygain, iValue;
+
+ switch (scantype)
+ {
+ case ST_TA:
+ ret = 0;
+ iValue = DPIGAINCONTROL_TA600;
+ break;
+ case ST_NEG:
+ ret = 1;
+ iValue = DPIGAINCONTROL_NEG600;
+ break;
+ default: /* Reflective */
+ ret = 1;
+ iValue = DPIGAINCONTROL600;
+ break;
+ }
+
+ mygain = get_value (SCAN_PARAM, iValue, ret, usbfile);
+ ret = 0;
+
+/*
+
+*/
+ if (scantype == ST_NORMAL)
+ {
+ if (dev->chipset->model == RTS8822L_02A)
+ {
+ switch (resolution)
+ {
+ case 100:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ case 2400:
+ case 4800:
+ ret = ((RTS_Debug->usbtype != USB11) && (mygain != 0)) ? 1 : 0;
+ break;
+ }
+ }
+ else
+ {
+ switch (resolution)
+ {
+ case 100:
+ case 200:
+ case 300:
+ case 600:
+ if (RTS_Debug->usbtype != USB11)
+ ret = (mygain != 0) ? 1 : 0;
+ else
+ ret = (resolution == 100) ? 1 : 0;
+ break;
+ case 1200:
+ case 2400:
+ ret = 0;
+ break;
+ }
+ }
+ }
+ else if (scantype == ST_TA)
+ {
+ switch (resolution)
+ {
+ /*hp3970 */
+ case 100:
+ case 200:
+ /*common */
+ case 300:
+ case 600:
+ case 1200:
+ case 2400:
+ /*hp4370 */
+ case 150:
+ case 4800:
+ ret = ((RTS_Debug->usbtype != USB11) && (mygain != 0)) ? 1 : 0;
+ break;
+ }
+ }
+ else
+ {
+ /* ST_NEG */
+ switch (resolution)
+ {
+ case 100:
+ case 200:
+ case 300:
+ case 600:
+ ret = ((RTS_Debug->usbtype != USB11) && (mygain != 0)) ? 1 : 0;
+ break;
+ case 1200:
+ case 2400:
+ case 4800: /*hp4370 */
+ ret = 0;
+ break;
+ }
+ }
+
+ DBG (DBG_FNC, "> Lamp_GetGainMode(resolution=%i, scantype=%s): %i\n",
+ resolution, dbg_scantype (scantype), ret);
+
+ return ret;
+}
+
+static SANE_Int
+GetOneLineInfo (struct st_device *dev, SANE_Int resolution,
+ SANE_Int * maximus, SANE_Int * minimus, double *average)
+{
+ SANE_Int rst = ERROR;
+
+ DBG (DBG_FNC,
+ "+ GetOneLineInfo(resolution=%i, *maximus, *minimus, *average):\n",
+ resolution);
+
+ /* Check parameters */
+ if ((maximus != NULL) && (minimus != NULL) && (average != NULL))
+ {
+ SANE_Byte *Regs, *image;
+ SANE_Int a, gainmode;
+ struct st_gain_offset gain_offset;
+ struct st_scanparams scancfg;
+
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (Regs != NULL)
+ {
+ /* Copy scanner registers */
+ memcpy (Regs, dev->init_regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ /* Setting some registers */
+ for (a = 0x192; a <= 0x19d; a++)
+ Regs[a] = 0;
+
+ /* Create calibration table */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ gain_offset.edcg1[a] = 256;
+ gain_offset.edcg2[a] = 0;
+ gain_offset.odcg1[a] = 256;
+ gain_offset.odcg2[a] = 0;
+ gain_offset.vgag1[a] = 4;
+ gain_offset.vgag2[a] = 4;
+ gain_offset.pag[a] = Get_PAG_Value (scan.scantype, a);
+ }
+
+ RTS_GetScanmode (dev, scantype, 0, resolution);
+
+ /* Setting scanning params */
+ memset (&scancfg, 0, sizeof (struct st_scanparams));
+ scancfg.colormode = CM_COLOR;
+ scancfg.resolution_x = resolution;
+ scancfg.resolution_y = resolution;
+ scancfg.coord.left = 100;
+ scancfg.coord.width = (resolution * 8.5) - 100;
+ scancfg.coord.top = 1;
+ scancfg.coord.height = 1;
+ scancfg.depth = 8;
+ scancfg.shadinglength = resolution * 8.5;
+ scancfg.v157c = scancfg.coord.width * 3;
+ scancfg.bytesperline = scancfg.v157c;
+
+ /* Reserve buffer for line */
+ image =
+ (SANE_Byte *) malloc (((scancfg.coord.width * 0x21) * 3) *
+ sizeof (SANE_Byte));
+ if (image != NULL)
+ {
+ gainmode =
+ Lamp_GetGainMode (dev, resolution & 0xffff, scan.scantype);
+ if (RTS_GetImage
+ (dev, Regs, &scancfg, &gain_offset, image, 0,
+ OP_STATIC_HEAD, gainmode) != ERROR)
+ {
+ /* Read all image to take max min and average colours */
+ SANE_Byte *pointer1 = image;
+ SANE_Byte *pointer2;
+ SANE_Byte *pointer3;
+ SANE_Int cmin[3]; /* min values */
+ SANE_Int cmax[3]; /* max values */
+ double cave[3]; /* average values */
+ SANE_Int mysize;
+
+ if (scancfg.colormode != CM_GRAY)
+ {
+ pointer2 = image;
+ pointer3 = image;
+ }
+ else
+ {
+ pointer2 = image + 1;
+ pointer3 = image + 2;
+ }
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ cmin[a] = 255;
+ cmax[a] = 0;
+ cave[a] = 0;
+ }
+
+ if (scancfg.coord.height > 0)
+ {
+ SANE_Int y, x;
+ SANE_Byte *mypointer;
+ SANE_Byte color;
+ SANE_Int desp[3];
+
+ desp[CL_RED] = pointer1 - pointer3;
+ desp[CL_GREEN] = pointer2 - pointer3;
+ desp[CL_BLUE] = 0;
+
+ for (y = 0; y < scancfg.coord.height; y++)
+ {
+ if (scancfg.coord.width > 0)
+ {
+ mypointer = pointer3;
+
+ for (x = 0; x < scancfg.coord.width; x++)
+ {
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ /* Take colour values */
+ color = *(mypointer + desp[a]);
+
+ /* Take max values for each color */
+ cmax[a] = max (cmax[a], color);
+
+ /* Take min values for each color */
+ cmin[a] = min (cmin[a], color);
+
+ /* Average */
+ cave[a] += color;
+ }
+
+ mypointer += 3;
+ }
+ }
+
+ /* point to the pixel that is below */
+ pointer1 += scancfg.coord.width * 3;
+ pointer2 += scancfg.coord.width * 3;
+ pointer3 += scancfg.coord.width * 3;
+ }
+ }
+
+ mysize = scancfg.coord.height * scancfg.coord.width;
+ if (mysize < 1)
+ mysize = 1;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ maximus[a] = cmax[a];
+ minimus[a] = cmin[a];
+ average[a] = cave[a] / mysize;
+ }
+
+ DBG (DBG_FNC, " -> GetOneLineInfo: max r=%3i g=%3i b=%3i\n",
+ maximus[CL_RED], maximus[CL_GREEN], maximus[CL_BLUE]);
+ DBG (DBG_FNC, " -> min r=%3i g=%3i b=%3i\n",
+ minimus[CL_RED], minimus[CL_GREEN], minimus[CL_BLUE]);
+ DBG (DBG_FNC,
+ " -> avg r=%3.0f g=%3.0f b=%3.0f\n",
+ average[CL_RED], average[CL_GREEN], average[CL_BLUE]);
+
+ rst = OK;
+ }
+
+ free (image);
+ }
+
+ free (Regs);
+ }
+ }
+
+ DBG (DBG_FNC, "- GetOneLineInfo: %i\n", rst);
+
+ return OK;
+}
+
+static SANE_Int
+Lamp_PWM_CheckStable (struct st_device *dev, SANE_Int resolution,
+ SANE_Int lamp)
+{
+ struct st_checkstable check;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Lamp_PWM_CheckStable(resolution=%i, lamp=%i):\n",
+ resolution, lamp);
+
+ rst = cfg_checkstable_get (lamp, &check);
+
+ if (rst == OK)
+ {
+ SANE_Int maximus[3] = { 0 };
+ SANE_Int minimus[3] = { 0 };
+ double average[3] = { 0 };
+ SANE_Int maxbigger;
+ SANE_Int last_colour = 0;
+
+ double diff = check.diff * 0.01;
+ long tottime = GetTickCount () + check.tottime;
+
+ while (GetTickCount () <= tottime)
+ {
+ rst = GetOneLineInfo (dev, resolution, maximus, minimus, average);
+ if (rst == OK)
+ {
+ /* Takes maximal colour value */
+ maxbigger =
+ max (maximus[CL_GREEN],
+ max (maximus[CL_BLUE], maximus[CL_RED]));
+
+ /*breaks when colour intensity increases 'diff' or lower */
+ if (abs (maxbigger - last_colour) < diff)
+ {
+ DBG (DBG_FNC, " -> PWM is ready\n");
+ break;
+ }
+
+ last_colour = maxbigger;
+ }
+
+ usleep (1000 * check.interval);
+ }
+
+ }
+
+ DBG (DBG_FNC, "- Lamp_PWM_CheckStable: %i\n", rst);
+
+ return OK;
+}
+
+static SANE_Byte
+Refs_Counter_Load (struct st_device *dev)
+{
+ SANE_Byte data = 15;
+
+ DBG (DBG_FNC, "+ Refs_Counter_Load:\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ if (RTS_EEPROM_ReadByte (dev->usb_handle, 0x78, &data) != OK)
+ data = 15;
+
+ DBG (DBG_FNC, "- Refs_Counter_Load: %i\n", _B0 (data));
+
+ return data;
+}
+
+static SANE_Int
+Refs_Counter_Save (struct st_device *dev, SANE_Byte data)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ Refs_Counter_Save(data=%i):\n", data);
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ if (data > 15)
+ data = 15;
+
+ rst = RTS_EEPROM_WriteByte (dev->usb_handle, 0x78, data);
+ }
+
+ DBG (DBG_FNC, "- Refs_Counter_Save: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Refs_Counter_Inc (struct st_device *dev)
+{
+ SANE_Byte data;
+
+ DBG (DBG_FNC, "+ Refs_Counter_Inc:\n");
+
+ data = Refs_Counter_Load (dev) + 1;
+
+ if (data >= 15)
+ data = 0;
+
+ Refs_Counter_Save (dev, data);
+
+ DBG (DBG_FNC, "- Refs_Counter_Inc() : Count=%i\n", data);
+
+ return OK;
+}
+
+static SANE_Int
+Load_StripCoords (SANE_Int scantype, SANE_Int * ypos, SANE_Int * xpos)
+{
+ SANE_Int iType;
+
+ switch (scantype)
+ {
+ case 3:
+ iType = CALIBNEGATIVEFILM;
+ break;
+ case 2:
+ iType = CALIBTRANSPARENT;
+ break;
+ default:
+ iType = CALIBREFLECTIVE;
+ break;
+ }
+
+ *xpos = get_value (iType, WSTRIPXPOS, 0, FITCALIBRATE);
+ *ypos = get_value (iType, WSTRIPYPOS, 0, FITCALIBRATE);
+
+ DBG (DBG_FNC, "> Load_StripCoords(scantype=%s): ypos=%i, xpos=%i\n",
+ dbg_scantype (scantype), *ypos, *xpos);
+
+ return OK;
+}
+
+static SANE_Int
+Head_Relocate (struct st_device *dev, SANE_Int speed, SANE_Int direction,
+ SANE_Int ypos)
+{
+ SANE_Int rst;
+ SANE_Byte *Regs;
+
+ DBG (DBG_FNC, "+ Head_Relocate(speed=%i, direction=%i, ypos=%i):\n", speed,
+ direction, ypos);
+
+ rst = ERROR;
+
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (Regs != NULL)
+ {
+ struct st_motormove mymotor;
+ struct st_motorpos mtrpos;
+
+ bzero (&mymotor, sizeof (struct st_motormove));
+ memcpy (Regs, dev->init_regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ if (speed < dev->motormove_count)
+ memcpy (&mymotor, dev->motormove[speed],
+ sizeof (struct st_motormove));
+
+ /*83fe */
+ mtrpos.coord_y = ypos;
+ mtrpos.options =
+ MTR_ENABLED | ((direction == MTR_BACKWARD) ? MTR_BACKWARD :
+ MTR_FORWARD);
+ mtrpos.v12e448 = 0;
+ mtrpos.v12e44c = 1;
+
+ Motor_Move (dev, Regs, &mymotor, &mtrpos);
+
+ /* waits 15 seconds */
+ RTS_WaitScanEnd (dev, 15000);
+
+ free (Regs);
+ rst = OK;
+ }
+
+ DBG (DBG_FNC, "- Head_Relocate: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Calib_CreateFixedBuffers ()
+{
+ SANE_Byte channel;
+ SANE_Int ret;
+
+ DBG (DBG_FNC, "> Calib_CreateFixedBuffers()\n");
+
+ ret = OK;
+ channel = 0;
+
+ while ((channel < 3) && (ret == OK))
+ {
+ /* First table */
+ if (fixed_black_shading[channel] == NULL)
+ fixed_black_shading[channel] =
+ (USHORT *) malloc (0x7f8 * sizeof (USHORT));
+
+ if (fixed_black_shading[channel] != NULL)
+ bzero (fixed_black_shading[channel], 0x7f8 * sizeof (USHORT));
+ else
+ ret = ERROR;
+
+ /* Second table */
+ if (fixed_white_shading[channel] == NULL)
+ fixed_white_shading[channel] =
+ (USHORT *) malloc (0x7f8 * sizeof (USHORT));
+
+ if (fixed_white_shading[channel] != NULL)
+ bzero (fixed_white_shading[channel], 0x7f8 * sizeof (USHORT));
+ else
+ ret = ERROR;
+
+ channel++;
+ }
+
+ return ret;
+}
+
+static SANE_Int
+Calib_CreateBuffers (struct st_device *dev, struct st_calibration *buffer,
+ SANE_Int my14b4)
+{
+ SANE_Int ebp, ret, channel;
+
+ ret = ERROR;
+ dev = dev;
+
+ buffer->shadinglength = scan.coord.width;
+ ebp = 0x14;
+
+ if (my14b4 != 0)
+ {
+ /* 673d */
+ if (Calib_CreateFixedBuffers () == OK)
+ {
+ for (channel = 0; channel < 3; channel++)
+ {
+ buffer->white_shading[channel] = fixed_white_shading[channel];
+ buffer->black_shading[channel] = fixed_black_shading[channel];
+ }
+ ret = OK;
+ }
+ }
+ else
+ {
+ /* 677f */
+ SANE_Int pos;
+ channel = 0;
+ while ((channel < 3) && (ret == OK))
+ {
+ buffer->black_shading[channel] =
+ (USHORT *) malloc (ebp +
+ (buffer->shadinglength * sizeof (USHORT)));
+ buffer->white_shading[channel] =
+ (USHORT *) malloc (ebp +
+ (buffer->shadinglength * sizeof (USHORT)));
+ if ((buffer->black_shading[channel] != NULL)
+ && (buffer->white_shading[channel] != NULL))
+ {
+ for (pos = 0; pos < buffer->shadinglength; pos++)
+ {
+ buffer->black_shading[channel][pos] = 0x00;
+ buffer->white_shading[channel][pos] = 0x4000;
+ }
+ ret = OK;
+ }
+ else
+ Calib_FreeBuffers (buffer);
+
+ channel++;
+ }
+ }
+
+ DBG (DBG_FNC, "> Calib_CreateBuffers: *buffer, my14b4=%i): %i\n", my14b4,
+ ret);
+
+ return ret;
+}
+
+static void
+Calib_FreeBuffers (struct st_calibration *caltables)
+{
+ DBG (DBG_FNC, "> Calib_FreeBuffers(*caltables)\n");
+
+ if (caltables != NULL)
+ {
+ SANE_Int channel;
+
+ for (channel = 0; channel < 3; channel++)
+ {
+ if (caltables->black_shading[channel] != NULL)
+ {
+ free (caltables->black_shading[channel]);
+ caltables->black_shading[channel] = NULL;
+ }
+
+ if (caltables->white_shading[channel] != NULL)
+ {
+ free (caltables->white_shading[channel]);
+ caltables->white_shading[channel] = NULL;
+ }
+ }
+ }
+}
+
+static SANE_Int
+Calib_LoadConfig (struct st_device *dev,
+ struct st_calibration_config *calibcfg, SANE_Int scantype,
+ SANE_Int resolution, SANE_Int bitmode)
+{
+ SANE_Int section, a;
+ struct st_autoref refcfg;
+
+ DBG (DBG_FNC,
+ "> Calib_LoadConfig(*calibcfg, scantype=%s, resolution=%i, bitmode=%i)\n",
+ dbg_scantype (scantype), resolution, bitmode);
+
+ switch (scantype)
+ {
+ case ST_NEG:
+ section = CALIBNEGATIVEFILM;
+ break;
+ case ST_TA:
+ section = CALIBTRANSPARENT;
+ break;
+ default:
+ section = CALIBREFLECTIVE;
+ break;
+ }
+
+ calibcfg->WStripXPos = get_value (section, WSTRIPXPOS, 0, FITCALIBRATE);
+ calibcfg->WStripYPos = get_value (section, WSTRIPYPOS, 0, FITCALIBRATE);
+ calibcfg->BStripXPos = get_value (section, BSTRIPXPOS, 0, FITCALIBRATE);
+ calibcfg->BStripYPos = get_value (section, WSTRIPYPOS, 0, FITCALIBRATE);
+
+ /* get calibration wrefs */
+ cfg_wrefs_get (dev->sensorcfg->type, bitmode, resolution, scantype,
+ &calibcfg->WRef[CL_RED], &calibcfg->WRef[CL_GREEN],
+ &calibcfg->WRef[CL_BLUE]);
+
+ /* 4913 */
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ WRef[a] = _B0 (calibcfg->WRef[a]);
+
+ calibcfg->BRef[a] = get_value (section, BREFR + a, 10, FITCALIBRATE);
+ calibcfg->OffsetEven1[a] =
+ get_value (section, OFFSETEVEN1R + a, 256, FITCALIBRATE);
+ calibcfg->OffsetEven2[a] =
+ get_value (section, OFFSETEVEN2R + a, 0, FITCALIBRATE);
+ calibcfg->OffsetOdd1[a] =
+ get_value (section, OFFSETODD1R + a, 256, FITCALIBRATE);
+ calibcfg->OffsetOdd2[a] =
+ get_value (section, OFFSETODD2R + a, 0, FITCALIBRATE);
+ }
+
+ calibcfg->RefBitDepth =
+ _B0 (get_value (section, REFBITDEPTH, 8, FITCALIBRATE));
+ calibcfg->CalibOffset10n =
+ _B0 (get_value (section, CALIBOFFSET10N, 3, FITCALIBRATE));
+ calibcfg->CalibOffset20n =
+ _B0 (get_value (section, CALIBOFFSET20N, 0, FITCALIBRATE));
+ calibcfg->OffsetHeight =
+ get_value (section, OFFSETHEIGHT, 10, FITCALIBRATE);
+
+ /* 4ae9 */
+
+ /* get left coordinate and length to calibrate offset */
+ cfg_offset_get (dev->sensorcfg->type, resolution, scantype,
+ &calibcfg->OffsetPixelStart, &calibcfg->OffsetNPixel);
+
+ /*4c49 */
+ calibcfg->OffsetNSigma = get_value (section, OFFSETNSIGMA, 2, FITCALIBRATE);
+ calibcfg->OffsetTargetMax =
+ get_value (section, OFFSETTARGETMAX, 0x32, FITCALIBRATE) * 0.01;
+ calibcfg->OffsetTargetMin =
+ get_value (section, OFFSETTARGETMIN, 2, FITCALIBRATE) * 0.01;
+ calibcfg->OffsetBoundaryRatio1 =
+ get_value (section, OFFSETBOUNDARYRATIO1, 0x64, FITCALIBRATE) * 0.01;
+ calibcfg->OffsetBoundaryRatio2 =
+ get_value (section, OFFSETBOUNDARYRATIO2, 0x64, FITCALIBRATE) * 0.01;
+
+ calibcfg->OffsetAvgRatio1 =
+ get_value (section, OFFSETAVGRATIO1, 0x64, FITCALIBRATE) * 0.01;
+ calibcfg->OffsetAvgRatio2 =
+ get_value (section, OFFSETAVGRATIO2, 0x64, FITCALIBRATE) * 0.01;
+ calibcfg->AdcOffQuickWay =
+ get_value (section, ADCOFFQUICKWAY, 1, FITCALIBRATE);
+ calibcfg->AdcOffPredictStart =
+ get_value (section, ADCOFFPREDICTSTART, 0xc8, FITCALIBRATE);
+ calibcfg->AdcOffPredictEnd =
+ get_value (section, ADCOFFPREDICTEND, 0x1f4, FITCALIBRATE);
+ calibcfg->AdcOffEvenOdd =
+ get_value (section, ADCOFFEVENODD, 1, FITCALIBRATE);
+ calibcfg->OffsetTuneStep1 =
+ _B0 (get_value (section, OFFSETTUNESTEP1, 1, FITCALIBRATE));
+ calibcfg->OffsetTuneStep2 =
+ _B0 (get_value (section, OFFSETTUNESTEP2, 1, FITCALIBRATE));
+ calibcfg->CalibGain10n = get_value (section, CALIBGAIN10N, 1, FITCALIBRATE);
+ calibcfg->CalibGain20n = get_value (section, CALIBGAIN20N, 0, FITCALIBRATE);
+ calibcfg->CalibPAGOn = get_value (section, CALIBPAGON, 0, FITCALIBRATE);
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ calibcfg->OffsetAvgTarget[a] =
+ _B0 (get_value (section, OFFSETAVGTARGETR + a, 0x0d, FITCALIBRATE));
+ calibcfg->PAG[a] = get_value (section, PAGR + a, 3, FITCALIBRATE);
+ calibcfg->Gain1[a] = get_value (section, GAIN1R + a, 4, FITCALIBRATE);
+ calibcfg->Gain2[a] = get_value (section, GAIN2R + a, 4, FITCALIBRATE);
+ calibcfg->WShadingPreDiff[a] =
+ get_value (section, WSHADINGPREDIFFR + a, -1, FITCALIBRATE);
+ calibcfg->BShadingPreDiff[a] =
+ get_value (section, BSHADINGPREDIFFR + a, 2, FITCALIBRATE);
+ }
+
+ calibcfg->GainHeight = get_value (section, GAINHEIGHT, 0x1e, FITCALIBRATE);
+ calibcfg->GainTargetFactor =
+ get_value (section, GAINTARGETFACTOR, 0x5a, FITCALIBRATE) * 0.01;
+ calibcfg->TotShading = get_value (section, TOTSHADING, 0, FITCALIBRATE);
+
+ /* White shading */
+ calibcfg->WShadingOn = get_value (section, WSHADINGON, 3, FITCALIBRATE);
+ calibcfg->WShadingHeight =
+ get_value (section, WSHADINGHEIGHT, 0x18, FITCALIBRATE);
+
+ /* Black shading */
+ calibcfg->BShadingOn = get_value (section, BSHADINGON, 2, FITCALIBRATE);
+ calibcfg->BShadingHeight =
+ get_value (section, BSHADINGHEIGHT, 0x1e, FITCALIBRATE);
+
+ calibcfg->BShadingDefCutOff =
+ get_value (section, BSHADINGDEFCUTOFF, 0, FITCALIBRATE);
+
+ refcfg.extern_boundary = 0;
+ cfg_autoref_get (&refcfg);
+ calibcfg->ExternBoundary = refcfg.extern_boundary * 0.01;
+
+ calibcfg->EffectivePixel =
+ cfg_effectivepixel_get (dev->sensorcfg->type, resolution);
+
+ return OK;
+}
+
+static SANE_Int
+Calib_AdcGain (struct st_device *dev, struct st_calibration_config *calibcfg,
+ SANE_Int arg2, SANE_Int gaincontrol)
+{
+ /*
+ 0606F8E0 04F60738 |Arg1 = 04F60738
+ 0606F8E4 0606F90C |Arg2 = 0606F90C calibcfg
+ 0606F8E8 00000001 |Arg3 = 00000001 arg2
+ 0606F8EC 00000001 \Arg4 = 00000001 gaincontrol
+ */
+
+ SANE_Int rst = ERROR;
+ SANE_Byte *myRegs; /*f1c0 */
+
+ DBG (DBG_FNC, "+ Calib_AdcGain(*calibcfg, arg2=%i, gaincontrol=%i)\n", arg2,
+ gaincontrol);
+
+ myRegs = (SANE_Byte *) malloc (sizeof (SANE_Byte) * RT_BUFFER_LEN);
+ if (myRegs != NULL)
+ {
+ struct st_scanparams *scancfg; /*f17c */
+ SANE_Int bytes_per_line, bytes_to_next_colour, bytes_per_pixel;
+
+ /* get register values to perform adc gain calibration */
+ memcpy (myRegs, &calibdata->Regs, sizeof (SANE_Byte) * RT_BUFFER_LEN);
+
+ scancfg =
+ (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ if (scancfg != NULL)
+ {
+ SANE_Byte *image, *pgain, *pcalgain;
+
+ /* get proper scan configuration */
+ memcpy (scancfg, &calibdata->scancfg,
+ sizeof (struct st_scanparams));
+
+ /* set gain control type */
+ Lamp_SetGainMode (dev, myRegs, scancfg->resolution_x, gaincontrol);
+
+ /* 8-bit depth */
+ scancfg->depth = 8;
+
+ /* set coordinates */
+ if ((scan.scantype > 0) && (scan.scantype < 4))
+ scancfg->coord.left += scan.ser;
+
+ if ((scancfg->coord.width & 1) == 0)
+ scancfg->coord.width++;
+
+ scancfg->coord.top = 1;
+ scancfg->coord.height = calibcfg->OffsetHeight;
+
+ /* three more values to read image data after getting image from scanner */
+ switch (scancfg->colormode)
+ {
+ case CM_GRAY:
+ case CM_LINEART:
+ bytes_to_next_colour = 0;
+ bytes_per_pixel = 1;
+ bytes_per_line = scancfg->coord.width;
+ break;
+ default: /* CM_COLOR */
+ /* c027 */
+ bytes_to_next_colour = 1;
+ bytes_per_line = scancfg->coord.width * 3;
+ if (scancfg->samplerate == LINE_RATE)
+ {
+ bytes_to_next_colour = scancfg->coord.width;
+ bytes_per_pixel = 1;
+ }
+ else
+ bytes_per_pixel = 3;
+ break;
+ }
+
+ /*7fc7 */
+ scancfg->v157c = bytes_per_line;
+ scancfg->bytesperline = bytes_per_line;
+
+ /* select type of gain parameters to set */
+ if (arg2 != 0)
+ {
+ pgain = calibdata->gain_offset.vgag1;
+ pcalgain = calibcfg->Gain1;
+ }
+ else
+ {
+ /*7ff2 */
+ pgain = calibdata->gain_offset.vgag2;
+ pcalgain = calibcfg->Gain2;
+ }
+
+ /*8002 */
+ /* Allocate space for image | size = 132912 */
+ image =
+ (SANE_Byte *) malloc (sizeof (SANE_Byte) *
+ ((scancfg->coord.height +
+ 16) * bytes_per_line));
+ if (image != NULL)
+ {
+ /* Lets read image */
+ if (RTS_GetImage
+ (dev, myRegs, scancfg, &calibdata->gain_offset, image, NULL,
+ OP_STATIC_HEAD, gaincontrol) == OK)
+ {
+ SANE_Int a;
+ SANE_Int vmin[3], vmax[3];
+ double dval[3] = { 0.0 }; /*f1a8 f1b0 f1b8 */
+ SANE_Byte *pimage = image;
+
+ /* initialize values */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ calibcfg->unk1[a] = 0;
+ calibcfg->unk2[a] = 0xff;
+
+ vmin[a] = 0xff;
+ vmax[a] = 0;
+ }
+
+ /* process image data */
+ if (scancfg->coord.width > 0)
+ {
+ /*8104 */
+ SANE_Int pos, myheight /*f164 */ ;
+ SANE_Int chn_sum[3];
+
+ for (pos = scancfg->coord.width; pos > 0; pos--)
+ {
+ chn_sum[CL_RED] = chn_sum[CL_GREEN] =
+ chn_sum[CL_BLUE] = 0;
+
+ if (scancfg->coord.height > 0)
+ for (myheight = 0;
+ myheight < scancfg->coord.height; myheight++)
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ chn_sum[a] +=
+ *(pimage + (bytes_per_line * myheight) +
+ (bytes_to_next_colour * a));
+
+ /*816e */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ vmin[a] =
+ min (vmin[a],
+ chn_sum[a] / scancfg->coord.height);
+ vmax[a] =
+ max (vmax[a],
+ chn_sum[a] / scancfg->coord.height);
+
+ calibcfg->unk1[a] =
+ max (calibcfg->unk1[a], vmax[a]);
+ calibcfg->unk2[a] =
+ min (calibcfg->unk1[a], vmin[a]);
+
+ dval[a] += vmax[a] & 0xffff;
+ }
+
+ pimage += bytes_per_pixel;
+ }
+ }
+
+ /*82b0 */
+ dval[CL_RED] /= scancfg->coord.width;
+ dval[CL_GREEN] /= scancfg->coord.width;
+ dval[CL_BLUE] /= scancfg->coord.width;
+
+ DBG (DBG_FNC, " -> adcgain (av/l): r=%f, g=%f, b=%f\n",
+ dval[CL_RED], dval[CL_GREEN], dval[CL_BLUE]);
+ DBG (DBG_FNC, " -> (max ): R=%i, G=%i, B=%i\n",
+ calibcfg->unk1[CL_RED], calibcfg->unk1[CL_GREEN],
+ calibcfg->unk1[CL_BLUE]);
+ DBG (DBG_FNC, " -> (min ): r=%i, g=%i, b=%i\n",
+ calibcfg->unk2[CL_RED], calibcfg->unk2[CL_GREEN],
+ calibcfg->unk2[CL_BLUE]);
+
+ if (scancfg->colormode == CM_COLOR)
+ {
+ /*8353 */
+ double dvalue;
+ SANE_Int ival;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ dvalue =
+ ((((calibcfg->WRef[a] * (1 << scancfg->depth)) *
+ calibcfg->GainTargetFactor) * 0.00390625) /
+ dval[a]) * ((44 - pgain[a]) / 40);
+ if (dvalue > 0.9090909090909091)
+ {
+ /*83d7 */
+ dvalue = min (44 - (40 / dvalue), 31);
+ ival = dvalue;
+ pgain[a] = _B0 (ival);
+ pcalgain[a] = _B0 (ival);
+ }
+ else
+ {
+ pgain[a] = 0;
+ pcalgain[a] = 0;
+ }
+ }
+ }
+ else
+ {
+ /*843c */
+ /*falta codigo */
+ double dvalue;
+ SANE_Int ival;
+
+ dvalue =
+ ((44 -
+ pgain[CL_RED]) / 40) * ((((1 << scancfg->depth) *
+ calibcfg->WRef[scancfg->
+ channel]) *
+ 0.9) * 0.00390625) /
+ 17.08509389671362;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ if (dvalue > 0.9090909090909091)
+ {
+ dvalue = min (44 - (40 / dvalue), 31);
+ ival = dvalue;
+ pgain[a] = _B0 (ival);
+ pcalgain[a] = _B0 (ival);
+ }
+ else
+ {
+ /*84e3 */
+ pgain[a] = 0;
+ pcalgain[a] = 0;
+ }
+ }
+ }
+
+ /*84fa */
+ /* Save buffer */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ dbg_tiff_save ("adcgain.tiff",
+ scancfg->coord.width,
+ scancfg->coord.height,
+ scancfg->depth,
+ CM_COLOR,
+ scancfg->resolution_x,
+ scancfg->resolution_y,
+ image,
+ (scancfg->coord.height +
+ 16) * bytes_per_line);
+ }
+
+ /* check if peak values are above offset average target + 5 */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ if (calibcfg->unk1[a] >= calibcfg->OffsetAvgTarget[a] + 5)
+ {
+ rst = OK;
+ break;
+ }
+ }
+
+ free (image);
+ }
+
+ free (scancfg);
+ }
+
+ free (myRegs);
+ }
+
+ /* v14b8 = (rst == OK)? 0: 1; */
+
+ /* show */
+ dbg_calibtable (&calibdata->gain_offset);
+
+ DBG (DBG_FNC, "- Calib_AdcGain: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+GainOffset_Save (struct st_device *dev, SANE_Int * offset, SANE_Byte * gain)
+{
+ SANE_Int rst = OK;
+
+ DBG (DBG_FNC, "+ GainOffset_Save(*offset, *gain):\n");
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ if ((offset != NULL) && (gain != NULL))
+ {
+ SANE_Int a, crc, value;
+
+ crc = 0x5B;
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ value = (*gain << 9) | *offset;
+ crc = _B0 (abs (crc - _B0 (value)));
+ rst =
+ RTS_EEPROM_WriteWord (dev->usb_handle, 0x70 + (a * 2), value);
+ }
+
+ if (rst == OK)
+ rst = RTS_EEPROM_WriteByte (dev->usb_handle, 0x76, crc);
+ }
+ else
+ rst = ERROR;
+ }
+
+ DBG (DBG_FNC, "- GainOffset_Save: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+Calib_PAGain (struct st_device *dev, struct st_calibration_config *calibcfg,
+ SANE_Int gainmode)
+{
+ SANE_Byte *Regs;
+ struct st_scanparams *scancfg;
+ SANE_Int channel_size;
+ SANE_Int bytes_to_next_colour = 0;
+ SANE_Int bytes_per_pixel = 0;
+ SANE_Int length = 0;
+ SANE_Byte *image;
+ double rst;
+ SANE_Int ret = ERROR;
+
+ DBG (DBG_FNC, "+ Calib_PAGain(*calibcfg, gainmode=%i)\n", gainmode);
+
+ Regs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ if (Regs != NULL)
+ {
+ scancfg =
+ (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ if (scancfg != NULL)
+ {
+ memcpy (Regs, &calibdata->Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (scancfg, &calibdata->scancfg,
+ sizeof (struct st_scanparams));
+
+ if (scan.scantype == ST_NORMAL)
+ {
+ /* bfa5 */
+ scancfg->coord.left = scan.ser;
+ scancfg->coord.width = (scancfg->sensorresolution * 17) / 2;
+ }
+ else
+ {
+ scancfg->coord.left = scan.ser + v0750;
+ scancfg->coord.width = (scancfg->sensorresolution * 3) / 2;
+ }
+
+ /* bfca */
+ if ((scancfg->coord.width & 1) == 1)
+ scancfg->coord.width++;
+
+ scancfg->coord.top = 1;
+ scancfg->coord.height = calibcfg->OffsetHeight;
+
+ channel_size = (scancfg->depth > 8) ? 2 : 1;
+
+ switch (scancfg->colormode)
+ {
+ case CM_GRAY:
+ case CM_LINEART:
+ bytes_to_next_colour = 0;
+ bytes_per_pixel = 1;
+ length = channel_size * scancfg->coord.width;
+ break;
+ default: /* CM_COLOR */
+ /* c027 */
+ bytes_to_next_colour = 1;
+ length = (channel_size * scancfg->coord.width) * 3;
+ if (scancfg->samplerate == LINE_RATE)
+ {
+ bytes_to_next_colour = scancfg->coord.width;
+ bytes_per_pixel = 1;
+ }
+ else
+ bytes_per_pixel = 3;
+ break;
+ }
+
+ /* c070 */
+ scancfg->v157c = length;
+
+ image =
+ (SANE_Byte *) malloc ((scancfg->coord.height * length) *
+ sizeof (SANE_Byte));
+ if (image != NULL)
+ {
+ ret =
+ RTS_GetImage (dev, Regs, scancfg, &calibdata->gain_offset,
+ image, 0, OP_STATIC_HEAD, gainmode);
+ if (ret == OK)
+ {
+ /* 429c105 */
+ SANE_Int a;
+ SANE_Byte *ptr[3];
+ SANE_Int vmin[3] = { 255, 255, 255 }; /* f16c|f16e|f170 */
+ SANE_Int vmax[3] = { 0, 0, 0 }; /* f164|f166|f168 */
+ SANE_Int total[3];
+
+ ptr[CL_RED] = image;
+ ptr[CL_GREEN] = image + bytes_to_next_colour;
+ ptr[CL_BLUE] = image + (bytes_to_next_colour * 2);
+
+ if (scancfg->coord.width > 0)
+ {
+ SANE_Int pos, b;
+
+ for (pos = 0; pos < scancfg->coord.width; pos++)
+ {
+ total[CL_BLUE] = 0;
+ total[CL_GREEN] = 0;
+ total[CL_RED] = 0;
+
+ for (a = 0; a < scancfg->coord.height; a++)
+ {
+ for (b = CL_RED; b <= CL_BLUE; b++)
+ total[b] +=
+ *(ptr[b] +
+ ((scancfg->coord.height - a) * length));
+ }
+
+ /* c1a5 */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ total[a] /= scancfg->coord.height;
+ vmin[a] = min (vmin[a], total[a]);
+ vmax[a] = max (vmax[a], total[a]);
+
+ ptr[a] += bytes_per_pixel;
+ }
+ }
+ }
+
+ /* 429c234 */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ rst =
+ (calibcfg->WRef[a] * calibcfg->GainTargetFactor) /
+ vmax[a];
+ if (rst <= 1.5)
+ {
+ if (rst <= 1.286)
+ {
+ if (rst <= 1.125)
+ calibdata->gain_offset.pag[a] = 0;
+ else
+ calibdata->gain_offset.pag[a] = 1;
+ }
+ else
+ calibdata->gain_offset.pag[a] = 2;
+ }
+ else
+ calibdata->gain_offset.pag[a] = 3;
+ }
+ }
+ free (image);
+ }
+ free (scancfg);
+ }
+ free (Regs);
+ }
+
+ DBG (DBG_FNC, "- Calib_PAGain: %i\n", ret);
+
+ return ret;
+}
+
+static SANE_Int
+Chipset_ID (struct st_device *dev)
+{
+ SANE_Int ret;
+
+ if (Read_Word (dev->usb_handle, 0xfe3c, &ret) == OK)
+ ret = _B0 (ret);
+ else
+ ret = 0;
+
+ DBG (DBG_FNC, "> Chipset_ID(): %i\n", ret);
+
+ return ret;
+}
+
+static SANE_Int
+Chipset_Name (struct st_device *dev, char *name, SANE_Int size)
+{
+ SANE_Int rst = ERROR;
+
+ if (name != NULL)
+ {
+ strncpy (name, dev->chipset->name, size);
+ rst = OK;
+ }
+
+ return rst;
+}
+
+static SANE_Int
+Refs_Load (struct st_device *dev, SANE_Int * x, SANE_Int * y)
+{
+ SANE_Int ret = OK;
+
+ DBG (DBG_FNC, "+ Refs_Load:\n");
+
+ *y = *x = 0;
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ SANE_Int data;
+
+ ret = ERROR;
+
+ if (RTS_EEPROM_ReadWord (dev->usb_handle, 0x6a, &data) == OK)
+ {
+ *x = data;
+ if (RTS_EEPROM_ReadWord (dev->usb_handle, 0x6c, &data) == OK)
+ {
+ *y = data;
+ if (RTS_EEPROM_ReadWord (dev->usb_handle, 0x6e, &data) == OK)
+ {
+ if ((_B0 (*y + *x + data)) == 0x5a)
+ ret = OK;
+ }
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- Refs_Load(y=%i, x=%i) : %i\n", *y, *x, ret);
+
+ return ret;
+}
+
+static SANE_Int
+Refs_Save (struct st_device *dev, SANE_Int left_leading, SANE_Int start_pos)
+{
+ SANE_Int ret = OK;
+
+ DBG (DBG_FNC, "+ Refs_Save(left_leading=%i, start_pos=%i)\n", left_leading,
+ start_pos);
+
+ /* check if chipset supports accessing eeprom */
+ if ((dev->chipset->capabilities & CAP_EEPROM) != 0)
+ {
+ ret = ERROR;
+
+ if (RTS_EEPROM_WriteWord (dev->usb_handle, 0x6a, left_leading) == OK)
+ {
+ if (RTS_EEPROM_WriteWord (dev->usb_handle, 0x6c, start_pos) == OK)
+ {
+ SANE_Byte data = _B0 (0x5a - (start_pos + left_leading));
+ ret = RTS_EEPROM_WriteByte (dev->usb_handle, 0x6e, data);
+ }
+ }
+ }
+
+ DBG (DBG_FNC, "- Refs_Save: %i\n", ret);
+
+ return ret;
+}
+
+static SANE_Int
+Calib_AdcOffsetRT (struct st_device *dev,
+ struct st_calibration_config *calibcfg, SANE_Int value)
+{
+/*
+05EFF8E4 04F10738 |Arg1 = 04F10738
+05EFF8E8 05EFF90C |Arg2 = 05EFF90C calibcfg
+05EFF8EC 00000001 \Arg3 = 00000001 value
+*/
+ SANE_Byte Regs[RT_BUFFER_LEN]; /*f1c4 */
+ SANE_Int channels_per_dot; /*f108 */
+ struct st_scanparams scancfg; /*f18c */
+ SANE_Int *pedcg; /*f114 */
+ SANE_Int *podcg; /*f118 */
+ SANE_Int *poffseteven; /*f130 */
+ SANE_Int *poffsetodd; /*f128 */
+ SANE_Int channel;
+ SANE_Int avgtarget[3]; /*f1b8 f1bc f1c0 */
+ SANE_Byte *scanbuffer; /*f0f8 */
+ SANE_Int scan_options; /*f12c */
+ SANE_Int highresolution; /*f144 */
+ double dbValues[3] = { 0, 0, 0 }; /*f148 f14c f150 */
+ SANE_Int do_loop; /*f0ec */
+ SANE_Int gainmode;
+ SANE_Byte *ptr; /*f0f4 */
+ SANE_Byte *mvgag; /*f0e4 *//*f10c */
+ USHORT wvalues[9]; /*0856 0858 085a 085c 085e 0860 0862 0864 0866 */
+ SANE_Int imgcount = 0;
+ /* myoffsetnpixel = f120 */
+ /* desp f0e8 & f140 */
+
+ DBG (DBG_FNC, "+ Calib_AdcOffsetRT(*calibcfg, value=%i)\n", value);
+
+ memcpy (&Regs, &calibdata->Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (&scancfg, &calibdata->scancfg, sizeof (struct st_scanparams));
+
+ channels_per_dot = (calibdata->scancfg.colormode == CM_COLOR) ? 3 : 1;
+
+ if (value != 0)
+ {
+ pedcg = &calibdata->gain_offset.edcg1[CL_RED];
+ podcg = &calibdata->gain_offset.odcg1[CL_RED];
+ poffseteven = &calibcfg->OffsetEven1[CL_RED];
+ poffsetodd = &calibcfg->OffsetOdd1[CL_RED];
+ }
+ else
+ {
+ /*c37c */
+ pedcg = &calibdata->gain_offset.edcg2[CL_RED];
+ podcg = &calibdata->gain_offset.odcg2[CL_RED];
+ poffseteven = &calibcfg->OffsetEven2[CL_RED];
+ poffsetodd = &calibcfg->OffsetOdd2[CL_RED];
+ }
+
+ /*c3a4 */
+ scancfg.coord.left = calibcfg->OffsetPixelStart;
+
+ if (channels_per_dot > 0)
+ {
+ for (channel = 0; channel < channels_per_dot; channel++)
+ {
+ avgtarget[channel] = calibcfg->OffsetAvgTarget[channel] << 8;
+ if (avgtarget[channel] == 0)
+ avgtarget[channel] = 0x80;
+ }
+ }
+
+ /* set image coordinates to scan */
+ scancfg.coord.width = calibcfg->OffsetNPixel;
+ if ((scancfg.coord.width & 1) == 0)
+ scancfg.coord.width++;
+
+ scancfg.bytesperline = channels_per_dot * scancfg.coord.width;
+ scancfg.coord.top = 1;
+ scancfg.coord.height = calibcfg->OffsetHeight;
+ scancfg.depth = 8;
+
+ /* allocate memory to store image */
+ scanbuffer =
+ (SANE_Byte *) malloc ((scancfg.bytesperline * calibcfg->OffsetHeight) *
+ sizeof (SANE_Byte));
+ if (scanbuffer == NULL)
+ return ERROR;
+
+ /*42ac477 */
+ scan_options = (linedarlampoff == 1) ? 1 : 0x101;
+ highresolution = (scancfg.sensorresolution >= 1200) ? TRUE : FALSE;
+
+ do
+ {
+ if (channels_per_dot > 0)
+ {
+ for (channel = 0; channel < channels_per_dot; channel++)
+ dbValues[channel] =
+ (40 / (44 - calibdata->gain_offset.vgag2[channel])) * (40 /
+ (44 -
+ calibdata->
+ gain_offset.
+ vgag1
+ [channel]));
+ }
+
+ /*429c50f */
+ /* Get Image */
+ gainmode = Lamp_GetGainMode (dev, scancfg.resolution_x, scan.scantype);
+ if (RTS_GetImage
+ (dev, Regs, &scancfg, &calibdata->gain_offset, scanbuffer, 0,
+ scan_options, gainmode) != OK)
+ {
+ free (scanbuffer);
+ return ERROR;
+ }
+
+ /*429c55f */
+ /* Save retrieved image */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ char fname[30];
+
+ imgcount++;
+ if (snprintf (fname, 30, "adcoffset_rt%i.tiff", imgcount) > 0)
+ dbg_tiff_save (fname,
+ scancfg.coord.width,
+ scancfg.coord.height,
+ scancfg.depth,
+ CM_COLOR,
+ scancfg.resolution_x,
+ scancfg.resolution_y,
+ scanbuffer,
+ scancfg.bytesperline * calibcfg->OffsetHeight);
+ }
+
+ /*429c5a5 */
+ do_loop = FALSE;
+
+ if (highresolution == TRUE)
+ {
+ /* f0fc = f0e4 = channel */
+ SANE_Int lf104;
+ SANE_Int *mydcg; /*f0f4 */
+ USHORT *mywvalue; /*ebp */
+
+ SANE_Byte is_ready[6]; /*f174 f178 f17c f180 f184 f18c */
+ SANE_Byte *ptr_ready; /*f11c */
+ SANE_Int colour;
+
+ for (channel = 0; channel < 6; channel++)
+ is_ready[channel] = FALSE;
+
+ if (channels_per_dot <= 0)
+ break;
+
+ ptr = scanbuffer;
+ mvgag = (SANE_Byte *) calibdata->gain_offset.vgag1;
+
+ for (channel = 0; channel < channels_per_dot; channel++)
+ {
+ for (lf104 = 0; lf104 < 2; lf104++)
+ {
+ if (lf104 == 0)
+ {
+ mywvalue = &wvalues[channel];
+ mydcg = pedcg;
+ ptr_ready = &is_ready[0];
+ }
+ else
+ {
+ /*1645 */
+ mywvalue = &wvalues[3];
+ mydcg = podcg;
+ ptr_ready = &is_ready[3];
+ }
+
+ /*1658 */
+ if (ptr_ready[channel] == FALSE)
+ {
+ colour = 0;
+ if (lf104 < calibcfg->OffsetNPixel)
+ {
+ SANE_Int dot;
+
+ for (dot = 0;
+ dot < (calibcfg->OffsetNPixel - lf104 + 1) / 2;
+ dot++)
+ colour +=
+ scanbuffer[mvgag[(lf104 * channels_per_dot)] +
+ (dot * (channels_per_dot * 2))];
+ }
+
+ /*c6b2 */
+ colour = colour << 8;
+ if (colour == 0)
+ {
+ /*c6b9 */
+ if (mydcg[channel] != 0x1ff)
+ {
+ /*c6d5 */
+ mydcg[channel] = 0x1ff;
+ do_loop = TRUE;
+ }
+ else
+ ptr_ready[channel] = TRUE;
+ }
+ else
+ {
+ SANE_Int myesi;
+ SANE_Int d;
+
+ /*c6e8 */
+ if (*mywvalue == 0)
+ mywvalue += 2;
+
+ colour /= (calibcfg->OffsetNPixel / 2);
+ if (colour >= avgtarget[channel])
+ {
+ colour -= avgtarget[channel];
+ myesi = 0;
+ }
+ else
+ {
+ colour = avgtarget[channel] - colour;
+ myesi = 1;
+ }
+
+ d = mydcg[channel];
+ if (d < 0x100)
+ d = 0xff - d;
+
+ if (myesi != 0)
+ {
+ /*c76e */
+ if ((d + colour) > 0x1ff)
+ {
+ if (*mvgag > 0)
+ {
+ *mvgag = *mvgag - 1;
+ do_loop = TRUE;
+ }
+ else
+ ptr_ready[channel] = TRUE; /*c7a0 */
+ }
+ else
+ d += colour;
+ }
+ else
+ {
+ /*c7ad */
+ if (colour > d)
+ {
+ if (*mvgag > 0)
+ {
+ *mvgag = *mvgag - 1;
+ do_loop = TRUE;
+ }
+ else
+ ptr_ready[channel] = TRUE;
+ }
+ else
+ d -= colour;
+ }
+
+ /*c7dd */
+ mydcg[channel] = (d < 0x100) ? 0x100 - d : d;
+ }
+
+ dbg_calibtable (&calibdata->gain_offset);
+ }
+ }
+
+ /*c804 */
+ mvgag++;
+ }
+ }
+ else
+ {
+ /* Low resolution */
+
+ SANE_Byte is_ready[3];
+ SANE_Int colour;
+
+ /*429c845 */
+ for (channel = 0; channel < channels_per_dot; channel++)
+ is_ready[channel] = FALSE;
+
+ if (channels_per_dot <= 0)
+ break;
+
+ ptr = scanbuffer;
+ mvgag = (SANE_Byte *) calibdata->gain_offset.vgag1;
+
+ for (channel = 0; channel < channels_per_dot; channel++)
+ {
+ if (is_ready[channel] == FALSE)
+ {
+ colour = 0;
+ if (calibcfg->OffsetNPixel > 0)
+ {
+ SANE_Int dot;
+
+ /* Take one channel colour values from offsetnpixel pixels */
+ for (dot = 0; dot < calibcfg->OffsetNPixel; dot++)
+ colour += *(ptr + (dot * channels_per_dot));
+ }
+
+ colour <<= 8;
+ if (colour == 0)
+ {
+ if (pedcg[channel] != 0x1ff)
+ {
+ do_loop = TRUE;
+ podcg[channel] = 0x1ff;
+ pedcg[channel] = 0x1ff;
+ }
+ else
+ is_ready[channel] = TRUE;
+ }
+ else
+ {
+ /*c8f7 */
+ SANE_Int myesi;
+ SANE_Int op1, op2, op3;
+
+ /* Get colour average */
+ colour /= calibcfg->OffsetNPixel;
+
+ /* get absolute difference with avgtarget */
+ myesi = (colour > avgtarget[channel]) ? 0 : 1;
+ colour = abs (avgtarget[channel] - colour);
+
+ if (scancfg.resolution_x > 600)
+ {
+ /*c923 */
+ if (wvalues[channel + 3] == 0)
+ wvalues[channel + 3]++;
+
+ if (wvalues[channel] == 0)
+ wvalues[channel]++;
+
+ op3 = max (wvalues[channel], wvalues[channel + 3]);
+ }
+ else
+ {
+ if (wvalues[channel + 6] == 0)
+ wvalues[channel + 6]++;
+
+ op3 = wvalues[channel + 6];
+ }
+
+ /*c9d3 */
+ op1 = (SANE_Int) (colour / (dbValues[channel] * op3));
+ op2 =
+ (pedcg[channel] <
+ 0x100) ? pedcg[channel] - 0xff : pedcg[channel];
+
+ if (myesi != 0)
+ {
+ /*c9f5 */
+ if (((op2 + op1) & 0xffff) > 0x1ff)
+ {
+ if (*mvgag != 0)
+ {
+ do_loop = TRUE;
+ *mvgag = *mvgag - 1;
+ }
+ else
+ is_ready[channel] = TRUE;
+ }
+ else
+ op2 += op1;
+ }
+ else
+ {
+ /*ca31 */
+ if (op1 > op2)
+ {
+ if (*mvgag > 0)
+ {
+ do_loop = TRUE;
+ *mvgag = *mvgag - 1;
+ }
+ else
+ is_ready[channel] = TRUE;
+ }
+ else
+ op2 -= op1;
+ }
+
+ /*ca54 */
+ if (op2 < 0x100)
+ op2 = 0x100 - op2;
+
+ pedcg[channel] = op2;
+ podcg[channel] = op2;
+ }
+ }
+ /*ca6f */
+ ptr++;
+ mvgag++;
+ dbg_calibtable (&calibdata->gain_offset);
+ }
+ }
+ }
+ while (do_loop != FALSE);
+
+ /*429cad1 */
+ for (channel = 0; channel < 3; channel++)
+ {
+ poffseteven[channel] =
+ (pedcg[channel] < 0x100) ? 0xff - pedcg[channel] : pedcg[channel];
+ poffsetodd[channel] =
+ (podcg[channel] < 0x100) ? 0xff - podcg[channel] : podcg[channel];
+ }
+
+ free (scanbuffer);
+
+ return OK;
+}
+
+static void
+Calib_LoadCut (struct st_device *dev, struct st_scanparams *scancfg,
+ SANE_Int scantype, struct st_calibration_config *calibcfg)
+{
+ double mylong; /*ee78 */
+ double mylong2;
+ /**/ SANE_Int channel[3];
+ SANE_Int a;
+
+ cfg_shading_cut_get (dev->sensorcfg->type, scancfg->depth,
+ scancfg->resolution_x, scantype, &channel[0],
+ &channel[1], &channel[2]);
+
+ mylong = 1 << scancfg->depth;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ mylong2 = channel[a];
+ calibcfg->ShadingCut[a] = (mylong * mylong2) * 0.000390625;
+ }
+}
+
+static SANE_Int
+Calib_BWShading (struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib, SANE_Int gainmode)
+{
+ /*
+ 0603F8E4 0603F90C |Arg1 = 0603F90C calibcfg
+ 0603F8E8 0603FAAC |Arg2 = 0603FAAC myCalib
+ 0603F8EC 00000001 \Arg3 = 00000001 gainmode
+ */
+
+ /*falta codigo */
+
+ /*silence gcc */
+ calibcfg = calibcfg;
+ myCalib = myCalib;
+ gainmode = gainmode;
+
+ return OK;
+}
+
+static SANE_Int
+Calib_WhiteShading_3 (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib, SANE_Int gainmode)
+{
+/*
+05EDF8E0 04F00738 |Arg1 = 04F00738
+05EDF8E4 05EDF90C |Arg2 = 05EDF90C calibcfg
+05EDF8E8 05EDFAAC |Arg3 = 05EDFAAC myCalib
+05EDF8EC 00000001 \Arg4 = 00000001 gainmode
+*/
+ SANE_Byte *myRegs; /*f1bc */
+ struct st_scanparams scancfg; /*f170 */
+ SANE_Int myWidth; /*f14c */
+ SANE_Int lf168, bytes_per_pixel;
+ SANE_Int bytes_per_line;
+ /**/ SANE_Int a;
+ double lf1a4[3];
+ SANE_Int otherheight; /*f150 */
+ SANE_Int otherheight2;
+ SANE_Int lf12c;
+ SANE_Int lf130;
+ double *buffer1; /*f138 */
+ double *buffer2; /*f144 */
+ SANE_Byte *scanbuffer; /*f164 */
+ SANE_Byte *ptr; /*f148 */
+ SANE_Int position; /*f140 */
+ SANE_Int lf13c, myHeight;
+ SANE_Int myESI, myEDI;
+ SANE_Int channel; /*f134 */
+ double myst;
+ double sumatorio;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "> Calib_WhiteShading3(*calibcfg, *myCalib, gainmode=%i)\n",
+ gainmode);
+
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, &calibdata->Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (&scancfg, &calibdata->scancfg, sizeof (struct st_scanparams));
+
+ Lamp_SetGainMode (dev, myRegs, scancfg.resolution_x, gainmode);
+
+ rst = OK;
+ scancfg.resolution_y = 200;
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ /*a184 */
+ scancfg.coord.left += scan.ser;
+ scancfg.coord.width &= 0xffff;
+ break;
+ case ST_TA:
+ case ST_NEG:
+ scancfg.coord.left += scan.ser;
+ break;
+ }
+
+ /*a11b */
+ if ((scancfg.coord.width & 1) != 0)
+ scancfg.coord.width++;
+
+ scancfg.coord.top = 1;
+ scancfg.coord.height = calibcfg->WShadingHeight;
+
+ switch (scancfg.colormode)
+ {
+ case CM_GRAY:
+ case CM_LINEART:
+ myWidth = scancfg.coord.width;
+ lf168 = 0;
+ bytes_per_line = ((scancfg.depth + 7) / 8) * myWidth;
+ bytes_per_pixel = 1;
+ break;
+ default: /* CM_COLOR */
+ myWidth = scancfg.coord.width * 3;
+ bytes_per_line = ((scancfg.depth + 7) / 8) * myWidth;
+ lf168 = (scancfg.samplerate == LINE_RATE) ? scancfg.coord.width : 1;
+ bytes_per_pixel = (scancfg.samplerate == PIXEL_RATE) ? 3 : 1;
+ break;
+ }
+
+ /*a1e8 */
+ scancfg.v157c = bytes_per_line;
+ scancfg.bytesperline = bytes_per_line;
+
+ for (a = 0; a < 3; a++)
+ lf1a4[a] = (calibcfg->WRef[a] * (1 << scancfg.depth)) >> 8;
+
+ /* debug this code because if it's correct, lf130 and lf12c are always 2 */
+ otherheight = calibcfg->WShadingHeight - 3;
+ otherheight -= (otherheight - 4);
+ otherheight2 = otherheight / 2;
+ otherheight -= otherheight2;
+ lf130 = otherheight2;
+ lf12c = otherheight;
+
+ buffer1 = (double *) malloc (otherheight * sizeof (double));
+ if (buffer1 == NULL)
+ return ERROR;
+
+ buffer2 = (double *) malloc (otherheight * sizeof (double));
+ if (buffer2 == NULL)
+ {
+ free (buffer1);
+ return ERROR;
+ }
+
+ scanbuffer =
+ (SANE_Byte *) malloc (((scancfg.coord.height + 16) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (scanbuffer == NULL)
+ {
+ free (buffer1);
+ free (buffer2);
+ return ERROR;
+ }
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ rst =
+ RTS_GetImage (dev, myRegs, &scancfg, &calibdata->gain_offset, scanbuffer,
+ myCalib, 0x20000080, gainmode);
+
+ for (a = 0; a < 3; a++)
+ myCalib->WRef[a] *= ((1 << scancfg.depth) >> 8);
+
+ if (rst == ERROR)
+ {
+ free (buffer1);
+ free (buffer2);
+ free (scanbuffer);
+ return ERROR;
+ }
+
+ if (scancfg.depth > 8)
+ {
+ /*a6d9 */
+ position = 0;
+ sumatorio = 0;
+ if (myWidth > 0)
+ {
+ do
+ {
+ switch (scancfg.colormode)
+ {
+ case CM_GRAY:
+ case CM_LINEART:
+ channel = 0;
+ lf13c = position;
+ break;
+ default: /*CM_COLOR */
+ if (scancfg.samplerate == PIXEL_RATE)
+ {
+ /* pixel rate */
+ channel = position % bytes_per_pixel;
+ lf13c = position / bytes_per_pixel;
+ }
+ else
+ {
+ /* line rate */
+ channel = position / lf168;
+ lf13c = position % lf168;
+ }
+ break;
+ }
+
+ /*a743 */
+ if (lf130 > 0)
+ bzero (buffer1, lf130 * sizeof (double));
+
+ /*a761 */
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ buffer2[a] = (1 << scancfg.depth) - 1.0;
+ }
+
+ /*a78f */
+ myESI = 0;
+ myEDI = 0;
+ ptr = scanbuffer + (position * 2);
+ myHeight = 0;
+
+ if (otherheight > 0)
+ {
+ do
+ {
+ myst = 0;
+ for (a = 0; a < 4; a++)
+ myst += data_lsb_get (ptr + (a * (myWidth * 2)), 2);
+
+ myEDI = 0;
+ myst = myst * 0.25;
+ if (myHeight < (otherheight - 4))
+ {
+ if (myst < buffer2[myESI])
+ {
+ buffer2[myESI] = myst;
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] < buffer2[a])
+ myESI = a;
+ }
+ }
+
+ /*a820 */
+ if (myst >= buffer1[myEDI])
+ {
+ buffer1[myEDI] = myst;
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] >= buffer1[a])
+ myEDI = a;
+ }
+ }
+ sumatorio += myst;
+ }
+ else
+ {
+ /*a853 */
+ if (myHeight == (otherheight - 4))
+ {
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] >= buffer2[a])
+ myESI = a;
+ }
+
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] < buffer1[a])
+ myEDI = a;
+ }
+ }
+
+ /*a895 */
+ if (myst >= buffer2[myESI])
+ {
+ /*a89c */
+ sumatorio -= buffer2[myESI];
+ sumatorio += myst;
+ buffer2[myESI] = myst;
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] >= buffer2[a])
+ myESI = a;
+ }
+ }
+ else
+ {
+ if (myst < buffer1[myEDI])
+ {
+ sumatorio -= buffer1[myEDI];
+ sumatorio += myst;
+ buffer1[myEDI] = myst;
+
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] < buffer1[a])
+ myEDI = a;
+ }
+ }
+ }
+ }
+
+ /*a901 */
+ ptr += (myWidth * 2);
+ myHeight++;
+ }
+ while (myHeight < otherheight);
+ }
+
+ /*a924 */
+ scancfg.ser = 0;
+ scancfg.startpos = otherheight - 4;
+
+ sumatorio = sumatorio / scancfg.startpos;
+ if (myCalib->shading_enabled != FALSE)
+ {
+ /*a94a */
+ myCalib->white_shading[channel][lf13c] =
+ (unsigned short) sumatorio;
+ }
+ else
+ {
+ /*a967 */
+ if ((scancfg.colormode != CM_GRAY)
+ && (scancfg.colormode != CM_LINEART))
+ sumatorio /= lf1a4[channel];
+ else
+ sumatorio /= lf1a4[scancfg.channel];
+
+ sumatorio = min (sumatorio * 0x4000, 65535);
+
+ if (myRegs[0x1bf] != 0x18)
+ myCalib->black_shading[channel][lf13c] |=
+ (0x140 -
+ ((((myRegs[0x1bf] >> 3) & 3) *
+ 3) << 6)) & ((int) sumatorio);
+ else
+ myCalib->white_shading[channel][lf13c] =
+ (unsigned short) sumatorio;
+ }
+
+ /*a9fd */
+ position++;
+ }
+ while (position < myWidth);
+ }
+ }
+ else
+ {
+ /*a6d9 */
+ position = 0;
+ sumatorio = 0;
+ if (myWidth > 0)
+ {
+ do
+ {
+ switch (scancfg.colormode)
+ {
+ case CM_GRAY:
+ case CM_LINEART:
+ channel = 0;
+ lf13c = position;
+ break;
+ default: /*CM_COLOR */
+ if (scancfg.samplerate == PIXEL_RATE)
+ {
+ channel = position % bytes_per_pixel;
+ lf13c = position / bytes_per_pixel;
+ }
+ else
+ {
+ channel = position / lf168;
+ lf13c = position % lf168;
+ }
+ break;
+ }
+
+ /*a743 */
+ if (lf130 > 0)
+ bzero (buffer1, lf130 * sizeof (double));
+
+ /*a761 */
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ buffer2[a] = (1 << scancfg.depth) - 1.0;
+ }
+
+ /*a78f */
+ myESI = 0;
+ myEDI = 0;
+ ptr = scanbuffer + position;
+ myHeight = 0;
+
+ if (otherheight > 0)
+ {
+ do
+ {
+ myst = 0;
+ for (a = 0; a < 4; a++)
+ myst += *(ptr + (a * myWidth));
+
+ myEDI = 0;
+ myst *= 0.25;
+ if (myHeight < (otherheight - 4))
+ {
+ if (myst < buffer2[myESI])
+ {
+ buffer2[myESI] = myst;
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] < buffer2[a])
+ myESI = a;
+ }
+ }
+ /*a820 */
+ if (myst >= buffer1[myEDI])
+ {
+ buffer1[myEDI] = myst;
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] >= buffer1[a])
+ myEDI = a;
+ }
+ }
+ sumatorio += myst;
+ }
+ else
+ {
+ /*a853 */
+ if (myHeight == (otherheight - 4))
+ {
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] >= buffer2[a])
+ myESI = a;
+ }
+
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] < buffer1[a])
+ myEDI = a;
+ }
+ }
+
+ /*a895 */
+ if (myst >= buffer2[myESI])
+ {
+ /*a89c */
+ sumatorio -= buffer2[myESI];
+ sumatorio += myst;
+ buffer2[myESI] = myst;
+ if (lf12c > 0)
+ {
+ for (a = 0; a < lf12c; a++)
+ if (buffer2[myESI] >= buffer2[a])
+ myESI = a;
+ }
+ }
+ else
+ {
+ if (myst < buffer1[myEDI])
+ {
+ sumatorio -= buffer1[myEDI];
+ sumatorio += myst;
+ buffer1[myEDI] = myst;
+
+ if (lf130 > 0)
+ {
+ for (a = 0; a < lf130; a++)
+ if (buffer1[myEDI] < buffer1[a])
+ myEDI = a;
+ }
+ }
+ }
+ }
+ /*a901 */
+ ptr += myWidth;
+ myHeight++;
+ }
+ while (myHeight < otherheight);
+ }
+ /*a924 */
+ scancfg.ser = 0;
+ scancfg.startpos = otherheight - 4;
+
+ sumatorio /= scancfg.startpos;
+ if (myCalib->shading_enabled != FALSE)
+ {
+ /*a94a */
+ myCalib->white_shading[channel][lf13c] =
+ (unsigned short) sumatorio;
+ }
+ else
+ {
+ /*a967 */
+ if ((scancfg.colormode != CM_GRAY)
+ && (scancfg.colormode != CM_LINEART))
+ sumatorio /= lf1a4[channel];
+ else
+ sumatorio /= lf1a4[scancfg.channel];
+
+ sumatorio = min (sumatorio * 0x4000, 65535);
+
+ if (myRegs[0x1bf] != 0x18)
+ myCalib->black_shading[channel][lf13c] |=
+ (0x140 -
+ ((((myRegs[0x1bf] >> 3) & 0x03) *
+ 3) << 6)) & ((int) sumatorio);
+ else
+ myCalib->white_shading[channel][lf13c] =
+ (unsigned short) sumatorio;
+ }
+ /*a9fd */
+ position++;
+ }
+ while (position < myWidth);
+ }
+ }
+
+ /*aa12 */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ dbg_tiff_save ("whiteshading3.tiff",
+ scancfg.coord.width,
+ scancfg.coord.height,
+ scancfg.depth,
+ CM_COLOR,
+ scancfg.resolution_x,
+ scancfg.resolution_y,
+ scanbuffer,
+ (scancfg.coord.height + 16) * bytes_per_line);
+ }
+
+ free (buffer1);
+ free (buffer2);
+ free (scanbuffer);
+
+ return OK;
+}
+
+static SANE_Int
+Calib_BlackShading (struct st_device *dev,
+ struct st_calibration_config *calibcfg,
+ struct st_calibration *myCalib, SANE_Int gainmode)
+{
+ /*
+ gainmode f8ec
+ myCalib f8e8
+ calibcfg f8e4
+ */
+ SANE_Byte *myRegs; /*f1bc */
+ struct st_scanparams scancfg; /*f020 */
+ double shadingprediff[6]; /*f08c f094 f09c f0a4 f0ac f0b4 */
+ double mylong; /*f018 */
+ double maxvalue; /*eff8 */
+ double sumatorio = 0.0;
+ double myst;
+ SANE_Int rst;
+ SANE_Int a;
+ SANE_Int mheight; /*efe0 */
+ SANE_Int current_line; /*efe4 */
+ SANE_Int bytes_per_line; /*efd8 */
+ SANE_Int position; /*lefcc */
+ SANE_Int leff0, lf010, lefd0;
+ SANE_Byte *buffer; /*efd4 */
+ SANE_Byte buff2[256]; /*F0BC */
+ SANE_Int buff3[0x8000];
+ SANE_Byte *ptr; /*f008 */
+ SANE_Int my14b4; /*f008 pisa ptr */
+ SANE_Int biggest; /*bx */
+ SANE_Int lowest; /*dx */
+ SANE_Int lefdc;
+ SANE_Int channel;
+ SANE_Int smvalues[3]; /*f04c f04e f050 */
+ double dbvalue[6]; /*lf05c lf060, lf064 lf068, lf06c lf070,
+ lf074 lf078, lf07c lf080, lf084 lf088 */
+
+ DBG (DBG_FNC, "> Calib_BlackShading(*calibcfg, *myCalib, gainmode=%i)\n",
+ gainmode);
+
+ rst = OK;
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, &calibdata->Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (&scancfg, &calibdata->scancfg, sizeof (struct st_scanparams));
+
+ Lamp_SetGainMode (dev, myRegs, scancfg.resolution_x, gainmode);
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ shadingprediff[a + 3] = calibcfg->BShadingPreDiff[a];
+
+ if ((scan.scantype >= ST_NORMAL) && (scan.scantype <= ST_NEG))
+ scancfg.coord.left += scan.ser;
+
+ if ((scancfg.coord.width & 1) != 0)
+ scancfg.coord.width++;
+
+ scancfg.coord.top = 1;
+ scancfg.depth = 8;
+ scancfg.coord.height = calibcfg->BShadingHeight;
+
+ if (scancfg.colormode != CM_COLOR)
+ {
+ bytes_per_line = scancfg.coord.width;
+ leff0 = 0;
+ lf010 = 1;
+ }
+ else
+ {
+ /*876c */
+ bytes_per_line = scancfg.coord.width * 3;
+ if (scancfg.samplerate == LINE_RATE)
+ {
+ leff0 = scancfg.coord.width;
+ lf010 = 1;
+ }
+ else
+ {
+ leff0 = 1;
+ lf010 = 3;
+ }
+ }
+
+ scancfg.v157c = bytes_per_line;
+ scancfg.bytesperline = bytes_per_line;
+
+ mylong = 1 << (16 - scancfg.depth);
+ if ((myRegs[0x1bf] & 0x18) != 0)
+ mylong /= 1 << (((myRegs[0x1bf] >> 5) & 3) + 4);
+
+ lefd0 =
+ ((((myRegs[0x1bf] >> 3) & 2) << 8) -
+ ((((myRegs[0x1bf] >> 3) & 1) * 3) << 6)) - 1;
+
+ if (scancfg.depth >= 8)
+ maxvalue = ((1 << (scancfg.depth - 8)) << 8) - 1;
+ else
+ maxvalue = (256 / (1 << (8 - scancfg.depth))) - 1;
+
+ Calib_LoadCut (dev, &scancfg, scan.scantype, calibcfg);
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ shadingprediff[a] = calibcfg->ShadingCut[a];
+
+ if (calibcfg->BShadingOn == -1)
+ {
+ SANE_Int b, d;
+ double e;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ myst = max (shadingprediff[a], 0);
+ myst = (maxvalue >= myst) ? shadingprediff[a] : maxvalue;
+ shadingprediff[a] = max (myst, 0);
+ }
+
+ b = 0;
+
+ while (b < bytes_per_line)
+ {
+ if (scancfg.colormode != CM_COLOR)
+ {
+ channel = 0;
+ d = b;
+ }
+ else
+ {
+ if (scancfg.samplerate == PIXEL_RATE)
+ {
+ channel = (b % lf010) & 0xffff;
+ d = (b / lf010) & 0xffff;
+ }
+ else
+ {
+ channel = (b / leff0) & 0xffff;
+ d = (b % leff0) & 0xffff;
+ }
+ }
+ /*89d0 */
+ e = min (lefd0, mylong * shadingprediff[channel]);
+ myCalib->black_shading[channel][d] |= (unsigned short) e & 0xffff;
+ b++;
+ }
+
+ return OK;
+ }
+
+ /* Allocate buffer to read image */
+ mheight = scancfg.coord.height;
+ buffer =
+ (SANE_Byte *) malloc (((scancfg.coord.height + 16) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (buffer == NULL)
+ return ERROR;
+
+ /* Turn off lamp */
+ Lamp_Status_Set (dev, NULL, FALSE, FLB_LAMP);
+ usleep (200 * 1000);
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ rst =
+ RTS_GetImage (dev, myRegs, &scancfg, &calibdata->gain_offset, buffer,
+ myCalib, 0x101, gainmode);
+ if (rst == ERROR)
+ {
+ /*8ac2 */
+ free (buffer);
+ memcpy (&calibdata->Regs, myRegs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+ free (myRegs);
+ return ERROR;
+ }
+
+ /* myRegs isn't going to be used anymore */
+ free (myRegs);
+ myRegs = NULL;
+
+ /* Turn on lamp again */
+ if (scan.scantype != ST_NORMAL)
+ {
+ Lamp_Status_Set (dev, NULL, FALSE, TMA_LAMP);
+ usleep (1000 * 1000);
+ }
+ else
+ Lamp_Status_Set (dev, NULL, TRUE, FLB_LAMP);
+
+ /* Save buffer */
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ dbg_tiff_save ("blackshading.tiff",
+ scancfg.coord.width,
+ scancfg.coord.height,
+ scancfg.depth,
+ CM_COLOR,
+ scancfg.resolution_x,
+ scancfg.resolution_y,
+ buffer, (scancfg.coord.height + 16) * bytes_per_line);
+ }
+
+ if (scancfg.depth > 8)
+ {
+ /*8bb2 */
+ bzero (&dbvalue, 6 * sizeof (double));
+ position = 0;
+
+ if (bytes_per_line > 0)
+ {
+ do
+ {
+ bzero (&buff3, 0x8000 * sizeof (SANE_Int));
+ sumatorio = 0;
+ ptr = buffer + position;
+ current_line = 0;
+ biggest = 0;
+ lowest = (int) maxvalue;
+ /* Toma los valores de una columna */
+ if (mheight > 0)
+ {
+ SANE_Int value;
+ do
+ {
+ value = data_lsb_get (ptr, 2);
+ biggest = max (biggest, value);
+ if (current_line < mheight)
+ {
+ sumatorio += value;
+ lowest = min (lowest, value);
+ biggest = max (biggest, value);
+
+ buff3[value]++;
+ }
+ else
+ {
+ /*8cab */
+ if (value > lowest)
+ {
+ buff3[lowest]--;
+ buff3[value]++;
+ sumatorio += value;
+ sumatorio -= lowest;
+
+ if (buff3[lowest] != 0)
+ {
+ do
+ {
+ lowest++;
+ }
+ while (buff3[lowest] == 0);
+ }
+ }
+ }
+ /*8d0b */
+ ptr += (bytes_per_line * 2);
+ current_line++;
+ }
+ while (current_line < mheight);
+ }
+ /*8d27 */
+ sumatorio /= mheight;
+
+ if (scancfg.colormode != CM_COLOR)
+ {
+ channel = 0;
+ lefdc = position;
+ }
+ else
+ {
+ /*8d5f */
+ if (scancfg.samplerate == PIXEL_RATE)
+ {
+ channel = position % lf010;
+ lefdc = (position / lf010) & 0xffff;
+ }
+ else
+ {
+ channel = position / leff0;
+ lefdc = position % leff0;
+ }
+ }
+
+ dbvalue[channel] += sumatorio;
+ if ((scancfg.colormode == CM_GRAY)
+ || (scancfg.colormode == CM_LINEART))
+ sumatorio += shadingprediff[scancfg.channel];
+ else
+ sumatorio += shadingprediff[channel];
+
+ myst = min (max (0, sumatorio), maxvalue);
+
+ dbvalue[channel + 3] = myst;
+
+ if ((calibcfg->BShadingOn == 1) || (calibcfg->BShadingOn == 2))
+ {
+ if (calibcfg->BShadingOn == 2)
+ {
+ myst -=
+ calibcfg->BRef[channel] * (1 << (scancfg.depth - 8));
+ myst = max (myst, 0);
+ }
+ /*8e6d */
+ myst *= mylong;
+ myCalib->black_shading[channel][lefdc] = min (myst, lefd0);
+ }
+
+ position++;
+ }
+ while (position < bytes_per_line);
+ }
+ }
+ else
+ {
+ /*8eb6 */
+ bzero (&dbvalue, 6 * sizeof (double));
+ position = 0;
+
+ if (bytes_per_line > 0)
+ {
+ do
+ {
+ bzero (&buff2, 256 * sizeof (SANE_Byte));
+ sumatorio = 0;
+ /* ptr points to the next position of the first line */
+ ptr = buffer + position;
+ biggest = 0;
+ lowest = (int) maxvalue;
+ current_line = 0;
+ /* Toma los valores de una columna */
+ if (mheight > 0)
+ {
+ my14b4 = v14b4;
+ do
+ {
+ biggest = max (biggest, *ptr);
+
+ if (my14b4 == 0)
+ {
+ /*8fd7 */
+ if (current_line < mheight)
+ {
+ sumatorio += *ptr;
+
+ lowest = min (lowest, *ptr);
+ biggest = max (biggest, *ptr);
+
+ buff2[*ptr]++;
+ }
+ else
+ {
+ /*9011 */
+ if (*ptr > lowest)
+ {
+ buff2[lowest]--;
+ buff2[*ptr]++;
+ sumatorio += *ptr;
+ sumatorio -= lowest;
+
+ if (buff2[lowest] != 0)
+ {
+ do
+ {
+ lowest++;
+ }
+ while (buff2[lowest] == 0);
+ }
+ }
+ }
+ }
+ else
+ sumatorio += *ptr;
+ /*9067 */
+ /* Point to the next pixel under current line */
+ ptr += bytes_per_line;
+ current_line++;
+ }
+ while (current_line < mheight);
+ }
+
+ /*908a */
+ /* Calculates average of each column */
+ sumatorio = sumatorio / mheight;
+
+ if (scancfg.colormode != CM_COLOR)
+ {
+ channel = 0;
+ lefdc = position;
+ }
+ else
+ {
+ /*90c5 */
+ if (scancfg.samplerate == PIXEL_RATE)
+ {
+ channel = position % lf010;
+ lefdc = (position / lf010) & 0xffff;
+ }
+ else
+ {
+ /*90fb */
+ channel = position / leff0;
+ lefdc = position % leff0;
+ }
+ }
+
+ /*911f */
+ dbvalue[channel] += sumatorio;
+ if ((scancfg.colormode == CM_GRAY)
+ || (scancfg.colormode == CM_LINEART))
+ sumatorio += shadingprediff[scancfg.channel];
+ else
+ sumatorio += shadingprediff[channel];
+
+ /*9151 */
+ myst = min (max (0, sumatorio), maxvalue);
+
+ /*9198 */
+ if (position >= 3)
+ {
+ double myst2;
+
+ myst -= dbvalue[channel + 3];
+ myst2 = myst;
+ myst = min (myst, shadingprediff[channel + 3]);
+
+ my14b4 = -shadingprediff[channel + 3];
+ if (myst >= my14b4)
+ myst = min (myst2, shadingprediff[channel + 3]);
+ else
+ myst = my14b4;
+
+ myst += dbvalue[channel + 3];
+ }
+
+ /*9203 */
+ dbvalue[channel + 3] = myst;
+
+ switch (calibcfg->BShadingOn)
+ {
+ case 1:
+ myCalib->black_shading[channel][lefdc] |=
+ (unsigned short) (((int) myst & 0xff) << 8) & 0xffff;
+ break;
+ case 2:
+ /*9268 */
+ my14b4 =
+ calibcfg->BRef[channel] / (1 << (8 - scancfg.depth));
+ myst -= my14b4;
+ myst = max (myst, 0);
+ myst *= mylong;
+ myCalib->black_shading[channel][lefdc] = min (myst, lefd0);
+ break;
+ }
+
+ /*92d8 */
+ position++;
+ }
+ while (position < bytes_per_line);
+ }
+ }
+
+ /*9306 */
+ if (calibcfg->BShadingOn == -2)
+ {
+ for (a = 0; a < 3; a++)
+ {
+ dbvalue[a] =
+ (dbvalue[a] / scancfg.coord.width) + calibcfg->ShadingCut[a];
+ if (dbvalue[a] < 0)
+ dbvalue[a] = 0;
+ smvalues[a] = min ((int) (dbvalue[a] + 0.5) & 0xffff, maxvalue);
+ }
+
+ if (scancfg.coord.width > 0)
+ {
+ SANE_Int b, c;
+
+ for (c = 0; c < scancfg.coord.width; c++)
+ for (b = 0; b < 3; b++)
+ myCalib->black_shading[b][c] |=
+ (unsigned short) min (smvalues[b] * mylong, lefd0);
+ }
+ }
+ /*9425 */
+ free (buffer);
+
+ return OK;
+}
+
+static SANE_Int
+Calibration (struct st_device *dev, SANE_Byte * Regs,
+ struct st_scanparams *scancfg, struct st_calibration *myCalib,
+ SANE_Int value)
+{
+ /*//SANE_Int Calibration([fa20]char *Regs, [fa24]struct st_scanparams *scancfg, [fa28]struct st_calibration myCalib, [fa2c]SANE_Int value)
+ */
+
+ struct st_calibration_config calibcfg; /* f90c */
+ SANE_Int a;
+ SANE_Byte gainmode;
+ SANE_Int lf900;
+
+ DBG (DBG_FNC, "> Calibration\n");
+ dbg_ScanParams (scancfg);
+
+ value = value; /*silence gcc */
+
+ memcpy (&calibdata->Regs, Regs, sizeof (SANE_Byte) * RT_BUFFER_LEN);
+
+ /*4213be8 */
+ memset (&calibcfg, 0x30, sizeof (struct st_calibration_config));
+ Calib_LoadConfig (dev, &calibcfg, scan.scantype, scancfg->resolution_x,
+ scancfg->depth);
+
+ bzero (&calibdata->gain_offset, sizeof (struct st_gain_offset)); /*[42b3654] */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ myCalib->WRef[a] = calibcfg.WRef[a];
+
+ calibdata->gain_offset.edcg1[a] = 256;
+ calibdata->gain_offset.odcg1[a] = 256;
+ calibdata->gain_offset.vgag1[a] = 4;
+ calibdata->gain_offset.vgag2[a] = 4;
+
+ /*3654|3656|3658
+ 365a|365c|365e
+ 3660|3662|3664
+ 3666|3668|366a
+ 366c|366d|366e
+ 366f|3670|3671
+ 3672|3673|3674 */
+ }
+
+ memcpy (&calibdata->scancfg, scancfg, sizeof (struct st_scanparams));
+ gainmode = Lamp_GetGainMode (dev, scancfg->resolution_x, scan.scantype); /* [lf904] = 1 */
+
+ /* 3cf3 */
+ myCalib->first_position = 1;
+ myCalib->shading_type = 0;
+ if (calibdata->scancfg.colormode == CM_LINEART)
+ {
+ calibdata->scancfg.colormode = CM_GRAY;
+ calibcfg.GainTargetFactor = 1.3;
+ }
+
+ lf900 = OK;
+ if (calibcfg.CalibPAGOn != 0)
+ {
+ if (Calib_PAGain (dev, &calibcfg, gainmode) != 0)
+ lf900 = ERROR;
+ /*ERROR*/}
+ else
+ {
+ /*3da7 */
+ if ((calibdata->scancfg.colormode != CM_GRAY)
+ && (calibdata->scancfg.colormode != CM_LINEART))
+ {
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ calibdata->gain_offset.pag[a] = calibcfg.PAG[a];
+ }
+ else
+ {
+ /* 3dd3 */
+ /* Default PAGain */
+ if (calibdata->scancfg.channel > 2)
+ calibdata->scancfg.channel = 0;
+
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ calibdata->gain_offset.pag[a] =
+ calibcfg.PAG[calibdata->scancfg.channel];
+ }
+ }
+
+ /* 3e01 */
+ if (calibcfg.CalibOffset10n != 0) /*==2*/
+ {
+ /*v14b4=1 offset[CL_RED]=0x174 offset[CL_GREEN]=0x16d offset[CL_BLUE]=0x160 */
+ if ((v14b4 != 0) && (offset[CL_RED] != 0) && (offset[CL_GREEN] != 0)
+ && (offset[CL_BLUE] != 0))
+ {
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ calibdata->gain_offset.edcg1[a] = offset[a];
+ calibdata->gain_offset.odcg1[a] = offset[a];
+ }
+ }
+ else
+ {
+ /* 3e84 */
+ if ((calibcfg.CalibOffset10n > 0) && (calibcfg.CalibOffset10n < 4))
+ {
+ /*if (calibcfg.CalibOffset10n != 0) */
+ if (calibcfg.CalibOffset10n == 3)
+ {
+ lf900 = Calib_AdcOffsetRT (dev, &calibcfg, 1);
+ }
+ else
+ {
+ /* 3eb2 */
+ /*falta codigo */
+ }
+ }
+ }
+ }
+ else
+ {
+ /* 3faf */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ calibdata->gain_offset.edcg1[a] =
+ abs (calibcfg.OffsetEven1[a] - 0x100);
+ calibdata->gain_offset.odcg1[a] =
+ abs (calibcfg.OffsetOdd1[a] - 0x100);
+ }
+ }
+
+ /* 3f13 3f0b */
+ if ((gainmode != 0) && (calibcfg.CalibGain10n != 0))
+ {
+ /*gain[CL_RED]=0x17 gain[CL_GREEN]=0x12 gain[CL_BLUE]=0x17 */
+ if ((v14b4 != 0) && (gain[CL_RED] != 0) && (gain[CL_GREEN] != 0)
+ && (gain[CL_BLUE] != 0))
+ {
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ calibdata->gain_offset.vgag1[a] = gain[a];
+ }
+ else
+ {
+ /*4025 */
+ lf900 = Calib_AdcGain (dev, &calibcfg, 1, gainmode);
+
+ if ((v14b4 != 0) && (lf900 == OK))
+ GainOffset_Save (dev, &calibdata->gain_offset.edcg1[0],
+ &calibdata->gain_offset.vgag1[0]);
+ }
+ }
+ else
+ {
+ /*4089 */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ calibdata->gain_offset.vgag1[a] = calibcfg.Gain1[a];
+ }
+
+ /*40a5 */
+ if ((gainmode != 0) && (calibcfg.CalibOffset20n != 0))
+ {
+ switch (calibcfg.CalibOffset20n)
+ {
+ case 3:
+ lf900 = Calib_AdcOffsetRT (dev, &calibcfg, 2);
+ break;
+ }
+ /*4140 */
+ /*falta codigo */
+ }
+ else
+ {
+ /*4162 */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ {
+ calibdata->gain_offset.edcg2[a] =
+ abs (calibcfg.OffsetEven2[a] - 0x40);
+ calibdata->gain_offset.odcg2[a] =
+ abs (calibcfg.OffsetOdd2[a] - 0x40);
+ }
+ }
+
+ /*41d6 */
+ if ((gainmode != 0) && (calibcfg.CalibGain20n != 0))
+ {
+ lf900 = Calib_AdcGain (dev, &calibcfg, 0, gainmode);
+ }
+ else
+ {
+ /*423c */
+ for (a = CL_RED; a <= CL_BLUE; a++)
+ calibdata->gain_offset.vgag2[a] = calibcfg.Gain2[a];
+ }
+
+ /*4258 */
+ if (calibcfg.TotShading != 0)
+ {
+ lf900 = Calib_BWShading (&calibcfg, myCalib, gainmode);
+ /*falta codigo */
+ }
+ else
+ {
+ /*428f */
+ if (gainmode != 0)
+ {
+ if (calibcfg.BShadingOn != 0)
+ lf900 = Calib_BlackShading (dev, &calibcfg, myCalib, gainmode);
+
+ /*42fd */
+ if ((lf900 != ERROR) && (calibcfg.WShadingOn != 0))
+ {
+ switch (calibcfg.WShadingOn)
+ {
+ default:
+ break;
+ case 3:
+ lf900 =
+ Calib_WhiteShading_3 (dev, &calibcfg, myCalib, gainmode);
+ break;
+ case 2:
+ break;
+ }
+ }
+ else
+ myCalib->shading_enabled = FALSE;
+ }
+ else
+ myCalib->shading_enabled = FALSE;
+ }
+
+ /*43ca */
+ memcpy (&myCalib->gain_offset, &calibdata->gain_offset,
+ sizeof (struct st_gain_offset));
+ memcpy (&mitabla2, &calibdata->gain_offset, sizeof (struct st_gain_offset));
+
+ /*4424 */
+ /* Park home after calibration */
+ if (get_value (SCANINFO, PARKHOMEAFTERCALIB, TRUE, FITCALIBRATE) == FALSE)
+ scan.ler -= calibcfg.WShadingHeight;
+ else
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+
+ return OK;
+}
+
+/*static void show_diff(struct st_device *dev, SANE_Byte *original)
+{
+ SANE_Byte *buffer = (SANE_Byte *)malloc(RT_BUFFER_LEN * sizeof(SANE_Byte));
+ SANE_Int a;
+
+ if ((buffer == NULL)||(original == NULL))
+ return;
+
+ if (RTS_ReadRegs(dev->usb_handle, buffer) != OK)
+ {
+ free(buffer);
+ return;
+ }
+
+ for (a = 0; a < RT_BUFFER_LEN; a++)
+ {
+ if ((original[a] & 0xff) != (buffer[a] & 0xff))
+ {
+ printf("%5i: %i -> %i\n", a, original[a] & 0xff, buffer[a] & 0xff);
+ original[a] = buffer[a] & 0xff;
+ }
+ }
+
+ free(buffer);
+} */
+
+static SANE_Int
+Load_Constrains (struct st_device *dev)
+{
+ SANE_Int rst = ERROR;
+
+ if (dev->constrains != NULL)
+ Free_Constrains (dev);
+
+ DBG (DBG_FNC, "> Load_Constrains\n");
+
+ dev->constrains =
+ (struct st_constrains *) malloc (sizeof (struct st_constrains));
+ if (dev->constrains != NULL)
+ {
+ cfg_constrains_get (dev->constrains);
+ rst = OK;
+ }
+
+ return rst;
+}
+
+static SANE_Int
+Constrains_Check (struct st_device *dev, SANE_Int Resolution,
+ SANE_Int scantype, struct st_coords *mycoords)
+{
+ /*
+ Constrains:
+ 100 dpi 850 x 1170 | 164 x 327
+ 300 dpi 2550 x 3510
+ 600 dpi 5100 x 7020
+ 1200 dpi 10200 x 14040
+ */
+
+ SANE_Int rst = ERROR;
+
+ if (dev->constrains != NULL)
+ {
+ struct st_coords coords;
+ struct st_coords *mc;
+
+ if ((scantype < ST_NORMAL) || (scantype > ST_NEG))
+ scantype = ST_NORMAL;
+
+ switch (scantype)
+ {
+ case ST_TA:
+ mc = &dev->constrains->slide;
+ break;
+ case ST_NEG:
+ mc = &dev->constrains->negative;
+ break;
+ default:
+ mc = &dev->constrains->reflective;
+ break;
+ }
+
+ coords.left = MM_TO_PIXEL (mc->left, Resolution);
+ coords.width = MM_TO_PIXEL (mc->width, Resolution);
+ coords.top = MM_TO_PIXEL (mc->top, Resolution);
+ coords.height = MM_TO_PIXEL (mc->height, Resolution);
+
+ /* Check left and top */
+ if (mycoords->left < 0)
+ mycoords->left = 0;
+
+ mycoords->left += coords.left;
+
+ if (mycoords->top < 0)
+ mycoords->top = 0;
+
+ mycoords->top += coords.top;
+
+ /* Check width and height */
+ if ((mycoords->width < 0) || (mycoords->width > coords.width))
+ mycoords->width = coords.width;
+
+ if ((mycoords->height < 0) || (mycoords->height > coords.height))
+ mycoords->height = coords.height;
+
+ rst = OK;
+ }
+
+ DBG (DBG_FNC,
+ "> Constrains_Check: Source=%s, Res=%i, LW=(%i,%i), TH=(%i,%i): %i\n",
+ dbg_scantype (scantype), Resolution, mycoords->left, mycoords->width,
+ mycoords->top, mycoords->height, rst);
+
+ return rst;
+}
+
+static struct st_coords *
+Constrains_Get (struct st_device *dev, SANE_Byte scantype)
+{
+ static struct st_coords *rst = NULL;
+
+ if (dev->constrains != NULL)
+ {
+ switch (scantype)
+ {
+ case ST_TA:
+ rst = &dev->constrains->slide;
+ break;
+ case ST_NEG:
+ rst = &dev->constrains->negative;
+ break;
+ default:
+ rst = &dev->constrains->reflective;
+ break;
+ }
+ }
+
+ return rst;
+}
+
+static void
+Free_Constrains (struct st_device *dev)
+{
+ DBG (DBG_FNC, "> Free_Constrains\n");
+
+ if (dev->constrains != NULL)
+ {
+ free (dev->constrains);
+ dev->constrains = NULL;
+ }
+}
+
+static void
+RTS_DebugInit ()
+{
+ /* Default vaules */
+ RTS_Debug->dev_model = HP3970;
+
+ RTS_Debug->DumpShadingData = FALSE;
+ RTS_Debug->SaveCalibFile = FALSE;
+ RTS_Debug->ScanWhiteBoard = FALSE;
+ RTS_Debug->EnableGamma = TRUE;
+ RTS_Debug->use_fixed_pwm = TRUE;
+ RTS_Debug->dmatransfersize = 0x80000;
+ RTS_Debug->dmasetlength = 0x7c0000;
+ RTS_Debug->dmabuffersize = 0x400000;
+ RTS_Debug->usbtype = -1;
+
+ /* Lamp settings */
+ RTS_Debug->overdrive_flb = 10000; /* msecs */
+ RTS_Debug->overdrive_ta = 10000; /* msecs */
+
+ RTS_Debug->warmup = TRUE;
+
+ /* Calibration settings */
+ RTS_Debug->calibrate = FALSE;
+ RTS_Debug->wshading = TRUE;
+}
+
+static void
+RTS_Setup_Gamma (SANE_Byte * Regs, struct st_hwdconfig *hwdcfg)
+{
+ DBG (DBG_FNC, "> RTS_Setup_Gamma(*Regs, *hwdcfg)\n");
+
+ if ((hwdcfg != NULL) && (Regs != NULL))
+ {
+ if (hwdcfg->use_gamma_tables != FALSE)
+ {
+ SANE_Int table_size;
+
+ /* set set table size */
+ data_bitset (&Regs[0x1d0], 0x0f, hwdcfg->gamma_tablesize);
+
+ /* enable gamma correction */
+ data_bitset (&Regs[0x1d0], 0x40, 1);
+
+
+ switch (Regs[0x1d0] & 0x0c)
+ {
+ case 0:
+ table_size = (Regs[0x1d0] & 1) | 0x0100;
+ break;
+ case 4:
+ table_size = (Regs[0x1d0] & 1) | 0x0400;
+ break;
+ case 8:
+ table_size = (Regs[0x1d0] & 1) | 0x1000;
+ break;
+ default:
+ table_size = hwdcfg->startpos & 0xffff;
+ break;
+ }
+
+ /* 5073 */
+ /* points to red gamma table */
+ data_wide_bitset (&Regs[0x1b4], 0x3fff, 0);
+
+ /* points to green gamma table */
+ data_wide_bitset (&Regs[0x1b6], 0x3fff, table_size);
+
+ /* points to blue gamma table */
+ data_wide_bitset (&Regs[0x1b8], 0x3fff, table_size * 2);
+
+ v15f8 = (((table_size * 3) + 15) / 16) & 0xffff;
+ }
+ else
+ {
+ /* disable gamma correction */
+ data_bitset (&Regs[0x1d0], 0x40, 0);
+ v15f8 = 0;
+ }
+ }
+}
+
+static SANE_Int
+RTS_USBType (struct st_device *dev)
+{
+ /* Gets USB type of this scanner */
+
+ SANE_Int rst = ERROR;
+ SANE_Byte data;
+
+ DBG (DBG_FNC, "+ RTS_USBType\n");
+
+ if (Read_Byte (dev->usb_handle, 0xfe11, &data) == OK)
+ rst = (data & 1);
+
+ DBG (DBG_FNC, "- RTS_USBType(void): %s\n",
+ (rst == USB11) ? "USB1.1" : "USB2.0");
+
+ return rst;
+}
+
+static SANE_Int
+Init_Vars (void)
+{
+ SANE_Int rst = OK;
+
+ hp_gamma = malloc (sizeof (struct st_gammatables));
+ if (hp_gamma != NULL)
+ bzero (hp_gamma, sizeof (struct st_gammatables));
+ else
+ rst = ERROR;
+
+ if (rst == OK)
+ {
+ RTS_Debug = malloc (sizeof (struct st_debug_opts));
+ if (RTS_Debug != NULL)
+ bzero (RTS_Debug, sizeof (struct st_debug_opts));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ default_gain_offset = malloc (sizeof (struct st_gain_offset));
+ if (default_gain_offset != NULL)
+ bzero (default_gain_offset, sizeof (struct st_gain_offset));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ calibdata = malloc (sizeof (struct st_calibration_data));
+ if (calibdata != NULL)
+ bzero (calibdata, sizeof (struct st_calibration_data));
+ else
+ rst = ERROR;
+ }
+
+ if (rst == OK)
+ {
+ wshading = malloc (sizeof (struct st_shading));
+ if (wshading != NULL)
+ bzero (wshading, sizeof (struct st_shading));
+ else
+ rst = ERROR;
+ }
+
+ waitforpwm = TRUE;
+
+ use_gamma_tables = TRUE;
+
+ if (rst == OK)
+ RTS_DebugInit ();
+ else
+ Free_Vars ();
+
+ return rst;
+}
+
+static void
+Free_Vars (void)
+{
+ if (RTS_Debug != NULL)
+ {
+ free (RTS_Debug);
+ RTS_Debug = NULL;
+ }
+
+ if (hp_gamma != NULL)
+ {
+ free (hp_gamma);
+ hp_gamma = NULL;
+ }
+
+ if (calibdata != NULL)
+ {
+ free (calibdata);
+ calibdata = NULL;
+ }
+
+ if (wshading != NULL)
+ {
+ if (wshading->rates != NULL)
+ free (wshading->rates);
+
+ free (wshading);
+ wshading = NULL;
+ }
+
+ if (default_gain_offset != NULL)
+ {
+ free (default_gain_offset);
+ default_gain_offset = NULL;
+ }
+
+}
+
+static SANE_Int
+Chipset_Reset (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ Chipset_Reset:\n");
+
+ /* I've found two ways to reset chipset. Next one will stay commented
+ rst = ERROR;
+ if (Read_Byte(dev->usb_handle, 0xe800, &data) == OK)
+ {
+ data |= 0x20;
+ if (Write_Byte(dev->usb_handle, 0xe800, data) == OK)
+ {
+ data &= 0xdf;
+ rst = Write_Byte(dev->usb_handle, 0xe800, data);
+ }
+ }
+ */
+
+ rst = IWrite_Buffer (dev->usb_handle, 0x0000, NULL, 0, 0x0801);
+
+ DBG (DBG_FNC, "- Chipset_Reset: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Enable_Read (struct st_device *dev, SANE_Int dmacs, SANE_Int size,
+ SANE_Int options)
+{
+ SANE_Int rst = ERROR;
+ SANE_Byte buffer[6];
+
+ DBG (DBG_FNC,
+ "+ RTS_DMA_Enable_Read(dmacs=0x%04x, size=%i, options=0x%06x)\n",
+ dmacs, size, options);
+
+ data_msb_set (&buffer[0], options, 3);
+
+ /* buffer size divided by 2 (words count) */
+ data_lsb_set (&buffer[3], size / 2, 3);
+
+ rst = IWrite_Buffer (dev->usb_handle, dmacs, buffer, 6, 0x0400);
+
+ DBG (DBG_FNC, "- RTS_DMA_Enable_Read: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Enable_Write (struct st_device *dev, SANE_Int dmacs, SANE_Int size,
+ SANE_Int options)
+{
+ SANE_Int rst = ERROR;
+ SANE_Byte buffer[6];
+
+ DBG (DBG_FNC,
+ "+ RTS_DMA_Enable_Write(dmacs=0x%04x, size=%i, options=0x%06x)\n",
+ dmacs, size, options);
+
+ data_msb_set (&buffer[0], options, 3);
+
+ /* buffer size divided by 2 (words count) */
+ data_lsb_set (&buffer[3], size / 2, 3);
+
+ rst = IWrite_Buffer (dev->usb_handle, dmacs, buffer, 6, 0x0401);
+
+ DBG (DBG_FNC, "- RTS_DMA_Enable_Write: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Cancel (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_DMA_Cancel:\n");
+
+ rst = IWrite_Word (dev->usb_handle, 0x0000, 0, 0x0600);
+
+ DBG (DBG_FNC, "- RTS_DMA_Cancel: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_DMA_Reset (struct st_device *dev)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_DMA_Reset:\n");
+
+ rst = IWrite_Word (dev->usb_handle, 0x0000, 0x0000, 0x0800);
+
+ DBG (DBG_FNC, "- RTS_DMA_Reset: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_WriteByte (USB_Handle usb_handle, SANE_Int address, SANE_Byte data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_WriteByte(address=%04x, data=%i):\n", address,
+ data);
+
+ rst = IWrite_Byte (usb_handle, address, data, 0x200, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_WriteByte: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_ReadWord (USB_Handle usb_handle, SANE_Int address, SANE_Int * data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_ReadWord(address=%04x, data):\n", address);
+
+ rst = IRead_Word (usb_handle, address, data, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_ReadWord: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_ReadByte (USB_Handle usb_handle, SANE_Int address,
+ SANE_Byte * data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_ReadByte(address=%04x, data):\n", address);
+
+ rst = IRead_Byte (usb_handle, address, data, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_ReadByte: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_WriteWord (USB_Handle usb_handle, SANE_Int address, SANE_Int data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_WriteWord(address=%04x, data=%i):\n", address,
+ data);
+
+ rst = IWrite_Word (usb_handle, address, data, 0x0200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_WriteWord: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_ReadInteger (USB_Handle usb_handle, SANE_Int address,
+ SANE_Int * data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_ReadInteger(address=%04x, data):\n", address);
+
+ rst = IRead_Integer (usb_handle, address, data, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_ReadInteger: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_WriteInteger (USB_Handle usb_handle, SANE_Int address,
+ SANE_Int data)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_WriteInteger(address=%04x, data):\n", address);
+
+ rst = IWrite_Integer (usb_handle, address, data, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_WriteInteger: %i\n", rst);
+
+ return rst;
+}
+
+static SANE_Int
+RTS_EEPROM_WriteBuffer (USB_Handle usb_handle, SANE_Int address,
+ SANE_Byte * data, SANE_Int size)
+{
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "+ RTS_EEPROM_WriteBuffer(address=%04x, data, size=%i):\n",
+ address, size);
+
+ rst = IWrite_Buffer (usb_handle, address, data, size, 0x200);
+
+ DBG (DBG_FNC, "- RTS_EEPROM_WriteBuffer: %i\n", rst);
+
+ return rst;
+}
+
+static void
+WShading_Emulate (SANE_Byte * buffer, SANE_Int * chnptr, SANE_Int size,
+ SANE_Int depth)
+{
+ if ((wshading->rates != NULL) && (chnptr != NULL))
+ {
+ if (*chnptr < wshading->count)
+ {
+ double maxvalue, chncolor;
+ SANE_Int chnsize;
+ SANE_Int pos;
+ SANE_Int icolor;
+
+ maxvalue = (1 << depth) - 1;
+ chnsize = (depth > 8) ? 2 : 1;
+
+ pos = 0;
+ while (pos < size)
+ {
+ /* get channel color */
+ chncolor = data_lsb_get (buffer + pos, chnsize);
+
+ /* apply shading coeficient */
+ chncolor *= wshading->rates[*chnptr];
+
+ /* care about limits */
+ chncolor = min (chncolor, maxvalue);
+
+ /* save color */
+ icolor = chncolor;
+ data_lsb_set (buffer + pos, icolor, chnsize);
+
+ *chnptr = *chnptr + 1;
+ if (*chnptr >= wshading->count)
+ *chnptr = 0;
+
+ pos += chnsize;
+ }
+ }
+ }
+}
+
+static SANE_Int
+WShading_Calibrate (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ struct st_scanparams *scancfg)
+{
+ struct st_calibration_config *calibcfg;
+ struct st_gain_offset myCalibTable;
+ struct st_scanparams *myscancfg;
+ SANE_Byte *myRegs; /*f1bc */
+ SANE_Int bytes_per_line;
+ /**/ SANE_Int x, y, a, C;
+ SANE_Byte *pattern; /*f164 */
+ double sumatorio;
+ SANE_Int gainmode;
+ SANE_Int rst;
+ SANE_Byte *avg_colors;
+
+ DBG (DBG_FNC, "> WShading_Calibrate(*myCalib)\n");
+
+ bzero (&myCalibTable, sizeof (struct st_gain_offset));
+ for (C = CL_RED; C <= CL_BLUE; C++)
+ {
+ myCalibTable.pag[C] = 3;
+ myCalibTable.vgag1[C] = 4;
+ myCalibTable.vgag2[C] = 4;
+ }
+
+ calibcfg =
+ (struct st_calibration_config *)
+ malloc (sizeof (struct st_calibration_config));
+ memset (calibcfg, 0x30, sizeof (struct st_calibration_config));
+
+ myscancfg = (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ memcpy (myscancfg, scancfg, sizeof (struct st_scanparams));
+
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ Calib_LoadConfig (dev, calibcfg, scan.scantype, myscancfg->resolution_x,
+ myscancfg->depth);
+ gainmode = Lamp_GetGainMode (dev, myscancfg->resolution_x, scan.scantype);
+
+ Lamp_SetGainMode (dev, myRegs, myscancfg->resolution_x, gainmode);
+
+ rst = OK;
+
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ /*a184 */
+ myscancfg->coord.left += scan.ser;
+ myscancfg->coord.width &= 0xffff;
+ break;
+ case ST_TA:
+ case ST_NEG:
+ myscancfg->coord.left += scan.ser;
+ break;
+ }
+
+ /*a11b */
+ if ((myscancfg->coord.width & 1) != 0)
+ myscancfg->coord.width++;
+
+ myscancfg->coord.top = 1;
+ myscancfg->coord.height = calibcfg->WShadingHeight;
+
+ myscancfg->sensorresolution = 0;
+
+ bytes_per_line =
+ myscancfg->coord.width * (((myscancfg->colormode == CM_COLOR) ? 3 : 1) *
+ ((myscancfg->depth > 8) ? 2 : 1));
+
+ /*a1e8 */
+ myscancfg->v157c = bytes_per_line;
+ myscancfg->bytesperline = bytes_per_line;
+
+ /* allocate space for pattern */
+ pattern =
+ (SANE_Byte *) malloc (((myscancfg->coord.height) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (pattern == NULL)
+ return ERROR;
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ rst =
+ RTS_GetImage (dev, myRegs, myscancfg, &myCalibTable, pattern, myCalib,
+ 0x20000000, gainmode);
+
+ if (rst != ERROR)
+ {
+ SANE_Int chn;
+ double colors[3] = { 0, 0, 0 };
+ double prueba;
+ SANE_Int data;
+ SANE_Int bytes_per_channel;
+
+ bytes_per_channel = (myscancfg->depth > 8) ? 2 : 1;
+
+ avg_colors = (SANE_Byte *) malloc (sizeof (SANE_Byte) * bytes_per_line);
+
+ if (avg_colors != NULL)
+ {
+ wshading->ptr = 0;
+ wshading->count = bytes_per_line / bytes_per_channel;
+
+ if (wshading->rates != NULL)
+ {
+ free (wshading->rates);
+ wshading->rates = NULL;
+ }
+ wshading->rates =
+ (double *) malloc (sizeof (double) * wshading->count);
+
+ chn = 0;
+ for (x = 0; x < wshading->count; x++)
+ {
+ sumatorio = 0;
+
+ for (y = 0; y < myscancfg->coord.height; y++)
+ {
+ data =
+ data_lsb_get (pattern +
+ ((x * bytes_per_channel) +
+ (bytes_per_line * y)), bytes_per_channel);
+ sumatorio += data;
+ }
+
+ sumatorio /= myscancfg->coord.height;
+ a = sumatorio;
+ colors[chn] = max (colors[chn], sumatorio);
+ chn++;
+ if (chn > 2)
+ chn = 0;
+
+ data_lsb_set (avg_colors + (x * bytes_per_channel), a,
+ bytes_per_channel);
+ }
+
+ DBG (DBG_FNC, " -> max colors RGB= %f %f %f\n", colors[0],
+ colors[1], colors[2]);
+
+ chn = 0;
+ for (x = 0; x < wshading->count; x++)
+ {
+ data =
+ data_lsb_get (avg_colors + (x * bytes_per_channel),
+ bytes_per_channel);
+ prueba = data;
+ *(wshading->rates + x) = colors[chn] / prueba;
+ chn++;
+ if (chn > 2)
+ chn = 0;
+ }
+ }
+
+ if (RTS_Debug->SaveCalibFile != FALSE)
+ {
+ dbg_tiff_save ("whiteshading_jkd.tiff",
+ myscancfg->coord.width,
+ myscancfg->coord.height,
+ myscancfg->depth,
+ CM_COLOR,
+ scancfg->resolution_x,
+ scancfg->resolution_y,
+ pattern, (myscancfg->coord.height) * bytes_per_line);
+ }
+
+#ifdef developing
+ {
+ FILE *archivo;
+ char texto[1024];
+
+ /* apply correction to the pattern to see the result */
+ chn = 0;
+ for (x = 0; x < myscancfg->coord.height * wshading->count; x++)
+ {
+ data =
+ data_lsb_get (pattern + (x * bytes_per_channel),
+ bytes_per_channel);
+ sumatorio = data;
+ sumatorio *= wshading->rates[chn];
+ if (sumatorio > ((1 << myscancfg->depth) - 1))
+ sumatorio = (1 << myscancfg->depth) - 1;
+
+ a = sumatorio;
+ data_lsb_set (pattern + (x * bytes_per_channel), a,
+ bytes_per_channel);
+
+ chn++;
+ if (chn == wshading->count)
+ chn = 0;
+ }
+
+ /* save corrected pattern */
+ dbg_tiff_save ("onwhiteshading_jkd.tiff",
+ myscancfg->coord.width,
+ myscancfg->coord.height,
+ myscancfg->depth,
+ CM_COLOR,
+ scancfg->resolution_x,
+ scancfg->resolution_y,
+ pattern, (myscancfg->coord.height) * bytes_per_line);
+
+ /* export coefficients */
+ archivo = fopen ("wShading.txt", "w");
+ for (x = 0; x < wshading->count; x++)
+ {
+ snprintf (texto, 1024, "%f", wshading->rates[x]);
+ fprintf (archivo, "%s\n", texto);
+ }
+
+ fclose (archivo);
+ }
+#endif
+ }
+
+ free (pattern);
+
+ return OK;
+}
+
+#ifdef developing
+static SANE_Int
+motor_pos (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib, struct st_scanparams *scancfg)
+{
+ struct st_calibration_config *calibcfg;
+ struct st_gain_offset myCalibTable;
+ struct st_scanparams *myscancfg;
+ SANE_Byte *myRegs; /*f1bc */
+ SANE_Int bytes_per_line;
+ /**/ SANE_Int a, C;
+ SANE_Byte *scanbuffer; /*f164 */
+ SANE_Int gainmode;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "> Calib_test(*myCalib)\n");
+
+ bzero (&myCalibTable, sizeof (struct st_gain_offset));
+
+ calibcfg =
+ (struct st_calibration_config *)
+ malloc (sizeof (struct st_calibration_config));
+ memset (calibcfg, 0x30, sizeof (struct st_calibration_config));
+
+ myscancfg = (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ memcpy (myscancfg, scancfg, sizeof (struct st_scanparams));
+
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ Calib_LoadConfig (dev, calibcfg, scan.scantype, myscancfg->resolution_x,
+ myscancfg->depth);
+ gainmode = Lamp_GetGainMode (dev, myscancfg->resolution_x, scan.scantype);
+
+ Lamp_SetGainMode (dev, myRegs, myscancfg->resolution_x, gainmode);
+
+ rst = OK;
+
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ /*a184 */
+ myscancfg->coord.left += scan.ser;
+ myscancfg->coord.width &= 0xffff;
+ break;
+ case ST_TA:
+ case ST_NEG:
+ myscancfg->coord.left += scan.ser;
+ break;
+ }
+
+ /*a11b */
+ if ((myscancfg->coord.width & 1) != 0)
+ myscancfg->coord.width++;
+
+ myscancfg->coord.top = 100;
+ myscancfg->coord.height = 30;
+
+ bytes_per_line = myscancfg->coord.width * 3;
+
+ /*a1e8 */
+ myscancfg->v157c = bytes_per_line;
+ myscancfg->bytesperline = bytes_per_line;
+
+ scanbuffer =
+ (SANE_Byte *) malloc (((myscancfg->coord.height + 16) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (scanbuffer == NULL)
+ return ERROR;
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ /*Head_Relocate(dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD, 5500); */
+
+ for (a = 0; a < 10; a++)
+ {
+ for (C = CL_RED; C <= CL_BLUE; C++)
+ {
+ myCalibTable.pag[C] = 3;
+ myCalibTable.vgag1[C] = 4;
+ myCalibTable.vgag2[C] = 4;
+ myCalibTable.edcg1[C] = a * 20;
+ }
+
+ dbg_ScanParams (myscancfg);
+
+ Head_Relocate (dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD,
+ 5000);
+ rst =
+ RTS_GetImage (dev, myRegs, myscancfg, &myCalibTable, scanbuffer,
+ myCalib, 0x20000000, gainmode);
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+
+ if (rst != ERROR)
+ {
+ char name[30];
+ snprintf (name, 30, "calibtest-%i.tiff", a);
+ dbg_tiff_save (name,
+ myscancfg->coord.width,
+ myscancfg->coord.height,
+ myscancfg->depth,
+ CM_COLOR,
+ myscancfg->resolution_x,
+ myscancfg->resolution_y,
+ scanbuffer,
+ (myscancfg->coord.height + 16) * bytes_per_line);
+ }
+ }
+
+ free (scanbuffer);
+
+ exit (0);
+ return OK;
+}
+
+static SANE_Int
+hp4370_prueba (struct st_device *dev)
+{
+ SANE_Int rst;
+ SANE_Int data = 0x0530, a;
+ SANE_Int transferred;
+ SANE_Byte buffer[512];
+
+ for (a = 0; a < 256; a++)
+ data_lsb_set (buffer + (a * 2), 0x9d7, 2);
+
+ rst = IWrite_Word (dev->usb_handle, 0x0000, data, 0x0800);
+ RTS_DMA_Enable_Write (dev, 0x4, 512, 0);
+ Bulk_Operation (dev, BLK_WRITE, 512, buffer, &transferred);
+
+ return rst;
+}
+
+static SANE_Int
+Calib_BlackShading_jkd (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib,
+ struct st_scanparams *scancfg)
+{
+ struct st_calibration_config *calibcfg;
+ struct st_gain_offset myCalibTable;
+ struct st_scanparams *myscancfg;
+ SANE_Byte *myRegs; /*f1bc */
+ SANE_Int bytes_per_line;
+ /**/ SANE_Int x, y, a, C;
+ SANE_Byte *scanbuffer; /*f164 */
+ double sumatorio;
+ SANE_Int gainmode;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "> Calib_BlackShading_jkd(*myCalib)\n");
+
+ bzero (&myCalibTable, sizeof (struct st_gain_offset));
+ for (C = CL_RED; C <= CL_BLUE; C++)
+ {
+ myCalibTable.pag[C] = 3;
+ myCalibTable.vgag1[C] = 4;
+ myCalibTable.vgag2[C] = 4;
+ }
+
+ calibcfg =
+ (struct st_calibration_config *)
+ malloc (sizeof (struct st_calibration_config));
+ memset (calibcfg, 0x30, sizeof (struct st_calibration_config));
+
+ myscancfg = (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ memcpy (myscancfg, scancfg, sizeof (struct st_scanparams));
+
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ Calib_LoadConfig (dev, calibcfg, scan.scantype, myscancfg->resolution_x,
+ myscancfg->depth);
+ gainmode = Lamp_GetGainMode (dev, myscancfg->resolution_x, scan.scantype);
+
+ Lamp_SetGainMode (dev, myRegs, myscancfg->resolution_x, gainmode);
+
+ rst = OK;
+
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ /*a184 */
+ myscancfg->coord.left += scan.ser;
+ myscancfg->coord.width &= 0xffff;
+ break;
+ case ST_TA:
+ case ST_NEG:
+ myscancfg->coord.left += scan.ser;
+ break;
+ }
+
+ /*a11b */
+ if ((myscancfg->coord.width & 1) != 0)
+ myscancfg->coord.width++;
+
+ myscancfg->coord.top = 1;
+ myscancfg->coord.height = calibcfg->BShadingHeight;
+
+ bytes_per_line = myscancfg->coord.width * 3;
+
+ /*a1e8 */
+ myscancfg->v157c = bytes_per_line;
+ myscancfg->bytesperline = bytes_per_line;
+
+ scanbuffer =
+ (SANE_Byte *) malloc (((myscancfg->coord.height + 16) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (scanbuffer == NULL)
+ return ERROR;
+
+ /* Turn off lamp */
+ Lamp_Status_Set (dev, NULL, FALSE, FLB_LAMP);
+ usleep (200 * 1000);
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ rst =
+ RTS_GetImage (dev, myRegs, myscancfg, &myCalibTable, scanbuffer, myCalib,
+ 0x101, gainmode);
+
+ /* Turn on lamp again */
+ if (scan.scantype != ST_NORMAL)
+ {
+ Lamp_Status_Set (dev, NULL, FALSE, TMA_LAMP);
+ usleep (1000 * 1000);
+ }
+ else
+ Lamp_Status_Set (dev, NULL, TRUE, FLB_LAMP);
+
+ if (rst != ERROR)
+ {
+ jkd_black = (SANE_Byte *) malloc (bytes_per_line);
+
+ if (jkd_black != NULL)
+ {
+ jkd_blackbpl = bytes_per_line;
+
+ for (x = 0; x < bytes_per_line; x++)
+ {
+ sumatorio = 0;
+
+ for (y = 0; y < myscancfg->coord.height + 16; y++)
+ sumatorio += scanbuffer[x + (bytes_per_line * y)];
+
+ sumatorio /= myscancfg->coord.height + 16;
+ a = sumatorio;
+ *(jkd_black + x) = _B0 (a);
+ }
+ }
+
+ /*if (RTS_Debug->SaveCalibFile != FALSE) */
+ {
+ dbg_tiff_save ("blackshading_jkd.tiff",
+ myscancfg->coord.width,
+ myscancfg->coord.height,
+ myscancfg->depth,
+ CM_COLOR,
+ myscancfg->resolution_x,
+ myscancfg->resolution_y,
+ scanbuffer,
+ (myscancfg->coord.height + 16) * bytes_per_line);
+ }
+ }
+
+ free (scanbuffer);
+
+ return OK;
+}
+
+static SANE_Int
+Calib_test (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib, struct st_scanparams *scancfg)
+{
+ struct st_calibration_config *calibcfg;
+ struct st_gain_offset myCalibTable;
+ struct st_scanparams *myscancfg;
+ SANE_Byte *myRegs; /*f1bc */
+ SANE_Int bytes_per_line;
+ /**/ SANE_Int a, C;
+ SANE_Byte *scanbuffer; /*f164 */
+ SANE_Int gainmode;
+ SANE_Int rst;
+
+ DBG (DBG_FNC, "> Calib_test(*myCalib)\n");
+
+ bzero (&myCalibTable, sizeof (struct st_gain_offset));
+
+ calibcfg =
+ (struct st_calibration_config *)
+ malloc (sizeof (struct st_calibration_config));
+ memset (calibcfg, 0x30, sizeof (struct st_calibration_config));
+
+ myscancfg = (struct st_scanparams *) malloc (sizeof (struct st_scanparams));
+ memcpy (myscancfg, scancfg, sizeof (struct st_scanparams));
+
+ myRegs = (SANE_Byte *) malloc (RT_BUFFER_LEN * sizeof (SANE_Byte));
+ memcpy (myRegs, Regs, RT_BUFFER_LEN * sizeof (SANE_Byte));
+
+ Calib_LoadConfig (dev, calibcfg, scan.scantype, myscancfg->resolution_x,
+ myscancfg->depth);
+ gainmode = Lamp_GetGainMode (dev, myscancfg->resolution_x, scan.scantype);
+
+ Lamp_SetGainMode (dev, myRegs, myscancfg->resolution_x, gainmode);
+
+ rst = OK;
+
+ switch (scan.scantype)
+ {
+ case ST_NORMAL:
+ /*a184 */
+ myscancfg->coord.left += scan.ser;
+ myscancfg->coord.width &= 0xffff;
+ break;
+ case ST_TA:
+ case ST_NEG:
+ myscancfg->coord.left += scan.ser;
+ break;
+ }
+
+ /*a11b */
+ if ((myscancfg->coord.width & 1) != 0)
+ myscancfg->coord.width++;
+
+ myscancfg->coord.top = 100;
+ myscancfg->coord.height = 30;
+
+ bytes_per_line = myscancfg->coord.width * 3;
+
+ /*a1e8 */
+ myscancfg->v157c = bytes_per_line;
+ myscancfg->bytesperline = bytes_per_line;
+
+ scanbuffer =
+ (SANE_Byte *) malloc (((myscancfg->coord.height + 16) * bytes_per_line) *
+ sizeof (SANE_Byte));
+ if (scanbuffer == NULL)
+ return ERROR;
+
+ /* Scan image */
+ myCalib->shading_enabled = FALSE;
+ /*Head_Relocate(dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD, 5500); */
+
+ for (a = 0; a < 10; a++)
+ {
+ for (C = CL_RED; C <= CL_BLUE; C++)
+ {
+ myCalibTable.pag[C] = 3;
+ myCalibTable.vgag1[C] = 4;
+ myCalibTable.vgag2[C] = 4;
+ myCalibTable.edcg1[C] = a * 20;
+ }
+
+ Head_Relocate (dev, dev->motorcfg->highspeedmotormove, MTR_FORWARD,
+ 5000);
+ rst =
+ RTS_GetImage (dev, myRegs, myscancfg, &myCalibTable, scanbuffer,
+ myCalib, 0x20000000, gainmode);
+ Head_ParkHome (dev, TRUE, dev->motorcfg->parkhomemotormove);
+
+ if (rst != ERROR)
+ {
+ char name[30];
+ snprintf (name, 30, "calibtest-%i.tiff", a);
+ dbg_tiff_save (name,
+ myscancfg->coord.width,
+ myscancfg->coord.height,
+ myscancfg->depth,
+ CM_COLOR,
+ myscancfg->resolution_x,
+ myscancfg->resolution_y,
+ scanbuffer,
+ (myscancfg->coord.height + 16) * bytes_per_line);
+ }
+ }
+
+ free (scanbuffer);
+
+ exit (0);
+ return OK;
+}
+
+static void
+prueba (SANE_Byte * a)
+{
+ /* SANE_Byte p[] = {}; */
+ /*int z = 69; */
+
+ /*(a + 11) = 0x0; */
+ /*a[1] = a[1] | 0x40; */
+
+ /*memcpy(a, &p, sizeof(p)); */
+
+ /*memcpy(a + 0x12, p, 10); */
+ /*a[0x146] &= 0xdf; */
+
+}
+
+void
+shadingtest1 (struct st_device *dev, SANE_Byte * Regs,
+ struct st_calibration *myCalib)
+{
+ USHORT *buffer;
+ int a;
+ int bit[2];
+
+ DBG (DBG_FNC, "+ shadingtest1(*Regs, *myCalib):\n");
+
+ if ((Regs == NULL) || (myCalib == NULL))
+ return;
+
+ RTS_DMA_Reset (dev);
+
+ bit[0] = (Regs[0x60b] >> 6) & 1;
+ bit[1] = (Regs[0x60b] >> 4) & 1;
+ Regs[0x060b] &= 0xaf;
+
+ Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b]);
+
+ Regs[0x1cf] = 0; /* reset config. By default black shading disabled and pixel-rate */
+ /*Regs[0x1cf] |= 2; shadingbase 0x2000 */
+ Regs[0x1cf] |= 4; /* White shading enabled */
+ Regs[0x1cf] |= 0x20; /* 16 bits per channel */
+
+ Write_Byte (dev->usb_handle, 0xe9cf, Regs[0x01cf]);
+
+ buffer = (USHORT *) malloc (sizeof (USHORT) * myCalib->shadinglength);
+
+ DBG (DBG_FNC, " -> shading length = %i\n", myCalib->shadinglength);
+
+ /* fill buffer */
+ for (a = 0; a < myCalib->shadinglength; a++)
+ buffer[a] = RTS_Debug->shd + (a * 500);
+
+ for (a = 0; a < 3; a++)
+ {
+ RTS_DMA_Write (dev, a | 0x14, 0,
+ sizeof (USHORT) * myCalib->shadinglength,
+ (SANE_Byte *) buffer);
+ }
+
+ data_bitset (&Regs[0x60b], 0x40, bit[0]); /*-x------*/
+ data_bitset (&Regs[0x60b], 0x10, bit[1]); /*---x----*/
+
+ Write_Byte (dev->usb_handle, 0xee0b, Regs[0x060b]);
+
+ DBG (DBG_FNC, "- shadingtest1\n");
+}
+
+#endif
+
+#endif /* RTS8822_CORE */